[
  {
    "path": ".github/workflows/msbuild.yml",
    "content": "name: MSBuild\n\non:\n  push:\n    branches: [ \"master\" ]\n    paths-ignore:\n      - '*.md'\n  pull_request:\n    branches: [ \"master\" ]\n    paths-ignore:\n      - '*.md'\n\nenv:\n  SOLUTION_FILE_PATH: \"visual-studio/quake3.sln\"\n  BUILD_CONFIGURATION: Release\n\njobs:\n  build:\n    runs-on: windows-latest\n\n    steps:\n    - uses: actions/checkout@v4\n\n    - name: Add MSBuild to PATH\n      uses: microsoft/setup-msbuild@v2\n\n    - name: Restore NuGet packages\n      working-directory: ${{env.GITHUB_WORKSPACE}}\n      run: nuget restore ${{env.SOLUTION_FILE_PATH}}\n\n    - name: Build\n      working-directory: ${{env.GITHUB_WORKSPACE}}\n      run: msbuild /m /p:Configuration=${{env.BUILD_CONFIGURATION}} ${{env.SOLUTION_FILE_PATH}}\n\n    - name: Upload Executable\n      uses: actions/upload-artifact@v4\n      with:\n        name: quake3\n        path: bin/x64/Release/quake3-ke.exe\n"
  },
  {
    "path": ".gitignore",
    "content": "*.opendb\n*.opensdf\n*.sdf\n*.suo\n*.user\nbin/\ntools/bin2hex.exe\ntools/bin2hex.obj\nvisual-studio/.vs/\nvisual-studio/vk_report\nvisual-studio/*.log\nvisual-studio/*.psess\nvisual-studio/*.vspx\n"
  },
  {
    "path": "COPYING.txt",
    "content": "\t\t    GNU GENERAL PUBLIC LICENSE\n\t\t       Version 2, June 1991\n\n Copyright (C) 1989, 1991 Free Software Foundation, Inc.\n                       51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n\t\t\t    Preamble\n\n  The licenses for most software are designed to take away your\nfreedom to share and change it.  By contrast, the GNU General Public\nLicense is intended to guarantee your freedom to share and change free\nsoftware--to make sure the software is free for all its users.  This\nGeneral Public License applies to most of the Free Software\nFoundation's software and to any other program whose authors commit to\nusing it.  (Some other Free Software Foundation software is covered by\nthe GNU Library General Public License instead.)  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthis service if you wish), that you receive source code or can get it\nif you want it, that you can change the software or use pieces of it\nin new free programs; and that you know you can do these things.\n\n  To protect your rights, we need to make restrictions that forbid\nanyone to deny you these rights or to ask you to surrender the rights.\nThese restrictions translate to certain responsibilities for you if you\ndistribute copies of the software, or if you modify it.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must give the recipients all the rights that\nyou have.  You must make sure that they, too, receive or can get the\nsource code.  And you must show them these terms so they know their\nrights.\n\n  We protect your rights with two steps: (1) copyright the software, and\n(2) offer you this license which gives you legal permission to copy,\ndistribute and/or modify the software.\n\n  Also, for each author's protection and ours, we want to make certain\nthat everyone understands that there is no warranty for this free\nsoftware.  If the software is modified by someone else and passed on, we\nwant its recipients to know that what they have is not the original, so\nthat any problems introduced by others will not reflect on the original\nauthors' reputations.\n\n  Finally, any free program is threatened constantly by software\npatents.  We wish to avoid the danger that redistributors of a free\nprogram will individually obtain patent licenses, in effect making the\nprogram proprietary.  To prevent this, we have made it clear that any\npatent must be licensed for everyone's free use or not licensed at all.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\f\n\t\t    GNU GENERAL PUBLIC LICENSE\n   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n  0. This License applies to any program or other work which contains\na notice placed by the copyright holder saying it may be distributed\nunder the terms of this General Public License.  The \"Program\", below,\nrefers to any such program or work, and a \"work based on the Program\"\nmeans either the Program or any derivative work under copyright law:\nthat is to say, a work containing the Program or a portion of it,\neither verbatim or with modifications and/or translated into another\nlanguage.  (Hereinafter, translation is included without limitation in\nthe term \"modification\".)  Each licensee is addressed as \"you\".\n\nActivities other than copying, distribution and modification are not\ncovered by this License; they are outside its scope.  The act of\nrunning the Program is not restricted, and the output from the Program\nis covered only if its contents constitute a work based on the\nProgram (independent of having been made by running the Program).\nWhether that is true depends on what the Program does.\n\n  1. You may copy and distribute verbatim copies of the Program's\nsource code as you receive it, in any medium, provided that you\nconspicuously and appropriately publish on each copy an appropriate\ncopyright notice and disclaimer of warranty; keep intact all the\nnotices that refer to this License and to the absence of any warranty;\nand give any other recipients of the Program a copy of this License\nalong with the Program.\n\nYou may charge a fee for the physical act of transferring a copy, and\nyou may at your option offer warranty protection in exchange for a fee.\n\n  2. You may modify your copy or copies of the Program or any portion\nof it, thus forming a work based on the Program, and copy and\ndistribute such modifications or work under the terms of Section 1\nabove, provided that you also meet all of these conditions:\n\n    a) You must cause the modified files to carry prominent notices\n    stating that you changed the files and the date of any change.\n\n    b) You must cause any work that you distribute or publish, that in\n    whole or in part contains or is derived from the Program or any\n    part thereof, to be licensed as a whole at no charge to all third\n    parties under the terms of this License.\n\n    c) If the modified program normally reads commands interactively\n    when run, you must cause it, when started running for such\n    interactive use in the most ordinary way, to print or display an\n    announcement including an appropriate copyright notice and a\n    notice that there is no warranty (or else, saying that you provide\n    a warranty) and that users may redistribute the program under\n    these conditions, and telling the user how to view a copy of this\n    License.  (Exception: if the Program itself is interactive but\n    does not normally print such an announcement, your work based on\n    the Program is not required to print an announcement.)\n\f\nThese requirements apply to the modified work as a whole.  If\nidentifiable sections of that work are not derived from the Program,\nand can be reasonably considered independent and separate works in\nthemselves, then this License, and its terms, do not apply to those\nsections when you distribute them as separate works.  But when you\ndistribute the same sections as part of a whole which is a work based\non the Program, the distribution of the whole must be on the terms of\nthis License, whose permissions for other licensees extend to the\nentire whole, and thus to each and every part regardless of who wrote it.\n\nThus, it is not the intent of this section to claim rights or contest\nyour rights to work written entirely by you; rather, the intent is to\nexercise the right to control the distribution of derivative or\ncollective works based on the Program.\n\nIn addition, mere aggregation of another work not based on the Program\nwith the Program (or with a work based on the Program) on a volume of\na storage or distribution medium does not bring the other work under\nthe scope of this License.\n\n  3. You may copy and distribute the Program (or a work based on it,\nunder Section 2) in object code or executable form under the terms of\nSections 1 and 2 above provided that you also do one of the following:\n\n    a) Accompany it with the complete corresponding machine-readable\n    source code, which must be distributed under the terms of Sections\n    1 and 2 above on a medium customarily used for software interchange; or,\n\n    b) Accompany it with a written offer, valid for at least three\n    years, to give any third party, for a charge no more than your\n    cost of physically performing source distribution, a complete\n    machine-readable copy of the corresponding source code, to be\n    distributed under the terms of Sections 1 and 2 above on a medium\n    customarily used for software interchange; or,\n\n    c) Accompany it with the information you received as to the offer\n    to distribute corresponding source code.  (This alternative is\n    allowed only for noncommercial distribution and only if you\n    received the program in object code or executable form with such\n    an offer, in accord with Subsection b above.)\n\nThe source code for a work means the preferred form of the work for\nmaking modifications to it.  For an executable work, complete source\ncode means all the source code for all modules it contains, plus any\nassociated interface definition files, plus the scripts used to\ncontrol compilation and installation of the executable.  However, as a\nspecial exception, the source code distributed need not include\nanything that is normally distributed (in either source or binary\nform) with the major components (compiler, kernel, and so on) of the\noperating system on which the executable runs, unless that component\nitself accompanies the executable.\n\nIf distribution of executable or object code is made by offering\naccess to copy from a designated place, then offering equivalent\naccess to copy the source code from the same place counts as\ndistribution of the source code, even though third parties are not\ncompelled to copy the source along with the object code.\n\f\n  4. You may not copy, modify, sublicense, or distribute the Program\nexcept as expressly provided under this License.  Any attempt\notherwise to copy, modify, sublicense or distribute the Program is\nvoid, and will automatically terminate your rights under this License.\nHowever, parties who have received copies, or rights, from you under\nthis License will not have their licenses terminated so long as such\nparties remain in full compliance.\n\n  5. You are not required to accept this License, since you have not\nsigned it.  However, nothing else grants you permission to modify or\ndistribute the Program or its derivative works.  These actions are\nprohibited by law if you do not accept this License.  Therefore, by\nmodifying or distributing the Program (or any work based on the\nProgram), you indicate your acceptance of this License to do so, and\nall its terms and conditions for copying, distributing or modifying\nthe Program or works based on it.\n\n  6. Each time you redistribute the Program (or any work based on the\nProgram), the recipient automatically receives a license from the\noriginal licensor to copy, distribute or modify the Program subject to\nthese terms and conditions.  You may not impose any further\nrestrictions on the recipients' exercise of the rights granted herein.\nYou are not responsible for enforcing compliance by third parties to\nthis License.\n\n  7. If, as a consequence of a court judgment or allegation of patent\ninfringement or for any other reason (not limited to patent issues),\nconditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot\ndistribute so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you\nmay not distribute the Program at all.  For example, if a patent\nlicense would not permit royalty-free redistribution of the Program by\nall those who receive copies directly or indirectly through you, then\nthe only way you could satisfy both it and this License would be to\nrefrain entirely from distribution of the Program.\n\nIf any portion of this section is held invalid or unenforceable under\nany particular circumstance, the balance of the section is intended to\napply and the section as a whole is intended to apply in other\ncircumstances.\n\nIt is not the purpose of this section to induce you to infringe any\npatents or other property right claims or to contest validity of any\nsuch claims; this section has the sole purpose of protecting the\nintegrity of the free software distribution system, which is\nimplemented by public license practices.  Many people have made\ngenerous contributions to the wide range of software distributed\nthrough that system in reliance on consistent application of that\nsystem; it is up to the author/donor to decide if he or she is willing\nto distribute software through any other system and a licensee cannot\nimpose that choice.\n\nThis section is intended to make thoroughly clear what is believed to\nbe a consequence of the rest of this License.\n\f\n  8. If the distribution and/or use of the Program is restricted in\ncertain countries either by patents or by copyrighted interfaces, the\noriginal copyright holder who places the Program under this License\nmay add an explicit geographical distribution limitation excluding\nthose countries, so that distribution is permitted only in or among\ncountries not thus excluded.  In such case, this License incorporates\nthe limitation as if written in the body of this License.\n\n  9. The Free Software Foundation may publish revised and/or new versions\nof the General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\nEach version is given a distinguishing version number.  If the Program\nspecifies a version number of this License which applies to it and \"any\nlater version\", you have the option of following the terms and conditions\neither of that version or of any later version published by the Free\nSoftware Foundation.  If the Program does not specify a version number of\nthis License, you may choose any version ever published by the Free Software\nFoundation.\n\n  10. If you wish to incorporate parts of the Program into other free\nprograms whose distribution conditions are different, write to the author\nto ask for permission.  For software which is copyrighted by the Free\nSoftware Foundation, write to the Free Software Foundation; we sometimes\nmake exceptions for this.  Our decision will be guided by the two goals\nof preserving the free status of all derivatives of our free software and\nof promoting the sharing and reuse of software generally.\n\n\t\t\t    NO WARRANTY\n\n  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\nFOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\nOTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\nPROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\nOR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\nTO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\nPROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\nREPAIR OR CORRECTION.\n\n  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\nREDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\nINCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\nOUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\nTO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\nYOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\nPROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGES.\n\n\t\t     END OF TERMS AND CONDITIONS\n\f\n"
  },
  {
    "path": "README.md",
    "content": "# Welcome to Quake 3 source code!\n\n![Actions Status](https://github.com/kennyalive/Quake-III-Arena-Kenny-Edition/actions/workflows/msbuild.yml/badge.svg)\n\n## What's in this repository\n* This repository contains Quake 3 Arena source code which can be built with modern versions of Visual Studio.\n* Only Windows x64 platform is supported.\n* I don't try to fix bugs inherited from the original Q3 source code distribution - in this regard the project is Q3-bugs-friendly. I still make fixes to functionality that did not stand the test of time (SetDeviceGammaRamp).\n* Some functionality related to ancient graphics hardware was removed. Also I removed compilation of qvm code to native instructions to simplify maintenance. This means all game code is run through QVM which is slower than native execution but fast enough for modern computers.\n* No changes to visuals or gameplay. Vulkan backend is now enabled by default. This change was made due to issues with the SetDeviceGammaRamp API.\n\n## Usage\n* Build `visual-studio/quake3.sln` solution and copy `quake3-ke.exe` to your local Quake-III-Arena installation folder.\n* To debug the game from Visual Studio, go to `quake3` project settings -> Debugging -> Command Arguments. Specify the game installation location: `+set fs_basepath <quake3/installation/directory>`\n\n## Vulkan support \nThe Vulkan backend supports everything provided by the original OpenGL version, including all available `r_` cvars. No new features have been added; the goal is to preserve existing functionality rather than expand it.\n\n#### New cvars:\n* **r_renderAPI** - 3D API to use. Requires vid_restart.\n    * 0 - OpenGL\n    * 1 - Vulkan\n \n* **r_gpu** - Select GPU in multi-GPU system (zero-based index). By default, GPU 0 is selected. Requires vid_restart.\n\n* **r_vsync** - Enable vsync in Vulkan. Requires vid_restart.\n\n* **r_shaderGamma** - Use compute shader to apply gamma instead of legacy HW gamma API (SetDeviceGammaRamp). \n\n* **r_twinMode** - Debug feature to compare rendering output between OpenGL/Vulkan APIs. Requires vid_restart.\n\n![twin_mode](https://user-images.githubusercontent.com/4964024/34961607-48aae882-fa40-11e7-9bf0-d4400afdad34.jpg)\n\n#### Additional information:\n* Q: How to start game with vulkan support? A: `quake3-ke.exe +set r_renderAPI 1`.\n* Q: How to enable vulkan support from Q3 console? A: `\\r_renderAPI 1` then `\\vid_restart`.\n* Q: How to enable twin mode from Q3 console? A: `\\r_twinMode 1` or `\\r_twinMode 1` then `\\vid_restart`.\n* Q: How to check that Vulkan backend is really active? A: `gfxinfo` console command reports information about active rendering backend.\n\n![quake3-ke](https://user-images.githubusercontent.com/4964024/28160268-4f0707d4-67c8-11e7-9009-8540789aab0b.jpeg)\n"
  },
  {
    "path": "README.txt",
    "content": "Quake III Arena GPL source release\n==================================\n\nThis file contains the following sections:\n\nLICENSE\nGENERAL NOTES\nCOMPILING ON WIN32\nCOMPILING ON GNU/LINUX\nCOMPILING ON MAC\n\nLICENSE\n=======\n\nSee COPYING.txt for the GNU GENERAL PUBLIC LICENSE\n\nSome source code in this release is not covered by the GPL:\n\nIO on .zip files using portions of zlib\n-----------------------------------------------------------------------------\nlines\tfile(s)\n4299\tcode/qcommon/unzip.c\n4546\tlibs/pak/unzip.cpp\nCopyright (C) 1998 Gilles Vollant\nzlib is Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler\n\n  This software is provided 'as-is', without any express or implied\n  warranty.  In no event will the authors be held liable for any damages\n  arising from the use of this software.\n\n  Permission is granted to anyone to use this software for any purpose,\n  including commercial applications, and to alter it and redistribute it\n  freely, subject to the following restrictions:\n\n  1. The origin of this software must not be misrepresented; you must not\n     claim that you wrote the original software. If you use this software\n     in a product, an acknowledgment in the product documentation would be\n     appreciated but is not required.\n  2. Altered source versions must be plainly marked as such, and must not be\n     misrepresented as being the original software.\n  3. This notice may not be removed or altered from any source distribution.\n\nMD4 Message-Digest Algorithm\n-----------------------------------------------------------------------------\nlines\tfile(s)\n299\t\tcode/qcommon/md4.c\n277\t\tcommon/md4.c\nCopyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All rights reserved.\n\nLicense to copy and use this software is granted provided that it is identified \nas the <93>RSA Data Security, Inc. MD4 Message-Digest Algorithm<94> in all mater\nial mentioning or referencing this software or this function.\nLicense is also granted to make and use derivative works provided that such work\ns are identified as <93>derived from the RSA Data Security, Inc. MD4 Message-Dig\nest Algorithm<94> in all material mentioning or referencing the derived work.\nRSA Data Security, Inc. makes no representations concerning either the merchanta\nbility of this software or the suitability of this software for any particular p\nurpose. It is provided <93>as is<94> without express or implied warranty of any \nkind.\n\nchecksums are used to validate pak files\n\nstandard C library replacement routines\n-----------------------------------------------------------------------------\nlines\tfile(s)\n1324\tcode/game/bg_lib.c\nCopyright (c) 1992, 1993\nThe Regents of the University of California. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions\nare met:\n1. Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n2. Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n3. All advertising materials mentioning features or use of this software\n   must display the following acknowledgement:\n     This product includes software developed by the University of\n     California, Berkeley and its contributors.\n4. Neither the name of the University nor the names of its contributors\n   may be used to endorse or promote products derived from this software\n   without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\nOR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\nHOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\nLIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\nOUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGE.\n\nADPCM coder/decoder\n-----------------------------------------------------------------------------\nlines\tfile(s)\n330\t\tcode/client/snd_adpcm.c\nCopyright 1992 by Stichting Mathematisch Centrum, Amsterdam, The\nNetherlands.\n\n                        All Rights Reserved\n\nPermission to use, copy, modify, and distribute this software and its \ndocumentation for any purpose and without fee is hereby granted, \nprovided that the above copyright notice appear in all copies and that\nboth that copyright notice and this permission notice appear in \nsupporting documentation, and that the names of Stichting Mathematisch\nCentrum or CWI not be used in advertising or publicity pertaining to\ndistribution of the software without specific, written prior permission.\n\nSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO\nTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND\nFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE\nFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\nWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\nACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT\nOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n\nJPEG library\n-----------------------------------------------------------------------------\ncode/jpeg-6\nlibs/jpeg6\nCopyright (C) 1991-1995, Thomas G. Lane\n\nPermission is hereby granted to use, copy, modify, and distribute this\nsoftware (or portions thereof) for any purpose, without fee, subject to these\nconditions:\n(1) If any part of the source code for this software is distributed, then this\nREADME file must be included, with this copyright and no-warranty notice\nunaltered; and any additions, deletions, or changes to the original files\nmust be clearly indicated in accompanying documentation.\n(2) If only executable code is distributed, then the accompanying\ndocumentation must state that \"this software is based in part on the work of\nthe Independent JPEG Group\".\n(3) Permission for use of this software is granted only if the user accepts\nfull responsibility for any undesirable consequences; the authors accept\nNO LIABILITY for damages of any kind.\n\nThese conditions apply to any software derived from or based on the IJG code,\nnot just to the unmodified library.  If you use our work, you ought to\nacknowledge us.\n\nNOTE: unfortunately the README that came with our copy of the library has\nbeen lost, so the one from release 6b is included instead. There are a few\n'glue type' modifications to the library to make it easier to use from\nthe engine, but otherwise the dependency can be easily cleaned up to a\nbetter release of the library.\n\n\nGENERAL NOTES\n=============\n\nA short summary of the file layout:\n\ncode/\t\t\t   \t\tQuake III Arena source code ( renderer, game code, OS layer etc. )\ncode/bspc\t\t\t\tbot routes compiler source code\nlcc/\t\t\t\t\tthe retargetable C compiler ( produces assembly to be turned into qvm bytecode by q3asm )\nq3asm/\t\t\t\t\tassembly to qvm bytecode compiler\nq3map/\t\t\t\t\tmap compiler ( .map -> .bsp ) - this is the version that comes with Q3Radiant 200f\nq3radiant/\t\t\t\tQ3Radiant map editor build 200f ( common/ and libs/ are support dirs for radiant )\n\nWhile we made sure we were still able to compile the game on Windows, GNU/Linux and Mac, this build didn't get any kind of extensive testing so it may not work completely right. Whenever an id game is released under GPL, several projects start making the source code more friendly to nowaday's compilers and environements. If you are picking up this release weeks/months/years after we uploaded it, you probably want to look around on the net for cleaned up versions of this codebase as well.\n\nCOMPILING ON WIN32\n==================\n\nVC7 / Visual C++ 2003 project files are provided:\ncode/quake3.sln\nq3radiant/Radiant.sln\n\nTo compile the qvms, you need to run some batch files:\nyou will need to have lcc.exe q3cpp.exe q3rcc.exe and q3asm.exe in your path\n( some precompiled binaries are provided in lcc/bin and code/win32/mod-sdk-setup/bin )\nthe qvm batch files are in code/game code/cgame code/q3_ui code/ui ..\n\nCOMPILING ON GNU/LINUX\n==================\n\nthe build system using cons, which may be known as scons's perl ancestor now\nyou don't have to track it down though, the build script is provided in the tree\nyou will need nasm and gcc 2.95\nmake sure you have the X Direct Graphics Access and X Video Mode extensions headers for your X11\na typical compile command goes like this:\n[..]/code$ ./unix/cons -- gcc=gcc-2.95 g++=g++-2.95\n\nCOMPILING ON MAC\n================\n\nproject file for OSX compile is in code/macosx/Quake3.pbproj\n"
  },
  {
    "path": "src/cgame/cg_consolecmds.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n// cg_consolecmds.c -- text commands typed in at the local console, or\n// executed by a key binding\n\n#include \"cg_local.h\"\n\n\nvoid CG_TargetCommand_f( void ) {\n\tint\t\ttargetNum;\n\tchar\ttest[4];\n\n\ttargetNum = CG_CrosshairPlayer();\n\tif (!targetNum ) {\n\t\treturn;\n\t}\n\n\ttrap_Argv( 1, test, 4 );\n\ttrap_SendConsoleCommand( va( \"gc %i %i\", targetNum, atoi( test ) ) );\n}\n\n\n\n/*\n=================\nCG_SizeUp_f\n\nKeybinding command\n=================\n*/\nstatic void CG_SizeUp_f (void) {\n\ttrap_Cvar_Set(\"cg_viewsize\", va(\"%i\",(int)(cg_viewsize.integer+10)));\n}\n\n\n/*\n=================\nCG_SizeDown_f\n\nKeybinding command\n=================\n*/\nstatic void CG_SizeDown_f (void) {\n\ttrap_Cvar_Set(\"cg_viewsize\", va(\"%i\",(int)(cg_viewsize.integer-10)));\n}\n\n\n/*\n=============\nCG_Viewpos_f\n\nDebugging command to print the current position\n=============\n*/\nstatic void CG_Viewpos_f (void) {\n\tCG_Printf (\"(%i %i %i) : %i\\n\", (int)cg.refdef.vieworg[0],\n\t\t(int)cg.refdef.vieworg[1], (int)cg.refdef.vieworg[2], \n\t\t(int)cg.refdefViewAngles[YAW]);\n}\n\n\nstatic void CG_ScoresDown_f( void ) {\n\tif ( cg.scoresRequestTime + 2000 < cg.time ) {\n\t\t// the scores are more than two seconds out of data,\n\t\t// so request new ones\n\t\tcg.scoresRequestTime = cg.time;\n\t\ttrap_SendClientCommand( \"score\" );\n\n\t\t// leave the current scores up if they were already\n\t\t// displayed, but if this is the first hit, clear them out\n\t\tif ( !cg.showScores ) {\n\t\t\tcg.showScores = qtrue;\n\t\t\tcg.numScores = 0;\n\t\t}\n\t} else {\n\t\t// show the cached contents even if they just pressed if it\n\t\t// is within two seconds\n\t\tcg.showScores = qtrue;\n\t}\n}\n\nstatic void CG_ScoresUp_f( void ) {\n\tif ( cg.showScores ) {\n\t\tcg.showScores = qfalse;\n\t\tcg.scoreFadeTime = cg.time;\n\t}\n}\n\nstatic void CG_TellTarget_f( void ) {\n\tint\t\tclientNum;\n\tchar\tcommand[128];\n\tchar\tmessage[128];\n\n\tclientNum = CG_CrosshairPlayer();\n\tif ( clientNum == -1 ) {\n\t\treturn;\n\t}\n\n\ttrap_Args( message, 128 );\n\tCom_sprintf( command, 128, \"tell %i %s\", clientNum, message );\n\ttrap_SendClientCommand( command );\n}\n\nstatic void CG_TellAttacker_f( void ) {\n\tint\t\tclientNum;\n\tchar\tcommand[128];\n\tchar\tmessage[128];\n\n\tclientNum = CG_LastAttacker();\n\tif ( clientNum == -1 ) {\n\t\treturn;\n\t}\n\n\ttrap_Args( message, 128 );\n\tCom_sprintf( command, 128, \"tell %i %s\", clientNum, message );\n\ttrap_SendClientCommand( command );\n}\n\nstatic void CG_VoiceTellTarget_f( void ) {\n\tint\t\tclientNum;\n\tchar\tcommand[128];\n\tchar\tmessage[128];\n\n\tclientNum = CG_CrosshairPlayer();\n\tif ( clientNum == -1 ) {\n\t\treturn;\n\t}\n\n\ttrap_Args( message, 128 );\n\tCom_sprintf( command, 128, \"vtell %i %s\", clientNum, message );\n\ttrap_SendClientCommand( command );\n}\n\nstatic void CG_VoiceTellAttacker_f( void ) {\n\tint\t\tclientNum;\n\tchar\tcommand[128];\n\tchar\tmessage[128];\n\n\tclientNum = CG_LastAttacker();\n\tif ( clientNum == -1 ) {\n\t\treturn;\n\t}\n\n\ttrap_Args( message, 128 );\n\tCom_sprintf( command, 128, \"vtell %i %s\", clientNum, message );\n\ttrap_SendClientCommand( command );\n}\n\n/*\n==================\nCG_StartOrbit_f\n==================\n*/\n\nstatic void CG_StartOrbit_f( void ) {\n\tchar var[MAX_TOKEN_CHARS];\n\n\ttrap_Cvar_VariableStringBuffer( \"developer\", var, sizeof( var ) );\n\tif ( !atoi(var) ) {\n\t\treturn;\n\t}\n\tif (cg_cameraOrbit.value != 0) {\n\t\ttrap_Cvar_Set (\"cg_cameraOrbit\", \"0\");\n\t\ttrap_Cvar_Set(\"cg_thirdPerson\", \"0\");\n\t} else {\n\t\ttrap_Cvar_Set(\"cg_cameraOrbit\", \"5\");\n\t\ttrap_Cvar_Set(\"cg_thirdPerson\", \"1\");\n\t\ttrap_Cvar_Set(\"cg_thirdPersonAngle\", \"0\");\n\t\ttrap_Cvar_Set(\"cg_thirdPersonRange\", \"100\");\n\t}\n}\n\n/*\nstatic void CG_Camera_f( void ) {\n\tchar name[1024];\n\ttrap_Argv( 1, name, sizeof(name));\n\tif (trap_loadCamera(name)) {\n\t\tcg.cameraMode = qtrue;\n\t\ttrap_startCamera(cg.time);\n\t} else {\n\t\tCG_Printf (\"Unable to load camera %s\\n\",name);\n\t}\n}\n*/\n\n\ntypedef struct {\n\tchar\t*cmd;\n\tvoid\t(*function)(void);\n} consoleCommand_t;\n\nstatic consoleCommand_t\tcommands[] = {\n\t{ \"testgun\", CG_TestGun_f },\n\t{ \"testmodel\", CG_TestModel_f },\n\t{ \"nextframe\", CG_TestModelNextFrame_f },\n\t{ \"prevframe\", CG_TestModelPrevFrame_f },\n\t{ \"nextskin\", CG_TestModelNextSkin_f },\n\t{ \"prevskin\", CG_TestModelPrevSkin_f },\n\t{ \"viewpos\", CG_Viewpos_f },\n\t{ \"+scores\", CG_ScoresDown_f },\n\t{ \"-scores\", CG_ScoresUp_f },\n\t{ \"+zoom\", CG_ZoomDown_f },\n\t{ \"-zoom\", CG_ZoomUp_f },\n\t{ \"sizeup\", CG_SizeUp_f },\n\t{ \"sizedown\", CG_SizeDown_f },\n\t{ \"weapnext\", CG_NextWeapon_f },\n\t{ \"weapprev\", CG_PrevWeapon_f },\n\t{ \"weapon\", CG_Weapon_f },\n\t{ \"tell_target\", CG_TellTarget_f },\n\t{ \"tell_attacker\", CG_TellAttacker_f },\n\t{ \"vtell_target\", CG_VoiceTellTarget_f },\n\t{ \"vtell_attacker\", CG_VoiceTellAttacker_f },\n\t{ \"tcmd\", CG_TargetCommand_f },\n\t{ \"startOrbit\", CG_StartOrbit_f },\n\t//{ \"camera\", CG_Camera_f },\n\t{ \"loaddeferred\", CG_LoadDeferredPlayers }\t\n};\n\n\n/*\n=================\nCG_ConsoleCommand\n\nThe string has been tokenized and can be retrieved with\nCmd_Argc() / Cmd_Argv()\n=================\n*/\nqboolean CG_ConsoleCommand( void ) {\n\tconst char\t*cmd;\n\tint\t\ti;\n\n\tcmd = CG_Argv(0);\n\n\tfor ( i = 0 ; i < sizeof( commands ) / sizeof( commands[0] ) ; i++ ) {\n\t\tif ( !Q_stricmp( cmd, commands[i].cmd ) ) {\n\t\t\tcommands[i].function();\n\t\t\treturn qtrue;\n\t\t}\n\t}\n\n\treturn qfalse;\n}\n\n\n/*\n=================\nCG_InitConsoleCommands\n\nLet the client system know about all of our commands\nso it can perform tab completion\n=================\n*/\nvoid CG_InitConsoleCommands( void ) {\n\tint\t\ti;\n\n\tfor ( i = 0 ; i < sizeof( commands ) / sizeof( commands[0] ) ; i++ ) {\n\t\ttrap_AddCommand( commands[i].cmd );\n\t}\n\n\t//\n\t// the game server will interpret these commands, which will be automatically\n\t// forwarded to the server after they are not recognized locally\n\t//\n\ttrap_AddCommand (\"kill\");\n\ttrap_AddCommand (\"say\");\n\ttrap_AddCommand (\"say_team\");\n\ttrap_AddCommand (\"tell\");\n\ttrap_AddCommand (\"vsay\");\n\ttrap_AddCommand (\"vsay_team\");\n\ttrap_AddCommand (\"vtell\");\n\ttrap_AddCommand (\"vtaunt\");\n\ttrap_AddCommand (\"vosay\");\n\ttrap_AddCommand (\"vosay_team\");\n\ttrap_AddCommand (\"votell\");\n\ttrap_AddCommand (\"give\");\n\ttrap_AddCommand (\"god\");\n\ttrap_AddCommand (\"notarget\");\n\ttrap_AddCommand (\"noclip\");\n\ttrap_AddCommand (\"team\");\n\ttrap_AddCommand (\"follow\");\n\ttrap_AddCommand (\"levelshot\");\n\ttrap_AddCommand (\"addbot\");\n\ttrap_AddCommand (\"setviewpos\");\n\ttrap_AddCommand (\"callvote\");\n\ttrap_AddCommand (\"vote\");\n\ttrap_AddCommand (\"callteamvote\");\n\ttrap_AddCommand (\"teamvote\");\n\ttrap_AddCommand (\"stats\");\n\ttrap_AddCommand (\"teamtask\");\n\ttrap_AddCommand (\"loaddefered\");\t// spelled wrong, but not changing for demo\n}\n"
  },
  {
    "path": "src/cgame/cg_draw.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n// cg_draw.c -- draw all of the graphical elements during\n// active (after loading) gameplay\n\n#include \"cg_local.h\"\n\nint drawTeamOverlayModificationCount = -1;\n\nint sortedTeamPlayers[TEAM_MAXOVERLAY];\nint\tnumSortedTeamPlayers;\n\nchar systemChat[256];\nchar teamChat1[256];\nchar teamChat2[256];\n\n/*\n==============\nCG_DrawField\n\nDraws large numbers for status bar and powerups\n==============\n*/\nstatic void CG_DrawField (int x, int y, int width, int value) {\n\tchar\tnum[16], *ptr;\n\tint\t\tl;\n\tint\t\tframe;\n\n\tif ( width < 1 ) {\n\t\treturn;\n\t}\n\n\t// draw number string\n\tif ( width > 5 ) {\n\t\twidth = 5;\n\t}\n\n\tswitch ( width ) {\n\tcase 1:\n\t\tvalue = value > 9 ? 9 : value;\n\t\tvalue = value < 0 ? 0 : value;\n\t\tbreak;\n\tcase 2:\n\t\tvalue = value > 99 ? 99 : value;\n\t\tvalue = value < -9 ? -9 : value;\n\t\tbreak;\n\tcase 3:\n\t\tvalue = value > 999 ? 999 : value;\n\t\tvalue = value < -99 ? -99 : value;\n\t\tbreak;\n\tcase 4:\n\t\tvalue = value > 9999 ? 9999 : value;\n\t\tvalue = value < -999 ? -999 : value;\n\t\tbreak;\n\t}\n\n\tCom_sprintf (num, sizeof(num), \"%i\", value);\n\tl = (int)strlen(num);\n\tif (l > width)\n\t\tl = width;\n\tx += 2 + CHAR_WIDTH*(width - l);\n\n\tptr = num;\n\twhile (*ptr && l)\n\t{\n\t\tif (*ptr == '-')\n\t\t\tframe = STAT_MINUS;\n\t\telse\n\t\t\tframe = *ptr -'0';\n\n\t\tCG_DrawPic( x,y, CHAR_WIDTH, CHAR_HEIGHT, cgs.media.numberShaders[frame] );\n\t\tx += CHAR_WIDTH;\n\t\tptr++;\n\t\tl--;\n\t}\n}\n\n/*\n================\nCG_Draw3DModel\n\n================\n*/\nvoid CG_Draw3DModel( float x, float y, float w, float h, qhandle_t model, qhandle_t skin, vec3_t origin, vec3_t angles ) {\n\trefdef_t\t\trefdef;\n\trefEntity_t\t\tent;\n\n\tif ( !cg_draw3dIcons.integer || !cg_drawIcons.integer ) {\n\t\treturn;\n\t}\n\n\tCG_AdjustFrom640( &x, &y, &w, &h );\n\n\tmemset( &refdef, 0, sizeof( refdef ) );\n\n\tmemset( &ent, 0, sizeof( ent ) );\n\tAnglesToAxis( angles, ent.axis );\n\tVectorCopy( origin, ent.origin );\n\tent.hModel = model;\n\tent.customSkin = skin;\n\tent.renderfx = RF_NOSHADOW;\t\t// no stencil shadows\n\n\trefdef.rdflags = RDF_NOWORLDMODEL;\n\n\tAxisClear( refdef.viewaxis );\n\n\trefdef.fov_x = 30;\n\trefdef.fov_y = 30;\n\n\trefdef.x = x;\n\trefdef.y = y;\n\trefdef.width = w;\n\trefdef.height = h;\n\n\trefdef.time = cg.time;\n\n\ttrap_R_ClearScene();\n\ttrap_R_AddRefEntityToScene( &ent );\n\ttrap_R_RenderScene( &refdef );\n}\n\n/*\n================\nCG_DrawHead\n\nUsed for both the status bar and the scoreboard\n================\n*/\nvoid CG_DrawHead( float x, float y, float w, float h, int clientNum, vec3_t headAngles ) {\n\tclipHandle_t\tcm;\n\tclientInfo_t\t*ci;\n\tfloat\t\t\tlen;\n\tvec3_t\t\t\torigin;\n\tvec3_t\t\t\tmins, maxs;\n\n\tci = &cgs.clientinfo[ clientNum ];\n\n\tif ( cg_draw3dIcons.integer ) {\n\t\tcm = ci->headModel;\n\t\tif ( !cm ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// offset the origin y and z to center the head\n\t\ttrap_R_ModelBounds( cm, mins, maxs );\n\n\t\torigin[2] = -0.5 * ( mins[2] + maxs[2] );\n\t\torigin[1] = 0.5 * ( mins[1] + maxs[1] );\n\n\t\t// calculate distance so the head nearly fills the box\n\t\t// assume heads are taller than wide\n\t\tlen = 0.7 * ( maxs[2] - mins[2] );\t\t\n\t\torigin[0] = len / 0.268;\t// len / tan( fov/2 )\n\n\t\t// allow per-model tweaking\n\t\tVectorAdd( origin, ci->headOffset, origin );\n\n\t\tCG_Draw3DModel( x, y, w, h, ci->headModel, ci->headSkin, origin, headAngles );\n\t} else if ( cg_drawIcons.integer ) {\n\t\tCG_DrawPic( x, y, w, h, ci->modelIcon );\n\t}\n\n\t// if they are deferred, draw a cross out\n\tif ( ci->deferred ) {\n\t\tCG_DrawPic( x, y, w, h, cgs.media.deferShader );\n\t}\n}\n\n/*\n================\nCG_DrawFlagModel\n\nUsed for both the status bar and the scoreboard\n================\n*/\nvoid CG_DrawFlagModel( float x, float y, float w, float h, int team, qboolean force2D ) {\n\tqhandle_t\t\tcm;\n\tfloat\t\t\tlen;\n\tvec3_t\t\t\torigin, angles;\n\tvec3_t\t\t\tmins, maxs;\n\tqhandle_t\t\thandle;\n\n\tif ( !force2D && cg_draw3dIcons.integer ) {\n\n\t\tVectorClear( angles );\n\n\t\tcm = cgs.media.redFlagModel;\n\n\t\t// offset the origin y and z to center the flag\n\t\ttrap_R_ModelBounds( cm, mins, maxs );\n\n\t\torigin[2] = -0.5 * ( mins[2] + maxs[2] );\n\t\torigin[1] = 0.5 * ( mins[1] + maxs[1] );\n\n\t\t// calculate distance so the flag nearly fills the box\n\t\t// assume heads are taller than wide\n\t\tlen = 0.5 * ( maxs[2] - mins[2] );\t\t\n\t\torigin[0] = len / 0.268;\t// len / tan( fov/2 )\n\n\t\tangles[YAW] = 60 * sin( cg.time / 2000.0 );;\n\n\t\tif( team == TEAM_RED ) {\n\t\t\thandle = cgs.media.redFlagModel;\n\t\t} else if( team == TEAM_BLUE ) {\n\t\t\thandle = cgs.media.blueFlagModel;\n\t\t} else if( team == TEAM_FREE ) {\n\t\t\thandle = cgs.media.neutralFlagModel;\n\t\t} else {\n\t\t\treturn;\n\t\t}\n\t\tCG_Draw3DModel( x, y, w, h, handle, 0, origin, angles );\n\t} else if ( cg_drawIcons.integer ) {\n\t\tgitem_t *item;\n\n\t\tif( team == TEAM_RED ) {\n\t\t\titem = BG_FindItemForPowerup( PW_REDFLAG );\n\t\t} else if( team == TEAM_BLUE ) {\n\t\t\titem = BG_FindItemForPowerup( PW_BLUEFLAG );\n\t\t} else if( team == TEAM_FREE ) {\n\t\t\titem = BG_FindItemForPowerup( PW_NEUTRALFLAG );\n\t\t} else {\n\t\t\treturn;\n\t\t}\n\t\tif (item) {\n\t\t  CG_DrawPic( x, y, w, h, cg_items[ ITEM_INDEX(item) ].icon );\n\t\t}\n\t}\n}\n\n/*\n================\nCG_DrawStatusBarHead\n\n================\n*/\nstatic void CG_DrawStatusBarHead( float x ) {\n\tvec3_t\t\tangles;\n\tfloat\t\tsize, stretch;\n\tfloat\t\tfrac;\n\n\tVectorClear( angles );\n\n\tif ( cg.damageTime && cg.time - cg.damageTime < DAMAGE_TIME ) {\n\t\tfrac = (float)(cg.time - cg.damageTime ) / DAMAGE_TIME;\n\t\tsize = ICON_SIZE * 1.25 * ( 1.5 - frac * 0.5 );\n\n\t\tstretch = size - ICON_SIZE * 1.25;\n\t\t// kick in the direction of damage\n\t\tx -= stretch * 0.5 + cg.damageX * stretch * 0.5;\n\n\t\tcg.headStartYaw = 180 + cg.damageX * 45;\n\n\t\tcg.headEndYaw = 180 + 20 * cos( crandom()*M_PI );\n\t\tcg.headEndPitch = 5 * cos( crandom()*M_PI );\n\n\t\tcg.headStartTime = cg.time;\n\t\tcg.headEndTime = cg.time + 100 + random() * 2000;\n\t} else {\n\t\tif ( cg.time >= cg.headEndTime ) {\n\t\t\t// select a new head angle\n\t\t\tcg.headStartYaw = cg.headEndYaw;\n\t\t\tcg.headStartPitch = cg.headEndPitch;\n\t\t\tcg.headStartTime = cg.headEndTime;\n\t\t\tcg.headEndTime = cg.time + 100 + random() * 2000;\n\n\t\t\tcg.headEndYaw = 180 + 20 * cos( crandom()*M_PI );\n\t\t\tcg.headEndPitch = 5 * cos( crandom()*M_PI );\n\t\t}\n\n\t\tsize = ICON_SIZE * 1.25;\n\t}\n\n\t// if the server was frozen for a while we may have a bad head start time\n\tif ( cg.headStartTime > cg.time ) {\n\t\tcg.headStartTime = cg.time;\n\t}\n\n\tfrac = ( cg.time - cg.headStartTime ) / (float)( cg.headEndTime - cg.headStartTime );\n\tfrac = frac * frac * ( 3 - 2 * frac );\n\tangles[YAW] = cg.headStartYaw + ( cg.headEndYaw - cg.headStartYaw ) * frac;\n\tangles[PITCH] = cg.headStartPitch + ( cg.headEndPitch - cg.headStartPitch ) * frac;\n\n\tCG_DrawHead( x, 480 - size, size, size, \n\t\t\t\tcg.snap->ps.clientNum, angles );\n}\n\n/*\n================\nCG_DrawStatusBarFlag\n\n================\n*/\nstatic void CG_DrawStatusBarFlag( float x, int team ) {\n\tCG_DrawFlagModel( x, 480 - ICON_SIZE, ICON_SIZE, ICON_SIZE, team, qfalse );\n}\n\n/*\n================\nCG_DrawTeamBackground\n\n================\n*/\nvoid CG_DrawTeamBackground( int x, int y, int w, int h, float alpha, int team )\n{\n\tvec4_t\t\thcolor;\n\n\thcolor[3] = alpha;\n\tif ( team == TEAM_RED ) {\n\t\thcolor[0] = 1;\n\t\thcolor[1] = 0;\n\t\thcolor[2] = 0;\n\t} else if ( team == TEAM_BLUE ) {\n\t\thcolor[0] = 0;\n\t\thcolor[1] = 0;\n\t\thcolor[2] = 1;\n\t} else {\n\t\treturn;\n\t}\n\ttrap_R_SetColor( hcolor );\n\tCG_DrawPic( x, y, w, h, cgs.media.teamStatusBar );\n\ttrap_R_SetColor( NULL );\n}\n\n/*\n================\nCG_DrawStatusBar\n\n================\n*/\nstatic void CG_DrawStatusBar( void ) {\n\tint\t\t\tcolor;\n\tcentity_t\t*cent;\n\tplayerState_t\t*ps;\n\tint\t\t\tvalue;\n\tvec4_t\t\thcolor;\n\tvec3_t\t\tangles;\n\tvec3_t\t\torigin;\n\n\tstatic float colors[4][4] = { \n//\t\t{ 0.2, 1.0, 0.2, 1.0 } , { 1.0, 0.2, 0.2, 1.0 }, {0.5, 0.5, 0.5, 1} };\n\t\t{ 1.0f, 0.69f, 0.0f, 1.0f },    // normal\n\t\t{ 1.0f, 0.2f, 0.2f, 1.0f },     // low health\n\t\t{ 0.5f, 0.5f, 0.5f, 1.0f },     // weapon firing\n\t\t{ 1.0f, 1.0f, 1.0f, 1.0f } };   // health > 100\n\n\tif ( cg_drawStatus.integer == 0 ) {\n\t\treturn;\n\t}\n\n\t// draw the team background\n\tCG_DrawTeamBackground( 0, 420, 640, 60, 0.33f, cg.snap->ps.persistant[PERS_TEAM] );\n\n\tcent = &cg_entities[cg.snap->ps.clientNum];\n\tps = &cg.snap->ps;\n\n\tVectorClear( angles );\n\n\t// draw any 3D icons first, so the changes back to 2D are minimized\n\tif ( cent->currentState.weapon && cg_weapons[ cent->currentState.weapon ].ammoModel ) {\n\t\torigin[0] = 70;\n\t\torigin[1] = 0;\n\t\torigin[2] = 0;\n\t\tangles[YAW] = 90 + 20 * sin( cg.time / 1000.0 );\n\t\tCG_Draw3DModel( CHAR_WIDTH*3 + TEXT_ICON_SPACE, 432, ICON_SIZE, ICON_SIZE,\n\t\t\t\t\t   cg_weapons[ cent->currentState.weapon ].ammoModel, 0, origin, angles );\n\t}\n\n\tCG_DrawStatusBarHead( 185 + CHAR_WIDTH*3 + TEXT_ICON_SPACE );\n\n\tif( cg.predictedPlayerState.powerups[PW_REDFLAG] ) {\n\t\tCG_DrawStatusBarFlag( 185 + CHAR_WIDTH*3 + TEXT_ICON_SPACE + ICON_SIZE, TEAM_RED );\n\t} else if( cg.predictedPlayerState.powerups[PW_BLUEFLAG] ) {\n\t\tCG_DrawStatusBarFlag( 185 + CHAR_WIDTH*3 + TEXT_ICON_SPACE + ICON_SIZE, TEAM_BLUE );\n\t} else if( cg.predictedPlayerState.powerups[PW_NEUTRALFLAG] ) {\n\t\tCG_DrawStatusBarFlag( 185 + CHAR_WIDTH*3 + TEXT_ICON_SPACE + ICON_SIZE, TEAM_FREE );\n\t}\n\n\tif ( ps->stats[ STAT_ARMOR ] ) {\n\t\torigin[0] = 90;\n\t\torigin[1] = 0;\n\t\torigin[2] = -10;\n\t\tangles[YAW] = ( cg.time & 2047 ) * 360 / 2048.0;\n\t\tCG_Draw3DModel( 370 + CHAR_WIDTH*3 + TEXT_ICON_SPACE, 432, ICON_SIZE, ICON_SIZE,\n\t\t\t\t\t   cgs.media.armorModel, 0, origin, angles );\n\t}\n\n\t//\n\t// ammo\n\t//\n\tif ( cent->currentState.weapon ) {\n\t\tvalue = ps->ammo[cent->currentState.weapon];\n\t\tif ( value > -1 ) {\n\t\t\tif ( cg.predictedPlayerState.weaponstate == WEAPON_FIRING\n\t\t\t\t&& cg.predictedPlayerState.weaponTime > 100 ) {\n\t\t\t\t// draw as dark grey when reloading\n\t\t\t\tcolor = 2;\t// dark grey\n\t\t\t} else {\n\t\t\t\tif ( value >= 0 ) {\n\t\t\t\t\tcolor = 0;\t// green\n\t\t\t\t} else {\n\t\t\t\t\tcolor = 1;\t// red\n\t\t\t\t}\n\t\t\t}\n\t\t\ttrap_R_SetColor( colors[color] );\n\t\t\t\n\t\t\tCG_DrawField (0, 432, 3, value);\n\t\t\ttrap_R_SetColor( NULL );\n\n\t\t\t// if we didn't draw a 3D icon, draw a 2D icon for ammo\n\t\t\tif ( !cg_draw3dIcons.integer && cg_drawIcons.integer ) {\n\t\t\t\tqhandle_t\ticon;\n\n\t\t\t\ticon = cg_weapons[ cg.predictedPlayerState.weapon ].ammoIcon;\n\t\t\t\tif ( icon ) {\n\t\t\t\t\tCG_DrawPic( CHAR_WIDTH*3 + TEXT_ICON_SPACE, 432, ICON_SIZE, ICON_SIZE, icon );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t//\n\t// health\n\t//\n\tvalue = ps->stats[STAT_HEALTH];\n\tif ( value > 100 ) {\n\t\ttrap_R_SetColor( colors[3] );\t\t// white\n\t} else if (value > 25) {\n\t\ttrap_R_SetColor( colors[0] );\t// green\n\t} else if (value > 0) {\n\t\tcolor = (cg.time >> 8) & 1;\t// flash\n\t\ttrap_R_SetColor( colors[color] );\n\t} else {\n\t\ttrap_R_SetColor( colors[1] );\t// red\n\t}\n\n\t// stretch the health up when taking damage\n\tCG_DrawField ( 185, 432, 3, value);\n\tCG_ColorForHealth( hcolor );\n\ttrap_R_SetColor( hcolor );\n\n\n\t//\n\t// armor\n\t//\n\tvalue = ps->stats[STAT_ARMOR];\n\tif (value > 0 ) {\n\t\ttrap_R_SetColor( colors[0] );\n\t\tCG_DrawField (370, 432, 3, value);\n\t\ttrap_R_SetColor( NULL );\n\t\t// if we didn't draw a 3D icon, draw a 2D icon for armor\n\t\tif ( !cg_draw3dIcons.integer && cg_drawIcons.integer ) {\n\t\t\tCG_DrawPic( 370 + CHAR_WIDTH*3 + TEXT_ICON_SPACE, 432, ICON_SIZE, ICON_SIZE, cgs.media.armorIcon );\n\t\t}\n\n\t}\n}\n\n/*\n===========================================================================================\n\n  UPPER RIGHT CORNER\n\n===========================================================================================\n*/\n\n/*\n================\nCG_DrawAttacker\n\n================\n*/\nstatic float CG_DrawAttacker( float y ) {\n\tint\t\t\tt;\n\tfloat\t\tsize;\n\tvec3_t\t\tangles;\n\tconst char\t*info;\n\tconst char\t*name;\n\tint\t\t\tclientNum;\n\n\tif ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) {\n\t\treturn y;\n\t}\n\n\tif ( !cg.attackerTime ) {\n\t\treturn y;\n\t}\n\n\tclientNum = cg.predictedPlayerState.persistant[PERS_ATTACKER];\n\tif ( clientNum < 0 || clientNum >= MAX_CLIENTS || clientNum == cg.snap->ps.clientNum ) {\n\t\treturn y;\n\t}\n\n\tt = cg.time - cg.attackerTime;\n\tif ( t > ATTACKER_HEAD_TIME ) {\n\t\tcg.attackerTime = 0;\n\t\treturn y;\n\t}\n\n\tsize = ICON_SIZE * 1.25;\n\n\tangles[PITCH] = 0;\n\tangles[YAW] = 180;\n\tangles[ROLL] = 0;\n\tCG_DrawHead( 640 - size, y, size, size, clientNum, angles );\n\n\tinfo = CG_ConfigString( CS_PLAYERS + clientNum );\n\tname = Info_ValueForKey(  info, \"n\" );\n\ty += size;\n\tCG_DrawBigString( 640 - ( Q_PrintStrlen( name ) * BIGCHAR_WIDTH), y, name, 0.5 );\n\n\treturn y + BIGCHAR_HEIGHT + 2;\n}\n\n/*\n==================\nCG_DrawSnapshot\n==================\n*/\nstatic float CG_DrawSnapshot( float y ) {\n\tchar\t\t*s;\n\tint\t\t\tw;\n\n\ts = va( \"time:%i snap:%i cmd:%i\", cg.snap->serverTime, \n\t\tcg.latestSnapshotNum, cgs.serverCommandSequence );\n\tw = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;\n\n\tCG_DrawBigString( 635 - w, y + 2, s, 1.0F);\n\n\treturn y + BIGCHAR_HEIGHT + 4;\n}\n\n/*\n==================\nCG_DrawFPS\n==================\n*/\n#define\tFPS_FRAMES\t4\nstatic float CG_DrawFPS( float y ) {\n\tchar\t\t*s;\n\tint\t\t\tw;\n\tstatic int\tpreviousTimes[FPS_FRAMES];\n\tstatic int\tindex;\n\tint\t\ti, total;\n\tint\t\tfps;\n\tstatic\tint\tprevious;\n\tint\t\tt, frameTime;\n\n\t// don't use serverTime, because that will be drifting to\n\t// correct for internet lag changes, timescales, timedemos, etc\n\tt = trap_Milliseconds();\n\tframeTime = t - previous;\n\tprevious = t;\n\n\tpreviousTimes[index % FPS_FRAMES] = frameTime;\n\tindex++;\n\tif ( index > FPS_FRAMES ) {\n\t\t// average multiple frames together to smooth changes out a bit\n\t\ttotal = 0;\n\t\tfor ( i = 0 ; i < FPS_FRAMES ; i++ ) {\n\t\t\ttotal += previousTimes[i];\n\t\t}\n\t\tif ( !total ) {\n\t\t\ttotal = 1;\n\t\t}\n\t\tfps = 1000 * FPS_FRAMES / total;\n\n\t\ts = va( \"%ifps\", fps );\n\t\tw = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;\n\n\t\tCG_DrawBigString( 635 - w, y + 2, s, 1.0F);\n\t}\n\n\treturn y + BIGCHAR_HEIGHT + 4;\n}\n\n/*\n=================\nCG_DrawTimer\n=================\n*/\nstatic float CG_DrawTimer( float y ) {\n\tchar\t\t*s;\n\tint\t\t\tw;\n\tint\t\t\tmins, seconds, tens;\n\tint\t\t\tmsec;\n\n\tmsec = cg.time - cgs.levelStartTime;\n\n\tseconds = msec / 1000;\n\tmins = seconds / 60;\n\tseconds -= mins * 60;\n\ttens = seconds / 10;\n\tseconds -= tens * 10;\n\n\ts = va( \"%i:%i%i\", mins, tens, seconds );\n\tw = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;\n\n\tCG_DrawBigString( 635 - w, y + 2, s, 1.0F);\n\n\treturn y + BIGCHAR_HEIGHT + 4;\n}\n\n\n/*\n=================\nCG_DrawTeamOverlay\n=================\n*/\n\nstatic float CG_DrawTeamOverlay( float y, qboolean right, qboolean upper ) {\n\tint x, w, h, xx;\n\tint i, j, len;\n\tconst char *p;\n\tvec4_t\t\thcolor;\n\tint pwidth, lwidth;\n\tint plyrs;\n\tchar st[16];\n\tclientInfo_t *ci;\n\tgitem_t\t*item;\n\tint ret_y, count;\n\n\tif ( !cg_drawTeamOverlay.integer ) {\n\t\treturn y;\n\t}\n\n\tif ( cg.snap->ps.persistant[PERS_TEAM] != TEAM_RED && cg.snap->ps.persistant[PERS_TEAM] != TEAM_BLUE ) {\n\t\treturn y; // Not on any team\n\t}\n\n\tplyrs = 0;\n\n\t// max player name width\n\tpwidth = 0;\n\tcount = (numSortedTeamPlayers > 8) ? 8 : numSortedTeamPlayers;\n\tfor (i = 0; i < count; i++) {\n\t\tci = cgs.clientinfo + sortedTeamPlayers[i];\n\t\tif ( ci->infoValid && ci->team == cg.snap->ps.persistant[PERS_TEAM]) {\n\t\t\tplyrs++;\n\t\t\tlen = CG_DrawStrlen(ci->name);\n\t\t\tif (len > pwidth)\n\t\t\t\tpwidth = len;\n\t\t}\n\t}\n\n\tif (!plyrs)\n\t\treturn y;\n\n\tif (pwidth > TEAM_OVERLAY_MAXNAME_WIDTH)\n\t\tpwidth = TEAM_OVERLAY_MAXNAME_WIDTH;\n\n\t// max location name width\n\tlwidth = 0;\n\tfor (i = 1; i < MAX_LOCATIONS; i++) {\n\t\tp = CG_ConfigString(CS_LOCATIONS + i);\n\t\tif (p && *p) {\n\t\t\tlen = CG_DrawStrlen(p);\n\t\t\tif (len > lwidth)\n\t\t\t\tlwidth = len;\n\t\t}\n\t}\n\n\tif (lwidth > TEAM_OVERLAY_MAXLOCATION_WIDTH)\n\t\tlwidth = TEAM_OVERLAY_MAXLOCATION_WIDTH;\n\n\tw = (pwidth + lwidth + 4 + 7) * TINYCHAR_WIDTH;\n\n\tif ( right )\n\t\tx = 640 - w;\n\telse\n\t\tx = 0;\n\n\th = plyrs * TINYCHAR_HEIGHT;\n\n\tif ( upper ) {\n\t\tret_y = y + h;\n\t} else {\n\t\ty -= h;\n\t\tret_y = y;\n\t}\n\n\tif ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_RED ) {\n\t\thcolor[0] = 1.0f;\n\t\thcolor[1] = 0.0f;\n\t\thcolor[2] = 0.0f;\n\t\thcolor[3] = 0.33f;\n\t} else { // if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE )\n\t\thcolor[0] = 0.0f;\n\t\thcolor[1] = 0.0f;\n\t\thcolor[2] = 1.0f;\n\t\thcolor[3] = 0.33f;\n\t}\n\ttrap_R_SetColor( hcolor );\n\tCG_DrawPic( x, y, w, h, cgs.media.teamStatusBar );\n\ttrap_R_SetColor( NULL );\n\n\tfor (i = 0; i < count; i++) {\n\t\tci = cgs.clientinfo + sortedTeamPlayers[i];\n\t\tif ( ci->infoValid && ci->team == cg.snap->ps.persistant[PERS_TEAM]) {\n\n\t\t\thcolor[0] = hcolor[1] = hcolor[2] = hcolor[3] = 1.0;\n\n\t\t\txx = x + TINYCHAR_WIDTH;\n\n\t\t\tCG_DrawStringExt( xx, y,\n\t\t\t\tci->name, hcolor, qfalse, qfalse,\n\t\t\t\tTINYCHAR_WIDTH, TINYCHAR_HEIGHT, TEAM_OVERLAY_MAXNAME_WIDTH);\n\n\t\t\tif (lwidth) {\n\t\t\t\tp = CG_ConfigString(CS_LOCATIONS + ci->location);\n\t\t\t\tif (!p || !*p)\n\t\t\t\t\tp = \"unknown\";\n\t\t\t\tlen = CG_DrawStrlen(p);\n\t\t\t\tif (len > lwidth)\n\t\t\t\t\tlen = lwidth;\n\n//\t\t\t\txx = x + TINYCHAR_WIDTH * 2 + TINYCHAR_WIDTH * pwidth + \n//\t\t\t\t\t((lwidth/2 - len/2) * TINYCHAR_WIDTH);\n\t\t\t\txx = x + TINYCHAR_WIDTH * 2 + TINYCHAR_WIDTH * pwidth;\n\t\t\t\tCG_DrawStringExt( xx, y,\n\t\t\t\t\tp, hcolor, qfalse, qfalse, TINYCHAR_WIDTH, TINYCHAR_HEIGHT,\n\t\t\t\t\tTEAM_OVERLAY_MAXLOCATION_WIDTH);\n\t\t\t}\n\n\t\t\tCG_GetColorForHealth( ci->health, ci->armor, hcolor );\n\n\t\t\tCom_sprintf (st, sizeof(st), \"%3i %3i\", ci->health,\tci->armor);\n\n\t\t\txx = x + TINYCHAR_WIDTH * 3 + \n\t\t\t\tTINYCHAR_WIDTH * pwidth + TINYCHAR_WIDTH * lwidth;\n\n\t\t\tCG_DrawStringExt( xx, y,\n\t\t\t\tst, hcolor, qfalse, qfalse,\n\t\t\t\tTINYCHAR_WIDTH, TINYCHAR_HEIGHT, 0 );\n\n\t\t\t// draw weapon icon\n\t\t\txx += TINYCHAR_WIDTH * 3;\n\n\t\t\tif ( cg_weapons[ci->curWeapon].weaponIcon ) {\n\t\t\t\tCG_DrawPic( xx, y, TINYCHAR_WIDTH, TINYCHAR_HEIGHT, \n\t\t\t\t\tcg_weapons[ci->curWeapon].weaponIcon );\n\t\t\t} else {\n\t\t\t\tCG_DrawPic( xx, y, TINYCHAR_WIDTH, TINYCHAR_HEIGHT, \n\t\t\t\t\tcgs.media.deferShader );\n\t\t\t}\n\n\t\t\t// Draw powerup icons\n\t\t\tif (right) {\n\t\t\t\txx = x;\n\t\t\t} else {\n\t\t\t\txx = x + w - TINYCHAR_WIDTH;\n\t\t\t}\n\t\t\tfor (j = 0; j <= PW_NUM_POWERUPS; j++) {\n\t\t\t\tif (ci->powerups & (1 << j)) {\n\n\t\t\t\t\titem = BG_FindItemForPowerup( j );\n\n\t\t\t\t\tif (item) {\n\t\t\t\t\t\tCG_DrawPic( xx, y, TINYCHAR_WIDTH, TINYCHAR_HEIGHT, \n\t\t\t\t\t\ttrap_R_RegisterShader( item->icon ) );\n\t\t\t\t\t\tif (right) {\n\t\t\t\t\t\t\txx -= TINYCHAR_WIDTH;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\txx += TINYCHAR_WIDTH;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ty += TINYCHAR_HEIGHT;\n\t\t}\n\t}\n\n\treturn ret_y;\n//#endif\n}\n\n\n/*\n=====================\nCG_DrawUpperRight\n\n=====================\n*/\nstatic void CG_DrawUpperRight( void ) {\n\tfloat\ty;\n\n\ty = 0;\n\n\tif ( cgs.gametype >= GT_TEAM && cg_drawTeamOverlay.integer == 1 ) {\n\t\ty = CG_DrawTeamOverlay( y, qtrue, qtrue );\n\t} \n\tif ( cg_drawSnapshot.integer ) {\n\t\ty = CG_DrawSnapshot( y );\n\t}\n\tif ( cg_drawFPS.integer ) {\n\t\ty = CG_DrawFPS( y );\n\t}\n\tif ( cg_drawTimer.integer ) {\n\t\ty = CG_DrawTimer( y );\n\t}\n\tif ( cg_drawAttacker.integer ) {\n\t\ty = CG_DrawAttacker( y );\n\t}\n\n}\n\n/*\n===========================================================================================\n\n  LOWER RIGHT CORNER\n\n===========================================================================================\n*/\n\n/*\n=================\nCG_DrawScores\n\nDraw the small two score display\n=================\n*/\nstatic float CG_DrawScores( float y ) {\n\tconst char\t*s;\n\tint\t\t\ts1, s2, score;\n\tint\t\t\tx, w;\n\tint\t\t\tv;\n\tvec4_t\t\tcolor;\n\tfloat\t\ty1;\n\tgitem_t\t\t*item;\n\n\ts1 = cgs.scores1;\n\ts2 = cgs.scores2;\n\n\ty -=  BIGCHAR_HEIGHT + 8;\n\n\ty1 = y;\n\n\t// draw from the right side to left\n\tif ( cgs.gametype >= GT_TEAM ) {\n\t\tx = 640;\n\t\tcolor[0] = 0.0f;\n\t\tcolor[1] = 0.0f;\n\t\tcolor[2] = 1.0f;\n\t\tcolor[3] = 0.33f;\n\t\ts = va( \"%2i\", s2 );\n\t\tw = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;\n\t\tx -= w;\n\t\tCG_FillRect( x, y-4,  w, BIGCHAR_HEIGHT+8, color );\n\t\tif ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE ) {\n\t\t\tCG_DrawPic( x, y-4, w, BIGCHAR_HEIGHT+8, cgs.media.selectShader );\n\t\t}\n\t\tCG_DrawBigString( x + 4, y, s, 1.0F);\n\n\t\tif ( cgs.gametype == GT_CTF ) {\n\t\t\t// Display flag status\n\t\t\titem = BG_FindItemForPowerup( PW_BLUEFLAG );\n\n\t\t\tif (item) {\n\t\t\t\ty1 = y - BIGCHAR_HEIGHT - 8;\n\t\t\t\tif( cgs.blueflag >= 0 && cgs.blueflag <= 2 ) {\n\t\t\t\t\tCG_DrawPic( x, y1-4, w, BIGCHAR_HEIGHT+8, cgs.media.blueFlagShader[cgs.blueflag] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcolor[0] = 1.0f;\n\t\tcolor[1] = 0.0f;\n\t\tcolor[2] = 0.0f;\n\t\tcolor[3] = 0.33f;\n\t\ts = va( \"%2i\", s1 );\n\t\tw = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;\n\t\tx -= w;\n\t\tCG_FillRect( x, y-4,  w, BIGCHAR_HEIGHT+8, color );\n\t\tif ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_RED ) {\n\t\t\tCG_DrawPic( x, y-4, w, BIGCHAR_HEIGHT+8, cgs.media.selectShader );\n\t\t}\n\t\tCG_DrawBigString( x + 4, y, s, 1.0F);\n\n\t\tif ( cgs.gametype == GT_CTF ) {\n\t\t\t// Display flag status\n\t\t\titem = BG_FindItemForPowerup( PW_REDFLAG );\n\n\t\t\tif (item) {\n\t\t\t\ty1 = y - BIGCHAR_HEIGHT - 8;\n\t\t\t\tif( cgs.redflag >= 0 && cgs.redflag <= 2 ) {\n\t\t\t\t\tCG_DrawPic( x, y1-4, w, BIGCHAR_HEIGHT+8, cgs.media.redFlagShader[cgs.redflag] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif ( cgs.gametype >= GT_CTF ) {\n\t\t\tv = cgs.capturelimit;\n\t\t} else {\n\t\t\tv = cgs.fraglimit;\n\t\t}\n\t\tif ( v ) {\n\t\t\ts = va( \"%2i\", v );\n\t\t\tw = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;\n\t\t\tx -= w;\n\t\t\tCG_DrawBigString( x + 4, y, s, 1.0F);\n\t\t}\n\n\t} else {\n\t\tqboolean\tspectator;\n\n\t\tx = 640;\n\t\tscore = cg.snap->ps.persistant[PERS_SCORE];\n\t\tspectator = ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR );\n\n\t\t// always show your score in the second box if not in first place\n\t\tif ( s1 != score ) {\n\t\t\ts2 = score;\n\t\t}\n\t\tif ( s2 != SCORE_NOT_PRESENT ) {\n\t\t\ts = va( \"%2i\", s2 );\n\t\t\tw = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;\n\t\t\tx -= w;\n\t\t\tif ( !spectator && score == s2 && score != s1 ) {\n\t\t\t\tcolor[0] = 1.0f;\n\t\t\t\tcolor[1] = 0.0f;\n\t\t\t\tcolor[2] = 0.0f;\n\t\t\t\tcolor[3] = 0.33f;\n\t\t\t\tCG_FillRect( x, y-4,  w, BIGCHAR_HEIGHT+8, color );\n\t\t\t\tCG_DrawPic( x, y-4, w, BIGCHAR_HEIGHT+8, cgs.media.selectShader );\n\t\t\t} else {\n\t\t\t\tcolor[0] = 0.5f;\n\t\t\t\tcolor[1] = 0.5f;\n\t\t\t\tcolor[2] = 0.5f;\n\t\t\t\tcolor[3] = 0.33f;\n\t\t\t\tCG_FillRect( x, y-4,  w, BIGCHAR_HEIGHT+8, color );\n\t\t\t}\t\n\t\t\tCG_DrawBigString( x + 4, y, s, 1.0F);\n\t\t}\n\n\t\t// first place\n\t\tif ( s1 != SCORE_NOT_PRESENT ) {\n\t\t\ts = va( \"%2i\", s1 );\n\t\t\tw = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;\n\t\t\tx -= w;\n\t\t\tif ( !spectator && score == s1 ) {\n\t\t\t\tcolor[0] = 0.0f;\n\t\t\t\tcolor[1] = 0.0f;\n\t\t\t\tcolor[2] = 1.0f;\n\t\t\t\tcolor[3] = 0.33f;\n\t\t\t\tCG_FillRect( x, y-4,  w, BIGCHAR_HEIGHT+8, color );\n\t\t\t\tCG_DrawPic( x, y-4, w, BIGCHAR_HEIGHT+8, cgs.media.selectShader );\n\t\t\t} else {\n\t\t\t\tcolor[0] = 0.5f;\n\t\t\t\tcolor[1] = 0.5f;\n\t\t\t\tcolor[2] = 0.5f;\n\t\t\t\tcolor[3] = 0.33f;\n\t\t\t\tCG_FillRect( x, y-4,  w, BIGCHAR_HEIGHT+8, color );\n\t\t\t}\t\n\t\t\tCG_DrawBigString( x + 4, y, s, 1.0F);\n\t\t}\n\n\t\tif ( cgs.fraglimit ) {\n\t\t\ts = va( \"%2i\", cgs.fraglimit );\n\t\t\tw = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;\n\t\t\tx -= w;\n\t\t\tCG_DrawBigString( x + 4, y, s, 1.0F);\n\t\t}\n\n\t}\n\n\treturn y1 - 8;\n}\n\n/*\n================\nCG_DrawPowerups\n================\n*/\nstatic float CG_DrawPowerups( float y ) {\n\tint\t\tsorted[MAX_POWERUPS];\n\tint\t\tsortedTime[MAX_POWERUPS];\n\tint\t\ti, j, k;\n\tint\t\tactive;\n\tplayerState_t\t*ps;\n\tint\t\tt;\n\tgitem_t\t*item;\n\tint\t\tx;\n\tint\t\tcolor;\n\tfloat\tsize;\n\tfloat\tf;\n\tstatic float colors[2][4] = { \n    { 0.2f, 1.0f, 0.2f, 1.0f } , \n    { 1.0f, 0.2f, 0.2f, 1.0f } \n  };\n\n\tps = &cg.snap->ps;\n\n\tif ( ps->stats[STAT_HEALTH] <= 0 ) {\n\t\treturn y;\n\t}\n\n\t// sort the list by time remaining\n\tactive = 0;\n\tfor ( i = 0 ; i < MAX_POWERUPS ; i++ ) {\n\t\tif ( !ps->powerups[ i ] ) {\n\t\t\tcontinue;\n\t\t}\n\t\tt = ps->powerups[ i ] - cg.time;\n\t\t// ZOID--don't draw if the power up has unlimited time (999 seconds)\n\t\t// This is true of the CTF flags\n\t\tif ( t < 0 || t > 999000) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// insert into the list\n\t\tfor ( j = 0 ; j < active ; j++ ) {\n\t\t\tif ( sortedTime[j] >= t ) {\n\t\t\t\tfor ( k = active - 1 ; k >= j ; k-- ) {\n\t\t\t\t\tsorted[k+1] = sorted[k];\n\t\t\t\t\tsortedTime[k+1] = sortedTime[k];\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tsorted[j] = i;\n\t\tsortedTime[j] = t;\n\t\tactive++;\n\t}\n\n\t// draw the icons and timers\n\tx = 640 - ICON_SIZE - CHAR_WIDTH * 2;\n\tfor ( i = 0 ; i < active ; i++ ) {\n\t\titem = BG_FindItemForPowerup( sorted[i] );\n\n    if (item) {\n\n\t\t  color = 1;\n\n\t\t  y -= ICON_SIZE;\n\n\t\t  trap_R_SetColor( colors[color] );\n\t\t  CG_DrawField( x, y, 2, sortedTime[ i ] / 1000 );\n\n\t\t  t = ps->powerups[ sorted[i] ];\n\t\t  if ( t - cg.time >= POWERUP_BLINKS * POWERUP_BLINK_TIME ) {\n\t\t\t  trap_R_SetColor( NULL );\n\t\t  } else {\n\t\t\t  vec4_t\tmodulate;\n\n\t\t\t  f = (float)( t - cg.time ) / POWERUP_BLINK_TIME;\n\t\t\t  f -= (int)f;\n\t\t\t  modulate[0] = modulate[1] = modulate[2] = modulate[3] = f;\n\t\t\t  trap_R_SetColor( modulate );\n\t\t  }\n\n\t\t  if ( cg.powerupActive == sorted[i] && \n\t\t\t  cg.time - cg.powerupTime < PULSE_TIME ) {\n\t\t\t  f = 1.0 - ( ( (float)cg.time - cg.powerupTime ) / PULSE_TIME );\n\t\t\t  size = ICON_SIZE * ( 1.0 + ( PULSE_SCALE - 1.0 ) * f );\n\t\t  } else {\n\t\t\t  size = ICON_SIZE;\n\t\t  }\n\n\t\t  CG_DrawPic( 640 - size, y + ICON_SIZE / 2 - size / 2, \n\t\t\t  size, size, trap_R_RegisterShader( item->icon ) );\n    }\n\t}\n\ttrap_R_SetColor( NULL );\n\n\treturn y;\n}\n\n/*\n=====================\nCG_DrawLowerRight\n\n=====================\n*/\nstatic void CG_DrawLowerRight( void ) {\n\tfloat\ty;\n\n\ty = 480 - ICON_SIZE;\n\n\tif ( cgs.gametype >= GT_TEAM && cg_drawTeamOverlay.integer == 2 ) {\n\t\ty = CG_DrawTeamOverlay( y, qtrue, qfalse );\n\t} \n\n\ty = CG_DrawScores( y );\n\ty = CG_DrawPowerups( y );\n}\n\n/*\n===================\nCG_DrawPickupItem\n===================\n*/\nstatic int CG_DrawPickupItem( int y ) {\n\tint\t\tvalue;\n\tfloat\t*fadeColor;\n\n\tif ( cg.snap->ps.stats[STAT_HEALTH] <= 0 ) {\n\t\treturn y;\n\t}\n\n\ty -= ICON_SIZE;\n\n\tvalue = cg.itemPickup;\n\tif ( value ) {\n\t\tfadeColor = CG_FadeColor( cg.itemPickupTime, 3000 );\n\t\tif ( fadeColor ) {\n\t\t\tCG_RegisterItemVisuals( value );\n\t\t\ttrap_R_SetColor( fadeColor );\n\t\t\tCG_DrawPic( 8, y, ICON_SIZE, ICON_SIZE, cg_items[ value ].icon );\n\t\t\tCG_DrawBigString( ICON_SIZE + 16, y + (ICON_SIZE/2 - BIGCHAR_HEIGHT/2), bg_itemlist[ value ].pickup_name, fadeColor[0] );\n\t\t\ttrap_R_SetColor( NULL );\n\t\t}\n\t}\n\t\n\treturn y;\n}\n\n/*\n=====================\nCG_DrawLowerLeft\n\n=====================\n*/\nstatic void CG_DrawLowerLeft( void ) {\n\tfloat\ty;\n\n\ty = 480 - ICON_SIZE;\n\n\tif ( cgs.gametype >= GT_TEAM && cg_drawTeamOverlay.integer == 3 ) {\n\t\ty = CG_DrawTeamOverlay( y, qfalse, qfalse );\n\t} \n\n\n\ty = CG_DrawPickupItem( y );\n}\n\n\n//===========================================================================================\n\n/*\n=================\nCG_DrawTeamInfo\n=================\n*/\nstatic void CG_DrawTeamInfo( void ) {\n\tint w, h;\n\tint i, len;\n\tvec4_t\t\thcolor;\n\tint\t\tchatHeight;\n\n#define CHATLOC_Y 420 // bottom end\n#define CHATLOC_X 0\n\n\tif (cg_teamChatHeight.integer < TEAMCHAT_HEIGHT)\n\t\tchatHeight = cg_teamChatHeight.integer;\n\telse\n\t\tchatHeight = TEAMCHAT_HEIGHT;\n\tif (chatHeight <= 0)\n\t\treturn; // disabled\n\n\tif (cgs.teamLastChatPos != cgs.teamChatPos) {\n\t\tif (cg.time - cgs.teamChatMsgTimes[cgs.teamLastChatPos % chatHeight] > cg_teamChatTime.integer) {\n\t\t\tcgs.teamLastChatPos++;\n\t\t}\n\n\t\th = (cgs.teamChatPos - cgs.teamLastChatPos) * TINYCHAR_HEIGHT;\n\n\t\tw = 0;\n\n\t\tfor (i = cgs.teamLastChatPos; i < cgs.teamChatPos; i++) {\n\t\t\tlen = CG_DrawStrlen(cgs.teamChatMsgs[i % chatHeight]);\n\t\t\tif (len > w)\n\t\t\t\tw = len;\n\t\t}\n\t\tw *= TINYCHAR_WIDTH;\n\t\tw += TINYCHAR_WIDTH * 2;\n\n\t\tif ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_RED ) {\n\t\t\thcolor[0] = 1.0f;\n\t\t\thcolor[1] = 0.0f;\n\t\t\thcolor[2] = 0.0f;\n\t\t\thcolor[3] = 0.33f;\n\t\t} else if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE ) {\n\t\t\thcolor[0] = 0.0f;\n\t\t\thcolor[1] = 0.0f;\n\t\t\thcolor[2] = 1.0f;\n\t\t\thcolor[3] = 0.33f;\n\t\t} else {\n\t\t\thcolor[0] = 0.0f;\n\t\t\thcolor[1] = 1.0f;\n\t\t\thcolor[2] = 0.0f;\n\t\t\thcolor[3] = 0.33f;\n\t\t}\n\n\t\ttrap_R_SetColor( hcolor );\n\t\tCG_DrawPic( CHATLOC_X, CHATLOC_Y - h, 640, h, cgs.media.teamStatusBar );\n\t\ttrap_R_SetColor( NULL );\n\n\t\thcolor[0] = hcolor[1] = hcolor[2] = 1.0f;\n\t\thcolor[3] = 1.0f;\n\n\t\tfor (i = cgs.teamChatPos - 1; i >= cgs.teamLastChatPos; i--) {\n\t\t\tCG_DrawStringExt( CHATLOC_X + TINYCHAR_WIDTH, \n\t\t\t\tCHATLOC_Y - (cgs.teamChatPos - i)*TINYCHAR_HEIGHT, \n\t\t\t\tcgs.teamChatMsgs[i % chatHeight], hcolor, qfalse, qfalse,\n\t\t\t\tTINYCHAR_WIDTH, TINYCHAR_HEIGHT, 0 );\n\t\t}\n\t}\n}\n\n/*\n===================\nCG_DrawHoldableItem\n===================\n*/\nstatic void CG_DrawHoldableItem( void ) { \n\tint\t\tvalue;\n\n\tvalue = cg.snap->ps.stats[STAT_HOLDABLE_ITEM];\n\tif ( value ) {\n\t\tCG_RegisterItemVisuals( value );\n\t\tCG_DrawPic( 640-ICON_SIZE, (SCREEN_HEIGHT-ICON_SIZE)/2, ICON_SIZE, ICON_SIZE, cg_items[ value ].icon );\n\t}\n\n}\n\n/*\n===================\nCG_DrawReward\n===================\n*/\nstatic void CG_DrawReward( void ) { \n\tfloat\t*color;\n\tint\t\ti, count;\n\tfloat\tx, y;\n\tchar\tbuf[32];\n\n\tif ( !cg_drawRewards.integer ) {\n\t\treturn;\n\t}\n\n\tcolor = CG_FadeColor( cg.rewardTime, REWARD_TIME );\n\tif ( !color ) {\n\t\tif (cg.rewardStack > 0) {\n\t\t\tfor(i = 0; i < cg.rewardStack; i++) {\n\t\t\t\tcg.rewardSound[i] = cg.rewardSound[i+1];\n\t\t\t\tcg.rewardShader[i] = cg.rewardShader[i+1];\n\t\t\t\tcg.rewardCount[i] = cg.rewardCount[i+1];\n\t\t\t}\n\t\t\tcg.rewardTime = cg.time;\n\t\t\tcg.rewardStack--;\n\t\t\tcolor = CG_FadeColor( cg.rewardTime, REWARD_TIME );\n\t\t\ttrap_S_StartLocalSound(cg.rewardSound[0], CHAN_ANNOUNCER);\n\t\t} else {\n\t\t\treturn;\n\t\t}\n\t}\n\n\ttrap_R_SetColor( color );\n\n\t/*\n\tcount = cg.rewardCount[0]/10;\t\t\t\t// number of big rewards to draw\n\n\tif (count) {\n\t\ty = 4;\n\t\tx = 320 - count * ICON_SIZE;\n\t\tfor ( i = 0 ; i < count ; i++ ) {\n\t\t\tCG_DrawPic( x, y, (ICON_SIZE*2)-4, (ICON_SIZE*2)-4, cg.rewardShader[0] );\n\t\t\tx += (ICON_SIZE*2);\n\t\t}\n\t}\n\n\tcount = cg.rewardCount[0] - count*10;\t\t// number of small rewards to draw\n\t*/\n\n\tif ( cg.rewardCount[0] >= 10 ) {\n\t\ty = 56;\n\t\tx = 320 - ICON_SIZE/2;\n\t\tCG_DrawPic( x, y, ICON_SIZE-4, ICON_SIZE-4, cg.rewardShader[0] );\n\t\tCom_sprintf(buf, sizeof(buf), \"%d\", cg.rewardCount[0]);\n\t\tx = ( SCREEN_WIDTH - SMALLCHAR_WIDTH * CG_DrawStrlen( buf ) ) / 2;\n\t\tCG_DrawStringExt( x, y+ICON_SIZE, buf, color, qfalse, qtrue,\n\t\t\t\t\t\t\t\tSMALLCHAR_WIDTH, SMALLCHAR_HEIGHT, 0 );\n\t}\n\telse {\n\n\t\tcount = cg.rewardCount[0];\n\n\t\ty = 56;\n\t\tx = 320 - count * ICON_SIZE/2;\n\t\tfor ( i = 0 ; i < count ; i++ ) {\n\t\t\tCG_DrawPic( x, y, ICON_SIZE-4, ICON_SIZE-4, cg.rewardShader[0] );\n\t\t\tx += ICON_SIZE;\n\t\t}\n\t}\n\ttrap_R_SetColor( NULL );\n}\n\n\n/*\n===============================================================================\n\nLAGOMETER\n\n===============================================================================\n*/\n\n#define\tLAG_SAMPLES\t\t128\n\n\ntypedef struct {\n\tint\t\tframeSamples[LAG_SAMPLES];\n\tint\t\tframeCount;\n\tint\t\tsnapshotFlags[LAG_SAMPLES];\n\tint\t\tsnapshotSamples[LAG_SAMPLES];\n\tint\t\tsnapshotCount;\n} lagometer_t;\n\nlagometer_t\t\tlagometer;\n\n/*\n==============\nCG_AddLagometerFrameInfo\n\nAdds the current interpolate / extrapolate bar for this frame\n==============\n*/\nvoid CG_AddLagometerFrameInfo( void ) {\n\tint\t\t\toffset;\n\n\toffset = cg.time - cg.latestSnapshotTime;\n\tlagometer.frameSamples[ lagometer.frameCount & ( LAG_SAMPLES - 1) ] = offset;\n\tlagometer.frameCount++;\n}\n\n/*\n==============\nCG_AddLagometerSnapshotInfo\n\nEach time a snapshot is received, log its ping time and\nthe number of snapshots that were dropped before it.\n\nPass NULL for a dropped packet.\n==============\n*/\nvoid CG_AddLagometerSnapshotInfo( snapshot_t *snap ) {\n\t// dropped packet\n\tif ( !snap ) {\n\t\tlagometer.snapshotSamples[ lagometer.snapshotCount & ( LAG_SAMPLES - 1) ] = -1;\n\t\tlagometer.snapshotCount++;\n\t\treturn;\n\t}\n\n\t// add this snapshot's info\n\tlagometer.snapshotSamples[ lagometer.snapshotCount & ( LAG_SAMPLES - 1) ] = snap->ping;\n\tlagometer.snapshotFlags[ lagometer.snapshotCount & ( LAG_SAMPLES - 1) ] = snap->snapFlags;\n\tlagometer.snapshotCount++;\n}\n\n/*\n==============\nCG_DrawDisconnect\n\nShould we draw something differnet for long lag vs no packets?\n==============\n*/\nstatic void CG_DrawDisconnect( void ) {\n\tfloat\t\tx, y;\n\tint\t\t\tcmdNum;\n\tusercmd_t\tcmd;\n\tconst char\t\t*s;\n\tint\t\t\tw;  // bk010215 - FIXME char message[1024];\n\n\t// draw the phone jack if we are completely past our buffers\n\tcmdNum = trap_GetCurrentCmdNumber() - CMD_BACKUP + 1;\n\ttrap_GetUserCmd( cmdNum, &cmd );\n\tif ( cmd.serverTime <= cg.snap->ps.commandTime\n\t\t|| cmd.serverTime > cg.time ) {\t// special check for map_restart // bk 0102165 - FIXME\n\t\treturn;\n\t}\n\n\t// also add text in center of screen\n\ts = \"Connection Interrupted\"; // bk 010215 - FIXME\n\tw = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;\n\tCG_DrawBigString( 320 - w/2, 100, s, 1.0F);\n\n\t// blink the icon\n\tif ( ( cg.time >> 9 ) & 1 ) {\n\t\treturn;\n\t}\n\n\tx = 640 - 48;\n\ty = 480 - 48;\n\n\tCG_DrawPic( x, y, 48, 48, trap_R_RegisterShader(\"gfx/2d/net.tga\" ) );\n}\n\n\n#define\tMAX_LAGOMETER_PING\t900\n#define\tMAX_LAGOMETER_RANGE\t300\n\n/*\n==============\nCG_DrawLagometer\n==============\n*/\nstatic void CG_DrawLagometer( void ) {\n\tint\t\ta, x, y, i;\n\tfloat\tv;\n\tfloat\tax, ay, aw, ah, mid, range;\n\tint\t\tcolor;\n\tfloat\tvscale;\n\n\tif ( !cg_lagometer.integer || cgs.localServer ) {\n\t\tCG_DrawDisconnect();\n\t\treturn;\n\t}\n\n\t//\n\t// draw the graph\n\t//\n\tx = 640 - 48;\n\ty = 480 - 48;\n\n\ttrap_R_SetColor( NULL );\n\tCG_DrawPic( x, y, 48, 48, cgs.media.lagometerShader );\n\n\tax = x;\n\tay = y;\n\taw = 48;\n\tah = 48;\n\tCG_AdjustFrom640( &ax, &ay, &aw, &ah );\n\n\tcolor = -1;\n\trange = ah / 3;\n\tmid = ay + range;\n\n\tvscale = range / MAX_LAGOMETER_RANGE;\n\n\t// draw the frame interpoalte / extrapolate graph\n\tfor ( a = 0 ; a < aw ; a++ ) {\n\t\ti = ( lagometer.frameCount - 1 - a ) & (LAG_SAMPLES - 1);\n\t\tv = lagometer.frameSamples[i];\n\t\tv *= vscale;\n\t\tif ( v > 0 ) {\n\t\t\tif ( color != 1 ) {\n\t\t\t\tcolor = 1;\n\t\t\t\ttrap_R_SetColor( g_color_table[ColorIndex(COLOR_YELLOW)] );\n\t\t\t}\n\t\t\tif ( v > range ) {\n\t\t\t\tv = range;\n\t\t\t}\n\t\t\ttrap_R_DrawStretchPic ( ax + aw - a, mid - v, 1, v, 0, 0, 0, 0, cgs.media.whiteShader );\n\t\t} else if ( v < 0 ) {\n\t\t\tif ( color != 2 ) {\n\t\t\t\tcolor = 2;\n\t\t\t\ttrap_R_SetColor( g_color_table[ColorIndex(COLOR_BLUE)] );\n\t\t\t}\n\t\t\tv = -v;\n\t\t\tif ( v > range ) {\n\t\t\t\tv = range;\n\t\t\t}\n\t\t\ttrap_R_DrawStretchPic( ax + aw - a, mid, 1, v, 0, 0, 0, 0, cgs.media.whiteShader );\n\t\t}\n\t}\n\n\t// draw the snapshot latency / drop graph\n\trange = ah / 2;\n\tvscale = range / MAX_LAGOMETER_PING;\n\n\tfor ( a = 0 ; a < aw ; a++ ) {\n\t\ti = ( lagometer.snapshotCount - 1 - a ) & (LAG_SAMPLES - 1);\n\t\tv = lagometer.snapshotSamples[i];\n\t\tif ( v > 0 ) {\n\t\t\tif ( lagometer.snapshotFlags[i] & SNAPFLAG_RATE_DELAYED ) {\n\t\t\t\tif ( color != 5 ) {\n\t\t\t\t\tcolor = 5;\t// YELLOW for rate delay\n\t\t\t\t\ttrap_R_SetColor( g_color_table[ColorIndex(COLOR_YELLOW)] );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif ( color != 3 ) {\n\t\t\t\t\tcolor = 3;\n\t\t\t\t\ttrap_R_SetColor( g_color_table[ColorIndex(COLOR_GREEN)] );\n\t\t\t\t}\n\t\t\t}\n\t\t\tv = v * vscale;\n\t\t\tif ( v > range ) {\n\t\t\t\tv = range;\n\t\t\t}\n\t\t\ttrap_R_DrawStretchPic( ax + aw - a, ay + ah - v, 1, v, 0, 0, 0, 0, cgs.media.whiteShader );\n\t\t} else if ( v < 0 ) {\n\t\t\tif ( color != 4 ) {\n\t\t\t\tcolor = 4;\t\t// RED for dropped snapshots\n\t\t\t\ttrap_R_SetColor( g_color_table[ColorIndex(COLOR_RED)] );\n\t\t\t}\n\t\t\ttrap_R_DrawStretchPic( ax + aw - a, ay + ah - range, 1, range, 0, 0, 0, 0, cgs.media.whiteShader );\n\t\t}\n\t}\n\n\ttrap_R_SetColor( NULL );\n\n\tif ( cg_nopredict.integer || cg_synchronousClients.integer ) {\n\t\tCG_DrawBigString( ax, ay, \"snc\", 1.0 );\n\t}\n\n\tCG_DrawDisconnect();\n}\n\n\n\n/*\n===============================================================================\n\nCENTER PRINTING\n\n===============================================================================\n*/\n\n\n/*\n==============\nCG_CenterPrint\n\nCalled for important messages that should stay in the center of the screen\nfor a few moments\n==============\n*/\nvoid CG_CenterPrint( const char *str, int y, int charWidth ) {\n\tchar\t*s;\n\n\tQ_strncpyz( cg.centerPrint, str, sizeof(cg.centerPrint) );\n\n\tcg.centerPrintTime = cg.time;\n\tcg.centerPrintY = y;\n\tcg.centerPrintCharWidth = charWidth;\n\n\t// count the number of lines for centering\n\tcg.centerPrintLines = 1;\n\ts = cg.centerPrint;\n\twhile( *s ) {\n\t\tif (*s == '\\n')\n\t\t\tcg.centerPrintLines++;\n\t\ts++;\n\t}\n}\n\n\n/*\n===================\nCG_DrawCenterString\n===================\n*/\nstatic void CG_DrawCenterString( void ) {\n\tchar\t*start;\n\tint\t\tl;\n\tint\t\tx, y, w;\n\tfloat\t*color;\n\n\tif ( !cg.centerPrintTime ) {\n\t\treturn;\n\t}\n\n\tcolor = CG_FadeColor( cg.centerPrintTime, 1000 * cg_centertime.value );\n\tif ( !color ) {\n\t\treturn;\n\t}\n\n\ttrap_R_SetColor( color );\n\n\tstart = cg.centerPrint;\n\n\ty = cg.centerPrintY - cg.centerPrintLines * BIGCHAR_HEIGHT / 2;\n\n\twhile ( 1 ) {\n\t\tchar linebuffer[1024];\n\n\t\tfor ( l = 0; l < 50; l++ ) {\n\t\t\tif ( !start[l] || start[l] == '\\n' ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tlinebuffer[l] = start[l];\n\t\t}\n\t\tlinebuffer[l] = 0;\n\n\t\tw = cg.centerPrintCharWidth * CG_DrawStrlen( linebuffer );\n\n\t\tx = ( SCREEN_WIDTH - w ) / 2;\n\n\t\tCG_DrawStringExt( x, y, linebuffer, color, qfalse, qtrue,\n\t\t\tcg.centerPrintCharWidth, (int)(cg.centerPrintCharWidth * 1.5), 0 );\n\n\t\ty += cg.centerPrintCharWidth * 1.5;\n\n\t\twhile ( *start && ( *start != '\\n' ) ) {\n\t\t\tstart++;\n\t\t}\n\t\tif ( !*start ) {\n\t\t\tbreak;\n\t\t}\n\t\tstart++;\n\t}\n\n\ttrap_R_SetColor( NULL );\n}\n\n\n\n/*\n================================================================================\n\nCROSSHAIR\n\n================================================================================\n*/\n\n\n/*\n=================\nCG_DrawCrosshair\n=================\n*/\nstatic void CG_DrawCrosshair(void) {\n\tfloat\t\tw, h;\n\tqhandle_t\thShader;\n\tfloat\t\tf;\n\tfloat\t\tx, y;\n\tint\t\t\tca;\n\n\tif ( !cg_drawCrosshair.integer ) {\n\t\treturn;\n\t}\n\n\tif ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR) {\n\t\treturn;\n\t}\n\n\tif ( cg.renderingThirdPerson ) {\n\t\treturn;\n\t}\n\n\t// set color based on health\n\tif ( cg_crosshairHealth.integer ) {\n\t\tvec4_t\t\thcolor;\n\n\t\tCG_ColorForHealth( hcolor );\n\t\ttrap_R_SetColor( hcolor );\n\t} else {\n\t\ttrap_R_SetColor( NULL );\n\t}\n\n\tw = h = cg_crosshairSize.value;\n\n\t// pulse the size of the crosshair when picking up items\n\tf = cg.time - cg.itemPickupBlendTime;\n\tif ( f > 0 && f < ITEM_BLOB_TIME ) {\n\t\tf /= ITEM_BLOB_TIME;\n\t\tw *= ( 1 + f );\n\t\th *= ( 1 + f );\n\t}\n\n\tx = cg_crosshairX.integer;\n\ty = cg_crosshairY.integer;\n\tCG_AdjustFrom640( &x, &y, &w, &h );\n\n\tca = cg_drawCrosshair.integer;\n\tif (ca < 0) {\n\t\tca = 0;\n\t}\n\thShader = cgs.media.crosshairShader[ ca % NUM_CROSSHAIRS ];\n\n\ttrap_R_DrawStretchPic( x + cg.refdef.x + 0.5 * (cg.refdef.width - w), \n\t\ty + cg.refdef.y + 0.5 * (cg.refdef.height - h), \n\t\tw, h, 0, 0, 1, 1, hShader );\n}\n\n\n\n/*\n=================\nCG_ScanForCrosshairEntity\n=================\n*/\nstatic void CG_ScanForCrosshairEntity( void ) {\n\ttrace_t\t\ttrace;\n\tvec3_t\t\tstart, end;\n\tint\t\t\tcontent;\n\n\tVectorCopy( cg.refdef.vieworg, start );\n\tVectorMA( start, 131072, cg.refdef.viewaxis[0], end );\n\n\tCG_Trace( &trace, start, vec3_origin, vec3_origin, end, \n\t\tcg.snap->ps.clientNum, CONTENTS_SOLID|CONTENTS_BODY );\n\tif ( trace.entityNum >= MAX_CLIENTS ) {\n\t\treturn;\n\t}\n\n\t// if the player is in fog, don't show it\n\tcontent = trap_CM_PointContents( trace.endpos, 0 );\n\tif ( content & CONTENTS_FOG ) {\n\t\treturn;\n\t}\n\n\t// if the player is invisible, don't show it\n\tif ( cg_entities[ trace.entityNum ].currentState.powerups & ( 1 << PW_INVIS ) ) {\n\t\treturn;\n\t}\n\n\t// update the fade timer\n\tcg.crosshairClientNum = trace.entityNum;\n\tcg.crosshairClientTime = cg.time;\n}\n\n\n/*\n=====================\nCG_DrawCrosshairNames\n=====================\n*/\nstatic void CG_DrawCrosshairNames( void ) {\n\tfloat\t\t*color;\n\tchar\t\t*name;\n\tfloat\t\tw;\n\n\tif ( !cg_drawCrosshair.integer ) {\n\t\treturn;\n\t}\n\tif ( !cg_drawCrosshairNames.integer ) {\n\t\treturn;\n\t}\n\tif ( cg.renderingThirdPerson ) {\n\t\treturn;\n\t}\n\n\t// scan the known entities to see if the crosshair is sighted on one\n\tCG_ScanForCrosshairEntity();\n\n\t// draw the name of the player being looked at\n\tcolor = CG_FadeColor( cg.crosshairClientTime, 1000 );\n\tif ( !color ) {\n\t\ttrap_R_SetColor( NULL );\n\t\treturn;\n\t}\n\n\tname = cgs.clientinfo[ cg.crosshairClientNum ].name;\n\tw = CG_DrawStrlen( name ) * BIGCHAR_WIDTH;\n\tCG_DrawBigString( 320 - w / 2, 170, name, color[3] * 0.5f );\n\ttrap_R_SetColor( NULL );\n}\n\n\n//==============================================================================\n\n/*\n=================\nCG_DrawSpectator\n=================\n*/\nstatic void CG_DrawSpectator(void) {\n\tCG_DrawBigString(320 - 9 * 8, 440, \"SPECTATOR\", 1.0F);\n\tif ( cgs.gametype == GT_TOURNAMENT ) {\n\t\tCG_DrawBigString(320 - 15 * 8, 460, \"waiting to play\", 1.0F);\n\t}\n\telse if ( cgs.gametype >= GT_TEAM ) {\n\t\tCG_DrawBigString(320 - 39 * 8, 460, \"press ESC and use the JOIN menu to play\", 1.0F);\n\t}\n}\n\n/*\n=================\nCG_DrawVote\n=================\n*/\nstatic void CG_DrawVote(void) {\n\tchar\t*s;\n\tint\t\tsec;\n\n\tif ( !cgs.voteTime ) {\n\t\treturn;\n\t}\n\n\t// play a talk beep whenever it is modified\n\tif ( cgs.voteModified ) {\n\t\tcgs.voteModified = qfalse;\n\t\ttrap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );\n\t}\n\n\tsec = ( VOTE_TIME - ( cg.time - cgs.voteTime ) ) / 1000;\n\tif ( sec < 0 ) {\n\t\tsec = 0;\n\t}\n\ts = va(\"VOTE(%i):%s yes:%i no:%i\", sec, cgs.voteString, cgs.voteYes, cgs.voteNo );\n\tCG_DrawSmallString( 0, 58, s, 1.0F );\n}\n\n/*\n=================\nCG_DrawTeamVote\n=================\n*/\nstatic void CG_DrawTeamVote(void) {\n\tchar\t*s;\n\tint\t\tsec, cs_offset;\n\n\tif ( cgs.clientinfo->team == TEAM_RED )\n\t\tcs_offset = 0;\n\telse if ( cgs.clientinfo->team == TEAM_BLUE )\n\t\tcs_offset = 1;\n\telse\n\t\treturn;\n\n\tif ( !cgs.teamVoteTime[cs_offset] ) {\n\t\treturn;\n\t}\n\n\t// play a talk beep whenever it is modified\n\tif ( cgs.teamVoteModified[cs_offset] ) {\n\t\tcgs.teamVoteModified[cs_offset] = qfalse;\n\t\ttrap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );\n\t}\n\n\tsec = ( VOTE_TIME - ( cg.time - cgs.teamVoteTime[cs_offset] ) ) / 1000;\n\tif ( sec < 0 ) {\n\t\tsec = 0;\n\t}\n\ts = va(\"TEAMVOTE(%i):%s yes:%i no:%i\", sec, cgs.teamVoteString[cs_offset],\n\t\t\t\t\t\t\tcgs.teamVoteYes[cs_offset], cgs.teamVoteNo[cs_offset] );\n\tCG_DrawSmallString( 0, 90, s, 1.0F );\n}\n\n\nstatic qboolean CG_DrawScoreboard() {\n\treturn CG_DrawOldScoreboard();\n}\n\n/*\n=================\nCG_DrawIntermission\n=================\n*/\nstatic void CG_DrawIntermission( void ) {\n//\tint key;\n\tif ( cgs.gametype == GT_SINGLE_PLAYER ) {\n\t\tCG_DrawCenterString();\n\t\treturn;\n\t}\n\tcg.scoreFadeTime = cg.time;\n\tcg.scoreBoardShowing = CG_DrawScoreboard();\n}\n\n/*\n=================\nCG_DrawFollow\n=================\n*/\nstatic qboolean CG_DrawFollow( void ) {\n\tfloat\t\tx;\n\tvec4_t\t\tcolor;\n\tconst char\t*name;\n\n\tif ( !(cg.snap->ps.pm_flags & PMF_FOLLOW) ) {\n\t\treturn qfalse;\n\t}\n\tcolor[0] = 1;\n\tcolor[1] = 1;\n\tcolor[2] = 1;\n\tcolor[3] = 1;\n\n\n\tCG_DrawBigString( 320 - 9 * 8, 24, \"following\", 1.0F );\n\n\tname = cgs.clientinfo[ cg.snap->ps.clientNum ].name;\n\n\tx = 0.5 * ( 640 - GIANT_WIDTH * CG_DrawStrlen( name ) );\n\n\tCG_DrawStringExt( x, 40, name, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );\n\n\treturn qtrue;\n}\n\n\n\n/*\n=================\nCG_DrawAmmoWarning\n=================\n*/\nstatic void CG_DrawAmmoWarning( void ) {\n\tconst char\t*s;\n\tint\t\t\tw;\n\n\tif ( cg_drawAmmoWarning.integer == 0 ) {\n\t\treturn;\n\t}\n\n\tif ( !cg.lowAmmoWarning ) {\n\t\treturn;\n\t}\n\n\tif ( cg.lowAmmoWarning == 2 ) {\n\t\ts = \"OUT OF AMMO\";\n\t} else {\n\t\ts = \"LOW AMMO WARNING\";\n\t}\n\tw = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;\n\tCG_DrawBigString(320 - w / 2, 64, s, 1.0F);\n}\n\n/*\n=================\nCG_DrawWarmup\n=================\n*/\nstatic void CG_DrawWarmup( void ) {\n\tint\t\t\tw;\n\tint\t\t\tsec;\n\tint\t\t\ti;\n\tfloat scale;\n\tclientInfo_t\t*ci1, *ci2;\n\tint\t\t\tcw;\n\tconst char\t*s;\n\n\tsec = cg.warmup;\n\tif ( !sec ) {\n\t\treturn;\n\t}\n\n\tif ( sec < 0 ) {\n\t\ts = \"Waiting for players\";\t\t\n\t\tw = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;\n\t\tCG_DrawBigString(320 - w / 2, 24, s, 1.0F);\n\t\tcg.warmupCount = 0;\n\t\treturn;\n\t}\n\n\tif (cgs.gametype == GT_TOURNAMENT) {\n\t\t// find the two active players\n\t\tci1 = NULL;\n\t\tci2 = NULL;\n\t\tfor ( i = 0 ; i < cgs.maxclients ; i++ ) {\n\t\t\tif ( cgs.clientinfo[i].infoValid && cgs.clientinfo[i].team == TEAM_FREE ) {\n\t\t\t\tif ( !ci1 ) {\n\t\t\t\t\tci1 = &cgs.clientinfo[i];\n\t\t\t\t} else {\n\t\t\t\t\tci2 = &cgs.clientinfo[i];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif ( ci1 && ci2 ) {\n\t\t\ts = va( \"%s vs %s\", ci1->name, ci2->name );\n\t\t\tw = CG_DrawStrlen( s );\n\t\t\tif ( w > 640 / GIANT_WIDTH ) {\n\t\t\t\tcw = 640 / w;\n\t\t\t} else {\n\t\t\t\tcw = GIANT_WIDTH;\n\t\t\t}\n\t\t\tCG_DrawStringExt( 320 - w * cw/2, 20,s, colorWhite, \n\t\t\t\t\tqfalse, qtrue, cw, (int)(cw * 1.5f), 0 );\n\t\t}\n\t} else {\n\t\tif ( cgs.gametype == GT_FFA ) {\n\t\t\ts = \"Free For All\";\n\t\t} else if ( cgs.gametype == GT_TEAM ) {\n\t\t\ts = \"Team Deathmatch\";\n\t\t} else if ( cgs.gametype == GT_CTF ) {\n\t\t\ts = \"Capture the Flag\";\n\t\t} else {\n\t\t\ts = \"\";\n\t\t}\n\t\tw = CG_DrawStrlen( s );\n\t\tif ( w > 640 / GIANT_WIDTH ) {\n\t\t\tcw = 640 / w;\n\t\t} else {\n\t\t\tcw = GIANT_WIDTH;\n\t\t}\n\t\tCG_DrawStringExt( 320 - w * cw/2, 25,s, colorWhite, \n\t\t\t\tqfalse, qtrue, cw, (int)(cw * 1.1f), 0 );\n\t}\n\n\tsec = ( sec - cg.time ) / 1000;\n\tif ( sec < 0 ) {\n\t\tcg.warmup = 0;\n\t\tsec = 0;\n\t}\n\ts = va( \"Starts in: %i\", sec + 1 );\n\tif ( sec != cg.warmupCount ) {\n\t\tcg.warmupCount = sec;\n\t\tswitch ( sec ) {\n\t\tcase 0:\n\t\t\ttrap_S_StartLocalSound( cgs.media.count1Sound, CHAN_ANNOUNCER );\n\t\t\tbreak;\n\t\tcase 1:\n\t\t\ttrap_S_StartLocalSound( cgs.media.count2Sound, CHAN_ANNOUNCER );\n\t\t\tbreak;\n\t\tcase 2:\n\t\t\ttrap_S_StartLocalSound( cgs.media.count3Sound, CHAN_ANNOUNCER );\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\t}\n\tscale = 0.45f;\n\tswitch ( cg.warmupCount ) {\n\tcase 0:\n\t\tcw = 28;\n\t\tscale = 0.54f;\n\t\tbreak;\n\tcase 1:\n\t\tcw = 24;\n\t\tscale = 0.51f;\n\t\tbreak;\n\tcase 2:\n\t\tcw = 20;\n\t\tscale = 0.48f;\n\t\tbreak;\n\tdefault:\n\t\tcw = 16;\n\t\tscale = 0.45f;\n\t\tbreak;\n\t}\n\n\tw = CG_DrawStrlen( s );\n\tCG_DrawStringExt( 320 - w * cw/2, 70, s, colorWhite, \n\t\t\tqfalse, qtrue, cw, (int)(cw * 1.5), 0 );\n}\n\n/*\n=================\nCG_Draw2D\n=================\n*/\nstatic void CG_Draw2D( void ) {\n\t// if we are taking a levelshot for the menu, don't draw anything\n\tif ( cg.levelShot ) {\n\t\treturn;\n\t}\n\n\tif ( cg_draw2D.integer == 0 ) {\n\t\treturn;\n\t}\n\n\tif ( cg.snap->ps.pm_type == PM_INTERMISSION ) {\n\t\tCG_DrawIntermission();\n\t\treturn;\n\t}\n\n/*\n\tif (cg.cameraMode) {\n\t\treturn;\n\t}\n*/\n\tif ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR ) {\n\t\tCG_DrawSpectator();\n\t\tCG_DrawCrosshair();\n\t\tCG_DrawCrosshairNames();\n\t} else {\n\t\t// don't draw any status if dead or the scoreboard is being explicitly shown\n\t\tif ( !cg.showScores && cg.snap->ps.stats[STAT_HEALTH] > 0 ) {\n\t\t\tCG_DrawStatusBar();\n\t\t\tCG_DrawAmmoWarning();\n\t\t\tCG_DrawCrosshair();\n\t\t\tCG_DrawCrosshairNames();\n\t\t\tCG_DrawWeaponSelect();\n\t\t\tCG_DrawHoldableItem();\n\t\t\tCG_DrawReward();\n\t\t}\n    \n\t\tif ( cgs.gametype >= GT_TEAM ) {\n\t\t\tCG_DrawTeamInfo();\n\t\t}\n\t}\n\n\tCG_DrawVote();\n\tCG_DrawTeamVote();\n\n\tCG_DrawLagometer();\n\tCG_DrawUpperRight();\n\n\tCG_DrawLowerRight();\n\tCG_DrawLowerLeft();\n\n\tif ( !CG_DrawFollow() ) {\n\t\tCG_DrawWarmup();\n\t}\n\n\t// don't draw center string if scoreboard is up\n\tcg.scoreBoardShowing = CG_DrawScoreboard();\n\tif ( !cg.scoreBoardShowing) {\n\t\tCG_DrawCenterString();\n\t}\n}\n\n\nstatic void CG_DrawTourneyScoreboard() {\n\tCG_DrawOldTourneyScoreboard();\n}\n\n/*\n=====================\nCG_DrawActive\n\nPerform all drawing needed to completely fill the screen\n=====================\n*/\nvoid CG_DrawActive( stereoFrame_t stereoView ) {\n\tfloat\t\tseparation;\n\tvec3_t\t\tbaseOrg;\n\n\t// optionally draw the info screen instead\n\tif ( !cg.snap ) {\n\t\tCG_DrawInformation();\n\t\treturn;\n\t}\n\n\t// optionally draw the tournement scoreboard instead\n\tif ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR &&\n\t\t( cg.snap->ps.pm_flags & PMF_SCOREBOARD ) ) {\n\t\tCG_DrawTourneyScoreboard();\n\t\treturn;\n\t}\n\n\tswitch ( stereoView ) {\n\tcase STEREO_CENTER:\n\t\tseparation = 0;\n\t\tbreak;\n\tcase STEREO_LEFT:\n\t\tseparation = -cg_stereoSeparation.value / 2;\n\t\tbreak;\n\tcase STEREO_RIGHT:\n\t\tseparation = cg_stereoSeparation.value / 2;\n\t\tbreak;\n\tdefault:\n\t\tseparation = 0;\n\t\tCG_Error( \"CG_DrawActive: Undefined stereoView\" );\n\t}\n\n\n\t// clear around the rendered view if sized down\n\tCG_TileClear();\n\n\t// offset vieworg appropriately if we're doing stereo separation\n\tVectorCopy( cg.refdef.vieworg, baseOrg );\n\tif ( separation != 0 ) {\n\t\tVectorMA( cg.refdef.vieworg, -separation, cg.refdef.viewaxis[1], cg.refdef.vieworg );\n\t}\n\n\t// draw 3D view\n\ttrap_R_RenderScene( &cg.refdef );\n\n\t// restore original viewpoint if running stereo\n\tif ( separation != 0 ) {\n\t\tVectorCopy( baseOrg, cg.refdef.vieworg );\n\t}\n\n\t// draw status bar and other floating elements\n \tCG_Draw2D();\n}\n\n\n\n"
  },
  {
    "path": "src/cgame/cg_drawtools.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n// cg_drawtools.c -- helper functions called by cg_draw, cg_scoreboard, cg_info, etc\n#include \"cg_local.h\"\n\n/*\n================\nCG_AdjustFrom640\n\nAdjusted for resolution and screen aspect ratio\n================\n*/\nvoid CG_AdjustFrom640( float *x, float *y, float *w, float *h ) {\n#if 0\n\t// adjust for wide screens\n\tif ( cgs.glconfig.vidWidth * 480 > cgs.glconfig.vidHeight * 640 ) {\n\t\t*x += 0.5 * ( cgs.glconfig.vidWidth - ( cgs.glconfig.vidHeight * 640 / 480 ) );\n\t}\n#endif\n\t// scale for screen sizes\n\t*x *= cgs.screenXScale;\n\t*y *= cgs.screenYScale;\n\t*w *= cgs.screenXScale;\n\t*h *= cgs.screenYScale;\n}\n\n/*\n================\nCG_FillRect\n\nCoordinates are 640*480 virtual values\n=================\n*/\nvoid CG_FillRect( float x, float y, float width, float height, const float *color ) {\n\ttrap_R_SetColor( color );\n\n\tCG_AdjustFrom640( &x, &y, &width, &height );\n\ttrap_R_DrawStretchPic( x, y, width, height, 0, 0, 0, 0, cgs.media.whiteShader );\n\n\ttrap_R_SetColor( NULL );\n}\n\n/*\n================\nCG_DrawSides\n\nCoords are virtual 640x480\n================\n*/\nvoid CG_DrawSides(float x, float y, float w, float h, float size) {\n\tCG_AdjustFrom640( &x, &y, &w, &h );\n\tsize *= cgs.screenXScale;\n\ttrap_R_DrawStretchPic( x, y, size, h, 0, 0, 0, 0, cgs.media.whiteShader );\n\ttrap_R_DrawStretchPic( x + w - size, y, size, h, 0, 0, 0, 0, cgs.media.whiteShader );\n}\n\nvoid CG_DrawTopBottom(float x, float y, float w, float h, float size) {\n\tCG_AdjustFrom640( &x, &y, &w, &h );\n\tsize *= cgs.screenYScale;\n\ttrap_R_DrawStretchPic( x, y, w, size, 0, 0, 0, 0, cgs.media.whiteShader );\n\ttrap_R_DrawStretchPic( x, y + h - size, w, size, 0, 0, 0, 0, cgs.media.whiteShader );\n}\n/*\n================\nUI_DrawRect\n\nCoordinates are 640*480 virtual values\n=================\n*/\nvoid CG_DrawRect( float x, float y, float width, float height, float size, const float *color ) {\n\ttrap_R_SetColor( color );\n\n  CG_DrawTopBottom(x, y, width, height, size);\n  CG_DrawSides(x, y, width, height, size);\n\n\ttrap_R_SetColor( NULL );\n}\n\n\n\n/*\n================\nCG_DrawPic\n\nCoordinates are 640*480 virtual values\n=================\n*/\nvoid CG_DrawPic( float x, float y, float width, float height, qhandle_t hShader ) {\n\tCG_AdjustFrom640( &x, &y, &width, &height );\n\ttrap_R_DrawStretchPic( x, y, width, height, 0, 0, 1, 1, hShader );\n}\n\n\n\n/*\n===============\nCG_DrawChar\n\nCoordinates and size in 640*480 virtual screen size\n===============\n*/\nvoid CG_DrawChar( int x, int y, int width, int height, int ch ) {\n\tint row, col;\n\tfloat frow, fcol;\n\tfloat size;\n\tfloat\tax, ay, aw, ah;\n\n\tch &= 255;\n\n\tif ( ch == ' ' ) {\n\t\treturn;\n\t}\n\n\tax = x;\n\tay = y;\n\taw = width;\n\tah = height;\n\tCG_AdjustFrom640( &ax, &ay, &aw, &ah );\n\n\trow = ch>>4;\n\tcol = ch&15;\n\n\tfrow = row*0.0625;\n\tfcol = col*0.0625;\n\tsize = 0.0625;\n\n\ttrap_R_DrawStretchPic( ax, ay, aw, ah,\n\t\t\t\t\t   fcol, frow, \n\t\t\t\t\t   fcol + size, frow + size, \n\t\t\t\t\t   cgs.media.charsetShader );\n}\n\n\n/*\n==================\nCG_DrawStringExt\n\nDraws a multi-colored string with a drop shadow, optionally forcing\nto a fixed color.\n\nCoordinates are at 640 by 480 virtual resolution\n==================\n*/\nvoid CG_DrawStringExt( int x, int y, const char *string, const float *setColor, \n\t\tqboolean forceColor, qboolean shadow, int charWidth, int charHeight, int maxChars ) {\n\tvec4_t\t\tcolor;\n\tconst char\t*s;\n\tint\t\t\txx;\n\tint\t\t\tcnt;\n\n\tif (maxChars <= 0)\n\t\tmaxChars = 32767; // do them all!\n\n\t// draw the drop shadow\n\tif (shadow) {\n\t\tcolor[0] = color[1] = color[2] = 0;\n\t\tcolor[3] = setColor[3];\n\t\ttrap_R_SetColor( color );\n\t\ts = string;\n\t\txx = x;\n\t\tcnt = 0;\n\t\twhile ( *s && cnt < maxChars) {\n\t\t\tif ( Q_IsColorString( s ) ) {\n\t\t\t\ts += 2;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tCG_DrawChar( xx + 2, y + 2, charWidth, charHeight, *s );\n\t\t\tcnt++;\n\t\t\txx += charWidth;\n\t\t\ts++;\n\t\t}\n\t}\n\n\t// draw the colored text\n\ts = string;\n\txx = x;\n\tcnt = 0;\n\ttrap_R_SetColor( setColor );\n\twhile ( *s && cnt < maxChars) {\n\t\tif ( Q_IsColorString( s ) ) {\n\t\t\tif ( !forceColor ) {\n\t\t\t\tmemcpy( color, g_color_table[ColorIndex(*(s+1))], sizeof( color ) );\n\t\t\t\tcolor[3] = setColor[3];\n\t\t\t\ttrap_R_SetColor( color );\n\t\t\t}\n\t\t\ts += 2;\n\t\t\tcontinue;\n\t\t}\n\t\tCG_DrawChar( xx, y, charWidth, charHeight, *s );\n\t\txx += charWidth;\n\t\tcnt++;\n\t\ts++;\n\t}\n\ttrap_R_SetColor( NULL );\n}\n\nvoid CG_DrawBigString( int x, int y, const char *s, float alpha ) {\n\tfloat\tcolor[4];\n\n\tcolor[0] = color[1] = color[2] = 1.0;\n\tcolor[3] = alpha;\n\tCG_DrawStringExt( x, y, s, color, qfalse, qtrue, BIGCHAR_WIDTH, BIGCHAR_HEIGHT, 0 );\n}\n\nvoid CG_DrawBigStringColor( int x, int y, const char *s, vec4_t color ) {\n\tCG_DrawStringExt( x, y, s, color, qtrue, qtrue, BIGCHAR_WIDTH, BIGCHAR_HEIGHT, 0 );\n}\n\nvoid CG_DrawSmallString( int x, int y, const char *s, float alpha ) {\n\tfloat\tcolor[4];\n\n\tcolor[0] = color[1] = color[2] = 1.0;\n\tcolor[3] = alpha;\n\tCG_DrawStringExt( x, y, s, color, qfalse, qfalse, SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT, 0 );\n}\n\nvoid CG_DrawSmallStringColor( int x, int y, const char *s, vec4_t color ) {\n\tCG_DrawStringExt( x, y, s, color, qtrue, qfalse, SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT, 0 );\n}\n\n/*\n=================\nCG_DrawStrlen\n\nReturns character count, skiping color escape codes\n=================\n*/\nint CG_DrawStrlen( const char *str ) {\n\tconst char *s = str;\n\tint count = 0;\n\n\twhile ( *s ) {\n\t\tif ( Q_IsColorString( s ) ) {\n\t\t\ts += 2;\n\t\t} else {\n\t\t\tcount++;\n\t\t\ts++;\n\t\t}\n\t}\n\n\treturn count;\n}\n\n/*\n=============\nCG_TileClearBox\n\nThis repeats a 64*64 tile graphic to fill the screen around a sized down\nrefresh window.\n=============\n*/\nstatic void CG_TileClearBox( int x, int y, int w, int h, qhandle_t hShader ) {\n\tfloat\ts1, t1, s2, t2;\n\n\ts1 = x/64.0;\n\tt1 = y/64.0;\n\ts2 = (x+w)/64.0;\n\tt2 = (y+h)/64.0;\n\ttrap_R_DrawStretchPic( x, y, w, h, s1, t1, s2, t2, hShader );\n}\n\n\n\n/*\n==============\nCG_TileClear\n\nClear around a sized down screen\n==============\n*/\nvoid CG_TileClear( void ) {\n\tint\t\ttop, bottom, left, right;\n\tint\t\tw, h;\n\n\tw = cgs.glconfig.vidWidth;\n\th = cgs.glconfig.vidHeight;\n\n\tif ( cg.refdef.x == 0 && cg.refdef.y == 0 && \n\t\tcg.refdef.width == w && cg.refdef.height == h ) {\n\t\treturn;\t\t// full screen rendering\n\t}\n\n\ttop = cg.refdef.y;\n\tbottom = top + cg.refdef.height-1;\n\tleft = cg.refdef.x;\n\tright = left + cg.refdef.width-1;\n\n\t// clear above view screen\n\tCG_TileClearBox( 0, 0, w, top, cgs.media.backTileShader );\n\n\t// clear below view screen\n\tCG_TileClearBox( 0, bottom, w, h - bottom, cgs.media.backTileShader );\n\n\t// clear left of view screen\n\tCG_TileClearBox( 0, top, left, bottom - top + 1, cgs.media.backTileShader );\n\n\t// clear right of view screen\n\tCG_TileClearBox( right, top, w - right, bottom - top + 1, cgs.media.backTileShader );\n}\n\n\n\n/*\n================\nCG_FadeColor\n================\n*/\nfloat *CG_FadeColor( int startMsec, int totalMsec ) {\n\tstatic vec4_t\t\tcolor;\n\tint\t\t\tt;\n\n\tif ( startMsec == 0 ) {\n\t\treturn NULL;\n\t}\n\n\tt = cg.time - startMsec;\n\n\tif ( t >= totalMsec ) {\n\t\treturn NULL;\n\t}\n\n\t// fade out\n\tif ( totalMsec - t < FADE_TIME ) {\n\t\tcolor[3] = ( totalMsec - t ) * 1.0/FADE_TIME;\n\t} else {\n\t\tcolor[3] = 1.0;\n\t}\n\tcolor[0] = color[1] = color[2] = 1;\n\n\treturn color;\n}\n\n\n/*\n================\nCG_TeamColor\n================\n*/\nfloat *CG_TeamColor( int team ) {\n\tstatic vec4_t\tred = {1, 0.2f, 0.2f, 1};\n\tstatic vec4_t\tblue = {0.2f, 0.2f, 1, 1};\n\tstatic vec4_t\tother = {1, 1, 1, 1};\n\tstatic vec4_t\tspectator = {0.7f, 0.7f, 0.7f, 1};\n\n\tswitch ( team ) {\n\tcase TEAM_RED:\n\t\treturn red;\n\tcase TEAM_BLUE:\n\t\treturn blue;\n\tcase TEAM_SPECTATOR:\n\t\treturn spectator;\n\tdefault:\n\t\treturn other;\n\t}\n}\n\n\n\n/*\n=================\nCG_GetColorForHealth\n=================\n*/\nvoid CG_GetColorForHealth( int health, int armor, vec4_t hcolor ) {\n\tint\t\tcount;\n\tint\t\tmax;\n\n\t// calculate the total points of damage that can\n\t// be sustained at the current health / armor level\n\tif ( health <= 0 ) {\n\t\tVectorClear( hcolor );\t// black\n\t\thcolor[3] = 1;\n\t\treturn;\n\t}\n\tcount = armor;\n\tmax = health * ARMOR_PROTECTION / ( 1.0 - ARMOR_PROTECTION );\n\tif ( max < count ) {\n\t\tcount = max;\n\t}\n\thealth += count;\n\n\t// set the color based on health\n\thcolor[0] = 1.0;\n\thcolor[3] = 1.0;\n\tif ( health >= 100 ) {\n\t\thcolor[2] = 1.0;\n\t} else if ( health < 66 ) {\n\t\thcolor[2] = 0;\n\t} else {\n\t\thcolor[2] = ( health - 66 ) / 33.0;\n\t}\n\n\tif ( health > 60 ) {\n\t\thcolor[1] = 1.0;\n\t} else if ( health < 30 ) {\n\t\thcolor[1] = 0;\n\t} else {\n\t\thcolor[1] = ( health - 30 ) / 30.0;\n\t}\n}\n\n/*\n=================\nCG_ColorForHealth\n=================\n*/\nvoid CG_ColorForHealth( vec4_t hcolor ) {\n\n\tCG_GetColorForHealth( cg.snap->ps.stats[STAT_HEALTH], \n\t\tcg.snap->ps.stats[STAT_ARMOR], hcolor );\n}\n\n\n\n\n// bk001205 - code below duplicated in q3_ui/ui-atoms.c\n// bk001205 - FIXME: does this belong in ui_shared.c?\n// bk001205 - FIXME: HARD_LINKED flags not visible here\n#ifndef Q3_STATIC // bk001205 - q_shared defines not visible here \n/*\n=================\nUI_DrawProportionalString2\n=================\n*/\nstatic int\tpropMap[128][3] = {\n{0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},\n{0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},\n\n{0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},\n{0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},\n\n{0, 0, PROP_SPACE_WIDTH},\t\t// SPACE\n{11, 122, 7},\t// !\n{154, 181, 14},\t// \"\n{55, 122, 17},\t// #\n{79, 122, 18},\t// $\n{101, 122, 23},\t// %\n{153, 122, 18},\t// &\n{9, 93, 7},\t\t// '\n{207, 122, 8},\t// (\n{230, 122, 9},\t// )\n{177, 122, 18},\t// *\n{30, 152, 18},\t// +\n{85, 181, 7},\t// ,\n{34, 93, 11},\t// -\n{110, 181, 6},\t// .\n{130, 152, 14},\t// /\n\n{22, 64, 17},\t// 0\n{41, 64, 12},\t// 1\n{58, 64, 17},\t// 2\n{78, 64, 18},\t// 3\n{98, 64, 19},\t// 4\n{120, 64, 18},\t// 5\n{141, 64, 18},\t// 6\n{204, 64, 16},\t// 7\n{162, 64, 17},\t// 8\n{182, 64, 18},\t// 9\n{59, 181, 7},\t// :\n{35,181, 7},\t// ;\n{203, 152, 14},\t// <\n{56, 93, 14},\t// =\n{228, 152, 14},\t// >\n{177, 181, 18},\t// ?\n\n{28, 122, 22},\t// @\n{5, 4, 18},\t\t// A\n{27, 4, 18},\t// B\n{48, 4, 18},\t// C\n{69, 4, 17},\t// D\n{90, 4, 13},\t// E\n{106, 4, 13},\t// F\n{121, 4, 18},\t// G\n{143, 4, 17},\t// H\n{164, 4, 8},\t// I\n{175, 4, 16},\t// J\n{195, 4, 18},\t// K\n{216, 4, 12},\t// L\n{230, 4, 23},\t// M\n{6, 34, 18},\t// N\n{27, 34, 18},\t// O\n\n{48, 34, 18},\t// P\n{68, 34, 18},\t// Q\n{90, 34, 17},\t// R\n{110, 34, 18},\t// S\n{130, 34, 14},\t// T\n{146, 34, 18},\t// U\n{166, 34, 19},\t// V\n{185, 34, 29},\t// W\n{215, 34, 18},\t// X\n{234, 34, 18},\t// Y\n{5, 64, 14},\t// Z\n{60, 152, 7},\t// [\n{106, 151, 13},\t// '\\'\n{83, 152, 7},\t// ]\n{128, 122, 17},\t// ^\n{4, 152, 21},\t// _\n\n{134, 181, 5},\t// '\n{5, 4, 18},\t\t// A\n{27, 4, 18},\t// B\n{48, 4, 18},\t// C\n{69, 4, 17},\t// D\n{90, 4, 13},\t// E\n{106, 4, 13},\t// F\n{121, 4, 18},\t// G\n{143, 4, 17},\t// H\n{164, 4, 8},\t// I\n{175, 4, 16},\t// J\n{195, 4, 18},\t// K\n{216, 4, 12},\t// L\n{230, 4, 23},\t// M\n{6, 34, 18},\t// N\n{27, 34, 18},\t// O\n\n{48, 34, 18},\t// P\n{68, 34, 18},\t// Q\n{90, 34, 17},\t// R\n{110, 34, 18},\t// S\n{130, 34, 14},\t// T\n{146, 34, 18},\t// U\n{166, 34, 19},\t// V\n{185, 34, 29},\t// W\n{215, 34, 18},\t// X\n{234, 34, 18},\t// Y\n{5, 64, 14},\t// Z\n{153, 152, 13},\t// {\n{11, 181, 5},\t// |\n{180, 152, 13},\t// }\n{79, 93, 17},\t// ~\n{0, 0, -1}\t\t// DEL\n};\n\nstatic int propMapB[26][3] = {\n{11, 12, 33},\n{49, 12, 31},\n{85, 12, 31},\n{120, 12, 30},\n{156, 12, 21},\n{183, 12, 21},\n{207, 12, 32},\n\n{13, 55, 30},\n{49, 55, 13},\n{66, 55, 29},\n{101, 55, 31},\n{135, 55, 21},\n{158, 55, 40},\n{204, 55, 32},\n\n{12, 97, 31},\n{48, 97, 31},\n{82, 97, 30},\n{118, 97, 30},\n{153, 97, 30},\n{185, 97, 25},\n{213, 97, 30},\n\n{11, 139, 32},\n{42, 139, 51},\n{93, 139, 32},\n{126, 139, 31},\n{158, 139, 25},\n};\n\n#define PROPB_GAP_WIDTH\t\t4\n#define PROPB_SPACE_WIDTH\t12\n#define PROPB_HEIGHT\t\t36\n\n/*\n=================\nUI_DrawBannerString\n=================\n*/\nstatic void UI_DrawBannerString2( int x, int y, const char* str, vec4_t color )\n{\n\tconst char* s;\n\tunsigned char\tch; // bk001204 : array subscript\n\tfloat\tax;\n\tfloat\tay;\n\tfloat\taw;\n\tfloat\tah;\n\tfloat\tfrow;\n\tfloat\tfcol;\n\tfloat\tfwidth;\n\tfloat\tfheight;\n\n\t// draw the colored text\n\ttrap_R_SetColor( color );\n\t\n\tax = x * cgs.screenXScale + cgs.screenXBias;\n\tay = y * cgs.screenXScale;\n\n\ts = str;\n\twhile ( *s )\n\t{\n\t\tch = *s & 127;\n\t\tif ( ch == ' ' ) {\n\t\t\tax += ((float)PROPB_SPACE_WIDTH + (float)PROPB_GAP_WIDTH)* cgs.screenXScale;\n\t\t}\n\t\telse if ( ch >= 'A' && ch <= 'Z' ) {\n\t\t\tch -= 'A';\n\t\t\tfcol = (float)propMapB[ch][0] / 256.0f;\n\t\t\tfrow = (float)propMapB[ch][1] / 256.0f;\n\t\t\tfwidth = (float)propMapB[ch][2] / 256.0f;\n\t\t\tfheight = (float)PROPB_HEIGHT / 256.0f;\n\t\t\taw = (float)propMapB[ch][2] * cgs.screenXScale;\n\t\t\tah = (float)PROPB_HEIGHT * cgs.screenXScale;\n\t\t\ttrap_R_DrawStretchPic( ax, ay, aw, ah, fcol, frow, fcol+fwidth, frow+fheight, cgs.media.charsetPropB );\n\t\t\tax += (aw + (float)PROPB_GAP_WIDTH * cgs.screenXScale);\n\t\t}\n\t\ts++;\n\t}\n\n\ttrap_R_SetColor( NULL );\n}\n\nvoid UI_DrawBannerString( int x, int y, const char* str, int style, vec4_t color ) {\n\tconst char *\ts;\n\tint\t\t\t\tch;\n\tint\t\t\t\twidth;\n\tvec4_t\t\t\tdrawcolor;\n\n\t// find the width of the drawn text\n\ts = str;\n\twidth = 0;\n\twhile ( *s ) {\n\t\tch = *s;\n\t\tif ( ch == ' ' ) {\n\t\t\twidth += PROPB_SPACE_WIDTH;\n\t\t}\n\t\telse if ( ch >= 'A' && ch <= 'Z' ) {\n\t\t\twidth += propMapB[ch - 'A'][2] + PROPB_GAP_WIDTH;\n\t\t}\n\t\ts++;\n\t}\n\twidth -= PROPB_GAP_WIDTH;\n\n\tswitch( style & UI_FORMATMASK ) {\n\t\tcase UI_CENTER:\n\t\t\tx -= width / 2;\n\t\t\tbreak;\n\n\t\tcase UI_RIGHT:\n\t\t\tx -= width;\n\t\t\tbreak;\n\n\t\tcase UI_LEFT:\n\t\tdefault:\n\t\t\tbreak;\n\t}\n\n\tif ( style & UI_DROPSHADOW ) {\n\t\tdrawcolor[0] = drawcolor[1] = drawcolor[2] = 0;\n\t\tdrawcolor[3] = color[3];\n\t\tUI_DrawBannerString2( x+2, y+2, str, drawcolor );\n\t}\n\n\tUI_DrawBannerString2( x, y, str, color );\n}\n\n\nint UI_ProportionalStringWidth( const char* str ) {\n\tconst char *\ts;\n\tint\t\t\t\tch;\n\tint\t\t\t\tcharWidth;\n\tint\t\t\t\twidth;\n\n\ts = str;\n\twidth = 0;\n\twhile ( *s ) {\n\t\tch = *s & 127;\n\t\tcharWidth = propMap[ch][2];\n\t\tif ( charWidth != -1 ) {\n\t\t\twidth += charWidth;\n\t\t\twidth += PROP_GAP_WIDTH;\n\t\t}\n\t\ts++;\n\t}\n\n\twidth -= PROP_GAP_WIDTH;\n\treturn width;\n}\n\nstatic void UI_DrawProportionalString2( int x, int y, const char* str, vec4_t color, float sizeScale, qhandle_t charset )\n{\n\tconst char* s;\n\tunsigned char\tch; // bk001204 - unsigned\n\tfloat\tax;\n\tfloat\tay;\n\tfloat\taw;\n\tfloat\tah;\n\tfloat\tfrow;\n\tfloat\tfcol;\n\tfloat\tfwidth;\n\tfloat\tfheight;\n\n\t// draw the colored text\n\ttrap_R_SetColor( color );\n\t\n\tax = x * cgs.screenXScale + cgs.screenXBias;\n\tay = y * cgs.screenXScale;\n\n\ts = str;\n\twhile ( *s )\n\t{\n\t\tch = *s & 127;\n\t\tif ( ch == ' ' ) {\n\t\t\taw = (float)PROP_SPACE_WIDTH * cgs.screenXScale * sizeScale;\n\t\t} else if ( propMap[ch][2] != -1 ) {\n\t\t\tfcol = (float)propMap[ch][0] / 256.0f;\n\t\t\tfrow = (float)propMap[ch][1] / 256.0f;\n\t\t\tfwidth = (float)propMap[ch][2] / 256.0f;\n\t\t\tfheight = (float)PROP_HEIGHT / 256.0f;\n\t\t\taw = (float)propMap[ch][2] * cgs.screenXScale * sizeScale;\n\t\t\tah = (float)PROP_HEIGHT * cgs.screenXScale * sizeScale;\n\t\t\ttrap_R_DrawStretchPic( ax, ay, aw, ah, fcol, frow, fcol+fwidth, frow+fheight, charset );\n\t\t} else {\n\t\t\taw = 0;\n\t\t}\n\n\t\tax += (aw + (float)PROP_GAP_WIDTH * cgs.screenXScale * sizeScale);\n\t\ts++;\n\t}\n\n\ttrap_R_SetColor( NULL );\n}\n\n/*\n=================\nUI_ProportionalSizeScale\n=================\n*/\nfloat UI_ProportionalSizeScale( int style ) {\n\tif(  style & UI_SMALLFONT ) {\n\t\treturn 0.75;\n\t}\n\n\treturn 1.00;\n}\n\n\n/*\n=================\nUI_DrawProportionalString\n=================\n*/\nvoid UI_DrawProportionalString( int x, int y, const char* str, int style, vec4_t color ) {\n\tvec4_t\tdrawcolor;\n\tint\t\twidth;\n\tfloat\tsizeScale;\n\n\tsizeScale = UI_ProportionalSizeScale( style );\n\n\tswitch( style & UI_FORMATMASK ) {\n\t\tcase UI_CENTER:\n\t\t\twidth = UI_ProportionalStringWidth( str ) * sizeScale;\n\t\t\tx -= width / 2;\n\t\t\tbreak;\n\n\t\tcase UI_RIGHT:\n\t\t\twidth = UI_ProportionalStringWidth( str ) * sizeScale;\n\t\t\tx -= width;\n\t\t\tbreak;\n\n\t\tcase UI_LEFT:\n\t\tdefault:\n\t\t\tbreak;\n\t}\n\n\tif ( style & UI_DROPSHADOW ) {\n\t\tdrawcolor[0] = drawcolor[1] = drawcolor[2] = 0;\n\t\tdrawcolor[3] = color[3];\n\t\tUI_DrawProportionalString2( x+2, y+2, str, drawcolor, sizeScale, cgs.media.charsetProp );\n\t}\n\n\tif ( style & UI_INVERSE ) {\n\t\tdrawcolor[0] = color[0] * 0.8;\n\t\tdrawcolor[1] = color[1] * 0.8;\n\t\tdrawcolor[2] = color[2] * 0.8;\n\t\tdrawcolor[3] = color[3];\n\t\tUI_DrawProportionalString2( x, y, str, drawcolor, sizeScale, cgs.media.charsetProp );\n\t\treturn;\n\t}\n\n\tif ( style & UI_PULSE ) {\n\t\tdrawcolor[0] = color[0] * 0.8;\n\t\tdrawcolor[1] = color[1] * 0.8;\n\t\tdrawcolor[2] = color[2] * 0.8;\n\t\tdrawcolor[3] = color[3];\n\t\tUI_DrawProportionalString2( x, y, str, color, sizeScale, cgs.media.charsetProp );\n\n\t\tdrawcolor[0] = color[0];\n\t\tdrawcolor[1] = color[1];\n\t\tdrawcolor[2] = color[2];\n\t\tdrawcolor[3] = 0.5 + 0.5 * sin( cg.time / PULSE_DIVISOR );\n\t\tUI_DrawProportionalString2( x, y, str, drawcolor, sizeScale, cgs.media.charsetPropGlow );\n\t\treturn;\n\t}\n\n\tUI_DrawProportionalString2( x, y, str, color, sizeScale, cgs.media.charsetProp );\n}\n#endif // Q3STATIC\n"
  },
  {
    "path": "src/cgame/cg_effects.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n// cg_effects.c -- these functions generate localentities, usually as a result\n// of event processing\n\n#include \"cg_local.h\"\n\n\n/*\n==================\nCG_BubbleTrail\n\nBullets shot underwater\n==================\n*/\nvoid CG_BubbleTrail( vec3_t start, vec3_t end, float spacing ) {\n\tvec3_t\t\tmove;\n\tvec3_t\t\tvec;\n\tfloat\t\tlen;\n\tint\t\t\ti;\n\n\tif ( cg_noProjectileTrail.integer ) {\n\t\treturn;\n\t}\n\n\tVectorCopy (start, move);\n\tVectorSubtract (end, start, vec);\n\tlen = VectorNormalize (vec);\n\n\t// advance a random amount first\n\ti = rand() % (int)spacing;\n\tVectorMA( move, i, vec, move );\n\n\tVectorScale (vec, spacing, vec);\n\n\tfor ( ; i < len; i += spacing ) {\n\t\tlocalEntity_t\t*le;\n\t\trefEntity_t\t\t*re;\n\n\t\tle = CG_AllocLocalEntity();\n\t\tle->leFlags = LEF_PUFF_DONT_SCALE;\n\t\tle->leType = LE_MOVE_SCALE_FADE;\n\t\tle->startTime = cg.time;\n\t\tle->endTime = cg.time + 1000 + random() * 250;\n\t\tle->lifeRate = 1.0 / ( le->endTime - le->startTime );\n\n\t\tre = &le->refEntity;\n\t\tre->shaderTime = cg.time / 1000.0f;\n\n\t\tre->reType = RT_SPRITE;\n\t\tre->rotation = 0;\n\t\tre->radius = 3;\n\t\tre->customShader = cgs.media.waterBubbleShader;\n\t\tre->shaderRGBA[0] = 0xff;\n\t\tre->shaderRGBA[1] = 0xff;\n\t\tre->shaderRGBA[2] = 0xff;\n\t\tre->shaderRGBA[3] = 0xff;\n\n\t\tle->color[3] = 1.0;\n\n\t\tle->pos.trType = TR_LINEAR;\n\t\tle->pos.trTime = cg.time;\n\t\tVectorCopy( move, le->pos.trBase );\n\t\tle->pos.trDelta[0] = crandom()*5;\n\t\tle->pos.trDelta[1] = crandom()*5;\n\t\tle->pos.trDelta[2] = crandom()*5 + 6;\n\n\t\tVectorAdd (move, vec, move);\n\t}\n}\n\n/*\n=====================\nCG_SmokePuff\n\nAdds a smoke puff or blood trail localEntity.\n=====================\n*/\nlocalEntity_t *CG_SmokePuff( const vec3_t p, const vec3_t vel, \n\t\t\t\t   float radius,\n\t\t\t\t   float r, float g, float b, float a,\n\t\t\t\t   float duration,\n\t\t\t\t   int startTime,\n\t\t\t\t   int fadeInTime,\n\t\t\t\t   int leFlags,\n\t\t\t\t   qhandle_t hShader ) {\n\tstatic int\tseed = 0x92;\n\tlocalEntity_t\t*le;\n\trefEntity_t\t\t*re;\n//\tint fadeInTime = startTime + duration / 2;\n\n\tle = CG_AllocLocalEntity();\n\tle->leFlags = leFlags;\n\tle->radius = radius;\n\n\tre = &le->refEntity;\n\tre->rotation = Q_random( &seed ) * 360;\n\tre->radius = radius;\n\tre->shaderTime = startTime / 1000.0f;\n\n\tle->leType = LE_MOVE_SCALE_FADE;\n\tle->startTime = startTime;\n\tle->fadeInTime = fadeInTime;\n\tle->endTime = startTime + duration;\n\tif ( fadeInTime > startTime ) {\n\t\tle->lifeRate = 1.0 / ( le->endTime - le->fadeInTime );\n\t}\n\telse {\n\t\tle->lifeRate = 1.0 / ( le->endTime - le->startTime );\n\t}\n\tle->color[0] = r;\n\tle->color[1] = g; \n\tle->color[2] = b;\n\tle->color[3] = a;\n\n\n\tle->pos.trType = TR_LINEAR;\n\tle->pos.trTime = startTime;\n\tVectorCopy( vel, le->pos.trDelta );\n\tVectorCopy( p, le->pos.trBase );\n\n\tVectorCopy( p, re->origin );\n\tre->customShader = hShader;\n\n\t\n\tre->shaderRGBA[0] = le->color[0] * 0xff;\n\tre->shaderRGBA[1] = le->color[1] * 0xff;\n\tre->shaderRGBA[2] = le->color[2] * 0xff;\n\tre->shaderRGBA[3] = 0xff;\n\t\n\n\tre->reType = RT_SPRITE;\n\tre->radius = le->radius;\n\n\treturn le;\n}\n\n/*\n==================\nCG_SpawnEffect\n\nPlayer teleporting in or out\n==================\n*/\nvoid CG_SpawnEffect( vec3_t org ) {\n\tlocalEntity_t\t*le;\n\trefEntity_t\t\t*re;\n\n\tle = CG_AllocLocalEntity();\n\tle->leFlags = 0;\n\tle->leType = LE_FADE_RGB;\n\tle->startTime = cg.time;\n\tle->endTime = cg.time + 500;\n\tle->lifeRate = 1.0 / ( le->endTime - le->startTime );\n\n\tle->color[0] = le->color[1] = le->color[2] = le->color[3] = 1.0;\n\n\tre = &le->refEntity;\n\n\tre->reType = RT_MODEL;\n\tre->shaderTime = cg.time / 1000.0f;\n\n\tre->customShader = cgs.media.teleportEffectShader;\n\tre->hModel = cgs.media.teleportEffectModel;\n\tAxisClear( re->axis );\n\n\tVectorCopy( org, re->origin );\n\tre->origin[2] -= 24;\n}\n\n/*\n==================\nCG_ScorePlum\n==================\n*/\nvoid CG_ScorePlum( int client, vec3_t org, int score ) {\n\tlocalEntity_t\t*le;\n\trefEntity_t\t\t*re;\n\tvec3_t\t\t\tangles;\n\tstatic vec3_t lastPos;\n\n\t// only visualize for the client that scored\n\tif (client != cg.predictedPlayerState.clientNum || cg_scorePlum.integer == 0) {\n\t\treturn;\n\t}\n\n\tle = CG_AllocLocalEntity();\n\tle->leFlags = 0;\n\tle->leType = LE_SCOREPLUM;\n\tle->startTime = cg.time;\n\tle->endTime = cg.time + 4000;\n\tle->lifeRate = 1.0 / ( le->endTime - le->startTime );\n\n\t\n\tle->color[0] = le->color[1] = le->color[2] = le->color[3] = 1.0;\n\tle->radius = score;\n\t\n\tVectorCopy( org, le->pos.trBase );\n\tif (org[2] >= lastPos[2] - 20 && org[2] <= lastPos[2] + 20) {\n\t\tle->pos.trBase[2] -= 20;\n\t}\n\n\t//CG_Printf( \"Plum origin %i %i %i -- %i\\n\", (int)org[0], (int)org[1], (int)org[2], (int)Distance(org, lastPos));\n\tVectorCopy(org, lastPos);\n\n\n\tre = &le->refEntity;\n\n\tre->reType = RT_SPRITE;\n\tre->radius = 16;\n\n\tVectorClear(angles);\n\tAnglesToAxis( angles, re->axis );\n}\n\n\n/*\n====================\nCG_MakeExplosion\n====================\n*/\nlocalEntity_t *CG_MakeExplosion( vec3_t origin, vec3_t dir, \n\t\t\t\t\t\t\t\tqhandle_t hModel, qhandle_t shader,\n\t\t\t\t\t\t\t\tint msec, qboolean isSprite ) {\n\tfloat\t\t\tang;\n\tlocalEntity_t\t*ex;\n\tint\t\t\t\toffset;\n\tvec3_t\t\t\ttmpVec, newOrigin;\n\n\tif ( msec <= 0 ) {\n\t\tCG_Error( \"CG_MakeExplosion: msec = %i\", msec );\n\t}\n\n\t// skew the time a bit so they aren't all in sync\n\toffset = rand() & 63;\n\n\tex = CG_AllocLocalEntity();\n\tif ( isSprite ) {\n\t\tex->leType = LE_SPRITE_EXPLOSION;\n\n\t\t// randomly rotate sprite orientation\n\t\tex->refEntity.rotation = rand() % 360;\n\t\tVectorScale( dir, 16, tmpVec );\n\t\tVectorAdd( tmpVec, origin, newOrigin );\n\t} else {\n\t\tex->leType = LE_EXPLOSION;\n\t\tVectorCopy( origin, newOrigin );\n\n\t\t// set axis with random rotate\n\t\tif ( !dir ) {\n\t\t\tAxisClear( ex->refEntity.axis );\n\t\t} else {\n\t\t\tang = rand() % 360;\n\t\t\tVectorCopy( dir, ex->refEntity.axis[0] );\n\t\t\tRotateAroundDirection( ex->refEntity.axis, ang );\n\t\t}\n\t}\n\n\tex->startTime = cg.time - offset;\n\tex->endTime = ex->startTime + msec;\n\n\t// bias the time so all shader effects start correctly\n\tex->refEntity.shaderTime = ex->startTime / 1000.0f;\n\n\tex->refEntity.hModel = hModel;\n\tex->refEntity.customShader = shader;\n\n\t// set origin\n\tVectorCopy( newOrigin, ex->refEntity.origin );\n\tVectorCopy( newOrigin, ex->refEntity.oldorigin );\n\n\tex->color[0] = ex->color[1] = ex->color[2] = 1.0;\n\n\treturn ex;\n}\n\n\n/*\n=================\nCG_Bleed\n\nThis is the spurt of blood when a character gets hit\n=================\n*/\nvoid CG_Bleed( vec3_t origin, int entityNum ) {\n\tlocalEntity_t\t*ex;\n\n\tif ( !cg_blood.integer ) {\n\t\treturn;\n\t}\n\n\tex = CG_AllocLocalEntity();\n\tex->leType = LE_EXPLOSION;\n\n\tex->startTime = cg.time;\n\tex->endTime = ex->startTime + 500;\n\t\n\tVectorCopy ( origin, ex->refEntity.origin);\n\tex->refEntity.reType = RT_SPRITE;\n\tex->refEntity.rotation = rand() % 360;\n\tex->refEntity.radius = 24;\n\n\tex->refEntity.customShader = cgs.media.bloodExplosionShader;\n\n\t// don't show player's own blood in view\n\tif ( entityNum == cg.snap->ps.clientNum ) {\n\t\tex->refEntity.renderfx |= RF_THIRD_PERSON;\n\t}\n}\n\n\n\n/*\n==================\nCG_LaunchGib\n==================\n*/\nvoid CG_LaunchGib( vec3_t origin, vec3_t velocity, qhandle_t hModel ) {\n\tlocalEntity_t\t*le;\n\trefEntity_t\t\t*re;\n\n\tle = CG_AllocLocalEntity();\n\tre = &le->refEntity;\n\n\tle->leType = LE_FRAGMENT;\n\tle->startTime = cg.time;\n\tle->endTime = le->startTime + 5000 + random() * 3000;\n\n\tVectorCopy( origin, re->origin );\n\tAxisCopy( axisDefault, re->axis );\n\tre->hModel = hModel;\n\n\tle->pos.trType = TR_GRAVITY;\n\tVectorCopy( origin, le->pos.trBase );\n\tVectorCopy( velocity, le->pos.trDelta );\n\tle->pos.trTime = cg.time;\n\n\tle->bounceFactor = 0.6f;\n\n\tle->leBounceSoundType = LEBS_BLOOD;\n\tle->leMarkType = LEMT_BLOOD;\n}\n\n/*\n===================\nCG_GibPlayer\n\nGenerated a bunch of gibs launching out from the bodies location\n===================\n*/\n#define\tGIB_VELOCITY\t250\n#define\tGIB_JUMP\t\t250\nvoid CG_GibPlayer( vec3_t playerOrigin ) {\n\tvec3_t\torigin, velocity;\n\n\tif ( !cg_blood.integer ) {\n\t\treturn;\n\t}\n\n\tVectorCopy( playerOrigin, origin );\n\tvelocity[0] = crandom()*GIB_VELOCITY;\n\tvelocity[1] = crandom()*GIB_VELOCITY;\n\tvelocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;\n\tif ( rand() & 1 ) {\n\t\tCG_LaunchGib( origin, velocity, cgs.media.gibSkull );\n\t} else {\n\t\tCG_LaunchGib( origin, velocity, cgs.media.gibBrain );\n\t}\n\n\t// allow gibs to be turned off for speed\n\tif ( !cg_gibs.integer ) {\n\t\treturn;\n\t}\n\n\tVectorCopy( playerOrigin, origin );\n\tvelocity[0] = crandom()*GIB_VELOCITY;\n\tvelocity[1] = crandom()*GIB_VELOCITY;\n\tvelocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;\n\tCG_LaunchGib( origin, velocity, cgs.media.gibAbdomen );\n\n\tVectorCopy( playerOrigin, origin );\n\tvelocity[0] = crandom()*GIB_VELOCITY;\n\tvelocity[1] = crandom()*GIB_VELOCITY;\n\tvelocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;\n\tCG_LaunchGib( origin, velocity, cgs.media.gibArm );\n\n\tVectorCopy( playerOrigin, origin );\n\tvelocity[0] = crandom()*GIB_VELOCITY;\n\tvelocity[1] = crandom()*GIB_VELOCITY;\n\tvelocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;\n\tCG_LaunchGib( origin, velocity, cgs.media.gibChest );\n\n\tVectorCopy( playerOrigin, origin );\n\tvelocity[0] = crandom()*GIB_VELOCITY;\n\tvelocity[1] = crandom()*GIB_VELOCITY;\n\tvelocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;\n\tCG_LaunchGib( origin, velocity, cgs.media.gibFist );\n\n\tVectorCopy( playerOrigin, origin );\n\tvelocity[0] = crandom()*GIB_VELOCITY;\n\tvelocity[1] = crandom()*GIB_VELOCITY;\n\tvelocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;\n\tCG_LaunchGib( origin, velocity, cgs.media.gibFoot );\n\n\tVectorCopy( playerOrigin, origin );\n\tvelocity[0] = crandom()*GIB_VELOCITY;\n\tvelocity[1] = crandom()*GIB_VELOCITY;\n\tvelocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;\n\tCG_LaunchGib( origin, velocity, cgs.media.gibForearm );\n\n\tVectorCopy( playerOrigin, origin );\n\tvelocity[0] = crandom()*GIB_VELOCITY;\n\tvelocity[1] = crandom()*GIB_VELOCITY;\n\tvelocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;\n\tCG_LaunchGib( origin, velocity, cgs.media.gibIntestine );\n\n\tVectorCopy( playerOrigin, origin );\n\tvelocity[0] = crandom()*GIB_VELOCITY;\n\tvelocity[1] = crandom()*GIB_VELOCITY;\n\tvelocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;\n\tCG_LaunchGib( origin, velocity, cgs.media.gibLeg );\n\n\tVectorCopy( playerOrigin, origin );\n\tvelocity[0] = crandom()*GIB_VELOCITY;\n\tvelocity[1] = crandom()*GIB_VELOCITY;\n\tvelocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;\n\tCG_LaunchGib( origin, velocity, cgs.media.gibLeg );\n}\n\n/*\n==================\nCG_LaunchGib\n==================\n*/\nvoid CG_LaunchExplode( vec3_t origin, vec3_t velocity, qhandle_t hModel ) {\n\tlocalEntity_t\t*le;\n\trefEntity_t\t\t*re;\n\n\tle = CG_AllocLocalEntity();\n\tre = &le->refEntity;\n\n\tle->leType = LE_FRAGMENT;\n\tle->startTime = cg.time;\n\tle->endTime = le->startTime + 10000 + random() * 6000;\n\n\tVectorCopy( origin, re->origin );\n\tAxisCopy( axisDefault, re->axis );\n\tre->hModel = hModel;\n\n\tle->pos.trType = TR_GRAVITY;\n\tVectorCopy( origin, le->pos.trBase );\n\tVectorCopy( velocity, le->pos.trDelta );\n\tle->pos.trTime = cg.time;\n\n\tle->bounceFactor = 0.1f;\n\n\tle->leBounceSoundType = LEBS_BRASS;\n\tle->leMarkType = LEMT_NONE;\n}\n\n#define\tEXP_VELOCITY\t100\n#define\tEXP_JUMP\t\t150\n/*\n===================\nCG_GibPlayer\n\nGenerated a bunch of gibs launching out from the bodies location\n===================\n*/\nvoid CG_BigExplode( vec3_t playerOrigin ) {\n\tvec3_t\torigin, velocity;\n\n\tif ( !cg_blood.integer ) {\n\t\treturn;\n\t}\n\n\tVectorCopy( playerOrigin, origin );\n\tvelocity[0] = crandom()*EXP_VELOCITY;\n\tvelocity[1] = crandom()*EXP_VELOCITY;\n\tvelocity[2] = EXP_JUMP + crandom()*EXP_VELOCITY;\n\tCG_LaunchExplode( origin, velocity, cgs.media.smoke2 );\n\n\tVectorCopy( playerOrigin, origin );\n\tvelocity[0] = crandom()*EXP_VELOCITY;\n\tvelocity[1] = crandom()*EXP_VELOCITY;\n\tvelocity[2] = EXP_JUMP + crandom()*EXP_VELOCITY;\n\tCG_LaunchExplode( origin, velocity, cgs.media.smoke2 );\n\n\tVectorCopy( playerOrigin, origin );\n\tvelocity[0] = crandom()*EXP_VELOCITY*1.5;\n\tvelocity[1] = crandom()*EXP_VELOCITY*1.5;\n\tvelocity[2] = EXP_JUMP + crandom()*EXP_VELOCITY;\n\tCG_LaunchExplode( origin, velocity, cgs.media.smoke2 );\n\n\tVectorCopy( playerOrigin, origin );\n\tvelocity[0] = crandom()*EXP_VELOCITY*2.0;\n\tvelocity[1] = crandom()*EXP_VELOCITY*2.0;\n\tvelocity[2] = EXP_JUMP + crandom()*EXP_VELOCITY;\n\tCG_LaunchExplode( origin, velocity, cgs.media.smoke2 );\n\n\tVectorCopy( playerOrigin, origin );\n\tvelocity[0] = crandom()*EXP_VELOCITY*2.5;\n\tvelocity[1] = crandom()*EXP_VELOCITY*2.5;\n\tvelocity[2] = EXP_JUMP + crandom()*EXP_VELOCITY;\n\tCG_LaunchExplode( origin, velocity, cgs.media.smoke2 );\n}\n\n"
  },
  {
    "path": "src/cgame/cg_ents.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n// cg_ents.c -- present snapshot entities, happens every single frame\n\n#include \"cg_local.h\"\n\n\n/*\n======================\nCG_PositionEntityOnTag\n\nModifies the entities position and axis by the given\ntag location\n======================\n*/\nvoid CG_PositionEntityOnTag( refEntity_t *entity, const refEntity_t *parent, \n\t\t\t\t\t\t\tqhandle_t parentModel, char *tagName ) {\n\tint\t\t\t\ti;\n\torientation_t\tlerped;\n\t\n\t// lerp the tag\n\ttrap_R_LerpTag( &lerped, parentModel, parent->oldframe, parent->frame,\n\t\t1.0 - parent->backlerp, tagName );\n\n\t// FIXME: allow origin offsets along tag?\n\tVectorCopy( parent->origin, entity->origin );\n\tfor ( i = 0 ; i < 3 ; i++ ) {\n\t\tVectorMA( entity->origin, lerped.origin[i], parent->axis[i], entity->origin );\n\t}\n\n\t// had to cast away the const to avoid compiler problems...\n\tMatrixMultiply( lerped.axis, ((refEntity_t *)parent)->axis, entity->axis );\n\tentity->backlerp = parent->backlerp;\n}\n\n\n/*\n======================\nCG_PositionRotatedEntityOnTag\n\nModifies the entities position and axis by the given\ntag location\n======================\n*/\nvoid CG_PositionRotatedEntityOnTag( refEntity_t *entity, const refEntity_t *parent, \n\t\t\t\t\t\t\tqhandle_t parentModel, char *tagName ) {\n\tint\t\t\t\ti;\n\torientation_t\tlerped;\n\tvec3_t\t\t\ttempAxis[3];\n\n//AxisClear( entity->axis );\n\t// lerp the tag\n\ttrap_R_LerpTag( &lerped, parentModel, parent->oldframe, parent->frame,\n\t\t1.0 - parent->backlerp, tagName );\n\n\t// FIXME: allow origin offsets along tag?\n\tVectorCopy( parent->origin, entity->origin );\n\tfor ( i = 0 ; i < 3 ; i++ ) {\n\t\tVectorMA( entity->origin, lerped.origin[i], parent->axis[i], entity->origin );\n\t}\n\n\t// had to cast away the const to avoid compiler problems...\n\tMatrixMultiply( entity->axis, lerped.axis, tempAxis );\n\tMatrixMultiply( tempAxis, ((refEntity_t *)parent)->axis, entity->axis );\n}\n\n\n\n/*\n==========================================================================\n\nFUNCTIONS CALLED EACH FRAME\n\n==========================================================================\n*/\n\n/*\n======================\nCG_SetEntitySoundPosition\n\nAlso called by event processing code\n======================\n*/\nvoid CG_SetEntitySoundPosition( centity_t *cent ) {\n\tif ( cent->currentState.solid == SOLID_BMODEL ) {\n\t\tvec3_t\torigin;\n\t\tfloat\t*v;\n\n\t\tv = cgs.inlineModelMidpoints[ cent->currentState.modelindex ];\n\t\tVectorAdd( cent->lerpOrigin, v, origin );\n\t\ttrap_S_UpdateEntityPosition( cent->currentState.number, origin );\n\t} else {\n\t\ttrap_S_UpdateEntityPosition( cent->currentState.number, cent->lerpOrigin );\n\t}\n}\n\n/*\n==================\nCG_EntityEffects\n\nAdd continuous entity effects, like local entity emission and lighting\n==================\n*/\nstatic void CG_EntityEffects( centity_t *cent ) {\n\n\t// update sound origins\n\tCG_SetEntitySoundPosition( cent );\n\n\t// add loop sound\n\tif ( cent->currentState.loopSound ) {\n\t\tif (cent->currentState.eType != ET_SPEAKER) {\n\t\t\ttrap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, \n\t\t\t\tcgs.gameSounds[ cent->currentState.loopSound ] );\n\t\t} else {\n\t\t\ttrap_S_AddRealLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, \n\t\t\t\tcgs.gameSounds[ cent->currentState.loopSound ] );\n\t\t}\n\t}\n\n\n\t// constant light glow\n\tif ( cent->currentState.constantLight ) {\n\t\tint\t\tcl;\n\t\tint\t\ti, r, g, b;\n\n\t\tcl = cent->currentState.constantLight;\n\t\tr = cl & 255;\n\t\tg = ( cl >> 8 ) & 255;\n\t\tb = ( cl >> 16 ) & 255;\n\t\ti = ( ( cl >> 24 ) & 255 ) * 4;\n\t\ttrap_R_AddLightToScene( cent->lerpOrigin, i, r, g, b );\n\t}\n\n}\n\n\n/*\n==================\nCG_General\n==================\n*/\nstatic void CG_General( centity_t *cent ) {\n\trefEntity_t\t\t\tent;\n\tentityState_t\t\t*s1;\n\n\ts1 = &cent->currentState;\n\n\t// if set to invisible, skip\n\tif (!s1->modelindex) {\n\t\treturn;\n\t}\n\n\tmemset (&ent, 0, sizeof(ent));\n\n\t// set frame\n\n\tent.frame = s1->frame;\n\tent.oldframe = ent.frame;\n\tent.backlerp = 0;\n\n\tVectorCopy( cent->lerpOrigin, ent.origin);\n\tVectorCopy( cent->lerpOrigin, ent.oldorigin);\n\n\tent.hModel = cgs.gameModels[s1->modelindex];\n\n\t// player model\n\tif (s1->number == cg.snap->ps.clientNum) {\n\t\tent.renderfx |= RF_THIRD_PERSON;\t// only draw from mirrors\n\t}\n\n\t// convert angles to axis\n\tAnglesToAxis( cent->lerpAngles, ent.axis );\n\n\t// add to refresh list\n\ttrap_R_AddRefEntityToScene (&ent);\n}\n\n/*\n==================\nCG_Speaker\n\nSpeaker entities can automatically play sounds\n==================\n*/\nstatic void CG_Speaker( centity_t *cent ) {\n\tif ( ! cent->currentState.clientNum ) {\t// FIXME: use something other than clientNum...\n\t\treturn;\t\t// not auto triggering\n\t}\n\n\tif ( cg.time < cent->miscTime ) {\n\t\treturn;\n\t}\n\n\ttrap_S_StartSound (NULL, cent->currentState.number, CHAN_ITEM, cgs.gameSounds[cent->currentState.eventParm] );\n\n\t//\tent->s.frame = ent->wait * 10;\n\t//\tent->s.clientNum = ent->random * 10;\n\tcent->miscTime = cg.time + cent->currentState.frame * 100 + cent->currentState.clientNum * 100 * crandom();\n}\n\n/*\n==================\nCG_Item\n==================\n*/\nstatic void CG_Item( centity_t *cent ) {\n\trefEntity_t\t\tent;\n\tentityState_t\t*es;\n\tgitem_t\t\t\t*item;\n\tint\t\t\t\tmsec;\n\tfloat\t\t\tfrac;\n\tfloat\t\t\tscale;\n\tweaponInfo_t\t*wi;\n\n\tes = &cent->currentState;\n\tif ( es->modelindex >= bg_numItems ) {\n\t\tCG_Error( \"Bad item index %i on entity\", es->modelindex );\n\t}\n\n\t// if set to invisible, skip\n\tif ( !es->modelindex || ( es->eFlags & EF_NODRAW ) ) {\n\t\treturn;\n\t}\n\n\titem = &bg_itemlist[ es->modelindex ];\n\tif ( cg_simpleItems.integer && item->giType != IT_TEAM ) {\n\t\tmemset( &ent, 0, sizeof( ent ) );\n\t\tent.reType = RT_SPRITE;\n\t\tVectorCopy( cent->lerpOrigin, ent.origin );\n\t\tent.radius = 14;\n\t\tent.customShader = cg_items[es->modelindex].icon;\n\t\tent.shaderRGBA[0] = 255;\n\t\tent.shaderRGBA[1] = 255;\n\t\tent.shaderRGBA[2] = 255;\n\t\tent.shaderRGBA[3] = 255;\n\t\ttrap_R_AddRefEntityToScene(&ent);\n\t\treturn;\n\t}\n\n\t// items bob up and down continuously\n\tscale = 0.005 + cent->currentState.number * 0.00001;\n\tcent->lerpOrigin[2] += 4 + cos( ( cg.time + 1000 ) *  scale ) * 4;\n\n\tmemset (&ent, 0, sizeof(ent));\n\n\t// autorotate at one of two speeds\n\tif ( item->giType == IT_HEALTH ) {\n\t\tVectorCopy( cg.autoAnglesFast, cent->lerpAngles );\n\t\tAxisCopy( cg.autoAxisFast, ent.axis );\n\t} else {\n\t\tVectorCopy( cg.autoAngles, cent->lerpAngles );\n\t\tAxisCopy( cg.autoAxis, ent.axis );\n\t}\n\n\twi = NULL;\n\t// the weapons have their origin where they attatch to player\n\t// models, so we need to offset them or they will rotate\n\t// eccentricly\n\tif ( item->giType == IT_WEAPON ) {\n\t\twi = &cg_weapons[item->giTag];\n\t\tcent->lerpOrigin[0] -= \n\t\t\twi->weaponMidpoint[0] * ent.axis[0][0] +\n\t\t\twi->weaponMidpoint[1] * ent.axis[1][0] +\n\t\t\twi->weaponMidpoint[2] * ent.axis[2][0];\n\t\tcent->lerpOrigin[1] -= \n\t\t\twi->weaponMidpoint[0] * ent.axis[0][1] +\n\t\t\twi->weaponMidpoint[1] * ent.axis[1][1] +\n\t\t\twi->weaponMidpoint[2] * ent.axis[2][1];\n\t\tcent->lerpOrigin[2] -= \n\t\t\twi->weaponMidpoint[0] * ent.axis[0][2] +\n\t\t\twi->weaponMidpoint[1] * ent.axis[1][2] +\n\t\t\twi->weaponMidpoint[2] * ent.axis[2][2];\n\n\t\tcent->lerpOrigin[2] += 8;\t// an extra height boost\n\t}\n\n\tent.hModel = cg_items[es->modelindex].models[0];\n\n\tVectorCopy( cent->lerpOrigin, ent.origin);\n\tVectorCopy( cent->lerpOrigin, ent.oldorigin);\n\n\tent.nonNormalizedAxes = qfalse;\n\n\t// if just respawned, slowly scale up\n\tmsec = cg.time - cent->miscTime;\n\tif ( msec >= 0 && msec < ITEM_SCALEUP_TIME ) {\n\t\tfrac = (float)msec / ITEM_SCALEUP_TIME;\n\t\tVectorScale( ent.axis[0], frac, ent.axis[0] );\n\t\tVectorScale( ent.axis[1], frac, ent.axis[1] );\n\t\tVectorScale( ent.axis[2], frac, ent.axis[2] );\n\t\tent.nonNormalizedAxes = qtrue;\n\t} else {\n\t\tfrac = 1.0;\n\t}\n\n\t// items without glow textures need to keep a minimum light value\n\t// so they are always visible\n\tif ( ( item->giType == IT_WEAPON ) ||\n\t\t ( item->giType == IT_ARMOR ) ) {\n\t\tent.renderfx |= RF_MINLIGHT;\n\t}\n\n\t// increase the size of the weapons when they are presented as items\n\tif ( item->giType == IT_WEAPON ) {\n\t\tVectorScale( ent.axis[0], 1.5, ent.axis[0] );\n\t\tVectorScale( ent.axis[1], 1.5, ent.axis[1] );\n\t\tVectorScale( ent.axis[2], 1.5, ent.axis[2] );\n\t\tent.nonNormalizedAxes = qtrue;\n\t}\n\n\t// add to refresh list\n\ttrap_R_AddRefEntityToScene(&ent);\n\n\t// accompanying rings / spheres for powerups\n\tif ( !cg_simpleItems.integer ) \n\t{\n\t\tvec3_t spinAngles;\n\n\t\tVectorClear( spinAngles );\n\n\t\tif ( item->giType == IT_HEALTH || item->giType == IT_POWERUP )\n\t\t{\n\t\t\tif ( ( ent.hModel = cg_items[es->modelindex].models[1] ) != 0 )\n\t\t\t{\n\t\t\t\tif ( item->giType == IT_POWERUP )\n\t\t\t\t{\n\t\t\t\t\tent.origin[2] += 12;\n\t\t\t\t\tspinAngles[1] = ( cg.time & 1023 ) * 360 / -1024.0f;\n\t\t\t\t}\n\t\t\t\tAnglesToAxis( spinAngles, ent.axis );\n\t\t\t\t\n\t\t\t\t// scale up if respawning\n\t\t\t\tif ( frac != 1.0 ) {\n\t\t\t\t\tVectorScale( ent.axis[0], frac, ent.axis[0] );\n\t\t\t\t\tVectorScale( ent.axis[1], frac, ent.axis[1] );\n\t\t\t\t\tVectorScale( ent.axis[2], frac, ent.axis[2] );\n\t\t\t\t\tent.nonNormalizedAxes = qtrue;\n\t\t\t\t}\n\t\t\t\ttrap_R_AddRefEntityToScene( &ent );\n\t\t\t}\n\t\t}\n\t}\n}\n\n//============================================================================\n\n/*\n===============\nCG_Missile\n===============\n*/\nstatic void CG_Missile( centity_t *cent ) {\n\trefEntity_t\t\t\tent;\n\tentityState_t\t\t*s1;\n\tconst weaponInfo_t\t\t*weapon;\n//\tint\tcol;\n\n\ts1 = &cent->currentState;\n\tif ( s1->weapon > WP_NUM_WEAPONS ) {\n\t\ts1->weapon = 0;\n\t}\n\tweapon = &cg_weapons[s1->weapon];\n\n\t// calculate the axis\n\tVectorCopy( s1->angles, cent->lerpAngles);\n\n\t// add trails\n\tif ( weapon->missileTrailFunc ) \n\t{\n\t\tweapon->missileTrailFunc( cent, weapon );\n\t}\n/*\n\tif ( cent->currentState.modelindex == TEAM_RED ) {\n\t\tcol = 1;\n\t}\n\telse if ( cent->currentState.modelindex == TEAM_BLUE ) {\n\t\tcol = 2;\n\t}\n\telse {\n\t\tcol = 0;\n\t}\n\n\t// add dynamic light\n\tif ( weapon->missileDlight ) {\n\t\ttrap_R_AddLightToScene(cent->lerpOrigin, weapon->missileDlight, \n\t\t\tweapon->missileDlightColor[col][0], weapon->missileDlightColor[col][1], weapon->missileDlightColor[col][2] );\n\t}\n*/\n\t// add dynamic light\n\tif ( weapon->missileDlight ) {\n\t\ttrap_R_AddLightToScene(cent->lerpOrigin, weapon->missileDlight, \n\t\t\tweapon->missileDlightColor[0], weapon->missileDlightColor[1], weapon->missileDlightColor[2] );\n\t}\n\n\t// add missile sound\n\tif ( weapon->missileSound ) {\n\t\tvec3_t\tvelocity;\n\n\t\tBG_EvaluateTrajectoryDelta( &cent->currentState.pos, cg.time, velocity );\n\n\t\ttrap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, velocity, weapon->missileSound );\n\t}\n\n\t// create the render entity\n\tmemset (&ent, 0, sizeof(ent));\n\tVectorCopy( cent->lerpOrigin, ent.origin);\n\tVectorCopy( cent->lerpOrigin, ent.oldorigin);\n\n\tif ( cent->currentState.weapon == WP_PLASMAGUN ) {\n\t\tent.reType = RT_SPRITE;\n\t\tent.radius = 16;\n\t\tent.rotation = 0;\n\t\tent.customShader = cgs.media.plasmaBallShader;\n\t\ttrap_R_AddRefEntityToScene( &ent );\n\t\treturn;\n\t}\n\n\t// flicker between two skins\n\tent.skinNum = cg.clientFrame & 1;\n\tent.hModel = weapon->missileModel;\n\tent.renderfx = weapon->missileRenderfx | RF_NOSHADOW;\n\n\t// convert direction of travel into axis\n\tif ( VectorNormalize2( s1->pos.trDelta, ent.axis[0] ) == 0 ) {\n\t\tent.axis[0][2] = 1;\n\t}\n\n\t// spin as it moves\n\tif ( s1->pos.trType != TR_STATIONARY ) {\n\t\tRotateAroundDirection( ent.axis, cg.time / 4 );\n\t} else {\n\t\t{\n\t\t\tRotateAroundDirection( ent.axis, s1->time );\n\t\t}\n\t}\n\n\t// add to refresh list, possibly with quad glow\n\tCG_AddRefEntityWithPowerups( &ent, s1, TEAM_FREE );\n}\n\n/*\n===============\nCG_Grapple\n\nThis is called when the grapple is sitting up against the wall\n===============\n*/\nstatic void CG_Grapple( centity_t *cent ) {\n\trefEntity_t\t\t\tent;\n\tentityState_t\t\t*s1;\n\tconst weaponInfo_t\t\t*weapon;\n\n\ts1 = &cent->currentState;\n\tif ( s1->weapon > WP_NUM_WEAPONS ) {\n\t\ts1->weapon = 0;\n\t}\n\tweapon = &cg_weapons[s1->weapon];\n\n\t// calculate the axis\n\tVectorCopy( s1->angles, cent->lerpAngles);\n\n#if 0 // FIXME add grapple pull sound here..?\n\t// add missile sound\n\tif ( weapon->missileSound ) {\n\t\ttrap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->missileSound );\n\t}\n#endif\n\n\t// Will draw cable if needed\n\tCG_GrappleTrail ( cent, weapon );\n\n\t// create the render entity\n\tmemset (&ent, 0, sizeof(ent));\n\tVectorCopy( cent->lerpOrigin, ent.origin);\n\tVectorCopy( cent->lerpOrigin, ent.oldorigin);\n\n\t// flicker between two skins\n\tent.skinNum = cg.clientFrame & 1;\n\tent.hModel = weapon->missileModel;\n\tent.renderfx = weapon->missileRenderfx | RF_NOSHADOW;\n\n\t// convert direction of travel into axis\n\tif ( VectorNormalize2( s1->pos.trDelta, ent.axis[0] ) == 0 ) {\n\t\tent.axis[0][2] = 1;\n\t}\n\n\ttrap_R_AddRefEntityToScene( &ent );\n}\n\n/*\n===============\nCG_Mover\n===============\n*/\nstatic void CG_Mover( centity_t *cent ) {\n\trefEntity_t\t\t\tent;\n\tentityState_t\t\t*s1;\n\n\ts1 = &cent->currentState;\n\n\t// create the render entity\n\tmemset (&ent, 0, sizeof(ent));\n\tVectorCopy( cent->lerpOrigin, ent.origin);\n\tVectorCopy( cent->lerpOrigin, ent.oldorigin);\n\tAnglesToAxis( cent->lerpAngles, ent.axis );\n\n\tent.renderfx = RF_NOSHADOW;\n\n\t// flicker between two skins (FIXME?)\n\tent.skinNum = ( cg.time >> 6 ) & 1;\n\n\t// get the model, either as a bmodel or a modelindex\n\tif ( s1->solid == SOLID_BMODEL ) {\n\t\tent.hModel = cgs.inlineDrawModel[s1->modelindex];\n\t} else {\n\t\tent.hModel = cgs.gameModels[s1->modelindex];\n\t}\n\n\t// add to refresh list\n\ttrap_R_AddRefEntityToScene(&ent);\n\n\t// add the secondary model\n\tif ( s1->modelindex2 ) {\n\t\tent.skinNum = 0;\n\t\tent.hModel = cgs.gameModels[s1->modelindex2];\n\t\ttrap_R_AddRefEntityToScene(&ent);\n\t}\n\n}\n\n/*\n===============\nCG_Beam\n\nAlso called as an event\n===============\n*/\nvoid CG_Beam( centity_t *cent ) {\n\trefEntity_t\t\t\tent;\n\tentityState_t\t\t*s1;\n\n\ts1 = &cent->currentState;\n\n\t// create the render entity\n\tmemset (&ent, 0, sizeof(ent));\n\tVectorCopy( s1->pos.trBase, ent.origin );\n\tVectorCopy( s1->origin2, ent.oldorigin );\n\tAxisClear( ent.axis );\n\tent.reType = RT_BEAM;\n\n\tent.renderfx = RF_NOSHADOW;\n\n\t// add to refresh list\n\ttrap_R_AddRefEntityToScene(&ent);\n}\n\n\n/*\n===============\nCG_Portal\n===============\n*/\nstatic void CG_Portal( centity_t *cent ) {\n\trefEntity_t\t\t\tent;\n\tentityState_t\t\t*s1;\n\n\ts1 = &cent->currentState;\n\n\t// create the render entity\n\tmemset (&ent, 0, sizeof(ent));\n\tVectorCopy( cent->lerpOrigin, ent.origin );\n\tVectorCopy( s1->origin2, ent.oldorigin );\n\tByteToDir( s1->eventParm, ent.axis[0] );\n\tPerpendicularVector( ent.axis[1], ent.axis[0] );\n\n\t// negating this tends to get the directions like they want\n\t// we really should have a camera roll value\n\tVectorSubtract( vec3_origin, ent.axis[1], ent.axis[1] );\n\n\tCrossProduct( ent.axis[0], ent.axis[1], ent.axis[2] );\n\tent.reType = RT_PORTALSURFACE;\n\tent.oldframe = s1->powerups;\n\tent.frame = s1->frame;\t\t// rotation speed\n\tent.skinNum = s1->clientNum/256.0 * 360;\t// roll offset\n\n\t// add to refresh list\n\ttrap_R_AddRefEntityToScene(&ent);\n}\n\n\n/*\n=========================\nCG_AdjustPositionForMover\n\nAlso called by client movement prediction code\n=========================\n*/\nvoid CG_AdjustPositionForMover( const vec3_t in, int moverNum, int fromTime, int toTime, vec3_t out ) {\n\tcentity_t\t*cent;\n\tvec3_t\toldOrigin, origin, deltaOrigin;\n\tvec3_t\toldAngles, angles, deltaAngles;\n\n\tif ( moverNum <= 0 || moverNum >= ENTITYNUM_MAX_NORMAL ) {\n\t\tVectorCopy( in, out );\n\t\treturn;\n\t}\n\n\tcent = &cg_entities[ moverNum ];\n\tif ( cent->currentState.eType != ET_MOVER ) {\n\t\tVectorCopy( in, out );\n\t\treturn;\n\t}\n\n\tBG_EvaluateTrajectory( &cent->currentState.pos, fromTime, oldOrigin );\n\tBG_EvaluateTrajectory( &cent->currentState.apos, fromTime, oldAngles );\n\n\tBG_EvaluateTrajectory( &cent->currentState.pos, toTime, origin );\n\tBG_EvaluateTrajectory( &cent->currentState.apos, toTime, angles );\n\n\tVectorSubtract( origin, oldOrigin, deltaOrigin );\n\tVectorSubtract( angles, oldAngles, deltaAngles );\n\n\tVectorAdd( in, deltaOrigin, out );\n\n\t// FIXME: origin change when on a rotating object\n}\n\n\n/*\n=============================\nCG_InterpolateEntityPosition\n=============================\n*/\nstatic void CG_InterpolateEntityPosition( centity_t *cent ) {\n\tvec3_t\t\tcurrent, next;\n\tfloat\t\tf;\n\n\t// it would be an internal error to find an entity that interpolates without\n\t// a snapshot ahead of the current one\n\tif ( cg.nextSnap == NULL ) {\n\t\tCG_Error( \"CG_InterpoateEntityPosition: cg.nextSnap == NULL\" );\n\t}\n\n\tf = cg.frameInterpolation;\n\n\t// this will linearize a sine or parabolic curve, but it is important\n\t// to not extrapolate player positions if more recent data is available\n\tBG_EvaluateTrajectory( &cent->currentState.pos, cg.snap->serverTime, current );\n\tBG_EvaluateTrajectory( &cent->nextState.pos, cg.nextSnap->serverTime, next );\n\n\tcent->lerpOrigin[0] = current[0] + f * ( next[0] - current[0] );\n\tcent->lerpOrigin[1] = current[1] + f * ( next[1] - current[1] );\n\tcent->lerpOrigin[2] = current[2] + f * ( next[2] - current[2] );\n\n\tBG_EvaluateTrajectory( &cent->currentState.apos, cg.snap->serverTime, current );\n\tBG_EvaluateTrajectory( &cent->nextState.apos, cg.nextSnap->serverTime, next );\n\n\tcent->lerpAngles[0] = LerpAngle( current[0], next[0], f );\n\tcent->lerpAngles[1] = LerpAngle( current[1], next[1], f );\n\tcent->lerpAngles[2] = LerpAngle( current[2], next[2], f );\n\n}\n\n/*\n===============\nCG_CalcEntityLerpPositions\n\n===============\n*/\nstatic void CG_CalcEntityLerpPositions( centity_t *cent ) {\n\n\t// if this player does not want to see extrapolated players\n\tif ( !cg_smoothClients.integer ) {\n\t\t// make sure the clients use TR_INTERPOLATE\n\t\tif ( cent->currentState.number < MAX_CLIENTS ) {\n\t\t\tcent->currentState.pos.trType = TR_INTERPOLATE;\n\t\t\tcent->nextState.pos.trType = TR_INTERPOLATE;\n\t\t}\n\t}\n\n\tif ( cent->interpolate && cent->currentState.pos.trType == TR_INTERPOLATE ) {\n\t\tCG_InterpolateEntityPosition( cent );\n\t\treturn;\n\t}\n\n\t// first see if we can interpolate between two snaps for\n\t// linear extrapolated clients\n\tif ( cent->interpolate && cent->currentState.pos.trType == TR_LINEAR_STOP &&\n\t\t\t\t\t\t\t\t\t\t\tcent->currentState.number < MAX_CLIENTS) {\n\t\tCG_InterpolateEntityPosition( cent );\n\t\treturn;\n\t}\n\n\t// just use the current frame and evaluate as best we can\n\tBG_EvaluateTrajectory( &cent->currentState.pos, cg.time, cent->lerpOrigin );\n\tBG_EvaluateTrajectory( &cent->currentState.apos, cg.time, cent->lerpAngles );\n\n\t// adjust for riding a mover if it wasn't rolled into the predicted\n\t// player state\n\tif ( cent != &cg.predictedPlayerEntity ) {\n\t\tCG_AdjustPositionForMover( cent->lerpOrigin, cent->currentState.groundEntityNum, \n\t\tcg.snap->serverTime, cg.time, cent->lerpOrigin );\n\t}\n}\n\n/*\n===============\nCG_TeamBase\n===============\n*/\nstatic void CG_TeamBase( centity_t *cent ) {\n\trefEntity_t model;\n\tif ( cgs.gametype == GT_CTF) {\n\t\t// show the flag base\n\t\tmemset(&model, 0, sizeof(model));\n\t\tmodel.reType = RT_MODEL;\n\t\tVectorCopy( cent->lerpOrigin, model.lightingOrigin );\n\t\tVectorCopy( cent->lerpOrigin, model.origin );\n\t\tAnglesToAxis( cent->currentState.angles, model.axis );\n\t\tif ( cent->currentState.modelindex == TEAM_RED ) {\n\t\t\tmodel.hModel = cgs.media.redFlagBaseModel;\n\t\t}\n\t\telse if ( cent->currentState.modelindex == TEAM_BLUE ) {\n\t\t\tmodel.hModel = cgs.media.blueFlagBaseModel;\n\t\t}\n\t\telse {\n\t\t\tmodel.hModel = cgs.media.neutralFlagBaseModel;\n\t\t}\n\t\ttrap_R_AddRefEntityToScene( &model );\n\t}\n}\n\n/*\n===============\nCG_AddCEntity\n\n===============\n*/\nstatic void CG_AddCEntity( centity_t *cent ) {\n\t// event-only entities will have been dealt with already\n\tif ( cent->currentState.eType >= ET_EVENTS ) {\n\t\treturn;\n\t}\n\n\t// calculate the current origin\n\tCG_CalcEntityLerpPositions( cent );\n\n\t// add automatic effects\n\tCG_EntityEffects( cent );\n\n\tswitch ( cent->currentState.eType ) {\n\tdefault:\n\t\tCG_Error( \"Bad entity type: %i\\n\", cent->currentState.eType );\n\t\tbreak;\n\tcase ET_INVISIBLE:\n\tcase ET_PUSH_TRIGGER:\n\tcase ET_TELEPORT_TRIGGER:\n\t\tbreak;\n\tcase ET_GENERAL:\n\t\tCG_General( cent );\n\t\tbreak;\n\tcase ET_PLAYER:\n\t\tCG_Player( cent );\n\t\tbreak;\n\tcase ET_ITEM:\n\t\tCG_Item( cent );\n\t\tbreak;\n\tcase ET_MISSILE:\n\t\tCG_Missile( cent );\n\t\tbreak;\n\tcase ET_MOVER:\n\t\tCG_Mover( cent );\n\t\tbreak;\n\tcase ET_BEAM:\n\t\tCG_Beam( cent );\n\t\tbreak;\n\tcase ET_PORTAL:\n\t\tCG_Portal( cent );\n\t\tbreak;\n\tcase ET_SPEAKER:\n\t\tCG_Speaker( cent );\n\t\tbreak;\n\tcase ET_GRAPPLE:\n\t\tCG_Grapple( cent );\n\t\tbreak;\n\tcase ET_TEAM:\n\t\tCG_TeamBase( cent );\n\t\tbreak;\n\t}\n}\n\n/*\n===============\nCG_AddPacketEntities\n\n===============\n*/\nvoid CG_AddPacketEntities( void ) {\n\tint\t\t\t\t\tnum;\n\tcentity_t\t\t\t*cent;\n\tplayerState_t\t\t*ps;\n\n\t// set cg.frameInterpolation\n\tif ( cg.nextSnap ) {\n\t\tint\t\tdelta;\n\n\t\tdelta = (cg.nextSnap->serverTime - cg.snap->serverTime);\n\t\tif ( delta == 0 ) {\n\t\t\tcg.frameInterpolation = 0;\n\t\t} else {\n\t\t\tcg.frameInterpolation = (float)( cg.time - cg.snap->serverTime ) / delta;\n\t\t}\n\t} else {\n\t\tcg.frameInterpolation = 0;\t// actually, it should never be used, because \n\t\t\t\t\t\t\t\t\t// no entities should be marked as interpolating\n\t}\n\n\t// the auto-rotating items will all have the same axis\n\tcg.autoAngles[0] = 0;\n\tcg.autoAngles[1] = ( cg.time & 2047 ) * 360 / 2048.0;\n\tcg.autoAngles[2] = 0;\n\n\tcg.autoAnglesFast[0] = 0;\n\tcg.autoAnglesFast[1] = ( cg.time & 1023 ) * 360 / 1024.0f;\n\tcg.autoAnglesFast[2] = 0;\n\n\tAnglesToAxis( cg.autoAngles, cg.autoAxis );\n\tAnglesToAxis( cg.autoAnglesFast, cg.autoAxisFast );\n\n\t// generate and add the entity from the playerstate\n\tps = &cg.predictedPlayerState;\n\tBG_PlayerStateToEntityState( ps, &cg.predictedPlayerEntity.currentState, qfalse );\n\tCG_AddCEntity( &cg.predictedPlayerEntity );\n\n\t// lerp the non-predicted value for lightning gun origins\n\tCG_CalcEntityLerpPositions( &cg_entities[ cg.snap->ps.clientNum ] );\n\n\t// add each entity sent over by the server\n\tfor ( num = 0 ; num < cg.snap->numEntities ; num++ ) {\n\t\tcent = &cg_entities[ cg.snap->entities[ num ].number ];\n\t\tCG_AddCEntity( cent );\n\t}\n}\n\n"
  },
  {
    "path": "src/cgame/cg_event.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n// cg_event.c -- handle entity events at snapshot or playerstate transitions\n\n#include \"cg_local.h\"\n\n\n/*\n===================\nCG_PlaceString\n\nAlso called by scoreboard drawing\n===================\n*/\nconst char\t*CG_PlaceString( int rank ) {\n\tstatic char\tstr[64];\n\tchar\t*s, *t;\n\n\tif ( rank & RANK_TIED_FLAG ) {\n\t\trank &= ~RANK_TIED_FLAG;\n\t\tt = \"Tied for \";\n\t} else {\n\t\tt = \"\";\n\t}\n\n\tif ( rank == 1 ) {\n\t\ts = S_COLOR_BLUE \"1st\" S_COLOR_WHITE;\t\t// draw in blue\n\t} else if ( rank == 2 ) {\n\t\ts = S_COLOR_RED \"2nd\" S_COLOR_WHITE;\t\t// draw in red\n\t} else if ( rank == 3 ) {\n\t\ts = S_COLOR_YELLOW \"3rd\" S_COLOR_WHITE;\t\t// draw in yellow\n\t} else if ( rank == 11 ) {\n\t\ts = \"11th\";\n\t} else if ( rank == 12 ) {\n\t\ts = \"12th\";\n\t} else if ( rank == 13 ) {\n\t\ts = \"13th\";\n\t} else if ( rank % 10 == 1 ) {\n\t\ts = va(\"%ist\", rank);\n\t} else if ( rank % 10 == 2 ) {\n\t\ts = va(\"%ind\", rank);\n\t} else if ( rank % 10 == 3 ) {\n\t\ts = va(\"%ird\", rank);\n\t} else {\n\t\ts = va(\"%ith\", rank);\n\t}\n\n\tCom_sprintf( str, sizeof( str ), \"%s%s\", t, s );\n\treturn str;\n}\n\n/*\n=============\nCG_Obituary\n=============\n*/\nstatic void CG_Obituary( entityState_t *ent ) {\n\tint\t\t\tmod;\n\tint\t\t\ttarget, attacker;\n\tchar\t\t*message;\n\tchar\t\t*message2;\n\tconst char\t*targetInfo;\n\tconst char\t*attackerInfo;\n\tchar\t\ttargetName[32];\n\tchar\t\tattackerName[32];\n\tgender_t\tgender;\n\tclientInfo_t\t*ci;\n\n\ttarget = ent->otherEntityNum;\n\tattacker = ent->otherEntityNum2;\n\tmod = ent->eventParm;\n\n\tif ( target < 0 || target >= MAX_CLIENTS ) {\n\t\tCG_Error( \"CG_Obituary: target out of range\" );\n\t}\n\tci = &cgs.clientinfo[target];\n\n\tif ( attacker < 0 || attacker >= MAX_CLIENTS ) {\n\t\tattacker = ENTITYNUM_WORLD;\n\t\tattackerInfo = NULL;\n\t} else {\n\t\tattackerInfo = CG_ConfigString( CS_PLAYERS + attacker );\n\t}\n\n\ttargetInfo = CG_ConfigString( CS_PLAYERS + target );\n\tif ( !targetInfo ) {\n\t\treturn;\n\t}\n\tQ_strncpyz( targetName, Info_ValueForKey( targetInfo, \"n\" ), sizeof(targetName) - 2);\n\tstrcat( targetName, S_COLOR_WHITE );\n\n\tmessage2 = \"\";\n\n\t// check for single client messages\n\n\tswitch( mod ) {\n\tcase MOD_SUICIDE:\n\t\tmessage = \"suicides\";\n\t\tbreak;\n\tcase MOD_FALLING:\n\t\tmessage = \"cratered\";\n\t\tbreak;\n\tcase MOD_CRUSH:\n\t\tmessage = \"was squished\";\n\t\tbreak;\n\tcase MOD_WATER:\n\t\tmessage = \"sank like a rock\";\n\t\tbreak;\n\tcase MOD_SLIME:\n\t\tmessage = \"melted\";\n\t\tbreak;\n\tcase MOD_LAVA:\n\t\tmessage = \"does a back flip into the lava\";\n\t\tbreak;\n\tcase MOD_TARGET_LASER:\n\t\tmessage = \"saw the light\";\n\t\tbreak;\n\tcase MOD_TRIGGER_HURT:\n\t\tmessage = \"was in the wrong place\";\n\t\tbreak;\n\tdefault:\n\t\tmessage = NULL;\n\t\tbreak;\n\t}\n\n\tif (attacker == target) {\n\t\tgender = ci->gender;\n\t\tswitch (mod) {\n\t\tcase MOD_GRENADE_SPLASH:\n\t\t\tif ( gender == GENDER_FEMALE )\n\t\t\t\tmessage = \"tripped on her own grenade\";\n\t\t\telse if ( gender == GENDER_NEUTER )\n\t\t\t\tmessage = \"tripped on its own grenade\";\n\t\t\telse\n\t\t\t\tmessage = \"tripped on his own grenade\";\n\t\t\tbreak;\n\t\tcase MOD_ROCKET_SPLASH:\n\t\t\tif ( gender == GENDER_FEMALE )\n\t\t\t\tmessage = \"blew herself up\";\n\t\t\telse if ( gender == GENDER_NEUTER )\n\t\t\t\tmessage = \"blew itself up\";\n\t\t\telse\n\t\t\t\tmessage = \"blew himself up\";\n\t\t\tbreak;\n\t\tcase MOD_PLASMA_SPLASH:\n\t\t\tif ( gender == GENDER_FEMALE )\n\t\t\t\tmessage = \"melted herself\";\n\t\t\telse if ( gender == GENDER_NEUTER )\n\t\t\t\tmessage = \"melted itself\";\n\t\t\telse\n\t\t\t\tmessage = \"melted himself\";\n\t\t\tbreak;\n\t\tcase MOD_BFG_SPLASH:\n\t\t\tmessage = \"should have used a smaller gun\";\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tif ( gender == GENDER_FEMALE )\n\t\t\t\tmessage = \"killed herself\";\n\t\t\telse if ( gender == GENDER_NEUTER )\n\t\t\t\tmessage = \"killed itself\";\n\t\t\telse\n\t\t\t\tmessage = \"killed himself\";\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (message) {\n\t\tCG_Printf( \"%s %s.\\n\", targetName, message);\n\t\treturn;\n\t}\n\n\t// check for kill messages from the current clientNum\n\tif ( attacker == cg.snap->ps.clientNum ) {\n\t\tchar\t*s;\n\n\t\tif ( cgs.gametype < GT_TEAM ) {\n\t\t\ts = va(\"You fragged %s\\n%s place with %i\", targetName, \n\t\t\t\tCG_PlaceString( cg.snap->ps.persistant[PERS_RANK] + 1 ),\n\t\t\t\tcg.snap->ps.persistant[PERS_SCORE] );\n\t\t} else {\n\t\t\ts = va(\"You fragged %s\", targetName );\n\t\t}\n\t\tCG_CenterPrint( s, SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH );\n\t\t// print the text message as well\n\t}\n\n\t// check for double client messages\n\tif ( !attackerInfo ) {\n\t\tattacker = ENTITYNUM_WORLD;\n\t\tstrcpy( attackerName, \"noname\" );\n\t} else {\n\t\tQ_strncpyz( attackerName, Info_ValueForKey( attackerInfo, \"n\" ), sizeof(attackerName) - 2);\n\t\tstrcat( attackerName, S_COLOR_WHITE );\n\t\t// check for kill messages about the current clientNum\n\t\tif ( target == cg.snap->ps.clientNum ) {\n\t\t\tQ_strncpyz( cg.killerName, attackerName, sizeof( cg.killerName ) );\n\t\t}\n\t}\n\n\tif ( attacker != ENTITYNUM_WORLD ) {\n\t\tswitch (mod) {\n\t\tcase MOD_GRAPPLE:\n\t\t\tmessage = \"was caught by\";\n\t\t\tbreak;\n\t\tcase MOD_GAUNTLET:\n\t\t\tmessage = \"was pummeled by\";\n\t\t\tbreak;\n\t\tcase MOD_MACHINEGUN:\n\t\t\tmessage = \"was machinegunned by\";\n\t\t\tbreak;\n\t\tcase MOD_SHOTGUN:\n\t\t\tmessage = \"was gunned down by\";\n\t\t\tbreak;\n\t\tcase MOD_GRENADE:\n\t\t\tmessage = \"ate\";\n\t\t\tmessage2 = \"'s grenade\";\n\t\t\tbreak;\n\t\tcase MOD_GRENADE_SPLASH:\n\t\t\tmessage = \"was shredded by\";\n\t\t\tmessage2 = \"'s shrapnel\";\n\t\t\tbreak;\n\t\tcase MOD_ROCKET:\n\t\t\tmessage = \"ate\";\n\t\t\tmessage2 = \"'s rocket\";\n\t\t\tbreak;\n\t\tcase MOD_ROCKET_SPLASH:\n\t\t\tmessage = \"almost dodged\";\n\t\t\tmessage2 = \"'s rocket\";\n\t\t\tbreak;\n\t\tcase MOD_PLASMA:\n\t\t\tmessage = \"was melted by\";\n\t\t\tmessage2 = \"'s plasmagun\";\n\t\t\tbreak;\n\t\tcase MOD_PLASMA_SPLASH:\n\t\t\tmessage = \"was melted by\";\n\t\t\tmessage2 = \"'s plasmagun\";\n\t\t\tbreak;\n\t\tcase MOD_RAILGUN:\n\t\t\tmessage = \"was railed by\";\n\t\t\tbreak;\n\t\tcase MOD_LIGHTNING:\n\t\t\tmessage = \"was electrocuted by\";\n\t\t\tbreak;\n\t\tcase MOD_BFG:\n\t\tcase MOD_BFG_SPLASH:\n\t\t\tmessage = \"was blasted by\";\n\t\t\tmessage2 = \"'s BFG\";\n\t\t\tbreak;\n\t\tcase MOD_TELEFRAG:\n\t\t\tmessage = \"tried to invade\";\n\t\t\tmessage2 = \"'s personal space\";\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tmessage = \"was killed by\";\n\t\t\tbreak;\n\t\t}\n\n\t\tif (message) {\n\t\t\tCG_Printf( \"%s %s %s%s\\n\", \n\t\t\t\ttargetName, message, attackerName, message2);\n\t\t\treturn;\n\t\t}\n\t}\n\n\t// we don't know what it was\n\tCG_Printf( \"%s died.\\n\", targetName );\n}\n\n//==========================================================================\n\n/*\n===============\nCG_UseItem\n===============\n*/\nstatic void CG_UseItem( centity_t *cent ) {\n\tclientInfo_t *ci;\n\tint\t\t\titemNum, clientNum;\n\tgitem_t\t\t*item;\n\tentityState_t *es;\n\n\tes = &cent->currentState;\n\t\n\titemNum = (es->event & ~EV_EVENT_BITS) - EV_USE_ITEM0;\n\tif ( itemNum < 0 || itemNum > HI_NUM_HOLDABLE ) {\n\t\titemNum = 0;\n\t}\n\n\t// print a message if the local player\n\tif ( es->number == cg.snap->ps.clientNum ) {\n\t\tif ( !itemNum ) {\n\t\t\tCG_CenterPrint( \"No item to use\", SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH );\n\t\t} else {\n\t\t\titem = BG_FindItemForHoldable( itemNum );\n\t\t\tCG_CenterPrint( va(\"Use %s\", item->pickup_name), SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH );\n\t\t}\n\t}\n\n\tswitch ( itemNum ) {\n\tdefault:\n\tcase HI_NONE:\n\t\ttrap_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.useNothingSound );\n\t\tbreak;\n\n\tcase HI_TELEPORTER:\n\t\tbreak;\n\n\tcase HI_MEDKIT:\n\t\tclientNum = cent->currentState.clientNum;\n\t\tif ( clientNum >= 0 && clientNum < MAX_CLIENTS ) {\n\t\t\tci = &cgs.clientinfo[ clientNum ];\n\t\t\tci->medkitUsageTime = cg.time;\n\t\t}\n\t\ttrap_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.medkitSound );\n\t\tbreak;\n\t}\n\n}\n\n/*\n================\nCG_ItemPickup\n\nA new item was picked up this frame\n================\n*/\nstatic void CG_ItemPickup( int itemNum ) {\n\tcg.itemPickup = itemNum;\n\tcg.itemPickupTime = cg.time;\n\tcg.itemPickupBlendTime = cg.time;\n\t// see if it should be the grabbed weapon\n\tif ( bg_itemlist[itemNum].giType == IT_WEAPON ) {\n\t\t// select it immediately\n\t\tif ( cg_autoswitch.integer && bg_itemlist[itemNum].giTag != WP_MACHINEGUN ) {\n\t\t\tcg.weaponSelectTime = cg.time;\n\t\t\tcg.weaponSelect = bg_itemlist[itemNum].giTag;\n\t\t}\n\t}\n\n}\n\n\n/*\n================\nCG_PainEvent\n\nAlso called by playerstate transition\n================\n*/\nvoid CG_PainEvent( centity_t *cent, int health ) {\n\tchar\t*snd;\n\n\t// don't do more than two pain sounds a second\n\tif ( cg.time - cent->pe.painTime < 500 ) {\n\t\treturn;\n\t}\n\n\tif ( health < 25 ) {\n\t\tsnd = \"*pain25_1.wav\";\n\t} else if ( health < 50 ) {\n\t\tsnd = \"*pain50_1.wav\";\n\t} else if ( health < 75 ) {\n\t\tsnd = \"*pain75_1.wav\";\n\t} else {\n\t\tsnd = \"*pain100_1.wav\";\n\t}\n\ttrap_S_StartSound( NULL, cent->currentState.number, CHAN_VOICE, \n\t\tCG_CustomSound( cent->currentState.number, snd ) );\n\n\t// save pain time for programitic twitch animation\n\tcent->pe.painTime = cg.time;\n\tcent->pe.painDirection ^= 1;\n}\n\n\n\n/*\n==============\nCG_EntityEvent\n\nAn entity has an event value\nalso called by CG_CheckPlayerstateEvents\n==============\n*/\n#define\tDEBUGNAME(x) if(cg_debugEvents.integer){CG_Printf(x\"\\n\");}\nvoid CG_EntityEvent( centity_t *cent, vec3_t position ) {\n\tentityState_t\t*es;\n\tint\t\t\t\tevent;\n\tvec3_t\t\t\tdir;\n\tconst char\t\t*s;\n\tint\t\t\t\tclientNum;\n\tclientInfo_t\t*ci;\n\n\tes = &cent->currentState;\n\tevent = es->event & ~EV_EVENT_BITS;\n\n\tif ( cg_debugEvents.integer ) {\n\t\tCG_Printf( \"ent:%3i  event:%3i \", es->number, event );\n\t}\n\n\tif ( !event ) {\n\t\tDEBUGNAME(\"ZEROEVENT\");\n\t\treturn;\n\t}\n\n\tclientNum = es->clientNum;\n\tif ( clientNum < 0 || clientNum >= MAX_CLIENTS ) {\n\t\tclientNum = 0;\n\t}\n\tci = &cgs.clientinfo[ clientNum ];\n\n\tswitch ( event ) {\n\t//\n\t// movement generated events\n\t//\n\tcase EV_FOOTSTEP:\n\t\tDEBUGNAME(\"EV_FOOTSTEP\");\n\t\tif (cg_footsteps.integer) {\n\t\t\ttrap_S_StartSound (NULL, es->number, CHAN_BODY, \n\t\t\t\tcgs.media.footsteps[ ci->footsteps ][rand()&3] );\n\t\t}\n\t\tbreak;\n\tcase EV_FOOTSTEP_METAL:\n\t\tDEBUGNAME(\"EV_FOOTSTEP_METAL\");\n\t\tif (cg_footsteps.integer) {\n\t\t\ttrap_S_StartSound (NULL, es->number, CHAN_BODY, \n\t\t\t\tcgs.media.footsteps[ FOOTSTEP_METAL ][rand()&3] );\n\t\t}\n\t\tbreak;\n\tcase EV_FOOTSPLASH:\n\t\tDEBUGNAME(\"EV_FOOTSPLASH\");\n\t\tif (cg_footsteps.integer) {\n\t\t\ttrap_S_StartSound (NULL, es->number, CHAN_BODY, \n\t\t\t\tcgs.media.footsteps[ FOOTSTEP_SPLASH ][rand()&3] );\n\t\t}\n\t\tbreak;\n\tcase EV_FOOTWADE:\n\t\tDEBUGNAME(\"EV_FOOTWADE\");\n\t\tif (cg_footsteps.integer) {\n\t\t\ttrap_S_StartSound (NULL, es->number, CHAN_BODY, \n\t\t\t\tcgs.media.footsteps[ FOOTSTEP_SPLASH ][rand()&3] );\n\t\t}\n\t\tbreak;\n\tcase EV_SWIM:\n\t\tDEBUGNAME(\"EV_SWIM\");\n\t\tif (cg_footsteps.integer) {\n\t\t\ttrap_S_StartSound (NULL, es->number, CHAN_BODY, \n\t\t\t\tcgs.media.footsteps[ FOOTSTEP_SPLASH ][rand()&3] );\n\t\t}\n\t\tbreak;\n\n\n\tcase EV_FALL_SHORT:\n\t\tDEBUGNAME(\"EV_FALL_SHORT\");\n\t\ttrap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.landSound );\n\t\tif ( clientNum == cg.predictedPlayerState.clientNum ) {\n\t\t\t// smooth landing z changes\n\t\t\tcg.landChange = -8;\n\t\t\tcg.landTime = cg.time;\n\t\t}\n\t\tbreak;\n\tcase EV_FALL_MEDIUM:\n\t\tDEBUGNAME(\"EV_FALL_MEDIUM\");\n\t\t// use normal pain sound\n\t\ttrap_S_StartSound( NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, \"*pain100_1.wav\" ) );\n\t\tif ( clientNum == cg.predictedPlayerState.clientNum ) {\n\t\t\t// smooth landing z changes\n\t\t\tcg.landChange = -16;\n\t\t\tcg.landTime = cg.time;\n\t\t}\n\t\tbreak;\n\tcase EV_FALL_FAR:\n\t\tDEBUGNAME(\"EV_FALL_FAR\");\n\t\ttrap_S_StartSound (NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, \"*fall1.wav\" ) );\n\t\tcent->pe.painTime = cg.time;\t// don't play a pain sound right after this\n\t\tif ( clientNum == cg.predictedPlayerState.clientNum ) {\n\t\t\t// smooth landing z changes\n\t\t\tcg.landChange = -24;\n\t\t\tcg.landTime = cg.time;\n\t\t}\n\t\tbreak;\n\n\tcase EV_STEP_4:\n\tcase EV_STEP_8:\n\tcase EV_STEP_12:\n\tcase EV_STEP_16:\t\t// smooth out step up transitions\n\t\tDEBUGNAME(\"EV_STEP\");\n\t{\n\t\tfloat\toldStep;\n\t\tint\t\tdelta;\n\t\tint\t\tstep;\n\n\t\tif ( clientNum != cg.predictedPlayerState.clientNum ) {\n\t\t\tbreak;\n\t\t}\n\t\t// if we are interpolating, we don't need to smooth steps\n\t\tif ( cg.demoPlayback || (cg.snap->ps.pm_flags & PMF_FOLLOW) ||\n\t\t\tcg_nopredict.integer || cg_synchronousClients.integer ) {\n\t\t\tbreak;\n\t\t}\n\t\t// check for stepping up before a previous step is completed\n\t\tdelta = cg.time - cg.stepTime;\n\t\tif (delta < STEP_TIME) {\n\t\t\toldStep = cg.stepChange * (STEP_TIME - delta) / STEP_TIME;\n\t\t} else {\n\t\t\toldStep = 0;\n\t\t}\n\n\t\t// add this amount\n\t\tstep = 4 * (event - EV_STEP_4 + 1 );\n\t\tcg.stepChange = oldStep + step;\n\t\tif ( cg.stepChange > MAX_STEP_CHANGE ) {\n\t\t\tcg.stepChange = MAX_STEP_CHANGE;\n\t\t}\n\t\tcg.stepTime = cg.time;\n\t\tbreak;\n\t}\n\n\tcase EV_JUMP_PAD:\n\t\tDEBUGNAME(\"EV_JUMP_PAD\");\n//\t\tCG_Printf( \"EV_JUMP_PAD w/effect #%i\\n\", es->eventParm );\n\t\t{\n\t\t\tlocalEntity_t\t*smoke;\n\t\t\tvec3_t\t\t\tup = {0, 0, 1};\n\n\n\t\t\tsmoke = CG_SmokePuff( cent->lerpOrigin, up, \n\t\t\t\t\t\t  32, \n\t\t\t\t\t\t  1, 1, 1, 0.33f,\n\t\t\t\t\t\t  1000, \n\t\t\t\t\t\t  cg.time, 0,\n\t\t\t\t\t\t  LEF_PUFF_DONT_SCALE, \n\t\t\t\t\t\t  cgs.media.smokePuffShader );\n\t\t}\n\n\t\t// boing sound at origin, jump sound on player\n\t\ttrap_S_StartSound ( cent->lerpOrigin, -1, CHAN_VOICE, cgs.media.jumpPadSound );\n\t\ttrap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, \"*jump1.wav\" ) );\n\t\tbreak;\n\n\tcase EV_JUMP:\n\t\tDEBUGNAME(\"EV_JUMP\");\n\t\ttrap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, \"*jump1.wav\" ) );\n\t\tbreak;\n\tcase EV_TAUNT:\n\t\tDEBUGNAME(\"EV_TAUNT\");\n\t\ttrap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, \"*taunt.wav\" ) );\n\t\tbreak;\n\tcase EV_WATER_TOUCH:\n\t\tDEBUGNAME(\"EV_WATER_TOUCH\");\n\t\ttrap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrInSound );\n\t\tbreak;\n\tcase EV_WATER_LEAVE:\n\t\tDEBUGNAME(\"EV_WATER_LEAVE\");\n\t\ttrap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrOutSound );\n\t\tbreak;\n\tcase EV_WATER_UNDER:\n\t\tDEBUGNAME(\"EV_WATER_UNDER\");\n\t\ttrap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrUnSound );\n\t\tbreak;\n\tcase EV_WATER_CLEAR:\n\t\tDEBUGNAME(\"EV_WATER_CLEAR\");\n\t\ttrap_S_StartSound (NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, \"*gasp.wav\" ) );\n\t\tbreak;\n\n\tcase EV_ITEM_PICKUP:\n\t\tDEBUGNAME(\"EV_ITEM_PICKUP\");\n\t\t{\n\t\t\tgitem_t\t*item;\n\t\t\tint\t\tindex;\n\n\t\t\tindex = es->eventParm;\t\t// player predicted\n\n\t\t\tif ( index < 1 || index >= bg_numItems ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\titem = &bg_itemlist[ index ];\n\n\t\t\t// powerups and team items will have a separate global sound, this one\n\t\t\t// will be played at prediction time\n\t\t\tif ( item->giType == IT_POWERUP || item->giType == IT_TEAM) {\n\t\t\t\ttrap_S_StartSound (NULL, es->number, CHAN_AUTO,\tcgs.media.n_healthSound );\n\t\t\t} else if (item->giType == IT_PERSISTANT_POWERUP) {\n\t\t\t} else {\n\t\t\t\ttrap_S_StartSound (NULL, es->number, CHAN_AUTO,\ttrap_S_RegisterSound( item->pickup_sound, qfalse ) );\n\t\t\t}\n\n\t\t\t// show icon and name on status bar\n\t\t\tif ( es->number == cg.snap->ps.clientNum ) {\n\t\t\t\tCG_ItemPickup( index );\n\t\t\t}\n\t\t}\n\t\tbreak;\n\n\tcase EV_GLOBAL_ITEM_PICKUP:\n\t\tDEBUGNAME(\"EV_GLOBAL_ITEM_PICKUP\");\n\t\t{\n\t\t\tgitem_t\t*item;\n\t\t\tint\t\tindex;\n\n\t\t\tindex = es->eventParm;\t\t// player predicted\n\n\t\t\tif ( index < 1 || index >= bg_numItems ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\titem = &bg_itemlist[ index ];\n\t\t\t// powerup pickups are global\n\t\t\tif( item->pickup_sound ) {\n\t\t\t\ttrap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_AUTO, trap_S_RegisterSound( item->pickup_sound, qfalse ) );\n\t\t\t}\n\n\t\t\t// show icon and name on status bar\n\t\t\tif ( es->number == cg.snap->ps.clientNum ) {\n\t\t\t\tCG_ItemPickup( index );\n\t\t\t}\n\t\t}\n\t\tbreak;\n\n\t//\n\t// weapon events\n\t//\n\tcase EV_NOAMMO:\n\t\tDEBUGNAME(\"EV_NOAMMO\");\n//\t\ttrap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.noAmmoSound );\n\t\tif ( es->number == cg.snap->ps.clientNum ) {\n\t\t\tCG_OutOfAmmoChange();\n\t\t}\n\t\tbreak;\n\tcase EV_CHANGE_WEAPON:\n\t\tDEBUGNAME(\"EV_CHANGE_WEAPON\");\n\t\ttrap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.selectSound );\n\t\tbreak;\n\tcase EV_FIRE_WEAPON:\n\t\tDEBUGNAME(\"EV_FIRE_WEAPON\");\n\t\tCG_FireWeapon( cent );\n\t\tbreak;\n\n\tcase EV_USE_ITEM0:\n\t\tDEBUGNAME(\"EV_USE_ITEM0\");\n\t\tCG_UseItem( cent );\n\t\tbreak;\n\tcase EV_USE_ITEM1:\n\t\tDEBUGNAME(\"EV_USE_ITEM1\");\n\t\tCG_UseItem( cent );\n\t\tbreak;\n\tcase EV_USE_ITEM2:\n\t\tDEBUGNAME(\"EV_USE_ITEM2\");\n\t\tCG_UseItem( cent );\n\t\tbreak;\n\tcase EV_USE_ITEM3:\n\t\tDEBUGNAME(\"EV_USE_ITEM3\");\n\t\tCG_UseItem( cent );\n\t\tbreak;\n\tcase EV_USE_ITEM4:\n\t\tDEBUGNAME(\"EV_USE_ITEM4\");\n\t\tCG_UseItem( cent );\n\t\tbreak;\n\tcase EV_USE_ITEM5:\n\t\tDEBUGNAME(\"EV_USE_ITEM5\");\n\t\tCG_UseItem( cent );\n\t\tbreak;\n\tcase EV_USE_ITEM6:\n\t\tDEBUGNAME(\"EV_USE_ITEM6\");\n\t\tCG_UseItem( cent );\n\t\tbreak;\n\tcase EV_USE_ITEM7:\n\t\tDEBUGNAME(\"EV_USE_ITEM7\");\n\t\tCG_UseItem( cent );\n\t\tbreak;\n\tcase EV_USE_ITEM8:\n\t\tDEBUGNAME(\"EV_USE_ITEM8\");\n\t\tCG_UseItem( cent );\n\t\tbreak;\n\tcase EV_USE_ITEM9:\n\t\tDEBUGNAME(\"EV_USE_ITEM9\");\n\t\tCG_UseItem( cent );\n\t\tbreak;\n\tcase EV_USE_ITEM10:\n\t\tDEBUGNAME(\"EV_USE_ITEM10\");\n\t\tCG_UseItem( cent );\n\t\tbreak;\n\tcase EV_USE_ITEM11:\n\t\tDEBUGNAME(\"EV_USE_ITEM11\");\n\t\tCG_UseItem( cent );\n\t\tbreak;\n\tcase EV_USE_ITEM12:\n\t\tDEBUGNAME(\"EV_USE_ITEM12\");\n\t\tCG_UseItem( cent );\n\t\tbreak;\n\tcase EV_USE_ITEM13:\n\t\tDEBUGNAME(\"EV_USE_ITEM13\");\n\t\tCG_UseItem( cent );\n\t\tbreak;\n\tcase EV_USE_ITEM14:\n\t\tDEBUGNAME(\"EV_USE_ITEM14\");\n\t\tCG_UseItem( cent );\n\t\tbreak;\n\n\t//=================================================================\n\n\t//\n\t// other events\n\t//\n\tcase EV_PLAYER_TELEPORT_IN:\n\t\tDEBUGNAME(\"EV_PLAYER_TELEPORT_IN\");\n\t\ttrap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.teleInSound );\n\t\tCG_SpawnEffect( position);\n\t\tbreak;\n\n\tcase EV_PLAYER_TELEPORT_OUT:\n\t\tDEBUGNAME(\"EV_PLAYER_TELEPORT_OUT\");\n\t\ttrap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.teleOutSound );\n\t\tCG_SpawnEffect(  position);\n\t\tbreak;\n\n\tcase EV_ITEM_POP:\n\t\tDEBUGNAME(\"EV_ITEM_POP\");\n\t\ttrap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.respawnSound );\n\t\tbreak;\n\tcase EV_ITEM_RESPAWN:\n\t\tDEBUGNAME(\"EV_ITEM_RESPAWN\");\n\t\tcent->miscTime = cg.time;\t// scale up from this\n\t\ttrap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.respawnSound );\n\t\tbreak;\n\n\tcase EV_GRENADE_BOUNCE:\n\t\tDEBUGNAME(\"EV_GRENADE_BOUNCE\");\n\t\tif ( rand() & 1 ) {\n\t\t\ttrap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.hgrenb1aSound );\n\t\t} else {\n\t\t\ttrap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.hgrenb2aSound );\n\t\t}\n\t\tbreak;\n\tcase EV_SCOREPLUM:\n\t\tDEBUGNAME(\"EV_SCOREPLUM\");\n\t\tCG_ScorePlum( cent->currentState.otherEntityNum, cent->lerpOrigin, cent->currentState.time );\n\t\tbreak;\n\n\t//\n\t// missile impacts\n\t//\n\tcase EV_MISSILE_HIT:\n\t\tDEBUGNAME(\"EV_MISSILE_HIT\");\n\t\tByteToDir( es->eventParm, dir );\n\t\tCG_MissileHitPlayer( es->weapon, position, dir, es->otherEntityNum );\n\t\tbreak;\n\n\tcase EV_MISSILE_MISS:\n\t\tDEBUGNAME(\"EV_MISSILE_MISS\");\n\t\tByteToDir( es->eventParm, dir );\n\t\tCG_MissileHitWall( es->weapon, 0, position, dir, IMPACTSOUND_DEFAULT );\n\t\tbreak;\n\n\tcase EV_MISSILE_MISS_METAL:\n\t\tDEBUGNAME(\"EV_MISSILE_MISS_METAL\");\n\t\tByteToDir( es->eventParm, dir );\n\t\tCG_MissileHitWall( es->weapon, 0, position, dir, IMPACTSOUND_METAL );\n\t\tbreak;\n\n\tcase EV_RAILTRAIL:\n\t\tDEBUGNAME(\"EV_RAILTRAIL\");\n\t\tcent->currentState.weapon = WP_RAILGUN;\n\t\t// if the end was on a nomark surface, don't make an explosion\n\t\tCG_RailTrail( ci, es->origin2, es->pos.trBase );\n\t\tif ( es->eventParm != 255 ) {\n\t\t\tByteToDir( es->eventParm, dir );\n\t\t\tCG_MissileHitWall( es->weapon, es->clientNum, position, dir, IMPACTSOUND_DEFAULT );\n\t\t}\n\t\tbreak;\n\n\tcase EV_BULLET_HIT_WALL:\n\t\tDEBUGNAME(\"EV_BULLET_HIT_WALL\");\n\t\tByteToDir( es->eventParm, dir );\n\t\tCG_Bullet( es->pos.trBase, es->otherEntityNum, dir, qfalse, ENTITYNUM_WORLD );\n\t\tbreak;\n\n\tcase EV_BULLET_HIT_FLESH:\n\t\tDEBUGNAME(\"EV_BULLET_HIT_FLESH\");\n\t\tCG_Bullet( es->pos.trBase, es->otherEntityNum, dir, qtrue, es->eventParm );\n\t\tbreak;\n\n\tcase EV_SHOTGUN:\n\t\tDEBUGNAME(\"EV_SHOTGUN\");\n\t\tCG_ShotgunFire( es );\n\t\tbreak;\n\n\tcase EV_GENERAL_SOUND:\n\t\tDEBUGNAME(\"EV_GENERAL_SOUND\");\n\t\tif ( cgs.gameSounds[ es->eventParm ] ) {\n\t\t\ttrap_S_StartSound (NULL, es->number, CHAN_VOICE, cgs.gameSounds[ es->eventParm ] );\n\t\t} else {\n\t\t\ts = CG_ConfigString( CS_SOUNDS + es->eventParm );\n\t\t\ttrap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, s ) );\n\t\t}\n\t\tbreak;\n\n\tcase EV_GLOBAL_SOUND:\t// play from the player's head so it never diminishes\n\t\tDEBUGNAME(\"EV_GLOBAL_SOUND\");\n\t\tif ( cgs.gameSounds[ es->eventParm ] ) {\n\t\t\ttrap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_AUTO, cgs.gameSounds[ es->eventParm ] );\n\t\t} else {\n\t\t\ts = CG_ConfigString( CS_SOUNDS + es->eventParm );\n\t\t\ttrap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_AUTO, CG_CustomSound( es->number, s ) );\n\t\t}\n\t\tbreak;\n\n\tcase EV_GLOBAL_TEAM_SOUND:\t// play from the player's head so it never diminishes\n\t\t{\n\t\t\tDEBUGNAME(\"EV_GLOBAL_TEAM_SOUND\");\n\t\t\tswitch( es->eventParm ) {\n\t\t\t\tcase GTS_RED_CAPTURE: // CTF: red team captured the blue flag, 1FCTF: red team captured the neutral flag\n\t\t\t\t\tif ( cgs.clientinfo[cg.clientNum].team == TEAM_RED )\n\t\t\t\t\t\tCG_AddBufferedSound( cgs.media.captureYourTeamSound );\n\t\t\t\t\telse\n\t\t\t\t\t\tCG_AddBufferedSound( cgs.media.captureOpponentSound );\n\t\t\t\t\tbreak;\n\t\t\t\tcase GTS_BLUE_CAPTURE: // CTF: blue team captured the red flag, 1FCTF: blue team captured the neutral flag\n\t\t\t\t\tif ( cgs.clientinfo[cg.clientNum].team == TEAM_BLUE )\n\t\t\t\t\t\tCG_AddBufferedSound( cgs.media.captureYourTeamSound );\n\t\t\t\t\telse\n\t\t\t\t\t\tCG_AddBufferedSound( cgs.media.captureOpponentSound );\n\t\t\t\t\tbreak;\n\t\t\t\tcase GTS_RED_RETURN: // CTF: blue flag returned, 1FCTF: never used\n\t\t\t\t\tif ( cgs.clientinfo[cg.clientNum].team == TEAM_RED )\n\t\t\t\t\t\tCG_AddBufferedSound( cgs.media.returnYourTeamSound );\n\t\t\t\t\telse\n\t\t\t\t\t\tCG_AddBufferedSound( cgs.media.returnOpponentSound );\n\t\t\t\t\t//\n\t\t\t\t\tCG_AddBufferedSound( cgs.media.blueFlagReturnedSound );\n\t\t\t\t\tbreak;\n\t\t\t\tcase GTS_BLUE_RETURN: // CTF red flag returned, 1FCTF: neutral flag returned\n\t\t\t\t\tif ( cgs.clientinfo[cg.clientNum].team == TEAM_BLUE )\n\t\t\t\t\t\tCG_AddBufferedSound( cgs.media.returnYourTeamSound );\n\t\t\t\t\telse\n\t\t\t\t\t\tCG_AddBufferedSound( cgs.media.returnOpponentSound );\n\t\t\t\t\t//\n\t\t\t\t\tCG_AddBufferedSound( cgs.media.redFlagReturnedSound );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase GTS_RED_TAKEN: // CTF: red team took blue flag, 1FCTF: blue team took the neutral flag\n\t\t\t\t\t// if this player picked up the flag then a sound is played in CG_CheckLocalSounds\n\t\t\t\t\tif (cg.snap->ps.powerups[PW_BLUEFLAG] || cg.snap->ps.powerups[PW_NEUTRALFLAG]) {\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\tif (cgs.clientinfo[cg.clientNum].team == TEAM_BLUE) {\n\t\t\t\t\t\t \tCG_AddBufferedSound( cgs.media.enemyTookYourFlagSound );\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (cgs.clientinfo[cg.clientNum].team == TEAM_RED) {\n \t\t\t\t\t\t\tCG_AddBufferedSound( cgs.media.yourTeamTookEnemyFlagSound );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase GTS_BLUE_TAKEN: // CTF: blue team took the red flag, 1FCTF red team took the neutral flag\n\t\t\t\t\t// if this player picked up the flag then a sound is played in CG_CheckLocalSounds\n\t\t\t\t\tif (cg.snap->ps.powerups[PW_REDFLAG] || cg.snap->ps.powerups[PW_NEUTRALFLAG]) {\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tif (cgs.clientinfo[cg.clientNum].team == TEAM_RED) {\n\t\t\t\t\t\t\tCG_AddBufferedSound( cgs.media.enemyTookYourFlagSound );\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (cgs.clientinfo[cg.clientNum].team == TEAM_BLUE) {\n\t\t\t\t\t\t\tCG_AddBufferedSound( cgs.media.yourTeamTookEnemyFlagSound );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase GTS_REDOBELISK_ATTACKED: // Overload: red obelisk is being attacked\n\t\t\t\t\tif (cgs.clientinfo[cg.clientNum].team == TEAM_RED) {\n\t\t\t\t\t\tCG_AddBufferedSound( cgs.media.yourBaseIsUnderAttackSound );\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase GTS_BLUEOBELISK_ATTACKED: // Overload: blue obelisk is being attacked\n\t\t\t\t\tif (cgs.clientinfo[cg.clientNum].team == TEAM_BLUE) {\n\t\t\t\t\t\tCG_AddBufferedSound( cgs.media.yourBaseIsUnderAttackSound );\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase GTS_REDTEAM_SCORED:\n\t\t\t\t\tCG_AddBufferedSound(cgs.media.redScoredSound);\n\t\t\t\t\tbreak;\n\t\t\t\tcase GTS_BLUETEAM_SCORED:\n\t\t\t\t\tCG_AddBufferedSound(cgs.media.blueScoredSound);\n\t\t\t\t\tbreak;\n\t\t\t\tcase GTS_REDTEAM_TOOK_LEAD:\n\t\t\t\t\tCG_AddBufferedSound(cgs.media.redLeadsSound);\n\t\t\t\t\tbreak;\n\t\t\t\tcase GTS_BLUETEAM_TOOK_LEAD:\n\t\t\t\t\tCG_AddBufferedSound(cgs.media.blueLeadsSound);\n\t\t\t\t\tbreak;\n\t\t\t\tcase GTS_TEAMS_ARE_TIED:\n\t\t\t\t\tCG_AddBufferedSound( cgs.media.teamsTiedSound );\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\tcase EV_PAIN:\n\t\t// local player sounds are triggered in CG_CheckLocalSounds,\n\t\t// so ignore events on the player\n\t\tDEBUGNAME(\"EV_PAIN\");\n\t\tif ( cent->currentState.number != cg.snap->ps.clientNum ) {\n\t\t\tCG_PainEvent( cent, es->eventParm );\n\t\t}\n\t\tbreak;\n\n\tcase EV_DEATH1:\n\tcase EV_DEATH2:\n\tcase EV_DEATH3:\n\t\tDEBUGNAME(\"EV_DEATHx\");\n\t\ttrap_S_StartSound( NULL, es->number, CHAN_VOICE, \n\t\t\t\tCG_CustomSound( es->number, va(\"*death%i.wav\", event - EV_DEATH1 + 1) ) );\n\t\tbreak;\n\n\n\tcase EV_OBITUARY:\n\t\tDEBUGNAME(\"EV_OBITUARY\");\n\t\tCG_Obituary( es );\n\t\tbreak;\n\n\t//\n\t// powerup events\n\t//\n\tcase EV_POWERUP_QUAD:\n\t\tDEBUGNAME(\"EV_POWERUP_QUAD\");\n\t\tif ( es->number == cg.snap->ps.clientNum ) {\n\t\t\tcg.powerupActive = PW_QUAD;\n\t\t\tcg.powerupTime = cg.time;\n\t\t}\n\t\ttrap_S_StartSound (NULL, es->number, CHAN_ITEM, cgs.media.quadSound );\n\t\tbreak;\n\tcase EV_POWERUP_BATTLESUIT:\n\t\tDEBUGNAME(\"EV_POWERUP_BATTLESUIT\");\n\t\tif ( es->number == cg.snap->ps.clientNum ) {\n\t\t\tcg.powerupActive = PW_BATTLESUIT;\n\t\t\tcg.powerupTime = cg.time;\n\t\t}\n\t\ttrap_S_StartSound (NULL, es->number, CHAN_ITEM, cgs.media.protectSound );\n\t\tbreak;\n\tcase EV_POWERUP_REGEN:\n\t\tDEBUGNAME(\"EV_POWERUP_REGEN\");\n\t\tif ( es->number == cg.snap->ps.clientNum ) {\n\t\t\tcg.powerupActive = PW_REGEN;\n\t\t\tcg.powerupTime = cg.time;\n\t\t}\n\t\ttrap_S_StartSound (NULL, es->number, CHAN_ITEM, cgs.media.regenSound );\n\t\tbreak;\n\n\tcase EV_GIB_PLAYER:\n\t\tDEBUGNAME(\"EV_GIB_PLAYER\");\n\t\t// don't play gib sound when using the kamikaze because it interferes\n\t\t// with the kamikaze sound, downside is that the gib sound will also\n\t\t// not be played when someone is gibbed while just carrying the kamikaze\n\t\tif ( !(es->eFlags & EF_KAMIKAZE) ) {\n\t\t\ttrap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.gibSound );\n\t\t}\n\t\tCG_GibPlayer( cent->lerpOrigin );\n\t\tbreak;\n\n\tcase EV_STOPLOOPINGSOUND:\n\t\tDEBUGNAME(\"EV_STOPLOOPINGSOUND\");\n\t\ttrap_S_StopLoopingSound( es->number );\n\t\tes->loopSound = 0;\n\t\tbreak;\n\n\tcase EV_DEBUG_LINE:\n\t\tDEBUGNAME(\"EV_DEBUG_LINE\");\n\t\tCG_Beam( cent );\n\t\tbreak;\n\n\tdefault:\n\t\tDEBUGNAME(\"UNKNOWN\");\n\t\tCG_Error( \"Unknown event: %i\", event );\n\t\tbreak;\n\t}\n\n}\n\n\n/*\n==============\nCG_CheckEvents\n\n==============\n*/\nvoid CG_CheckEvents( centity_t *cent ) {\n\t// check for event-only entities\n\tif ( cent->currentState.eType > ET_EVENTS ) {\n\t\tif ( cent->previousEvent ) {\n\t\t\treturn;\t// already fired\n\t\t}\n\t\t// if this is a player event set the entity number of the client entity number\n\t\tif ( cent->currentState.eFlags & EF_PLAYER_EVENT ) {\n\t\t\tcent->currentState.number = cent->currentState.otherEntityNum;\n\t\t}\n\n\t\tcent->previousEvent = 1;\n\n\t\tcent->currentState.event = cent->currentState.eType - ET_EVENTS;\n\t} else {\n\t\t// check for events riding with another entity\n\t\tif ( cent->currentState.event == cent->previousEvent ) {\n\t\t\treturn;\n\t\t}\n\t\tcent->previousEvent = cent->currentState.event;\n\t\tif ( ( cent->currentState.event & ~EV_EVENT_BITS ) == 0 ) {\n\t\t\treturn;\n\t\t}\n\t}\n\n\t// calculate the position at exactly the frame time\n\tBG_EvaluateTrajectory( &cent->currentState.pos, cg.snap->serverTime, cent->lerpOrigin );\n\tCG_SetEntitySoundPosition( cent );\n\n\tCG_EntityEvent( cent, cent->lerpOrigin );\n}\n\n"
  },
  {
    "path": "src/cgame/cg_info.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n// cg_info.c -- display information while data is being loading\n\n#include \"cg_local.h\"\n\n#define MAX_LOADING_PLAYER_ICONS\t16\n#define MAX_LOADING_ITEM_ICONS\t\t26\n\nstatic int\t\t\tloadingPlayerIconCount;\nstatic int\t\t\tloadingItemIconCount;\nstatic qhandle_t\tloadingPlayerIcons[MAX_LOADING_PLAYER_ICONS];\nstatic qhandle_t\tloadingItemIcons[MAX_LOADING_ITEM_ICONS];\n\n\n/*\n===================\nCG_DrawLoadingIcons\n===================\n*/\nstatic void CG_DrawLoadingIcons( void ) {\n\tint\t\tn;\n\tint\t\tx, y;\n\n\tfor( n = 0; n < loadingPlayerIconCount; n++ ) {\n\t\tx = 16 + n * 78;\n\t\ty = 324-40;\n\t\tCG_DrawPic( x, y, 64, 64, loadingPlayerIcons[n] );\n\t}\n\n\tfor( n = 0; n < loadingItemIconCount; n++ ) {\n\t\ty = 400-40;\n\t\tif( n >= 13 ) {\n\t\t\ty += 40;\n\t\t}\n\t\tx = 16 + n % 13 * 48;\n\t\tCG_DrawPic( x, y, 32, 32, loadingItemIcons[n] );\n\t}\n}\n\n\n/*\n======================\nCG_LoadingString\n\n======================\n*/\nvoid CG_LoadingString( const char *s ) {\n\tQ_strncpyz( cg.infoScreenText, s, sizeof( cg.infoScreenText ) );\n\n\ttrap_UpdateScreen();\n}\n\n/*\n===================\nCG_LoadingItem\n===================\n*/\nvoid CG_LoadingItem( int itemNum ) {\n\tgitem_t\t\t*item;\n\n\titem = &bg_itemlist[itemNum];\n\t\n\tif ( item->icon && loadingItemIconCount < MAX_LOADING_ITEM_ICONS ) {\n\t\tloadingItemIcons[loadingItemIconCount++] = trap_R_RegisterShaderNoMip( item->icon );\n\t}\n\n\tCG_LoadingString( item->pickup_name );\n}\n\n/*\n===================\nCG_LoadingClient\n===================\n*/\nvoid CG_LoadingClient( int clientNum ) {\n\tconst char\t\t*info;\n\tchar\t\t\t*skin;\n\tchar\t\t\tpersonality[MAX_QPATH];\n\tchar\t\t\tmodel[MAX_QPATH];\n\tchar\t\t\ticonName[MAX_QPATH];\n\n\tinfo = CG_ConfigString( CS_PLAYERS + clientNum );\n\n\tif ( loadingPlayerIconCount < MAX_LOADING_PLAYER_ICONS ) {\n\t\tQ_strncpyz( model, Info_ValueForKey( info, \"model\" ), sizeof( model ) );\n\t\tskin = Q_strrchr( model, '/' );\n\t\tif ( skin ) {\n\t\t\t*skin++ = '\\0';\n\t\t} else {\n\t\t\tskin = \"default\";\n\t\t}\n\n\t\tCom_sprintf( iconName, MAX_QPATH, \"models/players/%s/icon_%s.tga\", model, skin );\n\t\t\n\t\tloadingPlayerIcons[loadingPlayerIconCount] = trap_R_RegisterShaderNoMip( iconName );\n\t\tif ( !loadingPlayerIcons[loadingPlayerIconCount] ) {\n\t\t\tCom_sprintf( iconName, MAX_QPATH, \"models/players/characters/%s/icon_%s.tga\", model, skin );\n\t\t\tloadingPlayerIcons[loadingPlayerIconCount] = trap_R_RegisterShaderNoMip( iconName );\n\t\t}\n\t\tif ( !loadingPlayerIcons[loadingPlayerIconCount] ) {\n\t\t\tCom_sprintf( iconName, MAX_QPATH, \"models/players/%s/icon_%s.tga\", DEFAULT_MODEL, \"default\" );\n\t\t\tloadingPlayerIcons[loadingPlayerIconCount] = trap_R_RegisterShaderNoMip( iconName );\n\t\t}\n\t\tif ( loadingPlayerIcons[loadingPlayerIconCount] ) {\n\t\t\tloadingPlayerIconCount++;\n\t\t}\n\t}\n\n\tQ_strncpyz( personality, Info_ValueForKey( info, \"n\" ), sizeof(personality) );\n\tQ_CleanStr( personality );\n\n\tif( cgs.gametype == GT_SINGLE_PLAYER ) {\n\t\ttrap_S_RegisterSound( va( \"sound/player/announce/%s.wav\", personality ), qtrue );\n\t}\n\n\tCG_LoadingString( personality );\n}\n\n\n/*\n====================\nCG_DrawInformation\n\nDraw all the status / pacifier stuff during level loading\n====================\n*/\nvoid CG_DrawInformation( void ) {\n\tconst char\t*s;\n\tconst char\t*info;\n\tconst char\t*sysInfo;\n\tint\t\t\ty;\n\tint\t\t\tvalue;\n\tqhandle_t\tlevelshot;\n\tqhandle_t\tdetail;\n\tchar\t\tbuf[1024];\n\n\tinfo = CG_ConfigString( CS_SERVERINFO );\n\tsysInfo = CG_ConfigString( CS_SYSTEMINFO );\n\n\ts = Info_ValueForKey( info, \"mapname\" );\n\tlevelshot = trap_R_RegisterShaderNoMip( va( \"levelshots/%s.tga\", s ) );\n\tif ( !levelshot ) {\n\t\tlevelshot = trap_R_RegisterShaderNoMip( \"menu/art/unknownmap\" );\n\t}\n\ttrap_R_SetColor( NULL );\n\tCG_DrawPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, levelshot );\n\n\t// blend a detail texture over it\n\tdetail = trap_R_RegisterShader( \"levelShotDetail\" );\n\ttrap_R_DrawStretchPic( 0, 0, cgs.glconfig.vidWidth, cgs.glconfig.vidHeight, 0, 0, 2.5, 2, detail );\n\n\t// draw the icons of things as they are loaded\n\tCG_DrawLoadingIcons();\n\n\t// the first 150 rows are reserved for the client connection\n\t// screen to write into\n\tif ( cg.infoScreenText[0] ) {\n\t\tUI_DrawProportionalString( 320, 128-32, va(\"Loading... %s\", cg.infoScreenText),\n\t\t\tUI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );\n\t} else {\n\t\tUI_DrawProportionalString( 320, 128-32, \"Awaiting snapshot...\",\n\t\t\tUI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );\n\t}\n\n\t// draw info string information\n\n\ty = 180-32;\n\n\t// don't print server lines if playing a local game\n\ttrap_Cvar_VariableStringBuffer( \"sv_running\", buf, sizeof( buf ) );\n\tif ( !atoi( buf ) ) {\n\t\t// server hostname\n\t\tQ_strncpyz(buf, Info_ValueForKey( info, \"sv_hostname\" ), 1024);\n\t\tQ_CleanStr(buf);\n\t\tUI_DrawProportionalString( 320, y, buf,\n\t\t\tUI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );\n\t\ty += PROP_HEIGHT;\n\n\t\t// pure server\n\t\ts = Info_ValueForKey( sysInfo, \"sv_pure\" );\n\t\tif ( s[0] == '1' ) {\n\t\t\tUI_DrawProportionalString( 320, y, \"Pure Server\",\n\t\t\t\tUI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );\n\t\t\ty += PROP_HEIGHT;\n\t\t}\n\n\t\t// server-specific message of the day\n\t\ts = CG_ConfigString( CS_MOTD );\n\t\tif ( s[0] ) {\n\t\t\tUI_DrawProportionalString( 320, y, s,\n\t\t\t\tUI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );\n\t\t\ty += PROP_HEIGHT;\n\t\t}\n\n\t\t// some extra space after hostname and motd\n\t\ty += 10;\n\t}\n\n\t// map-specific message (long map name)\n\ts = CG_ConfigString( CS_MESSAGE );\n\tif ( s[0] ) {\n\t\tUI_DrawProportionalString( 320, y, s,\n\t\t\tUI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );\n\t\ty += PROP_HEIGHT;\n\t}\n\n\t// cheats warning\n\ts = Info_ValueForKey( sysInfo, \"sv_cheats\" );\n\tif ( s[0] == '1' ) {\n\t\tUI_DrawProportionalString( 320, y, \"CHEATS ARE ENABLED\",\n\t\t\tUI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );\n\t\ty += PROP_HEIGHT;\n\t}\n\n\t// game type\n\tswitch ( cgs.gametype ) {\n\tcase GT_FFA:\n\t\ts = \"Free For All\";\n\t\tbreak;\n\tcase GT_SINGLE_PLAYER:\n\t\ts = \"Single Player\";\n\t\tbreak;\n\tcase GT_TOURNAMENT:\n\t\ts = \"Tournament\";\n\t\tbreak;\n\tcase GT_TEAM:\n\t\ts = \"Team Deathmatch\";\n\t\tbreak;\n\tcase GT_CTF:\n\t\ts = \"Capture The Flag\";\n\t\tbreak;\n\tdefault:\n\t\ts = \"Unknown Gametype\";\n\t\tbreak;\n\t}\n\tUI_DrawProportionalString( 320, y, s,\n\t\tUI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );\n\ty += PROP_HEIGHT;\n\t\t\n\tvalue = atoi( Info_ValueForKey( info, \"timelimit\" ) );\n\tif ( value ) {\n\t\tUI_DrawProportionalString( 320, y, va( \"timelimit %i\", value ),\n\t\t\tUI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );\n\t\ty += PROP_HEIGHT;\n\t}\n\n\tif (cgs.gametype < GT_CTF ) {\n\t\tvalue = atoi( Info_ValueForKey( info, \"fraglimit\" ) );\n\t\tif ( value ) {\n\t\t\tUI_DrawProportionalString( 320, y, va( \"fraglimit %i\", value ),\n\t\t\t\tUI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );\n\t\t\ty += PROP_HEIGHT;\n\t\t}\n\t}\n\n\tif (cgs.gametype >= GT_CTF) {\n\t\tvalue = atoi( Info_ValueForKey( info, \"capturelimit\" ) );\n\t\tif ( value ) {\n\t\t\tUI_DrawProportionalString( 320, y, va( \"capturelimit %i\", value ),\n\t\t\t\tUI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );\n\t\t\ty += PROP_HEIGHT;\n\t\t}\n\t}\n}\n\n"
  },
  {
    "path": "src/cgame/cg_local.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n#include \"../game/q_shared.h\"\n#include \"tr_types.h\"\n#include \"../game/bg_public.h\"\n#include \"cg_public.h\"\n\n\n// The entire cgame module is unloaded and reloaded on each level change,\n// so there is NO persistant data between levels on the client side.\n// If you absolutely need something stored, it can either be kept\n// by the server in the server stored userinfos, or stashed in a cvar.\n\n#define\tPOWERUP_BLINKS\t\t5\n\n#define\tPOWERUP_BLINK_TIME\t1000\n#define\tFADE_TIME\t\t\t200\n#define\tPULSE_TIME\t\t\t200\n#define\tDAMAGE_DEFLECT_TIME\t100\n#define\tDAMAGE_RETURN_TIME\t400\n#define DAMAGE_TIME\t\t\t500\n#define\tLAND_DEFLECT_TIME\t150\n#define\tLAND_RETURN_TIME\t300\n#define\tSTEP_TIME\t\t\t200\n#define\tDUCK_TIME\t\t\t100\n#define\tPAIN_TWITCH_TIME\t200\n#define\tWEAPON_SELECT_TIME\t1400\n#define\tITEM_SCALEUP_TIME\t1000\n#define\tZOOM_TIME\t\t\t150\n#define\tITEM_BLOB_TIME\t\t200\n#define\tMUZZLE_FLASH_TIME\t20\n#define\tSINK_TIME\t\t\t1000\t\t// time for fragments to sink into ground before going away\n#define\tATTACKER_HEAD_TIME\t10000\n#define\tREWARD_TIME\t\t\t3000\n\n#define\tPULSE_SCALE\t\t\t1.5\t\t\t// amount to scale up the icons when activating\n\n#define\tMAX_STEP_CHANGE\t\t32\n\n#define\tMAX_VERTS_ON_POLY\t10\n#define\tMAX_MARK_POLYS\t\t256\n\n#define STAT_MINUS\t\t\t10\t// num frame for '-' stats digit\n\n#define\tICON_SIZE\t\t\t48\n#define\tCHAR_WIDTH\t\t\t32\n#define\tCHAR_HEIGHT\t\t\t48\n#define\tTEXT_ICON_SPACE\t\t4\n\n#define\tTEAMCHAT_WIDTH\t\t80\n#define TEAMCHAT_HEIGHT\t\t8\n\n// very large characters\n#define\tGIANT_WIDTH\t\t\t32\n#define\tGIANT_HEIGHT\t\t48\n\n#define\tNUM_CROSSHAIRS\t\t10\n\n#define TEAM_OVERLAY_MAXNAME_WIDTH\t12\n#define TEAM_OVERLAY_MAXLOCATION_WIDTH\t16\n\n#define\tDEFAULT_MODEL\t\t\t\"sarge\"\n#define\tDEFAULT_TEAM_MODEL\t\t\"sarge\"\n#define\tDEFAULT_TEAM_HEAD\t\t\"sarge\"\n\n#define DEFAULT_REDTEAM_NAME\t\t\"Stroggs\"\n#define DEFAULT_BLUETEAM_NAME\t\t\"Pagans\"\n\ntypedef enum {\n\tFOOTSTEP_NORMAL,\n\tFOOTSTEP_BOOT,\n\tFOOTSTEP_FLESH,\n\tFOOTSTEP_MECH,\n\tFOOTSTEP_ENERGY,\n\tFOOTSTEP_METAL,\n\tFOOTSTEP_SPLASH,\n\n\tFOOTSTEP_TOTAL\n} footstep_t;\n\ntypedef enum {\n\tIMPACTSOUND_DEFAULT,\n\tIMPACTSOUND_METAL,\n\tIMPACTSOUND_FLESH\n} impactSound_t;\n\n//=================================================\n\n// player entities need to track more information\n// than any other type of entity.\n\n// note that not every player entity is a client entity,\n// because corpses after respawn are outside the normal\n// client numbering range\n\n// when changing animation, set animationTime to frameTime + lerping time\n// The current lerp will finish out, then it will lerp to the new animation\ntypedef struct {\n\tint\t\t\toldFrame;\n\tint\t\t\toldFrameTime;\t\t// time when ->oldFrame was exactly on\n\n\tint\t\t\tframe;\n\tint\t\t\tframeTime;\t\t\t// time when ->frame will be exactly on\n\n\tfloat\t\tbacklerp;\n\n\tfloat\t\tyawAngle;\n\tqboolean\tyawing;\n\tfloat\t\tpitchAngle;\n\tqboolean\tpitching;\n\n\tint\t\t\tanimationNumber;\t// may include ANIM_TOGGLEBIT\n\tanimation_t\t*animation;\n\tint\t\t\tanimationTime;\t\t// time when the first frame of the animation will be exact\n} lerpFrame_t;\n\n\ntypedef struct {\n\tlerpFrame_t\t\tlegs, torso, flag;\n\tint\t\t\t\tpainTime;\n\tint\t\t\t\tpainDirection;\t// flip from 0 to 1\n\tint\t\t\t\tlightningFiring;\n\n\t// railgun trail spawning\n\tvec3_t\t\t\trailgunImpact;\n\tqboolean\t\trailgunFlash;\n\n\t// machinegun spinning\n\tfloat\t\t\tbarrelAngle;\n\tint\t\t\t\tbarrelTime;\n\tqboolean\t\tbarrelSpinning;\n} playerEntity_t;\n\n//=================================================\n\n\n\n// centity_t have a direct corespondence with gentity_t in the game, but\n// only the entityState_t is directly communicated to the cgame\ntypedef struct centity_s {\n\tentityState_t\tcurrentState;\t// from cg.frame\n\tentityState_t\tnextState;\t\t// from cg.nextFrame, if available\n\tqboolean\t\tinterpolate;\t// true if next is valid to interpolate to\n\tqboolean\t\tcurrentValid;\t// true if cg.frame holds this entity\n\n\tint\t\t\t\tmuzzleFlashTime;\t// move to playerEntity?\n\tint\t\t\t\tpreviousEvent;\n\tint\t\t\t\tteleportFlag;\n\n\tint\t\t\t\ttrailTime;\t\t// so missile trails can handle dropped initial packets\n\tint\t\t\t\tdustTrailTime;\n\tint\t\t\t\tmiscTime;\n\n\tint\t\t\t\tsnapShotTime;\t// last time this entity was found in a snapshot\n\n\tplayerEntity_t\tpe;\n\n\tint\t\t\t\terrorTime;\t\t// decay the error from this time\n\tvec3_t\t\t\terrorOrigin;\n\tvec3_t\t\t\terrorAngles;\n\t\n\tqboolean\t\textrapolated;\t// false if origin / angles is an interpolation\n\tvec3_t\t\t\trawOrigin;\n\tvec3_t\t\t\trawAngles;\n\n\tvec3_t\t\t\tbeamEnd;\n\n\t// exact interpolated position of entity on this frame\n\tvec3_t\t\t\tlerpOrigin;\n\tvec3_t\t\t\tlerpAngles;\n} centity_t;\n\n\n//======================================================================\n\n// local entities are created as a result of events or predicted actions,\n// and live independantly from all server transmitted entities\n\ntypedef struct markPoly_s {\n\tstruct markPoly_s\t*prevMark, *nextMark;\n\tint\t\t\ttime;\n\tqhandle_t\tmarkShader;\n\tqboolean\talphaFade;\t\t// fade alpha instead of rgb\n\tfloat\t\tcolor[4];\n\tpoly_t\t\tpoly;\n\tpolyVert_t\tverts[MAX_VERTS_ON_POLY];\n} markPoly_t;\n\n\ntypedef enum {\n\tLE_MARK,\n\tLE_EXPLOSION,\n\tLE_SPRITE_EXPLOSION,\n\tLE_FRAGMENT,\n\tLE_MOVE_SCALE_FADE,\n\tLE_FALL_SCALE_FADE,\n\tLE_FADE_RGB,\n\tLE_SCALE_FADE,\n\tLE_SCOREPLUM,\n} leType_t;\n\ntypedef enum {\n\tLEF_PUFF_DONT_SCALE  = 0x0001,\t\t\t// do not scale size over time\n\tLEF_TUMBLE\t\t\t = 0x0002,\t\t\t// tumble over time, used for ejecting shells\n\tLEF_SOUND1\t\t\t = 0x0004,\t\t\t// sound 1 for kamikaze\n\tLEF_SOUND2\t\t\t = 0x0008\t\t\t// sound 2 for kamikaze\n} leFlag_t;\n\ntypedef enum {\n\tLEMT_NONE,\n\tLEMT_BURN,\n\tLEMT_BLOOD\n} leMarkType_t;\t\t\t// fragment local entities can leave marks on walls\n\ntypedef enum {\n\tLEBS_NONE,\n\tLEBS_BLOOD,\n\tLEBS_BRASS\n} leBounceSoundType_t;\t// fragment local entities can make sounds on impacts\n\ntypedef struct localEntity_s {\n\tstruct localEntity_s\t*prev, *next;\n\tleType_t\t\tleType;\n\tint\t\t\t\tleFlags;\n\n\tint\t\t\t\tstartTime;\n\tint\t\t\t\tendTime;\n\tint\t\t\t\tfadeInTime;\n\n\tfloat\t\t\tlifeRate;\t\t\t// 1.0 / (endTime - startTime)\n\n\ttrajectory_t\tpos;\n\ttrajectory_t\tangles;\n\n\tfloat\t\t\tbounceFactor;\t\t// 0.0 = no bounce, 1.0 = perfect\n\n\tfloat\t\t\tcolor[4];\n\n\tfloat\t\t\tradius;\n\n\tfloat\t\t\tlight;\n\tvec3_t\t\t\tlightColor;\n\n\tleMarkType_t\t\tleMarkType;\t\t// mark to leave on fragment impact\n\tleBounceSoundType_t\tleBounceSoundType;\n\n\trefEntity_t\t\trefEntity;\t\t\n} localEntity_t;\n\n//======================================================================\n\n\ntypedef struct {\n\tint\t\t\t\tclient;\n\tint\t\t\t\tscore;\n\tint\t\t\t\tping;\n\tint\t\t\t\ttime;\n\tint\t\t\t\tscoreFlags;\n\tint\t\t\t\tpowerUps;\n\tint\t\t\t\taccuracy;\n\tint\t\t\t\timpressiveCount;\n\tint\t\t\t\texcellentCount;\n\tint\t\t\t\tguantletCount;\n\tint\t\t\t\tdefendCount;\n\tint\t\t\t\tassistCount;\n\tint\t\t\t\tcaptures;\n\tqboolean\tperfect;\n\tint\t\t\t\tteam;\n} score_t;\n\n// each client has an associated clientInfo_t\n// that contains media references necessary to present the\n// client model and other color coded effects\n// this is regenerated each time a client's configstring changes,\n// usually as a result of a userinfo (name, model, etc) change\n#define\tMAX_CUSTOM_SOUNDS\t32\n\ntypedef struct {\n\tqboolean\t\tinfoValid;\n\n\tchar\t\t\tname[MAX_QPATH];\n\tteam_t\t\t\tteam;\n\n\tint\t\t\t\tbotSkill;\t\t// 0 = not bot, 1-5 = bot\n\n\tvec3_t\t\t\tcolor1;\n\tvec3_t\t\t\tcolor2;\n\n\tint\t\t\t\tscore;\t\t\t// updated by score servercmds\n\tint\t\t\t\tlocation;\t\t// location index for team mode\n\tint\t\t\t\thealth;\t\t\t// you only get this info about your teammates\n\tint\t\t\t\tarmor;\n\tint\t\t\t\tcurWeapon;\n\n\tint\t\t\t\thandicap;\n\tint\t\t\t\twins, losses;\t// in tourney mode\n\n\tint\t\t\t\tteamTask;\t\t// task in teamplay (offence/defence)\n\tqboolean\t\tteamLeader;\t\t// true when this is a team leader\n\n\tint\t\t\t\tpowerups;\t\t// so can display quad/flag status\n\n\tint\t\t\t\tmedkitUsageTime;\n\tint\t\t\t\tinvulnerabilityStartTime;\n\tint\t\t\t\tinvulnerabilityStopTime;\n\n\tint\t\t\t\tbreathPuffTime;\n\n\t// when clientinfo is changed, the loading of models/skins/sounds\n\t// can be deferred until you are dead, to prevent hitches in\n\t// gameplay\n\tchar\t\t\tmodelName[MAX_QPATH];\n\tchar\t\t\tskinName[MAX_QPATH];\n\tchar\t\t\theadModelName[MAX_QPATH];\n\tchar\t\t\theadSkinName[MAX_QPATH];\n\tchar\t\t\tredTeam[MAX_TEAMNAME];\n\tchar\t\t\tblueTeam[MAX_TEAMNAME];\n\tqboolean\t\tdeferred;\n\n\tqboolean\t\tnewAnims;\t\t// true if using the new mission pack animations\n\tqboolean\t\tfixedlegs;\t\t// true if legs yaw is always the same as torso yaw\n\tqboolean\t\tfixedtorso;\t\t// true if torso never changes yaw\n\n\tvec3_t\t\t\theadOffset;\t\t// move head in icon views\n\tfootstep_t\t\tfootsteps;\n\tgender_t\t\tgender;\t\t\t// from model\n\n\tqhandle_t\t\tlegsModel;\n\tqhandle_t\t\tlegsSkin;\n\n\tqhandle_t\t\ttorsoModel;\n\tqhandle_t\t\ttorsoSkin;\n\n\tqhandle_t\t\theadModel;\n\tqhandle_t\t\theadSkin;\n\n\tqhandle_t\t\tmodelIcon;\n\n\tanimation_t\t\tanimations[MAX_TOTALANIMATIONS];\n\n\tsfxHandle_t\t\tsounds[MAX_CUSTOM_SOUNDS];\n} clientInfo_t;\n\n\n// each WP_* weapon enum has an associated weaponInfo_t\n// that contains media references necessary to present the\n// weapon and its effects\ntypedef struct weaponInfo_s {\n\tqboolean\t\tregistered;\n\tgitem_t\t\t\t*item;\n\n\tqhandle_t\t\thandsModel;\t\t\t// the hands don't actually draw, they just position the weapon\n\tqhandle_t\t\tweaponModel;\n\tqhandle_t\t\tbarrelModel;\n\tqhandle_t\t\tflashModel;\n\n\tvec3_t\t\t\tweaponMidpoint;\t\t// so it will rotate centered instead of by tag\n\n\tfloat\t\t\tflashDlight;\n\tvec3_t\t\t\tflashDlightColor;\n\tsfxHandle_t\t\tflashSound[4];\t\t// fast firing weapons randomly choose\n\n\tqhandle_t\t\tweaponIcon;\n\tqhandle_t\t\tammoIcon;\n\n\tqhandle_t\t\tammoModel;\n\n\tqhandle_t\t\tmissileModel;\n\tsfxHandle_t\t\tmissileSound;\n\tvoid\t\t\t(*missileTrailFunc)( centity_t *, const struct weaponInfo_s *wi );\n\tfloat\t\t\tmissileDlight;\n\tvec3_t\t\t\tmissileDlightColor;\n\tint\t\t\t\tmissileRenderfx;\n\n\tvoid\t\t\t(*ejectBrassFunc)( centity_t * );\n\n\tfloat\t\t\ttrailRadius;\n\tfloat\t\t\twiTrailTime;\n\n\tsfxHandle_t\t\treadySound;\n\tsfxHandle_t\t\tfiringSound;\n\tqboolean\t\tloopFireSound;\n} weaponInfo_t;\n\n\n// each IT_* item has an associated itemInfo_t\n// that constains media references necessary to present the\n// item and its effects\ntypedef struct {\n\tqboolean\t\tregistered;\n\tqhandle_t\t\tmodels[MAX_ITEM_MODELS];\n\tqhandle_t\t\ticon;\n} itemInfo_t;\n\n\ntypedef struct {\n\tint\t\t\t\titemNum;\n} powerupInfo_t;\n\n\n#define MAX_SKULLTRAIL\t\t10\n\ntypedef struct {\n\tvec3_t positions[MAX_SKULLTRAIL];\n\tint numpositions;\n} skulltrail_t;\n\n\n#define MAX_REWARDSTACK\t\t10\n#define MAX_SOUNDBUFFER\t\t20\n\n//======================================================================\n\n// all cg.stepTime, cg.duckTime, cg.landTime, etc are set to cg.time when the action\n// occurs, and they will have visible effects for #define STEP_TIME or whatever msec after\n\n#define MAX_PREDICTED_EVENTS\t16\n \ntypedef struct {\n\tint\t\t\tclientFrame;\t\t// incremented each frame\n\n\tint\t\t\tclientNum;\n\t\n\tqboolean\tdemoPlayback;\n\tqboolean\tlevelShot;\t\t\t// taking a level menu screenshot\n\tint\t\t\tdeferredPlayerLoading;\n\tqboolean\tloading;\t\t\t// don't defer players at initial startup\n\tqboolean\tintermissionStarted;\t// don't play voice rewards, because game will end shortly\n\n\t// there are only one or two snapshot_t that are relevent at a time\n\tint\t\t\tlatestSnapshotNum;\t// the number of snapshots the client system has received\n\tint\t\t\tlatestSnapshotTime;\t// the time from latestSnapshotNum, so we don't need to read the snapshot yet\n\n\tsnapshot_t\t*snap;\t\t\t\t// cg.snap->serverTime <= cg.time\n\tsnapshot_t\t*nextSnap;\t\t\t// cg.nextSnap->serverTime > cg.time, or NULL\n\tsnapshot_t\tactiveSnapshots[2];\n\n\tfloat\t\tframeInterpolation;\t// (float)( cg.time - cg.frame->serverTime ) / (cg.nextFrame->serverTime - cg.frame->serverTime)\n\n\tqboolean\tthisFrameTeleport;\n\tqboolean\tnextFrameTeleport;\n\n\tint\t\t\tframetime;\t\t// cg.time - cg.oldTime\n\n\tint\t\t\ttime;\t\t\t// this is the time value that the client\n\t\t\t\t\t\t\t\t// is rendering at.\n\tint\t\t\toldTime;\t\t// time at last frame, used for missile trails and prediction checking\n\n\tint\t\t\tphysicsTime;\t// either cg.snap->time or cg.nextSnap->time\n\n\tint\t\t\ttimelimitWarnings;\t// 5 min, 1 min, overtime\n\tint\t\t\tfraglimitWarnings;\n\n\tqboolean\tmapRestart;\t\t\t// set on a map restart to set back the weapon\n\n\tqboolean\trenderingThirdPerson;\t\t// during deaths, chasecams, etc\n\n\t// prediction state\n\tqboolean\thyperspace;\t\t\t\t// true if prediction has hit a trigger_teleport\n\tplayerState_t\tpredictedPlayerState;\n\tcentity_t\t\tpredictedPlayerEntity;\n\tqboolean\tvalidPPS;\t\t\t\t// clear until the first call to CG_PredictPlayerState\n\tint\t\t\tpredictedErrorTime;\n\tvec3_t\t\tpredictedError;\n\n\tint\t\t\teventSequence;\n\tint\t\t\tpredictableEvents[MAX_PREDICTED_EVENTS];\n\n\tfloat\t\tstepChange;\t\t\t\t// for stair up smoothing\n\tint\t\t\tstepTime;\n\n\tfloat\t\tduckChange;\t\t\t\t// for duck viewheight smoothing\n\tint\t\t\tduckTime;\n\n\tfloat\t\tlandChange;\t\t\t\t// for landing hard\n\tint\t\t\tlandTime;\n\n\t// input state sent to server\n\tint\t\t\tweaponSelect;\n\n\t// auto rotating items\n\tvec3_t\t\tautoAngles;\n\tvec3_t\t\tautoAxis[3];\n\tvec3_t\t\tautoAnglesFast;\n\tvec3_t\t\tautoAxisFast[3];\n\n\t// view rendering\n\trefdef_t\trefdef;\n\tvec3_t\t\trefdefViewAngles;\t\t// will be converted to refdef.viewaxis\n\n\t// zoom key\n\tqboolean\tzoomed;\n\tint\t\t\tzoomTime;\n\tfloat\t\tzoomSensitivity;\n\n\t// information screen text during loading\n\tchar\t\tinfoScreenText[MAX_STRING_CHARS];\n\n\t// scoreboard\n\tint\t\t\tscoresRequestTime;\n\tint\t\t\tnumScores;\n\tint\t\t\tselectedScore;\n\tint\t\t\tteamScores[2];\n\tscore_t\t\tscores[MAX_CLIENTS];\n\tqboolean\tshowScores;\n\tqboolean\tscoreBoardShowing;\n\tint\t\t\tscoreFadeTime;\n\tchar\t\tkillerName[MAX_NAME_LENGTH];\n\tchar\t\t\tspectatorList[MAX_STRING_CHARS];\t\t// list of names\n\tint\t\t\t\tspectatorLen;\t\t\t\t\t\t\t\t\t\t\t\t// length of list\n\tfloat\t\t\tspectatorWidth;\t\t\t\t\t\t\t\t\t\t\t// width in device units\n\tint\t\t\t\tspectatorTime;\t\t\t\t\t\t\t\t\t\t\t// next time to offset\n\tint\t\t\t\tspectatorPaintX;\t\t\t\t\t\t\t\t\t\t// current paint x\n\tint\t\t\t\tspectatorPaintX2;\t\t\t\t\t\t\t\t\t\t// current paint x\n\tint\t\t\t\tspectatorOffset;\t\t\t\t\t\t\t\t\t\t// current offset from start\n\tint\t\t\t\tspectatorPaintLen; \t\t\t\t\t\t\t\t\t// current offset from start\n\n\t// skull trails\n\tskulltrail_t\tskulltrails[MAX_CLIENTS];\n\n\t// centerprinting\n\tint\t\t\tcenterPrintTime;\n\tint\t\t\tcenterPrintCharWidth;\n\tint\t\t\tcenterPrintY;\n\tchar\t\tcenterPrint[1024];\n\tint\t\t\tcenterPrintLines;\n\n\t// low ammo warning state\n\tint\t\t\tlowAmmoWarning;\t\t// 1 = low, 2 = empty\n\n\t// kill timers for carnage reward\n\tint\t\t\tlastKillTime;\n\n\t// crosshair client ID\n\tint\t\t\tcrosshairClientNum;\n\tint\t\t\tcrosshairClientTime;\n\n\t// powerup active flashing\n\tint\t\t\tpowerupActive;\n\tint\t\t\tpowerupTime;\n\n\t// attacking player\n\tint\t\t\tattackerTime;\n\tint\t\t\tvoiceTime;\n\n\t// reward medals\n\tint\t\t\trewardStack;\n\tint\t\t\trewardTime;\n\tint\t\t\trewardCount[MAX_REWARDSTACK];\n\tqhandle_t\trewardShader[MAX_REWARDSTACK];\n\tqhandle_t\trewardSound[MAX_REWARDSTACK];\n\n\t// sound buffer mainly for announcer sounds\n\tint\t\t\tsoundBufferIn;\n\tint\t\t\tsoundBufferOut;\n\tint\t\t\tsoundTime;\n\tqhandle_t\tsoundBuffer[MAX_SOUNDBUFFER];\n\n\t// for voice chat buffer\n\tint\t\t\tvoiceChatTime;\n\tint\t\t\tvoiceChatBufferIn;\n\tint\t\t\tvoiceChatBufferOut;\n\n\t// warmup countdown\n\tint\t\t\twarmup;\n\tint\t\t\twarmupCount;\n\n\t//==========================\n\n\tint\t\t\titemPickup;\n\tint\t\t\titemPickupTime;\n\tint\t\t\titemPickupBlendTime;\t// the pulse around the crosshair is timed seperately\n\n\tint\t\t\tweaponSelectTime;\n\tint\t\t\tweaponAnimation;\n\tint\t\t\tweaponAnimationTime;\n\n\t// blend blobs\n\tfloat\t\tdamageTime;\n\tfloat\t\tdamageX, damageY, damageValue;\n\n\t// status bar head\n\tfloat\t\theadYaw;\n\tfloat\t\theadEndPitch;\n\tfloat\t\theadEndYaw;\n\tint\t\t\theadEndTime;\n\tfloat\t\theadStartPitch;\n\tfloat\t\theadStartYaw;\n\tint\t\t\theadStartTime;\n\n\t// view movement\n\tfloat\t\tv_dmg_time;\n\tfloat\t\tv_dmg_pitch;\n\tfloat\t\tv_dmg_roll;\n\n\tvec3_t\t\tkick_angles;\t// weapon kicks\n\tvec3_t\t\tkick_origin;\n\n\t// temp working variables for player view\n\tfloat\t\tbobfracsin;\n\tint\t\t\tbobcycle;\n\tfloat\t\txyspeed;\n\tint     nextOrbitTime;\n\n\t//qboolean cameraMode;\t\t// if rendering from a loaded camera\n\n\n\t// development tool\n\trefEntity_t\t\ttestModelEntity;\n\tchar\t\t\ttestModelName[MAX_QPATH];\n\tqboolean\t\ttestGun;\n\n} cg_t;\n\n\n// all of the model, shader, and sound references that are\n// loaded at gamestate time are stored in cgMedia_t\n// Other media that can be tied to clients, weapons, or items are\n// stored in the clientInfo_t, itemInfo_t, weaponInfo_t, and powerupInfo_t\ntypedef struct {\n\tqhandle_t\tcharsetShader;\n\tqhandle_t\tcharsetProp;\n\tqhandle_t\tcharsetPropGlow;\n\tqhandle_t\tcharsetPropB;\n\tqhandle_t\twhiteShader;\n\n\tqhandle_t\tredCubeModel;\n\tqhandle_t\tblueCubeModel;\n\tqhandle_t\tredCubeIcon;\n\tqhandle_t\tblueCubeIcon;\n\tqhandle_t\tredFlagModel;\n\tqhandle_t\tblueFlagModel;\n\tqhandle_t\tneutralFlagModel;\n\tqhandle_t\tredFlagShader[3];\n\tqhandle_t\tblueFlagShader[3];\n\tqhandle_t\tflagShader[4];\n\n\tqhandle_t\tflagPoleModel;\n\tqhandle_t\tflagFlapModel;\n\n\tqhandle_t\tredFlagFlapSkin;\n\tqhandle_t\tblueFlagFlapSkin;\n\tqhandle_t\tneutralFlagFlapSkin;\n\n\tqhandle_t\tredFlagBaseModel;\n\tqhandle_t\tblueFlagBaseModel;\n\tqhandle_t\tneutralFlagBaseModel;\n\n\tqhandle_t\tarmorModel;\n\tqhandle_t\tarmorIcon;\n\n\tqhandle_t\tteamStatusBar;\n\n\tqhandle_t\tdeferShader;\n\n\t// gib explosions\n\tqhandle_t\tgibAbdomen;\n\tqhandle_t\tgibArm;\n\tqhandle_t\tgibChest;\n\tqhandle_t\tgibFist;\n\tqhandle_t\tgibFoot;\n\tqhandle_t\tgibForearm;\n\tqhandle_t\tgibIntestine;\n\tqhandle_t\tgibLeg;\n\tqhandle_t\tgibSkull;\n\tqhandle_t\tgibBrain;\n\n\tqhandle_t\tsmoke2;\n\n\tqhandle_t\tmachinegunBrassModel;\n\tqhandle_t\tshotgunBrassModel;\n\n\tqhandle_t\trailRingsShader;\n\tqhandle_t\trailCoreShader;\n\n\tqhandle_t\tlightningShader;\n\n\tqhandle_t\tfriendShader;\n\n\tqhandle_t\tballoonShader;\n\tqhandle_t\tconnectionShader;\n\n\tqhandle_t\tselectShader;\n\tqhandle_t\tviewBloodShader;\n\tqhandle_t\ttracerShader;\n\tqhandle_t\tcrosshairShader[NUM_CROSSHAIRS];\n\tqhandle_t\tlagometerShader;\n\tqhandle_t\tbackTileShader;\n\tqhandle_t\tnoammoShader;\n\n\tqhandle_t\tsmokePuffShader;\n\tqhandle_t\tsmokePuffRageProShader;\n\tqhandle_t\tshotgunSmokePuffShader;\n\tqhandle_t\tplasmaBallShader;\n\tqhandle_t\twaterBubbleShader;\n\tqhandle_t\tbloodTrailShader;\n\n\tqhandle_t\tnumberShaders[11];\n\n\tqhandle_t\tshadowMarkShader;\n\n\tqhandle_t\tbotSkillShaders[5];\n\n\t// wall mark shaders\n\tqhandle_t\twakeMarkShader;\n\tqhandle_t\tbloodMarkShader;\n\tqhandle_t\tbulletMarkShader;\n\tqhandle_t\tburnMarkShader;\n\tqhandle_t\tholeMarkShader;\n\tqhandle_t\tenergyMarkShader;\n\n\t// powerup shaders\n\tqhandle_t\tquadShader;\n\tqhandle_t\tredQuadShader;\n\tqhandle_t\tquadWeaponShader;\n\tqhandle_t\tinvisShader;\n\tqhandle_t\tregenShader;\n\tqhandle_t\tbattleSuitShader;\n\tqhandle_t\tbattleWeaponShader;\n\tqhandle_t\thastePuffShader;\n\tqhandle_t\tredKamikazeShader;\n\tqhandle_t\tblueKamikazeShader;\n\n\t// weapon effect models\n\tqhandle_t\tbulletFlashModel;\n\tqhandle_t\tringFlashModel;\n\tqhandle_t\tdishFlashModel;\n\tqhandle_t\tlightningExplosionModel;\n\n\t// weapon effect shaders\n\tqhandle_t\trailExplosionShader;\n\tqhandle_t\tplasmaExplosionShader;\n\tqhandle_t\tbulletExplosionShader;\n\tqhandle_t\trocketExplosionShader;\n\tqhandle_t\tgrenadeExplosionShader;\n\tqhandle_t\tbfgExplosionShader;\n\tqhandle_t\tbloodExplosionShader;\n\n\t// special effects models\n\tqhandle_t\tteleportEffectModel;\n\tqhandle_t\tteleportEffectShader;\n\n\tqhandle_t\tinvulnerabilityPowerupModel;\n\n\t// scoreboard headers\n\tqhandle_t\tscoreboardName;\n\tqhandle_t\tscoreboardPing;\n\tqhandle_t\tscoreboardScore;\n\tqhandle_t\tscoreboardTime;\n\n\t// medals shown during gameplay\n\tqhandle_t\tmedalImpressive;\n\tqhandle_t\tmedalExcellent;\n\tqhandle_t\tmedalGauntlet;\n\tqhandle_t\tmedalDefend;\n\tqhandle_t\tmedalAssist;\n\tqhandle_t\tmedalCapture;\n\n\t// sounds\n\tsfxHandle_t\tquadSound;\n\tsfxHandle_t\ttracerSound;\n\tsfxHandle_t\tselectSound;\n\tsfxHandle_t\tuseNothingSound;\n\tsfxHandle_t\twearOffSound;\n\tsfxHandle_t\tfootsteps[FOOTSTEP_TOTAL][4];\n\tsfxHandle_t\tsfx_lghit1;\n\tsfxHandle_t\tsfx_lghit2;\n\tsfxHandle_t\tsfx_lghit3;\n\tsfxHandle_t\tsfx_ric1;\n\tsfxHandle_t\tsfx_ric2;\n\tsfxHandle_t\tsfx_ric3;\n\tsfxHandle_t\tsfx_railg;\n\tsfxHandle_t\tsfx_rockexp;\n\tsfxHandle_t\tsfx_plasmaexp;\n\n\tsfxHandle_t\tgibSound;\n\tsfxHandle_t\tgibBounce1Sound;\n\tsfxHandle_t\tgibBounce2Sound;\n\tsfxHandle_t\tgibBounce3Sound;\n\tsfxHandle_t\tteleInSound;\n\tsfxHandle_t\tteleOutSound;\n\tsfxHandle_t\tnoAmmoSound;\n\tsfxHandle_t\trespawnSound;\n\tsfxHandle_t talkSound;\n\tsfxHandle_t landSound;\n\tsfxHandle_t fallSound;\n\tsfxHandle_t jumpPadSound;\n\n\tsfxHandle_t oneMinuteSound;\n\tsfxHandle_t fiveMinuteSound;\n\tsfxHandle_t suddenDeathSound;\n\n\tsfxHandle_t threeFragSound;\n\tsfxHandle_t twoFragSound;\n\tsfxHandle_t oneFragSound;\n\n\tsfxHandle_t hitSound;\n\tsfxHandle_t hitSoundHighArmor;\n\tsfxHandle_t hitSoundLowArmor;\n\tsfxHandle_t hitTeamSound;\n\tsfxHandle_t impressiveSound;\n\tsfxHandle_t excellentSound;\n\tsfxHandle_t deniedSound;\n\tsfxHandle_t humiliationSound;\n\tsfxHandle_t assistSound;\n\tsfxHandle_t defendSound;\n\tsfxHandle_t firstImpressiveSound;\n\tsfxHandle_t firstExcellentSound;\n\tsfxHandle_t firstHumiliationSound;\n\n\tsfxHandle_t takenLeadSound;\n\tsfxHandle_t tiedLeadSound;\n\tsfxHandle_t lostLeadSound;\n\n\tsfxHandle_t voteNow;\n\tsfxHandle_t votePassed;\n\tsfxHandle_t voteFailed;\n\n\tsfxHandle_t watrInSound;\n\tsfxHandle_t watrOutSound;\n\tsfxHandle_t watrUnSound;\n\n\tsfxHandle_t flightSound;\n\tsfxHandle_t medkitSound;\n\n\tsfxHandle_t weaponHoverSound;\n\n\t// teamplay sounds\n\tsfxHandle_t captureAwardSound;\n\tsfxHandle_t redScoredSound;\n\tsfxHandle_t blueScoredSound;\n\tsfxHandle_t redLeadsSound;\n\tsfxHandle_t blueLeadsSound;\n\tsfxHandle_t teamsTiedSound;\n\n\tsfxHandle_t\tcaptureYourTeamSound;\n\tsfxHandle_t\tcaptureOpponentSound;\n\tsfxHandle_t\treturnYourTeamSound;\n\tsfxHandle_t\treturnOpponentSound;\n\tsfxHandle_t\ttakenYourTeamSound;\n\tsfxHandle_t\ttakenOpponentSound;\n\n\tsfxHandle_t redFlagReturnedSound;\n\tsfxHandle_t blueFlagReturnedSound;\n\tsfxHandle_t neutralFlagReturnedSound;\n\tsfxHandle_t\tenemyTookYourFlagSound;\n\tsfxHandle_t\tenemyTookTheFlagSound;\n\tsfxHandle_t yourTeamTookEnemyFlagSound;\n\tsfxHandle_t yourTeamTookTheFlagSound;\n\tsfxHandle_t\tyouHaveFlagSound;\n\tsfxHandle_t yourBaseIsUnderAttackSound;\n\tsfxHandle_t holyShitSound;\n\n\t// tournament sounds\n\tsfxHandle_t\tcount3Sound;\n\tsfxHandle_t\tcount2Sound;\n\tsfxHandle_t\tcount1Sound;\n\tsfxHandle_t\tcountFightSound;\n\tsfxHandle_t\tcountPrepareSound;\n\n\tqhandle_t cursor;\n\tqhandle_t selectCursor;\n\tqhandle_t sizeCursor;\n\n\tsfxHandle_t\tregenSound;\n\tsfxHandle_t\tprotectSound;\n\tsfxHandle_t\tn_healthSound;\n\tsfxHandle_t\thgrenb1aSound;\n\tsfxHandle_t\thgrenb2aSound;\n\tsfxHandle_t\twstbimplSound;\n\tsfxHandle_t\twstbimpmSound;\n\tsfxHandle_t\twstbimpdSound;\n\tsfxHandle_t\twstbactvSound;\n\n} cgMedia_t;\n\n\n// The client game static (cgs) structure hold everything\n// loaded or calculated from the gamestate.  It will NOT\n// be cleared when a tournement restart is done, allowing\n// all clients to begin playing instantly\ntypedef struct {\n\tgameState_t\t\tgameState;\t\t\t// gamestate from server\n\tglconfig_t\t\tglconfig;\t\t\t// rendering configuration\n\tfloat\t\t\tscreenXScale;\t\t// derived from glconfig\n\tfloat\t\t\tscreenYScale;\n\tfloat\t\t\tscreenXBias;\n\n\tint\t\t\t\tserverCommandSequence;\t// reliable command stream counter\n\tint\t\t\t\tprocessedSnapshotNum;// the number of snapshots cgame has requested\n\n\tqboolean\t\tlocalServer;\t\t// detected on startup by checking sv_running\n\n\t// parsed from serverinfo\n\tgametype_t\t\tgametype;\n\tint\t\t\t\tdmflags;\n\tint\t\t\t\tteamflags;\n\tint\t\t\t\tfraglimit;\n\tint\t\t\t\tcapturelimit;\n\tint\t\t\t\ttimelimit;\n\tint\t\t\t\tmaxclients;\n\tchar\t\t\tmapname[MAX_QPATH];\n\tchar\t\t\tredTeam[MAX_QPATH];\n\tchar\t\t\tblueTeam[MAX_QPATH];\n\n\tint\t\t\t\tvoteTime;\n\tint\t\t\t\tvoteYes;\n\tint\t\t\t\tvoteNo;\n\tqboolean\t\tvoteModified;\t\t\t// beep whenever changed\n\tchar\t\t\tvoteString[MAX_STRING_TOKENS];\n\n\tint\t\t\t\tteamVoteTime[2];\n\tint\t\t\t\tteamVoteYes[2];\n\tint\t\t\t\tteamVoteNo[2];\n\tqboolean\t\tteamVoteModified[2];\t// beep whenever changed\n\tchar\t\t\tteamVoteString[2][MAX_STRING_TOKENS];\n\n\tint\t\t\t\tlevelStartTime;\n\n\tint\t\t\t\tscores1, scores2;\t\t// from configstrings\n\tint\t\t\t\tredflag, blueflag;\t\t// flag status from configstrings\n\tint\t\t\t\tflagStatus;\n\n\tqboolean  newHud;\n\n\t//\n\t// locally derived information from gamestate\n\t//\n\tqhandle_t\t\tgameModels[MAX_MODELS];\n\tsfxHandle_t\t\tgameSounds[MAX_SOUNDS];\n\n\tint\t\t\t\tnumInlineModels;\n\tqhandle_t\t\tinlineDrawModel[MAX_MODELS];\n\tvec3_t\t\t\tinlineModelMidpoints[MAX_MODELS];\n\n\tclientInfo_t\tclientinfo[MAX_CLIENTS];\n\n\t// teamchat width is *3 because of embedded color codes\n\tchar\t\t\tteamChatMsgs[TEAMCHAT_HEIGHT][TEAMCHAT_WIDTH*3+1];\n\tint\t\t\t\tteamChatMsgTimes[TEAMCHAT_HEIGHT];\n\tint\t\t\t\tteamChatPos;\n\tint\t\t\t\tteamLastChatPos;\n\n\tint cursorX;\n\tint cursorY;\n\tqboolean eventHandling;\n\tqboolean mouseCaptured;\n\tqboolean sizingHud;\n\tvoid *capturedItem;\n\tqhandle_t activeCursor;\n\n\t// orders\n\tint currentOrder;\n\tqboolean orderPending;\n\tint orderTime;\n\tint currentVoiceClient;\n\tint acceptOrderTime;\n\tint acceptTask;\n\tint acceptLeader;\n\tchar acceptVoice[MAX_NAME_LENGTH];\n\n\t// media\n\tcgMedia_t\t\tmedia;\n\n} cgs_t;\n\n//==============================================================================\n\nextern\tcgs_t\t\t\tcgs;\nextern\tcg_t\t\t\tcg;\nextern\tcentity_t\t\tcg_entities[MAX_GENTITIES];\nextern\tweaponInfo_t\tcg_weapons[MAX_WEAPONS];\nextern\titemInfo_t\t\tcg_items[MAX_ITEMS];\nextern\tmarkPoly_t\t\tcg_markPolys[MAX_MARK_POLYS];\n\nextern\tvmCvar_t\t\tcg_centertime;\nextern\tvmCvar_t\t\tcg_runpitch;\nextern\tvmCvar_t\t\tcg_runroll;\nextern\tvmCvar_t\t\tcg_bobup;\nextern\tvmCvar_t\t\tcg_bobpitch;\nextern\tvmCvar_t\t\tcg_bobroll;\nextern\tvmCvar_t\t\tcg_swingSpeed;\nextern\tvmCvar_t\t\tcg_shadows;\nextern\tvmCvar_t\t\tcg_gibs;\nextern\tvmCvar_t\t\tcg_drawTimer;\nextern\tvmCvar_t\t\tcg_drawFPS;\nextern\tvmCvar_t\t\tcg_drawSnapshot;\nextern\tvmCvar_t\t\tcg_draw3dIcons;\nextern\tvmCvar_t\t\tcg_drawIcons;\nextern\tvmCvar_t\t\tcg_drawAmmoWarning;\nextern\tvmCvar_t\t\tcg_drawCrosshair;\nextern\tvmCvar_t\t\tcg_drawCrosshairNames;\nextern\tvmCvar_t\t\tcg_drawRewards;\nextern\tvmCvar_t\t\tcg_drawTeamOverlay;\nextern\tvmCvar_t\t\tcg_teamOverlayUserinfo;\nextern\tvmCvar_t\t\tcg_crosshairX;\nextern\tvmCvar_t\t\tcg_crosshairY;\nextern\tvmCvar_t\t\tcg_crosshairSize;\nextern\tvmCvar_t\t\tcg_crosshairHealth;\nextern\tvmCvar_t\t\tcg_drawStatus;\nextern\tvmCvar_t\t\tcg_draw2D;\nextern\tvmCvar_t\t\tcg_animSpeed;\nextern\tvmCvar_t\t\tcg_debugAnim;\nextern\tvmCvar_t\t\tcg_debugPosition;\nextern\tvmCvar_t\t\tcg_debugEvents;\nextern\tvmCvar_t\t\tcg_railTrailTime;\nextern\tvmCvar_t\t\tcg_errorDecay;\nextern\tvmCvar_t\t\tcg_nopredict;\nextern\tvmCvar_t\t\tcg_noPlayerAnims;\nextern\tvmCvar_t\t\tcg_showmiss;\nextern\tvmCvar_t\t\tcg_footsteps;\nextern\tvmCvar_t\t\tcg_addMarks;\nextern\tvmCvar_t\t\tcg_brassTime;\nextern\tvmCvar_t\t\tcg_gun_frame;\nextern\tvmCvar_t\t\tcg_gun_x;\nextern\tvmCvar_t\t\tcg_gun_y;\nextern\tvmCvar_t\t\tcg_gun_z;\nextern\tvmCvar_t\t\tcg_drawGun;\nextern\tvmCvar_t\t\tcg_viewsize;\nextern\tvmCvar_t\t\tcg_tracerChance;\nextern\tvmCvar_t\t\tcg_tracerWidth;\nextern\tvmCvar_t\t\tcg_tracerLength;\nextern\tvmCvar_t\t\tcg_autoswitch;\nextern\tvmCvar_t\t\tcg_ignore;\nextern\tvmCvar_t\t\tcg_simpleItems;\nextern\tvmCvar_t\t\tcg_fov;\nextern\tvmCvar_t\t\tcg_zoomFov;\nextern\tvmCvar_t\t\tcg_thirdPersonRange;\nextern\tvmCvar_t\t\tcg_thirdPersonAngle;\nextern\tvmCvar_t\t\tcg_thirdPerson;\nextern\tvmCvar_t\t\tcg_stereoSeparation;\nextern\tvmCvar_t\t\tcg_lagometer;\nextern\tvmCvar_t\t\tcg_drawAttacker;\nextern\tvmCvar_t\t\tcg_synchronousClients;\nextern\tvmCvar_t\t\tcg_teamChatTime;\nextern\tvmCvar_t\t\tcg_teamChatHeight;\nextern\tvmCvar_t\t\tcg_stats;\nextern\tvmCvar_t \t\tcg_forceModel;\nextern\tvmCvar_t \t\tcg_buildScript;\nextern\tvmCvar_t\t\tcg_paused;\nextern\tvmCvar_t\t\tcg_blood;\nextern\tvmCvar_t\t\tcg_predictItems;\nextern\tvmCvar_t\t\tcg_deferPlayers;\nextern\tvmCvar_t\t\tcg_drawFriend;\nextern\tvmCvar_t\t\tcg_teamChatsOnly;\nextern\tvmCvar_t\t\tcg_noVoiceChats;\nextern\tvmCvar_t\t\tcg_noVoiceText;\nextern  vmCvar_t\t\tcg_scorePlum;\nextern\tvmCvar_t\t\tcg_smoothClients;\nextern\tvmCvar_t\t\tpmove_fixed;\nextern\tvmCvar_t\t\tpmove_msec;\n//extern\tvmCvar_t\t\tcg_pmove_fixed;\nextern\tvmCvar_t\t\tcg_cameraOrbit;\nextern\tvmCvar_t\t\tcg_cameraOrbitDelay;\nextern\tvmCvar_t\t\tcg_timescaleFadeEnd;\nextern\tvmCvar_t\t\tcg_timescaleFadeSpeed;\nextern\tvmCvar_t\t\tcg_timescale;\nextern\tvmCvar_t\t\tcg_cameraMode;\nextern  vmCvar_t\t\tcg_smallFont;\nextern  vmCvar_t\t\tcg_bigFont;\nextern\tvmCvar_t\t\tcg_noTaunt;\nextern\tvmCvar_t\t\tcg_noProjectileTrail;\nextern\tvmCvar_t\t\tcg_oldRail;\nextern\tvmCvar_t\t\tcg_oldRocket;\nextern\tvmCvar_t\t\tcg_oldPlasma;\nextern\tvmCvar_t\t\tcg_trueLightning;\n\n//\n// cg_main.c\n//\nconst char *CG_ConfigString( int index );\nconst char *CG_Argv( int arg );\n\nvoid QDECL CG_Printf( const char *msg, ... );\nvoid QDECL CG_Error( const char *msg, ... );\n\nvoid CG_StartMusic( void );\n\nvoid CG_UpdateCvars( void );\n\nint CG_CrosshairPlayer( void );\nint CG_LastAttacker( void );\nvoid CG_LoadMenus(const char *menuFile);\nvoid CG_KeyEvent(int key, qboolean down);\nvoid CG_MouseEvent(int x, int y);\nvoid CG_EventHandling(int type);\nvoid CG_RankRunFrame( void );\nvoid CG_SetScoreSelection(void *menu);\nscore_t *CG_GetSelectedScore();\nvoid CG_BuildSpectatorString();\n\n\n//\n// cg_view.c\n//\nvoid CG_TestModel_f (void);\nvoid CG_TestGun_f (void);\nvoid CG_TestModelNextFrame_f (void);\nvoid CG_TestModelPrevFrame_f (void);\nvoid CG_TestModelNextSkin_f (void);\nvoid CG_TestModelPrevSkin_f (void);\nvoid CG_ZoomDown_f( void );\nvoid CG_ZoomUp_f( void );\nvoid CG_AddBufferedSound( sfxHandle_t sfx);\n\nvoid CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demoPlayback );\n\n\n//\n// cg_drawtools.c\n//\nvoid CG_AdjustFrom640( float *x, float *y, float *w, float *h );\nvoid CG_FillRect( float x, float y, float width, float height, const float *color );\nvoid CG_DrawPic( float x, float y, float width, float height, qhandle_t hShader );\nvoid CG_DrawString( float x, float y, const char *string, \n\t\t\t\t   float charWidth, float charHeight, const float *modulate );\n\n\nvoid CG_DrawStringExt( int x, int y, const char *string, const float *setColor, \n\t\tqboolean forceColor, qboolean shadow, int charWidth, int charHeight, int maxChars );\nvoid CG_DrawBigString( int x, int y, const char *s, float alpha );\nvoid CG_DrawBigStringColor( int x, int y, const char *s, vec4_t color );\nvoid CG_DrawSmallString( int x, int y, const char *s, float alpha );\nvoid CG_DrawSmallStringColor( int x, int y, const char *s, vec4_t color );\n\nint CG_DrawStrlen( const char *str );\n\nfloat\t*CG_FadeColor( int startMsec, int totalMsec );\nfloat *CG_TeamColor( int team );\nvoid CG_TileClear( void );\nvoid CG_ColorForHealth( vec4_t hcolor );\nvoid CG_GetColorForHealth( int health, int armor, vec4_t hcolor );\n\nvoid UI_DrawProportionalString( int x, int y, const char* str, int style, vec4_t color );\nvoid CG_DrawRect( float x, float y, float width, float height, float size, const float *color );\nvoid CG_DrawSides(float x, float y, float w, float h, float size);\nvoid CG_DrawTopBottom(float x, float y, float w, float h, float size);\n\n\n//\n// cg_draw.c, cg_newDraw.c\n//\nextern\tint sortedTeamPlayers[TEAM_MAXOVERLAY];\nextern\tint\tnumSortedTeamPlayers;\nextern\tint drawTeamOverlayModificationCount;\nextern  char systemChat[256];\nextern  char teamChat1[256];\nextern  char teamChat2[256];\n\nvoid CG_AddLagometerFrameInfo( void );\nvoid CG_AddLagometerSnapshotInfo( snapshot_t *snap );\nvoid CG_CenterPrint( const char *str, int y, int charWidth );\nvoid CG_DrawHead( float x, float y, float w, float h, int clientNum, vec3_t headAngles );\nvoid CG_DrawActive( stereoFrame_t stereoView );\nvoid CG_DrawFlagModel( float x, float y, float w, float h, int team, qboolean force2D );\nvoid CG_DrawTeamBackground( int x, int y, int w, int h, float alpha, int team );\nvoid CG_OwnerDraw(float x, float y, float w, float h, float text_x, float text_y, int ownerDraw, int ownerDrawFlags, int align, float special, float scale, vec4_t color, qhandle_t shader, int textStyle);\nvoid CG_Text_Paint(float x, float y, float scale, vec4_t color, const char *text, float adjust, int limit, int style);\nint CG_Text_Width(const char *text, float scale, int limit);\nint CG_Text_Height(const char *text, float scale, int limit);\nvoid CG_SelectPrevPlayer();\nvoid CG_SelectNextPlayer();\nfloat CG_GetValue(int ownerDraw);\nqboolean CG_OwnerDrawVisible(int flags);\nvoid CG_RunMenuScript(char **args);\nvoid CG_ShowResponseHead();\nvoid CG_SetPrintString(int type, const char *p);\nvoid CG_InitTeamChat();\nvoid CG_GetTeamColor(vec4_t *color);\nconst char *CG_GetGameStatusText();\nconst char *CG_GetKillerText();\nvoid CG_Draw3DModel( float x, float y, float w, float h, qhandle_t model, qhandle_t skin, vec3_t origin, vec3_t angles );\nvoid CG_Text_PaintChar(float x, float y, float width, float height, float scale, float s, float t, float s2, float t2, qhandle_t hShader);\nvoid CG_CheckOrderPending();\nconst char *CG_GameTypeString();\nqboolean CG_YourTeamHasFlag();\nqboolean CG_OtherTeamHasFlag();\nqhandle_t CG_StatusHandle(int task);\n\n\n\n//\n// cg_player.c\n//\nvoid CG_Player( centity_t *cent );\nvoid CG_ResetPlayerEntity( centity_t *cent );\nvoid CG_AddRefEntityWithPowerups( refEntity_t *ent, entityState_t *state, int team );\nvoid CG_NewClientInfo( int clientNum );\nsfxHandle_t\tCG_CustomSound( int clientNum, const char *soundName );\n\n//\n// cg_predict.c\n//\nvoid CG_BuildSolidList( void );\nint\tCG_PointContents( const vec3_t point, int passEntityNum );\nvoid CG_Trace( trace_t *result, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, \n\t\t\t\t\t int skipNumber, int mask );\nvoid CG_PredictPlayerState( void );\nvoid CG_LoadDeferredPlayers( void );\n\n\n//\n// cg_events.c\n//\nvoid CG_CheckEvents( centity_t *cent );\nconst char\t*CG_PlaceString( int rank );\nvoid CG_EntityEvent( centity_t *cent, vec3_t position );\nvoid CG_PainEvent( centity_t *cent, int health );\n\n\n//\n// cg_ents.c\n//\nvoid CG_SetEntitySoundPosition( centity_t *cent );\nvoid CG_AddPacketEntities( void );\nvoid CG_Beam( centity_t *cent );\nvoid CG_AdjustPositionForMover( const vec3_t in, int moverNum, int fromTime, int toTime, vec3_t out );\n\nvoid CG_PositionEntityOnTag( refEntity_t *entity, const refEntity_t *parent, \n\t\t\t\t\t\t\tqhandle_t parentModel, char *tagName );\nvoid CG_PositionRotatedEntityOnTag( refEntity_t *entity, const refEntity_t *parent, \n\t\t\t\t\t\t\tqhandle_t parentModel, char *tagName );\n\n\n\n//\n// cg_weapons.c\n//\nvoid CG_NextWeapon_f( void );\nvoid CG_PrevWeapon_f( void );\nvoid CG_Weapon_f( void );\n\nvoid CG_RegisterWeapon( int weaponNum );\nvoid CG_RegisterItemVisuals( int itemNum );\n\nvoid CG_FireWeapon( centity_t *cent );\nvoid CG_MissileHitWall( int weapon, int clientNum, vec3_t origin, vec3_t dir, impactSound_t soundType );\nvoid CG_MissileHitPlayer( int weapon, vec3_t origin, vec3_t dir, int entityNum );\nvoid CG_ShotgunFire( entityState_t *es );\nvoid CG_Bullet( vec3_t origin, int sourceEntityNum, vec3_t normal, qboolean flesh, int fleshEntityNum );\n\nvoid CG_RailTrail( clientInfo_t *ci, vec3_t start, vec3_t end );\nvoid CG_GrappleTrail( centity_t *ent, const weaponInfo_t *wi );\nvoid CG_AddViewWeapon (playerState_t *ps);\nvoid CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent, int team );\nvoid CG_DrawWeaponSelect( void );\n\nvoid CG_OutOfAmmoChange( void );\t// should this be in pmove?\n\n//\n// cg_marks.c\n//\nvoid\tCG_InitMarkPolys( void );\nvoid\tCG_AddMarks( void );\nvoid\tCG_ImpactMark( qhandle_t markShader, \n\t\t\t\t    const vec3_t origin, const vec3_t dir, \n\t\t\t\t\tfloat orientation, \n\t\t\t\t    float r, float g, float b, float a, \n\t\t\t\t\tqboolean alphaFade, \n\t\t\t\t\tfloat radius, qboolean temporary );\n\n//\n// cg_localents.c\n//\nvoid\tCG_InitLocalEntities( void );\nlocalEntity_t\t*CG_AllocLocalEntity( void );\nvoid\tCG_AddLocalEntities( void );\n\n//\n// cg_effects.c\n//\nlocalEntity_t *CG_SmokePuff( const vec3_t p, \n\t\t\t\t   const vec3_t vel, \n\t\t\t\t   float radius,\n\t\t\t\t   float r, float g, float b, float a,\n\t\t\t\t   float duration,\n\t\t\t\t   int startTime,\n\t\t\t\t   int fadeInTime,\n\t\t\t\t   int leFlags,\n\t\t\t\t   qhandle_t hShader );\nvoid CG_BubbleTrail( vec3_t start, vec3_t end, float spacing );\nvoid CG_SpawnEffect( vec3_t org );\nvoid CG_ScorePlum( int client, vec3_t org, int score );\n\nvoid CG_GibPlayer( vec3_t playerOrigin );\nvoid CG_BigExplode( vec3_t playerOrigin );\n\nvoid CG_Bleed( vec3_t origin, int entityNum );\n\nlocalEntity_t *CG_MakeExplosion( vec3_t origin, vec3_t dir,\n\t\t\t\t\t\t\t\tqhandle_t hModel, qhandle_t shader, int msec,\n\t\t\t\t\t\t\t\tqboolean isSprite );\n\n//\n// cg_snapshot.c\n//\nvoid CG_ProcessSnapshots( void );\n\n//\n// cg_info.c\n//\nvoid CG_LoadingString( const char *s );\nvoid CG_LoadingItem( int itemNum );\nvoid CG_LoadingClient( int clientNum );\nvoid CG_DrawInformation( void );\n\n//\n// cg_scoreboard.c\n//\nqboolean CG_DrawOldScoreboard( void );\nvoid CG_DrawOldTourneyScoreboard( void );\n\n//\n// cg_consolecmds.c\n//\nqboolean CG_ConsoleCommand( void );\nvoid CG_InitConsoleCommands( void );\n\n//\n// cg_servercmds.c\n//\nvoid CG_ExecuteNewServerCommands( int latestSequence );\nvoid CG_ParseServerinfo( void );\nvoid CG_SetConfigValues( void );\nvoid CG_LoadVoiceChats( void );\nvoid CG_ShaderStateChanged(void);\nvoid CG_VoiceChatLocal( int mode, qboolean voiceOnly, int clientNum, int color, const char *cmd );\nvoid CG_PlayBufferedVoiceChats( void );\n\n//\n// cg_playerstate.c\n//\nvoid CG_Respawn( void );\nvoid CG_TransitionPlayerState( playerState_t *ps, playerState_t *ops );\nvoid CG_CheckChangedPredictableEvents( playerState_t *ps );\n\n\n//===============================================\n\n//\n// system traps\n// These functions are how the cgame communicates with the main game system\n//\n\n// print message on the local console\nvoid\t\ttrap_Print( const char *fmt );\n\n// abort the game\nvoid\t\ttrap_Error( const char *fmt );\n\n// milliseconds should only be used for performance tuning, never\n// for anything game related.  Get time from the CG_DrawActiveFrame parameter\nint\t\t\ttrap_Milliseconds( void );\n\n// console variable interaction\nvoid\t\ttrap_Cvar_Register( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags );\nvoid\t\ttrap_Cvar_Update( vmCvar_t *vmCvar );\nvoid\t\ttrap_Cvar_Set( const char *var_name, const char *value );\nvoid\t\ttrap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize );\n\n// ServerCommand and ConsoleCommand parameter access\nint\t\t\ttrap_Argc( void );\nvoid\t\ttrap_Argv( int n, char *buffer, int bufferLength );\nvoid\t\ttrap_Args( char *buffer, int bufferLength );\n\n// filesystem access\n// returns length of file\nint\t\t\ttrap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode );\nvoid\t\ttrap_FS_Read( void *buffer, int len, fileHandle_t f );\nvoid\t\ttrap_FS_Write( const void *buffer, int len, fileHandle_t f );\nvoid\t\ttrap_FS_FCloseFile( fileHandle_t f );\nint\t\t\ttrap_FS_Seek( fileHandle_t f, long offset, int origin ); // fsOrigin_t\n\n// add commands to the local console as if they were typed in\n// for map changing, etc.  The command is not executed immediately,\n// but will be executed in order the next time console commands\n// are processed\nvoid\t\ttrap_SendConsoleCommand( const char *text );\n\n// register a command name so the console can perform command completion.\n// FIXME: replace this with a normal console command \"defineCommand\"?\nvoid\t\ttrap_AddCommand( const char *cmdName );\n\n// send a string to the server over the network\nvoid\t\ttrap_SendClientCommand( const char *s );\n\n// force a screen update, only used during gamestate load\nvoid\t\ttrap_UpdateScreen( void );\n\n// model collision\nvoid\t\ttrap_CM_LoadMap( const char *mapname );\nint\t\t\ttrap_CM_NumInlineModels( void );\nclipHandle_t trap_CM_InlineModel( int index );\t\t// 0 = world, 1+ = bmodels\nclipHandle_t trap_CM_TempBoxModel( const vec3_t mins, const vec3_t maxs );\nint\t\t\ttrap_CM_PointContents( const vec3_t p, clipHandle_t model );\nint\t\t\ttrap_CM_TransformedPointContents( const vec3_t p, clipHandle_t model, const vec3_t origin, const vec3_t angles );\nvoid\t\ttrap_CM_BoxTrace( trace_t *results, const vec3_t start, const vec3_t end,\n\t\t\t\t\t  const vec3_t mins, const vec3_t maxs,\n\t\t\t\t\t  clipHandle_t model, int brushmask );\nvoid\t\ttrap_CM_TransformedBoxTrace( trace_t *results, const vec3_t start, const vec3_t end,\n\t\t\t\t\t  const vec3_t mins, const vec3_t maxs,\n\t\t\t\t\t  clipHandle_t model, int brushmask,\n\t\t\t\t\t  const vec3_t origin, const vec3_t angles );\n\n// Returns the projection of a polygon onto the solid brushes in the world\nint\t\t\ttrap_CM_MarkFragments( int numPoints, const vec3_t *points, \n\t\t\tconst vec3_t projection,\n\t\t\tint maxPoints, vec3_t pointBuffer,\n\t\t\tint maxFragments, markFragment_t *fragmentBuffer );\n\n// normal sounds will have their volume dynamically changed as their entity\n// moves and the listener moves\nvoid\t\ttrap_S_StartSound( vec3_t origin, int entityNum, int entchannel, sfxHandle_t sfx );\nvoid\t\ttrap_S_StopLoopingSound(int entnum);\n\n// a local sound is always played full volume\nvoid\t\ttrap_S_StartLocalSound( sfxHandle_t sfx, int channelNum );\nvoid\t\ttrap_S_ClearLoopingSounds( qboolean killall );\nvoid\t\ttrap_S_AddLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx );\nvoid\t\ttrap_S_AddRealLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx );\nvoid\t\ttrap_S_UpdateEntityPosition( int entityNum, const vec3_t origin );\n\n// respatialize recalculates the volumes of sound as they should be heard by the\n// given entityNum and position\nvoid\t\ttrap_S_Respatialize( int entityNum, const vec3_t origin, vec3_t axis[3], int inwater );\nsfxHandle_t\ttrap_S_RegisterSound( const char *sample, qboolean compressed );\t\t// returns buzz if not found\nvoid\t\ttrap_S_StartBackgroundTrack( const char *intro, const char *loop );\t// empty name stops music\nvoid\ttrap_S_StopBackgroundTrack( void );\n\n\nvoid\t\ttrap_R_LoadWorldMap( const char *mapname );\n\n// all media should be registered during level startup to prevent\n// hitches during gameplay\nqhandle_t\ttrap_R_RegisterModel( const char *name );\t\t\t// returns rgb axis if not found\nqhandle_t\ttrap_R_RegisterSkin( const char *name );\t\t\t// returns all white if not found\nqhandle_t\ttrap_R_RegisterShader( const char *name );\t\t\t// returns all white if not found\nqhandle_t\ttrap_R_RegisterShaderNoMip( const char *name );\t\t\t// returns all white if not found\n\n// a scene is built up by calls to R_ClearScene and the various R_Add functions.\n// Nothing is drawn until R_RenderScene is called.\nvoid\t\ttrap_R_ClearScene( void );\nvoid\t\ttrap_R_AddRefEntityToScene( const refEntity_t *re );\n\n// polys are intended for simple wall marks, not really for doing\n// significant construction\nvoid\t\ttrap_R_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts );\nvoid\t\ttrap_R_AddPolysToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts, int numPolys );\nvoid\t\ttrap_R_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b );\nint\t\t\ttrap_R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir );\nvoid\t\ttrap_R_RenderScene( const refdef_t *fd );\nvoid\t\ttrap_R_SetColor( const float *rgba );\t// NULL = 1,1,1,1\nvoid\t\ttrap_R_DrawStretchPic( float x, float y, float w, float h, \n\t\t\tfloat s1, float t1, float s2, float t2, qhandle_t hShader );\nvoid\t\ttrap_R_ModelBounds( clipHandle_t model, vec3_t mins, vec3_t maxs );\nint\t\t\ttrap_R_LerpTag( orientation_t *tag, clipHandle_t mod, int startFrame, int endFrame, \n\t\t\t\t\t   float frac, const char *tagName );\nvoid\t\ttrap_R_RemapShader( const char *oldShader, const char *newShader, const char *timeOffset );\n\n// The glconfig_t will not change during the life of a cgame.\n// If it needs to change, the entire cgame will be restarted, because\n// all the qhandle_t are then invalid.\nvoid\t\ttrap_GetGlconfig( glconfig_t *glconfig );\n\n// the gamestate should be grabbed at startup, and whenever a\n// configstring changes\nvoid\t\ttrap_GetGameState( gameState_t *gamestate );\n\n// cgame will poll each frame to see if a newer snapshot has arrived\n// that it is interested in.  The time is returned seperately so that\n// snapshot latency can be calculated.\nvoid\t\ttrap_GetCurrentSnapshotNumber( int *snapshotNumber, int *serverTime );\n\n// a snapshot get can fail if the snapshot (or the entties it holds) is so\n// old that it has fallen out of the client system queue\nqboolean\ttrap_GetSnapshot( int snapshotNumber, snapshot_t *snapshot );\n\n// retrieve a text command from the server stream\n// the current snapshot will hold the number of the most recent command\n// qfalse can be returned if the client system handled the command\n// argc() / argv() can be used to examine the parameters of the command\nqboolean\ttrap_GetServerCommand( int serverCommandNumber );\n\n// returns the most recent command number that can be passed to GetUserCmd\n// this will always be at least one higher than the number in the current\n// snapshot, and it may be quite a few higher if it is a fast computer on\n// a lagged connection\nint\t\t\ttrap_GetCurrentCmdNumber( void );\t\n\nqboolean\ttrap_GetUserCmd( int cmdNumber, usercmd_t *ucmd );\n\n// used for the weapon select and zoom\nvoid\t\ttrap_SetUserCmdValue( int stateValue, float sensitivityScale );\n\n// aids for VM testing\nvoid\t\ttestPrintInt( char *string, int i );\nvoid\t\ttestPrintFloat( char *string, float f );\n\nint\t\t\ttrap_MemoryRemaining( void );\nvoid\t\ttrap_R_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font);\nqboolean\ttrap_Key_IsDown( int keynum );\nint\t\t\ttrap_Key_GetCatcher( void );\nvoid\t\ttrap_Key_SetCatcher( int catcher );\nint\t\t\ttrap_Key_GetKey( const char *binding );\n\n\ntypedef enum {\n  SYSTEM_PRINT,\n  CHAT_PRINT,\n  TEAMCHAT_PRINT\n} q3print_t; // bk001201 - warning: useless keyword or type name in empty declaration\n\n\nint trap_CIN_PlayCinematic( const char *arg0, int xpos, int ypos, int width, int height, int bits);\ne_status trap_CIN_StopCinematic(int handle);\ne_status trap_CIN_RunCinematic (int handle);\nvoid trap_CIN_DrawCinematic (int handle);\nvoid trap_CIN_SetExtents (int handle, int x, int y, int w, int h);\n\nvoid trap_SnapVector( float *v );\n\nqboolean\ttrap_GetEntityToken( char *buffer, int bufferSize );\n\nvoid\tCG_ClearParticles (void);\nvoid\tCG_AddParticles (void);\nvoid\tCG_ParticleSnow (qhandle_t pshader, vec3_t origin, vec3_t origin2, int turb, float range, int snum);\nvoid\tCG_ParticleSmoke (qhandle_t pshader, centity_t *cent);\nvoid\tCG_AddParticleShrapnel (localEntity_t *le);\nvoid\tCG_ParticleSnowFlurry (qhandle_t pshader, centity_t *cent);\nvoid\tCG_ParticleBulletDebris (vec3_t\torg, vec3_t vel, int duration);\nvoid\tCG_ParticleSparks (vec3_t org, vec3_t vel, int duration, float x, float y, float speed);\nvoid\tCG_ParticleDust (centity_t *cent, vec3_t origin, vec3_t dir);\nvoid\tCG_ParticleMisc (qhandle_t pshader, vec3_t origin, int size, int duration, float alpha);\nvoid\tCG_ParticleExplosion (char *animStr, vec3_t origin, vec3_t vel, int duration, int sizeStart, int sizeEnd);\nextern qboolean\t\tinitparticles;\nint CG_NewParticleArea ( int num );\n\n\n"
  },
  {
    "path": "src/cgame/cg_localents.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n\n// cg_localents.c -- every frame, generate renderer commands for locally\n// processed entities, like smoke puffs, gibs, shells, etc.\n\n#include \"cg_local.h\"\n\n#define\tMAX_LOCAL_ENTITIES\t512\nlocalEntity_t\tcg_localEntities[MAX_LOCAL_ENTITIES];\nlocalEntity_t\tcg_activeLocalEntities;\t\t// double linked list\nlocalEntity_t\t*cg_freeLocalEntities;\t\t// single linked list\n\n/*\n===================\nCG_InitLocalEntities\n\nThis is called at startup and for tournement restarts\n===================\n*/\nvoid\tCG_InitLocalEntities( void ) {\n\tint\t\ti;\n\n\tmemset( cg_localEntities, 0, sizeof( cg_localEntities ) );\n\tcg_activeLocalEntities.next = &cg_activeLocalEntities;\n\tcg_activeLocalEntities.prev = &cg_activeLocalEntities;\n\tcg_freeLocalEntities = cg_localEntities;\n\tfor ( i = 0 ; i < MAX_LOCAL_ENTITIES - 1 ; i++ ) {\n\t\tcg_localEntities[i].next = &cg_localEntities[i+1];\n\t}\n}\n\n\n/*\n==================\nCG_FreeLocalEntity\n==================\n*/\nvoid CG_FreeLocalEntity( localEntity_t *le ) {\n\tif ( !le->prev ) {\n\t\tCG_Error( \"CG_FreeLocalEntity: not active\" );\n\t}\n\n\t// remove from the doubly linked active list\n\tle->prev->next = le->next;\n\tle->next->prev = le->prev;\n\n\t// the free list is only singly linked\n\tle->next = cg_freeLocalEntities;\n\tcg_freeLocalEntities = le;\n}\n\n/*\n===================\nCG_AllocLocalEntity\n\nWill allways succeed, even if it requires freeing an old active entity\n===================\n*/\nlocalEntity_t\t*CG_AllocLocalEntity( void ) {\n\tlocalEntity_t\t*le;\n\n\tif ( !cg_freeLocalEntities ) {\n\t\t// no free entities, so free the one at the end of the chain\n\t\t// remove the oldest active entity\n\t\tCG_FreeLocalEntity( cg_activeLocalEntities.prev );\n\t}\n\n\tle = cg_freeLocalEntities;\n\tcg_freeLocalEntities = cg_freeLocalEntities->next;\n\n\tmemset( le, 0, sizeof( *le ) );\n\n\t// link into the active list\n\tle->next = cg_activeLocalEntities.next;\n\tle->prev = &cg_activeLocalEntities;\n\tcg_activeLocalEntities.next->prev = le;\n\tcg_activeLocalEntities.next = le;\n\treturn le;\n}\n\n\n/*\n====================================================================================\n\nFRAGMENT PROCESSING\n\nA fragment localentity interacts with the environment in some way (hitting walls),\nor generates more localentities along a trail.\n\n====================================================================================\n*/\n\n/*\n================\nCG_BloodTrail\n\nLeave expanding blood puffs behind gibs\n================\n*/\nvoid CG_BloodTrail( localEntity_t *le ) {\n\tint\t\tt;\n\tint\t\tt2;\n\tint\t\tstep;\n\tvec3_t\tnewOrigin;\n\tlocalEntity_t\t*blood;\n\n\tstep = 150;\n\tt = step * ( (cg.time - cg.frametime + step ) / step );\n\tt2 = step * ( cg.time / step );\n\n\tfor ( ; t <= t2; t += step ) {\n\t\tBG_EvaluateTrajectory( &le->pos, t, newOrigin );\n\n\t\tblood = CG_SmokePuff( newOrigin, vec3_origin, \n\t\t\t\t\t  20,\t\t// radius\n\t\t\t\t\t  1, 1, 1, 1,\t// color\n\t\t\t\t\t  2000,\t\t// trailTime\n\t\t\t\t\t  t,\t\t// startTime\n\t\t\t\t\t  0,\t\t// fadeInTime\n\t\t\t\t\t  0,\t\t// flags\n\t\t\t\t\t  cgs.media.bloodTrailShader );\n\t\t// use the optimized version\n\t\tblood->leType = LE_FALL_SCALE_FADE;\n\t\t// drop a total of 40 units over its lifetime\n\t\tblood->pos.trDelta[2] = 40;\n\t}\n}\n\n\n/*\n================\nCG_FragmentBounceMark\n================\n*/\nvoid CG_FragmentBounceMark( localEntity_t *le, trace_t *trace ) {\n\tint\t\t\tradius;\n\n\tif ( le->leMarkType == LEMT_BLOOD ) {\n\n\t\tradius = 16 + (rand()&31);\n\t\tCG_ImpactMark( cgs.media.bloodMarkShader, trace->endpos, trace->plane.normal, random()*360,\n\t\t\t1,1,1,1, qtrue, radius, qfalse );\n\t} else if ( le->leMarkType == LEMT_BURN ) {\n\n\t\tradius = 8 + (rand()&15);\n\t\tCG_ImpactMark( cgs.media.burnMarkShader, trace->endpos, trace->plane.normal, random()*360,\n\t\t\t1,1,1,1, qtrue, radius, qfalse );\n\t}\n\n\n\t// don't allow a fragment to make multiple marks, or they\n\t// pile up while settling\n\tle->leMarkType = LEMT_NONE;\n}\n\n/*\n================\nCG_FragmentBounceSound\n================\n*/\nvoid CG_FragmentBounceSound( localEntity_t *le, trace_t *trace ) {\n\tif ( le->leBounceSoundType == LEBS_BLOOD ) {\n\t\t// half the gibs will make splat sounds\n\t\tif ( rand() & 1 ) {\n\t\t\tint r = rand()&3;\n\t\t\tsfxHandle_t\ts;\n\n\t\t\tif ( r == 0 ) {\n\t\t\t\ts = cgs.media.gibBounce1Sound;\n\t\t\t} else if ( r == 1 ) {\n\t\t\t\ts = cgs.media.gibBounce2Sound;\n\t\t\t} else {\n\t\t\t\ts = cgs.media.gibBounce3Sound;\n\t\t\t}\n\t\t\ttrap_S_StartSound( trace->endpos, ENTITYNUM_WORLD, CHAN_AUTO, s );\n\t\t}\n\t} else if ( le->leBounceSoundType == LEBS_BRASS ) {\n\n\t}\n\n\t// don't allow a fragment to make multiple bounce sounds,\n\t// or it gets too noisy as they settle\n\tle->leBounceSoundType = LEBS_NONE;\n}\n\n\n/*\n================\nCG_ReflectVelocity\n================\n*/\nvoid CG_ReflectVelocity( localEntity_t *le, trace_t *trace ) {\n\tvec3_t\tvelocity;\n\tfloat\tdot;\n\tint\t\thitTime;\n\n\t// reflect the velocity on the trace plane\n\thitTime = cg.time - cg.frametime + cg.frametime * trace->fraction;\n\tBG_EvaluateTrajectoryDelta( &le->pos, hitTime, velocity );\n\tdot = DotProduct( velocity, trace->plane.normal );\n\tVectorMA( velocity, -2*dot, trace->plane.normal, le->pos.trDelta );\n\n\tVectorScale( le->pos.trDelta, le->bounceFactor, le->pos.trDelta );\n\n\tVectorCopy( trace->endpos, le->pos.trBase );\n\tle->pos.trTime = cg.time;\n\n\n\t// check for stop, making sure that even on low FPS systems it doesn't bobble\n\tif ( trace->allsolid || \n\t\t( trace->plane.normal[2] > 0 && \n\t\t( le->pos.trDelta[2] < 40 || le->pos.trDelta[2] < -cg.frametime * le->pos.trDelta[2] ) ) ) {\n\t\tle->pos.trType = TR_STATIONARY;\n\t} else {\n\n\t}\n}\n\n/*\n================\nCG_AddFragment\n================\n*/\nvoid CG_AddFragment( localEntity_t *le ) {\n\tvec3_t\tnewOrigin;\n\ttrace_t\ttrace;\n\n\tif ( le->pos.trType == TR_STATIONARY ) {\n\t\t// sink into the ground if near the removal time\n\t\tint\t\tt;\n\t\tfloat\toldZ;\n\t\t\n\t\tt = le->endTime - cg.time;\n\t\tif ( t < SINK_TIME ) {\n\t\t\t// we must use an explicit lighting origin, otherwise the\n\t\t\t// lighting would be lost as soon as the origin went\n\t\t\t// into the ground\n\t\t\tVectorCopy( le->refEntity.origin, le->refEntity.lightingOrigin );\n\t\t\tle->refEntity.renderfx |= RF_LIGHTING_ORIGIN;\n\t\t\toldZ = le->refEntity.origin[2];\n\t\t\tle->refEntity.origin[2] -= 16 * ( 1.0 - (float)t / SINK_TIME );\n\t\t\ttrap_R_AddRefEntityToScene( &le->refEntity );\n\t\t\tle->refEntity.origin[2] = oldZ;\n\t\t} else {\n\t\t\ttrap_R_AddRefEntityToScene( &le->refEntity );\n\t\t}\n\n\t\treturn;\n\t}\n\n\t// calculate new position\n\tBG_EvaluateTrajectory( &le->pos, cg.time, newOrigin );\n\n\t// trace a line from previous position to new position\n\tCG_Trace( &trace, le->refEntity.origin, NULL, NULL, newOrigin, -1, CONTENTS_SOLID );\n\tif ( trace.fraction == 1.0 ) {\n\t\t// still in free fall\n\t\tVectorCopy( newOrigin, le->refEntity.origin );\n\n\t\tif ( le->leFlags & LEF_TUMBLE ) {\n\t\t\tvec3_t angles;\n\n\t\t\tBG_EvaluateTrajectory( &le->angles, cg.time, angles );\n\t\t\tAnglesToAxis( angles, le->refEntity.axis );\n\t\t}\n\n\t\ttrap_R_AddRefEntityToScene( &le->refEntity );\n\n\t\t// add a blood trail\n\t\tif ( le->leBounceSoundType == LEBS_BLOOD ) {\n\t\t\tCG_BloodTrail( le );\n\t\t}\n\n\t\treturn;\n\t}\n\n\t// if it is in a nodrop zone, remove it\n\t// this keeps gibs from waiting at the bottom of pits of death\n\t// and floating levels\n\tif ( trap_CM_PointContents( trace.endpos, 0 ) & CONTENTS_NODROP ) {\n\t\tCG_FreeLocalEntity( le );\n\t\treturn;\n\t}\n\n\t// leave a mark\n\tCG_FragmentBounceMark( le, &trace );\n\n\t// do a bouncy sound\n\tCG_FragmentBounceSound( le, &trace );\n\n\t// reflect the velocity on the trace plane\n\tCG_ReflectVelocity( le, &trace );\n\n\ttrap_R_AddRefEntityToScene( &le->refEntity );\n}\n\n/*\n=====================================================================\n\nTRIVIAL LOCAL ENTITIES\n\nThese only do simple scaling or modulation before passing to the renderer\n=====================================================================\n*/\n\n/*\n====================\nCG_AddFadeRGB\n====================\n*/\nvoid CG_AddFadeRGB( localEntity_t *le ) {\n\trefEntity_t *re;\n\tfloat c;\n\n\tre = &le->refEntity;\n\n\tc = ( le->endTime - cg.time ) * le->lifeRate;\n\tc *= 0xff;\n\n\tre->shaderRGBA[0] = le->color[0] * c;\n\tre->shaderRGBA[1] = le->color[1] * c;\n\tre->shaderRGBA[2] = le->color[2] * c;\n\tre->shaderRGBA[3] = le->color[3] * c;\n\n\ttrap_R_AddRefEntityToScene( re );\n}\n\n/*\n==================\nCG_AddMoveScaleFade\n==================\n*/\nstatic void CG_AddMoveScaleFade( localEntity_t *le ) {\n\trefEntity_t\t*re;\n\tfloat\t\tc;\n\tvec3_t\t\tdelta;\n\tfloat\t\tlen;\n\n\tre = &le->refEntity;\n\n\tif ( le->fadeInTime > le->startTime && cg.time < le->fadeInTime ) {\n\t\t// fade / grow time\n\t\tc = 1.0 - (float) ( le->fadeInTime - cg.time ) / ( le->fadeInTime - le->startTime );\n\t}\n\telse {\n\t\t// fade / grow time\n\t\tc = ( le->endTime - cg.time ) * le->lifeRate;\n\t}\n\n\tre->shaderRGBA[3] = 0xff * c * le->color[3];\n\n\tif ( !( le->leFlags & LEF_PUFF_DONT_SCALE ) ) {\n\t\tre->radius = le->radius * ( 1.0 - c ) + 8;\n\t}\n\n\tBG_EvaluateTrajectory( &le->pos, cg.time, re->origin );\n\n\t// if the view would be \"inside\" the sprite, kill the sprite\n\t// so it doesn't add too much overdraw\n\tVectorSubtract( re->origin, cg.refdef.vieworg, delta );\n\tlen = VectorLength( delta );\n\tif ( len < le->radius ) {\n\t\tCG_FreeLocalEntity( le );\n\t\treturn;\n\t}\n\n\ttrap_R_AddRefEntityToScene( re );\n}\n\n\n/*\n===================\nCG_AddScaleFade\n\nFor rocket smokes that hang in place, fade out, and are\nremoved if the view passes through them.\nThere are often many of these, so it needs to be simple.\n===================\n*/\nstatic void CG_AddScaleFade( localEntity_t *le ) {\n\trefEntity_t\t*re;\n\tfloat\t\tc;\n\tvec3_t\t\tdelta;\n\tfloat\t\tlen;\n\n\tre = &le->refEntity;\n\n\t// fade / grow time\n\tc = ( le->endTime - cg.time ) * le->lifeRate;\n\n\tre->shaderRGBA[3] = 0xff * c * le->color[3];\n\tre->radius = le->radius * ( 1.0 - c ) + 8;\n\n\t// if the view would be \"inside\" the sprite, kill the sprite\n\t// so it doesn't add too much overdraw\n\tVectorSubtract( re->origin, cg.refdef.vieworg, delta );\n\tlen = VectorLength( delta );\n\tif ( len < le->radius ) {\n\t\tCG_FreeLocalEntity( le );\n\t\treturn;\n\t}\n\n\ttrap_R_AddRefEntityToScene( re );\n}\n\n\n/*\n=================\nCG_AddFallScaleFade\n\nThis is just an optimized CG_AddMoveScaleFade\nFor blood mists that drift down, fade out, and are\nremoved if the view passes through them.\nThere are often 100+ of these, so it needs to be simple.\n=================\n*/\nstatic void CG_AddFallScaleFade( localEntity_t *le ) {\n\trefEntity_t\t*re;\n\tfloat\t\tc;\n\tvec3_t\t\tdelta;\n\tfloat\t\tlen;\n\n\tre = &le->refEntity;\n\n\t// fade time\n\tc = ( le->endTime - cg.time ) * le->lifeRate;\n\n\tre->shaderRGBA[3] = 0xff * c * le->color[3];\n\n\tre->origin[2] = le->pos.trBase[2] - ( 1.0 - c ) * le->pos.trDelta[2];\n\n\tre->radius = le->radius * ( 1.0 - c ) + 16;\n\n\t// if the view would be \"inside\" the sprite, kill the sprite\n\t// so it doesn't add too much overdraw\n\tVectorSubtract( re->origin, cg.refdef.vieworg, delta );\n\tlen = VectorLength( delta );\n\tif ( len < le->radius ) {\n\t\tCG_FreeLocalEntity( le );\n\t\treturn;\n\t}\n\n\ttrap_R_AddRefEntityToScene( re );\n}\n\n\n\n/*\n================\nCG_AddExplosion\n================\n*/\nstatic void CG_AddExplosion( localEntity_t *ex ) {\n\trefEntity_t\t*ent;\n\n\tent = &ex->refEntity;\n\n\t// add the entity\n\ttrap_R_AddRefEntityToScene(ent);\n\n\t// add the dlight\n\tif ( ex->light ) {\n\t\tfloat\t\tlight;\n\n\t\tlight = (float)( cg.time - ex->startTime ) / ( ex->endTime - ex->startTime );\n\t\tif ( light < 0.5 ) {\n\t\t\tlight = 1.0;\n\t\t} else {\n\t\t\tlight = 1.0 - ( light - 0.5 ) * 2;\n\t\t}\n\t\tlight = ex->light * light;\n\t\ttrap_R_AddLightToScene(ent->origin, light, ex->lightColor[0], ex->lightColor[1], ex->lightColor[2] );\n\t}\n}\n\n/*\n================\nCG_AddSpriteExplosion\n================\n*/\nstatic void CG_AddSpriteExplosion( localEntity_t *le ) {\n\trefEntity_t\tre;\n\tfloat c;\n\n\tre = le->refEntity;\n\n\tc = ( le->endTime - cg.time ) / ( float ) ( le->endTime - le->startTime );\n\tif ( c > 1 ) {\n\t\tc = 1.0;\t// can happen during connection problems\n\t}\n\n\tre.shaderRGBA[0] = 0xff;\n\tre.shaderRGBA[1] = 0xff;\n\tre.shaderRGBA[2] = 0xff;\n\tre.shaderRGBA[3] = 0xff * c * 0.33;\n\n\tre.reType = RT_SPRITE;\n\tre.radius = 42 * ( 1.0 - c ) + 30;\n\n\ttrap_R_AddRefEntityToScene( &re );\n\n\t// add the dlight\n\tif ( le->light ) {\n\t\tfloat\t\tlight;\n\n\t\tlight = (float)( cg.time - le->startTime ) / ( le->endTime - le->startTime );\n\t\tif ( light < 0.5 ) {\n\t\t\tlight = 1.0;\n\t\t} else {\n\t\t\tlight = 1.0 - ( light - 0.5 ) * 2;\n\t\t}\n\t\tlight = le->light * light;\n\t\ttrap_R_AddLightToScene(re.origin, light, le->lightColor[0], le->lightColor[1], le->lightColor[2] );\n\t}\n}\n\n\n/*\n===================\nCG_AddScorePlum\n===================\n*/\n#define NUMBER_SIZE\t\t8\n\nvoid CG_AddScorePlum( localEntity_t *le ) {\n\trefEntity_t\t*re;\n\tvec3_t\t\torigin, delta, dir, vec, up = {0, 0, 1};\n\tfloat\t\tc, len;\n\tint\t\t\ti, score, digits[10], numdigits, negative;\n\n\tre = &le->refEntity;\n\n\tc = ( le->endTime - cg.time ) * le->lifeRate;\n\n\tscore = le->radius;\n\tif (score < 0) {\n\t\tre->shaderRGBA[0] = 0xff;\n\t\tre->shaderRGBA[1] = 0x11;\n\t\tre->shaderRGBA[2] = 0x11;\n\t}\n\telse {\n\t\tre->shaderRGBA[0] = 0xff;\n\t\tre->shaderRGBA[1] = 0xff;\n\t\tre->shaderRGBA[2] = 0xff;\n\t\tif (score >= 50) {\n\t\t\tre->shaderRGBA[1] = 0;\n\t\t} else if (score >= 20) {\n\t\t\tre->shaderRGBA[0] = re->shaderRGBA[1] = 0;\n\t\t} else if (score >= 10) {\n\t\t\tre->shaderRGBA[2] = 0;\n\t\t} else if (score >= 2) {\n\t\t\tre->shaderRGBA[0] = re->shaderRGBA[2] = 0;\n\t\t}\n\n\t}\n\tif (c < 0.25)\n\t\tre->shaderRGBA[3] = 0xff * 4 * c;\n\telse\n\t\tre->shaderRGBA[3] = 0xff;\n\n\tre->radius = NUMBER_SIZE / 2;\n\n\tVectorCopy(le->pos.trBase, origin);\n\torigin[2] += 110 - c * 100;\n\n\tVectorSubtract(cg.refdef.vieworg, origin, dir);\n\tCrossProduct(dir, up, vec);\n\tVectorNormalize(vec);\n\n\tVectorMA(origin, -10 + 20 * sin(c * 2 * M_PI), vec, origin);\n\n\t// if the view would be \"inside\" the sprite, kill the sprite\n\t// so it doesn't add too much overdraw\n\tVectorSubtract( origin, cg.refdef.vieworg, delta );\n\tlen = VectorLength( delta );\n\tif ( len < 20 ) {\n\t\tCG_FreeLocalEntity( le );\n\t\treturn;\n\t}\n\n\tnegative = qfalse;\n\tif (score < 0) {\n\t\tnegative = qtrue;\n\t\tscore = -score;\n\t}\n\n\tfor (numdigits = 0; !(numdigits && !score); numdigits++) {\n\t\tdigits[numdigits] = score % 10;\n\t\tscore = score / 10;\n\t}\n\n\tif (negative) {\n\t\tdigits[numdigits] = 10;\n\t\tnumdigits++;\n\t}\n\n\tfor (i = 0; i < numdigits; i++) {\n\t\tVectorMA(origin, (float) (((float) numdigits / 2) - i) * NUMBER_SIZE, vec, re->origin);\n\t\tre->customShader = cgs.media.numberShaders[digits[numdigits-1-i]];\n\t\ttrap_R_AddRefEntityToScene( re );\n\t}\n}\n\n\n\n\n//==============================================================================\n\n/*\n===================\nCG_AddLocalEntities\n\n===================\n*/\nvoid CG_AddLocalEntities( void ) {\n\tlocalEntity_t\t*le, *next;\n\n\t// walk the list backwards, so any new local entities generated\n\t// (trails, marks, etc) will be present this frame\n\tle = cg_activeLocalEntities.prev;\n\tfor ( ; le != &cg_activeLocalEntities ; le = next ) {\n\t\t// grab next now, so if the local entity is freed we\n\t\t// still have it\n\t\tnext = le->prev;\n\n\t\tif ( cg.time >= le->endTime ) {\n\t\t\tCG_FreeLocalEntity( le );\n\t\t\tcontinue;\n\t\t}\n\t\tswitch ( le->leType ) {\n\t\tdefault:\n\t\t\tCG_Error( \"Bad leType: %i\", le->leType );\n\t\t\tbreak;\n\n\t\tcase LE_MARK:\n\t\t\tbreak;\n\n\t\tcase LE_SPRITE_EXPLOSION:\n\t\t\tCG_AddSpriteExplosion( le );\n\t\t\tbreak;\n\n\t\tcase LE_EXPLOSION:\n\t\t\tCG_AddExplosion( le );\n\t\t\tbreak;\n\n\t\tcase LE_FRAGMENT:\t\t\t// gibs and brass\n\t\t\tCG_AddFragment( le );\n\t\t\tbreak;\n\n\t\tcase LE_MOVE_SCALE_FADE:\t\t// water bubbles\n\t\t\tCG_AddMoveScaleFade( le );\n\t\t\tbreak;\n\n\t\tcase LE_FADE_RGB:\t\t\t\t// teleporters, railtrails\n\t\t\tCG_AddFadeRGB( le );\n\t\t\tbreak;\n\n\t\tcase LE_FALL_SCALE_FADE: // gib blood trails\n\t\t\tCG_AddFallScaleFade( le );\n\t\t\tbreak;\n\n\t\tcase LE_SCALE_FADE:\t\t// rocket trails\n\t\t\tCG_AddScaleFade( le );\n\t\t\tbreak;\n\n\t\tcase LE_SCOREPLUM:\n\t\t\tCG_AddScorePlum( le );\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\n\n\n\n"
  },
  {
    "path": "src/cgame/cg_main.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n// cg_main.c -- initialization and primary entry point for cgame\n#include \"cg_local.h\"\n\nint forceModelModificationCount = -1;\n\nvoid CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum );\nvoid CG_Shutdown( void );\n\n\n/*\n================\nvmMain\n\nThis is the only way control passes into the module.\nThis must be the very first function compiled into the .q3vm file\n================\n*/\nintptr_t vmMain( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10, int arg11  ) {\n\n\tswitch ( command ) {\n\tcase CG_INIT:\n\t\tCG_Init( arg0, arg1, arg2 );\n\t\treturn 0;\n\tcase CG_SHUTDOWN:\n\t\tCG_Shutdown();\n\t\treturn 0;\n\tcase CG_CONSOLE_COMMAND:\n\t\treturn CG_ConsoleCommand();\n\tcase CG_DRAW_ACTIVE_FRAME:\n\t\tCG_DrawActiveFrame( arg0, arg1, arg2 );\n\t\treturn 0;\n\tcase CG_CROSSHAIR_PLAYER:\n\t\treturn CG_CrosshairPlayer();\n\tcase CG_LAST_ATTACKER:\n\t\treturn CG_LastAttacker();\n\tcase CG_KEY_EVENT:\n\t\tCG_KeyEvent(arg0, arg1);\n\t\treturn 0;\n\tcase CG_MOUSE_EVENT:\n\t\tCG_MouseEvent(arg0, arg1);\n\t\treturn 0;\n\tcase CG_EVENT_HANDLING:\n\t\tCG_EventHandling(arg0);\n\t\treturn 0;\n\tdefault:\n\t\tCG_Error( \"vmMain: unknown command %i\", command );\n\t\tbreak;\n\t}\n\treturn -1;\n}\n\n\ncg_t\t\t\t\tcg;\ncgs_t\t\t\t\tcgs;\ncentity_t\t\t\tcg_entities[MAX_GENTITIES];\nweaponInfo_t\t\tcg_weapons[MAX_WEAPONS];\nitemInfo_t\t\t\tcg_items[MAX_ITEMS];\n\n\nvmCvar_t\tcg_railTrailTime;\nvmCvar_t\tcg_centertime;\nvmCvar_t\tcg_runpitch;\nvmCvar_t\tcg_runroll;\nvmCvar_t\tcg_bobup;\nvmCvar_t\tcg_bobpitch;\nvmCvar_t\tcg_bobroll;\nvmCvar_t\tcg_swingSpeed;\nvmCvar_t\tcg_shadows;\nvmCvar_t\tcg_gibs;\nvmCvar_t\tcg_drawTimer;\nvmCvar_t\tcg_drawFPS;\nvmCvar_t\tcg_drawSnapshot;\nvmCvar_t\tcg_draw3dIcons;\nvmCvar_t\tcg_drawIcons;\nvmCvar_t\tcg_drawAmmoWarning;\nvmCvar_t\tcg_drawCrosshair;\nvmCvar_t\tcg_drawCrosshairNames;\nvmCvar_t\tcg_drawRewards;\nvmCvar_t\tcg_crosshairSize;\nvmCvar_t\tcg_crosshairX;\nvmCvar_t\tcg_crosshairY;\nvmCvar_t\tcg_crosshairHealth;\nvmCvar_t\tcg_draw2D;\nvmCvar_t\tcg_drawStatus;\nvmCvar_t\tcg_animSpeed;\nvmCvar_t\tcg_debugAnim;\nvmCvar_t\tcg_debugPosition;\nvmCvar_t\tcg_debugEvents;\nvmCvar_t\tcg_errorDecay;\nvmCvar_t\tcg_nopredict;\nvmCvar_t\tcg_noPlayerAnims;\nvmCvar_t\tcg_showmiss;\nvmCvar_t\tcg_footsteps;\nvmCvar_t\tcg_addMarks;\nvmCvar_t\tcg_brassTime;\nvmCvar_t\tcg_viewsize;\nvmCvar_t\tcg_drawGun;\nvmCvar_t\tcg_gun_frame;\nvmCvar_t\tcg_gun_x;\nvmCvar_t\tcg_gun_y;\nvmCvar_t\tcg_gun_z;\nvmCvar_t\tcg_tracerChance;\nvmCvar_t\tcg_tracerWidth;\nvmCvar_t\tcg_tracerLength;\nvmCvar_t\tcg_autoswitch;\nvmCvar_t\tcg_ignore;\nvmCvar_t\tcg_simpleItems;\nvmCvar_t\tcg_fov;\nvmCvar_t\tcg_zoomFov;\nvmCvar_t\tcg_thirdPerson;\nvmCvar_t\tcg_thirdPersonRange;\nvmCvar_t\tcg_thirdPersonAngle;\nvmCvar_t\tcg_stereoSeparation;\nvmCvar_t\tcg_lagometer;\nvmCvar_t\tcg_drawAttacker;\nvmCvar_t\tcg_synchronousClients;\nvmCvar_t \tcg_teamChatTime;\nvmCvar_t \tcg_teamChatHeight;\nvmCvar_t \tcg_stats;\nvmCvar_t \tcg_buildScript;\nvmCvar_t \tcg_forceModel;\nvmCvar_t\tcg_paused;\nvmCvar_t\tcg_blood;\nvmCvar_t\tcg_predictItems;\nvmCvar_t\tcg_deferPlayers;\nvmCvar_t\tcg_drawTeamOverlay;\nvmCvar_t\tcg_teamOverlayUserinfo;\nvmCvar_t\tcg_drawFriend;\nvmCvar_t\tcg_teamChatsOnly;\nvmCvar_t\tcg_noVoiceChats;\nvmCvar_t\tcg_noVoiceText;\nvmCvar_t\tcg_hudFiles;\nvmCvar_t \tcg_scorePlum;\nvmCvar_t \tcg_smoothClients;\nvmCvar_t\tpmove_fixed;\n//vmCvar_t\tcg_pmove_fixed;\nvmCvar_t\tpmove_msec;\nvmCvar_t\tcg_pmove_msec;\nvmCvar_t\tcg_cameraMode;\nvmCvar_t\tcg_cameraOrbit;\nvmCvar_t\tcg_cameraOrbitDelay;\nvmCvar_t\tcg_timescaleFadeEnd;\nvmCvar_t\tcg_timescaleFadeSpeed;\nvmCvar_t\tcg_timescale;\nvmCvar_t\tcg_smallFont;\nvmCvar_t\tcg_bigFont;\nvmCvar_t\tcg_noTaunt;\nvmCvar_t\tcg_noProjectileTrail;\nvmCvar_t\tcg_oldRail;\nvmCvar_t\tcg_oldRocket;\nvmCvar_t\tcg_oldPlasma;\nvmCvar_t\tcg_trueLightning;\n\ntypedef struct {\n\tvmCvar_t\t*vmCvar;\n\tchar\t\t*cvarName;\n\tchar\t\t*defaultString;\n\tint\t\t\tcvarFlags;\n} cvarTable_t;\n\nstatic cvarTable_t cvarTable[] = { // bk001129\n\t{ &cg_ignore, \"cg_ignore\", \"0\", 0 },\t// used for debugging\n\t{ &cg_autoswitch, \"cg_autoswitch\", \"1\", CVAR_ARCHIVE },\n\t{ &cg_drawGun, \"cg_drawGun\", \"1\", CVAR_ARCHIVE },\n\t{ &cg_zoomFov, \"cg_zoomfov\", \"22.5\", CVAR_ARCHIVE },\n\t{ &cg_fov, \"cg_fov\", \"90\", CVAR_ARCHIVE },\n\t{ &cg_viewsize, \"cg_viewsize\", \"100\", CVAR_ARCHIVE },\n\t{ &cg_stereoSeparation, \"cg_stereoSeparation\", \"0.4\", CVAR_ARCHIVE  },\n\t{ &cg_shadows, \"cg_shadows\", \"1\", CVAR_ARCHIVE  },\n\t{ &cg_gibs, \"cg_gibs\", \"1\", CVAR_ARCHIVE  },\n\t{ &cg_draw2D, \"cg_draw2D\", \"1\", CVAR_ARCHIVE  },\n\t{ &cg_drawStatus, \"cg_drawStatus\", \"1\", CVAR_ARCHIVE  },\n\t{ &cg_drawTimer, \"cg_drawTimer\", \"0\", CVAR_ARCHIVE  },\n\t{ &cg_drawFPS, \"cg_drawFPS\", \"0\", CVAR_ARCHIVE  },\n\t{ &cg_drawSnapshot, \"cg_drawSnapshot\", \"0\", CVAR_ARCHIVE  },\n\t{ &cg_draw3dIcons, \"cg_draw3dIcons\", \"1\", CVAR_ARCHIVE  },\n\t{ &cg_drawIcons, \"cg_drawIcons\", \"1\", CVAR_ARCHIVE  },\n\t{ &cg_drawAmmoWarning, \"cg_drawAmmoWarning\", \"1\", CVAR_ARCHIVE  },\n\t{ &cg_drawAttacker, \"cg_drawAttacker\", \"1\", CVAR_ARCHIVE  },\n\t{ &cg_drawCrosshair, \"cg_drawCrosshair\", \"4\", CVAR_ARCHIVE },\n\t{ &cg_drawCrosshairNames, \"cg_drawCrosshairNames\", \"1\", CVAR_ARCHIVE },\n\t{ &cg_drawRewards, \"cg_drawRewards\", \"1\", CVAR_ARCHIVE },\n\t{ &cg_crosshairSize, \"cg_crosshairSize\", \"24\", CVAR_ARCHIVE },\n\t{ &cg_crosshairHealth, \"cg_crosshairHealth\", \"1\", CVAR_ARCHIVE },\n\t{ &cg_crosshairX, \"cg_crosshairX\", \"0\", CVAR_ARCHIVE },\n\t{ &cg_crosshairY, \"cg_crosshairY\", \"0\", CVAR_ARCHIVE },\n\t{ &cg_brassTime, \"cg_brassTime\", \"2500\", CVAR_ARCHIVE },\n\t{ &cg_simpleItems, \"cg_simpleItems\", \"0\", CVAR_ARCHIVE },\n\t{ &cg_addMarks, \"cg_marks\", \"1\", CVAR_ARCHIVE },\n\t{ &cg_lagometer, \"cg_lagometer\", \"1\", CVAR_ARCHIVE },\n\t{ &cg_railTrailTime, \"cg_railTrailTime\", \"400\", CVAR_ARCHIVE  },\n\t{ &cg_gun_x, \"cg_gunX\", \"0\", CVAR_CHEAT },\n\t{ &cg_gun_y, \"cg_gunY\", \"0\", CVAR_CHEAT },\n\t{ &cg_gun_z, \"cg_gunZ\", \"0\", CVAR_CHEAT },\n\t{ &cg_centertime, \"cg_centertime\", \"3\", CVAR_CHEAT },\n\t{ &cg_runpitch, \"cg_runpitch\", \"0.002\", CVAR_ARCHIVE},\n\t{ &cg_runroll, \"cg_runroll\", \"0.005\", CVAR_ARCHIVE },\n\t{ &cg_bobup , \"cg_bobup\", \"0.005\", CVAR_CHEAT },\n\t{ &cg_bobpitch, \"cg_bobpitch\", \"0.002\", CVAR_ARCHIVE },\n\t{ &cg_bobroll, \"cg_bobroll\", \"0.002\", CVAR_ARCHIVE },\n\t{ &cg_swingSpeed, \"cg_swingSpeed\", \"0.3\", CVAR_CHEAT },\n\t{ &cg_animSpeed, \"cg_animspeed\", \"1\", CVAR_CHEAT },\n\t{ &cg_debugAnim, \"cg_debuganim\", \"0\", CVAR_CHEAT },\n\t{ &cg_debugPosition, \"cg_debugposition\", \"0\", CVAR_CHEAT },\n\t{ &cg_debugEvents, \"cg_debugevents\", \"0\", CVAR_CHEAT },\n\t{ &cg_errorDecay, \"cg_errordecay\", \"100\", 0 },\n\t{ &cg_nopredict, \"cg_nopredict\", \"0\", 0 },\n\t{ &cg_noPlayerAnims, \"cg_noplayeranims\", \"0\", CVAR_CHEAT },\n\t{ &cg_showmiss, \"cg_showmiss\", \"0\", 0 },\n\t{ &cg_footsteps, \"cg_footsteps\", \"1\", CVAR_CHEAT },\n\t{ &cg_tracerChance, \"cg_tracerchance\", \"0.4\", CVAR_CHEAT },\n\t{ &cg_tracerWidth, \"cg_tracerwidth\", \"1\", CVAR_CHEAT },\n\t{ &cg_tracerLength, \"cg_tracerlength\", \"100\", CVAR_CHEAT },\n\t{ &cg_thirdPersonRange, \"cg_thirdPersonRange\", \"40\", CVAR_CHEAT },\n\t{ &cg_thirdPersonAngle, \"cg_thirdPersonAngle\", \"0\", CVAR_CHEAT },\n\t{ &cg_thirdPerson, \"cg_thirdPerson\", \"0\", 0 },\n\t{ &cg_teamChatTime, \"cg_teamChatTime\", \"3000\", CVAR_ARCHIVE  },\n\t{ &cg_teamChatHeight, \"cg_teamChatHeight\", \"0\", CVAR_ARCHIVE  },\n\t{ &cg_forceModel, \"cg_forceModel\", \"0\", CVAR_ARCHIVE  },\n\t{ &cg_predictItems, \"cg_predictItems\", \"1\", CVAR_ARCHIVE },\n\t{ &cg_deferPlayers, \"cg_deferPlayers\", \"1\", CVAR_ARCHIVE },\n\t{ &cg_drawTeamOverlay, \"cg_drawTeamOverlay\", \"0\", CVAR_ARCHIVE },\n\t{ &cg_teamOverlayUserinfo, \"teamoverlay\", \"0\", CVAR_ROM | CVAR_USERINFO },\n\t{ &cg_stats, \"cg_stats\", \"0\", 0 },\n\t{ &cg_drawFriend, \"cg_drawFriend\", \"1\", CVAR_ARCHIVE },\n\t{ &cg_teamChatsOnly, \"cg_teamChatsOnly\", \"0\", CVAR_ARCHIVE },\n\t{ &cg_noVoiceChats, \"cg_noVoiceChats\", \"0\", CVAR_ARCHIVE },\n\t{ &cg_noVoiceText, \"cg_noVoiceText\", \"0\", CVAR_ARCHIVE },\n\t// the following variables are created in other parts of the system,\n\t// but we also reference them here\n\t{ &cg_buildScript, \"com_buildScript\", \"0\", 0 },\t// force loading of all possible data amd error on failures\n\t{ &cg_paused, \"cl_paused\", \"0\", CVAR_ROM },\n\t{ &cg_blood, \"com_blood\", \"1\", CVAR_ARCHIVE },\n\t{ &cg_synchronousClients, \"g_synchronousClients\", \"0\", 0 },\t// communicated by systeminfo\n\t{ &cg_cameraOrbit, \"cg_cameraOrbit\", \"0\", CVAR_CHEAT},\n\t{ &cg_cameraOrbitDelay, \"cg_cameraOrbitDelay\", \"50\", CVAR_ARCHIVE},\n\t{ &cg_timescaleFadeEnd, \"cg_timescaleFadeEnd\", \"1\", 0},\n\t{ &cg_timescaleFadeSpeed, \"cg_timescaleFadeSpeed\", \"0\", 0},\n\t{ &cg_timescale, \"timescale\", \"1\", 0},\n\t{ &cg_scorePlum, \"cg_scorePlums\", \"1\", CVAR_USERINFO | CVAR_ARCHIVE},\n\t{ &cg_smoothClients, \"cg_smoothClients\", \"0\", CVAR_USERINFO | CVAR_ARCHIVE},\n\t{ &cg_cameraMode, \"com_cameraMode\", \"0\", CVAR_CHEAT},\n\n\t{ &pmove_fixed, \"pmove_fixed\", \"0\", 0},\n\t{ &pmove_msec, \"pmove_msec\", \"8\", 0},\n\t{ &cg_noTaunt, \"cg_noTaunt\", \"0\", CVAR_ARCHIVE},\n\t{ &cg_noProjectileTrail, \"cg_noProjectileTrail\", \"0\", CVAR_ARCHIVE},\n\t{ &cg_smallFont, \"ui_smallFont\", \"0.25\", CVAR_ARCHIVE},\n\t{ &cg_bigFont, \"ui_bigFont\", \"0.4\", CVAR_ARCHIVE},\n\t{ &cg_oldRail, \"cg_oldRail\", \"1\", CVAR_ARCHIVE},\n\t{ &cg_oldRocket, \"cg_oldRocket\", \"1\", CVAR_ARCHIVE},\n\t{ &cg_oldPlasma, \"cg_oldPlasma\", \"1\", CVAR_ARCHIVE},\n\t{ &cg_trueLightning, \"cg_trueLightning\", \"0.0\", CVAR_ARCHIVE}\n//\t{ &cg_pmove_fixed, \"cg_pmove_fixed\", \"0\", CVAR_USERINFO | CVAR_ARCHIVE }\n};\n\nstatic int  cvarTableSize = sizeof( cvarTable ) / sizeof( cvarTable[0] );\n\n/*\n=================\nCG_RegisterCvars\n=================\n*/\nvoid CG_RegisterCvars( void ) {\n\tint\t\t\ti;\n\tcvarTable_t\t*cv;\n\tchar\t\tvar[MAX_TOKEN_CHARS];\n\n\tfor ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ ) {\n\t\ttrap_Cvar_Register( cv->vmCvar, cv->cvarName,\n\t\t\tcv->defaultString, cv->cvarFlags );\n\t}\n\n\t// see if we are also running the server on this machine\n\ttrap_Cvar_VariableStringBuffer( \"sv_running\", var, sizeof( var ) );\n\tcgs.localServer = atoi( var );\n\n\tforceModelModificationCount = cg_forceModel.modificationCount;\n\n\ttrap_Cvar_Register(NULL, \"model\", DEFAULT_MODEL, CVAR_USERINFO | CVAR_ARCHIVE );\n\ttrap_Cvar_Register(NULL, \"headmodel\", DEFAULT_MODEL, CVAR_USERINFO | CVAR_ARCHIVE );\n\ttrap_Cvar_Register(NULL, \"team_model\", DEFAULT_TEAM_MODEL, CVAR_USERINFO | CVAR_ARCHIVE );\n\ttrap_Cvar_Register(NULL, \"team_headmodel\", DEFAULT_TEAM_HEAD, CVAR_USERINFO | CVAR_ARCHIVE );\n}\n\n/*\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n===================\nCG_ForceModelChange\n===================\n*/\nstatic void CG_ForceModelChange( void ) {\n\tint\t\ti;\n\n\tfor (i=0 ; i<MAX_CLIENTS ; i++) {\n\t\tconst char\t\t*clientInfo;\n\n\t\tclientInfo = CG_ConfigString( CS_PLAYERS+i );\n\t\tif ( !clientInfo[0] ) {\n\t\t\tcontinue;\n\t\t}\n\t\tCG_NewClientInfo( i );\n\t}\n}\n\n/*\n=================\nCG_UpdateCvars\n=================\n*/\nvoid CG_UpdateCvars( void ) {\n\tint\t\t\ti;\n\tcvarTable_t\t*cv;\n\n\tfor ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ ) {\n\t\ttrap_Cvar_Update( cv->vmCvar );\n\t}\n\n\t// check for modications here\n\n\t// If team overlay is on, ask for updates from the server.  If its off,\n\t// let the server know so we don't receive it\n\tif ( drawTeamOverlayModificationCount != cg_drawTeamOverlay.modificationCount ) {\n\t\tdrawTeamOverlayModificationCount = cg_drawTeamOverlay.modificationCount;\n\n\t\tif ( cg_drawTeamOverlay.integer > 0 ) {\n\t\t\ttrap_Cvar_Set( \"teamoverlay\", \"1\" );\n\t\t} else {\n\t\t\ttrap_Cvar_Set( \"teamoverlay\", \"0\" );\n\t\t}\n\t\t// FIXME E3 HACK\n\t\ttrap_Cvar_Set( \"teamoverlay\", \"1\" );\n\t}\n\n\t// if force model changed\n\tif ( forceModelModificationCount != cg_forceModel.modificationCount ) {\n\t\tforceModelModificationCount = cg_forceModel.modificationCount;\n\t\tCG_ForceModelChange();\n\t}\n}\n\nint CG_CrosshairPlayer( void ) {\n\tif ( cg.time > ( cg.crosshairClientTime + 1000 ) ) {\n\t\treturn -1;\n\t}\n\treturn cg.crosshairClientNum;\n}\n\nint CG_LastAttacker( void ) {\n\tif ( !cg.attackerTime ) {\n\t\treturn -1;\n\t}\n\treturn cg.snap->ps.persistant[PERS_ATTACKER];\n}\n\nvoid QDECL CG_Printf( const char *msg, ... ) {\n\tva_list\t\targptr;\n\tchar\t\ttext[1024];\n\n\tva_start (argptr, msg);\n\tvsprintf (text, msg, argptr);\n\tva_end (argptr);\n\n\ttrap_Print( text );\n}\n\nvoid QDECL CG_Error( const char *msg, ... ) {\n\tva_list\t\targptr;\n\tchar\t\ttext[1024];\n\n\tva_start (argptr, msg);\n\tvsprintf (text, msg, argptr);\n\tva_end (argptr);\n\n\ttrap_Error( text );\n}\n\n#ifndef CGAME_HARD_LINKED\n// this is only here so the functions in q_shared.c and bg_*.c can link (FIXME)\n\nvoid QDECL Com_Error( int level, const char *error, ... ) {\n\tva_list\t\targptr;\n\tchar\t\ttext[1024];\n\n\tva_start (argptr, error);\n\tvsprintf (text, error, argptr);\n\tva_end (argptr);\n\n\tCG_Error( \"%s\", text);\n}\n\nvoid QDECL Com_Printf( const char *msg, ... ) {\n\tva_list\t\targptr;\n\tchar\t\ttext[1024];\n\n\tva_start (argptr, msg);\n\tvsprintf (text, msg, argptr);\n\tva_end (argptr);\n\n\tCG_Printf (\"%s\", text);\n}\n\n#endif\n\n/*\n================\nCG_Argv\n================\n*/\nconst char *CG_Argv( int arg ) {\n\tstatic char\tbuffer[MAX_STRING_CHARS];\n\n\ttrap_Argv( arg, buffer, sizeof( buffer ) );\n\n\treturn buffer;\n}\n\n\n//========================================================================\n\n/*\n=================\nCG_RegisterItemSounds\n\nThe server says this item is used on this level\n=================\n*/\nstatic void CG_RegisterItemSounds( int itemNum ) {\n\tgitem_t\t\t\t*item;\n\tchar\t\t\tdata[MAX_QPATH];\n\tchar\t\t\t*s, *start;\n\tint\t\t\t\tlen;\n\n\titem = &bg_itemlist[ itemNum ];\n\n\tif( item->pickup_sound ) {\n\t\ttrap_S_RegisterSound( item->pickup_sound, qfalse );\n\t}\n\n\t// parse the space seperated precache string for other media\n\ts = item->sounds;\n\tif (!s || !s[0])\n\t\treturn;\n\n\twhile (*s) {\n\t\tstart = s;\n\t\twhile (*s && *s != ' ') {\n\t\t\ts++;\n\t\t}\n\n\t\tlen = s-start;\n\t\tif (len >= MAX_QPATH || len < 5) {\n\t\t\tCG_Error( \"PrecacheItem: %s has bad precache string\", \n\t\t\t\titem->classname);\n\t\t\treturn;\n\t\t}\n\t\tmemcpy (data, start, len);\n\t\tdata[len] = 0;\n\t\tif ( *s ) {\n\t\t\ts++;\n\t\t}\n\n\t\tif ( !strcmp(data+len-3, \"wav\" )) {\n\t\t\ttrap_S_RegisterSound( data, qfalse );\n\t\t}\n\t}\n}\n\n\n/*\n=================\nCG_RegisterSounds\n\ncalled during a precache command\n=================\n*/\nstatic void CG_RegisterSounds( void ) {\n\tint\t\ti;\n\tchar\titems[MAX_ITEMS+1];\n\tchar\tname[MAX_QPATH];\n\tconst char\t*soundName;\n\n\tcgs.media.oneMinuteSound = trap_S_RegisterSound( \"sound/feedback/1_minute.wav\", qtrue );\n\tcgs.media.fiveMinuteSound = trap_S_RegisterSound( \"sound/feedback/5_minute.wav\", qtrue );\n\tcgs.media.suddenDeathSound = trap_S_RegisterSound( \"sound/feedback/sudden_death.wav\", qtrue );\n\tcgs.media.oneFragSound = trap_S_RegisterSound( \"sound/feedback/1_frag.wav\", qtrue );\n\tcgs.media.twoFragSound = trap_S_RegisterSound( \"sound/feedback/2_frags.wav\", qtrue );\n\tcgs.media.threeFragSound = trap_S_RegisterSound( \"sound/feedback/3_frags.wav\", qtrue );\n\tcgs.media.count3Sound = trap_S_RegisterSound( \"sound/feedback/three.wav\", qtrue );\n\tcgs.media.count2Sound = trap_S_RegisterSound( \"sound/feedback/two.wav\", qtrue );\n\tcgs.media.count1Sound = trap_S_RegisterSound( \"sound/feedback/one.wav\", qtrue );\n\tcgs.media.countFightSound = trap_S_RegisterSound( \"sound/feedback/fight.wav\", qtrue );\n\tcgs.media.countPrepareSound = trap_S_RegisterSound( \"sound/feedback/prepare.wav\", qtrue );\n\n\tif ( cgs.gametype >= GT_TEAM || cg_buildScript.integer ) {\n\n\t\tcgs.media.captureAwardSound = trap_S_RegisterSound( \"sound/teamplay/flagcapture_yourteam.wav\", qtrue );\n\t\tcgs.media.redLeadsSound = trap_S_RegisterSound( \"sound/feedback/redleads.wav\", qtrue );\n\t\tcgs.media.blueLeadsSound = trap_S_RegisterSound( \"sound/feedback/blueleads.wav\", qtrue );\n\t\tcgs.media.teamsTiedSound = trap_S_RegisterSound( \"sound/feedback/teamstied.wav\", qtrue );\n\t\tcgs.media.hitTeamSound = trap_S_RegisterSound( \"sound/feedback/hit_teammate.wav\", qtrue );\n\n\t\tcgs.media.redScoredSound = trap_S_RegisterSound( \"sound/teamplay/voc_red_scores.wav\", qtrue );\n\t\tcgs.media.blueScoredSound = trap_S_RegisterSound( \"sound/teamplay/voc_blue_scores.wav\", qtrue );\n\n\t\tcgs.media.captureYourTeamSound = trap_S_RegisterSound( \"sound/teamplay/flagcapture_yourteam.wav\", qtrue );\n\t\tcgs.media.captureOpponentSound = trap_S_RegisterSound( \"sound/teamplay/flagcapture_opponent.wav\", qtrue );\n\n\t\tcgs.media.returnYourTeamSound = trap_S_RegisterSound( \"sound/teamplay/flagreturn_yourteam.wav\", qtrue );\n\t\tcgs.media.returnOpponentSound = trap_S_RegisterSound( \"sound/teamplay/flagreturn_opponent.wav\", qtrue );\n\n\t\tcgs.media.takenYourTeamSound = trap_S_RegisterSound( \"sound/teamplay/flagtaken_yourteam.wav\", qtrue );\n\t\tcgs.media.takenOpponentSound = trap_S_RegisterSound( \"sound/teamplay/flagtaken_opponent.wav\", qtrue );\n\n\t\tif ( cgs.gametype == GT_CTF || cg_buildScript.integer ) {\n\t\t\tcgs.media.redFlagReturnedSound = trap_S_RegisterSound( \"sound/teamplay/voc_red_returned.wav\", qtrue );\n\t\t\tcgs.media.blueFlagReturnedSound = trap_S_RegisterSound( \"sound/teamplay/voc_blue_returned.wav\", qtrue );\n\t\t\tcgs.media.enemyTookYourFlagSound = trap_S_RegisterSound( \"sound/teamplay/voc_enemy_flag.wav\", qtrue );\n\t\t\tcgs.media.yourTeamTookEnemyFlagSound = trap_S_RegisterSound( \"sound/teamplay/voc_team_flag.wav\", qtrue );\n\t\t}\n\n\t\tcgs.media.youHaveFlagSound = trap_S_RegisterSound( \"sound/teamplay/voc_you_flag.wav\", qtrue );\n\t\tcgs.media.holyShitSound = trap_S_RegisterSound(\"sound/feedback/voc_holyshit.wav\", qtrue);\n\t\tcgs.media.neutralFlagReturnedSound = trap_S_RegisterSound( \"sound/teamplay/flagreturn_opponent.wav\", qtrue );\n\t\tcgs.media.yourTeamTookTheFlagSound = trap_S_RegisterSound( \"sound/teamplay/voc_team_1flag.wav\", qtrue );\n\t\tcgs.media.enemyTookTheFlagSound = trap_S_RegisterSound( \"sound/teamplay/voc_enemy_1flag.wav\", qtrue );\n\t}\n\n\tcgs.media.tracerSound = trap_S_RegisterSound( \"sound/weapons/machinegun/buletby1.wav\", qfalse );\n\tcgs.media.selectSound = trap_S_RegisterSound( \"sound/weapons/change.wav\", qfalse );\n\tcgs.media.wearOffSound = trap_S_RegisterSound( \"sound/items/wearoff.wav\", qfalse );\n\tcgs.media.useNothingSound = trap_S_RegisterSound( \"sound/items/use_nothing.wav\", qfalse );\n\tcgs.media.gibSound = trap_S_RegisterSound( \"sound/player/gibsplt1.wav\", qfalse );\n\tcgs.media.gibBounce1Sound = trap_S_RegisterSound( \"sound/player/gibimp1.wav\", qfalse );\n\tcgs.media.gibBounce2Sound = trap_S_RegisterSound( \"sound/player/gibimp2.wav\", qfalse );\n\tcgs.media.gibBounce3Sound = trap_S_RegisterSound( \"sound/player/gibimp3.wav\", qfalse );\n\n\tcgs.media.teleInSound = trap_S_RegisterSound( \"sound/world/telein.wav\", qfalse );\n\tcgs.media.teleOutSound = trap_S_RegisterSound( \"sound/world/teleout.wav\", qfalse );\n\tcgs.media.respawnSound = trap_S_RegisterSound( \"sound/items/respawn1.wav\", qfalse );\n\n\tcgs.media.noAmmoSound = trap_S_RegisterSound( \"sound/weapons/noammo.wav\", qfalse );\n\n\tcgs.media.talkSound = trap_S_RegisterSound( \"sound/player/talk.wav\", qfalse );\n\tcgs.media.landSound = trap_S_RegisterSound( \"sound/player/land1.wav\", qfalse);\n\n\tcgs.media.hitSound = trap_S_RegisterSound( \"sound/feedback/hit.wav\", qfalse );\n\n\tcgs.media.impressiveSound = trap_S_RegisterSound( \"sound/feedback/impressive.wav\", qtrue );\n\tcgs.media.excellentSound = trap_S_RegisterSound( \"sound/feedback/excellent.wav\", qtrue );\n\tcgs.media.deniedSound = trap_S_RegisterSound( \"sound/feedback/denied.wav\", qtrue );\n\tcgs.media.humiliationSound = trap_S_RegisterSound( \"sound/feedback/humiliation.wav\", qtrue );\n\tcgs.media.assistSound = trap_S_RegisterSound( \"sound/feedback/assist.wav\", qtrue );\n\tcgs.media.defendSound = trap_S_RegisterSound( \"sound/feedback/defense.wav\", qtrue );\n\n\tcgs.media.takenLeadSound = trap_S_RegisterSound( \"sound/feedback/takenlead.wav\", qtrue);\n\tcgs.media.tiedLeadSound = trap_S_RegisterSound( \"sound/feedback/tiedlead.wav\", qtrue);\n\tcgs.media.lostLeadSound = trap_S_RegisterSound( \"sound/feedback/lostlead.wav\", qtrue);\n\n\tcgs.media.watrInSound = trap_S_RegisterSound( \"sound/player/watr_in.wav\", qfalse);\n\tcgs.media.watrOutSound = trap_S_RegisterSound( \"sound/player/watr_out.wav\", qfalse);\n\tcgs.media.watrUnSound = trap_S_RegisterSound( \"sound/player/watr_un.wav\", qfalse);\n\n\tcgs.media.jumpPadSound = trap_S_RegisterSound (\"sound/world/jumppad.wav\", qfalse );\n\n\tfor (i=0 ; i<4 ; i++) {\n\t\tCom_sprintf (name, sizeof(name), \"sound/player/footsteps/step%i.wav\", i+1);\n\t\tcgs.media.footsteps[FOOTSTEP_NORMAL][i] = trap_S_RegisterSound (name, qfalse);\n\n\t\tCom_sprintf (name, sizeof(name), \"sound/player/footsteps/boot%i.wav\", i+1);\n\t\tcgs.media.footsteps[FOOTSTEP_BOOT][i] = trap_S_RegisterSound (name, qfalse);\n\n\t\tCom_sprintf (name, sizeof(name), \"sound/player/footsteps/flesh%i.wav\", i+1);\n\t\tcgs.media.footsteps[FOOTSTEP_FLESH][i] = trap_S_RegisterSound (name, qfalse);\n\n\t\tCom_sprintf (name, sizeof(name), \"sound/player/footsteps/mech%i.wav\", i+1);\n\t\tcgs.media.footsteps[FOOTSTEP_MECH][i] = trap_S_RegisterSound (name, qfalse);\n\n\t\tCom_sprintf (name, sizeof(name), \"sound/player/footsteps/energy%i.wav\", i+1);\n\t\tcgs.media.footsteps[FOOTSTEP_ENERGY][i] = trap_S_RegisterSound (name, qfalse);\n\n\t\tCom_sprintf (name, sizeof(name), \"sound/player/footsteps/splash%i.wav\", i+1);\n\t\tcgs.media.footsteps[FOOTSTEP_SPLASH][i] = trap_S_RegisterSound (name, qfalse);\n\n\t\tCom_sprintf (name, sizeof(name), \"sound/player/footsteps/clank%i.wav\", i+1);\n\t\tcgs.media.footsteps[FOOTSTEP_METAL][i] = trap_S_RegisterSound (name, qfalse);\n\t}\n\n\t// only register the items that the server says we need\n\tstrcpy( items, CG_ConfigString( CS_ITEMS ) );\n\n\tfor ( i = 1 ; i < bg_numItems ; i++ ) {\n//\t\tif ( items[ i ] == '1' || cg_buildScript.integer ) {\n\t\t\tCG_RegisterItemSounds( i );\n//\t\t}\n\t}\n\n\tfor ( i = 1 ; i < MAX_SOUNDS ; i++ ) {\n\t\tsoundName = CG_ConfigString( CS_SOUNDS+i );\n\t\tif ( !soundName[0] ) {\n\t\t\tbreak;\n\t\t}\n\t\tif ( soundName[0] == '*' ) {\n\t\t\tcontinue;\t// custom sound\n\t\t}\n\t\tcgs.gameSounds[i] = trap_S_RegisterSound( soundName, qfalse );\n\t}\n\n\t// FIXME: only needed with item\n\tcgs.media.flightSound = trap_S_RegisterSound( \"sound/items/flight.wav\", qfalse );\n\tcgs.media.medkitSound = trap_S_RegisterSound (\"sound/items/use_medkit.wav\", qfalse);\n\tcgs.media.quadSound = trap_S_RegisterSound(\"sound/items/damage3.wav\", qfalse);\n\tcgs.media.sfx_ric1 = trap_S_RegisterSound (\"sound/weapons/machinegun/ric1.wav\", qfalse);\n\tcgs.media.sfx_ric2 = trap_S_RegisterSound (\"sound/weapons/machinegun/ric2.wav\", qfalse);\n\tcgs.media.sfx_ric3 = trap_S_RegisterSound (\"sound/weapons/machinegun/ric3.wav\", qfalse);\n\tcgs.media.sfx_railg = trap_S_RegisterSound (\"sound/weapons/railgun/railgf1a.wav\", qfalse);\n\tcgs.media.sfx_rockexp = trap_S_RegisterSound (\"sound/weapons/rocket/rocklx1a.wav\", qfalse);\n\tcgs.media.sfx_plasmaexp = trap_S_RegisterSound (\"sound/weapons/plasma/plasmx1a.wav\", qfalse);\n\n\tcgs.media.regenSound = trap_S_RegisterSound(\"sound/items/regen.wav\", qfalse);\n\tcgs.media.protectSound = trap_S_RegisterSound(\"sound/items/protect3.wav\", qfalse);\n\tcgs.media.n_healthSound = trap_S_RegisterSound(\"sound/items/n_health.wav\", qfalse );\n\tcgs.media.hgrenb1aSound = trap_S_RegisterSound(\"sound/weapons/grenade/hgrenb1a.wav\", qfalse);\n\tcgs.media.hgrenb2aSound = trap_S_RegisterSound(\"sound/weapons/grenade/hgrenb2a.wav\", qfalse);\n}\n\n\n//===================================================================================\n\n\n/*\n=================\nCG_RegisterGraphics\n\nThis function may execute for a couple of minutes with a slow disk.\n=================\n*/\nstatic void CG_RegisterGraphics( void ) {\n\tint\t\t\ti;\n\tchar\t\titems[MAX_ITEMS+1];\n\tstatic char\t\t*sb_nums[11] = {\n\t\t\"gfx/2d/numbers/zero_32b\",\n\t\t\"gfx/2d/numbers/one_32b\",\n\t\t\"gfx/2d/numbers/two_32b\",\n\t\t\"gfx/2d/numbers/three_32b\",\n\t\t\"gfx/2d/numbers/four_32b\",\n\t\t\"gfx/2d/numbers/five_32b\",\n\t\t\"gfx/2d/numbers/six_32b\",\n\t\t\"gfx/2d/numbers/seven_32b\",\n\t\t\"gfx/2d/numbers/eight_32b\",\n\t\t\"gfx/2d/numbers/nine_32b\",\n\t\t\"gfx/2d/numbers/minus_32b\",\n\t};\n\n\t// clear any references to old media\n\tmemset( &cg.refdef, 0, sizeof( cg.refdef ) );\n\ttrap_R_ClearScene();\n\n\tCG_LoadingString( cgs.mapname );\n\n\ttrap_R_LoadWorldMap( cgs.mapname );\n\n\t// precache status bar pics\n\tCG_LoadingString( \"game media\" );\n\n\tfor ( i=0 ; i<11 ; i++) {\n\t\tcgs.media.numberShaders[i] = trap_R_RegisterShader( sb_nums[i] );\n\t}\n\n\tcgs.media.botSkillShaders[0] = trap_R_RegisterShader( \"menu/art/skill1.tga\" );\n\tcgs.media.botSkillShaders[1] = trap_R_RegisterShader( \"menu/art/skill2.tga\" );\n\tcgs.media.botSkillShaders[2] = trap_R_RegisterShader( \"menu/art/skill3.tga\" );\n\tcgs.media.botSkillShaders[3] = trap_R_RegisterShader( \"menu/art/skill4.tga\" );\n\tcgs.media.botSkillShaders[4] = trap_R_RegisterShader( \"menu/art/skill5.tga\" );\n\n\tcgs.media.viewBloodShader = trap_R_RegisterShader( \"viewBloodBlend\" );\n\n\tcgs.media.deferShader = trap_R_RegisterShaderNoMip( \"gfx/2d/defer.tga\" );\n\n\tcgs.media.scoreboardName = trap_R_RegisterShaderNoMip( \"menu/tab/name.tga\" );\n\tcgs.media.scoreboardPing = trap_R_RegisterShaderNoMip( \"menu/tab/ping.tga\" );\n\tcgs.media.scoreboardScore = trap_R_RegisterShaderNoMip( \"menu/tab/score.tga\" );\n\tcgs.media.scoreboardTime = trap_R_RegisterShaderNoMip( \"menu/tab/time.tga\" );\n\n\tcgs.media.smokePuffShader = trap_R_RegisterShader( \"smokePuff\" );\n\tcgs.media.smokePuffRageProShader = trap_R_RegisterShader( \"smokePuffRagePro\" );\n\tcgs.media.shotgunSmokePuffShader = trap_R_RegisterShader( \"shotgunSmokePuff\" );\n\tcgs.media.plasmaBallShader = trap_R_RegisterShader( \"sprites/plasma1\" );\n\tcgs.media.bloodTrailShader = trap_R_RegisterShader( \"bloodTrail\" );\n\tcgs.media.lagometerShader = trap_R_RegisterShader(\"lagometer\" );\n\tcgs.media.connectionShader = trap_R_RegisterShader( \"disconnected\" );\n\n\tcgs.media.waterBubbleShader = trap_R_RegisterShader( \"waterBubble\" );\n\n\tcgs.media.tracerShader = trap_R_RegisterShader( \"gfx/misc/tracer\" );\n\tcgs.media.selectShader = trap_R_RegisterShader( \"gfx/2d/select\" );\n\n\tfor ( i = 0 ; i < NUM_CROSSHAIRS ; i++ ) {\n\t\tcgs.media.crosshairShader[i] = trap_R_RegisterShader( va(\"gfx/2d/crosshair%c\", 'a'+i) );\n\t}\n\n\tcgs.media.backTileShader = trap_R_RegisterShader( \"gfx/2d/backtile\" );\n\tcgs.media.noammoShader = trap_R_RegisterShader( \"icons/noammo\" );\n\n\t// powerup shaders\n\tcgs.media.quadShader = trap_R_RegisterShader(\"powerups/quad\" );\n\tcgs.media.quadWeaponShader = trap_R_RegisterShader(\"powerups/quadWeapon\" );\n\tcgs.media.battleSuitShader = trap_R_RegisterShader(\"powerups/battleSuit\" );\n\tcgs.media.battleWeaponShader = trap_R_RegisterShader(\"powerups/battleWeapon\" );\n\tcgs.media.invisShader = trap_R_RegisterShader(\"powerups/invisibility\" );\n\tcgs.media.regenShader = trap_R_RegisterShader(\"powerups/regen\" );\n\tcgs.media.hastePuffShader = trap_R_RegisterShader(\"hasteSmokePuff\" );\n\n\tif ( cgs.gametype == GT_CTF || cg_buildScript.integer ) {\n\t\tcgs.media.redCubeModel = trap_R_RegisterModel( \"models/powerups/orb/r_orb.md3\" );\n\t\tcgs.media.blueCubeModel = trap_R_RegisterModel( \"models/powerups/orb/b_orb.md3\" );\n\t\tcgs.media.redCubeIcon = trap_R_RegisterShader( \"icons/skull_red\" );\n\t\tcgs.media.blueCubeIcon = trap_R_RegisterShader( \"icons/skull_blue\" );\n\t}\n\n\tif ( cgs.gametype == GT_CTF || cg_buildScript.integer ) {\n\t\tcgs.media.redFlagModel = trap_R_RegisterModel( \"models/flags/r_flag.md3\" );\n\t\tcgs.media.blueFlagModel = trap_R_RegisterModel( \"models/flags/b_flag.md3\" );\n\t\tcgs.media.redFlagShader[0] = trap_R_RegisterShaderNoMip( \"icons/iconf_red1\" );\n\t\tcgs.media.redFlagShader[1] = trap_R_RegisterShaderNoMip( \"icons/iconf_red2\" );\n\t\tcgs.media.redFlagShader[2] = trap_R_RegisterShaderNoMip( \"icons/iconf_red3\" );\n\t\tcgs.media.blueFlagShader[0] = trap_R_RegisterShaderNoMip( \"icons/iconf_blu1\" );\n\t\tcgs.media.blueFlagShader[1] = trap_R_RegisterShaderNoMip( \"icons/iconf_blu2\" );\n\t\tcgs.media.blueFlagShader[2] = trap_R_RegisterShaderNoMip( \"icons/iconf_blu3\" );\n\t}\n\n\tif ( cgs.gametype >= GT_TEAM || cg_buildScript.integer ) {\n\t\tcgs.media.friendShader = trap_R_RegisterShader( \"sprites/foe\" );\n\t\tcgs.media.redQuadShader = trap_R_RegisterShader(\"powerups/blueflag\" );\n\t\tcgs.media.teamStatusBar = trap_R_RegisterShader( \"gfx/2d/colorbar.tga\" );\n\t}\n\n\tcgs.media.armorModel = trap_R_RegisterModel( \"models/powerups/armor/armor_yel.md3\" );\n\tcgs.media.armorIcon  = trap_R_RegisterShaderNoMip( \"icons/iconr_yellow\" );\n\n\tcgs.media.machinegunBrassModel = trap_R_RegisterModel( \"models/weapons2/shells/m_shell.md3\" );\n\tcgs.media.shotgunBrassModel = trap_R_RegisterModel( \"models/weapons2/shells/s_shell.md3\" );\n\n\tcgs.media.gibAbdomen = trap_R_RegisterModel( \"models/gibs/abdomen.md3\" );\n\tcgs.media.gibArm = trap_R_RegisterModel( \"models/gibs/arm.md3\" );\n\tcgs.media.gibChest = trap_R_RegisterModel( \"models/gibs/chest.md3\" );\n\tcgs.media.gibFist = trap_R_RegisterModel( \"models/gibs/fist.md3\" );\n\tcgs.media.gibFoot = trap_R_RegisterModel( \"models/gibs/foot.md3\" );\n\tcgs.media.gibForearm = trap_R_RegisterModel( \"models/gibs/forearm.md3\" );\n\tcgs.media.gibIntestine = trap_R_RegisterModel( \"models/gibs/intestine.md3\" );\n\tcgs.media.gibLeg = trap_R_RegisterModel( \"models/gibs/leg.md3\" );\n\tcgs.media.gibSkull = trap_R_RegisterModel( \"models/gibs/skull.md3\" );\n\tcgs.media.gibBrain = trap_R_RegisterModel( \"models/gibs/brain.md3\" );\n\n\tcgs.media.smoke2 = trap_R_RegisterModel( \"models/weapons2/shells/s_shell.md3\" );\n\n\tcgs.media.balloonShader = trap_R_RegisterShader( \"sprites/balloon3\" );\n\n\tcgs.media.bloodExplosionShader = trap_R_RegisterShader( \"bloodExplosion\" );\n\n\tcgs.media.bulletFlashModel = trap_R_RegisterModel(\"models/weaphits/bullet.md3\");\n\tcgs.media.ringFlashModel = trap_R_RegisterModel(\"models/weaphits/ring02.md3\");\n\tcgs.media.dishFlashModel = trap_R_RegisterModel(\"models/weaphits/boom01.md3\");\n\tcgs.media.teleportEffectModel = trap_R_RegisterModel( \"models/misc/telep.md3\" );\n\tcgs.media.teleportEffectShader = trap_R_RegisterShader( \"teleportEffect\" );\n\n\tcgs.media.invulnerabilityPowerupModel = trap_R_RegisterModel( \"models/powerups/shield/shield.md3\" );\n\tcgs.media.medalImpressive = trap_R_RegisterShaderNoMip( \"medal_impressive\" );\n\tcgs.media.medalExcellent = trap_R_RegisterShaderNoMip( \"medal_excellent\" );\n\tcgs.media.medalGauntlet = trap_R_RegisterShaderNoMip( \"medal_gauntlet\" );\n\tcgs.media.medalDefend = trap_R_RegisterShaderNoMip( \"medal_defend\" );\n\tcgs.media.medalAssist = trap_R_RegisterShaderNoMip( \"medal_assist\" );\n\tcgs.media.medalCapture = trap_R_RegisterShaderNoMip( \"medal_capture\" );\n\n\n\tmemset( cg_items, 0, sizeof( cg_items ) );\n\tmemset( cg_weapons, 0, sizeof( cg_weapons ) );\n\n\t// only register the items that the server says we need\n\tstrcpy( items, CG_ConfigString( CS_ITEMS) );\n\n\tfor ( i = 1 ; i < bg_numItems ; i++ ) {\n\t\tif ( items[ i ] == '1' || cg_buildScript.integer ) {\n\t\t\tCG_LoadingItem( i );\n\t\t\tCG_RegisterItemVisuals( i );\n\t\t}\n\t}\n\n\t// wall marks\n\tcgs.media.bulletMarkShader = trap_R_RegisterShader( \"gfx/damage/bullet_mrk\" );\n\tcgs.media.burnMarkShader = trap_R_RegisterShader( \"gfx/damage/burn_med_mrk\" );\n\tcgs.media.holeMarkShader = trap_R_RegisterShader( \"gfx/damage/hole_lg_mrk\" );\n\tcgs.media.energyMarkShader = trap_R_RegisterShader( \"gfx/damage/plasma_mrk\" );\n\tcgs.media.shadowMarkShader = trap_R_RegisterShader( \"markShadow\" );\n\tcgs.media.wakeMarkShader = trap_R_RegisterShader( \"wake\" );\n\tcgs.media.bloodMarkShader = trap_R_RegisterShader( \"bloodMark\" );\n\n\t// register the inline models\n\tcgs.numInlineModels = trap_CM_NumInlineModels();\n\tfor ( i = 1 ; i < cgs.numInlineModels ; i++ ) {\n\t\tchar\tname[10];\n\t\tvec3_t\t\t\tmins, maxs;\n\t\tint\t\t\t\tj;\n\n\t\tCom_sprintf( name, sizeof(name), \"*%i\", i );\n\t\tcgs.inlineDrawModel[i] = trap_R_RegisterModel( name );\n\t\ttrap_R_ModelBounds( cgs.inlineDrawModel[i], mins, maxs );\n\t\tfor ( j = 0 ; j < 3 ; j++ ) {\n\t\t\tcgs.inlineModelMidpoints[i][j] = mins[j] + 0.5 * ( maxs[j] - mins[j] );\n\t\t}\n\t}\n\n\t// register all the server specified models\n\tfor (i=1 ; i<MAX_MODELS ; i++) {\n\t\tconst char\t\t*modelName;\n\n\t\tmodelName = CG_ConfigString( CS_MODELS+i );\n\t\tif ( !modelName[0] ) {\n\t\t\tbreak;\n\t\t}\n\t\tcgs.gameModels[i] = trap_R_RegisterModel( modelName );\n\t}\n\n\tCG_ClearParticles ();\n/*\n\tfor (i=1; i<MAX_PARTICLES_AREAS; i++)\n\t{\n\t\t{\n\t\t\tint rval;\n\n\t\t\trval = CG_NewParticleArea ( CS_PARTICLES + i);\n\t\t\tif (!rval)\n\t\t\t\tbreak;\n\t\t}\n\t}\n*/\n}\n\n\n\n/*\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n=======================\nCG_BuildSpectatorString\n\n=======================\n*/\nvoid CG_BuildSpectatorString() {\n\tint i;\n\tcg.spectatorList[0] = 0;\n\tfor (i = 0; i < MAX_CLIENTS; i++) {\n\t\tif (cgs.clientinfo[i].infoValid && cgs.clientinfo[i].team == TEAM_SPECTATOR ) {\n\t\t\tQ_strcat(cg.spectatorList, sizeof(cg.spectatorList), va(\"%s     \", cgs.clientinfo[i].name));\n\t\t}\n\t}\n\ti = (int)strlen(cg.spectatorList);\n\tif (i != cg.spectatorLen) {\n\t\tcg.spectatorLen = i;\n\t\tcg.spectatorWidth = -1;\n\t}\n}\n\n\n/*\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n===================\nCG_RegisterClients\n===================\n*/\nstatic void CG_RegisterClients( void ) {\n\tint\t\ti;\n\n\tCG_LoadingClient(cg.clientNum);\n\tCG_NewClientInfo(cg.clientNum);\n\n\tfor (i=0 ; i<MAX_CLIENTS ; i++) {\n\t\tconst char\t\t*clientInfo;\n\n\t\tif (cg.clientNum == i) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tclientInfo = CG_ConfigString( CS_PLAYERS+i );\n\t\tif ( !clientInfo[0]) {\n\t\t\tcontinue;\n\t\t}\n\t\tCG_LoadingClient( i );\n\t\tCG_NewClientInfo( i );\n\t}\n\tCG_BuildSpectatorString();\n}\n\n//===========================================================================\n\n/*\n=================\nCG_ConfigString\n=================\n*/\nconst char *CG_ConfigString( int index ) {\n\tif ( index < 0 || index >= MAX_CONFIGSTRINGS ) {\n\t\tCG_Error( \"CG_ConfigString: bad index: %i\", index );\n\t}\n\treturn cgs.gameState.stringData + cgs.gameState.stringOffsets[ index ];\n}\n\n//==================================================================\n\n/*\n======================\nCG_StartMusic\n\n======================\n*/\nvoid CG_StartMusic( void ) {\n\tchar\t*s;\n\tchar\tparm1[MAX_QPATH], parm2[MAX_QPATH];\n\n\t// start the background music\n\ts = (char *)CG_ConfigString( CS_MUSIC );\n\tQ_strncpyz( parm1, COM_Parse( &s ), sizeof( parm1 ) );\n\tQ_strncpyz( parm2, COM_Parse( &s ), sizeof( parm2 ) );\n\n\ttrap_S_StartBackgroundTrack( parm1, parm2 );\n}\n\n/*\n=================\nCG_Init\n\nCalled after every level change or subsystem restart\nWill perform callbacks to make the loading info screen update.\n=================\n*/\nvoid CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum ) {\n\tconst char\t*s;\n\n\t// clear everything\n\tmemset( &cgs, 0, sizeof( cgs ) );\n\tmemset( &cg, 0, sizeof( cg ) );\n\tmemset( cg_entities, 0, sizeof(cg_entities) );\n\tmemset( cg_weapons, 0, sizeof(cg_weapons) );\n\tmemset( cg_items, 0, sizeof(cg_items) );\n\n\tcg.clientNum = clientNum;\n\n\tcgs.processedSnapshotNum = serverMessageNum;\n\tcgs.serverCommandSequence = serverCommandSequence;\n\n\t// load a few needed things before we do any screen updates\n\tcgs.media.charsetShader\t\t= trap_R_RegisterShader( \"gfx/2d/bigchars\" );\n\tcgs.media.whiteShader\t\t= trap_R_RegisterShader( \"white\" );\n\tcgs.media.charsetProp\t\t= trap_R_RegisterShaderNoMip( \"menu/art/font1_prop.tga\" );\n\tcgs.media.charsetPropGlow\t= trap_R_RegisterShaderNoMip( \"menu/art/font1_prop_glo.tga\" );\n\tcgs.media.charsetPropB\t\t= trap_R_RegisterShaderNoMip( \"menu/art/font2_prop.tga\" );\n\n\tCG_RegisterCvars();\n\n\tCG_InitConsoleCommands();\n\n\tcg.weaponSelect = WP_MACHINEGUN;\n\n\tcgs.redflag = cgs.blueflag = -1; // For compatibily, default to unset for\n\tcgs.flagStatus = -1;\n\t// old servers\n\n\t// get the rendering configuration from the client system\n\ttrap_GetGlconfig( &cgs.glconfig );\n\tcgs.screenXScale = cgs.glconfig.vidWidth / 640.0;\n\tcgs.screenYScale = cgs.glconfig.vidHeight / 480.0;\n\n\t// get the gamestate from the client system\n\ttrap_GetGameState( &cgs.gameState );\n\n\t// check version\n\ts = CG_ConfigString( CS_GAME_VERSION );\n\tif ( strcmp( s, GAME_VERSION ) ) {\n\t\tCG_Error( \"Client/Server game mismatch: %s/%s\", GAME_VERSION, s );\n\t}\n\n\ts = CG_ConfigString( CS_LEVEL_START_TIME );\n\tcgs.levelStartTime = atoi( s );\n\n\tCG_ParseServerinfo();\n\n\t// load the new map\n\tCG_LoadingString( \"collision map\" );\n\n\ttrap_CM_LoadMap( cgs.mapname );\n\n\tcg.loading = qtrue;\t\t// force players to load instead of defer\n\n\tCG_LoadingString( \"sounds\" );\n\n\tCG_RegisterSounds();\n\n\tCG_LoadingString( \"graphics\" );\n\n\tCG_RegisterGraphics();\n\n\tCG_LoadingString( \"clients\" );\n\n\tCG_RegisterClients();\t\t// if low on memory, some clients will be deferred\n\n\tcg.loading = qfalse;\t// future players will be deferred\n\n\tCG_InitLocalEntities();\n\n\tCG_InitMarkPolys();\n\n\t// remove the last loading update\n\tcg.infoScreenText[0] = 0;\n\n\t// Make sure we have update values (scores)\n\tCG_SetConfigValues();\n\n\tCG_StartMusic();\n\n\tCG_LoadingString( \"\" );\n\n\tCG_ShaderStateChanged();\n\n\ttrap_S_ClearLoopingSounds( qtrue );\n}\n\n/*\n=================\nCG_Shutdown\n\nCalled before every level change or subsystem restart\n=================\n*/\nvoid CG_Shutdown( void ) {\n\t// some mods may need to do cleanup work here,\n\t// like closing files or archiving session data\n}\n\n\n/*\n==================\nCG_EventHandling\n==================\n type 0 - no event handling\n      1 - team menu\n      2 - hud editor\n\n*/\nvoid CG_EventHandling(int type) {\n}\n\n\n\nvoid CG_KeyEvent(int key, qboolean down) {\n}\n\nvoid CG_MouseEvent(int x, int y) {\n}\n"
  },
  {
    "path": "src/cgame/cg_marks.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n// cg_marks.c -- wall marks\n\n#include \"cg_local.h\"\n\n/*\n===================================================================\n\nMARK POLYS\n\n===================================================================\n*/\n\n\nmarkPoly_t\tcg_activeMarkPolys;\t\t\t// double linked list\nmarkPoly_t\t*cg_freeMarkPolys;\t\t\t// single linked list\nmarkPoly_t\tcg_markPolys[MAX_MARK_POLYS];\nstatic\t\tint\tmarkTotal;\n\n/*\n===================\nCG_InitMarkPolys\n\nThis is called at startup and for tournement restarts\n===================\n*/\nvoid\tCG_InitMarkPolys( void ) {\n\tint\t\ti;\n\n\tmemset( cg_markPolys, 0, sizeof(cg_markPolys) );\n\n\tcg_activeMarkPolys.nextMark = &cg_activeMarkPolys;\n\tcg_activeMarkPolys.prevMark = &cg_activeMarkPolys;\n\tcg_freeMarkPolys = cg_markPolys;\n\tfor ( i = 0 ; i < MAX_MARK_POLYS - 1 ; i++ ) {\n\t\tcg_markPolys[i].nextMark = &cg_markPolys[i+1];\n\t}\n}\n\n\n/*\n==================\nCG_FreeMarkPoly\n==================\n*/\nvoid CG_FreeMarkPoly( markPoly_t *le ) {\n\tif ( !le->prevMark ) {\n\t\tCG_Error( \"CG_FreeLocalEntity: not active\" );\n\t}\n\n\t// remove from the doubly linked active list\n\tle->prevMark->nextMark = le->nextMark;\n\tle->nextMark->prevMark = le->prevMark;\n\n\t// the free list is only singly linked\n\tle->nextMark = cg_freeMarkPolys;\n\tcg_freeMarkPolys = le;\n}\n\n/*\n===================\nCG_AllocMark\n\nWill allways succeed, even if it requires freeing an old active mark\n===================\n*/\nmarkPoly_t\t*CG_AllocMark( void ) {\n\tmarkPoly_t\t*le;\n\tint time;\n\n\tif ( !cg_freeMarkPolys ) {\n\t\t// no free entities, so free the one at the end of the chain\n\t\t// remove the oldest active entity\n\t\ttime = cg_activeMarkPolys.prevMark->time;\n\t\twhile (cg_activeMarkPolys.prevMark && time == cg_activeMarkPolys.prevMark->time) {\n\t\t\tCG_FreeMarkPoly( cg_activeMarkPolys.prevMark );\n\t\t}\n\t}\n\n\tle = cg_freeMarkPolys;\n\tcg_freeMarkPolys = cg_freeMarkPolys->nextMark;\n\n\tmemset( le, 0, sizeof( *le ) );\n\n\t// link into the active list\n\tle->nextMark = cg_activeMarkPolys.nextMark;\n\tle->prevMark = &cg_activeMarkPolys;\n\tcg_activeMarkPolys.nextMark->prevMark = le;\n\tcg_activeMarkPolys.nextMark = le;\n\treturn le;\n}\n\n\n\n/*\n=================\nCG_ImpactMark\n\norigin should be a point within a unit of the plane\ndir should be the plane normal\n\ntemporary marks will not be stored or randomly oriented, but immediately\npassed to the renderer.\n=================\n*/\n#define\tMAX_MARK_FRAGMENTS\t128\n#define\tMAX_MARK_POINTS\t\t384\n\nvoid CG_ImpactMark( qhandle_t markShader, const vec3_t origin, const vec3_t dir, \n\t\t\t\t   float orientation, float red, float green, float blue, float alpha,\n\t\t\t\t   qboolean alphaFade, float radius, qboolean temporary ) {\n\tvec3_t\t\t\taxis[3];\n\tfloat\t\t\ttexCoordScale;\n\tvec3_t\t\t\toriginalPoints[4];\n\tbyte\t\t\tcolors[4];\n\tint\t\t\t\ti, j;\n\tint\t\t\t\tnumFragments;\n\tmarkFragment_t\tmarkFragments[MAX_MARK_FRAGMENTS], *mf;\n\tvec3_t\t\t\tmarkPoints[MAX_MARK_POINTS];\n\tvec3_t\t\t\tprojection;\n\n\tif ( !cg_addMarks.integer ) {\n\t\treturn;\n\t}\n\n\tif ( radius <= 0 ) {\n\t\tCG_Error( \"CG_ImpactMark called with <= 0 radius\" );\n\t}\n\n\t//if ( markTotal >= MAX_MARK_POLYS ) {\n\t//\treturn;\n\t//}\n\n\t// create the texture axis\n\tVectorNormalize2( dir, axis[0] );\n\tPerpendicularVector( axis[1], axis[0] );\n\tRotatePointAroundVector( axis[2], axis[0], axis[1], orientation );\n\tCrossProduct( axis[0], axis[2], axis[1] );\n\n\ttexCoordScale = 0.5 * 1.0 / radius;\n\n\t// create the full polygon\n\tfor ( i = 0 ; i < 3 ; i++ ) {\n\t\toriginalPoints[0][i] = origin[i] - radius * axis[1][i] - radius * axis[2][i];\n\t\toriginalPoints[1][i] = origin[i] + radius * axis[1][i] - radius * axis[2][i];\n\t\toriginalPoints[2][i] = origin[i] + radius * axis[1][i] + radius * axis[2][i];\n\t\toriginalPoints[3][i] = origin[i] - radius * axis[1][i] + radius * axis[2][i];\n\t}\n\n\t// get the fragments\n\tVectorScale( dir, -20, projection );\n\tnumFragments = trap_CM_MarkFragments( 4, (void *)originalPoints,\n\t\t\t\t\tprojection, MAX_MARK_POINTS, markPoints[0],\n\t\t\t\t\tMAX_MARK_FRAGMENTS, markFragments );\n\n\tcolors[0] = red * 255;\n\tcolors[1] = green * 255;\n\tcolors[2] = blue * 255;\n\tcolors[3] = alpha * 255;\n\n\tfor ( i = 0, mf = markFragments ; i < numFragments ; i++, mf++ ) {\n\t\tpolyVert_t\t*v;\n\t\tpolyVert_t\tverts[MAX_VERTS_ON_POLY];\n\t\tmarkPoly_t\t*mark;\n\n\t\t// we have an upper limit on the complexity of polygons\n\t\t// that we store persistantly\n\t\tif ( mf->numPoints > MAX_VERTS_ON_POLY ) {\n\t\t\tmf->numPoints = MAX_VERTS_ON_POLY;\n\t\t}\n\t\tfor ( j = 0, v = verts ; j < mf->numPoints ; j++, v++ ) {\n\t\t\tvec3_t\t\tdelta;\n\n\t\t\tVectorCopy( markPoints[mf->firstPoint + j], v->xyz );\n\n\t\t\tVectorSubtract( v->xyz, origin, delta );\n\t\t\tv->st[0] = 0.5 + DotProduct( delta, axis[1] ) * texCoordScale;\n\t\t\tv->st[1] = 0.5 + DotProduct( delta, axis[2] ) * texCoordScale;\n\t\t\t*(int *)v->modulate = *(int *)colors;\n\t\t}\n\n\t\t// if it is a temporary (shadow) mark, add it immediately and forget about it\n\t\tif ( temporary ) {\n\t\t\ttrap_R_AddPolyToScene( markShader, mf->numPoints, verts );\n\t\t\tcontinue;\n\t\t}\n\n\t\t// otherwise save it persistantly\n\t\tmark = CG_AllocMark();\n\t\tmark->time = cg.time;\n\t\tmark->alphaFade = alphaFade;\n\t\tmark->markShader = markShader;\n\t\tmark->poly.numVerts = mf->numPoints;\n\t\tmark->color[0] = red;\n\t\tmark->color[1] = green;\n\t\tmark->color[2] = blue;\n\t\tmark->color[3] = alpha;\n\t\tmemcpy( mark->verts, verts, mf->numPoints * sizeof( verts[0] ) );\n\t\tmarkTotal++;\n\t}\n}\n\n\n/*\n===============\nCG_AddMarks\n===============\n*/\n#define\tMARK_TOTAL_TIME\t\t10000\n#define\tMARK_FADE_TIME\t\t1000\n\nvoid CG_AddMarks( void ) {\n\tint\t\t\tj;\n\tmarkPoly_t\t*mp, *next;\n\tint\t\t\tt;\n\tint\t\t\tfade;\n\n\tif ( !cg_addMarks.integer ) {\n\t\treturn;\n\t}\n\n\tmp = cg_activeMarkPolys.nextMark;\n\tfor ( ; mp != &cg_activeMarkPolys ; mp = next ) {\n\t\t// grab next now, so if the local entity is freed we\n\t\t// still have it\n\t\tnext = mp->nextMark;\n\n\t\t// see if it is time to completely remove it\n\t\tif ( cg.time > mp->time + MARK_TOTAL_TIME ) {\n\t\t\tCG_FreeMarkPoly( mp );\n\t\t\tcontinue;\n\t\t}\n\n\t\t// fade out the energy bursts\n\t\tif ( mp->markShader == cgs.media.energyMarkShader ) {\n\n\t\t\tfade = 450 - 450 * ( (cg.time - mp->time ) / 3000.0 );\n\t\t\tif ( fade < 255 ) {\n\t\t\t\tif ( fade < 0 ) {\n\t\t\t\t\tfade = 0;\n\t\t\t\t}\n\t\t\t\tif ( mp->verts[0].modulate[0] != 0 ) {\n\t\t\t\t\tfor ( j = 0 ; j < mp->poly.numVerts ; j++ ) {\n\t\t\t\t\t\tmp->verts[j].modulate[0] = mp->color[0] * fade;\n\t\t\t\t\t\tmp->verts[j].modulate[1] = mp->color[1] * fade;\n\t\t\t\t\t\tmp->verts[j].modulate[2] = mp->color[2] * fade;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// fade all marks out with time\n\t\tt = mp->time + MARK_TOTAL_TIME - cg.time;\n\t\tif ( t < MARK_FADE_TIME ) {\n\t\t\tfade = 255 * t / MARK_FADE_TIME;\n\t\t\tif ( mp->alphaFade ) {\n\t\t\t\tfor ( j = 0 ; j < mp->poly.numVerts ; j++ ) {\n\t\t\t\t\tmp->verts[j].modulate[3] = fade;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor ( j = 0 ; j < mp->poly.numVerts ; j++ ) {\n\t\t\t\t\tmp->verts[j].modulate[0] = mp->color[0] * fade;\n\t\t\t\t\tmp->verts[j].modulate[1] = mp->color[1] * fade;\n\t\t\t\t\tmp->verts[j].modulate[2] = mp->color[2] * fade;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\n\t\ttrap_R_AddPolyToScene( mp->markShader, mp->poly.numVerts, mp->verts );\n\t}\n}\n\n// cg_particles.c  \n\n#define BLOODRED\t2\n#define EMISIVEFADE\t3\n#define GREY75\t\t4\n\ntypedef struct particle_s\n{\n\tstruct particle_s\t*next;\n\n\tfloat\t\ttime;\n\tfloat\t\tendtime;\n\n\tvec3_t\t\torg;\n\tvec3_t\t\tvel;\n\tvec3_t\t\taccel;\n\tint\t\t\tcolor;\n\tfloat\t\tcolorvel;\n\tfloat\t\talpha;\n\tfloat\t\talphavel;\n\tint\t\t\ttype;\n\tqhandle_t\tpshader;\n\t\n\tfloat\t\theight;\n\tfloat\t\twidth;\n\t\t\t\t\n\tfloat\t\tendheight;\n\tfloat\t\tendwidth;\n\t\n\tfloat\t\tstart;\n\tfloat\t\tend;\n\n\tfloat\t\tstartfade;\n\tqboolean\trotate;\n\tint\t\t\tsnum;\n\t\n\tqboolean\tlink;\n\n\t// Ridah\n\tint\t\t\tshaderAnim;\n\tint\t\t\troll;\n\n\tint\t\t\taccumroll;\n\n} cparticle_t;\n\ntypedef enum\n{\n\tP_NONE,\n\tP_WEATHER,\n\tP_FLAT,\n\tP_SMOKE,\n\tP_ROTATE,\n\tP_WEATHER_TURBULENT,\n\tP_ANIM,\t// Ridah\n\tP_BAT,\n\tP_BLEED,\n\tP_FLAT_SCALEUP,\n\tP_FLAT_SCALEUP_FADE,\n\tP_WEATHER_FLURRY,\n\tP_SMOKE_IMPACT,\n\tP_BUBBLE,\n\tP_BUBBLE_TURBULENT,\n\tP_SPRITE\n} particle_type_t;\n\n#define\tMAX_SHADER_ANIMS\t\t32\n#define\tMAX_SHADER_ANIM_FRAMES\t64\n\nstatic char *shaderAnimNames[MAX_SHADER_ANIMS] = {\n\t\"explode1\",\n\tNULL\n};\nstatic qhandle_t shaderAnims[MAX_SHADER_ANIMS][MAX_SHADER_ANIM_FRAMES];\nstatic int\tshaderAnimCounts[MAX_SHADER_ANIMS] = {\n\t23\n};\nstatic float\tshaderAnimSTRatio[MAX_SHADER_ANIMS] = {\n\t1.0f\n};\nstatic int\tnumShaderAnims;\n// done.\n\n#define\t\tPARTICLE_GRAVITY\t40\n#define\t\tMAX_PARTICLES\t1024\n\ncparticle_t\t*active_particles, *free_particles;\ncparticle_t\tparticles[MAX_PARTICLES];\nint\t\tcl_numparticles = MAX_PARTICLES;\n\nqboolean\t\tinitparticles = qfalse;\nvec3_t\t\t\tpvforward, pvright, pvup;\nvec3_t\t\t\trforward, rright, rup;\n\nfloat\t\t\toldtime;\n\n/*\n===============\nCL_ClearParticles\n===============\n*/\nvoid CG_ClearParticles (void)\n{\n\tint\t\ti;\n\n\tmemset( particles, 0, sizeof(particles) );\n\n\tfree_particles = &particles[0];\n\tactive_particles = NULL;\n\n\tfor (i=0 ;i<cl_numparticles ; i++)\n\t{\n\t\tparticles[i].next = &particles[i+1];\n\t\tparticles[i].type = 0;\n\t}\n\tparticles[cl_numparticles-1].next = NULL;\n\n\toldtime = cg.time;\n\n\t// Ridah, init the shaderAnims\n\tfor (i=0; shaderAnimNames[i]; i++) {\n\t\tint j;\n\n\t\tfor (j=0; j<shaderAnimCounts[i]; j++) {\n\t\t\tshaderAnims[i][j] = trap_R_RegisterShader( va(\"%s%i\", shaderAnimNames[i], j+1) );\n\t\t}\n\t}\n\tnumShaderAnims = i;\n\t// done.\n\n\tinitparticles = qtrue;\n}\n\n\n/*\n=====================\nCG_AddParticleToScene\n=====================\n*/\nvoid CG_AddParticleToScene (cparticle_t *p, vec3_t org, float alpha)\n{\n\n\tvec3_t\t\tpoint;\n\tpolyVert_t\tverts[4];\n\tfloat\t\twidth;\n\tfloat\t\theight;\n\tfloat\t\ttime, time2;\n\tfloat\t\tratio;\n\tfloat\t\tinvratio;\n\tvec3_t\t\tcolor;\n\tpolyVert_t\tTRIverts[3];\n\tvec3_t\t\trright2, rup2;\n\n\tif (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT || p->type == P_WEATHER_FLURRY\n\t\t|| p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT)\n\t{// create a front facing polygon\n\t\t\t\n\t\tif (p->type != P_WEATHER_FLURRY)\n\t\t{\n\t\t\tif (p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT)\n\t\t\t{\n\t\t\t\tif (org[2] > p->end)\t\t\t\n\t\t\t\t{\t\n\t\t\t\t\tp->time = cg.time;\t\n\t\t\t\t\tVectorCopy (org, p->org); // Ridah, fixes rare snow flakes that flicker on the ground\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\tp->org[2] = ( p->start + crandom () * 4 );\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\tif (p->type == P_BUBBLE_TURBULENT)\n\t\t\t\t\t{\n\t\t\t\t\t\tp->vel[0] = crandom() * 4;\n\t\t\t\t\t\tp->vel[1] = crandom() * 4;\n\t\t\t\t\t}\n\t\t\t\t\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (org[2] < p->end)\t\t\t\n\t\t\t\t{\t\n\t\t\t\t\tp->time = cg.time;\t\n\t\t\t\t\tVectorCopy (org, p->org); // Ridah, fixes rare snow flakes that flicker on the ground\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\twhile (p->org[2] < p->end) \n\t\t\t\t\t{\n\t\t\t\t\t\tp->org[2] += (p->start - p->end); \n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\tif (p->type == P_WEATHER_TURBULENT)\n\t\t\t\t\t{\n\t\t\t\t\t\tp->vel[0] = crandom() * 16;\n\t\t\t\t\t\tp->vel[1] = crandom() * 16;\n\t\t\t\t\t}\n\t\t\t\t\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\n\t\t\t// Rafael snow pvs check\n\t\t\tif (!p->link)\n\t\t\t\treturn;\n\n\t\t\tp->alpha = 1;\n\t\t}\n\t\t\n\t\t// Ridah, had to do this or MAX_POLYS is being exceeded in village1.bsp\n\t\tif (Distance( cg.snap->ps.origin, org ) > 1024) {\n\t\t\treturn;\n\t\t}\n\t\t// done.\n\t\n\t\tif (p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT)\n\t\t{\n\t\t\tVectorMA (org, -p->height, pvup, point);\t\n\t\t\tVectorMA (point, -p->width, pvright, point);\t\n\t\t\tVectorCopy (point, verts[0].xyz);\t\n\t\t\tverts[0].st[0] = 0;\t\n\t\t\tverts[0].st[1] = 0;\t\n\t\t\tverts[0].modulate[0] = 255;\t\n\t\t\tverts[0].modulate[1] = 255;\t\n\t\t\tverts[0].modulate[2] = 255;\t\n\t\t\tverts[0].modulate[3] = 255 * p->alpha;\t\n\n\t\t\tVectorMA (org, -p->height, pvup, point);\t\n\t\t\tVectorMA (point, p->width, pvright, point);\t\n\t\t\tVectorCopy (point, verts[1].xyz);\t\n\t\t\tverts[1].st[0] = 0;\t\n\t\t\tverts[1].st[1] = 1;\t\n\t\t\tverts[1].modulate[0] = 255;\t\n\t\t\tverts[1].modulate[1] = 255;\t\n\t\t\tverts[1].modulate[2] = 255;\t\n\t\t\tverts[1].modulate[3] = 255 * p->alpha;\t\n\n\t\t\tVectorMA (org, p->height, pvup, point);\t\n\t\t\tVectorMA (point, p->width, pvright, point);\t\n\t\t\tVectorCopy (point, verts[2].xyz);\t\n\t\t\tverts[2].st[0] = 1;\t\n\t\t\tverts[2].st[1] = 1;\t\n\t\t\tverts[2].modulate[0] = 255;\t\n\t\t\tverts[2].modulate[1] = 255;\t\n\t\t\tverts[2].modulate[2] = 255;\t\n\t\t\tverts[2].modulate[3] = 255 * p->alpha;\t\n\n\t\t\tVectorMA (org, p->height, pvup, point);\t\n\t\t\tVectorMA (point, -p->width, pvright, point);\t\n\t\t\tVectorCopy (point, verts[3].xyz);\t\n\t\t\tverts[3].st[0] = 1;\t\n\t\t\tverts[3].st[1] = 0;\t\n\t\t\tverts[3].modulate[0] = 255;\t\n\t\t\tverts[3].modulate[1] = 255;\t\n\t\t\tverts[3].modulate[2] = 255;\t\n\t\t\tverts[3].modulate[3] = 255 * p->alpha;\t\n\t\t}\n\t\telse\n\t\t{\n\t\t\tVectorMA (org, -p->height, pvup, point);\t\n\t\t\tVectorMA (point, -p->width, pvright, point);\t\n\t\t\tVectorCopy( point, TRIverts[0].xyz );\n\t\t\tTRIverts[0].st[0] = 1;\n\t\t\tTRIverts[0].st[1] = 0;\n\t\t\tTRIverts[0].modulate[0] = 255;\n\t\t\tTRIverts[0].modulate[1] = 255;\n\t\t\tTRIverts[0].modulate[2] = 255;\n\t\t\tTRIverts[0].modulate[3] = 255 * p->alpha;\t\n\n\t\t\tVectorMA (org, p->height, pvup, point);\t\n\t\t\tVectorMA (point, -p->width, pvright, point);\t\n\t\t\tVectorCopy (point, TRIverts[1].xyz);\t\n\t\t\tTRIverts[1].st[0] = 0;\n\t\t\tTRIverts[1].st[1] = 0;\n\t\t\tTRIverts[1].modulate[0] = 255;\n\t\t\tTRIverts[1].modulate[1] = 255;\n\t\t\tTRIverts[1].modulate[2] = 255;\n\t\t\tTRIverts[1].modulate[3] = 255 * p->alpha;\t\n\n\t\t\tVectorMA (org, p->height, pvup, point);\t\n\t\t\tVectorMA (point, p->width, pvright, point);\t\n\t\t\tVectorCopy (point, TRIverts[2].xyz);\t\n\t\t\tTRIverts[2].st[0] = 0;\n\t\t\tTRIverts[2].st[1] = 1;\n\t\t\tTRIverts[2].modulate[0] = 255;\n\t\t\tTRIverts[2].modulate[1] = 255;\n\t\t\tTRIverts[2].modulate[2] = 255;\n\t\t\tTRIverts[2].modulate[3] = 255 * p->alpha;\t\n\t\t}\n\t\n\t}\n\telse if (p->type == P_SPRITE)\n\t{\n\t\tvec3_t\trr, ru;\n\t\tvec3_t\trotate_ang;\n\n\t\tVectorSet (color, 1.0, 1.0, 0.5);\n\t\ttime = cg.time - p->time;\n\t\ttime2 = p->endtime - p->time;\n\t\tratio = time / time2;\n\n\t\twidth = p->width + ( ratio * ( p->endwidth - p->width) );\n\t\theight = p->height + ( ratio * ( p->endheight - p->height) );\n\n\t\tif (p->roll) {\n\t\t\tvectoangles( cg.refdef.viewaxis[0], rotate_ang );\n\t\t\trotate_ang[ROLL] += p->roll;\n\t\t\tAngleVectors ( rotate_ang, NULL, rr, ru);\n\t\t}\n\n\t\tif (p->roll) {\n\t\t\tVectorMA (org, -height, ru, point);\t\n\t\t\tVectorMA (point, -width, rr, point);\t\n\t\t} else {\n\t\t\tVectorMA (org, -height, pvup, point);\t\n\t\t\tVectorMA (point, -width, pvright, point);\t\n\t\t}\n\t\tVectorCopy (point, verts[0].xyz);\t\n\t\tverts[0].st[0] = 0;\t\n\t\tverts[0].st[1] = 0;\t\n\t\tverts[0].modulate[0] = 255;\t\n\t\tverts[0].modulate[1] = 255;\t\n\t\tverts[0].modulate[2] = 255;\t\n\t\tverts[0].modulate[3] = 255;\n\n\t\tif (p->roll) {\n\t\t\tVectorMA (point, 2*height, ru, point);\t\n\t\t} else {\n\t\t\tVectorMA (point, 2*height, pvup, point);\t\n\t\t}\n\t\tVectorCopy (point, verts[1].xyz);\t\n\t\tverts[1].st[0] = 0;\t\n\t\tverts[1].st[1] = 1;\t\n\t\tverts[1].modulate[0] = 255;\t\n\t\tverts[1].modulate[1] = 255;\t\n\t\tverts[1].modulate[2] = 255;\t\n\t\tverts[1].modulate[3] = 255;\t\n\n\t\tif (p->roll) {\n\t\t\tVectorMA (point, 2*width, rr, point);\t\n\t\t} else {\n\t\t\tVectorMA (point, 2*width, pvright, point);\t\n\t\t}\n\t\tVectorCopy (point, verts[2].xyz);\t\n\t\tverts[2].st[0] = 1;\t\n\t\tverts[2].st[1] = 1;\t\n\t\tverts[2].modulate[0] = 255;\t\n\t\tverts[2].modulate[1] = 255;\t\n\t\tverts[2].modulate[2] = 255;\t\n\t\tverts[2].modulate[3] = 255;\t\n\n\t\tif (p->roll) {\n\t\t\tVectorMA (point, -2*height, ru, point);\t\n\t\t} else {\n\t\t\tVectorMA (point, -2*height, pvup, point);\t\n\t\t}\n\t\tVectorCopy (point, verts[3].xyz);\t\n\t\tverts[3].st[0] = 1;\t\n\t\tverts[3].st[1] = 0;\t\n\t\tverts[3].modulate[0] = 255;\t\n\t\tverts[3].modulate[1] = 255;\t\n\t\tverts[3].modulate[2] = 255;\t\n\t\tverts[3].modulate[3] = 255;\t\n\t}\n\telse if (p->type == P_SMOKE || p->type == P_SMOKE_IMPACT)\n\t{// create a front rotating facing polygon\n\n\t\tif ( p->type == P_SMOKE_IMPACT && Distance( cg.snap->ps.origin, org ) > 1024) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (p->color == BLOODRED)\n\t\t\tVectorSet (color, 0.22f, 0.0f, 0.0f);\n\t\telse if (p->color == GREY75)\n\t\t{\n\t\t\tfloat\tlen;\n\t\t\tfloat\tgreyit;\n\t\t\tfloat\tval;\n\t\t\tlen = Distance (cg.snap->ps.origin, org);\n\t\t\tif (!len)\n\t\t\t\tlen = 1;\n\n\t\t\tval = 4096/len;\n\t\t\tgreyit = 0.25 * val;\n\t\t\tif (greyit > 0.5)\n\t\t\t\tgreyit = 0.5;\n\n\t\t\tVectorSet (color, greyit, greyit, greyit);\n\t\t}\n\t\telse\n\t\t\tVectorSet (color, 1.0, 1.0, 1.0);\n\n\t\ttime = cg.time - p->time;\n\t\ttime2 = p->endtime - p->time;\n\t\tratio = time / time2;\n\t\t\n\t\tif (cg.time > p->startfade)\n\t\t{\n\t\t\tinvratio = 1 - ( (cg.time - p->startfade) / (p->endtime - p->startfade) );\n\n\t\t\tif (p->color == EMISIVEFADE)\n\t\t\t{\n\t\t\t\tfloat fval;\n\t\t\t\tfval = (invratio * invratio);\n\t\t\t\tif (fval < 0)\n\t\t\t\t\tfval = 0;\n\t\t\t\tVectorSet (color, fval , fval , fval );\n\t\t\t}\n\t\t\tinvratio *= p->alpha;\n\t\t}\n\t\telse \n\t\t\tinvratio = 1 * p->alpha;\n\n\t\tif (invratio > 1)\n\t\t\tinvratio = 1;\n\t\n\t\twidth = p->width + ( ratio * ( p->endwidth - p->width) );\n\t\theight = p->height + ( ratio * ( p->endheight - p->height) );\n\n\t\tif (p->type != P_SMOKE_IMPACT)\n\t\t{\n\t\t\tvec3_t temp;\n\n\t\t\tvectoangles (rforward, temp);\n\t\t\tp->accumroll += p->roll;\n\t\t\ttemp[ROLL] += p->accumroll * 0.1;\n\t\t\tAngleVectors ( temp, NULL, rright2, rup2);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tVectorCopy (rright, rright2);\n\t\t\tVectorCopy (rup, rup2);\n\t\t}\n\t\t\n\t\tif (p->rotate)\n\t\t{\n\t\t\tVectorMA (org, -height, rup2, point);\t\n\t\t\tVectorMA (point, -width, rright2, point);\t\n\t\t}\n\t\telse\n\t\t{\n\t\t\tVectorMA (org, -p->height, pvup, point);\t\n\t\t\tVectorMA (point, -p->width, pvright, point);\t\n\t\t}\n\t\tVectorCopy (point, verts[0].xyz);\t\n\t\tverts[0].st[0] = 0;\t\n\t\tverts[0].st[1] = 0;\t\n\t\tverts[0].modulate[0] = 255 * color[0];\t\n\t\tverts[0].modulate[1] = 255 * color[1];\t\n\t\tverts[0].modulate[2] = 255 * color[2];\t\n\t\tverts[0].modulate[3] = 255 * invratio;\t\n\n\t\tif (p->rotate)\n\t\t{\n\t\t\tVectorMA (org, -height, rup2, point);\t\n\t\t\tVectorMA (point, width, rright2, point);\t\n\t\t}\n\t\telse\n\t\t{\n\t\t\tVectorMA (org, -p->height, pvup, point);\t\n\t\t\tVectorMA (point, p->width, pvright, point);\t\n\t\t}\n\t\tVectorCopy (point, verts[1].xyz);\t\n\t\tverts[1].st[0] = 0;\t\n\t\tverts[1].st[1] = 1;\t\n\t\tverts[1].modulate[0] = 255 * color[0];\t\n\t\tverts[1].modulate[1] = 255 * color[1];\t\n\t\tverts[1].modulate[2] = 255 * color[2];\t\n\t\tverts[1].modulate[3] = 255 * invratio;\t\n\n\t\tif (p->rotate)\n\t\t{\n\t\t\tVectorMA (org, height, rup2, point);\t\n\t\t\tVectorMA (point, width, rright2, point);\t\n\t\t}\n\t\telse\n\t\t{\n\t\t\tVectorMA (org, p->height, pvup, point);\t\n\t\t\tVectorMA (point, p->width, pvright, point);\t\n\t\t}\n\t\tVectorCopy (point, verts[2].xyz);\t\n\t\tverts[2].st[0] = 1;\t\n\t\tverts[2].st[1] = 1;\t\n\t\tverts[2].modulate[0] = 255 * color[0];\t\n\t\tverts[2].modulate[1] = 255 * color[1];\t\n\t\tverts[2].modulate[2] = 255 * color[2];\t\n\t\tverts[2].modulate[3] = 255 * invratio;\t\n\n\t\tif (p->rotate)\n\t\t{\n\t\t\tVectorMA (org, height, rup2, point);\t\n\t\t\tVectorMA (point, -width, rright2, point);\t\n\t\t}\n\t\telse\n\t\t{\n\t\t\tVectorMA (org, p->height, pvup, point);\t\n\t\t\tVectorMA (point, -p->width, pvright, point);\t\n\t\t}\n\t\tVectorCopy (point, verts[3].xyz);\t\n\t\tverts[3].st[0] = 1;\t\n\t\tverts[3].st[1] = 0;\t\n\t\tverts[3].modulate[0] = 255 * color[0];\t\n\t\tverts[3].modulate[1] = 255 * color[1];\t\n\t\tverts[3].modulate[2] = 255 * color[2];\t\n\t\tverts[3].modulate[3] = 255  * invratio;\t\n\t\t\n\t}\n\telse if (p->type == P_BLEED)\n\t{\n\t\tvec3_t\trr, ru;\n\t\tvec3_t\trotate_ang;\n\t\tfloat\talpha;\n\n\t\talpha = p->alpha;\n\t\t\n\t\tif (p->roll) \n\t\t{\n\t\t\tvectoangles( cg.refdef.viewaxis[0], rotate_ang );\n\t\t\trotate_ang[ROLL] += p->roll;\n\t\t\tAngleVectors ( rotate_ang, NULL, rr, ru);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tVectorCopy (pvup, ru);\n\t\t\tVectorCopy (pvright, rr);\n\t\t}\n\n\t\tVectorMA (org, -p->height, ru, point);\t\n\t\tVectorMA (point, -p->width, rr, point);\t\n\t\tVectorCopy (point, verts[0].xyz);\t\n\t\tverts[0].st[0] = 0;\t\n\t\tverts[0].st[1] = 0;\t\n\t\tverts[0].modulate[0] = 111;\t\n\t\tverts[0].modulate[1] = 19;\t\n\t\tverts[0].modulate[2] = 9;\t\n\t\tverts[0].modulate[3] = 255 * alpha;\t\n\n\t\tVectorMA (org, -p->height, ru, point);\t\n\t\tVectorMA (point, p->width, rr, point);\t\n\t\tVectorCopy (point, verts[1].xyz);\t\n\t\tverts[1].st[0] = 0;\t\n\t\tverts[1].st[1] = 1;\t\n\t\tverts[1].modulate[0] = 111;\t\n\t\tverts[1].modulate[1] = 19;\t\n\t\tverts[1].modulate[2] = 9;\t\n\t\tverts[1].modulate[3] = 255 * alpha;\t\n\n\t\tVectorMA (org, p->height, ru, point);\t\n\t\tVectorMA (point, p->width, rr, point);\t\n\t\tVectorCopy (point, verts[2].xyz);\t\n\t\tverts[2].st[0] = 1;\t\n\t\tverts[2].st[1] = 1;\t\n\t\tverts[2].modulate[0] = 111;\t\n\t\tverts[2].modulate[1] = 19;\t\n\t\tverts[2].modulate[2] = 9;\t\n\t\tverts[2].modulate[3] = 255 * alpha;\t\n\n\t\tVectorMA (org, p->height, ru, point);\t\n\t\tVectorMA (point, -p->width, rr, point);\t\n\t\tVectorCopy (point, verts[3].xyz);\t\n\t\tverts[3].st[0] = 1;\t\n\t\tverts[3].st[1] = 0;\t\n\t\tverts[3].modulate[0] = 111;\t\n\t\tverts[3].modulate[1] = 19;\t\n\t\tverts[3].modulate[2] = 9;\t\n\t\tverts[3].modulate[3] = 255 * alpha;\t\n\n\t}\n\telse if (p->type == P_FLAT_SCALEUP)\n\t{\n\t\tfloat width, height;\n\t\tfloat sinR, cosR;\n\n\t\tif (p->color == BLOODRED)\n\t\t\tVectorSet (color, 1, 1, 1);\n\t\telse\n\t\t\tVectorSet (color, 0.5, 0.5, 0.5);\n\t\t\n\t\ttime = cg.time - p->time;\n\t\ttime2 = p->endtime - p->time;\n\t\tratio = time / time2;\n\n\t\twidth = p->width + ( ratio * ( p->endwidth - p->width) );\n\t\theight = p->height + ( ratio * ( p->endheight - p->height) );\n\n\t\tif (width > p->endwidth)\n\t\t\twidth = p->endwidth;\n\n\t\tif (height > p->endheight)\n\t\t\theight = p->endheight;\n\n\t\tsinR = height * sin(DEG2RAD(p->roll)) * sqrt(2);\n\t\tcosR = width * cos(DEG2RAD(p->roll)) * sqrt(2);\n\n\t\tVectorCopy (org, verts[0].xyz);\t\n\t\tverts[0].xyz[0] -= sinR;\n\t\tverts[0].xyz[1] -= cosR;\n\t\tverts[0].st[0] = 0;\t\n\t\tverts[0].st[1] = 0;\t\n\t\tverts[0].modulate[0] = 255 * color[0];\t\n\t\tverts[0].modulate[1] = 255 * color[1];\t\n\t\tverts[0].modulate[2] = 255 * color[2];\t\n\t\tverts[0].modulate[3] = 255;\t\n\n\t\tVectorCopy (org, verts[1].xyz);\t\n\t\tverts[1].xyz[0] -= cosR;\t\n\t\tverts[1].xyz[1] += sinR;\t\n\t\tverts[1].st[0] = 0;\t\n\t\tverts[1].st[1] = 1;\t\n\t\tverts[1].modulate[0] = 255 * color[0];\t\n\t\tverts[1].modulate[1] = 255 * color[1];\t\n\t\tverts[1].modulate[2] = 255 * color[2];\t\n\t\tverts[1].modulate[3] = 255;\t\n\n\t\tVectorCopy (org, verts[2].xyz);\t\n\t\tverts[2].xyz[0] += sinR;\t\n\t\tverts[2].xyz[1] += cosR;\t\n\t\tverts[2].st[0] = 1;\t\n\t\tverts[2].st[1] = 1;\t\n\t\tverts[2].modulate[0] = 255 * color[0];\t\n\t\tverts[2].modulate[1] = 255 * color[1];\t\n\t\tverts[2].modulate[2] = 255 * color[2];\t\n\t\tverts[2].modulate[3] = 255;\t\n\n\t\tVectorCopy (org, verts[3].xyz);\t\n\t\tverts[3].xyz[0] += cosR;\t\n\t\tverts[3].xyz[1] -= sinR;\t\n\t\tverts[3].st[0] = 1;\t\n\t\tverts[3].st[1] = 0;\t\n\t\tverts[3].modulate[0] = 255 * color[0];\t\n\t\tverts[3].modulate[1] = 255 * color[1];\t\n\t\tverts[3].modulate[2] = 255 * color[2];\t\n\t\tverts[3].modulate[3] = 255;\t\t\n\t}\n\telse if (p->type == P_FLAT)\n\t{\n\n\t\tVectorCopy (org, verts[0].xyz);\t\n\t\tverts[0].xyz[0] -= p->height;\t\n\t\tverts[0].xyz[1] -= p->width;\t\n\t\tverts[0].st[0] = 0;\t\n\t\tverts[0].st[1] = 0;\t\n\t\tverts[0].modulate[0] = 255;\t\n\t\tverts[0].modulate[1] = 255;\t\n\t\tverts[0].modulate[2] = 255;\t\n\t\tverts[0].modulate[3] = 255;\t\n\n\t\tVectorCopy (org, verts[1].xyz);\t\n\t\tverts[1].xyz[0] -= p->height;\t\n\t\tverts[1].xyz[1] += p->width;\t\n\t\tverts[1].st[0] = 0;\t\n\t\tverts[1].st[1] = 1;\t\n\t\tverts[1].modulate[0] = 255;\t\n\t\tverts[1].modulate[1] = 255;\t\n\t\tverts[1].modulate[2] = 255;\t\n\t\tverts[1].modulate[3] = 255;\t\n\n\t\tVectorCopy (org, verts[2].xyz);\t\n\t\tverts[2].xyz[0] += p->height;\t\n\t\tverts[2].xyz[1] += p->width;\t\n\t\tverts[2].st[0] = 1;\t\n\t\tverts[2].st[1] = 1;\t\n\t\tverts[2].modulate[0] = 255;\t\n\t\tverts[2].modulate[1] = 255;\t\n\t\tverts[2].modulate[2] = 255;\t\n\t\tverts[2].modulate[3] = 255;\t\n\n\t\tVectorCopy (org, verts[3].xyz);\t\n\t\tverts[3].xyz[0] += p->height;\t\n\t\tverts[3].xyz[1] -= p->width;\t\n\t\tverts[3].st[0] = 1;\t\n\t\tverts[3].st[1] = 0;\t\n\t\tverts[3].modulate[0] = 255;\t\n\t\tverts[3].modulate[1] = 255;\t\n\t\tverts[3].modulate[2] = 255;\t\n\t\tverts[3].modulate[3] = 255;\t\n\n\t}\n\t// Ridah\n\telse if (p->type == P_ANIM) {\n\t\tvec3_t\trr, ru;\n\t\tvec3_t\trotate_ang;\n\t\tint i, j;\n\n\t\ttime = cg.time - p->time;\n\t\ttime2 = p->endtime - p->time;\n\t\tratio = time / time2;\n\t\tif (ratio >= 1.0f) {\n\t\t\tratio = 0.9999f;\n\t\t}\n\n\t\twidth = p->width + ( ratio * ( p->endwidth - p->width) );\n\t\theight = p->height + ( ratio * ( p->endheight - p->height) );\n\n\t\t// if we are \"inside\" this sprite, don't draw\n\t\tif (Distance( cg.snap->ps.origin, org ) < width/1.5) {\n\t\t\treturn;\n\t\t}\n\n\t\ti = p->shaderAnim;\n\t\tj = (int)floor(ratio * shaderAnimCounts[p->shaderAnim]);\n\t\tp->pshader = shaderAnims[i][j];\n\n\t\tif (p->roll) {\n\t\t\tvectoangles( cg.refdef.viewaxis[0], rotate_ang );\n\t\t\trotate_ang[ROLL] += p->roll;\n\t\t\tAngleVectors ( rotate_ang, NULL, rr, ru);\n\t\t}\n\n\t\tif (p->roll) {\n\t\t\tVectorMA (org, -height, ru, point);\t\n\t\t\tVectorMA (point, -width, rr, point);\t\n\t\t} else {\n\t\t\tVectorMA (org, -height, pvup, point);\t\n\t\t\tVectorMA (point, -width, pvright, point);\t\n\t\t}\n\t\tVectorCopy (point, verts[0].xyz);\t\n\t\tverts[0].st[0] = 0;\t\n\t\tverts[0].st[1] = 0;\t\n\t\tverts[0].modulate[0] = 255;\t\n\t\tverts[0].modulate[1] = 255;\t\n\t\tverts[0].modulate[2] = 255;\t\n\t\tverts[0].modulate[3] = 255;\n\n\t\tif (p->roll) {\n\t\t\tVectorMA (point, 2*height, ru, point);\t\n\t\t} else {\n\t\t\tVectorMA (point, 2*height, pvup, point);\t\n\t\t}\n\t\tVectorCopy (point, verts[1].xyz);\t\n\t\tverts[1].st[0] = 0;\t\n\t\tverts[1].st[1] = 1;\t\n\t\tverts[1].modulate[0] = 255;\t\n\t\tverts[1].modulate[1] = 255;\t\n\t\tverts[1].modulate[2] = 255;\t\n\t\tverts[1].modulate[3] = 255;\t\n\n\t\tif (p->roll) {\n\t\t\tVectorMA (point, 2*width, rr, point);\t\n\t\t} else {\n\t\t\tVectorMA (point, 2*width, pvright, point);\t\n\t\t}\n\t\tVectorCopy (point, verts[2].xyz);\t\n\t\tverts[2].st[0] = 1;\t\n\t\tverts[2].st[1] = 1;\t\n\t\tverts[2].modulate[0] = 255;\t\n\t\tverts[2].modulate[1] = 255;\t\n\t\tverts[2].modulate[2] = 255;\t\n\t\tverts[2].modulate[3] = 255;\t\n\n\t\tif (p->roll) {\n\t\t\tVectorMA (point, -2*height, ru, point);\t\n\t\t} else {\n\t\t\tVectorMA (point, -2*height, pvup, point);\t\n\t\t}\n\t\tVectorCopy (point, verts[3].xyz);\t\n\t\tverts[3].st[0] = 1;\t\n\t\tverts[3].st[1] = 0;\t\n\t\tverts[3].modulate[0] = 255;\t\n\t\tverts[3].modulate[1] = 255;\t\n\t\tverts[3].modulate[2] = 255;\t\n\t\tverts[3].modulate[3] = 255;\t\n\t}\n\t// done.\n\t\n\tif (!p->pshader) {\n// (SA) temp commented out for DM\n//\t\tCG_Printf (\"CG_AddParticleToScene type %d p->pshader == ZERO\\n\", p->type);\n\t\treturn;\n\t}\n\n\tif (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT || p->type == P_WEATHER_FLURRY)\n\t\ttrap_R_AddPolyToScene( p->pshader, 3, TRIverts );\n\telse\n\t\ttrap_R_AddPolyToScene( p->pshader, 4, verts );\n\n}\n\n// Ridah, made this static so it doesn't interfere with other files\nstatic float roll = 0.0;\n\n/*\n===============\nCG_AddParticles\n===============\n*/\nvoid CG_AddParticles (void)\n{\n\tcparticle_t\t\t*p, *next;\n\tfloat\t\t\talpha;\n\tfloat\t\t\ttime, time2;\n\tvec3_t\t\t\torg;\n\tint\t\t\t\tcolor;\n\tcparticle_t\t\t*active, *tail;\n\tint\t\t\t\ttype;\n\tvec3_t\t\t\trotate_ang;\n\n\tif (!initparticles)\n\t\tCG_ClearParticles ();\n\n\tVectorCopy( cg.refdef.viewaxis[0], pvforward );\n\tVectorCopy( cg.refdef.viewaxis[1], pvright );\n\tVectorCopy( cg.refdef.viewaxis[2], pvup );\n\n\tvectoangles( cg.refdef.viewaxis[0], rotate_ang );\n\troll += ((cg.time - oldtime) * 0.1) ;\n\trotate_ang[ROLL] += (roll*0.9);\n\tAngleVectors ( rotate_ang, rforward, rright, rup);\n\t\n\toldtime = cg.time;\n\n\tactive = NULL;\n\ttail = NULL;\n\n\tfor (p=active_particles ; p ; p=next)\n\t{\n\n\t\tnext = p->next;\n\n\t\ttime = (cg.time - p->time)*0.001;\n\n\t\talpha = p->alpha + time*p->alphavel;\n\t\tif (alpha <= 0)\n\t\t{\t// faded out\n\t\t\tp->next = free_particles;\n\t\t\tfree_particles = p;\n\t\t\tp->type = 0;\n\t\t\tp->color = 0;\n\t\t\tp->alpha = 0;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (p->type == P_SMOKE || p->type == P_ANIM || p->type == P_BLEED || p->type == P_SMOKE_IMPACT)\n\t\t{\n\t\t\tif (cg.time > p->endtime)\n\t\t\t{\n\t\t\t\tp->next = free_particles;\n\t\t\t\tfree_particles = p;\n\t\t\t\tp->type = 0;\n\t\t\t\tp->color = 0;\n\t\t\t\tp->alpha = 0;\n\t\t\t\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t}\n\n\t\tif (p->type == P_WEATHER_FLURRY)\n\t\t{\n\t\t\tif (cg.time > p->endtime)\n\t\t\t{\n\t\t\t\tp->next = free_particles;\n\t\t\t\tfree_particles = p;\n\t\t\t\tp->type = 0;\n\t\t\t\tp->color = 0;\n\t\t\t\tp->alpha = 0;\n\t\t\t\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\n\t\tif (p->type == P_FLAT_SCALEUP_FADE)\n\t\t{\n\t\t\tif (cg.time > p->endtime)\n\t\t\t{\n\t\t\t\tp->next = free_particles;\n\t\t\t\tfree_particles = p;\n\t\t\t\tp->type = 0;\n\t\t\t\tp->color = 0;\n\t\t\t\tp->alpha = 0;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t}\n\n\t\tif ((p->type == P_BAT || p->type == P_SPRITE) && p->endtime < 0) {\n\t\t\t// temporary sprite\n\t\t\tCG_AddParticleToScene (p, p->org, alpha);\n\t\t\tp->next = free_particles;\n\t\t\tfree_particles = p;\n\t\t\tp->type = 0;\n\t\t\tp->color = 0;\n\t\t\tp->alpha = 0;\n\t\t\tcontinue;\n\t\t}\n\n\t\tp->next = NULL;\n\t\tif (!tail)\n\t\t\tactive = tail = p;\n\t\telse\n\t\t{\n\t\t\ttail->next = p;\n\t\t\ttail = p;\n\t\t}\n\n\t\tif (alpha > 1.0)\n\t\t\talpha = 1;\n\n\t\tcolor = p->color;\n\n\t\ttime2 = time*time;\n\n\t\torg[0] = p->org[0] + p->vel[0]*time + p->accel[0]*time2;\n\t\torg[1] = p->org[1] + p->vel[1]*time + p->accel[1]*time2;\n\t\torg[2] = p->org[2] + p->vel[2]*time + p->accel[2]*time2;\n\n\t\ttype = p->type;\n\n\t\tCG_AddParticleToScene (p, org, alpha);\n\t}\n\n\tactive_particles = active;\n}\n\n/*\n======================\nCG_AddParticles\n======================\n*/\nvoid CG_ParticleSnowFlurry (qhandle_t pshader, centity_t *cent)\n{\n\tcparticle_t\t*p;\n\tqboolean turb = qtrue;\n\n\tif (!pshader)\n\t\tCG_Printf (\"CG_ParticleSnowFlurry pshader == ZERO!\\n\");\n\n\tif (!free_particles)\n\t\treturn;\n\tp = free_particles;\n\tfree_particles = p->next;\n\tp->next = active_particles;\n\tactive_particles = p;\n\tp->time = cg.time;\n\tp->color = 0;\n\tp->alpha = 0.90f;\n\tp->alphavel = 0;\n\n\tp->start = cent->currentState.origin2[0];\n\tp->end = cent->currentState.origin2[1];\n\t\n\tp->endtime = cg.time + cent->currentState.time;\n\tp->startfade = cg.time + cent->currentState.time2;\n\t\n\tp->pshader = pshader;\n\t\n\tif (rand()%100 > 90)\n\t{\n\t\tp->height = 32;\n\t\tp->width = 32;\n\t\tp->alpha = 0.10f;\n\t}\n\telse\n\t{\n\t\tp->height = 1;\n\t\tp->width = 1;\n\t}\n\n\tp->vel[2] = -20;\n\n\tp->type = P_WEATHER_FLURRY;\n\t\n\tif (turb)\n\t\tp->vel[2] = -10;\n\t\n\tVectorCopy(cent->currentState.origin, p->org);\n\n\tp->org[0] = p->org[0];\n\tp->org[1] = p->org[1];\n\tp->org[2] = p->org[2];\n\n\tp->vel[0] = p->vel[1] = 0;\n\t\n\tp->accel[0] = p->accel[1] = p->accel[2] = 0;\n\n\tp->vel[0] += cent->currentState.angles[0] * 32 + (crandom() * 16);\n\tp->vel[1] += cent->currentState.angles[1] * 32 + (crandom() * 16);\n\tp->vel[2] += cent->currentState.angles[2];\n\n\tif (turb)\n\t{\n\t\tp->accel[0] = crandom () * 16;\n\t\tp->accel[1] = crandom () * 16;\n\t}\n\n}\n\nvoid CG_ParticleSnow (qhandle_t pshader, vec3_t origin, vec3_t origin2, int turb, float range, int snum)\n{\n\tcparticle_t\t*p;\n\n\tif (!pshader)\n\t\tCG_Printf (\"CG_ParticleSnow pshader == ZERO!\\n\");\n\n\tif (!free_particles)\n\t\treturn;\n\tp = free_particles;\n\tfree_particles = p->next;\n\tp->next = active_particles;\n\tactive_particles = p;\n\tp->time = cg.time;\n\tp->color = 0;\n\tp->alpha = 0.40f;\n\tp->alphavel = 0;\n\tp->start = origin[2];\n\tp->end = origin2[2];\n\tp->pshader = pshader;\n\tp->height = 1;\n\tp->width = 1;\n\t\n\tp->vel[2] = -50;\n\n\tif (turb)\n\t{\n\t\tp->type = P_WEATHER_TURBULENT;\n\t\tp->vel[2] = -50 * 1.3;\n\t}\n\telse\n\t{\n\t\tp->type = P_WEATHER;\n\t}\n\t\n\tVectorCopy(origin, p->org);\n\n\tp->org[0] = p->org[0] + ( crandom() * range);\n\tp->org[1] = p->org[1] + ( crandom() * range);\n\tp->org[2] = p->org[2] + ( crandom() * (p->start - p->end)); \n\n\tp->vel[0] = p->vel[1] = 0;\n\t\n\tp->accel[0] = p->accel[1] = p->accel[2] = 0;\n\n\tif (turb)\n\t{\n\t\tp->vel[0] = crandom() * 16;\n\t\tp->vel[1] = crandom() * 16;\n\t}\n\n\t// Rafael snow pvs check\n\tp->snum = snum;\n\tp->link = qtrue;\n\n}\n\nvoid CG_ParticleBubble (qhandle_t pshader, vec3_t origin, vec3_t origin2, int turb, float range, int snum)\n{\n\tcparticle_t\t*p;\n\tfloat\t\trandsize;\n\n\tif (!pshader)\n\t\tCG_Printf (\"CG_ParticleSnow pshader == ZERO!\\n\");\n\n\tif (!free_particles)\n\t\treturn;\n\tp = free_particles;\n\tfree_particles = p->next;\n\tp->next = active_particles;\n\tactive_particles = p;\n\tp->time = cg.time;\n\tp->color = 0;\n\tp->alpha = 0.40f;\n\tp->alphavel = 0;\n\tp->start = origin[2];\n\tp->end = origin2[2];\n\tp->pshader = pshader;\n\t\n\trandsize = 1 + (crandom() * 0.5);\n\t\n\tp->height = randsize;\n\tp->width = randsize;\n\t\n\tp->vel[2] = 50 + ( crandom() * 10 );\n\n\tif (turb)\n\t{\n\t\tp->type = P_BUBBLE_TURBULENT;\n\t\tp->vel[2] = 50 * 1.3;\n\t}\n\telse\n\t{\n\t\tp->type = P_BUBBLE;\n\t}\n\t\n\tVectorCopy(origin, p->org);\n\n\tp->org[0] = p->org[0] + ( crandom() * range);\n\tp->org[1] = p->org[1] + ( crandom() * range);\n\tp->org[2] = p->org[2] + ( crandom() * (p->start - p->end)); \n\n\tp->vel[0] = p->vel[1] = 0;\n\t\n\tp->accel[0] = p->accel[1] = p->accel[2] = 0;\n\n\tif (turb)\n\t{\n\t\tp->vel[0] = crandom() * 4;\n\t\tp->vel[1] = crandom() * 4;\n\t}\n\n\t// Rafael snow pvs check\n\tp->snum = snum;\n\tp->link = qtrue;\n\n}\n\nvoid CG_ParticleSmoke (qhandle_t pshader, centity_t *cent)\n{\n\n\t// using cent->density = enttime\n\t//\t\t cent->frame = startfade\n\tcparticle_t\t*p;\n\n\tif (!pshader)\n\t\tCG_Printf (\"CG_ParticleSmoke == ZERO!\\n\");\n\n\tif (!free_particles)\n\t\treturn;\n\tp = free_particles;\n\tfree_particles = p->next;\n\tp->next = active_particles;\n\tactive_particles = p;\n\tp->time = cg.time;\n\t\n\tp->endtime = cg.time + cent->currentState.time;\n\tp->startfade = cg.time + cent->currentState.time2;\n\t\n\tp->color = 0;\n\tp->alpha = 1.0;\n\tp->alphavel = 0;\n\tp->start = cent->currentState.origin[2];\n\tp->end = cent->currentState.origin2[2];\n\tp->pshader = pshader;\n\tp->rotate = qfalse;\n\tp->height = 8;\n\tp->width = 8;\n\tp->endheight = 32;\n\tp->endwidth = 32;\n\tp->type = P_SMOKE;\n\t\n\tVectorCopy(cent->currentState.origin, p->org);\n\n\tp->vel[0] = p->vel[1] = 0;\n\tp->accel[0] = p->accel[1] = p->accel[2] = 0;\n\n\tp->vel[2] = 5;\n\n\tif (cent->currentState.frame == 1)// reverse gravity\t\n\t\tp->vel[2] *= -1;\n\n\tp->roll = 8 + (crandom() * 4);\n}\n\n\nvoid CG_ParticleBulletDebris (vec3_t org, vec3_t vel, int duration)\n{\n\n\tcparticle_t\t*p;\n\n\tif (!free_particles)\n\t\treturn;\n\tp = free_particles;\n\tfree_particles = p->next;\n\tp->next = active_particles;\n\tactive_particles = p;\n\tp->time = cg.time;\n\t\n\tp->endtime = cg.time + duration;\n\tp->startfade = cg.time + duration/2;\n\t\n\tp->color = EMISIVEFADE;\n\tp->alpha = 1.0;\n\tp->alphavel = 0;\n\n\tp->height = 0.5;\n\tp->width = 0.5;\n\tp->endheight = 0.5;\n\tp->endwidth = 0.5;\n\n\tp->pshader = cgs.media.tracerShader;\n\n\tp->type = P_SMOKE;\n\t\n\tVectorCopy(org, p->org);\n\n\tp->vel[0] = vel[0];\n\tp->vel[1] = vel[1];\n\tp->vel[2] = vel[2];\n\tp->accel[0] = p->accel[1] = p->accel[2] = 0;\n\n\tp->accel[2] = -60;\n\tp->vel[2] += -20;\n\t\n}\n\n/*\n======================\nCG_ParticleExplosion\n======================\n*/\n\nvoid CG_ParticleExplosion (char *animStr, vec3_t origin, vec3_t vel, int duration, int sizeStart, int sizeEnd)\n{\n\tcparticle_t\t*p;\n\tint anim;\n\n\tif (animStr < (char *)10)\n\t\tCG_Error( \"CG_ParticleExplosion: animStr is probably an index rather than a string\" );\n\n\t// find the animation string\n\tfor (anim=0; shaderAnimNames[anim]; anim++) {\n\t\tif (!Q_stricmp( animStr, shaderAnimNames[anim] ))\n\t\t\tbreak;\n\t}\n\tif (!shaderAnimNames[anim]) {\n\t\tCG_Error(\"CG_ParticleExplosion: unknown animation string: %s\\n\", animStr);\n\t\treturn;\n\t}\n\n\tif (!free_particles)\n\t\treturn;\n\tp = free_particles;\n\tfree_particles = p->next;\n\tp->next = active_particles;\n\tactive_particles = p;\n\tp->time = cg.time;\n\tp->alpha = 0.5;\n\tp->alphavel = 0;\n\n\tif (duration < 0) {\n\t\tduration *= -1;\n\t\tp->roll = 0;\n\t} else {\n\t\tp->roll = crandom()*179;\n\t}\n\n\tp->shaderAnim = anim;\n\n\tp->width = sizeStart;\n\tp->height = sizeStart*shaderAnimSTRatio[anim];\t// for sprites that are stretch in either direction\n\n\tp->endheight = sizeEnd;\n\tp->endwidth = sizeEnd*shaderAnimSTRatio[anim];\n\n\tp->endtime = cg.time + duration;\n\n\tp->type = P_ANIM;\n\n\tVectorCopy( origin, p->org );\n\tVectorCopy( vel, p->vel );\n\tVectorClear( p->accel );\n\n}\n\n// Rafael Shrapnel\nvoid CG_AddParticleShrapnel (localEntity_t *le)\n{\n\treturn;\n}\n// done.\n\nint CG_NewParticleArea (int num)\n{\n\t// const char *str;\n\tchar *str;\n\tchar *token;\n\tint type;\n\tvec3_t origin, origin2;\n\tint\t\ti;\n\tfloat range = 0;\n\tint turb;\n\tint\tnumparticles;\n\tint\tsnum;\n\t\n\tstr = (char *) CG_ConfigString (num);\n\tif (!str[0])\n\t\treturn (0);\n\t\n\t// returns type 128 64 or 32\n\ttoken = COM_Parse (&str);\n\ttype = atoi (token);\n\t\n\tif (type == 1)\n\t\trange = 128;\n\telse if (type == 2)\n\t\trange = 64;\n\telse if (type == 3)\n\t\trange = 32;\n\telse if (type == 0)\n\t\trange = 256;\n\telse if (type == 4)\n\t\trange = 8;\n\telse if (type == 5)\n\t\trange = 16;\n\telse if (type == 6)\n\t\trange = 32;\n\telse if (type == 7)\n\t\trange = 64;\n\n\n\tfor (i=0; i<3; i++)\n\t{\n\t\ttoken = COM_Parse (&str);\n\t\torigin[i] = atof (token);\n\t}\n\n\tfor (i=0; i<3; i++)\n\t{\n\t\ttoken = COM_Parse (&str);\n\t\torigin2[i] = atof (token);\n\t}\n\t\t\n\ttoken = COM_Parse (&str);\n\tnumparticles = atoi (token);\n\t\n\ttoken = COM_Parse (&str);\n\tturb = atoi (token);\n\n\ttoken = COM_Parse (&str);\n\tsnum = atoi (token);\n\t\n\tfor (i=0; i<numparticles; i++)\n\t{\n\t\tif (type >= 4)\n\t\t\tCG_ParticleBubble (cgs.media.waterBubbleShader, origin, origin2, turb, range, snum);\n\t\telse\n\t\t\tCG_ParticleSnow (cgs.media.waterBubbleShader, origin, origin2, turb, range, snum);\n\t}\n\n\treturn (1);\n}\n\nvoid\tCG_SnowLink (centity_t *cent, qboolean particleOn)\n{\n\tcparticle_t\t\t*p, *next;\n\tint id;\n\n\tid = cent->currentState.frame;\n\n\tfor (p=active_particles ; p ; p=next)\n\t{\n\t\tnext = p->next;\n\t\t\n\t\tif (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT)\n\t\t{\n\t\t\tif (p->snum == id)\n\t\t\t{\n\t\t\t\tif (particleOn)\n\t\t\t\t\tp->link = qtrue;\n\t\t\t\telse\n\t\t\t\t\tp->link = qfalse;\n\t\t\t}\n\t\t}\n\n\t}\n}\n\nvoid CG_ParticleImpactSmokePuff (qhandle_t pshader, vec3_t origin)\n{\n\tcparticle_t\t*p;\n\n\tif (!pshader)\n\t\tCG_Printf (\"CG_ParticleImpactSmokePuff pshader == ZERO!\\n\");\n\n\tif (!free_particles)\n\t\treturn;\n\tp = free_particles;\n\tfree_particles = p->next;\n\tp->next = active_particles;\n\tactive_particles = p;\n\tp->time = cg.time;\n\tp->alpha = 0.25;\n\tp->alphavel = 0;\n\tp->roll = crandom()*179;\n\n\tp->pshader = pshader;\n\n\tp->endtime = cg.time + 1000;\n\tp->startfade = cg.time + 100;\n\n\tp->width = rand()%4 + 8;\n\tp->height = rand()%4 + 8;\n\n\tp->endheight = p->height *2;\n\tp->endwidth = p->width * 2;\n\n\tp->endtime = cg.time + 500;\n\n\tp->type = P_SMOKE_IMPACT;\n\n\tVectorCopy( origin, p->org );\n\tVectorSet(p->vel, 0, 0, 20);\n\tVectorSet(p->accel, 0, 0, 20);\n\n\tp->rotate = qtrue;\n}\n\nvoid CG_Particle_Bleed (qhandle_t pshader, vec3_t start, vec3_t dir, int fleshEntityNum, int duration)\n{\n\tcparticle_t\t*p;\n\n\tif (!pshader)\n\t\tCG_Printf (\"CG_Particle_Bleed pshader == ZERO!\\n\");\n\n\tif (!free_particles)\n\t\treturn;\n\tp = free_particles;\n\tfree_particles = p->next;\n\tp->next = active_particles;\n\tactive_particles = p;\n\tp->time = cg.time;\n\tp->alpha = 1.0;\n\tp->alphavel = 0;\n\tp->roll = 0;\n\n\tp->pshader = pshader;\n\n\tp->endtime = cg.time + duration;\n\t\n\tif (fleshEntityNum)\n\t\tp->startfade = cg.time;\n\telse\n\t\tp->startfade = cg.time + 100;\n\n\tp->width = 4;\n\tp->height = 4;\n\n\tp->endheight = 4+rand()%3;\n\tp->endwidth = p->endheight;\n\n\tp->type = P_SMOKE;\n\n\tVectorCopy( start, p->org );\n\tp->vel[0] = 0;\n\tp->vel[1] = 0;\n\tp->vel[2] = -20;\n\tVectorClear( p->accel );\n\n\tp->rotate = qfalse;\n\n\tp->roll = rand()%179;\n\t\n\tp->color = BLOODRED;\n\tp->alpha = 0.75;\n\n}\n\nvoid CG_Particle_OilParticle (qhandle_t pshader, centity_t *cent)\n{\n\tcparticle_t\t*p;\n\n\tint\t\t\ttime;\n\tint\t\t\ttime2;\n\tfloat\t\tratio;\n\n\tfloat\tduration = 1500;\n\n\ttime = cg.time;\n\ttime2 = cg.time + cent->currentState.time;\n\n\tratio =(float)1 - ((float)time / (float)time2);\n\n\tif (!pshader)\n\t\tCG_Printf (\"CG_Particle_OilParticle == ZERO!\\n\");\n\n\tif (!free_particles)\n\t\treturn;\n\tp = free_particles;\n\tfree_particles = p->next;\n\tp->next = active_particles;\n\tactive_particles = p;\n\tp->time = cg.time;\n\tp->alpha = 1.0;\n\tp->alphavel = 0;\n\tp->roll = 0;\n\n\tp->pshader = pshader;\n\n\tp->endtime = cg.time + duration;\n\t\n\tp->startfade = p->endtime;\n\n\tp->width = 1;\n\tp->height = 3;\n\n\tp->endheight = 3;\n\tp->endwidth = 1;\n\n\tp->type = P_SMOKE;\n\n\tVectorCopy(cent->currentState.origin, p->org );\t\n\t\n\tp->vel[0] = (cent->currentState.origin2[0] * (16 * ratio));\n\tp->vel[1] = (cent->currentState.origin2[1] * (16 * ratio));\n\tp->vel[2] = (cent->currentState.origin2[2]);\n\n\tp->snum = 1.0f;\n\n\tVectorClear( p->accel );\n\n\tp->accel[2] = -20;\n\n\tp->rotate = qfalse;\n\n\tp->roll = rand()%179;\n\t\n\tp->alpha = 0.75;\n\n}\n\n\nvoid CG_Particle_OilSlick (qhandle_t pshader, centity_t *cent)\n{\n\tcparticle_t\t*p;\n\t\n  \tif (!pshader)\n\t\tCG_Printf (\"CG_Particle_OilSlick == ZERO!\\n\");\n\n\tif (!free_particles)\n\t\treturn;\n\tp = free_particles;\n\tfree_particles = p->next;\n\tp->next = active_particles;\n\tactive_particles = p;\n\tp->time = cg.time;\n\t\n\tif (cent->currentState.angles2[2])\n\t\tp->endtime = cg.time + cent->currentState.angles2[2];\n\telse\n\t\tp->endtime = cg.time + 60000;\n\n\tp->startfade = p->endtime;\n\n\tp->alpha = 1.0;\n\tp->alphavel = 0;\n\tp->roll = 0;\n\n\tp->pshader = pshader;\n\n\tif (cent->currentState.angles2[0] || cent->currentState.angles2[1])\n\t{\n\t\tp->width = cent->currentState.angles2[0];\n\t\tp->height = cent->currentState.angles2[0];\n\n\t\tp->endheight = cent->currentState.angles2[1];\n\t\tp->endwidth = cent->currentState.angles2[1];\n\t}\n\telse\n\t{\n\t\tp->width = 8;\n\t\tp->height = 8;\n\n\t\tp->endheight = 16;\n\t\tp->endwidth = 16;\n\t}\n\n\tp->type = P_FLAT_SCALEUP;\n\n\tp->snum = 1.0;\n\n\tVectorCopy(cent->currentState.origin, p->org );\n\t\n\tp->org[2]+= 0.55 + (crandom() * 0.5);\n\n\tp->vel[0] = 0;\n\tp->vel[1] = 0;\n\tp->vel[2] = 0;\n\tVectorClear( p->accel );\n\n\tp->rotate = qfalse;\n\n\tp->roll = rand()%179;\n\t\n\tp->alpha = 0.75;\n\n}\n\nvoid CG_OilSlickRemove (centity_t *cent)\n{\n\tcparticle_t\t\t*p, *next;\n\tint\t\t\t\tid;\n\n\tid = 1.0f;\n\n\tif (!id)\n\t\tCG_Printf (\"CG_OilSlickRevove NULL id\\n\");\n\n\tfor (p=active_particles ; p ; p=next)\n\t{\n\t\tnext = p->next;\n\t\t\n\t\tif (p->type == P_FLAT_SCALEUP)\n\t\t{\n\t\t\tif (p->snum == id)\n\t\t\t{\n\t\t\t\tp->endtime = cg.time + 100;\n\t\t\t\tp->startfade = p->endtime;\n\t\t\t\tp->type = P_FLAT_SCALEUP_FADE;\n\n\t\t\t}\n\t\t}\n\n\t}\n}\n\nqboolean ValidBloodPool (vec3_t start)\n{\n#define EXTRUDE_DIST\t0.5\n\n\tvec3_t\tangles;\n\tvec3_t\tright, up;\n\tvec3_t\tthis_pos, x_pos, center_pos, end_pos;\n\tfloat\tx, y;\n\tfloat\tfwidth, fheight;\n\ttrace_t\ttrace;\n\tvec3_t\tnormal;\n\n\tfwidth = 16;\n\tfheight = 16;\n\n\tVectorSet (normal, 0, 0, 1);\n\n\tvectoangles (normal, angles);\n\tAngleVectors (angles, NULL, right, up);\n\n\tVectorMA (start, EXTRUDE_DIST, normal, center_pos);\n\n\tfor (x= -fwidth/2; x<fwidth; x+= fwidth)\n\t{\n\t\tVectorMA (center_pos, x, right, x_pos);\n\n\t\tfor (y= -fheight/2; y<fheight; y+= fheight)\n\t\t{\n\t\t\tVectorMA (x_pos, y, up, this_pos);\n\t\t\tVectorMA (this_pos, -EXTRUDE_DIST*2, normal, end_pos);\n\t\t\t\n\t\t\tCG_Trace (&trace, this_pos, NULL, NULL, end_pos, -1, CONTENTS_SOLID);\n\n\t\t\t\n\t\t\tif (trace.entityNum < (MAX_ENTITIES - 1)) // may only land on world\n\t\t\t\treturn qfalse;\n\n\t\t\tif (!(!trace.startsolid && trace.fraction < 1))\n\t\t\t\treturn qfalse;\n\t\t\n\t\t}\n\t}\n\n\treturn qtrue;\n}\n\nvoid CG_BloodPool (localEntity_t *le, qhandle_t pshader, trace_t *tr)\n{\t\n\tcparticle_t\t*p;\n\tqboolean\tlegit;\n\tvec3_t\t\tstart;\n\tfloat\t\trndSize;\n\t\n\tif (!pshader)\n\t\tCG_Printf (\"CG_BloodPool pshader == ZERO!\\n\");\n\n\tif (!free_particles)\n\t\treturn;\n\t\n\tVectorCopy (tr->endpos, start);\n\tlegit = ValidBloodPool (start);\n\n\tif (!legit) \n\t\treturn;\n\n\tp = free_particles;\n\tfree_particles = p->next;\n\tp->next = active_particles;\n\tactive_particles = p;\n\tp->time = cg.time;\n\t\n\tp->endtime = cg.time + 3000;\n\tp->startfade = p->endtime;\n\n\tp->alpha = 1.0;\n\tp->alphavel = 0;\n\tp->roll = 0;\n\n\tp->pshader = pshader;\n\n\trndSize = 0.4 + random()*0.6;\n\n\tp->width = 8*rndSize;\n\tp->height = 8*rndSize;\n\n\tp->endheight = 16*rndSize;\n\tp->endwidth = 16*rndSize;\n\t\n\tp->type = P_FLAT_SCALEUP;\n\n\tVectorCopy(start, p->org );\n\t\n\tp->vel[0] = 0;\n\tp->vel[1] = 0;\n\tp->vel[2] = 0;\n\tVectorClear( p->accel );\n\n\tp->rotate = qfalse;\n\n\tp->roll = rand()%179;\n\t\n\tp->alpha = 0.75;\n\t\n\tp->color = BLOODRED;\n}\n\n#define NORMALSIZE\t16\n#define LARGESIZE\t32\n\nvoid CG_ParticleBloodCloud (centity_t *cent, vec3_t origin, vec3_t dir)\n{\n\tfloat\tlength;\n\tfloat\tdist;\n\tfloat\tcrittersize;\n\tvec3_t\tangles, forward;\n\tvec3_t\tpoint;\n\tcparticle_t\t*p;\n\tint\t\ti;\n\t\n\tdist = 0;\n\n\tlength = VectorLength (dir);\n\tvectoangles (dir, angles);\n\tAngleVectors (angles, forward, NULL, NULL);\n\n\tcrittersize = LARGESIZE;\n\n\tif (length)\n\t\tdist = length / crittersize;\n\n\tif (dist < 1)\n\t\tdist = 1;\n\n\tVectorCopy (origin, point);\n\n\tfor (i=0; i<dist; i++)\n\t{\n\t\tVectorMA (point, crittersize, forward, point);\t\n\t\t\n\t\tif (!free_particles)\n\t\t\treturn;\n\n\t\tp = free_particles;\n\t\tfree_particles = p->next;\n\t\tp->next = active_particles;\n\t\tactive_particles = p;\n\n\t\tp->time = cg.time;\n\t\tp->alpha = 1.0;\n\t\tp->alphavel = 0;\n\t\tp->roll = 0;\n\n\t\tp->pshader = cgs.media.smokePuffShader;\n\n\t\tp->endtime = cg.time + 350 + (crandom() * 100);\n\t\t\n\t\tp->startfade = cg.time;\n\t\t\n\t\tp->width = LARGESIZE;\n\t\tp->height = LARGESIZE;\n\t\tp->endheight = LARGESIZE;\n\t\tp->endwidth = LARGESIZE;\n\n\t\tp->type = P_SMOKE;\n\n\t\tVectorCopy( origin, p->org );\n\t\t\n\t\tp->vel[0] = 0;\n\t\tp->vel[1] = 0;\n\t\tp->vel[2] = -1;\n\t\t\n\t\tVectorClear( p->accel );\n\n\t\tp->rotate = qfalse;\n\n\t\tp->roll = rand()%179;\n\t\t\n\t\tp->color = BLOODRED;\n\t\t\n\t\tp->alpha = 0.75;\n\t\t\n\t}\n\n\t\n}\n\nvoid CG_ParticleSparks (vec3_t org, vec3_t vel, int duration, float x, float y, float speed)\n{\n\tcparticle_t\t*p;\n\n\tif (!free_particles)\n\t\treturn;\n\tp = free_particles;\n\tfree_particles = p->next;\n\tp->next = active_particles;\n\tactive_particles = p;\n\tp->time = cg.time;\n\t\n\tp->endtime = cg.time + duration;\n\tp->startfade = cg.time + duration/2;\n\t\n\tp->color = EMISIVEFADE;\n\tp->alpha = 0.4f;\n\tp->alphavel = 0;\n\n\tp->height = 0.5;\n\tp->width = 0.5;\n\tp->endheight = 0.5;\n\tp->endwidth = 0.5;\n\n\tp->pshader = cgs.media.tracerShader;\n\n\tp->type = P_SMOKE;\n\t\n\tVectorCopy(org, p->org);\n\n\tp->org[0] += (crandom() * x);\n\tp->org[1] += (crandom() * y);\n\n\tp->vel[0] = vel[0];\n\tp->vel[1] = vel[1];\n\tp->vel[2] = vel[2];\n\n\tp->accel[0] = p->accel[1] = p->accel[2] = 0;\n\n\tp->vel[0] += (crandom() * 4);\n\tp->vel[1] += (crandom() * 4);\n\tp->vel[2] += (20 + (crandom() * 10)) * speed;\t\n\n\tp->accel[0] = crandom () * 4;\n\tp->accel[1] = crandom () * 4;\n\t\n}\n\nvoid CG_ParticleDust (centity_t *cent, vec3_t origin, vec3_t dir)\n{\n\tfloat\tlength;\n\tfloat\tdist;\n\tfloat\tcrittersize;\n\tvec3_t\tangles, forward;\n\tvec3_t\tpoint;\n\tcparticle_t\t*p;\n\tint\t\ti;\n\t\n\tdist = 0;\n\n\tVectorNegate (dir, dir);\n\tlength = VectorLength (dir);\n\tvectoangles (dir, angles);\n\tAngleVectors (angles, forward, NULL, NULL);\n\n\tcrittersize = LARGESIZE;\n\n\tif (length)\n\t\tdist = length / crittersize;\n\n\tif (dist < 1)\n\t\tdist = 1;\n\n\tVectorCopy (origin, point);\n\n\tfor (i=0; i<dist; i++)\n\t{\n\t\tVectorMA (point, crittersize, forward, point);\t\n\t\t\t\t\n\t\tif (!free_particles)\n\t\t\treturn;\n\n\t\tp = free_particles;\n\t\tfree_particles = p->next;\n\t\tp->next = active_particles;\n\t\tactive_particles = p;\n\n\t\tp->time = cg.time;\n\t\tp->alpha = 5.0;\n\t\tp->alphavel = 0;\n\t\tp->roll = 0;\n\n\t\tp->pshader = cgs.media.smokePuffShader;\n\n\t\t// RF, stay around for long enough to expand and dissipate naturally\n\t\tif (length)\n\t\t\tp->endtime = cg.time + 4500 + (crandom() * 3500);\n\t\telse\n\t\t\tp->endtime = cg.time + 750 + (crandom() * 500);\n\t\t\n\t\tp->startfade = cg.time;\n\t\t\n\t\tp->width = LARGESIZE;\n\t\tp->height = LARGESIZE;\n\n\t\t// RF, expand while falling\n\t\tp->endheight = LARGESIZE*3.0;\n\t\tp->endwidth = LARGESIZE*3.0;\n\n\t\tif (!length)\n\t\t{\n\t\t\tp->width *= 0.2f;\n\t\t\tp->height *= 0.2f;\n\n\t\t\tp->endheight = NORMALSIZE;\n\t\t\tp->endwidth = NORMALSIZE;\n\t\t}\n\n\t\tp->type = P_SMOKE;\n\n\t\tVectorCopy( point, p->org );\n\t\t\n\t\tp->vel[0] = crandom()*6;\n\t\tp->vel[1] = crandom()*6;\n\t\tp->vel[2] = random()*20;\n\n\t\t// RF, add some gravity/randomness\n\t\tp->accel[0] = crandom()*3;\n\t\tp->accel[1] = crandom()*3;\n\t\tp->accel[2] = -PARTICLE_GRAVITY*0.4;\n\n\t\tVectorClear( p->accel );\n\n\t\tp->rotate = qfalse;\n\n\t\tp->roll = rand()%179;\n\t\t\n\t\tp->alpha = 0.75;\n\t\t\n\t}\n\n\t\n}\n\nvoid CG_ParticleMisc (qhandle_t pshader, vec3_t origin, int size, int duration, float alpha)\n{\n\tcparticle_t\t*p;\n\n\tif (!pshader)\n\t\tCG_Printf (\"CG_ParticleImpactSmokePuff pshader == ZERO!\\n\");\n\n\tif (!free_particles)\n\t\treturn;\n\n\tp = free_particles;\n\tfree_particles = p->next;\n\tp->next = active_particles;\n\tactive_particles = p;\n\tp->time = cg.time;\n\tp->alpha = 1.0;\n\tp->alphavel = 0;\n\tp->roll = rand()%179;\n\n\tp->pshader = pshader;\n\n\tif (duration > 0)\n\t\tp->endtime = cg.time + duration;\n\telse\n\t\tp->endtime = duration;\n\n\tp->startfade = cg.time;\n\n\tp->width = size;\n\tp->height = size;\n\n\tp->endheight = size;\n\tp->endwidth = size;\n\n\tp->type = P_SPRITE;\n\n\tVectorCopy( origin, p->org );\n\n\tp->rotate = qfalse;\n}\n\n"
  },
  {
    "path": "src/cgame/cg_particles.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n// Rafael particles\n// cg_particles.c  \n\n#include \"cg_local.h\"\n\n#define BLOODRED\t2\n#define EMISIVEFADE\t3\n#define GREY75\t\t4\n\ntypedef struct particle_s\n{\n\tstruct particle_s\t*next;\n\n\tfloat\t\ttime;\n\tfloat\t\tendtime;\n\n\tvec3_t\t\torg;\n\tvec3_t\t\tvel;\n\tvec3_t\t\taccel;\n\tint\t\t\tcolor;\n\tfloat\t\tcolorvel;\n\tfloat\t\talpha;\n\tfloat\t\talphavel;\n\tint\t\t\ttype;\n\tqhandle_t\tpshader;\n\t\n\tfloat\t\theight;\n\tfloat\t\twidth;\n\t\t\t\t\n\tfloat\t\tendheight;\n\tfloat\t\tendwidth;\n\t\n\tfloat\t\tstart;\n\tfloat\t\tend;\n\n\tfloat\t\tstartfade;\n\tqboolean\trotate;\n\tint\t\t\tsnum;\n\t\n\tqboolean\tlink;\n\n\t// Ridah\n\tint\t\t\tshaderAnim;\n\tint\t\t\troll;\n\n\tint\t\t\taccumroll;\n\n} cparticle_t;\n\ntypedef enum\n{\n\tP_NONE,\n\tP_WEATHER,\n\tP_FLAT,\n\tP_SMOKE,\n\tP_ROTATE,\n\tP_WEATHER_TURBULENT,\n\tP_ANIM,\t// Ridah\n\tP_BAT,\n\tP_BLEED,\n\tP_FLAT_SCALEUP,\n\tP_FLAT_SCALEUP_FADE,\n\tP_WEATHER_FLURRY,\n\tP_SMOKE_IMPACT,\n\tP_BUBBLE,\n\tP_BUBBLE_TURBULENT,\n\tP_SPRITE\n} particle_type_t;\n\n#define\tMAX_SHADER_ANIMS\t\t32\n#define\tMAX_SHADER_ANIM_FRAMES\t64\n\nstatic char *shaderAnimNames[MAX_SHADER_ANIMS] = {\n\t\"explode1\",\n\t\"blacksmokeanim\",\n\t\"twiltb2\",\n\t\"expblue\",\n\t\"blacksmokeanimb\",\t// uses 'explode1' sequence\n\t\"blood\",\n\tNULL\n};\nstatic qhandle_t shaderAnims[MAX_SHADER_ANIMS][MAX_SHADER_ANIM_FRAMES];\nstatic int\tshaderAnimCounts[MAX_SHADER_ANIMS] = {\n\t23,\n\t25,\n\t45,\n\t25,\n\t23,\n\t5,\n};\nstatic float\tshaderAnimSTRatio[MAX_SHADER_ANIMS] = {\n\t1.405f,\n\t1.0f,\n\t1.0f,\n\t1.0f,\n\t1.0f,\n\t1.0f,\n};\nstatic int\tnumShaderAnims;\n// done.\n\n#define\t\tPARTICLE_GRAVITY\t40\n#define\t\tMAX_PARTICLES\t1024 * 8\n\ncparticle_t\t*active_particles, *free_particles;\ncparticle_t\tparticles[MAX_PARTICLES];\nint\t\tcl_numparticles = MAX_PARTICLES;\n\nqboolean\t\tinitparticles = qfalse;\nvec3_t\t\t\tvforward, vright, vup;\nvec3_t\t\t\trforward, rright, rup;\n\nfloat\t\t\toldtime;\n\n/*\n===============\nCL_ClearParticles\n===============\n*/\nvoid CG_ClearParticles (void)\n{\n\tint\t\ti;\n\n\tmemset( particles, 0, sizeof(particles) );\n\n\tfree_particles = &particles[0];\n\tactive_particles = NULL;\n\n\tfor (i=0 ;i<cl_numparticles ; i++)\n\t{\n\t\tparticles[i].next = &particles[i+1];\n\t\tparticles[i].type = 0;\n\t}\n\tparticles[cl_numparticles-1].next = NULL;\n\n\toldtime = cg.time;\n\n\t// Ridah, init the shaderAnims\n\tfor (i=0; shaderAnimNames[i]; i++) {\n\t\tint j;\n\n\t\tfor (j=0; j<shaderAnimCounts[i]; j++) {\n\t\t\tshaderAnims[i][j] = trap_R_RegisterShader( va(\"%s%i\", shaderAnimNames[i], j+1) );\n\t\t}\n\t}\n\tnumShaderAnims = i;\n\t// done.\n\n\tinitparticles = qtrue;\n}\n\n\n/*\n=====================\nCG_AddParticleToScene\n=====================\n*/\nvoid CG_AddParticleToScene (cparticle_t *p, vec3_t org, float alpha)\n{\n\n\tvec3_t\t\tpoint;\n\tpolyVert_t\tverts[4];\n\tfloat\t\twidth;\n\tfloat\t\theight;\n\tfloat\t\ttime, time2;\n\tfloat\t\tratio;\n\tfloat\t\tinvratio;\n\tvec3_t\t\tcolor;\n\tpolyVert_t\tTRIverts[3];\n\tvec3_t\t\trright2, rup2;\n\n\tif (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT || p->type == P_WEATHER_FLURRY\n\t\t|| p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT)\n\t{// create a front facing polygon\n\t\t\t\n\t\tif (p->type != P_WEATHER_FLURRY)\n\t\t{\n\t\t\tif (p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT)\n\t\t\t{\n\t\t\t\tif (org[2] > p->end)\t\t\t\n\t\t\t\t{\t\n\t\t\t\t\tp->time = cg.time;\t\n\t\t\t\t\tVectorCopy (org, p->org); // Ridah, fixes rare snow flakes that flicker on the ground\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\tp->org[2] = ( p->start + crandom () * 4 );\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\tif (p->type == P_BUBBLE_TURBULENT)\n\t\t\t\t\t{\n\t\t\t\t\t\tp->vel[0] = crandom() * 4;\n\t\t\t\t\t\tp->vel[1] = crandom() * 4;\n\t\t\t\t\t}\n\t\t\t\t\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (org[2] < p->end)\t\t\t\n\t\t\t\t{\t\n\t\t\t\t\tp->time = cg.time;\t\n\t\t\t\t\tVectorCopy (org, p->org); // Ridah, fixes rare snow flakes that flicker on the ground\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\twhile (p->org[2] < p->end) \n\t\t\t\t\t{\n\t\t\t\t\t\tp->org[2] += (p->start - p->end); \n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\tif (p->type == P_WEATHER_TURBULENT)\n\t\t\t\t\t{\n\t\t\t\t\t\tp->vel[0] = crandom() * 16;\n\t\t\t\t\t\tp->vel[1] = crandom() * 16;\n\t\t\t\t\t}\n\t\t\t\t\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\n\t\t\t// Rafael snow pvs check\n\t\t\tif (!p->link)\n\t\t\t\treturn;\n\n\t\t\tp->alpha = 1;\n\t\t}\n\t\t\n\t\t// Ridah, had to do this or MAX_POLYS is being exceeded in village1.bsp\n\t\tif (Distance( cg.snap->ps.origin, org ) > 1024) {\n\t\t\treturn;\n\t\t}\n\t\t// done.\n\t\n\t\tif (p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT)\n\t\t{\n\t\t\tVectorMA (org, -p->height, vup, point);\t\n\t\t\tVectorMA (point, -p->width, vright, point);\t\n\t\t\tVectorCopy (point, verts[0].xyz);\t\n\t\t\tverts[0].st[0] = 0;\t\n\t\t\tverts[0].st[1] = 0;\t\n\t\t\tverts[0].modulate[0] = 255;\t\n\t\t\tverts[0].modulate[1] = 255;\t\n\t\t\tverts[0].modulate[2] = 255;\t\n\t\t\tverts[0].modulate[3] = 255 * p->alpha;\t\n\n\t\t\tVectorMA (org, -p->height, vup, point);\t\n\t\t\tVectorMA (point, p->width, vright, point);\t\n\t\t\tVectorCopy (point, verts[1].xyz);\t\n\t\t\tverts[1].st[0] = 0;\t\n\t\t\tverts[1].st[1] = 1;\t\n\t\t\tverts[1].modulate[0] = 255;\t\n\t\t\tverts[1].modulate[1] = 255;\t\n\t\t\tverts[1].modulate[2] = 255;\t\n\t\t\tverts[1].modulate[3] = 255 * p->alpha;\t\n\n\t\t\tVectorMA (org, p->height, vup, point);\t\n\t\t\tVectorMA (point, p->width, vright, point);\t\n\t\t\tVectorCopy (point, verts[2].xyz);\t\n\t\t\tverts[2].st[0] = 1;\t\n\t\t\tverts[2].st[1] = 1;\t\n\t\t\tverts[2].modulate[0] = 255;\t\n\t\t\tverts[2].modulate[1] = 255;\t\n\t\t\tverts[2].modulate[2] = 255;\t\n\t\t\tverts[2].modulate[3] = 255 * p->alpha;\t\n\n\t\t\tVectorMA (org, p->height, vup, point);\t\n\t\t\tVectorMA (point, -p->width, vright, point);\t\n\t\t\tVectorCopy (point, verts[3].xyz);\t\n\t\t\tverts[3].st[0] = 1;\t\n\t\t\tverts[3].st[1] = 0;\t\n\t\t\tverts[3].modulate[0] = 255;\t\n\t\t\tverts[3].modulate[1] = 255;\t\n\t\t\tverts[3].modulate[2] = 255;\t\n\t\t\tverts[3].modulate[3] = 255 * p->alpha;\t\n\t\t}\n\t\telse\n\t\t{\n\t\t\tVectorMA (org, -p->height, vup, point);\t\n\t\t\tVectorMA (point, -p->width, vright, point);\t\n\t\t\tVectorCopy( point, TRIverts[0].xyz );\n\t\t\tTRIverts[0].st[0] = 1;\n\t\t\tTRIverts[0].st[1] = 0;\n\t\t\tTRIverts[0].modulate[0] = 255;\n\t\t\tTRIverts[0].modulate[1] = 255;\n\t\t\tTRIverts[0].modulate[2] = 255;\n\t\t\tTRIverts[0].modulate[3] = 255 * p->alpha;\t\n\n\t\t\tVectorMA (org, p->height, vup, point);\t\n\t\t\tVectorMA (point, -p->width, vright, point);\t\n\t\t\tVectorCopy (point, TRIverts[1].xyz);\t\n\t\t\tTRIverts[1].st[0] = 0;\n\t\t\tTRIverts[1].st[1] = 0;\n\t\t\tTRIverts[1].modulate[0] = 255;\n\t\t\tTRIverts[1].modulate[1] = 255;\n\t\t\tTRIverts[1].modulate[2] = 255;\n\t\t\tTRIverts[1].modulate[3] = 255 * p->alpha;\t\n\n\t\t\tVectorMA (org, p->height, vup, point);\t\n\t\t\tVectorMA (point, p->width, vright, point);\t\n\t\t\tVectorCopy (point, TRIverts[2].xyz);\t\n\t\t\tTRIverts[2].st[0] = 0;\n\t\t\tTRIverts[2].st[1] = 1;\n\t\t\tTRIverts[2].modulate[0] = 255;\n\t\t\tTRIverts[2].modulate[1] = 255;\n\t\t\tTRIverts[2].modulate[2] = 255;\n\t\t\tTRIverts[2].modulate[3] = 255 * p->alpha;\t\n\t\t}\n\t\n\t}\n\telse if (p->type == P_SPRITE)\n\t{\n\t\tvec3_t\trr, ru;\n\t\tvec3_t\trotate_ang;\n\n\t\tVectorSet (color, 1.0, 1.0, 1.0);\n\t\ttime = cg.time - p->time;\n\t\ttime2 = p->endtime - p->time;\n\t\tratio = time / time2;\n\n\t\twidth = p->width + ( ratio * ( p->endwidth - p->width) );\n\t\theight = p->height + ( ratio * ( p->endheight - p->height) );\n\n\t\tif (p->roll) {\n\t\t\tvectoangles( cg.refdef.viewaxis[0], rotate_ang );\n\t\t\trotate_ang[ROLL] += p->roll;\n\t\t\tAngleVectors ( rotate_ang, NULL, rr, ru);\n\t\t}\n\n\t\tif (p->roll) {\n\t\t\tVectorMA (org, -height, ru, point);\t\n\t\t\tVectorMA (point, -width, rr, point);\t\n\t\t} else {\n\t\t\tVectorMA (org, -height, vup, point);\t\n\t\t\tVectorMA (point, -width, vright, point);\t\n\t\t}\n\t\tVectorCopy (point, verts[0].xyz);\t\n\t\tverts[0].st[0] = 0;\t\n\t\tverts[0].st[1] = 0;\t\n\t\tverts[0].modulate[0] = 255;\t\n\t\tverts[0].modulate[1] = 255;\t\n\t\tverts[0].modulate[2] = 255;\t\n\t\tverts[0].modulate[3] = 255;\n\n\t\tif (p->roll) {\n\t\t\tVectorMA (point, 2*height, ru, point);\t\n\t\t} else {\n\t\t\tVectorMA (point, 2*height, vup, point);\t\n\t\t}\n\t\tVectorCopy (point, verts[1].xyz);\t\n\t\tverts[1].st[0] = 0;\t\n\t\tverts[1].st[1] = 1;\t\n\t\tverts[1].modulate[0] = 255;\t\n\t\tverts[1].modulate[1] = 255;\t\n\t\tverts[1].modulate[2] = 255;\t\n\t\tverts[1].modulate[3] = 255;\t\n\n\t\tif (p->roll) {\n\t\t\tVectorMA (point, 2*width, rr, point);\t\n\t\t} else {\n\t\t\tVectorMA (point, 2*width, vright, point);\t\n\t\t}\n\t\tVectorCopy (point, verts[2].xyz);\t\n\t\tverts[2].st[0] = 1;\t\n\t\tverts[2].st[1] = 1;\t\n\t\tverts[2].modulate[0] = 255;\t\n\t\tverts[2].modulate[1] = 255;\t\n\t\tverts[2].modulate[2] = 255;\t\n\t\tverts[2].modulate[3] = 255;\t\n\n\t\tif (p->roll) {\n\t\t\tVectorMA (point, -2*height, ru, point);\t\n\t\t} else {\n\t\t\tVectorMA (point, -2*height, vup, point);\t\n\t\t}\n\t\tVectorCopy (point, verts[3].xyz);\t\n\t\tverts[3].st[0] = 1;\t\n\t\tverts[3].st[1] = 0;\t\n\t\tverts[3].modulate[0] = 255;\t\n\t\tverts[3].modulate[1] = 255;\t\n\t\tverts[3].modulate[2] = 255;\t\n\t\tverts[3].modulate[3] = 255;\t\n\t}\n\telse if (p->type == P_SMOKE || p->type == P_SMOKE_IMPACT)\n\t{// create a front rotating facing polygon\n\n\t\tif ( p->type == P_SMOKE_IMPACT && Distance( cg.snap->ps.origin, org ) > 1024) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (p->color == BLOODRED)\n\t\t\tVectorSet (color, 0.22f, 0.0f, 0.0f);\n\t\telse if (p->color == GREY75)\n\t\t{\n\t\t\tfloat\tlen;\n\t\t\tfloat\tgreyit;\n\t\t\tfloat\tval;\n\t\t\tlen = Distance (cg.snap->ps.origin, org);\n\t\t\tif (!len)\n\t\t\t\tlen = 1;\n\n\t\t\tval = 4096/len;\n\t\t\tgreyit = 0.25 * val;\n\t\t\tif (greyit > 0.5)\n\t\t\t\tgreyit = 0.5;\n\n\t\t\tVectorSet (color, greyit, greyit, greyit);\n\t\t}\n\t\telse\n\t\t\tVectorSet (color, 1.0, 1.0, 1.0);\n\n\t\ttime = cg.time - p->time;\n\t\ttime2 = p->endtime - p->time;\n\t\tratio = time / time2;\n\t\t\n\t\tif (cg.time > p->startfade)\n\t\t{\n\t\t\tinvratio = 1 - ( (cg.time - p->startfade) / (p->endtime - p->startfade) );\n\n\t\t\tif (p->color == EMISIVEFADE)\n\t\t\t{\n\t\t\t\tfloat fval;\n\t\t\t\tfval = (invratio * invratio);\n\t\t\t\tif (fval < 0)\n\t\t\t\t\tfval = 0;\n\t\t\t\tVectorSet (color, fval , fval , fval );\n\t\t\t}\n\t\t\tinvratio *= p->alpha;\n\t\t}\n\t\telse \n\t\t\tinvratio = 1 * p->alpha;\n\n\t\tif ( cgs.glconfig.hardwareType == GLHW_RAGEPRO )\n\t\t\tinvratio = 1;\n\n\t\tif (invratio > 1)\n\t\t\tinvratio = 1;\n\t\n\t\twidth = p->width + ( ratio * ( p->endwidth - p->width) );\n\t\theight = p->height + ( ratio * ( p->endheight - p->height) );\n\n\t\tif (p->type != P_SMOKE_IMPACT)\n\t\t{\n\t\t\tvec3_t temp;\n\n\t\t\tvectoangles (rforward, temp);\n\t\t\tp->accumroll += p->roll;\n\t\t\ttemp[ROLL] += p->accumroll * 0.1;\n\t\t\tAngleVectors ( temp, NULL, rright2, rup2);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tVectorCopy (rright, rright2);\n\t\t\tVectorCopy (rup, rup2);\n\t\t}\n\t\t\n\t\tif (p->rotate)\n\t\t{\n\t\t\tVectorMA (org, -height, rup2, point);\t\n\t\t\tVectorMA (point, -width, rright2, point);\t\n\t\t}\n\t\telse\n\t\t{\n\t\t\tVectorMA (org, -p->height, vup, point);\t\n\t\t\tVectorMA (point, -p->width, vright, point);\t\n\t\t}\n\t\tVectorCopy (point, verts[0].xyz);\t\n\t\tverts[0].st[0] = 0;\t\n\t\tverts[0].st[1] = 0;\t\n\t\tverts[0].modulate[0] = 255 * color[0];\t\n\t\tverts[0].modulate[1] = 255 * color[1];\t\n\t\tverts[0].modulate[2] = 255 * color[2];\t\n\t\tverts[0].modulate[3] = 255 * invratio;\t\n\n\t\tif (p->rotate)\n\t\t{\n\t\t\tVectorMA (org, -height, rup2, point);\t\n\t\t\tVectorMA (point, width, rright2, point);\t\n\t\t}\n\t\telse\n\t\t{\n\t\t\tVectorMA (org, -p->height, vup, point);\t\n\t\t\tVectorMA (point, p->width, vright, point);\t\n\t\t}\n\t\tVectorCopy (point, verts[1].xyz);\t\n\t\tverts[1].st[0] = 0;\t\n\t\tverts[1].st[1] = 1;\t\n\t\tverts[1].modulate[0] = 255 * color[0];\t\n\t\tverts[1].modulate[1] = 255 * color[1];\t\n\t\tverts[1].modulate[2] = 255 * color[2];\t\n\t\tverts[1].modulate[3] = 255 * invratio;\t\n\n\t\tif (p->rotate)\n\t\t{\n\t\t\tVectorMA (org, height, rup2, point);\t\n\t\t\tVectorMA (point, width, rright2, point);\t\n\t\t}\n\t\telse\n\t\t{\n\t\t\tVectorMA (org, p->height, vup, point);\t\n\t\t\tVectorMA (point, p->width, vright, point);\t\n\t\t}\n\t\tVectorCopy (point, verts[2].xyz);\t\n\t\tverts[2].st[0] = 1;\t\n\t\tverts[2].st[1] = 1;\t\n\t\tverts[2].modulate[0] = 255 * color[0];\t\n\t\tverts[2].modulate[1] = 255 * color[1];\t\n\t\tverts[2].modulate[2] = 255 * color[2];\t\n\t\tverts[2].modulate[3] = 255 * invratio;\t\n\n\t\tif (p->rotate)\n\t\t{\n\t\t\tVectorMA (org, height, rup2, point);\t\n\t\t\tVectorMA (point, -width, rright2, point);\t\n\t\t}\n\t\telse\n\t\t{\n\t\t\tVectorMA (org, p->height, vup, point);\t\n\t\t\tVectorMA (point, -p->width, vright, point);\t\n\t\t}\n\t\tVectorCopy (point, verts[3].xyz);\t\n\t\tverts[3].st[0] = 1;\t\n\t\tverts[3].st[1] = 0;\t\n\t\tverts[3].modulate[0] = 255 * color[0];\t\n\t\tverts[3].modulate[1] = 255 * color[1];\t\n\t\tverts[3].modulate[2] = 255 * color[2];\t\n\t\tverts[3].modulate[3] = 255  * invratio;\t\n\t\t\n\t}\n\telse if (p->type == P_BLEED)\n\t{\n\t\tvec3_t\trr, ru;\n\t\tvec3_t\trotate_ang;\n\t\tfloat\talpha;\n\n\t\talpha = p->alpha;\n\t\t\n\t\tif ( cgs.glconfig.hardwareType == GLHW_RAGEPRO )\n\t\t\talpha = 1;\n\n\t\tif (p->roll) \n\t\t{\n\t\t\tvectoangles( cg.refdef.viewaxis[0], rotate_ang );\n\t\t\trotate_ang[ROLL] += p->roll;\n\t\t\tAngleVectors ( rotate_ang, NULL, rr, ru);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tVectorCopy (vup, ru);\n\t\t\tVectorCopy (vright, rr);\n\t\t}\n\n\t\tVectorMA (org, -p->height, ru, point);\t\n\t\tVectorMA (point, -p->width, rr, point);\t\n\t\tVectorCopy (point, verts[0].xyz);\t\n\t\tverts[0].st[0] = 0;\t\n\t\tverts[0].st[1] = 0;\t\n\t\tverts[0].modulate[0] = 111;\t\n\t\tverts[0].modulate[1] = 19;\t\n\t\tverts[0].modulate[2] = 9;\t\n\t\tverts[0].modulate[3] = 255 * alpha;\t\n\n\t\tVectorMA (org, -p->height, ru, point);\t\n\t\tVectorMA (point, p->width, rr, point);\t\n\t\tVectorCopy (point, verts[1].xyz);\t\n\t\tverts[1].st[0] = 0;\t\n\t\tverts[1].st[1] = 1;\t\n\t\tverts[1].modulate[0] = 111;\t\n\t\tverts[1].modulate[1] = 19;\t\n\t\tverts[1].modulate[2] = 9;\t\n\t\tverts[1].modulate[3] = 255 * alpha;\t\n\n\t\tVectorMA (org, p->height, ru, point);\t\n\t\tVectorMA (point, p->width, rr, point);\t\n\t\tVectorCopy (point, verts[2].xyz);\t\n\t\tverts[2].st[0] = 1;\t\n\t\tverts[2].st[1] = 1;\t\n\t\tverts[2].modulate[0] = 111;\t\n\t\tverts[2].modulate[1] = 19;\t\n\t\tverts[2].modulate[2] = 9;\t\n\t\tverts[2].modulate[3] = 255 * alpha;\t\n\n\t\tVectorMA (org, p->height, ru, point);\t\n\t\tVectorMA (point, -p->width, rr, point);\t\n\t\tVectorCopy (point, verts[3].xyz);\t\n\t\tverts[3].st[0] = 1;\t\n\t\tverts[3].st[1] = 0;\t\n\t\tverts[3].modulate[0] = 111;\t\n\t\tverts[3].modulate[1] = 19;\t\n\t\tverts[3].modulate[2] = 9;\t\n\t\tverts[3].modulate[3] = 255 * alpha;\t\n\n\t}\n\telse if (p->type == P_FLAT_SCALEUP)\n\t{\n\t\tfloat width, height;\n\t\tfloat sinR, cosR;\n\n\t\tif (p->color == BLOODRED)\n\t\t\tVectorSet (color, 1, 1, 1);\n\t\telse\n\t\t\tVectorSet (color, 0.5, 0.5, 0.5);\n\t\t\n\t\ttime = cg.time - p->time;\n\t\ttime2 = p->endtime - p->time;\n\t\tratio = time / time2;\n\n\t\twidth = p->width + ( ratio * ( p->endwidth - p->width) );\n\t\theight = p->height + ( ratio * ( p->endheight - p->height) );\n\n\t\tif (width > p->endwidth)\n\t\t\twidth = p->endwidth;\n\n\t\tif (height > p->endheight)\n\t\t\theight = p->endheight;\n\n\t\tsinR = height * sin(DEG2RAD(p->roll)) * sqrt(2);\n\t\tcosR = width * cos(DEG2RAD(p->roll)) * sqrt(2);\n\n\t\tVectorCopy (org, verts[0].xyz);\t\n\t\tverts[0].xyz[0] -= sinR;\n\t\tverts[0].xyz[1] -= cosR;\n\t\tverts[0].st[0] = 0;\t\n\t\tverts[0].st[1] = 0;\t\n\t\tverts[0].modulate[0] = 255 * color[0];\t\n\t\tverts[0].modulate[1] = 255 * color[1];\t\n\t\tverts[0].modulate[2] = 255 * color[2];\t\n\t\tverts[0].modulate[3] = 255;\t\n\n\t\tVectorCopy (org, verts[1].xyz);\t\n\t\tverts[1].xyz[0] -= cosR;\t\n\t\tverts[1].xyz[1] += sinR;\t\n\t\tverts[1].st[0] = 0;\t\n\t\tverts[1].st[1] = 1;\t\n\t\tverts[1].modulate[0] = 255 * color[0];\t\n\t\tverts[1].modulate[1] = 255 * color[1];\t\n\t\tverts[1].modulate[2] = 255 * color[2];\t\n\t\tverts[1].modulate[3] = 255;\t\n\n\t\tVectorCopy (org, verts[2].xyz);\t\n\t\tverts[2].xyz[0] += sinR;\t\n\t\tverts[2].xyz[1] += cosR;\t\n\t\tverts[2].st[0] = 1;\t\n\t\tverts[2].st[1] = 1;\t\n\t\tverts[2].modulate[0] = 255 * color[0];\t\n\t\tverts[2].modulate[1] = 255 * color[1];\t\n\t\tverts[2].modulate[2] = 255 * color[2];\t\n\t\tverts[2].modulate[3] = 255;\t\n\n\t\tVectorCopy (org, verts[3].xyz);\t\n\t\tverts[3].xyz[0] += cosR;\t\n\t\tverts[3].xyz[1] -= sinR;\t\n\t\tverts[3].st[0] = 1;\t\n\t\tverts[3].st[1] = 0;\t\n\t\tverts[3].modulate[0] = 255 * color[0];\t\n\t\tverts[3].modulate[1] = 255 * color[1];\t\n\t\tverts[3].modulate[2] = 255 * color[2];\t\n\t\tverts[3].modulate[3] = 255;\t\t\n\t}\n\telse if (p->type == P_FLAT)\n\t{\n\n\t\tVectorCopy (org, verts[0].xyz);\t\n\t\tverts[0].xyz[0] -= p->height;\t\n\t\tverts[0].xyz[1] -= p->width;\t\n\t\tverts[0].st[0] = 0;\t\n\t\tverts[0].st[1] = 0;\t\n\t\tverts[0].modulate[0] = 255;\t\n\t\tverts[0].modulate[1] = 255;\t\n\t\tverts[0].modulate[2] = 255;\t\n\t\tverts[0].modulate[3] = 255;\t\n\n\t\tVectorCopy (org, verts[1].xyz);\t\n\t\tverts[1].xyz[0] -= p->height;\t\n\t\tverts[1].xyz[1] += p->width;\t\n\t\tverts[1].st[0] = 0;\t\n\t\tverts[1].st[1] = 1;\t\n\t\tverts[1].modulate[0] = 255;\t\n\t\tverts[1].modulate[1] = 255;\t\n\t\tverts[1].modulate[2] = 255;\t\n\t\tverts[1].modulate[3] = 255;\t\n\n\t\tVectorCopy (org, verts[2].xyz);\t\n\t\tverts[2].xyz[0] += p->height;\t\n\t\tverts[2].xyz[1] += p->width;\t\n\t\tverts[2].st[0] = 1;\t\n\t\tverts[2].st[1] = 1;\t\n\t\tverts[2].modulate[0] = 255;\t\n\t\tverts[2].modulate[1] = 255;\t\n\t\tverts[2].modulate[2] = 255;\t\n\t\tverts[2].modulate[3] = 255;\t\n\n\t\tVectorCopy (org, verts[3].xyz);\t\n\t\tverts[3].xyz[0] += p->height;\t\n\t\tverts[3].xyz[1] -= p->width;\t\n\t\tverts[3].st[0] = 1;\t\n\t\tverts[3].st[1] = 0;\t\n\t\tverts[3].modulate[0] = 255;\t\n\t\tverts[3].modulate[1] = 255;\t\n\t\tverts[3].modulate[2] = 255;\t\n\t\tverts[3].modulate[3] = 255;\t\n\n\t}\n\t// Ridah\n\telse if (p->type == P_ANIM) {\n\t\tvec3_t\trr, ru;\n\t\tvec3_t\trotate_ang;\n\t\tint i, j;\n\n\t\ttime = cg.time - p->time;\n\t\ttime2 = p->endtime - p->time;\n\t\tratio = time / time2;\n\t\tif (ratio >= 1.0f) {\n\t\t\tratio = 0.9999f;\n\t\t}\n\n\t\twidth = p->width + ( ratio * ( p->endwidth - p->width) );\n\t\theight = p->height + ( ratio * ( p->endheight - p->height) );\n\n\t\t// if we are \"inside\" this sprite, don't draw\n\t\tif (Distance( cg.snap->ps.origin, org ) < width/1.5) {\n\t\t\treturn;\n\t\t}\n\n\t\ti = p->shaderAnim;\n\t\tj = (int)floor(ratio * shaderAnimCounts[p->shaderAnim]);\n\t\tp->pshader = shaderAnims[i][j];\n\n\t\tif (p->roll) {\n\t\t\tvectoangles( cg.refdef.viewaxis[0], rotate_ang );\n\t\t\trotate_ang[ROLL] += p->roll;\n\t\t\tAngleVectors ( rotate_ang, NULL, rr, ru);\n\t\t}\n\n\t\tif (p->roll) {\n\t\t\tVectorMA (org, -height, ru, point);\t\n\t\t\tVectorMA (point, -width, rr, point);\t\n\t\t} else {\n\t\t\tVectorMA (org, -height, vup, point);\t\n\t\t\tVectorMA (point, -width, vright, point);\t\n\t\t}\n\t\tVectorCopy (point, verts[0].xyz);\t\n\t\tverts[0].st[0] = 0;\t\n\t\tverts[0].st[1] = 0;\t\n\t\tverts[0].modulate[0] = 255;\t\n\t\tverts[0].modulate[1] = 255;\t\n\t\tverts[0].modulate[2] = 255;\t\n\t\tverts[0].modulate[3] = 255;\n\n\t\tif (p->roll) {\n\t\t\tVectorMA (point, 2*height, ru, point);\t\n\t\t} else {\n\t\t\tVectorMA (point, 2*height, vup, point);\t\n\t\t}\n\t\tVectorCopy (point, verts[1].xyz);\t\n\t\tverts[1].st[0] = 0;\t\n\t\tverts[1].st[1] = 1;\t\n\t\tverts[1].modulate[0] = 255;\t\n\t\tverts[1].modulate[1] = 255;\t\n\t\tverts[1].modulate[2] = 255;\t\n\t\tverts[1].modulate[3] = 255;\t\n\n\t\tif (p->roll) {\n\t\t\tVectorMA (point, 2*width, rr, point);\t\n\t\t} else {\n\t\t\tVectorMA (point, 2*width, vright, point);\t\n\t\t}\n\t\tVectorCopy (point, verts[2].xyz);\t\n\t\tverts[2].st[0] = 1;\t\n\t\tverts[2].st[1] = 1;\t\n\t\tverts[2].modulate[0] = 255;\t\n\t\tverts[2].modulate[1] = 255;\t\n\t\tverts[2].modulate[2] = 255;\t\n\t\tverts[2].modulate[3] = 255;\t\n\n\t\tif (p->roll) {\n\t\t\tVectorMA (point, -2*height, ru, point);\t\n\t\t} else {\n\t\t\tVectorMA (point, -2*height, vup, point);\t\n\t\t}\n\t\tVectorCopy (point, verts[3].xyz);\t\n\t\tverts[3].st[0] = 1;\t\n\t\tverts[3].st[1] = 0;\t\n\t\tverts[3].modulate[0] = 255;\t\n\t\tverts[3].modulate[1] = 255;\t\n\t\tverts[3].modulate[2] = 255;\t\n\t\tverts[3].modulate[3] = 255;\t\n\t}\n\t// done.\n\t\n\tif (!p->pshader) {\n// (SA) temp commented out for DM\n//\t\tCG_Printf (\"CG_AddParticleToScene type %d p->pshader == ZERO\\n\", p->type);\n\t\treturn;\n\t}\n\n\tif (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT || p->type == P_WEATHER_FLURRY)\n\t\ttrap_R_AddPolyToScene( p->pshader, 3, TRIverts );\n\telse\n\t\ttrap_R_AddPolyToScene( p->pshader, 4, verts );\n\n}\n\n// Ridah, made this static so it doesn't interfere with other files\nstatic float roll = 0.0;\n\n/*\n===============\nCG_AddParticles\n===============\n*/\nvoid CG_AddParticles (void)\n{\n\tcparticle_t\t\t*p, *next;\n\tfloat\t\t\talpha;\n\tfloat\t\t\ttime, time2;\n\tvec3_t\t\t\torg;\n\tint\t\t\t\tcolor;\n\tcparticle_t\t\t*active, *tail;\n\tint\t\t\t\ttype;\n\tvec3_t\t\t\trotate_ang;\n\n\tif (!initparticles)\n\t\tCG_ClearParticles ();\n\n\tVectorCopy( cg.refdef.viewaxis[0], vforward );\n\tVectorCopy( cg.refdef.viewaxis[1], vright );\n\tVectorCopy( cg.refdef.viewaxis[2], vup );\n\n\tvectoangles( cg.refdef.viewaxis[0], rotate_ang );\n\troll += ((cg.time - oldtime) * 0.1) ;\n\trotate_ang[ROLL] += (roll*0.9);\n\tAngleVectors ( rotate_ang, rforward, rright, rup);\n\t\n\toldtime = cg.time;\n\n\tactive = NULL;\n\ttail = NULL;\n\n\tfor (p=active_particles ; p ; p=next)\n\t{\n\n\t\tnext = p->next;\n\n\t\ttime = (cg.time - p->time)*0.001;\n\n\t\talpha = p->alpha + time*p->alphavel;\n\t\tif (alpha <= 0)\n\t\t{\t// faded out\n\t\t\tp->next = free_particles;\n\t\t\tfree_particles = p;\n\t\t\tp->type = 0;\n\t\t\tp->color = 0;\n\t\t\tp->alpha = 0;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (p->type == P_SMOKE || p->type == P_ANIM || p->type == P_BLEED || p->type == P_SMOKE_IMPACT)\n\t\t{\n\t\t\tif (cg.time > p->endtime)\n\t\t\t{\n\t\t\t\tp->next = free_particles;\n\t\t\t\tfree_particles = p;\n\t\t\t\tp->type = 0;\n\t\t\t\tp->color = 0;\n\t\t\t\tp->alpha = 0;\n\t\t\t\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t}\n\n\t\tif (p->type == P_WEATHER_FLURRY)\n\t\t{\n\t\t\tif (cg.time > p->endtime)\n\t\t\t{\n\t\t\t\tp->next = free_particles;\n\t\t\t\tfree_particles = p;\n\t\t\t\tp->type = 0;\n\t\t\t\tp->color = 0;\n\t\t\t\tp->alpha = 0;\n\t\t\t\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\n\t\tif (p->type == P_FLAT_SCALEUP_FADE)\n\t\t{\n\t\t\tif (cg.time > p->endtime)\n\t\t\t{\n\t\t\t\tp->next = free_particles;\n\t\t\t\tfree_particles = p;\n\t\t\t\tp->type = 0;\n\t\t\t\tp->color = 0;\n\t\t\t\tp->alpha = 0;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t}\n\n\t\tif ((p->type == P_BAT || p->type == P_SPRITE) && p->endtime < 0) {\n\t\t\t// temporary sprite\n\t\t\tCG_AddParticleToScene (p, p->org, alpha);\n\t\t\tp->next = free_particles;\n\t\t\tfree_particles = p;\n\t\t\tp->type = 0;\n\t\t\tp->color = 0;\n\t\t\tp->alpha = 0;\n\t\t\tcontinue;\n\t\t}\n\n\t\tp->next = NULL;\n\t\tif (!tail)\n\t\t\tactive = tail = p;\n\t\telse\n\t\t{\n\t\t\ttail->next = p;\n\t\t\ttail = p;\n\t\t}\n\n\t\tif (alpha > 1.0)\n\t\t\talpha = 1;\n\n\t\tcolor = p->color;\n\n\t\ttime2 = time*time;\n\n\t\torg[0] = p->org[0] + p->vel[0]*time + p->accel[0]*time2;\n\t\torg[1] = p->org[1] + p->vel[1]*time + p->accel[1]*time2;\n\t\torg[2] = p->org[2] + p->vel[2]*time + p->accel[2]*time2;\n\n\t\ttype = p->type;\n\n\t\tCG_AddParticleToScene (p, org, alpha);\n\t}\n\n\tactive_particles = active;\n}\n\n/*\n======================\nCG_AddParticles\n======================\n*/\nvoid CG_ParticleSnowFlurry (qhandle_t pshader, centity_t *cent)\n{\n\tcparticle_t\t*p;\n\tqboolean turb = qtrue;\n\n\tif (!pshader)\n\t\tCG_Printf (\"CG_ParticleSnowFlurry pshader == ZERO!\\n\");\n\n\tif (!free_particles)\n\t\treturn;\n\tp = free_particles;\n\tfree_particles = p->next;\n\tp->next = active_particles;\n\tactive_particles = p;\n\tp->time = cg.time;\n\tp->color = 0;\n\tp->alpha = 0.90f;\n\tp->alphavel = 0;\n\n\tp->start = cent->currentState.origin2[0];\n\tp->end = cent->currentState.origin2[1];\n\t\n\tp->endtime = cg.time + cent->currentState.time;\n\tp->startfade = cg.time + cent->currentState.time2;\n\t\n\tp->pshader = pshader;\n\t\n\tif (rand()%100 > 90)\n\t{\n\t\tp->height = 32;\n\t\tp->width = 32;\n\t\tp->alpha = 0.10f;\n\t}\n\telse\n\t{\n\t\tp->height = 1;\n\t\tp->width = 1;\n\t}\n\n\tp->vel[2] = -20;\n\n\tp->type = P_WEATHER_FLURRY;\n\t\n\tif (turb)\n\t\tp->vel[2] = -10;\n\t\n\tVectorCopy(cent->currentState.origin, p->org);\n\n\tp->org[0] = p->org[0];\n\tp->org[1] = p->org[1];\n\tp->org[2] = p->org[2];\n\n\tp->vel[0] = p->vel[1] = 0;\n\t\n\tp->accel[0] = p->accel[1] = p->accel[2] = 0;\n\n\tp->vel[0] += cent->currentState.angles[0] * 32 + (crandom() * 16);\n\tp->vel[1] += cent->currentState.angles[1] * 32 + (crandom() * 16);\n\tp->vel[2] += cent->currentState.angles[2];\n\n\tif (turb)\n\t{\n\t\tp->accel[0] = crandom () * 16;\n\t\tp->accel[1] = crandom () * 16;\n\t}\n\n}\n\nvoid CG_ParticleSnow (qhandle_t pshader, vec3_t origin, vec3_t origin2, int turb, float range, int snum)\n{\n\tcparticle_t\t*p;\n\n\tif (!pshader)\n\t\tCG_Printf (\"CG_ParticleSnow pshader == ZERO!\\n\");\n\n\tif (!free_particles)\n\t\treturn;\n\tp = free_particles;\n\tfree_particles = p->next;\n\tp->next = active_particles;\n\tactive_particles = p;\n\tp->time = cg.time;\n\tp->color = 0;\n\tp->alpha = 0.40f;\n\tp->alphavel = 0;\n\tp->start = origin[2];\n\tp->end = origin2[2];\n\tp->pshader = pshader;\n\tp->height = 1;\n\tp->width = 1;\n\t\n\tp->vel[2] = -50;\n\n\tif (turb)\n\t{\n\t\tp->type = P_WEATHER_TURBULENT;\n\t\tp->vel[2] = -50 * 1.3;\n\t}\n\telse\n\t{\n\t\tp->type = P_WEATHER;\n\t}\n\t\n\tVectorCopy(origin, p->org);\n\n\tp->org[0] = p->org[0] + ( crandom() * range);\n\tp->org[1] = p->org[1] + ( crandom() * range);\n\tp->org[2] = p->org[2] + ( crandom() * (p->start - p->end)); \n\n\tp->vel[0] = p->vel[1] = 0;\n\t\n\tp->accel[0] = p->accel[1] = p->accel[2] = 0;\n\n\tif (turb)\n\t{\n\t\tp->vel[0] = crandom() * 16;\n\t\tp->vel[1] = crandom() * 16;\n\t}\n\n\t// Rafael snow pvs check\n\tp->snum = snum;\n\tp->link = qtrue;\n\n}\n\nvoid CG_ParticleBubble (qhandle_t pshader, vec3_t origin, vec3_t origin2, int turb, float range, int snum)\n{\n\tcparticle_t\t*p;\n\tfloat\t\trandsize;\n\n\tif (!pshader)\n\t\tCG_Printf (\"CG_ParticleSnow pshader == ZERO!\\n\");\n\n\tif (!free_particles)\n\t\treturn;\n\tp = free_particles;\n\tfree_particles = p->next;\n\tp->next = active_particles;\n\tactive_particles = p;\n\tp->time = cg.time;\n\tp->color = 0;\n\tp->alpha = 0.40f;\n\tp->alphavel = 0;\n\tp->start = origin[2];\n\tp->end = origin2[2];\n\tp->pshader = pshader;\n\t\n\trandsize = 1 + (crandom() * 0.5);\n\t\n\tp->height = randsize;\n\tp->width = randsize;\n\t\n\tp->vel[2] = 50 + ( crandom() * 10 );\n\n\tif (turb)\n\t{\n\t\tp->type = P_BUBBLE_TURBULENT;\n\t\tp->vel[2] = 50 * 1.3;\n\t}\n\telse\n\t{\n\t\tp->type = P_BUBBLE;\n\t}\n\t\n\tVectorCopy(origin, p->org);\n\n\tp->org[0] = p->org[0] + ( crandom() * range);\n\tp->org[1] = p->org[1] + ( crandom() * range);\n\tp->org[2] = p->org[2] + ( crandom() * (p->start - p->end)); \n\n\tp->vel[0] = p->vel[1] = 0;\n\t\n\tp->accel[0] = p->accel[1] = p->accel[2] = 0;\n\n\tif (turb)\n\t{\n\t\tp->vel[0] = crandom() * 4;\n\t\tp->vel[1] = crandom() * 4;\n\t}\n\n\t// Rafael snow pvs check\n\tp->snum = snum;\n\tp->link = qtrue;\n\n}\n\nvoid CG_ParticleSmoke (qhandle_t pshader, centity_t *cent)\n{\n\n\t// using cent->density = enttime\n\t//\t\t cent->frame = startfade\n\tcparticle_t\t*p;\n\n\tif (!pshader)\n\t\tCG_Printf (\"CG_ParticleSmoke == ZERO!\\n\");\n\n\tif (!free_particles)\n\t\treturn;\n\tp = free_particles;\n\tfree_particles = p->next;\n\tp->next = active_particles;\n\tactive_particles = p;\n\tp->time = cg.time;\n\t\n\tp->endtime = cg.time + cent->currentState.time;\n\tp->startfade = cg.time + cent->currentState.time2;\n\t\n\tp->color = 0;\n\tp->alpha = 1.0;\n\tp->alphavel = 0;\n\tp->start = cent->currentState.origin[2];\n\tp->end = cent->currentState.origin2[2];\n\tp->pshader = pshader;\n\tp->rotate = qfalse;\n\tp->height = 8;\n\tp->width = 8;\n\tp->endheight = 32;\n\tp->endwidth = 32;\n\tp->type = P_SMOKE;\n\t\n\tVectorCopy(cent->currentState.origin, p->org);\n\n\tp->vel[0] = p->vel[1] = 0;\n\tp->accel[0] = p->accel[1] = p->accel[2] = 0;\n\n\tp->vel[2] = 5;\n\n\tif (cent->currentState.frame == 1)// reverse gravity\t\n\t\tp->vel[2] *= -1;\n\n\tp->roll = 8 + (crandom() * 4);\n}\n\n\nvoid CG_ParticleBulletDebris (vec3_t org, vec3_t vel, int duration)\n{\n\n\tcparticle_t\t*p;\n\n\tif (!free_particles)\n\t\treturn;\n\tp = free_particles;\n\tfree_particles = p->next;\n\tp->next = active_particles;\n\tactive_particles = p;\n\tp->time = cg.time;\n\t\n\tp->endtime = cg.time + duration;\n\tp->startfade = cg.time + duration/2;\n\t\n\tp->color = EMISIVEFADE;\n\tp->alpha = 1.0;\n\tp->alphavel = 0;\n\n\tp->height = 0.5;\n\tp->width = 0.5;\n\tp->endheight = 0.5;\n\tp->endwidth = 0.5;\n\n\tp->pshader = cgs.media.tracerShader;\n\n\tp->type = P_SMOKE;\n\t\n\tVectorCopy(org, p->org);\n\n\tp->vel[0] = vel[0];\n\tp->vel[1] = vel[1];\n\tp->vel[2] = vel[2];\n\tp->accel[0] = p->accel[1] = p->accel[2] = 0;\n\n\tp->accel[2] = -60;\n\tp->vel[2] += -20;\n\t\n}\n\n/*\n======================\nCG_ParticleExplosion\n======================\n*/\n\nvoid CG_ParticleExplosion (char *animStr, vec3_t origin, vec3_t vel, int duration, int sizeStart, int sizeEnd)\n{\n\tcparticle_t\t*p;\n\tint anim;\n\n\tif (animStr < (char *)10)\n\t\tCG_Error( \"CG_ParticleExplosion: animStr is probably an index rather than a string\" );\n\n\t// find the animation string\n\tfor (anim=0; shaderAnimNames[anim]; anim++) {\n\t\tif (!stricmp( animStr, shaderAnimNames[anim] ))\n\t\t\tbreak;\n\t}\n\tif (!shaderAnimNames[anim]) {\n\t\tCG_Error(\"CG_ParticleExplosion: unknown animation string: %s\\n\", animStr);\n\t\treturn;\n\t}\n\n\tif (!free_particles)\n\t\treturn;\n\tp = free_particles;\n\tfree_particles = p->next;\n\tp->next = active_particles;\n\tactive_particles = p;\n\tp->time = cg.time;\n\tp->alpha = 1.0;\n\tp->alphavel = 0;\n\n\tif (duration < 0) {\n\t\tduration *= -1;\n\t\tp->roll = 0;\n\t} else {\n\t\tp->roll = crandom()*179;\n\t}\n\n\tp->shaderAnim = anim;\n\n\tp->width = sizeStart;\n\tp->height = sizeStart*shaderAnimSTRatio[anim];\t// for sprites that are stretch in either direction\n\n\tp->endheight = sizeEnd;\n\tp->endwidth = sizeEnd*shaderAnimSTRatio[anim];\n\n\tp->endtime = cg.time + duration;\n\n\tp->type = P_ANIM;\n\n\tVectorCopy( origin, p->org );\n\tVectorCopy( vel, p->vel );\n\tVectorClear( p->accel );\n\n}\n\n// Rafael Shrapnel\nvoid CG_AddParticleShrapnel (localEntity_t *le)\n{\n\treturn;\n}\n// done.\n\nint CG_NewParticleArea (int num)\n{\n\t// const char *str;\n\tchar *str;\n\tchar *token;\n\tint type;\n\tvec3_t origin, origin2;\n\tint\t\ti;\n\tfloat range = 0;\n\tint turb;\n\tint\tnumparticles;\n\tint\tsnum;\n\t\n\tstr = (char *) CG_ConfigString (num);\n\tif (!str[0])\n\t\treturn (0);\n\t\n\t// returns type 128 64 or 32\n\ttoken = COM_Parse (&str);\n\ttype = atoi (token);\n\t\n\tif (type == 1)\n\t\trange = 128;\n\telse if (type == 2)\n\t\trange = 64;\n\telse if (type == 3)\n\t\trange = 32;\n\telse if (type == 0)\n\t\trange = 256;\n\telse if (type == 4)\n\t\trange = 8;\n\telse if (type == 5)\n\t\trange = 16;\n\telse if (type == 6)\n\t\trange = 32;\n\telse if (type == 7)\n\t\trange = 64;\n\n\n\tfor (i=0; i<3; i++)\n\t{\n\t\ttoken = COM_Parse (&str);\n\t\torigin[i] = atof (token);\n\t}\n\n\tfor (i=0; i<3; i++)\n\t{\n\t\ttoken = COM_Parse (&str);\n\t\torigin2[i] = atof (token);\n\t}\n\t\t\n\ttoken = COM_Parse (&str);\n\tnumparticles = atoi (token);\n\t\n\ttoken = COM_Parse (&str);\n\tturb = atoi (token);\n\n\ttoken = COM_Parse (&str);\n\tsnum = atoi (token);\n\t\n\tfor (i=0; i<numparticles; i++)\n\t{\n\t\tif (type >= 4)\n\t\t\tCG_ParticleBubble (cgs.media.waterBubbleShader, origin, origin2, turb, range, snum);\n\t\telse\n\t\t\tCG_ParticleSnow (cgs.media.waterBubbleShader, origin, origin2, turb, range, snum);\n\t}\n\n\treturn (1);\n}\n\nvoid\tCG_SnowLink (centity_t *cent, qboolean particleOn)\n{\n\tcparticle_t\t\t*p, *next;\n\tint id;\n\n\tid = cent->currentState.frame;\n\n\tfor (p=active_particles ; p ; p=next)\n\t{\n\t\tnext = p->next;\n\t\t\n\t\tif (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT)\n\t\t{\n\t\t\tif (p->snum == id)\n\t\t\t{\n\t\t\t\tif (particleOn)\n\t\t\t\t\tp->link = qtrue;\n\t\t\t\telse\n\t\t\t\t\tp->link = qfalse;\n\t\t\t}\n\t\t}\n\n\t}\n}\n\nvoid CG_ParticleImpactSmokePuff (qhandle_t pshader, vec3_t origin)\n{\n\tcparticle_t\t*p;\n\n\tif (!pshader)\n\t\tCG_Printf (\"CG_ParticleImpactSmokePuff pshader == ZERO!\\n\");\n\n\tif (!free_particles)\n\t\treturn;\n\tp = free_particles;\n\tfree_particles = p->next;\n\tp->next = active_particles;\n\tactive_particles = p;\n\tp->time = cg.time;\n\tp->alpha = 0.25;\n\tp->alphavel = 0;\n\tp->roll = crandom()*179;\n\n\tp->pshader = pshader;\n\n\tp->endtime = cg.time + 1000;\n\tp->startfade = cg.time + 100;\n\n\tp->width = rand()%4 + 8;\n\tp->height = rand()%4 + 8;\n\n\tp->endheight = p->height *2;\n\tp->endwidth = p->width * 2;\n\n\tp->endtime = cg.time + 500;\n\n\tp->type = P_SMOKE_IMPACT;\n\n\tVectorCopy( origin, p->org );\n\tVectorSet(p->vel, 0, 0, 20);\n\tVectorSet(p->accel, 0, 0, 20);\n\n\tp->rotate = qtrue;\n}\n\nvoid CG_Particle_Bleed (qhandle_t pshader, vec3_t start, vec3_t dir, int fleshEntityNum, int duration)\n{\n\tcparticle_t\t*p;\n\n\tif (!pshader)\n\t\tCG_Printf (\"CG_Particle_Bleed pshader == ZERO!\\n\");\n\n\tif (!free_particles)\n\t\treturn;\n\tp = free_particles;\n\tfree_particles = p->next;\n\tp->next = active_particles;\n\tactive_particles = p;\n\tp->time = cg.time;\n\tp->alpha = 1.0;\n\tp->alphavel = 0;\n\tp->roll = 0;\n\n\tp->pshader = pshader;\n\n\tp->endtime = cg.time + duration;\n\t\n\tif (fleshEntityNum)\n\t\tp->startfade = cg.time;\n\telse\n\t\tp->startfade = cg.time + 100;\n\n\tp->width = 4;\n\tp->height = 4;\n\n\tp->endheight = 4+rand()%3;\n\tp->endwidth = p->endheight;\n\n\tp->type = P_SMOKE;\n\n\tVectorCopy( start, p->org );\n\tp->vel[0] = 0;\n\tp->vel[1] = 0;\n\tp->vel[2] = -20;\n\tVectorClear( p->accel );\n\n\tp->rotate = qfalse;\n\n\tp->roll = rand()%179;\n\t\n\tp->color = BLOODRED;\n\tp->alpha = 0.75;\n\n}\n\nvoid CG_Particle_OilParticle (qhandle_t pshader, centity_t *cent)\n{\n\tcparticle_t\t*p;\n\n\tint\t\t\ttime;\n\tint\t\t\ttime2;\n\tfloat\t\tratio;\n\n\tfloat\tduration = 1500;\n\n\ttime = cg.time;\n\ttime2 = cg.time + cent->currentState.time;\n\n\tratio =(float)1 - ((float)time / (float)time2);\n\n\tif (!pshader)\n\t\tCG_Printf (\"CG_Particle_OilParticle == ZERO!\\n\");\n\n\tif (!free_particles)\n\t\treturn;\n\tp = free_particles;\n\tfree_particles = p->next;\n\tp->next = active_particles;\n\tactive_particles = p;\n\tp->time = cg.time;\n\tp->alpha = 1.0;\n\tp->alphavel = 0;\n\tp->roll = 0;\n\n\tp->pshader = pshader;\n\n\tp->endtime = cg.time + duration;\n\t\n\tp->startfade = p->endtime;\n\n\tp->width = 1;\n\tp->height = 3;\n\n\tp->endheight = 3;\n\tp->endwidth = 1;\n\n\tp->type = P_SMOKE;\n\n\tVectorCopy(cent->currentState.origin, p->org );\t\n\t\n\tp->vel[0] = (cent->currentState.origin2[0] * (16 * ratio));\n\tp->vel[1] = (cent->currentState.origin2[1] * (16 * ratio));\n\tp->vel[2] = (cent->currentState.origin2[2]);\n\n\tp->snum = 1.0f;\n\n\tVectorClear( p->accel );\n\n\tp->accel[2] = -20;\n\n\tp->rotate = qfalse;\n\n\tp->roll = rand()%179;\n\t\n\tp->alpha = 0.75;\n\n}\n\n\nvoid CG_Particle_OilSlick (qhandle_t pshader, centity_t *cent)\n{\n\tcparticle_t\t*p;\n\t\n  \tif (!pshader)\n\t\tCG_Printf (\"CG_Particle_OilSlick == ZERO!\\n\");\n\n\tif (!free_particles)\n\t\treturn;\n\tp = free_particles;\n\tfree_particles = p->next;\n\tp->next = active_particles;\n\tactive_particles = p;\n\tp->time = cg.time;\n\t\n\tif (cent->currentState.angles2[2])\n\t\tp->endtime = cg.time + cent->currentState.angles2[2];\n\telse\n\t\tp->endtime = cg.time + 60000;\n\n\tp->startfade = p->endtime;\n\n\tp->alpha = 1.0;\n\tp->alphavel = 0;\n\tp->roll = 0;\n\n\tp->pshader = pshader;\n\n\tif (cent->currentState.angles2[0] || cent->currentState.angles2[1])\n\t{\n\t\tp->width = cent->currentState.angles2[0];\n\t\tp->height = cent->currentState.angles2[0];\n\n\t\tp->endheight = cent->currentState.angles2[1];\n\t\tp->endwidth = cent->currentState.angles2[1];\n\t}\n\telse\n\t{\n\t\tp->width = 8;\n\t\tp->height = 8;\n\n\t\tp->endheight = 16;\n\t\tp->endwidth = 16;\n\t}\n\n\tp->type = P_FLAT_SCALEUP;\n\n\tp->snum = 1.0;\n\n\tVectorCopy(cent->currentState.origin, p->org );\n\t\n\tp->org[2]+= 0.55 + (crandom() * 0.5);\n\n\tp->vel[0] = 0;\n\tp->vel[1] = 0;\n\tp->vel[2] = 0;\n\tVectorClear( p->accel );\n\n\tp->rotate = qfalse;\n\n\tp->roll = rand()%179;\n\t\n\tp->alpha = 0.75;\n\n}\n\nvoid CG_OilSlickRemove (centity_t *cent)\n{\n\tcparticle_t\t\t*p, *next;\n\tint\t\t\t\tid;\n\n\tid = 1.0f;\n\n\tif (!id)\n\t\tCG_Printf (\"CG_OilSlickRevove NULL id\\n\");\n\n\tfor (p=active_particles ; p ; p=next)\n\t{\n\t\tnext = p->next;\n\t\t\n\t\tif (p->type == P_FLAT_SCALEUP)\n\t\t{\n\t\t\tif (p->snum == id)\n\t\t\t{\n\t\t\t\tp->endtime = cg.time + 100;\n\t\t\t\tp->startfade = p->endtime;\n\t\t\t\tp->type = P_FLAT_SCALEUP_FADE;\n\n\t\t\t}\n\t\t}\n\n\t}\n}\n\nqboolean ValidBloodPool (vec3_t start)\n{\n#define EXTRUDE_DIST\t0.5\n\n\tvec3_t\tangles;\n\tvec3_t\tright, up;\n\tvec3_t\tthis_pos, x_pos, center_pos, end_pos;\n\tfloat\tx, y;\n\tfloat\tfwidth, fheight;\n\ttrace_t\ttrace;\n\tvec3_t\tnormal;\n\n\tfwidth = 16;\n\tfheight = 16;\n\n\tVectorSet (normal, 0, 0, 1);\n\n\tvectoangles (normal, angles);\n\tAngleVectors (angles, NULL, right, up);\n\n\tVectorMA (start, EXTRUDE_DIST, normal, center_pos);\n\n\tfor (x= -fwidth/2; x<fwidth; x+= fwidth)\n\t{\n\t\tVectorMA (center_pos, x, right, x_pos);\n\n\t\tfor (y= -fheight/2; y<fheight; y+= fheight)\n\t\t{\n\t\t\tVectorMA (x_pos, y, up, this_pos);\n\t\t\tVectorMA (this_pos, -EXTRUDE_DIST*2, normal, end_pos);\n\t\t\t\n\t\t\tCG_Trace (&trace, this_pos, NULL, NULL, end_pos, -1, CONTENTS_SOLID);\n\n\t\t\t\n\t\t\tif (trace.entityNum < (MAX_ENTITIES - 1)) // may only land on world\n\t\t\t\treturn qfalse;\n\n\t\t\tif (!(!trace.startsolid && trace.fraction < 1))\n\t\t\t\treturn qfalse;\n\t\t\n\t\t}\n\t}\n\n\treturn qtrue;\n}\n\nvoid CG_BloodPool (localEntity_t *le, qhandle_t pshader, trace_t *tr)\n{\t\n\tcparticle_t\t*p;\n\tqboolean\tlegit;\n\tvec3_t\t\tstart;\n\tfloat\t\trndSize;\n\t\n\tif (!pshader)\n\t\tCG_Printf (\"CG_BloodPool pshader == ZERO!\\n\");\n\n\tif (!free_particles)\n\t\treturn;\n\t\n\tVectorCopy (tr->endpos, start);\n\tlegit = ValidBloodPool (start);\n\n\tif (!legit) \n\t\treturn;\n\n\tp = free_particles;\n\tfree_particles = p->next;\n\tp->next = active_particles;\n\tactive_particles = p;\n\tp->time = cg.time;\n\t\n\tp->endtime = cg.time + 3000;\n\tp->startfade = p->endtime;\n\n\tp->alpha = 1.0;\n\tp->alphavel = 0;\n\tp->roll = 0;\n\n\tp->pshader = pshader;\n\n\trndSize = 0.4 + random()*0.6;\n\n\tp->width = 8*rndSize;\n\tp->height = 8*rndSize;\n\n\tp->endheight = 16*rndSize;\n\tp->endwidth = 16*rndSize;\n\t\n\tp->type = P_FLAT_SCALEUP;\n\n\tVectorCopy(start, p->org );\n\t\n\tp->vel[0] = 0;\n\tp->vel[1] = 0;\n\tp->vel[2] = 0;\n\tVectorClear( p->accel );\n\n\tp->rotate = qfalse;\n\n\tp->roll = rand()%179;\n\t\n\tp->alpha = 0.75;\n\t\n\tp->color = BLOODRED;\n}\n\n#define NORMALSIZE\t16\n#define LARGESIZE\t32\n\nvoid CG_ParticleBloodCloud (centity_t *cent, vec3_t origin, vec3_t dir)\n{\n\tfloat\tlength;\n\tfloat\tdist;\n\tfloat\tcrittersize;\n\tvec3_t\tangles, forward;\n\tvec3_t\tpoint;\n\tcparticle_t\t*p;\n\tint\t\ti;\n\t\n\tdist = 0;\n\n\tlength = VectorLength (dir);\n\tvectoangles (dir, angles);\n\tAngleVectors (angles, forward, NULL, NULL);\n\n\tcrittersize = LARGESIZE;\n\n\tif (length)\n\t\tdist = length / crittersize;\n\n\tif (dist < 1)\n\t\tdist = 1;\n\n\tVectorCopy (origin, point);\n\n\tfor (i=0; i<dist; i++)\n\t{\n\t\tVectorMA (point, crittersize, forward, point);\t\n\t\t\n\t\tif (!free_particles)\n\t\t\treturn;\n\n\t\tp = free_particles;\n\t\tfree_particles = p->next;\n\t\tp->next = active_particles;\n\t\tactive_particles = p;\n\n\t\tp->time = cg.time;\n\t\tp->alpha = 1.0;\n\t\tp->alphavel = 0;\n\t\tp->roll = 0;\n\n\t\tp->pshader = cgs.media.smokePuffShader;\n\n\t\tp->endtime = cg.time + 350 + (crandom() * 100);\n\t\t\n\t\tp->startfade = cg.time;\n\t\t\n\t\tp->width = LARGESIZE;\n\t\tp->height = LARGESIZE;\n\t\tp->endheight = LARGESIZE;\n\t\tp->endwidth = LARGESIZE;\n\n\t\tp->type = P_SMOKE;\n\n\t\tVectorCopy( origin, p->org );\n\t\t\n\t\tp->vel[0] = 0;\n\t\tp->vel[1] = 0;\n\t\tp->vel[2] = -1;\n\t\t\n\t\tVectorClear( p->accel );\n\n\t\tp->rotate = qfalse;\n\n\t\tp->roll = rand()%179;\n\t\t\n\t\tp->color = BLOODRED;\n\t\t\n\t\tp->alpha = 0.75;\n\t\t\n\t}\n\n\t\n}\n\nvoid CG_ParticleSparks (vec3_t org, vec3_t vel, int duration, float x, float y, float speed)\n{\n\tcparticle_t\t*p;\n\n\tif (!free_particles)\n\t\treturn;\n\tp = free_particles;\n\tfree_particles = p->next;\n\tp->next = active_particles;\n\tactive_particles = p;\n\tp->time = cg.time;\n\t\n\tp->endtime = cg.time + duration;\n\tp->startfade = cg.time + duration/2;\n\t\n\tp->color = EMISIVEFADE;\n\tp->alpha = 0.4f;\n\tp->alphavel = 0;\n\n\tp->height = 0.5;\n\tp->width = 0.5;\n\tp->endheight = 0.5;\n\tp->endwidth = 0.5;\n\n\tp->pshader = cgs.media.tracerShader;\n\n\tp->type = P_SMOKE;\n\t\n\tVectorCopy(org, p->org);\n\n\tp->org[0] += (crandom() * x);\n\tp->org[1] += (crandom() * y);\n\n\tp->vel[0] = vel[0];\n\tp->vel[1] = vel[1];\n\tp->vel[2] = vel[2];\n\n\tp->accel[0] = p->accel[1] = p->accel[2] = 0;\n\n\tp->vel[0] += (crandom() * 4);\n\tp->vel[1] += (crandom() * 4);\n\tp->vel[2] += (20 + (crandom() * 10)) * speed;\t\n\n\tp->accel[0] = crandom () * 4;\n\tp->accel[1] = crandom () * 4;\n\t\n}\n\nvoid CG_ParticleDust (centity_t *cent, vec3_t origin, vec3_t dir)\n{\n\tfloat\tlength;\n\tfloat\tdist;\n\tfloat\tcrittersize;\n\tvec3_t\tangles, forward;\n\tvec3_t\tpoint;\n\tcparticle_t\t*p;\n\tint\t\ti;\n\t\n\tdist = 0;\n\n\tVectorNegate (dir, dir);\n\tlength = VectorLength (dir);\n\tvectoangles (dir, angles);\n\tAngleVectors (angles, forward, NULL, NULL);\n\n\tcrittersize = LARGESIZE;\n\n\tif (length)\n\t\tdist = length / crittersize;\n\n\tif (dist < 1)\n\t\tdist = 1;\n\n\tVectorCopy (origin, point);\n\n\tfor (i=0; i<dist; i++)\n\t{\n\t\tVectorMA (point, crittersize, forward, point);\t\n\t\t\t\t\n\t\tif (!free_particles)\n\t\t\treturn;\n\n\t\tp = free_particles;\n\t\tfree_particles = p->next;\n\t\tp->next = active_particles;\n\t\tactive_particles = p;\n\n\t\tp->time = cg.time;\n\t\tp->alpha = 5.0;\n\t\tp->alphavel = 0;\n\t\tp->roll = 0;\n\n\t\tp->pshader = cgs.media.smokePuffShader;\n\n\t\t// RF, stay around for long enough to expand and dissipate naturally\n\t\tif (length)\n\t\t\tp->endtime = cg.time + 4500 + (crandom() * 3500);\n\t\telse\n\t\t\tp->endtime = cg.time + 750 + (crandom() * 500);\n\t\t\n\t\tp->startfade = cg.time;\n\t\t\n\t\tp->width = LARGESIZE;\n\t\tp->height = LARGESIZE;\n\n\t\t// RF, expand while falling\n\t\tp->endheight = LARGESIZE*3.0;\n\t\tp->endwidth = LARGESIZE*3.0;\n\n\t\tif (!length)\n\t\t{\n\t\t\tp->width *= 0.2f;\n\t\t\tp->height *= 0.2f;\n\n\t\t\tp->endheight = NORMALSIZE;\n\t\t\tp->endwidth = NORMALSIZE;\n\t\t}\n\n\t\tp->type = P_SMOKE;\n\n\t\tVectorCopy( point, p->org );\n\t\t\n\t\tp->vel[0] = crandom()*6;\n\t\tp->vel[1] = crandom()*6;\n\t\tp->vel[2] = random()*20;\n\n\t\t// RF, add some gravity/randomness\n\t\tp->accel[0] = crandom()*3;\n\t\tp->accel[1] = crandom()*3;\n\t\tp->accel[2] = -PARTICLE_GRAVITY*0.4;\n\n\t\tVectorClear( p->accel );\n\n\t\tp->rotate = qfalse;\n\n\t\tp->roll = rand()%179;\n\t\t\n\t\tp->alpha = 0.75;\n\t\t\n\t}\n\n\t\n}\n\nvoid CG_ParticleMisc (qhandle_t pshader, vec3_t origin, int size, int duration, float alpha)\n{\n\tcparticle_t\t*p;\n\n\tif (!pshader)\n\t\tCG_Printf (\"CG_ParticleImpactSmokePuff pshader == ZERO!\\n\");\n\n\tif (!free_particles)\n\t\treturn;\n\n\tp = free_particles;\n\tfree_particles = p->next;\n\tp->next = active_particles;\n\tactive_particles = p;\n\tp->time = cg.time;\n\tp->alpha = 1.0;\n\tp->alphavel = 0;\n\tp->roll = rand()%179;\n\n\tp->pshader = pshader;\n\n\tif (duration > 0)\n\t\tp->endtime = cg.time + duration;\n\telse\n\t\tp->endtime = duration;\n\n\tp->startfade = cg.time;\n\n\tp->width = size;\n\tp->height = size;\n\n\tp->endheight = size;\n\tp->endwidth = size;\n\n\tp->type = P_SPRITE;\n\n\tVectorCopy( origin, p->org );\n\n\tp->rotate = qfalse;\n}\n"
  },
  {
    "path": "src/cgame/cg_players.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n// cg_players.c -- handle the media and animation for player entities\n#include \"cg_local.h\"\n\nchar\t*cg_customSoundNames[MAX_CUSTOM_SOUNDS] = {\n\t\"*death1.wav\",\n\t\"*death2.wav\",\n\t\"*death3.wav\",\n\t\"*jump1.wav\",\n\t\"*pain25_1.wav\",\n\t\"*pain50_1.wav\",\n\t\"*pain75_1.wav\",\n\t\"*pain100_1.wav\",\n\t\"*falling1.wav\",\n\t\"*gasp.wav\",\n\t\"*drown.wav\",\n\t\"*fall1.wav\",\n\t\"*taunt.wav\"\n};\n\n\n/*\n================\nCG_CustomSound\n\n================\n*/\nsfxHandle_t\tCG_CustomSound( int clientNum, const char *soundName ) {\n\tclientInfo_t *ci;\n\tint\t\t\ti;\n\n\tif ( soundName[0] != '*' ) {\n\t\treturn trap_S_RegisterSound( soundName, qfalse );\n\t}\n\n\tif ( clientNum < 0 || clientNum >= MAX_CLIENTS ) {\n\t\tclientNum = 0;\n\t}\n\tci = &cgs.clientinfo[ clientNum ];\n\n\tfor ( i = 0 ; i < MAX_CUSTOM_SOUNDS && cg_customSoundNames[i] ; i++ ) {\n\t\tif ( !strcmp( soundName, cg_customSoundNames[i] ) ) {\n\t\t\treturn ci->sounds[i];\n\t\t}\n\t}\n\n\tCG_Error( \"Unknown custom sound: %s\", soundName );\n\treturn 0;\n}\n\n\n\n/*\n=============================================================================\n\nCLIENT INFO\n\n=============================================================================\n*/\n\n/*\n======================\nCG_ParseAnimationFile\n\nRead a configuration file containing animation coutns and rates\nmodels/players/visor/animation.cfg, etc\n======================\n*/\nstatic qboolean\tCG_ParseAnimationFile( const char *filename, clientInfo_t *ci ) {\n\tchar\t\t*text_p, *prev;\n\tint\t\t\tlen;\n\tint\t\t\ti;\n\tchar\t\t*token;\n\tfloat\t\tfps;\n\tint\t\t\tskip;\n\tchar\t\ttext[20000];\n\tfileHandle_t\tf;\n\tanimation_t *animations;\n\n\tanimations = ci->animations;\n\n\t// load the file\n\tlen = trap_FS_FOpenFile( filename, &f, FS_READ );\n\tif ( len <= 0 ) {\n\t\treturn qfalse;\n\t}\n\tif ( len >= sizeof( text ) - 1 ) {\n\t\tCG_Printf( \"File %s too long\\n\", filename );\n\t\treturn qfalse;\n\t}\n\ttrap_FS_Read( text, len, f );\n\ttext[len] = 0;\n\ttrap_FS_FCloseFile( f );\n\n\t// parse the text\n\ttext_p = text;\n\tskip = 0;\t// quite the compiler warning\n\n\tci->footsteps = FOOTSTEP_NORMAL;\n\tVectorClear( ci->headOffset );\n\tci->gender = GENDER_MALE;\n\tci->fixedlegs = qfalse;\n\tci->fixedtorso = qfalse;\n\n\t// read optional parameters\n\twhile ( 1 ) {\n\t\tprev = text_p;\t// so we can unget\n\t\ttoken = COM_Parse( &text_p );\n\t\tif ( !token ) {\n\t\t\tbreak;\n\t\t}\n\t\tif ( !Q_stricmp( token, \"footsteps\" ) ) {\n\t\t\ttoken = COM_Parse( &text_p );\n\t\t\tif ( !token ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( !Q_stricmp( token, \"default\" ) || !Q_stricmp( token, \"normal\" ) ) {\n\t\t\t\tci->footsteps = FOOTSTEP_NORMAL;\n\t\t\t} else if ( !Q_stricmp( token, \"boot\" ) ) {\n\t\t\t\tci->footsteps = FOOTSTEP_BOOT;\n\t\t\t} else if ( !Q_stricmp( token, \"flesh\" ) ) {\n\t\t\t\tci->footsteps = FOOTSTEP_FLESH;\n\t\t\t} else if ( !Q_stricmp( token, \"mech\" ) ) {\n\t\t\t\tci->footsteps = FOOTSTEP_MECH;\n\t\t\t} else if ( !Q_stricmp( token, \"energy\" ) ) {\n\t\t\t\tci->footsteps = FOOTSTEP_ENERGY;\n\t\t\t} else {\n\t\t\t\tCG_Printf( \"Bad footsteps parm in %s: %s\\n\", filename, token );\n\t\t\t}\n\t\t\tcontinue;\n\t\t} else if ( !Q_stricmp( token, \"headoffset\" ) ) {\n\t\t\tfor ( i = 0 ; i < 3 ; i++ ) {\n\t\t\t\ttoken = COM_Parse( &text_p );\n\t\t\t\tif ( !token ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tci->headOffset[i] = atof( token );\n\t\t\t}\n\t\t\tcontinue;\n\t\t} else if ( !Q_stricmp( token, \"sex\" ) ) {\n\t\t\ttoken = COM_Parse( &text_p );\n\t\t\tif ( !token ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( token[0] == 'f' || token[0] == 'F' ) {\n\t\t\t\tci->gender = GENDER_FEMALE;\n\t\t\t} else if ( token[0] == 'n' || token[0] == 'N' ) {\n\t\t\t\tci->gender = GENDER_NEUTER;\n\t\t\t} else {\n\t\t\t\tci->gender = GENDER_MALE;\n\t\t\t}\n\t\t\tcontinue;\n\t\t} else if ( !Q_stricmp( token, \"fixedlegs\" ) ) {\n\t\t\tci->fixedlegs = qtrue;\n\t\t\tcontinue;\n\t\t} else if ( !Q_stricmp( token, \"fixedtorso\" ) ) {\n\t\t\tci->fixedtorso = qtrue;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// if it is a number, start parsing animations\n\t\tif ( token[0] >= '0' && token[0] <= '9' ) {\n\t\t\ttext_p = prev;\t// unget the token\n\t\t\tbreak;\n\t\t}\n\t\tCom_Printf( \"unknown token '%s' is %s\\n\", token, filename );\n\t}\n\n\t// read information for each frame\n\tfor ( i = 0 ; i < MAX_ANIMATIONS ; i++ ) {\n\n\t\ttoken = COM_Parse( &text_p );\n\t\tif ( !*token ) {\n\t\t\tif( i >= TORSO_GETFLAG && i <= TORSO_NEGATIVE ) {\n\t\t\t\tanimations[i].firstFrame = animations[TORSO_GESTURE].firstFrame;\n\t\t\t\tanimations[i].frameLerp = animations[TORSO_GESTURE].frameLerp;\n\t\t\t\tanimations[i].initialLerp = animations[TORSO_GESTURE].initialLerp;\n\t\t\t\tanimations[i].loopFrames = animations[TORSO_GESTURE].loopFrames;\n\t\t\t\tanimations[i].numFrames = animations[TORSO_GESTURE].numFrames;\n\t\t\t\tanimations[i].reversed = qfalse;\n\t\t\t\tanimations[i].flipflop = qfalse;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tanimations[i].firstFrame = atoi( token );\n\t\t// leg only frames are adjusted to not count the upper body only frames\n\t\tif ( i == LEGS_WALKCR ) {\n\t\t\tskip = animations[LEGS_WALKCR].firstFrame - animations[TORSO_GESTURE].firstFrame;\n\t\t}\n\t\tif ( i >= LEGS_WALKCR && i<TORSO_GETFLAG) {\n\t\t\tanimations[i].firstFrame -= skip;\n\t\t}\n\n\t\ttoken = COM_Parse( &text_p );\n\t\tif ( !*token ) {\n\t\t\tbreak;\n\t\t}\n\t\tanimations[i].numFrames = atoi( token );\n\n\t\tanimations[i].reversed = qfalse;\n\t\tanimations[i].flipflop = qfalse;\n\t\t// if numFrames is negative the animation is reversed\n\t\tif (animations[i].numFrames < 0) {\n\t\t\tanimations[i].numFrames = -animations[i].numFrames;\n\t\t\tanimations[i].reversed = qtrue;\n\t\t}\n\n\t\ttoken = COM_Parse( &text_p );\n\t\tif ( !*token ) {\n\t\t\tbreak;\n\t\t}\n\t\tanimations[i].loopFrames = atoi( token );\n\n\t\ttoken = COM_Parse( &text_p );\n\t\tif ( !*token ) {\n\t\t\tbreak;\n\t\t}\n\t\tfps = atof( token );\n\t\tif ( fps == 0 ) {\n\t\t\tfps = 1;\n\t\t}\n\t\tanimations[i].frameLerp = 1000 / fps;\n\t\tanimations[i].initialLerp = 1000 / fps;\n\t}\n\n\tif ( i != MAX_ANIMATIONS ) {\n\t\tCG_Printf( \"Error parsing animation file: %s\", filename );\n\t\treturn qfalse;\n\t}\n\n\t// crouch backward animation\n\tmemcpy(&animations[LEGS_BACKCR], &animations[LEGS_WALKCR], sizeof(animation_t));\n\tanimations[LEGS_BACKCR].reversed = qtrue;\n\t// walk backward animation\n\tmemcpy(&animations[LEGS_BACKWALK], &animations[LEGS_WALK], sizeof(animation_t));\n\tanimations[LEGS_BACKWALK].reversed = qtrue;\n\t// flag moving fast\n\tanimations[FLAG_RUN].firstFrame = 0;\n\tanimations[FLAG_RUN].numFrames = 16;\n\tanimations[FLAG_RUN].loopFrames = 16;\n\tanimations[FLAG_RUN].frameLerp = 1000 / 15;\n\tanimations[FLAG_RUN].initialLerp = 1000 / 15;\n\tanimations[FLAG_RUN].reversed = qfalse;\n\t// flag not moving or moving slowly\n\tanimations[FLAG_STAND].firstFrame = 16;\n\tanimations[FLAG_STAND].numFrames = 5;\n\tanimations[FLAG_STAND].loopFrames = 0;\n\tanimations[FLAG_STAND].frameLerp = 1000 / 20;\n\tanimations[FLAG_STAND].initialLerp = 1000 / 20;\n\tanimations[FLAG_STAND].reversed = qfalse;\n\t// flag speeding up\n\tanimations[FLAG_STAND2RUN].firstFrame = 16;\n\tanimations[FLAG_STAND2RUN].numFrames = 5;\n\tanimations[FLAG_STAND2RUN].loopFrames = 1;\n\tanimations[FLAG_STAND2RUN].frameLerp = 1000 / 15;\n\tanimations[FLAG_STAND2RUN].initialLerp = 1000 / 15;\n\tanimations[FLAG_STAND2RUN].reversed = qtrue;\n\t//\n\t// new anims changes\n\t//\n//\tanimations[TORSO_GETFLAG].flipflop = qtrue;\n//\tanimations[TORSO_GUARDBASE].flipflop = qtrue;\n//\tanimations[TORSO_PATROL].flipflop = qtrue;\n//\tanimations[TORSO_AFFIRMATIVE].flipflop = qtrue;\n//\tanimations[TORSO_NEGATIVE].flipflop = qtrue;\n\t//\n\treturn qtrue;\n}\n\n/*\n==========================\nCG_FileExists\n==========================\n*/\nstatic qboolean\tCG_FileExists(const char *filename) {\n\tint len;\n\n\tlen = trap_FS_FOpenFile( filename, 0, FS_READ );\n\tif (len>0) {\n\t\treturn qtrue;\n\t}\n\treturn qfalse;\n}\n\n/*\n==========================\nCG_FindClientModelFile\n==========================\n*/\nstatic qboolean\tCG_FindClientModelFile( char *filename, int length, clientInfo_t *ci, const char *teamName, const char *modelName, const char *skinName, const char *base, const char *ext ) {\n\tchar *team, *charactersFolder;\n\tint i;\n\n\tif ( cgs.gametype >= GT_TEAM ) {\n\t\tswitch ( ci->team ) {\n\t\t\tcase TEAM_BLUE: {\n\t\t\t\tteam = \"blue\";\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\tteam = \"red\";\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\telse {\n\t\tteam = \"default\";\n\t}\n\tcharactersFolder = \"\";\n\twhile(1) {\n\t\tfor ( i = 0; i < 2; i++ ) {\n\t\t\tif ( i == 0 && teamName && *teamName ) {\n\t\t\t\t//\t\t\t\t\t\t\t\t\"models/players/characters/james/stroggs/lower_lily_red.skin\"\n\t\t\t\tCom_sprintf( filename, length, \"models/players/%s%s/%s%s_%s_%s.%s\", charactersFolder, modelName, teamName, base, skinName, team, ext );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t//\t\t\t\t\t\t\t\t\"models/players/characters/james/lower_lily_red.skin\"\n\t\t\t\tCom_sprintf( filename, length, \"models/players/%s%s/%s_%s_%s.%s\", charactersFolder, modelName, base, skinName, team, ext );\n\t\t\t}\n\t\t\tif ( CG_FileExists( filename ) ) {\n\t\t\t\treturn qtrue;\n\t\t\t}\n\t\t\tif ( cgs.gametype >= GT_TEAM ) {\n\t\t\t\tif ( i == 0 && teamName && *teamName ) {\n\t\t\t\t\t//\t\t\t\t\t\t\t\t\"models/players/characters/james/stroggs/lower_red.skin\"\n\t\t\t\t\tCom_sprintf( filename, length, \"models/players/%s%s/%s%s_%s.%s\", charactersFolder, modelName, teamName, base, team, ext );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t//\t\t\t\t\t\t\t\t\"models/players/characters/james/lower_red.skin\"\n\t\t\t\t\tCom_sprintf( filename, length, \"models/players/%s%s/%s_%s.%s\", charactersFolder, modelName, base, team, ext );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif ( i == 0 && teamName && *teamName ) {\n\t\t\t\t\t//\t\t\t\t\t\t\t\t\"models/players/characters/james/stroggs/lower_lily.skin\"\n\t\t\t\t\tCom_sprintf( filename, length, \"models/players/%s%s/%s%s_%s.%s\", charactersFolder, modelName, teamName, base, skinName, ext );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t//\t\t\t\t\t\t\t\t\"models/players/characters/james/lower_lily.skin\"\n\t\t\t\t\tCom_sprintf( filename, length, \"models/players/%s%s/%s_%s.%s\", charactersFolder, modelName, base, skinName, ext );\n\t\t\t\t}\n\t\t\t}\n\t\t\tif ( CG_FileExists( filename ) ) {\n\t\t\t\treturn qtrue;\n\t\t\t}\n\t\t\tif ( !teamName || !*teamName ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\t// if tried the heads folder first\n\t\tif ( charactersFolder[0] ) {\n\t\t\tbreak;\n\t\t}\n\t\tcharactersFolder = \"characters/\";\n\t}\n\n\treturn qfalse;\n}\n\n/*\n==========================\nCG_FindClientHeadFile\n==========================\n*/\nstatic qboolean\tCG_FindClientHeadFile( char *filename, int length, clientInfo_t *ci, const char *teamName, const char *headModelName, const char *headSkinName, const char *base, const char *ext ) {\n\tchar *team, *headsFolder;\n\tint i;\n\n\tif ( cgs.gametype >= GT_TEAM ) {\n\t\tswitch ( ci->team ) {\n\t\t\tcase TEAM_BLUE: {\n\t\t\t\tteam = \"blue\";\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\tteam = \"red\";\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\telse {\n\t\tteam = \"default\";\n\t}\n\n\tif ( headModelName[0] == '*' ) {\n\t\theadsFolder = \"heads/\";\n\t\theadModelName++;\n\t}\n\telse {\n\t\theadsFolder = \"\";\n\t}\n\twhile(1) {\n\t\tfor ( i = 0; i < 2; i++ ) {\n\t\t\tif ( i == 0 && teamName && *teamName ) {\n\t\t\t\tCom_sprintf( filename, length, \"models/players/%s%s/%s/%s%s_%s.%s\", headsFolder, headModelName, headSkinName, teamName, base, team, ext );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tCom_sprintf( filename, length, \"models/players/%s%s/%s/%s_%s.%s\", headsFolder, headModelName, headSkinName, base, team, ext );\n\t\t\t}\n\t\t\tif ( CG_FileExists( filename ) ) {\n\t\t\t\treturn qtrue;\n\t\t\t}\n\t\t\tif ( cgs.gametype >= GT_TEAM ) {\n\t\t\t\tif ( i == 0 &&  teamName && *teamName ) {\n\t\t\t\t\tCom_sprintf( filename, length, \"models/players/%s%s/%s%s_%s.%s\", headsFolder, headModelName, teamName, base, team, ext );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tCom_sprintf( filename, length, \"models/players/%s%s/%s_%s.%s\", headsFolder, headModelName, base, team, ext );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif ( i == 0 && teamName && *teamName ) {\n\t\t\t\t\tCom_sprintf( filename, length, \"models/players/%s%s/%s%s_%s.%s\", headsFolder, headModelName, teamName, base, headSkinName, ext );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tCom_sprintf( filename, length, \"models/players/%s%s/%s_%s.%s\", headsFolder, headModelName, base, headSkinName, ext );\n\t\t\t\t}\n\t\t\t}\n\t\t\tif ( CG_FileExists( filename ) ) {\n\t\t\t\treturn qtrue;\n\t\t\t}\n\t\t\tif ( !teamName || !*teamName ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\t// if tried the heads folder first\n\t\tif ( headsFolder[0] ) {\n\t\t\tbreak;\n\t\t}\n\t\theadsFolder = \"heads/\";\n\t}\n\n\treturn qfalse;\n}\n\n/*\n==========================\nCG_RegisterClientSkin\n==========================\n*/\nstatic qboolean\tCG_RegisterClientSkin( clientInfo_t *ci, const char *teamName, const char *modelName, const char *skinName, const char *headModelName, const char *headSkinName ) {\n\tchar filename[MAX_QPATH];\n\n\t/*\n\tCom_sprintf( filename, sizeof( filename ), \"models/players/%s/%slower_%s.skin\", modelName, teamName, skinName );\n\tci->legsSkin = trap_R_RegisterSkin( filename );\n\tif (!ci->legsSkin) {\n\t\tCom_sprintf( filename, sizeof( filename ), \"models/players/characters/%s/%slower_%s.skin\", modelName, teamName, skinName );\n\t\tci->legsSkin = trap_R_RegisterSkin( filename );\n\t\tif (!ci->legsSkin) {\n\t\t\tCom_Printf( \"Leg skin load failure: %s\\n\", filename );\n\t\t}\n\t}\n\n\n\tCom_sprintf( filename, sizeof( filename ), \"models/players/%s/%supper_%s.skin\", modelName, teamName, skinName );\n\tci->torsoSkin = trap_R_RegisterSkin( filename );\n\tif (!ci->torsoSkin) {\n\t\tCom_sprintf( filename, sizeof( filename ), \"models/players/characters/%s/%supper_%s.skin\", modelName, teamName, skinName );\n\t\tci->torsoSkin = trap_R_RegisterSkin( filename );\n\t\tif (!ci->torsoSkin) {\n\t\t\tCom_Printf( \"Torso skin load failure: %s\\n\", filename );\n\t\t}\n\t}\n\t*/\n\tif ( CG_FindClientModelFile( filename, sizeof(filename), ci, teamName, modelName, skinName, \"lower\", \"skin\" ) ) {\n\t\tci->legsSkin = trap_R_RegisterSkin( filename );\n\t}\n\tif (!ci->legsSkin) {\n\t\tCom_Printf( \"Leg skin load failure: %s\\n\", filename );\n\t}\n\n\tif ( CG_FindClientModelFile( filename, sizeof(filename), ci, teamName, modelName, skinName, \"upper\", \"skin\" ) ) {\n\t\tci->torsoSkin = trap_R_RegisterSkin( filename );\n\t}\n\tif (!ci->torsoSkin) {\n\t\tCom_Printf( \"Torso skin load failure: %s\\n\", filename );\n\t}\n\n\tif ( CG_FindClientHeadFile( filename, sizeof(filename), ci, teamName, headModelName, headSkinName, \"head\", \"skin\" ) ) {\n\t\tci->headSkin = trap_R_RegisterSkin( filename );\n\t}\n\tif (!ci->headSkin) {\n\t\tCom_Printf( \"Head skin load failure: %s\\n\", filename );\n\t}\n\n\t// if any skins failed to load\n\tif ( !ci->legsSkin || !ci->torsoSkin || !ci->headSkin ) {\n\t\treturn qfalse;\n\t}\n\treturn qtrue;\n}\n\n/*\n==========================\nCG_RegisterClientModelname\n==========================\n*/\nstatic qboolean CG_RegisterClientModelname( clientInfo_t *ci, const char *modelName, const char *skinName, const char *headModelName, const char *headSkinName, const char *teamName ) {\n\tchar\tfilename[MAX_QPATH*2];\n\tconst char\t\t*headName;\n\tchar newTeamName[MAX_QPATH*2];\n\n\tif ( headModelName[0] == '\\0' ) {\n\t\theadName = modelName;\n\t}\n\telse {\n\t\theadName = headModelName;\n\t}\n\tCom_sprintf( filename, sizeof( filename ), \"models/players/%s/lower.md3\", modelName );\n\tci->legsModel = trap_R_RegisterModel( filename );\n\tif ( !ci->legsModel ) {\n\t\tCom_sprintf( filename, sizeof( filename ), \"models/players/characters/%s/lower.md3\", modelName );\n\t\tci->legsModel = trap_R_RegisterModel( filename );\n\t\tif ( !ci->legsModel ) {\n\t\t\tCom_Printf( \"Failed to load model file %s\\n\", filename );\n\t\t\treturn qfalse;\n\t\t}\n\t}\n\n\tCom_sprintf( filename, sizeof( filename ), \"models/players/%s/upper.md3\", modelName );\n\tci->torsoModel = trap_R_RegisterModel( filename );\n\tif ( !ci->torsoModel ) {\n\t\tCom_sprintf( filename, sizeof( filename ), \"models/players/characters/%s/upper.md3\", modelName );\n\t\tci->torsoModel = trap_R_RegisterModel( filename );\n\t\tif ( !ci->torsoModel ) {\n\t\t\tCom_Printf( \"Failed to load model file %s\\n\", filename );\n\t\t\treturn qfalse;\n\t\t}\n\t}\n\n\tif( headName[0] == '*' ) {\n\t\tCom_sprintf( filename, sizeof( filename ), \"models/players/heads/%s/%s.md3\", &headModelName[1], &headModelName[1] );\n\t}\n\telse {\n\t\tCom_sprintf( filename, sizeof( filename ), \"models/players/%s/head.md3\", headName );\n\t}\n\tci->headModel = trap_R_RegisterModel( filename );\n\t// if the head model could not be found and we didn't load from the heads folder try to load from there\n\tif ( !ci->headModel && headName[0] != '*' ) {\n\t\tCom_sprintf( filename, sizeof( filename ), \"models/players/heads/%s/%s.md3\", headModelName, headModelName );\n\t\tci->headModel = trap_R_RegisterModel( filename );\n\t}\n\tif ( !ci->headModel ) {\n\t\tCom_Printf( \"Failed to load model file %s\\n\", filename );\n\t\treturn qfalse;\n\t}\n\n\t// if any skins failed to load, return failure\n\tif ( !CG_RegisterClientSkin( ci, teamName, modelName, skinName, headName, headSkinName ) ) {\n\t\tif ( teamName && *teamName) {\n\t\t\tCom_Printf( \"Failed to load skin file: %s : %s : %s, %s : %s\\n\", teamName, modelName, skinName, headName, headSkinName );\n\t\t\tif( ci->team == TEAM_BLUE ) {\n\t\t\t\tCom_sprintf(newTeamName, sizeof(newTeamName), \"%s/\", DEFAULT_BLUETEAM_NAME);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tCom_sprintf(newTeamName, sizeof(newTeamName), \"%s/\", DEFAULT_REDTEAM_NAME);\n\t\t\t}\n\t\t\tif ( !CG_RegisterClientSkin( ci, newTeamName, modelName, skinName, headName, headSkinName ) ) {\n\t\t\t\tCom_Printf( \"Failed to load skin file: %s : %s : %s, %s : %s\\n\", newTeamName, modelName, skinName, headName, headSkinName );\n\t\t\t\treturn qfalse;\n\t\t\t}\n\t\t} else {\n\t\t\tCom_Printf( \"Failed to load skin file: %s : %s, %s : %s\\n\", modelName, skinName, headName, headSkinName );\n\t\t\treturn qfalse;\n\t\t}\n\t}\n\n\t// load the animations\n\tCom_sprintf( filename, sizeof( filename ), \"models/players/%s/animation.cfg\", modelName );\n\tif ( !CG_ParseAnimationFile( filename, ci ) ) {\n\t\tCom_sprintf( filename, sizeof( filename ), \"models/players/characters/%s/animation.cfg\", modelName );\n\t\tif ( !CG_ParseAnimationFile( filename, ci ) ) {\n\t\t\tCom_Printf( \"Failed to load animation file %s\\n\", filename );\n\t\t\treturn qfalse;\n\t\t}\n\t}\n\n\tif ( CG_FindClientHeadFile( filename, sizeof(filename), ci, teamName, headName, headSkinName, \"icon\", \"skin\" ) ) {\n\t\tci->modelIcon = trap_R_RegisterShaderNoMip( filename );\n\t}\n\telse if ( CG_FindClientHeadFile( filename, sizeof(filename), ci, teamName, headName, headSkinName, \"icon\", \"tga\" ) ) {\n\t\tci->modelIcon = trap_R_RegisterShaderNoMip( filename );\n\t}\n\n\tif ( !ci->modelIcon ) {\n\t\treturn qfalse;\n\t}\n\n\treturn qtrue;\n}\n\n/*\n====================\nCG_ColorFromString\n====================\n*/\nstatic void CG_ColorFromString( const char *v, vec3_t color ) {\n\tint val;\n\n\tVectorClear( color );\n\n\tval = atoi( v );\n\n\tif ( val < 1 || val > 7 ) {\n\t\tVectorSet( color, 1, 1, 1 );\n\t\treturn;\n\t}\n\n\tif ( val & 1 ) {\n\t\tcolor[2] = 1.0f;\n\t}\n\tif ( val & 2 ) {\n\t\tcolor[1] = 1.0f;\n\t}\n\tif ( val & 4 ) {\n\t\tcolor[0] = 1.0f;\n\t}\n}\n\n/*\n===================\nCG_LoadClientInfo\n\nLoad it now, taking the disk hits.\nThis will usually be deferred to a safe time\n===================\n*/\nstatic void CG_LoadClientInfo( clientInfo_t *ci ) {\n\tconst char\t*dir, *fallback;\n\tint\t\t\ti, modelloaded;\n\tconst char\t*s;\n\tint\t\t\tclientNum;\n\tchar\t\tteamname[MAX_QPATH];\n\n\tteamname[0] = 0;\n\tmodelloaded = qtrue;\n\tif ( !CG_RegisterClientModelname( ci, ci->modelName, ci->skinName, ci->headModelName, ci->headSkinName, teamname ) ) {\n\t\tif ( cg_buildScript.integer ) {\n\t\t\tCG_Error( \"CG_RegisterClientModelname( %s, %s, %s, %s %s ) failed\", ci->modelName, ci->skinName, ci->headModelName, ci->headSkinName, teamname );\n\t\t}\n\n\t\t// fall back to default team name\n\t\tif( cgs.gametype >= GT_TEAM) {\n\t\t\t// keep skin name\n\t\t\tif( ci->team == TEAM_BLUE ) {\n\t\t\t\tQ_strncpyz(teamname, DEFAULT_BLUETEAM_NAME, sizeof(teamname) );\n\t\t\t} else {\n\t\t\t\tQ_strncpyz(teamname, DEFAULT_REDTEAM_NAME, sizeof(teamname) );\n\t\t\t}\n\t\t\tif ( !CG_RegisterClientModelname( ci, DEFAULT_TEAM_MODEL, ci->skinName, DEFAULT_TEAM_HEAD, ci->skinName, teamname ) ) {\n\t\t\t\tCG_Error( \"DEFAULT_TEAM_MODEL / skin (%s/%s) failed to register\", DEFAULT_TEAM_MODEL, ci->skinName );\n\t\t\t}\n\t\t} else {\n\t\t\tif ( !CG_RegisterClientModelname( ci, DEFAULT_MODEL, \"default\", DEFAULT_MODEL, \"default\", teamname ) ) {\n\t\t\t\tCG_Error( \"DEFAULT_MODEL (%s) failed to register\", DEFAULT_MODEL );\n\t\t\t}\n\t\t}\n\t\tmodelloaded = qfalse;\n\t}\n\n\tci->newAnims = qfalse;\n\tif ( ci->torsoModel ) {\n\t\torientation_t tag;\n\t\t// if the torso model has the \"tag_flag\"\n\t\tif ( trap_R_LerpTag( &tag, ci->torsoModel, 0, 0, 1, \"tag_flag\" ) ) {\n\t\t\tci->newAnims = qtrue;\n\t\t}\n\t}\n\n\t// sounds\n\tdir = ci->modelName;\n\tfallback = (cgs.gametype >= GT_TEAM) ? DEFAULT_TEAM_MODEL : DEFAULT_MODEL;\n\n\tfor ( i = 0 ; i < MAX_CUSTOM_SOUNDS ; i++ ) {\n\t\ts = cg_customSoundNames[i];\n\t\tif ( !s ) {\n\t\t\tbreak;\n\t\t}\n\t\tci->sounds[i] = 0;\n\t\t// if the model didn't load use the sounds of the default model\n\t\tif (modelloaded) {\n\t\t\tci->sounds[i] = trap_S_RegisterSound( va(\"sound/player/%s/%s\", dir, s + 1), qfalse );\n\t\t}\n\t\tif ( !ci->sounds[i] ) {\n\t\t\tci->sounds[i] = trap_S_RegisterSound( va(\"sound/player/%s/%s\", fallback, s + 1), qfalse );\n\t\t}\n\t}\n\n\tci->deferred = qfalse;\n\n\t// reset any existing players and bodies, because they might be in bad\n\t// frames for this new model\n\tclientNum = ci - cgs.clientinfo;\n\tfor ( i = 0 ; i < MAX_GENTITIES ; i++ ) {\n\t\tif ( cg_entities[i].currentState.clientNum == clientNum\n\t\t\t&& cg_entities[i].currentState.eType == ET_PLAYER ) {\n\t\t\tCG_ResetPlayerEntity( &cg_entities[i] );\n\t\t}\n\t}\n}\n\n/*\n======================\nCG_CopyClientInfoModel\n======================\n*/\nstatic void CG_CopyClientInfoModel( clientInfo_t *from, clientInfo_t *to ) {\n\tVectorCopy( from->headOffset, to->headOffset );\n\tto->footsteps = from->footsteps;\n\tto->gender = from->gender;\n\n\tto->legsModel = from->legsModel;\n\tto->legsSkin = from->legsSkin;\n\tto->torsoModel = from->torsoModel;\n\tto->torsoSkin = from->torsoSkin;\n\tto->headModel = from->headModel;\n\tto->headSkin = from->headSkin;\n\tto->modelIcon = from->modelIcon;\n\n\tto->newAnims = from->newAnims;\n\n\tmemcpy( to->animations, from->animations, sizeof( to->animations ) );\n\tmemcpy( to->sounds, from->sounds, sizeof( to->sounds ) );\n}\n\n/*\n======================\nCG_ScanForExistingClientInfo\n======================\n*/\nstatic qboolean CG_ScanForExistingClientInfo( clientInfo_t *ci ) {\n\tint\t\ti;\n\tclientInfo_t\t*match;\n\n\tfor ( i = 0 ; i < cgs.maxclients ; i++ ) {\n\t\tmatch = &cgs.clientinfo[ i ];\n\t\tif ( !match->infoValid ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( match->deferred ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( !Q_stricmp( ci->modelName, match->modelName )\n\t\t\t&& !Q_stricmp( ci->skinName, match->skinName )\n\t\t\t&& !Q_stricmp( ci->headModelName, match->headModelName )\n\t\t\t&& !Q_stricmp( ci->headSkinName, match->headSkinName ) \n\t\t\t&& !Q_stricmp( ci->blueTeam, match->blueTeam ) \n\t\t\t&& !Q_stricmp( ci->redTeam, match->redTeam )\n\t\t\t&& (cgs.gametype < GT_TEAM || ci->team == match->team) ) {\n\t\t\t// this clientinfo is identical, so use it's handles\n\n\t\t\tci->deferred = qfalse;\n\n\t\t\tCG_CopyClientInfoModel( match, ci );\n\n\t\t\treturn qtrue;\n\t\t}\n\t}\n\n\t// nothing matches, so defer the load\n\treturn qfalse;\n}\n\n/*\n======================\nCG_SetDeferredClientInfo\n\nWe aren't going to load it now, so grab some other\nclient's info to use until we have some spare time.\n======================\n*/\nstatic void CG_SetDeferredClientInfo( clientInfo_t *ci ) {\n\tint\t\ti;\n\tclientInfo_t\t*match;\n\n\t// if someone else is already the same models and skins we\n\t// can just load the client info\n\tfor ( i = 0 ; i < cgs.maxclients ; i++ ) {\n\t\tmatch = &cgs.clientinfo[ i ];\n\t\tif ( !match->infoValid || match->deferred ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( Q_stricmp( ci->skinName, match->skinName ) ||\n\t\t\t Q_stricmp( ci->modelName, match->modelName ) ||\n//\t\t\t Q_stricmp( ci->headModelName, match->headModelName ) ||\n//\t\t\t Q_stricmp( ci->headSkinName, match->headSkinName ) ||\n\t\t\t (cgs.gametype >= GT_TEAM && ci->team != match->team) ) {\n\t\t\tcontinue;\n\t\t}\n\t\t// just load the real info cause it uses the same models and skins\n\t\tCG_LoadClientInfo( ci );\n\t\treturn;\n\t}\n\n\t// if we are in teamplay, only grab a model if the skin is correct\n\tif ( cgs.gametype >= GT_TEAM ) {\n\t\tfor ( i = 0 ; i < cgs.maxclients ; i++ ) {\n\t\t\tmatch = &cgs.clientinfo[ i ];\n\t\t\tif ( !match->infoValid || match->deferred ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif ( Q_stricmp( ci->skinName, match->skinName ) ||\n\t\t\t\t(cgs.gametype >= GT_TEAM && ci->team != match->team) ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tci->deferred = qtrue;\n\t\t\tCG_CopyClientInfoModel( match, ci );\n\t\t\treturn;\n\t\t}\n\t\t// load the full model, because we don't ever want to show\n\t\t// an improper team skin.  This will cause a hitch for the first\n\t\t// player, when the second enters.  Combat shouldn't be going on\n\t\t// yet, so it shouldn't matter\n\t\tCG_LoadClientInfo( ci );\n\t\treturn;\n\t}\n\n\t// find the first valid clientinfo and grab its stuff\n\tfor ( i = 0 ; i < cgs.maxclients ; i++ ) {\n\t\tmatch = &cgs.clientinfo[ i ];\n\t\tif ( !match->infoValid ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tci->deferred = qtrue;\n\t\tCG_CopyClientInfoModel( match, ci );\n\t\treturn;\n\t}\n\n\t// we should never get here...\n\tCG_Printf( \"CG_SetDeferredClientInfo: no valid clients!\\n\" );\n\n\tCG_LoadClientInfo( ci );\n}\n\n\n/*\n======================\nCG_NewClientInfo\n======================\n*/\nvoid CG_NewClientInfo( int clientNum ) {\n\tclientInfo_t *ci;\n\tclientInfo_t newInfo;\n\tconst char\t*configstring;\n\tconst char\t*v;\n\tchar\t\t*slash;\n\n\tci = &cgs.clientinfo[clientNum];\n\n\tconfigstring = CG_ConfigString( clientNum + CS_PLAYERS );\n\tif ( !configstring[0] ) {\n\t\tmemset( ci, 0, sizeof( *ci ) );\n\t\treturn;\t\t// player just left\n\t}\n\n\t// build into a temp buffer so the defer checks can use\n\t// the old value\n\tmemset( &newInfo, 0, sizeof( newInfo ) );\n\n\t// isolate the player's name\n\tv = Info_ValueForKey(configstring, \"n\");\n\tQ_strncpyz( newInfo.name, v, sizeof( newInfo.name ) );\n\n\t// colors\n\tv = Info_ValueForKey( configstring, \"c1\" );\n\tCG_ColorFromString( v, newInfo.color1 );\n\n\tv = Info_ValueForKey( configstring, \"c2\" );\n\tCG_ColorFromString( v, newInfo.color2 );\n\n\t// bot skill\n\tv = Info_ValueForKey( configstring, \"skill\" );\n\tnewInfo.botSkill = atoi( v );\n\n\t// handicap\n\tv = Info_ValueForKey( configstring, \"hc\" );\n\tnewInfo.handicap = atoi( v );\n\n\t// wins\n\tv = Info_ValueForKey( configstring, \"w\" );\n\tnewInfo.wins = atoi( v );\n\n\t// losses\n\tv = Info_ValueForKey( configstring, \"l\" );\n\tnewInfo.losses = atoi( v );\n\n\t// team\n\tv = Info_ValueForKey( configstring, \"t\" );\n\tnewInfo.team = atoi( v );\n\n\t// team task\n\tv = Info_ValueForKey( configstring, \"tt\" );\n\tnewInfo.teamTask = atoi(v);\n\n\t// team leader\n\tv = Info_ValueForKey( configstring, \"tl\" );\n\tnewInfo.teamLeader = atoi(v);\n\n\tv = Info_ValueForKey( configstring, \"g_redteam\" );\n\tQ_strncpyz(newInfo.redTeam, v, MAX_TEAMNAME);\n\n\tv = Info_ValueForKey( configstring, \"g_blueteam\" );\n\tQ_strncpyz(newInfo.blueTeam, v, MAX_TEAMNAME);\n\n\t// model\n\tv = Info_ValueForKey( configstring, \"model\" );\n\tif ( cg_forceModel.integer ) {\n\t\t// forcemodel makes everyone use a single model\n\t\t// to prevent load hitches\n\t\tchar modelStr[MAX_QPATH];\n\t\tchar *skin;\n\n\t\tif( cgs.gametype >= GT_TEAM ) {\n\t\t\tQ_strncpyz( newInfo.modelName, DEFAULT_TEAM_MODEL, sizeof( newInfo.modelName ) );\n\t\t\tQ_strncpyz( newInfo.skinName, \"default\", sizeof( newInfo.skinName ) );\n\t\t} else {\n\t\t\ttrap_Cvar_VariableStringBuffer( \"model\", modelStr, sizeof( modelStr ) );\n\t\t\tif ( ( skin = strchr( modelStr, '/' ) ) == NULL) {\n\t\t\t\tskin = \"default\";\n\t\t\t} else {\n\t\t\t\t*skin++ = 0;\n\t\t\t}\n\n\t\t\tQ_strncpyz( newInfo.skinName, skin, sizeof( newInfo.skinName ) );\n\t\t\tQ_strncpyz( newInfo.modelName, modelStr, sizeof( newInfo.modelName ) );\n\t\t}\n\n\t\tif ( cgs.gametype >= GT_TEAM ) {\n\t\t\t// keep skin name\n\t\t\tslash = strchr( v, '/' );\n\t\t\tif ( slash ) {\n\t\t\t\tQ_strncpyz( newInfo.skinName, slash + 1, sizeof( newInfo.skinName ) );\n\t\t\t}\n\t\t}\n\t} else {\n\t\tQ_strncpyz( newInfo.modelName, v, sizeof( newInfo.modelName ) );\n\n\t\tslash = strchr( newInfo.modelName, '/' );\n\t\tif ( !slash ) {\n\t\t\t// modelName didn not include a skin name\n\t\t\tQ_strncpyz( newInfo.skinName, \"default\", sizeof( newInfo.skinName ) );\n\t\t} else {\n\t\t\tQ_strncpyz( newInfo.skinName, slash + 1, sizeof( newInfo.skinName ) );\n\t\t\t// truncate modelName\n\t\t\t*slash = 0;\n\t\t}\n\t}\n\n\t// head model\n\tv = Info_ValueForKey( configstring, \"hmodel\" );\n\tif ( cg_forceModel.integer ) {\n\t\t// forcemodel makes everyone use a single model\n\t\t// to prevent load hitches\n\t\tchar modelStr[MAX_QPATH];\n\t\tchar *skin;\n\n\t\tif( cgs.gametype >= GT_TEAM ) {\n\t\t\tQ_strncpyz( newInfo.headModelName, DEFAULT_TEAM_MODEL, sizeof( newInfo.headModelName ) );\n\t\t\tQ_strncpyz( newInfo.headSkinName, \"default\", sizeof( newInfo.headSkinName ) );\n\t\t} else {\n\t\t\ttrap_Cvar_VariableStringBuffer( \"headmodel\", modelStr, sizeof( modelStr ) );\n\t\t\tif ( ( skin = strchr( modelStr, '/' ) ) == NULL) {\n\t\t\t\tskin = \"default\";\n\t\t\t} else {\n\t\t\t\t*skin++ = 0;\n\t\t\t}\n\n\t\t\tQ_strncpyz( newInfo.headSkinName, skin, sizeof( newInfo.headSkinName ) );\n\t\t\tQ_strncpyz( newInfo.headModelName, modelStr, sizeof( newInfo.headModelName ) );\n\t\t}\n\n\t\tif ( cgs.gametype >= GT_TEAM ) {\n\t\t\t// keep skin name\n\t\t\tslash = strchr( v, '/' );\n\t\t\tif ( slash ) {\n\t\t\t\tQ_strncpyz( newInfo.headSkinName, slash + 1, sizeof( newInfo.headSkinName ) );\n\t\t\t}\n\t\t}\n\t} else {\n\t\tQ_strncpyz( newInfo.headModelName, v, sizeof( newInfo.headModelName ) );\n\n\t\tslash = strchr( newInfo.headModelName, '/' );\n\t\tif ( !slash ) {\n\t\t\t// modelName didn not include a skin name\n\t\t\tQ_strncpyz( newInfo.headSkinName, \"default\", sizeof( newInfo.headSkinName ) );\n\t\t} else {\n\t\t\tQ_strncpyz( newInfo.headSkinName, slash + 1, sizeof( newInfo.headSkinName ) );\n\t\t\t// truncate modelName\n\t\t\t*slash = 0;\n\t\t}\n\t}\n\n\t// scan for an existing clientinfo that matches this modelname\n\t// so we can avoid loading checks if possible\n\tif ( !CG_ScanForExistingClientInfo( &newInfo ) ) {\n\t\tqboolean\tforceDefer;\n\n\t\tforceDefer = trap_MemoryRemaining() < 4000000;\n\n\t\t// if we are defering loads, just have it pick the first valid\n\t\tif ( forceDefer || (cg_deferPlayers.integer && !cg_buildScript.integer && !cg.loading ) ) {\n\t\t\t// keep whatever they had if it won't violate team skins\n\t\t\tCG_SetDeferredClientInfo( &newInfo );\n\t\t\t// if we are low on memory, leave them with this model\n\t\t\tif ( forceDefer ) {\n\t\t\t\tCG_Printf( \"Memory is low.  Using deferred model.\\n\" );\n\t\t\t\tnewInfo.deferred = qfalse;\n\t\t\t}\n\t\t} else {\n\t\t\tCG_LoadClientInfo( &newInfo );\n\t\t}\n\t}\n\n\t// replace whatever was there with the new one\n\tnewInfo.infoValid = qtrue;\n\t*ci = newInfo;\n}\n\n\n\n/*\n======================\nCG_LoadDeferredPlayers\n\nCalled each frame when a player is dead\nand the scoreboard is up\nso deferred players can be loaded\n======================\n*/\nvoid CG_LoadDeferredPlayers( void ) {\n\tint\t\ti;\n\tclientInfo_t\t*ci;\n\n\t// scan for a deferred player to load\n\tfor ( i = 0, ci = cgs.clientinfo ; i < cgs.maxclients ; i++, ci++ ) {\n\t\tif ( ci->infoValid && ci->deferred ) {\n\t\t\t// if we are low on memory, leave it deferred\n\t\t\tif ( trap_MemoryRemaining() < 4000000 ) {\n\t\t\t\tCG_Printf( \"Memory is low.  Using deferred model.\\n\" );\n\t\t\t\tci->deferred = qfalse;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tCG_LoadClientInfo( ci );\n//\t\t\tbreak;\n\t\t}\n\t}\n}\n\n/*\n=============================================================================\n\nPLAYER ANIMATION\n\n=============================================================================\n*/\n\n\n/*\n===============\nCG_SetLerpFrameAnimation\n\nmay include ANIM_TOGGLEBIT\n===============\n*/\nstatic void CG_SetLerpFrameAnimation( clientInfo_t *ci, lerpFrame_t *lf, int newAnimation ) {\n\tanimation_t\t*anim;\n\n\tlf->animationNumber = newAnimation;\n\tnewAnimation &= ~ANIM_TOGGLEBIT;\n\n\tif ( newAnimation < 0 || newAnimation >= MAX_TOTALANIMATIONS ) {\n\t\tCG_Error( \"Bad animation number: %i\", newAnimation );\n\t}\n\n\tanim = &ci->animations[ newAnimation ];\n\n\tlf->animation = anim;\n\tlf->animationTime = lf->frameTime + anim->initialLerp;\n\n\tif ( cg_debugAnim.integer ) {\n\t\tCG_Printf( \"Anim: %i\\n\", newAnimation );\n\t}\n}\n\n/*\n===============\nCG_RunLerpFrame\n\nSets cg.snap, cg.oldFrame, and cg.backlerp\ncg.time should be between oldFrameTime and frameTime after exit\n===============\n*/\nstatic void CG_RunLerpFrame( clientInfo_t *ci, lerpFrame_t *lf, int newAnimation, float speedScale ) {\n\tint\t\t\tf, numFrames;\n\tanimation_t\t*anim;\n\n\t// debugging tool to get no animations\n\tif ( cg_animSpeed.integer == 0 ) {\n\t\tlf->oldFrame = lf->frame = lf->backlerp = 0;\n\t\treturn;\n\t}\n\n\t// see if the animation sequence is switching\n\tif ( newAnimation != lf->animationNumber || !lf->animation ) {\n\t\tCG_SetLerpFrameAnimation( ci, lf, newAnimation );\n\t}\n\n\t// if we have passed the current frame, move it to\n\t// oldFrame and calculate a new frame\n\tif ( cg.time >= lf->frameTime ) {\n\t\tlf->oldFrame = lf->frame;\n\t\tlf->oldFrameTime = lf->frameTime;\n\n\t\t// get the next frame based on the animation\n\t\tanim = lf->animation;\n\t\tif ( !anim->frameLerp ) {\n\t\t\treturn;\t\t// shouldn't happen\n\t\t}\n\t\tif ( cg.time < lf->animationTime ) {\n\t\t\tlf->frameTime = lf->animationTime;\t\t// initial lerp\n\t\t} else {\n\t\t\tlf->frameTime = lf->oldFrameTime + anim->frameLerp;\n\t\t}\n\t\tf = ( lf->frameTime - lf->animationTime ) / anim->frameLerp;\n\t\tf *= speedScale;\t\t// adjust for haste, etc\n\n\t\tnumFrames = anim->numFrames;\n\t\tif (anim->flipflop) {\n\t\t\tnumFrames *= 2;\n\t\t}\n\t\tif ( f >= numFrames ) {\n\t\t\tf -= numFrames;\n\t\t\tif ( anim->loopFrames ) {\n\t\t\t\tf %= anim->loopFrames;\n\t\t\t\tf += anim->numFrames - anim->loopFrames;\n\t\t\t} else {\n\t\t\t\tf = numFrames - 1;\n\t\t\t\t// the animation is stuck at the end, so it\n\t\t\t\t// can immediately transition to another sequence\n\t\t\t\tlf->frameTime = cg.time;\n\t\t\t}\n\t\t}\n\t\tif ( anim->reversed ) {\n\t\t\tlf->frame = anim->firstFrame + anim->numFrames - 1 - f;\n\t\t}\n\t\telse if (anim->flipflop && f>=anim->numFrames) {\n\t\t\tlf->frame = anim->firstFrame + anim->numFrames - 1 - (f%anim->numFrames);\n\t\t}\n\t\telse {\n\t\t\tlf->frame = anim->firstFrame + f;\n\t\t}\n\t\tif ( cg.time > lf->frameTime ) {\n\t\t\tlf->frameTime = cg.time;\n\t\t\tif ( cg_debugAnim.integer ) {\n\t\t\t\tCG_Printf( \"Clamp lf->frameTime\\n\");\n\t\t\t}\n\t\t}\n\t}\n\n\tif ( lf->frameTime > cg.time + 200 ) {\n\t\tlf->frameTime = cg.time;\n\t}\n\n\tif ( lf->oldFrameTime > cg.time ) {\n\t\tlf->oldFrameTime = cg.time;\n\t}\n\t// calculate current lerp value\n\tif ( lf->frameTime == lf->oldFrameTime ) {\n\t\tlf->backlerp = 0;\n\t} else {\n\t\tlf->backlerp = 1.0 - (float)( cg.time - lf->oldFrameTime ) / ( lf->frameTime - lf->oldFrameTime );\n\t}\n}\n\n\n/*\n===============\nCG_ClearLerpFrame\n===============\n*/\nstatic void CG_ClearLerpFrame( clientInfo_t *ci, lerpFrame_t *lf, int animationNumber ) {\n\tlf->frameTime = lf->oldFrameTime = cg.time;\n\tCG_SetLerpFrameAnimation( ci, lf, animationNumber );\n\tlf->oldFrame = lf->frame = lf->animation->firstFrame;\n}\n\n\n/*\n===============\nCG_PlayerAnimation\n===============\n*/\nstatic void CG_PlayerAnimation( centity_t *cent, int *legsOld, int *legs, float *legsBackLerp,\n\t\t\t\t\t\tint *torsoOld, int *torso, float *torsoBackLerp ) {\n\tclientInfo_t\t*ci;\n\tint\t\t\t\tclientNum;\n\tfloat\t\t\tspeedScale;\n\n\tclientNum = cent->currentState.clientNum;\n\n\tif ( cg_noPlayerAnims.integer ) {\n\t\t*legsOld = *legs = *torsoOld = *torso = 0;\n\t\treturn;\n\t}\n\n\tif ( cent->currentState.powerups & ( 1 << PW_HASTE ) ) {\n\t\tspeedScale = 1.5;\n\t} else {\n\t\tspeedScale = 1;\n\t}\n\n\tci = &cgs.clientinfo[ clientNum ];\n\n\t// do the shuffle turn frames locally\n\tif ( cent->pe.legs.yawing && ( cent->currentState.legsAnim & ~ANIM_TOGGLEBIT ) == LEGS_IDLE ) {\n\t\tCG_RunLerpFrame( ci, &cent->pe.legs, LEGS_TURN, speedScale );\n\t} else {\n\t\tCG_RunLerpFrame( ci, &cent->pe.legs, cent->currentState.legsAnim, speedScale );\n\t}\n\n\t*legsOld = cent->pe.legs.oldFrame;\n\t*legs = cent->pe.legs.frame;\n\t*legsBackLerp = cent->pe.legs.backlerp;\n\n\tCG_RunLerpFrame( ci, &cent->pe.torso, cent->currentState.torsoAnim, speedScale );\n\n\t*torsoOld = cent->pe.torso.oldFrame;\n\t*torso = cent->pe.torso.frame;\n\t*torsoBackLerp = cent->pe.torso.backlerp;\n}\n\n/*\n=============================================================================\n\nPLAYER ANGLES\n\n=============================================================================\n*/\n\n/*\n==================\nCG_SwingAngles\n==================\n*/\nstatic void CG_SwingAngles( float destination, float swingTolerance, float clampTolerance,\n\t\t\t\t\tfloat speed, float *angle, qboolean *swinging ) {\n\tfloat\tswing;\n\tfloat\tmove;\n\tfloat\tscale;\n\n\tif ( !*swinging ) {\n\t\t// see if a swing should be started\n\t\tswing = AngleSubtract( *angle, destination );\n\t\tif ( swing > swingTolerance || swing < -swingTolerance ) {\n\t\t\t*swinging = qtrue;\n\t\t}\n\t}\n\n\tif ( !*swinging ) {\n\t\treturn;\n\t}\n\t\n\t// modify the speed depending on the delta\n\t// so it doesn't seem so linear\n\tswing = AngleSubtract( destination, *angle );\n\tscale = fabs( swing );\n\tif ( scale < swingTolerance * 0.5 ) {\n\t\tscale = 0.5;\n\t} else if ( scale < swingTolerance ) {\n\t\tscale = 1.0;\n\t} else {\n\t\tscale = 2.0;\n\t}\n\n\t// swing towards the destination angle\n\tif ( swing >= 0 ) {\n\t\tmove = cg.frametime * scale * speed;\n\t\tif ( move >= swing ) {\n\t\t\tmove = swing;\n\t\t\t*swinging = qfalse;\n\t\t}\n\t\t*angle = AngleMod( *angle + move );\n\t} else if ( swing < 0 ) {\n\t\tmove = cg.frametime * scale * -speed;\n\t\tif ( move <= swing ) {\n\t\t\tmove = swing;\n\t\t\t*swinging = qfalse;\n\t\t}\n\t\t*angle = AngleMod( *angle + move );\n\t}\n\n\t// clamp to no more than tolerance\n\tswing = AngleSubtract( destination, *angle );\n\tif ( swing > clampTolerance ) {\n\t\t*angle = AngleMod( destination - (clampTolerance - 1) );\n\t} else if ( swing < -clampTolerance ) {\n\t\t*angle = AngleMod( destination + (clampTolerance - 1) );\n\t}\n}\n\n/*\n=================\nCG_AddPainTwitch\n=================\n*/\nstatic void CG_AddPainTwitch( centity_t *cent, vec3_t torsoAngles ) {\n\tint\t\tt;\n\tfloat\tf;\n\n\tt = cg.time - cent->pe.painTime;\n\tif ( t >= PAIN_TWITCH_TIME ) {\n\t\treturn;\n\t}\n\n\tf = 1.0 - (float)t / PAIN_TWITCH_TIME;\n\n\tif ( cent->pe.painDirection ) {\n\t\ttorsoAngles[ROLL] += 20 * f;\n\t} else {\n\t\ttorsoAngles[ROLL] -= 20 * f;\n\t}\n}\n\n\n/*\n===============\nCG_PlayerAngles\n\nHandles seperate torso motion\n\n  legs pivot based on direction of movement\n\n  head always looks exactly at cent->lerpAngles\n\n  if motion < 20 degrees, show in head only\n  if < 45 degrees, also show in torso\n===============\n*/\nstatic void CG_PlayerAngles( centity_t *cent, vec3_t legs[3], vec3_t torso[3], vec3_t head[3] ) {\n\tvec3_t\t\tlegsAngles, torsoAngles, headAngles;\n\tfloat\t\tdest;\n\tstatic\tint\tmovementOffsets[8] = { 0, 22, 45, -22, 0, 22, -45, -22 };\n\tvec3_t\t\tvelocity;\n\tfloat\t\tspeed;\n\tint\t\t\tdir, clientNum;\n\tclientInfo_t\t*ci;\n\n\tVectorCopy( cent->lerpAngles, headAngles );\n\theadAngles[YAW] = AngleMod( headAngles[YAW] );\n\tVectorClear( legsAngles );\n\tVectorClear( torsoAngles );\n\n\t// --------- yaw -------------\n\n\t// allow yaw to drift a bit\n\tif ( ( cent->currentState.legsAnim & ~ANIM_TOGGLEBIT ) != LEGS_IDLE \n\t\t|| ( cent->currentState.torsoAnim & ~ANIM_TOGGLEBIT ) != TORSO_STAND  ) {\n\t\t// if not standing still, always point all in the same direction\n\t\tcent->pe.torso.yawing = qtrue;\t// always center\n\t\tcent->pe.torso.pitching = qtrue;\t// always center\n\t\tcent->pe.legs.yawing = qtrue;\t// always center\n\t}\n\n\t// adjust legs for movement dir\n\tif ( cent->currentState.eFlags & EF_DEAD ) {\n\t\t// don't let dead bodies twitch\n\t\tdir = 0;\n\t} else {\n\t\tdir = cent->currentState.angles2[YAW];\n\t\tif ( dir < 0 || dir > 7 ) {\n\t\t\tCG_Error( \"Bad player movement angle\" );\n\t\t}\n\t}\n\tlegsAngles[YAW] = headAngles[YAW] + movementOffsets[ dir ];\n\ttorsoAngles[YAW] = headAngles[YAW] + 0.25 * movementOffsets[ dir ];\n\n\t// torso\n\tCG_SwingAngles( torsoAngles[YAW], 25, 90, cg_swingSpeed.value, &cent->pe.torso.yawAngle, &cent->pe.torso.yawing );\n\tCG_SwingAngles( legsAngles[YAW], 40, 90, cg_swingSpeed.value, &cent->pe.legs.yawAngle, &cent->pe.legs.yawing );\n\n\ttorsoAngles[YAW] = cent->pe.torso.yawAngle;\n\tlegsAngles[YAW] = cent->pe.legs.yawAngle;\n\n\n\t// --------- pitch -------------\n\n\t// only show a fraction of the pitch angle in the torso\n\tif ( headAngles[PITCH] > 180 ) {\n\t\tdest = (-360 + headAngles[PITCH]) * 0.75f;\n\t} else {\n\t\tdest = headAngles[PITCH] * 0.75f;\n\t}\n\tCG_SwingAngles( dest, 15, 30, 0.1f, &cent->pe.torso.pitchAngle, &cent->pe.torso.pitching );\n\ttorsoAngles[PITCH] = cent->pe.torso.pitchAngle;\n\n\t//\n\tclientNum = cent->currentState.clientNum;\n\tif ( clientNum >= 0 && clientNum < MAX_CLIENTS ) {\n\t\tci = &cgs.clientinfo[ clientNum ];\n\t\tif ( ci->fixedtorso ) {\n\t\t\ttorsoAngles[PITCH] = 0.0f;\n\t\t}\n\t}\n\n\t// --------- roll -------------\n\n\n\t// lean towards the direction of travel\n\tVectorCopy( cent->currentState.pos.trDelta, velocity );\n\tspeed = VectorNormalize( velocity );\n\tif ( speed ) {\n\t\tvec3_t\taxis[3];\n\t\tfloat\tside;\n\n\t\tspeed *= 0.05f;\n\n\t\tAnglesToAxis( legsAngles, axis );\n\t\tside = speed * DotProduct( velocity, axis[1] );\n\t\tlegsAngles[ROLL] -= side;\n\n\t\tside = speed * DotProduct( velocity, axis[0] );\n\t\tlegsAngles[PITCH] += side;\n\t}\n\n\t//\n\tclientNum = cent->currentState.clientNum;\n\tif ( clientNum >= 0 && clientNum < MAX_CLIENTS ) {\n\t\tci = &cgs.clientinfo[ clientNum ];\n\t\tif ( ci->fixedlegs ) {\n\t\t\tlegsAngles[YAW] = torsoAngles[YAW];\n\t\t\tlegsAngles[PITCH] = 0.0f;\n\t\t\tlegsAngles[ROLL] = 0.0f;\n\t\t}\n\t}\n\n\t// pain twitch\n\tCG_AddPainTwitch( cent, torsoAngles );\n\n\t// pull the angles back out of the hierarchial chain\n\tAnglesSubtract( headAngles, torsoAngles, headAngles );\n\tAnglesSubtract( torsoAngles, legsAngles, torsoAngles );\n\tAnglesToAxis( legsAngles, legs );\n\tAnglesToAxis( torsoAngles, torso );\n\tAnglesToAxis( headAngles, head );\n}\n\n\n//==========================================================================\n\n/*\n===============\nCG_HasteTrail\n===============\n*/\nstatic void CG_HasteTrail( centity_t *cent ) {\n\tlocalEntity_t\t*smoke;\n\tvec3_t\t\t\torigin;\n\tint\t\t\t\tanim;\n\n\tif ( cent->trailTime > cg.time ) {\n\t\treturn;\n\t}\n\tanim = cent->pe.legs.animationNumber & ~ANIM_TOGGLEBIT;\n\tif ( anim != LEGS_RUN && anim != LEGS_BACK ) {\n\t\treturn;\n\t}\n\n\tcent->trailTime += 100;\n\tif ( cent->trailTime < cg.time ) {\n\t\tcent->trailTime = cg.time;\n\t}\n\n\tVectorCopy( cent->lerpOrigin, origin );\n\torigin[2] -= 16;\n\n\tsmoke = CG_SmokePuff( origin, vec3_origin, \n\t\t\t\t  8, \n\t\t\t\t  1, 1, 1, 1,\n\t\t\t\t  500, \n\t\t\t\t  cg.time,\n\t\t\t\t  0,\n\t\t\t\t  0,\n\t\t\t\t  cgs.media.hastePuffShader );\n\n\t// use the optimized local entity add\n\tsmoke->leType = LE_SCALE_FADE;\n}\n\n/*\n===============\nCG_TrailItem\n===============\n*/\nstatic void CG_TrailItem( centity_t *cent, qhandle_t hModel ) {\n\trefEntity_t\t\tent;\n\tvec3_t\t\t\tangles;\n\tvec3_t\t\t\taxis[3];\n\n\tVectorCopy( cent->lerpAngles, angles );\n\tangles[PITCH] = 0;\n\tangles[ROLL] = 0;\n\tAnglesToAxis( angles, axis );\n\n\tmemset( &ent, 0, sizeof( ent ) );\n\tVectorMA( cent->lerpOrigin, -16, axis[0], ent.origin );\n\tent.origin[2] += 16;\n\tangles[YAW] += 90;\n\tAnglesToAxis( angles, ent.axis );\n\n\tent.hModel = hModel;\n\ttrap_R_AddRefEntityToScene( &ent );\n}\n\n\n/*\n===============\nCG_PlayerFlag\n===============\n*/\nstatic void CG_PlayerFlag( centity_t *cent, qhandle_t hSkin, refEntity_t *torso ) {\n\tclientInfo_t\t*ci;\n\trefEntity_t\tpole;\n\trefEntity_t\tflag;\n\tvec3_t\t\tangles, dir;\n\tint\t\t\tlegsAnim, flagAnim, updateangles;\n\tfloat\t\tangle, d;\n\n\t// show the flag pole model\n\tmemset( &pole, 0, sizeof(pole) );\n\tpole.hModel = cgs.media.flagPoleModel;\n\tVectorCopy( torso->lightingOrigin, pole.lightingOrigin );\n\tpole.shadowPlane = torso->shadowPlane;\n\tpole.renderfx = torso->renderfx;\n\tCG_PositionEntityOnTag( &pole, torso, torso->hModel, \"tag_flag\" );\n\ttrap_R_AddRefEntityToScene( &pole );\n\n\t// show the flag model\n\tmemset( &flag, 0, sizeof(flag) );\n\tflag.hModel = cgs.media.flagFlapModel;\n\tflag.customSkin = hSkin;\n\tVectorCopy( torso->lightingOrigin, flag.lightingOrigin );\n\tflag.shadowPlane = torso->shadowPlane;\n\tflag.renderfx = torso->renderfx;\n\n\tVectorClear(angles);\n\n\tupdateangles = qfalse;\n\tlegsAnim = cent->currentState.legsAnim & ~ANIM_TOGGLEBIT;\n\tif( legsAnim == LEGS_IDLE || legsAnim == LEGS_IDLECR ) {\n\t\tflagAnim = FLAG_STAND;\n\t} else if ( legsAnim == LEGS_WALK || legsAnim == LEGS_WALKCR ) {\n\t\tflagAnim = FLAG_STAND;\n\t\tupdateangles = qtrue;\n\t} else {\n\t\tflagAnim = FLAG_RUN;\n\t\tupdateangles = qtrue;\n\t}\n\n\tif ( updateangles ) {\n\n\t\tVectorCopy( cent->currentState.pos.trDelta, dir );\n\t\t// add gravity\n\t\tdir[2] += 100;\n\t\tVectorNormalize( dir );\n\t\td = DotProduct(pole.axis[2], dir);\n\t\t// if there is anough movement orthogonal to the flag pole\n\t\tif (fabs(d) < 0.9) {\n\t\t\t//\n\t\t\td = DotProduct(pole.axis[0], dir);\n\t\t\tif (d > 1.0f) {\n\t\t\t\td = 1.0f;\n\t\t\t}\n\t\t\telse if (d < -1.0f) {\n\t\t\t\td = -1.0f;\n\t\t\t}\n\t\t\tangle = acos(d);\n\n\t\t\td = DotProduct(pole.axis[1], dir);\n\t\t\tif (d < 0) {\n\t\t\t\tangles[YAW] = 360 - angle * 180 / M_PI;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tangles[YAW] = angle * 180 / M_PI;\n\t\t\t}\n\t\t\tif (angles[YAW] < 0)\n\t\t\t\tangles[YAW] += 360;\n\t\t\tif (angles[YAW] > 360)\n\t\t\t\tangles[YAW] -= 360;\n\n\t\t\t//vectoangles( cent->currentState.pos.trDelta, tmpangles );\n\t\t\t//angles[YAW] = tmpangles[YAW] + 45 - cent->pe.torso.yawAngle;\n\t\t\t// change the yaw angle\n\t\t\tCG_SwingAngles( angles[YAW], 25, 90, 0.15f, &cent->pe.flag.yawAngle, &cent->pe.flag.yawing );\n\t\t}\n\n\t\t/*\n\t\td = DotProduct(pole.axis[2], dir);\n\t\tangle = Q_acos(d);\n\n\t\td = DotProduct(pole.axis[1], dir);\n\t\tif (d < 0) {\n\t\t\tangle = 360 - angle * 180 / M_PI;\n\t\t}\n\t\telse {\n\t\t\tangle = angle * 180 / M_PI;\n\t\t}\n\t\tif (angle > 340 && angle < 20) {\n\t\t\tflagAnim = FLAG_RUNUP;\n\t\t}\n\t\tif (angle > 160 && angle < 200) {\n\t\t\tflagAnim = FLAG_RUNDOWN;\n\t\t}\n\t\t*/\n\t}\n\n\t// set the yaw angle\n\tangles[YAW] = cent->pe.flag.yawAngle;\n\t// lerp the flag animation frames\n\tci = &cgs.clientinfo[ cent->currentState.clientNum ];\n\tCG_RunLerpFrame( ci, &cent->pe.flag, flagAnim, 1 );\n\tflag.oldframe = cent->pe.flag.oldFrame;\n\tflag.frame = cent->pe.flag.frame;\n\tflag.backlerp = cent->pe.flag.backlerp;\n\n\tAnglesToAxis( angles, flag.axis );\n\tCG_PositionRotatedEntityOnTag( &flag, &pole, pole.hModel, \"tag_flag\" );\n\n\ttrap_R_AddRefEntityToScene( &flag );\n}\n\n\n/*\n===============\nCG_PlayerPowerups\n===============\n*/\nstatic void CG_PlayerPowerups( centity_t *cent, refEntity_t *torso ) {\n\tint\t\tpowerups;\n\tclientInfo_t\t*ci;\n\n\tpowerups = cent->currentState.powerups;\n\tif ( !powerups ) {\n\t\treturn;\n\t}\n\n\t// quad gives a dlight\n\tif ( powerups & ( 1 << PW_QUAD ) ) {\n\t\ttrap_R_AddLightToScene( cent->lerpOrigin, 200 + (rand()&31), 0.2f, 0.2f, 1 );\n\t}\n\n\t// flight plays a looped sound\n\tif ( powerups & ( 1 << PW_FLIGHT ) ) {\n\t\ttrap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, cgs.media.flightSound );\n\t}\n\n\tci = &cgs.clientinfo[ cent->currentState.clientNum ];\n\t// redflag\n\tif ( powerups & ( 1 << PW_REDFLAG ) ) {\n\t\tif (ci->newAnims) {\n\t\t\tCG_PlayerFlag( cent, cgs.media.redFlagFlapSkin, torso );\n\t\t}\n\t\telse {\n\t\t\tCG_TrailItem( cent, cgs.media.redFlagModel );\n\t\t}\n\t\ttrap_R_AddLightToScene( cent->lerpOrigin, 200 + (rand()&31), 1.0, 0.2f, 0.2f );\n\t}\n\n\t// blueflag\n\tif ( powerups & ( 1 << PW_BLUEFLAG ) ) {\n\t\tif (ci->newAnims){\n\t\t\tCG_PlayerFlag( cent, cgs.media.blueFlagFlapSkin, torso );\n\t\t}\n\t\telse {\n\t\t\tCG_TrailItem( cent, cgs.media.blueFlagModel );\n\t\t}\n\t\ttrap_R_AddLightToScene( cent->lerpOrigin, 200 + (rand()&31), 0.2f, 0.2f, 1.0 );\n\t}\n\n\t// neutralflag\n\tif ( powerups & ( 1 << PW_NEUTRALFLAG ) ) {\n\t\tif (ci->newAnims) {\n\t\t\tCG_PlayerFlag( cent, cgs.media.neutralFlagFlapSkin, torso );\n\t\t}\n\t\telse {\n\t\t\tCG_TrailItem( cent, cgs.media.neutralFlagModel );\n\t\t}\n\t\ttrap_R_AddLightToScene( cent->lerpOrigin, 200 + (rand()&31), 1.0, 1.0, 1.0 );\n\t}\n\n\t// haste leaves smoke trails\n\tif ( powerups & ( 1 << PW_HASTE ) ) {\n\t\tCG_HasteTrail( cent );\n\t}\n}\n\n\n/*\n===============\nCG_PlayerFloatSprite\n\nFloat a sprite over the player's head\n===============\n*/\nstatic void CG_PlayerFloatSprite( centity_t *cent, qhandle_t shader ) {\n\tint\t\t\t\trf;\n\trefEntity_t\t\tent;\n\n\tif ( cent->currentState.number == cg.snap->ps.clientNum && !cg.renderingThirdPerson ) {\n\t\trf = RF_THIRD_PERSON;\t\t// only show in mirrors\n\t} else {\n\t\trf = 0;\n\t}\n\n\tmemset( &ent, 0, sizeof( ent ) );\n\tVectorCopy( cent->lerpOrigin, ent.origin );\n\tent.origin[2] += 48;\n\tent.reType = RT_SPRITE;\n\tent.customShader = shader;\n\tent.radius = 10;\n\tent.renderfx = rf;\n\tent.shaderRGBA[0] = 255;\n\tent.shaderRGBA[1] = 255;\n\tent.shaderRGBA[2] = 255;\n\tent.shaderRGBA[3] = 255;\n\ttrap_R_AddRefEntityToScene( &ent );\n}\n\n\n\n/*\n===============\nCG_PlayerSprites\n\nFloat sprites over the player's head\n===============\n*/\nstatic void CG_PlayerSprites( centity_t *cent ) {\n\tint\t\tteam;\n\n\tif ( cent->currentState.eFlags & EF_CONNECTION ) {\n\t\tCG_PlayerFloatSprite( cent, cgs.media.connectionShader );\n\t\treturn;\n\t}\n\n\tif ( cent->currentState.eFlags & EF_TALK ) {\n\t\tCG_PlayerFloatSprite( cent, cgs.media.balloonShader );\n\t\treturn;\n\t}\n\n\tif ( cent->currentState.eFlags & EF_AWARD_IMPRESSIVE ) {\n\t\tCG_PlayerFloatSprite( cent, cgs.media.medalImpressive );\n\t\treturn;\n\t}\n\n\tif ( cent->currentState.eFlags & EF_AWARD_EXCELLENT ) {\n\t\tCG_PlayerFloatSprite( cent, cgs.media.medalExcellent );\n\t\treturn;\n\t}\n\n\tif ( cent->currentState.eFlags & EF_AWARD_GAUNTLET ) {\n\t\tCG_PlayerFloatSprite( cent, cgs.media.medalGauntlet );\n\t\treturn;\n\t}\n\n\tif ( cent->currentState.eFlags & EF_AWARD_DEFEND ) {\n\t\tCG_PlayerFloatSprite( cent, cgs.media.medalDefend );\n\t\treturn;\n\t}\n\n\tif ( cent->currentState.eFlags & EF_AWARD_ASSIST ) {\n\t\tCG_PlayerFloatSprite( cent, cgs.media.medalAssist );\n\t\treturn;\n\t}\n\n\tif ( cent->currentState.eFlags & EF_AWARD_CAP ) {\n\t\tCG_PlayerFloatSprite( cent, cgs.media.medalCapture );\n\t\treturn;\n\t}\n\n\tteam = cgs.clientinfo[ cent->currentState.clientNum ].team;\n\tif ( !(cent->currentState.eFlags & EF_DEAD) && \n\t\tcg.snap->ps.persistant[PERS_TEAM] == team &&\n\t\tcgs.gametype >= GT_TEAM) {\n\t\tif (cg_drawFriend.integer) {\n\t\t\tCG_PlayerFloatSprite( cent, cgs.media.friendShader );\n\t\t}\n\t\treturn;\n\t}\n}\n\n/*\n===============\nCG_PlayerShadow\n\nReturns the Z component of the surface being shadowed\n\n  should it return a full plane instead of a Z?\n===============\n*/\n#define\tSHADOW_DISTANCE\t\t128\nstatic qboolean CG_PlayerShadow( centity_t *cent, float *shadowPlane ) {\n\tvec3_t\t\tend, mins = {-15, -15, 0}, maxs = {15, 15, 2};\n\ttrace_t\t\ttrace;\n\tfloat\t\talpha;\n\n\t*shadowPlane = 0;\n\n\tif ( cg_shadows.integer == 0 ) {\n\t\treturn qfalse;\n\t}\n\n\t// no shadows when invisible\n\tif ( cent->currentState.powerups & ( 1 << PW_INVIS ) ) {\n\t\treturn qfalse;\n\t}\n\n\t// send a trace down from the player to the ground\n\tVectorCopy( cent->lerpOrigin, end );\n\tend[2] -= SHADOW_DISTANCE;\n\n\ttrap_CM_BoxTrace( &trace, cent->lerpOrigin, end, mins, maxs, 0, MASK_PLAYERSOLID );\n\n\t// no shadow if too high\n\tif ( trace.fraction == 1.0 || trace.startsolid || trace.allsolid ) {\n\t\treturn qfalse;\n\t}\n\n\t*shadowPlane = trace.endpos[2] + 1;\n\n\tif ( cg_shadows.integer != 1 ) {\t// no mark for stencil or projection shadows\n\t\treturn qtrue;\n\t}\n\n\t// fade the shadow out with height\n\talpha = 1.0 - trace.fraction;\n\n\t// bk0101022 - hack / FPE - bogus planes?\n\t//assert( DotProduct( trace.plane.normal, trace.plane.normal ) != 0.0f ) \n\n\t// add the mark as a temporary, so it goes directly to the renderer\n\t// without taking a spot in the cg_marks array\n\tCG_ImpactMark( cgs.media.shadowMarkShader, trace.endpos, trace.plane.normal, \n\t\tcent->pe.legs.yawAngle, alpha,alpha,alpha,1, qfalse, 24, qtrue );\n\n\treturn qtrue;\n}\n\n\n/*\n===============\nCG_PlayerSplash\n\nDraw a mark at the water surface\n===============\n*/\nstatic void CG_PlayerSplash( centity_t *cent ) {\n\tvec3_t\t\tstart, end;\n\ttrace_t\t\ttrace;\n\tint\t\t\tcontents;\n\tpolyVert_t\tverts[4];\n\n\tif ( !cg_shadows.integer ) {\n\t\treturn;\n\t}\n\n\tVectorCopy( cent->lerpOrigin, end );\n\tend[2] -= 24;\n\n\t// if the feet aren't in liquid, don't make a mark\n\t// this won't handle moving water brushes, but they wouldn't draw right anyway...\n\tcontents = trap_CM_PointContents( end, 0 );\n\tif ( !( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) ) {\n\t\treturn;\n\t}\n\n\tVectorCopy( cent->lerpOrigin, start );\n\tstart[2] += 32;\n\n\t// if the head isn't out of liquid, don't make a mark\n\tcontents = trap_CM_PointContents( start, 0 );\n\tif ( contents & ( CONTENTS_SOLID | CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) {\n\t\treturn;\n\t}\n\n\t// trace down to find the surface\n\ttrap_CM_BoxTrace( &trace, start, end, NULL, NULL, 0, ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) );\n\n\tif ( trace.fraction == 1.0 ) {\n\t\treturn;\n\t}\n\n\t// create a mark polygon\n\tVectorCopy( trace.endpos, verts[0].xyz );\n\tverts[0].xyz[0] -= 32;\n\tverts[0].xyz[1] -= 32;\n\tverts[0].st[0] = 0;\n\tverts[0].st[1] = 0;\n\tverts[0].modulate[0] = 255;\n\tverts[0].modulate[1] = 255;\n\tverts[0].modulate[2] = 255;\n\tverts[0].modulate[3] = 255;\n\n\tVectorCopy( trace.endpos, verts[1].xyz );\n\tverts[1].xyz[0] -= 32;\n\tverts[1].xyz[1] += 32;\n\tverts[1].st[0] = 0;\n\tverts[1].st[1] = 1;\n\tverts[1].modulate[0] = 255;\n\tverts[1].modulate[1] = 255;\n\tverts[1].modulate[2] = 255;\n\tverts[1].modulate[3] = 255;\n\n\tVectorCopy( trace.endpos, verts[2].xyz );\n\tverts[2].xyz[0] += 32;\n\tverts[2].xyz[1] += 32;\n\tverts[2].st[0] = 1;\n\tverts[2].st[1] = 1;\n\tverts[2].modulate[0] = 255;\n\tverts[2].modulate[1] = 255;\n\tverts[2].modulate[2] = 255;\n\tverts[2].modulate[3] = 255;\n\n\tVectorCopy( trace.endpos, verts[3].xyz );\n\tverts[3].xyz[0] += 32;\n\tverts[3].xyz[1] -= 32;\n\tverts[3].st[0] = 1;\n\tverts[3].st[1] = 0;\n\tverts[3].modulate[0] = 255;\n\tverts[3].modulate[1] = 255;\n\tverts[3].modulate[2] = 255;\n\tverts[3].modulate[3] = 255;\n\n\ttrap_R_AddPolyToScene( cgs.media.wakeMarkShader, 4, verts );\n}\n\n\n\n/*\n===============\nCG_AddRefEntityWithPowerups\n\nAdds a piece with modifications or duplications for powerups\nAlso called by CG_Missile for quad rockets, but nobody can tell...\n===============\n*/\nvoid CG_AddRefEntityWithPowerups( refEntity_t *ent, entityState_t *state, int team ) {\n\n\tif ( state->powerups & ( 1 << PW_INVIS ) ) {\n\t\tent->customShader = cgs.media.invisShader;\n\t\ttrap_R_AddRefEntityToScene( ent );\n\t} else {\n\t\t/*\n\t\tif ( state->eFlags & EF_KAMIKAZE ) {\n\t\t\tif (team == TEAM_BLUE)\n\t\t\t\tent->customShader = cgs.media.blueKamikazeShader;\n\t\t\telse\n\t\t\t\tent->customShader = cgs.media.redKamikazeShader;\n\t\t\ttrap_R_AddRefEntityToScene( ent );\n\t\t}\n\t\telse {*/\n\t\t\ttrap_R_AddRefEntityToScene( ent );\n\t\t//}\n\n\t\tif ( state->powerups & ( 1 << PW_QUAD ) )\n\t\t{\n\t\t\tif (team == TEAM_RED)\n\t\t\t\tent->customShader = cgs.media.redQuadShader;\n\t\t\telse\n\t\t\t\tent->customShader = cgs.media.quadShader;\n\t\t\ttrap_R_AddRefEntityToScene( ent );\n\t\t}\n\t\tif ( state->powerups & ( 1 << PW_REGEN ) ) {\n\t\t\tif ( ( ( cg.time / 100 ) % 10 ) == 1 ) {\n\t\t\t\tent->customShader = cgs.media.regenShader;\n\t\t\t\ttrap_R_AddRefEntityToScene( ent );\n\t\t\t}\n\t\t}\n\t\tif ( state->powerups & ( 1 << PW_BATTLESUIT ) ) {\n\t\t\tent->customShader = cgs.media.battleSuitShader;\n\t\t\ttrap_R_AddRefEntityToScene( ent );\n\t\t}\n\t}\n}\n\n/*\n=================\nCG_LightVerts\n=================\n*/\nint CG_LightVerts( vec3_t normal, int numVerts, polyVert_t *verts )\n{\n\tint\t\t\t\ti, j;\n\tfloat\t\t\tincoming;\n\tvec3_t\t\t\tambientLight;\n\tvec3_t\t\t\tlightDir;\n\tvec3_t\t\t\tdirectedLight;\n\n\ttrap_R_LightForPoint( verts[0].xyz, ambientLight, directedLight, lightDir );\n\n\tfor (i = 0; i < numVerts; i++) {\n\t\tincoming = DotProduct (normal, lightDir);\n\t\tif ( incoming <= 0 ) {\n\t\t\tverts[i].modulate[0] = ambientLight[0];\n\t\t\tverts[i].modulate[1] = ambientLight[1];\n\t\t\tverts[i].modulate[2] = ambientLight[2];\n\t\t\tverts[i].modulate[3] = 255;\n\t\t\tcontinue;\n\t\t} \n\t\tj = ( ambientLight[0] + incoming * directedLight[0] );\n\t\tif ( j > 255 ) {\n\t\t\tj = 255;\n\t\t}\n\t\tverts[i].modulate[0] = j;\n\n\t\tj = ( ambientLight[1] + incoming * directedLight[1] );\n\t\tif ( j > 255 ) {\n\t\t\tj = 255;\n\t\t}\n\t\tverts[i].modulate[1] = j;\n\n\t\tj = ( ambientLight[2] + incoming * directedLight[2] );\n\t\tif ( j > 255 ) {\n\t\t\tj = 255;\n\t\t}\n\t\tverts[i].modulate[2] = j;\n\n\t\tverts[i].modulate[3] = 255;\n\t}\n\treturn qtrue;\n}\n\n/*\n===============\nCG_Player\n===============\n*/\nvoid CG_Player( centity_t *cent ) {\n\tclientInfo_t\t*ci;\n\trefEntity_t\t\tlegs;\n\trefEntity_t\t\ttorso;\n\trefEntity_t\t\thead;\n\tint\t\t\t\tclientNum;\n\tint\t\t\t\trenderfx;\n\tqboolean\t\tshadow;\n\tfloat\t\t\tshadowPlane;\n\n\t// the client number is stored in clientNum.  It can't be derived\n\t// from the entity number, because a single client may have\n\t// multiple corpses on the level using the same clientinfo\n\tclientNum = cent->currentState.clientNum;\n\tif ( clientNum < 0 || clientNum >= MAX_CLIENTS ) {\n\t\tCG_Error( \"Bad clientNum on player entity\");\n\t}\n\tci = &cgs.clientinfo[ clientNum ];\n\n\t// it is possible to see corpses from disconnected players that may\n\t// not have valid clientinfo\n\tif ( !ci->infoValid ) {\n\t\treturn;\n\t}\n\n\t// get the player model information\n\trenderfx = 0;\n\tif ( cent->currentState.number == cg.snap->ps.clientNum) {\n\t\tif (!cg.renderingThirdPerson) {\n\t\t\trenderfx = RF_THIRD_PERSON;\t\t\t// only draw in mirrors\n\t\t} else {\n\t\t\tif (cg_cameraMode.integer) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\n\tmemset( &legs, 0, sizeof(legs) );\n\tmemset( &torso, 0, sizeof(torso) );\n\tmemset( &head, 0, sizeof(head) );\n\n\t// get the rotation information\n\tCG_PlayerAngles( cent, legs.axis, torso.axis, head.axis );\n\t\n\t// get the animation state (after rotation, to allow feet shuffle)\n\tCG_PlayerAnimation( cent, &legs.oldframe, &legs.frame, &legs.backlerp,\n\t\t &torso.oldframe, &torso.frame, &torso.backlerp );\n\n\t// add the talk baloon or disconnect icon\n\tCG_PlayerSprites( cent );\n\n\t// add the shadow\n\tshadow = CG_PlayerShadow( cent, &shadowPlane );\n\n\t// add a water splash if partially in and out of water\n\tCG_PlayerSplash( cent );\n\n\tif ( cg_shadows.integer == 3 && shadow ) {\n\t\trenderfx |= RF_SHADOW_PLANE;\n\t}\n\trenderfx |= RF_LIGHTING_ORIGIN;\t\t\t// use the same origin for all\n\n\t//\n\t// add the legs\n\t//\n\tlegs.hModel = ci->legsModel;\n\tlegs.customSkin = ci->legsSkin;\n\n\tVectorCopy( cent->lerpOrigin, legs.origin );\n\n\tVectorCopy( cent->lerpOrigin, legs.lightingOrigin );\n\tlegs.shadowPlane = shadowPlane;\n\tlegs.renderfx = renderfx;\n\tVectorCopy (legs.origin, legs.oldorigin);\t// don't positionally lerp at all\n\n\tCG_AddRefEntityWithPowerups( &legs, &cent->currentState, ci->team );\n\n\t// if the model failed, allow the default nullmodel to be displayed\n\tif (!legs.hModel) {\n\t\treturn;\n\t}\n\n\t//\n\t// add the torso\n\t//\n\ttorso.hModel = ci->torsoModel;\n\tif (!torso.hModel) {\n\t\treturn;\n\t}\n\n\ttorso.customSkin = ci->torsoSkin;\n\n\tVectorCopy( cent->lerpOrigin, torso.lightingOrigin );\n\n\tCG_PositionRotatedEntityOnTag( &torso, &legs, ci->legsModel, \"tag_torso\");\n\n\ttorso.shadowPlane = shadowPlane;\n\ttorso.renderfx = renderfx;\n\n\tCG_AddRefEntityWithPowerups( &torso, &cent->currentState, ci->team );\n\n\t//\n\t// add the head\n\t//\n\thead.hModel = ci->headModel;\n\tif (!head.hModel) {\n\t\treturn;\n\t}\n\thead.customSkin = ci->headSkin;\n\n\tVectorCopy( cent->lerpOrigin, head.lightingOrigin );\n\n\tCG_PositionRotatedEntityOnTag( &head, &torso, ci->torsoModel, \"tag_head\");\n\n\thead.shadowPlane = shadowPlane;\n\thead.renderfx = renderfx;\n\n\tCG_AddRefEntityWithPowerups( &head, &cent->currentState, ci->team );\n\n\t//\n\t// add the gun / barrel / flash\n\t//\n\tCG_AddPlayerWeapon( &torso, NULL, cent, ci->team );\n\n\t// add powerups floating behind the player\n\tCG_PlayerPowerups( cent, &torso );\n}\n\n\n//=====================================================================\n\n/*\n===============\nCG_ResetPlayerEntity\n\nA player just came into view or teleported, so reset all animation info\n===============\n*/\nvoid CG_ResetPlayerEntity( centity_t *cent ) {\n\tcent->errorTime = -99999;\t\t// guarantee no error decay added\n\tcent->extrapolated = qfalse;\t\n\n\tCG_ClearLerpFrame( &cgs.clientinfo[ cent->currentState.clientNum ], &cent->pe.legs, cent->currentState.legsAnim );\n\tCG_ClearLerpFrame( &cgs.clientinfo[ cent->currentState.clientNum ], &cent->pe.torso, cent->currentState.torsoAnim );\n\n\tBG_EvaluateTrajectory( &cent->currentState.pos, cg.time, cent->lerpOrigin );\n\tBG_EvaluateTrajectory( &cent->currentState.apos, cg.time, cent->lerpAngles );\n\n\tVectorCopy( cent->lerpOrigin, cent->rawOrigin );\n\tVectorCopy( cent->lerpAngles, cent->rawAngles );\n\n\tmemset( &cent->pe.legs, 0, sizeof( cent->pe.legs ) );\n\tcent->pe.legs.yawAngle = cent->rawAngles[YAW];\n\tcent->pe.legs.yawing = qfalse;\n\tcent->pe.legs.pitchAngle = 0;\n\tcent->pe.legs.pitching = qfalse;\n\n\tmemset( &cent->pe.torso, 0, sizeof( cent->pe.legs ) );\n\tcent->pe.torso.yawAngle = cent->rawAngles[YAW];\n\tcent->pe.torso.yawing = qfalse;\n\tcent->pe.torso.pitchAngle = cent->rawAngles[PITCH];\n\tcent->pe.torso.pitching = qfalse;\n\n\tif ( cg_debugPosition.integer ) {\n\t\tCG_Printf(\"%i ResetPlayerEntity yaw=%i\\n\", cent->currentState.number, cent->pe.torso.yawAngle );\n\t}\n}\n\n"
  },
  {
    "path": "src/cgame/cg_playerstate.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n// cg_playerstate.c -- this file acts on changes in a new playerState_t\n// With normal play, this will be done after local prediction, but when\n// following another player or playing back a demo, it will be checked\n// when the snapshot transitions like all the other entities\n\n#include \"cg_local.h\"\n\n/*\n==============\nCG_CheckAmmo\n\nIf the ammo has gone low enough to generate the warning, play a sound\n==============\n*/\nvoid CG_CheckAmmo( void ) {\n\tint\t\ti;\n\tint\t\ttotal;\n\tint\t\tprevious;\n\tint\t\tweapons;\n\n\t// see about how many seconds of ammo we have remaining\n\tweapons = cg.snap->ps.stats[ STAT_WEAPONS ];\n\ttotal = 0;\n\tfor ( i = WP_MACHINEGUN ; i < WP_NUM_WEAPONS ; i++ ) {\n\t\tif ( ! ( weapons & ( 1 << i ) ) ) {\n\t\t\tcontinue;\n\t\t}\n\t\tswitch ( i ) {\n\t\tcase WP_ROCKET_LAUNCHER:\n\t\tcase WP_GRENADE_LAUNCHER:\n\t\tcase WP_RAILGUN:\n\t\tcase WP_SHOTGUN:\n\t\t\ttotal += cg.snap->ps.ammo[i] * 1000;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\ttotal += cg.snap->ps.ammo[i] * 200;\n\t\t\tbreak;\n\t\t}\n\t\tif ( total >= 5000 ) {\n\t\t\tcg.lowAmmoWarning = 0;\n\t\t\treturn;\n\t\t}\n\t}\n\n\tprevious = cg.lowAmmoWarning;\n\n\tif ( total == 0 ) {\n\t\tcg.lowAmmoWarning = 2;\n\t} else {\n\t\tcg.lowAmmoWarning = 1;\n\t}\n\n\t// play a sound on transitions\n\tif ( cg.lowAmmoWarning != previous ) {\n\t\ttrap_S_StartLocalSound( cgs.media.noAmmoSound, CHAN_LOCAL_SOUND );\n\t}\n}\n\n/*\n==============\nCG_DamageFeedback\n==============\n*/\nvoid CG_DamageFeedback( int yawByte, int pitchByte, int damage ) {\n\tfloat\t\tleft, front, up;\n\tfloat\t\tkick;\n\tint\t\t\thealth;\n\tfloat\t\tscale;\n\tvec3_t\t\tdir;\n\tvec3_t\t\tangles;\n\tfloat\t\tdist;\n\tfloat\t\tyaw, pitch;\n\n\t// show the attacking player's head and name in corner\n\tcg.attackerTime = cg.time;\n\n\t// the lower on health you are, the greater the view kick will be\n\thealth = cg.snap->ps.stats[STAT_HEALTH];\n\tif ( health < 40 ) {\n\t\tscale = 1;\n\t} else {\n\t\tscale = 40.0 / health;\n\t}\n\tkick = damage * scale;\n\n\tif (kick < 5)\n\t\tkick = 5;\n\tif (kick > 10)\n\t\tkick = 10;\n\n\t// if yaw and pitch are both 255, make the damage always centered (falling, etc)\n\tif ( yawByte == 255 && pitchByte == 255 ) {\n\t\tcg.damageX = 0;\n\t\tcg.damageY = 0;\n\t\tcg.v_dmg_roll = 0;\n\t\tcg.v_dmg_pitch = -kick;\n\t} else {\n\t\t// positional\n\t\tpitch = pitchByte / 255.0 * 360;\n\t\tyaw = yawByte / 255.0 * 360;\n\n\t\tangles[PITCH] = pitch;\n\t\tangles[YAW] = yaw;\n\t\tangles[ROLL] = 0;\n\n\t\tAngleVectors( angles, dir, NULL, NULL );\n\t\tVectorSubtract( vec3_origin, dir, dir );\n\n\t\tfront = DotProduct (dir, cg.refdef.viewaxis[0] );\n\t\tleft = DotProduct (dir, cg.refdef.viewaxis[1] );\n\t\tup = DotProduct (dir, cg.refdef.viewaxis[2] );\n\n\t\tdir[0] = front;\n\t\tdir[1] = left;\n\t\tdir[2] = 0;\n\t\tdist = VectorLength( dir );\n\t\tif ( dist < 0.1 ) {\n\t\t\tdist = 0.1f;\n\t\t}\n\n\t\tcg.v_dmg_roll = kick * left;\n\t\t\n\t\tcg.v_dmg_pitch = -kick * front;\n\n\t\tif ( front <= 0.1 ) {\n\t\t\tfront = 0.1f;\n\t\t}\n\t\tcg.damageX = -left / front;\n\t\tcg.damageY = up / dist;\n\t}\n\n\t// clamp the position\n\tif ( cg.damageX > 1.0 ) {\n\t\tcg.damageX = 1.0;\n\t}\n\tif ( cg.damageX < - 1.0 ) {\n\t\tcg.damageX = -1.0;\n\t}\n\n\tif ( cg.damageY > 1.0 ) {\n\t\tcg.damageY = 1.0;\n\t}\n\tif ( cg.damageY < - 1.0 ) {\n\t\tcg.damageY = -1.0;\n\t}\n\n\t// don't let the screen flashes vary as much\n\tif ( kick > 10 ) {\n\t\tkick = 10;\n\t}\n\tcg.damageValue = kick;\n\tcg.v_dmg_time = cg.time + DAMAGE_TIME;\n\tcg.damageTime = cg.snap->serverTime;\n}\n\n\n\n\n/*\n================\nCG_Respawn\n\nA respawn happened this snapshot\n================\n*/\nvoid CG_Respawn( void ) {\n\t// no error decay on player movement\n\tcg.thisFrameTeleport = qtrue;\n\n\t// display weapons available\n\tcg.weaponSelectTime = cg.time;\n\n\t// select the weapon the server says we are using\n\tcg.weaponSelect = cg.snap->ps.weapon;\n}\n\nextern char *eventnames[];\n\n/*\n==============\nCG_CheckPlayerstateEvents\n==============\n*/\nvoid CG_CheckPlayerstateEvents( playerState_t *ps, playerState_t *ops ) {\n\tint\t\t\ti;\n\tint\t\t\tevent;\n\tcentity_t\t*cent;\n\n\tif ( ps->externalEvent && ps->externalEvent != ops->externalEvent ) {\n\t\tcent = &cg_entities[ ps->clientNum ];\n\t\tcent->currentState.event = ps->externalEvent;\n\t\tcent->currentState.eventParm = ps->externalEventParm;\n\t\tCG_EntityEvent( cent, cent->lerpOrigin );\n\t}\n\n\tcent = &cg.predictedPlayerEntity; // cg_entities[ ps->clientNum ];\n\t// go through the predictable events buffer\n\tfor ( i = ps->eventSequence - MAX_PS_EVENTS ; i < ps->eventSequence ; i++ ) {\n\t\t// if we have a new predictable event\n\t\tif ( i >= ops->eventSequence\n\t\t\t// or the server told us to play another event instead of a predicted event we already issued\n\t\t\t// or something the server told us changed our prediction causing a different event\n\t\t\t|| (i > ops->eventSequence - MAX_PS_EVENTS && ps->events[i & (MAX_PS_EVENTS-1)] != ops->events[i & (MAX_PS_EVENTS-1)]) ) {\n\n\t\t\tevent = ps->events[ i & (MAX_PS_EVENTS-1) ];\n\t\t\tcent->currentState.event = event;\n\t\t\tcent->currentState.eventParm = ps->eventParms[ i & (MAX_PS_EVENTS-1) ];\n\t\t\tCG_EntityEvent( cent, cent->lerpOrigin );\n\n\t\t\tcg.predictableEvents[ i & (MAX_PREDICTED_EVENTS-1) ] = event;\n\n\t\t\tcg.eventSequence++;\n\t\t}\n\t}\n}\n\n/*\n==================\nCG_CheckChangedPredictableEvents\n==================\n*/\nvoid CG_CheckChangedPredictableEvents( playerState_t *ps ) {\n\tint i;\n\tint event;\n\tcentity_t\t*cent;\n\n\tcent = &cg.predictedPlayerEntity;\n\tfor ( i = ps->eventSequence - MAX_PS_EVENTS ; i < ps->eventSequence ; i++ ) {\n\t\t//\n\t\tif (i >= cg.eventSequence) {\n\t\t\tcontinue;\n\t\t}\n\t\t// if this event is not further back in than the maximum predictable events we remember\n\t\tif (i > cg.eventSequence - MAX_PREDICTED_EVENTS) {\n\t\t\t// if the new playerstate event is different from a previously predicted one\n\t\t\tif ( ps->events[i & (MAX_PS_EVENTS-1)] != cg.predictableEvents[i & (MAX_PREDICTED_EVENTS-1) ] ) {\n\n\t\t\t\tevent = ps->events[ i & (MAX_PS_EVENTS-1) ];\n\t\t\t\tcent->currentState.event = event;\n\t\t\t\tcent->currentState.eventParm = ps->eventParms[ i & (MAX_PS_EVENTS-1) ];\n\t\t\t\tCG_EntityEvent( cent, cent->lerpOrigin );\n\n\t\t\t\tcg.predictableEvents[ i & (MAX_PREDICTED_EVENTS-1) ] = event;\n\n\t\t\t\tif ( cg_showmiss.integer ) {\n\t\t\t\t\tCG_Printf(\"WARNING: changed predicted event\\n\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n/*\n==================\npushReward\n==================\n*/\nstatic void pushReward(sfxHandle_t sfx, qhandle_t shader, int rewardCount) {\n\tif (cg.rewardStack < (MAX_REWARDSTACK-1)) {\n\t\tcg.rewardStack++;\n\t\tcg.rewardSound[cg.rewardStack] = sfx;\n\t\tcg.rewardShader[cg.rewardStack] = shader;\n\t\tcg.rewardCount[cg.rewardStack] = rewardCount;\n\t}\n}\n\n/*\n==================\nCG_CheckLocalSounds\n==================\n*/\nvoid CG_CheckLocalSounds( playerState_t *ps, playerState_t *ops ) {\n\tint\t\t\thighScore, health, armor, reward;\n\tsfxHandle_t sfx;\n\n\t// don't play the sounds if the player just changed teams\n\tif ( ps->persistant[PERS_TEAM] != ops->persistant[PERS_TEAM] ) {\n\t\treturn;\n\t}\n\n\t// hit changes\n\tif ( ps->persistant[PERS_HITS] > ops->persistant[PERS_HITS] ) {\n\t\tarmor  = ps->persistant[PERS_ATTACKEE_ARMOR] & 0xff;\n\t\thealth = ps->persistant[PERS_ATTACKEE_ARMOR] >> 8;\n\t\ttrap_S_StartLocalSound( cgs.media.hitSound, CHAN_LOCAL_SOUND );\n\t} else if ( ps->persistant[PERS_HITS] < ops->persistant[PERS_HITS] ) {\n\t\ttrap_S_StartLocalSound( cgs.media.hitTeamSound, CHAN_LOCAL_SOUND );\n\t}\n\n\t// health changes of more than -1 should make pain sounds\n\tif ( ps->stats[STAT_HEALTH] < ops->stats[STAT_HEALTH] - 1 ) {\n\t\tif ( ps->stats[STAT_HEALTH] > 0 ) {\n\t\t\tCG_PainEvent( &cg.predictedPlayerEntity, ps->stats[STAT_HEALTH] );\n\t\t}\n\t}\n\n\n\t// if we are going into the intermission, don't start any voices\n\tif ( cg.intermissionStarted ) {\n\t\treturn;\n\t}\n\n\t// reward sounds\n\treward = qfalse;\n\tif (ps->persistant[PERS_CAPTURES] != ops->persistant[PERS_CAPTURES]) {\n\t\tpushReward(cgs.media.captureAwardSound, cgs.media.medalCapture, ps->persistant[PERS_CAPTURES]);\n\t\treward = qtrue;\n\t\t//Com_Printf(\"capture\\n\");\n\t}\n\tif (ps->persistant[PERS_IMPRESSIVE_COUNT] != ops->persistant[PERS_IMPRESSIVE_COUNT]) {\n\t\tsfx = cgs.media.impressiveSound;\n\t\tpushReward(sfx, cgs.media.medalImpressive, ps->persistant[PERS_IMPRESSIVE_COUNT]);\n\t\treward = qtrue;\n\t\t//Com_Printf(\"impressive\\n\");\n\t}\n\tif (ps->persistant[PERS_EXCELLENT_COUNT] != ops->persistant[PERS_EXCELLENT_COUNT]) {\n\t\tsfx = cgs.media.excellentSound;\n\t\tpushReward(sfx, cgs.media.medalExcellent, ps->persistant[PERS_EXCELLENT_COUNT]);\n\t\treward = qtrue;\n\t\t//Com_Printf(\"excellent\\n\");\n\t}\n\tif (ps->persistant[PERS_GAUNTLET_FRAG_COUNT] != ops->persistant[PERS_GAUNTLET_FRAG_COUNT]) {\n\t\tsfx = cgs.media.humiliationSound;\n\t\tpushReward(sfx, cgs.media.medalGauntlet, ps->persistant[PERS_GAUNTLET_FRAG_COUNT]);\n\t\treward = qtrue;\n\t\t//Com_Printf(\"guantlet frag\\n\");\n\t}\n\tif (ps->persistant[PERS_DEFEND_COUNT] != ops->persistant[PERS_DEFEND_COUNT]) {\n\t\tpushReward(cgs.media.defendSound, cgs.media.medalDefend, ps->persistant[PERS_DEFEND_COUNT]);\n\t\treward = qtrue;\n\t\t//Com_Printf(\"defend\\n\");\n\t}\n\tif (ps->persistant[PERS_ASSIST_COUNT] != ops->persistant[PERS_ASSIST_COUNT]) {\n\t\tpushReward(cgs.media.assistSound, cgs.media.medalAssist, ps->persistant[PERS_ASSIST_COUNT]);\n\t\treward = qtrue;\n\t\t//Com_Printf(\"assist\\n\");\n\t}\n\t// if any of the player event bits changed\n\tif (ps->persistant[PERS_PLAYEREVENTS] != ops->persistant[PERS_PLAYEREVENTS]) {\n\t\tif ((ps->persistant[PERS_PLAYEREVENTS] & PLAYEREVENT_DENIEDREWARD) !=\n\t\t\t\t(ops->persistant[PERS_PLAYEREVENTS] & PLAYEREVENT_DENIEDREWARD)) {\n\t\t\ttrap_S_StartLocalSound( cgs.media.deniedSound, CHAN_ANNOUNCER );\n\t\t}\n\t\telse if ((ps->persistant[PERS_PLAYEREVENTS] & PLAYEREVENT_GAUNTLETREWARD) !=\n\t\t\t\t(ops->persistant[PERS_PLAYEREVENTS] & PLAYEREVENT_GAUNTLETREWARD)) {\n\t\t\ttrap_S_StartLocalSound( cgs.media.humiliationSound, CHAN_ANNOUNCER );\n\t\t}\n\t\telse if ((ps->persistant[PERS_PLAYEREVENTS] & PLAYEREVENT_HOLYSHIT) !=\n\t\t\t\t(ops->persistant[PERS_PLAYEREVENTS] & PLAYEREVENT_HOLYSHIT)) {\n\t\t\ttrap_S_StartLocalSound( cgs.media.holyShitSound, CHAN_ANNOUNCER );\n\t\t}\n\t\treward = qtrue;\n\t}\n\n\t// check for flag pickup\n\tif ( cgs.gametype >= GT_TEAM ) {\n\t\tif ((ps->powerups[PW_REDFLAG] != ops->powerups[PW_REDFLAG] && ps->powerups[PW_REDFLAG]) ||\n\t\t\t(ps->powerups[PW_BLUEFLAG] != ops->powerups[PW_BLUEFLAG] && ps->powerups[PW_BLUEFLAG]) ||\n\t\t\t(ps->powerups[PW_NEUTRALFLAG] != ops->powerups[PW_NEUTRALFLAG] && ps->powerups[PW_NEUTRALFLAG]) )\n\t\t{\n\t\t\ttrap_S_StartLocalSound( cgs.media.youHaveFlagSound, CHAN_ANNOUNCER );\n\t\t}\n\t}\n\n\t// lead changes\n\tif (!reward) {\n\t\t//\n\t\tif ( !cg.warmup ) {\n\t\t\t// never play lead changes during warmup\n\t\t\tif ( ps->persistant[PERS_RANK] != ops->persistant[PERS_RANK] ) {\n\t\t\t\tif ( cgs.gametype < GT_TEAM) {\n\t\t\t\t\tif (  ps->persistant[PERS_RANK] == 0 ) {\n\t\t\t\t\t\tCG_AddBufferedSound(cgs.media.takenLeadSound);\n\t\t\t\t\t} else if ( ps->persistant[PERS_RANK] == RANK_TIED_FLAG ) {\n\t\t\t\t\t\tCG_AddBufferedSound(cgs.media.tiedLeadSound);\n\t\t\t\t\t} else if ( ( ops->persistant[PERS_RANK] & ~RANK_TIED_FLAG ) == 0 ) {\n\t\t\t\t\t\tCG_AddBufferedSound(cgs.media.lostLeadSound);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// timelimit warnings\n\tif ( cgs.timelimit > 0 ) {\n\t\tint\t\tmsec;\n\n\t\tmsec = cg.time - cgs.levelStartTime;\n\t\tif ( !( cg.timelimitWarnings & 4 ) && msec > ( cgs.timelimit * 60 + 2 ) * 1000 ) {\n\t\t\tcg.timelimitWarnings |= 1 | 2 | 4;\n\t\t\ttrap_S_StartLocalSound( cgs.media.suddenDeathSound, CHAN_ANNOUNCER );\n\t\t}\n\t\telse if ( !( cg.timelimitWarnings & 2 ) && msec > (cgs.timelimit - 1) * 60 * 1000 ) {\n\t\t\tcg.timelimitWarnings |= 1 | 2;\n\t\t\ttrap_S_StartLocalSound( cgs.media.oneMinuteSound, CHAN_ANNOUNCER );\n\t\t}\n\t\telse if ( cgs.timelimit > 5 && !( cg.timelimitWarnings & 1 ) && msec > (cgs.timelimit - 5) * 60 * 1000 ) {\n\t\t\tcg.timelimitWarnings |= 1;\n\t\t\ttrap_S_StartLocalSound( cgs.media.fiveMinuteSound, CHAN_ANNOUNCER );\n\t\t}\n\t}\n\n\t// fraglimit warnings\n\tif ( cgs.fraglimit > 0 && cgs.gametype < GT_CTF) {\n\t\thighScore = cgs.scores1;\n\t\tif ( !( cg.fraglimitWarnings & 4 ) && highScore == (cgs.fraglimit - 1) ) {\n\t\t\tcg.fraglimitWarnings |= 1 | 2 | 4;\n\t\t\tCG_AddBufferedSound(cgs.media.oneFragSound);\n\t\t}\n\t\telse if ( cgs.fraglimit > 2 && !( cg.fraglimitWarnings & 2 ) && highScore == (cgs.fraglimit - 2) ) {\n\t\t\tcg.fraglimitWarnings |= 1 | 2;\n\t\t\tCG_AddBufferedSound(cgs.media.twoFragSound);\n\t\t}\n\t\telse if ( cgs.fraglimit > 3 && !( cg.fraglimitWarnings & 1 ) && highScore == (cgs.fraglimit - 3) ) {\n\t\t\tcg.fraglimitWarnings |= 1;\n\t\t\tCG_AddBufferedSound(cgs.media.threeFragSound);\n\t\t}\n\t}\n}\n\n/*\n===============\nCG_TransitionPlayerState\n\n===============\n*/\nvoid CG_TransitionPlayerState( playerState_t *ps, playerState_t *ops ) {\n\t// check for changing follow mode\n\tif ( ps->clientNum != ops->clientNum ) {\n\t\tcg.thisFrameTeleport = qtrue;\n\t\t// make sure we don't get any unwanted transition effects\n\t\t*ops = *ps;\n\t}\n\n\t// damage events (player is getting wounded)\n\tif ( ps->damageEvent != ops->damageEvent && ps->damageCount ) {\n\t\tCG_DamageFeedback( ps->damageYaw, ps->damagePitch, ps->damageCount );\n\t}\n\n\t// respawning\n\tif ( ps->persistant[PERS_SPAWN_COUNT] != ops->persistant[PERS_SPAWN_COUNT] ) {\n\t\tCG_Respawn();\n\t}\n\n\tif ( cg.mapRestart ) {\n\t\tCG_Respawn();\n\t\tcg.mapRestart = qfalse;\n\t}\n\n\tif ( cg.snap->ps.pm_type != PM_INTERMISSION \n\t\t&& ps->persistant[PERS_TEAM] != TEAM_SPECTATOR ) {\n\t\tCG_CheckLocalSounds( ps, ops );\n\t}\n\n\t// check for going low on ammo\n\tCG_CheckAmmo();\n\n\t// run events\n\tCG_CheckPlayerstateEvents( ps, ops );\n\n\t// smooth the ducking viewheight change\n\tif ( ps->viewheight != ops->viewheight ) {\n\t\tcg.duckChange = ps->viewheight - ops->viewheight;\n\t\tcg.duckTime = cg.time;\n\t}\n}\n\n"
  },
  {
    "path": "src/cgame/cg_predict.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n// cg_predict.c -- this file generates cg.predictedPlayerState by either\n// interpolating between snapshots from the server or locally predicting\n// ahead the client's movement.\n// It also handles local physics interaction, like fragments bouncing off walls\n\n#include \"cg_local.h\"\n\nstatic\tpmove_t\t\tcg_pmove;\n\nstatic\tint\t\t\tcg_numSolidEntities;\nstatic\tcentity_t\t*cg_solidEntities[MAX_ENTITIES_IN_SNAPSHOT];\nstatic\tint\t\t\tcg_numTriggerEntities;\nstatic\tcentity_t\t*cg_triggerEntities[MAX_ENTITIES_IN_SNAPSHOT];\n\n/*\n====================\nCG_BuildSolidList\n\nWhen a new cg.snap has been set, this function builds a sublist\nof the entities that are actually solid, to make for more\nefficient collision detection\n====================\n*/\nvoid CG_BuildSolidList( void ) {\n\tint\t\t\ti;\n\tcentity_t\t*cent;\n\tsnapshot_t\t*snap;\n\tentityState_t\t*ent;\n\n\tcg_numSolidEntities = 0;\n\tcg_numTriggerEntities = 0;\n\n\tif ( cg.nextSnap && !cg.nextFrameTeleport && !cg.thisFrameTeleport ) {\n\t\tsnap = cg.nextSnap;\n\t} else {\n\t\tsnap = cg.snap;\n\t}\n\n\tfor ( i = 0 ; i < snap->numEntities ; i++ ) {\n\t\tcent = &cg_entities[ snap->entities[ i ].number ];\n\t\tent = &cent->currentState;\n\n\t\tif ( ent->eType == ET_ITEM || ent->eType == ET_PUSH_TRIGGER || ent->eType == ET_TELEPORT_TRIGGER ) {\n\t\t\tcg_triggerEntities[cg_numTriggerEntities] = cent;\n\t\t\tcg_numTriggerEntities++;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif ( cent->nextState.solid ) {\n\t\t\tcg_solidEntities[cg_numSolidEntities] = cent;\n\t\t\tcg_numSolidEntities++;\n\t\t\tcontinue;\n\t\t}\n\t}\n}\n\n/*\n====================\nCG_ClipMoveToEntities\n\n====================\n*/\nstatic void CG_ClipMoveToEntities ( const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end,\n\t\t\t\t\t\t\tint skipNumber, int mask, trace_t *tr ) {\n\tint\t\t\ti, x, zd, zu;\n\ttrace_t\t\ttrace;\n\tentityState_t\t*ent;\n\tclipHandle_t \tcmodel;\n\tvec3_t\t\tbmins, bmaxs;\n\tvec3_t\t\torigin, angles;\n\tcentity_t\t*cent;\n\n\tfor ( i = 0 ; i < cg_numSolidEntities ; i++ ) {\n\t\tcent = cg_solidEntities[ i ];\n\t\tent = &cent->currentState;\n\n\t\tif ( ent->number == skipNumber ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif ( ent->solid == SOLID_BMODEL ) {\n\t\t\t// special value for bmodel\n\t\t\tcmodel = trap_CM_InlineModel( ent->modelindex );\n\t\t\tVectorCopy( cent->lerpAngles, angles );\n\t\t\tBG_EvaluateTrajectory( &cent->currentState.pos, cg.physicsTime, origin );\n\t\t} else {\n\t\t\t// encoded bbox\n\t\t\tx = (ent->solid & 255);\n\t\t\tzd = ((ent->solid>>8) & 255);\n\t\t\tzu = ((ent->solid>>16) & 255) - 32;\n\n\t\t\tbmins[0] = bmins[1] = -x;\n\t\t\tbmaxs[0] = bmaxs[1] = x;\n\t\t\tbmins[2] = -zd;\n\t\t\tbmaxs[2] = zu;\n\n\t\t\tcmodel = trap_CM_TempBoxModel( bmins, bmaxs );\n\t\t\tVectorCopy( vec3_origin, angles );\n\t\t\tVectorCopy( cent->lerpOrigin, origin );\n\t\t}\n\n\n\t\ttrap_CM_TransformedBoxTrace ( &trace, start, end,\n\t\t\tmins, maxs, cmodel,  mask, origin, angles);\n\n\t\tif (trace.allsolid || trace.fraction < tr->fraction) {\n\t\t\ttrace.entityNum = ent->number;\n\t\t\t*tr = trace;\n\t\t} else if (trace.startsolid) {\n\t\t\ttr->startsolid = qtrue;\n\t\t}\n\t\tif ( tr->allsolid ) {\n\t\t\treturn;\n\t\t}\n\t}\n}\n\n/*\n================\nCG_Trace\n================\n*/\nvoid\tCG_Trace( trace_t *result, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, \n\t\t\t\t\t int skipNumber, int mask ) {\n\ttrace_t\tt;\n\n\ttrap_CM_BoxTrace ( &t, start, end, mins, maxs, 0, mask);\n\tt.entityNum = t.fraction != 1.0 ? ENTITYNUM_WORLD : ENTITYNUM_NONE;\n\t// check all other solid models\n\tCG_ClipMoveToEntities (start, mins, maxs, end, skipNumber, mask, &t);\n\n\t*result = t;\n}\n\n/*\n================\nCG_PointContents\n================\n*/\nint\t\tCG_PointContents( const vec3_t point, int passEntityNum ) {\n\tint\t\t\ti;\n\tentityState_t\t*ent;\n\tcentity_t\t*cent;\n\tclipHandle_t cmodel;\n\tint\t\t\tcontents;\n\n\tcontents = trap_CM_PointContents (point, 0);\n\n\tfor ( i = 0 ; i < cg_numSolidEntities ; i++ ) {\n\t\tcent = cg_solidEntities[ i ];\n\n\t\tent = &cent->currentState;\n\n\t\tif ( ent->number == passEntityNum ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (ent->solid != SOLID_BMODEL) { // special value for bmodel\n\t\t\tcontinue;\n\t\t}\n\n\t\tcmodel = trap_CM_InlineModel( ent->modelindex );\n\t\tif ( !cmodel ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tcontents |= trap_CM_TransformedPointContents( point, cmodel, ent->origin, ent->angles );\n\t}\n\n\treturn contents;\n}\n\n\n/*\n========================\nCG_InterpolatePlayerState\n\nGenerates cg.predictedPlayerState by interpolating between\ncg.snap->player_state and cg.nextFrame->player_state\n========================\n*/\nstatic void CG_InterpolatePlayerState( qboolean grabAngles ) {\n\tfloat\t\t\tf;\n\tint\t\t\t\ti;\n\tplayerState_t\t*out;\n\tsnapshot_t\t\t*prev, *next;\n\n\tout = &cg.predictedPlayerState;\n\tprev = cg.snap;\n\tnext = cg.nextSnap;\n\n\t*out = cg.snap->ps;\n\n\t// if we are still allowing local input, short circuit the view angles\n\tif ( grabAngles ) {\n\t\tusercmd_t\tcmd;\n\t\tint\t\t\tcmdNum;\n\n\t\tcmdNum = trap_GetCurrentCmdNumber();\n\t\ttrap_GetUserCmd( cmdNum, &cmd );\n\n\t\tPM_UpdateViewAngles( out, &cmd );\n\t}\n\n\t// if the next frame is a teleport, we can't lerp to it\n\tif ( cg.nextFrameTeleport ) {\n\t\treturn;\n\t}\n\n\tif ( !next || next->serverTime <= prev->serverTime ) {\n\t\treturn;\n\t}\n\n\tf = (float)( cg.time - prev->serverTime ) / ( next->serverTime - prev->serverTime );\n\n\ti = next->ps.bobCycle;\n\tif ( i < prev->ps.bobCycle ) {\n\t\ti += 256;\t\t// handle wraparound\n\t}\n\tout->bobCycle = prev->ps.bobCycle + f * ( i - prev->ps.bobCycle );\n\n\tfor ( i = 0 ; i < 3 ; i++ ) {\n\t\tout->origin[i] = prev->ps.origin[i] + f * (next->ps.origin[i] - prev->ps.origin[i] );\n\t\tif ( !grabAngles ) {\n\t\t\tout->viewangles[i] = LerpAngle( \n\t\t\t\tprev->ps.viewangles[i], next->ps.viewangles[i], f );\n\t\t}\n\t\tout->velocity[i] = prev->ps.velocity[i] + \n\t\t\tf * (next->ps.velocity[i] - prev->ps.velocity[i] );\n\t}\n\n}\n\n/*\n===================\nCG_TouchItem\n===================\n*/\nstatic void CG_TouchItem( centity_t *cent ) {\n\tgitem_t\t\t*item;\n\n\tif ( !cg_predictItems.integer ) {\n\t\treturn;\n\t}\n\tif ( !BG_PlayerTouchesItem( &cg.predictedPlayerState, &cent->currentState, cg.time ) ) {\n\t\treturn;\n\t}\n\n\t// never pick an item up twice in a prediction\n\tif ( cent->miscTime == cg.time ) {\n\t\treturn;\n\t}\n\n\tif ( !BG_CanItemBeGrabbed( cgs.gametype, &cent->currentState, &cg.predictedPlayerState ) ) {\n\t\treturn;\t\t// can't hold it\n\t}\n\n\titem = &bg_itemlist[ cent->currentState.modelindex ];\n\n\t// Special case for flags.  \n\t// We don't predict touching our own flag\n\tif( cgs.gametype == GT_CTF ) {\n\t\tif (cg.predictedPlayerState.persistant[PERS_TEAM] == TEAM_RED &&\n\t\t\titem->giTag == PW_REDFLAG)\n\t\t\treturn;\n\t\tif (cg.predictedPlayerState.persistant[PERS_TEAM] == TEAM_BLUE &&\n\t\t\titem->giTag == PW_BLUEFLAG)\n\t\t\treturn;\n\t}\n\n\t// grab it\n\tBG_AddPredictableEventToPlayerstate( EV_ITEM_PICKUP, cent->currentState.modelindex , &cg.predictedPlayerState);\n\n\t// remove it from the frame so it won't be drawn\n\tcent->currentState.eFlags |= EF_NODRAW;\n\n\t// don't touch it again this prediction\n\tcent->miscTime = cg.time;\n\n\t// if its a weapon, give them some predicted ammo so the autoswitch will work\n\tif ( item->giType == IT_WEAPON ) {\n\t\tcg.predictedPlayerState.stats[ STAT_WEAPONS ] |= 1 << item->giTag;\n\t\tif ( !cg.predictedPlayerState.ammo[ item->giTag ] ) {\n\t\t\tcg.predictedPlayerState.ammo[ item->giTag ] = 1;\n\t\t}\n\t}\n}\n\n\n/*\n=========================\nCG_TouchTriggerPrediction\n\nPredict push triggers and items\n=========================\n*/\nstatic void CG_TouchTriggerPrediction( void ) {\n\tint\t\t\ti;\n\ttrace_t\t\ttrace;\n\tentityState_t\t*ent;\n\tclipHandle_t cmodel;\n\tcentity_t\t*cent;\n\tqboolean\tspectator;\n\n\t// dead clients don't activate triggers\n\tif ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) {\n\t\treturn;\n\t}\n\n\tspectator = ( cg.predictedPlayerState.pm_type == PM_SPECTATOR );\n\n\tif ( cg.predictedPlayerState.pm_type != PM_NORMAL && !spectator ) {\n\t\treturn;\n\t}\n\n\tfor ( i = 0 ; i < cg_numTriggerEntities ; i++ ) {\n\t\tcent = cg_triggerEntities[ i ];\n\t\tent = &cent->currentState;\n\n\t\tif ( ent->eType == ET_ITEM && !spectator ) {\n\t\t\tCG_TouchItem( cent );\n\t\t\tcontinue;\n\t\t}\n\n\t\tif ( ent->solid != SOLID_BMODEL ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tcmodel = trap_CM_InlineModel( ent->modelindex );\n\t\tif ( !cmodel ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\ttrap_CM_BoxTrace( &trace, cg.predictedPlayerState.origin, cg.predictedPlayerState.origin, \n\t\t\tcg_pmove.mins, cg_pmove.maxs, cmodel, -1 );\n\n\t\tif ( !trace.startsolid ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif ( ent->eType == ET_TELEPORT_TRIGGER ) {\n\t\t\tcg.hyperspace = qtrue;\n\t\t} else if ( ent->eType == ET_PUSH_TRIGGER ) {\n\t\t\tBG_TouchJumpPad( &cg.predictedPlayerState, ent );\n\t\t}\n\t}\n\n\t// if we didn't touch a jump pad this pmove frame\n\tif ( cg.predictedPlayerState.jumppad_frame != cg.predictedPlayerState.pmove_framecount ) {\n\t\tcg.predictedPlayerState.jumppad_frame = 0;\n\t\tcg.predictedPlayerState.jumppad_ent = 0;\n\t}\n}\n\n\n\n/*\n=================\nCG_PredictPlayerState\n\nGenerates cg.predictedPlayerState for the current cg.time\ncg.predictedPlayerState is guaranteed to be valid after exiting.\n\nFor demo playback, this will be an interpolation between two valid\nplayerState_t.\n\nFor normal gameplay, it will be the result of predicted usercmd_t on\ntop of the most recent playerState_t received from the server.\n\nEach new snapshot will usually have one or more new usercmd over the last,\nbut we simulate all unacknowledged commands each time, not just the new ones.\nThis means that on an internet connection, quite a few pmoves may be issued\neach frame.\n\nOPTIMIZE: don't re-simulate unless the newly arrived snapshot playerState_t\ndiffers from the predicted one.  Would require saving all intermediate\nplayerState_t during prediction.\n\nWe detect prediction errors and allow them to be decayed off over several frames\nto ease the jerk.\n=================\n*/\nvoid CG_PredictPlayerState( void ) {\n\tint\t\t\tcmdNum, current;\n\tplayerState_t\toldPlayerState;\n\tqboolean\tmoved;\n\tusercmd_t\toldestCmd;\n\tusercmd_t\tlatestCmd;\n\n\tcg.hyperspace = qfalse;\t// will be set if touching a trigger_teleport\n\n\t// if this is the first frame we must guarantee\n\t// predictedPlayerState is valid even if there is some\n\t// other error condition\n\tif ( !cg.validPPS ) {\n\t\tcg.validPPS = qtrue;\n\t\tcg.predictedPlayerState = cg.snap->ps;\n\t}\n\n\n\t// demo playback just copies the moves\n\tif ( cg.demoPlayback || (cg.snap->ps.pm_flags & PMF_FOLLOW) ) {\n\t\tCG_InterpolatePlayerState( qfalse );\n\t\treturn;\n\t}\n\n\t// non-predicting local movement will grab the latest angles\n\tif ( cg_nopredict.integer || cg_synchronousClients.integer ) {\n\t\tCG_InterpolatePlayerState( qtrue );\n\t\treturn;\n\t}\n\n\t// prepare for pmove\n\tcg_pmove.ps = &cg.predictedPlayerState;\n\tcg_pmove.trace = CG_Trace;\n\tcg_pmove.pointcontents = CG_PointContents;\n\tif ( cg_pmove.ps->pm_type == PM_DEAD ) {\n\t\tcg_pmove.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY;\n\t}\n\telse {\n\t\tcg_pmove.tracemask = MASK_PLAYERSOLID;\n\t}\n\tif ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR ) {\n\t\tcg_pmove.tracemask &= ~CONTENTS_BODY;\t// spectators can fly through bodies\n\t}\n\tcg_pmove.noFootsteps = ( cgs.dmflags & DF_NO_FOOTSTEPS ) > 0;\n\n\t// save the state before the pmove so we can detect transitions\n\toldPlayerState = cg.predictedPlayerState;\n\n\tcurrent = trap_GetCurrentCmdNumber();\n\n\t// if we don't have the commands right after the snapshot, we\n\t// can't accurately predict a current position, so just freeze at\n\t// the last good position we had\n\tcmdNum = current - CMD_BACKUP + 1;\n\ttrap_GetUserCmd( cmdNum, &oldestCmd );\n\tif ( oldestCmd.serverTime > cg.snap->ps.commandTime \n\t\t&& oldestCmd.serverTime < cg.time ) {\t// special check for map_restart\n\t\tif ( cg_showmiss.integer ) {\n\t\t\tCG_Printf (\"exceeded PACKET_BACKUP on commands\\n\");\n\t\t}\n\t\treturn;\n\t}\n\n\t// get the latest command so we can know which commands are from previous map_restarts\n\ttrap_GetUserCmd( current, &latestCmd );\n\n\t// get the most recent information we have, even if\n\t// the server time is beyond our current cg.time,\n\t// because predicted player positions are going to \n\t// be ahead of everything else anyway\n\tif ( cg.nextSnap && !cg.nextFrameTeleport && !cg.thisFrameTeleport ) {\n\t\tcg.predictedPlayerState = cg.nextSnap->ps;\n\t\tcg.physicsTime = cg.nextSnap->serverTime;\n\t} else {\n\t\tcg.predictedPlayerState = cg.snap->ps;\n\t\tcg.physicsTime = cg.snap->serverTime;\n\t}\n\n\tif ( pmove_msec.integer < 8 ) {\n\t\ttrap_Cvar_Set(\"pmove_msec\", \"8\");\n\t}\n\telse if (pmove_msec.integer > 33) {\n\t\ttrap_Cvar_Set(\"pmove_msec\", \"33\");\n\t}\n\n\tcg_pmove.pmove_fixed = pmove_fixed.integer;// | cg_pmove_fixed.integer;\n\tcg_pmove.pmove_msec = pmove_msec.integer;\n\n\t// run cmds\n\tmoved = qfalse;\n\tfor ( cmdNum = current - CMD_BACKUP + 1 ; cmdNum <= current ; cmdNum++ ) {\n\t\t// get the command\n\t\ttrap_GetUserCmd( cmdNum, &cg_pmove.cmd );\n\n\t\tif ( cg_pmove.pmove_fixed ) {\n\t\t\tPM_UpdateViewAngles( cg_pmove.ps, &cg_pmove.cmd );\n\t\t}\n\n\t\t// don't do anything if the time is before the snapshot player time\n\t\tif ( cg_pmove.cmd.serverTime <= cg.predictedPlayerState.commandTime ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// don't do anything if the command was from a previous map_restart\n\t\tif ( cg_pmove.cmd.serverTime > latestCmd.serverTime ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// check for a prediction error from last frame\n\t\t// on a lan, this will often be the exact value\n\t\t// from the snapshot, but on a wan we will have\n\t\t// to predict several commands to get to the point\n\t\t// we want to compare\n\t\tif ( cg.predictedPlayerState.commandTime == oldPlayerState.commandTime ) {\n\t\t\tvec3_t\tdelta;\n\t\t\tfloat\tlen;\n\n\t\t\tif ( cg.thisFrameTeleport ) {\n\t\t\t\t// a teleport will not cause an error decay\n\t\t\t\tVectorClear( cg.predictedError );\n\t\t\t\tif ( cg_showmiss.integer ) {\n\t\t\t\t\tCG_Printf( \"PredictionTeleport\\n\" );\n\t\t\t\t}\n\t\t\t\tcg.thisFrameTeleport = qfalse;\n\t\t\t} else {\n\t\t\t\tvec3_t\tadjusted;\n\t\t\t\tCG_AdjustPositionForMover( cg.predictedPlayerState.origin, \n\t\t\t\t\tcg.predictedPlayerState.groundEntityNum, cg.physicsTime, cg.oldTime, adjusted );\n\n\t\t\t\tif ( cg_showmiss.integer ) {\n\t\t\t\t\tif (!VectorCompare( oldPlayerState.origin, adjusted )) {\n\t\t\t\t\t\tCG_Printf(\"prediction error\\n\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tVectorSubtract( oldPlayerState.origin, adjusted, delta );\n\t\t\t\tlen = VectorLength( delta );\n\t\t\t\tif ( len > 0.1 ) {\n\t\t\t\t\tif ( cg_showmiss.integer ) {\n\t\t\t\t\t\tCG_Printf(\"Prediction miss: %f\\n\", len);\n\t\t\t\t\t}\n\t\t\t\t\tif ( cg_errorDecay.integer ) {\n\t\t\t\t\t\tint\t\tt;\n\t\t\t\t\t\tfloat\tf;\n\n\t\t\t\t\t\tt = cg.time - cg.predictedErrorTime;\n\t\t\t\t\t\tf = ( cg_errorDecay.value - t ) / cg_errorDecay.value;\n\t\t\t\t\t\tif ( f < 0 ) {\n\t\t\t\t\t\t\tf = 0;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ( f > 0 && cg_showmiss.integer ) {\n\t\t\t\t\t\t\tCG_Printf(\"Double prediction decay: %f\\n\", f);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tVectorScale( cg.predictedError, f, cg.predictedError );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tVectorClear( cg.predictedError );\n\t\t\t\t\t}\n\t\t\t\t\tVectorAdd( delta, cg.predictedError, cg.predictedError );\n\t\t\t\t\tcg.predictedErrorTime = cg.oldTime;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// don't predict gauntlet firing, which is only supposed to happen\n\t\t// when it actually inflicts damage\n\t\tcg_pmove.gauntletHit = qfalse;\n\n\t\tif ( cg_pmove.pmove_fixed ) {\n\t\t\tcg_pmove.cmd.serverTime = ((cg_pmove.cmd.serverTime + pmove_msec.integer-1) / pmove_msec.integer) * pmove_msec.integer;\n\t\t}\n\n\t\tPmove (&cg_pmove);\n\n\t\tmoved = qtrue;\n\n\t\t// add push trigger movement effects\n\t\tCG_TouchTriggerPrediction();\n\n\t\t// check for predictable events that changed from previous predictions\n\t\t//CG_CheckChangedPredictableEvents(&cg.predictedPlayerState);\n\t}\n\n\tif ( cg_showmiss.integer > 1 ) {\n\t\tCG_Printf( \"[%i : %i] \", cg_pmove.cmd.serverTime, cg.time );\n\t}\n\n\tif ( !moved ) {\n\t\tif ( cg_showmiss.integer ) {\n\t\t\tCG_Printf( \"not moved\\n\" );\n\t\t}\n\t\treturn;\n\t}\n\n\t// adjust for the movement of the groundentity\n\tCG_AdjustPositionForMover( cg.predictedPlayerState.origin, \n\t\tcg.predictedPlayerState.groundEntityNum, \n\t\tcg.physicsTime, cg.time, cg.predictedPlayerState.origin );\n\n\tif ( cg_showmiss.integer ) {\n\t\tif (cg.predictedPlayerState.eventSequence > oldPlayerState.eventSequence + MAX_PS_EVENTS) {\n\t\t\tCG_Printf(\"WARNING: dropped event\\n\");\n\t\t}\n\t}\n\n\t// fire events and other transition triggered things\n\tCG_TransitionPlayerState( &cg.predictedPlayerState, &oldPlayerState );\n\n\tif ( cg_showmiss.integer ) {\n\t\tif (cg.eventSequence > cg.predictedPlayerState.eventSequence) {\n\t\t\tCG_Printf(\"WARNING: double event\\n\");\n\t\t\tcg.eventSequence = cg.predictedPlayerState.eventSequence;\n\t\t}\n\t}\n}\n\n\n"
  },
  {
    "path": "src/cgame/cg_public.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n\n\n#define\tCMD_BACKUP\t\t\t64\t\n#define\tCMD_MASK\t\t\t(CMD_BACKUP - 1)\n// allow a lot of command backups for very fast systems\n// multiple commands may be combined into a single packet, so this\n// needs to be larger than PACKET_BACKUP\n\n\n#define\tMAX_ENTITIES_IN_SNAPSHOT\t256\n\n// snapshots are a view of the server at a given time\n\n// Snapshots are generated at regular time intervals by the server,\n// but they may not be sent if a client's rate level is exceeded, or\n// they may be dropped by the network.\ntypedef struct {\n\tint\t\t\t\tsnapFlags;\t\t\t// SNAPFLAG_RATE_DELAYED, etc\n\tint\t\t\t\tping;\n\n\tint\t\t\t\tserverTime;\t\t// server time the message is valid for (in msec)\n\n\tbyte\t\t\tareamask[MAX_MAP_AREA_BYTES];\t\t// portalarea visibility bits\n\n\tplayerState_t\tps;\t\t\t\t\t\t// complete information about the current player at this time\n\n\tint\t\t\t\tnumEntities;\t\t\t// all of the entities that need to be presented\n\tentityState_t\tentities[MAX_ENTITIES_IN_SNAPSHOT];\t// at the time of this snapshot\n\n\tint\t\t\t\tnumServerCommands;\t\t// text based server commands to execute when this\n\tint\t\t\t\tserverCommandSequence;\t// snapshot becomes current\n} snapshot_t;\n\nenum {\n  CGAME_EVENT_NONE,\n  CGAME_EVENT_TEAMMENU,\n  CGAME_EVENT_SCOREBOARD,\n  CGAME_EVENT_EDITHUD\n};\n\n\n/*\n==================================================================\n\nfunctions imported from the main executable\n\n==================================================================\n*/\n\n#define\tCGAME_IMPORT_API_VERSION\t4\n\ntypedef enum {\n\tCG_PRINT,\n\tCG_ERROR,\n\tCG_MILLISECONDS,\n\tCG_CVAR_REGISTER,\n\tCG_CVAR_UPDATE,\n\tCG_CVAR_SET,\n\tCG_CVAR_VARIABLESTRINGBUFFER,\n\tCG_ARGC,\n\tCG_ARGV,\n\tCG_ARGS,\n\tCG_FS_FOPENFILE,\n\tCG_FS_READ,\n\tCG_FS_WRITE,\n\tCG_FS_FCLOSEFILE,\n\tCG_SENDCONSOLECOMMAND,\n\tCG_ADDCOMMAND,\n\tCG_SENDCLIENTCOMMAND,\n\tCG_UPDATESCREEN,\n\tCG_CM_LOADMAP,\n\tCG_CM_NUMINLINEMODELS,\n\tCG_CM_INLINEMODEL,\n\tCG_CM_LOADMODEL,\n\tCG_CM_TEMPBOXMODEL,\n\tCG_CM_POINTCONTENTS,\n\tCG_CM_TRANSFORMEDPOINTCONTENTS,\n\tCG_CM_BOXTRACE,\n\tCG_CM_TRANSFORMEDBOXTRACE,\n\tCG_CM_MARKFRAGMENTS,\n\tCG_S_STARTSOUND,\n\tCG_S_STARTLOCALSOUND,\n\tCG_S_CLEARLOOPINGSOUNDS,\n\tCG_S_ADDLOOPINGSOUND,\n\tCG_S_UPDATEENTITYPOSITION,\n\tCG_S_RESPATIALIZE,\n\tCG_S_REGISTERSOUND,\n\tCG_S_STARTBACKGROUNDTRACK,\n\tCG_R_LOADWORLDMAP,\n\tCG_R_REGISTERMODEL,\n\tCG_R_REGISTERSKIN,\n\tCG_R_REGISTERSHADER,\n\tCG_R_CLEARSCENE,\n\tCG_R_ADDREFENTITYTOSCENE,\n\tCG_R_ADDPOLYTOSCENE,\n\tCG_R_ADDLIGHTTOSCENE,\n\tCG_R_RENDERSCENE,\n\tCG_R_SETCOLOR,\n\tCG_R_DRAWSTRETCHPIC,\n\tCG_R_MODELBOUNDS,\n\tCG_R_LERPTAG,\n\tCG_GETGLCONFIG,\n\tCG_GETGAMESTATE,\n\tCG_GETCURRENTSNAPSHOTNUMBER,\n\tCG_GETSNAPSHOT,\n\tCG_GETSERVERCOMMAND,\n\tCG_GETCURRENTCMDNUMBER,\n\tCG_GETUSERCMD,\n\tCG_SETUSERCMDVALUE,\n\tCG_R_REGISTERSHADERNOMIP,\n\tCG_MEMORY_REMAINING,\n\tCG_R_REGISTERFONT,\n\tCG_KEY_ISDOWN,\n\tCG_KEY_GETCATCHER,\n\tCG_KEY_SETCATCHER,\n\tCG_KEY_GETKEY,\n \tCG_PC_ADD_GLOBAL_DEFINE,\n\tCG_PC_LOAD_SOURCE,\n\tCG_PC_FREE_SOURCE,\n\tCG_PC_READ_TOKEN,\n\tCG_PC_SOURCE_FILE_AND_LINE,\n\tCG_S_STOPBACKGROUNDTRACK,\n\tCG_REAL_TIME,\n\tCG_SNAPVECTOR,\n\tCG_REMOVECOMMAND,\n\tCG_R_LIGHTFORPOINT,\n\tCG_CIN_PLAYCINEMATIC,\n\tCG_CIN_STOPCINEMATIC,\n\tCG_CIN_RUNCINEMATIC,\n\tCG_CIN_DRAWCINEMATIC,\n\tCG_CIN_SETEXTENTS,\n\tCG_R_REMAP_SHADER,\n\tCG_S_ADDREALLOOPINGSOUND,\n\tCG_S_STOPLOOPINGSOUND,\n\n\tCG_CM_TEMPCAPSULEMODEL,\n\tCG_CM_CAPSULETRACE,\n\tCG_CM_TRANSFORMEDCAPSULETRACE,\n\tCG_R_ADDADDITIVELIGHTTOSCENE,\n\tCG_GET_ENTITY_TOKEN,\n\tCG_R_ADDPOLYSTOSCENE,\n\tCG_R_INPVS,\n\t// 1.32\n\tCG_FS_SEEK,\n\n/*\n\tCG_LOADCAMERA,\n\tCG_STARTCAMERA,\n\tCG_GETCAMERAINFO,\n*/\n\n\tCG_MEMSET = 100,\n\tCG_MEMCPY,\n\tCG_STRNCPY,\n\tCG_SIN,\n\tCG_COS,\n\tCG_ATAN2,\n\tCG_SQRT,\n\tCG_FLOOR,\n\tCG_CEIL,\n\tCG_TESTPRINTINT,\n\tCG_TESTPRINTFLOAT,\n\tCG_ACOS\n} cgameImport_t;\n\n\n/*\n==================================================================\n\nfunctions exported to the main executable\n\n==================================================================\n*/\n\ntypedef enum {\n\tCG_INIT,\n//\tvoid CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum )\n\t// called when the level loads or when the renderer is restarted\n\t// all media should be registered at this time\n\t// cgame will display loading status by calling SCR_Update, which\n\t// will call CG_DrawInformation during the loading process\n\t// reliableCommandSequence will be 0 on fresh loads, but higher for\n\t// demos, tourney restarts, or vid_restarts\n\n\tCG_SHUTDOWN,\n//\tvoid (*CG_Shutdown)( void );\n\t// oportunity to flush and close any open files\n\n\tCG_CONSOLE_COMMAND,\n//\tqboolean (*CG_ConsoleCommand)( void );\n\t// a console command has been issued locally that is not recognized by the\n\t// main game system.\n\t// use Cmd_Argc() / Cmd_Argv() to read the command, return qfalse if the\n\t// command is not known to the game\n\n\tCG_DRAW_ACTIVE_FRAME,\n//\tvoid (*CG_DrawActiveFrame)( int serverTime, stereoFrame_t stereoView, qboolean demoPlayback );\n\t// Generates and draws a game scene and status information at the given time.\n\t// If demoPlayback is set, local movement prediction will not be enabled\n\n\tCG_CROSSHAIR_PLAYER,\n//\tint (*CG_CrosshairPlayer)( void );\n\n\tCG_LAST_ATTACKER,\n//\tint (*CG_LastAttacker)( void );\n\n\tCG_KEY_EVENT, \n//\tvoid\t(*CG_KeyEvent)( int key, qboolean down );\n\n\tCG_MOUSE_EVENT,\n//\tvoid\t(*CG_MouseEvent)( int dx, int dy );\n\tCG_EVENT_HANDLING\n//\tvoid (*CG_EventHandling)(int type);\n} cgameExport_t;\n\n//----------------------------------------------\n"
  },
  {
    "path": "src/cgame/cg_scoreboard.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n// cg_scoreboard -- draw the scoreboard on top of the game screen\n#include \"cg_local.h\"\n\n\n#define\tSCOREBOARD_X\t\t(0)\n\n#define SB_HEADER\t\t\t86\n#define SB_TOP\t\t\t\t(SB_HEADER+32)\n\n// Where the status bar starts, so we don't overwrite it\n#define SB_STATUSBAR\t\t420\n\n#define SB_NORMAL_HEIGHT\t40\n#define SB_INTER_HEIGHT\t\t16 // interleaved height\n\n#define SB_MAXCLIENTS_NORMAL  ((SB_STATUSBAR - SB_TOP) / SB_NORMAL_HEIGHT)\n#define SB_MAXCLIENTS_INTER   ((SB_STATUSBAR - SB_TOP) / SB_INTER_HEIGHT - 1)\n\n// Used when interleaved\n\n\n\n#define SB_LEFT_BOTICON_X\t(SCOREBOARD_X+0)\n#define SB_LEFT_HEAD_X\t\t(SCOREBOARD_X+32)\n#define SB_RIGHT_BOTICON_X\t(SCOREBOARD_X+64)\n#define SB_RIGHT_HEAD_X\t\t(SCOREBOARD_X+96)\n// Normal\n#define SB_BOTICON_X\t\t(SCOREBOARD_X+32)\n#define SB_HEAD_X\t\t\t(SCOREBOARD_X+64)\n\n#define SB_SCORELINE_X\t\t112\n\n#define SB_RATING_WIDTH\t    (6 * BIGCHAR_WIDTH) // width 6\n#define SB_SCORE_X\t\t\t(SB_SCORELINE_X + BIGCHAR_WIDTH) // width 6\n#define SB_RATING_X\t\t\t(SB_SCORELINE_X + 6 * BIGCHAR_WIDTH) // width 6\n#define SB_PING_X\t\t\t(SB_SCORELINE_X + 12 * BIGCHAR_WIDTH + 8) // width 5\n#define SB_TIME_X\t\t\t(SB_SCORELINE_X + 17 * BIGCHAR_WIDTH + 8) // width 5\n#define SB_NAME_X\t\t\t(SB_SCORELINE_X + 22 * BIGCHAR_WIDTH) // width 15\n\n// The new and improved score board\n//\n// In cases where the number of clients is high, the score board heads are interleaved\n// here's the layout\n\n//\n//\t0   32   80  112  144   240  320  400   <-- pixel position\n//  bot head bot head score ping time name\n//  \n//  wins/losses are drawn on bot icon now\n\nstatic qboolean localClient; // true if local client has been displayed\n\n\n\t\t\t\t\t\t\t /*\n=================\nCG_DrawScoreboard\n=================\n*/\nstatic void CG_DrawClientScore( int y, score_t *score, float *color, float fade, qboolean largeFormat ) {\n\tchar\tstring[1024];\n\tvec3_t\theadAngles;\n\tclientInfo_t\t*ci;\n\tint iconx, headx;\n\n\tif ( score->client < 0 || score->client >= cgs.maxclients ) {\n\t\tCom_Printf( \"Bad score->client: %i\\n\", score->client );\n\t\treturn;\n\t}\n\t\n\tci = &cgs.clientinfo[score->client];\n\n\ticonx = SB_BOTICON_X + (SB_RATING_WIDTH / 2);\n\theadx = SB_HEAD_X + (SB_RATING_WIDTH / 2);\n\n\t// draw the handicap or bot skill marker (unless player has flag)\n\tif ( ci->powerups & ( 1 << PW_NEUTRALFLAG ) ) {\n\t\tif( largeFormat ) {\n\t\t\tCG_DrawFlagModel( iconx, y - ( 32 - BIGCHAR_HEIGHT ) / 2, 32, 32, TEAM_FREE, qfalse );\n\t\t}\n\t\telse {\n\t\t\tCG_DrawFlagModel( iconx, y, 16, 16, TEAM_FREE, qfalse );\n\t\t}\n\t} else if ( ci->powerups & ( 1 << PW_REDFLAG ) ) {\n\t\tif( largeFormat ) {\n\t\t\tCG_DrawFlagModel( iconx, y - ( 32 - BIGCHAR_HEIGHT ) / 2, 32, 32, TEAM_RED, qfalse );\n\t\t}\n\t\telse {\n\t\t\tCG_DrawFlagModel( iconx, y, 16, 16, TEAM_RED, qfalse );\n\t\t}\n\t} else if ( ci->powerups & ( 1 << PW_BLUEFLAG ) ) {\n\t\tif( largeFormat ) {\n\t\t\tCG_DrawFlagModel( iconx, y - ( 32 - BIGCHAR_HEIGHT ) / 2, 32, 32, TEAM_BLUE, qfalse );\n\t\t}\n\t\telse {\n\t\t\tCG_DrawFlagModel( iconx, y, 16, 16, TEAM_BLUE, qfalse );\n\t\t}\n\t} else {\n\t\tif ( ci->botSkill > 0 && ci->botSkill <= 5 ) {\n\t\t\tif ( cg_drawIcons.integer ) {\n\t\t\t\tif( largeFormat ) {\n\t\t\t\t\tCG_DrawPic( iconx, y - ( 32 - BIGCHAR_HEIGHT ) / 2, 32, 32, cgs.media.botSkillShaders[ ci->botSkill - 1 ] );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tCG_DrawPic( iconx, y, 16, 16, cgs.media.botSkillShaders[ ci->botSkill - 1 ] );\n\t\t\t\t}\n\t\t\t}\n\t\t} else if ( ci->handicap < 100 ) {\n\t\t\tCom_sprintf( string, sizeof( string ), \"%i\", ci->handicap );\n\t\t\tif ( cgs.gametype == GT_TOURNAMENT )\n\t\t\t\tCG_DrawSmallStringColor( iconx, y - SMALLCHAR_HEIGHT/2, string, color );\n\t\t\telse\n\t\t\t\tCG_DrawSmallStringColor( iconx, y, string, color );\n\t\t}\n\n\t\t// draw the wins / losses\n\t\tif ( cgs.gametype == GT_TOURNAMENT ) {\n\t\t\tCom_sprintf( string, sizeof( string ), \"%i/%i\", ci->wins, ci->losses );\n\t\t\tif( ci->handicap < 100 && !ci->botSkill ) {\n\t\t\t\tCG_DrawSmallStringColor( iconx, y + SMALLCHAR_HEIGHT/2, string, color );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tCG_DrawSmallStringColor( iconx, y, string, color );\n\t\t\t}\n\t\t}\n\t}\n\n\t// draw the face\n\tVectorClear( headAngles );\n\theadAngles[YAW] = 180;\n\tif( largeFormat ) {\n\t\tCG_DrawHead( headx, y - ( ICON_SIZE - BIGCHAR_HEIGHT ) / 2, ICON_SIZE, ICON_SIZE, \n\t\t\tscore->client, headAngles );\n\t}\n\telse {\n\t\tCG_DrawHead( headx, y, 16, 16, score->client, headAngles );\n\t}\n\n\t// draw the score line\n\tif ( score->ping == -1 ) {\n\t\tCom_sprintf(string, sizeof(string),\n\t\t\t\" connecting    %s\", ci->name);\n\t} else if ( ci->team == TEAM_SPECTATOR ) {\n\t\tCom_sprintf(string, sizeof(string),\n\t\t\t\" SPECT %3i %4i %s\", score->ping, score->time, ci->name);\n\t} else {\n\t\tCom_sprintf(string, sizeof(string),\n\t\t\t\"%5i %4i %4i %s\", score->score, score->ping, score->time, ci->name);\n\t}\n\n\t// highlight your position\n\tif ( score->client == cg.snap->ps.clientNum ) {\n\t\tfloat\thcolor[4];\n\t\tint\t\trank;\n\n\t\tlocalClient = qtrue;\n\n\t\tif ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR \n\t\t\t|| cgs.gametype >= GT_TEAM ) {\n\t\t\trank = -1;\n\t\t} else {\n\t\t\trank = cg.snap->ps.persistant[PERS_RANK] & ~RANK_TIED_FLAG;\n\t\t}\n\t\tif ( rank == 0 ) {\n\t\t\thcolor[0] = 0;\n\t\t\thcolor[1] = 0;\n\t\t\thcolor[2] = 0.7f;\n\t\t} else if ( rank == 1 ) {\n\t\t\thcolor[0] = 0.7f;\n\t\t\thcolor[1] = 0;\n\t\t\thcolor[2] = 0;\n\t\t} else if ( rank == 2 ) {\n\t\t\thcolor[0] = 0.7f;\n\t\t\thcolor[1] = 0.7f;\n\t\t\thcolor[2] = 0;\n\t\t} else {\n\t\t\thcolor[0] = 0.7f;\n\t\t\thcolor[1] = 0.7f;\n\t\t\thcolor[2] = 0.7f;\n\t\t}\n\n\t\thcolor[3] = fade * 0.7;\n\t\tCG_FillRect( SB_SCORELINE_X + BIGCHAR_WIDTH + (SB_RATING_WIDTH / 2), y, \n\t\t\t640 - SB_SCORELINE_X - BIGCHAR_WIDTH, BIGCHAR_HEIGHT+1, hcolor );\n\t}\n\n\tCG_DrawBigString( SB_SCORELINE_X + (SB_RATING_WIDTH / 2), y, string, fade );\n\n\t// add the \"ready\" marker for intermission exiting\n\tif ( cg.snap->ps.stats[ STAT_CLIENTS_READY ] & ( 1 << score->client ) ) {\n\t\tCG_DrawBigStringColor( iconx, y, \"READY\", color );\n\t}\n}\n\n/*\n=================\nCG_TeamScoreboard\n=================\n*/\nstatic int CG_TeamScoreboard( int y, team_t team, float fade, int maxClients, int lineHeight ) {\n\tint\t\ti;\n\tscore_t\t*score;\n\tfloat\tcolor[4];\n\tint\t\tcount;\n\tclientInfo_t\t*ci;\n\n\tcolor[0] = color[1] = color[2] = 1.0;\n\tcolor[3] = fade;\n\n\tcount = 0;\n\tfor ( i = 0 ; i < cg.numScores && count < maxClients ; i++ ) {\n\t\tscore = &cg.scores[i];\n\t\tci = &cgs.clientinfo[ score->client ];\n\n\t\tif ( team != ci->team ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tCG_DrawClientScore( y + lineHeight * count, score, color, fade, lineHeight == SB_NORMAL_HEIGHT );\n\n\t\tcount++;\n\t}\n\n\treturn count;\n}\n\n/*\n=================\nCG_DrawScoreboard\n\nDraw the normal in-game scoreboard\n=================\n*/\nqboolean CG_DrawOldScoreboard( void ) {\n\tint\t\tx, y, w, i, n1, n2;\n\tfloat\tfade;\n\tfloat\t*fadeColor;\n\tchar\t*s;\n\tint maxClients;\n\tint lineHeight;\n\tint topBorderSize, bottomBorderSize;\n\n\t// don't draw amuthing if the menu or console is up\n\tif ( cg_paused.integer ) {\n\t\tcg.deferredPlayerLoading = 0;\n\t\treturn qfalse;\n\t}\n\n\tif ( cgs.gametype == GT_SINGLE_PLAYER && cg.predictedPlayerState.pm_type == PM_INTERMISSION ) {\n\t\tcg.deferredPlayerLoading = 0;\n\t\treturn qfalse;\n\t}\n\n\t// don't draw scoreboard during death while warmup up\n\tif ( cg.warmup && !cg.showScores ) {\n\t\treturn qfalse;\n\t}\n\n\tif ( cg.showScores || cg.predictedPlayerState.pm_type == PM_DEAD ||\n\t\t cg.predictedPlayerState.pm_type == PM_INTERMISSION ) {\n\t\tfade = 1.0;\n\t\tfadeColor = colorWhite;\n\t} else {\n\t\tfadeColor = CG_FadeColor( cg.scoreFadeTime, FADE_TIME );\n\t\t\n\t\tif ( !fadeColor ) {\n\t\t\t// next time scoreboard comes up, don't print killer\n\t\t\tcg.deferredPlayerLoading = 0;\n\t\t\tcg.killerName[0] = 0;\n\t\t\treturn qfalse;\n\t\t}\n\t\tfade = *fadeColor;\n\t}\n\n\n\t// fragged by ... line\n\tif ( cg.killerName[0] ) {\n\t\ts = va(\"Fragged by %s\", cg.killerName );\n\t\tw = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;\n\t\tx = ( SCREEN_WIDTH - w ) / 2;\n\t\ty = 40;\n\t\tCG_DrawBigString( x, y, s, fade );\n\t}\n\n\t// current rank\n\tif ( cgs.gametype < GT_TEAM) {\n\t\tif (cg.snap->ps.persistant[PERS_TEAM] != TEAM_SPECTATOR ) {\n\t\t\ts = va(\"%s place with %i\",\n\t\t\t\tCG_PlaceString( cg.snap->ps.persistant[PERS_RANK] + 1 ),\n\t\t\t\tcg.snap->ps.persistant[PERS_SCORE] );\n\t\t\tw = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;\n\t\t\tx = ( SCREEN_WIDTH - w ) / 2;\n\t\t\ty = 60;\n\t\t\tCG_DrawBigString( x, y, s, fade );\n\t\t}\n\t} else {\n\t\tif ( cg.teamScores[0] == cg.teamScores[1] ) {\n\t\t\ts = va(\"Teams are tied at %i\", cg.teamScores[0] );\n\t\t} else if ( cg.teamScores[0] >= cg.teamScores[1] ) {\n\t\t\ts = va(\"Red leads %i to %i\",cg.teamScores[0], cg.teamScores[1] );\n\t\t} else {\n\t\t\ts = va(\"Blue leads %i to %i\",cg.teamScores[1], cg.teamScores[0] );\n\t\t}\n\n\t\tw = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;\n\t\tx = ( SCREEN_WIDTH - w ) / 2;\n\t\ty = 60;\n\t\tCG_DrawBigString( x, y, s, fade );\n\t}\n\n\t// scoreboard\n\ty = SB_HEADER;\n\n\tCG_DrawPic( SB_SCORE_X + (SB_RATING_WIDTH / 2), y, 64, 32, cgs.media.scoreboardScore );\n\tCG_DrawPic( SB_PING_X - (SB_RATING_WIDTH / 2), y, 64, 32, cgs.media.scoreboardPing );\n\tCG_DrawPic( SB_TIME_X - (SB_RATING_WIDTH / 2), y, 64, 32, cgs.media.scoreboardTime );\n\tCG_DrawPic( SB_NAME_X - (SB_RATING_WIDTH / 2), y, 64, 32, cgs.media.scoreboardName );\n\n\ty = SB_TOP;\n\n\t// If there are more than SB_MAXCLIENTS_NORMAL, use the interleaved scores\n\tif ( cg.numScores > SB_MAXCLIENTS_NORMAL ) {\n\t\tmaxClients = SB_MAXCLIENTS_INTER;\n\t\tlineHeight = SB_INTER_HEIGHT;\n\t\ttopBorderSize = 8;\n\t\tbottomBorderSize = 16;\n\t} else {\n\t\tmaxClients = SB_MAXCLIENTS_NORMAL;\n\t\tlineHeight = SB_NORMAL_HEIGHT;\n\t\ttopBorderSize = 16;\n\t\tbottomBorderSize = 16;\n\t}\n\n\tlocalClient = qfalse;\n\n\tif ( cgs.gametype >= GT_TEAM ) {\n\t\t//\n\t\t// teamplay scoreboard\n\t\t//\n\t\ty += lineHeight/2;\n\n\t\tif ( cg.teamScores[0] >= cg.teamScores[1] ) {\n\t\t\tn1 = CG_TeamScoreboard( y, TEAM_RED, fade, maxClients, lineHeight );\n\t\t\tCG_DrawTeamBackground( 0, y - topBorderSize, 640, n1 * lineHeight + bottomBorderSize, 0.33f, TEAM_RED );\n\t\t\ty += (n1 * lineHeight) + BIGCHAR_HEIGHT;\n\t\t\tmaxClients -= n1;\n\t\t\tn2 = CG_TeamScoreboard( y, TEAM_BLUE, fade, maxClients, lineHeight );\n\t\t\tCG_DrawTeamBackground( 0, y - topBorderSize, 640, n2 * lineHeight + bottomBorderSize, 0.33f, TEAM_BLUE );\n\t\t\ty += (n2 * lineHeight) + BIGCHAR_HEIGHT;\n\t\t\tmaxClients -= n2;\n\t\t} else {\n\t\t\tn1 = CG_TeamScoreboard( y, TEAM_BLUE, fade, maxClients, lineHeight );\n\t\t\tCG_DrawTeamBackground( 0, y - topBorderSize, 640, n1 * lineHeight + bottomBorderSize, 0.33f, TEAM_BLUE );\n\t\t\ty += (n1 * lineHeight) + BIGCHAR_HEIGHT;\n\t\t\tmaxClients -= n1;\n\t\t\tn2 = CG_TeamScoreboard( y, TEAM_RED, fade, maxClients, lineHeight );\n\t\t\tCG_DrawTeamBackground( 0, y - topBorderSize, 640, n2 * lineHeight + bottomBorderSize, 0.33f, TEAM_RED );\n\t\t\ty += (n2 * lineHeight) + BIGCHAR_HEIGHT;\n\t\t\tmaxClients -= n2;\n\t\t}\n\t\tn1 = CG_TeamScoreboard( y, TEAM_SPECTATOR, fade, maxClients, lineHeight );\n\t\ty += (n1 * lineHeight) + BIGCHAR_HEIGHT;\n\n\t} else {\n\t\t//\n\t\t// free for all scoreboard\n\t\t//\n\t\tn1 = CG_TeamScoreboard( y, TEAM_FREE, fade, maxClients, lineHeight );\n\t\ty += (n1 * lineHeight) + BIGCHAR_HEIGHT;\n\t\tn2 = CG_TeamScoreboard( y, TEAM_SPECTATOR, fade, maxClients - n1, lineHeight );\n\t\ty += (n2 * lineHeight) + BIGCHAR_HEIGHT;\n\t}\n\n\tif (!localClient) {\n\t\t// draw local client at the bottom\n\t\tfor ( i = 0 ; i < cg.numScores ; i++ ) {\n\t\t\tif ( cg.scores[i].client == cg.snap->ps.clientNum ) {\n\t\t\t\tCG_DrawClientScore( y, &cg.scores[i], fadeColor, fade, lineHeight == SB_NORMAL_HEIGHT );\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t// load any models that have been deferred\n\tif ( ++cg.deferredPlayerLoading > 10 ) {\n\t\tCG_LoadDeferredPlayers();\n\t}\n\n\treturn qtrue;\n}\n\n//================================================================================\n\n/*\n================\nCG_CenterGiantLine\n================\n*/\nstatic void CG_CenterGiantLine( float y, const char *string ) {\n\tfloat\t\tx;\n\tvec4_t\t\tcolor;\n\n\tcolor[0] = 1;\n\tcolor[1] = 1;\n\tcolor[2] = 1;\n\tcolor[3] = 1;\n\n\tx = 0.5 * ( 640 - GIANT_WIDTH * CG_DrawStrlen( string ) );\n\n\tCG_DrawStringExt( x, y, string, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );\n}\n\n/*\n=================\nCG_DrawTourneyScoreboard\n\nDraw the oversize scoreboard for tournements\n=================\n*/\nvoid CG_DrawOldTourneyScoreboard( void ) {\n\tconst char\t\t*s;\n\tvec4_t\t\t\tcolor;\n\tint\t\t\t\tmin, tens, ones;\n\tclientInfo_t\t*ci;\n\tint\t\t\t\ty;\n\tint\t\t\t\ti;\n\n\t// request more scores regularly\n\tif ( cg.scoresRequestTime + 2000 < cg.time ) {\n\t\tcg.scoresRequestTime = cg.time;\n\t\ttrap_SendClientCommand( \"score\" );\n\t}\n\n\tcolor[0] = 1;\n\tcolor[1] = 1;\n\tcolor[2] = 1;\n\tcolor[3] = 1;\n\n\t// draw the dialog background\n\tcolor[0] = color[1] = color[2] = 0;\n\tcolor[3] = 1;\n\tCG_FillRect( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, color );\n\n\t// print the mesage of the day\n\ts = CG_ConfigString( CS_MOTD );\n\tif ( !s[0] ) {\n\t\ts = \"Scoreboard\";\n\t}\n\n\t// print optional title\n\tCG_CenterGiantLine( 8, s );\n\n\t// print server time\n\tones = cg.time / 1000;\n\tmin = ones / 60;\n\tones %= 60;\n\ttens = ones / 10;\n\tones %= 10;\n\ts = va(\"%i:%i%i\", min, tens, ones );\n\n\tCG_CenterGiantLine( 64, s );\n\n\n\t// print the two scores\n\n\ty = 160;\n\tif ( cgs.gametype >= GT_TEAM ) {\n\t\t//\n\t\t// teamplay scoreboard\n\t\t//\n\t\tCG_DrawStringExt( 8, y, \"Red Team\", color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );\n\t\ts = va(\"%i\", cg.teamScores[0] );\n\t\tCG_DrawStringExt( 632 - GIANT_WIDTH * (int)strlen(s), y, s, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );\n\t\t\n\t\ty += 64;\n\n\t\tCG_DrawStringExt( 8, y, \"Blue Team\", color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );\n\t\ts = va(\"%i\", cg.teamScores[1] );\n\t\tCG_DrawStringExt( 632 - GIANT_WIDTH * (int)strlen(s), y, s, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );\n\t} else {\n\t\t//\n\t\t// free for all scoreboard\n\t\t//\n\t\tfor ( i = 0 ; i < MAX_CLIENTS ; i++ ) {\n\t\t\tci = &cgs.clientinfo[i];\n\t\t\tif ( !ci->infoValid ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif ( ci->team != TEAM_FREE ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tCG_DrawStringExt( 8, y, ci->name, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );\n\t\t\ts = va(\"%i\", ci->score );\n\t\t\tCG_DrawStringExt( 632 - GIANT_WIDTH * (int)strlen(s), y, s, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );\n\t\t\ty += 64;\n\t\t}\n\t}\n\n\n}\n\n"
  },
  {
    "path": "src/cgame/cg_servercmds.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n// cg_servercmds.c -- reliably sequenced text commands sent by the server\n// these are processed at snapshot transition time, so there will definately\n// be a valid snapshot this frame\n\n#include \"cg_local.h\"\n\n/*\n=================\nCG_ParseScores\n\n=================\n*/\nstatic void CG_ParseScores( void ) {\n\tint\t\ti, powerups;\n\n\tcg.numScores = atoi( CG_Argv( 1 ) );\n\tif ( cg.numScores > MAX_CLIENTS ) {\n\t\tcg.numScores = MAX_CLIENTS;\n\t}\n\n\tcg.teamScores[0] = atoi( CG_Argv( 2 ) );\n\tcg.teamScores[1] = atoi( CG_Argv( 3 ) );\n\n\tmemset( cg.scores, 0, sizeof( cg.scores ) );\n\tfor ( i = 0 ; i < cg.numScores ; i++ ) {\n\t\t//\n\t\tcg.scores[i].client = atoi( CG_Argv( i * 14 + 4 ) );\n\t\tcg.scores[i].score = atoi( CG_Argv( i * 14 + 5 ) );\n\t\tcg.scores[i].ping = atoi( CG_Argv( i * 14 + 6 ) );\n\t\tcg.scores[i].time = atoi( CG_Argv( i * 14 + 7 ) );\n\t\tcg.scores[i].scoreFlags = atoi( CG_Argv( i * 14 + 8 ) );\n\t\tpowerups = atoi( CG_Argv( i * 14 + 9 ) );\n\t\tcg.scores[i].accuracy = atoi(CG_Argv(i * 14 + 10));\n\t\tcg.scores[i].impressiveCount = atoi(CG_Argv(i * 14 + 11));\n\t\tcg.scores[i].excellentCount = atoi(CG_Argv(i * 14 + 12));\n\t\tcg.scores[i].guantletCount = atoi(CG_Argv(i * 14 + 13));\n\t\tcg.scores[i].defendCount = atoi(CG_Argv(i * 14 + 14));\n\t\tcg.scores[i].assistCount = atoi(CG_Argv(i * 14 + 15));\n\t\tcg.scores[i].perfect = atoi(CG_Argv(i * 14 + 16));\n\t\tcg.scores[i].captures = atoi(CG_Argv(i * 14 + 17));\n\n\t\tif ( cg.scores[i].client < 0 || cg.scores[i].client >= MAX_CLIENTS ) {\n\t\t\tcg.scores[i].client = 0;\n\t\t}\n\t\tcgs.clientinfo[ cg.scores[i].client ].score = cg.scores[i].score;\n\t\tcgs.clientinfo[ cg.scores[i].client ].powerups = powerups;\n\n\t\tcg.scores[i].team = cgs.clientinfo[cg.scores[i].client].team;\n\t}\n}\n\n/*\n=================\nCG_ParseTeamInfo\n\n=================\n*/\nstatic void CG_ParseTeamInfo( void ) {\n\tint\t\ti;\n\tint\t\tclient;\n\n\tnumSortedTeamPlayers = atoi( CG_Argv( 1 ) );\n\n\tfor ( i = 0 ; i < numSortedTeamPlayers ; i++ ) {\n\t\tclient = atoi( CG_Argv( i * 6 + 2 ) );\n\n\t\tsortedTeamPlayers[i] = client;\n\n\t\tcgs.clientinfo[ client ].location = atoi( CG_Argv( i * 6 + 3 ) );\n\t\tcgs.clientinfo[ client ].health = atoi( CG_Argv( i * 6 + 4 ) );\n\t\tcgs.clientinfo[ client ].armor = atoi( CG_Argv( i * 6 + 5 ) );\n\t\tcgs.clientinfo[ client ].curWeapon = atoi( CG_Argv( i * 6 + 6 ) );\n\t\tcgs.clientinfo[ client ].powerups = atoi( CG_Argv( i * 6 + 7 ) );\n\t}\n}\n\n\n/*\n================\nCG_ParseServerinfo\n\nThis is called explicitly when the gamestate is first received,\nand whenever the server updates any serverinfo flagged cvars\n================\n*/\nvoid CG_ParseServerinfo( void ) {\n\tconst char\t*info;\n\tchar\t*mapname;\n\n\tinfo = CG_ConfigString( CS_SERVERINFO );\n\tcgs.gametype = atoi( Info_ValueForKey( info, \"g_gametype\" ) );\n\ttrap_Cvar_Set(\"g_gametype\", va(\"%i\", cgs.gametype));\n\tcgs.dmflags = atoi( Info_ValueForKey( info, \"dmflags\" ) );\n\tcgs.teamflags = atoi( Info_ValueForKey( info, \"teamflags\" ) );\n\tcgs.fraglimit = atoi( Info_ValueForKey( info, \"fraglimit\" ) );\n\tcgs.capturelimit = atoi( Info_ValueForKey( info, \"capturelimit\" ) );\n\tcgs.timelimit = atoi( Info_ValueForKey( info, \"timelimit\" ) );\n\tcgs.maxclients = atoi( Info_ValueForKey( info, \"sv_maxclients\" ) );\n\tmapname = Info_ValueForKey( info, \"mapname\" );\n\tCom_sprintf( cgs.mapname, sizeof( cgs.mapname ), \"maps/%s.bsp\", mapname );\n\tQ_strncpyz( cgs.redTeam, Info_ValueForKey( info, \"g_redTeam\" ), sizeof(cgs.redTeam) );\n\ttrap_Cvar_Set(\"g_redTeam\", cgs.redTeam);\n\tQ_strncpyz( cgs.blueTeam, Info_ValueForKey( info, \"g_blueTeam\" ), sizeof(cgs.blueTeam) );\n\ttrap_Cvar_Set(\"g_blueTeam\", cgs.blueTeam);\n}\n\n/*\n==================\nCG_ParseWarmup\n==================\n*/\nstatic void CG_ParseWarmup( void ) {\n\tconst char\t*info;\n\tint\t\t\twarmup;\n\n\tinfo = CG_ConfigString( CS_WARMUP );\n\n\twarmup = atoi( info );\n\tcg.warmupCount = -1;\n\n\tif ( warmup == 0 && cg.warmup ) {\n\n\t} else if ( warmup > 0 && cg.warmup <= 0 ) {\n\t\t{\n\t\t\ttrap_S_StartLocalSound( cgs.media.countPrepareSound, CHAN_ANNOUNCER );\n\t\t}\n\t}\n\n\tcg.warmup = warmup;\n}\n\n/*\n================\nCG_SetConfigValues\n\nCalled on load to set the initial values from configure strings\n================\n*/\nvoid CG_SetConfigValues( void ) {\n\tconst char *s;\n\n\tcgs.scores1 = atoi( CG_ConfigString( CS_SCORES1 ) );\n\tcgs.scores2 = atoi( CG_ConfigString( CS_SCORES2 ) );\n\tcgs.levelStartTime = atoi( CG_ConfigString( CS_LEVEL_START_TIME ) );\n\tif( cgs.gametype == GT_CTF ) {\n\t\ts = CG_ConfigString( CS_FLAGSTATUS );\n\t\tcgs.redflag = s[0] - '0';\n\t\tcgs.blueflag = s[1] - '0';\n\t}\n\tcg.warmup = atoi( CG_ConfigString( CS_WARMUP ) );\n}\n\n/*\n=====================\nCG_ShaderStateChanged\n=====================\n*/\nvoid CG_ShaderStateChanged(void) {\n\tchar originalShader[MAX_QPATH];\n\tchar newShader[MAX_QPATH];\n\tchar timeOffset[16];\n\tconst char *o;\n\tchar *n,*t;\n\n\to = CG_ConfigString( CS_SHADERSTATE );\n\twhile (o && *o) {\n\t\tn = strstr(o, \"=\");\n\t\tif (n && *n) {\n\t\t\tstrncpy(originalShader, o, n-o);\n\t\t\toriginalShader[n-o] = 0;\n\t\t\tn++;\n\t\t\tt = strstr(n, \":\");\n\t\t\tif (t && *t) {\n\t\t\t\tstrncpy(newShader, n, t-n);\n\t\t\t\tnewShader[t-n] = 0;\n\t\t\t} else {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tt++;\n\t\t\to = strstr(t, \"@\");\n\t\t\tif (o) {\n\t\t\t\tstrncpy(timeOffset, t, o-t);\n\t\t\t\ttimeOffset[o-t] = 0;\n\t\t\t\to++;\n\t\t\t\ttrap_R_RemapShader( originalShader, newShader, timeOffset );\n\t\t\t}\n\t\t} else {\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\n/*\n================\nCG_ConfigStringModified\n\n================\n*/\nstatic void CG_ConfigStringModified( void ) {\n\tconst char\t*str;\n\tint\t\tnum;\n\n\tnum = atoi( CG_Argv( 1 ) );\n\n\t// get the gamestate from the client system, which will have the\n\t// new configstring already integrated\n\ttrap_GetGameState( &cgs.gameState );\n\n\t// look up the individual string that was modified\n\tstr = CG_ConfigString( num );\n\n\t// do something with it if necessary\n\tif ( num == CS_MUSIC ) {\n\t\tCG_StartMusic();\n\t} else if ( num == CS_SERVERINFO ) {\n\t\tCG_ParseServerinfo();\n\t} else if ( num == CS_WARMUP ) {\n\t\tCG_ParseWarmup();\n\t} else if ( num == CS_SCORES1 ) {\n\t\tcgs.scores1 = atoi( str );\n\t} else if ( num == CS_SCORES2 ) {\n\t\tcgs.scores2 = atoi( str );\n\t} else if ( num == CS_LEVEL_START_TIME ) {\n\t\tcgs.levelStartTime = atoi( str );\n\t} else if ( num == CS_VOTE_TIME ) {\n\t\tcgs.voteTime = atoi( str );\n\t\tcgs.voteModified = qtrue;\n\t} else if ( num == CS_VOTE_YES ) {\n\t\tcgs.voteYes = atoi( str );\n\t\tcgs.voteModified = qtrue;\n\t} else if ( num == CS_VOTE_NO ) {\n\t\tcgs.voteNo = atoi( str );\n\t\tcgs.voteModified = qtrue;\n\t} else if ( num == CS_VOTE_STRING ) {\n\t\tQ_strncpyz( cgs.voteString, str, sizeof( cgs.voteString ) );\n\t} else if ( num >= CS_TEAMVOTE_TIME && num <= CS_TEAMVOTE_TIME + 1) {\n\t\tcgs.teamVoteTime[num-CS_TEAMVOTE_TIME] = atoi( str );\n\t\tcgs.teamVoteModified[num-CS_TEAMVOTE_TIME] = qtrue;\n\t} else if ( num >= CS_TEAMVOTE_YES && num <= CS_TEAMVOTE_YES + 1) {\n\t\tcgs.teamVoteYes[num-CS_TEAMVOTE_YES] = atoi( str );\n\t\tcgs.teamVoteModified[num-CS_TEAMVOTE_YES] = qtrue;\n\t} else if ( num >= CS_TEAMVOTE_NO && num <= CS_TEAMVOTE_NO + 1) {\n\t\tcgs.teamVoteNo[num-CS_TEAMVOTE_NO] = atoi( str );\n\t\tcgs.teamVoteModified[num-CS_TEAMVOTE_NO] = qtrue;\n\t} else if ( num >= CS_TEAMVOTE_STRING && num <= CS_TEAMVOTE_STRING + 1) {\n\t\tQ_strncpyz( cgs.teamVoteString[num-CS_TEAMVOTE_STRING], str, sizeof( cgs.teamVoteString ) );\n\t} else if ( num == CS_INTERMISSION ) {\n\t\tcg.intermissionStarted = atoi( str );\n\t} else if ( num >= CS_MODELS && num < CS_MODELS+MAX_MODELS ) {\n\t\tcgs.gameModels[ num-CS_MODELS ] = trap_R_RegisterModel( str );\n\t} else if ( num >= CS_SOUNDS && num < CS_SOUNDS+MAX_MODELS ) {\n\t\tif ( str[0] != '*' ) {\t// player specific sounds don't register here\n\t\t\tcgs.gameSounds[ num-CS_SOUNDS] = trap_S_RegisterSound( str, qfalse );\n\t\t}\n\t} else if ( num >= CS_PLAYERS && num < CS_PLAYERS+MAX_CLIENTS ) {\n\t\tCG_NewClientInfo( num - CS_PLAYERS );\n\t\tCG_BuildSpectatorString();\n\t} else if ( num == CS_FLAGSTATUS ) {\n\t\tif( cgs.gametype == GT_CTF ) {\n\t\t\t// format is rb where its red/blue, 0 is at base, 1 is taken, 2 is dropped\n\t\t\tcgs.redflag = str[0] - '0';\n\t\t\tcgs.blueflag = str[1] - '0';\n\t\t}\n\t}\n\telse if ( num == CS_SHADERSTATE ) {\n\t\tCG_ShaderStateChanged();\n\t}\n\t\t\n}\n\n\n/*\n=======================\nCG_AddToTeamChat\n\n=======================\n*/\nstatic void CG_AddToTeamChat( const char *str ) {\n\tint len;\n\tchar *p, *ls;\n\tint lastcolor;\n\tint chatHeight;\n\n\tif (cg_teamChatHeight.integer < TEAMCHAT_HEIGHT) {\n\t\tchatHeight = cg_teamChatHeight.integer;\n\t} else {\n\t\tchatHeight = TEAMCHAT_HEIGHT;\n\t}\n\n\tif (chatHeight <= 0 || cg_teamChatTime.integer <= 0) {\n\t\t// team chat disabled, dump into normal chat\n\t\tcgs.teamChatPos = cgs.teamLastChatPos = 0;\n\t\treturn;\n\t}\n\n\tlen = 0;\n\n\tp = cgs.teamChatMsgs[cgs.teamChatPos % chatHeight];\n\t*p = 0;\n\n\tlastcolor = '7';\n\n\tls = NULL;\n\twhile (*str) {\n\t\tif (len > TEAMCHAT_WIDTH - 1) {\n\t\t\tif (ls) {\n\t\t\t\tstr -= (p - ls);\n\t\t\t\tstr++;\n\t\t\t\tp -= (p - ls);\n\t\t\t}\n\t\t\t*p = 0;\n\n\t\t\tcgs.teamChatMsgTimes[cgs.teamChatPos % chatHeight] = cg.time;\n\n\t\t\tcgs.teamChatPos++;\n\t\t\tp = cgs.teamChatMsgs[cgs.teamChatPos % chatHeight];\n\t\t\t*p = 0;\n\t\t\t*p++ = Q_COLOR_ESCAPE;\n\t\t\t*p++ = lastcolor;\n\t\t\tlen = 0;\n\t\t\tls = NULL;\n\t\t}\n\n\t\tif ( Q_IsColorString( str ) ) {\n\t\t\t*p++ = *str++;\n\t\t\tlastcolor = *str;\n\t\t\t*p++ = *str++;\n\t\t\tcontinue;\n\t\t}\n\t\tif (*str == ' ') {\n\t\t\tls = p;\n\t\t}\n\t\t*p++ = *str++;\n\t\tlen++;\n\t}\n\t*p = 0;\n\n\tcgs.teamChatMsgTimes[cgs.teamChatPos % chatHeight] = cg.time;\n\tcgs.teamChatPos++;\n\n\tif (cgs.teamChatPos - cgs.teamLastChatPos > chatHeight)\n\t\tcgs.teamLastChatPos = cgs.teamChatPos - chatHeight;\n}\n\n/*\n===============\nCG_MapRestart\n\nThe server has issued a map_restart, so the next snapshot\nis completely new and should not be interpolated to.\n\nA tournement restart will clear everything, but doesn't\nrequire a reload of all the media\n===============\n*/\nstatic void CG_MapRestart( void ) {\n\tif ( cg_showmiss.integer ) {\n\t\tCG_Printf( \"CG_MapRestart\\n\" );\n\t}\n\n\tCG_InitLocalEntities();\n\tCG_InitMarkPolys();\n\tCG_ClearParticles ();\n\n\t// make sure the \"3 frags left\" warnings play again\n\tcg.fraglimitWarnings = 0;\n\n\tcg.timelimitWarnings = 0;\n\n\tcg.intermissionStarted = qfalse;\n\n\tcgs.voteTime = 0;\n\n\tcg.mapRestart = qtrue;\n\n\tCG_StartMusic();\n\n\ttrap_S_ClearLoopingSounds(qtrue);\n\n\t// we really should clear more parts of cg here and stop sounds\n\n\t// play the \"fight\" sound if this is a restart without warmup\n\tif ( cg.warmup == 0 /* && cgs.gametype == GT_TOURNAMENT */) {\n\t\ttrap_S_StartLocalSound( cgs.media.countFightSound, CHAN_ANNOUNCER );\n\t\tCG_CenterPrint( \"FIGHT!\", 120, GIANTCHAR_WIDTH*2 );\n\t}\n\ttrap_Cvar_Set(\"cg_thirdPerson\", \"0\");\n}\n\n#define MAX_VOICEFILESIZE\t16384\n#define MAX_VOICEFILES\t\t8\n#define MAX_VOICECHATS\t\t64\n#define MAX_VOICESOUNDS\t\t64\n#define MAX_CHATSIZE\t\t64\n#define MAX_HEADMODELS\t\t64\n\ntypedef struct voiceChat_s\n{\n\tchar id[64];\n\tint numSounds;\n\tsfxHandle_t sounds[MAX_VOICESOUNDS];\n\tchar chats[MAX_VOICESOUNDS][MAX_CHATSIZE];\n} voiceChat_t;\n\ntypedef struct voiceChatList_s\n{\n\tchar name[64];\n\tint gender;\n\tint numVoiceChats;\n\tvoiceChat_t voiceChats[MAX_VOICECHATS];\n} voiceChatList_t;\n\ntypedef struct headModelVoiceChat_s\n{\n\tchar headmodel[64];\n\tint voiceChatNum;\n} headModelVoiceChat_t;\n\nvoiceChatList_t voiceChatLists[MAX_VOICEFILES];\nheadModelVoiceChat_t headModelVoiceChat[MAX_HEADMODELS];\n\n/*\n=================\nCG_ParseVoiceChats\n=================\n*/\nint CG_ParseVoiceChats( const char *filename, voiceChatList_t *voiceChatList, int maxVoiceChats ) {\n\tint\tlen, i;\n\tfileHandle_t f;\n\tchar buf[MAX_VOICEFILESIZE];\n\tchar **p, *ptr;\n\tchar *token;\n\tvoiceChat_t *voiceChats;\n\tqboolean compress;\n\tsfxHandle_t sound;\n\n\tcompress = qtrue;\n\tif (cg_buildScript.integer) {\n\t\tcompress = qfalse;\n\t}\n\n\tlen = trap_FS_FOpenFile( filename, &f, FS_READ );\n\tif ( !f ) {\n\t\ttrap_Print( va( S_COLOR_RED \"voice chat file not found: %s\\n\", filename ) );\n\t\treturn qfalse;\n\t}\n\tif ( len >= MAX_VOICEFILESIZE ) {\n\t\ttrap_Print( va( S_COLOR_RED \"voice chat file too large: %s is %i, max allowed is %i\", filename, len, MAX_VOICEFILESIZE ) );\n\t\ttrap_FS_FCloseFile( f );\n\t\treturn qfalse;\n\t}\n\n\ttrap_FS_Read( buf, len, f );\n\tbuf[len] = 0;\n\ttrap_FS_FCloseFile( f );\n\n\tptr = buf;\n\tp = &ptr;\n\n\tCom_sprintf(voiceChatList->name, sizeof(voiceChatList->name), \"%s\", filename);\n\tvoiceChats = voiceChatList->voiceChats;\n\tfor ( i = 0; i < maxVoiceChats; i++ ) {\n\t\tvoiceChats[i].id[0] = 0;\n\t}\n\ttoken = COM_ParseExt(p, qtrue);\n\tif (!token || token[0] == 0) {\n\t\treturn qtrue;\n\t}\n\tif (!Q_stricmp(token, \"female\")) {\n\t\tvoiceChatList->gender = GENDER_FEMALE;\n\t}\n\telse if (!Q_stricmp(token, \"male\")) {\n\t\tvoiceChatList->gender = GENDER_MALE;\n\t}\n\telse if (!Q_stricmp(token, \"neuter\")) {\n\t\tvoiceChatList->gender = GENDER_NEUTER;\n\t}\n\telse {\n\t\ttrap_Print( va( S_COLOR_RED \"expected gender not found in voice chat file: %s\\n\", filename ) );\n\t\treturn qfalse;\n\t}\n\n\tvoiceChatList->numVoiceChats = 0;\n\twhile ( 1 ) {\n\t\ttoken = COM_ParseExt(p, qtrue);\n\t\tif (!token || token[0] == 0) {\n\t\t\treturn qtrue;\n\t\t}\n\t\tCom_sprintf(voiceChats[voiceChatList->numVoiceChats].id, sizeof( voiceChats[voiceChatList->numVoiceChats].id ), \"%s\", token);\n\t\ttoken = COM_ParseExt(p, qtrue);\n\t\tif (Q_stricmp(token, \"{\")) {\n\t\t\ttrap_Print( va( S_COLOR_RED \"expected { found %s in voice chat file: %s\\n\", token, filename ) );\n\t\t\treturn qfalse;\n\t\t}\n\t\tvoiceChats[voiceChatList->numVoiceChats].numSounds = 0;\n\t\twhile(1) {\n\t\t\ttoken = COM_ParseExt(p, qtrue);\n\t\t\tif (!token || token[0] == 0) {\n\t\t\t\treturn qtrue;\n\t\t\t}\n\t\t\tif (!Q_stricmp(token, \"}\"))\n\t\t\t\tbreak;\n\t\t\tsound = trap_S_RegisterSound( token, compress );\n\t\t\tvoiceChats[voiceChatList->numVoiceChats].sounds[voiceChats[voiceChatList->numVoiceChats].numSounds] = sound;\n\t\t\ttoken = COM_ParseExt(p, qtrue);\n\t\t\tif (!token || token[0] == 0) {\n\t\t\t\treturn qtrue;\n\t\t\t}\n\t\t\tCom_sprintf(voiceChats[voiceChatList->numVoiceChats].chats[\n\t\t\t\t\t\t\tvoiceChats[voiceChatList->numVoiceChats].numSounds], MAX_CHATSIZE, \"%s\", token);\n\t\t\tif (sound)\n\t\t\t\tvoiceChats[voiceChatList->numVoiceChats].numSounds++;\n\t\t\tif (voiceChats[voiceChatList->numVoiceChats].numSounds >= MAX_VOICESOUNDS)\n\t\t\t\tbreak;\n\t\t}\n\t\tvoiceChatList->numVoiceChats++;\n\t\tif (voiceChatList->numVoiceChats >= maxVoiceChats)\n\t\t\treturn qtrue;\n\t}\n\treturn qtrue;\n}\n\n/*\n=================\nCG_LoadVoiceChats\n=================\n*/\nvoid CG_LoadVoiceChats( void ) {\n\tint size;\n\n\tsize = trap_MemoryRemaining();\n\tCG_ParseVoiceChats( \"scripts/female1.voice\", &voiceChatLists[0], MAX_VOICECHATS );\n\tCG_ParseVoiceChats( \"scripts/female2.voice\", &voiceChatLists[1], MAX_VOICECHATS );\n\tCG_ParseVoiceChats( \"scripts/female3.voice\", &voiceChatLists[2], MAX_VOICECHATS );\n\tCG_ParseVoiceChats( \"scripts/male1.voice\", &voiceChatLists[3], MAX_VOICECHATS );\n\tCG_ParseVoiceChats( \"scripts/male2.voice\", &voiceChatLists[4], MAX_VOICECHATS );\n\tCG_ParseVoiceChats( \"scripts/male3.voice\", &voiceChatLists[5], MAX_VOICECHATS );\n\tCG_ParseVoiceChats( \"scripts/male4.voice\", &voiceChatLists[6], MAX_VOICECHATS );\n\tCG_ParseVoiceChats( \"scripts/male5.voice\", &voiceChatLists[7], MAX_VOICECHATS );\n\tCG_Printf(\"voice chat memory size = %d\\n\", size - trap_MemoryRemaining());\n}\n\n/*\n=================\nCG_HeadModelVoiceChats\n=================\n*/\nint CG_HeadModelVoiceChats( char *filename ) {\n\tint\tlen, i;\n\tfileHandle_t f;\n\tchar buf[MAX_VOICEFILESIZE];\n\tchar **p, *ptr;\n\tchar *token;\n\n\tlen = trap_FS_FOpenFile( filename, &f, FS_READ );\n\tif ( !f ) {\n\t\t//trap_Print( va( \"voice chat file not found: %s\\n\", filename ) );\n\t\treturn -1;\n\t}\n\tif ( len >= MAX_VOICEFILESIZE ) {\n\t\ttrap_Print( va( S_COLOR_RED \"voice chat file too large: %s is %i, max allowed is %i\", filename, len, MAX_VOICEFILESIZE ) );\n\t\ttrap_FS_FCloseFile( f );\n\t\treturn -1;\n\t}\n\n\ttrap_FS_Read( buf, len, f );\n\tbuf[len] = 0;\n\ttrap_FS_FCloseFile( f );\n\n\tptr = buf;\n\tp = &ptr;\n\n\ttoken = COM_ParseExt(p, qtrue);\n\tif (!token || token[0] == 0) {\n\t\treturn -1;\n\t}\n\n\tfor ( i = 0; i < MAX_VOICEFILES; i++ ) {\n\t\tif ( !Q_stricmp(token, voiceChatLists[i].name) ) {\n\t\t\treturn i;\n\t\t}\n\t}\n\n\t//FIXME: maybe try to load the .voice file which name is stored in token?\n\n\treturn -1;\n}\n\n\n/*\n=================\nCG_GetVoiceChat\n=================\n*/\nint CG_GetVoiceChat( voiceChatList_t *voiceChatList, const char *id, sfxHandle_t *snd, char **chat) {\n\tint i, rnd;\n\n\tfor ( i = 0; i < voiceChatList->numVoiceChats; i++ ) {\n\t\tif ( !Q_stricmp( id, voiceChatList->voiceChats[i].id ) ) {\n\t\t\trnd = random() * voiceChatList->voiceChats[i].numSounds;\n\t\t\t*snd = voiceChatList->voiceChats[i].sounds[rnd];\n\t\t\t*chat = voiceChatList->voiceChats[i].chats[rnd];\n\t\t\treturn qtrue;\n\t\t}\n\t}\n\treturn qfalse;\n}\n\n/*\n=================\nCG_VoiceChatListForClient\n=================\n*/\nvoiceChatList_t *CG_VoiceChatListForClient( int clientNum ) {\n\tclientInfo_t *ci;\n\tint voiceChatNum, i, j, k, gender;\n\tchar filename[MAX_QPATH], headModelName[MAX_QPATH];\n\n\tif ( clientNum < 0 || clientNum >= MAX_CLIENTS ) {\n\t\tclientNum = 0;\n\t}\n\tci = &cgs.clientinfo[ clientNum ];\n\n\tfor ( k = 0; k < 2; k++ ) {\n\t\tif ( k == 0 ) {\n\t\t\tif (ci->headModelName[0] == '*') {\n\t\t\t\tCom_sprintf( headModelName, sizeof(headModelName), \"%s/%s\", ci->headModelName+1, ci->headSkinName );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tCom_sprintf( headModelName, sizeof(headModelName), \"%s/%s\", ci->headModelName, ci->headSkinName );\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tif (ci->headModelName[0] == '*') {\n\t\t\t\tCom_sprintf( headModelName, sizeof(headModelName), \"%s\", ci->headModelName+1 );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tCom_sprintf( headModelName, sizeof(headModelName), \"%s\", ci->headModelName );\n\t\t\t}\n\t\t}\n\t\t// find the voice file for the head model the client uses\n\t\tfor ( i = 0; i < MAX_HEADMODELS; i++ ) {\n\t\t\tif (!Q_stricmp(headModelVoiceChat[i].headmodel, headModelName)) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (i < MAX_HEADMODELS) {\n\t\t\treturn &voiceChatLists[headModelVoiceChat[i].voiceChatNum];\n\t\t}\n\t\t// find a <headmodelname>.vc file\n\t\tfor ( i = 0; i < MAX_HEADMODELS; i++ ) {\n\t\t\tif (!strlen(headModelVoiceChat[i].headmodel)) {\n\t\t\t\tCom_sprintf(filename, sizeof(filename), \"scripts/%s.vc\", headModelName);\n\t\t\t\tvoiceChatNum = CG_HeadModelVoiceChats(filename);\n\t\t\t\tif (voiceChatNum == -1)\n\t\t\t\t\tbreak;\n\t\t\t\tCom_sprintf(headModelVoiceChat[i].headmodel, sizeof ( headModelVoiceChat[i].headmodel ),\n\t\t\t\t\t\t\t\"%s\", headModelName);\n\t\t\t\theadModelVoiceChat[i].voiceChatNum = voiceChatNum;\n\t\t\t\treturn &voiceChatLists[headModelVoiceChat[i].voiceChatNum];\n\t\t\t}\n\t\t}\n\t}\n\tgender = ci->gender;\n\tfor (k = 0; k < 2; k++) {\n\t\t// just pick the first with the right gender\n\t\tfor ( i = 0; i < MAX_VOICEFILES; i++ ) {\n\t\t\tif (strlen(voiceChatLists[i].name)) {\n\t\t\t\tif (voiceChatLists[i].gender == gender) {\n\t\t\t\t\t// store this head model with voice chat for future reference\n\t\t\t\t\tfor ( j = 0; j < MAX_HEADMODELS; j++ ) {\n\t\t\t\t\t\tif (!strlen(headModelVoiceChat[j].headmodel)) {\n\t\t\t\t\t\t\tCom_sprintf(headModelVoiceChat[j].headmodel, sizeof ( headModelVoiceChat[j].headmodel ),\n\t\t\t\t\t\t\t\t\t\"%s\", headModelName);\n\t\t\t\t\t\t\theadModelVoiceChat[j].voiceChatNum = i;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn &voiceChatLists[i];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// fall back to male gender because we don't have neuter in the mission pack\n\t\tif (gender == GENDER_MALE)\n\t\t\tbreak;\n\t\tgender = GENDER_MALE;\n\t}\n\t// store this head model with voice chat for future reference\n\tfor ( j = 0; j < MAX_HEADMODELS; j++ ) {\n\t\tif (!strlen(headModelVoiceChat[j].headmodel)) {\n\t\t\tCom_sprintf(headModelVoiceChat[j].headmodel, sizeof ( headModelVoiceChat[j].headmodel ),\n\t\t\t\t\t\"%s\", headModelName);\n\t\t\theadModelVoiceChat[j].voiceChatNum = 0;\n\t\t\tbreak;\n\t\t}\n\t}\n\t// just return the first voice chat list\n\treturn &voiceChatLists[0];\n}\n\n#define MAX_VOICECHATBUFFER\t\t32\n\ntypedef struct bufferedVoiceChat_s\n{\n\tint clientNum;\n\tsfxHandle_t snd;\n\tint voiceOnly;\n\tchar cmd[MAX_SAY_TEXT];\n\tchar message[MAX_SAY_TEXT];\n} bufferedVoiceChat_t;\n\nbufferedVoiceChat_t voiceChatBuffer[MAX_VOICECHATBUFFER];\n\n/*\n=================\nCG_PlayVoiceChat\n=================\n*/\nvoid CG_PlayVoiceChat( bufferedVoiceChat_t *vchat ) {\n}\n\n/*\n=====================\nCG_PlayBufferedVoieChats\n=====================\n*/\nvoid CG_PlayBufferedVoiceChats( void ) {\n}\n\n/*\n=====================\nCG_AddBufferedVoiceChat\n=====================\n*/\nvoid CG_AddBufferedVoiceChat( bufferedVoiceChat_t *vchat ) {\n}\n\n/*\n=================\nCG_VoiceChatLocal\n=================\n*/\nvoid CG_VoiceChatLocal( int mode, qboolean voiceOnly, int clientNum, int color, const char *cmd ) {\n}\n\n/*\n=================\nCG_VoiceChat\n=================\n*/\nvoid CG_VoiceChat( int mode ) {\n}\n\n/*\n=================\nCG_RemoveChatEscapeChar\n=================\n*/\nstatic void CG_RemoveChatEscapeChar( char *text ) {\n\tint i, l;\n\n\tl = 0;\n\tfor ( i = 0; text[i]; i++ ) {\n\t\tif (text[i] == '\\x19')\n\t\t\tcontinue;\n\t\ttext[l++] = text[i];\n\t}\n\ttext[l] = '\\0';\n}\n\n/*\n=================\nCG_ServerCommand\n\nThe string has been tokenized and can be retrieved with\nCmd_Argc() / Cmd_Argv()\n=================\n*/\nstatic void CG_ServerCommand( void ) {\n\tconst char\t*cmd;\n\tchar\t\ttext[MAX_SAY_TEXT];\n\n\tcmd = CG_Argv(0);\n\n\tif ( !cmd[0] ) {\n\t\t// server claimed the command\n\t\treturn;\n\t}\n\n\tif ( !strcmp( cmd, \"cp\" ) ) {\n\t\tCG_CenterPrint( CG_Argv(1), SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH );\n\t\treturn;\n\t}\n\n\tif ( !strcmp( cmd, \"cs\" ) ) {\n\t\tCG_ConfigStringModified();\n\t\treturn;\n\t}\n\n\tif ( !strcmp( cmd, \"print\" ) ) {\n\t\tCG_Printf( \"%s\", CG_Argv(1) );\n\t\treturn;\n\t}\n\n\tif ( !strcmp( cmd, \"chat\" ) ) {\n\t\tif ( !cg_teamChatsOnly.integer ) {\n\t\t\ttrap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );\n\t\t\tQ_strncpyz( text, CG_Argv(1), MAX_SAY_TEXT );\n\t\t\tCG_RemoveChatEscapeChar( text );\n\t\t\tCG_Printf( \"%s\\n\", text );\n\t\t}\n\t\treturn;\n\t}\n\n\tif ( !strcmp( cmd, \"tchat\" ) ) {\n\t\ttrap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );\n\t\tQ_strncpyz( text, CG_Argv(1), MAX_SAY_TEXT );\n\t\tCG_RemoveChatEscapeChar( text );\n\t\tCG_AddToTeamChat( text );\n\t\tCG_Printf( \"%s\\n\", text );\n\t\treturn;\n\t}\n\tif ( !strcmp( cmd, \"vchat\" ) ) {\n\t\tCG_VoiceChat( SAY_ALL );\n\t\treturn;\n\t}\n\n\tif ( !strcmp( cmd, \"vtchat\" ) ) {\n\t\tCG_VoiceChat( SAY_TEAM );\n\t\treturn;\n\t}\n\n\tif ( !strcmp( cmd, \"vtell\" ) ) {\n\t\tCG_VoiceChat( SAY_TELL );\n\t\treturn;\n\t}\n\n\tif ( !strcmp( cmd, \"scores\" ) ) {\n\t\tCG_ParseScores();\n\t\treturn;\n\t}\n\n\tif ( !strcmp( cmd, \"tinfo\" ) ) {\n\t\tCG_ParseTeamInfo();\n\t\treturn;\n\t}\n\n\tif ( !strcmp( cmd, \"map_restart\" ) ) {\n\t\tCG_MapRestart();\n\t\treturn;\n\t}\n\n  if ( Q_stricmp (cmd, \"remapShader\") == 0 ) {\n\t\tif (trap_Argc() == 4) {\n\t\t\ttrap_R_RemapShader(CG_Argv(1), CG_Argv(2), CG_Argv(3));\n\t\t}\n\t}\n\n\t// loaddeferred can be both a servercmd and a consolecmd\n\tif ( !strcmp( cmd, \"loaddefered\" ) ) {\t// FIXME: spelled wrong, but not changing for demo\n\t\tCG_LoadDeferredPlayers();\n\t\treturn;\n\t}\n\n\t// clientLevelShot is sent before taking a special screenshot for\n\t// the menu system during development\n\tif ( !strcmp( cmd, \"clientLevelShot\" ) ) {\n\t\tcg.levelShot = qtrue;\n\t\treturn;\n\t}\n\n\tCG_Printf( \"Unknown client game command: %s\\n\", cmd );\n}\n\n\n/*\n====================\nCG_ExecuteNewServerCommands\n\nExecute all of the server commands that were received along\nwith this this snapshot.\n====================\n*/\nvoid CG_ExecuteNewServerCommands( int latestSequence ) {\n\twhile ( cgs.serverCommandSequence < latestSequence ) {\n\t\tif ( trap_GetServerCommand( ++cgs.serverCommandSequence ) ) {\n\t\t\tCG_ServerCommand();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/cgame/cg_snapshot.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n// cg_snapshot.c -- things that happen on snapshot transition,\n// not necessarily every single rendered frame\n\n#include \"cg_local.h\"\n\n\n\n/*\n==================\nCG_ResetEntity\n==================\n*/\nstatic void CG_ResetEntity( centity_t *cent ) {\n\t// if the previous snapshot this entity was updated in is at least\n\t// an event window back in time then we can reset the previous event\n\tif ( cent->snapShotTime < cg.time - EVENT_VALID_MSEC ) {\n\t\tcent->previousEvent = 0;\n\t}\n\n\tcent->trailTime = cg.snap->serverTime;\n\n\tVectorCopy (cent->currentState.origin, cent->lerpOrigin);\n\tVectorCopy (cent->currentState.angles, cent->lerpAngles);\n\tif ( cent->currentState.eType == ET_PLAYER ) {\n\t\tCG_ResetPlayerEntity( cent );\n\t}\n}\n\n/*\n===============\nCG_TransitionEntity\n\ncent->nextState is moved to cent->currentState and events are fired\n===============\n*/\nstatic void CG_TransitionEntity( centity_t *cent ) {\n\tcent->currentState = cent->nextState;\n\tcent->currentValid = qtrue;\n\n\t// reset if the entity wasn't in the last frame or was teleported\n\tif ( !cent->interpolate ) {\n\t\tCG_ResetEntity( cent );\n\t}\n\n\t// clear the next state.  if will be set by the next CG_SetNextSnap\n\tcent->interpolate = qfalse;\n\n\t// check for events\n\tCG_CheckEvents( cent );\n}\n\n\n/*\n==================\nCG_SetInitialSnapshot\n\nThis will only happen on the very first snapshot, or\non tourney restarts.  All other times will use \nCG_TransitionSnapshot instead.\n\nFIXME: Also called by map_restart?\n==================\n*/\nvoid CG_SetInitialSnapshot( snapshot_t *snap ) {\n\tint\t\t\t\ti;\n\tcentity_t\t\t*cent;\n\tentityState_t\t*state;\n\n\tcg.snap = snap;\n\n\tBG_PlayerStateToEntityState( &snap->ps, &cg_entities[ snap->ps.clientNum ].currentState, qfalse );\n\n\t// sort out solid entities\n\tCG_BuildSolidList();\n\n\tCG_ExecuteNewServerCommands( snap->serverCommandSequence );\n\n\t// set our local weapon selection pointer to\n\t// what the server has indicated the current weapon is\n\tCG_Respawn();\n\n\tfor ( i = 0 ; i < cg.snap->numEntities ; i++ ) {\n\t\tstate = &cg.snap->entities[ i ];\n\t\tcent = &cg_entities[ state->number ];\n\n\t\tmemcpy(&cent->currentState, state, sizeof(entityState_t));\n\t\t//cent->currentState = *state;\n\t\tcent->interpolate = qfalse;\n\t\tcent->currentValid = qtrue;\n\n\t\tCG_ResetEntity( cent );\n\n\t\t// check for events\n\t\tCG_CheckEvents( cent );\n\t}\n}\n\n\n/*\n===================\nCG_TransitionSnapshot\n\nThe transition point from snap to nextSnap has passed\n===================\n*/\nstatic void CG_TransitionSnapshot( void ) {\n\tcentity_t\t\t\t*cent;\n\tsnapshot_t\t\t\t*oldFrame;\n\tint\t\t\t\t\ti;\n\n\tif ( !cg.snap ) {\n\t\tCG_Error( \"CG_TransitionSnapshot: NULL cg.snap\" );\n\t}\n\tif ( !cg.nextSnap ) {\n\t\tCG_Error( \"CG_TransitionSnapshot: NULL cg.nextSnap\" );\n\t}\n\n\t// execute any server string commands before transitioning entities\n\tCG_ExecuteNewServerCommands( cg.nextSnap->serverCommandSequence );\n\n\t// if we had a map_restart, set everthing with initial\n\tif ( !cg.snap ) {\n\t}\n\n\t// clear the currentValid flag for all entities in the existing snapshot\n\tfor ( i = 0 ; i < cg.snap->numEntities ; i++ ) {\n\t\tcent = &cg_entities[ cg.snap->entities[ i ].number ];\n\t\tcent->currentValid = qfalse;\n\t}\n\n\t// move nextSnap to snap and do the transitions\n\toldFrame = cg.snap;\n\tcg.snap = cg.nextSnap;\n\n\tBG_PlayerStateToEntityState( &cg.snap->ps, &cg_entities[ cg.snap->ps.clientNum ].currentState, qfalse );\n\tcg_entities[ cg.snap->ps.clientNum ].interpolate = qfalse;\n\n\tfor ( i = 0 ; i < cg.snap->numEntities ; i++ ) {\n\t\tcent = &cg_entities[ cg.snap->entities[ i ].number ];\n\t\tCG_TransitionEntity( cent );\n\n\t\t// remember time of snapshot this entity was last updated in\n\t\tcent->snapShotTime = cg.snap->serverTime;\n\t}\n\n\tcg.nextSnap = NULL;\n\n\t// check for playerstate transition events\n\tif ( oldFrame ) {\n\t\tplayerState_t\t*ops, *ps;\n\n\t\tops = &oldFrame->ps;\n\t\tps = &cg.snap->ps;\n\t\t// teleporting checks are irrespective of prediction\n\t\tif ( ( ps->eFlags ^ ops->eFlags ) & EF_TELEPORT_BIT ) {\n\t\t\tcg.thisFrameTeleport = qtrue;\t// will be cleared by prediction code\n\t\t}\n\n\t\t// if we are not doing client side movement prediction for any\n\t\t// reason, then the client events and view changes will be issued now\n\t\tif ( cg.demoPlayback || (cg.snap->ps.pm_flags & PMF_FOLLOW)\n\t\t\t|| cg_nopredict.integer || cg_synchronousClients.integer ) {\n\t\t\tCG_TransitionPlayerState( ps, ops );\n\t\t}\n\t}\n\n}\n\n\n/*\n===================\nCG_SetNextSnap\n\nA new snapshot has just been read in from the client system.\n===================\n*/\nstatic void CG_SetNextSnap( snapshot_t *snap ) {\n\tint\t\t\t\t\tnum;\n\tentityState_t\t\t*es;\n\tcentity_t\t\t\t*cent;\n\n\tcg.nextSnap = snap;\n\n\tBG_PlayerStateToEntityState( &snap->ps, &cg_entities[ snap->ps.clientNum ].nextState, qfalse );\n\tcg_entities[ cg.snap->ps.clientNum ].interpolate = qtrue;\n\n\t// check for extrapolation errors\n\tfor ( num = 0 ; num < snap->numEntities ; num++ ) {\n\t\tes = &snap->entities[num];\n\t\tcent = &cg_entities[ es->number ];\n\n\t\tmemcpy(&cent->nextState, es, sizeof(entityState_t));\n\t\t//cent->nextState = *es;\n\n\t\t// if this frame is a teleport, or the entity wasn't in the\n\t\t// previous frame, don't interpolate\n\t\tif ( !cent->currentValid || ( ( cent->currentState.eFlags ^ es->eFlags ) & EF_TELEPORT_BIT )  ) {\n\t\t\tcent->interpolate = qfalse;\n\t\t} else {\n\t\t\tcent->interpolate = qtrue;\n\t\t}\n\t}\n\n\t// if the next frame is a teleport for the playerstate, we\n\t// can't interpolate during demos\n\tif ( cg.snap && ( ( snap->ps.eFlags ^ cg.snap->ps.eFlags ) & EF_TELEPORT_BIT ) ) {\n\t\tcg.nextFrameTeleport = qtrue;\n\t} else {\n\t\tcg.nextFrameTeleport = qfalse;\n\t}\n\n\t// if changing follow mode, don't interpolate\n\tif ( cg.nextSnap->ps.clientNum != cg.snap->ps.clientNum ) {\n\t\tcg.nextFrameTeleport = qtrue;\n\t}\n\n\t// if changing server restarts, don't interpolate\n\tif ( ( cg.nextSnap->snapFlags ^ cg.snap->snapFlags ) & SNAPFLAG_SERVERCOUNT ) {\n\t\tcg.nextFrameTeleport = qtrue;\n\t}\n\n\t// sort out solid entities\n\tCG_BuildSolidList();\n}\n\n\n/*\n========================\nCG_ReadNextSnapshot\n\nThis is the only place new snapshots are requested\nThis may increment cgs.processedSnapshotNum multiple\ntimes if the client system fails to return a\nvalid snapshot.\n========================\n*/\nstatic snapshot_t *CG_ReadNextSnapshot( void ) {\n\tqboolean\tr;\n\tsnapshot_t\t*dest;\n\n\tif ( cg.latestSnapshotNum > cgs.processedSnapshotNum + 1000 ) {\n\t\tCG_Printf( \"WARNING: CG_ReadNextSnapshot: way out of range, %i > %i\", \n\t\t\tcg.latestSnapshotNum, cgs.processedSnapshotNum );\n\t}\n\n\twhile ( cgs.processedSnapshotNum < cg.latestSnapshotNum ) {\n\t\t// decide which of the two slots to load it into\n\t\tif ( cg.snap == &cg.activeSnapshots[0] ) {\n\t\t\tdest = &cg.activeSnapshots[1];\n\t\t} else {\n\t\t\tdest = &cg.activeSnapshots[0];\n\t\t}\n\n\t\t// try to read the snapshot from the client system\n\t\tcgs.processedSnapshotNum++;\n\t\tr = trap_GetSnapshot( cgs.processedSnapshotNum, dest );\n\n\t\t// FIXME: why would trap_GetSnapshot return a snapshot with the same server time\n\t\tif ( cg.snap && r && dest->serverTime == cg.snap->serverTime ) {\n\t\t\t//continue;\n\t\t}\n\n\t\t// if it succeeded, return\n\t\tif ( r ) {\n\t\t\tCG_AddLagometerSnapshotInfo( dest );\n\t\t\treturn dest;\n\t\t}\n\n\t\t// a GetSnapshot will return failure if the snapshot\n\t\t// never arrived, or  is so old that its entities\n\t\t// have been shoved off the end of the circular\n\t\t// buffer in the client system.\n\n\t\t// record as a dropped packet\n\t\tCG_AddLagometerSnapshotInfo( NULL );\n\n\t\t// If there are additional snapshots, continue trying to\n\t\t// read them.\n\t}\n\n\t// nothing left to read\n\treturn NULL;\n}\n\n\n/*\n============\nCG_ProcessSnapshots\n\nWe are trying to set up a renderable view, so determine\nwhat the simulated time is, and try to get snapshots\nboth before and after that time if available.\n\nIf we don't have a valid cg.snap after exiting this function,\nthen a 3D game view cannot be rendered.  This should only happen\nright after the initial connection.  After cg.snap has been valid\nonce, it will never turn invalid.\n\nEven if cg.snap is valid, cg.nextSnap may not be, if the snapshot\nhasn't arrived yet (it becomes an extrapolating situation instead\nof an interpolating one)\n\n============\n*/\nvoid CG_ProcessSnapshots( void ) {\n\tsnapshot_t\t\t*snap;\n\tint\t\t\t\tn;\n\n\t// see what the latest snapshot the client system has is\n\ttrap_GetCurrentSnapshotNumber( &n, &cg.latestSnapshotTime );\n\tif ( n != cg.latestSnapshotNum ) {\n\t\tif ( n < cg.latestSnapshotNum ) {\n\t\t\t// this should never happen\n\t\t\tCG_Error( \"CG_ProcessSnapshots: n < cg.latestSnapshotNum\" );\n\t\t}\n\t\tcg.latestSnapshotNum = n;\n\t}\n\n\t// If we have yet to receive a snapshot, check for it.\n\t// Once we have gotten the first snapshot, cg.snap will\n\t// always have valid data for the rest of the game\n\twhile ( !cg.snap ) {\n\t\tsnap = CG_ReadNextSnapshot();\n\t\tif ( !snap ) {\n\t\t\t// we can't continue until we get a snapshot\n\t\t\treturn;\n\t\t}\n\n\t\t// set our weapon selection to what\n\t\t// the playerstate is currently using\n\t\tif ( !( snap->snapFlags & SNAPFLAG_NOT_ACTIVE ) ) {\n\t\t\tCG_SetInitialSnapshot( snap );\n\t\t}\n\t}\n\n\t// loop until we either have a valid nextSnap with a serverTime\n\t// greater than cg.time to interpolate towards, or we run\n\t// out of available snapshots\n\tdo {\n\t\t// if we don't have a nextframe, try and read a new one in\n\t\tif ( !cg.nextSnap ) {\n\t\t\tsnap = CG_ReadNextSnapshot();\n\n\t\t\t// if we still don't have a nextframe, we will just have to\n\t\t\t// extrapolate\n\t\t\tif ( !snap ) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tCG_SetNextSnap( snap );\n\n\n\t\t\t// if time went backwards, we have a level restart\n\t\t\tif ( cg.nextSnap->serverTime < cg.snap->serverTime ) {\n\t\t\t\tCG_Error( \"CG_ProcessSnapshots: Server time went backwards\" );\n\t\t\t}\n\t\t}\n\n\t\t// if our time is < nextFrame's, we have a nice interpolating state\n\t\tif ( cg.time >= cg.snap->serverTime && cg.time < cg.nextSnap->serverTime ) {\n\t\t\tbreak;\n\t\t}\n\n\t\t// we have passed the transition from nextFrame to frame\n\t\tCG_TransitionSnapshot();\n\t} while ( 1 );\n\n\t// assert our valid conditions upon exiting\n\tif ( cg.snap == NULL ) {\n\t\tCG_Error( \"CG_ProcessSnapshots: cg.snap == NULL\" );\n\t}\n\tif ( cg.time < cg.snap->serverTime ) {\n\t\t// this can happen right after a vid_restart\n\t\tcg.time = cg.snap->serverTime;\n\t}\n\tif ( cg.nextSnap != NULL && cg.nextSnap->serverTime <= cg.time ) {\n\t\tCG_Error( \"CG_ProcessSnapshots: cg.nextSnap->serverTime <= cg.time\" );\n\t}\n\n}\n\n"
  },
  {
    "path": "src/cgame/cg_syscalls.asm",
    "content": "code\n\nequ\ttrap_Print\t\t\t\t\t\t\t-1\nequ\ttrap_Error\t\t\t\t\t\t\t-2\nequ\ttrap_Milliseconds\t\t\t\t\t-3\nequ\ttrap_Cvar_Register\t\t\t\t\t-4\nequ\ttrap_Cvar_Update\t\t\t\t\t-5\nequ\ttrap_Cvar_Set\t\t\t\t\t\t-6\nequ trap_Cvar_VariableStringBuffer\t\t-7\nequ\ttrap_Argc\t\t\t\t\t\t\t-8\nequ\ttrap_Argv\t\t\t\t\t\t\t-9\nequ\ttrap_Args\t\t\t\t\t\t\t-10\nequ\ttrap_FS_FOpenFile\t\t\t\t\t-11\nequ\ttrap_FS_Read\t\t\t\t\t\t-12\nequ\ttrap_FS_Write\t\t\t\t\t\t-13 \nequ\ttrap_FS_FCloseFile\t\t\t\t\t-14\nequ\ttrap_SendConsoleCommand\t\t\t\t-15\nequ\ttrap_AddCommand\t\t\t\t\t\t-16\nequ\ttrap_SendClientCommand\t\t\t\t-17\nequ\ttrap_UpdateScreen\t\t\t\t\t-18\nequ\ttrap_CM_LoadMap\t\t\t\t\t\t-19\nequ\ttrap_CM_NumInlineModels\t\t\t\t-20\nequ\ttrap_CM_InlineModel\t\t\t\t\t-21\nequ\ttrap_CM_LoadModel\t\t\t\t\t-22\nequ\ttrap_CM_TempBoxModel\t\t\t\t-23\nequ\ttrap_CM_PointContents\t\t\t\t-24\nequ\ttrap_CM_TransformedPointContents\t-25\nequ\ttrap_CM_BoxTrace\t\t\t\t\t-26\nequ\ttrap_CM_TransformedBoxTrace\t\t\t-27\nequ\ttrap_CM_MarkFragments\t\t\t\t-28\nequ\ttrap_S_StartSound\t\t\t\t\t-29\nequ\ttrap_S_StartLocalSound\t\t\t\t-30\nequ\ttrap_S_ClearLoopingSounds\t\t\t-31\nequ\ttrap_S_AddLoopingSound\t\t\t\t-32\nequ\ttrap_S_UpdateEntityPosition\t\t\t-33\nequ\ttrap_S_Respatialize\t\t\t\t\t-34\nequ\ttrap_S_RegisterSound\t\t\t\t-35\nequ\ttrap_S_StartBackgroundTrack\t\t\t-36\nequ\ttrap_R_LoadWorldMap\t\t\t\t\t-37\nequ\ttrap_R_RegisterModel\t\t\t\t-38\nequ\ttrap_R_RegisterSkin\t\t\t\t\t-39\nequ\ttrap_R_RegisterShader\t\t\t\t-40\nequ\ttrap_R_ClearScene\t\t\t\t\t-41\nequ\ttrap_R_AddRefEntityToScene\t\t\t-42\nequ\ttrap_R_AddPolyToScene\t\t\t\t-43\nequ\ttrap_R_AddLightToScene\t\t\t\t-44\nequ\ttrap_R_RenderScene\t\t\t\t\t-45\nequ\ttrap_R_SetColor\t\t\t\t\t\t-46\nequ\ttrap_R_DrawStretchPic\t\t\t\t-47\nequ\ttrap_R_ModelBounds\t\t\t\t\t-48\nequ\ttrap_R_LerpTag\t\t\t\t\t\t-49\nequ\ttrap_GetGlconfig\t\t\t\t\t-50\nequ\ttrap_GetGameState\t\t\t\t\t-51\nequ\ttrap_GetCurrentSnapshotNumber\t\t-52\nequ\ttrap_GetSnapshot\t\t\t\t\t-53\nequ\ttrap_GetServerCommand\t\t\t\t-54\nequ\ttrap_GetCurrentCmdNumber\t\t\t-55\nequ\ttrap_GetUserCmd\t\t\t\t\t\t-56\nequ\ttrap_SetUserCmdValue\t\t\t\t-57\nequ\ttrap_R_RegisterShaderNoMip\t\t\t-58\nequ\ttrap_MemoryRemaining\t\t\t\t-59\nequ trap_R_RegisterFont\t\t\t\t\t-60\nequ trap_Key_IsDown\t\t\t\t\t\t-61\nequ trap_Key_GetCatcher\t\t\t\t\t-62\nequ trap_Key_SetCatcher\t\t\t\t\t-63\nequ trap_Key_GetKey\t\t\t\t\t\t-64\nequ trap_PC_AddGlobalDefine\t\t\t\t-65\nequ\ttrap_PC_LoadSource\t\t\t\t\t-66\nequ trap_PC_FreeSource\t\t\t\t\t-67\nequ trap_PC_ReadToken\t\t\t\t\t-68\nequ trap_PC_SourceFileAndLine\t\t\t-69\nequ trap_S_StopBackgroundTrack\t\t\t-70\nequ trap_RealTime\t\t\t\t\t\t-71\nequ trap_SnapVector\t\t\t\t\t\t-72\nequ trap_RemoveCommand\t\t\t\t\t-73\nequ trap_R_LightForPoint\t\t\t\t-74\nequ trap_CIN_PlayCinematic\t\t\t\t-75\nequ trap_CIN_StopCinematic\t\t\t\t-76\nequ trap_CIN_RunCinematic \t\t\t\t-77\nequ trap_CIN_DrawCinematic\t\t\t\t-78\nequ trap_CIN_SetExtents\t\t\t\t\t-79\nequ trap_R_RemapShader\t\t\t\t\t-80\nequ\ttrap_S_AddRealLoopingSound\t\t\t-81\nequ trap_S_StopLoopingSound\t\t\t\t-82\nequ trap_CM_TempCapsuleModel\t\t\t-83\nequ trap_CM_CapsuleTrace\t\t\t\t-84\nequ trap_CM_TransformedCapsuleTrace\t\t-85\nequ trap_R_AddAdditiveLightToScene\t\t-86\nequ trap_GetEntityToken\t\t\t\t\t-87\nequ\ttrap_R_AddPolysToScene\t\t\t\t-88\nequ trap_R_inPVS\t\t\t\t\t\t-89\nequ trap_FS_Seek\t\t\t-90\n\nequ\tmemset\t\t\t\t\t\t-101\nequ\tmemcpy\t\t\t\t\t\t-102\nequ\tstrncpy\t\t\t\t\t\t-103\nequ\tsin\t\t\t\t\t\t\t-104\nequ\tcos\t\t\t\t\t\t\t-105\nequ\tatan2\t\t\t\t\t\t-106\nequ\tsqrt\t\t\t\t\t\t-107\nequ floor\t\t\t\t\t\t-108\nequ\tceil\t\t\t\t\t\t-109\nequ\ttestPrintInt\t\t\t\t-110\nequ\ttestPrintFloat\t\t\t\t-111\nequ acos\t\t\t\t\t\t-112\n\n"
  },
  {
    "path": "src/cgame/cg_syscalls.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n// cg_syscalls.c -- this file is only included when building a dll\n// cg_syscalls.asm is included instead when building a qvm\n#ifdef Q3_VM\n#error \"Do not use in VM build\"\n#endif\n\n#include \"cg_local.h\"\n\nstatic intptr_t (QDECL *syscall)( intptr_t arg, ... ) = (intptr_t (QDECL *)( intptr_t, ...))-1;\n\n\nvoid dllEntry( intptr_t (QDECL  *syscallptr)( intptr_t arg,... ) ) {\n\tsyscall = syscallptr;\n}\n\n\nint PASSFLOAT( float x ) {\n\tfloat\tfloatTemp;\n\tfloatTemp = x;\n\treturn *(int *)&floatTemp;\n}\n\nvoid\ttrap_Print( const char *fmt ) {\n\tsyscall( CG_PRINT, fmt );\n}\n\nvoid\ttrap_Error( const char *fmt ) {\n\tsyscall( CG_ERROR, fmt );\n}\n\nint\t\ttrap_Milliseconds( void ) {\n\treturn syscall( CG_MILLISECONDS ); \n}\n\nvoid\ttrap_Cvar_Register( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags ) {\n\tsyscall( CG_CVAR_REGISTER, vmCvar, varName, defaultValue, flags );\n}\n\nvoid\ttrap_Cvar_Update( vmCvar_t *vmCvar ) {\n\tsyscall( CG_CVAR_UPDATE, vmCvar );\n}\n\nvoid\ttrap_Cvar_Set( const char *var_name, const char *value ) {\n\tsyscall( CG_CVAR_SET, var_name, value );\n}\n\nvoid trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize ) {\n\tsyscall( CG_CVAR_VARIABLESTRINGBUFFER, var_name, buffer, bufsize );\n}\n\nint\t\ttrap_Argc( void ) {\n\treturn syscall( CG_ARGC );\n}\n\nvoid\ttrap_Argv( int n, char *buffer, int bufferLength ) {\n\tsyscall( CG_ARGV, n, buffer, bufferLength );\n}\n\nvoid\ttrap_Args( char *buffer, int bufferLength ) {\n\tsyscall( CG_ARGS, buffer, bufferLength );\n}\n\nint\t\ttrap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode ) {\n\treturn syscall( CG_FS_FOPENFILE, qpath, f, mode );\n}\n\nvoid\ttrap_FS_Read( void *buffer, int len, fileHandle_t f ) {\n\tsyscall( CG_FS_READ, buffer, len, f );\n}\n\nvoid\ttrap_FS_Write( const void *buffer, int len, fileHandle_t f ) {\n\tsyscall( CG_FS_WRITE, buffer, len, f );\n}\n\nvoid\ttrap_FS_FCloseFile( fileHandle_t f ) {\n\tsyscall( CG_FS_FCLOSEFILE, f );\n}\n\nint trap_FS_Seek( fileHandle_t f, long offset, int origin ) {\n\treturn syscall( CG_FS_SEEK, f, offset, origin );\n}\n\nvoid\ttrap_SendConsoleCommand( const char *text ) {\n\tsyscall( CG_SENDCONSOLECOMMAND, text );\n}\n\nvoid\ttrap_AddCommand( const char *cmdName ) {\n\tsyscall( CG_ADDCOMMAND, cmdName );\n}\n\nvoid\ttrap_RemoveCommand( const char *cmdName ) {\n\tsyscall( CG_REMOVECOMMAND, cmdName );\n}\n\nvoid\ttrap_SendClientCommand( const char *s ) {\n\tsyscall( CG_SENDCLIENTCOMMAND, s );\n}\n\nvoid\ttrap_UpdateScreen( void ) {\n\tsyscall( CG_UPDATESCREEN );\n}\n\nvoid\ttrap_CM_LoadMap( const char *mapname ) {\n\tsyscall( CG_CM_LOADMAP, mapname );\n}\n\nint\t\ttrap_CM_NumInlineModels( void ) {\n\treturn syscall( CG_CM_NUMINLINEMODELS );\n}\n\nclipHandle_t trap_CM_InlineModel( int index ) {\n\treturn syscall( CG_CM_INLINEMODEL, index );\n}\n\nclipHandle_t trap_CM_TempBoxModel( const vec3_t mins, const vec3_t maxs ) {\n\treturn syscall( CG_CM_TEMPBOXMODEL, mins, maxs );\n}\n\nclipHandle_t trap_CM_TempCapsuleModel( const vec3_t mins, const vec3_t maxs ) {\n\treturn syscall( CG_CM_TEMPCAPSULEMODEL, mins, maxs );\n}\n\nint\t\ttrap_CM_PointContents( const vec3_t p, clipHandle_t model ) {\n\treturn syscall( CG_CM_POINTCONTENTS, p, model );\n}\n\nint\t\ttrap_CM_TransformedPointContents( const vec3_t p, clipHandle_t model, const vec3_t origin, const vec3_t angles ) {\n\treturn syscall( CG_CM_TRANSFORMEDPOINTCONTENTS, p, model, origin, angles );\n}\n\nvoid\ttrap_CM_BoxTrace( trace_t *results, const vec3_t start, const vec3_t end,\n\t\t\t\t\t\t  const vec3_t mins, const vec3_t maxs,\n\t\t\t\t\t\t  clipHandle_t model, int brushmask ) {\n\tsyscall( CG_CM_BOXTRACE, results, start, end, mins, maxs, model, brushmask );\n}\n\nvoid\ttrap_CM_CapsuleTrace( trace_t *results, const vec3_t start, const vec3_t end,\n\t\t\t\t\t\t  const vec3_t mins, const vec3_t maxs,\n\t\t\t\t\t\t  clipHandle_t model, int brushmask ) {\n\tsyscall( CG_CM_CAPSULETRACE, results, start, end, mins, maxs, model, brushmask );\n}\n\nvoid\ttrap_CM_TransformedBoxTrace( trace_t *results, const vec3_t start, const vec3_t end,\n\t\t\t\t\t\t  const vec3_t mins, const vec3_t maxs,\n\t\t\t\t\t\t  clipHandle_t model, int brushmask,\n\t\t\t\t\t\t  const vec3_t origin, const vec3_t angles ) {\n\tsyscall( CG_CM_TRANSFORMEDBOXTRACE, results, start, end, mins, maxs, model, brushmask, origin, angles );\n}\n\nvoid\ttrap_CM_TransformedCapsuleTrace( trace_t *results, const vec3_t start, const vec3_t end,\n\t\t\t\t\t\t  const vec3_t mins, const vec3_t maxs,\n\t\t\t\t\t\t  clipHandle_t model, int brushmask,\n\t\t\t\t\t\t  const vec3_t origin, const vec3_t angles ) {\n\tsyscall( CG_CM_TRANSFORMEDCAPSULETRACE, results, start, end, mins, maxs, model, brushmask, origin, angles );\n}\n\nint\t\ttrap_CM_MarkFragments( int numPoints, const vec3_t *points, \n\t\t\t\tconst vec3_t projection,\n\t\t\t\tint maxPoints, vec3_t pointBuffer,\n\t\t\t\tint maxFragments, markFragment_t *fragmentBuffer ) {\n\treturn syscall( CG_CM_MARKFRAGMENTS, numPoints, points, projection, maxPoints, pointBuffer, maxFragments, fragmentBuffer );\n}\n\nvoid\ttrap_S_StartSound( vec3_t origin, int entityNum, int entchannel, sfxHandle_t sfx ) {\n\tsyscall( CG_S_STARTSOUND, origin, entityNum, entchannel, sfx );\n}\n\nvoid\ttrap_S_StartLocalSound( sfxHandle_t sfx, int channelNum ) {\n\tsyscall( CG_S_STARTLOCALSOUND, sfx, channelNum );\n}\n\nvoid\ttrap_S_ClearLoopingSounds( qboolean killall ) {\n\tsyscall( CG_S_CLEARLOOPINGSOUNDS, killall );\n}\n\nvoid\ttrap_S_AddLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx ) {\n\tsyscall( CG_S_ADDLOOPINGSOUND, entityNum, origin, velocity, sfx );\n}\n\nvoid\ttrap_S_AddRealLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx ) {\n\tsyscall( CG_S_ADDREALLOOPINGSOUND, entityNum, origin, velocity, sfx );\n}\n\nvoid\ttrap_S_StopLoopingSound( int entityNum ) {\n\tsyscall( CG_S_STOPLOOPINGSOUND, entityNum );\n}\n\nvoid\ttrap_S_UpdateEntityPosition( int entityNum, const vec3_t origin ) {\n\tsyscall( CG_S_UPDATEENTITYPOSITION, entityNum, origin );\n}\n\nvoid\ttrap_S_Respatialize( int entityNum, const vec3_t origin, vec3_t axis[3], int inwater ) {\n\tsyscall( CG_S_RESPATIALIZE, entityNum, origin, axis, inwater );\n}\n\nsfxHandle_t\ttrap_S_RegisterSound( const char *sample, qboolean compressed ) {\n\treturn syscall( CG_S_REGISTERSOUND, sample, compressed );\n}\n\nvoid\ttrap_S_StartBackgroundTrack( const char *intro, const char *loop ) {\n\tsyscall( CG_S_STARTBACKGROUNDTRACK, intro, loop );\n}\n\nvoid\ttrap_R_LoadWorldMap( const char *mapname ) {\n\tsyscall( CG_R_LOADWORLDMAP, mapname );\n}\n\nqhandle_t trap_R_RegisterModel( const char *name ) {\n\treturn syscall( CG_R_REGISTERMODEL, name );\n}\n\nqhandle_t trap_R_RegisterSkin( const char *name ) {\n\treturn syscall( CG_R_REGISTERSKIN, name );\n}\n\nqhandle_t trap_R_RegisterShader( const char *name ) {\n\treturn syscall( CG_R_REGISTERSHADER, name );\n}\n\nqhandle_t trap_R_RegisterShaderNoMip( const char *name ) {\n\treturn syscall( CG_R_REGISTERSHADERNOMIP, name );\n}\n\nvoid trap_R_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font) {\n\tsyscall(CG_R_REGISTERFONT, fontName, pointSize, font );\n}\n\nvoid\ttrap_R_ClearScene( void ) {\n\tsyscall( CG_R_CLEARSCENE );\n}\n\nvoid\ttrap_R_AddRefEntityToScene( const refEntity_t *re ) {\n\tsyscall( CG_R_ADDREFENTITYTOSCENE, re );\n}\n\nvoid\ttrap_R_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts ) {\n\tsyscall( CG_R_ADDPOLYTOSCENE, hShader, numVerts, verts );\n}\n\nvoid\ttrap_R_AddPolysToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts, int num ) {\n\tsyscall( CG_R_ADDPOLYSTOSCENE, hShader, numVerts, verts, num );\n}\n\nint\t\ttrap_R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir ) {\n\treturn syscall( CG_R_LIGHTFORPOINT, point, ambientLight, directedLight, lightDir );\n}\n\nvoid\ttrap_R_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b ) {\n\tsyscall( CG_R_ADDLIGHTTOSCENE, org, PASSFLOAT(intensity), PASSFLOAT(r), PASSFLOAT(g), PASSFLOAT(b) );\n}\n\nvoid\ttrap_R_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, float g, float b ) {\n\tsyscall( CG_R_ADDADDITIVELIGHTTOSCENE, org, PASSFLOAT(intensity), PASSFLOAT(r), PASSFLOAT(g), PASSFLOAT(b) );\n}\n\nvoid\ttrap_R_RenderScene( const refdef_t *fd ) {\n\tsyscall( CG_R_RENDERSCENE, fd );\n}\n\nvoid\ttrap_R_SetColor( const float *rgba ) {\n\tsyscall( CG_R_SETCOLOR, rgba );\n}\n\nvoid\ttrap_R_DrawStretchPic( float x, float y, float w, float h, \n\t\t\t\t\t\t\t   float s1, float t1, float s2, float t2, qhandle_t hShader ) {\n\tsyscall( CG_R_DRAWSTRETCHPIC, PASSFLOAT(x), PASSFLOAT(y), PASSFLOAT(w), PASSFLOAT(h), PASSFLOAT(s1), PASSFLOAT(t1), PASSFLOAT(s2), PASSFLOAT(t2), hShader );\n}\n\nvoid\ttrap_R_ModelBounds( clipHandle_t model, vec3_t mins, vec3_t maxs ) {\n\tsyscall( CG_R_MODELBOUNDS, model, mins, maxs );\n}\n\nint\t\ttrap_R_LerpTag( orientation_t *tag, clipHandle_t mod, int startFrame, int endFrame, \n\t\t\t\t\t   float frac, const char *tagName ) {\n\treturn syscall( CG_R_LERPTAG, tag, mod, startFrame, endFrame, PASSFLOAT(frac), tagName );\n}\n\nvoid\ttrap_R_RemapShader( const char *oldShader, const char *newShader, const char *timeOffset ) {\n\tsyscall( CG_R_REMAP_SHADER, oldShader, newShader, timeOffset );\n}\n\nvoid\t\ttrap_GetGlconfig( glconfig_t *glconfig ) {\n\tsyscall( CG_GETGLCONFIG, glconfig );\n}\n\nvoid\t\ttrap_GetGameState( gameState_t *gamestate ) {\n\tsyscall( CG_GETGAMESTATE, gamestate );\n}\n\nvoid\t\ttrap_GetCurrentSnapshotNumber( int *snapshotNumber, int *serverTime ) {\n\tsyscall( CG_GETCURRENTSNAPSHOTNUMBER, snapshotNumber, serverTime );\n}\n\nqboolean\ttrap_GetSnapshot( int snapshotNumber, snapshot_t *snapshot ) {\n\treturn syscall( CG_GETSNAPSHOT, snapshotNumber, snapshot );\n}\n\nqboolean\ttrap_GetServerCommand( int serverCommandNumber ) {\n\treturn syscall( CG_GETSERVERCOMMAND, serverCommandNumber );\n}\n\nint\t\t\ttrap_GetCurrentCmdNumber( void ) {\n\treturn syscall( CG_GETCURRENTCMDNUMBER );\n}\n\nqboolean\ttrap_GetUserCmd( int cmdNumber, usercmd_t *ucmd ) {\n\treturn syscall( CG_GETUSERCMD, cmdNumber, ucmd );\n}\n\nvoid\t\ttrap_SetUserCmdValue( int stateValue, float sensitivityScale ) {\n\tsyscall( CG_SETUSERCMDVALUE, stateValue, PASSFLOAT(sensitivityScale) );\n}\n\nvoid\t\ttestPrintInt( char *string, int i ) {\n\tsyscall( CG_TESTPRINTINT, string, i );\n}\n\nvoid\t\ttestPrintFloat( char *string, float f ) {\n\tsyscall( CG_TESTPRINTFLOAT, string, PASSFLOAT(f) );\n}\n\nint trap_MemoryRemaining( void ) {\n\treturn syscall( CG_MEMORY_REMAINING );\n}\n\nqboolean trap_Key_IsDown( int keynum ) {\n\treturn syscall( CG_KEY_ISDOWN, keynum );\n}\n\nint trap_Key_GetCatcher( void ) {\n\treturn syscall( CG_KEY_GETCATCHER );\n}\n\nvoid trap_Key_SetCatcher( int catcher ) {\n\tsyscall( CG_KEY_SETCATCHER, catcher );\n}\n\nint trap_Key_GetKey( const char *binding ) {\n\treturn syscall( CG_KEY_GETKEY, binding );\n}\n\nint trap_PC_AddGlobalDefine( char *define ) {\n\treturn syscall( CG_PC_ADD_GLOBAL_DEFINE, define );\n}\n\nint trap_PC_LoadSource( const char *filename ) {\n\treturn syscall( CG_PC_LOAD_SOURCE, filename );\n}\n\nint trap_PC_FreeSource( int handle ) {\n\treturn syscall( CG_PC_FREE_SOURCE, handle );\n}\n\nint trap_PC_ReadToken( int handle, pc_token_t *pc_token ) {\n\treturn syscall( CG_PC_READ_TOKEN, handle, pc_token );\n}\n\nint trap_PC_SourceFileAndLine( int handle, char *filename, int *line ) {\n\treturn syscall( CG_PC_SOURCE_FILE_AND_LINE, handle, filename, line );\n}\n\nvoid\ttrap_S_StopBackgroundTrack( void ) {\n\tsyscall( CG_S_STOPBACKGROUNDTRACK );\n}\n\nint trap_RealTime(qtime_t *qtime) {\n\treturn syscall( CG_REAL_TIME, qtime );\n}\n\nvoid trap_SnapVector( float *v ) {\n\tsyscall( CG_SNAPVECTOR, v );\n}\n\n// this returns a handle.  arg0 is the name in the format \"idlogo.roq\", set arg1 to NULL, alteredstates to qfalse (do not alter gamestate)\nint trap_CIN_PlayCinematic( const char *arg0, int xpos, int ypos, int width, int height, int bits) {\n  return syscall(CG_CIN_PLAYCINEMATIC, arg0, xpos, ypos, width, height, bits);\n}\n \n// stops playing the cinematic and ends it.  should always return FMV_EOF\n// cinematics must be stopped in reverse order of when they are started\ne_status trap_CIN_StopCinematic(int handle) {\n  return syscall(CG_CIN_STOPCINEMATIC, handle);\n}\n\n\n// will run a frame of the cinematic but will not draw it.  Will return FMV_EOF if the end of the cinematic has been reached.\ne_status trap_CIN_RunCinematic (int handle) {\n  return syscall(CG_CIN_RUNCINEMATIC, handle);\n}\n \n\n// draws the current frame\nvoid trap_CIN_DrawCinematic (int handle) {\n  syscall(CG_CIN_DRAWCINEMATIC, handle);\n}\n \n\n// allows you to resize the animation dynamically\nvoid trap_CIN_SetExtents (int handle, int x, int y, int w, int h) {\n  syscall(CG_CIN_SETEXTENTS, handle, x, y, w, h);\n}\n\n/*\nqboolean trap_loadCamera( const char *name ) {\n\treturn syscall( CG_LOADCAMERA, name );\n}\n\nvoid trap_startCamera(int time) {\n\tsyscall(CG_STARTCAMERA, time);\n}\n\nqboolean trap_getCameraInfo( int time, vec3_t *origin, vec3_t *angles) {\n\treturn syscall( CG_GETCAMERAINFO, time, origin, angles );\n}\n*/\n\nqboolean trap_GetEntityToken( char *buffer, int bufferSize ) {\n\treturn syscall( CG_GET_ENTITY_TOKEN, buffer, bufferSize );\n}\n\nqboolean trap_R_inPVS( const vec3_t p1, const vec3_t p2 ) {\n\treturn syscall( CG_R_INPVS, p1, p2 );\n}\n"
  },
  {
    "path": "src/cgame/cg_view.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n// cg_view.c -- setup all the parameters (position, angle, etc)\n// for a 3D rendering\n#include \"cg_local.h\"\n\n\n/*\n=============================================================================\n\n  MODEL TESTING\n\nThe viewthing and gun positioning tools from Q2 have been integrated and\nenhanced into a single model testing facility.\n\nModel viewing can begin with either \"testmodel <modelname>\" or \"testgun <modelname>\".\n\nThe names must be the full pathname after the basedir, like \n\"models/weapons/v_launch/tris.md3\" or \"players/male/tris.md3\"\n\nTestmodel will create a fake entity 100 units in front of the current view\nposition, directly facing the viewer.  It will remain immobile, so you can\nmove around it to view it from different angles.\n\nTestgun will cause the model to follow the player around and supress the real\nview weapon model.  The default frame 0 of most guns is completely off screen,\nso you will probably have to cycle a couple frames to see it.\n\n\"nextframe\", \"prevframe\", \"nextskin\", and \"prevskin\" commands will change the\nframe or skin of the testmodel.  These are bound to F5, F6, F7, and F8 in\nq3default.cfg.\n\nIf a gun is being tested, the \"gun_x\", \"gun_y\", and \"gun_z\" variables will let\nyou adjust the positioning.\n\nNote that none of the model testing features update while the game is paused, so\nit may be convenient to test with deathmatch set to 1 so that bringing down the\nconsole doesn't pause the game.\n\n=============================================================================\n*/\n\n/*\n=================\nCG_TestModel_f\n\nCreates an entity in front of the current position, which\ncan then be moved around\n=================\n*/\nvoid CG_TestModel_f (void) {\n\tvec3_t\t\tangles;\n\n\tmemset( &cg.testModelEntity, 0, sizeof(cg.testModelEntity) );\n\tif ( trap_Argc() < 2 ) {\n\t\treturn;\n\t}\n\n\tQ_strncpyz (cg.testModelName, CG_Argv( 1 ), MAX_QPATH );\n\tcg.testModelEntity.hModel = trap_R_RegisterModel( cg.testModelName );\n\n\tif ( trap_Argc() == 3 ) {\n\t\tcg.testModelEntity.backlerp = atof( CG_Argv( 2 ) );\n\t\tcg.testModelEntity.frame = 1;\n\t\tcg.testModelEntity.oldframe = 0;\n\t}\n\tif (! cg.testModelEntity.hModel ) {\n\t\tCG_Printf( \"Can't register model\\n\" );\n\t\treturn;\n\t}\n\n\tVectorMA( cg.refdef.vieworg, 100, cg.refdef.viewaxis[0], cg.testModelEntity.origin );\n\n\tangles[PITCH] = 0;\n\tangles[YAW] = 180 + cg.refdefViewAngles[1];\n\tangles[ROLL] = 0;\n\n\tAnglesToAxis( angles, cg.testModelEntity.axis );\n\tcg.testGun = qfalse;\n}\n\n/*\n=================\nCG_TestGun_f\n\nReplaces the current view weapon with the given model\n=================\n*/\nvoid CG_TestGun_f (void) {\n\tCG_TestModel_f();\n\tcg.testGun = qtrue;\n\tcg.testModelEntity.renderfx = RF_MINLIGHT | RF_DEPTHHACK | RF_FIRST_PERSON;\n}\n\n\nvoid CG_TestModelNextFrame_f (void) {\n\tcg.testModelEntity.frame++;\n\tCG_Printf( \"frame %i\\n\", cg.testModelEntity.frame );\n}\n\nvoid CG_TestModelPrevFrame_f (void) {\n\tcg.testModelEntity.frame--;\n\tif ( cg.testModelEntity.frame < 0 ) {\n\t\tcg.testModelEntity.frame = 0;\n\t}\n\tCG_Printf( \"frame %i\\n\", cg.testModelEntity.frame );\n}\n\nvoid CG_TestModelNextSkin_f (void) {\n\tcg.testModelEntity.skinNum++;\n\tCG_Printf( \"skin %i\\n\", cg.testModelEntity.skinNum );\n}\n\nvoid CG_TestModelPrevSkin_f (void) {\n\tcg.testModelEntity.skinNum--;\n\tif ( cg.testModelEntity.skinNum < 0 ) {\n\t\tcg.testModelEntity.skinNum = 0;\n\t}\n\tCG_Printf( \"skin %i\\n\", cg.testModelEntity.skinNum );\n}\n\nstatic void CG_AddTestModel (void) {\n\tint\t\ti;\n\n\t// re-register the model, because the level may have changed\n\tcg.testModelEntity.hModel = trap_R_RegisterModel( cg.testModelName );\n\tif (! cg.testModelEntity.hModel ) {\n\t\tCG_Printf (\"Can't register model\\n\");\n\t\treturn;\n\t}\n\n\t// if testing a gun, set the origin reletive to the view origin\n\tif ( cg.testGun ) {\n\t\tVectorCopy( cg.refdef.vieworg, cg.testModelEntity.origin );\n\t\tVectorCopy( cg.refdef.viewaxis[0], cg.testModelEntity.axis[0] );\n\t\tVectorCopy( cg.refdef.viewaxis[1], cg.testModelEntity.axis[1] );\n\t\tVectorCopy( cg.refdef.viewaxis[2], cg.testModelEntity.axis[2] );\n\n\t\t// allow the position to be adjusted\n\t\tfor (i=0 ; i<3 ; i++) {\n\t\t\tcg.testModelEntity.origin[i] += cg.refdef.viewaxis[0][i] * cg_gun_x.value;\n\t\t\tcg.testModelEntity.origin[i] += cg.refdef.viewaxis[1][i] * cg_gun_y.value;\n\t\t\tcg.testModelEntity.origin[i] += cg.refdef.viewaxis[2][i] * cg_gun_z.value;\n\t\t}\n\t}\n\n\ttrap_R_AddRefEntityToScene( &cg.testModelEntity );\n}\n\n\n\n//============================================================================\n\n\n/*\n=================\nCG_CalcVrect\n\nSets the coordinates of the rendered window\n=================\n*/\nstatic void CG_CalcVrect (void) {\n\tint\t\tsize;\n\n\t// the intermission should allways be full screen\n\tif ( cg.snap->ps.pm_type == PM_INTERMISSION ) {\n\t\tsize = 100;\n\t} else {\n\t\t// bound normal viewsize\n\t\tif (cg_viewsize.integer < 30) {\n\t\t\ttrap_Cvar_Set (\"cg_viewsize\",\"30\");\n\t\t\tsize = 30;\n\t\t} else if (cg_viewsize.integer > 100) {\n\t\t\ttrap_Cvar_Set (\"cg_viewsize\",\"100\");\n\t\t\tsize = 100;\n\t\t} else {\n\t\t\tsize = cg_viewsize.integer;\n\t\t}\n\n\t}\n\tcg.refdef.width = cgs.glconfig.vidWidth*size/100;\n\tcg.refdef.width &= ~1;\n\n\tcg.refdef.height = cgs.glconfig.vidHeight*size/100;\n\tcg.refdef.height &= ~1;\n\n\tcg.refdef.x = (cgs.glconfig.vidWidth - cg.refdef.width)/2;\n\tcg.refdef.y = (cgs.glconfig.vidHeight - cg.refdef.height)/2;\n}\n\n//==============================================================================\n\n\n/*\n===============\nCG_OffsetThirdPersonView\n\n===============\n*/\n#define\tFOCUS_DISTANCE\t512\nstatic void CG_OffsetThirdPersonView( void ) {\n\tvec3_t\t\tforward, right, up;\n\tvec3_t\t\tview;\n\tvec3_t\t\tfocusAngles;\n\ttrace_t\t\ttrace;\n\tstatic vec3_t\tmins = { -4, -4, -4 };\n\tstatic vec3_t\tmaxs = { 4, 4, 4 };\n\tvec3_t\t\tfocusPoint;\n\tfloat\t\tfocusDist;\n\tfloat\t\tforwardScale, sideScale;\n\n\tcg.refdef.vieworg[2] += cg.predictedPlayerState.viewheight;\n\n\tVectorCopy( cg.refdefViewAngles, focusAngles );\n\n\t// if dead, look at killer\n\tif ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) {\n\t\tfocusAngles[YAW] = cg.predictedPlayerState.stats[STAT_DEAD_YAW];\n\t\tcg.refdefViewAngles[YAW] = cg.predictedPlayerState.stats[STAT_DEAD_YAW];\n\t}\n\n\tif ( focusAngles[PITCH] > 45 ) {\n\t\tfocusAngles[PITCH] = 45;\t\t// don't go too far overhead\n\t}\n\tAngleVectors( focusAngles, forward, NULL, NULL );\n\n\tVectorMA( cg.refdef.vieworg, FOCUS_DISTANCE, forward, focusPoint );\n\n\tVectorCopy( cg.refdef.vieworg, view );\n\n\tview[2] += 8;\n\n\tcg.refdefViewAngles[PITCH] *= 0.5;\n\n\tAngleVectors( cg.refdefViewAngles, forward, right, up );\n\n\tforwardScale = cos( cg_thirdPersonAngle.value / 180 * M_PI );\n\tsideScale = sin( cg_thirdPersonAngle.value / 180 * M_PI );\n\tVectorMA( view, -cg_thirdPersonRange.value * forwardScale, forward, view );\n\tVectorMA( view, -cg_thirdPersonRange.value * sideScale, right, view );\n\n\t// trace a ray from the origin to the viewpoint to make sure the view isn't\n\t// in a solid block.  Use an 8 by 8 block to prevent the view from near clipping anything\n\n\tif (!cg_cameraMode.integer) {\n\t\tCG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID );\n\n\t\tif ( trace.fraction != 1.0 ) {\n\t\t\tVectorCopy( trace.endpos, view );\n\t\t\tview[2] += (1.0 - trace.fraction) * 32;\n\t\t\t// try another trace to this position, because a tunnel may have the ceiling\n\t\t\t// close enogh that this is poking out\n\n\t\t\tCG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID );\n\t\t\tVectorCopy( trace.endpos, view );\n\t\t}\n\t}\n\n\n\tVectorCopy( view, cg.refdef.vieworg );\n\n\t// select pitch to look at focus point from vieword\n\tVectorSubtract( focusPoint, cg.refdef.vieworg, focusPoint );\n\tfocusDist = sqrt( focusPoint[0] * focusPoint[0] + focusPoint[1] * focusPoint[1] );\n\tif ( focusDist < 1 ) {\n\t\tfocusDist = 1;\t// should never happen\n\t}\n\tcg.refdefViewAngles[PITCH] = -180 / M_PI * atan2( focusPoint[2], focusDist );\n\tcg.refdefViewAngles[YAW] -= cg_thirdPersonAngle.value;\n}\n\n\n// this causes a compiler bug on mac MrC compiler\nstatic void CG_StepOffset( void ) {\n\tint\t\ttimeDelta;\n\t\n\t// smooth out stair climbing\n\ttimeDelta = cg.time - cg.stepTime;\n\tif ( timeDelta < STEP_TIME ) {\n\t\tcg.refdef.vieworg[2] -= cg.stepChange \n\t\t\t* (STEP_TIME - timeDelta) / STEP_TIME;\n\t}\n}\n\n/*\n===============\nCG_OffsetFirstPersonView\n\n===============\n*/\nstatic void CG_OffsetFirstPersonView( void ) {\n\tfloat\t\t\t*origin;\n\tfloat\t\t\t*angles;\n\tfloat\t\t\tbob;\n\tfloat\t\t\tratio;\n\tfloat\t\t\tdelta;\n\tfloat\t\t\tspeed;\n\tfloat\t\t\tf;\n\tvec3_t\t\t\tpredictedVelocity;\n\tint\t\t\t\ttimeDelta;\n\t\n\tif ( cg.snap->ps.pm_type == PM_INTERMISSION ) {\n\t\treturn;\n\t}\n\n\torigin = cg.refdef.vieworg;\n\tangles = cg.refdefViewAngles;\n\n\t// if dead, fix the angle and don't add any kick\n\tif ( cg.snap->ps.stats[STAT_HEALTH] <= 0 ) {\n\t\tangles[ROLL] = 40;\n\t\tangles[PITCH] = -15;\n\t\tangles[YAW] = cg.snap->ps.stats[STAT_DEAD_YAW];\n\t\torigin[2] += cg.predictedPlayerState.viewheight;\n\t\treturn;\n\t}\n\n\t// add angles based on weapon kick\n\tVectorAdd (angles, cg.kick_angles, angles);\n\n\t// add angles based on damage kick\n\tif ( cg.damageTime ) {\n\t\tratio = cg.time - cg.damageTime;\n\t\tif ( ratio < DAMAGE_DEFLECT_TIME ) {\n\t\t\tratio /= DAMAGE_DEFLECT_TIME;\n\t\t\tangles[PITCH] += ratio * cg.v_dmg_pitch;\n\t\t\tangles[ROLL] += ratio * cg.v_dmg_roll;\n\t\t} else {\n\t\t\tratio = 1.0 - ( ratio - DAMAGE_DEFLECT_TIME ) / DAMAGE_RETURN_TIME;\n\t\t\tif ( ratio > 0 ) {\n\t\t\t\tangles[PITCH] += ratio * cg.v_dmg_pitch;\n\t\t\t\tangles[ROLL] += ratio * cg.v_dmg_roll;\n\t\t\t}\n\t\t}\n\t}\n\n\t// add pitch based on fall kick\n#if 0\n\tratio = ( cg.time - cg.landTime) / FALL_TIME;\n\tif (ratio < 0)\n\t\tratio = 0;\n\tangles[PITCH] += ratio * cg.fall_value;\n#endif\n\n\t// add angles based on velocity\n\tVectorCopy( cg.predictedPlayerState.velocity, predictedVelocity );\n\n\tdelta = DotProduct ( predictedVelocity, cg.refdef.viewaxis[0]);\n\tangles[PITCH] += delta * cg_runpitch.value;\n\t\n\tdelta = DotProduct ( predictedVelocity, cg.refdef.viewaxis[1]);\n\tangles[ROLL] -= delta * cg_runroll.value;\n\n\t// add angles based on bob\n\n\t// make sure the bob is visible even at low speeds\n\tspeed = cg.xyspeed > 200 ? cg.xyspeed : 200;\n\n\tdelta = cg.bobfracsin * cg_bobpitch.value * speed;\n\tif (cg.predictedPlayerState.pm_flags & PMF_DUCKED)\n\t\tdelta *= 3;\t\t// crouching\n\tangles[PITCH] += delta;\n\tdelta = cg.bobfracsin * cg_bobroll.value * speed;\n\tif (cg.predictedPlayerState.pm_flags & PMF_DUCKED)\n\t\tdelta *= 3;\t\t// crouching accentuates roll\n\tif (cg.bobcycle & 1)\n\t\tdelta = -delta;\n\tangles[ROLL] += delta;\n\n//===================================\n\n\t// add view height\n\torigin[2] += cg.predictedPlayerState.viewheight;\n\n\t// smooth out duck height changes\n\ttimeDelta = cg.time - cg.duckTime;\n\tif ( timeDelta < DUCK_TIME) {\n\t\tcg.refdef.vieworg[2] -= cg.duckChange \n\t\t\t* (DUCK_TIME - timeDelta) / DUCK_TIME;\n\t}\n\n\t// add bob height\n\tbob = cg.bobfracsin * cg.xyspeed * cg_bobup.value;\n\tif (bob > 6) {\n\t\tbob = 6;\n\t}\n\n\torigin[2] += bob;\n\n\n\t// add fall height\n\tdelta = cg.time - cg.landTime;\n\tif ( delta < LAND_DEFLECT_TIME ) {\n\t\tf = delta / LAND_DEFLECT_TIME;\n\t\tcg.refdef.vieworg[2] += cg.landChange * f;\n\t} else if ( delta < LAND_DEFLECT_TIME + LAND_RETURN_TIME ) {\n\t\tdelta -= LAND_DEFLECT_TIME;\n\t\tf = 1.0 - ( delta / LAND_RETURN_TIME );\n\t\tcg.refdef.vieworg[2] += cg.landChange * f;\n\t}\n\n\t// add step offset\n\tCG_StepOffset();\n\n\t// add kick offset\n\n\tVectorAdd (origin, cg.kick_origin, origin);\n\n\t// pivot the eye based on a neck length\n#if 0\n\t{\n#define\tNECK_LENGTH\t\t8\n\tvec3_t\t\t\tforward, up;\n \n\tcg.refdef.vieworg[2] -= NECK_LENGTH;\n\tAngleVectors( cg.refdefViewAngles, forward, NULL, up );\n\tVectorMA( cg.refdef.vieworg, 3, forward, cg.refdef.vieworg );\n\tVectorMA( cg.refdef.vieworg, NECK_LENGTH, up, cg.refdef.vieworg );\n\t}\n#endif\n}\n\n//======================================================================\n\nvoid CG_ZoomDown_f( void ) { \n\tif ( cg.zoomed ) {\n\t\treturn;\n\t}\n\tcg.zoomed = qtrue;\n\tcg.zoomTime = cg.time;\n}\n\nvoid CG_ZoomUp_f( void ) { \n\tif ( !cg.zoomed ) {\n\t\treturn;\n\t}\n\tcg.zoomed = qfalse;\n\tcg.zoomTime = cg.time;\n}\n\n\n/*\n====================\nCG_CalcFov\n\nFixed fov at intermissions, otherwise account for fov variable and zooms.\n====================\n*/\n#define\tWAVE_AMPLITUDE\t1\n#define\tWAVE_FREQUENCY\t0.4\n\nstatic int CG_CalcFov( void ) {\n\tfloat\tx;\n\tfloat\tphase;\n\tfloat\tv;\n\tint\t\tcontents;\n\tfloat\tfov_x, fov_y;\n\tfloat\tzoomFov;\n\tfloat\tf;\n\tint\t\tinwater;\n\n\tif ( cg.predictedPlayerState.pm_type == PM_INTERMISSION ) {\n\t\t// if in intermission, use a fixed value\n\t\tfov_x = 90;\n\t} else {\n\t\t// user selectable\n\t\tif ( cgs.dmflags & DF_FIXED_FOV ) {\n\t\t\t// dmflag to prevent wide fov for all clients\n\t\t\tfov_x = 90;\n\t\t} else {\n\t\t\tfov_x = cg_fov.value;\n\t\t\tif ( fov_x < 1 ) {\n\t\t\t\tfov_x = 1;\n\t\t\t} else if ( fov_x > 160 ) {\n\t\t\t\tfov_x = 160;\n\t\t\t}\n\t\t}\n\n\t\t// account for zooms\n\t\tzoomFov = cg_zoomFov.value;\n\t\tif ( zoomFov < 1 ) {\n\t\t\tzoomFov = 1;\n\t\t} else if ( zoomFov > 160 ) {\n\t\t\tzoomFov = 160;\n\t\t}\n\n\t\tif ( cg.zoomed ) {\n\t\t\tf = ( cg.time - cg.zoomTime ) / (float)ZOOM_TIME;\n\t\t\tif ( f > 1.0 ) {\n\t\t\t\tfov_x = zoomFov;\n\t\t\t} else {\n\t\t\t\tfov_x = fov_x + f * ( zoomFov - fov_x );\n\t\t\t}\n\t\t} else {\n\t\t\tf = ( cg.time - cg.zoomTime ) / (float)ZOOM_TIME;\n\t\t\tif ( f > 1.0 ) {\n\t\t\t\tfov_x = fov_x;\n\t\t\t} else {\n\t\t\t\tfov_x = zoomFov + f * ( fov_x - zoomFov );\n\t\t\t}\n\t\t}\n\t}\n\n\tx = cg.refdef.width / tan( fov_x / 360 * M_PI );\n\tfov_y = atan2( cg.refdef.height, x );\n\tfov_y = fov_y * 360 / M_PI;\n\n\t// warp if underwater\n\tcontents = CG_PointContents( cg.refdef.vieworg, -1 );\n\tif ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ){\n\t\tphase = cg.time / 1000.0 * WAVE_FREQUENCY * M_PI * 2;\n\t\tv = WAVE_AMPLITUDE * sin( phase );\n\t\tfov_x += v;\n\t\tfov_y -= v;\n\t\tinwater = qtrue;\n\t}\n\telse {\n\t\tinwater = qfalse;\n\t}\n\n\n\t// set it\n\tcg.refdef.fov_x = fov_x;\n\tcg.refdef.fov_y = fov_y;\n\n\tif ( !cg.zoomed ) {\n\t\tcg.zoomSensitivity = 1;\n\t} else {\n\t\tcg.zoomSensitivity = cg.refdef.fov_y / 75.0;\n\t}\n\n\treturn inwater;\n}\n\n\n\n/*\n===============\nCG_DamageBlendBlob\n\n===============\n*/\nstatic void CG_DamageBlendBlob( void ) {\n\tint\t\t\tt;\n\tint\t\t\tmaxTime;\n\trefEntity_t\t\tent;\n\n\tif ( !cg.damageValue ) {\n\t\treturn;\n\t}\n\n\t//if (cg.cameraMode) {\n\t//\treturn;\n\t//}\n\n\tmaxTime = DAMAGE_TIME;\n\tt = cg.time - cg.damageTime;\n\tif ( t <= 0 || t >= maxTime ) {\n\t\treturn;\n\t}\n\n\n\tmemset( &ent, 0, sizeof( ent ) );\n\tent.reType = RT_SPRITE;\n\tent.renderfx = RF_FIRST_PERSON;\n\n\tVectorMA( cg.refdef.vieworg, 8, cg.refdef.viewaxis[0], ent.origin );\n\tVectorMA( ent.origin, cg.damageX * -8, cg.refdef.viewaxis[1], ent.origin );\n\tVectorMA( ent.origin, cg.damageY * 8, cg.refdef.viewaxis[2], ent.origin );\n\n\tent.radius = cg.damageValue * 3;\n\tent.customShader = cgs.media.viewBloodShader;\n\tent.shaderRGBA[0] = 255;\n\tent.shaderRGBA[1] = 255;\n\tent.shaderRGBA[2] = 255;\n\tent.shaderRGBA[3] = 200 * ( 1.0 - ((float)t / maxTime) );\n\ttrap_R_AddRefEntityToScene( &ent );\n}\n\n\n/*\n===============\nCG_CalcViewValues\n\nSets cg.refdef view values\n===============\n*/\nstatic int CG_CalcViewValues( void ) {\n\tplayerState_t\t*ps;\n\n\tmemset( &cg.refdef, 0, sizeof( cg.refdef ) );\n\n\t// strings for in game rendering\n\t// Q_strncpyz( cg.refdef.text[0], \"Park Ranger\", sizeof(cg.refdef.text[0]) );\n\t// Q_strncpyz( cg.refdef.text[1], \"19\", sizeof(cg.refdef.text[1]) );\n\n\t// calculate size of 3D view\n\tCG_CalcVrect();\n\n\tps = &cg.predictedPlayerState;\n/*\n\tif (cg.cameraMode) {\n\t\tvec3_t origin, angles;\n\t\tif (trap_getCameraInfo(cg.time, &origin, &angles)) {\n\t\t\tVectorCopy(origin, cg.refdef.vieworg);\n\t\t\tangles[ROLL] = 0;\n\t\t\tVectorCopy(angles, cg.refdefViewAngles);\n\t\t\tAnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis );\n\t\t\treturn CG_CalcFov();\n\t\t} else {\n\t\t\tcg.cameraMode = qfalse;\n\t\t}\n\t}\n*/\n\t// intermission view\n\tif ( ps->pm_type == PM_INTERMISSION ) {\n\t\tVectorCopy( ps->origin, cg.refdef.vieworg );\n\t\tVectorCopy( ps->viewangles, cg.refdefViewAngles );\n\t\tAnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis );\n\t\treturn CG_CalcFov();\n\t}\n\n\tcg.bobcycle = ( ps->bobCycle & 128 ) >> 7;\n\tcg.bobfracsin = fabs( sin( ( ps->bobCycle & 127 ) / 127.0 * M_PI ) );\n\tcg.xyspeed = sqrt( ps->velocity[0] * ps->velocity[0] +\n\t\tps->velocity[1] * ps->velocity[1] );\n\n\n\tVectorCopy( ps->origin, cg.refdef.vieworg );\n\tVectorCopy( ps->viewangles, cg.refdefViewAngles );\n\n\tif (cg_cameraOrbit.integer) {\n\t\tif (cg.time > cg.nextOrbitTime) {\n\t\t\tcg.nextOrbitTime = cg.time + cg_cameraOrbitDelay.integer;\n\t\t\tcg_thirdPersonAngle.value += cg_cameraOrbit.value;\n\t\t}\n\t}\n\t// add error decay\n\tif ( cg_errorDecay.value > 0 ) {\n\t\tint\t\tt;\n\t\tfloat\tf;\n\n\t\tt = cg.time - cg.predictedErrorTime;\n\t\tf = ( cg_errorDecay.value - t ) / cg_errorDecay.value;\n\t\tif ( f > 0 && f < 1 ) {\n\t\t\tVectorMA( cg.refdef.vieworg, f, cg.predictedError, cg.refdef.vieworg );\n\t\t} else {\n\t\t\tcg.predictedErrorTime = 0;\n\t\t}\n\t}\n\n\tif ( cg.renderingThirdPerson ) {\n\t\t// back away from character\n\t\tCG_OffsetThirdPersonView();\n\t} else {\n\t\t// offset for local bobbing and kicks\n\t\tCG_OffsetFirstPersonView();\n\t}\n\n\t// position eye reletive to origin\n\tAnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis );\n\n\tif ( cg.hyperspace ) {\n\t\tcg.refdef.rdflags |= RDF_NOWORLDMODEL | RDF_HYPERSPACE;\n\t}\n\n\t// field of view\n\treturn CG_CalcFov();\n}\n\n\n/*\n=====================\nCG_PowerupTimerSounds\n=====================\n*/\nstatic void CG_PowerupTimerSounds( void ) {\n\tint\t\ti;\n\tint\t\tt;\n\n\t// powerup timers going away\n\tfor ( i = 0 ; i < MAX_POWERUPS ; i++ ) {\n\t\tt = cg.snap->ps.powerups[i];\n\t\tif ( t <= cg.time ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( t - cg.time >= POWERUP_BLINKS * POWERUP_BLINK_TIME ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( ( t - cg.time ) / POWERUP_BLINK_TIME != ( t - cg.oldTime ) / POWERUP_BLINK_TIME ) {\n\t\t\ttrap_S_StartSound( NULL, cg.snap->ps.clientNum, CHAN_ITEM, cgs.media.wearOffSound );\n\t\t}\n\t}\n}\n\n/*\n=====================\nCG_AddBufferedSound\n=====================\n*/\nvoid CG_AddBufferedSound( sfxHandle_t sfx ) {\n\tif ( !sfx )\n\t\treturn;\n\tcg.soundBuffer[cg.soundBufferIn] = sfx;\n\tcg.soundBufferIn = (cg.soundBufferIn + 1) % MAX_SOUNDBUFFER;\n\tif (cg.soundBufferIn == cg.soundBufferOut) {\n\t\tcg.soundBufferOut++;\n\t}\n}\n\n/*\n=====================\nCG_PlayBufferedSounds\n=====================\n*/\nstatic void CG_PlayBufferedSounds( void ) {\n\tif ( cg.soundTime < cg.time ) {\n\t\tif (cg.soundBufferOut != cg.soundBufferIn && cg.soundBuffer[cg.soundBufferOut]) {\n\t\t\ttrap_S_StartLocalSound(cg.soundBuffer[cg.soundBufferOut], CHAN_ANNOUNCER);\n\t\t\tcg.soundBuffer[cg.soundBufferOut] = 0;\n\t\t\tcg.soundBufferOut = (cg.soundBufferOut + 1) % MAX_SOUNDBUFFER;\n\t\t\tcg.soundTime = cg.time + 750;\n\t\t}\n\t}\n}\n\n//=========================================================================\n\n/*\n=================\nCG_DrawActiveFrame\n\nGenerates and draws a game scene and status information at the given time.\n=================\n*/\nvoid CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demoPlayback ) {\n\tint\t\tinwater;\n\n\tcg.time = serverTime;\n\tcg.demoPlayback = demoPlayback;\n\n\t// update cvars\n\tCG_UpdateCvars();\n\n\t// if we are only updating the screen as a loading\n\t// pacifier, don't even try to read snapshots\n\tif ( cg.infoScreenText[0] != 0 ) {\n\t\tCG_DrawInformation();\n\t\treturn;\n\t}\n\n\t// any looped sounds will be respecified as entities\n\t// are added to the render list\n\ttrap_S_ClearLoopingSounds(qfalse);\n\n\t// clear all the render lists\n\ttrap_R_ClearScene();\n\n\t// set up cg.snap and possibly cg.nextSnap\n\tCG_ProcessSnapshots();\n\n\t// if we haven't received any snapshots yet, all\n\t// we can draw is the information screen\n\tif ( !cg.snap || ( cg.snap->snapFlags & SNAPFLAG_NOT_ACTIVE ) ) {\n\t\tCG_DrawInformation();\n\t\treturn;\n\t}\n\n\t// let the client system know what our weapon and zoom settings are\n\ttrap_SetUserCmdValue( cg.weaponSelect, cg.zoomSensitivity );\n\n\t// this counter will be bumped for every valid scene we generate\n\tcg.clientFrame++;\n\n\t// update cg.predictedPlayerState\n\tCG_PredictPlayerState();\n\n\t// decide on third person view\n\tcg.renderingThirdPerson = cg_thirdPerson.integer || (cg.snap->ps.stats[STAT_HEALTH] <= 0);\n\n\t// build cg.refdef\n\tinwater = CG_CalcViewValues();\n\n\t// first person blend blobs, done after AnglesToAxis\n\tif ( !cg.renderingThirdPerson ) {\n\t\tCG_DamageBlendBlob();\n\t}\n\n\t// build the render lists\n\tif ( !cg.hyperspace ) {\n\t\tCG_AddPacketEntities();\t\t\t// adter calcViewValues, so predicted player state is correct\n\t\tCG_AddMarks();\n\t\tCG_AddParticles ();\n\t\tCG_AddLocalEntities();\n\t}\n\tCG_AddViewWeapon( &cg.predictedPlayerState );\n\n\t// add buffered sounds\n\tCG_PlayBufferedSounds();\n\n\t// play buffered voice chats\n\tCG_PlayBufferedVoiceChats();\n\n\t// finish up the rest of the refdef\n\tif ( cg.testModelEntity.hModel ) {\n\t\tCG_AddTestModel();\n\t}\n\tcg.refdef.time = cg.time;\n\tmemcpy( cg.refdef.areamask, cg.snap->areamask, sizeof( cg.refdef.areamask ) );\n\n\t// warning sounds when powerup is wearing off\n\tCG_PowerupTimerSounds();\n\n\t// update audio positions\n\ttrap_S_Respatialize( cg.snap->ps.clientNum, cg.refdef.vieworg, cg.refdef.viewaxis, inwater );\n\n\t// make sure the lagometerSample and frame timing isn't done twice when in stereo\n\tif ( stereoView != STEREO_RIGHT ) {\n\t\tcg.frametime = cg.time - cg.oldTime;\n\t\tif ( cg.frametime < 0 ) {\n\t\t\tcg.frametime = 0;\n\t\t}\n\t\tcg.oldTime = cg.time;\n\t\tCG_AddLagometerFrameInfo();\n\t}\n\tif (cg_timescale.value != cg_timescaleFadeEnd.value) {\n\t\tif (cg_timescale.value < cg_timescaleFadeEnd.value) {\n\t\t\tcg_timescale.value += cg_timescaleFadeSpeed.value * ((float)cg.frametime) / 1000;\n\t\t\tif (cg_timescale.value > cg_timescaleFadeEnd.value)\n\t\t\t\tcg_timescale.value = cg_timescaleFadeEnd.value;\n\t\t}\n\t\telse {\n\t\t\tcg_timescale.value -= cg_timescaleFadeSpeed.value * ((float)cg.frametime) / 1000;\n\t\t\tif (cg_timescale.value < cg_timescaleFadeEnd.value)\n\t\t\t\tcg_timescale.value = cg_timescaleFadeEnd.value;\n\t\t}\n\t\tif (cg_timescaleFadeSpeed.value) {\n\t\t\ttrap_Cvar_Set(\"timescale\", va(\"%f\", cg_timescale.value));\n\t\t}\n\t}\n\n\t// actually issue the rendering calls\n\tCG_DrawActive( stereoView );\n\n\tif ( cg_stats.integer ) {\n\t\tCG_Printf( \"cg.clientFrame:%i\\n\", cg.clientFrame );\n\t}\n\n\n}\n\n"
  },
  {
    "path": "src/cgame/cg_weapons.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n// cg_weapons.c -- events and effects dealing with weapons\n#include \"cg_local.h\"\n\n/*\n==========================\nCG_MachineGunEjectBrass\n==========================\n*/\nstatic void CG_MachineGunEjectBrass( centity_t *cent ) {\n\tlocalEntity_t\t*le;\n\trefEntity_t\t\t*re;\n\tvec3_t\t\t\tvelocity, xvelocity;\n\tvec3_t\t\t\toffset, xoffset;\n\tfloat\t\t\twaterScale = 1.0f;\n\tvec3_t\t\t\tv[3];\n\n\tif ( cg_brassTime.integer <= 0 ) {\n\t\treturn;\n\t}\n\n\tle = CG_AllocLocalEntity();\n\tre = &le->refEntity;\n\n\tvelocity[0] = 0;\n\tvelocity[1] = -50 + 40 * crandom();\n\tvelocity[2] = 100 + 50 * crandom();\n\n\tle->leType = LE_FRAGMENT;\n\tle->startTime = cg.time;\n\tle->endTime = le->startTime + cg_brassTime.integer + ( cg_brassTime.integer / 4 ) * random();\n\n\tle->pos.trType = TR_GRAVITY;\n\tle->pos.trTime = cg.time - (rand()&15);\n\n\tAnglesToAxis( cent->lerpAngles, v );\n\n\toffset[0] = 8;\n\toffset[1] = -4;\n\toffset[2] = 24;\n\n\txoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0];\n\txoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1];\n\txoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2];\n\tVectorAdd( cent->lerpOrigin, xoffset, re->origin );\n\n\tVectorCopy( re->origin, le->pos.trBase );\n\n\tif ( CG_PointContents( re->origin, -1 ) & CONTENTS_WATER ) {\n\t\twaterScale = 0.10f;\n\t}\n\n\txvelocity[0] = velocity[0] * v[0][0] + velocity[1] * v[1][0] + velocity[2] * v[2][0];\n\txvelocity[1] = velocity[0] * v[0][1] + velocity[1] * v[1][1] + velocity[2] * v[2][1];\n\txvelocity[2] = velocity[0] * v[0][2] + velocity[1] * v[1][2] + velocity[2] * v[2][2];\n\tVectorScale( xvelocity, waterScale, le->pos.trDelta );\n\n\tAxisCopy( axisDefault, re->axis );\n\tre->hModel = cgs.media.machinegunBrassModel;\n\n\tle->bounceFactor = 0.4 * waterScale;\n\n\tle->angles.trType = TR_LINEAR;\n\tle->angles.trTime = cg.time;\n\tle->angles.trBase[0] = rand()&31;\n\tle->angles.trBase[1] = rand()&31;\n\tle->angles.trBase[2] = rand()&31;\n\tle->angles.trDelta[0] = 2;\n\tle->angles.trDelta[1] = 1;\n\tle->angles.trDelta[2] = 0;\n\n\tle->leFlags = LEF_TUMBLE;\n\tle->leBounceSoundType = LEBS_BRASS;\n\tle->leMarkType = LEMT_NONE;\n}\n\n/*\n==========================\nCG_ShotgunEjectBrass\n==========================\n*/\nstatic void CG_ShotgunEjectBrass( centity_t *cent ) {\n\tlocalEntity_t\t*le;\n\trefEntity_t\t\t*re;\n\tvec3_t\t\t\tvelocity, xvelocity;\n\tvec3_t\t\t\toffset, xoffset;\n\tvec3_t\t\t\tv[3];\n\tint\t\t\t\ti;\n\n\tif ( cg_brassTime.integer <= 0 ) {\n\t\treturn;\n\t}\n\n\tfor ( i = 0; i < 2; i++ ) {\n\t\tfloat\twaterScale = 1.0f;\n\n\t\tle = CG_AllocLocalEntity();\n\t\tre = &le->refEntity;\n\n\t\tvelocity[0] = 60 + 60 * crandom();\n\t\tif ( i == 0 ) {\n\t\t\tvelocity[1] = 40 + 10 * crandom();\n\t\t} else {\n\t\t\tvelocity[1] = -40 + 10 * crandom();\n\t\t}\n\t\tvelocity[2] = 100 + 50 * crandom();\n\n\t\tle->leType = LE_FRAGMENT;\n\t\tle->startTime = cg.time;\n\t\tle->endTime = le->startTime + cg_brassTime.integer*3 + cg_brassTime.integer * random();\n\n\t\tle->pos.trType = TR_GRAVITY;\n\t\tle->pos.trTime = cg.time;\n\n\t\tAnglesToAxis( cent->lerpAngles, v );\n\n\t\toffset[0] = 8;\n\t\toffset[1] = 0;\n\t\toffset[2] = 24;\n\n\t\txoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0];\n\t\txoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1];\n\t\txoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2];\n\t\tVectorAdd( cent->lerpOrigin, xoffset, re->origin );\n\t\tVectorCopy( re->origin, le->pos.trBase );\n\t\tif ( CG_PointContents( re->origin, -1 ) & CONTENTS_WATER ) {\n\t\t\twaterScale = 0.10f;\n\t\t}\n\n\t\txvelocity[0] = velocity[0] * v[0][0] + velocity[1] * v[1][0] + velocity[2] * v[2][0];\n\t\txvelocity[1] = velocity[0] * v[0][1] + velocity[1] * v[1][1] + velocity[2] * v[2][1];\n\t\txvelocity[2] = velocity[0] * v[0][2] + velocity[1] * v[1][2] + velocity[2] * v[2][2];\n\t\tVectorScale( xvelocity, waterScale, le->pos.trDelta );\n\n\t\tAxisCopy( axisDefault, re->axis );\n\t\tre->hModel = cgs.media.shotgunBrassModel;\n\t\tle->bounceFactor = 0.3f;\n\n\t\tle->angles.trType = TR_LINEAR;\n\t\tle->angles.trTime = cg.time;\n\t\tle->angles.trBase[0] = rand()&31;\n\t\tle->angles.trBase[1] = rand()&31;\n\t\tle->angles.trBase[2] = rand()&31;\n\t\tle->angles.trDelta[0] = 1;\n\t\tle->angles.trDelta[1] = 0.5;\n\t\tle->angles.trDelta[2] = 0;\n\n\t\tle->leFlags = LEF_TUMBLE;\n\t\tle->leBounceSoundType = LEBS_BRASS;\n\t\tle->leMarkType = LEMT_NONE;\n\t}\n}\n\n/*\n==========================\nCG_RailTrail\n==========================\n*/\nvoid CG_RailTrail (clientInfo_t *ci, vec3_t start, vec3_t end) {\n\tvec3_t axis[36], move, move2, next_move, vec, temp;\n\tfloat  len;\n\tint    i, j, skip;\n \n\tlocalEntity_t *le;\n\trefEntity_t   *re;\n \n#define RADIUS   4\n#define ROTATION 1\n#define SPACING  5\n \n\tstart[2] -= 4;\n\tVectorCopy (start, move);\n\tVectorSubtract (end, start, vec);\n\tlen = VectorNormalize (vec);\n\tPerpendicularVector(temp, vec);\n\tfor (i = 0 ; i < 36; i++) {\n\t\tRotatePointAroundVector(axis[i], vec, temp, i * 10);//banshee 2.4 was 10\n\t}\n \n\tle = CG_AllocLocalEntity();\n\tre = &le->refEntity;\n \n\tle->leType = LE_FADE_RGB;\n\tle->startTime = cg.time;\n\tle->endTime = cg.time + cg_railTrailTime.value;\n\tle->lifeRate = 1.0 / (le->endTime - le->startTime);\n \n\tre->shaderTime = cg.time / 1000.0f;\n\tre->reType = RT_RAIL_CORE;\n\tre->customShader = cgs.media.railCoreShader;\n \n\tVectorCopy(start, re->origin);\n\tVectorCopy(end, re->oldorigin);\n \n\tre->shaderRGBA[0] = ci->color1[0] * 255;\n    re->shaderRGBA[1] = ci->color1[1] * 255;\n    re->shaderRGBA[2] = ci->color1[2] * 255;\n    re->shaderRGBA[3] = 255;\n\n\tle->color[0] = ci->color1[0] * 0.75;\n\tle->color[1] = ci->color1[1] * 0.75;\n\tle->color[2] = ci->color1[2] * 0.75;\n\tle->color[3] = 1.0f;\n\n\tAxisClear( re->axis );\n \n\tVectorMA(move, 20, vec, move);\n\tVectorCopy(move, next_move);\n\tVectorScale (vec, SPACING, vec);\n\n\tif (cg_oldRail.integer != 0) {\n\t\t// nudge down a bit so it isn't exactly in center\n\t\tre->origin[2] -= 8;\n\t\tre->oldorigin[2] -= 8;\n\t\treturn;\n\t}\n\tskip = -1;\n \n\tj = 18;\n    for (i = 0; i < len; i += SPACING) {\n\t\tif (i != skip) {\n\t\t\tskip = i + SPACING;\n\t\t\tle = CG_AllocLocalEntity();\n            re = &le->refEntity;\n            le->leFlags = LEF_PUFF_DONT_SCALE;\n\t\t\tle->leType = LE_MOVE_SCALE_FADE;\n            le->startTime = cg.time;\n            le->endTime = cg.time + (i>>1) + 600;\n            le->lifeRate = 1.0 / (le->endTime - le->startTime);\n\n            re->shaderTime = cg.time / 1000.0f;\n            re->reType = RT_SPRITE;\n            re->radius = 1.1f;\n\t\t\tre->customShader = cgs.media.railRingsShader;\n\n            re->shaderRGBA[0] = ci->color2[0] * 255;\n            re->shaderRGBA[1] = ci->color2[1] * 255;\n            re->shaderRGBA[2] = ci->color2[2] * 255;\n            re->shaderRGBA[3] = 255;\n\n            le->color[0] = ci->color2[0] * 0.75;\n            le->color[1] = ci->color2[1] * 0.75;\n            le->color[2] = ci->color2[2] * 0.75;\n            le->color[3] = 1.0f;\n\n            le->pos.trType = TR_LINEAR;\n            le->pos.trTime = cg.time;\n\n\t\t\tVectorCopy( move, move2);\n            VectorMA(move2, RADIUS , axis[j], move2);\n            VectorCopy(move2, le->pos.trBase);\n\n            le->pos.trDelta[0] = axis[j][0]*6;\n            le->pos.trDelta[1] = axis[j][1]*6;\n            le->pos.trDelta[2] = axis[j][2]*6;\n\t\t}\n\n        VectorAdd (move, vec, move);\n\n        j = j + ROTATION < 36 ? j + ROTATION : (j + ROTATION) % 36;\n\t}\n}\n\n/*\n==========================\nCG_RocketTrail\n==========================\n*/\nstatic void CG_RocketTrail( centity_t *ent, const weaponInfo_t *wi ) {\n\tint\t\tstep;\n\tvec3_t\torigin, lastPos;\n\tint\t\tt;\n\tint\t\tstartTime, contents;\n\tint\t\tlastContents;\n\tentityState_t\t*es;\n\tvec3_t\tup;\n\tlocalEntity_t\t*smoke;\n\n\tif ( cg_noProjectileTrail.integer ) {\n\t\treturn;\n\t}\n\n\tup[0] = 0;\n\tup[1] = 0;\n\tup[2] = 0;\n\n\tstep = 50;\n\n\tes = &ent->currentState;\n\tstartTime = ent->trailTime;\n\tt = step * ( (startTime + step) / step );\n\n\tBG_EvaluateTrajectory( &es->pos, cg.time, origin );\n\tcontents = CG_PointContents( origin, -1 );\n\n\t// if object (e.g. grenade) is stationary, don't toss up smoke\n\tif ( es->pos.trType == TR_STATIONARY ) {\n\t\tent->trailTime = cg.time;\n\t\treturn;\n\t}\n\n\tBG_EvaluateTrajectory( &es->pos, ent->trailTime, lastPos );\n\tlastContents = CG_PointContents( lastPos, -1 );\n\n\tent->trailTime = cg.time;\n\n\tif ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) {\n\t\tif ( contents & lastContents & CONTENTS_WATER ) {\n\t\t\tCG_BubbleTrail( lastPos, origin, 8 );\n\t\t}\n\t\treturn;\n\t}\n\n\tfor ( ; t <= ent->trailTime ; t += step ) {\n\t\tBG_EvaluateTrajectory( &es->pos, t, lastPos );\n\n\t\tsmoke = CG_SmokePuff( lastPos, up, \n\t\t\t\t\t  wi->trailRadius, \n\t\t\t\t\t  1, 1, 1, 0.33f,\n\t\t\t\t\t  wi->wiTrailTime, \n\t\t\t\t\t  t,\n\t\t\t\t\t  0,\n\t\t\t\t\t  0, \n\t\t\t\t\t  cgs.media.smokePuffShader );\n\t\t// use the optimized local entity add\n\t\tsmoke->leType = LE_SCALE_FADE;\n\t}\n\n}\n\n/*\n==========================\nCG_NailTrail\n==========================\n*/\nstatic void CG_PlasmaTrail( centity_t *cent, const weaponInfo_t *wi ) {\n\tlocalEntity_t\t*le;\n\trefEntity_t\t\t*re;\n\tentityState_t\t*es;\n\tvec3_t\t\t\tvelocity, xvelocity, origin;\n\tvec3_t\t\t\toffset, xoffset;\n\tvec3_t\t\t\tv[3];\n\tint\t\t\t\tt, startTime, step;\n\n\tfloat\twaterScale = 1.0f;\n\n\tif ( cg_noProjectileTrail.integer || cg_oldPlasma.integer ) {\n\t\treturn;\n\t}\n\n\tstep = 50;\n\n\tes = &cent->currentState;\n\tstartTime = cent->trailTime;\n\tt = step * ( (startTime + step) / step );\n\n\tBG_EvaluateTrajectory( &es->pos, cg.time, origin );\n\n\tle = CG_AllocLocalEntity();\n\tre = &le->refEntity;\n\n\tvelocity[0] = 60 - 120 * crandom();\n\tvelocity[1] = 40 - 80 * crandom();\n\tvelocity[2] = 100 - 200 * crandom();\n\n\tle->leType = LE_MOVE_SCALE_FADE;\n\tle->leFlags = LEF_TUMBLE;\n\tle->leBounceSoundType = LEBS_NONE;\n\tle->leMarkType = LEMT_NONE;\n\n\tle->startTime = cg.time;\n\tle->endTime = le->startTime + 600;\n\n\tle->pos.trType = TR_GRAVITY;\n\tle->pos.trTime = cg.time;\n\n\tAnglesToAxis( cent->lerpAngles, v );\n\n\toffset[0] = 2;\n\toffset[1] = 2;\n\toffset[2] = 2;\n\n\txoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0];\n\txoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1];\n\txoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2];\n\n\tVectorAdd( origin, xoffset, re->origin );\n\tVectorCopy( re->origin, le->pos.trBase );\n\n\tif ( CG_PointContents( re->origin, -1 ) & CONTENTS_WATER ) {\n\t\twaterScale = 0.10f;\n\t}\n\n\txvelocity[0] = velocity[0] * v[0][0] + velocity[1] * v[1][0] + velocity[2] * v[2][0];\n\txvelocity[1] = velocity[0] * v[0][1] + velocity[1] * v[1][1] + velocity[2] * v[2][1];\n\txvelocity[2] = velocity[0] * v[0][2] + velocity[1] * v[1][2] + velocity[2] * v[2][2];\n\tVectorScale( xvelocity, waterScale, le->pos.trDelta );\n\n\tAxisCopy( axisDefault, re->axis );\n    re->shaderTime = cg.time / 1000.0f;\n    re->reType = RT_SPRITE;\n    re->radius = 0.25f;\n\tre->customShader = cgs.media.railRingsShader;\n\tle->bounceFactor = 0.3f;\n\n    re->shaderRGBA[0] = wi->flashDlightColor[0] * 63;\n    re->shaderRGBA[1] = wi->flashDlightColor[1] * 63;\n    re->shaderRGBA[2] = wi->flashDlightColor[2] * 63;\n    re->shaderRGBA[3] = 63;\n\n    le->color[0] = wi->flashDlightColor[0] * 0.2;\n    le->color[1] = wi->flashDlightColor[1] * 0.2;\n    le->color[2] = wi->flashDlightColor[2] * 0.2;\n    le->color[3] = 0.25f;\n\n\tle->angles.trType = TR_LINEAR;\n\tle->angles.trTime = cg.time;\n\tle->angles.trBase[0] = rand()&31;\n\tle->angles.trBase[1] = rand()&31;\n\tle->angles.trBase[2] = rand()&31;\n\tle->angles.trDelta[0] = 1;\n\tle->angles.trDelta[1] = 0.5;\n\tle->angles.trDelta[2] = 0;\n\n}\n/*\n==========================\nCG_GrappleTrail\n==========================\n*/\nvoid CG_GrappleTrail( centity_t *ent, const weaponInfo_t *wi ) {\n\tvec3_t\torigin;\n\tentityState_t\t*es;\n\tvec3_t\t\t\tforward, up;\n\trefEntity_t\t\tbeam;\n\n\tes = &ent->currentState;\n\n\tBG_EvaluateTrajectory( &es->pos, cg.time, origin );\n\tent->trailTime = cg.time;\n\n\tmemset( &beam, 0, sizeof( beam ) );\n\t//FIXME adjust for muzzle position\n\tVectorCopy ( cg_entities[ ent->currentState.otherEntityNum ].lerpOrigin, beam.origin );\n\tbeam.origin[2] += 26;\n\tAngleVectors( cg_entities[ ent->currentState.otherEntityNum ].lerpAngles, forward, NULL, up );\n\tVectorMA( beam.origin, -6, up, beam.origin );\n\tVectorCopy( origin, beam.oldorigin );\n\n\tif (Distance( beam.origin, beam.oldorigin ) < 64 )\n\t\treturn; // Don't draw if close\n\n\tbeam.reType = RT_LIGHTNING;\n\tbeam.customShader = cgs.media.lightningShader;\n\n\tAxisClear( beam.axis );\n\tbeam.shaderRGBA[0] = 0xff;\n\tbeam.shaderRGBA[1] = 0xff;\n\tbeam.shaderRGBA[2] = 0xff;\n\tbeam.shaderRGBA[3] = 0xff;\n\ttrap_R_AddRefEntityToScene( &beam );\n}\n\n/*\n==========================\nCG_GrenadeTrail\n==========================\n*/\nstatic void CG_GrenadeTrail( centity_t *ent, const weaponInfo_t *wi ) {\n\tCG_RocketTrail( ent, wi );\n}\n\n\n/*\n=================\nCG_RegisterWeapon\n\nThe server says this item is used on this level\n=================\n*/\nvoid CG_RegisterWeapon( int weaponNum ) {\n\tweaponInfo_t\t*weaponInfo;\n\tgitem_t\t\t\t*item, *ammo;\n\tchar\t\t\tpath[MAX_QPATH];\n\tvec3_t\t\t\tmins, maxs;\n\tint\t\t\t\ti;\n\n\tweaponInfo = &cg_weapons[weaponNum];\n\n\tif ( weaponNum == 0 ) {\n\t\treturn;\n\t}\n\n\tif ( weaponInfo->registered ) {\n\t\treturn;\n\t}\n\n\tmemset( weaponInfo, 0, sizeof( *weaponInfo ) );\n\tweaponInfo->registered = qtrue;\n\n\tfor ( item = bg_itemlist + 1 ; item->classname ; item++ ) {\n\t\tif ( item->giType == IT_WEAPON && item->giTag == weaponNum ) {\n\t\t\tweaponInfo->item = item;\n\t\t\tbreak;\n\t\t}\n\t}\n\tif ( !item->classname ) {\n\t\tCG_Error( \"Couldn't find weapon %i\", weaponNum );\n\t}\n\tCG_RegisterItemVisuals( item - bg_itemlist );\n\n\t// load cmodel before model so filecache works\n\tweaponInfo->weaponModel = trap_R_RegisterModel( item->world_model[0] );\n\n\t// calc midpoint for rotation\n\ttrap_R_ModelBounds( weaponInfo->weaponModel, mins, maxs );\n\tfor ( i = 0 ; i < 3 ; i++ ) {\n\t\tweaponInfo->weaponMidpoint[i] = mins[i] + 0.5 * ( maxs[i] - mins[i] );\n\t}\n\n\tweaponInfo->weaponIcon = trap_R_RegisterShader( item->icon );\n\tweaponInfo->ammoIcon = trap_R_RegisterShader( item->icon );\n\n\tfor ( ammo = bg_itemlist + 1 ; ammo->classname ; ammo++ ) {\n\t\tif ( ammo->giType == IT_AMMO && ammo->giTag == weaponNum ) {\n\t\t\tbreak;\n\t\t}\n\t}\n\tif ( ammo->classname && ammo->world_model[0] ) {\n\t\tweaponInfo->ammoModel = trap_R_RegisterModel( ammo->world_model[0] );\n\t}\n\n\tstrcpy( path, item->world_model[0] );\n\tCOM_StripExtension( path, path );\n\tstrcat( path, \"_flash.md3\" );\n\tweaponInfo->flashModel = trap_R_RegisterModel( path );\n\n\tstrcpy( path, item->world_model[0] );\n\tCOM_StripExtension( path, path );\n\tstrcat( path, \"_barrel.md3\" );\n\tweaponInfo->barrelModel = trap_R_RegisterModel( path );\n\n\tstrcpy( path, item->world_model[0] );\n\tCOM_StripExtension( path, path );\n\tstrcat( path, \"_hand.md3\" );\n\tweaponInfo->handsModel = trap_R_RegisterModel( path );\n\n\tif ( !weaponInfo->handsModel ) {\n\t\tweaponInfo->handsModel = trap_R_RegisterModel( \"models/weapons2/shotgun/shotgun_hand.md3\" );\n\t}\n\n\tweaponInfo->loopFireSound = qfalse;\n\n\tswitch ( weaponNum ) {\n\tcase WP_GAUNTLET:\n\t\tMAKERGB( weaponInfo->flashDlightColor, 0.6f, 0.6f, 1.0f );\n\t\tweaponInfo->firingSound = trap_S_RegisterSound( \"sound/weapons/melee/fstrun.wav\", qfalse );\n\t\tweaponInfo->flashSound[0] = trap_S_RegisterSound( \"sound/weapons/melee/fstatck.wav\", qfalse );\n\t\tbreak;\n\n\tcase WP_LIGHTNING:\n\t\tMAKERGB( weaponInfo->flashDlightColor, 0.6f, 0.6f, 1.0f );\n\t\tweaponInfo->readySound = trap_S_RegisterSound( \"sound/weapons/melee/fsthum.wav\", qfalse );\n\t\tweaponInfo->firingSound = trap_S_RegisterSound( \"sound/weapons/lightning/lg_hum.wav\", qfalse );\n\n\t\tweaponInfo->flashSound[0] = trap_S_RegisterSound( \"sound/weapons/lightning/lg_fire.wav\", qfalse );\n\t\tcgs.media.lightningShader = trap_R_RegisterShader( \"lightningBoltNew\");\n\t\tcgs.media.lightningExplosionModel = trap_R_RegisterModel( \"models/weaphits/crackle.md3\" );\n\t\tcgs.media.sfx_lghit1 = trap_S_RegisterSound( \"sound/weapons/lightning/lg_hit.wav\", qfalse );\n\t\tcgs.media.sfx_lghit2 = trap_S_RegisterSound( \"sound/weapons/lightning/lg_hit2.wav\", qfalse );\n\t\tcgs.media.sfx_lghit3 = trap_S_RegisterSound( \"sound/weapons/lightning/lg_hit3.wav\", qfalse );\n\n\t\tbreak;\n\n\tcase WP_GRAPPLING_HOOK:\n\t\tMAKERGB( weaponInfo->flashDlightColor, 0.6f, 0.6f, 1.0f );\n\t\tweaponInfo->missileModel = trap_R_RegisterModel( \"models/ammo/rocket/rocket.md3\" );\n\t\tweaponInfo->missileTrailFunc = CG_GrappleTrail;\n\t\tweaponInfo->missileDlight = 200;\n\t\tweaponInfo->wiTrailTime = 2000;\n\t\tweaponInfo->trailRadius = 64;\n\t\tMAKERGB( weaponInfo->missileDlightColor, 1, 0.75f, 0 );\n\t\tweaponInfo->readySound = trap_S_RegisterSound( \"sound/weapons/melee/fsthum.wav\", qfalse );\n\t\tweaponInfo->firingSound = trap_S_RegisterSound( \"sound/weapons/melee/fstrun.wav\", qfalse );\n\t\tbreak;\n\n\tcase WP_MACHINEGUN:\n\t\tMAKERGB( weaponInfo->flashDlightColor, 1, 1, 0 );\n\t\tweaponInfo->flashSound[0] = trap_S_RegisterSound( \"sound/weapons/machinegun/machgf1b.wav\", qfalse );\n\t\tweaponInfo->flashSound[1] = trap_S_RegisterSound( \"sound/weapons/machinegun/machgf2b.wav\", qfalse );\n\t\tweaponInfo->flashSound[2] = trap_S_RegisterSound( \"sound/weapons/machinegun/machgf3b.wav\", qfalse );\n\t\tweaponInfo->flashSound[3] = trap_S_RegisterSound( \"sound/weapons/machinegun/machgf4b.wav\", qfalse );\n\t\tweaponInfo->ejectBrassFunc = CG_MachineGunEjectBrass;\n\t\tcgs.media.bulletExplosionShader = trap_R_RegisterShader( \"bulletExplosion\" );\n\t\tbreak;\n\n\tcase WP_SHOTGUN:\n\t\tMAKERGB( weaponInfo->flashDlightColor, 1, 1, 0 );\n\t\tweaponInfo->flashSound[0] = trap_S_RegisterSound( \"sound/weapons/shotgun/sshotf1b.wav\", qfalse );\n\t\tweaponInfo->ejectBrassFunc = CG_ShotgunEjectBrass;\n\t\tbreak;\n\n\tcase WP_ROCKET_LAUNCHER:\n\t\tweaponInfo->missileModel = trap_R_RegisterModel( \"models/ammo/rocket/rocket.md3\" );\n\t\tweaponInfo->missileSound = trap_S_RegisterSound( \"sound/weapons/rocket/rockfly.wav\", qfalse );\n\t\tweaponInfo->missileTrailFunc = CG_RocketTrail;\n\t\tweaponInfo->missileDlight = 200;\n\t\tweaponInfo->wiTrailTime = 2000;\n\t\tweaponInfo->trailRadius = 64;\n\t\t\n\t\tMAKERGB( weaponInfo->missileDlightColor, 1, 0.75f, 0 );\n\t\tMAKERGB( weaponInfo->flashDlightColor, 1, 0.75f, 0 );\n\n\t\tweaponInfo->flashSound[0] = trap_S_RegisterSound( \"sound/weapons/rocket/rocklf1a.wav\", qfalse );\n\t\tcgs.media.rocketExplosionShader = trap_R_RegisterShader( \"rocketExplosion\" );\n\t\tbreak;\n\n\tcase WP_GRENADE_LAUNCHER:\n\t\tweaponInfo->missileModel = trap_R_RegisterModel( \"models/ammo/grenade1.md3\" );\n\t\tweaponInfo->missileTrailFunc = CG_GrenadeTrail;\n\t\tweaponInfo->wiTrailTime = 700;\n\t\tweaponInfo->trailRadius = 32;\n\t\tMAKERGB( weaponInfo->flashDlightColor, 1, 0.70f, 0 );\n\t\tweaponInfo->flashSound[0] = trap_S_RegisterSound( \"sound/weapons/grenade/grenlf1a.wav\", qfalse );\n\t\tcgs.media.grenadeExplosionShader = trap_R_RegisterShader( \"grenadeExplosion\" );\n\t\tbreak;\n\n\tcase WP_PLASMAGUN:\n//\t\tweaponInfo->missileModel = cgs.media.invulnerabilityPowerupModel;\n\t\tweaponInfo->missileTrailFunc = CG_PlasmaTrail;\n\t\tweaponInfo->missileSound = trap_S_RegisterSound( \"sound/weapons/plasma/lasfly.wav\", qfalse );\n\t\tMAKERGB( weaponInfo->flashDlightColor, 0.6f, 0.6f, 1.0f );\n\t\tweaponInfo->flashSound[0] = trap_S_RegisterSound( \"sound/weapons/plasma/hyprbf1a.wav\", qfalse );\n\t\tcgs.media.plasmaExplosionShader = trap_R_RegisterShader( \"plasmaExplosion\" );\n\t\tcgs.media.railRingsShader = trap_R_RegisterShader( \"railDisc\" );\n\t\tbreak;\n\n\tcase WP_RAILGUN:\n\t\tweaponInfo->readySound = trap_S_RegisterSound( \"sound/weapons/railgun/rg_hum.wav\", qfalse );\n\t\tMAKERGB( weaponInfo->flashDlightColor, 1, 0.5f, 0 );\n\t\tweaponInfo->flashSound[0] = trap_S_RegisterSound( \"sound/weapons/railgun/railgf1a.wav\", qfalse );\n\t\tcgs.media.railExplosionShader = trap_R_RegisterShader( \"railExplosion\" );\n\t\tcgs.media.railRingsShader = trap_R_RegisterShader( \"railDisc\" );\n\t\tcgs.media.railCoreShader = trap_R_RegisterShader( \"railCore\" );\n\t\tbreak;\n\n\tcase WP_BFG:\n\t\tweaponInfo->readySound = trap_S_RegisterSound( \"sound/weapons/bfg/bfg_hum.wav\", qfalse );\n\t\tMAKERGB( weaponInfo->flashDlightColor, 1, 0.7f, 1 );\n\t\tweaponInfo->flashSound[0] = trap_S_RegisterSound( \"sound/weapons/bfg/bfg_fire.wav\", qfalse );\n\t\tcgs.media.bfgExplosionShader = trap_R_RegisterShader( \"bfgExplosion\" );\n\t\tweaponInfo->missileModel = trap_R_RegisterModel( \"models/weaphits/bfg.md3\" );\n\t\tweaponInfo->missileSound = trap_S_RegisterSound( \"sound/weapons/rocket/rockfly.wav\", qfalse );\n\t\tbreak;\n\n\t default:\n\t\tMAKERGB( weaponInfo->flashDlightColor, 1, 1, 1 );\n\t\tweaponInfo->flashSound[0] = trap_S_RegisterSound( \"sound/weapons/rocket/rocklf1a.wav\", qfalse );\n\t\tbreak;\n\t}\n}\n\n/*\n=================\nCG_RegisterItemVisuals\n\nThe server says this item is used on this level\n=================\n*/\nvoid CG_RegisterItemVisuals( int itemNum ) {\n\titemInfo_t\t\t*itemInfo;\n\tgitem_t\t\t\t*item;\n\n\tif ( itemNum < 0 || itemNum >= bg_numItems ) {\n\t\tCG_Error( \"CG_RegisterItemVisuals: itemNum %d out of range [0-%d]\", itemNum, bg_numItems-1 );\n\t}\n\n\titemInfo = &cg_items[ itemNum ];\n\tif ( itemInfo->registered ) {\n\t\treturn;\n\t}\n\n\titem = &bg_itemlist[ itemNum ];\n\n\tmemset( itemInfo, 0, sizeof( &itemInfo ) );\n\titemInfo->registered = qtrue;\n\n\titemInfo->models[0] = trap_R_RegisterModel( item->world_model[0] );\n\n\titemInfo->icon = trap_R_RegisterShader( item->icon );\n\n\tif ( item->giType == IT_WEAPON ) {\n\t\tCG_RegisterWeapon( item->giTag );\n\t}\n\n\t//\n\t// powerups have an accompanying ring or sphere\n\t//\n\tif ( item->giType == IT_POWERUP || item->giType == IT_HEALTH || \n\t\titem->giType == IT_ARMOR || item->giType == IT_HOLDABLE ) {\n\t\tif ( item->world_model[1] ) {\n\t\t\titemInfo->models[1] = trap_R_RegisterModel( item->world_model[1] );\n\t\t}\n\t}\n}\n\n\n/*\n========================================================================================\n\nVIEW WEAPON\n\n========================================================================================\n*/\n\n/*\n=================\nCG_MapTorsoToWeaponFrame\n\n=================\n*/\nstatic int CG_MapTorsoToWeaponFrame( clientInfo_t *ci, int frame ) {\n\n\t// change weapon\n\tif ( frame >= ci->animations[TORSO_DROP].firstFrame \n\t\t&& frame < ci->animations[TORSO_DROP].firstFrame + 9 ) {\n\t\treturn frame - ci->animations[TORSO_DROP].firstFrame + 6;\n\t}\n\n\t// stand attack\n\tif ( frame >= ci->animations[TORSO_ATTACK].firstFrame \n\t\t&& frame < ci->animations[TORSO_ATTACK].firstFrame + 6 ) {\n\t\treturn 1 + frame - ci->animations[TORSO_ATTACK].firstFrame;\n\t}\n\n\t// stand attack 2\n\tif ( frame >= ci->animations[TORSO_ATTACK2].firstFrame \n\t\t&& frame < ci->animations[TORSO_ATTACK2].firstFrame + 6 ) {\n\t\treturn 1 + frame - ci->animations[TORSO_ATTACK2].firstFrame;\n\t}\n\t\n\treturn 0;\n}\n\n\n/*\n==============\nCG_CalculateWeaponPosition\n==============\n*/\nstatic void CG_CalculateWeaponPosition( vec3_t origin, vec3_t angles ) {\n\tfloat\tscale;\n\tint\t\tdelta;\n\tfloat\tfracsin;\n\n\tVectorCopy( cg.refdef.vieworg, origin );\n\tVectorCopy( cg.refdefViewAngles, angles );\n\n\t// on odd legs, invert some angles\n\tif ( cg.bobcycle & 1 ) {\n\t\tscale = -cg.xyspeed;\n\t} else {\n\t\tscale = cg.xyspeed;\n\t}\n\n\t// gun angles from bobbing\n\tangles[ROLL] += scale * cg.bobfracsin * 0.005;\n\tangles[YAW] += scale * cg.bobfracsin * 0.01;\n\tangles[PITCH] += cg.xyspeed * cg.bobfracsin * 0.005;\n\n\t// drop the weapon when landing\n\tdelta = cg.time - cg.landTime;\n\tif ( delta < LAND_DEFLECT_TIME ) {\n\t\torigin[2] += cg.landChange*0.25 * delta / LAND_DEFLECT_TIME;\n\t} else if ( delta < LAND_DEFLECT_TIME + LAND_RETURN_TIME ) {\n\t\torigin[2] += cg.landChange*0.25 * \n\t\t\t(LAND_DEFLECT_TIME + LAND_RETURN_TIME - delta) / LAND_RETURN_TIME;\n\t}\n\n#if 0\n\t// drop the weapon when stair climbing\n\tdelta = cg.time - cg.stepTime;\n\tif ( delta < STEP_TIME/2 ) {\n\t\torigin[2] -= cg.stepChange*0.25 * delta / (STEP_TIME/2);\n\t} else if ( delta < STEP_TIME ) {\n\t\torigin[2] -= cg.stepChange*0.25 * (STEP_TIME - delta) / (STEP_TIME/2);\n\t}\n#endif\n\n\t// idle drift\n\tscale = cg.xyspeed + 40;\n\tfracsin = sin( cg.time * 0.001 );\n\tangles[ROLL] += scale * fracsin * 0.01;\n\tangles[YAW] += scale * fracsin * 0.01;\n\tangles[PITCH] += scale * fracsin * 0.01;\n}\n\n\n/*\n===============\nCG_LightningBolt\n\nOrigin will be the exact tag point, which is slightly\ndifferent than the muzzle point used for determining hits.\nThe cent should be the non-predicted cent if it is from the player,\nso the endpoint will reflect the simulated strike (lagging the predicted\nangle)\n===============\n*/\nstatic void CG_LightningBolt( centity_t *cent, vec3_t origin ) {\n\ttrace_t  trace;\n\trefEntity_t  beam;\n\tvec3_t   forward;\n\tvec3_t   muzzlePoint, endPoint;\n\n\tif (cent->currentState.weapon != WP_LIGHTNING) {\n\t\treturn;\n\t}\n\n\tmemset( &beam, 0, sizeof( beam ) );\n\n\t// CPMA  \"true\" lightning\n\tif ((cent->currentState.number == cg.predictedPlayerState.clientNum) && (cg_trueLightning.value != 0)) {\n\t\tvec3_t angle;\n\t\tint i;\n\n\t\tfor (i = 0; i < 3; i++) {\n\t\t\tfloat a = cent->lerpAngles[i] - cg.refdefViewAngles[i];\n\t\t\tif (a > 180) {\n\t\t\t\ta -= 360;\n\t\t\t}\n\t\t\tif (a < -180) {\n\t\t\t\ta += 360;\n\t\t\t}\n\n\t\t\tangle[i] = cg.refdefViewAngles[i] + a * (1.0 - cg_trueLightning.value);\n\t\t\tif (angle[i] < 0) {\n\t\t\t\tangle[i] += 360;\n\t\t\t}\n\t\t\tif (angle[i] > 360) {\n\t\t\t\tangle[i] -= 360;\n\t\t\t}\n\t\t}\n\n\t\tAngleVectors(angle, forward, NULL, NULL );\n\t\tVectorCopy(cent->lerpOrigin, muzzlePoint );\n//\t\tVectorCopy(cg.refdef.vieworg, muzzlePoint );\n\t} else {\n\t\t// !CPMA\n\t\tAngleVectors( cent->lerpAngles, forward, NULL, NULL );\n\t\tVectorCopy(cent->lerpOrigin, muzzlePoint );\n\t}\n\n\t// FIXME: crouch\n\tmuzzlePoint[2] += DEFAULT_VIEWHEIGHT;\n\n\tVectorMA( muzzlePoint, 14, forward, muzzlePoint );\n\n\t// project forward by the lightning range\n\tVectorMA( muzzlePoint, LIGHTNING_RANGE, forward, endPoint );\n\n\t// see if it hit a wall\n\tCG_Trace( &trace, muzzlePoint, vec3_origin, vec3_origin, endPoint, \n\t\tcent->currentState.number, MASK_SHOT );\n\n\t// this is the endpoint\n\tVectorCopy( trace.endpos, beam.oldorigin );\n\n\t// use the provided origin, even though it may be slightly\n\t// different than the muzzle origin\n\tVectorCopy( origin, beam.origin );\n\n\tbeam.reType = RT_LIGHTNING;\n\tbeam.customShader = cgs.media.lightningShader;\n\ttrap_R_AddRefEntityToScene( &beam );\n\n\t// add the impact flare if it hit something\n\tif ( trace.fraction < 1.0 ) {\n\t\tvec3_t\tangles;\n\t\tvec3_t\tdir;\n\n\t\tVectorSubtract( beam.oldorigin, beam.origin, dir );\n\t\tVectorNormalize( dir );\n\n\t\tmemset( &beam, 0, sizeof( beam ) );\n\t\tbeam.hModel = cgs.media.lightningExplosionModel;\n\n\t\tVectorMA( trace.endpos, -16, dir, beam.origin );\n\n\t\t// make a random orientation\n\t\tangles[0] = rand() % 360;\n\t\tangles[1] = rand() % 360;\n\t\tangles[2] = rand() % 360;\n\t\tAnglesToAxis( angles, beam.axis );\n\t\ttrap_R_AddRefEntityToScene( &beam );\n\t}\n}\n/*\n\nstatic void CG_LightningBolt( centity_t *cent, vec3_t origin ) {\n\ttrace_t\t\ttrace;\n\trefEntity_t\t\tbeam;\n\tvec3_t\t\t\tforward;\n\tvec3_t\t\t\tmuzzlePoint, endPoint;\n\n\tif ( cent->currentState.weapon != WP_LIGHTNING ) {\n\t\treturn;\n\t}\n\n\tmemset( &beam, 0, sizeof( beam ) );\n\n\t// find muzzle point for this frame\n\tVectorCopy( cent->lerpOrigin, muzzlePoint );\n\tAngleVectors( cent->lerpAngles, forward, NULL, NULL );\n\n\t// FIXME: crouch\n\tmuzzlePoint[2] += DEFAULT_VIEWHEIGHT;\n\n\tVectorMA( muzzlePoint, 14, forward, muzzlePoint );\n\n\t// project forward by the lightning range\n\tVectorMA( muzzlePoint, LIGHTNING_RANGE, forward, endPoint );\n\n\t// see if it hit a wall\n\tCG_Trace( &trace, muzzlePoint, vec3_origin, vec3_origin, endPoint, \n\t\tcent->currentState.number, MASK_SHOT );\n\n\t// this is the endpoint\n\tVectorCopy( trace.endpos, beam.oldorigin );\n\n\t// use the provided origin, even though it may be slightly\n\t// different than the muzzle origin\n\tVectorCopy( origin, beam.origin );\n\n\tbeam.reType = RT_LIGHTNING;\n\tbeam.customShader = cgs.media.lightningShader;\n\ttrap_R_AddRefEntityToScene( &beam );\n\n\t// add the impact flare if it hit something\n\tif ( trace.fraction < 1.0 ) {\n\t\tvec3_t\tangles;\n\t\tvec3_t\tdir;\n\n\t\tVectorSubtract( beam.oldorigin, beam.origin, dir );\n\t\tVectorNormalize( dir );\n\n\t\tmemset( &beam, 0, sizeof( beam ) );\n\t\tbeam.hModel = cgs.media.lightningExplosionModel;\n\n\t\tVectorMA( trace.endpos, -16, dir, beam.origin );\n\n\t\t// make a random orientation\n\t\tangles[0] = rand() % 360;\n\t\tangles[1] = rand() % 360;\n\t\tangles[2] = rand() % 360;\n\t\tAnglesToAxis( angles, beam.axis );\n\t\ttrap_R_AddRefEntityToScene( &beam );\n\t}\n}\n*/\n\n/*\n===============\nCG_SpawnRailTrail\n\nOrigin will be the exact tag point, which is slightly\ndifferent than the muzzle point used for determining hits.\n===============\n*/\nstatic void CG_SpawnRailTrail( centity_t *cent, vec3_t origin ) {\n\tclientInfo_t\t*ci;\n\n\tif ( cent->currentState.weapon != WP_RAILGUN ) {\n\t\treturn;\n\t}\n\tif ( !cent->pe.railgunFlash ) {\n\t\treturn;\n\t}\n\tcent->pe.railgunFlash = qtrue;\n\tci = &cgs.clientinfo[ cent->currentState.clientNum ];\n\tCG_RailTrail( ci, origin, cent->pe.railgunImpact );\n}\n\n\n/*\n======================\nCG_MachinegunSpinAngle\n======================\n*/\n#define\t\tSPIN_SPEED\t0.9\n#define\t\tCOAST_TIME\t1000\nstatic float\tCG_MachinegunSpinAngle( centity_t *cent ) {\n\tint\t\tdelta;\n\tfloat\tangle;\n\tfloat\tspeed;\n\n\tdelta = cg.time - cent->pe.barrelTime;\n\tif ( cent->pe.barrelSpinning ) {\n\t\tangle = cent->pe.barrelAngle + delta * SPIN_SPEED;\n\t} else {\n\t\tif ( delta > COAST_TIME ) {\n\t\t\tdelta = COAST_TIME;\n\t\t}\n\n\t\tspeed = 0.5 * ( SPIN_SPEED + (float)( COAST_TIME - delta ) / COAST_TIME );\n\t\tangle = cent->pe.barrelAngle + delta * speed;\n\t}\n\n\tif ( cent->pe.barrelSpinning == !(cent->currentState.eFlags & EF_FIRING) ) {\n\t\tcent->pe.barrelTime = cg.time;\n\t\tcent->pe.barrelAngle = AngleMod( angle );\n\t\tcent->pe.barrelSpinning = !!(cent->currentState.eFlags & EF_FIRING);\n\t}\n\n\treturn angle;\n}\n\n\n/*\n========================\nCG_AddWeaponWithPowerups\n========================\n*/\nstatic void CG_AddWeaponWithPowerups( refEntity_t *gun, int powerups ) {\n\t// add powerup effects\n\tif ( powerups & ( 1 << PW_INVIS ) ) {\n\t\tgun->customShader = cgs.media.invisShader;\n\t\ttrap_R_AddRefEntityToScene( gun );\n\t} else {\n\t\ttrap_R_AddRefEntityToScene( gun );\n\n\t\tif ( powerups & ( 1 << PW_BATTLESUIT ) ) {\n\t\t\tgun->customShader = cgs.media.battleWeaponShader;\n\t\t\ttrap_R_AddRefEntityToScene( gun );\n\t\t}\n\t\tif ( powerups & ( 1 << PW_QUAD ) ) {\n\t\t\tgun->customShader = cgs.media.quadWeaponShader;\n\t\t\ttrap_R_AddRefEntityToScene( gun );\n\t\t}\n\t}\n}\n\n\n/*\n=============\nCG_AddPlayerWeapon\n\nUsed for both the view weapon (ps is valid) and the world modelother character models (ps is NULL)\nThe main player will have this called for BOTH cases, so effects like light and\nsound should only be done on the world model case.\n=============\n*/\nvoid CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent, int team ) {\n\trefEntity_t\tgun;\n\trefEntity_t\tbarrel;\n\trefEntity_t\tflash;\n\tvec3_t\t\tangles;\n\tweapon_t\tweaponNum;\n\tweaponInfo_t\t*weapon;\n\tcentity_t\t*nonPredictedCent;\n//\tint\tcol;\n\n\tweaponNum = cent->currentState.weapon;\n\n\tCG_RegisterWeapon( weaponNum );\n\tweapon = &cg_weapons[weaponNum];\n\n\t// add the weapon\n\tmemset( &gun, 0, sizeof( gun ) );\n\tVectorCopy( parent->lightingOrigin, gun.lightingOrigin );\n\tgun.shadowPlane = parent->shadowPlane;\n\tgun.renderfx = parent->renderfx;\n\n\t// set custom shading for railgun refire rate\n\tif ( ps ) {\n\t\tif ( cg.predictedPlayerState.weapon == WP_RAILGUN \n\t\t\t&& cg.predictedPlayerState.weaponstate == WEAPON_FIRING ) {\n\t\t\tfloat\tf;\n\n\t\t\tf = (float)cg.predictedPlayerState.weaponTime / 1500;\n\t\t\tgun.shaderRGBA[1] = 0;\n\t\t\tgun.shaderRGBA[0] = \n\t\t\tgun.shaderRGBA[2] = 255 * ( 1.0 - f );\n\t\t} else {\n\t\t\tgun.shaderRGBA[0] = 255;\n\t\t\tgun.shaderRGBA[1] = 255;\n\t\t\tgun.shaderRGBA[2] = 255;\n\t\t\tgun.shaderRGBA[3] = 255;\n\t\t}\n\t}\n\n\tgun.hModel = weapon->weaponModel;\n\tif (!gun.hModel) {\n\t\treturn;\n\t}\n\n\tif ( !ps ) {\n\t\t// add weapon ready sound\n\t\tcent->pe.lightningFiring = qfalse;\n\t\tif ( ( cent->currentState.eFlags & EF_FIRING ) && weapon->firingSound ) {\n\t\t\t// lightning gun and guantlet make a different sound when fire is held down\n\t\t\ttrap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->firingSound );\n\t\t\tcent->pe.lightningFiring = qtrue;\n\t\t} else if ( weapon->readySound ) {\n\t\t\ttrap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->readySound );\n\t\t}\n\t}\n\n\tCG_PositionEntityOnTag( &gun, parent, parent->hModel, \"tag_weapon\");\n\n\tCG_AddWeaponWithPowerups( &gun, cent->currentState.powerups );\n\n\t// add the spinning barrel\n\tif ( weapon->barrelModel ) {\n\t\tmemset( &barrel, 0, sizeof( barrel ) );\n\t\tVectorCopy( parent->lightingOrigin, barrel.lightingOrigin );\n\t\tbarrel.shadowPlane = parent->shadowPlane;\n\t\tbarrel.renderfx = parent->renderfx;\n\n\t\tbarrel.hModel = weapon->barrelModel;\n\t\tangles[YAW] = 0;\n\t\tangles[PITCH] = 0;\n\t\tangles[ROLL] = CG_MachinegunSpinAngle( cent );\n\t\tAnglesToAxis( angles, barrel.axis );\n\n\t\tCG_PositionRotatedEntityOnTag( &barrel, &gun, weapon->weaponModel, \"tag_barrel\" );\n\n\t\tCG_AddWeaponWithPowerups( &barrel, cent->currentState.powerups );\n\t}\n\n\t// make sure we aren't looking at cg.predictedPlayerEntity for LG\n\tnonPredictedCent = &cg_entities[cent->currentState.clientNum];\n\n\t// if the index of the nonPredictedCent is not the same as the clientNum\n\t// then this is a fake player (like on teh single player podiums), so\n\t// go ahead and use the cent\n\tif( ( nonPredictedCent - cg_entities ) != cent->currentState.clientNum ) {\n\t\tnonPredictedCent = cent;\n\t}\n\n\t// add the flash\n\tif ( ( weaponNum == WP_LIGHTNING || weaponNum == WP_GAUNTLET || weaponNum == WP_GRAPPLING_HOOK )\n\t\t&& ( nonPredictedCent->currentState.eFlags & EF_FIRING ) ) \n\t{\n\t\t// continuous flash\n\t} else {\n\t\t// impulse flash\n\t\tif ( cg.time - cent->muzzleFlashTime > MUZZLE_FLASH_TIME && !cent->pe.railgunFlash ) {\n\t\t\treturn;\n\t\t}\n\t}\n\n\tmemset( &flash, 0, sizeof( flash ) );\n\tVectorCopy( parent->lightingOrigin, flash.lightingOrigin );\n\tflash.shadowPlane = parent->shadowPlane;\n\tflash.renderfx = parent->renderfx;\n\n\tflash.hModel = weapon->flashModel;\n\tif (!flash.hModel) {\n\t\treturn;\n\t}\n\tangles[YAW] = 0;\n\tangles[PITCH] = 0;\n\tangles[ROLL] = crandom() * 10;\n\tAnglesToAxis( angles, flash.axis );\n\n\t// colorize the railgun blast\n\tif ( weaponNum == WP_RAILGUN ) {\n\t\tclientInfo_t\t*ci;\n\n\t\tci = &cgs.clientinfo[ cent->currentState.clientNum ];\n\t\tflash.shaderRGBA[0] = 255 * ci->color1[0];\n\t\tflash.shaderRGBA[1] = 255 * ci->color1[1];\n\t\tflash.shaderRGBA[2] = 255 * ci->color1[2];\n\t}\n\n\tCG_PositionRotatedEntityOnTag( &flash, &gun, weapon->weaponModel, \"tag_flash\");\n\ttrap_R_AddRefEntityToScene( &flash );\n\n\tif ( ps || cg.renderingThirdPerson ||\n\t\tcent->currentState.number != cg.predictedPlayerState.clientNum ) {\n\t\t// add lightning bolt\n\t\tCG_LightningBolt( nonPredictedCent, flash.origin );\n\n\t\t// add rail trail\n\t\tCG_SpawnRailTrail( cent, flash.origin );\n\n\t\tif ( weapon->flashDlightColor[0] || weapon->flashDlightColor[1] || weapon->flashDlightColor[2] ) {\n\t\t\ttrap_R_AddLightToScene( flash.origin, 300 + (rand()&31), weapon->flashDlightColor[0],\n\t\t\t\tweapon->flashDlightColor[1], weapon->flashDlightColor[2] );\n\t\t}\n\t}\n}\n\n/*\n==============\nCG_AddViewWeapon\n\nAdd the weapon, and flash for the player's view\n==============\n*/\nvoid CG_AddViewWeapon( playerState_t *ps ) {\n\trefEntity_t\thand;\n\tcentity_t\t*cent;\n\tclientInfo_t\t*ci;\n\tfloat\t\tfovOffset;\n\tvec3_t\t\tangles;\n\tweaponInfo_t\t*weapon;\n\n\tif ( ps->persistant[PERS_TEAM] == TEAM_SPECTATOR ) {\n\t\treturn;\n\t}\n\n\tif ( ps->pm_type == PM_INTERMISSION ) {\n\t\treturn;\n\t}\n\n\t// no gun if in third person view or a camera is active\n\t//if ( cg.renderingThirdPerson || cg.cameraMode) {\n\tif ( cg.renderingThirdPerson ) {\n\t\treturn;\n\t}\n\n\n\t// allow the gun to be completely removed\n\tif ( !cg_drawGun.integer ) {\n\t\tvec3_t\t\torigin;\n\n\t\tif ( cg.predictedPlayerState.eFlags & EF_FIRING ) {\n\t\t\t// special hack for lightning gun...\n\t\t\tVectorCopy( cg.refdef.vieworg, origin );\n\t\t\tVectorMA( origin, -8, cg.refdef.viewaxis[2], origin );\n\t\t\tCG_LightningBolt( &cg_entities[ps->clientNum], origin );\n\t\t}\n\t\treturn;\n\t}\n\n\t// don't draw if testing a gun model\n\tif ( cg.testGun ) {\n\t\treturn;\n\t}\n\n\t// drop gun lower at higher fov\n\tif ( cg_fov.integer > 90 ) {\n\t\tfovOffset = -0.2 * ( cg_fov.integer - 90 );\n\t} else {\n\t\tfovOffset = 0;\n\t}\n\n\tcent = &cg.predictedPlayerEntity;\t// &cg_entities[cg.snap->ps.clientNum];\n\tCG_RegisterWeapon( ps->weapon );\n\tweapon = &cg_weapons[ ps->weapon ];\n\n\tmemset (&hand, 0, sizeof(hand));\n\n\t// set up gun position\n\tCG_CalculateWeaponPosition( hand.origin, angles );\n\n\tVectorMA( hand.origin, cg_gun_x.value, cg.refdef.viewaxis[0], hand.origin );\n\tVectorMA( hand.origin, cg_gun_y.value, cg.refdef.viewaxis[1], hand.origin );\n\tVectorMA( hand.origin, (cg_gun_z.value+fovOffset), cg.refdef.viewaxis[2], hand.origin );\n\n\tAnglesToAxis( angles, hand.axis );\n\n\t// map torso animations to weapon animations\n\tif ( cg_gun_frame.integer ) {\n\t\t// development tool\n\t\thand.frame = hand.oldframe = cg_gun_frame.integer;\n\t\thand.backlerp = 0;\n\t} else {\n\t\t// get clientinfo for animation map\n\t\tci = &cgs.clientinfo[ cent->currentState.clientNum ];\n\t\thand.frame = CG_MapTorsoToWeaponFrame( ci, cent->pe.torso.frame );\n\t\thand.oldframe = CG_MapTorsoToWeaponFrame( ci, cent->pe.torso.oldFrame );\n\t\thand.backlerp = cent->pe.torso.backlerp;\n\t}\n\n\thand.hModel = weapon->handsModel;\n\thand.renderfx = RF_DEPTHHACK | RF_FIRST_PERSON | RF_MINLIGHT;\n\n\t// add everything onto the hand\n\tCG_AddPlayerWeapon( &hand, ps, &cg.predictedPlayerEntity, ps->persistant[PERS_TEAM] );\n}\n\n/*\n==============================================================================\n\nWEAPON SELECTION\n\n==============================================================================\n*/\n\n/*\n===================\nCG_DrawWeaponSelect\n===================\n*/\nvoid CG_DrawWeaponSelect( void ) {\n\tint\t\ti;\n\tint\t\tbits;\n\tint\t\tcount;\n\tint\t\tx, y, w;\n\tchar\t*name;\n\tfloat\t*color;\n\n\t// don't display if dead\n\tif ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) {\n\t\treturn;\n\t}\n\n\tcolor = CG_FadeColor( cg.weaponSelectTime, WEAPON_SELECT_TIME );\n\tif ( !color ) {\n\t\treturn;\n\t}\n\ttrap_R_SetColor( color );\n\n\t// showing weapon select clears pickup item display, but not the blend blob\n\tcg.itemPickupTime = 0;\n\n\t// count the number of weapons owned\n\tbits = cg.snap->ps.stats[ STAT_WEAPONS ];\n\tcount = 0;\n\tfor ( i = 1 ; i < 16 ; i++ ) {\n\t\tif ( bits & ( 1 << i ) ) {\n\t\t\tcount++;\n\t\t}\n\t}\n\n\tx = 320 - count * 20;\n\ty = 380;\n\n\tfor ( i = 1 ; i < 16 ; i++ ) {\n\t\tif ( !( bits & ( 1 << i ) ) ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tCG_RegisterWeapon( i );\n\n\t\t// draw weapon icon\n\t\tCG_DrawPic( x, y, 32, 32, cg_weapons[i].weaponIcon );\n\n\t\t// draw selection marker\n\t\tif ( i == cg.weaponSelect ) {\n\t\t\tCG_DrawPic( x-4, y-4, 40, 40, cgs.media.selectShader );\n\t\t}\n\n\t\t// no ammo cross on top\n\t\tif ( !cg.snap->ps.ammo[ i ] ) {\n\t\t\tCG_DrawPic( x, y, 32, 32, cgs.media.noammoShader );\n\t\t}\n\n\t\tx += 40;\n\t}\n\n\t// draw the selected name\n\tif ( cg_weapons[ cg.weaponSelect ].item ) {\n\t\tname = cg_weapons[ cg.weaponSelect ].item->pickup_name;\n\t\tif ( name ) {\n\t\t\tw = CG_DrawStrlen( name ) * BIGCHAR_WIDTH;\n\t\t\tx = ( SCREEN_WIDTH - w ) / 2;\n\t\t\tCG_DrawBigStringColor(x, y - 22, name, color);\n\t\t}\n\t}\n\n\ttrap_R_SetColor( NULL );\n}\n\n\n/*\n===============\nCG_WeaponSelectable\n===============\n*/\nstatic qboolean CG_WeaponSelectable( int i ) {\n\tif ( !cg.snap->ps.ammo[i] ) {\n\t\treturn qfalse;\n\t}\n\tif ( ! (cg.snap->ps.stats[ STAT_WEAPONS ] & ( 1 << i ) ) ) {\n\t\treturn qfalse;\n\t}\n\n\treturn qtrue;\n}\n\n/*\n===============\nCG_NextWeapon_f\n===============\n*/\nvoid CG_NextWeapon_f( void ) {\n\tint\t\ti;\n\tint\t\toriginal;\n\n\tif ( !cg.snap ) {\n\t\treturn;\n\t}\n\tif ( cg.snap->ps.pm_flags & PMF_FOLLOW ) {\n\t\treturn;\n\t}\n\n\tcg.weaponSelectTime = cg.time;\n\toriginal = cg.weaponSelect;\n\n\tfor ( i = 0 ; i < 16 ; i++ ) {\n\t\tcg.weaponSelect++;\n\t\tif ( cg.weaponSelect == 16 ) {\n\t\t\tcg.weaponSelect = 0;\n\t\t}\n\t\tif ( cg.weaponSelect == WP_GAUNTLET ) {\n\t\t\tcontinue;\t\t// never cycle to gauntlet\n\t\t}\n\t\tif ( CG_WeaponSelectable( cg.weaponSelect ) ) {\n\t\t\tbreak;\n\t\t}\n\t}\n\tif ( i == 16 ) {\n\t\tcg.weaponSelect = original;\n\t}\n}\n\n/*\n===============\nCG_PrevWeapon_f\n===============\n*/\nvoid CG_PrevWeapon_f( void ) {\n\tint\t\ti;\n\tint\t\toriginal;\n\n\tif ( !cg.snap ) {\n\t\treturn;\n\t}\n\tif ( cg.snap->ps.pm_flags & PMF_FOLLOW ) {\n\t\treturn;\n\t}\n\n\tcg.weaponSelectTime = cg.time;\n\toriginal = cg.weaponSelect;\n\n\tfor ( i = 0 ; i < 16 ; i++ ) {\n\t\tcg.weaponSelect--;\n\t\tif ( cg.weaponSelect == -1 ) {\n\t\t\tcg.weaponSelect = 15;\n\t\t}\n\t\tif ( cg.weaponSelect == WP_GAUNTLET ) {\n\t\t\tcontinue;\t\t// never cycle to gauntlet\n\t\t}\n\t\tif ( CG_WeaponSelectable( cg.weaponSelect ) ) {\n\t\t\tbreak;\n\t\t}\n\t}\n\tif ( i == 16 ) {\n\t\tcg.weaponSelect = original;\n\t}\n}\n\n/*\n===============\nCG_Weapon_f\n===============\n*/\nvoid CG_Weapon_f( void ) {\n\tint\t\tnum;\n\n\tif ( !cg.snap ) {\n\t\treturn;\n\t}\n\tif ( cg.snap->ps.pm_flags & PMF_FOLLOW ) {\n\t\treturn;\n\t}\n\n\tnum = atoi( CG_Argv( 1 ) );\n\n\tif ( num < 1 || num > 15 ) {\n\t\treturn;\n\t}\n\n\tcg.weaponSelectTime = cg.time;\n\n\tif ( ! ( cg.snap->ps.stats[STAT_WEAPONS] & ( 1 << num ) ) ) {\n\t\treturn;\t\t// don't have the weapon\n\t}\n\n\tcg.weaponSelect = num;\n}\n\n/*\n===================\nCG_OutOfAmmoChange\n\nThe current weapon has just run out of ammo\n===================\n*/\nvoid CG_OutOfAmmoChange( void ) {\n\tint\t\ti;\n\n\tcg.weaponSelectTime = cg.time;\n\n\tfor ( i = 15 ; i > 0 ; i-- ) {\n\t\tif ( CG_WeaponSelectable( i ) ) {\n\t\t\tcg.weaponSelect = i;\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\n\n\n/*\n===================================================================================================\n\nWEAPON EVENTS\n\n===================================================================================================\n*/\n\n/*\n================\nCG_FireWeapon\n\nCaused by an EV_FIRE_WEAPON event\n================\n*/\nvoid CG_FireWeapon( centity_t *cent ) {\n\tentityState_t *ent;\n\tint\t\t\t\tc;\n\tweaponInfo_t\t*weap;\n\n\tent = &cent->currentState;\n\tif ( ent->weapon == WP_NONE ) {\n\t\treturn;\n\t}\n\tif ( ent->weapon >= WP_NUM_WEAPONS ) {\n\t\tCG_Error( \"CG_FireWeapon: ent->weapon >= WP_NUM_WEAPONS\" );\n\t\treturn;\n\t}\n\tweap = &cg_weapons[ ent->weapon ];\n\n\t// mark the entity as muzzle flashing, so when it is added it will\n\t// append the flash to the weapon model\n\tcent->muzzleFlashTime = cg.time;\n\n\t// lightning gun only does this this on initial press\n\tif ( ent->weapon == WP_LIGHTNING ) {\n\t\tif ( cent->pe.lightningFiring ) {\n\t\t\treturn;\n\t\t}\n\t}\n\n\t// play quad sound if needed\n\tif ( cent->currentState.powerups & ( 1 << PW_QUAD ) ) {\n\t\ttrap_S_StartSound (NULL, cent->currentState.number, CHAN_ITEM, cgs.media.quadSound );\n\t}\n\n\t// play a sound\n\tfor ( c = 0 ; c < 4 ; c++ ) {\n\t\tif ( !weap->flashSound[c] ) {\n\t\t\tbreak;\n\t\t}\n\t}\n\tif ( c > 0 ) {\n\t\tc = rand() % c;\n\t\tif ( weap->flashSound[c] )\n\t\t{\n\t\t\ttrap_S_StartSound( NULL, ent->number, CHAN_WEAPON, weap->flashSound[c] );\n\t\t}\n\t}\n\n\t// do brass ejection\n\tif ( weap->ejectBrassFunc && cg_brassTime.integer > 0 ) {\n\t\tweap->ejectBrassFunc( cent );\n\t}\n}\n\n\n/*\n=================\nCG_MissileHitWall\n\nCaused by an EV_MISSILE_MISS event, or directly by local bullet tracing\n=================\n*/\nvoid CG_MissileHitWall( int weapon, int clientNum, vec3_t origin, vec3_t dir, impactSound_t soundType ) {\n\tqhandle_t\t\tmod;\n\tqhandle_t\t\tmark;\n\tqhandle_t\t\tshader;\n\tsfxHandle_t\t\tsfx;\n\tfloat\t\t\tradius;\n\tfloat\t\t\tlight;\n\tvec3_t\t\t\tlightColor;\n\tlocalEntity_t\t*le;\n\tint\t\t\t\tr;\n\tqboolean\t\talphaFade;\n\tqboolean\t\tisSprite;\n\tint\t\t\t\tduration;\n\tvec3_t\t\t\tsprOrg;\n\tvec3_t\t\t\tsprVel;\n\n\tmark = 0;\n\tradius = 32;\n\tsfx = 0;\n\tmod = 0;\n\tshader = 0;\n\tlight = 0;\n\tlightColor[0] = 1;\n\tlightColor[1] = 1;\n\tlightColor[2] = 0;\n\n\t// set defaults\n\tisSprite = qfalse;\n\tduration = 600;\n\n\tswitch ( weapon ) {\n\tdefault:\n\tcase WP_LIGHTNING:\n\t\t// no explosion at LG impact, it is added with the beam\n\t\tr = rand() & 3;\n\t\tif ( r < 2 ) {\n\t\t\tsfx = cgs.media.sfx_lghit2;\n\t\t} else if ( r == 2 ) {\n\t\t\tsfx = cgs.media.sfx_lghit1;\n\t\t} else {\n\t\t\tsfx = cgs.media.sfx_lghit3;\n\t\t}\n\t\tmark = cgs.media.holeMarkShader;\n\t\tradius = 12;\n\t\tbreak;\n\tcase WP_GRENADE_LAUNCHER:\n\t\tmod = cgs.media.dishFlashModel;\n\t\tshader = cgs.media.grenadeExplosionShader;\n\t\tsfx = cgs.media.sfx_rockexp;\n\t\tmark = cgs.media.burnMarkShader;\n\t\tradius = 64;\n\t\tlight = 300;\n\t\tisSprite = qtrue;\n\t\tbreak;\n\tcase WP_ROCKET_LAUNCHER:\n\t\tmod = cgs.media.dishFlashModel;\n\t\tshader = cgs.media.rocketExplosionShader;\n\t\tsfx = cgs.media.sfx_rockexp;\n\t\tmark = cgs.media.burnMarkShader;\n\t\tradius = 64;\n\t\tlight = 300;\n\t\tisSprite = qtrue;\n\t\tduration = 1000;\n\t\tlightColor[0] = 1;\n\t\tlightColor[1] = 0.75;\n\t\tlightColor[2] = 0.0;\n\t\tif (cg_oldRocket.integer == 0) {\n\t\t\t// explosion sprite animation\n\t\t\tVectorMA( origin, 24, dir, sprOrg );\n\t\t\tVectorScale( dir, 64, sprVel );\n\n\t\t\tCG_ParticleExplosion( \"explode1\", sprOrg, sprVel, 1400, 20, 30 );\n\t\t}\n\t\tbreak;\n\tcase WP_RAILGUN:\n\t\tmod = cgs.media.ringFlashModel;\n\t\tshader = cgs.media.railExplosionShader;\n\t\tsfx = cgs.media.sfx_plasmaexp;\n\t\tmark = cgs.media.energyMarkShader;\n\t\tradius = 24;\n\t\tbreak;\n\tcase WP_PLASMAGUN:\n\t\tmod = cgs.media.ringFlashModel;\n\t\tshader = cgs.media.plasmaExplosionShader;\n\t\tsfx = cgs.media.sfx_plasmaexp;\n\t\tmark = cgs.media.energyMarkShader;\n\t\tradius = 16;\n\t\tbreak;\n\tcase WP_BFG:\n\t\tmod = cgs.media.dishFlashModel;\n\t\tshader = cgs.media.bfgExplosionShader;\n\t\tsfx = cgs.media.sfx_rockexp;\n\t\tmark = cgs.media.burnMarkShader;\n\t\tradius = 32;\n\t\tisSprite = qtrue;\n\t\tbreak;\n\tcase WP_SHOTGUN:\n\t\tmod = cgs.media.bulletFlashModel;\n\t\tshader = cgs.media.bulletExplosionShader;\n\t\tmark = cgs.media.bulletMarkShader;\n\t\tsfx = 0;\n\t\tradius = 4;\n\t\tbreak;\n\tcase WP_MACHINEGUN:\n\t\tmod = cgs.media.bulletFlashModel;\n\t\tshader = cgs.media.bulletExplosionShader;\n\t\tmark = cgs.media.bulletMarkShader;\n\n\t\tr = rand() & 3;\n\t\tif ( r == 0 ) {\n\t\t\tsfx = cgs.media.sfx_ric1;\n\t\t} else if ( r == 1 ) {\n\t\t\tsfx = cgs.media.sfx_ric2;\n\t\t} else {\n\t\t\tsfx = cgs.media.sfx_ric3;\n\t\t}\n\n\t\tradius = 8;\n\t\tbreak;\n\t}\n\n\tif ( sfx ) {\n\t\ttrap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, sfx );\n\t}\n\n\t//\n\t// create the explosion\n\t//\n\tif ( mod ) {\n\t\tle = CG_MakeExplosion( origin, dir, \n\t\t\t\t\t\t\t   mod,\tshader,\n\t\t\t\t\t\t\t   duration, isSprite );\n\t\tle->light = light;\n\t\tVectorCopy( lightColor, le->lightColor );\n\t\tif ( weapon == WP_RAILGUN ) {\n\t\t\t// colorize with client color\n\t\t\tVectorCopy( cgs.clientinfo[clientNum].color1, le->color );\n\t\t}\n\t}\n\n\t//\n\t// impact mark\n\t//\n\talphaFade = (mark == cgs.media.energyMarkShader);\t// plasma fades alpha, all others fade color\n\tif ( weapon == WP_RAILGUN ) {\n\t\tfloat\t*color;\n\n\t\t// colorize with client color\n\t\tcolor = cgs.clientinfo[clientNum].color2;\n\t\tCG_ImpactMark( mark, origin, dir, random()*360, color[0],color[1], color[2],1, alphaFade, radius, qfalse );\n\t} else {\n\t\tCG_ImpactMark( mark, origin, dir, random()*360, 1,1,1,1, alphaFade, radius, qfalse );\n\t}\n}\n\n\n/*\n=================\nCG_MissileHitPlayer\n=================\n*/\nvoid CG_MissileHitPlayer( int weapon, vec3_t origin, vec3_t dir, int entityNum ) {\n\tCG_Bleed( origin, entityNum );\n\n\t// some weapons will make an explosion with the blood, while\n\t// others will just make the blood\n\tswitch ( weapon ) {\n\tcase WP_GRENADE_LAUNCHER:\n\tcase WP_ROCKET_LAUNCHER:\n\t\tCG_MissileHitWall( weapon, 0, origin, dir, IMPACTSOUND_FLESH );\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n}\n\n\n\n/*\n============================================================================\n\nSHOTGUN TRACING\n\n============================================================================\n*/\n\n/*\n================\nCG_ShotgunPellet\n================\n*/\nstatic void CG_ShotgunPellet( vec3_t start, vec3_t end, int skipNum ) {\n\ttrace_t\t\ttr;\n\tint sourceContentType, destContentType;\n\n\tCG_Trace( &tr, start, NULL, NULL, end, skipNum, MASK_SHOT );\n\n\tsourceContentType = trap_CM_PointContents( start, 0 );\n\tdestContentType = trap_CM_PointContents( tr.endpos, 0 );\n\n\t// FIXME: should probably move this cruft into CG_BubbleTrail\n\tif ( sourceContentType == destContentType ) {\n\t\tif ( sourceContentType & CONTENTS_WATER ) {\n\t\t\tCG_BubbleTrail( start, tr.endpos, 32 );\n\t\t}\n\t} else if ( sourceContentType & CONTENTS_WATER ) {\n\t\ttrace_t trace;\n\n\t\ttrap_CM_BoxTrace( &trace, end, start, NULL, NULL, 0, CONTENTS_WATER );\n\t\tCG_BubbleTrail( start, trace.endpos, 32 );\n\t} else if ( destContentType & CONTENTS_WATER ) {\n\t\ttrace_t trace;\n\n\t\ttrap_CM_BoxTrace( &trace, start, end, NULL, NULL, 0, CONTENTS_WATER );\n\t\tCG_BubbleTrail( tr.endpos, trace.endpos, 32 );\n\t}\n\n\tif (  tr.surfaceFlags & SURF_NOIMPACT ) {\n\t\treturn;\n\t}\n\n\tif ( cg_entities[tr.entityNum].currentState.eType == ET_PLAYER ) {\n\t\tCG_MissileHitPlayer( WP_SHOTGUN, tr.endpos, tr.plane.normal, tr.entityNum );\n\t} else {\n\t\tif ( tr.surfaceFlags & SURF_NOIMPACT ) {\n\t\t\t// SURF_NOIMPACT will not make a flame puff or a mark\n\t\t\treturn;\n\t\t}\n\t\tif ( tr.surfaceFlags & SURF_METALSTEPS ) {\n\t\t\tCG_MissileHitWall( WP_SHOTGUN, 0, tr.endpos, tr.plane.normal, IMPACTSOUND_METAL );\n\t\t} else {\n\t\t\tCG_MissileHitWall( WP_SHOTGUN, 0, tr.endpos, tr.plane.normal, IMPACTSOUND_DEFAULT );\n\t\t}\n\t}\n}\n\n/*\n================\nCG_ShotgunPattern\n\nPerform the same traces the server did to locate the\nhit splashes\n================\n*/\nstatic void CG_ShotgunPattern( vec3_t origin, vec3_t origin2, int seed, int otherEntNum ) {\n\tint\t\t\ti;\n\tfloat\t\tr, u;\n\tvec3_t\t\tend;\n\tvec3_t\t\tforward, right, up;\n\n\t// derive the right and up vectors from the forward vector, because\n\t// the client won't have any other information\n\tVectorNormalize2( origin2, forward );\n\tPerpendicularVector( right, forward );\n\tCrossProduct( forward, right, up );\n\n\t// generate the \"random\" spread pattern\n\tfor ( i = 0 ; i < DEFAULT_SHOTGUN_COUNT ; i++ ) {\n\t\tr = Q_crandom( &seed ) * DEFAULT_SHOTGUN_SPREAD * 16;\n\t\tu = Q_crandom( &seed ) * DEFAULT_SHOTGUN_SPREAD * 16;\n\t\tVectorMA( origin, 8192 * 16, forward, end);\n\t\tVectorMA (end, r, right, end);\n\t\tVectorMA (end, u, up, end);\n\n\t\tCG_ShotgunPellet( origin, end, otherEntNum );\n\t}\n}\n\n/*\n==============\nCG_ShotgunFire\n==============\n*/\nvoid CG_ShotgunFire( entityState_t *es ) {\n\tvec3_t\tv;\n\tvec3_t\tup;\n\tint\t\tcontents;\n\n\tVectorSubtract( es->origin2, es->pos.trBase, v );\n\tVectorNormalize( v );\n\tVectorScale( v, 32, v );\n\tVectorAdd( es->pos.trBase, v, v );\n\t\n\tcontents = trap_CM_PointContents( es->pos.trBase, 0 );\n\tif ( !( contents & CONTENTS_WATER ) ) {\n\t\tVectorSet( up, 0, 0, 8 );\n\t\tCG_SmokePuff( v, up, 32, 1, 1, 1, 0.33f, 900, cg.time, 0, LEF_PUFF_DONT_SCALE, cgs.media.shotgunSmokePuffShader );\n\t}\n\tCG_ShotgunPattern( es->pos.trBase, es->origin2, es->eventParm, es->otherEntityNum );\n}\n\n/*\n============================================================================\n\nBULLETS\n\n============================================================================\n*/\n\n\n/*\n===============\nCG_Tracer\n===============\n*/\nvoid CG_Tracer( vec3_t source, vec3_t dest ) {\n\tvec3_t\t\tforward, right;\n\tpolyVert_t\tverts[4];\n\tvec3_t\t\tline;\n\tfloat\t\tlen, begin, end;\n\tvec3_t\t\tstart, finish;\n\tvec3_t\t\tmidpoint;\n\n\t// tracer\n\tVectorSubtract( dest, source, forward );\n\tlen = VectorNormalize( forward );\n\n\t// start at least a little ways from the muzzle\n\tif ( len < 100 ) {\n\t\treturn;\n\t}\n\tbegin = 50 + random() * (len - 60);\n\tend = begin + cg_tracerLength.value;\n\tif ( end > len ) {\n\t\tend = len;\n\t}\n\tVectorMA( source, begin, forward, start );\n\tVectorMA( source, end, forward, finish );\n\n\tline[0] = DotProduct( forward, cg.refdef.viewaxis[1] );\n\tline[1] = DotProduct( forward, cg.refdef.viewaxis[2] );\n\n\tVectorScale( cg.refdef.viewaxis[1], line[1], right );\n\tVectorMA( right, -line[0], cg.refdef.viewaxis[2], right );\n\tVectorNormalize( right );\n\n\tVectorMA( finish, cg_tracerWidth.value, right, verts[0].xyz );\n\tverts[0].st[0] = 0;\n\tverts[0].st[1] = 1;\n\tverts[0].modulate[0] = 255;\n\tverts[0].modulate[1] = 255;\n\tverts[0].modulate[2] = 255;\n\tverts[0].modulate[3] = 255;\n\n\tVectorMA( finish, -cg_tracerWidth.value, right, verts[1].xyz );\n\tverts[1].st[0] = 1;\n\tverts[1].st[1] = 0;\n\tverts[1].modulate[0] = 255;\n\tverts[1].modulate[1] = 255;\n\tverts[1].modulate[2] = 255;\n\tverts[1].modulate[3] = 255;\n\n\tVectorMA( start, -cg_tracerWidth.value, right, verts[2].xyz );\n\tverts[2].st[0] = 1;\n\tverts[2].st[1] = 1;\n\tverts[2].modulate[0] = 255;\n\tverts[2].modulate[1] = 255;\n\tverts[2].modulate[2] = 255;\n\tverts[2].modulate[3] = 255;\n\n\tVectorMA( start, cg_tracerWidth.value, right, verts[3].xyz );\n\tverts[3].st[0] = 0;\n\tverts[3].st[1] = 0;\n\tverts[3].modulate[0] = 255;\n\tverts[3].modulate[1] = 255;\n\tverts[3].modulate[2] = 255;\n\tverts[3].modulate[3] = 255;\n\n\ttrap_R_AddPolyToScene( cgs.media.tracerShader, 4, verts );\n\n\tmidpoint[0] = ( start[0] + finish[0] ) * 0.5;\n\tmidpoint[1] = ( start[1] + finish[1] ) * 0.5;\n\tmidpoint[2] = ( start[2] + finish[2] ) * 0.5;\n\n\t// add the tracer sound\n\ttrap_S_StartSound( midpoint, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.tracerSound );\n\n}\n\n\n/*\n======================\nCG_CalcMuzzlePoint\n======================\n*/\nstatic qboolean\tCG_CalcMuzzlePoint( int entityNum, vec3_t muzzle ) {\n\tvec3_t\t\tforward;\n\tcentity_t\t*cent;\n\tint\t\t\tanim;\n\n\tif ( entityNum == cg.snap->ps.clientNum ) {\n\t\tVectorCopy( cg.snap->ps.origin, muzzle );\n\t\tmuzzle[2] += cg.snap->ps.viewheight;\n\t\tAngleVectors( cg.snap->ps.viewangles, forward, NULL, NULL );\n\t\tVectorMA( muzzle, 14, forward, muzzle );\n\t\treturn qtrue;\n\t}\n\n\tcent = &cg_entities[entityNum];\n\tif ( !cent->currentValid ) {\n\t\treturn qfalse;\n\t}\n\n\tVectorCopy( cent->currentState.pos.trBase, muzzle );\n\n\tAngleVectors( cent->currentState.apos.trBase, forward, NULL, NULL );\n\tanim = cent->currentState.legsAnim & ~ANIM_TOGGLEBIT;\n\tif ( anim == LEGS_WALKCR || anim == LEGS_IDLECR ) {\n\t\tmuzzle[2] += CROUCH_VIEWHEIGHT;\n\t} else {\n\t\tmuzzle[2] += DEFAULT_VIEWHEIGHT;\n\t}\n\n\tVectorMA( muzzle, 14, forward, muzzle );\n\n\treturn qtrue;\n\n}\n\n/*\n======================\nCG_Bullet\n\nRenders bullet effects.\n======================\n*/\nvoid CG_Bullet( vec3_t end, int sourceEntityNum, vec3_t normal, qboolean flesh, int fleshEntityNum ) {\n\ttrace_t trace;\n\tint sourceContentType, destContentType;\n\tvec3_t\t\tstart;\n\n\t// if the shooter is currently valid, calc a source point and possibly\n\t// do trail effects\n\tif ( sourceEntityNum >= 0 && cg_tracerChance.value > 0 ) {\n\t\tif ( CG_CalcMuzzlePoint( sourceEntityNum, start ) ) {\n\t\t\tsourceContentType = trap_CM_PointContents( start, 0 );\n\t\t\tdestContentType = trap_CM_PointContents( end, 0 );\n\n\t\t\t// do a complete bubble trail if necessary\n\t\t\tif ( ( sourceContentType == destContentType ) && ( sourceContentType & CONTENTS_WATER ) ) {\n\t\t\t\tCG_BubbleTrail( start, end, 32 );\n\t\t\t}\n\t\t\t// bubble trail from water into air\n\t\t\telse if ( ( sourceContentType & CONTENTS_WATER ) ) {\n\t\t\t\ttrap_CM_BoxTrace( &trace, end, start, NULL, NULL, 0, CONTENTS_WATER );\n\t\t\t\tCG_BubbleTrail( start, trace.endpos, 32 );\n\t\t\t}\n\t\t\t// bubble trail from air into water\n\t\t\telse if ( ( destContentType & CONTENTS_WATER ) ) {\n\t\t\t\ttrap_CM_BoxTrace( &trace, start, end, NULL, NULL, 0, CONTENTS_WATER );\n\t\t\t\tCG_BubbleTrail( trace.endpos, end, 32 );\n\t\t\t}\n\n\t\t\t// draw a tracer\n\t\t\tif ( random() < cg_tracerChance.value ) {\n\t\t\t\tCG_Tracer( start, end );\n\t\t\t}\n\t\t}\n\t}\n\n\t// impact splash and mark\n\tif ( flesh ) {\n\t\tCG_Bleed( end, fleshEntityNum );\n\t} else {\n\t\tCG_MissileHitWall( WP_MACHINEGUN, 0, end, normal, IMPACTSOUND_DEFAULT );\n\t}\n\n}\n"
  },
  {
    "path": "src/cgame/cgame.bat",
    "content": "rem make sure we have a safe environement\nset LIBRARY=\nset INCLUDE=\n\nmkdir ..\\..\\intermediate\\vm\\cgame\ncd ..\\..\\intermediate\\vm\\cgame\n\nset PATH=..\\..\\..\\tools\\bin;%PATH%\n\nset src=..\\..\\..\\source\nset cc=lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I%src%\\cgame -I%src%\\game -I%src%\\ui %1\n\n%cc% %src%/game/bg_misc.c\n@if errorlevel 1 goto quit\n%cc% %src%/game/bg_pmove.c\n@if errorlevel 1 goto quit\n%cc% %src%/game/bg_slidemove.c\n@if errorlevel 1 goto quit\n%cc% %src%/game/bg_lib.c\n@if errorlevel 1 goto quit\n%cc% %src%/game/q_math.c\n@if errorlevel 1 goto quit\n%cc% %src%/game/q_shared.c\n@if errorlevel 1 goto quit\n%cc% %src%/cgame/cg_consolecmds.c\n@if errorlevel 1 goto quit\n%cc% %src%/cgame/cg_draw.c\n@if errorlevel 1 goto quit\n%cc% %src%/cgame/cg_drawtools.c\n@if errorlevel 1 goto quit\n%cc% %src%/cgame/cg_effects.c\n@if errorlevel 1 goto quit\n%cc% %src%/cgame/cg_ents.c\n@if errorlevel 1 goto quit\n%cc% %src%/cgame/cg_event.c\n@if errorlevel 1 goto quit\n%cc% %src%/cgame/cg_info.c\n@if errorlevel 1 goto quit\n%cc% %src%/cgame/cg_localents.c\n@if errorlevel 1 goto quit\n%cc% %src%/cgame/cg_main.c\n@if errorlevel 1 goto quit\n%cc% %src%/cgame/cg_marks.c\n@if errorlevel 1 goto quit\n%cc% %src%/cgame/cg_players.c\n@if errorlevel 1 goto quit\n%cc% %src%/cgame/cg_playerstate.c\n@if errorlevel 1 goto quit\n%cc% %src%/cgame/cg_predict.c\n@if errorlevel 1 goto quit\n%cc% %src%/cgame/cg_scoreboard.c\n@if errorlevel 1 goto quit\n%cc% %src%/cgame/cg_servercmds.c\n@if errorlevel 1 goto quit\n%cc% %src%/cgame/cg_snapshot.c\n@if errorlevel 1 goto quit\n%cc% %src%/cgame/cg_view.c\n@if errorlevel 1 goto quit\n%cc% %src%/cgame/cg_weapons.c\n@if errorlevel 1 goto quit\n\nq3asm -f %src%/cgame/cgame\n:quit\ncd %src%/cgame\n"
  },
  {
    "path": "src/cgame/cgame.q3asm",
    "content": "-o \"..\\..\\..\\binaries\\vm\\cgame.qvm\"\ncg_main\n..\\..\\..\\source\\cgame\\cg_syscalls\ncg_consolecmds\ncg_draw\ncg_drawtools\ncg_effects\ncg_ents\ncg_event\ncg_info\ncg_localents\ncg_marks\ncg_players\ncg_playerstate\ncg_predict\ncg_scoreboard\ncg_servercmds\ncg_snapshot\ncg_view\ncg_weapons\nbg_slidemove\nbg_pmove\nbg_lib\nbg_misc\nq_math\nq_shared\n"
  },
  {
    "path": "src/cgame/tr_types.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n#ifndef __TR_TYPES_H\n#define __TR_TYPES_H\n\n\n#define\tMAX_DLIGHTS\t\t32\t\t\t// can't be increased, because bit flags are used on surfaces\n#define\tMAX_ENTITIES\t1023\t\t// can't be increased without changing drawsurf bit packing\n\n// renderfx flags\n#define\tRF_MINLIGHT\t\t\t1\t\t// allways have some light (viewmodel, some items)\n#define\tRF_THIRD_PERSON\t\t2\t\t// don't draw through eyes, only mirrors (player bodies, chat sprites)\n#define\tRF_FIRST_PERSON\t\t4\t\t// only draw through eyes (view weapon, damage blood blob)\n#define\tRF_DEPTHHACK\t\t8\t\t// for view weapon Z crunching\n#define\tRF_NOSHADOW\t\t\t64\t\t// don't add stencil shadows\n\n#define RF_LIGHTING_ORIGIN\t128\t\t// use refEntity->lightingOrigin instead of refEntity->origin\n\t\t\t\t\t\t\t\t\t// for lighting.  This allows entities to sink into the floor\n\t\t\t\t\t\t\t\t\t// with their origin going solid, and allows all parts of a\n\t\t\t\t\t\t\t\t\t// player to get the same lighting\n#define\tRF_SHADOW_PLANE\t\t256\t\t// use refEntity->shadowPlane\n#define\tRF_WRAP_FRAMES\t\t512\t\t// mod the model frames by the maxframes to allow continuous\n\t\t\t\t\t\t\t\t\t// animation without needing to know the frame count\n\n// refdef flags\n#define RDF_NOWORLDMODEL\t1\t\t// used for player configuration screen\n#define RDF_HYPERSPACE\t\t4\t\t// teleportation effect\n\ntypedef struct {\n\tvec3_t\t\txyz;\n\tfloat\t\tst[2];\n\tbyte\t\tmodulate[4];\n} polyVert_t;\n\ntypedef struct poly_s {\n\tqhandle_t\t\t\thShader;\n\tint\t\t\t\t\tnumVerts;\n\tpolyVert_t\t\t\t*verts;\n} poly_t;\n\ntypedef enum {\n\tRT_MODEL,\n\tRT_POLY,\n\tRT_SPRITE,\n\tRT_BEAM,\n\tRT_RAIL_CORE,\n\tRT_RAIL_RINGS,\n\tRT_LIGHTNING,\n\tRT_PORTALSURFACE,\t\t// doesn't draw anything, just info for portals\n\n\tRT_MAX_REF_ENTITY_TYPE\n} refEntityType_t;\n\ntypedef struct {\n\trefEntityType_t\treType;\n\tint\t\t\trenderfx;\n\n\tqhandle_t\thModel;\t\t\t\t// opaque type outside refresh\n\n\t// most recent data\n\tvec3_t\t\tlightingOrigin;\t\t// so multi-part models can be lit identically (RF_LIGHTING_ORIGIN)\n\tfloat\t\tshadowPlane;\t\t// projection shadows go here, stencils go slightly lower\n\n\tvec3_t\t\taxis[3];\t\t\t// rotation vectors\n\tqboolean\tnonNormalizedAxes;\t// axis are not normalized, i.e. they have scale\n\tfloat\t\torigin[3];\t\t\t// also used as MODEL_BEAM's \"from\"\n\tint\t\t\tframe;\t\t\t\t// also used as MODEL_BEAM's diameter\n\n\t// previous data for frame interpolation\n\tfloat\t\toldorigin[3];\t\t// also used as MODEL_BEAM's \"to\"\n\tint\t\t\toldframe;\n\tfloat\t\tbacklerp;\t\t\t// 0.0 = current, 1.0 = old\n\n\t// texturing\n\tint\t\t\tskinNum;\t\t\t// inline skin index\n\tqhandle_t\tcustomSkin;\t\t\t// NULL for default skin\n\tqhandle_t\tcustomShader;\t\t// use one image for the entire thing\n\n\t// misc\n\tbyte\t\tshaderRGBA[4];\t\t// colors used by rgbgen entity shaders\n\tfloat\t\tshaderTexCoord[2];\t// texture coordinates used by tcMod entity modifiers\n\tfloat\t\tshaderTime;\t\t\t// subtracted from refdef time to control effect start times\n\n\t// extra sprite information\n\tfloat\t\tradius;\n\tfloat\t\trotation;\n} refEntity_t;\n\n\n#define\tMAX_RENDER_STRINGS\t\t\t8\n#define\tMAX_RENDER_STRING_LENGTH\t32\n\ntypedef struct {\n\tint\t\t\tx, y, width, height;\n\tfloat\t\tfov_x, fov_y;\n\tvec3_t\t\tvieworg;\n\tvec3_t\t\tviewaxis[3];\t\t// transformation matrix\n\n\t// time in milliseconds for shader effects and other time dependent rendering issues\n\tint\t\t\ttime;\n\n\tint\t\t\trdflags;\t\t\t// RDF_NOWORLDMODEL, etc\n\n\t// 1 bits will prevent the associated area from rendering at all\n\tbyte\t\tareamask[MAX_MAP_AREA_BYTES];\n\n\t// text messages for deform text shaders\n\tchar\t\ttext[MAX_RENDER_STRINGS][MAX_RENDER_STRING_LENGTH];\n} refdef_t;\n\n\ntypedef enum {\n\tSTEREO_CENTER,\n\tSTEREO_LEFT,\n\tSTEREO_RIGHT\n} stereoFrame_t;\n\n\n/*\n** glconfig_t\n**\n** Contains variables specific to the OpenGL configuration\n** being run right now.  These are constant once the OpenGL\n** subsystem is initialized.\n*/\ntypedef enum {\n\tTC_NONE,\n\tTC_S3TC\n} textureCompression_t;\n\n\t\n// <artem>\n// glDriverType_t is not used by the engine and quake3 game anymore.\n// Single value (GLDRV_ICD) is left only for compatibility with other mods.\ntypedef enum {\n\tGLDRV_ICD // driver is integrated with window system\n} glDriverType_t;\n// </artem>\n\n// <artem>\n// glHardwareType_t is not used by the engine and quake3 game anymore.\n// Single value (GLHW_GENERIC) is left only for compatibility with other mods.\ntypedef enum {\n\tGLHW_GENERIC // where everthing works the way it should\n} glHardwareType_t;\n// </artem>\n\ntypedef struct {\n\tchar\t\t\t\t\trenderer_string[MAX_STRING_CHARS];\n\tchar\t\t\t\t\tvendor_string[MAX_STRING_CHARS];\n\tchar\t\t\t\t\tversion_string[MAX_STRING_CHARS];\n\tchar\t\t\t\t\textensions_string[BIG_INFO_STRING];\n\n\tint\t\t\t\t\t\tmaxTextureSize;\t\t\t// queried from GL\n\tint\t\t\t\t\t\tmaxActiveTextures;\t\t// multitexture ability\n\n\tint\t\t\t\t\t\tcolorBits, depthBits, stencilBits;\n\n\t// <artem>\n\t// Obsolete. Should be here for compatibility with other mods.\n\tglDriverType_t UNUSED_driverType;\n\t// </artem>\n\n\t// <artem>\n\t// Obsolete. Should be here for compatibility with other mods.\n\tglHardwareType_t UNUSED_hardwareType;\n\t// </artem>\n\n\tqboolean\t\t\t\tdeviceSupportsGamma;\n\ttextureCompression_t\ttextureCompression;\n\tqboolean\t\t\t\ttextureEnvAddAvailable;\n\n\tint\t\t\t\t\t\tvidWidth, vidHeight;\n\t// aspect is the screen's physical width / height, which may be different\n\t// than scrWidth / scrHeight if the pixels are non-square\n\t// normal screens should be 4/3, but wide aspect monitors may be 16/9\n\tfloat\t\t\t\t\twindowAspect;\n\n    // <artem>\n    // Obsolete. Should be here for compatibility with other mods.\n    int UNUSED_displayFrequency;\n    // </artem>\n\n\t// synonymous with \"does rendering consume the entire screen?\", therefore\n\t// a Voodoo or Voodoo2 will have this set to TRUE, as will a Win32 ICD that\n\t// used CDS.\n\tqboolean\t\t\t\tisFullscreen;\n\tqboolean\t\t\t\tstereoEnabled;\n\tqboolean\t\t\t\tsmpActive;\t\t// dual processor\n} glconfig_t;\n\n#if defined(Q3_VM) || defined(_WIN32)\n#define OPENGL_DRIVER_NAME\t\"opengl32\"\n#endif\t// !defined _WIN32\n\n#endif\t// __TR_TYPES_H\n"
  },
  {
    "path": "src/engine/botlib/aasfile.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n\n//NOTE:\tint =\tdefault signed\n//\t\t\t\tdefault long\n\n#define AASID\t\t\t\t\t\t(('S'<<24)+('A'<<16)+('A'<<8)+'E')\n#define AASVERSION_OLD\t\t\t\t4\n#define AASVERSION\t\t\t\t\t5\n\n//presence types\n#define PRESENCE_NONE\t\t\t\t1\n#define PRESENCE_NORMAL\t\t\t\t2\n#define PRESENCE_CROUCH\t\t\t\t4\n\n//travel types\n#define MAX_TRAVELTYPES\t\t\t\t32\n#define TRAVEL_INVALID\t\t\t\t1\t\t//temporary not possible\n#define TRAVEL_WALK\t\t\t\t\t2\t\t//walking\n#define TRAVEL_CROUCH\t\t\t\t3\t\t//crouching\n#define TRAVEL_BARRIERJUMP\t\t\t4\t\t//jumping onto a barrier\n#define TRAVEL_JUMP\t\t\t\t\t5\t\t//jumping\n#define TRAVEL_LADDER\t\t\t\t6\t\t//climbing a ladder\n#define TRAVEL_WALKOFFLEDGE\t\t\t7\t\t//walking of a ledge\n#define TRAVEL_SWIM\t\t\t\t\t8\t\t//swimming\n#define TRAVEL_WATERJUMP\t\t\t9\t\t//jump out of the water\n#define TRAVEL_TELEPORT\t\t\t\t10\t\t//teleportation\n#define TRAVEL_ELEVATOR\t\t\t\t11\t\t//travel by elevator\n#define TRAVEL_ROCKETJUMP\t\t\t12\t\t//rocket jumping required for travel\n#define TRAVEL_BFGJUMP\t\t\t\t13\t\t//bfg jumping required for travel\n#define TRAVEL_GRAPPLEHOOK\t\t\t14\t\t//grappling hook required for travel\n#define TRAVEL_DOUBLEJUMP\t\t\t15\t\t//double jump\n#define TRAVEL_RAMPJUMP\t\t\t\t16\t\t//ramp jump\n#define TRAVEL_STRAFEJUMP\t\t\t17\t\t//strafe jump\n#define TRAVEL_JUMPPAD\t\t\t\t18\t\t//jump pad\n#define TRAVEL_FUNCBOB\t\t\t\t19\t\t//func bob\n\n//additional travel flags\n#define TRAVELTYPE_MASK\t\t\t\t0xFFFFFF\n#define TRAVELFLAG_NOTTEAM1\t\t\t(1 << 24)\n#define TRAVELFLAG_NOTTEAM2\t\t\t(2 << 24)\n\n//face flags\n#define FACE_SOLID\t\t\t\t\t1\t\t//just solid at the other side\n#define FACE_LADDER\t\t\t\t\t2\t\t//ladder\n#define FACE_GROUND\t\t\t\t\t4\t\t//standing on ground when in this face\n#define FACE_GAP\t\t\t\t\t8\t\t//gap in the ground\n#define FACE_LIQUID\t\t\t\t\t16\t\t//face seperating two areas with liquid\n#define FACE_LIQUIDSURFACE\t\t\t32\t\t//face seperating liquid and air\n#define FACE_BRIDGE\t\t\t\t\t64\t\t//can walk over this face if bridge is closed\n\n//area contents\n#define AREACONTENTS_WATER\t\t\t\t1\n#define AREACONTENTS_LAVA\t\t\t\t2\n#define AREACONTENTS_SLIME\t\t\t\t4\n#define AREACONTENTS_CLUSTERPORTAL\t\t8\n#define AREACONTENTS_TELEPORTAL\t\t\t16\n#define AREACONTENTS_ROUTEPORTAL\t\t32\n#define AREACONTENTS_TELEPORTER\t\t\t64\n#define AREACONTENTS_JUMPPAD\t\t\t128\n#define AREACONTENTS_DONOTENTER\t\t\t256\n#define\tAREACONTENTS_VIEWPORTAL\t\t\t512\n#define AREACONTENTS_MOVER\t\t\t\t1024\n#define AREACONTENTS_NOTTEAM1\t\t\t2048\n#define AREACONTENTS_NOTTEAM2\t\t\t4096\n//number of model of the mover inside this area\n#define AREACONTENTS_MODELNUMSHIFT\t\t24\n#define AREACONTENTS_MAXMODELNUM\t\t0xFF\n#define AREACONTENTS_MODELNUM\t\t\t(AREACONTENTS_MAXMODELNUM << AREACONTENTS_MODELNUMSHIFT)\n\n//area flags\n#define AREA_GROUNDED\t\t\t\t1\t\t//bot can stand on the ground\n#define AREA_LADDER\t\t\t\t\t2\t\t//area contains one or more ladder faces\n#define AREA_LIQUID\t\t\t\t\t4\t\t//area contains a liquid\n#define AREA_DISABLED\t\t\t\t8\t\t//area is disabled for routing when set\n#define AREA_BRIDGE\t\t\t\t\t16\t\t//area ontop of a bridge\n\n//aas file header lumps\n#define AAS_LUMPS\t\t\t\t\t14\n#define AASLUMP_BBOXES\t\t\t\t0\n#define AASLUMP_VERTEXES\t\t\t1\n#define AASLUMP_PLANES\t\t\t\t2\n#define AASLUMP_EDGES\t\t\t\t3\n#define AASLUMP_EDGEINDEX\t\t\t4\n#define AASLUMP_FACES\t\t\t\t5\n#define AASLUMP_FACEINDEX\t\t\t6\n#define AASLUMP_AREAS\t\t\t\t7\n#define AASLUMP_AREASETTINGS\t\t8\n#define AASLUMP_REACHABILITY\t\t9\n#define AASLUMP_NODES\t\t\t\t10\n#define AASLUMP_PORTALS\t\t\t\t11\n#define AASLUMP_PORTALINDEX\t\t\t12\n#define AASLUMP_CLUSTERS\t\t\t13\n\n//========== bounding box =========\n\n//bounding box\ntypedef struct aas_bbox_s\n{\n\tint presencetype;\n\tint flags;\n\tvec3_t mins, maxs;\n} aas_bbox_t;\n\n//============ settings ===========\n\n//reachability to another area\ntypedef struct aas_reachability_s\n{\n\tint areanum;\t\t\t\t\t\t//number of the reachable area\n\tint facenum;\t\t\t\t\t\t//number of the face towards the other area\n\tint edgenum;\t\t\t\t\t\t//number of the edge towards the other area\n\tvec3_t start;\t\t\t\t\t\t//start point of inter area movement\n\tvec3_t end;\t\t\t\t\t\t\t//end point of inter area movement\n\tint traveltype;\t\t\t\t\t//type of travel required to get to the area\n\tunsigned short int traveltime;//travel time of the inter area movement\n} aas_reachability_t;\n\n//area settings\ntypedef struct aas_areasettings_s\n{\n\t//could also add all kind of statistic fields\n\tint contents;\t\t\t\t\t\t//contents of the area\n\tint areaflags;\t\t\t\t\t\t//several area flags\n\tint presencetype;\t\t\t\t\t//how a bot can be present in this area\n\tint cluster;\t\t\t\t\t\t//cluster the area belongs to, if negative it's a portal\n\tint clusterareanum;\t\t\t\t//number of the area in the cluster\n\tint numreachableareas;\t\t\t//number of reachable areas from this one\n\tint firstreachablearea;\t\t\t//first reachable area in the reachable area index\n} aas_areasettings_t;\n\n//cluster portal\ntypedef struct aas_portal_s\n{\n\tint areanum;\t\t\t\t\t\t//area that is the actual portal\n\tint frontcluster;\t\t\t\t\t//cluster at front of portal\n\tint backcluster;\t\t\t\t\t//cluster at back of portal\n\tint clusterareanum[2];\t\t\t//number of the area in the front and back cluster\n} aas_portal_t;\n\n//cluster portal index\ntypedef int aas_portalindex_t;\n\n//cluster\ntypedef struct aas_cluster_s\n{\n\tint numareas;\t\t\t\t\t\t//number of areas in the cluster\n\tint numreachabilityareas;\t\t\t//number of areas with reachabilities\n\tint numportals;\t\t\t\t\t\t//number of cluster portals\n\tint firstportal;\t\t\t\t\t//first cluster portal in the index\n} aas_cluster_t;\n\n//============ 3d definition ============\n\ntypedef vec3_t aas_vertex_t;\n\n//just a plane in the third dimension\ntypedef struct aas_plane_s\n{\n\tvec3_t normal;\t\t\t\t\t\t//normal vector of the plane\n\tfloat dist;\t\t\t\t\t\t\t//distance of the plane (normal vector * distance = point in plane)\n\tint type;\n} aas_plane_t;\n\n//edge\ntypedef struct aas_edge_s\n{\n\tint v[2];\t\t\t\t\t\t\t//numbers of the vertexes of this edge\n} aas_edge_t;\n\n//edge index, negative if vertexes are reversed\ntypedef int aas_edgeindex_t;\n\n//a face bounds an area, often it will also seperate two areas\ntypedef struct aas_face_s\n{\n\tint planenum;\t\t\t\t\t\t//number of the plane this face is in\n\tint faceflags;\t\t\t\t\t\t//face flags (no use to create face settings for just this field)\n\tint numedges;\t\t\t\t\t\t//number of edges in the boundary of the face\n\tint firstedge;\t\t\t\t\t\t//first edge in the edge index\n\tint frontarea;\t\t\t\t\t\t//area at the front of this face\n\tint backarea;\t\t\t\t\t\t//area at the back of this face\n} aas_face_t;\n\n//face index, stores a negative index if backside of face\ntypedef int aas_faceindex_t;\n\n//area with a boundary of faces\ntypedef struct aas_area_s\n{\n\tint areanum;\t\t\t\t\t\t//number of this area\n\t//3d definition\n\tint numfaces;\t\t\t\t\t\t//number of faces used for the boundary of the area\n\tint firstface;\t\t\t\t\t\t//first face in the face index used for the boundary of the area\n\tvec3_t mins;\t\t\t\t\t\t//mins of the area\n\tvec3_t maxs;\t\t\t\t\t\t//maxs of the area\n\tvec3_t center;\t\t\t\t\t\t//'center' of the area\n} aas_area_t;\n\n//nodes of the bsp tree\ntypedef struct aas_node_s\n{\n\tint planenum;\n\tint children[2];\t\t\t\t\t//child nodes of this node, or areas as leaves when negative\n\t\t\t\t\t\t\t\t\t\t//when a child is zero it's a solid leaf\n} aas_node_t;\n\n//=========== aas file ===============\n\n//header lump\ntypedef struct\n{\n\tint fileofs;\n\tint filelen;\n} aas_lump_t;\n\n//aas file header\ntypedef struct aas_header_s\n{\n\tint ident;\n\tint version;\n\tint bspchecksum;\n\t//data entries\n\taas_lump_t lumps[AAS_LUMPS];\n} aas_header_t;\n\n\n//====== additional information ======\n/*\n\n-\twhen a node child is a solid leaf the node child number is zero\n-\ttwo adjacent areas (sharing a plane at opposite sides) share a face\n\tthis face is a portal between the areas\n-\twhen an area uses a face from the faceindex with a positive index\n\tthen the face plane normal points into the area\n-\tthe face edges are stored counter clockwise using the edgeindex\n-\ttwo adjacent convex areas (sharing a face) only share One face\n\tthis is a simple result of the areas being convex\n-\tthe areas can't have a mixture of ground and gap faces\n\tother mixtures of faces in one area are allowed\n-\tareas with the AREACONTENTS_CLUSTERPORTAL in the settings have\n\tthe cluster number set to the negative portal number\n-\tedge zero is a dummy\n-\tface zero is a dummy\n-\tarea zero is a dummy\n-\tnode zero is a dummy\n*/\n"
  },
  {
    "path": "src/engine/botlib/be_aas_bsp.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tbe_aas_bsp.h\n *\n * desc:\t\tAAS\n *\n * $Archive: /source/code/botlib/be_aas_bsp.h $\n *\n *****************************************************************************/\n\n#ifdef AASINTERN\n//loads the given BSP file\nint AAS_LoadBSPFile(void);\n//dump the loaded BSP data\nvoid AAS_DumpBSPData(void);\n//unlink the given entity from the bsp tree leaves\nvoid AAS_UnlinkFromBSPLeaves(bsp_link_t *leaves);\n//link the given entity to the bsp tree leaves of the given model\nbsp_link_t *AAS_BSPLinkEntity(vec3_t absmins,\n\t\t\t\t\t\t\t\t\t\tvec3_t absmaxs,\n\t\t\t\t\t\t\t\t\t\tint entnum,\n\t\t\t\t\t\t\t\t\t\tint modelnum);\n\n//calculates collision with given entity\nqboolean AAS_EntityCollision(int entnum,\n\t\t\t\t\t\t\t\t\t\tvec3_t start,\n\t\t\t\t\t\t\t\t\t\tvec3_t boxmins,\n\t\t\t\t\t\t\t\t\t\tvec3_t boxmaxs,\n\t\t\t\t\t\t\t\t\t\tvec3_t end,\n\t\t\t\t\t\t\t\t\t\tint contentmask,\n\t\t\t\t\t\t\t\t\t\tbsp_trace_t *trace);\n//for debugging\nvoid AAS_PrintFreeBSPLinks(char *str);\n//\n#endif //AASINTERN\n\n#define MAX_EPAIRKEY\t\t128\n\n//trace through the world\nbsp_trace_t AAS_Trace(\tvec3_t start,\n\t\t\t\t\t\t\t\tvec3_t mins,\n\t\t\t\t\t\t\t\tvec3_t maxs,\n\t\t\t\t\t\t\t\tvec3_t end,\n\t\t\t\t\t\t\t\tint passent,\n\t\t\t\t\t\t\t\tint contentmask);\n//returns the contents at the given point\nint AAS_PointContents(vec3_t point);\n//returns true when p2 is in the PVS of p1\nqboolean AAS_inPVS(vec3_t p1, vec3_t p2);\n//returns true when p2 is in the PHS of p1\nqboolean AAS_inPHS(vec3_t p1, vec3_t p2);\n//returns true if the given areas are connected\nqboolean AAS_AreasConnected(int area1, int area2);\n//creates a list with entities totally or partly within the given box\nint AAS_BoxEntities(vec3_t absmins, vec3_t absmaxs, int *list, int maxcount);\n//gets the mins, maxs and origin of a BSP model\nvoid AAS_BSPModelMinsMaxsOrigin(int modelnum, vec3_t angles, vec3_t mins, vec3_t maxs, vec3_t origin);\n//handle to the next bsp entity\nint AAS_NextBSPEntity(int ent);\n//return the value of the BSP epair key\nint AAS_ValueForBSPEpairKey(int ent, char *key, char *value, int size);\n//get a vector for the BSP epair key\nint AAS_VectorForBSPEpairKey(int ent, char *key, vec3_t v);\n//get a float for the BSP epair key\nint AAS_FloatForBSPEpairKey(int ent, char *key, float *value);\n//get an integer for the BSP epair key\nint AAS_IntForBSPEpairKey(int ent, char *key, int *value);\n\n"
  },
  {
    "path": "src/engine/botlib/be_aas_bspq3.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tbe_aas_bspq3.c\n *\n * desc:\t\tBSP, Environment Sampling\n *\n * $Archive: /MissionPack/code/botlib/be_aas_bspq3.c $\n *\n *****************************************************************************/\n\n#include \"../../game/q_shared.h\"\n#include \"l_memory.h\"\n#include \"l_script.h\"\n#include \"l_precomp.h\"\n#include \"l_struct.h\"\n#include \"aasfile.h\"\n#include \"../../game/botlib.h\"\n#include \"../../game/be_aas.h\"\n#include \"be_aas_funcs.h\"\n#include \"be_aas_def.h\"\n\nextern botlib_import_t botimport;\n\n//#define TRACE_DEBUG\n\n#define ON_EPSILON\t\t0.005\n//#define DEG2RAD( a ) (( a * M_PI ) / 180.0F)\n\n#define MAX_BSPENTITIES\t\t2048\n\ntypedef struct rgb_s\n{\n\tint red;\n\tint green;\n\tint blue;\n} rgb_t;\n\n//bsp entity epair\ntypedef struct bsp_epair_s\n{\n\tchar *key;\n\tchar *value;\n\tstruct bsp_epair_s *next;\n} bsp_epair_t;\n\n//bsp data entity\ntypedef struct bsp_entity_s\n{\n\tbsp_epair_t *epairs;\n} bsp_entity_t;\n\n//id Sofware BSP data\ntypedef struct bsp_s\n{\n\t//true when bsp file is loaded\n\tint loaded;\n\t//entity data\n\tint entdatasize;\n\tchar *dentdata;\n\t//bsp entities\n\tint numentities;\n\tbsp_entity_t entities[MAX_BSPENTITIES];\n} bsp_t;\n\n//global bsp\nbsp_t bspworld;\n\n\n#ifdef BSP_DEBUG\ntypedef struct cname_s\n{\n\tint value;\n\tchar *name;\n} cname_t;\n\ncname_t contentnames[] =\n{\n\t{CONTENTS_SOLID,\"CONTENTS_SOLID\"},\n\t{CONTENTS_WINDOW,\"CONTENTS_WINDOW\"},\n\t{CONTENTS_AUX,\"CONTENTS_AUX\"},\n\t{CONTENTS_LAVA,\"CONTENTS_LAVA\"},\n\t{CONTENTS_SLIME,\"CONTENTS_SLIME\"},\n\t{CONTENTS_WATER,\"CONTENTS_WATER\"},\n\t{CONTENTS_MIST,\"CONTENTS_MIST\"},\n\t{LAST_VISIBLE_CONTENTS,\"LAST_VISIBLE_CONTENTS\"},\n\n\t{CONTENTS_AREAPORTAL,\"CONTENTS_AREAPORTAL\"},\n\t{CONTENTS_PLAYERCLIP,\"CONTENTS_PLAYERCLIP\"},\n\t{CONTENTS_MONSTERCLIP,\"CONTENTS_MONSTERCLIP\"},\n\t{CONTENTS_CURRENT_0,\"CONTENTS_CURRENT_0\"},\n\t{CONTENTS_CURRENT_90,\"CONTENTS_CURRENT_90\"},\n\t{CONTENTS_CURRENT_180,\"CONTENTS_CURRENT_180\"},\n\t{CONTENTS_CURRENT_270,\"CONTENTS_CURRENT_270\"},\n\t{CONTENTS_CURRENT_UP,\"CONTENTS_CURRENT_UP\"},\n\t{CONTENTS_CURRENT_DOWN,\"CONTENTS_CURRENT_DOWN\"},\n\t{CONTENTS_ORIGIN,\"CONTENTS_ORIGIN\"},\n\t{CONTENTS_MONSTER,\"CONTENTS_MONSTER\"},\n\t{CONTENTS_DEADMONSTER,\"CONTENTS_DEADMONSTER\"},\n\t{CONTENTS_DETAIL,\"CONTENTS_DETAIL\"},\n\t{CONTENTS_TRANSLUCENT,\"CONTENTS_TRANSLUCENT\"},\n\t{CONTENTS_LADDER,\"CONTENTS_LADDER\"},\n\t{0, 0}\n};\n\nvoid PrintContents(int contents)\n{\n\tint i;\n\n\tfor (i = 0; contentnames[i].value; i++)\n\t{\n\t\tif (contents & contentnames[i].value)\n\t\t{\n\t\t\tbotimport.Print(PRT_MESSAGE, \"%s\\n\", contentnames[i].name);\n\t\t} //end if\n\t} //end for\n} //end of the function PrintContents\n\n#endif // BSP_DEBUG\n//===========================================================================\n// traces axial boxes of any size through the world\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nbsp_trace_t AAS_Trace(vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int passent, int contentmask)\n{\n\tbsp_trace_t bsptrace;\n\tbotimport.Trace(&bsptrace, start, mins, maxs, end, passent, contentmask);\n\treturn bsptrace;\n} //end of the function AAS_Trace\n//===========================================================================\n// returns the contents at the given point\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_PointContents(vec3_t point)\n{\n\treturn botimport.PointContents(point);\n} //end of the function AAS_PointContents\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nqboolean AAS_EntityCollision(int entnum,\n\t\t\t\t\tvec3_t start, vec3_t boxmins, vec3_t boxmaxs, vec3_t end,\n\t\t\t\t\t\t\t\tint contentmask, bsp_trace_t *trace)\n{\n\tbsp_trace_t enttrace;\n\n\tbotimport.EntityTrace(&enttrace, start, boxmins, boxmaxs, end, entnum, contentmask);\n\tif (enttrace.fraction < trace->fraction)\n\t{\n\t\tCom_Memcpy(trace, &enttrace, sizeof(bsp_trace_t));\n\t\treturn qtrue;\n\t} //end if\n\treturn qfalse;\n} //end of the function AAS_EntityCollision\n//===========================================================================\n// returns true if in Potentially Hearable Set\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nqboolean AAS_inPVS(vec3_t p1, vec3_t p2)\n{\n\treturn (qboolean) botimport.inPVS(p1, p2);\n} //end of the function AAS_InPVS\n//===========================================================================\n// returns true if in Potentially Visible Set\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nqboolean AAS_inPHS(vec3_t p1, vec3_t p2)\n{\n\treturn qtrue;\n} //end of the function AAS_inPHS\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_BSPModelMinsMaxsOrigin(int modelnum, vec3_t angles, vec3_t mins, vec3_t maxs, vec3_t origin)\n{\n\tbotimport.BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, origin);\n} //end of the function AAS_BSPModelMinsMaxs\n//===========================================================================\n// unlinks the entity from all leaves\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_UnlinkFromBSPLeaves(bsp_link_t *leaves)\n{\n} //end of the function AAS_UnlinkFromBSPLeaves\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nbsp_link_t *AAS_BSPLinkEntity(vec3_t absmins, vec3_t absmaxs, int entnum, int modelnum)\n{\n\treturn NULL;\n} //end of the function AAS_BSPLinkEntity\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_BoxEntities(vec3_t absmins, vec3_t absmaxs, int *list, int maxcount)\n{\n\treturn 0;\n} //end of the function AAS_BoxEntities\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_NextBSPEntity(int ent)\n{\n\tent++;\n\tif (ent >= 1 && ent < bspworld.numentities) return ent;\n\treturn 0;\n} //end of the function AAS_NextBSPEntity\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_BSPEntityInRange(int ent)\n{\n\tif (ent <= 0 || ent >= bspworld.numentities)\n\t{\n\t\tbotimport.Print(PRT_MESSAGE, \"bsp entity out of range\\n\");\n\t\treturn qfalse;\n\t} //end if\n\treturn qtrue;\n} //end of the function AAS_BSPEntityInRange\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_ValueForBSPEpairKey(int ent, char *key, char *value, int size)\n{\n\tbsp_epair_t *epair;\n\n\tvalue[0] = '\\0';\n\tif (!AAS_BSPEntityInRange(ent)) return qfalse;\n\tfor (epair = bspworld.entities[ent].epairs; epair; epair = epair->next)\n\t{\n\t\tif (!strcmp(epair->key, key))\n\t\t{\n\t\t\tstrncpy(value, epair->value, size-1);\n\t\t\tvalue[size-1] = '\\0';\n\t\t\treturn qtrue;\n\t\t} //end if\n\t} //end for\n\treturn qfalse;\n} //end of the function AAS_FindBSPEpair\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_VectorForBSPEpairKey(int ent, char *key, vec3_t v)\n{\n\tchar buf[MAX_EPAIRKEY];\n\tdouble v1, v2, v3;\n\n\tVectorClear(v);\n\tif (!AAS_ValueForBSPEpairKey(ent, key, buf, MAX_EPAIRKEY)) return qfalse;\n\t//scanf into doubles, then assign, so it is vec_t size independent\n\tv1 = v2 = v3 = 0;\n\tsscanf(buf, \"%lf %lf %lf\", &v1, &v2, &v3);\n\tv[0] = v1;\n\tv[1] = v2;\n\tv[2] = v3;\n\treturn qtrue;\n} //end of the function AAS_VectorForBSPEpairKey\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_FloatForBSPEpairKey(int ent, char *key, float *value)\n{\n\tchar buf[MAX_EPAIRKEY];\n\t\n\t*value = 0;\n\tif (!AAS_ValueForBSPEpairKey(ent, key, buf, MAX_EPAIRKEY)) return qfalse;\n\t*value = atof(buf);\n\treturn qtrue;\n} //end of the function AAS_FloatForBSPEpairKey\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_IntForBSPEpairKey(int ent, char *key, int *value)\n{\n\tchar buf[MAX_EPAIRKEY];\n\t\n\t*value = 0;\n\tif (!AAS_ValueForBSPEpairKey(ent, key, buf, MAX_EPAIRKEY)) return qfalse;\n\t*value = atoi(buf);\n\treturn qtrue;\n} //end of the function AAS_IntForBSPEpairKey\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_FreeBSPEntities(void)\n{\n\tint i;\n\tbsp_entity_t *ent;\n\tbsp_epair_t *epair, *nextepair;\n\n\tfor (i = 1; i < bspworld.numentities; i++)\n\t{\n\t\tent = &bspworld.entities[i];\n\t\tfor (epair = ent->epairs; epair; epair = nextepair)\n\t\t{\n\t\t\tnextepair = epair->next;\n\t\t\t//\n\t\t\tif (epair->key) FreeMemory(epair->key);\n\t\t\tif (epair->value) FreeMemory(epair->value);\n\t\t\tFreeMemory(epair);\n\t\t} //end for\n\t} //end for\n\tbspworld.numentities = 0;\n} //end of the function AAS_FreeBSPEntities\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_ParseBSPEntities(void)\n{\n\tscript_t *script;\n\ttoken_t token;\n\tbsp_entity_t *ent;\n\tbsp_epair_t *epair;\n\n\tscript = LoadScriptMemory(bspworld.dentdata, bspworld.entdatasize, \"entdata\");\n\tSetScriptFlags(script, SCFL_NOSTRINGWHITESPACES|SCFL_NOSTRINGESCAPECHARS);//SCFL_PRIMITIVE);\n\n\tbspworld.numentities = 1;\n\n\twhile(PS_ReadToken(script, &token))\n\t{\n\t\tif (strcmp(token.string, \"{\"))\n\t\t{\n\t\t\tScriptError(script, \"invalid %s\\n\", token.string);\n\t\t\tAAS_FreeBSPEntities();\n\t\t\tFreeScript(script);\n\t\t\treturn;\n\t\t} //end if\n\t\tif (bspworld.numentities >= MAX_BSPENTITIES)\n\t\t{\n\t\t\tbotimport.Print(PRT_MESSAGE, \"too many entities in BSP file\\n\");\n\t\t\tbreak;\n\t\t} //end if\n\t\tent = &bspworld.entities[bspworld.numentities];\n\t\tbspworld.numentities++;\n\t\tent->epairs = NULL;\n\t\twhile(PS_ReadToken(script, &token))\n\t\t{\n\t\t\tif (!strcmp(token.string, \"}\")) break;\n\t\t\tepair = (bsp_epair_t *) GetClearedHunkMemory(sizeof(bsp_epair_t));\n\t\t\tepair->next = ent->epairs;\n\t\t\tent->epairs = epair;\n\t\t\tif (token.type != TT_STRING)\n\t\t\t{\n\t\t\t\tScriptError(script, \"invalid %s\\n\", token.string);\n\t\t\t\tAAS_FreeBSPEntities();\n\t\t\t\tFreeScript(script);\n\t\t\t\treturn;\n\t\t\t} //end if\n\t\t\tStripDoubleQuotes(token.string);\n\t\t\tepair->key = (char *) GetHunkMemory((int)strlen(token.string) + 1);\n\t\t\tstrcpy(epair->key, token.string);\n\t\t\tif (!PS_ExpectTokenType(script, TT_STRING, 0, &token))\n\t\t\t{\n\t\t\t\tAAS_FreeBSPEntities();\n\t\t\t\tFreeScript(script);\n\t\t\t\treturn;\n\t\t\t} //end if\n\t\t\tStripDoubleQuotes(token.string);\n\t\t\tepair->value = (char *) GetHunkMemory((int)strlen(token.string) + 1);\n\t\t\tstrcpy(epair->value, token.string);\n\t\t} //end while\n\t\tif (strcmp(token.string, \"}\"))\n\t\t{\n\t\t\tScriptError(script, \"missing }\\n\");\n\t\t\tAAS_FreeBSPEntities();\n\t\t\tFreeScript(script);\n\t\t\treturn;\n\t\t} //end if\n\t} //end while\n\tFreeScript(script);\n} //end of the function AAS_ParseBSPEntities\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_BSPTraceLight(vec3_t start, vec3_t end, vec3_t endpos, int *red, int *green, int *blue)\n{\n\treturn 0;\n} //end of the function AAS_BSPTraceLight\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_DumpBSPData(void)\n{\n\tAAS_FreeBSPEntities();\n\n\tif (bspworld.dentdata) FreeMemory(bspworld.dentdata);\n\tbspworld.dentdata = NULL;\n\tbspworld.entdatasize = 0;\n\t//\n\tbspworld.loaded = qfalse;\n\tCom_Memset( &bspworld, 0, sizeof(bspworld) );\n} //end of the function AAS_DumpBSPData\n//===========================================================================\n// load an bsp file\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_LoadBSPFile(void)\n{\n\tAAS_DumpBSPData();\n\tbspworld.entdatasize = (int)strlen(botimport.BSPEntityData()) + 1;\n\tbspworld.dentdata = (char *) GetClearedHunkMemory(bspworld.entdatasize);\n\tCom_Memcpy(bspworld.dentdata, botimport.BSPEntityData(), bspworld.entdatasize);\n\tAAS_ParseBSPEntities();\n\tbspworld.loaded = qtrue;\n\treturn BLERR_NOERROR;\n} //end of the function AAS_LoadBSPFile\n"
  },
  {
    "path": "src/engine/botlib/be_aas_cluster.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tbe_aas_cluster.c\n *\n * desc:\t\tarea clustering\n *\n * $Archive: /MissionPack/code/botlib/be_aas_cluster.c $\n *\n *****************************************************************************/\n\n#include \"../../game/q_shared.h\"\n#include \"l_memory.h\"\n#include \"l_script.h\"\n#include \"l_precomp.h\"\n#include \"l_struct.h\"\n#include \"l_log.h\"\n#include \"l_memory.h\"\n#include \"l_libvar.h\"\n#include \"aasfile.h\"\n#include \"../../game/botlib.h\"\n#include \"../../game/be_aas.h\"\n#include \"be_aas_funcs.h\"\n#include \"be_aas_def.h\"\n\nextern botlib_import_t botimport;\n\n#define AAS_MAX_PORTALS\t\t\t\t\t65536\n#define AAS_MAX_PORTALINDEXSIZE\t\t\t65536\n#define AAS_MAX_CLUSTERS\t\t\t\t65536\n//\n#define MAX_PORTALAREAS\t\t\t1024\n\n// do not flood through area faces, only use reachabilities\nint nofaceflood = qtrue;\n\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_RemoveClusterAreas(void)\n{\n\tint i;\n\n\tfor (i = 1; i < aasworld.numareas; i++)\n\t{\n\t\taasworld.areasettings[i].cluster = 0;\n\t} //end for\n} //end of the function AAS_RemoveClusterAreas\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_ClearCluster(int clusternum)\n{\n\tint i;\n\n\tfor (i = 1; i < aasworld.numareas; i++)\n\t{\n\t\tif (aasworld.areasettings[i].cluster == clusternum)\n\t\t{\n\t\t\taasworld.areasettings[i].cluster = 0;\n\t\t} //end if\n\t} //end for\n} //end of the function AAS_ClearCluster\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_RemovePortalsClusterReference(int clusternum)\n{\n\tint portalnum;\n\n\tfor (portalnum = 1; portalnum < aasworld.numportals; portalnum++)\n\t{\n\t\tif (aasworld.portals[portalnum].frontcluster == clusternum)\n\t\t{\n\t\t\taasworld.portals[portalnum].frontcluster = 0;\n\t\t} //end if\n\t\tif (aasworld.portals[portalnum].backcluster == clusternum)\n\t\t{\n\t\t\taasworld.portals[portalnum].backcluster = 0;\n\t\t} //end if\n\t} //end for\n} //end of the function AAS_RemovePortalsClusterReference\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_UpdatePortal(int areanum, int clusternum)\n{\n\tint portalnum;\n\taas_portal_t *portal;\n\taas_cluster_t *cluster;\n\n\t//find the portal of the area\n\tfor (portalnum = 1; portalnum < aasworld.numportals; portalnum++)\n\t{\n\t\tif (aasworld.portals[portalnum].areanum == areanum) break;\n\t} //end for\n\t//\n\tif (portalnum == aasworld.numportals)\n\t{\n\t\tAAS_Error(\"no portal of area %d\", areanum);\n\t\treturn qtrue;\n\t} //end if\n\t//\n\tportal = &aasworld.portals[portalnum];\n\t//if the portal is already fully updated\n\tif (portal->frontcluster == clusternum) return qtrue;\n\tif (portal->backcluster == clusternum) return qtrue;\n\t//if the portal has no front cluster yet\n\tif (!portal->frontcluster)\n\t{\n\t\tportal->frontcluster = clusternum;\n\t} //end if\n\t//if the portal has no back cluster yet\n\telse if (!portal->backcluster)\n\t{\n\t\tportal->backcluster = clusternum;\n\t} //end else if\n\telse\n\t{\n\t\t//remove the cluster portal flag contents\n\t\taasworld.areasettings[areanum].contents &= ~AREACONTENTS_CLUSTERPORTAL;\n\t\tLog_Write(\"portal area %d is seperating more than two clusters\\r\\n\", areanum);\n\t\treturn qfalse;\n\t} //end else\n\tif (aasworld.portalindexsize >= AAS_MAX_PORTALINDEXSIZE)\n\t{\n\t\tAAS_Error(\"AAS_MAX_PORTALINDEXSIZE\");\n\t\treturn qtrue;\n\t} //end if\n\t//set the area cluster number to the negative portal number\n\taasworld.areasettings[areanum].cluster = -portalnum;\n\t//add the portal to the cluster using the portal index\n\tcluster = &aasworld.clusters[clusternum];\n\taasworld.portalindex[cluster->firstportal + cluster->numportals] = portalnum;\n\taasworld.portalindexsize++;\n\tcluster->numportals++;\n\treturn qtrue;\n} //end of the function AAS_UpdatePortal\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_FloodClusterAreas_r(int areanum, int clusternum)\n{\n\taas_area_t *area;\n\taas_face_t *face;\n\tint facenum, i;\n\n\t//\n\tif (areanum <= 0 || areanum >= aasworld.numareas)\n\t{\n\t\tAAS_Error(\"AAS_FloodClusterAreas_r: areanum out of range\");\n\t\treturn qfalse;\n\t} //end if\n\t//if the area is already part of a cluster\n\tif (aasworld.areasettings[areanum].cluster > 0)\n\t{\n\t\tif (aasworld.areasettings[areanum].cluster == clusternum) return qtrue;\n\t\t//\n\t\t//there's a reachability going from one cluster to another only in one direction\n\t\t//\n\t\tAAS_Error(\"cluster %d touched cluster %d at area %d\\r\\n\",\n\t\t\t\tclusternum, aasworld.areasettings[areanum].cluster, areanum);\n\t\treturn qfalse;\n\t} //end if\n\t//don't add the cluster portal areas to the clusters\n\tif (aasworld.areasettings[areanum].contents & AREACONTENTS_CLUSTERPORTAL)\n\t{\n\t\treturn AAS_UpdatePortal(areanum, clusternum);\n\t} //end if\n\t//set the area cluster number\n\taasworld.areasettings[areanum].cluster = clusternum;\n\taasworld.areasettings[areanum].clusterareanum =\n\t\t\t\taasworld.clusters[clusternum].numareas;\n\t//the cluster has an extra area\n\taasworld.clusters[clusternum].numareas++;\n\n\tarea = &aasworld.areas[areanum];\n\t//use area faces to flood into adjacent areas\n\tif (!nofaceflood)\n\t{\n\t\tfor (i = 0; i < area->numfaces; i++)\n\t\t{\n\t\t\tfacenum = abs(aasworld.faceindex[area->firstface + i]);\n\t\t\tface = &aasworld.faces[facenum];\n\t\t\tif (face->frontarea == areanum)\n\t\t\t{\n\t\t\t\tif (face->backarea) if (!AAS_FloodClusterAreas_r(face->backarea, clusternum)) return qfalse;\n\t\t\t} //end if\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (face->frontarea) if (!AAS_FloodClusterAreas_r(face->frontarea, clusternum)) return qfalse;\n\t\t\t} //end else\n\t\t} //end for\n\t} //end if\n\t//use the reachabilities to flood into other areas\n\tfor (i = 0; i < aasworld.areasettings[areanum].numreachableareas; i++)\n\t{\n\t\tif (!aasworld.reachability[\n\t\t\t\t\taasworld.areasettings[areanum].firstreachablearea + i].areanum)\n\t\t{\n\t\t\tcontinue;\n\t\t} //end if\n\t\tif (!AAS_FloodClusterAreas_r(aasworld.reachability[\n\t\t\t\taasworld.areasettings[areanum].firstreachablearea + i].areanum, clusternum)) return qfalse;\n\t} //end for\n\treturn qtrue;\n} //end of the function AAS_FloodClusterAreas_r\n//===========================================================================\n// try to flood from all areas without cluster into areas with a cluster set\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_FloodClusterAreasUsingReachabilities(int clusternum)\n{\n\tint i, j, areanum;\n\n\tfor (i = 1; i < aasworld.numareas; i++)\n\t{\n\t\t//if this area already has a cluster set\n\t\tif (aasworld.areasettings[i].cluster)\n\t\t\tcontinue;\n\t\t//if this area is a cluster portal\n\t\tif (aasworld.areasettings[i].contents & AREACONTENTS_CLUSTERPORTAL)\n\t\t\tcontinue;\n\t\t//loop over the reachable areas from this area\n\t\tfor (j = 0; j < aasworld.areasettings[i].numreachableareas; j++)\n\t\t{\n\t\t\t//the reachable area\n\t\t\tareanum = aasworld.reachability[aasworld.areasettings[i].firstreachablearea + j].areanum;\n\t\t\t//if this area is a cluster portal\n\t\t\tif (aasworld.areasettings[areanum].contents & AREACONTENTS_CLUSTERPORTAL)\n\t\t\t\tcontinue;\n\t\t\t//if this area has a cluster set\n\t\t\tif (aasworld.areasettings[areanum].cluster)\n\t\t\t{\n\t\t\t\tif (!AAS_FloodClusterAreas_r(i, clusternum))\n\t\t\t\t\treturn qfalse;\n\t\t\t\ti = 0;\n\t\t\t\tbreak;\n\t\t\t} //end if\n\t\t} //end for\n\t} //end for\n\treturn qtrue;\n} //end of the function AAS_FloodClusterAreasUsingReachabilities\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_NumberClusterPortals(int clusternum)\n{\n\tint i, portalnum;\n\taas_cluster_t *cluster;\n\taas_portal_t *portal;\n\n\tcluster = &aasworld.clusters[clusternum];\n\tfor (i = 0; i < cluster->numportals; i++)\n\t{\n\t\tportalnum = aasworld.portalindex[cluster->firstportal + i];\n\t\tportal = &aasworld.portals[portalnum];\n\t\tif (portal->frontcluster == clusternum)\n\t\t{\n\t\t\tportal->clusterareanum[0] = cluster->numareas++;\n\t\t} //end if\n\t\telse\n\t\t{\n\t\t\tportal->clusterareanum[1] = cluster->numareas++;\n\t\t} //end else\n\t} //end for\n} //end of the function AAS_NumberClusterPortals\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_NumberClusterAreas(int clusternum)\n{\n\tint i, portalnum;\n\taas_cluster_t *cluster;\n\taas_portal_t *portal;\n\n\taasworld.clusters[clusternum].numareas = 0;\n\taasworld.clusters[clusternum].numreachabilityareas = 0;\n\t//number all areas in this cluster WITH reachabilities\n\tfor (i = 1; i < aasworld.numareas; i++)\n\t{\n\t\t//\n\t\tif (aasworld.areasettings[i].cluster != clusternum) continue;\n\t\t//\n\t\tif (!AAS_AreaReachability(i)) continue;\n\t\t//\n\t\taasworld.areasettings[i].clusterareanum = aasworld.clusters[clusternum].numareas;\n\t\t//the cluster has an extra area\n\t\taasworld.clusters[clusternum].numareas++;\n\t\taasworld.clusters[clusternum].numreachabilityareas++;\n\t} //end for\n\t//number all portals in this cluster WITH reachabilities\n\tcluster = &aasworld.clusters[clusternum];\n\tfor (i = 0; i < cluster->numportals; i++)\n\t{\n\t\tportalnum = aasworld.portalindex[cluster->firstportal + i];\n\t\tportal = &aasworld.portals[portalnum];\n\t\tif (!AAS_AreaReachability(portal->areanum)) continue;\n\t\tif (portal->frontcluster == clusternum)\n\t\t{\n\t\t\tportal->clusterareanum[0] = cluster->numareas++;\n\t\t\taasworld.clusters[clusternum].numreachabilityareas++;\n\t\t} //end if\n\t\telse\n\t\t{\n\t\t\tportal->clusterareanum[1] = cluster->numareas++;\n\t\t\taasworld.clusters[clusternum].numreachabilityareas++;\n\t\t} //end else\n\t} //end for\n\t//number all areas in this cluster WITHOUT reachabilities\n\tfor (i = 1; i < aasworld.numareas; i++)\n\t{\n\t\t//\n\t\tif (aasworld.areasettings[i].cluster != clusternum) continue;\n\t\t//\n\t\tif (AAS_AreaReachability(i)) continue;\n\t\t//\n\t\taasworld.areasettings[i].clusterareanum = aasworld.clusters[clusternum].numareas;\n\t\t//the cluster has an extra area\n\t\taasworld.clusters[clusternum].numareas++;\n\t} //end for\n\t//number all portals in this cluster WITHOUT reachabilities\n\tcluster = &aasworld.clusters[clusternum];\n\tfor (i = 0; i < cluster->numportals; i++)\n\t{\n\t\tportalnum = aasworld.portalindex[cluster->firstportal + i];\n\t\tportal = &aasworld.portals[portalnum];\n\t\tif (AAS_AreaReachability(portal->areanum)) continue;\n\t\tif (portal->frontcluster == clusternum)\n\t\t{\n\t\t\tportal->clusterareanum[0] = cluster->numareas++;\n\t\t} //end if\n\t\telse\n\t\t{\n\t\t\tportal->clusterareanum[1] = cluster->numareas++;\n\t\t} //end else\n\t} //end for\n} //end of the function AAS_NumberClusterAreas\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_FindClusters(void)\n{\n\tint i;\n\taas_cluster_t *cluster;\n\n\tAAS_RemoveClusterAreas();\n\t//\n\tfor (i = 1; i < aasworld.numareas; i++)\n\t{\n\t\t//if the area is already part of a cluster\n\t\tif (aasworld.areasettings[i].cluster)\n\t\t\tcontinue;\n\t\t// if not flooding through faces only use areas that have reachabilities\n\t\tif (nofaceflood)\n\t\t{\n\t\t\tif (!aasworld.areasettings[i].numreachableareas)\n\t\t\t\tcontinue;\n\t\t} //end if\n\t\t//if the area is a cluster portal\n\t\tif (aasworld.areasettings[i].contents & AREACONTENTS_CLUSTERPORTAL)\n\t\t\tcontinue;\n\t\tif (aasworld.numclusters >= AAS_MAX_CLUSTERS)\n\t\t{\n\t\t\tAAS_Error(\"AAS_MAX_CLUSTERS\");\n\t\t\treturn qfalse;\n\t\t} //end if\n\t\tcluster = &aasworld.clusters[aasworld.numclusters];\n\t\tcluster->numareas = 0;\n\t\tcluster->numreachabilityareas = 0;\n\t\tcluster->firstportal = aasworld.portalindexsize;\n\t\tcluster->numportals = 0;\n\t\t//flood the areas in this cluster\n\t\tif (!AAS_FloodClusterAreas_r(i, aasworld.numclusters))\n\t\t\treturn qfalse;\n\t\tif (!AAS_FloodClusterAreasUsingReachabilities(aasworld.numclusters))\n\t\t\treturn qfalse;\n\t\t//number the cluster areas\n\t\t//AAS_NumberClusterPortals(aasworld.numclusters);\n\t\tAAS_NumberClusterAreas(aasworld.numclusters);\n\t\t//Log_Write(\"cluster %d has %d areas\\r\\n\", aasworld.numclusters, cluster->numareas);\n\t\taasworld.numclusters++;\n\t} //end for\n\treturn qtrue;\n} //end of the function AAS_FindClusters\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_CreatePortals(void)\n{\n\tint i;\n\taas_portal_t *portal;\n\n\tfor (i = 1; i < aasworld.numareas; i++)\n\t{\n\t\t//if the area is a cluster portal\n\t\tif (aasworld.areasettings[i].contents & AREACONTENTS_CLUSTERPORTAL)\n\t\t{\n\t\t\tif (aasworld.numportals >= AAS_MAX_PORTALS)\n\t\t\t{\n\t\t\t\tAAS_Error(\"AAS_MAX_PORTALS\");\n\t\t\t\treturn;\n\t\t\t} //end if\n\t\t\tportal = &aasworld.portals[aasworld.numportals];\n\t\t\tportal->areanum = i;\n\t\t\tportal->frontcluster = 0;\n\t\t\tportal->backcluster = 0;\n\t\t\taasworld.numportals++;\n\t\t} //end if\n\t} //end for\n} //end of the function AAS_CreatePortals\n/*\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_MapContainsTeleporters(void)\n{\n\tbsp_entity_t *entities, *ent;\n\tchar *classname;\n\n\tentities = AAS_ParseBSPEntities();\n\n\tfor (ent = entities; ent; ent = ent->next)\n\t{\n\t\tclassname = AAS_ValueForBSPEpairKey(ent, \"classname\");\n\t\tif (classname && !strcmp(classname, \"misc_teleporter\"))\n\t\t{\n\t\t\tAAS_FreeBSPEntities(entities);\n\t\t\treturn qtrue;\n\t\t} //end if\n\t} //end for\n\treturn qfalse;\n} //end of the function AAS_MapContainsTeleporters\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_NonConvexFaces(aas_face_t *face1, aas_face_t *face2, int side1, int side2)\n{\n\tint i, j, edgenum;\n\taas_plane_t *plane1, *plane2;\n\taas_edge_t *edge;\n\t\n\n\tplane1 = &aasworld.planes[face1->planenum ^ side1];\n\tplane2 = &aasworld.planes[face2->planenum ^ side2];\n\n\t//check if one of the points of face1 is at the back of the plane of face2\n\tfor (i = 0; i < face1->numedges; i++)\n\t{\n\t\tedgenum = abs(aasworld.edgeindex[face1->firstedge + i]);\n\t\tedge = &aasworld.edges[edgenum];\n\t\tfor (j = 0; j < 2; j++)\n\t\t{\n\t\t\tif (DotProduct(plane2->normal, aasworld.vertexes[edge->v[j]]) -\n\t\t\t\t\t\t\tplane2->dist < -0.01) return qtrue;\n\t\t} //end for\n\t} //end for\n\tfor (i = 0; i < face2->numedges; i++)\n\t{\n\t\tedgenum = abs(aasworld.edgeindex[face2->firstedge + i]);\n\t\tedge = &aasworld.edges[edgenum];\n\t\tfor (j = 0; j < 2; j++)\n\t\t{\n\t\t\tif (DotProduct(plane1->normal, aasworld.vertexes[edge->v[j]]) -\n\t\t\t\t\t\t\tplane1->dist < -0.01) return qtrue;\n\t\t} //end for\n\t} //end for\n\n\treturn qfalse;\n} //end of the function AAS_NonConvexFaces\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nqboolean AAS_CanMergeAreas(int *areanums, int numareas)\n{\n\tint i, j, s, face1num, face2num, side1, side2, fn1, fn2;\n\taas_face_t *face1, *face2;\n\taas_area_t *area1, *area2;\n\n\tfor (i = 0; i < numareas; i++)\n\t{\n\t\tarea1 = &aasworld.areas[areanums[i]];\n\t\tfor (fn1 = 0; fn1 < area1->numfaces; fn1++)\n\t\t{\n\t\t\tface1num = abs(aasworld.faceindex[area1->firstface + fn1]);\n\t\t\tface1 = &aasworld.faces[face1num];\n\t\t\tside1 = face1->frontarea != areanums[i];\n\t\t\t//check if the face isn't a shared one with one of the other areas\n\t\t\tfor (s = 0; s < numareas; s++)\n\t\t\t{\n\t\t\t\tif (s == i) continue;\n\t\t\t\tif (face1->frontarea == s || face1->backarea == s) break;\n\t\t\t} //end for\n\t\t\t//if the face was a shared one\n\t\t\tif (s != numareas) continue;\n\t\t\t//\n\t\t\tfor (j = 0; j < numareas; j++)\n\t\t\t{\n\t\t\t\tif (j == i) continue;\n\t\t\t\tarea2 = &aasworld.areas[areanums[j]];\n\t\t\t\tfor (fn2 = 0; fn2 < area2->numfaces; fn2++)\n\t\t\t\t{\n\t\t\t\t\tface2num = abs(aasworld.faceindex[area2->firstface + fn2]);\n\t\t\t\t\tface2 = &aasworld.faces[face2num];\n\t\t\t\t\tside2 = face2->frontarea != areanums[j];\n\t\t\t\t\t//check if the face isn't a shared one with one of the other areas\n\t\t\t\t\tfor (s = 0; s < numareas; s++)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (s == j) continue;\n\t\t\t\t\t\tif (face2->frontarea == s || face2->backarea == s) break;\n\t\t\t\t\t} //end for\n\t\t\t\t\t//if the face was a shared one\n\t\t\t\t\tif (s != numareas) continue;\n\t\t\t\t\t//\n\t\t\t\t\tif (AAS_NonConvexFaces(face1, face2, side1, side2)) return qfalse;\n\t\t\t\t} //end for\n\t\t\t} //end for\n\t\t} //end for\n\t} //end for\n\treturn qtrue;\n} //end of the function AAS_CanMergeAreas\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nqboolean AAS_NonConvexEdges(aas_edge_t *edge1, aas_edge_t *edge2, int side1, int side2, int planenum)\n{\n\tint i;\n\tvec3_t edgevec1, edgevec2, normal1, normal2;\n\tfloat dist1, dist2;\n\taas_plane_t *plane;\n\n\tplane = &aasworld.planes[planenum];\n\tVectorSubtract(aasworld.vertexes[edge1->v[1]], aasworld.vertexes[edge1->v[0]], edgevec1);\n\tVectorSubtract(aasworld.vertexes[edge2->v[1]], aasworld.vertexes[edge2->v[0]], edgevec2);\n\tif (side1) VectorInverse(edgevec1);\n\tif (side2) VectorInverse(edgevec2);\n\t//\n\tCrossProduct(edgevec1, plane->normal, normal1);\n\tdist1 = DotProduct(normal1, aasworld.vertexes[edge1->v[0]]);\n\tCrossProduct(edgevec2, plane->normal, normal2);\n\tdist2 = DotProduct(normal2, aasworld.vertexes[edge2->v[0]]);\n\n\tfor (i = 0; i < 2; i++)\n\t{\n\t\tif (DotProduct(aasworld.vertexes[edge1->v[i]], normal2) - dist2 < -0.01) return qfalse;\n\t} //end for\n\tfor (i = 0; i < 2; i++)\n\t{\n\t\tif (DotProduct(aasworld.vertexes[edge2->v[i]], normal1) - dist1 < -0.01) return qfalse;\n\t} //end for\n\treturn qtrue;\n} //end of the function AAS_NonConvexEdges\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nqboolean AAS_CanMergeFaces(int *facenums, int numfaces, int planenum)\n{\n\tint i, j, s, edgenum1, edgenum2, side1, side2, en1, en2, ens;\n\taas_face_t *face1, *face2, *otherface;\n\taas_edge_t *edge1, *edge2;\n\n\tfor (i = 0; i < numfaces; i++)\n\t{\n\t\tface1 = &aasworld.faces[facenums[i]];\n\t\tfor (en1 = 0; en1 < face1->numedges; en1++)\n\t\t{\n\t\t\tedgenum1 = aasworld.edgeindex[face1->firstedge + en1];\n\t\t\tside1 = (edgenum1 < 0) ^ (face1->planenum != planenum);\n\t\t\tedgenum1 = abs(edgenum1);\n\t\t\tedge1 = &aasworld.edges[edgenum1];\n\t\t\t//check if the edge is shared with another face\n\t\t\tfor (s = 0; s < numfaces; s++)\n\t\t\t{\n\t\t\t\tif (s == i) continue;\n\t\t\t\totherface = &aasworld.faces[facenums[s]];\n\t\t\t\tfor (ens = 0; ens < otherface->numedges; ens++)\n\t\t\t\t{\n\t\t\t\t\tif (edgenum1 == abs(aasworld.edgeindex[otherface->firstedge + ens])) break;\n\t\t\t\t} //end for\n\t\t\t\tif (ens != otherface->numedges) break;\n\t\t\t} //end for\n\t\t\t//if the edge was shared\n\t\t\tif (s != numfaces) continue;\n\t\t\t//\n\t\t\tfor (j = 0; j < numfaces; j++)\n\t\t\t{\n\t\t\t\tif (j == i) continue;\n\t\t\t\tface2 = &aasworld.faces[facenums[j]];\n\t\t\t\tfor (en2 = 0; en2 < face2->numedges; en2++)\n\t\t\t\t{\n\t\t\t\t\tedgenum2 = aasworld.edgeindex[face2->firstedge + en2];\n\t\t\t\t\tside2 = (edgenum2 < 0) ^ (face2->planenum != planenum);\n\t\t\t\t\tedgenum2 = abs(edgenum2);\n\t\t\t\t\tedge2 = &aasworld.edges[edgenum2];\n\t\t\t\t\t//check if the edge is shared with another face\n\t\t\t\t\tfor (s = 0; s < numfaces; s++)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (s == i) continue;\n\t\t\t\t\t\totherface = &aasworld.faces[facenums[s]];\n\t\t\t\t\t\tfor (ens = 0; ens < otherface->numedges; ens++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (edgenum2 == abs(aasworld.edgeindex[otherface->firstedge + ens])) break;\n\t\t\t\t\t\t} //end for\n\t\t\t\t\t\tif (ens != otherface->numedges) break;\n\t\t\t\t\t} //end for\n\t\t\t\t\t//if the edge was shared\n\t\t\t\t\tif (s != numfaces) continue;\n\t\t\t\t\t//\n\t\t\t\t\tif (AAS_NonConvexEdges(edge1, edge2, side1, side2, planenum)) return qfalse;\n\t\t\t\t} //end for\n\t\t\t} //end for\n\t\t} //end for\n\t} //end for\n\treturn qtrue;\n} //end of the function AAS_CanMergeFaces*/\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_ConnectedAreas_r(int *areanums, int numareas, int *connectedareas, int curarea)\n{\n\tint i, j, otherareanum, facenum;\n\taas_area_t *area;\n\taas_face_t *face;\n\n\tconnectedareas[curarea] = qtrue;\n\tarea = &aasworld.areas[areanums[curarea]];\n\tfor (i = 0; i < area->numfaces; i++)\n\t{\n\t\tfacenum = abs(aasworld.faceindex[area->firstface + i]);\n\t\tface = &aasworld.faces[facenum];\n\t\t//if the face is solid\n\t\tif (face->faceflags & FACE_SOLID) continue;\n\t\t//get the area at the other side of the face\n\t\tif (face->frontarea != areanums[curarea]) otherareanum = face->frontarea;\n\t\telse otherareanum = face->backarea;\n\t\t//check if the face is leading to one of the other areas\n\t\tfor (j = 0; j < numareas; j++)\n\t\t{\n\t\t\tif (areanums[j] == otherareanum) break;\n\t\t} //end for\n\t\t//if the face isn't leading to one of the other areas\n\t\tif (j == numareas) continue;\n\t\t//if the other area is already connected\n\t\tif (connectedareas[j]) continue;\n\t\t//recursively proceed with the other area\n\t\tAAS_ConnectedAreas_r(areanums, numareas, connectedareas, j);\n\t} //end for\n} //end of the function AAS_ConnectedAreas_r\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nqboolean AAS_ConnectedAreas(int *areanums, int numareas)\n{\n\tint connectedareas[MAX_PORTALAREAS], i;\n\n\tCom_Memset(connectedareas, 0, sizeof(connectedareas));\n\tif (numareas < 1) return qfalse;\n\tif (numareas == 1) return qtrue;\n\tAAS_ConnectedAreas_r(areanums, numareas, connectedareas, 0);\n\tfor (i = 0; i < numareas; i++)\n\t{\n\t\tif (!connectedareas[i]) return qfalse;\n\t} //end for\n\treturn qtrue;\n} //end of the function AAS_ConnectedAreas\n//===========================================================================\n// gets adjacent areas with less presence types recursively\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_GetAdjacentAreasWithLessPresenceTypes_r(int *areanums, int numareas, int curareanum)\n{\n\tint i, j, presencetype, otherpresencetype, otherareanum, facenum;\n\taas_area_t *area;\n\taas_face_t *face;\n\n\tareanums[numareas++] = curareanum;\n\tarea = &aasworld.areas[curareanum];\n\tpresencetype = aasworld.areasettings[curareanum].presencetype;\n\tfor (i = 0; i < area->numfaces; i++)\n\t{\n\t\tfacenum = abs(aasworld.faceindex[area->firstface + i]);\n\t\tface = &aasworld.faces[facenum];\n\t\t//if the face is solid\n\t\tif (face->faceflags & FACE_SOLID) continue;\n\t\t//the area at the other side of the face\n\t\tif (face->frontarea != curareanum) otherareanum = face->frontarea;\n\t\telse otherareanum = face->backarea;\n\t\t//\n\t\totherpresencetype = aasworld.areasettings[otherareanum].presencetype;\n\t\t//if the other area has less presence types\n\t\tif ((presencetype & ~otherpresencetype) &&\n\t\t\t\t!(otherpresencetype & ~presencetype))\n\t\t{\n\t\t\t//check if the other area isn't already in the list\n\t\t\tfor (j = 0; j < numareas; j++)\n\t\t\t{\n\t\t\t\tif (otherareanum == areanums[j]) break;\n\t\t\t} //end for\n\t\t\t//if the other area isn't already in the list\n\t\t\tif (j == numareas)\n\t\t\t{\n\t\t\t\tif (numareas >= MAX_PORTALAREAS)\n\t\t\t\t{\n\t\t\t\t\tAAS_Error(\"MAX_PORTALAREAS\");\n\t\t\t\t\treturn numareas;\n\t\t\t\t} //end if\n\t\t\t\tnumareas = AAS_GetAdjacentAreasWithLessPresenceTypes_r(areanums, numareas, otherareanum);\n\t\t\t} //end if\n\t\t} //end if\n\t} //end for\n\treturn numareas;\n} //end of the function AAS_GetAdjacentAreasWithLessPresenceTypes_r\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_CheckAreaForPossiblePortals(int areanum)\n{\n\tint i, j, k, fen, ben, frontedgenum, backedgenum, facenum;\n\tint areanums[MAX_PORTALAREAS], numareas, otherareanum;\n\tint numareafrontfaces[MAX_PORTALAREAS], numareabackfaces[MAX_PORTALAREAS];\n\tint frontfacenums[MAX_PORTALAREAS], backfacenums[MAX_PORTALAREAS];\n\tint numfrontfaces, numbackfaces;\n\tint frontareanums[MAX_PORTALAREAS], backareanums[MAX_PORTALAREAS];\n\tint numfrontareas, numbackareas;\n\tint frontplanenum, backplanenum, faceplanenum;\n\taas_area_t *area;\n\taas_face_t *frontface, *backface, *face;\n\n\t//if it isn't already a portal\n\tif (aasworld.areasettings[areanum].contents & AREACONTENTS_CLUSTERPORTAL) return 0;\n\t//it must be a grounded area\n\tif (!(aasworld.areasettings[areanum].areaflags & AREA_GROUNDED)) return 0;\n\t//\n\tCom_Memset(numareafrontfaces, 0, sizeof(numareafrontfaces));\n\tCom_Memset(numareabackfaces, 0, sizeof(numareabackfaces));\n\tnumareas = numfrontfaces = numbackfaces = 0;\n\tnumfrontareas = numbackareas = 0;\n\tfrontplanenum = backplanenum = -1;\n\t//add any adjacent areas with less presence types\n\tnumareas = AAS_GetAdjacentAreasWithLessPresenceTypes_r(areanums, 0, areanum);\n\t//\n\tfor (i = 0; i < numareas; i++)\n\t{\n\t\tarea = &aasworld.areas[areanums[i]];\n\t\tfor (j = 0; j < area->numfaces; j++)\n\t\t{\n\t\t\tfacenum = abs(aasworld.faceindex[area->firstface + j]);\n\t\t\tface = &aasworld.faces[facenum];\n\t\t\t//if the face is solid\n\t\t\tif (face->faceflags & FACE_SOLID) continue;\n\t\t\t//check if the face is shared with one of the other areas\n\t\t\tfor (k = 0; k < numareas; k++)\n\t\t\t{\n\t\t\t\tif (k == i) continue;\n\t\t\t\tif (face->frontarea == areanums[k] || face->backarea == areanums[k]) break;\n\t\t\t} //end for\n\t\t\t//if the face is shared\n\t\t\tif (k != numareas) continue;\n\t\t\t//the number of the area at the other side of the face\n\t\t\tif (face->frontarea == areanums[i]) otherareanum = face->backarea;\n\t\t\telse otherareanum = face->frontarea;\n\t\t\t//if the other area already is a cluter portal\n\t\t\tif (aasworld.areasettings[otherareanum].contents & AREACONTENTS_CLUSTERPORTAL) return 0;\n\t\t\t//number of the plane of the area\n\t\t\tfaceplanenum = face->planenum & ~1;\n\t\t\t//\n\t\t\tif (frontplanenum < 0 || faceplanenum == frontplanenum)\n\t\t\t{\n\t\t\t\tfrontplanenum = faceplanenum;\n\t\t\t\tfrontfacenums[numfrontfaces++] = facenum;\n\t\t\t\tfor (k = 0; k < numfrontareas; k++)\n\t\t\t\t{\n\t\t\t\t\tif (frontareanums[k] == otherareanum) break;\n\t\t\t\t} //end for\n\t\t\t\tif (k == numfrontareas) frontareanums[numfrontareas++] = otherareanum;\n\t\t\t\tnumareafrontfaces[i]++;\n\t\t\t} //end if\n\t\t\telse if (backplanenum < 0 || faceplanenum == backplanenum)\n\t\t\t{\n\t\t\t\tbackplanenum = faceplanenum;\n\t\t\t\tbackfacenums[numbackfaces++] = facenum;\n\t\t\t\tfor (k = 0; k < numbackareas; k++)\n\t\t\t\t{\n\t\t\t\t\tif (backareanums[k] == otherareanum) break;\n\t\t\t\t} //end for\n\t\t\t\tif (k == numbackareas) backareanums[numbackareas++] = otherareanum;\n\t\t\t\tnumareabackfaces[i]++;\n\t\t\t} //end else\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t} //end else\n\t\t} //end for\n\t} //end for\n\t//every area should have at least one front face and one back face\n\tfor (i = 0; i < numareas; i++)\n\t{\n\t\tif (!numareafrontfaces[i] || !numareabackfaces[i]) return 0;\n\t} //end for\n\t//the front areas should all be connected\n\tif (!AAS_ConnectedAreas(frontareanums, numfrontareas)) return 0;\n\t//the back areas should all be connected\n\tif (!AAS_ConnectedAreas(backareanums, numbackareas)) return 0;\n\t//none of the front faces should have a shared edge with a back face\n\tfor (i = 0; i < numfrontfaces; i++)\n\t{\n\t\tfrontface = &aasworld.faces[frontfacenums[i]];\n\t\tfor (fen = 0; fen < frontface->numedges; fen++)\n\t\t{\n\t\t\tfrontedgenum = abs(aasworld.edgeindex[frontface->firstedge + fen]);\n\t\t\tfor (j = 0; j < numbackfaces; j++)\n\t\t\t{\n\t\t\t\tbackface = &aasworld.faces[backfacenums[j]];\n\t\t\t\tfor (ben = 0; ben < backface->numedges; ben++)\n\t\t\t\t{\n\t\t\t\t\tbackedgenum = abs(aasworld.edgeindex[backface->firstedge + ben]);\n\t\t\t\t\tif (frontedgenum == backedgenum) break;\n\t\t\t\t} //end for\n\t\t\t\tif (ben != backface->numedges) break;\n\t\t\t} //end for\n\t\t\tif (j != numbackfaces) break;\n\t\t} //end for\n\t\tif (fen != frontface->numedges) break;\n\t} //end for\n\tif (i != numfrontfaces) return 0;\n\t//set the cluster portal contents\n\tfor (i = 0; i < numareas; i++)\n\t{\n\t\taasworld.areasettings[areanums[i]].contents |= AREACONTENTS_CLUSTERPORTAL;\n\t\t//this area can be used as a route portal\n\t\taasworld.areasettings[areanums[i]].contents |= AREACONTENTS_ROUTEPORTAL;\n\t\tLog_Write(\"possible portal: %d\\r\\n\", areanums[i]);\n\t} //end for\n\t//\n\treturn numareas;\n} //end of the function AAS_CheckAreaForPossiblePortals\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_FindPossiblePortals(void)\n{\n\tint i, numpossibleportals;\n\n\tnumpossibleportals = 0;\n\tfor (i = 1; i < aasworld.numareas; i++)\n\t{\n\t\tnumpossibleportals += AAS_CheckAreaForPossiblePortals(i);\n\t} //end for\n\tbotimport.Print(PRT_MESSAGE, \"\\r%6d possible portal areas\\n\", numpossibleportals);\n} //end of the function AAS_FindPossiblePortals\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_RemoveAllPortals(void)\n{\n\tint i;\n\n\tfor (i = 1; i < aasworld.numareas; i++)\n\t{\n\t\taasworld.areasettings[i].contents &= ~AREACONTENTS_CLUSTERPORTAL;\n\t} //end for\n} //end of the function AAS_RemoveAllPortals\n\n#if 0\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_FloodCluster_r(int areanum, int clusternum)\n{\n\tint i, otherareanum;\n\taas_face_t *face;\n\taas_area_t *area;\n\n\t//set cluster mark\n\taasworld.areasettings[areanum].cluster = clusternum;\n\t//if the area is a portal\n\t//if (aasworld.areasettings[areanum].contents & AREACONTENTS_CLUSTERPORTAL) return;\n\t//\n\tarea = &aasworld.areas[areanum];\n\t//use area faces to flood into adjacent areas\n\tfor (i = 0; i < area->numfaces; i++)\n\t{\n\t\tface = &aasworld.faces[abs(aasworld.faceindex[area->firstface + i])];\n\t\t//\n\t\tif (face->frontarea != areanum) otherareanum = face->frontarea;\n\t\telse otherareanum = face->backarea;\n\t\t//if there's no area at the other side\n\t\tif (!otherareanum) continue;\n\t\t//if the area is a portal\n\t\tif (aasworld.areasettings[otherareanum].contents & AREACONTENTS_CLUSTERPORTAL) continue;\n\t\t//if the area is already marked\n\t\tif (aasworld.areasettings[otherareanum].cluster) continue;\n\t\t//\n\t\tAAS_FloodCluster_r(otherareanum, clusternum);\n\t} //end for\n\t//use the reachabilities to flood into other areas\n\tfor (i = 0; i < aasworld.areasettings[areanum].numreachableareas; i++)\n\t{\n\t\totherareanum = aasworld.reachability[\n\t\t\t\t\taasworld.areasettings[areanum].firstreachablearea + i].areanum;\n\t\tif (!otherareanum)\n\t\t{\n\t\t\tcontinue;\n\t\t\tAAS_Error(\"reachability %d has zero area\\n\", aasworld.areasettings[areanum].firstreachablearea + i);\n\t\t} //end if\n\t\t//if the area is a portal\n\t\tif (aasworld.areasettings[otherareanum].contents & AREACONTENTS_CLUSTERPORTAL) continue;\n\t\t//if the area is already marked\n\t\tif (aasworld.areasettings[otherareanum].cluster) continue;\n\t\t//\n\t\tAAS_FloodCluster_r(otherareanum, clusternum);\n\t} //end for\n} //end of the function AAS_FloodCluster_r\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_RemoveTeleporterPortals(void)\n{\n\tint i, j, areanum;\n\n\tfor (i = 1; i < aasworld.numareas; i++)\n\t{\n\t\tfor (j = 0; j < aasworld.areasettings[i].numreachableareas; j++)\n\t\t{\n\t\t\tareanum = aasworld.reachability[aasworld.areasettings[i].firstreachablearea + j].areanum;\n\t\t\tif (aasworld.reachability[aasworld.areasettings[i].firstreachablearea + j].traveltype == TRAVEL_TELEPORT)\n\t\t\t{\n\t\t\t\taasworld.areasettings[i].contents &= ~AREACONTENTS_CLUSTERPORTAL;\n\t\t\t\taasworld.areasettings[areanum].contents &= ~AREACONTENTS_CLUSTERPORTAL;\n\t\t\t\tbreak;\n\t\t\t} //end if\n\t\t} //end for\n\t} //end for\n} //end of the function AAS_RemoveTeleporterPortals\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_FloodClusterReachabilities(int clusternum)\n{\n\tint i, j, areanum;\n\n\tfor (i = 1; i < aasworld.numareas; i++)\n\t{\n\t\t//if this area already has a cluster set\n\t\tif (aasworld.areasettings[i].cluster) continue;\n\t\t//if this area is a cluster portal\n\t\tif (aasworld.areasettings[i].contents & AREACONTENTS_CLUSTERPORTAL) continue;\n\t\t//loop over the reachable areas from this area\n\t\tfor (j = 0; j < aasworld.areasettings[i].numreachableareas; j++)\n\t\t{\n\t\t\t//the reachable area\n\t\t\tareanum = aasworld.reachability[aasworld.areasettings[i].firstreachablearea + j].areanum;\n\t\t\t//if this area is a cluster portal\n\t\t\tif (aasworld.areasettings[areanum].contents & AREACONTENTS_CLUSTERPORTAL) continue;\n\t\t\t//if this area has a cluster set\n\t\t\tif (aasworld.areasettings[areanum].cluster == clusternum)\n\t\t\t{\n\t\t\t\tAAS_FloodCluster_r(i, clusternum);\n\t\t\t\ti = 0;\n\t\t\t\tbreak;\n\t\t\t} //end if\n\t\t} //end for\n\t} //end for\n} //end of the function AAS_FloodClusterReachabilities\n\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_RemoveNotClusterClosingPortals(void)\n{\n\tint i, j, k, facenum, otherareanum, nonclosingportals;\n\taas_area_t *area;\n\taas_face_t *face;\n\n\tAAS_RemoveTeleporterPortals();\n\t//\n\tnonclosingportals = 0;\n\tfor (i = 1; i < aasworld.numareas; i++)\n\t{\n\t\tif (!(aasworld.areasettings[i].contents & AREACONTENTS_CLUSTERPORTAL)) continue;\n\t\t//find a non-portal area adjacent to the portal area and flood\n\t\t//the cluster from there\n\t\tarea = &aasworld.areas[i];\n\t\tfor (j = 0; j < area->numfaces; j++)\n\t\t{\n\t\t\tfacenum = abs(aasworld.faceindex[area->firstface + j]);\n\t\t\tface = &aasworld.faces[facenum];\n\t\t\t//\n\t\t\tif (face->frontarea != i) otherareanum = face->frontarea;\n\t\t\telse otherareanum = face->backarea;\n\t\t\t//\n\t\t\tif (!otherareanum) continue;\n\t\t\t//\n\t\t\tif (aasworld.areasettings[otherareanum].contents & AREACONTENTS_CLUSTERPORTAL)\n\t\t\t{\n\t\t\t\tcontinue;\n\t\t\t} //end if\n\t\t\t//reset all cluster fields\n\t\t\tAAS_RemoveClusterAreas();\n\t\t\t//\n\t\t\tAAS_FloodCluster_r(otherareanum, 1);\n\t\t\tAAS_FloodClusterReachabilities(1);\n\t\t\t//check if all adjacent non-portal areas have a cluster set\n\t\t\tfor (k = 0; k < area->numfaces; k++)\n\t\t\t{\n\t\t\t\tfacenum = abs(aasworld.faceindex[area->firstface + k]);\n\t\t\t\tface = &aasworld.faces[facenum];\n\t\t\t\t//\n\t\t\t\tif (face->frontarea != i) otherareanum = face->frontarea;\n\t\t\t\telse otherareanum = face->backarea;\n\t\t\t\t//\n\t\t\t\tif (!otherareanum) continue;\n\t\t\t\t//\n\t\t\t\tif (aasworld.areasettings[otherareanum].contents & AREACONTENTS_CLUSTERPORTAL)\n\t\t\t\t{\n\t\t\t\t\tcontinue;\n\t\t\t\t} //end if\n\t\t\t\t//\n\t\t\t\tif (!aasworld.areasettings[otherareanum].cluster) break;\n\t\t\t} //end for\n\t\t\t//if all adjacent non-portal areas have a cluster set then the portal\n\t\t\t//didn't seal a cluster\n\t\t\tif (k >= area->numfaces)\n\t\t\t{\n\t\t\t\taasworld.areasettings[i].contents &= ~AREACONTENTS_CLUSTERPORTAL;\n\t\t\t\tnonclosingportals++;\n\t\t\t\t//recheck all the other portals again\n\t\t\t\ti = 0;\n\t\t\t\tbreak;\n\t\t\t} //end if\n\t\t} //end for\n\t} //end for\n\tbotimport.Print(PRT_MESSAGE, \"\\r%6d non closing portals removed\\n\", nonclosingportals);\n} //end of the function AAS_RemoveNotClusterClosingPortals\n\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\n\nvoid AAS_RemoveNotClusterClosingPortals(void)\n{\n\tint i, j, facenum, otherareanum, nonclosingportals, numseperatedclusters;\n\taas_area_t *area;\n\taas_face_t *face;\n\n\tAAS_RemoveTeleporterPortals();\n\t//\n\tnonclosingportals = 0;\n\tfor (i = 1; i < aasworld.numareas; i++)\n\t{\n\t\tif (!(aasworld.areasettings[i].contents & AREACONTENTS_CLUSTERPORTAL)) continue;\n\t\t//\n\t\tnumseperatedclusters = 0;\n\t\t//reset all cluster fields\n\t\tAAS_RemoveClusterAreas();\n\t\t//find a non-portal area adjacent to the portal area and flood\n\t\t//the cluster from there\n\t\tarea = &aasworld.areas[i];\n\t\tfor (j = 0; j < area->numfaces; j++)\n\t\t{\n\t\t\tfacenum = abs(aasworld.faceindex[area->firstface + j]);\n\t\t\tface = &aasworld.faces[facenum];\n\t\t\t//\n\t\t\tif (face->frontarea != i) otherareanum = face->frontarea;\n\t\t\telse otherareanum = face->backarea;\n\t\t\t//if not solid at the other side of the face\n\t\t\tif (!otherareanum) continue;\n\t\t\t//don't flood into other portals\n\t\t\tif (aasworld.areasettings[otherareanum].contents & AREACONTENTS_CLUSTERPORTAL) continue;\n\t\t\t//if the area already has a cluster set\n\t\t\tif (aasworld.areasettings[otherareanum].cluster) continue;\n\t\t\t//another cluster is seperated by this portal\n\t\t\tnumseperatedclusters++;\n\t\t\t//flood the cluster\n\t\t\tAAS_FloodCluster_r(otherareanum, numseperatedclusters);\n\t\t\tAAS_FloodClusterReachabilities(numseperatedclusters);\n\t\t} //end for\n\t\t//use the reachabilities to flood into other areas\n\t\tfor (j = 0; j < aasworld.areasettings[i].numreachableareas; j++)\n\t\t{\n\t\t\totherareanum = aasworld.reachability[\n\t\t\t\t\t\taasworld.areasettings[i].firstreachablearea + j].areanum;\n\t\t\t//this should never be qtrue but we check anyway\n\t\t\tif (!otherareanum) continue;\n\t\t\t//don't flood into other portals\n\t\t\tif (aasworld.areasettings[otherareanum].contents & AREACONTENTS_CLUSTERPORTAL) continue;\n\t\t\t//if the area already has a cluster set\n\t\t\tif (aasworld.areasettings[otherareanum].cluster) continue;\n\t\t\t//another cluster is seperated by this portal\n\t\t\tnumseperatedclusters++;\n\t\t\t//flood the cluster\n\t\t\tAAS_FloodCluster_r(otherareanum, numseperatedclusters);\n\t\t\tAAS_FloodClusterReachabilities(numseperatedclusters);\n\t\t} //end for\n\t\t//a portal must seperate no more and no less than 2 clusters\n\t\tif (numseperatedclusters != 2)\n\t\t{\n\t\t\taasworld.areasettings[i].contents &= ~AREACONTENTS_CLUSTERPORTAL;\n\t\t\tnonclosingportals++;\n\t\t\t//recheck all the other portals again\n\t\t\ti = 0;\n\t\t} //end if\n\t} //end for\n\tbotimport.Print(PRT_MESSAGE, \"\\r%6d non closing portals removed\\n\", nonclosingportals);\n} //end of the function AAS_RemoveNotClusterClosingPortals\n\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\n\nvoid AAS_AddTeleporterPortals(void)\n{\n\tint j, area2num, facenum, otherareanum;\n\tchar *target, *targetname, *classname;\n\tbsp_entity_t *entities, *ent, *dest;\n\tvec3_t origin, destorigin, mins, maxs, end;\n\tvec3_t bbmins, bbmaxs;\n\taas_area_t *area;\n\taas_face_t *face;\n\taas_trace_t trace;\n\taas_link_t *areas, *link;\n\n\tentities = AAS_ParseBSPEntities();\n\n\tfor (ent = entities; ent; ent = ent->next)\n\t{\n\t\tclassname = AAS_ValueForBSPEpairKey(ent, \"classname\");\n\t\tif (classname && !strcmp(classname, \"misc_teleporter\"))\n\t\t{\n\t\t\tif (!AAS_VectorForBSPEpairKey(ent, \"origin\", origin))\n\t\t\t{\n\t\t\t\tbotimport.Print(PRT_ERROR, \"teleporter (%s) without origin\\n\", target);\n\t\t\t\tcontinue;\n\t\t\t} //end if\n\t\t\t//\n\t\t\ttarget = AAS_ValueForBSPEpairKey(ent, \"target\");\n\t\t\tif (!target)\n\t\t\t{\n\t\t\t\tbotimport.Print(PRT_ERROR, \"teleporter (%s) without target\\n\", target);\n\t\t\t\tcontinue;\n\t\t\t} //end if\n\t\t\tfor (dest = entities; dest; dest = dest->next)\n\t\t\t{\n\t\t\t\tclassname = AAS_ValueForBSPEpairKey(dest, \"classname\");\n\t\t\t\tif (classname && !strcmp(classname, \"misc_teleporter_dest\"))\n\t\t\t\t{\n\t\t\t\t\ttargetname = AAS_ValueForBSPEpairKey(dest, \"targetname\");\n\t\t\t\t\tif (targetname && !strcmp(targetname, target))\n\t\t\t\t\t{\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t} //end if\n\t\t\t\t} //end if\n\t\t\t} //end for\n\t\t\tif (!dest)\n\t\t\t{\n\t\t\t\tbotimport.Print(PRT_ERROR, \"teleporter without destination (%s)\\n\", target);\n\t\t\t\tcontinue;\n\t\t\t} //end if\n\t\t\tif (!AAS_VectorForBSPEpairKey(dest, \"origin\", destorigin))\n\t\t\t{\n\t\t\t\tbotimport.Print(PRT_ERROR, \"teleporter destination (%s) without origin\\n\", target);\n\t\t\t\tcontinue;\n\t\t\t} //end if\n\t\t\tdestorigin[2] += 24; //just for q2e1m2, the dork has put the telepads in the ground\n\t\t\tVectorCopy(destorigin, end);\n\t\t\tend[2] -= 100;\n\t\t\ttrace = AAS_TraceClientBBox(destorigin, end, PRESENCE_CROUCH, -1);\n\t\t\tif (trace.startsolid)\n\t\t\t{\n\t\t\t\tbotimport.Print(PRT_ERROR, \"teleporter destination (%s) in solid\\n\", target);\n\t\t\t\tcontinue;\n\t\t\t} //end if\n\t\t\tVectorCopy(trace.endpos, destorigin);\n\t\t\tarea2num = AAS_PointAreaNum(destorigin);\n\t\t\t//reset all cluster fields\n\t\t\tfor (j = 0; j < aasworld.numareas; j++)\n\t\t\t{\n\t\t\t\taasworld.areasettings[j].cluster = 0;\n\t\t\t} //end for\n\t\t\t//\n\t\t\tVectorSet(mins, -8, -8, 8);\n\t\t\tVectorSet(maxs, 8, 8, 24);\n\t\t\t//\n\t\t\tAAS_PresenceTypeBoundingBox(PRESENCE_CROUCH, bbmins, bbmaxs);\n\t\t\t//\n\t\t\tVectorAdd(origin, mins, mins);\n\t\t\tVectorAdd(origin, maxs, maxs);\n\t\t\t//add bounding box size\n\t\t\tVectorSubtract(mins, bbmaxs, mins);\n\t\t\tVectorSubtract(maxs, bbmins, maxs);\n\t\t\t//link an invalid (-1) entity\n\t\t\tareas = AAS_AASLinkEntity(mins, maxs, -1);\n\t\t\t//\n\t\t\tfor (link = areas; link; link = link->next_area)\n\t\t\t{\n\t\t\t\tif (!AAS_AreaGrounded(link->areanum)) continue;\n\t\t\t\t//add the teleporter portal mark\n\t\t\t\taasworld.areasettings[link->areanum].contents |= AREACONTENTS_CLUSTERPORTAL |\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tAREACONTENTS_TELEPORTAL;\n\t\t\t} //end for\n\t\t\t//\n\t\t\tfor (link = areas; link; link = link->next_area)\n\t\t\t{\n\t\t\t\tif (!AAS_AreaGrounded(link->areanum)) continue;\n\t\t\t\t//find a non-portal area adjacent to the portal area and flood\n\t\t\t\t//the cluster from there\n\t\t\t\tarea = &aasworld.areas[link->areanum];\n\t\t\t\tfor (j = 0; j < area->numfaces; j++)\n\t\t\t\t{\n\t\t\t\t\tfacenum = abs(aasworld.faceindex[area->firstface + j]);\n\t\t\t\t\tface = &aasworld.faces[facenum];\n\t\t\t\t\t//\n\t\t\t\t\tif (face->frontarea != link->areanum) otherareanum = face->frontarea;\n\t\t\t\t\telse otherareanum = face->backarea;\n\t\t\t\t\t//\n\t\t\t\t\tif (!otherareanum) continue;\n\t\t\t\t\t//\n\t\t\t\t\tif (aasworld.areasettings[otherareanum].contents & AREACONTENTS_CLUSTERPORTAL)\n\t\t\t\t\t{\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t} //end if\n\t\t\t\t\t//\n\t\t\t\t\tAAS_FloodCluster_r(otherareanum, 1);\n\t\t\t\t} //end for\n\t\t\t} //end for\n\t\t\t//if the teleport destination IS in the same cluster\n\t\t\tif (aasworld.areasettings[area2num].cluster)\n\t\t\t{\n\t\t\t\tfor (link = areas; link; link = link->next_area)\n\t\t\t\t{\n\t\t\t\t\tif (!AAS_AreaGrounded(link->areanum)) continue;\n\t\t\t\t\t//add the teleporter portal mark\n\t\t\t\t\taasworld.areasettings[link->areanum].contents &= ~(AREACONTENTS_CLUSTERPORTAL |\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tAREACONTENTS_TELEPORTAL);\n\t\t\t\t} //end for\n\t\t\t} //end if\n\t\t} //end if\n\t} //end for\n\tAAS_FreeBSPEntities(entities);\n} //end of the function AAS_AddTeleporterPortals\n\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_AddTeleporterPortals(void)\n{\n\tint i, j, areanum;\n\n\tfor (i = 1; i < aasworld.numareas; i++)\n\t{\n\t\tfor (j = 0; j < aasworld.areasettings[i].numreachableareas; j++)\n\t\t{\n\t\t\tif (aasworld.reachability[aasworld.areasettings[i].firstreachablearea + j].traveltype != TRAVEL_TELEPORT) continue;\n\t\t\tareanum = aasworld.reachability[aasworld.areasettings[i].firstreachablearea + j].areanum;\n\t\t\taasworld.areasettings[areanum].contents |= AREACONTENTS_CLUSTERPORTAL;\n\t\t} //end for\n\t} //end for\n} //end of the function AAS_AddTeleporterPortals\n\n#endif\n\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_TestPortals(void)\n{\n\tint i;\n\taas_portal_t *portal;\n\n\tfor (i = 1; i < aasworld.numportals; i++)\n\t{\n\t\tportal = &aasworld.portals[i];\n\t\tif (!portal->frontcluster)\n\t\t{\n\t\t\taasworld.areasettings[portal->areanum].contents &= ~AREACONTENTS_CLUSTERPORTAL;\n\t\t\tLog_Write(\"portal area %d has no front cluster\\r\\n\", portal->areanum);\n\t\t\treturn qfalse;\n\t\t} //end if\n\t\tif (!portal->backcluster)\n\t\t{\n\t\t\taasworld.areasettings[portal->areanum].contents &= ~AREACONTENTS_CLUSTERPORTAL;\n\t\t\tLog_Write(\"portal area %d has no back cluster\\r\\n\", portal->areanum);\n\t\t\treturn qfalse;\n\t\t} //end if\n\t} //end for\n\treturn qtrue;\n} //end of the function\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_CountForcedClusterPortals(void)\n{\n\tint num, i;\n\n\tnum = 0;\n\tfor (i = 1; i < aasworld.numareas; i++)\n\t{\n\t\tif (aasworld.areasettings[i].contents & AREACONTENTS_CLUSTERPORTAL)\n\t\t{\n\t\t\tLog_Write(\"area %d is a forced portal area\\r\\n\", i);\n\t\t\tnum++;\n\t\t} //end if\n\t} //end for\n\tbotimport.Print(PRT_MESSAGE, \"%6d forced portal areas\\n\", num);\n} //end of the function AAS_CountForcedClusterPortals\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_CreateViewPortals(void)\n{\n\tint i;\n\n\tfor (i = 1; i < aasworld.numareas; i++)\n\t{\n\t\tif (aasworld.areasettings[i].contents & AREACONTENTS_CLUSTERPORTAL)\n\t\t{\n\t\t\taasworld.areasettings[i].contents |= AREACONTENTS_VIEWPORTAL;\n\t\t} //end if\n\t} //end for\n} //end of the function AAS_CreateViewPortals\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_SetViewPortalsAsClusterPortals(void)\n{\n\tint i;\n\n\tfor (i = 1; i < aasworld.numareas; i++)\n\t{\n\t\tif (aasworld.areasettings[i].contents & AREACONTENTS_VIEWPORTAL)\n\t\t{\n\t\t\taasworld.areasettings[i].contents |= AREACONTENTS_CLUSTERPORTAL;\n\t\t} //end if\n\t} //end for\n} //end of the function AAS_SetViewPortalsAsClusterPortals\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_InitClustering(void)\n{\n\tint i, removedPortalAreas;\n\tint n, total, numreachabilityareas;\n\n\tif (!aasworld.loaded) return;\n\t//if there are clusters\n\tif (aasworld.numclusters >= 1)\n\t{\n#ifndef BSPC\n\t\t//if clustering isn't forced\n\t\tif (!((int)LibVarGetValue(\"forceclustering\")) &&\n\t\t\t!((int)LibVarGetValue(\"forcereachability\"))) return;\n#endif\n\t} //end if\n\t//set all view portals as cluster portals in case we re-calculate the reachabilities and clusters (with -reach)\n\tAAS_SetViewPortalsAsClusterPortals();\n\t//count the number of forced cluster portals\n\tAAS_CountForcedClusterPortals();\n\t//remove all area cluster marks\n\tAAS_RemoveClusterAreas();\n\t//find possible cluster portals\n\tAAS_FindPossiblePortals();\n\t//craete portals to for the bot view\n\tAAS_CreateViewPortals();\n\t//remove all portals that are not closing a cluster\n\t//AAS_RemoveNotClusterClosingPortals();\n\t//initialize portal memory\n\tif (aasworld.portals) FreeMemory(aasworld.portals);\n\taasworld.portals = (aas_portal_t *) GetClearedMemory(AAS_MAX_PORTALS * sizeof(aas_portal_t));\n\t//initialize portal index memory\n\tif (aasworld.portalindex) FreeMemory(aasworld.portalindex);\n\taasworld.portalindex = (aas_portalindex_t *) GetClearedMemory(AAS_MAX_PORTALINDEXSIZE * sizeof(aas_portalindex_t));\n\t//initialize cluster memory\n\tif (aasworld.clusters) FreeMemory(aasworld.clusters);\n\taasworld.clusters = (aas_cluster_t *) GetClearedMemory(AAS_MAX_CLUSTERS * sizeof(aas_cluster_t));\n\t//\n\tremovedPortalAreas = 0;\n\tbotimport.Print(PRT_MESSAGE, \"\\r%6d removed portal areas\", removedPortalAreas);\n\twhile(1)\n\t{\n\t\tbotimport.Print(PRT_MESSAGE, \"\\r%6d\", removedPortalAreas);\n\t\t//initialize the number of portals and clusters\n\t\taasworld.numportals = 1;\t\t//portal 0 is a dummy\n\t\taasworld.portalindexsize = 0;\n\t\taasworld.numclusters = 1;\t\t//cluster 0 is a dummy\n\t\t//create the portals from the portal areas\n\t\tAAS_CreatePortals();\n\t\t//\n\t\tremovedPortalAreas++;\n\t\t//find the clusters\n\t\tif (!AAS_FindClusters())\n\t\t\tcontinue;\n\t\t//test the portals\n\t\tif (!AAS_TestPortals())\n\t\t\tcontinue;\n\t\t//\n\t\tbreak;\n\t} //end while\n\tbotimport.Print(PRT_MESSAGE, \"\\n\");\n\t//the AAS file should be saved\n\taasworld.savefile = qtrue;\n\t//write the portal areas to the log file\n\tfor (i = 1; i < aasworld.numportals; i++)\n\t{\n\t\tLog_Write(\"portal %d: area %d\\r\\n\", i, aasworld.portals[i].areanum);\n\t} //end for\n\t// report cluster info\n\tbotimport.Print(PRT_MESSAGE, \"%6d portals created\\n\", aasworld.numportals);\n\tbotimport.Print(PRT_MESSAGE, \"%6d clusters created\\n\", aasworld.numclusters);\n\tfor (i = 1; i < aasworld.numclusters; i++)\n\t{\n\t\tbotimport.Print(PRT_MESSAGE, \"cluster %d has %d reachability areas\\n\", i,\n\t\t\t\taasworld.clusters[i].numreachabilityareas);\n\t} //end for\n\t// report AAS file efficiency\n\tnumreachabilityareas = 0;\n\ttotal = 0;\n\tfor (i = 0; i < aasworld.numclusters; i++) {\n\t\tn = aasworld.clusters[i].numreachabilityareas;\n\t\tnumreachabilityareas += n;\n\t\ttotal += n * n;\n\t}\n\ttotal += numreachabilityareas * aasworld.numportals;\n\t//\n\tbotimport.Print(PRT_MESSAGE, \"%6i total reachability areas\\n\", numreachabilityareas);\n\tbotimport.Print(PRT_MESSAGE, \"%6i AAS memory/CPU usage (the lower the better)\\n\", total * 3);\n} //end of the function AAS_InitClustering\n"
  },
  {
    "path": "src/engine/botlib/be_aas_cluster.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tbe_aas_cluster.h\n *\n * desc:\t\tAAS\n *\n * $Archive: /source/code/botlib/be_aas_cluster.h $\n *\n *****************************************************************************/\n\n#ifdef AASINTERN\n//initialize the AAS clustering\nvoid AAS_InitClustering(void);\n//\nvoid AAS_SetViewPortalsAsClusterPortals(void);\n#endif //AASINTERN\n\n"
  },
  {
    "path": "src/engine/botlib/be_aas_debug.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tbe_aas_debug.c\n *\n * desc:\t\tAAS debug code\n *\n * $Archive: /MissionPack/code/botlib/be_aas_debug.c $\n *\n *****************************************************************************/\n\n#include \"../../game/q_shared.h\"\n#include \"l_memory.h\"\n#include \"l_script.h\"\n#include \"l_precomp.h\"\n#include \"l_struct.h\"\n#include \"l_libvar.h\"\n#include \"aasfile.h\"\n#include \"../../game/botlib.h\"\n#include \"../../game/be_aas.h\"\n#include \"be_interface.h\"\n#include \"be_aas_funcs.h\"\n#include \"be_aas_def.h\"\n\n#define MAX_DEBUGLINES\t\t\t\t1024\n#define MAX_DEBUGPOLYGONS\t\t\t8192\n\nint debuglines[MAX_DEBUGLINES];\nint debuglinevisible[MAX_DEBUGLINES];\nint numdebuglines;\n\nstatic int debugpolygons[MAX_DEBUGPOLYGONS];\n\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_ClearShownPolygons(void)\n{\n\tint i;\n//*\n\tfor (i = 0; i < MAX_DEBUGPOLYGONS; i++)\n\t{\n\t\tif (debugpolygons[i]) botimport.DebugPolygonDelete(debugpolygons[i]);\n\t\tdebugpolygons[i] = 0;\n\t} //end for\n//*/\n/*\n\tfor (i = 0; i < MAX_DEBUGPOLYGONS; i++)\n\t{\n\t\tbotimport.DebugPolygonDelete(i);\n\t\tdebugpolygons[i] = 0;\n\t} //end for\n*/\n} //end of the function AAS_ClearShownPolygons\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_ShowPolygon(int color, int numpoints, vec3_t *points)\n{\n\tint i;\n\n\tfor (i = 0; i < MAX_DEBUGPOLYGONS; i++)\n\t{\n\t\tif (!debugpolygons[i])\n\t\t{\n\t\t\tdebugpolygons[i] = botimport.DebugPolygonCreate(color, numpoints, points);\n\t\t\tbreak;\n\t\t} //end if\n\t} //end for\n} //end of the function AAS_ShowPolygon\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_ClearShownDebugLines(void)\n{\n\tint i;\n\n\t//make all lines invisible\n\tfor (i = 0; i < MAX_DEBUGLINES; i++)\n\t{\n\t\tif (debuglines[i])\n\t\t{\n\t\t\t//botimport.DebugLineShow(debuglines[i], NULL, NULL, LINECOLOR_NONE);\n\t\t\tbotimport.DebugLineDelete(debuglines[i]);\n\t\t\tdebuglines[i] = 0;\n\t\t\tdebuglinevisible[i] = qfalse;\n\t\t} //end if\n\t} //end for\n} //end of the function AAS_ClearShownDebugLines\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_DebugLine(vec3_t start, vec3_t end, int color)\n{\n\tint line;\n\n\tfor (line = 0; line < MAX_DEBUGLINES; line++)\n\t{\n\t\tif (!debuglines[line])\n\t\t{\n\t\t\tdebuglines[line] = botimport.DebugLineCreate();\n\t\t\tdebuglinevisible[line] = qfalse;\n\t\t\tnumdebuglines++;\n\t\t} //end if\n\t\tif (!debuglinevisible[line])\n\t\t{\n\t\t\tbotimport.DebugLineShow(debuglines[line], start, end, color);\n\t\t\tdebuglinevisible[line] = qtrue;\n\t\t\treturn;\n\t\t} //end else\n\t} //end for\n} //end of the function AAS_DebugLine\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_PermanentLine(vec3_t start, vec3_t end, int color)\n{\n\tint line;\n\n\tline = botimport.DebugLineCreate();\n\tbotimport.DebugLineShow(line, start, end, color);\n} //end of the function AAS_PermenentLine\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_DrawPermanentCross(vec3_t origin, float size, int color)\n{\n\tint i, debugline;\n\tvec3_t start, end;\n\n\tfor (i = 0; i < 3; i++)\n\t{\n\t\tVectorCopy(origin, start);\n\t\tstart[i] += size;\n\t\tVectorCopy(origin, end);\n\t\tend[i] -= size;\n\t\tAAS_DebugLine(start, end, color);\n\t\tdebugline = botimport.DebugLineCreate();\n\t\tbotimport.DebugLineShow(debugline, start, end, color);\n\t} //end for\n} //end of the function AAS_DrawPermanentCross\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_DrawPlaneCross(vec3_t point, vec3_t normal, float dist, int type, int color)\n{\n\tint n0, n1, n2, j, line, lines[2];\n\tvec3_t start1, end1, start2, end2;\n\n\t//make a cross in the hit plane at the hit point\n\tVectorCopy(point, start1);\n\tVectorCopy(point, end1);\n\tVectorCopy(point, start2);\n\tVectorCopy(point, end2);\n\n\tn0 = type % 3;\n\tn1 = (type + 1) % 3;\n\tn2 = (type + 2) % 3;\n\tstart1[n1] -= 6;\n\tstart1[n2] -= 6;\n\tend1[n1] += 6;\n\tend1[n2] += 6;\n\tstart2[n1] += 6;\n\tstart2[n2] -= 6;\n\tend2[n1] -= 6;\n\tend2[n2] += 6;\n\n\tstart1[n0] = (dist - (start1[n1] * normal[n1] +\n\t\t\t\tstart1[n2] * normal[n2])) / normal[n0];\n\tend1[n0] = (dist - (end1[n1] * normal[n1] +\n\t\t\t\tend1[n2] * normal[n2])) / normal[n0];\n\tstart2[n0] = (dist - (start2[n1] * normal[n1] +\n\t\t\t\tstart2[n2] * normal[n2])) / normal[n0];\n\tend2[n0] = (dist - (end2[n1] * normal[n1] +\n\t\t\t\tend2[n2] * normal[n2])) / normal[n0];\n\n\tfor (j = 0, line = 0; j < 2 && line < MAX_DEBUGLINES; line++)\n\t{\n\t\tif (!debuglines[line])\n\t\t{\n\t\t\tdebuglines[line] = botimport.DebugLineCreate();\n\t\t\tlines[j++] = debuglines[line];\n\t\t\tdebuglinevisible[line] = qtrue;\n\t\t\tnumdebuglines++;\n\t\t} //end if\n\t\telse if (!debuglinevisible[line])\n\t\t{\n\t\t\tlines[j++] = debuglines[line];\n\t\t\tdebuglinevisible[line] = qtrue;\n\t\t} //end else\n\t} //end for\n\tbotimport.DebugLineShow(lines[0], start1, end1, color);\n\tbotimport.DebugLineShow(lines[1], start2, end2, color);\n} //end of the function AAS_DrawPlaneCross\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_ShowBoundingBox(vec3_t origin, vec3_t mins, vec3_t maxs)\n{\n\tvec3_t bboxcorners[8];\n\tint lines[3];\n\tint i, j, line;\n\n\t//upper corners\n\tbboxcorners[0][0] = origin[0] + maxs[0];\n\tbboxcorners[0][1] = origin[1] + maxs[1];\n\tbboxcorners[0][2] = origin[2] + maxs[2];\n\t//\n\tbboxcorners[1][0] = origin[0] + mins[0];\n\tbboxcorners[1][1] = origin[1] + maxs[1];\n\tbboxcorners[1][2] = origin[2] + maxs[2];\n\t//\n\tbboxcorners[2][0] = origin[0] + mins[0];\n\tbboxcorners[2][1] = origin[1] + mins[1];\n\tbboxcorners[2][2] = origin[2] + maxs[2];\n\t//\n\tbboxcorners[3][0] = origin[0] + maxs[0];\n\tbboxcorners[3][1] = origin[1] + mins[1];\n\tbboxcorners[3][2] = origin[2] + maxs[2];\n\t//lower corners\n\tCom_Memcpy(bboxcorners[4], bboxcorners[0], sizeof(vec3_t) * 4);\n\tfor (i = 0; i < 4; i++) bboxcorners[4 + i][2] = origin[2] + mins[2];\n\t//draw bounding box\n\tfor (i = 0; i < 4; i++)\n\t{\n\t\tfor (j = 0, line = 0; j < 3 && line < MAX_DEBUGLINES; line++)\n\t\t{\n\t\t\tif (!debuglines[line])\n\t\t\t{\n\t\t\t\tdebuglines[line] = botimport.DebugLineCreate();\n\t\t\t\tlines[j++] = debuglines[line];\n\t\t\t\tdebuglinevisible[line] = qtrue;\n\t\t\t\tnumdebuglines++;\n\t\t\t} //end if\n\t\t\telse if (!debuglinevisible[line])\n\t\t\t{\n\t\t\t\tlines[j++] = debuglines[line];\n\t\t\t\tdebuglinevisible[line] = qtrue;\n\t\t\t} //end else\n\t\t} //end for\n\t\t//top plane\n\t\tbotimport.DebugLineShow(lines[0], bboxcorners[i],\n\t\t\t\t\t\t\t\t\tbboxcorners[(i+1)&3], LINECOLOR_RED);\n\t\t//bottom plane\n\t\tbotimport.DebugLineShow(lines[1], bboxcorners[4+i],\n\t\t\t\t\t\t\t\t\tbboxcorners[4+((i+1)&3)], LINECOLOR_RED);\n\t\t//vertical lines\n\t\tbotimport.DebugLineShow(lines[2], bboxcorners[i],\n\t\t\t\t\t\t\t\t\tbboxcorners[4+i], LINECOLOR_RED);\n\t} //end for\n} //end of the function AAS_ShowBoundingBox\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_ShowFace(int facenum)\n{\n\tint i, color, edgenum;\n\taas_edge_t *edge;\n\taas_face_t *face;\n\taas_plane_t *plane;\n\tvec3_t start, end;\n\n\tcolor = LINECOLOR_YELLOW;\n\t//check if face number is in range\n\tif (facenum >= aasworld.numfaces)\n\t{\n\t\tbotimport.Print(PRT_ERROR, \"facenum %d out of range\\n\", facenum);\n\t} //end if\n\tface = &aasworld.faces[facenum];\n\t//walk through the edges of the face\n\tfor (i = 0; i < face->numedges; i++)\n\t{\n\t\t//edge number\n\t\tedgenum = abs(aasworld.edgeindex[face->firstedge + i]);\n\t\t//check if edge number is in range\n\t\tif (edgenum >= aasworld.numedges)\n\t\t{\n\t\t\tbotimport.Print(PRT_ERROR, \"edgenum %d out of range\\n\", edgenum);\n\t\t} //end if\n\t\tedge = &aasworld.edges[edgenum];\n\t\tif (color == LINECOLOR_RED) color = LINECOLOR_GREEN;\n\t\telse if (color == LINECOLOR_GREEN) color = LINECOLOR_BLUE;\n\t\telse if (color == LINECOLOR_BLUE) color = LINECOLOR_YELLOW;\n\t\telse color = LINECOLOR_RED;\n\t\tAAS_DebugLine(aasworld.vertexes[edge->v[0]],\n\t\t\t\t\t\t\t\t\t\taasworld.vertexes[edge->v[1]],\n\t\t\t\t\t\t\t\t\t\tcolor);\n\t} //end for\n\tplane = &aasworld.planes[face->planenum];\n\tedgenum = abs(aasworld.edgeindex[face->firstedge]);\n\tedge = &aasworld.edges[edgenum];\n\tVectorCopy(aasworld.vertexes[edge->v[0]], start);\n\tVectorMA(start, 20, plane->normal, end);\n\tAAS_DebugLine(start, end, LINECOLOR_RED);\n} //end of the function AAS_ShowFace\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_ShowFacePolygon(int facenum, int color, int flip)\n{\n\tint i, edgenum, numpoints;\n\tvec3_t points[128];\n\taas_edge_t *edge;\n\taas_face_t *face;\n\n\t//check if face number is in range\n\tif (facenum >= aasworld.numfaces)\n\t{\n\t\tbotimport.Print(PRT_ERROR, \"facenum %d out of range\\n\", facenum);\n\t} //end if\n\tface = &aasworld.faces[facenum];\n\t//walk through the edges of the face\n\tnumpoints = 0;\n\tif (flip)\n\t{\n\t\tfor (i = face->numedges-1; i >= 0; i--)\n\t\t{\n\t\t\t//edge number\n\t\t\tedgenum = aasworld.edgeindex[face->firstedge + i];\n\t\t\tedge = &aasworld.edges[abs(edgenum)];\n\t\t\tVectorCopy(aasworld.vertexes[edge->v[edgenum < 0]], points[numpoints]);\n\t\t\tnumpoints++;\n\t\t} //end for\n\t} //end if\n\telse\n\t{\n\t\tfor (i = 0; i < face->numedges; i++)\n\t\t{\n\t\t\t//edge number\n\t\t\tedgenum = aasworld.edgeindex[face->firstedge + i];\n\t\t\tedge = &aasworld.edges[abs(edgenum)];\n\t\t\tVectorCopy(aasworld.vertexes[edge->v[edgenum < 0]], points[numpoints]);\n\t\t\tnumpoints++;\n\t\t} //end for\n\t} //end else\n\tAAS_ShowPolygon(color, numpoints, points);\n} //end of the function AAS_ShowFacePolygon\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_ShowArea(int areanum, int groundfacesonly)\n{\n\tint areaedges[MAX_DEBUGLINES];\n\tint numareaedges, i, j, n, color = 0, line;\n\tint facenum, edgenum;\n\taas_area_t *area;\n\taas_face_t *face;\n\taas_edge_t *edge;\n\n\t//\n\tnumareaedges = 0;\n\t//\n\tif (areanum < 0 || areanum >= aasworld.numareas)\n\t{\n\t\tbotimport.Print(PRT_ERROR, \"area %d out of range [0, %d]\\n\",\n\t\t\t\t\t\t\t\tareanum, aasworld.numareas);\n\t\treturn;\n\t} //end if\n\t//pointer to the convex area\n\tarea = &aasworld.areas[areanum];\n\t//walk through the faces of the area\n\tfor (i = 0; i < area->numfaces; i++)\n\t{\n\t\tfacenum = abs(aasworld.faceindex[area->firstface + i]);\n\t\t//check if face number is in range\n\t\tif (facenum >= aasworld.numfaces)\n\t\t{\n\t\t\tbotimport.Print(PRT_ERROR, \"facenum %d out of range\\n\", facenum);\n\t\t} //end if\n\t\tface = &aasworld.faces[facenum];\n\t\t//ground faces only\n\t\tif (groundfacesonly)\n\t\t{\n\t\t\tif (!(face->faceflags & (FACE_GROUND | FACE_LADDER))) continue;\n\t\t} //end if\n\t\t//walk through the edges of the face\n\t\tfor (j = 0; j < face->numedges; j++)\n\t\t{\n\t\t\t//edge number\n\t\t\tedgenum = abs(aasworld.edgeindex[face->firstedge + j]);\n\t\t\t//check if edge number is in range\n\t\t\tif (edgenum >= aasworld.numedges)\n\t\t\t{\n\t\t\t\tbotimport.Print(PRT_ERROR, \"edgenum %d out of range\\n\", edgenum);\n\t\t\t} //end if\n\t\t\t//check if the edge is stored already\n\t\t\tfor (n = 0; n < numareaedges; n++)\n\t\t\t{\n\t\t\t\tif (areaedges[n] == edgenum) break;\n\t\t\t} //end for\n\t\t\tif (n == numareaedges && numareaedges < MAX_DEBUGLINES)\n\t\t\t{\n\t\t\t\tareaedges[numareaedges++] = edgenum;\n\t\t\t} //end if\n\t\t} //end for\n\t\t//AAS_ShowFace(facenum);\n\t} //end for\n\t//draw all the edges\n\tfor (n = 0; n < numareaedges; n++)\n\t{\n\t\tfor (line = 0; line < MAX_DEBUGLINES; line++)\n\t\t{\n\t\t\tif (!debuglines[line])\n\t\t\t{\n\t\t\t\tdebuglines[line] = botimport.DebugLineCreate();\n\t\t\t\tdebuglinevisible[line] = qfalse;\n\t\t\t\tnumdebuglines++;\n\t\t\t} //end if\n\t\t\tif (!debuglinevisible[line])\n\t\t\t{\n\t\t\t\tbreak;\n\t\t\t} //end else\n\t\t} //end for\n\t\tif (line >= MAX_DEBUGLINES) return;\n\t\tedge = &aasworld.edges[areaedges[n]];\n\t\tif (color == LINECOLOR_RED) color = LINECOLOR_BLUE;\n\t\telse if (color == LINECOLOR_BLUE) color = LINECOLOR_GREEN;\n\t\telse if (color == LINECOLOR_GREEN) color = LINECOLOR_YELLOW;\n\t\telse color = LINECOLOR_RED;\n\t\tbotimport.DebugLineShow(debuglines[line],\n\t\t\t\t\t\t\t\t\taasworld.vertexes[edge->v[0]],\n\t\t\t\t\t\t\t\t\taasworld.vertexes[edge->v[1]],\n\t\t\t\t\t\t\t\t\tcolor);\n\t\tdebuglinevisible[line] = qtrue;\n\t} //end for*/\n} //end of the function AAS_ShowArea\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_ShowAreaPolygons(int areanum, int color, int groundfacesonly)\n{\n\tint i, facenum;\n\taas_area_t *area;\n\taas_face_t *face;\n\n\t//\n\tif (areanum < 0 || areanum >= aasworld.numareas)\n\t{\n\t\tbotimport.Print(PRT_ERROR, \"area %d out of range [0, %d]\\n\",\n\t\t\t\t\t\t\t\tareanum, aasworld.numareas);\n\t\treturn;\n\t} //end if\n\t//pointer to the convex area\n\tarea = &aasworld.areas[areanum];\n\t//walk through the faces of the area\n\tfor (i = 0; i < area->numfaces; i++)\n\t{\n\t\tfacenum = abs(aasworld.faceindex[area->firstface + i]);\n\t\t//check if face number is in range\n\t\tif (facenum >= aasworld.numfaces)\n\t\t{\n\t\t\tbotimport.Print(PRT_ERROR, \"facenum %d out of range\\n\", facenum);\n\t\t} //end if\n\t\tface = &aasworld.faces[facenum];\n\t\t//ground faces only\n\t\tif (groundfacesonly)\n\t\t{\n\t\t\tif (!(face->faceflags & (FACE_GROUND | FACE_LADDER))) continue;\n\t\t} //end if\n\t\tAAS_ShowFacePolygon(facenum, color, face->frontarea != areanum);\n\t} //end for\n} //end of the function AAS_ShowAreaPolygons\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_DrawCross(vec3_t origin, float size, int color)\n{\n\tint i;\n\tvec3_t start, end;\n\n\tfor (i = 0; i < 3; i++)\n\t{\n\t\tVectorCopy(origin, start);\n\t\tstart[i] += size;\n\t\tVectorCopy(origin, end);\n\t\tend[i] -= size;\n\t\tAAS_DebugLine(start, end, color);\n\t} //end for\n} //end of the function AAS_DrawCross\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_PrintTravelType(int traveltype)\n{\n#ifdef DEBUG\n\tchar *str;\n\t//\n\tswitch(traveltype & TRAVELTYPE_MASK)\n\t{\n\t\tcase TRAVEL_INVALID: str = \"TRAVEL_INVALID\"; break;\n\t\tcase TRAVEL_WALK: str = \"TRAVEL_WALK\"; break;\n\t\tcase TRAVEL_CROUCH: str = \"TRAVEL_CROUCH\"; break;\n\t\tcase TRAVEL_BARRIERJUMP: str = \"TRAVEL_BARRIERJUMP\"; break;\n\t\tcase TRAVEL_JUMP: str = \"TRAVEL_JUMP\"; break;\n\t\tcase TRAVEL_LADDER: str = \"TRAVEL_LADDER\"; break;\n\t\tcase TRAVEL_WALKOFFLEDGE: str = \"TRAVEL_WALKOFFLEDGE\"; break;\n\t\tcase TRAVEL_SWIM: str = \"TRAVEL_SWIM\"; break;\n\t\tcase TRAVEL_WATERJUMP: str = \"TRAVEL_WATERJUMP\"; break;\n\t\tcase TRAVEL_TELEPORT: str = \"TRAVEL_TELEPORT\"; break;\n\t\tcase TRAVEL_ELEVATOR: str = \"TRAVEL_ELEVATOR\"; break;\n\t\tcase TRAVEL_ROCKETJUMP: str = \"TRAVEL_ROCKETJUMP\"; break;\n\t\tcase TRAVEL_BFGJUMP: str = \"TRAVEL_BFGJUMP\"; break;\n\t\tcase TRAVEL_GRAPPLEHOOK: str = \"TRAVEL_GRAPPLEHOOK\"; break;\n\t\tcase TRAVEL_JUMPPAD: str = \"TRAVEL_JUMPPAD\"; break;\n\t\tcase TRAVEL_FUNCBOB: str = \"TRAVEL_FUNCBOB\"; break;\n\t\tdefault: str = \"UNKNOWN TRAVEL TYPE\"; break;\n\t} //end switch\n\tbotimport.Print(PRT_MESSAGE, \"%s\", str);\n#endif\n} //end of the function AAS_PrintTravelType\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_DrawArrow(vec3_t start, vec3_t end, int linecolor, int arrowcolor)\n{\n\tvec3_t dir, cross, p1, p2, up = {0, 0, 1};\n\tfloat dot;\n\n\tVectorSubtract(end, start, dir);\n\tVectorNormalize(dir);\n\tdot = DotProduct(dir, up);\n\tif (dot > 0.99 || dot < -0.99) VectorSet(cross, 1, 0, 0);\n\telse CrossProduct(dir, up, cross);\n\n\tVectorMA(end, -6, dir, p1);\n\tVectorCopy(p1, p2);\n\tVectorMA(p1, 6, cross, p1);\n\tVectorMA(p2, -6, cross, p2);\n\n\tAAS_DebugLine(start, end, linecolor);\n\tAAS_DebugLine(p1, end, arrowcolor);\n\tAAS_DebugLine(p2, end, arrowcolor);\n} //end of the function AAS_DrawArrow\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_ShowReachability(aas_reachability_t *reach)\n{\n\tvec3_t dir, cmdmove, velocity;\n\tfloat speed, zvel;\n\taas_clientmove_t move;\n\n\tAAS_ShowAreaPolygons(reach->areanum, 5, qtrue);\n\t//AAS_ShowArea(reach->areanum, qtrue);\n\tAAS_DrawArrow(reach->start, reach->end, LINECOLOR_BLUE, LINECOLOR_YELLOW);\n\t//\n\tif ((reach->traveltype & TRAVELTYPE_MASK) == TRAVEL_JUMP ||\n\t\t(reach->traveltype & TRAVELTYPE_MASK) == TRAVEL_WALKOFFLEDGE)\n\t{\n\t\tAAS_HorizontalVelocityForJump(aassettings.phys_jumpvel, reach->start, reach->end, &speed);\n\t\t//\n\t\tVectorSubtract(reach->end, reach->start, dir);\n\t\tdir[2] = 0;\n\t\tVectorNormalize(dir);\n\t\t//set the velocity\n\t\tVectorScale(dir, speed, velocity);\n\t\t//set the command movement\n\t\tVectorClear(cmdmove);\n\t\tcmdmove[2] = aassettings.phys_jumpvel;\n\t\t//\n\t\tAAS_PredictClientMovement(&move, -1, reach->start, PRESENCE_NORMAL, qtrue,\n\t\t\t\t\t\t\t\t\tvelocity, cmdmove, 3, 30, 0.1f,\n\t\t\t\t\t\t\t\t\tSE_HITGROUND|SE_ENTERWATER|SE_ENTERSLIME|\n\t\t\t\t\t\t\t\t\tSE_ENTERLAVA|SE_HITGROUNDDAMAGE, 0, qtrue);\n\t\t//\n\t\tif ((reach->traveltype & TRAVELTYPE_MASK) == TRAVEL_JUMP)\n\t\t{\n\t\t\tAAS_JumpReachRunStart(reach, dir);\n\t\t\tAAS_DrawCross(dir, 4, LINECOLOR_BLUE);\n\t\t} //end if\n\t} //end if\n\telse if ((reach->traveltype & TRAVELTYPE_MASK) == TRAVEL_ROCKETJUMP)\n\t{\n\t\tzvel = AAS_RocketJumpZVelocity(reach->start);\n\t\tAAS_HorizontalVelocityForJump(zvel, reach->start, reach->end, &speed);\n\t\t//\n\t\tVectorSubtract(reach->end, reach->start, dir);\n\t\tdir[2] = 0;\n\t\tVectorNormalize(dir);\n\t\t//get command movement\n\t\tVectorScale(dir, speed, cmdmove);\n\t\tVectorSet(velocity, 0, 0, zvel);\n\t\t//\n\t\tAAS_PredictClientMovement(&move, -1, reach->start, PRESENCE_NORMAL, qtrue,\n\t\t\t\t\t\t\t\t\tvelocity, cmdmove, 30, 30, 0.1f,\n\t\t\t\t\t\t\t\t\tSE_ENTERWATER|SE_ENTERSLIME|\n\t\t\t\t\t\t\t\t\tSE_ENTERLAVA|SE_HITGROUNDDAMAGE|\n\t\t\t\t\t\t\t\t\tSE_TOUCHJUMPPAD|SE_HITGROUNDAREA, reach->areanum, qtrue);\n\t} //end else if\n\telse if ((reach->traveltype & TRAVELTYPE_MASK) == TRAVEL_JUMPPAD)\n\t{\n\t\tVectorSet(cmdmove, 0, 0, 0);\n\t\t//\n\t\tVectorSubtract(reach->end, reach->start, dir);\n\t\tdir[2] = 0;\n\t\tVectorNormalize(dir);\n\t\t//set the velocity\n\t\t//NOTE: the edgenum is the horizontal velocity\n\t\tVectorScale(dir, reach->edgenum, velocity);\n\t\t//NOTE: the facenum is the Z velocity\n\t\tvelocity[2] = reach->facenum;\n\t\t//\n\t\tAAS_PredictClientMovement(&move, -1, reach->start, PRESENCE_NORMAL, qtrue,\n\t\t\t\t\t\t\t\t\tvelocity, cmdmove, 30, 30, 0.1f,\n\t\t\t\t\t\t\t\t\tSE_ENTERWATER|SE_ENTERSLIME|\n\t\t\t\t\t\t\t\t\tSE_ENTERLAVA|SE_HITGROUNDDAMAGE|\n\t\t\t\t\t\t\t\t\tSE_TOUCHJUMPPAD|SE_HITGROUNDAREA, reach->areanum, qtrue);\n\t} //end else if\n} //end of the function AAS_ShowReachability\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_ShowReachableAreas(int areanum)\n{\n\taas_areasettings_t *settings;\n\tstatic aas_reachability_t reach;\n\tstatic int index, lastareanum;\n\tstatic float lasttime;\n\n\tif (areanum != lastareanum)\n\t{\n\t\tindex = 0;\n\t\tlastareanum = areanum;\n\t} //end if\n\tsettings = &aasworld.areasettings[areanum];\n\t//\n\tif (!settings->numreachableareas) return;\n\t//\n\tif (index >= settings->numreachableareas) index = 0;\n\t//\n\tif (AAS_Time() - lasttime > 1.5)\n\t{\n\t\tCom_Memcpy(&reach, &aasworld.reachability[settings->firstreachablearea + index], sizeof(aas_reachability_t));\n\t\tindex++;\n\t\tlasttime = AAS_Time();\n\t\tAAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK);\n\t\tbotimport.Print(PRT_MESSAGE, \"\\n\");\n\t} //end if\n\tAAS_ShowReachability(&reach);\n} //end of the function ShowReachableAreas\n\nvoid AAS_FloodAreas_r(int areanum, int cluster, int *done)\n{\n\tint nextareanum, i, facenum;\n\taas_area_t *area;\n\taas_face_t *face;\n\taas_areasettings_t *settings;\n\taas_reachability_t *reach;\n\n\tAAS_ShowAreaPolygons(areanum, 1, qtrue);\n\t//pointer to the convex area\n\tarea = &aasworld.areas[areanum];\n\tsettings = &aasworld.areasettings[areanum];\n\t//walk through the faces of the area\n\tfor (i = 0; i < area->numfaces; i++)\n\t{\n\t\tfacenum = abs(aasworld.faceindex[area->firstface + i]);\n\t\tface = &aasworld.faces[facenum];\n\t\tif (face->frontarea == areanum)\n\t\t\tnextareanum = face->backarea;\n\t\telse\n\t\t\tnextareanum = face->frontarea;\n\t\tif (!nextareanum)\n\t\t\tcontinue;\n\t\tif (done[nextareanum])\n\t\t\tcontinue;\n\t\tdone[nextareanum] = qtrue;\n\t\tif (aasworld.areasettings[nextareanum].contents & AREACONTENTS_VIEWPORTAL)\n\t\t\tcontinue;\n\t\tif (AAS_AreaCluster(nextareanum) != cluster)\n\t\t\tcontinue;\n\t\tAAS_FloodAreas_r(nextareanum, cluster, done);\n\t} //end for\n\t//\n\tfor (i = 0; i < settings->numreachableareas; i++)\n\t{\n\t\treach = &aasworld.reachability[settings->firstreachablearea + i];\n\t\tnextareanum = reach->areanum;\n\t\tif (!nextareanum)\n\t\t\tcontinue;\n\t\tif (done[nextareanum])\n\t\t\tcontinue;\n\t\tdone[nextareanum] = qtrue;\n\t\tif (aasworld.areasettings[nextareanum].contents & AREACONTENTS_VIEWPORTAL)\n\t\t\tcontinue;\n\t\tif (AAS_AreaCluster(nextareanum) != cluster)\n\t\t\tcontinue;\n\t\t/*\n\t\tif ((reach->traveltype & TRAVELTYPE_MASK) == TRAVEL_WALKOFFLEDGE)\n\t\t{\n\t\t\tAAS_DebugLine(reach->start, reach->end, 1);\n\t\t}\n\t\t*/\n\t\tAAS_FloodAreas_r(nextareanum, cluster, done);\n\t}\n}\n\nvoid AAS_FloodAreas(vec3_t origin)\n{\n\tint areanum, cluster, *done;\n\n\tdone = (int *) GetClearedMemory(aasworld.numareas * sizeof(int));\n\tareanum = AAS_PointAreaNum(origin);\n\tcluster = AAS_AreaCluster(areanum);\n\tAAS_FloodAreas_r(areanum, cluster, done);\n}\n"
  },
  {
    "path": "src/engine/botlib/be_aas_debug.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tbe_aas_debug.h\n *\n * desc:\t\tAAS\n *\n * $Archive: /source/code/botlib/be_aas_debug.h $\n *\n *****************************************************************************/\n\n//clear the shown debug lines\nvoid AAS_ClearShownDebugLines(void);\n//\nvoid AAS_ClearShownPolygons(void);\n//show a debug line\nvoid AAS_DebugLine(vec3_t start, vec3_t end, int color);\n//show a permenent line\nvoid AAS_PermanentLine(vec3_t start, vec3_t end, int color);\n//show a permanent cross\nvoid AAS_DrawPermanentCross(vec3_t origin, float size, int color);\n//draw a cross in the plane\nvoid AAS_DrawPlaneCross(vec3_t point, vec3_t normal, float dist, int type, int color);\n//show a bounding box\nvoid AAS_ShowBoundingBox(vec3_t origin, vec3_t mins, vec3_t maxs);\n//show a face\nvoid AAS_ShowFace(int facenum);\n//show an area\nvoid AAS_ShowArea(int areanum, int groundfacesonly);\n//\nvoid AAS_ShowAreaPolygons(int areanum, int color, int groundfacesonly);\n//draw a cros\nvoid AAS_DrawCross(vec3_t origin, float size, int color);\n//print the travel type\nvoid AAS_PrintTravelType(int traveltype);\n//draw an arrow\nvoid AAS_DrawArrow(vec3_t start, vec3_t end, int linecolor, int arrowcolor);\n//visualize the given reachability\nvoid AAS_ShowReachability(struct aas_reachability_s *reach);\n//show the reachable areas from the given area\nvoid AAS_ShowReachableAreas(int areanum);\n\n"
  },
  {
    "path": "src/engine/botlib/be_aas_def.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tbe_aas_def.h\n *\n * desc:\t\tAAS\n *\n * $Archive: /source/code/botlib/be_aas_def.h $\n *\n *****************************************************************************/\n\n//debugging on\n#define AAS_DEBUG\n\n#define MAX_CLIENTS\t\t\t64\n#define\tMAX_MODELS\t\t\t256\t\t// these are sent over the net as 8 bits\n#define\tMAX_SOUNDS\t\t\t256\t\t// so they cannot be blindly increased\n#define\tMAX_CONFIGSTRINGS\t1024\n\n#define\tCS_SCORES\t\t\t32\n#define\tCS_MODELS\t\t\t(CS_SCORES+MAX_CLIENTS)\n#define\tCS_SOUNDS\t\t\t(CS_MODELS+MAX_MODELS)\n\n#define DF_AASENTNUMBER(x)\t\t(x - aasworld.entities)\n#define DF_NUMBERAASENT(x)\t\t(&aasworld.entities[x])\n#define DF_AASENTCLIENT(x)\t\t(x - aasworld.entities - 1)\n#define DF_CLIENTAASENT(x)\t\t(&aasworld.entities[x + 1])\n\n#ifndef MAX_PATH\n\t#define MAX_PATH\t\t\t\tMAX_QPATH\n#endif\n\n//string index (for model, sound and image index)\ntypedef struct aas_stringindex_s\n{\n\tint numindexes;\n\tchar **index;\n} aas_stringindex_t;\n\n//structure to link entities to areas and areas to entities\ntypedef struct aas_link_s\n{\n\tint entnum;\n\tint areanum;\n\tstruct aas_link_s *next_ent, *prev_ent;\n\tstruct aas_link_s *next_area, *prev_area;\n} aas_link_t;\n\n//structure to link entities to leaves and leaves to entities\ntypedef struct bsp_link_s\n{\n\tint entnum;\n\tint leafnum;\n\tstruct bsp_link_s *next_ent, *prev_ent;\n\tstruct bsp_link_s *next_leaf, *prev_leaf;\n} bsp_link_t;\n\ntypedef struct bsp_entdata_s\n{\n\tvec3_t origin;\n\tvec3_t angles;\n\tvec3_t absmins;\n\tvec3_t absmaxs;\n\tint solid;\n\tint modelnum;\n} bsp_entdata_t;\n\n//entity\ntypedef struct aas_entity_s\n{\n\t//entity info\n\taas_entityinfo_t i;\n\t//links into the AAS areas\n\taas_link_t *areas;\n\t//links into the BSP leaves\n\tbsp_link_t *leaves;\n} aas_entity_t;\n\ntypedef struct aas_settings_s\n{\n\tvec3_t phys_gravitydirection;\n\tfloat phys_friction;\n\tfloat phys_stopspeed;\n\tfloat phys_gravity;\n\tfloat phys_waterfriction;\n\tfloat phys_watergravity;\n\tfloat phys_maxvelocity;\n\tfloat phys_maxwalkvelocity;\n\tfloat phys_maxcrouchvelocity;\n\tfloat phys_maxswimvelocity;\n\tfloat phys_walkaccelerate;\n\tfloat phys_airaccelerate;\n\tfloat phys_swimaccelerate;\n\tfloat phys_maxstep;\n\tfloat phys_maxsteepness;\n\tfloat phys_maxwaterjump;\n\tfloat phys_maxbarrier;\n\tfloat phys_jumpvel;\n\tfloat phys_falldelta5;\n\tfloat phys_falldelta10;\n\tfloat rs_waterjump;\n\tfloat rs_teleport;\n\tfloat rs_barrierjump;\n\tfloat rs_startcrouch;\n\tfloat rs_startgrapple;\n\tfloat rs_startwalkoffledge;\n\tfloat rs_startjump;\n\tfloat rs_rocketjump;\n\tfloat rs_bfgjump;\n\tfloat rs_jumppad;\n\tfloat rs_aircontrolledjumppad;\n\tfloat rs_funcbob;\n\tfloat rs_startelevator;\n\tfloat rs_falldamage5;\n\tfloat rs_falldamage10;\n\tfloat rs_maxfallheight;\n\tfloat rs_maxjumpfallheight;\n} aas_settings_t;\n\n#define CACHETYPE_PORTAL\t\t0\n#define CACHETYPE_AREA\t\t\t1\n\n//routing cache\ntypedef struct aas_routingcache_s\n{\n\tbyte type;\t\t\t\t\t\t\t\t\t//portal or area cache\n\tfloat time;\t\t\t\t\t\t\t\t\t//last time accessed or updated\n\tint size;\t\t\t\t\t\t\t\t\t//size of the routing cache\n\tint cluster;\t\t\t\t\t\t\t\t//cluster the cache is for\n\tint areanum;\t\t\t\t\t\t\t\t//area the cache is created for\n\tvec3_t origin;\t\t\t\t\t\t\t\t//origin within the area\n\tfloat starttraveltime;\t\t\t\t\t\t//travel time to start with\n\tint travelflags;\t\t\t\t\t\t\t//combinations of the travel flags\n\tstruct aas_routingcache_s *prev, *next;\n\tstruct aas_routingcache_s *time_prev, *time_next;\n\tunsigned char *reachabilities;\t\t\t\t//reachabilities used for routing\n\tunsigned short int traveltimes[1];\t\t\t//travel time for every area (variable sized)\n} aas_routingcache_t;\n\n//fields for the routing algorithm\ntypedef struct aas_routingupdate_s\n{\n\tint cluster;\n\tint areanum;\t\t\t\t\t\t\t\t//area number of the update\n\tvec3_t start;\t\t\t\t\t\t\t\t//start point the area was entered\n\tunsigned short int tmptraveltime;\t\t\t//temporary travel time\n\tunsigned short int *areatraveltimes;\t\t//travel times within the area\n\tqboolean inlist;\t\t\t\t\t\t\t//true if the update is in the list\n\tstruct aas_routingupdate_s *next;\n\tstruct aas_routingupdate_s *prev;\n} aas_routingupdate_t;\n\n//reversed reachability link\ntypedef struct aas_reversedlink_s\n{\n\tint linknum;\t\t\t\t\t\t\t\t//the aas_areareachability_t\n\tint areanum;\t\t\t\t\t\t\t\t//reachable from this area\n\tstruct aas_reversedlink_s *next;\t\t\t//next link\n} aas_reversedlink_t;\n\n//reversed area reachability\ntypedef struct aas_reversedreachability_s\n{\n\tint numlinks;\n\taas_reversedlink_t *first;\n} aas_reversedreachability_t;\n\n//areas a reachability goes through\ntypedef struct aas_reachabilityareas_s\n{\n\tint firstarea, numareas;\n} aas_reachabilityareas_t;\n\ntypedef struct aas_s\n{\n\tint loaded;\t\t\t\t\t\t\t\t\t//true when an AAS file is loaded\n\tint initialized;\t\t\t\t\t\t\t//true when AAS has been initialized\n\tint savefile;\t\t\t\t\t\t\t\t//set true when file should be saved\n\tint bspchecksum;\n\t//current time\n\tfloat time;\n\tint numframes;\n\t//name of the aas file\n\tchar filename[MAX_PATH];\n\tchar mapname[MAX_PATH];\n\t//bounding boxes\n\tint numbboxes;\n\taas_bbox_t *bboxes;\n\t//vertexes\n\tint numvertexes;\n\taas_vertex_t *vertexes;\n\t//planes\n\tint numplanes;\n\taas_plane_t *planes;\n\t//edges\n\tint numedges;\n\taas_edge_t *edges;\n\t//edge index\n\tint edgeindexsize;\n\taas_edgeindex_t *edgeindex;\n\t//faces\n\tint numfaces;\n\taas_face_t *faces;\n\t//face index\n\tint faceindexsize;\n\taas_faceindex_t *faceindex;\n\t//convex areas\n\tint numareas;\n\taas_area_t *areas;\n\t//convex area settings\n\tint numareasettings;\n\taas_areasettings_t *areasettings;\n\t//reachablity list\n\tint reachabilitysize;\n\taas_reachability_t *reachability;\n\t//nodes of the bsp tree\n\tint numnodes;\n\taas_node_t *nodes;\n\t//cluster portals\n\tint numportals;\n\taas_portal_t *portals;\n\t//cluster portal index\n\tint portalindexsize;\n\taas_portalindex_t *portalindex;\n\t//clusters\n\tint numclusters;\n\taas_cluster_t *clusters;\n\t//\n\tint numreachabilityareas;\n\tfloat reachabilitytime;\n\t//enities linked in the areas\n\taas_link_t *linkheap;\t\t\t\t\t\t//heap with link structures\n\tint linkheapsize;\t\t\t\t\t\t\t//size of the link heap\n\taas_link_t *freelinks;\t\t\t\t\t\t//first free link\n\taas_link_t **arealinkedentities;\t\t\t//entities linked into areas\n\t//entities\n\tint maxentities;\n\tint maxclients;\n\taas_entity_t *entities;\n\t//string indexes\n\tchar *configstrings[MAX_CONFIGSTRINGS];\n\tint indexessetup;\n\t//index to retrieve travel flag for a travel type\n\tint travelflagfortype[MAX_TRAVELTYPES];\n\t//travel flags for each area based on contents\n\tint *areacontentstravelflags;\n\t//routing update\n\taas_routingupdate_t *areaupdate;\n\taas_routingupdate_t *portalupdate;\n\t//number of routing updates during a frame (reset every frame)\n\tint frameroutingupdates;\n\t//reversed reachability links\n\taas_reversedreachability_t *reversedreachability;\n\t//travel times within the areas\n\tunsigned short ***areatraveltimes;\n\t//array of size numclusters with cluster cache\n\taas_routingcache_t ***clusterareacache;\n\taas_routingcache_t **portalcache;\n\t//cache list sorted on time\n\taas_routingcache_t *oldestcache;\t\t// start of cache list sorted on time\n\taas_routingcache_t *newestcache;\t\t// end of cache list sorted on time\n\t//maximum travel time through portal areas\n\tint *portalmaxtraveltimes;\n\t//areas the reachabilities go through\n\tint *reachabilityareaindex;\n\taas_reachabilityareas_t *reachabilityareas;\n} aas_t;\n\n#define AASINTERN\n\n#ifndef BSPCINCLUDE\n\n#include \"be_aas_main.h\"\n#include \"be_aas_entity.h\"\n#include \"be_aas_sample.h\"\n#include \"be_aas_cluster.h\"\n#include \"be_aas_reach.h\"\n#include \"be_aas_route.h\"\n#include \"be_aas_routealt.h\"\n#include \"be_aas_debug.h\"\n#include \"be_aas_file.h\"\n#include \"be_aas_optimize.h\"\n#include \"be_aas_bsp.h\"\n#include \"be_aas_move.h\"\n\n#endif //BSPCINCLUDE\n"
  },
  {
    "path": "src/engine/botlib/be_aas_entity.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tbe_aas_entity.c\n *\n * desc:\t\tAAS entities\n *\n * $Archive: /MissionPack/code/botlib/be_aas_entity.c $\n *\n *****************************************************************************/\n\n#include \"../../game/q_shared.h\"\n#include \"l_memory.h\"\n#include \"l_script.h\"\n#include \"l_precomp.h\"\n#include \"l_struct.h\"\n#include \"l_utils.h\"\n#include \"l_log.h\"\n#include \"aasfile.h\"\n#include \"../../game/botlib.h\"\n#include \"../../game/be_aas.h\"\n#include \"be_aas_funcs.h\"\n#include \"be_interface.h\"\n#include \"be_aas_def.h\"\n\n#define MASK_SOLID\t\tCONTENTS_PLAYERCLIP\n\n//FIXME: these might change\nenum {\n\tET_GENERAL,\n\tET_PLAYER,\n\tET_ITEM,\n\tET_MISSILE,\n\tET_MOVER\n};\n\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_UpdateEntity(int entnum, bot_entitystate_t *state)\n{\n\tint relink;\n\taas_entity_t *ent;\n\tvec3_t absmins, absmaxs;\n\n\tif (!aasworld.loaded)\n\t{\n\t\tbotimport.Print(PRT_MESSAGE, \"AAS_UpdateEntity: not loaded\\n\");\n\t\treturn BLERR_NOAASFILE;\n\t} //end if\n\n\tent = &aasworld.entities[entnum];\n\n\tif (!state) {\n\t\t//unlink the entity\n\t\tAAS_UnlinkFromAreas(ent->areas);\n\t\t//unlink the entity from the BSP leaves\n\t\tAAS_UnlinkFromBSPLeaves(ent->leaves);\n\t\t//\n\t\tent->areas = NULL;\n\t\t//\n\t\tent->leaves = NULL;\n\t\treturn BLERR_NOERROR;\n\t}\n\n\tent->i.update_time = AAS_Time() - ent->i.ltime;\n\tent->i.type = state->type;\n\tent->i.flags = state->flags;\n\tent->i.ltime = AAS_Time();\n\tVectorCopy(ent->i.origin, ent->i.lastvisorigin);\n\tVectorCopy(state->old_origin, ent->i.old_origin);\n\tent->i.solid = state->solid;\n\tent->i.groundent = state->groundent;\n\tent->i.modelindex = state->modelindex;\n\tent->i.modelindex2 = state->modelindex2;\n\tent->i.frame = state->frame;\n\tent->i.event = state->event;\n\tent->i.eventParm = state->eventParm;\n\tent->i.powerups = state->powerups;\n\tent->i.weapon = state->weapon;\n\tent->i.legsAnim = state->legsAnim;\n\tent->i.torsoAnim = state->torsoAnim;\n\t//number of the entity\n\tent->i.number = entnum;\n\t//updated so set valid flag\n\tent->i.valid = qtrue;\n\t//link everything the first frame\n\tif (aasworld.numframes == 1) relink = qtrue;\n\telse relink = qfalse;\n\t//\n\tif (ent->i.solid == SOLID_BSP)\n\t{\n\t\t//if the angles of the model changed\n\t\tif (!VectorCompare(state->angles, ent->i.angles))\n\t\t{\n\t\t\tVectorCopy(state->angles, ent->i.angles);\n\t\t\trelink = qtrue;\n\t\t} //end if\n\t\t//get the mins and maxs of the model\n\t\t//FIXME: rotate mins and maxs\n\t\tAAS_BSPModelMinsMaxsOrigin(ent->i.modelindex, ent->i.angles, ent->i.mins, ent->i.maxs, NULL);\n\t} //end if\n\telse if (ent->i.solid == SOLID_BBOX)\n\t{\n\t\t//if the bounding box size changed\n\t\tif (!VectorCompare(state->mins, ent->i.mins) ||\n\t\t\t\t!VectorCompare(state->maxs, ent->i.maxs))\n\t\t{\n\t\t\tVectorCopy(state->mins, ent->i.mins);\n\t\t\tVectorCopy(state->maxs, ent->i.maxs);\n\t\t\trelink = qtrue;\n\t\t} //end if\n\t\tVectorCopy(state->angles, ent->i.angles);\n\t} //end if\n\t//if the origin changed\n\tif (!VectorCompare(state->origin, ent->i.origin))\n\t{\n\t\tVectorCopy(state->origin, ent->i.origin);\n\t\trelink = qtrue;\n\t} //end if\n\t//if the entity should be relinked\n\tif (relink)\n\t{\n\t\t//don't link the world model\n\t\tif (entnum != ENTITYNUM_WORLD)\n\t\t{\n\t\t\t//absolute mins and maxs\n\t\t\tVectorAdd(ent->i.mins, ent->i.origin, absmins);\n\t\t\tVectorAdd(ent->i.maxs, ent->i.origin, absmaxs);\n\t\t\t//unlink the entity\n\t\t\tAAS_UnlinkFromAreas(ent->areas);\n\t\t\t//relink the entity to the AAS areas (use the larges bbox)\n\t\t\tent->areas = AAS_LinkEntityClientBBox(absmins, absmaxs, entnum, PRESENCE_NORMAL);\n\t\t\t//unlink the entity from the BSP leaves\n\t\t\tAAS_UnlinkFromBSPLeaves(ent->leaves);\n\t\t\t//link the entity to the world BSP tree\n\t\t\tent->leaves = AAS_BSPLinkEntity(absmins, absmaxs, entnum, 0);\n\t\t} //end if\n\t} //end if\n\treturn BLERR_NOERROR;\n} //end of the function AAS_UpdateEntity\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_EntityInfo(int entnum, aas_entityinfo_t *info)\n{\n\tif (!aasworld.initialized)\n\t{\n\t\tbotimport.Print(PRT_FATAL, \"AAS_EntityInfo: aasworld not initialized\\n\");\n\t\tCom_Memset(info, 0, sizeof(aas_entityinfo_t));\n\t\treturn;\n\t} //end if\n\n\tif (entnum < 0 || entnum >= aasworld.maxentities)\n\t{\n\t\tbotimport.Print(PRT_FATAL, \"AAS_EntityInfo: entnum %d out of range\\n\", entnum);\n\t\tCom_Memset(info, 0, sizeof(aas_entityinfo_t));\n\t\treturn;\n\t} //end if\n\n\tCom_Memcpy(info, &aasworld.entities[entnum].i, sizeof(aas_entityinfo_t));\n} //end of the function AAS_EntityInfo\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_EntityOrigin(int entnum, vec3_t origin)\n{\n\tif (entnum < 0 || entnum >= aasworld.maxentities)\n\t{\n\t\tbotimport.Print(PRT_FATAL, \"AAS_EntityOrigin: entnum %d out of range\\n\", entnum);\n\t\tVectorClear(origin);\n\t\treturn;\n\t} //end if\n\n\tVectorCopy(aasworld.entities[entnum].i.origin, origin);\n} //end of the function AAS_EntityOrigin\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_EntityModelindex(int entnum)\n{\n\tif (entnum < 0 || entnum >= aasworld.maxentities)\n\t{\n\t\tbotimport.Print(PRT_FATAL, \"AAS_EntityModelindex: entnum %d out of range\\n\", entnum);\n\t\treturn 0;\n\t} //end if\n\treturn aasworld.entities[entnum].i.modelindex;\n} //end of the function AAS_EntityModelindex\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_EntityType(int entnum)\n{\n\tif (!aasworld.initialized) return 0;\n\n\tif (entnum < 0 || entnum >= aasworld.maxentities)\n\t{\n\t\tbotimport.Print(PRT_FATAL, \"AAS_EntityType: entnum %d out of range\\n\", entnum);\n\t\treturn 0;\n\t} //end if\n\treturn aasworld.entities[entnum].i.type;\n} //end of the AAS_EntityType\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_EntityModelNum(int entnum)\n{\n\tif (!aasworld.initialized) return 0;\n\n\tif (entnum < 0 || entnum >= aasworld.maxentities)\n\t{\n\t\tbotimport.Print(PRT_FATAL, \"AAS_EntityModelNum: entnum %d out of range\\n\", entnum);\n\t\treturn 0;\n\t} //end if\n\treturn aasworld.entities[entnum].i.modelindex;\n} //end of the function AAS_EntityModelNum\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_OriginOfMoverWithModelNum(int modelnum, vec3_t origin)\n{\n\tint i;\n\taas_entity_t *ent;\n\n\tfor (i = 0; i < aasworld.maxentities; i++)\n\t{\n\t\tent = &aasworld.entities[i];\n\t\tif (ent->i.type == ET_MOVER)\n\t\t{\n\t\t\tif (ent->i.modelindex == modelnum)\n\t\t\t{\n\t\t\t\tVectorCopy(ent->i.origin, origin);\n\t\t\t\treturn qtrue;\n\t\t\t} //end if\n\t\t} //end if\n\t} //end for\n\treturn qfalse;\n} //end of the function AAS_OriginOfMoverWithModelNum\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_EntitySize(int entnum, vec3_t mins, vec3_t maxs)\n{\n\taas_entity_t *ent;\n\n\tif (!aasworld.initialized) return;\n\n\tif (entnum < 0 || entnum >= aasworld.maxentities)\n\t{\n\t\tbotimport.Print(PRT_FATAL, \"AAS_EntitySize: entnum %d out of range\\n\", entnum);\n\t\treturn;\n\t} //end if\n\n\tent = &aasworld.entities[entnum];\n\tVectorCopy(ent->i.mins, mins);\n\tVectorCopy(ent->i.maxs, maxs);\n} //end of the function AAS_EntitySize\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_EntityBSPData(int entnum, bsp_entdata_t *entdata)\n{\n\taas_entity_t *ent;\n\n\tent = &aasworld.entities[entnum];\n\tVectorCopy(ent->i.origin, entdata->origin);\n\tVectorCopy(ent->i.angles, entdata->angles);\n\tVectorAdd(ent->i.origin, ent->i.mins, entdata->absmins);\n\tVectorAdd(ent->i.origin, ent->i.maxs, entdata->absmaxs);\n\tentdata->solid = ent->i.solid;\n\tentdata->modelnum = ent->i.modelindex - 1;\n} //end of the function AAS_EntityBSPData\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_ResetEntityLinks(void)\n{\n\tint i;\n\tfor (i = 0; i < aasworld.maxentities; i++)\n\t{\n\t\taasworld.entities[i].areas = NULL;\n\t\taasworld.entities[i].leaves = NULL;\n\t} //end for\n} //end of the function AAS_ResetEntityLinks\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_InvalidateEntities(void)\n{\n\tint i;\n\tfor (i = 0; i < aasworld.maxentities; i++)\n\t{\n\t\taasworld.entities[i].i.valid = qfalse;\n\t\taasworld.entities[i].i.number = i;\n\t} //end for\n} //end of the function AAS_InvalidateEntities\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_UnlinkInvalidEntities(void)\n{\n\tint i;\n\taas_entity_t *ent;\n\n\tfor (i = 0; i < aasworld.maxentities; i++)\n\t{\n\t\tent = &aasworld.entities[i];\n\t\tif (!ent->i.valid)\n\t\t{\n\t\t\tAAS_UnlinkFromAreas( ent->areas );\n\t\t\tent->areas = NULL;\n\t\t\tAAS_UnlinkFromBSPLeaves( ent->leaves );\n\t\t\tent->leaves = NULL;\n\t\t} //end for\n\t} //end for\n} //end of the function AAS_UnlinkInvalidEntities\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_NearestEntity(vec3_t origin, int modelindex)\n{\n\tint i, bestentnum;\n\tfloat dist, bestdist;\n\taas_entity_t *ent;\n\tvec3_t dir;\n\n\tbestentnum = 0;\n\tbestdist = 99999;\n\tfor (i = 0; i < aasworld.maxentities; i++)\n\t{\n\t\tent = &aasworld.entities[i];\n\t\tif (ent->i.modelindex != modelindex) continue;\n\t\tVectorSubtract(ent->i.origin, origin, dir);\n\t\tif (fabs(dir[0]) < 40)\n\t\t{\n\t\t\tif (fabs(dir[1]) < 40)\n\t\t\t{\n\t\t\t\tdist = VectorLength(dir);\n\t\t\t\tif (dist < bestdist)\n\t\t\t\t{\n\t\t\t\t\tbestdist = dist;\n\t\t\t\t\tbestentnum = i;\n\t\t\t\t} //end if\n\t\t\t} //end if\n\t\t} //end if\n\t} //end for\n\treturn bestentnum;\n} //end of the function AAS_NearestEntity\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_BestReachableEntityArea(int entnum)\n{\n\taas_entity_t *ent;\n\n\tent = &aasworld.entities[entnum];\n\treturn AAS_BestReachableLinkArea(ent->areas);\n} //end of the function AAS_BestReachableEntityArea\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_NextEntity(int entnum)\n{\n\tif (!aasworld.loaded) return 0;\n\n\tif (entnum < 0) entnum = -1;\n\twhile(++entnum < aasworld.maxentities)\n\t{\n\t\tif (aasworld.entities[entnum].i.valid) return entnum;\n\t} //end while\n\treturn 0;\n} //end of the function AAS_NextEntity\n"
  },
  {
    "path": "src/engine/botlib/be_aas_entity.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tbe_aas_entity.h\n *\n * desc:\t\tAAS\n *\n * $Archive: /source/code/botlib/be_aas_entity.h $\n *\n *****************************************************************************/\n\n#ifdef AASINTERN\n//invalidates all entity infos\nvoid AAS_InvalidateEntities(void);\n//unlink not updated entities\nvoid AAS_UnlinkInvalidEntities(void);\n//resets the entity AAS and BSP links (sets areas and leaves pointers to NULL)\nvoid AAS_ResetEntityLinks(void);\n//updates an entity\nint AAS_UpdateEntity(int ent, bot_entitystate_t *state);\n//gives the entity data used for collision detection\nvoid AAS_EntityBSPData(int entnum, bsp_entdata_t *entdata);\n#endif //AASINTERN\n\n//returns the size of the entity bounding box in mins and maxs\nvoid AAS_EntitySize(int entnum, vec3_t mins, vec3_t maxs);\n//returns the BSP model number of the entity\nint AAS_EntityModelNum(int entnum);\n//returns the origin of an entity with the given model number\nint AAS_OriginOfMoverWithModelNum(int modelnum, vec3_t origin);\n//returns the best reachable area the entity is situated in\nint AAS_BestReachableEntityArea(int entnum);\n//returns the info of the given entity\nvoid AAS_EntityInfo(int entnum, aas_entityinfo_t *info);\n//returns the next entity\nint AAS_NextEntity(int entnum);\n//returns the origin of the entity\nvoid AAS_EntityOrigin(int entnum, vec3_t origin);\n//returns the entity type\nint AAS_EntityType(int entnum);\n//returns the model index of the entity\nint AAS_EntityModelindex(int entnum);\n\n"
  },
  {
    "path": "src/engine/botlib/be_aas_file.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tbe_aas_file.c\n *\n * desc:\t\tAAS file loading/writing\n *\n * $Archive: /MissionPack/code/botlib/be_aas_file.c $\n *\n *****************************************************************************/\n\n#include \"../../game/q_shared.h\"\n#include \"l_memory.h\"\n#include \"l_script.h\"\n#include \"l_precomp.h\"\n#include \"l_struct.h\"\n#include \"l_libvar.h\"\n#include \"l_utils.h\"\n#include \"aasfile.h\"\n#include \"../../game/botlib.h\"\n#include \"../../game/be_aas.h\"\n#include \"be_aas_funcs.h\"\n#include \"be_interface.h\"\n#include \"be_aas_def.h\"\n\n//#define AASFILEDEBUG\n\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_SwapAASData(void)\n{\n\tint i, j;\n\t//bounding boxes\n\tfor (i = 0; i < aasworld.numbboxes; i++)\n\t{\n\t\taasworld.bboxes[i].presencetype = LittleLong(aasworld.bboxes[i].presencetype);\n\t\taasworld.bboxes[i].flags = LittleLong(aasworld.bboxes[i].flags);\n\t\tfor (j = 0; j < 3; j++)\n\t\t{\n\t\t\taasworld.bboxes[i].mins[j] = LittleLong(aasworld.bboxes[i].mins[j]);\n\t\t\taasworld.bboxes[i].maxs[j] = LittleLong(aasworld.bboxes[i].maxs[j]);\n\t\t} //end for\n\t} //end for\n\t//vertexes\n\tfor (i = 0; i < aasworld.numvertexes; i++)\n\t{\n\t\tfor (j = 0; j < 3; j++)\n\t\t\taasworld.vertexes[i][j] = LittleFloat(aasworld.vertexes[i][j]);\n\t} //end for\n\t//planes\n\tfor (i = 0; i < aasworld.numplanes; i++)\n\t{\n\t\tfor (j = 0; j < 3; j++)\n\t\t\taasworld.planes[i].normal[j] = LittleFloat(aasworld.planes[i].normal[j]);\n\t\taasworld.planes[i].dist = LittleFloat(aasworld.planes[i].dist);\n\t\taasworld.planes[i].type = LittleLong(aasworld.planes[i].type);\n\t} //end for\n\t//edges\n\tfor (i = 0; i < aasworld.numedges; i++)\n\t{\n\t\taasworld.edges[i].v[0] = LittleLong(aasworld.edges[i].v[0]);\n\t\taasworld.edges[i].v[1] = LittleLong(aasworld.edges[i].v[1]);\n\t} //end for\n\t//edgeindex\n\tfor (i = 0; i < aasworld.edgeindexsize; i++)\n\t{\n\t\taasworld.edgeindex[i] = LittleLong(aasworld.edgeindex[i]);\n\t} //end for\n\t//faces\n\tfor (i = 0; i < aasworld.numfaces; i++)\n\t{\n\t\taasworld.faces[i].planenum = LittleLong(aasworld.faces[i].planenum);\n\t\taasworld.faces[i].faceflags = LittleLong(aasworld.faces[i].faceflags);\n\t\taasworld.faces[i].numedges = LittleLong(aasworld.faces[i].numedges);\n\t\taasworld.faces[i].firstedge = LittleLong(aasworld.faces[i].firstedge);\n\t\taasworld.faces[i].frontarea = LittleLong(aasworld.faces[i].frontarea);\n\t\taasworld.faces[i].backarea = LittleLong(aasworld.faces[i].backarea);\n\t} //end for\n\t//face index\n\tfor (i = 0; i < aasworld.faceindexsize; i++)\n\t{\n\t\taasworld.faceindex[i] = LittleLong(aasworld.faceindex[i]);\n\t} //end for\n\t//convex areas\n\tfor (i = 0; i < aasworld.numareas; i++)\n\t{\n\t\taasworld.areas[i].areanum = LittleLong(aasworld.areas[i].areanum);\n\t\taasworld.areas[i].numfaces = LittleLong(aasworld.areas[i].numfaces);\n\t\taasworld.areas[i].firstface = LittleLong(aasworld.areas[i].firstface);\n\t\tfor (j = 0; j < 3; j++)\n\t\t{\n\t\t\taasworld.areas[i].mins[j] = LittleFloat(aasworld.areas[i].mins[j]);\n\t\t\taasworld.areas[i].maxs[j] = LittleFloat(aasworld.areas[i].maxs[j]);\n\t\t\taasworld.areas[i].center[j] = LittleFloat(aasworld.areas[i].center[j]);\n\t\t} //end for\n\t} //end for\n\t//area settings\n\tfor (i = 0; i < aasworld.numareasettings; i++)\n\t{\n\t\taasworld.areasettings[i].contents = LittleLong(aasworld.areasettings[i].contents);\n\t\taasworld.areasettings[i].areaflags = LittleLong(aasworld.areasettings[i].areaflags);\n\t\taasworld.areasettings[i].presencetype = LittleLong(aasworld.areasettings[i].presencetype);\n\t\taasworld.areasettings[i].cluster = LittleLong(aasworld.areasettings[i].cluster);\n\t\taasworld.areasettings[i].clusterareanum = LittleLong(aasworld.areasettings[i].clusterareanum);\n\t\taasworld.areasettings[i].numreachableareas = LittleLong(aasworld.areasettings[i].numreachableareas);\n\t\taasworld.areasettings[i].firstreachablearea = LittleLong(aasworld.areasettings[i].firstreachablearea);\n\t} //end for\n\t//area reachability\n\tfor (i = 0; i < aasworld.reachabilitysize; i++)\n\t{\n\t\taasworld.reachability[i].areanum = LittleLong(aasworld.reachability[i].areanum);\n\t\taasworld.reachability[i].facenum = LittleLong(aasworld.reachability[i].facenum);\n\t\taasworld.reachability[i].edgenum = LittleLong(aasworld.reachability[i].edgenum);\n\t\tfor (j = 0; j < 3; j++)\n\t\t{\n\t\t\taasworld.reachability[i].start[j] = LittleFloat(aasworld.reachability[i].start[j]);\n\t\t\taasworld.reachability[i].end[j] = LittleFloat(aasworld.reachability[i].end[j]);\n\t\t} //end for\n\t\taasworld.reachability[i].traveltype = LittleLong(aasworld.reachability[i].traveltype);\n\t\taasworld.reachability[i].traveltime = LittleShort(aasworld.reachability[i].traveltime);\n\t} //end for\n\t//nodes\n\tfor (i = 0; i < aasworld.numnodes; i++)\n\t{\n\t\taasworld.nodes[i].planenum = LittleLong(aasworld.nodes[i].planenum);\n\t\taasworld.nodes[i].children[0] = LittleLong(aasworld.nodes[i].children[0]);\n\t\taasworld.nodes[i].children[1] = LittleLong(aasworld.nodes[i].children[1]);\n\t} //end for\n\t//cluster portals\n\tfor (i = 0; i < aasworld.numportals; i++)\n\t{\n\t\taasworld.portals[i].areanum = LittleLong(aasworld.portals[i].areanum);\n\t\taasworld.portals[i].frontcluster = LittleLong(aasworld.portals[i].frontcluster);\n\t\taasworld.portals[i].backcluster = LittleLong(aasworld.portals[i].backcluster);\n\t\taasworld.portals[i].clusterareanum[0] = LittleLong(aasworld.portals[i].clusterareanum[0]);\n\t\taasworld.portals[i].clusterareanum[1] = LittleLong(aasworld.portals[i].clusterareanum[1]);\n\t} //end for\n\t//cluster portal index\n\tfor (i = 0; i < aasworld.portalindexsize; i++)\n\t{\n\t\taasworld.portalindex[i] = LittleLong(aasworld.portalindex[i]);\n\t} //end for\n\t//cluster\n\tfor (i = 0; i < aasworld.numclusters; i++)\n\t{\n\t\taasworld.clusters[i].numareas = LittleLong(aasworld.clusters[i].numareas);\n\t\taasworld.clusters[i].numreachabilityareas = LittleLong(aasworld.clusters[i].numreachabilityareas);\n\t\taasworld.clusters[i].numportals = LittleLong(aasworld.clusters[i].numportals);\n\t\taasworld.clusters[i].firstportal = LittleLong(aasworld.clusters[i].firstportal);\n\t} //end for\n} //end of the function AAS_SwapAASData\n//===========================================================================\n// dump the current loaded aas file\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_DumpAASData(void)\n{\n\taasworld.numbboxes = 0;\n\tif (aasworld.bboxes) FreeMemory(aasworld.bboxes);\n\taasworld.bboxes = NULL;\n\taasworld.numvertexes = 0;\n\tif (aasworld.vertexes) FreeMemory(aasworld.vertexes);\n\taasworld.vertexes = NULL;\n\taasworld.numplanes = 0;\n\tif (aasworld.planes) FreeMemory(aasworld.planes);\n\taasworld.planes = NULL;\n\taasworld.numedges = 0;\n\tif (aasworld.edges) FreeMemory(aasworld.edges);\n\taasworld.edges = NULL;\n\taasworld.edgeindexsize = 0;\n\tif (aasworld.edgeindex) FreeMemory(aasworld.edgeindex);\n\taasworld.edgeindex = NULL;\n\taasworld.numfaces = 0;\n\tif (aasworld.faces) FreeMemory(aasworld.faces);\n\taasworld.faces = NULL;\n\taasworld.faceindexsize = 0;\n\tif (aasworld.faceindex) FreeMemory(aasworld.faceindex);\n\taasworld.faceindex = NULL;\n\taasworld.numareas = 0;\n\tif (aasworld.areas) FreeMemory(aasworld.areas);\n\taasworld.areas = NULL;\n\taasworld.numareasettings = 0;\n\tif (aasworld.areasettings) FreeMemory(aasworld.areasettings);\n\taasworld.areasettings = NULL;\n\taasworld.reachabilitysize = 0;\n\tif (aasworld.reachability) FreeMemory(aasworld.reachability);\n\taasworld.reachability = NULL;\n\taasworld.numnodes = 0;\n\tif (aasworld.nodes) FreeMemory(aasworld.nodes);\n\taasworld.nodes = NULL;\n\taasworld.numportals = 0;\n\tif (aasworld.portals) FreeMemory(aasworld.portals);\n\taasworld.portals = NULL;\n\taasworld.numportals = 0;\n\tif (aasworld.portalindex) FreeMemory(aasworld.portalindex);\n\taasworld.portalindex = NULL;\n\taasworld.portalindexsize = 0;\n\tif (aasworld.clusters) FreeMemory(aasworld.clusters);\n\taasworld.clusters = NULL;\n\taasworld.numclusters = 0;\n\t//\n\taasworld.loaded = qfalse;\n\taasworld.initialized = qfalse;\n\taasworld.savefile = qfalse;\n} //end of the function AAS_DumpAASData\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\n#ifdef AASFILEDEBUG\nvoid AAS_FileInfo(void)\n{\n\tint i, n, optimized;\n\n\tbotimport.Print(PRT_MESSAGE, \"version = %d\\n\", AASVERSION);\n\tbotimport.Print(PRT_MESSAGE, \"numvertexes = %d\\n\", aasworld.numvertexes);\n\tbotimport.Print(PRT_MESSAGE, \"numplanes = %d\\n\", aasworld.numplanes);\n\tbotimport.Print(PRT_MESSAGE, \"numedges = %d\\n\", aasworld.numedges);\n\tbotimport.Print(PRT_MESSAGE, \"edgeindexsize = %d\\n\", aasworld.edgeindexsize);\n\tbotimport.Print(PRT_MESSAGE, \"numfaces = %d\\n\", aasworld.numfaces);\n\tbotimport.Print(PRT_MESSAGE, \"faceindexsize = %d\\n\", aasworld.faceindexsize);\n\tbotimport.Print(PRT_MESSAGE, \"numareas = %d\\n\", aasworld.numareas);\n\tbotimport.Print(PRT_MESSAGE, \"numareasettings = %d\\n\", aasworld.numareasettings);\n\tbotimport.Print(PRT_MESSAGE, \"reachabilitysize = %d\\n\", aasworld.reachabilitysize);\n\tbotimport.Print(PRT_MESSAGE, \"numnodes = %d\\n\", aasworld.numnodes);\n\tbotimport.Print(PRT_MESSAGE, \"numportals = %d\\n\", aasworld.numportals);\n\tbotimport.Print(PRT_MESSAGE, \"portalindexsize = %d\\n\", aasworld.portalindexsize);\n\tbotimport.Print(PRT_MESSAGE, \"numclusters = %d\\n\", aasworld.numclusters);\n\t//\n\tfor (n = 0, i = 0; i < aasworld.numareasettings; i++)\n\t{\n\t\tif (aasworld.areasettings[i].areaflags & AREA_GROUNDED) n++;\n\t} //end for\n\tbotimport.Print(PRT_MESSAGE, \"num grounded areas = %d\\n\", n);\n\t//\n\tbotimport.Print(PRT_MESSAGE, \"planes size %d bytes\\n\", aasworld.numplanes * sizeof(aas_plane_t));\n\tbotimport.Print(PRT_MESSAGE, \"areas size %d bytes\\n\", aasworld.numareas * sizeof(aas_area_t));\n\tbotimport.Print(PRT_MESSAGE, \"areasettings size %d bytes\\n\", aasworld.numareasettings * sizeof(aas_areasettings_t));\n\tbotimport.Print(PRT_MESSAGE, \"nodes size %d bytes\\n\", aasworld.numnodes * sizeof(aas_node_t));\n\tbotimport.Print(PRT_MESSAGE, \"reachability size %d bytes\\n\", aasworld.reachabilitysize * sizeof(aas_reachability_t));\n\tbotimport.Print(PRT_MESSAGE, \"portals size %d bytes\\n\", aasworld.numportals * sizeof(aas_portal_t));\n\tbotimport.Print(PRT_MESSAGE, \"clusters size %d bytes\\n\", aasworld.numclusters * sizeof(aas_cluster_t));\n\n\toptimized = aasworld.numplanes * sizeof(aas_plane_t) +\n\t\t\t\t\taasworld.numareas * sizeof(aas_area_t) +\n\t\t\t\t\taasworld.numareasettings * sizeof(aas_areasettings_t) +\n\t\t\t\t\taasworld.numnodes * sizeof(aas_node_t) +\n\t\t\t\t\taasworld.reachabilitysize * sizeof(aas_reachability_t) +\n\t\t\t\t\taasworld.numportals * sizeof(aas_portal_t) +\n\t\t\t\t\taasworld.numclusters * sizeof(aas_cluster_t);\n\tbotimport.Print(PRT_MESSAGE, \"optimzed size %d KB\\n\", optimized >> 10);\n} //end of the function AAS_FileInfo\n#endif //AASFILEDEBUG\n//===========================================================================\n// allocate memory and read a lump of a AAS file\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nchar *AAS_LoadAASLump(fileHandle_t fp, int offset, int length, int *lastoffset, int size)\n{\n\tchar *buf;\n\t//\n\tif (!length)\n\t{\n\t\t//just alloc a dummy\n\t\treturn (char *) GetClearedHunkMemory(size+1);\n\t} //end if\n\t//seek to the data\n\tif (offset != *lastoffset)\n\t{\n\t\tbotimport.Print(PRT_WARNING, \"AAS file not sequentially read\\n\");\n\t\tif (botimport.FS_Seek(fp, offset, FS_SEEK_SET))\n\t\t{\n\t\t\tAAS_Error(\"can't seek to aas lump\\n\");\n\t\t\tAAS_DumpAASData();\n\t\t\tbotimport.FS_FCloseFile(fp);\n\t\t\treturn 0;\n\t\t} //end if\n\t} //end if\n\t//allocate memory\n\tbuf = (char *) GetClearedHunkMemory(length+1);\n\t//read the data\n\tif (length)\n\t{\n\t\tbotimport.FS_Read(buf, length, fp );\n\t\t*lastoffset += length;\n\t} //end if\n\treturn buf;\n} //end of the function AAS_LoadAASLump\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_DData(unsigned char *data, int size)\n{\n\tint i;\n\n\tfor (i = 0; i < size; i++)\n\t{\n\t\tdata[i] ^= (unsigned char) i * 119;\n\t} //end for\n} //end of the function AAS_DData\n//===========================================================================\n// load an aas file\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_LoadAASFile(char *filename)\n{\n\tfileHandle_t fp;\n\taas_header_t header;\n\tint offset, length, lastoffset;\n\n\tbotimport.Print(PRT_MESSAGE, \"trying to load %s\\n\", filename);\n\t//dump current loaded aas file\n\tAAS_DumpAASData();\n\t//open the file\n\tbotimport.FS_FOpenFile( filename, &fp, FS_READ );\n\tif (!fp)\n\t{\n\t\tAAS_Error(\"can't open %s\\n\", filename);\n\t\treturn BLERR_CANNOTOPENAASFILE;\n\t} //end if\n\t//read the header\n\tbotimport.FS_Read(&header, sizeof(aas_header_t), fp );\n\tlastoffset = sizeof(aas_header_t);\n\t//check header identification\n\theader.ident = LittleLong(header.ident);\n\tif (header.ident != AASID)\n\t{\n\t\tAAS_Error(\"%s is not an AAS file\\n\", filename);\n\t\tbotimport.FS_FCloseFile(fp);\n\t\treturn BLERR_WRONGAASFILEID;\n\t} //end if\n\t//check the version\n\theader.version = LittleLong(header.version);\n\t//\n\tif (header.version != AASVERSION_OLD && header.version != AASVERSION)\n\t{\n\t\tAAS_Error(\"aas file %s is version %i, not %i\\n\", filename, header.version, AASVERSION);\n\t\tbotimport.FS_FCloseFile(fp);\n\t\treturn BLERR_WRONGAASFILEVERSION;\n\t} //end if\n\t//\n\tif (header.version == AASVERSION)\n\t{\n\t\tAAS_DData((unsigned char *) &header + 8, sizeof(aas_header_t) - 8);\n\t} //end if\n\t//\n\taasworld.bspchecksum = atoi(LibVarGetString( \"sv_mapChecksum\"));\n\tif (LittleLong(header.bspchecksum) != aasworld.bspchecksum)\n\t{\n\t\tAAS_Error(\"aas file %s is out of date\\n\", filename);\n\t\tbotimport.FS_FCloseFile(fp);\n\t\treturn BLERR_WRONGAASFILEVERSION;\n\t} //end if\n\t//load the lumps:\n\t//bounding boxes\n\toffset = LittleLong(header.lumps[AASLUMP_BBOXES].fileofs);\n\tlength = LittleLong(header.lumps[AASLUMP_BBOXES].filelen);\n\taasworld.bboxes = (aas_bbox_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_bbox_t));\n\taasworld.numbboxes = length / sizeof(aas_bbox_t);\n\tif (aasworld.numbboxes && !aasworld.bboxes) return BLERR_CANNOTREADAASLUMP;\n\t//vertexes\n\toffset = LittleLong(header.lumps[AASLUMP_VERTEXES].fileofs);\n\tlength = LittleLong(header.lumps[AASLUMP_VERTEXES].filelen);\n\taasworld.vertexes = (aas_vertex_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_vertex_t));\n\taasworld.numvertexes = length / sizeof(aas_vertex_t);\n\tif (aasworld.numvertexes && !aasworld.vertexes) return BLERR_CANNOTREADAASLUMP;\n\t//planes\n\toffset = LittleLong(header.lumps[AASLUMP_PLANES].fileofs);\n\tlength = LittleLong(header.lumps[AASLUMP_PLANES].filelen);\n\taasworld.planes = (aas_plane_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_plane_t));\n\taasworld.numplanes = length / sizeof(aas_plane_t);\n\tif (aasworld.numplanes && !aasworld.planes) return BLERR_CANNOTREADAASLUMP;\n\t//edges\n\toffset = LittleLong(header.lumps[AASLUMP_EDGES].fileofs);\n\tlength = LittleLong(header.lumps[AASLUMP_EDGES].filelen);\n\taasworld.edges = (aas_edge_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_edge_t));\n\taasworld.numedges = length / sizeof(aas_edge_t);\n\tif (aasworld.numedges && !aasworld.edges) return BLERR_CANNOTREADAASLUMP;\n\t//edgeindex\n\toffset = LittleLong(header.lumps[AASLUMP_EDGEINDEX].fileofs);\n\tlength = LittleLong(header.lumps[AASLUMP_EDGEINDEX].filelen);\n\taasworld.edgeindex = (aas_edgeindex_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_edgeindex_t));\n\taasworld.edgeindexsize = length / sizeof(aas_edgeindex_t);\n\tif (aasworld.edgeindexsize && !aasworld.edgeindex) return BLERR_CANNOTREADAASLUMP;\n\t//faces\n\toffset = LittleLong(header.lumps[AASLUMP_FACES].fileofs);\n\tlength = LittleLong(header.lumps[AASLUMP_FACES].filelen);\n\taasworld.faces = (aas_face_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_face_t));\n\taasworld.numfaces = length / sizeof(aas_face_t);\n\tif (aasworld.numfaces && !aasworld.faces) return BLERR_CANNOTREADAASLUMP;\n\t//faceindex\n\toffset = LittleLong(header.lumps[AASLUMP_FACEINDEX].fileofs);\n\tlength = LittleLong(header.lumps[AASLUMP_FACEINDEX].filelen);\n\taasworld.faceindex = (aas_faceindex_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_faceindex_t));\n\taasworld.faceindexsize = length / sizeof(aas_faceindex_t);\n\tif (aasworld.faceindexsize && !aasworld.faceindex) return BLERR_CANNOTREADAASLUMP;\n\t//convex areas\n\toffset = LittleLong(header.lumps[AASLUMP_AREAS].fileofs);\n\tlength = LittleLong(header.lumps[AASLUMP_AREAS].filelen);\n\taasworld.areas = (aas_area_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_area_t));\n\taasworld.numareas = length / sizeof(aas_area_t);\n\tif (aasworld.numareas && !aasworld.areas) return BLERR_CANNOTREADAASLUMP;\n\t//area settings\n\toffset = LittleLong(header.lumps[AASLUMP_AREASETTINGS].fileofs);\n\tlength = LittleLong(header.lumps[AASLUMP_AREASETTINGS].filelen);\n\taasworld.areasettings = (aas_areasettings_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_areasettings_t));\n\taasworld.numareasettings = length / sizeof(aas_areasettings_t);\n\tif (aasworld.numareasettings && !aasworld.areasettings) return BLERR_CANNOTREADAASLUMP;\n\t//reachability list\n\toffset = LittleLong(header.lumps[AASLUMP_REACHABILITY].fileofs);\n\tlength = LittleLong(header.lumps[AASLUMP_REACHABILITY].filelen);\n\taasworld.reachability = (aas_reachability_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_reachability_t));\n\taasworld.reachabilitysize = length / sizeof(aas_reachability_t);\n\tif (aasworld.reachabilitysize && !aasworld.reachability) return BLERR_CANNOTREADAASLUMP;\n\t//nodes\n\toffset = LittleLong(header.lumps[AASLUMP_NODES].fileofs);\n\tlength = LittleLong(header.lumps[AASLUMP_NODES].filelen);\n\taasworld.nodes = (aas_node_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_node_t));\n\taasworld.numnodes = length / sizeof(aas_node_t);\n\tif (aasworld.numnodes && !aasworld.nodes) return BLERR_CANNOTREADAASLUMP;\n\t//cluster portals\n\toffset = LittleLong(header.lumps[AASLUMP_PORTALS].fileofs);\n\tlength = LittleLong(header.lumps[AASLUMP_PORTALS].filelen);\n\taasworld.portals = (aas_portal_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_portal_t));\n\taasworld.numportals = length / sizeof(aas_portal_t);\n\tif (aasworld.numportals && !aasworld.portals) return BLERR_CANNOTREADAASLUMP;\n\t//cluster portal index\n\toffset = LittleLong(header.lumps[AASLUMP_PORTALINDEX].fileofs);\n\tlength = LittleLong(header.lumps[AASLUMP_PORTALINDEX].filelen);\n\taasworld.portalindex = (aas_portalindex_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_portalindex_t));\n\taasworld.portalindexsize = length / sizeof(aas_portalindex_t);\n\tif (aasworld.portalindexsize && !aasworld.portalindex) return BLERR_CANNOTREADAASLUMP;\n\t//clusters\n\toffset = LittleLong(header.lumps[AASLUMP_CLUSTERS].fileofs);\n\tlength = LittleLong(header.lumps[AASLUMP_CLUSTERS].filelen);\n\taasworld.clusters = (aas_cluster_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_cluster_t));\n\taasworld.numclusters = length / sizeof(aas_cluster_t);\n\tif (aasworld.numclusters && !aasworld.clusters) return BLERR_CANNOTREADAASLUMP;\n\t//swap everything\n\tAAS_SwapAASData();\n\t//aas file is loaded\n\taasworld.loaded = qtrue;\n\t//close the file\n\tbotimport.FS_FCloseFile(fp);\n\t//\n#ifdef AASFILEDEBUG\n\tAAS_FileInfo();\n#endif //AASFILEDEBUG\n\t//\n\treturn BLERR_NOERROR;\n} //end of the function AAS_LoadAASFile\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nstatic int AAS_WriteAASLump_offset;\n\nint AAS_WriteAASLump(fileHandle_t fp, aas_header_t *h, int lumpnum, void *data, int length)\n{\n\taas_lump_t *lump;\n\n\tlump = &h->lumps[lumpnum];\n\t\n\tlump->fileofs = LittleLong(AAS_WriteAASLump_offset);\t//LittleLong(ftell(fp));\n\tlump->filelen = LittleLong(length);\n\n\tif (length > 0)\n\t{\n\t\tbotimport.FS_Write(data, length, fp );\n\t} //end if\n\n\tAAS_WriteAASLump_offset += length;\n\n\treturn qtrue;\n} //end of the function AAS_WriteAASLump\n//===========================================================================\n// aas data is useless after writing to file because it is byte swapped\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nqboolean AAS_WriteAASFile(char *filename)\n{\n\taas_header_t header;\n\tfileHandle_t fp;\n\n\tbotimport.Print(PRT_MESSAGE, \"writing %s\\n\", filename);\n\t//swap the aas data\n\tAAS_SwapAASData();\n\t//initialize the file header\n\tCom_Memset(&header, 0, sizeof(aas_header_t));\n\theader.ident = LittleLong(AASID);\n\theader.version = LittleLong(AASVERSION);\n\theader.bspchecksum = LittleLong(aasworld.bspchecksum);\n\t//open a new file\n\tbotimport.FS_FOpenFile( filename, &fp, FS_WRITE );\n\tif (!fp)\n\t{\n\t\tbotimport.Print(PRT_ERROR, \"error opening %s\\n\", filename);\n\t\treturn qfalse;\n\t} //end if\n\t//write the header\n\tbotimport.FS_Write(&header, sizeof(aas_header_t), fp);\n\tAAS_WriteAASLump_offset = sizeof(aas_header_t);\n\t//add the data lumps to the file\n\tif (!AAS_WriteAASLump(fp, &header, AASLUMP_BBOXES, aasworld.bboxes,\n\t\taasworld.numbboxes * sizeof(aas_bbox_t))) return qfalse;\n\tif (!AAS_WriteAASLump(fp, &header, AASLUMP_VERTEXES, aasworld.vertexes,\n\t\taasworld.numvertexes * sizeof(aas_vertex_t))) return qfalse;\n\tif (!AAS_WriteAASLump(fp, &header, AASLUMP_PLANES, aasworld.planes,\n\t\taasworld.numplanes * sizeof(aas_plane_t))) return qfalse;\n\tif (!AAS_WriteAASLump(fp, &header, AASLUMP_EDGES, aasworld.edges,\n\t\taasworld.numedges * sizeof(aas_edge_t))) return qfalse;\n\tif (!AAS_WriteAASLump(fp, &header, AASLUMP_EDGEINDEX, aasworld.edgeindex,\n\t\taasworld.edgeindexsize * sizeof(aas_edgeindex_t))) return qfalse;\n\tif (!AAS_WriteAASLump(fp, &header, AASLUMP_FACES, aasworld.faces,\n\t\taasworld.numfaces * sizeof(aas_face_t))) return qfalse;\n\tif (!AAS_WriteAASLump(fp, &header, AASLUMP_FACEINDEX, aasworld.faceindex,\n\t\taasworld.faceindexsize * sizeof(aas_faceindex_t))) return qfalse;\n\tif (!AAS_WriteAASLump(fp, &header, AASLUMP_AREAS, aasworld.areas,\n\t\taasworld.numareas * sizeof(aas_area_t))) return qfalse;\n\tif (!AAS_WriteAASLump(fp, &header, AASLUMP_AREASETTINGS, aasworld.areasettings,\n\t\taasworld.numareasettings * sizeof(aas_areasettings_t))) return qfalse;\n\tif (!AAS_WriteAASLump(fp, &header, AASLUMP_REACHABILITY, aasworld.reachability,\n\t\taasworld.reachabilitysize * sizeof(aas_reachability_t))) return qfalse;\n\tif (!AAS_WriteAASLump(fp, &header, AASLUMP_NODES, aasworld.nodes,\n\t\taasworld.numnodes * sizeof(aas_node_t))) return qfalse;\n\tif (!AAS_WriteAASLump(fp, &header, AASLUMP_PORTALS, aasworld.portals,\n\t\taasworld.numportals * sizeof(aas_portal_t))) return qfalse;\n\tif (!AAS_WriteAASLump(fp, &header, AASLUMP_PORTALINDEX, aasworld.portalindex,\n\t\taasworld.portalindexsize * sizeof(aas_portalindex_t))) return qfalse;\n\tif (!AAS_WriteAASLump(fp, &header, AASLUMP_CLUSTERS, aasworld.clusters,\n\t\taasworld.numclusters * sizeof(aas_cluster_t))) return qfalse;\n\t//rewrite the header with the added lumps\n\tbotimport.FS_Seek(fp, 0, FS_SEEK_SET);\n\tAAS_DData((unsigned char *) &header + 8, sizeof(aas_header_t) - 8);\n\tbotimport.FS_Write(&header, sizeof(aas_header_t), fp);\n\t//close the file\n\tbotimport.FS_FCloseFile(fp);\n\treturn qtrue;\n} //end of the function AAS_WriteAASFile\n"
  },
  {
    "path": "src/engine/botlib/be_aas_file.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tbe_aas_file.h\n *\n * desc:\t\tAAS\n *\n * $Archive: /source/code/botlib/be_aas_file.h $\n *\n *****************************************************************************/\n\n#ifdef AASINTERN\n//loads the AAS file with the given name\nint AAS_LoadAASFile(char *filename);\n//writes an AAS file with the given name\nqboolean AAS_WriteAASFile(char *filename);\n//dumps the loaded AAS data\nvoid AAS_DumpAASData(void);\n//print AAS file information\nvoid AAS_FileInfo(void);\n#endif //AASINTERN\n\n"
  },
  {
    "path": "src/engine/botlib/be_aas_funcs.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tbe_aas_funcs.h\n *\n * desc:\t\tAAS\n *\n * $Archive: /source/code/botlib/be_aas_funcs.h $\n *\n *****************************************************************************/\n\n#ifndef BSPCINCLUDE\n\n#include \"be_aas_main.h\"\n#include \"be_aas_entity.h\"\n#include \"be_aas_sample.h\"\n#include \"be_aas_cluster.h\"\n#include \"be_aas_reach.h\"\n#include \"be_aas_route.h\"\n#include \"be_aas_routealt.h\"\n#include \"be_aas_debug.h\"\n#include \"be_aas_file.h\"\n#include \"be_aas_optimize.h\"\n#include \"be_aas_bsp.h\"\n#include \"be_aas_move.h\"\n\n#endif //BSPCINCLUDE\n"
  },
  {
    "path": "src/engine/botlib/be_aas_main.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tbe_aas_main.c\n *\n * desc:\t\tAAS\n *\n * $Archive: /MissionPack/code/botlib/be_aas_main.c $\n *\n *****************************************************************************/\n\n#include \"../../game/q_shared.h\"\n#include \"l_memory.h\"\n#include \"l_libvar.h\"\n#include \"l_utils.h\"\n#include \"l_script.h\"\n#include \"l_precomp.h\"\n#include \"l_struct.h\"\n#include \"l_log.h\"\n#include \"aasfile.h\"\n#include \"../../game/botlib.h\"\n#include \"../../game/be_aas.h\"\n#include \"be_aas_funcs.h\"\n#include \"be_interface.h\"\n#include \"be_aas_def.h\"\n\naas_t aasworld;\n\nlibvar_t *saveroutingcache;\n\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid QDECL AAS_Error(char *fmt, ...)\n{\n\tchar str[1024];\n\tva_list arglist;\n\n\tva_start(arglist, fmt);\n\tvsprintf(str, fmt, arglist);\n\tva_end(arglist);\n\tbotimport.Print(PRT_FATAL, str);\n} //end of the function AAS_Error\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nchar *AAS_StringFromIndex(char *indexname, char *stringindex[], int numindexes, int index)\n{\n\tif (!aasworld.indexessetup)\n\t{\n\t\tbotimport.Print(PRT_ERROR, \"%s: index %d not setup\\n\", indexname, index);\n\t\treturn \"\";\n\t} //end if\n\tif (index < 0 || index >= numindexes)\n\t{\n\t\tbotimport.Print(PRT_ERROR, \"%s: index %d out of range\\n\", indexname, index);\n\t\treturn \"\";\n\t} //end if\n\tif (!stringindex[index])\n\t{\n\t\tif (index)\n\t\t{\n\t\t\tbotimport.Print(PRT_ERROR, \"%s: reference to unused index %d\\n\", indexname, index);\n\t\t} //end if\n\t\treturn \"\";\n\t} //end if\n\treturn stringindex[index];\n} //end of the function AAS_StringFromIndex\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_IndexFromString(char *indexname, char *stringindex[], int numindexes, char *string)\n{\n\tint i;\n\tif (!aasworld.indexessetup)\n\t{\n\t\tbotimport.Print(PRT_ERROR, \"%s: index not setup \\\"%s\\\"\\n\", indexname, string);\n\t\treturn 0;\n\t} //end if\n\tfor (i = 0; i < numindexes; i++)\n\t{\n\t\tif (!stringindex[i]) continue;\n\t\tif (!Q_stricmp(stringindex[i], string)) return i;\n\t} //end for\n\treturn 0;\n} //end of the function AAS_IndexFromString\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nchar *AAS_ModelFromIndex(int index)\n{\n\treturn AAS_StringFromIndex(\"ModelFromIndex\", &aasworld.configstrings[CS_MODELS], MAX_MODELS, index);\n} //end of the function AAS_ModelFromIndex\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_IndexFromModel(char *modelname)\n{\n\treturn AAS_IndexFromString(\"IndexFromModel\", &aasworld.configstrings[CS_MODELS], MAX_MODELS, modelname);\n} //end of the function AAS_IndexFromModel\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_UpdateStringIndexes(int numconfigstrings, char *configstrings[])\n{\n\tint i;\n\t//set string pointers and copy the strings\n\tfor (i = 0; i < numconfigstrings; i++)\n\t{\n\t\tif (configstrings[i])\n\t\t{\n\t\t\t//if (aasworld.configstrings[i]) FreeMemory(aasworld.configstrings[i]);\n\t\t\taasworld.configstrings[i] = (char *) GetMemory((int)strlen(configstrings[i]) + 1);\n\t\t\tstrcpy(aasworld.configstrings[i], configstrings[i]);\n\t\t} //end if\n\t} //end for\n\taasworld.indexessetup = qtrue;\n} //end of the function AAS_UpdateStringIndexes\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_Loaded(void)\n{\n\treturn aasworld.loaded;\n} //end of the function AAS_Loaded\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_Initialized(void)\n{\n\treturn aasworld.initialized;\n} //end of the function AAS_Initialized\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_SetInitialized(void)\n{\n\taasworld.initialized = qtrue;\n\tbotimport.Print(PRT_MESSAGE, \"AAS initialized.\\n\");\n#ifdef DEBUG\n\t//create all the routing cache\n\t//AAS_CreateAllRoutingCache();\n\t//\n\t//AAS_RoutingInfo();\n#endif\n} //end of the function AAS_SetInitialized\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_ContinueInit(float time)\n{\n\t//if no AAS file loaded\n\tif (!aasworld.loaded) return;\n\t//if AAS is already initialized\n\tif (aasworld.initialized) return;\n\t//calculate reachability, if not finished return\n\tif (AAS_ContinueInitReachability(time)) return;\n\t//initialize clustering for the new map\n\tAAS_InitClustering();\n\t//if reachability has been calculated and an AAS file should be written\n\t//or there is a forced data optimization\n\tif (aasworld.savefile || ((int)LibVarGetValue(\"forcewrite\")))\n\t{\n\t\t//optimize the AAS data\n\t\tif ((int)LibVarValue(\"aasoptimize\", \"0\")) AAS_Optimize();\n\t\t//save the AAS file\n\t\tif (AAS_WriteAASFile(aasworld.filename))\n\t\t{\n\t\t\tbotimport.Print(PRT_MESSAGE, \"%s written succesfully\\n\", aasworld.filename);\n\t\t} //end if\n\t\telse\n\t\t{\n\t\t\tbotimport.Print(PRT_ERROR, \"couldn't write %s\\n\", aasworld.filename);\n\t\t} //end else\n\t} //end if\n\t//initialize the routing\n\tAAS_InitRouting();\n\t//at this point AAS is initialized\n\tAAS_SetInitialized();\n} //end of the function AAS_ContinueInit\n//===========================================================================\n// called at the start of every frame\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_StartFrame(float time)\n{\n\taasworld.time = time;\n\t//unlink all entities that were not updated last frame\n\tAAS_UnlinkInvalidEntities();\n\t//invalidate the entities\n\tAAS_InvalidateEntities();\n\t//initialize AAS\n\tAAS_ContinueInit(time);\n\t//\n\taasworld.frameroutingupdates = 0;\n\t//\n\tif (bot_developer)\n\t{\n\t\tif (LibVarGetValue(\"showcacheupdates\"))\n\t\t{\n\t\t\tAAS_RoutingInfo();\n\t\t\tLibVarSet(\"showcacheupdates\", \"0\");\n\t\t} //end if\n\t\tif (LibVarGetValue(\"showmemoryusage\"))\n\t\t{\n\t\t\tPrintUsedMemorySize();\n\t\t\tLibVarSet(\"showmemoryusage\", \"0\");\n\t\t} //end if\n\t\tif (LibVarGetValue(\"memorydump\"))\n\t\t{\n\t\t\tPrintMemoryLabels();\n\t\t\tLibVarSet(\"memorydump\", \"0\");\n\t\t} //end if\n\t} //end if\n\t//\n\tif (saveroutingcache->value)\n\t{\n\t\tAAS_WriteRouteCache();\n\t\tLibVarSet(\"saveroutingcache\", \"0\");\n\t} //end if\n\t//\n\taasworld.numframes++;\n\treturn BLERR_NOERROR;\n} //end of the function AAS_StartFrame\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nfloat AAS_Time(void)\n{\n\treturn aasworld.time;\n} //end of the function AAS_Time\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_ProjectPointOntoVector( vec3_t point, vec3_t vStart, vec3_t vEnd, vec3_t vProj )\n{\n\tvec3_t pVec, vec;\n\n\tVectorSubtract( point, vStart, pVec );\n\tVectorSubtract( vEnd, vStart, vec );\n\tVectorNormalize( vec );\n\t// project onto the directional vector for this segment\n\tVectorMA( vStart, DotProduct( pVec, vec ), vec, vProj );\n} //end of the function AAS_ProjectPointOntoVector\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_LoadFiles(const char *mapname)\n{\n\tint errnum;\n\tchar aasfile[MAX_PATH];\n//\tchar bspfile[MAX_PATH];\n\n\tstrcpy(aasworld.mapname, mapname);\n\t//NOTE: first reset the entity links into the AAS areas and BSP leaves\n\t// the AAS link heap and BSP link heap are reset after respectively the\n\t// AAS file and BSP file are loaded\n\tAAS_ResetEntityLinks();\n\t// load bsp info\n\tAAS_LoadBSPFile();\n\n\t//load the aas file\n\tCom_sprintf(aasfile, MAX_PATH, \"maps/%s.aas\", mapname);\n\terrnum = AAS_LoadAASFile(aasfile);\n\tif (errnum != BLERR_NOERROR)\n\t\treturn errnum;\n\n\tbotimport.Print(PRT_MESSAGE, \"loaded %s\\n\", aasfile);\n\tstrncpy(aasworld.filename, aasfile, MAX_PATH);\n\treturn BLERR_NOERROR;\n} //end of the function AAS_LoadFiles\n//===========================================================================\n// called everytime a map changes\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_LoadMap(const char *mapname)\n{\n\tint\terrnum;\n\n\t//if no mapname is provided then the string indexes are updated\n\tif (!mapname)\n\t{\n\t\treturn 0;\n\t} //end if\n\t//\n\taasworld.initialized = qfalse;\n\t//NOTE: free the routing caches before loading a new map because\n\t// to free the caches the old number of areas, number of clusters\n\t// and number of areas in a clusters must be available\n\tAAS_FreeRoutingCaches();\n\t//load the map\n\terrnum = AAS_LoadFiles(mapname);\n\tif (errnum != BLERR_NOERROR)\n\t{\n\t\taasworld.loaded = qfalse;\n\t\treturn errnum;\n\t} //end if\n\t//\n\tAAS_InitSettings();\n\t//initialize the AAS link heap for the new map\n\tAAS_InitAASLinkHeap();\n\t//initialize the AAS linked entities for the new map\n\tAAS_InitAASLinkedEntities();\n\t//initialize reachability for the new map\n\tAAS_InitReachability();\n\t//initialize the alternative routing\n\tAAS_InitAlternativeRouting();\n\t//everything went ok\n\treturn 0;\n} //end of the function AAS_LoadMap\n//===========================================================================\n// called when the library is first loaded\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_Setup(void)\n{\n\taasworld.maxclients = (int) LibVarValue(\"maxclients\", \"128\");\n\taasworld.maxentities = (int) LibVarValue(\"maxentities\", \"1024\");\n\t// as soon as it's set to 1 the routing cache will be saved\n\tsaveroutingcache = LibVar(\"saveroutingcache\", \"0\");\n\t//allocate memory for the entities\n\tif (aasworld.entities) FreeMemory(aasworld.entities);\n\taasworld.entities = (aas_entity_t *) GetClearedHunkMemory(aasworld.maxentities * sizeof(aas_entity_t));\n\t//invalidate all the entities\n\tAAS_InvalidateEntities();\n\t//force some recalculations\n\t//LibVarSet(\"forceclustering\", \"1\");\t\t\t//force clustering calculation\n\t//LibVarSet(\"forcereachability\", \"1\");\t\t//force reachability calculation\n\taasworld.numframes = 0;\n\treturn BLERR_NOERROR;\n} //end of the function AAS_Setup\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_Shutdown(void)\n{\n\tAAS_ShutdownAlternativeRouting();\n\t//\n\tAAS_DumpBSPData();\n\t//free routing caches\n\tAAS_FreeRoutingCaches();\n\t//free aas link heap\n\tAAS_FreeAASLinkHeap();\n\t//free aas linked entities\n\tAAS_FreeAASLinkedEntities();\n\t//free the aas data\n\tAAS_DumpAASData();\n\t//free the entities\n\tif (aasworld.entities) FreeMemory(aasworld.entities);\n\t//clear the aasworld structure\n\tCom_Memset(&aasworld, 0, sizeof(aas_t));\n\t//aas has not been initialized\n\taasworld.initialized = qfalse;\n\t//NOTE: as soon as a new .bsp file is loaded the .bsp file memory is\n\t// freed an reallocated, so there's no need to free that memory here\n\t//print shutdown\n\tbotimport.Print(PRT_MESSAGE, \"AAS shutdown.\\n\");\n} //end of the function AAS_Shutdown\n"
  },
  {
    "path": "src/engine/botlib/be_aas_main.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tbe_aas_main.h\n *\n * desc:\t\tAAS\n *\n * $Archive: /source/code/botlib/be_aas_main.h $\n *\n *****************************************************************************/\n\n#ifdef AASINTERN\n\nextern aas_t aasworld;\n\n//AAS error message\nvoid QDECL AAS_Error(char *fmt, ...);\n//set AAS initialized\nvoid AAS_SetInitialized(void);\n//setup AAS with the given number of entities and clients\nint AAS_Setup(void);\n//shutdown AAS\nvoid AAS_Shutdown(void);\n//start a new map\nint AAS_LoadMap(const char *mapname);\n//start a new time frame\nint AAS_StartFrame(float time);\n#endif //AASINTERN\n\n//returns true if AAS is initialized\nint AAS_Initialized(void);\n//returns true if the AAS file is loaded\nint AAS_Loaded(void);\n//returns the model name from the given index\nchar *AAS_ModelFromIndex(int index);\n//returns the index from the given model name\nint AAS_IndexFromModel(char *modelname);\n//returns the current time\nfloat AAS_Time(void);\n//\nvoid AAS_ProjectPointOntoVector( vec3_t point, vec3_t vStart, vec3_t vEnd, vec3_t vProj );\n"
  },
  {
    "path": "src/engine/botlib/be_aas_move.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tbe_aas_move.c\n *\n * desc:\t\tAAS\n *\n * $Archive: /MissionPack/code/botlib/be_aas_move.c $\n *\n *****************************************************************************/\n\n#include \"../../game/q_shared.h\"\n#include \"l_memory.h\"\n#include \"l_script.h\"\n#include \"l_precomp.h\"\n#include \"l_struct.h\"\n#include \"l_libvar.h\"\n#include \"aasfile.h\"\n#include \"../../game/botlib.h\"\n#include \"../../game/be_aas.h\"\n#include \"be_aas_funcs.h\"\n#include \"be_aas_def.h\"\n\nextern botlib_import_t botimport;\n\naas_settings_t aassettings;\n\n//#define AAS_MOVE_DEBUG\n\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_DropToFloor(vec3_t origin, vec3_t mins, vec3_t maxs)\n{\n\tvec3_t end;\n\tbsp_trace_t trace;\n\n\tVectorCopy(origin, end);\n\tend[2] -= 100;\n\ttrace = AAS_Trace(origin, mins, maxs, end, 0, CONTENTS_SOLID);\n\tif (trace.startsolid) return qfalse;\n\tVectorCopy(trace.endpos, origin);\n\treturn qtrue;\n} //end of the function AAS_DropToFloor\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_InitSettings(void)\n{\n\taassettings.phys_gravitydirection[0]\t= 0;\n\taassettings.phys_gravitydirection[1]\t= 0;\n\taassettings.phys_gravitydirection[2]\t= -1;\n\taassettings.phys_friction\t\t\t\t= LibVarValue(\"phys_friction\", \"6\");\n\taassettings.phys_stopspeed\t\t\t\t= LibVarValue(\"phys_stopspeed\", \"100\");\n\taassettings.phys_gravity\t\t\t\t= LibVarValue(\"phys_gravity\", \"800\");\n\taassettings.phys_waterfriction\t\t\t= LibVarValue(\"phys_waterfriction\", \"1\");\n\taassettings.phys_watergravity\t\t\t= LibVarValue(\"phys_watergravity\", \"400\");\n\taassettings.phys_maxvelocity\t\t\t= LibVarValue(\"phys_maxvelocity\", \"320\");\n\taassettings.phys_maxwalkvelocity\t\t= LibVarValue(\"phys_maxwalkvelocity\", \"320\");\n\taassettings.phys_maxcrouchvelocity\t\t= LibVarValue(\"phys_maxcrouchvelocity\", \"100\");\n\taassettings.phys_maxswimvelocity\t\t= LibVarValue(\"phys_maxswimvelocity\", \"150\");\n\taassettings.phys_walkaccelerate\t\t\t= LibVarValue(\"phys_walkaccelerate\", \"10\");\n\taassettings.phys_airaccelerate\t\t\t= LibVarValue(\"phys_airaccelerate\", \"1\");\n\taassettings.phys_swimaccelerate\t\t\t= LibVarValue(\"phys_swimaccelerate\", \"4\");\n\taassettings.phys_maxstep\t\t\t\t= LibVarValue(\"phys_maxstep\", \"19\");\n\taassettings.phys_maxsteepness\t\t\t= LibVarValue(\"phys_maxsteepness\", \"0.7\");\n\taassettings.phys_maxwaterjump\t\t\t= LibVarValue(\"phys_maxwaterjump\", \"18\");\n\taassettings.phys_maxbarrier\t\t\t\t= LibVarValue(\"phys_maxbarrier\", \"33\");\n\taassettings.phys_jumpvel\t\t\t\t= LibVarValue(\"phys_jumpvel\", \"270\");\n\taassettings.phys_falldelta5\t\t\t\t= LibVarValue(\"phys_falldelta5\", \"40\");\n\taassettings.phys_falldelta10\t\t\t= LibVarValue(\"phys_falldelta10\", \"60\");\n\taassettings.rs_waterjump\t\t\t\t= LibVarValue(\"rs_waterjump\", \"400\");\n\taassettings.rs_teleport\t\t\t\t\t= LibVarValue(\"rs_teleport\", \"50\");\n\taassettings.rs_barrierjump\t\t\t\t= LibVarValue(\"rs_barrierjump\", \"100\");\n\taassettings.rs_startcrouch\t\t\t\t= LibVarValue(\"rs_startcrouch\", \"300\");\n\taassettings.rs_startgrapple\t\t\t\t= LibVarValue(\"rs_startgrapple\", \"500\");\n\taassettings.rs_startwalkoffledge\t\t= LibVarValue(\"rs_startwalkoffledge\", \"70\");\n\taassettings.rs_startjump\t\t\t\t= LibVarValue(\"rs_startjump\", \"300\");\n\taassettings.rs_rocketjump\t\t\t\t= LibVarValue(\"rs_rocketjump\", \"500\");\n\taassettings.rs_bfgjump\t\t\t\t\t= LibVarValue(\"rs_bfgjump\", \"500\");\n\taassettings.rs_jumppad\t\t\t\t\t= LibVarValue(\"rs_jumppad\", \"250\");\n\taassettings.rs_aircontrolledjumppad\t\t= LibVarValue(\"rs_aircontrolledjumppad\", \"300\");\n\taassettings.rs_funcbob\t\t\t\t\t= LibVarValue(\"rs_funcbob\", \"300\");\n\taassettings.rs_startelevator\t\t\t= LibVarValue(\"rs_startelevator\", \"50\");\n\taassettings.rs_falldamage5\t\t\t\t= LibVarValue(\"rs_falldamage5\", \"300\");\n\taassettings.rs_falldamage10\t\t\t\t= LibVarValue(\"rs_falldamage10\", \"500\");\n\taassettings.rs_maxfallheight\t\t\t= LibVarValue(\"rs_maxfallheight\", \"0\");\n\taassettings.rs_maxjumpfallheight\t\t= LibVarValue(\"rs_maxjumpfallheight\", \"450\");\n} //end of the function AAS_InitSettings\n//===========================================================================\n// returns qtrue if the bot is against a ladder\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_AgainstLadder(vec3_t origin)\n{\n\tint areanum, i, facenum, side;\n\tvec3_t org;\n\taas_plane_t *plane;\n\taas_face_t *face;\n\taas_area_t *area;\n\n\tVectorCopy(origin, org);\n\tareanum = AAS_PointAreaNum(org);\n\tif (!areanum)\n\t{\n\t\torg[0] += 1;\n\t\tareanum = AAS_PointAreaNum(org);\n\t\tif (!areanum)\n\t\t{\n\t\t\torg[1] += 1;\n\t\t\tareanum = AAS_PointAreaNum(org);\n\t\t\tif (!areanum)\n\t\t\t{\n\t\t\t\torg[0] -= 2;\n\t\t\t\tareanum = AAS_PointAreaNum(org);\n\t\t\t\tif (!areanum)\n\t\t\t\t{\n\t\t\t\t\torg[1] -= 2;\n\t\t\t\t\tareanum = AAS_PointAreaNum(org);\n\t\t\t\t} //end if\n\t\t\t} //end if\n\t\t} //end if\n\t} //end if\n\t//if in solid... wrrr shouldn't happen\n\tif (!areanum) return qfalse;\n\t//if not in a ladder area\n\tif (!(aasworld.areasettings[areanum].areaflags & AREA_LADDER)) return qfalse;\n\t//if a crouch only area\n\tif (!(aasworld.areasettings[areanum].presencetype & PRESENCE_NORMAL)) return qfalse;\n\t//\n\tarea = &aasworld.areas[areanum];\n\tfor (i = 0; i < area->numfaces; i++)\n\t{\n\t\tfacenum = aasworld.faceindex[area->firstface + i];\n\t\tside = facenum < 0;\n\t\tface = &aasworld.faces[abs(facenum)];\n\t\t//if the face isn't a ladder face\n\t\tif (!(face->faceflags & FACE_LADDER)) continue;\n\t\t//get the plane the face is in\n\t\tplane = &aasworld.planes[face->planenum ^ side];\n\t\t//if the origin is pretty close to the plane\n\t\tif (fabs(DotProduct(plane->normal, origin) - plane->dist) < 3)\n\t\t{\n\t\t\tif (AAS_PointInsideFace(abs(facenum), origin, 0.1f)) return qtrue;\n\t\t} //end if\n\t} //end for\n\treturn qfalse;\n} //end of the function AAS_AgainstLadder\n//===========================================================================\n// returns qtrue if the bot is on the ground\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_OnGround(vec3_t origin, int presencetype, int passent)\n{\n\taas_trace_t trace;\n\tvec3_t end, up = {0, 0, 1};\n\taas_plane_t *plane;\n\n\tVectorCopy(origin, end);\n\tend[2] -= 10;\n\n\ttrace = AAS_TraceClientBBox(origin, end, presencetype, passent);\n\n\t//if in solid\n\tif (trace.startsolid) return qfalse;\n\t//if nothing hit at all\n\tif (trace.fraction >= 1.0) return qfalse;\n\t//if too far from the hit plane\n\tif (origin[2] - trace.endpos[2] > 10) return qfalse;\n\t//check if the plane isn't too steep\n\tplane = AAS_PlaneFromNum(trace.planenum);\n\tif (DotProduct(plane->normal, up) < aassettings.phys_maxsteepness) return qfalse;\n\t//the bot is on the ground\n\treturn qtrue;\n} //end of the function AAS_OnGround\n//===========================================================================\n// returns qtrue if a bot at the given position is swimming\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_Swimming(vec3_t origin)\n{\n\tvec3_t testorg;\n\n\tVectorCopy(origin, testorg);\n\ttestorg[2] -= 2;\n\tif (AAS_PointContents(testorg) & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER)) return qtrue;\n\treturn qfalse;\n} //end of the function AAS_Swimming\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nstatic vec3_t VEC_UP\t\t\t= {0, -1,  0};\nstatic vec3_t MOVEDIR_UP\t\t= {0,  0,  1};\nstatic vec3_t VEC_DOWN\t\t= {0, -2,  0};\nstatic vec3_t MOVEDIR_DOWN\t= {0,  0, -1};\n\nvoid AAS_SetMovedir(vec3_t angles, vec3_t movedir)\n{\n\tif (VectorCompare(angles, VEC_UP))\n\t{\n\t\tVectorCopy(MOVEDIR_UP, movedir);\n\t} //end if\n\telse if (VectorCompare(angles, VEC_DOWN))\n\t{\n\t\tVectorCopy(MOVEDIR_DOWN, movedir);\n\t} //end else if\n\telse\n\t{\n\t\tAngleVectors(angles, movedir, NULL, NULL);\n\t} //end else\n} //end of the function AAS_SetMovedir\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_JumpReachRunStart(aas_reachability_t *reach, vec3_t runstart)\n{\n\tvec3_t hordir, start, cmdmove;\n\taas_clientmove_t move;\n\n\t//\n\thordir[0] = reach->start[0] - reach->end[0];\n\thordir[1] = reach->start[1] - reach->end[1];\n\thordir[2] = 0;\n\tVectorNormalize(hordir);\n\t//start point\n\tVectorCopy(reach->start, start);\n\tstart[2] += 1;\n\t//get command movement\n\tVectorScale(hordir, 400, cmdmove);\n\t//\n\tAAS_PredictClientMovement(&move, -1, start, PRESENCE_NORMAL, qtrue,\n\t\t\t\t\t\t\t\tvec3_origin, cmdmove, 1, 2, 0.1f,\n\t\t\t\t\t\t\t\tSE_ENTERWATER|SE_ENTERSLIME|SE_ENTERLAVA|\n\t\t\t\t\t\t\t\tSE_HITGROUNDDAMAGE|SE_GAP, 0, qfalse);\n\tVectorCopy(move.endpos, runstart);\n\t//don't enter slime or lava and don't fall from too high\n\tif (move.stopevent & (SE_ENTERSLIME|SE_ENTERLAVA|SE_HITGROUNDDAMAGE))\n\t{\n\t\tVectorCopy(start, runstart);\n\t} //end if\n} //end of the function AAS_JumpReachRunStart\n//===========================================================================\n// returns the Z velocity when rocket jumping at the origin\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nfloat AAS_WeaponJumpZVelocity(vec3_t origin, float radiusdamage)\n{\n\tvec3_t kvel, v, start, end, forward, right, viewangles, dir;\n\tfloat\tmass, knockback, points;\n\tvec3_t rocketoffset = {8, 8, -8};\n\tvec3_t botmins = {-16, -16, -24};\n\tvec3_t botmaxs = {16, 16, 32};\n\tbsp_trace_t bsptrace;\n\n\t//look down (90 degrees)\n\tviewangles[PITCH] = 90;\n\tviewangles[YAW] = 0;\n\tviewangles[ROLL] = 0;\n\t//get the start point shooting from\n\tVectorCopy(origin, start);\n\tstart[2] += 8; //view offset Z\n\tAngleVectors(viewangles, forward, right, NULL);\n\tstart[0] += forward[0] * rocketoffset[0] + right[0] * rocketoffset[1];\n\tstart[1] += forward[1] * rocketoffset[0] + right[1] * rocketoffset[1];\n\tstart[2] += forward[2] * rocketoffset[0] + right[2] * rocketoffset[1] + rocketoffset[2];\n\t//end point of the trace\n\tVectorMA(start, 500, forward, end);\n\t//trace a line to get the impact point\n\tbsptrace = AAS_Trace(start, NULL, NULL, end, 1, CONTENTS_SOLID);\n\t//calculate the damage the bot will get from the rocket impact\n\tVectorAdd(botmins, botmaxs, v);\n\tVectorMA(origin, 0.5, v, v);\n\tVectorSubtract(bsptrace.endpos, v, v);\n\t//\n\tpoints = radiusdamage - 0.5 * VectorLength(v);\n\tif (points < 0) points = 0;\n\t//the owner of the rocket gets half the damage\n\tpoints *= 0.5;\n\t//mass of the bot (p_client.c: PutClientInServer)\n\tmass = 200;\n\t//knockback is the same as the damage points\n\tknockback = points;\n\t//direction of the damage (from trace.endpos to bot origin)\n\tVectorSubtract(origin, bsptrace.endpos, dir);\n\tVectorNormalize(dir);\n\t//damage velocity\n\tVectorScale(dir, 1600.0 * (float)knockback / mass, kvel);\t//the rocket jump hack...\n\t//rocket impact velocity + jump velocity\n\treturn kvel[2] + aassettings.phys_jumpvel;\n} //end of the function AAS_WeaponJumpZVelocity\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nfloat AAS_RocketJumpZVelocity(vec3_t origin)\n{\n\t//rocket radius damage is 120 (p_weapon.c: Weapon_RocketLauncher_Fire)\n\treturn AAS_WeaponJumpZVelocity(origin, 120);\n} //end of the function AAS_RocketJumpZVelocity\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nfloat AAS_BFGJumpZVelocity(vec3_t origin)\n{\n\t//bfg radius damage is 1000 (p_weapon.c: weapon_bfg_fire)\n\treturn AAS_WeaponJumpZVelocity(origin, 120);\n} //end of the function AAS_BFGJumpZVelocity\n//===========================================================================\n// applies ground friction to the given velocity\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_Accelerate(vec3_t velocity, float frametime, vec3_t wishdir, float wishspeed, float accel)\n{\n\t// q2 style\n\tint\t\t\ti;\n\tfloat\t\taddspeed, accelspeed, currentspeed;\n\n\tcurrentspeed = DotProduct(velocity, wishdir);\n\taddspeed = wishspeed - currentspeed;\n\tif (addspeed <= 0) {\n\t\treturn;\n\t}\n\taccelspeed = accel*frametime*wishspeed;\n\tif (accelspeed > addspeed) {\n\t\taccelspeed = addspeed;\n\t}\n\t\n\tfor (i=0 ; i<3 ; i++) {\n\t\tvelocity[i] += accelspeed*wishdir[i];\t\n\t}\n} //end of the function AAS_Accelerate\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_AirControl(vec3_t start, vec3_t end, vec3_t velocity, vec3_t cmdmove)\n{\n\tvec3_t dir;\n\n\tVectorSubtract(end, start, dir);\n} //end of the function AAS_AirControl\n//===========================================================================\n// applies ground friction to the given velocity\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_ApplyFriction(vec3_t vel, float friction, float stopspeed,\n\t\t\t\t\t\t\t\t\t\t\t\t\tfloat frametime)\n{\n\tfloat speed, control, newspeed;\n\n\t//horizontal speed\n\tspeed = sqrt(vel[0] * vel[0] + vel[1] * vel[1]);\n\tif (speed)\n\t{\n\t\tcontrol = speed < stopspeed ? stopspeed : speed;\n\t\tnewspeed = speed - frametime * control * friction;\n\t\tif (newspeed < 0) newspeed = 0;\n\t\tnewspeed /= speed;\n\t\tvel[0] *= newspeed;\n\t\tvel[1] *= newspeed;\n\t} //end if\n} //end of the function AAS_ApplyFriction\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_ClipToBBox(aas_trace_t *trace, vec3_t start, vec3_t end, int presencetype, vec3_t mins, vec3_t maxs)\n{\n\tint i, j, side;\n\tfloat front, back, frac, planedist;\n\tvec3_t bboxmins, bboxmaxs, absmins, absmaxs, dir, mid;\n\n\tAAS_PresenceTypeBoundingBox(presencetype, bboxmins, bboxmaxs);\n\tVectorSubtract(mins, bboxmaxs, absmins);\n\tVectorSubtract(maxs, bboxmins, absmaxs);\n\t//\n\tVectorCopy(end, trace->endpos);\n\ttrace->fraction = 1;\n\tfor (i = 0; i < 3; i++)\n\t{\n\t\tif (start[i] < absmins[i] && end[i] < absmins[i]) return qfalse;\n\t\tif (start[i] > absmaxs[i] && end[i] > absmaxs[i]) return qfalse;\n\t} //end for\n\t//check bounding box collision\n\tVectorSubtract(end, start, dir);\n\tfrac = 1;\n\tfor (i = 0; i < 3; i++)\n\t{\n\t\t//get plane to test collision with for the current axis direction\n\t\tif (dir[i] > 0) planedist = absmins[i];\n\t\telse planedist = absmaxs[i];\n\t\t//calculate collision fraction\n\t\tfront = start[i] - planedist;\n\t\tback = end[i] - planedist;\n\t\tfrac = front / (front-back);\n\t\t//check if between bounding planes of next axis\n\t\tside = i + 1;\n\t\tif (side > 2) side = 0;\n\t\tmid[side] = start[side] + dir[side] * frac;\n\t\tif (mid[side] > absmins[side] && mid[side] < absmaxs[side])\n\t\t{\n\t\t\t//check if between bounding planes of next axis\n\t\t\tside++;\n\t\t\tif (side > 2) side = 0;\n\t\t\tmid[side] = start[side] + dir[side] * frac;\n\t\t\tif (mid[side] > absmins[side] && mid[side] < absmaxs[side])\n\t\t\t{\n\t\t\t\tmid[i] = planedist;\n\t\t\t\tbreak;\n\t\t\t} //end if\n\t\t} //end if\n\t} //end for\n\t//if there was a collision\n\tif (i != 3)\n\t{\n\t\ttrace->startsolid = qfalse;\n\t\ttrace->fraction = frac;\n\t\ttrace->ent = 0;\n\t\ttrace->planenum = 0;\n\t\ttrace->area = 0;\n\t\ttrace->lastarea = 0;\n\t\t//trace endpos\n\t\tfor (j = 0; j < 3; j++) trace->endpos[j] = start[j] + dir[j] * frac;\n\t\treturn qtrue;\n\t} //end if\n\treturn qfalse;\n} //end of the function AAS_ClipToBBox\n//===========================================================================\n// predicts the movement\n// assumes regular bounding box sizes\n// NOTE: out of water jumping is not included\n// NOTE: grappling hook is not included\n//\n// Parameter:\t\t\torigin\t\t\t: origin to start with\n//\t\t\t\t\t\tpresencetype\t: presence type to start with\n//\t\t\t\t\t\tvelocity\t\t: velocity to start with\n//\t\t\t\t\t\tcmdmove\t\t\t: client command movement\n//\t\t\t\t\t\tcmdframes\t\t: number of frame cmdmove is valid\n//\t\t\t\t\t\tmaxframes\t\t: maximum number of predicted frames\n//\t\t\t\t\t\tframetime\t\t: duration of one predicted frame\n//\t\t\t\t\t\tstopevent\t\t: events that stop the prediction\n//\t\t\t\t\t\tstopareanum\t\t: stop as soon as entered this area\n// Returns:\t\t\t\taas_clientmove_t\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_ClientMovementPrediction(struct aas_clientmove_s *move,\n\t\t\t\t\t\t\t\tint entnum, vec3_t origin,\n\t\t\t\t\t\t\t\tint presencetype, int onground,\n\t\t\t\t\t\t\t\tvec3_t velocity, vec3_t cmdmove,\n\t\t\t\t\t\t\t\tint cmdframes,\n\t\t\t\t\t\t\t\tint maxframes, float frametime,\n\t\t\t\t\t\t\t\tint stopevent, int stopareanum,\n\t\t\t\t\t\t\t\tvec3_t mins, vec3_t maxs, int visualize)\n{\n\tfloat phys_friction, phys_stopspeed, phys_gravity, phys_waterfriction;\n\tfloat phys_watergravity;\n\tfloat phys_walkaccelerate, phys_airaccelerate, phys_swimaccelerate;\n\tfloat phys_maxwalkvelocity, phys_maxcrouchvelocity, phys_maxswimvelocity;\n\tfloat phys_maxstep, phys_maxsteepness, phys_jumpvel, friction;\n\tfloat gravity, delta, maxvel, wishspeed, accelerate;\n\t//float velchange, newvel;\n\tint n, i, j, pc, step, swimming, ax, crouch, event, jump_frame, areanum;\n\tint areas[20], numareas;\n\tvec3_t points[20];\n\tvec3_t org, end, feet, start, stepend, lastorg, wishdir;\n\tvec3_t frame_test_vel, old_frame_test_vel, left_test_vel;\n\tvec3_t up = {0, 0, 1};\n\taas_plane_t *plane, *plane2;\n\taas_trace_t trace, steptrace;\n\t\n\tif (frametime <= 0) frametime = 0.1f;\n\t//\n\tphys_friction = aassettings.phys_friction;\n\tphys_stopspeed = aassettings.phys_stopspeed;\n\tphys_gravity = aassettings.phys_gravity;\n\tphys_waterfriction = aassettings.phys_waterfriction;\n\tphys_watergravity = aassettings.phys_watergravity;\n\tphys_maxwalkvelocity = aassettings.phys_maxwalkvelocity;// * frametime;\n\tphys_maxcrouchvelocity = aassettings.phys_maxcrouchvelocity;// * frametime;\n\tphys_maxswimvelocity = aassettings.phys_maxswimvelocity;// * frametime;\n\tphys_walkaccelerate = aassettings.phys_walkaccelerate;\n\tphys_airaccelerate = aassettings.phys_airaccelerate;\n\tphys_swimaccelerate = aassettings.phys_swimaccelerate;\n\tphys_maxstep = aassettings.phys_maxstep;\n\tphys_maxsteepness = aassettings.phys_maxsteepness;\n\tphys_jumpvel = aassettings.phys_jumpvel * frametime;\n\t//\n\tCom_Memset(move, 0, sizeof(aas_clientmove_t));\n\tCom_Memset(&trace, 0, sizeof(aas_trace_t));\n\t//start at the current origin\n\tVectorCopy(origin, org);\n\torg[2] += 0.25;\n\t//velocity to test for the first frame\n\tVectorScale(velocity, frametime, frame_test_vel);\n\t//\n\tjump_frame = -1;\n\t//predict a maximum of 'maxframes' ahead\n\tfor (n = 0; n < maxframes; n++)\n\t{\n\t\tswimming = AAS_Swimming(org);\n\t\t//get gravity depending on swimming or not\n\t\tgravity = swimming ? phys_watergravity : phys_gravity;\n\t\t//apply gravity at the START of the frame\n\t\tframe_test_vel[2] = frame_test_vel[2] - (gravity * 0.1 * frametime);\n\t\t//if on the ground or swimming\n\t\tif (onground || swimming)\n\t\t{\n\t\t\tfriction = swimming ? phys_friction : phys_waterfriction;\n\t\t\t//apply friction\n\t\t\tVectorScale(frame_test_vel, 1/frametime, frame_test_vel);\n\t\t\tAAS_ApplyFriction(frame_test_vel, friction, phys_stopspeed, frametime);\n\t\t\tVectorScale(frame_test_vel, frametime, frame_test_vel);\n\t\t} //end if\n\t\tcrouch = qfalse;\n\t\t//apply command movement\n\t\tif (n < cmdframes)\n\t\t{\n\t\t\tax = 0;\n\t\t\tmaxvel = phys_maxwalkvelocity;\n\t\t\taccelerate = phys_airaccelerate;\n\t\t\tVectorCopy(cmdmove, wishdir);\n\t\t\tif (onground)\n\t\t\t{\n\t\t\t\tif (cmdmove[2] < -300)\n\t\t\t\t{\n\t\t\t\t\tcrouch = qtrue;\n\t\t\t\t\tmaxvel = phys_maxcrouchvelocity;\n\t\t\t\t} //end if\n\t\t\t\t//if not swimming and upmove is positive then jump\n\t\t\t\tif (!swimming && cmdmove[2] > 1)\n\t\t\t\t{\n\t\t\t\t\t//jump velocity minus the gravity for one frame + 5 for safety\n\t\t\t\t\tframe_test_vel[2] = phys_jumpvel - (gravity * 0.1 * frametime) + 5;\n\t\t\t\t\tjump_frame = n;\n\t\t\t\t\t//jumping so air accelerate\n\t\t\t\t\taccelerate = phys_airaccelerate;\n\t\t\t\t} //end if\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\taccelerate = phys_walkaccelerate;\n\t\t\t\t} //end else\n\t\t\t\tax = 2;\n\t\t\t} //end if\n\t\t\tif (swimming)\n\t\t\t{\n\t\t\t\tmaxvel = phys_maxswimvelocity;\n\t\t\t\taccelerate = phys_swimaccelerate;\n\t\t\t\tax = 3;\n\t\t\t} //end if\n\t\t\telse\n\t\t\t{\n\t\t\t\twishdir[2] = 0;\n\t\t\t} //end else\n\t\t\t//\n\t\t\twishspeed = VectorNormalize(wishdir);\n\t\t\tif (wishspeed > maxvel) wishspeed = maxvel;\n\t\t\tVectorScale(frame_test_vel, 1/frametime, frame_test_vel);\n\t\t\tAAS_Accelerate(frame_test_vel, frametime, wishdir, wishspeed, accelerate);\n\t\t\tVectorScale(frame_test_vel, frametime, frame_test_vel);\n\t\t\t/*\n\t\t\tfor (i = 0; i < ax; i++)\n\t\t\t{\n\t\t\t\tvelchange = (cmdmove[i] * frametime) - frame_test_vel[i];\n\t\t\t\tif (velchange > phys_maxacceleration) velchange = phys_maxacceleration;\n\t\t\t\telse if (velchange < -phys_maxacceleration) velchange = -phys_maxacceleration;\n\t\t\t\tnewvel = frame_test_vel[i] + velchange;\n\t\t\t\t//\n\t\t\t\tif (frame_test_vel[i] <= maxvel && newvel > maxvel) frame_test_vel[i] = maxvel;\n\t\t\t\telse if (frame_test_vel[i] >= -maxvel && newvel < -maxvel) frame_test_vel[i] = -maxvel;\n\t\t\t\telse frame_test_vel[i] = newvel;\n\t\t\t} //end for\n\t\t\t*/\n\t\t} //end if\n\t\tif (crouch)\n\t\t{\n\t\t\tpresencetype = PRESENCE_CROUCH;\n\t\t} //end if\n\t\telse if (presencetype == PRESENCE_CROUCH)\n\t\t{\n\t\t\tif (AAS_PointPresenceType(org) & PRESENCE_NORMAL)\n\t\t\t{\n\t\t\t\tpresencetype = PRESENCE_NORMAL;\n\t\t\t} //end if\n\t\t} //end else\n\t\t//save the current origin\n\t\tVectorCopy(org, lastorg);\n\t\t//move linear during one frame\n\t\tVectorCopy(frame_test_vel, left_test_vel);\n\t\tj = 0;\n\t\tdo\n\t\t{\n\t\t\tVectorAdd(org, left_test_vel, end);\n\t\t\t//trace a bounding box\n\t\t\ttrace = AAS_TraceClientBBox(org, end, presencetype, entnum);\n\t\t\t//\n//#ifdef AAS_MOVE_DEBUG\n\t\t\tif (visualize)\n\t\t\t{\n\t\t\t\tif (trace.startsolid) botimport.Print(PRT_MESSAGE, \"PredictMovement: start solid\\n\");\n\t\t\t\tAAS_DebugLine(org, trace.endpos, LINECOLOR_RED);\n\t\t\t} //end if\n//#endif //AAS_MOVE_DEBUG\n\t\t\t//\n\t\t\tif (stopevent & (SE_ENTERAREA|SE_TOUCHJUMPPAD|SE_TOUCHTELEPORTER|SE_TOUCHCLUSTERPORTAL))\n\t\t\t{\n\t\t\t\tnumareas = AAS_TraceAreas(org, trace.endpos, areas, points, 20);\n\t\t\t\tfor (i = 0; i < numareas; i++)\n\t\t\t\t{\n\t\t\t\t\tif (stopevent & SE_ENTERAREA)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (areas[i] == stopareanum)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tVectorCopy(points[i], move->endpos);\n\t\t\t\t\t\t\tVectorScale(frame_test_vel, 1/frametime, move->velocity);\n\t\t\t\t\t\t\tmove->endarea = areas[i];\n\t\t\t\t\t\t\tmove->trace = trace;\n\t\t\t\t\t\t\tmove->stopevent = SE_ENTERAREA;\n\t\t\t\t\t\t\tmove->presencetype = presencetype;\n\t\t\t\t\t\t\tmove->endcontents = 0;\n\t\t\t\t\t\t\tmove->time = n * frametime;\n\t\t\t\t\t\t\tmove->frames = n;\n\t\t\t\t\t\t\treturn qtrue;\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t} //end if\n\t\t\t\t\t//NOTE: if not the first frame\n\t\t\t\t\tif ((stopevent & SE_TOUCHJUMPPAD) && n)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (aasworld.areasettings[areas[i]].contents & AREACONTENTS_JUMPPAD)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tVectorCopy(points[i], move->endpos);\n\t\t\t\t\t\t\tVectorScale(frame_test_vel, 1/frametime, move->velocity);\n\t\t\t\t\t\t\tmove->endarea = areas[i];\n\t\t\t\t\t\t\tmove->trace = trace;\n\t\t\t\t\t\t\tmove->stopevent = SE_TOUCHJUMPPAD;\n\t\t\t\t\t\t\tmove->presencetype = presencetype;\n\t\t\t\t\t\t\tmove->endcontents = 0;\n\t\t\t\t\t\t\tmove->time = n * frametime;\n\t\t\t\t\t\t\tmove->frames = n;\n\t\t\t\t\t\t\treturn qtrue;\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t} //end if\n\t\t\t\t\tif (stopevent & SE_TOUCHTELEPORTER)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (aasworld.areasettings[areas[i]].contents & AREACONTENTS_TELEPORTER)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tVectorCopy(points[i], move->endpos);\n\t\t\t\t\t\t\tmove->endarea = areas[i];\n\t\t\t\t\t\t\tVectorScale(frame_test_vel, 1/frametime, move->velocity);\n\t\t\t\t\t\t\tmove->trace = trace;\n\t\t\t\t\t\t\tmove->stopevent = SE_TOUCHTELEPORTER;\n\t\t\t\t\t\t\tmove->presencetype = presencetype;\n\t\t\t\t\t\t\tmove->endcontents = 0;\n\t\t\t\t\t\t\tmove->time = n * frametime;\n\t\t\t\t\t\t\tmove->frames = n;\n\t\t\t\t\t\t\treturn qtrue;\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t} //end if\n\t\t\t\t\tif (stopevent & SE_TOUCHCLUSTERPORTAL)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (aasworld.areasettings[areas[i]].contents & AREACONTENTS_CLUSTERPORTAL)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tVectorCopy(points[i], move->endpos);\n\t\t\t\t\t\t\tmove->endarea = areas[i];\n\t\t\t\t\t\t\tVectorScale(frame_test_vel, 1/frametime, move->velocity);\n\t\t\t\t\t\t\tmove->trace = trace;\n\t\t\t\t\t\t\tmove->stopevent = SE_TOUCHCLUSTERPORTAL;\n\t\t\t\t\t\t\tmove->presencetype = presencetype;\n\t\t\t\t\t\t\tmove->endcontents = 0;\n\t\t\t\t\t\t\tmove->time = n * frametime;\n\t\t\t\t\t\t\tmove->frames = n;\n\t\t\t\t\t\t\treturn qtrue;\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t} //end if\n\t\t\t\t} //end for\n\t\t\t} //end if\n\t\t\t//\n\t\t\tif (stopevent & SE_HITBOUNDINGBOX)\n\t\t\t{\n\t\t\t\tif (AAS_ClipToBBox(&trace, org, trace.endpos, presencetype, mins, maxs))\n\t\t\t\t{\n\t\t\t\t\tVectorCopy(trace.endpos, move->endpos);\n\t\t\t\t\tmove->endarea = AAS_PointAreaNum(move->endpos);\n\t\t\t\t\tVectorScale(frame_test_vel, 1/frametime, move->velocity);\n\t\t\t\t\tmove->trace = trace;\n\t\t\t\t\tmove->stopevent = SE_HITBOUNDINGBOX;\n\t\t\t\t\tmove->presencetype = presencetype;\n\t\t\t\t\tmove->endcontents = 0;\n\t\t\t\t\tmove->time = n * frametime;\n\t\t\t\t\tmove->frames = n;\n\t\t\t\t\treturn qtrue;\n\t\t\t\t} //end if\n\t\t\t} //end if\n\t\t\t//move the entity to the trace end point\n\t\t\tVectorCopy(trace.endpos, org);\n\t\t\t//if there was a collision\n\t\t\tif (trace.fraction < 1.0)\n\t\t\t{\n\t\t\t\t//get the plane the bounding box collided with\n\t\t\t\tplane = AAS_PlaneFromNum(trace.planenum);\n\t\t\t\t//\n\t\t\t\tif (stopevent & SE_HITGROUNDAREA)\n\t\t\t\t{\n\t\t\t\t\tif (DotProduct(plane->normal, up) > phys_maxsteepness)\n\t\t\t\t\t{\n\t\t\t\t\t\tVectorCopy(org, start);\n\t\t\t\t\t\tstart[2] += 0.5;\n\t\t\t\t\t\tif (AAS_PointAreaNum(start) == stopareanum)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tVectorCopy(start, move->endpos);\n\t\t\t\t\t\t\tmove->endarea = stopareanum;\n\t\t\t\t\t\t\tVectorScale(frame_test_vel, 1/frametime, move->velocity);\n\t\t\t\t\t\t\tmove->trace = trace;\n\t\t\t\t\t\t\tmove->stopevent = SE_HITGROUNDAREA;\n\t\t\t\t\t\t\tmove->presencetype = presencetype;\n\t\t\t\t\t\t\tmove->endcontents = 0;\n\t\t\t\t\t\t\tmove->time = n * frametime;\n\t\t\t\t\t\t\tmove->frames = n;\n\t\t\t\t\t\t\treturn qtrue;\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t} //end if\n\t\t\t\t} //end if\n\t\t\t\t//assume there's no step\n\t\t\t\tstep = qfalse;\n\t\t\t\t//if it is a vertical plane and the bot didn't jump recently\n\t\t\t\tif (plane->normal[2] == 0 && (jump_frame < 0 || n - jump_frame > 2))\n\t\t\t\t{\n\t\t\t\t\t//check for a step\n\t\t\t\t\tVectorMA(org, -0.25, plane->normal, start);\n\t\t\t\t\tVectorCopy(start, stepend);\n\t\t\t\t\tstart[2] += phys_maxstep;\n\t\t\t\t\tsteptrace = AAS_TraceClientBBox(start, stepend, presencetype, entnum);\n\t\t\t\t\t//\n\t\t\t\t\tif (!steptrace.startsolid)\n\t\t\t\t\t{\n\t\t\t\t\t\tplane2 = AAS_PlaneFromNum(steptrace.planenum);\n\t\t\t\t\t\tif (DotProduct(plane2->normal, up) > phys_maxsteepness)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tVectorSubtract(end, steptrace.endpos, left_test_vel);\n\t\t\t\t\t\t\tleft_test_vel[2] = 0;\n\t\t\t\t\t\t\tframe_test_vel[2] = 0;\n//#ifdef AAS_MOVE_DEBUG\n\t\t\t\t\t\t\tif (visualize)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (steptrace.endpos[2] - org[2] > 0.125)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tVectorCopy(org, start);\n\t\t\t\t\t\t\t\t\tstart[2] = steptrace.endpos[2];\n\t\t\t\t\t\t\t\t\tAAS_DebugLine(org, start, LINECOLOR_BLUE);\n\t\t\t\t\t\t\t\t} //end if\n\t\t\t\t\t\t\t} //end if\n//#endif //AAS_MOVE_DEBUG\n\t\t\t\t\t\t\torg[2] = steptrace.endpos[2];\n\t\t\t\t\t\t\tstep = qtrue;\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t} //end if\n\t\t\t\t} //end if\n\t\t\t\t//\n\t\t\t\tif (!step)\n\t\t\t\t{\n\t\t\t\t\t//velocity left to test for this frame is the projection\n\t\t\t\t\t//of the current test velocity into the hit plane \n\t\t\t\t\tVectorMA(left_test_vel, -DotProduct(left_test_vel, plane->normal),\n\t\t\t\t\t\t\t\t\t\tplane->normal, left_test_vel);\n\t\t\t\t\t//store the old velocity for landing check\n\t\t\t\t\tVectorCopy(frame_test_vel, old_frame_test_vel);\n\t\t\t\t\t//test velocity for the next frame is the projection\n\t\t\t\t\t//of the velocity of the current frame into the hit plane \n\t\t\t\t\tVectorMA(frame_test_vel, -DotProduct(frame_test_vel, plane->normal),\n\t\t\t\t\t\t\t\t\t\tplane->normal, frame_test_vel);\n\t\t\t\t\t//check for a landing on an almost horizontal floor\n\t\t\t\t\tif (DotProduct(plane->normal, up) > phys_maxsteepness)\n\t\t\t\t\t{\n\t\t\t\t\t\tonground = qtrue;\n\t\t\t\t\t} //end if\n\t\t\t\t\tif (stopevent & SE_HITGROUNDDAMAGE)\n\t\t\t\t\t{\n\t\t\t\t\t\tdelta = 0;\n\t\t\t\t\t\tif (old_frame_test_vel[2] < 0 &&\n\t\t\t\t\t\t\t\tframe_test_vel[2] > old_frame_test_vel[2] &&\n\t\t\t\t\t\t\t\t!onground)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdelta = old_frame_test_vel[2];\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t\telse if (onground)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdelta = frame_test_vel[2] - old_frame_test_vel[2];\n\t\t\t\t\t\t} //end else\n\t\t\t\t\t\tif (delta)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdelta = delta * 10;\n\t\t\t\t\t\t\tdelta = delta * delta * 0.0001;\n\t\t\t\t\t\t\tif (swimming) delta = 0;\n\t\t\t\t\t\t\t// never take falling damage if completely underwater\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tif (ent->waterlevel == 3) return;\n\t\t\t\t\t\t\tif (ent->waterlevel == 2) delta *= 0.25;\n\t\t\t\t\t\t\tif (ent->waterlevel == 1) delta *= 0.5;\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\tif (delta > 40)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tVectorCopy(org, move->endpos);\n\t\t\t\t\t\t\t\tmove->endarea = AAS_PointAreaNum(org);\n\t\t\t\t\t\t\t\tVectorCopy(frame_test_vel, move->velocity);\n\t\t\t\t\t\t\t\tmove->trace = trace;\n\t\t\t\t\t\t\t\tmove->stopevent = SE_HITGROUNDDAMAGE;\n\t\t\t\t\t\t\t\tmove->presencetype = presencetype;\n\t\t\t\t\t\t\t\tmove->endcontents = 0;\n\t\t\t\t\t\t\t\tmove->time = n * frametime;\n\t\t\t\t\t\t\t\tmove->frames = n;\n\t\t\t\t\t\t\t\treturn qtrue;\n\t\t\t\t\t\t\t} //end if\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t} //end if\n\t\t\t\t} //end if\n\t\t\t} //end if\n\t\t\t//extra check to prevent endless loop\n\t\t\tif (++j > 20) return qfalse;\n\t\t//while there is a plane hit\n\t\t} while(trace.fraction < 1.0);\n\t\t//if going down\n\t\tif (frame_test_vel[2] <= 10)\n\t\t{\n\t\t\t//check for a liquid at the feet of the bot\n\t\t\tVectorCopy(org, feet);\n\t\t\tfeet[2] -= 22;\n\t\t\tpc = AAS_PointContents(feet);\n\t\t\t//get event from pc\n\t\t\tevent = SE_NONE;\n\t\t\tif (pc & CONTENTS_LAVA) event |= SE_ENTERLAVA;\n\t\t\tif (pc & CONTENTS_SLIME) event |= SE_ENTERSLIME;\n\t\t\tif (pc & CONTENTS_WATER) event |= SE_ENTERWATER;\n\t\t\t//\n\t\t\tareanum = AAS_PointAreaNum(org);\n\t\t\tif (aasworld.areasettings[areanum].contents & AREACONTENTS_LAVA)\n\t\t\t\tevent |= SE_ENTERLAVA;\n\t\t\tif (aasworld.areasettings[areanum].contents & AREACONTENTS_SLIME)\n\t\t\t\tevent |= SE_ENTERSLIME;\n\t\t\tif (aasworld.areasettings[areanum].contents & AREACONTENTS_WATER)\n\t\t\t\tevent |= SE_ENTERWATER;\n\t\t\t//if in lava or slime\n\t\t\tif (event & stopevent)\n\t\t\t{\n\t\t\t\tVectorCopy(org, move->endpos);\n\t\t\t\tmove->endarea = areanum;\n\t\t\t\tVectorScale(frame_test_vel, 1/frametime, move->velocity);\n\t\t\t\tmove->stopevent = event & stopevent;\n\t\t\t\tmove->presencetype = presencetype;\n\t\t\t\tmove->endcontents = pc;\n\t\t\t\tmove->time = n * frametime;\n\t\t\t\tmove->frames = n;\n\t\t\t\treturn qtrue;\n\t\t\t} //end if\n\t\t} //end if\n\t\t//\n\t\tonground = AAS_OnGround(org, presencetype, entnum);\n\t\t//if onground and on the ground for at least one whole frame\n\t\tif (onground)\n\t\t{\n\t\t\tif (stopevent & SE_HITGROUND)\n\t\t\t{\n\t\t\t\tVectorCopy(org, move->endpos);\n\t\t\t\tmove->endarea = AAS_PointAreaNum(org);\n\t\t\t\tVectorScale(frame_test_vel, 1/frametime, move->velocity);\n\t\t\t\tmove->trace = trace;\n\t\t\t\tmove->stopevent = SE_HITGROUND;\n\t\t\t\tmove->presencetype = presencetype;\n\t\t\t\tmove->endcontents = 0;\n\t\t\t\tmove->time = n * frametime;\n\t\t\t\tmove->frames = n;\n\t\t\t\treturn qtrue;\n\t\t\t} //end if\n\t\t} //end if\n\t\telse if (stopevent & SE_LEAVEGROUND)\n\t\t{\n\t\t\tVectorCopy(org, move->endpos);\n\t\t\tmove->endarea = AAS_PointAreaNum(org);\n\t\t\tVectorScale(frame_test_vel, 1/frametime, move->velocity);\n\t\t\tmove->trace = trace;\n\t\t\tmove->stopevent = SE_LEAVEGROUND;\n\t\t\tmove->presencetype = presencetype;\n\t\t\tmove->endcontents = 0;\n\t\t\tmove->time = n * frametime;\n\t\t\tmove->frames = n;\n\t\t\treturn qtrue;\n\t\t} //end else if\n\t\telse if (stopevent & SE_GAP)\n\t\t{\n\t\t\taas_trace_t gaptrace;\n\n\t\t\tVectorCopy(org, start);\n\t\t\tVectorCopy(start, end);\n\t\t\tend[2] -= 48 + aassettings.phys_maxbarrier;\n\t\t\tgaptrace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, -1);\n\t\t\t//if solid is found the bot cannot walk any further and will not fall into a gap\n\t\t\tif (!gaptrace.startsolid)\n\t\t\t{\n\t\t\t\t//if it is a gap (lower than one step height)\n\t\t\t\tif (gaptrace.endpos[2] < org[2] - aassettings.phys_maxstep - 1)\n\t\t\t\t{\n\t\t\t\t\tif (!(AAS_PointContents(end) & CONTENTS_WATER))\n\t\t\t\t\t{\n\t\t\t\t\t\tVectorCopy(lastorg, move->endpos);\n\t\t\t\t\t\tmove->endarea = AAS_PointAreaNum(lastorg);\n\t\t\t\t\t\tVectorScale(frame_test_vel, 1/frametime, move->velocity);\n\t\t\t\t\t\tmove->trace = trace;\n\t\t\t\t\t\tmove->stopevent = SE_GAP;\n\t\t\t\t\t\tmove->presencetype = presencetype;\n\t\t\t\t\t\tmove->endcontents = 0;\n\t\t\t\t\t\tmove->time = n * frametime;\n\t\t\t\t\t\tmove->frames = n;\n\t\t\t\t\t\treturn qtrue;\n\t\t\t\t\t} //end if\n\t\t\t\t} //end if\n\t\t\t} //end if\n\t\t} //end else if\n\t} //end for\n\t//\n\tVectorCopy(org, move->endpos);\n\tmove->endarea = AAS_PointAreaNum(org);\n\tVectorScale(frame_test_vel, 1/frametime, move->velocity);\n\tmove->stopevent = SE_NONE;\n\tmove->presencetype = presencetype;\n\tmove->endcontents = 0;\n\tmove->time = n * frametime;\n\tmove->frames = n;\n\t//\n\treturn qtrue;\n} //end of the function AAS_ClientMovementPrediction\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_PredictClientMovement(struct aas_clientmove_s *move,\n\t\t\t\t\t\t\t\tint entnum, vec3_t origin,\n\t\t\t\t\t\t\t\tint presencetype, int onground,\n\t\t\t\t\t\t\t\tvec3_t velocity, vec3_t cmdmove,\n\t\t\t\t\t\t\t\tint cmdframes,\n\t\t\t\t\t\t\t\tint maxframes, float frametime,\n\t\t\t\t\t\t\t\tint stopevent, int stopareanum, int visualize)\n{\n\tvec3_t mins, maxs;\n\treturn AAS_ClientMovementPrediction(move, entnum, origin, presencetype, onground,\n\t\t\t\t\t\t\t\t\t\tvelocity, cmdmove, cmdframes, maxframes,\n\t\t\t\t\t\t\t\t\t\tframetime, stopevent, stopareanum,\n\t\t\t\t\t\t\t\t\t\tmins, maxs, visualize);\n} //end of the function AAS_PredictClientMovement\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_ClientMovementHitBBox(struct aas_clientmove_s *move,\n\t\t\t\t\t\t\t\tint entnum, vec3_t origin,\n\t\t\t\t\t\t\t\tint presencetype, int onground,\n\t\t\t\t\t\t\t\tvec3_t velocity, vec3_t cmdmove,\n\t\t\t\t\t\t\t\tint cmdframes,\n\t\t\t\t\t\t\t\tint maxframes, float frametime,\n\t\t\t\t\t\t\t\tvec3_t mins, vec3_t maxs, int visualize)\n{\n\treturn AAS_ClientMovementPrediction(move, entnum, origin, presencetype, onground,\n\t\t\t\t\t\t\t\t\t\tvelocity, cmdmove, cmdframes, maxframes,\n\t\t\t\t\t\t\t\t\t\tframetime, SE_HITBOUNDINGBOX, 0,\n\t\t\t\t\t\t\t\t\t\tmins, maxs, visualize);\n} //end of the function AAS_ClientMovementHitBBox\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_TestMovementPrediction(int entnum, vec3_t origin, vec3_t dir)\n{\n\tvec3_t velocity, cmdmove;\n\taas_clientmove_t move;\n\n\tVectorClear(velocity);\n\tif (!AAS_Swimming(origin)) dir[2] = 0;\n\tVectorNormalize(dir);\n\tVectorScale(dir, 400, cmdmove);\n\tcmdmove[2] = 224;\n\tAAS_ClearShownDebugLines();\n\tAAS_PredictClientMovement(&move, entnum, origin, PRESENCE_NORMAL, qtrue,\n\t\t\t\t\t\t\t\t\tvelocity, cmdmove, 13, 13, 0.1f, SE_HITGROUND, 0, qtrue);//SE_LEAVEGROUND);\n\tif (move.stopevent & SE_LEAVEGROUND)\n\t{\n\t\tbotimport.Print(PRT_MESSAGE, \"leave ground\\n\");\n\t} //end if\n} //end of the function TestMovementPrediction\n//===========================================================================\n// calculates the horizontal velocity needed to perform a jump from start\n// to end\n//\n// Parameter:\t\t\tzvel\t: z velocity for jump\n//\t\t\t\t\t\tstart\t: start position of jump\n//\t\t\t\t\t\tend\t\t: end position of jump\n//\t\t\t\t\t\t*speed\t: returned speed for jump\n// Returns:\t\t\t\tqfalse if too high or too far from start to end\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_HorizontalVelocityForJump(float zvel, vec3_t start, vec3_t end, float *velocity)\n{\n\tfloat phys_gravity, phys_maxvelocity;\n\tfloat maxjump, height2fall, t, top;\n\tvec3_t dir;\n\n\tphys_gravity = aassettings.phys_gravity;\n\tphys_maxvelocity = aassettings.phys_maxvelocity;\n\n\t//maximum height a player can jump with the given initial z velocity\n\tmaxjump = 0.5 * phys_gravity * (zvel / phys_gravity) * (zvel / phys_gravity);\n\t//top of the parabolic jump\n\ttop = start[2] + maxjump;\n\t//height the bot will fall from the top\n\theight2fall = top - end[2];\n\t//if the goal is to high to jump to\n\tif (height2fall < 0)\n\t{\n\t\t*velocity = phys_maxvelocity;\n\t\treturn 0;\n\t} //end if\n\t//time a player takes to fall the height\n\tt = sqrt(height2fall / (0.5 * phys_gravity));\n  \t//direction from start to end\n\tVectorSubtract(end, start, dir);\n\t//\n\tif ( (t + zvel / phys_gravity) == 0.0f ) {\n\t\t*velocity = phys_maxvelocity;\n\t\treturn 0;\n\t}\n\t//calculate horizontal speed\n\t*velocity = sqrt(dir[0]*dir[0] + dir[1]*dir[1]) / (t + zvel / phys_gravity);\n\t//the horizontal speed must be lower than the max speed\n\tif (*velocity > phys_maxvelocity)\n\t{\n\t\t*velocity = phys_maxvelocity;\n\t\treturn 0;\n\t} //end if\n\treturn 1;\n} //end of the function AAS_HorizontalVelocityForJump\n"
  },
  {
    "path": "src/engine/botlib/be_aas_move.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tbe_aas_move.h\n *\n * desc:\t\tAAS\n *\n * $Archive: /source/code/botlib/be_aas_move.h $\n *\n *****************************************************************************/\n\n#ifdef AASINTERN\nextern aas_settings_t aassettings;\n#endif //AASINTERN\n\n//movement prediction\nint AAS_PredictClientMovement(struct aas_clientmove_s *move,\n\t\t\t\t\t\t\tint entnum, vec3_t origin,\n\t\t\t\t\t\t\tint presencetype, int onground,\n\t\t\t\t\t\t\tvec3_t velocity, vec3_t cmdmove,\n\t\t\t\t\t\t\tint cmdframes,\n\t\t\t\t\t\t\tint maxframes, float frametime,\n\t\t\t\t\t\t\tint stopevent, int stopareanum, int visualize);\n//predict movement until bounding box is hit\nint AAS_ClientMovementHitBBox(struct aas_clientmove_s *move,\n\t\t\t\t\t\t\t\tint entnum, vec3_t origin,\n\t\t\t\t\t\t\t\tint presencetype, int onground,\n\t\t\t\t\t\t\t\tvec3_t velocity, vec3_t cmdmove,\n\t\t\t\t\t\t\t\tint cmdframes,\n\t\t\t\t\t\t\t\tint maxframes, float frametime,\n\t\t\t\t\t\t\t\tvec3_t mins, vec3_t maxs, int visualize);\n//returns true if on the ground at the given origin\nint AAS_OnGround(vec3_t origin, int presencetype, int passent);\n//returns true if swimming at the given origin\nint AAS_Swimming(vec3_t origin);\n//returns the jump reachability run start point\nvoid AAS_JumpReachRunStart(struct aas_reachability_s *reach, vec3_t runstart);\n//returns true if against a ladder at the given origin\nint AAS_AgainstLadder(vec3_t origin);\n//rocket jump Z velocity when rocket-jumping at origin\nfloat AAS_RocketJumpZVelocity(vec3_t origin);\n//bfg jump Z velocity when bfg-jumping at origin\nfloat AAS_BFGJumpZVelocity(vec3_t origin);\n//calculates the horizontal velocity needed for a jump and returns true this velocity could be calculated\nint AAS_HorizontalVelocityForJump(float zvel, vec3_t start, vec3_t end, float *velocity);\n//\nvoid AAS_SetMovedir(vec3_t angles, vec3_t movedir);\n//\nint AAS_DropToFloor(vec3_t origin, vec3_t mins, vec3_t maxs);\n//\nvoid AAS_InitSettings(void);\n"
  },
  {
    "path": "src/engine/botlib/be_aas_optimize.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tbe_aas_optimize.c\n *\n * desc:\t\tdecreases the .aas file size after the reachabilities have\n *\t\t\t\tbeen calculated, just dumps all the faces, edges and vertexes\n *\n * $Archive: /MissionPack/code/botlib/be_aas_optimize.c $\n *\n *****************************************************************************/\n\n#include \"../../game/q_shared.h\"\n#include \"l_libvar.h\"\n#include \"l_memory.h\"\n#include \"l_script.h\"\n#include \"l_precomp.h\"\n#include \"l_struct.h\"\n#include \"aasfile.h\"\n#include \"../../game/botlib.h\"\n#include \"../../game/be_aas.h\"\n#include \"be_aas_funcs.h\"\n#include \"be_interface.h\"\n#include \"be_aas_def.h\"\n\ntypedef struct optimized_s\n{\n\t//vertexes\n\tint numvertexes;\n\taas_vertex_t *vertexes;\n\t//edges\n\tint numedges;\n\taas_edge_t *edges;\n\t//edge index\n\tint edgeindexsize;\n\taas_edgeindex_t *edgeindex;\n\t//faces\n\tint numfaces;\n\taas_face_t *faces;\n\t//face index\n\tint faceindexsize;\n\taas_faceindex_t *faceindex;\n\t//convex areas\n\tint numareas;\n\taas_area_t *areas;\n\t//\n\tint *vertexoptimizeindex;\n\tint *edgeoptimizeindex;\n\tint *faceoptimizeindex;\n} optimized_t;\n\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_KeepEdge(aas_edge_t *edge)\n{\n\treturn 1;\n} //end of the function AAS_KeepFace\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_OptimizeEdge(optimized_t *optimized, int edgenum)\n{\n\tint i, optedgenum;\n\taas_edge_t *edge, *optedge;\n\n\tedge = &aasworld.edges[abs(edgenum)];\n\tif (!AAS_KeepEdge(edge)) return 0;\n\n\toptedgenum = optimized->edgeoptimizeindex[abs(edgenum)];\n\tif (optedgenum)\n\t{\n\t\t//keep the edge reversed sign\n\t\tif (edgenum > 0) return optedgenum;\n\t\telse return -optedgenum;\n\t} //end if\n\n\toptedge = &optimized->edges[optimized->numedges];\n\n\tfor (i = 0; i < 2; i++)\n\t{\n\t\tif (optimized->vertexoptimizeindex[edge->v[i]])\n\t\t{\n\t\t\toptedge->v[i] = optimized->vertexoptimizeindex[edge->v[i]];\n\t\t} //end if\n\t\telse\n\t\t{\n\t\t\tVectorCopy(aasworld.vertexes[edge->v[i]], optimized->vertexes[optimized->numvertexes]);\n\t\t\toptedge->v[i] = optimized->numvertexes;\n\t\t\toptimized->vertexoptimizeindex[edge->v[i]] = optimized->numvertexes;\n\t\t\toptimized->numvertexes++;\n\t\t} //end else\n\t} //end for\n\toptimized->edgeoptimizeindex[abs(edgenum)] = optimized->numedges;\n\toptedgenum = optimized->numedges;\n\toptimized->numedges++;\n\t//keep the edge reversed sign\n\tif (edgenum > 0) return optedgenum;\n\telse return -optedgenum;\n} //end of the function AAS_OptimizeEdge\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_KeepFace(aas_face_t *face)\n{\n\tif (!(face->faceflags & FACE_LADDER)) return 0;\n\telse return 1;\n} //end of the function AAS_KeepFace\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_OptimizeFace(optimized_t *optimized, int facenum)\n{\n\tint i, edgenum, optedgenum, optfacenum;\n\taas_face_t *face, *optface;\n\n\tface = &aasworld.faces[abs(facenum)];\n\tif (!AAS_KeepFace(face)) return 0;\n\n\toptfacenum = optimized->faceoptimizeindex[abs(facenum)];\n\tif (optfacenum)\n\t{\n\t\t//keep the face side sign\n\t\tif (facenum > 0) return optfacenum;\n\t\telse return -optfacenum;\n\t} //end if\n\n\toptface = &optimized->faces[optimized->numfaces];\n\tCom_Memcpy(optface, face, sizeof(aas_face_t));\n\n\toptface->numedges = 0;\n\toptface->firstedge = optimized->edgeindexsize;\n\tfor (i = 0; i < face->numedges; i++)\n\t{\n\t\tedgenum = aasworld.edgeindex[face->firstedge + i];\n\t\toptedgenum = AAS_OptimizeEdge(optimized, edgenum);\n\t\tif (optedgenum)\n\t\t{\n\t\t\toptimized->edgeindex[optface->firstedge + optface->numedges] = optedgenum;\n\t\t\toptface->numedges++;\n\t\t\toptimized->edgeindexsize++;\n\t\t} //end if\n\t} //end for\n\toptimized->faceoptimizeindex[abs(facenum)] = optimized->numfaces;\n\toptfacenum = optimized->numfaces;\n\toptimized->numfaces++;\n\t//keep the face side sign\n\tif (facenum > 0) return optfacenum;\n\telse return -optfacenum;\n} //end of the function AAS_OptimizeFace\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_OptimizeArea(optimized_t *optimized, int areanum)\n{\n\tint i, facenum, optfacenum;\n\taas_area_t *area, *optarea;\n\n\tarea = &aasworld.areas[areanum];\n\toptarea = &optimized->areas[areanum];\n\tCom_Memcpy(optarea, area, sizeof(aas_area_t));\n\n\toptarea->numfaces = 0;\n\toptarea->firstface = optimized->faceindexsize;\n\tfor (i = 0; i < area->numfaces; i++)\n\t{\n\t\tfacenum = aasworld.faceindex[area->firstface + i];\n\t\toptfacenum = AAS_OptimizeFace(optimized, facenum);\n\t\tif (optfacenum)\n\t\t{\n\t\t\toptimized->faceindex[optarea->firstface + optarea->numfaces] = optfacenum;\n\t\t\toptarea->numfaces++;\n\t\t\toptimized->faceindexsize++;\n\t\t} //end if\n\t} //end for\n} //end of the function AAS_OptimizeArea\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_OptimizeAlloc(optimized_t *optimized)\n{\n\toptimized->vertexes = (aas_vertex_t *) GetClearedMemory(aasworld.numvertexes * sizeof(aas_vertex_t));\n\toptimized->numvertexes = 0;\n\toptimized->edges = (aas_edge_t *) GetClearedMemory(aasworld.numedges * sizeof(aas_edge_t));\n\toptimized->numedges = 1; //edge zero is a dummy\n\toptimized->edgeindex = (aas_edgeindex_t *) GetClearedMemory(aasworld.edgeindexsize * sizeof(aas_edgeindex_t));\n\toptimized->edgeindexsize = 0;\n\toptimized->faces = (aas_face_t *) GetClearedMemory(aasworld.numfaces * sizeof(aas_face_t));\n\toptimized->numfaces = 1; //face zero is a dummy\n\toptimized->faceindex = (aas_faceindex_t *) GetClearedMemory(aasworld.faceindexsize * sizeof(aas_faceindex_t));\n\toptimized->faceindexsize = 0;\n\toptimized->areas = (aas_area_t *) GetClearedMemory(aasworld.numareas * sizeof(aas_area_t));\n\toptimized->numareas = aasworld.numareas;\n\t//\n\toptimized->vertexoptimizeindex = (int *) GetClearedMemory(aasworld.numvertexes * sizeof(int));\n\toptimized->edgeoptimizeindex = (int *) GetClearedMemory(aasworld.numedges * sizeof(int));\n\toptimized->faceoptimizeindex = (int *) GetClearedMemory(aasworld.numfaces * sizeof(int));\n} //end of the function AAS_OptimizeAlloc\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_OptimizeStore(optimized_t *optimized)\n{\n\t//store the optimized vertexes\n\tif (aasworld.vertexes) FreeMemory(aasworld.vertexes);\n\taasworld.vertexes = optimized->vertexes;\n\taasworld.numvertexes = optimized->numvertexes;\n\t//store the optimized edges\n\tif (aasworld.edges) FreeMemory(aasworld.edges);\n\taasworld.edges = optimized->edges;\n\taasworld.numedges = optimized->numedges;\n\t//store the optimized edge index\n\tif (aasworld.edgeindex) FreeMemory(aasworld.edgeindex);\n\taasworld.edgeindex = optimized->edgeindex;\n\taasworld.edgeindexsize = optimized->edgeindexsize;\n\t//store the optimized faces\n\tif (aasworld.faces) FreeMemory(aasworld.faces);\n\taasworld.faces = optimized->faces;\n\taasworld.numfaces = optimized->numfaces;\n\t//store the optimized face index\n\tif (aasworld.faceindex) FreeMemory(aasworld.faceindex);\n\taasworld.faceindex = optimized->faceindex;\n\taasworld.faceindexsize = optimized->faceindexsize;\n\t//store the optimized areas\n\tif (aasworld.areas) FreeMemory(aasworld.areas);\n\taasworld.areas = optimized->areas;\n\taasworld.numareas = optimized->numareas;\n\t//free optimize indexes\n\tFreeMemory(optimized->vertexoptimizeindex);\n\tFreeMemory(optimized->edgeoptimizeindex);\n\tFreeMemory(optimized->faceoptimizeindex);\n} //end of the function AAS_OptimizeStore\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_Optimize(void)\n{\n\tint i, sign;\n\toptimized_t optimized;\n\n\tAAS_OptimizeAlloc(&optimized);\n\tfor (i = 1; i < aasworld.numareas; i++)\n\t{\n\t\tAAS_OptimizeArea(&optimized, i);\n\t} //end for\n\t//reset the reachability face pointers\n\tfor (i = 0; i < aasworld.reachabilitysize; i++)\n\t{\n\t\t//NOTE: for TRAVEL_ELEVATOR the facenum is the model number of\n\t\t//\t\tthe elevator\n\t\tif ((aasworld.reachability[i].traveltype & TRAVELTYPE_MASK) == TRAVEL_ELEVATOR) continue;\n\t\t//NOTE: for TRAVEL_JUMPPAD the facenum is the Z velocity and the edgenum is the hor velocity\n\t\tif ((aasworld.reachability[i].traveltype & TRAVELTYPE_MASK) == TRAVEL_JUMPPAD) continue;\n\t\t//NOTE: for TRAVEL_FUNCBOB the facenum and edgenum contain other coded information\n\t\tif ((aasworld.reachability[i].traveltype & TRAVELTYPE_MASK) == TRAVEL_FUNCBOB) continue;\n\t\t//\n\t\tsign = aasworld.reachability[i].facenum;\n\t\taasworld.reachability[i].facenum = optimized.faceoptimizeindex[abs(aasworld.reachability[i].facenum)];\n\t\tif (sign < 0) aasworld.reachability[i].facenum = -aasworld.reachability[i].facenum;\n\t\tsign = aasworld.reachability[i].edgenum;\n\t\taasworld.reachability[i].edgenum = optimized.edgeoptimizeindex[abs(aasworld.reachability[i].edgenum)];\n\t\tif (sign < 0) aasworld.reachability[i].edgenum = -aasworld.reachability[i].edgenum;\n\t} //end for\n\t//store the optimized AAS data into aasworld\n\tAAS_OptimizeStore(&optimized);\n\t//print some nice stuff :)\n\tbotimport.Print(PRT_MESSAGE, \"AAS data optimized.\\n\");\n} //end of the function AAS_Optimize\n"
  },
  {
    "path": "src/engine/botlib/be_aas_optimize.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tbe_aas_optimize.h\n *\n * desc:\t\tAAS\n *\n * $Archive: /source/code/botlib/be_aas_optimize.h $\n *\n *****************************************************************************/\n\nvoid AAS_Optimize(void);\n\n"
  },
  {
    "path": "src/engine/botlib/be_aas_reach.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tbe_aas_reach.c\n *\n * desc:\t\treachability calculations\n *\n * $Archive: /MissionPack/code/botlib/be_aas_reach.c $\n *\n *****************************************************************************/\n\n#include \"../../game/q_shared.h\"\n#include \"l_log.h\"\n#include \"l_memory.h\"\n#include \"l_script.h\"\n#include \"l_libvar.h\"\n#include \"l_precomp.h\"\n#include \"l_struct.h\"\n#include \"aasfile.h\"\n#include \"../../game/botlib.h\"\n#include \"../../game/be_aas.h\"\n#include \"be_aas_funcs.h\"\n#include \"be_aas_def.h\"\n\nextern int Sys_MilliSeconds(void);\n\n\nextern botlib_import_t botimport;\n\n//#define REACH_DEBUG\n\n//NOTE: all travel times are in hundreth of a second\n//maximum number of reachability links\n#define AAS_MAX_REACHABILITYSIZE\t\t\t65536\n//number of areas reachability is calculated for each frame\n#define REACHABILITYAREASPERCYCLE\t\t\t15\n//number of units reachability points are placed inside the areas\n#define INSIDEUNITS\t\t\t\t\t\t\t2\n#define INSIDEUNITS_WALKEND\t\t\t\t\t5\n#define INSIDEUNITS_WALKSTART\t\t\t\t0.1\n#define INSIDEUNITS_WATERJUMP\t\t\t\t15\n//area flag used for weapon jumping\n#define AREA_WEAPONJUMP\t\t\t\t\t\t8192\t//valid area to weapon jump to\n//number of reachabilities of each type\nint reach_swim;\t\t\t//swim\nint reach_equalfloor;\t//walk on floors with equal height\nint reach_step;\t\t\t//step up\nint reach_walk;\t\t\t//walk of step\nint reach_barrier;\t\t//jump up to a barrier\nint reach_waterjump;\t//jump out of water\nint reach_walkoffledge;\t//walk of a ledge\nint reach_jump;\t\t\t//jump\nint reach_ladder;\t\t//climb or descent a ladder\nint reach_teleport;\t\t//teleport\nint reach_elevator;\t\t//use an elevator\nint reach_funcbob;\t\t//use a func bob\nint reach_grapple;\t\t//grapple hook\nint reach_doublejump;\t//double jump\nint reach_rampjump;\t\t//ramp jump\nint reach_strafejump;\t//strafe jump (just normal jump but further)\nint reach_rocketjump;\t//rocket jump\nint reach_bfgjump;\t\t//bfg jump\nint reach_jumppad;\t\t//jump pads\n//if true grapple reachabilities are skipped\nint calcgrapplereach;\n//linked reachability\ntypedef struct aas_lreachability_s\n{\n\tint areanum;\t\t\t\t\t//number of the reachable area\n\tint facenum;\t\t\t\t\t//number of the face towards the other area\n\tint edgenum;\t\t\t\t\t//number of the edge towards the other area\n\tvec3_t start;\t\t\t\t\t//start point of inter area movement\n\tvec3_t end;\t\t\t\t\t\t//end point of inter area movement\n\tint traveltype;\t\t\t\t\t//type of travel required to get to the area\n\tunsigned short int traveltime;\t//travel time of the inter area movement\n\t//\n\tstruct aas_lreachability_s *next;\n} aas_lreachability_t;\n//temporary reachabilities\naas_lreachability_t *reachabilityheap;\t//heap with reachabilities\naas_lreachability_t *nextreachability;\t//next free reachability from the heap\naas_lreachability_t **areareachability;\t//reachability links for every area\nint numlreachabilities;\n\n//===========================================================================\n// returns the surface area of the given face\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nfloat AAS_FaceArea(aas_face_t *face)\n{\n\tint i, edgenum, side;\n\tfloat total;\n\tvec_t *v;\n\tvec3_t d1, d2, cross;\n\taas_edge_t *edge;\n\n\tedgenum = aasworld.edgeindex[face->firstedge];\n\tside = edgenum < 0;\n\tedge = &aasworld.edges[abs(edgenum)];\n\tv = aasworld.vertexes[edge->v[side]];\n\n\ttotal = 0;\n\tfor (i = 1; i < face->numedges - 1; i++)\n\t{\n\t\tedgenum = aasworld.edgeindex[face->firstedge + i];\n\t\tside = edgenum < 0;\n\t\tedge = &aasworld.edges[abs(edgenum)];\n\t\tVectorSubtract(aasworld.vertexes[edge->v[side]], v, d1);\n\t\tVectorSubtract(aasworld.vertexes[edge->v[!side]], v, d2);\n\t\tCrossProduct(d1, d2, cross);\n\t\ttotal += 0.5 * VectorLength(cross);\n\t} //end for\n\treturn total;\n} //end of the function AAS_FaceArea\n//===========================================================================\n// returns the volume of an area\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nfloat AAS_AreaVolume(int areanum)\n{\n\tint i, edgenum, facenum, side;\n\tvec_t d, a, volume;\n\tvec3_t corner;\n\taas_plane_t *plane;\n\taas_edge_t *edge;\n\taas_face_t *face;\n\taas_area_t *area;\n\n\tarea = &aasworld.areas[areanum];\n\tfacenum = aasworld.faceindex[area->firstface];\n\tface = &aasworld.faces[abs(facenum)];\n\tedgenum = aasworld.edgeindex[face->firstedge];\n\tedge = &aasworld.edges[abs(edgenum)];\n\t//\n\tVectorCopy(aasworld.vertexes[edge->v[0]], corner);\n\n\t//make tetrahedrons to all other faces\n\tvolume = 0;\n\tfor (i = 0; i < area->numfaces; i++)\n\t{\n\t\tfacenum = abs(aasworld.faceindex[area->firstface + i]);\n\t\tface = &aasworld.faces[facenum];\n\t\tside = face->backarea != areanum;\n\t\tplane = &aasworld.planes[face->planenum ^ side];\n\t\td = -(DotProduct (corner, plane->normal) - plane->dist);\n\t\ta = AAS_FaceArea(face);\n\t\tvolume += d * a;\n\t} //end for\n\n\tvolume /= 3;\n\treturn volume;\n} //end of the function AAS_AreaVolume\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_BestReachableLinkArea(aas_link_t *areas)\n{\n\taas_link_t *link;\n\n\tfor (link = areas; link; link = link->next_area)\n\t{\n\t\tif (AAS_AreaGrounded(link->areanum) || AAS_AreaSwim(link->areanum))\n\t\t{\n\t\t\treturn link->areanum;\n\t\t} //end if\n\t} //end for\n\t//\n\tfor (link = areas; link; link = link->next_area)\n\t{\n\t\tif (link->areanum) return link->areanum;\n\t\t//FIXME: this is a bad idea when the reachability is not yet\n\t\t// calculated when the level items are loaded\n\t\tif (AAS_AreaReachability(link->areanum))\n\t\t\treturn link->areanum;\n\t} //end for\n\treturn 0;\n} //end of the function AAS_BestReachableLinkArea\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_GetJumpPadInfo(int ent, vec3_t areastart, vec3_t absmins, vec3_t absmaxs, vec3_t velocity)\n{\n\tint modelnum, ent2;\n\tfloat speed, height, gravity, time, dist, forward;\n\tvec3_t origin, angles, teststart, ent2origin;\n\taas_trace_t trace;\n\tchar model[MAX_EPAIRKEY];\n\tchar target[MAX_EPAIRKEY], targetname[MAX_EPAIRKEY];\n\n\t//\n\tAAS_FloatForBSPEpairKey(ent, \"speed\", &speed);\n\tif (!speed) speed = 1000;\n\tVectorClear(angles);\n\t//get the mins, maxs and origin of the model\n\tAAS_ValueForBSPEpairKey(ent, \"model\", model, MAX_EPAIRKEY);\n\tif (model[0]) modelnum = atoi(model+1);\n\telse modelnum = 0;\n\tAAS_BSPModelMinsMaxsOrigin(modelnum, angles, absmins, absmaxs, origin);\n\tVectorAdd(origin, absmins, absmins);\n\tVectorAdd(origin, absmaxs, absmaxs);\n\tVectorAdd(absmins, absmaxs, origin);\n\tVectorScale (origin, 0.5, origin);\n\n\t//get the start areas\n\tVectorCopy(origin, teststart);\n\tteststart[2] += 64;\n\ttrace = AAS_TraceClientBBox(teststart, origin, PRESENCE_CROUCH, -1);\n\tif (trace.startsolid)\n\t{\n\t\tbotimport.Print(PRT_MESSAGE, \"trigger_push start solid\\n\");\n\t\tVectorCopy(origin, areastart);\n\t} //end if\n\telse\n\t{\n\t\tVectorCopy(trace.endpos, areastart);\n\t} //end else\n\tareastart[2] += 0.125;\n\t//\n\t//AAS_DrawPermanentCross(origin, 4, 4);\n\t//get the target entity\n\tAAS_ValueForBSPEpairKey(ent, \"target\", target, MAX_EPAIRKEY);\n\tfor (ent2 = AAS_NextBSPEntity(0); ent2; ent2 = AAS_NextBSPEntity(ent2))\n\t{\n\t\tif (!AAS_ValueForBSPEpairKey(ent2, \"targetname\", targetname, MAX_EPAIRKEY)) continue;\n\t\tif (!strcmp(targetname, target)) break;\n\t} //end for\n\tif (!ent2)\n\t{\n\t\tbotimport.Print(PRT_MESSAGE, \"trigger_push without target entity %s\\n\", target);\n\t\treturn qfalse;\n\t} //end if\n\tAAS_VectorForBSPEpairKey(ent2, \"origin\", ent2origin);\n\t//\n\theight = ent2origin[2] - origin[2];\n\tgravity = aassettings.phys_gravity;\n\ttime = sqrt( height / ( 0.5 * gravity ) );\n\tif (!time)\n\t{\n\t\tbotimport.Print(PRT_MESSAGE, \"trigger_push without time\\n\");\n\t\treturn qfalse;\n\t} //end if\n\t// set s.origin2 to the push velocity\n\tVectorSubtract ( ent2origin, origin, velocity);\n\tdist = VectorNormalize( velocity);\n\tforward = dist / time;\n\t//FIXME: why multiply by 1.1\n\tforward *= 1.1f;\n\tVectorScale(velocity, forward, velocity);\n\tvelocity[2] = time * gravity;\n\treturn qtrue;\n} //end of the function AAS_GetJumpPadInfo\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_BestReachableFromJumpPadArea(vec3_t origin, vec3_t mins, vec3_t maxs)\n{\n\tint area2num, ent, bot_visualizejumppads, bestareanum;\n\tfloat volume, bestareavolume;\n\tvec3_t areastart, cmdmove, bboxmins, bboxmaxs;\n\tvec3_t absmins, absmaxs, velocity;\n\taas_clientmove_t move;\n\taas_link_t *areas, *link;\n\tchar classname[MAX_EPAIRKEY];\n\n#ifdef BSPC\n\tbot_visualizejumppads = 0;\n#else\n\tbot_visualizejumppads = LibVarValue(\"bot_visualizejumppads\", \"0\");\n#endif\n\tVectorAdd(origin, mins, bboxmins);\n\tVectorAdd(origin, maxs, bboxmaxs);\n\tfor (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent))\n\t{\n\t\tif (!AAS_ValueForBSPEpairKey(ent, \"classname\", classname, MAX_EPAIRKEY)) continue;\n\t\tif (strcmp(classname, \"trigger_push\")) continue;\n\t\t//\n\t\tif (!AAS_GetJumpPadInfo(ent, areastart, absmins, absmaxs, velocity)) continue;\n\t\t//get the areas the jump pad brush is in\n\t\tareas = AAS_LinkEntityClientBBox(absmins, absmaxs, -1, PRESENCE_CROUCH);\n\t\tfor (link = areas; link; link = link->next_area)\n\t\t{\n\t\t\tif (AAS_AreaJumpPad(link->areanum)) break;\n\t\t} //end for\n\t\tif (!link)\n\t\t{\n\t\t\tbotimport.Print(PRT_MESSAGE, \"trigger_push not in any jump pad area\\n\");\n\t\t\tAAS_UnlinkFromAreas(areas);\n\t\t\tcontinue;\n\t\t} //end if\n\t\t//\n\t\t//botimport.Print(PRT_MESSAGE, \"found a trigger_push with velocity %f %f %f\\n\", velocity[0], velocity[1], velocity[2]);\n\t\t//\n\t\tVectorSet(cmdmove, 0, 0, 0);\n\t\tCom_Memset(&move, 0, sizeof(aas_clientmove_t));\n\t\tarea2num = 0;\n\t\tAAS_ClientMovementHitBBox(&move, -1, areastart, PRESENCE_NORMAL, qfalse,\n\t\t\t\t\t\t\t\tvelocity, cmdmove, 0, 30, 0.1f, bboxmins, bboxmaxs, bot_visualizejumppads);\n\t\tif (move.frames < 30)\n\t\t{\n\t\t\tbestareanum = 0;\n\t\t\tbestareavolume = 0;\n\t\t\tfor (link = areas; link; link = link->next_area)\n\t\t\t{\n\t\t\t\tif (!AAS_AreaJumpPad(link->areanum)) continue;\n\t\t\t\tvolume = AAS_AreaVolume(link->areanum);\n\t\t\t\tif (volume >= bestareavolume)\n\t\t\t\t{\n\t\t\t\t\tbestareanum = link->areanum;\n\t\t\t\t\tbestareavolume = volume;\n\t\t\t\t} //end if\n\t\t\t} //end if\n\t\t\tAAS_UnlinkFromAreas(areas);\n\t\t\treturn bestareanum;\n\t\t} //end if\n\t\tAAS_UnlinkFromAreas(areas);\n\t} //end for\n\treturn 0;\n} //end of the function AAS_BestReachableFromJumpPadArea\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_BestReachableArea(vec3_t origin, vec3_t mins, vec3_t maxs, vec3_t goalorigin)\n{\n\tint areanum, i, j, k, l;\n\taas_link_t *areas;\n\tvec3_t absmins, absmaxs;\n\t//vec3_t bbmins, bbmaxs;\n\tvec3_t start, end;\n\taas_trace_t trace;\n\n\tif (!aasworld.loaded)\n\t{\n\t\tbotimport.Print(PRT_ERROR, \"AAS_BestReachableArea: aas not loaded\\n\");\n\t\treturn 0;\n\t} //end if\n\t//find a point in an area\n\tVectorCopy(origin, start);\n\tareanum = AAS_PointAreaNum(start);\n\t//while no area found fudge around a little\n\tfor (i = 0; i < 5 && !areanum; i++)\n\t{\n\t\tfor (j = 0; j < 5 && !areanum; j++)\n\t\t{\n\t\t\tfor (k = -1; k <= 1 && !areanum; k++)\n\t\t\t{\n\t\t\t\tfor (l = -1; l <= 1 && !areanum; l++)\n\t\t\t\t{\n\t\t\t\t\tVectorCopy(origin, start);\n\t\t\t\t\tstart[0] += (float) j * 4 * k;\n\t\t\t\t\tstart[1] += (float) j * 4 * l;\n\t\t\t\t\tstart[2] += (float) i * 4;\n\t\t\t\t\tareanum = AAS_PointAreaNum(start);\n\t\t\t\t} //end for\n\t\t\t} //end for\n\t\t} //end for\n\t} //end for\n\t//if an area was found\n\tif (areanum)\n\t{\n\t\t//drop client bbox down and try again\n\t\tVectorCopy(start, end);\n\t\tstart[2] += 0.25;\n\t\tend[2] -= 50;\n\t\ttrace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, -1);\n\t\tif (!trace.startsolid)\n\t\t{\n\t\t\tareanum = AAS_PointAreaNum(trace.endpos);\n\t\t\tVectorCopy(trace.endpos, goalorigin);\n\t\t\t//FIXME: cannot enable next line right now because the reachability\n\t\t\t// does not have to be calculated when the level items are loaded\n\t\t\t//if the origin is in an area with reachability\n\t\t\t//if (AAS_AreaReachability(areanum)) return areanum;\n\t\t\tif (areanum) return areanum;\n\t\t} //end if\n\t\telse\n\t\t{\n\t\t\t//it can very well happen that the AAS_PointAreaNum function tells that\n\t\t\t//a point is in an area and that starting a AAS_TraceClientBBox from that\n\t\t\t//point will return trace.startsolid qtrue\n#if 0\n\t\t\tif (AAS_PointAreaNum(start))\n\t\t\t{\n\t\t\t\tLog_Write(\"point %f %f %f in area %d but trace startsolid\", start[0], start[1], start[2], areanum);\n\t\t\t\tAAS_DrawPermanentCross(start, 4, LINECOLOR_RED);\n\t\t\t} //end if\n\t\t\tbotimport.Print(PRT_MESSAGE, \"AAS_BestReachableArea: start solid\\n\");\n#endif\n\t\t\tVectorCopy(start, goalorigin);\n\t\t\treturn areanum;\n\t\t} //end else\n\t} //end if\n\t//\n\t//AAS_PresenceTypeBoundingBox(PRESENCE_CROUCH, bbmins, bbmaxs);\n\t//NOTE: the goal origin does not have to be in the goal area\n\t// because the bot will have to move towards the item origin anyway\n\tVectorCopy(origin, goalorigin);\n\t//\n\tVectorAdd(origin, mins, absmins);\n\tVectorAdd(origin, maxs, absmaxs);\n\t//add bounding box size\n\t//VectorSubtract(absmins, bbmaxs, absmins);\n\t//VectorSubtract(absmaxs, bbmins, absmaxs);\n\t//link an invalid (-1) entity\n\tareas = AAS_LinkEntityClientBBox(absmins, absmaxs, -1, PRESENCE_CROUCH);\n\t//get the reachable link arae\n\tareanum = AAS_BestReachableLinkArea(areas);\n\t//unlink the invalid entity\n\tAAS_UnlinkFromAreas(areas);\n\t//\n\treturn areanum;\n} //end of the function AAS_BestReachableArea\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_SetupReachabilityHeap(void)\n{\n\tint i;\n\n\treachabilityheap = (aas_lreachability_t *) GetClearedMemory(\n\t\t\t\t\t\tAAS_MAX_REACHABILITYSIZE * sizeof(aas_lreachability_t));\n\tfor (i = 0; i < AAS_MAX_REACHABILITYSIZE-1; i++)\n\t{\n\t\treachabilityheap[i].next = &reachabilityheap[i+1];\n\t} //end for\n\treachabilityheap[AAS_MAX_REACHABILITYSIZE-1].next = NULL;\n\tnextreachability = reachabilityheap;\n\tnumlreachabilities = 0;\n} //end of the function AAS_InitReachabilityHeap\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_ShutDownReachabilityHeap(void)\n{\n\tFreeMemory(reachabilityheap);\n\tnumlreachabilities = 0;\n} //end of the function AAS_ShutDownReachabilityHeap\n//===========================================================================\n// returns a reachability link\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\naas_lreachability_t *AAS_AllocReachability(void)\n{\n\taas_lreachability_t *r;\n\n\tif (!nextreachability) return NULL;\n\t//make sure the error message only shows up once\n\tif (!nextreachability->next) AAS_Error(\"AAS_MAX_REACHABILITYSIZE\");\n\t//\n\tr = nextreachability;\n\tnextreachability = nextreachability->next;\n\tnumlreachabilities++;\n\treturn r;\n} //end of the function AAS_AllocReachability\n//===========================================================================\n// frees a reachability link\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_FreeReachability(aas_lreachability_t *lreach)\n{\n\tCom_Memset(lreach, 0, sizeof(aas_lreachability_t));\n\n\tlreach->next = nextreachability;\n\tnextreachability = lreach;\n\tnumlreachabilities--;\n} //end of the function AAS_FreeReachability\n//===========================================================================\n// returns qtrue if the area has reachability links\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_AreaReachability(int areanum)\n{\n\tif (areanum < 0 || areanum >= aasworld.numareas)\n\t{\n\t\tAAS_Error(\"AAS_AreaReachability: areanum %d out of range\", areanum);\n\t\treturn 0;\n\t} //end if\n\treturn aasworld.areasettings[areanum].numreachableareas;\n} //end of the function AAS_AreaReachability\n//===========================================================================\n// returns the surface area of all ground faces together of the area\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nfloat AAS_AreaGroundFaceArea(int areanum)\n{\n\tint i;\n\tfloat total;\n\taas_area_t *area;\n\taas_face_t *face;\n\n\ttotal = 0;\n\tarea = &aasworld.areas[areanum];\n\tfor (i = 0; i < area->numfaces; i++)\n\t{\n\t\tface = &aasworld.faces[abs(aasworld.faceindex[area->firstface + i])];\n\t\tif (!(face->faceflags & FACE_GROUND)) continue;\n\t\t//\n\t\ttotal += AAS_FaceArea(face);\n\t} //end for\n\treturn total;\n} //end of the function AAS_AreaGroundFaceArea\n//===========================================================================\n// returns the center of a face\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_FaceCenter(int facenum, vec3_t center)\n{\n\tint i;\n\tfloat scale;\n\taas_face_t *face;\n\taas_edge_t *edge;\n\n\tface = &aasworld.faces[facenum];\n\n\tVectorClear(center);\n\tfor (i = 0; i < face->numedges; i++)\n\t{\n\t\tedge = &aasworld.edges[abs(aasworld.edgeindex[face->firstedge + i])];\n\t\tVectorAdd(center, aasworld.vertexes[edge->v[0]], center);\n\t\tVectorAdd(center, aasworld.vertexes[edge->v[1]], center);\n\t} //end for\n\tscale = 0.5 / face->numedges;\n\tVectorScale(center, scale, center);\n} //end of the function AAS_FaceCenter\n//===========================================================================\n// returns the maximum distance a player can fall before being damaged\n// damage = deltavelocity*deltavelocity  * 0.0001\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_FallDamageDistance(void)\n{\n\tfloat maxzvelocity, gravity, t;\n\n\tmaxzvelocity = sqrt(30.f * 10000.f);\n\tgravity = aassettings.phys_gravity;\n\tt = maxzvelocity / gravity;\n\treturn 0.5 * gravity * t * t;\n} //end of the function AAS_FallDamageDistance\n//===========================================================================\n// distance = 0.5 * gravity * t * t\n// vel = t * gravity\n// damage = vel * vel * 0.0001\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nfloat AAS_FallDelta(float distance)\n{\n\tfloat t, delta, gravity;\n\n\tgravity = aassettings.phys_gravity;\n\tt = sqrt(fabs(distance) * 2 / gravity);\n\tdelta = t * gravity;\n\treturn delta * delta * 0.0001;\n} //end of the function AAS_FallDelta\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nfloat AAS_MaxJumpHeight(float phys_jumpvel)\n{\n\tfloat phys_gravity;\n\n\tphys_gravity = aassettings.phys_gravity;\n\t//maximum height a player can jump with the given initial z velocity\n\treturn 0.5 * phys_gravity * (phys_jumpvel / phys_gravity) * (phys_jumpvel / phys_gravity);\n} //end of the function MaxJumpHeight\n//===========================================================================\n// returns true if a player can only crouch in the area\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nfloat AAS_MaxJumpDistance(float phys_jumpvel)\n{\n\tfloat phys_gravity, phys_maxvelocity, t;\n\n\tphys_gravity = aassettings.phys_gravity;\n\tphys_maxvelocity = aassettings.phys_maxvelocity;\n\t//time a player takes to fall the height\n\tt = sqrt(aassettings.rs_maxjumpfallheight / (0.5 * phys_gravity));\n   //maximum distance\n\treturn phys_maxvelocity * (t + phys_jumpvel / phys_gravity);\n} //end of the function AAS_MaxJumpDistance\n//===========================================================================\n// returns true if a player can only crouch in the area\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_AreaCrouch(int areanum)\n{\n\tif (!(aasworld.areasettings[areanum].presencetype & PRESENCE_NORMAL)) return qtrue;\n\telse return qfalse;\n} //end of the function AAS_AreaCrouch\n//===========================================================================\n// returns qtrue if it is possible to swim in the area\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_AreaSwim(int areanum)\n{\n\tif (aasworld.areasettings[areanum].areaflags & AREA_LIQUID) return qtrue;\n\telse return qfalse;\n} //end of the function AAS_AreaSwim\n//===========================================================================\n// returns qtrue if the area contains a liquid\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_AreaLiquid(int areanum)\n{\n\tif (aasworld.areasettings[areanum].areaflags & AREA_LIQUID) return qtrue;\n\telse return qfalse;\n} //end of the function AAS_AreaLiquid\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_AreaLava(int areanum)\n{\n\treturn (aasworld.areasettings[areanum].contents & AREACONTENTS_LAVA);\n} //end of the function AAS_AreaLava\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_AreaSlime(int areanum)\n{\n\treturn (aasworld.areasettings[areanum].contents & AREACONTENTS_SLIME);\n} //end of the function AAS_AreaSlime\n//===========================================================================\n// returns qtrue if the area contains ground faces\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_AreaGrounded(int areanum)\n{\n\treturn (aasworld.areasettings[areanum].areaflags & AREA_GROUNDED);\n} //end of the function AAS_AreaGround\n//===========================================================================\n// returns true if the area contains ladder faces\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_AreaLadder(int areanum)\n{\n\treturn (aasworld.areasettings[areanum].areaflags & AREA_LADDER);\n} //end of the function AAS_AreaLadder\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_AreaJumpPad(int areanum)\n{\n\treturn (aasworld.areasettings[areanum].contents & AREACONTENTS_JUMPPAD);\n} //end of the function AAS_AreaJumpPad\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_AreaTeleporter(int areanum)\n{\n\treturn (aasworld.areasettings[areanum].contents & AREACONTENTS_TELEPORTER);\n} //end of the function AAS_AreaTeleporter\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_AreaClusterPortal(int areanum)\n{\n\treturn (aasworld.areasettings[areanum].contents & AREACONTENTS_CLUSTERPORTAL);\n} //end of the function AAS_AreaClusterPortal\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_AreaDoNotEnter(int areanum)\n{\n\treturn (aasworld.areasettings[areanum].contents & AREACONTENTS_DONOTENTER);\n} //end of the function AAS_AreaDoNotEnter\n//===========================================================================\n// returns the time it takes perform a barrier jump\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nunsigned short int AAS_BarrierJumpTravelTime(void)\n{\n\treturn aassettings.phys_jumpvel / (aassettings.phys_gravity * 0.1);\n} //end op the function AAS_BarrierJumpTravelTime\n//===========================================================================\n// returns true if there already exists a reachability from area1 to area2\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nqboolean AAS_ReachabilityExists(int area1num, int area2num)\n{\n\taas_lreachability_t *r;\n\n\tfor (r = areareachability[area1num]; r; r = r->next)\n\t{\n\t\tif (r->areanum == area2num) return qtrue;\n\t} //end for\n\treturn qfalse;\n} //end of the function AAS_ReachabilityExists\n//===========================================================================\n// returns true if there is a solid just after the end point when going\n// from start to end\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_NearbySolidOrGap(vec3_t start, vec3_t end)\n{\n\tvec3_t dir, testpoint;\n\tint areanum;\n\n\tVectorSubtract(end, start, dir);\n\tdir[2] = 0;\n\tVectorNormalize(dir);\n\tVectorMA(end, 48, dir, testpoint);\n\n\tareanum = AAS_PointAreaNum(testpoint);\n\tif (!areanum)\n\t{\n\t\ttestpoint[2] += 16;\n\t\tareanum = AAS_PointAreaNum(testpoint);\n\t\tif (!areanum) return qtrue;\n\t} //end if\n\tVectorMA(end, 64, dir, testpoint);\n\tareanum = AAS_PointAreaNum(testpoint);\n\tif (areanum)\n\t{\n\t\tif (!AAS_AreaSwim(areanum) && !AAS_AreaGrounded(areanum)) return qtrue;\n\t} //end if\n\treturn qfalse;\n} //end of the function AAS_SolidGapTime\n//===========================================================================\n// searches for swim reachabilities between adjacent areas\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_Reachability_Swim(int area1num, int area2num)\n{\n\tint i, j, face1num, face2num, side1;\n\taas_area_t *area1, *area2;\n\taas_areasettings_t *areasettings;\n\taas_lreachability_t *lreach;\n\taas_face_t *face1;\n\taas_plane_t *plane;\n\tvec3_t start;\n\n\tif (!AAS_AreaSwim(area1num) || !AAS_AreaSwim(area2num)) return qfalse;\n\t//if the second area is crouch only\n\tif (!(aasworld.areasettings[area2num].presencetype & PRESENCE_NORMAL)) return qfalse;\n\n\tarea1 = &aasworld.areas[area1num];\n\tarea2 = &aasworld.areas[area2num];\n\n\t//if the areas are not near anough\n\tfor (i = 0; i < 3; i++)\n\t{\n\t\tif (area1->mins[i] > area2->maxs[i] + 10) return qfalse;\n\t\tif (area1->maxs[i] < area2->mins[i] - 10) return qfalse;\n\t} //end for\n\t//find a shared face and create a reachability link\n\tfor (i = 0; i < area1->numfaces; i++)\n\t{\n\t\tface1num = aasworld.faceindex[area1->firstface + i];\n\t\tside1 = face1num < 0;\n\t\tface1num = abs(face1num);\n\t\t//\n\t\tfor (j = 0; j < area2->numfaces; j++)\n\t\t{\n\t\t\tface2num = abs(aasworld.faceindex[area2->firstface + j]);\n\t\t\t//\n\t\t\tif (face1num == face2num)\n\t\t\t{\n\t\t\t\tAAS_FaceCenter(face1num, start);\n\t\t\t\t//\n\t\t\t\tif (AAS_PointContents(start) & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER))\n\t\t\t\t{\n\t\t\t\t\t//\n\t\t\t\t\tface1 = &aasworld.faces[face1num];\n\t\t\t\t\tareasettings = &aasworld.areasettings[area1num];\n\t\t\t\t\t//create a new reachability link\n\t\t\t\t\tlreach = AAS_AllocReachability();\n\t\t\t\t\tif (!lreach) return qfalse;\n\t\t\t\t\tlreach->areanum = area2num;\n\t\t\t\t\tlreach->facenum = face1num;\n\t\t\t\t\tlreach->edgenum = 0;\n\t\t\t\t\tVectorCopy(start, lreach->start);\n\t\t\t\t\tplane = &aasworld.planes[face1->planenum ^ side1];\n\t\t\t\t\tVectorMA(lreach->start, -INSIDEUNITS, plane->normal, lreach->end);\n\t\t\t\t\tlreach->traveltype = TRAVEL_SWIM;\n\t\t\t\t\tlreach->traveltime = 1;\n\t\t\t\t\t//if the volume of the area is rather small\n\t\t\t\t\tif (AAS_AreaVolume(area2num) < 800)\n\t\t\t\t\t\tlreach->traveltime += 200;\n\t\t\t\t\t//if (!(AAS_PointContents(start) & MASK_WATER)) lreach->traveltime += 500;\n\t\t\t\t\t//link the reachability\n\t\t\t\t\tlreach->next = areareachability[area1num];\n\t\t\t\t\tareareachability[area1num] = lreach;\n\t\t\t\t\treach_swim++;\n\t\t\t\t\treturn qtrue;\n\t\t\t\t} //end if\n\t\t\t} //end if\n\t\t} //end for\n\t} //end for\n\treturn qfalse;\n} //end of the function AAS_Reachability_Swim\n//===========================================================================\n// searches for reachabilities between adjacent areas with equal floor\n// heights\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_Reachability_EqualFloorHeight(int area1num, int area2num)\n{\n\tint i, j, edgenum, edgenum1, edgenum2, foundreach, side;\n\tfloat height, bestheight, length, bestlength;\n\tvec3_t dir, start, end, normal, invgravity, gravitydirection = {0, 0, -1};\n\tvec3_t edgevec;\n\taas_area_t *area1, *area2;\n\taas_face_t *face1, *face2;\n\taas_edge_t *edge;\n\taas_plane_t *plane2;\n\taas_lreachability_t lr, *lreach;\n\n\tif (!AAS_AreaGrounded(area1num) || !AAS_AreaGrounded(area2num)) return qfalse;\n\n\tarea1 = &aasworld.areas[area1num];\n\tarea2 = &aasworld.areas[area2num];\n\t//if the areas are not near anough in the x-y direction\n\tfor (i = 0; i < 2; i++)\n\t{\n\t\tif (area1->mins[i] > area2->maxs[i] + 10) return qfalse;\n\t\tif (area1->maxs[i] < area2->mins[i] - 10) return qfalse;\n\t} //end for\n\t//if area 2 is too high above area 1\n\tif (area2->mins[2] > area1->maxs[2]) return qfalse;\n\t//\n\tVectorCopy(gravitydirection, invgravity);\n\tVectorInverse(invgravity);\n\t//\n\tbestheight = 99999;\n\tbestlength = 0;\n\tfoundreach = qfalse;\n\tCom_Memset(&lr, 0, sizeof(aas_lreachability_t)); //make the compiler happy\n\t//\n\t//check if the areas have ground faces with a common edge\n\t//if existing use the lowest common edge for a reachability link\n\tfor (i = 0; i < area1->numfaces; i++)\n\t{\n\t\tface1 = &aasworld.faces[abs(aasworld.faceindex[area1->firstface + i])];\n\t\tif (!(face1->faceflags & FACE_GROUND)) continue;\n\t\t//\n\t\tfor (j = 0; j < area2->numfaces; j++)\n\t\t{\n\t\t\tface2 = &aasworld.faces[abs(aasworld.faceindex[area2->firstface + j])];\n\t\t\tif (!(face2->faceflags & FACE_GROUND)) continue;\n\t\t\t//if there is a common edge\n\t\t\tfor (edgenum1 = 0; edgenum1 < face1->numedges; edgenum1++)\n\t\t\t{\n\t\t\t\tfor (edgenum2 = 0; edgenum2 < face2->numedges; edgenum2++)\n\t\t\t\t{\n\t\t\t\t\tif (abs(aasworld.edgeindex[face1->firstedge + edgenum1]) !=\n\t\t\t\t\t\t\tabs(aasworld.edgeindex[face2->firstedge + edgenum2]))\n\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\tedgenum = aasworld.edgeindex[face1->firstedge + edgenum1];\n\t\t\t\t\tside = edgenum < 0;\n\t\t\t\t\tedge = &aasworld.edges[abs(edgenum)];\n\t\t\t\t\t//get the length of the edge\n\t\t\t\t\tVectorSubtract(aasworld.vertexes[edge->v[1]],\n\t\t\t\t\t\t\t\taasworld.vertexes[edge->v[0]], dir);\n\t\t\t\t\tlength = VectorLength(dir);\n\t\t\t\t\t//get the start point\n\t\t\t\t\tVectorAdd(aasworld.vertexes[edge->v[0]],\n\t\t\t\t\t\t\t\taasworld.vertexes[edge->v[1]], start);\n\t\t\t\t\tVectorScale(start, 0.5, start);\n\t\t\t\t\tVectorCopy(start, end);\n\t\t\t\t\t//get the end point several units inside area2\n\t\t\t\t\t//and the start point several units inside area1\n\t\t\t\t\t//NOTE: normal is pointing into area2 because the\n\t\t\t\t\t//face edges are stored counter clockwise\n\t\t\t\t\tVectorSubtract(aasworld.vertexes[edge->v[side]],\n\t\t\t\t\t\t\t\taasworld.vertexes[edge->v[!side]], edgevec);\n\t\t\t\t\tplane2 = &aasworld.planes[face2->planenum];\n\t\t\t\t\tCrossProduct(edgevec, plane2->normal, normal);\n\t\t\t\t\tVectorNormalize(normal);\n\t\t\t\t\t//\n\t\t\t\t\t//VectorMA(start, -1, normal, start);\n\t\t\t\t\tVectorMA(end, INSIDEUNITS_WALKEND, normal, end);\n\t\t\t\t\tVectorMA(start, INSIDEUNITS_WALKSTART, normal, start);\n\t\t\t\t\tend[2] += 0.125;\n\t\t\t\t\t//\n\t\t\t\t\theight = DotProduct(invgravity, start);\n\t\t\t\t\t//NOTE: if there's nearby solid or a gap area after this area\n\t\t\t\t\t//disabled this crap\n\t\t\t\t\t//if (AAS_NearbySolidOrGap(start, end)) height += 200;\n\t\t\t\t\t//NOTE: disabled because it disables reachabilities to very small areas\n\t\t\t\t\t//if (AAS_PointAreaNum(end) != area2num) continue;\n\t\t\t\t\t//get the longest lowest edge\n\t\t\t\t\tif (height < bestheight ||\n\t\t\t\t\t\t\t(height < bestheight + 1 && length > bestlength))\n\t\t\t\t\t{\n\t\t\t\t\t\tbestheight = height;\n\t\t\t\t\t\tbestlength = length;\n\t\t\t\t\t\t//create a new reachability link\n\t\t\t\t\t\tlr.areanum = area2num;\n\t\t\t\t\t\tlr.facenum = 0;\n\t\t\t\t\t\tlr.edgenum = edgenum;\n\t\t\t\t\t\tVectorCopy(start, lr.start);\n\t\t\t\t\t\tVectorCopy(end, lr.end);\n\t\t\t\t\t\tlr.traveltype = TRAVEL_WALK;\n\t\t\t\t\t\tlr.traveltime = 1;\n\t\t\t\t\t\tfoundreach = qtrue;\n\t\t\t\t\t} //end if\n\t\t\t\t} //end for\n\t\t\t} //end for\n\t\t} //end for\n\t} //end for\n\tif (foundreach)\n\t{\n\t\t//create a new reachability link\n\t\tlreach = AAS_AllocReachability();\n\t\tif (!lreach) return qfalse;\n\t\tlreach->areanum = lr.areanum;\n\t\tlreach->facenum = lr.facenum;\n\t\tlreach->edgenum = lr.edgenum;\n\t\tVectorCopy(lr.start, lreach->start);\n\t\tVectorCopy(lr.end, lreach->end);\n\t\tlreach->traveltype = lr.traveltype;\n\t\tlreach->traveltime = lr.traveltime;\n\t\tlreach->next = areareachability[area1num];\n\t\tareareachability[area1num] = lreach;\n\t\t//if going into a crouch area\n\t\tif (!AAS_AreaCrouch(area1num) && AAS_AreaCrouch(area2num))\n\t\t{\n\t\t\tlreach->traveltime += aassettings.rs_startcrouch;\n\t\t} //end if\n\t\t/*\n\t\t//NOTE: if there's nearby solid or a gap area after this area\n\t\tif (!AAS_NearbySolidOrGap(lreach->start, lreach->end))\n\t\t{\n\t\t\tlreach->traveltime += 100;\n\t\t} //end if\n\t\t*/\n\t\t//avoid rather small areas\n\t\t//if (AAS_AreaGroundFaceArea(lreach->areanum) < 500) lreach->traveltime += 100;\n\t\t//\n\t\treach_equalfloor++;\n\t\treturn qtrue;\n\t} //end if\n\treturn qfalse;\n} //end of the function AAS_Reachability_EqualFloorHeight\n//===========================================================================\n// searches step, barrier, waterjump and walk off ledge reachabilities\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_Reachability_Step_Barrier_WaterJump_WalkOffLedge(int area1num, int area2num)\n{\n\tint i, j, k, l, edge1num, edge2num, areas[10], numareas;\n\tint ground_bestarea2groundedgenum, ground_foundreach;\n\tint water_bestarea2groundedgenum, water_foundreach;\n\tint side1, area1swim, faceside1, groundface1num;\n\tfloat dist, dist1, dist2, diff, invgravitydot, ortdot;\n\tfloat x1, x2, x3, x4, y1, y2, y3, y4, tmp, y;\n\tfloat length, ground_bestlength, water_bestlength, ground_bestdist, water_bestdist;\n\tvec3_t v1, v2, v3, v4, tmpv, p1area1, p1area2, p2area1, p2area2;\n\tvec3_t normal, ort, edgevec, start, end, dir;\n\tvec3_t ground_beststart, ground_bestend, ground_bestnormal;\n\tvec3_t water_beststart, water_bestend, water_bestnormal;\n\tvec3_t invgravity = {0, 0, 1};\n\tvec3_t testpoint;\n\taas_plane_t *plane;\n\taas_area_t *area1, *area2;\n\taas_face_t *groundface1, *groundface2, *ground_bestface1, *water_bestface1;\n\taas_edge_t *edge1, *edge2;\n\taas_lreachability_t *lreach;\n\taas_trace_t trace;\n\n\t//must be able to walk or swim in the first area\n\tif (!AAS_AreaGrounded(area1num) && !AAS_AreaSwim(area1num)) return qfalse;\n\t//\n\tif (!AAS_AreaGrounded(area2num) && !AAS_AreaSwim(area2num)) return qfalse;\n\t//\n\tarea1 = &aasworld.areas[area1num];\n\tarea2 = &aasworld.areas[area2num];\n\t//if the first area contains a liquid\n\tarea1swim = AAS_AreaSwim(area1num);\n\t//if the areas are not near anough in the x-y direction\n\tfor (i = 0; i < 2; i++)\n\t{\n\t\tif (area1->mins[i] > area2->maxs[i] + 10) return qfalse;\n\t\tif (area1->maxs[i] < area2->mins[i] - 10) return qfalse;\n\t} //end for\n\t//\n\tground_foundreach = qfalse;\n\tground_bestdist = 99999;\n\tground_bestlength = 0;\n\tground_bestarea2groundedgenum = 0;\n\t//\n\twater_foundreach = qfalse;\n\twater_bestdist = 99999;\n\twater_bestlength = 0;\n\twater_bestarea2groundedgenum = 0;\n\t//\n\tfor (i = 0; i < area1->numfaces; i++)\n\t{\n\t\tgroundface1num = aasworld.faceindex[area1->firstface + i];\n\t\tfaceside1 = groundface1num < 0;\n\t\tgroundface1 = &aasworld.faces[abs(groundface1num)];\n\t\t//if this isn't a ground face\n\t\tif (!(groundface1->faceflags & FACE_GROUND))\n\t\t{\n\t\t\t//if we can swim in the first area\n\t\t\tif (area1swim)\n\t\t\t{\n\t\t\t\t//face plane must be more or less horizontal\n\t\t\t\tplane = &aasworld.planes[groundface1->planenum ^ (!faceside1)];\n\t\t\t\tif (DotProduct(plane->normal, invgravity) < 0.7) continue;\n\t\t\t} //end if\n\t\t\telse\n\t\t\t{\n\t\t\t\t//if we can't swim in the area it must be a ground face\n\t\t\t\tcontinue;\n\t\t\t} //end else\n\t\t} //end if\n\t\t//\n\t\tfor (k = 0; k < groundface1->numedges; k++)\n\t\t{\n\t\t\tedge1num = aasworld.edgeindex[groundface1->firstedge + k];\n\t\t\tside1 = (edge1num < 0);\n\t\t\t//NOTE: for water faces we must take the side area 1 is\n\t\t\t// on into account because the face is shared and doesn't\n\t\t\t// have to be oriented correctly\n\t\t\tif (!(groundface1->faceflags & FACE_GROUND)) side1 = (side1 == faceside1);\n\t\t\tedge1num = abs(edge1num);\n\t\t\tedge1 = &aasworld.edges[edge1num];\n\t\t\t//vertexes of the edge\n\t\t\tVectorCopy(aasworld.vertexes[edge1->v[!side1]], v1);\n\t\t\tVectorCopy(aasworld.vertexes[edge1->v[side1]], v2);\n\t\t\t//get a vertical plane through the edge\n\t\t\t//NOTE: normal is pointing into area 2 because the\n\t\t\t//face edges are stored counter clockwise\n\t\t\tVectorSubtract(v2, v1, edgevec);\n\t\t\tCrossProduct(edgevec, invgravity, normal);\n\t\t\tVectorNormalize(normal);\n\t\t\tdist = DotProduct(normal, v1);\n\t\t\t//check the faces from the second area\n\t\t\tfor (j = 0; j < area2->numfaces; j++)\n\t\t\t{\n\t\t\t\tgroundface2 = &aasworld.faces[abs(aasworld.faceindex[area2->firstface + j])];\n\t\t\t\t//must be a ground face\n\t\t\t\tif (!(groundface2->faceflags & FACE_GROUND)) continue;\n\t\t\t\t//check the edges of this ground face\n\t\t\t\tfor (l = 0; l < groundface2->numedges; l++)\n\t\t\t\t{\n\t\t\t\t\tedge2num = abs(aasworld.edgeindex[groundface2->firstedge + l]);\n\t\t\t\t\tedge2 = &aasworld.edges[edge2num];\n\t\t\t\t\t//vertexes of the edge\n\t\t\t\t\tVectorCopy(aasworld.vertexes[edge2->v[0]], v3);\n\t\t\t\t\tVectorCopy(aasworld.vertexes[edge2->v[1]], v4);\n\t\t\t\t\t//check the distance between the two points and the vertical plane\n\t\t\t\t\t//through the edge of area1\n\t\t\t\t\tdiff = DotProduct(normal, v3) - dist;\n\t\t\t\t\tif (diff < -0.1 || diff > 0.1) continue;\n\t\t\t\t\tdiff = DotProduct(normal, v4) - dist;\n\t\t\t\t\tif (diff < -0.1 || diff > 0.1) continue;\n\t\t\t\t\t//\n\t\t\t\t\t//project the two ground edges into the step side plane\n\t\t\t\t\t//and calculate the shortest distance between the two\n\t\t\t\t\t//edges if they overlap in the direction orthogonal to\n\t\t\t\t\t//the gravity direction\n\t\t\t\t\tCrossProduct(invgravity, normal, ort);\n\t\t\t\t\tinvgravitydot = DotProduct(invgravity, invgravity);\n\t\t\t\t\tortdot = DotProduct(ort, ort);\n\t\t\t\t\t//projection into the step plane\n\t\t\t\t\t//NOTE: since gravity is vertical this is just the z coordinate\n\t\t\t\t\ty1 = v1[2];//DotProduct(v1, invgravity) / invgravitydot;\n\t\t\t\t\ty2 = v2[2];//DotProduct(v2, invgravity) / invgravitydot;\n\t\t\t\t\ty3 = v3[2];//DotProduct(v3, invgravity) / invgravitydot;\n\t\t\t\t\ty4 = v4[2];//DotProduct(v4, invgravity) / invgravitydot;\n\t\t\t\t\t//\n\t\t\t\t\tx1 = DotProduct(v1, ort) / ortdot;\n\t\t\t\t\tx2 = DotProduct(v2, ort) / ortdot;\n\t\t\t\t\tx3 = DotProduct(v3, ort) / ortdot;\n\t\t\t\t\tx4 = DotProduct(v4, ort) / ortdot;\n\t\t\t\t\t//\n\t\t\t\t\tif (x1 > x2)\n\t\t\t\t\t{\n\t\t\t\t\t\ttmp = x1; x1 = x2; x2 = tmp;\n\t\t\t\t\t\ttmp = y1; y1 = y2; y2 = tmp;\n\t\t\t\t\t\tVectorCopy(v1, tmpv); VectorCopy(v2, v1); VectorCopy(tmpv, v2);\n\t\t\t\t\t} //end if\n\t\t\t\t\tif (x3 > x4)\n\t\t\t\t\t{\n\t\t\t\t\t\ttmp = x3; x3 = x4; x4 = tmp;\n\t\t\t\t\t\ttmp = y3; y3 = y4; y4 = tmp;\n\t\t\t\t\t\tVectorCopy(v3, tmpv); VectorCopy(v4, v3); VectorCopy(tmpv, v4);\n\t\t\t\t\t} //end if\n\t\t\t\t\t//if the two projected edge lines have no overlap\n\t\t\t\t\tif (x2 <= x3 || x4 <= x1)\n\t\t\t\t\t{\n//\t\t\t\t\t\tLog_Write(\"lines no overlap: from area %d to %d\\r\\n\", area1num, area2num);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t} //end if\n\t\t\t\t\t//if the two lines fully overlap\n\t\t\t\t\tif ((x1 - 0.5 < x3 && x4 < x2 + 0.5) &&\n\t\t\t\t\t\t\t(x3 - 0.5 < x1 && x2 < x4 + 0.5))\n\t\t\t\t\t{\n\t\t\t\t\t\tdist1 = y3 - y1;\n\t\t\t\t\t\tdist2 = y4 - y2;\n\t\t\t\t\t\tVectorCopy(v1, p1area1);\n\t\t\t\t\t\tVectorCopy(v2, p2area1);\n\t\t\t\t\t\tVectorCopy(v3, p1area2);\n\t\t\t\t\t\tVectorCopy(v4, p2area2);\n\t\t\t\t\t} //end if\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t//if the points are equal\n\t\t\t\t\t\tif (x1 > x3 - 0.1 && x1 < x3 + 0.1)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdist1 = y3 - y1;\n\t\t\t\t\t\t\tVectorCopy(v1, p1area1);\n\t\t\t\t\t\t\tVectorCopy(v3, p1area2);\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t\telse if (x1 < x3)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ty = y1 + (x3 - x1) * (y2 - y1) / (x2 - x1);\n\t\t\t\t\t\t\tdist1 = y3 - y;\n\t\t\t\t\t\t\tVectorCopy(v3, p1area1);\n\t\t\t\t\t\t\tp1area1[2] = y;\n\t\t\t\t\t\t\tVectorCopy(v3, p1area2);\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ty = y3 + (x1 - x3) * (y4 - y3) / (x4 - x3);\n\t\t\t\t\t\t\tdist1 = y - y1;\n\t\t\t\t\t\t\tVectorCopy(v1, p1area1);\n\t\t\t\t\t\t\tVectorCopy(v1, p1area2);\n\t\t\t\t\t\t\tp1area2[2] = y;\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t\t//if the points are equal\n\t\t\t\t\t\tif (x2 > x4 - 0.1 && x2 < x4 + 0.1)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdist2 = y4 - y2;\n\t\t\t\t\t\t\tVectorCopy(v2, p2area1);\n\t\t\t\t\t\t\tVectorCopy(v4, p2area2);\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t\telse if (x2 < x4)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ty = y3 + (x2 - x3) * (y4 - y3) / (x4 - x3);\n\t\t\t\t\t\t\tdist2 = y - y2;\n\t\t\t\t\t\t\tVectorCopy(v2, p2area1);\n\t\t\t\t\t\t\tVectorCopy(v2, p2area2);\n\t\t\t\t\t\t\tp2area2[2] = y;\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ty = y1 + (x4 - x1) * (y2 - y1) / (x2 - x1);\n\t\t\t\t\t\t\tdist2 = y4 - y;\n\t\t\t\t\t\t\tVectorCopy(v4, p2area1);\n\t\t\t\t\t\t\tp2area1[2] = y;\n\t\t\t\t\t\t\tVectorCopy(v4, p2area2);\n\t\t\t\t\t\t} //end else\n\t\t\t\t\t} //end else\n\t\t\t\t\t//if both distances are pretty much equal\n\t\t\t\t\t//then we take the middle of the points\n\t\t\t\t\tif (dist1 > dist2 - 1 && dist1 < dist2 + 1)\n\t\t\t\t\t{\n\t\t\t\t\t\tdist = dist1;\n\t\t\t\t\t\tVectorAdd(p1area1, p2area1, start);\n\t\t\t\t\t\tVectorScale(start, 0.5, start);\n\t\t\t\t\t\tVectorAdd(p1area2, p2area2, end);\n\t\t\t\t\t\tVectorScale(end, 0.5, end);\n\t\t\t\t\t} //end if\n\t\t\t\t\telse if (dist1 < dist2)\n\t\t\t\t\t{\n\t\t\t\t\t\tdist = dist1;\n\t\t\t\t\t\tVectorCopy(p1area1, start);\n\t\t\t\t\t\tVectorCopy(p1area2, end);\n\t\t\t\t\t} //end else if\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tdist = dist2;\n\t\t\t\t\t\tVectorCopy(p2area1, start);\n\t\t\t\t\t\tVectorCopy(p2area2, end);\n\t\t\t\t\t} //end else\n\t\t\t\t\t//get the length of the overlapping part of the edges of the two areas\n\t\t\t\t\tVectorSubtract(p2area2, p1area2, dir);\n\t\t\t\t\tlength = VectorLength(dir);\n\t\t\t\t\t//\n\t\t\t\t\tif (groundface1->faceflags & FACE_GROUND)\n\t\t\t\t\t{\n\t\t\t\t\t\t//if the vertical distance is smaller\n\t\t\t\t\t\tif (dist < ground_bestdist ||\n\t\t\t\t\t\t\t\t//or the vertical distance is pretty much the same\n\t\t\t\t\t\t\t\t//but the overlapping part of the edges is longer\n\t\t\t\t\t\t\t\t(dist < ground_bestdist + 1 && length > ground_bestlength))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tground_bestdist = dist;\n\t\t\t\t\t\t\tground_bestlength = length;\n\t\t\t\t\t\t\tground_foundreach = qtrue;\n\t\t\t\t\t\t\tground_bestarea2groundedgenum = edge1num;\n\t\t\t\t\t\t\tground_bestface1 = groundface1;\n\t\t\t\t\t\t\t//best point towards area1\n\t\t\t\t\t\t\tVectorCopy(start, ground_beststart);\n\t\t\t\t\t\t\t//normal is pointing into area2\n\t\t\t\t\t\t\tVectorCopy(normal, ground_bestnormal);\n\t\t\t\t\t\t\t//best point towards area2\n\t\t\t\t\t\t\tVectorCopy(end, ground_bestend);\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t} //end if\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t//if the vertical distance is smaller\n\t\t\t\t\t\tif (dist < water_bestdist ||\n\t\t\t\t\t\t\t\t//or the vertical distance is pretty much the same\n\t\t\t\t\t\t\t\t//but the overlapping part of the edges is longer\n\t\t\t\t\t\t\t\t(dist < water_bestdist + 1 && length > water_bestlength))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\twater_bestdist = dist;\n\t\t\t\t\t\t\twater_bestlength = length;\n\t\t\t\t\t\t\twater_foundreach = qtrue;\n\t\t\t\t\t\t\twater_bestarea2groundedgenum = edge1num;\n\t\t\t\t\t\t\twater_bestface1 = groundface1;\n\t\t\t\t\t\t\t//best point towards area1\n\t\t\t\t\t\t\tVectorCopy(start, water_beststart);\n\t\t\t\t\t\t\t//normal is pointing into area2\n\t\t\t\t\t\t\tVectorCopy(normal, water_bestnormal);\n\t\t\t\t\t\t\t//best point towards area2\n\t\t\t\t\t\t\tVectorCopy(end, water_bestend);\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t} //end else\n\t\t\t\t} //end for\n\t\t\t} //end for\n\t\t} //end for\n\t} //end for\n\t//\n\t// NOTE: swim reachabilities are already filtered out\n\t//\n\t// Steps\n\t//\n\t//        ---------\n\t//        |          step height -> TRAVEL_WALK\n\t//--------|\n\t//\n\t//        ---------\n\t//~~~~~~~~|          step height and low water -> TRAVEL_WALK\n\t//--------|\n\t//\n\t//~~~~~~~~~~~~~~~~~~\n\t//        ---------\n\t//        |          step height and low water up to the step -> TRAVEL_WALK\n\t//--------|\n\t//\n\t//check for a step reachability\n\tif (ground_foundreach)\n\t{\n\t\t//if area2 is higher but lower than the maximum step height\n\t\t//NOTE: ground_bestdist >= 0 also catches equal floor reachabilities\n\t\tif (ground_bestdist >= 0 && ground_bestdist < aassettings.phys_maxstep)\n\t\t{\n\t\t\t//create walk reachability from area1 to area2\n\t\t\tlreach = AAS_AllocReachability();\n\t\t\tif (!lreach) return qfalse;\n\t\t\tlreach->areanum = area2num;\n\t\t\tlreach->facenum = 0;\n\t\t\tlreach->edgenum = ground_bestarea2groundedgenum;\n\t\t\tVectorMA(ground_beststart, INSIDEUNITS_WALKSTART, ground_bestnormal, lreach->start);\n\t\t\tVectorMA(ground_bestend, INSIDEUNITS_WALKEND, ground_bestnormal, lreach->end);\n\t\t\tlreach->traveltype = TRAVEL_WALK;\n\t\t\tlreach->traveltime = 0;//1;\n\t\t\t//if going into a crouch area\n\t\t\tif (!AAS_AreaCrouch(area1num) && AAS_AreaCrouch(area2num))\n\t\t\t{\n\t\t\t\tlreach->traveltime += aassettings.rs_startcrouch;\n\t\t\t} //end if\n\t\t\tlreach->next = areareachability[area1num];\n\t\t\tareareachability[area1num] = lreach;\n\t\t\t//NOTE: if there's nearby solid or a gap area after this area\n\t\t\t/*\n\t\t\tif (!AAS_NearbySolidOrGap(lreach->start, lreach->end))\n\t\t\t{\n\t\t\t\tlreach->traveltime += 100;\n\t\t\t} //end if\n\t\t\t*/\n\t\t\t//avoid rather small areas\n\t\t\t//if (AAS_AreaGroundFaceArea(lreach->areanum) < 500) lreach->traveltime += 100;\n\t\t\t//\n\t\t\treach_step++;\n\t\t\treturn qtrue;\n\t\t} //end if\n\t} //end if\n\t//\n\t// Water Jumps\n\t//\n\t//        ---------\n\t//        |\n\t//~~~~~~~~|\n\t//        |\n\t//        |          higher than step height and water up to waterjump height -> TRAVEL_WATERJUMP\n\t//--------|\n\t//\n\t//~~~~~~~~~~~~~~~~~~\n\t//        ---------\n\t//        |\n\t//        |\n\t//        |\n\t//        |          higher than step height and low water up to the step -> TRAVEL_WATERJUMP\n\t//--------|\n\t//\n\t//check for a waterjump reachability\n\tif (water_foundreach)\n\t{\n\t\t//get a test point a little bit towards area1\n\t\tVectorMA(water_bestend, -INSIDEUNITS, water_bestnormal, testpoint);\n\t\t//go down the maximum waterjump height\n\t\ttestpoint[2] -= aassettings.phys_maxwaterjump;\n\t\t//if there IS water the sv_maxwaterjump height below the bestend point\n\t\tif (aasworld.areasettings[AAS_PointAreaNum(testpoint)].areaflags & AREA_LIQUID)\n\t\t{\n\t\t\t//don't create rediculous water jump reachabilities from areas very far below\n\t\t\t//the water surface\n\t\t\tif (water_bestdist < aassettings.phys_maxwaterjump + 24)\n\t\t\t{\n\t\t\t\t//waterjumping from or towards a crouch only area is not possible in Quake2\n\t\t\t\tif ((aasworld.areasettings[area1num].presencetype & PRESENCE_NORMAL) &&\n\t\t\t\t\t\t(aasworld.areasettings[area2num].presencetype & PRESENCE_NORMAL))\n\t\t\t\t{\n\t\t\t\t\t//create water jump reachability from area1 to area2\n\t\t\t\t\tlreach = AAS_AllocReachability();\n\t\t\t\t\tif (!lreach) return qfalse;\n\t\t\t\t\tlreach->areanum = area2num;\n\t\t\t\t\tlreach->facenum = 0;\n\t\t\t\t\tlreach->edgenum = water_bestarea2groundedgenum;\n\t\t\t\t\tVectorCopy(water_beststart, lreach->start);\n\t\t\t\t\tVectorMA(water_bestend, INSIDEUNITS_WATERJUMP, water_bestnormal, lreach->end);\n\t\t\t\t\tlreach->traveltype = TRAVEL_WATERJUMP;\n\t\t\t\t\tlreach->traveltime = aassettings.rs_waterjump;\n\t\t\t\t\tlreach->next = areareachability[area1num];\n\t\t\t\t\tareareachability[area1num] = lreach;\n\t\t\t\t\t//we've got another waterjump reachability\n\t\t\t\t\treach_waterjump++;\n\t\t\t\t\treturn qtrue;\n\t\t\t\t} //end if\n\t\t\t} //end if\n\t\t} //end if\n\t} //end if\n\t//\n\t// Barrier Jumps\n\t//\n\t//        ---------\n\t//        |\n\t//        |\n\t//        |\n\t//        |         higher than step height lower than barrier height -> TRAVEL_BARRIERJUMP\n\t//--------|\n\t//\n\t//        ---------\n\t//        |\n\t//        |\n\t//        |\n\t//~~~~~~~~|         higher than step height lower than barrier height\n\t//--------|         and a thin layer of water in the area to jump from -> TRAVEL_BARRIERJUMP\n\t//\n\t//check for a barrier jump reachability\n\tif (ground_foundreach)\n\t{\n\t\t//if area2 is higher but lower than the maximum barrier jump height\n\t\tif (ground_bestdist > 0 && ground_bestdist < aassettings.phys_maxbarrier)\n\t\t{\n\t\t\t//if no water in area1 or a very thin layer of water on the ground\n\t\t\tif (!water_foundreach || (ground_bestdist - water_bestdist < 16))\n\t\t\t{\n\t\t\t\t//cannot perform a barrier jump towards or from a crouch area in Quake2\n\t\t\t\tif (!AAS_AreaCrouch(area1num) && !AAS_AreaCrouch(area2num))\n\t\t\t\t{\n\t\t\t\t\t//create barrier jump reachability from area1 to area2\n\t\t\t\t\tlreach = AAS_AllocReachability();\n\t\t\t\t\tif (!lreach) return qfalse;\n\t\t\t\t\tlreach->areanum = area2num;\n\t\t\t\t\tlreach->facenum = 0;\n\t\t\t\t\tlreach->edgenum = ground_bestarea2groundedgenum;\n\t\t\t\t\tVectorMA(ground_beststart, INSIDEUNITS_WALKSTART, ground_bestnormal, lreach->start);\n\t\t\t\t\tVectorMA(ground_bestend, INSIDEUNITS_WALKEND, ground_bestnormal, lreach->end);\n\t\t\t\t\tlreach->traveltype = TRAVEL_BARRIERJUMP;\n\t\t\t\t\tlreach->traveltime = aassettings.rs_barrierjump;//AAS_BarrierJumpTravelTime();\n\t\t\t\t\tlreach->next = areareachability[area1num];\n\t\t\t\t\tareareachability[area1num] = lreach;\n\t\t\t\t\t//we've got another barrierjump reachability\n\t\t\t\t\treach_barrier++;\n\t\t\t\t\treturn qtrue;\n\t\t\t\t} //end if\n\t\t\t} //end if\n\t\t} //end if\n\t} //end if\n\t//\n\t// Walk and Walk Off Ledge\n\t//\n\t//--------|\n\t//        |          can walk or step back -> TRAVEL_WALK\n\t//        ---------\n\t//\n\t//--------|\n\t//        |\n\t//        |\n\t//        |\n\t//        |          cannot walk/step back -> TRAVEL_WALKOFFLEDGE\n\t//        ---------\n\t//\n\t//--------|\n\t//        |\n\t//        |~~~~~~~~\n\t//        |\n\t//        |          cannot step back but can waterjump back -> TRAVEL_WALKOFFLEDGE\n\t//        ---------  FIXME: create TRAVEL_WALK reach??\n\t//\n\t//check for a walk or walk off ledge reachability\n\tif (ground_foundreach)\n\t{\n\t\tif (ground_bestdist < 0)\n\t\t{\n\t\t\tif (ground_bestdist > -aassettings.phys_maxstep)\n\t\t\t{\n\t\t\t\t//create walk reachability from area1 to area2\n\t\t\t\tlreach = AAS_AllocReachability();\n\t\t\t\tif (!lreach) return qfalse;\n\t\t\t\tlreach->areanum = area2num;\n\t\t\t\tlreach->facenum = 0;\n\t\t\t\tlreach->edgenum = ground_bestarea2groundedgenum;\n\t\t\t\tVectorMA(ground_beststart, INSIDEUNITS_WALKSTART, ground_bestnormal, lreach->start);\n\t\t\t\tVectorMA(ground_bestend, INSIDEUNITS_WALKEND, ground_bestnormal, lreach->end);\n\t\t\t\tlreach->traveltype = TRAVEL_WALK;\n\t\t\t\tlreach->traveltime = 1;\n\t\t\t\tlreach->next = areareachability[area1num];\n\t\t\t\tareareachability[area1num] = lreach;\n\t\t\t\t//we've got another walk reachability\n\t\t\t\treach_walk++;\n\t\t\t\treturn qtrue;\n\t\t\t} //end if\n\t\t\t// if no maximum fall height set or less than the max\n\t\t\tif (!aassettings.rs_maxfallheight || fabs(ground_bestdist) < aassettings.rs_maxfallheight) {\n\t\t\t\t//trace a bounding box vertically to check for solids\n\t\t\t\tVectorMA(ground_bestend, INSIDEUNITS, ground_bestnormal, ground_bestend);\n\t\t\t\tVectorCopy(ground_bestend, start);\n\t\t\t\tstart[2] = ground_beststart[2];\n\t\t\t\tVectorCopy(ground_bestend, end);\n\t\t\t\tend[2] += 4;\n\t\t\t\ttrace = AAS_TraceClientBBox(start, end, PRESENCE_NORMAL, -1);\n\t\t\t\t//if no solids were found\n\t\t\t\tif (!trace.startsolid && trace.fraction >= 1.0)\n\t\t\t\t{\n\t\t\t\t\t//the trace end point must be in the goal area\n\t\t\t\t\ttrace.endpos[2] += 1;\n\t\t\t\t\tif (AAS_PointAreaNum(trace.endpos) == area2num)\n\t\t\t\t\t{\n\t\t\t\t\t\t//if not going through a cluster portal\n\t\t\t\t\t\tnumareas = AAS_TraceAreas(start, end, areas, NULL, sizeof(areas) / sizeof(int));\n\t\t\t\t\t\tfor (i = 0; i < numareas; i++)\n\t\t\t\t\t\t\tif (AAS_AreaClusterPortal(areas[i]))\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tif (i >= numareas)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t//create a walk off ledge reachability from area1 to area2\n\t\t\t\t\t\t\tlreach = AAS_AllocReachability();\n\t\t\t\t\t\t\tif (!lreach) return qfalse;\n\t\t\t\t\t\t\tlreach->areanum = area2num;\n\t\t\t\t\t\t\tlreach->facenum = 0;\n\t\t\t\t\t\t\tlreach->edgenum = ground_bestarea2groundedgenum;\n\t\t\t\t\t\t\tVectorCopy(ground_beststart, lreach->start);\n\t\t\t\t\t\t\tVectorCopy(ground_bestend, lreach->end);\n\t\t\t\t\t\t\tlreach->traveltype = TRAVEL_WALKOFFLEDGE;\n\t\t\t\t\t\t\tlreach->traveltime = aassettings.rs_startwalkoffledge + fabs(ground_bestdist) * 50 / aassettings.phys_gravity;\n\t\t\t\t\t\t\t//if falling from too high and not falling into water\n\t\t\t\t\t\t\tif (!AAS_AreaSwim(area2num) && !AAS_AreaJumpPad(area2num))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (AAS_FallDelta(ground_bestdist) > aassettings.phys_falldelta5)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tlreach->traveltime += aassettings.rs_falldamage5;\n\t\t\t\t\t\t\t\t} //end if\n\t\t\t\t\t\t\t\tif (AAS_FallDelta(ground_bestdist) > aassettings.phys_falldelta10)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tlreach->traveltime += aassettings.rs_falldamage10;\n\t\t\t\t\t\t\t\t} //end if\n\t\t\t\t\t\t\t} //end if\n\t\t\t\t\t\t\tlreach->next = areareachability[area1num];\n\t\t\t\t\t\t\tareareachability[area1num] = lreach;\n\t\t\t\t\t\t\t//\n\t\t\t\t\t\t\treach_walkoffledge++;\n\t\t\t\t\t\t\t//NOTE: don't create a weapon (rl, bfg) jump reachability here\n\t\t\t\t\t\t\t//because it interferes with other reachabilities\n\t\t\t\t\t\t\t//like the ladder reachability\n\t\t\t\t\t\t\treturn qtrue;\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t} //end if\n\t\t\t\t} //end if\n\t\t\t} //end if\n\t\t} //end else\n\t} //end if\n\treturn qfalse;\n} //end of the function AAS_Reachability_Step_Barrier_WaterJump_WalkOffLedge\n//===========================================================================\n// returns the distance between the two vectors\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nfloat VectorDistance(vec3_t v1, vec3_t v2)\n{\n\tvec3_t dir;\n\n\tVectorSubtract(v2, v1, dir);\n\treturn VectorLength(dir);\n} //end of the function VectorDistance\n//===========================================================================\n// returns true if the first vector is between the last two vectors\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint VectorBetweenVectors(vec3_t v, vec3_t v1, vec3_t v2)\n{\n\tvec3_t dir1, dir2;\n\n\tVectorSubtract(v, v1, dir1);\n\tVectorSubtract(v, v2, dir2);\n\treturn (DotProduct(dir1, dir2) <= 0);\n} //end of the function VectorBetweenVectors\n//===========================================================================\n// returns the mid point between the two vectors\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid VectorMiddle(vec3_t v1, vec3_t v2, vec3_t middle)\n{\n\tVectorAdd(v1, v2, middle);\n\tVectorScale(middle, 0.5, middle);\n} //end of the function VectorMiddle\n//===========================================================================\n// calculate a range of points closest to each other on both edges\n//\n// Parameter:\t\t\tbeststart1\t\tstart of the range of points on edge v1-v2\n//\t\t\t\t\t\tbeststart2\t\tend of the range of points  on edge v1-v2\n//\t\t\t\t\t\tbestend1\t\tstart of the range of points on edge v3-v4\n//\t\t\t\t\t\tbestend2\t\tend of the range of points  on edge v3-v4\n//\t\t\t\t\t\tbestdist\t\tbest distance so far\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\n/*\nfloat AAS_ClosestEdgePoints(vec3_t v1, vec3_t v2, vec3_t v3, vec3_t v4,\n\t\t\t\t\t\t\taas_plane_t *plane1, aas_plane_t *plane2,\n\t\t\t\t\t\t\tvec3_t beststart, vec3_t bestend, float bestdist)\n{\n\tvec3_t dir1, dir2, p1, p2, p3, p4;\n\tfloat a1, a2, b1, b2, dist;\n\tint founddist;\n\n\t//edge vectors\n\tVectorSubtract(v2, v1, dir1);\n\tVectorSubtract(v4, v3, dir2);\n\t//get the horizontal directions\n\tdir1[2] = 0;\n\tdir2[2] = 0;\n\t//\n\t// p1 = point on an edge vector of area2 closest to v1\n\t// p2 = point on an edge vector of area2 closest to v2\n\t// p3 = point on an edge vector of area1 closest to v3\n\t// p4 = point on an edge vector of area1 closest to v4\n\t//\n\tif (dir2[0])\n\t{\n\t\ta2 = dir2[1] / dir2[0];\n\t\tb2 = v3[1] - a2 * v3[0];\n\t\t//point on the edge vector of area2 closest to v1\n\t\tp1[0] = (DotProduct(v1, dir2) - (a2 * dir2[0] + b2 * dir2[1])) / dir2[0];\n\t\tp1[1] = a2 * p1[0] + b2;\n\t\t//point on the edge vector of area2 closest to v2\n\t\tp2[0] = (DotProduct(v2, dir2) - (a2 * dir2[0] + b2 * dir2[1])) / dir2[0];\n\t\tp2[1] = a2 * p2[0] + b2;\n\t} //end if\n\telse\n\t{\n\t\t//point on the edge vector of area2 closest to v1\n\t\tp1[0] = v3[0];\n\t\tp1[1] = v1[1];\n\t\t//point on the edge vector of area2 closest to v2\n\t\tp2[0] = v3[0];\n\t\tp2[1] = v2[1];\n\t} //end else\n\t//\n\tif (dir1[0])\n\t{\n\t\t//\n\t\ta1 = dir1[1] / dir1[0];\n\t\tb1 = v1[1] - a1 * v1[0];\n\t\t//point on the edge vector of area1 closest to v3\n\t\tp3[0] = (DotProduct(v3, dir1) - (a1 * dir1[0] + b1 * dir1[1])) / dir1[0];\n\t\tp3[1] = a1 * p3[0] + b1;\n\t\t//point on the edge vector of area1 closest to v4\n\t\tp4[0] = (DotProduct(v4, dir1) - (a1 * dir1[0] + b1 * dir1[1])) / dir1[0];\n\t\tp4[1] = a1 * p4[0] + b1;\n\t} //end if\n\telse\n\t{\n\t\t//point on the edge vector of area1 closest to v3\n\t\tp3[0] = v1[0];\n\t\tp3[1] = v3[1];\n\t\t//point on the edge vector of area1 closest to v4\n\t\tp4[0] = v1[0];\n\t\tp4[1] = v4[1];\n\t} //end else\n\t//start with zero z-coordinates\n\tp1[2] = 0;\n\tp2[2] = 0;\n\tp3[2] = 0;\n\tp4[2] = 0;\n\t//calculate the z-coordinates from the ground planes\n\tp1[2] = (plane2->dist - DotProduct(plane2->normal, p1)) / plane2->normal[2];\n\tp2[2] = (plane2->dist - DotProduct(plane2->normal, p2)) / plane2->normal[2];\n\tp3[2] = (plane1->dist - DotProduct(plane1->normal, p3)) / plane1->normal[2];\n\tp4[2] = (plane1->dist - DotProduct(plane1->normal, p4)) / plane1->normal[2];\n\t//\n\tfounddist = qfalse;\n\t//\n\tif (VectorBetweenVectors(p1, v3, v4))\n\t{\n\t\tdist = VectorDistance(v1, p1);\n\t\tif (dist > bestdist - 0.5 && dist < bestdist + 0.5)\n\t\t{\n\t\t\tVectorMiddle(beststart, v1, beststart);\n\t\t\tVectorMiddle(bestend, p1, bestend);\n\t\t} //end if\n\t\telse if (dist < bestdist)\n\t\t{\n\t\t\tbestdist = dist;\n\t\t\tVectorCopy(v1, beststart);\n\t\t\tVectorCopy(p1, bestend);\n\t\t} //end if\n\t\tfounddist = qtrue;\n\t} //end if\n\tif (VectorBetweenVectors(p2, v3, v4))\n\t{\n\t\tdist = VectorDistance(v2, p2);\n\t\tif (dist > bestdist - 0.5 && dist < bestdist + 0.5)\n\t\t{\n\t\t\tVectorMiddle(beststart, v2, beststart);\n\t\t\tVectorMiddle(bestend, p2, bestend);\n\t\t} //end if\n\t\telse if (dist < bestdist)\n\t\t{\n\t\t\tbestdist = dist;\n\t\t\tVectorCopy(v2, beststart);\n\t\t\tVectorCopy(p2, bestend);\n\t\t} //end if\n\t\tfounddist = qtrue;\n\t} //end else if\n\tif (VectorBetweenVectors(p3, v1, v2))\n\t{\n\t\tdist = VectorDistance(v3, p3);\n\t\tif (dist > bestdist - 0.5 && dist < bestdist + 0.5)\n\t\t{\n\t\t\tVectorMiddle(beststart, p3, beststart);\n\t\t\tVectorMiddle(bestend, v3, bestend);\n\t\t} //end if\n\t\telse if (dist < bestdist)\n\t\t{\n\t\t\tbestdist = dist;\n\t\t\tVectorCopy(p3, beststart);\n\t\t\tVectorCopy(v3, bestend);\n\t\t} //end if\n\t\tfounddist = qtrue;\n\t} //end else if\n\tif (VectorBetweenVectors(p4, v1, v2))\n\t{\n\t\tdist = VectorDistance(v4, p4);\n\t\tif (dist > bestdist - 0.5 && dist < bestdist + 0.5)\n\t\t{\n\t\t\tVectorMiddle(beststart, p4, beststart);\n\t\t\tVectorMiddle(bestend, v4, bestend);\n\t\t} //end if\n\t\telse if (dist < bestdist)\n\t\t{\n\t\t\tbestdist = dist;\n\t\t\tVectorCopy(p4, beststart);\n\t\t\tVectorCopy(v4, bestend);\n\t\t} //end if\n\t\tfounddist = qtrue;\n\t} //end else if\n\t//if no shortest distance was found the shortest distance\n\t//is between one of the vertexes of edge1 and one of edge2\n\tif (!founddist)\n\t{\n\t\tdist = VectorDistance(v1, v3);\n\t\tif (dist < bestdist)\n\t\t{\n\t\t\tbestdist = dist;\n\t\t\tVectorCopy(v1, beststart);\n\t\t\tVectorCopy(v3, bestend);\n\t\t} //end if\n\t\tdist = VectorDistance(v1, v4);\n\t\tif (dist < bestdist)\n\t\t{\n\t\t\tbestdist = dist;\n\t\t\tVectorCopy(v1, beststart);\n\t\t\tVectorCopy(v4, bestend);\n\t\t} //end if\n\t\tdist = VectorDistance(v2, v3);\n\t\tif (dist < bestdist)\n\t\t{\n\t\t\tbestdist = dist;\n\t\t\tVectorCopy(v2, beststart);\n\t\t\tVectorCopy(v3, bestend);\n\t\t} //end if\n\t\tdist = VectorDistance(v2, v4);\n\t\tif (dist < bestdist)\n\t\t{\n\t\t\tbestdist = dist;\n\t\t\tVectorCopy(v2, beststart);\n\t\t\tVectorCopy(v4, bestend);\n\t\t} //end if\n\t} //end if\n\treturn bestdist;\n} //end of the function AAS_ClosestEdgePoints*/\n\nfloat AAS_ClosestEdgePoints(vec3_t v1, vec3_t v2, vec3_t v3, vec3_t v4,\n\t\t\t\t\t\t\taas_plane_t *plane1, aas_plane_t *plane2,\n\t\t\t\t\t\t\tvec3_t beststart1, vec3_t bestend1,\n\t\t\t\t\t\t\tvec3_t beststart2, vec3_t bestend2, float bestdist)\n{\n\tvec3_t dir1, dir2, p1, p2, p3, p4;\n\tfloat a1, a2, b1, b2, dist, dist1, dist2;\n\tint founddist;\n\n\t//edge vectors\n\tVectorSubtract(v2, v1, dir1);\n\tVectorSubtract(v4, v3, dir2);\n\t//get the horizontal directions\n\tdir1[2] = 0;\n\tdir2[2] = 0;\n\t//\n\t// p1 = point on an edge vector of area2 closest to v1\n\t// p2 = point on an edge vector of area2 closest to v2\n\t// p3 = point on an edge vector of area1 closest to v3\n\t// p4 = point on an edge vector of area1 closest to v4\n\t//\n\tif (dir2[0])\n\t{\n\t\ta2 = dir2[1] / dir2[0];\n\t\tb2 = v3[1] - a2 * v3[0];\n\t\t//point on the edge vector of area2 closest to v1\n\t\tp1[0] = (DotProduct(v1, dir2) - (a2 * dir2[0] + b2 * dir2[1])) / dir2[0];\n\t\tp1[1] = a2 * p1[0] + b2;\n\t\t//point on the edge vector of area2 closest to v2\n\t\tp2[0] = (DotProduct(v2, dir2) - (a2 * dir2[0] + b2 * dir2[1])) / dir2[0];\n\t\tp2[1] = a2 * p2[0] + b2;\n\t} //end if\n\telse\n\t{\n\t\t//point on the edge vector of area2 closest to v1\n\t\tp1[0] = v3[0];\n\t\tp1[1] = v1[1];\n\t\t//point on the edge vector of area2 closest to v2\n\t\tp2[0] = v3[0];\n\t\tp2[1] = v2[1];\n\t} //end else\n\t//\n\tif (dir1[0])\n\t{\n\t\t//\n\t\ta1 = dir1[1] / dir1[0];\n\t\tb1 = v1[1] - a1 * v1[0];\n\t\t//point on the edge vector of area1 closest to v3\n\t\tp3[0] = (DotProduct(v3, dir1) - (a1 * dir1[0] + b1 * dir1[1])) / dir1[0];\n\t\tp3[1] = a1 * p3[0] + b1;\n\t\t//point on the edge vector of area1 closest to v4\n\t\tp4[0] = (DotProduct(v4, dir1) - (a1 * dir1[0] + b1 * dir1[1])) / dir1[0];\n\t\tp4[1] = a1 * p4[0] + b1;\n\t} //end if\n\telse\n\t{\n\t\t//point on the edge vector of area1 closest to v3\n\t\tp3[0] = v1[0];\n\t\tp3[1] = v3[1];\n\t\t//point on the edge vector of area1 closest to v4\n\t\tp4[0] = v1[0];\n\t\tp4[1] = v4[1];\n\t} //end else\n\t//start with zero z-coordinates\n\tp1[2] = 0;\n\tp2[2] = 0;\n\tp3[2] = 0;\n\tp4[2] = 0;\n\t//calculate the z-coordinates from the ground planes\n\tp1[2] = (plane2->dist - DotProduct(plane2->normal, p1)) / plane2->normal[2];\n\tp2[2] = (plane2->dist - DotProduct(plane2->normal, p2)) / plane2->normal[2];\n\tp3[2] = (plane1->dist - DotProduct(plane1->normal, p3)) / plane1->normal[2];\n\tp4[2] = (plane1->dist - DotProduct(plane1->normal, p4)) / plane1->normal[2];\n\t//\n\tfounddist = qfalse;\n\t//\n\tif (VectorBetweenVectors(p1, v3, v4))\n\t{\n\t\tdist = VectorDistance(v1, p1);\n\t\tif (dist > bestdist - 0.5 && dist < bestdist + 0.5)\n\t\t{\n\t\t\tdist1 = VectorDistance(beststart1, v1);\n\t\t\tdist2 = VectorDistance(beststart2, v1);\n\t\t\tif (dist1 > dist2)\n\t\t\t{\n\t\t\t\tif (dist1 > VectorDistance(beststart1, beststart2)) VectorCopy(v1, beststart2);\n\t\t\t} //end if\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (dist2 > VectorDistance(beststart1, beststart2)) VectorCopy(v1, beststart1);\n\t\t\t} //end else\n\t\t\tdist1 = VectorDistance(bestend1, p1);\n\t\t\tdist2 = VectorDistance(bestend2, p1);\n\t\t\tif (dist1 > dist2)\n\t\t\t{\n\t\t\t\tif (dist1 > VectorDistance(bestend1, bestend2)) VectorCopy(p1, bestend2);\n\t\t\t} //end if\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (dist2 > VectorDistance(bestend1, bestend2)) VectorCopy(p1, bestend1);\n\t\t\t} //end else\n\t\t} //end if\n\t\telse if (dist < bestdist)\n\t\t{\n\t\t\tbestdist = dist;\n\t\t\tVectorCopy(v1, beststart1);\n\t\t\tVectorCopy(v1, beststart2);\n\t\t\tVectorCopy(p1, bestend1);\n\t\t\tVectorCopy(p1, bestend2);\n\t\t} //end if\n\t\tfounddist = qtrue;\n\t} //end if\n\tif (VectorBetweenVectors(p2, v3, v4))\n\t{\n\t\tdist = VectorDistance(v2, p2);\n\t\tif (dist > bestdist - 0.5 && dist < bestdist + 0.5)\n\t\t{\n\t\t\tdist1 = VectorDistance(beststart1, v2);\n\t\t\tdist2 = VectorDistance(beststart2, v2);\n\t\t\tif (dist1 > dist2)\n\t\t\t{\n\t\t\t\tif (dist1 > VectorDistance(beststart1, beststart2)) VectorCopy(v2, beststart2);\n\t\t\t} //end if\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (dist2 > VectorDistance(beststart1, beststart2)) VectorCopy(v2, beststart1);\n\t\t\t} //end else\n\t\t\tdist1 = VectorDistance(bestend1, p2);\n\t\t\tdist2 = VectorDistance(bestend2, p2);\n\t\t\tif (dist1 > dist2)\n\t\t\t{\n\t\t\t\tif (dist1 > VectorDistance(bestend1, bestend2)) VectorCopy(p2, bestend2);\n\t\t\t} //end if\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (dist2 > VectorDistance(bestend1, bestend2)) VectorCopy(p2, bestend1);\n\t\t\t} //end else\n\t\t} //end if\n\t\telse if (dist < bestdist)\n\t\t{\n\t\t\tbestdist = dist;\n\t\t\tVectorCopy(v2, beststart1);\n\t\t\tVectorCopy(v2, beststart2);\n\t\t\tVectorCopy(p2, bestend1);\n\t\t\tVectorCopy(p2, bestend2);\n\t\t} //end if\n\t\tfounddist = qtrue;\n\t} //end else if\n\tif (VectorBetweenVectors(p3, v1, v2))\n\t{\n\t\tdist = VectorDistance(v3, p3);\n\t\tif (dist > bestdist - 0.5 && dist < bestdist + 0.5)\n\t\t{\n\t\t\tdist1 = VectorDistance(beststart1, p3);\n\t\t\tdist2 = VectorDistance(beststart2, p3);\n\t\t\tif (dist1 > dist2)\n\t\t\t{\n\t\t\t\tif (dist1 > VectorDistance(beststart1, beststart2)) VectorCopy(p3, beststart2);\n\t\t\t} //end if\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (dist2 > VectorDistance(beststart1, beststart2)) VectorCopy(p3, beststart1);\n\t\t\t} //end else\n\t\t\tdist1 = VectorDistance(bestend1, v3);\n\t\t\tdist2 = VectorDistance(bestend2, v3);\n\t\t\tif (dist1 > dist2)\n\t\t\t{\n\t\t\t\tif (dist1 > VectorDistance(bestend1, bestend2)) VectorCopy(v3, bestend2);\n\t\t\t} //end if\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (dist2 > VectorDistance(bestend1, bestend2)) VectorCopy(v3, bestend1);\n\t\t\t} //end else\n\t\t} //end if\n\t\telse if (dist < bestdist)\n\t\t{\n\t\t\tbestdist = dist;\n\t\t\tVectorCopy(p3, beststart1);\n\t\t\tVectorCopy(p3, beststart2);\n\t\t\tVectorCopy(v3, bestend1);\n\t\t\tVectorCopy(v3, bestend2);\n\t\t} //end if\n\t\tfounddist = qtrue;\n\t} //end else if\n\tif (VectorBetweenVectors(p4, v1, v2))\n\t{\n\t\tdist = VectorDistance(v4, p4);\n\t\tif (dist > bestdist - 0.5 && dist < bestdist + 0.5)\n\t\t{\n\t\t\tdist1 = VectorDistance(beststart1, p4);\n\t\t\tdist2 = VectorDistance(beststart2, p4);\n\t\t\tif (dist1 > dist2)\n\t\t\t{\n\t\t\t\tif (dist1 > VectorDistance(beststart1, beststart2)) VectorCopy(p4, beststart2);\n\t\t\t} //end if\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (dist2 > VectorDistance(beststart1, beststart2)) VectorCopy(p4, beststart1);\n\t\t\t} //end else\n\t\t\tdist1 = VectorDistance(bestend1, v4);\n\t\t\tdist2 = VectorDistance(bestend2, v4);\n\t\t\tif (dist1 > dist2)\n\t\t\t{\n\t\t\t\tif (dist1 > VectorDistance(bestend1, bestend2)) VectorCopy(v4, bestend2);\n\t\t\t} //end if\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (dist2 > VectorDistance(bestend1, bestend2)) VectorCopy(v4, bestend1);\n\t\t\t} //end else\n\t\t} //end if\n\t\telse if (dist < bestdist)\n\t\t{\n\t\t\tbestdist = dist;\n\t\t\tVectorCopy(p4, beststart1);\n\t\t\tVectorCopy(p4, beststart2);\n\t\t\tVectorCopy(v4, bestend1);\n\t\t\tVectorCopy(v4, bestend2);\n\t\t} //end if\n\t\tfounddist = qtrue;\n\t} //end else if\n\t//if no shortest distance was found the shortest distance\n\t//is between one of the vertexes of edge1 and one of edge2\n\tif (!founddist)\n\t{\n\t\tdist = VectorDistance(v1, v3);\n\t\tif (dist < bestdist)\n\t\t{\n\t\t\tbestdist = dist;\n\t\t\tVectorCopy(v1, beststart1);\n\t\t\tVectorCopy(v1, beststart2);\n\t\t\tVectorCopy(v3, bestend1);\n\t\t\tVectorCopy(v3, bestend2);\n\t\t} //end if\n\t\tdist = VectorDistance(v1, v4);\n\t\tif (dist < bestdist)\n\t\t{\n\t\t\tbestdist = dist;\n\t\t\tVectorCopy(v1, beststart1);\n\t\t\tVectorCopy(v1, beststart2);\n\t\t\tVectorCopy(v4, bestend1);\n\t\t\tVectorCopy(v4, bestend2);\n\t\t} //end if\n\t\tdist = VectorDistance(v2, v3);\n\t\tif (dist < bestdist)\n\t\t{\n\t\t\tbestdist = dist;\n\t\t\tVectorCopy(v2, beststart1);\n\t\t\tVectorCopy(v2, beststart2);\n\t\t\tVectorCopy(v3, bestend1);\n\t\t\tVectorCopy(v3, bestend2);\n\t\t} //end if\n\t\tdist = VectorDistance(v2, v4);\n\t\tif (dist < bestdist)\n\t\t{\n\t\t\tbestdist = dist;\n\t\t\tVectorCopy(v2, beststart1);\n\t\t\tVectorCopy(v2, beststart2);\n\t\t\tVectorCopy(v4, bestend1);\n\t\t\tVectorCopy(v4, bestend2);\n\t\t} //end if\n\t} //end if\n\treturn bestdist;\n} //end of the function AAS_ClosestEdgePoints\n//===========================================================================\n// creates possible jump reachabilities between the areas\n//\n// The two closest points on the ground of the areas are calculated\n// One of the points will be on an edge of a ground face of area1 and\n// one on an edge of a ground face of area2.\n// If there is a range of closest points the point in the middle of this range\n// is selected.\n// Between these two points there must be one or more gaps.\n// If the gaps exist a potential jump is predicted.\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_Reachability_Jump(int area1num, int area2num)\n{\n\tint i, j, k, l, face1num, face2num, edge1num, edge2num, traveltype;\n\tint stopevent, areas[10], numareas;\n\tfloat phys_jumpvel, maxjumpdistance, maxjumpheight, height, bestdist, speed;\n\tvec_t *v1, *v2, *v3, *v4;\n\tvec3_t beststart, beststart2, bestend, bestend2;\n\tvec3_t teststart, testend, dir, velocity, cmdmove, up = {0, 0, 1}, sidewards;\n\taas_area_t *area1, *area2;\n\taas_face_t *face1, *face2;\n\taas_edge_t *edge1, *edge2;\n\taas_plane_t *plane1, *plane2, *plane;\n\taas_trace_t trace;\n\taas_clientmove_t move;\n\taas_lreachability_t *lreach;\n\n\tif (!AAS_AreaGrounded(area1num) || !AAS_AreaGrounded(area2num)) return qfalse;\n\t//cannot jump from or to a crouch area\n\tif (AAS_AreaCrouch(area1num) || AAS_AreaCrouch(area2num)) return qfalse;\n\t//\n\tarea1 = &aasworld.areas[area1num];\n\tarea2 = &aasworld.areas[area2num];\n\t//\n\tphys_jumpvel = aassettings.phys_jumpvel;\n\t//maximum distance a player can jump\n\tmaxjumpdistance = 2 * AAS_MaxJumpDistance(phys_jumpvel);\n\t//maximum height a player can jump with the given initial z velocity\n\tmaxjumpheight = AAS_MaxJumpHeight(phys_jumpvel);\n\n\t//if the areas are not near anough in the x-y direction\n\tfor (i = 0; i < 2; i++)\n\t{\n\t\tif (area1->mins[i] > area2->maxs[i] + maxjumpdistance) return qfalse;\n\t\tif (area1->maxs[i] < area2->mins[i] - maxjumpdistance) return qfalse;\n\t} //end for\n\t//if area2 is way to high to jump up to\n\tif (area2->mins[2] > area1->maxs[2] + maxjumpheight) return qfalse;\n\t//\n\tbestdist = 999999;\n\t//\n\tfor (i = 0; i < area1->numfaces; i++)\n\t{\n\t\tface1num = aasworld.faceindex[area1->firstface + i];\n\t\tface1 = &aasworld.faces[abs(face1num)];\n\t\t//if not a ground face\n\t\tif (!(face1->faceflags & FACE_GROUND)) continue;\n\t\t//\n\t\tfor (j = 0; j < area2->numfaces; j++)\n\t\t{\n\t\t\tface2num = aasworld.faceindex[area2->firstface + j];\n\t\t\tface2 = &aasworld.faces[abs(face2num)];\n\t\t\t//if not a ground face\n\t\t\tif (!(face2->faceflags & FACE_GROUND)) continue;\n\t\t\t//\n\t\t\tfor (k = 0; k < face1->numedges; k++)\n\t\t\t{\n\t\t\t\tedge1num = abs(aasworld.edgeindex[face1->firstedge + k]);\n\t\t\t\tedge1 = &aasworld.edges[edge1num];\n\t\t\t\tfor (l = 0; l < face2->numedges; l++)\n\t\t\t\t{\n\t\t\t\t\tedge2num = abs(aasworld.edgeindex[face2->firstedge + l]);\n\t\t\t\t\tedge2 = &aasworld.edges[edge2num];\n\t\t\t\t\t//calculate the minimum distance between the two edges\n\t\t\t\t\tv1 = aasworld.vertexes[edge1->v[0]];\n\t\t\t\t\tv2 = aasworld.vertexes[edge1->v[1]];\n\t\t\t\t\tv3 = aasworld.vertexes[edge2->v[0]];\n\t\t\t\t\tv4 = aasworld.vertexes[edge2->v[1]];\n\t\t\t\t\t//get the ground planes\n\t\t\t\t\tplane1 = &aasworld.planes[face1->planenum];\n\t\t\t\t\tplane2 = &aasworld.planes[face2->planenum];\n\t\t\t\t\t//\n\t\t\t\t\tbestdist = AAS_ClosestEdgePoints(v1, v2, v3, v4, plane1, plane2,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tbeststart, bestend,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tbeststart2, bestend2, bestdist);\n\t\t\t\t} //end for\n\t\t\t} //end for\n\t\t} //end for\n\t} //end for\n\tVectorMiddle(beststart, beststart2, beststart);\n\tVectorMiddle(bestend, bestend2, bestend);\n\tif (bestdist > 4 && bestdist < maxjumpdistance)\n\t{\n//\t\tLog_Write(\"shortest distance between %d and %d is %f\\r\\n\", area1num, area2num, bestdist);\n\t\t// if very close and almost no height difference then the bot can walk\n\t\tif (bestdist <= 48 && fabs(beststart[2] - bestend[2]) < 8)\n\t\t{\n\t\t\tspeed = 400;\n\t\t\ttraveltype = TRAVEL_WALKOFFLEDGE;\n\t\t} //end if\n\t\telse if (AAS_HorizontalVelocityForJump(0, beststart, bestend, &speed))\n\t\t{\n\t\t\t//FIXME: why multiply with 1.2???\n\t\t\tspeed *= 1.2f;\n\t\t\ttraveltype = TRAVEL_WALKOFFLEDGE;\n\t\t} //end else if\n\t\telse\n\t\t{\n\t\t\t//get the horizontal speed for the jump, if it isn't possible to calculate this\n\t\t\t//speed (the jump is not possible) then there's no jump reachability created\n\t\t\tif (!AAS_HorizontalVelocityForJump(phys_jumpvel, beststart, bestend, &speed))\n\t\t\t\treturn qfalse;\n\t\t\tspeed *= 1.05f;\n\t\t\ttraveltype = TRAVEL_JUMP;\n\t\t\t//\n\t\t\t//NOTE: test if the horizontal distance isn't too small\n\t\t\tVectorSubtract(bestend, beststart, dir);\n\t\t\tdir[2] = 0;\n\t\t\tif (VectorLength(dir) < 10)\n\t\t\t\treturn qfalse;\n\t\t} //end if\n\t\t//\n\t\tVectorSubtract(bestend, beststart, dir);\n\t\tVectorNormalize(dir);\n\t\tVectorMA(beststart, 1, dir, teststart);\n\t\t//\n\t\tVectorCopy(teststart, testend);\n\t\ttestend[2] -= 100;\n\t\ttrace = AAS_TraceClientBBox(teststart, testend, PRESENCE_NORMAL, -1);\n\t\t//\n\t\tif (trace.startsolid)\n\t\t\treturn qfalse;\n\t\tif (trace.fraction < 1)\n\t\t{\n\t\t\tplane = &aasworld.planes[trace.planenum];\n\t\t\t// if the bot can stand on the surface\n\t\t\tif (DotProduct(plane->normal, up) >= 0.7)\n\t\t\t{\n\t\t\t\t// if no lava or slime below\n\t\t\t\tif (!(AAS_PointContents(trace.endpos) & (CONTENTS_LAVA|CONTENTS_SLIME)))\n\t\t\t\t{\n\t\t\t\t\tif (teststart[2] - trace.endpos[2] <= aassettings.phys_maxbarrier)\n\t\t\t\t\t\treturn qfalse;\n\t\t\t\t} //end if\n\t\t\t} //end if\n\t\t} //end if\n\t\t//\n\t\tVectorMA(bestend, -1, dir, teststart);\n\t\t//\n\t\tVectorCopy(teststart, testend);\n\t\ttestend[2] -= 100;\n\t\ttrace = AAS_TraceClientBBox(teststart, testend, PRESENCE_NORMAL, -1);\n\t\t//\n\t\tif (trace.startsolid)\n\t\t\treturn qfalse;\n\t\tif (trace.fraction < 1)\n\t\t{\n\t\t\tplane = &aasworld.planes[trace.planenum];\n\t\t\t// if the bot can stand on the surface\n\t\t\tif (DotProduct(plane->normal, up) >= 0.7)\n\t\t\t{\n\t\t\t\t// if no lava or slime below\n\t\t\t\tif (!(AAS_PointContents(trace.endpos) & (CONTENTS_LAVA|CONTENTS_SLIME)))\n\t\t\t\t{\n\t\t\t\t\tif (teststart[2] - trace.endpos[2] <= aassettings.phys_maxbarrier)\n\t\t\t\t\t\treturn qfalse;\n\t\t\t\t} //end if\n\t\t\t} //end if\n\t\t} //end if\n\t\t//\n\t\t// get command movement\n\t\tVectorClear(cmdmove);\n\t\tif ((traveltype & TRAVELTYPE_MASK) == TRAVEL_JUMP)\n\t\t\tcmdmove[2] = aassettings.phys_jumpvel;\n\t\telse\n\t\t\tcmdmove[2] = 0;\n\t\t//\n\t\tVectorSubtract(bestend, beststart, dir);\n\t\tdir[2] = 0;\n\t\tVectorNormalize(dir);\n\t\tCrossProduct(dir, up, sidewards);\n\t\t//\n\t\tstopevent = SE_HITGROUND|SE_ENTERWATER|SE_ENTERSLIME|SE_ENTERLAVA|SE_HITGROUNDDAMAGE;\n\t\tif (!AAS_AreaClusterPortal(area1num) && !AAS_AreaClusterPortal(area2num))\n\t\t\tstopevent |= SE_TOUCHCLUSTERPORTAL;\n\t\t//\n\t\tfor (i = 0; i < 3; i++)\n\t\t{\n\t\t\t//\n\t\t\tif (i == 1)\n\t\t\t\tVectorAdd(testend, sidewards, testend);\n\t\t\telse if (i == 2)\n\t\t\t\tVectorSubtract(bestend, sidewards, testend);\n\t\t\telse\n\t\t\t\tVectorCopy(bestend, testend);\n\t\t\tVectorSubtract(testend, beststart, dir);\n\t\t\tdir[2] = 0;\n\t\t\tVectorNormalize(dir);\n\t\t\tVectorScale(dir, speed, velocity);\n\t\t\t//\n\t\t\tAAS_PredictClientMovement(&move, -1, beststart, PRESENCE_NORMAL, qtrue,\n\t\t\t\t\t\t\t\t\t\tvelocity, cmdmove, 3, 30, 0.1f,\n\t\t\t\t\t\t\t\t\t\tstopevent, 0, qfalse);\n\t\t\t// if prediction time wasn't enough to fully predict the movement\n\t\t\tif (move.frames >= 30)\n\t\t\t\treturn qfalse;\n\t\t\t// don't enter slime or lava and don't fall from too high\n\t\t\tif (move.stopevent & (SE_ENTERSLIME|SE_ENTERLAVA))\n\t\t\t\treturn qfalse;\n\t\t\t// never jump or fall through a cluster portal\n\t\t\tif (move.stopevent & SE_TOUCHCLUSTERPORTAL)\n\t\t\t\treturn qfalse;\n\t\t\t//the end position should be in area2, also test a little bit back\n\t\t\t//because the predicted jump could have rushed through the area\n\t\t\tVectorMA(move.endpos, -64, dir, teststart);\n\t\t\tteststart[2] += 1;\n\t\t\tnumareas = AAS_TraceAreas(move.endpos, teststart, areas, NULL, sizeof(areas) / sizeof(int));\n\t\t\tfor (j = 0; j < numareas; j++)\n\t\t\t{\n\t\t\t\tif (areas[j] == area2num)\n\t\t\t\t\tbreak;\n\t\t\t} //end for\n\t\t\tif (j < numareas)\n\t\t\t\tbreak;\n\t\t}\n\t\tif (i >= 3)\n\t\t\treturn qfalse;\n\t\t//\n#ifdef REACH_DEBUG\n\t\t//create the reachability\n\t\tLog_Write(\"jump reachability between %d and %d\\r\\n\", area1num, area2num);\n#endif //REACH_DEBUG\n\t\t//create a new reachability link\n\t\tlreach = AAS_AllocReachability();\n\t\tif (!lreach) return qfalse;\n\t\tlreach->areanum = area2num;\n\t\tlreach->facenum = 0;\n\t\tlreach->edgenum = 0;\n\t\tVectorCopy(beststart, lreach->start);\n\t\tVectorCopy(bestend, lreach->end);\n\t\tlreach->traveltype = traveltype;\n\n\t\tVectorSubtract(bestend, beststart, dir);\n\t\theight = dir[2];\n\t\tdir[2] = 0;\n\t\tif ((traveltype & TRAVELTYPE_MASK) == TRAVEL_WALKOFFLEDGE && height > VectorLength(dir))\n\t\t{\n\t\t\tlreach->traveltime = aassettings.rs_startwalkoffledge + height * 50 / aassettings.phys_gravity;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tlreach->traveltime = aassettings.rs_startjump + VectorDistance(bestend, beststart) * 240 / aassettings.phys_maxwalkvelocity;\n\t\t} //end if\n\t\t//\n\t\tif (!AAS_AreaJumpPad(area2num))\n\t\t{\n\t\t\tif (AAS_FallDelta(beststart[2] - bestend[2]) > aassettings.phys_falldelta5)\n\t\t\t{\n\t\t\t\tlreach->traveltime += aassettings.rs_falldamage5;\n\t\t\t} //end if\n\t\t\telse if (AAS_FallDelta(beststart[2] - bestend[2]) > aassettings.phys_falldelta10)\n\t\t\t{\n\t\t\t\tlreach->traveltime += aassettings.rs_falldamage10;\n\t\t\t} //end if\n\t\t} //end if\n\t\tlreach->next = areareachability[area1num];\n\t\tareareachability[area1num] = lreach;\n\t\t//\n\t\tif ((traveltype & TRAVELTYPE_MASK) == TRAVEL_JUMP)\n\t\t\treach_jump++;\n\t\telse\n\t\t\treach_walkoffledge++;\n\t} //end if\n\treturn qfalse;\n} //end of the function AAS_Reachability_Jump\n//===========================================================================\n// create a possible ladder reachability from area1 to area2\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_Reachability_Ladder(int area1num, int area2num)\n{\n\tint i, j, k, l, edge1num, edge2num, sharededgenum, lowestedgenum;\n\tint face1num, face2num, ladderface1num, ladderface2num;\n\tint ladderface1vertical, ladderface2vertical, firstv;\n\tfloat face1area, face2area, bestface1area, bestface2area;\n\tfloat phys_jumpvel, maxjumpheight;\n\tvec3_t area1point, area2point, v1, v2, up = {0, 0, 1};\n\tvec3_t mid, lowestpoint, start, end, sharededgevec, dir;\n\taas_area_t *area1, *area2;\n\taas_face_t *face1, *face2, *ladderface1, *ladderface2;\n\taas_plane_t *plane1, *plane2;\n\taas_edge_t *sharededge, *edge1;\n\taas_lreachability_t *lreach;\n\taas_trace_t trace;\n\n\tif (!AAS_AreaLadder(area1num) || !AAS_AreaLadder(area2num)) return qfalse;\n\t//\n\tphys_jumpvel = aassettings.phys_jumpvel;\n\t//maximum height a player can jump with the given initial z velocity\n\tmaxjumpheight = AAS_MaxJumpHeight(phys_jumpvel);\n\n\tarea1 = &aasworld.areas[area1num];\n\tarea2 = &aasworld.areas[area2num];\n\t//\n\tladderface1 = NULL;\n\tladderface2 = NULL;\n\tladderface1num = 0; //make compiler happy\n\tladderface2num = 0; //make compiler happy\n\tbestface1area = -9999;\n\tbestface2area = -9999;\n\tsharededgenum = 0; //make compiler happy\n\tlowestedgenum = 0; //make compiler happy\n\t//\n\tfor (i = 0; i < area1->numfaces; i++)\n\t{\n\t\tface1num = aasworld.faceindex[area1->firstface + i];\n\t\tface1 = &aasworld.faces[abs(face1num)];\n\t\t//if not a ladder face\n\t\tif (!(face1->faceflags & FACE_LADDER)) continue;\n\t\t//\n\t\tfor (j = 0; j < area2->numfaces; j++)\n\t\t{\n\t\t\tface2num = aasworld.faceindex[area2->firstface + j];\n\t\t\tface2 = &aasworld.faces[abs(face2num)];\n\t\t\t//if not a ladder face\n\t\t\tif (!(face2->faceflags & FACE_LADDER)) continue;\n\t\t\t//check if the faces share an edge\n\t\t\tfor (k = 0; k < face1->numedges; k++)\n\t\t\t{\n\t\t\t\tedge1num = aasworld.edgeindex[face1->firstedge + k];\n\t\t\t\tfor (l = 0; l < face2->numedges; l++)\n\t\t\t\t{\n\t\t\t\t\tedge2num = aasworld.edgeindex[face2->firstedge + l];\n\t\t\t\t\tif (abs(edge1num) == abs(edge2num))\n\t\t\t\t\t{\n\t\t\t\t\t\t//get the face with the largest area\n\t\t\t\t\t\tface1area = AAS_FaceArea(face1);\n\t\t\t\t\t\tface2area = AAS_FaceArea(face2);\n\t\t\t\t\t\tif (face1area > bestface1area && face2area > bestface2area)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tbestface1area = face1area;\n\t\t\t\t\t\t\tbestface2area = face2area;\n\t\t\t\t\t\t\tladderface1 = face1;\n\t\t\t\t\t\t\tladderface2 = face2;\n\t\t\t\t\t\t\tladderface1num = face1num;\n\t\t\t\t\t\t\tladderface2num = face2num;\n\t\t\t\t\t\t\tsharededgenum = edge1num;\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t} //end if\n\t\t\t\t} //end for\n\t\t\t\tif (l != face2->numedges) break;\n\t\t\t} //end for\n\t\t} //end for\n\t} //end for\n\t//\n\tif (ladderface1 && ladderface2)\n\t{\n\t\t//get the middle of the shared edge\n\t\tsharededge = &aasworld.edges[abs(sharededgenum)];\n\t\tfirstv = sharededgenum < 0;\n\t\t//\n\t\tVectorCopy(aasworld.vertexes[sharededge->v[firstv]], v1);\n\t\tVectorCopy(aasworld.vertexes[sharededge->v[!firstv]], v2);\n\t\tVectorAdd(v1, v2, area1point);\n\t\tVectorScale(area1point, 0.5, area1point);\n\t\tVectorCopy(area1point, area2point);\n\t\t//\n\t\t//if the face plane in area 1 is pretty much vertical\n\t\tplane1 = &aasworld.planes[ladderface1->planenum ^ (ladderface1num < 0)];\n\t\tplane2 = &aasworld.planes[ladderface2->planenum ^ (ladderface2num < 0)];\n\t\t//\n\t\t//get the points really into the areas\n\t\tVectorSubtract(v2, v1, sharededgevec);\n\t\tCrossProduct(plane1->normal, sharededgevec, dir);\n\t\tVectorNormalize(dir);\n\t\t//NOTE: 32 because that's larger than 16 (bot bbox x,y)\n\t\tVectorMA(area1point, -32, dir, area1point);\n\t\tVectorMA(area2point, 32, dir, area2point);\n\t\t//\n\t\tladderface1vertical = fabs(DotProduct(plane1->normal, up)) < 0.1;\n\t\tladderface2vertical = fabs(DotProduct(plane2->normal, up)) < 0.1;\n\t\t//there's only reachability between vertical ladder faces\n\t\tif (!ladderface1vertical && !ladderface2vertical) return qfalse;\n\t\t//if both vertical ladder faces\n\t\tif (ladderface1vertical && ladderface2vertical\n\t\t\t\t\t//and the ladder faces do not make a sharp corner\n\t\t\t\t\t&& DotProduct(plane1->normal, plane2->normal) > 0.7\n\t\t\t\t\t//and the shared edge is not too vertical\n\t\t\t\t\t&& fabs(DotProduct(sharededgevec, up)) < 0.7)\n\t\t{\n\t\t\t//create a new reachability link\n\t\t\tlreach = AAS_AllocReachability();\n\t\t\tif (!lreach) return qfalse;\n\t\t\tlreach->areanum = area2num;\n\t\t\tlreach->facenum = ladderface1num;\n\t\t\tlreach->edgenum = abs(sharededgenum);\n\t\t\tVectorCopy(area1point, lreach->start);\n\t\t\t//VectorCopy(area2point, lreach->end);\n\t\t\tVectorMA(area2point, -3, plane1->normal, lreach->end);\n\t\t\tlreach->traveltype = TRAVEL_LADDER;\n\t\t\tlreach->traveltime = 10;\n\t\t\tlreach->next = areareachability[area1num];\n\t\t\tareareachability[area1num] = lreach;\n\t\t\t//\n\t\t\treach_ladder++;\n\t\t\t//create a new reachability link\n\t\t\tlreach = AAS_AllocReachability();\n\t\t\tif (!lreach) return qfalse;\n\t\t\tlreach->areanum = area1num;\n\t\t\tlreach->facenum = ladderface2num;\n\t\t\tlreach->edgenum = abs(sharededgenum);\n\t\t\tVectorCopy(area2point, lreach->start);\n\t\t\t//VectorCopy(area1point, lreach->end);\n\t\t\tVectorMA(area1point, -3, plane1->normal, lreach->end);\n\t\t\tlreach->traveltype = TRAVEL_LADDER;\n\t\t\tlreach->traveltime = 10;\n\t\t\tlreach->next = areareachability[area2num];\n\t\t\tareareachability[area2num] = lreach;\n\t\t\t//\n\t\t\treach_ladder++;\n\t\t\t//\n\t\t\treturn qtrue;\n\t\t} //end if\n\t\t//if the second ladder face is also a ground face\n\t\t//create ladder end (just ladder) reachability and\n\t\t//walk off a ladder (ledge) reachability\n\t\tif (ladderface1vertical && (ladderface2->faceflags & FACE_GROUND))\n\t\t{\n\t\t\t//create a new reachability link\n\t\t\tlreach = AAS_AllocReachability();\n\t\t\tif (!lreach) return qfalse;\n\t\t\tlreach->areanum = area2num;\n\t\t\tlreach->facenum = ladderface1num;\n\t\t\tlreach->edgenum = abs(sharededgenum);\n\t\t\tVectorCopy(area1point, lreach->start);\n\t\t\tVectorCopy(area2point, lreach->end);\n\t\t\tlreach->end[2] += 16;\n\t\t\tVectorMA(lreach->end, -15, plane1->normal, lreach->end);\n\t\t\tlreach->traveltype = TRAVEL_LADDER;\n\t\t\tlreach->traveltime = 10;\n\t\t\tlreach->next = areareachability[area1num];\n\t\t\tareareachability[area1num] = lreach;\n\t\t\t//\n\t\t\treach_ladder++;\n\t\t\t//create a new reachability link\n\t\t\tlreach = AAS_AllocReachability();\n\t\t\tif (!lreach) return qfalse;\n\t\t\tlreach->areanum = area1num;\n\t\t\tlreach->facenum = ladderface2num;\n\t\t\tlreach->edgenum = abs(sharededgenum);\n\t\t\tVectorCopy(area2point, lreach->start);\n\t\t\tVectorCopy(area1point, lreach->end);\n\t\t\tlreach->traveltype = TRAVEL_WALKOFFLEDGE;\n\t\t\tlreach->traveltime = 10;\n\t\t\tlreach->next = areareachability[area2num];\n\t\t\tareareachability[area2num] = lreach;\n\t\t\t//\n\t\t\treach_walkoffledge++;\n\t\t\t//\n\t\t\treturn qtrue;\n\t\t} //end if\n\t\t//\n\t\tif (ladderface1vertical)\n\t\t{\n\t\t\t//find lowest edge of the ladder face\n\t\t\tlowestpoint[2] = 99999;\n\t\t\tfor (i = 0; i < ladderface1->numedges; i++)\n\t\t\t{\n\t\t\t\tedge1num = abs(aasworld.edgeindex[ladderface1->firstedge + i]);\n\t\t\t\tedge1 = &aasworld.edges[edge1num];\n\t\t\t\t//\n\t\t\t\tVectorCopy(aasworld.vertexes[edge1->v[0]], v1);\n\t\t\t\tVectorCopy(aasworld.vertexes[edge1->v[1]], v2);\n\t\t\t\t//\n\t\t\t\tVectorAdd(v1, v2, mid);\n\t\t\t\tVectorScale(mid, 0.5, mid);\n\t\t\t\t//\n\t\t\t\tif (mid[2] < lowestpoint[2])\n\t\t\t\t{\n\t\t\t\t\tVectorCopy(mid, lowestpoint);\n\t\t\t\t\tlowestedgenum = edge1num;\n\t\t\t\t} //end if\n\t\t\t} //end for\n\t\t\t//\n\t\t\tplane1 = &aasworld.planes[ladderface1->planenum];\n\t\t\t//trace down in the middle of this edge\n\t\t\tVectorMA(lowestpoint, 5, plane1->normal, start);\n\t\t\tVectorCopy(start, end);\n\t\t\tstart[2] += 5;\n\t\t\tend[2] -= 100;\n\t\t\t//trace without entity collision\n\t\t\ttrace = AAS_TraceClientBBox(start, end, PRESENCE_NORMAL, -1);\n\t\t\t//\n\t\t\t//\n#ifdef REACH_DEBUG\n\t\t\tif (trace.startsolid)\n\t\t\t{\n\t\t\t\tLog_Write(\"trace from area %d started in solid\\r\\n\", area1num);\n\t\t\t} //end if\n#endif //REACH_DEBUG\n\t\t\t//\n\t\t\ttrace.endpos[2] += 1;\n\t\t\tarea2num = AAS_PointAreaNum(trace.endpos);\n\t\t\t//\n\t\t\tarea2 = &aasworld.areas[area2num];\n\t\t\tfor (i = 0; i < area2->numfaces; i++)\n\t\t\t{\n\t\t\t\tface2num = aasworld.faceindex[area2->firstface + i];\n\t\t\t\tface2 = &aasworld.faces[abs(face2num)];\n\t\t\t\t//\n\t\t\t\tif (face2->faceflags & FACE_LADDER)\n\t\t\t\t{\n\t\t\t\t\tplane2 = &aasworld.planes[face2->planenum];\n\t\t\t\t\tif (fabs(DotProduct(plane2->normal, up)) < 0.1) break;\n\t\t\t\t} //end if\n\t\t\t} //end for\n\t\t\t//if from another area without vertical ladder faces\n\t\t\tif (i >= area2->numfaces && area2num != area1num &&\n\t\t\t\t\t\t//the reachabilities shouldn't exist already\n\t\t\t\t\t\t!AAS_ReachabilityExists(area1num, area2num) &&\n\t\t\t\t\t\t!AAS_ReachabilityExists(area2num, area1num))\n\t\t\t{\n\t\t\t\t//if the height is jumpable\n\t\t\t\tif (start[2] - trace.endpos[2] < maxjumpheight)\n\t\t\t\t{\n\t\t\t\t\t//create a new reachability link\n\t\t\t\t\tlreach = AAS_AllocReachability();\n\t\t\t\t\tif (!lreach) return qfalse;\n\t\t\t\t\tlreach->areanum = area2num;\n\t\t\t\t\tlreach->facenum = ladderface1num;\n\t\t\t\t\tlreach->edgenum = lowestedgenum;\n\t\t\t\t\tVectorCopy(lowestpoint, lreach->start);\n\t\t\t\t\tVectorCopy(trace.endpos, lreach->end);\n\t\t\t\t\tlreach->traveltype = TRAVEL_LADDER;\n\t\t\t\t\tlreach->traveltime = 10;\n\t\t\t\t\tlreach->next = areareachability[area1num];\n\t\t\t\t\tareareachability[area1num] = lreach;\n\t\t\t\t\t//\n\t\t\t\t\treach_ladder++;\n\t\t\t\t\t//create a new reachability link\n\t\t\t\t\tlreach = AAS_AllocReachability();\n\t\t\t\t\tif (!lreach) return qfalse;\n\t\t\t\t\tlreach->areanum = area1num;\n\t\t\t\t\tlreach->facenum = ladderface1num;\n\t\t\t\t\tlreach->edgenum = lowestedgenum;\n\t\t\t\t\tVectorCopy(trace.endpos, lreach->start);\n\t\t\t\t\t//get the end point a little bit into the ladder\n\t\t\t\t\tVectorMA(lowestpoint, -5, plane1->normal, lreach->end);\n\t\t\t\t\t//get the end point a little higher\n\t\t\t\t\tlreach->end[2] += 10;\n\t\t\t\t\tlreach->traveltype = TRAVEL_JUMP;\n\t\t\t\t\tlreach->traveltime = 10;\n\t\t\t\t\tlreach->next = areareachability[area2num];\n\t\t\t\t\tareareachability[area2num] = lreach;\n\t\t\t\t\t//\n\t\t\t\t\treach_jump++;\t\n\t\t\t\t\t//\n\t\t\t\t\treturn qtrue;\n#ifdef REACH_DEBUG\n\t\t\t\t\tLog_Write(\"jump up to ladder reach between %d and %d\\r\\n\", area2num, area1num);\n#endif //REACH_DEBUG\n\t\t\t\t} //end if\n#ifdef REACH_DEBUG\n\t\t\t\telse Log_Write(\"jump too high between area %d and %d\\r\\n\", area2num, area1num);\n#endif //REACH_DEBUG\n\t\t\t} //end if\n\t\t\t/*//if slime or lava below the ladder\n\t\t\t//try jump reachability from far towards the ladder\n\t\t\tif (aasworld.areasettings[area2num].contents & (AREACONTENTS_SLIME\n\t\t\t\t\t\t\t\t\t\t\t\t\t| AREACONTENTS_LAVA))\n\t\t\t{\n\t\t\t\tfor (i = 20; i <= 120; i += 20)\n\t\t\t\t{\n\t\t\t\t\t//trace down in the middle of this edge\n\t\t\t\t\tVectorMA(lowestpoint, i, plane1->normal, start);\n\t\t\t\t\tVectorCopy(start, end);\n\t\t\t\t\tstart[2] += 5;\n\t\t\t\t\tend[2] -= 100;\n\t\t\t\t\t//trace without entity collision\n\t\t\t\t\ttrace = AAS_TraceClientBBox(start, end, PRESENCE_NORMAL, -1);\n\t\t\t\t\t//\n\t\t\t\t\tif (trace.startsolid) break;\n\t\t\t\t\ttrace.endpos[2] += 1;\n\t\t\t\t\tarea2num = AAS_PointAreaNum(trace.endpos);\n\t\t\t\t\tif (area2num == area1num) continue;\n\t\t\t\t\t//\n\t\t\t\t\tif (start[2] - trace.endpos[2] > maxjumpheight) continue;\n\t\t\t\t\tif (aasworld.areasettings[area2num].contents & (AREACONTENTS_SLIME\n\t\t\t\t\t\t\t\t\t\t\t\t| AREACONTENTS_LAVA)) continue;\n\t\t\t\t\t//\n\t\t\t\t\t//create a new reachability link\n\t\t\t\t\tlreach = AAS_AllocReachability();\n\t\t\t\t\tif (!lreach) return qfalse;\n\t\t\t\t\tlreach->areanum = area1num;\n\t\t\t\t\tlreach->facenum = ladderface1num;\n\t\t\t\t\tlreach->edgenum = lowestedgenum;\n\t\t\t\t\tVectorCopy(trace.endpos, lreach->start);\n\t\t\t\t\tVectorCopy(lowestpoint, lreach->end);\n\t\t\t\t\tlreach->end[2] += 5;\n\t\t\t\t\tlreach->traveltype = TRAVEL_JUMP;\n\t\t\t\t\tlreach->traveltime = 10;\n\t\t\t\t\tlreach->next = areareachability[area2num];\n\t\t\t\t\tareareachability[area2num] = lreach;\n\t\t\t\t\t//\n\t\t\t\t\treach_jump++;\n\t\t\t\t\t//\n\t\t\t\t\tLog_Write(\"jump far to ladder reach between %d and %d\\r\\n\", area2num, area1num);\n\t\t\t\t\t//\n\t\t\t\t\tbreak;\n\t\t\t\t} //end for\n\t\t\t} //end if*/\n\t\t} //end if\n\t} //end if\n\treturn qfalse;\n} //end of the function AAS_Reachability_Ladder\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_TravelFlagsForTeam(int ent)\n{\n\tint notteam;\n\n\tif (!AAS_IntForBSPEpairKey(ent, \"bot_notteam\", &notteam))\n\t\treturn 0;\n\tif (notteam == 1)\n\t\treturn TRAVELFLAG_NOTTEAM1;\n\tif (notteam == 2)\n\t\treturn TRAVELFLAG_NOTTEAM2;\n\treturn 0;\n} //end of the function AAS_TravelFlagsForTeam\n//===========================================================================\n// create possible teleporter reachabilities\n// this is very game dependent.... :(\n//\n// classname = trigger_multiple or trigger_teleport\n// target = \"t1\"\n//\n// classname = target_teleporter\n// targetname = \"t1\"\n// target = \"t2\"\n//\n// classname = misc_teleporter_dest\n// targetname = \"t2\"\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_Reachability_Teleport(void)\n{\n\tint area1num, area2num;\n\tchar target[MAX_EPAIRKEY], targetname[MAX_EPAIRKEY];\n\tchar classname[MAX_EPAIRKEY], model[MAX_EPAIRKEY];\n\tint ent, dest;\n\tfloat angle;\n\tvec3_t origin, destorigin, mins, maxs, end, angles;\n\tvec3_t mid, velocity, cmdmove;\n\taas_lreachability_t *lreach;\n\taas_clientmove_t move;\n\taas_trace_t trace;\n\taas_link_t *areas, *link;\n\n\tfor (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent))\n\t{\n\t\tif (!AAS_ValueForBSPEpairKey(ent, \"classname\", classname, MAX_EPAIRKEY)) continue;\n\t\tif (!strcmp(classname, \"trigger_multiple\"))\n\t\t{\n\t\t\tAAS_ValueForBSPEpairKey(ent, \"model\", model, MAX_EPAIRKEY);\n//#ifdef REACH_DEBUG\n\t\t\tbotimport.Print(PRT_MESSAGE, \"trigger_multiple model = \\\"%s\\\"\\n\", model);\n//#endif REACH_DEBUG\n\t\t\tVectorClear(angles);\n\t\t\tAAS_BSPModelMinsMaxsOrigin(atoi(model+1), angles, mins, maxs, origin);\n\t\t\t//\n\t\t\tif (!AAS_ValueForBSPEpairKey(ent, \"target\", target, MAX_EPAIRKEY))\n\t\t\t{\n\t\t\t\tbotimport.Print(PRT_ERROR, \"trigger_multiple at %1.0f %1.0f %1.0f without target\\n\",\n\t\t\t\t\t\t\t\t\torigin[0], origin[1], origin[2]);\n\t\t\t\tcontinue;\n\t\t\t} //end if\n\t\t\tfor (dest = AAS_NextBSPEntity(0); dest; dest = AAS_NextBSPEntity(dest))\n\t\t\t{\n\t\t\t\tif (!AAS_ValueForBSPEpairKey(dest, \"classname\", classname, MAX_EPAIRKEY)) continue;\n\t\t\t\tif (!strcmp(classname, \"target_teleporter\"))\n\t\t\t\t{\n\t\t\t\t\tif (!AAS_ValueForBSPEpairKey(dest, \"targetname\", targetname, MAX_EPAIRKEY)) continue;\n\t\t\t\t\tif (!strcmp(targetname, target))\n\t\t\t\t\t{\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t} //end if\n\t\t\t\t} //end if\n\t\t\t} //end for\n\t\t\tif (!dest)\n\t\t\t{\n\t\t\t\tcontinue;\n\t\t\t} //end if\n\t\t\tif (!AAS_ValueForBSPEpairKey(dest, \"target\", target, MAX_EPAIRKEY))\n\t\t\t{\n\t\t\t\tbotimport.Print(PRT_ERROR, \"target_teleporter without target\\n\");\n\t\t\t\tcontinue;\n\t\t\t} //end if\n\t\t} //end else\n\t\telse if (!strcmp(classname, \"trigger_teleport\"))\n\t\t{\n\t\t\tAAS_ValueForBSPEpairKey(ent, \"model\", model, MAX_EPAIRKEY);\n//#ifdef REACH_DEBUG\n\t\t\tbotimport.Print(PRT_MESSAGE, \"trigger_teleport model = \\\"%s\\\"\\n\", model);\n//#endif REACH_DEBUG\n\t\t\tVectorClear(angles);\n\t\t\tAAS_BSPModelMinsMaxsOrigin(atoi(model+1), angles, mins, maxs, origin);\n\t\t\t//\n\t\t\tif (!AAS_ValueForBSPEpairKey(ent, \"target\", target, MAX_EPAIRKEY))\n\t\t\t{\n\t\t\t\tbotimport.Print(PRT_ERROR, \"trigger_teleport at %1.0f %1.0f %1.0f without target\\n\",\n\t\t\t\t\t\t\t\t\torigin[0], origin[1], origin[2]);\n\t\t\t\tcontinue;\n\t\t\t} //end if\n\t\t} //end if\n\t\telse\n\t\t{\n\t\t\tcontinue;\n\t\t} //end else\n\t\t//\n\t\tfor (dest = AAS_NextBSPEntity(0); dest; dest = AAS_NextBSPEntity(dest))\n\t\t{\n\t\t\t//classname should be misc_teleporter_dest\n\t\t\t//but I've also seen target_position and actually any\n\t\t\t//entity could be used... burp\n\t\t\tif (AAS_ValueForBSPEpairKey(dest, \"targetname\", targetname, MAX_EPAIRKEY))\n\t\t\t{\n\t\t\t\tif (!strcmp(targetname, target))\n\t\t\t\t{\n\t\t\t\t\tbreak;\n\t\t\t\t} //end if\n\t\t\t} //end if\n\t\t} //end for\n\t\tif (!dest)\n\t\t{\n\t\t\tbotimport.Print(PRT_ERROR, \"teleporter without misc_teleporter_dest (%s)\\n\", target);\n\t\t\tcontinue;\n\t\t} //end if\n\t\tif (!AAS_VectorForBSPEpairKey(dest, \"origin\", destorigin))\n\t\t{\n\t\t\tbotimport.Print(PRT_ERROR, \"teleporter destination (%s) without origin\\n\", target);\n\t\t\tcontinue;\n\t\t} //end if\n\t\t//\n\t\tarea2num = AAS_PointAreaNum(destorigin);\n\t\t//if not teleported into a teleporter or into a jumppad\n\t\tif (!AAS_AreaTeleporter(area2num) && !AAS_AreaJumpPad(area2num))\n\t\t{\n\t\t\tVectorCopy(destorigin, end);\n\t\t\tend[2] -= 64;\n\t\t\ttrace = AAS_TraceClientBBox(destorigin, end, PRESENCE_CROUCH, -1);\n\t\t\tif (trace.startsolid)\n\t\t\t{\n\t\t\t\tbotimport.Print(PRT_ERROR, \"teleporter destination (%s) in solid\\n\", target);\n\t\t\t\tcontinue;\n\t\t\t} //end if\n\t\t\tarea2num = AAS_PointAreaNum(trace.endpos);\n\t\t\t//\n\t\t\t/*\n\t\t\tif (!AAS_AreaTeleporter(area2num) &&\n\t\t\t\t!AAS_AreaJumpPad(area2num) &&\n\t\t\t\t!AAS_AreaGrounded(area2num))\n\t\t\t{\n\t\t\t\tVectorCopy(trace.endpos, destorigin);\n\t\t\t}\n\t\t\telse*/\n\t\t\t{\n\t\t\t\t//predict where you'll end up\n\t\t\t\tAAS_FloatForBSPEpairKey(dest, \"angle\", &angle);\n\t\t\t\tif (angle)\n\t\t\t\t{\n\t\t\t\t\tVectorSet(angles, 0, angle, 0);\n\t\t\t\t\tAngleVectors(angles, velocity, NULL, NULL);\n\t\t\t\t\tVectorScale(velocity, 400, velocity);\n\t\t\t\t} //end if\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tVectorClear(velocity);\n\t\t\t\t} //end else\n\t\t\t\tVectorClear(cmdmove);\n\t\t\t\tAAS_PredictClientMovement(&move, -1, destorigin, PRESENCE_NORMAL, qfalse,\n\t\t\t\t\t\t\t\t\t\tvelocity, cmdmove, 0, 30, 0.1f,\n\t\t\t\t\t\t\t\t\t\tSE_HITGROUND|SE_ENTERWATER|SE_ENTERSLIME|\n\t\t\t\t\t\t\t\t\t\tSE_ENTERLAVA|SE_HITGROUNDDAMAGE|SE_TOUCHJUMPPAD|SE_TOUCHTELEPORTER, 0, qfalse); //qtrue);\n\t\t\t\tarea2num = AAS_PointAreaNum(move.endpos);\n\t\t\t\tif (move.stopevent & (SE_ENTERSLIME|SE_ENTERLAVA))\n\t\t\t\t{\n\t\t\t\t\tbotimport.Print(PRT_WARNING, \"teleported into slime or lava at dest %s\\n\", target);\n\t\t\t\t} //end if\n\t\t\t\tVectorCopy(move.endpos, destorigin);\n\t\t\t} //end else\n\t\t} //end if\n\t\t//\n\t\t//botimport.Print(PRT_MESSAGE, \"teleporter brush origin at %f %f %f\\n\", origin[0], origin[1], origin[2]);\n\t\t//botimport.Print(PRT_MESSAGE, \"teleporter brush mins = %f %f %f\\n\", mins[0], mins[1], mins[2]);\n\t\t//botimport.Print(PRT_MESSAGE, \"teleporter brush maxs = %f %f %f\\n\", maxs[0], maxs[1], maxs[2]);\n\t\tVectorAdd(origin, mins, mins);\n\t\tVectorAdd(origin, maxs, maxs);\n\t\t//\n\t\tVectorAdd(mins, maxs, mid);\n\t\tVectorScale(mid, 0.5, mid);\n\t\t//link an invalid (-1) entity\n\t\tareas = AAS_LinkEntityClientBBox(mins, maxs, -1, PRESENCE_CROUCH);\n\t\tif (!areas) botimport.Print(PRT_MESSAGE, \"trigger_multiple not in any area\\n\");\n\t\t//\n\t\tfor (link = areas; link; link = link->next_area)\n\t\t{\n\t\t\t//if (!AAS_AreaGrounded(link->areanum)) continue;\n\t\t\tif (!AAS_AreaTeleporter(link->areanum)) continue;\n\t\t\t//\n\t\t\tarea1num = link->areanum;\n\t\t\t//create a new reachability link\n\t\t\tlreach = AAS_AllocReachability();\n\t\t\tif (!lreach) break;\n\t\t\tlreach->areanum = area2num;\n\t\t\tlreach->facenum = 0;\n\t\t\tlreach->edgenum = 0;\n\t\t\tVectorCopy(mid, lreach->start);\n\t\t\tVectorCopy(destorigin, lreach->end);\n\t\t\tlreach->traveltype = TRAVEL_TELEPORT;\n\t\t\tlreach->traveltype |= AAS_TravelFlagsForTeam(ent);\n\t\t\tlreach->traveltime = aassettings.rs_teleport;\n\t\t\tlreach->next = areareachability[area1num];\n\t\t\tareareachability[area1num] = lreach;\n\t\t\t//\n\t\t\treach_teleport++;\n\t\t} //end for\n\t\t//unlink the invalid entity\n\t\tAAS_UnlinkFromAreas(areas);\n\t} //end for\n} //end of the function AAS_Reachability_Teleport\n//===========================================================================\n// create possible elevator (func_plat) reachabilities\n// this is very game dependent.... :(\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_Reachability_Elevator(void)\n{\n\tint area1num, area2num, modelnum, i, j, k, l, n, p;\n\tfloat lip, height, speed;\n\tchar model[MAX_EPAIRKEY], classname[MAX_EPAIRKEY];\n\tint ent;\n\tvec3_t mins, maxs, origin, angles = {0, 0, 0};\n\tvec3_t pos1, pos2, mids, platbottom, plattop;\n\tvec3_t bottomorg, toporg, start, end, dir;\n\tvec_t xvals[8], yvals[8], xvals_top[8], yvals_top[8];\n\taas_lreachability_t *lreach;\n\taas_trace_t trace;\n\n#ifdef REACH_DEBUG\n\tLog_Write(\"AAS_Reachability_Elevator\\r\\n\");\n#endif //REACH_DEBUG\n\tfor (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent))\n\t{\n\t\tif (!AAS_ValueForBSPEpairKey(ent, \"classname\", classname, MAX_EPAIRKEY)) continue;\n\t\tif (!strcmp(classname, \"func_plat\"))\n\t\t{\n#ifdef REACH_DEBUG\n\t\t\tLog_Write(\"found func plat\\r\\n\");\n#endif //REACH_DEBUG\n\t\t\tif (!AAS_ValueForBSPEpairKey(ent, \"model\", model, MAX_EPAIRKEY))\n\t\t\t{\n\t\t\t\tbotimport.Print(PRT_ERROR, \"func_plat without model\\n\");\n\t\t\t\tcontinue;\n\t\t\t} //end if\n\t\t\t//get the model number, and skip the leading *\n\t\t\tmodelnum = atoi(model+1);\n\t\t\tif (modelnum <= 0)\n\t\t\t{\n\t\t\t\tbotimport.Print(PRT_ERROR, \"func_plat with invalid model number\\n\");\n\t\t\t\tcontinue;\n\t\t\t} //end if\n\t\t\t//get the mins, maxs and origin of the model\n\t\t\t//NOTE: the origin is usually (0,0,0) and the mins and maxs\n\t\t\t//      are the absolute mins and maxs\n\t\t\tAAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, origin);\n\t\t\t//\n\t\t\tAAS_VectorForBSPEpairKey(ent, \"origin\", origin);\n\t\t\t//pos1 is the top position, pos2 is the bottom\n\t\t\tVectorCopy(origin, pos1);\n\t\t\tVectorCopy(origin, pos2);\n\t\t\t//get the lip of the plat\n\t\t\tAAS_FloatForBSPEpairKey(ent, \"lip\", &lip);\n\t\t\tif (!lip) lip = 8;\n\t\t\t//get the movement height of the plat\n\t\t\tAAS_FloatForBSPEpairKey(ent, \"height\", &height);\n\t\t\tif (!height) height = (maxs[2] - mins[2]) - lip;\n\t\t\t//get the speed of the plat\n\t\t\tAAS_FloatForBSPEpairKey(ent, \"speed\", &speed);\n\t\t\tif (!speed) speed = 200;\n\t\t\t//get bottom position below pos1\n\t\t\tpos2[2] -= height;\n\t\t\t//\n\t\t\t//get a point just above the plat in the bottom position\n\t\t\tVectorAdd(mins, maxs, mids);\n\t\t\tVectorMA(pos2, 0.5, mids, platbottom);\n\t\t\tplatbottom[2] = maxs[2] - (pos1[2] - pos2[2]) + 2;\n\t\t\t//get a point just above the plat in the top position\n\t\t\tVectorAdd(mins, maxs, mids);\n\t\t\tVectorMA(pos2, 0.5, mids, plattop);\n\t\t\tplattop[2] = maxs[2] + 2;\n\t\t\t//\n\t\t\t/*if (!area1num)\n\t\t\t{\n\t\t\t\tLog_Write(\"no grounded area near plat bottom\\r\\n\");\n\t\t\t\tcontinue;\n\t\t\t} //end if*/\n\t\t\t//get the mins and maxs a little larger\n\t\t\tfor (i = 0; i < 3; i++)\n\t\t\t{\n\t\t\t\tmins[i] -= 1;\n\t\t\t\tmaxs[i] += 1;\n\t\t\t} //end for\n\t\t\t//\n\t\t\t//botimport.Print(PRT_MESSAGE, \"platbottom[2] = %1.1f plattop[2] = %1.1f\\n\", platbottom[2], plattop[2]);\n\t\t\t//\n\t\t\tVectorAdd(mins, maxs, mids);\n\t\t\tVectorScale(mids, 0.5, mids);\n\t\t\t//\n\t\t\txvals[0] = mins[0]; xvals[1] = mids[0]; xvals[2] = maxs[0]; xvals[3] = mids[0];\n\t\t\tyvals[0] = mids[1]; yvals[1] = maxs[1]; yvals[2] = mids[1]; yvals[3] = mins[1];\n\t\t\t//\n\t\t\txvals[4] = mins[0]; xvals[5] = maxs[0]; xvals[6] = maxs[0]; xvals[7] = mins[0];\n\t\t\tyvals[4] = maxs[1]; yvals[5] = maxs[1]; yvals[6] = mins[1]; yvals[7] = mins[1];\n\t\t\t//find adjacent areas around the bottom of the plat\n\t\t\tfor (i = 0; i < 9; i++)\n\t\t\t{\n\t\t\t\tif (i < 8) //check at the sides of the plat\n\t\t\t\t{\n\t\t\t\t\tbottomorg[0] = origin[0] + xvals[i];\n\t\t\t\t\tbottomorg[1] = origin[1] + yvals[i];\n\t\t\t\t\tbottomorg[2] = platbottom[2] + 16;\n\t\t\t\t\t//get a grounded or swim area near the plat in the bottom position\n\t\t\t\t\tarea1num = AAS_PointAreaNum(bottomorg);\n\t\t\t\t\tfor (k = 0; k < 16; k++)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (area1num)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (AAS_AreaGrounded(area1num) || AAS_AreaSwim(area1num)) break;\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t\tbottomorg[2] += 4;\n\t\t\t\t\t\tarea1num = AAS_PointAreaNum(bottomorg);\n\t\t\t\t\t} //end if\n\t\t\t\t\t//if in solid\n\t\t\t\t\tif (k >= 16)\n\t\t\t\t\t{\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t} //end if\n\t\t\t\t} //end if\n\t\t\t\telse //at the middle of the plat\n\t\t\t\t{\n\t\t\t\t\tVectorCopy(plattop, bottomorg);\n\t\t\t\t\tbottomorg[2] += 24;\n\t\t\t\t\tarea1num = AAS_PointAreaNum(bottomorg);\n\t\t\t\t\tif (!area1num) continue;\n\t\t\t\t\tVectorCopy(platbottom, bottomorg);\n\t\t\t\t\tbottomorg[2] += 24;\n\t\t\t\t} //end else\n\t\t\t\t//look at adjacent areas around the top of the plat\n\t\t\t\t//make larger steps to outside the plat everytime\n\t\t\t\tfor (n = 0; n < 3; n++)\n\t\t\t\t{\n\t\t\t\t\tfor (k = 0; k < 3; k++)\n\t\t\t\t\t{\n\t\t\t\t\t\tmins[k] -= 4;\n\t\t\t\t\t\tmaxs[k] += 4;\n\t\t\t\t\t} //end for\n\t\t\t\t\txvals_top[0] = mins[0]; xvals_top[1] = mids[0]; xvals_top[2] = maxs[0]; xvals_top[3] = mids[0];\n\t\t\t\t\tyvals_top[0] = mids[1]; yvals_top[1] = maxs[1]; yvals_top[2] = mids[1]; yvals_top[3] = mins[1];\n\t\t\t\t\t//\n\t\t\t\t\txvals_top[4] = mins[0]; xvals_top[5] = maxs[0]; xvals_top[6] = maxs[0]; xvals_top[7] = mins[0];\n\t\t\t\t\tyvals_top[4] = maxs[1]; yvals_top[5] = maxs[1]; yvals_top[6] = mins[1]; yvals_top[7] = mins[1];\n\t\t\t\t\t//\n\t\t\t\t\tfor (j = 0; j < 8; j++)\n\t\t\t\t\t{\n\t\t\t\t\t\ttoporg[0] = origin[0] + xvals_top[j];\n\t\t\t\t\t\ttoporg[1] = origin[1] + yvals_top[j];\n\t\t\t\t\t\ttoporg[2] = plattop[2] + 16;\n\t\t\t\t\t\t//get a grounded or swim area near the plat in the top position\n\t\t\t\t\t\tarea2num = AAS_PointAreaNum(toporg);\n\t\t\t\t\t\tfor (l = 0; l < 16; l++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (area2num)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (AAS_AreaGrounded(area2num) || AAS_AreaSwim(area2num))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tVectorCopy(plattop, start);\n\t\t\t\t\t\t\t\t\tstart[2] += 32;\n\t\t\t\t\t\t\t\t\tVectorCopy(toporg, end);\n\t\t\t\t\t\t\t\t\tend[2] += 1;\n\t\t\t\t\t\t\t\t\ttrace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, -1);\n\t\t\t\t\t\t\t\t\tif (trace.fraction >= 1) break;\n\t\t\t\t\t\t\t\t} //end if\n\t\t\t\t\t\t\t} //end if\n\t\t\t\t\t\t\ttoporg[2] += 4;\n\t\t\t\t\t\t\tarea2num = AAS_PointAreaNum(toporg);\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t\t//if in solid\n\t\t\t\t\t\tif (l >= 16) continue;\n\t\t\t\t\t\t//never create a reachability in the same area\n\t\t\t\t\t\tif (area2num == area1num) continue;\n\t\t\t\t\t\t//if the area isn't grounded\n\t\t\t\t\t\tif (!AAS_AreaGrounded(area2num)) continue;\n\t\t\t\t\t\t//if there already exists reachability between the areas\n\t\t\t\t\t\tif (AAS_ReachabilityExists(area1num, area2num)) continue;\n\t\t\t\t\t\t//if the reachability start is within the elevator bounding box\n\t\t\t\t\t\tVectorSubtract(bottomorg, platbottom, dir);\n\t\t\t\t\t\tVectorNormalize(dir);\n\t\t\t\t\t\tdir[0] = bottomorg[0] + 24 * dir[0];\n\t\t\t\t\t\tdir[1] = bottomorg[1] + 24 * dir[1];\n\t\t\t\t\t\tdir[2] = bottomorg[2];\n\t\t\t\t\t\t//\n\t\t\t\t\t\tfor (p = 0; p < 3; p++)\n\t\t\t\t\t\t\tif (dir[p] < origin[p] + mins[p] || dir[p] > origin[p] + maxs[p]) break;\n\t\t\t\t\t\tif (p >= 3) continue;\n\t\t\t\t\t\t//create a new reachability link\n\t\t\t\t\t\tlreach = AAS_AllocReachability();\n\t\t\t\t\t\tif (!lreach) continue;\n\t\t\t\t\t\tlreach->areanum = area2num;\n\t\t\t\t\t\t//the facenum is the model number\n\t\t\t\t\t\tlreach->facenum = modelnum;\n\t\t\t\t\t\t//the edgenum is the height\n\t\t\t\t\t\tlreach->edgenum = (int) height;\n\t\t\t\t\t\t//\n\t\t\t\t\t\tVectorCopy(dir, lreach->start);\n\t\t\t\t\t\tVectorCopy(toporg, lreach->end);\n\t\t\t\t\t\tlreach->traveltype = TRAVEL_ELEVATOR;\n\t\t\t\t\t\tlreach->traveltype |= AAS_TravelFlagsForTeam(ent);\n\t\t\t\t\t\tlreach->traveltime = aassettings.rs_startelevator + height * 100 / speed;\n\t\t\t\t\t\tlreach->next = areareachability[area1num];\n\t\t\t\t\t\tareareachability[area1num] = lreach;\n\t\t\t\t\t\t//don't go any further to the outside\n\t\t\t\t\t\tn = 9999;\n\t\t\t\t\t\t//\n#ifdef REACH_DEBUG\n\t\t\t\t\t\tLog_Write(\"elevator reach from %d to %d\\r\\n\", area1num, area2num);\n#endif //REACH_DEBUG\n\t\t\t\t\t\t//\n\t\t\t\t\t\treach_elevator++;\n\t\t\t\t\t} //end for\n\t\t\t\t} //end for\n\t\t\t} //end for\n\t\t} //end if\n\t} //end for\n} //end of the function AAS_Reachability_Elevator\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\naas_lreachability_t *AAS_FindFaceReachabilities(vec3_t *facepoints, int numpoints, aas_plane_t *plane, int towardsface)\n{\n\tint i, j, k, l;\n\tint facenum, edgenum, bestfacenum;\n\tfloat *v1, *v2, *v3, *v4;\n\tfloat bestdist, speed, hordist, dist;\n\tvec3_t beststart, beststart2, bestend, bestend2, tmp, hordir, testpoint;\n\taas_lreachability_t *lreach, *lreachabilities;\n\taas_area_t *area;\n\taas_face_t *face;\n\taas_edge_t *edge;\n\taas_plane_t *faceplane, *bestfaceplane;\n\n\t//\n\tlreachabilities = NULL;\n\tbestfacenum = 0;\n\tbestfaceplane = NULL;\n\t//\n\tfor (i = 1; i < aasworld.numareas; i++)\n\t{\n\t\tarea = &aasworld.areas[i];\n\t\t// get the shortest distance between one of the func_bob start edges and\n\t\t// one of the face edges of area1\n\t\tbestdist = 999999;\n\t\tfor (j = 0; j < area->numfaces; j++)\n\t\t{\n\t\t\tfacenum = aasworld.faceindex[area->firstface + j];\n\t\t\tface = &aasworld.faces[abs(facenum)];\n\t\t\t//if not a ground face\n\t\t\tif (!(face->faceflags & FACE_GROUND)) continue;\n\t\t\t//get the ground planes\n\t\t\tfaceplane = &aasworld.planes[face->planenum];\n\t\t\t//\n\t\t\tfor (k = 0; k < face->numedges; k++)\n\t\t\t{\n\t\t\t\tedgenum = abs(aasworld.edgeindex[face->firstedge + k]);\n\t\t\t\tedge = &aasworld.edges[edgenum];\n\t\t\t\t//calculate the minimum distance between the two edges\n\t\t\t\tv1 = aasworld.vertexes[edge->v[0]];\n\t\t\t\tv2 = aasworld.vertexes[edge->v[1]];\n\t\t\t\t//\n\t\t\t\tfor (l = 0; l < numpoints; l++)\n\t\t\t\t{\n\t\t\t\t\tv3 = facepoints[l];\n\t\t\t\t\tv4 = facepoints[(l+1) % numpoints];\n\t\t\t\t\tdist = AAS_ClosestEdgePoints(v1, v2, v3, v4, faceplane, plane,\n\t\t\t\t\t\t\t\t\t\t\t\t\tbeststart, bestend,\n\t\t\t\t\t\t\t\t\t\t\t\t\tbeststart2, bestend2, bestdist);\n\t\t\t\t\tif (dist < bestdist)\n\t\t\t\t\t{\n\t\t\t\t\t\tbestfacenum = facenum;\n\t\t\t\t\t\tbestfaceplane = faceplane;\n\t\t\t\t\t\tbestdist = dist;\n\t\t\t\t\t} //end if\n\t\t\t\t} //end for\n\t\t\t} //end for\n\t\t} //end for\n\t\t//\n\t\tif (bestdist > 192) continue;\n\t\t//\n\t\tVectorMiddle(beststart, beststart2, beststart);\n\t\tVectorMiddle(bestend, bestend2, bestend);\n\t\t//\n\t\tif (!towardsface)\n\t\t{\n\t\t\tVectorCopy(beststart, tmp);\n\t\t\tVectorCopy(bestend, beststart);\n\t\t\tVectorCopy(tmp, bestend);\n\t\t} //end if\n\t\t//\n\t\tVectorSubtract(bestend, beststart, hordir);\n\t\thordir[2] = 0;\n\t\thordist = VectorLength(hordir);\n\t\t//\n\t\tif (hordist > 2 * AAS_MaxJumpDistance(aassettings.phys_jumpvel)) continue;\n\t\t//the end point should not be significantly higher than the start point\n\t\tif (bestend[2] - 32 > beststart[2]) continue;\n\t\t//don't fall down too far\n\t\tif (bestend[2] < beststart[2] - 128) continue;\n\t\t//the distance should not be too far\n\t\tif (hordist > 32)\n\t\t{\n\t\t\t//check for walk off ledge\n\t\t\tif (!AAS_HorizontalVelocityForJump(0, beststart, bestend, &speed)) continue;\n\t\t} //end if\n\t\t//\n\t\tbeststart[2] += 1;\n\t\tbestend[2] += 1;\n\t\t//\n\t\tif (towardsface) VectorCopy(bestend, testpoint);\n\t\telse VectorCopy(beststart, testpoint);\n\t\ttestpoint[2] = 0;\n\t\ttestpoint[2] = (bestfaceplane->dist - DotProduct(bestfaceplane->normal, testpoint)) / bestfaceplane->normal[2];\n\t\t//\n\t\tif (!AAS_PointInsideFace(bestfacenum, testpoint, 0.1f))\n\t\t{\n\t\t\t//if the faces are not overlapping then only go down\n\t\t\tif (bestend[2] - 16 > beststart[2]) continue;\n\t\t} //end if\n\t\tlreach = AAS_AllocReachability();\n\t\tif (!lreach) return lreachabilities;\n\t\tlreach->areanum = i;\n\t\tlreach->facenum = 0;\n\t\tlreach->edgenum = 0;\n\t\tVectorCopy(beststart, lreach->start);\n\t\tVectorCopy(bestend, lreach->end);\n\t\tlreach->traveltype = 0;\n\t\tlreach->traveltime = 0;\n\t\tlreach->next = lreachabilities;\n\t\tlreachabilities = lreach;\n#ifndef BSPC\n\t\tif (towardsface) AAS_PermanentLine(lreach->start, lreach->end, 1);\n\t\telse AAS_PermanentLine(lreach->start, lreach->end, 2);\n#endif\n\t} //end for\n\treturn lreachabilities;\n} //end of the function AAS_FindFaceReachabilities\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_Reachability_FuncBobbing(void)\n{\n\tint ent, spawnflags, modelnum, axis;\n\tint i, numareas, areas[10];\n\tchar classname[MAX_EPAIRKEY], model[MAX_EPAIRKEY];\n\tvec3_t origin, move_end, move_start, move_start_top, move_end_top;\n\tvec3_t mins, maxs, angles = {0, 0, 0};\n\tvec3_t start_edgeverts[4], end_edgeverts[4], mid;\n\tvec3_t org, start, end, dir, points[10];\n\tfloat height;\n\taas_plane_t start_plane, end_plane;\n\taas_lreachability_t *startreach, *endreach, *nextstartreach, *nextendreach, *lreach;\n\taas_lreachability_t *firststartreach, *firstendreach;\n\n\tfor (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent))\n\t{\n\t\tif (!AAS_ValueForBSPEpairKey(ent, \"classname\", classname, MAX_EPAIRKEY)) continue;\n\t\tif (strcmp(classname, \"func_bobbing\")) continue;\n\t\tAAS_FloatForBSPEpairKey(ent, \"height\", &height);\n\t\tif (!height) height = 32;\n\t\t//\n\t\tif (!AAS_ValueForBSPEpairKey(ent, \"model\", model, MAX_EPAIRKEY))\n\t\t{\n\t\t\tbotimport.Print(PRT_ERROR, \"func_bobbing without model\\n\");\n\t\t\tcontinue;\n\t\t} //end if\n\t\t//get the model number, and skip the leading *\n\t\tmodelnum = atoi(model+1);\n\t\tif (modelnum <= 0)\n\t\t{\n\t\t\tbotimport.Print(PRT_ERROR, \"func_bobbing with invalid model number\\n\");\n\t\t\tcontinue;\n\t\t} //end if\n\t\t//if the entity has an origin set then use it\n\t\tif (!AAS_VectorForBSPEpairKey(ent, \"origin\", origin))\n\t\t\tVectorSet(origin, 0, 0, 0);\n\t\t//\n\t\tAAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, NULL);\n\t\t//\n\t\tVectorAdd(mins, origin, mins);\n\t\tVectorAdd(maxs, origin, maxs);\n\t\t//\n\t\tVectorAdd(mins, maxs, mid);\n\t\tVectorScale(mid, 0.5, mid);\n\t\tVectorCopy(mid, origin);\n\t\t//\n\t\tVectorCopy(origin, move_end);\n\t\tVectorCopy(origin, move_start);\n\t\t//\n\t\tAAS_IntForBSPEpairKey(ent, \"spawnflags\", &spawnflags);\n\t\t// set the axis of bobbing\n\t\tif (spawnflags & 1) axis = 0;\n\t\telse if (spawnflags & 2) axis = 1;\n\t\telse axis = 2;\n\t\t//\n\t\tmove_start[axis] -= height;\n\t\tmove_end[axis] += height;\n\t\t//\n\t\tLog_Write(\"funcbob model %d, start = {%1.1f, %1.1f, %1.1f} end = {%1.1f, %1.1f, %1.1f}\\n\",\n\t\t\t\t\tmodelnum, move_start[0], move_start[1], move_start[2], move_end[0], move_end[1], move_end[2]);\n\t\t//\n#ifndef BSPC\n\t\t/*\n\t\tAAS_DrawPermanentCross(move_start, 4, 1);\n\t\tAAS_DrawPermanentCross(move_end, 4, 2);\n\t\t*/\n#endif\n\t\t//\n\t\tfor (i = 0; i < 4; i++)\n\t\t{\n\t\t\tVectorCopy(move_start, start_edgeverts[i]);\n\t\t\tstart_edgeverts[i][2] += maxs[2] - mid[2]; //+ bbox maxs z\n\t\t\tstart_edgeverts[i][2] += 24;\t//+ player origin to ground dist\n\t\t} //end for\n\t\tstart_edgeverts[0][0] += maxs[0] - mid[0];\n\t\tstart_edgeverts[0][1] += maxs[1] - mid[1];\n\t\tstart_edgeverts[1][0] += maxs[0] - mid[0];\n\t\tstart_edgeverts[1][1] += mins[1] - mid[1];\n\t\tstart_edgeverts[2][0] += mins[0] - mid[0];\n\t\tstart_edgeverts[2][1] += mins[1] - mid[1];\n\t\tstart_edgeverts[3][0] += mins[0] - mid[0];\n\t\tstart_edgeverts[3][1] += maxs[1] - mid[1];\n\t\t//\n\t\tstart_plane.dist = start_edgeverts[0][2];\n\t\tVectorSet(start_plane.normal, 0, 0, 1);\n\t\t//\n\t\tfor (i = 0; i < 4; i++)\n\t\t{\n\t\t\tVectorCopy(move_end, end_edgeverts[i]);\n\t\t\tend_edgeverts[i][2] += maxs[2] - mid[2]; //+ bbox maxs z\n\t\t\tend_edgeverts[i][2] += 24;\t//+ player origin to ground dist\n\t\t} //end for\n\t\tend_edgeverts[0][0] += maxs[0] - mid[0];\n\t\tend_edgeverts[0][1] += maxs[1] - mid[1];\n\t\tend_edgeverts[1][0] += maxs[0] - mid[0];\n\t\tend_edgeverts[1][1] += mins[1] - mid[1];\n\t\tend_edgeverts[2][0] += mins[0] - mid[0];\n\t\tend_edgeverts[2][1] += mins[1] - mid[1];\n\t\tend_edgeverts[3][0] += mins[0] - mid[0];\n\t\tend_edgeverts[3][1] += maxs[1] - mid[1];\n\t\t//\n\t\tend_plane.dist = end_edgeverts[0][2];\n\t\tVectorSet(end_plane.normal, 0, 0, 1);\n\t\t//\n#ifndef BSPC\n#if 0\n\t\tfor (i = 0; i < 4; i++)\n\t\t{\n\t\t\tAAS_PermanentLine(start_edgeverts[i], start_edgeverts[(i+1)%4], 1);\n\t\t\tAAS_PermanentLine(end_edgeverts[i], end_edgeverts[(i+1)%4], 1);\n\t\t} //end for\n#endif\n#endif\n\t\tVectorCopy(move_start, move_start_top);\n\t\tmove_start_top[2] += maxs[2] - mid[2] + 24; //+ bbox maxs z\n\t\tVectorCopy(move_end, move_end_top);\n\t\tmove_end_top[2] += maxs[2] - mid[2] + 24; //+ bbox maxs z\n\t\t//\n\t\tif (!AAS_PointAreaNum(move_start_top)) continue;\n\t\tif (!AAS_PointAreaNum(move_end_top)) continue;\n\t\t//\n\t\tfor (i = 0; i < 2; i++)\n\t\t{\n\t\t\tfirststartreach = firstendreach = NULL;\n\t\t\t//\n\t\t\tif (i == 0)\n\t\t\t{\n\t\t\t\tfirststartreach = AAS_FindFaceReachabilities(start_edgeverts, 4, &start_plane, qtrue);\n\t\t\t\tfirstendreach = AAS_FindFaceReachabilities(end_edgeverts, 4, &end_plane, qfalse);\n\t\t\t} //end if\n\t\t\telse\n\t\t\t{\n\t\t\t\tfirststartreach = AAS_FindFaceReachabilities(end_edgeverts, 4, &end_plane, qtrue);\n\t\t\t\tfirstendreach = AAS_FindFaceReachabilities(start_edgeverts, 4, &start_plane, qfalse);\n\t\t\t} //end else\n\t\t\t//\n\t\t\t//create reachabilities from start to end\n\t\t\tfor (startreach = firststartreach; startreach; startreach = nextstartreach)\n\t\t\t{\n\t\t\t\tnextstartreach = startreach->next;\n\t\t\t\t//\n\t\t\t\t//trace = AAS_TraceClientBBox(startreach->start, move_start_top, PRESENCE_NORMAL, -1);\n\t\t\t\t//if (trace.fraction < 1) continue;\n\t\t\t\t//\n\t\t\t\tfor (endreach = firstendreach; endreach; endreach = nextendreach)\n\t\t\t\t{\n\t\t\t\t\tnextendreach = endreach->next;\n\t\t\t\t\t//\n\t\t\t\t\t//trace = AAS_TraceClientBBox(endreach->end, move_end_top, PRESENCE_NORMAL, -1);\n\t\t\t\t\t//if (trace.fraction < 1) continue;\n\t\t\t\t\t//\n\t\t\t\t\tLog_Write(\"funcbob reach from area %d to %d\\n\", startreach->areanum, endreach->areanum);\n\t\t\t\t\t//\n\t\t\t\t\t//\n\t\t\t\t\tif (i == 0) VectorCopy(move_start_top, org);\n\t\t\t\t\telse VectorCopy(move_end_top, org);\n\t\t\t\t\tVectorSubtract(startreach->start, org, dir);\n\t\t\t\t\tdir[2] = 0;\n\t\t\t\t\tVectorNormalize(dir);\n\t\t\t\t\tVectorCopy(startreach->start, start);\n\t\t\t\t\tVectorMA(startreach->start, 1, dir, start);\n\t\t\t\t\tstart[2] += 1;\n\t\t\t\t\tVectorMA(startreach->start, 16, dir, end);\n\t\t\t\t\tend[2] += 1;\n\t\t\t\t\t//\n\t\t\t\t\tnumareas = AAS_TraceAreas(start, end, areas, points, 10);\n\t\t\t\t\tif (numareas <= 0) continue;\n\t\t\t\t\tif (numareas > 1) VectorCopy(points[1], startreach->start);\n\t\t\t\t\telse VectorCopy(end, startreach->start);\n\t\t\t\t\t//\n\t\t\t\t\tif (!AAS_PointAreaNum(startreach->start)) continue;\n\t\t\t\t\tif (!AAS_PointAreaNum(endreach->end)) continue;\n\t\t\t\t\t//\n\t\t\t\t\tlreach = AAS_AllocReachability();\n\t\t\t\t\tlreach->areanum = endreach->areanum;\n\t\t\t\t\tif (i == 0) lreach->edgenum = ((int)move_start[axis] << 16) | ((int) move_end[axis] & 0x0000ffff);\n\t\t\t\t\telse lreach->edgenum = ((int)move_end[axis] << 16) | ((int) move_start[axis] & 0x0000ffff);\n\t\t\t\t\tlreach->facenum = (spawnflags << 16) | modelnum;\n\t\t\t\t\tVectorCopy(startreach->start, lreach->start);\n\t\t\t\t\tVectorCopy(endreach->end, lreach->end);\n#ifndef BSPC\n//\t\t\t\t\tAAS_DrawArrow(lreach->start, lreach->end, LINECOLOR_BLUE, LINECOLOR_YELLOW);\n//\t\t\t\t\tAAS_PermanentLine(lreach->start, lreach->end, 1);\n#endif\n\t\t\t\t\tlreach->traveltype = TRAVEL_FUNCBOB;\n\t\t\t\t\tlreach->traveltype |= AAS_TravelFlagsForTeam(ent);\n\t\t\t\t\tlreach->traveltime = aassettings.rs_funcbob;\n\t\t\t\t\treach_funcbob++;\n\t\t\t\t\tlreach->next = areareachability[startreach->areanum];\n\t\t\t\t\tareareachability[startreach->areanum] = lreach;\n\t\t\t\t\t//\n\t\t\t\t} //end for\n\t\t\t} //end for\n\t\t\tfor (startreach = firststartreach; startreach; startreach = nextstartreach)\n\t\t\t{\n\t\t\t\tnextstartreach = startreach->next;\n\t\t\t\tAAS_FreeReachability(startreach);\n\t\t\t} //end for\n\t\t\tfor (endreach = firstendreach; endreach; endreach = nextendreach)\n\t\t\t{\n\t\t\t\tnextendreach = endreach->next;\n\t\t\t\tAAS_FreeReachability(endreach);\n\t\t\t} //end for\n\t\t\t//only go up with func_bobbing entities that go up and down\n\t\t\tif (!(spawnflags & 1) && !(spawnflags & 2)) break;\n\t\t} //end for\n\t} //end for\n} //end of the function AAS_Reachability_FuncBobbing\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_Reachability_JumpPad(void)\n{\n\tint face2num, i, ret, area2num, visualize, ent, bot_visualizejumppads;\n\t//int modelnum, ent2;\n\t//float dist, time, height, gravity, forward;\n\tfloat speed, zvel, hordist;\n\taas_face_t *face2;\n\taas_area_t *area2;\n\taas_lreachability_t *lreach;\n\tvec3_t areastart, facecenter, dir, cmdmove;\n\tvec3_t velocity, absmins, absmaxs;\n\t//vec3_t origin, ent2origin, angles, teststart;\n\taas_clientmove_t move;\n\t//aas_trace_t trace;\n\taas_link_t *areas, *link;\n\t//char target[MAX_EPAIRKEY], targetname[MAX_EPAIRKEY], model[MAX_EPAIRKEY];\n\tchar classname[MAX_EPAIRKEY];\n\n#ifdef BSPC\n\tbot_visualizejumppads = 0;\n#else\n\tbot_visualizejumppads = LibVarValue(\"bot_visualizejumppads\", \"0\");\n#endif\n\tfor (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent))\n\t{\n\t\tif (!AAS_ValueForBSPEpairKey(ent, \"classname\", classname, MAX_EPAIRKEY)) continue;\n\t\tif (strcmp(classname, \"trigger_push\")) continue;\n\t\t//\n\t\tif (!AAS_GetJumpPadInfo(ent, areastart, absmins, absmaxs, velocity)) continue;\n\t\t/*\n\t\t//\n\t\tAAS_FloatForBSPEpairKey(ent, \"speed\", &speed);\n\t\tif (!speed) speed = 1000;\n//\t\tAAS_VectorForBSPEpairKey(ent, \"angles\", angles);\n//\t\tAAS_SetMovedir(angles, velocity);\n//\t\tVectorScale(velocity, speed, velocity);\n\t\tVectorClear(angles);\n\t\t//get the mins, maxs and origin of the model\n\t\tAAS_ValueForBSPEpairKey(ent, \"model\", model, MAX_EPAIRKEY);\n\t\tif (model[0]) modelnum = atoi(model+1);\n\t\telse modelnum = 0;\n\t\tAAS_BSPModelMinsMaxsOrigin(modelnum, angles, absmins, absmaxs, origin);\n\t\tVectorAdd(origin, absmins, absmins);\n\t\tVectorAdd(origin, absmaxs, absmaxs);\n\t\t//\n#ifdef REACH_DEBUG\n\t\tbotimport.Print(PRT_MESSAGE, \"absmins = %f %f %f\\n\", absmins[0], absmins[1], absmins[2]);\n\t\tbotimport.Print(PRT_MESSAGE, \"absmaxs = %f %f %f\\n\", absmaxs[0], absmaxs[1], absmaxs[2]);\n#endif REACH_DEBUG\n\t\tVectorAdd(absmins, absmaxs, origin);\n\t\tVectorScale (origin, 0.5, origin);\n\n\t\t//get the start areas\n\t\tVectorCopy(origin, teststart);\n\t\tteststart[2] += 64;\n\t\ttrace = AAS_TraceClientBBox(teststart, origin, PRESENCE_CROUCH, -1);\n\t\tif (trace.startsolid)\n\t\t{\n\t\t\tbotimport.Print(PRT_MESSAGE, \"trigger_push start solid\\n\");\n\t\t\tVectorCopy(origin, areastart);\n\t\t} //end if\n\t\telse\n\t\t{\n\t\t\tVectorCopy(trace.endpos, areastart);\n\t\t} //end else\n\t\tareastart[2] += 0.125;\n\t\t//\n\t\t//AAS_DrawPermanentCross(origin, 4, 4);\n\t\t//get the target entity\n\t\tAAS_ValueForBSPEpairKey(ent, \"target\", target, MAX_EPAIRKEY);\n\t\tfor (ent2 = AAS_NextBSPEntity(0); ent2; ent2 = AAS_NextBSPEntity(ent2))\n\t\t{\n\t\t\tif (!AAS_ValueForBSPEpairKey(ent2, \"targetname\", targetname, MAX_EPAIRKEY)) continue;\n\t\t\tif (!strcmp(targetname, target)) break;\n\t\t} //end for\n\t\tif (!ent2)\n\t\t{\n\t\t\tbotimport.Print(PRT_MESSAGE, \"trigger_push without target entity %s\\n\", target);\n\t\t\tcontinue;\n\t\t} //end if\n\t\tAAS_VectorForBSPEpairKey(ent2, \"origin\", ent2origin);\n\t\t//\n\t\theight = ent2origin[2] - origin[2];\n\t\tgravity = aassettings.sv_gravity;\n\t\ttime = sqrt( height / ( 0.5 * gravity ) );\n\t\tif (!time)\n\t\t{\n\t\t\tbotimport.Print(PRT_MESSAGE, \"trigger_push without time\\n\");\n\t\t\tcontinue;\n\t\t} //end if\n\t\t// set s.origin2 to the push velocity\n\t\tVectorSubtract ( ent2origin, origin, velocity);\n\t\tdist = VectorNormalize( velocity);\n\t\tforward = dist / time;\n\t\t//FIXME: why multiply by 1.1\n\t\tforward *= 1.1;\n\t\tVectorScale(velocity, forward, velocity);\n\t\tvelocity[2] = time * gravity;\n\t\t*/\n\t\t//get the areas the jump pad brush is in\n\t\tareas = AAS_LinkEntityClientBBox(absmins, absmaxs, -1, PRESENCE_CROUCH);\n\t\t/*\n\t\tfor (link = areas; link; link = link->next_area)\n\t\t{\n\t\t\tif (link->areanum == 563)\n\t\t\t{\n\t\t\t\tret = qfalse;\n\t\t\t}\n\t\t}\n        */\n\t\tfor (link = areas; link; link = link->next_area)\n\t\t{\n\t\t\tif (AAS_AreaJumpPad(link->areanum)) break;\n\t\t} //end for\n\t\tif (!link)\n\t\t{\n\t\t\tbotimport.Print(PRT_MESSAGE, \"trigger_push not in any jump pad area\\n\");\n\t\t\tAAS_UnlinkFromAreas(areas);\n\t\t\tcontinue;\n\t\t} //end if\n\t\t//\n\t\tbotimport.Print(PRT_MESSAGE, \"found a trigger_push with velocity %f %f %f\\n\", velocity[0], velocity[1], velocity[2]);\n\t\t//if there is a horizontal velocity check for a reachability without air control\n\t\tif (velocity[0] || velocity[1])\n\t\t{\n\t\t\tVectorSet(cmdmove, 0, 0, 0);\n\t\t\t//VectorCopy(velocity, cmdmove);\n\t\t\t//cmdmove[2] = 0;\n\t\t\tCom_Memset(&move, 0, sizeof(aas_clientmove_t));\n\t\t\tarea2num = 0;\n\t\t\tfor (i = 0; i < 20; i++)\n\t\t\t{\n\t\t\t\tAAS_PredictClientMovement(&move, -1, areastart, PRESENCE_NORMAL, qfalse,\n\t\t\t\t\t\t\t\t\t\tvelocity, cmdmove, 0, 30, 0.1f,\n\t\t\t\t\t\t\t\t\t\tSE_HITGROUND|SE_ENTERWATER|SE_ENTERSLIME|\n\t\t\t\t\t\t\t\t\t\tSE_ENTERLAVA|SE_HITGROUNDDAMAGE|SE_TOUCHJUMPPAD|SE_TOUCHTELEPORTER, 0, bot_visualizejumppads);\n\t\t\t\tarea2num = move.endarea;\n\t\t\t\tfor (link = areas; link; link = link->next_area)\n\t\t\t\t{\n\t\t\t\t\tif (!AAS_AreaJumpPad(link->areanum)) continue;\n\t\t\t\t\tif (link->areanum == area2num) break;\n\t\t\t\t} //end if\n\t\t\t\tif (!link) break;\n\t\t\t\tVectorCopy(move.endpos, areastart);\n\t\t\t\tVectorCopy(move.velocity, velocity);\n\t\t\t} //end for\n\t\t\tif (area2num && i < 20)\n\t\t\t{\n\t\t\t\tfor (link = areas; link; link = link->next_area)\n\t\t\t\t{\n\t\t\t\t\tif (!AAS_AreaJumpPad(link->areanum)) continue;\n\t\t\t\t\tif (AAS_ReachabilityExists(link->areanum, area2num)) continue;\n\t\t\t\t\t//create a rocket or bfg jump reachability from area1 to area2\n\t\t\t\t\tlreach = AAS_AllocReachability();\n\t\t\t\t\tif (!lreach)\n\t\t\t\t\t{\n\t\t\t\t\t\tAAS_UnlinkFromAreas(areas);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t} //end if\n\t\t\t\t\tlreach->areanum = area2num;\n\t\t\t\t\t//NOTE: the facenum is the Z velocity\n\t\t\t\t\tlreach->facenum = velocity[2];\n\t\t\t\t\t//NOTE: the edgenum is the horizontal velocity\n\t\t\t\t\tlreach->edgenum = sqrt(velocity[0] * velocity[0] + velocity[1] * velocity[1]);\n\t\t\t\t\tVectorCopy(areastart, lreach->start);\n\t\t\t\t\tVectorCopy(move.endpos, lreach->end);\n\t\t\t\t\tlreach->traveltype = TRAVEL_JUMPPAD;\n\t\t\t\t\tlreach->traveltype |= AAS_TravelFlagsForTeam(ent);\n\t\t\t\t\tlreach->traveltime = aassettings.rs_jumppad;\n\t\t\t\t\tlreach->next = areareachability[link->areanum];\n\t\t\t\t\tareareachability[link->areanum] = lreach;\n\t\t\t\t\t//\n\t\t\t\t\treach_jumppad++;\n\t\t\t\t} //end for\n\t\t\t} //end if\n\t\t} //end if\n\t\t//\n\t\tif (fabs(velocity[0]) > 100 || fabs(velocity[1]) > 100) continue;\n\t\t//check for areas we can reach with air control\n\t\tfor (area2num = 1; area2num < aasworld.numareas; area2num++)\n\t\t{\n\t\t\tvisualize = qfalse;\n\t\t\t/*\n\t\t\tif (area2num == 3568)\n\t\t\t{\n\t\t\t\tfor (link = areas; link; link = link->next_area)\n\t\t\t\t{\n\t\t\t\t\tif (link->areanum == 3380)\n\t\t\t\t\t{\n\t\t\t\t\t\tvisualize = qtrue;\n\t\t\t\t\t\tbotimport.Print(PRT_MESSAGE, \"bah\\n\");\n\t\t\t\t\t} //end if\n\t\t\t\t} //end for\n\t\t\t} //end if*/\n\t\t\t//never try to go back to one of the original jumppad areas\n\t\t\t//and don't create reachabilities if they already exist\n\t\t\tfor (link = areas; link; link = link->next_area)\n\t\t\t{\n\t\t\t\tif (AAS_ReachabilityExists(link->areanum, area2num)) break;\n\t\t\t\tif (AAS_AreaJumpPad(link->areanum))\n\t\t\t\t{\n\t\t\t\t\tif (link->areanum == area2num) break;\n\t\t\t\t} //end if\n\t\t\t} //end if\n\t\t\tif (link) continue;\n\t\t\t//\n\t\t\tarea2 = &aasworld.areas[area2num];\n\t\t\tfor (i = 0; i < area2->numfaces; i++)\n\t\t\t{\n\t\t\t\tface2num = aasworld.faceindex[area2->firstface + i];\n\t\t\t\tface2 = &aasworld.faces[abs(face2num)];\n\t\t\t\t//if it is not a ground face\n\t\t\t\tif (!(face2->faceflags & FACE_GROUND)) continue;\n\t\t\t\t//get the center of the face\n\t\t\t\tAAS_FaceCenter(face2num, facecenter);\n\t\t\t\t//only go higher up\n\t\t\t\tif (facecenter[2] < areastart[2]) continue;\n\t\t\t\t//get the jumppad jump z velocity\n\t\t\t\tzvel = velocity[2];\n\t\t\t\t//get the horizontal speed for the jump, if it isn't possible to calculate this\n\t\t\t\t//speed\n\t\t\t\tret = AAS_HorizontalVelocityForJump(zvel, areastart, facecenter, &speed);\n\t\t\t\tif (ret && speed < 150)\n\t\t\t\t{\n\t\t\t\t\t//direction towards the face center\n\t\t\t\t\tVectorSubtract(facecenter, areastart, dir);\n\t\t\t\t\tdir[2] = 0;\n\t\t\t\t\thordist = VectorNormalize(dir);\n\t\t\t\t\t//if (hordist < 1.6 * facecenter[2] - areastart[2])\n\t\t\t\t\t{\n\t\t\t\t\t\t//get command movement\n\t\t\t\t\t\tVectorScale(dir, speed, cmdmove);\n\t\t\t\t\t\t//\n\t\t\t\t\t\tAAS_PredictClientMovement(&move, -1, areastart, PRESENCE_NORMAL, qfalse,\n\t\t\t\t\t\t\t\t\t\t\t\t\tvelocity, cmdmove, 30, 30, 0.1f,\n\t\t\t\t\t\t\t\t\t\t\t\t\tSE_ENTERWATER|SE_ENTERSLIME|\n\t\t\t\t\t\t\t\t\t\t\t\t\tSE_ENTERLAVA|SE_HITGROUNDDAMAGE|\n\t\t\t\t\t\t\t\t\t\t\t\t\tSE_TOUCHJUMPPAD|SE_TOUCHTELEPORTER|SE_HITGROUNDAREA, area2num, visualize);\n\t\t\t\t\t\t//if prediction time wasn't enough to fully predict the movement\n\t\t\t\t\t\t//don't enter slime or lava and don't fall from too high\n\t\t\t\t\t\tif (move.frames < 30 && \n\t\t\t\t\t\t\t\t!(move.stopevent & (SE_ENTERSLIME|SE_ENTERLAVA|SE_HITGROUNDDAMAGE))\n\t\t\t\t\t\t\t\t&& (move.stopevent & (SE_HITGROUNDAREA|SE_TOUCHJUMPPAD|SE_TOUCHTELEPORTER)))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t//never go back to the same jumppad\n\t\t\t\t\t\t\tfor (link = areas; link; link = link->next_area)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (link->areanum == move.endarea) break;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (!link)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfor (link = areas; link; link = link->next_area)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tif (!AAS_AreaJumpPad(link->areanum)) continue;\n\t\t\t\t\t\t\t\t\tif (AAS_ReachabilityExists(link->areanum, area2num)) continue;\n\t\t\t\t\t\t\t\t\t//create a jumppad reachability from area1 to area2\n\t\t\t\t\t\t\t\t\tlreach = AAS_AllocReachability();\n\t\t\t\t\t\t\t\t\tif (!lreach)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tAAS_UnlinkFromAreas(areas);\n\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t} //end if\n\t\t\t\t\t\t\t\t\tlreach->areanum = move.endarea;\n\t\t\t\t\t\t\t\t\t//NOTE: the facenum is the Z velocity\n\t\t\t\t\t\t\t\t\tlreach->facenum = velocity[2];\n\t\t\t\t\t\t\t\t\t//NOTE: the edgenum is the horizontal velocity\n\t\t\t\t\t\t\t\t\tlreach->edgenum = sqrt(cmdmove[0] * cmdmove[0] + cmdmove[1] * cmdmove[1]);\n\t\t\t\t\t\t\t\t\tVectorCopy(areastart, lreach->start);\n\t\t\t\t\t\t\t\t\tVectorCopy(facecenter, lreach->end);\n\t\t\t\t\t\t\t\t\tlreach->traveltype = TRAVEL_JUMPPAD;\n\t\t\t\t\t\t\t\t\tlreach->traveltype |= AAS_TravelFlagsForTeam(ent);\n\t\t\t\t\t\t\t\t\tlreach->traveltime = aassettings.rs_aircontrolledjumppad;\n\t\t\t\t\t\t\t\t\tlreach->next = areareachability[link->areanum];\n\t\t\t\t\t\t\t\t\tareareachability[link->areanum] = lreach;\n\t\t\t\t\t\t\t\t\t//\n\t\t\t\t\t\t\t\t\treach_jumppad++;\n\t\t\t\t\t\t\t\t} //end for\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t} //end if\n\t\t\t\t} //end for\n\t\t\t} //end for\n\t\t} //end for\n\t\tAAS_UnlinkFromAreas(areas);\n\t} //end for\n} //end of the function AAS_Reachability_JumpPad\n//===========================================================================\n// never point at ground faces\n// always a higher and pretty far area\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_Reachability_Grapple(int area1num, int area2num)\n{\n\tint face2num, i, j, areanum, numareas, areas[20];\n\tfloat mingrappleangle, z, hordist;\n\tbsp_trace_t bsptrace;\n\taas_trace_t trace;\n\taas_face_t *face2;\n\taas_area_t *area1, *area2;\n\taas_lreachability_t *lreach;\n\tvec3_t areastart, facecenter, start, end, dir, down = {0, 0, -1};\n\tvec_t *v;\n\n\t//only grapple when on the ground or swimming\n\tif (!AAS_AreaGrounded(area1num) && !AAS_AreaSwim(area1num)) return qfalse;\n\t//don't grapple from a crouch area\n\tif (!(AAS_AreaPresenceType(area1num) & PRESENCE_NORMAL)) return qfalse;\n\t//NOTE: disabled area swim it doesn't work right\n\tif (AAS_AreaSwim(area1num)) return qfalse;\n\t//\n\tarea1 = &aasworld.areas[area1num];\n\tarea2 = &aasworld.areas[area2num];\n\t//don't grapple towards way lower areas\n\tif (area2->maxs[2] < area1->mins[2]) return qfalse;\n\t//\n\tVectorCopy(aasworld.areas[area1num].center, start);\n\t//if not a swim area\n\tif (!AAS_AreaSwim(area1num))\n\t{\n\t\tif (!AAS_PointAreaNum(start)) Log_Write(\"area %d center %f %f %f in solid?\\r\\n\", area1num,\n\t\t\t\t\t\t\t\tstart[0], start[1], start[2]);\n\t\tVectorCopy(start, end);\n\t\tend[2] -= 1000;\n\t\ttrace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, -1);\n\t\tif (trace.startsolid) return qfalse;\n\t\tVectorCopy(trace.endpos, areastart);\n\t} //end if\n\telse\n\t{\n\t\tif (!(AAS_PointContents(start) & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER))) return qfalse;\n\t} //end else\n\t//\n\t//start is now the start point\n\t//\n\tfor (i = 0; i < area2->numfaces; i++)\n\t{\n\t\tface2num = aasworld.faceindex[area2->firstface + i];\n\t\tface2 = &aasworld.faces[abs(face2num)];\n\t\t//if it is not a solid face\n\t\tif (!(face2->faceflags & FACE_SOLID)) continue;\n\t\t//direction towards the first vertex of the face\n\t\tv = aasworld.vertexes[aasworld.edges[abs(aasworld.edgeindex[face2->firstedge])].v[0]];\n\t\tVectorSubtract(v, areastart, dir);\n\t\t//if the face plane is facing away\n\t\tif (DotProduct(aasworld.planes[face2->planenum].normal, dir) > 0) continue;\n\t\t//get the center of the face\n\t\tAAS_FaceCenter(face2num, facecenter);\n\t\t//only go higher up with the grapple\n\t\tif (facecenter[2] < areastart[2] + 64) continue;\n\t\t//only use vertical faces or downward facing faces\n\t\tif (DotProduct(aasworld.planes[face2->planenum].normal, down) < 0) continue;\n\t\t//direction towards the face center\n\t\tVectorSubtract(facecenter, areastart, dir);\n\t\t//\n\t\tz = dir[2];\n\t\tdir[2] = 0;\n\t\thordist = VectorLength(dir);\n\t\tif (!hordist) continue;\n\t\t//if too far\n\t\tif (hordist > 2000) continue;\n\t\t//check the minimal angle of the movement\n\t\tmingrappleangle = 15; //15 degrees\n\t\tif (z / hordist < tan(2 * M_PI * mingrappleangle / 360)) continue;\n\t\t//\n\t\tVectorCopy(facecenter, start);\n\t\tVectorMA(facecenter, -500, aasworld.planes[face2->planenum].normal, end);\n\t\t//\n\t\tbsptrace = AAS_Trace(start, NULL, NULL, end, 0, CONTENTS_SOLID);\n\t\t//the grapple won't stick to the sky and the grapple point should be near the AAS wall\n\t\tif ((bsptrace.surface.flags & SURF_SKY) || (bsptrace.fraction * 500 > 32)) continue;\n\t\t//trace a full bounding box from the area center on the ground to\n\t\t//the center of the face\n\t\tVectorSubtract(facecenter, areastart, dir);\n\t\tVectorNormalize(dir);\n\t\tVectorMA(areastart, 4, dir, start);\n\t\tVectorCopy(bsptrace.endpos, end);\n\t\ttrace = AAS_TraceClientBBox(start, end, PRESENCE_NORMAL, -1);\n\t\tVectorSubtract(trace.endpos, facecenter, dir);\n\t\tif (VectorLength(dir) > 24) continue;\n\t\t//\n\t\tVectorCopy(trace.endpos, start);\n\t\tVectorCopy(trace.endpos, end);\n\t\tend[2] -= AAS_FallDamageDistance();\n\t\ttrace = AAS_TraceClientBBox(start, end, PRESENCE_NORMAL, -1);\n\t\tif (trace.fraction >= 1) continue;\n\t\t//area to end in\n\t\tareanum = AAS_PointAreaNum(trace.endpos);\n\t\t//if not in lava or slime\n\t\tif (aasworld.areasettings[areanum].contents & (AREACONTENTS_SLIME|AREACONTENTS_LAVA))\n\t\t{\n\t\t\tcontinue;\n\t\t} //end if\n\t\t//do not go the the source area\n\t\tif (areanum == area1num) continue;\n\t\t//don't create reachabilities if they already exist\n\t\tif (AAS_ReachabilityExists(area1num, areanum)) continue;\n\t\t//only end in areas we can stand\n\t\tif (!AAS_AreaGrounded(areanum)) continue;\n\t\t//never go through cluster portals!!\n\t\tnumareas = AAS_TraceAreas(areastart, bsptrace.endpos, areas, NULL, 20);\n\t\tif (numareas >= 20) continue;\n\t\tfor (j = 0; j < numareas; j++)\n\t\t{\n\t\t\tif (aasworld.areasettings[areas[j]].contents & AREACONTENTS_CLUSTERPORTAL) break;\n\t\t} //end for\n\t\tif (j < numareas) continue;\n\t\t//create a new reachability link\n\t\tlreach = AAS_AllocReachability();\n\t\tif (!lreach) return qfalse;\n\t\tlreach->areanum = areanum;\n\t\tlreach->facenum = face2num;\n\t\tlreach->edgenum = 0;\n\t\tVectorCopy(areastart, lreach->start);\n\t\t//VectorCopy(facecenter, lreach->end);\n\t\tVectorCopy(bsptrace.endpos, lreach->end);\n\t\tlreach->traveltype = TRAVEL_GRAPPLEHOOK;\n\t\tVectorSubtract(lreach->end, lreach->start, dir);\n\t\tlreach->traveltime = aassettings.rs_startgrapple + VectorLength(dir) * 0.25;\n\t\tlreach->next = areareachability[area1num];\n\t\tareareachability[area1num] = lreach;\n\t\t//\n\t\treach_grapple++;\n\t} //end for\n\t//\n\treturn qfalse;\n} //end of the function AAS_Reachability_Grapple\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_SetWeaponJumpAreaFlags(void)\n{\n\tint ent, i;\n\tvec3_t mins = {-15, -15, -15}, maxs = {15, 15, 15};\n\tvec3_t origin;\n\tint areanum, weaponjumpareas, spawnflags;\n\tchar classname[MAX_EPAIRKEY];\n\n\tweaponjumpareas = 0;\n\tfor (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent))\n\t{\n\t\tif (!AAS_ValueForBSPEpairKey(ent, \"classname\", classname, MAX_EPAIRKEY)) continue;\n\t\tif (\n\t\t\t!strcmp(classname, \"item_armor_body\") ||\n\t\t\t!strcmp(classname, \"item_armor_combat\") ||\n\t\t\t!strcmp(classname, \"item_health_mega\") ||\n\t\t\t!strcmp(classname, \"weapon_grenadelauncher\") ||\n\t\t\t!strcmp(classname, \"weapon_rocketlauncher\") ||\n\t\t\t!strcmp(classname, \"weapon_lightning\") ||\n\t\t\t!strcmp(classname, \"weapon_plasmagun\") ||\n\t\t\t!strcmp(classname, \"weapon_railgun\") ||\n\t\t\t!strcmp(classname, \"weapon_bfg\") ||\n\t\t\t!strcmp(classname, \"item_quad\") ||\n\t\t\t!strcmp(classname, \"item_regen\") ||\n\t\t\t!strcmp(classname, \"item_invulnerability\"))\n\t\t{\n\t\t\tif (AAS_VectorForBSPEpairKey(ent, \"origin\", origin))\n\t\t\t{\n\t\t\t\tspawnflags = 0;\n\t\t\t\tAAS_IntForBSPEpairKey(ent, \"spawnflags\", &spawnflags);\n\t\t\t\t//if not a stationary item\n\t\t\t\tif (!(spawnflags & 1))\n\t\t\t\t{\n\t\t\t\t\tif (!AAS_DropToFloor(origin, mins, maxs))\n\t\t\t\t\t{\n\t\t\t\t\t\tbotimport.Print(PRT_MESSAGE, \"%s in solid at (%1.1f %1.1f %1.1f)\\n\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassname, origin[0], origin[1], origin[2]);\n\t\t\t\t\t} //end if\n\t\t\t\t} //end if\n\t\t\t\t//areanum = AAS_PointAreaNum(origin);\n\t\t\t\tareanum = AAS_BestReachableArea(origin, mins, maxs, origin);\n\t\t\t\t//the bot may rocket jump towards this area\n\t\t\t\taasworld.areasettings[areanum].areaflags |= AREA_WEAPONJUMP;\n\t\t\t\t//\n\t\t\t\t//if (!AAS_AreaGrounded(areanum))\n\t\t\t\t//\tbotimport.Print(PRT_MESSAGE, \"area not grounded\\n\");\n\t\t\t\t//\n\t\t\t\tweaponjumpareas++;\n\t\t\t} //end if\n\t\t} //end if\n\t} //end for\n\tfor (i = 1; i < aasworld.numareas; i++)\n\t{\n\t\tif (aasworld.areasettings[i].contents & AREACONTENTS_JUMPPAD)\n\t\t{\n\t\t\taasworld.areasettings[i].areaflags |= AREA_WEAPONJUMP;\n\t\t\tweaponjumpareas++;\n\t\t} //end if\n\t} //end for\n\tbotimport.Print(PRT_MESSAGE, \"%d weapon jump areas\\n\", weaponjumpareas);\n} //end of the function AAS_SetWeaponJumpAreaFlags\n//===========================================================================\n// create a possible weapon jump reachability from area1 to area2\n//\n// check if there's a cool item in the second area\n// check if area1 is lower than area2\n// check if the bot can rocketjump from area1 to area2\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_Reachability_WeaponJump(int area1num, int area2num)\n{\n\tint face2num, i, n, ret, visualize;\n\tfloat speed, zvel, hordist;\n\taas_face_t *face2;\n\taas_area_t *area1, *area2;\n\taas_lreachability_t *lreach;\n\tvec3_t areastart, facecenter, start, end, dir, cmdmove;// teststart;\n\tvec3_t velocity;\n\taas_clientmove_t move;\n\taas_trace_t trace;\n\n\tvisualize = qfalse;\n//\tif (area1num == 4436 && area2num == 4318)\n//\t{\n//\t\tvisualize = qtrue;\n//\t}\n\tif (!AAS_AreaGrounded(area1num) || AAS_AreaSwim(area1num)) return qfalse;\n\tif (!AAS_AreaGrounded(area2num)) return qfalse;\n\t//NOTE: only weapon jump towards areas with an interesting item in it??\n\tif (!(aasworld.areasettings[area2num].areaflags & AREA_WEAPONJUMP)) return qfalse;\n\t//\n\tarea1 = &aasworld.areas[area1num];\n\tarea2 = &aasworld.areas[area2num];\n\t//don't weapon jump towards way lower areas\n\tif (area2->maxs[2] < area1->mins[2]) return qfalse;\n\t//\n\tVectorCopy(aasworld.areas[area1num].center, start);\n\t//if not a swim area\n\tif (!AAS_PointAreaNum(start)) Log_Write(\"area %d center %f %f %f in solid?\\r\\n\", area1num,\n\t\t\t\t\t\t\tstart[0], start[1], start[2]);\n\tVectorCopy(start, end);\n\tend[2] -= 1000;\n\ttrace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, -1);\n\tif (trace.startsolid) return qfalse;\n\tVectorCopy(trace.endpos, areastart);\n\t//\n\t//areastart is now the start point\n\t//\n\tfor (i = 0; i < area2->numfaces; i++)\n\t{\n\t\tface2num = aasworld.faceindex[area2->firstface + i];\n\t\tface2 = &aasworld.faces[abs(face2num)];\n\t\t//if it is not a solid face\n\t\tif (!(face2->faceflags & FACE_GROUND)) continue;\n\t\t//get the center of the face\n\t\tAAS_FaceCenter(face2num, facecenter);\n\t\t//only go higher up with weapon jumps\n\t\tif (facecenter[2] < areastart[2] + 64) continue;\n\t\t//NOTE: set to 2 to allow bfg jump reachabilities\n\t\tfor (n = 0; n < 1/*2*/; n++)\n\t\t{\n\t\t\t//get the rocket jump z velocity\n\t\t\tif (n) zvel = AAS_BFGJumpZVelocity(areastart);\n\t\t\telse zvel = AAS_RocketJumpZVelocity(areastart);\n\t\t\t//get the horizontal speed for the jump, if it isn't possible to calculate this\n\t\t\t//speed (the jump is not possible) then there's no jump reachability created\n\t\t\tret = AAS_HorizontalVelocityForJump(zvel, areastart, facecenter, &speed);\n\t\t\tif (ret && speed < 300)\n\t\t\t{\n\t\t\t\t//direction towards the face center\n\t\t\t\tVectorSubtract(facecenter, areastart, dir);\n\t\t\t\tdir[2] = 0;\n\t\t\t\thordist = VectorNormalize(dir);\n\t\t\t\t//if (hordist < 1.6 * (facecenter[2] - areastart[2]))\n\t\t\t\t{\n\t\t\t\t\t//get command movement\n\t\t\t\t\tVectorScale(dir, speed, cmdmove);\n\t\t\t\t\tVectorSet(velocity, 0, 0, zvel);\n\t\t\t\t\t/*\n\t\t\t\t\t//get command movement\n\t\t\t\t\tVectorScale(dir, speed, velocity);\n\t\t\t\t\tvelocity[2] = zvel;\n\t\t\t\t\tVectorSet(cmdmove, 0, 0, 0);\n\t\t\t\t\t*/\n\t\t\t\t\t//\n\t\t\t\t\tAAS_PredictClientMovement(&move, -1, areastart, PRESENCE_NORMAL, qtrue,\n\t\t\t\t\t\t\t\t\t\t\t\tvelocity, cmdmove, 30, 30, 0.1f,\n\t\t\t\t\t\t\t\t\t\t\t\tSE_ENTERWATER|SE_ENTERSLIME|\n\t\t\t\t\t\t\t\t\t\t\t\tSE_ENTERLAVA|SE_HITGROUNDDAMAGE|\n\t\t\t\t\t\t\t\t\t\t\t\tSE_TOUCHJUMPPAD|SE_HITGROUND|SE_HITGROUNDAREA, area2num, visualize);\n\t\t\t\t\t//if prediction time wasn't enough to fully predict the movement\n\t\t\t\t\t//don't enter slime or lava and don't fall from too high\n\t\t\t\t\tif (move.frames < 30 && \n\t\t\t\t\t\t\t!(move.stopevent & (SE_ENTERSLIME|SE_ENTERLAVA|SE_HITGROUNDDAMAGE))\n\t\t\t\t\t\t\t\t&& (move.stopevent & (SE_HITGROUNDAREA|SE_TOUCHJUMPPAD)))\n\t\t\t\t\t{\n\t\t\t\t\t\t//create a rocket or bfg jump reachability from area1 to area2\n\t\t\t\t\t\tlreach = AAS_AllocReachability();\n\t\t\t\t\t\tif (!lreach) return qfalse;\n\t\t\t\t\t\tlreach->areanum = area2num;\n\t\t\t\t\t\tlreach->facenum = 0;\n\t\t\t\t\t\tlreach->edgenum = 0;\n\t\t\t\t\t\tVectorCopy(areastart, lreach->start);\n\t\t\t\t\t\tVectorCopy(facecenter, lreach->end);\n\t\t\t\t\t\tif (n)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tlreach->traveltype = TRAVEL_BFGJUMP;\n\t\t\t\t\t\t\tlreach->traveltime = aassettings.rs_bfgjump;\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tlreach->traveltype = TRAVEL_ROCKETJUMP;\n\t\t\t\t\t\t\tlreach->traveltime = aassettings.rs_rocketjump;\n\t\t\t\t\t\t} //end else\n\t\t\t\t\t\tlreach->next = areareachability[area1num];\n\t\t\t\t\t\tareareachability[area1num] = lreach;\n\t\t\t\t\t\t//\n\t\t\t\t\t\treach_rocketjump++;\n\t\t\t\t\t\treturn qtrue;\n\t\t\t\t\t} //end if\n\t\t\t\t} //end if\n\t\t\t} //end if\n\t\t} //end for\n\t} //end for\n\t//\n\treturn qfalse;\n} //end of the function AAS_Reachability_WeaponJump\n//===========================================================================\n// calculates additional walk off ledge reachabilities for the given area\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_Reachability_WalkOffLedge(int areanum)\n{\n\tint i, j, k, l, m, n, p, areas[10], numareas;\n\tint face1num, face2num, face3num, edge1num, edge2num, edge3num;\n\tint otherareanum, gap, reachareanum, side;\n\taas_area_t *area, *area2;\n\taas_face_t *face1, *face2, *face3;\n\taas_edge_t *edge;\n\taas_plane_t *plane;\n\tvec_t *v1, *v2;\n\tvec3_t sharededgevec, mid, dir, testend;\n\taas_lreachability_t *lreach;\n\taas_trace_t trace;\n\n\tif (!AAS_AreaGrounded(areanum) || AAS_AreaSwim(areanum)) return;\n\t//\n\tarea = &aasworld.areas[areanum];\n\t//\n\tfor (i = 0; i < area->numfaces; i++)\n\t{\n\t\tface1num = aasworld.faceindex[area->firstface + i];\n\t\tface1 = &aasworld.faces[abs(face1num)];\n\t\t//face 1 must be a ground face\n\t\tif (!(face1->faceflags & FACE_GROUND)) continue;\n\t\t//go through all the edges of this ground face\n\t\tfor (k = 0; k < face1->numedges; k++)\n\t\t{\n\t\t\tedge1num = aasworld.edgeindex[face1->firstedge + k];\n\t\t\t//find another not ground face using this same edge\n\t\t\tfor (j = 0; j < area->numfaces; j++)\n\t\t\t{\n\t\t\t\tface2num = aasworld.faceindex[area->firstface + j];\n\t\t\t\tface2 = &aasworld.faces[abs(face2num)];\n\t\t\t\t//face 2 may not be a ground face\n\t\t\t\tif (face2->faceflags & FACE_GROUND) continue;\n\t\t\t\t//compare all the edges\n\t\t\t\tfor (l = 0; l < face2->numedges; l++)\n\t\t\t\t{\n\t\t\t\t\tedge2num = aasworld.edgeindex[face2->firstedge + l];\n\t\t\t\t\tif (abs(edge1num) == abs(edge2num))\n\t\t\t\t\t{\n\t\t\t\t\t\t//get the area at the other side of the face\n\t\t\t\t\t\tif (face2->frontarea == areanum) otherareanum = face2->backarea;\n\t\t\t\t\t\telse otherareanum = face2->frontarea;\n\t\t\t\t\t\t//\n\t\t\t\t\t\tarea2 = &aasworld.areas[otherareanum];\n\t\t\t\t\t\t//if the other area is grounded!\n\t\t\t\t\t\tif (aasworld.areasettings[otherareanum].areaflags & AREA_GROUNDED)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t//check for a possible gap\n\t\t\t\t\t\t\tgap = qfalse;\n\t\t\t\t\t\t\tfor (n = 0; n < area2->numfaces; n++)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tface3num = aasworld.faceindex[area2->firstface + n];\n\t\t\t\t\t\t\t\t//may not be the shared face of the two areas\n\t\t\t\t\t\t\t\tif (abs(face3num) == abs(face2num)) continue;\n\t\t\t\t\t\t\t\t//\n\t\t\t\t\t\t\t\tface3 = &aasworld.faces[abs(face3num)];\n\t\t\t\t\t\t\t\t//find an edge shared by all three faces\n\t\t\t\t\t\t\t\tfor (m = 0; m < face3->numedges; m++)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tedge3num = aasworld.edgeindex[face3->firstedge + m];\n\t\t\t\t\t\t\t\t\t//but the edge should be shared by all three faces\n\t\t\t\t\t\t\t\t\tif (abs(edge3num) == abs(edge1num))\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tif (!(face3->faceflags & FACE_SOLID))\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tgap = qtrue;\n\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t\t} //end if\n\t\t\t\t\t\t\t\t\t\t//\n\t\t\t\t\t\t\t\t\t\tif (face3->faceflags & FACE_GROUND)\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tgap = qfalse;\n\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t\t} //end if\n\t\t\t\t\t\t\t\t\t\t//FIXME: there are more situations to be handled\n\t\t\t\t\t\t\t\t\t\tgap = qtrue;\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t} //end if\n\t\t\t\t\t\t\t\t} //end for\n\t\t\t\t\t\t\t\tif (m < face3->numedges) break;\n\t\t\t\t\t\t\t} //end for\n\t\t\t\t\t\t\tif (!gap) break;\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t\t//check for a walk off ledge reachability\n\t\t\t\t\t\tedge = &aasworld.edges[abs(edge1num)];\n\t\t\t\t\t\tside = edge1num < 0;\n\t\t\t\t\t\t//\n\t\t\t\t\t\tv1 = aasworld.vertexes[edge->v[side]];\n\t\t\t\t\t\tv2 = aasworld.vertexes[edge->v[!side]];\n\t\t\t\t\t\t//\n\t\t\t\t\t\tplane = &aasworld.planes[face1->planenum];\n\t\t\t\t\t\t//get the points really into the areas\n\t\t\t\t\t\tVectorSubtract(v2, v1, sharededgevec);\n\t\t\t\t\t\tCrossProduct(plane->normal, sharededgevec, dir);\n\t\t\t\t\t\tVectorNormalize(dir);\n\t\t\t\t\t\t//\n\t\t\t\t\t\tVectorAdd(v1, v2, mid);\n\t\t\t\t\t\tVectorScale(mid, 0.5, mid);\n\t\t\t\t\t\tVectorMA(mid, 8, dir, mid);\n\t\t\t\t\t\t//\n\t\t\t\t\t\tVectorCopy(mid, testend);\n\t\t\t\t\t\ttestend[2] -= 1000;\n\t\t\t\t\t\ttrace = AAS_TraceClientBBox(mid, testend, PRESENCE_CROUCH, -1);\n\t\t\t\t\t\t//\n\t\t\t\t\t\tif (trace.startsolid)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t//Log_Write(\"area %d: trace.startsolid\\r\\n\", areanum);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t\treachareanum = AAS_PointAreaNum(trace.endpos);\n\t\t\t\t\t\tif (reachareanum == areanum)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t//Log_Write(\"area %d: same area\\r\\n\", areanum);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t\tif (AAS_ReachabilityExists(areanum, reachareanum))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t//Log_Write(\"area %d: reachability already exists\\r\\n\", areanum);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t\tif (!AAS_AreaGrounded(reachareanum) && !AAS_AreaSwim(reachareanum))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t//Log_Write(\"area %d, reach area %d: not grounded and not swim\\r\\n\", areanum, reachareanum);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t\t//\n\t\t\t\t\t\tif (aasworld.areasettings[reachareanum].contents & (AREACONTENTS_SLIME\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t| AREACONTENTS_LAVA))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t//Log_Write(\"area %d, reach area %d: lava or slime\\r\\n\", areanum, reachareanum);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t\t//if not going through a cluster portal\n\t\t\t\t\t\tnumareas = AAS_TraceAreas(mid, testend, areas, NULL, sizeof(areas) / sizeof(int));\n\t\t\t\t\t\tfor (p = 0; p < numareas; p++)\n\t\t\t\t\t\t\tif (AAS_AreaClusterPortal(areas[p]))\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tif (p < numareas)\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t// if a maximum fall height is set and the bot would fall down further\n\t\t\t\t\t\tif (aassettings.rs_maxfallheight && fabs(mid[2] - trace.endpos[2]) > aassettings.rs_maxfallheight)\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t//\n\t\t\t\t\t\tlreach = AAS_AllocReachability();\n\t\t\t\t\t\tif (!lreach) break;\n\t\t\t\t\t\tlreach->areanum = reachareanum;\n\t\t\t\t\t\tlreach->facenum = 0;\n\t\t\t\t\t\tlreach->edgenum = edge1num;\n\t\t\t\t\t\tVectorCopy(mid, lreach->start);\n\t\t\t\t\t\tVectorCopy(trace.endpos, lreach->end);\n\t\t\t\t\t\tlreach->traveltype = TRAVEL_WALKOFFLEDGE;\n\t\t\t\t\t\tlreach->traveltime = aassettings.rs_startwalkoffledge + fabs(mid[2] - trace.endpos[2]) * 50 / aassettings.phys_gravity;\n\t\t\t\t\t\tif (!AAS_AreaSwim(reachareanum) && !AAS_AreaJumpPad(reachareanum))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (AAS_FallDelta(mid[2] - trace.endpos[2]) > aassettings.phys_falldelta5)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tlreach->traveltime += aassettings.rs_falldamage5;\n\t\t\t\t\t\t\t} //end if\n\t\t\t\t\t\t\telse if (AAS_FallDelta(mid[2] - trace.endpos[2]) > aassettings.phys_falldelta10)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tlreach->traveltime += aassettings.rs_falldamage10;\n\t\t\t\t\t\t\t} //end if\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t\tlreach->next = areareachability[areanum];\n\t\t\t\t\t\tareareachability[areanum] = lreach;\n\t\t\t\t\t\t//we've got another walk off ledge reachability\n\t\t\t\t\t\treach_walkoffledge++;\n\t\t\t\t\t} //end if\n\t\t\t\t} //end for\n\t\t\t} //end for\n\t\t} //end for\n\t} //end for\n} //end of the function AAS_Reachability_WalkOffLedge\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_StoreReachability(void)\n{\n\tint i;\n\taas_areasettings_t *areasettings;\n\taas_lreachability_t *lreach;\n\taas_reachability_t *reach;\n\n\tif (aasworld.reachability) FreeMemory(aasworld.reachability);\n\taasworld.reachability = (aas_reachability_t *) GetClearedMemory((numlreachabilities + 10) * sizeof(aas_reachability_t));\n\taasworld.reachabilitysize = 1;\n\tfor (i = 0; i < aasworld.numareas; i++)\n\t{\n\t\tareasettings = &aasworld.areasettings[i];\n\t\tareasettings->firstreachablearea = aasworld.reachabilitysize;\n\t\tareasettings->numreachableareas = 0;\n\t\tfor (lreach = areareachability[i]; lreach; lreach = lreach->next)\n\t\t{\n\t\t\treach = &aasworld.reachability[areasettings->firstreachablearea +\n\t\t\t\t\t\t\t\t\t\t\t\t\tareasettings->numreachableareas];\n\t\t\treach->areanum = lreach->areanum;\n\t\t\treach->facenum = lreach->facenum;\n\t\t\treach->edgenum = lreach->edgenum;\n\t\t\tVectorCopy(lreach->start, reach->start);\n\t\t\tVectorCopy(lreach->end, reach->end);\n\t\t\treach->traveltype = lreach->traveltype;\n\t\t\treach->traveltime = lreach->traveltime;\n\t\t\t//\n\t\t\tareasettings->numreachableareas++;\n\t\t} //end for\n\t\taasworld.reachabilitysize += areasettings->numreachableareas;\n\t} //end for\n} //end of the function AAS_StoreReachability\n//===========================================================================\n//\n// TRAVEL_WALK\t\t\t\t\t100%\tequal floor height + steps\n// TRAVEL_CROUCH\t\t\t\t100%\n// TRAVEL_BARRIERJUMP\t\t\t100%\n// TRAVEL_JUMP\t\t\t\t\t 80%\n// TRAVEL_LADDER\t\t\t\t100%\t+ fall down from ladder + jump up to ladder\n// TRAVEL_WALKOFFLEDGE\t\t\t 90%\twalk off very steep walls?\n// TRAVEL_SWIM\t\t\t\t\t100%\n// TRAVEL_WATERJUMP\t\t\t\t100%\n// TRAVEL_TELEPORT\t\t\t\t100%\n// TRAVEL_ELEVATOR\t\t\t\t100%\n// TRAVEL_GRAPPLEHOOK\t\t\t100%\n// TRAVEL_DOUBLEJUMP\t\t\t  0%\n// TRAVEL_RAMPJUMP\t\t\t\t  0%\n// TRAVEL_STRAFEJUMP\t\t\t  0%\n// TRAVEL_ROCKETJUMP\t\t\t100%\t(currently limited towards areas with items)\n// TRAVEL_BFGJUMP\t\t\t\t  0%\t(currently disabled)\n// TRAVEL_JUMPPAD\t\t\t\t100%\n// TRAVEL_FUNCBOB\t\t\t\t100%\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\ttrue if NOT finished\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_ContinueInitReachability(float time)\n{\n\tint i, j, todo, start_time;\n\tstatic float framereachability, reachability_delay;\n\tstatic int lastpercentage;\n\n\tif (!aasworld.loaded) return qfalse;\n\t//if reachability is calculated for all areas\n\tif (aasworld.numreachabilityareas >= aasworld.numareas + 2) return qfalse;\n\t//if starting with area 1 (area 0 is a dummy)\n\tif (aasworld.numreachabilityareas == 1)\n\t{\n\t\tbotimport.Print(PRT_MESSAGE, \"calculating reachability...\\n\");\n\t\tlastpercentage = 0;\n\t\tframereachability = 2000;\n\t\treachability_delay = 1000;\n\t} //end if\n\t//number of areas to calculate reachability for this cycle\n\ttodo = aasworld.numreachabilityareas + (int) framereachability;\n\tstart_time = Sys_MilliSeconds();\n\t//loop over the areas\n\tfor (i = aasworld.numreachabilityareas; i < aasworld.numareas && i < todo; i++)\n\t{\n\t\taasworld.numreachabilityareas++;\n\t\t//only create jumppad reachabilities from jumppad areas\n\t\tif (aasworld.areasettings[i].contents & AREACONTENTS_JUMPPAD)\n\t\t{\n\t\t\tcontinue;\n\t\t} //end if\n\t\t//loop over the areas\n\t\tfor (j = 1; j < aasworld.numareas; j++)\n\t\t{\n\t\t\tif (i == j) continue;\n\t\t\t//never create reachabilities from teleporter or jumppad areas to regular areas\n\t\t\tif (aasworld.areasettings[i].contents & (AREACONTENTS_TELEPORTER|AREACONTENTS_JUMPPAD))\n\t\t\t{\n\t\t\t\tif (!(aasworld.areasettings[j].contents & (AREACONTENTS_TELEPORTER|AREACONTENTS_JUMPPAD)))\n\t\t\t\t{\n\t\t\t\t\tcontinue;\n\t\t\t\t} //end if\n\t\t\t} //end if\n\t\t\t//if there already is a reachability link from area i to j\n\t\t\tif (AAS_ReachabilityExists(i, j)) continue;\n\t\t\t//check for a swim reachability\n\t\t\tif (AAS_Reachability_Swim(i, j)) continue;\n\t\t\t//check for a simple walk on equal floor height reachability\n\t\t\tif (AAS_Reachability_EqualFloorHeight(i, j)) continue;\n\t\t\t//check for step, barrier, waterjump and walk off ledge reachabilities\n\t\t\tif (AAS_Reachability_Step_Barrier_WaterJump_WalkOffLedge(i, j)) continue;\n\t\t\t//check for ladder reachabilities\n\t\t\tif (AAS_Reachability_Ladder(i, j)) continue;\n\t\t\t//check for a jump reachability\n\t\t\tif (AAS_Reachability_Jump(i, j)) continue;\n\t\t} //end for\n\t\t//never create these reachabilities from teleporter or jumppad areas\n\t\tif (aasworld.areasettings[i].contents & (AREACONTENTS_TELEPORTER|AREACONTENTS_JUMPPAD))\n\t\t{\n\t\t\tcontinue;\n\t\t} //end if\n\t\t//loop over the areas\n\t\tfor (j = 1; j < aasworld.numareas; j++)\n\t\t{\n\t\t\tif (i == j) continue;\n\t\t\t//\n\t\t\tif (AAS_ReachabilityExists(i, j)) continue;\n\t\t\t//check for a grapple hook reachability\n\t\t\tif (calcgrapplereach) AAS_Reachability_Grapple(i, j);\n\t\t\t//check for a weapon jump reachability\n\t\t\tAAS_Reachability_WeaponJump(i, j);\n\t\t} //end for\n\t\t//if the calculation took more time than the max reachability delay\n\t\tif (Sys_MilliSeconds() - start_time > (int) reachability_delay) break;\n\t\t//\n\t\tif (aasworld.numreachabilityareas * 1000 / aasworld.numareas > lastpercentage) break;\n\t} //end for\n\t//\n\tif (aasworld.numreachabilityareas == aasworld.numareas)\n\t{\n\t\tbotimport.Print(PRT_MESSAGE, \"\\r%6.1f%%\", (float) 100.0);\n\t\tbotimport.Print(PRT_MESSAGE, \"\\nplease wait while storing reachability...\\n\");\n\t\taasworld.numreachabilityareas++;\n\t} //end if\n\t//if this is the last step in the reachability calculations\n\telse if (aasworld.numreachabilityareas == aasworld.numareas + 1)\n\t{\n\t\t//create additional walk off ledge reachabilities for every area\n\t\tfor (i = 1; i < aasworld.numareas; i++)\n\t\t{\n\t\t\t//only create jumppad reachabilities from jumppad areas\n\t\t\tif (aasworld.areasettings[i].contents & AREACONTENTS_JUMPPAD)\n\t\t\t{\n\t\t\t\tcontinue;\n\t\t\t} //end if\n\t\t\tAAS_Reachability_WalkOffLedge(i);\n\t\t} //end for\n\t\t//create jump pad reachabilities\n\t\tAAS_Reachability_JumpPad();\n\t\t//create teleporter reachabilities\n\t\tAAS_Reachability_Teleport();\n\t\t//create elevator (func_plat) reachabilities\n\t\tAAS_Reachability_Elevator();\n\t\t//create func_bobbing reachabilities\n\t\tAAS_Reachability_FuncBobbing();\n\t\t//\n#ifdef DEBUG\n\t\tbotimport.Print(PRT_MESSAGE, \"%6d reach swim\\n\", reach_swim);\n\t\tbotimport.Print(PRT_MESSAGE, \"%6d reach equal floor\\n\", reach_equalfloor);\n\t\tbotimport.Print(PRT_MESSAGE, \"%6d reach step\\n\", reach_step);\n\t\tbotimport.Print(PRT_MESSAGE, \"%6d reach barrier\\n\", reach_barrier);\n\t\tbotimport.Print(PRT_MESSAGE, \"%6d reach waterjump\\n\", reach_waterjump);\n\t\tbotimport.Print(PRT_MESSAGE, \"%6d reach walkoffledge\\n\", reach_walkoffledge);\n\t\tbotimport.Print(PRT_MESSAGE, \"%6d reach jump\\n\", reach_jump);\n\t\tbotimport.Print(PRT_MESSAGE, \"%6d reach ladder\\n\", reach_ladder);\n\t\tbotimport.Print(PRT_MESSAGE, \"%6d reach walk\\n\", reach_walk);\n\t\tbotimport.Print(PRT_MESSAGE, \"%6d reach teleport\\n\", reach_teleport);\n\t\tbotimport.Print(PRT_MESSAGE, \"%6d reach funcbob\\n\", reach_funcbob);\n\t\tbotimport.Print(PRT_MESSAGE, \"%6d reach elevator\\n\", reach_elevator);\n\t\tbotimport.Print(PRT_MESSAGE, \"%6d reach grapple\\n\", reach_grapple);\n\t\tbotimport.Print(PRT_MESSAGE, \"%6d reach rocketjump\\n\", reach_rocketjump);\n\t\tbotimport.Print(PRT_MESSAGE, \"%6d reach jumppad\\n\", reach_jumppad);\n#endif\n\t\t//*/\n\t\t//store all the reachabilities\n\t\tAAS_StoreReachability();\n\t\t//free the reachability link heap\n\t\tAAS_ShutDownReachabilityHeap();\n\t\t//\n\t\tFreeMemory(areareachability);\n\t\t//\n\t\taasworld.numreachabilityareas++;\n\t\t//\n\t\tbotimport.Print(PRT_MESSAGE, \"calculating clusters...\\n\");\n\t} //end if\n\telse\n\t{\n\t\tlastpercentage = aasworld.numreachabilityareas * 1000 / aasworld.numareas;\n\t\tbotimport.Print(PRT_MESSAGE, \"\\r%6.1f%%\", (float) lastpercentage / 10);\n\t} //end else\n\t//not yet finished\n\treturn qtrue;\n} //end of the function AAS_ContinueInitReachability\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_InitReachability(void)\n{\n\tif (!aasworld.loaded) return;\n\n\tif (aasworld.reachabilitysize)\n\t{\n#ifndef BSPC\n\t\tif (!((int)LibVarGetValue(\"forcereachability\")))\n\t\t{\n\t\t\taasworld.numreachabilityareas = aasworld.numareas + 2;\n\t\t\treturn;\n\t\t} //end if\n#else\n\t\taasworld.numreachabilityareas = aasworld.numareas + 2;\n\t\treturn;\n#endif //BSPC\n\t} //end if\n#ifndef BSPC\n\tcalcgrapplereach = LibVarGetValue(\"grapplereach\");\n#endif\n\taasworld.savefile = qtrue;\n\t//start with area 1 because area zero is a dummy\n\taasworld.numreachabilityareas = 1;\n\t////aasworld.numreachabilityareas = aasworld.numareas + 1;\t\t//only calculate entity reachabilities\n\t//setup the heap with reachability links\n\tAAS_SetupReachabilityHeap();\n\t//allocate area reachability link array\n\tareareachability = (aas_lreachability_t **) GetClearedMemory(\n\t\t\t\t\t\t\t\t\taasworld.numareas * sizeof(aas_lreachability_t *));\n\t//\n\tAAS_SetWeaponJumpAreaFlags();\n} //end of the function AAS_InitReachable\n"
  },
  {
    "path": "src/engine/botlib/be_aas_reach.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tbe_aas_reach.h\n *\n * desc:\t\tAAS\n *\n * $Archive: /source/code/botlib/be_aas_reach.h $\n *\n *****************************************************************************/\n\n#ifdef AASINTERN\n//initialize calculating the reachabilities\nvoid AAS_InitReachability(void);\n//continue calculating the reachabilities\nint AAS_ContinueInitReachability(float time);\n//\nint AAS_BestReachableLinkArea(aas_link_t *areas);\n#endif //AASINTERN\n\n//returns true if the are has reachabilities to other areas\nint AAS_AreaReachability(int areanum);\n//returns the best reachable area and goal origin for a bounding box at the given origin\nint AAS_BestReachableArea(vec3_t origin, vec3_t mins, vec3_t maxs, vec3_t goalorigin);\n//returns the best jumppad area from which the bbox at origin is reachable\nint AAS_BestReachableFromJumpPadArea(vec3_t origin, vec3_t mins, vec3_t maxs);\n//returns the next reachability using the given model\nint AAS_NextModelReachability(int num, int modelnum);\n//returns the total area of the ground faces of the given area\nfloat AAS_AreaGroundFaceArea(int areanum);\n//returns true if the area is crouch only\nint AAS_AreaCrouch(int areanum);\n//returns true if a player can swim in this area\nint AAS_AreaSwim(int areanum);\n//returns true if the area is filled with a liquid\nint AAS_AreaLiquid(int areanum);\n//returns true if the area contains lava\nint AAS_AreaLava(int areanum);\n//returns true if the area contains slime\nint AAS_AreaSlime(int areanum);\n//returns true if the area has one or more ground faces\nint AAS_AreaGrounded(int areanum);\n//returns true if the area has one or more ladder faces\nint AAS_AreaLadder(int areanum);\n//returns true if the area is a jump pad\nint AAS_AreaJumpPad(int areanum);\n//returns true if the area is donotenter\nint AAS_AreaDoNotEnter(int areanum);\n"
  },
  {
    "path": "src/engine/botlib/be_aas_route.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tbe_aas_route.c\n *\n * desc:\t\tAAS\n *\n * $Archive: /MissionPack/code/botlib/be_aas_route.c $\n *\n *****************************************************************************/\n\n#include \"../../game/q_shared.h\"\n#include \"l_utils.h\"\n#include \"l_memory.h\"\n#include \"l_log.h\"\n#include \"l_crc.h\"\n#include \"l_libvar.h\"\n#include \"l_script.h\"\n#include \"l_precomp.h\"\n#include \"l_struct.h\"\n#include \"aasfile.h\"\n#include \"../../game/botlib.h\"\n#include \"../../game/be_aas.h\"\n#include \"be_aas_funcs.h\"\n#include \"be_interface.h\"\n#include \"be_aas_def.h\"\n\n#define ROUTING_DEBUG\n\n//travel time in hundreths of a second = distance * 100 / speed\n#define DISTANCEFACTOR_CROUCH\t\t1.3f\t\t//crouch speed = 100\n#define DISTANCEFACTOR_SWIM\t\t\t1\t\t//should be 0.66, swim speed = 150\n#define DISTANCEFACTOR_WALK\t\t\t0.33f\t//walk speed = 300\n\n//cache refresh time\n#define CACHE_REFRESHTIME\t\t15.0f\t//15 seconds refresh time\n\n//maximum number of routing updates each frame\n#define MAX_FRAMEROUTINGUPDATES\t\t10\n\n\n/*\n\n  area routing cache:\n  stores the distances within one cluster to a specific goal area\n  this goal area is in this same cluster and could be a cluster portal\n  for every cluster there's a list with routing cache for every area\n  in that cluster (including the portals of that cluster)\n  area cache stores aasworld.clusters[?].numreachabilityareas travel times\n\n  portal routing cache:\n  stores the distances of all portals to a specific goal area\n  this goal area could be in any cluster and could also be a cluster portal\n  for every area (aasworld.numareas) the portal cache stores\n  aasworld.numportals travel times\n\n*/\n\n#ifdef ROUTING_DEBUG\nint numareacacheupdates;\nint numportalcacheupdates;\n#endif //ROUTING_DEBUG\n\nint routingcachesize;\nint max_routingcachesize;\n\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\n#ifdef ROUTING_DEBUG\nvoid AAS_RoutingInfo(void)\n{\n\tbotimport.Print(PRT_MESSAGE, \"%d area cache updates\\n\", numareacacheupdates);\n\tbotimport.Print(PRT_MESSAGE, \"%d portal cache updates\\n\", numportalcacheupdates);\n\tbotimport.Print(PRT_MESSAGE, \"%d bytes routing cache\\n\", routingcachesize);\n} //end of the function AAS_RoutingInfo\n#endif //ROUTING_DEBUG\n//===========================================================================\n// returns the number of the area in the cluster\n// assumes the given area is in the given cluster or a portal of the cluster\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\n__inline int AAS_ClusterAreaNum(int cluster, int areanum)\n{\n\tint side, areacluster;\n\n\tareacluster = aasworld.areasettings[areanum].cluster;\n\tif (areacluster > 0) return aasworld.areasettings[areanum].clusterareanum;\n\telse\n\t{\n/*#ifdef ROUTING_DEBUG\n\t\tif (aasworld.portals[-areacluster].frontcluster != cluster &&\n\t\t\t\taasworld.portals[-areacluster].backcluster != cluster)\n\t\t{\n\t\t\tbotimport.Print(PRT_ERROR, \"portal %d: does not belong to cluster %d\\n\"\n\t\t\t\t\t\t\t\t\t\t\t, -areacluster, cluster);\n\t\t} //end if\n#endif //ROUTING_DEBUG*/\n\t\tside = aasworld.portals[-areacluster].frontcluster != cluster;\n\t\treturn aasworld.portals[-areacluster].clusterareanum[side];\n\t} //end else\n} //end of the function AAS_ClusterAreaNum\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_InitTravelFlagFromType(void)\n{\n\tint i;\n\n\tfor (i = 0; i < MAX_TRAVELTYPES; i++)\n\t{\n\t\taasworld.travelflagfortype[i] = TFL_INVALID;\n\t} //end for\n\taasworld.travelflagfortype[TRAVEL_INVALID] = TFL_INVALID;\n\taasworld.travelflagfortype[TRAVEL_WALK] = TFL_WALK;\n\taasworld.travelflagfortype[TRAVEL_CROUCH] = TFL_CROUCH;\n\taasworld.travelflagfortype[TRAVEL_BARRIERJUMP] = TFL_BARRIERJUMP;\n\taasworld.travelflagfortype[TRAVEL_JUMP] = TFL_JUMP;\n\taasworld.travelflagfortype[TRAVEL_LADDER] = TFL_LADDER;\n\taasworld.travelflagfortype[TRAVEL_WALKOFFLEDGE] = TFL_WALKOFFLEDGE;\n\taasworld.travelflagfortype[TRAVEL_SWIM] = TFL_SWIM;\n\taasworld.travelflagfortype[TRAVEL_WATERJUMP] = TFL_WATERJUMP;\n\taasworld.travelflagfortype[TRAVEL_TELEPORT] = TFL_TELEPORT;\n\taasworld.travelflagfortype[TRAVEL_ELEVATOR] = TFL_ELEVATOR;\n\taasworld.travelflagfortype[TRAVEL_ROCKETJUMP] = TFL_ROCKETJUMP;\n\taasworld.travelflagfortype[TRAVEL_BFGJUMP] = TFL_BFGJUMP;\n\taasworld.travelflagfortype[TRAVEL_GRAPPLEHOOK] = TFL_GRAPPLEHOOK;\n\taasworld.travelflagfortype[TRAVEL_DOUBLEJUMP] = TFL_DOUBLEJUMP;\n\taasworld.travelflagfortype[TRAVEL_RAMPJUMP] = TFL_RAMPJUMP;\n\taasworld.travelflagfortype[TRAVEL_STRAFEJUMP] = TFL_STRAFEJUMP;\n\taasworld.travelflagfortype[TRAVEL_JUMPPAD] = TFL_JUMPPAD;\n\taasworld.travelflagfortype[TRAVEL_FUNCBOB] = TFL_FUNCBOB;\n} //end of the function AAS_InitTravelFlagFromType\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\n__inline int AAS_TravelFlagForType_inline(int traveltype)\n{\n\tint tfl;\n\n\ttfl = 0;\n\tif (tfl & TRAVELFLAG_NOTTEAM1)\n\t\ttfl |= TFL_NOTTEAM1;\n\tif (tfl & TRAVELFLAG_NOTTEAM2)\n\t\ttfl |= TFL_NOTTEAM2;\n\ttraveltype &= TRAVELTYPE_MASK;\n\tif (traveltype < 0 || traveltype >= MAX_TRAVELTYPES)\n\t\treturn TFL_INVALID;\n\ttfl |= aasworld.travelflagfortype[traveltype];\n\treturn tfl;\n} //end of the function AAS_TravelFlagForType_inline\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_TravelFlagForType(int traveltype)\n{\n\treturn AAS_TravelFlagForType_inline(traveltype);\n} //end of the function AAS_TravelFlagForType_inline\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_UnlinkCache(aas_routingcache_t *cache)\n{\n\tif (cache->time_next) cache->time_next->time_prev = cache->time_prev;\n\telse aasworld.newestcache = cache->time_prev;\n\tif (cache->time_prev) cache->time_prev->time_next = cache->time_next;\n\telse aasworld.oldestcache = cache->time_next;\n\tcache->time_next = NULL;\n\tcache->time_prev = NULL;\n} //end of the function AAS_UnlinkCache\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_LinkCache(aas_routingcache_t *cache)\n{\n\tif (aasworld.newestcache)\n\t{\n\t\taasworld.newestcache->time_next = cache;\n\t\tcache->time_prev = aasworld.newestcache;\n\t} //end if\n\telse\n\t{\n\t\taasworld.oldestcache = cache;\n\t\tcache->time_prev = NULL;\n\t} //end else\n\tcache->time_next = NULL;\n\taasworld.newestcache = cache;\n} //end of the function AAS_LinkCache\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_FreeRoutingCache(aas_routingcache_t *cache)\n{\n\tAAS_UnlinkCache(cache);\n\troutingcachesize -= cache->size;\n\tFreeMemory(cache);\n} //end of the function AAS_FreeRoutingCache\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_RemoveRoutingCacheInCluster( int clusternum )\n{\n\tint i;\n\taas_routingcache_t *cache, *nextcache;\n\taas_cluster_t *cluster;\n\n\tif (!aasworld.clusterareacache)\n\t\treturn;\n\tcluster = &aasworld.clusters[clusternum];\n\tfor (i = 0; i < cluster->numareas; i++)\n\t{\n\t\tfor (cache = aasworld.clusterareacache[clusternum][i]; cache; cache = nextcache)\n\t\t{\n\t\t\tnextcache = cache->next;\n\t\t\tAAS_FreeRoutingCache(cache);\n\t\t} //end for\n\t\taasworld.clusterareacache[clusternum][i] = NULL;\n\t} //end for\n} //end of the function AAS_RemoveRoutingCacheInCluster\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_RemoveRoutingCacheUsingArea( int areanum )\n{\n\tint i, clusternum;\n\taas_routingcache_t *cache, *nextcache;\n\n\tclusternum = aasworld.areasettings[areanum].cluster;\n\tif (clusternum > 0)\n\t{\n\t\t//remove all the cache in the cluster the area is in\n\t\tAAS_RemoveRoutingCacheInCluster( clusternum );\n\t} //end if\n\telse\n\t{\n\t\t// if this is a portal remove all cache in both the front and back cluster\n\t\tAAS_RemoveRoutingCacheInCluster( aasworld.portals[-clusternum].frontcluster );\n\t\tAAS_RemoveRoutingCacheInCluster( aasworld.portals[-clusternum].backcluster );\n\t} //end else\n\t// remove all portal cache\n\tfor (i = 0; i < aasworld.numareas; i++)\n\t{\n\t\t//refresh portal cache\n\t\tfor (cache = aasworld.portalcache[i]; cache; cache = nextcache)\n\t\t{\n\t\t\tnextcache = cache->next;\n\t\t\tAAS_FreeRoutingCache(cache);\n\t\t} //end for\n\t\taasworld.portalcache[i] = NULL;\n\t} //end for\n} //end of the function AAS_RemoveRoutingCacheUsingArea\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_EnableRoutingArea(int areanum, int enable)\n{\n\tint flags;\n\n\tif (areanum <= 0 || areanum >= aasworld.numareas)\n\t{\n\t\tif (bot_developer)\n\t\t{\n\t\t\tbotimport.Print(PRT_ERROR, \"AAS_EnableRoutingArea: areanum %d out of range\\n\", areanum);\n\t\t} //end if\n\t\treturn 0;\n\t} //end if\n\tflags = aasworld.areasettings[areanum].areaflags & AREA_DISABLED;\n\tif (enable < 0)\n\t\treturn !flags;\n\n\tif (enable)\n\t\taasworld.areasettings[areanum].areaflags &= ~AREA_DISABLED;\n\telse\n\t\taasworld.areasettings[areanum].areaflags |= AREA_DISABLED;\n\t// if the status of the area changed\n\tif ( (flags & AREA_DISABLED) != (aasworld.areasettings[areanum].areaflags & AREA_DISABLED) )\n\t{\n\t\t//remove all routing cache involving this area\n\t\tAAS_RemoveRoutingCacheUsingArea( areanum );\n\t} //end if\n\treturn !flags;\n} //end of the function AAS_EnableRoutingArea\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\n__inline float AAS_RoutingTime(void)\n{\n\treturn AAS_Time();\n} //end of the function AAS_RoutingTime\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_GetAreaContentsTravelFlags(int areanum)\n{\n\tint contents, tfl;\n\n\tcontents = aasworld.areasettings[areanum].contents;\n\ttfl = 0;\n\tif (contents & AREACONTENTS_WATER)\n\t\ttfl |= TFL_WATER;\n\telse if (contents & AREACONTENTS_SLIME)\n\t\ttfl |= TFL_SLIME;\n\telse if (contents & AREACONTENTS_LAVA)\n\t\ttfl |= TFL_LAVA;\n\telse\n\t\ttfl |= TFL_AIR;\n\tif (contents & AREACONTENTS_DONOTENTER)\n\t\ttfl |= TFL_DONOTENTER;\n\tif (contents & AREACONTENTS_NOTTEAM1)\n\t\ttfl |= TFL_NOTTEAM1;\n\tif (contents & AREACONTENTS_NOTTEAM2)\n\t\ttfl |= TFL_NOTTEAM2;\n\tif (aasworld.areasettings[areanum].areaflags & AREA_BRIDGE)\n\t\ttfl |= TFL_BRIDGE;\n\treturn tfl;\n} //end of the function AAS_GetAreaContentsTravelFlags\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\n__inline int AAS_AreaContentsTravelFlags_inline(int areanum)\n{\n\treturn aasworld.areacontentstravelflags[areanum];\n} //end of the function AAS_AreaContentsTravelFlags\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_AreaContentsTravelFlags(int areanum)\n{\n\treturn aasworld.areacontentstravelflags[areanum];\n} //end of the function AAS_AreaContentsTravelFlags\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_InitAreaContentsTravelFlags(void)\n{\n\tint i;\n\n\tif (aasworld.areacontentstravelflags) FreeMemory(aasworld.areacontentstravelflags);\n\taasworld.areacontentstravelflags = (int *) GetClearedMemory(aasworld.numareas * sizeof(int));\n\t//\n\tfor (i = 0; i < aasworld.numareas; i++) {\n\t\taasworld.areacontentstravelflags[i] = AAS_GetAreaContentsTravelFlags(i);\n\t}\n} //end of the function AAS_InitAreaContentsTravelFlags\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_CreateReversedReachability(void)\n{\n\tint i, n;\n\taas_reversedlink_t *revlink;\n\taas_reachability_t *reach;\n\taas_areasettings_t *settings;\n\tchar *ptr;\n#ifdef DEBUG\n\tint starttime;\n\n\tstarttime = Sys_MilliSeconds();\n#endif\n\t//free reversed links that have already been created\n\tif (aasworld.reversedreachability) FreeMemory(aasworld.reversedreachability);\n\t//allocate memory for the reversed reachability links\n\tptr = (char *) GetClearedMemory(aasworld.numareas * sizeof(aas_reversedreachability_t) +\n\t\t\t\t\t\t\taasworld.reachabilitysize * sizeof(aas_reversedlink_t));\n\t//\n\taasworld.reversedreachability = (aas_reversedreachability_t *) ptr;\n\t//pointer to the memory for the reversed links\n\tptr += aasworld.numareas * sizeof(aas_reversedreachability_t);\n\t//check all reachabilities of all areas\n\tfor (i = 1; i < aasworld.numareas; i++)\n\t{\n\t\t//settings of the area\n\t\tsettings = &aasworld.areasettings[i];\n\t\t//\n\t\tif (settings->numreachableareas >= 128)\n\t\t\tbotimport.Print(PRT_WARNING, \"area %d has more than 128 reachabilities\\n\", i);\n\t\t//create reversed links for the reachabilities\n\t\tfor (n = 0; n < settings->numreachableareas && n < 128; n++)\n\t\t{\n\t\t\t//reachability link\n\t\t\treach = &aasworld.reachability[settings->firstreachablearea + n];\n\t\t\t//\n\t\t\trevlink = (aas_reversedlink_t *) ptr;\n\t\t\tptr += sizeof(aas_reversedlink_t);\n\t\t\t//\n\t\t\trevlink->areanum = i;\n\t\t\trevlink->linknum = settings->firstreachablearea + n;\n\t\t\trevlink->next = aasworld.reversedreachability[reach->areanum].first;\n\t\t\taasworld.reversedreachability[reach->areanum].first = revlink;\n\t\t\taasworld.reversedreachability[reach->areanum].numlinks++;\n\t\t} //end for\n\t} //end for\n#ifdef DEBUG\n\tbotimport.Print(PRT_MESSAGE, \"reversed reachability %d msec\\n\", Sys_MilliSeconds() - starttime);\n#endif\n} //end of the function AAS_CreateReversedReachability\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nunsigned short int AAS_AreaTravelTime(int areanum, vec3_t start, vec3_t end)\n{\n\tint intdist;\n\tfloat dist;\n\tvec3_t dir;\n\n\tVectorSubtract(start, end, dir);\n\tdist = VectorLength(dir);\n\t//if crouch only area\n\tif (AAS_AreaCrouch(areanum)) dist *= DISTANCEFACTOR_CROUCH;\n\t//if swim area\n\telse if (AAS_AreaSwim(areanum)) dist *= DISTANCEFACTOR_SWIM;\n\t//normal walk area\n\telse dist *= DISTANCEFACTOR_WALK;\n\t//\n\tintdist = (int) dist;\n\t//make sure the distance isn't zero\n\tif (intdist <= 0) intdist = 1;\n\treturn intdist;\n} //end of the function AAS_AreaTravelTime\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_CalculateAreaTravelTimes(void)\n{\n\tint i, l, n, size;\n\tchar *ptr;\n\tvec3_t end;\n\taas_reversedreachability_t *revreach;\n\taas_reversedlink_t *revlink;\n\taas_reachability_t *reach;\n\taas_areasettings_t *settings;\n\tint starttime;\n\n\tstarttime = Sys_MilliSeconds();\n\t//if there are still area travel times, free the memory\n\tif (aasworld.areatraveltimes) FreeMemory(aasworld.areatraveltimes);\n\t//get the total size of all the area travel times\n\tsize = aasworld.numareas * sizeof(unsigned short **);\n\tfor (i = 0; i < aasworld.numareas; i++)\n\t{\n\t\trevreach = &aasworld.reversedreachability[i];\n\t\t//settings of the area\n\t\tsettings = &aasworld.areasettings[i];\n\t\t//\n\t\tsize += settings->numreachableareas * sizeof(unsigned short *);\n\t\t//\n\t\tsize += settings->numreachableareas * revreach->numlinks * sizeof(unsigned short);\n\t} //end for\n\t//allocate memory for the area travel times\n\tptr = (char *) GetClearedMemory(size);\n\taasworld.areatraveltimes = (unsigned short ***) ptr;\n\tptr += aasworld.numareas * sizeof(unsigned short **);\n\t//calcluate the travel times for all the areas\n\tfor (i = 0; i < aasworld.numareas; i++)\n\t{\n\t\t//reversed reachabilities of this area\n\t\trevreach = &aasworld.reversedreachability[i];\n\t\t//settings of the area\n\t\tsettings = &aasworld.areasettings[i];\n\t\t//\n\t\taasworld.areatraveltimes[i] = (unsigned short **) ptr;\n\t\tptr += settings->numreachableareas * sizeof(unsigned short *);\n\t\t//\n\t\tfor (l = 0; l < settings->numreachableareas; l++)\n\t\t{\n\t\t\taasworld.areatraveltimes[i][l] = (unsigned short *) ptr;\n\t\t\tptr += revreach->numlinks * sizeof(unsigned short);\n\t\t\t//reachability link\n\t\t\treach = &aasworld.reachability[settings->firstreachablearea + l];\n\t\t\t//\n\t\t\tfor (n = 0, revlink = revreach->first; revlink; revlink = revlink->next, n++)\n\t\t\t{\n\t\t\t\tVectorCopy(aasworld.reachability[revlink->linknum].end, end);\n\t\t\t\t//\n\t\t\t\taasworld.areatraveltimes[i][l][n] = AAS_AreaTravelTime(i, end, reach->start);\n\t\t\t} //end for\n\t\t} //end for\n\t} //end for\n#ifdef DEBUG\n\tbotimport.Print(PRT_MESSAGE, \"area travel times %d msec\\n\", Sys_MilliSeconds() - starttime);\n#endif\n} //end of the function AAS_CalculateAreaTravelTimes\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_PortalMaxTravelTime(int portalnum)\n{\n\tint l, n, t, maxt;\n\taas_portal_t *portal;\n\taas_reversedreachability_t *revreach;\n\taas_reversedlink_t *revlink;\n\taas_areasettings_t *settings;\n\n\tportal = &aasworld.portals[portalnum];\n\t//reversed reachabilities of this portal area\n\trevreach = &aasworld.reversedreachability[portal->areanum];\n\t//settings of the portal area\n\tsettings = &aasworld.areasettings[portal->areanum];\n\t//\n\tmaxt = 0;\n\tfor (l = 0; l < settings->numreachableareas; l++)\n\t{\n\t\tfor (n = 0, revlink = revreach->first; revlink; revlink = revlink->next, n++)\n\t\t{\n\t\t\tt = aasworld.areatraveltimes[portal->areanum][l][n];\n\t\t\tif (t > maxt)\n\t\t\t{\n\t\t\t\tmaxt = t;\n\t\t\t} //end if\n\t\t} //end for\n\t} //end for\n\treturn maxt;\n} //end of the function AAS_PortalMaxTravelTime\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_InitPortalMaxTravelTimes(void)\n{\n\tint i;\n\n\tif (aasworld.portalmaxtraveltimes) FreeMemory(aasworld.portalmaxtraveltimes);\n\n\taasworld.portalmaxtraveltimes = (int *) GetClearedMemory(aasworld.numportals * sizeof(int));\n\n\tfor (i = 0; i < aasworld.numportals; i++)\n\t{\n\t\taasworld.portalmaxtraveltimes[i] = AAS_PortalMaxTravelTime(i);\n\t\t//botimport.Print(PRT_MESSAGE, \"portal %d max tt = %d\\n\", i, aasworld.portalmaxtraveltimes[i]);\n\t} //end for\n} //end of the function AAS_InitPortalMaxTravelTimes\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\n/*\nint AAS_FreeOldestCache(void)\n{\n\tint i, j, bestcluster, bestarea, freed;\n\tfloat besttime;\n\taas_routingcache_t *cache, *bestcache;\n\n\tfreed = qfalse;\n\tbesttime = 999999999;\n\tbestcache = NULL;\n\tbestcluster = 0;\n\tbestarea = 0;\n\t//refresh cluster cache\n\tfor (i = 0; i < aasworld.numclusters; i++)\n\t{\n\t\tfor (j = 0; j < aasworld.clusters[i].numareas; j++)\n\t\t{\n\t\t\tfor (cache = aasworld.clusterareacache[i][j]; cache; cache = cache->next)\n\t\t\t{\n\t\t\t\t//never remove cache leading towards a portal\n\t\t\t\tif (aasworld.areasettings[cache->areanum].cluster < 0) continue;\n\t\t\t\t//if this cache is older than the cache we found so far\n\t\t\t\tif (cache->time < besttime)\n\t\t\t\t{\n\t\t\t\t\tbestcache = cache;\n\t\t\t\t\tbestcluster = i;\n\t\t\t\t\tbestarea = j;\n\t\t\t\t\tbesttime = cache->time;\n\t\t\t\t} //end if\n\t\t\t} //end for\n\t\t} //end for\n\t} //end for\n\tif (bestcache)\n\t{\n\t\tcache = bestcache;\n\t\tif (cache->prev) cache->prev->next = cache->next;\n\t\telse aasworld.clusterareacache[bestcluster][bestarea] = cache->next;\n\t\tif (cache->next) cache->next->prev = cache->prev;\n\t\tAAS_FreeRoutingCache(cache);\n\t\tfreed = qtrue;\n\t} //end if\n\tbesttime = 999999999;\n\tbestcache = NULL;\n\tbestarea = 0;\n\tfor (i = 0; i < aasworld.numareas; i++)\n\t{\n\t\t//refresh portal cache\n\t\tfor (cache = aasworld.portalcache[i]; cache; cache = cache->next)\n\t\t{\n\t\t\tif (cache->time < besttime)\n\t\t\t{\n\t\t\t\tbestcache = cache;\n\t\t\t\tbestarea = i;\n\t\t\t\tbesttime = cache->time;\n\t\t\t} //end if\n\t\t} //end for\n\t} //end for\n\tif (bestcache)\n\t{\n\t\tcache = bestcache;\n\t\tif (cache->prev) cache->prev->next = cache->next;\n\t\telse aasworld.portalcache[bestarea] = cache->next;\n\t\tif (cache->next) cache->next->prev = cache->prev;\n\t\tAAS_FreeRoutingCache(cache);\n\t\tfreed = qtrue;\n\t} //end if\n\treturn freed;\n} //end of the function AAS_FreeOldestCache\n*/\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_FreeOldestCache(void)\n{\n\tint clusterareanum;\n\taas_routingcache_t *cache;\n\n\tfor (cache = aasworld.oldestcache; cache; cache = cache->time_next) {\n\t\t// never free area cache leading towards a portal\n\t\tif (cache->type == CACHETYPE_AREA && aasworld.areasettings[cache->areanum].cluster < 0) {\n\t\t\tcontinue;\n\t\t}\n\t\tbreak;\n\t}\n\tif (cache) {\n\t\t// unlink the cache\n\t\tif (cache->type == CACHETYPE_AREA) {\n\t\t\t//number of the area in the cluster\n\t\t\tclusterareanum = AAS_ClusterAreaNum(cache->cluster, cache->areanum);\n\t\t\t// unlink from cluster area cache\n\t\t\tif (cache->prev) cache->prev->next = cache->next;\n\t\t\telse aasworld.clusterareacache[cache->cluster][clusterareanum] = cache->next;\n\t\t\tif (cache->next) cache->next->prev = cache->prev;\n\t\t}\n\t\telse {\n\t\t\t// unlink from portal cache\n\t\t\tif (cache->prev) cache->prev->next = cache->next;\n\t\t\telse aasworld.portalcache[cache->areanum] = cache->next;\n\t\t\tif (cache->next) cache->next->prev = cache->prev;\n\t\t}\n\t\tAAS_FreeRoutingCache(cache);\n\t\treturn qtrue;\n\t}\n\treturn qfalse;\n} //end of the function AAS_FreeOldestCache\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\naas_routingcache_t *AAS_AllocRoutingCache(int numtraveltimes)\n{\n\taas_routingcache_t *cache;\n\tint size;\n\n\t//\n\tsize = sizeof(aas_routingcache_t)\n\t\t\t\t\t\t+ numtraveltimes * sizeof(unsigned short int)\n\t\t\t\t\t\t+ numtraveltimes * sizeof(unsigned char);\n\t//\n\troutingcachesize += size;\n\t//\n\tcache = (aas_routingcache_t *) GetClearedMemory(size);\n\tcache->reachabilities = (unsigned char *) cache + sizeof(aas_routingcache_t)\n\t\t\t\t\t\t\t\t+ numtraveltimes * sizeof(unsigned short int);\n\tcache->size = size;\n\treturn cache;\n} //end of the function AAS_AllocRoutingCache\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_FreeAllClusterAreaCache(void)\n{\n\tint i, j;\n\taas_routingcache_t *cache, *nextcache;\n\taas_cluster_t *cluster;\n\n\t//free all cluster cache if existing\n\tif (!aasworld.clusterareacache) return;\n\t//free caches\n\tfor (i = 0; i < aasworld.numclusters; i++)\n\t{\n\t\tcluster = &aasworld.clusters[i];\n\t\tfor (j = 0; j < cluster->numareas; j++)\n\t\t{\n\t\t\tfor (cache = aasworld.clusterareacache[i][j]; cache; cache = nextcache)\n\t\t\t{\n\t\t\t\tnextcache = cache->next;\n\t\t\t\tAAS_FreeRoutingCache(cache);\n\t\t\t} //end for\n\t\t\taasworld.clusterareacache[i][j] = NULL;\n\t\t} //end for\n\t} //end for\n\t//free the cluster cache array\n\tFreeMemory(aasworld.clusterareacache);\n\taasworld.clusterareacache = NULL;\n} //end of the function AAS_FreeAllClusterAreaCache\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_InitClusterAreaCache(void)\n{\n\tint i, size;\n\tchar *ptr;\n\n\t//\n\tfor (size = 0, i = 0; i < aasworld.numclusters; i++)\n\t{\n\t\tsize += aasworld.clusters[i].numareas;\n\t} //end for\n\t//two dimensional array with pointers for every cluster to routing cache\n\t//for every area in that cluster\n\tptr = (char *) GetClearedMemory(\n\t\t\t\taasworld.numclusters * sizeof(aas_routingcache_t **) +\n\t\t\t\tsize * sizeof(aas_routingcache_t *));\n\taasworld.clusterareacache = (aas_routingcache_t ***) ptr;\n\tptr += aasworld.numclusters * sizeof(aas_routingcache_t **);\n\tfor (i = 0; i < aasworld.numclusters; i++)\n\t{\n\t\taasworld.clusterareacache[i] = (aas_routingcache_t **) ptr;\n\t\tptr += aasworld.clusters[i].numareas * sizeof(aas_routingcache_t *);\n\t} //end for\n} //end of the function AAS_InitClusterAreaCache\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_FreeAllPortalCache(void)\n{\n\tint i;\n\taas_routingcache_t *cache, *nextcache;\n\n\t//free all portal cache if existing\n\tif (!aasworld.portalcache) return;\n\t//free portal caches\n\tfor (i = 0; i < aasworld.numareas; i++)\n\t{\n\t\tfor (cache = aasworld.portalcache[i]; cache; cache = nextcache)\n\t\t{\n\t\t\tnextcache = cache->next;\n\t\t\tAAS_FreeRoutingCache(cache);\n\t\t} //end for\n\t\taasworld.portalcache[i] = NULL;\n\t} //end for\n\tFreeMemory(aasworld.portalcache);\n\taasworld.portalcache = NULL;\n} //end of the function AAS_FreeAllPortalCache\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_InitPortalCache(void)\n{\n\t//\n\taasworld.portalcache = (aas_routingcache_t **) GetClearedMemory(\n\t\t\t\t\t\t\t\taasworld.numareas * sizeof(aas_routingcache_t *));\n} //end of the function AAS_InitPortalCache\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_InitRoutingUpdate(void)\n{\n\tint i, maxreachabilityareas;\n\n\t//free routing update fields if already existing\n\tif (aasworld.areaupdate) FreeMemory(aasworld.areaupdate);\n\t//\n\tmaxreachabilityareas = 0;\n\tfor (i = 0; i < aasworld.numclusters; i++)\n\t{\n\t\tif (aasworld.clusters[i].numreachabilityareas > maxreachabilityareas)\n\t\t{\n\t\t\tmaxreachabilityareas = aasworld.clusters[i].numreachabilityareas;\n\t\t} //end if\n\t} //end for\n\t//allocate memory for the routing update fields\n\taasworld.areaupdate = (aas_routingupdate_t *) GetClearedMemory(\n\t\t\t\t\t\t\t\t\tmaxreachabilityareas * sizeof(aas_routingupdate_t));\n\t//\n\tif (aasworld.portalupdate) FreeMemory(aasworld.portalupdate);\n\t//allocate memory for the portal update fields\n\taasworld.portalupdate = (aas_routingupdate_t *) GetClearedMemory(\n\t\t\t\t\t\t\t\t\t(aasworld.numportals+1) * sizeof(aas_routingupdate_t));\n} //end of the function AAS_InitRoutingUpdate\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_CreateAllRoutingCache(void)\n{\n\tint i, j, t;\n\n\taasworld.initialized = qtrue;\n\tbotimport.Print(PRT_MESSAGE, \"AAS_CreateAllRoutingCache\\n\");\n\tfor (i = 1; i < aasworld.numareas; i++)\n\t{\n\t\tif (!AAS_AreaReachability(i)) continue;\n\t\tfor (j = 1; j < aasworld.numareas; j++)\n\t\t{\n\t\t\tif (i == j) continue;\n\t\t\tif (!AAS_AreaReachability(j)) continue;\n\t\t\tt = AAS_AreaTravelTimeToGoalArea(i, aasworld.areas[i].center, j, TFL_DEFAULT);\n\t\t\t//Log_Write(\"traveltime from %d to %d is %d\", i, j, t);\n\t\t} //end for\n\t} //end for\n\taasworld.initialized = qfalse;\n} //end of the function AAS_CreateAllRoutingCache\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\n\n//the route cache header\n//this header is followed by numportalcache + numareacache aas_routingcache_t\n//structures that store routing cache\ntypedef struct routecacheheader_s\n{\n\tint ident;\n\tint version;\n\tint numareas;\n\tint numclusters;\n\tint areacrc;\n\tint clustercrc;\n\tint numportalcache;\n\tint numareacache;\n} routecacheheader_t;\n\n#define RCID\t\t\t\t\t\t(('C'<<24)+('R'<<16)+('E'<<8)+'M')\n#define RCVERSION\t\t\t\t\t2\n\n//void AAS_DecompressVis(byte *in, int numareas, byte *decompressed);\n//int AAS_CompressVis(byte *vis, int numareas, byte *dest);\n\nvoid AAS_WriteRouteCache(void)\n{\n\tint i, j, numportalcache, numareacache, totalsize;\n\taas_routingcache_t *cache;\n\taas_cluster_t *cluster;\n\tfileHandle_t fp;\n\tchar filename[MAX_QPATH];\n\troutecacheheader_t routecacheheader;\n\n\tnumportalcache = 0;\n\tfor (i = 0; i < aasworld.numareas; i++)\n\t{\n\t\tfor (cache = aasworld.portalcache[i]; cache; cache = cache->next)\n\t\t{\n\t\t\tnumportalcache++;\n\t\t} //end for\n\t} //end for\n\tnumareacache = 0;\n\tfor (i = 0; i < aasworld.numclusters; i++)\n\t{\n\t\tcluster = &aasworld.clusters[i];\n\t\tfor (j = 0; j < cluster->numareas; j++)\n\t\t{\n\t\t\tfor (cache = aasworld.clusterareacache[i][j]; cache; cache = cache->next)\n\t\t\t{\n\t\t\t\tnumareacache++;\n\t\t\t} //end for\n\t\t} //end for\n\t} //end for\n\t// open the file for writing\n\tCom_sprintf(filename, MAX_QPATH, \"maps/%s.rcd\", aasworld.mapname);\n\tbotimport.FS_FOpenFile( filename, &fp, FS_WRITE );\n\tif (!fp)\n\t{\n\t\tAAS_Error(\"Unable to open file: %s\\n\", filename);\n\t\treturn;\n\t} //end if\n\t//create the header\n\troutecacheheader.ident = RCID;\n\troutecacheheader.version = RCVERSION;\n\troutecacheheader.numareas = aasworld.numareas;\n\troutecacheheader.numclusters = aasworld.numclusters;\n\troutecacheheader.areacrc = CRC_ProcessString( (unsigned char *)aasworld.areas, sizeof(aas_area_t) * aasworld.numareas );\n\troutecacheheader.clustercrc = CRC_ProcessString( (unsigned char *)aasworld.clusters, sizeof(aas_cluster_t) * aasworld.numclusters );\n\troutecacheheader.numportalcache = numportalcache;\n\troutecacheheader.numareacache = numareacache;\n\t//write the header\n\tbotimport.FS_Write(&routecacheheader, sizeof(routecacheheader_t), fp);\n\t//\n\ttotalsize = 0;\n\t//write all the cache\n\tfor (i = 0; i < aasworld.numareas; i++)\n\t{\n\t\tfor (cache = aasworld.portalcache[i]; cache; cache = cache->next)\n\t\t{\n\t\t\tbotimport.FS_Write(cache, cache->size, fp);\n\t\t\ttotalsize += cache->size;\n\t\t} //end for\n\t} //end for\n\tfor (i = 0; i < aasworld.numclusters; i++)\n\t{\n\t\tcluster = &aasworld.clusters[i];\n\t\tfor (j = 0; j < cluster->numareas; j++)\n\t\t{\n\t\t\tfor (cache = aasworld.clusterareacache[i][j]; cache; cache = cache->next)\n\t\t\t{\n\t\t\t\tbotimport.FS_Write(cache, cache->size, fp);\n\t\t\t\ttotalsize += cache->size;\n\t\t\t} //end for\n\t\t} //end for\n\t} //end for\n\t// write the visareas\n\t/*\n\tfor (i = 0; i < aasworld.numareas; i++)\n\t{\n\t\tif (!aasworld.areavisibility[i]) {\n\t\t\tsize = 0;\n\t\t\tbotimport.FS_Write(&size, sizeof(int), fp);\n\t\t\tcontinue;\n\t\t}\n\t\tAAS_DecompressVis( aasworld.areavisibility[i], aasworld.numareas, aasworld.decompressedvis );\n\t\tsize = AAS_CompressVis( aasworld.decompressedvis, aasworld.numareas, aasworld.decompressedvis );\n\t\tbotimport.FS_Write(&size, sizeof(int), fp);\n\t\tbotimport.FS_Write(aasworld.decompressedvis, size, fp);\n\t}\n\t*/\n\t//\n\tbotimport.FS_FCloseFile(fp);\n\tbotimport.Print(PRT_MESSAGE, \"\\nroute cache written to %s\\n\", filename);\n\tbotimport.Print(PRT_MESSAGE, \"written %d bytes of routing cache\\n\", totalsize);\n} //end of the function AAS_WriteRouteCache\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\naas_routingcache_t *AAS_ReadCache(fileHandle_t fp)\n{\n\tint size;\n\taas_routingcache_t *cache;\n\n\tbotimport.FS_Read(&size, sizeof(size), fp);\n\tcache = (aas_routingcache_t *) GetMemory(size);\n\tcache->size = size;\n\tbotimport.FS_Read((unsigned char *)cache + sizeof(size), size - sizeof(size), fp);\n\tcache->reachabilities = (unsigned char *) cache + sizeof(aas_routingcache_t) - sizeof(unsigned short) +\n\t\t(size - sizeof(aas_routingcache_t) + sizeof(unsigned short)) / 3 * 2;\n\treturn cache;\n} //end of the function AAS_ReadCache\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_ReadRouteCache(void)\n{\n\tint i, clusterareanum;//, size;\n\tfileHandle_t fp;\n\tchar filename[MAX_QPATH];\n\troutecacheheader_t routecacheheader;\n\taas_routingcache_t *cache;\n\n\tCom_sprintf(filename, MAX_QPATH, \"maps/%s.rcd\", aasworld.mapname);\n\tbotimport.FS_FOpenFile( filename, &fp, FS_READ );\n\tif (!fp)\n\t{\n\t\treturn qfalse;\n\t} //end if\n\tbotimport.FS_Read(&routecacheheader, sizeof(routecacheheader_t), fp );\n\tif (routecacheheader.ident != RCID)\n\t{\n\t\tAAS_Error(\"%s is not a route cache dump\\n\");\n\t\treturn qfalse;\n\t} //end if\n\tif (routecacheheader.version != RCVERSION)\n\t{\n\t\tAAS_Error(\"route cache dump has wrong version %d, should be %d\", routecacheheader.version, RCVERSION);\n\t\treturn qfalse;\n\t} //end if\n\tif (routecacheheader.numareas != aasworld.numareas)\n\t{\n\t\t//AAS_Error(\"route cache dump has wrong number of areas\\n\");\n\t\treturn qfalse;\n\t} //end if\n\tif (routecacheheader.numclusters != aasworld.numclusters)\n\t{\n\t\t//AAS_Error(\"route cache dump has wrong number of clusters\\n\");\n\t\treturn qfalse;\n\t} //end if\n\tif (routecacheheader.areacrc !=\n\t\tCRC_ProcessString( (unsigned char *)aasworld.areas, sizeof(aas_area_t) * aasworld.numareas ))\n\t{\n\t\t//AAS_Error(\"route cache dump area CRC incorrect\\n\");\n\t\treturn qfalse;\n\t} //end if\n\tif (routecacheheader.clustercrc !=\n\t\tCRC_ProcessString( (unsigned char *)aasworld.clusters, sizeof(aas_cluster_t) * aasworld.numclusters ))\n\t{\n\t\t//AAS_Error(\"route cache dump cluster CRC incorrect\\n\");\n\t\treturn qfalse;\n\t} //end if\n\t//read all the portal cache\n\tfor (i = 0; i < routecacheheader.numportalcache; i++)\n\t{\n\t\tcache = AAS_ReadCache(fp);\n\t\tcache->next = aasworld.portalcache[cache->areanum];\n\t\tcache->prev = NULL;\n\t\tif (aasworld.portalcache[cache->areanum])\n\t\t\taasworld.portalcache[cache->areanum]->prev = cache;\n\t\taasworld.portalcache[cache->areanum] = cache;\n\t} //end for\n\t//read all the cluster area cache\n\tfor (i = 0; i < routecacheheader.numareacache; i++)\n\t{\n\t\tcache = AAS_ReadCache(fp);\n\t\tclusterareanum = AAS_ClusterAreaNum(cache->cluster, cache->areanum);\n\t\tcache->next = aasworld.clusterareacache[cache->cluster][clusterareanum];\n\t\tcache->prev = NULL;\n\t\tif (aasworld.clusterareacache[cache->cluster][clusterareanum])\n\t\t\taasworld.clusterareacache[cache->cluster][clusterareanum]->prev = cache;\n\t\taasworld.clusterareacache[cache->cluster][clusterareanum] = cache;\n\t} //end for\n\t// read the visareas\n\t/*\n\taasworld.areavisibility = (byte **) GetClearedMemory(aasworld.numareas * sizeof(byte *));\n\taasworld.decompressedvis = (byte *) GetClearedMemory(aasworld.numareas * sizeof(byte));\n\tfor (i = 0; i < aasworld.numareas; i++)\n\t{\n\t\tbotimport.FS_Read(&size, sizeof(size), fp );\n\t\tif (size) {\n\t\t\taasworld.areavisibility[i] = (byte *) GetMemory(size);\n\t\t\tbotimport.FS_Read(aasworld.areavisibility[i], size, fp );\n\t\t}\n\t}\n\t*/\n\t//\n\tbotimport.FS_FCloseFile(fp);\n\treturn qtrue;\n} //end of the function AAS_ReadRouteCache\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\n#define MAX_REACHABILITYPASSAREAS\t\t32\n\nvoid AAS_InitReachabilityAreas(void)\n{\n\tint i, j, numareas, areas[MAX_REACHABILITYPASSAREAS];\n\tint numreachareas;\n\taas_reachability_t *reach;\n\tvec3_t start, end;\n\n\tif (aasworld.reachabilityareas)\n\t\tFreeMemory(aasworld.reachabilityareas);\n\tif (aasworld.reachabilityareaindex)\n\t\tFreeMemory(aasworld.reachabilityareaindex);\n\n\taasworld.reachabilityareas = (aas_reachabilityareas_t *)\n\t\t\t\tGetClearedMemory(aasworld.reachabilitysize * sizeof(aas_reachabilityareas_t));\n\taasworld.reachabilityareaindex = (int *)\n\t\t\t\tGetClearedMemory(aasworld.reachabilitysize * MAX_REACHABILITYPASSAREAS * sizeof(int));\n\tnumreachareas = 0;\n\tfor (i = 0; i < aasworld.reachabilitysize; i++)\n\t{\n\t\treach = &aasworld.reachability[i];\n\t\tnumareas = 0;\n\t\tswitch(reach->traveltype & TRAVELTYPE_MASK)\n\t\t{\n\t\t\t//trace areas from start to end\n\t\t\tcase TRAVEL_BARRIERJUMP:\n\t\t\tcase TRAVEL_WATERJUMP:\n\t\t\t\tVectorCopy(reach->start, end);\n\t\t\t\tend[2] = reach->end[2];\n\t\t\t\tnumareas = AAS_TraceAreas(reach->start, end, areas, NULL, MAX_REACHABILITYPASSAREAS);\n\t\t\t\tbreak;\n\t\t\tcase TRAVEL_WALKOFFLEDGE:\n\t\t\t\tVectorCopy(reach->end, start);\n\t\t\t\tstart[2] = reach->start[2];\n\t\t\t\tnumareas = AAS_TraceAreas(start, reach->end, areas, NULL, MAX_REACHABILITYPASSAREAS);\n\t\t\t\tbreak;\n\t\t\tcase TRAVEL_GRAPPLEHOOK:\n\t\t\t\tnumareas = AAS_TraceAreas(reach->start, reach->end, areas, NULL, MAX_REACHABILITYPASSAREAS);\n\t\t\t\tbreak;\n\n\t\t\t//trace arch\n\t\t\tcase TRAVEL_JUMP: break;\n\t\t\tcase TRAVEL_ROCKETJUMP: break;\n\t\t\tcase TRAVEL_BFGJUMP: break;\n\t\t\tcase TRAVEL_JUMPPAD: break;\n\n\t\t\t//trace from reach->start to entity center, along entity movement\n\t\t\t//and from entity center to reach->end\n\t\t\tcase TRAVEL_ELEVATOR: break;\n\t\t\tcase TRAVEL_FUNCBOB: break;\n\n\t\t\t//no areas in between\n\t\t\tcase TRAVEL_WALK: break;\n\t\t\tcase TRAVEL_CROUCH: break;\n\t\t\tcase TRAVEL_LADDER: break;\n\t\t\tcase TRAVEL_SWIM: break;\n\t\t\tcase TRAVEL_TELEPORT: break;\n\t\t\tdefault: break;\n\t\t} //end switch\n\t\taasworld.reachabilityareas[i].firstarea = numreachareas;\n\t\taasworld.reachabilityareas[i].numareas = numareas;\n\t\tfor (j = 0; j < numareas; j++)\n\t\t{\n\t\t\taasworld.reachabilityareaindex[numreachareas++] = areas[j];\n\t\t} //end for\n\t} //end for\n} //end of the function AAS_InitReachabilityAreas\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_InitRouting(void)\n{\n\tAAS_InitTravelFlagFromType();\n\t//\n\tAAS_InitAreaContentsTravelFlags();\n\t//initialize the routing update fields\n\tAAS_InitRoutingUpdate();\n\t//create reversed reachability links used by the routing update algorithm\n\tAAS_CreateReversedReachability();\n\t//initialize the cluster cache\n\tAAS_InitClusterAreaCache();\n\t//initialize portal cache\n\tAAS_InitPortalCache();\n\t//initialize the area travel times\n\tAAS_CalculateAreaTravelTimes();\n\t//calculate the maximum travel times through portals\n\tAAS_InitPortalMaxTravelTimes();\n\t//get the areas reachabilities go through\n\tAAS_InitReachabilityAreas();\n\t//\n#ifdef ROUTING_DEBUG\n\tnumareacacheupdates = 0;\n\tnumportalcacheupdates = 0;\n#endif //ROUTING_DEBUG\n\t//\n\troutingcachesize = 0;\n\tmax_routingcachesize = 1024 * (int) LibVarValue(\"max_routingcache\", \"4096\");\n\t// read any routing cache if available\n\tAAS_ReadRouteCache();\n} //end of the function AAS_InitRouting\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_FreeRoutingCaches(void)\n{\n\t// free all the existing cluster area cache\n\tAAS_FreeAllClusterAreaCache();\n\t// free all the existing portal cache\n\tAAS_FreeAllPortalCache();\n\t// free cached travel times within areas\n\tif (aasworld.areatraveltimes) FreeMemory(aasworld.areatraveltimes);\n\taasworld.areatraveltimes = NULL;\n\t// free cached maximum travel time through cluster portals\n\tif (aasworld.portalmaxtraveltimes) FreeMemory(aasworld.portalmaxtraveltimes);\n\taasworld.portalmaxtraveltimes = NULL;\n\t// free reversed reachability links\n\tif (aasworld.reversedreachability) FreeMemory(aasworld.reversedreachability);\n\taasworld.reversedreachability = NULL;\n\t// free routing algorithm memory\n\tif (aasworld.areaupdate) FreeMemory(aasworld.areaupdate);\n\taasworld.areaupdate = NULL;\n\tif (aasworld.portalupdate) FreeMemory(aasworld.portalupdate);\n\taasworld.portalupdate = NULL;\n\t// free lists with areas the reachabilities go through\n\tif (aasworld.reachabilityareas) FreeMemory(aasworld.reachabilityareas);\n\taasworld.reachabilityareas = NULL;\n\t// free the reachability area index\n\tif (aasworld.reachabilityareaindex) FreeMemory(aasworld.reachabilityareaindex);\n\taasworld.reachabilityareaindex = NULL;\n\t// free area contents travel flags look up table\n\tif (aasworld.areacontentstravelflags) FreeMemory(aasworld.areacontentstravelflags);\n\taasworld.areacontentstravelflags = NULL;\n} //end of the function AAS_FreeRoutingCaches\n//===========================================================================\n// update the given routing cache\n//\n// Parameter:\t\t\tareacache\t\t: routing cache to update\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_UpdateAreaRoutingCache(aas_routingcache_t *areacache)\n{\n\tint i, nextareanum, cluster, badtravelflags, clusterareanum, linknum;\n\tint numreachabilityareas;\n\tunsigned short int t, startareatraveltimes[128]; //NOTE: not more than 128 reachabilities per area allowed\n\taas_routingupdate_t *updateliststart, *updatelistend, *curupdate, *nextupdate;\n\taas_reachability_t *reach;\n\taas_reversedreachability_t *revreach;\n\taas_reversedlink_t *revlink;\n\n#ifdef ROUTING_DEBUG\n\tnumareacacheupdates++;\n#endif //ROUTING_DEBUG\n\t//number of reachability areas within this cluster\n\tnumreachabilityareas = aasworld.clusters[areacache->cluster].numreachabilityareas;\n\t//\n\taasworld.frameroutingupdates++;\n\t//clear the routing update fields\n//\tCom_Memset(aasworld.areaupdate, 0, aasworld.numareas * sizeof(aas_routingupdate_t));\n\t//\n\tbadtravelflags = ~areacache->travelflags;\n\t//\n\tclusterareanum = AAS_ClusterAreaNum(areacache->cluster, areacache->areanum);\n\tif (clusterareanum >= numreachabilityareas) return;\n\t//\n\tCom_Memset(startareatraveltimes, 0, sizeof(startareatraveltimes));\n\t//\n\tcurupdate = &aasworld.areaupdate[clusterareanum];\n\tcurupdate->areanum = areacache->areanum;\n\t//VectorCopy(areacache->origin, curupdate->start);\n\tcurupdate->areatraveltimes = startareatraveltimes;\n\tcurupdate->tmptraveltime = areacache->starttraveltime;\n\t//\n\tareacache->traveltimes[clusterareanum] = areacache->starttraveltime;\n\t//put the area to start with in the current read list\n\tcurupdate->next = NULL;\n\tcurupdate->prev = NULL;\n\tupdateliststart = curupdate;\n\tupdatelistend = curupdate;\n\t//while there are updates in the current list\n\twhile (updateliststart)\n\t{\n\t\tcurupdate = updateliststart;\n\t\t//\n\t\tif (curupdate->next) curupdate->next->prev = NULL;\n\t\telse updatelistend = NULL;\n\t\tupdateliststart = curupdate->next;\n\t\t//\n\t\tcurupdate->inlist = qfalse;\n\t\t//check all reversed reachability links\n\t\trevreach = &aasworld.reversedreachability[curupdate->areanum];\n\t\t//\n\t\tfor (i = 0, revlink = revreach->first; revlink; revlink = revlink->next, i++)\n\t\t{\n\t\t\tlinknum = revlink->linknum;\n\t\t\treach = &aasworld.reachability[linknum];\n\t\t\t//if there is used an undesired travel type\n\t\t\tif (AAS_TravelFlagForType_inline(reach->traveltype) & badtravelflags) continue;\n\t\t\t//if not allowed to enter the next area\n\t\t\tif (aasworld.areasettings[reach->areanum].areaflags & AREA_DISABLED) continue;\n\t\t\t//if the next area has a not allowed travel flag\n\t\t\tif (AAS_AreaContentsTravelFlags_inline(reach->areanum) & badtravelflags) continue;\n\t\t\t//number of the area the reversed reachability leads to\n\t\t\tnextareanum = revlink->areanum;\n\t\t\t//get the cluster number of the area\n\t\t\tcluster = aasworld.areasettings[nextareanum].cluster;\n\t\t\t//don't leave the cluster\n\t\t\tif (cluster > 0 && cluster != areacache->cluster) continue;\n\t\t\t//get the number of the area in the cluster\n\t\t\tclusterareanum = AAS_ClusterAreaNum(areacache->cluster, nextareanum);\n\t\t\tif (clusterareanum >= numreachabilityareas) continue;\n\t\t\t//time already travelled plus the traveltime through\n\t\t\t//the current area plus the travel time from the reachability\n\t\t\tt = curupdate->tmptraveltime +\n\t\t\t\t\t\t//AAS_AreaTravelTime(curupdate->areanum, curupdate->start, reach->end) +\n\t\t\t\t\t\tcurupdate->areatraveltimes[i] +\n\t\t\t\t\t\t\treach->traveltime;\n\t\t\t//\n\t\t\tif (!areacache->traveltimes[clusterareanum] ||\n\t\t\t\t\tareacache->traveltimes[clusterareanum] > t)\n\t\t\t{\n\t\t\t\tareacache->traveltimes[clusterareanum] = t;\n\t\t\t\tareacache->reachabilities[clusterareanum] = linknum - aasworld.areasettings[nextareanum].firstreachablearea;\n\t\t\t\tnextupdate = &aasworld.areaupdate[clusterareanum];\n\t\t\t\tnextupdate->areanum = nextareanum;\n\t\t\t\tnextupdate->tmptraveltime = t;\n\t\t\t\t//VectorCopy(reach->start, nextupdate->start);\n\t\t\t\tnextupdate->areatraveltimes = aasworld.areatraveltimes[nextareanum][linknum -\n\t\t\t\t\t\t\t\t\t\t\t\t\taasworld.areasettings[nextareanum].firstreachablearea];\n\t\t\t\tif (!nextupdate->inlist)\n\t\t\t\t{\n\t\t\t\t\t// we add the update to the end of the list\n\t\t\t\t\t// we could also use a B+ tree to have a real sorted list\n\t\t\t\t\t// on travel time which makes for faster routing updates\n\t\t\t\t\tnextupdate->next = NULL;\n\t\t\t\t\tnextupdate->prev = updatelistend;\n\t\t\t\t\tif (updatelistend) updatelistend->next = nextupdate;\n\t\t\t\t\telse updateliststart = nextupdate;\n\t\t\t\t\tupdatelistend = nextupdate;\n\t\t\t\t\tnextupdate->inlist = qtrue;\n\t\t\t\t} //end if\n\t\t\t} //end if\n\t\t} //end for\n\t} //end while\n} //end of the function AAS_UpdateAreaRoutingCache\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\naas_routingcache_t *AAS_GetAreaRoutingCache(int clusternum, int areanum, int travelflags)\n{\n\tint clusterareanum;\n\taas_routingcache_t *cache, *clustercache;\n\n\t//number of the area in the cluster\n\tclusterareanum = AAS_ClusterAreaNum(clusternum, areanum);\n\t//pointer to the cache for the area in the cluster\n\tclustercache = aasworld.clusterareacache[clusternum][clusterareanum];\n\t//find the cache without undesired travel flags\n\tfor (cache = clustercache; cache; cache = cache->next)\n\t{\n\t\t//if there aren't used any undesired travel types for the cache\n\t\tif (cache->travelflags == travelflags) break;\n\t} //end for\n\t//if there was no cache\n\tif (!cache)\n\t{\n\t\tcache = AAS_AllocRoutingCache(aasworld.clusters[clusternum].numreachabilityareas);\n\t\tcache->cluster = clusternum;\n\t\tcache->areanum = areanum;\n\t\tVectorCopy(aasworld.areas[areanum].center, cache->origin);\n\t\tcache->starttraveltime = 1;\n\t\tcache->travelflags = travelflags;\n\t\tcache->prev = NULL;\n\t\tcache->next = clustercache;\n\t\tif (clustercache) clustercache->prev = cache;\n\t\taasworld.clusterareacache[clusternum][clusterareanum] = cache;\n\t\tAAS_UpdateAreaRoutingCache(cache);\n\t} //end if\n\telse\n\t{\n\t\tAAS_UnlinkCache(cache);\n\t} //end else\n\t//the cache has been accessed\n\tcache->time = AAS_RoutingTime();\n\tcache->type = CACHETYPE_AREA;\n\tAAS_LinkCache(cache);\n\treturn cache;\n} //end of the function AAS_GetAreaRoutingCache\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_UpdatePortalRoutingCache(aas_routingcache_t *portalcache)\n{\n\tint i, portalnum, clusterareanum, clusternum;\n\tunsigned short int t;\n\taas_portal_t *portal;\n\taas_cluster_t *cluster;\n\taas_routingcache_t *cache;\n\taas_routingupdate_t *updateliststart, *updatelistend, *curupdate, *nextupdate;\n\n#ifdef ROUTING_DEBUG\n\tnumportalcacheupdates++;\n#endif //ROUTING_DEBUG\n\t//clear the routing update fields\n//\tCom_Memset(aasworld.portalupdate, 0, (aasworld.numportals+1) * sizeof(aas_routingupdate_t));\n\t//\n\tcurupdate = &aasworld.portalupdate[aasworld.numportals];\n\tcurupdate->cluster = portalcache->cluster;\n\tcurupdate->areanum = portalcache->areanum;\n\tcurupdate->tmptraveltime = portalcache->starttraveltime;\n\t//if the start area is a cluster portal, store the travel time for that portal\n\tclusternum = aasworld.areasettings[portalcache->areanum].cluster;\n\tif (clusternum < 0)\n\t{\n\t\tportalcache->traveltimes[-clusternum] = portalcache->starttraveltime;\n\t} //end if\n\t//put the area to start with in the current read list\n\tcurupdate->next = NULL;\n\tcurupdate->prev = NULL;\n\tupdateliststart = curupdate;\n\tupdatelistend = curupdate;\n\t//while there are updates in the current list\n\twhile (updateliststart)\n\t{\n\t\tcurupdate = updateliststart;\n\t\t//remove the current update from the list\n\t\tif (curupdate->next) curupdate->next->prev = NULL;\n\t\telse updatelistend = NULL;\n\t\tupdateliststart = curupdate->next;\n\t\t//current update is removed from the list\n\t\tcurupdate->inlist = qfalse;\n\t\t//\n\t\tcluster = &aasworld.clusters[curupdate->cluster];\n\t\t//\n\t\tcache = AAS_GetAreaRoutingCache(curupdate->cluster,\n\t\t\t\t\t\t\t\tcurupdate->areanum, portalcache->travelflags);\n\t\t//take all portals of the cluster\n\t\tfor (i = 0; i < cluster->numportals; i++)\n\t\t{\n\t\t\tportalnum = aasworld.portalindex[cluster->firstportal + i];\n\t\t\tportal = &aasworld.portals[portalnum];\n\t\t\t//if this is the portal of the current update continue\n\t\t\tif (portal->areanum == curupdate->areanum) continue;\n\t\t\t//\n\t\t\tclusterareanum = AAS_ClusterAreaNum(curupdate->cluster, portal->areanum);\n\t\t\tif (clusterareanum >= cluster->numreachabilityareas) continue;\n\t\t\t//\n\t\t\tt = cache->traveltimes[clusterareanum];\n\t\t\tif (!t) continue;\n\t\t\tt += curupdate->tmptraveltime;\n\t\t\t//\n\t\t\tif (!portalcache->traveltimes[portalnum] ||\n\t\t\t\t\tportalcache->traveltimes[portalnum] > t)\n\t\t\t{\n\t\t\t\tportalcache->traveltimes[portalnum] = t;\n\t\t\t\tnextupdate = &aasworld.portalupdate[portalnum];\n\t\t\t\tif (portal->frontcluster == curupdate->cluster)\n\t\t\t\t{\n\t\t\t\t\tnextupdate->cluster = portal->backcluster;\n\t\t\t\t} //end if\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tnextupdate->cluster = portal->frontcluster;\n\t\t\t\t} //end else\n\t\t\t\tnextupdate->areanum = portal->areanum;\n\t\t\t\t//add travel time through the actual portal area for the next update\n\t\t\t\tnextupdate->tmptraveltime = t + aasworld.portalmaxtraveltimes[portalnum];\n\t\t\t\tif (!nextupdate->inlist)\n\t\t\t\t{\n\t\t\t\t\t// we add the update to the end of the list\n\t\t\t\t\t// we could also use a B+ tree to have a real sorted list\n\t\t\t\t\t// on travel time which makes for faster routing updates\n\t\t\t\t\tnextupdate->next = NULL;\n\t\t\t\t\tnextupdate->prev = updatelistend;\n\t\t\t\t\tif (updatelistend) updatelistend->next = nextupdate;\n\t\t\t\t\telse updateliststart = nextupdate;\n\t\t\t\t\tupdatelistend = nextupdate;\n\t\t\t\t\tnextupdate->inlist = qtrue;\n\t\t\t\t} //end if\n\t\t\t} //end if\n\t\t} //end for\n\t} //end while\n} //end of the function AAS_UpdatePortalRoutingCache\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\naas_routingcache_t *AAS_GetPortalRoutingCache(int clusternum, int areanum, int travelflags)\n{\n\taas_routingcache_t *cache;\n\n\t//find the cached portal routing if existing\n\tfor (cache = aasworld.portalcache[areanum]; cache; cache = cache->next)\n\t{\n\t\tif (cache->travelflags == travelflags) break;\n\t} //end for\n\t//if the portal routing isn't cached\n\tif (!cache)\n\t{\n\t\tcache = AAS_AllocRoutingCache(aasworld.numportals);\n\t\tcache->cluster = clusternum;\n\t\tcache->areanum = areanum;\n\t\tVectorCopy(aasworld.areas[areanum].center, cache->origin);\n\t\tcache->starttraveltime = 1;\n\t\tcache->travelflags = travelflags;\n\t\t//add the cache to the cache list\n\t\tcache->prev = NULL;\n\t\tcache->next = aasworld.portalcache[areanum];\n\t\tif (aasworld.portalcache[areanum]) aasworld.portalcache[areanum]->prev = cache;\n\t\taasworld.portalcache[areanum] = cache;\n\t\t//update the cache\n\t\tAAS_UpdatePortalRoutingCache(cache);\n\t} //end if\n\telse\n\t{\n\t\tAAS_UnlinkCache(cache);\n\t} //end else\n\t//the cache has been accessed\n\tcache->time = AAS_RoutingTime();\n\tcache->type = CACHETYPE_PORTAL;\n\tAAS_LinkCache(cache);\n\treturn cache;\n} //end of the function AAS_GetPortalRoutingCache\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_AreaRouteToGoalArea(int areanum, vec3_t origin, int goalareanum, int travelflags, int *traveltime, int *reachnum)\n{\n\tint clusternum, goalclusternum, portalnum, i, clusterareanum, bestreachnum;\n\tunsigned short int t, besttime;\n\taas_portal_t *portal;\n\taas_cluster_t *cluster;\n\taas_routingcache_t *areacache, *portalcache;\n\taas_reachability_t *reach;\n\n\tif (!aasworld.initialized) return qfalse;\n\n\tif (areanum == goalareanum)\n\t{\n\t\t*traveltime = 1;\n\t\t*reachnum = 0;\n\t\treturn qtrue;\n\t}\n\t//\n\tif (areanum <= 0 || areanum >= aasworld.numareas)\n\t{\n\t\tif (bot_developer)\n\t\t{\n\t\t\tbotimport.Print(PRT_ERROR, \"AAS_AreaTravelTimeToGoalArea: areanum %d out of range\\n\", areanum);\n\t\t} //end if\n\t\treturn qfalse;\n\t} //end if\n\tif (goalareanum <= 0 || goalareanum >= aasworld.numareas)\n\t{\n\t\tif (bot_developer)\n\t\t{\n\t\t\tbotimport.Print(PRT_ERROR, \"AAS_AreaTravelTimeToGoalArea: goalareanum %d out of range\\n\", goalareanum);\n\t\t} //end if\n\t\treturn qfalse;\n\t} //end if\n\t// make sure the routing cache doesn't grow to large\n\twhile(AvailableMemory() < 1 * 1024 * 1024) {\n\t\tif (!AAS_FreeOldestCache()) break;\n\t}\n\t//\n\tif (AAS_AreaDoNotEnter(areanum) || AAS_AreaDoNotEnter(goalareanum))\n\t{\n\t\ttravelflags |= TFL_DONOTENTER;\n\t} //end if\n\t//NOTE: the number of routing updates is limited per frame\n\t/*\n\tif (aasworld.frameroutingupdates > MAX_FRAMEROUTINGUPDATES)\n\t{\n#ifdef DEBUG\n\t\t//Log_Write(\"WARNING: AAS_AreaTravelTimeToGoalArea: frame routing updates overflowed\");\n#endif\n\t\treturn 0;\n\t} //end if\n\t*/\n\t//\n\tclusternum = aasworld.areasettings[areanum].cluster;\n\tgoalclusternum = aasworld.areasettings[goalareanum].cluster;\n\t//check if the area is a portal of the goal area cluster\n\tif (clusternum < 0 && goalclusternum > 0)\n\t{\n\t\tportal = &aasworld.portals[-clusternum];\n\t\tif (portal->frontcluster == goalclusternum ||\n\t\t\t\tportal->backcluster == goalclusternum)\n\t\t{\n\t\t\tclusternum = goalclusternum;\n\t\t} //end if\n\t} //end if\n\t//check if the goalarea is a portal of the area cluster\n\telse if (clusternum > 0 && goalclusternum < 0)\n\t{\n\t\tportal = &aasworld.portals[-goalclusternum];\n\t\tif (portal->frontcluster == clusternum ||\n\t\t\t\tportal->backcluster == clusternum)\n\t\t{\n\t\t\tgoalclusternum = clusternum;\n\t\t} //end if\n\t} //end if\n\t//if both areas are in the same cluster\n\t//NOTE: there might be a shorter route via another cluster!!! but we don't care\n\tif (clusternum > 0 && goalclusternum > 0 && clusternum == goalclusternum)\n\t{\n\t\t//\n\t\tareacache = AAS_GetAreaRoutingCache(clusternum, goalareanum, travelflags);\n\t\t//the number of the area in the cluster\n\t\tclusterareanum = AAS_ClusterAreaNum(clusternum, areanum);\n\t\t//the cluster the area is in\n\t\tcluster = &aasworld.clusters[clusternum];\n\t\t//if the area is NOT a reachability area\n\t\tif (clusterareanum >= cluster->numreachabilityareas) return 0;\n\t\t//if it is possible to travel to the goal area through this cluster\n\t\tif (areacache->traveltimes[clusterareanum] != 0)\n\t\t{\n\t\t\t*reachnum = aasworld.areasettings[areanum].firstreachablearea +\n\t\t\t\t\t\t\tareacache->reachabilities[clusterareanum];\n\t\t\tif (!origin) {\n\t\t\t\t*traveltime = areacache->traveltimes[clusterareanum];\n\t\t\t\treturn qtrue;\n\t\t\t}\n\t\t\treach = &aasworld.reachability[*reachnum];\n\t\t\t*traveltime = areacache->traveltimes[clusterareanum] +\n\t\t\t\t\t\t\tAAS_AreaTravelTime(areanum, origin, reach->start);\n\t\t\t//\n\t\t\treturn qtrue;\n\t\t} //end if\n\t} //end if\n\t//\n\tclusternum = aasworld.areasettings[areanum].cluster;\n\tgoalclusternum = aasworld.areasettings[goalareanum].cluster;\n\t//if the goal area is a portal\n\tif (goalclusternum < 0)\n\t{\n\t\t//just assume the goal area is part of the front cluster\n\t\tportal = &aasworld.portals[-goalclusternum];\n\t\tgoalclusternum = portal->frontcluster;\n\t} //end if\n\t//get the portal routing cache\n\tportalcache = AAS_GetPortalRoutingCache(goalclusternum, goalareanum, travelflags);\n\t//if the area is a cluster portal, read directly from the portal cache\n\tif (clusternum < 0)\n\t{\n\t\t*traveltime = portalcache->traveltimes[-clusternum];\n\t\t*reachnum = aasworld.areasettings[areanum].firstreachablearea +\n\t\t\t\t\t\tportalcache->reachabilities[-clusternum];\n\t\treturn qtrue;\n\t} //end if\n\t//\n\tbesttime = 0;\n\tbestreachnum = -1;\n\t//the cluster the area is in\n\tcluster = &aasworld.clusters[clusternum];\n\t//find the portal of the area cluster leading towards the goal area\n\tfor (i = 0; i < cluster->numportals; i++)\n\t{\n\t\tportalnum = aasworld.portalindex[cluster->firstportal + i];\n\t\t//if the goal area isn't reachable from the portal\n\t\tif (!portalcache->traveltimes[portalnum]) continue;\n\t\t//\n\t\tportal = &aasworld.portals[portalnum];\n\t\t//get the cache of the portal area\n\t\tareacache = AAS_GetAreaRoutingCache(clusternum, portal->areanum, travelflags);\n\t\t//current area inside the current cluster\n\t\tclusterareanum = AAS_ClusterAreaNum(clusternum, areanum);\n\t\t//if the area is NOT a reachability area\n\t\tif (clusterareanum >= cluster->numreachabilityareas) continue;\n\t\t//if the portal is NOT reachable from this area\n\t\tif (!areacache->traveltimes[clusterareanum]) continue;\n\t\t//total travel time is the travel time the portal area is from\n\t\t//the goal area plus the travel time towards the portal area\n\t\tt = portalcache->traveltimes[portalnum] + areacache->traveltimes[clusterareanum];\n\t\t//FIXME: add the exact travel time through the actual portal area\n\t\t//NOTE: for now we just add the largest travel time through the portal area\n\t\t//\t\tbecause we can't directly calculate the exact travel time\n\t\t//\t\tto be more specific we don't know which reachability was used to travel\n\t\t//\t\tinto the portal area\n\t\tt += aasworld.portalmaxtraveltimes[portalnum];\n\t\t//\n\t\tif (origin)\n\t\t{\n\t\t\t*reachnum = aasworld.areasettings[areanum].firstreachablearea +\n\t\t\t\t\t\t\tareacache->reachabilities[clusterareanum];\n\t\t\treach = aasworld.reachability + *reachnum;\n\t\t\tt += AAS_AreaTravelTime(areanum, origin, reach->start);\n\t\t} //end if\n\t\t//if the time is better than the one already found\n\t\tif (!besttime || t < besttime)\n\t\t{\n\t\t\tbestreachnum = *reachnum;\n\t\t\tbesttime = t;\n\t\t} //end if\n\t} //end for\n\tif (bestreachnum < 0) {\n\t\treturn qfalse;\n\t}\n\t*reachnum = bestreachnum;\n\t*traveltime = besttime;\n\treturn qtrue;\n} //end of the function AAS_AreaRouteToGoalArea\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_AreaTravelTimeToGoalArea(int areanum, vec3_t origin, int goalareanum, int travelflags)\n{\n\tint traveltime, reachnum;\n\n\tif (AAS_AreaRouteToGoalArea(areanum, origin, goalareanum, travelflags, &traveltime, &reachnum))\n\t{\n\t\treturn traveltime;\n\t}\n\treturn 0;\n} //end of the function AAS_AreaTravelTimeToGoalArea\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_AreaReachabilityToGoalArea(int areanum, vec3_t origin, int goalareanum, int travelflags)\n{\n\tint traveltime, reachnum;\n\n\tif (AAS_AreaRouteToGoalArea(areanum, origin, goalareanum, travelflags, &traveltime, &reachnum))\n\t{\n\t\treturn reachnum;\n\t}\n\treturn 0;\n} //end of the function AAS_AreaReachabilityToGoalArea\n//===========================================================================\n// predict the route and stop on one of the stop events\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_PredictRoute(struct aas_predictroute_s *route, int areanum, vec3_t origin,\n\t\t\t\t\t\t\tint goalareanum, int travelflags, int maxareas, int maxtime,\n\t\t\t\t\t\t\tint stopevent, int stopcontents, int stoptfl, int stopareanum)\n{\n\tint curareanum, reachnum, i, j, testareanum;\n\tvec3_t curorigin;\n\taas_reachability_t *reach;\n\taas_reachabilityareas_t *reachareas;\n\n\t//init output\n\troute->stopevent = RSE_NONE;\n\troute->endarea = goalareanum;\n\troute->endcontents = 0;\n\troute->endtravelflags = 0;\n\tVectorCopy(origin, route->endpos);\n\troute->time = 0;\n\n\tcurareanum = areanum;\n\tVectorCopy(origin, curorigin);\n\n\tfor (i = 0; curareanum != goalareanum && (!maxareas || i < maxareas) && i < aasworld.numareas; i++)\n\t{\n\t\treachnum = AAS_AreaReachabilityToGoalArea(curareanum, curorigin, goalareanum, travelflags);\n\t\tif (!reachnum)\n\t\t{\n\t\t\troute->stopevent = RSE_NOROUTE;\n\t\t\treturn qfalse;\n\t\t} //end if\n\t\treach = &aasworld.reachability[reachnum];\n\t\t//\n\t\tif (stopevent & RSE_USETRAVELTYPE)\n\t\t{\n\t\t\tif (AAS_TravelFlagForType_inline(reach->traveltype) & stoptfl)\n\t\t\t{\n\t\t\t\troute->stopevent = RSE_USETRAVELTYPE;\n\t\t\t\troute->endarea = curareanum;\n\t\t\t\troute->endcontents = aasworld.areasettings[curareanum].contents;\n\t\t\t\troute->endtravelflags = AAS_TravelFlagForType_inline(reach->traveltype);\n\t\t\t\tVectorCopy(reach->start, route->endpos);\n\t\t\t\treturn qtrue;\n\t\t\t} //end if\n\t\t\tif (AAS_AreaContentsTravelFlags_inline(reach->areanum) & stoptfl)\n\t\t\t{\n\t\t\t\troute->stopevent = RSE_USETRAVELTYPE;\n\t\t\t\troute->endarea = reach->areanum;\n\t\t\t\troute->endcontents = aasworld.areasettings[reach->areanum].contents;\n\t\t\t\troute->endtravelflags = AAS_AreaContentsTravelFlags_inline(reach->areanum);\n\t\t\t\tVectorCopy(reach->end, route->endpos);\n\t\t\t\troute->time += AAS_AreaTravelTime(areanum, origin, reach->start);\n\t\t\t\troute->time += reach->traveltime;\n\t\t\t\treturn qtrue;\n\t\t\t} //end if\n\t\t} //end if\n\t\treachareas = &aasworld.reachabilityareas[reachnum];\n\t\tfor (j = 0; j < reachareas->numareas + 1; j++)\n\t\t{\n\t\t\tif (j >= reachareas->numareas)\n\t\t\t\ttestareanum = reach->areanum;\n\t\t\telse\n\t\t\t\ttestareanum = aasworld.reachabilityareaindex[reachareas->firstarea + j];\n\t\t\tif (stopevent & RSE_ENTERCONTENTS)\n\t\t\t{\n\t\t\t\tif (aasworld.areasettings[testareanum].contents & stopcontents)\n\t\t\t\t{\n\t\t\t\t\troute->stopevent = RSE_ENTERCONTENTS;\n\t\t\t\t\troute->endarea = testareanum;\n\t\t\t\t\troute->endcontents = aasworld.areasettings[testareanum].contents;\n\t\t\t\t\tVectorCopy(reach->end, route->endpos);\n\t\t\t\t\troute->time += AAS_AreaTravelTime(areanum, origin, reach->start);\n\t\t\t\t\troute->time += reach->traveltime;\n\t\t\t\t\treturn qtrue;\n\t\t\t\t} //end if\n\t\t\t} //end if\n\t\t\tif (stopevent & RSE_ENTERAREA)\n\t\t\t{\n\t\t\t\tif (testareanum == stopareanum)\n\t\t\t\t{\n\t\t\t\t\troute->stopevent = RSE_ENTERAREA;\n\t\t\t\t\troute->endarea = testareanum;\n\t\t\t\t\troute->endcontents = aasworld.areasettings[testareanum].contents;\n\t\t\t\t\tVectorCopy(reach->start, route->endpos);\n\t\t\t\t\treturn qtrue;\n\t\t\t\t} //end if\n\t\t\t} //end if\n\t\t} //end for\n\n\t\troute->time += AAS_AreaTravelTime(areanum, origin, reach->start);\n\t\troute->time += reach->traveltime;\n\t\troute->endarea = reach->areanum;\n\t\troute->endcontents = aasworld.areasettings[reach->areanum].contents;\n\t\troute->endtravelflags = AAS_TravelFlagForType_inline(reach->traveltype);\n\t\tVectorCopy(reach->end, route->endpos);\n\t\t//\n\t\tcurareanum = reach->areanum;\n\t\tVectorCopy(reach->end, curorigin);\n\t\t//\n\t\tif (maxtime && route->time > maxtime)\n\t\t\tbreak;\n\t} //end while\n\tif (curareanum != goalareanum)\n\t\treturn qfalse;\n\treturn qtrue;\n} //end of the function AAS_PredictRoute\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_BridgeWalkable(int areanum)\n{\n\treturn qfalse;\n} //end of the function AAS_BridgeWalkable\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_ReachabilityFromNum(int num, struct aas_reachability_s *reach)\n{\n\tif (!aasworld.initialized)\n\t{\n\t\tCom_Memset(reach, 0, sizeof(aas_reachability_t));\n\t\treturn;\n\t} //end if\n\tif (num < 0 || num >= aasworld.reachabilitysize)\n\t{\n\t\tCom_Memset(reach, 0, sizeof(aas_reachability_t));\n\t\treturn;\n\t} //end if\n\tCom_Memcpy(reach, &aasworld.reachability[num], sizeof(aas_reachability_t));;\n} //end of the function AAS_ReachabilityFromNum\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_NextAreaReachability(int areanum, int reachnum)\n{\n\taas_areasettings_t *settings;\n\n\tif (!aasworld.initialized) return 0;\n\n\tif (areanum <= 0 || areanum >= aasworld.numareas)\n\t{\n\t\tbotimport.Print(PRT_ERROR, \"AAS_NextAreaReachability: areanum %d out of range\\n\", areanum);\n\t\treturn 0;\n\t} //end if\n\n\tsettings = &aasworld.areasettings[areanum];\n\tif (!reachnum)\n\t{\n\t\treturn settings->firstreachablearea;\n\t} //end if\n\tif (reachnum < settings->firstreachablearea)\n\t{\n\t\tbotimport.Print(PRT_FATAL, \"AAS_NextAreaReachability: reachnum < settings->firstreachableara\");\n\t\treturn 0;\n\t} //end if\n\treachnum++;\n\tif (reachnum >= settings->firstreachablearea + settings->numreachableareas)\n\t{\n\t\treturn 0;\n\t} //end if\n\treturn reachnum;\n} //end of the function AAS_NextAreaReachability\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_NextModelReachability(int num, int modelnum)\n{\n\tint i;\n\n\tif (num <= 0) num = 1;\n\telse if (num >= aasworld.reachabilitysize) return 0;\n\telse num++;\n\t//\n\tfor (i = num; i < aasworld.reachabilitysize; i++)\n\t{\n\t\tif ((aasworld.reachability[i].traveltype & TRAVELTYPE_MASK) == TRAVEL_ELEVATOR)\n\t\t{\n\t\t\tif (aasworld.reachability[i].facenum == modelnum) return i;\n\t\t} //end if\n\t\telse if ((aasworld.reachability[i].traveltype & TRAVELTYPE_MASK) == TRAVEL_FUNCBOB)\n\t\t{\n\t\t\tif ((aasworld.reachability[i].facenum & 0x0000FFFF) == modelnum) return i;\n\t\t} //end if\n\t} //end for\n\treturn 0;\n} //end of the function AAS_NextModelReachability\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_RandomGoalArea(int areanum, int travelflags, int *goalareanum, vec3_t goalorigin)\n{\n\tint i, n, t;\n\tvec3_t start, end;\n\taas_trace_t trace;\n\n\t//if the area has no reachabilities\n\tif (!AAS_AreaReachability(areanum)) return qfalse;\n\t//\n\tn = aasworld.numareas * random();\n\tfor (i = 0; i < aasworld.numareas; i++)\n\t{\n\t\tif (n <= 0) n = 1;\n\t\tif (n >= aasworld.numareas) n = 1;\n\t\tif (AAS_AreaReachability(n))\n\t\t{\n\t\t\tt = AAS_AreaTravelTimeToGoalArea(areanum, aasworld.areas[areanum].center, n, travelflags);\n\t\t\t//if the goal is reachable\n\t\t\tif (t > 0)\n\t\t\t{\n\t\t\t\tif (AAS_AreaSwim(n))\n\t\t\t\t{\n\t\t\t\t\t*goalareanum = n;\n\t\t\t\t\tVectorCopy(aasworld.areas[n].center, goalorigin);\n\t\t\t\t\t//botimport.Print(PRT_MESSAGE, \"found random goal area %d\\n\", *goalareanum);\n\t\t\t\t\treturn qtrue;\n\t\t\t\t} //end if\n\t\t\t\tVectorCopy(aasworld.areas[n].center, start);\n\t\t\t\tif (!AAS_PointAreaNum(start))\n\t\t\t\t\tLog_Write(\"area %d center %f %f %f in solid?\", n, start[0], start[1], start[2]);\n\t\t\t\tVectorCopy(start, end);\n\t\t\t\tend[2] -= 300;\n\t\t\t\ttrace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, -1);\n\t\t\t\tif (!trace.startsolid && trace.fraction < 1 && AAS_PointAreaNum(trace.endpos) == n)\n\t\t\t\t{\n\t\t\t\t\tif (AAS_AreaGroundFaceArea(n) > 300)\n\t\t\t\t\t{\n\t\t\t\t\t\t*goalareanum = n;\n\t\t\t\t\t\tVectorCopy(trace.endpos, goalorigin);\n\t\t\t\t\t\t//botimport.Print(PRT_MESSAGE, \"found random goal area %d\\n\", *goalareanum);\n\t\t\t\t\t\treturn qtrue;\n\t\t\t\t\t} //end if\n\t\t\t\t} //end if\n\t\t\t} //end if\n\t\t} //end if\n\t\tn++;\n\t} //end for\n\treturn qfalse;\n} //end of the function AAS_RandomGoalArea\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_AreaVisible(int srcarea, int destarea)\n{\n\treturn qfalse;\n} //end of the function AAS_AreaVisible\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nfloat DistancePointToLine(vec3_t v1, vec3_t v2, vec3_t point)\n{\n\tvec3_t vec, p2;\n\n\tAAS_ProjectPointOntoVector(point, v1, v2, p2);\n\tVectorSubtract(point, p2, vec);\n\treturn VectorLength(vec);\n} //end of the function DistancePointToLine\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_NearestHideArea(int srcnum, vec3_t origin, int areanum, int enemynum, vec3_t enemyorigin, int enemyareanum, int travelflags)\n{\n\tint i, j, nextareanum, badtravelflags, numreach, bestarea;\n\tunsigned short int t, besttraveltime;\n\tstatic unsigned short int *hidetraveltimes;\n\taas_routingupdate_t *updateliststart, *updatelistend, *curupdate, *nextupdate;\n\taas_reachability_t *reach;\n\tfloat dist1, dist2;\n\tvec3_t v1, v2, p;\n\tqboolean startVisible;\n\n\t//\n\tif (!hidetraveltimes)\n\t{\n\t\thidetraveltimes = (unsigned short int *) GetClearedMemory(aasworld.numareas * sizeof(unsigned short int));\n\t} //end if\n\telse\n\t{\n\t\tCom_Memset(hidetraveltimes, 0, aasworld.numareas * sizeof(unsigned short int));\n\t} //end else\n\tbesttraveltime = 0;\n\tbestarea = 0;\n\t//assume visible\n\tstartVisible = qtrue;\n\t//\n\tbadtravelflags = ~travelflags;\n\t//\n\tcurupdate = &aasworld.areaupdate[areanum];\n\tcurupdate->areanum = areanum;\n\tVectorCopy(origin, curupdate->start);\n\tcurupdate->areatraveltimes = aasworld.areatraveltimes[areanum][0];\n\tcurupdate->tmptraveltime = 0;\n\t//put the area to start with in the current read list\n\tcurupdate->next = NULL;\n\tcurupdate->prev = NULL;\n\tupdateliststart = curupdate;\n\tupdatelistend = curupdate;\n\t//while there are updates in the list\n\twhile (updateliststart)\n\t{\n\t\tcurupdate = updateliststart;\n\t\t//\n\t\tif (curupdate->next) curupdate->next->prev = NULL;\n\t\telse updatelistend = NULL;\n\t\tupdateliststart = curupdate->next;\n\t\t//\n\t\tcurupdate->inlist = qfalse;\n\t\t//check all reversed reachability links\n\t\tnumreach = aasworld.areasettings[curupdate->areanum].numreachableareas;\n\t\treach = &aasworld.reachability[aasworld.areasettings[curupdate->areanum].firstreachablearea];\n\t\t//\n\t\tfor (i = 0; i < numreach; i++, reach++)\n\t\t{\n\t\t\t//if an undesired travel type is used\n\t\t\tif (AAS_TravelFlagForType_inline(reach->traveltype) & badtravelflags) continue;\n\t\t\t//\n\t\t\tif (AAS_AreaContentsTravelFlags_inline(reach->areanum) & badtravelflags) continue;\n\t\t\t//number of the area the reachability leads to\n\t\t\tnextareanum = reach->areanum;\n\t\t\t// if this moves us into the enemies area, skip it\n\t\t\tif (nextareanum == enemyareanum) continue;\n\t\t\t//time already travelled plus the traveltime through\n\t\t\t//the current area plus the travel time from the reachability\n\t\t\tt = curupdate->tmptraveltime +\n\t\t\t\t\t\tAAS_AreaTravelTime(curupdate->areanum, curupdate->start, reach->start) +\n\t\t\t\t\t\t\treach->traveltime;\n\n\t\t\t//avoid going near the enemy\n\t\t\tAAS_ProjectPointOntoVector(enemyorigin, curupdate->start, reach->end, p);\n\t\t\tfor (j = 0; j < 3; j++)\n\t\t\t\tif ((p[j] > curupdate->start[j] && p[j] > reach->end[j]) ||\n\t\t\t\t\t(p[j] < curupdate->start[j] && p[j] < reach->end[j]))\n\t\t\t\t\tbreak;\n\t\t\tif (j < 3)\n\t\t\t{\n\t\t\t\tVectorSubtract(enemyorigin, reach->end, v2);\n\t\t\t} //end if\n\t\t\telse\n\t\t\t{\n\t\t\t\tVectorSubtract(enemyorigin, p, v2);\n\t\t\t} //end else\n\t\t\tdist2 = VectorLength(v2);\n\t\t\t//never go through the enemy\n\t\t\tif (dist2 < 40) continue;\n\t\t\t//\n\t\t\tVectorSubtract(enemyorigin, curupdate->start, v1);\n\t\t\tdist1 = VectorLength(v1);\n\t\t\t//\n\t\t\tif (dist2 < dist1)\n\t\t\t{\n\t\t\t\tt += (dist1 - dist2) * 10;\n\t\t\t}\n\t\t\t// if we weren't visible when starting, make sure we don't move into their view\n\t\t\tif (!startVisible && AAS_AreaVisible(enemyareanum, nextareanum)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t//\n\t\t\tif (besttraveltime && t >= besttraveltime) continue;\n\t\t\t//\n\t\t\tif (!hidetraveltimes[nextareanum] ||\n\t\t\t\t\thidetraveltimes[nextareanum] > t)\n\t\t\t{\n\t\t\t\t//if the nextarea is not visible from the enemy area\n\t\t\t\tif (!AAS_AreaVisible(enemyareanum, nextareanum))\n\t\t\t\t{\n\t\t\t\t\tbesttraveltime = t;\n\t\t\t\t\tbestarea = nextareanum;\n\t\t\t\t} //end if\n\t\t\t\thidetraveltimes[nextareanum] = t;\n\t\t\t\tnextupdate = &aasworld.areaupdate[nextareanum];\n\t\t\t\tnextupdate->areanum = nextareanum;\n\t\t\t\tnextupdate->tmptraveltime = t;\n\t\t\t\t//remember where we entered this area\n\t\t\t\tVectorCopy(reach->end, nextupdate->start);\n\t\t\t\t//if this update is not in the list yet\n\t\t\t\tif (!nextupdate->inlist)\n\t\t\t\t{\n\t\t\t\t\t//add the new update to the end of the list\n\t\t\t\t\tnextupdate->next = NULL;\n\t\t\t\t\tnextupdate->prev = updatelistend;\n\t\t\t\t\tif (updatelistend) updatelistend->next = nextupdate;\n\t\t\t\t\telse updateliststart = nextupdate;\n\t\t\t\t\tupdatelistend = nextupdate;\n\t\t\t\t\tnextupdate->inlist = qtrue;\n\t\t\t\t} //end if\n\t\t\t} //end if\n\t\t} //end for\n\t} //end while\n\treturn bestarea;\n} //end of the function AAS_NearestHideArea\n"
  },
  {
    "path": "src/engine/botlib/be_aas_route.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tbe_aas_route.h\n *\n * desc:\t\tAAS\n *\n * $Archive: /source/code/botlib/be_aas_route.h $\n *\n *****************************************************************************/\n\n#ifdef AASINTERN\n//initialize the AAS routing\nvoid AAS_InitRouting(void);\n//free the AAS routing caches\nvoid AAS_FreeRoutingCaches(void);\n//returns the travel time from start to end in the given area\nunsigned short int AAS_AreaTravelTime(int areanum, vec3_t start, vec3_t end);\n//\nvoid AAS_CreateAllRoutingCache(void);\nvoid AAS_WriteRouteCache(void);\n//\nvoid AAS_RoutingInfo(void);\n#endif //AASINTERN\n\n//returns the travel flag for the given travel type\nint AAS_TravelFlagForType(int traveltype);\n//return the travel flag(s) for traveling through this area\nint AAS_AreaContentsTravelFlags(int areanum);\n//returns the index of the next reachability for the given area\nint AAS_NextAreaReachability(int areanum, int reachnum);\n//returns the reachability with the given index\nvoid AAS_ReachabilityFromNum(int num, struct aas_reachability_s *reach);\n//returns a random goal area and goal origin\nint AAS_RandomGoalArea(int areanum, int travelflags, int *goalareanum, vec3_t goalorigin);\n//enable or disable an area for routing\nint AAS_EnableRoutingArea(int areanum, int enable);\n//returns the travel time within the given area from start to end\nunsigned short int AAS_AreaTravelTime(int areanum, vec3_t start, vec3_t end);\n//returns the travel time from the area to the goal area using the given travel flags\nint AAS_AreaTravelTimeToGoalArea(int areanum, vec3_t origin, int goalareanum, int travelflags);\n//predict a route up to a stop event\nint AAS_PredictRoute(struct aas_predictroute_s *route, int areanum, vec3_t origin,\n\t\t\t\t\t\t\tint goalareanum, int travelflags, int maxareas, int maxtime,\n\t\t\t\t\t\t\tint stopevent, int stopcontents, int stoptfl, int stopareanum);\n\n\n"
  },
  {
    "path": "src/engine/botlib/be_aas_routealt.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tbe_aas_routealt.c\n *\n * desc:\t\tAAS\n *\n * $Archive: /MissionPack/code/botlib/be_aas_routealt.c $\n *\n *****************************************************************************/\n\n#include \"../../game/q_shared.h\"\n#include \"l_utils.h\"\n#include \"l_memory.h\"\n#include \"l_log.h\"\n#include \"l_script.h\"\n#include \"l_precomp.h\"\n#include \"l_struct.h\"\n#include \"aasfile.h\"\n#include \"../../game/botlib.h\"\n#include \"../../game/be_aas.h\"\n#include \"be_aas_funcs.h\"\n#include \"be_interface.h\"\n#include \"be_aas_def.h\"\n\n#define ENABLE_ALTROUTING\n//#define ALTROUTE_DEBUG\n\ntypedef struct midrangearea_s\n{\n\tint valid;\n\tunsigned short starttime;\n\tunsigned short goaltime;\n} midrangearea_t;\n\nmidrangearea_t *midrangeareas;\nint *clusterareas;\nint numclusterareas;\n\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_AltRoutingFloodCluster_r(int areanum)\n{\n\tint i, otherareanum;\n\taas_area_t *area;\n\taas_face_t *face;\n\n\t//add the current area to the areas of the current cluster\n\tclusterareas[numclusterareas] = areanum;\n\tnumclusterareas++;\n\t//remove the area from the mid range areas\n\tmidrangeareas[areanum].valid = qfalse;\n\t//flood to other areas through the faces of this area\n\tarea = &aasworld.areas[areanum];\n\tfor (i = 0; i < area->numfaces; i++)\n\t{\n\t\tface = &aasworld.faces[abs(aasworld.faceindex[area->firstface + i])];\n\t\t//get the area at the other side of the face\n\t\tif (face->frontarea == areanum) otherareanum = face->backarea;\n\t\telse otherareanum = face->frontarea;\n\t\t//if there is an area at the other side of this face\n\t\tif (!otherareanum) continue;\n\t\t//if the other area is not a midrange area\n\t\tif (!midrangeareas[otherareanum].valid) continue;\n\t\t//\n\t\tAAS_AltRoutingFloodCluster_r(otherareanum);\n\t} //end for\n} //end of the function AAS_AltRoutingFloodCluster_r\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_AlternativeRouteGoals(vec3_t start, int startareanum, vec3_t goal, int goalareanum, int travelflags,\n\t\t\t\t\t\t\t\t\t\t aas_altroutegoal_t *altroutegoals, int maxaltroutegoals,\n\t\t\t\t\t\t\t\t\t\t int type)\n{\n#ifndef ENABLE_ALTROUTING\n\treturn 0;\n#else\n\tint i, j, bestareanum;\n\tint numaltroutegoals, nummidrangeareas;\n\tint starttime, goaltime, goaltraveltime;\n\tfloat dist, bestdist;\n\tvec3_t mid, dir;\n#ifdef ALTROUTE_DEBUG\n\tint startmillisecs;\n\n\tstartmillisecs = Sys_MilliSeconds();\n#endif\n\n\tif (!startareanum || !goalareanum)\n\t\treturn 0;\n\t//travel time towards the goal area\n\tgoaltraveltime = AAS_AreaTravelTimeToGoalArea(startareanum, start, goalareanum, travelflags);\n\t//clear the midrange areas\n\tCom_Memset(midrangeareas, 0, aasworld.numareas * sizeof(midrangearea_t));\n\tnumaltroutegoals = 0;\n\t//\n\tnummidrangeareas = 0;\n\t//\n\tfor (i = 1; i < aasworld.numareas; i++)\n\t{\n\t\t//\n\t\tif (!(type & ALTROUTEGOAL_ALL))\n\t\t{\n\t\t\tif (!(type & ALTROUTEGOAL_CLUSTERPORTALS && (aasworld.areasettings[i].contents & AREACONTENTS_CLUSTERPORTAL)))\n\t\t\t{\n\t\t\t\tif (!(type & ALTROUTEGOAL_VIEWPORTALS && (aasworld.areasettings[i].contents & AREACONTENTS_VIEWPORTAL)))\n\t\t\t\t{\n\t\t\t\t\tcontinue;\n\t\t\t\t} //end if\n\t\t\t} //end if\n\t\t} //end if\n\t\t//if the area has no reachabilities\n\t\tif (!AAS_AreaReachability(i)) continue;\n\t\t//tavel time from the area to the start area\n\t\tstarttime = AAS_AreaTravelTimeToGoalArea(startareanum, start, i, travelflags);\n\t\tif (!starttime) continue;\n\t\t//if the travel time from the start to the area is greater than the shortest goal travel time\n\t\tif (starttime > (float) 1.1 * goaltraveltime) continue;\n\t\t//travel time from the area to the goal area\n\t\tgoaltime = AAS_AreaTravelTimeToGoalArea(i, NULL, goalareanum, travelflags);\n\t\tif (!goaltime) continue;\n\t\t//if the travel time from the area to the goal is greater than the shortest goal travel time\n\t\tif (goaltime > (float) 0.8 * goaltraveltime) continue;\n\t\t//this is a mid range area\n\t\tmidrangeareas[i].valid = qtrue;\n\t\tmidrangeareas[i].starttime = starttime;\n\t\tmidrangeareas[i].goaltime = goaltime;\n\t\tLog_Write(\"%d midrange area %d\", nummidrangeareas, i);\n\t\tnummidrangeareas++;\n\t} //end for\n\t//\n\tfor (i = 1; i < aasworld.numareas; i++)\n\t{\n\t\tif (!midrangeareas[i].valid) continue;\n\t\t//get the areas in one cluster\n\t\tnumclusterareas = 0;\n\t\tAAS_AltRoutingFloodCluster_r(i);\n\t\t//now we've got a cluster with areas through which an alternative route could go\n\t\t//get the 'center' of the cluster\n\t\tVectorClear(mid);\n\t\tfor (j = 0; j < numclusterareas; j++)\n\t\t{\n\t\t\tVectorAdd(mid, aasworld.areas[clusterareas[j]].center, mid);\n\t\t} //end for\n\t\tVectorScale(mid, 1.0 / numclusterareas, mid);\n\t\t//get the area closest to the center of the cluster\n\t\tbestdist = 999999;\n\t\tbestareanum = 0;\n\t\tfor (j = 0; j < numclusterareas; j++)\n\t\t{\n\t\t\tVectorSubtract(mid, aasworld.areas[clusterareas[j]].center, dir);\n\t\t\tdist = VectorLength(dir);\n\t\t\tif (dist < bestdist)\n\t\t\t{\n\t\t\t\tbestdist = dist;\n\t\t\t\tbestareanum = clusterareas[j];\n\t\t\t} //end if\n\t\t} //end for\n\t\t//now we've got an area for an alternative route\n\t\t//FIXME: add alternative goal origin\n\t\tVectorCopy(aasworld.areas[bestareanum].center, altroutegoals[numaltroutegoals].origin);\n\t\taltroutegoals[numaltroutegoals].areanum = bestareanum;\n\t\taltroutegoals[numaltroutegoals].starttraveltime = midrangeareas[bestareanum].starttime;\n\t\taltroutegoals[numaltroutegoals].goaltraveltime = midrangeareas[bestareanum].goaltime;\n\t\taltroutegoals[numaltroutegoals].extratraveltime =\n\t\t\t\t\t(midrangeareas[bestareanum].starttime + midrangeareas[bestareanum].goaltime) -\n\t\t\t\t\t\t\t\tgoaltraveltime;\n\t\tnumaltroutegoals++;\n\t\t//\n#ifdef ALTROUTE_DEBUG\n\t\tAAS_ShowAreaPolygons(bestareanum, 1, qtrue);\n#endif\n\t\t//don't return more than the maximum alternative route goals\n\t\tif (numaltroutegoals >= maxaltroutegoals) break;\n\t} //end for\n#ifdef ALTROUTE_DEBUG\n\tbotimport.Print(PRT_MESSAGE, \"alternative route goals in %d msec\\n\", Sys_MilliSeconds() - startmillisecs);\n#endif\n\treturn numaltroutegoals;\n#endif\n} //end of the function AAS_AlternativeRouteGoals\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_InitAlternativeRouting(void)\n{\n#ifdef ENABLE_ALTROUTING\n\tif (midrangeareas) FreeMemory(midrangeareas);\n\tmidrangeareas = (midrangearea_t *) GetMemory(aasworld.numareas * sizeof(midrangearea_t));\n\tif (clusterareas) FreeMemory(clusterareas);\n\tclusterareas = (int *) GetMemory(aasworld.numareas * sizeof(int));\n#endif\n} //end of the function AAS_InitAlternativeRouting\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_ShutdownAlternativeRouting(void)\n{\n#ifdef ENABLE_ALTROUTING\n\tif (midrangeareas) FreeMemory(midrangeareas);\n\tmidrangeareas = NULL;\n\tif (clusterareas) FreeMemory(clusterareas);\n\tclusterareas = NULL;\n\tnumclusterareas = 0;\n#endif\n} //end of the function AAS_ShutdownAlternativeRouting\n"
  },
  {
    "path": "src/engine/botlib/be_aas_routealt.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tbe_aas_routealt.h\n *\n * desc:\t\tAAS\n *\n * $Archive: /source/code/botlib/be_aas_routealt.h $\n *\n *****************************************************************************/\n\n#ifdef AASINTERN\nvoid AAS_InitAlternativeRouting(void);\nvoid AAS_ShutdownAlternativeRouting(void);\n#endif //AASINTERN\n\n\nint AAS_AlternativeRouteGoals(vec3_t start, int startareanum, vec3_t goal, int goalareanum, int travelflags,\n\t\t\t\t\t\t\t\t\t\taas_altroutegoal_t *altroutegoals, int maxaltroutegoals,\n\t\t\t\t\t\t\t\t\t\tint type);\n"
  },
  {
    "path": "src/engine/botlib/be_aas_sample.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tbe_aas_sample.c\n *\n * desc:\t\tAAS environment sampling\n *\n * $Archive: /MissionPack/code/botlib/be_aas_sample.c $\n *\n *****************************************************************************/\n\n#include \"../../game/q_shared.h\"\n#include \"l_memory.h\"\n#include \"l_script.h\"\n#include \"l_precomp.h\"\n#include \"l_struct.h\"\n#ifndef BSPC\n#include \"l_libvar.h\"\n#endif\n#include \"aasfile.h\"\n#include \"../../game/botlib.h\"\n#include \"../../game/be_aas.h\"\n#include \"be_interface.h\"\n#include \"be_aas_funcs.h\"\n#include \"be_aas_def.h\"\n\nextern botlib_import_t botimport;\n\n//#define AAS_SAMPLE_DEBUG\n\n#define BBOX_NORMAL_EPSILON\t\t0.001\n\n#define ON_EPSILON\t\t\t\t\t0 //0.0005\n\n#define TRACEPLANE_EPSILON\t\t\t0.125\n\ntypedef struct aas_tracestack_s\n{\n\tvec3_t start;\t\t//start point of the piece of line to trace\n\tvec3_t end;\t\t\t//end point of the piece of line to trace\n\tint planenum;\t\t//last plane used as splitter\n\tint nodenum;\t\t//node found after splitting with planenum\n} aas_tracestack_t;\n\nint numaaslinks;\n\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_PresenceTypeBoundingBox(int presencetype, vec3_t mins, vec3_t maxs)\n{\n\tint index;\n\t//bounding box size for each presence type\n\tvec3_t boxmins[3] = {{0, 0, 0}, {-15, -15, -24}, {-15, -15, -24}};\n\tvec3_t boxmaxs[3] = {{0, 0, 0}, { 15,  15,  32}, { 15,  15,   8}};\n\n\tif (presencetype == PRESENCE_NORMAL) index = 1;\n\telse if (presencetype == PRESENCE_CROUCH) index = 2;\n\telse\n\t{\n\t\tbotimport.Print(PRT_FATAL, \"AAS_PresenceTypeBoundingBox: unknown presence type\\n\");\n\t\tindex = 2;\n\t} //end if\n\tVectorCopy(boxmins[index], mins);\n\tVectorCopy(boxmaxs[index], maxs);\n} //end of the function AAS_PresenceTypeBoundingBox\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_InitAASLinkHeap(void)\n{\n\tint i, max_aaslinks;\n\n\tmax_aaslinks = aasworld.linkheapsize;\n\t//if there's no link heap present\n\tif (!aasworld.linkheap)\n\t{\n#ifdef BSPC\n\t\tmax_aaslinks = 6144;\n#else\n\t\tmax_aaslinks = (int) LibVarValue(\"max_aaslinks\", \"6144\");\n#endif\n\t\tif (max_aaslinks < 0) max_aaslinks = 0;\n\t\taasworld.linkheapsize = max_aaslinks;\n\t\taasworld.linkheap = (aas_link_t *) GetHunkMemory(max_aaslinks * sizeof(aas_link_t));\n\t} //end if\n\t//link the links on the heap\n\taasworld.linkheap[0].prev_ent = NULL;\n\taasworld.linkheap[0].next_ent = &aasworld.linkheap[1];\n\tfor (i = 1; i < max_aaslinks-1; i++)\n\t{\n\t\taasworld.linkheap[i].prev_ent = &aasworld.linkheap[i - 1];\n\t\taasworld.linkheap[i].next_ent = &aasworld.linkheap[i + 1];\n\t} //end for\n\taasworld.linkheap[max_aaslinks-1].prev_ent = &aasworld.linkheap[max_aaslinks-2];\n\taasworld.linkheap[max_aaslinks-1].next_ent = NULL;\n\t//pointer to the first free link\n\taasworld.freelinks = &aasworld.linkheap[0];\n\t//\n\tnumaaslinks = max_aaslinks;\n} //end of the function AAS_InitAASLinkHeap\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_FreeAASLinkHeap(void)\n{\n\tif (aasworld.linkheap) FreeMemory(aasworld.linkheap);\n\taasworld.linkheap = NULL;\n\taasworld.linkheapsize = 0;\n} //end of the function AAS_FreeAASLinkHeap\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\naas_link_t *AAS_AllocAASLink(void)\n{\n\taas_link_t *link;\n\n\tlink = aasworld.freelinks;\n\tif (!link)\n\t{\n#ifndef BSPC\n\t\tif (bot_developer)\n#endif\n\t\t{\n\t\t\tbotimport.Print(PRT_FATAL, \"empty aas link heap\\n\");\n\t\t} //end if\n\t\treturn NULL;\n\t} //end if\n\tif (aasworld.freelinks) aasworld.freelinks = aasworld.freelinks->next_ent;\n\tif (aasworld.freelinks) aasworld.freelinks->prev_ent = NULL;\n\tnumaaslinks--;\n\treturn link;\n} //end of the function AAS_AllocAASLink\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_DeAllocAASLink(aas_link_t *link)\n{\n\tif (aasworld.freelinks) aasworld.freelinks->prev_ent = link;\n\tlink->prev_ent = NULL;\n\tlink->next_ent = aasworld.freelinks;\n\tlink->prev_area = NULL;\n\tlink->next_area = NULL;\n\taasworld.freelinks = link;\n\tnumaaslinks++;\n} //end of the function AAS_DeAllocAASLink\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_InitAASLinkedEntities(void)\n{\n\tif (!aasworld.loaded) return;\n\tif (aasworld.arealinkedentities) FreeMemory(aasworld.arealinkedentities);\n\taasworld.arealinkedentities = (aas_link_t **) GetClearedHunkMemory(\n\t\t\t\t\t\taasworld.numareas * sizeof(aas_link_t *));\n} //end of the function AAS_InitAASLinkedEntities\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_FreeAASLinkedEntities(void)\n{\n\tif (aasworld.arealinkedentities) FreeMemory(aasworld.arealinkedentities);\n\taasworld.arealinkedentities = NULL;\n} //end of the function AAS_InitAASLinkedEntities\n//===========================================================================\n// returns the AAS area the point is in\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_PointAreaNum(vec3_t point)\n{\n\tint nodenum;\n\tvec_t\tdist;\n\taas_node_t *node;\n\taas_plane_t *plane;\n\n\tif (!aasworld.loaded)\n\t{\n\t\tbotimport.Print(PRT_ERROR, \"AAS_PointAreaNum: aas not loaded\\n\");\n\t\treturn 0;\n\t} //end if\n\n\t//start with node 1 because node zero is a dummy used for solid leafs\n\tnodenum = 1;\n\twhile (nodenum > 0)\n\t{\n//\t\tbotimport.Print(PRT_MESSAGE, \"[%d]\", nodenum);\n#ifdef AAS_SAMPLE_DEBUG\n\t\tif (nodenum >= aasworld.numnodes)\n\t\t{\n\t\t\tbotimport.Print(PRT_ERROR, \"nodenum = %d >= aasworld.numnodes = %d\\n\", nodenum, aasworld.numnodes);\n\t\t\treturn 0;\n\t\t} //end if\n#endif //AAS_SAMPLE_DEBUG\n\t\tnode = &aasworld.nodes[nodenum];\n#ifdef AAS_SAMPLE_DEBUG\n\t\tif (node->planenum < 0 || node->planenum >= aasworld.numplanes)\n\t\t{\n\t\t\tbotimport.Print(PRT_ERROR, \"node->planenum = %d >= aasworld.numplanes = %d\\n\", node->planenum, aasworld.numplanes);\n\t\t\treturn 0;\n\t\t} //end if\n#endif //AAS_SAMPLE_DEBUG\n\t\tplane = &aasworld.planes[node->planenum];\n\t\tdist = DotProduct(point, plane->normal) - plane->dist;\n\t\tif (dist > 0) nodenum = node->children[0];\n\t\telse nodenum = node->children[1];\n\t} //end while\n\tif (!nodenum)\n\t{\n#ifdef AAS_SAMPLE_DEBUG\n\t\tbotimport.Print(PRT_MESSAGE, \"in solid\\n\");\n#endif //AAS_SAMPLE_DEBUG\n\t\treturn 0;\n\t} //end if\n\treturn -nodenum;\n} //end of the function AAS_PointAreaNum\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_PointReachabilityAreaIndex( vec3_t origin )\n{\n\tint areanum, cluster, i, index;\n\n\tif (!aasworld.initialized)\n\t\treturn 0;\n\n\tif ( !origin )\n\t{\n\t\tindex = 0;\n\t\tfor (i = 0; i < aasworld.numclusters; i++)\n\t\t{\n\t\t\tindex += aasworld.clusters[i].numreachabilityareas;\n\t\t} //end for\n\t\treturn index;\n\t} //end if\n\n\tareanum = AAS_PointAreaNum( origin );\n\tif ( !areanum || !AAS_AreaReachability(areanum) )\n\t\treturn 0;\n\tcluster = aasworld.areasettings[areanum].cluster;\n\tareanum = aasworld.areasettings[areanum].clusterareanum;\n\tif (cluster < 0)\n\t{\n\t\tcluster = aasworld.portals[-cluster].frontcluster;\n\t\tareanum = aasworld.portals[-cluster].clusterareanum[0];\n\t} //end if\n\n\tindex = 0;\n\tfor (i = 0; i < cluster; i++)\n\t{\n\t\tindex += aasworld.clusters[i].numreachabilityareas;\n\t} //end for\n\tindex += areanum;\n\treturn index;\n} //end of the function AAS_PointReachabilityAreaIndex\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_AreaCluster(int areanum)\n{\n\tif (areanum <= 0 || areanum >= aasworld.numareas)\n\t{\n\t\tbotimport.Print(PRT_ERROR, \"AAS_AreaCluster: invalid area number\\n\");\n\t\treturn 0;\n\t} //end if\n\treturn aasworld.areasettings[areanum].cluster;\n} //end of the function AAS_AreaCluster\n//===========================================================================\n// returns the presence types of the given area\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_AreaPresenceType(int areanum)\n{\n\tif (!aasworld.loaded) return 0;\n\tif (areanum <= 0 || areanum >= aasworld.numareas)\n\t{\n\t\tbotimport.Print(PRT_ERROR, \"AAS_AreaPresenceType: invalid area number\\n\");\n\t\treturn 0;\n\t} //end if\n\treturn aasworld.areasettings[areanum].presencetype;\n} //end of the function AAS_AreaPresenceType\n//===========================================================================\n// returns the presence type at the given point\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_PointPresenceType(vec3_t point)\n{\n\tint areanum;\n\n\tif (!aasworld.loaded) return 0;\n\n\tareanum = AAS_PointAreaNum(point);\n\tif (!areanum) return PRESENCE_NONE;\n\treturn aasworld.areasettings[areanum].presencetype;\n} //end of the function AAS_PointPresenceType\n//===========================================================================\n// calculates the minimum distance between the origin of the box and the\n// given plane when both will collide on the given side of the plane\n//\n// normal\t=\tnormal vector of plane to calculate distance from\n// mins\t\t=\tminimums of box relative to origin\n// maxs\t\t=\tmaximums of box relative to origin\n// side\t\t=\tside of the plane we want to calculate the distance from\n//\t\t\t\t\t0 normal vector side\n//\t\t\t\t\t1 not normal vector side\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvec_t AAS_BoxOriginDistanceFromPlane(vec3_t normal, vec3_t mins, vec3_t maxs, int side)\n{\n\tvec3_t v1, v2;\n\tint i;\n\n\t//swap maxs and mins when on the other side of the plane\n\tif (side)\n\t{\n\t\t//get a point of the box that would be one of the first\n\t\t//to collide with the plane\n\t\tfor (i = 0; i < 3; i++)\n\t\t{\n\t\t\tif (normal[i] > BBOX_NORMAL_EPSILON) v1[i] = maxs[i];\n\t\t\telse if (normal[i] < -BBOX_NORMAL_EPSILON) v1[i] = mins[i];\n\t\t\telse v1[i] = 0;\n\t\t} //end for\n\t} //end if\n\telse\n\t{\n\t\t//get a point of the box that would be one of the first\n\t\t//to collide with the plane\n\t\tfor (i = 0; i < 3; i++)\n\t\t{\n\t\t\tif (normal[i] > BBOX_NORMAL_EPSILON) v1[i] = mins[i];\n\t\t\telse if (normal[i] < -BBOX_NORMAL_EPSILON) v1[i] = maxs[i];\n\t\t\telse v1[i] = 0;\n\t\t} //end for\n\t} //end else\n\t//\n\tVectorCopy(normal, v2);\n\tVectorInverse(v2);\n//\tVectorNegate(normal, v2);\n\treturn DotProduct(v1, v2);\n} //end of the function AAS_BoxOriginDistanceFromPlane\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nqboolean AAS_AreaEntityCollision(int areanum, vec3_t start, vec3_t end,\n\t\t\t\t\t\t\t\t\t\tint presencetype, int passent, aas_trace_t *trace)\n{\n\tint collision;\n\tvec3_t boxmins, boxmaxs;\n\taas_link_t *link;\n\tbsp_trace_t bsptrace;\n\n\tAAS_PresenceTypeBoundingBox(presencetype, boxmins, boxmaxs);\n\n\tCom_Memset(&bsptrace, 0, sizeof(bsp_trace_t)); //make compiler happy\n\t//assume no collision\n\tbsptrace.fraction = 1;\n\tcollision = qfalse;\n\tfor (link = aasworld.arealinkedentities[areanum]; link; link = link->next_ent)\n\t{\n\t\t//ignore the pass entity\n\t\tif (link->entnum == passent) continue;\n\t\t//\n\t\tif (AAS_EntityCollision(link->entnum, start, boxmins, boxmaxs, end,\n\t\t\t\t\t\t\t\t\t\t\t\tCONTENTS_SOLID|CONTENTS_PLAYERCLIP, &bsptrace))\n\t\t{\n\t\t\tcollision = qtrue;\n\t\t} //end if\n\t} //end for\n\tif (collision)\n\t{\n\t\ttrace->startsolid = bsptrace.startsolid;\n\t\ttrace->ent = bsptrace.ent;\n\t\tVectorCopy(bsptrace.endpos, trace->endpos);\n\t\ttrace->area = 0;\n\t\ttrace->planenum = 0;\n\t\treturn qtrue;\n\t} //end if\n\treturn qfalse;\n} //end of the function AAS_AreaEntityCollision\n//===========================================================================\n// recursive subdivision of the line by the BSP tree.\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\naas_trace_t AAS_TraceClientBBox(vec3_t start, vec3_t end, int presencetype,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tint passent)\n{\n\tint side, nodenum, tmpplanenum;\n\tfloat front, back, frac;\n\tvec3_t cur_start, cur_end, cur_mid, v1, v2;\n\taas_tracestack_t tracestack[127];\n\taas_tracestack_t *tstack_p;\n\taas_node_t *aasnode;\n\taas_plane_t *plane;\n\taas_trace_t trace;\n\n\t//clear the trace structure\n\tCom_Memset(&trace, 0, sizeof(aas_trace_t));\n\n\tif (!aasworld.loaded) return trace;\n\t\n\ttstack_p = tracestack;\n\t//we start with the whole line on the stack\n\tVectorCopy(start, tstack_p->start);\n\tVectorCopy(end, tstack_p->end);\n\ttstack_p->planenum = 0;\n\t//start with node 1 because node zero is a dummy for a solid leaf\n\ttstack_p->nodenum = 1;\t\t//starting at the root of the tree\n\ttstack_p++;\n\t\n\twhile (1)\n\t{\n\t\t//pop up the stack\n\t\ttstack_p--;\n\t\t//if the trace stack is empty (ended up with a piece of the\n\t\t//line to be traced in an area)\n\t\tif (tstack_p < tracestack)\n\t\t{\n\t\t\ttstack_p++;\n\t\t\t//nothing was hit\n\t\t\ttrace.startsolid = qfalse;\n\t\t\ttrace.fraction = 1.0;\n\t\t\t//endpos is the end of the line\n\t\t\tVectorCopy(end, trace.endpos);\n\t\t\t//nothing hit\n\t\t\ttrace.ent = 0;\n\t\t\ttrace.area = 0;\n\t\t\ttrace.planenum = 0;\n\t\t\treturn trace;\n\t\t} //end if\n\t\t//number of the current node to test the line against\n\t\tnodenum = tstack_p->nodenum;\n\t\t//if it is an area\n\t\tif (nodenum < 0)\n\t\t{\n#ifdef AAS_SAMPLE_DEBUG\n\t\t\tif (-nodenum > aasworld.numareasettings)\n\t\t\t{\n\t\t\t\tbotimport.Print(PRT_ERROR, \"AAS_TraceBoundingBox: -nodenum out of range\\n\");\n\t\t\t\treturn trace;\n\t\t\t} //end if\n#endif //AAS_SAMPLE_DEBUG\n\t\t\t//botimport.Print(PRT_MESSAGE, \"areanum = %d, must be %d\\n\", -nodenum, AAS_PointAreaNum(start));\n\t\t\t//if can't enter the area because it hasn't got the right presence type\n\t\t\tif (!(aasworld.areasettings[-nodenum].presencetype & presencetype))\n\t\t\t{\n\t\t\t\t//if the start point is still the initial start point\n\t\t\t\t//NOTE: no need for epsilons because the points will be\n\t\t\t\t//exactly the same when they're both the start point\n\t\t\t\tif (tstack_p->start[0] == start[0] &&\n\t\t\t\t\t\ttstack_p->start[1] == start[1] &&\n\t\t\t\t\t\ttstack_p->start[2] == start[2])\n\t\t\t\t{\n\t\t\t\t\ttrace.startsolid = qtrue;\n\t\t\t\t\ttrace.fraction = 0.0;\n\t\t\t\t\tVectorClear(v1);\n\t\t\t\t} //end if\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\ttrace.startsolid = qfalse;\n\t\t\t\t\tVectorSubtract(end, start, v1);\n\t\t\t\t\tVectorSubtract(tstack_p->start, start, v2);\n\t\t\t\t\ttrace.fraction = VectorLength(v2) / VectorNormalize(v1);\n\t\t\t\t\tVectorMA(tstack_p->start, -0.125, v1, tstack_p->start);\n\t\t\t\t} //end else\n\t\t\t\tVectorCopy(tstack_p->start, trace.endpos);\n\t\t\t\ttrace.ent = 0;\n\t\t\t\ttrace.area = -nodenum;\n//\t\t\t\tVectorSubtract(end, start, v1);\n\t\t\t\ttrace.planenum = tstack_p->planenum;\n\t\t\t\t//always take the plane with normal facing towards the trace start\n\t\t\t\tplane = &aasworld.planes[trace.planenum];\n\t\t\t\tif (DotProduct(v1, plane->normal) > 0) trace.planenum ^= 1;\n\t\t\t\treturn trace;\n\t\t\t} //end if\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (passent >= 0)\n\t\t\t\t{\n\t\t\t\t\tif (AAS_AreaEntityCollision(-nodenum, tstack_p->start,\n\t\t\t\t\t\t\t\t\t\t\t\t\ttstack_p->end, presencetype, passent,\n\t\t\t\t\t\t\t\t\t\t\t\t\t&trace))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (!trace.startsolid)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tVectorSubtract(end, start, v1);\n\t\t\t\t\t\t\tVectorSubtract(trace.endpos, start, v2);\n\t\t\t\t\t\t\ttrace.fraction = VectorLength(v2) / VectorLength(v1);\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t\treturn trace;\n\t\t\t\t\t} //end if\n\t\t\t\t} //end if\n\t\t\t} //end else\n\t\t\ttrace.lastarea = -nodenum;\n\t\t\tcontinue;\n\t\t} //end if\n\t\t//if it is a solid leaf\n\t\tif (!nodenum)\n\t\t{\n\t\t\t//if the start point is still the initial start point\n\t\t\t//NOTE: no need for epsilons because the points will be\n\t\t\t//exactly the same when they're both the start point\n\t\t\tif (tstack_p->start[0] == start[0] &&\n\t\t\t\t\ttstack_p->start[1] == start[1] &&\n\t\t\t\t\ttstack_p->start[2] == start[2])\n\t\t\t{\n\t\t\t\ttrace.startsolid = qtrue;\n\t\t\t\ttrace.fraction = 0.0;\n\t\t\t\tVectorClear(v1);\n\t\t\t} //end if\n\t\t\telse\n\t\t\t{\n\t\t\t\ttrace.startsolid = qfalse;\n\t\t\t\tVectorSubtract(end, start, v1);\n\t\t\t\tVectorSubtract(tstack_p->start, start, v2);\n\t\t\t\ttrace.fraction = VectorLength(v2) / VectorNormalize(v1);\n\t\t\t\tVectorMA(tstack_p->start, -0.125, v1, tstack_p->start);\n\t\t\t} //end else\n\t\t\tVectorCopy(tstack_p->start, trace.endpos);\n\t\t\ttrace.ent = 0;\n\t\t\ttrace.area = 0;\t//hit solid leaf\n//\t\t\tVectorSubtract(end, start, v1);\n\t\t\ttrace.planenum = tstack_p->planenum;\n\t\t\t//always take the plane with normal facing towards the trace start\n\t\t\tplane = &aasworld.planes[trace.planenum];\n\t\t\tif (DotProduct(v1, plane->normal) > 0) trace.planenum ^= 1;\n\t\t\treturn trace;\n\t\t} //end if\n#ifdef AAS_SAMPLE_DEBUG\n\t\tif (nodenum > aasworld.numnodes)\n\t\t{\n\t\t\tbotimport.Print(PRT_ERROR, \"AAS_TraceBoundingBox: nodenum out of range\\n\");\n\t\t\treturn trace;\n\t\t} //end if\n#endif //AAS_SAMPLE_DEBUG\n\t\t//the node to test against\n\t\taasnode = &aasworld.nodes[nodenum];\n\t\t//start point of current line to test against node\n\t\tVectorCopy(tstack_p->start, cur_start);\n\t\t//end point of the current line to test against node\n\t\tVectorCopy(tstack_p->end, cur_end);\n\t\t//the current node plane\n\t\tplane = &aasworld.planes[aasnode->planenum];\n\n        front = DotProduct(cur_start, plane->normal) - plane->dist;\n        back = DotProduct(cur_end, plane->normal) - plane->dist;\n\t\t// bk010221 - old location of FPE hack and divide by zero expression\n\t\t//if the whole to be traced line is totally at the front of this node\n\t\t//only go down the tree with the front child\n\t\tif ((front >= -ON_EPSILON && back >= -ON_EPSILON))\n\t\t{\n\t\t\t//keep the current start and end point on the stack\n\t\t\t//and go down the tree with the front child\n\t\t\ttstack_p->nodenum = aasnode->children[0];\n\t\t\ttstack_p++;\n\t\t\tif (tstack_p >= &tracestack[127])\n\t\t\t{\n\t\t\t\tbotimport.Print(PRT_ERROR, \"AAS_TraceBoundingBox: stack overflow\\n\");\n\t\t\t\treturn trace;\n\t\t\t} //end if\n\t\t} //end if\n\t\t//if the whole to be traced line is totally at the back of this node\n\t\t//only go down the tree with the back child\n\t\telse if ((front < ON_EPSILON && back < ON_EPSILON))\n\t\t{\n\t\t\t//keep the current start and end point on the stack\n\t\t\t//and go down the tree with the back child\n\t\t\ttstack_p->nodenum = aasnode->children[1];\n\t\t\ttstack_p++;\n\t\t\tif (tstack_p >= &tracestack[127])\n\t\t\t{\n\t\t\t\tbotimport.Print(PRT_ERROR, \"AAS_TraceBoundingBox: stack overflow\\n\");\n\t\t\t\treturn trace;\n\t\t\t} //end if\n\t\t} //end if\n\t\t//go down the tree both at the front and back of the node\n\t\telse\n\t\t{\n\t\t\ttmpplanenum = tstack_p->planenum;\n\t\t\t// bk010221 - new location of divide by zero (see above)\n\t\t\tif ( front == back ) front -= 0.001f; // bk0101022 - hack/FPE \n                \t//calculate the hitpoint with the node (split point of the line)\n\t\t\t//put the crosspoint TRACEPLANE_EPSILON pixels on the near side\n\t\t\tif (front < 0) frac = (front + TRACEPLANE_EPSILON)/(front-back);\n\t\t\telse frac = (front - TRACEPLANE_EPSILON)/(front-back); // bk010221\n\t\t\t//\n\t\t\tif (frac < 0)\n\t\t\t\tfrac = 0.001f; //0\n\t\t\telse if (frac > 1)\n\t\t\t\tfrac = 0.999f; //1\n\t\t\t//frac = front / (front-back);\n\t\t\t//\n\t\t\tcur_mid[0] = cur_start[0] + (cur_end[0] - cur_start[0]) * frac;\n\t\t\tcur_mid[1] = cur_start[1] + (cur_end[1] - cur_start[1]) * frac;\n\t\t\tcur_mid[2] = cur_start[2] + (cur_end[2] - cur_start[2]) * frac;\n\n//\t\t\tAAS_DrawPlaneCross(cur_mid, plane->normal, plane->dist, plane->type, LINECOLOR_RED);\n\t\t\t//side the front part of the line is on\n\t\t\tside = front < 0;\n\t\t\t//first put the end part of the line on the stack (back side)\n\t\t\tVectorCopy(cur_mid, tstack_p->start);\n\t\t\t//not necesary to store because still on stack\n\t\t\t//VectorCopy(cur_end, tstack_p->end);\n\t\t\ttstack_p->planenum = aasnode->planenum;\n\t\t\ttstack_p->nodenum = aasnode->children[!side];\n\t\t\ttstack_p++;\n\t\t\tif (tstack_p >= &tracestack[127])\n\t\t\t{\n\t\t\t\tbotimport.Print(PRT_ERROR, \"AAS_TraceBoundingBox: stack overflow\\n\");\n\t\t\t\treturn trace;\n\t\t\t} //end if\n\t\t\t//now put the part near the start of the line on the stack so we will\n\t\t\t//continue with thats part first. This way we'll find the first\n\t\t\t//hit of the bbox\n\t\t\tVectorCopy(cur_start, tstack_p->start);\n\t\t\tVectorCopy(cur_mid, tstack_p->end);\n\t\t\ttstack_p->planenum = tmpplanenum;\n\t\t\ttstack_p->nodenum = aasnode->children[side];\n\t\t\ttstack_p++;\n\t\t\tif (tstack_p >= &tracestack[127])\n\t\t\t{\n\t\t\t\tbotimport.Print(PRT_ERROR, \"AAS_TraceBoundingBox: stack overflow\\n\");\n\t\t\t\treturn trace;\n\t\t\t} //end if\n\t\t} //end else\n\t} //end while\n//\treturn trace;\n} //end of the function AAS_TraceClientBBox\n//===========================================================================\n// recursive subdivision of the line by the BSP tree.\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_TraceAreas(vec3_t start, vec3_t end, int *areas, vec3_t *points, int maxareas)\n{\n\tint side, nodenum, tmpplanenum;\n\tint numareas;\n\tfloat front, back, frac;\n\tvec3_t cur_start, cur_end, cur_mid;\n\taas_tracestack_t tracestack[127];\n\taas_tracestack_t *tstack_p;\n\taas_node_t *aasnode;\n\taas_plane_t *plane;\n\n\tnumareas = 0;\n\tareas[0] = 0;\n\tif (!aasworld.loaded) return numareas;\n\n\ttstack_p = tracestack;\n\t//we start with the whole line on the stack\n\tVectorCopy(start, tstack_p->start);\n\tVectorCopy(end, tstack_p->end);\n\ttstack_p->planenum = 0;\n\t//start with node 1 because node zero is a dummy for a solid leaf\n\ttstack_p->nodenum = 1;\t\t//starting at the root of the tree\n\ttstack_p++;\n\n\twhile (1)\n\t{\n\t\t//pop up the stack\n\t\ttstack_p--;\n\t\t//if the trace stack is empty (ended up with a piece of the\n\t\t//line to be traced in an area)\n\t\tif (tstack_p < tracestack)\n\t\t{\n\t\t\treturn numareas;\n\t\t} //end if\n\t\t//number of the current node to test the line against\n\t\tnodenum = tstack_p->nodenum;\n\t\t//if it is an area\n\t\tif (nodenum < 0)\n\t\t{\n#ifdef AAS_SAMPLE_DEBUG\n\t\t\tif (-nodenum > aasworld.numareasettings)\n\t\t\t{\n\t\t\t\tbotimport.Print(PRT_ERROR, \"AAS_TraceAreas: -nodenum = %d out of range\\n\", -nodenum);\n\t\t\t\treturn numareas;\n\t\t\t} //end if\n#endif //AAS_SAMPLE_DEBUG\n\t\t\t//botimport.Print(PRT_MESSAGE, \"areanum = %d, must be %d\\n\", -nodenum, AAS_PointAreaNum(start));\n\t\t\tareas[numareas] = -nodenum;\n\t\t\tif (points) VectorCopy(tstack_p->start, points[numareas]);\n\t\t\tnumareas++;\n\t\t\tif (numareas >= maxareas) return numareas;\n\t\t\tcontinue;\n\t\t} //end if\n\t\t//if it is a solid leaf\n\t\tif (!nodenum)\n\t\t{\n\t\t\tcontinue;\n\t\t} //end if\n#ifdef AAS_SAMPLE_DEBUG\n\t\tif (nodenum > aasworld.numnodes)\n\t\t{\n\t\t\tbotimport.Print(PRT_ERROR, \"AAS_TraceAreas: nodenum out of range\\n\");\n\t\t\treturn numareas;\n\t\t} //end if\n#endif //AAS_SAMPLE_DEBUG\n\t\t//the node to test against\n\t\taasnode = &aasworld.nodes[nodenum];\n\t\t//start point of current line to test against node\n\t\tVectorCopy(tstack_p->start, cur_start);\n\t\t//end point of the current line to test against node\n\t\tVectorCopy(tstack_p->end, cur_end);\n\t\t//the current node plane\n\t\tplane = &aasworld.planes[aasnode->planenum];\n\n        front = DotProduct(cur_start, plane->normal) - plane->dist;\n        back = DotProduct(cur_end, plane->normal) - plane->dist;\n\n\t\t//if the whole to be traced line is totally at the front of this node\n\t\t//only go down the tree with the front child\n\t\tif (front > 0 && back > 0)\n\t\t{\n\t\t\t//keep the current start and end point on the stack\n\t\t\t//and go down the tree with the front child\n\t\t\ttstack_p->nodenum = aasnode->children[0];\n\t\t\ttstack_p++;\n\t\t\tif (tstack_p >= &tracestack[127])\n\t\t\t{\n\t\t\t\tbotimport.Print(PRT_ERROR, \"AAS_TraceAreas: stack overflow\\n\");\n\t\t\t\treturn numareas;\n\t\t\t} //end if\n\t\t} //end if\n\t\t//if the whole to be traced line is totally at the back of this node\n\t\t//only go down the tree with the back child\n\t\telse if (front <= 0 && back <= 0)\n\t\t{\n\t\t\t//keep the current start and end point on the stack\n\t\t\t//and go down the tree with the back child\n\t\t\ttstack_p->nodenum = aasnode->children[1];\n\t\t\ttstack_p++;\n\t\t\tif (tstack_p >= &tracestack[127])\n\t\t\t{\n\t\t\t\tbotimport.Print(PRT_ERROR, \"AAS_TraceAreas: stack overflow\\n\");\n\t\t\t\treturn numareas;\n\t\t\t} //end if\n\t\t} //end if\n\t\t//go down the tree both at the front and back of the node\n\t\telse\n\t\t{\n\t\t\ttmpplanenum = tstack_p->planenum;\n\t\t\t//calculate the hitpoint with the node (split point of the line)\n\t\t\t//put the crosspoint TRACEPLANE_EPSILON pixels on the near side\n\t\t\tif (front < 0) frac = (front)/(front-back);\n\t\t\telse frac = (front)/(front-back);\n\t\t\tif (frac < 0) frac = 0;\n\t\t\telse if (frac > 1) frac = 1;\n\t\t\t//frac = front / (front-back);\n\t\t\t//\n\t\t\tcur_mid[0] = cur_start[0] + (cur_end[0] - cur_start[0]) * frac;\n\t\t\tcur_mid[1] = cur_start[1] + (cur_end[1] - cur_start[1]) * frac;\n\t\t\tcur_mid[2] = cur_start[2] + (cur_end[2] - cur_start[2]) * frac;\n\n//\t\t\tAAS_DrawPlaneCross(cur_mid, plane->normal, plane->dist, plane->type, LINECOLOR_RED);\n\t\t\t//side the front part of the line is on\n\t\t\tside = front < 0;\n\t\t\t//first put the end part of the line on the stack (back side)\n\t\t\tVectorCopy(cur_mid, tstack_p->start);\n\t\t\t//not necesary to store because still on stack\n\t\t\t//VectorCopy(cur_end, tstack_p->end);\n\t\t\ttstack_p->planenum = aasnode->planenum;\n\t\t\ttstack_p->nodenum = aasnode->children[!side];\n\t\t\ttstack_p++;\n\t\t\tif (tstack_p >= &tracestack[127])\n\t\t\t{\n\t\t\t\tbotimport.Print(PRT_ERROR, \"AAS_TraceAreas: stack overflow\\n\");\n\t\t\t\treturn numareas;\n\t\t\t} //end if\n\t\t\t//now put the part near the start of the line on the stack so we will\n\t\t\t//continue with thats part first. This way we'll find the first\n\t\t\t//hit of the bbox\n\t\t\tVectorCopy(cur_start, tstack_p->start);\n\t\t\tVectorCopy(cur_mid, tstack_p->end);\n\t\t\ttstack_p->planenum = tmpplanenum;\n\t\t\ttstack_p->nodenum = aasnode->children[side];\n\t\t\ttstack_p++;\n\t\t\tif (tstack_p >= &tracestack[127])\n\t\t\t{\n\t\t\t\tbotimport.Print(PRT_ERROR, \"AAS_TraceAreas: stack overflow\\n\");\n\t\t\t\treturn numareas;\n\t\t\t} //end if\n\t\t} //end else\n\t} //end while\n//\treturn numareas;\n} //end of the function AAS_TraceAreas\n//===========================================================================\n// a simple cross product\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\n// void AAS_OrthogonalToVectors(vec3_t v1, vec3_t v2, vec3_t res)\n#define AAS_OrthogonalToVectors(v1, v2, res) \\\n\t(res)[0] = ((v1)[1] * (v2)[2]) - ((v1)[2] * (v2)[1]);\\\n\t(res)[1] = ((v1)[2] * (v2)[0]) - ((v1)[0] * (v2)[2]);\\\n\t(res)[2] = ((v1)[0] * (v2)[1]) - ((v1)[1] * (v2)[0]);\n//===========================================================================\n// tests if the given point is within the face boundaries\n//\n// Parameter:\t\t\t\tface\t\t: face to test if the point is in it\n//\t\t\t\t\t\t\t\tpnormal\t: normal of the plane to use for the face\n//\t\t\t\t\t\t\t\tpoint\t\t: point to test if inside face boundaries\n// Returns:\t\t\t\t\tqtrue if the point is within the face boundaries\n// Changes Globals:\t\t-\n//===========================================================================\nqboolean AAS_InsideFace(aas_face_t *face, vec3_t pnormal, vec3_t point, float epsilon)\n{\n\tint i, firstvertex, edgenum;\n\tvec3_t v0;\n\tvec3_t edgevec, pointvec, sepnormal;\n\taas_edge_t *edge;\n#ifdef AAS_SAMPLE_DEBUG\n\tint lastvertex = 0;\n#endif //AAS_SAMPLE_DEBUG\n\n\tif (!aasworld.loaded) return qfalse;\n\n\tfor (i = 0; i < face->numedges; i++)\n\t{\n\t\tedgenum = aasworld.edgeindex[face->firstedge + i];\n\t\tedge = &aasworld.edges[abs(edgenum)];\n\t\t//get the first vertex of the edge\n\t\tfirstvertex = edgenum < 0;\n\t\tVectorCopy(aasworld.vertexes[edge->v[firstvertex]], v0);\n\t\t//edge vector\n\t\tVectorSubtract(aasworld.vertexes[edge->v[!firstvertex]], v0, edgevec);\n\t\t//\n#ifdef AAS_SAMPLE_DEBUG\n\t\tif (lastvertex && lastvertex != edge->v[firstvertex])\n\t\t{\n\t\t\tbotimport.Print(PRT_MESSAGE, \"winding not counter clockwise\\n\");\n\t\t} //end if\n\t\tlastvertex = edge->v[!firstvertex];\n#endif //AAS_SAMPLE_DEBUG\n\t\t//vector from first edge point to point possible in face\n\t\tVectorSubtract(point, v0, pointvec);\n\t\t//get a vector pointing inside the face orthogonal to both the\n\t\t//edge vector and the normal vector of the plane the face is in\n\t\t//this vector defines a plane through the origin (first vertex of\n\t\t//edge) and through both the edge vector and the normal vector\n\t\t//of the plane\n\t\tAAS_OrthogonalToVectors(edgevec, pnormal, sepnormal);\n\t\t//check on wich side of the above plane the point is\n\t\t//this is done by checking the sign of the dot product of the\n\t\t//vector orthogonal vector from above and the vector from the\n\t\t//origin (first vertex of edge) to the point \n\t\t//if the dotproduct is smaller than zero the point is outside the face\n\t\tif (DotProduct(pointvec, sepnormal) < -epsilon) return qfalse;\n\t} //end for\n\treturn qtrue;\n} //end of the function AAS_InsideFace\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nqboolean AAS_PointInsideFace(int facenum, vec3_t point, float epsilon)\n{\n\tint i, firstvertex, edgenum;\n\tvec_t *v1, *v2;\n\tvec3_t edgevec, pointvec, sepnormal;\n\taas_edge_t *edge;\n\taas_plane_t *plane;\n\taas_face_t *face;\n\n\tif (!aasworld.loaded) return qfalse;\n\n\tface = &aasworld.faces[facenum];\n\tplane = &aasworld.planes[face->planenum];\n\t//\n\tfor (i = 0; i < face->numedges; i++)\n\t{\n\t\tedgenum = aasworld.edgeindex[face->firstedge + i];\n\t\tedge = &aasworld.edges[abs(edgenum)];\n\t\t//get the first vertex of the edge\n\t\tfirstvertex = edgenum < 0;\n\t\tv1 = aasworld.vertexes[edge->v[firstvertex]];\n\t\tv2 = aasworld.vertexes[edge->v[!firstvertex]];\n\t\t//edge vector\n\t\tVectorSubtract(v2, v1, edgevec);\n\t\t//vector from first edge point to point possible in face\n\t\tVectorSubtract(point, v1, pointvec);\n\t\t//\n\t\tCrossProduct(edgevec, plane->normal, sepnormal);\n\t\t//\n\t\tif (DotProduct(pointvec, sepnormal) < -epsilon) return qfalse;\n\t} //end for\n\treturn qtrue;\n} //end of the function AAS_PointInsideFace\n//===========================================================================\n// returns the ground face the given point is above in the given area\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\naas_face_t *AAS_AreaGroundFace(int areanum, vec3_t point)\n{\n\tint i, facenum;\n\tvec3_t up = {0, 0, 1};\n\tvec3_t normal;\n\taas_area_t *area;\n\taas_face_t *face;\n\n\tif (!aasworld.loaded) return NULL;\n\n\tarea = &aasworld.areas[areanum];\n\tfor (i = 0; i < area->numfaces; i++)\n\t{\n\t\tfacenum = aasworld.faceindex[area->firstface + i];\n\t\tface = &aasworld.faces[abs(facenum)];\n\t\t//if this is a ground face\n\t\tif (face->faceflags & FACE_GROUND)\n\t\t{\n\t\t\t//get the up or down normal\n\t\t\tif (aasworld.planes[face->planenum].normal[2] < 0) VectorNegate(up, normal);\n\t\t\telse VectorCopy(up, normal);\n\t\t\t//check if the point is in the face\n\t\t\tif (AAS_InsideFace(face, normal, point, 0.01f)) return face;\n\t\t} //end if\n\t} //end for\n\treturn NULL;\n} //end of the function AAS_AreaGroundFace\n//===========================================================================\n// returns the face the trace end position is situated in\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_FacePlane(int facenum, vec3_t normal, float *dist)\n{\n\taas_plane_t *plane;\n\n\tplane = &aasworld.planes[aasworld.faces[facenum].planenum];\n\tVectorCopy(plane->normal, normal);\n\t*dist = plane->dist;\n} //end of the function AAS_FacePlane\n//===========================================================================\n// returns the face the trace end position is situated in\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\naas_face_t *AAS_TraceEndFace(aas_trace_t *trace)\n{\n\tint i, facenum;\n\taas_area_t *area;\n\taas_face_t *face, *firstface = NULL;\n\n\tif (!aasworld.loaded) return NULL;\n\n\t//if started in solid no face was hit\n\tif (trace->startsolid) return NULL;\n\t//trace->lastarea is the last area the trace was in\n\tarea = &aasworld.areas[trace->lastarea];\n\t//check which face the trace.endpos was in\n\tfor (i = 0; i < area->numfaces; i++)\n\t{\n\t\tfacenum = aasworld.faceindex[area->firstface + i];\n\t\tface = &aasworld.faces[abs(facenum)];\n\t\t//if the face is in the same plane as the trace end point\n\t\tif ((face->planenum & ~1) == (trace->planenum & ~1))\n\t\t{\n\t\t\t//firstface is used for optimization, if theres only one\n\t\t\t//face in the plane then it has to be the good one\n\t\t\t//if there are more faces in the same plane then always\n\t\t\t//check the one with the fewest edges first\n/*\t\t\tif (firstface)\n\t\t\t{\n\t\t\t\tif (firstface->numedges < face->numedges)\n\t\t\t\t{\n\t\t\t\t\tif (AAS_InsideFace(firstface,\n\t\t\t\t\t\taasworld.planes[face->planenum].normal, trace->endpos))\n\t\t\t\t\t{\n\t\t\t\t\t\treturn firstface;\n\t\t\t\t\t} //end if\n\t\t\t\t\tfirstface = face;\n\t\t\t\t} //end if\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (AAS_InsideFace(face,\n\t\t\t\t\t\taasworld.planes[face->planenum].normal, trace->endpos))\n\t\t\t\t\t{\n\t\t\t\t\t\treturn face;\n\t\t\t\t\t} //end if\n\t\t\t\t} //end else\n\t\t\t} //end if\n\t\t\telse\n\t\t\t{\n\t\t\t\tfirstface = face;\n\t\t\t} //end else*/\n\t\t\tif (AAS_InsideFace(face,\n\t\t\t\t\t\taasworld.planes[face->planenum].normal, trace->endpos, 0.01f)) return face;\n\t\t} //end if\n\t} //end for\n\treturn firstface;\n} //end of the function AAS_TraceEndFace\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_BoxOnPlaneSide2(vec3_t absmins, vec3_t absmaxs, aas_plane_t *p)\n{\n\tint i, sides;\n\tfloat dist1, dist2;\n\tvec3_t corners[2];\n\n\tfor (i = 0; i < 3; i++)\n\t{\n\t\tif (p->normal[i] < 0)\n\t\t{\n\t\t\tcorners[0][i] = absmins[i];\n\t\t\tcorners[1][i] = absmaxs[i];\n\t\t} //end if\n\t\telse\n\t\t{\n\t\t\tcorners[1][i] = absmins[i];\n\t\t\tcorners[0][i] = absmaxs[i];\n\t\t} //end else\n\t} //end for\n\tdist1 = DotProduct(p->normal, corners[0]) - p->dist;\n\tdist2 = DotProduct(p->normal, corners[1]) - p->dist;\n\tsides = 0;\n\tif (dist1 >= 0) sides = 1;\n\tif (dist2 < 0) sides |= 2;\n\n\treturn sides;\n} //end of the function AAS_BoxOnPlaneSide2\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\n//int AAS_BoxOnPlaneSide(vec3_t absmins, vec3_t absmaxs, aas_plane_t *p)\n#define AAS_BoxOnPlaneSide(absmins, absmaxs, p) (\\\n\t( (p)->type < 3) ?\\\n\t(\\\n\t\t( (p)->dist <= (absmins)[(p)->type]) ?\\\n\t\t(\\\n\t\t\t1\\\n\t\t)\\\n\t\t:\\\n\t\t(\\\n\t\t\t( (p)->dist >= (absmaxs)[(p)->type]) ?\\\n\t\t\t(\\\n\t\t\t\t2\\\n\t\t\t)\\\n\t\t\t:\\\n\t\t\t(\\\n\t\t\t\t3\\\n\t\t\t)\\\n\t\t)\\\n\t)\\\n\t:\\\n\t(\\\n\t\tAAS_BoxOnPlaneSide2((absmins), (absmaxs), (p))\\\n\t)\\\n) //end of the function AAS_BoxOnPlaneSide\n//===========================================================================\n// remove the links to this entity from all areas\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_UnlinkFromAreas(aas_link_t *areas)\n{\n\taas_link_t *link, *nextlink;\n\n\tfor (link = areas; link; link = nextlink)\n\t{\n\t\t//next area the entity is linked in\n\t\tnextlink = link->next_area;\n\t\t//remove the entity from the linked list of this area\n\t\tif (link->prev_ent) link->prev_ent->next_ent = link->next_ent;\n\t\telse aasworld.arealinkedentities[link->areanum] = link->next_ent;\n\t\tif (link->next_ent) link->next_ent->prev_ent = link->prev_ent;\n\t\t//deallocate the link structure\n\t\tAAS_DeAllocAASLink(link);\n\t} //end for\n} //end of the function AAS_UnlinkFromAreas\n//===========================================================================\n// link the entity to the areas the bounding box is totally or partly\n// situated in. This is done with recursion down the tree using the\n// bounding box to test for plane sides\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\n\ntypedef struct\n{\n\tint nodenum;\t\t//node found after splitting\n} aas_linkstack_t;\n\naas_link_t *AAS_AASLinkEntity(vec3_t absmins, vec3_t absmaxs, int entnum)\n{\n\tint side, nodenum;\n\taas_linkstack_t linkstack[128];\n\taas_linkstack_t *lstack_p;\n\taas_node_t *aasnode;\n\taas_plane_t *plane;\n\taas_link_t *link, *areas;\n\n\tif (!aasworld.loaded)\n\t{\n\t\tbotimport.Print(PRT_ERROR, \"AAS_LinkEntity: aas not loaded\\n\");\n\t\treturn NULL;\n\t} //end if\n\n\tareas = NULL;\n\t//\n\tlstack_p = linkstack;\n\t//we start with the whole line on the stack\n\t//start with node 1 because node zero is a dummy used for solid leafs\n\tlstack_p->nodenum = 1;\t\t//starting at the root of the tree\n\tlstack_p++;\n\t\n\twhile (1)\n\t{\n\t\t//pop up the stack\n\t\tlstack_p--;\n\t\t//if the trace stack is empty (ended up with a piece of the\n\t\t//line to be traced in an area)\n\t\tif (lstack_p < linkstack) break;\n\t\t//number of the current node to test the line against\n\t\tnodenum = lstack_p->nodenum;\n\t\t//if it is an area\n\t\tif (nodenum < 0)\n\t\t{\n\t\t\t//NOTE: the entity might have already been linked into this area\n\t\t\t// because several node children can point to the same area\n\t\t\tfor (link = aasworld.arealinkedentities[-nodenum]; link; link = link->next_ent)\n\t\t\t{\n\t\t\t\tif (link->entnum == entnum) break;\n\t\t\t} //end for\n\t\t\tif (link) continue;\n\t\t\t//\n\t\t\tlink = AAS_AllocAASLink();\n\t\t\tif (!link) return areas;\n\t\t\tlink->entnum = entnum;\n\t\t\tlink->areanum = -nodenum;\n\t\t\t//put the link into the double linked area list of the entity\n\t\t\tlink->prev_area = NULL;\n\t\t\tlink->next_area = areas;\n\t\t\tif (areas) areas->prev_area = link;\n\t\t\tareas = link;\n\t\t\t//put the link into the double linked entity list of the area\n\t\t\tlink->prev_ent = NULL;\n\t\t\tlink->next_ent = aasworld.arealinkedentities[-nodenum];\n\t\t\tif (aasworld.arealinkedentities[-nodenum])\n\t\t\t\t\taasworld.arealinkedentities[-nodenum]->prev_ent = link;\n\t\t\taasworld.arealinkedentities[-nodenum] = link;\n\t\t\t//\n\t\t\tcontinue;\n\t\t} //end if\n\t\t//if solid leaf\n\t\tif (!nodenum) continue;\n\t\t//the node to test against\n\t\taasnode = &aasworld.nodes[nodenum];\n\t\t//the current node plane\n\t\tplane = &aasworld.planes[aasnode->planenum];\n\t\t//get the side(s) the box is situated relative to the plane\n\t\tside = AAS_BoxOnPlaneSide2(absmins, absmaxs, plane);\n\t\t//if on the front side of the node\n\t\tif (side & 1)\n\t\t{\n\t\t\tlstack_p->nodenum = aasnode->children[0];\n\t\t\tlstack_p++;\n\t\t} //end if\n\t\tif (lstack_p >= &linkstack[127])\n\t\t{\n\t\t\tbotimport.Print(PRT_ERROR, \"AAS_LinkEntity: stack overflow\\n\");\n\t\t\tbreak;\n\t\t} //end if\n\t\t//if on the back side of the node\n\t\tif (side & 2)\n\t\t{\n\t\t\tlstack_p->nodenum = aasnode->children[1];\n\t\t\tlstack_p++;\n\t\t} //end if\n\t\tif (lstack_p >= &linkstack[127])\n\t\t{\n\t\t\tbotimport.Print(PRT_ERROR, \"AAS_LinkEntity: stack overflow\\n\");\n\t\t\tbreak;\n\t\t} //end if\n\t} //end while\n\treturn areas;\n} //end of the function AAS_AASLinkEntity\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\naas_link_t *AAS_LinkEntityClientBBox(vec3_t absmins, vec3_t absmaxs, int entnum, int presencetype)\n{\n\tvec3_t mins, maxs;\n\tvec3_t newabsmins, newabsmaxs;\n\n\tAAS_PresenceTypeBoundingBox(presencetype, mins, maxs);\n\tVectorSubtract(absmins, maxs, newabsmins);\n\tVectorSubtract(absmaxs, mins, newabsmaxs);\n\t//relink the entity\n\treturn AAS_AASLinkEntity(newabsmins, newabsmaxs, entnum);\n} //end of the function AAS_LinkEntityClientBBox\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_BBoxAreas(vec3_t absmins, vec3_t absmaxs, int *areas, int maxareas)\n{\n\taas_link_t *linkedareas, *link;\n\tint num;\n\n\tlinkedareas = AAS_AASLinkEntity(absmins, absmaxs, -1);\n\tnum = 0;\n\tfor (link = linkedareas; link; link = link->next_area)\n\t{\n\t\tareas[num] = link->areanum;\n\t\tnum++;\n\t\tif (num >= maxareas)\n\t\t\tbreak;\n\t} //end for\n\tAAS_UnlinkFromAreas(linkedareas);\n\treturn num;\n} //end of the function AAS_BBoxAreas\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AAS_AreaInfo( int areanum, aas_areainfo_t *info )\n{\n\taas_areasettings_t *settings;\n\tif (!info)\n\t\treturn 0;\n\tif (areanum <= 0 || areanum >= aasworld.numareas)\n\t{\n\t\tbotimport.Print(PRT_ERROR, \"AAS_AreaInfo: areanum %d out of range\\n\", areanum);\n\t\treturn 0;\n\t} //end if\n\tsettings = &aasworld.areasettings[areanum];\n\tinfo->cluster = settings->cluster;\n\tinfo->contents = settings->contents;\n\tinfo->flags = settings->areaflags;\n\tinfo->presencetype = settings->presencetype;\n\tVectorCopy(aasworld.areas[areanum].mins, info->mins);\n\tVectorCopy(aasworld.areas[areanum].maxs, info->maxs);\n\tVectorCopy(aasworld.areas[areanum].center, info->center);\n\treturn sizeof(aas_areainfo_t);\n} //end of the function AAS_AreaInfo\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\naas_plane_t *AAS_PlaneFromNum(int planenum)\n{\n\tif (!aasworld.loaded) return 0;\n\n\treturn &aasworld.planes[planenum];\n} //end of the function AAS_PlaneFromNum\n"
  },
  {
    "path": "src/engine/botlib/be_aas_sample.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tbe_aas_sample.h\n *\n * desc:\t\tAAS\n *\n * $Archive: /source/code/botlib/be_aas_sample.h $\n *\n *****************************************************************************/\n\n#ifdef AASINTERN\nvoid AAS_InitAASLinkHeap(void);\nvoid AAS_InitAASLinkedEntities(void);\nvoid AAS_FreeAASLinkHeap(void);\nvoid AAS_FreeAASLinkedEntities(void);\naas_face_t *AAS_AreaGroundFace(int areanum, vec3_t point);\naas_face_t *AAS_TraceEndFace(aas_trace_t *trace);\naas_plane_t *AAS_PlaneFromNum(int planenum);\naas_link_t *AAS_AASLinkEntity(vec3_t absmins, vec3_t absmaxs, int entnum);\naas_link_t *AAS_LinkEntityClientBBox(vec3_t absmins, vec3_t absmaxs, int entnum, int presencetype);\nqboolean AAS_PointInsideFace(int facenum, vec3_t point, float epsilon);\nqboolean AAS_InsideFace(aas_face_t *face, vec3_t pnormal, vec3_t point, float epsilon);\nvoid AAS_UnlinkFromAreas(aas_link_t *areas);\n#endif //AASINTERN\n\n//returns the mins and maxs of the bounding box for the given presence type\nvoid AAS_PresenceTypeBoundingBox(int presencetype, vec3_t mins, vec3_t maxs);\n//returns the cluster the area is in (negative portal number if the area is a portal)\nint AAS_AreaCluster(int areanum);\n//returns the presence type(s) of the area\nint AAS_AreaPresenceType(int areanum);\n//returns the presence type(s) at the given point\nint AAS_PointPresenceType(vec3_t point);\n//returns the result of the trace of a client bbox\naas_trace_t AAS_TraceClientBBox(vec3_t start, vec3_t end, int presencetype, int passent);\n//stores the areas the trace went through and returns the number of passed areas\nint AAS_TraceAreas(vec3_t start, vec3_t end, int *areas, vec3_t *points, int maxareas);\n//returns the areas the bounding box is in\nint AAS_BBoxAreas(vec3_t absmins, vec3_t absmaxs, int *areas, int maxareas);\n//return area information\nint AAS_AreaInfo( int areanum, aas_areainfo_t *info );\n//returns the area the point is in\nint AAS_PointAreaNum(vec3_t point);\n//\nint AAS_PointReachabilityAreaIndex( vec3_t point );\n//returns the plane the given face is in\nvoid AAS_FacePlane(int facenum, vec3_t normal, float *dist);\n\n"
  },
  {
    "path": "src/engine/botlib/be_ai_char.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tbe_ai_char.c\n *\n * desc:\t\tbot characters\n *\n * $Archive: /MissionPack/code/botlib/be_ai_char.c $\n *\n *****************************************************************************/\n\n#include \"../../game/q_shared.h\"\n#include \"l_log.h\"\n#include \"l_memory.h\"\n#include \"l_utils.h\"\n#include \"l_script.h\"\n#include \"l_precomp.h\"\n#include \"l_struct.h\"\n#include \"l_libvar.h\"\n#include \"aasfile.h\"\n#include \"../../game/botlib.h\"\n#include \"../../game/be_aas.h\"\n#include \"be_aas_funcs.h\"\n#include \"be_interface.h\"\n#include \"../../game/be_ai_char.h\"\n\n#define MAX_CHARACTERISTICS\t\t80\n\n#define CT_INTEGER\t\t\t\t1\n#define CT_FLOAT\t\t\t\t2\n#define CT_STRING\t\t\t\t3\n\n#define DEFAULT_CHARACTER\t\t\"bots/default_c.c\"\n\n//characteristic value\nunion cvalue\n{\n\tint integer;\n\tfloat _float;\n\tchar *string;\n};\n//a characteristic\ntypedef struct bot_characteristic_s\n{\n\tchar type;\t\t\t\t\t\t//characteristic type\n\tunion cvalue value;\t\t\t\t//characteristic value\n} bot_characteristic_t;\n\n//a bot character\ntypedef struct bot_character_s\n{\n\tchar filename[MAX_QPATH];\n\tfloat skill;\n\tbot_characteristic_t c[1];\t\t//variable sized\n} bot_character_t;\n\nbot_character_t *botcharacters[MAX_CLIENTS + 1];\n\n//========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//========================================================================\nbot_character_t *BotCharacterFromHandle(int handle)\n{\n\tif (handle <= 0 || handle > MAX_CLIENTS)\n\t{\n\t\tbotimport.Print(PRT_FATAL, \"character handle %d out of range\\n\", handle);\n\t\treturn NULL;\n\t} //end if\n\tif (!botcharacters[handle])\n\t{\n\t\tbotimport.Print(PRT_FATAL, \"invalid character %d\\n\", handle);\n\t\treturn NULL;\n\t} //end if\n\treturn botcharacters[handle];\n} //end of the function BotCharacterFromHandle\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotDumpCharacter(bot_character_t *ch)\n{\n\tint i;\n\n\tLog_Write(\"%s\", ch->filename);\n\tLog_Write(\"skill %d\\n\", ch->skill);\n\tLog_Write(\"{\\n\");\n\tfor (i = 0; i < MAX_CHARACTERISTICS; i++)\n\t{\n\t\tswitch(ch->c[i].type)\n\t\t{\n\t\t\tcase CT_INTEGER: Log_Write(\" %4d %d\\n\", i, ch->c[i].value.integer); break;\n\t\t\tcase CT_FLOAT: Log_Write(\" %4d %f\\n\", i, ch->c[i].value._float); break;\n\t\t\tcase CT_STRING: Log_Write(\" %4d %s\\n\", i, ch->c[i].value.string); break;\n\t\t} //end case\n\t} //end for\n\tLog_Write(\"}\\n\");\n} //end of the function BotDumpCharacter\n//========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//========================================================================\nvoid BotFreeCharacterStrings(bot_character_t *ch)\n{\n\tint i;\n\n\tfor (i = 0; i < MAX_CHARACTERISTICS; i++)\n\t{\n\t\tif (ch->c[i].type == CT_STRING)\n\t\t{\n\t\t\tFreeMemory(ch->c[i].value.string);\n\t\t} //end if\n\t} //end for\n} //end of the function BotFreeCharacterStrings\n//========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//========================================================================\nvoid BotFreeCharacter2(int handle)\n{\n\tif (handle <= 0 || handle > MAX_CLIENTS)\n\t{\n\t\tbotimport.Print(PRT_FATAL, \"character handle %d out of range\\n\", handle);\n\t\treturn;\n\t} //end if\n\tif (!botcharacters[handle])\n\t{\n\t\tbotimport.Print(PRT_FATAL, \"invalid character %d\\n\", handle);\n\t\treturn;\n\t} //end if\n\tBotFreeCharacterStrings(botcharacters[handle]);\n\tFreeMemory(botcharacters[handle]);\n\tbotcharacters[handle] = NULL;\n} //end of the function BotFreeCharacter2\n//========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//========================================================================\nvoid BotFreeCharacter(int handle)\n{\n\tif (!LibVarGetValue(\"bot_reloadcharacters\")) return;\n\tBotFreeCharacter2(handle);\n} //end of the function BotFreeCharacter\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotDefaultCharacteristics(bot_character_t *ch, bot_character_t *defaultch)\n{\n\tint i;\n\n\tfor (i = 0; i < MAX_CHARACTERISTICS; i++)\n\t{\n\t\tif (ch->c[i].type) continue;\n\t\t//\n\t\tif (defaultch->c[i].type == CT_FLOAT)\n\t\t{\n\t\t\tch->c[i].type = CT_FLOAT;\n\t\t\tch->c[i].value._float = defaultch->c[i].value._float;\n\t\t} //end if\n\t\telse if (defaultch->c[i].type == CT_INTEGER)\n\t\t{\n\t\t\tch->c[i].type = CT_INTEGER;\n\t\t\tch->c[i].value.integer = defaultch->c[i].value.integer;\n\t\t} //end else if\n\t\telse if (defaultch->c[i].type == CT_STRING)\n\t\t{\n\t\t\tch->c[i].type = CT_STRING;\n\t\t\tch->c[i].value.string = (char *) GetMemory((int)strlen(defaultch->c[i].value.string)+1);\n\t\t\tstrcpy(ch->c[i].value.string, defaultch->c[i].value.string);\n\t\t} //end else if\n\t} //end for\n} //end of the function BotDefaultCharacteristics\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nbot_character_t *BotLoadCharacterFromFile(char *charfile, int skill)\n{\n\tint indent, index, foundcharacter;\n\tbot_character_t *ch;\n\tsource_t *source;\n\ttoken_t token;\n\n\tfoundcharacter = qfalse;\n\t//a bot character is parsed in two phases\n\tPC_SetBaseFolder(BOTFILESBASEFOLDER);\n\tsource = LoadSourceFile(charfile);\n\tif (!source)\n\t{\n\t\tbotimport.Print(PRT_ERROR, \"counldn't load %s\\n\", charfile);\n\t\treturn NULL;\n\t} //end if\n\tch = (bot_character_t *) GetClearedMemory(sizeof(bot_character_t) +\n\t\t\t\t\tMAX_CHARACTERISTICS * sizeof(bot_characteristic_t));\n\tstrcpy(ch->filename, charfile);\n\twhile(PC_ReadToken(source, &token))\n\t{\n\t\tif (!strcmp(token.string, \"skill\"))\n\t\t{\n\t\t\tif (!PC_ExpectTokenType(source, TT_NUMBER, 0, &token))\n\t\t\t{\n\t\t\t\tFreeSource(source);\n\t\t\t\tBotFreeCharacterStrings(ch);\n\t\t\t\tFreeMemory(ch);\n\t\t\t\treturn NULL;\n\t\t\t} //end if\n\t\t\tif (!PC_ExpectTokenString(source, \"{\"))\n\t\t\t{\n\t\t\t\tFreeSource(source);\n\t\t\t\tBotFreeCharacterStrings(ch);\n\t\t\t\tFreeMemory(ch);\n\t\t\t\treturn NULL;\n\t\t\t} //end if\n\t\t\t//if it's the correct skill\n\t\t\tif (skill < 0 || (int)token.intvalue == skill)\n\t\t\t{\n\t\t\t\tfoundcharacter = qtrue;\n\t\t\t\tch->skill = token.intvalue;\n\t\t\t\twhile(PC_ExpectAnyToken(source, &token))\n\t\t\t\t{\n\t\t\t\t\tif (!strcmp(token.string, \"}\")) break;\n\t\t\t\t\tif (token.type != TT_NUMBER || !(token.subtype & TT_INTEGER))\n\t\t\t\t\t{\n\t\t\t\t\t\tSourceError(source, \"expected integer index, found %s\\n\", token.string);\n\t\t\t\t\t\tFreeSource(source);\n\t\t\t\t\t\tBotFreeCharacterStrings(ch);\n\t\t\t\t\t\tFreeMemory(ch);\n\t\t\t\t\t\treturn NULL;\n\t\t\t\t\t} //end if\n\t\t\t\t\tindex = token.intvalue;\n\t\t\t\t\tif (index < 0 || index > MAX_CHARACTERISTICS)\n\t\t\t\t\t{\n\t\t\t\t\t\tSourceError(source, \"characteristic index out of range [0, %d]\\n\", MAX_CHARACTERISTICS);\n\t\t\t\t\t\tFreeSource(source);\n\t\t\t\t\t\tBotFreeCharacterStrings(ch);\n\t\t\t\t\t\tFreeMemory(ch);\n\t\t\t\t\t\treturn NULL;\n\t\t\t\t\t} //end if\n\t\t\t\t\tif (ch->c[index].type)\n\t\t\t\t\t{\n\t\t\t\t\t\tSourceError(source, \"characteristic %d already initialized\\n\", index);\n\t\t\t\t\t\tFreeSource(source);\n\t\t\t\t\t\tBotFreeCharacterStrings(ch);\n\t\t\t\t\t\tFreeMemory(ch);\n\t\t\t\t\t\treturn NULL;\n\t\t\t\t\t} //end if\n\t\t\t\t\tif (!PC_ExpectAnyToken(source, &token))\n\t\t\t\t\t{\n\t\t\t\t\t\tFreeSource(source);\n\t\t\t\t\t\tBotFreeCharacterStrings(ch);\n\t\t\t\t\t\tFreeMemory(ch);\n\t\t\t\t\t\treturn NULL;\n\t\t\t\t\t} //end if\n\t\t\t\t\tif (token.type == TT_NUMBER)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (token.subtype & TT_FLOAT)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tch->c[index].value._float = token.floatvalue;\n\t\t\t\t\t\t\tch->c[index].type = CT_FLOAT;\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tch->c[index].value.integer = token.intvalue;\n\t\t\t\t\t\t\tch->c[index].type = CT_INTEGER;\n\t\t\t\t\t\t} //end else\n\t\t\t\t\t} //end if\n\t\t\t\t\telse if (token.type == TT_STRING)\n\t\t\t\t\t{\n\t\t\t\t\t\tStripDoubleQuotes(token.string);\n\t\t\t\t\t\tch->c[index].value.string = (char*)GetMemory((int)strlen(token.string)+1);\n\t\t\t\t\t\tstrcpy(ch->c[index].value.string, token.string);\n\t\t\t\t\t\tch->c[index].type = CT_STRING;\n\t\t\t\t\t} //end else if\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tSourceError(source, \"expected integer, float or string, found %s\\n\", token.string);\n\t\t\t\t\t\tFreeSource(source);\n\t\t\t\t\t\tBotFreeCharacterStrings(ch);\n\t\t\t\t\t\tFreeMemory(ch);\n\t\t\t\t\t\treturn NULL;\n\t\t\t\t\t} //end else\n\t\t\t\t} //end if\n\t\t\t\tbreak;\n\t\t\t} //end if\n\t\t\telse\n\t\t\t{\n\t\t\t\tindent = 1;\n\t\t\t\twhile(indent)\n\t\t\t\t{\n\t\t\t\t\tif (!PC_ExpectAnyToken(source, &token))\n\t\t\t\t\t{\n\t\t\t\t\t\tFreeSource(source);\n\t\t\t\t\t\tBotFreeCharacterStrings(ch);\n\t\t\t\t\t\tFreeMemory(ch);\n\t\t\t\t\t\treturn NULL;\n\t\t\t\t\t} //end if\n\t\t\t\t\tif (!strcmp(token.string, \"{\")) indent++;\n\t\t\t\t\telse if (!strcmp(token.string, \"}\")) indent--;\n\t\t\t\t} //end while\n\t\t\t} //end else\n\t\t} //end if\n\t\telse\n\t\t{\n\t\t\tSourceError(source, \"unknown definition %s\\n\", token.string);\n\t\t\tFreeSource(source);\n\t\t\tBotFreeCharacterStrings(ch);\n\t\t\tFreeMemory(ch);\n\t\t\treturn NULL;\n\t\t} //end else\n\t} //end while\n\tFreeSource(source);\n\t//\n\tif (!foundcharacter)\n\t{\n\t\tBotFreeCharacterStrings(ch);\n\t\tFreeMemory(ch);\n\t\treturn NULL;\n\t} //end if\n\treturn ch;\n} //end of the function BotLoadCharacterFromFile\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotFindCachedCharacter(char *charfile, float skill)\n{\n\tint handle;\n\n\tfor (handle = 1; handle <= MAX_CLIENTS; handle++)\n\t{\n\t\tif ( !botcharacters[handle] ) continue;\n\t\tif ( strcmp( botcharacters[handle]->filename, charfile ) == 0 &&\n\t\t\t(skill < 0 || fabs(botcharacters[handle]->skill - skill) < 0.01) )\n\t\t{\n\t\t\treturn handle;\n\t\t} //end if\n\t} //end for\n\treturn 0;\n} //end of the function BotFindCachedCharacter\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotLoadCachedCharacter(char *charfile, float skill, int reload)\n{\n\tint handle, cachedhandle, intskill;\n\tbot_character_t *ch = NULL;\n#ifdef DEBUG\n\tint starttime;\n\n\tstarttime = Sys_MilliSeconds();\n#endif //DEBUG\n\n\t//find a free spot for a character\n\tfor (handle = 1; handle <= MAX_CLIENTS; handle++)\n\t{\n\t\tif (!botcharacters[handle]) break;\n\t} //end for\n\tif (handle > MAX_CLIENTS) return 0;\n\t//try to load a cached character with the given skill\n\tif (!reload)\n\t{\n\t\tcachedhandle = BotFindCachedCharacter(charfile, skill);\n\t\tif (cachedhandle)\n\t\t{\n\t\t\tbotimport.Print(PRT_MESSAGE, \"loaded cached skill %f from %s\\n\", skill, charfile);\n\t\t\treturn cachedhandle;\n\t\t} //end if\n\t} //end else\n\t//\n\tintskill = (int) (skill + 0.5);\n\t//try to load the character with the given skill\n\tch = BotLoadCharacterFromFile(charfile, intskill);\n\tif (ch)\n\t{\n\t\tbotcharacters[handle] = ch;\n\t\t//\n\t\tbotimport.Print(PRT_MESSAGE, \"loaded skill %d from %s\\n\", intskill, charfile);\n#ifdef DEBUG\n\t\tif (bot_developer)\n\t\t{\n\t\t\tbotimport.Print(PRT_MESSAGE, \"skill %d loaded in %d msec from %s\\n\", intskill, Sys_MilliSeconds() - starttime, charfile);\n\t\t} //end if\n#endif //DEBUG\n\t\treturn handle;\n\t} //end if\n\t//\n\tbotimport.Print(PRT_WARNING, \"couldn't find skill %d in %s\\n\", intskill, charfile);\n\t//\n\tif (!reload)\n\t{\n\t\t//try to load a cached default character with the given skill\n\t\tcachedhandle = BotFindCachedCharacter(DEFAULT_CHARACTER, skill);\n\t\tif (cachedhandle)\n\t\t{\n\t\t\tbotimport.Print(PRT_MESSAGE, \"loaded cached default skill %d from %s\\n\", intskill, charfile);\n\t\t\treturn cachedhandle;\n\t\t} //end if\n\t} //end if\n\t//try to load the default character with the given skill\n\tch = BotLoadCharacterFromFile(DEFAULT_CHARACTER, intskill);\n\tif (ch)\n\t{\n\t\tbotcharacters[handle] = ch;\n\t\tbotimport.Print(PRT_MESSAGE, \"loaded default skill %d from %s\\n\", intskill, charfile);\n\t\treturn handle;\n\t} //end if\n\t//\n\tif (!reload)\n\t{\n\t\t//try to load a cached character with any skill\n\t\tcachedhandle = BotFindCachedCharacter(charfile, -1);\n\t\tif (cachedhandle)\n\t\t{\n\t\t\tbotimport.Print(PRT_MESSAGE, \"loaded cached skill %f from %s\\n\", botcharacters[cachedhandle]->skill, charfile);\n\t\t\treturn cachedhandle;\n\t\t} //end if\n\t} //end if\n\t//try to load a character with any skill\n\tch = BotLoadCharacterFromFile(charfile, -1);\n\tif (ch)\n\t{\n\t\tbotcharacters[handle] = ch;\n\t\tbotimport.Print(PRT_MESSAGE, \"loaded skill %f from %s\\n\", ch->skill, charfile);\n\t\treturn handle;\n\t} //end if\n\t//\n\tif (!reload)\n\t{\n\t\t//try to load a cached character with any skill\n\t\tcachedhandle = BotFindCachedCharacter(DEFAULT_CHARACTER, -1);\n\t\tif (cachedhandle)\n\t\t{\n\t\t\tbotimport.Print(PRT_MESSAGE, \"loaded cached default skill %f from %s\\n\", botcharacters[cachedhandle]->skill, charfile);\n\t\t\treturn cachedhandle;\n\t\t} //end if\n\t} //end if\n\t//try to load a character with any skill\n\tch = BotLoadCharacterFromFile(DEFAULT_CHARACTER, -1);\n\tif (ch)\n\t{\n\t\tbotcharacters[handle] = ch;\n\t\tbotimport.Print(PRT_MESSAGE, \"loaded default skill %f from %s\\n\", ch->skill, charfile);\n\t\treturn handle;\n\t} //end if\n\t//\n\tbotimport.Print(PRT_WARNING, \"couldn't load any skill from %s\\n\", charfile);\n\t//couldn't load any character\n\treturn 0;\n} //end of the function BotLoadCachedCharacter\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotLoadCharacterSkill(char *charfile, float skill)\n{\n\tint ch, defaultch;\n\n\tdefaultch = BotLoadCachedCharacter(DEFAULT_CHARACTER, skill, qfalse);\n\tch = BotLoadCachedCharacter(charfile, skill, LibVarGetValue(\"bot_reloadcharacters\"));\n\n\tif (defaultch && ch)\n\t{\n\t\tBotDefaultCharacteristics(botcharacters[ch], botcharacters[defaultch]);\n\t} //end if\n\n\treturn ch;\n} //end of the function BotLoadCharacterSkill\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotInterpolateCharacters(int handle1, int handle2, float desiredskill)\n{\n\tbot_character_t *ch1, *ch2, *out;\n\tint i, handle;\n\tfloat scale;\n\n\tch1 = BotCharacterFromHandle(handle1);\n\tch2 = BotCharacterFromHandle(handle2);\n\tif (!ch1 || !ch2)\n\t\treturn 0;\n\t//find a free spot for a character\n\tfor (handle = 1; handle <= MAX_CLIENTS; handle++)\n\t{\n\t\tif (!botcharacters[handle]) break;\n\t} //end for\n\tif (handle > MAX_CLIENTS) return 0;\n\tout = (bot_character_t *) GetClearedMemory(sizeof(bot_character_t) +\n\t\t\t\t\tMAX_CHARACTERISTICS * sizeof(bot_characteristic_t));\n\tout->skill = desiredskill;\n\tstrcpy(out->filename, ch1->filename);\n\tbotcharacters[handle] = out;\n\n\tscale = (float) (desiredskill - ch1->skill) / (ch2->skill - ch1->skill);\n\tfor (i = 0; i < MAX_CHARACTERISTICS; i++)\n\t{\n\t\t//\n\t\tif (ch1->c[i].type == CT_FLOAT && ch2->c[i].type == CT_FLOAT)\n\t\t{\n\t\t\tout->c[i].type = CT_FLOAT;\n\t\t\tout->c[i].value._float = ch1->c[i].value._float +\n\t\t\t\t\t\t\t\t(ch2->c[i].value._float - ch1->c[i].value._float) * scale;\n\t\t} //end if\n\t\telse if (ch1->c[i].type == CT_INTEGER)\n\t\t{\n\t\t\tout->c[i].type = CT_INTEGER;\n\t\t\tout->c[i].value.integer = ch1->c[i].value.integer;\n\t\t} //end else if\n\t\telse if (ch1->c[i].type == CT_STRING)\n\t\t{\n\t\t\tout->c[i].type = CT_STRING;\n\t\t\tout->c[i].value.string = (char *) GetMemory((int)strlen(ch1->c[i].value.string)+1);\n\t\t\tstrcpy(out->c[i].value.string, ch1->c[i].value.string);\n\t\t} //end else if\n\t} //end for\n\treturn handle;\n} //end of the function BotInterpolateCharacters\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotLoadCharacter(char *charfile, float skill)\n{\n\tint firstskill, secondskill, handle;\n\n\t//make sure the skill is in the valid range\n\tif (skill < 1.0) skill = 1.0;\n\telse if (skill > 5.0) skill = 5.0;\n\t//skill 1, 4 and 5 should be available in the character files\n\tif (skill == 1.0 || skill == 4.0 || skill == 5.0)\n\t{\n\t\treturn BotLoadCharacterSkill(charfile, skill);\n\t} //end if\n\t//check if there's a cached skill\n\thandle = BotFindCachedCharacter(charfile, skill);\n\tif (handle)\n\t{\n\t\tbotimport.Print(PRT_MESSAGE, \"loaded cached skill %f from %s\\n\", skill, charfile);\n\t\treturn handle;\n\t} //end if\n\tif (skill < 4.0)\n\t{\n\t\t//load skill 1 and 4\n\t\tfirstskill = BotLoadCharacterSkill(charfile, 1);\n\t\tif (!firstskill) return 0;\n\t\tsecondskill = BotLoadCharacterSkill(charfile, 4);\n\t\tif (!secondskill) return firstskill;\n\t} //end if\n\telse\n\t{\n\t\t//load skill 4 and 5\n\t\tfirstskill = BotLoadCharacterSkill(charfile, 4);\n\t\tif (!firstskill) return 0;\n\t\tsecondskill = BotLoadCharacterSkill(charfile, 5);\n\t\tif (!secondskill) return firstskill;\n\t} //end else\n\t//interpolate between the two skills\n\thandle = BotInterpolateCharacters(firstskill, secondskill, skill);\n\tif (!handle) return 0;\n\t//write the character to the log file\n\tBotDumpCharacter(botcharacters[handle]);\n\t//\n\treturn handle;\n} //end of the function BotLoadCharacter\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint CheckCharacteristicIndex(int character, int index)\n{\n\tbot_character_t *ch;\n\n\tch = BotCharacterFromHandle(character);\n\tif (!ch) return qfalse;\n\tif (index < 0 || index >= MAX_CHARACTERISTICS)\n\t{\n\t\tbotimport.Print(PRT_ERROR, \"characteristic %d does not exist\\n\", index);\n\t\treturn qfalse;\n\t} //end if\n\tif (!ch->c[index].type)\n\t{\n\t\tbotimport.Print(PRT_ERROR, \"characteristic %d is not initialized\\n\", index);\n\t\treturn qfalse;\n\t} //end if\n\treturn qtrue;\n} //end of the function CheckCharacteristicIndex\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nfloat Characteristic_Float(int character, int index)\n{\n\tbot_character_t *ch;\n\n\tch = BotCharacterFromHandle(character);\n\tif (!ch) return 0;\n\t//check if the index is in range\n\tif (!CheckCharacteristicIndex(character, index)) return 0;\n\t//an integer will be converted to a float\n\tif (ch->c[index].type == CT_INTEGER)\n\t{\n\t\treturn (float) ch->c[index].value.integer;\n\t} //end if\n\t//floats are just returned\n\telse if (ch->c[index].type == CT_FLOAT)\n\t{\n\t\treturn ch->c[index].value._float;\n\t} //end else if\n\t//cannot convert a string pointer to a float\n\telse\n\t{\n\t\tbotimport.Print(PRT_ERROR, \"characteristic %d is not a float\\n\", index);\n\t\treturn 0;\n\t} //end else if\n//\treturn 0;\n} //end of the function Characteristic_Float\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nfloat Characteristic_BFloat(int character, int index, float min, float max)\n{\n\tfloat value;\n\tbot_character_t *ch;\n\n\tch = BotCharacterFromHandle(character);\n\tif (!ch) return 0;\n\tif (min > max)\n\t{\n\t\tbotimport.Print(PRT_ERROR, \"cannot bound characteristic %d between %f and %f\\n\", index, min, max);\n\t\treturn 0;\n\t} //end if\n\tvalue = Characteristic_Float(character, index);\n\tif (value < min) return min;\n\tif (value > max) return max;\n\treturn value;\n} //end of the function Characteristic_BFloat\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint Characteristic_Integer(int character, int index)\n{\n\tbot_character_t *ch;\n\n\tch = BotCharacterFromHandle(character);\n\tif (!ch) return 0;\n\t//check if the index is in range\n\tif (!CheckCharacteristicIndex(character, index)) return 0;\n\t//an integer will just be returned\n\tif (ch->c[index].type == CT_INTEGER)\n\t{\n\t\treturn ch->c[index].value.integer;\n\t} //end if\n\t//floats are casted to integers\n\telse if (ch->c[index].type == CT_FLOAT)\n\t{\n\t\treturn (int) ch->c[index].value._float;\n\t} //end else if\n\telse\n\t{\n\t\tbotimport.Print(PRT_ERROR, \"characteristic %d is not a integer\\n\", index);\n\t\treturn 0;\n\t} //end else if\n//\treturn 0;\n} //end of the function Characteristic_Integer\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint Characteristic_BInteger(int character, int index, int min, int max)\n{\n\tint value;\n\tbot_character_t *ch;\n\n\tch = BotCharacterFromHandle(character);\n\tif (!ch) return 0;\n\tif (min > max)\n\t{\n\t\tbotimport.Print(PRT_ERROR, \"cannot bound characteristic %d between %d and %d\\n\", index, min, max);\n\t\treturn 0;\n\t} //end if\n\tvalue = Characteristic_Integer(character, index);\n\tif (value < min) return min;\n\tif (value > max) return max;\n\treturn value;\n} //end of the function Characteristic_BInteger\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid Characteristic_String(int character, int index, char *buf, int size)\n{\n\tbot_character_t *ch;\n\n\tch = BotCharacterFromHandle(character);\n\tif (!ch) return;\n\t//check if the index is in range\n\tif (!CheckCharacteristicIndex(character, index)) return;\n\t//an integer will be converted to a float\n\tif (ch->c[index].type == CT_STRING)\n\t{\n\t\tstrncpy(buf, ch->c[index].value.string, size-1);\n\t\tbuf[size-1] = '\\0';\n\t\treturn;\n\t} //end if\n\telse\n\t{\n\t\tbotimport.Print(PRT_ERROR, \"characteristic %d is not a string\\n\", index);\n\t\treturn;\n\t} //end else if\n\treturn;\n} //end of the function Characteristic_String\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotShutdownCharacters(void)\n{\n\tint handle;\n\n\tfor (handle = 1; handle <= MAX_CLIENTS; handle++)\n\t{\n\t\tif (botcharacters[handle])\n\t\t{\n\t\t\tBotFreeCharacter2(handle);\n\t\t} //end if\n\t} //end for\n} //end of the function BotShutdownCharacters\n\n"
  },
  {
    "path": "src/engine/botlib/be_ai_chat.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tbe_ai_chat.c\n *\n * desc:\t\tbot chat AI\n *\n * $Archive: /MissionPack/code/botlib/be_ai_chat.c $\n *\n *****************************************************************************/\n\n#include \"../../game/q_shared.h\"\n#include \"l_memory.h\"\n#include \"l_libvar.h\"\n#include \"l_script.h\"\n#include \"l_precomp.h\"\n#include \"l_struct.h\"\n#include \"l_utils.h\"\n#include \"l_log.h\"\n#include \"aasfile.h\"\n#include \"../../game/botlib.h\"\n#include \"../../game/be_aas.h\"\n#include \"be_aas_funcs.h\"\n#include \"be_interface.h\"\n#include \"../../game/be_ea.h\"\n#include \"../../game/be_ai_chat.h\"\n\n\n//escape character\n#define ESCAPE_CHAR\t\t\t\t0x01\t//'_'\n//\n// \"hi \", people, \" \", 0, \" entered the game\"\n//becomes:\n// \"hi _rpeople_ _v0_ entered the game\"\n//\n\n//match piece types\n#define MT_VARIABLE\t\t\t\t\t1\t\t//variable match piece\n#define MT_STRING\t\t\t\t\t2\t\t//string match piece\n//reply chat key flags\n#define RCKFL_AND\t\t\t\t\t1\t\t//key must be present\n#define RCKFL_NOT\t\t\t\t\t2\t\t//key must be absent\n#define RCKFL_NAME\t\t\t\t\t4\t\t//name of bot must be present\n#define RCKFL_STRING\t\t\t\t8\t\t//key is a string\n#define RCKFL_VARIABLES\t\t\t\t16\t\t//key is a match template\n#define RCKFL_BOTNAMES\t\t\t\t32\t\t//key is a series of botnames\n#define RCKFL_GENDERFEMALE\t\t\t64\t\t//bot must be female\n#define RCKFL_GENDERMALE\t\t\t128\t\t//bot must be male\n#define RCKFL_GENDERLESS\t\t\t256\t\t//bot must be genderless\n//time to ignore a chat message after using it\n#define CHATMESSAGE_RECENTTIME\t20\n\n//the actuall chat messages\ntypedef struct bot_chatmessage_s\n{\n\tchar *chatmessage;\t\t\t\t\t//chat message string\n\tfloat time;\t\t\t\t\t\t\t//last time used\n\tstruct bot_chatmessage_s *next;\t\t//next chat message in a list\n} bot_chatmessage_t;\n//bot chat type with chat lines\ntypedef struct bot_chattype_s\n{\n\tchar name[MAX_CHATTYPE_NAME];\n\tint numchatmessages;\n\tbot_chatmessage_t *firstchatmessage;\n\tstruct bot_chattype_s *next;\n} bot_chattype_t;\n//bot chat lines\ntypedef struct bot_chat_s\n{\n\tbot_chattype_t *types;\n} bot_chat_t;\n\n//random string\ntypedef struct bot_randomstring_s\n{\n\tchar *string;\n\tstruct bot_randomstring_s *next;\n} bot_randomstring_t;\n//list with random strings\ntypedef struct bot_randomlist_s\n{\n\tchar *string;\n\tint numstrings;\n\tbot_randomstring_t *firstrandomstring;\n\tstruct bot_randomlist_s *next;\n} bot_randomlist_t;\n\n//synonym\ntypedef struct bot_synonym_s\n{\n\tchar *string;\n\tfloat weight;\n\tstruct bot_synonym_s *next;\n} bot_synonym_t;\n//list with synonyms\ntypedef struct bot_synonymlist_s\n{\n\tunsigned long int context;\n\tfloat totalweight;\n\tbot_synonym_t *firstsynonym;\n\tstruct bot_synonymlist_s *next;\n} bot_synonymlist_t;\n\n//fixed match string\ntypedef struct bot_matchstring_s\n{\n\tchar *string;\n\tstruct bot_matchstring_s *next;\n} bot_matchstring_t;\n\n//piece of a match template\ntypedef struct bot_matchpiece_s\n{\n\tint type;\n\tbot_matchstring_t *firststring;\n\tint variable;\n\tstruct bot_matchpiece_s *next;\n} bot_matchpiece_t;\n//match template\ntypedef struct bot_matchtemplate_s\n{\n\tunsigned long int context;\n\tint type;\n\tint subtype;\n\tbot_matchpiece_t *first;\n\tstruct bot_matchtemplate_s *next;\n} bot_matchtemplate_t;\n\n//reply chat key\ntypedef struct bot_replychatkey_s\n{\n\tint flags;\n\tchar *string;\n\tbot_matchpiece_t *match;\n\tstruct bot_replychatkey_s *next;\n} bot_replychatkey_t;\n//reply chat\ntypedef struct bot_replychat_s\n{\n\tbot_replychatkey_t *keys;\n\tfloat priority;\n\tint numchatmessages;\n\tbot_chatmessage_t *firstchatmessage;\n\tstruct bot_replychat_s *next;\n} bot_replychat_t;\n\n//string list\ntypedef struct bot_stringlist_s\n{\n\tchar *string;\n\tstruct bot_stringlist_s *next;\n} bot_stringlist_t;\n\n//chat state of a bot\ntypedef struct bot_chatstate_s\n{\n\tint gender;\t\t\t\t\t\t\t\t\t\t\t//0=it, 1=female, 2=male\n\tint client;\t\t\t\t\t\t\t\t\t\t\t//client number\n\tchar name[32];\t\t\t\t\t\t\t\t\t\t//name of the bot\n\tchar chatmessage[MAX_MESSAGE_SIZE];\n\tint handle;\n\t//the console messages visible to the bot\n\tbot_consolemessage_t *firstmessage;\t\t\t//first message is the first typed message\n\tbot_consolemessage_t *lastmessage;\t\t\t//last message is the last typed message, bottom of console\n\t//number of console messages stored in the state\n\tint numconsolemessages;\n\t//the bot chat lines\n\tbot_chat_t *chat;\n} bot_chatstate_t;\n\ntypedef struct {\n\tbot_chat_t\t*chat;\n\tchar\t\tfilename[MAX_QPATH];\n\tchar\t\tchatname[MAX_QPATH];\n} bot_ichatdata_t;\n\nbot_ichatdata_t\t*ichatdata[MAX_CLIENTS];\n\nbot_chatstate_t *botchatstates[MAX_CLIENTS+1];\n//console message heap\nbot_consolemessage_t *consolemessageheap = NULL;\nbot_consolemessage_t *freeconsolemessages = NULL;\n//list with match strings\nbot_matchtemplate_t *matchtemplates = NULL;\n//list with synonyms\nbot_synonymlist_t *synonyms = NULL;\n//list with random strings\nbot_randomlist_t *randomstrings = NULL;\n//reply chats\nbot_replychat_t *replychats = NULL;\n\n//========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//========================================================================\nbot_chatstate_t *BotChatStateFromHandle(int handle)\n{\n\tif (handle <= 0 || handle > MAX_CLIENTS)\n\t{\n\t\tbotimport.Print(PRT_FATAL, \"chat state handle %d out of range\\n\", handle);\n\t\treturn NULL;\n\t} //end if\n\tif (!botchatstates[handle])\n\t{\n\t\tbotimport.Print(PRT_FATAL, \"invalid chat state %d\\n\", handle);\n\t\treturn NULL;\n\t} //end if\n\treturn botchatstates[handle];\n} //end of the function BotChatStateFromHandle\n//===========================================================================\n// initialize the heap with unused console messages\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid InitConsoleMessageHeap(void)\n{\n\tint i, max_messages;\n\n\tif (consolemessageheap) FreeMemory(consolemessageheap);\n\t//\n\tmax_messages = (int) LibVarValue(\"max_messages\", \"1024\");\n\tconsolemessageheap = (bot_consolemessage_t *) GetClearedHunkMemory(max_messages *\n\t\t\t\t\t\t\t\t\t\t\t\tsizeof(bot_consolemessage_t));\n\tconsolemessageheap[0].prev = NULL;\n\tconsolemessageheap[0].next = &consolemessageheap[1];\n\tfor (i = 1; i < max_messages-1; i++)\n\t{\n\t\tconsolemessageheap[i].prev = &consolemessageheap[i - 1];\n\t\tconsolemessageheap[i].next = &consolemessageheap[i + 1];\n\t} //end for\n\tconsolemessageheap[max_messages-1].prev = &consolemessageheap[max_messages-2];\n\tconsolemessageheap[max_messages-1].next = NULL;\n\t//pointer to the free console messages\n\tfreeconsolemessages = consolemessageheap;\n} //end of the function InitConsoleMessageHeap\n//===========================================================================\n// allocate one console message from the heap\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nbot_consolemessage_t *AllocConsoleMessage(void)\n{\n\tbot_consolemessage_t *message;\n\tmessage = freeconsolemessages;\n\tif (freeconsolemessages) freeconsolemessages = freeconsolemessages->next;\n\tif (freeconsolemessages) freeconsolemessages->prev = NULL;\n\treturn message;\n} //end of the function AllocConsoleMessage\n//===========================================================================\n// deallocate one console message from the heap\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid FreeConsoleMessage(bot_consolemessage_t *message)\n{\n\tif (freeconsolemessages) freeconsolemessages->prev = message;\n\tmessage->prev = NULL;\n\tmessage->next = freeconsolemessages;\n\tfreeconsolemessages = message;\n} //end of the function FreeConsoleMessage\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotRemoveConsoleMessage(int chatstate, int handle)\n{\n\tbot_consolemessage_t *m, *nextm;\n\tbot_chatstate_t *cs;\n\n\tcs = BotChatStateFromHandle(chatstate);\n\tif (!cs) return;\n\n\tfor (m = cs->firstmessage; m; m = nextm)\n\t{\n\t\tnextm = m->next;\n\t\tif (m->handle == handle)\n\t\t{\n\t\t\tif (m->next) m->next->prev = m->prev;\n\t\t\telse cs->lastmessage = m->prev;\n\t\t\tif (m->prev) m->prev->next = m->next;\n\t\t\telse cs->firstmessage = m->next;\n\n\t\t\tFreeConsoleMessage(m);\n\t\t\tcs->numconsolemessages--;\n\t\t\tbreak;\n\t\t} //end if\n\t} //end for\n} //end of the function BotRemoveConsoleMessage\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotQueueConsoleMessage(int chatstate, int type, char *message)\n{\n\tbot_consolemessage_t *m;\n\tbot_chatstate_t *cs;\n\n\tcs = BotChatStateFromHandle(chatstate);\n\tif (!cs) return;\n\n\tm = AllocConsoleMessage();\n\tif (!m)\n\t{\n\t\tbotimport.Print(PRT_ERROR, \"empty console message heap\\n\");\n\t\treturn;\n\t} //end if\n\tcs->handle++;\n\tif (cs->handle <= 0 || cs->handle > 8192) cs->handle = 1;\n\tm->handle = cs->handle;\n\tm->time = AAS_Time();\n\tm->type = type;\n\tstrncpy(m->message, message, MAX_MESSAGE_SIZE);\n\tm->next = NULL;\n\tif (cs->lastmessage)\n\t{\n\t\tcs->lastmessage->next = m;\n\t\tm->prev = cs->lastmessage;\n\t\tcs->lastmessage = m;\n\t} //end if\n\telse\n\t{\n\t\tcs->lastmessage = m;\n\t\tcs->firstmessage = m;\n\t\tm->prev = NULL;\n\t} //end if\n\tcs->numconsolemessages++;\n} //end of the function BotQueueConsoleMessage\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotNextConsoleMessage(int chatstate, bot_consolemessage_t *cm)\n{\n\tbot_chatstate_t *cs;\n\n\tcs = BotChatStateFromHandle(chatstate);\n\tif (!cs) return 0;\n\tif (cs->firstmessage)\n\t{\n\t\tCom_Memcpy(cm, cs->firstmessage, sizeof(bot_consolemessage_t));\n\t\tcm->next = cm->prev = NULL;\n\t\treturn cm->handle;\n\t} //end if\n\treturn 0;\n} //end of the function BotConsoleMessage\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotNumConsoleMessages(int chatstate)\n{\n\tbot_chatstate_t *cs;\n\n\tcs = BotChatStateFromHandle(chatstate);\n\tif (!cs) return 0;\n\treturn cs->numconsolemessages;\n} //end of the function BotNumConsoleMessages\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint IsWhiteSpace(char c)\n{\n\tif ((c >= 'a' && c <= 'z')\n\t\t|| (c >= 'A' && c <= 'Z')\n\t\t|| (c >= '0' && c <= '9')\n\t\t|| c == '(' || c == ')'\n\t\t|| c == '?' || c == ':'\n\t\t|| c == '\\''|| c == '/'\n\t\t|| c == ',' || c == '.'\n\t\t|| c == '['\t|| c == ']'\n\t\t|| c == '-' || c == '_'\n\t\t|| c == '+' || c == '=') return qfalse;\n\treturn qtrue;\n} //end of the function IsWhiteSpace\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotRemoveTildes(char *message)\n{\n\tint i;\n\n\t//remove all tildes from the chat message\n\tfor (i = 0; message[i]; i++)\n\t{\n\t\tif (message[i] == '~')\n\t\t{\n\t\t\tmemmove(&message[i], &message[i+1], (int)strlen(&message[i+1])+1);\n\t\t} //end if\n\t} //end for\n} //end of the function BotRemoveTildes\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid UnifyWhiteSpaces(char *string)\n{\n\tchar *ptr, *oldptr;\n\n\tfor (ptr = oldptr = string; *ptr; oldptr = ptr)\n\t{\n\t\twhile(*ptr && IsWhiteSpace(*ptr)) ptr++;\n\t\tif (ptr > oldptr)\n\t\t{\n\t\t\t//if not at the start and not at the end of the string\n\t\t\t//write only one space\n\t\t\tif (oldptr > string && *ptr) *oldptr++ = ' ';\n\t\t\t//remove all other white spaces\n\t\t\tif (ptr > oldptr) memmove(oldptr, ptr, (int)strlen(ptr)+1);\n\t\t} //end if\n\t\twhile(*ptr && !IsWhiteSpace(*ptr)) ptr++;\n\t} //end while\n} //end of the function UnifyWhiteSpaces\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint StringContains(char *str1, char *str2, int casesensitive)\n{\n\tint len, i, j, index;\n\n\tif (str1 == NULL || str2 == NULL) return -1;\n\n\tlen = (int)strlen(str1) - (int)strlen(str2);\n\tindex = 0;\n\tfor (i = 0; i <= len; i++, str1++, index++)\n\t{\n\t\tfor (j = 0; str2[j]; j++)\n\t\t{\n\t\t\tif (casesensitive)\n\t\t\t{\n\t\t\t\tif (str1[j] != str2[j]) break;\n\t\t\t} //end if\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (toupper(str1[j]) != toupper(str2[j])) break;\n\t\t\t} //end else\n\t\t} //end for\n\t\tif (!str2[j]) return index;\n\t} //end for\n\treturn -1;\n} //end of the function StringContains\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nchar *StringContainsWord(char *str1, char *str2, int casesensitive)\n{\n\tint len, i, j;\n\n\tlen = (int)strlen(str1) - (int)strlen(str2);\n\tfor (i = 0; i <= len; i++, str1++)\n\t{\n\t\t//if not at the start of the string\n\t\tif (i)\n\t\t{\n\t\t\t//skip to the start of the next word\n\t\t\twhile(*str1 && *str1 != ' ' && *str1 != '.' && *str1 != ',' && *str1 != '!') str1++;\n\t\t\tif (!*str1) break;\n\t\t\tstr1++;\n\t\t} //end for\n\t\t//compare the word\n\t\tfor (j = 0; str2[j]; j++)\n\t\t{\n\t\t\tif (casesensitive)\n\t\t\t{\n\t\t\t\tif (str1[j] != str2[j]) break;\n\t\t\t} //end if\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (toupper(str1[j]) != toupper(str2[j])) break;\n\t\t\t} //end else\n\t\t} //end for\n\t\t//if there was a word match\n\t\tif (!str2[j])\n\t\t{\n\t\t\t//if the first string has an end of word\n\t\t\tif (!str1[j] || str1[j] == ' ' || str1[j] == '.' || str1[j] == ',' || str1[j] == '!') return str1;\n\t\t} //end if\n\t} //end for\n\treturn NULL;\n} //end of the function StringContainsWord\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid StringReplaceWords(char *string, char *synonym, char *replacement)\n{\n\tchar *str, *str2;\n\n\t//find the synonym in the string\n\tstr = StringContainsWord(string, synonym, qfalse);\n\t//if the synonym occured in the string\n\twhile(str)\n\t{\n\t\t//if the synonym isn't part of the replacement which is already in the string\n\t\t//usefull for abreviations\n\t\tstr2 = StringContainsWord(string, replacement, qfalse);\n\t\twhile(str2)\n\t\t{\n\t\t\tif (str2 <= str && str < str2 + (int)strlen(replacement)) break;\n\t\t\tstr2 = StringContainsWord(str2+1, replacement, qfalse);\n\t\t} //end while\n\t\tif (!str2)\n\t\t{\n\t\t\tmemmove(str + (int)strlen(replacement), str+(int)strlen(synonym), (int)strlen(str+(int)strlen(synonym))+1);\n\t\t\t//append the synonum replacement\n\t\t\tCom_Memcpy(str, replacement, (int)strlen(replacement));\n\t\t} //end if\n\t\t//find the next synonym in the string\n\t\tstr = StringContainsWord(str+(int)strlen(replacement), synonym, qfalse);\n\t} //end if\n} //end of the function StringReplaceWords\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotDumpSynonymList(bot_synonymlist_t *synlist)\n{\n\tFILE *fp;\n\tbot_synonymlist_t *syn;\n\tbot_synonym_t *synonym;\n\n\tfp = Log_FilePointer();\n\tif (!fp) return;\n\tfor (syn = synlist; syn; syn = syn->next)\n\t{\n\t        fprintf(fp, \"%ld : [\", syn->context);\n\t\tfor (synonym = syn->firstsynonym; synonym; synonym = synonym->next)\n\t\t{\n\t\t\tfprintf(fp, \"(\\\"%s\\\", %1.2f)\", synonym->string, synonym->weight);\n\t\t\tif (synonym->next) fprintf(fp, \", \");\n\t\t} //end for\n\t\tfprintf(fp, \"]\\n\");\n\t} //end for\n} //end of the function BotDumpSynonymList\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nbot_synonymlist_t *BotLoadSynonyms(char *filename)\n{\n\tint pass, size, contextlevel, numsynonyms;\n\tunsigned long int context, contextstack[32];\n\tchar *ptr = NULL;\n\tsource_t *source;\n\ttoken_t token;\n\tbot_synonymlist_t *synlist, *lastsyn, *syn;\n\tbot_synonym_t *synonym, *lastsynonym;\n\n\tsize = 0;\n\tsynlist = NULL; //make compiler happy\n\tsyn = NULL; //make compiler happy\n\tsynonym = NULL; //make compiler happy\n\t//the synonyms are parsed in two phases\n\tfor (pass = 0; pass < 2; pass++)\n\t{\n\t\t//\n\t\tif (pass && size) ptr = (char *) GetClearedHunkMemory(size);\n\t\t//\n\t\tPC_SetBaseFolder(BOTFILESBASEFOLDER);\n\t\tsource = LoadSourceFile(filename);\n\t\tif (!source)\n\t\t{\n\t\t\tbotimport.Print(PRT_ERROR, \"counldn't load %s\\n\", filename);\n\t\t\treturn NULL;\n\t\t} //end if\n\t\t//\n\t\tcontext = 0;\n\t\tcontextlevel = 0;\n\t\tsynlist = NULL; //list synonyms\n\t\tlastsyn = NULL; //last synonym in the list\n\t\t//\n\t\twhile(PC_ReadToken(source, &token))\n\t\t{\n\t\t\tif (token.type == TT_NUMBER)\n\t\t\t{\n\t\t\t\tcontext |= token.intvalue;\n\t\t\t\tcontextstack[contextlevel] = token.intvalue;\n\t\t\t\tcontextlevel++;\n\t\t\t\tif (contextlevel >= 32)\n\t\t\t\t{\n\t\t\t\t\tSourceError(source, \"more than 32 context levels\");\n\t\t\t\t\tFreeSource(source);\n\t\t\t\t\treturn NULL;\n\t\t\t\t} //end if\n\t\t\t\tif (!PC_ExpectTokenString(source, \"{\"))\n\t\t\t\t{\n\t\t\t\t\tFreeSource(source);\n\t\t\t\t\treturn NULL;\n\t\t\t\t} //end if\n\t\t\t} //end if\n\t\t\telse if (token.type == TT_PUNCTUATION)\n\t\t\t{\n\t\t\t\tif (!strcmp(token.string, \"}\"))\n\t\t\t\t{\n\t\t\t\t\tcontextlevel--;\n\t\t\t\t\tif (contextlevel < 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tSourceError(source, \"too many }\");\n\t\t\t\t\t\tFreeSource(source);\n\t\t\t\t\t\treturn NULL;\n\t\t\t\t\t} //end if\n\t\t\t\t\tcontext &= ~contextstack[contextlevel];\n\t\t\t\t} //end if\n\t\t\t\telse if (!strcmp(token.string, \"[\"))\n\t\t\t\t{\n\t\t\t\t\tsize += sizeof(bot_synonymlist_t);\n\t\t\t\t\tif (pass)\n\t\t\t\t\t{\n\t\t\t\t\t\tsyn = (bot_synonymlist_t *) ptr;\n\t\t\t\t\t\tptr += sizeof(bot_synonymlist_t);\n\t\t\t\t\t\tsyn->context = context;\n\t\t\t\t\t\tsyn->firstsynonym = NULL;\n\t\t\t\t\t\tsyn->next = NULL;\n\t\t\t\t\t\tif (lastsyn) lastsyn->next = syn;\n\t\t\t\t\t\telse synlist = syn;\n\t\t\t\t\t\tlastsyn = syn;\n\t\t\t\t\t} //end if\n\t\t\t\t\tnumsynonyms = 0;\n\t\t\t\t\tlastsynonym = NULL;\n\t\t\t\t\twhile(1)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (!PC_ExpectTokenString(source, \"(\") ||\n\t\t\t\t\t\t\t!PC_ExpectTokenType(source, TT_STRING, 0, &token))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tFreeSource(source);\n\t\t\t\t\t\t\treturn NULL;\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t\tStripDoubleQuotes(token.string);\n\t\t\t\t\t\tif ((int)strlen(token.string) <= 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tSourceError(source, \"empty string\", token.string);\n\t\t\t\t\t\t\tFreeSource(source);\n\t\t\t\t\t\t\treturn NULL;\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t\tsize += sizeof(bot_synonym_t) + (int)strlen(token.string) + 1;\n\t\t\t\t\t\tif (pass)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsynonym = (bot_synonym_t *) ptr;\n\t\t\t\t\t\t\tptr += sizeof(bot_synonym_t);\n\t\t\t\t\t\t\tsynonym->string = ptr;\n\t\t\t\t\t\t\tptr += (int)strlen(token.string) + 1;\n\t\t\t\t\t\t\tstrcpy(synonym->string, token.string);\n\t\t\t\t\t\t\t//\n\t\t\t\t\t\t\tif (lastsynonym) lastsynonym->next = synonym;\n\t\t\t\t\t\t\telse syn->firstsynonym = synonym;\n\t\t\t\t\t\t\tlastsynonym = synonym;\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t\tnumsynonyms++;\n\t\t\t\t\t\tif (!PC_ExpectTokenString(source, \",\") ||\n\t\t\t\t\t\t\t!PC_ExpectTokenType(source, TT_NUMBER, 0, &token) ||\n\t\t\t\t\t\t\t!PC_ExpectTokenString(source, \")\"))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tFreeSource(source);\n\t\t\t\t\t\t\treturn NULL;\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t\tif (pass)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsynonym->weight = token.floatvalue;\n\t\t\t\t\t\t\tsyn->totalweight += synonym->weight;\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t\tif (PC_CheckTokenString(source, \"]\")) break;\n\t\t\t\t\t\tif (!PC_ExpectTokenString(source, \",\"))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tFreeSource(source);\n\t\t\t\t\t\t\treturn NULL;\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t} //end while\n\t\t\t\t\tif (numsynonyms < 2)\n\t\t\t\t\t{\n\t\t\t\t\t\tSourceError(source, \"synonym must have at least two entries\\n\");\n\t\t\t\t\t\tFreeSource(source);\n\t\t\t\t\t\treturn NULL;\n\t\t\t\t\t} //end if\n\t\t\t\t} //end else\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tSourceError(source, \"unexpected %s\", token.string);\n\t\t\t\t\tFreeSource(source);\n\t\t\t\t\treturn NULL;\n\t\t\t\t} //end if\n\t\t\t} //end else if\n\t\t} //end while\n\t\t//\n\t\tFreeSource(source);\n\t\t//\n\t\tif (contextlevel > 0)\n\t\t{\n\t\t\tSourceError(source, \"missing }\");\n\t\t\treturn NULL;\n\t\t} //end if\n\t} //end for\n\tbotimport.Print(PRT_MESSAGE, \"loaded %s\\n\", filename);\n\t//\n\t//BotDumpSynonymList(synlist);\n\t//\n\treturn synlist;\n} //end of the function BotLoadSynonyms\n//===========================================================================\n// replace all the synonyms in the string\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotReplaceSynonyms(char *string, unsigned long int context)\n{\n\tbot_synonymlist_t *syn;\n\tbot_synonym_t *synonym;\n\n\tfor (syn = synonyms; syn; syn = syn->next)\n\t{\n\t\tif (!(syn->context & context)) continue;\n\t\tfor (synonym = syn->firstsynonym->next; synonym; synonym = synonym->next)\n\t\t{\n\t\t\tStringReplaceWords(string, synonym->string, syn->firstsynonym->string);\n\t\t} //end for\n\t} //end for\n} //end of the function BotReplaceSynonyms\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotReplaceWeightedSynonyms(char *string, unsigned long int context)\n{\n\tbot_synonymlist_t *syn;\n\tbot_synonym_t *synonym, *replacement;\n\tfloat weight, curweight;\n\n\tfor (syn = synonyms; syn; syn = syn->next)\n\t{\n\t\tif (!(syn->context & context)) continue;\n\t\t//choose a weighted random replacement synonym\n\t\tweight = random() * syn->totalweight;\n\t\tif (!weight) continue;\n\t\tcurweight = 0;\n\t\tfor (replacement = syn->firstsynonym; replacement; replacement = replacement->next)\n\t\t{\n\t\t\tcurweight += replacement->weight;\n\t\t\tif (weight < curweight) break;\n\t\t} //end for\n\t\tif (!replacement) continue;\n\t\t//replace all synonyms with the replacement\n\t\tfor (synonym = syn->firstsynonym; synonym; synonym = synonym->next)\n\t\t{\n\t\t\tif (synonym == replacement) continue;\n\t\t\tStringReplaceWords(string, synonym->string, replacement->string);\n\t\t} //end for\n\t} //end for\n} //end of the function BotReplaceWeightedSynonyms\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotReplaceReplySynonyms(char *string, unsigned long int context)\n{\n\tchar *str1, *str2, *replacement;\n\tbot_synonymlist_t *syn;\n\tbot_synonym_t *synonym;\n\n\tfor (str1 = string; *str1; )\n\t{\n\t\t//go to the start of the next word\n\t\twhile(*str1 && *str1 <= ' ') str1++;\n\t\tif (!*str1) break;\n\t\t//\n\t\tfor (syn = synonyms; syn; syn = syn->next)\n\t\t{\n\t\t\tif (!(syn->context & context)) continue;\n\t\t\tfor (synonym = syn->firstsynonym->next; synonym; synonym = synonym->next)\n\t\t\t{\n\t\t\t\tstr2 = synonym->string;\n\t\t\t\t//if the synonym is not at the front of the string continue\n\t\t\t\tstr2 = StringContainsWord(str1, synonym->string, qfalse);\n\t\t\t\tif (!str2 || str2 != str1) continue;\n\t\t\t\t//\n\t\t\t\treplacement = syn->firstsynonym->string;\n\t\t\t\t//if the replacement IS in front of the string continue\n\t\t\t\tstr2 = StringContainsWord(str1, replacement, qfalse);\n\t\t\t\tif (str2 && str2 == str1) continue;\n\t\t\t\t//\n\t\t\t\tmemmove(str1 + (int)strlen(replacement), str1+(int)strlen(synonym->string),\n\t\t\t\t\t\t\t(int)strlen(str1+(int)strlen(synonym->string)) + 1);\n\t\t\t\t//append the synonum replacement\n\t\t\t\tCom_Memcpy(str1, replacement, (int)strlen(replacement));\n\t\t\t\t//\n\t\t\t\tbreak;\n\t\t\t} //end for\n\t\t\t//if a synonym has been replaced\n\t\t\tif (synonym) break;\n\t\t} //end for\n\t\t//skip over this word\n\t\twhile(*str1 && *str1 > ' ') str1++;\n\t\tif (!*str1) break;\n\t} //end while\n} //end of the function BotReplaceReplySynonyms\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotLoadChatMessage(source_t *source, char *chatmessagestring)\n{\n\tchar *ptr;\n\ttoken_t token;\n\n\tptr = chatmessagestring;\n\t*ptr = 0;\n\t//\n\twhile(1)\n\t{\n\t\tif (!PC_ExpectAnyToken(source, &token)) return qfalse;\n\t\t//fixed string\n\t\tif (token.type == TT_STRING)\n\t\t{\n\t\t\tStripDoubleQuotes(token.string);\n\t\t\tif ((int)strlen(ptr) + (int)strlen(token.string) + 1 > MAX_MESSAGE_SIZE)\n\t\t\t{\n\t\t\t\tSourceError(source, \"chat message too long\\n\");\n\t\t\t\treturn qfalse;\n\t\t\t} //end if\n\t\t\tstrcat(ptr, token.string);\n\t\t} //end else if\n\t\t//variable string\n\t\telse if (token.type == TT_NUMBER && (token.subtype & TT_INTEGER))\n\t\t{\n\t\t\tif ((int)strlen(ptr) + 7 > MAX_MESSAGE_SIZE)\n\t\t\t{\n\t\t\t\tSourceError(source, \"chat message too long\\n\");\n\t\t\t\treturn qfalse;\n\t\t\t} //end if\n\t\t\tsprintf(&ptr[(int)strlen(ptr)], \"%cv%ld%c\", ESCAPE_CHAR, token.intvalue, ESCAPE_CHAR);\n\t\t} //end if\n\t\t//random string\n\t\telse if (token.type == TT_NAME)\n\t\t{\n\t\t\tif ((int)strlen(ptr) + 7 > MAX_MESSAGE_SIZE)\n\t\t\t{\n\t\t\t\tSourceError(source, \"chat message too long\\n\");\n\t\t\t\treturn qfalse;\n\t\t\t} //end if\n\t\t\tsprintf(&ptr[(int)strlen(ptr)], \"%cr%s%c\", ESCAPE_CHAR, token.string, ESCAPE_CHAR);\n\t\t} //end else if\n\t\telse\n\t\t{\n\t\t\tSourceError(source, \"unknown message component %s\\n\", token.string);\n\t\t\treturn qfalse;\n\t\t} //end else\n\t\tif (PC_CheckTokenString(source, \";\")) break;\n\t\tif (!PC_ExpectTokenString(source, \",\")) return qfalse;\n\t} //end while\n\t//\n\treturn qtrue;\n} //end of the function BotLoadChatMessage\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotDumpRandomStringList(bot_randomlist_t *randomlist)\n{\n\tFILE *fp;\n\tbot_randomlist_t *random;\n\tbot_randomstring_t *rs;\n\n\tfp = Log_FilePointer();\n\tif (!fp) return;\n\tfor (random = randomlist; random; random = random->next)\n\t{\n\t\tfprintf(fp, \"%s = {\", random->string);\n\t\tfor (rs = random->firstrandomstring; rs; rs = rs->next)\n\t\t{\n\t\t\tfprintf(fp, \"\\\"%s\\\"\", rs->string);\n\t\t\tif (rs->next) fprintf(fp, \", \");\n\t\t\telse fprintf(fp, \"}\\n\");\n\t\t} //end for\n\t} //end for\n} //end of the function BotDumpRandomStringList\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nbot_randomlist_t *BotLoadRandomStrings(char *filename)\n{\n\tint pass, size;\n\tchar *ptr = NULL, chatmessagestring[MAX_MESSAGE_SIZE];\n\tsource_t *source;\n\ttoken_t token;\n\tbot_randomlist_t *randomlist, *lastrandom, *random;\n\tbot_randomstring_t *randomstring;\n\n#ifdef DEBUG\n\tint starttime = Sys_MilliSeconds();\n#endif //DEBUG\n\n\tsize = 0;\n\trandomlist = NULL;\n\trandom = NULL;\n\t//the synonyms are parsed in two phases\n\tfor (pass = 0; pass < 2; pass++)\n\t{\n\t\t//\n\t\tif (pass && size) ptr = (char *) GetClearedHunkMemory(size);\n\t\t//\n\t\tPC_SetBaseFolder(BOTFILESBASEFOLDER);\n\t\tsource = LoadSourceFile(filename);\n\t\tif (!source)\n\t\t{\n\t\t\tbotimport.Print(PRT_ERROR, \"counldn't load %s\\n\", filename);\n\t\t\treturn NULL;\n\t\t} //end if\n\t\t//\n\t\trandomlist = NULL; //list\n\t\tlastrandom = NULL; //last\n\t\t//\n\t\twhile(PC_ReadToken(source, &token))\n\t\t{\n\t\t\tif (token.type != TT_NAME)\n\t\t\t{\n\t\t\t\tSourceError(source, \"unknown random %s\", token.string);\n\t\t\t\tFreeSource(source);\n\t\t\t\treturn NULL;\n\t\t\t} //end if\n\t\t\tsize += sizeof(bot_randomlist_t) + (int)strlen(token.string) + 1;\n\t\t\tif (pass)\n\t\t\t{\n\t\t\t\trandom = (bot_randomlist_t *) ptr;\n\t\t\t\tptr += sizeof(bot_randomlist_t);\n\t\t\t\trandom->string = ptr;\n\t\t\t\tptr += (int)strlen(token.string) + 1;\n\t\t\t\tstrcpy(random->string, token.string);\n\t\t\t\trandom->firstrandomstring = NULL;\n\t\t\t\trandom->numstrings = 0;\n\t\t\t\t//\n\t\t\t\tif (lastrandom) lastrandom->next = random;\n\t\t\t\telse randomlist = random;\n\t\t\t\tlastrandom = random;\n\t\t\t} //end if\n\t\t\tif (!PC_ExpectTokenString(source, \"=\") ||\n\t\t\t\t!PC_ExpectTokenString(source, \"{\"))\n\t\t\t{\n\t\t\t\tFreeSource(source);\n\t\t\t\treturn NULL;\n\t\t\t} //end if\n\t\t\twhile(!PC_CheckTokenString(source, \"}\"))\n\t\t\t{\n\t\t\t\tif (!BotLoadChatMessage(source, chatmessagestring))\n\t\t\t\t{\n\t\t\t\t\tFreeSource(source);\n\t\t\t\t\treturn NULL;\n\t\t\t\t} //end if\n\t\t\t\tsize += sizeof(bot_randomstring_t) + (int)strlen(chatmessagestring) + 1;\n\t\t\t\tif (pass)\n\t\t\t\t{\n\t\t\t\t\trandomstring = (bot_randomstring_t *) ptr;\n\t\t\t\t\tptr += sizeof(bot_randomstring_t);\n\t\t\t\t\trandomstring->string = ptr;\n\t\t\t\t\tptr += (int)strlen(chatmessagestring) + 1;\n\t\t\t\t\tstrcpy(randomstring->string, chatmessagestring);\n\t\t\t\t\t//\n\t\t\t\t\trandom->numstrings++;\n\t\t\t\t\trandomstring->next = random->firstrandomstring;\n\t\t\t\t\trandom->firstrandomstring = randomstring;\n\t\t\t\t} //end if\n\t\t\t} //end while\n\t\t} //end while\n\t\t//free the source after one pass\n\t\tFreeSource(source);\n\t} //end for\n\tbotimport.Print(PRT_MESSAGE, \"loaded %s\\n\", filename);\n\t//\n#ifdef DEBUG\n\tbotimport.Print(PRT_MESSAGE, \"random strings %d msec\\n\", Sys_MilliSeconds() - starttime);\n\t//BotDumpRandomStringList(randomlist);\n#endif //DEBUG\n\t//\n\treturn randomlist;\n} //end of the function BotLoadRandomStrings\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nchar *RandomString(char *name)\n{\n\tbot_randomlist_t *random;\n\tbot_randomstring_t *rs;\n\tint i;\n\n\tfor (random = randomstrings; random; random = random->next)\n\t{\n\t\tif (!strcmp(random->string, name))\n\t\t{\n\t\t\ti = random() * random->numstrings;\n\t\t\tfor (rs = random->firstrandomstring; rs; rs = rs->next)\n\t\t\t{\n\t\t\t\tif (--i < 0) break;\n\t\t\t} //end for\n\t\t\tif (rs)\n\t\t\t{\n\t\t\t\treturn rs->string;\n\t\t\t} //end if\n\t\t} //end for\n\t} //end for\n\treturn NULL;\n} //end of the function RandomString\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotDumpMatchTemplates(bot_matchtemplate_t *matches)\n{\n\tFILE *fp;\n\tbot_matchtemplate_t *mt;\n\tbot_matchpiece_t *mp;\n\tbot_matchstring_t *ms;\n\n\tfp = Log_FilePointer();\n\tif (!fp) return;\n\tfor (mt = matches; mt; mt = mt->next)\n\t{\n\t        fprintf(fp, \"{ \" );\n\t\tfor (mp = mt->first; mp; mp = mp->next)\n\t\t{\n\t\t\tif (mp->type == MT_STRING)\n\t\t\t{\n\t\t\t\tfor (ms = mp->firststring; ms; ms = ms->next)\n\t\t\t\t{\n\t\t\t\t\tfprintf(fp, \"\\\"%s\\\"\", ms->string);\n\t\t\t\t\tif (ms->next) fprintf(fp, \"|\");\n\t\t\t\t} //end for\n\t\t\t} //end if\n\t\t\telse if (mp->type == MT_VARIABLE)\n\t\t\t{\n\t\t\t\tfprintf(fp, \"%d\", mp->variable);\n\t\t\t} //end else if\n\t\t\tif (mp->next) fprintf(fp, \", \");\n\t\t} //end for\n\t\tfprintf(fp, \" = (%d, %d);}\\n\", mt->type, mt->subtype);\n\t} //end for\n} //end of the function BotDumpMatchTemplates\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotFreeMatchPieces(bot_matchpiece_t *matchpieces)\n{\n\tbot_matchpiece_t *mp, *nextmp;\n\tbot_matchstring_t *ms, *nextms;\n\n\tfor (mp = matchpieces; mp; mp = nextmp)\n\t{\n\t\tnextmp = mp->next;\n\t\tif (mp->type == MT_STRING)\n\t\t{\n\t\t\tfor (ms = mp->firststring; ms; ms = nextms)\n\t\t\t{\n\t\t\t\tnextms = ms->next;\n\t\t\t\tFreeMemory(ms);\n\t\t\t} //end for\n\t\t} //end if\n\t\tFreeMemory(mp);\n\t} //end for\n} //end of the function BotFreeMatchPieces\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nbot_matchpiece_t *BotLoadMatchPieces(source_t *source, char *endtoken)\n{\n\tint lastwasvariable, emptystring;\n\ttoken_t token;\n\tbot_matchpiece_t *matchpiece, *firstpiece, *lastpiece;\n\tbot_matchstring_t *matchstring, *lastmatchstring;\n\n\tfirstpiece = NULL;\n\tlastpiece = NULL;\n\t//\n\tlastwasvariable = qfalse;\n\t//\n\twhile(PC_ReadToken(source, &token))\n\t{\n\t\tif (token.type == TT_NUMBER && (token.subtype & TT_INTEGER))\n\t\t{\n\t\t\tif (token.intvalue < 0 || token.intvalue >= MAX_MATCHVARIABLES)\n\t\t\t{\n\t\t\t\tSourceError(source, \"can't have more than %d match variables\\n\", MAX_MATCHVARIABLES);\n\t\t\t\tFreeSource(source);\n\t\t\t\tBotFreeMatchPieces(firstpiece);\n\t\t\t\treturn NULL;\n\t\t\t} //end if\n\t\t\tif (lastwasvariable)\n\t\t\t{\n\t\t\t\tSourceError(source, \"not allowed to have adjacent variables\\n\");\n\t\t\t\tFreeSource(source);\n\t\t\t\tBotFreeMatchPieces(firstpiece);\n\t\t\t\treturn NULL;\n\t\t\t} //end if\n\t\t\tlastwasvariable = qtrue;\n\t\t\t//\n\t\t\tmatchpiece = (bot_matchpiece_t *) GetClearedHunkMemory(sizeof(bot_matchpiece_t));\n\t\t\tmatchpiece->type = MT_VARIABLE;\n\t\t\tmatchpiece->variable = token.intvalue;\n\t\t\tmatchpiece->next = NULL;\n\t\t\tif (lastpiece) lastpiece->next = matchpiece;\n\t\t\telse firstpiece = matchpiece;\n\t\t\tlastpiece = matchpiece;\n\t\t} //end if\n\t\telse if (token.type == TT_STRING)\n\t\t{\n\t\t\t//\n\t\t\tmatchpiece = (bot_matchpiece_t *) GetClearedHunkMemory(sizeof(bot_matchpiece_t));\n\t\t\tmatchpiece->firststring = NULL;\n\t\t\tmatchpiece->type = MT_STRING;\n\t\t\tmatchpiece->variable = 0;\n\t\t\tmatchpiece->next = NULL;\n\t\t\tif (lastpiece) lastpiece->next = matchpiece;\n\t\t\telse firstpiece = matchpiece;\n\t\t\tlastpiece = matchpiece;\n\t\t\t//\n\t\t\tlastmatchstring = NULL;\n\t\t\temptystring = qfalse;\n\t\t\t//\n\t\t\tdo\n\t\t\t{\n\t\t\t\tif (matchpiece->firststring)\n\t\t\t\t{\n\t\t\t\t\tif (!PC_ExpectTokenType(source, TT_STRING, 0, &token))\n\t\t\t\t\t{\n\t\t\t\t\t\tFreeSource(source);\n\t\t\t\t\t\tBotFreeMatchPieces(firstpiece);\n\t\t\t\t\t\treturn NULL;\n\t\t\t\t\t} //end if\n\t\t\t\t} //end if\n\t\t\t\tStripDoubleQuotes(token.string);\n\t\t\t\tmatchstring = (bot_matchstring_t *) GetClearedHunkMemory(sizeof(bot_matchstring_t) + (int)strlen(token.string) + 1);\n\t\t\t\tmatchstring->string = (char *) matchstring + sizeof(bot_matchstring_t);\n\t\t\t\tstrcpy(matchstring->string, token.string);\n\t\t\t\tif (!(int)strlen(token.string)) emptystring = qtrue;\n\t\t\t\tmatchstring->next = NULL;\n\t\t\t\tif (lastmatchstring) lastmatchstring->next = matchstring;\n\t\t\t\telse matchpiece->firststring = matchstring;\n\t\t\t\tlastmatchstring = matchstring;\n\t\t\t} while(PC_CheckTokenString(source, \"|\"));\n\t\t\t//if there was no empty string found\n\t\t\tif (!emptystring) lastwasvariable = qfalse;\n\t\t} //end if\n\t\telse\n\t\t{\n\t\t\tSourceError(source, \"invalid token %s\\n\", token.string);\n\t\t\tFreeSource(source);\n\t\t\tBotFreeMatchPieces(firstpiece);\n\t\t\treturn NULL;\n\t\t} //end else\n\t\tif (PC_CheckTokenString(source, endtoken)) break;\n\t\tif (!PC_ExpectTokenString(source, \",\"))\n\t\t{\n\t\t\tFreeSource(source);\n\t\t\tBotFreeMatchPieces(firstpiece);\n\t\t\treturn NULL;\n\t\t} //end if\n\t} //end while\n\treturn firstpiece;\n} //end of the function BotLoadMatchPieces\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotFreeMatchTemplates(bot_matchtemplate_t *mt)\n{\n\tbot_matchtemplate_t *nextmt;\n\n\tfor (; mt; mt = nextmt)\n\t{\n\t\tnextmt = mt->next;\n\t\tBotFreeMatchPieces(mt->first);\n\t\tFreeMemory(mt);\n\t} //end for\n} //end of the function BotFreeMatchTemplates\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nbot_matchtemplate_t *BotLoadMatchTemplates(char *matchfile)\n{\n\tsource_t *source;\n\ttoken_t token;\n\tbot_matchtemplate_t *matchtemplate, *matches, *lastmatch;\n\tunsigned long int context;\n\n\tPC_SetBaseFolder(BOTFILESBASEFOLDER);\n\tsource = LoadSourceFile(matchfile);\n\tif (!source)\n\t{\n\t\tbotimport.Print(PRT_ERROR, \"counldn't load %s\\n\", matchfile);\n\t\treturn NULL;\n\t} //end if\n\t//\n\tmatches = NULL; //list with matches\n\tlastmatch = NULL; //last match in the list\n\n\twhile(PC_ReadToken(source, &token))\n\t{\n\t\tif (token.type != TT_NUMBER || !(token.subtype & TT_INTEGER))\n\t\t{\n\t\t\tSourceError(source, \"expected integer, found %s\\n\", token.string);\n\t\t\tBotFreeMatchTemplates(matches);\n\t\t\tFreeSource(source);\n\t\t\treturn NULL;\n\t\t} //end if\n\t\t//the context\n\t\tcontext = token.intvalue;\n\t\t//\n\t\tif (!PC_ExpectTokenString(source, \"{\"))\n\t\t{\n\t\t\tBotFreeMatchTemplates(matches);\n\t\t\tFreeSource(source);\n\t\t\treturn NULL;\n\t\t} //end if\n\t\t//\n\t\twhile(PC_ReadToken(source, &token))\n\t\t{\n\t\t\tif (!strcmp(token.string, \"}\")) break;\n\t\t\t//\n\t\t\tPC_UnreadLastToken(source);\n\t\t\t//\n\t\t\tmatchtemplate = (bot_matchtemplate_t *) GetClearedHunkMemory(sizeof(bot_matchtemplate_t));\n\t\t\tmatchtemplate->context = context;\n\t\t\tmatchtemplate->next = NULL;\n\t\t\t//add the match template to the list\n\t\t\tif (lastmatch) lastmatch->next = matchtemplate;\n\t\t\telse matches = matchtemplate;\n\t\t\tlastmatch = matchtemplate;\n\t\t\t//load the match template\n\t\t\tmatchtemplate->first = BotLoadMatchPieces(source, \"=\");\n\t\t\tif (!matchtemplate->first)\n\t\t\t{\n\t\t\t\tBotFreeMatchTemplates(matches);\n\t\t\t\treturn NULL;\n\t\t\t} //end if\n\t\t\t//read the match type\n\t\t\tif (!PC_ExpectTokenString(source, \"(\") ||\n\t\t\t\t!PC_ExpectTokenType(source, TT_NUMBER, TT_INTEGER, &token))\n\t\t\t{\n\t\t\t\tBotFreeMatchTemplates(matches);\n\t\t\t\tFreeSource(source);\n\t\t\t\treturn NULL;\n\t\t\t} //end if\n\t\t\tmatchtemplate->type = token.intvalue;\n\t\t\t//read the match subtype\n\t\t\tif (!PC_ExpectTokenString(source, \",\") ||\n\t\t\t\t!PC_ExpectTokenType(source, TT_NUMBER, TT_INTEGER, &token))\n\t\t\t{\n\t\t\t\tBotFreeMatchTemplates(matches);\n\t\t\t\tFreeSource(source);\n\t\t\t\treturn NULL;\n\t\t\t} //end if\n\t\t\tmatchtemplate->subtype = token.intvalue;\n\t\t\t//read trailing punctuations\n\t\t\tif (!PC_ExpectTokenString(source, \")\") ||\n\t\t\t\t!PC_ExpectTokenString(source, \";\"))\n\t\t\t{\n\t\t\t\tBotFreeMatchTemplates(matches);\n\t\t\t\tFreeSource(source);\n\t\t\t\treturn NULL;\n\t\t\t} //end if\n\t\t} //end while\n\t} //end while\n\t//free the source\n\tFreeSource(source);\n\tbotimport.Print(PRT_MESSAGE, \"loaded %s\\n\", matchfile);\n\t//\n\t//BotDumpMatchTemplates(matches);\n\t//\n\treturn matches;\n} //end of the function BotLoadMatchTemplates\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint StringsMatch(bot_matchpiece_t *pieces, bot_match_t *match)\n{\n\tint lastvariable, index;\n\tchar *strptr, *newstrptr;\n\tbot_matchpiece_t *mp;\n\tbot_matchstring_t *ms;\n\n\t//no last variable\n\tlastvariable = -1;\n\t//pointer to the string to compare the match string with\n\tstrptr = match->string;\n\t//Log_Write(\"match: %s\", strptr);\n\t//compare the string with the current match string\n\tfor (mp = pieces; mp; mp = mp->next)\n\t{\n\t\t//if it is a piece of string\n\t\tif (mp->type == MT_STRING)\n\t\t{\n\t\t\tnewstrptr = NULL;\n\t\t\tfor (ms = mp->firststring; ms; ms = ms->next)\n\t\t\t{\n\t\t\t\tif (!(int)strlen(ms->string))\n\t\t\t\t{\n\t\t\t\t\tnewstrptr = strptr;\n\t\t\t\t\tbreak;\n\t\t\t\t} //end if\n\t\t\t\t//Log_Write(\"MT_STRING: %s\", mp->string);\n\t\t\t\tindex = StringContains(strptr, ms->string, qfalse);\n\t\t\t\tif (index >= 0)\n\t\t\t\t{\n\t\t\t\t\tnewstrptr = strptr + index;\n\t\t\t\t\tif (lastvariable >= 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tmatch->variables[lastvariable].length =\n\t\t\t\t\t\t\t\t(newstrptr - match->string) - match->variables[lastvariable].offset;\n\t\t\t\t\t\t\t\t//newstrptr - match->variables[lastvariable].ptr;\n\t\t\t\t\t\tlastvariable = -1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t} //end if\n\t\t\t\t\telse if (index == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t} //end else\n\t\t\t\t\tnewstrptr = NULL;\n\t\t\t\t} //end if\n\t\t\t} //end for\n\t\t\tif (!newstrptr) return qfalse;\n\t\t\tstrptr = newstrptr + (int)strlen(ms->string);\n\t\t} //end if\n\t\t//if it is a variable piece of string\n\t\telse if (mp->type == MT_VARIABLE)\n\t\t{\n\t\t\t//Log_Write(\"MT_VARIABLE\");\n\t\t\tmatch->variables[mp->variable].offset = strptr - match->string;\n\t\t\tlastvariable = mp->variable;\n\t\t} //end else if\n\t} //end for\n\t//if a match was found\n\tif (!mp && (lastvariable >= 0 || !(int)strlen(strptr)))\n\t{\n\t\t//if the last piece was a variable string\n\t\tif (lastvariable >= 0)\n\t\t{\n        \t\tassert( match->variables[lastvariable].offset >= 0 ); // bk001204\n\t\t\tmatch->variables[lastvariable].length =\n\t\t\t\t(int)strlen(&match->string[ (int) match->variables[lastvariable].offset]);\n\t\t} //end if\n\t\treturn qtrue;\n\t} //end if\n\treturn qfalse;\n} //end of the function StringsMatch\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotFindMatch(char *str, bot_match_t *match, unsigned long int context)\n{\n\tint i;\n\tbot_matchtemplate_t *ms;\n\n\tstrncpy(match->string, str, MAX_MESSAGE_SIZE);\n\t//remove any trailing enters\n\twhile((int)strlen(match->string) &&\n\t\t\tmatch->string[(int)strlen(match->string)-1] == '\\n')\n\t{\n\t\tmatch->string[(int)strlen(match->string)-1] = '\\0';\n\t} //end while\n\t//compare the string with all the match strings\n\tfor (ms = matchtemplates; ms; ms = ms->next)\n\t{\n\t\tif (!(ms->context & context)) continue;\n\t\t//reset the match variable offsets\n\t\tfor (i = 0; i < MAX_MATCHVARIABLES; i++) match->variables[i].offset = -1;\n\t\t//\n\t\tif (StringsMatch(ms->first, match))\n\t\t{\n\t\t\tmatch->type = ms->type;\n\t\t\tmatch->subtype = ms->subtype;\n\t\t\treturn qtrue;\n\t\t} //end if\n\t} //end for\n\treturn qfalse;\n} //end of the function BotFindMatch\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotMatchVariable(bot_match_t *match, int variable, char *buf, int size)\n{\n\tif (variable < 0 || variable >= MAX_MATCHVARIABLES)\n\t{\n\t\tbotimport.Print(PRT_FATAL, \"BotMatchVariable: variable out of range\\n\");\n\t\tstrcpy(buf, \"\");\n\t\treturn;\n\t} //end if\n\n\tif (match->variables[variable].offset >= 0)\n\t{\n\t\tif (match->variables[variable].length < size)\n\t\t\tsize = match->variables[variable].length+1;\n\t\tassert( match->variables[variable].offset >= 0 ); // bk001204\n\t\tstrncpy(buf, &match->string[ (int) match->variables[variable].offset], size-1);\n\t\tbuf[size-1] = '\\0';\n\t} //end if\n\telse\n\t{\n\t\tstrcpy(buf, \"\");\n\t} //end else\n\treturn;\n} //end of the function BotMatchVariable\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nbot_stringlist_t *BotFindStringInList(bot_stringlist_t *list, char *string)\n{\n\tbot_stringlist_t *s;\n\n\tfor (s = list; s; s = s->next)\n\t{\n\t\tif (!strcmp(s->string, string)) return s;\n\t} //end for\n\treturn NULL;\n} //end of the function BotFindStringInList\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nbot_stringlist_t *BotCheckChatMessageIntegrety(char *message, bot_stringlist_t *stringlist)\n{\n\tint i;\n\tchar *msgptr;\n\tchar temp[MAX_MESSAGE_SIZE];\n\tbot_stringlist_t *s;\n\n\tmsgptr = message;\n\t//\n\twhile(*msgptr)\n\t{\n\t\tif (*msgptr == ESCAPE_CHAR)\n\t\t{\n\t\t\tmsgptr++;\n\t\t\tswitch(*msgptr)\n\t\t\t{\n\t\t\t\tcase 'v': //variable\n\t\t\t\t{\n\t\t\t\t\t//step over the 'v'\n\t\t\t\t\tmsgptr++;\n\t\t\t\t\twhile(*msgptr && *msgptr != ESCAPE_CHAR) msgptr++;\n\t\t\t\t\t//step over the trailing escape char\n\t\t\t\t\tif (*msgptr) msgptr++;\n\t\t\t\t\tbreak;\n\t\t\t\t} //end case\n\t\t\t\tcase 'r': //random\n\t\t\t\t{\n\t\t\t\t\t//step over the 'r'\n\t\t\t\t\tmsgptr++;\n\t\t\t\t\tfor (i = 0; (*msgptr && *msgptr != ESCAPE_CHAR); i++)\n\t\t\t\t\t{\n\t\t\t\t\t\ttemp[i] = *msgptr++;\n\t\t\t\t\t} //end while\n\t\t\t\t\ttemp[i] = '\\0';\n\t\t\t\t\t//step over the trailing escape char\n\t\t\t\t\tif (*msgptr) msgptr++;\n\t\t\t\t\t//find the random keyword\n\t\t\t\t\tif (!RandomString(temp))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (!BotFindStringInList(stringlist, temp))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tLog_Write(\"%s = {\\\"%s\\\"} //MISSING RANDOM\\r\\n\", temp, temp);\n\t\t\t\t\t\t\ts = (bot_stringlist_t*) GetClearedMemory(sizeof(bot_stringlist_t) + (int)strlen(temp) + 1);\n\t\t\t\t\t\t\ts->string = (char *) s + sizeof(bot_stringlist_t);\n\t\t\t\t\t\t\tstrcpy(s->string, temp);\n\t\t\t\t\t\t\ts->next = stringlist;\n\t\t\t\t\t\t\tstringlist = s;\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t} //end if\n\t\t\t\t\tbreak;\n\t\t\t\t} //end case\n\t\t\t\tdefault:\n\t\t\t\t{\n\t\t\t\t\tbotimport.Print(PRT_FATAL, \"BotCheckChatMessageIntegrety: message \\\"%s\\\" invalid escape char\\n\", message);\n\t\t\t\t\tbreak;\n\t\t\t\t} //end default\n\t\t\t} //end switch\n\t\t} //end if\n\t\telse\n\t\t{\n\t\t\tmsgptr++;\n\t\t} //end else\n\t} //end while\n\treturn stringlist;\n} //end of the function BotCheckChatMessageIntegrety\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotCheckInitialChatIntegrety(bot_chat_t *chat)\n{\n\tbot_chattype_t *t;\n\tbot_chatmessage_t *cm;\n\tbot_stringlist_t *stringlist, *s, *nexts;\n\n\tstringlist = NULL;\n\tfor (t = chat->types; t; t = t->next)\n\t{\n\t\tfor (cm = t->firstchatmessage; cm; cm = cm->next)\n\t\t{\n\t\t\tstringlist = BotCheckChatMessageIntegrety(cm->chatmessage, stringlist);\n\t\t} //end for\n\t} //end for\n\tfor (s = stringlist; s; s = nexts)\n\t{\n\t\tnexts = s->next;\n\t\tFreeMemory(s);\n\t} //end for\n} //end of the function BotCheckInitialChatIntegrety\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotCheckReplyChatIntegrety(bot_replychat_t *replychat)\n{\n\tbot_replychat_t *rp;\n\tbot_chatmessage_t *cm;\n\tbot_stringlist_t *stringlist, *s, *nexts;\n\n\tstringlist = NULL;\n\tfor (rp = replychat; rp; rp = rp->next)\n\t{\n\t\tfor (cm = rp->firstchatmessage; cm; cm = cm->next)\n\t\t{\n\t\t\tstringlist = BotCheckChatMessageIntegrety(cm->chatmessage, stringlist);\n\t\t} //end for\n\t} //end for\n\tfor (s = stringlist; s; s = nexts)\n\t{\n\t\tnexts = s->next;\n\t\tFreeMemory(s);\n\t} //end for\n} //end of the function BotCheckReplyChatIntegrety\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotDumpReplyChat(bot_replychat_t *replychat)\n{\n\tFILE *fp;\n\tbot_replychat_t *rp;\n\tbot_replychatkey_t *key;\n\tbot_chatmessage_t *cm;\n\tbot_matchpiece_t *mp;\n\n\tfp = Log_FilePointer();\n\tif (!fp) return;\n\tfprintf(fp, \"BotDumpReplyChat:\\n\");\n\tfor (rp = replychat; rp; rp = rp->next)\n\t{\n\t\tfprintf(fp, \"[\");\n\t\tfor (key = rp->keys; key; key = key->next)\n\t\t{\n\t\t\tif (key->flags & RCKFL_AND) fprintf(fp, \"&\");\n\t\t\telse if (key->flags & RCKFL_NOT) fprintf(fp, \"!\");\n\t\t\t//\n\t\t\tif (key->flags & RCKFL_NAME) fprintf(fp, \"name\");\n\t\t\telse if (key->flags & RCKFL_GENDERFEMALE) fprintf(fp, \"female\");\n\t\t\telse if (key->flags & RCKFL_GENDERMALE) fprintf(fp, \"male\");\n\t\t\telse if (key->flags & RCKFL_GENDERLESS) fprintf(fp, \"it\");\n\t\t\telse if (key->flags & RCKFL_VARIABLES)\n\t\t\t{\n\t\t\t\tfprintf(fp, \"(\");\n\t\t\t\tfor (mp = key->match; mp; mp = mp->next)\n\t\t\t\t{\n\t\t\t\t\tif (mp->type == MT_STRING) fprintf(fp, \"\\\"%s\\\"\", mp->firststring->string);\n\t\t\t\t\telse fprintf(fp, \"%d\", mp->variable);\n\t\t\t\t\tif (mp->next) fprintf(fp, \", \");\n\t\t\t\t} //end for\n\t\t\t\tfprintf(fp, \")\");\n\t\t\t} //end if\n\t\t\telse if (key->flags & RCKFL_STRING)\n\t\t\t{\n\t\t\t\tfprintf(fp, \"\\\"%s\\\"\", key->string);\n\t\t\t} //end if\n\t\t\tif (key->next) fprintf(fp, \", \");\n\t\t\telse fprintf(fp, \"] = %1.0f\\n\", rp->priority);\n\t\t} //end for\n\t\tfprintf(fp, \"{\\n\");\n\t\tfor (cm = rp->firstchatmessage; cm; cm = cm->next)\n\t\t{\n\t\t\tfprintf(fp, \"\\t\\\"%s\\\";\\n\", cm->chatmessage);\n\t\t} //end for\n\t\tfprintf(fp, \"}\\n\");\n\t} //end for\n} //end of the function BotDumpReplyChat\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotFreeReplyChat(bot_replychat_t *replychat)\n{\n\tbot_replychat_t *rp, *nextrp;\n\tbot_replychatkey_t *key, *nextkey;\n\tbot_chatmessage_t *cm, *nextcm;\n\n\tfor (rp = replychat; rp; rp = nextrp)\n\t{\n\t\tnextrp = rp->next;\n\t\tfor (key = rp->keys; key; key = nextkey)\n\t\t{\n\t\t\tnextkey = key->next;\n\t\t\tif (key->match) BotFreeMatchPieces(key->match);\n\t\t\tif (key->string) FreeMemory(key->string);\n\t\t\tFreeMemory(key);\n\t\t} //end for\n\t\tfor (cm = rp->firstchatmessage; cm; cm = nextcm)\n\t\t{\n\t\t\tnextcm = cm->next;\n\t\t\tFreeMemory(cm);\n\t\t} //end for\n\t\tFreeMemory(rp);\n\t} //end for\n} //end of the function BotFreeReplyChat\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotCheckValidReplyChatKeySet(source_t *source, bot_replychatkey_t *keys)\n{\n\tint allprefixed, hasvariableskey, hasstringkey;\n\tbot_matchpiece_t *m;\n\tbot_matchstring_t *ms;\n\tbot_replychatkey_t *key, *key2;\n\n\t//\n\tallprefixed = qtrue;\n\thasvariableskey = hasstringkey = qfalse;\n\tfor (key = keys; key; key = key->next)\n\t{\n\t\tif (!(key->flags & (RCKFL_AND|RCKFL_NOT)))\n\t\t{\n\t\t\tallprefixed = qfalse;\n\t\t\tif (key->flags & RCKFL_VARIABLES)\n\t\t\t{\n\t\t\t\tfor (m = key->match; m; m = m->next)\n\t\t\t\t{\n\t\t\t\t\tif (m->type == MT_VARIABLE) hasvariableskey = qtrue;\n\t\t\t\t} //end for\n\t\t\t} //end if\n\t\t\telse if (key->flags & RCKFL_STRING)\n\t\t\t{\n\t\t\t\thasstringkey = qtrue;\n\t\t\t} //end else if\n\t\t} //end if\n\t\telse if ((key->flags & RCKFL_AND) && (key->flags & RCKFL_STRING))\n\t\t{\n\t\t\tfor (key2 = keys; key2; key2 = key2->next)\n\t\t\t{\n\t\t\t\tif (key2 == key) continue;\n\t\t\t\tif (key2->flags & RCKFL_NOT) continue;\n\t\t\t\tif (key2->flags & RCKFL_VARIABLES)\n\t\t\t\t{\n\t\t\t\t\tfor (m = key2->match; m; m = m->next)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (m->type == MT_STRING)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfor (ms = m->firststring; ms; ms = ms->next)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (StringContains(ms->string, key->string, qfalse) != -1)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t} //end if\n\t\t\t\t\t\t\t} //end for\n\t\t\t\t\t\t\tif (ms) break;\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t\telse if (m->type == MT_VARIABLE)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t} //end for\n\t\t\t\t\tif (!m)\n\t\t\t\t\t{\n\t\t\t\t\t\tSourceWarning(source, \"one of the match templates does not \"\n\t\t\t\t\t\t\t\t\t\t\"leave space for the key %s with the & prefix\", key->string);\n\t\t\t\t\t} //end if\n\t\t\t\t} //end if\n\t\t\t} //end for\n\t\t} //end else\n\t\tif ((key->flags & RCKFL_NOT) && (key->flags & RCKFL_STRING))\n\t\t{\n\t\t\tfor (key2 = keys; key2; key2 = key2->next)\n\t\t\t{\n\t\t\t\tif (key2 == key) continue;\n\t\t\t\tif (key2->flags & RCKFL_NOT) continue;\n\t\t\t\tif (key2->flags & RCKFL_STRING)\n\t\t\t\t{\n\t\t\t\t\tif (StringContains(key2->string, key->string, qfalse) != -1)\n\t\t\t\t\t{\n\t\t\t\t\t\tSourceWarning(source, \"the key %s with prefix ! is inside the key %s\", key->string, key2->string);\n\t\t\t\t\t} //end if\n\t\t\t\t} //end if\n\t\t\t\telse if (key2->flags & RCKFL_VARIABLES)\n\t\t\t\t{\n\t\t\t\t\tfor (m = key2->match; m; m = m->next)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (m->type == MT_STRING)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfor (ms = m->firststring; ms; ms = ms->next)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (StringContains(ms->string, key->string, qfalse) != -1)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tSourceWarning(source, \"the key %s with prefix ! is inside \"\n\t\t\t\t\t\t\t\t\t\t\t\t\"the match template string %s\", key->string, ms->string);\n\t\t\t\t\t\t\t\t} //end if\n\t\t\t\t\t\t\t} //end for\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t} //end for\n\t\t\t\t} //end else if\n\t\t\t} //end for\n\t\t} //end if\n\t} //end for\n\tif (allprefixed) SourceWarning(source, \"all keys have a & or ! prefix\");\n\tif (hasvariableskey && hasstringkey)\n\t{\n\t\tSourceWarning(source, \"variables from the match template(s) could be \"\n\t\t\t\t\t\t\t\t\"invalid when outputting one of the chat messages\");\n\t} //end if\n} //end of the function BotCheckValidReplyChatKeySet\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nbot_replychat_t *BotLoadReplyChat(char *filename)\n{\n\tchar chatmessagestring[MAX_MESSAGE_SIZE];\n\tchar namebuffer[MAX_MESSAGE_SIZE];\n\tsource_t *source;\n\ttoken_t token;\n\tbot_chatmessage_t *chatmessage = NULL;\n\tbot_replychat_t *replychat, *replychatlist;\n\tbot_replychatkey_t *key;\n\n\tPC_SetBaseFolder(BOTFILESBASEFOLDER);\n\tsource = LoadSourceFile(filename);\n\tif (!source)\n\t{\n\t\tbotimport.Print(PRT_ERROR, \"counldn't load %s\\n\", filename);\n\t\treturn NULL;\n\t} //end if\n\t//\n\treplychatlist = NULL;\n\t//\n\twhile(PC_ReadToken(source, &token))\n\t{\n\t\tif (strcmp(token.string, \"[\"))\n\t\t{\n\t\t\tSourceError(source, \"expected [, found %s\", token.string);\n\t\t\tBotFreeReplyChat(replychatlist);\n\t\t\tFreeSource(source);\n\t\t\treturn NULL;\n\t\t} //end if\n\t\t//\n\t\treplychat = (bot_replychat_t*) GetClearedHunkMemory(sizeof(bot_replychat_t));\n\t\treplychat->keys = NULL;\n\t\treplychat->next = replychatlist;\n\t\treplychatlist = replychat;\n\t\t//read the keys, there must be at least one key\n\t\tdo\n\t\t{\n\t\t\t//allocate a key\n\t\t\tkey = (bot_replychatkey_t *) GetClearedHunkMemory(sizeof(bot_replychatkey_t));\n\t\t\tkey->flags = 0;\n\t\t\tkey->string = NULL;\n\t\t\tkey->match = NULL;\n\t\t\tkey->next = replychat->keys;\n\t\t\treplychat->keys = key;\n\t\t\t//check for MUST BE PRESENT and MUST BE ABSENT keys\n\t\t\tif (PC_CheckTokenString(source, \"&\")) key->flags |= RCKFL_AND;\n\t\t\telse if (PC_CheckTokenString(source, \"!\")) key->flags |= RCKFL_NOT;\n\t\t\t//special keys\n\t\t\tif (PC_CheckTokenString(source, \"name\")) key->flags |= RCKFL_NAME;\n\t\t\telse if (PC_CheckTokenString(source, \"female\")) key->flags |= RCKFL_GENDERFEMALE;\n\t\t\telse if (PC_CheckTokenString(source, \"male\")) key->flags |= RCKFL_GENDERMALE;\n\t\t\telse if (PC_CheckTokenString(source, \"it\")) key->flags |= RCKFL_GENDERLESS;\n\t\t\telse if (PC_CheckTokenString(source, \"(\")) //match key\n\t\t\t{\n\t\t\t\tkey->flags |= RCKFL_VARIABLES;\n\t\t\t\tkey->match = BotLoadMatchPieces(source, \")\");\n\t\t\t\tif (!key->match)\n\t\t\t\t{\n\t\t\t\t\tBotFreeReplyChat(replychatlist);\n\t\t\t\t\treturn NULL;\n\t\t\t\t} //end if\n\t\t\t} //end else if\n\t\t\telse if (PC_CheckTokenString(source, \"<\")) //bot names\n\t\t\t{\n\t\t\t\tkey->flags |= RCKFL_BOTNAMES;\n\t\t\t\tstrcpy(namebuffer, \"\");\n\t\t\t\tdo\n\t\t\t\t{\n\t\t\t\t\tif (!PC_ExpectTokenType(source, TT_STRING, 0, &token))\n\t\t\t\t\t{\n\t\t\t\t\t\tBotFreeReplyChat(replychatlist);\n\t\t\t\t\t\tFreeSource(source);\n\t\t\t\t\t\treturn NULL;\n\t\t\t\t\t} //end if\n\t\t\t\t\tStripDoubleQuotes(token.string);\n\t\t\t\t\tif ((int)strlen(namebuffer)) strcat(namebuffer, \"\\\\\");\n\t\t\t\t\tstrcat(namebuffer, token.string);\n\t\t\t\t} while(PC_CheckTokenString(source, \",\"));\n\t\t\t\tif (!PC_ExpectTokenString(source, \">\"))\n\t\t\t\t{\n\t\t\t\t\tBotFreeReplyChat(replychatlist);\n\t\t\t\t\tFreeSource(source);\n\t\t\t\t\treturn NULL;\n\t\t\t\t} //end if\n\t\t\t\tkey->string = (char *) GetClearedHunkMemory((int)strlen(namebuffer) + 1);\n\t\t\t\tstrcpy(key->string, namebuffer);\n\t\t\t} //end else if\n\t\t\telse //normal string key\n\t\t\t{\n\t\t\t\tkey->flags |= RCKFL_STRING;\n\t\t\t\tif (!PC_ExpectTokenType(source, TT_STRING, 0, &token))\n\t\t\t\t{\n\t\t\t\t\tBotFreeReplyChat(replychatlist);\n\t\t\t\t\tFreeSource(source);\n\t\t\t\t\treturn NULL;\n\t\t\t\t} //end if\n\t\t\t\tStripDoubleQuotes(token.string);\n\t\t\t\tkey->string = (char *) GetClearedHunkMemory((int)strlen(token.string) + 1);\n\t\t\t\tstrcpy(key->string, token.string);\n\t\t\t} //end else\n\t\t\t//\n\t\t\tPC_CheckTokenString(source, \",\");\n\t\t} while(!PC_CheckTokenString(source, \"]\"));\n\t\t//\n\t\tBotCheckValidReplyChatKeySet(source, replychat->keys);\n\t\t//read the = sign and the priority\n\t\tif (!PC_ExpectTokenString(source, \"=\") ||\n\t\t\t!PC_ExpectTokenType(source, TT_NUMBER, 0, &token))\n\t\t{\n\t\t\tBotFreeReplyChat(replychatlist);\n\t\t\tFreeSource(source);\n\t\t\treturn NULL;\n\t\t} //end if\n\t\treplychat->priority = token.floatvalue;\n\t\t//read the leading {\n\t\tif (!PC_ExpectTokenString(source, \"{\"))\n\t\t{\n\t\t\tBotFreeReplyChat(replychatlist);\n\t\t\tFreeSource(source);\n\t\t\treturn NULL;\n\t\t} //end if\n\t\treplychat->numchatmessages = 0;\n\t\t//while the trailing } is not found\n\t\twhile(!PC_CheckTokenString(source, \"}\"))\n\t\t{\n\t\t\tif (!BotLoadChatMessage(source, chatmessagestring))\n\t\t\t{\n\t\t\t\tBotFreeReplyChat(replychatlist);\n\t\t\t\tFreeSource(source);\n\t\t\t\treturn NULL;\n\t\t\t} //end if\n\t\t\tchatmessage = (bot_chatmessage_t *) GetClearedHunkMemory(sizeof(bot_chatmessage_t) + (int)strlen(chatmessagestring) + 1);\n\t\t\tchatmessage->chatmessage = (char *) chatmessage + sizeof(bot_chatmessage_t);\n\t\t\tstrcpy(chatmessage->chatmessage, chatmessagestring);\n\t\t\tchatmessage->time = -2*CHATMESSAGE_RECENTTIME;\n\t\t\tchatmessage->next = replychat->firstchatmessage;\n\t\t\t//add the chat message to the reply chat\n\t\t\treplychat->firstchatmessage = chatmessage;\n\t\t\treplychat->numchatmessages++;\n\t\t} //end while\n\t} //end while\n\tFreeSource(source);\n\tbotimport.Print(PRT_MESSAGE, \"loaded %s\\n\", filename);\n\t//\n\t//BotDumpReplyChat(replychatlist);\n\tif (bot_developer)\n\t{\n\t\tBotCheckReplyChatIntegrety(replychatlist);\n\t} //end if\n\t//\n\tif (!replychatlist) botimport.Print(PRT_MESSAGE, \"no rchats\\n\");\n\t//\n\treturn replychatlist;\n} //end of the function BotLoadReplyChat\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotDumpInitialChat(bot_chat_t *chat)\n{\n\tbot_chattype_t *t;\n\tbot_chatmessage_t *m;\n\n\tLog_Write(\"{\");\n\tfor (t = chat->types; t; t = t->next)\n\t{\n\t\tLog_Write(\" type \\\"%s\\\"\", t->name);\n\t\tLog_Write(\" {\");\n\t\tLog_Write(\"  numchatmessages = %d\", t->numchatmessages);\n\t\tfor (m = t->firstchatmessage; m; m = m->next)\n\t\t{\n\t\t\tLog_Write(\"  \\\"%s\\\"\", m->chatmessage);\n\t\t} //end for\n\t\tLog_Write(\" }\");\n\t} //end for\n\tLog_Write(\"}\");\n} //end of the function BotDumpInitialChat\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nbot_chat_t *BotLoadInitialChat(char *chatfile, char *chatname)\n{\n\tint pass, foundchat, indent, size;\n\tchar *ptr = NULL;\n\tchar chatmessagestring[MAX_MESSAGE_SIZE];\n\tsource_t *source;\n\ttoken_t token;\n\tbot_chat_t *chat = NULL;\n\tbot_chattype_t *chattype = NULL;\n\tbot_chatmessage_t *chatmessage = NULL;\n#ifdef DEBUG\n\tint starttime;\n\n\tstarttime = Sys_MilliSeconds();\n#endif //DEBUG\n\t//\n\tsize = 0;\n\tfoundchat = qfalse;\n\t//a bot chat is parsed in two phases\n\tfor (pass = 0; pass < 2; pass++)\n\t{\n\t\t//allocate memory\n\t\tif (pass && size) ptr = (char *) GetClearedMemory(size);\n\t\t//load the source file\n\t\tPC_SetBaseFolder(BOTFILESBASEFOLDER);\n\t\tsource = LoadSourceFile(chatfile);\n\t\tif (!source)\n\t\t{\n\t\t\tbotimport.Print(PRT_ERROR, \"counldn't load %s\\n\", chatfile);\n\t\t\treturn NULL;\n\t\t} //end if\n\t\t//chat structure\n\t\tif (pass)\n\t\t{\n\t\t\tchat = (bot_chat_t *) ptr;\n\t\t\tptr += sizeof(bot_chat_t);\n\t\t} //end if\n\t\tsize = sizeof(bot_chat_t);\n\t\t//\n\t\twhile(PC_ReadToken(source, &token))\n\t\t{\n\t\t\tif (!strcmp(token.string, \"chat\"))\n\t\t\t{\n\t\t\t\tif (!PC_ExpectTokenType(source, TT_STRING, 0, &token))\n\t\t\t\t{\n\t\t\t\t\tFreeSource(source);\n\t\t\t\t\treturn NULL;\n\t\t\t\t} //end if\n\t\t\t\tStripDoubleQuotes(token.string);\n\t\t\t\t//after the chat name we expect a opening brace\n\t\t\t\tif (!PC_ExpectTokenString(source, \"{\"))\n\t\t\t\t{\n\t\t\t\t\tFreeSource(source);\n\t\t\t\t\treturn NULL;\n\t\t\t\t} //end if\n\t\t\t\t//if the chat name is found\n\t\t\t\tif (!Q_stricmp(token.string, chatname))\n\t\t\t\t{\n\t\t\t\t\tfoundchat = qtrue;\n\t\t\t\t\t//read the chat types\n\t\t\t\t\twhile(1)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (!PC_ExpectAnyToken(source, &token))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tFreeSource(source);\n\t\t\t\t\t\t\treturn NULL;\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t\tif (!strcmp(token.string, \"}\")) break;\n\t\t\t\t\t\tif (strcmp(token.string, \"type\"))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tSourceError(source, \"expected type found %s\\n\", token.string);\n\t\t\t\t\t\t\tFreeSource(source);\n\t\t\t\t\t\t\treturn NULL;\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t\t//expect the chat type name\n\t\t\t\t\t\tif (!PC_ExpectTokenType(source, TT_STRING, 0, &token) ||\n\t\t\t\t\t\t\t!PC_ExpectTokenString(source, \"{\"))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tFreeSource(source);\n\t\t\t\t\t\t\treturn NULL;\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t\tStripDoubleQuotes(token.string);\n\t\t\t\t\t\tif (pass)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tchattype = (bot_chattype_t *) ptr;\n\t\t\t\t\t\t\tstrncpy(chattype->name, token.string, MAX_CHATTYPE_NAME);\n\t\t\t\t\t\t\tchattype->firstchatmessage = NULL;\n\t\t\t\t\t\t\t//add the chat type to the chat\n\t\t\t\t\t\t\tchattype->next = chat->types;\n\t\t\t\t\t\t\tchat->types = chattype;\n\t\t\t\t\t\t\t//\n\t\t\t\t\t\t\tptr += sizeof(bot_chattype_t);\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t\tsize += sizeof(bot_chattype_t);\n\t\t\t\t\t\t//read the chat messages\n\t\t\t\t\t\twhile(!PC_CheckTokenString(source, \"}\"))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (!BotLoadChatMessage(source, chatmessagestring))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tFreeSource(source);\n\t\t\t\t\t\t\t\treturn NULL;\n\t\t\t\t\t\t\t} //end if\n\t\t\t\t\t\t\tif (pass)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tchatmessage = (bot_chatmessage_t *) ptr;\n\t\t\t\t\t\t\t\tchatmessage->time = -2*CHATMESSAGE_RECENTTIME;\n\t\t\t\t\t\t\t\t//put the chat message in the list\n\t\t\t\t\t\t\t\tchatmessage->next = chattype->firstchatmessage;\n\t\t\t\t\t\t\t\tchattype->firstchatmessage = chatmessage;\n\t\t\t\t\t\t\t\t//store the chat message\n\t\t\t\t\t\t\t\tptr += sizeof(bot_chatmessage_t);\n\t\t\t\t\t\t\t\tchatmessage->chatmessage = ptr;\n\t\t\t\t\t\t\t\tstrcpy(chatmessage->chatmessage, chatmessagestring);\n\t\t\t\t\t\t\t\tptr += (int)strlen(chatmessagestring) + 1;\n\t\t\t\t\t\t\t\t//the number of chat messages increased\n\t\t\t\t\t\t\t\tchattype->numchatmessages++;\n\t\t\t\t\t\t\t} //end if\n\t\t\t\t\t\t\tsize += sizeof(bot_chatmessage_t) + (int)strlen(chatmessagestring) + 1;\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t} //end while\n\t\t\t\t} //end if\n\t\t\t\telse //skip the bot chat\n\t\t\t\t{\n\t\t\t\t\tindent = 1;\n\t\t\t\t\twhile(indent)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (!PC_ExpectAnyToken(source, &token))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tFreeSource(source);\n\t\t\t\t\t\t\treturn NULL;\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t\tif (!strcmp(token.string, \"{\")) indent++;\n\t\t\t\t\t\telse if (!strcmp(token.string, \"}\")) indent--;\n\t\t\t\t\t} //end while\n\t\t\t\t} //end else\n\t\t\t} //end if\n\t\t\telse\n\t\t\t{\n\t\t\t\tSourceError(source, \"unknown definition %s\\n\", token.string);\n\t\t\t\tFreeSource(source);\n\t\t\t\treturn NULL;\n\t\t\t} //end else\n\t\t} //end while\n\t\t//free the source\n\t\tFreeSource(source);\n\t\t//if the requested character is not found\n\t\tif (!foundchat)\n\t\t{\n\t\t\tbotimport.Print(PRT_ERROR, \"couldn't find chat %s in %s\\n\", chatname, chatfile);\n\t\t\treturn NULL;\n\t\t} //end if\n\t} //end for\n\t//\n\tbotimport.Print(PRT_MESSAGE, \"loaded %s from %s\\n\", chatname, chatfile);\n\t//\n\t//BotDumpInitialChat(chat);\n\tif (bot_developer)\n\t{\n\t\tBotCheckInitialChatIntegrety(chat);\n\t} //end if\n#ifdef DEBUG\n\tbotimport.Print(PRT_MESSAGE, \"initial chats loaded in %d msec\\n\", Sys_MilliSeconds() - starttime);\n#endif //DEBUG\n\t//character was read succesfully\n\treturn chat;\n} //end of the function BotLoadInitialChat\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotFreeChatFile(int chatstate)\n{\n\tbot_chatstate_t *cs;\n\n\tcs = BotChatStateFromHandle(chatstate);\n\tif (!cs) return;\n\tif (cs->chat) FreeMemory(cs->chat);\n\tcs->chat = NULL;\n} //end of the function BotFreeChatFile\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotLoadChatFile(int chatstate, char *chatfile, char *chatname)\n{\n\tbot_chatstate_t *cs;\n\tint n, avail = 0;\n\n\tcs = BotChatStateFromHandle(chatstate);\n\tif (!cs) return BLERR_CANNOTLOADICHAT;\n\tBotFreeChatFile(chatstate);\n\n\tif (!LibVarGetValue(\"bot_reloadcharacters\"))\n\t{\n\t\tavail = -1;\n\t\tfor( n = 0; n < MAX_CLIENTS; n++ ) {\n\t\t\tif( !ichatdata[n] ) {\n\t\t\t\tif( avail == -1 ) {\n\t\t\t\t\tavail = n;\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif( strcmp( chatfile, ichatdata[n]->filename ) != 0 ) { \n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif( strcmp( chatname, ichatdata[n]->chatname ) != 0 ) { \n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tcs->chat = ichatdata[n]->chat;\n\t\t//\t\tbotimport.Print( PRT_MESSAGE, \"retained %s from %s\\n\", chatname, chatfile );\n\t\t\treturn BLERR_NOERROR;\n\t\t}\n\n\t\tif( avail == -1 ) {\n\t\t\tbotimport.Print(PRT_FATAL, \"ichatdata table full; couldn't load chat %s from %s\\n\", chatname, chatfile);\n\t\t\treturn BLERR_CANNOTLOADICHAT;\n\t\t}\n\t}\n\n\tcs->chat = BotLoadInitialChat(chatfile, chatname);\n\tif (!cs->chat)\n\t{\n\t\tbotimport.Print(PRT_FATAL, \"couldn't load chat %s from %s\\n\", chatname, chatfile);\n\t\treturn BLERR_CANNOTLOADICHAT;\n\t} //end if\n\tif (!LibVarGetValue(\"bot_reloadcharacters\"))\n\t{\n\t\tichatdata[avail] = (bot_ichatdata_t*) GetClearedMemory( sizeof(bot_ichatdata_t) );\n\t\tichatdata[avail]->chat = cs->chat;\n\t\tQ_strncpyz( ichatdata[avail]->chatname, chatname, sizeof(ichatdata[avail]->chatname) );\n\t\tQ_strncpyz( ichatdata[avail]->filename, chatfile, sizeof(ichatdata[avail]->filename) );\n\t} //end if\n\n\treturn BLERR_NOERROR;\n} //end of the function BotLoadChatFile\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotExpandChatMessage(char *outmessage, char *message, unsigned long mcontext,\n\t\t\t\t\t\t\t bot_match_t *match, unsigned long vcontext, int reply)\n{\n\tint num, len, i, expansion;\n\tchar *outputbuf, *ptr, *msgptr;\n\tchar temp[MAX_MESSAGE_SIZE];\n\n\texpansion = qfalse;\n\tmsgptr = message;\n\toutputbuf = outmessage;\n\tlen = 0;\n\t//\n\twhile(*msgptr)\n\t{\n\t\tif (*msgptr == ESCAPE_CHAR)\n\t\t{\n\t\t\tmsgptr++;\n\t\t\tswitch(*msgptr)\n\t\t\t{\n\t\t\t\tcase 'v': //variable\n\t\t\t\t{\n\t\t\t\t\tmsgptr++;\n\t\t\t\t\tnum = 0;\n\t\t\t\t\twhile(*msgptr && *msgptr != ESCAPE_CHAR)\n\t\t\t\t\t{\n\t\t\t\t\t\tnum = num * 10 + (*msgptr++) - '0';\n\t\t\t\t\t} //end while\n\t\t\t\t\t//step over the trailing escape char\n\t\t\t\t\tif (*msgptr) msgptr++;\n\t\t\t\t\tif (num > MAX_MATCHVARIABLES)\n\t\t\t\t\t{\n\t\t\t\t\t\tbotimport.Print(PRT_ERROR, \"BotConstructChat: message %s variable %d out of range\\n\", message, num);\n\t\t\t\t\t\treturn qfalse;\n\t\t\t\t\t} //end if\n\t\t\t\t\tif (match->variables[num].offset >= 0)\n\t\t\t\t\t{\n\t\t\t\t\t        assert( match->variables[num].offset >= 0 ); // bk001204\n\t\t\t\t\t\tptr = &match->string[ (int) match->variables[num].offset];\n\t\t\t\t\t\tfor (i = 0; i < match->variables[num].length; i++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttemp[i] = ptr[i];\n\t\t\t\t\t\t} //end for\n\t\t\t\t\t\ttemp[i] = 0;\n\t\t\t\t\t\t//if it's a reply message\n\t\t\t\t\t\tif (reply)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t//replace the reply synonyms in the variables\n\t\t\t\t\t\t\tBotReplaceReplySynonyms(temp, vcontext);\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t\telse \n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t//replace synonyms in the variable context\n\t\t\t\t\t\t\tBotReplaceSynonyms(temp, vcontext);\n\t\t\t\t\t\t} //end else\n\t\t\t\t\t\t//\n\t\t\t\t\t\tif (len + (int)strlen(temp) >= MAX_MESSAGE_SIZE)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tbotimport.Print(PRT_ERROR, \"BotConstructChat: message %s too long\\n\", message);\n\t\t\t\t\t\t\treturn qfalse;\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t\tstrcpy(&outputbuf[len], temp);\n\t\t\t\t\t\tlen += (int)strlen(temp);\n\t\t\t\t\t} //end if\n\t\t\t\t\tbreak;\n\t\t\t\t} //end case\n\t\t\t\tcase 'r': //random\n\t\t\t\t{\n\t\t\t\t\tmsgptr++;\n\t\t\t\t\tfor (i = 0; (*msgptr && *msgptr != ESCAPE_CHAR); i++)\n\t\t\t\t\t{\n\t\t\t\t\t\ttemp[i] = *msgptr++;\n\t\t\t\t\t} //end while\n\t\t\t\t\ttemp[i] = '\\0';\n\t\t\t\t\t//step over the trailing escape char\n\t\t\t\t\tif (*msgptr) msgptr++;\n\t\t\t\t\t//find the random keyword\n\t\t\t\t\tptr = RandomString(temp);\n\t\t\t\t\tif (!ptr)\n\t\t\t\t\t{\n\t\t\t\t\t\tbotimport.Print(PRT_ERROR, \"BotConstructChat: unknown random string %s\\n\", temp);\n\t\t\t\t\t\treturn qfalse;\n\t\t\t\t\t} //end if\n\t\t\t\t\tif (len + (int)strlen(ptr) >= MAX_MESSAGE_SIZE)\n\t\t\t\t\t{\n\t\t\t\t\t\tbotimport.Print(PRT_ERROR, \"BotConstructChat: message \\\"%s\\\" too long\\n\", message);\n\t\t\t\t\t\treturn qfalse;\n\t\t\t\t\t} //end if\n\t\t\t\t\tstrcpy(&outputbuf[len], ptr);\n\t\t\t\t\tlen += (int)strlen(ptr);\n\t\t\t\t\texpansion = qtrue;\n\t\t\t\t\tbreak;\n\t\t\t\t} //end case\n\t\t\t\tdefault:\n\t\t\t\t{\n\t\t\t\t\tbotimport.Print(PRT_FATAL, \"BotConstructChat: message \\\"%s\\\" invalid escape char\\n\", message);\n\t\t\t\t\tbreak;\n\t\t\t\t} //end default\n\t\t\t} //end switch\n\t\t} //end if\n\t\telse\n\t\t{\n\t\t\toutputbuf[len++] = *msgptr++;\n\t\t\tif (len >= MAX_MESSAGE_SIZE)\n\t\t\t{\n\t\t\t\tbotimport.Print(PRT_ERROR, \"BotConstructChat: message \\\"%s\\\" too long\\n\", message);\n\t\t\t\tbreak;\n\t\t\t} //end if\n\t\t} //end else\n\t} //end while\n\toutputbuf[len] = '\\0';\n\t//replace synonyms weighted in the message context\n\tBotReplaceWeightedSynonyms(outputbuf, mcontext);\n\t//return true if a random was expanded\n\treturn expansion;\n} //end of the function BotExpandChatMessage\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotConstructChatMessage(bot_chatstate_t *chatstate, char *message, unsigned long mcontext,\n\t\t\t\t\t\t\t bot_match_t *match, unsigned long vcontext, int reply)\n{\n\tint i;\n\tchar srcmessage[MAX_MESSAGE_SIZE];\n\n\tstrcpy(srcmessage, message);\n\tfor (i = 0; i < 10; i++)\n\t{\n\t\tif (!BotExpandChatMessage(chatstate->chatmessage, srcmessage, mcontext, match, vcontext, reply))\n\t\t{\n\t\t\tbreak;\n\t\t} //end if\n\t\tstrcpy(srcmessage, chatstate->chatmessage);\n\t} //end for\n\tif (i >= 10)\n\t{\n\t\tbotimport.Print(PRT_WARNING, \"too many expansions in chat message\\n\");\n\t\tbotimport.Print(PRT_WARNING, \"%s\\n\", chatstate->chatmessage);\n\t} //end if\n} //end of the function BotConstructChatMessage\n//===========================================================================\n// randomly chooses one of the chat message of the given type\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nchar *BotChooseInitialChatMessage(bot_chatstate_t *cs, char *type)\n{\n\tint n, numchatmessages;\n\tfloat besttime;\n\tbot_chattype_t *t;\n\tbot_chatmessage_t *m, *bestchatmessage;\n\tbot_chat_t *chat;\n\n\tchat = cs->chat;\n\tfor (t = chat->types; t; t = t->next)\n\t{\n\t\tif (!Q_stricmp(t->name, type))\n\t\t{\n\t\t\tnumchatmessages = 0;\n\t\t\tfor (m = t->firstchatmessage; m; m = m->next)\n\t\t\t{\n\t\t\t\tif (m->time > AAS_Time()) continue;\n\t\t\t\tnumchatmessages++;\n\t\t\t} //end if\n\t\t\t//if all chat messages have been used recently\n\t\t\tif (numchatmessages <= 0)\n\t\t\t{\n\t\t\t\tbesttime = 0;\n\t\t\t\tbestchatmessage = NULL;\n\t\t\t\tfor (m = t->firstchatmessage; m; m = m->next)\n\t\t\t\t{\n\t\t\t\t\tif (!besttime || m->time < besttime)\n\t\t\t\t\t{\n\t\t\t\t\t\tbestchatmessage = m;\n\t\t\t\t\t\tbesttime = m->time;\n\t\t\t\t\t} //end if\n\t\t\t\t} //end for\n\t\t\t\tif (bestchatmessage) return bestchatmessage->chatmessage;\n\t\t\t} //end if\n\t\t\telse //choose a chat message randomly\n\t\t\t{\n\t\t\t\tn = random() * numchatmessages;\n\t\t\t\tfor (m = t->firstchatmessage; m; m = m->next)\n\t\t\t\t{\n\t\t\t\t\tif (m->time > AAS_Time()) continue;\n\t\t\t\t\tif (--n < 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tm->time = AAS_Time() + CHATMESSAGE_RECENTTIME;\n\t\t\t\t\t\treturn m->chatmessage;\n\t\t\t\t\t} //end if\n\t\t\t\t} //end for\n\t\t\t} //end else\n\t\t\treturn NULL;\n\t\t} //end if\n\t} //end for\n\treturn NULL;\n} //end of the function BotChooseInitialChatMessage\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotNumInitialChats(int chatstate, char *type)\n{\n\tbot_chatstate_t *cs;\n\tbot_chattype_t *t;\n\n\tcs = BotChatStateFromHandle(chatstate);\n\tif (!cs) return 0;\n\n\tfor (t = cs->chat->types; t; t = t->next)\n\t{\n\t\tif (!Q_stricmp(t->name, type))\n\t\t{\n\t\t\tif (LibVarGetValue(\"bot_testichat\")) {\n\t\t\t\tbotimport.Print(PRT_MESSAGE, \"%s has %d chat lines\\n\", type, t->numchatmessages);\n\t\t\t\tbotimport.Print(PRT_MESSAGE, \"-------------------\\n\");\n\t\t\t}\n\t\t\treturn t->numchatmessages;\n\t\t} //end if\n\t} //end for\n\treturn 0;\n} //end of the function BotNumInitialChats\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotInitialChat(int chatstate, char *type, int mcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7)\n{\n\tchar *message;\n\tint index;\n\tbot_match_t match;\n\tbot_chatstate_t *cs;\n\n\tcs = BotChatStateFromHandle(chatstate);\n\tif (!cs) return;\n\t//if no chat file is loaded\n\tif (!cs->chat) return;\n\t//choose a chat message randomly of the given type\n\tmessage = BotChooseInitialChatMessage(cs, type);\n\t//if there's no message of the given type\n\tif (!message)\n\t{\n#ifdef DEBUG\n\t\tbotimport.Print(PRT_MESSAGE, \"no chat messages of type %s\\n\", type);\n#endif //DEBUG\n\t\treturn;\n\t} //end if\n\t//\n\tCom_Memset(&match, 0, sizeof(match));\n\tindex = 0;\n\tif( var0 ) {\n\t\tstrcat(match.string, var0);\n\t\tmatch.variables[0].offset = index;\n\t\tmatch.variables[0].length = (int)strlen(var0);\n\t\tindex += (int)strlen(var0);\n\t}\n\tif( var1 ) {\n\t\tstrcat(match.string, var1);\n\t\tmatch.variables[1].offset = index;\n\t\tmatch.variables[1].length = (int)strlen(var1);\n\t\tindex += (int)strlen(var1);\n\t}\n\tif( var2 ) {\n\t\tstrcat(match.string, var2);\n\t\tmatch.variables[2].offset = index;\n\t\tmatch.variables[2].length = (int)strlen(var2);\n\t\tindex += (int)strlen(var2);\n\t}\n\tif( var3 ) {\n\t\tstrcat(match.string, var3);\n\t\tmatch.variables[3].offset = index;\n\t\tmatch.variables[3].length = (int)strlen(var3);\n\t\tindex += (int)strlen(var3);\n\t}\n\tif( var4 ) {\n\t\tstrcat(match.string, var4);\n\t\tmatch.variables[4].offset = index;\n\t\tmatch.variables[4].length = (int)strlen(var4);\n\t\tindex += (int)strlen(var4);\n\t}\n\tif( var5 ) {\n\t\tstrcat(match.string, var5);\n\t\tmatch.variables[5].offset = index;\n\t\tmatch.variables[5].length = (int)strlen(var5);\n\t\tindex += (int)strlen(var5);\n\t}\n\tif( var6 ) {\n\t\tstrcat(match.string, var6);\n\t\tmatch.variables[6].offset = index;\n\t\tmatch.variables[6].length = (int)strlen(var6);\n\t\tindex += (int)strlen(var6);\n\t}\n\tif( var7 ) {\n\t\tstrcat(match.string, var7);\n\t\tmatch.variables[7].offset = index;\n\t\tmatch.variables[7].length = (int)strlen(var7);\n\t\tindex += (int)strlen(var7);\n\t}\n \t//\n\tBotConstructChatMessage(cs, message, mcontext, &match, 0, qfalse);\n} //end of the function BotInitialChat\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotPrintReplyChatKeys(bot_replychat_t *replychat)\n{\n\tbot_replychatkey_t *key;\n\tbot_matchpiece_t *mp;\n\n\tbotimport.Print(PRT_MESSAGE, \"[\");\n\tfor (key = replychat->keys; key; key = key->next)\n\t{\n\t\tif (key->flags & RCKFL_AND) botimport.Print(PRT_MESSAGE, \"&\");\n\t\telse if (key->flags & RCKFL_NOT) botimport.Print(PRT_MESSAGE, \"!\");\n\t\t//\n\t\tif (key->flags & RCKFL_NAME) botimport.Print(PRT_MESSAGE, \"name\");\n\t\telse if (key->flags & RCKFL_GENDERFEMALE) botimport.Print(PRT_MESSAGE, \"female\");\n\t\telse if (key->flags & RCKFL_GENDERMALE) botimport.Print(PRT_MESSAGE, \"male\");\n\t\telse if (key->flags & RCKFL_GENDERLESS) botimport.Print(PRT_MESSAGE, \"it\");\n\t\telse if (key->flags & RCKFL_VARIABLES)\n\t\t{\n\t\t\tbotimport.Print(PRT_MESSAGE, \"(\");\n\t\t\tfor (mp = key->match; mp; mp = mp->next)\n\t\t\t{\n\t\t\t\tif (mp->type == MT_STRING) botimport.Print(PRT_MESSAGE, \"\\\"%s\\\"\", mp->firststring->string);\n\t\t\t\telse botimport.Print(PRT_MESSAGE, \"%d\", mp->variable);\n\t\t\t\tif (mp->next) botimport.Print(PRT_MESSAGE, \", \");\n\t\t\t} //end for\n\t\t\tbotimport.Print(PRT_MESSAGE, \")\");\n\t\t} //end if\n\t\telse if (key->flags & RCKFL_STRING)\n\t\t{\n\t\t\tbotimport.Print(PRT_MESSAGE, \"\\\"%s\\\"\", key->string);\n\t\t} //end if\n\t\tif (key->next) botimport.Print(PRT_MESSAGE, \", \");\n\t\telse botimport.Print(PRT_MESSAGE, \"] = %1.0f\\n\", replychat->priority);\n\t} //end for\n\tbotimport.Print(PRT_MESSAGE, \"{\\n\");\n} //end of the function BotPrintReplyChatKeys\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotReplyChat(int chatstate, char *message, int mcontext, int vcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7)\n{\n\tbot_replychat_t *rchat, *bestrchat;\n\tbot_replychatkey_t *key;\n\tbot_chatmessage_t *m, *bestchatmessage;\n\tbot_match_t match, bestmatch;\n\tint bestpriority, num, found, res, numchatmessages, index;\n\tbot_chatstate_t *cs;\n\n\tcs = BotChatStateFromHandle(chatstate);\n\tif (!cs) return qfalse;\n\tCom_Memset(&match, 0, sizeof(bot_match_t));\n\tstrcpy(match.string, message);\n\tbestpriority = -1;\n\tbestchatmessage = NULL;\n\tbestrchat = NULL;\n\t//go through all the reply chats\n\tfor (rchat = replychats; rchat; rchat = rchat->next)\n\t{\n\t\tfound = qfalse;\n\t\tfor (key = rchat->keys; key; key = key->next)\n\t\t{\n\t\t\tres = qfalse;\n\t\t\t//get the match result\n\t\t\tif (key->flags & RCKFL_NAME) res = (StringContains(message, cs->name, qfalse) != -1);\n\t\t\telse if (key->flags & RCKFL_BOTNAMES) res = (StringContains(key->string, cs->name, qfalse) != -1);\n\t\t\telse if (key->flags & RCKFL_GENDERFEMALE) res = (cs->gender == CHAT_GENDERFEMALE);\n\t\t\telse if (key->flags & RCKFL_GENDERMALE) res = (cs->gender == CHAT_GENDERMALE);\n\t\t\telse if (key->flags & RCKFL_GENDERLESS) res = (cs->gender == CHAT_GENDERLESS);\n\t\t\telse if (key->flags & RCKFL_VARIABLES) res = StringsMatch(key->match, &match);\n\t\t\telse if (key->flags & RCKFL_STRING) res = (StringContainsWord(message, key->string, qfalse) != NULL);\n\t\t\t//if the key must be present\n\t\t\tif (key->flags & RCKFL_AND)\n\t\t\t{\n\t\t\t\tif (!res)\n\t\t\t\t{\n\t\t\t\t\tfound = qfalse;\n\t\t\t\t\tbreak;\n\t\t\t\t} //end if\n\t\t\t} //end else if\n\t\t\t//if the key must be absent\n\t\t\telse if (key->flags & RCKFL_NOT)\n\t\t\t{\n\t\t\t\tif (res)\n\t\t\t\t{\n\t\t\t\t\tfound = qfalse;\n\t\t\t\t\tbreak;\n\t\t\t\t} //end if\n\t\t\t} //end if\n\t\t\telse if (res)\n\t\t\t{\n\t\t\t\tfound = qtrue;\n\t\t\t} //end else\n\t\t} //end for\n\t\t//\n\t\tif (found)\n\t\t{\n\t\t\tif (rchat->priority > bestpriority)\n\t\t\t{\n\t\t\t\tnumchatmessages = 0;\n\t\t\t\tfor (m = rchat->firstchatmessage; m; m = m->next)\n\t\t\t\t{\n\t\t\t\t\tif (m->time > AAS_Time()) continue;\n\t\t\t\t\tnumchatmessages++;\n\t\t\t\t} //end if\n\t\t\t\tnum = random() * numchatmessages;\n\t\t\t\tfor (m = rchat->firstchatmessage; m; m = m->next)\n\t\t\t\t{\n\t\t\t\t\tif (--num < 0) break;\n\t\t\t\t\tif (m->time > AAS_Time()) continue;\n\t\t\t\t} //end for\n\t\t\t\t//if the reply chat has a message\n\t\t\t\tif (m)\n\t\t\t\t{\n\t\t\t\t\tCom_Memcpy(&bestmatch, &match, sizeof(bot_match_t));\n\t\t\t\t\tbestchatmessage = m;\n\t\t\t\t\tbestrchat = rchat;\n\t\t\t\t\tbestpriority = rchat->priority;\n\t\t\t\t} //end if\n\t\t\t} //end if\n\t\t} //end if\n\t} //end for\n\tif (bestchatmessage)\n\t{\n\t\tindex = (int)strlen(bestmatch.string);\n\t\tif( var0 ) {\n\t\t\tstrcat(bestmatch.string, var0);\n\t\t\tbestmatch.variables[0].offset = index;\n\t\t\tbestmatch.variables[0].length = (int)strlen(var0);\n\t\t\tindex += (int)strlen(var0);\n\t\t}\n\t\tif( var1 ) {\n\t\t\tstrcat(bestmatch.string, var1);\n\t\t\tbestmatch.variables[1].offset = index;\n\t\t\tbestmatch.variables[1].length = (int)strlen(var1);\n\t\t\tindex += (int)strlen(var1);\n\t\t}\n\t\tif( var2 ) {\n\t\t\tstrcat(bestmatch.string, var2);\n\t\t\tbestmatch.variables[2].offset = index;\n\t\t\tbestmatch.variables[2].length = (int)strlen(var2);\n\t\t\tindex += (int)strlen(var2);\n\t\t}\n\t\tif( var3 ) {\n\t\t\tstrcat(bestmatch.string, var3);\n\t\t\tbestmatch.variables[3].offset = index;\n\t\t\tbestmatch.variables[3].length = (int)strlen(var3);\n\t\t\tindex += (int)strlen(var3);\n\t\t}\n\t\tif( var4 ) {\n\t\t\tstrcat(bestmatch.string, var4);\n\t\t\tbestmatch.variables[4].offset = index;\n\t\t\tbestmatch.variables[4].length = (int)strlen(var4);\n\t\t\tindex += (int)strlen(var4);\n\t\t}\n\t\tif( var5 ) {\n\t\t\tstrcat(bestmatch.string, var5);\n\t\t\tbestmatch.variables[5].offset = index;\n\t\t\tbestmatch.variables[5].length = (int)strlen(var5);\n\t\t\tindex += (int)strlen(var5);\n\t\t}\n\t\tif( var6 ) {\n\t\t\tstrcat(bestmatch.string, var6);\n\t\t\tbestmatch.variables[6].offset = index;\n\t\t\tbestmatch.variables[6].length = (int)strlen(var6);\n\t\t\tindex += (int)strlen(var6);\n\t\t}\n\t\tif( var7 ) {\n\t\t\tstrcat(bestmatch.string, var7);\n\t\t\tbestmatch.variables[7].offset = index;\n\t\t\tbestmatch.variables[7].length = (int)strlen(var7);\n\t\t\tindex += (int)strlen(var7);\n\t\t}\n\t\tif (LibVarGetValue(\"bot_testrchat\"))\n\t\t{\n\t\t\tfor (m = bestrchat->firstchatmessage; m; m = m->next)\n\t\t\t{\n\t\t\t\tBotConstructChatMessage(cs, m->chatmessage, mcontext, &bestmatch, vcontext, qtrue);\n\t\t\t\tBotRemoveTildes(cs->chatmessage);\n\t\t\t\tbotimport.Print(PRT_MESSAGE, \"%s\\n\", cs->chatmessage);\n\t\t\t} //end if\n\t\t} //end if\n\t\telse\n\t\t{\n\t\t\tbestchatmessage->time = AAS_Time() + CHATMESSAGE_RECENTTIME;\n\t\t\tBotConstructChatMessage(cs, bestchatmessage->chatmessage, mcontext, &bestmatch, vcontext, qtrue);\n\t\t} //end else\n\t\treturn qtrue;\n\t} //end if\n\treturn qfalse;\n} //end of the function BotReplyChat\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotChatLength(int chatstate)\n{\n\tbot_chatstate_t *cs;\n\n\tcs = BotChatStateFromHandle(chatstate);\n\tif (!cs) return 0;\n\treturn (int)strlen(cs->chatmessage);\n} //end of the function BotChatLength\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotEnterChat(int chatstate, int clientto, int sendto)\n{\n\tbot_chatstate_t *cs;\n\n\tcs = BotChatStateFromHandle(chatstate);\n\tif (!cs) return;\n\n\tif ((int)strlen(cs->chatmessage))\n\t{\n\t\tBotRemoveTildes(cs->chatmessage);\n\t\tif (LibVarGetValue(\"bot_testichat\")) {\n\t\t\tbotimport.Print(PRT_MESSAGE, \"%s\\n\", cs->chatmessage);\n\t\t}\n\t\telse {\n\t\t\tswitch(sendto) {\n\t\t\t\tcase CHAT_TEAM:\n\t\t\t\t\tEA_Command(cs->client, va(\"say_team %s\", cs->chatmessage));\n\t\t\t\t\tbreak;\n\t\t\t\tcase CHAT_TELL:\n\t\t\t\t\tEA_Command(cs->client, va(\"tell %d %s\", clientto, cs->chatmessage));\n\t\t\t\t\tbreak;\n\t\t\t\tdefault: //CHAT_ALL\n\t\t\t\t\tEA_Command(cs->client, va(\"say %s\", cs->chatmessage));\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\t//clear the chat message from the state\n\t\tstrcpy(cs->chatmessage, \"\");\n\t} //end if\n} //end of the function BotEnterChat\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotGetChatMessage(int chatstate, char *buf, int size)\n{\n\tbot_chatstate_t *cs;\n\n\tcs = BotChatStateFromHandle(chatstate);\n\tif (!cs) return;\n\n\tBotRemoveTildes(cs->chatmessage);\n\tstrncpy(buf, cs->chatmessage, size-1);\n\tbuf[size-1] = '\\0';\n\t//clear the chat message from the state\n\tstrcpy(cs->chatmessage, \"\");\n} //end of the function BotGetChatMessage\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotSetChatGender(int chatstate, int gender)\n{\n\tbot_chatstate_t *cs;\n\n\tcs = BotChatStateFromHandle(chatstate);\n\tif (!cs) return;\n\tswitch(gender)\n\t{\n\t\tcase CHAT_GENDERFEMALE: cs->gender = CHAT_GENDERFEMALE; break;\n\t\tcase CHAT_GENDERMALE: cs->gender = CHAT_GENDERMALE; break;\n\t\tdefault: cs->gender = CHAT_GENDERLESS; break;\n\t} //end switch\n} //end of the function BotSetChatGender\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotSetChatName(int chatstate, char *name, int client)\n{\n\tbot_chatstate_t *cs;\n\n\tcs = BotChatStateFromHandle(chatstate);\n\tif (!cs) return;\n\tcs->client = client;\n\tCom_Memset(cs->name, 0, sizeof(cs->name));\n\tstrncpy(cs->name, name, sizeof(cs->name));\n\tcs->name[sizeof(cs->name)-1] = '\\0';\n} //end of the function BotSetChatName\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotResetChatAI(void)\n{\n\tbot_replychat_t *rchat;\n\tbot_chatmessage_t *m;\n\n\tfor (rchat = replychats; rchat; rchat = rchat->next)\n\t{\n\t\tfor (m = rchat->firstchatmessage; m; m = m->next)\n\t\t{\n\t\t\tm->time = 0;\n\t\t} //end for\n\t} //end for\n} //end of the function BotResetChatAI\n//========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//========================================================================\nint BotAllocChatState(void)\n{\n\tint i;\n\n\tfor (i = 1; i <= MAX_CLIENTS; i++)\n\t{\n\t\tif (!botchatstates[i])\n\t\t{\n\t\t\tbotchatstates[i] = (bot_chatstate_t*) GetClearedMemory(sizeof(bot_chatstate_t));\n\t\t\treturn i;\n\t\t} //end if\n\t} //end for\n\treturn 0;\n} //end of the function BotAllocChatState\n//========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//========================================================================\nvoid BotFreeChatState(int handle)\n{\n\tbot_chatstate_t *cs;\n\tbot_consolemessage_t m;\n\tint h;\n\n\tif (handle <= 0 || handle > MAX_CLIENTS)\n\t{\n\t\tbotimport.Print(PRT_FATAL, \"chat state handle %d out of range\\n\", handle);\n\t\treturn;\n\t} //end if\n\tif (!botchatstates[handle])\n\t{\n\t\tbotimport.Print(PRT_FATAL, \"invalid chat state %d\\n\", handle);\n\t\treturn;\n\t} //end if\n\tcs = botchatstates[handle];\n\tif (LibVarGetValue(\"bot_reloadcharacters\"))\n\t{\n\t\tBotFreeChatFile(handle);\n\t} //end if\n\t//free all the console messages left in the chat state\n\tfor (h = BotNextConsoleMessage(handle, &m); h; h = BotNextConsoleMessage(handle, &m))\n\t{\n\t\t//remove the console message\n\t\tBotRemoveConsoleMessage(handle, h);\n\t} //end for\n\tFreeMemory(botchatstates[handle]);\n\tbotchatstates[handle] = NULL;\n} //end of the function BotFreeChatState\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotSetupChatAI(void)\n{\n\tchar *file;\n\n#ifdef DEBUG\n\tint starttime = Sys_MilliSeconds();\n#endif //DEBUG\n\n\tfile = LibVarString(\"synfile\", \"syn.c\");\n\tsynonyms = BotLoadSynonyms(file);\n\tfile = LibVarString(\"rndfile\", \"rnd.c\");\n\trandomstrings = BotLoadRandomStrings(file);\n\tfile = LibVarString(\"matchfile\", \"match.c\");\n\tmatchtemplates = BotLoadMatchTemplates(file);\n\t//\n\tif (!LibVarValue(\"nochat\", \"0\"))\n\t{\n\t\tfile = LibVarString(\"rchatfile\", \"rchat.c\");\n\t\treplychats = BotLoadReplyChat(file);\n\t} //end if\n\n\tInitConsoleMessageHeap();\n\n#ifdef DEBUG\n\tbotimport.Print(PRT_MESSAGE, \"setup chat AI %d msec\\n\", Sys_MilliSeconds() - starttime);\n#endif //DEBUG\n\treturn BLERR_NOERROR;\n} //end of the function BotSetupChatAI\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotShutdownChatAI(void)\n{\n\tint i;\n\n\t//free all remaining chat states\n\tfor(i = 0; i < MAX_CLIENTS; i++)\n\t{\n\t\tif (botchatstates[i])\n\t\t{\n\t\t\tBotFreeChatState(i);\n\t\t} //end if\n\t} //end for\n\t//free all cached chats\n\tfor(i = 0; i < MAX_CLIENTS; i++)\n\t{\n\t\tif (ichatdata[i])\n\t\t{\n\t\t\tFreeMemory(ichatdata[i]->chat);\n\t\t\tFreeMemory(ichatdata[i]);\n\t\t\tichatdata[i] = NULL;\n\t\t} //end if\n\t} //end for\n\tif (consolemessageheap) FreeMemory(consolemessageheap);\n\tconsolemessageheap = NULL;\n\tif (matchtemplates) BotFreeMatchTemplates(matchtemplates);\n\tmatchtemplates = NULL;\n\tif (randomstrings) FreeMemory(randomstrings);\n\trandomstrings = NULL;\n\tif (synonyms) FreeMemory(synonyms);\n\tsynonyms = NULL;\n\tif (replychats) BotFreeReplyChat(replychats);\n\treplychats = NULL;\n} //end of the function BotShutdownChatAI\n"
  },
  {
    "path": "src/engine/botlib/be_ai_gen.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tbe_ai_gen.c\n *\n * desc:\t\tgenetic selection\n *\n * $Archive: /MissionPack/code/botlib/be_ai_gen.c $\n *\n *****************************************************************************/\n\n#include \"../../game/q_shared.h\"\n#include \"l_memory.h\"\n#include \"l_log.h\"\n#include \"l_utils.h\"\n#include \"l_script.h\"\n#include \"l_precomp.h\"\n#include \"l_struct.h\"\n#include \"aasfile.h\"\n#include \"../../game/botlib.h\"\n#include \"../../game/be_aas.h\"\n#include \"be_aas_funcs.h\"\n#include \"be_interface.h\"\n#include \"../../game/be_ai_gen.h\"\n\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint GeneticSelection(int numranks, float *rankings)\n{\n\tfloat sum, select;\n\tint i, index;\n\n\tsum = 0;\n\tfor (i = 0; i < numranks; i++)\n\t{\n\t\tif (rankings[i] < 0) continue;\n\t\tsum += rankings[i];\n\t} //end for\n\tif (sum > 0)\n\t{\n\t\t//select a bot where the ones with the higest rankings have\n\t\t//the highest chance of being selected\n\t\tselect = random() * sum;\n\t\tfor (i = 0; i < numranks; i++)\n\t\t{\n\t\t\tif (rankings[i] < 0) continue;\n\t\t\tsum -= rankings[i];\n\t\t\tif (sum <= 0) return i;\n\t\t} //end for\n\t} //end if\n\t//select a bot randomly\n\tindex = random() * numranks;\n\tfor (i = 0; i < numranks; i++)\n\t{\n\t\tif (rankings[index] >= 0) return index;\n\t\tindex = (index + 1) % numranks;\n\t} //end for\n\treturn 0;\n} //end of the function GeneticSelection\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint GeneticParentsAndChildSelection(int numranks, float *ranks, int *parent1, int *parent2, int *child)\n{\n\tfloat rankings[256], max;\n\tint i;\n\n\tif (numranks > 256)\n\t{\n\t\tbotimport.Print(PRT_WARNING, \"GeneticParentsAndChildSelection: too many bots\\n\");\n\t\t*parent1 = *parent2 = *child = 0;\n\t\treturn qfalse;\n\t} //end if\n\tfor (max = 0, i = 0; i < numranks; i++)\n\t{\n\t\tif (ranks[i] < 0) continue;\n\t\tmax++;\n\t} //end for\n\tif (max < 3)\n\t{\n\t\tbotimport.Print(PRT_WARNING, \"GeneticParentsAndChildSelection: too few valid bots\\n\");\n\t\t*parent1 = *parent2 = *child = 0;\n\t\treturn qfalse;\n\t} //end if\n\tCom_Memcpy(rankings, ranks, sizeof(float) * numranks);\n\t//select first parent\n\t*parent1 = GeneticSelection(numranks, rankings);\n\trankings[*parent1] = -1;\n\t//select second parent\n\t*parent2 = GeneticSelection(numranks, rankings);\n\trankings[*parent2] = -1;\n\t//reverse the rankings\n\tmax = 0;\n\tfor (i = 0; i < numranks; i++)\n\t{\n\t\tif (rankings[i] < 0) continue;\n\t\tif (rankings[i] > max) max = rankings[i];\n\t} //end for\n\tfor (i = 0; i < numranks; i++)\n\t{\n\t\tif (rankings[i] < 0) continue;\n\t\trankings[i] = max - rankings[i];\n\t} //end for\n\t//select child\n\t*child = GeneticSelection(numranks, rankings);\n\treturn qtrue;\n} //end of the function GeneticParentsAndChildSelection\n"
  },
  {
    "path": "src/engine/botlib/be_ai_goal.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tbe_ai_goal.c\n *\n * desc:\t\tgoal AI\n *\n * $Archive: /MissionPack/code/botlib/be_ai_goal.c $\n *\n *****************************************************************************/\n\n#include \"../../game/q_shared.h\"\n#include \"l_utils.h\"\n#include \"l_libvar.h\"\n#include \"l_memory.h\"\n#include \"l_log.h\"\n#include \"l_script.h\"\n#include \"l_precomp.h\"\n#include \"l_struct.h\"\n#include \"aasfile.h\"\n#include \"../../game/botlib.h\"\n#include \"../../game/be_aas.h\"\n#include \"be_aas_funcs.h\"\n#include \"be_interface.h\"\n#include \"be_ai_weight.h\"\n#include \"../../game/be_ai_goal.h\"\n#include \"../../game/be_ai_move.h\"\n\n//#define DEBUG_AI_GOAL\n#ifdef RANDOMIZE\n#define UNDECIDEDFUZZY\n#endif //RANDOMIZE\n#define DROPPEDWEIGHT\n//minimum avoid goal time\n#define AVOID_MINIMUM_TIME\t\t10\n//default avoid goal time\n#define AVOID_DEFAULT_TIME\t\t30\n//avoid dropped goal time\n#define AVOID_DROPPED_TIME\t\t10\n//\n#define TRAVELTIME_SCALE\t\t0.01\n//item flags\n#define IFL_NOTFREE\t\t\t\t1\t\t//not in free for all\n#define IFL_NOTTEAM\t\t\t\t2\t\t//not in team play\n#define IFL_NOTSINGLE\t\t\t4\t\t//not in single player\n#define IFL_NOTBOT\t\t\t\t8\t\t//bot should never go for this\n#define IFL_ROAM\t\t\t\t16\t\t//bot roam goal\n\n//location in the map \"target_location\"\ntypedef struct maplocation_s\n{\n\tvec3_t origin;\n\tint areanum;\n\tchar name[MAX_EPAIRKEY];\n\tstruct maplocation_s *next;\n} maplocation_t;\n\n//camp spots \"info_camp\"\ntypedef struct campspot_s\n{\n\tvec3_t origin;\n\tint areanum;\n\tchar name[MAX_EPAIRKEY];\n\tfloat range;\n\tfloat weight;\n\tfloat wait;\n\tfloat random;\n\tstruct campspot_s *next;\n} campspot_t;\n\n//FIXME: these are game specific\ntypedef enum {\n\tGT_FFA,\t\t\t\t// free for all\n\tGT_TOURNAMENT,\t\t// one on one tournament\n\tGT_SINGLE_PLAYER,\t// single player tournament\n\n\t//-- team games go after this --\n\n\tGT_TEAM,\t\t\t// team deathmatch\n\tGT_CTF,\t\t\t\t// capture the flag\n\tGT_MAX_GAME_TYPE\n} gametype_t;\n\ntypedef struct levelitem_s\n{\n\tint number;\t\t\t\t\t\t\t//number of the level item\n\tint iteminfo;\t\t\t\t\t\t//index into the item info\n\tint flags;\t\t\t\t\t\t\t//item flags\n\tfloat weight;\t\t\t\t\t\t//fixed roam weight\n\tvec3_t origin;\t\t\t\t\t\t//origin of the item\n\tint goalareanum;\t\t\t\t\t//area the item is in\n\tvec3_t goalorigin;\t\t\t\t\t//goal origin within the area\n\tint entitynum;\t\t\t\t\t\t//entity number\n\tfloat timeout;\t\t\t\t\t\t//item is removed after this time\n\tstruct levelitem_s *prev, *next;\n} levelitem_t;\n\ntypedef struct iteminfo_s\n{\n\tchar classname[32];\t\t\t\t\t//classname of the item\n\tchar name[MAX_STRINGFIELD];\t\t\t//name of the item\n\tchar model[MAX_STRINGFIELD];\t\t//model of the item\n\tint modelindex;\t\t\t\t\t\t//model index\n\tint type;\t\t\t\t\t\t\t//item type\n\tint index;\t\t\t\t\t\t\t//index in the inventory\n\tfloat respawntime;\t\t\t\t\t//respawn time\n\tvec3_t mins;\t\t\t\t\t\t//mins of the item\n\tvec3_t maxs;\t\t\t\t\t\t//maxs of the item\n\tint number;\t\t\t\t\t\t\t//number of the item info\n} iteminfo_t;\n\n#define ITEMINFO_OFS(x)\t(int)(intptr_t)&(((iteminfo_t *)0)->x)\n\nfielddef_t iteminfo_fields[] =\n{\n{\"name\", ITEMINFO_OFS(name), FT_STRING},\n{\"model\", ITEMINFO_OFS(model), FT_STRING},\n{\"modelindex\", ITEMINFO_OFS(modelindex), FT_INT},\n{\"type\", ITEMINFO_OFS(type), FT_INT},\n{\"index\", ITEMINFO_OFS(index), FT_INT},\n{\"respawntime\", ITEMINFO_OFS(respawntime), FT_FLOAT},\n{\"mins\", ITEMINFO_OFS(mins), FT_FLOAT|FT_ARRAY, 3},\n{\"maxs\", ITEMINFO_OFS(maxs), FT_FLOAT|FT_ARRAY, 3},\n{0, 0, 0}\n};\n\nstructdef_t iteminfo_struct =\n{\n\tsizeof(iteminfo_t), iteminfo_fields\n};\n\ntypedef struct itemconfig_s\n{\n\tint numiteminfo;\n\titeminfo_t *iteminfo;\n} itemconfig_t;\n\n//goal state\ntypedef struct bot_goalstate_s\n{\n\tstruct weightconfig_s *itemweightconfig;\t//weight config\n\tint *itemweightindex;\t\t\t\t\t\t//index from item to weight\n\t//\n\tint client;\t\t\t\t\t\t\t\t\t//client using this goal state\n\tint lastreachabilityarea;\t\t\t\t\t//last area with reachabilities the bot was in\n\t//\n\tbot_goal_t goalstack[MAX_GOALSTACK];\t\t//goal stack\n\tint goalstacktop;\t\t\t\t\t\t\t//the top of the goal stack\n\t//\n\tint avoidgoals[MAX_AVOIDGOALS];\t\t\t\t//goals to avoid\n\tfloat avoidgoaltimes[MAX_AVOIDGOALS];\t\t//times to avoid the goals\n} bot_goalstate_t;\n\nbot_goalstate_t *botgoalstates[MAX_CLIENTS + 1]; // bk001206 - FIXME: init?\n//item configuration\nitemconfig_t *itemconfig = NULL; // bk001206 - init\n//level items\nlevelitem_t *levelitemheap = NULL; // bk001206 - init\nlevelitem_t *freelevelitems = NULL; // bk001206 - init\nlevelitem_t *levelitems = NULL; // bk001206 - init\nint numlevelitems = 0;\n//map locations\nmaplocation_t *maplocations = NULL; // bk001206 - init\n//camp spots\ncampspot_t *campspots = NULL; // bk001206 - init\n//the game type\nint g_gametype = 0; // bk001206 - init\n//additional dropped item weight\nlibvar_t *droppedweight = NULL; // bk001206 - init\n\n//========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//========================================================================\nbot_goalstate_t *BotGoalStateFromHandle(int handle)\n{\n\tif (handle <= 0 || handle > MAX_CLIENTS)\n\t{\n\t\tbotimport.Print(PRT_FATAL, \"goal state handle %d out of range\\n\", handle);\n\t\treturn NULL;\n\t} //end if\n\tif (!botgoalstates[handle])\n\t{\n\t\tbotimport.Print(PRT_FATAL, \"invalid goal state %d\\n\", handle);\n\t\treturn NULL;\n\t} //end if\n\treturn botgoalstates[handle];\n} //end of the function BotGoalStateFromHandle\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotInterbreedGoalFuzzyLogic(int parent1, int parent2, int child)\n{\n\tbot_goalstate_t *p1, *p2, *c;\n\n\tp1 = BotGoalStateFromHandle(parent1);\n\tp2 = BotGoalStateFromHandle(parent2);\n\tc = BotGoalStateFromHandle(child);\n\n\tInterbreedWeightConfigs(p1->itemweightconfig, p2->itemweightconfig,\n\t\t\t\t\t\t\t\t\tc->itemweightconfig);\n} //end of the function BotInterbreedingGoalFuzzyLogic\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotSaveGoalFuzzyLogic(int goalstate, char *filename)\n{\n\tbot_goalstate_t *gs;\n\n\tgs = BotGoalStateFromHandle(goalstate);\n\n\t//WriteWeightConfig(filename, gs->itemweightconfig);\n} //end of the function BotSaveGoalFuzzyLogic\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotMutateGoalFuzzyLogic(int goalstate, float range)\n{\n\tbot_goalstate_t *gs;\n\n\tgs = BotGoalStateFromHandle(goalstate);\n\n\tEvolveWeightConfig(gs->itemweightconfig);\n} //end of the function BotMutateGoalFuzzyLogic\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nitemconfig_t *LoadItemConfig(char *filename)\n{\n\tint max_iteminfo;\n\ttoken_t token;\n\tchar path[MAX_PATH];\n\tsource_t *source;\n\titemconfig_t *ic;\n\titeminfo_t *ii;\n\n\tmax_iteminfo = (int) LibVarValue(\"max_iteminfo\", \"256\");\n\tif (max_iteminfo < 0)\n\t{\n\t\tbotimport.Print(PRT_ERROR, \"max_iteminfo = %d\\n\", max_iteminfo);\n\t\tmax_iteminfo = 256;\n\t\tLibVarSet( \"max_iteminfo\", \"256\" );\n\t}\n\n\tstrncpy( path, filename, MAX_PATH );\n\tPC_SetBaseFolder(BOTFILESBASEFOLDER);\n\tsource = LoadSourceFile( path );\n\tif( !source ) {\n\t\tbotimport.Print( PRT_ERROR, \"counldn't load %s\\n\", path );\n\t\treturn NULL;\n\t} //end if\n\t//initialize item config\n\tic = (itemconfig_t *) GetClearedHunkMemory(sizeof(itemconfig_t) +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tmax_iteminfo * sizeof(iteminfo_t));\n\tic->iteminfo = (iteminfo_t *) ((char *) ic + sizeof(itemconfig_t));\n\tic->numiteminfo = 0;\n\t//parse the item config file\n\twhile(PC_ReadToken(source, &token))\n\t{\n\t\tif (!strcmp(token.string, \"iteminfo\"))\n\t\t{\n\t\t\tif (ic->numiteminfo >= max_iteminfo)\n\t\t\t{\n\t\t\t\tSourceError(source, \"more than %d item info defined\\n\", max_iteminfo);\n\t\t\t\tFreeMemory(ic);\n\t\t\t\tFreeSource(source);\n\t\t\t\treturn NULL;\n\t\t\t} //end if\n\t\t\tii = &ic->iteminfo[ic->numiteminfo];\n\t\t\tCom_Memset(ii, 0, sizeof(iteminfo_t));\n\t\t\tif (!PC_ExpectTokenType(source, TT_STRING, 0, &token))\n\t\t\t{\n\t\t\t\tFreeMemory(ic);\n\t\t\t\tFreeMemory(source);\n\t\t\t\treturn NULL;\n\t\t\t} //end if\n\t\t\tStripDoubleQuotes(token.string);\n\t\t\tstrncpy(ii->classname, token.string, sizeof(ii->classname)-1);\n\t\t\tif (!ReadStructure(source, &iteminfo_struct, (char *) ii))\n\t\t\t{\n\t\t\t\tFreeMemory(ic);\n\t\t\t\tFreeSource(source);\n\t\t\t\treturn NULL;\n\t\t\t} //end if\n\t\t\tii->number = ic->numiteminfo;\n\t\t\tic->numiteminfo++;\n\t\t} //end if\n\t\telse\n\t\t{\n\t\t\tSourceError(source, \"unknown definition %s\\n\", token.string);\n\t\t\tFreeMemory(ic);\n\t\t\tFreeSource(source);\n\t\t\treturn NULL;\n\t\t} //end else\n\t} //end while\n\tFreeSource(source);\n\t//\n\tif (!ic->numiteminfo) botimport.Print(PRT_WARNING, \"no item info loaded\\n\");\n\tbotimport.Print(PRT_MESSAGE, \"loaded %s\\n\", path);\n\treturn ic;\n} //end of the function LoadItemConfig\n//===========================================================================\n// index to find the weight function of an iteminfo\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint *ItemWeightIndex(weightconfig_t *iwc, itemconfig_t *ic)\n{\n\tint *index, i;\n\n\t//initialize item weight index\n\tindex = (int *) GetClearedMemory(sizeof(int) * ic->numiteminfo);\n\n\tfor (i = 0; i < ic->numiteminfo; i++)\n\t{\n\t\tindex[i] = FindFuzzyWeight(iwc, ic->iteminfo[i].classname);\n\t\tif (index[i] < 0)\n\t\t{\n\t\t\tLog_Write(\"item info %d \\\"%s\\\" has no fuzzy weight\\r\\n\", i, ic->iteminfo[i].classname);\n\t\t} //end if\n\t} //end for\n\treturn index;\n} //end of the function ItemWeightIndex\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid InitLevelItemHeap(void)\n{\n\tint i, max_levelitems;\n\n\tif (levelitemheap) FreeMemory(levelitemheap);\n\n\tmax_levelitems = (int) LibVarValue(\"max_levelitems\", \"256\");\n\tlevelitemheap = (levelitem_t *) GetClearedMemory(max_levelitems * sizeof(levelitem_t));\n\n\tfor (i = 0; i < max_levelitems-1; i++)\n\t{\n\t\tlevelitemheap[i].next = &levelitemheap[i + 1];\n\t} //end for\n\tlevelitemheap[max_levelitems-1].next = NULL;\n\t//\n\tfreelevelitems = levelitemheap;\n} //end of the function InitLevelItemHeap\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nlevelitem_t *AllocLevelItem(void)\n{\n\tlevelitem_t *li;\n\n\tli = freelevelitems;\n\tif (!li)\n\t{\n\t\tbotimport.Print(PRT_FATAL, \"out of level items\\n\");\n\t\treturn NULL;\n\t} //end if\n\t//\n\tfreelevelitems = freelevelitems->next;\n\tCom_Memset(li, 0, sizeof(levelitem_t));\n\treturn li;\n} //end of the function AllocLevelItem\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid FreeLevelItem(levelitem_t *li)\n{\n\tli->next = freelevelitems;\n\tfreelevelitems = li;\n} //end of the function FreeLevelItem\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AddLevelItemToList(levelitem_t *li)\n{\n\tif (levelitems) levelitems->prev = li;\n\tli->prev = NULL;\n\tli->next = levelitems;\n\tlevelitems = li;\n} //end of the function AddLevelItemToList\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid RemoveLevelItemFromList(levelitem_t *li)\n{\n\tif (li->prev) li->prev->next = li->next;\n\telse levelitems = li->next;\n\tif (li->next) li->next->prev = li->prev;\n} //end of the function RemoveLevelItemFromList\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotFreeInfoEntities(void)\n{\n\tmaplocation_t *ml, *nextml;\n\tcampspot_t *cs, *nextcs;\n\n\tfor (ml = maplocations; ml; ml = nextml)\n\t{\n\t\tnextml = ml->next;\n\t\tFreeMemory(ml);\n\t} //end for\n\tmaplocations = NULL;\n\tfor (cs = campspots; cs; cs = nextcs)\n\t{\n\t\tnextcs = cs->next;\n\t\tFreeMemory(cs);\n\t} //end for\n\tcampspots = NULL;\n} //end of the function BotFreeInfoEntities\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotInitInfoEntities(void)\n{\n\tchar classname[MAX_EPAIRKEY];\n\tmaplocation_t *ml;\n\tcampspot_t *cs;\n\tint ent, numlocations, numcampspots;\n\n\tBotFreeInfoEntities();\n\t//\n\tnumlocations = 0;\n\tnumcampspots = 0;\n\tfor (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent))\n\t{\n\t\tif (!AAS_ValueForBSPEpairKey(ent, \"classname\", classname, MAX_EPAIRKEY)) continue;\n\n\t\t//map locations\n\t\tif (!strcmp(classname, \"target_location\"))\n\t\t{\n\t\t\tml = (maplocation_t *) GetClearedMemory(sizeof(maplocation_t));\n\t\t\tAAS_VectorForBSPEpairKey(ent, \"origin\", ml->origin);\n\t\t\tAAS_ValueForBSPEpairKey(ent, \"message\", ml->name, sizeof(ml->name));\n\t\t\tml->areanum = AAS_PointAreaNum(ml->origin);\n\t\t\tml->next = maplocations;\n\t\t\tmaplocations = ml;\n\t\t\tnumlocations++;\n\t\t} //end if\n\t\t//camp spots\n\t\telse if (!strcmp(classname, \"info_camp\"))\n\t\t{\n\t\t\tcs = (campspot_t *) GetClearedMemory(sizeof(campspot_t));\n\t\t\tAAS_VectorForBSPEpairKey(ent, \"origin\", cs->origin);\n\t\t\t//cs->origin[2] += 16;\n\t\t\tAAS_ValueForBSPEpairKey(ent, \"message\", cs->name, sizeof(cs->name));\n\t\t\tAAS_FloatForBSPEpairKey(ent, \"range\", &cs->range);\n\t\t\tAAS_FloatForBSPEpairKey(ent, \"weight\", &cs->weight);\n\t\t\tAAS_FloatForBSPEpairKey(ent, \"wait\", &cs->wait);\n\t\t\tAAS_FloatForBSPEpairKey(ent, \"random\", &cs->random);\n\t\t\tcs->areanum = AAS_PointAreaNum(cs->origin);\n\t\t\tif (!cs->areanum)\n\t\t\t{\n\t\t\t\tbotimport.Print(PRT_MESSAGE, \"camp spot at %1.1f %1.1f %1.1f in solid\\n\", cs->origin[0], cs->origin[1], cs->origin[2]);\n\t\t\t\tFreeMemory(cs);\n\t\t\t\tcontinue;\n\t\t\t} //end if\n\t\t\tcs->next = campspots;\n\t\t\tcampspots = cs;\n\t\t\t//AAS_DrawPermanentCross(cs->origin, 4, LINECOLOR_YELLOW);\n\t\t\tnumcampspots++;\n\t\t} //end else if\n\t} //end for\n\tif (bot_developer)\n\t{\n\t\tbotimport.Print(PRT_MESSAGE, \"%d map locations\\n\", numlocations);\n\t\tbotimport.Print(PRT_MESSAGE, \"%d camp spots\\n\", numcampspots);\n\t} //end if\n} //end of the function BotInitInfoEntities\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotInitLevelItems(void)\n{\n\tint i, spawnflags, value;\n\tchar classname[MAX_EPAIRKEY];\n\tvec3_t origin, end;\n\tint ent, goalareanum;\n\titemconfig_t *ic;\n\tlevelitem_t *li;\n\tbsp_trace_t trace;\n\n\t//initialize the map locations and camp spots\n\tBotInitInfoEntities();\n\n\t//initialize the level item heap\n\tInitLevelItemHeap();\n\tlevelitems = NULL;\n\tnumlevelitems = 0;\n\t//\n\tic = itemconfig;\n\tif (!ic) return;\n\n\t//if there's no AAS file loaded\n\tif (!AAS_Loaded()) return;\n\n\t//update the modelindexes of the item info\n\tfor (i = 0; i < ic->numiteminfo; i++)\n\t{\n\t\t//ic->iteminfo[i].modelindex = AAS_IndexFromModel(ic->iteminfo[i].model);\n\t\tif (!ic->iteminfo[i].modelindex)\n\t\t{\n\t\t\tLog_Write(\"item %s has modelindex 0\", ic->iteminfo[i].classname);\n\t\t} //end if\n\t} //end for\n\n\tfor (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent))\n\t{\n\t\tif (!AAS_ValueForBSPEpairKey(ent, \"classname\", classname, MAX_EPAIRKEY)) continue;\n\t\t//\n\t\tspawnflags = 0;\n\t\tAAS_IntForBSPEpairKey(ent, \"spawnflags\", &spawnflags);\n\t\t//\n\t\tfor (i = 0; i < ic->numiteminfo; i++)\n\t\t{\n\t\t\tif (!strcmp(classname, ic->iteminfo[i].classname)) break;\n\t\t} //end for\n\t\tif (i >= ic->numiteminfo)\n\t\t{\n\t\t\tLog_Write(\"entity %s unknown item\\r\\n\", classname);\n\t\t\tcontinue;\n\t\t} //end if\n\t\t//get the origin of the item\n\t\tif (!AAS_VectorForBSPEpairKey(ent, \"origin\", origin))\n\t\t{\n\t\t\tbotimport.Print(PRT_ERROR, \"item %s without origin\\n\", classname);\n\t\t\tcontinue;\n\t\t} //end else\n\t\t//\n\t\tgoalareanum = 0;\n\t\t//if it is a floating item\n\t\tif (spawnflags & 1)\n\t\t{\n\t\t\t//if the item is not floating in water\n\t\t\tif (!(AAS_PointContents(origin) & CONTENTS_WATER))\n\t\t\t{\n\t\t\t\tVectorCopy(origin, end);\n\t\t\t\tend[2] -= 32;\n\t\t\t\ttrace = AAS_Trace(origin, ic->iteminfo[i].mins, ic->iteminfo[i].maxs, end, -1, CONTENTS_SOLID|CONTENTS_PLAYERCLIP);\n\t\t\t\t//if the item not near the ground\n\t\t\t\tif (trace.fraction >= 1)\n\t\t\t\t{\n\t\t\t\t\t//if the item is not reachable from a jumppad\n\t\t\t\t\tgoalareanum = AAS_BestReachableFromJumpPadArea(origin, ic->iteminfo[i].mins, ic->iteminfo[i].maxs);\n\t\t\t\t\tLog_Write(\"item %s reachable from jumppad area %d\\r\\n\", ic->iteminfo[i].classname, goalareanum);\n\t\t\t\t\t//botimport.Print(PRT_MESSAGE, \"item %s reachable from jumppad area %d\\r\\n\", ic->iteminfo[i].classname, goalareanum);\n\t\t\t\t\tif (!goalareanum) continue;\n\t\t\t\t} //end if\n\t\t\t} //end if\n\t\t} //end if\n\n\t\tli = AllocLevelItem();\n\t\tif (!li) return;\n\t\t//\n\t\tli->number = ++numlevelitems;\n\t\tli->timeout = 0;\n\t\tli->entitynum = 0;\n\t\t//\n\t\tli->flags = 0;\n\t\tAAS_IntForBSPEpairKey(ent, \"notfree\", &value);\n\t\tif (value) li->flags |= IFL_NOTFREE;\n\t\tAAS_IntForBSPEpairKey(ent, \"notteam\", &value);\n\t\tif (value) li->flags |= IFL_NOTTEAM;\n\t\tAAS_IntForBSPEpairKey(ent, \"notsingle\", &value);\n\t\tif (value) li->flags |= IFL_NOTSINGLE;\n\t\tAAS_IntForBSPEpairKey(ent, \"notbot\", &value);\n\t\tif (value) li->flags |= IFL_NOTBOT;\n\t\tif (!strcmp(classname, \"item_botroam\"))\n\t\t{\n\t\t\tli->flags |= IFL_ROAM;\n\t\t\tAAS_FloatForBSPEpairKey(ent, \"weight\", &li->weight);\n\t\t} //end if\n\t\t//if not a stationary item\n\t\tif (!(spawnflags & 1))\n\t\t{\n\t\t\tif (!AAS_DropToFloor(origin, ic->iteminfo[i].mins, ic->iteminfo[i].maxs))\n\t\t\t{\n\t\t\t\tbotimport.Print(PRT_MESSAGE, \"%s in solid at (%1.1f %1.1f %1.1f)\\n\",\n\t\t\t\t\t\t\t\t\t\t\t\tclassname, origin[0], origin[1], origin[2]);\n\t\t\t} //end if\n\t\t} //end if\n\t\t//item info of the level item\n\t\tli->iteminfo = i;\n\t\t//origin of the item\n\t\tVectorCopy(origin, li->origin);\n\t\t//\n\t\tif (goalareanum)\n\t\t{\n\t\t\tli->goalareanum = goalareanum;\n\t\t\tVectorCopy(origin, li->goalorigin);\n\t\t} //end if\n\t\telse\n\t\t{\n\t\t\t//get the item goal area and goal origin\n\t\t\tli->goalareanum = AAS_BestReachableArea(origin,\n\t\t\t\t\t\t\tic->iteminfo[i].mins, ic->iteminfo[i].maxs,\n\t\t\t\t\t\t\tli->goalorigin);\n\t\t\tif (!li->goalareanum)\n\t\t\t{\n\t\t\t\tbotimport.Print(PRT_MESSAGE, \"%s not reachable for bots at (%1.1f %1.1f %1.1f)\\n\",\n\t\t\t\t\t\t\t\t\t\t\t\tclassname, origin[0], origin[1], origin[2]);\n\t\t\t} //end if\n\t\t} //end else\n\t\t//\n\t\tAddLevelItemToList(li);\n\t} //end for\n\tbotimport.Print(PRT_MESSAGE, \"found %d level items\\n\", numlevelitems);\n} //end of the function BotInitLevelItems\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotGoalName(int number, char *name, int size)\n{\n\tlevelitem_t *li;\n\n\tif (!itemconfig) return;\n\t//\n\tfor (li = levelitems; li; li = li->next)\n\t{\n\t\tif (li->number == number)\n\t\t{\n\t\t\tstrncpy(name, itemconfig->iteminfo[li->iteminfo].name, size-1);\n\t\t\tname[size-1] = '\\0';\n\t\t\treturn;\n\t\t} //end for\n\t} //end for\n\tstrcpy(name, \"\");\n\treturn;\n} //end of the function BotGoalName\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotResetAvoidGoals(int goalstate)\n{\n\tbot_goalstate_t *gs;\n\n\tgs = BotGoalStateFromHandle(goalstate);\n\tif (!gs) return;\n\tCom_Memset(gs->avoidgoals, 0, MAX_AVOIDGOALS * sizeof(int));\n\tCom_Memset(gs->avoidgoaltimes, 0, MAX_AVOIDGOALS * sizeof(float));\n} //end of the function BotResetAvoidGoals\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotDumpAvoidGoals(int goalstate)\n{\n\tint i;\n\tbot_goalstate_t *gs;\n\tchar name[32];\n\n\tgs = BotGoalStateFromHandle(goalstate);\n\tif (!gs) return;\n\tfor (i = 0; i < MAX_AVOIDGOALS; i++)\n\t{\n\t\tif (gs->avoidgoaltimes[i] >= AAS_Time())\n\t\t{\n\t\t\tBotGoalName(gs->avoidgoals[i], name, 32);\n\t\t\tLog_Write(\"avoid goal %s, number %d for %f seconds\", name,\n\t\t\t\tgs->avoidgoals[i], gs->avoidgoaltimes[i] - AAS_Time());\n\t\t} //end if\n\t} //end for\n} //end of the function BotDumpAvoidGoals\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotAddToAvoidGoals(bot_goalstate_t *gs, int number, float avoidtime)\n{\n\tint i;\n\n\tfor (i = 0; i < MAX_AVOIDGOALS; i++)\n\t{\n\t\t//if the avoid goal is already stored\n\t\tif (gs->avoidgoals[i] == number)\n\t\t{\n\t\t\tgs->avoidgoals[i] = number;\n\t\t\tgs->avoidgoaltimes[i] = AAS_Time() + avoidtime;\n\t\t\treturn;\n\t\t} //end if\n\t} //end for\n\n\tfor (i = 0; i < MAX_AVOIDGOALS; i++)\n\t{\n\t\t//if this avoid goal has expired\n\t\tif (gs->avoidgoaltimes[i] < AAS_Time())\n\t\t{\n\t\t\tgs->avoidgoals[i] = number;\n\t\t\tgs->avoidgoaltimes[i] = AAS_Time() + avoidtime;\n\t\t\treturn;\n\t\t} //end if\n\t} //end for\n} //end of the function BotAddToAvoidGoals\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotRemoveFromAvoidGoals(int goalstate, int number)\n{\n\tint i;\n\tbot_goalstate_t *gs;\n\n\tgs = BotGoalStateFromHandle(goalstate);\n\tif (!gs) return;\n\t//don't use the goals the bot wants to avoid\n\tfor (i = 0; i < MAX_AVOIDGOALS; i++)\n\t{\n\t\tif (gs->avoidgoals[i] == number && gs->avoidgoaltimes[i] >= AAS_Time())\n\t\t{\n\t\t\tgs->avoidgoaltimes[i] = 0;\n\t\t\treturn;\n\t\t} //end if\n\t} //end for\n} //end of the function BotRemoveFromAvoidGoals\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nfloat BotAvoidGoalTime(int goalstate, int number)\n{\n\tint i;\n\tbot_goalstate_t *gs;\n\n\tgs = BotGoalStateFromHandle(goalstate);\n\tif (!gs) return 0;\n\t//don't use the goals the bot wants to avoid\n\tfor (i = 0; i < MAX_AVOIDGOALS; i++)\n\t{\n\t\tif (gs->avoidgoals[i] == number && gs->avoidgoaltimes[i] >= AAS_Time())\n\t\t{\n\t\t\treturn gs->avoidgoaltimes[i] - AAS_Time();\n\t\t} //end if\n\t} //end for\n\treturn 0;\n} //end of the function BotAvoidGoalTime\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotSetAvoidGoalTime(int goalstate, int number, float avoidtime)\n{\n\tbot_goalstate_t *gs;\n\tlevelitem_t *li;\n\n\tgs = BotGoalStateFromHandle(goalstate);\n\tif (!gs)\n\t\treturn;\n\tif (avoidtime < 0)\n\t{\n\t\tif (!itemconfig)\n\t\t\treturn;\n\t\t//\n\t\tfor (li = levelitems; li; li = li->next)\n\t\t{\n\t\t\tif (li->number == number)\n\t\t\t{\n\t\t\t\tavoidtime = itemconfig->iteminfo[li->iteminfo].respawntime;\n\t\t\t\tif (!avoidtime)\n\t\t\t\t\tavoidtime = AVOID_DEFAULT_TIME;\n\t\t\t\tif (avoidtime < AVOID_MINIMUM_TIME)\n\t\t\t\t\tavoidtime = AVOID_MINIMUM_TIME;\n\t\t\t\tBotAddToAvoidGoals(gs, number, avoidtime);\n\t\t\t\treturn;\n\t\t\t} //end for\n\t\t} //end for\n\t\treturn;\n\t} //end if\n\telse\n\t{\n\t\tBotAddToAvoidGoals(gs, number, avoidtime);\n\t} //end else\n} //end of the function BotSetAvoidGoalTime\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotGetLevelItemGoal(int index, char *name, bot_goal_t *goal)\n{\n\tlevelitem_t *li;\n\n\tif (!itemconfig) return -1;\n\tli = levelitems;\n\tif (index >= 0)\n\t{\n\t\tfor (; li; li = li->next)\n\t\t{\n\t\t\tif (li->number == index)\n\t\t\t{\n\t\t\t\tli = li->next;\n\t\t\t\tbreak;\n\t\t\t} //end if\n\t\t} //end for\n\t} //end for\n\tfor (; li; li = li->next)\n\t{\n\t\t//\n\t\tif (g_gametype == GT_SINGLE_PLAYER) {\n\t\t\tif (li->flags & IFL_NOTSINGLE) continue;\n\t\t}\n\t\telse if (g_gametype >= GT_TEAM) {\n\t\t\tif (li->flags & IFL_NOTTEAM) continue;\n\t\t}\n\t\telse {\n\t\t\tif (li->flags & IFL_NOTFREE) continue;\n\t\t}\n\t\tif (li->flags & IFL_NOTBOT) continue;\n\t\t//\n\t\tif (!Q_stricmp(name, itemconfig->iteminfo[li->iteminfo].name))\n\t\t{\n\t\t\tgoal->areanum = li->goalareanum;\n\t\t\tVectorCopy(li->goalorigin, goal->origin);\n\t\t\tgoal->entitynum = li->entitynum;\n\t\t\tVectorCopy(itemconfig->iteminfo[li->iteminfo].mins, goal->mins);\n\t\t\tVectorCopy(itemconfig->iteminfo[li->iteminfo].maxs, goal->maxs);\n\t\t\tgoal->number = li->number;\n\t\t\tgoal->flags = GFL_ITEM;\n\t\t\tif (li->timeout) goal->flags |= GFL_DROPPED;\n\t\t\t//botimport.Print(PRT_MESSAGE, \"found li %s\\n\", itemconfig->iteminfo[li->iteminfo].name);\n\t\t\treturn li->number;\n\t\t} //end if\n\t} //end for\n\treturn -1;\n} //end of the function BotGetLevelItemGoal\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotGetMapLocationGoal(char *name, bot_goal_t *goal)\n{\n\tmaplocation_t *ml;\n\tvec3_t mins = {-8, -8, -8}, maxs = {8, 8, 8};\n\n\tfor (ml = maplocations; ml; ml = ml->next)\n\t{\n\t\tif (!Q_stricmp(ml->name, name))\n\t\t{\n\t\t\tgoal->areanum = ml->areanum;\n\t\t\tVectorCopy(ml->origin, goal->origin);\n\t\t\tgoal->entitynum = 0;\n\t\t\tVectorCopy(mins, goal->mins);\n\t\t\tVectorCopy(maxs, goal->maxs);\n\t\t\treturn qtrue;\n\t\t} //end if\n\t} //end for\n\treturn qfalse;\n} //end of the function BotGetMapLocationGoal\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotGetNextCampSpotGoal(int num, bot_goal_t *goal)\n{\n\tint i;\n\tcampspot_t *cs;\n\tvec3_t mins = {-8, -8, -8}, maxs = {8, 8, 8};\n\n\tif (num < 0) num = 0;\n\ti = num;\n\tfor (cs = campspots; cs; cs = cs->next)\n\t{\n\t\tif (--i < 0)\n\t\t{\n\t\t\tgoal->areanum = cs->areanum;\n\t\t\tVectorCopy(cs->origin, goal->origin);\n\t\t\tgoal->entitynum = 0;\n\t\t\tVectorCopy(mins, goal->mins);\n\t\t\tVectorCopy(maxs, goal->maxs);\n\t\t\treturn num+1;\n\t\t} //end if\n\t} //end for\n\treturn 0;\n} //end of the function BotGetNextCampSpotGoal\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotFindEntityForLevelItem(levelitem_t *li)\n{\n\tint ent, modelindex;\n\titemconfig_t *ic;\n\taas_entityinfo_t entinfo;\n\tvec3_t dir;\n\n\tic = itemconfig;\n\tif (!itemconfig) return;\n\tfor (ent = AAS_NextEntity(0); ent; ent = AAS_NextEntity(ent))\n\t{\n\t\t//get the model index of the entity\n\t\tmodelindex = AAS_EntityModelindex(ent);\n\t\t//\n\t\tif (!modelindex) continue;\n\t\t//get info about the entity\n\t\tAAS_EntityInfo(ent, &entinfo);\n\t\t//if the entity is still moving\n\t\tif (entinfo.origin[0] != entinfo.lastvisorigin[0] ||\n\t\t\t\tentinfo.origin[1] != entinfo.lastvisorigin[1] ||\n\t\t\t\tentinfo.origin[2] != entinfo.lastvisorigin[2]) continue;\n\t\t//\n\t\tif (ic->iteminfo[li->iteminfo].modelindex == modelindex)\n\t\t{\n\t\t\t//check if the entity is very close\n\t\t\tVectorSubtract(li->origin, entinfo.origin, dir);\n\t\t\tif (VectorLength(dir) < 30)\n\t\t\t{\n\t\t\t\t//found an entity for this level item\n\t\t\t\tli->entitynum = ent;\n\t\t\t} //end if\n\t\t} //end if\n\t} //end for\n} //end of the function BotFindEntityForLevelItem\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\n\n//NOTE: enum entityType_t in bg_public.h\n#define ET_ITEM\t\t\t2\n\nvoid BotUpdateEntityItems(void)\n{\n\tint ent, i, modelindex;\n\tvec3_t dir;\n\tlevelitem_t *li, *nextli;\n\taas_entityinfo_t entinfo;\n\titemconfig_t *ic;\n\n\t//timeout current entity items if necessary\n\tfor (li = levelitems; li; li = nextli)\n\t{\n\t\tnextli = li->next;\n\t\t//if it is a item that will time out\n\t\tif (li->timeout)\n\t\t{\n\t\t\t//timeout the item\n\t\t\tif (li->timeout < AAS_Time())\n\t\t\t{\n\t\t\t\tRemoveLevelItemFromList(li);\n\t\t\t\tFreeLevelItem(li);\n\t\t\t} //end if\n\t\t} //end if\n\t} //end for\n\t//find new entity items\n\tic = itemconfig;\n\tif (!itemconfig) return;\n\t//\n\tfor (ent = AAS_NextEntity(0); ent; ent = AAS_NextEntity(ent))\n\t{\n\t\tif (AAS_EntityType(ent) != ET_ITEM) continue;\n\t\t//get the model index of the entity\n\t\tmodelindex = AAS_EntityModelindex(ent);\n\t\t//\n\t\tif (!modelindex) continue;\n\t\t//get info about the entity\n\t\tAAS_EntityInfo(ent, &entinfo);\n\t\t//FIXME: don't do this\n\t\t//skip all floating items for now\n\t\t//if (entinfo.groundent != ENTITYNUM_WORLD) continue;\n\t\t//if the entity is still moving\n\t\tif (entinfo.origin[0] != entinfo.lastvisorigin[0] ||\n\t\t\t\tentinfo.origin[1] != entinfo.lastvisorigin[1] ||\n\t\t\t\tentinfo.origin[2] != entinfo.lastvisorigin[2]) continue;\n\t\t//check if the entity is already stored as a level item\n\t\tfor (li = levelitems; li; li = li->next)\n\t\t{\n\t\t\t//if the level item is linked to an entity\n\t\t\tif (li->entitynum && li->entitynum == ent)\n\t\t\t{\n\t\t\t\t//the entity is re-used if the models are different\n\t\t\t\tif (ic->iteminfo[li->iteminfo].modelindex != modelindex)\n\t\t\t\t{\n\t\t\t\t\t//remove this level item\n\t\t\t\t\tRemoveLevelItemFromList(li);\n\t\t\t\t\tFreeLevelItem(li);\n\t\t\t\t\tli = NULL;\n\t\t\t\t\tbreak;\n\t\t\t\t} //end if\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (entinfo.origin[0] != li->origin[0] ||\n\t\t\t\t\t\tentinfo.origin[1] != li->origin[1] ||\n\t\t\t\t\t\tentinfo.origin[2] != li->origin[2])\n\t\t\t\t\t{\n\t\t\t\t\t\tVectorCopy(entinfo.origin, li->origin);\n\t\t\t\t\t\t//also update the goal area number\n\t\t\t\t\t\tli->goalareanum = AAS_BestReachableArea(li->origin,\n\t\t\t\t\t\t\t\t\t\tic->iteminfo[li->iteminfo].mins, ic->iteminfo[li->iteminfo].maxs,\n\t\t\t\t\t\t\t\t\t\tli->goalorigin);\n\t\t\t\t\t} //end if\n\t\t\t\t\tbreak;\n\t\t\t\t} //end else\n\t\t\t} //end if\n\t\t} //end for\n\t\tif (li) continue;\n\t\t//try to link the entity to a level item\n\t\tfor (li = levelitems; li; li = li->next)\n\t\t{\n\t\t\t//if this level item is already linked\n\t\t\tif (li->entitynum) continue;\n\t\t\t//\n\t\t\tif (g_gametype == GT_SINGLE_PLAYER) {\n\t\t\t\tif (li->flags & IFL_NOTSINGLE) continue;\n\t\t\t}\n\t\t\telse if (g_gametype >= GT_TEAM) {\n\t\t\t\tif (li->flags & IFL_NOTTEAM) continue;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (li->flags & IFL_NOTFREE) continue;\n\t\t\t}\n\t\t\t//if the model of the level item and the entity are the same\n\t\t\tif (ic->iteminfo[li->iteminfo].modelindex == modelindex)\n\t\t\t{\n\t\t\t\t//check if the entity is very close\n\t\t\t\tVectorSubtract(li->origin, entinfo.origin, dir);\n\t\t\t\tif (VectorLength(dir) < 30)\n\t\t\t\t{\n\t\t\t\t\t//found an entity for this level item\n\t\t\t\t\tli->entitynum = ent;\n\t\t\t\t\t//if the origin is different\n\t\t\t\t\tif (entinfo.origin[0] != li->origin[0] ||\n\t\t\t\t\t\tentinfo.origin[1] != li->origin[1] ||\n\t\t\t\t\t\tentinfo.origin[2] != li->origin[2])\n\t\t\t\t\t{\n\t\t\t\t\t\t//update the level item origin\n\t\t\t\t\t\tVectorCopy(entinfo.origin, li->origin);\n\t\t\t\t\t\t//also update the goal area number\n\t\t\t\t\t\tli->goalareanum = AAS_BestReachableArea(li->origin,\n\t\t\t\t\t\t\t\t\t\tic->iteminfo[li->iteminfo].mins, ic->iteminfo[li->iteminfo].maxs,\n\t\t\t\t\t\t\t\t\t\tli->goalorigin);\n\t\t\t\t\t} //end if\n#ifdef DEBUG\n\t\t\t\t\tLog_Write(\"linked item %s to an entity\", ic->iteminfo[li->iteminfo].classname);\n#endif //DEBUG\n\t\t\t\t\tbreak;\n\t\t\t\t} //end if\n\t\t\t} //end else\n\t\t} //end for\n\t\tif (li) continue;\n\t\t//check if the model is from a known item\n\t\tfor (i = 0; i < ic->numiteminfo; i++)\n\t\t{\n\t\t\tif (ic->iteminfo[i].modelindex == modelindex)\n\t\t\t{\n\t\t\t\tbreak;\n\t\t\t} //end if\n\t\t} //end for\n\t\t//if the model is not from a known item\n\t\tif (i >= ic->numiteminfo) continue;\n\t\t//allocate a new level item\n\t\tli = AllocLevelItem();\n\t\t//\n\t\tif (!li) continue;\n\t\t//entity number of the level item\n\t\tli->entitynum = ent;\n\t\t//number for the level item\n\t\tli->number = numlevelitems + ent;\n\t\t//set the item info index for the level item\n\t\tli->iteminfo = i;\n\t\t//origin of the item\n\t\tVectorCopy(entinfo.origin, li->origin);\n\t\t//get the item goal area and goal origin\n\t\tli->goalareanum = AAS_BestReachableArea(li->origin,\n\t\t\t\t\t\t\t\t\tic->iteminfo[i].mins, ic->iteminfo[i].maxs,\n\t\t\t\t\t\t\t\t\tli->goalorigin);\n\t\t//never go for items dropped into jumppads\n\t\tif (AAS_AreaJumpPad(li->goalareanum))\n\t\t{\n\t\t\tFreeLevelItem(li);\n\t\t\tcontinue;\n\t\t} //end if\n\t\t//time this item out after 30 seconds\n\t\t//dropped items disappear after 30 seconds\n\t\tli->timeout = AAS_Time() + 30;\n\t\t//add the level item to the list\n\t\tAddLevelItemToList(li);\n\t\t//botimport.Print(PRT_MESSAGE, \"found new level item %s\\n\", ic->iteminfo[i].classname);\n\t} //end for\n\t/*\n\tfor (li = levelitems; li; li = li->next)\n\t{\n\t\tif (!li->entitynum)\n\t\t{\n\t\t\tBotFindEntityForLevelItem(li);\n\t\t} //end if\n\t} //end for*/\n} //end of the function BotUpdateEntityItems\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotDumpGoalStack(int goalstate)\n{\n\tint i;\n\tbot_goalstate_t *gs;\n\tchar name[32];\n\n\tgs = BotGoalStateFromHandle(goalstate);\n\tif (!gs) return;\n\tfor (i = 1; i <= gs->goalstacktop; i++)\n\t{\n\t\tBotGoalName(gs->goalstack[i].number, name, 32);\n\t\tLog_Write(\"%d: %s\", i, name);\n\t} //end for\n} //end of the function BotDumpGoalStack\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotPushGoal(int goalstate, bot_goal_t *goal)\n{\n\tbot_goalstate_t *gs;\n\n\tgs = BotGoalStateFromHandle(goalstate);\n\tif (!gs) return;\n\tif (gs->goalstacktop >= MAX_GOALSTACK-1)\n\t{\n\t\tbotimport.Print(PRT_ERROR, \"goal heap overflow\\n\");\n\t\tBotDumpGoalStack(goalstate);\n\t\treturn;\n\t} //end if\n\tgs->goalstacktop++;\n\tCom_Memcpy(&gs->goalstack[gs->goalstacktop], goal, sizeof(bot_goal_t));\n} //end of the function BotPushGoal\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotPopGoal(int goalstate)\n{\n\tbot_goalstate_t *gs;\n\n\tgs = BotGoalStateFromHandle(goalstate);\n\tif (!gs) return;\n\tif (gs->goalstacktop > 0) gs->goalstacktop--;\n} //end of the function BotPopGoal\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotEmptyGoalStack(int goalstate)\n{\n\tbot_goalstate_t *gs;\n\n\tgs = BotGoalStateFromHandle(goalstate);\n\tif (!gs) return;\n\tgs->goalstacktop = 0;\n} //end of the function BotEmptyGoalStack\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotGetTopGoal(int goalstate, bot_goal_t *goal)\n{\n\tbot_goalstate_t *gs;\n\n\tgs = BotGoalStateFromHandle(goalstate);\n\tif (!gs) return qfalse;\n\tif (!gs->goalstacktop) return qfalse;\n\tCom_Memcpy(goal, &gs->goalstack[gs->goalstacktop], sizeof(bot_goal_t));\n\treturn qtrue;\n} //end of the function BotGetTopGoal\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotGetSecondGoal(int goalstate, bot_goal_t *goal)\n{\n\tbot_goalstate_t *gs;\n\n\tgs = BotGoalStateFromHandle(goalstate);\n\tif (!gs) return qfalse;\n\tif (gs->goalstacktop <= 1) return qfalse;\n\tCom_Memcpy(goal, &gs->goalstack[gs->goalstacktop-1], sizeof(bot_goal_t));\n\treturn qtrue;\n} //end of the function BotGetSecondGoal\n//===========================================================================\n// pops a new long term goal on the goal stack in the goalstate\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotChooseLTGItem(int goalstate, vec3_t origin, int *inventory, int travelflags)\n{\n\tint areanum, t, weightnum;\n\tfloat weight, bestweight, avoidtime;\n\titeminfo_t *iteminfo;\n\titemconfig_t *ic;\n\tlevelitem_t *li, *bestitem;\n\tbot_goal_t goal;\n\tbot_goalstate_t *gs;\n\n\tgs = BotGoalStateFromHandle(goalstate);\n\tif (!gs)\n\t\treturn qfalse;\n\tif (!gs->itemweightconfig)\n\t\treturn qfalse;\n\t//get the area the bot is in\n\tareanum = BotReachabilityArea(origin, gs->client);\n\t//if the bot is in solid or if the area the bot is in has no reachability links\n\tif (!areanum || !AAS_AreaReachability(areanum))\n\t{\n\t\t//use the last valid area the bot was in\n\t\tareanum = gs->lastreachabilityarea;\n\t} //end if\n\t//remember the last area with reachabilities the bot was in\n\tgs->lastreachabilityarea = areanum;\n\t//if still in solid\n\tif (!areanum)\n\t\treturn qfalse;\n\t//the item configuration\n\tic = itemconfig;\n\tif (!itemconfig)\n\t\treturn qfalse;\n\t//best weight and item so far\n\tbestweight = 0;\n\tbestitem = NULL;\n\tCom_Memset(&goal, 0, sizeof(bot_goal_t));\n\t//go through the items in the level\n\tfor (li = levelitems; li; li = li->next)\n\t{\n\t\tif (g_gametype == GT_SINGLE_PLAYER) {\n\t\t\tif (li->flags & IFL_NOTSINGLE)\n\t\t\t\tcontinue;\n\t\t}\n\t\telse if (g_gametype >= GT_TEAM) {\n\t\t\tif (li->flags & IFL_NOTTEAM)\n\t\t\t\tcontinue;\n\t\t}\n\t\telse {\n\t\t\tif (li->flags & IFL_NOTFREE)\n\t\t\t\tcontinue;\n\t\t}\n\t\tif (li->flags & IFL_NOTBOT)\n\t\t\tcontinue;\n\t\t//if the item is not in a possible goal area\n\t\tif (!li->goalareanum)\n\t\t\tcontinue;\n\t\t//FIXME: is this a good thing? added this for items that never spawned into the game (f.i. CTF flags in obelisk)\n\t\tif (!li->entitynum && !(li->flags & IFL_ROAM))\n\t\t\tcontinue;\n\t\t//get the fuzzy weight function for this item\n\t\titeminfo = &ic->iteminfo[li->iteminfo];\n\t\tweightnum = gs->itemweightindex[iteminfo->number];\n\t\tif (weightnum < 0)\n\t\t\tcontinue;\n\n#ifdef UNDECIDEDFUZZY\n\t\tweight = FuzzyWeightUndecided(inventory, gs->itemweightconfig, weightnum);\n#else\n\t\tweight = FuzzyWeight(inventory, gs->itemweightconfig, weightnum);\n#endif //UNDECIDEDFUZZY\n#ifdef DROPPEDWEIGHT\n\t\t//HACK: to make dropped items more attractive\n\t\tif (li->timeout)\n\t\t\tweight += droppedweight->value;\n#endif //DROPPEDWEIGHT\n\t\t//use weight scale for item_botroam\n\t\tif (li->flags & IFL_ROAM) weight *= li->weight;\n\t\t//\n\t\tif (weight > 0)\n\t\t{\n\t\t\t//get the travel time towards the goal area\n\t\t\tt = AAS_AreaTravelTimeToGoalArea(areanum, origin, li->goalareanum, travelflags);\n\t\t\t//if the goal is reachable\n\t\t\tif (t > 0)\n\t\t\t{\n\t\t\t\t//if this item won't respawn before we get there\n\t\t\t\tavoidtime = BotAvoidGoalTime(goalstate, li->number);\n\t\t\t\tif (avoidtime - t * 0.009 > 0)\n\t\t\t\t\tcontinue;\n\t\t\t\t//\n\t\t\t\tweight /= (float) t * TRAVELTIME_SCALE;\n\t\t\t\t//\n\t\t\t\tif (weight > bestweight)\n\t\t\t\t{\n\t\t\t\t\tbestweight = weight;\n\t\t\t\t\tbestitem = li;\n\t\t\t\t} //end if\n\t\t\t} //end if\n\t\t} //end if\n\t} //end for\n\t//if no goal item found\n\tif (!bestitem)\n\t{\n\t\t/*\n\t\t//if not in lava or slime\n\t\tif (!AAS_AreaLava(areanum) && !AAS_AreaSlime(areanum))\n\t\t{\n\t\t\tif (AAS_RandomGoalArea(areanum, travelflags, &goal.areanum, goal.origin))\n\t\t\t{\n\t\t\t\tVectorSet(goal.mins, -15, -15, -15);\n\t\t\t\tVectorSet(goal.maxs, 15, 15, 15);\n\t\t\t\tgoal.entitynum = 0;\n\t\t\t\tgoal.number = 0;\n\t\t\t\tgoal.flags = GFL_ROAM;\n\t\t\t\tgoal.iteminfo = 0;\n\t\t\t\t//push the goal on the stack\n\t\t\t\tBotPushGoal(goalstate, &goal);\n\t\t\t\t//\n#ifdef DEBUG\n\t\t\t\tbotimport.Print(PRT_MESSAGE, \"chosen roam goal area %d\\n\", goal.areanum);\n#endif //DEBUG\n\t\t\t\treturn qtrue;\n\t\t\t} //end if\n\t\t} //end if\n\t\t*/\n\t\treturn qfalse;\n\t} //end if\n\t//create a bot goal for this item\n\titeminfo = &ic->iteminfo[bestitem->iteminfo];\n\tVectorCopy(bestitem->goalorigin, goal.origin);\n\tVectorCopy(iteminfo->mins, goal.mins);\n\tVectorCopy(iteminfo->maxs, goal.maxs);\n\tgoal.areanum = bestitem->goalareanum;\n\tgoal.entitynum = bestitem->entitynum;\n\tgoal.number = bestitem->number;\n\tgoal.flags = GFL_ITEM;\n\tif (bestitem->timeout)\n\t\tgoal.flags |= GFL_DROPPED;\n\tif (bestitem->flags & IFL_ROAM)\n\t\tgoal.flags |= GFL_ROAM;\n\tgoal.iteminfo = bestitem->iteminfo;\n\t//if it's a dropped item\n\tif (bestitem->timeout)\n\t{\n\t\tavoidtime = AVOID_DROPPED_TIME;\n\t} //end if\n\telse\n\t{\n\t\tavoidtime = iteminfo->respawntime;\n\t\tif (!avoidtime)\n\t\t\tavoidtime = AVOID_DEFAULT_TIME;\n\t\tif (avoidtime < AVOID_MINIMUM_TIME)\n\t\t\tavoidtime = AVOID_MINIMUM_TIME;\n\t} //end else\n\t//add the chosen goal to the goals to avoid for a while\n\tBotAddToAvoidGoals(gs, bestitem->number, avoidtime);\n\t//push the goal on the stack\n\tBotPushGoal(goalstate, &goal);\n\t//\n\treturn qtrue;\n} //end of the function BotChooseLTGItem\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotChooseNBGItem(int goalstate, vec3_t origin, int *inventory, int travelflags,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tbot_goal_t *ltg, float maxtime)\n{\n\tint areanum, t, weightnum, ltg_time;\n\tfloat weight, bestweight, avoidtime;\n\titeminfo_t *iteminfo;\n\titemconfig_t *ic;\n\tlevelitem_t *li, *bestitem;\n\tbot_goal_t goal;\n\tbot_goalstate_t *gs;\n\n\tgs = BotGoalStateFromHandle(goalstate);\n\tif (!gs)\n\t\treturn qfalse;\n\tif (!gs->itemweightconfig)\n\t\treturn qfalse;\n\t//get the area the bot is in\n\tareanum = BotReachabilityArea(origin, gs->client);\n\t//if the bot is in solid or if the area the bot is in has no reachability links\n\tif (!areanum || !AAS_AreaReachability(areanum))\n\t{\n\t\t//use the last valid area the bot was in\n\t\tareanum = gs->lastreachabilityarea;\n\t} //end if\n\t//remember the last area with reachabilities the bot was in\n\tgs->lastreachabilityarea = areanum;\n\t//if still in solid\n\tif (!areanum)\n\t\treturn qfalse;\n\t//\n\tif (ltg) ltg_time = AAS_AreaTravelTimeToGoalArea(areanum, origin, ltg->areanum, travelflags);\n\telse ltg_time = 99999;\n\t//the item configuration\n\tic = itemconfig;\n\tif (!itemconfig)\n\t\treturn qfalse;\n\t//best weight and item so far\n\tbestweight = 0;\n\tbestitem = NULL;\n\tCom_Memset(&goal, 0, sizeof(bot_goal_t));\n\t//go through the items in the level\n\tfor (li = levelitems; li; li = li->next)\n\t{\n\t\tif (g_gametype == GT_SINGLE_PLAYER) {\n\t\t\tif (li->flags & IFL_NOTSINGLE)\n\t\t\t\tcontinue;\n\t\t}\n\t\telse if (g_gametype >= GT_TEAM) {\n\t\t\tif (li->flags & IFL_NOTTEAM)\n\t\t\t\tcontinue;\n\t\t}\n\t\telse {\n\t\t\tif (li->flags & IFL_NOTFREE)\n\t\t\t\tcontinue;\n\t\t}\n\t\tif (li->flags & IFL_NOTBOT)\n\t\t\tcontinue;\n\t\t//if the item is in a possible goal area\n\t\tif (!li->goalareanum)\n\t\t\tcontinue;\n\t\t//FIXME: is this a good thing? added this for items that never spawned into the game (f.i. CTF flags in obelisk)\n\t\tif (!li->entitynum && !(li->flags & IFL_ROAM))\n\t\t\tcontinue;\n\t\t//get the fuzzy weight function for this item\n\t\titeminfo = &ic->iteminfo[li->iteminfo];\n\t\tweightnum = gs->itemweightindex[iteminfo->number];\n\t\tif (weightnum < 0)\n\t\t\tcontinue;\n\t\t//\n#ifdef UNDECIDEDFUZZY\n\t\tweight = FuzzyWeightUndecided(inventory, gs->itemweightconfig, weightnum);\n#else\n\t\tweight = FuzzyWeight(inventory, gs->itemweightconfig, weightnum);\n#endif //UNDECIDEDFUZZY\n#ifdef DROPPEDWEIGHT\n\t\t//HACK: to make dropped items more attractive\n\t\tif (li->timeout)\n\t\t\tweight += droppedweight->value;\n#endif //DROPPEDWEIGHT\n\t\t//use weight scale for item_botroam\n\t\tif (li->flags & IFL_ROAM) weight *= li->weight;\n\t\t//\n\t\tif (weight > 0)\n\t\t{\n\t\t\t//get the travel time towards the goal area\n\t\t\tt = AAS_AreaTravelTimeToGoalArea(areanum, origin, li->goalareanum, travelflags);\n\t\t\t//if the goal is reachable\n\t\t\tif (t > 0 && t < maxtime)\n\t\t\t{\n\t\t\t\t//if this item won't respawn before we get there\n\t\t\t\tavoidtime = BotAvoidGoalTime(goalstate, li->number);\n\t\t\t\tif (avoidtime - t * 0.009 > 0)\n\t\t\t\t\tcontinue;\n\t\t\t\t//\n\t\t\t\tweight /= (float) t * TRAVELTIME_SCALE;\n\t\t\t\t//\n\t\t\t\tif (weight > bestweight)\n\t\t\t\t{\n\t\t\t\t\tt = 0;\n\t\t\t\t\tif (ltg && !li->timeout)\n\t\t\t\t\t{\n\t\t\t\t\t\t//get the travel time from the goal to the long term goal\n\t\t\t\t\t\tt = AAS_AreaTravelTimeToGoalArea(li->goalareanum, li->goalorigin, ltg->areanum, travelflags);\n\t\t\t\t\t} //end if\n\t\t\t\t\t//if the travel back is possible and doesn't take too long\n\t\t\t\t\tif (t <= ltg_time)\n\t\t\t\t\t{\n\t\t\t\t\t\tbestweight = weight;\n\t\t\t\t\t\tbestitem = li;\n\t\t\t\t\t} //end if\n\t\t\t\t} //end if\n\t\t\t} //end if\n\t\t} //end if\n\t} //end for\n\t//if no goal item found\n\tif (!bestitem)\n\t\treturn qfalse;\n\t//create a bot goal for this item\n\titeminfo = &ic->iteminfo[bestitem->iteminfo];\n\tVectorCopy(bestitem->goalorigin, goal.origin);\n\tVectorCopy(iteminfo->mins, goal.mins);\n\tVectorCopy(iteminfo->maxs, goal.maxs);\n\tgoal.areanum = bestitem->goalareanum;\n\tgoal.entitynum = bestitem->entitynum;\n\tgoal.number = bestitem->number;\n\tgoal.flags = GFL_ITEM;\n\tif (bestitem->timeout)\n\t\tgoal.flags |= GFL_DROPPED;\n\tif (bestitem->flags & IFL_ROAM)\n\t\tgoal.flags |= GFL_ROAM;\n\tgoal.iteminfo = bestitem->iteminfo;\n\t//if it's a dropped item\n\tif (bestitem->timeout)\n\t{\n\t\tavoidtime = AVOID_DROPPED_TIME;\n\t} //end if\n\telse\n\t{\n\t\tavoidtime = iteminfo->respawntime;\n\t\tif (!avoidtime)\n\t\t\tavoidtime = AVOID_DEFAULT_TIME;\n\t\tif (avoidtime < AVOID_MINIMUM_TIME)\n\t\t\tavoidtime = AVOID_MINIMUM_TIME;\n\t} //end else\n\t//add the chosen goal to the goals to avoid for a while\n\tBotAddToAvoidGoals(gs, bestitem->number, avoidtime);\n\t//push the goal on the stack\n\tBotPushGoal(goalstate, &goal);\n\t//\n\treturn qtrue;\n} //end of the function BotChooseNBGItem\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotTouchingGoal(vec3_t origin, bot_goal_t *goal)\n{\n\tint i;\n\tvec3_t boxmins, boxmaxs;\n\tvec3_t absmins, absmaxs;\n\tvec3_t safety_maxs = {0, 0, 0}; //{4, 4, 10};\n\tvec3_t safety_mins = {0, 0, 0}; //{-4, -4, 0};\n\n\tAAS_PresenceTypeBoundingBox(PRESENCE_NORMAL, boxmins, boxmaxs);\n\tVectorSubtract(goal->mins, boxmaxs, absmins);\n\tVectorSubtract(goal->maxs, boxmins, absmaxs);\n\tVectorAdd(absmins, goal->origin, absmins);\n\tVectorAdd(absmaxs, goal->origin, absmaxs);\n\t//make the box a little smaller for safety\n\tVectorSubtract(absmaxs, safety_maxs, absmaxs);\n\tVectorSubtract(absmins, safety_mins, absmins);\n\n\tfor (i = 0; i < 3; i++)\n\t{\n\t\tif (origin[i] < absmins[i] || origin[i] > absmaxs[i]) return qfalse;\n\t} //end for\n\treturn qtrue;\n} //end of the function BotTouchingGoal\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotItemGoalInVisButNotVisible(int viewer, vec3_t eye, vec3_t viewangles, bot_goal_t *goal)\n{\n\taas_entityinfo_t entinfo;\n\tbsp_trace_t trace;\n\tvec3_t middle;\n\n\tif (!(goal->flags & GFL_ITEM)) return qfalse;\n\t//\n\tVectorAdd(goal->mins, goal->mins, middle);\n\tVectorScale(middle, 0.5, middle);\n\tVectorAdd(goal->origin, middle, middle);\n\t//\n\ttrace = AAS_Trace(eye, NULL, NULL, middle, viewer, CONTENTS_SOLID);\n\t//if the goal middle point is visible\n\tif (trace.fraction >= 1)\n\t{\n\t\t//the goal entity number doesn't have to be valid\n\t\t//just assume it's valid\n\t\tif (goal->entitynum <= 0)\n\t\t\treturn qfalse;\n\t\t//\n\t\t//if the entity data isn't valid\n\t\tAAS_EntityInfo(goal->entitynum, &entinfo);\n\t\t//NOTE: for some wacko reason entities are sometimes\n\t\t// not updated\n\t\t//if (!entinfo.valid) return qtrue;\n\t\tif (entinfo.ltime < AAS_Time() - 0.5)\n\t\t\treturn qtrue;\n\t} //end if\n\treturn qfalse;\n} //end of the function BotItemGoalInVisButNotVisible\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotResetGoalState(int goalstate)\n{\n\tbot_goalstate_t *gs;\n\n\tgs = BotGoalStateFromHandle(goalstate);\n\tif (!gs) return;\n\tCom_Memset(gs->goalstack, 0, MAX_GOALSTACK * sizeof(bot_goal_t));\n\tgs->goalstacktop = 0;\n\tBotResetAvoidGoals(goalstate);\n} //end of the function BotResetGoalState\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotLoadItemWeights(int goalstate, char *filename)\n{\n\tbot_goalstate_t *gs;\n\n\tgs = BotGoalStateFromHandle(goalstate);\n\tif (!gs) return BLERR_CANNOTLOADITEMWEIGHTS;\n\t//load the weight configuration\n\tgs->itemweightconfig = ReadWeightConfig(filename);\n\tif (!gs->itemweightconfig)\n\t{\n\t\tbotimport.Print(PRT_FATAL, \"couldn't load weights\\n\");\n\t\treturn BLERR_CANNOTLOADITEMWEIGHTS;\n\t} //end if\n\t//if there's no item configuration\n\tif (!itemconfig) return BLERR_CANNOTLOADITEMWEIGHTS;\n\t//create the item weight index\n\tgs->itemweightindex = ItemWeightIndex(gs->itemweightconfig, itemconfig);\n\t//everything went ok\n\treturn BLERR_NOERROR;\n} //end of the function BotLoadItemWeights\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotFreeItemWeights(int goalstate)\n{\n\tbot_goalstate_t *gs;\n\n\tgs = BotGoalStateFromHandle(goalstate);\n\tif (!gs) return;\n\tif (gs->itemweightconfig) FreeWeightConfig(gs->itemweightconfig);\n\tif (gs->itemweightindex) FreeMemory(gs->itemweightindex);\n} //end of the function BotFreeItemWeights\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotAllocGoalState(int client)\n{\n\tint i;\n\n\tfor (i = 1; i <= MAX_CLIENTS; i++)\n\t{\n\t\tif (!botgoalstates[i])\n\t\t{\n\t\t\tbotgoalstates[i] = (bot_goalstate_t*) GetClearedMemory(sizeof(bot_goalstate_t));\n\t\t\tbotgoalstates[i]->client = client;\n\t\t\treturn i;\n\t\t} //end if\n\t} //end for\n\treturn 0;\n} //end of the function BotAllocGoalState\n//========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//========================================================================\nvoid BotFreeGoalState(int handle)\n{\n\tif (handle <= 0 || handle > MAX_CLIENTS)\n\t{\n\t\tbotimport.Print(PRT_FATAL, \"goal state handle %d out of range\\n\", handle);\n\t\treturn;\n\t} //end if\n\tif (!botgoalstates[handle])\n\t{\n\t\tbotimport.Print(PRT_FATAL, \"invalid goal state handle %d\\n\", handle);\n\t\treturn;\n\t} //end if\n\tBotFreeItemWeights(handle);\n\tFreeMemory(botgoalstates[handle]);\n\tbotgoalstates[handle] = NULL;\n} //end of the function BotFreeGoalState\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotSetupGoalAI(void)\n{\n\tchar *filename;\n\n\t//check if teamplay is on\n\tg_gametype = LibVarValue(\"g_gametype\", \"0\");\n\t//item configuration file\n\tfilename = LibVarString(\"itemconfig\", \"items.c\");\n\t//load the item configuration\n\titemconfig = LoadItemConfig(filename);\n\tif (!itemconfig)\n\t{\n\t\tbotimport.Print(PRT_FATAL, \"couldn't load item config\\n\");\n\t\treturn BLERR_CANNOTLOADITEMCONFIG;\n\t} //end if\n\t//\n\tdroppedweight = LibVar(\"droppedweight\", \"1000\");\n\t//everything went ok\n\treturn BLERR_NOERROR;\n} //end of the function BotSetupGoalAI\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotShutdownGoalAI(void)\n{\n\tint i;\n\n\tif (itemconfig) FreeMemory(itemconfig);\n\titemconfig = NULL;\n\tif (levelitemheap) FreeMemory(levelitemheap);\n\tlevelitemheap = NULL;\n\tfreelevelitems = NULL;\n\tlevelitems = NULL;\n\tnumlevelitems = 0;\n\n\tBotFreeInfoEntities();\n\n\tfor (i = 1; i <= MAX_CLIENTS; i++)\n\t{\n\t\tif (botgoalstates[i])\n\t\t{\n\t\t\tBotFreeGoalState(i);\n\t\t} //end if\n\t} //end for\n} //end of the function BotShutdownGoalAI\n"
  },
  {
    "path": "src/engine/botlib/be_ai_move.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tbe_ai_move.c\n *\n * desc:\t\tbot movement AI\n *\n * $Archive: /MissionPack/code/botlib/be_ai_move.c $\n *\n *****************************************************************************/\n\n#include \"../../game/q_shared.h\"\n#include \"l_memory.h\"\n#include \"l_libvar.h\"\n#include \"l_utils.h\"\n#include \"l_script.h\"\n#include \"l_precomp.h\"\n#include \"l_struct.h\"\n#include \"aasfile.h\"\n#include \"../../game/botlib.h\"\n#include \"../../game/be_aas.h\"\n#include \"be_aas_funcs.h\"\n#include \"be_interface.h\"\n\n#include \"../../game/be_ea.h\"\n#include \"../../game/be_ai_goal.h\"\n#include \"../../game/be_ai_move.h\"\n\n\n//#define DEBUG_AI_MOVE\n//#define DEBUG_ELEVATOR\n//#define DEBUG_GRAPPLE\n\n// bk001204 - redundant bot_avoidspot_t, see ../game/be_ai_move.h\n\n//movement state\n//NOTE: the moveflags MFL_ONGROUND, MFL_TELEPORTED, MFL_WATERJUMP and\n//\t\tMFL_GRAPPLEPULL must be set outside the movement code\ntypedef struct bot_movestate_s\n{\n\t//input vars (all set outside the movement code)\n\tvec3_t origin;\t\t\t\t\t\t\t\t//origin of the bot\n\tvec3_t velocity;\t\t\t\t\t\t\t//velocity of the bot\n\tvec3_t viewoffset;\t\t\t\t\t\t\t//view offset\n\tint entitynum;\t\t\t\t\t\t\t\t//entity number of the bot\n\tint client;\t\t\t\t\t\t\t\t\t//client number of the bot\n\tfloat thinktime;\t\t\t\t\t\t\t//time the bot thinks\n\tint presencetype;\t\t\t\t\t\t\t//presencetype of the bot\n\tvec3_t viewangles;\t\t\t\t\t\t\t//view angles of the bot\n\t//state vars\n\tint areanum;\t\t\t\t\t\t\t\t//area the bot is in\n\tint lastareanum;\t\t\t\t\t\t\t//last area the bot was in\n\tint lastgoalareanum;\t\t\t\t\t\t//last goal area number\n\tint lastreachnum;\t\t\t\t\t\t\t//last reachability number\n\tvec3_t lastorigin;\t\t\t\t\t\t\t//origin previous cycle\n\tint reachareanum;\t\t\t\t\t\t\t//area number of the reachabilty\n\tint moveflags;\t\t\t\t\t\t\t\t//movement flags\n\tint jumpreach;\t\t\t\t\t\t\t\t//set when jumped\n\tfloat grapplevisible_time;\t\t\t\t\t//last time the grapple was visible\n\tfloat lastgrappledist;\t\t\t\t\t\t//last distance to the grapple end\n\tfloat reachability_time;\t\t\t\t\t//time to use current reachability\n\tint avoidreach[MAX_AVOIDREACH];\t\t\t\t//reachabilities to avoid\n\tfloat avoidreachtimes[MAX_AVOIDREACH];\t\t//times to avoid the reachabilities\n\tint avoidreachtries[MAX_AVOIDREACH];\t\t//number of tries before avoiding\n\t//\n\tbot_avoidspot_t avoidspots[MAX_AVOIDSPOTS];\t//spots to avoid\n\tint numavoidspots;\n} bot_movestate_t;\n\n//used to avoid reachability links for some time after being used\n#define AVOIDREACH\n#define AVOIDREACH_TIME\t\t\t6\t\t//avoid links for 6 seconds after use\n#define AVOIDREACH_TRIES\t\t4\n//prediction times\n#define PREDICTIONTIME_JUMP\t3\t\t//in seconds\n#define PREDICTIONTIME_MOVE\t2\t\t//in seconds\n//weapon indexes for weapon jumping\n#define WEAPONINDEX_ROCKET_LAUNCHER\t\t5\n#define WEAPONINDEX_BFG\t\t\t\t\t9\n\n#define MODELTYPE_FUNC_PLAT\t\t1\n#define MODELTYPE_FUNC_BOB\t\t2\n#define MODELTYPE_FUNC_DOOR\t\t3\n#define MODELTYPE_FUNC_STATIC\t4\n\nlibvar_t *sv_maxstep;\nlibvar_t *sv_maxbarrier;\nlibvar_t *sv_gravity;\nlibvar_t *weapindex_rocketlauncher;\nlibvar_t *weapindex_bfg10k;\nlibvar_t *weapindex_grapple;\nlibvar_t *entitytypemissile;\nlibvar_t *offhandgrapple;\nlibvar_t *cmd_grappleoff;\nlibvar_t *cmd_grappleon;\n//type of model, func_plat or func_bobbing\nint modeltypes[MAX_MODELS];\n\nbot_movestate_t *botmovestates[MAX_CLIENTS+1];\n\n//========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//========================================================================\nint BotAllocMoveState(void)\n{\n\tint i;\n\n\tfor (i = 1; i <= MAX_CLIENTS; i++)\n\t{\n\t\tif (!botmovestates[i])\n\t\t{\n\t\t\tbotmovestates[i] = (bot_movestate_t*) GetClearedMemory(sizeof(bot_movestate_t));\n\t\t\treturn i;\n\t\t} //end if\n\t} //end for\n\treturn 0;\n} //end of the function BotAllocMoveState\n//========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//========================================================================\nvoid BotFreeMoveState(int handle)\n{\n\tif (handle <= 0 || handle > MAX_CLIENTS)\n\t{\n\t\tbotimport.Print(PRT_FATAL, \"move state handle %d out of range\\n\", handle);\n\t\treturn;\n\t} //end if\n\tif (!botmovestates[handle])\n\t{\n\t\tbotimport.Print(PRT_FATAL, \"invalid move state %d\\n\", handle);\n\t\treturn;\n\t} //end if\n\tFreeMemory(botmovestates[handle]);\n\tbotmovestates[handle] = NULL;\n} //end of the function BotFreeMoveState\n//========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//========================================================================\nbot_movestate_t *BotMoveStateFromHandle(int handle)\n{\n\tif (handle <= 0 || handle > MAX_CLIENTS)\n\t{\n\t\tbotimport.Print(PRT_FATAL, \"move state handle %d out of range\\n\", handle);\n\t\treturn NULL;\n\t} //end if\n\tif (!botmovestates[handle])\n\t{\n\t\tbotimport.Print(PRT_FATAL, \"invalid move state %d\\n\", handle);\n\t\treturn NULL;\n\t} //end if\n\treturn botmovestates[handle];\n} //end of the function BotMoveStateFromHandle\n//========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//========================================================================\nvoid BotInitMoveState(int handle, bot_initmove_t *initmove)\n{\n\tbot_movestate_t *ms;\n\n\tms = BotMoveStateFromHandle(handle);\n\tif (!ms) return;\n\tVectorCopy(initmove->origin, ms->origin);\n\tVectorCopy(initmove->velocity, ms->velocity);\n\tVectorCopy(initmove->viewoffset, ms->viewoffset);\n\tms->entitynum = initmove->entitynum;\n\tms->client = initmove->client;\n\tms->thinktime = initmove->thinktime;\n\tms->presencetype = initmove->presencetype;\n\tVectorCopy(initmove->viewangles, ms->viewangles);\n\t//\n\tms->moveflags &= ~MFL_ONGROUND;\n\tif (initmove->or_moveflags & MFL_ONGROUND) ms->moveflags |= MFL_ONGROUND;\n\tms->moveflags &= ~MFL_TELEPORTED;\t\n\tif (initmove->or_moveflags & MFL_TELEPORTED) ms->moveflags |= MFL_TELEPORTED;\n\tms->moveflags &= ~MFL_WATERJUMP;\n\tif (initmove->or_moveflags & MFL_WATERJUMP) ms->moveflags |= MFL_WATERJUMP;\n\tms->moveflags &= ~MFL_WALK;\n\tif (initmove->or_moveflags & MFL_WALK) ms->moveflags |= MFL_WALK;\n\tms->moveflags &= ~MFL_GRAPPLEPULL;\n\tif (initmove->or_moveflags & MFL_GRAPPLEPULL) ms->moveflags |= MFL_GRAPPLEPULL;\n} //end of the function BotInitMoveState\n//========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//========================================================================\nfloat AngleDiff(float ang1, float ang2)\n{\n\tfloat diff;\n\n\tdiff = ang1 - ang2;\n\tif (ang1 > ang2)\n\t{\n\t\tif (diff > 180.0) diff -= 360.0;\n\t} //end if\n\telse\n\t{\n\t\tif (diff < -180.0) diff += 360.0;\n\t} //end else\n\treturn diff;\n} //end of the function AngleDiff\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotFuzzyPointReachabilityArea(vec3_t origin)\n{\n\tint firstareanum, j, x, y, z;\n\tint areas[10], numareas, areanum, bestareanum;\n\tfloat dist, bestdist;\n\tvec3_t points[10], v, end;\n\n\tfirstareanum = 0;\n\tareanum = AAS_PointAreaNum(origin);\n\tif (areanum)\n\t{\n\t\tfirstareanum = areanum;\n\t\tif (AAS_AreaReachability(areanum)) return areanum;\n\t} //end if\n\tVectorCopy(origin, end);\n\tend[2] += 4;\n\tnumareas = AAS_TraceAreas(origin, end, areas, points, 10);\n\tfor (j = 0; j < numareas; j++)\n\t{\n\t\tif (AAS_AreaReachability(areas[j])) return areas[j];\n\t} //end for\n\tbestdist = 999999;\n\tbestareanum = 0;\n\tfor (z = 1; z >= -1; z -= 1)\n\t{\n\t\tfor (x = 1; x >= -1; x -= 1)\n\t\t{\n\t\t\tfor (y = 1; y >= -1; y -= 1)\n\t\t\t{\n\t\t\t\tVectorCopy(origin, end);\n\t\t\t\tend[0] += x * 8;\n\t\t\t\tend[1] += y * 8;\n\t\t\t\tend[2] += z * 12;\n\t\t\t\tnumareas = AAS_TraceAreas(origin, end, areas, points, 10);\n\t\t\t\tfor (j = 0; j < numareas; j++)\n\t\t\t\t{\n\t\t\t\t\tif (AAS_AreaReachability(areas[j]))\n\t\t\t\t\t{\n\t\t\t\t\t\tVectorSubtract(points[j], origin, v);\n\t\t\t\t\t\tdist = VectorLength(v);\n\t\t\t\t\t\tif (dist < bestdist)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tbestareanum = areas[j];\n\t\t\t\t\t\t\tbestdist = dist;\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t} //end if\n\t\t\t\t\tif (!firstareanum) firstareanum = areas[j];\n\t\t\t\t} //end for\n\t\t\t} //end for\n\t\t} //end for\n\t\tif (bestareanum) return bestareanum;\n\t} //end for\n\treturn firstareanum;\n} //end of the function BotFuzzyPointReachabilityArea\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotReachabilityArea(vec3_t origin, int client)\n{\n\tint modelnum, modeltype, reachnum, areanum;\n\taas_reachability_t reach;\n\tvec3_t org, end, mins, maxs, up = {0, 0, 1};\n\tbsp_trace_t bsptrace;\n\taas_trace_t trace;\n\n\t//check if the bot is standing on something\n\tAAS_PresenceTypeBoundingBox(PRESENCE_CROUCH, mins, maxs);\n\tVectorMA(origin, -3, up, end);\n\tbsptrace = AAS_Trace(origin, mins, maxs, end, client, CONTENTS_SOLID|CONTENTS_PLAYERCLIP);\n\tif (!bsptrace.startsolid && bsptrace.fraction < 1 && bsptrace.ent != ENTITYNUM_NONE)\n\t{\n\t\t//if standing on the world the bot should be in a valid area\n\t\tif (bsptrace.ent == ENTITYNUM_WORLD)\n\t\t{\n\t\t\treturn BotFuzzyPointReachabilityArea(origin);\n\t\t} //end if\n\n\t\tmodelnum = AAS_EntityModelindex(bsptrace.ent);\n\t\tmodeltype = modeltypes[modelnum];\n\n\t\t//if standing on a func_plat or func_bobbing then the bot is assumed to be\n\t\t//in the area the reachability points to\n\t\tif (modeltype == MODELTYPE_FUNC_PLAT || modeltype == MODELTYPE_FUNC_BOB)\n\t\t{\n\t\t\treachnum = AAS_NextModelReachability(0, modelnum);\n\t\t\tif (reachnum)\n\t\t\t{\n\t\t\t\tAAS_ReachabilityFromNum(reachnum, &reach);\n\t\t\t\treturn reach.areanum;\n\t\t\t} //end if\n\t\t} //end else if\n\n\t\t//if the bot is swimming the bot should be in a valid area\n\t\tif (AAS_Swimming(origin))\n\t\t{\n\t\t\treturn BotFuzzyPointReachabilityArea(origin);\n\t\t} //end if\n\t\t//\n\t\tareanum = BotFuzzyPointReachabilityArea(origin);\n\t\t//if the bot is in an area with reachabilities\n\t\tif (areanum && AAS_AreaReachability(areanum)) return areanum;\n\t\t//trace down till the ground is hit because the bot is standing on some other entity\n\t\tVectorCopy(origin, org);\n\t\tVectorCopy(org, end);\n\t\tend[2] -= 800;\n\t\ttrace = AAS_TraceClientBBox(org, end, PRESENCE_CROUCH, -1);\n\t\tif (!trace.startsolid)\n\t\t{\n\t\t\tVectorCopy(trace.endpos, org);\n\t\t} //end if\n\t\t//\n\t\treturn BotFuzzyPointReachabilityArea(org);\n\t} //end if\n\t//\n\treturn BotFuzzyPointReachabilityArea(origin);\n} //end of the function BotReachabilityArea\n//===========================================================================\n// returns the reachability area the bot is in\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\n/*\nint BotReachabilityArea(vec3_t origin, int testground)\n{\n\tint firstareanum, i, j, x, y, z;\n\tint areas[10], numareas, areanum, bestareanum;\n\tfloat dist, bestdist;\n\tvec3_t org, end, points[10], v;\n\taas_trace_t trace;\n\n\tfirstareanum = 0;\n\tfor (i = 0; i < 2; i++)\n\t{\n\t\tVectorCopy(origin, org);\n\t\t//if test at the ground (used when bot is standing on an entity)\n\t\tif (i > 0)\n\t\t{\n\t\t\tVectorCopy(origin, end);\n\t\t\tend[2] -= 800;\n\t\t\ttrace = AAS_TraceClientBBox(origin, end, PRESENCE_CROUCH, -1);\n\t\t\tif (!trace.startsolid)\n\t\t\t{\n\t\t\t\tVectorCopy(trace.endpos, org);\n\t\t\t} //end if\n\t\t} //end if\n\n\t\tfirstareanum = 0;\n\t\tareanum = AAS_PointAreaNum(org);\n\t\tif (areanum)\n\t\t{\n\t\t\tfirstareanum = areanum;\n\t\t\tif (AAS_AreaReachability(areanum)) return areanum;\n\t\t} //end if\n\t\tbestdist = 999999;\n\t\tbestareanum = 0;\n\t\tfor (z = 1; z >= -1; z -= 1)\n\t\t{\n\t\t\tfor (x = 1; x >= -1; x -= 1)\n\t\t\t{\n\t\t\t\tfor (y = 1; y >= -1; y -= 1)\n\t\t\t\t{\n\t\t\t\t\tVectorCopy(org, end);\n\t\t\t\t\tend[0] += x * 8;\n\t\t\t\t\tend[1] += y * 8;\n\t\t\t\t\tend[2] += z * 12;\n\t\t\t\t\tnumareas = AAS_TraceAreas(org, end, areas, points, 10);\n\t\t\t\t\tfor (j = 0; j < numareas; j++)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (AAS_AreaReachability(areas[j]))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tVectorSubtract(points[j], org, v);\n\t\t\t\t\t\t\tdist = VectorLength(v);\n\t\t\t\t\t\t\tif (dist < bestdist)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tbestareanum = areas[j];\n\t\t\t\t\t\t\t\tbestdist = dist;\n\t\t\t\t\t\t\t} //end if\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t} //end for\n\t\t\t\t} //end for\n\t\t\t} //end for\n\t\t\tif (bestareanum) return bestareanum;\n\t\t} //end for\n\t\tif (!testground) break;\n\t} //end for\n//#ifdef DEBUG\n\t//botimport.Print(PRT_MESSAGE, \"no reachability area\\n\");\n//#endif //DEBUG\n\treturn firstareanum;\n} //end of the function BotReachabilityArea*/\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotOnMover(vec3_t origin, int entnum, aas_reachability_t *reach)\n{\n\tint i, modelnum;\n\tvec3_t mins, maxs, modelorigin, org, end;\n\tvec3_t angles = {0, 0, 0};\n\tvec3_t boxmins = {-16, -16, -8}, boxmaxs = {16, 16, 8};\n\tbsp_trace_t trace;\n\n\tmodelnum = reach->facenum & 0x0000FFFF;\n\t//get some bsp model info\n\tAAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, NULL);\n\t//\n\tif (!AAS_OriginOfMoverWithModelNum(modelnum, modelorigin))\n\t{\n\t\tbotimport.Print(PRT_MESSAGE, \"no entity with model %d\\n\", modelnum);\n\t\treturn qfalse;\n\t} //end if\n\t//\n\tfor (i = 0; i < 2; i++)\n\t{\n\t\tif (origin[i] > modelorigin[i] + maxs[i] + 16) return qfalse;\n\t\tif (origin[i] < modelorigin[i] + mins[i] - 16) return qfalse;\n\t} //end for\n\t//\n\tVectorCopy(origin, org);\n\torg[2] += 24;\n\tVectorCopy(origin, end);\n\tend[2] -= 48;\n\t//\n\ttrace = AAS_Trace(org, boxmins, boxmaxs, end, entnum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP);\n\tif (!trace.startsolid && !trace.allsolid)\n\t{\n\t\t//NOTE: the reachability face number is the model number of the elevator\n\t\tif (trace.ent != ENTITYNUM_NONE && AAS_EntityModelNum(trace.ent) == modelnum)\n\t\t{\n\t\t\treturn qtrue;\n\t\t} //end if\n\t} //end if\n\treturn qfalse;\n} //end of the function BotOnMover\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint MoverDown(aas_reachability_t *reach)\n{\n\tint modelnum;\n\tvec3_t mins, maxs, origin;\n\tvec3_t angles = {0, 0, 0};\n\n\tmodelnum = reach->facenum & 0x0000FFFF;\n\t//get some bsp model info\n\tAAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, origin);\n\t//\n\tif (!AAS_OriginOfMoverWithModelNum(modelnum, origin))\n\t{\n\t\tbotimport.Print(PRT_MESSAGE, \"no entity with model %d\\n\", modelnum);\n\t\treturn qfalse;\n\t} //end if\n\t//if the top of the plat is below the reachability start point\n\tif (origin[2] + maxs[2] < reach->start[2]) return qtrue;\n\treturn qfalse;\n} //end of the function MoverDown\n//========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//========================================================================\nvoid BotSetBrushModelTypes(void)\n{\n\tint ent, modelnum;\n\tchar classname[MAX_EPAIRKEY], model[MAX_EPAIRKEY];\n\n\tCom_Memset(modeltypes, 0, MAX_MODELS * sizeof(int));\n\t//\n\tfor (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent))\n\t{\n\t\tif (!AAS_ValueForBSPEpairKey(ent, \"classname\", classname, MAX_EPAIRKEY)) continue;\n\t\tif (!AAS_ValueForBSPEpairKey(ent, \"model\", model, MAX_EPAIRKEY)) continue;\n\t\tif (model[0]) modelnum = atoi(model+1);\n\t\telse modelnum = 0;\n\n\t\tif (modelnum < 0 || modelnum > MAX_MODELS)\n\t\t{\n\t\t\tbotimport.Print(PRT_MESSAGE, \"entity %s model number out of range\\n\", classname);\n\t\t\tcontinue;\n\t\t} //end if\n\n\t\tif (!Q_stricmp(classname, \"func_bobbing\"))\n\t\t\tmodeltypes[modelnum] = MODELTYPE_FUNC_BOB;\n\t\telse if (!Q_stricmp(classname, \"func_plat\"))\n\t\t\tmodeltypes[modelnum] = MODELTYPE_FUNC_PLAT;\n\t\telse if (!Q_stricmp(classname, \"func_door\"))\n\t\t\tmodeltypes[modelnum] = MODELTYPE_FUNC_DOOR;\n\t\telse if (!Q_stricmp(classname, \"func_static\"))\n\t\t\tmodeltypes[modelnum] = MODELTYPE_FUNC_STATIC;\n\t} //end for\n} //end of the function BotSetBrushModelTypes\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotOnTopOfEntity(bot_movestate_t *ms)\n{\n\tvec3_t mins, maxs, end, up = {0, 0, 1};\n\tbsp_trace_t trace;\n\n\tAAS_PresenceTypeBoundingBox(ms->presencetype, mins, maxs);\n\tVectorMA(ms->origin, -3, up, end);\n\ttrace = AAS_Trace(ms->origin, mins, maxs, end, ms->entitynum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP);\n\tif (!trace.startsolid && (trace.ent != ENTITYNUM_WORLD && trace.ent != ENTITYNUM_NONE) )\n\t{\n\t\treturn trace.ent;\n\t} //end if\n\treturn -1;\n} //end of the function BotOnTopOfEntity\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotValidTravel(vec3_t origin, aas_reachability_t *reach, int travelflags)\n{\n\t//if the reachability uses an unwanted travel type\n\tif (AAS_TravelFlagForType(reach->traveltype) & ~travelflags) return qfalse;\n\t//don't go into areas with bad travel types\n\tif (AAS_AreaContentsTravelFlags(reach->areanum) & ~travelflags) return qfalse;\n\treturn qtrue;\n} //end of the function BotValidTravel\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotAddToAvoidReach(bot_movestate_t *ms, int number, float avoidtime)\n{\n\tint i;\n\n\tfor (i = 0; i < MAX_AVOIDREACH; i++)\n\t{\n\t\tif (ms->avoidreach[i] == number)\n\t\t{\n\t\t\tif (ms->avoidreachtimes[i] > AAS_Time()) ms->avoidreachtries[i]++;\n\t\t\telse ms->avoidreachtries[i] = 1;\n\t\t\tms->avoidreachtimes[i] = AAS_Time() + avoidtime;\n\t\t\treturn;\n\t\t} //end if\n\t} //end for\n\t//add the reachability to the reachabilities to avoid for a while\n\tfor (i = 0; i < MAX_AVOIDREACH; i++)\n\t{\n\t\tif (ms->avoidreachtimes[i] < AAS_Time())\n\t\t{\n\t\t\tms->avoidreach[i] = number;\n\t\t\tms->avoidreachtimes[i] = AAS_Time() + avoidtime;\n\t\t\tms->avoidreachtries[i] = 1;\n\t\t\treturn;\n\t\t} //end if\n\t} //end for\n} //end of the function BotAddToAvoidReach\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nfloat DistanceFromLineSquared(vec3_t p, vec3_t lp1, vec3_t lp2)\n{\n\tvec3_t proj, dir;\n\tint j;\n\n\tAAS_ProjectPointOntoVector(p, lp1, lp2, proj);\n\tfor (j = 0; j < 3; j++)\n\t\tif ((proj[j] > lp1[j] && proj[j] > lp2[j]) ||\n\t\t\t(proj[j] < lp1[j] && proj[j] < lp2[j]))\n\t\t\tbreak;\n\tif (j < 3) {\n\t\tif (fabs(proj[j] - lp1[j]) < fabs(proj[j] - lp2[j]))\n\t\t\tVectorSubtract(p, lp1, dir);\n\t\telse\n\t\t\tVectorSubtract(p, lp2, dir);\n\t\treturn VectorLengthSquared(dir);\n\t}\n\tVectorSubtract(p, proj, dir);\n\treturn VectorLengthSquared(dir);\n} //end of the function DistanceFromLineSquared\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nfloat VectorDistanceSquared(vec3_t p1, vec3_t p2)\n{\n\tvec3_t dir;\n\tVectorSubtract(p2, p1, dir);\n\treturn VectorLengthSquared(dir);\n} //end of the function VectorDistanceSquared\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotAvoidSpots(vec3_t origin, aas_reachability_t *reach, bot_avoidspot_t *avoidspots, int numavoidspots)\n{\n\tint checkbetween, i, type;\n\tfloat squareddist, squaredradius;\n\n\tswitch(reach->traveltype & TRAVELTYPE_MASK)\n\t{\n\t\tcase TRAVEL_WALK: checkbetween = qtrue; break;\n\t\tcase TRAVEL_CROUCH: checkbetween = qtrue; break;\n\t\tcase TRAVEL_BARRIERJUMP: checkbetween = qtrue; break;\n\t\tcase TRAVEL_LADDER: checkbetween = qtrue; break;\n\t\tcase TRAVEL_WALKOFFLEDGE: checkbetween = qfalse; break;\n\t\tcase TRAVEL_JUMP: checkbetween = qfalse; break;\n\t\tcase TRAVEL_SWIM: checkbetween = qtrue; break;\n\t\tcase TRAVEL_WATERJUMP: checkbetween = qtrue; break;\n\t\tcase TRAVEL_TELEPORT: checkbetween = qfalse; break;\n\t\tcase TRAVEL_ELEVATOR: checkbetween = qfalse; break;\n\t\tcase TRAVEL_GRAPPLEHOOK: checkbetween = qfalse; break;\n\t\tcase TRAVEL_ROCKETJUMP: checkbetween = qfalse; break;\n\t\tcase TRAVEL_BFGJUMP: checkbetween = qfalse; break;\n\t\tcase TRAVEL_JUMPPAD: checkbetween = qfalse; break;\n\t\tcase TRAVEL_FUNCBOB: checkbetween = qfalse; break;\n\t\tdefault: checkbetween = qtrue; break;\n\t} //end switch\n\n\ttype = AVOID_CLEAR;\n\tfor (i = 0; i < numavoidspots; i++)\n\t{\n\t\tsquaredradius = Square(avoidspots[i].radius);\n\t\tsquareddist = DistanceFromLineSquared(avoidspots[i].origin, origin, reach->start);\n\t\t// if moving towards the avoid spot\n\t\tif (squareddist < squaredradius &&\n\t\t\tVectorDistanceSquared(avoidspots[i].origin, origin) > squareddist)\n\t\t{\n\t\t\ttype = avoidspots[i].type;\n\t\t} //end if\n\t\telse if (checkbetween) {\n\t\t\tsquareddist = DistanceFromLineSquared(avoidspots[i].origin, reach->start, reach->end);\n\t\t\t// if moving towards the avoid spot\n\t\t\tif (squareddist < squaredradius &&\n\t\t\t\tVectorDistanceSquared(avoidspots[i].origin, reach->start) > squareddist)\n\t\t\t{\n\t\t\t\ttype = avoidspots[i].type;\n\t\t\t} //end if\n\t\t} //end if\n\t\telse\n\t\t{\n\t\t\tVectorDistanceSquared(avoidspots[i].origin, reach->end);\n\t\t\t// if the reachability leads closer to the avoid spot\n\t\t\tif (squareddist < squaredradius && \n\t\t\t\tVectorDistanceSquared(avoidspots[i].origin, reach->start) > squareddist)\n\t\t\t{\n\t\t\t\ttype = avoidspots[i].type;\n\t\t\t} //end if\n\t\t} //end else\n\t\tif (type == AVOID_ALWAYS)\n\t\t\treturn type;\n\t} //end for\n\treturn type;\n} //end of the function BotAvoidSpots\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotAddAvoidSpot(int movestate, vec3_t origin, float radius, int type)\n{\n\tbot_movestate_t *ms;\n\n\tms = BotMoveStateFromHandle(movestate);\n\tif (!ms) return;\n\tif (type == AVOID_CLEAR)\n\t{\n\t\tms->numavoidspots = 0;\n\t\treturn;\n\t} //end if\n\n\tif (ms->numavoidspots >= MAX_AVOIDSPOTS)\n\t\treturn;\n\tVectorCopy(origin, ms->avoidspots[ms->numavoidspots].origin);\n\tms->avoidspots[ms->numavoidspots].radius = radius;\n\tms->avoidspots[ms->numavoidspots].type = type;\n\tms->numavoidspots++;\n} //end of the function BotAddAvoidSpot\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotGetReachabilityToGoal(vec3_t origin, int areanum,\n\t\t\t\t\t\t\t\t\t  int lastgoalareanum, int lastareanum,\n\t\t\t\t\t\t\t\t\t  int *avoidreach, float *avoidreachtimes, int *avoidreachtries,\n\t\t\t\t\t\t\t\t\t  bot_goal_t *goal, int travelflags, int movetravelflags,\n\t\t\t\t\t\t\t\t\t  struct bot_avoidspot_s *avoidspots, int numavoidspots, int *flags)\n{\n\tint i, t, besttime, bestreachnum, reachnum;\n\taas_reachability_t reach;\n\n\t//if not in a valid area\n\tif (!areanum) return 0;\n\t//\n\tif (AAS_AreaDoNotEnter(areanum) || AAS_AreaDoNotEnter(goal->areanum))\n\t{\n\t\ttravelflags |= TFL_DONOTENTER;\n\t\tmovetravelflags |= TFL_DONOTENTER;\n\t} //end if\n\t//use the routing to find the next area to go to\n\tbesttime = 0;\n\tbestreachnum = 0;\n\t//\n\tfor (reachnum = AAS_NextAreaReachability(areanum, 0); reachnum;\n\t\treachnum = AAS_NextAreaReachability(areanum, reachnum))\n\t{\n#ifdef AVOIDREACH\n\t\t//check if it isn't an reachability to avoid\n\t\tfor (i = 0; i < MAX_AVOIDREACH; i++)\n\t\t{\n\t\t\tif (avoidreach[i] == reachnum && avoidreachtimes[i] >= AAS_Time()) break;\n\t\t} //end for\n\t\tif (i != MAX_AVOIDREACH && avoidreachtries[i] > AVOIDREACH_TRIES)\n\t\t{\n#ifdef DEBUG\n\t\t\tif (bot_developer)\n\t\t\t{\n\t\t\t\tbotimport.Print(PRT_MESSAGE, \"avoiding reachability %d\\n\", avoidreach[i]);\n\t\t\t} //end if\n#endif //DEBUG\n\t\t\tcontinue;\n\t\t} //end if\n#endif //AVOIDREACH\n\t\t//get the reachability from the number\n\t\tAAS_ReachabilityFromNum(reachnum, &reach);\n\t\t//NOTE: do not go back to the previous area if the goal didn't change\n\t\t//NOTE: is this actually avoidance of local routing minima between two areas???\n\t\tif (lastgoalareanum == goal->areanum && reach.areanum == lastareanum) continue;\n\t\t//if (AAS_AreaContentsTravelFlags(reach.areanum) & ~travelflags) continue;\n\t\t//if the travel isn't valid\n\t\tif (!BotValidTravel(origin, &reach, movetravelflags)) continue;\n\t\t//get the travel time\n\t\tt = AAS_AreaTravelTimeToGoalArea(reach.areanum, reach.end, goal->areanum, travelflags);\n\t\t//if the goal area isn't reachable from the reachable area\n\t\tif (!t) continue;\n\t\t//if the bot should not use this reachability to avoid bad spots\n\t\tif (BotAvoidSpots(origin, &reach, avoidspots, numavoidspots)) {\n\t\t\tif (flags) {\n\t\t\t\t*flags |= MOVERESULT_BLOCKEDBYAVOIDSPOT;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\t//add the travel time towards the area\n\t\tt += reach.traveltime;// + AAS_AreaTravelTime(areanum, origin, reach.start);\n\t\t//if the travel time is better than the ones already found\n\t\tif (!besttime || t < besttime)\n\t\t{\n\t\t\tbesttime = t;\n\t\t\tbestreachnum = reachnum;\n\t\t} //end if\n\t} //end for\n\t//\n\treturn bestreachnum;\n} //end of the function BotGetReachabilityToGoal\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotAddToTarget(vec3_t start, vec3_t end, float maxdist, float *dist, vec3_t target)\n{\n\tvec3_t dir;\n\tfloat curdist;\n\n\tVectorSubtract(end, start, dir);\n\tcurdist = VectorNormalize(dir);\n\tif (*dist + curdist < maxdist)\n\t{\n\t\tVectorCopy(end, target);\n\t\t*dist += curdist;\n\t\treturn qfalse;\n\t} //end if\n\telse\n\t{\n\t\tVectorMA(start, maxdist - *dist, dir, target);\n\t\t*dist = maxdist;\n\t\treturn qtrue;\n\t} //end else\n} //end of the function BotAddToTarget\n\nint BotMovementViewTarget(int movestate, bot_goal_t *goal, int travelflags, float lookahead, vec3_t target)\n{\n\taas_reachability_t reach;\n\tint reachnum, lastareanum;\n\tbot_movestate_t *ms;\n\tvec3_t end;\n\tfloat dist;\n\n\tms = BotMoveStateFromHandle(movestate);\n\tif (!ms) return qfalse;\n\treachnum = 0;\n\t//if the bot has no goal or no last reachability\n\tif (!ms->lastreachnum || !goal) return qfalse;\n\n\treachnum = ms->lastreachnum;\n\tVectorCopy(ms->origin, end);\n\tlastareanum = ms->lastareanum;\n\tdist = 0;\n\twhile(reachnum && dist < lookahead)\n\t{\n\t\tAAS_ReachabilityFromNum(reachnum, &reach);\n\t\tif (BotAddToTarget(end, reach.start, lookahead, &dist, target)) return qtrue;\n\t\t//never look beyond teleporters\n\t\tif ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_TELEPORT) return qtrue;\n\t\t//never look beyond the weapon jump point\n\t\tif ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_ROCKETJUMP) return qtrue;\n\t\tif ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_BFGJUMP) return qtrue;\n\t\t//don't add jump pad distances\n\t\tif ((reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_JUMPPAD &&\n\t\t\t(reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_ELEVATOR &&\n\t\t\t(reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_FUNCBOB)\n\t\t{\n\t\t\tif (BotAddToTarget(reach.start, reach.end, lookahead, &dist, target)) return qtrue;\n\t\t} //end if\n\t\treachnum = BotGetReachabilityToGoal(reach.end, reach.areanum,\n\t\t\t\t\t\tms->lastgoalareanum, lastareanum,\n\t\t\t\t\t\t\tms->avoidreach, ms->avoidreachtimes, ms->avoidreachtries,\n\t\t\t\t\t\t\t\t\tgoal, travelflags, travelflags, NULL, 0, NULL);\n\t\tVectorCopy(reach.end, end);\n\t\tlastareanum = reach.areanum;\n\t\tif (lastareanum == goal->areanum)\n\t\t{\n\t\t\tBotAddToTarget(reach.end, goal->origin, lookahead, &dist, target);\n\t\t\treturn qtrue;\n\t\t} //end if\n\t} //end while\n\t//\n\treturn qfalse;\n} //end of the function BotMovementViewTarget\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotVisible(int ent, vec3_t eye, vec3_t target)\n{\n\tbsp_trace_t trace;\n\n\ttrace = AAS_Trace(eye, NULL, NULL, target, ent, CONTENTS_SOLID|CONTENTS_PLAYERCLIP);\n\tif (trace.fraction >= 1) return qtrue;\n\treturn qfalse;\n} //end of the function BotVisible\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotPredictVisiblePosition(vec3_t origin, int areanum, bot_goal_t *goal, int travelflags, vec3_t target)\n{\n\taas_reachability_t reach;\n\tint reachnum, lastgoalareanum, lastareanum, i;\n\tint avoidreach[MAX_AVOIDREACH];\n\tfloat avoidreachtimes[MAX_AVOIDREACH];\n\tint avoidreachtries[MAX_AVOIDREACH];\n\tvec3_t end;\n\n\t//if the bot has no goal or no last reachability\n\tif (!goal) return qfalse;\n\t//if the areanum is not valid\n\tif (!areanum) return qfalse;\n\t//if the goal areanum is not valid\n\tif (!goal->areanum) return qfalse;\n\n\tCom_Memset(avoidreach, 0, MAX_AVOIDREACH * sizeof(int));\n\tlastgoalareanum = goal->areanum;\n\tlastareanum = areanum;\n\tVectorCopy(origin, end);\n\t//only do 20 hops\n\tfor (i = 0; i < 20 && (areanum != goal->areanum); i++)\n\t{\n\t\t//\n\t\treachnum = BotGetReachabilityToGoal(end, areanum,\n\t\t\t\t\t\tlastgoalareanum, lastareanum,\n\t\t\t\t\t\t\tavoidreach, avoidreachtimes, avoidreachtries,\n\t\t\t\t\t\t\t\t\tgoal, travelflags, travelflags, NULL, 0, NULL);\n\t\tif (!reachnum) return qfalse;\n\t\tAAS_ReachabilityFromNum(reachnum, &reach);\n\t\t//\n\t\tif (BotVisible(goal->entitynum, goal->origin, reach.start))\n\t\t{\n\t\t\tVectorCopy(reach.start, target);\n\t\t\treturn qtrue;\n\t\t} //end if\n\t\t//\n\t\tif (BotVisible(goal->entitynum, goal->origin, reach.end))\n\t\t{\n\t\t\tVectorCopy(reach.end, target);\n\t\t\treturn qtrue;\n\t\t} //end if\n\t\t//\n\t\tif (reach.areanum == goal->areanum)\n\t\t{\n\t\t\tVectorCopy(reach.end, target);\n\t\t\treturn qtrue;\n\t\t} //end if\n\t\t//\n\t\tlastareanum = areanum;\n\t\tareanum = reach.areanum;\n\t\tVectorCopy(reach.end, end);\n\t\t//\n\t} //end while\n\t//\n\treturn qfalse;\n} //end of the function BotPredictVisiblePosition\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid MoverBottomCenter(aas_reachability_t *reach, vec3_t bottomcenter)\n{\n\tint modelnum;\n\tvec3_t mins, maxs, origin, mids;\n\tvec3_t angles = {0, 0, 0};\n\n\tmodelnum = reach->facenum & 0x0000FFFF;\n\t//get some bsp model info\n\tAAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, origin);\n\t//\n\tif (!AAS_OriginOfMoverWithModelNum(modelnum, origin))\n\t{\n\t\tbotimport.Print(PRT_MESSAGE, \"no entity with model %d\\n\", modelnum);\n\t} //end if\n\t//get a point just above the plat in the bottom position\n\tVectorAdd(mins, maxs, mids);\n\tVectorMA(origin, 0.5, mids, bottomcenter);\n\tbottomcenter[2] = reach->start[2];\n} //end of the function MoverBottomCenter\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nfloat BotGapDistance(vec3_t origin, vec3_t hordir, int entnum)\n{\n\tfloat dist, startz;\n\tvec3_t start, end;\n\taas_trace_t trace;\n\n\t//do gap checking\n\tstartz = origin[2];\n\t//this enables walking down stairs more fluidly\n\t{\n\t\tVectorCopy(origin, start);\n\t\tVectorCopy(origin, end);\n\t\tend[2] -= 60;\n\t\ttrace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, entnum);\n\t\tif (trace.fraction >= 1) return 1;\n\t\tstartz = trace.endpos[2] + 1;\n\t}\n\t//\n\tfor (dist = 8; dist <= 100; dist += 8)\n\t{\n\t\tVectorMA(origin, dist, hordir, start);\n\t\tstart[2] = startz + 24;\n\t\tVectorCopy(start, end);\n\t\tend[2] -= 48 + sv_maxbarrier->value;\n\t\ttrace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, entnum);\n\t\t//if solid is found the bot can't walk any further and fall into a gap\n\t\tif (!trace.startsolid)\n\t\t{\n\t\t\t//if it is a gap\n\t\t\tif (trace.endpos[2] < startz - sv_maxstep->value - 8)\n\t\t\t{\n\t\t\t\tVectorCopy(trace.endpos, end);\n\t\t\t\tend[2] -= 20;\n\t\t\t\tif (AAS_PointContents(end) & CONTENTS_WATER) break;\n\t\t\t\t//if a gap is found slow down\n\t\t\t\t//botimport.Print(PRT_MESSAGE, \"gap at %f\\n\", dist);\n\t\t\t\treturn dist;\n\t\t\t} //end if\n\t\t\tstartz = trace.endpos[2];\n\t\t} //end if\n\t} //end for\n\treturn 0;\n} //end of the function BotGapDistance\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotCheckBarrierJump(bot_movestate_t *ms, vec3_t dir, float speed)\n{\n\tvec3_t start, hordir, end;\n\taas_trace_t trace;\n\n\tVectorCopy(ms->origin, end);\n\tend[2] += sv_maxbarrier->value;\n\t//trace right up\n\ttrace = AAS_TraceClientBBox(ms->origin, end, PRESENCE_NORMAL, ms->entitynum);\n\t//this shouldn't happen... but we check anyway\n\tif (trace.startsolid) return qfalse;\n\t//if very low ceiling it isn't possible to jump up to a barrier\n\tif (trace.endpos[2] - ms->origin[2] < sv_maxstep->value) return qfalse;\n\t//\n\thordir[0] = dir[0];\n\thordir[1] = dir[1];\n\thordir[2] = 0;\n\tVectorNormalize(hordir);\n\tVectorMA(ms->origin, ms->thinktime * speed * 0.5, hordir, end);\n\tVectorCopy(trace.endpos, start);\n\tend[2] = trace.endpos[2];\n\t//trace from previous trace end pos horizontally in the move direction\n\ttrace = AAS_TraceClientBBox(start, end, PRESENCE_NORMAL, ms->entitynum);\n\t//again this shouldn't happen\n\tif (trace.startsolid) return qfalse;\n\t//\n\tVectorCopy(trace.endpos, start);\n\tVectorCopy(trace.endpos, end);\n\tend[2] = ms->origin[2];\n\t//trace down from the previous trace end pos\n\ttrace = AAS_TraceClientBBox(start, end, PRESENCE_NORMAL, ms->entitynum);\n\t//if solid\n\tif (trace.startsolid) return qfalse;\n\t//if no obstacle at all\n\tif (trace.fraction >= 1.0) return qfalse;\n\t//if less than the maximum step height\n\tif (trace.endpos[2] - ms->origin[2] < sv_maxstep->value) return qfalse;\n\t//\n\tEA_Jump(ms->client);\n\tEA_Move(ms->client, hordir, speed);\n\tms->moveflags |= MFL_BARRIERJUMP;\n\t//there is a barrier\n\treturn qtrue;\n} //end of the function BotCheckBarrierJump\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotSwimInDirection(bot_movestate_t *ms, vec3_t dir, float speed, int type)\n{\n\tvec3_t normdir;\n\n\tVectorCopy(dir, normdir);\n\tVectorNormalize(normdir);\n\tEA_Move(ms->client, normdir, speed);\n\treturn qtrue;\n} //end of the function BotSwimInDirection\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotWalkInDirection(bot_movestate_t *ms, vec3_t dir, float speed, int type)\n{\n\tvec3_t hordir, cmdmove, velocity, tmpdir, origin;\n\tint presencetype, maxframes, cmdframes, stopevent;\n\taas_clientmove_t move;\n\tfloat dist;\n\n\tif (AAS_OnGround(ms->origin, ms->presencetype, ms->entitynum)) ms->moveflags |= MFL_ONGROUND;\n\t//if the bot is on the ground\n\tif (ms->moveflags & MFL_ONGROUND)\n\t{\n\t\t//if there is a barrier the bot can jump on\n\t\tif (BotCheckBarrierJump(ms, dir, speed)) return qtrue;\n\t\t//remove barrier jump flag\n\t\tms->moveflags &= ~MFL_BARRIERJUMP;\n\t\t//get the presence type for the movement\n\t\tif ((type & MOVE_CROUCH) && !(type & MOVE_JUMP)) presencetype = PRESENCE_CROUCH;\n\t\telse presencetype = PRESENCE_NORMAL;\n\t\t//horizontal direction\n\t\thordir[0] = dir[0];\n\t\thordir[1] = dir[1];\n\t\thordir[2] = 0;\n\t\tVectorNormalize(hordir);\n\t\t//if the bot is not supposed to jump\n\t\tif (!(type & MOVE_JUMP))\n\t\t{\n\t\t\t//if there is a gap, try to jump over it\n\t\t\tif (BotGapDistance(ms->origin, hordir, ms->entitynum) > 0) type |= MOVE_JUMP;\n\t\t} //end if\n\t\t//get command movement\n\t\tVectorScale(hordir, speed, cmdmove);\n\t\tVectorCopy(ms->velocity, velocity);\n\t\t//\n\t\tif (type & MOVE_JUMP)\n\t\t{\n\t\t\t//botimport.Print(PRT_MESSAGE, \"trying jump\\n\");\n\t\t\tcmdmove[2] = 400;\n\t\t\tmaxframes = PREDICTIONTIME_JUMP / 0.1;\n\t\t\tcmdframes = 1;\n\t\t\tstopevent = SE_HITGROUND|SE_HITGROUNDDAMAGE|\n\t\t\t\t\t\tSE_ENTERWATER|SE_ENTERSLIME|SE_ENTERLAVA;\n\t\t} //end if\n\t\telse\n\t\t{\n\t\t\tmaxframes = 2;\n\t\t\tcmdframes = 2;\n\t\t\tstopevent = SE_HITGROUNDDAMAGE|\n\t\t\t\t\t\tSE_ENTERWATER|SE_ENTERSLIME|SE_ENTERLAVA;\n\t\t} //end else\n\t\t//AAS_ClearShownDebugLines();\n\t\t//\n\t\tVectorCopy(ms->origin, origin);\n\t\torigin[2] += 0.5;\n\t\tAAS_PredictClientMovement(&move, ms->entitynum, origin, presencetype, qtrue,\n\t\t\t\t\t\t\t\t\tvelocity, cmdmove, cmdframes, maxframes, 0.1f,\n\t\t\t\t\t\t\t\t\tstopevent, 0, qfalse);//qtrue);\n\t\t//if prediction time wasn't enough to fully predict the movement\n\t\tif (move.frames >= maxframes && (type & MOVE_JUMP))\n\t\t{\n\t\t\t//botimport.Print(PRT_MESSAGE, \"client %d: max prediction frames\\n\", ms->client);\n\t\t\treturn qfalse;\n\t\t} //end if\n\t\t//don't enter slime or lava and don't fall from too high\n\t\tif (move.stopevent & (SE_ENTERSLIME|SE_ENTERLAVA|SE_HITGROUNDDAMAGE))\n\t\t{\n\t\t\t//botimport.Print(PRT_MESSAGE, \"client %d: would be hurt \", ms->client);\n\t\t\t//if (move.stopevent & SE_ENTERSLIME) botimport.Print(PRT_MESSAGE, \"slime\\n\");\n\t\t\t//if (move.stopevent & SE_ENTERLAVA) botimport.Print(PRT_MESSAGE, \"lava\\n\");\n\t\t\t//if (move.stopevent & SE_HITGROUNDDAMAGE) botimport.Print(PRT_MESSAGE, \"hitground\\n\");\n\t\t\treturn qfalse;\n\t\t} //end if\n\t\t//if ground was hit\n\t\tif (move.stopevent & SE_HITGROUND)\n\t\t{\n\t\t\t//check for nearby gap\n\t\t\tVectorNormalize2(move.velocity, tmpdir);\n\t\t\tdist = BotGapDistance(move.endpos, tmpdir, ms->entitynum);\n\t\t\tif (dist > 0) return qfalse;\n\t\t\t//\n\t\t\tdist = BotGapDistance(move.endpos, hordir, ms->entitynum);\n\t\t\tif (dist > 0) return qfalse;\n\t\t} //end if\n\t\t//get horizontal movement\n\t\ttmpdir[0] = move.endpos[0] - ms->origin[0];\n\t\ttmpdir[1] = move.endpos[1] - ms->origin[1];\n\t\ttmpdir[2] = 0;\n\t\t//\n\t\t//AAS_DrawCross(move.endpos, 4, LINECOLOR_BLUE);\n\t\t//the bot is blocked by something\n\t\tif (VectorLength(tmpdir) < speed * ms->thinktime * 0.5) return qfalse;\n\t\t//perform the movement\n\t\tif (type & MOVE_JUMP) EA_Jump(ms->client);\n\t\tif (type & MOVE_CROUCH) EA_Crouch(ms->client);\n\t\tEA_Move(ms->client, hordir, speed);\n\t\t//movement was succesfull\n\t\treturn qtrue;\n\t} //end if\n\telse\n\t{\n\t\tif (ms->moveflags & MFL_BARRIERJUMP)\n\t\t{\n\t\t\t//if near the top or going down\n\t\t\tif (ms->velocity[2] < 50)\n\t\t\t{\n\t\t\t\tEA_Move(ms->client, dir, speed);\n\t\t\t} //end if\n\t\t} //end if\n\t\t//FIXME: do air control to avoid hazards\n\t\treturn qtrue;\n\t} //end else\n} //end of the function BotWalkInDirection\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotMoveInDirection(int movestate, vec3_t dir, float speed, int type)\n{\n\tbot_movestate_t *ms;\n\n\tms = BotMoveStateFromHandle(movestate);\n\tif (!ms) return qfalse;\n\t//if swimming\n\tif (AAS_Swimming(ms->origin))\n\t{\n\t\treturn BotSwimInDirection(ms, dir, speed, type);\n\t} //end if\n\telse\n\t{\n\t\treturn BotWalkInDirection(ms, dir, speed, type);\n\t} //end else\n} //end of the function BotMoveInDirection\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint Intersection(vec2_t p1, vec2_t p2, vec2_t p3, vec2_t p4, vec2_t out)\n{\n   float x1, dx1, dy1, x2, dx2, dy2, d;\n\n   dx1 = p2[0] - p1[0];\n   dy1 = p2[1] - p1[1];\n   dx2 = p4[0] - p3[0];\n   dy2 = p4[1] - p3[1];\n\n   d = dy1 * dx2 - dx1 * dy2;\n   if (d != 0)\n   {\n      x1 = p1[1] * dx1 - p1[0] * dy1;\n      x2 = p3[1] * dx2 - p3[0] * dy2;\n      out[0] = (int) ((dx1 * x2 - dx2 * x1) / d);\n      out[1] = (int) ((dy1 * x2 - dy2 * x1) / d);\n\t\treturn qtrue;\n   } //end if\n   else\n   {\n      return qfalse;\n   } //end else\n} //end of the function Intersection\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotCheckBlocked(bot_movestate_t *ms, vec3_t dir, int checkbottom, bot_moveresult_t *result)\n{\n\tvec3_t mins, maxs, end, up = {0, 0, 1};\n\tbsp_trace_t trace;\n\n\t//test for entities obstructing the bot's path\n\tAAS_PresenceTypeBoundingBox(ms->presencetype, mins, maxs);\n\t//\n\tif (fabs(DotProduct(dir, up)) < 0.7)\n\t{\n\t\tmins[2] += sv_maxstep->value; //if the bot can step on\n\t\tmaxs[2] -= 10; //a little lower to avoid low ceiling\n\t} //end if\n\tVectorMA(ms->origin, 3, dir, end);\n\ttrace = AAS_Trace(ms->origin, mins, maxs, end, ms->entitynum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_BODY);\n\t//if not started in solid and not hitting the world entity\n\tif (!trace.startsolid && (trace.ent != ENTITYNUM_WORLD && trace.ent != ENTITYNUM_NONE) )\n\t{\n\t\tresult->blocked = qtrue;\n\t\tresult->blockentity = trace.ent;\n#ifdef DEBUG\n\t\t//botimport.Print(PRT_MESSAGE, \"%d: BotCheckBlocked: I'm blocked\\n\", ms->client);\n#endif //DEBUG\n\t} //end if\n\t//if not in an area with reachability\n\telse if (checkbottom && !AAS_AreaReachability(ms->areanum))\n\t{\n\t\t//check if the bot is standing on something\n\t\tAAS_PresenceTypeBoundingBox(ms->presencetype, mins, maxs);\n\t\tVectorMA(ms->origin, -3, up, end);\n\t\ttrace = AAS_Trace(ms->origin, mins, maxs, end, ms->entitynum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP);\n\t\tif (!trace.startsolid && (trace.ent != ENTITYNUM_WORLD && trace.ent != ENTITYNUM_NONE) )\n\t\t{\n\t\t\tresult->blocked = qtrue;\n\t\t\tresult->blockentity = trace.ent;\n\t\t\tresult->flags |= MOVERESULT_ONTOPOFOBSTACLE;\n#ifdef DEBUG\n\t\t\t//botimport.Print(PRT_MESSAGE, \"%d: BotCheckBlocked: I'm blocked\\n\", ms->client);\n#endif //DEBUG\n\t\t} //end if\n\t} //end else\n} //end of the function BotCheckBlocked\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotClearMoveResult(bot_moveresult_t *moveresult)\n{\n\tmoveresult->failure = qfalse;\n\tmoveresult->type = 0;\n\tmoveresult->blocked = qfalse;\n\tmoveresult->blockentity = 0;\n\tmoveresult->traveltype = 0;\n\tmoveresult->flags = 0;\n} //end of the function BotClearMoveResult\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nbot_moveresult_t BotTravel_Walk(bot_movestate_t *ms, aas_reachability_t *reach)\n{\n\tfloat dist, speed;\n\tvec3_t hordir;\n\tbot_moveresult_t result;\n\n\tBotClearMoveResult(&result);\n\t//first walk straight to the reachability start\n\thordir[0] = reach->start[0] - ms->origin[0];\n\thordir[1] = reach->start[1] - ms->origin[1];\n\thordir[2] = 0;\n\tdist = VectorNormalize(hordir);\n\t//\n\tBotCheckBlocked(ms, hordir, qtrue, &result);\n\t//\n\tif (dist < 10)\n\t{\n\t\t//walk straight to the reachability end\n\t\thordir[0] = reach->end[0] - ms->origin[0];\n\t\thordir[1] = reach->end[1] - ms->origin[1];\n\t\thordir[2] = 0;\n\t\tdist = VectorNormalize(hordir);\n\t} //end if\n\t//if going towards a crouch area\n\tif (!(AAS_AreaPresenceType(reach->areanum) & PRESENCE_NORMAL))\n\t{\n\t\t//if pretty close to the reachable area\n\t\tif (dist < 20) EA_Crouch(ms->client);\n\t} //end if\n\t//\n\tdist = BotGapDistance(ms->origin, hordir, ms->entitynum);\n\t//\n\tif (ms->moveflags & MFL_WALK)\n\t{\n\t\tif (dist > 0) speed = 200 - (180 - 1 * dist);\n\t\telse speed = 200;\n\t\tEA_Walk(ms->client);\n\t} //end if\n\telse\n\t{\n\t\tif (dist > 0) speed = 400 - (360 - 2 * dist);\n\t\telse speed = 400;\n\t} //end else\n\t//elemantary action move in direction\n\tEA_Move(ms->client, hordir, speed);\n\tVectorCopy(hordir, result.movedir);\n\t//\n\treturn result;\n} //end of the function BotTravel_Walk\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nbot_moveresult_t BotFinishTravel_Walk(bot_movestate_t *ms, aas_reachability_t *reach)\n{\n\tvec3_t hordir;\n\tfloat dist, speed;\n\tbot_moveresult_t result;\n\n\tBotClearMoveResult(&result);\n\t//if not on the ground and changed areas... don't walk back!!\n\t//(doesn't seem to help)\n\t/*\n\tms->areanum = BotFuzzyPointReachabilityArea(ms->origin);\n\tif (ms->areanum == reach->areanum)\n\t{\n#ifdef DEBUG\n\t\tbotimport.Print(PRT_MESSAGE, \"BotFinishTravel_Walk: already in reach area\\n\");\n#endif //DEBUG\n\t\treturn result;\n\t} //end if*/\n\t//go straight to the reachability end\n\thordir[0] = reach->end[0] - ms->origin[0];\n\thordir[1] = reach->end[1] - ms->origin[1];\n\thordir[2] = 0;\n\tdist = VectorNormalize(hordir);\n\t//\n\tif (dist > 100) dist = 100;\n\tspeed = 400 - (400 - 3 * dist);\n\t//\n\tEA_Move(ms->client, hordir, speed);\n\tVectorCopy(hordir, result.movedir);\n\t//\n\treturn result;\n} //end of the function BotFinishTravel_Walk\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nbot_moveresult_t BotTravel_Crouch(bot_movestate_t *ms, aas_reachability_t *reach)\n{\n\tfloat speed;\n\tvec3_t hordir;\n\tbot_moveresult_t result;\n\n\tBotClearMoveResult(&result);\n\t//\n\tspeed = 400;\n\t//walk straight to reachability end\n\thordir[0] = reach->end[0] - ms->origin[0];\n\thordir[1] = reach->end[1] - ms->origin[1];\n\thordir[2] = 0;\n\tVectorNormalize(hordir);\n\t//\n\tBotCheckBlocked(ms, hordir, qtrue, &result);\n\t//elemantary actions\n\tEA_Crouch(ms->client);\n\tEA_Move(ms->client, hordir, speed);\n\t//\n\tVectorCopy(hordir, result.movedir);\n\t//\n\treturn result;\n} //end of the function BotTravel_Crouch\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nbot_moveresult_t BotTravel_BarrierJump(bot_movestate_t *ms, aas_reachability_t *reach)\n{\n\tfloat dist, speed;\n\tvec3_t hordir;\n\tbot_moveresult_t result;\n\n\tBotClearMoveResult(&result);\n\t//walk straight to reachability start\n\thordir[0] = reach->start[0] - ms->origin[0];\n\thordir[1] = reach->start[1] - ms->origin[1];\n\thordir[2] = 0;\n\tdist = VectorNormalize(hordir);\n\t//\n\tBotCheckBlocked(ms, hordir, qtrue, &result);\n\t//if pretty close to the barrier\n\tif (dist < 9)\n\t{\n\t\tEA_Jump(ms->client);\n\t} //end if\n\telse\n\t{\n\t\tif (dist > 60) dist = 60;\n\t\tspeed = 360 - (360 - 6 * dist);\n\t\tEA_Move(ms->client, hordir, speed);\n\t} //end else\n\tVectorCopy(hordir, result.movedir);\n\t//\n\treturn result;\n} //end of the function BotTravel_BarrierJump\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nbot_moveresult_t BotFinishTravel_BarrierJump(bot_movestate_t *ms, aas_reachability_t *reach)\n{\n\tfloat dist;\n\tvec3_t hordir;\n\tbot_moveresult_t result;\n\n\tBotClearMoveResult(&result);\n\t//if near the top or going down\n\tif (ms->velocity[2] < 250)\n\t{\n\t\thordir[0] = reach->end[0] - ms->origin[0];\n\t\thordir[1] = reach->end[1] - ms->origin[1];\n\t\thordir[2] = 0;\n\t\tdist = VectorNormalize(hordir);\n\t\t//\n\t\tBotCheckBlocked(ms, hordir, qtrue, &result);\n\t\t//\n\t\tEA_Move(ms->client, hordir, 400);\n\t\tVectorCopy(hordir, result.movedir);\n\t} //end if\n\t//\n\treturn result;\n} //end of the function BotFinishTravel_BarrierJump\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nbot_moveresult_t BotTravel_Swim(bot_movestate_t *ms, aas_reachability_t *reach)\n{\n\tvec3_t dir;\n\tbot_moveresult_t result;\n\n\tBotClearMoveResult(&result);\n\t//swim straight to reachability end\n\tVectorSubtract(reach->start, ms->origin, dir);\n\tVectorNormalize(dir);\n\t//\n\tBotCheckBlocked(ms, dir, qtrue, &result);\n\t//elemantary actions\n\tEA_Move(ms->client, dir, 400);\n\t//\n\tVectorCopy(dir, result.movedir);\n\tVector2Angles(dir, result.ideal_viewangles);\n\tresult.flags |= MOVERESULT_SWIMVIEW;\n\t//\n\treturn result;\n} //end of the function BotTravel_Swim\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nbot_moveresult_t BotTravel_WaterJump(bot_movestate_t *ms, aas_reachability_t *reach)\n{\n\tvec3_t dir, hordir;\n\tfloat dist;\n\tbot_moveresult_t result;\n\n\tBotClearMoveResult(&result);\n\t//swim straight to reachability end\n\tVectorSubtract(reach->end, ms->origin, dir);\n\tVectorCopy(dir, hordir);\n\thordir[2] = 0;\n\tdir[2] += 15 + crandom() * 40;\n\t//botimport.Print(PRT_MESSAGE, \"BotTravel_WaterJump: dir[2] = %f\\n\", dir[2]);\n\tVectorNormalize(dir);\n\tdist = VectorNormalize(hordir);\n\t//elemantary actions\n\t//EA_Move(ms->client, dir, 400);\n\tEA_MoveForward(ms->client);\n\t//move up if close to the actual out of water jump spot\n\tif (dist < 40) EA_MoveUp(ms->client);\n\t//set the ideal view angles\n\tVector2Angles(dir, result.ideal_viewangles);\n\tresult.flags |= MOVERESULT_MOVEMENTVIEW;\n\t//\n\tVectorCopy(dir, result.movedir);\n\t//\n\treturn result;\n} //end of the function BotTravel_WaterJump\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nbot_moveresult_t BotFinishTravel_WaterJump(bot_movestate_t *ms, aas_reachability_t *reach)\n{\n\tvec3_t dir, pnt;\n\tfloat dist;\n\tbot_moveresult_t result;\n\n\t//botimport.Print(PRT_MESSAGE, \"BotFinishTravel_WaterJump\\n\");\n\tBotClearMoveResult(&result);\n\t//if waterjumping there's nothing to do\n\tif (ms->moveflags & MFL_WATERJUMP) return result;\n\t//if not touching any water anymore don't do anything\n\t//otherwise the bot sometimes keeps jumping?\n\tVectorCopy(ms->origin, pnt);\n\tpnt[2] -= 32;\t//extra for q2dm4 near red armor/mega health\n\tif (!(AAS_PointContents(pnt) & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER))) return result;\n\t//swim straight to reachability end\n\tVectorSubtract(reach->end, ms->origin, dir);\n\tdir[0] += crandom() * 10;\n\tdir[1] += crandom() * 10;\n\tdir[2] += 70 + crandom() * 10;\n\tdist = VectorNormalize(dir);\n\t//elemantary actions\n\tEA_Move(ms->client, dir, 400);\n\t//set the ideal view angles\n\tVector2Angles(dir, result.ideal_viewangles);\n\tresult.flags |= MOVERESULT_MOVEMENTVIEW;\n\t//\n\tVectorCopy(dir, result.movedir);\n\t//\n\treturn result;\n} //end of the function BotFinishTravel_WaterJump\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nbot_moveresult_t BotTravel_WalkOffLedge(bot_movestate_t *ms, aas_reachability_t *reach)\n{\n\tvec3_t hordir, dir;\n\tfloat dist, speed, reachhordist;\n\tbot_moveresult_t result;\n\n\tBotClearMoveResult(&result);\n\t//check if the bot is blocked by anything\n\tVectorSubtract(reach->start, ms->origin, dir);\n\tVectorNormalize(dir);\n\tBotCheckBlocked(ms, dir, qtrue, &result);\n\t//if the reachability start and end are practially above each other\n\tVectorSubtract(reach->end, reach->start, dir);\n\tdir[2] = 0;\n\treachhordist = VectorLength(dir);\n\t//walk straight to the reachability start\n\thordir[0] = reach->start[0] - ms->origin[0];\n\thordir[1] = reach->start[1] - ms->origin[1];\n\thordir[2] = 0;\n\tdist = VectorNormalize(hordir);\n\t//if pretty close to the start focus on the reachability end\n\tif (dist < 48)\n\t{\n\t\thordir[0] = reach->end[0] - ms->origin[0];\n\t\thordir[1] = reach->end[1] - ms->origin[1];\n\t\thordir[2] = 0;\n\t\tVectorNormalize(hordir);\n\t\t//\n\t\tif (reachhordist < 20)\n\t\t{\n\t\t\tspeed = 100;\n\t\t} //end if\n\t\telse if (!AAS_HorizontalVelocityForJump(0, reach->start, reach->end, &speed))\n\t\t{\n\t\t\tspeed = 400;\n\t\t} //end if\n\t} //end if\n\telse\n\t{\n\t\tif (reachhordist < 20)\n\t\t{\n\t\t\tif (dist > 64) dist = 64;\n\t\t\tspeed = 400 - (256 - 4 * dist);\n\t\t} //end if\n\t\telse\n\t\t{\n\t\t\tspeed = 400;\n\t\t} //end else\n\t} //end else\n\t//\n\tBotCheckBlocked(ms, hordir, qtrue, &result);\n\t//elemantary action\n\tEA_Move(ms->client, hordir, speed);\n\tVectorCopy(hordir, result.movedir);\n\t//\n\treturn result;\n} //end of the function BotTravel_WalkOffLedge\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotAirControl(vec3_t origin, vec3_t velocity, vec3_t goal, vec3_t dir, float *speed)\n{\n\tvec3_t org, vel;\n\tfloat dist;\n\tint i;\n\n\tVectorCopy(origin, org);\n\tVectorScale(velocity, 0.1, vel);\n\tfor (i = 0; i < 50; i++)\n\t{\n\t\tvel[2] -= sv_gravity->value * 0.01;\n\t\t//if going down and next position would be below the goal\n\t\tif (vel[2] < 0 && org[2] + vel[2] < goal[2])\n\t\t{\n\t\t\tVectorScale(vel, (goal[2] - org[2]) / vel[2], vel);\n\t\t\tVectorAdd(org, vel, org);\n\t\t\tVectorSubtract(goal, org, dir);\n\t\t\tdist = VectorNormalize(dir);\n\t\t\tif (dist > 32) dist = 32;\n\t\t\t*speed = 400 - (400 - 13 * dist);\n\t\t\treturn qtrue;\n\t\t} //end if\n\t\telse\n\t\t{\n\t\t\tVectorAdd(org, vel, org);\n\t\t} //end else\n\t} //end for\n\tVectorSet(dir, 0, 0, 0);\n\t*speed = 400;\n\treturn qfalse;\n} //end of the function BotAirControl\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nbot_moveresult_t BotFinishTravel_WalkOffLedge(bot_movestate_t *ms, aas_reachability_t *reach)\n{\n\tvec3_t dir, hordir, end, v;\n\tfloat dist, speed;\n\tbot_moveresult_t result;\n\n\tBotClearMoveResult(&result);\n\t//\n\tVectorSubtract(reach->end, ms->origin, dir);\n\tBotCheckBlocked(ms, dir, qtrue, &result);\n\t//\n\tVectorSubtract(reach->end, ms->origin, v);\n\tv[2] = 0;\n\tdist = VectorNormalize(v);\n\tif (dist > 16) VectorMA(reach->end, 16, v, end);\n\telse VectorCopy(reach->end, end);\n\t//\n\tif (!BotAirControl(ms->origin, ms->velocity, end, hordir, &speed))\n\t{\n\t\t//go straight to the reachability end\n\t\tVectorCopy(dir, hordir);\n\t\thordir[2] = 0;\n\t\t//\n\t\tdist = VectorNormalize(hordir);\n\t\tspeed = 400;\n\t} //end if\n\t//\n\tEA_Move(ms->client, hordir, speed);\n\tVectorCopy(hordir, result.movedir);\n\t//\n\treturn result;\n} //end of the function BotFinishTravel_WalkOffLedge\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\n/*\nbot_moveresult_t BotTravel_Jump(bot_movestate_t *ms, aas_reachability_t *reach)\n{\n\tvec3_t hordir;\n\tfloat dist, gapdist, speed, horspeed, sv_jumpvel;\n\tbot_moveresult_t result;\n\n\tBotClearMoveResult(&result);\n\t//\n\tsv_jumpvel = botlibglobals.sv_jumpvel->value;\n\t//walk straight to the reachability start\n\thordir[0] = reach->start[0] - ms->origin[0];\n\thordir[1] = reach->start[1] - ms->origin[1];\n\thordir[2] = 0;\n\tdist = VectorNormalize(hordir);\n\t//\n\tspeed = 350;\n\t//\n\tgapdist = BotGapDistance(ms, hordir, ms->entitynum);\n\t//if pretty close to the start focus on the reachability end\n\tif (dist < 50 || (gapdist && gapdist < 50))\n\t{\n\t\t//NOTE: using max speed (400) works best\n\t\t//if (AAS_HorizontalVelocityForJump(sv_jumpvel, ms->origin, reach->end, &horspeed))\n\t\t//{\n\t\t//\tspeed = horspeed * 400 / botlibglobals.sv_maxwalkvelocity->value;\n\t\t//} //end if\n\t\thordir[0] = reach->end[0] - ms->origin[0];\n\t\thordir[1] = reach->end[1] - ms->origin[1];\n\t\tVectorNormalize(hordir);\n\t\t//elemantary action jump\n\t\tEA_Jump(ms->client);\n\t\t//\n\t\tms->jumpreach = ms->lastreachnum;\n\t\tspeed = 600;\n\t} //end if\n\telse\n\t{\n\t\tif (AAS_HorizontalVelocityForJump(sv_jumpvel, reach->start, reach->end, &horspeed))\n\t\t{\n\t\t\tspeed = horspeed * 400 / botlibglobals.sv_maxwalkvelocity->value;\n\t\t} //end if\n\t} //end else\n\t//elemantary action\n\tEA_Move(ms->client, hordir, speed);\n\tVectorCopy(hordir, result.movedir);\n\t//\n\treturn result;\n} //end of the function BotTravel_Jump*/\n/*\nbot_moveresult_t BotTravel_Jump(bot_movestate_t *ms, aas_reachability_t *reach)\n{\n\tvec3_t hordir, dir1, dir2, mins, maxs, start, end;\n\tfloat dist1, dist2, speed;\n\tbot_moveresult_t result;\n\tbsp_trace_t trace;\n\n\tBotClearMoveResult(&result);\n\t//\n\thordir[0] = reach->start[0] - reach->end[0];\n\thordir[1] = reach->start[1] - reach->end[1];\n\thordir[2] = 0;\n\tVectorNormalize(hordir);\n\t//\n\tVectorCopy(reach->start, start);\n\tstart[2] += 1;\n\t//minus back the bouding box size plus 16\n\tVectorMA(reach->start, 80, hordir, end);\n\t//\n\tAAS_PresenceTypeBoundingBox(PRESENCE_NORMAL, mins, maxs);\n\t//check for solids\n\ttrace = AAS_Trace(start, mins, maxs, end, ms->entitynum, MASK_PLAYERSOLID);\n\tif (trace.startsolid) VectorCopy(start, trace.endpos);\n\t//check for a gap\n\tfor (dist1 = 0; dist1 < 80; dist1 += 10)\n\t{\n\t\tVectorMA(start, dist1+10, hordir, end);\n\t\tend[2] += 1;\n\t\tif (AAS_PointAreaNum(end) != ms->reachareanum) break;\n\t} //end for\n\tif (dist1 < 80) VectorMA(reach->start, dist1, hordir, trace.endpos);\n//\tdist1 = BotGapDistance(start, hordir, ms->entitynum);\n//\tif (dist1 && dist1 <= trace.fraction * 80) VectorMA(reach->start, dist1-20, hordir, trace.endpos);\n\t//\n\tVectorSubtract(ms->origin, reach->start, dir1);\n\tdir1[2] = 0;\n\tdist1 = VectorNormalize(dir1);\n\tVectorSubtract(ms->origin, trace.endpos, dir2);\n\tdir2[2] = 0;\n\tdist2 = VectorNormalize(dir2);\n\t//if just before the reachability start\n\tif (DotProduct(dir1, dir2) < -0.8 || dist2 < 5)\n\t{\n\t\t//botimport.Print(PRT_MESSAGE, \"between jump start and run to point\\n\");\n\t\thordir[0] = reach->end[0] - ms->origin[0];\n\t\thordir[1] = reach->end[1] - ms->origin[1];\n\t\thordir[2] = 0;\n\t\tVectorNormalize(hordir);\n\t\t//elemantary action jump\n\t\tif (dist1 < 24) EA_Jump(ms->client);\n\t\telse if (dist1 < 32) EA_DelayedJump(ms->client);\n\t\tEA_Move(ms->client, hordir, 600);\n\t\t//\n\t\tms->jumpreach = ms->lastreachnum;\n\t} //end if\n\telse\n\t{\n\t\t//botimport.Print(PRT_MESSAGE, \"going towards run to point\\n\");\n\t\thordir[0] = trace.endpos[0] - ms->origin[0];\n\t\thordir[1] = trace.endpos[1] - ms->origin[1];\n\t\thordir[2] = 0;\n\t\tVectorNormalize(hordir);\n\t\t//\n\t\tif (dist2 > 80) dist2 = 80;\n\t\tspeed = 400 - (400 - 5 * dist2);\n\t\tEA_Move(ms->client, hordir, speed);\n\t} //end else\n\tVectorCopy(hordir, result.movedir);\n\t//\n\treturn result;\n} //end of the function BotTravel_Jump*/\n//*\nbot_moveresult_t BotTravel_Jump(bot_movestate_t *ms, aas_reachability_t *reach)\n{\n\tvec3_t hordir, dir1, dir2, start, end, runstart;\n//\tvec3_t runstart, dir1, dir2, hordir;\n\tfloat dist1, dist2, speed;\n\tbot_moveresult_t result;\n\n\tBotClearMoveResult(&result);\n\t//\n\tAAS_JumpReachRunStart(reach, runstart);\n\t//*\n\thordir[0] = runstart[0] - reach->start[0];\n\thordir[1] = runstart[1] - reach->start[1];\n\thordir[2] = 0;\n\tVectorNormalize(hordir);\n\t//\n\tVectorCopy(reach->start, start);\n\tstart[2] += 1;\n\tVectorMA(reach->start, 80, hordir, runstart);\n\t//check for a gap\n\tfor (dist1 = 0; dist1 < 80; dist1 += 10)\n\t{\n\t\tVectorMA(start, dist1+10, hordir, end);\n\t\tend[2] += 1;\n\t\tif (AAS_PointAreaNum(end) != ms->reachareanum) break;\n\t} //end for\n\tif (dist1 < 80) VectorMA(reach->start, dist1, hordir, runstart);\n\t//\n\tVectorSubtract(ms->origin, reach->start, dir1);\n\tdir1[2] = 0;\n\tdist1 = VectorNormalize(dir1);\n\tVectorSubtract(ms->origin, runstart, dir2);\n\tdir2[2] = 0;\n\tdist2 = VectorNormalize(dir2);\n\t//if just before the reachability start\n\tif (DotProduct(dir1, dir2) < -0.8 || dist2 < 5)\n\t{\n//\t\tbotimport.Print(PRT_MESSAGE, \"between jump start and run start point\\n\");\n\t\thordir[0] = reach->end[0] - ms->origin[0];\n\t\thordir[1] = reach->end[1] - ms->origin[1];\n\t\thordir[2] = 0;\n\t\tVectorNormalize(hordir);\n\t\t//elemantary action jump\n\t\tif (dist1 < 24) EA_Jump(ms->client);\n\t\telse if (dist1 < 32) EA_DelayedJump(ms->client);\n\t\tEA_Move(ms->client, hordir, 600);\n\t\t//\n\t\tms->jumpreach = ms->lastreachnum;\n\t} //end if\n\telse\n\t{\n//\t\tbotimport.Print(PRT_MESSAGE, \"going towards run start point\\n\");\n\t\thordir[0] = runstart[0] - ms->origin[0];\n\t\thordir[1] = runstart[1] - ms->origin[1];\n\t\thordir[2] = 0;\n\t\tVectorNormalize(hordir);\n\t\t//\n\t\tif (dist2 > 80) dist2 = 80;\n\t\tspeed = 400 - (400 - 5 * dist2);\n\t\tEA_Move(ms->client, hordir, speed);\n\t} //end else\n\tVectorCopy(hordir, result.movedir);\n\t//\n\treturn result;\n} //end of the function BotTravel_Jump*/\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nbot_moveresult_t BotFinishTravel_Jump(bot_movestate_t *ms, aas_reachability_t *reach)\n{\n\tvec3_t hordir, hordir2;\n\tfloat speed, dist;\n\tbot_moveresult_t result;\n\n\tBotClearMoveResult(&result);\n\t//if not jumped yet\n\tif (!ms->jumpreach) return result;\n\t//go straight to the reachability end\n\thordir[0] = reach->end[0] - ms->origin[0];\n\thordir[1] = reach->end[1] - ms->origin[1];\n\thordir[2] = 0;\n\tdist = VectorNormalize(hordir);\n\t//\n\thordir2[0] = reach->end[0] - reach->start[0];\n\thordir2[1] = reach->end[1] - reach->start[1];\n\thordir2[2] = 0;\n\tVectorNormalize(hordir2);\n\t//\n\tif (DotProduct(hordir, hordir2) < -0.5 && dist < 24) return result;\n\t//always use max speed when traveling through the air\n\tspeed = 800;\n\t//\n\tEA_Move(ms->client, hordir, speed);\n\tVectorCopy(hordir, result.movedir);\n\t//\n\treturn result;\n} //end of the function BotFinishTravel_Jump\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nbot_moveresult_t BotTravel_Ladder(bot_movestate_t *ms, aas_reachability_t *reach)\n{\n\t//float dist, speed;\n\tvec3_t dir, viewdir;//, hordir;\n\tvec3_t origin = {0, 0, 0};\n//\tvec3_t up = {0, 0, 1};\n\tbot_moveresult_t result;\n\n\tBotClearMoveResult(&result);\n\t//\n//\tif ((ms->moveflags & MFL_AGAINSTLADDER))\n\t\t//NOTE: not a good idea for ladders starting in water\n\t\t// || !(ms->moveflags & MFL_ONGROUND))\n\t{\n\t\t//botimport.Print(PRT_MESSAGE, \"against ladder or not on ground\\n\");\n\t\tVectorSubtract(reach->end, ms->origin, dir);\n\t\tVectorNormalize(dir);\n\t\t//set the ideal view angles, facing the ladder up or down\n\t\tviewdir[0] = dir[0];\n\t\tviewdir[1] = dir[1];\n\t\tviewdir[2] = 3 * dir[2];\n\t\tVector2Angles(viewdir, result.ideal_viewangles);\n\t\t//elemantary action\n\t\tEA_Move(ms->client, origin, 0);\n\t\tEA_MoveForward(ms->client);\n\t\t//set movement view flag so the AI can see the view is focussed\n\t\tresult.flags |= MOVERESULT_MOVEMENTVIEW;\n\t} //end if\n/*\telse\n\t{\n\t\t//botimport.Print(PRT_MESSAGE, \"moving towards ladder\\n\");\n\t\tVectorSubtract(reach->end, ms->origin, dir);\n\t\t//make sure the horizontal movement is large anough\n\t\tVectorCopy(dir, hordir);\n\t\thordir[2] = 0;\n\t\tdist = VectorNormalize(hordir);\n\t\t//\n\t\tdir[0] = hordir[0];\n\t\tdir[1] = hordir[1];\n\t\tif (dir[2] > 0) dir[2] = 1;\n\t\telse dir[2] = -1;\n\t\tif (dist > 50) dist = 50;\n\t\tspeed = 400 - (200 - 4 * dist);\n\t\tEA_Move(ms->client, dir, speed);\n\t} //end else*/\n\t//save the movement direction\n\tVectorCopy(dir, result.movedir);\n\t//\n\treturn result;\n} //end of the function BotTravel_Ladder\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nbot_moveresult_t BotTravel_Teleport(bot_movestate_t *ms, aas_reachability_t *reach)\n{\n\tvec3_t hordir;\n\tfloat dist;\n\tbot_moveresult_t result;\n\n\tBotClearMoveResult(&result);\n\t//if the bot is being teleported\n\tif (ms->moveflags & MFL_TELEPORTED) return result;\n\n\t//walk straight to center of the teleporter\n\tVectorSubtract(reach->start, ms->origin, hordir);\n\tif (!(ms->moveflags & MFL_SWIMMING)) hordir[2] = 0;\n\tdist = VectorNormalize(hordir);\n\t//\n\tBotCheckBlocked(ms, hordir, qtrue, &result);\n\n\tif (dist < 30) EA_Move(ms->client, hordir, 200);\n\telse EA_Move(ms->client, hordir, 400);\n\n\tif (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;\n\n\tVectorCopy(hordir, result.movedir);\n\treturn result;\n} //end of the function BotTravel_Teleport\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nbot_moveresult_t BotTravel_Elevator(bot_movestate_t *ms, aas_reachability_t *reach)\n{\n\tvec3_t dir, dir1, dir2, hordir, bottomcenter;\n\tfloat dist, dist1, dist2, speed;\n\tbot_moveresult_t result;\n\n\tBotClearMoveResult(&result);\n\t//if standing on the plat\n\tif (BotOnMover(ms->origin, ms->entitynum, reach))\n\t{\n#ifdef DEBUG_ELEVATOR\n\t\tbotimport.Print(PRT_MESSAGE, \"bot on elevator\\n\");\n#endif //DEBUG_ELEVATOR\n\t\t//if vertically not too far from the end point\n\t\tif (fabs(ms->origin[2] - reach->end[2]) < sv_maxbarrier->value)\n\t\t{\n#ifdef DEBUG_ELEVATOR\n\t\t\tbotimport.Print(PRT_MESSAGE, \"bot moving to end\\n\");\n#endif //DEBUG_ELEVATOR\n\t\t\t//move to the end point\n\t\t\tVectorSubtract(reach->end, ms->origin, hordir);\n\t\t\thordir[2] = 0;\n\t\t\tVectorNormalize(hordir);\n\t\t\tif (!BotCheckBarrierJump(ms, hordir, 100))\n\t\t\t{\n\t\t\t\tEA_Move(ms->client, hordir, 400);\n\t\t\t} //end if\n\t\t\tVectorCopy(hordir, result.movedir);\n\t\t} //end else\n\t\t//if not really close to the center of the elevator\n\t\telse\n\t\t{\n\t\t\tMoverBottomCenter(reach, bottomcenter);\n\t\t\tVectorSubtract(bottomcenter, ms->origin, hordir);\n\t\t\thordir[2] = 0;\n\t\t\tdist = VectorNormalize(hordir);\n\t\t\t//\n\t\t\tif (dist > 10)\n\t\t\t{\n#ifdef DEBUG_ELEVATOR\n\t\t\t\tbotimport.Print(PRT_MESSAGE, \"bot moving to center\\n\");\n#endif //DEBUG_ELEVATOR\n\t\t\t\t//move to the center of the plat\n\t\t\t\tif (dist > 100) dist = 100;\n\t\t\t\tspeed = 400 - (400 - 4 * dist);\n\t\t\t\t//\n\t\t\t\tEA_Move(ms->client, hordir, speed);\n\t\t\t\tVectorCopy(hordir, result.movedir);\n\t\t\t} //end if\n\t\t} //end else\n\t} //end if\n\telse\n\t{\n#ifdef DEBUG_ELEVATOR\n\t\tbotimport.Print(PRT_MESSAGE, \"bot not on elevator\\n\");\n#endif //DEBUG_ELEVATOR\n\t\t//if very near the reachability end\n\t\tVectorSubtract(reach->end, ms->origin, dir);\n\t\tdist = VectorLength(dir);\n\t\tif (dist < 64)\n\t\t{\n\t\t\tif (dist > 60) dist = 60;\n\t\t\tspeed = 360 - (360 - 6 * dist);\n\t\t\t//\n\t\t\tif ((ms->moveflags & MFL_SWIMMING) || !BotCheckBarrierJump(ms, dir, 50))\n\t\t\t{\n\t\t\t\tif (speed > 5) EA_Move(ms->client, dir, speed);\n\t\t\t} //end if\n\t\t\tVectorCopy(dir, result.movedir);\n\t\t\t//\n\t\t\tif (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;\n\t\t\t//stop using this reachability\n\t\t\tms->reachability_time = 0;\n\t\t\treturn result;\n\t\t} //end if\n\t\t//get direction and distance to reachability start\n\t\tVectorSubtract(reach->start, ms->origin, dir1);\n\t\tif (!(ms->moveflags & MFL_SWIMMING)) dir1[2] = 0;\n\t\tdist1 = VectorNormalize(dir1);\n\t\t//if the elevator isn't down\n\t\tif (!MoverDown(reach))\n\t\t{\n#ifdef DEBUG_ELEVATOR\n\t\t\tbotimport.Print(PRT_MESSAGE, \"elevator not down\\n\");\n#endif //DEBUG_ELEVATOR\n\t\t\tdist = dist1;\n\t\t\tVectorCopy(dir1, dir);\n\t\t\t//\n\t\t\tBotCheckBlocked(ms, dir, qfalse, &result);\n\t\t\t//\n\t\t\tif (dist > 60) dist = 60;\n\t\t\tspeed = 360 - (360 - 6 * dist);\n\t\t\t//\n\t\t\tif (!(ms->moveflags & MFL_SWIMMING) && !BotCheckBarrierJump(ms, dir, 50))\n\t\t\t{\n\t\t\t\tif (speed > 5) EA_Move(ms->client, dir, speed);\n\t\t\t} //end if\n\t\t\tVectorCopy(dir, result.movedir);\n\t\t\t//\n\t\t\tif (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;\n\t\t\t//this isn't a failure... just wait till the elevator comes down\n\t\t\tresult.type = RESULTTYPE_ELEVATORUP;\n\t\t\tresult.flags |= MOVERESULT_WAITING;\n\t\t\treturn result;\n\t\t} //end if\n\t\t//get direction and distance to elevator bottom center\n\t\tMoverBottomCenter(reach, bottomcenter);\n\t\tVectorSubtract(bottomcenter, ms->origin, dir2);\n\t\tif (!(ms->moveflags & MFL_SWIMMING)) dir2[2] = 0;\n\t\tdist2 = VectorNormalize(dir2);\n\t\t//if very close to the reachability start or\n\t\t//closer to the elevator center or\n\t\t//between reachability start and elevator center\n\t\tif (dist1 < 20 || dist2 < dist1 || DotProduct(dir1, dir2) < 0)\n\t\t{\n#ifdef DEBUG_ELEVATOR\n\t\t\tbotimport.Print(PRT_MESSAGE, \"bot moving to center\\n\");\n#endif //DEBUG_ELEVATOR\n\t\t\tdist = dist2;\n\t\t\tVectorCopy(dir2, dir);\n\t\t} //end if\n\t\telse //closer to the reachability start\n\t\t{\n#ifdef DEBUG_ELEVATOR\n\t\t\tbotimport.Print(PRT_MESSAGE, \"bot moving to start\\n\");\n#endif //DEBUG_ELEVATOR\n\t\t\tdist = dist1;\n\t\t\tVectorCopy(dir1, dir);\n\t\t} //end else\n\t\t//\n\t\tBotCheckBlocked(ms, dir, qfalse, &result);\n\t\t//\n\t\tif (dist > 60) dist = 60;\n\t\tspeed = 400 - (400 - 6 * dist);\n\t\t//\n\t\tif (!(ms->moveflags & MFL_SWIMMING) && !BotCheckBarrierJump(ms, dir, 50))\n\t\t{\n\t\t\tEA_Move(ms->client, dir, speed);\n\t\t} //end if\n\t\tVectorCopy(dir, result.movedir);\n\t\t//\n\t\tif (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;\n\t} //end else\n\treturn result;\n} //end of the function BotTravel_Elevator\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nbot_moveresult_t BotFinishTravel_Elevator(bot_movestate_t *ms, aas_reachability_t *reach)\n{\n\tvec3_t bottomcenter, bottomdir, topdir;\n\tbot_moveresult_t result;\n\n\tBotClearMoveResult(&result);\n\t//\n\tMoverBottomCenter(reach, bottomcenter);\n\tVectorSubtract(bottomcenter, ms->origin, bottomdir);\n\t//\n\tVectorSubtract(reach->end, ms->origin, topdir);\n\t//\n\tif (fabs(bottomdir[2]) < fabs(topdir[2]))\n\t{\n\t\tVectorNormalize(bottomdir);\n\t\tEA_Move(ms->client, bottomdir, 300);\n\t} //end if\n\telse\n\t{\n\t\tVectorNormalize(topdir);\n\t\tEA_Move(ms->client, topdir, 300);\n\t} //end else\n\treturn result;\n} //end of the function BotFinishTravel_Elevator\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotFuncBobStartEnd(aas_reachability_t *reach, vec3_t start, vec3_t end, vec3_t origin)\n{\n\tint spawnflags, modelnum;\n\tvec3_t mins, maxs, mid, angles = {0, 0, 0};\n\tint num0, num1;\n\n\tmodelnum = reach->facenum & 0x0000FFFF;\n\tif (!AAS_OriginOfMoverWithModelNum(modelnum, origin))\n\t{\n\t\tbotimport.Print(PRT_MESSAGE, \"BotFuncBobStartEnd: no entity with model %d\\n\", modelnum);\n\t\tVectorSet(start, 0, 0, 0);\n\t\tVectorSet(end, 0, 0, 0);\n\t\treturn;\n\t} //end if\n\tAAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, NULL);\n\tVectorAdd(mins, maxs, mid);\n\tVectorScale(mid, 0.5, mid);\n\tVectorCopy(mid, start);\n\tVectorCopy(mid, end);\n\tspawnflags = reach->facenum >> 16;\n\tnum0 = reach->edgenum >> 16;\n\tif (num0 > 0x00007FFF) num0 |= 0xFFFF0000;\n\tnum1 = reach->edgenum & 0x0000FFFF;\n\tif (num1 > 0x00007FFF) num1 |= 0xFFFF0000;\n\tif (spawnflags & 1)\n\t{\n\t\tstart[0] = num0;\n\t\tend[0] = num1;\n\t\t//\n\t\torigin[0] += mid[0];\n\t\torigin[1] = mid[1];\n\t\torigin[2] = mid[2];\n\t} //end if\n\telse if (spawnflags & 2)\n\t{\n\t\tstart[1] = num0;\n\t\tend[1] = num1;\n\t\t//\n\t\torigin[0] = mid[0];\n\t\torigin[1] += mid[1];\n\t\torigin[2] = mid[2];\n\t} //end else if\n\telse\n\t{\n\t\tstart[2] = num0;\n\t\tend[2] = num1;\n\t\t//\n\t\torigin[0] = mid[0];\n\t\torigin[1] = mid[1];\n\t\torigin[2] += mid[2];\n\t} //end else\n} //end of the function BotFuncBobStartEnd\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nbot_moveresult_t BotTravel_FuncBobbing(bot_movestate_t *ms, aas_reachability_t *reach)\n{\n\tvec3_t dir, dir1, dir2, hordir, bottomcenter, bob_start, bob_end, bob_origin;\n\tfloat dist, dist1, dist2, speed;\n\tbot_moveresult_t result;\n\n\tBotClearMoveResult(&result);\n\t//\n\tBotFuncBobStartEnd(reach, bob_start, bob_end, bob_origin);\n\t//if standing ontop of the func_bobbing\n\tif (BotOnMover(ms->origin, ms->entitynum, reach))\n\t{\n#ifdef DEBUG_FUNCBOB\n\t\tbotimport.Print(PRT_MESSAGE, \"bot on func_bobbing\\n\");\n#endif\n\t\t//if near end point of reachability\n\t\tVectorSubtract(bob_origin, bob_end, dir);\n\t\tif (VectorLength(dir) < 24)\n\t\t{\n#ifdef DEBUG_FUNCBOB\n\t\t\tbotimport.Print(PRT_MESSAGE, \"bot moving to reachability end\\n\");\n#endif\n\t\t\t//move to the end point\n\t\t\tVectorSubtract(reach->end, ms->origin, hordir);\n\t\t\thordir[2] = 0;\n\t\t\tVectorNormalize(hordir);\n\t\t\tif (!BotCheckBarrierJump(ms, hordir, 100))\n\t\t\t{\n\t\t\t\tEA_Move(ms->client, hordir, 400);\n\t\t\t} //end if\n\t\t\tVectorCopy(hordir, result.movedir);\n\t\t} //end else\n\t\t//if not really close to the center of the elevator\n\t\telse\n\t\t{\n\t\t\tMoverBottomCenter(reach, bottomcenter);\n\t\t\tVectorSubtract(bottomcenter, ms->origin, hordir);\n\t\t\thordir[2] = 0;\n\t\t\tdist = VectorNormalize(hordir);\n\t\t\t//\n\t\t\tif (dist > 10)\n\t\t\t{\n#ifdef DEBUG_FUNCBOB\n\t\t\t\tbotimport.Print(PRT_MESSAGE, \"bot moving to func_bobbing center\\n\");\n#endif\n\t\t\t\t//move to the center of the plat\n\t\t\t\tif (dist > 100) dist = 100;\n\t\t\t\tspeed = 400 - (400 - 4 * dist);\n\t\t\t\t//\n\t\t\t\tEA_Move(ms->client, hordir, speed);\n\t\t\t\tVectorCopy(hordir, result.movedir);\n\t\t\t} //end if\n\t\t} //end else\n\t} //end if\n\telse\n\t{\n#ifdef DEBUG_FUNCBOB\n\t\tbotimport.Print(PRT_MESSAGE, \"bot not ontop of func_bobbing\\n\");\n#endif\n\t\t//if very near the reachability end\n\t\tVectorSubtract(reach->end, ms->origin, dir);\n\t\tdist = VectorLength(dir);\n\t\tif (dist < 64)\n\t\t{\n#ifdef DEBUG_FUNCBOB\n\t\t\tbotimport.Print(PRT_MESSAGE, \"bot moving to end\\n\");\n#endif\n\t\t\tif (dist > 60) dist = 60;\n\t\t\tspeed = 360 - (360 - 6 * dist);\n\t\t\t//if swimming or no barrier jump\n\t\t\tif ((ms->moveflags & MFL_SWIMMING) || !BotCheckBarrierJump(ms, dir, 50))\n\t\t\t{\n\t\t\t\tif (speed > 5) EA_Move(ms->client, dir, speed);\n\t\t\t} //end if\n\t\t\tVectorCopy(dir, result.movedir);\n\t\t\t//\n\t\t\tif (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;\n\t\t\t//stop using this reachability\n\t\t\tms->reachability_time = 0;\n\t\t\treturn result;\n\t\t} //end if\n\t\t//get direction and distance to reachability start\n\t\tVectorSubtract(reach->start, ms->origin, dir1);\n\t\tif (!(ms->moveflags & MFL_SWIMMING)) dir1[2] = 0;\n\t\tdist1 = VectorNormalize(dir1);\n\t\t//if func_bobbing is Not it's start position\n\t\tVectorSubtract(bob_origin, bob_start, dir);\n\t\tif (VectorLength(dir) > 16)\n\t\t{\n#ifdef DEBUG_FUNCBOB\n\t\t\tbotimport.Print(PRT_MESSAGE, \"func_bobbing not at start\\n\");\n#endif\n\t\t\tdist = dist1;\n\t\t\tVectorCopy(dir1, dir);\n\t\t\t//\n\t\t\tBotCheckBlocked(ms, dir, qfalse, &result);\n\t\t\t//\n\t\t\tif (dist > 60) dist = 60;\n\t\t\tspeed = 360 - (360 - 6 * dist);\n\t\t\t//\n\t\t\tif (!(ms->moveflags & MFL_SWIMMING) && !BotCheckBarrierJump(ms, dir, 50))\n\t\t\t{\n\t\t\t\tif (speed > 5) EA_Move(ms->client, dir, speed);\n\t\t\t} //end if\n\t\t\tVectorCopy(dir, result.movedir);\n\t\t\t//\n\t\t\tif (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;\n\t\t\t//this isn't a failure... just wait till the func_bobbing arrives\n\t\t\tresult.type = RESULTTYPE_WAITFORFUNCBOBBING;\n\t\t\tresult.flags |= MOVERESULT_WAITING;\n\t\t\treturn result;\n\t\t} //end if\n\t\t//get direction and distance to func_bob bottom center\n\t\tMoverBottomCenter(reach, bottomcenter);\n\t\tVectorSubtract(bottomcenter, ms->origin, dir2);\n\t\tif (!(ms->moveflags & MFL_SWIMMING)) dir2[2] = 0;\n\t\tdist2 = VectorNormalize(dir2);\n\t\t//if very close to the reachability start or\n\t\t//closer to the elevator center or\n\t\t//between reachability start and func_bobbing center\n\t\tif (dist1 < 20 || dist2 < dist1 || DotProduct(dir1, dir2) < 0)\n\t\t{\n#ifdef DEBUG_FUNCBOB\n\t\t\tbotimport.Print(PRT_MESSAGE, \"bot moving to func_bobbing center\\n\");\n#endif\n\t\t\tdist = dist2;\n\t\t\tVectorCopy(dir2, dir);\n\t\t} //end if\n\t\telse //closer to the reachability start\n\t\t{\n#ifdef DEBUG_FUNCBOB\n\t\t\tbotimport.Print(PRT_MESSAGE, \"bot moving to reachability start\\n\");\n#endif\n\t\t\tdist = dist1;\n\t\t\tVectorCopy(dir1, dir);\n\t\t} //end else\n\t\t//\n\t\tBotCheckBlocked(ms, dir, qfalse, &result);\n\t\t//\n\t\tif (dist > 60) dist = 60;\n\t\tspeed = 400 - (400 - 6 * dist);\n\t\t//\n\t\tif (!(ms->moveflags & MFL_SWIMMING) && !BotCheckBarrierJump(ms, dir, 50))\n\t\t{\n\t\t\tEA_Move(ms->client, dir, speed);\n\t\t} //end if\n\t\tVectorCopy(dir, result.movedir);\n\t\t//\n\t\tif (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;\n\t} //end else\n\treturn result;\n} //end of the function BotTravel_FuncBobbing\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nbot_moveresult_t BotFinishTravel_FuncBobbing(bot_movestate_t *ms, aas_reachability_t *reach)\n{\n\tvec3_t bob_origin, bob_start, bob_end, dir, hordir, bottomcenter;\n\tbot_moveresult_t result;\n\tfloat dist, speed;\n\n\tBotClearMoveResult(&result);\n\t//\n\tBotFuncBobStartEnd(reach, bob_start, bob_end, bob_origin);\n\t//\n\tVectorSubtract(bob_origin, bob_end, dir);\n\tdist = VectorLength(dir);\n\t//if the func_bobbing is near the end\n\tif (dist < 16)\n\t{\n\t\tVectorSubtract(reach->end, ms->origin, hordir);\n\t\tif (!(ms->moveflags & MFL_SWIMMING)) hordir[2] = 0;\n\t\tdist = VectorNormalize(hordir);\n\t\t//\n\t\tif (dist > 60) dist = 60;\n\t\tspeed = 360 - (360 - 6 * dist);\n\t\t//\n\t\tif (speed > 5) EA_Move(ms->client, dir, speed);\n\t\tVectorCopy(dir, result.movedir);\n\t\t//\n\t\tif (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;\n\t} //end if\n\telse\n\t{\n\t\tMoverBottomCenter(reach, bottomcenter);\n\t\tVectorSubtract(bottomcenter, ms->origin, hordir);\n\t\tif (!(ms->moveflags & MFL_SWIMMING)) hordir[2] = 0;\n\t\tdist = VectorNormalize(hordir);\n\t\t//\n\t\tif (dist > 5)\n\t\t{\n\t\t\t//move to the center of the plat\n\t\t\tif (dist > 100) dist = 100;\n\t\t\tspeed = 400 - (400 - 4 * dist);\n\t\t\t//\n\t\t\tEA_Move(ms->client, hordir, speed);\n\t\t\tVectorCopy(hordir, result.movedir);\n\t\t} //end if\n\t} //end else\n\treturn result;\n} //end of the function BotFinishTravel_FuncBobbing\n//===========================================================================\n// 0  no valid grapple hook visible\n// 1  the grapple hook is still flying\n// 2  the grapple hooked into a wall\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint GrappleState(bot_movestate_t *ms, aas_reachability_t *reach)\n{\n\tint i;\n\taas_entityinfo_t entinfo;\n\n\t//if the grapple hook is pulling\n\tif (ms->moveflags & MFL_GRAPPLEPULL)\n\t\treturn 2;\n\t//check for a visible grapple missile entity\n\t//or visible grapple entity\n\tfor (i = AAS_NextEntity(0); i; i = AAS_NextEntity(i))\n\t{\n\t\tif (AAS_EntityType(i) == (int) entitytypemissile->value)\n\t\t{\n\t\t\tAAS_EntityInfo(i, &entinfo);\n\t\t\tif (entinfo.weapon == (int) weapindex_grapple->value)\n\t\t\t{\n\t\t\t\treturn 1;\n\t\t\t} //end if\n\t\t} //end if\n\t} //end for\n\t//no valid grapple at all\n\treturn 0;\n} //end of the function GrappleState\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotResetGrapple(bot_movestate_t *ms)\n{\n\taas_reachability_t reach;\n\n\tAAS_ReachabilityFromNum(ms->lastreachnum, &reach);\n\t//if not using the grapple hook reachability anymore\n\tif ((reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_GRAPPLEHOOK)\n\t{\n\t\tif ((ms->moveflags & MFL_ACTIVEGRAPPLE) || ms->grapplevisible_time)\n\t\t{\n\t\t\tif (offhandgrapple->value)\n\t\t\t\tEA_Command(ms->client, cmd_grappleoff->string);\n\t\t\tms->moveflags &= ~MFL_ACTIVEGRAPPLE;\n\t\t\tms->grapplevisible_time = 0;\n#ifdef DEBUG_GRAPPLE\n\t\t\tbotimport.Print(PRT_MESSAGE, \"reset grapple\\n\");\n#endif //DEBUG_GRAPPLE\n\t\t} //end if\n\t} //end if\n} //end of the function BotResetGrapple\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nbot_moveresult_t BotTravel_Grapple(bot_movestate_t *ms, aas_reachability_t *reach)\n{\n\tbot_moveresult_t result;\n\tfloat dist, speed;\n\tvec3_t dir, viewdir, org;\n\tint state, areanum;\n\tbsp_trace_t trace;\n\n#ifdef DEBUG_GRAPPLE\n\tstatic int debugline;\n\tif (!debugline) debugline = botimport.DebugLineCreate();\n\tbotimport.DebugLineShow(debugline, reach->start, reach->end, LINECOLOR_BLUE);\n#endif //DEBUG_GRAPPLE\n\n\tBotClearMoveResult(&result);\n\t//\n\tif (ms->moveflags & MFL_GRAPPLERESET)\n\t{\n\t\tif (offhandgrapple->value)\n\t\t\tEA_Command(ms->client, cmd_grappleoff->string);\n\t\tms->moveflags &= ~MFL_ACTIVEGRAPPLE;\n\t\treturn result;\n\t} //end if\n\t//\n\tif (!(int) offhandgrapple->value)\n\t{\n\t\tresult.weapon = weapindex_grapple->value;\n\t\tresult.flags |= MOVERESULT_MOVEMENTWEAPON;\n\t} //end if\n\t//\n\tif (ms->moveflags & MFL_ACTIVEGRAPPLE)\n\t{\n#ifdef DEBUG_GRAPPLE\n\t\tbotimport.Print(PRT_MESSAGE, \"BotTravel_Grapple: active grapple\\n\");\n#endif //DEBUG_GRAPPLE\n\t\t//\n\t\tstate = GrappleState(ms, reach);\n\t\t//\n\t\tVectorSubtract(reach->end, ms->origin, dir);\n\t\tdir[2] = 0;\n\t\tdist = VectorLength(dir);\n\t\t//if very close to the grapple end or the grappled is hooked and\n\t\t//the bot doesn't get any closer\n\t\tif (state && dist < 48)\n\t\t{\n\t\t\tif (ms->lastgrappledist - dist < 1)\n\t\t\t{\n#ifdef DEBUG_GRAPPLE\n\t\t\t\tbotimport.Print(PRT_ERROR, \"grapple normal end\\n\");\n#endif //DEBUG_GRAPPLE\n\t\t\t\tif (offhandgrapple->value)\n\t\t\t\t\tEA_Command(ms->client, cmd_grappleoff->string);\n\t\t\t\tms->moveflags &= ~MFL_ACTIVEGRAPPLE;\n\t\t\t\tms->moveflags |= MFL_GRAPPLERESET;\n\t\t\t\tms->reachability_time = 0;\t//end the reachability\n\t\t\t\treturn result;\n\t\t\t} //end if\n\t\t} //end if\n\t\t//if no valid grapple at all, or the grapple hooked and the bot\n\t\t//isn't moving anymore\n\t\telse if (!state || (state == 2 && dist > ms->lastgrappledist - 2))\n\t\t{\n\t\t\tif (ms->grapplevisible_time < AAS_Time() - 0.4)\n\t\t\t{\n#ifdef DEBUG_GRAPPLE\n\t\t\t\tbotimport.Print(PRT_ERROR, \"grapple not visible\\n\");\n#endif //DEBUG_GRAPPLE\n\t\t\t\tif (offhandgrapple->value)\n\t\t\t\t\tEA_Command(ms->client, cmd_grappleoff->string);\n\t\t\t\tms->moveflags &= ~MFL_ACTIVEGRAPPLE;\n\t\t\t\tms->moveflags |= MFL_GRAPPLERESET;\n\t\t\t\tms->reachability_time = 0;\t//end the reachability\n\t\t\t\treturn result;\n\t\t\t} //end if\n\t\t} //end if\n\t\telse\n\t\t{\n\t\t\tms->grapplevisible_time = AAS_Time();\n\t\t} //end else\n\t\t//\n\t\tif (!(int) offhandgrapple->value)\n\t\t{\n\t\t\tEA_Attack(ms->client);\n\t\t} //end if\n\t\t//remember the current grapple distance\n\t\tms->lastgrappledist = dist;\n\t} //end if\n\telse\n\t{\n#ifdef DEBUG_GRAPPLE\n\t\tbotimport.Print(PRT_MESSAGE, \"BotTravel_Grapple: inactive grapple\\n\");\n#endif //DEBUG_GRAPPLE\n\t\t//\n\t\tms->grapplevisible_time = AAS_Time();\n\t\t//\n\t\tVectorSubtract(reach->start, ms->origin, dir);\n\t\tif (!(ms->moveflags & MFL_SWIMMING)) dir[2] = 0;\n\t\tVectorAdd(ms->origin, ms->viewoffset, org);\n\t\tVectorSubtract(reach->end, org, viewdir);\n\t\t//\n\t\tdist = VectorNormalize(dir);\n\t\tVector2Angles(viewdir, result.ideal_viewangles);\n\t\tresult.flags |= MOVERESULT_MOVEMENTVIEW;\n\t\t//\n\t\tif (dist < 5 &&\n\t\t\tfabs(AngleDiff(result.ideal_viewangles[0], ms->viewangles[0])) < 2 &&\n\t\t\tfabs(AngleDiff(result.ideal_viewangles[1], ms->viewangles[1])) < 2)\n\t\t{\n#ifdef DEBUG_GRAPPLE\n\t\t\tbotimport.Print(PRT_MESSAGE, \"BotTravel_Grapple: activating grapple\\n\");\n#endif //DEBUG_GRAPPLE\n\t\t\t//check if the grapple missile path is clear\n\t\t\tVectorAdd(ms->origin, ms->viewoffset, org);\n\t\t\ttrace = AAS_Trace(org, NULL, NULL, reach->end, ms->entitynum, CONTENTS_SOLID);\n\t\t\tVectorSubtract(reach->end, trace.endpos, dir);\n\t\t\tif (VectorLength(dir) > 16)\n\t\t\t{\n\t\t\t\tresult.failure = qtrue;\n\t\t\t\treturn result;\n\t\t\t} //end if\n\t\t\t//activate the grapple\n\t\t\tif (offhandgrapple->value)\n\t\t\t{\n\t\t\t\tEA_Command(ms->client, cmd_grappleon->string);\n\t\t\t} //end if\n\t\t\telse\n\t\t\t{\n\t\t\t\tEA_Attack(ms->client);\n\t\t\t} //end else\n\t\t\tms->moveflags |= MFL_ACTIVEGRAPPLE;\n\t\t\tms->lastgrappledist = 999999;\n\t\t} //end if\n\t\telse\n\t\t{\n\t\t\tif (dist < 70) speed = 300 - (300 - 4 * dist);\n\t\t\telse speed = 400;\n\t\t\t//\n\t\t\tBotCheckBlocked(ms, dir, qtrue, &result);\n\t\t\t//elemantary action move in direction\n\t\t\tEA_Move(ms->client, dir, speed);\n\t\t\tVectorCopy(dir, result.movedir);\n\t\t} //end else\n\t\t//if in another area before actually grappling\n\t\tareanum = AAS_PointAreaNum(ms->origin);\n\t\tif (areanum && areanum != ms->reachareanum) ms->reachability_time = 0;\n\t} //end else\n\treturn result;\n} //end of the function BotTravel_Grapple\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t\t-\n//===========================================================================\nbot_moveresult_t BotTravel_RocketJump(bot_movestate_t *ms, aas_reachability_t *reach)\n{\n\tvec3_t hordir;\n\tfloat dist, speed;\n\tbot_moveresult_t result;\n\n\t//botimport.Print(PRT_MESSAGE, \"BotTravel_RocketJump: bah\\n\");\n\tBotClearMoveResult(&result);\n\t//\n\thordir[0] = reach->start[0] - ms->origin[0];\n\thordir[1] = reach->start[1] - ms->origin[1];\n\thordir[2] = 0;\n\t//\n\tdist = VectorNormalize(hordir);\n\t//look in the movement direction\n\tVector2Angles(hordir, result.ideal_viewangles);\n\t//look straight down\n\tresult.ideal_viewangles[PITCH] = 90;\n\t//\n\tif (dist < 5 &&\n\t\t\tfabs(AngleDiff(result.ideal_viewangles[0], ms->viewangles[0])) < 5 &&\n\t\t\tfabs(AngleDiff(result.ideal_viewangles[1], ms->viewangles[1])) < 5)\n\t{\n\t\t//botimport.Print(PRT_MESSAGE, \"between jump start and run start point\\n\");\n\t\thordir[0] = reach->end[0] - ms->origin[0];\n\t\thordir[1] = reach->end[1] - ms->origin[1];\n\t\thordir[2] = 0;\n\t\tVectorNormalize(hordir);\n\t\t//elemantary action jump\n\t\tEA_Jump(ms->client);\n\t\tEA_Attack(ms->client);\n\t\tEA_Move(ms->client, hordir, 800);\n\t\t//\n\t\tms->jumpreach = ms->lastreachnum;\n\t} //end if\n\telse\n\t{\n\t\tif (dist > 80) dist = 80;\n\t\tspeed = 400 - (400 - 5 * dist);\n\t\tEA_Move(ms->client, hordir, speed);\n\t} //end else\n\t//look in the movement direction\n\tVector2Angles(hordir, result.ideal_viewangles);\n\t//look straight down\n\tresult.ideal_viewangles[PITCH] = 90;\n\t//set the view angles directly\n\tEA_View(ms->client, result.ideal_viewangles);\n\t//view is important for the movment\n\tresult.flags |= MOVERESULT_MOVEMENTVIEWSET;\n\t//select the rocket launcher\n\tEA_SelectWeapon(ms->client, (int) weapindex_rocketlauncher->value);\n\t//weapon is used for movement\n\tresult.weapon = (int) weapindex_rocketlauncher->value;\n\tresult.flags |= MOVERESULT_MOVEMENTWEAPON;\n\t//\n\tVectorCopy(hordir, result.movedir);\n\t//\n\treturn result;\n} //end of the function BotTravel_RocketJump\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nbot_moveresult_t BotTravel_BFGJump(bot_movestate_t *ms, aas_reachability_t *reach)\n{\n\tvec3_t hordir;\n\tfloat dist, speed;\n\tbot_moveresult_t result;\n\n\t//botimport.Print(PRT_MESSAGE, \"BotTravel_BFGJump: bah\\n\");\n\tBotClearMoveResult(&result);\n\t//\n\thordir[0] = reach->start[0] - ms->origin[0];\n\thordir[1] = reach->start[1] - ms->origin[1];\n\thordir[2] = 0;\n\t//\n\tdist = VectorNormalize(hordir);\n\t//\n\tif (dist < 5 &&\n\t\t\tfabs(AngleDiff(result.ideal_viewangles[0], ms->viewangles[0])) < 5 &&\n\t\t\tfabs(AngleDiff(result.ideal_viewangles[1], ms->viewangles[1])) < 5)\n\t{\n\t\t//botimport.Print(PRT_MESSAGE, \"between jump start and run start point\\n\");\n\t\thordir[0] = reach->end[0] - ms->origin[0];\n\t\thordir[1] = reach->end[1] - ms->origin[1];\n\t\thordir[2] = 0;\n\t\tVectorNormalize(hordir);\n\t\t//elemantary action jump\n\t\tEA_Jump(ms->client);\n\t\tEA_Attack(ms->client);\n\t\tEA_Move(ms->client, hordir, 800);\n\t\t//\n\t\tms->jumpreach = ms->lastreachnum;\n\t} //end if\n\telse\n\t{\n\t\tif (dist > 80) dist = 80;\n\t\tspeed = 400 - (400 - 5 * dist);\n\t\tEA_Move(ms->client, hordir, speed);\n\t} //end else\n\t//look in the movement direction\n\tVector2Angles(hordir, result.ideal_viewangles);\n\t//look straight down\n\tresult.ideal_viewangles[PITCH] = 90;\n\t//set the view angles directly\n\tEA_View(ms->client, result.ideal_viewangles);\n\t//view is important for the movment\n\tresult.flags |= MOVERESULT_MOVEMENTVIEWSET;\n\t//select the rocket launcher\n\tEA_SelectWeapon(ms->client, (int) weapindex_bfg10k->value);\n\t//weapon is used for movement\n\tresult.weapon = (int) weapindex_bfg10k->value;\n\tresult.flags |= MOVERESULT_MOVEMENTWEAPON;\n\t//\n\tVectorCopy(hordir, result.movedir);\n\t//\n\treturn result;\n} //end of the function BotTravel_BFGJump\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nbot_moveresult_t BotFinishTravel_WeaponJump(bot_movestate_t *ms, aas_reachability_t *reach)\n{\n\tvec3_t hordir;\n\tfloat speed;\n\tbot_moveresult_t result;\n\n\tBotClearMoveResult(&result);\n\t//if not jumped yet\n\tif (!ms->jumpreach) return result;\n\t/*\n\t//go straight to the reachability end\n\thordir[0] = reach->end[0] - ms->origin[0];\n\thordir[1] = reach->end[1] - ms->origin[1];\n\thordir[2] = 0;\n\tVectorNormalize(hordir);\n\t//always use max speed when traveling through the air\n\tEA_Move(ms->client, hordir, 800);\n\tVectorCopy(hordir, result.movedir);\n\t*/\n\t//\n\tif (!BotAirControl(ms->origin, ms->velocity, reach->end, hordir, &speed))\n\t{\n\t\t//go straight to the reachability end\n\t\tVectorSubtract(reach->end, ms->origin, hordir);\n\t\thordir[2] = 0;\n\t\tVectorNormalize(hordir);\n\t\tspeed = 400;\n\t} //end if\n\t//\n\tEA_Move(ms->client, hordir, speed);\n\tVectorCopy(hordir, result.movedir);\n\t//\n\treturn result;\n} //end of the function BotFinishTravel_WeaponJump\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nbot_moveresult_t BotTravel_JumpPad(bot_movestate_t *ms, aas_reachability_t *reach)\n{\n\tfloat dist, speed;\n\tvec3_t hordir;\n\tbot_moveresult_t result;\n\n\tBotClearMoveResult(&result);\n\t//first walk straight to the reachability start\n\thordir[0] = reach->start[0] - ms->origin[0];\n\thordir[1] = reach->start[1] - ms->origin[1];\n\thordir[2] = 0;\n\tdist = VectorNormalize(hordir);\n\t//\n\tBotCheckBlocked(ms, hordir, qtrue, &result);\n\tspeed = 400;\n\t//elemantary action move in direction\n\tEA_Move(ms->client, hordir, speed);\n\tVectorCopy(hordir, result.movedir);\n\t//\n\treturn result;\n} //end of the function BotTravel_JumpPad\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nbot_moveresult_t BotFinishTravel_JumpPad(bot_movestate_t *ms, aas_reachability_t *reach)\n{\n\tfloat speed;\n\tvec3_t hordir;\n\tbot_moveresult_t result;\n\n\tBotClearMoveResult(&result);\n\tif (!BotAirControl(ms->origin, ms->velocity, reach->end, hordir, &speed))\n\t{\n\t\thordir[0] = reach->end[0] - ms->origin[0];\n\t\thordir[1] = reach->end[1] - ms->origin[1];\n\t\thordir[2] = 0;\n\t\tVectorNormalize(hordir);\n\t\tspeed = 400;\n\t} //end if\n\tBotCheckBlocked(ms, hordir, qtrue, &result);\n\t//elemantary action move in direction\n\tEA_Move(ms->client, hordir, speed);\n\tVectorCopy(hordir, result.movedir);\n\t//\n\treturn result;\n} //end of the function BotFinishTravel_JumpPad\n//===========================================================================\n// time before the reachability times out\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotReachabilityTime(aas_reachability_t *reach)\n{\n\tswitch(reach->traveltype & TRAVELTYPE_MASK)\n\t{\n\t\tcase TRAVEL_WALK: return 5;\n\t\tcase TRAVEL_CROUCH: return 5;\n\t\tcase TRAVEL_BARRIERJUMP: return 5;\n\t\tcase TRAVEL_LADDER: return 6;\n\t\tcase TRAVEL_WALKOFFLEDGE: return 5;\n\t\tcase TRAVEL_JUMP: return 5;\n\t\tcase TRAVEL_SWIM: return 5;\n\t\tcase TRAVEL_WATERJUMP: return 5;\n\t\tcase TRAVEL_TELEPORT: return 5;\n\t\tcase TRAVEL_ELEVATOR: return 10;\n\t\tcase TRAVEL_GRAPPLEHOOK: return 8;\n\t\tcase TRAVEL_ROCKETJUMP: return 6;\n\t\tcase TRAVEL_BFGJUMP: return 6;\n\t\tcase TRAVEL_JUMPPAD: return 10;\n\t\tcase TRAVEL_FUNCBOB: return 10;\n\t\tdefault:\n\t\t{\n\t\t\tbotimport.Print(PRT_ERROR, \"travel type %d not implemented yet\\n\", reach->traveltype);\n\t\t\treturn 8;\n\t\t} //end case\n\t} //end switch\n} //end of the function BotReachabilityTime\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nbot_moveresult_t BotMoveInGoalArea(bot_movestate_t *ms, bot_goal_t *goal)\n{\n\tbot_moveresult_t result;\n\tvec3_t dir;\n\tfloat dist, speed;\n\n#ifdef DEBUG\n\t//botimport.Print(PRT_MESSAGE, \"%s: moving straight to goal\\n\", ClientName(ms->entitynum-1));\n\t//AAS_ClearShownDebugLines();\n\t//AAS_DebugLine(ms->origin, goal->origin, LINECOLOR_RED);\n#endif //DEBUG\n\tBotClearMoveResult(&result);\n\t//walk straight to the goal origin\n\tdir[0] = goal->origin[0] - ms->origin[0];\n\tdir[1] = goal->origin[1] - ms->origin[1];\n\tif (ms->moveflags & MFL_SWIMMING)\n\t{\n\t\tdir[2] = goal->origin[2] - ms->origin[2];\n\t\tresult.traveltype = TRAVEL_SWIM;\n\t} //end if\n\telse\n\t{\n\t\tdir[2] = 0;\n\t\tresult.traveltype = TRAVEL_WALK;\n\t} //endif\n\t//\n\tdist = VectorNormalize(dir);\n\tif (dist > 100) dist = 100;\n\tspeed = 400 - (400 - 4 * dist);\n\tif (speed < 10) speed = 0;\n\t//\n\tBotCheckBlocked(ms, dir, qtrue, &result);\n\t//elemantary action move in direction\n\tEA_Move(ms->client, dir, speed);\n\tVectorCopy(dir, result.movedir);\n\t//\n\tif (ms->moveflags & MFL_SWIMMING)\n\t{\n\t\tVector2Angles(dir, result.ideal_viewangles);\n\t\tresult.flags |= MOVERESULT_SWIMVIEW;\n\t} //end if\n\t//if (!debugline) debugline = botimport.DebugLineCreate();\n\t//botimport.DebugLineShow(debugline, ms->origin, goal->origin, LINECOLOR_BLUE);\n\t//\n\tms->lastreachnum = 0;\n\tms->lastareanum = 0;\n\tms->lastgoalareanum = goal->areanum;\n\tVectorCopy(ms->origin, ms->lastorigin);\n\t//\n\treturn result;\n} //end of the function BotMoveInGoalArea\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotMoveToGoal(bot_moveresult_t *result, int movestate, bot_goal_t *goal, int travelflags)\n{\n\tint reachnum, lastreachnum, foundjumppad, ent, resultflags;\n\taas_reachability_t reach, lastreach;\n\tbot_movestate_t *ms;\n\t//vec3_t mins, maxs, up = {0, 0, 1};\n\t//bsp_trace_t trace;\n\t//static int debugline;\n\n\n\tBotClearMoveResult(result);\n\t//\n\tms = BotMoveStateFromHandle(movestate);\n\tif (!ms) return;\n\t//reset the grapple before testing if the bot has a valid goal\n\t//because the bot could loose all it's goals when stuck to a wall\n\tBotResetGrapple(ms);\n\t//\n\tif (!goal)\n\t{\n#ifdef DEBUG\n\t\tbotimport.Print(PRT_MESSAGE, \"client %d: movetogoal -> no goal\\n\", ms->client);\n#endif //DEBUG\n\t\tresult->failure = qtrue;\n\t\treturn;\n\t} //end if\n\t//botimport.Print(PRT_MESSAGE, \"numavoidreach = %d\\n\", ms->numavoidreach);\n\t//remove some of the move flags\n\tms->moveflags &= ~(MFL_SWIMMING|MFL_AGAINSTLADDER);\n\t//set some of the move flags\n\t//NOTE: the MFL_ONGROUND flag is also set in the higher AI\n\tif (AAS_OnGround(ms->origin, ms->presencetype, ms->entitynum)) ms->moveflags |= MFL_ONGROUND;\n\t//\n\tif (ms->moveflags & MFL_ONGROUND)\n\t{\n\t\tint modeltype, modelnum;\n\n\t\tent = BotOnTopOfEntity(ms);\n\n\t\tif (ent != -1)\n\t\t{\n\t\t\tmodelnum = AAS_EntityModelindex(ent);\n\t\t\tif (modelnum >= 0 && modelnum < MAX_MODELS)\n\t\t\t{\n\t\t\t\tmodeltype = modeltypes[modelnum];\n\n\t\t\t\tif (modeltype == MODELTYPE_FUNC_PLAT)\n\t\t\t\t{\n\t\t\t\t\tAAS_ReachabilityFromNum(ms->lastreachnum, &reach);\n\t\t\t\t\t//if the bot is Not using the elevator\n\t\t\t\t\tif ((reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_ELEVATOR ||\n\t\t\t\t\t\t//NOTE: the face number is the plat model number\n\t\t\t\t\t\t(reach.facenum & 0x0000FFFF) != modelnum)\n\t\t\t\t\t{\n\t\t\t\t\t\treachnum = AAS_NextModelReachability(0, modelnum);\n\t\t\t\t\t\tif (reachnum)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t//botimport.Print(PRT_MESSAGE, \"client %d: accidentally ended up on func_plat\\n\", ms->client);\n\t\t\t\t\t\t\tAAS_ReachabilityFromNum(reachnum, &reach);\n\t\t\t\t\t\t\tms->lastreachnum = reachnum;\n\t\t\t\t\t\t\tms->reachability_time = AAS_Time() + BotReachabilityTime(&reach);\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (bot_developer)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tbotimport.Print(PRT_MESSAGE, \"client %d: on func_plat without reachability\\n\", ms->client);\n\t\t\t\t\t\t\t} //end if\n\t\t\t\t\t\t\tresult->blocked = qtrue;\n\t\t\t\t\t\t\tresult->blockentity = ent;\n\t\t\t\t\t\t\tresult->flags |= MOVERESULT_ONTOPOFOBSTACLE;\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t} //end else\n\t\t\t\t\t} //end if\n\t\t\t\t\tresult->flags |= MOVERESULT_ONTOPOF_ELEVATOR;\n\t\t\t\t} //end if\n\t\t\t\telse if (modeltype == MODELTYPE_FUNC_BOB)\n\t\t\t\t{\n\t\t\t\t\tAAS_ReachabilityFromNum(ms->lastreachnum, &reach);\n\t\t\t\t\t//if the bot is Not using the func bobbing\n\t\t\t\t\tif ((reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_FUNCBOB ||\n\t\t\t\t\t\t//NOTE: the face number is the func_bobbing model number\n\t\t\t\t\t\t(reach.facenum & 0x0000FFFF) != modelnum)\n\t\t\t\t\t{\n\t\t\t\t\t\treachnum = AAS_NextModelReachability(0, modelnum);\n\t\t\t\t\t\tif (reachnum)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t//botimport.Print(PRT_MESSAGE, \"client %d: accidentally ended up on func_bobbing\\n\", ms->client);\n\t\t\t\t\t\t\tAAS_ReachabilityFromNum(reachnum, &reach);\n\t\t\t\t\t\t\tms->lastreachnum = reachnum;\n\t\t\t\t\t\t\tms->reachability_time = AAS_Time() + BotReachabilityTime(&reach);\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (bot_developer)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tbotimport.Print(PRT_MESSAGE, \"client %d: on func_bobbing without reachability\\n\", ms->client);\n\t\t\t\t\t\t\t} //end if\n\t\t\t\t\t\t\tresult->blocked = qtrue;\n\t\t\t\t\t\t\tresult->blockentity = ent;\n\t\t\t\t\t\t\tresult->flags |= MOVERESULT_ONTOPOFOBSTACLE;\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t} //end else\n\t\t\t\t\t} //end if\n\t\t\t\t\tresult->flags |= MOVERESULT_ONTOPOF_FUNCBOB;\n\t\t\t\t} //end if\n\t\t\t\telse if (modeltype == MODELTYPE_FUNC_STATIC || modeltype == MODELTYPE_FUNC_DOOR)\n\t\t\t\t{\n\t\t\t\t\t// check if ontop of a door bridge ?\n\t\t\t\t\tms->areanum = BotFuzzyPointReachabilityArea(ms->origin);\n\t\t\t\t\t// if not in a reachability area\n\t\t\t\t\tif (!AAS_AreaReachability(ms->areanum))\n\t\t\t\t\t{\n\t\t\t\t\t\tresult->blocked = qtrue;\n\t\t\t\t\t\tresult->blockentity = ent;\n\t\t\t\t\t\tresult->flags |= MOVERESULT_ONTOPOFOBSTACLE;\n\t\t\t\t\t\treturn;\n\t\t\t\t\t} //end if\n\t\t\t\t} //end else if\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tresult->blocked = qtrue;\n\t\t\t\t\tresult->blockentity = ent;\n\t\t\t\t\tresult->flags |= MOVERESULT_ONTOPOFOBSTACLE;\n\t\t\t\t\treturn;\n\t\t\t\t} //end else\n\t\t\t} //end if\n\t\t} //end if\n\t} //end if\n\t//if swimming\n\tif (AAS_Swimming(ms->origin)) ms->moveflags |= MFL_SWIMMING;\n\t//if against a ladder\n\tif (AAS_AgainstLadder(ms->origin)) ms->moveflags |= MFL_AGAINSTLADDER;\n\t//if the bot is on the ground, swimming or against a ladder\n\tif (ms->moveflags & (MFL_ONGROUND|MFL_SWIMMING|MFL_AGAINSTLADDER))\n\t{\n\t\t//botimport.Print(PRT_MESSAGE, \"%s: onground, swimming or against ladder\\n\", ClientName(ms->entitynum-1));\n\t\t//\n\t\tAAS_ReachabilityFromNum(ms->lastreachnum, &lastreach);\n\t\t//reachability area the bot is in\n\t\t//ms->areanum = BotReachabilityArea(ms->origin, ((lastreach.traveltype & TRAVELTYPE_MASK) != TRAVEL_ELEVATOR));\n\t\tms->areanum = BotFuzzyPointReachabilityArea(ms->origin);\n\t\t//\n\t\tif ( !ms->areanum )\n\t\t{\n\t\t\tresult->failure = qtrue;\n\t\t\tresult->blocked = qtrue;\n\t\t\tresult->blockentity = 0;\n\t\t\tresult->type = RESULTTYPE_INSOLIDAREA;\n\t\t\treturn;\n\t\t} //end if\n\t\t//if the bot is in the goal area\n\t\tif (ms->areanum == goal->areanum)\n\t\t{\n\t\t\t*result = BotMoveInGoalArea(ms, goal);\n\t\t\treturn;\n\t\t} //end if\n\t\t//assume we can use the reachability from the last frame\n\t\treachnum = ms->lastreachnum;\n\t\t//if there is a last reachability\n\t\tif (reachnum)\n\t\t{\n\t\t\tAAS_ReachabilityFromNum(reachnum, &reach);\n\t\t\t//check if the reachability is still valid\n\t\t\tif (!(AAS_TravelFlagForType(reach.traveltype) & travelflags))\n\t\t\t{\n\t\t\t\treachnum = 0;\n\t\t\t} //end if\n\t\t\t//special grapple hook case\n\t\t\telse if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_GRAPPLEHOOK)\n\t\t\t{\n\t\t\t\tif (ms->reachability_time < AAS_Time() ||\n\t\t\t\t\t(ms->moveflags & MFL_GRAPPLERESET))\n\t\t\t\t{\n\t\t\t\t\treachnum = 0;\n\t\t\t\t} //end if\n\t\t\t} //end if\n\t\t\t//special elevator case\n\t\t\telse if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_ELEVATOR ||\n\t\t\t\t(reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_FUNCBOB)\n\t\t\t{\n\t\t\t\tif ((result->flags & MOVERESULT_ONTOPOF_FUNCBOB) ||\n\t\t\t\t\t(result->flags & MOVERESULT_ONTOPOF_FUNCBOB))\n\t\t\t\t{\n\t\t\t\t\tms->reachability_time = AAS_Time() + 5;\n\t\t\t\t} //end if\n\t\t\t\t//if the bot was going for an elevator and reached the reachability area\n\t\t\t\tif (ms->areanum == reach.areanum ||\n\t\t\t\t\tms->reachability_time < AAS_Time())\n\t\t\t\t{\n\t\t\t\t\treachnum = 0;\n\t\t\t\t} //end if\n\t\t\t} //end if\n\t\t\telse\n\t\t\t{\n#ifdef DEBUG\n\t\t\t\tif (bot_developer)\n\t\t\t\t{\n\t\t\t\t\tif (ms->reachability_time < AAS_Time())\n\t\t\t\t\t{\n\t\t\t\t\t\tbotimport.Print(PRT_MESSAGE, \"client %d: reachability timeout in \", ms->client);\n\t\t\t\t\t\tAAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK);\n\t\t\t\t\t\tbotimport.Print(PRT_MESSAGE, \"\\n\");\n\t\t\t\t\t} //end if\n\t\t\t\t\t/*\n\t\t\t\t\tif (ms->lastareanum != ms->areanum)\n\t\t\t\t\t{\n\t\t\t\t\t\tbotimport.Print(PRT_MESSAGE, \"changed from area %d to %d\\n\", ms->lastareanum, ms->areanum);\n\t\t\t\t\t} //end if*/\n\t\t\t\t} //end if\n#endif //DEBUG\n\t\t\t\t//if the goal area changed or the reachability timed out\n\t\t\t\t//or the area changed\n\t\t\t\tif (ms->lastgoalareanum != goal->areanum ||\n\t\t\t\t\t\tms->reachability_time < AAS_Time() ||\n\t\t\t\t\t\tms->lastareanum != ms->areanum)\n\t\t\t\t{\n\t\t\t\t\treachnum = 0;\n\t\t\t\t\t//botimport.Print(PRT_MESSAGE, \"area change or timeout\\n\");\n\t\t\t\t} //end else if\n\t\t\t} //end else\n\t\t} //end if\n\t\tresultflags = 0;\n\t\t//if the bot needs a new reachability\n\t\tif (!reachnum)\n\t\t{\n\t\t\t//if the area has no reachability links\n\t\t\tif (!AAS_AreaReachability(ms->areanum))\n\t\t\t{\n#ifdef DEBUG\n\t\t\t\tif (bot_developer)\n\t\t\t\t{\n\t\t\t\t\tbotimport.Print(PRT_MESSAGE, \"area %d no reachability\\n\", ms->areanum);\n\t\t\t\t} //end if\n#endif //DEBUG\n\t\t\t} //end if\n\t\t\t//get a new reachability leading towards the goal\n\t\t\treachnum = BotGetReachabilityToGoal(ms->origin, ms->areanum,\n\t\t\t\t\t\t\t\tms->lastgoalareanum, ms->lastareanum,\n\t\t\t\t\t\t\t\t\t\t\tms->avoidreach, ms->avoidreachtimes, ms->avoidreachtries,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tgoal, travelflags, travelflags,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tms->avoidspots, ms->numavoidspots, &resultflags);\n\t\t\t//the area number the reachability starts in\n\t\t\tms->reachareanum = ms->areanum;\n\t\t\t//reset some state variables\n\t\t\tms->jumpreach = 0;\t\t\t\t\t\t//for TRAVEL_JUMP\n\t\t\tms->moveflags &= ~MFL_GRAPPLERESET;\t//for TRAVEL_GRAPPLEHOOK\n\t\t\t//if there is a reachability to the goal\n\t\t\tif (reachnum)\n\t\t\t{\n\t\t\t\tAAS_ReachabilityFromNum(reachnum, &reach);\n\t\t\t\t//set a timeout for this reachability\n\t\t\t\tms->reachability_time = AAS_Time() + BotReachabilityTime(&reach);\n\t\t\t\t//\n#ifdef AVOIDREACH\n\t\t\t\t//add the reachability to the reachabilities to avoid for a while\n\t\t\t\tBotAddToAvoidReach(ms, reachnum, AVOIDREACH_TIME);\n#endif //AVOIDREACH\n\t\t\t} //end if\n#ifdef DEBUG\n\t\t\t\n\t\t\telse if (bot_developer)\n\t\t\t{\n\t\t\t\tbotimport.Print(PRT_MESSAGE, \"goal not reachable\\n\");\n\t\t\t\tCom_Memset(&reach, 0, sizeof(aas_reachability_t)); //make compiler happy\n\t\t\t} //end else\n\t\t\tif (bot_developer)\n\t\t\t{\n\t\t\t\t//if still going for the same goal\n\t\t\t\tif (ms->lastgoalareanum == goal->areanum)\n\t\t\t\t{\n\t\t\t\t\tif (ms->lastareanum == reach.areanum)\n\t\t\t\t\t{\n\t\t\t\t\t\tbotimport.Print(PRT_MESSAGE, \"same goal, going back to previous area\\n\");\n\t\t\t\t\t} //end if\n\t\t\t\t} //end if\n\t\t\t} //end if\n#endif //DEBUG\n\t\t} //end else\n\t\t//\n\t\tms->lastreachnum = reachnum;\n\t\tms->lastgoalareanum = goal->areanum;\n\t\tms->lastareanum = ms->areanum;\n\t\t//if the bot has a reachability\n\t\tif (reachnum)\n\t\t{\n\t\t\t//get the reachability from the number\n\t\t\tAAS_ReachabilityFromNum(reachnum, &reach);\n\t\t\tresult->traveltype = reach.traveltype;\n\t\t\t//\n#ifdef DEBUG_AI_MOVE\n\t\t\tAAS_ClearShownDebugLines();\n\t\t\tAAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK);\n\t\t\tAAS_ShowReachability(&reach);\n#endif //DEBUG_AI_MOVE\n\t\t\t//\n#ifdef DEBUG\n\t\t\t//botimport.Print(PRT_MESSAGE, \"client %d: \", ms->client);\n\t\t\t//AAS_PrintTravelType(reach.traveltype);\n\t\t\t//botimport.Print(PRT_MESSAGE, \"\\n\");\n#endif //DEBUG\n\t\t\tswitch(reach.traveltype & TRAVELTYPE_MASK)\n\t\t\t{\n\t\t\t\tcase TRAVEL_WALK: *result = BotTravel_Walk(ms, &reach); break;\n\t\t\t\tcase TRAVEL_CROUCH: *result = BotTravel_Crouch(ms, &reach); break;\n\t\t\t\tcase TRAVEL_BARRIERJUMP: *result = BotTravel_BarrierJump(ms, &reach); break;\n\t\t\t\tcase TRAVEL_LADDER: *result = BotTravel_Ladder(ms, &reach); break;\n\t\t\t\tcase TRAVEL_WALKOFFLEDGE: *result = BotTravel_WalkOffLedge(ms, &reach); break;\n\t\t\t\tcase TRAVEL_JUMP: *result = BotTravel_Jump(ms, &reach); break;\n\t\t\t\tcase TRAVEL_SWIM: *result = BotTravel_Swim(ms, &reach); break;\n\t\t\t\tcase TRAVEL_WATERJUMP: *result = BotTravel_WaterJump(ms, &reach); break;\n\t\t\t\tcase TRAVEL_TELEPORT: *result = BotTravel_Teleport(ms, &reach); break;\n\t\t\t\tcase TRAVEL_ELEVATOR: *result = BotTravel_Elevator(ms, &reach); break;\n\t\t\t\tcase TRAVEL_GRAPPLEHOOK: *result = BotTravel_Grapple(ms, &reach); break;\n\t\t\t\tcase TRAVEL_ROCKETJUMP: *result = BotTravel_RocketJump(ms, &reach); break;\n\t\t\t\tcase TRAVEL_BFGJUMP: *result = BotTravel_BFGJump(ms, &reach); break;\n\t\t\t\tcase TRAVEL_JUMPPAD: *result = BotTravel_JumpPad(ms, &reach); break;\n\t\t\t\tcase TRAVEL_FUNCBOB: *result = BotTravel_FuncBobbing(ms, &reach); break;\n\t\t\t\tdefault:\n\t\t\t\t{\n\t\t\t\t\tbotimport.Print(PRT_FATAL, \"travel type %d not implemented yet\\n\", (reach.traveltype & TRAVELTYPE_MASK));\n\t\t\t\t\tbreak;\n\t\t\t\t} //end case\n\t\t\t} //end switch\n\t\t\tresult->traveltype = reach.traveltype;\n\t\t\tresult->flags |= resultflags;\n\t\t} //end if\n\t\telse\n\t\t{\n\t\t\tresult->failure = qtrue;\n\t\t\tresult->flags |= resultflags;\n\t\t\tCom_Memset(&reach, 0, sizeof(aas_reachability_t));\n\t\t} //end else\n#ifdef DEBUG\n\t\tif (bot_developer)\n\t\t{\n\t\t\tif (result->failure)\n\t\t\t{\n\t\t\t\tbotimport.Print(PRT_MESSAGE, \"client %d: movement failure in \", ms->client);\n\t\t\t\tAAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK);\n\t\t\t\tbotimport.Print(PRT_MESSAGE, \"\\n\");\n\t\t\t} //end if\n\t\t} //end if\n#endif //DEBUG\n\t} //end if\n\telse\n\t{\n\t\tint i, numareas, areas[16];\n\t\tvec3_t end;\n\n\t\t//special handling of jump pads when the bot uses a jump pad without knowing it\n\t\tfoundjumppad = qfalse;\n\t\tVectorMA(ms->origin, -2 * ms->thinktime, ms->velocity, end);\n\t\tnumareas = AAS_TraceAreas(ms->origin, end, areas, NULL, 16);\n\t\tfor (i = numareas-1; i >= 0; i--)\n\t\t{\n\t\t\tif (AAS_AreaJumpPad(areas[i]))\n\t\t\t{\n\t\t\t\t//botimport.Print(PRT_MESSAGE, \"client %d used a jumppad without knowing, area %d\\n\", ms->client, areas[i]);\n\t\t\t\tfoundjumppad = qtrue;\n\t\t\t\tlastreachnum = BotGetReachabilityToGoal(end, areas[i],\n\t\t\t\t\t\t\tms->lastgoalareanum, ms->lastareanum,\n\t\t\t\t\t\t\tms->avoidreach, ms->avoidreachtimes, ms->avoidreachtries,\n\t\t\t\t\t\t\tgoal, travelflags, TFL_JUMPPAD, ms->avoidspots, ms->numavoidspots, NULL);\n\t\t\t\tif (lastreachnum)\n\t\t\t\t{\n\t\t\t\t\tms->lastreachnum = lastreachnum;\n\t\t\t\t\tms->lastareanum = areas[i];\n\t\t\t\t\t//botimport.Print(PRT_MESSAGE, \"found jumppad reachability\\n\");\n\t\t\t\t\tbreak;\n\t\t\t\t} //end if\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tfor (lastreachnum = AAS_NextAreaReachability(areas[i], 0); lastreachnum;\n\t\t\t\t\t\tlastreachnum = AAS_NextAreaReachability(areas[i], lastreachnum))\n\t\t\t\t\t{\n\t\t\t\t\t\t//get the reachability from the number\n\t\t\t\t\t\tAAS_ReachabilityFromNum(lastreachnum, &reach);\n\t\t\t\t\t\tif ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_JUMPPAD)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tms->lastreachnum = lastreachnum;\n\t\t\t\t\t\t\tms->lastareanum = areas[i];\n\t\t\t\t\t\t\t//botimport.Print(PRT_MESSAGE, \"found jumppad reachability hard!!\\n\");\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t} //end for\n\t\t\t\t\tif (lastreachnum) break;\n\t\t\t\t} //end else\n\t\t\t} //end if\n\t\t} //end for\n\t\tif (bot_developer)\n\t\t{\n\t\t\t//if a jumppad is found with the trace but no reachability is found\n\t\t\tif (foundjumppad && !ms->lastreachnum)\n\t\t\t{\n\t\t\t\tbotimport.Print(PRT_MESSAGE, \"client %d didn't find jumppad reachability\\n\", ms->client);\n\t\t\t} //end if\n\t\t} //end if\n\t\t//\n\t\tif (ms->lastreachnum)\n\t\t{\n\t\t\t//botimport.Print(PRT_MESSAGE, \"%s: NOT onground, swimming or against ladder\\n\", ClientName(ms->entitynum-1));\n\t\t\tAAS_ReachabilityFromNum(ms->lastreachnum, &reach);\n\t\t\tresult->traveltype = reach.traveltype;\n#ifdef DEBUG\n\t\t\t//botimport.Print(PRT_MESSAGE, \"client %d finish: \", ms->client);\n\t\t\t//AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK);\n\t\t\t//botimport.Print(PRT_MESSAGE, \"\\n\");\n#endif //DEBUG\n\t\t\t//\n\t\t\tswitch(reach.traveltype & TRAVELTYPE_MASK)\n\t\t\t{\n\t\t\t\tcase TRAVEL_WALK: *result = BotTravel_Walk(ms, &reach); break;//BotFinishTravel_Walk(ms, &reach); break;\n\t\t\t\tcase TRAVEL_CROUCH: /*do nothing*/ break;\n\t\t\t\tcase TRAVEL_BARRIERJUMP: *result = BotFinishTravel_BarrierJump(ms, &reach); break;\n\t\t\t\tcase TRAVEL_LADDER: *result = BotTravel_Ladder(ms, &reach); break;\n\t\t\t\tcase TRAVEL_WALKOFFLEDGE: *result = BotFinishTravel_WalkOffLedge(ms, &reach); break;\n\t\t\t\tcase TRAVEL_JUMP: *result = BotFinishTravel_Jump(ms, &reach); break;\n\t\t\t\tcase TRAVEL_SWIM: *result = BotTravel_Swim(ms, &reach); break;\n\t\t\t\tcase TRAVEL_WATERJUMP: *result = BotFinishTravel_WaterJump(ms, &reach); break;\n\t\t\t\tcase TRAVEL_TELEPORT: /*do nothing*/ break;\n\t\t\t\tcase TRAVEL_ELEVATOR: *result = BotFinishTravel_Elevator(ms, &reach); break;\n\t\t\t\tcase TRAVEL_GRAPPLEHOOK: *result = BotTravel_Grapple(ms, &reach); break;\n\t\t\t\tcase TRAVEL_ROCKETJUMP:\n\t\t\t\tcase TRAVEL_BFGJUMP: *result = BotFinishTravel_WeaponJump(ms, &reach); break;\n\t\t\t\tcase TRAVEL_JUMPPAD: *result = BotFinishTravel_JumpPad(ms, &reach); break;\n\t\t\t\tcase TRAVEL_FUNCBOB: *result = BotFinishTravel_FuncBobbing(ms, &reach); break;\n\t\t\t\tdefault:\n\t\t\t\t{\n\t\t\t\t\tbotimport.Print(PRT_FATAL, \"(last) travel type %d not implemented yet\\n\", (reach.traveltype & TRAVELTYPE_MASK));\n\t\t\t\t\tbreak;\n\t\t\t\t} //end case\n\t\t\t} //end switch\n\t\t\tresult->traveltype = reach.traveltype;\n#ifdef DEBUG\n\t\t\tif (bot_developer)\n\t\t\t{\n\t\t\t\tif (result->failure)\n\t\t\t\t{\n\t\t\t\t\tbotimport.Print(PRT_MESSAGE, \"client %d: movement failure in finish \", ms->client);\n\t\t\t\t\tAAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK);\n\t\t\t\t\tbotimport.Print(PRT_MESSAGE, \"\\n\");\n\t\t\t\t} //end if\n\t\t\t} //end if\n#endif //DEBUG\n\t\t} //end if\n\t} //end else\n\t//FIXME: is it right to do this here?\n\tif (result->blocked) ms->reachability_time -= 10 * ms->thinktime;\n\t//copy the last origin\n\tVectorCopy(ms->origin, ms->lastorigin);\n\t//return the movement result\n\treturn;\n} //end of the function BotMoveToGoal\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotResetAvoidReach(int movestate)\n{\n\tbot_movestate_t *ms;\n\n\tms = BotMoveStateFromHandle(movestate);\n\tif (!ms) return;\n\tCom_Memset(ms->avoidreach, 0, MAX_AVOIDREACH * sizeof(int));\n\tCom_Memset(ms->avoidreachtimes, 0, MAX_AVOIDREACH * sizeof(float));\n\tCom_Memset(ms->avoidreachtries, 0, MAX_AVOIDREACH * sizeof(int));\n} //end of the function BotResetAvoidReach\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotResetLastAvoidReach(int movestate)\n{\n\tint i, latest;\n\tfloat latesttime;\n\tbot_movestate_t *ms;\n\n\tms = BotMoveStateFromHandle(movestate);\n\tif (!ms) return;\n\tlatesttime = 0;\n\tlatest = 0;\n\tfor (i = 0; i < MAX_AVOIDREACH; i++)\n\t{\n\t\tif (ms->avoidreachtimes[i] > latesttime)\n\t\t{\n\t\t\tlatesttime = ms->avoidreachtimes[i];\n\t\t\tlatest = i;\n\t\t} //end if\n\t} //end for\n\tif (latesttime)\n\t{\n\t\tms->avoidreachtimes[latest] = 0;\n\t\tif (ms->avoidreachtries[i] > 0) ms->avoidreachtries[latest]--;\n\t} //end if\n} //end of the function BotResetLastAvoidReach\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotResetMoveState(int movestate)\n{\n\tbot_movestate_t *ms;\n\n\tms = BotMoveStateFromHandle(movestate);\n\tif (!ms) return;\n\tCom_Memset(ms, 0, sizeof(bot_movestate_t));\n} //end of the function BotResetMoveState\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotSetupMoveAI(void)\n{\n\tBotSetBrushModelTypes();\n\tsv_maxstep = LibVar(\"sv_step\", \"18\");\n\tsv_maxbarrier = LibVar(\"sv_maxbarrier\", \"32\");\n\tsv_gravity = LibVar(\"sv_gravity\", \"800\");\n\tweapindex_rocketlauncher = LibVar(\"weapindex_rocketlauncher\", \"5\");\n\tweapindex_bfg10k = LibVar(\"weapindex_bfg10k\", \"9\");\n\tweapindex_grapple = LibVar(\"weapindex_grapple\", \"10\");\n\tentitytypemissile = LibVar(\"entitytypemissile\", \"3\");\n\toffhandgrapple = LibVar(\"offhandgrapple\", \"0\");\n\tcmd_grappleon = LibVar(\"cmd_grappleon\", \"grappleon\");\n\tcmd_grappleoff = LibVar(\"cmd_grappleoff\", \"grappleoff\");\n\treturn BLERR_NOERROR;\n} //end of the function BotSetupMoveAI\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotShutdownMoveAI(void)\n{\n\tint i;\n\n\tfor (i = 1; i <= MAX_CLIENTS; i++)\n\t{\n\t\tif (botmovestates[i])\n\t\t{\n\t\t\tFreeMemory(botmovestates[i]);\n\t\t\tbotmovestates[i] = NULL;\n\t\t} //end if\n\t} //end for\n} //end of the function BotShutdownMoveAI\n\n\n"
  },
  {
    "path": "src/engine/botlib/be_ai_weap.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tbe_ai_weap.c\n *\n * desc:\t\tweapon AI\n *\n * $Archive: /MissionPack/code/botlib/be_ai_weap.c $\n *\n *****************************************************************************/\n\n#include \"../../game/q_shared.h\"\n#include \"l_libvar.h\"\n#include \"l_log.h\"\n#include \"l_memory.h\"\n#include \"l_utils.h\"\n#include \"l_script.h\"\n#include \"l_precomp.h\"\n#include \"l_struct.h\"\n#include \"aasfile.h\"\n#include \"../../game/botlib.h\"\n#include \"../../game/be_aas.h\"\n#include \"be_aas_funcs.h\"\n#include \"be_interface.h\"\n#include \"be_ai_weight.h\"\t\t//fuzzy weights\n#include \"../../game/be_ai_weap.h\"\n\n//#define DEBUG_AI_WEAP\n\n//structure field offsets\n#define WEAPON_OFS(x) (int)(intptr_t)&(((weaponinfo_t *)0)->x)\n#define PROJECTILE_OFS(x) (int)(intptr_t)&(((projectileinfo_t *)0)->x)\n\n//weapon definition // bk001212 - static\nstatic fielddef_t weaponinfo_fields[] =\n{\n{\"number\", WEAPON_OFS(number), FT_INT},\t\t\t\t\t\t//weapon number\n{\"name\", WEAPON_OFS(name), FT_STRING},\t\t\t\t\t\t\t//name of the weapon\n{\"level\", WEAPON_OFS(level), FT_INT},\n{\"model\", WEAPON_OFS(model), FT_STRING},\t\t\t\t\t\t//model of the weapon\n{\"weaponindex\", WEAPON_OFS(weaponindex), FT_INT},\t\t\t//index of weapon in inventory\n{\"flags\", WEAPON_OFS(flags), FT_INT},\t\t\t\t\t\t\t//special flags\n{\"projectile\", WEAPON_OFS(projectile), FT_STRING},\t\t\t//projectile used by the weapon\n{\"numprojectiles\", WEAPON_OFS(numprojectiles), FT_INT},\t//number of projectiles\n{\"hspread\", WEAPON_OFS(hspread), FT_FLOAT},\t\t\t\t\t//horizontal spread of projectiles (degrees from middle)\n{\"vspread\", WEAPON_OFS(vspread), FT_FLOAT},\t\t\t\t\t//vertical spread of projectiles (degrees from middle)\n{\"speed\", WEAPON_OFS(speed), FT_FLOAT},\t\t\t\t\t\t//speed of the projectile (0 = instant hit)\n{\"acceleration\", WEAPON_OFS(acceleration), FT_FLOAT},\t\t//\"acceleration\" * time (in seconds) + \"speed\" = projectile speed\n{\"recoil\", WEAPON_OFS(recoil), FT_FLOAT|FT_ARRAY, 3},\t\t//amount of recoil the player gets from the weapon\n{\"offset\", WEAPON_OFS(offset), FT_FLOAT|FT_ARRAY, 3},\t\t//projectile start offset relative to eye and view angles\n{\"angleoffset\", WEAPON_OFS(angleoffset), FT_FLOAT|FT_ARRAY, 3},//offset of the shoot angles relative to the view angles\n{\"extrazvelocity\", WEAPON_OFS(extrazvelocity), FT_FLOAT},//extra z velocity the projectile gets\n{\"ammoamount\", WEAPON_OFS(ammoamount), FT_INT},\t\t\t\t//ammo amount used per shot\n{\"ammoindex\", WEAPON_OFS(ammoindex), FT_INT},\t\t\t\t//index of ammo in inventory\n{\"activate\", WEAPON_OFS(activate), FT_FLOAT},\t\t\t\t//time it takes to select the weapon\n{\"reload\", WEAPON_OFS(reload), FT_FLOAT},\t\t\t\t\t\t//time it takes to reload the weapon\n{\"spinup\", WEAPON_OFS(spinup), FT_FLOAT},\t\t\t\t\t\t//time it takes before first shot\n{\"spindown\", WEAPON_OFS(spindown), FT_FLOAT},\t\t\t\t//time it takes before weapon stops firing\n{NULL, 0, 0, 0}\n};\n\n//projectile definition\nstatic fielddef_t projectileinfo_fields[] =\n{\n{\"name\", PROJECTILE_OFS(name), FT_STRING},\t\t\t\t\t//name of the projectile\n{\"model\", WEAPON_OFS(model), FT_STRING},\t\t\t\t\t\t//model of the projectile\n{\"flags\", PROJECTILE_OFS(flags), FT_INT},\t\t\t\t\t\t//special flags\n{\"gravity\", PROJECTILE_OFS(gravity), FT_FLOAT},\t\t\t\t//amount of gravity applied to the projectile [0,1]\n{\"damage\", PROJECTILE_OFS(damage), FT_INT},\t\t\t\t\t//damage of the projectile\n{\"radius\", PROJECTILE_OFS(radius), FT_FLOAT},\t\t\t\t//radius of damage\n{\"visdamage\", PROJECTILE_OFS(visdamage), FT_INT},\t\t\t//damage of the projectile to visible entities\n{\"damagetype\", PROJECTILE_OFS(damagetype), FT_INT},\t\t//type of damage (combination of the DAMAGETYPE_? flags)\n{\"healthinc\", PROJECTILE_OFS(healthinc), FT_INT},\t\t\t//health increase the owner gets\n{\"push\", PROJECTILE_OFS(push), FT_FLOAT},\t\t\t\t\t\t//amount a player is pushed away from the projectile impact\n{\"detonation\", PROJECTILE_OFS(detonation), FT_FLOAT},\t\t//time before projectile explodes after fire pressed\n{\"bounce\", PROJECTILE_OFS(bounce), FT_FLOAT},\t\t\t\t//amount the projectile bounces\n{\"bouncefric\", PROJECTILE_OFS(bouncefric), FT_FLOAT}, \t//amount the bounce decreases per bounce\n{\"bouncestop\", PROJECTILE_OFS(bouncestop), FT_FLOAT},\t\t//minimum bounce value before bouncing stops\n//recurive projectile definition??\n{NULL, 0, 0, 0}\n};\n\nstatic structdef_t weaponinfo_struct =\n{\n\tsizeof(weaponinfo_t), weaponinfo_fields\n};\nstatic structdef_t projectileinfo_struct =\n{\n\tsizeof(projectileinfo_t), projectileinfo_fields\n};\n\n//weapon configuration: set of weapons with projectiles\ntypedef struct weaponconfig_s\n{\n\tint numweapons;\n\tint numprojectiles;\n\tprojectileinfo_t *projectileinfo;\n\tweaponinfo_t *weaponinfo;\n} weaponconfig_t;\n\n//the bot weapon state\ntypedef struct bot_weaponstate_s\n{\n\tstruct weightconfig_s *weaponweightconfig;\t\t//weapon weight configuration\n\tint *weaponweightindex;\t\t\t\t\t\t\t//weapon weight index\n} bot_weaponstate_t;\n\nstatic bot_weaponstate_t *botweaponstates[MAX_CLIENTS+1];\nstatic weaponconfig_t *weaponconfig;\n\n//========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//========================================================================\nint BotValidWeaponNumber(int weaponnum)\n{\n\tif (weaponnum <= 0 || weaponnum > weaponconfig->numweapons)\n\t{\n\t\tbotimport.Print(PRT_ERROR, \"weapon number out of range\\n\");\n\t\treturn qfalse;\n\t} //end if\n\treturn qtrue;\n} //end of the function BotValidWeaponNumber\n//========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//========================================================================\nbot_weaponstate_t *BotWeaponStateFromHandle(int handle)\n{\n\tif (handle <= 0 || handle > MAX_CLIENTS)\n\t{\n\t\tbotimport.Print(PRT_FATAL, \"move state handle %d out of range\\n\", handle);\n\t\treturn NULL;\n\t} //end if\n\tif (!botweaponstates[handle])\n\t{\n\t\tbotimport.Print(PRT_FATAL, \"invalid move state %d\\n\", handle);\n\t\treturn NULL;\n\t} //end if\n\treturn botweaponstates[handle];\n} //end of the function BotWeaponStateFromHandle\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\n#ifdef DEBUG_AI_WEAP\nvoid DumpWeaponConfig(weaponconfig_t *wc)\n{\n\tFILE *fp;\n\tint i;\n\n\tfp = Log_FileStruct();\n\tif (!fp) return;\n\tfor (i = 0; i < wc->numprojectiles; i++)\n\t{\n\t\tWriteStructure(fp, &projectileinfo_struct, (char *) &wc->projectileinfo[i]);\n\t\tLog_Flush();\n\t} //end for\n\tfor (i = 0; i < wc->numweapons; i++)\n\t{\n\t\tWriteStructure(fp, &weaponinfo_struct, (char *) &wc->weaponinfo[i]);\n\t\tLog_Flush();\n\t} //end for\n} //end of the function DumpWeaponConfig\n#endif //DEBUG_AI_WEAP\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nweaponconfig_t *LoadWeaponConfig(char *filename)\n{\n\tint max_weaponinfo, max_projectileinfo;\n\ttoken_t token;\n\tchar path[MAX_PATH];\n\tint i, j;\n\tsource_t *source;\n\tweaponconfig_t *wc;\n\tweaponinfo_t weaponinfo;\n\n\tmax_weaponinfo = (int) LibVarValue(\"max_weaponinfo\", \"32\");\n\tif (max_weaponinfo < 0)\n\t{\n\t\tbotimport.Print(PRT_ERROR, \"max_weaponinfo = %d\\n\", max_weaponinfo);\n\t\tmax_weaponinfo = 32;\n\t\tLibVarSet(\"max_weaponinfo\", \"32\");\n\t} //end if\n\tmax_projectileinfo = (int) LibVarValue(\"max_projectileinfo\", \"32\");\n\tif (max_projectileinfo < 0)\n\t{\n\t\tbotimport.Print(PRT_ERROR, \"max_projectileinfo = %d\\n\", max_projectileinfo);\n\t\tmax_projectileinfo = 32;\n\t\tLibVarSet(\"max_projectileinfo\", \"32\");\n\t} //end if\n\tstrncpy(path, filename, MAX_PATH);\n\tPC_SetBaseFolder(BOTFILESBASEFOLDER);\n\tsource = LoadSourceFile(path);\n\tif (!source)\n\t{\n\t\tbotimport.Print(PRT_ERROR, \"counldn't load %s\\n\", path);\n\t\treturn NULL;\n\t} //end if\n\t//initialize weapon config\n\twc = (weaponconfig_t *) GetClearedHunkMemory(sizeof(weaponconfig_t) +\n\t\t\t\t\t\t\t\t\t\tmax_weaponinfo * sizeof(weaponinfo_t) +\n\t\t\t\t\t\t\t\t\t\tmax_projectileinfo * sizeof(projectileinfo_t));\n\twc->weaponinfo = (weaponinfo_t *) ((char *) wc + sizeof(weaponconfig_t));\n\twc->projectileinfo = (projectileinfo_t *) ((char *) wc->weaponinfo +\n\t\t\t\t\t\t\t\t\t\tmax_weaponinfo * sizeof(weaponinfo_t));\n\twc->numweapons = max_weaponinfo;\n\twc->numprojectiles = 0;\n\t//parse the source file\n\twhile(PC_ReadToken(source, &token))\n\t{\n\t\tif (!strcmp(token.string, \"weaponinfo\"))\n\t\t{\n\t\t\tCom_Memset(&weaponinfo, 0, sizeof(weaponinfo_t));\n\t\t\tif (!ReadStructure(source, &weaponinfo_struct, (char *) &weaponinfo))\n\t\t\t{\n\t\t\t\tFreeMemory(wc);\n\t\t\t\tFreeSource(source);\n\t\t\t\treturn NULL;\n\t\t\t} //end if\n\t\t\tif (weaponinfo.number < 0 || weaponinfo.number >= max_weaponinfo)\n\t\t\t{\n\t\t\t\tbotimport.Print(PRT_ERROR, \"weapon info number %d out of range in %s\\n\", weaponinfo.number, path);\n\t\t\t\tFreeMemory(wc);\n\t\t\t\tFreeSource(source);\n\t\t\t\treturn NULL;\n\t\t\t} //end if\n\t\t\tCom_Memcpy(&wc->weaponinfo[weaponinfo.number], &weaponinfo, sizeof(weaponinfo_t));\n\t\t\twc->weaponinfo[weaponinfo.number].valid = qtrue;\n\t\t} //end if\n\t\telse if (!strcmp(token.string, \"projectileinfo\"))\n\t\t{\n\t\t\tif (wc->numprojectiles >= max_projectileinfo)\n\t\t\t{\n\t\t\t\tbotimport.Print(PRT_ERROR, \"more than %d projectiles defined in %s\\n\", max_projectileinfo, path);\n\t\t\t\tFreeMemory(wc);\n\t\t\t\tFreeSource(source);\n\t\t\t\treturn NULL;\n\t\t\t} //end if\n\t\t\tCom_Memset(&wc->projectileinfo[wc->numprojectiles], 0, sizeof(projectileinfo_t));\n\t\t\tif (!ReadStructure(source, &projectileinfo_struct, (char *) &wc->projectileinfo[wc->numprojectiles]))\n\t\t\t{\n\t\t\t\tFreeMemory(wc);\n\t\t\t\tFreeSource(source);\n\t\t\t\treturn NULL;\n\t\t\t} //end if\n\t\t\twc->numprojectiles++;\n\t\t} //end if\n\t\telse\n\t\t{\n\t\t\tbotimport.Print(PRT_ERROR, \"unknown definition %s in %s\\n\", token.string, path);\n\t\t\tFreeMemory(wc);\n\t\t\tFreeSource(source);\n\t\t\treturn NULL;\n\t\t} //end else\n\t} //end while\n\tFreeSource(source);\n\t//fix up weapons\n\tfor (i = 0; i < wc->numweapons; i++)\n\t{\n\t\tif (!wc->weaponinfo[i].valid) continue;\n\t\tif (!wc->weaponinfo[i].name[0])\n\t\t{\n\t\t\tbotimport.Print(PRT_ERROR, \"weapon %d has no name in %s\\n\", i, path);\n\t\t\tFreeMemory(wc);\n\t\t\treturn NULL;\n\t\t} //end if\n\t\tif (!wc->weaponinfo[i].projectile[0])\n\t\t{\n\t\t\tbotimport.Print(PRT_ERROR, \"weapon %s has no projectile in %s\\n\", wc->weaponinfo[i].name, path);\n\t\t\tFreeMemory(wc);\n\t\t\treturn NULL;\n\t\t} //end if\n\t\t//find the projectile info and copy it to the weapon info\n\t\tfor (j = 0; j < wc->numprojectiles; j++)\n\t\t{\n\t\t\tif (!strcmp(wc->projectileinfo[j].name, wc->weaponinfo[i].projectile))\n\t\t\t{\n\t\t\t\tCom_Memcpy(&wc->weaponinfo[i].proj, &wc->projectileinfo[j], sizeof(projectileinfo_t));\n\t\t\t\tbreak;\n\t\t\t} //end if\n\t\t} //end for\n\t\tif (j == wc->numprojectiles)\n\t\t{\n\t\t\tbotimport.Print(PRT_ERROR, \"weapon %s uses undefined projectile in %s\\n\", wc->weaponinfo[i].name, path);\n\t\t\tFreeMemory(wc);\n\t\t\treturn NULL;\n\t\t} //end if\n\t} //end for\n\tif (!wc->numweapons) botimport.Print(PRT_WARNING, \"no weapon info loaded\\n\");\n\tbotimport.Print(PRT_MESSAGE, \"loaded %s\\n\", path);\n\treturn wc;\n} //end of the function LoadWeaponConfig\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint *WeaponWeightIndex(weightconfig_t *wwc, weaponconfig_t *wc)\n{\n\tint *index, i;\n\n\t//initialize item weight index\n\tindex = (int *) GetClearedMemory(sizeof(int) * wc->numweapons);\n\n\tfor (i = 0; i < wc->numweapons; i++)\n\t{\n\t\tindex[i] = FindFuzzyWeight(wwc, wc->weaponinfo[i].name);\n\t} //end for\n\treturn index;\n} //end of the function WeaponWeightIndex\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotFreeWeaponWeights(int weaponstate)\n{\n\tbot_weaponstate_t *ws;\n\n\tws = BotWeaponStateFromHandle(weaponstate);\n\tif (!ws) return;\n\tif (ws->weaponweightconfig) FreeWeightConfig(ws->weaponweightconfig);\n\tif (ws->weaponweightindex) FreeMemory(ws->weaponweightindex);\n} //end of the function BotFreeWeaponWeights\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotLoadWeaponWeights(int weaponstate, char *filename)\n{\n\tbot_weaponstate_t *ws;\n\n\tws = BotWeaponStateFromHandle(weaponstate);\n\tif (!ws) return BLERR_CANNOTLOADWEAPONWEIGHTS;\n\tBotFreeWeaponWeights(weaponstate);\n\t//\n\tws->weaponweightconfig = ReadWeightConfig(filename);\n\tif (!ws->weaponweightconfig)\n\t{\n\t\tbotimport.Print(PRT_FATAL, \"couldn't load weapon config %s\\n\", filename);\n\t\treturn BLERR_CANNOTLOADWEAPONWEIGHTS;\n\t} //end if\n\tif (!weaponconfig) return BLERR_CANNOTLOADWEAPONCONFIG;\n\tws->weaponweightindex = WeaponWeightIndex(ws->weaponweightconfig, weaponconfig);\n\treturn BLERR_NOERROR;\n} //end of the function BotLoadWeaponWeights\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotGetWeaponInfo(int weaponstate, int weapon, weaponinfo_t *weaponinfo)\n{\n\tbot_weaponstate_t *ws;\n\n\tif (!BotValidWeaponNumber(weapon)) return;\n\tws = BotWeaponStateFromHandle(weaponstate);\n\tif (!ws) return;\n\tif (!weaponconfig) return;\n\tCom_Memcpy(weaponinfo, &weaponconfig->weaponinfo[weapon], sizeof(weaponinfo_t));\n} //end of the function BotGetWeaponInfo\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotChooseBestFightWeapon(int weaponstate, int *inventory)\n{\n\tint i, index, bestweapon;\n\tfloat weight, bestweight;\n\tweaponconfig_t *wc;\n\tbot_weaponstate_t *ws;\n\n\tws = BotWeaponStateFromHandle(weaponstate);\n\tif (!ws) return 0;\n\twc = weaponconfig;\n\tif (!weaponconfig) return 0;\n\n\t//if the bot has no weapon weight configuration\n\tif (!ws->weaponweightconfig) return 0;\n\n\tbestweight = 0;\n\tbestweapon = 0;\n\tfor (i = 0; i < wc->numweapons; i++)\n\t{\n\t\tif (!wc->weaponinfo[i].valid) continue;\n\t\tindex = ws->weaponweightindex[i];\n\t\tif (index < 0) continue;\n\t\tweight = FuzzyWeight(inventory, ws->weaponweightconfig, index);\n\t\tif (weight > bestweight)\n\t\t{\n\t\t\tbestweight = weight;\n\t\t\tbestweapon = i;\n\t\t} //end if\n\t} //end for\n\treturn bestweapon;\n} //end of the function BotChooseBestFightWeapon\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotResetWeaponState(int weaponstate)\n{\n\tstruct weightconfig_s *weaponweightconfig;\n\tint *weaponweightindex;\n\tbot_weaponstate_t *ws;\n\n\tws = BotWeaponStateFromHandle(weaponstate);\n\tif (!ws) return;\n\tweaponweightconfig = ws->weaponweightconfig;\n\tweaponweightindex = ws->weaponweightindex;\n\n\t//Com_Memset(ws, 0, sizeof(bot_weaponstate_t));\n\tws->weaponweightconfig = weaponweightconfig;\n\tws->weaponweightindex = weaponweightindex;\n} //end of the function BotResetWeaponState\n//========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//========================================================================\nint BotAllocWeaponState(void)\n{\n\tint i;\n\n\tfor (i = 1; i <= MAX_CLIENTS; i++)\n\t{\n\t\tif (!botweaponstates[i])\n\t\t{\n\t\t\tbotweaponstates[i] = (bot_weaponstate_t*) GetClearedMemory(sizeof(bot_weaponstate_t));\n\t\t\treturn i;\n\t\t} //end if\n\t} //end for\n\treturn 0;\n} //end of the function BotAllocWeaponState\n//========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//========================================================================\nvoid BotFreeWeaponState(int handle)\n{\n\tif (handle <= 0 || handle > MAX_CLIENTS)\n\t{\n\t\tbotimport.Print(PRT_FATAL, \"move state handle %d out of range\\n\", handle);\n\t\treturn;\n\t} //end if\n\tif (!botweaponstates[handle])\n\t{\n\t\tbotimport.Print(PRT_FATAL, \"invalid move state %d\\n\", handle);\n\t\treturn;\n\t} //end if\n\tBotFreeWeaponWeights(handle);\n\tFreeMemory(botweaponstates[handle]);\n\tbotweaponstates[handle] = NULL;\n} //end of the function BotFreeWeaponState\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint BotSetupWeaponAI(void)\n{\n\tchar *file;\n\n\tfile = LibVarString(\"weaponconfig\", \"weapons.c\");\n\tweaponconfig = LoadWeaponConfig(file);\n\tif (!weaponconfig)\n\t{\n\t\tbotimport.Print(PRT_FATAL, \"couldn't load the weapon config\\n\");\n\t\treturn BLERR_CANNOTLOADWEAPONCONFIG;\n\t} //end if\n\n#ifdef DEBUG_AI_WEAP\n\tDumpWeaponConfig(weaponconfig);\n#endif //DEBUG_AI_WEAP\n\t//\n\treturn BLERR_NOERROR;\n} //end of the function BotSetupWeaponAI\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotShutdownWeaponAI(void)\n{\n\tint i;\n\n\tif (weaponconfig) FreeMemory(weaponconfig);\n\tweaponconfig = NULL;\n\n\tfor (i = 1; i <= MAX_CLIENTS; i++)\n\t{\n\t\tif (botweaponstates[i])\n\t\t{\n\t\t\tBotFreeWeaponState(i);\n\t\t} //end if\n\t} //end for\n} //end of the function BotShutdownWeaponAI\n\n"
  },
  {
    "path": "src/engine/botlib/be_ai_weight.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tbe_ai_weight.c\n *\n * desc:\t\tfuzzy logic\n *\n * $Archive: /MissionPack/code/botlib/be_ai_weight.c $\n *\n *****************************************************************************/\n\n#include \"../../game/q_shared.h\"\n#include \"l_memory.h\"\n#include \"l_log.h\"\n#include \"l_utils.h\"\n#include \"l_script.h\"\n#include \"l_precomp.h\"\n#include \"l_struct.h\"\n#include \"l_libvar.h\"\n#include \"aasfile.h\"\n#include \"../../game/botlib.h\"\n#include \"../../game/be_aas.h\"\n#include \"be_aas_funcs.h\"\n#include \"be_interface.h\"\n#include \"be_ai_weight.h\"\n\n#define MAX_INVENTORYVALUE\t\t\t999999\n#define EVALUATERECURSIVELY\n\n#define MAX_WEIGHT_FILES\t\t\t128\nweightconfig_t\t*weightFileList[MAX_WEIGHT_FILES];\n\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint ReadValue(source_t *source, float *value)\n{\n\ttoken_t token;\n\n\tif (!PC_ExpectAnyToken(source, &token)) return qfalse;\n\tif (!strcmp(token.string, \"-\"))\n\t{\n\t\tSourceWarning(source, \"negative value set to zero\\n\");\n\t\tif (!PC_ExpectTokenType(source, TT_NUMBER, 0, &token)) return qfalse;\n\t} //end if\n\tif (token.type != TT_NUMBER)\n\t{\n\t\tSourceError(source, \"invalid return value %s\\n\", token.string);\n\t\treturn qfalse;\n\t} //end if\n\t*value = token.floatvalue;\n\treturn qtrue;\n} //end of the function ReadValue\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint ReadFuzzyWeight(source_t *source, fuzzyseperator_t *fs)\n{\n\tif (PC_CheckTokenString(source, \"balance\"))\n\t{\n\t\tfs->type = WT_BALANCE;\n\t\tif (!PC_ExpectTokenString(source, \"(\")) return qfalse;\n\t\tif (!ReadValue(source, &fs->weight)) return qfalse;\n\t\tif (!PC_ExpectTokenString(source, \",\")) return qfalse;\n\t\tif (!ReadValue(source, &fs->minweight)) return qfalse;\n\t\tif (!PC_ExpectTokenString(source, \",\")) return qfalse;\n\t\tif (!ReadValue(source, &fs->maxweight)) return qfalse;\n\t\tif (!PC_ExpectTokenString(source, \")\")) return qfalse;\n\t} //end if\n\telse\n\t{\n\t\tfs->type = 0;\n\t\tif (!ReadValue(source, &fs->weight)) return qfalse;\n\t\tfs->minweight = fs->weight;\n\t\tfs->maxweight = fs->weight;\n\t} //end if\n\tif (!PC_ExpectTokenString(source, \";\")) return qfalse;\n\treturn qtrue;\n} //end of the function ReadFuzzyWeight\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid FreeFuzzySeperators_r(fuzzyseperator_t *fs)\n{\n\tif (!fs) return;\n\tif (fs->child) FreeFuzzySeperators_r(fs->child);\n\tif (fs->next) FreeFuzzySeperators_r(fs->next);\n\tFreeMemory(fs);\n} //end of the function FreeFuzzySeperators\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid FreeWeightConfig2(weightconfig_t *config)\n{\n\tint i;\n\n\tfor (i = 0; i < config->numweights; i++)\n\t{\n\t\tFreeFuzzySeperators_r(config->weights[i].firstseperator);\n\t\tif (config->weights[i].name) FreeMemory(config->weights[i].name);\n\t} //end for\n\tFreeMemory(config);\n} //end of the function FreeWeightConfig2\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid FreeWeightConfig(weightconfig_t *config)\n{\n\tif (!LibVarGetValue(\"bot_reloadcharacters\")) return;\n\tFreeWeightConfig2(config);\n} //end of the function FreeWeightConfig\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nfuzzyseperator_t *ReadFuzzySeperators_r(source_t *source)\n{\n\tint newindent, index, def, founddefault;\n\ttoken_t token;\n\tfuzzyseperator_t *fs, *lastfs, *firstfs;\n\n\tfounddefault = qfalse;\n\tfirstfs = NULL;\n\tlastfs = NULL;\n\tif (!PC_ExpectTokenString(source, \"(\")) return NULL;\n\tif (!PC_ExpectTokenType(source, TT_NUMBER, TT_INTEGER, &token)) return NULL;\n\tindex = token.intvalue;\n\tif (!PC_ExpectTokenString(source, \")\")) return NULL;\n\tif (!PC_ExpectTokenString(source, \"{\")) return NULL;\n\tif (!PC_ExpectAnyToken(source, &token)) return NULL;\n\tdo\n\t{\n\t\tdef = !strcmp(token.string, \"default\");\n\t\tif (def || !strcmp(token.string, \"case\"))\n\t\t{\n\t\t\tfs = (fuzzyseperator_t *) GetClearedMemory(sizeof(fuzzyseperator_t));\n\t\t\tfs->index = index;\n\t\t\tif (lastfs) lastfs->next = fs;\n\t\t\telse firstfs = fs;\n\t\t\tlastfs = fs;\n\t\t\tif (def)\n\t\t\t{\n\t\t\t\tif (founddefault)\n\t\t\t\t{\n\t\t\t\t\tSourceError(source, \"switch already has a default\\n\");\n\t\t\t\t\tFreeFuzzySeperators_r(firstfs);\n\t\t\t\t\treturn NULL;\n\t\t\t\t} //end if\n\t\t\t\tfs->value = MAX_INVENTORYVALUE;\n\t\t\t\tfounddefault = qtrue;\n\t\t\t} //end if\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (!PC_ExpectTokenType(source, TT_NUMBER, TT_INTEGER, &token))\n\t\t\t\t{\n\t\t\t\t\tFreeFuzzySeperators_r(firstfs);\n\t\t\t\t\treturn NULL;\n\t\t\t\t} //end if\n\t\t\t\tfs->value = token.intvalue;\n\t\t\t} //end else\n\t\t\tif (!PC_ExpectTokenString(source, \":\") || !PC_ExpectAnyToken(source, &token))\n\t\t\t{\n\t\t\t\tFreeFuzzySeperators_r(firstfs);\n\t\t\t\treturn NULL;\n\t\t\t} //end if\n\t\t\tnewindent = qfalse;\n\t\t\tif (!strcmp(token.string, \"{\"))\n\t\t\t{\n\t\t\t\tnewindent = qtrue;\n\t\t\t\tif (!PC_ExpectAnyToken(source, &token))\n\t\t\t\t{\n\t\t\t\t\tFreeFuzzySeperators_r(firstfs);\n\t\t\t\t\treturn NULL;\n\t\t\t\t} //end if\n\t\t\t} //end if\n\t\t\tif (!strcmp(token.string, \"return\"))\n\t\t\t{\n\t\t\t\tif (!ReadFuzzyWeight(source, fs))\n\t\t\t\t{\n\t\t\t\t\tFreeFuzzySeperators_r(firstfs);\n\t\t\t\t\treturn NULL;\n\t\t\t\t} //end if\n\t\t\t} //end if\n\t\t\telse if (!strcmp(token.string, \"switch\"))\n\t\t\t{\n\t\t\t\tfs->child = ReadFuzzySeperators_r(source);\n\t\t\t\tif (!fs->child)\n\t\t\t\t{\n\t\t\t\t\tFreeFuzzySeperators_r(firstfs);\n\t\t\t\t\treturn NULL;\n\t\t\t\t} //end if\n\t\t\t} //end else if\n\t\t\telse\n\t\t\t{\n\t\t\t\tSourceError(source, \"invalid name %s\\n\", token.string);\n\t\t\t\treturn NULL;\n\t\t\t} //end else\n\t\t\tif (newindent)\n\t\t\t{\n\t\t\t\tif (!PC_ExpectTokenString(source, \"}\"))\n\t\t\t\t{\n\t\t\t\t\tFreeFuzzySeperators_r(firstfs);\n\t\t\t\t\treturn NULL;\n\t\t\t\t} //end if\n\t\t\t} //end if\n\t\t} //end if\n\t\telse\n\t\t{\n\t\t\tFreeFuzzySeperators_r(firstfs);\n\t\t\tSourceError(source, \"invalid name %s\\n\", token.string);\n\t\t\treturn NULL;\n\t\t} //end else\n\t\tif (!PC_ExpectAnyToken(source, &token))\n\t\t{\n\t\t\tFreeFuzzySeperators_r(firstfs);\n\t\t\treturn NULL;\n\t\t} //end if\n\t} while(strcmp(token.string, \"}\"));\n\t//\n\tif (!founddefault)\n\t{\n\t\tSourceWarning(source, \"switch without default\\n\");\n\t\tfs = (fuzzyseperator_t *) GetClearedMemory(sizeof(fuzzyseperator_t));\n\t\tfs->index = index;\n\t\tfs->value = MAX_INVENTORYVALUE;\n\t\tfs->weight = 0;\n\t\tfs->next = NULL;\n\t\tfs->child = NULL;\n\t\tif (lastfs) lastfs->next = fs;\n\t\telse firstfs = fs;\n\t\tlastfs = fs;\n\t} //end if\n\t//\n\treturn firstfs;\n} //end of the function ReadFuzzySeperators_r\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nweightconfig_t *ReadWeightConfig(char *filename)\n{\n\tint newindent, avail = 0, n;\n\ttoken_t token;\n\tsource_t *source;\n\tfuzzyseperator_t *fs;\n\tweightconfig_t *config = NULL;\n#ifdef DEBUG\n\tint starttime;\n\n\tstarttime = Sys_MilliSeconds();\n#endif //DEBUG\n\n\tif (!LibVarGetValue(\"bot_reloadcharacters\"))\n\t{\n\t\tavail = -1;\n\t\tfor( n = 0; n < MAX_WEIGHT_FILES; n++ )\n\t\t{\n\t\t\tconfig = weightFileList[n];\n\t\t\tif( !config )\n\t\t\t{\n\t\t\t\tif( avail == -1 )\n\t\t\t\t{\n\t\t\t\t\tavail = n;\n\t\t\t\t} //end if\n\t\t\t\tcontinue;\n\t\t\t} //end if\n\t\t\tif( strcmp( filename, config->filename ) == 0 )\n\t\t\t{\n\t\t\t\t//botimport.Print( PRT_MESSAGE, \"retained %s\\n\", filename );\n\t\t\t\treturn config;\n\t\t\t} //end if\n\t\t} //end for\n\n\t\tif( avail == -1 )\n\t\t{\n\t\t\tbotimport.Print( PRT_ERROR, \"weightFileList was full trying to load %s\\n\", filename );\n\t\t\treturn NULL;\n\t\t} //end if\n\t} //end if\n\n\tPC_SetBaseFolder(BOTFILESBASEFOLDER);\n\tsource = LoadSourceFile(filename);\n\tif (!source)\n\t{\n\t\tbotimport.Print(PRT_ERROR, \"counldn't load %s\\n\", filename);\n\t\treturn NULL;\n\t} //end if\n\t//\n\tconfig = (weightconfig_t *) GetClearedMemory(sizeof(weightconfig_t));\n\tconfig->numweights = 0;\n\tQ_strncpyz( config->filename, filename, sizeof(config->filename) );\n\t//parse the item config file\n\twhile(PC_ReadToken(source, &token))\n\t{\n\t\tif (!strcmp(token.string, \"weight\"))\n\t\t{\n\t\t\tif (config->numweights >= MAX_WEIGHTS)\n\t\t\t{\n\t\t\t\tSourceWarning(source, \"too many fuzzy weights\\n\");\n\t\t\t\tbreak;\n\t\t\t} //end if\n\t\t\tif (!PC_ExpectTokenType(source, TT_STRING, 0, &token))\n\t\t\t{\n\t\t\t\tFreeWeightConfig(config);\n\t\t\t\tFreeSource(source);\n\t\t\t\treturn NULL;\n\t\t\t} //end if\n\t\t\tStripDoubleQuotes(token.string);\n\t\t\tconfig->weights[config->numweights].name = (char *) GetClearedMemory((int)strlen(token.string) + 1);\n\t\t\tstrcpy(config->weights[config->numweights].name, token.string);\n\t\t\tif (!PC_ExpectAnyToken(source, &token))\n\t\t\t{\n\t\t\t\tFreeWeightConfig(config);\n\t\t\t\tFreeSource(source);\n\t\t\t\treturn NULL;\n\t\t\t} //end if\n\t\t\tnewindent = qfalse;\n\t\t\tif (!strcmp(token.string, \"{\"))\n\t\t\t{\n\t\t\t\tnewindent = qtrue;\n\t\t\t\tif (!PC_ExpectAnyToken(source, &token))\n\t\t\t\t{\n\t\t\t\t\tFreeWeightConfig(config);\n\t\t\t\t\tFreeSource(source);\n\t\t\t\t\treturn NULL;\n\t\t\t\t} //end if\n\t\t\t} //end if\n\t\t\tif (!strcmp(token.string, \"switch\"))\n\t\t\t{\n\t\t\t\tfs = ReadFuzzySeperators_r(source);\n\t\t\t\tif (!fs)\n\t\t\t\t{\n\t\t\t\t\tFreeWeightConfig(config);\n\t\t\t\t\tFreeSource(source);\n\t\t\t\t\treturn NULL;\n\t\t\t\t} //end if\n\t\t\t\tconfig->weights[config->numweights].firstseperator = fs;\n\t\t\t} //end if\n\t\t\telse if (!strcmp(token.string, \"return\"))\n\t\t\t{\n\t\t\t\tfs = (fuzzyseperator_t *) GetClearedMemory(sizeof(fuzzyseperator_t));\n\t\t\t\tfs->index = 0;\n\t\t\t\tfs->value = MAX_INVENTORYVALUE;\n\t\t\t\tfs->next = NULL;\n\t\t\t\tfs->child = NULL;\n\t\t\t\tif (!ReadFuzzyWeight(source, fs))\n\t\t\t\t{\n\t\t\t\t\tFreeMemory(fs);\n\t\t\t\t\tFreeWeightConfig(config);\n\t\t\t\t\tFreeSource(source);\n\t\t\t\t\treturn NULL;\n\t\t\t\t} //end if\n\t\t\t\tconfig->weights[config->numweights].firstseperator = fs;\n\t\t\t} //end else if\n\t\t\telse\n\t\t\t{\n\t\t\t\tSourceError(source, \"invalid name %s\\n\", token.string);\n\t\t\t\tFreeWeightConfig(config);\n\t\t\t\tFreeSource(source);\n\t\t\t\treturn NULL;\n\t\t\t} //end else\n\t\t\tif (newindent)\n\t\t\t{\n\t\t\t\tif (!PC_ExpectTokenString(source, \"}\"))\n\t\t\t\t{\n\t\t\t\t\tFreeWeightConfig(config);\n\t\t\t\t\tFreeSource(source);\n\t\t\t\t\treturn NULL;\n\t\t\t\t} //end if\n\t\t\t} //end if\n\t\t\tconfig->numweights++;\n\t\t} //end if\n\t\telse\n\t\t{\n\t\t\tSourceError(source, \"invalid name %s\\n\", token.string);\n\t\t\tFreeWeightConfig(config);\n\t\t\tFreeSource(source);\n\t\t\treturn NULL;\n\t\t} //end else\n\t} //end while\n\t//free the source at the end of a pass\n\tFreeSource(source);\n\t//if the file was located in a pak file\n\tbotimport.Print(PRT_MESSAGE, \"loaded %s\\n\", filename);\n#ifdef DEBUG\n\tif (bot_developer)\n\t{\n\t\tbotimport.Print(PRT_MESSAGE, \"weights loaded in %d msec\\n\", Sys_MilliSeconds() - starttime);\n\t} //end if\n#endif //DEBUG\n\t//\n\tif (!LibVarGetValue(\"bot_reloadcharacters\"))\n\t{\n\t\tweightFileList[avail] = config;\n\t} //end if\n\t//\n\treturn config;\n} //end of the function ReadWeightConfig\n#if 0\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nqboolean WriteFuzzyWeight(FILE *fp, fuzzyseperator_t *fs)\n{\n\tif (fs->type == WT_BALANCE)\n\t{\n\t\tif (fprintf(fp, \" return balance(\") < 0) return qfalse;\n\t\tif (!WriteFloat(fp, fs->weight)) return qfalse;\n\t\tif (fprintf(fp, \",\") < 0) return qfalse;\n\t\tif (!WriteFloat(fp, fs->minweight)) return qfalse;\n\t\tif (fprintf(fp, \",\") < 0) return qfalse;\n\t\tif (!WriteFloat(fp, fs->maxweight)) return qfalse;\n\t\tif (fprintf(fp, \");\\n\") < 0) return qfalse;\n\t} //end if\n\telse\n\t{\n\t\tif (fprintf(fp, \" return \") < 0) return qfalse;\n\t\tif (!WriteFloat(fp, fs->weight)) return qfalse;\n\t\tif (fprintf(fp, \";\\n\") < 0) return qfalse;\n\t} //end else\n\treturn qtrue;\n} //end of the function WriteFuzzyWeight\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nqboolean WriteFuzzySeperators_r(FILE *fp, fuzzyseperator_t *fs, int indent)\n{\n\tif (!WriteIndent(fp, indent)) return qfalse;\n\tif (fprintf(fp, \"switch(%d)\\n\", fs->index) < 0) return qfalse;\n\tif (!WriteIndent(fp, indent)) return qfalse;\n\tif (fprintf(fp, \"{\\n\") < 0) return qfalse;\n\tindent++;\n\tdo\n\t{\n\t\tif (!WriteIndent(fp, indent)) return qfalse;\n\t\tif (fs->next)\n\t\t{\n\t\t\tif (fprintf(fp, \"case %d:\", fs->value) < 0) return qfalse;\n\t\t} //end if\n\t\telse\n\t\t{\n\t\t\tif (fprintf(fp, \"default:\") < 0) return qfalse;\n\t\t} //end else\n\t\tif (fs->child)\n\t\t{\n\t\t\tif (fprintf(fp, \"\\n\") < 0) return qfalse;\n\t\t\tif (!WriteIndent(fp, indent)) return qfalse;\n\t\t\tif (fprintf(fp, \"{\\n\") < 0) return qfalse;\n\t\t\tif (!WriteFuzzySeperators_r(fp, fs->child, indent + 1)) return qfalse;\n\t\t\tif (!WriteIndent(fp, indent)) return qfalse;\n\t\t\tif (fs->next)\n\t\t\t{\n\t\t\t\tif (fprintf(fp, \"} //end case\\n\") < 0) return qfalse;\n\t\t\t} //end if\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (fprintf(fp, \"} //end default\\n\") < 0) return qfalse;\n\t\t\t} //end else\n\t\t} //end if\n\t\telse\n\t\t{\n\t\t\tif (!WriteFuzzyWeight(fp, fs)) return qfalse;\n\t\t} //end else\n\t\tfs = fs->next;\n\t} while(fs);\n\tindent--;\n\tif (!WriteIndent(fp, indent)) return qfalse;\n\tif (fprintf(fp, \"} //end switch\\n\") < 0) return qfalse;\n\treturn qtrue;\n} //end of the function WriteItemFuzzyWeights_r\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nqboolean WriteWeightConfig(char *filename, weightconfig_t *config)\n{\n\tint i;\n\tFILE *fp;\n\tweight_t *ifw;\n\n\tfp = fopen(filename, \"wb\");\n\tif (!fp) return qfalse;\n\n\tfor (i = 0; i < config->numweights; i++)\n\t{\n\t\tifw = &config->weights[i];\n\t\tif (fprintf(fp, \"\\nweight \\\"%s\\\"\\n\", ifw->name) < 0) return qfalse;\n\t\tif (fprintf(fp, \"{\\n\") < 0) return qfalse;\n\t\tif (ifw->firstseperator->index > 0)\n\t\t{\n\t\t\tif (!WriteFuzzySeperators_r(fp, ifw->firstseperator, 1)) return qfalse;\n\t\t} //end if\n\t\telse\n\t\t{\n\t\t\tif (!WriteIndent(fp, 1)) return qfalse;\n\t\t\tif (!WriteFuzzyWeight(fp, ifw->firstseperator)) return qfalse;\n\t\t} //end else\n\t\tif (fprintf(fp, \"} //end weight\\n\") < 0) return qfalse;\n\t} //end for\n\tfclose(fp);\n\treturn qtrue;\n} //end of the function WriteWeightConfig\n#endif\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint FindFuzzyWeight(weightconfig_t *wc, char *name)\n{\n\tint i;\n\n\tfor (i = 0; i < wc->numweights; i++)\n\t{\n\t\tif (!strcmp(wc->weights[i].name, name))\n\t\t{\n\t\t\treturn i;\n\t\t} //end if\n\t} //end if\n\treturn -1;\n} //end of the function FindFuzzyWeight\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nfloat FuzzyWeight_r(int *inventory, fuzzyseperator_t *fs)\n{\n\tfloat scale, w1, w2;\n\n\tif (inventory[fs->index] < fs->value)\n\t{\n\t\tif (fs->child) return FuzzyWeight_r(inventory, fs->child);\n\t\telse return fs->weight;\n\t} //end if\n\telse if (fs->next)\n\t{\n\t\tif (inventory[fs->index] < fs->next->value)\n\t\t{\n\t\t\t//first weight\n\t\t\tif (fs->child) w1 = FuzzyWeight_r(inventory, fs->child);\n\t\t\telse w1 = fs->weight;\n\t\t\t//second weight\n\t\t\tif (fs->next->child) w2 = FuzzyWeight_r(inventory, fs->next->child);\n\t\t\telse w2 = fs->next->weight;\n\t\t\t//the scale factor\n\t\t\tscale = (inventory[fs->index] - fs->value) / (fs->next->value - fs->value);\n\t\t\t//scale between the two weights\n\t\t\treturn scale * w1 + (1 - scale) * w2;\n\t\t} //end if\n\t\treturn FuzzyWeight_r(inventory, fs->next);\n\t} //end else if\n\treturn fs->weight;\n} //end of the function FuzzyWeight_r\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nfloat FuzzyWeightUndecided_r(int *inventory, fuzzyseperator_t *fs)\n{\n\tfloat scale, w1, w2;\n\n\tif (inventory[fs->index] < fs->value)\n\t{\n\t\tif (fs->child) return FuzzyWeightUndecided_r(inventory, fs->child);\n\t\telse return fs->minweight + random() * (fs->maxweight - fs->minweight);\n\t} //end if\n\telse if (fs->next)\n\t{\n\t\tif (inventory[fs->index] < fs->next->value)\n\t\t{\n\t\t\t//first weight\n\t\t\tif (fs->child) w1 = FuzzyWeightUndecided_r(inventory, fs->child);\n\t\t\telse w1 = fs->minweight + random() * (fs->maxweight - fs->minweight);\n\t\t\t//second weight\n\t\t\tif (fs->next->child) w2 = FuzzyWeight_r(inventory, fs->next->child);\n\t\t\telse w2 = fs->next->minweight + random() * (fs->next->maxweight - fs->next->minweight);\n\t\t\t//the scale factor\n\t\t\tscale = (inventory[fs->index] - fs->value) / (fs->next->value - fs->value);\n\t\t\t//scale between the two weights\n\t\t\treturn scale * w1 + (1 - scale) * w2;\n\t\t} //end if\n\t\treturn FuzzyWeightUndecided_r(inventory, fs->next);\n\t} //end else if\n\treturn fs->weight;\n} //end of the function FuzzyWeightUndecided_r\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nfloat FuzzyWeight(int *inventory, weightconfig_t *wc, int weightnum)\n{\n#ifdef EVALUATERECURSIVELY\n\treturn FuzzyWeight_r(inventory, wc->weights[weightnum].firstseperator);\n#else\n\tfuzzyseperator_t *s;\n\n\ts = wc->weights[weightnum].firstseperator;\n\tif (!s) return 0;\n\twhile(1)\n\t{\n\t\tif (inventory[s->index] < s->value)\n\t\t{\n\t\t\tif (s->child) s = s->child;\n\t\t\telse return s->weight;\n\t\t} //end if\n\t\telse\n\t\t{\n\t\t\tif (s->next) s = s->next;\n\t\t\telse return s->weight;\n\t\t} //end else\n\t} //end if\n\treturn 0;\n#endif\n} //end of the function FuzzyWeight\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nfloat FuzzyWeightUndecided(int *inventory, weightconfig_t *wc, int weightnum)\n{\n#ifdef EVALUATERECURSIVELY\n\treturn FuzzyWeightUndecided_r(inventory, wc->weights[weightnum].firstseperator);\n#else\n\tfuzzyseperator_t *s;\n\n\ts = wc->weights[weightnum].firstseperator;\n\tif (!s) return 0;\n\twhile(1)\n\t{\n\t\tif (inventory[s->index] < s->value)\n\t\t{\n\t\t\tif (s->child) s = s->child;\n\t\t\telse return s->minweight + random() * (s->maxweight - s->minweight);\n\t\t} //end if\n\t\telse\n\t\t{\n\t\t\tif (s->next) s = s->next;\n\t\t\telse return s->minweight + random() * (s->maxweight - s->minweight);\n\t\t} //end else\n\t} //end if\n\treturn 0;\n#endif\n} //end of the function FuzzyWeightUndecided\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid EvolveFuzzySeperator_r(fuzzyseperator_t *fs)\n{\n\tif (fs->child)\n\t{\n\t\tEvolveFuzzySeperator_r(fs->child);\n\t} //end if\n\telse if (fs->type == WT_BALANCE)\n\t{\n\t\t//every once in a while an evolution leap occurs, mutation\n\t\tif (random() < 0.01) fs->weight += crandom() * (fs->maxweight - fs->minweight);\n\t\telse fs->weight += crandom() * (fs->maxweight - fs->minweight) * 0.5;\n\t\t//modify bounds if necesary because of mutation\n\t\tif (fs->weight < fs->minweight) fs->minweight = fs->weight;\n\t\telse if (fs->weight > fs->maxweight) fs->maxweight = fs->weight;\n\t} //end else if\n\tif (fs->next) EvolveFuzzySeperator_r(fs->next);\n} //end of the function EvolveFuzzySeperator_r\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid EvolveWeightConfig(weightconfig_t *config)\n{\n\tint i;\n\n\tfor (i = 0; i < config->numweights; i++)\n\t{\n\t\tEvolveFuzzySeperator_r(config->weights[i].firstseperator);\n\t} //end for\n} //end of the function EvolveWeightConfig\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid ScaleFuzzySeperator_r(fuzzyseperator_t *fs, float scale)\n{\n\tif (fs->child)\n\t{\n\t\tScaleFuzzySeperator_r(fs->child, scale);\n\t} //end if\n\telse if (fs->type == WT_BALANCE)\n\t{\n\t\t//\n\t\tfs->weight = (fs->maxweight + fs->minweight) * scale;\n\t\t//get the weight between bounds\n\t\tif (fs->weight < fs->minweight) fs->weight = fs->minweight;\n\t\telse if (fs->weight > fs->maxweight) fs->weight = fs->maxweight;\n\t} //end else if\n\tif (fs->next) ScaleFuzzySeperator_r(fs->next, scale);\n} //end of the function ScaleFuzzySeperator_r\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid ScaleWeight(weightconfig_t *config, char *name, float scale)\n{\n\tint i;\n\n\tif (scale < 0) scale = 0;\n\telse if (scale > 1) scale = 1;\n\tfor (i = 0; i < config->numweights; i++)\n\t{\n\t\tif (!strcmp(name, config->weights[i].name))\n\t\t{\n\t\t\tScaleFuzzySeperator_r(config->weights[i].firstseperator, scale);\n\t\t\tbreak;\n\t\t} //end if\n\t} //end for\n} //end of the function ScaleWeight\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid ScaleFuzzySeperatorBalanceRange_r(fuzzyseperator_t *fs, float scale)\n{\n\tif (fs->child)\n\t{\n\t\tScaleFuzzySeperatorBalanceRange_r(fs->child, scale);\n\t} //end if\n\telse if (fs->type == WT_BALANCE)\n\t{\n\t\tfloat mid = (fs->minweight + fs->maxweight) * 0.5;\n\t\t//get the weight between bounds\n\t\tfs->maxweight = mid + (fs->maxweight - mid) * scale;\n\t\tfs->minweight = mid + (fs->minweight - mid) * scale;\n\t\tif (fs->maxweight < fs->minweight)\n\t\t{\n\t\t\tfs->maxweight = fs->minweight;\n\t\t} //end if\n\t} //end else if\n\tif (fs->next) ScaleFuzzySeperatorBalanceRange_r(fs->next, scale);\n} //end of the function ScaleFuzzySeperatorBalanceRange_r\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid ScaleFuzzyBalanceRange(weightconfig_t *config, float scale)\n{\n\tint i;\n\n\tif (scale < 0) scale = 0;\n\telse if (scale > 100) scale = 100;\n\tfor (i = 0; i < config->numweights; i++)\n\t{\n\t\tScaleFuzzySeperatorBalanceRange_r(config->weights[i].firstseperator, scale);\n\t} //end for\n} //end of the function ScaleFuzzyBalanceRange\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint InterbreedFuzzySeperator_r(fuzzyseperator_t *fs1, fuzzyseperator_t *fs2,\n\t\t\t\t\t\t\t\tfuzzyseperator_t *fsout)\n{\n\tif (fs1->child)\n\t{\n\t\tif (!fs2->child || !fsout->child)\n\t\t{\n\t\t\tbotimport.Print(PRT_ERROR, \"cannot interbreed weight configs, unequal child\\n\");\n\t\t\treturn qfalse;\n\t\t} //end if\n\t\tif (!InterbreedFuzzySeperator_r(fs2->child, fs2->child, fsout->child))\n\t\t{\n\t\t\treturn qfalse;\n\t\t} //end if\n\t} //end if\n\telse if (fs1->type == WT_BALANCE)\n\t{\n\t\tif (fs2->type != WT_BALANCE || fsout->type != WT_BALANCE)\n\t\t{\n\t\t\tbotimport.Print(PRT_ERROR, \"cannot interbreed weight configs, unequal balance\\n\");\n\t\t\treturn qfalse;\n\t\t} //end if\n\t\tfsout->weight = (fs1->weight + fs2->weight) / 2;\n\t\tif (fsout->weight > fsout->maxweight) fsout->maxweight = fsout->weight;\n\t\tif (fsout->weight > fsout->minweight) fsout->minweight = fsout->weight;\n\t} //end else if\n\tif (fs1->next)\n\t{\n\t\tif (!fs2->next || !fsout->next)\n\t\t{\n\t\t\tbotimport.Print(PRT_ERROR, \"cannot interbreed weight configs, unequal next\\n\");\n\t\t\treturn qfalse;\n\t\t} //end if\n\t\tif (!InterbreedFuzzySeperator_r(fs1->next, fs2->next, fsout->next))\n\t\t{\n\t\t\treturn qfalse;\n\t\t} //end if\n\t} //end if\n\treturn qtrue;\n} //end of the function InterbreedFuzzySeperator_r\n//===========================================================================\n// config1 and config2 are interbreeded and stored in configout\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid InterbreedWeightConfigs(weightconfig_t *config1, weightconfig_t *config2,\n\t\t\t\t\t\t\t\tweightconfig_t *configout)\n{\n\tint i;\n\n\tif (config1->numweights != config2->numweights ||\n\t\tconfig1->numweights != configout->numweights)\n\t{\n\t\tbotimport.Print(PRT_ERROR, \"cannot interbreed weight configs, unequal numweights\\n\");\n\t\treturn;\n\t} //end if\n\tfor (i = 0; i < config1->numweights; i++)\n\t{\n\t\tInterbreedFuzzySeperator_r(config1->weights[i].firstseperator,\n\t\t\t\t\t\t\t\t\tconfig2->weights[i].firstseperator,\n\t\t\t\t\t\t\t\t\tconfigout->weights[i].firstseperator);\n\t} //end for\n} //end of the function InterbreedWeightConfigs\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid BotShutdownWeights(void)\n{\n\tint i;\n\n\tfor( i = 0; i < MAX_WEIGHT_FILES; i++ )\n\t{\n\t\tif (weightFileList[i])\n\t\t{\n\t\t\tFreeWeightConfig2(weightFileList[i]);\n\t\t\tweightFileList[i] = NULL;\n\t\t} //end if\n\t} //end for\n} //end of the function BotShutdownWeights\n"
  },
  {
    "path": "src/engine/botlib/be_ai_weight.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tbe_ai_weight.h\n *\n * desc:\t\tfuzzy weights\n *\n * $Archive: /source/code/botlib/be_ai_weight.h $\n *\n *****************************************************************************/\n\n#define WT_BALANCE\t\t\t1\n#define MAX_WEIGHTS\t\t\t128\n\n//fuzzy seperator\ntypedef struct fuzzyseperator_s\n{\n\tint index;\n\tint value;\n\tint type;\n\tfloat weight;\n\tfloat minweight;\n\tfloat maxweight;\n\tstruct fuzzyseperator_s *child;\n\tstruct fuzzyseperator_s *next;\n} fuzzyseperator_t;\n\n//fuzzy weight\ntypedef struct weight_s\n{\n\tchar *name;\n\tstruct fuzzyseperator_s *firstseperator;\n} weight_t;\n\n//weight configuration\ntypedef struct weightconfig_s\n{\n\tint numweights;\n\tweight_t weights[MAX_WEIGHTS];\n\tchar\t\tfilename[MAX_QPATH];\n} weightconfig_t;\n\n//reads a weight configuration\nweightconfig_t *ReadWeightConfig(char *filename);\n//free a weight configuration\nvoid FreeWeightConfig(weightconfig_t *config);\n//writes a weight configuration, returns true if successfull\nqboolean WriteWeightConfig(char *filename, weightconfig_t *config);\n//find the fuzzy weight with the given name\nint FindFuzzyWeight(weightconfig_t *wc, char *name);\n//returns the fuzzy weight for the given inventory and weight\nfloat FuzzyWeight(int *inventory, weightconfig_t *wc, int weightnum);\nfloat FuzzyWeightUndecided(int *inventory, weightconfig_t *wc, int weightnum);\n//scales the weight with the given name\nvoid ScaleWeight(weightconfig_t *config, char *name, float scale);\n//scale the balance range\nvoid ScaleBalanceRange(weightconfig_t *config, float scale);\n//evolves the weight configuration\nvoid EvolveWeightConfig(weightconfig_t *config);\n//interbreed the weight configurations and stores the interbreeded one in configout\nvoid InterbreedWeightConfigs(weightconfig_t *config1, weightconfig_t *config2, weightconfig_t *configout);\n//frees cached weight configurations\nvoid BotShutdownWeights(void);\n"
  },
  {
    "path": "src/engine/botlib/be_ea.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tbe_ea.c\n *\n * desc:\t\telementary actions\n *\n * $Archive: /MissionPack/code/botlib/be_ea.c $\n *\n *****************************************************************************/\n\n#include \"../../game/q_shared.h\"\n#include \"l_memory.h\"\n#include \"l_script.h\"\n#include \"l_precomp.h\"\n#include \"l_struct.h\"\n#include \"../../game/botlib.h\"\n#include \"be_interface.h\"\n\n#define MAX_USERMOVE\t\t\t\t400\n#define MAX_COMMANDARGUMENTS\t\t10\n#define ACTION_JUMPEDLASTFRAME\t\t128\n\nbot_input_t *botinputs;\n\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid EA_Say(int client, char *str)\n{\n\tbotimport.BotClientCommand(client, va(\"say %s\", str) );\n} //end of the function EA_Say\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid EA_SayTeam(int client, char *str)\n{\n\tbotimport.BotClientCommand(client, va(\"say_team %s\", str));\n} //end of the function EA_SayTeam\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid EA_Tell(int client, int clientto, char *str)\n{\n\tbotimport.BotClientCommand(client, va(\"tell %d, %s\", clientto, str));\n} //end of the function EA_SayTeam\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid EA_UseItem(int client, char *it)\n{\n\tbotimport.BotClientCommand(client, va(\"use %s\", it));\n} //end of the function EA_UseItem\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid EA_DropItem(int client, char *it)\n{\n\tbotimport.BotClientCommand(client, va(\"drop %s\", it));\n} //end of the function EA_DropItem\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid EA_UseInv(int client, char *inv)\n{\n\tbotimport.BotClientCommand(client, va(\"invuse %s\", inv));\n} //end of the function EA_UseInv\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid EA_DropInv(int client, char *inv)\n{\n\tbotimport.BotClientCommand(client, va(\"invdrop %s\", inv));\n} //end of the function EA_DropInv\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid EA_Gesture(int client)\n{\n\tbot_input_t *bi;\n\n\tbi = &botinputs[client];\n\n\tbi->actionflags |= ACTION_GESTURE;\n} //end of the function EA_Gesture\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid EA_Command(int client, char *command)\n{\n\tbotimport.BotClientCommand(client, command);\n} //end of the function EA_Command\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid EA_SelectWeapon(int client, int weapon)\n{\n\tbot_input_t *bi;\n\n\tbi = &botinputs[client];\n\n\tbi->weapon = weapon;\n} //end of the function EA_SelectWeapon\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid EA_Attack(int client)\n{\n\tbot_input_t *bi;\n\n\tbi = &botinputs[client];\n\n\tbi->actionflags |= ACTION_ATTACK;\n} //end of the function EA_Attack\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid EA_Talk(int client)\n{\n\tbot_input_t *bi;\n\n\tbi = &botinputs[client];\n\n\tbi->actionflags |= ACTION_TALK;\n} //end of the function EA_Talk\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid EA_Use(int client)\n{\n\tbot_input_t *bi;\n\n\tbi = &botinputs[client];\n\n\tbi->actionflags |= ACTION_USE;\n} //end of the function EA_Use\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid EA_Respawn(int client)\n{\n\tbot_input_t *bi;\n\n\tbi = &botinputs[client];\n\n\tbi->actionflags |= ACTION_RESPAWN;\n} //end of the function EA_Respawn\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid EA_Jump(int client)\n{\n\tbot_input_t *bi;\n\n\tbi = &botinputs[client];\n\n\tif (bi->actionflags & ACTION_JUMPEDLASTFRAME)\n\t{\n\t\tbi->actionflags &= ~ACTION_JUMP;\n\t} //end if\n\telse\n\t{\n\t\tbi->actionflags |= ACTION_JUMP;\n\t} //end if\n} //end of the function EA_Jump\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid EA_DelayedJump(int client)\n{\n\tbot_input_t *bi;\n\n\tbi = &botinputs[client];\n\n\tif (bi->actionflags & ACTION_JUMPEDLASTFRAME)\n\t{\n\t\tbi->actionflags &= ~ACTION_DELAYEDJUMP;\n\t} //end if\n\telse\n\t{\n\t\tbi->actionflags |= ACTION_DELAYEDJUMP;\n\t} //end if\n} //end of the function EA_DelayedJump\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid EA_Crouch(int client)\n{\n\tbot_input_t *bi;\n\n\tbi = &botinputs[client];\n\n\tbi->actionflags |= ACTION_CROUCH;\n} //end of the function EA_Crouch\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid EA_Walk(int client)\n{\n\tbot_input_t *bi;\n\n\tbi = &botinputs[client];\n\n\tbi->actionflags |= ACTION_WALK;\n} //end of the function EA_Walk\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid EA_Action(int client, int action)\n{\n\tbot_input_t *bi;\n\n\tbi = &botinputs[client];\n\n\tbi->actionflags |= action;\n} //end of function EA_Action\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid EA_MoveUp(int client)\n{\n\tbot_input_t *bi;\n\n\tbi = &botinputs[client];\n\n\tbi->actionflags |= ACTION_MOVEUP;\n} //end of the function EA_MoveUp\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid EA_MoveDown(int client)\n{\n\tbot_input_t *bi;\n\n\tbi = &botinputs[client];\n\n\tbi->actionflags |= ACTION_MOVEDOWN;\n} //end of the function EA_MoveDown\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid EA_MoveForward(int client)\n{\n\tbot_input_t *bi;\n\n\tbi = &botinputs[client];\n\n\tbi->actionflags |= ACTION_MOVEFORWARD;\n} //end of the function EA_MoveForward\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid EA_MoveBack(int client)\n{\n\tbot_input_t *bi;\n\n\tbi = &botinputs[client];\n\n\tbi->actionflags |= ACTION_MOVEBACK;\n} //end of the function EA_MoveBack\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid EA_MoveLeft(int client)\n{\n\tbot_input_t *bi;\n\n\tbi = &botinputs[client];\n\n\tbi->actionflags |= ACTION_MOVELEFT;\n} //end of the function EA_MoveLeft\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid EA_MoveRight(int client)\n{\n\tbot_input_t *bi;\n\n\tbi = &botinputs[client];\n\n\tbi->actionflags |= ACTION_MOVERIGHT;\n} //end of the function EA_MoveRight\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid EA_Move(int client, vec3_t dir, float speed)\n{\n\tbot_input_t *bi;\n\n\tbi = &botinputs[client];\n\n\tVectorCopy(dir, bi->dir);\n\t//cap speed\n\tif (speed > MAX_USERMOVE) speed = MAX_USERMOVE;\n\telse if (speed < -MAX_USERMOVE) speed = -MAX_USERMOVE;\n\tbi->speed = speed;\n} //end of the function EA_Move\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid EA_View(int client, vec3_t viewangles)\n{\n\tbot_input_t *bi;\n\n\tbi = &botinputs[client];\n\n\tVectorCopy(viewangles, bi->viewangles);\n} //end of the function EA_View\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid EA_EndRegular(int client, float thinktime)\n{\n/*\n\tbot_input_t *bi;\n\tint jumped = qfalse;\n\n\tbi = &botinputs[client];\n\n\tbi->actionflags &= ~ACTION_JUMPEDLASTFRAME;\n\n\tbi->thinktime = thinktime;\n\tbotimport.BotInput(client, bi);\n\n\tbi->thinktime = 0;\n\tVectorClear(bi->dir);\n\tbi->speed = 0;\n\tjumped = bi->actionflags & ACTION_JUMP;\n\tbi->actionflags = 0;\n\tif (jumped) bi->actionflags |= ACTION_JUMPEDLASTFRAME;\n*/\n} //end of the function EA_EndRegular\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid EA_GetInput(int client, float thinktime, bot_input_t *input)\n{\n\tbot_input_t *bi;\n//\tint jumped = qfalse;\n\n\tbi = &botinputs[client];\n\n//\tbi->actionflags &= ~ACTION_JUMPEDLASTFRAME;\n\n\tbi->thinktime = thinktime;\n\tCom_Memcpy(input, bi, sizeof(bot_input_t));\n\n\t/*\n\tbi->thinktime = 0;\n\tVectorClear(bi->dir);\n\tbi->speed = 0;\n\tjumped = bi->actionflags & ACTION_JUMP;\n\tbi->actionflags = 0;\n\tif (jumped) bi->actionflags |= ACTION_JUMPEDLASTFRAME;\n\t*/\n} //end of the function EA_GetInput\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid EA_ResetInput(int client)\n{\n\tbot_input_t *bi;\n\tint jumped = qfalse;\n\n\tbi = &botinputs[client];\n\tbi->actionflags &= ~ACTION_JUMPEDLASTFRAME;\n\n\tbi->thinktime = 0;\n\tVectorClear(bi->dir);\n\tbi->speed = 0;\n\tjumped = bi->actionflags & ACTION_JUMP;\n\tbi->actionflags = 0;\n\tif (jumped) bi->actionflags |= ACTION_JUMPEDLASTFRAME;\n} //end of the function EA_ResetInput\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint EA_Setup(void)\n{\n\t//initialize the bot inputs\n\tbotinputs = (bot_input_t *) GetClearedHunkMemory(\n\t\t\t\t\t\t\t\t\tbotlibglobals.maxclients * sizeof(bot_input_t));\n\treturn BLERR_NOERROR;\n} //end of the function EA_Setup\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid EA_Shutdown(void)\n{\n\tFreeMemory(botinputs);\n\tbotinputs = NULL;\n} //end of the function EA_Shutdown\n"
  },
  {
    "path": "src/engine/botlib/be_interface.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tbe_interface.c // bk010221 - FIXME - DEAD code elimination\n *\n * desc:\t\tbot library interface\n *\n * $Archive: /MissionPack/code/botlib/be_interface.c $\n *\n *****************************************************************************/\n\n#include \"../../game/q_shared.h\"\n#include \"l_memory.h\"\n#include \"l_log.h\"\n#include \"l_libvar.h\"\n#include \"l_script.h\"\n#include \"l_precomp.h\"\n#include \"l_struct.h\"\n#include \"aasfile.h\"\n#include \"../../game/botlib.h\"\n#include \"../../game/be_aas.h\"\n#include \"be_aas_funcs.h\"\n#include \"be_aas_def.h\"\n#include \"be_interface.h\"\n\n#include \"../../game/be_ea.h\"\n#include \"be_ai_weight.h\"\n#include \"../../game/be_ai_goal.h\"\n#include \"../../game/be_ai_move.h\"\n#include \"../../game/be_ai_weap.h\"\n#include \"../../game/be_ai_chat.h\"\n#include \"../../game/be_ai_char.h\"\n#include \"../../game/be_ai_gen.h\"\n\n//library globals in a structure\nbotlib_globals_t botlibglobals;\n\nbotlib_export_t be_botlib_export;\nbotlib_import_t botimport;\n//\nint bot_developer;\n//qtrue if the library is setup\nint botlibsetup = qfalse;\n\n//===========================================================================\n//\n// several functions used by the exported functions\n//\n//===========================================================================\n\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint Sys_MilliSeconds(void)\n{\n\treturn clock() * 1000 / CLOCKS_PER_SEC;\n} //end of the function Sys_MilliSeconds\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nqboolean ValidClientNumber(int num, char *str)\n{\n\tif (num < 0 || num > botlibglobals.maxclients)\n\t{\n\t\t//weird: the disabled stuff results in a crash\n\t\tbotimport.Print(PRT_ERROR, \"%s: invalid client number %d, [0, %d]\\n\",\n\t\t\t\t\t\t\t\t\t\tstr, num, botlibglobals.maxclients);\n\t\treturn qfalse;\n\t} //end if\n\treturn qtrue;\n} //end of the function BotValidateClientNumber\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nqboolean ValidEntityNumber(int num, char *str)\n{\n\tif (num < 0 || num > botlibglobals.maxentities)\n\t{\n\t\tbotimport.Print(PRT_ERROR, \"%s: invalid entity number %d, [0, %d]\\n\",\n\t\t\t\t\t\t\t\t\t\tstr, num, botlibglobals.maxentities);\n\t\treturn qfalse;\n\t} //end if\n\treturn qtrue;\n} //end of the function BotValidateClientNumber\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nqboolean BotLibSetup(char *str)\n{\n\tif (!botlibglobals.botlibsetup)\n\t{\n\t\tbotimport.Print(PRT_ERROR, \"%s: bot library used before being setup\\n\", str);\n\t\treturn qfalse;\n\t} //end if\n\treturn qtrue;\n} //end of the function BotLibSetup\n\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint Export_BotLibSetup(void)\n{\n\tint\t\terrnum;\n\t\n\tbot_developer = LibVarGetValue(\"bot_developer\");\n  memset( &botlibglobals, 0, sizeof(botlibglobals) ); // bk001207 - init\n\t//initialize byte swapping (litte endian etc.)\n    // Swap_Init();\n\t// Log_Open(\"botlib.log\");\n\t//\n\tbotimport.Print(PRT_MESSAGE, \"------- BotLib Initialization -------\\n\");\n\t//\n\tbotlibglobals.maxclients = (int) LibVarValue(\"maxclients\", \"128\");\n\tbotlibglobals.maxentities = (int) LibVarValue(\"maxentities\", \"1024\");\n\n\terrnum = AAS_Setup();\t\t\t//be_aas_main.c\n\tif (errnum != BLERR_NOERROR) return errnum;\n\terrnum = EA_Setup();\t\t\t//be_ea.c\n\tif (errnum != BLERR_NOERROR) return errnum;\n\terrnum = BotSetupWeaponAI();\t//be_ai_weap.c\n\tif (errnum != BLERR_NOERROR)return errnum;\n\terrnum = BotSetupGoalAI();\t\t//be_ai_goal.c\n\tif (errnum != BLERR_NOERROR) return errnum;\n\terrnum = BotSetupChatAI();\t\t//be_ai_chat.c\n\tif (errnum != BLERR_NOERROR) return errnum;\n\terrnum = BotSetupMoveAI();\t\t//be_ai_move.c\n\tif (errnum != BLERR_NOERROR) return errnum;\n\n\tbotlibsetup = qtrue;\n\tbotlibglobals.botlibsetup = qtrue;\n\n\treturn BLERR_NOERROR;\n} //end of the function Export_BotLibSetup\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint Export_BotLibShutdown(void)\n{\n\tif (!BotLibSetup(\"BotLibShutdown\")) return BLERR_LIBRARYNOTSETUP;\n#ifndef DEMO\n\t//DumpFileCRCs();\n#endif //DEMO\n\t//\n\tBotShutdownChatAI();\t\t//be_ai_chat.c\n\tBotShutdownMoveAI();\t\t//be_ai_move.c\n\tBotShutdownGoalAI();\t\t//be_ai_goal.c\n\tBotShutdownWeaponAI();\t\t//be_ai_weap.c\n\tBotShutdownWeights();\t\t//be_ai_weight.c\n\tBotShutdownCharacters();\t//be_ai_char.c\n\t//shud down aas\n\tAAS_Shutdown();\n\t//shut down bot elemantary actions\n\tEA_Shutdown();\n\t//free all libvars\n\tLibVarDeAllocAll();\n\t//remove all global defines from the pre compiler\n\tPC_RemoveAllGlobalDefines();\n\n\t//dump all allocated memory\n//\tDumpMemory();\n#ifdef DEBUG\n\tPrintMemoryLabels();\n#endif\n\t//shut down library log file\n\tLog_Shutdown();\n\t//\n\tbotlibsetup = qfalse;\n\tbotlibglobals.botlibsetup = qfalse;\n\t// print any files still open\n\tPC_CheckOpenSourceHandles();\n\t//\n\treturn BLERR_NOERROR;\n} //end of the function Export_BotLibShutdown\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint Export_BotLibVarSet(char *var_name, char *value)\n{\n\tLibVarSet(var_name, value);\n\treturn BLERR_NOERROR;\n} //end of the function Export_BotLibVarSet\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint Export_BotLibVarGet(char *var_name, char *value, int size)\n{\n\tchar *varvalue;\n\n\tvarvalue = LibVarGetString(var_name);\n\tstrncpy(value, varvalue, size-1);\n\tvalue[size-1] = '\\0';\n\treturn BLERR_NOERROR;\n} //end of the function Export_BotLibVarGet\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint Export_BotLibStartFrame(float time)\n{\n\tif (!BotLibSetup(\"BotStartFrame\")) return BLERR_LIBRARYNOTSETUP;\n\treturn AAS_StartFrame(time);\n} //end of the function Export_BotLibStartFrame\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint Export_BotLibLoadMap(const char *mapname)\n{\n#ifdef DEBUG\n\tint starttime = Sys_MilliSeconds();\n#endif\n\tint errnum;\n\n\tif (!BotLibSetup(\"BotLoadMap\")) return BLERR_LIBRARYNOTSETUP;\n\t//\n\tbotimport.Print(PRT_MESSAGE, \"------------ Map Loading ------------\\n\");\n\t//startup AAS for the current map, model and sound index\n\terrnum = AAS_LoadMap(mapname);\n\tif (errnum != BLERR_NOERROR) return errnum;\n\t//initialize the items in the level\n\tBotInitLevelItems();\t\t//be_ai_goal.h\n\tBotSetBrushModelTypes();\t//be_ai_move.h\n\t//\n\tbotimport.Print(PRT_MESSAGE, \"-------------------------------------\\n\");\n#ifdef DEBUG\n\tbotimport.Print(PRT_MESSAGE, \"map loaded in %d msec\\n\", Sys_MilliSeconds() - starttime);\n#endif\n\t//\n\treturn BLERR_NOERROR;\n} //end of the function Export_BotLibLoadMap\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint Export_BotLibUpdateEntity(int ent, bot_entitystate_t *state)\n{\n\tif (!BotLibSetup(\"BotUpdateEntity\")) return BLERR_LIBRARYNOTSETUP;\n\tif (!ValidEntityNumber(ent, \"BotUpdateEntity\")) return BLERR_INVALIDENTITYNUMBER;\n\n\treturn AAS_UpdateEntity(ent, state);\n} //end of the function Export_BotLibUpdateEntity\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid AAS_TestMovementPrediction(int entnum, vec3_t origin, vec3_t dir);\nvoid ElevatorBottomCenter(aas_reachability_t *reach, vec3_t bottomcenter);\nint BotGetReachabilityToGoal(vec3_t origin, int areanum,\n\t\t\t\t\t\t\t\t\t  int lastgoalareanum, int lastareanum,\n\t\t\t\t\t\t\t\t\t  int *avoidreach, float *avoidreachtimes, int *avoidreachtries,\n\t\t\t\t\t\t\t\t\t  bot_goal_t *goal, int travelflags, int movetravelflags,\n\t\t\t\t\t\t\t\t\t  struct bot_avoidspot_s *avoidspots, int numavoidspots, int *flags);\n\nint AAS_PointLight(vec3_t origin, int *red, int *green, int *blue);\n\nint AAS_TraceAreas(vec3_t start, vec3_t end, int *areas, vec3_t *points, int maxareas);\n\nint AAS_Reachability_WeaponJump(int area1num, int area2num);\n\nint BotFuzzyPointReachabilityArea(vec3_t origin);\n\nfloat BotGapDistance(vec3_t origin, vec3_t hordir, int entnum);\n\nvoid AAS_FloodAreas(vec3_t origin);\n\nint BotExportTest(int parm0, char *parm1, vec3_t parm2, vec3_t parm3)\n{\n\n//\treturn AAS_PointLight(parm2, NULL, NULL, NULL);\n\n#ifdef DEBUG\n\tstatic int area = -1;\n\tstatic int line[2];\n\tint newarea, i, highlightarea, flood;\n//\tint reachnum;\n\tvec3_t eye, forward, right, end, origin;\n//\tvec3_t bottomcenter;\n//\taas_trace_t trace;\n//\taas_face_t *face;\n//\taas_entity_t *ent;\n//\tbsp_trace_t bsptrace;\n//\taas_reachability_t reach;\n//\tbot_goal_t goal;\n\n\t// clock_t start_time, end_time;\n\tvec3_t mins = {-16, -16, -24};\n\tvec3_t maxs = {16, 16, 32};\n\n//\tint areas[10], numareas;\n\n\n\t//return 0;\n\n\tif (!aasworld.loaded) return 0;\n\n\t/*\n\tif (parm0 & 1)\n\t{\n\t\tAAS_ClearShownPolygons();\n\t\tAAS_FloodAreas(parm2);\n\t} //end if\n\treturn 0;\n\t*/\n\tfor (i = 0; i < 2; i++) if (!line[i]) line[i] = botimport.DebugLineCreate();\n\n//\tAAS_ClearShownDebugLines();\n\n\t//if (AAS_AgainstLadder(parm2)) botimport.Print(PRT_MESSAGE, \"against ladder\\n\");\n\t//BotOnGround(parm2, PRESENCE_NORMAL, 1, &newarea, &newarea);\n\t//botimport.Print(PRT_MESSAGE, \"%f %f %f\\n\", parm2[0], parm2[1], parm2[2]);\n\t//*\n\thighlightarea = LibVarGetValue(\"bot_highlightarea\");\n\tif (highlightarea > 0)\n\t{\n\t\tnewarea = highlightarea;\n\t} //end if\n\telse\n\t{\n\t\tVectorCopy(parm2, origin);\n\t\torigin[2] += 0.5;\n\t\t//newarea = AAS_PointAreaNum(origin);\n\t\tnewarea = BotFuzzyPointReachabilityArea(origin);\n\t} //end else\n\n\tbotimport.Print(PRT_MESSAGE, \"\\rtravel time to goal (%d) = %d  \", botlibglobals.goalareanum,\n\t\tAAS_AreaTravelTimeToGoalArea(newarea, origin, botlibglobals.goalareanum, TFL_DEFAULT));\n\t//newarea = BotReachabilityArea(origin, qtrue);\n\tif (newarea != area)\n\t{\n\t\tbotimport.Print(PRT_MESSAGE, \"origin = %f, %f, %f\\n\", origin[0], origin[1], origin[2]);\n\t\tarea = newarea;\n\t\tbotimport.Print(PRT_MESSAGE, \"new area %d, cluster %d, presence type %d\\n\",\n\t\t\t\t\tarea, AAS_AreaCluster(area), AAS_PointPresenceType(origin));\n\t\tbotimport.Print(PRT_MESSAGE, \"area contents: \");\n\t\tif (aasworld.areasettings[area].contents & AREACONTENTS_WATER)\n\t\t{\n\t\t\tbotimport.Print(PRT_MESSAGE, \"water &\");\n\t\t} //end if\n\t\tif (aasworld.areasettings[area].contents & AREACONTENTS_LAVA)\n\t\t{\n\t\t\tbotimport.Print(PRT_MESSAGE, \"lava &\");\n\t\t} //end if\n\t\tif (aasworld.areasettings[area].contents & AREACONTENTS_SLIME)\n\t\t{\n\t\t\tbotimport.Print(PRT_MESSAGE, \"slime &\");\n\t\t} //end if\n\t\tif (aasworld.areasettings[area].contents & AREACONTENTS_JUMPPAD)\n\t\t{\n\t\t\tbotimport.Print(PRT_MESSAGE, \"jump pad &\");\n\t\t} //end if\n\t\tif (aasworld.areasettings[area].contents & AREACONTENTS_CLUSTERPORTAL)\n\t\t{\n\t\t\tbotimport.Print(PRT_MESSAGE, \"cluster portal &\");\n\t\t} //end if\n\t\tif (aasworld.areasettings[area].contents & AREACONTENTS_VIEWPORTAL)\n\t\t{\n\t\t\tbotimport.Print(PRT_MESSAGE, \"view portal &\");\n\t\t} //end if\n\t\tif (aasworld.areasettings[area].contents & AREACONTENTS_DONOTENTER)\n\t\t{\n\t\t\tbotimport.Print(PRT_MESSAGE, \"do not enter &\");\n\t\t} //end if\n\t\tif (aasworld.areasettings[area].contents & AREACONTENTS_MOVER)\n\t\t{\n\t\t\tbotimport.Print(PRT_MESSAGE, \"mover &\");\n\t\t} //end if\n\t\tif (!aasworld.areasettings[area].contents)\n\t\t{\n\t\t\tbotimport.Print(PRT_MESSAGE, \"empty\");\n\t\t} //end if\n\t\tbotimport.Print(PRT_MESSAGE, \"\\n\");\n\t\tbotimport.Print(PRT_MESSAGE, \"travel time to goal (%d) = %d\\n\", botlibglobals.goalareanum,\n\t\t\t\t\tAAS_AreaTravelTimeToGoalArea(newarea, origin, botlibglobals.goalareanum, TFL_DEFAULT|TFL_ROCKETJUMP));\n\t\t/*\n\t\tVectorCopy(origin, end);\n\t\tend[2] += 5;\n\t\tnumareas = AAS_TraceAreas(origin, end, areas, NULL, 10);\n\t\tAAS_TraceClientBBox(origin, end, PRESENCE_CROUCH, -1);\n\t\tbotimport.Print(PRT_MESSAGE, \"num areas = %d, area = %d\\n\", numareas, areas[0]);\n\t\t*/\n\t\t/*\n\t\tbotlibglobals.goalareanum = newarea;\n\t\tVectorCopy(parm2, botlibglobals.goalorigin);\n\t\tbotimport.Print(PRT_MESSAGE, \"new goal %2.1f %2.1f %2.1f area %d\\n\",\n\t\t\t\t\t\t\t\torigin[0], origin[1], origin[2], newarea);\n\t\t*/\n\t} //end if\n\t//*\n\tflood = LibVarGetValue(\"bot_flood\");\n\tif (parm0 & 1)\n\t{\n\t\tif (flood)\n\t\t{\n\t\t\tAAS_ClearShownPolygons();\n\t\t\tAAS_ClearShownDebugLines();\n\t\t\tAAS_FloodAreas(parm2);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tbotlibglobals.goalareanum = newarea;\n\t\t\tVectorCopy(parm2, botlibglobals.goalorigin);\n\t\t\tbotimport.Print(PRT_MESSAGE, \"new goal %2.1f %2.1f %2.1f area %d\\n\",\n\t\t\t\t\t\t\t\t\torigin[0], origin[1], origin[2], newarea);\n\t\t}\n\t} //end if*/\n\tif (flood)\n\t\treturn 0;\n//\tif (parm0 & BUTTON_USE)\n//\t{\n//\t\tbotlibglobals.runai = !botlibglobals.runai;\n//\t\tif (botlibglobals.runai) botimport.Print(PRT_MESSAGE, \"started AI\\n\");\n//\t\telse botimport.Print(PRT_MESSAGE, \"stopped AI\\n\");\n\t\t//* /\n\t\t/*\n\t\tgoal.areanum = botlibglobals.goalareanum;\n\t\treachnum = BotGetReachabilityToGoal(parm2, newarea, 1,\n\t\t\t\t\t\t\t\t\t\tms.avoidreach, ms.avoidreachtimes,\n\t\t\t\t\t\t\t\t\t\t&goal, TFL_DEFAULT);\n\t\tif (!reachnum)\n\t\t{\n\t\t\tbotimport.Print(PRT_MESSAGE, \"goal not reachable\\n\");\n\t\t} //end if\n\t\telse\n\t\t{\n\t\t\tAAS_ReachabilityFromNum(reachnum, &reach);\n\t\t\tAAS_ClearShownDebugLines();\n\t\t\tAAS_ShowArea(area, qtrue);\n\t\t\tAAS_ShowArea(reach.areanum, qtrue);\n\t\t\tAAS_DrawCross(reach.start, 6, LINECOLOR_BLUE);\n\t\t\tAAS_DrawCross(reach.end, 6, LINECOLOR_RED);\n\t\t\t//\n\t\t\tif ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_ELEVATOR)\n\t\t\t{\n\t\t\t\tElevatorBottomCenter(&reach, bottomcenter);\n\t\t\t\tAAS_DrawCross(bottomcenter, 10, LINECOLOR_GREEN);\n\t\t\t} //end if\n\t\t} //end else*/\n//\t\tbotimport.Print(PRT_MESSAGE, \"travel time to goal = %d\\n\",\n//\t\t\t\t\tAAS_AreaTravelTimeToGoalArea(area, origin, botlibglobals.goalareanum, TFL_DEFAULT));\n//\t\tbotimport.Print(PRT_MESSAGE, \"test rj from 703 to 716\\n\");\n//\t\tAAS_Reachability_WeaponJump(703, 716);\n//\t} //end if*/\n\n/*\tface = AAS_AreaGroundFace(newarea, parm2);\n\tif (face)\n\t{\n\t\tAAS_ShowFace(face - aasworld.faces);\n\t} //end if*/\n\t/*\n\tAAS_ClearShownDebugLines();\n\tAAS_ShowArea(newarea, parm0 & BUTTON_USE);\n\tAAS_ShowReachableAreas(area);\n\t*/\n\tAAS_ClearShownPolygons();\n\tAAS_ClearShownDebugLines();\n\tAAS_ShowAreaPolygons(newarea, 1, parm0 & 4);\n\tif (parm0 & 2) AAS_ShowReachableAreas(area);\n\telse\n\t{\n\t\tstatic int lastgoalareanum, lastareanum;\n\t\tstatic int avoidreach[MAX_AVOIDREACH];\n\t\tstatic float avoidreachtimes[MAX_AVOIDREACH];\n\t\tstatic int avoidreachtries[MAX_AVOIDREACH];\n\t\tint reachnum, resultFlags;\n\t\tbot_goal_t goal;\n\t\taas_reachability_t reach;\n\n\t\t/*\n\t\tgoal.areanum = botlibglobals.goalareanum;\n\t\tVectorCopy(botlibglobals.goalorigin, goal.origin);\n\t\treachnum = BotGetReachabilityToGoal(origin, newarea,\n\t\t\t\t\t\t\t\t\t  lastgoalareanum, lastareanum,\n\t\t\t\t\t\t\t\t\t  avoidreach, avoidreachtimes, avoidreachtries,\n\t\t\t\t\t\t\t\t\t  &goal, TFL_DEFAULT|TFL_FUNCBOB|TFL_ROCKETJUMP, TFL_DEFAULT|TFL_FUNCBOB|TFL_ROCKETJUMP,\n\t\t\t\t\t\t\t\t\t  NULL, 0, &resultFlags);\n\t\tAAS_ReachabilityFromNum(reachnum, &reach);\n\t\tAAS_ShowReachability(&reach);\n\t\t*/\n\t\tint curarea;\n\t\tvec3_t curorigin;\n\n\t\tgoal.areanum = botlibglobals.goalareanum;\n\t\tVectorCopy(botlibglobals.goalorigin, goal.origin);\n\t\tVectorCopy(origin, curorigin);\n\t\tcurarea = newarea;\n\t\tfor ( i = 0; i < 100; i++ ) {\n\t\t\tif ( curarea == goal.areanum ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\treachnum = BotGetReachabilityToGoal(curorigin, curarea,\n\t\t\t\t\t\t\t\t\t\t  lastgoalareanum, lastareanum,\n\t\t\t\t\t\t\t\t\t\t  avoidreach, avoidreachtimes, avoidreachtries,\n\t\t\t\t\t\t\t\t\t\t  &goal, TFL_DEFAULT|TFL_FUNCBOB|TFL_ROCKETJUMP, TFL_DEFAULT|TFL_FUNCBOB|TFL_ROCKETJUMP,\n\t\t\t\t\t\t\t\t\t\t  NULL, 0, &resultFlags);\n\t\t\tAAS_ReachabilityFromNum(reachnum, &reach);\n\t\t\tAAS_ShowReachability(&reach);\n\t\t\tVectorCopy(reach.end, origin);\n\t\t\tlastareanum = curarea;\n\t\t\tcurarea = reach.areanum;\n\t\t}\n\t} //end else\n\tVectorClear(forward);\n\t//BotGapDistance(origin, forward, 0);\n\t/*\n\tif (parm0 & BUTTON_USE)\n\t{\n\t\tbotimport.Print(PRT_MESSAGE, \"test rj from 703 to 716\\n\");\n\t\tAAS_Reachability_WeaponJump(703, 716);\n\t} //end if*/\n\n\tAngleVectors(parm3, forward, right, NULL);\n\t//get the eye 16 units to the right of the origin\n\tVectorMA(parm2, 8, right, eye);\n\t//get the eye 24 units up\n\teye[2] += 24;\n\t//get the end point for the line to be traced\n\tVectorMA(eye, 800, forward, end);\n\n//\tAAS_TestMovementPrediction(1, parm2, forward);\n/*\n    //trace the line to find the hit point\n\ttrace = AAS_TraceClientBBox(eye, end, PRESENCE_NORMAL, 1);\n\tif (!line[0]) line[0] = botimport.DebugLineCreate();\n\tbotimport.DebugLineShow(line[0], eye, trace.endpos, LINECOLOR_BLUE);\n\t//\n\tAAS_ClearShownDebugLines();\n\tif (trace.ent)\n\t{\n\t\tent = &aasworld.entities[trace.ent];\n\t\tAAS_ShowBoundingBox(ent->origin, ent->mins, ent->maxs);\n\t} //end if\n*/\n\n/*\n\tstart_time = clock();\n\tfor (i = 0; i < 2000; i++)\n\t{\n\t\tAAS_Trace2(eye, mins, maxs, end, 1, MASK_PLAYERSOLID);\n//\t\tAAS_TraceClientBBox(eye, end, PRESENCE_NORMAL, 1);\n\t} //end for\n\tend_time = clock();\n\tbotimport.Print(PRT_MESSAGE, \"me %lu clocks, %lu CLOCKS_PER_SEC\\n\", end_time - start_time, CLOCKS_PER_SEC);\n\tstart_time = clock();\n\tfor (i = 0; i < 2000; i++)\n\t{\n\t\tAAS_Trace(eye, mins, maxs, end, 1, MASK_PLAYERSOLID);\n\t} //end for\n\tend_time = clock();\n\tbotimport.Print(PRT_MESSAGE, \"id %lu clocks, %lu CLOCKS_PER_SEC\\n\", end_time - start_time, CLOCKS_PER_SEC);\n*/\n\n    // TTimo: nested comments are BAD for gcc -Werror, use #if 0 instead..\n#if 0\n\tAAS_ClearShownDebugLines();\n\t//bsptrace = AAS_Trace(eye, NULL, NULL, end, 1, MASK_PLAYERSOLID);\n\tbsptrace = AAS_Trace(eye, mins, maxs, end, 1, MASK_PLAYERSOLID);\n\tif (!line[0]) line[0] = botimport.DebugLineCreate();\n\tbotimport.DebugLineShow(line[0], eye, bsptrace.endpos, LINECOLOR_YELLOW);\n\tif (bsptrace.fraction < 1.0)\n\t{\n\t\tface = AAS_TraceEndFace(&trace);\n\t\tif (face)\n\t\t{\n\t\t\tAAS_ShowFace(face - aasworld.faces);\n\t\t} //end if\n\t\t\n\t\tAAS_DrawPlaneCross(bsptrace.endpos,\n\t\t\t\t\t\t\t\t\tbsptrace.plane.normal,\n\t\t\t\t\t\t\t\t\tbsptrace.plane.dist + bsptrace.exp_dist,\n\t\t\t\t\t\t\t\t\tbsptrace.plane.type, LINECOLOR_GREEN);\n\t\tif (trace.ent)\n\t\t{\n\t\t\tent = &aasworld.entities[trace.ent];\n\t\t\tAAS_ShowBoundingBox(ent->origin, ent->mins, ent->maxs);\n\t\t} //end if\n\t} //end if\n\t//bsptrace = AAS_Trace2(eye, NULL, NULL, end, 1, MASK_PLAYERSOLID);\n\tbsptrace = AAS_Trace2(eye, mins, maxs, end, 1, MASK_PLAYERSOLID);\n\tbotimport.DebugLineShow(line[1], eye, bsptrace.endpos, LINECOLOR_BLUE);\n\tif (bsptrace.fraction < 1.0)\n\t{\n\t\tAAS_DrawPlaneCross(bsptrace.endpos,\n\t\t\t\t\t\t\t\t\tbsptrace.plane.normal,\n\t\t\t\t\t\t\t\t\tbsptrace.plane.dist,// + bsptrace.exp_dist,\n\t\t\t\t\t\t\t\t\tbsptrace.plane.type, LINECOLOR_RED);\n\t\tif (bsptrace.ent)\n\t\t{\n\t\t\tent = &aasworld.entities[bsptrace.ent];\n\t\t\tAAS_ShowBoundingBox(ent->origin, ent->mins, ent->maxs);\n\t\t} //end if\n\t} //end if\n#endif\n#endif\n\treturn 0;\n} //end of the function BotExportTest\n\n\n/*\n============\nInit_AAS_Export\n============\n*/\nstatic void Init_AAS_Export( aas_export_t *aas ) {\n\t//--------------------------------------------\n\t// be_aas_entity.c\n\t//--------------------------------------------\n\taas->AAS_EntityInfo = AAS_EntityInfo;\n\t//--------------------------------------------\n\t// be_aas_main.c\n\t//--------------------------------------------\n\taas->AAS_Initialized = AAS_Initialized;\n\taas->AAS_PresenceTypeBoundingBox = AAS_PresenceTypeBoundingBox;\n\taas->AAS_Time = AAS_Time;\n\t//--------------------------------------------\n\t// be_aas_sample.c\n\t//--------------------------------------------\n\taas->AAS_PointAreaNum = AAS_PointAreaNum;\n\taas->AAS_PointReachabilityAreaIndex = AAS_PointReachabilityAreaIndex;\n\taas->AAS_TraceAreas = AAS_TraceAreas;\n\taas->AAS_BBoxAreas = AAS_BBoxAreas;\n\taas->AAS_AreaInfo = AAS_AreaInfo;\n\t//--------------------------------------------\n\t// be_aas_bspq3.c\n\t//--------------------------------------------\n\taas->AAS_PointContents = AAS_PointContents;\n\taas->AAS_NextBSPEntity = AAS_NextBSPEntity;\n\taas->AAS_ValueForBSPEpairKey = AAS_ValueForBSPEpairKey;\n\taas->AAS_VectorForBSPEpairKey = AAS_VectorForBSPEpairKey;\n\taas->AAS_FloatForBSPEpairKey = AAS_FloatForBSPEpairKey;\n\taas->AAS_IntForBSPEpairKey = AAS_IntForBSPEpairKey;\n\t//--------------------------------------------\n\t// be_aas_reach.c\n\t//--------------------------------------------\n\taas->AAS_AreaReachability = AAS_AreaReachability;\n\t//--------------------------------------------\n\t// be_aas_route.c\n\t//--------------------------------------------\n\taas->AAS_AreaTravelTimeToGoalArea = AAS_AreaTravelTimeToGoalArea;\n\taas->AAS_EnableRoutingArea = AAS_EnableRoutingArea;\n\taas->AAS_PredictRoute = AAS_PredictRoute;\n\t//--------------------------------------------\n\t// be_aas_altroute.c\n\t//--------------------------------------------\n\taas->AAS_AlternativeRouteGoals = AAS_AlternativeRouteGoals;\n\t//--------------------------------------------\n\t// be_aas_move.c\n\t//--------------------------------------------\n\taas->AAS_Swimming = AAS_Swimming;\n\taas->AAS_PredictClientMovement = AAS_PredictClientMovement;\n}\n\n  \n/*\n============\nInit_EA_Export\n============\n*/\nstatic void Init_EA_Export( ea_export_t *ea ) {\n\t//ClientCommand elementary actions\n\tea->EA_Command = EA_Command;\n\tea->EA_Say = EA_Say;\n\tea->EA_SayTeam = EA_SayTeam;\n\n\tea->EA_Action = EA_Action;\n\tea->EA_Gesture = EA_Gesture;\n\tea->EA_Talk = EA_Talk;\n\tea->EA_Attack = EA_Attack;\n\tea->EA_Use = EA_Use;\n\tea->EA_Respawn = EA_Respawn;\n\tea->EA_Crouch = EA_Crouch;\n\tea->EA_MoveUp = EA_MoveUp;\n\tea->EA_MoveDown = EA_MoveDown;\n\tea->EA_MoveForward = EA_MoveForward;\n\tea->EA_MoveBack = EA_MoveBack;\n\tea->EA_MoveLeft = EA_MoveLeft;\n\tea->EA_MoveRight = EA_MoveRight;\n\n\tea->EA_SelectWeapon = EA_SelectWeapon;\n\tea->EA_Jump = EA_Jump;\n\tea->EA_DelayedJump = EA_DelayedJump;\n\tea->EA_Move = EA_Move;\n\tea->EA_View = EA_View;\n\tea->EA_GetInput = EA_GetInput;\n\tea->EA_EndRegular = EA_EndRegular;\n\tea->EA_ResetInput = EA_ResetInput;\n}\n\n\n/*\n============\nInit_AI_Export\n============\n*/\nstatic void Init_AI_Export( ai_export_t *ai ) {\n\t//-----------------------------------\n\t// be_ai_char.h\n\t//-----------------------------------\n\tai->BotLoadCharacter = BotLoadCharacter;\n\tai->BotFreeCharacter = BotFreeCharacter;\n\tai->Characteristic_Float = Characteristic_Float;\n\tai->Characteristic_BFloat = Characteristic_BFloat;\n\tai->Characteristic_Integer = Characteristic_Integer;\n\tai->Characteristic_BInteger = Characteristic_BInteger;\n\tai->Characteristic_String = Characteristic_String;\n\t//-----------------------------------\n\t// be_ai_chat.h\n\t//-----------------------------------\n\tai->BotAllocChatState = BotAllocChatState;\n\tai->BotFreeChatState = BotFreeChatState;\n\tai->BotQueueConsoleMessage = BotQueueConsoleMessage;\n\tai->BotRemoveConsoleMessage = BotRemoveConsoleMessage;\n\tai->BotNextConsoleMessage = BotNextConsoleMessage;\n\tai->BotNumConsoleMessages = BotNumConsoleMessages;\n\tai->BotInitialChat = BotInitialChat;\n\tai->BotNumInitialChats = BotNumInitialChats;\n\tai->BotReplyChat = BotReplyChat;\n\tai->BotChatLength = BotChatLength;\n\tai->BotEnterChat = BotEnterChat;\n\tai->BotGetChatMessage = BotGetChatMessage;\n\tai->StringContains = StringContains;\n\tai->BotFindMatch = BotFindMatch;\n\tai->BotMatchVariable = BotMatchVariable;\n\tai->UnifyWhiteSpaces = UnifyWhiteSpaces;\n\tai->BotReplaceSynonyms = BotReplaceSynonyms;\n\tai->BotLoadChatFile = BotLoadChatFile;\n\tai->BotSetChatGender = BotSetChatGender;\n\tai->BotSetChatName = BotSetChatName;\n\t//-----------------------------------\n\t// be_ai_goal.h\n\t//-----------------------------------\n\tai->BotResetGoalState = BotResetGoalState;\n\tai->BotResetAvoidGoals = BotResetAvoidGoals;\n\tai->BotRemoveFromAvoidGoals = BotRemoveFromAvoidGoals;\n\tai->BotPushGoal = BotPushGoal;\n\tai->BotPopGoal = BotPopGoal;\n\tai->BotEmptyGoalStack = BotEmptyGoalStack;\n\tai->BotDumpAvoidGoals = BotDumpAvoidGoals;\n\tai->BotDumpGoalStack = BotDumpGoalStack;\n\tai->BotGoalName = BotGoalName;\n\tai->BotGetTopGoal = BotGetTopGoal;\n\tai->BotGetSecondGoal = BotGetSecondGoal;\n\tai->BotChooseLTGItem = BotChooseLTGItem;\n\tai->BotChooseNBGItem = BotChooseNBGItem;\n\tai->BotTouchingGoal = BotTouchingGoal;\n\tai->BotItemGoalInVisButNotVisible = BotItemGoalInVisButNotVisible;\n\tai->BotGetLevelItemGoal = BotGetLevelItemGoal;\n\tai->BotGetNextCampSpotGoal = BotGetNextCampSpotGoal;\n\tai->BotGetMapLocationGoal = BotGetMapLocationGoal;\n\tai->BotAvoidGoalTime = BotAvoidGoalTime;\n\tai->BotSetAvoidGoalTime = BotSetAvoidGoalTime;\n\tai->BotInitLevelItems = BotInitLevelItems;\n\tai->BotUpdateEntityItems = BotUpdateEntityItems;\n\tai->BotLoadItemWeights = BotLoadItemWeights;\n\tai->BotFreeItemWeights = BotFreeItemWeights;\n\tai->BotInterbreedGoalFuzzyLogic = BotInterbreedGoalFuzzyLogic;\n\tai->BotSaveGoalFuzzyLogic = BotSaveGoalFuzzyLogic;\n\tai->BotMutateGoalFuzzyLogic = BotMutateGoalFuzzyLogic;\n\tai->BotAllocGoalState = BotAllocGoalState;\n\tai->BotFreeGoalState = BotFreeGoalState;\n\t//-----------------------------------\n\t// be_ai_move.h\n\t//-----------------------------------\n\tai->BotResetMoveState = BotResetMoveState;\n\tai->BotMoveToGoal = BotMoveToGoal;\n\tai->BotMoveInDirection = BotMoveInDirection;\n\tai->BotResetAvoidReach = BotResetAvoidReach;\n\tai->BotResetLastAvoidReach = BotResetLastAvoidReach;\n\tai->BotReachabilityArea = BotReachabilityArea;\n\tai->BotMovementViewTarget = BotMovementViewTarget;\n\tai->BotPredictVisiblePosition = BotPredictVisiblePosition;\n\tai->BotAllocMoveState = BotAllocMoveState;\n\tai->BotFreeMoveState = BotFreeMoveState;\n\tai->BotInitMoveState = BotInitMoveState;\n\tai->BotAddAvoidSpot = BotAddAvoidSpot;\n\t//-----------------------------------\n\t// be_ai_weap.h\n\t//-----------------------------------\n\tai->BotChooseBestFightWeapon = BotChooseBestFightWeapon;\n\tai->BotGetWeaponInfo = BotGetWeaponInfo;\n\tai->BotLoadWeaponWeights = BotLoadWeaponWeights;\n\tai->BotAllocWeaponState = BotAllocWeaponState;\n\tai->BotFreeWeaponState = BotFreeWeaponState;\n\tai->BotResetWeaponState = BotResetWeaponState;\n\t//-----------------------------------\n\t// be_ai_gen.h\n\t//-----------------------------------\n\tai->GeneticParentsAndChildSelection = GeneticParentsAndChildSelection;\n}\n\n\n/*\n============\nGetBotLibAPI\n============\n*/\nbotlib_export_t *GetBotLibAPI(int apiVersion, botlib_import_t *import) {\n\tassert(import);   // bk001129 - this wasn't set for baseq3/\n  botimport = *import;\n  assert(botimport.Print);   // bk001129 - pars pro toto\n\n\tCom_Memset( &be_botlib_export, 0, sizeof( be_botlib_export ) );\n\n\tif ( apiVersion != BOTLIB_API_VERSION ) {\n\t\tbotimport.Print( PRT_ERROR, \"Mismatched BOTLIB_API_VERSION: expected %i, got %i\\n\", BOTLIB_API_VERSION, apiVersion );\n\t\treturn NULL;\n\t}\n\n\tInit_AAS_Export(&be_botlib_export.aas);\n\tInit_EA_Export(&be_botlib_export.ea);\n\tInit_AI_Export(&be_botlib_export.ai);\n\n\tbe_botlib_export.BotLibSetup = Export_BotLibSetup;\n\tbe_botlib_export.BotLibShutdown = Export_BotLibShutdown;\n\tbe_botlib_export.BotLibVarSet = Export_BotLibVarSet;\n\tbe_botlib_export.BotLibVarGet = Export_BotLibVarGet;\n\n\tbe_botlib_export.PC_AddGlobalDefine = PC_AddGlobalDefine;\n\tbe_botlib_export.PC_LoadSourceHandle = PC_LoadSourceHandle;\n\tbe_botlib_export.PC_FreeSourceHandle = PC_FreeSourceHandle;\n\tbe_botlib_export.PC_ReadTokenHandle = PC_ReadTokenHandle;\n\tbe_botlib_export.PC_SourceFileAndLine = PC_SourceFileAndLine;\n\n\tbe_botlib_export.BotLibStartFrame = Export_BotLibStartFrame;\n\tbe_botlib_export.BotLibLoadMap = Export_BotLibLoadMap;\n\tbe_botlib_export.BotLibUpdateEntity = Export_BotLibUpdateEntity;\n\tbe_botlib_export.Test = BotExportTest;\n\n\treturn &be_botlib_export;\n}\n"
  },
  {
    "path": "src/engine/botlib/be_interface.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tbe_interface.h\n *\n * desc:\t\tbotlib interface\n *\n * $Archive: /source/code/botlib/be_interface.h $\n *\n *****************************************************************************/\n\n//#define DEBUG\t\t\t//debug code\n#define RANDOMIZE\t\t//randomize bot behaviour\n\n//FIXME: get rid of this global structure\ntypedef struct botlib_globals_s\n{\n\tint botlibsetup;\t\t\t\t\t\t//true when the bot library has been setup\n\tint maxentities;\t\t\t\t\t\t//maximum number of entities\n\tint maxclients;\t\t\t\t\t\t\t//maximum number of clients\n\tfloat time;\t\t\t\t\t\t\t\t//the global time\n#ifdef DEBUG\n\tqboolean debug;\t\t\t\t\t\t\t//true if debug is on\n\tint goalareanum;\n\tvec3_t goalorigin;\n\tint runai;\n#endif\n} botlib_globals_t;\n\n\nextern botlib_globals_t botlibglobals;\nextern botlib_import_t botimport;\nextern int bot_developer;\t\t\t\t\t//true if developer is on\n\n//\nint Sys_MilliSeconds(void);\n\n"
  },
  {
    "path": "src/engine/botlib/l_crc.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tl_crc.c\n *\n * desc:\t\tCRC calculation\n *\n * $Archive: /MissionPack/CODE/botlib/l_crc.c $\n *\n *****************************************************************************/\n\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n\n#include \"../../game/q_shared.h\"\n#include \"../../game/botlib.h\"\n#include \"be_interface.h\"\t\t\t//for botimport.Print\n\n\n// FIXME: byte swap?\n\n// this is a 16 bit, non-reflected CRC using the polynomial 0x1021\n// and the initial and final xor values shown below...  in other words, the\n// CCITT standard CRC used by XMODEM\n\n#define CRC_INIT_VALUE\t0xffff\n#define CRC_XOR_VALUE\t0x0000\n\nunsigned short crctable[257] =\n{\n\t0x0000,\t0x1021,\t0x2042,\t0x3063,\t0x4084,\t0x50a5,\t0x60c6,\t0x70e7,\n\t0x8108,\t0x9129,\t0xa14a,\t0xb16b,\t0xc18c,\t0xd1ad,\t0xe1ce,\t0xf1ef,\n\t0x1231,\t0x0210,\t0x3273,\t0x2252,\t0x52b5,\t0x4294,\t0x72f7,\t0x62d6,\n\t0x9339,\t0x8318,\t0xb37b,\t0xa35a,\t0xd3bd,\t0xc39c,\t0xf3ff,\t0xe3de,\n\t0x2462,\t0x3443,\t0x0420,\t0x1401,\t0x64e6,\t0x74c7,\t0x44a4,\t0x5485,\n\t0xa56a,\t0xb54b,\t0x8528,\t0x9509,\t0xe5ee,\t0xf5cf,\t0xc5ac,\t0xd58d,\n\t0x3653,\t0x2672,\t0x1611,\t0x0630,\t0x76d7,\t0x66f6,\t0x5695,\t0x46b4,\n\t0xb75b,\t0xa77a,\t0x9719,\t0x8738,\t0xf7df,\t0xe7fe,\t0xd79d,\t0xc7bc,\n\t0x48c4,\t0x58e5,\t0x6886,\t0x78a7,\t0x0840,\t0x1861,\t0x2802,\t0x3823,\n\t0xc9cc,\t0xd9ed,\t0xe98e,\t0xf9af,\t0x8948,\t0x9969,\t0xa90a,\t0xb92b,\n\t0x5af5,\t0x4ad4,\t0x7ab7,\t0x6a96,\t0x1a71,\t0x0a50,\t0x3a33,\t0x2a12,\n\t0xdbfd,\t0xcbdc,\t0xfbbf,\t0xeb9e,\t0x9b79,\t0x8b58,\t0xbb3b,\t0xab1a,\n\t0x6ca6,\t0x7c87,\t0x4ce4,\t0x5cc5,\t0x2c22,\t0x3c03,\t0x0c60,\t0x1c41,\n\t0xedae,\t0xfd8f,\t0xcdec,\t0xddcd,\t0xad2a,\t0xbd0b,\t0x8d68,\t0x9d49,\n\t0x7e97,\t0x6eb6,\t0x5ed5,\t0x4ef4,\t0x3e13,\t0x2e32,\t0x1e51,\t0x0e70,\n\t0xff9f,\t0xefbe,\t0xdfdd,\t0xcffc,\t0xbf1b,\t0xaf3a,\t0x9f59,\t0x8f78,\n\t0x9188,\t0x81a9,\t0xb1ca,\t0xa1eb,\t0xd10c,\t0xc12d,\t0xf14e,\t0xe16f,\n\t0x1080,\t0x00a1,\t0x30c2,\t0x20e3,\t0x5004,\t0x4025,\t0x7046,\t0x6067,\n\t0x83b9,\t0x9398,\t0xa3fb,\t0xb3da,\t0xc33d,\t0xd31c,\t0xe37f,\t0xf35e,\n\t0x02b1,\t0x1290,\t0x22f3,\t0x32d2,\t0x4235,\t0x5214,\t0x6277,\t0x7256,\n\t0xb5ea,\t0xa5cb,\t0x95a8,\t0x8589,\t0xf56e,\t0xe54f,\t0xd52c,\t0xc50d,\n\t0x34e2,\t0x24c3,\t0x14a0,\t0x0481,\t0x7466,\t0x6447,\t0x5424,\t0x4405,\n\t0xa7db,\t0xb7fa,\t0x8799,\t0x97b8,\t0xe75f,\t0xf77e,\t0xc71d,\t0xd73c,\n\t0x26d3,\t0x36f2,\t0x0691,\t0x16b0,\t0x6657,\t0x7676,\t0x4615,\t0x5634,\n\t0xd94c,\t0xc96d,\t0xf90e,\t0xe92f,\t0x99c8,\t0x89e9,\t0xb98a,\t0xa9ab,\n\t0x5844,\t0x4865,\t0x7806,\t0x6827,\t0x18c0,\t0x08e1,\t0x3882,\t0x28a3,\n\t0xcb7d,\t0xdb5c,\t0xeb3f,\t0xfb1e,\t0x8bf9,\t0x9bd8,\t0xabbb,\t0xbb9a,\n\t0x4a75,\t0x5a54,\t0x6a37,\t0x7a16,\t0x0af1,\t0x1ad0,\t0x2ab3,\t0x3a92,\n\t0xfd2e,\t0xed0f,\t0xdd6c,\t0xcd4d,\t0xbdaa,\t0xad8b,\t0x9de8,\t0x8dc9,\n\t0x7c26,\t0x6c07,\t0x5c64,\t0x4c45,\t0x3ca2,\t0x2c83,\t0x1ce0,\t0x0cc1,\n\t0xef1f,\t0xff3e,\t0xcf5d,\t0xdf7c,\t0xaf9b,\t0xbfba,\t0x8fd9,\t0x9ff8,\n\t0x6e17,\t0x7e36,\t0x4e55,\t0x5e74,\t0x2e93,\t0x3eb2,\t0x0ed1,\t0x1ef0\n};\n\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid CRC_Init(unsigned short *crcvalue)\n{\n\t*crcvalue = CRC_INIT_VALUE;\n} //end of the function CRC_Init\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid CRC_ProcessByte(unsigned short *crcvalue, byte data)\n{\n\t*crcvalue = (*crcvalue << 8) ^ crctable[(*crcvalue >> 8) ^ data];\n} //end of the function CRC_ProcessByte\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nunsigned short CRC_Value(unsigned short crcvalue)\n{\n\treturn crcvalue ^ CRC_XOR_VALUE;\n} //end of the function CRC_Value\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nunsigned short CRC_ProcessString(unsigned char *data, int length)\n{\n\tunsigned short crcvalue;\n\tint i, ind;\n\n\tCRC_Init(&crcvalue);\n\n\tfor (i = 0; i < length; i++)\n\t{\n\t\tind = (crcvalue >> 8) ^ data[i];\n\t\tif (ind < 0 || ind > 256) ind = 0;\n\t\tcrcvalue = (crcvalue << 8) ^ crctable[ind];\n\t} //end for\n\treturn CRC_Value(crcvalue);\n} //end of the function CRC_ProcessString\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid CRC_ContinueProcessString(unsigned short *crc, char *data, int length)\n{\n\tint i;\n\n\tfor (i = 0; i < length; i++)\n\t{\n\t\t*crc = (*crc << 8) ^ crctable[(*crc >> 8) ^ data[i]];\n\t} //end for\n} //end of the function CRC_ProcessString\n"
  },
  {
    "path": "src/engine/botlib/l_crc.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\ntypedef unsigned short crc_t;\n\nvoid CRC_Init(unsigned short *crcvalue);\nvoid CRC_ProcessByte(unsigned short *crcvalue, byte data);\nunsigned short CRC_Value(unsigned short crcvalue);\nunsigned short CRC_ProcessString(unsigned char *data, int length);\nvoid CRC_ContinueProcessString(unsigned short *crc, char *data, int length);\n"
  },
  {
    "path": "src/engine/botlib/l_libvar.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tl_libvar.c\n *\n * desc:\t\tbot library variables\n *\n * $Archive: /MissionPack/code/botlib/l_libvar.c $\n *\n *****************************************************************************/\n\n#include \"../../game/q_shared.h\"\n#include \"l_memory.h\"\n#include \"l_libvar.h\"\n\n//list with library variables\nlibvar_t *libvarlist;\n\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nfloat LibVarStringValue(char *string)\n{\n\tint dotfound = 0;\n\tfloat value = 0;\n\n\twhile(*string)\n\t{\n\t\tif (*string < '0' || *string > '9')\n\t\t{\n\t\t\tif (dotfound || *string != '.')\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t} //end if\n\t\t\telse\n\t\t\t{\n\t\t\t\tdotfound = 10;\n\t\t\t\tstring++;\n\t\t\t} //end if\n\t\t} //end if\n\t\tif (dotfound)\n\t\t{\n\t\t\tvalue = value + (float) (*string - '0') / (float) dotfound;\n\t\t\tdotfound *= 10;\n\t\t} //end if\n\t\telse\n\t\t{\n\t\t\tvalue = value * 10.0 + (float) (*string - '0');\n\t\t} //end else\n\t\tstring++;\n\t} //end while\n\treturn value;\n} //end of the function LibVarStringValue\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nlibvar_t *LibVarAlloc(char *var_name)\n{\n\tlibvar_t *v;\n\n\tv = (libvar_t *) GetMemory(sizeof(libvar_t) + (int)strlen(var_name) + 1);\n\tCom_Memset(v, 0, sizeof(libvar_t));\n\tv->name = (char *) v + sizeof(libvar_t);\n\tstrcpy(v->name, var_name);\n\t//add the variable in the list\n\tv->next = libvarlist;\n\tlibvarlist = v;\n\treturn v;\n} //end of the function LibVarAlloc\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid LibVarDeAlloc(libvar_t *v)\n{\n\tif (v->string) FreeMemory(v->string);\n\tFreeMemory(v);\n} //end of the function LibVarDeAlloc\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid LibVarDeAllocAll(void)\n{\n\tlibvar_t *v;\n\n\tfor (v = libvarlist; v; v = libvarlist)\n\t{\n\t\tlibvarlist = libvarlist->next;\n\t\tLibVarDeAlloc(v);\n\t} //end for\n\tlibvarlist = NULL;\n} //end of the function LibVarDeAllocAll\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nlibvar_t *LibVarGet(char *var_name)\n{\n\tlibvar_t *v;\n\n\tfor (v = libvarlist; v; v = v->next)\n\t{\n\t\tif (!Q_stricmp(v->name, var_name))\n\t\t{\n\t\t\treturn v;\n\t\t} //end if\n\t} //end for\n\treturn NULL;\n} //end of the function LibVarGet\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nchar *LibVarGetString(char *var_name)\n{\n\tlibvar_t *v;\n\n\tv = LibVarGet(var_name);\n\tif (v)\n\t{\n\t\treturn v->string;\n\t} //end if\n\telse\n\t{\n\t\treturn \"\";\n\t} //end else\n} //end of the function LibVarGetString\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nfloat LibVarGetValue(char *var_name)\n{\n\tlibvar_t *v;\n\n\tv = LibVarGet(var_name);\n\tif (v)\n\t{\n\t\treturn v->value;\n\t} //end if\n\telse\n\t{\n\t\treturn 0;\n\t} //end else\n} //end of the function LibVarGetValue\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nlibvar_t *LibVar(char *var_name, char *value)\n{\n\tlibvar_t *v;\n\tv = LibVarGet(var_name);\n\tif (v) return v;\n\t//create new variable\n\tv = LibVarAlloc(var_name);\n\t//variable string\n\tv->string = (char *) GetMemory((int)strlen(value) + 1);\n\tstrcpy(v->string, value);\n\t//the value\n\tv->value = LibVarStringValue(v->string);\n\t//variable is modified\n\tv->modified = qtrue;\n\t//\n\treturn v;\n} //end of the function LibVar\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nchar *LibVarString(char *var_name, char *value)\n{\n\tlibvar_t *v;\n\n\tv = LibVar(var_name, value);\n\treturn v->string;\n} //end of the function LibVarString\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nfloat LibVarValue(char *var_name, char *value)\n{\n\tlibvar_t *v;\n\n\tv = LibVar(var_name, value);\n\treturn v->value;\n} //end of the function LibVarValue\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid LibVarSet(char *var_name, char *value)\n{\n\tlibvar_t *v;\n\n\tv = LibVarGet(var_name);\n\tif (v)\n\t{\n\t\tFreeMemory(v->string);\n\t} //end if\n\telse\n\t{\n\t\tv = LibVarAlloc(var_name);\n\t} //end else\n\t//variable string\n\tv->string = (char *) GetMemory((int)strlen(value) + 1);\n\tstrcpy(v->string, value);\n\t//the value\n\tv->value = LibVarStringValue(v->string);\n\t//variable is modified\n\tv->modified = qtrue;\n} //end of the function LibVarSet\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nqboolean LibVarChanged(char *var_name)\n{\n\tlibvar_t *v;\n\n\tv = LibVarGet(var_name);\n\tif (v)\n\t{\n\t\treturn v->modified;\n\t} //end if\n\telse\n\t{\n\t\treturn qfalse;\n\t} //end else\n} //end of the function LibVarChanged\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid LibVarSetNotModified(char *var_name)\n{\n\tlibvar_t *v;\n\n\tv = LibVarGet(var_name);\n\tif (v)\n\t{\n\t\tv->modified = qfalse;\n\t} //end if\n} //end of the function LibVarSetNotModified\n"
  },
  {
    "path": "src/engine/botlib/l_libvar.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tl_libvar.h\n *\n * desc:\t\tbotlib vars\n *\n * $Archive: /source/code/botlib/l_libvar.h $\n *\n *****************************************************************************/\n\n//library variable\ntypedef struct libvar_s\n{\n\tchar\t\t*name;\n\tchar\t\t*string;\n\tint\t\tflags;\n\tqboolean\tmodified;\t// set each time the cvar is changed\n\tfloat\t\tvalue;\n\tstruct\tlibvar_s *next;\n} libvar_t;\n\n//removes all library variables\nvoid LibVarDeAllocAll(void);\n//gets the library variable with the given name\nlibvar_t *LibVarGet(char *var_name);\n//gets the string of the library variable with the given name\nchar *LibVarGetString(char *var_name);\n//gets the value of the library variable with the given name\nfloat LibVarGetValue(char *var_name);\n//creates the library variable if not existing already and returns it\nlibvar_t *LibVar(char *var_name, char *value);\n//creates the library variable if not existing already and returns the value\nfloat LibVarValue(char *var_name, char *value);\n//creates the library variable if not existing already and returns the value string\nchar *LibVarString(char *var_name, char *value);\n//sets the library variable\nvoid LibVarSet(char *var_name, char *value);\n//returns true if the library variable has been modified\nqboolean LibVarChanged(char *var_name);\n//sets the library variable to unmodified\nvoid LibVarSetNotModified(char *var_name);\n\n"
  },
  {
    "path": "src/engine/botlib/l_log.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tl_log.c\n *\n * desc:\t\tlog file\n *\n * $Archive: /MissionPack/CODE/botlib/l_log.c $\n *\n *****************************************************************************/\n\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n\n#include \"../../game/q_shared.h\"\n#include \"../../game/botlib.h\"\n#include \"be_interface.h\"\t\t\t//for botimport.Print\n#include \"l_libvar.h\"\n\n#define MAX_LOGFILENAMESIZE\t\t1024\n\ntypedef struct logfile_s\n{\n\tchar filename[MAX_LOGFILENAMESIZE];\n\tFILE *fp;\n\tint numwrites;\n} logfile_t;\n\nstatic logfile_t logfile;\n\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid Log_Open(char *filename)\n{\n\tif (!LibVarValue(\"log\", \"0\")) return;\n\tif (!filename || !strlen(filename))\n\t{\n\t\tbotimport.Print(PRT_MESSAGE, \"openlog <filename>\\n\");\n\t\treturn;\n\t} //end if\n\tif (logfile.fp)\n\t{\n\t\tbotimport.Print(PRT_ERROR, \"log file %s is already opened\\n\", logfile.filename);\n\t\treturn;\n\t} //end if\n\tlogfile.fp = fopen(filename, \"wb\");\n\tif (!logfile.fp)\n\t{\n\t\tbotimport.Print(PRT_ERROR, \"can't open the log file %s\\n\", filename);\n\t\treturn;\n\t} //end if\n\tstrncpy(logfile.filename, filename, MAX_LOGFILENAMESIZE);\n\tbotimport.Print(PRT_MESSAGE, \"Opened log %s\\n\", logfile.filename);\n} //end of the function Log_Create\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid Log_Close(void)\n{\n\tif (!logfile.fp) return;\n\tif (fclose(logfile.fp))\n\t{\n\t\tbotimport.Print(PRT_ERROR, \"can't close log file %s\\n\", logfile.filename);\n\t\treturn;\n\t} //end if\n\tlogfile.fp = NULL;\n\tbotimport.Print(PRT_MESSAGE, \"Closed log %s\\n\", logfile.filename);\n} //end of the function Log_Close\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid Log_Shutdown(void)\n{\n\tif (logfile.fp) Log_Close();\n} //end of the function Log_Shutdown\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid QDECL Log_Write(char *fmt, ...)\n{\n\tva_list ap;\n\n\tif (!logfile.fp) return;\n\tva_start(ap, fmt);\n\tvfprintf(logfile.fp, fmt, ap);\n\tva_end(ap);\n\t//fprintf(logfile.fp, \"\\r\\n\");\n\tfflush(logfile.fp);\n} //end of the function Log_Write\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid QDECL Log_WriteTimeStamped(char *fmt, ...)\n{\n\tva_list ap;\n\n\tif (!logfile.fp) return;\n\tfprintf(logfile.fp, \"%d   %02d:%02d:%02d:%02d   \",\n\t\t\t\t\tlogfile.numwrites,\n\t\t\t\t\t(int) (botlibglobals.time / 60 / 60),\n\t\t\t\t\t(int) (botlibglobals.time / 60),\n\t\t\t\t\t(int) (botlibglobals.time),\n\t\t\t\t\t(int) ((int) (botlibglobals.time * 100)) -\n\t\t\t\t\t\t\t((int) botlibglobals.time) * 100);\n\tva_start(ap, fmt);\n\tvfprintf(logfile.fp, fmt, ap);\n\tva_end(ap);\n\tfprintf(logfile.fp, \"\\r\\n\");\n\tlogfile.numwrites++;\n\tfflush(logfile.fp);\n} //end of the function Log_Write\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nFILE *Log_FilePointer(void)\n{\n\treturn logfile.fp;\n} //end of the function Log_FilePointer\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid Log_Flush(void)\n{\n\tif (logfile.fp) fflush(logfile.fp);\n} //end of the function Log_Flush\n\n"
  },
  {
    "path": "src/engine/botlib/l_log.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tl_log.h\n *\n * desc:\t\tlog file\n *\n * $Archive: /source/code/botlib/l_log.h $\n *\n *****************************************************************************/\n\n//open a log file\nvoid Log_Open(char *filename);\n//close the current log file\nvoid Log_Close(void);\n//close log file if present\nvoid Log_Shutdown(void);\n//write to the current opened log file\nvoid QDECL Log_Write(char *fmt, ...);\n//write to the current opened log file with a time stamp\nvoid QDECL Log_WriteTimeStamped(char *fmt, ...);\n//returns a pointer to the log file\nFILE *Log_FilePointer(void);\n//flush log file\nvoid Log_Flush(void);\n\n"
  },
  {
    "path": "src/engine/botlib/l_memory.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tl_memory.c\n *\n * desc:\t\tmemory allocation\n *\n * $Archive: /MissionPack/code/botlib/l_memory.c $\n *\n *****************************************************************************/\n\n#include \"../../game/q_shared.h\"\n#include \"../../game/botlib.h\"\n#include \"l_log.h\"\n#include \"be_interface.h\"\n\n//#define MEMDEBUG\n//#define MEMORYMANEGER\n\n#define MEM_ID\t\t0x12345678l\n#define HUNK_ID\t\t0x87654321l\n\nint allocatedmemory;\nint totalmemorysize;\nint numblocks;\n\n#ifdef MEMORYMANEGER\n\ntypedef struct memoryblock_s\n{\n\tunsigned long int id;\n\tvoid *ptr;\n\tint size;\n#ifdef MEMDEBUG\n\tchar *label;\n\tchar *file;\n\tint line;\n#endif //MEMDEBUG\n\tstruct memoryblock_s *prev, *next;\n} memoryblock_t;\n\nmemoryblock_t *memory;\n\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid LinkMemoryBlock(memoryblock_t *block)\n{\n\tblock->prev = NULL;\n\tblock->next = memory;\n\tif (memory) memory->prev = block;\n\tmemory = block;\n} //end of the function LinkMemoryBlock\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid UnlinkMemoryBlock(memoryblock_t *block)\n{\n\tif (block->prev) block->prev->next = block->next;\n\telse memory = block->next;\n\tif (block->next) block->next->prev = block->prev;\n} //end of the function UnlinkMemoryBlock\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\n#ifdef MEMDEBUG\nvoid *GetMemoryDebug(unsigned long size, char *label, char *file, int line)\n#else\nvoid *GetMemory(unsigned long size)\n#endif //MEMDEBUG\n{\n\tvoid *ptr;\n\tmemoryblock_t *block;\n  assert(botimport.GetMemory); // bk001129 - was NULL'ed\n\tptr = botimport.GetMemory(size + sizeof(memoryblock_t));\n\tblock = (memoryblock_t *) ptr;\n\tblock->id = MEM_ID;\n\tblock->ptr = (char *) ptr + sizeof(memoryblock_t);\n\tblock->size = size + sizeof(memoryblock_t);\n#ifdef MEMDEBUG\n\tblock->label = label;\n\tblock->file = file;\n\tblock->line = line;\n#endif //MEMDEBUG\n\tLinkMemoryBlock(block);\n\tallocatedmemory += block->size;\n\ttotalmemorysize += block->size + sizeof(memoryblock_t);\n\tnumblocks++;\n\treturn block->ptr;\n} //end of the function GetMemoryDebug\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\n#ifdef MEMDEBUG\nvoid *GetClearedMemoryDebug(unsigned long size, char *label, char *file, int line)\n#else\nvoid *GetClearedMemory(unsigned long size)\n#endif //MEMDEBUG\n{\n\tvoid *ptr;\n#ifdef MEMDEBUG\n\tptr = GetMemoryDebug(size, label, file, line);\n#else\n\tptr = GetMemory(size);\n#endif //MEMDEBUG\n\tCom_Memset(ptr, 0, size);\n\treturn ptr;\n} //end of the function GetClearedMemory\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\n#ifdef MEMDEBUG\nvoid *GetHunkMemoryDebug(unsigned long size, char *label, char *file, int line)\n#else\nvoid *GetHunkMemory(unsigned long size)\n#endif //MEMDEBUG\n{\n\tvoid *ptr;\n\tmemoryblock_t *block;\n\n\tptr = botimport.HunkAlloc(size + sizeof(memoryblock_t));\n\tblock = (memoryblock_t *) ptr;\n\tblock->id = HUNK_ID;\n\tblock->ptr = (char *) ptr + sizeof(memoryblock_t);\n\tblock->size = size + sizeof(memoryblock_t);\n#ifdef MEMDEBUG\n\tblock->label = label;\n\tblock->file = file;\n\tblock->line = line;\n#endif //MEMDEBUG\n\tLinkMemoryBlock(block);\n\tallocatedmemory += block->size;\n\ttotalmemorysize += block->size + sizeof(memoryblock_t);\n\tnumblocks++;\n\treturn block->ptr;\n} //end of the function GetHunkMemoryDebug\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\n#ifdef MEMDEBUG\nvoid *GetClearedHunkMemoryDebug(unsigned long size, char *label, char *file, int line)\n#else\nvoid *GetClearedHunkMemory(unsigned long size)\n#endif //MEMDEBUG\n{\n\tvoid *ptr;\n#ifdef MEMDEBUG\n\tptr = GetHunkMemoryDebug(size, label, file, line);\n#else\n\tptr = GetHunkMemory(size);\n#endif //MEMDEBUG\n\tCom_Memset(ptr, 0, size);\n\treturn ptr;\n} //end of the function GetClearedHunkMemory\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nmemoryblock_t *BlockFromPointer(void *ptr, char *str)\n{\n\tmemoryblock_t *block;\n\n\tif (!ptr)\n\t{\n#ifdef MEMDEBUG\n\t\t//char *crash = (char *) NULL;\n\t\t//crash[0] = 1;\n\t\tbotimport.Print(PRT_FATAL, \"%s: NULL pointer\\n\", str);\n#endif // MEMDEBUG\n\t\treturn NULL;\n\t} //end if\n\tblock = (memoryblock_t *) ((char *) ptr - sizeof(memoryblock_t));\n\tif (block->id != MEM_ID && block->id != HUNK_ID)\n\t{\n\t\tbotimport.Print(PRT_FATAL, \"%s: invalid memory block\\n\", str);\n\t\treturn NULL;\n\t} //end if\n\tif (block->ptr != ptr)\n\t{\n\t\tbotimport.Print(PRT_FATAL, \"%s: memory block pointer invalid\\n\", str);\n\t\treturn NULL;\n\t} //end if\n\treturn block;\n} //end of the function BlockFromPointer\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid FreeMemory(void *ptr)\n{\n\tmemoryblock_t *block;\n\n\tblock = BlockFromPointer(ptr, \"FreeMemory\");\n\tif (!block) return;\n\tUnlinkMemoryBlock(block);\n\tallocatedmemory -= block->size;\n\ttotalmemorysize -= block->size + sizeof(memoryblock_t);\n\tnumblocks--;\n\t//\n\tif (block->id == MEM_ID)\n\t{\n\t\tbotimport.FreeMemory(block);\n\t} //end if\n} //end of the function FreeMemory\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AvailableMemory(void)\n{\n\treturn botimport.AvailableMemory();\n} //end of the function AvailableMemory\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint MemoryByteSize(void *ptr)\n{\n\tmemoryblock_t *block;\n\n\tblock = BlockFromPointer(ptr, \"MemoryByteSize\");\n\tif (!block) return 0;\n\treturn block->size;\n} //end of the function MemoryByteSize\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid PrintUsedMemorySize(void)\n{\n\tbotimport.Print(PRT_MESSAGE, \"total allocated memory: %d KB\\n\", allocatedmemory >> 10);\n\tbotimport.Print(PRT_MESSAGE, \"total botlib memory: %d KB\\n\", totalmemorysize >> 10);\n\tbotimport.Print(PRT_MESSAGE, \"total memory blocks: %d\\n\", numblocks);\n} //end of the function PrintUsedMemorySize\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid PrintMemoryLabels(void)\n{\n\tmemoryblock_t *block;\n\tint i;\n\n\tPrintUsedMemorySize();\n\ti = 0;\n\tLog_Write(\"============= Botlib memory log ==============\\r\\n\");\n\tLog_Write(\"\\r\\n\");\n\tfor (block = memory; block; block = block->next)\n\t{\n#ifdef MEMDEBUG\n\t\tif (block->id == HUNK_ID)\n\t\t{\n\t\t\tLog_Write(\"%6d, hunk %p, %8d: %24s line %6d: %s\\r\\n\", i, block->ptr, block->size, block->file, block->line, block->label);\n\t\t} //end if\n\t\telse\n\t\t{\n\t\t\tLog_Write(\"%6d,      %p, %8d: %24s line %6d: %s\\r\\n\", i, block->ptr, block->size, block->file, block->line, block->label);\n\t\t} //end else\n#endif //MEMDEBUG\n\t\ti++;\n\t} //end for\n} //end of the function PrintMemoryLabels\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid DumpMemory(void)\n{\n\tmemoryblock_t *block;\n\n\tfor (block = memory; block; block = memory)\n\t{\n\t\tFreeMemory(block->ptr);\n\t} //end for\n\ttotalmemorysize = 0;\n\tallocatedmemory = 0;\n} //end of the function DumpMemory\n\n#else\n\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\n#ifdef MEMDEBUG\nvoid *GetMemoryDebug(unsigned long size, char *label, char *file, int line)\n#else\nvoid *GetMemory(unsigned long size)\n#endif //MEMDEBUG\n{\n\tvoid *ptr;\n\tunsigned long int *memid;\n\n\tptr = botimport.GetMemory(size + sizeof(unsigned long int));\n\tif (!ptr) return NULL;\n\tmemid = (unsigned long int *) ptr;\n\t*memid = MEM_ID;\n\treturn (unsigned long int *) ((char *) ptr + sizeof(unsigned long int));\n} //end of the function GetMemory\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\n#ifdef MEMDEBUG\nvoid *GetClearedMemoryDebug(unsigned long size, char *label, char *file, int line)\n#else\nvoid *GetClearedMemory(unsigned long size)\n#endif //MEMDEBUG\n{\n\tvoid *ptr;\n#ifdef MEMDEBUG\n\tptr = GetMemoryDebug(size, label, file, line);\n#else\n\tptr = GetMemory(size);\n#endif //MEMDEBUG\n\tCom_Memset(ptr, 0, size);\n\treturn ptr;\n} //end of the function GetClearedMemory\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\n#ifdef MEMDEBUG\nvoid *GetHunkMemoryDebug(unsigned long size, char *label, char *file, int line)\n#else\nvoid *GetHunkMemory(unsigned long size)\n#endif //MEMDEBUG\n{\n\tvoid *ptr;\n\tunsigned long int *memid;\n\n\tptr = botimport.HunkAlloc(size + sizeof(unsigned long int));\n\tif (!ptr) return NULL;\n\tmemid = (unsigned long int *) ptr;\n\t*memid = HUNK_ID;\n\treturn (unsigned long int *) ((char *) ptr + sizeof(unsigned long int));\n} //end of the function GetHunkMemory\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\n#ifdef MEMDEBUG\nvoid *GetClearedHunkMemoryDebug(unsigned long size, char *label, char *file, int line)\n#else\nvoid *GetClearedHunkMemory(unsigned long size)\n#endif //MEMDEBUG\n{\n\tvoid *ptr;\n#ifdef MEMDEBUG\n\tptr = GetHunkMemoryDebug(size, label, file, line);\n#else\n\tptr = GetHunkMemory(size);\n#endif //MEMDEBUG\n\tCom_Memset(ptr, 0, size);\n\treturn ptr;\n} //end of the function GetClearedHunkMemory\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid FreeMemory(void *ptr)\n{\n\tunsigned long int *memid;\n\n\tmemid = (unsigned long int *) ((char *) ptr - sizeof(unsigned long int));\n\n\tif (*memid == MEM_ID)\n\t{\n\t\tbotimport.FreeMemory(memid);\n\t} //end if\n} //end of the function FreeMemory\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint AvailableMemory(void)\n{\n\treturn botimport.AvailableMemory();\n} //end of the function AvailableMemory\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid PrintUsedMemorySize(void)\n{\n} //end of the function PrintUsedMemorySize\n//===========================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid PrintMemoryLabels(void)\n{\n} //end of the function PrintMemoryLabels\n\n#endif\n"
  },
  {
    "path": "src/engine/botlib/l_memory.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tl_memory.h\n *\n * desc:\t\tmemory management\n *\n * $Archive: /source/code/botlib/l_memory.h $\n *\n *****************************************************************************/\n\n//#define MEMDEBUG\n\n#ifdef MEMDEBUG\n#define GetMemory(size)\t\t\t\tGetMemoryDebug(size, #size, __FILE__, __LINE__);\n#define GetClearedMemory(size)\t\tGetClearedMemoryDebug(size, #size, __FILE__, __LINE__);\n//allocate a memory block of the given size\nvoid *GetMemoryDebug(unsigned long size, char *label, char *file, int line);\n//allocate a memory block of the given size and clear it\nvoid *GetClearedMemoryDebug(unsigned long size, char *label, char *file, int line);\n//\n#define GetHunkMemory(size)\t\t\tGetHunkMemoryDebug(size, #size, __FILE__, __LINE__);\n#define GetClearedHunkMemory(size)\tGetClearedHunkMemoryDebug(size, #size, __FILE__, __LINE__);\n//allocate a memory block of the given size\nvoid *GetHunkMemoryDebug(unsigned long size, char *label, char *file, int line);\n//allocate a memory block of the given size and clear it\nvoid *GetClearedHunkMemoryDebug(unsigned long size, char *label, char *file, int line);\n#else\n//allocate a memory block of the given size\nvoid *GetMemory(unsigned long size);\n//allocate a memory block of the given size and clear it\nvoid *GetClearedMemory(unsigned long size);\n//\n#ifdef BSPC\n#define GetHunkMemory GetMemory\n#define GetClearedHunkMemory GetClearedMemory\n#else\n//allocate a memory block of the given size\nvoid *GetHunkMemory(unsigned long size);\n//allocate a memory block of the given size and clear it\nvoid *GetClearedHunkMemory(unsigned long size);\n#endif\n#endif\n\n//free the given memory block\nvoid FreeMemory(void *ptr);\n//returns the amount available memory\nint AvailableMemory(void);\n//prints the total used memory size\nvoid PrintUsedMemorySize(void);\n//print all memory blocks with label\nvoid PrintMemoryLabels(void);\n//returns the size of the memory block in bytes\nint MemoryByteSize(void *ptr);\n//free all allocated memory\nvoid DumpMemory(void);\n"
  },
  {
    "path": "src/engine/botlib/l_precomp.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n\n/*****************************************************************************\n * name:\t\tl_precomp.c\n *\n * desc:\t\tpre compiler\n *\n * $Archive: /MissionPack/code/botlib/l_precomp.c $\n *\n *****************************************************************************/\n\n//Notes:\t\t\tfix: PC_StringizeTokens\n\n//#define SCREWUP\n//#define BOTLIB\n//#define QUAKE\n//#define QUAKEC\n//#define MEQCC\n\n#ifdef SCREWUP\n#include <stdio.h>\n#include <stdlib.h>\n#include <limits.h>\n#include <string.h>\n#include <stdarg.h>\n#include <time.h>\n#include \"l_memory.h\"\n#include \"l_script.h\"\n#include \"l_precomp.h\"\n\ntypedef enum {qfalse, qtrue}\tqboolean;\n#endif //SCREWUP\n\n#ifdef BOTLIB\n#include \"../../game/q_shared.h\"\n#include \"../../game/botlib.h\"\n#include \"be_interface.h\"\n#include \"l_memory.h\"\n#include \"l_script.h\"\n#include \"l_precomp.h\"\n#include \"l_log.h\"\n#endif //BOTLIB\n\n#ifdef MEQCC\n#include \"qcc.h\"\n#include \"time.h\"   //time & ctime\n#include \"math.h\"   //fabs\n#include \"l_memory.h\"\n#include \"l_script.h\"\n#include \"l_precomp.h\"\n#include \"l_log.h\"\n\n#define qtrue\ttrue\n#define qfalse\tfalse\n#endif //MEQCC\n\n#ifdef BSPC\n//include files for usage in the BSP Converter\n#include \"../bspc/qbsp.h\"\n#include \"../bspc/l_log.h\"\n#include \"../bspc/l_mem.h\"\n#include \"l_precomp.h\"\n\n#define qtrue\ttrue\n#define qfalse\tfalse\n#define Q_stricmp\tstricmp\n\n#endif //BSPC\n\n#if defined(QUAKE) && !defined(BSPC)\n#include \"l_utils.h\"\n#endif //QUAKE\n\n//#define DEBUG_EVAL\n\n#define MAX_DEFINEPARMS\t\t\t128\n\n#define DEFINEHASHING\t\t\t1\n\n//directive name with parse function\ntypedef struct directive_s\n{\n\tchar *name;\n\tint (*func)(source_t *source);\n} directive_t;\n\n#define DEFINEHASHSIZE\t\t1024\n\n#define TOKEN_HEAP_SIZE\t\t4096\n\nint numtokens;\n/*\nint tokenheapinitialized;\t\t\t\t//true when the token heap is initialized\ntoken_t token_heap[TOKEN_HEAP_SIZE];\t//heap with tokens\ntoken_t *freetokens;\t\t\t\t\t//free tokens from the heap\n*/\n\n//list with global defines added to every source loaded\ndefine_t *globaldefines;\n\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nvoid QDECL SourceError(source_t *source, char *str, ...)\n{\n\tchar text[1024];\n\tva_list ap;\n\n\tva_start(ap, str);\n\tvsprintf(text, str, ap);\n\tva_end(ap);\n#ifdef BOTLIB\n\tbotimport.Print(PRT_ERROR, \"file %s, line %d: %s\\n\", source->scriptstack->filename, source->scriptstack->line, text);\n#endif\t//BOTLIB\n#ifdef MEQCC\n\tprintf(\"error: file %s, line %d: %s\\n\", source->scriptstack->filename, source->scriptstack->line, text);\n#endif //MEQCC\n#ifdef BSPC\n\tLog_Print(\"error: file %s, line %d: %s\\n\", source->scriptstack->filename, source->scriptstack->line, text);\n#endif //BSPC\n} //end of the function SourceError\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid QDECL SourceWarning(source_t *source, char *str, ...)\n{\n\tchar text[1024];\n\tva_list ap;\n\n\tva_start(ap, str);\n\tvsprintf(text, str, ap);\n\tva_end(ap);\n#ifdef BOTLIB\n\tbotimport.Print(PRT_WARNING, \"file %s, line %d: %s\\n\", source->scriptstack->filename, source->scriptstack->line, text);\n#endif //BOTLIB\n#ifdef MEQCC\n\tprintf(\"warning: file %s, line %d: %s\\n\", source->scriptstack->filename, source->scriptstack->line, text);\n#endif //MEQCC\n#ifdef BSPC\n\tLog_Print(\"warning: file %s, line %d: %s\\n\", source->scriptstack->filename, source->scriptstack->line, text);\n#endif //BSPC\n} //end of the function ScriptWarning\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nvoid PC_PushIndent(source_t *source, int type, int skip)\n{\n\tindent_t *indent;\n\n\tindent = (indent_t *) GetMemory(sizeof(indent_t));\n\tindent->type = type;\n\tindent->script = source->scriptstack;\n\tindent->skip = (skip != 0);\n\tsource->skip += indent->skip;\n\tindent->next = source->indentstack;\n\tsource->indentstack = indent;\n} //end of the function PC_PushIndent\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nvoid PC_PopIndent(source_t *source, int *type, int *skip)\n{\n\tindent_t *indent;\n\n\t*type = 0;\n\t*skip = 0;\n\n\tindent = source->indentstack;\n\tif (!indent) return;\n\n\t//must be an indent from the current script\n\tif (source->indentstack->script != source->scriptstack) return;\n\n\t*type = indent->type;\n\t*skip = indent->skip;\n\tsource->indentstack = source->indentstack->next;\n\tsource->skip -= indent->skip;\n\tFreeMemory(indent);\n} //end of the function PC_PopIndent\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nvoid PC_PushScript(source_t *source, script_t *script)\n{\n\tscript_t *s;\n\n\tfor (s = source->scriptstack; s; s = s->next)\n\t{\n\t\tif (!Q_stricmp(s->filename, script->filename))\n\t\t{\n\t\t\tSourceError(source, \"%s recursively included\", script->filename);\n\t\t\treturn;\n\t\t} //end if\n\t} //end for\n\t//push the script on the script stack\n\tscript->next = source->scriptstack;\n\tsource->scriptstack = script;\n} //end of the function PC_PushScript\n//============================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nvoid PC_InitTokenHeap(void)\n{\n\t/*\n\tint i;\n\n\tif (tokenheapinitialized) return;\n\tfreetokens = NULL;\n\tfor (i = 0; i < TOKEN_HEAP_SIZE; i++)\n\t{\n\t\ttoken_heap[i].next = freetokens;\n\t\tfreetokens = &token_heap[i];\n\t} //end for\n\ttokenheapinitialized = qtrue;\n\t*/\n} //end of the function PC_InitTokenHeap\n//============================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\ntoken_t *PC_CopyToken(token_t *token)\n{\n\ttoken_t *t;\n\n//\tt = (token_t *) malloc(sizeof(token_t));\n\tt = (token_t *) GetMemory(sizeof(token_t));\n//\tt = freetokens;\n\tif (!t)\n\t{\n#ifdef BSPC\n\t\tError(\"out of token space\\n\");\n#else\n\t\tCom_Error(ERR_FATAL, \"out of token space\\n\");\n#endif\n\t\treturn NULL;\n\t} //end if\n//\tfreetokens = freetokens->next;\n\tCom_Memcpy(t, token, sizeof(token_t));\n\tt->next = NULL;\n\tnumtokens++;\n\treturn t;\n} //end of the function PC_CopyToken\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nvoid PC_FreeToken(token_t *token)\n{\n\t//free(token);\n\tFreeMemory(token);\n//\ttoken->next = freetokens;\n//\tfreetokens = token;\n\tnumtokens--;\n} //end of the function PC_FreeToken\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PC_ReadSourceToken(source_t *source, token_t *token)\n{\n\ttoken_t *t;\n\tscript_t *script;\n\tint type, skip;\n\n\t//if there's no token already available\n\twhile(!source->tokens)\n\t{\n\t\t//if there's a token to read from the script\n\t\tif (PS_ReadToken(source->scriptstack, token)) return qtrue;\n\t\t//if at the end of the script\n\t\tif (EndOfScript(source->scriptstack))\n\t\t{\n\t\t\t//remove all indents of the script\n\t\t\twhile(source->indentstack &&\n\t\t\t\t\tsource->indentstack->script == source->scriptstack)\n\t\t\t{\n\t\t\t\tSourceWarning(source, \"missing #endif\");\n\t\t\t\tPC_PopIndent(source, &type, &skip);\n\t\t\t} //end if\n\t\t} //end if\n\t\t//if this was the initial script\n\t\tif (!source->scriptstack->next) return qfalse;\n\t\t//remove the script and return to the last one\n\t\tscript = source->scriptstack;\n\t\tsource->scriptstack = source->scriptstack->next;\n\t\tFreeScript(script);\n\t} //end while\n\t//copy the already available token\n\tCom_Memcpy(token, source->tokens, sizeof(token_t));\n\t//free the read token\n\tt = source->tokens;\n\tsource->tokens = source->tokens->next;\n\tPC_FreeToken(t);\n\treturn qtrue;\n} //end of the function PC_ReadSourceToken\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PC_UnreadSourceToken(source_t *source, token_t *token)\n{\n\ttoken_t *t;\n\n\tt = PC_CopyToken(token);\n\tt->next = source->tokens;\n\tsource->tokens = t;\n\treturn qtrue;\n} //end of the function PC_UnreadSourceToken\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PC_ReadDefineParms(source_t *source, define_t *define, token_t **parms, int maxparms)\n{\n\ttoken_t token, *t, *last;\n\tint i, done, lastcomma, numparms, indent;\n\n\tif (!PC_ReadSourceToken(source, &token))\n\t{\n\t\tSourceError(source, \"define %s missing parms\", define->name);\n\t\treturn qfalse;\n\t} //end if\n\t//\n\tif (define->numparms > maxparms)\n\t{\n\t\tSourceError(source, \"define with more than %d parameters\", maxparms);\n\t\treturn qfalse;\n\t} //end if\n\t//\n\tfor (i = 0; i < define->numparms; i++) parms[i] = NULL;\n\t//if no leading \"(\"\n\tif (strcmp(token.string, \"(\"))\n\t{\n\t\tPC_UnreadSourceToken(source, &token);\n\t\tSourceError(source, \"define %s missing parms\", define->name);\n\t\treturn qfalse;\n\t} //end if\n\t//read the define parameters\n\tfor (done = 0, numparms = 0, indent = 0; !done;)\n\t{\n\t\tif (numparms >= maxparms)\n\t\t{\n\t\t\tSourceError(source, \"define %s with too many parms\", define->name);\n\t\t\treturn qfalse;\n\t\t} //end if\n\t\tif (numparms >= define->numparms)\n\t\t{\n\t\t\tSourceWarning(source, \"define %s has too many parms\", define->name);\n\t\t\treturn qfalse;\n\t\t} //end if\n\t\tparms[numparms] = NULL;\n\t\tlastcomma = 1;\n\t\tlast = NULL;\n\t\twhile(!done)\n\t\t{\n\t\t\t//\n\t\t\tif (!PC_ReadSourceToken(source, &token))\n\t\t\t{\n\t\t\t\tSourceError(source, \"define %s incomplete\", define->name);\n\t\t\t\treturn qfalse;\n\t\t\t} //end if\n\t\t\t//\n\t\t\tif (!strcmp(token.string, \",\"))\n\t\t\t{\n\t\t\t\tif (indent <= 0)\n\t\t\t\t{\n\t\t\t\t\tif (lastcomma) SourceWarning(source, \"too many comma's\");\n\t\t\t\t\tlastcomma = 1;\n\t\t\t\t\tbreak;\n\t\t\t\t} //end if\n\t\t\t} //end if\n\t\t\tlastcomma = 0;\n\t\t\t//\n\t\t\tif (!strcmp(token.string, \"(\"))\n\t\t\t{\n\t\t\t\tindent++;\n\t\t\t\tcontinue;\n\t\t\t} //end if\n\t\t\telse if (!strcmp(token.string, \")\"))\n\t\t\t{\n\t\t\t\tif (--indent <= 0)\n\t\t\t\t{\n\t\t\t\t\tif (!parms[define->numparms-1])\n\t\t\t\t\t{\n\t\t\t\t\t\tSourceWarning(source, \"too few define parms\");\n\t\t\t\t\t} //end if\n\t\t\t\t\tdone = 1;\n\t\t\t\t\tbreak;\n\t\t\t\t} //end if\n\t\t\t} //end if\n\t\t\t//\n\t\t\tif (numparms < define->numparms)\n\t\t\t{\n\t\t\t\t//\n\t\t\t\tt = PC_CopyToken(&token);\n\t\t\t\tt->next = NULL;\n\t\t\t\tif (last) last->next = t;\n\t\t\t\telse parms[numparms] = t;\n\t\t\t\tlast = t;\n\t\t\t} //end if\n\t\t} //end while\n\t\tnumparms++;\n\t} //end for\n\treturn qtrue;\n} //end of the function PC_ReadDefineParms\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PC_StringizeTokens(token_t *tokens, token_t *token)\n{\n\ttoken_t *t;\n\n\ttoken->type = TT_STRING;\n\ttoken->whitespace_p = NULL;\n\ttoken->endwhitespace_p = NULL;\n\ttoken->string[0] = '\\0';\n\tstrcat(token->string, \"\\\"\");\n\tfor (t = tokens; t; t = t->next)\n\t{\n\t\tstrncat(token->string, t->string, MAX_TOKEN - (int)strlen(token->string));\n\t} //end for\n\tstrncat(token->string, \"\\\"\", MAX_TOKEN - (int)strlen(token->string));\n\treturn qtrue;\n} //end of the function PC_StringizeTokens\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PC_MergeTokens(token_t *t1, token_t *t2)\n{\n\t//merging of a name with a name or number\n\tif (t1->type == TT_NAME && (t2->type == TT_NAME || t2->type == TT_NUMBER))\n\t{\n\t\tstrcat(t1->string, t2->string);\n\t\treturn qtrue;\n\t} //end if\n\t//merging of two strings\n\tif (t1->type == TT_STRING && t2->type == TT_STRING)\n\t{\n\t\t//remove trailing double quote\n\t\tt1->string[strlen(t1->string)-1] = '\\0';\n\t\t//concat without leading double quote\n\t\tstrcat(t1->string, &t2->string[1]);\n\t\treturn qtrue;\n\t} //end if\n\t//FIXME: merging of two number of the same sub type\n\treturn qfalse;\n} //end of the function PC_MergeTokens\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\n/*\nvoid PC_PrintDefine(define_t *define)\n{\n\tprintf(\"define->name = %s\\n\", define->name);\n\tprintf(\"define->flags = %d\\n\", define->flags);\n\tprintf(\"define->builtin = %d\\n\", define->builtin);\n\tprintf(\"define->numparms = %d\\n\", define->numparms);\n//\ttoken_t *parms;\t\t\t\t\t//define parameters\n//\ttoken_t *tokens;\t\t\t\t\t//macro tokens (possibly containing parm tokens)\n//\tstruct define_s *next;\t\t\t//next defined macro in a list\n} //end of the function PC_PrintDefine*/\n#if DEFINEHASHING\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nvoid PC_PrintDefineHashTable(define_t **definehash)\n{\n\tint i;\n\tdefine_t *d;\n\n\tfor (i = 0; i < DEFINEHASHSIZE; i++)\n\t{\n\t\tLog_Write(\"%4d:\", i);\n\t\tfor (d = definehash[i]; d; d = d->hashnext)\n\t\t{\n\t\t\tLog_Write(\" %s\", d->name);\n\t\t} //end for\n\t\tLog_Write(\"\\n\");\n\t} //end for\n} //end of the function PC_PrintDefineHashTable\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\n//char primes[16] = {1, 3, 5, 7, 11, 13, 17, 19, 23, 27, 29, 31, 37, 41, 43, 47};\n\nint PC_NameHash(char *name)\n{\n\tint register hash, i;\n\n\thash = 0;\n\tfor (i = 0; name[i] != '\\0'; i++)\n\t{\n\t\thash += name[i] * (119 + i);\n\t\t//hash += (name[i] << 7) + i;\n\t\t//hash += (name[i] << (i&15));\n\t} //end while\n\thash = (hash ^ (hash >> 10) ^ (hash >> 20)) & (DEFINEHASHSIZE-1);\n\treturn hash;\n} //end of the function PC_NameHash\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nvoid PC_AddDefineToHash(define_t *define, define_t **definehash)\n{\n\tint hash;\n\n\thash = PC_NameHash(define->name);\n\tdefine->hashnext = definehash[hash];\n\tdefinehash[hash] = define;\n} //end of the function PC_AddDefineToHash\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\ndefine_t *PC_FindHashedDefine(define_t **definehash, char *name)\n{\n\tdefine_t *d;\n\tint hash;\n\n\thash = PC_NameHash(name);\n\tfor (d = definehash[hash]; d; d = d->hashnext)\n\t{\n\t\tif (!strcmp(d->name, name)) return d;\n\t} //end for\n\treturn NULL;\n} //end of the function PC_FindHashedDefine\n#endif //DEFINEHASHING\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\ndefine_t *PC_FindDefine(define_t *defines, char *name)\n{\n\tdefine_t *d;\n\n\tfor (d = defines; d; d = d->next)\n\t{\n\t\tif (!strcmp(d->name, name)) return d;\n\t} //end for\n\treturn NULL;\n} //end of the function PC_FindDefine\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\tnumber of the parm\n//\t\t\t\t\t\t\t\tif no parm found with the given name -1 is returned\n// Changes Globals:\t\t-\n//============================================================================\nint PC_FindDefineParm(define_t *define, char *name)\n{\n\ttoken_t *p;\n\tint i;\n\n\ti = 0;\n\tfor (p = define->parms; p; p = p->next)\n\t{\n\t\tif (!strcmp(p->string, name)) return i;\n\t\ti++;\n\t} //end for\n\treturn -1;\n} //end of the function PC_FindDefineParm\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nvoid PC_FreeDefine(define_t *define)\n{\n\ttoken_t *t, *next;\n\n\t//free the define parameters\n\tfor (t = define->parms; t; t = next)\n\t{\n\t\tnext = t->next;\n\t\tPC_FreeToken(t);\n\t} //end for\n\t//free the define tokens\n\tfor (t = define->tokens; t; t = next)\n\t{\n\t\tnext = t->next;\n\t\tPC_FreeToken(t);\n\t} //end for\n\t//free the define\n\tFreeMemory(define);\n} //end of the function PC_FreeDefine\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nvoid PC_AddBuiltinDefines(source_t *source)\n{\n\tint i;\n\tdefine_t *define;\n\tstruct builtinStruct\n\t{\n\t\tchar *string;\n\t\tint builtin;\n\n\t\tbuiltinStruct(char* istring, int ibuiltin)\n\t\t\t: string(istring), builtin(ibuiltin) {}\n\t} builtin[] = { // bk001204 - brackets\n\t\t{ \"__LINE__\",\tBUILTIN_LINE },\n\t\t{ \"__FILE__\",\tBUILTIN_FILE },\n\t\t{ \"__DATE__\",\tBUILTIN_DATE },\n\t\t{ \"__TIME__\",\tBUILTIN_TIME },\n//\t\t{ \"__STDC__\", BUILTIN_STDC },\n\t\t{ NULL, 0 }\n\t};\n\n\tfor (i = 0; builtin[i].string; i++)\n\t{\n\t\tdefine = (define_t *) GetMemory(sizeof(define_t) + (int)strlen(builtin[i].string) + 1);\n\t\tCom_Memset(define, 0, sizeof(define_t));\n\t\tdefine->name = (char *) define + sizeof(define_t);\n\t\tstrcpy(define->name, builtin[i].string);\n\t\tdefine->flags |= DEFINE_FIXED;\n\t\tdefine->builtin = builtin[i].builtin;\n\t\t//add the define to the source\n#if DEFINEHASHING\n\t\tPC_AddDefineToHash(define, source->definehash);\n#else\n\t\tdefine->next = source->defines;\n\t\tsource->defines = define;\n#endif //DEFINEHASHING\n\t} //end for\n} //end of the function PC_AddBuiltinDefines\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PC_ExpandBuiltinDefine(source_t *source, token_t *deftoken, define_t *define,\n\t\t\t\t\t\t\t\t\t\ttoken_t **firsttoken, token_t **lasttoken)\n{\n\ttoken_t *token;\n\ttime_t t;\n\tchar *curtime;\n\n\ttoken = PC_CopyToken(deftoken);\n\tswitch(define->builtin)\n\t{\n\t\tcase BUILTIN_LINE:\n\t\t{\n\t\t\tsprintf(token->string, \"%d\", deftoken->line);\n#ifdef NUMBERVALUE\n\t\t\ttoken->intvalue = deftoken->line;\n\t\t\ttoken->floatvalue = deftoken->line;\n#endif //NUMBERVALUE\n\t\t\ttoken->type = TT_NUMBER;\n\t\t\ttoken->subtype = TT_DECIMAL | TT_INTEGER;\n\t\t\t*firsttoken = token;\n\t\t\t*lasttoken = token;\n\t\t\tbreak;\n\t\t} //end case\n\t\tcase BUILTIN_FILE:\n\t\t{\n\t\t\tstrcpy(token->string, source->scriptstack->filename);\n\t\t\ttoken->type = TT_NAME;\n\t\t\ttoken->subtype = (int)strlen(token->string);\n\t\t\t*firsttoken = token;\n\t\t\t*lasttoken = token;\n\t\t\tbreak;\n\t\t} //end case\n\t\tcase BUILTIN_DATE:\n\t\t{\n\t\t\tt = time(NULL);\n\t\t\tcurtime = ctime((const time_t*)&t);\n\t\t\tstrcpy(token->string, \"\\\"\");\n\t\t\tstrncat(token->string, curtime+4, 7);\n\t\t\tstrncat(token->string+7, curtime+20, 4);\n\t\t\tstrcat(token->string, \"\\\"\");\n\t\t\tfree(curtime);\n\t\t\ttoken->type = TT_NAME;\n\t\t\ttoken->subtype = (int)strlen(token->string);\n\t\t\t*firsttoken = token;\n\t\t\t*lasttoken = token;\n\t\t\tbreak;\n\t\t} //end case\n\t\tcase BUILTIN_TIME:\n\t\t{\n\t\t\tt = time(NULL);\n\t\t\tcurtime = ctime((const time_t*)&t);\n\t\t\tstrcpy(token->string, \"\\\"\");\n\t\t\tstrncat(token->string, curtime+11, 8);\n\t\t\tstrcat(token->string, \"\\\"\");\n\t\t\tfree(curtime);\n\t\t\ttoken->type = TT_NAME;\n\t\t\ttoken->subtype = (int)strlen(token->string);\n\t\t\t*firsttoken = token;\n\t\t\t*lasttoken = token;\n\t\t\tbreak;\n\t\t} //end case\n\t\tcase BUILTIN_STDC:\n\t\tdefault:\n\t\t{\n\t\t\t*firsttoken = NULL;\n\t\t\t*lasttoken = NULL;\n\t\t\tbreak;\n\t\t} //end case\n\t} //end switch\n\treturn qtrue;\n} //end of the function PC_ExpandBuiltinDefine\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PC_ExpandDefine(source_t *source, token_t *deftoken, define_t *define,\n\t\t\t\t\t\t\t\t\t\ttoken_t **firsttoken, token_t **lasttoken)\n{\n\ttoken_t *parms[MAX_DEFINEPARMS], *dt, *pt, *t;\n\ttoken_t *t1, *t2, *first, *last, *nextpt, token;\n\tint parmnum, i;\n\n\t//if it is a builtin define\n\tif (define->builtin)\n\t{\n\t\treturn PC_ExpandBuiltinDefine(source, deftoken, define, firsttoken, lasttoken);\n\t} //end if\n\t//if the define has parameters\n\tif (define->numparms)\n\t{\n\t\tif (!PC_ReadDefineParms(source, define, parms, MAX_DEFINEPARMS)) return qfalse;\n#ifdef DEBUG_EVAL\n\t\tfor (i = 0; i < define->numparms; i++)\n\t\t{\n\t\t\tLog_Write(\"define parms %d:\", i);\n\t\t\tfor (pt = parms[i]; pt; pt = pt->next)\n\t\t\t{\n\t\t\t\tLog_Write(\"%s\", pt->string);\n\t\t\t} //end for\n\t\t} //end for\n#endif //DEBUG_EVAL\n\t} //end if\n\t//empty list at first\n\tfirst = NULL;\n\tlast = NULL;\n\t//create a list with tokens of the expanded define\n\tfor (dt = define->tokens; dt; dt = dt->next)\n\t{\n\t\tparmnum = -1;\n\t\t//if the token is a name, it could be a define parameter\n\t\tif (dt->type == TT_NAME)\n\t\t{\n\t\t\tparmnum = PC_FindDefineParm(define, dt->string);\n\t\t} //end if\n\t\t//if it is a define parameter\n\t\tif (parmnum >= 0)\n\t\t{\n\t\t\tfor (pt = parms[parmnum]; pt; pt = pt->next)\n\t\t\t{\n\t\t\t\tt = PC_CopyToken(pt);\n\t\t\t\t//add the token to the list\n\t\t\t\tt->next = NULL;\n\t\t\t\tif (last) last->next = t;\n\t\t\t\telse first = t;\n\t\t\t\tlast = t;\n\t\t\t} //end for\n\t\t} //end if\n\t\telse\n\t\t{\n\t\t\t//if stringizing operator\n\t\t\tif (dt->string[0] == '#' && dt->string[1] == '\\0')\n\t\t\t{\n\t\t\t\t//the stringizing operator must be followed by a define parameter\n\t\t\t\tif (dt->next) parmnum = PC_FindDefineParm(define, dt->next->string);\n\t\t\t\telse parmnum = -1;\n\t\t\t\t//\n\t\t\t\tif (parmnum >= 0)\n\t\t\t\t{\n\t\t\t\t\t//step over the stringizing operator\n\t\t\t\t\tdt = dt->next;\n\t\t\t\t\t//stringize the define parameter tokens\n\t\t\t\t\tif (!PC_StringizeTokens(parms[parmnum], &token))\n\t\t\t\t\t{\n\t\t\t\t\t\tSourceError(source, \"can't stringize tokens\");\n\t\t\t\t\t\treturn qfalse;\n\t\t\t\t\t} //end if\n\t\t\t\t\tt = PC_CopyToken(&token);\n\t\t\t\t} //end if\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tSourceWarning(source, \"stringizing operator without define parameter\");\n\t\t\t\t\tcontinue;\n\t\t\t\t} //end if\n\t\t\t} //end if\n\t\t\telse\n\t\t\t{\n\t\t\t\tt = PC_CopyToken(dt);\n\t\t\t} //end else\n\t\t\t//add the token to the list\n\t\t\tt->next = NULL;\n\t\t\tif (last) last->next = t;\n\t\t\telse first = t;\n\t\t\tlast = t;\n\t\t} //end else\n\t} //end for\n\t//check for the merging operator\n\tfor (t = first; t; )\n\t{\n\t\tif (t->next)\n\t\t{\n\t\t\t//if the merging operator\n\t\t\tif (t->next->string[0] == '#' && t->next->string[1] == '#')\n\t\t\t{\n\t\t\t\tt1 = t;\n\t\t\t\tt2 = t->next->next;\n\t\t\t\tif (t2)\n\t\t\t\t{\n\t\t\t\t\tif (!PC_MergeTokens(t1, t2))\n\t\t\t\t\t{\n\t\t\t\t\t\tSourceError(source, \"can't merge %s with %s\", t1->string, t2->string);\n\t\t\t\t\t\treturn qfalse;\n\t\t\t\t\t} //end if\n\t\t\t\t\tPC_FreeToken(t1->next);\n\t\t\t\t\tt1->next = t2->next;\n\t\t\t\t\tif (t2 == last) last = t1;\n\t\t\t\t\tPC_FreeToken(t2);\n\t\t\t\t\tcontinue;\n\t\t\t\t} //end if\n\t\t\t} //end if\n\t\t} //end if\n\t\tt = t->next;\n\t} //end for\n\t//store the first and last token of the list\n\t*firsttoken = first;\n\t*lasttoken = last;\n\t//free all the parameter tokens\n\tfor (i = 0; i < define->numparms; i++)\n\t{\n\t\tfor (pt = parms[i]; pt; pt = nextpt)\n\t\t{\n\t\t\tnextpt = pt->next;\n\t\t\tPC_FreeToken(pt);\n\t\t} //end for\n\t} //end for\n\t//\n\treturn qtrue;\n} //end of the function PC_ExpandDefine\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PC_ExpandDefineIntoSource(source_t *source, token_t *deftoken, define_t *define)\n{\n\ttoken_t *firsttoken, *lasttoken;\n\n\tif (!PC_ExpandDefine(source, deftoken, define, &firsttoken, &lasttoken)) return qfalse;\n\n\tif (firsttoken && lasttoken)\n\t{\n\t\tlasttoken->next = source->tokens;\n\t\tsource->tokens = firsttoken;\n\t\treturn qtrue;\n\t} //end if\n\treturn qfalse;\n} //end of the function PC_ExpandDefineIntoSource\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nvoid PC_ConvertPath(char *path)\n{\n\tchar *ptr;\n\n\t//remove double path seperators\n\tfor (ptr = path; *ptr;)\n\t{\n\t\tif ((*ptr == '\\\\' || *ptr == '/') &&\n\t\t\t\t(*(ptr+1) == '\\\\' || *(ptr+1) == '/'))\n\t\t{\n\t\t\tstrcpy(ptr, ptr+1);\n\t\t} //end if\n\t\telse\n\t\t{\n\t\t\tptr++;\n\t\t} //end else\n\t} //end while\n\t//set OS dependent path seperators\n\tfor (ptr = path; *ptr;)\n\t{\n\t\tif (*ptr == '/' || *ptr == '\\\\') *ptr = PATHSEPERATOR_CHAR;\n\t\tptr++;\n\t} //end while\n} //end of the function PC_ConvertPath\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PC_Directive_include(source_t *source)\n{\n\tscript_t *script;\n\ttoken_t token;\n\tchar path[MAX_PATH];\n#ifdef QUAKE\n\tfoundfile_t file;\n#endif //QUAKE\n\n\tif (source->skip > 0) return qtrue;\n\t//\n\tif (!PC_ReadSourceToken(source, &token))\n\t{\n\t\tSourceError(source, \"#include without file name\");\n\t\treturn qfalse;\n\t} //end if\n\tif (token.linescrossed > 0)\n\t{\n\t\tSourceError(source, \"#include without file name\");\n\t\treturn qfalse;\n\t} //end if\n\tif (token.type == TT_STRING)\n\t{\n\t\tStripDoubleQuotes(token.string);\n\t\tPC_ConvertPath(token.string);\n\t\tscript = LoadScriptFile(token.string);\n\t\tif (!script)\n\t\t{\n\t\t\tstrcpy(path, source->includepath);\n\t\t\tstrcat(path, token.string);\n\t\t\tscript = LoadScriptFile(path);\n\t\t} //end if\n\t} //end if\n\telse if (token.type == TT_PUNCTUATION && *token.string == '<')\n\t{\n\t\tstrcpy(path, source->includepath);\n\t\twhile(PC_ReadSourceToken(source, &token))\n\t\t{\n\t\t\tif (token.linescrossed > 0)\n\t\t\t{\n\t\t\t\tPC_UnreadSourceToken(source, &token);\n\t\t\t\tbreak;\n\t\t\t} //end if\n\t\t\tif (token.type == TT_PUNCTUATION && *token.string == '>') break;\n\t\t\tstrncat(path, token.string, MAX_PATH);\n\t\t} //end while\n\t\tif (*token.string != '>')\n\t\t{\n\t\t\tSourceWarning(source, \"#include missing trailing >\");\n\t\t} //end if\n\t\tif (!strlen(path))\n\t\t{\n\t\t\tSourceError(source, \"#include without file name between < >\");\n\t\t\treturn qfalse;\n\t\t} //end if\n\t\tPC_ConvertPath(path);\n\t\tscript = LoadScriptFile(path);\n\t} //end if\n\telse\n\t{\n\t\tSourceError(source, \"#include without file name\");\n\t\treturn qfalse;\n\t} //end else\n#ifdef QUAKE\n\tif (!script)\n\t{\n\t\tCom_Memset(&file, 0, sizeof(foundfile_t));\n\t\tscript = LoadScriptFile(path);\n\t\tif (script) strncpy(script->filename, path, MAX_PATH);\n\t} //end if\n#endif //QUAKE\n\tif (!script)\n\t{\n#ifdef SCREWUP\n\t\tSourceWarning(source, \"file %s not found\", path);\n\t\treturn qtrue;\n#else\n\t\tSourceError(source, \"file %s not found\", path);\n\t\treturn qfalse;\n#endif //SCREWUP\n\t} //end if\n\tPC_PushScript(source, script);\n\treturn qtrue;\n} //end of the function PC_Directive_include\n//============================================================================\n// reads a token from the current line, continues reading on the next\n// line only if a backslash '\\' is encountered.\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PC_ReadLine(source_t *source, token_t *token)\n{\n\tint crossline;\n\n\tcrossline = 0;\n\tdo\n\t{\n\t\tif (!PC_ReadSourceToken(source, token)) return qfalse;\n\t\t\n\t\tif (token->linescrossed > crossline)\n\t\t{\n\t\t\tPC_UnreadSourceToken(source, token);\n\t\t\treturn qfalse;\n\t\t} //end if\n\t\tcrossline = 1;\n\t} while(!strcmp(token->string, \"\\\\\"));\n\treturn qtrue;\n} //end of the function PC_ReadLine\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PC_WhiteSpaceBeforeToken(token_t *token)\n{\n\treturn token->endwhitespace_p - token->whitespace_p > 0;\n} //end of the function PC_WhiteSpaceBeforeToken\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nvoid PC_ClearTokenWhiteSpace(token_t *token)\n{\n\ttoken->whitespace_p = NULL;\n\ttoken->endwhitespace_p = NULL;\n\ttoken->linescrossed = 0;\n} //end of the function PC_ClearTokenWhiteSpace\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PC_Directive_undef(source_t *source)\n{\n\ttoken_t token;\n\tdefine_t *define, *lastdefine;\n\tint hash;\n\n\tif (source->skip > 0) return qtrue;\n\t//\n\tif (!PC_ReadLine(source, &token))\n\t{\n\t\tSourceError(source, \"undef without name\");\n\t\treturn qfalse;\n\t} //end if\n\tif (token.type != TT_NAME)\n\t{\n\t\tPC_UnreadSourceToken(source, &token);\n\t\tSourceError(source, \"expected name, found %s\", token.string);\n\t\treturn qfalse;\n\t} //end if\n#if DEFINEHASHING\n\n\thash = PC_NameHash(token.string);\n\tfor (lastdefine = NULL, define = source->definehash[hash]; define; define = define->hashnext)\n\t{\n\t\tif (!strcmp(define->name, token.string))\n\t\t{\n\t\t\tif (define->flags & DEFINE_FIXED)\n\t\t\t{\n\t\t\t\tSourceWarning(source, \"can't undef %s\", token.string);\n\t\t\t} //end if\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (lastdefine) lastdefine->hashnext = define->hashnext;\n\t\t\t\telse source->definehash[hash] = define->hashnext;\n\t\t\t\tPC_FreeDefine(define);\n\t\t\t} //end else\n\t\t\tbreak;\n\t\t} //end if\n\t\tlastdefine = define;\n\t} //end for\n#else //DEFINEHASHING\n\tfor (lastdefine = NULL, define = source->defines; define; define = define->next)\n\t{\n\t\tif (!strcmp(define->name, token.string))\n\t\t{\n\t\t\tif (define->flags & DEFINE_FIXED)\n\t\t\t{\n\t\t\t\tSourceWarning(source, \"can't undef %s\", token.string);\n\t\t\t} //end if\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (lastdefine) lastdefine->next = define->next;\n\t\t\t\telse source->defines = define->next;\n\t\t\t\tPC_FreeDefine(define);\n\t\t\t} //end else\n\t\t\tbreak;\n\t\t} //end if\n\t\tlastdefine = define;\n\t} //end for\n#endif //DEFINEHASHING\n\treturn qtrue;\n} //end of the function PC_Directive_undef\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PC_Directive_define(source_t *source)\n{\n\ttoken_t token, *t, *last;\n\tdefine_t *define;\n\n\tif (source->skip > 0) return qtrue;\n\t//\n\tif (!PC_ReadLine(source, &token))\n\t{\n\t\tSourceError(source, \"#define without name\");\n\t\treturn qfalse;\n\t} //end if\n\tif (token.type != TT_NAME)\n\t{\n\t\tPC_UnreadSourceToken(source, &token);\n\t\tSourceError(source, \"expected name after #define, found %s\", token.string);\n\t\treturn qfalse;\n\t} //end if\n\t//check if the define already exists\n#if DEFINEHASHING\n\tdefine = PC_FindHashedDefine(source->definehash, token.string);\n#else\n\tdefine = PC_FindDefine(source->defines, token.string);\n#endif //DEFINEHASHING\n\tif (define)\n\t{\n\t\tif (define->flags & DEFINE_FIXED)\n\t\t{\n\t\t\tSourceError(source, \"can't redefine %s\", token.string);\n\t\t\treturn qfalse;\n\t\t} //end if\n\t\tSourceWarning(source, \"redefinition of %s\", token.string);\n\t\t//unread the define name before executing the #undef directive\n\t\tPC_UnreadSourceToken(source, &token);\n\t\tif (!PC_Directive_undef(source)) return qfalse;\n\t\t//if the define was not removed (define->flags & DEFINE_FIXED)\n#if DEFINEHASHING\n\t\tdefine = PC_FindHashedDefine(source->definehash, token.string);\n#else\n\t\tdefine = PC_FindDefine(source->defines, token.string);\n#endif //DEFINEHASHING\n\t} //end if\n\t//allocate define\n\tdefine = (define_t *) GetMemory(sizeof(define_t) + (int)strlen(token.string) + 1);\n\tCom_Memset(define, 0, sizeof(define_t));\n\tdefine->name = (char *) define + sizeof(define_t);\n\tstrcpy(define->name, token.string);\n\t//add the define to the source\n#if DEFINEHASHING\n\tPC_AddDefineToHash(define, source->definehash);\n#else //DEFINEHASHING\n\tdefine->next = source->defines;\n\tsource->defines = define;\n#endif //DEFINEHASHING\n\t//if nothing is defined, just return\n\tif (!PC_ReadLine(source, &token)) return qtrue;\n\t//if it is a define with parameters\n\tif (!PC_WhiteSpaceBeforeToken(&token) && !strcmp(token.string, \"(\"))\n\t{\n\t\t//read the define parameters\n\t\tlast = NULL;\n\t\tif (!PC_CheckTokenString(source, \")\"))\n\t\t{\n\t\t\twhile(1)\n\t\t\t{\n\t\t\t\tif (!PC_ReadLine(source, &token))\n\t\t\t\t{\n\t\t\t\t\tSourceError(source, \"expected define parameter\");\n\t\t\t\t\treturn qfalse;\n\t\t\t\t} //end if\n\t\t\t\t//if it isn't a name\n\t\t\t\tif (token.type != TT_NAME)\n\t\t\t\t{\n\t\t\t\t\tSourceError(source, \"invalid define parameter\");\n\t\t\t\t\treturn qfalse;\n\t\t\t\t} //end if\n\t\t\t\t//\n\t\t\t\tif (PC_FindDefineParm(define, token.string) >= 0)\n\t\t\t\t{\n\t\t\t\t\tSourceError(source, \"two the same define parameters\");\n\t\t\t\t\treturn qfalse;\n\t\t\t\t} //end if\n\t\t\t\t//add the define parm\n\t\t\t\tt = PC_CopyToken(&token);\n\t\t\t\tPC_ClearTokenWhiteSpace(t);\n\t\t\t\tt->next = NULL;\n\t\t\t\tif (last) last->next = t;\n\t\t\t\telse define->parms = t;\n\t\t\t\tlast = t;\n\t\t\t\tdefine->numparms++;\n\t\t\t\t//read next token\n\t\t\t\tif (!PC_ReadLine(source, &token))\n\t\t\t\t{\n\t\t\t\t\tSourceError(source, \"define parameters not terminated\");\n\t\t\t\t\treturn qfalse;\n\t\t\t\t} //end if\n\t\t\t\t//\n\t\t\t\tif (!strcmp(token.string, \")\")) break;\n\t\t\t\t//then it must be a comma\n\t\t\t\tif (strcmp(token.string, \",\"))\n\t\t\t\t{\n\t\t\t\t\tSourceError(source, \"define not terminated\");\n\t\t\t\t\treturn qfalse;\n\t\t\t\t} //end if\n\t\t\t} //end while\n\t\t} //end if\n\t\tif (!PC_ReadLine(source, &token)) return qtrue;\n\t} //end if\n\t//read the defined stuff\n\tlast = NULL;\n\tdo\n\t{\n\t\tt = PC_CopyToken(&token);\n\t\tif (t->type == TT_NAME && !strcmp(t->string, define->name))\n\t\t{\n\t\t\tSourceError(source, \"recursive define (removed recursion)\");\n\t\t\tcontinue;\n\t\t} //end if\n\t\tPC_ClearTokenWhiteSpace(t);\n\t\tt->next = NULL;\n\t\tif (last) last->next = t;\n\t\telse define->tokens = t;\n\t\tlast = t;\n\t} while(PC_ReadLine(source, &token));\n\t//\n\tif (last)\n\t{\n\t\t//check for merge operators at the beginning or end\n\t\tif (!strcmp(define->tokens->string, \"##\") ||\n\t\t\t\t!strcmp(last->string, \"##\"))\n\t\t{\n\t\t\tSourceError(source, \"define with misplaced ##\");\n\t\t\treturn qfalse;\n\t\t} //end if\n\t} //end if\n\treturn qtrue;\n} //end of the function PC_Directive_define\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\ndefine_t *PC_DefineFromString(char *string)\n{\n\tscript_t *script;\n\tsource_t src;\n\ttoken_t *t;\n\tint res, i;\n\tdefine_t *def;\n\n\tPC_InitTokenHeap();\n\n\tscript = LoadScriptMemory(string, (int)strlen(string), \"*extern\");\n\t//create a new source\n\tCom_Memset(&src, 0, sizeof(source_t));\n\tstrncpy(src.filename, \"*extern\", MAX_PATH);\n\tsrc.scriptstack = script;\n#if DEFINEHASHING\n\tsrc.definehash = (define_t**) GetClearedMemory(DEFINEHASHSIZE * sizeof(define_t *));\n#endif //DEFINEHASHING\n\t//create a define from the source\n\tres = PC_Directive_define(&src);\n\t//free any tokens if left\n\tfor (t = src.tokens; t; t = src.tokens)\n\t{\n\t\tsrc.tokens = src.tokens->next;\n\t\tPC_FreeToken(t);\n\t} //end for\n#ifdef DEFINEHASHING\n\tdef = NULL;\n\tfor (i = 0; i < DEFINEHASHSIZE; i++)\n\t{\n\t\tif (src.definehash[i])\n\t\t{\n\t\t\tdef = src.definehash[i];\n\t\t\tbreak;\n\t\t} //end if\n\t} //end for\n#else\n\tdef = src.defines;\n#endif //DEFINEHASHING\n\t//\n#if DEFINEHASHING\n\tFreeMemory(src.definehash);\n#endif //DEFINEHASHING\n\t//\n\tFreeScript(script);\n\t//if the define was created succesfully\n\tif (res > 0) return def;\n\t//free the define is created\n\tif (src.defines) PC_FreeDefine(def);\n\t//\n\treturn NULL;\n} //end of the function PC_DefineFromString\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PC_AddDefine(source_t *source, char *string)\n{\n\tdefine_t *define;\n\n\tdefine = PC_DefineFromString(string);\n\tif (!define) return qfalse;\n#if DEFINEHASHING\n\tPC_AddDefineToHash(define, source->definehash);\n#else //DEFINEHASHING\n\tdefine->next = source->defines;\n\tsource->defines = define;\n#endif //DEFINEHASHING\n\treturn qtrue;\n} //end of the function PC_AddDefine\n//============================================================================\n// add a globals define that will be added to all opened sources\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PC_AddGlobalDefine(char *string)\n{\n\tdefine_t *define;\n\n\tdefine = PC_DefineFromString(string);\n\tif (!define) return qfalse;\n\tdefine->next = globaldefines;\n\tglobaldefines = define;\n\treturn qtrue;\n} //end of the function PC_AddGlobalDefine\n//============================================================================\n// remove the given global define\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PC_RemoveGlobalDefine(char *name)\n{\n\tdefine_t *define;\n\n\tdefine = PC_FindDefine(globaldefines, name);\n\tif (define)\n\t{\n\t\tPC_FreeDefine(define);\n\t\treturn qtrue;\n\t} //end if\n\treturn qfalse;\n} //end of the function PC_RemoveGlobalDefine\n//============================================================================\n// remove all globals defines\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nvoid PC_RemoveAllGlobalDefines(void)\n{\n\tdefine_t *define;\n\n\tfor (define = globaldefines; define; define = globaldefines)\n\t{\n\t\tglobaldefines = globaldefines->next;\n\t\tPC_FreeDefine(define);\n\t} //end for\n} //end of the function PC_RemoveAllGlobalDefines\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\ndefine_t *PC_CopyDefine(source_t *source, define_t *define)\n{\n\tdefine_t *newdefine;\n\ttoken_t *token, *newtoken, *lasttoken;\n\n\tnewdefine = (define_t *) GetMemory(sizeof(define_t) + (int)strlen(define->name) + 1);\n\t//copy the define name\n\tnewdefine->name = (char *) newdefine + sizeof(define_t);\n\tstrcpy(newdefine->name, define->name);\n\tnewdefine->flags = define->flags;\n\tnewdefine->builtin = define->builtin;\n\tnewdefine->numparms = define->numparms;\n\t//the define is not linked\n\tnewdefine->next = NULL;\n\tnewdefine->hashnext = NULL;\n\t//copy the define tokens\n\tnewdefine->tokens = NULL;\n\tfor (lasttoken = NULL, token = define->tokens; token; token = token->next)\n\t{\n\t\tnewtoken = PC_CopyToken(token);\n\t\tnewtoken->next = NULL;\n\t\tif (lasttoken) lasttoken->next = newtoken;\n\t\telse newdefine->tokens = newtoken;\n\t\tlasttoken = newtoken;\n\t} //end for\n\t//copy the define parameters\n\tnewdefine->parms = NULL;\n\tfor (lasttoken = NULL, token = define->parms; token; token = token->next)\n\t{\n\t\tnewtoken = PC_CopyToken(token);\n\t\tnewtoken->next = NULL;\n\t\tif (lasttoken) lasttoken->next = newtoken;\n\t\telse newdefine->parms = newtoken;\n\t\tlasttoken = newtoken;\n\t} //end for\n\treturn newdefine;\n} //end of the function PC_CopyDefine\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nvoid PC_AddGlobalDefinesToSource(source_t *source)\n{\n\tdefine_t *define, *newdefine;\n\n\tfor (define = globaldefines; define; define = define->next)\n\t{\n\t\tnewdefine = PC_CopyDefine(source, define);\n#if DEFINEHASHING\n\t\tPC_AddDefineToHash(newdefine, source->definehash);\n#else //DEFINEHASHING\n\t\tnewdefine->next = source->defines;\n\t\tsource->defines = newdefine;\n#endif //DEFINEHASHING\n\t} //end for\n} //end of the function PC_AddGlobalDefinesToSource\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PC_Directive_if_def(source_t *source, int type)\n{\n\ttoken_t token;\n\tdefine_t *d;\n\tint skip;\n\n\tif (!PC_ReadLine(source, &token))\n\t{\n\t\tSourceError(source, \"#ifdef without name\");\n\t\treturn qfalse;\n\t} //end if\n\tif (token.type != TT_NAME)\n\t{\n\t\tPC_UnreadSourceToken(source, &token);\n\t\tSourceError(source, \"expected name after #ifdef, found %s\", token.string);\n\t\treturn qfalse;\n\t} //end if\n#if DEFINEHASHING\n\td = PC_FindHashedDefine(source->definehash, token.string);\n#else\n\td = PC_FindDefine(source->defines, token.string);\n#endif //DEFINEHASHING\n\tskip = (type == INDENT_IFDEF) == (d == NULL);\n\tPC_PushIndent(source, type, skip);\n\treturn qtrue;\n} //end of the function PC_Directiveif_def\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PC_Directive_ifdef(source_t *source)\n{\n\treturn PC_Directive_if_def(source, INDENT_IFDEF);\n} //end of the function PC_Directive_ifdef\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PC_Directive_ifndef(source_t *source)\n{\n\treturn PC_Directive_if_def(source, INDENT_IFNDEF);\n} //end of the function PC_Directive_ifndef\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PC_Directive_else(source_t *source)\n{\n\tint type, skip;\n\n\tPC_PopIndent(source, &type, &skip);\n\tif (!type)\n\t{\n\t\tSourceError(source, \"misplaced #else\");\n\t\treturn qfalse;\n\t} //end if\n\tif (type == INDENT_ELSE)\n\t{\n\t\tSourceError(source, \"#else after #else\");\n\t\treturn qfalse;\n\t} //end if\n\tPC_PushIndent(source, INDENT_ELSE, !skip);\n\treturn qtrue;\n} //end of the function PC_Directive_else\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PC_Directive_endif(source_t *source)\n{\n\tint type, skip;\n\n\tPC_PopIndent(source, &type, &skip);\n\tif (!type)\n\t{\n\t\tSourceError(source, \"misplaced #endif\");\n\t\treturn qfalse;\n\t} //end if\n\treturn qtrue;\n} //end of the function PC_Directive_endif\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\ntypedef struct operator_s\n{\n\tint operatorCode;\n\tint priority;\n\tint parentheses;\n\tstruct operator_s *prev, *next;\n} operator_t;\n\ntypedef struct value_s\n{\n\tsigned long int intvalue;\n\tdouble floatvalue;\n\tint parentheses;\n\tstruct value_s *prev, *next;\n} value_t;\n\nint PC_OperatorPriority(int op)\n{\n\tswitch(op)\n\t{\n\t\tcase P_MUL: return 15;\n\t\tcase P_DIV: return 15;\n\t\tcase P_MOD: return 15;\n\t\tcase P_ADD: return 14;\n\t\tcase P_SUB: return 14;\n\n\t\tcase P_LOGIC_AND: return 7;\n\t\tcase P_LOGIC_OR: return 6;\n\t\tcase P_LOGIC_GEQ: return 12;\n\t\tcase P_LOGIC_LEQ: return 12;\n\t\tcase P_LOGIC_EQ: return 11;\n\t\tcase P_LOGIC_UNEQ: return 11;\n\n\t\tcase P_LOGIC_NOT: return 16;\n\t\tcase P_LOGIC_GREATER: return 12;\n\t\tcase P_LOGIC_LESS: return 12;\n\n\t\tcase P_RSHIFT: return 13;\n\t\tcase P_LSHIFT: return 13;\n\n\t\tcase P_BIN_AND: return 10;\n\t\tcase P_BIN_OR: return 8;\n\t\tcase P_BIN_XOR: return 9;\n\t\tcase P_BIN_NOT: return 16;\n\n\t\tcase P_COLON: return 5;\n\t\tcase P_QUESTIONMARK: return 5;\n\t} //end switch\n\treturn qfalse;\n} //end of the function PC_OperatorPriority\n\n//#define AllocValue()\t\t\tGetClearedMemory(sizeof(value_t));\n//#define FreeValue(val)\t\tFreeMemory(val)\n//#define AllocOperator(op)\t\top = (operator_t *) GetClearedMemory(sizeof(operator_t));\n//#define FreeOperator(op)\t\tFreeMemory(op);\n\n#define MAX_VALUES\t\t64\n#define MAX_OPERATORS\t64\n#define AllocValue(val)\t\t\t\t\t\t\t\t\t\\\n\tif (numvalues >= MAX_VALUES) {\t\t\t\t\t\t\\\n\t\tSourceError(source, \"out of value space\\n\");\t\t\\\n\t\terror = 1;\t\t\t\t\t\t\t\t\t\t\\\n\t\tbreak;\t\t\t\t\t\t\t\t\t\t\t\\\n\t}\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\telse\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\tval = &value_heap[numvalues++];\n#define FreeValue(val)\n//\n#define AllocOperator(op)\t\t\t\t\t\t\t\t\\\n\tif (numoperators >= MAX_OPERATORS) {\t\t\t\t\\\n\t\tSourceError(source, \"out of operator space\\n\");\t\\\n\t\terror = 1;\t\t\t\t\t\t\t\t\t\t\\\n\t\tbreak;\t\t\t\t\t\t\t\t\t\t\t\\\n\t}\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\telse\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\top = &operator_heap[numoperators++];\n#define FreeOperator(op)\n\nint PC_EvaluateTokens(source_t *source, token_t *tokens, signed long int *intvalue,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdouble *floatvalue, int integer)\n{\n\toperator_t *o, *firstoperator, *lastoperator;\n\tvalue_t *v, *firstvalue, *lastvalue, *v1, *v2;\n\ttoken_t *t;\n\tint brace = 0;\n\tint parentheses = 0;\n\tint error = 0;\n\tint lastwasvalue = 0;\n\tint negativevalue = 0;\n\tint questmarkintvalue = 0;\n\tdouble questmarkfloatvalue = 0;\n\tint gotquestmarkvalue = qfalse;\n\tint lastoperatortype = 0;\n\t//\n\toperator_t operator_heap[MAX_OPERATORS];\n\tint numoperators = 0;\n\tvalue_t value_heap[MAX_VALUES];\n\tint numvalues = 0;\n\n\tfirstoperator = lastoperator = NULL;\n\tfirstvalue = lastvalue = NULL;\n\tif (intvalue) *intvalue = 0;\n\tif (floatvalue) *floatvalue = 0;\n\tfor (t = tokens; t; t = t->next)\n\t{\n\t\tswitch(t->type)\n\t\t{\n\t\t\tcase TT_NAME:\n\t\t\t{\n\t\t\t\tif (lastwasvalue || negativevalue)\n\t\t\t\t{\n\t\t\t\t\tSourceError(source, \"syntax error in #if/#elif\");\n\t\t\t\t\terror = 1;\n\t\t\t\t\tbreak;\n\t\t\t\t} //end if\n\t\t\t\tif (strcmp(t->string, \"defined\"))\n\t\t\t\t{\n\t\t\t\t\tSourceError(source, \"undefined name %s in #if/#elif\", t->string);\n\t\t\t\t\terror = 1;\n\t\t\t\t\tbreak;\n\t\t\t\t} //end if\n\t\t\t\tt = t->next;\n\t\t\t\tif (!strcmp(t->string, \"(\"))\n\t\t\t\t{\n\t\t\t\t\tbrace = qtrue;\n\t\t\t\t\tt = t->next;\n\t\t\t\t} //end if\n\t\t\t\tif (!t || t->type != TT_NAME)\n\t\t\t\t{\n\t\t\t\t\tSourceError(source, \"defined without name in #if/#elif\");\n\t\t\t\t\terror = 1;\n\t\t\t\t\tbreak;\n\t\t\t\t} //end if\n\t\t\t\t//v = (value_t *) GetClearedMemory(sizeof(value_t));\n\t\t\t\tAllocValue(v);\n#if DEFINEHASHING\n\t\t\t\tif (PC_FindHashedDefine(source->definehash, t->string))\n#else\t\t\t\n\t\t\t\tif (PC_FindDefine(source->defines, t->string))\n#endif //DEFINEHASHING\n\t\t\t\t{\n\t\t\t\t\tv->intvalue = 1;\n\t\t\t\t\tv->floatvalue = 1;\n\t\t\t\t} //end if\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tv->intvalue = 0;\n\t\t\t\t\tv->floatvalue = 0;\n\t\t\t\t} //end else\n\t\t\t\tv->parentheses = parentheses;\n\t\t\t\tv->next = NULL;\n\t\t\t\tv->prev = lastvalue;\n\t\t\t\tif (lastvalue) lastvalue->next = v;\n\t\t\t\telse firstvalue = v;\n\t\t\t\tlastvalue = v;\n\t\t\t\tif (brace)\n\t\t\t\t{\n\t\t\t\t\tt = t->next;\n\t\t\t\t\tif (!t || strcmp(t->string, \")\"))\n\t\t\t\t\t{\n\t\t\t\t\t\tSourceError(source, \"defined without ) in #if/#elif\");\n\t\t\t\t\t\terror = 1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t} //end if\n\t\t\t\t} //end if\n\t\t\t\tbrace = qfalse;\n\t\t\t\t// defined() creates a value\n\t\t\t\tlastwasvalue = 1;\n\t\t\t\tbreak;\n\t\t\t} //end case\n\t\t\tcase TT_NUMBER:\n\t\t\t{\n\t\t\t\tif (lastwasvalue)\n\t\t\t\t{\n\t\t\t\t\tSourceError(source, \"syntax error in #if/#elif\");\n\t\t\t\t\terror = 1;\n\t\t\t\t\tbreak;\n\t\t\t\t} //end if\n\t\t\t\t//v = (value_t *) GetClearedMemory(sizeof(value_t));\n\t\t\t\tAllocValue(v);\n\t\t\t\tif (negativevalue)\n\t\t\t\t{\n\t\t\t\t\tv->intvalue = - (signed int) t->intvalue;\n\t\t\t\t\tv->floatvalue = - t->floatvalue;\n\t\t\t\t} //end if\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tv->intvalue = t->intvalue;\n\t\t\t\t\tv->floatvalue = t->floatvalue;\n\t\t\t\t} //end else\n\t\t\t\tv->parentheses = parentheses;\n\t\t\t\tv->next = NULL;\n\t\t\t\tv->prev = lastvalue;\n\t\t\t\tif (lastvalue) lastvalue->next = v;\n\t\t\t\telse firstvalue = v;\n\t\t\t\tlastvalue = v;\n\t\t\t\t//last token was a value\n\t\t\t\tlastwasvalue = 1;\n\t\t\t\t//\n\t\t\t\tnegativevalue = 0;\n\t\t\t\tbreak;\n\t\t\t} //end case\n\t\t\tcase TT_PUNCTUATION:\n\t\t\t{\n\t\t\t\tif (negativevalue)\n\t\t\t\t{\n\t\t\t\t\tSourceError(source, \"misplaced minus sign in #if/#elif\");\n\t\t\t\t\terror = 1;\n\t\t\t\t\tbreak;\n\t\t\t\t} //end if\n\t\t\t\tif (t->subtype == P_PARENTHESESOPEN)\n\t\t\t\t{\n\t\t\t\t\tparentheses++;\n\t\t\t\t\tbreak;\n\t\t\t\t} //end if\n\t\t\t\telse if (t->subtype == P_PARENTHESESCLOSE)\n\t\t\t\t{\n\t\t\t\t\tparentheses--;\n\t\t\t\t\tif (parentheses < 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tSourceError(source, \"too many ) in #if/#elsif\");\n\t\t\t\t\t\terror = 1;\n\t\t\t\t\t} //end if\n\t\t\t\t\tbreak;\n\t\t\t\t} //end else if\n\t\t\t\t//check for invalid operators on floating point values\n\t\t\t\tif (!integer)\n\t\t\t\t{\n\t\t\t\t\tif (t->subtype == P_BIN_NOT || t->subtype == P_MOD ||\n\t\t\t\t\t\tt->subtype == P_RSHIFT || t->subtype == P_LSHIFT ||\n\t\t\t\t\t\tt->subtype == P_BIN_AND || t->subtype == P_BIN_OR ||\n\t\t\t\t\t\tt->subtype == P_BIN_XOR)\n\t\t\t\t\t{\n\t\t\t\t\t\tSourceError(source, \"illigal operator %s on floating point operands\\n\", t->string);\n\t\t\t\t\t\terror = 1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t} //end if\n\t\t\t\t} //end if\n\t\t\t\tswitch(t->subtype)\n\t\t\t\t{\n\t\t\t\t\tcase P_LOGIC_NOT:\n\t\t\t\t\tcase P_BIN_NOT:\n\t\t\t\t\t{\n\t\t\t\t\t\tif (lastwasvalue)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tSourceError(source, \"! or ~ after value in #if/#elif\");\n\t\t\t\t\t\t\terror = 1;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t} //end case\n\t\t\t\t\tcase P_INC:\n\t\t\t\t\tcase P_DEC:\n\t\t\t\t\t{\n\t\t\t\t\t\tSourceError(source, \"++ or -- used in #if/#elif\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t} //end case\n\t\t\t\t\tcase P_SUB:\n\t\t\t\t\t{\n\t\t\t\t\t\tif (!lastwasvalue)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tnegativevalue = 1;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t} //end case\n\t\t\t\t\t\n\t\t\t\t\tcase P_MUL:\n\t\t\t\t\tcase P_DIV:\n\t\t\t\t\tcase P_MOD:\n\t\t\t\t\tcase P_ADD:\n\n\t\t\t\t\tcase P_LOGIC_AND:\n\t\t\t\t\tcase P_LOGIC_OR:\n\t\t\t\t\tcase P_LOGIC_GEQ:\n\t\t\t\t\tcase P_LOGIC_LEQ:\n\t\t\t\t\tcase P_LOGIC_EQ:\n\t\t\t\t\tcase P_LOGIC_UNEQ:\n\n\t\t\t\t\tcase P_LOGIC_GREATER:\n\t\t\t\t\tcase P_LOGIC_LESS:\n\n\t\t\t\t\tcase P_RSHIFT:\n\t\t\t\t\tcase P_LSHIFT:\n\n\t\t\t\t\tcase P_BIN_AND:\n\t\t\t\t\tcase P_BIN_OR:\n\t\t\t\t\tcase P_BIN_XOR:\n\n\t\t\t\t\tcase P_COLON:\n\t\t\t\t\tcase P_QUESTIONMARK:\n\t\t\t\t\t{\n\t\t\t\t\t\tif (!lastwasvalue)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tSourceError(source, \"operator %s after operator in #if/#elif\", t->string);\n\t\t\t\t\t\t\terror = 1;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t} //end if\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t} //end case\n\t\t\t\t\tdefault:\n\t\t\t\t\t{\n\t\t\t\t\t\tSourceError(source, \"invalid operator %s in #if/#elif\", t->string);\n\t\t\t\t\t\terror = 1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t} //end default\n\t\t\t\t} //end switch\n\t\t\t\tif (!error && !negativevalue)\n\t\t\t\t{\n\t\t\t\t\t//o = (operator_t *) GetClearedMemory(sizeof(operator_t));\n\t\t\t\t\tAllocOperator(o);\n\t\t\t\t\to->operatorCode = t->subtype;\n\t\t\t\t\to->priority = PC_OperatorPriority(t->subtype);\n\t\t\t\t\to->parentheses = parentheses;\n\t\t\t\t\to->next = NULL;\n\t\t\t\t\to->prev = lastoperator;\n\t\t\t\t\tif (lastoperator) lastoperator->next = o;\n\t\t\t\t\telse firstoperator = o;\n\t\t\t\t\tlastoperator = o;\n\t\t\t\t\tlastwasvalue = 0;\n\t\t\t\t} //end if\n\t\t\t\tbreak;\n\t\t\t} //end case\n\t\t\tdefault:\n\t\t\t{\n\t\t\t\tSourceError(source, \"unknown %s in #if/#elif\", t->string);\n\t\t\t\terror = 1;\n\t\t\t\tbreak;\n\t\t\t} //end default\n\t\t} //end switch\n\t\tif (error) break;\n\t} //end for\n\tif (!error)\n\t{\n\t\tif (!lastwasvalue)\n\t\t{\n\t\t\tSourceError(source, \"trailing operator in #if/#elif\");\n\t\t\terror = 1;\n\t\t} //end if\n\t\telse if (parentheses)\n\t\t{\n\t\t\tSourceError(source, \"too many ( in #if/#elif\");\n\t\t\terror = 1;\n\t\t} //end else if\n\t} //end if\n\t//\n\tgotquestmarkvalue = qfalse;\n\tquestmarkintvalue = 0;\n\tquestmarkfloatvalue = 0;\n\t//while there are operators\n\twhile(!error && firstoperator)\n\t{\n\t\tv = firstvalue;\n\t\tfor (o = firstoperator; o->next; o = o->next)\n\t\t{\n\t\t\t//if the current operator is nested deeper in parentheses\n\t\t\t//than the next operator\n\t\t\tif (o->parentheses > o->next->parentheses) break;\n\t\t\t//if the current and next operator are nested equally deep in parentheses\n\t\t\tif (o->parentheses == o->next->parentheses)\n\t\t\t{\n\t\t\t\t//if the priority of the current operator is equal or higher\n\t\t\t\t//than the priority of the next operator\n\t\t\t\tif (o->priority >= o->next->priority) break;\n\t\t\t} //end if\n\t\t\t//if the arity of the operator isn't equal to 1\n\t\t\tif (o->operatorCode != P_LOGIC_NOT\n\t\t\t\t\t&& o->operatorCode != P_BIN_NOT) v = v->next;\n\t\t\t//if there's no value or no next value\n\t\t\tif (!v)\n\t\t\t{\n\t\t\t\tSourceError(source, \"mising values in #if/#elif\");\n\t\t\t\terror = 1;\n\t\t\t\tbreak;\n\t\t\t} //end if\n\t\t} //end for\n\t\tif (error) break;\n\t\tv1 = v;\n\t\tv2 = v->next;\n#ifdef DEBUG_EVAL\n\t\tif (integer)\n\t\t{\n\t\t\tLog_Write(\"operator %s, value1 = %d\", PunctuationFromNum(source->scriptstack, o->operator), v1->intvalue);\n\t\t\tif (v2) Log_Write(\"value2 = %d\", v2->intvalue);\n\t\t} //end if\n\t\telse\n\t\t{\n\t\t\tLog_Write(\"operator %s, value1 = %f\", PunctuationFromNum(source->scriptstack, o->operator), v1->floatvalue);\n\t\t\tif (v2) Log_Write(\"value2 = %f\", v2->floatvalue);\n\t\t} //end else\n#endif //DEBUG_EVAL\n\t\tswitch(o->operatorCode)\n\t\t{\n\t\t\tcase P_LOGIC_NOT:\t\tv1->intvalue = !v1->intvalue;\n\t\t\t\t\t\t\t\t\tv1->floatvalue = !v1->floatvalue; break;\n\t\t\tcase P_BIN_NOT:\t\t\tv1->intvalue = ~v1->intvalue;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\tcase P_MUL:\t\t\t\tv1->intvalue *= v2->intvalue;\n\t\t\t\t\t\t\t\t\tv1->floatvalue *= v2->floatvalue; break;\n\t\t\tcase P_DIV:\t\t\t\tif (!v2->intvalue || !v2->floatvalue)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tSourceError(source, \"divide by zero in #if/#elif\\n\");\n\t\t\t\t\t\t\t\t\t\terror = 1;\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tv1->intvalue /= v2->intvalue;\n\t\t\t\t\t\t\t\t\tv1->floatvalue /= v2->floatvalue; break;\n\t\t\tcase P_MOD:\t\t\t\tif (!v2->intvalue)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tSourceError(source, \"divide by zero in #if/#elif\\n\");\n\t\t\t\t\t\t\t\t\t\terror = 1;\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tv1->intvalue %= v2->intvalue; break;\n\t\t\tcase P_ADD:\t\t\t\tv1->intvalue += v2->intvalue;\n\t\t\t\t\t\t\t\t\tv1->floatvalue += v2->floatvalue; break;\n\t\t\tcase P_SUB:\t\t\t\tv1->intvalue -= v2->intvalue;\n\t\t\t\t\t\t\t\t\tv1->floatvalue -= v2->floatvalue; break;\n\t\t\tcase P_LOGIC_AND:\t\tv1->intvalue = v1->intvalue && v2->intvalue;\n\t\t\t\t\t\t\t\t\tv1->floatvalue = v1->floatvalue && v2->floatvalue; break;\n\t\t\tcase P_LOGIC_OR:\t\tv1->intvalue = v1->intvalue || v2->intvalue;\n\t\t\t\t\t\t\t\t\tv1->floatvalue = v1->floatvalue || v2->floatvalue; break;\n\t\t\tcase P_LOGIC_GEQ:\t\tv1->intvalue = v1->intvalue >= v2->intvalue;\n\t\t\t\t\t\t\t\t\tv1->floatvalue = v1->floatvalue >= v2->floatvalue; break;\n\t\t\tcase P_LOGIC_LEQ:\t\tv1->intvalue = v1->intvalue <= v2->intvalue;\n\t\t\t\t\t\t\t\t\tv1->floatvalue = v1->floatvalue <= v2->floatvalue; break;\n\t\t\tcase P_LOGIC_EQ:\t\tv1->intvalue = v1->intvalue == v2->intvalue;\n\t\t\t\t\t\t\t\t\tv1->floatvalue = v1->floatvalue == v2->floatvalue; break;\n\t\t\tcase P_LOGIC_UNEQ:\t\tv1->intvalue = v1->intvalue != v2->intvalue;\n\t\t\t\t\t\t\t\t\tv1->floatvalue = v1->floatvalue != v2->floatvalue; break;\n\t\t\tcase P_LOGIC_GREATER:\tv1->intvalue = v1->intvalue > v2->intvalue;\n\t\t\t\t\t\t\t\t\tv1->floatvalue = v1->floatvalue > v2->floatvalue; break;\n\t\t\tcase P_LOGIC_LESS:\t\tv1->intvalue = v1->intvalue < v2->intvalue;\n\t\t\t\t\t\t\t\t\tv1->floatvalue = v1->floatvalue < v2->floatvalue; break;\n\t\t\tcase P_RSHIFT:\t\t\tv1->intvalue >>= v2->intvalue;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\tcase P_LSHIFT:\t\t\tv1->intvalue <<= v2->intvalue;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\tcase P_BIN_AND:\t\t\tv1->intvalue &= v2->intvalue;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\tcase P_BIN_OR:\t\t\tv1->intvalue |= v2->intvalue;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\tcase P_BIN_XOR:\t\t\tv1->intvalue ^= v2->intvalue;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\tcase P_COLON:\n\t\t\t{\n\t\t\t\tif (!gotquestmarkvalue)\n\t\t\t\t{\n\t\t\t\t\tSourceError(source, \": without ? in #if/#elif\");\n\t\t\t\t\terror = 1;\n\t\t\t\t\tbreak;\n\t\t\t\t} //end if\n\t\t\t\tif (integer)\n\t\t\t\t{\n\t\t\t\t\tif (!questmarkintvalue) v1->intvalue = v2->intvalue;\n\t\t\t\t} //end if\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (!questmarkfloatvalue) v1->floatvalue = v2->floatvalue;\n\t\t\t\t} //end else\n\t\t\t\tgotquestmarkvalue = qfalse;\n\t\t\t\tbreak;\n\t\t\t} //end case\n\t\t\tcase P_QUESTIONMARK:\n\t\t\t{\n\t\t\t\tif (gotquestmarkvalue)\n\t\t\t\t{\n\t\t\t\t\tSourceError(source, \"? after ? in #if/#elif\");\n\t\t\t\t\terror = 1;\n\t\t\t\t\tbreak;\n\t\t\t\t} //end if\n\t\t\t\tquestmarkintvalue = v1->intvalue;\n\t\t\t\tquestmarkfloatvalue = v1->floatvalue;\n\t\t\t\tgotquestmarkvalue = qtrue;\n\t\t\t\tbreak;\n\t\t\t} //end if\n\t\t} //end switch\n#ifdef DEBUG_EVAL\n\t\tif (integer) Log_Write(\"result value = %d\", v1->intvalue);\n\t\telse Log_Write(\"result value = %f\", v1->floatvalue);\n#endif //DEBUG_EVAL\n\t\tif (error) break;\n\t\tlastoperatortype = o->operatorCode;\n\t\t//if not an operator with arity 1\n\t\tif (o->operatorCode != P_LOGIC_NOT\n\t\t\t&& o->operatorCode != P_BIN_NOT)\n\t\t{\n\t\t\t//remove the second value if not question mark operator\n\t\t\tif (o->operatorCode != P_QUESTIONMARK) v = v->next;\n\t\t\t//\n\t\t\tif (v->prev) v->prev->next = v->next;\n\t\t\telse firstvalue = v->next;\n\t\t\tif (v->next) v->next->prev = v->prev;\n\t\t\telse lastvalue = v->prev;\n\t\t\t//FreeMemory(v);\n\t\t\tFreeValue(v);\n\t\t} //end if\n\t\t//remove the operator\n\t\tif (o->prev) o->prev->next = o->next;\n\t\telse firstoperator = o->next;\n\t\tif (o->next) o->next->prev = o->prev;\n\t\telse lastoperator = o->prev;\n\t\t//FreeMemory(o);\n\t\tFreeOperator(o);\n\t} //end while\n\tif (firstvalue)\n\t{\n\t\tif (intvalue) *intvalue = firstvalue->intvalue;\n\t\tif (floatvalue) *floatvalue = firstvalue->floatvalue;\n\t} //end if\n\tfor (o = firstoperator; o; o = lastoperator)\n\t{\n\t\tlastoperator = o->next;\n\t\t//FreeMemory(o);\n\t\tFreeOperator(o);\n\t} //end for\n\tfor (v = firstvalue; v; v = lastvalue)\n\t{\n\t\tlastvalue = v->next;\n\t\t//FreeMemory(v);\n\t\tFreeValue(v);\n\t} //end for\n\tif (!error) return qtrue;\n\tif (intvalue) *intvalue = 0;\n\tif (floatvalue) *floatvalue = 0;\n\treturn qfalse;\n} //end of the function PC_EvaluateTokens\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PC_Evaluate(source_t *source, signed long int *intvalue,\n\t\t\t\t\t\t\t\t\t\t\t\tdouble *floatvalue, int integer)\n{\n\ttoken_t token, *firsttoken, *lasttoken;\n\ttoken_t *t, *nexttoken;\n\tdefine_t *define;\n\tint defined = qfalse;\n\n\tif (intvalue) *intvalue = 0;\n\tif (floatvalue) *floatvalue = 0;\n\t//\n\tif (!PC_ReadLine(source, &token))\n\t{\n\t\tSourceError(source, \"no value after #if/#elif\");\n\t\treturn qfalse;\n\t} //end if\n\tfirsttoken = NULL;\n\tlasttoken = NULL;\n\tdo\n\t{\n\t\t//if the token is a name\n\t\tif (token.type == TT_NAME)\n\t\t{\n\t\t\tif (defined)\n\t\t\t{\n\t\t\t\tdefined = qfalse;\n\t\t\t\tt = PC_CopyToken(&token);\n\t\t\t\tt->next = NULL;\n\t\t\t\tif (lasttoken) lasttoken->next = t;\n\t\t\t\telse firsttoken = t;\n\t\t\t\tlasttoken = t;\n\t\t\t} //end if\n\t\t\telse if (!strcmp(token.string, \"defined\"))\n\t\t\t{\n\t\t\t\tdefined = qtrue;\n\t\t\t\tt = PC_CopyToken(&token);\n\t\t\t\tt->next = NULL;\n\t\t\t\tif (lasttoken) lasttoken->next = t;\n\t\t\t\telse firsttoken = t;\n\t\t\t\tlasttoken = t;\n\t\t\t} //end if\n\t\t\telse\n\t\t\t{\n\t\t\t\t//then it must be a define\n#if DEFINEHASHING\n\t\t\t\tdefine = PC_FindHashedDefine(source->definehash, token.string);\n#else\n\t\t\t\tdefine = PC_FindDefine(source->defines, token.string);\n#endif //DEFINEHASHING\n\t\t\t\tif (!define)\n\t\t\t\t{\n\t\t\t\t\tSourceError(source, \"can't evaluate %s, not defined\", token.string);\n\t\t\t\t\treturn qfalse;\n\t\t\t\t} //end if\n\t\t\t\tif (!PC_ExpandDefineIntoSource(source, &token, define)) return qfalse;\n\t\t\t} //end else\n\t\t} //end if\n\t\t//if the token is a number or a punctuation\n\t\telse if (token.type == TT_NUMBER || token.type == TT_PUNCTUATION)\n\t\t{\n\t\t\tt = PC_CopyToken(&token);\n\t\t\tt->next = NULL;\n\t\t\tif (lasttoken) lasttoken->next = t;\n\t\t\telse firsttoken = t;\n\t\t\tlasttoken = t;\n\t\t} //end else\n\t\telse //can't evaluate the token\n\t\t{\n\t\t\tSourceError(source, \"can't evaluate %s\", token.string);\n\t\t\treturn qfalse;\n\t\t} //end else\n\t} while(PC_ReadLine(source, &token));\n\t//\n\tif (!PC_EvaluateTokens(source, firsttoken, intvalue, floatvalue, integer)) return qfalse;\n\t//\n#ifdef DEBUG_EVAL\n\tLog_Write(\"eval:\");\n#endif //DEBUG_EVAL\n\tfor (t = firsttoken; t; t = nexttoken)\n\t{\n#ifdef DEBUG_EVAL\n\t\tLog_Write(\" %s\", t->string);\n#endif //DEBUG_EVAL\n\t\tnexttoken = t->next;\n\t\tPC_FreeToken(t);\n\t} //end for\n#ifdef DEBUG_EVAL\n\tif (integer) Log_Write(\"eval result: %d\", *intvalue);\n\telse Log_Write(\"eval result: %f\", *floatvalue);\n#endif //DEBUG_EVAL\n\t//\n\treturn qtrue;\n} //end of the function PC_Evaluate\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PC_DollarEvaluate(source_t *source, signed long int *intvalue,\n\t\t\t\t\t\t\t\t\t\t\t\tdouble *floatvalue, int integer)\n{\n\tint indent, defined = qfalse;\n\ttoken_t token, *firsttoken, *lasttoken;\n\ttoken_t *t, *nexttoken;\n\tdefine_t *define;\n\n\tif (intvalue) *intvalue = 0;\n\tif (floatvalue) *floatvalue = 0;\n\t//\n\tif (!PC_ReadSourceToken(source, &token))\n\t{\n\t\tSourceError(source, \"no leading ( after $evalint/$evalfloat\");\n\t\treturn qfalse;\n\t} //end if\n\tif (!PC_ReadSourceToken(source, &token))\n\t{\n\t\tSourceError(source, \"nothing to evaluate\");\n\t\treturn qfalse;\n\t} //end if\n\tindent = 1;\n\tfirsttoken = NULL;\n\tlasttoken = NULL;\n\tdo\n\t{\n\t\t//if the token is a name\n\t\tif (token.type == TT_NAME)\n\t\t{\n\t\t\tif (defined)\n\t\t\t{\n\t\t\t\tdefined = qfalse;\n\t\t\t\tt = PC_CopyToken(&token);\n\t\t\t\tt->next = NULL;\n\t\t\t\tif (lasttoken) lasttoken->next = t;\n\t\t\t\telse firsttoken = t;\n\t\t\t\tlasttoken = t;\n\t\t\t} //end if\n\t\t\telse if (!strcmp(token.string, \"defined\"))\n\t\t\t{\n\t\t\t\tdefined = qtrue;\n\t\t\t\tt = PC_CopyToken(&token);\n\t\t\t\tt->next = NULL;\n\t\t\t\tif (lasttoken) lasttoken->next = t;\n\t\t\t\telse firsttoken = t;\n\t\t\t\tlasttoken = t;\n\t\t\t} //end if\n\t\t\telse\n\t\t\t{\n\t\t\t\t//then it must be a define\n#if DEFINEHASHING\n\t\t\t\tdefine = PC_FindHashedDefine(source->definehash, token.string);\n#else\n\t\t\t\tdefine = PC_FindDefine(source->defines, token.string);\n#endif //DEFINEHASHING\n\t\t\t\tif (!define)\n\t\t\t\t{\n\t\t\t\t\tSourceError(source, \"can't evaluate %s, not defined\", token.string);\n\t\t\t\t\treturn qfalse;\n\t\t\t\t} //end if\n\t\t\t\tif (!PC_ExpandDefineIntoSource(source, &token, define)) return qfalse;\n\t\t\t} //end else\n\t\t} //end if\n\t\t//if the token is a number or a punctuation\n\t\telse if (token.type == TT_NUMBER || token.type == TT_PUNCTUATION)\n\t\t{\n\t\t\tif (*token.string == '(') indent++;\n\t\t\telse if (*token.string == ')') indent--;\n\t\t\tif (indent <= 0) break;\n\t\t\tt = PC_CopyToken(&token);\n\t\t\tt->next = NULL;\n\t\t\tif (lasttoken) lasttoken->next = t;\n\t\t\telse firsttoken = t;\n\t\t\tlasttoken = t;\n\t\t} //end else\n\t\telse //can't evaluate the token\n\t\t{\n\t\t\tSourceError(source, \"can't evaluate %s\", token.string);\n\t\t\treturn qfalse;\n\t\t} //end else\n\t} while(PC_ReadSourceToken(source, &token));\n\t//\n\tif (!PC_EvaluateTokens(source, firsttoken, intvalue, floatvalue, integer)) return qfalse;\n\t//\n#ifdef DEBUG_EVAL\n\tLog_Write(\"$eval:\");\n#endif //DEBUG_EVAL\n\tfor (t = firsttoken; t; t = nexttoken)\n\t{\n#ifdef DEBUG_EVAL\n\t\tLog_Write(\" %s\", t->string);\n#endif //DEBUG_EVAL\n\t\tnexttoken = t->next;\n\t\tPC_FreeToken(t);\n\t} //end for\n#ifdef DEBUG_EVAL\n\tif (integer) Log_Write(\"$eval result: %d\", *intvalue);\n\telse Log_Write(\"$eval result: %f\", *floatvalue);\n#endif //DEBUG_EVAL\n\t//\n\treturn qtrue;\n} //end of the function PC_DollarEvaluate\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PC_Directive_elif(source_t *source)\n{\n\tsigned long int value;\n\tint type, skip;\n\n\tPC_PopIndent(source, &type, &skip);\n\tif (!type || type == INDENT_ELSE)\n\t{\n\t\tSourceError(source, \"misplaced #elif\");\n\t\treturn qfalse;\n\t} //end if\n\tif (!PC_Evaluate(source, &value, NULL, qtrue)) return qfalse;\n\tskip = (value == 0);\n\tPC_PushIndent(source, INDENT_ELIF, skip);\n\treturn qtrue;\n} //end of the function PC_Directive_elif\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PC_Directive_if(source_t *source)\n{\n\tsigned long int value;\n\tint skip;\n\n\tif (!PC_Evaluate(source, &value, NULL, qtrue)) return qfalse;\n\tskip = (value == 0);\n\tPC_PushIndent(source, INDENT_IF, skip);\n\treturn qtrue;\n} //end of the function PC_Directive\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PC_Directive_line(source_t *source)\n{\n\tSourceError(source, \"#line directive not supported\");\n\treturn qfalse;\n} //end of the function PC_Directive_line\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PC_Directive_error(source_t *source)\n{\n\ttoken_t token;\n\n\tstrcpy(token.string, \"\");\n\tPC_ReadSourceToken(source, &token);\n\tSourceError(source, \"#error directive: %s\", token.string);\n\treturn qfalse;\n} //end of the function PC_Directive_error\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PC_Directive_pragma(source_t *source)\n{\n\ttoken_t token;\n\n\tSourceWarning(source, \"#pragma directive not supported\");\n\twhile(PC_ReadLine(source, &token)) ;\n\treturn qtrue;\n} //end of the function PC_Directive_pragma\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nvoid UnreadSignToken(source_t *source)\n{\n\ttoken_t token;\n\n\ttoken.line = source->scriptstack->line;\n\ttoken.whitespace_p = source->scriptstack->script_p;\n\ttoken.endwhitespace_p = source->scriptstack->script_p;\n\ttoken.linescrossed = 0;\n\tstrcpy(token.string, \"-\");\n\ttoken.type = TT_PUNCTUATION;\n\ttoken.subtype = P_SUB;\n\tPC_UnreadSourceToken(source, &token);\n} //end of the function UnreadSignToken\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PC_Directive_eval(source_t *source)\n{\n\tsigned long int value;\n\ttoken_t token;\n\n\tif (!PC_Evaluate(source, &value, NULL, qtrue)) return qfalse;\n\t//\n\ttoken.line = source->scriptstack->line;\n\ttoken.whitespace_p = source->scriptstack->script_p;\n\ttoken.endwhitespace_p = source->scriptstack->script_p;\n\ttoken.linescrossed = 0;\n\tsprintf(token.string, \"%d\", abs(value));\n\ttoken.type = TT_NUMBER;\n\ttoken.subtype = TT_INTEGER|TT_LONG|TT_DECIMAL;\n\tPC_UnreadSourceToken(source, &token);\n\tif (value < 0) UnreadSignToken(source);\n\treturn qtrue;\n} //end of the function PC_Directive_eval\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PC_Directive_evalfloat(source_t *source)\n{\n\tdouble value;\n\ttoken_t token;\n\n\tif (!PC_Evaluate(source, NULL, &value, qfalse)) return qfalse;\n\ttoken.line = source->scriptstack->line;\n\ttoken.whitespace_p = source->scriptstack->script_p;\n\ttoken.endwhitespace_p = source->scriptstack->script_p;\n\ttoken.linescrossed = 0;\n\tsprintf(token.string, \"%1.2f\", fabs(value));\n\ttoken.type = TT_NUMBER;\n\ttoken.subtype = TT_FLOAT|TT_LONG|TT_DECIMAL;\n\tPC_UnreadSourceToken(source, &token);\n\tif (value < 0) UnreadSignToken(source);\n\treturn qtrue;\n} //end of the function PC_Directive_evalfloat\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\ndirective_t directives[20] =\n{\n\t{\"if\", PC_Directive_if},\n\t{\"ifdef\", PC_Directive_ifdef},\n\t{\"ifndef\", PC_Directive_ifndef},\n\t{\"elif\", PC_Directive_elif},\n\t{\"else\", PC_Directive_else},\n\t{\"endif\", PC_Directive_endif},\n\t{\"include\", PC_Directive_include},\n\t{\"define\", PC_Directive_define},\n\t{\"undef\", PC_Directive_undef},\n\t{\"line\", PC_Directive_line},\n\t{\"error\", PC_Directive_error},\n\t{\"pragma\", PC_Directive_pragma},\n\t{\"eval\", PC_Directive_eval},\n\t{\"evalfloat\", PC_Directive_evalfloat},\n\t{NULL, NULL}\n};\n\nint PC_ReadDirective(source_t *source)\n{\n\ttoken_t token;\n\tint i;\n\n\t//read the directive name\n\tif (!PC_ReadSourceToken(source, &token))\n\t{\n\t\tSourceError(source, \"found # without name\");\n\t\treturn qfalse;\n\t} //end if\n\t//directive name must be on the same line\n\tif (token.linescrossed > 0)\n\t{\n\t\tPC_UnreadSourceToken(source, &token);\n\t\tSourceError(source, \"found # at end of line\");\n\t\treturn qfalse;\n\t} //end if\n\t//if if is a name\n\tif (token.type == TT_NAME)\n\t{\n\t\t//find the precompiler directive\n\t\tfor (i = 0; directives[i].name; i++)\n\t\t{\n\t\t\tif (!strcmp(directives[i].name, token.string))\n\t\t\t{\n\t\t\t\treturn directives[i].func(source);\n\t\t\t} //end if\n\t\t} //end for\n\t} //end if\n\tSourceError(source, \"unknown precompiler directive %s\", token.string);\n\treturn qfalse;\n} //end of the function PC_ReadDirective\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PC_DollarDirective_evalint(source_t *source)\n{\n\tsigned long int value;\n\ttoken_t token;\n\n\tif (!PC_DollarEvaluate(source, &value, NULL, qtrue)) return qfalse;\n\t//\n\ttoken.line = source->scriptstack->line;\n\ttoken.whitespace_p = source->scriptstack->script_p;\n\ttoken.endwhitespace_p = source->scriptstack->script_p;\n\ttoken.linescrossed = 0;\n\tsprintf(token.string, \"%d\", abs(value));\n\ttoken.type = TT_NUMBER;\n\ttoken.subtype = TT_INTEGER|TT_LONG|TT_DECIMAL;\n#ifdef NUMBERVALUE\n\ttoken.intvalue = value;\n\ttoken.floatvalue = value;\n#endif //NUMBERVALUE\n\tPC_UnreadSourceToken(source, &token);\n\tif (value < 0) UnreadSignToken(source);\n\treturn qtrue;\n} //end of the function PC_DollarDirective_evalint\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PC_DollarDirective_evalfloat(source_t *source)\n{\n\tdouble value;\n\ttoken_t token;\n\n\tif (!PC_DollarEvaluate(source, NULL, &value, qfalse)) return qfalse;\n\ttoken.line = source->scriptstack->line;\n\ttoken.whitespace_p = source->scriptstack->script_p;\n\ttoken.endwhitespace_p = source->scriptstack->script_p;\n\ttoken.linescrossed = 0;\n\tsprintf(token.string, \"%1.2f\", fabs(value));\n\ttoken.type = TT_NUMBER;\n\ttoken.subtype = TT_FLOAT|TT_LONG|TT_DECIMAL;\n#ifdef NUMBERVALUE\n\ttoken.intvalue = (unsigned long) value;\n\ttoken.floatvalue = value;\n#endif //NUMBERVALUE\n\tPC_UnreadSourceToken(source, &token);\n\tif (value < 0) UnreadSignToken(source);\n\treturn qtrue;\n} //end of the function PC_DollarDirective_evalfloat\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\ndirective_t dollardirectives[20] =\n{\n\t{\"evalint\", PC_DollarDirective_evalint},\n\t{\"evalfloat\", PC_DollarDirective_evalfloat},\n\t{NULL, NULL}\n};\n\nint PC_ReadDollarDirective(source_t *source)\n{\n\ttoken_t token;\n\tint i;\n\n\t//read the directive name\n\tif (!PC_ReadSourceToken(source, &token))\n\t{\n\t\tSourceError(source, \"found $ without name\");\n\t\treturn qfalse;\n\t} //end if\n\t//directive name must be on the same line\n\tif (token.linescrossed > 0)\n\t{\n\t\tPC_UnreadSourceToken(source, &token);\n\t\tSourceError(source, \"found $ at end of line\");\n\t\treturn qfalse;\n\t} //end if\n\t//if if is a name\n\tif (token.type == TT_NAME)\n\t{\n\t\t//find the precompiler directive\n\t\tfor (i = 0; dollardirectives[i].name; i++)\n\t\t{\n\t\t\tif (!strcmp(dollardirectives[i].name, token.string))\n\t\t\t{\n\t\t\t\treturn dollardirectives[i].func(source);\n\t\t\t} //end if\n\t\t} //end for\n\t} //end if\n\tPC_UnreadSourceToken(source, &token);\n\tSourceError(source, \"unknown precompiler directive %s\", token.string);\n\treturn qfalse;\n} //end of the function PC_ReadDirective\n\n#ifdef QUAKEC\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint BuiltinFunction(source_t *source)\n{\n\ttoken_t token;\n\n\tif (!PC_ReadSourceToken(source, &token)) return qfalse;\n\tif (token.type == TT_NUMBER)\n\t{\n\t\tPC_UnreadSourceToken(source, &token);\n\t\treturn qtrue;\n\t} //end if\n\telse\n\t{\n\t\tPC_UnreadSourceToken(source, &token);\n\t\treturn qfalse;\n\t} //end else\n} //end of the function BuiltinFunction\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint QuakeCMacro(source_t *source)\n{\n\tint i;\n\ttoken_t token;\n\n\tif (!PC_ReadSourceToken(source, &token)) return qtrue;\n\tif (token.type != TT_NAME)\n\t{\n\t\tPC_UnreadSourceToken(source, &token);\n\t\treturn qtrue;\n\t} //end if\n\t//find the precompiler directive\n\tfor (i = 0; dollardirectives[i].name; i++)\n\t{\n\t\tif (!strcmp(dollardirectives[i].name, token.string))\n\t\t{\n\t\t\tPC_UnreadSourceToken(source, &token);\n\t\t\treturn qfalse;\n\t\t} //end if\n\t} //end for\n\tPC_UnreadSourceToken(source, &token);\n\treturn qtrue;\n} //end of the function QuakeCMacro\n#endif //QUAKEC\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PC_ReadToken(source_t *source, token_t *token)\n{\n\tdefine_t *define;\n\n\twhile(1)\n\t{\n\t\tif (!PC_ReadSourceToken(source, token)) return qfalse;\n\t\t//check for precompiler directives\n\t\tif (token->type == TT_PUNCTUATION && *token->string == '#')\n\t\t{\n#ifdef QUAKEC\n\t\t\tif (!BuiltinFunction(source))\n#endif //QUAKC\n\t\t\t{\n\t\t\t\t//read the precompiler directive\n\t\t\t\tif (!PC_ReadDirective(source)) return qfalse;\n\t\t\t\tcontinue;\n\t\t\t} //end if\n\t\t} //end if\n\t\tif (token->type == TT_PUNCTUATION && *token->string == '$')\n\t\t{\n#ifdef QUAKEC\n\t\t\tif (!QuakeCMacro(source))\n#endif //QUAKEC\n\t\t\t{\n\t\t\t\t//read the precompiler directive\n\t\t\t\tif (!PC_ReadDollarDirective(source)) return qfalse;\n\t\t\t\tcontinue;\n\t\t\t} //end if\n\t\t} //end if\n\t\t// recursively concatenate strings that are behind each other still resolving defines\n\t\tif (token->type == TT_STRING)\n\t\t{\n\t\t\ttoken_t newtoken;\n\t\t\tif (PC_ReadToken(source, &newtoken))\n\t\t\t{\n\t\t\t\tif (newtoken.type == TT_STRING)\n\t\t\t\t{\n\t\t\t\t\ttoken->string[strlen(token->string)-1] = '\\0';\n\t\t\t\t\tif (strlen(token->string) + (int)strlen(newtoken.string+1) + 1 >= MAX_TOKEN)\n\t\t\t\t\t{\n\t\t\t\t\t\tSourceError(source, \"string longer than MAX_TOKEN %d\\n\", MAX_TOKEN);\n\t\t\t\t\t\treturn qfalse;\n\t\t\t\t\t}\n\t\t\t\t\tstrcat(token->string, newtoken.string+1);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tPC_UnreadToken(source, &newtoken);\n\t\t\t\t}\n\t\t\t}\n\t\t} //end if\n\t\t//if skipping source because of conditional compilation\n\t\tif (source->skip) continue;\n\t\t//if the token is a name\n\t\tif (token->type == TT_NAME)\n\t\t{\n\t\t\t//check if the name is a define macro\n#if DEFINEHASHING\n\t\t\tdefine = PC_FindHashedDefine(source->definehash, token->string);\n#else\n\t\t\tdefine = PC_FindDefine(source->defines, token->string);\n#endif //DEFINEHASHING\n\t\t\t//if it is a define macro\n\t\t\tif (define)\n\t\t\t{\n\t\t\t\t//expand the defined macro\n\t\t\t\tif (!PC_ExpandDefineIntoSource(source, token, define)) return qfalse;\n\t\t\t\tcontinue;\n\t\t\t} //end if\n\t\t} //end if\n\t\t//copy token for unreading\n\t\tCom_Memcpy(&source->token, token, sizeof(token_t));\n\t\t//found a token\n\t\treturn qtrue;\n\t} //end while\n} //end of the function PC_ReadToken\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PC_ExpectTokenString(source_t *source, char *string)\n{\n\ttoken_t token;\n\n\tif (!PC_ReadToken(source, &token))\n\t{\n\t\tSourceError(source, \"couldn't find expected %s\", string);\n\t\treturn qfalse;\n\t} //end if\n\n\tif (strcmp(token.string, string))\n\t{\n\t\tSourceError(source, \"expected %s, found %s\", string, token.string);\n\t\treturn qfalse;\n\t} //end if\n\treturn qtrue;\n} //end of the function PC_ExpectTokenString\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PC_ExpectTokenType(source_t *source, int type, int subtype, token_t *token)\n{\n\tchar str[MAX_TOKEN];\n\n\tif (!PC_ReadToken(source, token))\n\t{\n\t\tSourceError(source, \"couldn't read expected token\");\n\t\treturn qfalse;\n\t} //end if\n\n\tif (token->type != type)\n\t{\n\t\tstrcpy(str, \"\");\n\t\tif (type == TT_STRING) strcpy(str, \"string\");\n\t\tif (type == TT_LITERAL) strcpy(str, \"literal\");\n\t\tif (type == TT_NUMBER) strcpy(str, \"number\");\n\t\tif (type == TT_NAME) strcpy(str, \"name\");\n\t\tif (type == TT_PUNCTUATION) strcpy(str, \"punctuation\");\n\t\tSourceError(source, \"expected a %s, found %s\", str, token->string);\n\t\treturn qfalse;\n\t} //end if\n\tif (token->type == TT_NUMBER)\n\t{\n\t\tif ((token->subtype & subtype) != subtype)\n\t\t{\n\t\t\tif (subtype & TT_DECIMAL) strcpy(str, \"decimal\");\n\t\t\tif (subtype & TT_HEX) strcpy(str, \"hex\");\n\t\t\tif (subtype & TT_OCTAL) strcpy(str, \"octal\");\n\t\t\tif (subtype & TT_BINARY) strcpy(str, \"binary\");\n\t\t\tif (subtype & TT_LONG) strcat(str, \" long\");\n\t\t\tif (subtype & TT_UNSIGNED) strcat(str, \" unsigned\");\n\t\t\tif (subtype & TT_FLOAT) strcat(str, \" float\");\n\t\t\tif (subtype & TT_INTEGER) strcat(str, \" integer\");\n\t\t\tSourceError(source, \"expected %s, found %s\", str, token->string);\n\t\t\treturn qfalse;\n\t\t} //end if\n\t} //end if\n\telse if (token->type == TT_PUNCTUATION)\n\t{\n\t\tif (token->subtype != subtype)\n\t\t{\n\t\t\tSourceError(source, \"found %s\", token->string);\n\t\t\treturn qfalse;\n\t\t} //end if\n\t} //end else if\n\treturn qtrue;\n} //end of the function PC_ExpectTokenType\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PC_ExpectAnyToken(source_t *source, token_t *token)\n{\n\tif (!PC_ReadToken(source, token))\n\t{\n\t\tSourceError(source, \"couldn't read expected token\");\n\t\treturn qfalse;\n\t} //end if\n\telse\n\t{\n\t\treturn qtrue;\n\t} //end else\n} //end of the function PC_ExpectAnyToken\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PC_CheckTokenString(source_t *source, char *string)\n{\n\ttoken_t tok;\n\n\tif (!PC_ReadToken(source, &tok)) return qfalse;\n\t//if the token is available\n\tif (!strcmp(tok.string, string)) return qtrue;\n\t//\n\tPC_UnreadSourceToken(source, &tok);\n\treturn qfalse;\n} //end of the function PC_CheckTokenString\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PC_CheckTokenType(source_t *source, int type, int subtype, token_t *token)\n{\n\ttoken_t tok;\n\n\tif (!PC_ReadToken(source, &tok)) return qfalse;\n\t//if the type matches\n\tif (tok.type == type &&\n\t\t\t(tok.subtype & subtype) == subtype)\n\t{\n\t\tCom_Memcpy(token, &tok, sizeof(token_t));\n\t\treturn qtrue;\n\t} //end if\n\t//\n\tPC_UnreadSourceToken(source, &tok);\n\treturn qfalse;\n} //end of the function PC_CheckTokenType\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PC_SkipUntilString(source_t *source, char *string)\n{\n\ttoken_t token;\n\n\twhile(PC_ReadToken(source, &token))\n\t{\n\t\tif (!strcmp(token.string, string)) return qtrue;\n\t} //end while\n\treturn qfalse;\n} //end of the function PC_SkipUntilString\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nvoid PC_UnreadLastToken(source_t *source)\n{\n\tPC_UnreadSourceToken(source, &source->token);\n} //end of the function PC_UnreadLastToken\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nvoid PC_UnreadToken(source_t *source, token_t *token)\n{\n\tPC_UnreadSourceToken(source, token);\n} //end of the function PC_UnreadToken\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nvoid PC_SetIncludePath(source_t *source, char *path)\n{\n\tstrncpy(source->includepath, path, MAX_PATH);\n\t//add trailing path seperator\n\tif (source->includepath[strlen(source->includepath)-1] != '\\\\' &&\n\t\tsource->includepath[strlen(source->includepath)-1] != '/')\n\t{\n\t\tstrcat(source->includepath, PATHSEPERATOR_STR);\n\t} //end if\n} //end of the function PC_SetIncludePath\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nvoid PC_SetPunctuations(source_t *source, punctuation_t *p)\n{\n\tsource->punctuations = p;\n} //end of the function PC_SetPunctuations\n//============================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nsource_t *LoadSourceFile(const char *filename)\n{\n\tsource_t *source;\n\tscript_t *script;\n\n\tPC_InitTokenHeap();\n\n\tscript = LoadScriptFile(filename);\n\tif (!script) return NULL;\n\n\tscript->next = NULL;\n\n\tsource = (source_t *) GetMemory(sizeof(source_t));\n\tCom_Memset(source, 0, sizeof(source_t));\n\n\tstrncpy(source->filename, filename, MAX_PATH);\n\tsource->scriptstack = script;\n\tsource->tokens = NULL;\n\tsource->defines = NULL;\n\tsource->indentstack = NULL;\n\tsource->skip = 0;\n\n#if DEFINEHASHING\n\tsource->definehash = (define_t**) GetClearedMemory(DEFINEHASHSIZE * sizeof(define_t *));\n#endif //DEFINEHASHING\n\tPC_AddGlobalDefinesToSource(source);\n\treturn source;\n} //end of the function LoadSourceFile\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nsource_t *LoadSourceMemory(char *ptr, int length, char *name)\n{\n\tsource_t *source;\n\tscript_t *script;\n\n\tPC_InitTokenHeap();\n\n\tscript = LoadScriptMemory(ptr, length, name);\n\tif (!script) return NULL;\n\tscript->next = NULL;\n\n\tsource = (source_t *) GetMemory(sizeof(source_t));\n\tCom_Memset(source, 0, sizeof(source_t));\n\n\tstrncpy(source->filename, name, MAX_PATH);\n\tsource->scriptstack = script;\n\tsource->tokens = NULL;\n\tsource->defines = NULL;\n\tsource->indentstack = NULL;\n\tsource->skip = 0;\n\n#if DEFINEHASHING\n\tsource->definehash = (define_t**) GetClearedMemory(DEFINEHASHSIZE * sizeof(define_t *));\n#endif //DEFINEHASHING\n\tPC_AddGlobalDefinesToSource(source);\n\treturn source;\n} //end of the function LoadSourceMemory\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nvoid FreeSource(source_t *source)\n{\n\tscript_t *script;\n\ttoken_t *token;\n\tdefine_t *define;\n\tindent_t *indent;\n\tint i;\n\n\t//PC_PrintDefineHashTable(source->definehash);\n\t//free all the scripts\n\twhile(source->scriptstack)\n\t{\n\t\tscript = source->scriptstack;\n\t\tsource->scriptstack = source->scriptstack->next;\n\t\tFreeScript(script);\n\t} //end for\n\t//free all the tokens\n\twhile(source->tokens)\n\t{\n\t\ttoken = source->tokens;\n\t\tsource->tokens = source->tokens->next;\n\t\tPC_FreeToken(token);\n\t} //end for\n#if DEFINEHASHING\n\tfor (i = 0; i < DEFINEHASHSIZE; i++)\n\t{\n\t\twhile(source->definehash[i])\n\t\t{\n\t\t\tdefine = source->definehash[i];\n\t\t\tsource->definehash[i] = source->definehash[i]->hashnext;\n\t\t\tPC_FreeDefine(define);\n\t\t} //end while\n\t} //end for\n#else //DEFINEHASHING\n\t//free all defines\n\twhile(source->defines)\n\t{\n\t\tdefine = source->defines;\n\t\tsource->defines = source->defines->next;\n\t\tPC_FreeDefine(define);\n\t} //end for\n#endif //DEFINEHASHING\n\t//free all indents\n\twhile(source->indentstack)\n\t{\n\t\tindent = source->indentstack;\n\t\tsource->indentstack = source->indentstack->next;\n\t\tFreeMemory(indent);\n\t} //end for\n#if DEFINEHASHING\n\t//\n\tif (source->definehash) FreeMemory(source->definehash);\n#endif //DEFINEHASHING\n\t//free the source itself\n\tFreeMemory(source);\n} //end of the function FreeSource\n//============================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\n\n#define MAX_SOURCEFILES\t\t64\n\nsource_t *sourceFiles[MAX_SOURCEFILES];\n\nint PC_LoadSourceHandle(const char *filename)\n{\n\tsource_t *source;\n\tint i;\n\n\tfor (i = 1; i < MAX_SOURCEFILES; i++)\n\t{\n\t\tif (!sourceFiles[i])\n\t\t\tbreak;\n\t} //end for\n\tif (i >= MAX_SOURCEFILES)\n\t\treturn 0;\n\tPS_SetBaseFolder(\"\");\n\tsource = LoadSourceFile(filename);\n\tif (!source)\n\t\treturn 0;\n\tsourceFiles[i] = source;\n\treturn i;\n} //end of the function PC_LoadSourceHandle\n//============================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PC_FreeSourceHandle(int handle)\n{\n\tif (handle < 1 || handle >= MAX_SOURCEFILES)\n\t\treturn qfalse;\n\tif (!sourceFiles[handle])\n\t\treturn qfalse;\n\n\tFreeSource(sourceFiles[handle]);\n\tsourceFiles[handle] = NULL;\n\treturn qtrue;\n} //end of the function PC_FreeSourceHandle\n//============================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PC_ReadTokenHandle(int handle, pc_token_t *pc_token)\n{\n\ttoken_t token;\n\tint ret;\n\n\tif (handle < 1 || handle >= MAX_SOURCEFILES)\n\t\treturn 0;\n\tif (!sourceFiles[handle])\n\t\treturn 0;\n\n\tret = PC_ReadToken(sourceFiles[handle], &token);\n\tstrcpy(pc_token->string, token.string);\n\tpc_token->type = token.type;\n\tpc_token->subtype = token.subtype;\n\tpc_token->intvalue = token.intvalue;\n\tpc_token->floatvalue = token.floatvalue;\n\tif (pc_token->type == TT_STRING)\n\t\tStripDoubleQuotes(pc_token->string);\n\treturn ret;\n} //end of the function PC_ReadTokenHandle\n//============================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PC_SourceFileAndLine(int handle, char *filename, int *line)\n{\n\tif (handle < 1 || handle >= MAX_SOURCEFILES)\n\t\treturn qfalse;\n\tif (!sourceFiles[handle])\n\t\treturn qfalse;\n\n\tstrcpy(filename, sourceFiles[handle]->filename);\n\tif (sourceFiles[handle]->scriptstack)\n\t\t*line = sourceFiles[handle]->scriptstack->line;\n\telse\n\t\t*line = 0;\n\treturn qtrue;\n} //end of the function PC_SourceFileAndLine\n//============================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nvoid PC_SetBaseFolder(char *path)\n{\n\tPS_SetBaseFolder(path);\n} //end of the function PC_SetBaseFolder\n//============================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nvoid PC_CheckOpenSourceHandles(void)\n{\n\tint i;\n\n\tfor (i = 1; i < MAX_SOURCEFILES; i++)\n\t{\n\t\tif (sourceFiles[i])\n\t\t{\n#ifdef BOTLIB\n\t\t\tbotimport.Print(PRT_ERROR, \"file %s still open in precompiler\\n\", sourceFiles[i]->scriptstack->filename);\n#endif\t//BOTLIB\n\t\t} //end if\n\t} //end for\n} //end of the function PC_CheckOpenSourceHandles\n\n"
  },
  {
    "path": "src/engine/botlib/l_precomp.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tl_precomp.h\n *\n * desc:\t\tpre compiler\n *\n * $Archive: /source/code/botlib/l_precomp.h $\n *\n *****************************************************************************/\n\n#ifndef MAX_PATH\n\t#define MAX_PATH\t\t\tMAX_QPATH\n#endif\n\n#ifndef PATH_SEPERATORSTR\n\t#if defined(WIN32)|defined(_WIN32)|defined(__NT__)|defined(__WINDOWS__)|defined(__WINDOWS_386__)\n\t\t#define PATHSEPERATOR_STR\t\t\"\\\\\"\n\t#else\n\t\t#define PATHSEPERATOR_STR\t\t\"/\"\n\t#endif\n#endif\n#ifndef PATH_SEPERATORCHAR\n\t#if defined(WIN32)|defined(_WIN32)|defined(__NT__)|defined(__WINDOWS__)|defined(__WINDOWS_386__)\n\t\t#define PATHSEPERATOR_CHAR\t\t'\\\\'\n\t#else\n\t\t#define PATHSEPERATOR_CHAR\t\t'/'\n\t#endif\n#endif\n\n#if defined(BSPC) && !defined(QDECL)\n#define QDECL\n#endif\n\n\n#define DEFINE_FIXED\t\t\t0x0001\n\n#define BUILTIN_LINE\t\t\t1\n#define BUILTIN_FILE\t\t\t2\n#define BUILTIN_DATE\t\t\t3\n#define BUILTIN_TIME\t\t\t4\n#define BUILTIN_STDC\t\t\t5\n\n#define INDENT_IF\t\t\t\t0x0001\n#define INDENT_ELSE\t\t\t\t0x0002\n#define INDENT_ELIF\t\t\t\t0x0004\n#define INDENT_IFDEF\t\t\t0x0008\n#define INDENT_IFNDEF\t\t\t0x0010\n\n//macro definitions\ntypedef struct define_s\n{\n\tchar *name;\t\t\t\t\t\t\t//define name\n\tint flags;\t\t\t\t\t\t\t//define flags\n\tint builtin;\t\t\t\t\t\t// > 0 if builtin define\n\tint numparms;\t\t\t\t\t\t//number of define parameters\n\ttoken_t *parms;\t\t\t\t\t\t//define parameters\n\ttoken_t *tokens;\t\t\t\t\t//macro tokens (possibly containing parm tokens)\n\tstruct define_s *next;\t\t\t\t//next defined macro in a list\n\tstruct define_s *hashnext;\t\t\t//next define in the hash chain\n} define_t;\n\n//indents\n//used for conditional compilation directives:\n//#if, #else, #elif, #ifdef, #ifndef\ntypedef struct indent_s\n{\n\tint type;\t\t\t\t\t\t\t\t//indent type\n\tint skip;\t\t\t\t\t\t\t\t//true if skipping current indent\n\tscript_t *script;\t\t\t\t\t\t//script the indent was in\n\tstruct indent_s *next;\t\t\t\t\t//next indent on the indent stack\n} indent_t;\n\n//source file\ntypedef struct source_s\n{\n\tchar filename[1024];\t\t\t\t\t//file name of the script\n\tchar includepath[1024];\t\t\t\t\t//path to include files\n\tpunctuation_t *punctuations;\t\t\t//punctuations to use\n\tscript_t *scriptstack;\t\t\t\t\t//stack with scripts of the source\n\ttoken_t *tokens;\t\t\t\t\t\t//tokens to read first\n\tdefine_t *defines;\t\t\t\t\t\t//list with macro definitions\n\tdefine_t **definehash;\t\t\t\t\t//hash chain with defines\n\tindent_t *indentstack;\t\t\t\t\t//stack with indents\n\tint skip;\t\t\t\t\t\t\t\t// > 0 if skipping conditional code\n\ttoken_t token;\t\t\t\t\t\t\t//last read token\n} source_t;\n\n\n//read a token from the source\nint PC_ReadToken(source_t *source, token_t *token);\n//expect a certain token\nint PC_ExpectTokenString(source_t *source, char *string);\n//expect a certain token type\nint PC_ExpectTokenType(source_t *source, int type, int subtype, token_t *token);\n//expect a token\nint PC_ExpectAnyToken(source_t *source, token_t *token);\n//returns true when the token is available\nint PC_CheckTokenString(source_t *source, char *string);\n//returns true an reads the token when a token with the given type is available\nint PC_CheckTokenType(source_t *source, int type, int subtype, token_t *token);\n//skip tokens until the given token string is read\nint PC_SkipUntilString(source_t *source, char *string);\n//unread the last token read from the script\nvoid PC_UnreadLastToken(source_t *source);\n//unread the given token\nvoid PC_UnreadToken(source_t *source, token_t *token);\n//read a token only if on the same line, lines are concatenated with a slash\nint PC_ReadLine(source_t *source, token_t *token);\n//returns true if there was a white space in front of the token\nint PC_WhiteSpaceBeforeToken(token_t *token);\n//add a define to the source\nint PC_AddDefine(source_t *source, char *string);\n//add a globals define that will be added to all opened sources\nint PC_AddGlobalDefine(char *string);\n//remove the given global define\nint PC_RemoveGlobalDefine(char *name);\n//remove all globals defines\nvoid PC_RemoveAllGlobalDefines(void);\n//add builtin defines\nvoid PC_AddBuiltinDefines(source_t *source);\n//set the source include path\nvoid PC_SetIncludePath(source_t *source, char *path);\n//set the punction set\nvoid PC_SetPunctuations(source_t *source, punctuation_t *p);\n//set the base folder to load files from\nvoid PC_SetBaseFolder(char *path);\n//load a source file\nsource_t *LoadSourceFile(const char *filename);\n//load a source from memory\nsource_t *LoadSourceMemory(char *ptr, int length, char *name);\n//free the given source\nvoid FreeSource(source_t *source);\n//print a source error\nvoid QDECL SourceError(source_t *source, char *str, ...);\n//print a source warning\nvoid QDECL SourceWarning(source_t *source, char *str, ...);\n\n#ifdef BSPC\n// some of BSPC source does include game/q_shared.h and some does not\n// we define pc_token_s pc_token_t if needed (yes, it's ugly)\n#ifndef __Q_SHARED_H\n#define MAX_TOKENLENGTH\t\t1024\ntypedef struct pc_token_s\n{\n\tint type;\n\tint subtype;\n\tint intvalue;\n\tfloat floatvalue;\n\tchar string[MAX_TOKENLENGTH];\n} pc_token_t;\n#endif //!_Q_SHARED_H\n#endif //BSPC\n\n//\nint PC_LoadSourceHandle(const char *filename);\nint PC_FreeSourceHandle(int handle);\nint PC_ReadTokenHandle(int handle, pc_token_t *pc_token);\nint PC_SourceFileAndLine(int handle, char *filename, int *line);\nvoid PC_CheckOpenSourceHandles(void);\n"
  },
  {
    "path": "src/engine/botlib/l_script.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tl_script.c\n *\n * desc:\t\tlexicographical parser\n *\n * $Archive: /MissionPack/code/botlib/l_script.c $\n *\n *****************************************************************************/\n\n//#define SCREWUP\n//#define BOTLIB\n//#define MEQCC\n//#define BSPC\n\n#ifdef SCREWUP\n#include <stdio.h>\n#include <stdlib.h>\n#include <limits.h>\n#include <string.h>\n#include <stdarg.h>\n#include \"l_memory.h\"\n#include \"l_script.h\"\n\ntypedef enum {qfalse, qtrue}\tqboolean;\n\n#endif //SCREWUP\n\n#ifdef BOTLIB\n//include files for usage in the bot library\n#include \"../../game/q_shared.h\"\n#include \"../../game/botlib.h\"\n#include \"be_interface.h\"\n#include \"l_script.h\"\n#include \"l_memory.h\"\n#include \"l_log.h\"\n#include \"l_libvar.h\"\n#endif //BOTLIB\n\n#ifdef MEQCC\n//include files for usage in MrElusive's QuakeC Compiler\n#include \"qcc.h\"\n#include \"l_script.h\"\n#include \"l_memory.h\"\n#include \"l_log.h\"\n\n#define qtrue\ttrue\n#define qfalse\tfalse\n#endif //MEQCC\n\n#ifdef BSPC\n//include files for usage in the BSP Converter\n#include \"../bspc/qbsp.h\"\n#include \"../bspc/l_log.h\"\n#include \"../bspc/l_mem.h\"\n\n#define qtrue\ttrue\n#define qfalse\tfalse\n#endif //BSPC\n\n\n#define PUNCTABLE\n\n//longer punctuations first\npunctuation_t default_punctuations[] =\n{\n\t//binary operators\n\t{\">>=\",P_RSHIFT_ASSIGN, NULL},\n\t{\"<<=\",P_LSHIFT_ASSIGN, NULL},\n\t//\n\t{\"...\",P_PARMS, NULL},\n\t//define merge operator\n\t{\"##\",P_PRECOMPMERGE, NULL},\n\t//logic operators\n\t{\"&&\",P_LOGIC_AND, NULL},\n\t{\"||\",P_LOGIC_OR, NULL},\n\t{\">=\",P_LOGIC_GEQ, NULL},\n\t{\"<=\",P_LOGIC_LEQ, NULL},\n\t{\"==\",P_LOGIC_EQ, NULL},\n\t{\"!=\",P_LOGIC_UNEQ, NULL},\n\t//arithmatic operators\n\t{\"*=\",P_MUL_ASSIGN, NULL},\n\t{\"/=\",P_DIV_ASSIGN, NULL},\n\t{\"%=\",P_MOD_ASSIGN, NULL},\n\t{\"+=\",P_ADD_ASSIGN, NULL},\n\t{\"-=\",P_SUB_ASSIGN, NULL},\n\t{\"++\",P_INC, NULL},\n\t{\"--\",P_DEC, NULL},\n\t//binary operators\n\t{\"&=\",P_BIN_AND_ASSIGN, NULL},\n\t{\"|=\",P_BIN_OR_ASSIGN, NULL},\n\t{\"^=\",P_BIN_XOR_ASSIGN, NULL},\n\t{\">>\",P_RSHIFT, NULL},\n\t{\"<<\",P_LSHIFT, NULL},\n\t//reference operators\n\t{\"->\",P_POINTERREF, NULL},\n\t//C++\n\t{\"::\",P_CPP1, NULL},\n\t{\".*\",P_CPP2, NULL},\n\t//arithmatic operators\n\t{\"*\",P_MUL, NULL},\n\t{\"/\",P_DIV, NULL},\n\t{\"%\",P_MOD, NULL},\n\t{\"+\",P_ADD, NULL},\n\t{\"-\",P_SUB, NULL},\n\t{\"=\",P_ASSIGN, NULL},\n\t//binary operators\n\t{\"&\",P_BIN_AND, NULL},\n\t{\"|\",P_BIN_OR, NULL},\n\t{\"^\",P_BIN_XOR, NULL},\n\t{\"~\",P_BIN_NOT, NULL},\n\t//logic operators\n\t{\"!\",P_LOGIC_NOT, NULL},\n\t{\">\",P_LOGIC_GREATER, NULL},\n\t{\"<\",P_LOGIC_LESS, NULL},\n\t//reference operator\n\t{\".\",P_REF, NULL},\n\t//seperators\n\t{\",\",P_COMMA, NULL},\n\t{\";\",P_SEMICOLON, NULL},\n\t//label indication\n\t{\":\",P_COLON, NULL},\n\t//if statement\n\t{\"?\",P_QUESTIONMARK, NULL},\n\t//embracements\n\t{\"(\",P_PARENTHESESOPEN, NULL},\n\t{\")\",P_PARENTHESESCLOSE, NULL},\n\t{\"{\",P_BRACEOPEN, NULL},\n\t{\"}\",P_BRACECLOSE, NULL},\n\t{\"[\",P_SQBRACKETOPEN, NULL},\n\t{\"]\",P_SQBRACKETCLOSE, NULL},\n\t//\n\t{\"\\\\\",P_BACKSLASH, NULL},\n\t//precompiler operator\n\t{\"#\",P_PRECOMP, NULL},\n#ifdef DOLLAR\n\t{\"$\",P_DOLLAR, NULL},\n#endif //DOLLAR\n\t{NULL, 0}\n};\n\n#ifdef BSPC\nchar basefolder[MAX_PATH];\n#else\nchar basefolder[MAX_QPATH];\n#endif\n\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid PS_CreatePunctuationTable(script_t *script, punctuation_t *punctuations)\n{\n\tint i;\n\tpunctuation_t *p, *lastp, *newp;\n\n\t//get memory for the table\n\tif (!script->punctuationtable) script->punctuationtable = (punctuation_t **)\n\t\t\t\t\t\t\t\t\t\t\t\tGetMemory(256 * sizeof(punctuation_t *));\n\tCom_Memset(script->punctuationtable, 0, 256 * sizeof(punctuation_t *));\n\t//add the punctuations in the list to the punctuation table\n\tfor (i = 0; punctuations[i].p; i++)\n\t{\n\t\tnewp = &punctuations[i];\n\t\tlastp = NULL;\n\t\t//sort the punctuations in this table entry on length (longer punctuations first)\n\t\tfor (p = script->punctuationtable[(unsigned int) newp->p[0]]; p; p = p->next)\n\t\t{\n\t\t\tif (strlen(p->p) < (int)strlen(newp->p))\n\t\t\t{\n\t\t\t\tnewp->next = p;\n\t\t\t\tif (lastp) lastp->next = newp;\n\t\t\t\telse script->punctuationtable[(unsigned int) newp->p[0]] = newp;\n\t\t\t\tbreak;\n\t\t\t} //end if\n\t\t\tlastp = p;\n\t\t} //end for\n\t\tif (!p)\n\t\t{\n\t\t\tnewp->next = NULL;\n\t\t\tif (lastp) lastp->next = newp;\n\t\t\telse script->punctuationtable[(unsigned int) newp->p[0]] = newp;\n\t\t} //end if\n\t} //end for\n} //end of the function PS_CreatePunctuationTable\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nchar *PunctuationFromNum(script_t *script, int num)\n{\n\tint i;\n\n\tfor (i = 0; script->punctuations[i].p; i++)\n\t{\n\t\tif (script->punctuations[i].n == num) return script->punctuations[i].p;\n\t} //end for\n\treturn \"unkown punctuation\";\n} //end of the function PunctuationFromNum\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid QDECL ScriptError(script_t *script, char *str, ...)\n{\n\tchar text[1024];\n\tva_list ap;\n\n\tif (script->flags & SCFL_NOERRORS) return;\n\n\tva_start(ap, str);\n\tvsprintf(text, str, ap);\n\tva_end(ap);\n#ifdef BOTLIB\n\tbotimport.Print(PRT_ERROR, \"file %s, line %d: %s\\n\", script->filename, script->line, text);\n#endif //BOTLIB\n#ifdef MEQCC\n\tprintf(\"error: file %s, line %d: %s\\n\", script->filename, script->line, text);\n#endif //MEQCC\n#ifdef BSPC\n\tLog_Print(\"error: file %s, line %d: %s\\n\", script->filename, script->line, text);\n#endif //BSPC\n} //end of the function ScriptError\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid QDECL ScriptWarning(script_t *script, char *str, ...)\n{\n\tchar text[1024];\n\tva_list ap;\n\n\tif (script->flags & SCFL_NOWARNINGS) return;\n\n\tva_start(ap, str);\n\tvsprintf(text, str, ap);\n\tva_end(ap);\n#ifdef BOTLIB\n\tbotimport.Print(PRT_WARNING, \"file %s, line %d: %s\\n\", script->filename, script->line, text);\n#endif //BOTLIB\n#ifdef MEQCC\n\tprintf(\"warning: file %s, line %d: %s\\n\", script->filename, script->line, text);\n#endif //MEQCC\n#ifdef BSPC\n\tLog_Print(\"warning: file %s, line %d: %s\\n\", script->filename, script->line, text);\n#endif //BSPC\n} //end of the function ScriptWarning\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nvoid SetScriptPunctuations(script_t *script, punctuation_t *p)\n{\n#ifdef PUNCTABLE\n\tif (p) PS_CreatePunctuationTable(script, p);\n\telse  PS_CreatePunctuationTable(script, default_punctuations);\n#endif //PUNCTABLE\n\tif (p) script->punctuations = p;\n\telse script->punctuations = default_punctuations;\n} //end of the function SetScriptPunctuations\n//============================================================================\n// Reads spaces, tabs, C-like comments etc.\n// When a newline character is found the scripts line counter is increased.\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PS_ReadWhiteSpace(script_t *script)\n{\n\twhile(1)\n\t{\n\t\t//skip white space\n\t\twhile(*script->script_p <= ' ')\n\t\t{\n\t\t\tif (!*script->script_p) return 0;\n\t\t\tif (*script->script_p == '\\n') script->line++;\n\t\t\tscript->script_p++;\n\t\t} //end while\n\t\t//skip comments\n\t\tif (*script->script_p == '/')\n\t\t{\n\t\t\t//comments //\n\t\t\tif (*(script->script_p+1) == '/')\n\t\t\t{\n\t\t\t\tscript->script_p++;\n\t\t\t\tdo\n\t\t\t\t{\n\t\t\t\t\tscript->script_p++;\n\t\t\t\t\tif (!*script->script_p) return 0;\n\t\t\t\t} //end do\n\t\t\t\twhile(*script->script_p != '\\n');\n\t\t\t\tscript->line++;\n\t\t\t\tscript->script_p++;\n\t\t\t\tif (!*script->script_p) return 0;\n\t\t\t\tcontinue;\n\t\t\t} //end if\n\t\t\t//comments /* */\n\t\t\telse if (*(script->script_p+1) == '*')\n\t\t\t{\n\t\t\t\tscript->script_p++;\n\t\t\t\tdo\n\t\t\t\t{\n\t\t\t\t\tscript->script_p++;\n\t\t\t\t\tif (!*script->script_p) return 0;\n\t\t\t\t\tif (*script->script_p == '\\n') script->line++;\n\t\t\t\t} //end do\n\t\t\t\twhile(!(*script->script_p == '*' && *(script->script_p+1) == '/'));\n\t\t\t\tscript->script_p++;\n\t\t\t\tif (!*script->script_p) return 0;\n\t\t\t\tscript->script_p++;\n\t\t\t\tif (!*script->script_p) return 0;\n\t\t\t\tcontinue;\n\t\t\t} //end if\n\t\t} //end if\n\t\tbreak;\n\t} //end while\n\treturn 1;\n} //end of the function PS_ReadWhiteSpace\n//============================================================================\n// Reads an escape character.\n//\n// Parameter:\t\t\t\tscript\t\t: script to read from\n//\t\t\t\t\t\t\t\tch\t\t\t\t: place to store the read escape character\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PS_ReadEscapeCharacter(script_t *script, char *ch)\n{\n\tint c, val, i;\n\n\t//step over the leading '\\\\'\n\tscript->script_p++;\n\t//determine the escape character\n\tswitch(*script->script_p)\n\t{\n\t\tcase '\\\\': c = '\\\\'; break;\n\t\tcase 'n': c = '\\n'; break;\n\t\tcase 'r': c = '\\r'; break;\n\t\tcase 't': c = '\\t'; break;\n\t\tcase 'v': c = '\\v'; break;\n\t\tcase 'b': c = '\\b'; break;\n\t\tcase 'f': c = '\\f'; break;\n\t\tcase 'a': c = '\\a'; break;\n\t\tcase '\\'': c = '\\''; break;\n\t\tcase '\\\"': c = '\\\"'; break;\n\t\tcase '\\?': c = '\\?'; break;\n\t\tcase 'x':\n\t\t{\n\t\t\tscript->script_p++;\n\t\t\tfor (i = 0, val = 0; ; i++, script->script_p++)\n\t\t\t{\n\t\t\t\tc = *script->script_p;\n\t\t\t\tif (c >= '0' && c <= '9') c = c - '0';\n\t\t\t\telse if (c >= 'A' && c <= 'Z') c = c - 'A' + 10;\n\t\t\t\telse if (c >= 'a' && c <= 'z') c = c - 'a' + 10;\n\t\t\t\telse break;\n\t\t\t\tval = (val << 4) + c;\n\t\t\t} //end for\n\t\t\tscript->script_p--;\n\t\t\tif (val > 0xFF)\n\t\t\t{\n\t\t\t\tScriptWarning(script, \"too large value in escape character\");\n\t\t\t\tval = 0xFF;\n\t\t\t} //end if\n\t\t\tc = val;\n\t\t\tbreak;\n\t\t} //end case\n\t\tdefault: //NOTE: decimal ASCII code, NOT octal\n\t\t{\n\t\t\tif (*script->script_p < '0' || *script->script_p > '9') ScriptError(script, \"unknown escape char\");\n\t\t\tfor (i = 0, val = 0; ; i++, script->script_p++)\n\t\t\t{\n\t\t\t\tc = *script->script_p;\n\t\t\t\tif (c >= '0' && c <= '9') c = c - '0';\n\t\t\t\telse break;\n\t\t\t\tval = val * 10 + c;\n\t\t\t} //end for\n\t\t\tscript->script_p--;\n\t\t\tif (val > 0xFF)\n\t\t\t{\n\t\t\t\tScriptWarning(script, \"too large value in escape character\");\n\t\t\t\tval = 0xFF;\n\t\t\t} //end if\n\t\t\tc = val;\n\t\t\tbreak;\n\t\t} //end default\n\t} //end switch\n\t//step over the escape character or the last digit of the number\n\tscript->script_p++;\n\t//store the escape character\n\t*ch = c;\n\t//succesfully read escape character\n\treturn 1;\n} //end of the function PS_ReadEscapeCharacter\n//============================================================================\n// Reads C-like string. Escape characters are interpretted.\n// Quotes are included with the string.\n// Reads two strings with a white space between them as one string.\n//\n// Parameter:\t\t\t\tscript\t\t: script to read from\n//\t\t\t\t\t\t\t\ttoken\t\t\t: buffer to store the string\n// Returns:\t\t\t\t\tqtrue when a string was read succesfully\n// Changes Globals:\t\t-\n//============================================================================\nint PS_ReadString(script_t *script, token_t *token, int quote)\n{\n\tint len, tmpline;\n\tchar *tmpscript_p;\n\n\tif (quote == '\\\"') token->type = TT_STRING;\n\telse token->type = TT_LITERAL;\n\n\tlen = 0;\n\t//leading quote\n\ttoken->string[len++] = *script->script_p++;\n\t//\n\twhile(1)\n\t{\n\t\t//minus 2 because trailing double quote and zero have to be appended\n\t\tif (len >= MAX_TOKEN - 2)\n\t\t{\n\t\t\tScriptError(script, \"string longer than MAX_TOKEN = %d\", MAX_TOKEN);\n\t\t\treturn 0;\n\t\t} //end if\n\t\t//if there is an escape character and\n\t\t//if escape characters inside a string are allowed\n\t\tif (*script->script_p == '\\\\' && !(script->flags & SCFL_NOSTRINGESCAPECHARS))\n\t\t{\n\t\t\tif (!PS_ReadEscapeCharacter(script, &token->string[len]))\n\t\t\t{\n\t\t\t\ttoken->string[len] = 0;\n\t\t\t\treturn 0;\n\t\t\t} //end if\n\t\t\tlen++;\n\t\t} //end if\n\t\t//if a trailing quote\n\t\telse if (*script->script_p == quote)\n\t\t{\n\t\t\t//step over the double quote\n\t\t\tscript->script_p++;\n\t\t\t//if white spaces in a string are not allowed\n\t\t\tif (script->flags & SCFL_NOSTRINGWHITESPACES) break;\n\t\t\t//\n\t\t\ttmpscript_p = script->script_p;\n\t\t\ttmpline = script->line;\n\t\t\t//read unusefull stuff between possible two following strings\n\t\t\tif (!PS_ReadWhiteSpace(script))\n\t\t\t{\n\t\t\t\tscript->script_p = tmpscript_p;\n\t\t\t\tscript->line = tmpline;\n\t\t\t\tbreak;\n\t\t\t} //end if\n\t\t\t//if there's no leading double qoute\n\t\t\tif (*script->script_p != quote)\n\t\t\t{\n\t\t\t\tscript->script_p = tmpscript_p;\n\t\t\t\tscript->line = tmpline;\n\t\t\t\tbreak;\n\t\t\t} //end if\n\t\t\t//step over the new leading double quote\n\t\t\tscript->script_p++;\n\t\t} //end if\n\t\telse\n\t\t{\n\t\t\tif (*script->script_p == '\\0')\n\t\t\t{\n\t\t\t\ttoken->string[len] = 0;\n\t\t\t\tScriptError(script, \"missing trailing quote\");\n\t\t\t\treturn 0;\n\t\t\t} //end if\n\t      if (*script->script_p == '\\n')\n\t\t\t{\n\t\t\t\ttoken->string[len] = 0;\n\t\t\t\tScriptError(script, \"newline inside string %s\", token->string);\n\t\t\t\treturn 0;\n\t\t\t} //end if\n\t\t\ttoken->string[len++] = *script->script_p++;\n\t\t} //end else\n\t} //end while\n\t//trailing quote\n\ttoken->string[len++] = quote;\n\t//end string with a zero\n\ttoken->string[len] = '\\0';\n\t//the sub type is the length of the string\n\ttoken->subtype = len;\n\treturn 1;\n} //end of the function PS_ReadString\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PS_ReadName(script_t *script, token_t *token)\n{\n\tint len = 0;\n\tchar c;\n\n\ttoken->type = TT_NAME;\n\tdo\n\t{\n\t\ttoken->string[len++] = *script->script_p++;\n\t\tif (len >= MAX_TOKEN)\n\t\t{\n\t\t\tScriptError(script, \"name longer than MAX_TOKEN = %d\", MAX_TOKEN);\n\t\t\treturn 0;\n\t\t} //end if\n\t\tc = *script->script_p;\n   } while ((c >= 'a' && c <= 'z') ||\n\t\t\t\t(c >= 'A' && c <= 'Z') ||\n\t\t\t\t(c >= '0' && c <= '9') ||\n\t\t\t\tc == '_');\n\ttoken->string[len] = '\\0';\n\t//the sub type is the length of the name\n\ttoken->subtype = len;\n\treturn 1;\n} //end of the function PS_ReadName\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nvoid NumberValue(char *string, int subtype, unsigned long int *intvalue,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tlong double *floatvalue)\n{\n\tunsigned long int dotfound = 0;\n\n\t*intvalue = 0;\n\t*floatvalue = 0;\n\t//floating point number\n\tif (subtype & TT_FLOAT)\n\t{\n\t\twhile(*string)\n\t\t{\n\t\t\tif (*string == '.')\n\t\t\t{\n\t\t\t\tif (dotfound) return;\n\t\t\t\tdotfound = 10;\n\t\t\t\tstring++;\n\t\t\t} //end if\n\t\t\tif (dotfound)\n\t\t\t{\n\t\t\t\t*floatvalue = *floatvalue + (long double) (*string - '0') /\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t(long double) dotfound;\n\t\t\t\tdotfound *= 10;\n\t\t\t} //end if\n\t\t\telse\n\t\t\t{\n\t\t\t\t*floatvalue = *floatvalue * 10.0 + (long double) (*string - '0');\n\t\t\t} //end else\n\t\t\tstring++;\n\t\t} //end while\n\t\t*intvalue = (unsigned long) *floatvalue;\n\t} //end if\n\telse if (subtype & TT_DECIMAL)\n\t{\n\t\twhile(*string) *intvalue = *intvalue * 10 + (*string++ - '0');\n\t\t*floatvalue = *intvalue;\n\t} //end else if\n\telse if (subtype & TT_HEX)\n\t{\n\t\t//step over the leading 0x or 0X\n\t\tstring += 2;\n\t\twhile(*string)\n\t\t{\n\t\t\t*intvalue <<= 4;\n\t\t\tif (*string >= 'a' && *string <= 'f') *intvalue += *string - 'a' + 10;\n\t\t\telse if (*string >= 'A' && *string <= 'F') *intvalue += *string - 'A' + 10;\n\t\t\telse *intvalue += *string - '0';\n\t\t\tstring++;\n\t\t} //end while\n\t\t*floatvalue = *intvalue;\n\t} //end else if\n\telse if (subtype & TT_OCTAL)\n\t{\n\t\t//step over the first zero\n\t\tstring += 1;\n\t\twhile(*string) *intvalue = (*intvalue << 3) + (*string++ - '0');\n\t\t*floatvalue = *intvalue;\n\t} //end else if\n\telse if (subtype & TT_BINARY)\n\t{\n\t\t//step over the leading 0b or 0B\n\t\tstring += 2;\n\t\twhile(*string) *intvalue = (*intvalue << 1) + (*string++ - '0');\n\t\t*floatvalue = *intvalue;\n\t} //end else if\n} //end of the function NumberValue\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PS_ReadNumber(script_t *script, token_t *token)\n{\n\tint len = 0, i;\n\tint octal, dot;\n\tchar c;\n//\tunsigned long int intvalue = 0;\n//\tlong double floatvalue = 0;\n\n\ttoken->type = TT_NUMBER;\n\t//check for a hexadecimal number\n\tif (*script->script_p == '0' &&\n\t\t(*(script->script_p + 1) == 'x' ||\n\t\t*(script->script_p + 1) == 'X'))\n\t{\n\t\ttoken->string[len++] = *script->script_p++;\n\t\ttoken->string[len++] = *script->script_p++;\n\t\tc = *script->script_p;\n\t\t//hexadecimal\n\t\twhile((c >= '0' && c <= '9') ||\n\t\t\t\t\t(c >= 'a' && c <= 'f') ||\n\t\t\t\t\t(c >= 'A' && c <= 'A'))\n\t\t{\n\t\t\ttoken->string[len++] = *script->script_p++;\n\t\t\tif (len >= MAX_TOKEN)\n\t\t\t{\n\t\t\t\tScriptError(script, \"hexadecimal number longer than MAX_TOKEN = %d\", MAX_TOKEN);\n\t\t\t\treturn 0;\n\t\t\t} //end if\n\t\t\tc = *script->script_p;\n\t\t} //end while\n\t\ttoken->subtype |= TT_HEX;\n\t} //end if\n#ifdef BINARYNUMBERS\n\t//check for a binary number\n\telse if (*script->script_p == '0' &&\n\t\t(*(script->script_p + 1) == 'b' ||\n\t\t*(script->script_p + 1) == 'B'))\n\t{\n\t\ttoken->string[len++] = *script->script_p++;\n\t\ttoken->string[len++] = *script->script_p++;\n\t\tc = *script->script_p;\n\t\t//binary\n\t\twhile(c == '0' || c == '1')\n\t\t{\n\t\t\ttoken->string[len++] = *script->script_p++;\n\t\t\tif (len >= MAX_TOKEN)\n\t\t\t{\n\t\t\t\tScriptError(script, \"binary number longer than MAX_TOKEN = %d\", MAX_TOKEN);\n\t\t\t\treturn 0;\n\t\t\t} //end if\n\t\t\tc = *script->script_p;\n\t\t} //end while\n\t\ttoken->subtype |= TT_BINARY;\n\t} //end if\n#endif //BINARYNUMBERS\n\telse //decimal or octal integer or floating point number\n\t{\n\t\toctal = qfalse;\n\t\tdot = qfalse;\n\t\tif (*script->script_p == '0') octal = qtrue;\n\t\twhile(1)\n\t\t{\n\t\t\tc = *script->script_p;\n\t\t\tif (c == '.') dot = qtrue;\n\t\t\telse if (c == '8' || c == '9') octal = qfalse;\n\t\t\telse if (c < '0' || c > '9') break;\n\t\t\ttoken->string[len++] = *script->script_p++;\n\t\t\tif (len >= MAX_TOKEN - 1)\n\t\t\t{\n\t\t\t\tScriptError(script, \"number longer than MAX_TOKEN = %d\", MAX_TOKEN);\n\t\t\t\treturn 0;\n\t\t\t} //end if\n\t\t} //end while\n\t\tif (octal) token->subtype |= TT_OCTAL;\n\t\telse token->subtype |= TT_DECIMAL;\n\t\tif (dot) token->subtype |= TT_FLOAT;\n\t} //end else\n\tfor (i = 0; i < 2; i++)\n\t{\n\t\tc = *script->script_p;\n\t\t//check for a LONG number\n\t\tif ( (c == 'l' || c == 'L') // bk001204 - brackets \n\t\t     && !(token->subtype & TT_LONG))\n\t\t{\n\t\t\tscript->script_p++;\n\t\t\ttoken->subtype |= TT_LONG;\n\t\t} //end if\n\t\t//check for an UNSIGNED number\n\t\telse if ( (c == 'u' || c == 'U') // bk001204 - brackets \n\t\t\t  && !(token->subtype & (TT_UNSIGNED | TT_FLOAT)))\n\t\t{\n\t\t\tscript->script_p++;\n\t\t\ttoken->subtype |= TT_UNSIGNED;\n\t\t} //end if\n\t} //end for\n\ttoken->string[len] = '\\0';\n#ifdef NUMBERVALUE\n\tNumberValue(token->string, token->subtype, &token->intvalue, &token->floatvalue);\n#endif //NUMBERVALUE\n\tif (!(token->subtype & TT_FLOAT)) token->subtype |= TT_INTEGER;\n\treturn 1;\n} //end of the function PS_ReadNumber\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PS_ReadLiteral(script_t *script, token_t *token)\n{\n\ttoken->type = TT_LITERAL;\n\t//first quote\n\ttoken->string[0] = *script->script_p++;\n\t//check for end of file\n\tif (!*script->script_p)\n\t{\n\t\tScriptError(script, \"end of file before trailing \\'\");\n\t\treturn 0;\n\t} //end if\n\t//if it is an escape character\n\tif (*script->script_p == '\\\\')\n\t{\n\t\tif (!PS_ReadEscapeCharacter(script, &token->string[1])) return 0;\n\t} //end if\n\telse\n\t{\n\t\ttoken->string[1] = *script->script_p++;\n\t} //end else\n\t//check for trailing quote\n\tif (*script->script_p != '\\'')\n\t{\n\t\tScriptWarning(script, \"too many characters in literal, ignored\");\n\t\twhile(*script->script_p &&\n\t\t\t\t*script->script_p != '\\'' &&\n\t\t\t\t*script->script_p != '\\n')\n\t\t{\n\t\t\tscript->script_p++;\n\t\t} //end while\n\t\tif (*script->script_p == '\\'') script->script_p++;\n\t} //end if\n\t//store the trailing quote\n\ttoken->string[2] = *script->script_p++;\n\t//store trailing zero to end the string\n\ttoken->string[3] = '\\0';\n\t//the sub type is the integer literal value\n\ttoken->subtype = token->string[1];\n\t//\n\treturn 1;\n} //end of the function PS_ReadLiteral\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PS_ReadPunctuation(script_t *script, token_t *token)\n{\n\tint len;\n\tchar *p;\n\tpunctuation_t *punc;\n\n#ifdef PUNCTABLE\n\tfor (punc = script->punctuationtable[(unsigned int)*script->script_p]; punc; punc = punc->next)\n\t{\n#else\n\tint i;\n\n\tfor (i = 0; script->punctuations[i].p; i++)\n\t{\n\t\tpunc = &script->punctuations[i];\n#endif //PUNCTABLE\n\t\tp = punc->p;\n\t\tlen = (int)strlen(p);\n\t\t//if the script contains at least as much characters as the punctuation\n\t\tif (script->script_p + len <= script->end_p)\n\t\t{\n\t\t\t//if the script contains the punctuation\n\t\t\tif (!strncmp(script->script_p, p, len))\n\t\t\t{\n\t\t\t\tstrncpy(token->string, p, MAX_TOKEN);\n\t\t\t\tscript->script_p += len;\n\t\t\t\ttoken->type = TT_PUNCTUATION;\n\t\t\t\t//sub type is the number of the punctuation\n\t\t\t\ttoken->subtype = punc->n;\n\t\t\t\treturn 1;\n\t\t\t} //end if\n\t\t} //end if\n\t} //end for\n\treturn 0;\n} //end of the function PS_ReadPunctuation\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PS_ReadPrimitive(script_t *script, token_t *token)\n{\n\tint len;\n\n\tlen = 0;\n\twhile(*script->script_p > ' ' && *script->script_p != ';')\n\t{\n\t\tif (len >= MAX_TOKEN)\n\t\t{\n\t\t\tScriptError(script, \"primitive token longer than MAX_TOKEN = %d\", MAX_TOKEN);\n\t\t\treturn 0;\n\t\t} //end if\n\t\ttoken->string[len++] = *script->script_p++;\n\t} //end while\n\ttoken->string[len] = 0;\n\t//copy the token into the script structure\n\tCom_Memcpy(&script->token, token, sizeof(token_t));\n\t//primitive reading successfull\n\treturn 1;\n} //end of the function PS_ReadPrimitive\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PS_ReadToken(script_t *script, token_t *token)\n{\n\t//if there is a token available (from UnreadToken)\n\tif (script->tokenavailable)\n\t{\n\t\tscript->tokenavailable = 0;\n\t\tCom_Memcpy(token, &script->token, sizeof(token_t));\n\t\treturn 1;\n\t} //end if\n\t//save script pointer\n\tscript->lastscript_p = script->script_p;\n\t//save line counter\n\tscript->lastline = script->line;\n\t//clear the token stuff\n\tCom_Memset(token, 0, sizeof(token_t));\n\t//start of the white space\n\tscript->whitespace_p = script->script_p;\n\ttoken->whitespace_p = script->script_p;\n\t//read unusefull stuff\n\tif (!PS_ReadWhiteSpace(script)) return 0;\n\t//end of the white space\n\tscript->endwhitespace_p = script->script_p;\n\ttoken->endwhitespace_p = script->script_p;\n\t//line the token is on\n\ttoken->line = script->line;\n\t//number of lines crossed before token\n\ttoken->linescrossed = script->line - script->lastline;\n\t//if there is a leading double quote\n\tif (*script->script_p == '\\\"')\n\t{\n\t\tif (!PS_ReadString(script, token, '\\\"')) return 0;\n\t} //end if\n\t//if an literal\n\telse if (*script->script_p == '\\'')\n\t{\n\t\t//if (!PS_ReadLiteral(script, token)) return 0;\n\t\tif (!PS_ReadString(script, token, '\\'')) return 0;\n\t} //end if\n\t//if there is a number\n\telse if ((*script->script_p >= '0' && *script->script_p <= '9') ||\n\t\t\t\t(*script->script_p == '.' &&\n\t\t\t\t(*(script->script_p + 1) >= '0' && *(script->script_p + 1) <= '9')))\n\t{\n\t\tif (!PS_ReadNumber(script, token)) return 0;\n\t} //end if\n\t//if this is a primitive script\n\telse if (script->flags & SCFL_PRIMITIVE)\n\t{\n\t\treturn PS_ReadPrimitive(script, token);\n\t} //end else if\n\t//if there is a name\n\telse if ((*script->script_p >= 'a' && *script->script_p <= 'z') ||\n\t\t(*script->script_p >= 'A' && *script->script_p <= 'Z') ||\n\t\t*script->script_p == '_')\n\t{\n\t\tif (!PS_ReadName(script, token)) return 0;\n\t} //end if\n\t//check for punctuations\n\telse if (!PS_ReadPunctuation(script, token))\n\t{\n\t\tScriptError(script, \"can't read token\");\n\t\treturn 0;\n\t} //end if\n\t//copy the token into the script structure\n\tCom_Memcpy(&script->token, token, sizeof(token_t));\n\t//succesfully read a token\n\treturn 1;\n} //end of the function PS_ReadToken\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PS_ExpectTokenString(script_t *script, char *string)\n{\n\ttoken_t token;\n\n\tif (!PS_ReadToken(script, &token))\n\t{\n\t\tScriptError(script, \"couldn't find expected %s\", string);\n\t\treturn 0;\n\t} //end if\n\n\tif (strcmp(token.string, string))\n\t{\n\t\tScriptError(script, \"expected %s, found %s\", string, token.string);\n\t\treturn 0;\n\t} //end if\n\treturn 1;\n} //end of the function PS_ExpectToken\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PS_ExpectTokenType(script_t *script, int type, int subtype, token_t *token)\n{\n\tchar str[MAX_TOKEN];\n\n\tif (!PS_ReadToken(script, token))\n\t{\n\t\tScriptError(script, \"couldn't read expected token\");\n\t\treturn 0;\n\t} //end if\n\n\tif (token->type != type)\n\t{\n\t\tif (type == TT_STRING) strcpy(str, \"string\");\n\t\tif (type == TT_LITERAL) strcpy(str, \"literal\");\n\t\tif (type == TT_NUMBER) strcpy(str, \"number\");\n\t\tif (type == TT_NAME) strcpy(str, \"name\");\n\t\tif (type == TT_PUNCTUATION) strcpy(str, \"punctuation\");\n\t\tScriptError(script, \"expected a %s, found %s\", str, token->string);\n\t\treturn 0;\n\t} //end if\n\tif (token->type == TT_NUMBER)\n\t{\n\t\tif ((token->subtype & subtype) != subtype)\n\t\t{\n\t\t\tif (subtype & TT_DECIMAL) strcpy(str, \"decimal\");\n\t\t\tif (subtype & TT_HEX) strcpy(str, \"hex\");\n\t\t\tif (subtype & TT_OCTAL) strcpy(str, \"octal\");\n\t\t\tif (subtype & TT_BINARY) strcpy(str, \"binary\");\n\t\t\tif (subtype & TT_LONG) strcat(str, \" long\");\n\t\t\tif (subtype & TT_UNSIGNED) strcat(str, \" unsigned\");\n\t\t\tif (subtype & TT_FLOAT) strcat(str, \" float\");\n\t\t\tif (subtype & TT_INTEGER) strcat(str, \" integer\");\n\t\t\tScriptError(script, \"expected %s, found %s\", str, token->string);\n\t\t\treturn 0;\n\t\t} //end if\n\t} //end if\n\telse if (token->type == TT_PUNCTUATION)\n\t{\n\t\tif (subtype < 0)\n\t\t{\n\t\t\tScriptError(script, \"BUG: wrong punctuation subtype\");\n\t\t\treturn 0;\n\t\t} //end if\n\t\tif (token->subtype != subtype)\n\t\t{\n\t\t\tScriptError(script, \"expected %s, found %s\",\n\t\t\t\t\t\t\tscript->punctuations[subtype], token->string);\n\t\t\treturn 0;\n\t\t} //end if\n\t} //end else if\n\treturn 1;\n} //end of the function PS_ExpectTokenType\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PS_ExpectAnyToken(script_t *script, token_t *token)\n{\n\tif (!PS_ReadToken(script, token))\n\t{\n\t\tScriptError(script, \"couldn't read expected token\");\n\t\treturn 0;\n\t} //end if\n\telse\n\t{\n\t\treturn 1;\n\t} //end else\n} //end of the function PS_ExpectAnyToken\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PS_CheckTokenString(script_t *script, char *string)\n{\n\ttoken_t tok;\n\n\tif (!PS_ReadToken(script, &tok)) return 0;\n\t//if the token is available\n\tif (!strcmp(tok.string, string)) return 1;\n\t//token not available\n\tscript->script_p = script->lastscript_p;\n\treturn 0;\n} //end of the function PS_CheckTokenString\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PS_CheckTokenType(script_t *script, int type, int subtype, token_t *token)\n{\n\ttoken_t tok;\n\n\tif (!PS_ReadToken(script, &tok)) return 0;\n\t//if the type matches\n\tif (tok.type == type &&\n\t\t\t(tok.subtype & subtype) == subtype)\n\t{\n\t\tCom_Memcpy(token, &tok, sizeof(token_t));\n\t\treturn 1;\n\t} //end if\n\t//token is not available\n\tscript->script_p = script->lastscript_p;\n\treturn 0;\n} //end of the function PS_CheckTokenType\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint PS_SkipUntilString(script_t *script, char *string)\n{\n\ttoken_t token;\n\n\twhile(PS_ReadToken(script, &token))\n\t{\n\t\tif (!strcmp(token.string, string)) return 1;\n\t} //end while\n\treturn 0;\n} //end of the function PS_SkipUntilString\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nvoid PS_UnreadLastToken(script_t *script)\n{\n\tscript->tokenavailable = 1;\n} //end of the function UnreadLastToken\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nvoid PS_UnreadToken(script_t *script, token_t *token)\n{\n\tCom_Memcpy(&script->token, token, sizeof(token_t));\n\tscript->tokenavailable = 1;\n} //end of the function UnreadToken\n//============================================================================\n// returns the next character of the read white space, returns NULL if none\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nchar PS_NextWhiteSpaceChar(script_t *script)\n{\n\tif (script->whitespace_p != script->endwhitespace_p)\n\t{\n\t\treturn *script->whitespace_p++;\n\t} //end if\n\telse\n\t{\n\t\treturn 0;\n\t} //end else\n} //end of the function PS_NextWhiteSpaceChar\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nvoid StripDoubleQuotes(char *string)\n{\n\tif (*string == '\\\"')\n\t{\n\t\tstrcpy(string, string+1);\n\t} //end if\n\tif (string[strlen(string)-1] == '\\\"')\n\t{\n\t\tstring[strlen(string)-1] = '\\0';\n\t} //end if\n} //end of the function StripDoubleQuotes\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nvoid StripSingleQuotes(char *string)\n{\n\tif (*string == '\\'')\n\t{\n\t\tstrcpy(string, string+1);\n\t} //end if\n\tif (string[strlen(string)-1] == '\\'')\n\t{\n\t\tstring[strlen(string)-1] = '\\0';\n\t} //end if\n} //end of the function StripSingleQuotes\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nlong double ReadSignedFloat(script_t *script)\n{\n\ttoken_t token;\n\tlong double sign = 1;\n\n\tPS_ExpectAnyToken(script, &token);\n\tif (!strcmp(token.string, \"-\"))\n\t{\n\t\tsign = -1;\n\t\tPS_ExpectTokenType(script, TT_NUMBER, 0, &token);\n\t} //end if\n\telse if (token.type != TT_NUMBER)\n\t{\n\t\tScriptError(script, \"expected float value, found %s\\n\", token.string);\n\t} //end else if\n\treturn sign * token.floatvalue;\n} //end of the function ReadSignedFloat\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nsigned long int ReadSignedInt(script_t *script)\n{\n\ttoken_t token;\n\tsigned long int sign = 1;\n\n\tPS_ExpectAnyToken(script, &token);\n\tif (!strcmp(token.string, \"-\"))\n\t{\n\t\tsign = -1;\n\t\tPS_ExpectTokenType(script, TT_NUMBER, TT_INTEGER, &token);\n\t} //end if\n\telse if (token.type != TT_NUMBER || token.subtype == TT_FLOAT)\n\t{\n\t\tScriptError(script, \"expected integer value, found %s\\n\", token.string);\n\t} //end else if\n\treturn sign * token.intvalue;\n} //end of the function ReadSignedInt\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nvoid SetScriptFlags(script_t *script, int flags)\n{\n\tscript->flags = flags;\n} //end of the function SetScriptFlags\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint GetScriptFlags(script_t *script)\n{\n\treturn script->flags;\n} //end of the function GetScriptFlags\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nvoid ResetScript(script_t *script)\n{\n\t//pointer in script buffer\n\tscript->script_p = script->buffer;\n\t//pointer in script buffer before reading token\n\tscript->lastscript_p = script->buffer;\n\t//begin of white space\n\tscript->whitespace_p = NULL;\n\t//end of white space\n\tscript->endwhitespace_p = NULL;\n\t//set if there's a token available in script->token\n\tscript->tokenavailable = 0;\n\t//\n\tscript->line = 1;\n\tscript->lastline = 1;\n\t//clear the saved token\n\tCom_Memset(&script->token, 0, sizeof(token_t));\n} //end of the function ResetScript\n//============================================================================\n// returns true if at the end of the script\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint EndOfScript(script_t *script)\n{\n\treturn script->script_p >= script->end_p;\n} //end of the function EndOfScript\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint NumLinesCrossed(script_t *script)\n{\n\treturn script->line - script->lastline;\n} //end of the function NumLinesCrossed\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint ScriptSkipTo(script_t *script, char *value)\n{\n\tint len;\n\tchar firstchar;\n\n\tfirstchar = *value;\n\tlen = (int)strlen(value);\n\tdo\n\t{\n\t\tif (!PS_ReadWhiteSpace(script)) return 0;\n\t\tif (*script->script_p == firstchar)\n\t\t{\n\t\t\tif (!strncmp(script->script_p, value, len))\n\t\t\t{\n\t\t\t\treturn 1;\n\t\t\t} //end if\n\t\t} //end if\n\t\tscript->script_p++;\n\t} while(1);\n} //end of the function ScriptSkipTo\n#ifndef BOTLIB\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nint FileLength(FILE *fp)\n{\n\tint pos;\n\tint end;\n\n\tpos = ftell(fp);\n\tfseek(fp, 0, SEEK_END);\n\tend = ftell(fp);\n\tfseek(fp, pos, SEEK_SET);\n\n\treturn end;\n} //end of the function FileLength\n#endif\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nscript_t *LoadScriptFile(const char *filename)\n{\n#ifdef BOTLIB\n\tfileHandle_t fp;\n\tchar pathname[MAX_QPATH];\n#else\n\tFILE *fp;\n#endif\n\tint length;\n\tvoid *buffer;\n\tscript_t *script;\n\n#ifdef BOTLIB\n\tif (strlen(basefolder))\n\t\tCom_sprintf(pathname, sizeof(pathname), \"%s/%s\", basefolder, filename);\n\telse\n\t\tCom_sprintf(pathname, sizeof(pathname), \"%s\", filename);\n\tlength = botimport.FS_FOpenFile( pathname, &fp, FS_READ );\n\tif (!fp) return NULL;\n#else\n\tfp = fopen(filename, \"rb\");\n\tif (!fp) return NULL;\n\n\tlength = FileLength(fp);\n#endif\n\n\tbuffer = GetClearedMemory(sizeof(script_t) + length + 1);\n\tscript = (script_t *) buffer;\n\tCom_Memset(script, 0, sizeof(script_t));\n\tstrcpy(script->filename, filename);\n\tscript->buffer = (char *) buffer + sizeof(script_t);\n\tscript->buffer[length] = 0;\n\tscript->length = length;\n\t//pointer in script buffer\n\tscript->script_p = script->buffer;\n\t//pointer in script buffer before reading token\n\tscript->lastscript_p = script->buffer;\n\t//pointer to end of script buffer\n\tscript->end_p = &script->buffer[length];\n\t//set if there's a token available in script->token\n\tscript->tokenavailable = 0;\n\t//\n\tscript->line = 1;\n\tscript->lastline = 1;\n\t//\n\tSetScriptPunctuations(script, NULL);\n\t//\n#ifdef BOTLIB\n\tbotimport.FS_Read(script->buffer, length, fp);\n\tbotimport.FS_FCloseFile(fp);\n#else\n\tif (fread(script->buffer, length, 1, fp) != 1)\n\t{\n\t\tFreeMemory(buffer);\n\t\tscript = NULL;\n\t} //end if\n\tfclose(fp);\n#endif\n\t//\n\tscript->length = COM_Compress(script->buffer);\n\n\treturn script;\n} //end of the function LoadScriptFile\n//============================================================================\n//\n// Parameter:\t\t\t-\n// Returns:\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nscript_t *LoadScriptMemory(char *ptr, int length, char *name)\n{\n\tvoid *buffer;\n\tscript_t *script;\n\n\tbuffer = GetClearedMemory(sizeof(script_t) + length + 1);\n\tscript = (script_t *) buffer;\n\tCom_Memset(script, 0, sizeof(script_t));\n\tstrcpy(script->filename, name);\n\tscript->buffer = (char *) buffer + sizeof(script_t);\n\tscript->buffer[length] = 0;\n\tscript->length = length;\n\t//pointer in script buffer\n\tscript->script_p = script->buffer;\n\t//pointer in script buffer before reading token\n\tscript->lastscript_p = script->buffer;\n\t//pointer to end of script buffer\n\tscript->end_p = &script->buffer[length];\n\t//set if there's a token available in script->token\n\tscript->tokenavailable = 0;\n\t//\n\tscript->line = 1;\n\tscript->lastline = 1;\n\t//\n\tSetScriptPunctuations(script, NULL);\n\t//\n\tCom_Memcpy(script->buffer, ptr, length);\n\t//\n\treturn script;\n} //end of the function LoadScriptMemory\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nvoid FreeScript(script_t *script)\n{\n#ifdef PUNCTABLE\n\tif (script->punctuationtable) FreeMemory(script->punctuationtable);\n#endif //PUNCTABLE\n\tFreeMemory(script);\n} //end of the function FreeScript\n//============================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//============================================================================\nvoid PS_SetBaseFolder(char *path)\n{\n#ifdef BSPC\n\tsprintf(basefolder, path);\n#else\n\tCom_sprintf(basefolder, sizeof(basefolder), path);\n#endif\n} //end of the function PS_SetBaseFolder\n"
  },
  {
    "path": "src/engine/botlib/l_script.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tl_script.h\n *\n * desc:\t\tlexicographical parser\n *\n * $Archive: /source/code/botlib/l_script.h $\n *\n *****************************************************************************/\n\n//undef if binary numbers of the form 0b... or 0B... are not allowed\n#define BINARYNUMBERS\n//undef if not using the token.intvalue and token.floatvalue\n#define NUMBERVALUE\n//use dollar sign also as punctuation\n#define DOLLAR\n\n//maximum token length\n#define MAX_TOKEN\t\t\t\t\t1024\n\n#if defined(BSPC) && !defined(QDECL)\n#define QDECL\n#endif\n\n\n//script flags\n#define SCFL_NOERRORS\t\t\t\t0x0001\n#define SCFL_NOWARNINGS\t\t\t\t0x0002\n#define SCFL_NOSTRINGWHITESPACES\t0x0004\n#define SCFL_NOSTRINGESCAPECHARS\t0x0008\n#define SCFL_PRIMITIVE\t\t\t\t0x0010\n#define SCFL_NOBINARYNUMBERS\t\t0x0020\n#define SCFL_NONUMBERVALUES\t\t0x0040\n\n//token types\n#define TT_STRING\t\t\t\t\t\t1\t\t\t// string\n#define TT_LITERAL\t\t\t\t\t2\t\t\t// literal\n#define TT_NUMBER\t\t\t\t\t\t3\t\t\t// number\n#define TT_NAME\t\t\t\t\t\t4\t\t\t// name\n#define TT_PUNCTUATION\t\t\t\t5\t\t\t// punctuation\n\n//string sub type\n//---------------\n//\t\tthe length of the string\n//literal sub type\n//----------------\n//\t\tthe ASCII code of the literal\n//number sub type\n//---------------\n#define TT_DECIMAL\t\t\t\t\t0x0008\t// decimal number\n#define TT_HEX\t\t\t\t\t\t\t0x0100\t// hexadecimal number\n#define TT_OCTAL\t\t\t\t\t\t0x0200\t// octal number\n#ifdef BINARYNUMBERS\n#define TT_BINARY\t\t\t\t\t\t0x0400\t// binary number\n#endif //BINARYNUMBERS\n#define TT_FLOAT\t\t\t\t\t\t0x0800\t// floating point number\n#define TT_INTEGER\t\t\t\t\t0x1000\t// integer number\n#define TT_LONG\t\t\t\t\t\t0x2000\t// long number\n#define TT_UNSIGNED\t\t\t\t\t0x4000\t// unsigned number\n//punctuation sub type\n//--------------------\n#define P_RSHIFT_ASSIGN\t\t\t\t1\n#define P_LSHIFT_ASSIGN\t\t\t\t2\n#define P_PARMS\t\t\t\t\t\t3\n#define P_PRECOMPMERGE\t\t\t\t4\n\n#define P_LOGIC_AND\t\t\t\t\t5\n#define P_LOGIC_OR\t\t\t\t\t6\n#define P_LOGIC_GEQ\t\t\t\t\t7\n#define P_LOGIC_LEQ\t\t\t\t\t8\n#define P_LOGIC_EQ\t\t\t\t\t9\n#define P_LOGIC_UNEQ\t\t\t\t\t10\n\n#define P_MUL_ASSIGN\t\t\t\t\t11\n#define P_DIV_ASSIGN\t\t\t\t\t12\n#define P_MOD_ASSIGN\t\t\t\t\t13\n#define P_ADD_ASSIGN\t\t\t\t\t14\n#define P_SUB_ASSIGN\t\t\t\t\t15\n#define P_INC\t\t\t\t\t\t\t16\n#define P_DEC\t\t\t\t\t\t\t17\n\n#define P_BIN_AND_ASSIGN\t\t\t18\n#define P_BIN_OR_ASSIGN\t\t\t\t19\n#define P_BIN_XOR_ASSIGN\t\t\t20\n#define P_RSHIFT\t\t\t\t\t\t21\n#define P_LSHIFT\t\t\t\t\t\t22\n\n#define P_POINTERREF\t\t\t\t\t23\n#define P_CPP1\t\t\t\t\t\t\t24\n#define P_CPP2\t\t\t\t\t\t\t25\n#define P_MUL\t\t\t\t\t\t\t26\n#define P_DIV\t\t\t\t\t\t\t27\n#define P_MOD\t\t\t\t\t\t\t28\n#define P_ADD\t\t\t\t\t\t\t29\n#define P_SUB\t\t\t\t\t\t\t30\n#define P_ASSIGN\t\t\t\t\t\t31\n\n#define P_BIN_AND\t\t\t\t\t\t32\n#define P_BIN_OR\t\t\t\t\t\t33\n#define P_BIN_XOR\t\t\t\t\t\t34\n#define P_BIN_NOT\t\t\t\t\t\t35\n\n#define P_LOGIC_NOT\t\t\t\t\t36\n#define P_LOGIC_GREATER\t\t\t\t37\n#define P_LOGIC_LESS\t\t\t\t\t38\n\n#define P_REF\t\t\t\t\t\t\t39\n#define P_COMMA\t\t\t\t\t\t40\n#define P_SEMICOLON\t\t\t\t\t41\n#define P_COLON\t\t\t\t\t\t42\n#define P_QUESTIONMARK\t\t\t\t43\n\n#define P_PARENTHESESOPEN\t\t\t44\n#define P_PARENTHESESCLOSE\t\t\t45\n#define P_BRACEOPEN\t\t\t\t\t46\n#define P_BRACECLOSE\t\t\t\t\t47\n#define P_SQBRACKETOPEN\t\t\t\t48\n#define P_SQBRACKETCLOSE\t\t\t49\n#define P_BACKSLASH\t\t\t\t\t50\n\n#define P_PRECOMP\t\t\t\t\t\t51\n#define P_DOLLAR\t\t\t\t\t\t52\n//name sub type\n//-------------\n//\t\tthe length of the name\n\n//punctuation\ntypedef struct punctuation_s\n{\n\tchar *p;\t\t\t\t\t\t//punctuation character(s)\n\tint n;\t\t\t\t\t\t\t//punctuation indication\n\tstruct punctuation_s *next;\t\t//next punctuation\n} punctuation_t;\n\n//token\ntypedef struct token_s\n{\n\tchar string[MAX_TOKEN];\t\t\t//available token\n\tint type;\t\t\t\t\t\t//last read token type\n\tint subtype;\t\t\t\t\t//last read token sub type\n#ifdef NUMBERVALUE\n\tunsigned long int intvalue;\t//integer value\n\tlong double floatvalue;\t\t\t//floating point value\n#endif //NUMBERVALUE\n\tchar *whitespace_p;\t\t\t\t//start of white space before token\n\tchar *endwhitespace_p;\t\t\t//start of white space before token\n\tint line;\t\t\t\t\t\t//line the token was on\n\tint linescrossed;\t\t\t\t//lines crossed in white space\n\tstruct token_s *next;\t\t\t//next token in chain\n} token_t;\n\n//script file\ntypedef struct script_s\n{\n\tchar filename[1024];\t\t\t//file name of the script\n\tchar *buffer;\t\t\t\t\t//buffer containing the script\n\tchar *script_p;\t\t\t\t\t//current pointer in the script\n\tchar *end_p;\t\t\t\t\t//pointer to the end of the script\n\tchar *lastscript_p;\t\t\t\t//script pointer before reading token\n\tchar *whitespace_p;\t\t\t\t//begin of the white space\n\tchar *endwhitespace_p;\t\t\t//end of the white space\n\tint length;\t\t\t\t\t\t//length of the script in bytes\n\tint line;\t\t\t\t\t\t//current line in script\n\tint lastline;\t\t\t\t\t//line before reading token\n\tint tokenavailable;\t\t\t\t//set by UnreadLastToken\n\tint flags;\t\t\t\t\t\t//several script flags\n\tpunctuation_t *punctuations;\t//the punctuations used in the script\n\tpunctuation_t **punctuationtable;\n\ttoken_t token;\t\t\t\t\t//available token\n\tstruct script_s *next;\t\t\t//next script in a chain\n} script_t;\n\n//read a token from the script\nint PS_ReadToken(script_t *script, token_t *token);\n//expect a certain token\nint PS_ExpectTokenString(script_t *script, char *string);\n//expect a certain token type\nint PS_ExpectTokenType(script_t *script, int type, int subtype, token_t *token);\n//expect a token\nint PS_ExpectAnyToken(script_t *script, token_t *token);\n//returns true when the token is available\nint PS_CheckTokenString(script_t *script, char *string);\n//returns true an reads the token when a token with the given type is available\nint PS_CheckTokenType(script_t *script, int type, int subtype, token_t *token);\n//skip tokens until the given token string is read\nint PS_SkipUntilString(script_t *script, char *string);\n//unread the last token read from the script\nvoid PS_UnreadLastToken(script_t *script);\n//unread the given token\nvoid PS_UnreadToken(script_t *script, token_t *token);\n//returns the next character of the read white space, returns NULL if none\nchar PS_NextWhiteSpaceChar(script_t *script);\n//remove any leading and trailing double quotes from the token\nvoid StripDoubleQuotes(char *string);\n//remove any leading and trailing single quotes from the token\nvoid StripSingleQuotes(char *string);\n//read a possible signed integer\nsigned long int ReadSignedInt(script_t *script);\n//read a possible signed floating point number\nlong double ReadSignedFloat(script_t *script);\n//set an array with punctuations, NULL restores default C/C++ set\nvoid SetScriptPunctuations(script_t *script, punctuation_t *p);\n//set script flags\nvoid SetScriptFlags(script_t *script, int flags);\n//get script flags\nint GetScriptFlags(script_t *script);\n//reset a script\nvoid ResetScript(script_t *script);\n//returns true if at the end of the script\nint EndOfScript(script_t *script);\n//returns a pointer to the punctuation with the given number\nchar *PunctuationFromNum(script_t *script, int num);\n//load a script from the given file at the given offset with the given length\nscript_t *LoadScriptFile(const char *filename);\n//load a script from the given memory with the given length\nscript_t *LoadScriptMemory(char *ptr, int length, char *name);\n//free a script\nvoid FreeScript(script_t *script);\n//set the base folder to load files from\nvoid PS_SetBaseFolder(char *path);\n//print a script error with filename and line number\nvoid QDECL ScriptError(script_t *script, char *str, ...);\n//print a script warning with filename and line number\nvoid QDECL ScriptWarning(script_t *script, char *str, ...);\n\n\n"
  },
  {
    "path": "src/engine/botlib/l_struct.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tl_struct.c\n *\n * desc:\t\tstructure reading / writing\n *\n * $Archive: /MissionPack/CODE/botlib/l_struct.c $\n *\n *****************************************************************************/\n\n#ifdef BOTLIB\n#include \"../../game/q_shared.h\"\n#include \"../../game/botlib.h\"\t\t\t\t//for the include of be_interface.h\n#include \"l_script.h\"\n#include \"l_precomp.h\"\n#include \"l_struct.h\"\n#include \"l_utils.h\"\n#include \"be_interface.h\"\n#endif //BOTLIB\n\n#ifdef BSPC\n//include files for usage in the BSP Converter\n#include \"../bspc/qbsp.h\"\n#include \"../bspc/l_log.h\"\n#include \"../bspc/l_mem.h\"\n#include \"l_precomp.h\"\n#include \"l_struct.h\"\n\n#define qtrue\ttrue\n#define qfalse\tfalse\n#endif //BSPC\n\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nfielddef_t *FindField(fielddef_t *defs, char *name)\n{\n\tint i;\n\n\tfor (i = 0; defs[i].name; i++)\n\t{\n\t\tif (!strcmp(defs[i].name, name)) return &defs[i];\n\t} //end for\n\treturn NULL;\n} //end of the function FindField\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nqboolean ReadNumber(source_t *source, fielddef_t *fd, void *p)\n{\n\ttoken_t token;\n\tint negative = qfalse;\n\tlong int intval, intmin = 0, intmax = 0;\n\tdouble floatval;\n\n\tif (!PC_ExpectAnyToken(source, &token)) return (qboolean) 0;\n\n\t//check for minus sign\n\tif (token.type == TT_PUNCTUATION)\n\t{\n\t\tif (fd->type & FT_UNSIGNED)\n\t\t{\n\t\t\tSourceError(source, \"expected unsigned value, found %s\", token.string);\n\t\t\treturn (qboolean) 0;\n\t\t} //end if\n\t\t//if not a minus sign\n\t\tif (strcmp(token.string, \"-\"))\n\t\t{\n\t\t\tSourceError(source, \"unexpected punctuation %s\", token.string);\n\t\t\treturn (qboolean) 0;\n\t\t} //end if\n\t\tnegative = qtrue;\n\t\t//read the number\n\t\tif (!PC_ExpectAnyToken(source, &token)) return (qboolean) 0;\n\t} //end if\n\t//check if it is a number\n\tif (token.type != TT_NUMBER)\n\t{\n\t\tSourceError(source, \"expected number, found %s\", token.string);\n\t\treturn (qboolean) 0;\n\t} //end if\n\t//check for a float value\n\tif (token.subtype & TT_FLOAT)\n\t{\n\t\tif ((fd->type & FT_TYPE) != FT_FLOAT)\n\t\t{\n\t\t\tSourceError(source, \"unexpected float\");\n\t\t\treturn (qboolean) 0;\n\t\t} //end if\n\t\tfloatval = token.floatvalue;\n\t\tif (negative) floatval = -floatval;\n\t\tif (fd->type & FT_BOUNDED)\n\t\t{\n\t\t\tif (floatval < fd->floatmin || floatval > fd->floatmax)\n\t\t\t{\n\t\t\t\tSourceError(source, \"float out of range [%f, %f]\", fd->floatmin, fd->floatmax);\n\t\t\t\treturn (qboolean) 0;\n\t\t\t} //end if\n\t\t} //end if\n\t\t*(float *) p = (float) floatval;\n\t\treturn (qboolean) 1;\n\t} //end if\n\t//\n\tintval = token.intvalue;\n\tif (negative) intval = -intval;\n\t//check bounds\n\tif ((fd->type & FT_TYPE) == FT_CHAR)\n\t{\n\t\tif (fd->type & FT_UNSIGNED) {intmin = 0; intmax = 255;}\n\t\telse {intmin = -128; intmax = 127;}\n\t} //end if\n\tif ((fd->type & FT_TYPE) == FT_INT)\n\t{\n\t\tif (fd->type & FT_UNSIGNED) {intmin = 0; intmax = 65535;}\n\t\telse {intmin = -32768; intmax = 32767;}\n\t} //end else if\n\tif ((fd->type & FT_TYPE) == FT_CHAR || (fd->type & FT_TYPE) == FT_INT)\n\t{\n\t\tif (fd->type & FT_BOUNDED)\n\t\t{\n\t\t\tintmin = Maximum(intmin, fd->floatmin);\n\t\t\tintmax = Minimum(intmax, fd->floatmax);\n\t\t} //end if\n\t\tif (intval < intmin || intval > intmax)\n\t\t{\n\t\t\tSourceError(source, \"value %d out of range [%d, %d]\", intval, intmin, intmax);\n\t\t\treturn (qboolean) 0;\n\t\t} //end if\n\t} //end if\n\telse if ((fd->type & FT_TYPE) == FT_FLOAT)\n\t{\n\t\tif (fd->type & FT_BOUNDED)\n\t\t{\n\t\t\tif (intval < fd->floatmin || intval > fd->floatmax)\n\t\t\t{\n\t\t\t\tSourceError(source, \"value %d out of range [%f, %f]\", intval, fd->floatmin, fd->floatmax);\n\t\t\t\treturn (qboolean) 0;\n\t\t\t} //end if\n\t\t} //end if\n\t} //end else if\n\t//store the value\n\tif ((fd->type & FT_TYPE) == FT_CHAR)\n\t{\n\t\tif (fd->type & FT_UNSIGNED) *(unsigned char *) p = (unsigned char) intval;\n\t\telse *(char *) p = (char) intval;\n\t} //end if\n\telse if ((fd->type & FT_TYPE) == FT_INT)\n\t{\n\t\tif (fd->type & FT_UNSIGNED) *(unsigned int *) p = (unsigned int) intval;\n\t\telse *(int *) p = (int) intval;\n\t} //end else\n\telse if ((fd->type & FT_TYPE) == FT_FLOAT)\n\t{\n\t\t*(float *) p = (float) intval;\n\t} //end else\n\treturn (qboolean) 1;\n} //end of the function ReadNumber\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nqboolean ReadChar(source_t *source, fielddef_t *fd, void *p)\n{\n\ttoken_t token;\n\n\tif (!PC_ExpectAnyToken(source, &token)) return (qboolean) 0;\n\n\t//take literals into account\n\tif (token.type == TT_LITERAL)\n\t{\n\t\tStripSingleQuotes(token.string);\n\t\t*(char *) p = token.string[0];\n\t} //end if\n\telse\n\t{\n\t\tPC_UnreadLastToken(source);\n\t\tif (!ReadNumber(source, fd, p)) return (qboolean) 0;\n\t} //end if\n\treturn (qboolean) 1;\n} //end of the function ReadChar\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint ReadString(source_t *source, fielddef_t *fd, void *p)\n{\n\ttoken_t token;\n\n\tif (!PC_ExpectTokenType(source, TT_STRING, 0, &token)) return 0;\n\t//remove the double quotes\n\tStripDoubleQuotes(token.string);\n\t//copy the string\n\tstrncpy((char *) p, token.string, MAX_STRINGFIELD);\n\t//make sure the string is closed with a zero\n\t((char *)p)[MAX_STRINGFIELD-1] = '\\0';\n\t//\n\treturn 1;\n} //end of the function ReadString\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint ReadStructure(source_t *source, structdef_t *def, char *structure)\n{\n\ttoken_t token;\n\tfielddef_t *fd;\n\tvoid *p;\n\tint num;\n\n\tif (!PC_ExpectTokenString(source, \"{\")) return 0;\n\twhile(1)\n\t{\n\t\tif (!PC_ExpectAnyToken(source, &token)) return qfalse;\n\t\t//if end of structure\n\t\tif (!strcmp(token.string, \"}\")) break;\n\t\t//find the field with the name\n\t\tfd = FindField(def->fields, token.string);\n\t\tif (!fd)\n\t\t{\n\t\t\tSourceError(source, \"unknown structure field %s\", token.string);\n\t\t\treturn qfalse;\n\t\t} //end if\n\t\tif (fd->type & FT_ARRAY)\n\t\t{\n\t\t\tnum = fd->maxarray;\n\t\t\tif (!PC_ExpectTokenString(source, \"{\")) return qfalse;\n\t\t} //end if\n\t\telse\n\t\t{\n\t\t\tnum = 1;\n\t\t} //end else\n\t\tp = (void *)(structure + fd->offset);\n\t\twhile (num-- > 0)\n\t\t{\n\t\t\tif (fd->type & FT_ARRAY)\n\t\t\t{\n\t\t\t\tif (PC_CheckTokenString(source, \"}\")) break;\n\t\t\t} //end if\n\t\t\tswitch(fd->type & FT_TYPE)\n\t\t\t{\n\t\t\t\tcase FT_CHAR:\n\t\t\t\t{\n\t\t\t\t\tif (!ReadChar(source, fd, p)) return qfalse;\n\t\t\t\t\tp = (char *) p + sizeof(char);\n\t\t\t\t\tbreak;\n\t\t\t\t} //end case\n\t\t\t\tcase FT_INT:\n\t\t\t\t{\n\t\t\t\t\tif (!ReadNumber(source, fd, p)) return qfalse;\n\t\t\t\t\tp = (char *) p + sizeof(int);\n\t\t\t\t\tbreak;\n\t\t\t\t} //end case\n\t\t\t\tcase FT_FLOAT:\n\t\t\t\t{\n\t\t\t\t\tif (!ReadNumber(source, fd, p)) return qfalse;\n\t\t\t\t\tp = (char *) p + sizeof(float);\n\t\t\t\t\tbreak;\n\t\t\t\t} //end case\n\t\t\t\tcase FT_STRING:\n\t\t\t\t{\n\t\t\t\t\tif (!ReadString(source, fd, p)) return qfalse;\n\t\t\t\t\tp = (char *) p + MAX_STRINGFIELD;\n\t\t\t\t\tbreak;\n\t\t\t\t} //end case\n\t\t\t\tcase FT_STRUCT:\n\t\t\t\t{\n\t\t\t\t\tif (!fd->substruct)\n\t\t\t\t\t{\n\t\t\t\t\t\tSourceError(source, \"BUG: no sub structure defined\");\n\t\t\t\t\t\treturn qfalse;\n\t\t\t\t\t} //end if\n\t\t\t\t\tReadStructure(source, fd->substruct, (char *) p);\n\t\t\t\t\tp = (char *) p + fd->substruct->size;\n\t\t\t\t\tbreak;\n\t\t\t\t} //end case\n\t\t\t} //end switch\n\t\t\tif (fd->type & FT_ARRAY)\n\t\t\t{\n\t\t\t\tif (!PC_ExpectAnyToken(source, &token)) return qfalse;\n\t\t\t\tif (!strcmp(token.string, \"}\")) break;\n\t\t\t\tif (strcmp(token.string, \",\"))\n\t\t\t\t{\n\t\t\t\t\tSourceError(source, \"expected a comma, found %s\", token.string);\n\t\t\t\t\treturn qfalse;\n\t\t\t\t} //end if\n\t\t\t} //end if\n\t\t} //end while\n\t} //end while\n\treturn qtrue;\n} //end of the function ReadStructure\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint WriteIndent(FILE *fp, int indent)\n{\n\twhile(indent-- > 0)\n\t{\n\t\tif (fprintf(fp, \"\\t\") < 0) return qfalse;\n\t} //end while\n\treturn qtrue;\n} //end of the function WriteIndent\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint WriteFloat(FILE *fp, float value)\n{\n\tchar buf[128];\n\tint l;\n\n\tsprintf(buf, \"%f\", value);\n\tl = (int)strlen(buf);\n\t//strip any trailing zeros\n\twhile(l-- > 1)\n\t{\n\t\tif (buf[l] != '0' && buf[l] != '.') break;\n\t\tif (buf[l] == '.')\n\t\t{\n\t\t\tbuf[l] = 0;\n\t\t\tbreak;\n\t\t} //end if\n\t\tbuf[l] = 0;\n\t} //end while\n\t//write the float to file\n\tif (fprintf(fp, \"%s\", buf) < 0) return 0;\n\treturn 1;\n} //end of the function WriteFloat\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint WriteStructWithIndent(FILE *fp, structdef_t *def, char *structure, int indent)\n{\n\tint i, num;\n\tvoid *p;\n\tfielddef_t *fd;\n\n\tif (!WriteIndent(fp, indent)) return qfalse;\n\tif (fprintf(fp, \"{\\r\\n\") < 0) return qfalse;\n\n\tindent++;\n\tfor (i = 0; def->fields[i].name; i++)\n\t{\n\t\tfd = &def->fields[i];\n\t\tif (!WriteIndent(fp, indent)) return qfalse;\n\t\tif (fprintf(fp, \"%s\\t\", fd->name) < 0) return qfalse;\n\t\tp = (void *)(structure + fd->offset);\n\t\tif (fd->type & FT_ARRAY)\n\t\t{\n\t\t\tnum = fd->maxarray;\n\t\t\tif (fprintf(fp, \"{\") < 0) return qfalse;\n\t\t} //end if\n\t\telse\n\t\t{\n\t\t\tnum = 1;\n\t\t} //end else\n\t\twhile(num-- > 0)\n\t\t{\n\t\t\tswitch(fd->type & FT_TYPE)\n\t\t\t{\n\t\t\t\tcase FT_CHAR:\n\t\t\t\t{\n\t\t\t\t\tif (fprintf(fp, \"%d\", *(char *) p) < 0) return qfalse;\n\t\t\t\t\tp = (char *) p + sizeof(char);\n\t\t\t\t\tbreak;\n\t\t\t\t} //end case\n\t\t\t\tcase FT_INT:\n\t\t\t\t{\n\t\t\t\t\tif (fprintf(fp, \"%d\", *(int *) p) < 0) return qfalse;\n\t\t\t\t\tp = (char *) p + sizeof(int);\n\t\t\t\t\tbreak;\n\t\t\t\t} //end case\n\t\t\t\tcase FT_FLOAT:\n\t\t\t\t{\n\t\t\t\t\tif (!WriteFloat(fp, *(float *)p)) return qfalse;\n\t\t\t\t\tp = (char *) p + sizeof(float);\n\t\t\t\t\tbreak;\n\t\t\t\t} //end case\n\t\t\t\tcase FT_STRING:\n\t\t\t\t{\n\t\t\t\t\tif (fprintf(fp, \"\\\"%s\\\"\", (char *) p) < 0) return qfalse;\n\t\t\t\t\tp = (char *) p + MAX_STRINGFIELD;\n\t\t\t\t\tbreak;\n\t\t\t\t} //end case\n\t\t\t\tcase FT_STRUCT:\n\t\t\t\t{\n\t\t\t\t\tif (!WriteStructWithIndent(fp, fd->substruct, structure, indent)) return qfalse;\n\t\t\t\t\tp = (char *) p + fd->substruct->size;\n\t\t\t\t\tbreak;\n\t\t\t\t} //end case\n\t\t\t} //end switch\n\t\t\tif (fd->type & FT_ARRAY)\n\t\t\t{\n\t\t\t\tif (num > 0)\n\t\t\t\t{\n\t\t\t\t\tif (fprintf(fp, \",\") < 0) return qfalse;\n\t\t\t\t} //end if\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (fprintf(fp, \"}\") < 0) return qfalse;\n\t\t\t\t} //end else\n\t\t\t} //end if\n\t\t} //end while\n\t\tif (fprintf(fp, \"\\r\\n\") < 0) return qfalse;\n\t} //end for\n\tindent--;\n\n\tif (!WriteIndent(fp, indent)) return qfalse;\n\tif (fprintf(fp, \"}\\r\\n\") < 0) return qfalse;\n\treturn qtrue;\n} //end of the function WriteStructWithIndent\n//===========================================================================\n//\n// Parameter:\t\t\t\t-\n// Returns:\t\t\t\t\t-\n// Changes Globals:\t\t-\n//===========================================================================\nint WriteStructure(FILE *fp, structdef_t *def, char *structure)\n{\n\treturn WriteStructWithIndent(fp, def, structure, 0);\n} //end of the function WriteStructure\n\n"
  },
  {
    "path": "src/engine/botlib/l_struct.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tl_struct.h\n *\n * desc:\t\tstructure reading/writing\n *\n * $Archive: /source/code/botlib/l_struct.h $\n *\n *****************************************************************************/\n\n\n#define MAX_STRINGFIELD\t\t\t\t80\n//field types\n#define FT_CHAR\t\t\t\t\t\t1\t\t\t// char\n#define FT_INT\t\t\t\t\t\t\t2\t\t\t// int\n#define FT_FLOAT\t\t\t\t\t\t3\t\t\t// float\n#define FT_STRING\t\t\t\t\t\t4\t\t\t// char [MAX_STRINGFIELD]\n#define FT_STRUCT\t\t\t\t\t\t6\t\t\t// struct (sub structure)\n//type only mask\n#define FT_TYPE\t\t\t\t\t\t0x00FF\t// only type, clear subtype\n//sub types\n#define FT_ARRAY\t\t\t\t\t\t0x0100\t// array of type\n#define FT_BOUNDED\t\t\t\t\t0x0200\t// bounded value\n#define FT_UNSIGNED\t\t\t\t\t0x0400\n\n//structure field definition\ntypedef struct fielddef_s\n{\n\tchar *name;\t\t\t\t\t\t\t\t\t\t//name of the field\n\tint offset;\t\t\t\t\t\t\t\t\t\t//offset in the structure\n\tint type;\t\t\t\t\t\t\t\t\t\t//type of the field\n\t//type specific fields\n\tint maxarray;\t\t\t\t\t\t\t\t\t//maximum array size\n\tfloat floatmin, floatmax;\t\t\t\t\t//float min and max\n\tstruct structdef_s *substruct;\t\t\t//sub structure\n} fielddef_t;\n\n//structure definition\ntypedef struct structdef_s\n{\n\tint size;\n\tfielddef_t *fields;\n} structdef_t;\n\n//read a structure from a script\nint ReadStructure(source_t *source, structdef_t *def, char *structure);\n//write a structure to a file\nint WriteStructure(FILE *fp, structdef_t *def, char *structure);\n//writes indents\nint WriteIndent(FILE *fp, int indent);\n//writes a float without traling zeros\nint WriteFloat(FILE *fp, float value);\n\n\n"
  },
  {
    "path": "src/engine/botlib/l_utils.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tl_util.h\n *\n * desc:\t\tutils\n *\n * $Archive: /source/code/botlib/l_util.h $\n *\n *****************************************************************************/\n\n#define Vector2Angles(v,a)\t\tvectoangles(v,a)\n#define MAX_PATH\t\t\t\tMAX_QPATH\n#define Maximum(x,y)\t\t\t(x > y ? x : y)\n#define Minimum(x,y)\t\t\t(x < y ? x : y)\n"
  },
  {
    "path": "src/engine/client/cl_cgame.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n// cl_cgame.c  -- client system interaction with client game\n\n#include \"client.h\"\n\n#include \"../../game/botlib.h\"\n\nextern\tbotlib_export_t\t*botlib_export;\n\nextern qboolean loadCamera(const char *name);\nextern void startCamera(int time);\nextern qboolean getCameraInfo(int time, vec3_t *origin, vec3_t *angles);\n\n/*\n====================\nCL_GetGameState\n====================\n*/\nvoid CL_GetGameState( gameState_t *gs ) {\n\t*gs = cl.gameState;\n}\n\n/*\n====================\nCL_GetGlconfig\n====================\n*/\nvoid CL_GetGlconfig( glconfig_t *glconfig ) {\n\t*glconfig = cls.glconfig;\n}\n\n\n/*\n====================\nCL_GetUserCmd\n====================\n*/\nqboolean CL_GetUserCmd( int cmdNumber, usercmd_t *ucmd ) {\n\t// cmds[cmdNumber] is the last properly generated command\n\n\t// can't return anything that we haven't created yet\n\tif ( cmdNumber > cl.cmdNumber ) {\n\t\tCom_Error( ERR_DROP, \"CL_GetUserCmd: %i >= %i\", cmdNumber, cl.cmdNumber );\n\t}\n\n\t// the usercmd has been overwritten in the wrapping\n\t// buffer because it is too far out of date\n\tif ( cmdNumber <= cl.cmdNumber - CMD_BACKUP ) {\n\t\treturn qfalse;\n\t}\n\n\t*ucmd = cl.cmds[ cmdNumber & CMD_MASK ];\n\n\treturn qtrue;\n}\n\nint CL_GetCurrentCmdNumber( void ) {\n\treturn cl.cmdNumber;\n}\n\n\n/*\n====================\nCL_GetParseEntityState\n====================\n*/\nqboolean\tCL_GetParseEntityState( int parseEntityNumber, entityState_t *state ) {\n\t// can't return anything that hasn't been parsed yet\n\tif ( parseEntityNumber >= cl.parseEntitiesNum ) {\n\t\tCom_Error( ERR_DROP, \"CL_GetParseEntityState: %i >= %i\",\n\t\t\tparseEntityNumber, cl.parseEntitiesNum );\n\t}\n\n\t// can't return anything that has been overwritten in the circular buffer\n\tif ( parseEntityNumber <= cl.parseEntitiesNum - MAX_PARSE_ENTITIES ) {\n\t\treturn qfalse;\n\t}\n\n\t*state = cl.parseEntities[ parseEntityNumber & ( MAX_PARSE_ENTITIES - 1 ) ];\n\treturn qtrue;\n}\n\n/*\n====================\nCL_GetCurrentSnapshotNumber\n====================\n*/\nvoid\tCL_GetCurrentSnapshotNumber( int *snapshotNumber, int *serverTime ) {\n\t*snapshotNumber = cl.snap.messageNum;\n\t*serverTime = cl.snap.serverTime;\n}\n\n/*\n====================\nCL_GetSnapshot\n====================\n*/\nqboolean\tCL_GetSnapshot( int snapshotNumber, snapshot_t *snapshot ) {\n\tclSnapshot_t\t*clSnap;\n\tint\t\t\t\ti, count;\n\n\tif ( snapshotNumber > cl.snap.messageNum ) {\n\t\tCom_Error( ERR_DROP, \"CL_GetSnapshot: snapshotNumber > cl.snapshot.messageNum\" );\n\t}\n\n\t// if the frame has fallen out of the circular buffer, we can't return it\n\tif ( cl.snap.messageNum - snapshotNumber >= PACKET_BACKUP ) {\n\t\treturn qfalse;\n\t}\n\n\t// if the frame is not valid, we can't return it\n\tclSnap = &cl.snapshots[snapshotNumber & PACKET_MASK];\n\tif ( !clSnap->valid ) {\n\t\treturn qfalse;\n\t}\n\n\t// if the entities in the frame have fallen out of their\n\t// circular buffer, we can't return it\n\tif ( cl.parseEntitiesNum - clSnap->parseEntitiesNum >= MAX_PARSE_ENTITIES ) {\n\t\treturn qfalse;\n\t}\n\n\t// write the snapshot\n\tsnapshot->snapFlags = clSnap->snapFlags;\n\tsnapshot->serverCommandSequence = clSnap->serverCommandNum;\n\tsnapshot->ping = clSnap->ping;\n\tsnapshot->serverTime = clSnap->serverTime;\n\tCom_Memcpy( snapshot->areamask, clSnap->areamask, sizeof( snapshot->areamask ) );\n\tsnapshot->ps = clSnap->ps;\n\tcount = clSnap->numEntities;\n\tif ( count > MAX_ENTITIES_IN_SNAPSHOT ) {\n\t\tCom_DPrintf( \"CL_GetSnapshot: truncated %i entities to %i\\n\", count, MAX_ENTITIES_IN_SNAPSHOT );\n\t\tcount = MAX_ENTITIES_IN_SNAPSHOT;\n\t}\n\tsnapshot->numEntities = count;\n\tfor ( i = 0 ; i < count ; i++ ) {\n\t\tsnapshot->entities[i] = \n\t\t\tcl.parseEntities[ ( clSnap->parseEntitiesNum + i ) & (MAX_PARSE_ENTITIES-1) ];\n\t}\n\n\t// FIXME: configstring changes and server commands!!!\n\n\treturn qtrue;\n}\n\n/*\n=====================\nCL_SetUserCmdValue\n=====================\n*/\nvoid CL_SetUserCmdValue( int userCmdValue, float sensitivityScale ) {\n\tcl.cgameUserCmdValue = userCmdValue;\n\tcl.cgameSensitivity = sensitivityScale;\n}\n\n/*\n=====================\nCL_AddCgameCommand\n=====================\n*/\nvoid CL_AddCgameCommand( const char *cmdName ) {\n\tCmd_AddCommand( cmdName, NULL );\n}\n\n/*\n=====================\nCL_CgameError\n=====================\n*/\nvoid CL_CgameError( const char *string ) {\n\tCom_Error( ERR_DROP, \"%s\", string );\n}\n\n\n/*\n=====================\nCL_ConfigstringModified\n=====================\n*/\nvoid CL_ConfigstringModified( void ) {\n\tchar\t\t*old, *s;\n\tint\t\t\ti, index;\n\tchar\t\t*dup;\n\tgameState_t\toldGs;\n\tint\t\t\tlen;\n\n\tindex = atoi( Cmd_Argv(1) );\n\tif ( index < 0 || index >= MAX_CONFIGSTRINGS ) {\n\t\tCom_Error( ERR_DROP, \"configstring > MAX_CONFIGSTRINGS\" );\n\t}\n\t// get everything after \"cs <num>\"\n\ts = Cmd_ArgsFrom(2);\n\n\told = cl.gameState.stringData + cl.gameState.stringOffsets[ index ];\n\tif ( !strcmp( old, s ) ) {\n\t\treturn;\t\t// unchanged\n\t}\n\n\t// build the new gameState_t\n\toldGs = cl.gameState;\n\n\tCom_Memset( &cl.gameState, 0, sizeof( cl.gameState ) );\n\n\t// leave the first 0 for uninitialized strings\n\tcl.gameState.dataCount = 1;\n\t\t\n\tfor ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) {\n\t\tif ( i == index ) {\n\t\t\tdup = s;\n\t\t} else {\n\t\t\tdup = oldGs.stringData + oldGs.stringOffsets[ i ];\n\t\t}\n\t\tif ( !dup[0] ) {\n\t\t\tcontinue;\t\t// leave with the default empty string\n\t\t}\n\n\t\tlen = (int)strlen( dup );\n\n\t\tif ( len + 1 + cl.gameState.dataCount > MAX_GAMESTATE_CHARS ) {\n\t\t\tCom_Error( ERR_DROP, \"MAX_GAMESTATE_CHARS exceeded\" );\n\t\t}\n\n\t\t// append it to the gameState string buffer\n\t\tcl.gameState.stringOffsets[ i ] = cl.gameState.dataCount;\n\t\tCom_Memcpy( cl.gameState.stringData + cl.gameState.dataCount, dup, len + 1 );\n\t\tcl.gameState.dataCount += len + 1;\n\t}\n\n\tif ( index == CS_SYSTEMINFO ) {\n\t\t// parse serverId and other cvars\n\t\tCL_SystemInfoChanged();\n\t}\n\n}\n\n\n/*\n===================\nCL_GetServerCommand\n\nSet up argc/argv for the given command\n===================\n*/\nqboolean CL_GetServerCommand( int serverCommandNumber ) {\n\tchar\t*s;\n\tchar\t*cmd;\n\tstatic char bigConfigString[BIG_INFO_STRING];\n\tint argc;\n\n\t// if we have irretrievably lost a reliable command, drop the connection\n\tif ( serverCommandNumber <= clc.serverCommandSequence - MAX_RELIABLE_COMMANDS ) {\n\t\t// when a demo record was started after the client got a whole bunch of\n\t\t// reliable commands then the client never got those first reliable commands\n\t\tif ( clc.demoplaying )\n\t\t\treturn qfalse;\n\t\tCom_Error( ERR_DROP, \"CL_GetServerCommand: a reliable command was cycled out\" );\n\t\treturn qfalse;\n\t}\n\n\tif ( serverCommandNumber > clc.serverCommandSequence ) {\n\t\tCom_Error( ERR_DROP, \"CL_GetServerCommand: requested a command not received\" );\n\t\treturn qfalse;\n\t}\n\n\ts = clc.serverCommands[ serverCommandNumber & ( MAX_RELIABLE_COMMANDS - 1 ) ];\n\tclc.lastExecutedServerCommand = serverCommandNumber;\n\n\tCom_DPrintf( \"serverCommand: %i : %s\\n\", serverCommandNumber, s );\n\nrescan:\n\tCmd_TokenizeString( s );\n\tcmd = Cmd_Argv(0);\n\targc = Cmd_Argc();\n\n\tif ( !strcmp( cmd, \"disconnect\" ) ) {\n\t\t// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=552\n\t\t// allow server to indicate why they were disconnected\n\t\tif ( argc >= 2 )\n\t\t\tCom_Error (ERR_SERVERDISCONNECT, va( \"Server Disconnected - %s\", Cmd_Argv( 1 ) ) );\n\t\telse\n\t\t\tCom_Error (ERR_SERVERDISCONNECT,\"Server disconnected\\n\");\n\t}\n\n\tif ( !strcmp( cmd, \"bcs0\" ) ) {\n\t\tCom_sprintf( bigConfigString, BIG_INFO_STRING, \"cs %s \\\"%s\", Cmd_Argv(1), Cmd_Argv(2) );\n\t\treturn qfalse;\n\t}\n\n\tif ( !strcmp( cmd, \"bcs1\" ) ) {\n\t\ts = Cmd_Argv(2);\n\t\tif( (int)strlen(bigConfigString) + (int)strlen(s) >= BIG_INFO_STRING ) {\n\t\t\tCom_Error( ERR_DROP, \"bcs exceeded BIG_INFO_STRING\" );\n\t\t}\n\t\tstrcat( bigConfigString, s );\n\t\treturn qfalse;\n\t}\n\n\tif ( !strcmp( cmd, \"bcs2\" ) ) {\n\t\ts = Cmd_Argv(2);\n\t\tif( (int)strlen(bigConfigString) + (int)strlen(s) + 1 >= BIG_INFO_STRING ) {\n\t\t\tCom_Error( ERR_DROP, \"bcs exceeded BIG_INFO_STRING\" );\n\t\t}\n\t\tstrcat( bigConfigString, s );\n\t\tstrcat( bigConfigString, \"\\\"\" );\n\t\ts = bigConfigString;\n\t\tgoto rescan;\n\t}\n\n\tif ( !strcmp( cmd, \"cs\" ) ) {\n\t\tCL_ConfigstringModified();\n\t\t// reparse the string, because CL_ConfigstringModified may have done another Cmd_TokenizeString()\n\t\tCmd_TokenizeString( s );\n\t\treturn qtrue;\n\t}\n\n\tif ( !strcmp( cmd, \"map_restart\" ) ) {\n\t\t// clear notify lines and outgoing commands before passing\n\t\t// the restart to the cgame\n\t\tCon_ClearNotify();\n\t\tCom_Memset( cl.cmds, 0, sizeof( cl.cmds ) );\n\t\treturn qtrue;\n\t}\n\n\t// the clientLevelShot command is used during development\n\t// to generate 128*128 screenshots from the intermission\n\t// point of levels for the menu system to use\n\t// we pass it along to the cgame to make apropriate adjustments,\n\t// but we also clear the console and notify lines here\n\tif ( !strcmp( cmd, \"clientLevelShot\" ) ) {\n\t\t// don't do it if we aren't running the server locally,\n\t\t// otherwise malicious remote servers could overwrite\n\t\t// the existing thumbnails\n\t\tif ( !com_sv_running->integer ) {\n\t\t\treturn qfalse;\n\t\t}\n\t\t// close the console\n\t\tCon_Close();\n\t\t// take a special screenshot next frame\n\t\tCbuf_AddText( \"wait ; wait ; wait ; wait ; screenshot levelshot\\n\" );\n\t\treturn qtrue;\n\t}\n\n\t// we may want to put a \"connect to other server\" command here\n\n\t// cgame can now act on the command\n\treturn qtrue;\n}\n\n\n/*\n====================\nCL_CM_LoadMap\n\nJust adds default parameters that cgame doesn't need to know about\n====================\n*/\nvoid CL_CM_LoadMap( const char *mapname ) {\n\tint\t\tchecksum;\n\n\tCM_LoadMap( mapname, qtrue, &checksum );\n}\n\n/*\n====================\nCL_ShutdonwCGame\n\n====================\n*/\nvoid CL_ShutdownCGame( void ) {\n\tcls.keyCatchers &= ~KEYCATCH_CGAME;\n\tcls.cgameStarted = qfalse;\n\tif ( !cgvm ) {\n\t\treturn;\n\t}\n\tVM_Call( cgvm, CG_SHUTDOWN );\n\tVM_Free( cgvm );\n\tcgvm = NULL;\n}\n\nstatic int\tFloatAsInt( float f ) {\n\tint\t\ttemp;\n\n\t*(float *)&temp = f;\n\n\treturn temp;\n}\n\n/*\n====================\nCL_CgameSystemCalls\n\nThe cgame module is making a system call\n====================\n*/\n#define\tVMA(x) VM_ArgPtr(args[x])\n#define\tVMF(x) (*(float*)&args[x])\n\nintptr_t CL_CgameSystemCalls( intptr_t *args ) {\n\tswitch( args[0] ) {\n\tcase CG_PRINT:\n\t\tCom_Printf( \"%s\", VMA(1) );\n\t\treturn 0;\n\tcase CG_ERROR:\n\t\tCom_Error( ERR_DROP, \"%s\", VMA(1) );\n\t\treturn 0;\n\tcase CG_MILLISECONDS:\n\t\treturn Sys_Milliseconds();\n\tcase CG_CVAR_REGISTER:\n\t\tCvar_Register( (vmCvar_t*) VMA(1), (const char*) VMA(2), (const char*) VMA(3), args[4] ); \n\t\treturn 0;\n\tcase CG_CVAR_UPDATE:\n\t\tCvar_Update( (vmCvar_t*) VMA(1) );\n\t\treturn 0;\n\tcase CG_CVAR_SET:\n\t\tCvar_Set( (const char*) VMA(1), (const char*) VMA(2) );\n\t\treturn 0;\n\tcase CG_CVAR_VARIABLESTRINGBUFFER:\n\t\tCvar_VariableStringBuffer( (const char*) VMA(1), (char*) VMA(2), args[3] );\n\t\treturn 0;\n\tcase CG_ARGC:\n\t\treturn Cmd_Argc();\n\tcase CG_ARGV:\n\t\tCmd_ArgvBuffer( args[1], (char*) VMA(2), args[3] );\n\t\treturn 0;\n\tcase CG_ARGS:\n\t\tCmd_ArgsBuffer( (char*) VMA(1), args[2] );\n\t\treturn 0;\n\tcase CG_FS_FOPENFILE:\n\t\treturn FS_FOpenFileByMode( (const char*) VMA(1), (fileHandle_t*) VMA(2), (fsMode_t) args[3] );\n\tcase CG_FS_READ:\n\t\tFS_Read2( VMA(1), args[2], args[3] );\n\t\treturn 0;\n\tcase CG_FS_WRITE:\n\t\tFS_Write( VMA(1), args[2], args[3] );\n\t\treturn 0;\n\tcase CG_FS_FCLOSEFILE:\n\t\tFS_FCloseFile( args[1] );\n\t\treturn 0;\n\tcase CG_FS_SEEK:\n\t\treturn FS_Seek( args[1], args[2], args[3] );\n\tcase CG_SENDCONSOLECOMMAND:\n\t\tCbuf_AddText( (const char*) VMA(1) );\n\t\treturn 0;\n\tcase CG_ADDCOMMAND:\n\t\tCL_AddCgameCommand( (const char*) VMA(1) );\n\t\treturn 0;\n\tcase CG_REMOVECOMMAND:\n\t\tCmd_RemoveCommand( (const char*) VMA(1) );\n\t\treturn 0;\n\tcase CG_SENDCLIENTCOMMAND:\n\t\tCL_AddReliableCommand( (const char*) VMA(1) );\n\t\treturn 0;\n\tcase CG_UPDATESCREEN:\n\t\t// this is used during lengthy level loading, so pump message loop\n//\t\tCom_EventLoop();\t// FIXME: if a server restarts here, BAD THINGS HAPPEN!\n// We can't call Com_EventLoop here, a restart will crash and this _does_ happen\n// if there is a map change while we are downloading at pk3.\n// ZOID\n\t\tSCR_UpdateScreen();\n\t\treturn 0;\n\tcase CG_CM_LOADMAP:\n\t\tCL_CM_LoadMap( (const char*) VMA(1) );\n\t\treturn 0;\n\tcase CG_CM_NUMINLINEMODELS:\n\t\treturn CM_NumInlineModels();\n\tcase CG_CM_INLINEMODEL:\n\t\treturn CM_InlineModel( args[1] );\n\tcase CG_CM_TEMPBOXMODEL:\n\t\treturn CM_TempBoxModel((const vec_t*)VMA(1), (const vec_t*) VMA(2), /*int capsule*/ qfalse);\n\tcase CG_CM_TEMPCAPSULEMODEL:\n\t\treturn CM_TempBoxModel((const vec_t*)VMA(1), (const vec_t*) VMA(2), /*int capsule*/ qtrue);\n\tcase CG_CM_POINTCONTENTS:\n\t\treturn CM_PointContents((const vec_t*) VMA(1), args[2]);\n\tcase CG_CM_TRANSFORMEDPOINTCONTENTS:\n\t\treturn CM_TransformedPointContents((const vec_t*)VMA(1), args[2], (const vec_t*)VMA(3), (const vec_t*) VMA(4));\n\tcase CG_CM_BOXTRACE:\n\t\tCM_BoxTrace((trace_t*)VMA(1), (const vec_t*)VMA(2), (const vec_t*) VMA(3), (vec_t*) VMA(4), (vec_t*) VMA(5), args[6], args[7], /*int capsule*/ qfalse);\n\t\treturn 0;\n\tcase CG_CM_CAPSULETRACE:\n\t\tCM_BoxTrace((trace_t*)VMA(1), (const vec_t*)VMA(2), (const vec_t*) VMA(3), (vec_t*) VMA(4), (vec_t*) VMA(5), args[6], args[7], /*int capsule*/ qtrue);\n\t\treturn 0;\n\tcase CG_CM_TRANSFORMEDBOXTRACE:\n\t\tCM_TransformedBoxTrace((trace_t*)VMA(1), (const vec_t*)VMA(2), (const vec_t*)VMA(3), (vec_t*)VMA(4), (vec_t*)VMA(5), args[6], args[7], (const vec_t*)VMA(8), (const vec_t*) VMA(9), /*int capsule*/ qfalse);\n\t\treturn 0;\n\tcase CG_CM_TRANSFORMEDCAPSULETRACE:\n\t\tCM_TransformedBoxTrace((trace_t*)VMA(1), (const vec_t*)VMA(2), (const vec_t*)VMA(3), (vec_t*)VMA(4), (vec_t*)VMA(5), args[6], args[7], (const vec_t*)VMA(8), (const vec_t*) VMA(9), /*int capsule*/ qtrue);\n\t\treturn 0;\n\tcase CG_CM_MARKFRAGMENTS:\n\t\treturn re.MarkFragments(args[1], (const vec3_t*)VMA(2), (const vec_t*) VMA(3), args[4], (vec_t*) VMA(5), args[6], (markFragment_t*) VMA(7));\n\tcase CG_S_STARTSOUND:\n\t\tS_StartSound( (vec_t*) VMA(1), args[2], args[3], args[4] );\n\t\treturn 0;\n\tcase CG_S_STARTLOCALSOUND:\n\t\tS_StartLocalSound( args[1], args[2] );\n\t\treturn 0;\n\tcase CG_S_CLEARLOOPINGSOUNDS:\n\t\tS_ClearLoopingSounds((qboolean) args[1]);\n\t\treturn 0;\n\tcase CG_S_ADDLOOPINGSOUND:\n\t\tS_AddLoopingSound(args[1], (const vec_t*)VMA(2), (const vec_t*) VMA(3), args[4]);\n\t\treturn 0;\n\tcase CG_S_ADDREALLOOPINGSOUND:\n\t\tS_AddRealLoopingSound(args[1], (const vec_t*)VMA(2), (const vec_t*) VMA(3), args[4]);\n\t\treturn 0;\n\tcase CG_S_STOPLOOPINGSOUND:\n\t\tS_StopLoopingSound( args[1] );\n\t\treturn 0;\n\tcase CG_S_UPDATEENTITYPOSITION:\n\t\tS_UpdateEntityPosition(args[1], (const vec_t*) VMA(2));\n\t\treturn 0;\n\tcase CG_S_RESPATIALIZE:\n\t\tS_Respatialize(args[1], (const vec_t*) VMA(2), (vec3_t*) VMA(3), args[4]);\n\t\treturn 0;\n\tcase CG_S_REGISTERSOUND:\n\t\treturn S_RegisterSound( (const char*) VMA(1), (qboolean) args[2] );\n\tcase CG_S_STARTBACKGROUNDTRACK:\n\t\tS_StartBackgroundTrack( (const char*) VMA(1), (const char*) VMA(2) );\n\t\treturn 0;\n\tcase CG_R_LOADWORLDMAP:\n\t\tre.LoadWorld( (const char*) VMA(1) );\n\t\treturn 0; \n\tcase CG_R_REGISTERMODEL:\n\t\treturn re.RegisterModel( (const char*) VMA(1) );\n\tcase CG_R_REGISTERSKIN:\n\t\treturn re.RegisterSkin( (const char*) VMA(1) );\n\tcase CG_R_REGISTERSHADER:\n\t\treturn re.RegisterShader( (const char*) VMA(1) );\n\tcase CG_R_REGISTERSHADERNOMIP:\n\t\treturn re.RegisterShaderNoMip( (const char*) VMA(1) );\n\tcase CG_R_REGISTERFONT:\n\t\tre.RegisterFont( (const char*) VMA(1), args[2], (fontInfo_t*) VMA(3));\n\tcase CG_R_CLEARSCENE:\n\t\tre.ClearScene();\n\t\treturn 0;\n\tcase CG_R_ADDREFENTITYTOSCENE:\n\t\tre.AddRefEntityToScene( (const refEntity_t*) VMA(1) );\n\t\treturn 0;\n\tcase CG_R_ADDPOLYTOSCENE:\n\t\tre.AddPolyToScene( args[1], args[2], (const polyVert_t*) VMA(3), 1 );\n\t\treturn 0;\n\tcase CG_R_ADDPOLYSTOSCENE:\n\t\tre.AddPolyToScene( args[1], args[2], (const polyVert_t*) VMA(3), args[4] );\n\t\treturn 0;\n\tcase CG_R_LIGHTFORPOINT:\n\t\treturn re.LightForPoint( (vec_t*) VMA(1), (vec_t*) VMA(2), (vec_t*) VMA(3), (vec_t*) VMA(4) );\n\tcase CG_R_ADDLIGHTTOSCENE:\n\t\tre.AddLightToScene((const vec_t*) VMA(1), VMF(2), VMF(3), VMF(4), VMF(5));\n\t\treturn 0;\n\tcase CG_R_ADDADDITIVELIGHTTOSCENE:\n\t\tre.AddAdditiveLightToScene((const vec_t*) VMA(1), VMF(2), VMF(3), VMF(4), VMF(5));\n\t\treturn 0;\n\tcase CG_R_RENDERSCENE:\n\t\tre.RenderScene( (const refdef_t*) VMA(1) );\n\t\treturn 0;\n\tcase CG_R_SETCOLOR:\n\t\tre.SetColor( (const float*) VMA(1) );\n\t\treturn 0;\n\tcase CG_R_DRAWSTRETCHPIC:\n\t\tre.DrawStretchPic( VMF(1), VMF(2), VMF(3), VMF(4), VMF(5), VMF(6), VMF(7), VMF(8), args[9] );\n\t\treturn 0;\n\tcase CG_R_MODELBOUNDS:\n\t\tre.ModelBounds( args[1], (vec_t*) VMA(2), (vec_t*) VMA(3) );\n\t\treturn 0;\n\tcase CG_R_LERPTAG:\n\t\treturn re.LerpTag( (orientation_t*) VMA(1), args[2], args[3], args[4], VMF(5), (const char*) VMA(6) );\n\tcase CG_GETGLCONFIG:\n\t\tCL_GetGlconfig( (glconfig_t*) VMA(1) );\n\t\treturn 0;\n\tcase CG_GETGAMESTATE:\n\t\tCL_GetGameState( (gameState_t*) VMA(1) );\n\t\treturn 0;\n\tcase CG_GETCURRENTSNAPSHOTNUMBER:\n\t\tCL_GetCurrentSnapshotNumber( (int*) VMA(1), (int*) VMA(2) );\n\t\treturn 0;\n\tcase CG_GETSNAPSHOT:\n\t\treturn CL_GetSnapshot( args[1], (snapshot_t*) VMA(2) );\n\tcase CG_GETSERVERCOMMAND:\n\t\treturn CL_GetServerCommand( args[1] );\n\tcase CG_GETCURRENTCMDNUMBER:\n\t\treturn CL_GetCurrentCmdNumber();\n\tcase CG_GETUSERCMD:\n\t\treturn CL_GetUserCmd( args[1], (usercmd_t*) VMA(2) );\n\tcase CG_SETUSERCMDVALUE:\n\t\tCL_SetUserCmdValue( args[1], VMF(2) );\n\t\treturn 0;\n\tcase CG_MEMORY_REMAINING:\n\t\treturn Hunk_MemoryRemaining();\n  case CG_KEY_ISDOWN:\n\t\treturn Key_IsDown( args[1] );\n  case CG_KEY_GETCATCHER:\n\t\treturn Key_GetCatcher();\n  case CG_KEY_SETCATCHER:\n\t\tKey_SetCatcher( args[1] );\n    return 0;\n  case CG_KEY_GETKEY:\n\t\treturn Key_GetKey( (const char*) VMA(1) );\n\n\n\n\tcase CG_MEMSET:\n\t\tCom_Memset( VMA(1), args[2], args[3] );\n\t\treturn 0;\n\tcase CG_MEMCPY:\n\t\tCom_Memcpy( VMA(1), VMA(2), args[3] );\n\t\treturn 0;\n\tcase CG_STRNCPY:\n        strncpy( (char*)VMA(1), (const char*)VMA(2), args[3] );\n        return args[1];\n\tcase CG_SIN:\n\t\treturn FloatAsInt( sin( VMF(1) ) );\n\tcase CG_COS:\n\t\treturn FloatAsInt( cos( VMF(1) ) );\n\tcase CG_ATAN2:\n\t\treturn FloatAsInt( atan2( VMF(1), VMF(2) ) );\n\tcase CG_SQRT:\n\t\treturn FloatAsInt( sqrt( VMF(1) ) );\n\tcase CG_FLOOR:\n\t\treturn FloatAsInt( floor( VMF(1) ) );\n\tcase CG_CEIL:\n\t\treturn FloatAsInt( ceil( VMF(1) ) );\n\tcase CG_ACOS:\n\t\treturn FloatAsInt( Q_acos( VMF(1) ) );\n\n\tcase CG_PC_ADD_GLOBAL_DEFINE:\n\t\treturn botlib_export->PC_AddGlobalDefine( (char*) VMA(1) );\n\tcase CG_PC_LOAD_SOURCE:\n\t\treturn botlib_export->PC_LoadSourceHandle( (const char*) VMA(1) );\n\tcase CG_PC_FREE_SOURCE:\n\t\treturn botlib_export->PC_FreeSourceHandle( args[1] );\n\tcase CG_PC_READ_TOKEN:\n\t\treturn botlib_export->PC_ReadTokenHandle( args[1], (pc_token_t*) VMA(2) );\n\tcase CG_PC_SOURCE_FILE_AND_LINE:\n\t\treturn botlib_export->PC_SourceFileAndLine( args[1], (char*) VMA(2), (int*) VMA(3) );\n\n\tcase CG_S_STOPBACKGROUNDTRACK:\n\t\tS_StopBackgroundTrack();\n\t\treturn 0;\n\n\tcase CG_REAL_TIME:\n\t\treturn Com_RealTime( (qtime_t*) VMA(1) );\n\tcase CG_SNAPVECTOR:\n\t\tSys_SnapVector( (float*) VMA(1) );\n\t\treturn 0;\n\n\tcase CG_CIN_PLAYCINEMATIC:\n\t  return CIN_PlayCinematic((const char*) VMA(1), args[2], args[3], args[4], args[5], args[6]);\n\n\tcase CG_CIN_STOPCINEMATIC:\n\t  return CIN_StopCinematic(args[1]);\n\n\tcase CG_CIN_RUNCINEMATIC:\n\t  return CIN_RunCinematic(args[1]);\n\n\tcase CG_CIN_DRAWCINEMATIC:\n\t  CIN_DrawCinematic(args[1]);\n\t  return 0;\n\n\tcase CG_CIN_SETEXTENTS:\n\t  CIN_SetExtents(args[1], args[2], args[3], args[4], args[5]);\n\t  return 0;\n\n\tcase CG_R_REMAP_SHADER:\n\t\tre.RemapShader( (const char*) VMA(1), (const char*) VMA(2), (const char*) VMA(3) );\n\t\treturn 0;\n\n/*\n\tcase CG_LOADCAMERA:\n\t\treturn loadCamera(VMA(1));\n\n\tcase CG_STARTCAMERA:\n\t\tstartCamera(args[1]);\n\t\treturn 0;\n\n\tcase CG_GETCAMERAINFO:\n\t\treturn getCameraInfo(args[1], VMA(2), VMA(3));\n*/\n\tcase CG_GET_ENTITY_TOKEN:\n\t\treturn re.GetEntityToken( (char*) VMA(1), args[2] );\n\tcase CG_R_INPVS:\n\t\treturn re.inPVS((const vec_t*)VMA(1), (const vec_t*) VMA(2));\n\n\tdefault:\n\t        assert(0); // bk010102\n\t\tCom_Error( ERR_DROP, \"Bad cgame system trap: %i\", args[0] );\n\t}\n\treturn 0;\n}\n\n\n/*\n====================\nCL_InitCGame\n\nShould only be called by CL_StartHunkUsers\n====================\n*/\nvoid CL_InitCGame( void ) {\n\tconst char\t\t\t*info;\n\tconst char\t\t\t*mapname;\n\tint\t\t\t\t\tt1, t2;\n\tvmInterpret_t\t\tinterpret;\n\n\tt1 = Sys_Milliseconds();\n\n\t// put away the console\n\tCon_Close();\n\n\t// find the current mapname\n\tinfo = cl.gameState.stringData + cl.gameState.stringOffsets[ CS_SERVERINFO ];\n\tmapname = Info_ValueForKey( info, \"mapname\" );\n\tCom_sprintf( cl.mapname, sizeof( cl.mapname ), \"maps/%s.bsp\", mapname );\n\n\t// load the dll or bytecode\n\tif ( cl_connectedToPureServer != 0 ) {\n\t\t// if sv_pure is set we only allow qvms to be loaded\n\t\tinterpret = VMI_BYTECODE;\n\t}\n\telse {\n\t\tinterpret = (vmInterpret_t) (int) Cvar_VariableValue( \"vm_cgame\" );\n\t}\n\tcgvm = VM_Create( \"cgame\", CL_CgameSystemCalls, interpret );\n\tif ( !cgvm ) {\n\t\tCom_Error( ERR_DROP, \"VM_Create on cgame failed\" );\n\t}\n\tcls.state = CA_LOADING;\n\n\t// init for this gamestate\n\t// use the lastExecutedServerCommand instead of the serverCommandSequence\n\t// otherwise server commands sent just before a gamestate are dropped\n\tVM_Call( cgvm, CG_INIT, clc.serverMessageSequence, clc.lastExecutedServerCommand, clc.clientNum );\n\n\t// we will send a usercmd this frame, which\n\t// will cause the server to send us the first snapshot\n\tcls.state = CA_PRIMED;\n\n\tt2 = Sys_Milliseconds();\n\n\tCom_Printf( \"CL_InitCGame: %5.2f seconds\\n\", (t2-t1)/1000.0 );\n\n\t// have the renderer touch all its images, so they are present\n\t// on the card even if the driver does deferred loading\n\tre.EndRegistration();\n\n\t// make sure everything is paged in\n\tif (!Sys_LowPhysicalMemory()) {\n\t\tCom_TouchMemory();\n\t}\n\n\t// clear anything that got printed\n\tCon_ClearNotify ();\n}\n\n\n/*\n====================\nCL_GameCommand\n\nSee if the current console command is claimed by the cgame\n====================\n*/\nqboolean CL_GameCommand( void ) {\n\tif ( !cgvm ) {\n\t\treturn qfalse;\n\t}\n\n\treturn (qboolean) VM_Call( cgvm, CG_CONSOLE_COMMAND );\n}\n\n\n\n/*\n=====================\nCL_CGameRendering\n=====================\n*/\nvoid CL_CGameRendering( stereoFrame_t stereo ) {\n\tVM_Call( cgvm, CG_DRAW_ACTIVE_FRAME, cl.serverTime, stereo, clc.demoplaying );\n\tVM_Debug( 0 );\n}\n\n\n/*\n=================\nCL_AdjustTimeDelta\n\nAdjust the clients view of server time.\n\nWe attempt to have cl.serverTime exactly equal the server's view\nof time plus the timeNudge, but with variable latencies over\nthe internet it will often need to drift a bit to match conditions.\n\nOur ideal time would be to have the adjusted time approach, but not pass,\nthe very latest snapshot.\n\nAdjustments are only made when a new snapshot arrives with a rational\nlatency, which keeps the adjustment process framerate independent and\nprevents massive overadjustment during times of significant packet loss\nor bursted delayed packets.\n=================\n*/\n\n#define\tRESET_TIME\t500\n\nvoid CL_AdjustTimeDelta( void ) {\n\tint\t\tresetTime;\n\tint\t\tnewDelta;\n\tint\t\tdeltaDelta;\n\n\tcl.newSnapshots = qfalse;\n\n\t// the delta never drifts when replaying a demo\n\tif ( clc.demoplaying ) {\n\t\treturn;\n\t}\n\n\t// if the current time is WAY off, just correct to the current value\n\tif ( com_sv_running->integer ) {\n\t\tresetTime = 100;\n\t} else {\n\t\tresetTime = RESET_TIME;\n\t}\n\n\tnewDelta = cl.snap.serverTime - cls.realtime;\n\tdeltaDelta = abs( newDelta - cl.serverTimeDelta );\n\n\tif ( deltaDelta > RESET_TIME ) {\n\t\tcl.serverTimeDelta = newDelta;\n\t\tcl.oldServerTime = cl.snap.serverTime;\t// FIXME: is this a problem for cgame?\n\t\tcl.serverTime = cl.snap.serverTime;\n\t\tif ( cl_showTimeDelta->integer ) {\n\t\t\tCom_Printf( \"<RESET> \" );\n\t\t}\n\t} else if ( deltaDelta > 100 ) {\n\t\t// fast adjust, cut the difference in half\n\t\tif ( cl_showTimeDelta->integer ) {\n\t\t\tCom_Printf( \"<FAST> \" );\n\t\t}\n\t\tcl.serverTimeDelta = ( cl.serverTimeDelta + newDelta ) >> 1;\n\t} else {\n\t\t// slow drift adjust, only move 1 or 2 msec\n\n\t\t// if any of the frames between this and the previous snapshot\n\t\t// had to be extrapolated, nudge our sense of time back a little\n\t\t// the granularity of +1 / -2 is too high for timescale modified frametimes\n\t\tif ( com_timescale->value == 0 || com_timescale->value == 1 ) {\n\t\t\tif ( cl.extrapolatedSnapshot ) {\n\t\t\t\tcl.extrapolatedSnapshot = qfalse;\n\t\t\t\tcl.serverTimeDelta -= 2;\n\t\t\t} else {\n\t\t\t\t// otherwise, move our sense of time forward to minimize total latency\n\t\t\t\tcl.serverTimeDelta++;\n\t\t\t}\n\t\t}\n\t}\n\n\tif ( cl_showTimeDelta->integer ) {\n\t\tCom_Printf( \"%i \", cl.serverTimeDelta );\n\t}\n}\n\n\n/*\n==================\nCL_FirstSnapshot\n==================\n*/\nvoid CL_FirstSnapshot( void ) {\n\t// ignore snapshots that don't have entities\n\tif ( cl.snap.snapFlags & SNAPFLAG_NOT_ACTIVE ) {\n\t\treturn;\n\t}\n\tcls.state = CA_ACTIVE;\n\n\t// set the timedelta so we are exactly on this first frame\n\tcl.serverTimeDelta = cl.snap.serverTime - cls.realtime;\n\tcl.oldServerTime = cl.snap.serverTime;\n\n\tclc.timeDemoBaseTime = cl.snap.serverTime;\n\n\t// if this is the first frame of active play,\n\t// execute the contents of activeAction now\n\t// this is to allow scripting a timedemo to start right\n\t// after loading\n\tif ( cl_activeAction->string[0] ) {\n\t\tCbuf_AddText( cl_activeAction->string );\n\t\tCvar_Set( \"activeAction\", \"\" );\n\t}\n\t\n\tSys_BeginProfiling();\n}\n\n/*\n==================\nCL_SetCGameTime\n==================\n*/\nvoid CL_SetCGameTime( void ) {\n\t// getting a valid frame message ends the connection process\n\tif ( cls.state != CA_ACTIVE ) {\n\t\tif ( cls.state != CA_PRIMED ) {\n\t\t\treturn;\n\t\t}\n\t\tif ( clc.demoplaying ) {\n\t\t\t// we shouldn't get the first snapshot on the same frame\n\t\t\t// as the gamestate, because it causes a bad time skip\n\t\t\tif ( !clc.firstDemoFrameSkipped ) {\n\t\t\t\tclc.firstDemoFrameSkipped = qtrue;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tCL_ReadDemoMessage();\n\t\t}\n\t\tif ( cl.newSnapshots ) {\n\t\t\tcl.newSnapshots = qfalse;\n\t\t\tCL_FirstSnapshot();\n\t\t}\n\t\tif ( cls.state != CA_ACTIVE ) {\n\t\t\treturn;\n\t\t}\n\t}\t\n\n\t// if we have gotten to this point, cl.snap is guaranteed to be valid\n\tif ( !cl.snap.valid ) {\n\t\tCom_Error( ERR_DROP, \"CL_SetCGameTime: !cl.snap.valid\" );\n\t}\n\n\t// allow pause in single player\n\tif ( sv_paused->integer && cl_paused->integer && com_sv_running->integer ) {\n\t\t// paused\n\t\treturn;\n\t}\n\n\tif ( cl.snap.serverTime < cl.oldFrameServerTime ) {\n\t\tCom_Error( ERR_DROP, \"cl.snap.serverTime < cl.oldFrameServerTime\" );\n\t}\n\tcl.oldFrameServerTime = cl.snap.serverTime;\n\n\n\t// get our current view of time\n\n\tif ( clc.demoplaying && cl_freezeDemo->integer ) {\n\t\t// cl_freezeDemo is used to lock a demo in place for single frame advances\n\n\t} else {\n\t\t// cl_timeNudge is a user adjustable cvar that allows more\n\t\t// or less latency to be added in the interest of better \n\t\t// smoothness or better responsiveness.\n\t\tint tn;\n\t\t\n\t\ttn = cl_timeNudge->integer;\n\t\tif (tn<-30) {\n\t\t\ttn = -30;\n\t\t} else if (tn>30) {\n\t\t\ttn = 30;\n\t\t}\n\n\t\tcl.serverTime = cls.realtime + cl.serverTimeDelta - tn;\n\n\t\t// guarantee that time will never flow backwards, even if\n\t\t// serverTimeDelta made an adjustment or cl_timeNudge was changed\n\t\tif ( cl.serverTime < cl.oldServerTime ) {\n\t\t\tcl.serverTime = cl.oldServerTime;\n\t\t}\n\t\tcl.oldServerTime = cl.serverTime;\n\n\t\t// note if we are almost past the latest frame (without timeNudge),\n\t\t// so we will try and adjust back a bit when the next snapshot arrives\n\t\tif ( cls.realtime + cl.serverTimeDelta >= cl.snap.serverTime - 5 ) {\n\t\t\tcl.extrapolatedSnapshot = qtrue;\n\t\t}\n\t}\n\n\t// if we have gotten new snapshots, drift serverTimeDelta\n\t// don't do this every frame, or a period of packet loss would\n\t// make a huge adjustment\n\tif ( cl.newSnapshots ) {\n\t\tCL_AdjustTimeDelta();\n\t}\n\n\tif ( !clc.demoplaying ) {\n\t\treturn;\n\t}\n\n\t// if we are playing a demo back, we can just keep reading\n\t// messages from the demo file until the cgame definately\n\t// has valid snapshots to interpolate between\n\n\t// a timedemo will always use a deterministic set of time samples\n\t// no matter what speed machine it is run on,\n\t// while a normal demo may have different time samples\n\t// each time it is played back\n\tif ( cl_timedemo->integer ) {\n\t\tif (!clc.timeDemoStart) {\n\t\t\tclc.timeDemoStart = Sys_Milliseconds();\n\t\t}\n\t\tclc.timeDemoFrames++;\n\t\tcl.serverTime = clc.timeDemoBaseTime + clc.timeDemoFrames * 50;\n\t}\n\n\twhile ( cl.serverTime >= cl.snap.serverTime ) {\n\t\t// feed another messag, which should change\n\t\t// the contents of cl.snap\n\t\tCL_ReadDemoMessage();\n\t\tif ( cls.state != CA_ACTIVE ) {\n\t\t\treturn;\t\t// end of demo\n\t\t}\n\t}\n\n}\n\n\n\n"
  },
  {
    "path": "src/engine/client/cl_cin.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tcl_cin.c\n *\n * desc:\t\tvideo and cinematic playback\n *\n * $Archive: /MissionPack/code/client/cl_cin.c $\n *\n * cl_glconfig.hwtype trtypes 3dfx/ragepro need 256x256\n *\n *****************************************************************************/\n\n#include \"client.h\"\n#include \"snd_local.h\"\n\n#define MAXSIZE\t\t\t\t8\n#define MINSIZE\t\t\t\t4\n\n#define DEFAULT_CIN_WIDTH\t512\n#define DEFAULT_CIN_HEIGHT\t512\n\n#define ROQ_QUAD\t\t\t0x1000\n#define ROQ_QUAD_INFO\t\t0x1001\n#define ROQ_CODEBOOK\t\t0x1002\n#define ROQ_QUAD_VQ\t\t\t0x1011\n#define ROQ_QUAD_JPEG\t\t0x1012\n#define ROQ_QUAD_HANG\t\t0x1013\n#define ROQ_PACKET\t\t\t0x1030\n#define ZA_SOUND_MONO\t\t0x1020\n#define ZA_SOUND_STEREO\t\t0x1021\n\n#define MAX_VIDEO_HANDLES\t16\n\nextern\tint\t\ts_paintedtime;\nextern\tint\t\ts_rawend;\n\n\nstatic void RoQ_init( void );\n\n/******************************************************************************\n*\n* Class:\t\ttrFMV\n*\n* Description:\tRoQ/RnR manipulation routines\n*\t\t\t\tnot entirely complete for first run\n*\n******************************************************************************/\n\nstatic\tlong\t\t\t\tROQ_YY_tab[256];\nstatic\tlong\t\t\t\tROQ_UB_tab[256];\nstatic\tlong\t\t\t\tROQ_UG_tab[256];\nstatic\tlong\t\t\t\tROQ_VG_tab[256];\nstatic\tlong\t\t\t\tROQ_VR_tab[256];\nstatic\tunsigned short\t\tvq2[256*16*4];\nstatic\tunsigned short\t\tvq4[256*64*4];\nstatic\tunsigned short\t\tvq8[256*256*4];\n\n\ntypedef struct {\n\tbyte\t\t\t\tlinbuf[DEFAULT_CIN_WIDTH*DEFAULT_CIN_HEIGHT*4*2];\n\tbyte\t\t\t\tfile[65536];\n\tshort\t\t\t\tsqrTable[256];\n\n\tint\t\t            mcomp[256];\n\tbyte\t\t\t\t*qStatus[2][32768];\n\n\tlong\t\t\t\toldXOff, oldYOff, oldysize, oldxsize;\n\n\tint\t\t\t\t\tcurrentHandle;\n} cinematics_t;\n\ntypedef struct {\n\tchar\t\t\t\tfileName[MAX_OSPATH];\n\tint\t\t\t\t\tCIN_WIDTH, CIN_HEIGHT;\n\tint\t\t\t\t\txpos, ypos, width, height;\n\tqboolean\t\t\tlooping, holdAtEnd, dirty, alterGameState, silent, shader;\n\tfileHandle_t\t\tiFile;\n\te_status\t\t\tstatus;\n\tunsigned int\t\tstartTime;\n\tunsigned int\t\tlastTime;\n\tlong\t\t\t\ttfps;\n\tlong\t\t\t\tRoQPlayed;\n\tlong\t\t\t\tROQSize;\n\tunsigned int\t\tRoQFrameSize;\n\tlong\t\t\t\tonQuad;\n\tlong\t\t\t\tnumQuads;\n\tlong\t\t\t\tsamplesPerLine;\n\tunsigned int\t\troq_id;\n\tlong\t\t\t\tscreenDelta;\n\n\tvoid ( *VQ0)(byte *status, void *qdata );\n\tvoid ( *VQ1)(byte *status, void *qdata );\n\tvoid ( *VQNormal)(byte *status, void *qdata );\n\tvoid ( *VQBuffer)(byte *status, void *qdata );\n\n\tlong\t\t\t\tsamplesPerPixel;\t\t\t\t// defaults to 2\n\tbyte*\t\t\t\tgray;\n\tunsigned int\t\txsize, ysize, maxsize, minsize;\n\n\tqboolean\t\t\thalf, smootheddouble, inMemory;\n\tlong\t\t\t\tnormalBuffer0;\n\tlong\t\t\t\troq_flags;\n\tlong\t\t\t\troqF0;\n\tlong\t\t\t\troqF1;\n\tlong\t\t\t\tt[2];\n\tlong\t\t\t\troqFPS;\n\tint\t\t\t\t\tplayonwalls;\n\tbyte*\t\t\t\tbuf;\n\tlong\t\t\t\tdrawX, drawY;\n} cin_cache;\n\nstatic cinematics_t\t\tcin;\nstatic cin_cache\t\tcinTable[MAX_VIDEO_HANDLES];\nstatic int\t\t\t\tcurrentHandle = -1;\nstatic int\t\t\t\tCL_handle = -1;\n\nextern int\t\t\t\ts_soundtime;\t\t// sample PAIRS\nextern int   \t\t\ts_paintedtime; \t\t// sample PAIRS\n\n\nvoid CIN_CloseAllVideos(void) {\n\tint\t\ti;\n\n\tfor ( i = 0 ; i < MAX_VIDEO_HANDLES ; i++ ) {\n\t\tif (cinTable[i].fileName[0] != 0 ) {\n\t\t\tCIN_StopCinematic(i);\n\t\t}\n\t}\n}\n\n\nstatic int CIN_HandleForVideo(void) {\n\tint\t\ti;\n\n\tfor ( i = 0 ; i < MAX_VIDEO_HANDLES ; i++ ) {\n\t\tif ( cinTable[i].fileName[0] == 0 ) {\n\t\t\treturn i;\n\t\t}\n\t}\n\tCom_Error( ERR_DROP, \"CIN_HandleForVideo: none free\" );\n\treturn -1;\n}\n\n\nextern int CL_ScaledMilliseconds(void);\n\n//-----------------------------------------------------------------------------\n// RllSetupTable\n//\n// Allocates and initializes the square table.\n//\n// Parameters:\tNone\n//\n// Returns:\t\tNothing\n//-----------------------------------------------------------------------------\nstatic void RllSetupTable()\n{\n\tint z;\n\n\tfor (z=0;z<128;z++) {\n\t\tcin.sqrTable[z] = (short)(z*z);\n\t\tcin.sqrTable[z+128] = (short)(-cin.sqrTable[z]);\n\t}\n}\n\n\n\n//-----------------------------------------------------------------------------\n// RllDecodeMonoToMono\n//\n// Decode mono source data into a mono buffer.\n//\n// Parameters:\tfrom -> buffer holding encoded data\n//\t\t\t\tto ->\tbuffer to hold decoded data\n//\t\t\t\tsize =\tnumber of bytes of input (= # of shorts of output)\n//\t\t\t\tsignedOutput = 0 for unsigned output, non-zero for signed output\n//\t\t\t\tflag = flags from asset header\n//\n// Returns:\t\tNumber of samples placed in output buffer\n//-----------------------------------------------------------------------------\nlong RllDecodeMonoToMono(unsigned char *from,short *to,unsigned int size,char signedOutput ,unsigned short flag)\n{\n\tunsigned int z;\n\tint prev;\n\t\n\tif (signedOutput)\t\n\t\tprev =  flag - 0x8000;\n\telse \n\t\tprev = flag;\n\n\tfor (z=0;z<size;z++) {\n\t\tprev = to[z] = (short)(prev + cin.sqrTable[from[z]]); \n\t}\n\treturn size;\t//*sizeof(short));\n}\n\n\n//-----------------------------------------------------------------------------\n// RllDecodeMonoToStereo\n//\n// Decode mono source data into a stereo buffer. Output is 4 times the number\n// of bytes in the input.\n//\n// Parameters:\tfrom -> buffer holding encoded data\n//\t\t\t\tto ->\tbuffer to hold decoded data\n//\t\t\t\tsize =\tnumber of bytes of input (= 1/4 # of bytes of output)\n//\t\t\t\tsignedOutput = 0 for unsigned output, non-zero for signed output\n//\t\t\t\tflag = flags from asset header\n//\n// Returns:\t\tNumber of samples placed in output buffer\n//-----------------------------------------------------------------------------\nlong RllDecodeMonoToStereo(unsigned char *from,short *to,unsigned int size,char signedOutput,unsigned short flag)\n{\n\tunsigned int z;\n\tint prev;\n\t\n\tif (signedOutput)\t\n\t\tprev =  flag - 0x8000;\n\telse \n\t\tprev = flag;\n\n\tfor (z = 0; z < size; z++) {\n\t\tprev = (short)(prev + cin.sqrTable[from[z]]);\n\t\tto[z*2+0] = to[z*2+1] = (short)(prev);\n\t}\n\t\n\treturn size;\t// * 2 * sizeof(short));\n}\n\n\n//-----------------------------------------------------------------------------\n// RllDecodeStereoToStereo\n//\n// Decode stereo source data into a stereo buffer.\n//\n// Parameters:\tfrom -> buffer holding encoded data\n//\t\t\t\tto ->\tbuffer to hold decoded data\n//\t\t\t\tsize =\tnumber of bytes of input (= 1/2 # of bytes of output)\n//\t\t\t\tsignedOutput = 0 for unsigned output, non-zero for signed output\n//\t\t\t\tflag = flags from asset header\n//\n// Returns:\t\tNumber of samples placed in output buffer\n//-----------------------------------------------------------------------------\nlong RllDecodeStereoToStereo(unsigned char *from,short *to,unsigned int size,char signedOutput, unsigned short flag)\n{\n\tunsigned int z;\n\tunsigned char *zz = from;\n\tint\tprevL, prevR;\n\n\tif (signedOutput) {\n\t\tprevL = (flag & 0xff00) - 0x8000;\n\t\tprevR = ((flag & 0x00ff) << 8) - 0x8000;\n\t} else {\n\t\tprevL = flag & 0xff00;\n\t\tprevR = (flag & 0x00ff) << 8;\n\t}\n\n\tfor (z=0;z<size;z+=2) {\n                prevL = (short)(prevL + cin.sqrTable[*zz++]); \n                prevR = (short)(prevR + cin.sqrTable[*zz++]);\n                to[z+0] = (short)(prevL);\n                to[z+1] = (short)(prevR);\n\t}\n\t\n\treturn (size>>1);\t//*sizeof(short));\n}\n\n\n//-----------------------------------------------------------------------------\n// RllDecodeStereoToMono\n//\n// Decode stereo source data into a mono buffer.\n//\n// Parameters:\tfrom -> buffer holding encoded data\n//\t\t\t\tto ->\tbuffer to hold decoded data\n//\t\t\t\tsize =\tnumber of bytes of input (= # of bytes of output)\n//\t\t\t\tsignedOutput = 0 for unsigned output, non-zero for signed output\n//\t\t\t\tflag = flags from asset header\n//\n// Returns:\t\tNumber of samples placed in output buffer\n//-----------------------------------------------------------------------------\nlong RllDecodeStereoToMono(unsigned char *from,short *to,unsigned int size,char signedOutput, unsigned short flag)\n{\n\tunsigned int z;\n\tint prevL,prevR;\n\t\n\tif (signedOutput) {\n\t\tprevL = (flag & 0xff00) - 0x8000;\n\t\tprevR = ((flag & 0x00ff) << 8) -0x8000;\n\t} else {\n\t\tprevL = flag & 0xff00;\n\t\tprevR = (flag & 0x00ff) << 8;\n\t}\n\n\tfor (z=0;z<size;z+=1) {\n\t\tprevL= prevL + cin.sqrTable[from[z*2]];\n\t\tprevR = prevR + cin.sqrTable[from[z*2+1]];\n\t\tto[z] = (short)((prevL + prevR)/2);\n\t}\n\n\treturn size;\n}\n\n/******************************************************************************\n*\n* Function:\t\t\n*\n* Description:\t\n*\n******************************************************************************/\n\nstatic void move8_32( byte *src, byte *dst, int spl )\n{\n\tdouble *dsrc, *ddst;\n\tint dspl;\n\n\tdsrc = (double *)src;\n\tddst = (double *)dst;\n\tdspl = spl>>3;\n\n\tddst[0] = dsrc[0]; ddst[1] = dsrc[1]; ddst[2] = dsrc[2]; ddst[3] = dsrc[3];\n\tdsrc += dspl; ddst += dspl;\n\tddst[0] = dsrc[0]; ddst[1] = dsrc[1]; ddst[2] = dsrc[2]; ddst[3] = dsrc[3];\n\tdsrc += dspl; ddst += dspl;\n\tddst[0] = dsrc[0]; ddst[1] = dsrc[1]; ddst[2] = dsrc[2]; ddst[3] = dsrc[3];\n\tdsrc += dspl; ddst += dspl;\n\tddst[0] = dsrc[0]; ddst[1] = dsrc[1]; ddst[2] = dsrc[2]; ddst[3] = dsrc[3];\n\tdsrc += dspl; ddst += dspl;\n\tddst[0] = dsrc[0]; ddst[1] = dsrc[1]; ddst[2] = dsrc[2]; ddst[3] = dsrc[3];\n\tdsrc += dspl; ddst += dspl;\n\tddst[0] = dsrc[0]; ddst[1] = dsrc[1]; ddst[2] = dsrc[2]; ddst[3] = dsrc[3];\n\tdsrc += dspl; ddst += dspl;\n\tddst[0] = dsrc[0]; ddst[1] = dsrc[1]; ddst[2] = dsrc[2]; ddst[3] = dsrc[3];\n\tdsrc += dspl; ddst += dspl;\n\tddst[0] = dsrc[0]; ddst[1] = dsrc[1]; ddst[2] = dsrc[2]; ddst[3] = dsrc[3];\n}\n\n/******************************************************************************\n*\n* Function:\t\t\n*\n* Description:\t\n*\n******************************************************************************/\n\nstatic void move4_32( byte *src, byte *dst, int spl  )\n{\n\tdouble *dsrc, *ddst;\n\tint dspl;\n\n\tdsrc = (double *)src;\n\tddst = (double *)dst;\n\tdspl = spl>>3;\n\n\tddst[0] = dsrc[0]; ddst[1] = dsrc[1];\n\tdsrc += dspl; ddst += dspl;\n\tddst[0] = dsrc[0]; ddst[1] = dsrc[1];\n\tdsrc += dspl; ddst += dspl;\n\tddst[0] = dsrc[0]; ddst[1] = dsrc[1];\n\tdsrc += dspl; ddst += dspl;\n\tddst[0] = dsrc[0]; ddst[1] = dsrc[1];\n}\n\n/******************************************************************************\n*\n* Function:\t\t\n*\n* Description:\t\n*\n******************************************************************************/\n\nstatic void blit8_32( byte *src, byte *dst, int spl  )\n{\n\tdouble *dsrc, *ddst;\n\tint dspl;\n\n\tdsrc = (double *)src;\n\tddst = (double *)dst;\n\tdspl = spl>>3;\n\n\tddst[0] = dsrc[0]; ddst[1] = dsrc[1]; ddst[2] = dsrc[2]; ddst[3] = dsrc[3];\n\tdsrc += 4; ddst += dspl;\n\tddst[0] = dsrc[0]; ddst[1] = dsrc[1]; ddst[2] = dsrc[2]; ddst[3] = dsrc[3];\n\tdsrc += 4; ddst += dspl;\n\tddst[0] = dsrc[0]; ddst[1] = dsrc[1]; ddst[2] = dsrc[2]; ddst[3] = dsrc[3];\n\tdsrc += 4; ddst += dspl;\n\tddst[0] = dsrc[0]; ddst[1] = dsrc[1]; ddst[2] = dsrc[2]; ddst[3] = dsrc[3];\n\tdsrc += 4; ddst += dspl;\n\tddst[0] = dsrc[0]; ddst[1] = dsrc[1]; ddst[2] = dsrc[2]; ddst[3] = dsrc[3];\n\tdsrc += 4; ddst += dspl;\n\tddst[0] = dsrc[0]; ddst[1] = dsrc[1]; ddst[2] = dsrc[2]; ddst[3] = dsrc[3];\n\tdsrc += 4; ddst += dspl;\n\tddst[0] = dsrc[0]; ddst[1] = dsrc[1]; ddst[2] = dsrc[2]; ddst[3] = dsrc[3];\n\tdsrc += 4; ddst += dspl;\n\tddst[0] = dsrc[0]; ddst[1] = dsrc[1]; ddst[2] = dsrc[2]; ddst[3] = dsrc[3];\n}\n\n/******************************************************************************\n*\n* Function:\t\t\n*\n* Description:\t\n*\n******************************************************************************/\n#define movs double\nstatic void blit4_32( byte *src, byte *dst, int spl  )\n{\n\tmovs *dsrc, *ddst;\n\tint dspl;\n\n\tdsrc = (movs *)src;\n\tddst = (movs *)dst;\n\tdspl = spl>>3;\n\n\tddst[0] = dsrc[0]; ddst[1] = dsrc[1];\n\tdsrc += 2; ddst += dspl;\n\tddst[0] = dsrc[0]; ddst[1] = dsrc[1];\n\tdsrc += 2; ddst += dspl;\n\tddst[0] = dsrc[0]; ddst[1] = dsrc[1];\n\tdsrc += 2; ddst += dspl;\n\tddst[0] = dsrc[0]; ddst[1] = dsrc[1];\n}\n\n/******************************************************************************\n*\n* Function:\t\t\n*\n* Description:\t\n*\n******************************************************************************/\n\nstatic void blit2_32( byte *src, byte *dst, int spl  )\n{\n\tdouble *dsrc, *ddst;\n\tint dspl;\n\n\tdsrc = (double *)src;\n\tddst = (double *)dst;\n\tdspl = spl>>3;\n\n\tddst[0] = dsrc[0];\n\tddst[dspl] = dsrc[1];\n}\n\n/******************************************************************************\n*\n* Function:\t\t\n*\n* Description:\t\n*\n******************************************************************************/\n\nstatic void blitVQQuad32fs( byte **status, unsigned char *data )\n{\nunsigned short\tnewd, celdata, code;\nunsigned int\tindex, i;\nint\t\tspl;\n\n\tnewd\t= 0;\n\tceldata = 0;\n\tindex\t= 0;\n\t\n        spl = cinTable[currentHandle].samplesPerLine;\n        \n\tdo {\n\t\tif (!newd) { \n\t\t\tnewd = 7;\n\t\t\tceldata = data[0] + data[1]*256;\n\t\t\tdata += 2;\n\t\t} else {\n\t\t\tnewd--;\n\t\t}\n\n\t\tcode = (unsigned short)(celdata&0xc000); \n\t\tceldata <<= 2;\n\t\t\n\t\tswitch (code) {\n\t\t\tcase\t0x8000:\t\t\t\t\t\t\t\t\t\t\t\t\t// vq code\n\t\t\t\tblit8_32( (byte *)&vq8[(*data)*128], status[index], spl );\n\t\t\t\tdata++;\n\t\t\t\tindex += 5;\n\t\t\t\tbreak;\n\t\t\tcase\t0xc000:\t\t\t\t\t\t\t\t\t\t\t\t\t// drop\n\t\t\t\tindex++;\t\t\t\t\t\t\t\t\t\t\t\t\t// skip 8x8\n\t\t\t\tfor(i=0;i<4;i++) {\n\t\t\t\t\tif (!newd) { \n\t\t\t\t\t\tnewd = 7;\n\t\t\t\t\t\tceldata = data[0] + data[1]*256;\n\t\t\t\t\t\tdata += 2;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tnewd--;\n\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\tcode = (unsigned short)(celdata&0xc000); celdata <<= 2; \n\n\t\t\t\t\tswitch (code) {\t\t\t\t\t\t\t\t\t\t\t// code in top two bits of code\n\t\t\t\t\t\tcase\t0x8000:\t\t\t\t\t\t\t\t\t\t// 4x4 vq code\n\t\t\t\t\t\t\tblit4_32( (byte *)&vq4[(*data)*32], status[index], spl );\n\t\t\t\t\t\t\tdata++;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase\t0xc000:\t\t\t\t\t\t\t\t\t\t// 2x2 vq code\n\t\t\t\t\t\t\tblit2_32( (byte *)&vq2[(*data)*8], status[index], spl );\n\t\t\t\t\t\t\tdata++;\n\t\t\t\t\t\t\tblit2_32( (byte *)&vq2[(*data)*8], status[index]+8, spl );\n\t\t\t\t\t\t\tdata++;\n\t\t\t\t\t\t\tblit2_32( (byte *)&vq2[(*data)*8], status[index]+spl*2, spl );\n\t\t\t\t\t\t\tdata++;\n\t\t\t\t\t\t\tblit2_32( (byte *)&vq2[(*data)*8], status[index]+spl*2+8, spl );\n\t\t\t\t\t\t\tdata++;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase\t0x4000:\t\t\t\t\t\t\t\t\t\t// motion compensation\n\t\t\t\t\t\t\tmove4_32( status[index] + cin.mcomp[(*data)], status[index], spl );\n\t\t\t\t\t\t\tdata++;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tindex++;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase\t0x4000:\t\t\t\t\t\t\t\t\t\t\t\t\t// motion compensation\n\t\t\t\tmove8_32( status[index] + cin.mcomp[(*data)], status[index], spl );\n\t\t\t\tdata++;\n\t\t\t\tindex += 5;\n\t\t\t\tbreak;\n\t\t\tcase\t0x0000:\n\t\t\t\tindex += 5;\n\t\t\t\tbreak;\n\t\t}\n\t} while ( status[index] != NULL );\n}\n\n/******************************************************************************\n*\n* Function:\t\t\n*\n* Description:\t\n*\n******************************************************************************/\n\nstatic void ROQ_GenYUVTables( void )\n{\n\tfloat t_ub,t_vr,t_ug,t_vg;\n\tlong i;\n\n\tt_ub = (1.77200f/2.0f) * (float)(1<<6) + 0.5f;\n\tt_vr = (1.40200f/2.0f) * (float)(1<<6) + 0.5f;\n\tt_ug = (0.34414f/2.0f) * (float)(1<<6) + 0.5f;\n\tt_vg = (0.71414f/2.0f) * (float)(1<<6) + 0.5f;\n\tfor(i=0;i<256;i++) {\n\t\tfloat x = (float)(2 * i - 255);\n\t\n\t\tROQ_UB_tab[i] = (long)( ( t_ub * x) + (1<<5));\n\t\tROQ_VR_tab[i] = (long)( ( t_vr * x) + (1<<5));\n\t\tROQ_UG_tab[i] = (long)( (-t_ug * x)\t\t );\n\t\tROQ_VG_tab[i] = (long)( (-t_vg * x) + (1<<5));\n\t\tROQ_YY_tab[i] = (long)( (i << 6) | (i >> 2) );\n\t}\n}\n\n#define VQ2TO4(a,b,c,d) { \\\n    \t*c++ = a[0];\t\\\n\t*d++ = a[0];\t\\\n\t*d++ = a[0];\t\\\n\t*c++ = a[1];\t\\\n\t*d++ = a[1];\t\\\n\t*d++ = a[1];\t\\\n\t*c++ = b[0];\t\\\n\t*d++ = b[0];\t\\\n\t*d++ = b[0];\t\\\n\t*c++ = b[1];\t\\\n\t*d++ = b[1];\t\\\n\t*d++ = b[1];\t\\\n\t*d++ = a[0];\t\\\n\t*d++ = a[0];\t\\\n\t*d++ = a[1];\t\\\n\t*d++ = a[1];\t\\\n\t*d++ = b[0];\t\\\n\t*d++ = b[0];\t\\\n\t*d++ = b[1];\t\\\n\t*d++ = b[1];\t\\\n\ta += 2; b += 2; }\n \n#define VQ2TO2(a,b,c,d) { \\\n\t*c++ = *a;\t\\\n\t*d++ = *a;\t\\\n\t*d++ = *a;\t\\\n\t*c++ = *b;\t\\\n\t*d++ = *b;\t\\\n\t*d++ = *b;\t\\\n\t*d++ = *a;\t\\\n\t*d++ = *a;\t\\\n\t*d++ = *b;\t\\\n\t*d++ = *b;\t\\\n\ta++; b++; }\n\n/******************************************************************************\n*\n* Function:\t\t\n*\n* Description:\t\n*\n******************************************************************************/\n\nstatic unsigned short yuv_to_rgb( long y, long u, long v )\n{ \n\tlong r,g,b,YY = (long)(ROQ_YY_tab[(y)]);\n\n\tr = (YY + ROQ_VR_tab[v]) >> 9;\n\tg = (YY + ROQ_UG_tab[u] + ROQ_VG_tab[v]) >> 8;\n\tb = (YY + ROQ_UB_tab[u]) >> 9;\n\t\n\tif (r<0) r = 0; if (g<0) g = 0; if (b<0) b = 0;\n\tif (r > 31) r = 31; if (g > 63) g = 63; if (b > 31) b = 31;\n\n\treturn (unsigned short)((r<<11)+(g<<5)+(b));\n}\n\n/******************************************************************************\n*\n* Function:\t\t\n*\n* Description:\t\n*\n******************************************************************************/\n#if defined(MACOS_X)\n\nstatic inline unsigned int yuv_to_rgb24( long y, long u, long v )\n{ \n\tlong r,g,b,YY;\n        \n        YY = (long)(ROQ_YY_tab[(y)]);\n\n\tr = (YY + ROQ_VR_tab[v]) >> 6;\n\tg = (YY + ROQ_UG_tab[u] + ROQ_VG_tab[v]) >> 6;\n\tb = (YY + ROQ_UB_tab[u]) >> 6;\n\t\n\tif (r<0) r = 0; if (g<0) g = 0; if (b<0) b = 0;\n\tif (r > 255) r = 255; if (g > 255) g = 255; if (b > 255) b = 255;\n\t\n\treturn ((r<<24)|(g<<16)|(b<<8))|(255);\t//+(255<<24));\n}\n\n#else\nstatic unsigned int yuv_to_rgb24( long y, long u, long v )\n{ \n\tlong r,g,b,YY = (long)(ROQ_YY_tab[(y)]);\n\n\tr = (YY + ROQ_VR_tab[v]) >> 6;\n\tg = (YY + ROQ_UG_tab[u] + ROQ_VG_tab[v]) >> 6;\n\tb = (YY + ROQ_UB_tab[u]) >> 6;\n\t\n\tif (r<0) r = 0; if (g<0) g = 0; if (b<0) b = 0;\n\tif (r > 255) r = 255; if (g > 255) g = 255; if (b > 255) b = 255;\n\t\n\treturn LittleLong ((r)|(g<<8)|(b<<16)|(255<<24));\n}\n#endif\n\n/******************************************************************************\n*\n* Function:\t\t\n*\n* Description:\t\n*\n******************************************************************************/\n\nstatic void decodeCodeBook( byte *input, unsigned short roq_flags )\n{\n\tlong\ti, j, two, four;\n\tunsigned short\t*aptr, *bptr, *cptr, *dptr;\n\tlong\ty0,y1,y2,y3,cr,cb;\n\tbyte\t*bbptr, *baptr, *bcptr, *bdptr;\n\tunsigned int *iaptr, *ibptr, *icptr, *idptr;\n\n\tif (!roq_flags) {\n\t\ttwo = four = 256;\n\t} else {\n\t\ttwo  = roq_flags>>8;\n\t\tif (!two) two = 256;\n\t\tfour = roq_flags&0xff;\n\t}\n\n\tfour *= 2;\n\n\tbptr = (unsigned short *)vq2;\n\n\tif (!cinTable[currentHandle].half) {\n\t\tif (!cinTable[currentHandle].smootheddouble) {\n//\n// normal height\n//\n\t\t\tif (cinTable[currentHandle].samplesPerPixel==2) {\n\t\t\t\tfor(i=0;i<two;i++) {\n\t\t\t\t\ty0 = (long)*input++;\n\t\t\t\t\ty1 = (long)*input++;\n\t\t\t\t\ty2 = (long)*input++;\n\t\t\t\t\ty3 = (long)*input++;\n\t\t\t\t\tcr = (long)*input++;\n\t\t\t\t\tcb = (long)*input++;\n\t\t\t\t\t*bptr++ = yuv_to_rgb( y0, cr, cb );\n\t\t\t\t\t*bptr++ = yuv_to_rgb( y1, cr, cb );\n\t\t\t\t\t*bptr++ = yuv_to_rgb( y2, cr, cb );\n\t\t\t\t\t*bptr++ = yuv_to_rgb( y3, cr, cb );\n\t\t\t\t}\n\n\t\t\t\tcptr = (unsigned short *)vq4;\n\t\t\t\tdptr = (unsigned short *)vq8;\n\t\t\n\t\t\t\tfor(i=0;i<four;i++) {\n\t\t\t\t\taptr = (unsigned short *)vq2 + (*input++)*4;\n\t\t\t\t\tbptr = (unsigned short *)vq2 + (*input++)*4;\n\t\t\t\t\tfor(j=0;j<2;j++)\n\t\t\t\t\t\tVQ2TO4(aptr,bptr,cptr,dptr);\n\t\t\t\t}\n\t\t\t} else if (cinTable[currentHandle].samplesPerPixel==4) {\n\t\t\t\tibptr = (unsigned int *)bptr;\n\t\t\t\tfor(i=0;i<two;i++) {\n\t\t\t\t\ty0 = (long)*input++;\n\t\t\t\t\ty1 = (long)*input++;\n\t\t\t\t\ty2 = (long)*input++;\n\t\t\t\t\ty3 = (long)*input++;\n\t\t\t\t\tcr = (long)*input++;\n\t\t\t\t\tcb = (long)*input++;\n\t\t\t\t\t*ibptr++ = yuv_to_rgb24( y0, cr, cb );\n\t\t\t\t\t*ibptr++ = yuv_to_rgb24( y1, cr, cb );\n\t\t\t\t\t*ibptr++ = yuv_to_rgb24( y2, cr, cb );\n\t\t\t\t\t*ibptr++ = yuv_to_rgb24( y3, cr, cb );\n\t\t\t\t}\n\n\t\t\t\ticptr = (unsigned int *)vq4;\n\t\t\t\tidptr = (unsigned int *)vq8;\n\t\n\t\t\t\tfor(i=0;i<four;i++) {\n\t\t\t\t\tiaptr = (unsigned int *)vq2 + (*input++)*4;\n\t\t\t\t\tibptr = (unsigned int *)vq2 + (*input++)*4;\n\t\t\t\t\tfor(j=0;j<2;j++) \n\t\t\t\t\t\tVQ2TO4(iaptr, ibptr, icptr, idptr);\n\t\t\t\t}\n\t\t\t} else if (cinTable[currentHandle].samplesPerPixel==1) {\n\t\t\t\tbbptr = (byte *)bptr;\n\t\t\t\tfor(i=0;i<two;i++) {\n\t\t\t\t\t*bbptr++ = cinTable[currentHandle].gray[*input++];\n\t\t\t\t\t*bbptr++ = cinTable[currentHandle].gray[*input++];\n\t\t\t\t\t*bbptr++ = cinTable[currentHandle].gray[*input++];\n\t\t\t\t\t*bbptr++ = cinTable[currentHandle].gray[*input]; input +=3;\n\t\t\t\t}\n\n\t\t\t\tbcptr = (byte *)vq4;\n\t\t\t\tbdptr = (byte *)vq8;\n\t\n\t\t\t\tfor(i=0;i<four;i++) {\n\t\t\t\t\tbaptr = (byte *)vq2 + (*input++)*4;\n\t\t\t\t\tbbptr = (byte *)vq2 + (*input++)*4;\n\t\t\t\t\tfor(j=0;j<2;j++) \n\t\t\t\t\t\tVQ2TO4(baptr,bbptr,bcptr,bdptr);\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n//\n// double height, smoothed\n//\n\t\t\tif (cinTable[currentHandle].samplesPerPixel==2) {\n\t\t\t\tfor(i=0;i<two;i++) {\n\t\t\t\t\ty0 = (long)*input++;\n\t\t\t\t\ty1 = (long)*input++;\n\t\t\t\t\ty2 = (long)*input++;\n\t\t\t\t\ty3 = (long)*input++;\n\t\t\t\t\tcr = (long)*input++;\n\t\t\t\t\tcb = (long)*input++;\n\t\t\t\t\t*bptr++ = yuv_to_rgb( y0, cr, cb );\n\t\t\t\t\t*bptr++ = yuv_to_rgb( y1, cr, cb );\n\t\t\t\t\t*bptr++ = yuv_to_rgb( ((y0*3)+y2)/4, cr, cb );\n\t\t\t\t\t*bptr++ = yuv_to_rgb( ((y1*3)+y3)/4, cr, cb );\n\t\t\t\t\t*bptr++ = yuv_to_rgb( (y0+(y2*3))/4, cr, cb );\n\t\t\t\t\t*bptr++ = yuv_to_rgb( (y1+(y3*3))/4, cr, cb );\n\t\t\t\t\t*bptr++ = yuv_to_rgb( y2, cr, cb );\n\t\t\t\t\t*bptr++ = yuv_to_rgb( y3, cr, cb );\n\t\t\t\t}\n\n\t\t\t\tcptr = (unsigned short *)vq4;\n\t\t\t\tdptr = (unsigned short *)vq8;\n\t\t\n\t\t\t\tfor(i=0;i<four;i++) {\n\t\t\t\t\taptr = (unsigned short *)vq2 + (*input++)*8;\n\t\t\t\t\tbptr = (unsigned short *)vq2 + (*input++)*8;\n\t\t\t\t\tfor(j=0;j<2;j++) {\n\t\t\t\t\t\tVQ2TO4(aptr,bptr,cptr,dptr);\n\t\t\t\t\t\tVQ2TO4(aptr,bptr,cptr,dptr);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (cinTable[currentHandle].samplesPerPixel==4) {\n\t\t\t\tibptr = (unsigned int *)bptr;\n\t\t\t\tfor(i=0;i<two;i++) {\n\t\t\t\t\ty0 = (long)*input++;\n\t\t\t\t\ty1 = (long)*input++;\n\t\t\t\t\ty2 = (long)*input++;\n\t\t\t\t\ty3 = (long)*input++;\n\t\t\t\t\tcr = (long)*input++;\n\t\t\t\t\tcb = (long)*input++;\n\t\t\t\t\t*ibptr++ = yuv_to_rgb24( y0, cr, cb );\n\t\t\t\t\t*ibptr++ = yuv_to_rgb24( y1, cr, cb );\n\t\t\t\t\t*ibptr++ = yuv_to_rgb24( ((y0*3)+y2)/4, cr, cb );\n\t\t\t\t\t*ibptr++ = yuv_to_rgb24( ((y1*3)+y3)/4, cr, cb );\n\t\t\t\t\t*ibptr++ = yuv_to_rgb24( (y0+(y2*3))/4, cr, cb );\n\t\t\t\t\t*ibptr++ = yuv_to_rgb24( (y1+(y3*3))/4, cr, cb );\n\t\t\t\t\t*ibptr++ = yuv_to_rgb24( y2, cr, cb );\n\t\t\t\t\t*ibptr++ = yuv_to_rgb24( y3, cr, cb );\n\t\t\t\t}\n\n\t\t\t\ticptr = (unsigned int *)vq4;\n\t\t\t\tidptr = (unsigned int *)vq8;\n\t\n\t\t\t\tfor(i=0;i<four;i++) {\n\t\t\t\t\tiaptr = (unsigned int *)vq2 + (*input++)*8;\n\t\t\t\t\tibptr = (unsigned int *)vq2 + (*input++)*8;\n\t\t\t\t\tfor(j=0;j<2;j++) {\n\t\t\t\t\t\tVQ2TO4(iaptr, ibptr, icptr, idptr);\n\t\t\t\t\t\tVQ2TO4(iaptr, ibptr, icptr, idptr);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (cinTable[currentHandle].samplesPerPixel==1) {\n\t\t\t\tbbptr = (byte *)bptr;\n\t\t\t\tfor(i=0;i<two;i++) {\n\t\t\t\t\ty0 = (long)*input++;\n\t\t\t\t\ty1 = (long)*input++;\n\t\t\t\t\ty2 = (long)*input++;\n\t\t\t\t\ty3 = (long)*input; input+= 3;\n\t\t\t\t\t*bbptr++ = cinTable[currentHandle].gray[y0];\n\t\t\t\t\t*bbptr++ = cinTable[currentHandle].gray[y1];\n\t\t\t\t\t*bbptr++ = cinTable[currentHandle].gray[((y0*3)+y2)/4];\n\t\t\t\t\t*bbptr++ = cinTable[currentHandle].gray[((y1*3)+y3)/4];\n\t\t\t\t\t*bbptr++ = cinTable[currentHandle].gray[(y0+(y2*3))/4];\n\t\t\t\t\t*bbptr++ = cinTable[currentHandle].gray[(y1+(y3*3))/4];\t\t\t\t\t\t\n\t\t\t\t\t*bbptr++ = cinTable[currentHandle].gray[y2];\n\t\t\t\t\t*bbptr++ = cinTable[currentHandle].gray[y3];\n\t\t\t\t}\n\n\t\t\t\tbcptr = (byte *)vq4;\n\t\t\t\tbdptr = (byte *)vq8;\n\t\n\t\t\t\tfor(i=0;i<four;i++) {\n\t\t\t\t\tbaptr = (byte *)vq2 + (*input++)*8;\n\t\t\t\t\tbbptr = (byte *)vq2 + (*input++)*8;\n\t\t\t\t\tfor(j=0;j<2;j++) {\n\t\t\t\t\t\tVQ2TO4(baptr,bbptr,bcptr,bdptr);\n\t\t\t\t\t\tVQ2TO4(baptr,bbptr,bcptr,bdptr);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\t\t\t\n\t\t}\n\t} else {\n//\n// 1/4 screen\n//\n\t\tif (cinTable[currentHandle].samplesPerPixel==2) {\n\t\t\tfor(i=0;i<two;i++) {\n\t\t\t\ty0 = (long)*input; input+=2;\n\t\t\t\ty2 = (long)*input; input+=2;\n\t\t\t\tcr = (long)*input++;\n\t\t\t\tcb = (long)*input++;\n\t\t\t\t*bptr++ = yuv_to_rgb( y0, cr, cb );\n\t\t\t\t*bptr++ = yuv_to_rgb( y2, cr, cb );\n\t\t\t}\n\n\t\t\tcptr = (unsigned short *)vq4;\n\t\t\tdptr = (unsigned short *)vq8;\n\t\n\t\t\tfor(i=0;i<four;i++) {\n\t\t\t\taptr = (unsigned short *)vq2 + (*input++)*2;\n\t\t\t\tbptr = (unsigned short *)vq2 + (*input++)*2;\n\t\t\t\tfor(j=0;j<2;j++) { \n\t\t\t\t\tVQ2TO2(aptr,bptr,cptr,dptr);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (cinTable[currentHandle].samplesPerPixel == 1) {\n\t\t\tbbptr = (byte *)bptr;\n\t\t\t\t\n\t\t\tfor(i=0;i<two;i++) {\n\t\t\t\t*bbptr++ = cinTable[currentHandle].gray[*input]; input+=2;\n\t\t\t\t*bbptr++ = cinTable[currentHandle].gray[*input]; input+=4;\n\t\t\t}\n\n\t\t\tbcptr = (byte *)vq4;\n\t\t\tbdptr = (byte *)vq8;\n\t\n\t\t\tfor(i=0;i<four;i++) {\n\t\t\t\tbaptr = (byte *)vq2 + (*input++)*2;\n\t\t\t\tbbptr = (byte *)vq2 + (*input++)*2;\n\t\t\t\tfor(j=0;j<2;j++) { \n\t\t\t\t\tVQ2TO2(baptr,bbptr,bcptr,bdptr);\n\t\t\t\t}\n\t\t\t}\t\t\t\n\t\t} else if (cinTable[currentHandle].samplesPerPixel == 4) {\n\t\t\tibptr = (unsigned int *) bptr;\n\t\t\tfor(i=0;i<two;i++) {\n\t\t\t\ty0 = (long)*input; input+=2;\n\t\t\t\ty2 = (long)*input; input+=2;\n\t\t\t\tcr = (long)*input++;\n\t\t\t\tcb = (long)*input++;\n\t\t\t\t*ibptr++ = yuv_to_rgb24( y0, cr, cb );\n\t\t\t\t*ibptr++ = yuv_to_rgb24( y2, cr, cb );\n\t\t\t}\n\n\t\t\ticptr = (unsigned int *)vq4;\n\t\t\tidptr = (unsigned int *)vq8;\n\t\n\t\t\tfor(i=0;i<four;i++) {\n\t\t\t\tiaptr = (unsigned int *)vq2 + (*input++)*2;\n\t\t\t\tibptr = (unsigned int *)vq2 + (*input++)*2;\n\t\t\t\tfor(j=0;j<2;j++) { \n\t\t\t\t\tVQ2TO2(iaptr,ibptr,icptr,idptr);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n/******************************************************************************\n*\n* Function:\t\t\n*\n* Description:\t\n*\n******************************************************************************/\n\nstatic void recurseQuad( long startX, long startY, long quadSize, long xOff, long yOff )\n{\n\tbyte *scroff;\n\tlong bigx, bigy, lowx, lowy, useY;\n\tlong offset;\n\n\toffset = cinTable[currentHandle].screenDelta;\n\t\n\tlowx = lowy = 0;\n\tbigx = cinTable[currentHandle].xsize;\n\tbigy = cinTable[currentHandle].ysize;\n\n\tif (bigx > cinTable[currentHandle].CIN_WIDTH) bigx = cinTable[currentHandle].CIN_WIDTH;\n\tif (bigy > cinTable[currentHandle].CIN_HEIGHT) bigy = cinTable[currentHandle].CIN_HEIGHT;\n\n\tif ( (startX >= lowx) && (startX+quadSize) <= (bigx) && (startY+quadSize) <= (bigy) && (startY >= lowy) && quadSize <= MAXSIZE) {\n\t\tuseY = startY;\n\t\tscroff = cin.linbuf + (useY+((cinTable[currentHandle].CIN_HEIGHT-bigy)>>1)+yOff)*(cinTable[currentHandle].samplesPerLine) + (((startX+xOff))*cinTable[currentHandle].samplesPerPixel);\n\n\t\tcin.qStatus[0][cinTable[currentHandle].onQuad  ] = scroff;\n\t\tcin.qStatus[1][cinTable[currentHandle].onQuad++] = scroff+offset;\n\t}\n\n\tif ( quadSize != MINSIZE ) {\n\t\tquadSize >>= 1;\n\t\trecurseQuad( startX,\t\t  startY\t\t  , quadSize, xOff, yOff );\n\t\trecurseQuad( startX+quadSize, startY\t\t  , quadSize, xOff, yOff );\n\t\trecurseQuad( startX,\t\t  startY+quadSize , quadSize, xOff, yOff );\n\t\trecurseQuad( startX+quadSize, startY+quadSize , quadSize, xOff, yOff );\n\t}\n}\n\n\n/******************************************************************************\n*\n* Function:\t\t\n*\n* Description:\t\n*\n******************************************************************************/\n\nstatic void setupQuad( long xOff, long yOff )\n{\n\tlong numQuadCels, i,x,y;\n\tbyte *temp;\n\n\tif (xOff == cin.oldXOff && yOff == cin.oldYOff && (long)cinTable[currentHandle].ysize == cin.oldysize && (long)cinTable[currentHandle].xsize == cin.oldxsize) {\n\t\treturn;\n\t}\n\n\tcin.oldXOff = xOff;\n\tcin.oldYOff = yOff;\n\tcin.oldysize = cinTable[currentHandle].ysize;\n\tcin.oldxsize = cinTable[currentHandle].xsize;\n\n\tnumQuadCels  = (cinTable[currentHandle].CIN_WIDTH*cinTable[currentHandle].CIN_HEIGHT) / (16);\n\tnumQuadCels += numQuadCels/4 + numQuadCels/16;\n\tnumQuadCels += 64;\t\t\t\t\t\t\t  // for overflow\n\n\tnumQuadCels  = (cinTable[currentHandle].xsize*cinTable[currentHandle].ysize) / (16);\n\tnumQuadCels += numQuadCels/4;\n\tnumQuadCels += 64;\t\t\t\t\t\t\t  // for overflow\n\n\tcinTable[currentHandle].onQuad = 0;\n\n\tfor(y=0;y<(long)cinTable[currentHandle].ysize;y+=16) \n\t\tfor(x=0;x<(long)cinTable[currentHandle].xsize;x+=16) \n\t\t\trecurseQuad( x, y, 16, xOff, yOff );\n\n\ttemp = NULL;\n\n\tfor(i=(numQuadCels-64);i<numQuadCels;i++) {\n\t\tcin.qStatus[0][i] = temp;\t\t\t  // eoq\n\t\tcin.qStatus[1][i] = temp;\t\t\t  // eoq\n\t}\n}\n\n/******************************************************************************\n*\n* Function:\t\t\n*\n* Description:\t\n*\n******************************************************************************/\n\nstatic void readQuadInfo( byte *qData )\n{\n\tif (currentHandle < 0) return;\n\n\tcinTable[currentHandle].xsize    = qData[0]+qData[1]*256;\n\tcinTable[currentHandle].ysize    = qData[2]+qData[3]*256;\n\tcinTable[currentHandle].maxsize  = qData[4]+qData[5]*256;\n\tcinTable[currentHandle].minsize  = qData[6]+qData[7]*256;\n\t\n\tcinTable[currentHandle].CIN_HEIGHT = cinTable[currentHandle].ysize;\n\tcinTable[currentHandle].CIN_WIDTH  = cinTable[currentHandle].xsize;\n\n\tcinTable[currentHandle].samplesPerLine = cinTable[currentHandle].CIN_WIDTH*cinTable[currentHandle].samplesPerPixel;\n\tcinTable[currentHandle].screenDelta = cinTable[currentHandle].CIN_HEIGHT*cinTable[currentHandle].samplesPerLine;\n\n\tcinTable[currentHandle].half = qfalse;\n\tcinTable[currentHandle].smootheddouble = qfalse;\n\t\n\tcinTable[currentHandle].VQ0 = cinTable[currentHandle].VQNormal;\n\tcinTable[currentHandle].VQ1 = cinTable[currentHandle].VQBuffer;\n\n    cinTable[currentHandle].t[0] = cinTable[currentHandle].screenDelta;\n    cinTable[currentHandle].t[1] = -cinTable[currentHandle].screenDelta;\n\n    cinTable[currentHandle].drawX = cinTable[currentHandle].CIN_WIDTH;\n    cinTable[currentHandle].drawY = cinTable[currentHandle].CIN_HEIGHT;\n}\n\n/******************************************************************************\n*\n* Function:\t\t\n*\n* Description:\t\n*\n******************************************************************************/\n\nstatic void RoQPrepMcomp( long xoff, long yoff ) \n{\n\tlong i, j, x, y, temp, temp2;\n\n\ti=cinTable[currentHandle].samplesPerLine; j=cinTable[currentHandle].samplesPerPixel;\n\tif ( cinTable[currentHandle].xsize == (cinTable[currentHandle].ysize*4) && !cinTable[currentHandle].half ) { j = j+j; i = i+i; }\n\t\n\tfor(y=0;y<16;y++) {\n\t\ttemp2 = (y+yoff-8)*i;\n\t\tfor(x=0;x<16;x++) {\n\t\t\ttemp = (x+xoff-8)*j;\n\t\t\tcin.mcomp[(x*16)+y] = cinTable[currentHandle].normalBuffer0-(temp2+temp);\n\t\t}\n\t}\n}\n\n/******************************************************************************\n*\n* Function:\t\t\n*\n* Description:\t\n*\n******************************************************************************/\n\nstatic void initRoQ() \n{\n\tif (currentHandle < 0) return;\n\n\tcinTable[currentHandle].VQNormal = (void (*)(byte *, void *))blitVQQuad32fs;\n\tcinTable[currentHandle].VQBuffer = (void (*)(byte *, void *))blitVQQuad32fs;\n\tcinTable[currentHandle].samplesPerPixel = 4;\n\tROQ_GenYUVTables();\n\tRllSetupTable();\n}\n\n/******************************************************************************\n*\n* Function:\t\t\n*\n* Description:\t\n*\n******************************************************************************/\n/*\nstatic byte* RoQFetchInterlaced( byte *source ) {\n\tint x, *src, *dst;\n\n\tif (currentHandle < 0) return NULL;\n\n\tsrc = (int *)source;\n\tdst = (int *)cinTable[currentHandle].buf2;\n\n\tfor(x=0;x<256*256;x++) {\n\t\t*dst = *src;\n\t\tdst++; src += 2;\n\t}\n\treturn cinTable[currentHandle].buf2;\n}\n*/\nstatic void RoQReset() {\n\t\n\tif (currentHandle < 0) return;\n\n\tSys_EndStreamedFile(cinTable[currentHandle].iFile);\n\tFS_FCloseFile( cinTable[currentHandle].iFile );\n\tFS_FOpenFileRead (cinTable[currentHandle].fileName, &cinTable[currentHandle].iFile, qtrue);\n\t// let the background thread start reading ahead\n\tSys_BeginStreamedFile( cinTable[currentHandle].iFile, 0x10000 );\n\tSys_StreamedRead (cin.file, 16, 1, cinTable[currentHandle].iFile);\n\tRoQ_init();\n\tcinTable[currentHandle].status = FMV_LOOPED;\n}\n\n/******************************************************************************\n*\n* Function:\t\t\n*\n* Description:\t\n*\n******************************************************************************/\n\nstatic void RoQInterrupt(void)\n{\n\tbyte\t\t\t\t*framedata;\n        short\t\tsbuf[32768];\n        int\t\tssize;\n        \n\tif (currentHandle < 0) return;\n\n\tSys_StreamedRead( cin.file, cinTable[currentHandle].RoQFrameSize+8, 1, cinTable[currentHandle].iFile );\n\tif ( cinTable[currentHandle].RoQPlayed >= cinTable[currentHandle].ROQSize ) { \n\t\tif (cinTable[currentHandle].holdAtEnd==qfalse) {\n\t\t\tif (cinTable[currentHandle].looping) {\n\t\t\t\tRoQReset();\n\t\t\t} else {\n\t\t\t\tcinTable[currentHandle].status = FMV_EOF;\n\t\t\t}\n\t\t} else {\n\t\t\tcinTable[currentHandle].status = FMV_IDLE;\n\t\t}\n\t\treturn; \n\t}\n\n\tframedata = cin.file;\n//\n// new frame is ready\n//\nredump:\n\tswitch(cinTable[currentHandle].roq_id) \n\t{\n\t\tcase\tROQ_QUAD_VQ:\n\t\t\tif ((cinTable[currentHandle].numQuads&1)) {\n\t\t\t\tcinTable[currentHandle].normalBuffer0 = cinTable[currentHandle].t[1];\n\t\t\t\tRoQPrepMcomp( cinTable[currentHandle].roqF0, cinTable[currentHandle].roqF1 );\n\t\t\t\tcinTable[currentHandle].VQ1( (byte *)cin.qStatus[1], framedata);\n\t\t\t\tcinTable[currentHandle].buf = \tcin.linbuf + cinTable[currentHandle].screenDelta;\n\t\t\t} else {\n\t\t\t\tcinTable[currentHandle].normalBuffer0 = cinTable[currentHandle].t[0];\n\t\t\t\tRoQPrepMcomp( cinTable[currentHandle].roqF0, cinTable[currentHandle].roqF1 );\n\t\t\t\tcinTable[currentHandle].VQ0( (byte *)cin.qStatus[0], framedata );\n\t\t\t\tcinTable[currentHandle].buf = \tcin.linbuf;\n\t\t\t}\n\t\t\tif (cinTable[currentHandle].numQuads == 0) {\t\t// first frame\n\t\t\t\tCom_Memcpy(cin.linbuf+cinTable[currentHandle].screenDelta, cin.linbuf, cinTable[currentHandle].samplesPerLine*cinTable[currentHandle].ysize);\n\t\t\t}\n\t\t\tcinTable[currentHandle].numQuads++;\n\t\t\tcinTable[currentHandle].dirty = qtrue;\n\t\t\tbreak;\n\t\tcase\tROQ_CODEBOOK:\n\t\t\tdecodeCodeBook( framedata, (unsigned short)cinTable[currentHandle].roq_flags );\n\t\t\tbreak;\n\t\tcase\tZA_SOUND_MONO:\n\t\t\tif (!cinTable[currentHandle].silent) {\n\t\t\t\tssize = RllDecodeMonoToStereo( framedata, sbuf, cinTable[currentHandle].RoQFrameSize, 0, (unsigned short)cinTable[currentHandle].roq_flags);\n                                S_RawSamples( ssize, 22050, 2, 1, (byte *)sbuf, 1.0f );\n\t\t\t}\n\t\t\tbreak;\n\t\tcase\tZA_SOUND_STEREO:\n\t\t\tif (!cinTable[currentHandle].silent) {\n\t\t\t\tif (cinTable[currentHandle].numQuads == -1) {\n\t\t\t\t\tS_Update();\n\t\t\t\t\ts_rawend = s_soundtime;\n\t\t\t\t}\n\t\t\t\tssize = RllDecodeStereoToStereo( framedata, sbuf, cinTable[currentHandle].RoQFrameSize, 0, (unsigned short)cinTable[currentHandle].roq_flags);\n                                S_RawSamples( ssize, 22050, 2, 2, (byte *)sbuf, 1.0f );\n\t\t\t}\n\t\t\tbreak;\n\t\tcase\tROQ_QUAD_INFO:\n\t\t\tif (cinTable[currentHandle].numQuads == -1) {\n\t\t\t\treadQuadInfo( framedata );\n\t\t\t\tsetupQuad( 0, 0 );\n\t\t\t\t// we need to use CL_ScaledMilliseconds because of the smp mode calls from the renderer\n\t\t\t\tcinTable[currentHandle].startTime = cinTable[currentHandle].lastTime = CL_ScaledMilliseconds()*com_timescale->value;\n\t\t\t}\n\t\t\tif (cinTable[currentHandle].numQuads != 1) cinTable[currentHandle].numQuads = 0;\n\t\t\tbreak;\n\t\tcase\tROQ_PACKET:\n\t\t\tcinTable[currentHandle].inMemory = (qboolean) cinTable[currentHandle].roq_flags;\n\t\t\tcinTable[currentHandle].RoQFrameSize = 0;           // for header\n\t\t\tbreak;\n\t\tcase\tROQ_QUAD_HANG:\n\t\t\tcinTable[currentHandle].RoQFrameSize = 0;\n\t\t\tbreak;\n\t\tcase\tROQ_QUAD_JPEG:\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tcinTable[currentHandle].status = FMV_EOF;\n\t\t\tbreak;\n\t}\t\n//\n// read in next frame data\n//\n\tif ( cinTable[currentHandle].RoQPlayed >= cinTable[currentHandle].ROQSize ) { \n\t\tif (cinTable[currentHandle].holdAtEnd==qfalse) {\n\t\t\tif (cinTable[currentHandle].looping) {\n\t\t\t\tRoQReset();\n\t\t\t} else {\n\t\t\t\tcinTable[currentHandle].status = FMV_EOF;\n\t\t\t}\n\t\t} else {\n\t\t\tcinTable[currentHandle].status = FMV_IDLE;\n\t\t}\n\t\treturn; \n\t}\n\t\n\tframedata\t\t += cinTable[currentHandle].RoQFrameSize;\n\tcinTable[currentHandle].roq_id\t\t = framedata[0] + framedata[1]*256;\n\tcinTable[currentHandle].RoQFrameSize = framedata[2] + framedata[3]*256 + framedata[4]*65536;\n\tcinTable[currentHandle].roq_flags\t = framedata[6] + framedata[7]*256;\n\tcinTable[currentHandle].roqF0\t\t = (char)framedata[7];\n\tcinTable[currentHandle].roqF1\t\t = (char)framedata[6];\n\n\tif (cinTable[currentHandle].RoQFrameSize>65536||cinTable[currentHandle].roq_id==0x1084) {\n\t\tCom_DPrintf(\"roq_size>65536||roq_id==0x1084\\n\");\n\t\tcinTable[currentHandle].status = FMV_EOF;\n\t\tif (cinTable[currentHandle].looping) {\n\t\t\tRoQReset();\n\t\t}\n\t\treturn;\n\t}\n\tif (cinTable[currentHandle].inMemory && (cinTable[currentHandle].status != FMV_EOF)) { ((int&)cinTable[currentHandle].inMemory)--; framedata += 8; goto redump; }\n//\n// one more frame hits the dust\n//\n//\tassert(cinTable[currentHandle].RoQFrameSize <= 65536);\n//\tr = Sys_StreamedRead( cin.file, cinTable[currentHandle].RoQFrameSize+8, 1, cinTable[currentHandle].iFile );\n\tcinTable[currentHandle].RoQPlayed\t+= cinTable[currentHandle].RoQFrameSize+8;\n}\n\n/******************************************************************************\n*\n* Function:\t\t\n*\n* Description:\t\n*\n******************************************************************************/\n\nstatic void RoQ_init( void )\n{\n\t// we need to use CL_ScaledMilliseconds because of the smp mode calls from the renderer\n\tcinTable[currentHandle].startTime = cinTable[currentHandle].lastTime = CL_ScaledMilliseconds()*com_timescale->value;\n\n\tcinTable[currentHandle].RoQPlayed = 24;\n\n/*\tget frame rate */\t\n\tcinTable[currentHandle].roqFPS\t = cin.file[ 6] + cin.file[ 7]*256;\n\t\n\tif (!cinTable[currentHandle].roqFPS) cinTable[currentHandle].roqFPS = 30;\n\n\tcinTable[currentHandle].numQuads = -1;\n\n\tcinTable[currentHandle].roq_id\t\t= cin.file[ 8] + cin.file[ 9]*256;\n\tcinTable[currentHandle].RoQFrameSize\t= cin.file[10] + cin.file[11]*256 + cin.file[12]*65536;\n\tcinTable[currentHandle].roq_flags\t= cin.file[14] + cin.file[15]*256;\n\n\tif (cinTable[currentHandle].RoQFrameSize > 65536 || !cinTable[currentHandle].RoQFrameSize) { \n\t\treturn;\n\t}\n\n}\n\n/******************************************************************************\n*\n* Function:\t\t\n*\n* Description:\t\n*\n******************************************************************************/\n\nstatic void RoQShutdown( void ) {\n\tconst char *s;\n\n\tif (!cinTable[currentHandle].buf) {\n\t\treturn;\n\t}\n\n\tif ( cinTable[currentHandle].status == FMV_IDLE ) {\n\t\treturn;\n\t}\n\tCom_DPrintf(\"finished cinematic\\n\");\n\tcinTable[currentHandle].status = FMV_IDLE;\n\n\tif (cinTable[currentHandle].iFile) {\n\t\tSys_EndStreamedFile( cinTable[currentHandle].iFile );\n\t\tFS_FCloseFile( cinTable[currentHandle].iFile );\n\t\tcinTable[currentHandle].iFile = 0;\n\t}\n\n\tif (cinTable[currentHandle].alterGameState) {\n\t\tcls.state = CA_DISCONNECTED;\n\t\t// we can't just do a vstr nextmap, because\n\t\t// if we are aborting the intro cinematic with\n\t\t// a devmap command, nextmap would be valid by\n\t\t// the time it was referenced\n\t\ts = Cvar_VariableString( \"nextmap\" );\n\t\tif ( s[0] ) {\n\t\t\tCbuf_ExecuteText( EXEC_APPEND, va(\"%s\\n\", s) );\n\t\t\tCvar_Set( \"nextmap\", \"\" );\n\t\t}\n\t\tCL_handle = -1;\n\t}\n\tcinTable[currentHandle].fileName[0] = 0;\n\tcurrentHandle = -1;\n}\n\n/*\n==================\nSCR_StopCinematic\n==================\n*/\ne_status CIN_StopCinematic(int handle) {\n\t\n\tif (handle < 0 || handle>= MAX_VIDEO_HANDLES || cinTable[handle].status == FMV_EOF) return FMV_EOF;\n\tcurrentHandle = handle;\n\n\tCom_DPrintf(\"trFMV::stop(), closing %s\\n\", cinTable[currentHandle].fileName);\n\n\tif (!cinTable[currentHandle].buf) {\n\t\treturn FMV_EOF;\n\t}\n\n\tif (cinTable[currentHandle].alterGameState) {\n\t\tif ( cls.state != CA_CINEMATIC ) {\n\t\t\treturn cinTable[currentHandle].status;\n\t\t}\n\t}\n\tcinTable[currentHandle].status = FMV_EOF;\n\tRoQShutdown();\n\n\treturn FMV_EOF;\n}\n\n/*\n==================\nSCR_RunCinematic\n\nFetch and decompress the pending frame\n==================\n*/\n\n\ne_status CIN_RunCinematic (int handle)\n{\n        // bk001204 - init\n\tint\tstart = 0;\n\tint     thisTime = 0;\n\n\tif (handle < 0 || handle>= MAX_VIDEO_HANDLES || cinTable[handle].status == FMV_EOF) return FMV_EOF;\n\n\tif (cin.currentHandle != handle) {\n\t\tcurrentHandle = handle;\n\t\tcin.currentHandle = currentHandle;\n\t\tcinTable[currentHandle].status = FMV_EOF;\n\t\tRoQReset();\n\t}\n\n\tif (cinTable[handle].playonwalls < -1)\n\t{\n\t\treturn cinTable[handle].status;\n\t}\n\n\tcurrentHandle = handle;\n\n\tif (cinTable[currentHandle].alterGameState) {\n\t\tif ( cls.state != CA_CINEMATIC ) {\n\t\t\treturn cinTable[currentHandle].status;\n\t\t}\n\t}\n\n\tif (cinTable[currentHandle].status == FMV_IDLE) {\n\t\treturn cinTable[currentHandle].status;\n\t}\n\n\t// we need to use CL_ScaledMilliseconds because of the smp mode calls from the renderer\n\tthisTime = CL_ScaledMilliseconds()*com_timescale->value;\n\tif (cinTable[currentHandle].shader && (abs((int)(thisTime - cinTable[currentHandle].lastTime)))>100) {\n\t\tcinTable[currentHandle].startTime += thisTime - cinTable[currentHandle].lastTime;\n\t}\n\t// we need to use CL_ScaledMilliseconds because of the smp mode calls from the renderer\n\tcinTable[currentHandle].tfps = ((((CL_ScaledMilliseconds()*com_timescale->value) - cinTable[currentHandle].startTime)*3)/100);\n\n\tstart = cinTable[currentHandle].startTime;\n\twhile(  (cinTable[currentHandle].tfps != cinTable[currentHandle].numQuads)\n\t\t&& (cinTable[currentHandle].status == FMV_PLAY) ) \n\t{\n\t\tRoQInterrupt();\n\t\tif (start != (int)cinTable[currentHandle].startTime) {\n\t\t\t// we need to use CL_ScaledMilliseconds because of the smp mode calls from the renderer\n\t\t  cinTable[currentHandle].tfps = ((((CL_ScaledMilliseconds()*com_timescale->value)\n\t\t\t\t\t\t\t  - cinTable[currentHandle].startTime)*3)/100);\n\t\t\tstart = cinTable[currentHandle].startTime;\n\t\t}\n\t}\n\n\tcinTable[currentHandle].lastTime = thisTime;\n\n\tif (cinTable[currentHandle].status == FMV_LOOPED) {\n\t\tcinTable[currentHandle].status = FMV_PLAY;\n\t}\n\n\tif (cinTable[currentHandle].status == FMV_EOF) {\n\t  if (cinTable[currentHandle].looping) {\n\t\tRoQReset();\n\t  } else {\n\t\tRoQShutdown();\n\t  }\n\t}\n\n\treturn cinTable[currentHandle].status;\n}\n\n/*\n==================\nCL_PlayCinematic\n\n==================\n*/\nint CIN_PlayCinematic( const char *arg, int x, int y, int w, int h, int systemBits ) {\n\tunsigned short RoQID;\n\tchar\tname[MAX_OSPATH];\n\tint\t\ti;\n\n\tif (strstr(arg, \"/\") == NULL && strstr(arg, \"\\\\\") == NULL) {\n\t\tCom_sprintf (name, sizeof(name), \"video/%s\", arg);\n\t} else {\n\t\tCom_sprintf (name, sizeof(name), \"%s\", arg);\n\t}\n\n\tif (!(systemBits & CIN_system)) {\n\t\tfor ( i = 0 ; i < MAX_VIDEO_HANDLES ; i++ ) {\n\t\t\tif (!strcmp(cinTable[i].fileName, name) ) {\n\t\t\t\treturn i;\n\t\t\t}\n\t\t}\n\t}\n\n\tCom_DPrintf(\"SCR_PlayCinematic( %s )\\n\", arg);\n\n\tCom_Memset(&cin, 0, sizeof(cinematics_t) );\n\tcurrentHandle = CIN_HandleForVideo();\n\n\tcin.currentHandle = currentHandle;\n\n\tstrcpy(cinTable[currentHandle].fileName, name);\n\n\tcinTable[currentHandle].ROQSize = 0;\n\tcinTable[currentHandle].ROQSize = FS_FOpenFileRead (cinTable[currentHandle].fileName, &cinTable[currentHandle].iFile, qtrue);\n\n\tif (cinTable[currentHandle].ROQSize<=0) {\n\t\tCom_DPrintf(\"play(%s), ROQSize<=0\\n\", arg);\n\t\tcinTable[currentHandle].fileName[0] = 0;\n\t\treturn -1;\n\t}\n\n\tCIN_SetExtents(currentHandle, x, y, w, h);\n\tCIN_SetLooping(currentHandle, (qboolean) ((systemBits & CIN_loop)!=0));\n\n\tcinTable[currentHandle].CIN_HEIGHT = DEFAULT_CIN_HEIGHT;\n\tcinTable[currentHandle].CIN_WIDTH  =  DEFAULT_CIN_WIDTH;\n\tcinTable[currentHandle].holdAtEnd = (qboolean) ((systemBits & CIN_hold) != 0);\n\tcinTable[currentHandle].alterGameState = (qboolean) ((systemBits & CIN_system) != 0);\n\tcinTable[currentHandle].playonwalls = 1;\n\tcinTable[currentHandle].silent = (qboolean) ((systemBits & CIN_silent) != 0);\n\tcinTable[currentHandle].shader = (qboolean) ((systemBits & CIN_shader) != 0);\n\n\tif (cinTable[currentHandle].alterGameState) {\n\t\t// close the menu\n\t\tif ( uivm ) {\n\t\t\tVM_Call( uivm, UI_SET_ACTIVE_MENU, UIMENU_NONE );\n\t\t}\n\t} else {\n\t\tcinTable[currentHandle].playonwalls = cl_inGameVideo->integer;\n\t}\n\n\tinitRoQ();\n\t\t\t\t\t\n\tFS_Read (cin.file, 16, cinTable[currentHandle].iFile);\n\n\tRoQID = (unsigned short)(cin.file[0]) + (unsigned short)(cin.file[1])*256;\n\tif (RoQID == 0x1084)\n\t{\n\t\tRoQ_init();\n//\t\tFS_Read (cin.file, cinTable[currentHandle].RoQFrameSize+8, cinTable[currentHandle].iFile);\n\t\t// let the background thread start reading ahead\n\t\tSys_BeginStreamedFile( cinTable[currentHandle].iFile, 0x10000 );\n\n\t\tcinTable[currentHandle].status = FMV_PLAY;\n\t\tCom_DPrintf(\"trFMV::play(), playing %s\\n\", arg);\n\n\t\tif (cinTable[currentHandle].alterGameState) {\n\t\t\tcls.state = CA_CINEMATIC;\n\t\t}\n\t\t\n\t\tCon_Close();\n\n\t\ts_rawend = s_soundtime;\n\n\t\treturn currentHandle;\n\t}\n\tCom_DPrintf(\"trFMV::play(), invalid RoQ ID\\n\");\n\n\tRoQShutdown();\n\treturn -1;\n}\n\nvoid CIN_SetExtents (int handle, int x, int y, int w, int h) {\n\tif (handle < 0 || handle>= MAX_VIDEO_HANDLES || cinTable[handle].status == FMV_EOF) return;\n\tcinTable[handle].xpos = x;\n\tcinTable[handle].ypos = y;\n\tcinTable[handle].width = w;\n\tcinTable[handle].height = h;\n\tcinTable[handle].dirty = qtrue;\n}\n\nvoid CIN_SetLooping(int handle, qboolean loop) {\n\tif (handle < 0 || handle>= MAX_VIDEO_HANDLES || cinTable[handle].status == FMV_EOF) return;\n\tcinTable[handle].looping = loop;\n}\n\n/*\n==================\nSCR_DrawCinematic\n\n==================\n*/\nvoid CIN_DrawCinematic (int handle) {\n\tfloat\tx, y, w, h;\n\tbyte\t*buf;\n\n\tif (handle < 0 || handle>= MAX_VIDEO_HANDLES || cinTable[handle].status == FMV_EOF) return;\n\n\tif (!cinTable[handle].buf) {\n\t\treturn;\n\t}\n\n\tx = cinTable[handle].xpos;\n\ty = cinTable[handle].ypos;\n\tw = cinTable[handle].width;\n\th = cinTable[handle].height;\n\tbuf = cinTable[handle].buf;\n\tSCR_AdjustFrom640( &x, &y, &w, &h );\n\n\tif (cinTable[handle].dirty && (cinTable[handle].CIN_WIDTH != cinTable[handle].drawX || cinTable[handle].CIN_HEIGHT != cinTable[handle].drawY)) {\n\t\tint ix, iy, *buf2, *buf3, xm, ym, ll;\n                \n\t\txm = cinTable[handle].CIN_WIDTH/256;\n\t\tym = cinTable[handle].CIN_HEIGHT/256;\n                ll = 8;\n                if (cinTable[handle].CIN_WIDTH==512) {\n                    ll = 9;\n                }\n                \n\t\tbuf3 = (int*)buf;\n\t\tbuf2 = (int*) Hunk_AllocateTempMemory( 256*256*4 );\n                if (xm==2 && ym==2) {\n                    byte *bc2, *bc3;\n                    int\tic, iiy;\n                    \n                    bc2 = (byte *)buf2;\n                    bc3 = (byte *)buf3;\n                    for (iy = 0; iy<256; iy++) {\n                            iiy = iy<<12;\n                            for (ix = 0; ix<2048; ix+=8) {\n                                for(ic = ix;ic<(ix+4);ic++) {\n                                    *bc2=(bc3[iiy+ic]+bc3[iiy+4+ic]+bc3[iiy+2048+ic]+bc3[iiy+2048+4+ic])>>2;\n                                    bc2++;\n                                }\n                            }\n                    }\n                } else if (xm==2 && ym==1) {\n                    byte *bc2, *bc3;\n                    int\tic, iiy;\n                    \n                    bc2 = (byte *)buf2;\n                    bc3 = (byte *)buf3;\n                    for (iy = 0; iy<256; iy++) {\n                            iiy = iy<<11;\n                            for (ix = 0; ix<2048; ix+=8) {\n                                for(ic = ix;ic<(ix+4);ic++) {\n                                    *bc2=(bc3[iiy+ic]+bc3[iiy+4+ic])>>1;\n                                    bc2++;\n                                }\n                            }\n                    }\n                } else {\n                    for (iy = 0; iy<256; iy++) {\n                            for (ix = 0; ix<256; ix++) {\n                                    buf2[(iy<<8)+ix] = buf3[((iy*ym)<<ll) + (ix*xm)];\n                            }\n                    }\n                }\n\t\tre.DrawStretchRaw( x, y, w, h, 256, 256, (byte *)buf2, handle, qtrue);\n\t\tcinTable[handle].dirty = qfalse;\n\t\tHunk_FreeTempMemory(buf2);\n\t\treturn;\n\t}\n\n\tre.DrawStretchRaw( x, y, w, h, cinTable[handle].drawX, cinTable[handle].drawY, buf, handle, cinTable[handle].dirty);\n\tcinTable[handle].dirty = qfalse;\n}\n\nvoid CL_PlayCinematic_f(void) {\n\tchar\t*arg, *s;\n\tqboolean\tholdatend;\n\tint bits = CIN_system;\n\n\tCom_DPrintf(\"CL_PlayCinematic_f\\n\");\n\tif (cls.state == CA_CINEMATIC) {\n\t\tSCR_StopCinematic();\n\t}\n\n\targ = Cmd_Argv( 1 );\n\ts = Cmd_Argv(2);\n\n\tholdatend = qfalse;\n\tif ((s && s[0] == '1') || Q_stricmp(arg,\"demoend.roq\")==0 || Q_stricmp(arg,\"end.roq\")==0) {\n\t\tbits |= CIN_hold;\n\t}\n\tif (s && s[0] == '2') {\n\t\tbits |= CIN_loop;\n\t}\n\n\tS_StopAllSounds ();\n\n\tCL_handle = CIN_PlayCinematic( arg, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, bits );\n\tif (CL_handle >= 0) {\n\t\tdo {\n\t\t\tSCR_RunCinematic();\n\t\t} while (cinTable[currentHandle].buf == NULL && cinTable[currentHandle].status == FMV_PLAY);\t\t// wait for first frame (load codebook and sound)\n\t}\n}\n\n\nvoid SCR_DrawCinematic (void) {\n\tif (CL_handle >= 0 && CL_handle < MAX_VIDEO_HANDLES) {\n\t\tCIN_DrawCinematic(CL_handle);\n\t}\n}\n\nvoid SCR_RunCinematic (void)\n{\n\tif (CL_handle >= 0 && CL_handle < MAX_VIDEO_HANDLES) {\n\t\tCIN_RunCinematic(CL_handle);\n\t}\n}\n\nvoid SCR_StopCinematic(void) {\n\tif (CL_handle >= 0 && CL_handle < MAX_VIDEO_HANDLES) {\n\t\tCIN_StopCinematic(CL_handle);\n\t\tS_StopAllSounds ();\n\t\tCL_handle = -1;\n\t}\n}\n\nvoid CIN_UploadCinematic(int handle) {\n\tif (handle >= 0 && handle < MAX_VIDEO_HANDLES) {\n\t\tif (!cinTable[handle].buf) {\n\t\t\treturn;\n\t\t}\n\t\tif (cinTable[handle].playonwalls <= 0 && cinTable[handle].dirty) {\n\t\t\tif (cinTable[handle].playonwalls == 0) {\n\t\t\t\tcinTable[handle].playonwalls = -1;\n\t\t\t} else {\n\t\t\t\tif (cinTable[handle].playonwalls == -1) {\n\t\t\t\t\tcinTable[handle].playonwalls = -2;\n\t\t\t\t} else {\n\t\t\t\t\tcinTable[handle].dirty = qfalse;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tre.UploadCinematic( 256, 256, 256, 256, cinTable[handle].buf, handle, cinTable[handle].dirty);\n\t\tif (cl_inGameVideo->integer == 0 && cinTable[handle].playonwalls == 1) {\n\t\t\tcinTable[handle].playonwalls--;\n\t\t}\n\t}\n}\n\n"
  },
  {
    "path": "src/engine/client/cl_console.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n// console.c\n\n#include \"client.h\"\n\n\nint g_console_field_width = 78;\n\n\n#define\tNUM_CON_TIMES 4\n\n#define\t\tCON_TEXTSIZE\t32768\ntypedef struct {\n\tqboolean\tinitialized;\n\n\tshort\ttext[CON_TEXTSIZE];\n\tint\t\tcurrent;\t\t// line where next message will be printed\n\tint\t\tx;\t\t\t\t// offset in current line for next print\n\tint\t\tdisplay;\t\t// bottom of console displays this line\n\n\tint \tlinewidth;\t\t// characters across screen\n\tint\t\ttotallines;\t\t// total lines in console scrollback\n\n\tfloat\txadjust;\t\t// for wide aspect screens\n\n\tfloat\tdisplayFrac;\t// aproaches finalFrac at scr_conspeed\n\tfloat\tfinalFrac;\t\t// 0.0 to 1.0 lines of console to display\n\n\tint\t\tvislines;\t\t// in scanlines\n\n\tint\t\ttimes[NUM_CON_TIMES];\t// cls.realtime time the line was generated\n\t\t\t\t\t\t\t\t// for transparent notify lines\n\tvec4_t\tcolor;\n} console_t;\n\nextern\tconsole_t\tcon;\n\nconsole_t\tcon;\n\ncvar_t\t\t*con_conspeed;\ncvar_t\t\t*con_notifytime;\n\n#define\tDEFAULT_CONSOLE_WIDTH\t78\n\nvec4_t\tconsole_color = {1.0, 1.0, 1.0, 1.0};\n\n\n/*\n================\nCon_ToggleConsole_f\n================\n*/\nvoid Con_ToggleConsole_f (void) {\n\t// closing a full screen console restarts the demo loop\n\tif ( cls.state == CA_DISCONNECTED && cls.keyCatchers == KEYCATCH_CONSOLE ) {\n\t\tCL_StartDemoLoop();\n\t\treturn;\n\t}\n\n\tField_Clear( &g_consoleField );\n\tg_consoleField.widthInChars = g_console_field_width;\n\n\tCon_ClearNotify ();\n\tcls.keyCatchers ^= KEYCATCH_CONSOLE;\n}\n\n/*\n================\nCon_MessageMode_f\n================\n*/\nvoid Con_MessageMode_f (void) {\n\tchat_playerNum = -1;\n\tchat_team = qfalse;\n\tField_Clear( &chatField );\n\tchatField.widthInChars = 30;\n\n\tcls.keyCatchers ^= KEYCATCH_MESSAGE;\n}\n\n/*\n================\nCon_MessageMode2_f\n================\n*/\nvoid Con_MessageMode2_f (void) {\n\tchat_playerNum = -1;\n\tchat_team = qtrue;\n\tField_Clear( &chatField );\n\tchatField.widthInChars = 25;\n\tcls.keyCatchers ^= KEYCATCH_MESSAGE;\n}\n\n/*\n================\nCon_MessageMode3_f\n================\n*/\nvoid Con_MessageMode3_f (void) {\n\tchat_playerNum = VM_Call( cgvm, CG_CROSSHAIR_PLAYER );\n\tif ( chat_playerNum < 0 || chat_playerNum >= MAX_CLIENTS ) {\n\t\tchat_playerNum = -1;\n\t\treturn;\n\t}\n\tchat_team = qfalse;\n\tField_Clear( &chatField );\n\tchatField.widthInChars = 30;\n\tcls.keyCatchers ^= KEYCATCH_MESSAGE;\n}\n\n/*\n================\nCon_MessageMode4_f\n================\n*/\nvoid Con_MessageMode4_f (void) {\n\tchat_playerNum = VM_Call( cgvm, CG_LAST_ATTACKER );\n\tif ( chat_playerNum < 0 || chat_playerNum >= MAX_CLIENTS ) {\n\t\tchat_playerNum = -1;\n\t\treturn;\n\t}\n\tchat_team = qfalse;\n\tField_Clear( &chatField );\n\tchatField.widthInChars = 30;\n\tcls.keyCatchers ^= KEYCATCH_MESSAGE;\n}\n\n/*\n================\nCon_Clear_f\n================\n*/\nvoid Con_Clear_f (void) {\n\tint\t\ti;\n\n\tfor ( i = 0 ; i < CON_TEXTSIZE ; i++ ) {\n\t\tcon.text[i] = (ColorIndex(COLOR_WHITE)<<8) | ' ';\n\t}\n\n\tCon_Bottom();\t\t// go to end\n}\n\n\t\t\t\t\t\t\n/*\n================\nCon_Dump_f\n\nSave the console contents out to a file\n================\n*/\nvoid Con_Dump_f (void)\n{\n\tint\t\tl, x, i;\n\tshort\t*line;\n\tfileHandle_t\tf;\n\tchar\tbuffer[1024];\n\n\tif (Cmd_Argc() != 2)\n\t{\n\t\tCom_Printf (\"usage: condump <filename>\\n\");\n\t\treturn;\n\t}\n\n\tCom_Printf (\"Dumped console text to %s.\\n\", Cmd_Argv(1) );\n\n\tf = FS_FOpenFileWrite( Cmd_Argv( 1 ) );\n\tif (!f)\n\t{\n\t\tCom_Printf (\"ERROR: couldn't open.\\n\");\n\t\treturn;\n\t}\n\n\t// skip empty lines\n\tfor (l = con.current - con.totallines + 1 ; l <= con.current ; l++)\n\t{\n\t\tline = con.text + (l%con.totallines)*con.linewidth;\n\t\tfor (x=0 ; x<con.linewidth ; x++)\n\t\t\tif ((line[x] & 0xff) != ' ')\n\t\t\t\tbreak;\n\t\tif (x != con.linewidth)\n\t\t\tbreak;\n\t}\n\n\t// write the remaining lines\n\tbuffer[con.linewidth] = 0;\n\tfor ( ; l <= con.current ; l++)\n\t{\n\t\tline = con.text + (l%con.totallines)*con.linewidth;\n\t\tfor(i=0; i<con.linewidth; i++)\n\t\t\tbuffer[i] = line[i] & 0xff;\n\t\tfor (x=con.linewidth-1 ; x>=0 ; x--)\n\t\t{\n\t\t\tif (buffer[x] == ' ')\n\t\t\t\tbuffer[x] = 0;\n\t\t\telse\n\t\t\t\tbreak;\n\t\t}\n\t\tstrcat( buffer, \"\\n\" );\n\t\tFS_Write(buffer, (int)strlen(buffer), f);\n\t}\n\n\tFS_FCloseFile( f );\n}\n\n\t\t\t\t\t\t\n/*\n================\nCon_ClearNotify\n================\n*/\nvoid Con_ClearNotify( void ) {\n\tint\t\ti;\n\t\n\tfor ( i = 0 ; i < NUM_CON_TIMES ; i++ ) {\n\t\tcon.times[i] = 0;\n\t}\n}\n\n\t\t\t\t\t\t\n\n/*\n================\nCon_CheckResize\n\nIf the line width has changed, reformat the buffer.\n================\n*/\nvoid Con_CheckResize (void)\n{\n\tint\t\ti, j, width, oldwidth, oldtotallines, numlines, numchars;\n\tMAC_STATIC short\ttbuf[CON_TEXTSIZE];\n\n\twidth = (SCREEN_WIDTH / SMALLCHAR_WIDTH) - 2;\n\n\tif (width == con.linewidth)\n\t\treturn;\n\n\tif (width < 1)\t\t\t// video hasn't been initialized yet\n\t{\n\t\twidth = DEFAULT_CONSOLE_WIDTH;\n\t\tcon.linewidth = width;\n\t\tcon.totallines = CON_TEXTSIZE / con.linewidth;\n\t\tfor(i=0; i<CON_TEXTSIZE; i++)\n\n\t\t\tcon.text[i] = (ColorIndex(COLOR_WHITE)<<8) | ' ';\n\t}\n\telse\n\t{\n\t\toldwidth = con.linewidth;\n\t\tcon.linewidth = width;\n\t\toldtotallines = con.totallines;\n\t\tcon.totallines = CON_TEXTSIZE / con.linewidth;\n\t\tnumlines = oldtotallines;\n\n\t\tif (con.totallines < numlines)\n\t\t\tnumlines = con.totallines;\n\n\t\tnumchars = oldwidth;\n\t\n\t\tif (con.linewidth < numchars)\n\t\t\tnumchars = con.linewidth;\n\n\t\tCom_Memcpy (tbuf, con.text, CON_TEXTSIZE * sizeof(short));\n\t\tfor(i=0; i<CON_TEXTSIZE; i++)\n\n\t\t\tcon.text[i] = (ColorIndex(COLOR_WHITE)<<8) | ' ';\n\n\n\t\tfor (i=0 ; i<numlines ; i++)\n\t\t{\n\t\t\tfor (j=0 ; j<numchars ; j++)\n\t\t\t{\n\t\t\t\tcon.text[(con.totallines - 1 - i) * con.linewidth + j] =\n\t\t\t\t\t\ttbuf[((con.current - i + oldtotallines) %\n\t\t\t\t\t\t\t  oldtotallines) * oldwidth + j];\n\t\t\t}\n\t\t}\n\n\t\tCon_ClearNotify ();\n\t}\n\n\tcon.current = con.totallines - 1;\n\tcon.display = con.current;\n}\n\n\n/*\n================\nCon_Init\n================\n*/\nvoid Con_Init (void) {\n\tint\t\ti;\n\n\tcon_notifytime = Cvar_Get (\"con_notifytime\", \"3\", 0);\n\tcon_conspeed = Cvar_Get (\"scr_conspeed\", \"3\", 0);\n\n\tField_Clear( &g_consoleField );\n\tg_consoleField.widthInChars = g_console_field_width;\n\tfor ( i = 0 ; i < COMMAND_HISTORY ; i++ ) {\n\t\tField_Clear( &historyEditLines[i] );\n\t\thistoryEditLines[i].widthInChars = g_console_field_width;\n\t}\n\n\tCmd_AddCommand (\"toggleconsole\", Con_ToggleConsole_f);\n\tCmd_AddCommand (\"messagemode\", Con_MessageMode_f);\n\tCmd_AddCommand (\"messagemode2\", Con_MessageMode2_f);\n\tCmd_AddCommand (\"messagemode3\", Con_MessageMode3_f);\n\tCmd_AddCommand (\"messagemode4\", Con_MessageMode4_f);\n\tCmd_AddCommand (\"clear\", Con_Clear_f);\n\tCmd_AddCommand (\"condump\", Con_Dump_f);\n}\n\n\n/*\n===============\nCon_Linefeed\n===============\n*/\nvoid Con_Linefeed (qboolean skipnotify)\n{\n\tint\t\ti;\n\n\t// mark time for transparent overlay\n\tif (con.current >= 0)\n\t{\n    if (skipnotify)\n\t\t  con.times[con.current % NUM_CON_TIMES] = 0;\n    else\n\t\t  con.times[con.current % NUM_CON_TIMES] = cls.realtime;\n\t}\n\n\tcon.x = 0;\n\tif (con.display == con.current)\n\t\tcon.display++;\n\tcon.current++;\n\tfor(i=0; i<con.linewidth; i++)\n\t\tcon.text[(con.current%con.totallines)*con.linewidth+i] = (ColorIndex(COLOR_WHITE)<<8) | ' ';\n}\n\n/*\n================\nCL_ConsolePrint\n\nHandles cursor positioning, line wrapping, etc\nAll console printing must go through this in order to be logged to disk\nIf no console is visible, the text will appear at the top of the game window\n================\n*/\nvoid CL_ConsolePrint( char *txt ) {\n\tint\t\ty;\n\tint\t\tc, l;\n\tint\t\tcolor;\n\tqboolean skipnotify = qfalse;\t\t// NERVE - SMF\n\tint prev;\t\t\t\t\t\t\t// NERVE - SMF\n\n\t// TTimo - prefix for text that shows up in console but not in notify\n\t// backported from RTCW\n\tif ( !Q_strncmp( txt, \"[skipnotify]\", 12 ) ) {\n\t\tskipnotify = qtrue;\n\t\ttxt += 12;\n\t}\n\t\n\t// for some demos we don't want to ever show anything on the console\n\tif ( cl_noprint && cl_noprint->integer ) {\n\t\treturn;\n\t}\n\t\n\tif (!con.initialized) {\n\t\tcon.color[0] = \n\t\tcon.color[1] = \n\t\tcon.color[2] =\n\t\tcon.color[3] = 1.0f;\n\t\tcon.linewidth = -1;\n\t\tCon_CheckResize ();\n\t\tcon.initialized = qtrue;\n\t}\n\n\tcolor = ColorIndex(COLOR_WHITE);\n\n\twhile ( (c = *txt) != 0 ) {\n\t\tif ( Q_IsColorString( txt ) ) {\n\t\t\tcolor = ColorIndex( *(txt+1) );\n\t\t\ttxt += 2;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// count word length\n\t\tfor (l=0 ; l< con.linewidth ; l++) {\n\t\t\tif ( txt[l] <= ' ') {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t}\n\n\t\t// word wrap\n\t\tif (l != con.linewidth && (con.x + l >= con.linewidth) ) {\n\t\t\tCon_Linefeed(skipnotify);\n\n\t\t}\n\n\t\ttxt++;\n\n\t\tswitch (c)\n\t\t{\n\t\tcase '\\n':\n\t\t\tCon_Linefeed (skipnotify);\n\t\t\tbreak;\n\t\tcase '\\r':\n\t\t\tcon.x = 0;\n\t\t\tbreak;\n\t\tdefault:\t// display character and advance\n\t\t\ty = con.current % con.totallines;\n\t\t\tcon.text[y*con.linewidth+con.x] = (color << 8) | c;\n\t\t\tcon.x++;\n\t\t\tif (con.x >= con.linewidth) {\n\t\t\t\tCon_Linefeed(skipnotify);\n\t\t\t\tcon.x = 0;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t}\n\n\n\t// mark time for transparent overlay\n\tif (con.current >= 0) {\n\t\t// NERVE - SMF\n\t\tif ( skipnotify ) {\n\t\t\tprev = con.current % NUM_CON_TIMES - 1;\n\t\t\tif ( prev < 0 )\n\t\t\t\tprev = NUM_CON_TIMES - 1;\n\t\t\tcon.times[prev] = 0;\n\t\t}\n\t\telse\n\t\t// -NERVE - SMF\n\t\t\tcon.times[con.current % NUM_CON_TIMES] = cls.realtime;\n\t}\n}\n\n\n/*\n==============================================================================\n\nDRAWING\n\n==============================================================================\n*/\n\n\n/*\n================\nCon_DrawInput\n\nDraw the editline after a ] prompt\n================\n*/\nvoid Con_DrawInput (void) {\n\tint\t\ty;\n\n\tif ( cls.state != CA_DISCONNECTED && !(cls.keyCatchers & KEYCATCH_CONSOLE ) ) {\n\t\treturn;\n\t}\n\n\ty = con.vislines - ( SMALLCHAR_HEIGHT * 2 );\n\n\tre.SetColor( con.color );\n\n\tSCR_DrawSmallChar( con.xadjust + 1 * SMALLCHAR_WIDTH, y, ']' );\n\n\tField_Draw( &g_consoleField, con.xadjust + 2 * SMALLCHAR_WIDTH, y,\n\t\tSCREEN_WIDTH - 3 * SMALLCHAR_WIDTH, qtrue );\n}\n\n\n/*\n================\nCon_DrawNotify\n\nDraws the last few lines of output transparently over the game top\n================\n*/\nvoid Con_DrawNotify (void)\n{\n\tint\t\tx, v;\n\tshort\t*text;\n\tint\t\ti;\n\tint\t\ttime;\n\tint\t\tskip;\n\tint\t\tcurrentColor;\n\n\tcurrentColor = 7;\n\tre.SetColor( g_color_table[currentColor] );\n\n\tv = 0;\n\tfor (i= con.current-NUM_CON_TIMES+1 ; i<=con.current ; i++)\n\t{\n\t\tif (i < 0)\n\t\t\tcontinue;\n\t\ttime = con.times[i % NUM_CON_TIMES];\n\t\tif (time == 0)\n\t\t\tcontinue;\n\t\ttime = cls.realtime - time;\n\t\tif (time > con_notifytime->value*1000)\n\t\t\tcontinue;\n\t\ttext = con.text + (i % con.totallines)*con.linewidth;\n\n\t\tif (cl.snap.ps.pm_type != PM_INTERMISSION && cls.keyCatchers & (KEYCATCH_UI | KEYCATCH_CGAME) ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tfor (x = 0 ; x < con.linewidth ; x++) {\n\t\t\tif ( ( text[x] & 0xff ) == ' ' ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif ( ( (text[x]>>8)&7 ) != currentColor ) {\n\t\t\t\tcurrentColor = (text[x]>>8)&7;\n\t\t\t\tre.SetColor( g_color_table[currentColor] );\n\t\t\t}\n\t\t\tSCR_DrawSmallChar( cl_conXOffset->integer + con.xadjust + (x+1)*SMALLCHAR_WIDTH, v, text[x] & 0xff );\n\t\t}\n\n\t\tv += SMALLCHAR_HEIGHT;\n\t}\n\n\tre.SetColor( NULL );\n\n\tif (cls.keyCatchers & (KEYCATCH_UI | KEYCATCH_CGAME) ) {\n\t\treturn;\n\t}\n\n\t// draw the chat line\n\tif ( cls.keyCatchers & KEYCATCH_MESSAGE )\n\t{\n\t\tif (chat_team)\n\t\t{\n\t\t\tSCR_DrawBigString (8, v, \"say_team:\", 1.0f );\n\t\t\tskip = 11;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tSCR_DrawBigString (8, v, \"say:\", 1.0f );\n\t\t\tskip = 5;\n\t\t}\n\n\t\tField_BigDraw( &chatField, skip * BIGCHAR_WIDTH, v,\n\t\t\tSCREEN_WIDTH - ( skip + 1 ) * BIGCHAR_WIDTH, qtrue );\n\n\t\tv += BIGCHAR_HEIGHT;\n\t}\n\n}\n\n/*\n================\nCon_DrawSolidConsole\n\nDraws the console with the solid background\n================\n*/\nvoid Con_DrawSolidConsole( float frac ) {\n\tint\t\t\t\ti, x, y;\n\tint\t\t\t\trows;\n\tshort\t\t\t*text;\n\tint\t\t\t\trow;\n\tint\t\t\t\tlines;\n//\tqhandle_t\t\tconShader;\n\tint\t\t\t\tcurrentColor;\n\tvec4_t\t\t\tcolor;\n\n\tlines = cls.glconfig.vidHeight * frac;\n\tif (lines <= 0)\n\t\treturn;\n\n\tif (lines > cls.glconfig.vidHeight )\n\t\tlines = cls.glconfig.vidHeight;\n\n\t// on wide screens, we will center the text\n\tcon.xadjust = 0;\n\tSCR_AdjustFrom640( &con.xadjust, NULL, NULL, NULL );\n\n\t// draw the background\n\ty = frac * SCREEN_HEIGHT - 2;\n\tif ( y < 1 ) {\n\t\ty = 0;\n\t}\n\telse {\n\t\tSCR_DrawPic( 0, 0, SCREEN_WIDTH, y, cls.consoleShader );\n\t}\n\n\tcolor[0] = 1;\n\tcolor[1] = 0;\n\tcolor[2] = 0;\n\tcolor[3] = 1;\n\tSCR_FillRect( 0, y, SCREEN_WIDTH, 2, color );\n\n\n\t// draw the version number\n\n\tre.SetColor( g_color_table[ColorIndex(COLOR_RED)] );\n\n\ti = (int)strlen( Q3_VERSION );\n\n\tfor (x=0 ; x<i ; x++) {\n\n\t\tSCR_DrawSmallChar( cls.glconfig.vidWidth - ( i - x ) * SMALLCHAR_WIDTH, \n\n\t\t\t(lines-(SMALLCHAR_HEIGHT+SMALLCHAR_HEIGHT/2)), Q3_VERSION[x] );\n\n\t}\n\n\n\t// draw the text\n\tcon.vislines = lines;\n\trows = (lines-SMALLCHAR_WIDTH)/SMALLCHAR_WIDTH;\t\t// rows of text to draw\n\n\ty = lines - (SMALLCHAR_HEIGHT*3);\n\n\t// draw from the bottom up\n\tif (con.display != con.current)\n\t{\n\t// draw arrows to show the buffer is backscrolled\n\t\tre.SetColor( g_color_table[ColorIndex(COLOR_RED)] );\n\t\tfor (x=0 ; x<con.linewidth ; x+=4)\n\t\t\tSCR_DrawSmallChar( con.xadjust + (x+1)*SMALLCHAR_WIDTH, y, '^' );\n\t\ty -= SMALLCHAR_HEIGHT;\n\t\trows--;\n\t}\n\t\n\trow = con.display;\n\n\tif ( con.x == 0 ) {\n\t\trow--;\n\t}\n\n\tcurrentColor = 7;\n\tre.SetColor( g_color_table[currentColor] );\n\n\tfor (i=0 ; i<rows ; i++, y -= SMALLCHAR_HEIGHT, row--)\n\t{\n\t\tif (row < 0)\n\t\t\tbreak;\n\t\tif (con.current - row >= con.totallines) {\n\t\t\t// past scrollback wrap point\n\t\t\tcontinue;\t\n\t\t}\n\n\t\ttext = con.text + (row % con.totallines)*con.linewidth;\n\n\t\tfor (x=0 ; x<con.linewidth ; x++) {\n\t\t\tif ( ( text[x] & 0xff ) == ' ' ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif ( ( (text[x]>>8)&7 ) != currentColor ) {\n\t\t\t\tcurrentColor = (text[x]>>8)&7;\n\t\t\t\tre.SetColor( g_color_table[currentColor] );\n\t\t\t}\n\t\t\tSCR_DrawSmallChar(  con.xadjust + (x+1)*SMALLCHAR_WIDTH, y, text[x] & 0xff );\n\t\t}\n\t}\n\n\t// draw the input prompt, user text, and cursor if desired\n\tCon_DrawInput ();\n\n\tre.SetColor( NULL );\n}\n\n\n\n/*\n==================\nCon_DrawConsole\n==================\n*/\nvoid Con_DrawConsole( void ) {\n\t// check for console width changes from a vid mode change\n\tCon_CheckResize ();\n\n\t// if disconnected, render console full screen\n\tif ( cls.state == CA_DISCONNECTED ) {\n\t\tif ( !( cls.keyCatchers & (KEYCATCH_UI | KEYCATCH_CGAME)) ) {\n\t\t\tCon_DrawSolidConsole( 1.0 );\n\t\t\treturn;\n\t\t}\n\t}\n\n\tif ( con.displayFrac ) {\n\t\tCon_DrawSolidConsole( con.displayFrac );\n\t} else {\n\t\t// draw notify lines\n\t\tif ( cls.state == CA_ACTIVE ) {\n\t\t\tCon_DrawNotify ();\n\t\t}\n\t}\n}\n\n//================================================================\n\n/*\n==================\nCon_RunConsole\n\nScroll it up or down\n==================\n*/\nvoid Con_RunConsole (void) {\n\t// decide on the destination height of the console\n\tif ( cls.keyCatchers & KEYCATCH_CONSOLE )\n\t\tcon.finalFrac = 0.5;\t\t// half screen\n\telse\n\t\tcon.finalFrac = 0;\t\t\t\t// none visible\n\t\n\t// scroll towards the destination height\n\tif (con.finalFrac < con.displayFrac)\n\t{\n\t\tcon.displayFrac -= con_conspeed->value*cls.realFrametime*0.001;\n\t\tif (con.finalFrac > con.displayFrac)\n\t\t\tcon.displayFrac = con.finalFrac;\n\n\t}\n\telse if (con.finalFrac > con.displayFrac)\n\t{\n\t\tcon.displayFrac += con_conspeed->value*cls.realFrametime*0.001;\n\t\tif (con.finalFrac < con.displayFrac)\n\t\t\tcon.displayFrac = con.finalFrac;\n\t}\n\n}\n\n\nvoid Con_PageUp( void ) {\n\tcon.display -= 2;\n\tif ( con.current - con.display >= con.totallines ) {\n\t\tcon.display = con.current - con.totallines + 1;\n\t}\n}\n\nvoid Con_PageDown( void ) {\n\tcon.display += 2;\n\tif (con.display > con.current) {\n\t\tcon.display = con.current;\n\t}\n}\n\nvoid Con_Top( void ) {\n\tcon.display = con.totallines;\n\tif ( con.current - con.display >= con.totallines ) {\n\t\tcon.display = con.current - con.totallines + 1;\n\t}\n}\n\nvoid Con_Bottom( void ) {\n\tcon.display = con.current;\n}\n\n\nvoid Con_Close( void ) {\n\tif ( !com_cl_running->integer ) {\n\t\treturn;\n\t}\n\tField_Clear( &g_consoleField );\n\tCon_ClearNotify ();\n\tcls.keyCatchers &= ~KEYCATCH_CONSOLE;\n\tcon.finalFrac = 0;\t\t\t\t// none visible\n\tcon.displayFrac = 0;\n}\n"
  },
  {
    "path": "src/engine/client/cl_input.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n// cl.input.c  -- builds an intended movement command to send to the server\n\n#include \"client.h\"\n\nunsigned\tframe_msec;\nint\t\t\told_com_frameTime;\n\n/*\n===============================================================================\n\nKEY BUTTONS\n\nContinuous button event tracking is complicated by the fact that two different\ninput sources (say, mouse button 1 and the control key) can both press the\nsame button, but the button should only be released when both of the\npressing key have been released.\n\nWhen a key event issues a button command (+forward, +attack, etc), it appends\nits key number as argv(1) so it can be matched up with the release.\n\nargv(2) will be set to the time the event happened, which allows exact\ncontrol even at low framerates when the down and up events may both get qued\nat the same time.\n\n===============================================================================\n*/\n\n\nkbutton_t\tin_left, in_right, in_forward, in_back;\nkbutton_t\tin_lookup, in_lookdown, in_moveleft, in_moveright;\nkbutton_t\tin_strafe, in_speed;\nkbutton_t\tin_up, in_down;\n\nkbutton_t\tin_buttons[16];\n\n\nqboolean\tin_mlooking;\n\n\nvoid IN_MLookDown( void ) {\n\tin_mlooking = qtrue;\n}\n\nvoid IN_MLookUp( void ) {\n\tin_mlooking = qfalse;\n\tif ( !cl_freelook->integer ) {\n\t\tIN_CenterView ();\n\t}\n}\n\nvoid IN_KeyDown( kbutton_t *b ) {\n\tint\t\tk;\n\tchar\t*c;\n\t\n\tc = Cmd_Argv(1);\n\tif ( c[0] ) {\n\t\tk = atoi(c);\n\t} else {\n\t\tk = -1;\t\t// typed manually at the console for continuous down\n\t}\n\n\tif ( k == b->down[0] || k == b->down[1] ) {\n\t\treturn;\t\t// repeating key\n\t}\n\t\n\tif ( !b->down[0] ) {\n\t\tb->down[0] = k;\n\t} else if ( !b->down[1] ) {\n\t\tb->down[1] = k;\n\t} else {\n\t\tCom_Printf (\"Three keys down for a button!\\n\");\n\t\treturn;\n\t}\n\t\n\tif ( b->active ) {\n\t\treturn;\t\t// still down\n\t}\n\n\t// save timestamp for partial frame summing\n\tc = Cmd_Argv(2);\n\tb->downtime = atoi(c);\n\n\tb->active = qtrue;\n\tb->wasPressed = qtrue;\n}\n\nvoid IN_KeyUp( kbutton_t *b ) {\n\tint\t\tk;\n\tchar\t*c;\n\tunsigned\tuptime;\n\n\tc = Cmd_Argv(1);\n\tif ( c[0] ) {\n\t\tk = atoi(c);\n\t} else {\n\t\t// typed manually at the console, assume for unsticking, so clear all\n\t\tb->down[0] = b->down[1] = 0;\n\t\tb->active = qfalse;\n\t\treturn;\n\t}\n\n\tif ( b->down[0] == k ) {\n\t\tb->down[0] = 0;\n\t} else if ( b->down[1] == k ) {\n\t\tb->down[1] = 0;\n\t} else {\n\t\treturn;\t\t// key up without coresponding down (menu pass through)\n\t}\n\tif ( b->down[0] || b->down[1] ) {\n\t\treturn;\t\t// some other key is still holding it down\n\t}\n\n\tb->active = qfalse;\n\n\t// save timestamp for partial frame summing\n\tc = Cmd_Argv(2);\n\tuptime = atoi(c);\n\tif ( uptime ) {\n\t\tb->msec += uptime - b->downtime;\n\t} else {\n\t\tb->msec += frame_msec / 2;\n\t}\n\n\tb->active = qfalse;\n}\n\n\n\n/*\n===============\nCL_KeyState\n\nReturns the fraction of the frame that the key was down\n===============\n*/\nfloat CL_KeyState( kbutton_t *key ) {\n\tfloat\t\tval;\n\tint\t\t\tmsec;\n\n\tmsec = key->msec;\n\tkey->msec = 0;\n\n\tif ( key->active ) {\n\t\t// still down\n\t\tif ( !key->downtime ) {\n\t\t\tmsec = com_frameTime;\n\t\t} else {\n\t\t\tmsec += com_frameTime - key->downtime;\n\t\t}\n\t\tkey->downtime = com_frameTime;\n\t}\n\n#if 0\n\tif (msec) {\n\t\tCom_Printf (\"%i \", msec);\n\t}\n#endif\n\n\tval = (float)msec / frame_msec;\n\tif ( val < 0 ) {\n\t\tval = 0;\n\t}\n\tif ( val > 1 ) {\n\t\tval = 1;\n\t}\n\n\treturn val;\n}\n\n\n\nvoid IN_UpDown(void) {IN_KeyDown(&in_up);}\nvoid IN_UpUp(void) {IN_KeyUp(&in_up);}\nvoid IN_DownDown(void) {IN_KeyDown(&in_down);}\nvoid IN_DownUp(void) {IN_KeyUp(&in_down);}\nvoid IN_LeftDown(void) {IN_KeyDown(&in_left);}\nvoid IN_LeftUp(void) {IN_KeyUp(&in_left);}\nvoid IN_RightDown(void) {IN_KeyDown(&in_right);}\nvoid IN_RightUp(void) {IN_KeyUp(&in_right);}\nvoid IN_ForwardDown(void) {IN_KeyDown(&in_forward);}\nvoid IN_ForwardUp(void) {IN_KeyUp(&in_forward);}\nvoid IN_BackDown(void) {IN_KeyDown(&in_back);}\nvoid IN_BackUp(void) {IN_KeyUp(&in_back);}\nvoid IN_LookupDown(void) {IN_KeyDown(&in_lookup);}\nvoid IN_LookupUp(void) {IN_KeyUp(&in_lookup);}\nvoid IN_LookdownDown(void) {IN_KeyDown(&in_lookdown);}\nvoid IN_LookdownUp(void) {IN_KeyUp(&in_lookdown);}\nvoid IN_MoveleftDown(void) {IN_KeyDown(&in_moveleft);}\nvoid IN_MoveleftUp(void) {IN_KeyUp(&in_moveleft);}\nvoid IN_MoverightDown(void) {IN_KeyDown(&in_moveright);}\nvoid IN_MoverightUp(void) {IN_KeyUp(&in_moveright);}\n\nvoid IN_SpeedDown(void) {IN_KeyDown(&in_speed);}\nvoid IN_SpeedUp(void) {IN_KeyUp(&in_speed);}\nvoid IN_StrafeDown(void) {IN_KeyDown(&in_strafe);}\nvoid IN_StrafeUp(void) {IN_KeyUp(&in_strafe);}\n\nvoid IN_Button0Down(void) {IN_KeyDown(&in_buttons[0]);}\nvoid IN_Button0Up(void) {IN_KeyUp(&in_buttons[0]);}\nvoid IN_Button1Down(void) {IN_KeyDown(&in_buttons[1]);}\nvoid IN_Button1Up(void) {IN_KeyUp(&in_buttons[1]);}\nvoid IN_Button2Down(void) {IN_KeyDown(&in_buttons[2]);}\nvoid IN_Button2Up(void) {IN_KeyUp(&in_buttons[2]);}\nvoid IN_Button3Down(void) {IN_KeyDown(&in_buttons[3]);}\nvoid IN_Button3Up(void) {IN_KeyUp(&in_buttons[3]);}\nvoid IN_Button4Down(void) {IN_KeyDown(&in_buttons[4]);}\nvoid IN_Button4Up(void) {IN_KeyUp(&in_buttons[4]);}\nvoid IN_Button5Down(void) {IN_KeyDown(&in_buttons[5]);}\nvoid IN_Button5Up(void) {IN_KeyUp(&in_buttons[5]);}\nvoid IN_Button6Down(void) {IN_KeyDown(&in_buttons[6]);}\nvoid IN_Button6Up(void) {IN_KeyUp(&in_buttons[6]);}\nvoid IN_Button7Down(void) {IN_KeyDown(&in_buttons[7]);}\nvoid IN_Button7Up(void) {IN_KeyUp(&in_buttons[7]);}\nvoid IN_Button8Down(void) {IN_KeyDown(&in_buttons[8]);}\nvoid IN_Button8Up(void) {IN_KeyUp(&in_buttons[8]);}\nvoid IN_Button9Down(void) {IN_KeyDown(&in_buttons[9]);}\nvoid IN_Button9Up(void) {IN_KeyUp(&in_buttons[9]);}\nvoid IN_Button10Down(void) {IN_KeyDown(&in_buttons[10]);}\nvoid IN_Button10Up(void) {IN_KeyUp(&in_buttons[10]);}\nvoid IN_Button11Down(void) {IN_KeyDown(&in_buttons[11]);}\nvoid IN_Button11Up(void) {IN_KeyUp(&in_buttons[11]);}\nvoid IN_Button12Down(void) {IN_KeyDown(&in_buttons[12]);}\nvoid IN_Button12Up(void) {IN_KeyUp(&in_buttons[12]);}\nvoid IN_Button13Down(void) {IN_KeyDown(&in_buttons[13]);}\nvoid IN_Button13Up(void) {IN_KeyUp(&in_buttons[13]);}\nvoid IN_Button14Down(void) {IN_KeyDown(&in_buttons[14]);}\nvoid IN_Button14Up(void) {IN_KeyUp(&in_buttons[14]);}\nvoid IN_Button15Down(void) {IN_KeyDown(&in_buttons[15]);}\nvoid IN_Button15Up(void) {IN_KeyUp(&in_buttons[15]);}\n\nvoid IN_ButtonDown (void) {\n\tIN_KeyDown(&in_buttons[1]);}\nvoid IN_ButtonUp (void) {\n\tIN_KeyUp(&in_buttons[1]);}\n\nvoid IN_CenterView (void) {\n\tcl.viewangles[PITCH] = -SHORT2ANGLE(cl.snap.ps.delta_angles[PITCH]);\n}\n\n\n//==========================================================================\n\ncvar_t\t*cl_upspeed;\ncvar_t\t*cl_forwardspeed;\ncvar_t\t*cl_sidespeed;\n\ncvar_t\t*cl_yawspeed;\ncvar_t\t*cl_pitchspeed;\n\ncvar_t\t*cl_run;\n\ncvar_t\t*cl_anglespeedkey;\n\n\n/*\n================\nCL_AdjustAngles\n\nMoves the local angle positions\n================\n*/\nvoid CL_AdjustAngles( void ) {\n\tfloat\tspeed;\n\t\n\tif ( in_speed.active ) {\n\t\tspeed = 0.001 * cls.frametime * cl_anglespeedkey->value;\n\t} else {\n\t\tspeed = 0.001 * cls.frametime;\n\t}\n\n\tif ( !in_strafe.active ) {\n\t\tcl.viewangles[YAW] -= speed*cl_yawspeed->value*CL_KeyState (&in_right);\n\t\tcl.viewangles[YAW] += speed*cl_yawspeed->value*CL_KeyState (&in_left);\n\t}\n\n\tcl.viewangles[PITCH] -= speed*cl_pitchspeed->value * CL_KeyState (&in_lookup);\n\tcl.viewangles[PITCH] += speed*cl_pitchspeed->value * CL_KeyState (&in_lookdown);\n}\n\n/*\n================\nCL_KeyMove\n\nSets the usercmd_t based on key states\n================\n*/\nvoid CL_KeyMove( usercmd_t *cmd ) {\n\tint\t\tmovespeed;\n\tint\t\tforward, side, up;\n\n\t//\n\t// adjust for speed key / running\n\t// the walking flag is to keep animations consistant\n\t// even during acceleration and develeration\n\t//\n\tif ( in_speed.active ^ cl_run->integer ) {\n\t\tmovespeed = 127;\n\t\tcmd->buttons &= ~BUTTON_WALKING;\n\t} else {\n\t\tcmd->buttons |= BUTTON_WALKING;\n\t\tmovespeed = 64;\n\t}\n\n\tforward = 0;\n\tside = 0;\n\tup = 0;\n\tif ( in_strafe.active ) {\n\t\tside += movespeed * CL_KeyState (&in_right);\n\t\tside -= movespeed * CL_KeyState (&in_left);\n\t}\n\n\tside += movespeed * CL_KeyState (&in_moveright);\n\tside -= movespeed * CL_KeyState (&in_moveleft);\n\n\n\tup += movespeed * CL_KeyState (&in_up);\n\tup -= movespeed * CL_KeyState (&in_down);\n\n\tforward += movespeed * CL_KeyState (&in_forward);\n\tforward -= movespeed * CL_KeyState (&in_back);\n\n\tcmd->forwardmove = ClampChar( forward );\n\tcmd->rightmove = ClampChar( side );\n\tcmd->upmove = ClampChar( up );\n}\n\n/*\n=================\nCL_MouseEvent\n=================\n*/\nvoid CL_MouseEvent( int dx, int dy, int time ) {\n\tif ( cls.keyCatchers & KEYCATCH_UI ) {\n\t\tVM_Call( uivm, UI_MOUSE_EVENT, dx, dy );\n\t} else if (cls.keyCatchers & KEYCATCH_CGAME) {\n\t\tVM_Call (cgvm, CG_MOUSE_EVENT, dx, dy);\n\t} else {\n\t\tcl.mouseDx[cl.mouseIndex] += dx;\n\t\tcl.mouseDy[cl.mouseIndex] += dy;\n\t}\n}\n\n/*\n=================\nCL_JoystickEvent\n\nJoystick values stay set until changed\n=================\n*/\nvoid CL_JoystickEvent( int axis, int value, int time ) {\n\tif ( axis < 0 || axis >= MAX_JOYSTICK_AXIS ) {\n\t\tCom_Error( ERR_DROP, \"CL_JoystickEvent: bad axis %i\", axis );\n\t}\n\tcl.joystickAxis[axis] = value;\n}\n\n/*\n=================\nCL_JoystickMove\n=================\n*/\nvoid CL_JoystickMove( usercmd_t *cmd ) {\n\tint\t\tmovespeed;\n\tfloat\tanglespeed;\n\n\tif ( in_speed.active ^ cl_run->integer ) {\n\t\tmovespeed = 2;\n\t} else {\n\t\tmovespeed = 1;\n\t\tcmd->buttons |= BUTTON_WALKING;\n\t}\n\n\tif ( in_speed.active ) {\n\t\tanglespeed = 0.001 * cls.frametime * cl_anglespeedkey->value;\n\t} else {\n\t\tanglespeed = 0.001 * cls.frametime;\n\t}\n\n\tif ( !in_strafe.active ) {\n\t\tcl.viewangles[YAW] += anglespeed * cl_yawspeed->value * cl.joystickAxis[AXIS_SIDE];\n\t} else {\n\t\tcmd->rightmove = ClampChar( cmd->rightmove + cl.joystickAxis[AXIS_SIDE] );\n\t}\n\n\tif ( in_mlooking ) {\n\t\tcl.viewangles[PITCH] += anglespeed * cl_pitchspeed->value * cl.joystickAxis[AXIS_FORWARD];\n\t} else {\n\t\tcmd->forwardmove = ClampChar( cmd->forwardmove + cl.joystickAxis[AXIS_FORWARD] );\n\t}\n\n\tcmd->upmove = ClampChar( cmd->upmove + cl.joystickAxis[AXIS_UP] );\n}\n\n/*\n=================\nCL_MouseMove\n=================\n*/\nvoid CL_MouseMove( usercmd_t *cmd ) {\n\tfloat\tmx, my;\n\tfloat\taccelSensitivity;\n\tfloat\trate;\n\n\t// allow mouse smoothing\n\tif ( m_filter->integer ) {\n\t\tmx = ( cl.mouseDx[0] + cl.mouseDx[1] ) * 0.5;\n\t\tmy = ( cl.mouseDy[0] + cl.mouseDy[1] ) * 0.5;\n\t} else {\n\t\tmx = cl.mouseDx[cl.mouseIndex];\n\t\tmy = cl.mouseDy[cl.mouseIndex];\n\t}\n\tcl.mouseIndex ^= 1;\n\tcl.mouseDx[cl.mouseIndex] = 0;\n\tcl.mouseDy[cl.mouseIndex] = 0;\n\n\trate = sqrt( mx * mx + my * my ) / (float)frame_msec;\n\taccelSensitivity = cl_sensitivity->value + rate * cl_mouseAccel->value;\n\n\t// scale by FOV\n\taccelSensitivity *= cl.cgameSensitivity;\n\n\tif ( rate && cl_showMouseRate->integer ) {\n\t\tCom_Printf( \"%f : %f\\n\", rate, accelSensitivity );\n\t}\n\n\tmx *= accelSensitivity;\n\tmy *= accelSensitivity;\n\n\tif (!mx && !my) {\n\t\treturn;\n\t}\n\n\t// add mouse X/Y movement to cmd\n\tif ( in_strafe.active ) {\n\t\tcmd->rightmove = ClampChar( cmd->rightmove + m_side->value * mx );\n\t} else {\n\t\tcl.viewangles[YAW] -= m_yaw->value * mx;\n\t}\n\n\tif ( (in_mlooking || cl_freelook->integer) && !in_strafe.active ) {\n\t\tcl.viewangles[PITCH] += m_pitch->value * my;\n\t} else {\n\t\tcmd->forwardmove = ClampChar( cmd->forwardmove - m_forward->value * my );\n\t}\n}\n\n\n/*\n==============\nCL_CmdButtons\n==============\n*/\nvoid CL_CmdButtons( usercmd_t *cmd ) {\n\tint\t\ti;\n\n\t//\n\t// figure button bits\n\t// send a button bit even if the key was pressed and released in\n\t// less than a frame\n\t//\t\n\tfor (i = 0 ; i < 15 ; i++) {\n\t\tif ( in_buttons[i].active || in_buttons[i].wasPressed ) {\n\t\t\tcmd->buttons |= 1 << i;\n\t\t}\n\t\tin_buttons[i].wasPressed = qfalse;\n\t}\n\n\tif ( cls.keyCatchers ) {\n\t\tcmd->buttons |= BUTTON_TALK;\n\t}\n\n\t// allow the game to know if any key at all is\n\t// currently pressed, even if it isn't bound to anything\n\tif ( anykeydown && !cls.keyCatchers ) {\n\t\tcmd->buttons |= BUTTON_ANY;\n\t}\n}\n\n\n/*\n==============\nCL_FinishMove\n==============\n*/\nvoid CL_FinishMove( usercmd_t *cmd ) {\n\tint\t\ti;\n\n\t// copy the state that the cgame is currently sending\n\tcmd->weapon = cl.cgameUserCmdValue;\n\n\t// send the current server time so the amount of movement\n\t// can be determined without allowing cheating\n\tcmd->serverTime = cl.serverTime;\n\n\tfor (i=0 ; i<3 ; i++) {\n\t\tcmd->angles[i] = ANGLE2SHORT(cl.viewangles[i]);\n\t}\n}\n\n\n/*\n=================\nCL_CreateCmd\n=================\n*/\nusercmd_t CL_CreateCmd( void ) {\n\tusercmd_t\tcmd;\n\tvec3_t\t\toldAngles;\n\n\tVectorCopy( cl.viewangles, oldAngles );\n\n\t// keyboard angle adjustment\n\tCL_AdjustAngles ();\n\t\n\tCom_Memset( &cmd, 0, sizeof( cmd ) );\n\n\tCL_CmdButtons( &cmd );\n\n\t// get basic movement from keyboard\n\tCL_KeyMove( &cmd );\n\n\t// get basic movement from mouse\n\tCL_MouseMove( &cmd );\n\n\t// get basic movement from joystick\n\tCL_JoystickMove( &cmd );\n\n\t// check to make sure the angles haven't wrapped\n\tif ( cl.viewangles[PITCH] - oldAngles[PITCH] > 90 ) {\n\t\tcl.viewangles[PITCH] = oldAngles[PITCH] + 90;\n\t} else if ( oldAngles[PITCH] - cl.viewangles[PITCH] > 90 ) {\n\t\tcl.viewangles[PITCH] = oldAngles[PITCH] - 90;\n\t} \n\n\t// store out the final values\n\tCL_FinishMove( &cmd );\n\n\t// draw debug graphs of turning for mouse testing\n\tif ( cl_debugMove->integer ) {\n\t\tif ( cl_debugMove->integer == 1 ) {\n\t\t\tSCR_DebugGraph( fabs(cl.viewangles[YAW] - oldAngles[YAW]), 0 );\n\t\t}\n\t\tif ( cl_debugMove->integer == 2 ) {\n\t\t\tSCR_DebugGraph( fabs(cl.viewangles[PITCH] - oldAngles[PITCH]), 0 );\n\t\t}\n\t}\n\n\treturn cmd;\n}\n\n\n/*\n=================\nCL_CreateNewCommands\n\nCreate a new usercmd_t structure for this frame\n=================\n*/\nvoid CL_CreateNewCommands( void ) {\n\tusercmd_t\t*cmd;\n\tint\t\t\tcmdNum;\n\n\t// no need to create usercmds until we have a gamestate\n\tif ( cls.state < CA_PRIMED ) {\n\t\treturn;\n\t}\n\n\tframe_msec = com_frameTime - old_com_frameTime;\n\n\t// if running less than 5fps, truncate the extra time to prevent\n\t// unexpected moves after a hitch\n\tif ( frame_msec > 200 ) {\n\t\tframe_msec = 200;\n\t}\n\told_com_frameTime = com_frameTime;\n\n\n\t// generate a command for this frame\n\tcl.cmdNumber++;\n\tcmdNum = cl.cmdNumber & CMD_MASK;\n\tcl.cmds[cmdNum] = CL_CreateCmd ();\n\tcmd = &cl.cmds[cmdNum];\n}\n\n/*\n=================\nCL_ReadyToSendPacket\n\nReturns qfalse if we are over the maxpackets limit\nand should choke back the bandwidth a bit by not sending\na packet this frame.  All the commands will still get\ndelivered in the next packet, but saving a header and\ngetting more delta compression will reduce total bandwidth.\n=================\n*/\nqboolean CL_ReadyToSendPacket( void ) {\n\tint\t\toldPacketNum;\n\tint\t\tdelta;\n\n\t// don't send anything if playing back a demo\n\tif ( clc.demoplaying || cls.state == CA_CINEMATIC ) {\n\t\treturn qfalse;\n\t}\n\n\t// If we are downloading, we send no less than 50ms between packets\n\tif ( *clc.downloadTempName &&\n\t\tcls.realtime - clc.lastPacketSentTime < 50 ) {\n\t\treturn qfalse;\n\t}\n\n\t// if we don't have a valid gamestate yet, only send\n\t// one packet a second\n\tif ( cls.state != CA_ACTIVE && \n\t\tcls.state != CA_PRIMED && \n\t\t!*clc.downloadTempName &&\n\t\tcls.realtime - clc.lastPacketSentTime < 1000 ) {\n\t\treturn qfalse;\n\t}\n\n\t// send every frame for loopbacks\n\tif ( clc.netchan.remoteAddress.type == NA_LOOPBACK ) {\n\t\treturn qtrue;\n\t}\n\n\t// send every frame for LAN\n\tif ( Sys_IsLANAddress( clc.netchan.remoteAddress ) ) {\n\t\treturn qtrue;\n\t}\n\n\t// check for exceeding cl_maxpackets\n\tif ( cl_maxpackets->integer < 15 ) {\n\t\tCvar_Set( \"cl_maxpackets\", \"15\" );\n\t} else if ( cl_maxpackets->integer > 125 ) {\n\t\tCvar_Set( \"cl_maxpackets\", \"125\" );\n\t}\n\toldPacketNum = (clc.netchan.outgoingSequence - 1) & PACKET_MASK;\n\tdelta = cls.realtime -  cl.outPackets[ oldPacketNum ].p_realtime;\n\tif ( delta < 1000 / cl_maxpackets->integer ) {\n\t\t// the accumulated commands will go out in the next packet\n\t\treturn qfalse;\n\t}\n\n\treturn qtrue;\n}\n\n/*\n===================\nCL_WritePacket\n\nCreate and send the command packet to the server\nIncluding both the reliable commands and the usercmds\n\nDuring normal gameplay, a client packet will contain something like:\n\n4\tsequence number\n2\tqport\n4\tserverid\n4\tacknowledged sequence number\n4\tclc.serverCommandSequence\n<optional reliable commands>\n1\tclc_move or clc_moveNoDelta\n1\tcommand count\n<count * usercmds>\n\n===================\n*/\nvoid CL_WritePacket( void ) {\n\tmsg_t\t\tbuf;\n\tbyte\t\tdata[MAX_MSGLEN];\n\tint\t\t\ti, j;\n\tusercmd_t\t*cmd, *oldcmd;\n\tusercmd_t\tnullcmd;\n\tint\t\t\tpacketNum;\n\tint\t\t\toldPacketNum;\n\tint\t\t\tcount, key;\n\n\t// don't send anything if playing back a demo\n\tif ( clc.demoplaying || cls.state == CA_CINEMATIC ) {\n\t\treturn;\n\t}\n\n\tCom_Memset( &nullcmd, 0, sizeof(nullcmd) );\n\toldcmd = &nullcmd;\n\n\tMSG_Init( &buf, data, sizeof(data) );\n\n\tMSG_Bitstream( &buf );\n\t// write the current serverId so the server\n\t// can tell if this is from the current gameState\n\tMSG_WriteLong( &buf, cl.serverId );\n\n\t// write the last message we received, which can\n\t// be used for delta compression, and is also used\n\t// to tell if we dropped a gamestate\n\tMSG_WriteLong( &buf, clc.serverMessageSequence );\n\n\t// write the last reliable message we received\n\tMSG_WriteLong( &buf, clc.serverCommandSequence );\n\n\t// write any unacknowledged clientCommands\n\tfor ( i = clc.reliableAcknowledge + 1 ; i <= clc.reliableSequence ; i++ ) {\n\t\tMSG_WriteByte( &buf, clc_clientCommand );\n\t\tMSG_WriteLong( &buf, i );\n\t\tMSG_WriteString( &buf, clc.reliableCommands[ i & (MAX_RELIABLE_COMMANDS-1) ] );\n\t}\n\n\t// we want to send all the usercmds that were generated in the last\n\t// few packet, so even if a couple packets are dropped in a row,\n\t// all the cmds will make it to the server\n\tif ( cl_packetdup->integer < 0 ) {\n\t\tCvar_Set( \"cl_packetdup\", \"0\" );\n\t} else if ( cl_packetdup->integer > 5 ) {\n\t\tCvar_Set( \"cl_packetdup\", \"5\" );\n\t}\n\toldPacketNum = (clc.netchan.outgoingSequence - 1 - cl_packetdup->integer) & PACKET_MASK;\n\tcount = cl.cmdNumber - cl.outPackets[ oldPacketNum ].p_cmdNumber;\n\tif ( count > MAX_PACKET_USERCMDS ) {\n\t\tcount = MAX_PACKET_USERCMDS;\n\t\tCom_Printf(\"MAX_PACKET_USERCMDS\\n\");\n\t}\n\tif ( count >= 1 ) {\n\t\tif ( cl_showSend->integer ) {\n\t\t\tCom_Printf( \"(%i)\", count );\n\t\t}\n\n\t\t// begin a client move command\n\t\tif ( cl_nodelta->integer || !cl.snap.valid || clc.demowaiting\n\t\t\t|| clc.serverMessageSequence != cl.snap.messageNum ) {\n\t\t\tMSG_WriteByte (&buf, clc_moveNoDelta);\n\t\t} else {\n\t\t\tMSG_WriteByte (&buf, clc_move);\n\t\t}\n\n\t\t// write the command count\n\t\tMSG_WriteByte( &buf, count );\n\n\t\t// use the checksum feed in the key\n\t\tkey = clc.checksumFeed;\n\t\t// also use the message acknowledge\n\t\tkey ^= clc.serverMessageSequence;\n\t\t// also use the last acknowledged server command in the key\n\t\tkey ^= Com_HashKey(clc.serverCommands[ clc.serverCommandSequence & (MAX_RELIABLE_COMMANDS-1) ], 32);\n\n\t\t// write all the commands, including the predicted command\n\t\tfor ( i = 0 ; i < count ; i++ ) {\n\t\t\tj = (cl.cmdNumber - count + i + 1) & CMD_MASK;\n\t\t\tcmd = &cl.cmds[j];\n\t\t\tMSG_WriteDeltaUsercmdKey (&buf, key, oldcmd, cmd);\n\t\t\toldcmd = cmd;\n\t\t}\n\t}\n\n\t//\n\t// deliver the message\n\t//\n\tpacketNum = clc.netchan.outgoingSequence & PACKET_MASK;\n\tcl.outPackets[ packetNum ].p_realtime = cls.realtime;\n\tcl.outPackets[ packetNum ].p_serverTime = oldcmd->serverTime;\n\tcl.outPackets[ packetNum ].p_cmdNumber = cl.cmdNumber;\n\tclc.lastPacketSentTime = cls.realtime;\n\n\tif ( cl_showSend->integer ) {\n\t\tCom_Printf( \"%i \", buf.cursize );\n\t}\n\n\tCL_Netchan_Transmit (&clc.netchan, &buf);\t\n\n\t// clients never really should have messages large enough\n\t// to fragment, but in case they do, fire them all off\n\t// at once\n\t// TTimo: this causes a packet burst, which is bad karma for winsock\n\t// added a WARNING message, we'll see if there are legit situations where this happens\n\twhile ( clc.netchan.unsentFragments ) {\n\t\tCom_DPrintf( \"WARNING: #462 unsent fragments (not supposed to happen!)\\n\" );\n\t\tCL_Netchan_TransmitNextFragment( &clc.netchan );\n\t}\n}\n\n/*\n=================\nCL_SendCmd\n\nCalled every frame to builds and sends a command packet to the server.\n=================\n*/\nvoid CL_SendCmd( void ) {\n\t// don't send any message if not connected\n\tif ( cls.state < CA_CONNECTED ) {\n\t\treturn;\n\t}\n\n\t// don't send commands if paused\n\tif ( com_sv_running->integer && sv_paused->integer && cl_paused->integer ) {\n\t\treturn;\n\t}\n\n\t// we create commands even if a demo is playing,\n\tCL_CreateNewCommands();\n\n\t// don't send a packet if the last packet was sent too recently\n\tif ( !CL_ReadyToSendPacket() ) {\n\t\tif ( cl_showSend->integer ) {\n\t\t\tCom_Printf( \". \" );\n\t\t}\n\t\treturn;\n\t}\n\n\tCL_WritePacket();\n}\n\n/*\n============\nCL_InitInput\n============\n*/\nvoid CL_InitInput( void ) {\n\tCmd_AddCommand (\"centerview\",IN_CenterView);\n\n\tCmd_AddCommand (\"+moveup\",IN_UpDown);\n\tCmd_AddCommand (\"-moveup\",IN_UpUp);\n\tCmd_AddCommand (\"+movedown\",IN_DownDown);\n\tCmd_AddCommand (\"-movedown\",IN_DownUp);\n\tCmd_AddCommand (\"+left\",IN_LeftDown);\n\tCmd_AddCommand (\"-left\",IN_LeftUp);\n\tCmd_AddCommand (\"+right\",IN_RightDown);\n\tCmd_AddCommand (\"-right\",IN_RightUp);\n\tCmd_AddCommand (\"+forward\",IN_ForwardDown);\n\tCmd_AddCommand (\"-forward\",IN_ForwardUp);\n\tCmd_AddCommand (\"+back\",IN_BackDown);\n\tCmd_AddCommand (\"-back\",IN_BackUp);\n\tCmd_AddCommand (\"+lookup\", IN_LookupDown);\n\tCmd_AddCommand (\"-lookup\", IN_LookupUp);\n\tCmd_AddCommand (\"+lookdown\", IN_LookdownDown);\n\tCmd_AddCommand (\"-lookdown\", IN_LookdownUp);\n\tCmd_AddCommand (\"+strafe\", IN_StrafeDown);\n\tCmd_AddCommand (\"-strafe\", IN_StrafeUp);\n\tCmd_AddCommand (\"+moveleft\", IN_MoveleftDown);\n\tCmd_AddCommand (\"-moveleft\", IN_MoveleftUp);\n\tCmd_AddCommand (\"+moveright\", IN_MoverightDown);\n\tCmd_AddCommand (\"-moveright\", IN_MoverightUp);\n\tCmd_AddCommand (\"+speed\", IN_SpeedDown);\n\tCmd_AddCommand (\"-speed\", IN_SpeedUp);\n\tCmd_AddCommand (\"+attack\", IN_Button0Down);\n\tCmd_AddCommand (\"-attack\", IN_Button0Up);\n\tCmd_AddCommand (\"+button0\", IN_Button0Down);\n\tCmd_AddCommand (\"-button0\", IN_Button0Up);\n\tCmd_AddCommand (\"+button1\", IN_Button1Down);\n\tCmd_AddCommand (\"-button1\", IN_Button1Up);\n\tCmd_AddCommand (\"+button2\", IN_Button2Down);\n\tCmd_AddCommand (\"-button2\", IN_Button2Up);\n\tCmd_AddCommand (\"+button3\", IN_Button3Down);\n\tCmd_AddCommand (\"-button3\", IN_Button3Up);\n\tCmd_AddCommand (\"+button4\", IN_Button4Down);\n\tCmd_AddCommand (\"-button4\", IN_Button4Up);\n\tCmd_AddCommand (\"+button5\", IN_Button5Down);\n\tCmd_AddCommand (\"-button5\", IN_Button5Up);\n\tCmd_AddCommand (\"+button6\", IN_Button6Down);\n\tCmd_AddCommand (\"-button6\", IN_Button6Up);\n\tCmd_AddCommand (\"+button7\", IN_Button7Down);\n\tCmd_AddCommand (\"-button7\", IN_Button7Up);\n\tCmd_AddCommand (\"+button8\", IN_Button8Down);\n\tCmd_AddCommand (\"-button8\", IN_Button8Up);\n\tCmd_AddCommand (\"+button9\", IN_Button9Down);\n\tCmd_AddCommand (\"-button9\", IN_Button9Up);\n\tCmd_AddCommand (\"+button10\", IN_Button10Down);\n\tCmd_AddCommand (\"-button10\", IN_Button10Up);\n\tCmd_AddCommand (\"+button11\", IN_Button11Down);\n\tCmd_AddCommand (\"-button11\", IN_Button11Up);\n\tCmd_AddCommand (\"+button12\", IN_Button12Down);\n\tCmd_AddCommand (\"-button12\", IN_Button12Up);\n\tCmd_AddCommand (\"+button13\", IN_Button13Down);\n\tCmd_AddCommand (\"-button13\", IN_Button13Up);\n\tCmd_AddCommand (\"+button14\", IN_Button14Down);\n\tCmd_AddCommand (\"-button14\", IN_Button14Up);\n\tCmd_AddCommand (\"+mlook\", IN_MLookDown);\n\tCmd_AddCommand (\"-mlook\", IN_MLookUp);\n\n\tcl_nodelta = Cvar_Get (\"cl_nodelta\", \"0\", 0);\n\tcl_debugMove = Cvar_Get (\"cl_debugMove\", \"0\", 0);\n}\n"
  },
  {
    "path": "src/engine/client/cl_keys.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n#include \"client.h\"\n\n/*\n\nkey up events are sent even if in console mode\n\n*/\n\nfield_t\thistoryEditLines[COMMAND_HISTORY];\n\nint\t\t\tnextHistoryLine;\t\t// the last line in the history buffer, not masked\nint\t\t\thistoryLine;\t// the line being displayed from history buffer\n\t\t\t\t\t\t\t// will be <= nextHistoryLine\n\nfield_t\t\tg_consoleField;\nfield_t\t\tchatField;\nqboolean\tchat_team;\n\nint\t\t\tchat_playerNum;\n\n\nqboolean\tkey_overstrikeMode;\n\nqboolean\tanykeydown;\nqkey_t\t\tkeys[MAX_KEYS];\n\n\ntypedef struct {\n\tchar\t*name;\n\tint\t\tkeynum;\n} keyname_t;\n\n\n// names not in this list can either be lowercase ascii, or '0xnn' hex sequences\nkeyname_t keynames[] =\n{\n\t{\"TAB\", K_TAB},\n\t{\"ENTER\", K_ENTER},\n\t{\"ESCAPE\", K_ESCAPE},\n\t{\"SPACE\", K_SPACE},\n\t{\"BACKSPACE\", K_BACKSPACE},\n\t{\"UPARROW\", K_UPARROW},\n\t{\"DOWNARROW\", K_DOWNARROW},\n\t{\"LEFTARROW\", K_LEFTARROW},\n\t{\"RIGHTARROW\", K_RIGHTARROW},\n\n\t{\"ALT\", K_ALT},\n\t{\"CTRL\", K_CTRL},\n\t{\"SHIFT\", K_SHIFT},\n\n\t{\"COMMAND\", K_COMMAND},\n\n\t{\"CAPSLOCK\", K_CAPSLOCK},\n\n\t\n\t{\"F1\", K_F1},\n\t{\"F2\", K_F2},\n\t{\"F3\", K_F3},\n\t{\"F4\", K_F4},\n\t{\"F5\", K_F5},\n\t{\"F6\", K_F6},\n\t{\"F7\", K_F7},\n\t{\"F8\", K_F8},\n\t{\"F9\", K_F9},\n\t{\"F10\", K_F10},\n\t{\"F11\", K_F11},\n\t{\"F12\", K_F12},\n\n\t{\"INS\", K_INS},\n\t{\"DEL\", K_DEL},\n\t{\"PGDN\", K_PGDN},\n\t{\"PGUP\", K_PGUP},\n\t{\"HOME\", K_HOME},\n\t{\"END\", K_END},\n\n\t{\"MOUSE1\", K_MOUSE1},\n\t{\"MOUSE2\", K_MOUSE2},\n\t{\"MOUSE3\", K_MOUSE3},\n\t{\"MOUSE4\", K_MOUSE4},\n\t{\"MOUSE5\", K_MOUSE5},\n\n\t{\"MWHEELUP\",\tK_MWHEELUP },\n\t{\"MWHEELDOWN\",\tK_MWHEELDOWN },\n\n\t{\"JOY1\", K_JOY1},\n\t{\"JOY2\", K_JOY2},\n\t{\"JOY3\", K_JOY3},\n\t{\"JOY4\", K_JOY4},\n\t{\"JOY5\", K_JOY5},\n\t{\"JOY6\", K_JOY6},\n\t{\"JOY7\", K_JOY7},\n\t{\"JOY8\", K_JOY8},\n\t{\"JOY9\", K_JOY9},\n\t{\"JOY10\", K_JOY10},\n\t{\"JOY11\", K_JOY11},\n\t{\"JOY12\", K_JOY12},\n\t{\"JOY13\", K_JOY13},\n\t{\"JOY14\", K_JOY14},\n\t{\"JOY15\", K_JOY15},\n\t{\"JOY16\", K_JOY16},\n\t{\"JOY17\", K_JOY17},\n\t{\"JOY18\", K_JOY18},\n\t{\"JOY19\", K_JOY19},\n\t{\"JOY20\", K_JOY20},\n\t{\"JOY21\", K_JOY21},\n\t{\"JOY22\", K_JOY22},\n\t{\"JOY23\", K_JOY23},\n\t{\"JOY24\", K_JOY24},\n\t{\"JOY25\", K_JOY25},\n\t{\"JOY26\", K_JOY26},\n\t{\"JOY27\", K_JOY27},\n\t{\"JOY28\", K_JOY28},\n\t{\"JOY29\", K_JOY29},\n\t{\"JOY30\", K_JOY30},\n\t{\"JOY31\", K_JOY31},\n\t{\"JOY32\", K_JOY32},\n\n\t{\"AUX1\", K_AUX1},\n\t{\"AUX2\", K_AUX2},\n\t{\"AUX3\", K_AUX3},\n\t{\"AUX4\", K_AUX4},\n\t{\"AUX5\", K_AUX5},\n\t{\"AUX6\", K_AUX6},\n\t{\"AUX7\", K_AUX7},\n\t{\"AUX8\", K_AUX8},\n\t{\"AUX9\", K_AUX9},\n\t{\"AUX10\", K_AUX10},\n\t{\"AUX11\", K_AUX11},\n\t{\"AUX12\", K_AUX12},\n\t{\"AUX13\", K_AUX13},\n\t{\"AUX14\", K_AUX14},\n\t{\"AUX15\", K_AUX15},\n\t{\"AUX16\", K_AUX16},\n\n\t{\"KP_HOME\",\t\t\tK_KP_HOME },\n\t{\"KP_UPARROW\",\t\tK_KP_UPARROW },\n\t{\"KP_PGUP\",\t\t\tK_KP_PGUP },\n\t{\"KP_LEFTARROW\",\tK_KP_LEFTARROW },\n\t{\"KP_5\",\t\t\tK_KP_5 },\n\t{\"KP_RIGHTARROW\",\tK_KP_RIGHTARROW },\n\t{\"KP_END\",\t\t\tK_KP_END },\n\t{\"KP_DOWNARROW\",\tK_KP_DOWNARROW },\n\t{\"KP_PGDN\",\t\t\tK_KP_PGDN },\n\t{\"KP_ENTER\",\t\tK_KP_ENTER },\n\t{\"KP_INS\",\t\t\tK_KP_INS },\n\t{\"KP_DEL\",\t\t\tK_KP_DEL },\n\t{\"KP_SLASH\",\t\tK_KP_SLASH },\n\t{\"KP_MINUS\",\t\tK_KP_MINUS },\n\t{\"KP_PLUS\",\t\t\tK_KP_PLUS },\n\t{\"KP_NUMLOCK\",\t\tK_KP_NUMLOCK },\n\t{\"KP_STAR\",\t\t\tK_KP_STAR },\n\t{\"KP_EQUALS\",\t\tK_KP_EQUALS },\n\n\t{\"PAUSE\", K_PAUSE},\n\t\n\t{\"SEMICOLON\", ';'},\t// because a raw semicolon seperates commands\n\n\t{NULL,0}\n};\n\n/*\n=============================================================================\n\nEDIT FIELDS\n\n=============================================================================\n*/\n\n\n/*\n===================\nField_Draw\n\nHandles horizontal scrolling and cursor blinking\nx, y, amd width are in pixels\n===================\n*/\nvoid Field_VariableSizeDraw( field_t *edit, int x, int y, int width, int size, qboolean showCursor ) {\n\tint\t\tlen;\n\tint\t\tdrawLen;\n\tint\t\tprestep;\n\tint\t\tcursorChar;\n\tchar\tstr[MAX_STRING_CHARS];\n\tint\t\ti;\n\n\tdrawLen = edit->widthInChars;\n\tlen = (int)strlen( edit->buffer ) + 1;\n\n\t// guarantee that cursor will be visible\n\tif ( len <= drawLen ) {\n\t\tprestep = 0;\n\t} else {\n\t\tif ( edit->scroll + drawLen > len ) {\n\t\t\tedit->scroll = len - drawLen;\n\t\t\tif ( edit->scroll < 0 ) {\n\t\t\t\tedit->scroll = 0;\n\t\t\t}\n\t\t}\n\t\tprestep = edit->scroll;\n\n/*\n\t\tif ( edit->cursor < len - drawLen ) {\n\t\t\tprestep = edit->cursor;\t// cursor at start\n\t\t} else {\n\t\t\tprestep = len - drawLen;\n\t\t}\n*/\n\t}\n\n\tif ( prestep + drawLen > len ) {\n\t\tdrawLen = len - prestep;\n\t}\n\n\t// extract <drawLen> characters from the field at <prestep>\n\tif ( drawLen >= MAX_STRING_CHARS ) {\n\t\tCom_Error( ERR_DROP, \"drawLen >= MAX_STRING_CHARS\" );\n\t}\n\n\tCom_Memcpy( str, edit->buffer + prestep, drawLen );\n\tstr[ drawLen ] = 0;\n\n\t// draw it\n\tif ( size == SMALLCHAR_WIDTH ) {\n\t\tfloat\tcolor[4];\n\n\t\tcolor[0] = color[1] = color[2] = color[3] = 1.0;\n\t\tSCR_DrawSmallStringExt( x, y, str, color, qfalse );\n\t} else {\n\t\t// draw big string with drop shadow\n\t\tSCR_DrawBigString( x, y, str, 1.0 );\n\t}\n\n\t// draw the cursor\n\tif ( !showCursor ) {\n\t\treturn;\n\t}\n\n\tif ( (int)( cls.realtime >> 8 ) & 1 ) {\n\t\treturn;\t\t// off blink\n\t}\n\n\tif ( key_overstrikeMode ) {\n\t\tcursorChar = 11;\n\t} else {\n\t\tcursorChar = 10;\n\t}\n\n\ti = drawLen - ( Q_PrintStrlen( str ) + 1 );\n\n\tif ( size == SMALLCHAR_WIDTH ) {\n\t\tSCR_DrawSmallChar( x + ( edit->cursor - prestep - i ) * size, y, cursorChar );\n\t} else {\n\t\tstr[0] = cursorChar;\n\t\tstr[1] = 0;\n\t\tSCR_DrawBigString( x + ( edit->cursor - prestep - i ) * size, y, str, 1.0 );\n\n\t}\n}\n\nvoid Field_Draw( field_t *edit, int x, int y, int width, qboolean showCursor ) \n{\n\tField_VariableSizeDraw( edit, x, y, width, SMALLCHAR_WIDTH, showCursor );\n}\n\nvoid Field_BigDraw( field_t *edit, int x, int y, int width, qboolean showCursor ) \n{\n\tField_VariableSizeDraw( edit, x, y, width, BIGCHAR_WIDTH, showCursor );\n}\n\n/*\n================\nField_Paste\n================\n*/\nvoid Field_Paste( field_t *edit ) {\n\tchar\t*cbd;\n\tint\t\tpasteLen, i;\n\n\tcbd = Sys_GetClipboardData();\n\n\tif ( !cbd ) {\n\t\treturn;\n\t}\n\n\t// send as if typed, so insert / overstrike works properly\n\tpasteLen = (int)strlen( cbd );\n\tfor ( i = 0 ; i < pasteLen ; i++ ) {\n\t\tField_CharEvent( edit, cbd[i] );\n\t}\n\n\tZ_Free( cbd );\n}\n\n/*\n=================\nField_KeyDownEvent\n\nPerforms the basic line editing functions for the console,\nin-game talk, and menu fields\n\nKey events are used for non-printable characters, others are gotten from char events.\n=================\n*/\nvoid Field_KeyDownEvent( field_t *edit, int key ) {\n\tint\t\tlen;\n\n\t// shift-insert is paste\n\tif ( ( ( key == K_INS ) || ( key == K_KP_INS ) ) && keys[K_SHIFT].down ) {\n\t\tField_Paste( edit );\n\t\treturn;\n\t}\n\n\tlen = (int)strlen( edit->buffer );\n\n\tif ( key == K_DEL ) {\n\t\tif ( edit->cursor < len ) {\n\t\t\tmemmove( edit->buffer + edit->cursor, \n\t\t\t\tedit->buffer + edit->cursor + 1, len - edit->cursor );\n\t\t}\n\t\treturn;\n\t}\n\n\tif ( key == K_RIGHTARROW ) \n\t{\n\t\tif ( edit->cursor < len ) {\n\t\t\tedit->cursor++;\n\t\t}\n\n\t\tif ( edit->cursor >= edit->scroll + edit->widthInChars && edit->cursor <= len )\n\t\t{\n\t\t\tedit->scroll++;\n\t\t}\n\t\treturn;\n\t}\n\n\tif ( key == K_LEFTARROW ) \n\t{\n\t\tif ( edit->cursor > 0 ) {\n\t\t\tedit->cursor--;\n\t\t}\n\t\tif ( edit->cursor < edit->scroll )\n\t\t{\n\t\t\tedit->scroll--;\n\t\t}\n\t\treturn;\n\t}\n\n\tif ( key == K_HOME || ( tolower(key) == 'a' && keys[K_CTRL].down ) ) {\n\t\tedit->cursor = 0;\n\t\treturn;\n\t}\n\n\tif ( key == K_END || ( tolower(key) == 'e' && keys[K_CTRL].down ) ) {\n\t\tedit->cursor = len;\n\t\treturn;\n\t}\n\n\tif ( key == K_INS ) {\n\t\tkey_overstrikeMode = (qboolean) !key_overstrikeMode;\n\t\treturn;\n\t}\n}\n\n/*\n==================\nField_CharEvent\n==================\n*/\nvoid Field_CharEvent( field_t *edit, int ch ) {\n\tint\t\tlen;\n\n\tif ( ch == 'v' - 'a' + 1 ) {\t// ctrl-v is paste\n\t\tField_Paste( edit );\n\t\treturn;\n\t}\n\n\tif ( ch == 'c' - 'a' + 1 ) {\t// ctrl-c clears the field\n\t\tField_Clear( edit );\n\t\treturn;\n\t}\n\n\tlen = (int)strlen( edit->buffer );\n\n\tif ( ch == 'h' - 'a' + 1 )\t{\t// ctrl-h is backspace\n\t\tif ( edit->cursor > 0 ) {\n\t\t\tmemmove( edit->buffer + edit->cursor - 1, \n\t\t\t\tedit->buffer + edit->cursor, len + 1 - edit->cursor );\n\t\t\tedit->cursor--;\n\t\t\tif ( edit->cursor < edit->scroll )\n\t\t\t{\n\t\t\t\tedit->scroll--;\n\t\t\t}\n\t\t}\n\t\treturn;\n\t}\n\n\tif ( ch == 'a' - 'a' + 1 ) {\t// ctrl-a is home\n\t\tedit->cursor = 0;\n\t\tedit->scroll = 0;\n\t\treturn;\n\t}\n\n\tif ( ch == 'e' - 'a' + 1 ) {\t// ctrl-e is end\n\t\tedit->cursor = len;\n\t\tedit->scroll = edit->cursor - edit->widthInChars;\n\t\treturn;\n\t}\n\n\t//\n\t// ignore any other non printable chars\n\t//\n\tif ( ch < 32 ) {\n\t\treturn;\n\t}\n\n\tif ( key_overstrikeMode ) {\t\n\t\tif ( edit->cursor == MAX_EDIT_LINE - 1 )\n\t\t\treturn;\n\t\tedit->buffer[edit->cursor] = ch;\n\t\tedit->cursor++;\n\t} else {\t// insert mode\n\t\tif ( len == MAX_EDIT_LINE - 1 ) {\n\t\t\treturn; // all full\n\t\t}\n\t\tmemmove( edit->buffer + edit->cursor + 1, \n\t\t\tedit->buffer + edit->cursor, len + 1 - edit->cursor );\n\t\tedit->buffer[edit->cursor] = ch;\n\t\tedit->cursor++;\n\t}\n\n\n\tif ( edit->cursor >= edit->widthInChars ) {\n\t\tedit->scroll++;\n\t}\n\n\tif ( edit->cursor == len + 1) {\n\t\tedit->buffer[edit->cursor] = 0;\n\t}\n}\n\n/*\n=============================================================================\n\nCONSOLE LINE EDITING\n\n==============================================================================\n*/\n\n/*\n====================\nConsole_Key\n\nHandles history and console scrollback\n====================\n*/\nvoid Console_Key (int key) {\n\t// ctrl-L clears screen\n\tif ( key == 'l' && keys[K_CTRL].down ) {\n\t\tCbuf_AddText (\"clear\\n\");\n\t\treturn;\n\t}\n\n\t// enter finishes the line\n\tif ( key == K_ENTER || key == K_KP_ENTER ) {\n\t\t// if not in the game explicitly prepent a slash if needed\n\t\tif ( cls.state != CA_ACTIVE && g_consoleField.buffer[0] != '\\\\' \n\t\t\t&& g_consoleField.buffer[0] != '/' ) {\n\t\t\tchar\ttemp[MAX_STRING_CHARS];\n\n\t\t\tQ_strncpyz( temp, g_consoleField.buffer, sizeof( temp ) );\n\t\t\tCom_sprintf( g_consoleField.buffer, sizeof( g_consoleField.buffer ), \"\\\\%s\", temp );\n\t\t\tg_consoleField.cursor++;\n\t\t}\n\n\t\tCom_Printf ( \"]%s\\n\", g_consoleField.buffer );\n\n\t\t// leading slash is an explicit command\n\t\tif ( g_consoleField.buffer[0] == '\\\\' || g_consoleField.buffer[0] == '/' ) {\n\t\t\tCbuf_AddText( g_consoleField.buffer+1 );\t// valid command\n\t\t\tCbuf_AddText (\"\\n\");\n\t\t} else {\n\t\t\t// other text will be chat messages\n\t\t\tif ( !g_consoleField.buffer[0] ) {\n\t\t\t\treturn;\t// empty lines just scroll the console without adding to history\n\t\t\t} else {\n\t\t\t\tCbuf_AddText (\"cmd say \");\n\t\t\t\tCbuf_AddText( g_consoleField.buffer );\n\t\t\t\tCbuf_AddText (\"\\n\");\n\t\t\t}\n\t\t}\n\n\t\t// copy line to history buffer\n\t\thistoryEditLines[nextHistoryLine % COMMAND_HISTORY] = g_consoleField;\n\t\tnextHistoryLine++;\n\t\thistoryLine = nextHistoryLine;\n\n\t\tField_Clear( &g_consoleField );\n\n\t\tg_consoleField.widthInChars = g_console_field_width;\n\n\t\tif ( cls.state == CA_DISCONNECTED ) {\n\t\t\tSCR_UpdateScreen ();\t// force an update, because the command\n\t\t}\t\t\t\t\t\t\t// may take some time\n\t\treturn;\n\t}\n\n\t// command completion\n\n\tif (key == K_TAB) {\n\t\tField_CompleteCommand(&g_consoleField);\n\t\treturn;\n\t}\n\n\t// command history (ctrl-p ctrl-n for unix style)\n\n\tif ( (key == K_MWHEELUP && keys[K_SHIFT].down) || ( key == K_UPARROW ) || ( key == K_KP_UPARROW ) ||\n\t\t ( ( tolower(key) == 'p' ) && keys[K_CTRL].down ) ) {\n\t\tif ( nextHistoryLine - historyLine < COMMAND_HISTORY \n\t\t\t&& historyLine > 0 ) {\n\t\t\thistoryLine--;\n\t\t}\n\t\tg_consoleField = historyEditLines[ historyLine % COMMAND_HISTORY ];\n\t\treturn;\n\t}\n\n\tif ( (key == K_MWHEELDOWN && keys[K_SHIFT].down) || ( key == K_DOWNARROW ) || ( key == K_KP_DOWNARROW ) ||\n\t\t ( ( tolower(key) == 'n' ) && keys[K_CTRL].down ) ) {\n\t\tif (historyLine == nextHistoryLine)\n\t\t\treturn;\n\t\thistoryLine++;\n\t\tg_consoleField = historyEditLines[ historyLine % COMMAND_HISTORY ];\n\t\treturn;\n\t}\n\n\t// console scrolling\n\tif ( key == K_PGUP ) {\n\t\tCon_PageUp();\n\t\treturn;\n\t}\n\n\tif ( key == K_PGDN) {\n\t\tCon_PageDown();\n\t\treturn;\n\t}\n\n\tif ( key == K_MWHEELUP) {\t//----(SA)\tadded some mousewheel functionality to the console\n\t\tCon_PageUp();\n\t\tif(keys[K_CTRL].down) {\t// hold <ctrl> to accelerate scrolling\n\t\t\tCon_PageUp();\n\t\t\tCon_PageUp();\n\t\t}\n\t\treturn;\n\t}\n\n\tif ( key == K_MWHEELDOWN) {\t//----(SA)\tadded some mousewheel functionality to the console\n\t\tCon_PageDown();\n\t\tif(keys[K_CTRL].down) {\t// hold <ctrl> to accelerate scrolling\n\t\t\tCon_PageDown();\n\t\t\tCon_PageDown();\n\t\t}\n\t\treturn;\n\t}\n\n\t// ctrl-home = top of console\n\tif ( key == K_HOME && keys[K_CTRL].down ) {\n\t\tCon_Top();\n\t\treturn;\n\t}\n\n\t// ctrl-end = bottom of console\n\tif ( key == K_END && keys[K_CTRL].down ) {\n\t\tCon_Bottom();\n\t\treturn;\n\t}\n\n\t// pass to the normal editline routine\n\tField_KeyDownEvent( &g_consoleField, key );\n}\n\n//============================================================================\n\n\n/*\n================\nMessage_Key\n\nIn game talk message\n================\n*/\nvoid Message_Key( int key ) {\n\n\tchar\tbuffer[MAX_STRING_CHARS];\n\n\n\tif (key == K_ESCAPE) {\n\t\tcls.keyCatchers &= ~KEYCATCH_MESSAGE;\n\t\tField_Clear( &chatField );\n\t\treturn;\n\t}\n\n\tif ( key == K_ENTER || key == K_KP_ENTER )\n\t{\n\t\tif ( chatField.buffer[0] && cls.state == CA_ACTIVE ) {\n\t\t\tif (chat_playerNum != -1 )\n\n\t\t\t\tCom_sprintf( buffer, sizeof( buffer ), \"tell %i \\\"%s\\\"\\n\", chat_playerNum, chatField.buffer );\n\n\t\t\telse if (chat_team)\n\n\t\t\t\tCom_sprintf( buffer, sizeof( buffer ), \"say_team \\\"%s\\\"\\n\", chatField.buffer );\n\t\t\telse\n\t\t\t\tCom_sprintf( buffer, sizeof( buffer ), \"say \\\"%s\\\"\\n\", chatField.buffer );\n\n\n\n\t\t\tCL_AddReliableCommand( buffer );\n\t\t}\n\t\tcls.keyCatchers &= ~KEYCATCH_MESSAGE;\n\t\tField_Clear( &chatField );\n\t\treturn;\n\t}\n\n\tField_KeyDownEvent( &chatField, key );\n}\n\n//============================================================================\n\n\nqboolean Key_GetOverstrikeMode( void ) {\n\treturn key_overstrikeMode;\n}\n\n\nvoid Key_SetOverstrikeMode( qboolean state ) {\n\tkey_overstrikeMode = state;\n}\n\n\n/*\n===================\nKey_IsDown\n===================\n*/\nqboolean Key_IsDown( int keynum ) {\n\tif ( keynum == -1 ) {\n\t\treturn qfalse;\n\t}\n\n\treturn keys[keynum].down;\n}\n\n\n/*\n===================\nKey_StringToKeynum\n\nReturns a key number to be used to index keys[] by looking at\nthe given string.  Single ascii characters return themselves, while\nthe K_* names are matched up.\n\n0x11 will be interpreted as raw hex, which will allow new controlers\n\nto be configured even if they don't have defined names.\n===================\n*/\nint Key_StringToKeynum( char *str ) {\n\tkeyname_t\t*kn;\n\t\n\tif ( !str || !str[0] ) {\n\t\treturn -1;\n\t}\n\tif ( !str[1] ) {\n\t\treturn str[0];\n\t}\n\n\t// check for hex code\n\tif ( str[0] == '0' && str[1] == 'x' && (int)strlen( str ) == 4) {\n\t\tint\t\tn1, n2;\n\t\t\n\t\tn1 = str[2];\n\t\tif ( n1 >= '0' && n1 <= '9' ) {\n\t\t\tn1 -= '0';\n\t\t} else if ( n1 >= 'a' && n1 <= 'f' ) {\n\t\t\tn1 = n1 - 'a' + 10;\n\t\t} else {\n\t\t\tn1 = 0;\n\t\t}\n\n\t\tn2 = str[3];\n\t\tif ( n2 >= '0' && n2 <= '9' ) {\n\t\t\tn2 -= '0';\n\t\t} else if ( n2 >= 'a' && n2 <= 'f' ) {\n\t\t\tn2 = n2 - 'a' + 10;\n\t\t} else {\n\t\t\tn2 = 0;\n\t\t}\n\n\t\treturn n1 * 16 + n2;\n\t}\n\n\t// scan for a text match\n\tfor ( kn=keynames ; kn->name ; kn++ ) {\n\t\tif ( !Q_stricmp( str,kn->name ) )\n\t\t\treturn kn->keynum;\n\t}\n\n\treturn -1;\n}\n\n/*\n===================\nKey_KeynumToString\n\nReturns a string (either a single ascii char, a K_* name, or a 0x11 hex string) for the\ngiven keynum.\n===================\n*/\nchar *Key_KeynumToString( int keynum ) {\n\tkeyname_t\t*kn;\t\n\tstatic\tchar\ttinystr[5];\n\tint\t\t\ti, j;\n\n\tif ( keynum == -1 ) {\n\t\treturn \"<KEY NOT FOUND>\";\n\t}\n\n\tif ( keynum < 0 || keynum > 255 ) {\n\t\treturn \"<OUT OF RANGE>\";\n\t}\n\n\t// check for printable ascii (don't use quote)\n\tif ( keynum > 32 && keynum < 127 && keynum != '\"' && keynum != ';' ) {\n\t\ttinystr[0] = keynum;\n\t\ttinystr[1] = 0;\n\t\treturn tinystr;\n\t}\n\n\t// check for a key string\n\tfor ( kn=keynames ; kn->name ; kn++ ) {\n\t\tif (keynum == kn->keynum) {\n\t\t\treturn kn->name;\n\t\t}\n\t}\n\n\t// make a hex string\n\ti = keynum >> 4;\n\tj = keynum & 15;\n\n\ttinystr[0] = '0';\n\ttinystr[1] = 'x';\n\ttinystr[2] = i > 9 ? i - 10 + 'a' : i + '0';\n\ttinystr[3] = j > 9 ? j - 10 + 'a' : j + '0';\n\ttinystr[4] = 0;\n\n\treturn tinystr;\n}\n\n\n/*\n===================\nKey_SetBinding\n===================\n*/\nvoid Key_SetBinding( int keynum, const char *binding ) {\n\tif ( keynum == -1 ) {\n\t\treturn;\n\t}\n\n\t// free old bindings\n\tif ( keys[ keynum ].binding ) {\n\t\tZ_Free( keys[ keynum ].binding );\n\t}\n\t\t\n\t// allocate memory for new binding\n\tkeys[keynum].binding = CopyString( binding );\n\n\t// consider this like modifying an archived cvar, so the\n\t// file write will be triggered at the next oportunity\n\tcvar_modifiedFlags |= CVAR_ARCHIVE;\n}\n\n\n/*\n===================\nKey_GetBinding\n===================\n*/\nchar *Key_GetBinding( int keynum ) {\n\tif ( keynum == -1 ) {\n\t\treturn \"\";\n\t}\n\n\treturn keys[ keynum ].binding;\n}\n\n/* \n===================\nKey_GetKey\n===================\n*/\n\nint Key_GetKey(const char *binding) {\n  int i;\n\n  if (binding) {\n  \tfor (i=0 ; i<256 ; i++) {\n      if (keys[i].binding && Q_stricmp(binding, keys[i].binding) == 0) {\n        return i;\n      }\n    }\n  }\n  return -1;\n}\n\n/*\n===================\nKey_Unbind_f\n===================\n*/\nvoid Key_Unbind_f (void)\n{\n\tint\t\tb;\n\n\tif (Cmd_Argc() != 2)\n\t{\n\t\tCom_Printf (\"unbind <key> : remove commands from a key\\n\");\n\t\treturn;\n\t}\n\t\n\tb = Key_StringToKeynum (Cmd_Argv(1));\n\tif (b==-1)\n\t{\n\t\tCom_Printf (\"\\\"%s\\\" isn't a valid key\\n\", Cmd_Argv(1));\n\t\treturn;\n\t}\n\n\tKey_SetBinding (b, \"\");\n}\n\n/*\n===================\nKey_Unbindall_f\n===================\n*/\nvoid Key_Unbindall_f (void)\n{\n\tint\t\ti;\n\t\n\tfor (i=0 ; i<256 ; i++)\n\t\tif (keys[i].binding)\n\t\t\tKey_SetBinding (i, \"\");\n}\n\n\n/*\n===================\nKey_Bind_f\n===================\n*/\nvoid Key_Bind_f (void)\n{\n\tint\t\t\ti, c, b;\n\tchar\t\tcmd[1024];\n\t\n\tc = Cmd_Argc();\n\n\tif (c < 2)\n\t{\n\t\tCom_Printf (\"bind <key> [command] : attach a command to a key\\n\");\n\t\treturn;\n\t}\n\tb = Key_StringToKeynum (Cmd_Argv(1));\n\tif (b==-1)\n\t{\n\t\tCom_Printf (\"\\\"%s\\\" isn't a valid key\\n\", Cmd_Argv(1));\n\t\treturn;\n\t}\n\n\tif (c == 2)\n\t{\n\t\tif (keys[b].binding)\n\t\t\tCom_Printf (\"\\\"%s\\\" = \\\"%s\\\"\\n\", Cmd_Argv(1), keys[b].binding );\n\t\telse\n\t\t\tCom_Printf (\"\\\"%s\\\" is not bound\\n\", Cmd_Argv(1) );\n\t\treturn;\n\t}\n\t\n// copy the rest of the command line\n\tcmd[0] = 0;\t\t// start out with a null string\n\tfor (i=2 ; i< c ; i++)\n\t{\n\t\tstrcat (cmd, Cmd_Argv(i));\n\t\tif (i != (c-1))\n\t\t\tstrcat (cmd, \" \");\n\t}\n\n\tKey_SetBinding (b, cmd);\n}\n\n/*\n============\nKey_WriteBindings\n\nWrites lines containing \"bind key value\"\n============\n*/\nvoid Key_WriteBindings( fileHandle_t f ) {\n\tint\t\ti;\n\n\tFS_Printf (f, \"unbindall\\n\" );\n\n\tfor (i=0 ; i<256 ; i++) {\n\t\tif (keys[i].binding && keys[i].binding[0] ) {\n\t\t\tFS_Printf (f, \"bind %s \\\"%s\\\"\\n\", Key_KeynumToString(i), keys[i].binding);\n\n\t\t}\n\n\t}\n}\n\n\n/*\n============\nKey_Bindlist_f\n\n============\n*/\nvoid Key_Bindlist_f( void ) {\n\tint\t\ti;\n\n\tfor ( i = 0 ; i < 256 ; i++ ) {\n\t\tif ( keys[i].binding && keys[i].binding[0] ) {\n\t\t\tCom_Printf( \"%s \\\"%s\\\"\\n\", Key_KeynumToString(i), keys[i].binding );\n\t\t}\n\t}\n}\n\n/*\n===================\nCL_InitKeyCommands\n===================\n*/\nvoid CL_InitKeyCommands( void ) {\n\t// register our functions\n\tCmd_AddCommand (\"bind\",Key_Bind_f);\n\tCmd_AddCommand (\"unbind\",Key_Unbind_f);\n\tCmd_AddCommand (\"unbindall\",Key_Unbindall_f);\n\tCmd_AddCommand (\"bindlist\",Key_Bindlist_f);\n}\n\n/*\n===================\nCL_AddKeyUpCommands\n===================\n*/\nvoid CL_AddKeyUpCommands( int key, char *kb ) {\n\tint i;\n\tchar button[1024], *buttonPtr;\n\tchar\tcmd[1024];\n\tqboolean keyevent;\n\n\tif ( !kb ) {\n\t\treturn;\n\t}\n\tkeyevent = qfalse;\n\tbuttonPtr = button;\n\tfor ( i = 0; ; i++ ) {\n\t\tif ( kb[i] == ';' || !kb[i] ) {\n\t\t\t*buttonPtr = '\\0';\n\t\t\tif ( button[0] == '+') {\n\t\t\t\t// button commands add keynum and time as parms so that multiple\n\t\t\t\t// sources can be discriminated and subframe corrected\n\t\t\t\tCom_sprintf (cmd, sizeof(cmd), \"-%s %i %i\\n\", button+1, key, time);\n\t\t\t\tCbuf_AddText (cmd);\n\t\t\t\tkeyevent = qtrue;\n\t\t\t} else {\n\t\t\t\tif (keyevent) {\n\t\t\t\t\t// down-only command\n\t\t\t\t\tCbuf_AddText (button);\n\t\t\t\t\tCbuf_AddText (\"\\n\");\n\t\t\t\t}\n\t\t\t}\n\t\t\tbuttonPtr = button;\n\t\t\twhile ( (kb[i] <= ' ' || kb[i] == ';') && kb[i] != 0 ) {\n\t\t\t\ti++;\n\t\t\t}\n\t\t}\n\t\t*buttonPtr++ = kb[i];\n\t\tif ( !kb[i] ) {\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\n/*\n===================\nCL_KeyEvent\n\nCalled by the system for both key up and key down events\n===================\n*/\nvoid CL_KeyEvent (int key, qboolean down, unsigned time) {\n\tchar\t*kb;\n\tchar\tcmd[1024];\n\n\t// update auto-repeat status and BUTTON_ANY status\n\tkeys[key].down = down;\n\n\tif (down) {\n\t\tkeys[key].repeats++;\n\t\tif ( keys[key].repeats == 1) {\n\t\t\t((int&)anykeydown)++;\n\t\t}\n\t} else {\n\t\tkeys[key].repeats = 0;\n\t\t((int&)anykeydown)--;\n\t\tif (anykeydown < 0) {\n\t\t\t(int&)anykeydown = 0;\n\t\t}\n\t}\n\n#ifdef __linux__\n  if (key == K_ENTER)\n  {\n    if (down)\n    {\n      if (keys[K_ALT].down)\n      {\n        Key_ClearStates();\n        if (Cvar_VariableValue(\"r_fullscreen\") == 0)\n        {\n          Com_Printf(\"Switching to fullscreen rendering\\n\");\n          Cvar_Set(\"r_fullscreen\", \"1\");\n        }\n        else\n        {\n          Com_Printf(\"Switching to windowed rendering\\n\");\n          Cvar_Set(\"r_fullscreen\", \"0\");\n        }\n        Cbuf_ExecuteText( EXEC_APPEND, \"vid_restart\\n\");\n        return;\n      }\n    }\n  }\n#endif\n\n\t// console key is hardcoded, so the user can never unbind it\n\tif (key == '`' || key == '~') {\n\t\tif (!down) {\n\t\t\treturn;\n\t\t}\n    Con_ToggleConsole_f ();\n\t\treturn;\n\t}\n\n\n\t// keys can still be used for bound actions\n\tif ( down && ( key < 128 || key == K_MOUSE1 ) && ( clc.demoplaying || cls.state == CA_CINEMATIC ) && !cls.keyCatchers) {\n\n\t\tif (Cvar_VariableValue (\"com_cameraMode\") == 0) {\n\t\t\tCvar_Set (\"nextdemo\",\"\");\n\t\t\tkey = K_ESCAPE;\n\t\t}\n\t}\n\n\n\t// escape is always handled special\n\tif ( key == K_ESCAPE && down ) {\n\t\tif ( cls.keyCatchers & KEYCATCH_MESSAGE ) {\n\t\t\t// clear message mode\n\t\t\tMessage_Key( key );\n\t\t\treturn;\n\t\t}\n\n\t\t// escape always gets out of CGAME stuff\n\t\tif (cls.keyCatchers & KEYCATCH_CGAME) {\n\t\t\tcls.keyCatchers &= ~KEYCATCH_CGAME;\n\t\t\tVM_Call (cgvm, CG_EVENT_HANDLING, CGAME_EVENT_NONE);\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !( cls.keyCatchers & KEYCATCH_UI ) ) {\n\t\t\tif ( cls.state == CA_ACTIVE && !clc.demoplaying ) {\n\t\t\t\tVM_Call( uivm, UI_SET_ACTIVE_MENU, UIMENU_INGAME );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tCL_Disconnect_f();\n\t\t\t\tS_StopAllSounds();\n\t\t\t\tVM_Call( uivm, UI_SET_ACTIVE_MENU, UIMENU_MAIN );\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tVM_Call( uivm, UI_KEY_EVENT, key, down );\n\t\treturn;\n\t}\n\n\t//\n\t// key up events only perform actions if the game key binding is\n\t// a button command (leading + sign).  These will be processed even in\n\t// console mode and menu mode, to keep the character from continuing \n\t// an action started before a mode switch.\n\t//\n\tif (!down) {\n\t\tkb = keys[key].binding;\n\n\t\tCL_AddKeyUpCommands( key, kb );\n\n\t\tif ( cls.keyCatchers & KEYCATCH_UI && uivm ) {\n\t\t\tVM_Call( uivm, UI_KEY_EVENT, key, down );\n\t\t} else if ( cls.keyCatchers & KEYCATCH_CGAME && cgvm ) {\n\t\t\tVM_Call( cgvm, CG_KEY_EVENT, key, down );\n\t\t} \n\n\t\treturn;\n\t}\n\n\n\t// distribute the key down event to the apropriate handler\n\tif ( cls.keyCatchers & KEYCATCH_CONSOLE ) {\n\t\tConsole_Key( key );\n\t} else if ( cls.keyCatchers & KEYCATCH_UI ) {\n\t\tif ( uivm ) {\n\t\t\tVM_Call( uivm, UI_KEY_EVENT, key, down );\n\t\t} \n\t} else if ( cls.keyCatchers & KEYCATCH_CGAME ) {\n\t\tif ( cgvm ) {\n\t\t\tVM_Call( cgvm, CG_KEY_EVENT, key, down );\n\t\t} \n\t} else if ( cls.keyCatchers & KEYCATCH_MESSAGE ) {\n\t\tMessage_Key( key );\n\t} else if ( cls.state == CA_DISCONNECTED ) {\n\t\tConsole_Key( key );\n\t} else {\n\t\t// send the bound action\n\t\tkb = keys[key].binding;\n\t\tif ( !kb ) {\n\t\t\tif (key >= 200) {\n\t\t\t\tCom_Printf (\"%s is unbound, use controls menu to set.\\n\"\n\t\t\t\t\t, Key_KeynumToString( key ) );\n\t\t\t}\n\t\t} else if (kb[0] == '+') {\t\n\t\t\tint i;\n\t\t\tchar button[1024], *buttonPtr;\n\t\t\tbuttonPtr = button;\n\t\t\tfor ( i = 0; ; i++ ) {\n\t\t\t\tif ( kb[i] == ';' || !kb[i] ) {\n\t\t\t\t\t*buttonPtr = '\\0';\n\t\t\t\t\tif ( button[0] == '+') {\n\t\t\t\t\t\t// button commands add keynum and time as parms so that multiple\n\t\t\t\t\t\t// sources can be discriminated and subframe corrected\n\t\t\t\t\t\tCom_sprintf (cmd, sizeof(cmd), \"%s %i %i\\n\", button, key, time);\n\t\t\t\t\t\tCbuf_AddText (cmd);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// down-only command\n\t\t\t\t\t\tCbuf_AddText (button);\n\t\t\t\t\t\tCbuf_AddText (\"\\n\");\n\t\t\t\t\t}\n\t\t\t\t\tbuttonPtr = button;\n\t\t\t\t\twhile ( (kb[i] <= ' ' || kb[i] == ';') && kb[i] != 0 ) {\n\t\t\t\t\t\ti++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t*buttonPtr++ = kb[i];\n\t\t\t\tif ( !kb[i] ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\t// down-only command\n\t\t\tCbuf_AddText (kb);\n\t\t\tCbuf_AddText (\"\\n\");\n\t\t}\n\t}\n}\n\n\n/*\n===================\nCL_CharEvent\n\nNormal keyboard characters, already shifted / capslocked / etc\n===================\n*/\nvoid CL_CharEvent( int key ) {\n\t// the console key should never be used as a char\n\tif ( key == '`' || key == '~' ) {\n\t\treturn;\n\t}\n\n\t// distribute the key down event to the apropriate handler\n\tif ( cls.keyCatchers & KEYCATCH_CONSOLE )\n\t{\n\t\tField_CharEvent( &g_consoleField, key );\n\t}\n\telse if ( cls.keyCatchers & KEYCATCH_UI )\n\t{\n\t\tVM_Call( uivm, UI_KEY_EVENT, key | K_CHAR_FLAG, qtrue );\n\t}\n\telse if ( cls.keyCatchers & KEYCATCH_MESSAGE ) \n\t{\n\t\tField_CharEvent( &chatField, key );\n\t}\n\telse if ( cls.state == CA_DISCONNECTED )\n\t{\n\t\tField_CharEvent( &g_consoleField, key );\n\t}\n}\n\n\n/*\n===================\nKey_ClearStates\n===================\n*/\nvoid Key_ClearStates (void)\n{\n\tint\t\ti;\n\n\tanykeydown = qfalse;\n\n\tfor ( i=0 ; i < MAX_KEYS ; i++ ) {\n\t\tif ( keys[i].down ) {\n\t\t\tCL_KeyEvent( i, qfalse, 0 );\n\n\t\t}\n\t\tkeys[i].down = (qboolean) 0;\n\t\tkeys[i].repeats = 0;\n\t}\n}\n\n"
  },
  {
    "path": "src/engine/client/cl_main.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n// cl_main.c  -- client main loop\n\n#include \"client.h\"\n#include <limits.h>\n\ncvar_t\t*cl_nodelta;\ncvar_t\t*cl_debugMove;\n\ncvar_t\t*cl_noprint;\ncvar_t\t*cl_motd;\n\ncvar_t\t*rcon_client_password;\ncvar_t\t*rconAddress;\n\ncvar_t\t*cl_timeout;\ncvar_t\t*cl_maxpackets;\ncvar_t\t*cl_packetdup;\ncvar_t\t*cl_timeNudge;\ncvar_t\t*cl_showTimeDelta;\ncvar_t\t*cl_freezeDemo;\n\ncvar_t\t*cl_shownet;\ncvar_t\t*cl_showSend;\ncvar_t\t*cl_timedemo;\ncvar_t\t*cl_avidemo;\ncvar_t\t*cl_forceavidemo;\n\ncvar_t\t*cl_freelook;\ncvar_t\t*cl_sensitivity;\n\ncvar_t\t*cl_mouseAccel;\ncvar_t\t*cl_showMouseRate;\n\ncvar_t\t*m_pitch;\ncvar_t\t*m_yaw;\ncvar_t\t*m_forward;\ncvar_t\t*m_side;\ncvar_t\t*m_filter;\n\ncvar_t\t*cl_activeAction;\n\ncvar_t\t*cl_motdString;\n\ncvar_t\t*cl_allowDownload;\ncvar_t\t*cl_conXOffset;\ncvar_t\t*cl_inGameVideo;\n\ncvar_t\t*cl_serverStatusResendTime;\ncvar_t\t*cl_trn;\n\nclientActive_t\t\tcl;\nclientConnection_t\tclc;\nclientStatic_t\t\tcls;\nvm_t\t\t\t\t*cgvm;\n\n// Structure containing functions exported from refresh DLL\nrefexport_t\tre;\n\nping_t\tcl_pinglist[MAX_PINGREQUESTS];\n\ntypedef struct serverStatus_s\n{\n\tchar string[BIG_INFO_STRING];\n\tnetadr_t address;\n\tint time, startTime;\n\tqboolean pending;\n\tqboolean print;\n\tqboolean retrieved;\n} serverStatus_t;\n\nserverStatus_t cl_serverStatusList[MAX_SERVERSTATUSREQUESTS];\nint serverStatusCount;\n\n#if defined __USEA3D && defined __A3D_GEOM\n\tvoid hA3Dg_ExportRenderGeom (refexport_t *incoming_re);\n#endif\n\nextern void SV_BotFrame( int time );\nvoid CL_CheckForResend( void );\nvoid CL_ShowIP_f(void);\nvoid CL_ServerStatus_f(void);\nvoid CL_ServerStatusResponse( netadr_t from, msg_t *msg );\n\n/*\n===============\nCL_CDDialog\n\nCalled by Com_Error when a cd is needed\n===============\n*/\nvoid CL_CDDialog( void ) {\n\tcls.cddialog = qtrue;\t// start it next frame\n}\n\n\n/*\n=======================================================================\n\nCLIENT RELIABLE COMMAND COMMUNICATION\n\n=======================================================================\n*/\n\n/*\n======================\nCL_AddReliableCommand\n\nThe given command will be transmitted to the server, and is gauranteed to\nnot have future usercmd_t executed before it is executed\n======================\n*/\nvoid CL_AddReliableCommand( const char *cmd ) {\n\tint\t\tindex;\n\n\t// if we would be losing an old command that hasn't been acknowledged,\n\t// we must drop the connection\n\tif ( clc.reliableSequence - clc.reliableAcknowledge > MAX_RELIABLE_COMMANDS ) {\n\t\tCom_Error( ERR_DROP, \"Client command overflow\" );\n\t}\n\tclc.reliableSequence++;\n\tindex = clc.reliableSequence & ( MAX_RELIABLE_COMMANDS - 1 );\n\tQ_strncpyz( clc.reliableCommands[ index ], cmd, sizeof( clc.reliableCommands[ index ] ) );\n}\n\n/*\n======================\nCL_ChangeReliableCommand\n======================\n*/\nvoid CL_ChangeReliableCommand( void ) {\n\tint r, index, l;\n\n\tr = clc.reliableSequence - (random() * 5);\n\tindex = clc.reliableSequence & ( MAX_RELIABLE_COMMANDS - 1 );\n\tl = (int)strlen(clc.reliableCommands[ index ]);\n\tif ( l >= MAX_STRING_CHARS - 1 ) {\n\t\tl = MAX_STRING_CHARS - 2;\n\t}\n\tclc.reliableCommands[ index ][ l ] = '\\n';\n\tclc.reliableCommands[ index ][ l+1 ] = '\\0';\n}\n\n/*\n=======================================================================\n\nCLIENT SIDE DEMO RECORDING\n\n=======================================================================\n*/\n\n/*\n====================\nCL_WriteDemoMessage\n\nDumps the current net message, prefixed by the length\n====================\n*/\nvoid CL_WriteDemoMessage ( msg_t *msg, int headerBytes ) {\n\tint\t\tlen, swlen;\n\n\t// write the packet sequence\n\tlen = clc.serverMessageSequence;\n\tswlen = LittleLong( len );\n\tFS_Write (&swlen, 4, clc.demofile);\n\n\t// skip the packet sequencing information\n\tlen = msg->cursize - headerBytes;\n\tswlen = LittleLong(len);\n\tFS_Write (&swlen, 4, clc.demofile);\n\tFS_Write ( msg->data + headerBytes, len, clc.demofile );\n}\n\n\n/*\n====================\nCL_StopRecording_f\n\nstop recording a demo\n====================\n*/\nvoid CL_StopRecord_f( void ) {\n\tint\t\tlen;\n\n\tif ( !clc.demorecording ) {\n\t\tCom_Printf (\"Not recording a demo.\\n\");\n\t\treturn;\n\t}\n\n\t// finish up\n\tlen = -1;\n\tFS_Write (&len, 4, clc.demofile);\n\tFS_Write (&len, 4, clc.demofile);\n\tFS_FCloseFile (clc.demofile);\n\tclc.demofile = 0;\n\tclc.demorecording = qfalse;\n\tclc.spDemoRecording = qfalse;\n\tCom_Printf (\"Stopped demo.\\n\");\n}\n\n/* \n================== \nCL_DemoFilename\n================== \n*/  \nvoid CL_DemoFilename( int number, char *fileName ) {\n\tint\t\ta,b,c,d;\n\n\tif ( number < 0 || number > 9999 ) {\n\t\tCom_sprintf( fileName, MAX_QPATH, \"demo9999.tga\" );\n\t\treturn;\n\t}\n\n\ta = number / 1000;\n\tnumber -= a*1000;\n\tb = number / 100;\n\tnumber -= b*100;\n\tc = number / 10;\n\tnumber -= c*10;\n\td = number;\n\n\tCom_sprintf( fileName, MAX_QPATH, \"demo%i%i%i%i\"\n\t\t, a, b, c, d );\n}\n\n/*\n====================\nCL_Record_f\n\nrecord <demoname>\n\nBegins recording a demo from the current position\n====================\n*/\nstatic char\t\tdemoName[MAX_QPATH];\t// compiler bug workaround\nvoid CL_Record_f( void ) {\n\tchar\t\tname[MAX_OSPATH];\n\tbyte\t\tbufData[MAX_MSGLEN];\n\tmsg_t\tbuf;\n\tint\t\t\ti;\n\tint\t\t\tlen;\n\tentityState_t\t*ent;\n\tentityState_t\tnullstate;\n\tchar\t\t*s;\n\n\tif ( Cmd_Argc() > 2 ) {\n\t\tCom_Printf (\"record <demoname>\\n\");\n\t\treturn;\n\t}\n\n\tif ( clc.demorecording ) {\n\t\tif (!clc.spDemoRecording) {\n\t\t\tCom_Printf (\"Already recording.\\n\");\n\t\t}\n\t\treturn;\n\t}\n\n\tif ( cls.state != CA_ACTIVE ) {\n\t\tCom_Printf (\"You must be in a level to record.\\n\");\n\t\treturn;\n\t}\n\n  // sync 0 doesn't prevent recording, so not forcing it off .. everyone does g_sync 1 ; record ; g_sync 0 ..\n\tif ( !Cvar_VariableValue( \"g_synchronousClients\" ) ) {\n\t\tCom_Printf (S_COLOR_YELLOW \"WARNING: You should set 'g_synchronousClients 1' for smoother demo recording\\n\");\n\t}\n\n\tif ( Cmd_Argc() == 2 ) {\n\t\ts = Cmd_Argv(1);\n\t\tQ_strncpyz( demoName, s, sizeof( demoName ) );\n\t\tCom_sprintf (name, sizeof(name), \"demos/%s.dm_%d\", demoName, PROTOCOL_VERSION );\n\t} else {\n\t\tint\t\tnumber;\n\n\t\t// scan for a free demo name\n\t\tfor ( number = 0 ; number <= 9999 ; number++ ) {\n\t\t\tCL_DemoFilename( number, demoName );\n\t\t\tCom_sprintf (name, sizeof(name), \"demos/%s.dm_%d\", demoName, PROTOCOL_VERSION );\n\n\t\t\tlen = FS_ReadFile( name, NULL );\n\t\t\tif ( len <= 0 ) {\n\t\t\t\tbreak;\t// file doesn't exist\n\t\t\t}\n\t\t}\n\t}\n\n\t// open the demo file\n\n\tCom_Printf (\"recording to %s.\\n\", name);\n\tclc.demofile = FS_FOpenFileWrite( name );\n\tif ( !clc.demofile ) {\n\t\tCom_Printf (\"ERROR: couldn't open.\\n\");\n\t\treturn;\n\t}\n\tclc.demorecording = qtrue;\n\tif (Cvar_VariableValue(\"ui_recordSPDemo\")) {\n\t  clc.spDemoRecording = qtrue;\n\t} else {\n\t  clc.spDemoRecording = qfalse;\n\t}\n\n\n\tQ_strncpyz( clc.demoName, demoName, sizeof( clc.demoName ) );\n\n\t// don't start saving messages until a non-delta compressed message is received\n\tclc.demowaiting = qtrue;\n\n\t// write out the gamestate message\n\tMSG_Init (&buf, bufData, sizeof(bufData));\n\tMSG_Bitstream(&buf);\n\n\t// NOTE, MRE: all server->client messages now acknowledge\n\tMSG_WriteLong( &buf, clc.reliableSequence );\n\n\tMSG_WriteByte (&buf, svc_gamestate);\n\tMSG_WriteLong (&buf, clc.serverCommandSequence );\n\n\t// configstrings\n\tfor ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) {\n\t\tif ( !cl.gameState.stringOffsets[i] ) {\n\t\t\tcontinue;\n\t\t}\n\t\ts = cl.gameState.stringData + cl.gameState.stringOffsets[i];\n\t\tMSG_WriteByte (&buf, svc_configstring);\n\t\tMSG_WriteShort (&buf, i);\n\t\tMSG_WriteBigString (&buf, s);\n\t}\n\n\t// baselines\n\tCom_Memset (&nullstate, 0, sizeof(nullstate));\n\tfor ( i = 0; i < MAX_GENTITIES ; i++ ) {\n\t\tent = &cl.entityBaselines[i];\n\t\tif ( !ent->number ) {\n\t\t\tcontinue;\n\t\t}\n\t\tMSG_WriteByte (&buf, svc_baseline);\t\t\n\t\tMSG_WriteDeltaEntity (&buf, &nullstate, ent, qtrue );\n\t}\n\n\tMSG_WriteByte( &buf, svc_EOF );\n\t\n\t// finished writing the gamestate stuff\n\n\t// write the client num\n\tMSG_WriteLong(&buf, clc.clientNum);\n\t// write the checksum feed\n\tMSG_WriteLong(&buf, clc.checksumFeed);\n\n\t// finished writing the client packet\n\tMSG_WriteByte( &buf, svc_EOF );\n\n\t// write it to the demo file\n\tlen = LittleLong( clc.serverMessageSequence - 1 );\n\tFS_Write (&len, 4, clc.demofile);\n\n\tlen = LittleLong (buf.cursize);\n\tFS_Write (&len, 4, clc.demofile);\n\tFS_Write (buf.data, buf.cursize, clc.demofile);\n\n\t// the rest of the demo file will be copied from net messages\n}\n\n/*\n=======================================================================\n\nCLIENT SIDE DEMO PLAYBACK\n\n=======================================================================\n*/\n\n/*\n=================\nCL_DemoCompleted\n=================\n*/\nvoid CL_DemoCompleted( void ) {\n\tif (cl_timedemo && cl_timedemo->integer) {\n\t\tint\ttime;\n\t\t\n\t\ttime = Sys_Milliseconds() - clc.timeDemoStart;\n\t\tif ( time > 0 ) {\n\t\t\tCom_Printf (\"%i frames, %3.1f seconds: %3.1f fps\\n\", clc.timeDemoFrames,\n\t\t\ttime/1000.0, clc.timeDemoFrames*1000.0 / time);\n\t\t}\n\t}\n\n\tCL_Disconnect( qtrue );\n\tCL_NextDemo();\n}\n\n/*\n=================\nCL_ReadDemoMessage\n=================\n*/\nvoid CL_ReadDemoMessage( void ) {\n\tint\t\t\tr;\n\tmsg_t\t\tbuf;\n\tbyte\t\tbufData[ MAX_MSGLEN ];\n\tint\t\t\ts;\n\n\tif ( !clc.demofile ) {\n\t\tCL_DemoCompleted ();\n\t\treturn;\n\t}\n\n\t// get the sequence number\n\tr = FS_Read( &s, 4, clc.demofile);\n\tif ( r != 4 ) {\n\t\tCL_DemoCompleted ();\n\t\treturn;\n\t}\n\tclc.serverMessageSequence = LittleLong( s );\n\n\t// init the message\n\tMSG_Init( &buf, bufData, sizeof( bufData ) );\n\n\t// get the length\n\tr = FS_Read (&buf.cursize, 4, clc.demofile);\n\tif ( r != 4 ) {\n\t\tCL_DemoCompleted ();\n\t\treturn;\n\t}\n\tbuf.cursize = LittleLong( buf.cursize );\n\tif ( buf.cursize == -1 ) {\n\t\tCL_DemoCompleted ();\n\t\treturn;\n\t}\n\tif ( buf.cursize > buf.maxsize ) {\n\t\tCom_Error (ERR_DROP, \"CL_ReadDemoMessage: demoMsglen > MAX_MSGLEN\");\n\t}\n\tr = FS_Read( buf.data, buf.cursize, clc.demofile );\n\tif ( r != buf.cursize ) {\n\t\tCom_Printf( \"Demo file was truncated.\\n\");\n\t\tCL_DemoCompleted ();\n\t\treturn;\n\t}\n\n\tclc.lastPacketTime = cls.realtime;\n\tbuf.readcount = 0;\n\tCL_ParseServerMessage( &buf );\n}\n\n/*\n====================\nCL_WalkDemoExt\n====================\n*/\nstatic void CL_WalkDemoExt(char *arg, char *name, int *demofile)\n{\n\tint i = 0;\n\t*demofile = 0;\n\twhile(demo_protocols[i])\n\t{\n\t\tCom_sprintf (name, MAX_OSPATH, \"demos/%s.dm_%d\", arg, demo_protocols[i]);\n\t\tFS_FOpenFileRead( name, demofile, qtrue );\n\t\tif (*demofile)\n\t\t{\n\t\t\tCom_Printf(\"Demo file: %s\\n\", name);\n\t\t\tbreak;\n\t\t}\n\t\telse\n\t\t\tCom_Printf(\"Not found: %s\\n\", name);\n\t\ti++;\n\t}\n}\n\n/*\n====================\nCL_PlayDemo_f\n\ndemo <demoname>\n\n====================\n*/\nvoid CL_PlayDemo_f( void ) {\n\tchar\t\tname[MAX_OSPATH];\n\tchar\t\t*arg, *ext_test;\n\tint\t\t\tprotocol, i;\n\tchar\t\tretry[MAX_OSPATH];\n\n\tif (Cmd_Argc() != 2) {\n\t\tCom_Printf (\"playdemo <demoname>\\n\");\n\t\treturn;\n\t}\n\n\t// make sure a local server is killed\n\tCvar_Set( \"sv_killserver\", \"1\" );\n\n\tCL_Disconnect( qtrue );\n\n\t// open the demo file\n\targ = Cmd_Argv(1);\n\t\n\t// check for an extension .dm_?? (?? is protocol)\n\text_test = arg + (int)strlen(arg) - 6;\n\tif ((strlen(arg) > 6) && (ext_test[0] == '.') && ((ext_test[1] == 'd') || (ext_test[1] == 'D')) && ((ext_test[2] == 'm') || (ext_test[2] == 'M')) && (ext_test[3] == '_'))\n\t{\n\t\tprotocol = atoi(ext_test+4);\n\t\ti=0;\n\t\twhile(demo_protocols[i])\n\t\t{\n\t\t\tif (demo_protocols[i] == protocol)\n\t\t\t\tbreak;\n\t\t\ti++;\n\t\t}\n\t\tif (demo_protocols[i])\n\t\t{\n\t\t\tCom_sprintf (name, sizeof(name), \"demos/%s\", arg);\n\t\t\tFS_FOpenFileRead( name, &clc.demofile, qtrue );\n\t\t} else {\n\t\t\tCom_Printf(\"Protocol %d not supported for demos\\n\", protocol);\n\t\t\tQ_strncpyz(retry, arg, sizeof(retry));\n\t\t\tretry[strlen(retry)-6] = 0;\n\t\t\tCL_WalkDemoExt( retry, name, &clc.demofile );\n\t\t}\n\t} else {\n\t\tCL_WalkDemoExt( arg, name, &clc.demofile );\n\t}\n\t\n\tif (!clc.demofile) {\n\t\tCom_Error( ERR_DROP, \"couldn't open %s\", name);\n\t\treturn;\n\t}\n\tQ_strncpyz( clc.demoName, Cmd_Argv(1), sizeof( clc.demoName ) );\n\n\tCon_Close();\n\n\tcls.state = CA_CONNECTED;\n\tclc.demoplaying = qtrue;\n\tQ_strncpyz( cls.servername, Cmd_Argv(1), sizeof( cls.servername ) );\n\n\t// read demo messages until connected\n\twhile ( cls.state >= CA_CONNECTED && cls.state < CA_PRIMED ) {\n\t\tCL_ReadDemoMessage();\n\t}\n\t// don't get the first snapshot this frame, to prevent the long\n\t// time from the gamestate load from messing causing a time skip\n\tclc.firstDemoFrameSkipped = qfalse;\n}\n\n\n/*\n====================\nCL_StartDemoLoop\n\nClosing the main menu will restart the demo loop\n====================\n*/\nvoid CL_StartDemoLoop( void ) {\n\t// start the demo loop again\n\tCbuf_AddText (\"d1\\n\");\n\tcls.keyCatchers = 0;\n}\n\n/*\n==================\nCL_NextDemo\n\nCalled when a demo or cinematic finishes\nIf the \"nextdemo\" cvar is set, that command will be issued\n==================\n*/\nvoid CL_NextDemo( void ) {\n\tchar\tv[MAX_STRING_CHARS];\n\n\tQ_strncpyz( v, Cvar_VariableString (\"nextdemo\"), sizeof(v) );\n\tv[MAX_STRING_CHARS-1] = 0;\n\tCom_DPrintf(\"CL_NextDemo: %s\\n\", v );\n\tif (!v[0]) {\n\t\treturn;\n\t}\n\n\tCvar_Set (\"nextdemo\",\"\");\n\tCbuf_AddText (v);\n\tCbuf_AddText (\"\\n\");\n\tCbuf_Execute();\n}\n\n\n//======================================================================\n\n/*\n=====================\nCL_ShutdownAll\n=====================\n*/\nvoid CL_ShutdownAll(void) {\n\n\t// clear sounds\n\tS_DisableSounds();\n\t// shutdown CGame\n\tCL_ShutdownCGame();\n\t// shutdown UI\n\tCL_ShutdownUI();\n\n\t// shutdown the renderer\n\tif ( re.Shutdown ) {\n\t\tre.Shutdown( qfalse );\t\t// don't destroy window or context\n\t}\n\n\tcls.uiStarted = qfalse;\n\tcls.cgameStarted = qfalse;\n\tcls.rendererStarted = qfalse;\n\tcls.soundRegistered = qfalse;\n}\n\n/*\n=================\nCL_FlushMemory\n\nCalled by CL_MapLoading, CL_Connect_f, CL_PlayDemo_f, and CL_ParseGamestate the only\nways a client gets into a game\nAlso called by Com_Error\n=================\n*/\nvoid CL_FlushMemory( void ) {\n\n\t// shutdown all the client stuff\n\tCL_ShutdownAll();\n\n\t// if not running a server clear the whole hunk\n\tif ( !com_sv_running->integer ) {\n\t\t// clear the whole hunk\n\t\tHunk_Clear();\n\t\t// clear collision map data\n\t\tCM_ClearMap();\n\t}\n\telse {\n\t\t// clear all the client data on the hunk\n\t\tHunk_ClearToMark();\n\t}\n\n\tCL_StartHunkUsers();\n}\n\n/*\n=====================\nCL_MapLoading\n\nA local server is starting to load a map, so update the\nscreen to let the user know about it, then dump all client\nmemory on the hunk from cgame, ui, and renderer\n=====================\n*/\nvoid CL_MapLoading( void ) {\n\tif ( !com_cl_running->integer ) {\n\t\treturn;\n\t}\n\n\tCon_Close();\n\tcls.keyCatchers = 0;\n\n\t// if we are already connected to the local host, stay connected\n\tif ( cls.state >= CA_CONNECTED && !Q_stricmp( cls.servername, \"localhost\" ) ) {\n\t\tcls.state = CA_CONNECTED;\t\t// so the connect screen is drawn\n\t\tCom_Memset( cls.updateInfoString, 0, sizeof( cls.updateInfoString ) );\n\t\tCom_Memset( clc.serverMessage, 0, sizeof( clc.serverMessage ) );\n\t\tCom_Memset( &cl.gameState, 0, sizeof( cl.gameState ) );\n\t\tclc.lastPacketSentTime = -9999;\n\t\tSCR_UpdateScreen();\n\t} else {\n\t\t// clear nextmap so the cinematic shutdown doesn't execute it\n\t\tCvar_Set( \"nextmap\", \"\" );\n\t\tCL_Disconnect( qtrue );\n\t\tQ_strncpyz( cls.servername, \"localhost\", sizeof(cls.servername) );\n\t\tcls.state = CA_CHALLENGING;\t\t// so the connect screen is drawn\n\t\tcls.keyCatchers = 0;\n\t\tSCR_UpdateScreen();\n\t\tclc.connectTime = -RETRANSMIT_TIMEOUT;\n\t\tNET_StringToAdr( cls.servername, &clc.serverAddress);\n\t\t// we don't need a challenge on the localhost\n\n\t\tCL_CheckForResend();\n\t}\n}\n\n/*\n=====================\nCL_ClearState\n\nCalled before parsing a gamestate\n=====================\n*/\nvoid CL_ClearState (void) {\n\n//\tS_StopAllSounds();\n\n\tCom_Memset( &cl, 0, sizeof( cl ) );\n}\n\n\n/*\n=====================\nCL_Disconnect\n\nCalled when a connection, demo, or cinematic is being terminated.\nGoes from a connected state to either a menu state or a console state\nSends a disconnect message to the server\nThis is also called on Com_Error and Com_Quit, so it shouldn't cause any errors\n=====================\n*/\nvoid CL_Disconnect( qboolean showMainMenu ) {\n\tif ( !com_cl_running || !com_cl_running->integer ) {\n\t\treturn;\n\t}\n\n\t// shutting down the client so enter full screen ui mode\n\tCvar_Set(\"r_uiFullScreen\", \"1\");\n\n\tif ( clc.demorecording ) {\n\t\tCL_StopRecord_f ();\n\t}\n\n\tif (clc.download) {\n\t\tFS_FCloseFile( clc.download );\n\t\tclc.download = 0;\n\t}\n\t*clc.downloadTempName = *clc.downloadName = 0;\n\tCvar_Set( \"cl_downloadName\", \"\" );\n\n\tif ( clc.demofile ) {\n\t\tFS_FCloseFile( clc.demofile );\n\t\tclc.demofile = 0;\n\t}\n\n\tif ( uivm && showMainMenu ) {\n\t\tVM_Call( uivm, UI_SET_ACTIVE_MENU, UIMENU_NONE );\n\t}\n\n\tSCR_StopCinematic ();\n\tS_ClearSoundBuffer();\n\n\t// send a disconnect message to the server\n\t// send it a few times in case one is dropped\n\tif ( cls.state >= CA_CONNECTED ) {\n\t\tCL_AddReliableCommand( \"disconnect\" );\n\t\tCL_WritePacket();\n\t\tCL_WritePacket();\n\t\tCL_WritePacket();\n\t}\n\t\n\tCL_ClearState ();\n\n\t// wipe the client connection\n\tCom_Memset( &clc, 0, sizeof( clc ) );\n\n\tcls.state = CA_DISCONNECTED;\n\n\t// allow cheats locally\n\tCvar_Set( \"sv_cheats\", \"1\" );\n\n\t// not connected to a pure server anymore\n\tcl_connectedToPureServer = qfalse;\n}\n\n\n/*\n===================\nCL_ForwardCommandToServer\n\nadds the current command line as a clientCommand\nthings like godmode, noclip, etc, are commands directed to the server,\nso when they are typed in at the console, they will need to be forwarded.\n===================\n*/\nvoid CL_ForwardCommandToServer( const char *string ) {\n\tchar\t*cmd;\n\n\tcmd = Cmd_Argv(0);\n\n\t// ignore key up commands\n\tif ( cmd[0] == '-' ) {\n\t\treturn;\n\t}\n\n\tif ( clc.demoplaying || cls.state < CA_CONNECTED || cmd[0] == '+' ) {\n\t\tCom_Printf (\"Unknown command \\\"%s\\\"\\n\", cmd);\n\t\treturn;\n\t}\n\n\tif ( Cmd_Argc() > 1 ) {\n\t\tCL_AddReliableCommand( string );\n\t} else {\n\t\tCL_AddReliableCommand( cmd );\n\t}\n}\n\n/*\n===================\nCL_RequestMotd\n\n===================\n*/\nvoid CL_RequestMotd( void ) {\n\tchar\t\tinfo[MAX_INFO_STRING];\n\n\tif ( !cl_motd->integer ) {\n\t\treturn;\n\t}\n\tCom_Printf( \"Resolving %s\\n\", UPDATE_SERVER_NAME );\n\tif ( !NET_StringToAdr( UPDATE_SERVER_NAME, &cls.updateServer  ) ) {\n\t\tCom_Printf( \"Couldn't resolve address\\n\" );\n\t\treturn;\n\t}\n\tcls.updateServer.port = BigShort( PORT_UPDATE );\n\tCom_Printf( \"%s resolved to %i.%i.%i.%i:%i\\n\", UPDATE_SERVER_NAME,\n\t\tcls.updateServer.ip[0], cls.updateServer.ip[1],\n\t\tcls.updateServer.ip[2], cls.updateServer.ip[3],\n\t\tBigShort( cls.updateServer.port ) );\n\t\n\tinfo[0] = 0;\n  // NOTE TTimo xoring against Com_Milliseconds, otherwise we may not have a true randomization\n  // only srand I could catch before here is tr_noise.c l:26 srand(1001)\n  // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=382\n  // NOTE: the Com_Milliseconds xoring only affects the lower 16-bit word,\n  //   but I decided it was enough randomization\n\tCom_sprintf( cls.updateChallenge, sizeof( cls.updateChallenge ), \"%i\", ((rand() << 16) ^ rand()) ^ Com_Milliseconds());\n\n\tInfo_SetValueForKey( info, \"challenge\", cls.updateChallenge );\n\tInfo_SetValueForKey( info, \"renderer\", cls.glconfig.renderer_string );\n\tInfo_SetValueForKey( info, \"version\", com_version->string );\n\n\tNET_OutOfBandPrint( NS_CLIENT, cls.updateServer, \"getmotd \\\"%s\\\"\\n\", info );\n}\n\n/*\n===================\nCL_RequestAuthorization\n\nAuthorization server protocol\n-----------------------------\n\nAll commands are text in Q3 out of band packets (leading 0xff 0xff 0xff 0xff).\n\nWhenever the client tries to get a challenge from the server it wants to\nconnect to, it also blindly fires off a packet to the authorize server:\n\ngetKeyAuthorize <challenge> <cdkey>\n\ncdkey may be \"demo\"\n\n\n#OLD The authorize server returns a:\n#OLD \n#OLD keyAthorize <challenge> <accept | deny>\n#OLD \n#OLD A client will be accepted if the cdkey is valid and it has not been used by any other IP\n#OLD address in the last 15 minutes.\n\n\nThe server sends a:\n\ngetIpAuthorize <challenge> <ip>\n\nThe authorize server returns a:\n\nipAuthorize <challenge> <accept | deny | demo | unknown >\n\nA client will be accepted if a valid cdkey was sent by that ip (only) in the last 15 minutes.\nIf no response is received from the authorize server after two tries, the client will be let\nin anyway.\n===================\n*/\nvoid CL_RequestAuthorization( void ) {\n\tchar\tnums[64];\n\tint\t\ti, j, l;\n\tcvar_t\t*fs;\n\n\tif ( !cls.authorizeServer.port ) {\n\t\tCom_Printf( \"Resolving %s\\n\", AUTHORIZE_SERVER_NAME );\n\t\tif ( !NET_StringToAdr( AUTHORIZE_SERVER_NAME, &cls.authorizeServer  ) ) {\n\t\t\tCom_Printf( \"Couldn't resolve address\\n\" );\n\t\t\treturn;\n\t\t}\n\n\t\tcls.authorizeServer.port = BigShort( PORT_AUTHORIZE );\n\t\tCom_Printf( \"%s resolved to %i.%i.%i.%i:%i\\n\", AUTHORIZE_SERVER_NAME,\n\t\t\tcls.authorizeServer.ip[0], cls.authorizeServer.ip[1],\n\t\t\tcls.authorizeServer.ip[2], cls.authorizeServer.ip[3],\n\t\t\tBigShort( cls.authorizeServer.port ) );\n\t}\n\tif ( cls.authorizeServer.type == NA_BAD ) {\n\t\treturn;\n\t}\n\n\tif ( Cvar_VariableValue( \"fs_restrict\" ) ) {\n\t\tQ_strncpyz( nums, \"demota\", sizeof( nums ) );\n\t} else {\n\t\t// only grab the alphanumeric values from the cdkey, to avoid any dashes or spaces\n\t\tj = 0;\n\t\tl = (int)strlen( cl_cdkey );\n\t\tif ( l > 32 ) {\n\t\t\tl = 32;\n\t\t}\n\t\tfor ( i = 0 ; i < l ; i++ ) {\n\t\t\tif ( ( cl_cdkey[i] >= '0' && cl_cdkey[i] <= '9' )\n\t\t\t\t|| ( cl_cdkey[i] >= 'a' && cl_cdkey[i] <= 'z' )\n\t\t\t\t|| ( cl_cdkey[i] >= 'A' && cl_cdkey[i] <= 'Z' )\n\t\t\t\t) {\n\t\t\t\tnums[j] = cl_cdkey[i];\n\t\t\t\tj++;\n\t\t\t}\n\t\t}\n\t\tnums[j] = 0;\n\t}\n\n\tfs = Cvar_Get (\"cl_anonymous\", \"0\", CVAR_INIT|CVAR_SYSTEMINFO );\n\n\tNET_OutOfBandPrint(NS_CLIENT, cls.authorizeServer, va(\"getKeyAuthorize %i %s\", fs->integer, nums) );\n}\n\n/*\n======================================================================\n\nCONSOLE COMMANDS\n\n======================================================================\n*/\n\n/*\n==================\nCL_ForwardToServer_f\n==================\n*/\nvoid CL_ForwardToServer_f( void ) {\n\tif ( cls.state != CA_ACTIVE || clc.demoplaying ) {\n\t\tCom_Printf (\"Not connected to a server.\\n\");\n\t\treturn;\n\t}\n\t\n\t// don't forward the first argument\n\tif ( Cmd_Argc() > 1 ) {\n\t\tCL_AddReliableCommand( Cmd_Args() );\n\t}\n}\n\n/*\n==================\nCL_Setenv_f\n\nMostly for controlling voodoo environment variables\n==================\n*/\nvoid CL_Setenv_f( void ) {\n\tint argc = Cmd_Argc();\n\n\tif ( argc > 2 ) {\n\t\tchar buffer[1024];\n\t\tint i;\n\n\t\tstrcpy( buffer, Cmd_Argv(1) );\n\t\tstrcat( buffer, \"=\" );\n\n\t\tfor ( i = 2; i < argc; i++ ) {\n\t\t\tstrcat( buffer, Cmd_Argv( i ) );\n\t\t\tstrcat( buffer, \" \" );\n\t\t}\n\n\t\tputenv( buffer );\n\t} else if ( argc == 2 ) {\n\t\tchar *env = getenv( Cmd_Argv(1) );\n\n\t\tif ( env ) {\n\t\t\tCom_Printf( \"%s=%s\\n\", Cmd_Argv(1), env );\n\t\t} else {\n\t\t\tCom_Printf( \"%s undefined\\n\", Cmd_Argv(1), env );\n\t\t}\n\t}\n}\n\n\n/*\n==================\nCL_Disconnect_f\n==================\n*/\nvoid CL_Disconnect_f( void ) {\n\tSCR_StopCinematic();\n\tCvar_Set(\"ui_singlePlayerActive\", \"0\");\n\tif ( cls.state != CA_DISCONNECTED && cls.state != CA_CINEMATIC ) {\n\t\tCom_Error (ERR_DISCONNECT, \"Disconnected from server\");\n\t}\n}\n\n\n/*\n================\nCL_Reconnect_f\n\n================\n*/\nvoid CL_Reconnect_f( void ) {\n\tif ( !strlen( cls.servername ) || !strcmp( cls.servername, \"localhost\" ) ) {\n\t\tCom_Printf( \"Can't reconnect to localhost.\\n\" );\n\t\treturn;\n\t}\n\tCvar_Set(\"ui_singlePlayerActive\", \"0\");\n\tCbuf_AddText( va(\"connect %s\\n\", cls.servername ) );\n}\n\n/*\n================\nCL_Connect_f\n\n================\n*/\nvoid CL_Connect_f( void ) {\n\tchar\t*server;\n\n\tif ( Cmd_Argc() != 2 ) {\n\t\tCom_Printf( \"usage: connect [server]\\n\");\n\t\treturn;\t\n\t}\n\n\tCvar_Set(\"ui_singlePlayerActive\", \"0\");\n\n\t// fire a message off to the motd server\n\tCL_RequestMotd();\n\n\t// clear any previous \"server full\" type messages\n\tclc.serverMessage[0] = 0;\n\n\tserver = Cmd_Argv (1);\n\n\tif ( com_sv_running->integer && !strcmp( server, \"localhost\" ) ) {\n\t\t// if running a local server, kill it\n\t\tSV_Shutdown( \"Server quit\\n\" );\n\t}\n\n\t// make sure a local server is killed\n\tCvar_Set( \"sv_killserver\", \"1\" );\n\tSV_Frame( 0 );\n\n\tCL_Disconnect( qtrue );\n\tCon_Close();\n\n\t/* MrE: 2000-09-13: now called in CL_DownloadsComplete\n\tCL_FlushMemory( );\n\t*/\n\n\tQ_strncpyz( cls.servername, server, sizeof(cls.servername) );\n\n\tif (!NET_StringToAdr( cls.servername, &clc.serverAddress) ) {\n\t\tCom_Printf (\"Bad server address\\n\");\n\t\tcls.state = CA_DISCONNECTED;\n\t\treturn;\n\t}\n\tif (clc.serverAddress.port == 0) {\n\t\tclc.serverAddress.port = BigShort( PORT_SERVER );\n\t}\n\tCom_Printf( \"%s resolved to %i.%i.%i.%i:%i\\n\", cls.servername,\n\t\tclc.serverAddress.ip[0], clc.serverAddress.ip[1],\n\t\tclc.serverAddress.ip[2], clc.serverAddress.ip[3],\n\t\tBigShort( clc.serverAddress.port ) );\n\n\t// if we aren't playing on a lan, we need to authenticate\n\t// with the cd key\n\tif ( NET_IsLocalAddress( clc.serverAddress ) ) {\n\t\tcls.state = CA_CHALLENGING;\n\t} else {\n\t\tcls.state = CA_CONNECTING;\n\t}\n\n\tcls.keyCatchers = 0;\n\tclc.connectTime = -99999;\t// CL_CheckForResend() will fire immediately\n\tclc.connectPacketCount = 0;\n\n\t// server connection string\n\tCvar_Set( \"cl_currentServerAddress\", server );\n}\n\n\n/*\n=====================\nCL_Rcon_f\n\n  Send the rest of the command line over as\n  an unconnected command.\n=====================\n*/\nvoid CL_Rcon_f( void ) {\n\tchar\tmessage[1024];\n\tnetadr_t\tto;\n\n\tif ( !rcon_client_password->string ) {\n\t\tCom_Printf (\"You must set 'rconpassword' before\\n\"\n\t\t\t\t\t\"issuing an rcon command.\\n\");\n\t\treturn;\n\t}\n\n\tmessage[0] = -1;\n\tmessage[1] = -1;\n\tmessage[2] = -1;\n\tmessage[3] = -1;\n\tmessage[4] = 0;\n\n\tstrcat (message, \"rcon \");\n\n\tstrcat (message, rcon_client_password->string);\n\tstrcat (message, \" \");\n\n\t// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=543\n\tstrcat (message, Cmd_Cmd()+5);\n\n\tif ( cls.state >= CA_CONNECTED ) {\n\t\tto = clc.netchan.remoteAddress;\n\t} else {\n\t\tif (!strlen(rconAddress->string)) {\n\t\t\tCom_Printf (\"You must either be connected,\\n\"\n\t\t\t\t\t\t\"or set the 'rconAddress' cvar\\n\"\n\t\t\t\t\t\t\"to issue rcon commands\\n\");\n\n\t\t\treturn;\n\t\t}\n\t\tNET_StringToAdr (rconAddress->string, &to);\n\t\tif (to.port == 0) {\n\t\t\tto.port = BigShort (PORT_SERVER);\n\t\t}\n\t}\n\t\n\tNET_SendPacket (NS_CLIENT, (int)strlen(message)+1, message, to);\n}\n\n/*\n=================\nCL_SendPureChecksums\n=================\n*/\nvoid CL_SendPureChecksums( void ) {\n\tconst char *pChecksums;\n\tchar cMsg[MAX_INFO_VALUE];\n\tint i;\n\n\t// if we are pure we need to send back a command with our referenced pk3 checksums\n\tpChecksums = FS_ReferencedPakPureChecksums();\n\n\t// \"cp\"\n\t// \"Yf\"\n\tCom_sprintf(cMsg, sizeof(cMsg), \"Yf \");\n\tQ_strcat(cMsg, sizeof(cMsg), va(\"%d \", cl.serverId) );\n\tQ_strcat(cMsg, sizeof(cMsg), pChecksums);\n\tfor (i = 0; i < 2; i++) {\n\t\tcMsg[i] += 10;\n\t}\n\tCL_AddReliableCommand( cMsg );\n}\n\n/*\n=================\nCL_ResetPureClientAtServer\n=================\n*/\nvoid CL_ResetPureClientAtServer( void ) {\n\tCL_AddReliableCommand( va(\"vdr\") );\n}\n\n/*\n=================\nCL_Vid_Restart_f\n\nRestart the video subsystem\n\nwe also have to reload the UI and CGame because the renderer\ndoesn't know what graphics to reload\n=================\n*/\nvoid CL_Vid_Restart_f( void ) {\n\n\t// don't let them loop during the restart\n\tS_StopAllSounds();\n\t// shutdown the UI\n\tCL_ShutdownUI();\n\t// shutdown the CGame\n\tCL_ShutdownCGame();\n\t// shutdown the renderer and clear the renderer interface\n\tCL_ShutdownRef();\n\t// client is no longer pure untill new checksums are sent\n\tCL_ResetPureClientAtServer();\n\t// clear pak references\n\tFS_ClearPakReferences( FS_UI_REF | FS_CGAME_REF );\n\t// reinitialize the filesystem if the game directory or checksum has changed\n\tFS_ConditionalRestart( clc.checksumFeed );\n\n\tcls.rendererStarted = qfalse;\n\tcls.uiStarted = qfalse;\n\tcls.cgameStarted = qfalse;\n\tcls.soundRegistered = qfalse;\n\n\t// unpause so the cgame definately gets a snapshot and renders a frame\n\tCvar_Set( \"cl_paused\", \"0\" );\n\n\t// if not running a server clear the whole hunk\n\tif ( !com_sv_running->integer ) {\n\t\t// clear the whole hunk\n\t\tHunk_Clear();\n\t}\n\telse {\n\t\t// clear all the client data on the hunk\n\t\tHunk_ClearToMark();\n\t}\n\n\t// initialize the renderer interface\n\tCL_InitRef();\n\n\t// startup all the client stuff\n\tCL_StartHunkUsers();\n\n\t// start the cgame if connected\n\tif ( cls.state > CA_CONNECTED && cls.state != CA_CINEMATIC ) {\n\t\tcls.cgameStarted = qtrue;\n\t\tCL_InitCGame();\n\t\t// send pure checksums\n\t\tCL_SendPureChecksums();\n\t}\n}\n\n/*\n=================\nCL_Snd_Restart_f\n\nRestart the sound subsystem\nThe cgame and game must also be forced to restart because\nhandles will be invalid\n=================\n*/\nvoid CL_Snd_Restart_f( void ) {\n\tS_Shutdown();\n\tS_Init();\n\n\tCL_Vid_Restart_f();\n}\n\n\n/*\n==================\nCL_PK3List_f\n==================\n*/\nvoid CL_OpenedPK3List_f( void ) {\n\tCom_Printf(\"Opened PK3 Names: %s\\n\", FS_LoadedPakNames());\n}\n\n/*\n==================\nCL_PureList_f\n==================\n*/\nvoid CL_ReferencedPK3List_f( void ) {\n\tCom_Printf(\"Referenced PK3 Names: %s\\n\", FS_ReferencedPakNames());\n}\n\n/*\n==================\nCL_Configstrings_f\n==================\n*/\nvoid CL_Configstrings_f( void ) {\n\tint\t\ti;\n\tint\t\tofs;\n\n\tif ( cls.state != CA_ACTIVE ) {\n\t\tCom_Printf( \"Not connected to a server.\\n\");\n\t\treturn;\n\t}\n\n\tfor ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) {\n\t\tofs = cl.gameState.stringOffsets[ i ];\n\t\tif ( !ofs ) {\n\t\t\tcontinue;\n\t\t}\n\t\tCom_Printf( \"%4i: %s\\n\", i, cl.gameState.stringData + ofs );\n\t}\n}\n\n/*\n==============\nCL_Clientinfo_f\n==============\n*/\nvoid CL_Clientinfo_f( void ) {\n\tCom_Printf( \"--------- Client Information ---------\\n\" );\n\tCom_Printf( \"state: %i\\n\", cls.state );\n\tCom_Printf( \"Server: %s\\n\", cls.servername );\n\tCom_Printf (\"User info settings:\\n\");\n\tInfo_Print( Cvar_InfoString( CVAR_USERINFO ) );\n\tCom_Printf( \"--------------------------------------\\n\" );\n}\n\n\n//====================================================================\n\n/*\n=================\nCL_DownloadsComplete\n\nCalled when all downloading has been completed\n=================\n*/\nvoid CL_DownloadsComplete( void ) {\n\n\t// if we downloaded files we need to restart the file system\n\tif (clc.downloadRestart) {\n\t\tclc.downloadRestart = qfalse;\n\n\t\tFS_Restart(clc.checksumFeed); // We possibly downloaded a pak, restart the file system to load it\n\n\t\t// inform the server so we get new gamestate info\n\t\tCL_AddReliableCommand( \"donedl\" );\n\n\t\t// by sending the donedl command we request a new gamestate\n\t\t// so we don't want to load stuff yet\n\t\treturn;\n\t}\n\n\t// let the client game init and load data\n\tcls.state = CA_LOADING;\n\n\t// Pump the loop, this may change gamestate!\n\tCom_EventLoop();\n\n\t// if the gamestate was changed by calling Com_EventLoop\n\t// then we loaded everything already and we don't want to do it again.\n\tif ( cls.state != CA_LOADING ) {\n\t\treturn;\n\t}\n\n\t// starting to load a map so we get out of full screen ui mode\n\tCvar_Set(\"r_uiFullScreen\", \"0\");\n\n\t// flush client memory and start loading stuff\n\t// this will also (re)load the UI\n\t// if this is a local client then only the client part of the hunk\n\t// will be cleared, note that this is done after the hunk mark has been set\n\tCL_FlushMemory();\n\n\t// initialize the CGame\n\tcls.cgameStarted = qtrue;\n\tCL_InitCGame();\n\n\t// set pure checksums\n\tCL_SendPureChecksums();\n\n\tCL_WritePacket();\n\tCL_WritePacket();\n\tCL_WritePacket();\n}\n\n/*\n=================\nCL_BeginDownload\n\nRequests a file to download from the server.  Stores it in the current\ngame directory.\n=================\n*/\nvoid CL_BeginDownload( const char *localName, const char *remoteName ) {\n\n\tCom_DPrintf(\"***** CL_BeginDownload *****\\n\"\n\t\t\t\t\"Localname: %s\\n\"\n\t\t\t\t\"Remotename: %s\\n\"\n\t\t\t\t\"****************************\\n\", localName, remoteName);\n\n\tQ_strncpyz ( clc.downloadName, localName, sizeof(clc.downloadName) );\n\tCom_sprintf( clc.downloadTempName, sizeof(clc.downloadTempName), \"%s.tmp\", localName );\n\n\t// Set so UI gets access to it\n\tCvar_Set( \"cl_downloadName\", remoteName );\n\tCvar_Set( \"cl_downloadSize\", \"0\" );\n\tCvar_Set( \"cl_downloadCount\", \"0\" );\n\tCvar_SetValue( \"cl_downloadTime\", cls.realtime );\n\n\tclc.downloadBlock = 0; // Starting new file\n\tclc.downloadCount = 0;\n\n\tCL_AddReliableCommand( va(\"download %s\", remoteName) );\n}\n\n/*\n=================\nCL_NextDownload\n\nA download completed or failed\n=================\n*/\nvoid CL_NextDownload(void) {\n\tchar *s;\n\tchar *remoteName, *localName;\n\n\t// We are looking to start a download here\n\tif (*clc.downloadList) {\n\t\ts = clc.downloadList;\n\n\t\t// format is:\n\t\t//  @remotename@localname@remotename@localname, etc.\n\n\t\tif (*s == '@')\n\t\t\ts++;\n\t\tremoteName = s;\n\t\t\n\t\tif ( (s = strchr(s, '@')) == NULL ) {\n\t\t\tCL_DownloadsComplete();\n\t\t\treturn;\n\t\t}\n\n\t\t*s++ = 0;\n\t\tlocalName = s;\n\t\tif ( (s = strchr(s, '@')) != NULL )\n\t\t\t*s++ = 0;\n\t\telse\n\t\t\ts = localName + (int)strlen(localName); // point at the nul byte\n\n\t\tCL_BeginDownload( localName, remoteName );\n\n\t\tclc.downloadRestart = qtrue;\n\n\t\t// move over the rest\n\t\tmemmove( clc.downloadList, s, (int)strlen(s) + 1);\n\n\t\treturn;\n\t}\n\n\tCL_DownloadsComplete();\n}\n\n/*\n=================\nCL_InitDownloads\n\nAfter receiving a valid game state, we valid the cgame and local zip files here\nand determine if we need to download them\n=================\n*/\nvoid CL_InitDownloads(void) {\n  char missingfiles[1024];\n\n  if ( !cl_allowDownload->integer )\n  {\n    // autodownload is disabled on the client\n    // but it's possible that some referenced files on the server are missing\n    if (FS_ComparePaks( missingfiles, sizeof( missingfiles ), qfalse ) )\n    {      \n      // NOTE TTimo I would rather have that printed as a modal message box\n      //   but at this point while joining the game we don't know wether we will successfully join or not\n      Com_Printf( \"\\nWARNING: You are missing some files referenced by the server:\\n%s\"\n                  \"You might not be able to join the game\\n\"\n                  \"Go to the setting menu to turn on autodownload, or get the file elsewhere\\n\\n\", missingfiles );\n    }\n  }\n  else if ( FS_ComparePaks( clc.downloadList, sizeof( clc.downloadList ) , qtrue ) ) {\n\n    Com_Printf(\"Need paks: %s\\n\", clc.downloadList );\n\n\t\tif ( *clc.downloadList ) {\n\t\t\t// if autodownloading is not enabled on the server\n\t\t\tcls.state = CA_CONNECTED;\n\t\t\tCL_NextDownload();\n\t\t\treturn;\n\t\t}\n\n\t}\n\t\t\n\tCL_DownloadsComplete();\n}\n\n/*\n=================\nCL_CheckForResend\n\nResend a connect message if the last one has timed out\n=================\n*/\nvoid CL_CheckForResend( void ) {\n\tint\t\tport, i;\n\tchar\tinfo[MAX_INFO_STRING];\n\tchar\tdata[MAX_INFO_STRING];\n\n\t// don't send anything if playing back a demo\n\tif ( clc.demoplaying ) {\n\t\treturn;\n\t}\n\n\t// resend if we haven't gotten a reply yet\n\tif ( cls.state != CA_CONNECTING && cls.state != CA_CHALLENGING ) {\n\t\treturn;\n\t}\n\n\tif ( cls.realtime - clc.connectTime < RETRANSMIT_TIMEOUT ) {\n\t\treturn;\n\t}\n\n\tclc.connectTime = cls.realtime;\t// for retransmit requests\n\tclc.connectPacketCount++;\n\n\n\tswitch ( cls.state ) {\n\tcase CA_CONNECTING:\n\t\t// requesting a challenge\n\t\tif ( !Sys_IsLANAddress( clc.serverAddress ) ) {\n\t\t\tCL_RequestAuthorization();\n\t\t}\n\t\tNET_OutOfBandPrint(NS_CLIENT, clc.serverAddress, \"getchallenge\");\n\t\tbreak;\n\t\t\n\tcase CA_CHALLENGING:\n\t\t// sending back the challenge\n\t\tport = Cvar_VariableValue (\"net_qport\");\n\n\t\tQ_strncpyz( info, Cvar_InfoString( CVAR_USERINFO ), sizeof( info ) );\n\t\tInfo_SetValueForKey( info, \"protocol\", va(\"%i\", PROTOCOL_VERSION ) );\n\t\tInfo_SetValueForKey( info, \"qport\", va(\"%i\", port ) );\n\t\tInfo_SetValueForKey( info, \"challenge\", va(\"%i\", clc.challenge ) );\n\t\t\n\t\tstrcpy(data, \"connect \");\n    // TTimo adding \" \" around the userinfo string to avoid truncated userinfo on the server\n    //   (Com_TokenizeString tokenizes around spaces)\n    data[8] = '\"';\n\n\t\tfor(i=0;i<strlen(info);i++) {\n\t\t\tdata[9+i] = info[i];\t// + (clc.challenge)&0x3;\n\t\t}\n    data[9+i] = '\"';\n\t\tdata[10+i] = 0;\n\n    // NOTE TTimo don't forget to set the right data length!\n\t\tNET_OutOfBandData( NS_CLIENT, clc.serverAddress, (byte*) &data[0], i+10 );\n\t\t// the most current userinfo has been sent, so watch for any\n\t\t// newer changes to userinfo variables\n\t\tcvar_modifiedFlags &= ~CVAR_USERINFO;\n\t\tbreak;\n\n\tdefault:\n\t\tCom_Error( ERR_FATAL, \"CL_CheckForResend: bad cls.state\" );\n\t}\n}\n\n/*\n===================\nCL_DisconnectPacket\n\nSometimes the server can drop the client and the netchan based\ndisconnect can be lost.  If the client continues to send packets\nto the server, the server will send out of band disconnect packets\nto the client so it doesn't have to wait for the full timeout period.\n===================\n*/\nvoid CL_DisconnectPacket( netadr_t from ) {\n\tif ( cls.state < CA_AUTHORIZING ) {\n\t\treturn;\n\t}\n\n\t// if not from our server, ignore it\n\tif ( !NET_CompareAdr( from, clc.netchan.remoteAddress ) ) {\n\t\treturn;\n\t}\n\n\t// if we have received packets within three seconds, ignore it\n\t// (it might be a malicious spoof)\n\tif ( cls.realtime - clc.lastPacketTime < 3000 ) {\n\t\treturn;\n\t}\n\n\t// drop the connection\n\tCom_Printf( \"Server disconnected for unknown reason\\n\" );\n\tCvar_Set(\"com_errorMessage\", \"Server disconnected for unknown reason\\n\" );\n\tCL_Disconnect( qtrue );\n}\n\n\n/*\n===================\nCL_MotdPacket\n\n===================\n*/\nvoid CL_MotdPacket( netadr_t from ) {\n\tchar\t*challenge;\n\tchar\t*info;\n\n\t// if not from our server, ignore it\n\tif ( !NET_CompareAdr( from, cls.updateServer ) ) {\n\t\treturn;\n\t}\n\n\tinfo = Cmd_Argv(1);\n\n\t// check challenge\n\tchallenge = Info_ValueForKey( info, \"challenge\" );\n\tif ( strcmp( challenge, cls.updateChallenge ) ) {\n\t\treturn;\n\t}\n\n\tchallenge = Info_ValueForKey( info, \"motd\" );\n\n\tQ_strncpyz( cls.updateInfoString, info, sizeof( cls.updateInfoString ) );\n\tCvar_Set( \"cl_motdString\", challenge );\n}\n\n/*\n===================\nCL_InitServerInfo\n===================\n*/\nvoid CL_InitServerInfo( serverInfo_t *server, serverAddress_t *address ) {\n\tserver->adr.type  = NA_IP;\n\tserver->adr.ip[0] = address->ip[0];\n\tserver->adr.ip[1] = address->ip[1];\n\tserver->adr.ip[2] = address->ip[2];\n\tserver->adr.ip[3] = address->ip[3];\n\tserver->adr.port  = address->port;\n\tserver->clients = 0;\n\tserver->hostName[0] = '\\0';\n\tserver->mapName[0] = '\\0';\n\tserver->maxClients = 0;\n\tserver->maxPing = 0;\n\tserver->minPing = 0;\n\tserver->ping = -1;\n\tserver->game[0] = '\\0';\n\tserver->gameType = 0;\n\tserver->netType = 0;\n}\n\n#define MAX_SERVERSPERPACKET\t256\n\n/*\n===================\nCL_ServersResponsePacket\n===================\n*/\nvoid CL_ServersResponsePacket( netadr_t from, msg_t *msg ) {\n\tint\t\t\t\ti, count, max, total;\n\tserverAddress_t addresses[MAX_SERVERSPERPACKET];\n\tint\t\t\t\tnumservers;\n\tbyte*\t\t\tbuffptr;\n\tbyte*\t\t\tbuffend;\n\t\n\tCom_Printf(\"CL_ServersResponsePacket\\n\");\n\n\tif (cls.numglobalservers == -1) {\n\t\t// state to detect lack of servers or lack of response\n\t\tcls.numglobalservers = 0;\n\t\tcls.numGlobalServerAddresses = 0;\n\t}\n\n\tif (cls.nummplayerservers == -1) {\n\t\tcls.nummplayerservers = 0;\n\t}\n\n\t// parse through server response string\n\tnumservers = 0;\n\tbuffptr    = msg->data;\n\tbuffend    = buffptr + msg->cursize;\n\twhile (buffptr+1 < buffend) {\n\t\t// advance to initial token\n\t\tdo {\n\t\t\tif (*buffptr++ == '\\\\')\n\t\t\t\tbreak;\t\t\n\t\t}\n\t\twhile (buffptr < buffend);\n\n\t\tif ( buffptr >= buffend - 6 ) {\n\t\t\tbreak;\n\t\t}\n\n\t\t// parse out ip\n\t\taddresses[numservers].ip[0] = *buffptr++;\n\t\taddresses[numservers].ip[1] = *buffptr++;\n\t\taddresses[numservers].ip[2] = *buffptr++;\n\t\taddresses[numservers].ip[3] = *buffptr++;\n\n\t\t// parse out port\n\t\taddresses[numservers].port = (*buffptr++)<<8;\n\t\taddresses[numservers].port += *buffptr++;\n\t\taddresses[numservers].port = BigShort( addresses[numservers].port );\n\n\t\t// syntax check\n\t\tif (*buffptr != '\\\\') {\n\t\t\tbreak;\n\t\t}\n\n\t\tCom_DPrintf( \"server: %d ip: %d.%d.%d.%d:%d\\n\",numservers,\n\t\t\t\taddresses[numservers].ip[0],\n\t\t\t\taddresses[numservers].ip[1],\n\t\t\t\taddresses[numservers].ip[2],\n\t\t\t\taddresses[numservers].ip[3],\n\t\t\t\taddresses[numservers].port );\n\n\t\tnumservers++;\n\t\tif (numservers >= MAX_SERVERSPERPACKET) {\n\t\t\tbreak;\n\t\t}\n\n\t\t// parse out EOT\n\t\tif (buffptr[1] == 'E' && buffptr[2] == 'O' && buffptr[3] == 'T') {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (cls.masterNum == 0) {\n\t\tcount = cls.numglobalservers;\n\t\tmax = MAX_GLOBAL_SERVERS;\n\t} else {\n\t\tcount = cls.nummplayerservers;\n\t\tmax = MAX_OTHER_SERVERS;\n\t}\n\n\tfor (i = 0; i < numservers && count < max; i++) {\n\t\t// build net address\n\t\tserverInfo_t *server = (cls.masterNum == 0) ? &cls.globalServers[count] : &cls.mplayerServers[count];\n\n\t\tCL_InitServerInfo( server, &addresses[i] );\n\t\t// advance to next slot\n\t\tcount++;\n\t}\n\n\t// if getting the global list\n\tif (cls.masterNum == 0) {\n\t\tif ( cls.numGlobalServerAddresses < MAX_GLOBAL_SERVERS ) {\n\t\t\t// if we couldn't store the servers in the main list anymore\n\t\t\tfor (; i < numservers && count >= max; i++) {\n\t\t\t\tserverAddress_t *addr;\n\t\t\t\t// just store the addresses in an additional list\n\t\t\t\taddr = &cls.globalServerAddresses[cls.numGlobalServerAddresses++];\n\t\t\t\taddr->ip[0] = addresses[i].ip[0];\n\t\t\t\taddr->ip[1] = addresses[i].ip[1];\n\t\t\t\taddr->ip[2] = addresses[i].ip[2];\n\t\t\t\taddr->ip[3] = addresses[i].ip[3];\n\t\t\t\taddr->port  = addresses[i].port;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (cls.masterNum == 0) {\n\t\tcls.numglobalservers = count;\n\t\ttotal = count + cls.numGlobalServerAddresses;\n\t} else {\n\t\tcls.nummplayerservers = count;\n\t\ttotal = count;\n\t}\n\n\tCom_Printf(\"%d servers parsed (total %d)\\n\", numservers, total);\n}\n\n/*\n=================\nCL_ConnectionlessPacket\n\nResponses to broadcasts, etc\n=================\n*/\nvoid CL_ConnectionlessPacket( netadr_t from, msg_t *msg ) {\n\tchar\t*s;\n\tchar\t*c;\n\n\tMSG_BeginReadingOOB( msg );\n\tMSG_ReadLong( msg );\t// skip the -1\n\n\ts = MSG_ReadStringLine( msg );\n\n\tCmd_TokenizeString( s );\n\n\tc = Cmd_Argv(0);\n\n\tCom_DPrintf (\"CL packet %s: %s\\n\", NET_AdrToString(from), c);\n\n\t// challenge from the server we are connecting to\n\tif ( !Q_stricmp(c, \"challengeResponse\") ) {\n\t\tif ( cls.state != CA_CONNECTING ) {\n\t\t\tCom_Printf( \"Unwanted challenge response received.  Ignored.\\n\" );\n\t\t} else {\n\t\t\t// start sending challenge repsonse instead of challenge request packets\n\t\t\tclc.challenge = atoi(Cmd_Argv(1));\n\t\t\tcls.state = CA_CHALLENGING;\n\t\t\tclc.connectPacketCount = 0;\n\t\t\tclc.connectTime = -99999;\n\n\t\t\t// take this address as the new server address.  This allows\n\t\t\t// a server proxy to hand off connections to multiple servers\n\t\t\tclc.serverAddress = from;\n\t\t\tCom_DPrintf (\"challengeResponse: %d\\n\", clc.challenge);\n\t\t}\n\t\treturn;\n\t}\n\n\t// server connection\n\tif ( !Q_stricmp(c, \"connectResponse\") ) {\n\t\tif ( cls.state >= CA_CONNECTED ) {\n\t\t\tCom_Printf (\"Dup connect received.  Ignored.\\n\");\n\t\t\treturn;\n\t\t}\n\t\tif ( cls.state != CA_CHALLENGING ) {\n\t\t\tCom_Printf (\"connectResponse packet while not connecting.  Ignored.\\n\");\n\t\t\treturn;\n\t\t}\n\t\tif ( !NET_CompareBaseAdr( from, clc.serverAddress ) ) {\n\t\t\tCom_Printf( \"connectResponse from a different address.  Ignored.\\n\" );\n\t\t\tCom_Printf( \"%s should have been %s\\n\", NET_AdrToString( from ), \n\t\t\t\tNET_AdrToString( clc.serverAddress ) );\n\t\t\treturn;\n\t\t}\n\t\tNetchan_Setup (NS_CLIENT, &clc.netchan, from, Cvar_VariableValue( \"net_qport\" ) );\n\t\tcls.state = CA_CONNECTED;\n\t\tclc.lastPacketSentTime = -9999;\t\t// send first packet immediately\n\t\treturn;\n\t}\n\n\t// server responding to an info broadcast\n\tif ( !Q_stricmp(c, \"infoResponse\") ) {\n\t\tCL_ServerInfoPacket( from, msg );\n\t\treturn;\n\t}\n\n\t// server responding to a get playerlist\n\tif ( !Q_stricmp(c, \"statusResponse\") ) {\n\t\tCL_ServerStatusResponse( from, msg );\n\t\treturn;\n\t}\n\n\t// a disconnect message from the server, which will happen if the server\n\t// dropped the connection but it is still getting packets from us\n\tif (!Q_stricmp(c, \"disconnect\")) {\n\t\tCL_DisconnectPacket( from );\n\t\treturn;\n\t}\n\n\t// echo request from server\n\tif ( !Q_stricmp(c, \"echo\") ) {\n\t\tNET_OutOfBandPrint( NS_CLIENT, from, \"%s\", Cmd_Argv(1) );\n\t\treturn;\n\t}\n\n\t// cd check\n\tif ( !Q_stricmp(c, \"keyAuthorize\") ) {\n\t\t// we don't use these now, so dump them on the floor\n\t\treturn;\n\t}\n\n\t// global MOTD from id\n\tif ( !Q_stricmp(c, \"motd\") ) {\n\t\tCL_MotdPacket( from );\n\t\treturn;\n\t}\n\n\t// echo request from server\n\tif ( !Q_stricmp(c, \"print\") ) {\n\t\ts = MSG_ReadString( msg );\n\t\tQ_strncpyz( clc.serverMessage, s, sizeof( clc.serverMessage ) );\n\t\tCom_Printf( \"%s\", s );\n\t\treturn;\n\t}\n\n\t// echo request from server\n\tif ( !Q_strncmp(c, \"getserversResponse\", 18) ) {\n\t\tCL_ServersResponsePacket( from, msg );\n\t\treturn;\n\t}\n\n\tCom_DPrintf (\"Unknown connectionless packet command.\\n\");\n}\n\n\n/*\n=================\nCL_PacketEvent\n\nA packet has arrived from the main event loop\n=================\n*/\nvoid CL_PacketEvent( netadr_t from, msg_t *msg ) {\n\tint\t\theaderBytes;\n\n\tclc.lastPacketTime = cls.realtime;\n\n\tif ( msg->cursize >= 4 && *(int *)msg->data == -1 ) {\n\t\tCL_ConnectionlessPacket( from, msg );\n\t\treturn;\n\t}\n\n\tif ( cls.state < CA_CONNECTED ) {\n\t\treturn;\t\t// can't be a valid sequenced packet\n\t}\n\n\tif ( msg->cursize < 4 ) {\n\t\tCom_Printf (\"%s: Runt packet\\n\",NET_AdrToString( from ));\n\t\treturn;\n\t}\n\n\t//\n\t// packet from server\n\t//\n\tif ( !NET_CompareAdr( from, clc.netchan.remoteAddress ) ) {\n\t\tCom_DPrintf (\"%s:sequenced packet without connection\\n\"\n\t\t\t,NET_AdrToString( from ) );\n\t\t// FIXME: send a client disconnect?\n\t\treturn;\n\t}\n\n\tif (!CL_Netchan_Process( &clc.netchan, msg) ) {\n\t\treturn;\t\t// out of order, duplicated, etc\n\t}\n\n\t// the header is different lengths for reliable and unreliable messages\n\theaderBytes = msg->readcount;\n\n\t// track the last message received so it can be returned in \n\t// client messages, allowing the server to detect a dropped\n\t// gamestate\n\tclc.serverMessageSequence = LittleLong( *(int *)msg->data );\n\n\tclc.lastPacketTime = cls.realtime;\n\tCL_ParseServerMessage( msg );\n\n\t//\n\t// we don't know if it is ok to save a demo message until\n\t// after we have parsed the frame\n\t//\n\tif ( clc.demorecording && !clc.demowaiting ) {\n\t\tCL_WriteDemoMessage( msg, headerBytes );\n\t}\n}\n\n/*\n==================\nCL_CheckTimeout\n\n==================\n*/\nvoid CL_CheckTimeout( void ) {\n\t//\n\t// check timeout\n\t//\n\tif ( ( !cl_paused->integer || !sv_paused->integer ) \n\t\t&& cls.state >= CA_CONNECTED && cls.state != CA_CINEMATIC\n\t    && cls.realtime - clc.lastPacketTime > cl_timeout->value*1000) {\n\t\tif (++cl.timeoutcount > 5) {\t// timeoutcount saves debugger\n\t\t\tCom_Printf (\"\\nServer connection timed out.\\n\");\n\t\t\tCL_Disconnect( qtrue );\n\t\t\treturn;\n\t\t}\n\t} else {\n\t\tcl.timeoutcount = 0;\n\t}\n}\n\n\n//============================================================================\n\n/*\n==================\nCL_CheckUserinfo\n\n==================\n*/\nvoid CL_CheckUserinfo( void ) {\n\t// don't add reliable commands when not yet connected\n\tif ( cls.state < CA_CHALLENGING ) {\n\t\treturn;\n\t}\n\t// don't overflow the reliable command buffer when paused\n\tif ( cl_paused->integer ) {\n\t\treturn;\n\t}\n\t// send a reliable userinfo update if needed\n\tif ( cvar_modifiedFlags & CVAR_USERINFO ) {\n\t\tcvar_modifiedFlags &= ~CVAR_USERINFO;\n\t\tCL_AddReliableCommand( va(\"userinfo \\\"%s\\\"\", Cvar_InfoString( CVAR_USERINFO ) ) );\n\t}\n\n}\n\n/*\n==================\nCL_Frame\n\n==================\n*/\nvoid CL_Frame ( int msec ) {\n\n\tif ( !com_cl_running->integer ) {\n\t\treturn;\n\t}\n\n\tif ( cls.cddialog ) {\n\t\t// bring up the cd error dialog if needed\n\t\tcls.cddialog = qfalse;\n\t\tVM_Call( uivm, UI_SET_ACTIVE_MENU, UIMENU_NEED_CD );\n\t} else\tif ( cls.state == CA_DISCONNECTED && !( cls.keyCatchers & KEYCATCH_UI )\n\t\t&& !com_sv_running->integer ) {\n\t\t// if disconnected, bring up the menu\n\t\tS_StopAllSounds();\n\t\tVM_Call( uivm, UI_SET_ACTIVE_MENU, UIMENU_MAIN );\n\t}\n\n\t// if recording an avi, lock to a fixed fps\n\tif ( cl_avidemo->integer && msec) {\n\t\t// save the current screen\n\t\tif ( cls.state == CA_ACTIVE || cl_forceavidemo->integer) {\n\t\t\tCbuf_ExecuteText( EXEC_NOW, \"screenshot silent\\n\" );\n\t\t}\n\t\t// fixed time for next frame'\n\t\tmsec = (1000 / cl_avidemo->integer) * com_timescale->value;\n\t\tif (msec == 0) {\n\t\t\tmsec = 1;\n\t\t}\n\t}\n\t\n\t// save the msec before checking pause\n\tcls.realFrametime = msec;\n\n\t// decide the simulation time\n\tcls.frametime = msec;\n\n\tcls.realtime += cls.frametime;\n\n\tif ( cl_timegraph->integer ) {\n\t\tSCR_DebugGraph ( cls.realFrametime * 0.25, 0 );\n\t}\n\n\t// see if we need to update any userinfo\n\tCL_CheckUserinfo();\n\n\t// if we haven't gotten a packet in a long time,\n\t// drop the connection\n\tCL_CheckTimeout();\n\n\t// send intentions now\n\tCL_SendCmd();\n\n\t// resend a connection request if necessary\n\tCL_CheckForResend();\n\n\t// decide on the serverTime to render\n\tCL_SetCGameTime();\n\n\t// update the screen\n\tSCR_UpdateScreen();\n\n\t// update audio\n\tS_Update();\n\n\t// advance local effects for next frame\n\tSCR_RunCinematic();\n\n\tCon_RunConsole();\n\n\tcls.framecount++;\n}\n\n\n//============================================================================\n\n/*\n================\nCL_RefPrintf\n\nDLL glue\n================\n*/\nvoid QDECL CL_RefPrintf( int print_level, const char *fmt, ...) {\n\tva_list\t\targptr;\n\tchar\t\tmsg[MAXPRINTMSG];\n\t\n\tva_start (argptr,fmt);\n\tQ_vsnprintf (msg, sizeof(msg), fmt, argptr);\n\tva_end (argptr);\n\n\tif ( print_level == PRINT_ALL ) {\n\t\tCom_Printf (\"%s\", msg);\n\t} else if ( print_level == PRINT_WARNING ) {\n\t\tCom_Printf (S_COLOR_YELLOW \"%s\", msg);\t\t// yellow\n\t} else if ( print_level == PRINT_DEVELOPER ) {\n\t\tCom_DPrintf (S_COLOR_RED \"%s\", msg);\t\t// red\n\t}\n}\n\n\n\n/*\n============\nCL_ShutdownRef\n============\n*/\nvoid CL_ShutdownRef( void ) {\n\tif ( !re.Shutdown ) {\n\t\treturn;\n\t}\n\tre.Shutdown( qtrue );\n\tCom_Memset( &re, 0, sizeof( re ) );\n}\n\n/*\n============\nCL_InitRenderer\n============\n*/\nvoid CL_InitRenderer( void ) {\n\t// this sets up the renderer and calls R_Init\n\tre.BeginRegistration( &cls.glconfig );\n\n\t// load character sets\n\tcls.charSetShader = re.RegisterShader( \"gfx/2d/bigchars\" );\n\tcls.whiteShader = re.RegisterShader( \"white\" );\n\tcls.consoleShader = re.RegisterShader( \"console\" );\n\tg_console_field_width = cls.glconfig.vidWidth / SMALLCHAR_WIDTH - 2;\n\tg_consoleField.widthInChars = g_console_field_width;\n}\n\n/*\n============================\nCL_StartHunkUsers\n\nAfter the server has cleared the hunk, these will need to be restarted\nThis is the only place that any of these functions are called from\n============================\n*/\nvoid CL_StartHunkUsers( void ) {\n\tif (!com_cl_running) {\n\t\treturn;\n\t}\n\n\tif ( !com_cl_running->integer ) {\n\t\treturn;\n\t}\n\n\tif ( !cls.rendererStarted ) {\n\t\tcls.rendererStarted = qtrue;\n\t\tCL_InitRenderer();\n\t}\n\n\tif ( !cls.soundStarted ) {\n\t\tcls.soundStarted = qtrue;\n\t\tS_Init();\n\t}\n\n\tif ( !cls.soundRegistered ) {\n\t\tcls.soundRegistered = qtrue;\n\t\tS_BeginRegistration();\n\t}\n\n\tif ( !cls.uiStarted ) {\n\t\tcls.uiStarted = qtrue;\n\t\tCL_InitUI();\n\t}\n}\n\n/*\n============\nCL_RefMalloc\n============\n*/\nvoid *CL_RefMalloc( int size ) {\n\treturn Z_TagMalloc( size, TAG_RENDERER );\n}\n\nint CL_ScaledMilliseconds(void) {\n\treturn Sys_Milliseconds()*com_timescale->value;\n}\n\n/*\n============\nCL_InitRef\n============\n*/\nvoid CL_InitRef( void ) {\n\trefimport_t\tri;\n\trefexport_t\t*ret;\n\n\tCom_Printf( \"----- Initializing Renderer ----\\n\" );\n\n\tri.Cmd_AddCommand = Cmd_AddCommand;\n\tri.Cmd_RemoveCommand = Cmd_RemoveCommand;\n\tri.Cmd_Argc = Cmd_Argc;\n\tri.Cmd_Argv = Cmd_Argv;\n\tri.Cmd_ExecuteText = Cbuf_ExecuteText;\n\tri.Printf = CL_RefPrintf;\n\tri.Error = Com_Error;\n\tri.Milliseconds = CL_ScaledMilliseconds;\n\tri.Malloc = CL_RefMalloc;\n\tri.Free = Z_Free;\n#ifdef HUNK_DEBUG\n\tri.Hunk_AllocDebug = Hunk_AllocDebug;\n#else\n\tri.Hunk_Alloc = Hunk_Alloc;\n#endif\n\tri.Hunk_AllocateTempMemory = Hunk_AllocateTempMemory;\n\tri.Hunk_FreeTempMemory = Hunk_FreeTempMemory;\n\tri.CM_DrawDebugSurface = CM_DrawDebugSurface;\n\tri.FS_ReadFile = FS_ReadFile;\n\tri.FS_FreeFile = FS_FreeFile;\n\tri.FS_WriteFile = FS_WriteFile;\n\tri.FS_FreeFileList = FS_FreeFileList;\n\tri.FS_ListFiles = FS_ListFiles;\n\tri.FS_FileIsInPAK = FS_FileIsInPAK;\n\tri.FS_FileExists = FS_FileExists;\n\tri.Cvar_Get = Cvar_Get;\n\tri.Cvar_Set = Cvar_Set;\n\n\t// cinematic stuff\n\n\tri.CIN_UploadCinematic = CIN_UploadCinematic;\n\tri.CIN_PlayCinematic = CIN_PlayCinematic;\n\tri.CIN_RunCinematic = CIN_RunCinematic;\n\n\tret = GetRefAPI( REF_API_VERSION, &ri );\n\n#if defined __USEA3D && defined __A3D_GEOM\n\thA3Dg_ExportRenderGeom (ret);\n#endif\n\n\tCom_Printf( \"-------------------------------\\n\");\n\n\tif ( !ret ) {\n\t\tCom_Error (ERR_FATAL, \"Couldn't initialize refresh\" );\n\t}\n\n\tre = *ret;\n\n\t// unpause so the cgame definately gets a snapshot and renders a frame\n\tCvar_Set( \"cl_paused\", \"0\" );\n}\n\n\n//===========================================================================================\n\n\nvoid CL_SetModel_f( void ) {\n\tchar\t*arg;\n\tchar\tname[256];\n\n\targ = Cmd_Argv( 1 );\n\tif (arg[0]) {\n\t\tCvar_Set( \"model\", arg );\n\t\tCvar_Set( \"headmodel\", arg );\n\t} else {\n\t\tCvar_VariableStringBuffer( \"model\", name, sizeof(name) );\n\t\tCom_Printf(\"model is set to %s\\n\", name);\n\t}\n}\n\n/*\n====================\nCL_Init\n====================\n*/\nvoid CL_Init( void ) {\n\tCom_Printf( \"----- Client Initialization -----\\n\" );\n\n\tCon_Init ();\t\n\n\tCL_ClearState ();\n\n\tcls.state = CA_DISCONNECTED;\t// no longer CA_UNINITIALIZED\n\n\tcls.realtime = 0;\n\n\tCL_InitInput ();\n\n\t//\n\t// register our variables\n\t//\n\tcl_noprint = Cvar_Get( \"cl_noprint\", \"0\", 0 );\n\tcl_motd = Cvar_Get (\"cl_motd\", \"1\", 0);\n\n\tcl_timeout = Cvar_Get (\"cl_timeout\", \"200\", 0);\n\n\tcl_timeNudge = Cvar_Get (\"cl_timeNudge\", \"0\", CVAR_TEMP );\n\tcl_shownet = Cvar_Get (\"cl_shownet\", \"0\", CVAR_TEMP );\n\tcl_showSend = Cvar_Get (\"cl_showSend\", \"0\", CVAR_TEMP );\n\tcl_showTimeDelta = Cvar_Get (\"cl_showTimeDelta\", \"0\", CVAR_TEMP );\n\tcl_freezeDemo = Cvar_Get (\"cl_freezeDemo\", \"0\", CVAR_TEMP );\n\trcon_client_password = Cvar_Get (\"rconPassword\", \"\", CVAR_TEMP );\n\tcl_activeAction = Cvar_Get( \"activeAction\", \"\", CVAR_TEMP );\n\n\tcl_timedemo = Cvar_Get (\"timedemo\", \"0\", 0);\n\tcl_avidemo = Cvar_Get (\"cl_avidemo\", \"0\", 0);\n\tcl_forceavidemo = Cvar_Get (\"cl_forceavidemo\", \"0\", 0);\n\n\trconAddress = Cvar_Get (\"rconAddress\", \"\", 0);\n\n\tcl_yawspeed = Cvar_Get (\"cl_yawspeed\", \"140\", CVAR_ARCHIVE);\n\tcl_pitchspeed = Cvar_Get (\"cl_pitchspeed\", \"140\", CVAR_ARCHIVE);\n\tcl_anglespeedkey = Cvar_Get (\"cl_anglespeedkey\", \"1.5\", 0);\n\n\tcl_maxpackets = Cvar_Get (\"cl_maxpackets\", \"30\", CVAR_ARCHIVE );\n\tcl_packetdup = Cvar_Get (\"cl_packetdup\", \"1\", CVAR_ARCHIVE );\n\n\tcl_run = Cvar_Get (\"cl_run\", \"1\", CVAR_ARCHIVE);\n\tcl_sensitivity = Cvar_Get (\"sensitivity\", \"5\", CVAR_ARCHIVE);\n\tcl_mouseAccel = Cvar_Get (\"cl_mouseAccel\", \"0\", CVAR_ARCHIVE);\n\tcl_freelook = Cvar_Get( \"cl_freelook\", \"1\", CVAR_ARCHIVE );\n\n\tcl_showMouseRate = Cvar_Get (\"cl_showmouserate\", \"0\", 0);\n\n\tcl_allowDownload = Cvar_Get (\"cl_allowDownload\", \"0\", CVAR_ARCHIVE);\n\n\tcl_conXOffset = Cvar_Get (\"cl_conXOffset\", \"0\", 0);\n#ifdef MACOS_X\n        // In game video is REALLY slow in Mac OS X right now due to driver slowness\n\tcl_inGameVideo = Cvar_Get (\"r_inGameVideo\", \"0\", CVAR_ARCHIVE);\n#else\n\tcl_inGameVideo = Cvar_Get (\"r_inGameVideo\", \"1\", CVAR_ARCHIVE);\n#endif\n\n\tcl_serverStatusResendTime = Cvar_Get (\"cl_serverStatusResendTime\", \"750\", 0);\n\n\t// init autoswitch so the ui will have it correctly even\n\t// if the cgame hasn't been started\n\tCvar_Get (\"cg_autoswitch\", \"1\", CVAR_ARCHIVE);\n\n\tm_pitch = Cvar_Get (\"m_pitch\", \"0.022\", CVAR_ARCHIVE);\n\tm_yaw = Cvar_Get (\"m_yaw\", \"0.022\", CVAR_ARCHIVE);\n\tm_forward = Cvar_Get (\"m_forward\", \"0.25\", CVAR_ARCHIVE);\n\tm_side = Cvar_Get (\"m_side\", \"0.25\", CVAR_ARCHIVE);\n#ifdef MACOS_X\n        // Input is jittery on OS X w/o this\n\tm_filter = Cvar_Get (\"m_filter\", \"1\", CVAR_ARCHIVE);\n#else\n\tm_filter = Cvar_Get (\"m_filter\", \"0\", CVAR_ARCHIVE);\n#endif\n\n\tcl_motdString = Cvar_Get( \"cl_motdString\", \"\", CVAR_ROM );\n\n\tCvar_Get( \"cl_maxPing\", \"800\", CVAR_ARCHIVE );\n\n\n\t// userinfo\n\tCvar_Get (\"name\", \"UnnamedPlayer\", CVAR_USERINFO | CVAR_ARCHIVE );\n\tCvar_Get (\"rate\", \"3000\", CVAR_USERINFO | CVAR_ARCHIVE );\n\tCvar_Get (\"snaps\", \"20\", CVAR_USERINFO | CVAR_ARCHIVE );\n\tCvar_Get (\"model\", \"sarge\", CVAR_USERINFO | CVAR_ARCHIVE );\n\tCvar_Get (\"headmodel\", \"sarge\", CVAR_USERINFO | CVAR_ARCHIVE );\n\tCvar_Get (\"team_model\", \"james\", CVAR_USERINFO | CVAR_ARCHIVE );\n\tCvar_Get (\"team_headmodel\", \"*james\", CVAR_USERINFO | CVAR_ARCHIVE );\n\tCvar_Get (\"g_redTeam\", \"Stroggs\", CVAR_SERVERINFO | CVAR_ARCHIVE);\n\tCvar_Get (\"g_blueTeam\", \"Pagans\", CVAR_SERVERINFO | CVAR_ARCHIVE);\n\tCvar_Get (\"color1\",  \"4\", CVAR_USERINFO | CVAR_ARCHIVE );\n\tCvar_Get (\"color2\", \"5\", CVAR_USERINFO | CVAR_ARCHIVE );\n\tCvar_Get (\"handicap\", \"100\", CVAR_USERINFO | CVAR_ARCHIVE );\n\tCvar_Get (\"teamtask\", \"0\", CVAR_USERINFO );\n\tCvar_Get (\"sex\", \"male\", CVAR_USERINFO | CVAR_ARCHIVE );\n\tCvar_Get (\"cl_anonymous\", \"0\", CVAR_USERINFO | CVAR_ARCHIVE );\n\n\tCvar_Get (\"password\", \"\", CVAR_USERINFO);\n\tCvar_Get (\"cg_predictItems\", \"1\", CVAR_USERINFO | CVAR_ARCHIVE );\n\n\n\t// cgame might not be initialized before menu is used\n\tCvar_Get (\"cg_viewsize\", \"100\", CVAR_ARCHIVE );\n\n\t//\n\t// register our commands\n\t//\n\tCmd_AddCommand (\"cmd\", CL_ForwardToServer_f);\n\tCmd_AddCommand (\"configstrings\", CL_Configstrings_f);\n\tCmd_AddCommand (\"clientinfo\", CL_Clientinfo_f);\n\tCmd_AddCommand (\"snd_restart\", CL_Snd_Restart_f);\n\tCmd_AddCommand (\"vid_restart\", CL_Vid_Restart_f);\n\tCmd_AddCommand (\"disconnect\", CL_Disconnect_f);\n\tCmd_AddCommand (\"record\", CL_Record_f);\n\tCmd_AddCommand (\"demo\", CL_PlayDemo_f);\n\tCmd_AddCommand (\"cinematic\", CL_PlayCinematic_f);\n\tCmd_AddCommand (\"stoprecord\", CL_StopRecord_f);\n\tCmd_AddCommand (\"connect\", CL_Connect_f);\n\tCmd_AddCommand (\"reconnect\", CL_Reconnect_f);\n\tCmd_AddCommand (\"localservers\", CL_LocalServers_f);\n\tCmd_AddCommand (\"globalservers\", CL_GlobalServers_f);\n\tCmd_AddCommand (\"rcon\", CL_Rcon_f);\n\tCmd_AddCommand (\"setenv\", CL_Setenv_f );\n\tCmd_AddCommand (\"ping\", CL_Ping_f );\n\tCmd_AddCommand (\"serverstatus\", CL_ServerStatus_f );\n\tCmd_AddCommand (\"showip\", CL_ShowIP_f );\n\tCmd_AddCommand (\"fs_openedList\", CL_OpenedPK3List_f );\n\tCmd_AddCommand (\"fs_referencedList\", CL_ReferencedPK3List_f );\n\tCmd_AddCommand (\"model\", CL_SetModel_f );\n\tCL_InitRef();\n\n\tSCR_Init ();\n\n\tCbuf_Execute ();\n\n\tCvar_Set( \"cl_running\", \"1\" );\n\n\tCom_Printf( \"----- Client Initialization Complete -----\\n\" );\n}\n\n\n/*\n===============\nCL_Shutdown\n\n===============\n*/\nvoid CL_Shutdown( void ) {\n\tstatic qboolean recursive = qfalse;\n\t\n\tCom_Printf( \"----- CL_Shutdown -----\\n\" );\n\n\tif ( recursive ) {\n\t\tprintf (\"recursive shutdown\\n\");\n\t\treturn;\n\t}\n\trecursive = qtrue;\n\n\tCL_Disconnect( qtrue );\n\n\tS_Shutdown();\n\tCL_ShutdownRef();\n\t\n\tCL_ShutdownUI();\n\n\tCmd_RemoveCommand (\"cmd\");\n\tCmd_RemoveCommand (\"configstrings\");\n\tCmd_RemoveCommand (\"userinfo\");\n\tCmd_RemoveCommand (\"snd_restart\");\n\tCmd_RemoveCommand (\"vid_restart\");\n\tCmd_RemoveCommand (\"disconnect\");\n\tCmd_RemoveCommand (\"record\");\n\tCmd_RemoveCommand (\"demo\");\n\tCmd_RemoveCommand (\"cinematic\");\n\tCmd_RemoveCommand (\"stoprecord\");\n\tCmd_RemoveCommand (\"connect\");\n\tCmd_RemoveCommand (\"localservers\");\n\tCmd_RemoveCommand (\"globalservers\");\n\tCmd_RemoveCommand (\"rcon\");\n\tCmd_RemoveCommand (\"setenv\");\n\tCmd_RemoveCommand (\"ping\");\n\tCmd_RemoveCommand (\"serverstatus\");\n\tCmd_RemoveCommand (\"showip\");\n\tCmd_RemoveCommand (\"model\");\n\n\tCvar_Set( \"cl_running\", \"0\" );\n\n\trecursive = qfalse;\n\n\tCom_Memset( &cls, 0, sizeof( cls ) );\n\n\tCom_Printf( \"-----------------------\\n\" );\n\n}\n\nstatic void CL_SetServerInfo(serverInfo_t *server, const char *info, int ping) {\n\tif (server) {\n\t\tif (info) {\n\t\t\tserver->clients = atoi(Info_ValueForKey(info, \"clients\"));\n\t\t\tQ_strncpyz(server->hostName,Info_ValueForKey(info, \"hostname\"), MAX_NAME_LENGTH);\n\t\t\tQ_strncpyz(server->mapName, Info_ValueForKey(info, \"mapname\"), MAX_NAME_LENGTH);\n\t\t\tserver->maxClients = atoi(Info_ValueForKey(info, \"sv_maxclients\"));\n\t\t\tQ_strncpyz(server->game,Info_ValueForKey(info, \"game\"), MAX_NAME_LENGTH);\n\t\t\tserver->gameType = atoi(Info_ValueForKey(info, \"gametype\"));\n\t\t\tserver->netType = atoi(Info_ValueForKey(info, \"nettype\"));\n\t\t\tserver->minPing = atoi(Info_ValueForKey(info, \"minping\"));\n\t\t\tserver->maxPing = atoi(Info_ValueForKey(info, \"maxping\"));\n\t\t\tserver->punkbuster = atoi(Info_ValueForKey(info, \"punkbuster\"));\n\t\t}\n\t\tserver->ping = ping;\n\t}\n}\n\nstatic void CL_SetServerInfoByAddress(netadr_t from, const char *info, int ping) {\n\tint i;\n\n\tfor (i = 0; i < MAX_OTHER_SERVERS; i++) {\n\t\tif (NET_CompareAdr(from, cls.localServers[i].adr)) {\n\t\t\tCL_SetServerInfo(&cls.localServers[i], info, ping);\n\t\t}\n\t}\n\n\tfor (i = 0; i < MAX_OTHER_SERVERS; i++) {\n\t\tif (NET_CompareAdr(from, cls.mplayerServers[i].adr)) {\n\t\t\tCL_SetServerInfo(&cls.mplayerServers[i], info, ping);\n\t\t}\n\t}\n\n\tfor (i = 0; i < MAX_GLOBAL_SERVERS; i++) {\n\t\tif (NET_CompareAdr(from, cls.globalServers[i].adr)) {\n\t\t\tCL_SetServerInfo(&cls.globalServers[i], info, ping);\n\t\t}\n\t}\n\n\tfor (i = 0; i < MAX_OTHER_SERVERS; i++) {\n\t\tif (NET_CompareAdr(from, cls.favoriteServers[i].adr)) {\n\t\t\tCL_SetServerInfo(&cls.favoriteServers[i], info, ping);\n\t\t}\n\t}\n\n}\n\n/*\n===================\nCL_ServerInfoPacket\n===================\n*/\nvoid CL_ServerInfoPacket( netadr_t from, msg_t *msg ) {\n\tint\t\ti, type;\n\tchar\tinfo[MAX_INFO_STRING];\n\tchar*\tstr;\n\tchar\t*infoString;\n\tint\t\tprot;\n\n\tinfoString = MSG_ReadString( msg );\n\n\t// if this isn't the correct protocol version, ignore it\n\tprot = atoi( Info_ValueForKey( infoString, \"protocol\" ) );\n\tif ( prot != PROTOCOL_VERSION ) {\n\t\tCom_DPrintf( \"Different protocol info packet: %s\\n\", infoString );\n\t\treturn;\n\t}\n\n\t// iterate servers waiting for ping response\n\tfor (i=0; i<MAX_PINGREQUESTS; i++)\n\t{\n\t\tif ( cl_pinglist[i].adr.port && !cl_pinglist[i].time && NET_CompareAdr( from, cl_pinglist[i].adr ) )\n\t\t{\n\t\t\t// calc ping time\n\t\t\tcl_pinglist[i].time = cls.realtime - cl_pinglist[i].start + 1;\n\t\t\tCom_DPrintf( \"ping time %dms from %s\\n\", cl_pinglist[i].time, NET_AdrToString( from ) );\n\n\t\t\t// save of info\n\t\t\tQ_strncpyz( cl_pinglist[i].info, infoString, sizeof( cl_pinglist[i].info ) );\n\n\t\t\t// tack on the net type\n\t\t\t// NOTE: make sure these types are in sync with the netnames strings in the UI\n\t\t\tswitch (from.type)\n\t\t\t{\n\t\t\t\tcase NA_BROADCAST:\n\t\t\t\tcase NA_IP:\n\t\t\t\t\tstr = \"udp\";\n\t\t\t\t\ttype = 1;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase NA_IPX:\n\t\t\t\tcase NA_BROADCAST_IPX:\n\t\t\t\t\tstr = \"ipx\";\n\t\t\t\t\ttype = 2;\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tstr = \"???\";\n\t\t\t\t\ttype = 0;\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tInfo_SetValueForKey( cl_pinglist[i].info, \"nettype\", va(\"%d\", type) );\n\t\t\tCL_SetServerInfoByAddress(from, infoString, cl_pinglist[i].time);\n\n\t\t\treturn;\n\t\t}\n\t}\n\n\t// if not just sent a local broadcast or pinging local servers\n\tif (cls.pingUpdateSource != AS_LOCAL) {\n\t\treturn;\n\t}\n\n\tfor ( i = 0 ; i < MAX_OTHER_SERVERS ; i++ ) {\n\t\t// empty slot\n\t\tif ( cls.localServers[i].adr.port == 0 ) {\n\t\t\tbreak;\n\t\t}\n\n\t\t// avoid duplicate\n\t\tif ( NET_CompareAdr( from, cls.localServers[i].adr ) ) {\n\t\t\treturn;\n\t\t}\n\t}\n\n\tif ( i == MAX_OTHER_SERVERS ) {\n\t\tCom_DPrintf( \"MAX_OTHER_SERVERS hit, dropping infoResponse\\n\" );\n\t\treturn;\n\t}\n\n\t// add this to the list\n\tcls.numlocalservers = i+1;\n\tcls.localServers[i].adr = from;\n\tcls.localServers[i].clients = 0;\n\tcls.localServers[i].hostName[0] = '\\0';\n\tcls.localServers[i].mapName[0] = '\\0';\n\tcls.localServers[i].maxClients = 0;\n\tcls.localServers[i].maxPing = 0;\n\tcls.localServers[i].minPing = 0;\n\tcls.localServers[i].ping = -1;\n\tcls.localServers[i].game[0] = '\\0';\n\tcls.localServers[i].gameType = 0;\n\tcls.localServers[i].netType = from.type;\n\tcls.localServers[i].punkbuster = 0;\n\t\t\t\t\t\t\t\t\t \n\tQ_strncpyz( info, MSG_ReadString( msg ), MAX_INFO_STRING );\n\tif (strlen(info)) {\n\t\tif (info[strlen(info)-1] != '\\n') {\n\t\t\tstrncat(info, \"\\n\", sizeof(info));\n\t\t}\n\t\tCom_Printf( \"%s: %s\", NET_AdrToString( from ), info );\n\t}\n}\n\n/*\n===================\nCL_GetServerStatus\n===================\n*/\nserverStatus_t *CL_GetServerStatus( netadr_t from ) {\n\tserverStatus_t *serverStatus;\n\tint i, oldest, oldestTime;\n\n\tserverStatus = NULL;\n\tfor (i = 0; i < MAX_SERVERSTATUSREQUESTS; i++) {\n\t\tif ( NET_CompareAdr( from, cl_serverStatusList[i].address ) ) {\n\t\t\treturn &cl_serverStatusList[i];\n\t\t}\n\t}\n\tfor (i = 0; i < MAX_SERVERSTATUSREQUESTS; i++) {\n\t\tif ( cl_serverStatusList[i].retrieved ) {\n\t\t\treturn &cl_serverStatusList[i];\n\t\t}\n\t}\n\toldest = -1;\n\toldestTime = 0;\n\tfor (i = 0; i < MAX_SERVERSTATUSREQUESTS; i++) {\n\t\tif (oldest == -1 || cl_serverStatusList[i].startTime < oldestTime) {\n\t\t\toldest = i;\n\t\t\toldestTime = cl_serverStatusList[i].startTime;\n\t\t}\n\t}\n\tif (oldest != -1) {\n\t\treturn &cl_serverStatusList[oldest];\n\t}\n\tserverStatusCount++;\n\treturn &cl_serverStatusList[serverStatusCount & (MAX_SERVERSTATUSREQUESTS-1)];\n}\n\n/*\n===================\nCL_ServerStatus\n===================\n*/\nint CL_ServerStatus( char *serverAddress, char *serverStatusString, int maxLen ) {\n\tint i;\n\tnetadr_t\tto;\n\tserverStatus_t *serverStatus;\n\n\t// if no server address then reset all server status requests\n\tif ( !serverAddress ) {\n\t\tfor (i = 0; i < MAX_SERVERSTATUSREQUESTS; i++) {\n\t\t\tcl_serverStatusList[i].address.port = 0;\n\t\t\tcl_serverStatusList[i].retrieved = qtrue;\n\t\t}\n\t\treturn qfalse;\n\t}\n\t// get the address\n\tif ( !NET_StringToAdr( serverAddress, &to ) ) {\n\t\treturn qfalse;\n\t}\n\tserverStatus = CL_GetServerStatus( to );\n\t// if no server status string then reset the server status request for this address\n\tif ( !serverStatusString ) {\n\t\tserverStatus->retrieved = qtrue;\n\t\treturn qfalse;\n\t}\n\n\t// if this server status request has the same address\n\tif ( NET_CompareAdr( to, serverStatus->address) ) {\n\t\t// if we recieved an response for this server status request\n\t\tif (!serverStatus->pending) {\n\t\t\tQ_strncpyz(serverStatusString, serverStatus->string, maxLen);\n\t\t\tserverStatus->retrieved = qtrue;\n\t\t\tserverStatus->startTime = 0;\n\t\t\treturn qtrue;\n\t\t}\n\t\t// resend the request regularly\n\t\telse if ( serverStatus->startTime < Com_Milliseconds() - cl_serverStatusResendTime->integer ) {\n\t\t\tserverStatus->print = qfalse;\n\t\t\tserverStatus->pending = qtrue;\n\t\t\tserverStatus->retrieved = qfalse;\n\t\t\tserverStatus->time = 0;\n\t\t\tserverStatus->startTime = Com_Milliseconds();\n\t\t\tNET_OutOfBandPrint( NS_CLIENT, to, \"getstatus\" );\n\t\t\treturn qfalse;\n\t\t}\n\t}\n\t// if retrieved\n\telse if ( serverStatus->retrieved ) {\n\t\tserverStatus->address = to;\n\t\tserverStatus->print = qfalse;\n\t\tserverStatus->pending = qtrue;\n\t\tserverStatus->retrieved = qfalse;\n\t\tserverStatus->startTime = Com_Milliseconds();\n\t\tserverStatus->time = 0;\n\t\tNET_OutOfBandPrint( NS_CLIENT, to, \"getstatus\" );\n\t\treturn qfalse;\n\t}\n\treturn qfalse;\n}\n\n/*\n===================\nCL_ServerStatusResponse\n===================\n*/\nvoid CL_ServerStatusResponse( netadr_t from, msg_t *msg ) {\n\tchar\t*s;\n\tchar\tinfo[MAX_INFO_STRING];\n\tint\t\ti, l, score, ping;\n\tint\t\tlen;\n\tserverStatus_t *serverStatus;\n\n\tserverStatus = NULL;\n\tfor (i = 0; i < MAX_SERVERSTATUSREQUESTS; i++) {\n\t\tif ( NET_CompareAdr( from, cl_serverStatusList[i].address ) ) {\n\t\t\tserverStatus = &cl_serverStatusList[i];\n\t\t\tbreak;\n\t\t}\n\t}\n\t// if we didn't request this server status\n\tif (!serverStatus) {\n\t\treturn;\n\t}\n\n\ts = MSG_ReadStringLine( msg );\n\n\tlen = 0;\n\tCom_sprintf(&serverStatus->string[len], sizeof(serverStatus->string)-len, \"%s\", s);\n\n\tif (serverStatus->print) {\n\t\tCom_Printf(\"Server settings:\\n\");\n\t\t// print cvars\n\t\twhile (*s) {\n\t\t\tfor (i = 0; i < 2 && *s; i++) {\n\t\t\t\tif (*s == '\\\\')\n\t\t\t\t\ts++;\n\t\t\t\tl = 0;\n\t\t\t\twhile (*s) {\n\t\t\t\t\tinfo[l++] = *s;\n\t\t\t\t\tif (l >= MAX_INFO_STRING-1)\n\t\t\t\t\t\tbreak;\n\t\t\t\t\ts++;\n\t\t\t\t\tif (*s == '\\\\') {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tinfo[l] = '\\0';\n\t\t\t\tif (i) {\n\t\t\t\t\tCom_Printf(\"%s\\n\", info);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tCom_Printf(\"%-24s\", info);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tlen = (int)strlen(serverStatus->string);\n\tCom_sprintf(&serverStatus->string[len], sizeof(serverStatus->string)-len, \"\\\\\");\n\n\tif (serverStatus->print) {\n\t\tCom_Printf(\"\\nPlayers:\\n\");\n\t\tCom_Printf(\"num: score: ping: name:\\n\");\n\t}\n\tfor (i = 0, s = MSG_ReadStringLine( msg ); *s; s = MSG_ReadStringLine( msg ), i++) {\n\n\t\tlen = (int)strlen(serverStatus->string);\n\t\tCom_sprintf(&serverStatus->string[len], sizeof(serverStatus->string)-len, \"\\\\%s\", s);\n\n\t\tif (serverStatus->print) {\n\t\t\tscore = ping = 0;\n\t\t\tsscanf(s, \"%d %d\", &score, &ping);\n\t\t\ts = strchr(s, ' ');\n\t\t\tif (s)\n\t\t\t\ts = strchr(s+1, ' ');\n\t\t\tif (s)\n\t\t\t\ts++;\n\t\t\telse\n\t\t\t\ts = \"unknown\";\n\t\t\tCom_Printf(\"%-2d   %-3d    %-3d   %s\\n\", i, score, ping, s );\n\t\t}\n\t}\n\tlen = (int)strlen(serverStatus->string);\n\tCom_sprintf(&serverStatus->string[len], sizeof(serverStatus->string)-len, \"\\\\\");\n\n\tserverStatus->time = Com_Milliseconds();\n\tserverStatus->address = from;\n\tserverStatus->pending = qfalse;\n\tif (serverStatus->print) {\n\t\tserverStatus->retrieved = qtrue;\n\t}\n}\n\n/*\n==================\nCL_LocalServers_f\n==================\n*/\nvoid CL_LocalServers_f( void ) {\n\tchar\t\t*message;\n\tint\t\t\ti, j;\n\tnetadr_t\tto;\n\n\tCom_Printf( \"Scanning for servers on the local network...\\n\");\n\n\t// reset the list, waiting for response\n\tcls.numlocalservers = 0;\n\tcls.pingUpdateSource = AS_LOCAL;\n\n\tfor (i = 0; i < MAX_OTHER_SERVERS; i++) {\n\t\tqboolean b = cls.localServers[i].visible;\n\t\tCom_Memset(&cls.localServers[i], 0, sizeof(cls.localServers[i]));\n\t\tcls.localServers[i].visible = b;\n\t}\n\tCom_Memset( &to, 0, sizeof( to ) );\n\n\t// The 'xxx' in the message is a challenge that will be echoed back\n\t// by the server.  We don't care about that here, but master servers\n\t// can use that to prevent spoofed server responses from invalid ip\n\tmessage = \"\\377\\377\\377\\377getinfo xxx\";\n\n\t// send each message twice in case one is dropped\n\tfor ( i = 0 ; i < 2 ; i++ ) {\n\t\t// send a broadcast packet on each server port\n\t\t// we support multiple server ports so a single machine\n\t\t// can nicely run multiple servers\n\t\tfor ( j = 0 ; j < NUM_SERVER_PORTS ; j++ ) {\n\t\t\tto.port = BigShort( (short)(PORT_SERVER + j) );\n\n\t\t\tto.type = NA_BROADCAST;\n\t\t\tNET_SendPacket( NS_CLIENT, (int)strlen( message ), message, to );\n\n\t\t\tto.type = NA_BROADCAST_IPX;\n\t\t\tNET_SendPacket( NS_CLIENT, (int)strlen( message ), message, to );\n\t\t}\n\t}\n}\n\n/*\n==================\nCL_GlobalServers_f\n==================\n*/\nvoid CL_GlobalServers_f( void ) {\n\tnetadr_t\tto;\n\tint\t\t\ti;\n\tint\t\t\tcount;\n\tchar\t\t*buffptr;\n\tchar\t\tcommand[1024];\n\t\n\tif ( Cmd_Argc() < 3) {\n\t\tCom_Printf( \"usage: globalservers <master# 0-1> <protocol> [keywords]\\n\");\n\t\treturn;\t\n\t}\n\n\tcls.masterNum = atoi( Cmd_Argv(1) );\n\n\tCom_Printf( \"Requesting servers from the master...\\n\");\n\n\t// reset the list, waiting for response\n\t// -1 is used to distinguish a \"no response\"\n\n\tif( cls.masterNum == 1 ) {\n\t\tNET_StringToAdr( MASTER_SERVER_NAME, &to );\n\t\tcls.nummplayerservers = -1;\n\t\tcls.pingUpdateSource = AS_MPLAYER;\n\t}\n\telse {\n\t\tNET_StringToAdr( MASTER_SERVER_NAME, &to );\n\t\tcls.numglobalservers = -1;\n\t\tcls.pingUpdateSource = AS_GLOBAL;\n\t}\n\tto.type = NA_IP;\n\tto.port = BigShort(PORT_MASTER);\n\n\tsprintf( command, \"getservers %s\", Cmd_Argv(2) );\n\n\t// tack on keywords\n\tbuffptr = command + (int)strlen( command );\n\tcount   = Cmd_Argc();\n\tfor (i=3; i<count; i++)\n\t\tbuffptr += sprintf( buffptr, \" %s\", Cmd_Argv(i) );\n\n\t// if we are a demo, automatically add a \"demo\" keyword\n\tif ( Cvar_VariableValue( \"fs_restrict\" ) ) {\n\t\tbuffptr += sprintf( buffptr, \" demo\" );\n\t}\n\n\tNET_OutOfBandPrint( NS_SERVER, to, command );\n}\n\n\n/*\n==================\nCL_GetPing\n==================\n*/\nvoid CL_GetPing( int n, char *buf, int buflen, int *pingtime )\n{\n\tconst char\t*str;\n\tint\t\ttime;\n\tint\t\tmaxPing;\n\n\tif (!cl_pinglist[n].adr.port)\n\t{\n\t\t// empty slot\n\t\tbuf[0]    = '\\0';\n\t\t*pingtime = 0;\n\t\treturn;\n\t}\n\n\tstr = NET_AdrToString( cl_pinglist[n].adr );\n\tQ_strncpyz( buf, str, buflen );\n\n\ttime = cl_pinglist[n].time;\n\tif (!time)\n\t{\n\t\t// check for timeout\n\t\ttime = cls.realtime - cl_pinglist[n].start;\n\t\tmaxPing = Cvar_VariableIntegerValue( \"cl_maxPing\" );\n\t\tif( maxPing < 100 ) {\n\t\t\tmaxPing = 100;\n\t\t}\n\t\tif (time < maxPing)\n\t\t{\n\t\t\t// not timed out yet\n\t\t\ttime = 0;\n\t\t}\n\t}\n\n\tCL_SetServerInfoByAddress(cl_pinglist[n].adr, cl_pinglist[n].info, cl_pinglist[n].time);\n\n\t*pingtime = time;\n}\n\n/*\n==================\nCL_UpdateServerInfo\n==================\n*/\nvoid CL_UpdateServerInfo( int n )\n{\n\tif (!cl_pinglist[n].adr.port)\n\t{\n\t\treturn;\n\t}\n\n\tCL_SetServerInfoByAddress(cl_pinglist[n].adr, cl_pinglist[n].info, cl_pinglist[n].time );\n}\n\n/*\n==================\nCL_GetPingInfo\n==================\n*/\nvoid CL_GetPingInfo( int n, char *buf, int buflen )\n{\n\tif (!cl_pinglist[n].adr.port)\n\t{\n\t\t// empty slot\n\t\tif (buflen)\n\t\t\tbuf[0] = '\\0';\n\t\treturn;\n\t}\n\n\tQ_strncpyz( buf, cl_pinglist[n].info, buflen );\n}\n\n/*\n==================\nCL_ClearPing\n==================\n*/\nvoid CL_ClearPing( int n )\n{\n\tif (n < 0 || n >= MAX_PINGREQUESTS)\n\t\treturn;\n\n\tcl_pinglist[n].adr.port = 0;\n}\n\n/*\n==================\nCL_GetPingQueueCount\n==================\n*/\nint CL_GetPingQueueCount( void )\n{\n\tint\t\ti;\n\tint\t\tcount;\n\tping_t*\tpingptr;\n\n\tcount   = 0;\n\tpingptr = cl_pinglist;\n\n\tfor (i=0; i<MAX_PINGREQUESTS; i++, pingptr++ ) {\n\t\tif (pingptr->adr.port) {\n\t\t\tcount++;\n\t\t}\n\t}\n\n\treturn (count);\n}\n\n/*\n==================\nCL_GetFreePing\n==================\n*/\nping_t* CL_GetFreePing( void )\n{\n\tping_t*\tpingptr;\n\tping_t*\tbest;\t\n\tint\t\toldest;\n\tint\t\ti;\n\tint\t\ttime;\n\n\tpingptr = cl_pinglist;\n\tfor (i=0; i<MAX_PINGREQUESTS; i++, pingptr++ )\n\t{\n\t\t// find free ping slot\n\t\tif (pingptr->adr.port)\n\t\t{\n\t\t\tif (!pingptr->time)\n\t\t\t{\n\t\t\t\tif (cls.realtime - pingptr->start < 500)\n\t\t\t\t{\n\t\t\t\t\t// still waiting for response\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (pingptr->time < 500)\n\t\t\t{\n\t\t\t\t// results have not been queried\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\t// clear it\n\t\tpingptr->adr.port = 0;\n\t\treturn (pingptr);\n\t}\n\n\t// use oldest entry\n\tpingptr = cl_pinglist;\n\tbest    = cl_pinglist;\n\toldest  = INT_MIN;\n\tfor (i=0; i<MAX_PINGREQUESTS; i++, pingptr++ )\n\t{\n\t\t// scan for oldest\n\t\ttime = cls.realtime - pingptr->start;\n\t\tif (time > oldest)\n\t\t{\n\t\t\toldest = time;\n\t\t\tbest   = pingptr;\n\t\t}\n\t}\n\n\treturn (best);\n}\n\n/*\n==================\nCL_Ping_f\n==================\n*/\nvoid CL_Ping_f( void ) {\n\tnetadr_t\tto;\n\tping_t*\t\tpingptr;\n\tchar*\t\tserver;\n\n\tif ( Cmd_Argc() != 2 ) {\n\t\tCom_Printf( \"usage: ping [server]\\n\");\n\t\treturn;\t\n\t}\n\n\tCom_Memset( &to, 0, sizeof(netadr_t) );\n\n\tserver = Cmd_Argv(1);\n\n\tif ( !NET_StringToAdr( server, &to ) ) {\n\t\treturn;\n\t}\n\n\tpingptr = CL_GetFreePing();\n\n\tmemcpy( &pingptr->adr, &to, sizeof (netadr_t) );\n\tpingptr->start = cls.realtime;\n\tpingptr->time  = 0;\n\n\tCL_SetServerInfoByAddress(pingptr->adr, NULL, 0);\n\t\t\n\tNET_OutOfBandPrint( NS_CLIENT, to, \"getinfo xxx\" );\n}\n\n/*\n==================\nCL_UpdateVisiblePings_f\n==================\n*/\nqboolean CL_UpdateVisiblePings_f(int source) {\n\tint\t\t\tslots, i;\n\tchar\t\tbuff[MAX_STRING_CHARS];\n\tint\t\t\tpingTime;\n\tint\t\t\tmax;\n\tqboolean status = qfalse;\n\n\tif (source < 0 || source > AS_FAVORITES) {\n\t\treturn qfalse;\n\t}\n\n\tcls.pingUpdateSource = source;\n\n\tslots = CL_GetPingQueueCount();\n\tif (slots < MAX_PINGREQUESTS) {\n\t\tserverInfo_t *server = NULL;\n\n\t\tmax = (source == AS_GLOBAL) ? MAX_GLOBAL_SERVERS : MAX_OTHER_SERVERS;\n\t\tswitch (source) {\n\t\t\tcase AS_LOCAL :\n\t\t\t\tserver = &cls.localServers[0];\n\t\t\t\tmax = cls.numlocalservers;\n\t\t\tbreak;\n\t\t\tcase AS_MPLAYER :\n\t\t\t\tserver = &cls.mplayerServers[0];\n\t\t\t\tmax = cls.nummplayerservers;\n\t\t\tbreak;\n\t\t\tcase AS_GLOBAL :\n\t\t\t\tserver = &cls.globalServers[0];\n\t\t\t\tmax = cls.numglobalservers;\n\t\t\tbreak;\n\t\t\tcase AS_FAVORITES :\n\t\t\t\tserver = &cls.favoriteServers[0];\n\t\t\t\tmax = cls.numfavoriteservers;\n\t\t\tbreak;\n\t\t}\n\t\tfor (i = 0; i < max; i++) {\n\t\t\tif (server[i].visible) {\n\t\t\t\tif (server[i].ping == -1) {\n\t\t\t\t\tint j;\n\n\t\t\t\t\tif (slots >= MAX_PINGREQUESTS) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tfor (j = 0; j < MAX_PINGREQUESTS; j++) {\n\t\t\t\t\t\tif (!cl_pinglist[j].adr.port) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (NET_CompareAdr( cl_pinglist[j].adr, server[i].adr)) {\n\t\t\t\t\t\t\t// already on the list\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (j >= MAX_PINGREQUESTS) {\n\t\t\t\t\t\tstatus = qtrue;\n\t\t\t\t\t\tfor (j = 0; j < MAX_PINGREQUESTS; j++) {\n\t\t\t\t\t\t\tif (!cl_pinglist[j].adr.port) {\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tmemcpy(&cl_pinglist[j].adr, &server[i].adr, sizeof(netadr_t));\n\t\t\t\t\t\tcl_pinglist[j].start = cls.realtime;\n\t\t\t\t\t\tcl_pinglist[j].time = 0;\n\t\t\t\t\t\tNET_OutOfBandPrint( NS_CLIENT, cl_pinglist[j].adr, \"getinfo xxx\" );\n\t\t\t\t\t\tslots++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// if the server has a ping higher than cl_maxPing or\n\t\t\t\t// the ping packet got lost\n\t\t\t\telse if (server[i].ping == 0) {\n\t\t\t\t\t// if we are updating global servers\n\t\t\t\t\tif (source == AS_GLOBAL) {\n\t\t\t\t\t\t//\n\t\t\t\t\t\tif ( cls.numGlobalServerAddresses > 0 ) {\n\t\t\t\t\t\t\t// overwrite this server with one from the additional global servers\n\t\t\t\t\t\t\tcls.numGlobalServerAddresses--;\n\t\t\t\t\t\t\tCL_InitServerInfo(&server[i], &cls.globalServerAddresses[cls.numGlobalServerAddresses]);\n\t\t\t\t\t\t\t// NOTE: the server[i].visible flag stays untouched\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} \n\n\tif (slots) {\n\t\tstatus = qtrue;\n\t}\n\tfor (i = 0; i < MAX_PINGREQUESTS; i++) {\n\t\tif (!cl_pinglist[i].adr.port) {\n\t\t\tcontinue;\n\t\t}\n\t\tCL_GetPing( i, buff, MAX_STRING_CHARS, &pingTime );\n\t\tif (pingTime != 0) {\n\t\t\tCL_ClearPing(i);\n\t\t\tstatus = qtrue;\n\t\t}\n\t}\n\n\treturn status;\n}\n\n/*\n==================\nCL_ServerStatus_f\n==================\n*/\nvoid CL_ServerStatus_f(void) {\n\tnetadr_t\tto;\n\tchar\t\t*server;\n\tserverStatus_t *serverStatus;\n\n\tCom_Memset( &to, 0, sizeof(netadr_t) );\n\n\tif ( Cmd_Argc() != 2 ) {\n\t\tif ( cls.state != CA_ACTIVE || clc.demoplaying ) {\n\t\t\tCom_Printf (\"Not connected to a server.\\n\");\n\t\t\tCom_Printf( \"Usage: serverstatus [server]\\n\");\n\t\t\treturn;\t\n\t\t}\n\t\tserver = cls.servername;\n\t}\n\telse {\n\t\tserver = Cmd_Argv(1);\n\t}\n\n\tif ( !NET_StringToAdr( server, &to ) ) {\n\t\treturn;\n\t}\n\n\tNET_OutOfBandPrint( NS_CLIENT, to, \"getstatus\" );\n\n\tserverStatus = CL_GetServerStatus( to );\n\tserverStatus->address = to;\n\tserverStatus->print = qtrue;\n\tserverStatus->pending = qtrue;\n}\n\n/*\n==================\nCL_ShowIP_f\n==================\n*/\nvoid CL_ShowIP_f(void) {\n\tSys_ShowIP();\n}\n\n/*\n=================\nbool CL_CDKeyValidate\n=================\n*/\nqboolean CL_CDKeyValidate( const char *key, const char *checksum ) {\n\tchar\tch;\n\tbyte\tsum;\n\tchar\tchs[3];\n\tint i, len;\n\n\tlen = (int)strlen(key);\n\tif( len != CDKEY_LEN ) {\n\t\treturn qfalse;\n\t}\n\n\tif( checksum && (int)strlen( checksum ) != CDCHKSUM_LEN ) {\n\t\treturn qfalse;\n\t}\n\n\tsum = 0;\n\t// for loop gets rid of conditional assignment warning\n\tfor (i = 0; i < len; i++) {\n\t\tch = *key++;\n\t\tif (ch>='a' && ch<='z') {\n\t\t\tch -= 32;\n\t\t}\n\t\tswitch( ch ) {\n\t\tcase '2':\n\t\tcase '3':\n\t\tcase '7':\n\t\tcase 'A':\n\t\tcase 'B':\n\t\tcase 'C':\n\t\tcase 'D':\n\t\tcase 'G':\n\t\tcase 'H':\n\t\tcase 'J':\n\t\tcase 'L':\n\t\tcase 'P':\n\t\tcase 'R':\n\t\tcase 'S':\n\t\tcase 'T':\n\t\tcase 'W':\n\t\t\tsum += ch;\n\t\t\tcontinue;\n\t\tdefault:\n\t\t\treturn qfalse;\n\t\t}\n\t}\n\n\tsprintf(chs, \"%02x\", sum);\n\t\n\tif (checksum && !Q_stricmp(chs, checksum)) {\n\t\treturn qtrue;\n\t}\n\n\tif (!checksum) {\n\t\treturn qtrue;\n\t}\n\n\treturn qfalse;\n}\n\n\n"
  },
  {
    "path": "src/engine/client/cl_net_chan.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n#include \"../../game/q_shared.h\"\n#include \"../qcommon/qcommon.h\"\n#include \"client.h\"\n\n/*\n==============\nCL_Netchan_Encode\n\n\t// first 12 bytes of the data are always:\n\tlong serverId;\n\tlong messageAcknowledge;\n\tlong reliableAcknowledge;\n\n==============\n*/\nstatic void CL_Netchan_Encode( msg_t *msg ) {\n\tint serverId, messageAcknowledge, reliableAcknowledge;\n\tint i, index, srdc, sbit, soob;\n\tbyte key, *string;\n\n\tif ( msg->cursize <= CL_ENCODE_START ) {\n\t\treturn;\n\t}\n\n        srdc = msg->readcount;\n        sbit = msg->bit;\n        soob = msg->oob;\n        \n        msg->bit = 0;\n        msg->readcount = 0;\n\t\tmsg->oob = (qboolean) 0;\n        \n        serverId = MSG_ReadLong(msg);\n\tmessageAcknowledge = MSG_ReadLong(msg);\n\treliableAcknowledge = MSG_ReadLong(msg);\n\n\tmsg->oob = (qboolean) soob;\n        msg->bit = sbit;\n        msg->readcount = srdc;\n        \n\tstring = (byte *)clc.serverCommands[ reliableAcknowledge & (MAX_RELIABLE_COMMANDS-1) ];\n\tindex = 0;\n\t//\n\tkey = clc.challenge ^ serverId ^ messageAcknowledge;\n\tfor (i = CL_ENCODE_START; i < msg->cursize; i++) {\n\t\t// modify the key with the last received now acknowledged server command\n\t\tif (!string[index])\n\t\t\tindex = 0;\n\t\tif (string[index] > 127 || string[index] == '%') {\n\t\t\tkey ^= '.' << (i & 1);\n\t\t}\n\t\telse {\n\t\t\tkey ^= string[index] << (i & 1);\n\t\t}\n\t\tindex++;\n\t\t// encode the data with this key\n\t\t*(msg->data + i) = (*(msg->data + i)) ^ key;\n\t}\n}\n\n/*\n==============\nCL_Netchan_Decode\n\n\t// first four bytes of the data are always:\n\tlong reliableAcknowledge;\n\n==============\n*/\nstatic void CL_Netchan_Decode( msg_t *msg ) {\n\tlong reliableAcknowledge, i, index;\n\tbyte key, *string;\n        int\tsrdc, sbit, soob;\n\n        srdc = msg->readcount;\n        sbit = msg->bit;\n        soob = msg->oob;\n        \n        msg->oob = (qboolean) 0;\n        \n\treliableAcknowledge = MSG_ReadLong(msg);\n\n        msg->oob = (qboolean) soob;\n        msg->bit = sbit;\n        msg->readcount = srdc;\n\n\tstring = (byte*) clc.reliableCommands[ reliableAcknowledge & (MAX_RELIABLE_COMMANDS-1) ];\n\tindex = 0;\n\t// xor the client challenge with the netchan sequence number (need something that changes every message)\n\tkey = clc.challenge ^ LittleLong( *(unsigned *)msg->data );\n\tfor (i = msg->readcount + CL_DECODE_START; i < msg->cursize; i++) {\n\t\t// modify the key with the last sent and with this message acknowledged client command\n\t\tif (!string[index])\n\t\t\tindex = 0;\n\t\tif (string[index] > 127 || string[index] == '%') {\n\t\t\tkey ^= '.' << (i & 1);\n\t\t}\n\t\telse {\n\t\t\tkey ^= string[index] << (i & 1);\n\t\t}\n\t\tindex++;\n\t\t// decode the data with this key\n\t\t*(msg->data + i) = *(msg->data + i) ^ key;\n\t}\n}\n\n/*\n=================\nCL_Netchan_TransmitNextFragment\n=================\n*/\nvoid CL_Netchan_TransmitNextFragment( netchan_t *chan ) {\n\tNetchan_TransmitNextFragment( chan );\n}\n\n/*\n===============\nCL_Netchan_Transmit\n================\n*/\nvoid CL_Netchan_Transmit( netchan_t *chan, msg_t* msg ) {\n\tMSG_WriteByte( msg, clc_EOF );\n\n\tCL_Netchan_Encode( msg );\n\tNetchan_Transmit( chan, msg->cursize, msg->data );\n}\n\nextern \tint oldsize;\nint newsize = 0;\n\n/*\n=================\nCL_Netchan_Process\n=================\n*/\nqboolean CL_Netchan_Process( netchan_t *chan, msg_t *msg ) {\n\tint ret;\n\n\tret = Netchan_Process( chan, msg );\n\tif (!ret)\n\t\treturn qfalse;\n\tCL_Netchan_Decode( msg );\n\tnewsize += msg->cursize;\n\treturn qtrue;\n}\n"
  },
  {
    "path": "src/engine/client/cl_parse.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n// cl_parse.c  -- parse a message received from the server\n\n#include \"client.h\"\n\nchar *svc_strings[256] = {\n\t\"svc_bad\",\n\n\t\"svc_nop\",\n\t\"svc_gamestate\",\n\t\"svc_configstring\",\n\t\"svc_baseline\",\t\n\t\"svc_serverCommand\",\n\t\"svc_download\",\n\t\"svc_snapshot\"\n};\n\nvoid SHOWNET( msg_t *msg, char *s) {\n\tif ( cl_shownet->integer >= 2) {\n\t\tCom_Printf (\"%3i:%s\\n\", msg->readcount-1, s);\n\t}\n}\n\n\n/*\n=========================================================================\n\nMESSAGE PARSING\n\n=========================================================================\n*/\n\n/*\n==================\nCL_DeltaEntity\n\nParses deltas from the given base and adds the resulting entity\nto the current frame\n==================\n*/\nvoid CL_DeltaEntity (msg_t *msg, clSnapshot_t *frame, int newnum, entityState_t *old, \n\t\t\t\t\t qboolean unchanged) {\n\tentityState_t\t*state;\n\n\t// save the parsed entity state into the big circular buffer so\n\t// it can be used as the source for a later delta\n\tstate = &cl.parseEntities[cl.parseEntitiesNum & (MAX_PARSE_ENTITIES-1)];\n\n\tif ( unchanged ) {\n\t\t*state = *old;\n\t} else {\n\t\tMSG_ReadDeltaEntity( msg, old, state, newnum );\n\t}\n\n\tif ( state->number == (MAX_GENTITIES-1) ) {\n\t\treturn;\t\t// entity was delta removed\n\t}\n\tcl.parseEntitiesNum++;\n\tframe->numEntities++;\n}\n\n/*\n==================\nCL_ParsePacketEntities\n\n==================\n*/\nvoid CL_ParsePacketEntities( msg_t *msg, clSnapshot_t *oldframe, clSnapshot_t *newframe) {\n\tint\t\t\tnewnum;\n\tentityState_t\t*oldstate;\n\tint\t\t\toldindex, oldnum;\n\n\tnewframe->parseEntitiesNum = cl.parseEntitiesNum;\n\tnewframe->numEntities = 0;\n\n\t// delta from the entities present in oldframe\n\toldindex = 0;\n\toldstate = NULL;\n\tif (!oldframe) {\n\t\toldnum = 99999;\n\t} else {\n\t\tif ( oldindex >= oldframe->numEntities ) {\n\t\t\toldnum = 99999;\n\t\t} else {\n\t\t\toldstate = &cl.parseEntities[\n\t\t\t\t(oldframe->parseEntitiesNum + oldindex) & (MAX_PARSE_ENTITIES-1)];\n\t\t\toldnum = oldstate->number;\n\t\t}\n\t}\n\n\twhile ( 1 ) {\n\t\t// read the entity index number\n\t\tnewnum = MSG_ReadBits( msg, GENTITYNUM_BITS );\n\n\t\tif ( newnum == (MAX_GENTITIES-1) ) {\n\t\t\tbreak;\n\t\t}\n\n\t\tif ( msg->readcount > msg->cursize ) {\n\t\t\tCom_Error (ERR_DROP,\"CL_ParsePacketEntities: end of message\");\n\t\t}\n\n\t\twhile ( oldnum < newnum ) {\n\t\t\t// one or more entities from the old packet are unchanged\n\t\t\tif ( cl_shownet->integer == 3 ) {\n\t\t\t\tCom_Printf (\"%3i:  unchanged: %i\\n\", msg->readcount, oldnum);\n\t\t\t}\n\t\t\tCL_DeltaEntity( msg, newframe, oldnum, oldstate, qtrue );\n\t\t\t\n\t\t\toldindex++;\n\n\t\t\tif ( oldindex >= oldframe->numEntities ) {\n\t\t\t\toldnum = 99999;\n\t\t\t} else {\n\t\t\t\toldstate = &cl.parseEntities[\n\t\t\t\t\t(oldframe->parseEntitiesNum + oldindex) & (MAX_PARSE_ENTITIES-1)];\n\t\t\t\toldnum = oldstate->number;\n\t\t\t}\n\t\t}\n\t\tif (oldnum == newnum) {\n\t\t\t// delta from previous state\n\t\t\tif ( cl_shownet->integer == 3 ) {\n\t\t\t\tCom_Printf (\"%3i:  delta: %i\\n\", msg->readcount, newnum);\n\t\t\t}\n\t\t\tCL_DeltaEntity( msg, newframe, newnum, oldstate, qfalse );\n\n\t\t\toldindex++;\n\n\t\t\tif ( oldindex >= oldframe->numEntities ) {\n\t\t\t\toldnum = 99999;\n\t\t\t} else {\n\t\t\t\toldstate = &cl.parseEntities[\n\t\t\t\t\t(oldframe->parseEntitiesNum + oldindex) & (MAX_PARSE_ENTITIES-1)];\n\t\t\t\toldnum = oldstate->number;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tif ( oldnum > newnum ) {\n\t\t\t// delta from baseline\n\t\t\tif ( cl_shownet->integer == 3 ) {\n\t\t\t\tCom_Printf (\"%3i:  baseline: %i\\n\", msg->readcount, newnum);\n\t\t\t}\n\t\t\tCL_DeltaEntity( msg, newframe, newnum, &cl.entityBaselines[newnum], qfalse );\n\t\t\tcontinue;\n\t\t}\n\n\t}\n\n\t// any remaining entities in the old frame are copied over\n\twhile ( oldnum != 99999 ) {\n\t\t// one or more entities from the old packet are unchanged\n\t\tif ( cl_shownet->integer == 3 ) {\n\t\t\tCom_Printf (\"%3i:  unchanged: %i\\n\", msg->readcount, oldnum);\n\t\t}\n\t\tCL_DeltaEntity( msg, newframe, oldnum, oldstate, qtrue );\n\t\t\n\t\toldindex++;\n\n\t\tif ( oldindex >= oldframe->numEntities ) {\n\t\t\toldnum = 99999;\n\t\t} else {\n\t\t\toldstate = &cl.parseEntities[\n\t\t\t\t(oldframe->parseEntitiesNum + oldindex) & (MAX_PARSE_ENTITIES-1)];\n\t\t\toldnum = oldstate->number;\n\t\t}\n\t}\n}\n\n\n/*\n================\nCL_ParseSnapshot\n\nIf the snapshot is parsed properly, it will be copied to\ncl.snap and saved in cl.snapshots[].  If the snapshot is invalid\nfor any reason, no changes to the state will be made at all.\n================\n*/\nvoid CL_ParseSnapshot( msg_t *msg ) {\n\tint\t\t\tlen;\n\tclSnapshot_t\t*old;\n\tclSnapshot_t\tnewSnap;\n\tint\t\t\tdeltaNum;\n\tint\t\t\toldMessageNum;\n\tint\t\t\ti, packetNum;\n\n\t// get the reliable sequence acknowledge number\n\t// NOTE: now sent with all server to client messages\n\t//clc.reliableAcknowledge = MSG_ReadLong( msg );\n\n\t// read in the new snapshot to a temporary buffer\n\t// we will only copy to cl.snap if it is valid\n\tCom_Memset (&newSnap, 0, sizeof(newSnap));\n\n\t// we will have read any new server commands in this\n\t// message before we got to svc_snapshot\n\tnewSnap.serverCommandNum = clc.serverCommandSequence;\n\n\tnewSnap.serverTime = MSG_ReadLong( msg );\n\n\tnewSnap.messageNum = clc.serverMessageSequence;\n\n\tdeltaNum = MSG_ReadByte( msg );\n\tif ( !deltaNum ) {\n\t\tnewSnap.deltaNum = -1;\n\t} else {\n\t\tnewSnap.deltaNum = newSnap.messageNum - deltaNum;\n\t}\n\tnewSnap.snapFlags = MSG_ReadByte( msg );\n\n\t// If the frame is delta compressed from data that we\n\t// no longer have available, we must suck up the rest of\n\t// the frame, but not use it, then ask for a non-compressed\n\t// message \n\tif ( newSnap.deltaNum <= 0 ) {\n\t\tnewSnap.valid = qtrue;\t\t// uncompressed frame\n\t\told = NULL;\n\t\tclc.demowaiting = qfalse;\t// we can start recording now\n\t} else {\n\t\told = &cl.snapshots[newSnap.deltaNum & PACKET_MASK];\n\t\tif ( !old->valid ) {\n\t\t\t// should never happen\n\t\t\tCom_Printf (\"Delta from invalid frame (not supposed to happen!).\\n\");\n\t\t} else if ( old->messageNum != newSnap.deltaNum ) {\n\t\t\t// The frame that the server did the delta from\n\t\t\t// is too old, so we can't reconstruct it properly.\n\t\t\tCom_Printf (\"Delta frame too old.\\n\");\n\t\t} else if ( cl.parseEntitiesNum - old->parseEntitiesNum > MAX_PARSE_ENTITIES-128 ) {\n\t\t\tCom_Printf (\"Delta parseEntitiesNum too old.\\n\");\n\t\t} else {\n\t\t\tnewSnap.valid = qtrue;\t// valid delta parse\n\t\t}\n\t}\n\n\t// read areamask\n\tlen = MSG_ReadByte( msg );\n\tMSG_ReadData( msg, &newSnap.areamask, len);\n\n\t// read playerinfo\n\tSHOWNET( msg, \"playerstate\" );\n\tif ( old ) {\n\t\tMSG_ReadDeltaPlayerstate( msg, &old->ps, &newSnap.ps );\n\t} else {\n\t\tMSG_ReadDeltaPlayerstate( msg, NULL, &newSnap.ps );\n\t}\n\n\t// read packet entities\n\tSHOWNET( msg, \"packet entities\" );\n\tCL_ParsePacketEntities( msg, old, &newSnap );\n\n\t// if not valid, dump the entire thing now that it has\n\t// been properly read\n\tif ( !newSnap.valid ) {\n\t\treturn;\n\t}\n\n\t// clear the valid flags of any snapshots between the last\n\t// received and this one, so if there was a dropped packet\n\t// it won't look like something valid to delta from next\n\t// time we wrap around in the buffer\n\toldMessageNum = cl.snap.messageNum + 1;\n\n\tif ( newSnap.messageNum - oldMessageNum >= PACKET_BACKUP ) {\n\t\toldMessageNum = newSnap.messageNum - ( PACKET_BACKUP - 1 );\n\t}\n\tfor ( ; oldMessageNum < newSnap.messageNum ; oldMessageNum++ ) {\n\t\tcl.snapshots[oldMessageNum & PACKET_MASK].valid = qfalse;\n\t}\n\n\t// copy to the current good spot\n\tcl.snap = newSnap;\n\tcl.snap.ping = 999;\n\t// calculate ping time\n\tfor ( i = 0 ; i < PACKET_BACKUP ; i++ ) {\n\t\tpacketNum = ( clc.netchan.outgoingSequence - 1 - i ) & PACKET_MASK;\n\t\tif ( cl.snap.ps.commandTime >= cl.outPackets[ packetNum ].p_serverTime ) {\n\t\t\tcl.snap.ping = cls.realtime - cl.outPackets[ packetNum ].p_realtime;\n\t\t\tbreak;\n\t\t}\n\t}\n\t// save the frame off in the backup array for later delta comparisons\n\tcl.snapshots[cl.snap.messageNum & PACKET_MASK] = cl.snap;\n\n\tif (cl_shownet->integer == 3) {\n\t\tCom_Printf( \"   snapshot:%i  delta:%i  ping:%i\\n\", cl.snap.messageNum,\n\t\tcl.snap.deltaNum, cl.snap.ping );\n\t}\n\n\tcl.newSnapshots = qtrue;\n}\n\n\n//=====================================================================\n\nint cl_connectedToPureServer;\n\n/*\n==================\nCL_SystemInfoChanged\n\nThe systeminfo configstring has been changed, so parse\nnew information out of it.  This will happen at every\ngamestate, and possibly during gameplay.\n==================\n*/\nvoid CL_SystemInfoChanged( void ) {\n\tchar\t\t\t*systemInfo;\n\tconst char\t\t*s, *t;\n\tchar\t\t\tkey[BIG_INFO_KEY];\n\tchar\t\t\tvalue[BIG_INFO_VALUE];\n\tqboolean\t\tgameSet;\n\n\tsystemInfo = cl.gameState.stringData + cl.gameState.stringOffsets[ CS_SYSTEMINFO ];\n\t// NOTE TTimo:\n\t// when the serverId changes, any further messages we send to the server will use this new serverId\n\t// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=475\n\t// in some cases, outdated cp commands might get sent with this news serverId\n\tcl.serverId = atoi( Info_ValueForKey( systemInfo, \"sv_serverid\" ) );\n\n\t// don't set any vars when playing a demo\n\tif ( clc.demoplaying ) {\n\t\treturn;\n\t}\n\n\ts = Info_ValueForKey( systemInfo, \"sv_cheats\" );\n\tif ( atoi(s) == 0 ) {\n\t\tCvar_SetCheatState();\n\t}\n\n\t// check pure server string\n\ts = Info_ValueForKey( systemInfo, \"sv_paks\" );\n\tt = Info_ValueForKey( systemInfo, \"sv_pakNames\" );\n\tFS_PureServerSetLoadedPaks( s, t );\n\n\ts = Info_ValueForKey( systemInfo, \"sv_referencedPaks\" );\n\tt = Info_ValueForKey( systemInfo, \"sv_referencedPakNames\" );\n\tFS_PureServerSetReferencedPaks( s, t );\n\n\tgameSet = qfalse;\n\t// scan through all the variables in the systeminfo and locally set cvars to match\n\ts = systemInfo;\n\twhile ( s ) {\n\t\tInfo_NextPair( &s, key, value );\n\t\tif ( !key[0] ) {\n\t\t\tbreak;\n\t\t}\n\t\t// ehw!\n\t\tif ( !Q_stricmp( key, \"fs_game\" ) ) {\n\t\t\tgameSet = qtrue;\n\t\t}\n\n\t\tCvar_Set( key, value );\n\t}\n\t// if game folder should not be set and it is set at the client side\n\tif ( !gameSet && *Cvar_VariableString(\"fs_game\") ) {\n\t\tCvar_Set( \"fs_game\", \"\" );\n\t}\n\tcl_connectedToPureServer = Cvar_VariableValue( \"sv_pure\" );\n}\n\n/*\n==================\nCL_ParseGamestate\n==================\n*/\nvoid CL_ParseGamestate( msg_t *msg ) {\n\tint\t\t\t\ti;\n\tentityState_t\t*es;\n\tint\t\t\t\tnewnum;\n\tentityState_t\tnullstate;\n\tint\t\t\t\tcmd;\n\tchar\t\t\t*s;\n\n\tCon_Close();\n\n\tclc.connectPacketCount = 0;\n\n\t// wipe local client state\n\tCL_ClearState();\n\n\t// a gamestate always marks a server command sequence\n\tclc.serverCommandSequence = MSG_ReadLong( msg );\n\n\t// parse all the configstrings and baselines\n\tcl.gameState.dataCount = 1;\t// leave a 0 at the beginning for uninitialized configstrings\n\twhile ( 1 ) {\n\t\tcmd = MSG_ReadByte( msg );\n\n\t\tif ( cmd == svc_EOF ) {\n\t\t\tbreak;\n\t\t}\n\t\t\n\t\tif ( cmd == svc_configstring ) {\n\t\t\tint\t\tlen;\n\n\t\t\ti = MSG_ReadShort( msg );\n\t\t\tif ( i < 0 || i >= MAX_CONFIGSTRINGS ) {\n\t\t\t\tCom_Error( ERR_DROP, \"configstring > MAX_CONFIGSTRINGS\" );\n\t\t\t}\n\t\t\ts = MSG_ReadBigString( msg );\n\t\t\tlen = (int)strlen( s );\n\n\t\t\tif ( len + 1 + cl.gameState.dataCount > MAX_GAMESTATE_CHARS ) {\n\t\t\t\tCom_Error( ERR_DROP, \"MAX_GAMESTATE_CHARS exceeded\" );\n\t\t\t}\n\n\t\t\t// append it to the gameState string buffer\n\t\t\tcl.gameState.stringOffsets[ i ] = cl.gameState.dataCount;\n\t\t\tCom_Memcpy( cl.gameState.stringData + cl.gameState.dataCount, s, len + 1 );\n\t\t\tcl.gameState.dataCount += len + 1;\n\t\t} else if ( cmd == svc_baseline ) {\n\t\t\tnewnum = MSG_ReadBits( msg, GENTITYNUM_BITS );\n\t\t\tif ( newnum < 0 || newnum >= MAX_GENTITIES ) {\n\t\t\t\tCom_Error( ERR_DROP, \"Baseline number out of range: %i\", newnum );\n\t\t\t}\n\t\t\tCom_Memset (&nullstate, 0, sizeof(nullstate));\n\t\t\tes = &cl.entityBaselines[ newnum ];\n\t\t\tMSG_ReadDeltaEntity( msg, &nullstate, es, newnum );\n\t\t} else {\n\t\t\tCom_Error( ERR_DROP, \"CL_ParseGamestate: bad command byte\" );\n\t\t}\n\t}\n\n\tclc.clientNum = MSG_ReadLong(msg);\n\t// read the checksum feed\n\tclc.checksumFeed = MSG_ReadLong( msg );\n\n\t// parse serverId and other cvars\n\tCL_SystemInfoChanged();\n\n\t// reinitialize the filesystem if the game directory has changed\n  FS_ConditionalRestart( clc.checksumFeed );\n\n\t// This used to call CL_StartHunkUsers, but now we enter the download state before loading the\n\t// cgame\n\tCL_InitDownloads();\n\n\t// make sure the game starts\n\tCvar_Set( \"cl_paused\", \"0\" );\n}\n\n\n//=====================================================================\n\n/*\n=====================\nCL_ParseDownload\n\nA download message has been received from the server\n=====================\n*/\nvoid CL_ParseDownload ( msg_t *msg ) {\n\tint\t\tsize;\n\tunsigned char data[MAX_MSGLEN];\n\tint block;\n\n\t// read the data\n\tblock = MSG_ReadShort ( msg );\n\n\tif ( !block )\n\t{\n\t\t// block zero is special, contains file size\n\t\tclc.downloadSize = MSG_ReadLong ( msg );\n\n\t\tCvar_SetValue( \"cl_downloadSize\", clc.downloadSize );\n\n\t\tif (clc.downloadSize < 0)\n\t\t{\n\t\t\tCom_Error(ERR_DROP, MSG_ReadString( msg ) );\n\t\t\treturn;\n\t\t}\n\t}\n\n\tsize = MSG_ReadShort ( msg );\n\tif (size > 0)\n\t\tMSG_ReadData( msg, data, size );\n\n\tif (clc.downloadBlock != block) {\n\t\tCom_DPrintf( \"CL_ParseDownload: Expected block %d, got %d\\n\", clc.downloadBlock, block);\n\t\treturn;\n\t}\n\n\t// open the file if not opened yet\n\tif (!clc.download)\n\t{\n\t\tif (!*clc.downloadTempName) {\n\t\t\tCom_Printf(\"Server sending download, but no download was requested\\n\");\n\t\t\tCL_AddReliableCommand( \"stopdl\" );\n\t\t\treturn;\n\t\t}\n\n\t\tclc.download = FS_SV_FOpenFileWrite( clc.downloadTempName );\n\n\t\tif (!clc.download) {\n\t\t\tCom_Printf( \"Could not create %s\\n\", clc.downloadTempName );\n\t\t\tCL_AddReliableCommand( \"stopdl\" );\n\t\t\tCL_NextDownload();\n\t\t\treturn;\n\t\t}\n\t}\n\n\tif (size)\n\t\tFS_Write( data, size, clc.download );\n\n\tCL_AddReliableCommand( va(\"nextdl %d\", clc.downloadBlock) );\n\tclc.downloadBlock++;\n\n\tclc.downloadCount += size;\n\n\t// So UI gets access to it\n\tCvar_SetValue( \"cl_downloadCount\", clc.downloadCount );\n\n\tif (!size) { // A zero length block means EOF\n\t\tif (clc.download) {\n\t\t\tFS_FCloseFile( clc.download );\n\t\t\tclc.download = 0;\n\n\t\t\t// rename the file\n\t\t\tFS_SV_Rename ( clc.downloadTempName, clc.downloadName );\n\t\t}\n\t\t*clc.downloadTempName = *clc.downloadName = 0;\n\t\tCvar_Set( \"cl_downloadName\", \"\" );\n\n\t\t// send intentions now\n\t\t// We need this because without it, we would hold the last nextdl and then start\n\t\t// loading right away.  If we take a while to load, the server is happily trying\n\t\t// to send us that last block over and over.\n\t\t// Write it twice to help make sure we acknowledge the download\n\t\tCL_WritePacket();\n\t\tCL_WritePacket();\n\n\t\t// get another file if needed\n\t\tCL_NextDownload ();\n\t}\n}\n\n/*\n=====================\nCL_ParseCommandString\n\nCommand strings are just saved off until cgame asks for them\nwhen it transitions a snapshot\n=====================\n*/\nvoid CL_ParseCommandString( msg_t *msg ) {\n\tchar\t*s;\n\tint\t\tseq;\n\tint\t\tindex;\n\n\tseq = MSG_ReadLong( msg );\n\ts = MSG_ReadString( msg );\n\n\t// see if we have already executed stored it off\n\tif ( clc.serverCommandSequence >= seq ) {\n\t\treturn;\n\t}\n\tclc.serverCommandSequence = seq;\n\n\tindex = seq & (MAX_RELIABLE_COMMANDS-1);\n\tQ_strncpyz( clc.serverCommands[ index ], s, sizeof( clc.serverCommands[ index ] ) );\n}\n\n\n/*\n=====================\nCL_ParseServerMessage\n=====================\n*/\nvoid CL_ParseServerMessage( msg_t *msg ) {\n\tint\t\t\tcmd;\n\n\tif ( cl_shownet->integer == 1 ) {\n\t\tCom_Printf (\"%i \",msg->cursize);\n\t} else if ( cl_shownet->integer >= 2 ) {\n\t\tCom_Printf (\"------------------\\n\");\n\t}\n\n\tMSG_Bitstream(msg);\n\n\t// get the reliable sequence acknowledge number\n\tclc.reliableAcknowledge = MSG_ReadLong( msg );\n\t// \n\tif ( clc.reliableAcknowledge < clc.reliableSequence - MAX_RELIABLE_COMMANDS ) {\n\t\tclc.reliableAcknowledge = clc.reliableSequence;\n\t}\n\n\t//\n\t// parse the message\n\t//\n\twhile ( 1 ) {\n\t\tif ( msg->readcount > msg->cursize ) {\n\t\t\tCom_Error (ERR_DROP,\"CL_ParseServerMessage: read past end of server message\");\n\t\t\tbreak;\n\t\t}\n\n\t\tcmd = MSG_ReadByte( msg );\n\n\t\tif ( cmd == svc_EOF) {\n\t\t\tSHOWNET( msg, \"END OF MESSAGE\" );\n\t\t\tbreak;\n\t\t}\n\n\t\tif ( cl_shownet->integer >= 2 ) {\n\t\t\tif ( !svc_strings[cmd] ) {\n\t\t\t\tCom_Printf( \"%3i:BAD CMD %i\\n\", msg->readcount-1, cmd );\n\t\t\t} else {\n\t\t\t\tSHOWNET( msg, svc_strings[cmd] );\n\t\t\t}\n\t\t}\n\t\n\t// other commands\n\t\tswitch ( cmd ) {\n\t\tdefault:\n\t\t\tCom_Error (ERR_DROP,\"CL_ParseServerMessage: Illegible server message\\n\");\n\t\t\tbreak;\t\t\t\n\t\tcase svc_nop:\n\t\t\tbreak;\n\t\tcase svc_serverCommand:\n\t\t\tCL_ParseCommandString( msg );\n\t\t\tbreak;\n\t\tcase svc_gamestate:\n\t\t\tCL_ParseGamestate( msg );\n\t\t\tbreak;\n\t\tcase svc_snapshot:\n\t\t\tCL_ParseSnapshot( msg );\n\t\t\tbreak;\n\t\tcase svc_download:\n\t\t\tCL_ParseDownload( msg );\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\n\n"
  },
  {
    "path": "src/engine/client/cl_scrn.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n// cl_scrn.c -- master for refresh, status bar, console, chat, notify, etc\n\n#include \"client.h\"\n\nqboolean\tscr_initialized;\t\t// ready to draw\n\ncvar_t\t\t*cl_timegraph;\ncvar_t\t\t*cl_debuggraph;\ncvar_t\t\t*cl_graphheight;\ncvar_t\t\t*cl_graphscale;\ncvar_t\t\t*cl_graphshift;\n\n/*\n================\nSCR_DrawNamedPic\n\nCoordinates are 640*480 virtual values\n=================\n*/\nvoid SCR_DrawNamedPic( float x, float y, float width, float height, const char *picname ) {\n\tqhandle_t\thShader;\n\n\tassert( width != 0 );\n\n\thShader = re.RegisterShader( picname );\n\tSCR_AdjustFrom640( &x, &y, &width, &height );\n\tre.DrawStretchPic( x, y, width, height, 0, 0, 1, 1, hShader );\n}\n\n\n/*\n================\nSCR_AdjustFrom640\n\nAdjusted for resolution and screen aspect ratio\n================\n*/\nvoid SCR_AdjustFrom640( float *x, float *y, float *w, float *h ) {\n\tfloat\txscale;\n\tfloat\tyscale;\n\n#if 0\n\t\t// adjust for wide screens\n\t\tif ( cls.glconfig.vidWidth * 480 > cls.glconfig.vidHeight * 640 ) {\n\t\t\t*x += 0.5 * ( cls.glconfig.vidWidth - ( cls.glconfig.vidHeight * 640 / 480 ) );\n\t\t}\n#endif\n\n\t// scale for screen sizes\n\txscale = cls.glconfig.vidWidth / 640.0;\n\tyscale = cls.glconfig.vidHeight / 480.0;\n\tif ( x ) {\n\t\t*x *= xscale;\n\t}\n\tif ( y ) {\n\t\t*y *= yscale;\n\t}\n\tif ( w ) {\n\t\t*w *= xscale;\n\t}\n\tif ( h ) {\n\t\t*h *= yscale;\n\t}\n}\n\n/*\n================\nSCR_FillRect\n\nCoordinates are 640*480 virtual values\n=================\n*/\nvoid SCR_FillRect( float x, float y, float width, float height, const float *color ) {\n\tre.SetColor( color );\n\n\tSCR_AdjustFrom640( &x, &y, &width, &height );\n\tre.DrawStretchPic( x, y, width, height, 0, 0, 0, 0, cls.whiteShader );\n\n\tre.SetColor( NULL );\n}\n\n\n/*\n================\nSCR_DrawPic\n\nCoordinates are 640*480 virtual values\n=================\n*/\nvoid SCR_DrawPic( float x, float y, float width, float height, qhandle_t hShader ) {\n\tSCR_AdjustFrom640( &x, &y, &width, &height );\n\tre.DrawStretchPic( x, y, width, height, 0, 0, 1, 1, hShader );\n}\n\n\n\n/*\n** SCR_DrawChar\n** chars are drawn at 640*480 virtual screen size\n*/\nstatic void SCR_DrawChar( int x, int y, float size, int ch ) {\n\tint row, col;\n\tfloat frow, fcol;\n\tfloat\tax, ay, aw, ah;\n\n\tch &= 255;\n\n\tif ( ch == ' ' ) {\n\t\treturn;\n\t}\n\n\tif ( y < -size ) {\n\t\treturn;\n\t}\n\n\tax = x;\n\tay = y;\n\taw = size;\n\tah = size;\n\tSCR_AdjustFrom640( &ax, &ay, &aw, &ah );\n\n\trow = ch>>4;\n\tcol = ch&15;\n\n\tfrow = row*0.0625;\n\tfcol = col*0.0625;\n\tsize = 0.0625;\n\n\tre.DrawStretchPic( ax, ay, aw, ah,\n\t\t\t\t\t   fcol, frow, \n\t\t\t\t\t   fcol + size, frow + size, \n\t\t\t\t\t   cls.charSetShader );\n}\n\n/*\n** SCR_DrawSmallChar\n** small chars are drawn at native screen resolution\n*/\nvoid SCR_DrawSmallChar( int x, int y, int ch ) {\n\tint row, col;\n\tfloat frow, fcol;\n\tfloat size;\n\n\tch &= 255;\n\n\tif ( ch == ' ' ) {\n\t\treturn;\n\t}\n\n\tif ( y < -SMALLCHAR_HEIGHT ) {\n\t\treturn;\n\t}\n\n\trow = ch>>4;\n\tcol = ch&15;\n\n\tfrow = row*0.0625;\n\tfcol = col*0.0625;\n\tsize = 0.0625;\n\n\tre.DrawStretchPic( x, y, SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT,\n\t\t\t\t\t   fcol, frow, \n\t\t\t\t\t   fcol + size, frow + size, \n\t\t\t\t\t   cls.charSetShader );\n}\n\n\n/*\n==================\nSCR_DrawBigString[Color]\n\nDraws a multi-colored string with a drop shadow, optionally forcing\nto a fixed color.\n\nCoordinates are at 640 by 480 virtual resolution\n==================\n*/\nvoid SCR_DrawStringExt( int x, int y, float size, const char *string, float *setColor, qboolean forceColor ) {\n\tvec4_t\t\tcolor;\n\tconst char\t*s;\n\tint\t\t\txx;\n\n\t// draw the drop shadow\n\tcolor[0] = color[1] = color[2] = 0;\n\tcolor[3] = setColor[3];\n\tre.SetColor( color );\n\ts = string;\n\txx = x;\n\twhile ( *s ) {\n\t\tif ( Q_IsColorString( s ) ) {\n\t\t\ts += 2;\n\t\t\tcontinue;\n\t\t}\n\t\tSCR_DrawChar( xx+2, y+2, size, *s );\n\t\txx += size;\n\t\ts++;\n\t}\n\n\n\t// draw the colored text\n\ts = string;\n\txx = x;\n\tre.SetColor( setColor );\n\twhile ( *s ) {\n\t\tif ( Q_IsColorString( s ) ) {\n\t\t\tif ( !forceColor ) {\n\t\t\t\tCom_Memcpy( color, g_color_table[ColorIndex(*(s+1))], sizeof( color ) );\n\t\t\t\tcolor[3] = setColor[3];\n\t\t\t\tre.SetColor( color );\n\t\t\t}\n\t\t\ts += 2;\n\t\t\tcontinue;\n\t\t}\n\t\tSCR_DrawChar( xx, y, size, *s );\n\t\txx += size;\n\t\ts++;\n\t}\n\tre.SetColor( NULL );\n}\n\n\nvoid SCR_DrawBigString( int x, int y, const char *s, float alpha ) {\n\tfloat\tcolor[4];\n\n\tcolor[0] = color[1] = color[2] = 1.0;\n\tcolor[3] = alpha;\n\tSCR_DrawStringExt( x, y, BIGCHAR_WIDTH, s, color, qfalse );\n}\n\nvoid SCR_DrawBigStringColor( int x, int y, const char *s, vec4_t color ) {\n\tSCR_DrawStringExt( x, y, BIGCHAR_WIDTH, s, color, qtrue );\n}\n\n\n/*\n==================\nSCR_DrawSmallString[Color]\n\nDraws a multi-colored string with a drop shadow, optionally forcing\nto a fixed color.\n\nCoordinates are at 640 by 480 virtual resolution\n==================\n*/\nvoid SCR_DrawSmallStringExt( int x, int y, const char *string, float *setColor, qboolean forceColor ) {\n\tvec4_t\t\tcolor;\n\tconst char\t*s;\n\tint\t\t\txx;\n\n\t// draw the colored text\n\ts = string;\n\txx = x;\n\tre.SetColor( setColor );\n\twhile ( *s ) {\n\t\tif ( Q_IsColorString( s ) ) {\n\t\t\tif ( !forceColor ) {\n\t\t\t\tCom_Memcpy( color, g_color_table[ColorIndex(*(s+1))], sizeof( color ) );\n\t\t\t\tcolor[3] = setColor[3];\n\t\t\t\tre.SetColor( color );\n\t\t\t}\n\t\t\ts += 2;\n\t\t\tcontinue;\n\t\t}\n\t\tSCR_DrawSmallChar( xx, y, *s );\n\t\txx += SMALLCHAR_WIDTH;\n\t\ts++;\n\t}\n\tre.SetColor( NULL );\n}\n\n\n\n/*\n** SCR_Strlen -- skips color escape codes\n*/\nstatic int SCR_Strlen( const char *str ) {\n\tconst char *s = str;\n\tint count = 0;\n\n\twhile ( *s ) {\n\t\tif ( Q_IsColorString( s ) ) {\n\t\t\ts += 2;\n\t\t} else {\n\t\t\tcount++;\n\t\t\ts++;\n\t\t}\n\t}\n\n\treturn count;\n}\n\n/*\n** SCR_GetBigStringWidth\n*/ \nint\tSCR_GetBigStringWidth( const char *str ) {\n\treturn SCR_Strlen( str ) * 16;\n}\n\n\n//===============================================================================\n\n/*\n=================\nSCR_DrawDemoRecording\n=================\n*/\nvoid SCR_DrawDemoRecording( void ) {\n\tchar\tstring[1024];\n\tint\t\tpos;\n\n\tif ( !clc.demorecording ) {\n\t\treturn;\n\t}\n\tif ( clc.spDemoRecording ) {\n\t\treturn;\n\t}\n\n\tpos = FS_FTell( clc.demofile );\n\tsprintf( string, \"RECORDING %s: %ik\", clc.demoName, pos / 1024 );\n\n\tSCR_DrawStringExt( 320 - (int)strlen( string ) * 4, 20, 8, string, g_color_table[7], qtrue );\n}\n\n\n/*\n===============================================================================\n\nDEBUG GRAPH\n\n===============================================================================\n*/\n\ntypedef struct\n{\n\tfloat\tvalue;\n\tint\t\tcolor;\n} graphsamp_t;\n\nstatic\tint\t\t\tcurrent;\nstatic\tgraphsamp_t\tvalues[1024];\n\n/*\n==============\nSCR_DebugGraph\n==============\n*/\nvoid SCR_DebugGraph (float value, int color)\n{\n\tvalues[current&1023].value = value;\n\tvalues[current&1023].color = color;\n\tcurrent++;\n}\n\n/*\n==============\nSCR_DrawDebugGraph\n==============\n*/\nvoid SCR_DrawDebugGraph (void)\n{\n\tint\t\ta, x, y, w, i, h;\n\tfloat\tv;\n\tint\t\tcolor;\n\n\t//\n\t// draw the graph\n\t//\n\tw = cls.glconfig.vidWidth;\n\tx = 0;\n\ty = cls.glconfig.vidHeight;\n\tre.SetColor( g_color_table[0] );\n\tre.DrawStretchPic(x, y - cl_graphheight->integer, \n\t\tw, cl_graphheight->integer, 0, 0, 0, 0, cls.whiteShader );\n\tre.SetColor( NULL );\n\n\tfor (a=0 ; a<w ; a++)\n\t{\n\t\ti = (current-1-a+1024) & 1023;\n\t\tv = values[i].value;\n\t\tcolor = values[i].color;\n\t\tv = v * cl_graphscale->integer + cl_graphshift->integer;\n\t\t\n\t\tif (v < 0)\n\t\t\tv += cl_graphheight->integer * (1+(int)(-v / cl_graphheight->integer));\n\t\th = (int)v % cl_graphheight->integer;\n\t\tre.DrawStretchPic( x+w-1-a, y - h, 1, h, 0, 0, 0, 0, cls.whiteShader );\n\t}\n}\n\n//=============================================================================\n\n/*\n==================\nSCR_Init\n==================\n*/\nvoid SCR_Init( void ) {\n\tcl_timegraph = Cvar_Get (\"timegraph\", \"0\", CVAR_CHEAT);\n\tcl_debuggraph = Cvar_Get (\"debuggraph\", \"0\", CVAR_CHEAT);\n\tcl_graphheight = Cvar_Get (\"graphheight\", \"32\", CVAR_CHEAT);\n\tcl_graphscale = Cvar_Get (\"graphscale\", \"1\", CVAR_CHEAT);\n\tcl_graphshift = Cvar_Get (\"graphshift\", \"0\", CVAR_CHEAT);\n\n\tscr_initialized = qtrue;\n}\n\n\n//=======================================================\n\n/*\n==================\nSCR_DrawScreenField\n\nThis will be called twice if rendering in stereo mode\n==================\n*/\nvoid SCR_DrawScreenField( stereoFrame_t stereoFrame ) {\n\tre.BeginFrame( stereoFrame );\n\n\t// wide aspect ratio screens need to have the sides cleared\n\t// unless they are displaying game renderings\n\tif ( cls.state != CA_ACTIVE ) {\n\t\tif ( cls.glconfig.vidWidth * 480 > cls.glconfig.vidHeight * 640 ) {\n\t\t\tre.SetColor( g_color_table[0] );\n\t\t\tre.DrawStretchPic( 0, 0, cls.glconfig.vidWidth, cls.glconfig.vidHeight, 0, 0, 0, 0, cls.whiteShader );\n\t\t\tre.SetColor( NULL );\n\t\t}\n\t}\n\n\tif ( !uivm ) {\n\t\tCom_DPrintf(\"draw screen without UI loaded\\n\");\n\t\treturn;\n\t}\n\n\t// if the menu is going to cover the entire screen, we\n\t// don't need to render anything under it\n\tif ( !VM_Call( uivm, UI_IS_FULLSCREEN )) {\n\t\tswitch( cls.state ) {\n\t\tdefault:\n\t\t\tCom_Error( ERR_FATAL, \"SCR_DrawScreenField: bad cls.state\" );\n\t\t\tbreak;\n\t\tcase CA_CINEMATIC:\n\t\t\tSCR_DrawCinematic();\n\t\t\tbreak;\n\t\tcase CA_DISCONNECTED:\n\t\t\t// force menu up\n\t\t\tS_StopAllSounds();\n\t\t\tVM_Call( uivm, UI_SET_ACTIVE_MENU, UIMENU_MAIN );\n\t\t\tbreak;\n\t\tcase CA_CONNECTING:\n\t\tcase CA_CHALLENGING:\n\t\tcase CA_CONNECTED:\n\t\t\t// connecting clients will only show the connection dialog\n\t\t\t// refresh to update the time\n\t\t\tVM_Call( uivm, UI_REFRESH, cls.realtime );\n\t\t\tVM_Call( uivm, UI_DRAW_CONNECT_SCREEN, qfalse );\n\t\t\tbreak;\n\t\tcase CA_LOADING:\n\t\tcase CA_PRIMED:\n\t\t\t// draw the game information screen and loading progress\n\t\t\tCL_CGameRendering( stereoFrame );\n\n\t\t\t// also draw the connection information, so it doesn't\n\t\t\t// flash away too briefly on local or lan games\n\t\t\t// refresh to update the time\n\t\t\tVM_Call( uivm, UI_REFRESH, cls.realtime );\n\t\t\tVM_Call( uivm, UI_DRAW_CONNECT_SCREEN, qtrue );\n\t\t\tbreak;\n\t\tcase CA_ACTIVE:\n\t\t\tCL_CGameRendering( stereoFrame );\n\t\t\tSCR_DrawDemoRecording();\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// the menu draws next\n\tif ( cls.keyCatchers & KEYCATCH_UI && uivm ) {\n\t\tVM_Call( uivm, UI_REFRESH, cls.realtime );\n\t}\n\n\t// console draws next\n\tCon_DrawConsole ();\n\n\t// debug graph can be drawn on top of anything\n\tif ( cl_debuggraph->integer || cl_timegraph->integer || cl_debugMove->integer ) {\n\t\tSCR_DrawDebugGraph ();\n\t}\n}\n\n/*\n==================\nSCR_UpdateScreen\n\nThis is called every frame, and can also be called explicitly to flush\ntext to the screen.\n==================\n*/\nvoid SCR_UpdateScreen( void ) {\n\tstatic int\trecursive;\n\n\tif ( !scr_initialized ) {\n\t\treturn;\t\t\t\t// not initialized yet\n\t}\n\n\tif ( ++recursive > 2 ) {\n\t\tCom_Error( ERR_FATAL, \"SCR_UpdateScreen: recursively called\" );\n\t}\n\trecursive = 1;\n\n\t// if running in stereo, we need to draw the frame twice\n\tif ( cls.glconfig.stereoEnabled ) {\n\t\tSCR_DrawScreenField( STEREO_LEFT );\n\t\tSCR_DrawScreenField( STEREO_RIGHT );\n\t} else {\n\t\tSCR_DrawScreenField( STEREO_CENTER );\n\t}\n\n\tif ( com_speeds->integer ) {\n\t\tre.EndFrame( &time_frontend, &time_backend );\n\t} else {\n\t\tre.EndFrame( NULL, NULL );\n\t}\n\n\trecursive = 0;\n}\n\n"
  },
  {
    "path": "src/engine/client/cl_ui.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n#include \"client.h\"\n\n#include \"../../game/botlib.h\"\n\nextern\tbotlib_export_t\t*botlib_export;\n\nvm_t *uivm;\n\n/*\n====================\nGetClientState\n====================\n*/\nstatic void GetClientState( uiClientState_t *state ) {\n\tstate->connectPacketCount = clc.connectPacketCount;\n\tstate->connState = cls.state;\n\tQ_strncpyz( state->servername, cls.servername, sizeof( state->servername ) );\n\tQ_strncpyz( state->updateInfoString, cls.updateInfoString, sizeof( state->updateInfoString ) );\n\tQ_strncpyz( state->messageString, clc.serverMessage, sizeof( state->messageString ) );\n\tstate->clientNum = cl.snap.ps.clientNum;\n}\n\n/*\n====================\nLAN_LoadCachedServers\n====================\n*/\nvoid LAN_LoadCachedServers( ) {\n\tint size;\n\tfileHandle_t fileIn;\n\tcls.numglobalservers = cls.nummplayerservers = cls.numfavoriteservers = 0;\n\tcls.numGlobalServerAddresses = 0;\n\tif (FS_SV_FOpenFileRead(\"servercache.dat\", &fileIn)) {\n\t\tFS_Read(&cls.numglobalservers, sizeof(int), fileIn);\n\t\tFS_Read(&cls.nummplayerservers, sizeof(int), fileIn);\n\t\tFS_Read(&cls.numfavoriteservers, sizeof(int), fileIn);\n\t\tFS_Read(&size, sizeof(int), fileIn);\n\t\tif (size == sizeof(cls.globalServers) + sizeof(cls.favoriteServers) + sizeof(cls.mplayerServers)) {\n\t\t\tFS_Read(&cls.globalServers, sizeof(cls.globalServers), fileIn);\n\t\t\tFS_Read(&cls.mplayerServers, sizeof(cls.mplayerServers), fileIn);\n\t\t\tFS_Read(&cls.favoriteServers, sizeof(cls.favoriteServers), fileIn);\n\t\t} else {\n\t\t\tcls.numglobalservers = cls.nummplayerservers = cls.numfavoriteservers = 0;\n\t\t\tcls.numGlobalServerAddresses = 0;\n\t\t}\n\t\tFS_FCloseFile(fileIn);\n\t}\n}\n\n/*\n====================\nLAN_SaveServersToCache\n====================\n*/\nvoid LAN_SaveServersToCache( ) {\n\tint size;\n\tfileHandle_t fileOut = FS_SV_FOpenFileWrite(\"servercache.dat\");\n\tFS_Write(&cls.numglobalservers, sizeof(int), fileOut);\n\tFS_Write(&cls.nummplayerservers, sizeof(int), fileOut);\n\tFS_Write(&cls.numfavoriteservers, sizeof(int), fileOut);\n\tsize = sizeof(cls.globalServers) + sizeof(cls.favoriteServers) + sizeof(cls.mplayerServers);\n\tFS_Write(&size, sizeof(int), fileOut);\n\tFS_Write(&cls.globalServers, sizeof(cls.globalServers), fileOut);\n\tFS_Write(&cls.mplayerServers, sizeof(cls.mplayerServers), fileOut);\n\tFS_Write(&cls.favoriteServers, sizeof(cls.favoriteServers), fileOut);\n\tFS_FCloseFile(fileOut);\n}\n\n\n/*\n====================\nLAN_ResetPings\n====================\n*/\nstatic void LAN_ResetPings(int source) {\n\tint count,i;\n\tserverInfo_t *servers = NULL;\n\tcount = 0;\n\n\tswitch (source) {\n\t\tcase AS_LOCAL :\n\t\t\tservers = &cls.localServers[0];\n\t\t\tcount = MAX_OTHER_SERVERS;\n\t\t\tbreak;\n\t\tcase AS_MPLAYER :\n\t\t\tservers = &cls.mplayerServers[0];\n\t\t\tcount = MAX_OTHER_SERVERS;\n\t\t\tbreak;\n\t\tcase AS_GLOBAL :\n\t\t\tservers = &cls.globalServers[0];\n\t\t\tcount = MAX_GLOBAL_SERVERS;\n\t\t\tbreak;\n\t\tcase AS_FAVORITES :\n\t\t\tservers = &cls.favoriteServers[0];\n\t\t\tcount = MAX_OTHER_SERVERS;\n\t\t\tbreak;\n\t}\n\tif (servers) {\n\t\tfor (i = 0; i < count; i++) {\n\t\t\tservers[i].ping = -1;\n\t\t}\n\t}\n}\n\n/*\n====================\nLAN_AddServer\n====================\n*/\nstatic int LAN_AddServer(int source, const char *name, const char *address) {\n\tint max, *count, i;\n\tnetadr_t adr;\n\tserverInfo_t *servers = NULL;\n\tmax = MAX_OTHER_SERVERS;\n\tcount = 0;\n\n\tswitch (source) {\n\t\tcase AS_LOCAL :\n\t\t\tcount = &cls.numlocalservers;\n\t\t\tservers = &cls.localServers[0];\n\t\t\tbreak;\n\t\tcase AS_MPLAYER :\n\t\t\tcount = &cls.nummplayerservers;\n\t\t\tservers = &cls.mplayerServers[0];\n\t\t\tbreak;\n\t\tcase AS_GLOBAL :\n\t\t\tmax = MAX_GLOBAL_SERVERS;\n\t\t\tcount = &cls.numglobalservers;\n\t\t\tservers = &cls.globalServers[0];\n\t\t\tbreak;\n\t\tcase AS_FAVORITES :\n\t\t\tcount = &cls.numfavoriteservers;\n\t\t\tservers = &cls.favoriteServers[0];\n\t\t\tbreak;\n\t}\n\tif (servers && *count < max) {\n\t\tNET_StringToAdr( address, &adr );\n\t\tfor ( i = 0; i < *count; i++ ) {\n\t\t\tif (NET_CompareAdr(servers[i].adr, adr)) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (i >= *count) {\n\t\t\tservers[*count].adr = adr;\n\t\t\tQ_strncpyz(servers[*count].hostName, name, sizeof(servers[*count].hostName));\n\t\t\tservers[*count].visible = qtrue;\n\t\t\t(*count)++;\n\t\t\treturn 1;\n\t\t}\n\t\treturn 0;\n\t}\n\treturn -1;\n}\n\n/*\n====================\nLAN_RemoveServer\n====================\n*/\nstatic void LAN_RemoveServer(int source, const char *addr) {\n\tint *count, i;\n\tserverInfo_t *servers = NULL;\n\tcount = 0;\n\tswitch (source) {\n\t\tcase AS_LOCAL :\n\t\t\tcount = &cls.numlocalservers;\n\t\t\tservers = &cls.localServers[0];\n\t\t\tbreak;\n\t\tcase AS_MPLAYER :\n\t\t\tcount = &cls.nummplayerservers;\n\t\t\tservers = &cls.mplayerServers[0];\n\t\t\tbreak;\n\t\tcase AS_GLOBAL :\n\t\t\tcount = &cls.numglobalservers;\n\t\t\tservers = &cls.globalServers[0];\n\t\t\tbreak;\n\t\tcase AS_FAVORITES :\n\t\t\tcount = &cls.numfavoriteservers;\n\t\t\tservers = &cls.favoriteServers[0];\n\t\t\tbreak;\n\t}\n\tif (servers) {\n\t\tnetadr_t comp;\n\t\tNET_StringToAdr( addr, &comp );\n\t\tfor (i = 0; i < *count; i++) {\n\t\t\tif (NET_CompareAdr( comp, servers[i].adr)) {\n\t\t\t\tint j = i;\n\t\t\t\twhile (j < *count - 1) {\n\t\t\t\t\tCom_Memcpy(&servers[j], &servers[j+1], sizeof(servers[j]));\n\t\t\t\t\tj++;\n\t\t\t\t}\n\t\t\t\t(*count)--;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n}\n\n\n/*\n====================\nLAN_GetServerCount\n====================\n*/\nstatic int LAN_GetServerCount( int source ) {\n\tswitch (source) {\n\t\tcase AS_LOCAL :\n\t\t\treturn cls.numlocalservers;\n\t\t\tbreak;\n\t\tcase AS_MPLAYER :\n\t\t\treturn cls.nummplayerservers;\n\t\t\tbreak;\n\t\tcase AS_GLOBAL :\n\t\t\treturn cls.numglobalservers;\n\t\t\tbreak;\n\t\tcase AS_FAVORITES :\n\t\t\treturn cls.numfavoriteservers;\n\t\t\tbreak;\n\t}\n\treturn 0;\n}\n\n/*\n====================\nLAN_GetLocalServerAddressString\n====================\n*/\nstatic void LAN_GetServerAddressString( int source, int n, char *buf, int buflen ) {\n\tswitch (source) {\n\t\tcase AS_LOCAL :\n\t\t\tif (n >= 0 && n < MAX_OTHER_SERVERS) {\n\t\t\t\tQ_strncpyz(buf, NET_AdrToString( cls.localServers[n].adr) , buflen );\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase AS_MPLAYER :\n\t\t\tif (n >= 0 && n < MAX_OTHER_SERVERS) {\n\t\t\t\tQ_strncpyz(buf, NET_AdrToString( cls.mplayerServers[n].adr) , buflen );\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase AS_GLOBAL :\n\t\t\tif (n >= 0 && n < MAX_GLOBAL_SERVERS) {\n\t\t\t\tQ_strncpyz(buf, NET_AdrToString( cls.globalServers[n].adr) , buflen );\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase AS_FAVORITES :\n\t\t\tif (n >= 0 && n < MAX_OTHER_SERVERS) {\n\t\t\t\tQ_strncpyz(buf, NET_AdrToString( cls.favoriteServers[n].adr) , buflen );\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tbreak;\n\t}\n\tbuf[0] = '\\0';\n}\n\n/*\n====================\nLAN_GetServerInfo\n====================\n*/\nstatic void LAN_GetServerInfo( int source, int n, char *buf, int buflen ) {\n\tchar info[MAX_STRING_CHARS];\n\tserverInfo_t *server = NULL;\n\tinfo[0] = '\\0';\n\tswitch (source) {\n\t\tcase AS_LOCAL :\n\t\t\tif (n >= 0 && n < MAX_OTHER_SERVERS) {\n\t\t\t\tserver = &cls.localServers[n];\n\t\t\t}\n\t\t\tbreak;\n\t\tcase AS_MPLAYER :\n\t\t\tif (n >= 0 && n < MAX_OTHER_SERVERS) {\n\t\t\t\tserver = &cls.mplayerServers[n];\n\t\t\t}\n\t\t\tbreak;\n\t\tcase AS_GLOBAL :\n\t\t\tif (n >= 0 && n < MAX_GLOBAL_SERVERS) {\n\t\t\t\tserver = &cls.globalServers[n];\n\t\t\t}\n\t\t\tbreak;\n\t\tcase AS_FAVORITES :\n\t\t\tif (n >= 0 && n < MAX_OTHER_SERVERS) {\n\t\t\t\tserver = &cls.favoriteServers[n];\n\t\t\t}\n\t\t\tbreak;\n\t}\n\tif (server && buf) {\n\t\tbuf[0] = '\\0';\n\t\tInfo_SetValueForKey( info, \"hostname\", server->hostName);\n\t\tInfo_SetValueForKey( info, \"mapname\", server->mapName);\n\t\tInfo_SetValueForKey( info, \"clients\", va(\"%i\",server->clients));\n\t\tInfo_SetValueForKey( info, \"sv_maxclients\", va(\"%i\",server->maxClients));\n\t\tInfo_SetValueForKey( info, \"ping\", va(\"%i\",server->ping));\n\t\tInfo_SetValueForKey( info, \"minping\", va(\"%i\",server->minPing));\n\t\tInfo_SetValueForKey( info, \"maxping\", va(\"%i\",server->maxPing));\n\t\tInfo_SetValueForKey( info, \"game\", server->game);\n\t\tInfo_SetValueForKey( info, \"gametype\", va(\"%i\",server->gameType));\n\t\tInfo_SetValueForKey( info, \"nettype\", va(\"%i\",server->netType));\n\t\tInfo_SetValueForKey( info, \"addr\", NET_AdrToString(server->adr));\n\t\tInfo_SetValueForKey( info, \"punkbuster\", va(\"%i\", server->punkbuster));\n\t\tQ_strncpyz(buf, info, buflen);\n\t} else {\n\t\tif (buf) {\n\t\t\tbuf[0] = '\\0';\n\t\t}\n\t}\n}\n\n/*\n====================\nLAN_GetServerPing\n====================\n*/\nstatic int LAN_GetServerPing( int source, int n ) {\n\tserverInfo_t *server = NULL;\n\tswitch (source) {\n\t\tcase AS_LOCAL :\n\t\t\tif (n >= 0 && n < MAX_OTHER_SERVERS) {\n\t\t\t\tserver = &cls.localServers[n];\n\t\t\t}\n\t\t\tbreak;\n\t\tcase AS_MPLAYER :\n\t\t\tif (n >= 0 && n < MAX_OTHER_SERVERS) {\n\t\t\t\tserver = &cls.mplayerServers[n];\n\t\t\t}\n\t\t\tbreak;\n\t\tcase AS_GLOBAL :\n\t\t\tif (n >= 0 && n < MAX_GLOBAL_SERVERS) {\n\t\t\t\tserver = &cls.globalServers[n];\n\t\t\t}\n\t\t\tbreak;\n\t\tcase AS_FAVORITES :\n\t\t\tif (n >= 0 && n < MAX_OTHER_SERVERS) {\n\t\t\t\tserver = &cls.favoriteServers[n];\n\t\t\t}\n\t\t\tbreak;\n\t}\n\tif (server) {\n\t\treturn server->ping;\n\t}\n\treturn -1;\n}\n\n/*\n====================\nLAN_GetServerPtr\n====================\n*/\nstatic serverInfo_t *LAN_GetServerPtr( int source, int n ) {\n\tswitch (source) {\n\t\tcase AS_LOCAL :\n\t\t\tif (n >= 0 && n < MAX_OTHER_SERVERS) {\n\t\t\t\treturn &cls.localServers[n];\n\t\t\t}\n\t\t\tbreak;\n\t\tcase AS_MPLAYER :\n\t\t\tif (n >= 0 && n < MAX_OTHER_SERVERS) {\n\t\t\t\treturn &cls.mplayerServers[n];\n\t\t\t}\n\t\t\tbreak;\n\t\tcase AS_GLOBAL :\n\t\t\tif (n >= 0 && n < MAX_GLOBAL_SERVERS) {\n\t\t\t\treturn &cls.globalServers[n];\n\t\t\t}\n\t\t\tbreak;\n\t\tcase AS_FAVORITES :\n\t\t\tif (n >= 0 && n < MAX_OTHER_SERVERS) {\n\t\t\t\treturn &cls.favoriteServers[n];\n\t\t\t}\n\t\t\tbreak;\n\t}\n\treturn NULL;\n}\n\n/*\n====================\nLAN_CompareServers\n====================\n*/\nstatic int LAN_CompareServers( int source, int sortKey, int sortDir, int s1, int s2 ) {\n\tint res;\n\tserverInfo_t *server1, *server2;\n\n\tserver1 = LAN_GetServerPtr(source, s1);\n\tserver2 = LAN_GetServerPtr(source, s2);\n\tif (!server1 || !server2) {\n\t\treturn 0;\n\t}\n\n\tres = 0;\n\tswitch( sortKey ) {\n\t\tcase SORT_HOST:\n\t\t\tres = Q_stricmp( server1->hostName, server2->hostName );\n\t\t\tbreak;\n\n\t\tcase SORT_MAP:\n\t\t\tres = Q_stricmp( server1->mapName, server2->mapName );\n\t\t\tbreak;\n\t\tcase SORT_CLIENTS:\n\t\t\tif (server1->clients < server2->clients) {\n\t\t\t\tres = -1;\n\t\t\t}\n\t\t\telse if (server1->clients > server2->clients) {\n\t\t\t\tres = 1;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tres = 0;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase SORT_GAME:\n\t\t\tif (server1->gameType < server2->gameType) {\n\t\t\t\tres = -1;\n\t\t\t}\n\t\t\telse if (server1->gameType > server2->gameType) {\n\t\t\t\tres = 1;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tres = 0;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase SORT_PING:\n\t\t\tif (server1->ping < server2->ping) {\n\t\t\t\tres = -1;\n\t\t\t}\n\t\t\telse if (server1->ping > server2->ping) {\n\t\t\t\tres = 1;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tres = 0;\n\t\t\t}\n\t\t\tbreak;\n\t}\n\n\tif (sortDir) {\n\t\tif (res < 0)\n\t\t\treturn 1;\n\t\tif (res > 0)\n\t\t\treturn -1;\n\t\treturn 0;\n\t}\n\treturn res;\n}\n\n/*\n====================\nLAN_GetPingQueueCount\n====================\n*/\nstatic int LAN_GetPingQueueCount( void ) {\n\treturn (CL_GetPingQueueCount());\n}\n\n/*\n====================\nLAN_ClearPing\n====================\n*/\nstatic void LAN_ClearPing( int n ) {\n\tCL_ClearPing( n );\n}\n\n/*\n====================\nLAN_GetPing\n====================\n*/\nstatic void LAN_GetPing( int n, char *buf, int buflen, int *pingtime ) {\n\tCL_GetPing( n, buf, buflen, pingtime );\n}\n\n/*\n====================\nLAN_GetPingInfo\n====================\n*/\nstatic void LAN_GetPingInfo( int n, char *buf, int buflen ) {\n\tCL_GetPingInfo( n, buf, buflen );\n}\n\n/*\n====================\nLAN_MarkServerVisible\n====================\n*/\nstatic void LAN_MarkServerVisible(int source, int n, qboolean visible ) {\n\tif (n == -1) {\n\t\tint count = MAX_OTHER_SERVERS;\n\t\tserverInfo_t *server = NULL;\n\t\tswitch (source) {\n\t\t\tcase AS_LOCAL :\n\t\t\t\tserver = &cls.localServers[0];\n\t\t\t\tbreak;\n\t\t\tcase AS_MPLAYER :\n\t\t\t\tserver = &cls.mplayerServers[0];\n\t\t\t\tbreak;\n\t\t\tcase AS_GLOBAL :\n\t\t\t\tserver = &cls.globalServers[0];\n\t\t\t\tcount = MAX_GLOBAL_SERVERS;\n\t\t\t\tbreak;\n\t\t\tcase AS_FAVORITES :\n\t\t\t\tserver = &cls.favoriteServers[0];\n\t\t\t\tbreak;\n\t\t}\n\t\tif (server) {\n\t\t\tfor (n = 0; n < count; n++) {\n\t\t\t\tserver[n].visible = visible;\n\t\t\t}\n\t\t}\n\n\t} else {\n\t\tswitch (source) {\n\t\t\tcase AS_LOCAL :\n\t\t\t\tif (n >= 0 && n < MAX_OTHER_SERVERS) {\n\t\t\t\t\tcls.localServers[n].visible = visible;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase AS_MPLAYER :\n\t\t\t\tif (n >= 0 && n < MAX_OTHER_SERVERS) {\n\t\t\t\t\tcls.mplayerServers[n].visible = visible;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase AS_GLOBAL :\n\t\t\t\tif (n >= 0 && n < MAX_GLOBAL_SERVERS) {\n\t\t\t\t\tcls.globalServers[n].visible = visible;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase AS_FAVORITES :\n\t\t\t\tif (n >= 0 && n < MAX_OTHER_SERVERS) {\n\t\t\t\t\tcls.favoriteServers[n].visible = visible;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\t}\n}\n\n\n/*\n=======================\nLAN_ServerIsVisible\n=======================\n*/\nstatic int LAN_ServerIsVisible(int source, int n ) {\n\tswitch (source) {\n\t\tcase AS_LOCAL :\n\t\t\tif (n >= 0 && n < MAX_OTHER_SERVERS) {\n\t\t\t\treturn cls.localServers[n].visible;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase AS_MPLAYER :\n\t\t\tif (n >= 0 && n < MAX_OTHER_SERVERS) {\n\t\t\t\treturn cls.mplayerServers[n].visible;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase AS_GLOBAL :\n\t\t\tif (n >= 0 && n < MAX_GLOBAL_SERVERS) {\n\t\t\t\treturn cls.globalServers[n].visible;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase AS_FAVORITES :\n\t\t\tif (n >= 0 && n < MAX_OTHER_SERVERS) {\n\t\t\t\treturn cls.favoriteServers[n].visible;\n\t\t\t}\n\t\t\tbreak;\n\t}\n\treturn qfalse;\n}\n\n/*\n=======================\nLAN_UpdateVisiblePings\n=======================\n*/\nqboolean LAN_UpdateVisiblePings(int source ) {\n\treturn CL_UpdateVisiblePings_f(source);\n}\n\n/*\n====================\nLAN_GetServerStatus\n====================\n*/\nint LAN_GetServerStatus( char *serverAddress, char *serverStatus, int maxLen ) {\n\treturn CL_ServerStatus( serverAddress, serverStatus, maxLen );\n}\n\n/*\n====================\nCL_GetGlConfig\n====================\n*/\nstatic void CL_GetGlconfig( glconfig_t *config ) {\n\t*config = cls.glconfig;\n}\n\n/*\n====================\nGetClipboardData\n====================\n*/\nstatic void GetClipboardData( char *buf, int buflen ) {\n\tchar\t*cbd;\n\n\tcbd = Sys_GetClipboardData();\n\n\tif ( !cbd ) {\n\t\t*buf = 0;\n\t\treturn;\n\t}\n\n\tQ_strncpyz( buf, cbd, buflen );\n\n\tZ_Free( cbd );\n}\n\n/*\n====================\nKey_KeynumToStringBuf\n====================\n*/\nstatic void Key_KeynumToStringBuf( int keynum, char *buf, int buflen ) {\n\tQ_strncpyz( buf, Key_KeynumToString( keynum ), buflen );\n}\n\n/*\n====================\nKey_GetBindingBuf\n====================\n*/\nstatic void Key_GetBindingBuf( int keynum, char *buf, int buflen ) {\n\tchar\t*value;\n\n\tvalue = Key_GetBinding( keynum );\n\tif ( value ) {\n\t\tQ_strncpyz( buf, value, buflen );\n\t}\n\telse {\n\t\t*buf = 0;\n\t}\n}\n\n/*\n====================\nKey_GetCatcher\n====================\n*/\nint Key_GetCatcher( void ) {\n\treturn cls.keyCatchers;\n}\n\n/*\n====================\nKet_SetCatcher\n====================\n*/\nvoid Key_SetCatcher( int catcher ) {\n\tcls.keyCatchers = catcher;\n}\n\n\n/*\n====================\nCLUI_GetCDKey\n====================\n*/\nstatic void CLUI_GetCDKey( char *buf, int buflen ) {\n\tcvar_t\t*fs;\n\tfs = Cvar_Get (\"fs_game\", \"\", CVAR_INIT|CVAR_SYSTEMINFO );\n\tif (UI_usesUniqueCDKey() && fs && fs->string[0] != 0) {\n\t\tCom_Memcpy( buf, &cl_cdkey[16], 16);\n\t\tbuf[16] = 0;\n\t} else {\n\t\tCom_Memcpy( buf, cl_cdkey, 16);\n\t\tbuf[16] = 0;\n\t}\n}\n\n\n/*\n====================\nCLUI_SetCDKey\n====================\n*/\nstatic void CLUI_SetCDKey( char *buf ) {\n\tcvar_t\t*fs;\n\tfs = Cvar_Get (\"fs_game\", \"\", CVAR_INIT|CVAR_SYSTEMINFO );\n\tif (UI_usesUniqueCDKey() && fs && fs->string[0] != 0) {\n\t\tCom_Memcpy( &cl_cdkey[16], buf, 16 );\n\t\tcl_cdkey[32] = 0;\n\t\t// set the flag so the fle will be written at the next opportunity\n\t\tcvar_modifiedFlags |= CVAR_ARCHIVE;\n\t} else {\n\t\tCom_Memcpy( cl_cdkey, buf, 16 );\n\t\t// set the flag so the fle will be written at the next opportunity\n\t\tcvar_modifiedFlags |= CVAR_ARCHIVE;\n\t}\n}\n\n/*\n====================\nGetConfigString\n====================\n*/\nstatic int GetConfigString(int index, char *buf, int size)\n{\n\tint\t\toffset;\n\n\tif (index < 0 || index >= MAX_CONFIGSTRINGS)\n\t\treturn qfalse;\n\n\toffset = cl.gameState.stringOffsets[index];\n\tif (!offset) {\n\t\tif( size ) {\n\t\t\tbuf[0] = 0;\n\t\t}\n\t\treturn qfalse;\n\t}\n\n\tQ_strncpyz( buf, cl.gameState.stringData+offset, size);\n \n\treturn qtrue;\n}\n\n/*\n====================\nFloatAsInt\n====================\n*/\nstatic int FloatAsInt( float f ) {\n\tint\t\ttemp;\n\n\t*(float *)&temp = f;\n\n\treturn temp;\n}\n\nvoid *VM_ArgPtr( intptr_t intValue );\n#define\tVMA(x) VM_ArgPtr(args[x])\n#define\tVMF(x) (*(float*)&args[x])\n\n/*\n====================\nCL_UISystemCalls\n\nThe ui module is making a system call\n====================\n*/\nintptr_t CL_UISystemCalls( intptr_t *args ) {\n\tswitch( args[0] ) {\n\tcase UI_ERROR:\n\t\tCom_Error( ERR_DROP, \"%s\", VMA(1) );\n\t\treturn 0;\n\n\tcase UI_PRINT:\n\t\tCom_Printf( \"%s\", VMA(1) );\n\t\treturn 0;\n\n\tcase UI_MILLISECONDS:\n\t\treturn Sys_Milliseconds();\n\n\tcase UI_CVAR_REGISTER:\n\t\tCvar_Register( (vmCvar_t*) VMA(1), (const char*) VMA(2), (const char*) VMA(3), args[4] ); \n\t\treturn 0;\n\n\tcase UI_CVAR_UPDATE:\n\t\tCvar_Update( (vmCvar_t*) VMA(1) );\n\t\treturn 0;\n\n\tcase UI_CVAR_SET:\n\t\tCvar_Set( (const char*) VMA(1), (const char*) VMA(2) );\n\t\treturn 0;\n\n\tcase UI_CVAR_VARIABLEVALUE:\n\t\treturn FloatAsInt( Cvar_VariableValue( (const char*) VMA(1) ) );\n\n\tcase UI_CVAR_VARIABLESTRINGBUFFER:\n\t\tCvar_VariableStringBuffer( (const char*) VMA(1), (char*) VMA(2), args[3] );\n\t\treturn 0;\n\n\tcase UI_CVAR_SETVALUE:\n\t\tCvar_SetValue( (const char*) VMA(1), VMF(2) );\n\t\treturn 0;\n\n\tcase UI_CVAR_RESET:\n\t\tCvar_Reset( (const char*) VMA(1) );\n\t\treturn 0;\n\n\tcase UI_CVAR_CREATE:\n\t\tCvar_Get( (const char*) VMA(1), (const char*) VMA(2), args[3] );\n\t\treturn 0;\n\n\tcase UI_CVAR_INFOSTRINGBUFFER:\n\t\tCvar_InfoStringBuffer( args[1], (char*) VMA(2), args[3] );\n\t\treturn 0;\n\n\tcase UI_ARGC:\n\t\treturn Cmd_Argc();\n\n\tcase UI_ARGV:\n\t\tCmd_ArgvBuffer( args[1], (char*) VMA(2), args[3] );\n\t\treturn 0;\n\n\tcase UI_CMD_EXECUTETEXT:\n\t\tCbuf_ExecuteText( args[1], (char*) VMA(2) );\n\t\treturn 0;\n\n\tcase UI_FS_FOPENFILE:\n\t\treturn FS_FOpenFileByMode( (const char*) VMA(1), (fileHandle_t*) VMA(2), (fsMode_t) args[3] );\n\n\tcase UI_FS_READ:\n\t\tFS_Read2( VMA(1), args[2], args[3] );\n\t\treturn 0;\n\n\tcase UI_FS_WRITE:\n\t\tFS_Write( VMA(1), args[2], args[3] );\n\t\treturn 0;\n\n\tcase UI_FS_FCLOSEFILE:\n\t\tFS_FCloseFile( args[1] );\n\t\treturn 0;\n\n\tcase UI_FS_GETFILELIST:\n\t\treturn FS_GetFileList( (const char*) VMA(1), (const char*) VMA(2), (char*) VMA(3), args[4] );\n\n\tcase UI_FS_SEEK:\n\t\treturn FS_Seek( args[1], args[2], args[3] );\n\t\n\tcase UI_R_REGISTERMODEL:\n\t\treturn re.RegisterModel( (const char*) VMA(1) );\n\n\tcase UI_R_REGISTERSKIN:\n\t\treturn re.RegisterSkin( (const char*) VMA(1) );\n\n\tcase UI_R_REGISTERSHADERNOMIP:\n\t\treturn re.RegisterShaderNoMip( (const char*) VMA(1) );\n\n\tcase UI_R_CLEARSCENE:\n\t\tre.ClearScene();\n\t\treturn 0;\n\n\tcase UI_R_ADDREFENTITYTOSCENE:\n\t\tre.AddRefEntityToScene( (const refEntity_t*) VMA(1) );\n\t\treturn 0;\n\n\tcase UI_R_ADDPOLYTOSCENE:\n\t\tre.AddPolyToScene( args[1], args[2], (const polyVert_t*) VMA(3), 1 );\n\t\treturn 0;\n\n\tcase UI_R_ADDLIGHTTOSCENE:\n\t\tre.AddLightToScene( (const vec_t*) VMA(1), VMF(2), VMF(3), VMF(4), VMF(5) );\n\t\treturn 0;\n\n\tcase UI_R_RENDERSCENE:\n\t\tre.RenderScene( (const refdef_t*) VMA(1) );\n\t\treturn 0;\n\n\tcase UI_R_SETCOLOR:\n\t\tre.SetColor( (const float*) VMA(1) );\n\t\treturn 0;\n\n\tcase UI_R_DRAWSTRETCHPIC:\n\t\tre.DrawStretchPic( VMF(1), VMF(2), VMF(3), VMF(4), VMF(5), VMF(6), VMF(7), VMF(8), args[9] );\n\t\treturn 0;\n\n  case UI_R_MODELBOUNDS:\n\t\tre.ModelBounds( args[1], (vec_t*) VMA(2), (vec_t*) VMA(3) );\n\t\treturn 0;\n\n\tcase UI_UPDATESCREEN:\n\t\tSCR_UpdateScreen();\n\t\treturn 0;\n\n\tcase UI_CM_LERPTAG:\n\t\tre.LerpTag( (orientation_t*) VMA(1), args[2], args[3], args[4], VMF(5), (const char*) VMA(6) );\n\t\treturn 0;\n\n\tcase UI_S_REGISTERSOUND:\n\t\treturn S_RegisterSound( (const char*) VMA(1), (qboolean) args[2] );\n\n\tcase UI_S_STARTLOCALSOUND:\n\t\tS_StartLocalSound( args[1], args[2] );\n\t\treturn 0;\n\n\tcase UI_KEY_KEYNUMTOSTRINGBUF:\n\t\tKey_KeynumToStringBuf( args[1], (char*) VMA(2), args[3] );\n\t\treturn 0;\n\n\tcase UI_KEY_GETBINDINGBUF:\n\t\tKey_GetBindingBuf( args[1], (char*) VMA(2), args[3] );\n\t\treturn 0;\n\n\tcase UI_KEY_SETBINDING:\n\t\tKey_SetBinding( args[1], (const char*) VMA(2) );\n\t\treturn 0;\n\n\tcase UI_KEY_ISDOWN:\n\t\treturn Key_IsDown( args[1] );\n\n\tcase UI_KEY_GETOVERSTRIKEMODE:\n\t\treturn Key_GetOverstrikeMode();\n\n\tcase UI_KEY_SETOVERSTRIKEMODE:\n\t\tKey_SetOverstrikeMode( (qboolean) args[1] );\n\t\treturn 0;\n\n\tcase UI_KEY_CLEARSTATES:\n\t\tKey_ClearStates();\n\t\treturn 0;\n\n\tcase UI_KEY_GETCATCHER:\n\t\treturn Key_GetCatcher();\n\n\tcase UI_KEY_SETCATCHER:\n\t\tKey_SetCatcher( args[1] );\n\t\treturn 0;\n\n\tcase UI_GETCLIPBOARDDATA:\n\t\tGetClipboardData( (char*) VMA(1), args[2] );\n\t\treturn 0;\n\n\tcase UI_GETCLIENTSTATE:\n\t\tGetClientState( (uiClientState_t*) VMA(1) );\n\t\treturn 0;\t\t\n\n\tcase UI_GETGLCONFIG:\n\t\tCL_GetGlconfig( (glconfig_t*) VMA(1) );\n\t\treturn 0;\n\n\tcase UI_GETCONFIGSTRING:\n\t\treturn GetConfigString( args[1], (char*) VMA(2), args[3] );\n\n\tcase UI_LAN_LOADCACHEDSERVERS:\n\t\tLAN_LoadCachedServers();\n\t\treturn 0;\n\n\tcase UI_LAN_SAVECACHEDSERVERS:\n\t\tLAN_SaveServersToCache();\n\t\treturn 0;\n\n\tcase UI_LAN_ADDSERVER:\n\t\treturn LAN_AddServer(args[1], (const char*) VMA(2), (const char*) VMA(3));\n\n\tcase UI_LAN_REMOVESERVER:\n\t\tLAN_RemoveServer(args[1], (const char*) VMA(2));\n\t\treturn 0;\n\n\tcase UI_LAN_GETPINGQUEUECOUNT:\n\t\treturn LAN_GetPingQueueCount();\n\n\tcase UI_LAN_CLEARPING:\n\t\tLAN_ClearPing( args[1] );\n\t\treturn 0;\n\n\tcase UI_LAN_GETPING:\n\t\tLAN_GetPing( args[1], (char*) VMA(2), args[3], (int*) VMA(4) );\n\t\treturn 0;\n\n\tcase UI_LAN_GETPINGINFO:\n\t\tLAN_GetPingInfo( args[1], (char*) VMA(2), args[3] );\n\t\treturn 0;\n\n\tcase UI_LAN_GETSERVERCOUNT:\n\t\treturn LAN_GetServerCount(args[1]);\n\n\tcase UI_LAN_GETSERVERADDRESSSTRING:\n\t\tLAN_GetServerAddressString( args[1], args[2], (char*) VMA(3), args[4] );\n\t\treturn 0;\n\n\tcase UI_LAN_GETSERVERINFO:\n\t\tLAN_GetServerInfo( args[1], args[2], (char*) VMA(3), args[4] );\n\t\treturn 0;\n\n\tcase UI_LAN_GETSERVERPING:\n\t\treturn LAN_GetServerPing( args[1], args[2] );\n\n\tcase UI_LAN_MARKSERVERVISIBLE:\n\t\tLAN_MarkServerVisible( args[1], args[2], (qboolean) args[3] );\n\t\treturn 0;\n\n\tcase UI_LAN_SERVERISVISIBLE:\n\t\treturn LAN_ServerIsVisible( args[1], args[2] );\n\n\tcase UI_LAN_UPDATEVISIBLEPINGS:\n\t\treturn LAN_UpdateVisiblePings( args[1] );\n\n\tcase UI_LAN_RESETPINGS:\n\t\tLAN_ResetPings( args[1] );\n\t\treturn 0;\n\n\tcase UI_LAN_SERVERSTATUS:\n\t\treturn LAN_GetServerStatus( (char*) VMA(1), (char*) VMA(2), args[3] );\n\n\tcase UI_LAN_COMPARESERVERS:\n\t\treturn LAN_CompareServers( args[1], args[2], args[3], args[4], args[5] );\n\n\tcase UI_MEMORY_REMAINING:\n\t\treturn Hunk_MemoryRemaining();\n\n\tcase UI_GET_CDKEY:\n\t\tCLUI_GetCDKey( (char*) VMA(1), args[2] );\n\t\treturn 0;\n\n\tcase UI_SET_CDKEY:\n\t\tCLUI_SetCDKey( (char*) VMA(1) );\n\t\treturn 0;\n\t\n\tcase UI_SET_PBCLSTATUS:\n\t\treturn 0;\t\n\n\tcase UI_R_REGISTERFONT:\n\t\tre.RegisterFont( (const char*) VMA(1), args[2], (fontInfo_t*) VMA(3));\n\t\treturn 0;\n\n\tcase UI_MEMSET:\n\t\tCom_Memset( VMA(1), args[2], args[3] );\n\t\treturn 0;\n\n\tcase UI_MEMCPY:\n\t\tCom_Memcpy( VMA(1), VMA(2), args[3] );\n\t\treturn 0;\n\n\tcase UI_STRNCPY:\n        strncpy( (char*)VMA(1), (const char*)VMA(2), args[3] );\n        return args[1];\n\tcase UI_SIN:\n\t\treturn FloatAsInt( sin( VMF(1) ) );\n\n\tcase UI_COS:\n\t\treturn FloatAsInt( cos( VMF(1) ) );\n\n\tcase UI_ATAN2:\n\t\treturn FloatAsInt( atan2( VMF(1), VMF(2) ) );\n\n\tcase UI_SQRT:\n\t\treturn FloatAsInt( sqrt( VMF(1) ) );\n\n\tcase UI_FLOOR:\n\t\treturn FloatAsInt( floor( VMF(1) ) );\n\n\tcase UI_CEIL:\n\t\treturn FloatAsInt( ceil( VMF(1) ) );\n\n\tcase UI_PC_ADD_GLOBAL_DEFINE:\n\t\treturn botlib_export->PC_AddGlobalDefine( (char*) VMA(1) );\n\tcase UI_PC_LOAD_SOURCE:\n\t\treturn botlib_export->PC_LoadSourceHandle( (const char*) VMA(1) );\n\tcase UI_PC_FREE_SOURCE:\n\t\treturn botlib_export->PC_FreeSourceHandle( args[1] );\n\tcase UI_PC_READ_TOKEN:\n\t\treturn botlib_export->PC_ReadTokenHandle( args[1], (pc_token_t*) VMA(2) );\n\tcase UI_PC_SOURCE_FILE_AND_LINE:\n\t\treturn botlib_export->PC_SourceFileAndLine( args[1], (char*) VMA(2), (int*) VMA(3) );\n\n\tcase UI_S_STOPBACKGROUNDTRACK:\n\t\tS_StopBackgroundTrack();\n\t\treturn 0;\n\tcase UI_S_STARTBACKGROUNDTRACK:\n\t\tS_StartBackgroundTrack( (const char*) VMA(1), (const char*) VMA(2));\n\t\treturn 0;\n\n\tcase UI_REAL_TIME:\n\t\treturn Com_RealTime( (qtime_t*) VMA(1) );\n\n\tcase UI_CIN_PLAYCINEMATIC:\n\t  Com_DPrintf(\"UI_CIN_PlayCinematic\\n\");\n\t  return CIN_PlayCinematic( (const char*) VMA(1), args[2], args[3], args[4], args[5], args[6]);\n\n\tcase UI_CIN_STOPCINEMATIC:\n\t  return CIN_StopCinematic(args[1]);\n\n\tcase UI_CIN_RUNCINEMATIC:\n\t  return CIN_RunCinematic(args[1]);\n\n\tcase UI_CIN_DRAWCINEMATIC:\n\t  CIN_DrawCinematic(args[1]);\n\t  return 0;\n\n\tcase UI_CIN_SETEXTENTS:\n\t  CIN_SetExtents(args[1], args[2], args[3], args[4], args[5]);\n\t  return 0;\n\n\tcase UI_R_REMAP_SHADER:\n\t\tre.RemapShader( (const char*) VMA(1), (const char*) VMA(2), (const char*) VMA(3) );\n\t\treturn 0;\n\n\tcase UI_VERIFY_CDKEY:\n\t\treturn CL_CDKeyValidate( (const char*) VMA(1), (const char*) VMA(2));\n\n\n\t\t\n\tdefault:\n\t\tCom_Error( ERR_DROP, \"Bad UI system trap: %i\", args[0] );\n\n\t}\n\n\treturn 0;\n}\n\n/*\n====================\nCL_ShutdownUI\n====================\n*/\nvoid CL_ShutdownUI( void ) {\n\tcls.keyCatchers &= ~KEYCATCH_UI;\n\tcls.uiStarted = qfalse;\n\tif ( !uivm ) {\n\t\treturn;\n\t}\n\tVM_Call( uivm, UI_SHUTDOWN );\n\tVM_Free( uivm );\n\tuivm = NULL;\n}\n\n/*\n====================\nCL_InitUI\n====================\n*/\n#define UI_OLD_API_VERSION\t4\n\nvoid CL_InitUI( void ) {\n\tint\t\tv;\n\tvmInterpret_t\t\tinterpret;\n\n\t// load the dll or bytecode\n\tif ( cl_connectedToPureServer != 0 ) {\n\t\t// if sv_pure is set we only allow qvms to be loaded\n\t\tinterpret = VMI_BYTECODE;\n\t}\n\telse {\n\t\tinterpret = (vmInterpret_t) (int) Cvar_VariableValue( \"vm_ui\" );\n\t}\n\tuivm = VM_Create( \"ui\", CL_UISystemCalls, interpret );\n\tif ( !uivm ) {\n\t\tCom_Error( ERR_FATAL, \"VM_Create on UI failed\" );\n\t}\n\n\t// sanity check\n\tv = VM_Call( uivm, UI_GETAPIVERSION );\n\tif (v == UI_OLD_API_VERSION) {\n//\t\tCom_Printf(S_COLOR_YELLOW \"WARNING: loading old Quake III Arena User Interface version %d\\n\", v );\n\t\t// init for this gamestate\n\t\tVM_Call( uivm, UI_INIT, (cls.state >= CA_AUTHORIZING && cls.state < CA_ACTIVE));\n\t}\n\telse if (v != UI_API_VERSION) {\n\t\tCom_Error( ERR_DROP, \"User Interface is version %d, expected %d\", v, UI_API_VERSION );\n\t\tcls.uiStarted = qfalse;\n\t}\n\telse {\n\t\t// init for this gamestate\n\t\tVM_Call( uivm, UI_INIT, (cls.state >= CA_AUTHORIZING && cls.state < CA_ACTIVE) );\n\t}\n}\n\nqboolean UI_usesUniqueCDKey() {\n\tif (uivm) {\n\t\treturn (qboolean) (VM_Call( uivm, UI_HASUNIQUECDKEY) == qtrue);\n\t} else {\n\t\treturn qfalse;\n\t}\n}\n\n/*\n====================\nUI_GameCommand\n\nSee if the current console command is claimed by the ui\n====================\n*/\nqboolean UI_GameCommand( void ) {\n\tif ( !uivm ) {\n\t\treturn qfalse;\n\t}\n\n\treturn (qboolean) VM_Call( uivm, UI_CONSOLE_COMMAND, cls.realtime );\n}\n"
  },
  {
    "path": "src/engine/client/client.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n// client.h -- primary header for client\n\n#include \"../../game/q_shared.h\"\n#include \"../qcommon/qcommon.h\"\n#include \"../renderer/tr_public.h\"\n#include \"../../q3_ui/ui_public.h\"\n#include \"keys.h\"\n#include \"snd_public.h\"\n#include \"../../cgame/cg_public.h\"\n#include \"../../game/bg_public.h\"\n\n#define\tRETRANSMIT_TIMEOUT\t3000\t// time between connection packet retransmits\n\n\n// snapshots are a view of the server at a given time\ntypedef struct {\n\tqboolean\t\tvalid;\t\t\t// cleared if delta parsing was invalid\n\tint\t\t\t\tsnapFlags;\t\t// rate delayed and dropped commands\n\n\tint\t\t\t\tserverTime;\t\t// server time the message is valid for (in msec)\n\n\tint\t\t\t\tmessageNum;\t\t// copied from netchan->incoming_sequence\n\tint\t\t\t\tdeltaNum;\t\t// messageNum the delta is from\n\tint\t\t\t\tping;\t\t\t// time from when cmdNum-1 was sent to time packet was reeceived\n\tbyte\t\t\tareamask[MAX_MAP_AREA_BYTES];\t\t// portalarea visibility bits\n\n\tint\t\t\t\tcmdNum;\t\t\t// the next cmdNum the server is expecting\n\tplayerState_t\tps;\t\t\t\t\t\t// complete information about the current player at this time\n\n\tint\t\t\t\tnumEntities;\t\t\t// all of the entities that need to be presented\n\tint\t\t\t\tparseEntitiesNum;\t\t// at the time of this snapshot\n\n\tint\t\t\t\tserverCommandNum;\t\t// execute all commands up to this before\n\t\t\t\t\t\t\t\t\t\t\t// making the snapshot current\n} clSnapshot_t;\n\n\n\n/*\n=============================================================================\n\nthe clientActive_t structure is wiped completely at every\nnew gamestate_t, potentially several times during an established connection\n\n=============================================================================\n*/\n\ntypedef struct {\n\tint\t\tp_cmdNumber;\t\t// cl.cmdNumber when packet was sent\n\tint\t\tp_serverTime;\t\t// usercmd->serverTime when packet was sent\n\tint\t\tp_realtime;\t\t\t// cls.realtime when packet was sent\n} outPacket_t;\n\n// the parseEntities array must be large enough to hold PACKET_BACKUP frames of\n// entities, so that when a delta compressed message arives from the server\n// it can be un-deltad from the original \n#define\tMAX_PARSE_ENTITIES\t2048\n\nextern int g_console_field_width;\n\ntypedef struct {\n\tint\t\t\ttimeoutcount;\t\t// it requres several frames in a timeout condition\n\t\t\t\t\t\t\t\t\t// to disconnect, preventing debugging breaks from\n\t\t\t\t\t\t\t\t\t// causing immediate disconnects on continue\n\tclSnapshot_t\tsnap;\t\t\t// latest received from server\n\n\tint\t\t\tserverTime;\t\t\t// may be paused during play\n\tint\t\t\toldServerTime;\t\t// to prevent time from flowing bakcwards\n\tint\t\t\toldFrameServerTime;\t// to check tournament restarts\n\tint\t\t\tserverTimeDelta;\t// cl.serverTime = cls.realtime + cl.serverTimeDelta\n\t\t\t\t\t\t\t\t\t// this value changes as net lag varies\n\tqboolean\textrapolatedSnapshot;\t// set if any cgame frame has been forced to extrapolate\n\t\t\t\t\t\t\t\t\t// cleared when CL_AdjustTimeDelta looks at it\n\tqboolean\tnewSnapshots;\t\t// set on parse of any valid packet\n\n\tgameState_t\tgameState;\t\t\t// configstrings\n\tchar\t\tmapname[MAX_QPATH];\t// extracted from CS_SERVERINFO\n\n\tint\t\t\tparseEntitiesNum;\t// index (not anded off) into cl_parse_entities[]\n\n\tint\t\t\tmouseDx[2], mouseDy[2];\t// added to by mouse events\n\tint\t\t\tmouseIndex;\n\tint\t\t\tjoystickAxis[MAX_JOYSTICK_AXIS];\t// set by joystick events\n\n\t// cgame communicates a few values to the client system\n\tint\t\t\tcgameUserCmdValue;\t// current weapon to add to usercmd_t\n\tfloat\t\tcgameSensitivity;\n\n\t// cmds[cmdNumber] is the predicted command, [cmdNumber-1] is the last\n\t// properly generated command\n\tusercmd_t\tcmds[CMD_BACKUP];\t// each mesage will send several old cmds\n\tint\t\t\tcmdNumber;\t\t\t// incremented each frame, because multiple\n\t\t\t\t\t\t\t\t\t// frames may need to be packed into a single packet\n\n\toutPacket_t\toutPackets[PACKET_BACKUP];\t// information about each packet we have sent out\n\n\t// the client maintains its own idea of view angles, which are\n\t// sent to the server each frame.  It is cleared to 0 upon entering each level.\n\t// the server sends a delta each frame which is added to the locally\n\t// tracked view angles to account for standing on rotating objects,\n\t// and teleport direction changes\n\tvec3_t\t\tviewangles;\n\n\tint\t\t\tserverId;\t\t\t// included in each client message so the server\n\t\t\t\t\t\t\t\t\t\t\t\t// can tell if it is for a prior map_restart\n\t// big stuff at end of structure so most offsets are 15 bits or less\n\tclSnapshot_t\tsnapshots[PACKET_BACKUP];\n\n\tentityState_t\tentityBaselines[MAX_GENTITIES];\t// for delta compression when not in previous frame\n\n\tentityState_t\tparseEntities[MAX_PARSE_ENTITIES];\n} clientActive_t;\n\nextern\tclientActive_t\t\tcl;\n\n/*\n=============================================================================\n\nthe clientConnection_t structure is wiped when disconnecting from a server,\neither to go to a full screen console, play a demo, or connect to a different server\n\nA connection can be to either a server through the network layer or a\ndemo through a file.\n\n=============================================================================\n*/\n\n\ntypedef struct {\n\n\tint\t\t\tclientNum;\n\tint\t\t\tlastPacketSentTime;\t\t\t// for retransmits during connection\n\tint\t\t\tlastPacketTime;\t\t\t\t// for timeouts\n\n\tnetadr_t\tserverAddress;\n\tint\t\t\tconnectTime;\t\t\t\t// for connection retransmits\n\tint\t\t\tconnectPacketCount;\t\t\t// for display on connection dialog\n\tchar\t\tserverMessage[MAX_STRING_TOKENS];\t// for display on connection dialog\n\n\tint\t\t\tchallenge;\t\t\t\t\t// from the server to use for connecting\n\tint\t\t\tchecksumFeed;\t\t\t\t// from the server for checksum calculations\n\n\t// these are our reliable messages that go to the server\n\tint\t\t\treliableSequence;\n\tint\t\t\treliableAcknowledge;\t\t// the last one the server has executed\n\tchar\t\treliableCommands[MAX_RELIABLE_COMMANDS][MAX_STRING_CHARS];\n\n\t// server message (unreliable) and command (reliable) sequence\n\t// numbers are NOT cleared at level changes, but continue to\n\t// increase as long as the connection is valid\n\n\t// message sequence is used by both the network layer and the\n\t// delta compression layer\n\tint\t\t\tserverMessageSequence;\n\n\t// reliable messages received from server\n\tint\t\t\tserverCommandSequence;\n\tint\t\t\tlastExecutedServerCommand;\t\t// last server command grabbed or executed with CL_GetServerCommand\n\tchar\t\tserverCommands[MAX_RELIABLE_COMMANDS][MAX_STRING_CHARS];\n\n\t// file transfer from server\n\tfileHandle_t download;\n\tchar\t\tdownloadTempName[MAX_OSPATH];\n\tchar\t\tdownloadName[MAX_OSPATH];\n\tint\t\t\tdownloadNumber;\n\tint\t\t\tdownloadBlock;\t// block we are waiting for\n\tint\t\t\tdownloadCount;\t// how many bytes we got\n\tint\t\t\tdownloadSize;\t// how many bytes we got\n\tchar\t\tdownloadList[MAX_INFO_STRING]; // list of paks we need to download\n\tqboolean\tdownloadRestart;\t// if true, we need to do another FS_Restart because we downloaded a pak\n\n\t// demo information\n\tchar\t\tdemoName[MAX_QPATH];\n\tqboolean\tspDemoRecording;\n\tqboolean\tdemorecording;\n\tqboolean\tdemoplaying;\n\tqboolean\tdemowaiting;\t// don't record until a non-delta message is received\n\tqboolean\tfirstDemoFrameSkipped;\n\tfileHandle_t\tdemofile;\n\n\tint\t\t\ttimeDemoFrames;\t\t// counter of rendered frames\n\tint\t\t\ttimeDemoStart;\t\t// cls.realtime before first frame\n\tint\t\t\ttimeDemoBaseTime;\t// each frame will be at this time + frameNum * 50\n\n\t// big stuff at end of structure so most offsets are 15 bits or less\n\tnetchan_t\tnetchan;\n} clientConnection_t;\n\nextern\tclientConnection_t clc;\n\n/*\n==================================================================\n\nthe clientStatic_t structure is never wiped, and is used even when\nno client connection is active at all\n\n==================================================================\n*/\n\ntypedef struct {\n\tnetadr_t\tadr;\n\tint\t\t\tstart;\n\tint\t\t\ttime;\n\tchar\t\tinfo[MAX_INFO_STRING];\n} ping_t;\n\ntypedef struct {\n\tnetadr_t\tadr;\n\tchar\t  \thostName[MAX_NAME_LENGTH];\n\tchar\t  \tmapName[MAX_NAME_LENGTH];\n\tchar\t  \tgame[MAX_NAME_LENGTH];\n\tint\t\t\tnetType;\n\tint\t\t\tgameType;\n\tint\t\t  \tclients;\n\tint\t\t  \tmaxClients;\n\tint\t\t\tminPing;\n\tint\t\t\tmaxPing;\n\tint\t\t\tping;\n\tqboolean\tvisible;\n\tint\t\t\tpunkbuster;\n} serverInfo_t;\n\ntypedef struct {\n\tbyte\tip[4];\n\tunsigned short\tport;\n} serverAddress_t;\n\ntypedef struct {\n\tconnstate_t\tstate;\t\t\t\t// connection status\n\tint\t\t\tkeyCatchers;\t\t// bit flags\n\n\tqboolean\tcddialog;\t\t\t// bring up the cd needed dialog next frame\n\n\tchar\t\tservername[MAX_OSPATH];\t\t// name of server from original connect (used by reconnect)\n\n\t// when the server clears the hunk, all of these must be restarted\n\tqboolean\trendererStarted;\n\tqboolean\tsoundStarted;\n\tqboolean\tsoundRegistered;\n\tqboolean\tuiStarted;\n\tqboolean\tcgameStarted;\n\n\tint\t\t\tframecount;\n\tint\t\t\tframetime;\t\t\t// msec since last frame\n\n\tint\t\t\trealtime;\t\t\t// ignores pause\n\tint\t\t\trealFrametime;\t\t// ignoring pause, so console always works\n\n\tint\t\t\tnumlocalservers;\n\tserverInfo_t\tlocalServers[MAX_OTHER_SERVERS];\n\n\tint\t\t\tnumglobalservers;\n\tserverInfo_t  globalServers[MAX_GLOBAL_SERVERS];\n\t// additional global servers\n\tint\t\t\tnumGlobalServerAddresses;\n\tserverAddress_t\t\tglobalServerAddresses[MAX_GLOBAL_SERVERS];\n\n\tint\t\t\tnumfavoriteservers;\n\tserverInfo_t\tfavoriteServers[MAX_OTHER_SERVERS];\n\n\tint\t\t\tnummplayerservers;\n\tserverInfo_t\tmplayerServers[MAX_OTHER_SERVERS];\n\n\tint pingUpdateSource;\t\t// source currently pinging or updating\n\n\tint masterNum;\n\n\t// update server info\n\tnetadr_t\tupdateServer;\n\tchar\t\tupdateChallenge[MAX_TOKEN_CHARS];\n\tchar\t\tupdateInfoString[MAX_INFO_STRING];\n\n\tnetadr_t\tauthorizeServer;\n\n\t// rendering info\n\tglconfig_t\tglconfig;\n\tqhandle_t\tcharSetShader;\n\tqhandle_t\twhiteShader;\n\tqhandle_t\tconsoleShader;\n} clientStatic_t;\n\nextern\tclientStatic_t\t\tcls;\n\n//=============================================================================\n\nextern\tvm_t\t\t\t*cgvm;\t// interface to cgame dll or vm\nextern\tvm_t\t\t\t*uivm;\t// interface to ui dll or vm\nextern\trefexport_t\t\tre;\t\t// interface to refresh .dll\n\n\n//\n// cvars\n//\nextern\tcvar_t\t*cl_nodelta;\nextern\tcvar_t\t*cl_debugMove;\nextern\tcvar_t\t*cl_noprint;\nextern\tcvar_t\t*cl_timegraph;\nextern\tcvar_t\t*cl_maxpackets;\nextern\tcvar_t\t*cl_packetdup;\nextern\tcvar_t\t*cl_shownet;\nextern\tcvar_t\t*cl_showSend;\nextern\tcvar_t\t*cl_timeNudge;\nextern\tcvar_t\t*cl_showTimeDelta;\nextern\tcvar_t\t*cl_freezeDemo;\n\nextern\tcvar_t\t*cl_yawspeed;\nextern\tcvar_t\t*cl_pitchspeed;\nextern\tcvar_t\t*cl_run;\nextern\tcvar_t\t*cl_anglespeedkey;\n\nextern\tcvar_t\t*cl_sensitivity;\nextern\tcvar_t\t*cl_freelook;\n\nextern\tcvar_t\t*cl_mouseAccel;\nextern\tcvar_t\t*cl_showMouseRate;\n\nextern\tcvar_t\t*m_pitch;\nextern\tcvar_t\t*m_yaw;\nextern\tcvar_t\t*m_forward;\nextern\tcvar_t\t*m_side;\nextern\tcvar_t\t*m_filter;\n\nextern\tcvar_t\t*cl_timedemo;\n\nextern\tcvar_t\t*cl_activeAction;\n\nextern\tcvar_t\t*cl_allowDownload;\nextern\tcvar_t\t*cl_conXOffset;\nextern\tcvar_t\t*cl_inGameVideo;\n\n//=================================================\n\n//\n// cl_main\n//\n\nvoid CL_Init (void);\nvoid CL_FlushMemory(void);\nvoid CL_ShutdownAll(void);\nvoid CL_AddReliableCommand( const char *cmd );\n\nvoid CL_StartHunkUsers( void );\n\nvoid CL_Disconnect_f (void);\nvoid CL_Vid_Restart_f( void );\nvoid CL_Snd_Restart_f (void);\nvoid CL_StartDemoLoop( void );\nvoid CL_NextDemo( void );\nvoid CL_ReadDemoMessage( void );\n\nvoid CL_InitDownloads(void);\nvoid CL_NextDownload(void);\n\nvoid CL_GetPing( int n, char *buf, int buflen, int *pingtime );\nvoid CL_GetPingInfo( int n, char *buf, int buflen );\nvoid CL_ClearPing( int n );\nint CL_GetPingQueueCount( void );\n\nvoid CL_ShutdownRef( void );\nvoid CL_InitRef( void );\nqboolean CL_CDKeyValidate( const char *key, const char *checksum );\nint CL_ServerStatus( char *serverAddress, char *serverStatusString, int maxLen );\n\n\n//\n// cl_input\n//\ntypedef struct {\n\tint\t\t\tdown[2];\t\t// key nums holding it down\n\tunsigned\tdowntime;\t\t// msec timestamp\n\tunsigned\tmsec;\t\t\t// msec down this frame if both a down and up happened\n\tqboolean\tactive;\t\t\t// current state\n\tqboolean\twasPressed;\t\t// set when down, not cleared when up\n} kbutton_t;\n\nextern\tkbutton_t\tin_mlook, in_klook;\nextern \tkbutton_t \tin_strafe;\nextern \tkbutton_t \tin_speed;\n\nvoid CL_InitInput (void);\nvoid CL_SendCmd (void);\nvoid CL_ClearState (void);\nvoid CL_ReadPackets (void);\n\nvoid CL_WritePacket( void );\nvoid IN_CenterView (void);\n\nvoid CL_VerifyCode( void );\n\nfloat CL_KeyState (kbutton_t *key);\nchar *Key_KeynumToString (int keynum);\n\n//\n// cl_parse.c\n//\nextern int cl_connectedToPureServer;\n\nvoid CL_SystemInfoChanged( void );\nvoid CL_ParseServerMessage( msg_t *msg );\n\n//====================================================================\n\nvoid\tCL_ServerInfoPacket( netadr_t from, msg_t *msg );\nvoid\tCL_LocalServers_f( void );\nvoid\tCL_GlobalServers_f( void );\nvoid\tCL_FavoriteServers_f( void );\nvoid\tCL_Ping_f( void );\nqboolean CL_UpdateVisiblePings_f( int source );\n\n\n//\n// console\n//\nvoid Con_DrawCharacter (int cx, int line, int num);\n\nvoid Con_CheckResize (void);\nvoid Con_Init (void);\nvoid Con_Clear_f (void);\nvoid Con_ToggleConsole_f (void);\nvoid Con_DrawNotify (void);\nvoid Con_ClearNotify (void);\nvoid Con_RunConsole (void);\nvoid Con_DrawConsole (void);\nvoid Con_PageUp( void );\nvoid Con_PageDown( void );\nvoid Con_Top( void );\nvoid Con_Bottom( void );\nvoid Con_Close( void );\n\n\n//\n// cl_scrn.c\n//\nvoid\tSCR_Init (void);\nvoid\tSCR_UpdateScreen (void);\n\nvoid\tSCR_DebugGraph (float value, int color);\n\nint\t\tSCR_GetBigStringWidth( const char *str );\t// returns in virtual 640x480 coordinates\n\nvoid\tSCR_AdjustFrom640( float *x, float *y, float *w, float *h );\nvoid\tSCR_FillRect( float x, float y, float width, float height, \n\t\t\t\t\t const float *color );\nvoid\tSCR_DrawPic( float x, float y, float width, float height, qhandle_t hShader );\nvoid\tSCR_DrawNamedPic( float x, float y, float width, float height, const char *picname );\n\nvoid\tSCR_DrawBigString( int x, int y, const char *s, float alpha );\t\t\t// draws a string with embedded color control characters with fade\nvoid\tSCR_DrawBigStringColor( int x, int y, const char *s, vec4_t color );\t// ignores embedded color control characters\nvoid\tSCR_DrawSmallStringExt( int x, int y, const char *string, float *setColor, qboolean forceColor );\nvoid\tSCR_DrawSmallChar( int x, int y, int ch );\n\n\n//\n// cl_cin.c\n//\n\nvoid CL_PlayCinematic_f( void );\nvoid SCR_DrawCinematic (void);\nvoid SCR_RunCinematic (void);\nvoid SCR_StopCinematic (void);\nint CIN_PlayCinematic( const char *arg0, int xpos, int ypos, int width, int height, int bits);\ne_status CIN_StopCinematic(int handle);\ne_status CIN_RunCinematic (int handle);\nvoid CIN_DrawCinematic (int handle);\nvoid CIN_SetExtents (int handle, int x, int y, int w, int h);\nvoid CIN_SetLooping (int handle, qboolean loop);\nvoid CIN_UploadCinematic(int handle);\nvoid CIN_CloseAllVideos(void);\n\n//\n// cl_cgame.c\n//\nvoid CL_InitCGame( void );\nvoid CL_ShutdownCGame( void );\nqboolean CL_GameCommand( void );\nvoid CL_CGameRendering( stereoFrame_t stereo );\nvoid CL_SetCGameTime( void );\nvoid CL_FirstSnapshot( void );\nvoid CL_ShaderStateChanged(void);\n\n//\n// cl_ui.c\n//\nvoid CL_InitUI( void );\nvoid CL_ShutdownUI( void );\nint Key_GetCatcher( void );\nvoid Key_SetCatcher( int catcher );\nvoid LAN_LoadCachedServers();\nvoid LAN_SaveServersToCache();\n\n\n//\n// cl_net_chan.c\n//\nvoid CL_Netchan_Transmit( netchan_t *chan, msg_t* msg);\t//int length, const byte *data );\nvoid CL_Netchan_TransmitNextFragment( netchan_t *chan );\nqboolean CL_Netchan_Process( netchan_t *chan, msg_t *msg );\n"
  },
  {
    "path": "src/engine/client/keys.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n#include \"../../q3_ui/keycodes.h\"\n\n#define\tMAX_KEYS\t\t256\n\ntypedef struct {\n\tqboolean\tdown;\n\tint\t\t\trepeats;\t\t// if > 1, it is autorepeating\n\tchar\t\t*binding;\n} qkey_t;\n\nextern\tqboolean\tkey_overstrikeMode;\nextern\tqkey_t\t\tkeys[MAX_KEYS];\n\n// NOTE TTimo the declaration of field_t and Field_Clear is now in qcommon/qcommon.h\nvoid Field_KeyDownEvent( field_t *edit, int key );\nvoid Field_CharEvent( field_t *edit, int ch );\nvoid Field_Draw( field_t *edit, int x, int y, int width, qboolean showCursor );\nvoid Field_BigDraw( field_t *edit, int x, int y, int width, qboolean showCursor );\n\n#define\t\tCOMMAND_HISTORY\t\t32\nextern\tfield_t\thistoryEditLines[COMMAND_HISTORY];\n\nextern\tfield_t\tg_consoleField;\nextern\tfield_t\tchatField;\nextern\tqboolean\tanykeydown;\nextern\tqboolean\tchat_team;\nextern\tint\t\t\tchat_playerNum;\n\nvoid Key_WriteBindings( fileHandle_t f );\nvoid Key_SetBinding( int keynum, const char *binding );\nchar *Key_GetBinding( int keynum );\nqboolean Key_IsDown( int keynum );\nqboolean Key_GetOverstrikeMode( void );\nvoid Key_SetOverstrikeMode( qboolean state );\nvoid Key_ClearStates( void );\nint Key_GetKey(const char *binding);\n"
  },
  {
    "path": "src/engine/client/snd_adpcm.c",
    "content": "/***********************************************************\nCopyright 1992 by Stichting Mathematisch Centrum, Amsterdam, The\nNetherlands.\n\n                        All Rights Reserved\n\nPermission to use, copy, modify, and distribute this software and its \ndocumentation for any purpose and without fee is hereby granted, \nprovided that the above copyright notice appear in all copies and that\nboth that copyright notice and this permission notice appear in \nsupporting documentation, and that the names of Stichting Mathematisch\nCentrum or CWI not be used in advertising or publicity pertaining to\ndistribution of the software without specific, written prior permission.\n\nSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO\nTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND\nFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE\nFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\nWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\nACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT\nOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n\n******************************************************************/\n\n/*\n** Intel/DVI ADPCM coder/decoder.\n**\n** The algorithm for this coder was taken from the IMA Compatability Project\n** proceedings, Vol 2, Number 2; May 1992.\n**\n** Version 1.2, 18-Dec-92.\n*/\n\n#include \"snd_local.h\"\n\n\n/* Intel ADPCM step variation table */\nstatic int indexTable[16] = {\n    -1, -1, -1, -1, 2, 4, 6, 8,\n    -1, -1, -1, -1, 2, 4, 6, 8,\n};\n\nstatic int stepsizeTable[89] = {\n    7, 8, 9, 10, 11, 12, 13, 14, 16, 17,\n    19, 21, 23, 25, 28, 31, 34, 37, 41, 45,\n    50, 55, 60, 66, 73, 80, 88, 97, 107, 118,\n    130, 143, 157, 173, 190, 209, 230, 253, 279, 307,\n    337, 371, 408, 449, 494, 544, 598, 658, 724, 796,\n    876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,\n    2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,\n    5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,\n    15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767\n};\n\n   \nvoid S_AdpcmEncode( short indata[], char outdata[], int len, struct adpcm_state *state ) {\n    short *inp;\t\t\t/* Input buffer pointer */\n    signed char *outp;\t\t/* output buffer pointer */\n    int val;\t\t\t/* Current input sample value */\n    int sign;\t\t\t/* Current adpcm sign bit */\n    int delta;\t\t\t/* Current adpcm output value */\n    int diff;\t\t\t/* Difference between val and sample */\n    int step;\t\t\t/* Stepsize */\n    int valpred;\t\t/* Predicted output value */\n    int vpdiff;\t\t\t/* Current change to valpred */\n    int index;\t\t\t/* Current step change index */\n    int outputbuffer;\t\t/* place to keep previous 4-bit value */\n    int bufferstep;\t\t/* toggle between outputbuffer/output */\n\n    outp = (signed char *)outdata;\n    inp = indata;\n\n    valpred = state->sample;\n    index = state->index;\n    step = stepsizeTable[index];\n    \n\toutputbuffer = 0;\t// quiet a compiler warning\n    bufferstep = 1;\n\n    for ( ; len > 0 ; len-- ) {\n\t\tval = *inp++;\n\n\t\t/* Step 1 - compute difference with previous value */\n\t\tdiff = val - valpred;\n\t\tsign = (diff < 0) ? 8 : 0;\n\t\tif ( sign ) diff = (-diff);\n\n\t\t/* Step 2 - Divide and clamp */\n\t\t/* Note:\n\t\t** This code *approximately* computes:\n\t\t**    delta = diff*4/step;\n\t\t**    vpdiff = (delta+0.5)*step/4;\n\t\t** but in shift step bits are dropped. The net result of this is\n\t\t** that even if you have fast mul/div hardware you cannot put it to\n\t\t** good use since the fixup would be too expensive.\n\t\t*/\n\t\tdelta = 0;\n\t\tvpdiff = (step >> 3);\n\t\t\n\t\tif ( diff >= step ) {\n\t\t\tdelta = 4;\n\t\t\tdiff -= step;\n\t\t\tvpdiff += step;\n\t\t}\n\t\tstep >>= 1;\n\t\tif ( diff >= step  ) {\n\t\t\tdelta |= 2;\n\t\t\tdiff -= step;\n\t\t\tvpdiff += step;\n\t\t}\n\t\tstep >>= 1;\n\t\tif ( diff >= step ) {\n\t\t\tdelta |= 1;\n\t\t\tvpdiff += step;\n\t\t}\n\n\t\t/* Step 3 - Update previous value */\n\t\tif ( sign )\n\t\t  valpred -= vpdiff;\n\t\telse\n\t\t  valpred += vpdiff;\n\n\t\t/* Step 4 - Clamp previous value to 16 bits */\n\t\tif ( valpred > 32767 )\n\t\t  valpred = 32767;\n\t\telse if ( valpred < -32768 )\n\t\t  valpred = -32768;\n\n\t\t/* Step 5 - Assemble value, update index and step values */\n\t\tdelta |= sign;\n\t\t\n\t\tindex += indexTable[delta];\n\t\tif ( index < 0 ) index = 0;\n\t\tif ( index > 88 ) index = 88;\n\t\tstep = stepsizeTable[index];\n\n\t\t/* Step 6 - Output value */\n\t\tif ( bufferstep ) {\n\t\t\toutputbuffer = (delta << 4) & 0xf0;\n\t\t} else {\n\t\t\t*outp++ = (delta & 0x0f) | outputbuffer;\n\t\t}\n\t\tbufferstep = !bufferstep;\n    }\n\n    /* Output last step, if needed */\n    if ( !bufferstep )\n      *outp++ = outputbuffer;\n    \n    state->sample = valpred;\n    state->index = index;\n}\n\n\n/* static */ void S_AdpcmDecode( const char indata[], short *outdata, int len, struct adpcm_state *state ) {\n    signed char *inp;\t\t/* Input buffer pointer */\n    int outp;\t\t\t/* output buffer pointer */\n    int sign;\t\t\t/* Current adpcm sign bit */\n    int delta;\t\t\t/* Current adpcm output value */\n    int step;\t\t\t/* Stepsize */\n    int valpred;\t\t/* Predicted value */\n    int vpdiff;\t\t\t/* Current change to valpred */\n    int index;\t\t\t/* Current step change index */\n    int inputbuffer;\t\t/* place to keep next 4-bit value */\n    int bufferstep;\t\t/* toggle between inputbuffer/input */\n\n    outp = 0;\n    inp = (signed char *)indata;\n\n    valpred = state->sample;\n    index = state->index;\n    step = stepsizeTable[index];\n\n    bufferstep = 0;\n    inputbuffer = 0;\t// quiet a compiler warning\n    for ( ; len > 0 ; len-- ) {\n\t\t\n\t\t/* Step 1 - get the delta value */\n\t\tif ( bufferstep ) {\n\t\t\tdelta = inputbuffer & 0xf;\n\t\t} else {\n\t\t\tinputbuffer = *inp++;\n\t\t\tdelta = (inputbuffer >> 4) & 0xf;\n\t\t}\n\t\tbufferstep = !bufferstep;\n\n\t\t/* Step 2 - Find new index value (for later) */\n\t\tindex += indexTable[delta];\n\t\tif ( index < 0 ) index = 0;\n\t\tif ( index > 88 ) index = 88;\n\n\t\t/* Step 3 - Separate sign and magnitude */\n\t\tsign = delta & 8;\n\t\tdelta = delta & 7;\n\n\t\t/* Step 4 - Compute difference and new predicted value */\n\t\t/*\n\t\t** Computes 'vpdiff = (delta+0.5)*step/4', but see comment\n\t\t** in adpcm_coder.\n\t\t*/\n\t\tvpdiff = step >> 3;\n\t\tif ( delta & 4 ) vpdiff += step;\n\t\tif ( delta & 2 ) vpdiff += step>>1;\n\t\tif ( delta & 1 ) vpdiff += step>>2;\n\n\t\tif ( sign )\n\t\t  valpred -= vpdiff;\n\t\telse\n\t\t  valpred += vpdiff;\n\n\t\t/* Step 5 - clamp output value */\n\t\tif ( valpred > 32767 )\n\t\t  valpred = 32767;\n\t\telse if ( valpred < -32768 )\n\t\t  valpred = -32768;\n\n\t\t/* Step 6 - Update step value */\n\t\tstep = stepsizeTable[index];\n\n\t\t/* Step 7 - Output value */\n\t\toutdata[outp] = valpred;\n\t\toutp++;\n    }\n\n    state->sample = valpred;\n    state->index = index;\n}\n\n\n/*\n====================\nS_AdpcmMemoryNeeded\n\nReturns the amount of memory (in bytes) needed to store the samples in out internal adpcm format\n====================\n*/\nint S_AdpcmMemoryNeeded( const wavinfo_t *info ) {\n\tfloat\tscale;\n\tint\t\tscaledSampleCount;\n\tint\t\tsampleMemory;\n\tint\t\tblockCount;\n\tint\t\theaderMemory;\n\n\t// determine scale to convert from input sampling rate to desired sampling rate\n\tscale = (float)info->rate / dma.speed;\n\n\t// calc number of samples at playback sampling rate\n\tscaledSampleCount = info->samples / scale;\n\n\t// calc memory need to store those samples using ADPCM at 4 bits per sample\n\tsampleMemory = scaledSampleCount / 2;\n\n\t// calc number of sample blocks needed of PAINTBUFFER_SIZE\n\tblockCount = scaledSampleCount / PAINTBUFFER_SIZE;\n\tif( scaledSampleCount % PAINTBUFFER_SIZE ) {\n\t\tblockCount++;\n\t}\n\n\t// calc memory needed to store the block headers\n\theaderMemory = blockCount * sizeof(adpcm_state_t);\n\n\treturn sampleMemory + headerMemory;\n}\n\n\n/*\n====================\nS_AdpcmGetSamples\n====================\n*/\nvoid S_AdpcmGetSamples(sndBuffer *chunk, short *to) {\n\tadpcm_state_t\tstate;\n\tbyte\t\t\t*out;\n\n\t// get the starting state from the block header\n\tstate.index = chunk->adpcm.index;\n\tstate.sample = chunk->adpcm.sample;\n\n\tout = (byte *)chunk->sndChunk;\n\t// get samples\n\tS_AdpcmDecode( (const char*) out, to, SND_CHUNK_SIZE_BYTE*2, &state );\n}\n\n\n/*\n====================\nS_AdpcmEncodeSound\n====================\n*/\nvoid S_AdpcmEncodeSound( sfx_t *sfx, short *samples ) {\n\tadpcm_state_t\tstate;\n\tint\t\t\t\tinOffset;\n\tint\t\t\t\tcount;\n\tint\t\t\t\tn;\n\tsndBuffer\t\t*newchunk, *chunk;\n\tbyte\t\t\t*out;\n\n\tinOffset = 0;\n\tcount = sfx->soundLength;\n\tstate.index = 0;\n\tstate.sample = samples[0];\n\n\tchunk = NULL;\n\twhile( count ) {\n\t\tn = count;\n\t\tif( n > SND_CHUNK_SIZE_BYTE*2 ) {\n\t\t\tn = SND_CHUNK_SIZE_BYTE*2;\n\t\t}\n\n\t\tnewchunk = SND_malloc();\n\t\tif (sfx->soundData == NULL) {\n\t\t\tsfx->soundData = newchunk;\n\t\t} else {\n\t\t\tchunk->next = newchunk;\n\t\t}\n\t\tchunk = newchunk;\n\n\t\t// output the header\n\t\tchunk->adpcm.index  = state.index;\n\t\tchunk->adpcm.sample = state.sample;\n\n\t\tout = (byte *)chunk->sndChunk;\n\n\t\t// encode the samples\n\t\tS_AdpcmEncode( samples + inOffset, (char*) out, n, &state );\n\n\t\tinOffset += n;\n\t\tcount -= n;\n\t}\n}\n"
  },
  {
    "path": "src/engine/client/snd_dma.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tsnd_dma.c\n *\n * desc:\t\tmain control for any streaming sound output device\n *\n * $Archive: /MissionPack/code/client/snd_dma.c $\n *\n *****************************************************************************/\n\n#include \"snd_local.h\"\n#include \"client.h\"\n\nvoid S_Play_f(void);\nvoid S_SoundList_f(void);\nvoid S_Music_f(void);\n\nvoid S_Update_();\nvoid S_StopAllSounds(void);\nvoid S_UpdateBackgroundTrack( void );\n\nstatic fileHandle_t s_backgroundFile;\nstatic wavinfo_t\ts_backgroundInfo;\n//int\t\t\ts_nextWavChunk;\nstatic int\t\t\ts_backgroundSamples;\nstatic char\t\ts_backgroundLoop[MAX_QPATH];\n//static char\t\ts_backgroundMusic[MAX_QPATH]; //TTimo: unused\n\n\n// =======================================================================\n// Internal sound data & structures\n// =======================================================================\n\n// only begin attenuating sound volumes when outside the FULLVOLUME range\n#define\t\tSOUND_FULLVOLUME\t80\n\n#define\t\tSOUND_ATTENUATE\t\t0.0008f\n\nchannel_t   s_channels[MAX_CHANNELS];\nchannel_t   loop_channels[MAX_CHANNELS];\nint\t\t\tnumLoopChannels;\n\nstatic int\ts_soundStarted;\nstatic\t\tqboolean\ts_soundMuted;\n\ndma_t\t\tdma;\n\nstatic int\t\t\tlistener_number;\nstatic vec3_t\t\tlistener_origin;\nstatic vec3_t\t\tlistener_axis[3];\n\nint\t\t\ts_soundtime;\t\t// sample PAIRS\nint   \t\ts_paintedtime; \t\t// sample PAIRS\n\n// MAX_SFX may be larger than MAX_SOUNDS because\n// of custom player sounds\n#define\t\tMAX_SFX\t\t\t4096\nsfx_t\t\ts_knownSfx[MAX_SFX];\nint\t\t\ts_numSfx = 0;\n\n#define\t\tLOOP_HASH\t\t128\nstatic\tsfx_t\t\t*sfxHash[LOOP_HASH];\n\ncvar_t\t\t*s_volume;\ncvar_t\t\t*s_testsound;\ncvar_t\t\t*s_khz;\ncvar_t\t\t*s_show;\ncvar_t\t\t*s_mixahead;\ncvar_t\t\t*s_mixPreStep;\ncvar_t\t\t*s_musicVolume;\ncvar_t\t\t*s_separation;\ncvar_t\t\t*s_doppler;\n\nstatic loopSound_t\t\tloopSounds[MAX_GENTITIES];\nstatic\tchannel_t\t\t*freelist = NULL;\n\nint\t\t\t\t\t\ts_rawend;\nportable_samplepair_t\ts_rawsamples[MAX_RAW_SAMPLES];\n\n\n// ====================================================================\n// User-setable variables\n// ====================================================================\n\n\nvoid S_SoundInfo_f(void) {\t\n\tCom_Printf(\"----- Sound Info -----\\n\" );\n\tif (!s_soundStarted) {\n\t\tCom_Printf (\"sound system not started\\n\");\n\t} else {\n\t\tif ( s_soundMuted ) {\n\t\t\tCom_Printf (\"sound system is muted\\n\");\n\t\t}\n\n\t\tCom_Printf(\"%5d stereo\\n\", dma.channels - 1);\n\t\tCom_Printf(\"%5d samples\\n\", dma.samples);\n\t\tCom_Printf(\"%5d samplebits\\n\", dma.samplebits);\n\t\tCom_Printf(\"%5d submission_chunk\\n\", dma.submission_chunk);\n\t\tCom_Printf(\"%5d speed\\n\", dma.speed);\n\t\tCom_Printf(\"0x%x dma buffer\\n\", dma.buffer);\n\t\tif ( s_backgroundFile ) {\n\t\t\tCom_Printf(\"Background file: %s\\n\", s_backgroundLoop );\n\t\t} else {\n\t\t\tCom_Printf(\"No background file.\\n\" );\n\t\t}\n\n\t}\n\tCom_Printf(\"----------------------\\n\" );\n}\n\n\n\n/*\n================\nS_Init\n================\n*/\nvoid S_Init( void ) {\n\tcvar_t\t*cv;\n\tqboolean\tr;\n\n\tCom_Printf(\"\\n------- sound initialization -------\\n\");\n\n\ts_volume = Cvar_Get (\"s_volume\", \"0.8\", CVAR_ARCHIVE);\n\ts_musicVolume = Cvar_Get (\"s_musicvolume\", \"0.25\", CVAR_ARCHIVE);\n\ts_separation = Cvar_Get (\"s_separation\", \"0.5\", CVAR_ARCHIVE);\n\ts_doppler = Cvar_Get (\"s_doppler\", \"1\", CVAR_ARCHIVE);\n\ts_khz = Cvar_Get (\"s_khz\", \"22\", CVAR_ARCHIVE);\n\ts_mixahead = Cvar_Get (\"s_mixahead\", \"0.2\", CVAR_ARCHIVE);\n\n\ts_mixPreStep = Cvar_Get (\"s_mixPreStep\", \"0.05\", CVAR_ARCHIVE);\n\ts_show = Cvar_Get (\"s_show\", \"0\", CVAR_CHEAT);\n\ts_testsound = Cvar_Get (\"s_testsound\", \"0\", CVAR_CHEAT);\n\n\tcv = Cvar_Get (\"s_initsound\", \"1\", 0);\n\tif ( !cv->integer ) {\n\t\tCom_Printf (\"not initializing.\\n\");\n\t\tCom_Printf(\"------------------------------------\\n\");\n\t\treturn;\n\t}\n\n\tCmd_AddCommand(\"play\", S_Play_f);\n\tCmd_AddCommand(\"music\", S_Music_f);\n\tCmd_AddCommand(\"s_list\", S_SoundList_f);\n\tCmd_AddCommand(\"s_info\", S_SoundInfo_f);\n\tCmd_AddCommand(\"s_stop\", S_StopAllSounds);\n\n\tr = SNDDMA_Init();\n\tCom_Printf(\"------------------------------------\\n\");\n\n\tif ( r ) {\n\t\ts_soundStarted = 1;\n\t\ts_soundMuted = (qboolean) 1;\n//\t\ts_numSfx = 0;\n\n\t\tCom_Memset(sfxHash, 0, sizeof(sfx_t *)*LOOP_HASH);\n\n\t\ts_soundtime = 0;\n\t\ts_paintedtime = 0;\n\n\t\tS_StopAllSounds ();\n\n\t\tS_SoundInfo_f();\n\t}\n\n}\n\n\nvoid S_ChannelFree(channel_t *v) {\n\tv->thesfx = NULL;\n\t*(channel_t **)v = freelist;\n\tfreelist = (channel_t*)v;\n}\n\nchannel_t*\tS_ChannelMalloc() {\n\tchannel_t *v;\n\tif (freelist == NULL) {\n\t\treturn NULL;\n\t}\n\tv = freelist;\n\tfreelist = *(channel_t **)freelist;\n\tv->allocTime = Com_Milliseconds();\n\treturn v;\n}\n\nvoid S_ChannelSetup() {\n\tchannel_t *p, *q;\n\n\t// clear all the sounds so they don't\n\tCom_Memset( s_channels, 0, sizeof( s_channels ) );\n\n\tp = s_channels;;\n\tq = p + MAX_CHANNELS;\n\twhile (--q > p) {\n\t\t*(channel_t **)q = q-1;\n\t}\n\t\n\t*(channel_t **)q = NULL;\n\tfreelist = p + MAX_CHANNELS - 1;\n\tCom_DPrintf(\"Channel memory manager started\\n\");\n}\n\n// =======================================================================\n// Shutdown sound engine\n// =======================================================================\n\nvoid S_Shutdown( void ) {\n\tif ( !s_soundStarted ) {\n\t\treturn;\n\t}\n\n\tSNDDMA_Shutdown();\n\n\ts_soundStarted = 0;\n\n    Cmd_RemoveCommand(\"play\");\n\tCmd_RemoveCommand(\"music\");\n\tCmd_RemoveCommand(\"stopsound\");\n\tCmd_RemoveCommand(\"soundlist\");\n\tCmd_RemoveCommand(\"soundinfo\");\n}\n\n\n// =======================================================================\n// Load a sound\n// =======================================================================\n\n/*\n================\nreturn a hash value for the sfx name\n================\n*/\nstatic long S_HashSFXName(const char *name) {\n\tint\t\ti;\n\tlong\thash;\n\tchar\tletter;\n\n\thash = 0;\n\ti = 0;\n\twhile (name[i] != '\\0') {\n\t\tletter = tolower(name[i]);\n\t\tif (letter =='.') break;\t\t\t\t// don't include extension\n\t\tif (letter =='\\\\') letter = '/';\t\t// damn path names\n\t\thash+=(long)(letter)*(i+119);\n\t\ti++;\n\t}\n\thash &= (LOOP_HASH-1);\n\treturn hash;\n}\n\n/*\n==================\nS_FindName\n\nWill allocate a new sfx if it isn't found\n==================\n*/\nstatic sfx_t *S_FindName( const char *name ) {\n\tint\t\ti;\n\tint\t\thash;\n\n\tsfx_t\t*sfx;\n\n\tif (!name) {\n\t\tCom_Error (ERR_FATAL, \"S_FindName: NULL\\n\");\n\t}\n\tif (!name[0]) {\n\t\tCom_Error (ERR_FATAL, \"S_FindName: empty name\\n\");\n\t}\n\n\tif (strlen(name) >= MAX_QPATH) {\n\t\tCom_Error (ERR_FATAL, \"Sound name too long: %s\", name);\n\t}\n\n\thash = S_HashSFXName(name);\n\n\tsfx = sfxHash[hash];\n\t// see if already loaded\n\twhile (sfx) {\n\t\tif (!Q_stricmp(sfx->soundName, name) ) {\n\t\t\treturn sfx;\n\t\t}\n\t\tsfx = sfx->next;\n\t}\n\n\t// find a free sfx\n\tfor (i=0 ; i < s_numSfx ; i++) {\n\t\tif (!s_knownSfx[i].soundName[0]) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (i == s_numSfx) {\n\t\tif (s_numSfx == MAX_SFX) {\n\t\t\tCom_Error (ERR_FATAL, \"S_FindName: out of sfx_t\");\n\t\t}\n\t\ts_numSfx++;\n\t}\n\t\n\tsfx = &s_knownSfx[i];\n\tCom_Memset (sfx, 0, sizeof(*sfx));\n\tstrcpy (sfx->soundName, name);\n\n\tsfx->next = sfxHash[hash];\n\tsfxHash[hash] = sfx;\n\n\treturn sfx;\n}\n\n/*\n=================\nS_DefaultSound\n=================\n*/\nvoid S_DefaultSound( sfx_t *sfx ) {\n\t\n\tint\t\ti;\n\n\tsfx->soundLength = 512;\n\tsfx->soundData = SND_malloc();\n\tsfx->soundData->next = NULL;\n\n\n\tfor ( i = 0 ; i < sfx->soundLength ; i++ ) {\n\t\tsfx->soundData->sndChunk[i] = i;\n\t}\n}\n\n/*\n===================\nS_DisableSounds\n\nDisables sounds until the next S_BeginRegistration.\nThis is called when the hunk is cleared and the sounds\nare no longer valid.\n===================\n*/\nvoid S_DisableSounds( void ) {\n\tS_StopAllSounds();\n\ts_soundMuted = qtrue;\n}\n\n/*\n=====================\nS_BeginRegistration\n\n=====================\n*/\nvoid S_BeginRegistration( void ) {\n\ts_soundMuted = qfalse;\t\t// we can play again\n\n\tif (s_numSfx == 0) {\n\t\tSND_setup();\n\n\t\ts_numSfx = 0;\n\t\tCom_Memset( s_knownSfx, 0, sizeof( s_knownSfx ) );\n\t\tCom_Memset(sfxHash, 0, sizeof(sfx_t *)*LOOP_HASH);\n\n\t\tS_RegisterSound(\"sound/feedback/hit.wav\", qfalse);\t\t// changed to a sound in baseq3\n\t}\n}\n\n\n/*\n==================\nS_RegisterSound\n\nCreates a default buzz sound if the file can't be loaded\n==================\n*/\nsfxHandle_t\tS_RegisterSound( const char *name, qboolean compressed ) {\n\tsfx_t\t*sfx;\n\n\tcompressed = qfalse;\n\tif (!s_soundStarted) {\n\t\treturn 0;\n\t}\n\n\tif ( (int)strlen( name ) >= MAX_QPATH ) {\n\t\tCom_Printf( \"Sound name exceeds MAX_QPATH\\n\" );\n\t\treturn 0;\n\t}\n\n\tsfx = S_FindName( name );\n\tif ( sfx->soundData ) {\n\t\tif ( sfx->defaultSound ) {\n\t\t\tCom_Printf( S_COLOR_YELLOW \"WARNING: could not find %s - using default\\n\", sfx->soundName );\n\t\t\treturn 0;\n\t\t}\n\t\treturn sfx - s_knownSfx;\n\t}\n\n\tsfx->inMemory = qfalse;\n\tsfx->soundCompressed = compressed;\n\n  S_memoryLoad(sfx);\n\n\tif ( sfx->defaultSound ) {\n\t\tCom_Printf( S_COLOR_YELLOW \"WARNING: could not find %s - using default\\n\", sfx->soundName );\n\t\treturn 0;\n\t}\n\n\treturn sfx - s_knownSfx;\n}\n\nvoid S_memoryLoad(sfx_t\t*sfx) {\n\t// load the sound file\n\tif ( !S_LoadSound ( sfx ) ) {\n//\t\tCom_Printf( S_COLOR_YELLOW \"WARNING: couldn't load sound: %s\\n\", sfx->soundName );\n\t\tsfx->defaultSound = qtrue;\n\t}\n\tsfx->inMemory = qtrue;\n}\n\n//=============================================================================\n\n/*\n=================\nS_SpatializeOrigin\n\nUsed for spatializing s_channels\n=================\n*/\nvoid S_SpatializeOrigin (vec3_t origin, int master_vol, int *left_vol, int *right_vol)\n{\n    vec_t\t\tdot;\n    vec_t\t\tdist;\n    vec_t\t\tlscale, rscale, scale;\n    vec3_t\t\tsource_vec;\n    vec3_t\t\tvec;\n\n\tconst float dist_mult = SOUND_ATTENUATE;\n\t\n\t// calculate stereo seperation and distance attenuation\n\tVectorSubtract(origin, listener_origin, source_vec);\n\n\tdist = VectorNormalize(source_vec);\n\tdist -= SOUND_FULLVOLUME;\n\tif (dist < 0)\n\t\tdist = 0;\t\t\t// close enough to be at full volume\n\tdist *= dist_mult;\t\t// different attenuation levels\n\t\n\tVectorRotate( source_vec, listener_axis, vec );\n\n\tdot = -vec[1];\n\n\tif (dma.channels == 1)\n\t{ // no attenuation = no spatialization\n\t\trscale = 1.0;\n\t\tlscale = 1.0;\n\t}\n\telse\n\t{\n\t\trscale = 0.5 * (1.0 + dot);\n\t\tlscale = 0.5 * (1.0 - dot);\n\t\t//rscale = s_separation->value + ( 1.0 - s_separation->value ) * dot;\n\t\t//lscale = s_separation->value - ( 1.0 - s_separation->value ) * dot;\n\t\tif ( rscale < 0 ) {\n\t\t\trscale = 0;\n\t\t}\n\t\tif ( lscale < 0 ) {\n\t\t\tlscale = 0;\n\t\t}\n\t}\n\n\t// add in distance effect\n\tscale = (1.0 - dist) * rscale;\n\t*right_vol = (master_vol * scale);\n\tif (*right_vol < 0)\n\t\t*right_vol = 0;\n\n\tscale = (1.0 - dist) * lscale;\n\t*left_vol = (master_vol * scale);\n\tif (*left_vol < 0)\n\t\t*left_vol = 0;\n}\n\n// =======================================================================\n// Start a sound effect\n// =======================================================================\n\n/*\n====================\nS_StartSound\n\nValidates the parms and ques the sound up\nif pos is NULL, the sound will be dynamically sourced from the entity\nEntchannel 0 will never override a playing sound\n====================\n*/\nvoid S_StartSound(vec3_t origin, int entityNum, int entchannel, sfxHandle_t sfxHandle ) {\n\tchannel_t\t*ch;\n\tsfx_t\t\t*sfx;\n  int i, oldest, chosen, time;\n  int\tinplay, allowed;\n\n\tif ( !s_soundStarted || s_soundMuted ) {\n\t\treturn;\n\t}\n\n\tif ( !origin && ( entityNum < 0 || entityNum > MAX_GENTITIES ) ) {\n\t\tCom_Error( ERR_DROP, \"S_StartSound: bad entitynum %i\", entityNum );\n\t}\n\n\tif ( sfxHandle < 0 || sfxHandle >= s_numSfx ) {\n\t\tCom_Printf( S_COLOR_YELLOW, \"S_StartSound: handle %i out of range\\n\", sfxHandle );\n\t\treturn;\n\t}\n\n\tsfx = &s_knownSfx[ sfxHandle ];\n\n\tif (sfx->inMemory == qfalse) {\n\t\tS_memoryLoad(sfx);\n\t}\n\n\tif ( s_show->integer == 1 ) {\n\t\tCom_Printf( \"%i : %s\\n\", s_paintedtime, sfx->soundName );\n\t}\n\n\ttime = Com_Milliseconds();\n\n//\tCom_Printf(\"playing %s\\n\", sfx->soundName);\n\t// pick a channel to play on\n\n\tallowed = 4;\n\tif (entityNum == listener_number) {\n\t\tallowed = 8;\n\t}\n\n\tch = s_channels;\n\tinplay = 0;\n\tfor ( i = 0; i < MAX_CHANNELS ; i++, ch++ ) {\t\t\n\t\tif (ch[i].entnum == entityNum && ch[i].thesfx == sfx) {\n\t\t\tif (time - ch[i].allocTime < 50) {\n//\t\t\t\tif (Cvar_VariableValue( \"cg_showmiss\" )) {\n//\t\t\t\t\tCom_Printf(\"double sound start\\n\");\n//\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tinplay++;\n\t\t}\n\t}\n\n\tif (inplay>allowed) {\n\t\treturn;\n\t}\n\n\tsfx->lastTimeUsed = time;\n\n\tch = S_ChannelMalloc();\t// entityNum, entchannel);\n\tif (!ch) {\n\t\tch = s_channels;\n\n\t\toldest = sfx->lastTimeUsed;\n\t\tchosen = -1;\n\t\tfor ( i = 0 ; i < MAX_CHANNELS ; i++, ch++ ) {\n\t\t\tif (ch->entnum != listener_number && ch->entnum == entityNum && ch->allocTime<oldest && ch->entchannel != CHAN_ANNOUNCER) {\n\t\t\t\toldest = ch->allocTime;\n\t\t\t\tchosen = i;\n\t\t\t}\n\t\t}\n\t\tif (chosen == -1) {\n\t\t\tch = s_channels;\n\t\t\tfor ( i = 0 ; i < MAX_CHANNELS ; i++, ch++ ) {\n\t\t\t\tif (ch->entnum != listener_number && ch->allocTime<oldest && ch->entchannel != CHAN_ANNOUNCER) {\n\t\t\t\t\toldest = ch->allocTime;\n\t\t\t\t\tchosen = i;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (chosen == -1) {\n\t\t\t\tif (ch->entnum == listener_number) {\n\t\t\t\t\tfor ( i = 0 ; i < MAX_CHANNELS ; i++, ch++ ) {\n\t\t\t\t\t\tif (ch->allocTime<oldest) {\n\t\t\t\t\t\t\toldest = ch->allocTime;\n\t\t\t\t\t\t\tchosen = i;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (chosen == -1) {\n\t\t\t\t\tCom_Printf(\"dropping sound\\n\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tch = &s_channels[chosen];\n\t\tch->allocTime = sfx->lastTimeUsed;\n\t}\n\n\tif (origin) {\n\t\tVectorCopy (origin, ch->origin);\n\t\tch->fixed_origin = qtrue;\n\t} else {\n\t\tch->fixed_origin = qfalse;\n\t}\n\n\tch->master_vol = 127;\n\tch->entnum = entityNum;\n\tch->thesfx = sfx;\n\tch->startSample = START_SAMPLE_IMMEDIATE;\n\tch->entchannel = entchannel;\n\tch->leftvol = ch->master_vol;\t\t// these will get calced at next spatialize\n\tch->rightvol = ch->master_vol;\t\t// unless the game isn't running\n\tch->doppler = qfalse;\n}\n\n\n/*\n==================\nS_StartLocalSound\n==================\n*/\nvoid S_StartLocalSound( sfxHandle_t sfxHandle, int channelNum ) {\n\tif ( !s_soundStarted || s_soundMuted ) {\n\t\treturn;\n\t}\n\n\tif ( sfxHandle < 0 || sfxHandle >= s_numSfx ) {\n\t\tCom_Printf( S_COLOR_YELLOW, \"S_StartLocalSound: handle %i out of range\\n\", sfxHandle );\n\t\treturn;\n\t}\n\n\tS_StartSound (NULL, listener_number, channelNum, sfxHandle );\n}\n\n\n/*\n==================\nS_ClearSoundBuffer\n\nIf we are about to perform file access, clear the buffer\nso sound doesn't stutter.\n==================\n*/\nvoid S_ClearSoundBuffer( void ) {\n\tint\t\tclear;\n\t\t\n\tif (!s_soundStarted)\n\t\treturn;\n\n\t// stop looping sounds\n\tCom_Memset(loopSounds, 0, MAX_GENTITIES*sizeof(loopSound_t));\n\tCom_Memset(loop_channels, 0, MAX_CHANNELS*sizeof(channel_t));\n\tnumLoopChannels = 0;\n\n\tS_ChannelSetup();\n\n\ts_rawend = 0;\n\n\tif (dma.samplebits == 8)\n\t\tclear = 0x80;\n\telse\n\t\tclear = 0;\n\n\tSNDDMA_BeginPainting ();\n\tif (dma.buffer)\n    // TTimo: due to a particular bug workaround in linux sound code,\n    //   have to optionally use a custom C implementation of Com_Memset\n    //   not affecting win32, we have #define Snd_Memset Com_Memset\n    // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=371\n\t\tSnd_Memset(dma.buffer, clear, dma.samples * dma.samplebits/8);\n\tSNDDMA_Submit ();\n}\n\n/*\n==================\nS_StopAllSounds\n==================\n*/\nvoid S_StopAllSounds(void) {\n\tif ( !s_soundStarted ) {\n\t\treturn;\n\t}\n\n\t// stop the background music\n\tS_StopBackgroundTrack();\n\n\tS_ClearSoundBuffer ();\n}\n\n/*\n==============================================================\n\ncontinuous looping sounds are added each frame\n\n==============================================================\n*/\n\nvoid S_StopLoopingSound(int entityNum) {\n\tloopSounds[entityNum].active = qfalse;\n//\tloopSounds[entityNum].sfx = 0;\n\tloopSounds[entityNum].kill = qfalse;\n}\n\n/*\n==================\nS_ClearLoopingSounds\n\n==================\n*/\nvoid S_ClearLoopingSounds( qboolean killall ) {\n\tint i;\n\tfor ( i = 0 ; i < MAX_GENTITIES ; i++) {\n\t\tif (killall || loopSounds[i].kill == qtrue || (loopSounds[i].sfx && loopSounds[i].sfx->soundLength == 0)) {\n\t\t\tloopSounds[i].kill = qfalse;\n\t\t\tS_StopLoopingSound(i);\n\t\t}\n\t}\n\tnumLoopChannels = 0;\n}\n\n/*\n==================\nS_AddLoopingSound\n\nCalled during entity generation for a frame\nInclude velocity in case I get around to doing doppler...\n==================\n*/\nvoid S_AddLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfxHandle ) {\n\tsfx_t *sfx;\n\n\tif ( !s_soundStarted || s_soundMuted ) {\n\t\treturn;\n\t}\n\n\tif ( sfxHandle < 0 || sfxHandle >= s_numSfx ) {\n\t\tCom_Printf( S_COLOR_YELLOW, \"S_AddLoopingSound: handle %i out of range\\n\", sfxHandle );\n\t\treturn;\n\t}\n\n\tsfx = &s_knownSfx[ sfxHandle ];\n\n\tif (sfx->inMemory == qfalse) {\n\t\tS_memoryLoad(sfx);\n\t}\n\n\tif ( !sfx->soundLength ) {\n\t\tCom_Error( ERR_DROP, \"%s has length 0\", sfx->soundName );\n\t}\n\n\tVectorCopy( origin, loopSounds[entityNum].origin );\n\tVectorCopy( velocity, loopSounds[entityNum].velocity );\n\tloopSounds[entityNum].active = qtrue;\n\tloopSounds[entityNum].kill = qtrue;\n\tloopSounds[entityNum].doppler = qfalse;\n\tloopSounds[entityNum].oldDopplerScale = 1.0;\n\tloopSounds[entityNum].dopplerScale = 1.0;\n\tloopSounds[entityNum].sfx = sfx;\n\n\tif (s_doppler->integer && VectorLengthSquared(velocity)>0.0) {\n\t\tvec3_t\tout;\n\t\tfloat\tlena, lenb;\n\n\t\tloopSounds[entityNum].doppler = qtrue;\n\t\tlena = DistanceSquared(loopSounds[listener_number].origin, loopSounds[entityNum].origin);\n\t\tVectorAdd(loopSounds[entityNum].origin, loopSounds[entityNum].velocity, out);\n\t\tlenb = DistanceSquared(loopSounds[listener_number].origin, out);\n\t\tif ((loopSounds[entityNum].framenum+1) != cls.framecount) {\n\t\t\tloopSounds[entityNum].oldDopplerScale = 1.0;\n\t\t} else {\n\t\t\tloopSounds[entityNum].oldDopplerScale = loopSounds[entityNum].dopplerScale;\n\t\t}\n\t\tloopSounds[entityNum].dopplerScale = lenb/(lena*100);\n\t\tif (loopSounds[entityNum].dopplerScale<=1.0) {\n\t\t\tloopSounds[entityNum].doppler = qfalse;\t\t\t// don't bother doing the math\n\t\t}\n\t}\n\n\tloopSounds[entityNum].framenum = cls.framecount;\n}\n\n/*\n==================\nS_AddLoopingSound\n\nCalled during entity generation for a frame\nInclude velocity in case I get around to doing doppler...\n==================\n*/\nvoid S_AddRealLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfxHandle ) {\n\tsfx_t *sfx;\n\n\tif ( !s_soundStarted || s_soundMuted ) {\n\t\treturn;\n\t}\n\n\tif ( sfxHandle < 0 || sfxHandle >= s_numSfx ) {\n\t\tCom_Printf( S_COLOR_YELLOW, \"S_AddRealLoopingSound: handle %i out of range\\n\", sfxHandle );\n\t\treturn;\n\t}\n\n\tsfx = &s_knownSfx[ sfxHandle ];\n\n\tif (sfx->inMemory == qfalse) {\n\t\tS_memoryLoad(sfx);\n\t}\n\n\tif ( !sfx->soundLength ) {\n\t\tCom_Error( ERR_DROP, \"%s has length 0\", sfx->soundName );\n\t}\n\tVectorCopy( origin, loopSounds[entityNum].origin );\n\tVectorCopy( velocity, loopSounds[entityNum].velocity );\n\tloopSounds[entityNum].sfx = sfx;\n\tloopSounds[entityNum].active = qtrue;\n\tloopSounds[entityNum].kill = qfalse;\n\tloopSounds[entityNum].doppler = qfalse;\n}\n\n\n\n/*\n==================\nS_AddLoopSounds\n\nSpatialize all of the looping sounds.\nAll sounds are on the same cycle, so any duplicates can just\nsum up the channel multipliers.\n==================\n*/\nvoid S_AddLoopSounds (void) {\n\tint\t\t\ti, j, time;\n\tint\t\t\tleft_total, right_total, left, right;\n\tchannel_t\t*ch;\n\tloopSound_t\t*loop, *loop2;\n\tstatic int\tloopFrame;\n\n\n\tnumLoopChannels = 0;\n\n\ttime = Com_Milliseconds();\n\n\tloopFrame++;\n\tfor ( i = 0 ; i < MAX_GENTITIES ; i++) {\n\t\tloop = &loopSounds[i];\n\t\tif ( !loop->active || loop->mergeFrame == loopFrame ) {\n\t\t\tcontinue;\t// already merged into an earlier sound\n\t\t}\n\n\t\tif (loop->kill) {\n\t\t\tS_SpatializeOrigin( loop->origin, 127, &left_total, &right_total);\t\t\t// 3d\n\t\t} else {\n\t\t\tS_SpatializeOrigin( loop->origin, 90,  &left_total, &right_total);\t\t\t// sphere\n\t\t}\n\n\t\tloop->sfx->lastTimeUsed = time;\n\n\t\tfor (j=(i+1); j< MAX_GENTITIES ; j++) {\n\t\t\tloop2 = &loopSounds[j];\n\t\t\tif ( !loop2->active || loop2->doppler || loop2->sfx != loop->sfx) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tloop2->mergeFrame = loopFrame;\n\n\t\t\tif (loop2->kill) {\n\t\t\t\tS_SpatializeOrigin( loop2->origin, 127, &left, &right);\t\t\t\t// 3d\n\t\t\t} else {\n\t\t\t\tS_SpatializeOrigin( loop2->origin, 90,  &left, &right);\t\t\t\t// sphere\n\t\t\t}\n\n\t\t\tloop2->sfx->lastTimeUsed = time;\n\t\t\tleft_total += left;\n\t\t\tright_total += right;\n\t\t}\n\t\tif (left_total == 0 && right_total == 0) {\n\t\t\tcontinue;\t\t// not audible\n\t\t}\n\n\t\t// allocate a channel\n\t\tch = &loop_channels[numLoopChannels];\n\t\t\n\t\tif (left_total > 255) {\n\t\t\tleft_total = 255;\n\t\t}\n\t\tif (right_total > 255) {\n\t\t\tright_total = 255;\n\t\t}\n\t\t\n\t\tch->master_vol = 127;\n\t\tch->leftvol = left_total;\n\t\tch->rightvol = right_total;\n\t\tch->thesfx = loop->sfx;\n\t\tch->doppler = loop->doppler;\n\t\tch->dopplerScale = loop->dopplerScale;\n\t\tch->oldDopplerScale = loop->oldDopplerScale;\n\t\tnumLoopChannels++;\n\t\tif (numLoopChannels == MAX_CHANNELS) {\n\t\t\treturn;\n\t\t}\n\t}\n}\n\n//=============================================================================\n\n/*\n=================\nS_ByteSwapRawSamples\n\nIf raw data has been loaded in little endien binary form, this must be done.\nIf raw data was calculated, as with ADPCM, this should not be called.\n=================\n*/\nvoid S_ByteSwapRawSamples( int samples, int width, int s_channels, const byte *data ) {\n\tint\t\ti;\n\n\tif ( width != 2 ) {\n\t\treturn;\n\t}\n\tif ( LittleShort( 256 ) == 256 ) {\n\t\treturn;\n\t}\n\n\tif ( s_channels == 2 ) {\n\t\tsamples <<= 1;\n\t}\n\tfor ( i = 0 ; i < samples ; i++ ) {\n\t\t((short *)data)[i] = LittleShort( ((short *)data)[i] );\n\t}\n}\n\nportable_samplepair_t *S_GetRawSamplePointer() {\n\treturn s_rawsamples;\n}\n\n/*\n============\nS_RawSamples\n\nMusic streaming\n============\n*/\nvoid S_RawSamples( int samples, int rate, int width, int s_channels, const byte *data, float volume ) {\n\tint\t\ti;\n\tint\t\tsrc, dst;\n\tfloat\tscale;\n\tint\t\tintVolume;\n\n\tif ( !s_soundStarted || s_soundMuted ) {\n\t\treturn;\n\t}\n\n\tintVolume = 256 * volume;\n\n\tif ( s_rawend < s_soundtime ) {\n\t\tCom_DPrintf( \"S_RawSamples: resetting minimum: %i < %i\\n\", s_rawend, s_soundtime );\n\t\ts_rawend = s_soundtime;\n\t}\n\n\tscale = (float)rate / dma.speed;\n\n//Com_Printf (\"%i < %i < %i\\n\", s_soundtime, s_paintedtime, s_rawend);\n\tif (s_channels == 2 && width == 2)\n\t{\n\t\tif (scale == 1.0)\n\t\t{\t// optimized case\n\t\t\tfor (i=0 ; i<samples ; i++)\n\t\t\t{\n\t\t\t\tdst = s_rawend&(MAX_RAW_SAMPLES-1);\n\t\t\t\ts_rawend++;\n\t\t\t\ts_rawsamples[dst].left = ((short *)data)[i*2] * intVolume;\n\t\t\t\ts_rawsamples[dst].right = ((short *)data)[i*2+1] * intVolume;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfor (i=0 ; ; i++)\n\t\t\t{\n\t\t\t\tsrc = i*scale;\n\t\t\t\tif (src >= samples)\n\t\t\t\t\tbreak;\n\t\t\t\tdst = s_rawend&(MAX_RAW_SAMPLES-1);\n\t\t\t\ts_rawend++;\n\t\t\t\ts_rawsamples[dst].left = ((short *)data)[src*2] * intVolume;\n\t\t\t\ts_rawsamples[dst].right = ((short *)data)[src*2+1] * intVolume;\n\t\t\t}\n\t\t}\n\t}\n\telse if (s_channels == 1 && width == 2)\n\t{\n\t\tfor (i=0 ; ; i++)\n\t\t{\n\t\t\tsrc = i*scale;\n\t\t\tif (src >= samples)\n\t\t\t\tbreak;\n\t\t\tdst = s_rawend&(MAX_RAW_SAMPLES-1);\n\t\t\ts_rawend++;\n\t\t\ts_rawsamples[dst].left = ((short *)data)[src] * intVolume;\n\t\t\ts_rawsamples[dst].right = ((short *)data)[src] * intVolume;\n\t\t}\n\t}\n\telse if (s_channels == 2 && width == 1)\n\t{\n\t\tintVolume *= 256;\n\n\t\tfor (i=0 ; ; i++)\n\t\t{\n\t\t\tsrc = i*scale;\n\t\t\tif (src >= samples)\n\t\t\t\tbreak;\n\t\t\tdst = s_rawend&(MAX_RAW_SAMPLES-1);\n\t\t\ts_rawend++;\n\t\t\ts_rawsamples[dst].left = ((char *)data)[src*2] * intVolume;\n\t\t\ts_rawsamples[dst].right = ((char *)data)[src*2+1] * intVolume;\n\t\t}\n\t}\n\telse if (s_channels == 1 && width == 1)\n\t{\n\t\tintVolume *= 256;\n\n\t\tfor (i=0 ; ; i++)\n\t\t{\n\t\t\tsrc = i*scale;\n\t\t\tif (src >= samples)\n\t\t\t\tbreak;\n\t\t\tdst = s_rawend&(MAX_RAW_SAMPLES-1);\n\t\t\ts_rawend++;\n\t\t\ts_rawsamples[dst].left = (((byte *)data)[src]-128) * intVolume;\n\t\t\ts_rawsamples[dst].right = (((byte *)data)[src]-128) * intVolume;\n\t\t}\n\t}\n\n\tif ( s_rawend > s_soundtime + MAX_RAW_SAMPLES ) {\n\t\tCom_DPrintf( \"S_RawSamples: overflowed %i > %i\\n\", s_rawend, s_soundtime );\n\t}\n}\n\n//=============================================================================\n\n/*\n=====================\nS_UpdateEntityPosition\n\nlet the sound system know where an entity currently is\n======================\n*/\nvoid S_UpdateEntityPosition( int entityNum, const vec3_t origin ) {\n\tif ( entityNum < 0 || entityNum > MAX_GENTITIES ) {\n\t\tCom_Error( ERR_DROP, \"S_UpdateEntityPosition: bad entitynum %i\", entityNum );\n\t}\n\tVectorCopy( origin, loopSounds[entityNum].origin );\n}\n\n\n/*\n============\nS_Respatialize\n\nChange the volumes of all the playing sounds for changes in their positions\n============\n*/\nvoid S_Respatialize( int entityNum, const vec3_t head, vec3_t axis[3], int inwater ) {\n\tint\t\t\ti;\n\tchannel_t\t*ch;\n\tvec3_t\t\torigin;\n\n\tif ( !s_soundStarted || s_soundMuted ) {\n\t\treturn;\n\t}\n\n\tlistener_number = entityNum;\n\tVectorCopy(head, listener_origin);\n\tVectorCopy(axis[0], listener_axis[0]);\n\tVectorCopy(axis[1], listener_axis[1]);\n\tVectorCopy(axis[2], listener_axis[2]);\n\n\t// update spatialization for dynamic sounds\t\n\tch = s_channels;\n\tfor ( i = 0 ; i < MAX_CHANNELS ; i++, ch++ ) {\n\t\tif ( !ch->thesfx ) {\n\t\t\tcontinue;\n\t\t}\n\t\t// anything coming from the view entity will always be full volume\n\t\tif (ch->entnum == listener_number) {\n\t\t\tch->leftvol = ch->master_vol;\n\t\t\tch->rightvol = ch->master_vol;\n\t\t} else {\n\t\t\tif (ch->fixed_origin) {\n\t\t\t\tVectorCopy( ch->origin, origin );\n\t\t\t} else {\n\t\t\t\tVectorCopy( loopSounds[ ch->entnum ].origin, origin );\n\t\t\t}\n\n\t\t\tS_SpatializeOrigin (origin, ch->master_vol, &ch->leftvol, &ch->rightvol);\n\t\t}\n\t}\n\n\t// add loopsounds\n\tS_AddLoopSounds ();\n}\n\n\n/*\n========================\nS_ScanChannelStarts\n\nReturns qtrue if any new sounds were started since the last mix\n========================\n*/\nqboolean S_ScanChannelStarts( void ) {\n\tchannel_t\t\t*ch;\n\tint\t\t\t\ti;\n\tqboolean\t\tnewSamples;\n\n\tnewSamples = qfalse;\n\tch = s_channels;\n\n\tfor (i=0; i<MAX_CHANNELS ; i++, ch++) {\n\t\tif ( !ch->thesfx ) {\n\t\t\tcontinue;\n\t\t}\n\t\t// if this channel was just started this frame,\n\t\t// set the sample count to it begins mixing\n\t\t// into the very first sample\n\t\tif ( ch->startSample == START_SAMPLE_IMMEDIATE ) {\n\t\t\tch->startSample = s_paintedtime;\n\t\t\tnewSamples = qtrue;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// if it is completely finished by now, clear it\n\t\tif ( ch->startSample + (ch->thesfx->soundLength) <= s_paintedtime ) {\n\t\t\tS_ChannelFree(ch);\n\t\t}\n\t}\n\n\treturn newSamples;\n}\n\n/*\n============\nS_Update\n\nCalled once each time through the main loop\n============\n*/\nvoid S_Update( void ) {\n\tint\t\t\ti;\n\tint\t\t\ttotal;\n\tchannel_t\t*ch;\n\n\tif ( !s_soundStarted || s_soundMuted ) {\n\t\tCom_DPrintf (\"not started or muted\\n\");\n\t\treturn;\n\t}\n\n\t//\n\t// debugging output\n\t//\n\tif ( s_show->integer == 2 ) {\n\t\ttotal = 0;\n\t\tch = s_channels;\n\t\tfor (i=0 ; i<MAX_CHANNELS; i++, ch++) {\n\t\t\tif (ch->thesfx && (ch->leftvol || ch->rightvol) ) {\n\t\t\t\tCom_Printf (\"%f %f %s\\n\", ch->leftvol, ch->rightvol, ch->thesfx->soundName);\n\t\t\t\ttotal++;\n\t\t\t}\n\t\t}\n\t\t\n\t\tCom_Printf (\"----(%i)---- painted: %i\\n\", total, s_paintedtime);\n\t}\n\n\t// add raw data from streamed samples\n\tS_UpdateBackgroundTrack();\n\n\t// mix some sound\n\tS_Update_();\n}\n\nvoid S_GetSoundtime(void)\n{\n\tint\t\tsamplepos;\n\tstatic\tint\t\tbuffers;\n\tstatic\tint\t\toldsamplepos;\n\tint\t\tfullsamples;\n\t\n\tfullsamples = dma.samples / dma.channels;\n\n\t// it is possible to miscount buffers if it has wrapped twice between\n\t// calls to S_Update.  Oh well.\n\tsamplepos = SNDDMA_GetDMAPos();\n\tif (samplepos < oldsamplepos)\n\t{\n\t\tbuffers++;\t\t\t\t\t// buffer wrapped\n\t\t\n\t\tif (s_paintedtime > 0x40000000)\n\t\t{\t// time to chop things off to avoid 32 bit limits\n\t\t\tbuffers = 0;\n\t\t\ts_paintedtime = fullsamples;\n\t\t\tS_StopAllSounds ();\n\t\t}\n\t}\n\toldsamplepos = samplepos;\n\n\ts_soundtime = buffers*fullsamples + samplepos/dma.channels;\n\n#if 0\n// check to make sure that we haven't overshot\n\tif (s_paintedtime < s_soundtime)\n\t{\n\t\tCom_DPrintf (\"S_Update_ : overflow\\n\");\n\t\ts_paintedtime = s_soundtime;\n\t}\n#endif\n\n\tif ( dma.submission_chunk < 256 ) {\n\t\ts_paintedtime = s_soundtime + s_mixPreStep->value * dma.speed;\n\t} else {\n\t\ts_paintedtime = s_soundtime + dma.submission_chunk;\n\t}\n}\n\n\nvoid S_Update_(void) {\n\tunsigned        endtime;\n\tint\t\t\t\tsamps;\n\tstatic\t\t\tfloat\tlastTime = 0.0f;\n\tfloat\t\t\tma, op;\n\tfloat\t\t\tthisTime, sane;\n\tstatic\t\t\tint ot = -1;\n\n\tif ( !s_soundStarted || s_soundMuted ) {\n\t\treturn;\n\t}\n\n\tthisTime = Com_Milliseconds();\n\n\t// Updates s_soundtime\n\tS_GetSoundtime();\n\n\tif (s_soundtime == ot) {\n\t\treturn;\n\t}\n\tot = s_soundtime;\n\n\t// clear any sound effects that end before the current time,\n\t// and start any new sounds\n\tS_ScanChannelStarts();\n\n\tsane = thisTime - lastTime;\n\tif (sane<11) {\n\t\tsane = 11;\t\t\t// 85hz\n\t}\n\n\tma = s_mixahead->value * dma.speed;\n\top = s_mixPreStep->value + sane*dma.speed*0.01;\n\n\tif (op < ma) {\n\t\tma = op;\n\t}\n\n\t// mix ahead of current position\n\tendtime = s_soundtime + ma;\n\n\t// mix to an even submission block size\n\tendtime = (endtime + dma.submission_chunk-1)\n\t\t& ~(dma.submission_chunk-1);\n\n\t// never mix more than the complete buffer\n\tsamps = dma.samples >> (dma.channels-1);\n\tif (endtime - s_soundtime > samps)\n\t\tendtime = s_soundtime + samps;\n\n\n\n\tSNDDMA_BeginPainting ();\n\n\tS_PaintChannels (endtime);\n\n\tSNDDMA_Submit ();\n\n\tlastTime = thisTime;\n}\n\n/*\n===============================================================================\n\nconsole functions\n\n===============================================================================\n*/\n\nvoid S_Play_f( void ) {\n\tint \t\ti;\n\tsfxHandle_t\th;\n\tchar\t\tname[256];\n\t\n\ti = 1;\n\twhile ( i<Cmd_Argc() ) {\n\t\tif ( !Q_strrchr(Cmd_Argv(i), '.') ) {\n\t\t\tCom_sprintf( name, sizeof(name), \"%s.wav\", Cmd_Argv(1) );\n\t\t} else {\n\t\t\tQ_strncpyz( name, Cmd_Argv(i), sizeof(name) );\n\t\t}\n\t\th = S_RegisterSound( name, qfalse );\n\t\tif( h ) {\n\t\t\tS_StartLocalSound( h, CHAN_LOCAL_SOUND );\n\t\t}\n\t\ti++;\n\t}\n}\n\nvoid S_Music_f( void ) {\n\tint\t\tc;\n\n\tc = Cmd_Argc();\n\n\tif ( c == 2 ) {\n\t\tS_StartBackgroundTrack( Cmd_Argv(1), Cmd_Argv(1) );\n\t\ts_backgroundLoop[0] = 0;\n\t} else if ( c == 3 ) {\n\t\tS_StartBackgroundTrack( Cmd_Argv(1), Cmd_Argv(2) );\n\t} else {\n\t\tCom_Printf (\"music <musicfile> [loopfile]\\n\");\n\t\treturn;\n\t}\n\n}\n\nvoid S_SoundList_f( void ) {\n\tint\t\ti;\n\tsfx_t\t*sfx;\n\tint\t\tsize, total;\n\tchar\ttype[4][16];\n\tchar\tmem[2][16];\n\n\tstrcpy(type[0], \"16bit\");\n\tstrcpy(type[1], \"adpcm\");\n\tstrcpy(type[2], \"daub4\");\n\tstrcpy(type[3], \"mulaw\");\n\tstrcpy(mem[0], \"paged out\");\n\tstrcpy(mem[1], \"resident \");\n\ttotal = 0;\n\tfor (sfx=s_knownSfx, i=0 ; i<s_numSfx ; i++, sfx++) {\n\t\tsize = sfx->soundLength;\n\t\ttotal += size;\n\t\tCom_Printf(\"%6i[%s] : %s[%s]\\n\", size, type[sfx->soundCompressionMethod], sfx->soundName, mem[sfx->inMemory] );\n\t}\n\tCom_Printf (\"Total resident: %i\\n\", total);\n\tS_DisplayFreeMemory();\n}\n\n\n/*\n===============================================================================\n\nbackground music functions\n\n===============================================================================\n*/\n\nint\tFGetLittleLong( fileHandle_t f ) {\n\tint\t\tv;\n\n\tFS_Read( &v, sizeof(v), f );\n\n\treturn LittleLong( v);\n}\n\nint\tFGetLittleShort( fileHandle_t f ) {\n\tshort\tv;\n\n\tFS_Read( &v, sizeof(v), f );\n\n\treturn LittleShort( v);\n}\n\n// returns the length of the data in the chunk, or 0 if not found\nint S_FindWavChunk( fileHandle_t f, char *chunk ) {\n\tchar\tname[5];\n\tint\t\tlen;\n\tint\t\tr;\n\n\tname[4] = 0;\n\tlen = 0;\n\tr = FS_Read( name, 4, f );\n\tif ( r != 4 ) {\n\t\treturn 0;\n\t}\n\tlen = FGetLittleLong( f );\n\tif ( len < 0 || len > 0xfffffff ) {\n\t\tlen = 0;\n\t\treturn 0;\n\t}\n\tlen = (len + 1 ) & ~1;\t\t// pad to word boundary\n//\ts_nextWavChunk += len + 8;\n\n\tif ( strcmp( name, chunk ) ) {\n\t\treturn 0;\n\t}\n\n\treturn len;\n}\n\n/*\n======================\nS_StopBackgroundTrack\n======================\n*/\nvoid S_StopBackgroundTrack( void ) {\n\tif ( !s_backgroundFile ) {\n\t\treturn;\n\t}\n\tSys_EndStreamedFile( s_backgroundFile );\n\tFS_FCloseFile( s_backgroundFile );\n\ts_backgroundFile = 0;\n\ts_rawend = 0;\n}\n\n/*\n======================\nS_StartBackgroundTrack\n======================\n*/\nvoid S_StartBackgroundTrack( const char *intro, const char *loop ){\n\tint\t\tlen;\n\tchar\tdump[16];\n\tchar\tname[MAX_QPATH];\n\n\tif ( !intro ) {\n\t\tintro = \"\";\n\t}\n\tif ( !loop || !loop[0] ) {\n\t\tloop = intro;\n\t}\n\tCom_DPrintf( \"S_StartBackgroundTrack( %s, %s )\\n\", intro, loop );\n\n\tQ_strncpyz( name, intro, sizeof( name ) - 4 );\n\tCOM_DefaultExtension( name, sizeof( name ), \".wav\" );\n\n\tif ( !intro[0] ) {\n\t\treturn;\n\t}\n\n\tQ_strncpyz( s_backgroundLoop, loop, sizeof( s_backgroundLoop ) );\n\n\t// close the background track, but DON'T reset s_rawend\n\t// if restarting the same back ground track\n\tif ( s_backgroundFile ) {\n\t\tSys_EndStreamedFile( s_backgroundFile );\n\t\tFS_FCloseFile( s_backgroundFile );\n\t\ts_backgroundFile = 0;\n\t}\n\n\t//\n\t// open up a wav file and get all the info\n\t//\n\tFS_FOpenFileRead( name, &s_backgroundFile, qtrue );\n\tif ( !s_backgroundFile ) {\n\t\tCom_Printf( S_COLOR_YELLOW \"WARNING: couldn't open music file %s\\n\", name );\n\t\treturn;\n\t}\n\n\t// skip the riff wav header\n\n\tFS_Read(dump, 12, s_backgroundFile);\n\n\tif ( !S_FindWavChunk( s_backgroundFile, \"fmt \" ) ) {\n\t\tCom_Printf( \"No fmt chunk in %s\\n\", name );\n\t\tFS_FCloseFile( s_backgroundFile );\n\t\ts_backgroundFile = 0;\n\t\treturn;\n\t}\n\n\t// save name for soundinfo\n\ts_backgroundInfo.format = FGetLittleShort( s_backgroundFile );\n\ts_backgroundInfo.channels = FGetLittleShort( s_backgroundFile );\n\ts_backgroundInfo.rate = FGetLittleLong( s_backgroundFile );\n\tFGetLittleLong(  s_backgroundFile );\n\tFGetLittleShort(  s_backgroundFile );\n\ts_backgroundInfo.width = FGetLittleShort( s_backgroundFile ) / 8;\n\n\tif ( s_backgroundInfo.format != WAV_FORMAT_PCM ) {\n\t\tFS_FCloseFile( s_backgroundFile );\n\t\ts_backgroundFile = 0;\n\t\tCom_Printf(\"Not a microsoft PCM format wav: %s\\n\", name);\n\t\treturn;\n\t}\n\n\tif ( s_backgroundInfo.channels != 2 || s_backgroundInfo.rate != 22050 ) {\n\t\tCom_Printf(S_COLOR_YELLOW \"WARNING: music file %s is not 22k stereo\\n\", name );\n\t}\n\n\tif ( ( len = S_FindWavChunk( s_backgroundFile, \"data\" ) ) == 0 ) {\n\t\tFS_FCloseFile( s_backgroundFile );\n\t\ts_backgroundFile = 0;\n\t\tCom_Printf(\"No data chunk in %s\\n\", name);\n\t\treturn;\n\t}\n\n\ts_backgroundInfo.samples = len / (s_backgroundInfo.width * s_backgroundInfo.channels);\n\n\ts_backgroundSamples = s_backgroundInfo.samples;\n\n\t//\n\t// start the background streaming\n\t//\n\tSys_BeginStreamedFile( s_backgroundFile, 0x10000 );\n}\n\n/*\n======================\nS_UpdateBackgroundTrack\n======================\n*/\nvoid S_UpdateBackgroundTrack( void ) {\n\tint\t\tbufferSamples;\n\tint\t\tfileSamples;\n\tbyte\traw[30000];\t\t// just enough to fit in a mac stack frame\n\tint\t\tfileBytes;\n\tint\t\tr;\n\tstatic\tfloat\tmusicVolume = 0.5f;\n\n\tif ( !s_backgroundFile ) {\n\t\treturn;\n\t}\n\n\t// graeme see if this is OK\n\tmusicVolume = (musicVolume + (s_musicVolume->value * 2))/4.0f;\n\n\t// don't bother playing anything if musicvolume is 0\n\tif ( musicVolume <= 0 ) {\n\t\treturn;\n\t}\n\n\t// see how many samples should be copied into the raw buffer\n\tif ( s_rawend < s_soundtime ) {\n\t\ts_rawend = s_soundtime;\n\t}\n\n\twhile ( s_rawend < s_soundtime + MAX_RAW_SAMPLES ) {\n\t\tbufferSamples = MAX_RAW_SAMPLES - (s_rawend - s_soundtime);\n\n\t\t// decide how much data needs to be read from the file\n\t\tfileSamples = bufferSamples * s_backgroundInfo.rate / dma.speed;\n\n\t\t// don't try and read past the end of the file\n\t\tif ( fileSamples > s_backgroundSamples ) {\n\t\t\tfileSamples = s_backgroundSamples;\n\t\t}\n\n\t\t// our max buffer size\n\t\tfileBytes = fileSamples * (s_backgroundInfo.width * s_backgroundInfo.channels);\n\t\tif ( fileBytes > sizeof(raw) ) {\n\t\t\tfileBytes = sizeof(raw);\n\t\t\tfileSamples = fileBytes / (s_backgroundInfo.width * s_backgroundInfo.channels);\n\t\t}\n\n\t\tr = Sys_StreamedRead( raw, 1, fileBytes, s_backgroundFile );\n\t\tif ( r != fileBytes ) {\n\t\t\tCom_Printf(\"StreamedRead failure on music track\\n\");\n\t\t\tS_StopBackgroundTrack();\n\t\t\treturn;\n\t\t}\n\n\t\t// byte swap if needed\n\t\tS_ByteSwapRawSamples( fileSamples, s_backgroundInfo.width, s_backgroundInfo.channels, raw );\n\n\t\t// add to raw buffer\n\t\tS_RawSamples( fileSamples, s_backgroundInfo.rate, \n\t\t\ts_backgroundInfo.width, s_backgroundInfo.channels, raw, musicVolume );\n\n\t\ts_backgroundSamples -= fileSamples;\n\t\tif ( !s_backgroundSamples ) {\n\t\t\t// loop\n\t\t\tif (s_backgroundLoop[0]) {\n\t\t\t\tSys_EndStreamedFile( s_backgroundFile );\n\t\t\t\tFS_FCloseFile( s_backgroundFile );\n\t\t\t\ts_backgroundFile = 0;\n\t\t\t\tS_StartBackgroundTrack( s_backgroundLoop, s_backgroundLoop );\n\t\t\t\tif ( !s_backgroundFile ) {\n\t\t\t\t\treturn;\t\t// loop failed to restart\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\ts_backgroundFile = 0;\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n}\n\n\n/*\n======================\nS_FreeOldestSound\n======================\n*/\n\nvoid S_FreeOldestSound() {\n\tint\ti, oldest, used;\n\tsfx_t\t*sfx;\n\tsndBuffer\t*buffer, *nbuffer;\n\n\toldest = Com_Milliseconds();\n\tused = 0;\n\n\tfor (i=1 ; i < s_numSfx ; i++) {\n\t\tsfx = &s_knownSfx[i];\n\t\tif (sfx->inMemory && sfx->lastTimeUsed<oldest) {\n\t\t\tused = i;\n\t\t\toldest = sfx->lastTimeUsed;\n\t\t}\n\t}\n\n\tsfx = &s_knownSfx[used];\n\n\tCom_DPrintf(\"S_FreeOldestSound: freeing sound %s\\n\", sfx->soundName);\n\n\tbuffer = sfx->soundData;\n\twhile(buffer != NULL) {\n\t\tnbuffer = buffer->next;\n\t\tSND_free(buffer);\n\t\tbuffer = nbuffer;\n\t}\n\tsfx->inMemory = qfalse;\n\tsfx->soundData = NULL;\n}\n"
  },
  {
    "path": "src/engine/client/snd_local.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n// snd_local.h -- private sound definations\n\n\n#include \"../../game/q_shared.h\"\n#include \"../qcommon/qcommon.h\"\n#include \"snd_public.h\"\n\n#define\tPAINTBUFFER_SIZE\t\t4096\t\t\t\t\t// this is in samples\n\n#define SND_CHUNK_SIZE\t\t\t1024\t\t\t\t\t// samples\n#define SND_CHUNK_SIZE_FLOAT\t(SND_CHUNK_SIZE/2)\t\t// floats\n#define SND_CHUNK_SIZE_BYTE\t\t(SND_CHUNK_SIZE*2)\t\t// floats\n\ntypedef struct {\n\tint\t\t\tleft;\t// the final values will be clamped to +/- 0x00ffff00 and shifted down\n\tint\t\t\tright;\n} portable_samplepair_t;\n\ntypedef struct adpcm_state {\n    short\tsample;\t\t/* Previous output value */\n    char\tindex;\t\t/* Index into stepsize table */\n} adpcm_state_t;\n\ntypedef\tstruct sndBuffer_s {\n\tshort\t\t\t\t\tsndChunk[SND_CHUNK_SIZE];\n\tstruct sndBuffer_s\t\t*next;\n    int\t\t\t\t\t\tsize;\n\tadpcm_state_t\t\t\tadpcm;\n} sndBuffer;\n\ntypedef struct sfx_s {\n\tsndBuffer\t\t*soundData;\n\tqboolean\t\tdefaultSound;\t\t\t// couldn't be loaded, so use buzz\n\tqboolean\t\tinMemory;\t\t\t\t// not in Memory\n\tqboolean\t\tsoundCompressed;\t\t// not in Memory\n\tint\t\t\t\tsoundCompressionMethod;\t\n\tint \t\t\tsoundLength;\n\tchar \t\t\tsoundName[MAX_QPATH];\n\tint\t\t\t\tlastTimeUsed;\n\tstruct sfx_s\t*next;\n} sfx_t;\n\ntypedef struct {\n\tint\t\t\tchannels;\n\tint\t\t\tsamples;\t\t\t\t// mono samples in buffer\n\tint\t\t\tsubmission_chunk;\t\t// don't mix less than this #\n\tint\t\t\tsamplebits;\n\tint\t\t\tspeed;\n\tbyte\t\t*buffer;\n} dma_t;\n\n#define START_SAMPLE_IMMEDIATE\t0x7fffffff\n\ntypedef struct loopSound_s {\n\tvec3_t\t\torigin;\n\tvec3_t\t\tvelocity;\n\tsfx_t\t\t*sfx;\n\tint\t\t\tmergeFrame;\n\tqboolean\tactive;\n\tqboolean\tkill;\n\tqboolean\tdoppler;\n\tfloat\t\tdopplerScale;\n\tfloat\t\toldDopplerScale;\n\tint\t\t\tframenum;\n} loopSound_t;\n\ntypedef struct\n{\n\tint\t\t\tallocTime;\n\tint\t\t\tstartSample;\t// START_SAMPLE_IMMEDIATE = set immediately on next mix\n\tint\t\t\tentnum;\t\t\t// to allow overriding a specific sound\n\tint\t\t\tentchannel;\t\t// to allow overriding a specific sound\n\tint\t\t\tleftvol;\t\t// 0-255 volume after spatialization\n\tint\t\t\trightvol;\t\t// 0-255 volume after spatialization\n\tint\t\t\tmaster_vol;\t\t// 0-255 volume before spatialization\n\tfloat\t\tdopplerScale;\n\tfloat\t\toldDopplerScale;\n\tvec3_t\t\torigin;\t\t\t// only use if fixed_origin is set\n\tqboolean\tfixed_origin;\t// use origin instead of fetching entnum's origin\n\tsfx_t\t\t*thesfx;\t\t// sfx structure\n\tqboolean\tdoppler;\n} channel_t;\n\n\n#define\tWAV_FORMAT_PCM\t\t1\n\n\ntypedef struct {\n\tint\t\t\tformat;\n\tint\t\t\trate;\n\tint\t\t\twidth;\n\tint\t\t\tchannels;\n\tint\t\t\tsamples;\n\tint\t\t\tdataofs;\t\t// chunk starts this many bytes from file start\n} wavinfo_t;\n\n\n/*\n====================================================================\n\n  SYSTEM SPECIFIC FUNCTIONS\n\n====================================================================\n*/\n\n// initializes cycling through a DMA buffer and returns information on it\nqboolean SNDDMA_Init(void);\n\n// gets the current DMA position\nint\t\tSNDDMA_GetDMAPos(void);\n\n// shutdown the DMA xfer.\nvoid\tSNDDMA_Shutdown(void);\n\nvoid\tSNDDMA_BeginPainting (void);\n\nvoid\tSNDDMA_Submit(void);\n\n//====================================================================\n\n#define\tMAX_CHANNELS\t\t\t96\n\nextern\tchannel_t   s_channels[MAX_CHANNELS];\nextern\tchannel_t   loop_channels[MAX_CHANNELS];\nextern\tint\t\tnumLoopChannels;\n\nextern\tint\t\ts_paintedtime;\nextern\tint\t\ts_rawend;\nextern\tvec3_t\tlistener_forward;\nextern\tvec3_t\tlistener_right;\nextern\tvec3_t\tlistener_up;\nextern\tdma_t\tdma;\n\n#define\tMAX_RAW_SAMPLES\t16384\nextern\tportable_samplepair_t\ts_rawsamples[MAX_RAW_SAMPLES];\n\nextern cvar_t\t*s_volume;\nextern cvar_t\t*s_nosound;\nextern cvar_t\t*s_khz;\nextern cvar_t\t*s_show;\nextern cvar_t\t*s_mixahead;\n\nextern cvar_t\t*s_testsound;\nextern cvar_t\t*s_separation;\n\nqboolean S_LoadSound( sfx_t *sfx );\n\nvoid\t\tSND_free(sndBuffer *v);\nsndBuffer*\tSND_malloc();\nvoid\t\tSND_setup();\n\nvoid S_PaintChannels(int endtime);\n\nvoid S_memoryLoad(sfx_t *sfx);\nportable_samplepair_t *S_GetRawSamplePointer();\n\n// adpcm functions\nint  S_AdpcmMemoryNeeded( const wavinfo_t *info );\nvoid S_AdpcmEncodeSound( sfx_t *sfx, short *samples );\nvoid S_AdpcmGetSamples(sndBuffer *chunk, short *to);\n\n// wavelet function\n\n#define SENTINEL_MULAW_ZERO_RUN 127\n#define SENTINEL_MULAW_FOUR_BIT_RUN 126\n\nvoid S_FreeOldestSound();\n\n#define\tNXStream byte\n\nvoid encodeWavelet(sfx_t *sfx, short *packets);\nvoid decodeWavelet( sndBuffer *stream, short *packets);\n\nvoid encodeMuLaw( sfx_t *sfx, short *packets);\nextern short mulawToShort[256];\n\nextern short *sfxScratchBuffer;\nextern sfx_t *sfxScratchPointer;\nextern int\t   sfxScratchIndex;\n\n"
  },
  {
    "path": "src/engine/client/snd_mem.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/*****************************************************************************\n * name:\t\tsnd_mem.c\n *\n * desc:\t\tsound caching\n *\n * $Archive: /MissionPack/code/client/snd_mem.c $\n *\n *****************************************************************************/\n\n#include \"snd_local.h\"\n\n#define DEF_COMSOUNDMEGS \"8\"\n\n/*\n===============================================================================\n\nmemory management\n\n===============================================================================\n*/\n\nstatic\tsndBuffer\t*buffer = NULL;\nstatic\tsndBuffer\t*freelist = NULL;\nstatic\tint inUse = 0;\nstatic\tint totalInUse = 0;\n\nshort *sfxScratchBuffer = NULL;\nsfx_t *sfxScratchPointer = NULL;\nint\t   sfxScratchIndex = 0;\n\nvoid\tSND_free(sndBuffer *v) {\n\t*(sndBuffer **)v = freelist;\n\tfreelist = (sndBuffer*)v;\n\tinUse += sizeof(sndBuffer);\n}\n\nsndBuffer*\tSND_malloc() {\n\tsndBuffer *v;\nredo:\n\tif (freelist == NULL) {\n\t\tS_FreeOldestSound();\n\t\tgoto redo;\n\t}\n\n\tinUse -= sizeof(sndBuffer);\n\ttotalInUse += sizeof(sndBuffer);\n\n\tv = freelist;\n\tfreelist = *(sndBuffer **)freelist;\n\tv->next = NULL;\n\treturn v;\n}\n\nvoid SND_setup() {\n\tsndBuffer *p, *q;\n\tcvar_t\t*cv;\n\tint scs;\n\n\tcv = Cvar_Get( \"com_soundMegs\", DEF_COMSOUNDMEGS, CVAR_LATCH | CVAR_ARCHIVE );\n\n\tscs = (cv->integer*1536);\n\n\tbuffer = (sndBuffer*) malloc(scs*sizeof(sndBuffer));\n\t// allocate the stack based hunk allocator\n\tsfxScratchBuffer = (short*) malloc(SND_CHUNK_SIZE * sizeof(short) * 4);\t//Hunk_Alloc(SND_CHUNK_SIZE * sizeof(short) * 4);\n\tsfxScratchPointer = NULL;\n\n\tinUse = scs*sizeof(sndBuffer);\n\tp = buffer;;\n\tq = p + scs;\n\twhile (--q > p)\n\t\t*(sndBuffer **)q = q-1;\n\t\n\t*(sndBuffer **)q = NULL;\n\tfreelist = p + scs - 1;\n\n\tCom_Printf(\"Sound memory manager started\\n\");\n}\n\n/*\n===============================================================================\n\nWAV loading\n\n===============================================================================\n*/\n\nstatic\tbyte\t*data_p;\nstatic\tbyte \t*iff_end;\nstatic\tbyte \t*last_chunk;\nstatic\tbyte \t*iff_data;\nstatic\tint \tiff_chunk_len;\n\nstatic short GetLittleShort(void)\n{\n\tshort val = 0;\n\tval = *data_p;\n\tval = val + (*(data_p+1)<<8);\n\tdata_p += 2;\n\treturn val;\n}\n\nstatic int GetLittleLong(void)\n{\n\tint val = 0;\n\tval = *data_p;\n\tval = val + (*(data_p+1)<<8);\n\tval = val + (*(data_p+2)<<16);\n\tval = val + (*(data_p+3)<<24);\n\tdata_p += 4;\n\treturn val;\n}\n\nstatic void FindNextChunk(char *name)\n{\n\twhile (1)\n\t{\n\t\tdata_p=last_chunk;\n\n\t\tif (data_p >= iff_end)\n\t\t{\t// didn't find the chunk\n\t\t\tdata_p = NULL;\n\t\t\treturn;\n\t\t}\n\t\t\n\t\tdata_p += 4;\n\t\tiff_chunk_len = GetLittleLong();\n\t\tif (iff_chunk_len < 0)\n\t\t{\n\t\t\tdata_p = NULL;\n\t\t\treturn;\n\t\t}\n\t\tdata_p -= 8;\n\t\tlast_chunk = data_p + 8 + ( (iff_chunk_len + 1) & ~1 );\n\t\tif (!strncmp((char *)data_p, name, 4))\n\t\t\treturn;\n\t}\n}\n\nstatic void FindChunk(char *name)\n{\n\tlast_chunk = iff_data;\n\tFindNextChunk (name);\n}\n\n/*\n============\nGetWavinfo\n============\n*/\nstatic wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength)\n{\n\twavinfo_t\tinfo;\n\n\tCom_Memset (&info, 0, sizeof(info));\n\n\tif (!wav)\n\t\treturn info;\n\t\t\n\tiff_data = wav;\n\tiff_end = wav + wavlength;\n\n// find \"RIFF\" chunk\n\tFindChunk(\"RIFF\");\n\tif (!(data_p && !strncmp((char *)data_p+8, \"WAVE\", 4)))\n\t{\n\t\tCom_Printf(\"Missing RIFF/WAVE chunks\\n\");\n\t\treturn info;\n\t}\n\n// get \"fmt \" chunk\n\tiff_data = data_p + 12;\n// DumpChunks ();\n\n\tFindChunk(\"fmt \");\n\tif (!data_p)\n\t{\n\t\tCom_Printf(\"Missing fmt chunk\\n\");\n\t\treturn info;\n\t}\n\tdata_p += 8;\n\tinfo.format = GetLittleShort();\n\tinfo.channels = GetLittleShort();\n\tinfo.rate = GetLittleLong();\n\tdata_p += 4+2;\n\tinfo.width = GetLittleShort() / 8;\n\n\tif (info.format != 1)\n\t{\n\t\tCom_Printf(\"Microsoft PCM format only\\n\");\n\t\treturn info;\n\t}\n\n\n// find data chunk\n\tFindChunk(\"data\");\n\tif (!data_p)\n\t{\n\t\tCom_Printf(\"Missing data chunk\\n\");\n\t\treturn info;\n\t}\n\n\tdata_p += 4;\n\tinfo.samples = GetLittleLong () / info.width;\n\tinfo.dataofs = data_p - wav;\n\n\treturn info;\n}\n\n\n/*\n================\nResampleSfx\n\nresample / decimate to the current source rate\n================\n*/\nstatic void ResampleSfx( sfx_t *sfx, int inrate, int inwidth, byte *data, qboolean compressed ) {\n\tint\t\toutcount;\n\tint\t\tsrcsample;\n\tfloat\tstepscale;\n\tint\t\ti;\n\tint\t\tsample, samplefrac, fracstep;\n\tint\t\t\tpart;\n\tsndBuffer\t*chunk;\n\t\n\tstepscale = (float)inrate / dma.speed;\t// this is usually 0.5, 1, or 2\n\n\toutcount = sfx->soundLength / stepscale;\n\tsfx->soundLength = outcount;\n\n\tsamplefrac = 0;\n\tfracstep = stepscale * 256;\n\tchunk = sfx->soundData;\n\n\tfor (i=0 ; i<outcount ; i++)\n\t{\n\t\tsrcsample = samplefrac >> 8;\n\t\tsamplefrac += fracstep;\n\t\tif( inwidth == 2 ) {\n\t\t\tsample = LittleShort ( ((short *)data)[srcsample] );\n\t\t} else {\n\t\t\tsample = (int)( (unsigned char)(data[srcsample]) - 128) << 8;\n\t\t}\n\t\tpart  = (i&(SND_CHUNK_SIZE-1));\n\t\tif (part == 0) {\n\t\t\tsndBuffer\t*newchunk;\n\t\t\tnewchunk = SND_malloc();\n\t\t\tif (chunk == NULL) {\n\t\t\t\tsfx->soundData = newchunk;\n\t\t\t} else {\n\t\t\t\tchunk->next = newchunk;\n\t\t\t}\n\t\t\tchunk = newchunk;\n\t\t}\n\n\t\tchunk->sndChunk[part] = sample;\n\t}\n}\n\n/*\n================\nResampleSfx\n\nresample / decimate to the current source rate\n================\n*/\nstatic int ResampleSfxRaw( short *sfx, int inrate, int inwidth, int samples, byte *data ) {\n\tint\t\t\toutcount;\n\tint\t\t\tsrcsample;\n\tfloat\t\tstepscale;\n\tint\t\t\ti;\n\tint\t\t\tsample, samplefrac, fracstep;\n\t\n\tstepscale = (float)inrate / dma.speed;\t// this is usually 0.5, 1, or 2\n\n\toutcount = samples / stepscale;\n\n\tsamplefrac = 0;\n\tfracstep = stepscale * 256;\n\n\tfor (i=0 ; i<outcount ; i++)\n\t{\n\t\tsrcsample = samplefrac >> 8;\n\t\tsamplefrac += fracstep;\n\t\tif( inwidth == 2 ) {\n\t\t\tsample = LittleShort ( ((short *)data)[srcsample] );\n\t\t} else {\n\t\t\tsample = (int)( (unsigned char)(data[srcsample]) - 128) << 8;\n\t\t}\n\t\tsfx[i] = sample;\n\t}\n\treturn outcount;\n}\n\n\n//=============================================================================\n\n/*\n==============\nS_LoadSound\n\nThe filename may be different than sfx->name in the case\nof a forced fallback of a player specific sound\n==============\n*/\nqboolean S_LoadSound( sfx_t *sfx )\n{\n\tbyte\t*data;\n\tshort\t*samples;\n\twavinfo_t\tinfo;\n\tint\t\tsize;\n\n\t// player specific sounds are never directly loaded\n\tif ( sfx->soundName[0] == '*') {\n\t\treturn qfalse;\n\t}\n\n\t// load it in\n\tsize = FS_ReadFile( sfx->soundName, (void **)&data );\n\tif ( !data ) {\n\t\treturn qfalse;\n\t}\n\n\tinfo = GetWavinfo( sfx->soundName, data, size );\n\tif ( info.channels != 1 ) {\n\t\tCom_Printf (\"%s is a stereo wav file\\n\", sfx->soundName);\n\t\tFS_FreeFile (data);\n\t\treturn qfalse;\n\t}\n\n\tif ( info.width == 1 ) {\n\t\tCom_DPrintf(S_COLOR_YELLOW \"WARNING: %s is a 8 bit wav file\\n\", sfx->soundName);\n\t}\n\n\tif ( info.rate != 22050 ) {\n\t\tCom_DPrintf(S_COLOR_YELLOW \"WARNING: %s is not a 22kHz wav file\\n\", sfx->soundName);\n\t}\n\n\tsamples = (short*) Hunk_AllocateTempMemory(info.samples * sizeof(short) * 2);\n\n\tsfx->lastTimeUsed = Com_Milliseconds()+1;\n\n\t// each of these compression schemes works just fine\n\t// but the 16bit quality is much nicer and with a local\n\t// install assured we can rely upon the sound memory\n\t// manager to do the right thing for us and page\n\t// sound in as needed\n\n\tif( sfx->soundCompressed == qtrue) {\n\t\tsfx->soundCompressionMethod = 1;\n\t\tsfx->soundData = NULL;\n\t\tsfx->soundLength = ResampleSfxRaw( samples, info.rate, info.width, info.samples, (data + info.dataofs) );\n\t\tS_AdpcmEncodeSound(sfx, samples);\n#if 0\n\t} else if (info.samples>(SND_CHUNK_SIZE*16) && info.width >1) {\n\t\tsfx->soundCompressionMethod = 3;\n\t\tsfx->soundData = NULL;\n\t\tsfx->soundLength = ResampleSfxRaw( samples, info.rate, info.width, info.samples, (data + info.dataofs) );\n\t\tencodeMuLaw( sfx, samples);\n\t} else if (info.samples>(SND_CHUNK_SIZE*6400) && info.width >1) {\n\t\tsfx->soundCompressionMethod = 2;\n\t\tsfx->soundData = NULL;\n\t\tsfx->soundLength = ResampleSfxRaw( samples, info.rate, info.width, info.samples, (data + info.dataofs) );\n\t\tencodeWavelet( sfx, samples);\n#endif\n\t} else {\n\t\tsfx->soundCompressionMethod = 0;\n\t\tsfx->soundLength = info.samples;\n\t\tsfx->soundData = NULL;\n\t\tResampleSfx( sfx, info.rate, info.width, data + info.dataofs, qfalse );\n\t}\n\t\n\tHunk_FreeTempMemory(samples);\n\tFS_FreeFile( data );\n\n\treturn qtrue;\n}\n\nvoid S_DisplayFreeMemory() {\n\tCom_Printf(\"%d bytes free sound buffer memory, %d total used\\n\", inUse, totalInUse);\n}\n"
  },
  {
    "path": "src/engine/client/snd_mix.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n// snd_mix.c -- portable code to mix sounds for snd_dma.c\n\n#include \"snd_local.h\"\n\nstatic portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE];\nstatic int snd_vol;\n\n// bk001119 - these not static, required by unix/snd_mixa.s\nint*     snd_p;  \nint      snd_linear_count;\nshort*   snd_out;\n\n#if !( (defined __linux__ || defined __FreeBSD__ ) && (defined __i386__) ) // rb010123\n#if\t!id386\n\nvoid S_WriteLinearBlastStereo16 (void)\n{\n\tint\t\ti;\n\tint\t\tval;\n\n\tfor (i=0 ; i<snd_linear_count ; i+=2)\n\t{\n\t\tval = snd_p[i]>>8;\n\t\tif (val > 0x7fff)\n\t\t\tsnd_out[i] = 0x7fff;\n\t\telse if (val < -32768)\n\t\t\tsnd_out[i] = -32768;\n\t\telse\n\t\t\tsnd_out[i] = val;\n\n\t\tval = snd_p[i+1]>>8;\n\t\tif (val > 0x7fff)\n\t\t\tsnd_out[i+1] = 0x7fff;\n\t\telse if (val < -32768)\n\t\t\tsnd_out[i+1] = -32768;\n\t\telse\n\t\t\tsnd_out[i+1] = val;\n\t}\n}\n#else\n\n__declspec( naked ) void S_WriteLinearBlastStereo16 (void)\n{\n\t__asm {\n\n push edi\n push ebx\n mov ecx,ds:dword ptr[snd_linear_count]\n mov ebx,ds:dword ptr[snd_p]\n mov edi,ds:dword ptr[snd_out]\nLWLBLoopTop:\n mov eax,ds:dword ptr[-8+ebx+ecx*4]\n sar eax,8\n cmp eax,07FFFh\n jg LClampHigh\n cmp eax,0FFFF8000h\n jnl LClampDone\n mov eax,0FFFF8000h\n jmp LClampDone\nLClampHigh:\n mov eax,07FFFh\nLClampDone:\n mov edx,ds:dword ptr[-4+ebx+ecx*4]\n sar edx,8\n cmp edx,07FFFh\n jg LClampHigh2\n cmp edx,0FFFF8000h\n jnl LClampDone2\n mov edx,0FFFF8000h\n jmp LClampDone2\nLClampHigh2:\n mov edx,07FFFh\nLClampDone2:\n shl edx,16\n and eax,0FFFFh\n or edx,eax\n mov ds:dword ptr[-4+edi+ecx*2],edx\n sub ecx,2\n jnz LWLBLoopTop\n pop ebx\n pop edi\n ret\n\t}\n}\n\n#endif\n#else\n// forward declare, implementation somewhere else\nvoid S_WriteLinearBlastStereo16 (void);\n#endif\n\nvoid S_TransferStereo16 (unsigned long *pbuf, int endtime)\n{\n\tint\t\tlpos;\n\tint\t\tls_paintedtime;\n\t\n\tsnd_p = (int *) paintbuffer;\n\tls_paintedtime = s_paintedtime;\n\n\twhile (ls_paintedtime < endtime)\n\t{\n\t// handle recirculating buffer issues\n\t\tlpos = ls_paintedtime & ((dma.samples>>1)-1);\n\n\t\tsnd_out = (short *) pbuf + (lpos<<1);\n\n\t\tsnd_linear_count = (dma.samples>>1) - lpos;\n\t\tif (ls_paintedtime + snd_linear_count > endtime)\n\t\t\tsnd_linear_count = endtime - ls_paintedtime;\n\n\t\tsnd_linear_count <<= 1;\n\n\t// write a linear blast of samples\n\t\tS_WriteLinearBlastStereo16 ();\n\n\t\tsnd_p += snd_linear_count;\n\t\tls_paintedtime += (snd_linear_count>>1);\n\t}\n}\n\n/*\n===================\nS_TransferPaintBuffer\n\n===================\n*/\nvoid S_TransferPaintBuffer(int endtime)\n{\n\tint \tout_idx;\n\tint \tcount;\n\tint \tout_mask;\n\tint \t*p;\n\tint \tstep;\n\tint\t\tval;\n\tunsigned long *pbuf;\n\n\tpbuf = (unsigned long *)dma.buffer;\n\n\n\tif ( s_testsound->integer ) {\n\t\tint\t\ti;\n\t\tint\t\tcount;\n\n\t\t// write a fixed sine wave\n\t\tcount = (endtime - s_paintedtime);\n\t\tfor (i=0 ; i<count ; i++)\n\t\t\tpaintbuffer[i].left = paintbuffer[i].right = sin((s_paintedtime+i)*0.1)*20000*256;\n\t}\n\n\n\tif (dma.samplebits == 16 && dma.channels == 2)\n\t{\t// optimized case\n\t\tS_TransferStereo16 (pbuf, endtime);\n\t}\n\telse\n\t{\t// general case\n\t\tp = (int *) paintbuffer;\n\t\tcount = (endtime - s_paintedtime) * dma.channels;\n\t\tout_mask = dma.samples - 1; \n\t\tout_idx = s_paintedtime * dma.channels & out_mask;\n\t\tstep = 3 - dma.channels;\n\n\t\tif (dma.samplebits == 16)\n\t\t{\n\t\t\tshort *out = (short *) pbuf;\n\t\t\twhile (count--)\n\t\t\t{\n\t\t\t\tval = *p >> 8;\n\t\t\t\tp+= step;\n\t\t\t\tif (val > 0x7fff)\n\t\t\t\t\tval = 0x7fff;\n\t\t\t\telse if (val < -32768)\n\t\t\t\t\tval = -32768;\n\t\t\t\tout[out_idx] = val;\n\t\t\t\tout_idx = (out_idx + 1) & out_mask;\n\t\t\t}\n\t\t}\n\t\telse if (dma.samplebits == 8)\n\t\t{\n\t\t\tunsigned char *out = (unsigned char *) pbuf;\n\t\t\twhile (count--)\n\t\t\t{\n\t\t\t\tval = *p >> 8;\n\t\t\t\tp+= step;\n\t\t\t\tif (val > 0x7fff)\n\t\t\t\t\tval = 0x7fff;\n\t\t\t\telse if (val < -32768)\n\t\t\t\t\tval = -32768;\n\t\t\t\tout[out_idx] = (val>>8) + 128;\n\t\t\t\tout_idx = (out_idx + 1) & out_mask;\n\t\t\t}\n\t\t}\n\t}\n}\n\n\n/*\n===============================================================================\n\nCHANNEL MIXING\n\n===============================================================================\n*/\n\nstatic void S_PaintChannelFrom16( channel_t *ch, const sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {\n\tint\t\t\t\t\t\tdata, aoff, boff;\n\tint\t\t\t\t\t\tleftvol, rightvol;\n\tint\t\t\t\t\t\ti, j;\n\tportable_samplepair_t\t*samp;\n\tsndBuffer\t\t\t\t*chunk;\n\tshort\t\t\t\t\t*samples;\n\tfloat\t\t\t\t\tooff, fdata, fdiv, fleftvol, frightvol;\n\n\tsamp = &paintbuffer[ bufferOffset ];\n\n\tif (ch->doppler) {\n\t\tsampleOffset = sampleOffset*ch->oldDopplerScale;\n\t}\n\n\tchunk = sc->soundData;\n\twhile (sampleOffset>=SND_CHUNK_SIZE) {\n\t\tchunk = chunk->next;\n\t\tsampleOffset -= SND_CHUNK_SIZE;\n\t\tif (!chunk) {\n\t\t\tchunk = sc->soundData;\n\t\t}\n\t}\n\n\tif (!ch->doppler || ch->dopplerScale==1.0f) {\n#if idppc_altivec\n\t\tvector signed short volume_vec;\n\t\tvector unsigned int volume_shift;\n\t\tint vectorCount, samplesLeft, chunkSamplesLeft;\n#endif\n\t\tleftvol = ch->leftvol*snd_vol;\n\t\trightvol = ch->rightvol*snd_vol;\n\t\tsamples = chunk->sndChunk;\n#if idppc_altivec\n\t\t((short *)&volume_vec)[0] = leftvol;\n\t\t((short *)&volume_vec)[1] = leftvol;\n\t\t((short *)&volume_vec)[4] = leftvol;\n\t\t((short *)&volume_vec)[5] = leftvol;\n\t\t((short *)&volume_vec)[2] = rightvol;\n\t\t((short *)&volume_vec)[3] = rightvol;\n\t\t((short *)&volume_vec)[6] = rightvol;\n\t\t((short *)&volume_vec)[7] = rightvol;\n\t\tvolume_shift = vec_splat_u32(8);\n\t\ti = 0;\n\n\t\twhile(i < count) {\n\t\t\t/* Try to align destination to 16-byte boundary */\n\t\t\twhile(i < count && (((unsigned long)&samp[i] & 0x1f) || ((count-i) < 8) || ((SND_CHUNK_SIZE - sampleOffset) < 8))) {\n\t\t\t\tdata  = samples[sampleOffset++];\n\t\t\t\tsamp[i].left += (data * leftvol)>>8;\n\t\t\t\tsamp[i].right += (data * rightvol)>>8;\n\t\n\t\t\t\tif (sampleOffset == SND_CHUNK_SIZE) {\n\t\t\t\t\tchunk = chunk->next;\n\t\t\t\t\tsamples = chunk->sndChunk;\n\t\t\t\t\tsampleOffset = 0;\n\t\t\t\t}\n\t\t\t\ti++;\n\t\t\t}\n\t\t\t/* Destination is now aligned.  Process as many 8-sample \n\t\t\t   chunks as we can before we run out of room from the current\n\t\t\t   sound chunk.  We do 8 per loop to avoid extra source data reads. */\n\t\t\tsamplesLeft = count - i;\n\t\t\tchunkSamplesLeft = SND_CHUNK_SIZE - sampleOffset;\n\t\t\tif(samplesLeft > chunkSamplesLeft)\n\t\t\t\tsamplesLeft = chunkSamplesLeft;\n\t\t\t\n\t\t\tvectorCount = samplesLeft / 8;\n\t\t\t\n\t\t\tif(vectorCount)\n\t\t\t{\n\t\t\t\tvector unsigned char tmp;\n\t\t\t\tvector short s0, s1, sampleData0, sampleData1;\n\t\t\t\tvector short samples0, samples1;\n\t\t\t\tvector signed int left0, right0;\n\t\t\t\tvector signed int merge0, merge1;\n\t\t\t\tvector signed int d0, d1, d2, d3;\t\t\t\t\n\t\t\t\tvector unsigned char samplePermute0 = \n\t\t\t\t\t(vector unsigned char)(0, 1, 4, 5, 0, 1, 4, 5, 2, 3, 6, 7, 2, 3, 6, 7);\n\t\t\t\tvector unsigned char samplePermute1 = \n\t\t\t\t\t(vector unsigned char)(8, 9, 12, 13, 8, 9, 12, 13, 10, 11, 14, 15, 10, 11, 14, 15);\n\t\t\t\tvector unsigned char loadPermute0, loadPermute1;\n\t\t\t\t\n\t\t\t\t// Rather than permute the vectors after we load them to do the sample\n\t\t\t\t// replication and rearrangement, we permute the alignment vector so\n\t\t\t\t// we do everything in one step below and avoid data shuffling.\n\t\t\t\ttmp = vec_lvsl(0,&samples[sampleOffset]);\t\t\t\t\t\t\t\t\n\t\t\t\tloadPermute0 = vec_perm(tmp,tmp,samplePermute0);\n\t\t\t\tloadPermute1 = vec_perm(tmp,tmp,samplePermute1);\n\t\t\t\t\n\t\t\t\ts0 = *(vector short *)&samples[sampleOffset];\n\t\t\t\twhile(vectorCount)\n\t\t\t\t{\n\t\t\t\t\t/* Load up source (16-bit) sample data */\n\t\t\t\t\ts1 = *(vector short *)&samples[sampleOffset+7];\n\t\t\t\t\t\n\t\t\t\t\t/* Load up destination sample data */\n\t\t\t\t\td0 = *(vector signed int *)&samp[i];\n\t\t\t\t\td1 = *(vector signed int *)&samp[i+2];\n\t\t\t\t\td2 = *(vector signed int *)&samp[i+4];\n\t\t\t\t\td3 = *(vector signed int *)&samp[i+6];\n\n\t\t\t\t\tsampleData0 = vec_perm(s0,s1,loadPermute0);\n\t\t\t\t\tsampleData1 = vec_perm(s0,s1,loadPermute1);\n\t\t\t\t\t\n\t\t\t\t\tmerge0 = vec_mule(sampleData0,volume_vec);\n\t\t\t\t\tmerge0 = vec_sra(merge0,volume_shift);\t/* Shift down to proper range */\n\t\t\t\t\t\n\t\t\t\t\tmerge1 = vec_mulo(sampleData0,volume_vec);\n\t\t\t\t\tmerge1 = vec_sra(merge1,volume_shift);\n\t\t\t\t\t\n\t\t\t\t\td0 = vec_add(merge0,d0);\n\t\t\t\t\td1 = vec_add(merge1,d1);\n\t\t\t\t\t\n\t\t\t\t\tmerge0 = vec_mule(sampleData1,volume_vec);\n\t\t\t\t\tmerge0 = vec_sra(merge0,volume_shift);\t/* Shift down to proper range */\n\t\t\t\t\t\n\t\t\t\t\tmerge1 = vec_mulo(sampleData1,volume_vec);\n\t\t\t\t\tmerge1 = vec_sra(merge1,volume_shift);\t\t\t\t\t\n\n\t\t\t\t\td2 = vec_add(merge0,d2);\n\t\t\t\t\td3 = vec_add(merge1,d3);\n\n\t\t\t\t\t/* Store destination sample data */\n\t\t\t\t\t*(vector signed int *)&samp[i] = d0;\n\t\t\t\t\t*(vector signed int *)&samp[i+2] = d1;\n\t\t\t\t\t*(vector signed int *)&samp[i+4] = d2;\n\t\t\t\t\t*(vector signed int *)&samp[i+6] = d3;\n\n\t\t\t\t\ti += 8;\n\t\t\t\t\tvectorCount--;\n\t\t\t\t\ts0 = s1;\n\t\t\t\t\tsampleOffset += 8;\n\t\t\t\t}\n\t\t\t\tif (sampleOffset == SND_CHUNK_SIZE) {\n\t\t\t\t\tchunk = chunk->next;\n\t\t\t\t\tsamples = chunk->sndChunk;\n\t\t\t\t\tsampleOffset = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n#else\t\t\t\n\t\tfor ( i=0 ; i<count ; i++ ) {\n\t\t\tdata  = samples[sampleOffset++];\n\t\t\tsamp[i].left += (data * leftvol)>>8;\n\t\t\tsamp[i].right += (data * rightvol)>>8;\n\n\t\t\tif (sampleOffset == SND_CHUNK_SIZE) {\n\t\t\t\tchunk = chunk->next;\n\t\t\t\tsamples = chunk->sndChunk;\n\t\t\t\tsampleOffset = 0;\n\t\t\t}\n\t\t}\n#endif\n\t} else {\n\t\tfleftvol = ch->leftvol*snd_vol;\n\t\tfrightvol = ch->rightvol*snd_vol;\n\n\t\tooff = sampleOffset;\n\t\tsamples = chunk->sndChunk;\n\t\t\n\n\n\n\t\tfor ( i=0 ; i<count ; i++ ) {\n\n\t\t\taoff = ooff;\n\t\t\tooff = ooff + ch->dopplerScale;\n\t\t\tboff = ooff;\n\t\t\tfdata = 0;\n\t\t\tfor (j=aoff; j<boff; j++) {\n\t\t\t\tif (j == SND_CHUNK_SIZE) {\n\t\t\t\t\tchunk = chunk->next;\n\t\t\t\t\tif (!chunk) {\n\t\t\t\t\t\tchunk = sc->soundData;\n\t\t\t\t\t}\n\t\t\t\t\tsamples = chunk->sndChunk;\n\t\t\t\t\tooff -= SND_CHUNK_SIZE;\n\t\t\t\t}\n\t\t\t\tfdata  += samples[j&(SND_CHUNK_SIZE-1)];\n\t\t\t}\n\t\t\tfdiv = 256 * (boff-aoff);\n\t\t\tsamp[i].left += (fdata * fleftvol)/fdiv;\n\t\t\tsamp[i].right += (fdata * frightvol)/fdiv;\n\t\t}\n\t}\n}\n\nvoid S_PaintChannelFromWavelet( channel_t *ch, sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {\n\tint\t\t\t\t\t\tdata;\n\tint\t\t\t\t\t\tleftvol, rightvol;\n\tint\t\t\t\t\t\ti;\n\tportable_samplepair_t\t*samp;\n\tsndBuffer\t\t\t\t*chunk;\n\tshort\t\t\t\t\t*samples;\n\n\tleftvol = ch->leftvol*snd_vol;\n\trightvol = ch->rightvol*snd_vol;\n\n\ti = 0;\n\tsamp = &paintbuffer[ bufferOffset ];\n\tchunk = sc->soundData;\n\twhile (sampleOffset>=(SND_CHUNK_SIZE_FLOAT*4)) {\n\t\tchunk = chunk->next;\n\t\tsampleOffset -= (SND_CHUNK_SIZE_FLOAT*4);\n\t\ti++;\n\t}\n\n\tif (i!=sfxScratchIndex || sfxScratchPointer != sc) {\n\t\tS_AdpcmGetSamples( chunk, sfxScratchBuffer );\n\t\tsfxScratchIndex = i;\n\t\tsfxScratchPointer = sc;\n\t}\n\n\tsamples = sfxScratchBuffer;\n\n\tfor ( i=0 ; i<count ; i++ ) {\n\t\tdata  = samples[sampleOffset++];\n\t\tsamp[i].left += (data * leftvol)>>8;\n\t\tsamp[i].right += (data * rightvol)>>8;\n\n\t\tif (sampleOffset == SND_CHUNK_SIZE*2) {\n\t\t\tchunk = chunk->next;\n\t\t\tdecodeWavelet(chunk, sfxScratchBuffer);\n\t\t\tsfxScratchIndex++;\n\t\t\tsampleOffset = 0;\n\t\t}\n\t}\n}\n\nvoid S_PaintChannelFromADPCM( channel_t *ch, sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {\n\tint\t\t\t\t\t\tdata;\n\tint\t\t\t\t\t\tleftvol, rightvol;\n\tint\t\t\t\t\t\ti;\n\tportable_samplepair_t\t*samp;\n\tsndBuffer\t\t\t\t*chunk;\n\tshort\t\t\t\t\t*samples;\n\n\tleftvol = ch->leftvol*snd_vol;\n\trightvol = ch->rightvol*snd_vol;\n\n\ti = 0;\n\tsamp = &paintbuffer[ bufferOffset ];\n\tchunk = sc->soundData;\n\n\tif (ch->doppler) {\n\t\tsampleOffset = sampleOffset*ch->oldDopplerScale;\n\t}\n\n\twhile (sampleOffset>=(SND_CHUNK_SIZE*4)) {\n\t\tchunk = chunk->next;\n\t\tsampleOffset -= (SND_CHUNK_SIZE*4);\n\t\ti++;\n\t}\n\n\tif (i!=sfxScratchIndex || sfxScratchPointer != sc) {\n\t\tS_AdpcmGetSamples( chunk, sfxScratchBuffer );\n\t\tsfxScratchIndex = i;\n\t\tsfxScratchPointer = sc;\n\t}\n\n\tsamples = sfxScratchBuffer;\n\n\tfor ( i=0 ; i<count ; i++ ) {\n\t\tdata  = samples[sampleOffset++];\n\t\tsamp[i].left += (data * leftvol)>>8;\n\t\tsamp[i].right += (data * rightvol)>>8;\n\n\t\tif (sampleOffset == SND_CHUNK_SIZE*4) {\n\t\t\tchunk = chunk->next;\n\t\t\tS_AdpcmGetSamples( chunk, sfxScratchBuffer);\n\t\t\tsampleOffset = 0;\n\t\t\tsfxScratchIndex++;\n\t\t}\n\t}\n}\n\nvoid S_PaintChannelFromMuLaw( channel_t *ch, sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {\n\tint\t\t\t\t\t\tdata;\n\tint\t\t\t\t\t\tleftvol, rightvol;\n\tint\t\t\t\t\t\ti;\n\tportable_samplepair_t\t*samp;\n\tsndBuffer\t\t\t\t*chunk;\n\tbyte\t\t\t\t\t*samples;\n\tfloat\t\t\t\t\tooff;\n\n\tleftvol = ch->leftvol*snd_vol;\n\trightvol = ch->rightvol*snd_vol;\n\n\tsamp = &paintbuffer[ bufferOffset ];\n\tchunk = sc->soundData;\n\twhile (sampleOffset>=(SND_CHUNK_SIZE*2)) {\n\t\tchunk = chunk->next;\n\t\tsampleOffset -= (SND_CHUNK_SIZE*2);\n\t\tif (!chunk) {\n\t\t\tchunk = sc->soundData;\n\t\t}\n\t}\n\n\tif (!ch->doppler) {\n\t\tsamples = (byte *)chunk->sndChunk + sampleOffset;\n\t\tfor ( i=0 ; i<count ; i++ ) {\n\t\t\tdata  = mulawToShort[*samples];\n\t\t\tsamp[i].left += (data * leftvol)>>8;\n\t\t\tsamp[i].right += (data * rightvol)>>8;\n\t\t\tsamples++;\n\t\t\tif (samples == (byte *)chunk->sndChunk+(SND_CHUNK_SIZE*2)) {\n\t\t\t\tchunk = chunk->next;\n\t\t\t\tsamples = (byte *)chunk->sndChunk;\n\t\t\t}\n\t\t}\n\t} else {\n\t\tooff = sampleOffset;\n\t\tsamples = (byte *)chunk->sndChunk;\n\t\tfor ( i=0 ; i<count ; i++ ) {\n\t\t\tdata  = mulawToShort[samples[(int)(ooff)]];\n\t\t\tooff = ooff + ch->dopplerScale;\n\t\t\tsamp[i].left += (data * leftvol)>>8;\n\t\t\tsamp[i].right += (data * rightvol)>>8;\n\t\t\tif (ooff >= SND_CHUNK_SIZE*2) {\n\t\t\t\tchunk = chunk->next;\n\t\t\t\tif (!chunk) {\n\t\t\t\t\tchunk = sc->soundData;\n\t\t\t\t}\n\t\t\t\tsamples = (byte *)chunk->sndChunk;\n\t\t\t\tooff = 0.0;\n\t\t\t}\n\t\t}\n\t}\n}\n\n/*\n===================\nS_PaintChannels\n===================\n*/\nvoid S_PaintChannels( int endtime ) {\n\tint \ti;\n\tint \tend;\n\tchannel_t *ch;\n\tsfx_t\t*sc;\n\tint\t\tltime, count;\n\tint\t\tsampleOffset;\n\n\n\tsnd_vol = s_volume->value*255;\n\n//Com_Printf (\"%i to %i\\n\", s_paintedtime, endtime);\n\twhile ( s_paintedtime < endtime ) {\n\t\t// if paintbuffer is smaller than DMA buffer\n\t\t// we may need to fill it multiple times\n\t\tend = endtime;\n\t\tif ( endtime - s_paintedtime > PAINTBUFFER_SIZE ) {\n\t\t\tend = s_paintedtime + PAINTBUFFER_SIZE;\n\t\t}\n\n\t\t// clear the paint buffer to either music or zeros\n\t\tif ( s_rawend < s_paintedtime ) {\n\t\t\tif ( s_rawend ) {\n\t\t\t\t//Com_DPrintf (\"background sound underrun\\n\");\n\t\t\t}\n\t\t\tCom_Memset(paintbuffer, 0, (end - s_paintedtime) * sizeof(portable_samplepair_t));\n\t\t} else {\n\t\t\t// copy from the streaming sound source\n\t\t\tint\t\ts;\n\t\t\tint\t\tstop;\n\n\t\t\tstop = (end < s_rawend) ? end : s_rawend;\n\n\t\t\tfor ( i = s_paintedtime ; i < stop ; i++ ) {\n\t\t\t\ts = i&(MAX_RAW_SAMPLES-1);\n\t\t\t\tpaintbuffer[i-s_paintedtime] = s_rawsamples[s];\n\t\t\t}\n//\t\tif (i != end)\n//\t\t\tCom_Printf (\"partial stream\\n\");\n//\t\telse\n//\t\t\tCom_Printf (\"full stream\\n\");\n\t\t\tfor ( ; i < end ; i++ ) {\n\t\t\t\tpaintbuffer[i-s_paintedtime].left =\n\t\t\t\tpaintbuffer[i-s_paintedtime].right = 0;\n\t\t\t}\n\t\t}\n\n\t\t// paint in the channels.\n\t\tch = s_channels;\n\t\tfor ( i = 0; i < MAX_CHANNELS ; i++, ch++ ) {\t\t\n\t\t\tif ( !ch->thesfx || (ch->leftvol<0.25 && ch->rightvol<0.25 )) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tltime = s_paintedtime;\n\t\t\tsc = ch->thesfx;\n\n\t\t\tsampleOffset = ltime - ch->startSample;\n\t\t\tcount = end - ltime;\n\t\t\tif ( sampleOffset + count > sc->soundLength ) {\n\t\t\t\tcount = sc->soundLength - sampleOffset;\n\t\t\t}\n\n\t\t\tif ( count > 0 ) {\t\n\t\t\t\tif( sc->soundCompressionMethod == 1) {\n\t\t\t\t\tS_PaintChannelFromADPCM\t\t(ch, sc, count, sampleOffset, ltime - s_paintedtime);\n\t\t\t\t} else if( sc->soundCompressionMethod == 2) {\n\t\t\t\t\tS_PaintChannelFromWavelet\t(ch, sc, count, sampleOffset, ltime - s_paintedtime);\n\t\t\t\t} else if( sc->soundCompressionMethod == 3) {\n\t\t\t\t\tS_PaintChannelFromMuLaw\t(ch, sc, count, sampleOffset, ltime - s_paintedtime);\n\t\t\t\t} else {\n\t\t\t\t\tS_PaintChannelFrom16\t\t(ch, sc, count, sampleOffset, ltime - s_paintedtime);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// paint in the looped channels.\n\t\tch = loop_channels;\n\t\tfor ( i = 0; i < numLoopChannels ; i++, ch++ ) {\t\t\n\t\t\tif ( !ch->thesfx || (!ch->leftvol && !ch->rightvol )) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tltime = s_paintedtime;\n\t\t\tsc = ch->thesfx;\n\n\t\t\tif (sc->soundData==NULL || sc->soundLength==0) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// we might have to make two passes if it\n\t\t\t// is a looping sound effect and the end of\n\t\t\t// the sample is hit\n\t\t\tdo {\n\t\t\t\tsampleOffset = (ltime % sc->soundLength);\n\n\t\t\t\tcount = end - ltime;\n\t\t\t\tif ( sampleOffset + count > sc->soundLength ) {\n\t\t\t\t\tcount = sc->soundLength - sampleOffset;\n\t\t\t\t}\n\n\t\t\t\tif ( count > 0 ) {\t\n\t\t\t\t\tif( sc->soundCompressionMethod == 1) {\n\t\t\t\t\t\tS_PaintChannelFromADPCM\t\t(ch, sc, count, sampleOffset, ltime - s_paintedtime);\n\t\t\t\t\t} else if( sc->soundCompressionMethod == 2) {\n\t\t\t\t\t\tS_PaintChannelFromWavelet\t(ch, sc, count, sampleOffset, ltime - s_paintedtime);\n\t\t\t\t\t} else if( sc->soundCompressionMethod == 3) {\n\t\t\t\t\t\tS_PaintChannelFromMuLaw\t\t(ch, sc, count, sampleOffset, ltime - s_paintedtime);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tS_PaintChannelFrom16\t\t(ch, sc, count, sampleOffset, ltime - s_paintedtime);\n\t\t\t\t\t}\n\t\t\t\t\tltime += count;\n\t\t\t\t}\n\t\t\t} while ( ltime < end);\n\t\t}\n\n\t\t// transfer out according to DMA format\n\t\tS_TransferPaintBuffer( end );\n\t\ts_paintedtime = end;\n\t}\n}\n"
  },
  {
    "path": "src/engine/client/snd_public.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n\nvoid S_Init( void );\nvoid S_Shutdown( void );\n\n// if origin is NULL, the sound will be dynamically sourced from the entity\nvoid S_StartSound( vec3_t origin, int entnum, int entchannel, sfxHandle_t sfx );\nvoid S_StartLocalSound( sfxHandle_t sfx, int channelNum );\n\nvoid S_StartBackgroundTrack( const char *intro, const char *loop );\nvoid S_StopBackgroundTrack( void );\n\n// cinematics and voice-over-network will send raw samples\n// 1.0 volume will be direct output of source samples\nvoid S_RawSamples (int samples, int rate, int width, int channels, \n\t\t\t\t   const byte *data, float volume);\n\n// stop all sounds and the background track\nvoid S_StopAllSounds( void );\n\n// all continuous looping sounds must be added before calling S_Update\nvoid S_ClearLoopingSounds( qboolean killall );\nvoid S_AddLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx );\nvoid S_AddRealLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx );\nvoid S_StopLoopingSound(int entityNum );\n\n// recompute the reletive volumes for all running sounds\n// reletive to the given entityNum / orientation\nvoid S_Respatialize( int entityNum, const vec3_t origin, vec3_t axis[3], int inwater );\n\n// let the sound system know where an entity currently is\nvoid S_UpdateEntityPosition( int entityNum, const vec3_t origin );\n\nvoid S_Update( void );\n\nvoid S_DisableSounds( void );\n\nvoid S_BeginRegistration( void );\n\n// RegisterSound will allways return a valid sample, even if it\n// has to create a placeholder.  This prevents continuous filesystem\n// checks for missing files\nsfxHandle_t\tS_RegisterSound( const char *sample, qboolean compressed );\n\nvoid S_DisplayFreeMemory(void);\n\nvoid S_ClearSoundBuffer( void );\n\nvoid SNDDMA_Activate( void );\n\nvoid S_UpdateBackgroundTrack( void );\n"
  },
  {
    "path": "src/engine/client/snd_wavelet.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n#include \"snd_local.h\"\n\nlong myftol( float f );\n\n#define C0 0.4829629131445341\n#define C1 0.8365163037378079\n#define C2 0.2241438680420134\n#define C3 -0.1294095225512604\n\nvoid daub4(float b[], unsigned long n, int isign)\n{\n\tfloat wksp[4097];\n\tfloat\t*a=b-1;\t\t\t\t\t\t// numerical recipies so a[1] = b[0]\n\n\tunsigned long nh,nh1,i,j;\n\n\tif (n < 4) return;\n\n\tnh1=(nh=n >> 1)+1;\n\tif (isign >= 0) {\n\t\tfor (i=1,j=1;j<=n-3;j+=2,i++) {\n\t\t\twksp[i]\t   = C0*a[j]+C1*a[j+1]+C2*a[j+2]+C3*a[j+3];\n\t\t\twksp[i+nh] = C3*a[j]-C2*a[j+1]+C1*a[j+2]-C0*a[j+3];\n\t\t}\n\t\twksp[i   ] = C0*a[n-1]+C1*a[n]+C2*a[1]+C3*a[2];\n\t\twksp[i+nh] = C3*a[n-1]-C2*a[n]+C1*a[1]-C0*a[2];\n\t} else {\n\t\twksp[1] = C2*a[nh]+C1*a[n]+C0*a[1]+C3*a[nh1];\n\t\twksp[2] = C3*a[nh]-C0*a[n]+C1*a[1]-C2*a[nh1];\n\t\tfor (i=1,j=3;i<nh;i++) {\n\t\t\twksp[j++] = C2*a[i]+C1*a[i+nh]+C0*a[i+1]+C3*a[i+nh1];\n\t\t\twksp[j++] = C3*a[i]-C0*a[i+nh]+C1*a[i+1]-C2*a[i+nh1];\n\t\t}\n\t}\n\tfor (i=1;i<=n;i++) {\n\t\ta[i]=wksp[i];\n\t}\n}\n\nvoid wt1(float a[], unsigned long n, int isign)\n{\n\tunsigned long nn;\n\tint inverseStartLength = n/4;\n\tif (n < inverseStartLength) return;\n\tif (isign >= 0) {\n\t\tfor (nn=n;nn>=inverseStartLength;nn>>=1) daub4(a,nn,isign);\n\t} else {\n\t\tfor (nn=inverseStartLength;nn<=n;nn<<=1) daub4(a,nn,isign);\n\t}\n}\n\n/* The number of bits required by each value */\nstatic unsigned char numBits[] = {\n   0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,\n   6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,\n   7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,\n   7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,\n   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,\n   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,\n   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,\n   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,\n};\n\nbyte MuLawEncode(short s) {\n\tunsigned long adjusted;\n\tbyte sign, exponent, mantissa;\n\n\tsign = (s<0)?0:0x80;\n\n\tif (s<0) s=-s;\n\tadjusted = (long)s << (16-sizeof(short)*8);\n\tadjusted += 128L + 4L;\n\tif (adjusted > 32767) adjusted = 32767;\n\texponent = numBits[(adjusted>>7)&0xff] - 1;\n\tmantissa = (adjusted>>(exponent+3))&0xf;\n\treturn ~(sign | (exponent<<4) | mantissa);\n}\n\nshort MuLawDecode(byte uLaw) {\n\tsigned long adjusted;\n\tbyte exponent, mantissa;\n\n\tuLaw = ~uLaw;\n\texponent = (uLaw>>4) & 0x7;\n\tmantissa = (uLaw&0xf) + 16;\n\tadjusted = (mantissa << (exponent +3)) - 128 - 4;\n\n\treturn (uLaw & 0x80)? adjusted : -adjusted;\n}\n\nshort mulawToShort[256];\nstatic qboolean madeTable = qfalse;\n\nstatic\tint\tNXStreamCount;\n\nvoid NXPutc(NXStream *stream, char out) {\n\tstream[NXStreamCount++] = out;\n}\n\n\nvoid encodeWavelet( sfx_t *sfx, short *packets) {\n\tfloat\twksp[4097], temp;\n\tint\t\ti, samples, size;\n\tsndBuffer\t\t*newchunk, *chunk;\n\tbyte\t\t\t*out;\n\n\tif (!madeTable) {\n\t\tfor (i=0;i<256;i++) {\n\t\t\tmulawToShort[i] = (float)MuLawDecode((byte)i);\n\t\t}\n\t\tmadeTable = qtrue;\n\t}\n\tchunk = NULL;\n\n\tsamples = sfx->soundLength;\n\twhile(samples>0) {\n\t\tsize = samples;\n\t\tif (size>(SND_CHUNK_SIZE*2)) {\n\t\t\tsize = (SND_CHUNK_SIZE*2);\n\t\t}\n\n\t\tif (size<4) {\n\t\t\tsize = 4;\n\t\t}\n\n\t\tnewchunk = SND_malloc();\n\t\tif (sfx->soundData == NULL) {\n\t\t\tsfx->soundData = newchunk;\n\t\t} else {\n\t\t\tchunk->next = newchunk;\n\t\t}\n\t\tchunk = newchunk;\n\t\tfor(i=0; i<size; i++) {\n\t\t\twksp[i] = *packets;\n\t\t\tpackets++;\n\t\t}\n\t\twt1(wksp, size, 1);\n\t\tout = (byte *)chunk->sndChunk;\n\n\t\tfor(i=0;i<size;i++) {\n\t\t\ttemp = wksp[i];\n\t\t\tif (temp > 32767) temp = 32767; else if (temp<-32768) temp = -32768;\n\t\t\tout[i] = MuLawEncode((short)temp);\n\t\t}\n\n\t\tchunk->size = size;\n\t\tsamples -= size;\n\t}\n}\n\nvoid decodeWavelet(sndBuffer *chunk, short *to) {\n\tfloat\t\t\twksp[4097];\n\tint\t\t\t\ti;\n\tbyte\t\t\t*out;\n\n\tint size = chunk->size;\n\t\n\tout = (byte *)chunk->sndChunk;\n\tfor(i=0;i<size;i++) {\n\t\twksp[i] = mulawToShort[out[i]];\n\t}\n\n\twt1(wksp, size, -1);\n\t\n\tif (!to) return;\n\n\tfor(i=0; i<size; i++) {\n\t\tto[i] = wksp[i];\n\t}\n}\n\n\nvoid encodeMuLaw( sfx_t *sfx, short *packets) {\n\tint\t\ti, samples, size, grade, poop;\n\tsndBuffer\t\t*newchunk, *chunk;\n\tbyte\t\t\t*out;\n\n\tif (!madeTable) {\n\t\tfor (i=0;i<256;i++) {\n\t\t\tmulawToShort[i] = (float)MuLawDecode((byte)i);\n\t\t}\n\t\tmadeTable = qtrue;\n\t}\n\n\tchunk = NULL;\n\tsamples = sfx->soundLength;\n\tgrade = 0;\n\n\twhile(samples>0) {\n\t\tsize = samples;\n\t\tif (size>(SND_CHUNK_SIZE*2)) {\n\t\t\tsize = (SND_CHUNK_SIZE*2);\n\t\t}\n\n\t\tnewchunk = SND_malloc();\n\t\tif (sfx->soundData == NULL) {\n\t\t\tsfx->soundData = newchunk;\n\t\t} else {\n\t\t\tchunk->next = newchunk;\n\t\t}\n\t\tchunk = newchunk;\n\t\tout = (byte *)chunk->sndChunk;\n\t\tfor(i=0; i<size; i++) {\n\t\t\tpoop = packets[0]+grade;\n\t\t\tif (poop>32767) {\n\t\t\t\tpoop = 32767;\n\t\t\t} else if (poop<-32768) {\n\t\t\t\tpoop = -32768;\n\t\t\t}\n\t\t\tout[i] = MuLawEncode((short)poop);\n\t\t\tgrade = poop - mulawToShort[out[i]];\n\t\t\tpackets++;\n\t\t}\n\t\tchunk->size = size;\n\t\tsamples -= size;\n\t}\n}\n\nvoid decodeMuLaw(sndBuffer *chunk, short *to) {\n\tint\t\t\t\ti;\n\tbyte\t\t\t*out;\n\n\tint size = chunk->size;\n\t\n\tout = (byte *)chunk->sndChunk;\n\tfor(i=0;i<size;i++) {\n\t\tto[i] = mulawToShort[out[i]];\n\t}\n}\n\n\n"
  },
  {
    "path": "src/engine/platform/resource.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//{{NO_DEPENDENCIES}}\n// Microsoft Developer Studio generated include file.\n// Used by winquake.rc\n//\n#define IDS_STRING1                     1\n#define IDI_ICON1                       1\n#define IDB_BITMAP1                     1\n#define IDB_BITMAP2                     128\n#define IDC_CURSOR1                     129\n#define IDC_CURSOR2                     130\n#define IDC_CURSOR3                     131\n\n// Next default values for new objects\n// \n#ifdef APSTUDIO_INVOKED\n#ifndef APSTUDIO_READONLY_SYMBOLS\n#define _APS_NO_MFC                     1\n#define _APS_NEXT_RESOURCE_VALUE        132\n#define _APS_NEXT_COMMAND_VALUE         40001\n#define _APS_NEXT_CONTROL_VALUE         1005\n#define _APS_NEXT_SYMED_VALUE           101\n#endif\n#endif\n"
  },
  {
    "path": "src/engine/platform/win_gamma.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n/*\n** WIN_GAMMA.C\n*/\n#include <assert.h>\n#include \"../renderer/tr_local.h\"\n#include \"../qcommon/qcommon.h\"\n#include \"win_local.h\"\n\nstatic unsigned short s_oldHardwareGamma[3][256];\n\n/*\n** WG_CheckHardwareGamma\n**\n** Determines if the underlying hardware supports the Win32 gamma correction API.\n*/\nvoid WG_CheckHardwareGamma( void )\n{\n\tHDC\t\t\thDC;\n\n\tglConfig.deviceSupportsGamma = qfalse;\n\n\tif ( !r_ignorehwgamma->integer )\n\t{\n\t\thDC = GetDC( GetDesktopWindow() );\n\t\tglConfig.deviceSupportsGamma = (qboolean) GetDeviceGammaRamp( hDC, s_oldHardwareGamma );\n\t\tReleaseDC( GetDesktopWindow(), hDC );\n\n\t\tif ( glConfig.deviceSupportsGamma )\n\t\t{\n\t\t\t//\n\t\t\t// do a sanity check on the gamma values\n\t\t\t//\n\t\t\tif ( ( HIBYTE( s_oldHardwareGamma[0][255] ) <= HIBYTE( s_oldHardwareGamma[0][0] ) ) ||\n\t\t\t\t ( HIBYTE( s_oldHardwareGamma[1][255] ) <= HIBYTE( s_oldHardwareGamma[1][0] ) ) ||\n\t\t\t\t ( HIBYTE( s_oldHardwareGamma[2][255] ) <= HIBYTE( s_oldHardwareGamma[2][0] ) ) )\n\t\t\t{\n\t\t\t\tglConfig.deviceSupportsGamma = qfalse;\n\t\t\t\tri.Printf( PRINT_WARNING, \"WARNING: device has broken gamma support, generated gamma.dat\\n\" );\n\t\t\t}\n\n\t\t\t//\n\t\t\t// make sure that we didn't have a prior crash in the game, and if so we need to\n\t\t\t// restore the gamma values to at least a linear value\n\t\t\t//\n\t\t\tif ( ( HIBYTE( s_oldHardwareGamma[0][181] ) == 255 ) )\n\t\t\t{\n\t\t\t\tint g;\n\n\t\t\t\tri.Printf( PRINT_WARNING, \"WARNING: suspicious gamma tables, using linear ramp for restoration\\n\" );\n\n\t\t\t\tfor ( g = 0; g < 255; g++ )\n\t\t\t\t{\n\t\t\t\t\ts_oldHardwareGamma[0][g] = g << 8;\n\t\t\t\t\ts_oldHardwareGamma[1][g] = g << 8;\n\t\t\t\t\ts_oldHardwareGamma[2][g] = g << 8;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n/*\n** GLimp_SetGamma\n**\n** This routine should only be called if glConfig.deviceSupportsGamma is TRUE\n*/\nvoid GLimp_SetGamma( unsigned char mapping[256]) {\n\tunsigned short table[3][256];\n\tint\t\ti, j;\n\tint\t\tret;\n\n\tif ( !glConfig.deviceSupportsGamma || r_ignorehwgamma->integer ) {\n\t\treturn;\n\t}\n\n\tfor ( i = 0; i < 256; i++ ) {\n\t\tunsigned short value = (((unsigned short)mapping[i]) << 8) | mapping[i];\n\t\ttable[0][i] = value;\n\t\ttable[1][i] = value;\n\t\ttable[2][i] = value;\n\t}\n\n\t// Win2K puts this odd restriction on gamma ramps...\n\tCom_DPrintf( \"performing W2K gamma clamp.\\n\" );\n\tfor ( j = 0 ; j < 3 ; j++ ) {\n\t\tfor ( i = 0 ; i < 128 ; i++ ) {\n\t\t\tif ( table[j][i] > ( (128+i) << 8 ) ) {\n\t\t\t\ttable[j][i] = (128+i) << 8;\n\t\t\t}\n\t\t}\n\t\tif ( table[j][127] > 254<<8 ) {\n\t\t\ttable[j][127] = 254<<8;\n\t\t}\n\t}\n\t\n\t// enforce constantly increasing\n\tfor ( j = 0 ; j < 3 ; j++ ) {\n\t\tfor ( i = 1 ; i < 256 ; i++ ) {\n\t\t\tif ( table[j][i] < table[j][i-1] ) {\n\t\t\t\ttable[j][i] = table[j][i-1];\n\t\t\t}\n\t\t}\n\t}\n\n\tHDC hdc = GetDC(NULL);\n\tret = SetDeviceGammaRamp( hdc, table );\n\tif ( !ret ) {\n\t\tCom_Printf( \"SetDeviceGammaRamp failed.\\n\" );\n\t}\n\tReleaseDC(NULL, hdc);\n}\n\n/*\n** WG_RestoreGamma\n*/\nvoid WG_RestoreGamma( void )\n{\n\tif ( glConfig.deviceSupportsGamma )\n\t{\n\t\tHDC hDC;\n\n\t\thDC = GetDC( GetDesktopWindow() );\n\t\tSetDeviceGammaRamp( hDC, s_oldHardwareGamma );\n\t\tReleaseDC( GetDesktopWindow(), hDC );\n\t}\n}\n\nvoid GLimp_RestoreGamma()\n{\n\tWG_RestoreGamma();\n}\n"
  },
  {
    "path": "src/engine/platform/win_glimp.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n/*\n** WIN_GLIMP.C\n**\n** This file contains ALL Win32 specific stuff having to do with the\n** OpenGL/Vulkan refresh.  When a port is being made the following functions\n** must be implemented by the port:\n**\n** GLimp_EndFrame\n** GLimp_Init\n** GLimp_LogComment\n** GLimp_Shutdown\n**\n** vk_imp_init\n** vk_imp_shutdown\n** vk_imp_create_surface\n*/\n#include \"../renderer/tr_local.h\"\n#include \"resource.h\"\n#include \"win_local.h\"\n\n#define\tMAIN_WINDOW_CLASS_NAME\t\"Quake 3: Arena\"\n#define\tTWIN_WINDOW_CLASS_NAME\t\"Quake 3: Arena [Twin]\"\n\nstatic bool s_main_window_class_registered = false;\nstatic bool s_twin_window_class_registered = false;\n\nstatic HDC gl_hdc; // handle to device context\nstatic HGLRC gl_hglrc; // handle to GL rendering context\n\nstatic HINSTANCE vk_library_handle; // HINSTANCE for the Vulkan library\n\nFILE* log_fp;\n\nqboolean QGL_Init(const char *dllname);\nvoid QGL_Shutdown();\nvoid QGL_EnableLogging(qboolean enable);\nvoid WG_CheckHardwareGamma();\nvoid WG_RestoreGamma();\n\nstatic int GetDesktopCaps(int index) {\n    HDC hdc = GetDC(GetDesktopWindow());\n    int value = GetDeviceCaps(hdc, index);\n    ReleaseDC(GetDesktopWindow(), hdc);\n    return value;\n}\nstatic int GetDesktopColorDepth() { return GetDesktopCaps(BITSPIXEL); }\nstatic int GetDesktopWidth() { return GetDesktopCaps(HORZRES); }\nstatic int GetDesktopHeight() { return GetDesktopCaps(VERTRES); }\n\n/*\n** ChoosePFD\n**\n** Helper function that replaces ChoosePixelFormat.\n*/\nstatic int GLW_ChoosePixelFormat(HDC hDC, const PIXELFORMATDESCRIPTOR *pPFD)\n{\n    const int MAX_PFDS = 512;\n\tPIXELFORMATDESCRIPTOR pfds[MAX_PFDS+1];\n\n\tri.Printf(PRINT_ALL, \"...GLW_ChoosePFD( %d, %d, %d )\\n\", (int) pPFD->cColorBits, (int) pPFD->cDepthBits, (int) pPFD->cStencilBits);\n\n\t// count number of PFDs\n\tint maxPFD = DescribePixelFormat(hDC, 1, sizeof( PIXELFORMATDESCRIPTOR ), &pfds[0]);\n\tif (maxPFD > MAX_PFDS) {\n\t\tri.Printf(PRINT_WARNING, \"...numPFDs > MAX_PFDS (%d > %d)\\n\", maxPFD, MAX_PFDS);\n\t\tmaxPFD = MAX_PFDS;\n\t}\n\n\tri.Printf(PRINT_ALL, \"...%d PFDs found\\n\", maxPFD);\n\n\t// grab information\n\tfor (int i = 1; i <= maxPFD; i++) {\n\t\tDescribePixelFormat(hDC, i, sizeof(PIXELFORMATDESCRIPTOR), &pfds[i]);\n\t}\n\n\t// look for a best match\n    int bestMatch = 0;\n\tfor (int i = 1; i <= maxPFD; i++ ) {\n        if (bestMatch != 0 &&\n            (pfds[bestMatch].dwFlags & PFD_STEREO) == (pPFD->dwFlags & PFD_STEREO) &&\n            pfds[bestMatch].cColorBits == pPFD->cColorBits &&\n            pfds[bestMatch].cDepthBits == pPFD->cDepthBits &&\n            pfds[bestMatch].cStencilBits == pPFD->cStencilBits)\n        {\n            break;\n        }\n\n\t\t//\n\t\t// make sure this has hardware acceleration\n\t\t//\n\t\tif ((pfds[i].dwFlags & PFD_GENERIC_FORMAT) != 0)  {\n\t\t\tif (r_verbose->integer) {\n\t\t\t\tri.Printf( PRINT_ALL, \"...PFD %d rejected, software acceleration\\n\", i );\n            }\n            continue;\n\t\t}\n\n\t\t// verify pixel type\n\t\tif (pfds[i].iPixelType != PFD_TYPE_RGBA) {\n\t\t\tif (r_verbose->integer) {\n\t\t\t\tri.Printf( PRINT_ALL, \"...PFD %d rejected, not RGBA\\n\", i );\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\t// verify proper flags\n\t\tif ((pfds[i].dwFlags & pPFD->dwFlags) != pPFD->dwFlags) {\n\t\t\tif (r_verbose->integer) {\n\t\t\t\tri.Printf( PRINT_ALL, \"...PFD %d rejected, improper flags (%x instead of %x)\\n\", i, pfds[i].dwFlags, pPFD->dwFlags );\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\t// verify enough bits\n\t\tif (pfds[i].cDepthBits < 15) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ((pfds[i].cStencilBits < 4) && (pPFD->cStencilBits > 0)) {\n\t\t\tcontinue;\n\t\t}\n\n        if (!bestMatch) {\n            bestMatch = i;\n            continue;\n        }\n\n\t\t//\n\t\t// selection criteria (in order of priority):\n\t\t// \n\t\t//  PFD_STEREO\n\t\t//  colorBits\n\t\t//  depthBits\n\t\t//  stencilBits\n\t\t//\n        bool same_stereo = (pfds[i].dwFlags & PFD_STEREO) == (pfds[bestMatch].dwFlags & PFD_STEREO);\n        bool better_stereo = (pfds[i].dwFlags & PFD_STEREO) == (pPFD->dwFlags & PFD_STEREO) &&\n            (pfds[bestMatch].dwFlags & PFD_STEREO) != (pPFD->dwFlags & PFD_STEREO);\n\n        bool same_color = pfds[i].cColorBits == pfds[bestMatch].cColorBits;\n        bool better_color = (pfds[bestMatch].cColorBits >= pPFD->cColorBits)\n            ? pfds[i].cColorBits >= pPFD->cColorBits && pfds[i].cColorBits < pfds[bestMatch].cColorBits\n            : pfds[i].cColorBits > pfds[bestMatch].cColorBits;\n\n        bool same_depth = pfds[i].cDepthBits == pfds[bestMatch].cDepthBits;\n        bool better_depth = (pfds[bestMatch].cDepthBits >= pPFD->cDepthBits)\n            ? pfds[i].cDepthBits >= pPFD->cDepthBits && pfds[i].cDepthBits < pfds[bestMatch].cDepthBits\n            : pfds[i].cDepthBits > pfds[bestMatch].cDepthBits;\n\n        bool better_stencil;\n        if (pPFD->cStencilBits == 0)\n            better_stencil = pfds[i].cStencilBits == 0 && pfds[bestMatch].cStencilBits != 0;\n        else\n            better_stencil = (pfds[bestMatch].cStencilBits >= pPFD->cStencilBits)\n                ? pfds[i].cStencilBits >= pPFD->cStencilBits && pfds[i].cStencilBits < pfds[bestMatch].cStencilBits\n                : pfds[i].cStencilBits > pfds[bestMatch].cStencilBits;\n\n        if (better_stereo)\n            bestMatch = i;\n        else if (same_stereo) {\n            if (better_color)\n                bestMatch = i;\n            else if (same_color) {\n                if (better_depth)\n                    bestMatch = i;\n                else if (same_depth) {\n                    if (better_stencil)\n                        bestMatch = i;\n                }\n            }\n        }\n\t}\n\n\tif ( !bestMatch )\n\t\treturn 0;\n\n\tif ((pfds[bestMatch].dwFlags & PFD_GENERIC_FORMAT) != 0 || (pfds[bestMatch].dwFlags & PFD_GENERIC_ACCELERATED) != 0) {\n        ri.Printf(PRINT_ALL, \"...no hardware acceleration found\\n\");\n        return 0;\n\t}\n\n    ri.Printf(PRINT_ALL, \"...hardware acceleration found\\n\");\n\treturn bestMatch;\n}\n\nstatic bool GLW_SetPixelFormat(HDC hdc, PIXELFORMATDESCRIPTOR *pPFD, int colorbits, int depthbits, int stencilbits, qboolean stereo) {\n    const PIXELFORMATDESCRIPTOR pfd_base =\n    {\n        sizeof(PIXELFORMATDESCRIPTOR),\t// size of this pfd\n        1,\t\t\t\t\t\t\t\t// version number\n        PFD_DRAW_TO_WINDOW |\t\t\t// support window\n        PFD_SUPPORT_OPENGL |\t\t\t// support OpenGL\n        PFD_DOUBLEBUFFER,\t\t\t\t// double buffered\n        PFD_TYPE_RGBA,\t\t\t\t\t// RGBA type\n        0,\t                \t\t\t// color bits\n        0, 0, 0, 0, 0, 0,\t\t\t\t// color bits ignored\n        0,\t\t\t\t\t\t\t\t// no alpha buffer\n        0,\t\t\t\t\t\t\t\t// shift bit ignored\n        0,\t\t\t\t\t\t\t\t// no accumulation buffer\n        0, 0, 0, 0, \t\t\t\t\t// accum bits ignored\n        0,\t                \t\t\t// z-buffer\tbits\n        0,              \t    \t\t// stencil buffer bits\n        0,\t\t\t\t\t\t\t\t// no auxiliary buffer\n        PFD_MAIN_PLANE,\t\t\t\t\t// main layer\n        0,\t\t\t\t\t\t\t\t// reserved\n        0, 0, 0\t\t\t\t\t\t\t// layer masks ignored\n    };\n\n    *pPFD = pfd_base;\n\n    pPFD->cColorBits = (BYTE)colorbits;\n    pPFD->cDepthBits = (BYTE)depthbits;\n    pPFD->cStencilBits = (BYTE)stencilbits;\n\n    if (stereo)\n    {\n        ri.Printf(PRINT_ALL, \"...attempting to use stereo\\n\");\n        pPFD->dwFlags |= PFD_STEREO;\n    }\n\n    int pixelformat = GLW_ChoosePixelFormat(hdc, pPFD);\n\tif (pixelformat == 0) {\n\t\tri.Printf( PRINT_ALL, \"...GLW_ChoosePixelFormat failed\\n\");\n\t\treturn false;\n\t}\n\tri.Printf( PRINT_ALL, \"...PIXELFORMAT %d selected\\n\", pixelformat );\n\n\tDescribePixelFormat(hdc, pixelformat, sizeof( *pPFD ), pPFD);\n\tif (SetPixelFormat(hdc, pixelformat, pPFD ) == FALSE) {\n\t\tri.Printf (PRINT_ALL, \"...SetPixelFormat failed\\n\", hdc);\n\t\treturn false;\n\t}\n    return true;\n}\n\n// Sets pixel format and creates opengl context for the given window.\nstatic qboolean GLW_InitDriver(HWND hwnd) {\n\tri.Printf( PRINT_ALL, \"Initializing OpenGL driver\\n\" );\n\n\t//\n\t// get a DC for our window\n\t//\n\tri.Printf(PRINT_ALL, \"...getting DC: \");\n    gl_hdc = GetDC(hwnd);\n\tif (gl_hdc == NULL) {\n\t\tri.Printf(PRINT_ALL, \"failed\\n\");\n\t\treturn qfalse;\n\t}\n\tri.Printf(PRINT_ALL, \"succeeded\\n\");\n\n\t//\n\t// set pixel format\n\t//\n    int colorbits = GetDesktopColorDepth();\n    int depthbits = (r_depthbits->integer == 0) ? 24 : r_depthbits->integer;\n    int stencilbits = r_stencilbits->integer;\n\n    PIXELFORMATDESCRIPTOR pfd;\n    if (!GLW_SetPixelFormat(gl_hdc, &pfd, colorbits, depthbits, stencilbits, (qboolean)r_stereo->integer)) {\n        ReleaseDC(hwnd, gl_hdc);\n\t\tgl_hdc = NULL;\n        ri.Printf(PRINT_ALL, \"...failed to find an appropriate PIXELFORMAT\\n\");\n        return qfalse;\n\t}\n\n    // report if stereo is desired but unavailable\n\tif (!(pfd.dwFlags & PFD_STEREO) && (r_stereo->integer != 0)) {\n\t\tri.Printf(PRINT_ALL, \"...failed to select stereo pixel format\\n\");\n\t}\n\n    //\n    // startup the OpenGL subsystem by creating a context and making it current\n    //\n    ri.Printf(PRINT_ALL, \"...creating GL context: \");\n    gl_hglrc = qwglCreateContext(gl_hdc);\n    if (gl_hglrc == NULL) {\n        ReleaseDC(hwnd, gl_hdc);\n\t\tgl_hdc = NULL;\n        ri.Printf(PRINT_ALL, \"failed\\n\");\n        return qfalse;\n    }\n    ri.Printf(PRINT_ALL, \"succeeded\\n\");\n\n    ri.Printf(PRINT_ALL, \"...making context current: \");\n    if (!qwglMakeCurrent(gl_hdc, gl_hglrc)) {\n        qwglDeleteContext(gl_hglrc);\n\t\tgl_hglrc = NULL;\n        ReleaseDC(hwnd, gl_hdc);\n\t\tgl_hdc = NULL;\n        ri.Printf(PRINT_ALL, \"failed\\n\");\n        return qfalse;\n    }\n    ri.Printf(PRINT_ALL, \"succeeded\\n\");\n\n\tglConfig.colorBits = ( int ) pfd.cColorBits;\n\tglConfig.depthBits = ( int ) pfd.cDepthBits;\n\tglConfig.stencilBits = ( int ) pfd.cStencilBits;\n    glConfig.stereoEnabled = (pfd.dwFlags & PFD_STEREO) ? qtrue : qfalse;\n\treturn qtrue;\n}\n\nstatic HWND create_main_window(int width, int height, qboolean fullscreen)\n{\n\t//\n\t// register the window class if necessary\n\t//\n\tif (!s_main_window_class_registered)\n\t{\n        cvar_t* cv = ri.Cvar_Get( \"win_wndproc\", \"\", 0 );\n        WNDPROC\twndproc;\n        sscanf(cv->string, \"%p\", (void **)&wndproc);\n\n\t\tWNDCLASS wc;\n\n\t\tmemset( &wc, 0, sizeof( wc ) );\n\n\t\twc.style         = 0;\n\t\twc.lpfnWndProc   = wndproc;\n\t\twc.cbClsExtra    = 0;\n\t\twc.cbWndExtra    = 0;\n\t\twc.hInstance     = g_wv.hInstance;\n\t\twc.hIcon         = LoadIcon( g_wv.hInstance, MAKEINTRESOURCE(IDI_ICON1));\n\t\twc.hCursor       = LoadCursor (NULL,IDC_ARROW);\n\t\twc.hbrBackground = (HBRUSH) (void *)COLOR_GRAYTEXT;\n\t\twc.lpszMenuName  = 0;\n\t\twc.lpszClassName = MAIN_WINDOW_CLASS_NAME;\n\n\t\tif ( !RegisterClass( &wc ) )\n\t\t{\n\t\t\tri.Error( ERR_FATAL, \"create_main_window: could not register window class\" );\n\t\t}\n\t\ts_main_window_class_registered = true;\n\t\tri.Printf( PRINT_ALL, \"...registered window class\\n\" );\n\t}\n\n\t//\n\t// compute width and height\n\t//\n    RECT r;\n\tr.left = 0;\n\tr.top = 0;\n\tr.right  = width;\n\tr.bottom = height;\n\n    int\tstylebits;\n\tif ( fullscreen )\n\t{\n\t\tstylebits = WS_POPUP|WS_VISIBLE|WS_SYSMENU;\n\t}\n\telse\n\t{\n\t\tstylebits = WS_OVERLAPPED | WS_BORDER | WS_CAPTION | WS_VISIBLE | WS_SYSMENU;\n\t\tAdjustWindowRect (&r, stylebits, FALSE);\n\t}\n\n\tint w = r.right - r.left;\n\tint h = r.bottom - r.top;\n\n    int x, y;\n\n\tif ( fullscreen  )\n\t{\n\t\tx = 0;\n\t\ty = 0;\n\t}\n\telse\n\t{\n\t\tcvar_t* vid_xpos = ri.Cvar_Get (\"vid_xpos\", \"\", 0);\n\t\tcvar_t* vid_ypos = ri.Cvar_Get (\"vid_ypos\", \"\", 0);\n\t\tx = vid_xpos->integer;\n\t\ty = vid_ypos->integer;\n\n\t\t// adjust window coordinates if necessary \n\t\t// so that the window is completely on screen\n\t\tif ( x < 0 )\n\t\t\tx = 0;\n\t\tif ( y < 0 )\n\t\t\ty = 0;\n\n        int desktop_width = GetDesktopWidth();\n        int desktop_height = GetDesktopHeight();\n\n\t\tif (w < desktop_width && h < desktop_height)\n\t\t{\n\t\t\tif ( x + w > desktop_width )\n\t\t\t\tx = ( desktop_width - w );\n\t\t\tif ( y + h > desktop_height )\n\t\t\t\ty = ( desktop_height - h );\n\t\t}\n\t}\n\n\tchar window_name[1024];\n\tif (r_twinMode->integer == 0) {\n\t\tstrcpy(window_name, MAIN_WINDOW_CLASS_NAME);\n\t} else {\n\t\tconst char* api_name = \"invalid-render-api\";\n\t\tif (get_render_api() == RENDER_API_GL)\n\t\t\tapi_name = \"OpenGL\";\n\t\telse if (get_render_api() == RENDER_API_VK)\n\t\t\tapi_name = \"Vulkan\";\n\t\telse if (get_render_api() == RENDER_API_DX)\n\t\t\tapi_name = \"DX12\";\n\t\tsprintf(window_name, \"%s [%s]\", MAIN_WINDOW_CLASS_NAME, api_name);\n\t}\n\n\tHWND hwnd = CreateWindowEx(\n\t\t\t0, \n\t\t\tMAIN_WINDOW_CLASS_NAME,\n\t\t\twindow_name,\n\t\t\tstylebits,\n\t\t\tx, y, w, h,\n\t\t\tNULL,\n\t\t\tNULL,\n\t\t\tg_wv.hInstance,\n\t\t\tNULL);\n\n\tif (!hwnd)\n\t{\n\t\tri.Error (ERR_FATAL, \"create_main_window() - Couldn't create window\");\n\t}\n\n\tShowWindow(hwnd, SW_SHOW);\n\tUpdateWindow(hwnd);\n\tri.Printf(PRINT_ALL, \"...created window@%d,%d (%dx%d)\\n\", x, y, w, h);\n    return hwnd;\n}\n\nstatic HWND create_twin_window(int width, int height, RenderApi render_api)\n{\n    //\n    // register the window class if necessary\n    //\n    if (!s_twin_window_class_registered)\n    {\n        WNDCLASS wc;\n\n        memset( &wc, 0, sizeof( wc ) );\n\n        wc.style         = 0;\n        wc.lpfnWndProc   = DefWindowProc;\n        wc.cbClsExtra    = 0;\n        wc.cbWndExtra    = 0;\n        wc.hInstance     = g_wv.hInstance;\n        wc.hIcon         = LoadIcon( g_wv.hInstance, MAKEINTRESOURCE(IDI_ICON1));\n        wc.hCursor       = LoadCursor (NULL,IDC_ARROW);\n        wc.hbrBackground = (HBRUSH) (void *)COLOR_GRAYTEXT;\n        wc.lpszMenuName  = 0;\n        wc.lpszClassName = TWIN_WINDOW_CLASS_NAME;\n\n        if ( !RegisterClass( &wc ) )\n        {\n            ri.Error( ERR_FATAL, \"create_twin_window: could not register window class\" );\n        }\n\t\ts_twin_window_class_registered = true;\n        ri.Printf( PRINT_ALL, \"...registered twin window class\\n\" );\n    }\n\n    //\n    // compute width and height\n    //\n    RECT r;\n    r.left = 0;\n    r.top = 0;\n    r.right  = width;\n    r.bottom = height;\n\n    int stylebits = WS_OVERLAPPED | WS_BORDER | WS_CAPTION | WS_VISIBLE | WS_SYSMENU;\n    AdjustWindowRect (&r, stylebits, FALSE);\n\n    int w = r.right - r.left;\n    int h = r.bottom - r.top;\n\n    cvar_t* vid_xpos = ri.Cvar_Get (\"vid_xpos\", \"\", 0);\n    cvar_t* vid_ypos = ri.Cvar_Get (\"vid_ypos\", \"\", 0);\n\tint x, y;\n\n\tbool first_twin_window =\n\t\t\t(get_render_api() != RENDER_API_GL && render_api == RENDER_API_GL) ||\n\t\t\t(get_render_api() == RENDER_API_GL && render_api == RENDER_API_VK);\n\n\tif (first_twin_window) {\n\t\tx = vid_xpos->integer + width + 5;\n\t\ty = vid_ypos->integer;\n\t}  else {\n\t\tx = vid_xpos->integer + 2*width + 10;\n\t\ty = vid_ypos->integer;\n\t}\n\n\tint desktop_width = GetDesktopWidth();\n    int desktop_height = GetDesktopHeight();\n\n    if (x < 0)\n        x = 0;\n\telse if (x >= desktop_width - 20)\n\t\tx = desktop_width - 20;\n\n    if (y < 0)\n        y = 0;\n\telse if (y >= desktop_height - 20)\n\t\ty = desktop_height - 20;\n\t\n\tchar window_name[1024];\n\tconst char* api_name = \"invalid-render-api\";\n\tif (render_api == RENDER_API_GL)\n\t\tapi_name = \"OpenGL\";\n\telse if (render_api == RENDER_API_VK)\n\t\tapi_name = \"Vulkan\";\n\telse if (render_api == RENDER_API_DX)\n\t\tapi_name = \"DX12\";\n\tsprintf(window_name, \"%s [%s]\", MAIN_WINDOW_CLASS_NAME, api_name);\n\n    HWND hwnd = CreateWindowEx(\n        0, \n        TWIN_WINDOW_CLASS_NAME,\n        window_name,\n        stylebits,\n        x, y, w, h,\n        NULL,\n        NULL,\n        g_wv.hInstance,\n        NULL);\n\n    if (!hwnd)\n    {\n        ri.Error (ERR_FATAL, \"create_twin_window() - Couldn't create window\");\n    }\n\n    ShowWindow(hwnd, SW_SHOW);\n    UpdateWindow(hwnd);\n    ri.Printf(PRINT_ALL, \"...created twin window@%d,%d (%dx%d)\\n\", x, y, w, h);\n    return hwnd;\n}\n\nstatic void SetMode(int mode, qboolean fullscreen) {\n\tif (fullscreen) {\n\t\tri.Printf( PRINT_ALL, \"...setting fullscreen mode:\");\n\t\tglConfig.vidWidth = GetDesktopWidth();\n\t\tglConfig.vidHeight = GetDesktopHeight();\n\t\tglConfig.windowAspect = 1.0f;\n\t} else {\n\t\tri.Printf( PRINT_ALL, \"...setting mode %d:\", mode );\n\t\tif (!R_GetModeInfo(&glConfig.vidWidth, &glConfig.vidHeight, &glConfig.windowAspect, mode)) {\n\t\t\tri.Printf( PRINT_ALL, \" invalid mode\\n\" );\n\t\t\tri.Error(ERR_FATAL, \"SetMode - could not set the given mode (%d)\\n\", mode);\n\t\t}\n\n\t\t// Ensure that window size does not exceed desktop size.\n\t\t// CreateWindow Win32 API does not allow to create windows larger than desktop.\n\t\tint desktop_width = GetDesktopWidth();\n\t\tint desktop_height = GetDesktopHeight();\n\n\t\tif (glConfig.vidWidth > desktop_width || glConfig.vidHeight > desktop_height) {\n\t\t\tint default_mode = 4;\n\t\t\tri.Printf(PRINT_WARNING, \"\\nMode %d specifies width that is larger than desktop width: using default mode %d\\n\", mode, default_mode);\n\t\t\t\n\t\t\tri.Printf( PRINT_ALL, \"...setting mode %d:\", default_mode );\n\t\t\tif (!R_GetModeInfo(&glConfig.vidWidth, &glConfig.vidHeight, &glConfig.windowAspect, default_mode)) {\n\t\t\t\tri.Printf( PRINT_ALL, \" invalid mode\\n\" );\n\t\t\t\tri.Error(ERR_FATAL, \"SetMode - could not set the given mode (%d)\\n\", default_mode);\n\t\t\t}\n\t\t}\n\t}\n\tglConfig.isFullscreen = fullscreen;\n\tri.Printf( PRINT_ALL, \" %d %d %s\\n\", glConfig.vidWidth, glConfig.vidHeight, fullscreen ? \"FS\" : \"W\");\n}\n\n/*\n** GLW_InitExtensions\n*/\nstatic void GLW_InitExtensions( void )\n{\n\tri.Printf( PRINT_ALL, \"Initializing OpenGL extensions\\n\" );\n\n\t// GL_S3_s3tc\n\tglConfig.textureCompression = TC_NONE;\n\tif ( strstr( glConfig.extensions_string, \"GL_S3_s3tc\" ) )\n\t{\n\t\tif ( r_ext_compressed_textures->integer )\n\t\t{\n\t\t\tglConfig.textureCompression = TC_S3TC;\n\t\t\tri.Printf( PRINT_ALL, \"...using GL_S3_s3tc\\n\" );\n\t\t}\n\t\telse\n\t\t{\n\t\t\tglConfig.textureCompression = TC_NONE;\n\t\t\tri.Printf( PRINT_ALL, \"...ignoring GL_S3_s3tc\\n\" );\n\t\t}\n\t}\n\telse\n\t{\n\t\tri.Printf( PRINT_ALL, \"...GL_S3_s3tc not found\\n\" );\n\t}\n\n\t// GL_EXT_texture_env_add\n\tglConfig.textureEnvAddAvailable = qfalse;\n\tif ( strstr( glConfig.extensions_string, \"EXT_texture_env_add\" ) )\n\t{\n\t\tif ( r_ext_texture_env_add->integer )\n\t\t{\n\t\t\tglConfig.textureEnvAddAvailable = qtrue;\n\t\t\tri.Printf( PRINT_ALL, \"...using GL_EXT_texture_env_add\\n\" );\n\t\t}\n\t\telse\n\t\t{\n\t\t\tglConfig.textureEnvAddAvailable = qfalse;\n\t\t\tri.Printf( PRINT_ALL, \"...ignoring GL_EXT_texture_env_add\\n\" );\n\t\t}\n\t}\n\telse\n\t{\n\t\tri.Printf( PRINT_ALL, \"...GL_EXT_texture_env_add not found\\n\" );\n\t}\n\n\t// WGL_EXT_swap_control\n\tqwglSwapIntervalEXT = ( BOOL (WINAPI *)(int)) qwglGetProcAddress( \"wglSwapIntervalEXT\" );\n\tif ( qwglSwapIntervalEXT )\n\t{\n\t\tri.Printf( PRINT_ALL, \"...using WGL_EXT_swap_control\\n\" );\n\t\tr_swapInterval->modified = qtrue;\t// force a set next frame\n\t}\n\telse\n\t{\n\t\tri.Printf( PRINT_ALL, \"...WGL_EXT_swap_control not found\\n\" );\n\t}\n\n    // GL_ARB_multitexture\n    {\n        if (!strstr(glConfig.extensions_string, \"GL_ARB_multitexture\"))\n            ri.Error(ERR_FATAL, \"GL_ARB_multitexture not found\");\n\n        qglActiveTextureARB = ( void (APIENTRY * ) (GLenum target) ) qwglGetProcAddress(\"glActiveTextureARB\");\n        qglClientActiveTextureARB = ( void (APIENTRY * ) (GLenum target) ) qwglGetProcAddress(\"glClientActiveTextureARB\");\n\n        if (!qglActiveTextureARB || !qglClientActiveTextureARB)\n            ri.Error(ERR_FATAL, \"GL_ARB_multitexture: could not initialize function pointers\");\n\n        qglGetIntegerv(GL_MAX_ACTIVE_TEXTURES_ARB, &glConfig.maxActiveTextures);\n\n        if (glConfig.maxActiveTextures < 2)\n            ri.Error(ERR_FATAL, \"GL_ARB_multitexture: < 2 texture units\");\n\n        ri.Printf(PRINT_ALL, \"...using GL_ARB_multitexture\\n\");\n    }\n\n\t// GL_EXT_compiled_vertex_array\n\tqglLockArraysEXT = NULL;\n\tqglUnlockArraysEXT = NULL;\n\tif ( strstr( glConfig.extensions_string, \"GL_EXT_compiled_vertex_array\" ) )\n\t{\n\t\tif ( r_ext_compiled_vertex_array->integer )\n\t\t{\n\t\t\tri.Printf( PRINT_ALL, \"...using GL_EXT_compiled_vertex_array\\n\" );\n\t\t\tqglLockArraysEXT = ( void ( APIENTRY * )( int, int ) ) qwglGetProcAddress( \"glLockArraysEXT\" );\n\t\t\tqglUnlockArraysEXT = ( void ( APIENTRY * )( void ) ) qwglGetProcAddress( \"glUnlockArraysEXT\" );\n\t\t\tif (!qglLockArraysEXT || !qglUnlockArraysEXT) {\n\t\t\t\tri.Error (ERR_FATAL, \"bad getprocaddress\");\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tri.Printf( PRINT_ALL, \"...ignoring GL_EXT_compiled_vertex_array\\n\" );\n\t\t}\n\t}\n\telse\n\t{\n\t\tri.Printf( PRINT_ALL, \"...GL_EXT_compiled_vertex_array not found\\n\" );\n\t}\n}\n\n/*\n** GLimp_EndFrame\n*/\nvoid GLimp_EndFrame (void)\n{\n\tif (!gl_active)\n\t\treturn;\n\n\t//\n\t// swapinterval stuff\n\t//\n\tif ( r_swapInterval->modified ) {\n\t\tr_swapInterval->modified = qfalse;\n\n\t\tif ( !glConfig.stereoEnabled ) {\t// why?\n\t\t\tif ( qwglSwapIntervalEXT ) {\n\t\t\t\tqwglSwapIntervalEXT( r_swapInterval->integer );\n\t\t\t}\n\t\t}\n\t}\n\n\n\t// don't flip if drawing to front buffer\n\tif ( Q_stricmp( r_drawBuffer->string, \"GL_FRONT\" ) != 0 )\n\t{\n\t\t\tSwapBuffers( gl_hdc );\n\t}\n\n\t// check logging\n\tQGL_EnableLogging( (qboolean) r_logFile->integer );\n}\n\n/*\n** GLimp_Init\n**\n** This is the platform specific OpenGL initialization function.  It\n** is responsible for loading OpenGL, initializing it, setting\n** extensions, creating a window of the appropriate size, doing\n** fullscreen manipulations, etc.  Its overall responsibility is\n** to make sure that a functional OpenGL subsystem is operating\n** when it returns to the ref.\n*/\nvoid GLimp_Init( void )\n{\n\tri.Printf( PRINT_ALL, \"Initializing OpenGL subsystem\\n\" );\n\n\t// load appropriate DLL and initialize subsystem\n\t//\n\t// load the driver and bind our function pointers to it\n\t//\n\tif (!QGL_Init(r_glDriver->string)) {\n\t\tif (Q_stricmp(r_glDriver->string, OPENGL_DRIVER_NAME)) {\n\t\t\tri.Printf(PRINT_ALL, \"...attempting to load default driver: %s\\n\", OPENGL_DRIVER_NAME);\n\n\t\t\tif (!QGL_Init(OPENGL_DRIVER_NAME)) {\n\t\t\t   ri.Error(ERR_FATAL, \"QGL_Init - could not load OpenGL driver\\n\");\n\t\t\t}\n\t\t\tri.Cvar_Set( \"r_glDriver\", OPENGL_DRIVER_NAME );\n\t\t\tr_glDriver->modified = qfalse;\n\t\t}\n\t}\n\n\tSetMode(r_mode->integer, (qboolean)r_fullscreen->integer);\n\n\tif (get_render_api() == RENDER_API_GL) {\n\t\tg_wv.hWnd_opengl = create_main_window(glConfig.vidWidth, glConfig.vidHeight, (qboolean)r_fullscreen->integer);\n\t\tg_wv.hWnd = g_wv.hWnd_opengl;\n\t\tSetForegroundWindow(g_wv.hWnd);\n\t\tSetFocus(g_wv.hWnd);\n\t\tWG_CheckHardwareGamma();\n\t} else {\n\t\tg_wv.hWnd_opengl = create_twin_window(glConfig.vidWidth, glConfig.vidHeight, RENDER_API_GL);\n\t}\n\n\tif (!GLW_InitDriver(g_wv.hWnd_opengl)) {\n\t\tri.Error(ERR_FATAL, \"GLW_InitDriver - could not initialize OpenGL subsystem\\n\");\n\t}\n\n\t// get our config strings\n\tQ_strncpyz( glConfig.vendor_string, (const char*) qglGetString (GL_VENDOR), sizeof( glConfig.vendor_string ) );\n\tQ_strncpyz(glConfig.renderer_string, (const char*)qglGetString(GL_RENDERER), sizeof(glConfig.renderer_string));\n\tQ_strncpyz(glConfig.version_string, (const char*)qglGetString(GL_VERSION), sizeof(glConfig.version_string));\n\tQ_strncpyz(glConfig.extensions_string, (const char*)qglGetString(GL_EXTENSIONS), sizeof(glConfig.extensions_string));\n\n\tGLW_InitExtensions();\n}\n\n/*\n** GLimp_Shutdown\n**\n** This routine does all OS specific shutdown procedures for the OpenGL\n** subsystem.\n*/\nvoid GLimp_Shutdown( void )\n{\n\tconst char *success[] = { \"failed\", \"success\" };\n\n\tri.Printf(PRINT_ALL, \"Shutting down OpenGL subsystem\\n\");\n\n\tif (qwglMakeCurrent) {\n\t\tint retVal = qwglMakeCurrent(NULL, NULL) != 0;\n\t\tri.Printf(PRINT_ALL, \"...wglMakeCurrent( NULL, NULL ): %s\\n\", success[retVal]);\n\t}\n\n\tif (gl_hglrc) {\n\t\tint retVal = qwglDeleteContext(gl_hglrc) != 0;\n\t\tri.Printf(PRINT_ALL, \"...deleting GL context: %s\\n\", success[retVal]);\n\t\tgl_hglrc = NULL;\n\t}\n\n\tif (gl_hdc) {\n\t\tint retVal = ReleaseDC(g_wv.hWnd_opengl, gl_hdc) != 0;\n\t\tri.Printf(PRINT_ALL, \"...releasing DC: %s\\n\", success[retVal]);\n\t\tgl_hdc = NULL;\n\t}\n\n\t// destroy window\n\tif (g_wv.hWnd_opengl) {\n\t\tri.Printf(PRINT_ALL, \"...destroying opengl window\\n\");\n\t\tShowWindow(g_wv.hWnd_opengl, SW_HIDE);\n\t\tDestroyWindow(g_wv.hWnd_opengl);\n\n\t\tif (g_wv.hWnd == g_wv.hWnd_opengl) {\n\t\t\tg_wv.hWnd = NULL;\n\t\t}\n\t\tg_wv.hWnd_opengl = NULL;\n\t}\n\n\tQGL_Shutdown();\n\n\tWG_RestoreGamma();\n\n\tgl_active = false;\n\tmemset(&glConfig, 0, sizeof(glConfig));\n\tmemset(&glState, 0, sizeof(glState));\n\n\tif (log_fp) {\n\t\tfclose(log_fp);\n\t\tlog_fp = 0;\n\t}\n}\n\nvoid GLimp_LogComment( char *comment ) \n{\n\tif ( log_fp ) {\n\t\tfprintf( log_fp, \"%s\", comment );\n\t}\n}\n\nvoid vk_imp_init() {\n\tri.Printf(PRINT_ALL, \"Initializing Vulkan subsystem\\n\");\n\n\t// This will set qgl pointers to no-op placeholders.\n\tif (!gl_active) {\n\t\tQGL_Init(nullptr);\n\t\tqglActiveTextureARB = [] (GLenum)  {};\n\t\tqglClientActiveTextureARB = [](GLenum) {};\n\t}\n\n\t// Load Vulkan DLL.\n\tconst char* dll_name = \"vulkan-1.dll\";\n\n\tri.Printf(PRINT_ALL, \"...calling LoadLibrary('%s'): \", dll_name);\n\tvk_library_handle = LoadLibrary(dll_name);\n\n\tif (vk_library_handle == NULL) {\n\t\tri.Printf(PRINT_ALL, \"failed\\n\");\n\t\tri.Error(ERR_FATAL, \"vk_imp_init - could not load %s\\n\", dll_name);\n\t}\n\tri.Printf( PRINT_ALL, \"succeeded\\n\" );\n\n\tvkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)GetProcAddress(vk_library_handle, \"vkGetInstanceProcAddr\");\n\n\t// Create window.\n\tSetMode(r_mode->integer, (qboolean)r_fullscreen->integer);\n\n\tif (get_render_api() == RENDER_API_VK) {\n\t\tg_wv.hWnd_vulkan = create_main_window(glConfig.vidWidth, glConfig.vidHeight, (qboolean)r_fullscreen->integer);\n\t\tg_wv.hWnd = g_wv.hWnd_vulkan;\n\t\tSetForegroundWindow(g_wv.hWnd);\n\t\tSetFocus(g_wv.hWnd);\n\t\tWG_CheckHardwareGamma();\n\t} else {\n\t\tg_wv.hWnd_vulkan = create_twin_window(glConfig.vidWidth, glConfig.vidHeight, RENDER_API_VK);\n\t}\n}\n\nvoid vk_imp_shutdown() {\n\tri.Printf(PRINT_ALL, \"Shutting down Vulkan subsystem\\n\");\n\n\tif (g_wv.hWnd_vulkan) {\n\t\tri.Printf(PRINT_ALL, \"...destroying Vulkan window\\n\");\n\t\tDestroyWindow(g_wv.hWnd_vulkan);\n\n\t\tif (g_wv.hWnd == g_wv.hWnd_vulkan) {\n\t\t\tg_wv.hWnd = NULL;\n\t\t}\n\t\tg_wv.hWnd_vulkan = NULL;\n\t}\n\n\tif (vk_library_handle != NULL) {\n\t\tri.Printf(PRINT_ALL, \"...unloading Vulkan DLL\\n\");\n\t\tFreeLibrary(vk_library_handle);\n\t\tvk_library_handle = NULL;\n\t}\n\tvkGetInstanceProcAddr = nullptr;\n\n\t// For vulkan mode we still have qgl pointers initialized with placeholder values.\n\t// Reset them the same way as we do in opengl mode.\n\tQGL_Shutdown();\n\n\tWG_RestoreGamma();\n\n\tmemset(&glConfig, 0, sizeof(glConfig));\n\tmemset(&glState, 0, sizeof(glState));\n\n\tif (log_fp) {\n\t\tfclose(log_fp);\n\t\tlog_fp = 0;\n\t}\n}\n\nvoid vk_imp_create_surface() {\n\tVkWin32SurfaceCreateInfoKHR desc;\n\tdesc.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;\n\tdesc.pNext = nullptr;\n\tdesc.flags = 0;\n\tdesc.hinstance = ::GetModuleHandle(nullptr);\n\tdesc.hwnd = g_wv.hWnd_vulkan;\n\tVK_CHECK(vkCreateWin32SurfaceKHR(vk.instance, &desc, nullptr, &vk.surface));\n}\n\nvoid dx_imp_init() {\n\tri.Printf(PRINT_ALL, \"Initializing DX12 subsystem\\n\");\n\n\t// This will set qgl pointers to no-op placeholders.\n\tif (!gl_active) {\n\t\tQGL_Init(nullptr);\n\t\tqglActiveTextureARB = [] (GLenum)  {};\n\t\tqglClientActiveTextureARB = [](GLenum) {};\n\t}\n\n\t// Create window.\n\tSetMode(r_mode->integer, (qboolean)r_fullscreen->integer);\n\n\tif (get_render_api() == RENDER_API_DX) {\n\t\tg_wv.hWnd_dx = create_main_window(glConfig.vidWidth, glConfig.vidHeight, (qboolean)r_fullscreen->integer);\n\t\tg_wv.hWnd = g_wv.hWnd_dx;\n\t\tSetForegroundWindow(g_wv.hWnd);\n\t\tSetFocus(g_wv.hWnd);\n\t\tWG_CheckHardwareGamma();\n\t} else {\n\t\tg_wv.hWnd_dx = create_twin_window(glConfig.vidWidth, glConfig.vidHeight, RENDER_API_DX);\n\t}\n}\n\nvoid dx_imp_shutdown() {\n\tri.Printf(PRINT_ALL, \"Shutting down DX12 subsystem\\n\");\n\n\tif (g_wv.hWnd_dx) {\n\t\tri.Printf(PRINT_ALL, \"...destroying DX12 window\\n\");\n\t\tDestroyWindow(g_wv.hWnd_dx);\n\n\t\tif (g_wv.hWnd == g_wv.hWnd_dx) {\n\t\t\tg_wv.hWnd = NULL;\n\t\t}\n\t\tg_wv.hWnd_dx = NULL;\n\t}\n\n\t// For DX12 mode we still have qgl pointers initialized with placeholder values.\n\t// Reset them the same way as we do in opengl mode.\n\tQGL_Shutdown();\n\n\tWG_RestoreGamma();\n\n\tmemset(&glConfig, 0, sizeof(glConfig));\n\tmemset(&glState, 0, sizeof(glState));\n\n\tif (log_fp) {\n\t\tfclose(log_fp);\n\t\tlog_fp = 0;\n\t}\n}\n\n/*\n===========================================================\n\nSMP acceleration\n\n===========================================================\n*/\n\nHANDLE\trenderCommandsEvent;\nHANDLE\trenderCompletedEvent;\nHANDLE\trenderActiveEvent;\n\nvoid (*glimpRenderThread)( void );\n\nvoid GLimp_RenderThreadWrapper( void ) {\n\tglimpRenderThread();\n\n\t// unbind the context before we die\n\tqwglMakeCurrent( gl_hdc, NULL );\n}\n\n/*\n=======================\nGLimp_SpawnRenderThread\n=======================\n*/\nHANDLE\trenderThreadHandle;\nint\t\trenderThreadId;\nqboolean GLimp_SpawnRenderThread( void (*function)( void ) ) {\n\n\trenderCommandsEvent = CreateEvent( NULL, TRUE, FALSE, NULL );\n\trenderCompletedEvent = CreateEvent( NULL, TRUE, FALSE, NULL );\n\trenderActiveEvent = CreateEvent( NULL, TRUE, FALSE, NULL );\n\n\tglimpRenderThread = function;\n\n\trenderThreadHandle = CreateThread(\n\t   NULL,\t// LPSECURITY_ATTRIBUTES lpsa,\n\t   0,\t\t// DWORD cbStack,\n\t   (LPTHREAD_START_ROUTINE)GLimp_RenderThreadWrapper,\t// LPTHREAD_START_ROUTINE lpStartAddr,\n\t   0,\t\t\t// LPVOID lpvThreadParm,\n\t   0,\t\t\t//   DWORD fdwCreate,\n\t   (LPDWORD)&renderThreadId );\n\n\tif ( !renderThreadHandle ) {\n\t\treturn qfalse;\n\t}\n\n\treturn qtrue;\n}\n\nstatic\tvoid\t*smpData;\nstatic\tint\t\twglErrors;\n\nvoid *GLimp_RendererSleep( void ) {\n\tvoid\t*data;\n\n\tif ( !qwglMakeCurrent( gl_hdc, NULL ) ) {\n\t\twglErrors++;\n\t}\n\n\tResetEvent( renderActiveEvent );\n\n\t// after this, the front end can exit GLimp_FrontEndSleep\n\tSetEvent( renderCompletedEvent );\n\n\tWaitForSingleObject( renderCommandsEvent, INFINITE );\n\n\tif ( !qwglMakeCurrent( gl_hdc, gl_hglrc ) ) {\n\t\twglErrors++;\n\t}\n\n\tResetEvent( renderCompletedEvent );\n\tResetEvent( renderCommandsEvent );\n\n\tdata = smpData;\n\n\t// after this, the main thread can exit GLimp_WakeRenderer\n\tSetEvent( renderActiveEvent );\n\n\treturn data;\n}\n\n\nvoid GLimp_FrontEndSleep( void ) {\n\tWaitForSingleObject( renderCompletedEvent, INFINITE );\n\n\tif ( !qwglMakeCurrent( gl_hdc, gl_hglrc ) ) {\n\t\twglErrors++;\n\t}\n}\n\n\nvoid GLimp_WakeRenderer( void *data ) {\n\tsmpData = data;\n\n\tif ( !qwglMakeCurrent( gl_hdc, NULL ) ) {\n\t\twglErrors++;\n\t}\n\n\t// after this, the renderer can continue through GLimp_RendererSleep\n\tSetEvent( renderCommandsEvent );\n\n\tWaitForSingleObject( renderActiveEvent, INFINITE );\n}\n\n"
  },
  {
    "path": "src/engine/platform/win_input.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n// win_input.c -- win32 mouse and joystick code\n// 02/21/97 JCB Added extended DirectInput code to support external controllers.\n\n#include \"../client/client.h\"\n#include \"win_local.h\"\n\n\ntypedef struct {\n\tint\t\t\toldButtonState;\n\n\tqboolean\tmouseActive;\n\tqboolean\tmouseInitialized;\n} WinMouseVars_t;\n\nstatic WinMouseVars_t s_wmv;\n\nstatic int\twindow_center_x, window_center_y;\n\ncvar_t\t*in_mouse;\ncvar_t  *in_logitechbug;\n\nqboolean\tin_appactive;\n\n/*\n============================================================\n\nWIN32 MOUSE CONTROL\n\n============================================================\n*/\n\n/*\n================\nIN_InitWin32Mouse\n================\n*/\nvoid IN_InitWin32Mouse( void ) \n{\n}\n\n/*\n================\nIN_ShutdownWin32Mouse\n================\n*/\nvoid IN_ShutdownWin32Mouse( void ) {\n}\n\n/*\n================\nIN_ActivateWin32Mouse\n================\n*/\nvoid IN_ActivateWin32Mouse( void ) {\n\tint\t\t\twidth, height;\n\tRECT\t\twindow_rect;\n\n\twidth = GetSystemMetrics (SM_CXSCREEN);\n\theight = GetSystemMetrics (SM_CYSCREEN);\n\n\tGetWindowRect ( g_wv.hWnd, &window_rect);\n\tif (window_rect.left < 0)\n\t\twindow_rect.left = 0;\n\tif (window_rect.top < 0)\n\t\twindow_rect.top = 0;\n\tif (window_rect.right >= width)\n\t\twindow_rect.right = width-1;\n\tif (window_rect.bottom >= height-1)\n\t\twindow_rect.bottom = height-1;\n\twindow_center_x = (window_rect.right + window_rect.left)/2;\n\twindow_center_y = (window_rect.top + window_rect.bottom)/2;\n\n\tSetCursorPos (window_center_x, window_center_y);\n\n\tSetCapture ( g_wv.hWnd );\n\tClipCursor (&window_rect);\n\twhile (ShowCursor (FALSE) >= 0)\n\t\t;\n}\n\n/*\n================\nIN_DeactivateWin32Mouse\n================\n*/\nvoid IN_DeactivateWin32Mouse( void ) \n{\n\tClipCursor (NULL);\n\tReleaseCapture ();\n\twhile (ShowCursor (TRUE) < 0)\n\t\t;\n}\n\n/*\n================\nIN_Win32Mouse\n================\n*/\nvoid IN_Win32Mouse( int *mx, int *my ) {\n\tPOINT\t\tcurrent_pos;\n\n\t// find mouse movement\n\tGetCursorPos (&current_pos);\n\n\t// force the mouse to the center, so there's room to move\n\tSetCursorPos (window_center_x, window_center_y);\n\n\t*mx = current_pos.x - window_center_x;\n\t*my = current_pos.y - window_center_y;\n}\n\n/*\n============================================================\n\n  MOUSE CONTROL\n\n============================================================\n*/\n\n/*\n===========\nIN_ActivateMouse\n\nCalled when the window gains focus or changes in some way\n===========\n*/\nvoid IN_ActivateMouse( void ) \n{\n\tif (!s_wmv.mouseInitialized ) {\n\t\treturn;\n\t}\n\tif ( !in_mouse->integer ) \n\t{\n\t\ts_wmv.mouseActive = qfalse;\n\t\treturn;\n\t}\n\tif ( s_wmv.mouseActive ) \n\t{\n\t\treturn;\n\t}\n\n\ts_wmv.mouseActive = qtrue;\n\n\tIN_ActivateWin32Mouse();\n}\n\n\n/*\n===========\nIN_DeactivateMouse\n\nCalled when the window loses focus\n===========\n*/\nvoid IN_DeactivateMouse( void ) {\n\tif (!s_wmv.mouseInitialized ) {\n\t\treturn;\n\t}\n\tif (!s_wmv.mouseActive ) {\n\t\treturn;\n\t}\n\ts_wmv.mouseActive = qfalse;\n\n\tIN_DeactivateWin32Mouse();\n}\n\n\n\n/*\n===========\nIN_StartupMouse\n===========\n*/\nvoid IN_StartupMouse( void ) \n{\n\ts_wmv.mouseInitialized = qfalse;\n\n\tif ( in_mouse->integer == 0 ) {\n\t\tCom_Printf (\"Mouse control not active.\\n\");\n\t\treturn;\n\t}\n\n\ts_wmv.mouseInitialized = qtrue;\n\tIN_InitWin32Mouse();\n    Com_Printf (\"Win32 mouse input initialized.\\n\");\n}\n\n/*\n===========\nIN_MouseEvent\n===========\n*/\nvoid IN_MouseEvent (int mstate)\n{\n\tint\t\ti;\n\n\tif ( !s_wmv.mouseInitialized )\n\t\treturn;\n\n// perform button actions\n\tfor  (i = 0 ; i < 3 ; i++ )\n\t{\n\t\tif ( (mstate & (1<<i)) &&\n\t\t\t!(s_wmv.oldButtonState & (1<<i)) )\n\t\t{\n\t\t\tSys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_MOUSE1 + i, qtrue, 0, NULL );\n\t\t}\n\n\t\tif ( !(mstate & (1<<i)) &&\n\t\t\t(s_wmv.oldButtonState & (1<<i)) )\n\t\t{\n\t\t\tSys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_MOUSE1 + i, qfalse, 0, NULL );\n\t\t}\n\t}\t\n\n\ts_wmv.oldButtonState = mstate;\n}\n\n\n/*\n===========\nIN_MouseMove\n===========\n*/\nvoid IN_MouseMove ( void ) {\n\tint\t\tmx, my;\n\n    IN_Win32Mouse( &mx, &my );\n\n\tif ( !mx && !my ) {\n\t\treturn;\n\t}\n\n\tSys_QueEvent( 0, SE_MOUSE, mx, my, 0, NULL );\n}\n\n\n/*\n=========================================================================\n\n=========================================================================\n*/\n\n/*\n===========\nIN_Startup\n===========\n*/\nvoid IN_Startup( void ) {\n\tCom_Printf (\"\\n------- Input Initialization -------\\n\");\n\tIN_StartupMouse ();\n\tCom_Printf (\"------------------------------------\\n\");\n\n\tin_mouse->modified = qfalse;\n}\n\n/*\n===========\nIN_Shutdown\n===========\n*/\nvoid IN_Shutdown( void ) {\n\tIN_DeactivateMouse();\n}\n\n\n/*\n===========\nIN_Init\n===========\n*/\nvoid IN_Init( void ) {\n    in_mouse = Cvar_Get (\"in_mouse\", \"1\", CVAR_ARCHIVE|CVAR_LATCH);\n\tin_logitechbug  = Cvar_Get (\"in_logitechbug\", \"0\", CVAR_ARCHIVE);\n\n\tIN_Startup();\n}\n\n\n/*\n===========\nIN_Activate\n\nCalled when the main window gains or loses focus.\nThe window may have been destroyed and recreated\nbetween a deactivate and an activate.\n===========\n*/\nvoid IN_Activate (qboolean active) {\n\tin_appactive = active;\n\n\tif ( !active )\n\t{\n\t\tIN_DeactivateMouse();\n\t}\n}\n\n\n/*\n==================\nIN_Frame\n\nCalled every frame, even if not generating commands\n==================\n*/\nvoid IN_Frame (void) {\n\tif ( !s_wmv.mouseInitialized ) {\n\t\treturn;\n\t}\n\n\tif ( cls.keyCatchers & KEYCATCH_CONSOLE ) {\n\t\t// temporarily deactivate if not in the game and\n\t\t// running on the desktop\n\t\t// voodoo always counts as full screen\n\t\tif (Cvar_VariableValue (\"r_fullscreen\") == 0 )\t{\n\t\t\tIN_DeactivateMouse ();\n\t\t\treturn;\n\t\t}\n\t}\n\n\tif ( !in_appactive ) {\n\t\tIN_DeactivateMouse ();\n\t\treturn;\n\t}\n\n\tIN_ActivateMouse();\n\n\t// post events to the system que\n\tIN_MouseMove();\n\n}\n"
  },
  {
    "path": "src/engine/platform/win_local.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n// win_local.h: Win32-specific Quake3 header file\n\n#pragma once\n\n#if defined (_MSC_VER) && (_MSC_VER >= 1200)\n#pragma warning(disable : 4201)\n#pragma warning( push )\n#endif\n#include <windows.h>\n#if defined (_MSC_VER) && (_MSC_VER >= 1200)\n#pragma warning( pop )\n#endif\n\n#define\tDIRECTSOUND_VERSION\t0x0300\n\n#include <dsound.h>\n#include <winsock.h>\n#include <wsipx.h>\n\nvoid\tIN_MouseEvent (int mstate);\n\nvoid Sys_QueEvent( int time, sysEventType_t type, int value, int value2, int ptrLength, void *ptr );\n\nvoid\tSys_CreateConsole( void );\nvoid\tSys_DestroyConsole( void );\n\nchar\t*Sys_ConsoleInput (void);\n\nqboolean\tSys_GetPacket ( netadr_t *net_from, msg_t *net_message );\n\n// Input subsystem\n\nvoid\tIN_Init (void);\nvoid\tIN_Shutdown (void);\n\nvoid\tIN_Activate (qboolean active);\nvoid\tIN_Frame (void);\n\n// window procedure\nLONG WINAPI MainWndProc (\n    HWND    hWnd,\n    UINT    uMsg,\n    WPARAM  wParam,\n    LPARAM  lParam);\n\nvoid Conbuf_AppendText( const char *msg );\n\nvoid SNDDMA_Activate( void );\nint  SNDDMA_InitDS ();\n\ntypedef struct\n{\n\t\n\tHINSTANCE\t\treflib_library;\t\t// Handle to refresh DLL \n\tqboolean\t\treflib_active;\n\n\tHWND\t\t\thWnd; // main window, refers to one of the hWnd_XXX listed below\n\n    HWND            hWnd_opengl;\n    HWND            hWnd_vulkan;\n\tHWND\t\t\thWnd_dx;\n\n\tHINSTANCE\t\thInstance;\n\tqboolean\t\tactiveApp;\n\tqboolean\t\tisMinimized;\n\tOSVERSIONINFO\tosversion;\n\n\t// when we get a windows message, we store the time off so keyboard processing\n\t// can know the exact time of an event\n\tunsigned\t\tsysMsgTime;\n} WinVars_t;\n\nextern WinVars_t\tg_wv;\n"
  },
  {
    "path": "src/engine/platform/win_main.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n// win_main.c\n\n#include \"../client/client.h\"\n#include \"../qcommon/qcommon.h\"\n#include \"win_local.h\"\n#include \"resource.h\"\n#include <errno.h>\n#include <float.h>\n#include <fcntl.h>\n#include <stdio.h>\n#include <direct.h>\n#include <io.h>\n#include <conio.h>\n\n#define\tCD_BASEDIR\t\"quake3\"\n#define\tCD_EXE\t\t\"quake3.exe\"\n#define\tCD_BASEDIR_LINUX\t\"bin\\\\x86\\\\glibc-2.1\"\n#define\tCD_EXE_LINUX \"quake3\"\n#define MEM_THRESHOLD 96*1024*1024\n\nstatic char\t\tsys_cmdline[MAX_STRING_CHARS];\n\n// define this to use alternate spanking method\n// I found out that the regular way doesn't work on my box for some reason\n// see the associated spank.sh script\n#define ALT_SPANK\n#ifdef ALT_SPANK\n#include <stdio.h>\n#include <sys\\stat.h>\n\nint fh = 0;\n\nvoid Spk_Open(char *name)\n{\n  fh = open( name, O_TRUNC | O_CREAT | O_WRONLY, S_IREAD | S_IWRITE );\n};\n\nvoid Spk_Close()\n{\n  if (!fh)\n    return;\n\n  close( fh );\n  fh = 0;\n}\n\nvoid Spk_Printf (const char *text, ...)\n{\n  va_list argptr;\n  char buf[32768];\n\n  if (!fh)\n    return;\n\n  va_start (argptr,text);\n  vsprintf (buf, text, argptr);\n  write(fh, buf, (int)strlen(buf));\n  _commit(fh);\n  va_end (argptr);\n\n};\n#endif\n\n/*\n==================\nSys_LowPhysicalMemory()\n==================\n*/\n\nqboolean Sys_LowPhysicalMemory() {\n\tMEMORYSTATUS stat;\n  GlobalMemoryStatus (&stat);\n\treturn (stat.dwTotalPhys <= MEM_THRESHOLD) ? qtrue : qfalse;\n}\n\n/*\n==================\nSys_BeginProfiling\n==================\n*/\nvoid Sys_BeginProfiling( void ) {\n\t// this is just used on the mac build\n}\n\n/*\n=============\nSys_Error\n\nShow the early console as an error dialog\n=============\n*/\nvoid QDECL Sys_Error( const char *error, ... ) {\n\tva_list\t\targptr;\n\tchar\t\ttext[4096];\n    MSG        msg;\n\n\tva_start (argptr, error);\n\tvsprintf (text, error, argptr);\n\tva_end (argptr);\n\n\tConbuf_AppendText( text );\n\tConbuf_AppendText( \"\\n\" );\n\n\tSys_SetErrorText( text );\n\tSys_ShowConsole( 1, qtrue );\n\n\ttimeEndPeriod( 1 );\n\n\tIN_Shutdown();\n\n\t// wait for the user to quit\n\twhile ( 1 ) {\n\t\tif (!GetMessage (&msg, NULL, 0, 0))\n\t\t\tCom_Quit_f ();\n\t\tTranslateMessage (&msg);\n      \tDispatchMessage (&msg);\n\t}\n\n\tSys_DestroyConsole();\n\n\texit (1);\n}\n\n/*\n==============\nSys_Quit\n==============\n*/\nvoid Sys_Quit( void ) {\n\ttimeEndPeriod( 1 );\n\tIN_Shutdown();\n\tSys_DestroyConsole();\n\n\texit (0);\n}\n\n/*\n==============\nSys_Print\n==============\n*/\nvoid Sys_Print( const char *msg ) {\n\tConbuf_AppendText( msg );\n}\n\n\n/*\n==============\nSys_Mkdir\n==============\n*/\nvoid Sys_Mkdir( const char *path ) {\n\t_mkdir (path);\n}\n\n/*\n==============\nSys_Cwd\n==============\n*/\nchar *Sys_Cwd( void ) {\n\tstatic char cwd[MAX_OSPATH];\n\n\t_getcwd( cwd, sizeof( cwd ) - 1 );\n\tcwd[MAX_OSPATH-1] = 0;\n\n\treturn cwd;\n}\n\n/*\n==============\nSys_DefaultCDPath\n==============\n*/\nchar *Sys_DefaultCDPath( void ) {\n\treturn \"\";\n}\n\n/*\n==============\nSys_DefaultBasePath\n==============\n*/\nchar *Sys_DefaultBasePath( void ) {\n\treturn Sys_Cwd();\n}\n\n/*\n==============================================================\n\nDIRECTORY SCANNING\n\n==============================================================\n*/\n\n#define\tMAX_FOUND_FILES\t0x1000\n\nvoid Sys_ListFilteredFiles( const char *basedir, char *subdirs, char *filter, char **list, int *numfiles ) {\n\tchar\t\tsearch[MAX_OSPATH], newsubdirs[MAX_OSPATH];\n\tchar\t\tfilename[MAX_OSPATH];\n\tint\t\t\tfindhandle;\n\tstruct _finddata_t findinfo;\n\n\tif ( *numfiles >= MAX_FOUND_FILES - 1 ) {\n\t\treturn;\n\t}\n\n\tif (strlen(subdirs)) {\n\t\tCom_sprintf( search, sizeof(search), \"%s\\\\%s\\\\*\", basedir, subdirs );\n\t}\n\telse {\n\t\tCom_sprintf( search, sizeof(search), \"%s\\\\*\", basedir );\n\t}\n\n\tfindhandle = _findfirst (search, &findinfo);\n\tif (findhandle == -1) {\n\t\treturn;\n\t}\n\n\tdo {\n\t\tif (findinfo.attrib & _A_SUBDIR) {\n\t\t\tif (Q_stricmp(findinfo.name, \".\") && Q_stricmp(findinfo.name, \"..\")) {\n\t\t\t\tif (strlen(subdirs)) {\n\t\t\t\t\tCom_sprintf( newsubdirs, sizeof(newsubdirs), \"%s\\\\%s\", subdirs, findinfo.name);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tCom_sprintf( newsubdirs, sizeof(newsubdirs), \"%s\", findinfo.name);\n\t\t\t\t}\n\t\t\t\tSys_ListFilteredFiles( basedir, newsubdirs, filter, list, numfiles );\n\t\t\t}\n\t\t}\n\t\tif ( *numfiles >= MAX_FOUND_FILES - 1 ) {\n\t\t\tbreak;\n\t\t}\n\t\tCom_sprintf( filename, sizeof(filename), \"%s\\\\%s\", subdirs, findinfo.name );\n\t\tif (!Com_FilterPath( filter, filename, qfalse ))\n\t\t\tcontinue;\n\t\tlist[ *numfiles ] = CopyString( filename );\n\t\t(*numfiles)++;\n\t} while ( _findnext (findhandle, &findinfo) != -1 );\n\n\t_findclose (findhandle);\n}\n\nstatic qboolean strgtr(const char *s0, const char *s1) {\n\tint l0, l1, i;\n\n\tl0 = (int)strlen(s0);\n\tl1 = (int)strlen(s1);\n\n\tif (l1<l0) {\n\t\tl0 = l1;\n\t}\n\n\tfor(i=0;i<l0;i++) {\n\t\tif (s1[i] > s0[i]) {\n\t\t\treturn qtrue;\n\t\t}\n\t\tif (s1[i] < s0[i]) {\n\t\t\treturn qfalse;\n\t\t}\n\t}\n\treturn qfalse;\n}\n\nchar **Sys_ListFiles( const char *directory, const char *extension, char *filter, int *numfiles, qboolean wantsubs ) {\n\tchar\t\tsearch[MAX_OSPATH];\n\tint\t\t\tnfiles;\n\tchar\t\t**listCopy;\n\tchar\t\t*list[MAX_FOUND_FILES];\n\tstruct _finddata_t findinfo;\n\tintptr_t  findhandle;\n\tint\t\t\tflag;\n\tint\t\t\ti;\n\n\tif (filter) {\n\n\t\tnfiles = 0;\n\t\tSys_ListFilteredFiles( directory, \"\", filter, list, &nfiles );\n\n\t\tlist[ nfiles ] = 0;\n\t\t*numfiles = nfiles;\n\n\t\tif (!nfiles)\n\t\t\treturn NULL;\n\n\t\tlistCopy = (char**) Z_Malloc( ( nfiles + 1 ) * sizeof( *listCopy ) );\n\t\tfor ( i = 0 ; i < nfiles ; i++ ) {\n\t\t\tlistCopy[i] = list[i];\n\t\t}\n\t\tlistCopy[i] = NULL;\n\n\t\treturn listCopy;\n\t}\n\n\tif ( !extension) {\n\t\textension = \"\";\n\t}\n\n\t// passing a slash as extension will find directories\n\tif ( extension[0] == '/' && extension[1] == 0 ) {\n\t\textension = \"\";\n\t\tflag = 0;\n\t} else {\n\t\tflag = _A_SUBDIR;\n\t}\n\n\tCom_sprintf( search, sizeof(search), \"%s\\\\*%s\", directory, extension );\n\n\t// search\n\tnfiles = 0;\n\n\tfindhandle = _findfirst (search, &findinfo);\n\tif (findhandle == -1) {\n\t\t*numfiles = 0;\n\t\treturn NULL;\n\t}\n\n\tdo {\n\t\tif ( (!wantsubs && flag ^ ( findinfo.attrib & _A_SUBDIR )) || (wantsubs && findinfo.attrib & _A_SUBDIR) ) {\n\t\t\tif ( nfiles == MAX_FOUND_FILES - 1 ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tlist[ nfiles ] = CopyString( findinfo.name );\n\t\t\tnfiles++;\n\t\t}\n\t} while ( _findnext (findhandle, &findinfo) != -1 );\n\n\tlist[ nfiles ] = 0;\n\n\t_findclose (findhandle);\n\n\t// return a copy of the list\n\t*numfiles = nfiles;\n\n\tif ( !nfiles ) {\n\t\treturn NULL;\n\t}\n\n\tlistCopy = (char**) Z_Malloc( ( nfiles + 1 ) * sizeof( *listCopy ) );\n\tfor ( i = 0 ; i < nfiles ; i++ ) {\n\t\tlistCopy[i] = list[i];\n\t}\n\tlistCopy[i] = NULL;\n\n\tdo {\n\t\tflag = 0;\n\t\tfor(i=1; i<nfiles; i++) {\n\t\t\tif (strgtr(listCopy[i-1], listCopy[i])) {\n\t\t\t\tchar *temp = listCopy[i];\n\t\t\t\tlistCopy[i] = listCopy[i-1];\n\t\t\t\tlistCopy[i-1] = temp;\n\t\t\t\tflag = 1;\n\t\t\t}\n\t\t}\n\t} while(flag);\n\n\treturn listCopy;\n}\n\nvoid\tSys_FreeFileList( char **list ) {\n\tint\t\ti;\n\n\tif ( !list ) {\n\t\treturn;\n\t}\n\n\tfor ( i = 0 ; list[i] ; i++ ) {\n\t\tZ_Free( list[i] );\n\t}\n\n\tZ_Free( list );\n}\n\n//========================================================\n\n\n/*\n================\nSys_ScanForCD\n\nSearch all the drives to see if there is a valid CD to grab\nthe cddir from\n================\n*/\nqboolean Sys_ScanForCD( void ) {\n\tstatic char\tcddir[MAX_OSPATH];\n\tchar\t\tdrive[4];\n\tFILE\t\t*f;\n\tchar\t\ttest[MAX_OSPATH];\n#if 0\n\t// don't override a cdpath on the command line\n\tif ( strstr( sys_cmdline, \"cdpath\" ) ) {\n\t\treturn;\n\t}\n#endif\n\n\tdrive[0] = 'c';\n\tdrive[1] = ':';\n\tdrive[2] = '\\\\';\n\tdrive[3] = 0;\n\n\t// scan the drives\n\tfor ( drive[0] = 'c' ; drive[0] <= 'z' ; drive[0]++ ) {\n\t\tif ( GetDriveType (drive) != DRIVE_CDROM ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tsprintf (cddir, \"%s%s\", drive, CD_BASEDIR);\n\t\tsprintf (test, \"%s\\\\%s\", cddir, CD_EXE);\n\t\tf = fopen( test, \"r\" );\n\t\tif ( f ) {\n\t\t\tfclose (f);\n\t\t\treturn qtrue;\n    } else {\n      sprintf(cddir, \"%s%s\", drive, CD_BASEDIR_LINUX);\n      sprintf(test, \"%s\\\\%s\", cddir, CD_EXE_LINUX);\n  \t\tf = fopen( test, \"r\" );\n\t  \tif ( f ) {\n\t\t  \tfclose (f);\n\t\t\t  return qtrue;\n      }\n    }\n\t}\n\n\treturn qfalse;\n}\n\n/*\n================\nSys_CheckCD\n\nReturn true if the proper CD is in the drive\n================\n*/\nqboolean\tSys_CheckCD( void ) {\n  // FIXME: mission pack\n  return qtrue;\n\t//return Sys_ScanForCD();\n}\n\n\n/*\n================\nSys_GetClipboardData\n\n================\n*/\nchar *Sys_GetClipboardData( void ) {\n\tchar *data = NULL;\n\tchar *cliptext;\n\n\tif ( OpenClipboard( NULL ) != 0 ) {\n\t\tHANDLE hClipboardData;\n\n\t\tif ( ( hClipboardData = GetClipboardData( CF_TEXT ) ) != 0 ) {\n\t\t\tif ( ( cliptext = (char*) GlobalLock( hClipboardData ) ) != 0 ) {\n\t\t\t\tdata = (char*) Z_Malloc( GlobalSize( hClipboardData ) + 1 );\n\t\t\t\tQ_strncpyz( data, cliptext, GlobalSize( hClipboardData ) );\n\t\t\t\tGlobalUnlock( hClipboardData );\n\t\t\t\t\n\t\t\t\tstrtok( data, \"\\n\\r\\b\" );\n\t\t\t}\n\t\t}\n\t\tCloseClipboard();\n\t}\n\treturn data;\n}\n\n\n/*\n========================================================================\n\nLOAD/UNLOAD DLL\n\n========================================================================\n*/\n\n/*\n=================\nSys_UnloadDll\n\n=================\n*/\nvoid Sys_UnloadDll( void *dllHandle ) {\n\tif ( !dllHandle ) {\n\t\treturn;\n\t}\n\tif ( !FreeLibrary( (HMODULE) dllHandle ) ) {\n\t\tCom_Error (ERR_FATAL, \"Sys_UnloadDll FreeLibrary failed\");\n\t}\n}\n\n/*\n=================\nSys_LoadDll\n\nUsed to load a development dll instead of a virtual machine\n\nTTimo: added some verbosity in debug\n=================\n*/\nextern char\t\t*FS_BuildOSPath( const char *base, const char *game, const char *qpath );\n\n// fqpath param added 7/20/02 by T.Ray - Sys_LoadDll is only called in vm.c at this time\n// fqpath will be empty if dll not loaded, otherwise will hold fully qualified path of dll module loaded\n// fqpath buffersize must be at least MAX_QPATH+1 bytes long\nvoid * QDECL Sys_LoadDll( const char *name, char *fqpath , intptr_t (QDECL **entryPoint)(int, ...),\n\t\t\t\t  intptr_t (QDECL *systemcalls)(intptr_t, ...) ) {\n\tstatic int\tlastWarning = 0;\n\tHINSTANCE\tlibHandle;\n\tvoid\t(QDECL *dllEntry)( intptr_t (QDECL *syscallptr)(intptr_t, ...) );\n\tchar\t*basepath;\n\tchar\t*cdpath;\n\tchar\t*gamedir;\n\tchar\t*fn;\n#ifdef NDEBUG\n\tint\t\ttimestamp;\n  int   ret;\n#endif\n\tchar\tfilename[MAX_QPATH];\n\n\t*fqpath = 0 ;\t\t// added 7/20/02 by T.Ray\n\n\tCom_sprintf( filename, sizeof( filename ), \"%s.dll\", name );\n\n#ifdef NDEBUG\n\ttimestamp = Sys_Milliseconds();\n\tif( ((timestamp - lastWarning) > (5 * 60000)) && !Cvar_VariableIntegerValue( \"dedicated\" )\n\t\t&& !Cvar_VariableIntegerValue( \"com_blindlyLoadDLLs\" ) ) {\n\t\tif (FS_FileExists(filename)) {\n\t\t\tlastWarning = timestamp;\n\t\t\tret = MessageBoxEx( NULL, \"You are about to load a .DLL executable that\\n\"\n\t\t\t\t  \"has not been verified for use with Quake III Arena.\\n\"\n\t\t\t\t  \"This type of file can compromise the security of\\n\"\n\t\t\t\t  \"your computer.\\n\\n\"\n\t\t\t\t  \"Select 'OK' if you choose to load it anyway.\",\n\t\t\t\t  \"Security Warning\", MB_OKCANCEL | MB_ICONEXCLAMATION | MB_DEFBUTTON2 | MB_TOPMOST | MB_SETFOREGROUND,\n\t\t\t\t  MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ) );\n\t\t\tif( ret != IDOK ) {\n\t\t\t\treturn NULL;\n\t\t\t}\n\t\t}\n\t}\n#endif\n\n#ifndef NDEBUG\n\tlibHandle = LoadLibrary( filename );\n  if (libHandle)\n    Com_Printf(\"LoadLibrary '%s' ok\\n\", filename);\n  else\n    Com_Printf(\"LoadLibrary '%s' failed\\n\", filename);\n\tif ( !libHandle ) {\n#endif\n\tbasepath = Cvar_VariableString( \"fs_basepath\" );\n\tcdpath = Cvar_VariableString( \"fs_cdpath\" );\n\tgamedir = Cvar_VariableString( \"fs_game\" );\n\n\tfn = FS_BuildOSPath( basepath, gamedir, filename );\n\tlibHandle = LoadLibrary( fn );\n#ifndef NDEBUG\n  if (libHandle)\n    Com_Printf(\"LoadLibrary '%s' ok\\n\", fn);\n  else\n    Com_Printf(\"LoadLibrary '%s' failed\\n\", fn);\n#endif\n\n\tif ( !libHandle ) {\n\t\tif( cdpath[0] ) {\n\t\t\tfn = FS_BuildOSPath( cdpath, gamedir, filename );\n\t\t\tlibHandle = LoadLibrary( fn );\n#ifndef NDEBUG\n      if (libHandle)\n        Com_Printf(\"LoadLibrary '%s' ok\\n\", fn);\n      else\n        Com_Printf(\"LoadLibrary '%s' failed\\n\", fn);\n#endif\n\t\t}\n\n\t\tif ( !libHandle ) {\n\t\t\treturn NULL;\n\t\t}\n\t}\n#ifndef NDEBUG\n\t}\n#endif\n\n\tdllEntry = ( void (QDECL *)( intptr_t (QDECL *)( intptr_t, ... ) ) )GetProcAddress( libHandle, \"dllEntry\" ); \n\t*entryPoint = (intptr_t (QDECL *)(int,...))GetProcAddress( libHandle, \"vmMain\" );\n\tif ( !*entryPoint || !dllEntry ) {\n\t\tFreeLibrary( libHandle );\n\t\treturn NULL;\n\t}\n\tdllEntry( systemcalls );\n\n\tif ( libHandle ) Q_strncpyz ( fqpath , filename , MAX_QPATH ) ;\t\t// added 7/20/02 by T.Ray\n\treturn libHandle;\n}\n\n\n/*\n========================================================================\n\nBACKGROUND FILE STREAMING\n\n========================================================================\n*/\n\n#if 1\n\nvoid Sys_InitStreamThread( void ) {\n}\n\nvoid Sys_ShutdownStreamThread( void ) {\n}\n\nvoid Sys_BeginStreamedFile( fileHandle_t f, int readAhead ) {\n}\n\nvoid Sys_EndStreamedFile( fileHandle_t f ) {\n}\n\nint Sys_StreamedRead( void *buffer, int size, int count, fileHandle_t f ) {\n   return FS_Read( buffer, size * count, f );\n}\n\nvoid Sys_StreamSeek( fileHandle_t f, int offset, int origin ) {\n   FS_Seek( f, offset, origin );\n}\n\n\n#else\n\ntypedef struct {\n\tfileHandle_t\tfile;\n\tbyte\t*buffer;\n\tqboolean\teof;\n\tqboolean\tactive;\n\tint\t\tbufferSize;\n\tint\t\tstreamPosition;\t// next byte to be returned by Sys_StreamRead\n\tint\t\tthreadPosition;\t// next byte to be read from file\n} streamsIO_t;\n\ntypedef struct {\n\tHANDLE\t\t\t\tthreadHandle;\n\tint\t\t\t\t\tthreadId;\n\tCRITICAL_SECTION\tcrit;\n\tstreamsIO_t\t\t\tsIO[MAX_FILE_HANDLES];\n} streamState_t;\n\nstreamState_t\tstream;\n\n/*\n===============\nSys_StreamThread\n\nA thread will be sitting in this loop forever\n================\n*/\nvoid Sys_StreamThread( void ) {\n\tint\t\tbuffer;\n\tint\t\tcount;\n\tint\t\treadCount;\n\tint\t\tbufferPoint;\n\tint\t\tr, i;\n\n\twhile (1) {\n\t\tSleep( 10 );\n//\t\tEnterCriticalSection (&stream.crit);\n\n\t\tfor (i=1;i<MAX_FILE_HANDLES;i++) {\n\t\t\t// if there is any space left in the buffer, fill it up\n\t\t\tif ( stream.sIO[i].active  && !stream.sIO[i].eof ) {\n\t\t\t\tcount = stream.sIO[i].bufferSize - (stream.sIO[i].threadPosition - stream.sIO[i].streamPosition);\n\t\t\t\tif ( !count ) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tbufferPoint = stream.sIO[i].threadPosition % stream.sIO[i].bufferSize;\n\t\t\t\tbuffer = stream.sIO[i].bufferSize - bufferPoint;\n\t\t\t\treadCount = buffer < count ? buffer : count;\n\n\t\t\t\tr = FS_Read( stream.sIO[i].buffer + bufferPoint, readCount, stream.sIO[i].file );\n\t\t\t\tstream.sIO[i].threadPosition += r;\n\n\t\t\t\tif ( r != readCount ) {\n\t\t\t\t\tstream.sIO[i].eof = qtrue;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n//\t\tLeaveCriticalSection (&stream.crit);\n\t}\n}\n\n/*\n===============\nSys_InitStreamThread\n\n================\n*/\nvoid Sys_InitStreamThread( void ) {\n\tint i;\n\n\tInitializeCriticalSection ( &stream.crit );\n\n\t// don't leave the critical section until there is a\n\t// valid file to stream, which will cause the StreamThread\n\t// to sleep without any overhead\n//\tEnterCriticalSection( &stream.crit );\n\n\tstream.threadHandle = CreateThread(\n\t   NULL,\t// LPSECURITY_ATTRIBUTES lpsa,\n\t   0,\t\t// DWORD cbStack,\n\t   (LPTHREAD_START_ROUTINE)Sys_StreamThread,\t// LPTHREAD_START_ROUTINE lpStartAddr,\n\t   0,\t\t\t// LPVOID lpvThreadParm,\n\t   0,\t\t\t//   DWORD fdwCreate,\n\t   &stream.threadId);\n\tfor(i=0;i<MAX_FILE_HANDLES;i++) {\n\t\tstream.sIO[i].active = qfalse;\n\t}\n}\n\n/*\n===============\nSys_ShutdownStreamThread\n\n================\n*/\nvoid Sys_ShutdownStreamThread( void ) {\n}\n\n\n/*\n===============\nSys_BeginStreamedFile\n\n================\n*/\nvoid Sys_BeginStreamedFile( fileHandle_t f, int readAhead ) {\n\tif ( stream.sIO[f].file ) {\n\t\tSys_EndStreamedFile( stream.sIO[f].file );\n\t}\n\n\tstream.sIO[f].file = f;\n\tstream.sIO[f].buffer = Z_Malloc( readAhead );\n\tstream.sIO[f].bufferSize = readAhead;\n\tstream.sIO[f].streamPosition = 0;\n\tstream.sIO[f].threadPosition = 0;\n\tstream.sIO[f].eof = qfalse;\n\tstream.sIO[f].active = qtrue;\n\n\t// let the thread start running\n//\tLeaveCriticalSection( &stream.crit );\n}\n\n/*\n===============\nSys_EndStreamedFile\n\n================\n*/\nvoid Sys_EndStreamedFile( fileHandle_t f ) {\n\tif ( f != stream.sIO[f].file ) {\n\t\tCom_Error( ERR_FATAL, \"Sys_EndStreamedFile: wrong file\");\n\t}\n\t// don't leave critical section until another stream is started\n\tEnterCriticalSection( &stream.crit );\n\n\tstream.sIO[f].file = 0;\n\tstream.sIO[f].active = qfalse;\n\n\tZ_Free( stream.sIO[f].buffer );\n\n\tLeaveCriticalSection( &stream.crit );\n}\n\n\n/*\n===============\nSys_StreamedRead\n\n================\n*/\nint Sys_StreamedRead( void *buffer, int size, int count, fileHandle_t f ) {\n\tint\t\tavailable;\n\tint\t\tremaining;\n\tint\t\tsleepCount;\n\tint\t\tcopy;\n\tint\t\tbufferCount;\n\tint\t\tbufferPoint;\n\tbyte\t*dest;\n\n\tif (stream.sIO[f].active == qfalse) {\n\t\tCom_Error( ERR_FATAL, \"Streamed read with non-streaming file\" );\n\t}\n\n\tdest = (byte *)buffer;\n\tremaining = size * count;\n\n\tif ( remaining <= 0 ) {\n\t\tCom_Error( ERR_FATAL, \"Streamed read with non-positive size\" );\n\t}\n\n\tsleepCount = 0;\n\twhile ( remaining > 0 ) {\n\t\tavailable = stream.sIO[f].threadPosition - stream.sIO[f].streamPosition;\n\t\tif ( !available ) {\n\t\t\tif ( stream.sIO[f].eof ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( sleepCount == 1 ) {\n\t\t\t\tCom_DPrintf( \"Sys_StreamedRead: waiting\\n\" );\n\t\t\t}\n\t\t\tif ( ++sleepCount > 100 ) {\n\t\t\t\tCom_Error( ERR_FATAL, \"Sys_StreamedRead: thread has died\");\n\t\t\t}\n\t\t\tSleep( 10 );\n\t\t\tcontinue;\n\t\t}\n\n\t\tEnterCriticalSection( &stream.crit );\n\n\t\tbufferPoint = stream.sIO[f].streamPosition % stream.sIO[f].bufferSize;\n\t\tbufferCount = stream.sIO[f].bufferSize - bufferPoint;\n\n\t\tcopy = available < bufferCount ? available : bufferCount;\n\t\tif ( copy > remaining ) {\n\t\t\tcopy = remaining;\n\t\t}\n\t\tmemcpy( dest, stream.sIO[f].buffer + bufferPoint, copy );\n\t\tstream.sIO[f].streamPosition += copy;\n\t\tdest += copy;\n\t\tremaining -= copy;\n\n\t\tLeaveCriticalSection( &stream.crit );\n\t}\n\n\treturn (count * size - remaining) / size;\n}\n\n/*\n===============\nSys_StreamSeek\n\n================\n*/\nvoid Sys_StreamSeek( fileHandle_t f, int offset, int origin ) {\n\n\t// halt the thread\n\tEnterCriticalSection( &stream.crit );\n\n\t// clear to that point\n\tFS_Seek( f, offset, origin );\n\tstream.sIO[f].streamPosition = 0;\n\tstream.sIO[f].threadPosition = 0;\n\tstream.sIO[f].eof = qfalse;\n\n\t// let the thread start running at the new position\n\tLeaveCriticalSection( &stream.crit );\n}\n\n#endif\n\n/*\n========================================================================\n\nEVENT LOOP\n\n========================================================================\n*/\n\n#define\tMAX_QUED_EVENTS\t\t256\n#define\tMASK_QUED_EVENTS\t( MAX_QUED_EVENTS - 1 )\n\nsysEvent_t\teventQue[MAX_QUED_EVENTS];\nint\t\t\teventHead, eventTail;\nbyte\t\tsys_packetReceived[MAX_MSGLEN];\n\n/*\n================\nSys_QueEvent\n\nA time of 0 will get the current time\nPtr should either be null, or point to a block of data that can\nbe freed by the game later.\n================\n*/\nvoid Sys_QueEvent( int time, sysEventType_t type, int value, int value2, int ptrLength, void *ptr ) {\n\tsysEvent_t\t*ev;\n\n\tev = &eventQue[ eventHead & MASK_QUED_EVENTS ];\n\tif ( eventHead - eventTail >= MAX_QUED_EVENTS ) {\n\t\tCom_Printf(\"Sys_QueEvent: overflow\\n\");\n\t\t// we are discarding an event, but don't leak memory\n\t\tif ( ev->evPtr ) {\n\t\t\tZ_Free( ev->evPtr );\n\t\t}\n\t\teventTail++;\n\t}\n\n\teventHead++;\n\n\tif ( time == 0 ) {\n\t\ttime = Sys_Milliseconds();\n\t}\n\n\tev->evTime = time;\n\tev->evType = type;\n\tev->evValue = value;\n\tev->evValue2 = value2;\n\tev->evPtrLength = ptrLength;\n\tev->evPtr = ptr;\n}\n\n/*\n================\nSys_GetEvent\n\n================\n*/\nsysEvent_t Sys_GetEvent( void ) {\n    MSG\t\t\tmsg;\n\tsysEvent_t\tev;\n\tchar\t\t*s;\n\tmsg_t\t\tnetmsg;\n\tnetadr_t\tadr;\n\n\t// return if we have data\n\tif ( eventHead > eventTail ) {\n\t\teventTail++;\n\t\treturn eventQue[ ( eventTail - 1 ) & MASK_QUED_EVENTS ];\n\t}\n\n\t// pump the message loop\n\twhile (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE)) {\n\t\tif ( !GetMessage (&msg, NULL, 0, 0) ) {\n\t\t\tCom_Quit_f();\n\t\t}\n\n\t\t// save the msg time, because wndprocs don't have access to the timestamp\n\t\tg_wv.sysMsgTime = msg.time;\n\n\t\tTranslateMessage (&msg);\n      \tDispatchMessage (&msg);\n\t}\n\n\t// check for console commands\n\ts = Sys_ConsoleInput();\n\tif ( s ) {\n\t\tchar\t*b;\n\t\tint\t\tlen;\n\n\t\tlen = (int)strlen( s ) + 1;\n\t\tb = (char*)Z_Malloc( len );\n\t\tQ_strncpyz( b, s, len-1 );\n\t\tSys_QueEvent( 0, SE_CONSOLE, 0, 0, len, b );\n\t}\n\n\t// check for network packets\n\tMSG_Init( &netmsg, sys_packetReceived, sizeof( sys_packetReceived ) );\n\tif ( Sys_GetPacket ( &adr, &netmsg ) ) {\n\t\tnetadr_t\t\t*buf;\n\t\tint\t\t\t\tlen;\n\n\t\t// copy out to a seperate buffer for qeueing\n\t\t// the readcount stepahead is for SOCKS support\n\t\tlen = sizeof( netadr_t ) + netmsg.cursize - netmsg.readcount;\n\t\tbuf = (netadr_t*) Z_Malloc( len );\n\t\t*buf = adr;\n\t\tmemcpy( buf+1, &netmsg.data[netmsg.readcount], netmsg.cursize - netmsg.readcount );\n\t\tSys_QueEvent( 0, SE_PACKET, 0, 0, len, buf );\n\t}\n\n\t// return if we have data\n\tif ( eventHead > eventTail ) {\n\t\teventTail++;\n\t\treturn eventQue[ ( eventTail - 1 ) & MASK_QUED_EVENTS ];\n\t}\n\n\t// create an empty event to return\n\n\tmemset( &ev, 0, sizeof( ev ) );\n\tev.evTime = timeGetTime();\n\n\treturn ev;\n}\n\n//================================================================\n\n/*\n=================\nSys_In_Restart_f\n\nRestart the input subsystem\n=================\n*/\nvoid Sys_In_Restart_f( void ) {\n\tIN_Shutdown();\n\tIN_Init();\n}\n\n\n/*\n=================\nSys_Net_Restart_f\n\nRestart the network subsystem\n=================\n*/\nvoid Sys_Net_Restart_f( void ) {\n\tNET_Restart();\n}\n\n\n/*\n================\nSys_Init\n\nCalled after the common systems (cvars, files, etc)\nare initialized\n================\n*/\n#define OSR2_BUILD_NUMBER 1111\n#define WIN98_BUILD_NUMBER 1998\n\nvoid Sys_Init( void ) {\n\tint cpuid;\n\n\t// make sure the timer is high precision, otherwise\n\t// NT gets 18ms resolution\n\ttimeBeginPeriod( 1 );\n\n\tCmd_AddCommand (\"in_restart\", Sys_In_Restart_f);\n\tCmd_AddCommand (\"net_restart\", Sys_Net_Restart_f);\n\n\tg_wv.osversion.dwOSVersionInfoSize = sizeof( g_wv.osversion );\n\n\tif (!GetVersionEx (&g_wv.osversion))\n\t\tSys_Error (\"Couldn't get OS info\");\n\n\tif (g_wv.osversion.dwMajorVersion < 4)\n\t\tSys_Error (\"Quake3 requires Windows version 4 or greater\");\n\tif (g_wv.osversion.dwPlatformId == VER_PLATFORM_WIN32s)\n\t\tSys_Error (\"Quake3 doesn't run on Win32s\");\n\n\tif ( g_wv.osversion.dwPlatformId == VER_PLATFORM_WIN32_NT )\n\t{\n\t\tCvar_Set( \"arch\", \"winnt\" );\n\t}\n\telse if ( g_wv.osversion.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS )\n\t{\n\t\tif ( LOWORD( g_wv.osversion.dwBuildNumber ) >= WIN98_BUILD_NUMBER )\n\t\t{\n\t\t\tCvar_Set( \"arch\", \"win98\" );\n\t\t}\n\t\telse if ( LOWORD( g_wv.osversion.dwBuildNumber ) >= OSR2_BUILD_NUMBER )\n\t\t{\n\t\t\tCvar_Set( \"arch\", \"win95 osr2.x\" );\n\t\t}\n\t\telse\n\t\t{\n\t\t\tCvar_Set( \"arch\", \"win95\" );\n\t\t}\n\t}\n\telse\n\t{\n\t\tCvar_Set( \"arch\", \"unknown Windows variant\" );\n\t}\n\n\t// save out a couple things in rom cvars for the renderer to access\n\tCvar_Get( \"win_wndproc\", va(\"%p\", MainWndProc), CVAR_ROM );\n\n\t//\n\t// figure out our CPU\n\t//\n\tCvar_Get( \"sys_cpustring\", \"detect\", 0 );\n\tif ( !Q_stricmp( Cvar_VariableString( \"sys_cpustring\"), \"detect\" ) )\n\t{\n\t\tCom_Printf( \"...detecting CPU, found \" );\n\n\t\tcpuid = Sys_GetProcessorId();\n\n\t\tswitch ( cpuid )\n\t\t{\n\t\tcase CPUID_GENERIC:\n\t\t\tCvar_Set( \"sys_cpustring\", \"generic\" );\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tCom_Error( ERR_FATAL, \"Unknown cpu type %d\\n\", cpuid );\n\t\t\tbreak;\n\t\t}\n\t}\n\telse\n\t{\n\t\tCom_Printf( \"...forcing CPU type to \" );\n\t\tif ( !Q_stricmp( Cvar_VariableString( \"sys_cpustring\" ), \"generic\" ) )\n\t\t{\n\t\t\tcpuid = CPUID_GENERIC;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tCom_Printf( \"WARNING: unknown sys_cpustring '%s'\\n\", Cvar_VariableString( \"sys_cpustring\" ) );\n\t\t\tcpuid = CPUID_GENERIC;\n\t\t}\n\t}\n\tCvar_SetValue( \"sys_cpuid\", cpuid );\n\tCom_Printf( \"%s\\n\", Cvar_VariableString( \"sys_cpustring\" ) );\n\n\tCvar_Set( \"username\", Sys_GetCurrentUser() );\n\n\tIN_Init();\t\t// FIXME: not in dedicated?\n}\n\n\n//=======================================================================\n\nint\ttotalMsec, countMsec;\n\n/*\n==================\nWinMain\n\n==================\n*/\nint WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {\n\tchar\t\tcwd[MAX_OSPATH];\n\tint\t\t\tstartTime, endTime;\n\n    // should never get a previous instance in Win32\n    if ( hPrevInstance ) {\n        return 0;\n\t}\n\n\tg_wv.hInstance = hInstance;\n\tQ_strncpyz( sys_cmdline, lpCmdLine, sizeof( sys_cmdline ) );\n\n\t// done before Com/Sys_Init since we need this for error output\n\tSys_CreateConsole();\n\n\t// no abort/retry/fail errors\n\tSetErrorMode( SEM_FAILCRITICALERRORS );\n\n\t// get the initial time base\n\tSys_Milliseconds();\n#if 0\n\t// if we find the CD, add a +set cddir xxx command line\n\tSys_ScanForCD();\n#endif\n\n\tSys_InitStreamThread();\n\n\tCom_Init( sys_cmdline );\n\tNET_Init();\n\n\t_getcwd (cwd, sizeof(cwd));\n\tCom_Printf(\"Working directory: %s\\n\", cwd);\n\n\t// hide the early console since we've reached the point where we\n\t// have a working graphics subsystems\n\tif ( !com_dedicated->integer && !com_viewlog->integer ) {\n\t\tSys_ShowConsole( 0, qfalse );\n\t}\n\n    // main game loop\n\twhile( 1 ) {\n\t\t// if not running as a game client, sleep a bit\n\t\tif ( g_wv.isMinimized || ( com_dedicated && com_dedicated->integer ) ) {\n\t\t\tSleep( 5 );\n\t\t}\n\n\t\t// set low precision every frame, because some system calls\n\t\t// reset it arbitrarily\n//\t\t_controlfp( _PC_24, _MCW_PC );\n//    _controlfp( -1, _MCW_EM  ); // no exceptions, even if some crappy\n                                // syscall turns them back on!\n\n\t\tstartTime = Sys_Milliseconds();\n\n\t\t// make sure mouse and joystick are only called once a frame\n\t\tIN_Frame();\n\n\t\t// run the game\n\t\tCom_Frame();\n\n\t\tendTime = Sys_Milliseconds();\n\t\ttotalMsec += endTime - startTime;\n\t\tcountMsec++;\n\t}\n\n\t// never gets here\n}\n\n\n"
  },
  {
    "path": "src/engine/platform/win_net.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n// net_wins.c\n\n#include \"../../game/q_shared.h\"\n#include \"../qcommon/qcommon.h\"\n#include \"win_local.h\"\n\nstatic WSADATA\twinsockdata;\nstatic qboolean\twinsockInitialized = qfalse;\nstatic qboolean usingSocks = qfalse;\nstatic qboolean networkingEnabled = qfalse;\n\nstatic cvar_t\t*net_noudp;\nstatic cvar_t\t*net_noipx;\n\nstatic cvar_t\t*net_socksEnabled;\nstatic cvar_t\t*net_socksServer;\nstatic cvar_t\t*net_socksPort;\nstatic cvar_t\t*net_socksUsername;\nstatic cvar_t\t*net_socksPassword;\nstatic struct sockaddr\tsocksRelayAddr;\n\nstatic SOCKET\tip_socket;\nstatic SOCKET\tsocks_socket;\nstatic SOCKET\tipx_socket;\n\n#define\tMAX_IPS\t\t16\nstatic\tint\t\tnumIP;\nstatic\tbyte\tlocalIP[MAX_IPS][4];\n\n//=============================================================================\n\n\n/*\n====================\nNET_ErrorString\n====================\n*/\nchar *NET_ErrorString( void ) {\n\tint\t\tcode;\n\n\tcode = WSAGetLastError();\n\tswitch( code ) {\n\tcase WSAEINTR: return \"WSAEINTR\";\n\tcase WSAEBADF: return \"WSAEBADF\";\n\tcase WSAEACCES: return \"WSAEACCES\";\n\tcase WSAEDISCON: return \"WSAEDISCON\";\n\tcase WSAEFAULT: return \"WSAEFAULT\";\n\tcase WSAEINVAL: return \"WSAEINVAL\";\n\tcase WSAEMFILE: return \"WSAEMFILE\";\n\tcase WSAEWOULDBLOCK: return \"WSAEWOULDBLOCK\";\n\tcase WSAEINPROGRESS: return \"WSAEINPROGRESS\";\n\tcase WSAEALREADY: return \"WSAEALREADY\";\n\tcase WSAENOTSOCK: return \"WSAENOTSOCK\";\n\tcase WSAEDESTADDRREQ: return \"WSAEDESTADDRREQ\";\n\tcase WSAEMSGSIZE: return \"WSAEMSGSIZE\";\n\tcase WSAEPROTOTYPE: return \"WSAEPROTOTYPE\";\n\tcase WSAENOPROTOOPT: return \"WSAENOPROTOOPT\";\n\tcase WSAEPROTONOSUPPORT: return \"WSAEPROTONOSUPPORT\";\n\tcase WSAESOCKTNOSUPPORT: return \"WSAESOCKTNOSUPPORT\";\n\tcase WSAEOPNOTSUPP: return \"WSAEOPNOTSUPP\";\n\tcase WSAEPFNOSUPPORT: return \"WSAEPFNOSUPPORT\";\n\tcase WSAEAFNOSUPPORT: return \"WSAEAFNOSUPPORT\";\n\tcase WSAEADDRINUSE: return \"WSAEADDRINUSE\";\n\tcase WSAEADDRNOTAVAIL: return \"WSAEADDRNOTAVAIL\";\n\tcase WSAENETDOWN: return \"WSAENETDOWN\";\n\tcase WSAENETUNREACH: return \"WSAENETUNREACH\";\n\tcase WSAENETRESET: return \"WSAENETRESET\";\n\tcase WSAECONNABORTED: return \"WSWSAECONNABORTEDAEINTR\";\n\tcase WSAECONNRESET: return \"WSAECONNRESET\";\n\tcase WSAENOBUFS: return \"WSAENOBUFS\";\n\tcase WSAEISCONN: return \"WSAEISCONN\";\n\tcase WSAENOTCONN: return \"WSAENOTCONN\";\n\tcase WSAESHUTDOWN: return \"WSAESHUTDOWN\";\n\tcase WSAETOOMANYREFS: return \"WSAETOOMANYREFS\";\n\tcase WSAETIMEDOUT: return \"WSAETIMEDOUT\";\n\tcase WSAECONNREFUSED: return \"WSAECONNREFUSED\";\n\tcase WSAELOOP: return \"WSAELOOP\";\n\tcase WSAENAMETOOLONG: return \"WSAENAMETOOLONG\";\n\tcase WSAEHOSTDOWN: return \"WSAEHOSTDOWN\";\n\tcase WSASYSNOTREADY: return \"WSASYSNOTREADY\";\n\tcase WSAVERNOTSUPPORTED: return \"WSAVERNOTSUPPORTED\";\n\tcase WSANOTINITIALISED: return \"WSANOTINITIALISED\";\n\tcase WSAHOST_NOT_FOUND: return \"WSAHOST_NOT_FOUND\";\n\tcase WSATRY_AGAIN: return \"WSATRY_AGAIN\";\n\tcase WSANO_RECOVERY: return \"WSANO_RECOVERY\";\n\tcase WSANO_DATA: return \"WSANO_DATA\";\n\tdefault: return \"NO ERROR\";\n\t}\n}\n\nvoid NetadrToSockadr( netadr_t *a, struct sockaddr *s ) {\n\tmemset( s, 0, sizeof(*s) );\n\n\tif( a->type == NA_BROADCAST ) {\n\t\t((struct sockaddr_in *)s)->sin_family = AF_INET;\n\t\t((struct sockaddr_in *)s)->sin_port = a->port;\n\t\t((struct sockaddr_in *)s)->sin_addr.s_addr = INADDR_BROADCAST;\n\t}\n\telse if( a->type == NA_IP ) {\n\t\t((struct sockaddr_in *)s)->sin_family = AF_INET;\n\t\t((struct sockaddr_in *)s)->sin_addr.s_addr = *(int *)&a->ip;\n\t\t((struct sockaddr_in *)s)->sin_port = a->port;\n\t}\n\telse if( a->type == NA_IPX ) {\n\t\t((struct sockaddr_ipx *)s)->sa_family = AF_IPX;\n\t\tmemcpy( ((struct sockaddr_ipx *)s)->sa_netnum, &a->ipx[0], 4 );\n\t\tmemcpy( ((struct sockaddr_ipx *)s)->sa_nodenum, &a->ipx[4], 6 );\n\t\t((struct sockaddr_ipx *)s)->sa_socket = a->port;\n\t}\n\telse if( a->type == NA_BROADCAST_IPX ) {\n\t\t((struct sockaddr_ipx *)s)->sa_family = AF_IPX;\n\t\tmemset( ((struct sockaddr_ipx *)s)->sa_netnum, 0, 4 );\n\t\tmemset( ((struct sockaddr_ipx *)s)->sa_nodenum, 0xff, 6 );\n\t\t((struct sockaddr_ipx *)s)->sa_socket = a->port;\n\t}\n}\n\n\nvoid SockadrToNetadr( struct sockaddr *s, netadr_t *a ) {\n\tif (s->sa_family == AF_INET) {\n\t\ta->type = NA_IP;\n\t\t*(int *)&a->ip = ((struct sockaddr_in *)s)->sin_addr.s_addr;\n\t\ta->port = ((struct sockaddr_in *)s)->sin_port;\n\t}\n\telse if( s->sa_family == AF_IPX ) {\n\t\ta->type = NA_IPX;\n\t\tmemcpy( &a->ipx[0], ((struct sockaddr_ipx *)s)->sa_netnum, 4 );\n\t\tmemcpy( &a->ipx[4], ((struct sockaddr_ipx *)s)->sa_nodenum, 6 );\n\t\ta->port = ((struct sockaddr_ipx *)s)->sa_socket;\n\t}\n}\n\n\n/*\n=============\nSys_StringToAdr\n\nidnewt\n192.246.40.70\n12121212.121212121212\n=============\n*/\n#define DO(src,dest)\t\\\n\tcopy[0] = s[src];\t\\\n\tcopy[1] = s[src + 1];\t\\\n\tsscanf (copy, \"%x\", &val);\t\\\n\t((struct sockaddr_ipx *)sadr)->dest = val\n\nqboolean Sys_StringToSockaddr( const char *s, struct sockaddr *sadr ) {\n\tstruct hostent\t*h;\n\tint\t\tval;\n\tchar\tcopy[MAX_STRING_CHARS];\n\t\n\tmemset( sadr, 0, sizeof( *sadr ) );\n\n\t// check for an IPX address\n\tif( ( (int)strlen( s ) == 21 ) && ( s[8] == '.' ) ) {\n\t\t((struct sockaddr_ipx *)sadr)->sa_family = AF_IPX;\n\t\t((struct sockaddr_ipx *)sadr)->sa_socket = 0;\n\t\tcopy[2] = 0;\n\t\tDO(0, sa_netnum[0]);\n\t\tDO(2, sa_netnum[1]);\n\t\tDO(4, sa_netnum[2]);\n\t\tDO(6, sa_netnum[3]);\n\t\tDO(9, sa_nodenum[0]);\n\t\tDO(11, sa_nodenum[1]);\n\t\tDO(13, sa_nodenum[2]);\n\t\tDO(15, sa_nodenum[3]);\n\t\tDO(17, sa_nodenum[4]);\n\t\tDO(19, sa_nodenum[5]);\n\t}\n\telse {\n\t\t((struct sockaddr_in *)sadr)->sin_family = AF_INET;\n\t\t((struct sockaddr_in *)sadr)->sin_port = 0;\n\n\t\tif( s[0] >= '0' && s[0] <= '9' ) {\n\t\t\t*(int *)&((struct sockaddr_in *)sadr)->sin_addr = inet_addr(s);\n\t\t} else {\n\t\t\tif( ( h = gethostbyname( s ) ) == 0 ) {\n\t\t\t\treturn (qboolean) 0;\n\t\t\t}\n\t\t\t*(int *)&((struct sockaddr_in *)sadr)->sin_addr = *(int *)h->h_addr_list[0];\n\t\t}\n\t}\n\t\n\treturn qtrue;\n}\n\n#undef DO\n\n/*\n=============\nSys_StringToAdr\n\nidnewt\n192.246.40.70\n=============\n*/\nqboolean Sys_StringToAdr( const char *s, netadr_t *a ) {\n\tstruct sockaddr sadr;\n\t\n\tif ( !Sys_StringToSockaddr( s, &sadr ) ) {\n\t\treturn qfalse;\n\t}\n\t\n\tSockadrToNetadr( &sadr, a );\n\treturn qtrue;\n}\n\n//=============================================================================\n\n/*\n==================\nSys_GetPacket\n\nNever called by the game logic, just the system event queing\n==================\n*/\nint\trecvfromCount;\n\nqboolean Sys_GetPacket( netadr_t *net_from, msg_t *net_message ) {\n\tint \tret;\n\tstruct sockaddr from;\n\tint\t\tfromlen;\n\tint\t\tnet_socket;\n\tint\t\tprotocol;\n\tint\t\terr;\n\n\tfor( protocol = 0 ; protocol < 2 ; protocol++ )\t{\n\t\tif( protocol == 0 ) {\n\t\t\tnet_socket = ip_socket;\n\t\t}\n\t\telse {\n\t\t\tnet_socket = ipx_socket;\n\t\t}\n\n\t\tif( !net_socket ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tfromlen = sizeof(from);\n\t\trecvfromCount++;\t\t// performance check\n\t\tret = recvfrom( net_socket, (char*) net_message->data, net_message->maxsize, 0, (struct sockaddr *)&from, &fromlen );\n\t\tif (ret == SOCKET_ERROR)\n\t\t{\n\t\t\terr = WSAGetLastError();\n\n\t\t\tif( err == WSAEWOULDBLOCK || err == WSAECONNRESET ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tCom_Printf( \"NET_GetPacket: %s\\n\", NET_ErrorString() );\n\t\t\tcontinue;\n\t\t}\n\n\t\tif ( net_socket == ip_socket ) {\n\t\t\tmemset( ((struct sockaddr_in *)&from)->sin_zero, 0, 8 );\n\t\t}\n\n\t\tif ( usingSocks && net_socket == ip_socket && memcmp( &from, &socksRelayAddr, fromlen ) == 0 ) {\n\t\t\tif ( ret < 10 || net_message->data[0] != 0 || net_message->data[1] != 0 || net_message->data[2] != 0 || net_message->data[3] != 1 ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tnet_from->type = NA_IP;\n\t\t\tnet_from->ip[0] = net_message->data[4];\n\t\t\tnet_from->ip[1] = net_message->data[5];\n\t\t\tnet_from->ip[2] = net_message->data[6];\n\t\t\tnet_from->ip[3] = net_message->data[7];\n\t\t\tnet_from->port = *(short *)&net_message->data[8];\n\t\t\tnet_message->readcount = 10;\n\t\t}\n\t\telse {\n\t\t\tSockadrToNetadr( &from, net_from );\n\t\t\tnet_message->readcount = 0;\n\t\t}\n\n\t\tif( ret == net_message->maxsize ) {\n\t\t\tCom_Printf( \"Oversize packet from %s\\n\", NET_AdrToString (*net_from) );\n\t\t\tcontinue;\n\t\t}\n\n\t\tnet_message->cursize = ret;\n\t\treturn qtrue;\n\t}\n\n\treturn qfalse;\n}\n\n//=============================================================================\n\nstatic char socksBuf[4096];\n\n/*\n==================\nSys_SendPacket\n==================\n*/\nvoid Sys_SendPacket( int length, const void *data, netadr_t to ) {\n\tint\t\t\t\tret;\n\tstruct sockaddr\taddr;\n\tSOCKET\t\t\tnet_socket;\n\n\tif( to.type == NA_BROADCAST ) {\n\t\tnet_socket = ip_socket;\n\t}\n\telse if( to.type == NA_IP ) {\n\t\tnet_socket = ip_socket;\n\t}\n\telse if( to.type == NA_IPX ) {\n\t\tnet_socket = ipx_socket;\n\t}\n\telse if( to.type == NA_BROADCAST_IPX ) {\n\t\tnet_socket = ipx_socket;\n\t}\n\telse {\n\t\tCom_Error( ERR_FATAL, \"Sys_SendPacket: bad address type\" );\n\t\treturn;\n\t}\n\n\tif( !net_socket ) {\n\t\treturn;\n\t}\n\n\tNetadrToSockadr( &to, &addr );\n\n\tif( usingSocks && to.type == NA_IP ) {\n\t\tsocksBuf[0] = 0;\t// reserved\n\t\tsocksBuf[1] = 0;\n\t\tsocksBuf[2] = 0;\t// fragment (not fragmented)\n\t\tsocksBuf[3] = 1;\t// address type: IPV4\n\t\t*(int *)&socksBuf[4] = ((struct sockaddr_in *)&addr)->sin_addr.s_addr;\n\t\t*(short *)&socksBuf[8] = ((struct sockaddr_in *)&addr)->sin_port;\n\t\tmemcpy( &socksBuf[10], data, length );\n\t\tret = sendto( net_socket, socksBuf, length+10, 0, &socksRelayAddr, sizeof(socksRelayAddr) );\n\t}\n\telse {\n\t\tret = sendto( net_socket, (const char*) data, length, 0, &addr, sizeof(addr) );\n\t}\n\tif( ret == SOCKET_ERROR ) {\n\t\tint err = WSAGetLastError();\n\n\t\t// wouldblock is silent\n\t\tif( err == WSAEWOULDBLOCK ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// some PPP links do not allow broadcasts and return an error\n\t\tif( ( err == WSAEADDRNOTAVAIL ) && ( ( to.type == NA_BROADCAST ) || ( to.type == NA_BROADCAST_IPX ) ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tCom_Printf( \"NET_SendPacket: %s\\n\", NET_ErrorString() );\n\t}\n}\n\n\n//=============================================================================\n\n/*\n==================\nSys_IsLANAddress\n\nLAN clients will have their rate var ignored\n==================\n*/\nqboolean Sys_IsLANAddress( netadr_t adr ) {\n\tint\t\ti;\n\n\tif( adr.type == NA_LOOPBACK ) {\n\t\treturn qtrue;\n\t}\n\n\tif( adr.type == NA_IPX ) {\n\t\treturn qtrue;\n\t}\n\n\tif( adr.type != NA_IP ) {\n\t\treturn qfalse;\n\t}\n\n\t// choose which comparison to use based on the class of the address being tested\n\t// any local adresses of a different class than the address being tested will fail based on the first byte\n\n\tif( adr.ip[0] == 127 && adr.ip[1] == 0 && adr.ip[2] == 0 && adr.ip[3] == 1 ) {\n\t\treturn qtrue;\n\t}\n\n\t// Class A\n\tif( (adr.ip[0] & 0x80) == 0x00 ) {\n\t\tfor ( i = 0 ; i < numIP ; i++ ) {\n\t\t\tif( adr.ip[0] == localIP[i][0] ) {\n\t\t\t\treturn qtrue;\n\t\t\t}\n\t\t}\n\t\t// the RFC1918 class a block will pass the above test\n\t\treturn qfalse;\n\t}\n\n\t// Class B\n\tif( (adr.ip[0] & 0xc0) == 0x80 ) {\n\t\tfor ( i = 0 ; i < numIP ; i++ ) {\n\t\t\tif( adr.ip[0] == localIP[i][0] && adr.ip[1] == localIP[i][1] ) {\n\t\t\t\treturn qtrue;\n\t\t\t}\n\t\t\t// also check against the RFC1918 class b blocks\n\t\t\tif( adr.ip[0] == 172 && localIP[i][0] == 172 && (adr.ip[1] & 0xf0) == 16 && (localIP[i][1] & 0xf0) == 16 ) {\n\t\t\t\treturn qtrue;\n\t\t\t}\n\t\t}\n\t\treturn qfalse;\n\t}\n\n\t// Class C\n\tfor ( i = 0 ; i < numIP ; i++ ) {\n\t\tif( adr.ip[0] == localIP[i][0] && adr.ip[1] == localIP[i][1] && adr.ip[2] == localIP[i][2] ) {\n\t\t\treturn qtrue;\n\t\t}\n\t\t// also check against the RFC1918 class c blocks\n\t\tif( adr.ip[0] == 192 && localIP[i][0] == 192 && adr.ip[1] == 168 && localIP[i][1] == 168 ) {\n\t\t\treturn qtrue;\n\t\t}\n\t}\n\treturn qfalse;\n}\n\n/*\n==================\nSys_ShowIP\n==================\n*/\nvoid Sys_ShowIP(void) {\n\tint i;\n\n\tfor (i = 0; i < numIP; i++) {\n\t\tCom_Printf( \"IP: %i.%i.%i.%i\\n\", localIP[i][0], localIP[i][1], localIP[i][2], localIP[i][3] );\n\t}\n}\n\n\n//=============================================================================\n\n\n/*\n====================\nNET_IPSocket\n====================\n*/\nint NET_IPSocket( char *net_interface, int port ) {\n\tSOCKET\t\t\t\tnewsocket;\n\tstruct sockaddr_in\taddress;\n\tu_long\t\t\t_true = qtrue;\n\tint\t\t\t\t\ti = 1;\n\tint\t\t\t\t\terr;\n\n\tif( net_interface ) {\n\t\tCom_Printf( \"Opening IP socket: %s:%i\\n\", net_interface, port );\n\t}\n\telse {\n\t\tCom_Printf( \"Opening IP socket: localhost:%i\\n\", port );\n\t}\n\n\tif( ( newsocket = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ) ) == INVALID_SOCKET ) {\n\t\terr = WSAGetLastError();\n\t\tif( err != WSAEAFNOSUPPORT ) {\n\t\t\tCom_Printf( \"WARNING: UDP_OpenSocket: socket: %s\\n\", NET_ErrorString() );\n\t\t}\n\t\treturn 0;\n\t}\n\n\t// make it non-blocking\n\tif( ioctlsocket( newsocket, FIONBIO, &(u_long&)_true ) == SOCKET_ERROR ) {\n\t\tCom_Printf( \"WARNING: UDP_OpenSocket: ioctl FIONBIO: %s\\n\", NET_ErrorString() );\n\t\treturn 0;\n\t}\n\n\t// make it broadcast capable\n\tif( setsockopt( newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i) ) == SOCKET_ERROR ) {\n\t\tCom_Printf( \"WARNING: UDP_OpenSocket: setsockopt SO_BROADCAST: %s\\n\", NET_ErrorString() );\n\t\treturn 0;\n\t}\n\n\tif( !net_interface || !net_interface[0] || !Q_stricmp(net_interface, \"localhost\") ) {\n\t\taddress.sin_addr.s_addr = INADDR_ANY;\n\t}\n\telse {\n\t\tSys_StringToSockaddr( net_interface, (struct sockaddr *)&address );\n\t}\n\n\tif( port == PORT_ANY ) {\n\t\taddress.sin_port = 0;\n\t}\n\telse {\n\t\taddress.sin_port = htons( (short)port );\n\t}\n\n\taddress.sin_family = AF_INET;\n\n\tif( bind( newsocket, (const sockaddr*) (void *)&address, sizeof(address) ) == SOCKET_ERROR ) {\n\t\tCom_Printf( \"WARNING: UDP_OpenSocket: bind: %s\\n\", NET_ErrorString() );\n\t\tclosesocket( newsocket );\n\t\treturn 0;\n\t}\n\n\treturn newsocket;\n}\n\n\n/*\n====================\nNET_OpenSocks\n====================\n*/\nvoid NET_OpenSocks( int port ) {\n\tstruct sockaddr_in\taddress;\n\tint\t\t\t\t\terr;\n\tstruct hostent\t\t*h;\n\tint\t\t\t\t\tlen;\n\tqboolean\t\t\trfc1929;\n\tunsigned char\t\tbuf[64];\n\n\tusingSocks = qfalse;\n\n\tCom_Printf( \"Opening connection to SOCKS server.\\n\" );\n\n\tif ( ( socks_socket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ) ) == INVALID_SOCKET ) {\n\t\terr = WSAGetLastError();\n\t\tCom_Printf( \"WARNING: NET_OpenSocks: socket: %s\\n\", NET_ErrorString() );\n\t\treturn;\n\t}\n\n\th = gethostbyname( net_socksServer->string );\n\tif ( h == NULL ) {\n\t\terr = WSAGetLastError();\n\t\tCom_Printf( \"WARNING: NET_OpenSocks: gethostbyname: %s\\n\", NET_ErrorString() );\n\t\treturn;\n\t}\n\tif ( h->h_addrtype != AF_INET ) {\n\t\tCom_Printf( \"WARNING: NET_OpenSocks: gethostbyname: address type was not AF_INET\\n\" );\n\t\treturn;\n\t}\n\taddress.sin_family = AF_INET;\n\taddress.sin_addr.s_addr = *(int *)h->h_addr_list[0];\n\taddress.sin_port = htons( (short)net_socksPort->integer );\n\n\tif ( connect( socks_socket, (struct sockaddr *)&address, sizeof( address ) ) == SOCKET_ERROR ) {\n\t\terr = WSAGetLastError();\n\t\tCom_Printf( \"NET_OpenSocks: connect: %s\\n\", NET_ErrorString() );\n\t\treturn;\n\t}\n\n\t// send socks authentication handshake\n\tif ( *net_socksUsername->string || *net_socksPassword->string ) {\n\t\trfc1929 = qtrue;\n\t}\n\telse {\n\t\trfc1929 = qfalse;\n\t}\n\n\tbuf[0] = 5;\t\t// SOCKS version\n\t// method count\n\tif ( rfc1929 ) {\n\t\tbuf[1] = 2;\n\t\tlen = 4;\n\t}\n\telse {\n\t\tbuf[1] = 1;\n\t\tlen = 3;\n\t}\n\tbuf[2] = 0;\t\t// method #1 - method id #00: no authentication\n\tif ( rfc1929 ) {\n\t\tbuf[2] = 2;\t\t// method #2 - method id #02: username/password\n\t}\n\tif ( send( socks_socket, (const char*) buf, len, 0 ) == SOCKET_ERROR ) {\n\t\terr = WSAGetLastError();\n\t\tCom_Printf( \"NET_OpenSocks: send: %s\\n\", NET_ErrorString() );\n\t\treturn;\n\t}\n\n\t// get the response\n\tlen = recv( socks_socket, (char*) buf, 64, 0 );\n\tif ( len == SOCKET_ERROR ) {\n\t\terr = WSAGetLastError();\n\t\tCom_Printf( \"NET_OpenSocks: recv: %s\\n\", NET_ErrorString() );\n\t\treturn;\n\t}\n\tif ( len != 2 || buf[0] != 5 ) {\n\t\tCom_Printf( \"NET_OpenSocks: bad response\\n\" );\n\t\treturn;\n\t}\n\tswitch( buf[1] ) {\n\tcase 0:\t// no authentication\n\t\tbreak;\n\tcase 2: // username/password authentication\n\t\tbreak;\n\tdefault:\n\t\tCom_Printf( \"NET_OpenSocks: request denied\\n\" );\n\t\treturn;\n\t}\n\n\t// do username/password authentication if needed\n\tif ( buf[1] == 2 ) {\n\t\tint\t\tulen;\n\t\tint\t\tplen;\n\n\t\t// build the request\n\t\tulen = (int)strlen( net_socksUsername->string );\n\t\tplen = (int)strlen( net_socksPassword->string );\n\n\t\tbuf[0] = 1;\t\t// username/password authentication version\n\t\tbuf[1] = ulen;\n\t\tif ( ulen ) {\n\t\t\tmemcpy( &buf[2], net_socksUsername->string, ulen );\n\t\t}\n\t\tbuf[2 + ulen] = plen;\n\t\tif ( plen ) {\n\t\t\tmemcpy( &buf[3 + ulen], net_socksPassword->string, plen );\n\t\t}\n\n\t\t// send it\n\t\tif ( send( socks_socket, (const char*) buf, 3 + ulen + plen, 0 ) == SOCKET_ERROR ) {\n\t\t\terr = WSAGetLastError();\n\t\t\tCom_Printf( \"NET_OpenSocks: send: %s\\n\", NET_ErrorString() );\n\t\t\treturn;\n\t\t}\n\n\t\t// get the response\n\t\tlen = recv( socks_socket, (char*) buf, 64, 0 );\n\t\tif ( len == SOCKET_ERROR ) {\n\t\t\terr = WSAGetLastError();\n\t\t\tCom_Printf( \"NET_OpenSocks: recv: %s\\n\", NET_ErrorString() );\n\t\t\treturn;\n\t\t}\n\t\tif ( len != 2 || buf[0] != 1 ) {\n\t\t\tCom_Printf( \"NET_OpenSocks: bad response\\n\" );\n\t\t\treturn;\n\t\t}\n\t\tif ( buf[1] != 0 ) {\n\t\t\tCom_Printf( \"NET_OpenSocks: authentication failed\\n\" );\n\t\t\treturn;\n\t\t}\n\t}\n\n\t// send the UDP associate request\n\tbuf[0] = 5;\t\t// SOCKS version\n\tbuf[1] = 3;\t\t// command: UDP associate\n\tbuf[2] = 0;\t\t// reserved\n\tbuf[3] = 1;\t\t// address type: IPV4\n\t*(int *)&buf[4] = INADDR_ANY;\n\t*(short *)&buf[8] = htons( (short)port );\t\t// port\n\tif ( send( socks_socket, (const char*) buf, 10, 0 ) == SOCKET_ERROR ) {\n\t\terr = WSAGetLastError();\n\t\tCom_Printf( \"NET_OpenSocks: send: %s\\n\", NET_ErrorString() );\n\t\treturn;\n\t}\n\n\t// get the response\n\tlen = recv( socks_socket, (char*) buf, 64, 0 );\n\tif( len == SOCKET_ERROR ) {\n\t\terr = WSAGetLastError();\n\t\tCom_Printf( \"NET_OpenSocks: recv: %s\\n\", NET_ErrorString() );\n\t\treturn;\n\t}\n\tif( len < 2 || buf[0] != 5 ) {\n\t\tCom_Printf( \"NET_OpenSocks: bad response\\n\" );\n\t\treturn;\n\t}\n\t// check completion code\n\tif( buf[1] != 0 ) {\n\t\tCom_Printf( \"NET_OpenSocks: request denied: %i\\n\", buf[1] );\n\t\treturn;\n\t}\n\tif( buf[3] != 1 ) {\n\t\tCom_Printf( \"NET_OpenSocks: relay address is not IPV4: %i\\n\", buf[3] );\n\t\treturn;\n\t}\n\t((struct sockaddr_in *)&socksRelayAddr)->sin_family = AF_INET;\n\t((struct sockaddr_in *)&socksRelayAddr)->sin_addr.s_addr = *(int *)&buf[4];\n\t((struct sockaddr_in *)&socksRelayAddr)->sin_port = *(short *)&buf[8];\n\tmemset( ((struct sockaddr_in *)&socksRelayAddr)->sin_zero, 0, 8 );\n\n\tusingSocks = qtrue;\n}\n\n\n/*\n=====================\nNET_GetLocalAddress\n=====================\n*/\nvoid NET_GetLocalAddress( void ) {\n\tchar\t\t\t\thostname[256];\n\tstruct hostent\t\t*hostInfo;\n\tint\t\t\t\t\terror;\n\tchar\t\t\t\t*p;\n\tint\t\t\t\t\tip;\n\tint\t\t\t\t\tn;\n\n\tif( gethostname( hostname, 256 ) == SOCKET_ERROR ) {\n\t\terror = WSAGetLastError();\n\t\treturn;\n\t}\n\n\thostInfo = gethostbyname( hostname );\n\tif( !hostInfo ) {\n\t\terror = WSAGetLastError();\n\t\treturn;\n\t}\n\n\tCom_Printf( \"Hostname: %s\\n\", hostInfo->h_name );\n\tn = 0;\n\twhile( ( p = hostInfo->h_aliases[n++] ) != NULL ) {\n\t\tCom_Printf( \"Alias: %s\\n\", p );\n\t}\n\n\tif ( hostInfo->h_addrtype != AF_INET ) {\n\t\treturn;\n\t}\n\n\tnumIP = 0;\n\twhile( ( p = hostInfo->h_addr_list[numIP] ) != NULL && numIP < MAX_IPS ) {\n\t\tip = ntohl( *(int *)p );\n\t\tlocalIP[ numIP ][0] = p[0];\n\t\tlocalIP[ numIP ][1] = p[1];\n\t\tlocalIP[ numIP ][2] = p[2];\n\t\tlocalIP[ numIP ][3] = p[3];\n\t\tCom_Printf( \"IP: %i.%i.%i.%i\\n\", ( ip >> 24 ) & 0xff, ( ip >> 16 ) & 0xff, ( ip >> 8 ) & 0xff, ip & 0xff );\n\t\tnumIP++;\n\t}\n}\n\n/*\n====================\nNET_OpenIP\n====================\n*/\nvoid NET_OpenIP( void ) {\n\tcvar_t\t*ip;\n\tint\t\tport;\n\tint\t\ti;\n\n\tip = Cvar_Get( \"net_ip\", \"localhost\", CVAR_LATCH );\n\tport = Cvar_Get( \"net_port\", va( \"%i\", PORT_SERVER ), CVAR_LATCH )->integer;\n\n\t// automatically scan for a valid port, so multiple\n\t// dedicated servers can be started without requiring\n\t// a different net_port for each one\n\tfor( i = 0 ; i < 10 ; i++ ) {\n\t\tip_socket = NET_IPSocket( ip->string, port + i );\n\t\tif ( ip_socket ) {\n\t\t\tCvar_SetValue( \"net_port\", port + i );\n\t\t\tif ( net_socksEnabled->integer ) {\n\t\t\t\tNET_OpenSocks( port + i );\n\t\t\t}\n\t\t\tNET_GetLocalAddress();\n\t\t\treturn;\n\t\t}\n\t}\n\tCom_Printf( \"WARNING: Couldn't allocate IP port\\n\");\n}\n\n\n/*\n====================\nNET_IPXSocket\n====================\n*/\nint NET_IPXSocket( int port ) {\n\tSOCKET\t\t\t\tnewsocket;\n\tstruct sockaddr_ipx\taddress;\n\tint\t\t\t\t\t_true = 1;\n\tint\t\t\t\t\terr;\n\n\tif( ( newsocket = socket( AF_IPX, SOCK_DGRAM, NSPROTO_IPX ) ) == INVALID_SOCKET ) {\n\t\terr = WSAGetLastError();\n\t\tif (err != WSAEAFNOSUPPORT) {\n\t\t\tCom_Printf( \"WARNING: IPX_Socket: socket: %s\\n\", NET_ErrorString() );\n\t\t}\n\t\treturn 0;\n\t}\n\n\t// make it non-blocking\n\tif( ioctlsocket( newsocket, FIONBIO, &(u_long&)_true ) == SOCKET_ERROR ) {\n\t\tCom_Printf( \"WARNING: IPX_Socket: ioctl FIONBIO: %s\\n\", NET_ErrorString() );\n\t\treturn 0;\n\t}\n\n\t// make it broadcast capable\n\tif( setsockopt( newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&_true, sizeof( _true ) ) == SOCKET_ERROR ) {\n\t\tCom_Printf( \"WARNING: IPX_Socket: setsockopt SO_BROADCAST: %s\\n\", NET_ErrorString() );\n\t\treturn 0;\n\t}\n\n\taddress.sa_family = AF_IPX;\n\tmemset( address.sa_netnum, 0, 4 );\n\tmemset( address.sa_nodenum, 0, 6 );\n\tif( port == PORT_ANY ) {\n\t\taddress.sa_socket = 0;\n\t}\n\telse {\n\t\taddress.sa_socket = htons( (short)port );\n\t}\n\n\tif( bind( newsocket, (const sockaddr*) (void *)&address, sizeof(address) ) == SOCKET_ERROR ) {\n\t\tCom_Printf( \"WARNING: IPX_Socket: bind: %s\\n\", NET_ErrorString() );\n\t\tclosesocket( newsocket );\n\t\treturn 0;\n\t}\n\n\treturn newsocket;\n}\n\n\n/*\n====================\nNET_OpenIPX\n====================\n*/\nvoid NET_OpenIPX( void ) {\n\tint\t\tport;\n\n\tport = Cvar_Get( \"net_port\", va( \"%i\", PORT_SERVER ), CVAR_LATCH )->integer;\n\tipx_socket = NET_IPXSocket( port );\n}\n\n\n\n//===================================================================\n\n\n/*\n====================\nNET_GetCvars\n====================\n*/\nstatic qboolean NET_GetCvars( void ) {\n\tqboolean\tmodified;\n\n\tmodified = qfalse;\n\n\tif( net_noudp && net_noudp->modified ) {\n\t\tmodified = qtrue;\n\t}\n\tnet_noudp = Cvar_Get( \"net_noudp\", \"0\", CVAR_LATCH | CVAR_ARCHIVE );\n\n\tif( net_noipx && net_noipx->modified ) {\n\t\tmodified = qtrue;\n\t}\n\tnet_noipx = Cvar_Get( \"net_noipx\", \"0\", CVAR_LATCH | CVAR_ARCHIVE );\n\n\n\tif( net_socksEnabled && net_socksEnabled->modified ) {\n\t\tmodified = qtrue;\n\t}\n\tnet_socksEnabled = Cvar_Get( \"net_socksEnabled\", \"0\", CVAR_LATCH | CVAR_ARCHIVE );\n\n\tif( net_socksServer && net_socksServer->modified ) {\n\t\tmodified = qtrue;\n\t}\n\tnet_socksServer = Cvar_Get( \"net_socksServer\", \"\", CVAR_LATCH | CVAR_ARCHIVE );\n\n\tif( net_socksPort && net_socksPort->modified ) {\n\t\tmodified = qtrue;\n\t}\n\tnet_socksPort = Cvar_Get( \"net_socksPort\", \"1080\", CVAR_LATCH | CVAR_ARCHIVE );\n\n\tif( net_socksUsername && net_socksUsername->modified ) {\n\t\tmodified = qtrue;\n\t}\n\tnet_socksUsername = Cvar_Get( \"net_socksUsername\", \"\", CVAR_LATCH | CVAR_ARCHIVE );\n\n\tif( net_socksPassword && net_socksPassword->modified ) {\n\t\tmodified = qtrue;\n\t}\n\tnet_socksPassword = Cvar_Get( \"net_socksPassword\", \"\", CVAR_LATCH | CVAR_ARCHIVE );\n\n\n\treturn modified;\n}\n\n\n/*\n====================\nNET_Config\n====================\n*/\nvoid NET_Config( qboolean enableNetworking ) {\n\tqboolean\tmodified;\n\tqboolean\tstop;\n\tqboolean\tstart;\n\n\t// get any latched changes to cvars\n\tmodified = NET_GetCvars();\n\n\tif( net_noudp->integer && net_noipx->integer ) {\n\t\tenableNetworking = qfalse;\n\t}\n\n\t// if enable state is the same and no cvars were modified, we have nothing to do\n\tif( enableNetworking == networkingEnabled && !modified ) {\n\t\treturn;\n\t}\n\n\tif( enableNetworking == networkingEnabled ) {\n\t\tif( enableNetworking ) {\n\t\t\tstop = qtrue;\n\t\t\tstart = qtrue;\n\t\t}\n\t\telse {\n\t\t\tstop = qfalse;\n\t\t\tstart = qfalse;\n\t\t}\n\t}\n\telse {\n\t\tif( enableNetworking ) {\n\t\t\tstop = qfalse;\n\t\t\tstart = qtrue;\n\t\t}\n\t\telse {\n\t\t\tstop = qtrue;\n\t\t\tstart = qfalse;\n\t\t}\n\t\tnetworkingEnabled = enableNetworking;\n\t}\n\n\tif( stop ) {\n\t\tif ( ip_socket && ip_socket != INVALID_SOCKET ) {\n\t\t\tclosesocket( ip_socket );\n\t\t\tip_socket = 0;\n\t\t}\n\n\t\tif ( socks_socket && socks_socket != INVALID_SOCKET ) {\n\t\t\tclosesocket( socks_socket );\n\t\t\tsocks_socket = 0;\n\t\t}\n\n\t\tif ( ipx_socket && ipx_socket != INVALID_SOCKET ) {\n\t\t\tclosesocket( ipx_socket );\n\t\t\tipx_socket = 0;\n\t\t}\n\t}\n\n\tif( start ) {\n\t\tif (! net_noudp->integer ) {\n\t\t\tNET_OpenIP();\n\t\t}\n\t\tif (! net_noipx->integer ) {\n\t\t\tNET_OpenIPX();\n\t\t}\n\t}\n}\n\n\n/*\n====================\nNET_Init\n====================\n*/\nvoid NET_Init( void ) {\n\tint\t\tr;\n\n\tr = WSAStartup( MAKEWORD( 1, 1 ), &winsockdata );\n\tif( r ) {\n\t\tCom_Printf( \"WARNING: Winsock initialization failed, returned %d\\n\", r );\n\t\treturn;\n\t}\n\n\twinsockInitialized = qtrue;\n\tCom_Printf( \"Winsock Initialized\\n\" );\n\n\t// this is really just to get the cvars registered\n\tNET_GetCvars();\n\n\t//FIXME testing!\n\tNET_Config( qtrue );\n}\n\n\n/*\n====================\nNET_Shutdown\n====================\n*/\nvoid NET_Shutdown( void ) {\n\tif ( !winsockInitialized ) {\n\t\treturn;\n\t}\n\tNET_Config( qfalse );\n\tWSACleanup();\n\twinsockInitialized = qfalse;\n}\n\n\n/*\n====================\nNET_Sleep\n\nsleeps msec or until net socket is ready\n====================\n*/\nvoid NET_Sleep( int msec ) {\n}\n\n\n/*\n====================\nNET_Restart_f\n====================\n*/\nvoid NET_Restart( void ) {\n\tNET_Config( networkingEnabled );\n}\n"
  },
  {
    "path": "src/engine/platform/win_qgl.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n/*\n** QGL_WIN.C\n**\n** This file implements the operating system binding of GL to QGL function\n** pointers.  When doing a port of Quake3 you must implement the following\n** two functions:\n**\n** QGL_Init() - loads libraries, assigns function pointers, etc.\n** QGL_Shutdown() - unloads libraries, NULLs function pointers\n*/\n#include \"../renderer/tr_local.h\"\n\nextern FILE* log_fp;\n\nstatic HINSTANCE hinstOpenGL; // HINSTANCE for the OpenGL library\n\nvoid QGL_EnableLogging( qboolean enable );\n\nHGLRC ( WINAPI * qwglCreateContext)(HDC);\nBOOL  ( WINAPI * qwglDeleteContext)(HGLRC);\nPROC  ( WINAPI * qwglGetProcAddress)(LPCSTR);\nBOOL  ( WINAPI * qwglMakeCurrent)(HDC, HGLRC);\nint   ( WINAPI * qwglSwapIntervalEXT)( int interval );\n\nvoid ( APIENTRY * qglAlphaFunc )(GLenum func, GLclampf ref);\nvoid ( APIENTRY * qglBegin )(GLenum mode);\nvoid ( APIENTRY * qglBindTexture )(GLenum target, GLuint texture);\nvoid ( APIENTRY * qglBlendFunc )(GLenum sfactor, GLenum dfactor);\nvoid ( APIENTRY * qglClear )(GLbitfield mask);\nvoid ( APIENTRY * qglClearColor )(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);\nvoid ( APIENTRY * qglClipPlane )(GLenum plane, const GLdouble *equation);\nvoid ( APIENTRY * qglColor3f )(GLfloat red, GLfloat green, GLfloat blue);\nvoid ( APIENTRY * qglColorMask )(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);\nvoid ( APIENTRY * qglColorPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);\nvoid ( APIENTRY * qglCullFace )(GLenum mode);\nvoid ( APIENTRY * qglDeleteTextures )(GLsizei n, const GLuint *textures);\nvoid ( APIENTRY * qglDepthFunc )(GLenum func);\nvoid ( APIENTRY * qglDepthMask )(GLboolean flag);\nvoid ( APIENTRY * qglDepthRange )(GLclampd zNear, GLclampd zFar);\nvoid ( APIENTRY * qglDisable )(GLenum cap);\nvoid ( APIENTRY * qglDisableClientState )(GLenum array);\nvoid ( APIENTRY * qglDrawBuffer )(GLenum mode);\nvoid ( APIENTRY * qglDrawElements )(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices);\nvoid ( APIENTRY * qglEnable )(GLenum cap);\nvoid ( APIENTRY * qglEnableClientState )(GLenum array);\nvoid ( APIENTRY * qglEnd )(void);\nvoid ( APIENTRY * qglFinish )(void);\nGLenum ( APIENTRY * qglGetError )(void);\nvoid ( APIENTRY * qglGetIntegerv )(GLenum pname, GLint *params);\nconst GLubyte * ( APIENTRY * qglGetString )(GLenum name);\nvoid ( APIENTRY * qglLineWidth )(GLfloat width);\nvoid ( APIENTRY * qglLoadIdentity )(void);\nvoid ( APIENTRY * qglLoadMatrixf )(const GLfloat *m);\nvoid ( APIENTRY * qglMatrixMode )(GLenum mode);\nvoid ( APIENTRY * qglOrtho )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);\nvoid ( APIENTRY * qglPolygonMode )(GLenum face, GLenum mode);\nvoid ( APIENTRY * qglPolygonOffset )(GLfloat factor, GLfloat units);\nvoid ( APIENTRY * qglPopMatrix )(void);\nvoid ( APIENTRY * qglPushMatrix )(void);\nvoid ( APIENTRY * qglReadPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels);\nvoid ( APIENTRY * qglScissor )(GLint x, GLint y, GLsizei width, GLsizei height);\nvoid ( APIENTRY * qglStencilFunc )(GLenum func, GLint ref, GLuint mask);\nvoid ( APIENTRY * qglStencilOp )(GLenum fail, GLenum zfail, GLenum zpass);\nvoid ( APIENTRY * qglTexCoord2f )(GLfloat s, GLfloat t);\nvoid ( APIENTRY * qglTexCoord2fv )(const GLfloat *v);\nvoid ( APIENTRY * qglTexCoordPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);\nvoid ( APIENTRY * qglTexEnvf )(GLenum target, GLenum pname, GLfloat param);\nvoid ( APIENTRY * qglTexImage2D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);\nvoid ( APIENTRY * qglTexParameterf )(GLenum target, GLenum pname, GLfloat param);\nvoid ( APIENTRY * qglTexParameterfv )(GLenum target, GLenum pname, const GLfloat *params);\nvoid ( APIENTRY * qglTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);\nvoid ( APIENTRY * qglVertex2f )(GLfloat x, GLfloat y);\nvoid ( APIENTRY * qglVertex3f )(GLfloat x, GLfloat y, GLfloat z);\nvoid ( APIENTRY * qglVertex3fv )(const GLfloat *v);\nvoid ( APIENTRY * qglVertexPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);\nvoid ( APIENTRY * qglViewport )(GLint x, GLint y, GLsizei width, GLsizei height);\n\n\nstatic void ( APIENTRY * dllAlphaFunc )(GLenum func, GLclampf ref);\nstatic void ( APIENTRY * dllBegin )(GLenum mode);\nstatic void ( APIENTRY * dllBindTexture )(GLenum target, GLuint texture);\nstatic void ( APIENTRY * dllBlendFunc )(GLenum sfactor, GLenum dfactor);\nstatic void ( APIENTRY * dllClear )(GLbitfield mask);\nstatic void ( APIENTRY * dllClearColor )(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);\nstatic void ( APIENTRY * dllClipPlane )(GLenum plane, const GLdouble *equation);\nstatic void ( APIENTRY * dllColor3f )(GLfloat red, GLfloat green, GLfloat blue);\nstatic void ( APIENTRY * dllColorMask )(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);\nstatic void ( APIENTRY * dllColorPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);\nstatic void ( APIENTRY * dllCullFace )(GLenum mode);\nstatic void ( APIENTRY * dllDeleteTextures )(GLsizei n, const GLuint *textures);\nstatic void ( APIENTRY * dllDepthFunc )(GLenum func);\nstatic void ( APIENTRY * dllDepthMask )(GLboolean flag);\nstatic void ( APIENTRY * dllDepthRange )(GLclampd zNear, GLclampd zFar);\nstatic void ( APIENTRY * dllDisable )(GLenum cap);\nstatic void ( APIENTRY * dllDisableClientState )(GLenum array);\nstatic void ( APIENTRY * dllDrawBuffer )(GLenum mode);\nstatic void ( APIENTRY * dllDrawElements )(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices);\nstatic void ( APIENTRY * dllEnable )(GLenum cap);\nstatic void ( APIENTRY * dllEnableClientState )(GLenum array);\nstatic void ( APIENTRY * dllEnd )(void);\nstatic void ( APIENTRY * dllFinish )(void);\nGLenum ( APIENTRY * dllGetError )(void);\nstatic void ( APIENTRY * dllGetIntegerv )(GLenum pname, GLint *params);\nconst GLubyte * ( APIENTRY * dllGetString )(GLenum name);\nstatic void ( APIENTRY * dllLineWidth )(GLfloat width);\nstatic void ( APIENTRY * dllLoadIdentity )(void);\nstatic void ( APIENTRY * dllLoadMatrixf )(const GLfloat *m);\nstatic void ( APIENTRY * dllMatrixMode )(GLenum mode);\nstatic void ( APIENTRY * dllOrtho )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);\nstatic void ( APIENTRY * dllPolygonMode )(GLenum face, GLenum mode);\nstatic void ( APIENTRY * dllPolygonOffset )(GLfloat factor, GLfloat units);\nstatic void ( APIENTRY * dllPopMatrix )(void);\nstatic void ( APIENTRY * dllPushMatrix )(void);\nstatic void ( APIENTRY * dllReadPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels);\nstatic void ( APIENTRY * dllScissor )(GLint x, GLint y, GLsizei width, GLsizei height);\nstatic void ( APIENTRY * dllStencilFunc )(GLenum func, GLint ref, GLuint mask);\nstatic void ( APIENTRY * dllStencilOp )(GLenum fail, GLenum zfail, GLenum zpass);\nstatic void ( APIENTRY * dllTexCoord2f )(GLfloat s, GLfloat t);\nstatic void ( APIENTRY * dllTexCoord2fv )(const GLfloat *v);\nstatic void ( APIENTRY * dllTexCoordPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);\nstatic void ( APIENTRY * dllTexEnvf )(GLenum target, GLenum pname, GLfloat param);\nstatic void ( APIENTRY * dllTexImage2D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);\nstatic void ( APIENTRY * dllTexParameterf )(GLenum target, GLenum pname, GLfloat param);\nstatic void ( APIENTRY * dllTexParameterfv )(GLenum target, GLenum pname, const GLfloat *params);\nstatic void ( APIENTRY * dllTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);\nstatic void ( APIENTRY * dllVertex2f )(GLfloat x, GLfloat y);\nstatic void ( APIENTRY * dllVertex3f )(GLfloat x, GLfloat y, GLfloat z);\nstatic void ( APIENTRY * dllVertex3fv )(const GLfloat *v);\nstatic void ( APIENTRY * dllVertexPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);\nstatic void ( APIENTRY * dllViewport )(GLint x, GLint y, GLsizei width, GLsizei height);\n\n\n//\n// Placeholder functions to replace OpenGL calls when Vulkan renderer is active.\n//\nstatic HGLRC nowglCreateContext(HDC) { return NULL;}\nstatic BOOL  nowglDeleteContext(HGLRC) { return FALSE; }\nstatic PROC  nowglGetProcAddress(LPCSTR) { return NULL; }\nstatic BOOL  nowglMakeCurrent(HDC, HGLRC) { return FALSE; }\nstatic int   nowglSwapIntervalEXT( int interval ) { return -1; }\n\nstatic void noglActiveTextureARB ( GLenum texture ) {}\nstatic void noglClientActiveTextureARB ( GLenum texture ) {}\nstatic void noglLockArraysEXT (GLint, GLint) {}\nstatic void noglUnlockArraysEXT (void) {}\nstatic void noglAlphaFunc(GLenum func, GLclampf ref) {}\nstatic void noglBegin(GLenum mode) {}\nstatic void noglBindTexture(GLenum target, GLuint texture) {}\nstatic void noglBlendFunc(GLenum sfactor, GLenum dfactor) {}\nstatic void noglClear(GLbitfield mask) {}\nstatic void noglClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {}\nstatic void noglClipPlane(GLenum plane, const GLdouble *equation) {}\nstatic void noglColor3f(GLfloat red, GLfloat green, GLfloat blue) {}\nstatic void noglColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {}\nstatic void noglColorPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) {}\nstatic void noglCullFace(GLenum mode) {}\nstatic void noglDeleteTextures(GLsizei n, const GLuint *textures) {}\nstatic void noglDepthFunc(GLenum func) {}\nstatic void noglDepthMask(GLboolean flag) {}\nstatic void noglDepthRange(GLclampd zNear, GLclampd zFar) {}\nstatic void noglDisable(GLenum cap) {}\nstatic void noglDisableClientState(GLenum array) {}\nstatic void noglDrawBuffer(GLenum mode) {}\nstatic void noglDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) {}\nstatic void noglEnable(GLenum cap) {}\nstatic void noglEnableClientState(GLenum array) {}\nstatic void noglEnd(void) {}\nstatic void noglFinish(void) {}\nstatic GLenum noglGetError(void) { return GL_NO_ERROR; }\nstatic void noglGetIntegerv(GLenum pname, GLint *params) {}\nstatic const GLubyte* noglGetString(GLenum name) { static char* s = \"\"; return (GLubyte*)s;}\nstatic void noglLineWidth(GLfloat width) {}\nstatic void noglLoadIdentity(void) {}\nstatic void noglLoadMatrixf(const GLfloat *m) {}\nstatic void noglMatrixMode(GLenum mode) {}\nstatic void noglOrtho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar) {}\nstatic void noglPolygonMode(GLenum face, GLenum mode) {}\nstatic void noglPolygonOffset(GLfloat factor, GLfloat units) {}\nstatic void noglPopMatrix(void) {}\nstatic void noglPushMatrix(void) {}\nstatic void noglReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels) {}\nstatic void noglScissor(GLint x, GLint y, GLsizei width, GLsizei height) {}\nstatic void noglStencilFunc(GLenum func, GLint ref, GLuint mask) {}\nstatic void noglStencilOp(GLenum fail, GLenum zfail, GLenum zpass) {}\nstatic void noglTexCoord2f(GLfloat s, GLfloat t) {}\nstatic void noglTexCoord2fv(const GLfloat *v) {}\nstatic void noglTexCoordPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) {}\nstatic void noglTexEnvf(GLenum target, GLenum pname, GLfloat param) {}\nstatic void noglTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels) {}\nstatic void noglTexParameterf(GLenum target, GLenum pname, GLfloat param) {}\nstatic void noglTexParameterfv(GLenum target, GLenum pname, const GLfloat *params) {}\nstatic void noglTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels) {}\nstatic void noglVertex2f(GLfloat x, GLfloat y) {}\nstatic void noglVertex3f(GLfloat x, GLfloat y, GLfloat z) {}\nstatic void noglVertex3fv(const GLfloat *v) {}\nstatic void noglVertexPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) {}\nstatic void noglViewport(GLint x, GLint y, GLsizei width, GLsizei height) {}\n\n\nstatic const char * BooleanToString( GLboolean b )\n{\n\tif ( b == GL_FALSE )\n\t\treturn \"GL_FALSE\";\n\telse if ( b == GL_TRUE )\n\t\treturn \"GL_TRUE\";\n\telse\n\t\treturn \"OUT OF RANGE FOR BOOLEAN\";\n}\n\nstatic const char * FuncToString( GLenum f )\n{\n\tswitch ( f )\n\t{\n\tcase GL_ALWAYS:\n\t\treturn \"GL_ALWAYS\";\n\tcase GL_NEVER:\n\t\treturn \"GL_NEVER\";\n\tcase GL_LEQUAL:\n\t\treturn \"GL_LEQUAL\";\n\tcase GL_LESS:\n\t\treturn \"GL_LESS\";\n\tcase GL_EQUAL:\n\t\treturn \"GL_EQUAL\";\n\tcase GL_GREATER:\n\t\treturn \"GL_GREATER\";\n\tcase GL_GEQUAL:\n\t\treturn \"GL_GEQUAL\";\n\tcase GL_NOTEQUAL:\n\t\treturn \"GL_NOTEQUAL\";\n\tdefault:\n\t\treturn \"!!! UNKNOWN !!!\";\n\t}\n}\n\nstatic const char * PrimToString( GLenum mode )\n{\n\tstatic char prim[1024];\n\n\tif ( mode == GL_TRIANGLES )\n\t\tstrcpy( prim, \"GL_TRIANGLES\" );\n\telse if ( mode == GL_TRIANGLE_STRIP )\n\t\tstrcpy( prim, \"GL_TRIANGLE_STRIP\" );\n\telse if ( mode == GL_TRIANGLE_FAN )\n\t\tstrcpy( prim, \"GL_TRIANGLE_FAN\" );\n\telse if ( mode == GL_QUADS )\n\t\tstrcpy( prim, \"GL_QUADS\" );\n\telse if ( mode == GL_QUAD_STRIP )\n\t\tstrcpy( prim, \"GL_QUAD_STRIP\" );\n\telse if ( mode == GL_POLYGON )\n\t\tstrcpy( prim, \"GL_POLYGON\" );\n\telse if ( mode == GL_POINTS )\n\t\tstrcpy( prim, \"GL_POINTS\" );\n\telse if ( mode == GL_LINES )\n\t\tstrcpy( prim, \"GL_LINES\" );\n\telse if ( mode == GL_LINE_STRIP )\n\t\tstrcpy( prim, \"GL_LINE_STRIP\" );\n\telse if ( mode == GL_LINE_LOOP )\n\t\tstrcpy( prim, \"GL_LINE_LOOP\" );\n\telse\n\t\tsprintf( prim, \"0x%x\", mode );\n\n\treturn prim;\n}\n\nstatic const char * CapToString( GLenum cap )\n{\n\tstatic char buffer[1024];\n\n\tswitch ( cap )\n\t{\n\tcase GL_TEXTURE_2D:\n\t\treturn \"GL_TEXTURE_2D\";\n\tcase GL_BLEND:\n\t\treturn \"GL_BLEND\";\n\tcase GL_DEPTH_TEST:\n\t\treturn \"GL_DEPTH_TEST\";\n\tcase GL_CULL_FACE:\n\t\treturn \"GL_CULL_FACE\";\n\tcase GL_CLIP_PLANE0:\n\t\treturn \"GL_CLIP_PLANE0\";\n\tcase GL_COLOR_ARRAY:\n\t\treturn \"GL_COLOR_ARRAY\";\n\tcase GL_TEXTURE_COORD_ARRAY:\n\t\treturn \"GL_TEXTURE_COORD_ARRAY\";\n\tcase GL_VERTEX_ARRAY:\n\t\treturn \"GL_VERTEX_ARRAY\";\n\tcase GL_ALPHA_TEST:\n\t\treturn \"GL_ALPHA_TEST\";\n\tcase GL_STENCIL_TEST:\n\t\treturn \"GL_STENCIL_TEST\";\n\tdefault:\n\t\tsprintf( buffer, \"0x%x\", cap );\n\t}\n\n\treturn buffer;\n}\n\nstatic const char * TypeToString( GLenum t )\n{\n\tswitch ( t )\n\t{\n\tcase GL_BYTE:\n\t\treturn \"GL_BYTE\";\n\tcase GL_UNSIGNED_BYTE:\n\t\treturn \"GL_UNSIGNED_BYTE\";\n\tcase GL_SHORT:\n\t\treturn \"GL_SHORT\";\n\tcase GL_UNSIGNED_SHORT:\n\t\treturn \"GL_UNSIGNED_SHORT\";\n\tcase GL_INT:\n\t\treturn \"GL_INT\";\n\tcase GL_UNSIGNED_INT:\n\t\treturn \"GL_UNSIGNED_INT\";\n\tcase GL_FLOAT:\n\t\treturn \"GL_FLOAT\";\n\tcase GL_DOUBLE:\n\t\treturn \"GL_DOUBLE\";\n\tdefault:\n\t\treturn \"!!! UNKNOWN !!!\";\n\t}\n}\n\nstatic void APIENTRY logAlphaFunc(GLenum func, GLclampf ref)\n{\n\tfprintf( log_fp, \"glAlphaFunc( 0x%x, %f )\\n\", func, ref );\n\tdllAlphaFunc( func, ref );\n}\nstatic void APIENTRY logBegin(GLenum mode)\n{\n\tfprintf( log_fp, \"glBegin( %s )\\n\", PrimToString( mode ));\n\tdllBegin( mode );\n}\nstatic void APIENTRY logBindTexture(GLenum target, GLuint texture)\n{\n\tfprintf( log_fp, \"glBindTexture( 0x%x, %u )\\n\", target, texture );\n\tdllBindTexture( target, texture );\n}\nstatic void BlendToName( char *n, GLenum f )\n{\n\tswitch ( f )\n\t{\n\tcase GL_ONE:\n\t\tstrcpy( n, \"GL_ONE\" );\n\t\tbreak;\n\tcase GL_ZERO:\n\t\tstrcpy( n, \"GL_ZERO\" );\n\t\tbreak;\n\tcase GL_SRC_ALPHA:\n\t\tstrcpy( n, \"GL_SRC_ALPHA\" );\n\t\tbreak;\n\tcase GL_ONE_MINUS_SRC_ALPHA:\n\t\tstrcpy( n, \"GL_ONE_MINUS_SRC_ALPHA\" );\n\t\tbreak;\n\tcase GL_DST_COLOR:\n\t\tstrcpy( n, \"GL_DST_COLOR\" );\n\t\tbreak;\n\tcase GL_ONE_MINUS_DST_COLOR:\n\t\tstrcpy( n, \"GL_ONE_MINUS_DST_COLOR\" );\n\t\tbreak;\n\tcase GL_DST_ALPHA:\n\t\tstrcpy( n, \"GL_DST_ALPHA\" );\n\t\tbreak;\n\tdefault:\n\t\tsprintf( n, \"0x%x\", f );\n\t}\n}\nstatic void APIENTRY logBlendFunc(GLenum sfactor, GLenum dfactor)\n{\n\tchar sf[128], df[128];\n\n\tBlendToName( sf, sfactor );\n\tBlendToName( df, dfactor );\n\n\tfprintf( log_fp, \"glBlendFunc( %s, %s )\\n\", sf, df );\n\tdllBlendFunc( sfactor, dfactor );\n}\nstatic void APIENTRY logClear(GLbitfield mask)\n{\n\tfprintf( log_fp, \"glClear( 0x%x = \", mask );\n\n\tif ( mask & GL_COLOR_BUFFER_BIT )\n\t\tfprintf( log_fp, \"GL_COLOR_BUFFER_BIT \" );\n\tif ( mask & GL_DEPTH_BUFFER_BIT )\n\t\tfprintf( log_fp, \"GL_DEPTH_BUFFER_BIT \" );\n\tif ( mask & GL_STENCIL_BUFFER_BIT )\n\t\tfprintf( log_fp, \"GL_STENCIL_BUFFER_BIT \" );\n\tif ( mask & GL_ACCUM_BUFFER_BIT )\n\t\tfprintf( log_fp, \"GL_ACCUM_BUFFER_BIT \" );\n\n\tfprintf( log_fp, \")\\n\" );\n\tdllClear( mask );\n}\nstatic void APIENTRY logClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)\n{\n\tfprintf( log_fp, \"glClearColor\\n\" );\n\tdllClearColor( red, green, blue, alpha );\n}\nstatic void APIENTRY logClipPlane(GLenum plane, const GLdouble *equation)\n{\n\tfprintf( log_fp, \"glClipPlane\\n\" );\n\tdllClipPlane( plane, equation );\n}\nstatic void APIENTRY logColor3f(GLfloat red, GLfloat green, GLfloat blue)\n{\n\tfprintf( log_fp, \"glColor3f\\n\" );\n\tdllColor3f( red, green, blue );\n}\n\n#define SIG( x ) fprintf( log_fp, x \"\\n\" )\n\nstatic void APIENTRY logColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)\n{\n\tSIG( \"glColorMask\" );\n\tdllColorMask( red, green, blue, alpha );\n}\nstatic void APIENTRY logColorPointer(GLint size, GLenum type, GLsizei stride, const void *pointer)\n{\n\tfprintf( log_fp, \"glColorPointer( %d, %s, %d, MEM )\\n\", size, TypeToString( type ), stride );\n\tdllColorPointer( size, type, stride, pointer );\n}\nstatic void APIENTRY logCullFace(GLenum mode)\n{\n\tfprintf( log_fp, \"glCullFace( %s )\\n\", ( mode == GL_FRONT ) ? \"GL_FRONT\" : \"GL_BACK\" );\n\tdllCullFace( mode );\n}\nstatic void APIENTRY logDeleteTextures(GLsizei n, const GLuint *textures)\n{\n\tSIG( \"glDeleteTextures\" );\n\tdllDeleteTextures( n, textures );\n}\nstatic void APIENTRY logDepthFunc(GLenum func)\n{\n\tfprintf( log_fp, \"glDepthFunc( %s )\\n\", FuncToString( func ) );\n\tdllDepthFunc( func );\n}\nstatic void APIENTRY logDepthMask(GLboolean flag)\n{\n\tfprintf( log_fp, \"glDepthMask( %s )\\n\", BooleanToString( flag ) );\n\tdllDepthMask( flag );\n}\nstatic void APIENTRY logDepthRange(GLclampd zNear, GLclampd zFar)\n{\n\tfprintf( log_fp, \"glDepthRange( %f, %f )\\n\", ( float ) zNear, ( float ) zFar );\n\tdllDepthRange( zNear, zFar );\n}\nstatic void APIENTRY logDisable(GLenum cap)\n{\n\tfprintf( log_fp, \"glDisable( %s )\\n\", CapToString( cap ) );\n\tdllDisable( cap );\n}\nstatic void APIENTRY logDisableClientState(GLenum array)\n{\n\tfprintf( log_fp, \"glDisableClientState( %s )\\n\", CapToString( array ) );\n\tdllDisableClientState( array );\n}\nstatic void APIENTRY logDrawBuffer(GLenum mode)\n{\n\tSIG( \"glDrawBuffer\" );\n\tdllDrawBuffer( mode );\n}\nstatic void APIENTRY logDrawElements(GLenum mode, GLsizei count, GLenum type, const void *indices)\n{\n\tfprintf( log_fp, \"glDrawElements( %s, %d, %s, MEM )\\n\", PrimToString( mode ), count, TypeToString( type ) );\n\tdllDrawElements( mode, count, type, indices );\n}\nstatic void APIENTRY logEnable(GLenum cap)\n{\n\tfprintf( log_fp, \"glEnable( %s )\\n\", CapToString( cap ) );\n\tdllEnable( cap );\n}\n\nstatic void APIENTRY logEnableClientState(GLenum array)\n{\n\tfprintf( log_fp, \"glEnableClientState( %s )\\n\", CapToString( array ) );\n\tdllEnableClientState( array );\n}\n\nstatic void APIENTRY logEnd(void)\n{\n\tSIG( \"glEnd\" );\n\tdllEnd();\n}\nstatic void APIENTRY logFinish(void)\n{\n\tSIG( \"glFinish\" );\n\tdllFinish();\n}\nstatic GLenum APIENTRY logGetError(void)\n{\n\tSIG( \"glGetError\" );\n\treturn dllGetError();\n}\nstatic void APIENTRY logGetIntegerv(GLenum pname, GLint *params)\n{\n\tSIG( \"glGetIntegerv\" );\n\tdllGetIntegerv( pname, params );\n}\nstatic const GLubyte * APIENTRY logGetString(GLenum name)\n{\n\tSIG( \"glGetString\" );\n\treturn dllGetString( name );\n}\nstatic void APIENTRY logLineWidth(GLfloat width)\n{\n\tSIG( \"glLineWidth\" );\n\tdllLineWidth( width );\n}\nstatic void APIENTRY logLoadIdentity(void)\n{\n\tSIG( \"glLoadIdentity\" );\n\tdllLoadIdentity();\n}\nstatic void APIENTRY logLoadMatrixf(const GLfloat *m)\n{\n\tSIG( \"glLoadMatrixf\" );\n\tdllLoadMatrixf( m );\n}\nstatic void APIENTRY logMatrixMode(GLenum mode)\n{\n\tSIG( \"glMatrixMode\" );\n\tdllMatrixMode( mode );\n}\nstatic void APIENTRY logOrtho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar)\n{\n\tSIG( \"glOrtho\" );\n\tdllOrtho( left, right, bottom, top, zNear, zFar );\n}\nstatic void APIENTRY logPolygonMode(GLenum face, GLenum mode)\n{\n\tfprintf( log_fp, \"glPolygonMode( 0x%x, 0x%x )\\n\", face, mode );\n\tdllPolygonMode( face, mode );\n}\nstatic void APIENTRY logPolygonOffset(GLfloat factor, GLfloat units)\n{\n\tSIG( \"glPolygonOffset\" );\n\tdllPolygonOffset( factor, units );\n}\nstatic void APIENTRY logPopMatrix(void)\n{\n\tSIG( \"glPopMatrix\" );\n\tdllPopMatrix();\n}\nstatic void APIENTRY logPushMatrix(void)\n{\n\tSIG( \"glPushMatrix\" );\n\tdllPushMatrix();\n}\nstatic void APIENTRY logReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels)\n{\n\tSIG( \"glReadPixels\" );\n\tdllReadPixels( x, y, width, height, format, type, pixels );\n}\nstatic void APIENTRY logScissor(GLint x, GLint y, GLsizei width, GLsizei height)\n{\n\tfprintf( log_fp, \"glScissor( %d, %d, %d, %d )\\n\", x, y, width, height );\n\tdllScissor( x, y, width, height );\n}\nstatic void APIENTRY logStencilFunc(GLenum func, GLint ref, GLuint mask)\n{\n\tSIG( \"glStencilFunc\" );\n\tdllStencilFunc( func, ref, mask );\n}\nstatic void APIENTRY logStencilOp(GLenum fail, GLenum zfail, GLenum zpass)\n{\n\tSIG( \"glStencilOp\" );\n\tdllStencilOp( fail, zfail, zpass );\n}\nstatic void APIENTRY logTexCoord2f(GLfloat s, GLfloat t)\n{\n\tSIG( \"glTexCoord2f\" );\n\tdllTexCoord2f( s, t );\n}\nstatic void APIENTRY logTexCoord2fv(const GLfloat *v)\n{\n\tSIG( \"glTexCoord2fv\" );\n\tdllTexCoord2fv( v );\n}\nstatic void APIENTRY logTexCoordPointer(GLint size, GLenum type, GLsizei stride, const void *pointer)\n{\n\tfprintf( log_fp, \"glTexCoordPointer( %d, %s, %d, MEM )\\n\", size, TypeToString( type ), stride );\n\tdllTexCoordPointer( size, type, stride, pointer );\n}\n\nstatic void APIENTRY logTexEnvf(GLenum target, GLenum pname, GLfloat param)\n{\n\tfprintf( log_fp, \"glTexEnvf( 0x%x, 0x%x, %f )\\n\", target, pname, param );\n\tdllTexEnvf( target, pname, param );\n}\nstatic void APIENTRY logTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels)\n{\n\tSIG( \"glTexImage2D\" );\n\tdllTexImage2D( target, level, internalformat, width, height, border, format, type, pixels );\n}\nstatic void APIENTRY logTexParameterf(GLenum target, GLenum pname, GLfloat param)\n{\n\tfprintf( log_fp, \"glTexParameterf( 0x%x, 0x%x, %f )\\n\", target, pname, param );\n\tdllTexParameterf( target, pname, param );\n}\nstatic void APIENTRY logTexParameterfv(GLenum target, GLenum pname, const GLfloat *params)\n{\n\tSIG( \"glTexParameterfv\" );\n\tdllTexParameterfv( target, pname, params );\n}\nstatic void APIENTRY logTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels)\n{\n\tSIG( \"glTexSubImage2D\" );\n\tdllTexSubImage2D( target, level, xoffset, yoffset, width, height, format, type, pixels );\n}\nstatic void APIENTRY logVertex2f(GLfloat x, GLfloat y)\n{\n\tSIG( \"glVertex2f\" );\n\tdllVertex2f( x, y );\n}\nstatic void APIENTRY logVertex3f(GLfloat x, GLfloat y, GLfloat z)\n{\n\tSIG( \"glVertex3f\" );\n\tdllVertex3f( x, y, z );\n}\nstatic void APIENTRY logVertex3fv(const GLfloat *v)\n{\n\tSIG( \"glVertex3fv\" );\n\tdllVertex3fv( v );\n}\nstatic void APIENTRY logVertexPointer(GLint size, GLenum type, GLsizei stride, const void *pointer)\n{\n\tfprintf( log_fp, \"glVertexPointer( %d, %s, %d, MEM )\\n\", size, TypeToString( type ), stride );\n\tdllVertexPointer( size, type, stride, pointer );\n}\nstatic void APIENTRY logViewport(GLint x, GLint y, GLsizei width, GLsizei height)\n{\n\tfprintf( log_fp, \"glViewport( %d, %d, %d, %d )\\n\", x, y, width, height );\n\tdllViewport( x, y, width, height );\n}\n\n/*\n** QGL_Shutdown\n**\n** Unloads the specified DLL then nulls out all the proc pointers.  This\n** is only called during a hard shutdown of the OGL subsystem (e.g. vid_restart).\n*/\nvoid QGL_Shutdown( void )\n{\n\tif ( hinstOpenGL )\n\t{\n\t\tri.Printf( PRINT_ALL, \"...shutting down QGL\\n\" );\n\t\tri.Printf( PRINT_ALL, \"...unloading OpenGL DLL\\n\" );\n\t\tFreeLibrary( hinstOpenGL );\n\t\thinstOpenGL = NULL;\n\t}\n\n\tqglAlphaFunc                 = NULL;\n\tqglBegin                     = NULL;\n\tqglBindTexture               = NULL;\n\tqglBlendFunc                 = NULL;\n\tqglClear                     = NULL;\n\tqglClearColor                = NULL;\n\tqglClipPlane                 = NULL;\n\tqglColor3f                   = NULL;\n\tqglColorMask                 = NULL;\n\tqglColorPointer              = NULL;\n\tqglCullFace                  = NULL;\n\tqglDeleteTextures            = NULL;\n\tqglDepthFunc                 = NULL;\n\tqglDepthMask                 = NULL;\n\tqglDepthRange                = NULL;\n\tqglDisable                   = NULL;\n\tqglDisableClientState        = NULL;\n\tqglDrawBuffer                = NULL;\n\tqglDrawElements              = NULL;\n\tqglEnable                    = NULL;\n\tqglEnableClientState         = NULL;\n\tqglEnd                       = NULL;\n\tqglFinish                    = NULL;\n\tqglGetError                  = NULL;\n\tqglGetIntegerv               = NULL;\n\tqglGetString                 = NULL;\n\tqglLineWidth                 = NULL;\n\tqglLoadIdentity              = NULL;\n\tqglLoadMatrixf               = NULL;\n\tqglMatrixMode                = NULL;\n\tqglOrtho                     = NULL;\n\tqglPolygonMode               = NULL;\n\tqglPolygonOffset             = NULL;\n\tqglPopMatrix                 = NULL;\n\tqglPushMatrix                = NULL;\n\tqglReadPixels                = NULL;\n\tqglScissor                   = NULL;\n\tqglStencilFunc               = NULL;\n\tqglStencilOp                 = NULL;\n\tqglTexCoord2f                = NULL;\n\tqglTexCoord2fv               = NULL;\n\tqglTexCoordPointer           = NULL;\n\tqglTexEnvf                   = NULL;\n\tqglTexImage2D                = NULL;\n\tqglTexParameterf             = NULL;\n\tqglTexParameterfv            = NULL;\n\tqglTexSubImage2D             = NULL;\n\tqglVertex2f                  = NULL;\n\tqglVertex3f                  = NULL;\n\tqglVertex3fv                 = NULL;\n\tqglVertexPointer             = NULL;\n\tqglViewport                  = NULL;\n\n\tqwglCreateContext            = NULL;\n\tqwglDeleteContext            = NULL;\n\tqwglGetProcAddress           = NULL;\n\tqwglMakeCurrent              = NULL;\n}\n\n#\tpragma warning (disable : 4113 4133 4047 )\n#\tdefine GPA( a ) (dllname ? (void*)GetProcAddress(hinstOpenGL, #a) : (void*)(&no ## a))\n\n/*\n** QGL_Init\n**\n** This is responsible for binding our qgl function pointers to \n** the appropriate GL stuff.  In Windows this means doing a \n** LoadLibrary and a bunch of calls to GetProcAddress.  On other\n** operating systems we need to do the right thing, whatever that\n** might be.\n*/\nqboolean QGL_Init( const char *dllname )\n{\n\tif (dllname != nullptr) {\n\t\tassert( hinstOpenGL == 0 );\n\n\t\tri.Printf( PRINT_ALL, \"...initializing QGL\\n\" );\n\t\tri.Printf( PRINT_ALL, \"...calling LoadLibrary('%s'): \", dllname );\n\n\t\tif ( ( hinstOpenGL = LoadLibrary( dllname ) ) == 0 )\n\t\t{\n\t\t\tri.Printf( PRINT_ALL, \"failed\\n\" );\n\t\t\treturn qfalse;\n\t\t}\n\t\tri.Printf( PRINT_ALL, \"succeeded\\n\" );\n\t}\n\n\tqglAlphaFunc                 = dllAlphaFunc = (decltype(dllAlphaFunc))GPA(glAlphaFunc);\n\tqglBegin                     = dllBegin = (decltype(dllBegin))GPA(glBegin);\n\tqglBindTexture               = dllBindTexture = (decltype(dllBindTexture))GPA(glBindTexture);\n\tqglBlendFunc                 = dllBlendFunc = (decltype(dllBlendFunc))GPA(glBlendFunc);\n\tqglClear                     = dllClear = (decltype(dllClear))GPA(glClear);\n\tqglClearColor                = dllClearColor = (decltype(dllClearColor))GPA(glClearColor);\n\tqglClipPlane                 = dllClipPlane = (decltype(dllClipPlane))GPA(glClipPlane);\n\tqglColor3f                   = dllColor3f = (decltype(dllColor3f))GPA(glColor3f);\n\tqglColorMask                 = dllColorMask = (decltype(dllColorMask))GPA(glColorMask);\n\tqglColorPointer              = dllColorPointer = (decltype(dllColorPointer))GPA(glColorPointer);\n\tqglCullFace                  = dllCullFace = (decltype(dllCullFace))GPA(glCullFace);\n\tqglDeleteTextures            = dllDeleteTextures = (decltype(dllDeleteTextures))GPA(glDeleteTextures);\n\tqglDepthFunc                 = dllDepthFunc = (decltype(dllDepthFunc))GPA(glDepthFunc);\n\tqglDepthMask                 = dllDepthMask = (decltype(dllDepthMask))GPA(glDepthMask);\n\tqglDepthRange                = dllDepthRange = (decltype(dllDepthRange))GPA(glDepthRange);\n\tqglDisable                   = dllDisable = (decltype(dllDisable))GPA(glDisable);\n\tqglDisableClientState        = dllDisableClientState = (decltype(dllDisableClientState))GPA(glDisableClientState);\n\tqglDrawBuffer                = dllDrawBuffer = (decltype(dllDrawBuffer))GPA(glDrawBuffer);\n\tqglDrawElements              = dllDrawElements = (decltype(dllDrawElements))GPA(glDrawElements);\n\tqglEnable                    = \tdllEnable                    = (decltype(dllEnable))GPA(glEnable);\n\tqglEnableClientState         = \tdllEnableClientState         = (decltype(dllEnableClientState))GPA(glEnableClientState);\n\tqglEnd                       = \tdllEnd                       = (decltype(dllEnd))GPA(glEnd);\n\tqglFinish                    = \tdllFinish                    = (decltype(dllFinish))GPA(glFinish);\n\tqglGetError                  = \tdllGetError                  = ( GLenum (__stdcall * )(void) ) GPA( glGetError );\n\tqglGetIntegerv               = \tdllGetIntegerv               = (decltype(dllGetIntegerv))GPA(glGetIntegerv);\n\tqglGetString                 = \tdllGetString                 = (decltype(dllGetString))GPA(glGetString);\n\tqglLineWidth                 = \tdllLineWidth                 = (decltype(dllLineWidth))GPA(glLineWidth);\n\tqglLoadIdentity              = \tdllLoadIdentity              = (decltype(dllLoadIdentity))GPA(glLoadIdentity);\n\tqglLoadMatrixf               = \tdllLoadMatrixf               = (decltype(dllLoadMatrixf))GPA(glLoadMatrixf);\n\tqglMatrixMode                = \tdllMatrixMode                = (decltype(dllMatrixMode))GPA(glMatrixMode);\n\tqglOrtho                     = \tdllOrtho                     = (decltype(dllOrtho))GPA(glOrtho);\n\tqglPolygonMode               = \tdllPolygonMode               = (decltype(dllPolygonMode))GPA(glPolygonMode);\n\tqglPolygonOffset             = \tdllPolygonOffset             = (decltype(dllPolygonOffset))GPA(glPolygonOffset);\n\tqglPopMatrix                 = \tdllPopMatrix                 = (decltype(dllPopMatrix))GPA(glPopMatrix);\n\tqglPushMatrix                = \tdllPushMatrix                = (decltype(dllPushMatrix))GPA(glPushMatrix);\n\tqglReadPixels                = \tdllReadPixels                = (decltype(dllReadPixels))GPA(glReadPixels);\n\tqglScissor                   = \tdllScissor                   = (decltype(dllScissor))GPA(glScissor);\n\tqglStencilFunc               = \tdllStencilFunc               = (decltype(dllStencilFunc))GPA(glStencilFunc);\n\tqglStencilOp                 = \tdllStencilOp                 = (decltype(dllStencilOp))GPA(glStencilOp);\n\tqglTexCoord2f                = \tdllTexCoord2f                = (decltype(dllTexCoord2f))GPA(glTexCoord2f);\n\tqglTexCoord2fv               = \tdllTexCoord2fv               = (decltype(dllTexCoord2fv))GPA(glTexCoord2fv);\n\tqglTexCoordPointer           = \tdllTexCoordPointer           = (decltype(dllTexCoordPointer))GPA(glTexCoordPointer);\n\tqglTexEnvf                   = \tdllTexEnvf                   = (decltype(dllTexEnvf))GPA(glTexEnvf);\n\tqglTexImage2D                = \tdllTexImage2D                = (decltype(dllTexImage2D))GPA(glTexImage2D);\n\tqglTexParameterf             = \tdllTexParameterf             = (decltype(dllTexParameterf))GPA(glTexParameterf);\n\tqglTexParameterfv            = \tdllTexParameterfv            = (decltype(dllTexParameterfv))GPA(glTexParameterfv);\n\tqglTexSubImage2D             = \tdllTexSubImage2D             = (decltype(dllTexSubImage2D))GPA(glTexSubImage2D);\n\tqglVertex2f                  = \tdllVertex2f                  = (decltype(dllVertex2f))GPA(glVertex2f);\n\tqglVertex3f                  = \tdllVertex3f                  = (decltype(dllVertex3f))GPA(glVertex3f);\n\tqglVertex3fv                 = \tdllVertex3fv                 = (decltype(dllVertex3fv))GPA(glVertex3fv);\n\tqglVertexPointer             = \tdllVertexPointer             = (decltype(dllVertexPointer))GPA(glVertexPointer);\n\tqglViewport                  = \tdllViewport                  = (decltype(dllViewport))GPA(glViewport);\n\n\tqwglCreateContext            = (decltype(qwglCreateContext))GPA(wglCreateContext);\n\tqwglDeleteContext            = (decltype(qwglDeleteContext))GPA(wglDeleteContext);\n\tqwglGetProcAddress           = (decltype(qwglGetProcAddress))GPA(wglGetProcAddress);\n\tqwglMakeCurrent              = (decltype(qwglMakeCurrent))GPA(wglMakeCurrent);\n\n\tqwglSwapIntervalEXT = 0;\n\tqglActiveTextureARB = 0;\n\tqglClientActiveTextureARB = 0;\n\tqglLockArraysEXT = 0;\n\tqglUnlockArraysEXT = 0;\n\n\tif (dllname != nullptr) {\n\t\t// check logging\n\t\tQGL_EnableLogging( (qboolean) r_logFile->integer );\n\t}\n\n\treturn qtrue;\n}\n\nvoid QGL_EnableLogging( qboolean enable )\n{\n\tstatic qboolean isEnabled;\n\n\t// return if we're already active\n\tif ( isEnabled && enable ) {\n\t\t// decrement log counter and stop if it has reached 0\n\t\tri.Cvar_Set( \"r_logFile\", va(\"%d\", r_logFile->integer - 1 ) );\n\t\tif ( r_logFile->integer ) {\n\t\t\treturn;\n\t\t}\n\t\tenable = qfalse;\n\t}\n\n\t// return if we're already disabled\n\tif ( !enable && !isEnabled )\n\t\treturn;\n\n\tisEnabled = enable;\n\n\tif ( enable )\n\t{\n\t\tif ( !log_fp )\n\t\t{\n\t\t\tstruct tm *newtime;\n\t\t\ttime_t aclock;\n\t\t\tchar buffer[1024];\n\t\t\tcvar_t\t*basedir;\n\n\t\t\ttime( &aclock );\n\t\t\tnewtime = localtime( &aclock );\n\n\t\t\tasctime( newtime );\n\n\t\t\tbasedir = ri.Cvar_Get( \"fs_basepath\", \"\", 0 );\n\t\t\tCom_sprintf( buffer, sizeof(buffer), \"%s/gl.log\", basedir->string ); \n\t\t\tlog_fp = fopen( buffer, \"wt\" );\n\n\t\t\tfprintf( log_fp, \"%s\\n\", asctime( newtime ) );\n\t\t}\n\n\t\tqglAlphaFunc                 = logAlphaFunc;\n\t\tqglBegin                     = logBegin;\n\t\tqglBindTexture               = logBindTexture;\n\t\tqglBlendFunc                 = logBlendFunc;\n\t\tqglClear                     = logClear;\n\t\tqglClearColor                = logClearColor;\n\t\tqglClipPlane                 = logClipPlane;\n\t\tqglColor3f                   = logColor3f;\n\t\tqglColorMask                 = logColorMask;\n\t\tqglColorPointer              = logColorPointer;\n\t\tqglCullFace                  = logCullFace;\n\t\tqglDeleteTextures            = logDeleteTextures ;\n\t\tqglDepthFunc                 = logDepthFunc ;\n\t\tqglDepthMask                 = logDepthMask ;\n\t\tqglDepthRange                = logDepthRange ;\n\t\tqglDisable                   = logDisable ;\n\t\tqglDisableClientState        = logDisableClientState ;\n\t\tqglDrawBuffer                = logDrawBuffer ;\n\t\tqglDrawElements              = logDrawElements ;\n\t\tqglEnable                    = \tlogEnable                    ;\n\t\tqglEnableClientState         = \tlogEnableClientState         ;\n\t\tqglEnd                       = \tlogEnd                       ;\n\t\tqglFinish                    = \tlogFinish                    ;\n\t\tqglGetError                  = \tlogGetError                  ;\n\t\tqglGetIntegerv               = \tlogGetIntegerv               ;\n\t\tqglGetString                 = \tlogGetString                 ;\n\t\tqglLineWidth                 = \tlogLineWidth                 ;\n\t\tqglLoadIdentity              = \tlogLoadIdentity              ;\n\t\tqglLoadMatrixf               = \tlogLoadMatrixf               ;\n\t\tqglMatrixMode                = \tlogMatrixMode                ;\n\t\tqglOrtho                     = \tlogOrtho                     ;\n\t\tqglPolygonMode               = \tlogPolygonMode               ;\n\t\tqglPolygonOffset             = \tlogPolygonOffset             ;\n\t\tqglPopMatrix                 = \tlogPopMatrix                 ;\n\t\tqglPushMatrix                = \tlogPushMatrix                ;\n\t\tqglReadPixels                = \tlogReadPixels                ;\n\t\tqglScissor                   = \tlogScissor                   ;\n\t\tqglStencilFunc               = \tlogStencilFunc               ;\n\t\tqglStencilOp                 = \tlogStencilOp                 ;\n\t\tqglTexCoord2f                = \tlogTexCoord2f                ;\n\t\tqglTexCoord2fv               = \tlogTexCoord2fv               ;\n\t\tqglTexCoordPointer           = \tlogTexCoordPointer           ;\n\t\tqglTexEnvf                   = \tlogTexEnvf                   ;\n\t\tqglTexImage2D                = \tlogTexImage2D                ;\n\t\tqglTexParameterf             = \tlogTexParameterf             ;\n\t\tqglTexParameterfv            = \tlogTexParameterfv            ;\n\t\tqglTexSubImage2D             = \tlogTexSubImage2D             ;\n\t\tqglVertex2f                  = \tlogVertex2f                  ;\n\t\tqglVertex3f                  = \tlogVertex3f                  ;\n\t\tqglVertex3fv                 = \tlogVertex3fv                 ;\n\t\tqglVertexPointer             = \tlogVertexPointer             ;\n\t\tqglViewport                  = \tlogViewport                  ;\n\t}\n\telse\n\t{\n\t\tif ( log_fp )\t{\n\t\t\tfprintf( log_fp, \"*** CLOSING LOG ***\\n\" );\n\t\t\tfclose( log_fp );\n\t\t\tlog_fp = NULL;\n\t\t}\n\t\tqglAlphaFunc                 = dllAlphaFunc;\n\t\tqglBegin                     = dllBegin;\n\t\tqglBindTexture               = dllBindTexture;\n\t\tqglBlendFunc                 = dllBlendFunc;\n\t\tqglClear                     = dllClear;\n\t\tqglClearColor                = dllClearColor;\n\t\tqglClipPlane                 = dllClipPlane;\n\t\tqglColor3f                   = dllColor3f;\n\t\tqglColorMask                 = dllColorMask;\n\t\tqglColorPointer              = dllColorPointer;\n\t\tqglCullFace                  = dllCullFace;\n\t\tqglDeleteTextures            = dllDeleteTextures ;\n\t\tqglDepthFunc                 = dllDepthFunc ;\n\t\tqglDepthMask                 = dllDepthMask ;\n\t\tqglDepthRange                = dllDepthRange ;\n\t\tqglDisable                   = dllDisable ;\n\t\tqglDisableClientState        = dllDisableClientState ;\n\t\tqglDrawBuffer                = dllDrawBuffer ;\n\t\tqglDrawElements              = dllDrawElements ;\n\t\tqglEnable                    = \tdllEnable                    ;\n\t\tqglEnableClientState         = \tdllEnableClientState         ;\n\t\tqglEnd                       = \tdllEnd                       ;\n\t\tqglFinish                    = \tdllFinish                    ;\n\t\tqglGetError                  = \tdllGetError                  ;\n\t\tqglGetIntegerv               = \tdllGetIntegerv               ;\n\t\tqglGetString                 = \tdllGetString                 ;\n\t\tqglLineWidth                 = \tdllLineWidth                 ;\n\t\tqglLoadIdentity              = \tdllLoadIdentity              ;\n\t\tqglLoadMatrixf               = \tdllLoadMatrixf               ;\n\t\tqglMatrixMode                = \tdllMatrixMode                ;\n\t\tqglOrtho                     = \tdllOrtho                     ;\n\t\tqglPolygonMode               = \tdllPolygonMode               ;\n\t\tqglPolygonOffset             = \tdllPolygonOffset             ;\n\t\tqglPopMatrix                 = \tdllPopMatrix                 ;\n\t\tqglPushMatrix                = \tdllPushMatrix                ;\n\t\tqglReadPixels                = \tdllReadPixels                ;\n\t\tqglScissor                   = \tdllScissor                   ;\n\t\tqglStencilFunc               = \tdllStencilFunc               ;\n\t\tqglStencilOp                 = \tdllStencilOp                 ;\n\t\tqglTexCoord2f                = \tdllTexCoord2f                ;\n\t\tqglTexCoord2fv               = \tdllTexCoord2fv               ;\n\t\tqglTexCoordPointer           = \tdllTexCoordPointer           ;\n\t\tqglTexEnvf                   = \tdllTexEnvf                   ;\n\t    qglTexImage2D                = \tdllTexImage2D                ;\n\t\tqglTexParameterf             = \tdllTexParameterf             ;\n\t\tqglTexParameterfv            = \tdllTexParameterfv            ;\n\t\tqglTexSubImage2D             = \tdllTexSubImage2D             ;\n\t\tqglVertex2f                  = \tdllVertex2f                  ;\n\t\tqglVertex3f                  = \tdllVertex3f                  ;\n\t\tqglVertex3fv                 = \tdllVertex3fv                 ;\n\t\tqglVertexPointer             = \tdllVertexPointer             ;\n\t\tqglViewport                  = \tdllViewport                  ;\n\t}\n}\n\n#pragma warning (default : 4113 4133 4047 )\n"
  },
  {
    "path": "src/engine/platform/win_shared.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n#include \"../../game/q_shared.h\"\n#include \"../qcommon/qcommon.h\"\n#include \"win_local.h\"\n#include <lmerr.h>\n#include <lmcons.h>\n#include <lmwksta.h>\n#include <errno.h>\n#include <fcntl.h>\n#include <stdio.h>\n#include <direct.h>\n#include <io.h>\n#include <conio.h>\n\n/*\n================\nSys_Milliseconds\n================\n*/\nint\t\t\tsys_timeBase;\nint Sys_Milliseconds (void)\n{\n\tint\t\t\tsys_curtime;\n\tstatic qboolean\tinitialized = qfalse;\n\n\tif (!initialized) {\n\t\tsys_timeBase = timeGetTime();\n\t\tinitialized = qtrue;\n\t}\n\tsys_curtime = timeGetTime() - sys_timeBase;\n\n\treturn sys_curtime;\n}\n\n/*\n================\nSys_SnapVector\n================\n*/\nvoid Sys_SnapVector( float *v )\n{\n\tv[0] = (int)v[0];\n\tv[1] = (int)v[1];\n\tv[2] = (int)v[2];\n}\n\n\n/*\n**\n** Disable all optimizations temporarily so this code works correctly!\n**\n*/\n#pragma optimize( \"\", off )\n\n/*\n** --------------------------------------------------------------------------------\n**\n** PROCESSOR STUFF\n**\n** --------------------------------------------------------------------------------\n*/\n\nint Sys_GetProcessorId( void )\n{\n\treturn CPUID_GENERIC;\n}\n\n/*\n**\n** Re-enable optimizations back to what they were\n**\n*/\n#pragma optimize( \"\", on )\n\n//============================================\n\nchar *Sys_GetCurrentUser( void )\n{\n\tstatic char s_userName[1024];\n\tunsigned long size = sizeof( s_userName );\n\n\n\tif ( !GetUserName( s_userName, &size ) )\n\t\tstrcpy( s_userName, \"player\" );\n\n\tif ( !s_userName[0] )\n\t{\n\t\tstrcpy( s_userName, \"player\" );\n\t}\n\n\treturn s_userName;\n}\n\nchar\t*Sys_DefaultHomePath(void) {\n\treturn NULL;\n}\n\nchar *Sys_DefaultInstallPath(void)\n{\n\treturn Sys_Cwd();\n}\n\n"
  },
  {
    "path": "src/engine/platform/win_snd.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n#include <float.h>\n\n#include \"../client/snd_local.h\"\n#define CINTERFACE\n#include \"win_local.h\"\n\nHRESULT (WINAPI *pDirectSoundCreate)(GUID FAR *lpGUID, LPDIRECTSOUND FAR *lplpDS, IUnknown FAR *pUnkOuter);\n#define iDirectSoundCreate(a,b,c)\tpDirectSoundCreate(a,b,c)\n\n#define SECONDARY_BUFFER_SIZE\t0x10000\n\n\nstatic qboolean\tdsound_init;\nstatic int\t\tsample16;\nstatic DWORD\tgSndBufSize;\nstatic DWORD\tlocksize;\nstatic LPDIRECTSOUND pDS;\nstatic LPDIRECTSOUNDBUFFER pDSBuf, pDSPBuf;\nstatic HINSTANCE hInstDS;\n\n\nstatic const char *DSoundError( int error ) {\n\tswitch ( error ) {\n\tcase DSERR_BUFFERLOST:\n\t\treturn \"DSERR_BUFFERLOST\";\n\tcase DSERR_INVALIDCALL:\n\t\treturn \"DSERR_INVALIDCALLS\";\n\tcase DSERR_INVALIDPARAM:\n\t\treturn \"DSERR_INVALIDPARAM\";\n\tcase DSERR_PRIOLEVELNEEDED:\n\t\treturn \"DSERR_PRIOLEVELNEEDED\";\n\t}\n\n\treturn \"unknown\";\n}\n\n/*\n==================\nSNDDMA_Shutdown\n==================\n*/\nvoid SNDDMA_Shutdown( void ) {\n\tCom_DPrintf( \"Shutting down sound system\\n\" );\n\n\tif ( pDS ) {\n\t\tCom_DPrintf( \"Destroying DS buffers\\n\" );\n\t\tif ( pDS )\n\t\t{\n\t\t\tCom_DPrintf( \"...setting NORMAL coop level\\n\" );\n\t\t\tpDS->lpVtbl->SetCooperativeLevel( pDS, g_wv.hWnd, DSSCL_PRIORITY );\n\t\t}\n\n\t\tif ( pDSBuf )\n\t\t{\n\t\t\tCom_DPrintf( \"...stopping and releasing sound buffer\\n\" );\n\t\t\tpDSBuf->lpVtbl->Stop( pDSBuf );\n\t\t\tpDSBuf->lpVtbl->Release( pDSBuf );\n\t\t}\n\n\t\t// only release primary buffer if it's not also the mixing buffer we just released\n\t\tif ( pDSPBuf && ( pDSBuf != pDSPBuf ) )\n\t\t{\n\t\t\tCom_DPrintf( \"...releasing primary buffer\\n\" );\n\t\t\tpDSPBuf->lpVtbl->Release( pDSPBuf );\n\t\t}\n\t\tpDSBuf = NULL;\n\t\tpDSPBuf = NULL;\n\n\t\tdma.buffer = NULL;\n\n\t\tCom_DPrintf( \"...releasing DS object\\n\" );\n\t\tpDS->lpVtbl->Release( pDS );\n\t}\n\n\tif ( hInstDS ) {\n\t\tCom_DPrintf( \"...freeing DSOUND.DLL\\n\" );\n\t\tFreeLibrary( hInstDS );\n\t\thInstDS = NULL;\n\t}\n\n\tpDS = NULL;\n\tpDSBuf = NULL;\n\tpDSPBuf = NULL;\n\tdsound_init = qfalse;\n\tmemset ((void *)&dma, 0, sizeof (dma));\n\tCoUninitialize( );\n}\n\n/*\n==================\nSNDDMA_Init\n\nInitialize direct sound\nReturns false if failed\n==================\n*/\nqboolean SNDDMA_Init(void) {\n\n\tmemset ((void *)&dma, 0, sizeof (dma));\n\tdsound_init = (qboolean) 0;\n\n\tCoInitialize(NULL);\n\n\tif ( !SNDDMA_InitDS () ) {\n\t\treturn qfalse;\n\t}\n\n\tdsound_init = qtrue;\n\n\tCom_DPrintf(\"Completed successfully\\n\" );\n\n    return qtrue;\n}\n\nint SNDDMA_InitDS ()\n{\n\tHRESULT\t\t\thresult;\n\tDSBUFFERDESC\tdsbuf;\n\tDSBCAPS\t\t\tdsbcaps;\n\tWAVEFORMATEX\tformat;\n\tint\t\t\t\tuse8;\n\n\tCom_Printf( \"Initializing DirectSound\\n\");\n\n    const GUID CLSID_DirectSound = {0x47d4d946, 0x62e8, 0x11cf, 0x93, 0xbc, 0x44, 0x45, 0x53, 0x54, 0x0, 0x0};\n    const GUID CLSID_DirectSound8 = {0x3901cc3f, 0x84b5, 0x4fa4, 0xba, 0x35, 0xaa, 0x81, 0x72, 0xb8, 0xa0, 0x9b};\n    const GUID IID_IDirectSound8 = {0xC50A7E93, 0xF395, 0x4834, 0x9E, 0xF6, 0x7F, 0xA9, 0x9D, 0xE5, 0x09, 0x66};\n    const GUID IID_IDirectSound = {0x279AFA83, 0x4981, 0x11CE, 0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60};\n\n\tuse8 = 1;\n    // Create IDirectSound using the primary sound device\n    if( FAILED( hresult = CoCreateInstance(CLSID_DirectSound8, NULL, CLSCTX_INPROC_SERVER, IID_IDirectSound8, (void **)&pDS))) {\n\t\tuse8 = 0;\n\t    if( FAILED( hresult = CoCreateInstance(CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER, IID_IDirectSound, (void **)&pDS))) {\n\t\t\tCom_Printf (\"failed\\n\");\n\t\t\tSNDDMA_Shutdown ();\n\t\t\treturn qfalse;\n\t\t}\n\t}\n\n\thresult = pDS->lpVtbl->Initialize( pDS, NULL);\n\n\tCom_DPrintf( \"ok\\n\" );\n\n\tCom_DPrintf(\"...setting DSSCL_PRIORITY coop level: \" );\n\n\tif ( DS_OK != pDS->lpVtbl->SetCooperativeLevel( pDS, g_wv.hWnd, DSSCL_PRIORITY ) )\t{\n\t\tCom_Printf (\"failed\\n\");\n\t\tSNDDMA_Shutdown ();\n\t\treturn qfalse;\n\t}\n\tCom_DPrintf(\"ok\\n\" );\n\n\n\t// create the secondary buffer we'll actually work with\n\tdma.channels = 2;\n\tdma.samplebits = 16;\n\n//\tif (s_khz->integer == 44)\n//\t\tdma.speed = 44100;\n//\telse if (s_khz->integer == 22)\n//\t\tdma.speed = 22050;\n//\telse\n//\t\tdma.speed = 11025;\n\n\tdma.speed = 22050;\n\tmemset (&format, 0, sizeof(format));\n\tformat.wFormatTag = WAVE_FORMAT_PCM;\n    format.nChannels = dma.channels;\n    format.wBitsPerSample = dma.samplebits;\n    format.nSamplesPerSec = dma.speed;\n    format.nBlockAlign = format.nChannels * format.wBitsPerSample / 8;\n    format.cbSize = 0;\n    format.nAvgBytesPerSec = format.nSamplesPerSec*format.nBlockAlign; \n\n\tmemset (&dsbuf, 0, sizeof(dsbuf));\n\tdsbuf.dwSize = sizeof(DSBUFFERDESC);\n\n\t// Micah: take advantage of 2D hardware.if available.\n\tdsbuf.dwFlags = DSBCAPS_LOCHARDWARE;\n\tif (use8) {\n\t\tdsbuf.dwFlags |= DSBCAPS_GETCURRENTPOSITION2;\n\t}\n\tdsbuf.dwBufferBytes = SECONDARY_BUFFER_SIZE;\n\tdsbuf.lpwfxFormat = &format;\n\t\n\tmemset(&dsbcaps, 0, sizeof(dsbcaps));\n\tdsbcaps.dwSize = sizeof(dsbcaps);\n\t\n\tCom_DPrintf( \"...creating secondary buffer: \" );\n\tif (DS_OK == pDS->lpVtbl->CreateSoundBuffer(pDS, &dsbuf, &pDSBuf, NULL)) {\n\t\tCom_Printf( \"locked hardware.  ok\\n\" );\n\t}\n\telse {\n\t\t// Couldn't get hardware, fallback to software.\n\t\tdsbuf.dwFlags = DSBCAPS_LOCSOFTWARE;\n\t\tif (use8) {\n\t\t\tdsbuf.dwFlags |= DSBCAPS_GETCURRENTPOSITION2;\n\t\t}\n\t\tif (DS_OK != pDS->lpVtbl->CreateSoundBuffer(pDS, &dsbuf, &pDSBuf, NULL)) {\n\t\t\tCom_Printf( \"failed\\n\" );\n\t\t\tSNDDMA_Shutdown ();\n\t\t\treturn qfalse;\n\t\t}\n\t\tCom_DPrintf( \"forced to software.  ok\\n\" );\n\t}\n\t\t\n\t// Make sure mixer is active\n\tif ( DS_OK != pDSBuf->lpVtbl->Play(pDSBuf, 0, 0, DSBPLAY_LOOPING) ) {\n\t\tCom_Printf (\"*** Looped sound play failed ***\\n\");\n\t\tSNDDMA_Shutdown ();\n\t\treturn qfalse;\n\t}\n\n\t// get the returned buffer size\n\tif ( DS_OK != pDSBuf->lpVtbl->GetCaps (pDSBuf, &dsbcaps) ) {\n\t\tCom_Printf (\"*** GetCaps failed ***\\n\");\n\t\tSNDDMA_Shutdown ();\n\t\treturn qfalse;\n\t}\n\t\n\tgSndBufSize = dsbcaps.dwBufferBytes;\n\n\tdma.channels = format.nChannels;\n\tdma.samplebits = format.wBitsPerSample;\n\tdma.speed = format.nSamplesPerSec;\n\tdma.samples = gSndBufSize/(dma.samplebits/8);\n\tdma.submission_chunk = 1;\n\tdma.buffer = NULL;\t\t\t// must be locked first\n\n\tsample16 = (dma.samplebits/8) - 1;\n\n\tSNDDMA_BeginPainting ();\n\tif (dma.buffer)\n\t\tmemset(dma.buffer, 0, dma.samples * dma.samplebits/8);\n\tSNDDMA_Submit ();\n\treturn 1;\n}\n/*\n==============\nSNDDMA_GetDMAPos\n\nreturn the current sample position (in mono samples read)\ninside the recirculating dma buffer, so the mixing code will know\nhow many sample are required to fill it up.\n===============\n*/\nint SNDDMA_GetDMAPos( void ) {\n\tMMTIME\tmmtime;\n\tint\t\ts;\n\tDWORD\tdwWrite;\n\n\tif ( !dsound_init ) {\n\t\treturn 0;\n\t}\n\n\tmmtime.wType = TIME_SAMPLES;\n\tpDSBuf->lpVtbl->GetCurrentPosition(pDSBuf, &mmtime.u.sample, &dwWrite);\n\n\ts = mmtime.u.sample;\n\n\ts >>= sample16;\n\n\ts &= (dma.samples-1);\n\n\treturn s;\n}\n\n/*\n==============\nSNDDMA_BeginPainting\n\nMakes sure dma.buffer is valid\n===============\n*/\nvoid SNDDMA_BeginPainting( void ) {\n\tint\t\treps;\n\tDWORD\tdwSize2;\n\tDWORD\t*pbuf, *pbuf2;\n\tHRESULT\thresult;\n\tDWORD\tdwStatus;\n\n\tif ( !pDSBuf ) {\n\t\treturn;\n\t}\n\n\t// if the buffer was lost or stopped, restore it and/or restart it\n\tif ( pDSBuf->lpVtbl->GetStatus (pDSBuf, &dwStatus) != DS_OK ) {\n\t\tCom_Printf (\"Couldn't get sound buffer status\\n\");\n\t}\n\t\n\tif (dwStatus & DSBSTATUS_BUFFERLOST)\n\t\tpDSBuf->lpVtbl->Restore (pDSBuf);\n\t\n\tif (!(dwStatus & DSBSTATUS_PLAYING))\n\t\tpDSBuf->lpVtbl->Play(pDSBuf, 0, 0, DSBPLAY_LOOPING);\n\n\t// lock the dsound buffer\n\n\treps = 0;\n\tdma.buffer = NULL;\n\n\twhile ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, (LPVOID*) &pbuf, &locksize, \n\t\t\t\t\t\t\t\t   (LPVOID*) &pbuf2, &dwSize2, 0)) != DS_OK)\n\t{\n\t\tif (hresult != DSERR_BUFFERLOST)\n\t\t{\n\t\t\tCom_Printf( \"SNDDMA_BeginPainting: Lock failed with error '%s'\\n\", DSoundError( hresult ) );\n\t\t\tS_Shutdown ();\n\t\t\treturn;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tpDSBuf->lpVtbl->Restore( pDSBuf );\n\t\t}\n\n\t\tif (++reps > 2)\n\t\t\treturn;\n\t}\n\tdma.buffer = (unsigned char *)pbuf;\n}\n\n/*\n==============\nSNDDMA_Submit\n\nSend sound to device if buffer isn't really the dma buffer\nAlso unlocks the dsound buffer\n===============\n*/\nvoid SNDDMA_Submit( void ) {\n    // unlock the dsound buffer\n\tif ( pDSBuf ) {\n\t\tpDSBuf->lpVtbl->Unlock(pDSBuf, dma.buffer, locksize, NULL, 0);\n\t}\n}\n\n\n/*\n=================\nSNDDMA_Activate\n\nWhen we change windows we need to do this\n=================\n*/\nvoid SNDDMA_Activate( void ) {\n\tif ( !pDS ) {\n\t\treturn;\n\t}\n\n\tif ( DS_OK != pDS->lpVtbl->SetCooperativeLevel( pDS, g_wv.hWnd, DSSCL_PRIORITY ) )\t{\n\t\tCom_Printf (\"sound SetCooperativeLevel failed\\n\");\n\t\tSNDDMA_Shutdown ();\n\t}\n}\n\n\n"
  },
  {
    "path": "src/engine/platform/win_syscon.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n// win_syscon.h\n#include \"../client/client.h\"\n#include \"win_local.h\"\n#include \"resource.h\"\n#include <errno.h>\n#include <float.h>\n#include <fcntl.h>\n#include <stdio.h>\n#include <direct.h>\n#include <io.h>\n#include <conio.h>\n\n#define COPY_ID\t\t\t1\n#define QUIT_ID\t\t\t2\n#define CLEAR_ID\t\t3\n\n#define ERRORBOX_ID\t\t10\n#define ERRORTEXT_ID\t11\n\n#define EDIT_ID\t\t\t100\n#define INPUT_ID\t\t101\n\ntypedef struct\n{\n\tHWND\t\thWnd;\n\tHWND\t\thwndBuffer;\n\n\tHWND\t\thwndButtonClear;\n\tHWND\t\thwndButtonCopy;\n\tHWND\t\thwndButtonQuit;\n\n\tHWND\t\thwndErrorBox;\n\tHWND\t\thwndErrorText;\n\n\tHBITMAP\t\thbmLogo;\n\tHBITMAP\t\thbmClearBitmap;\n\n\tHBRUSH\t\thbrEditBackground;\n\tHBRUSH\t\thbrErrorBackground;\n\n\tHFONT\t\thfBufferFont;\n\tHFONT\t\thfButtonFont;\n\n\tHWND\t\thwndInputLine;\n\n\tchar\t\terrorString[80];\n\n\tchar\t\tconsoleText[512], returnedText[512];\n\tint\t\t\tvisLevel;\n\tqboolean\tquitOnClose;\n\tint\t\t\twindowWidth, windowHeight;\n\t\n\tWNDPROC\t\tSysInputLineWndProc;\n\n} WinConData;\n\nstatic WinConData s_wcd;\n\nstatic LRESULT WINAPI ConWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)\n{\n\tchar *cmdString;\n\tstatic qboolean s_timePolarity;\n\n\tswitch (uMsg)\n\t{\n\tcase WM_ACTIVATE:\n\t\tif ( LOWORD( wParam ) != WA_INACTIVE )\n\t\t{\n\t\t\tSetFocus( s_wcd.hwndInputLine );\n\t\t}\n\n\t\tif ( com_viewlog && ( com_dedicated && !com_dedicated->integer ) )\n\t\t{\n\t\t\t// if the viewlog is open, check to see if it's being minimized\n\t\t\tif ( com_viewlog->integer == 1 )\n\t\t\t{\n\t\t\t\tif ( HIWORD( wParam ) )\t\t// minimized flag\n\t\t\t\t{\n\t\t\t\t\tCvar_Set( \"viewlog\", \"2\" );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if ( com_viewlog->integer == 2 )\n\t\t\t{\n\t\t\t\tif ( !HIWORD( wParam ) )\t\t// minimized flag\n\t\t\t\t{\n\t\t\t\t\tCvar_Set( \"viewlog\", \"1\" );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tbreak;\n\n\tcase WM_CLOSE:\n\t\tif ( ( com_dedicated && com_dedicated->integer ) )\n\t\t{\n\t\t\tcmdString = CopyString( \"quit\" );\n\t\t\tSys_QueEvent( 0, SE_CONSOLE, 0, 0, (int)strlen( cmdString ) + 1, cmdString );\n\t\t}\n\t\telse if ( s_wcd.quitOnClose )\n\t\t{\n\t\t\tPostQuitMessage( 0 );\n\t\t}\n\t\telse\n\t\t{\n\t\t\tSys_ShowConsole( 0, qfalse );\n\t\t\tCvar_Set( \"viewlog\", \"0\" );\n\t\t}\n\t\treturn 0;\n\tcase WM_CTLCOLORSTATIC:\n\t\tif ( ( HWND ) lParam == s_wcd.hwndBuffer )\n\t\t{\n\t\t\tSetBkColor( ( HDC ) wParam, RGB( 0x00, 0x00, 0xB0 ) );\n\t\t\tSetTextColor( ( HDC ) wParam, RGB( 0xff, 0xff, 0x00 ) );\n\t\t\treturn ( LRESULT ) s_wcd.hbrEditBackground;\n\t\t}\n\t\telse if ( ( HWND ) lParam == s_wcd.hwndErrorBox )\n\t\t{\n\t\t\tif ( s_timePolarity & 1 )\n\t\t\t{\n\t\t\t\tSetBkColor( ( HDC ) wParam, RGB( 0x80, 0x80, 0x80 ) );\n\t\t\t\tSetTextColor( ( HDC ) wParam, RGB( 0xff, 0x0, 0x00 ) );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tSetBkColor( ( HDC ) wParam, RGB( 0x80, 0x80, 0x80 ) );\n\t\t\t\tSetTextColor( ( HDC ) wParam, RGB( 0x00, 0x0, 0x00 ) );\n\t\t\t}\n\t\t\treturn ( LRESULT ) s_wcd.hbrErrorBackground;\n\t\t}\n\t\tbreak;\n\n\tcase WM_COMMAND:\n\t\tif ( wParam == COPY_ID )\n\t\t{\n\t\t\tSendMessage( s_wcd.hwndBuffer, EM_SETSEL, 0, -1 );\n\t\t\tSendMessage( s_wcd.hwndBuffer, WM_COPY, 0, 0 );\n\t\t}\n\t\telse if ( wParam == QUIT_ID )\n\t\t{\n\t\t\tif ( s_wcd.quitOnClose )\n\t\t\t{\n\t\t\t\tPostQuitMessage( 0 );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcmdString = CopyString( \"quit\" );\n\t\t\t\tSys_QueEvent( 0, SE_CONSOLE, 0, 0, (int)strlen( cmdString ) + 1, cmdString );\n\t\t\t}\n\t\t}\n\t\telse if ( wParam == CLEAR_ID )\n\t\t{\n\t\t\tSendMessage( s_wcd.hwndBuffer, EM_SETSEL, 0, -1 );\n\t\t\tSendMessage( s_wcd.hwndBuffer, EM_REPLACESEL, FALSE, ( LPARAM ) \"\" );\n\t\t\tUpdateWindow( s_wcd.hwndBuffer );\n\t\t}\n\t\tbreak;\n\tcase WM_CREATE:\n\t\ts_wcd.hbrEditBackground = CreateSolidBrush( RGB( 0x00, 0x00, 0xB0 ) );\n\t\ts_wcd.hbrErrorBackground = CreateSolidBrush( RGB( 0x80, 0x80, 0x80 ) );\n\t\tSetTimer( hWnd, 1, 1000, NULL );\n\t\tbreak;\n\tcase WM_TIMER:\n\t\tif ( wParam == 1 )\n\t\t{\n\t\t\ts_timePolarity = (qboolean) !s_timePolarity;\n\t\t\tif ( s_wcd.hwndErrorBox )\n\t\t\t{\n\t\t\t\tInvalidateRect( s_wcd.hwndErrorBox, NULL, FALSE );\n\t\t\t}\n\t\t}\n\t\tbreak;\n    }\n\n    return DefWindowProc( hWnd, uMsg, wParam, lParam );\n}\n\nLONG WINAPI InputLineWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)\n{\n\tchar inputBuffer[1024];\n\n\tswitch ( uMsg )\n\t{\n\tcase WM_KILLFOCUS:\n\t\tif ( ( HWND ) wParam == s_wcd.hWnd ||\n\t\t\t ( HWND ) wParam == s_wcd.hwndErrorBox )\n\t\t{\n\t\t\tSetFocus( hWnd );\n\t\t\treturn 0;\n\t\t}\n\t\tbreak;\n\n\tcase WM_CHAR:\n\t\tif ( wParam == 13 )\n\t\t{\n\t\t\tGetWindowText( s_wcd.hwndInputLine, inputBuffer, sizeof( inputBuffer ) );\n\t\t\tstrncat( s_wcd.consoleText, inputBuffer, sizeof( s_wcd.consoleText ) - (int)strlen( s_wcd.consoleText ) - 5 );\n\t\t\tstrcat( s_wcd.consoleText, \"\\n\" );\n\t\t\tSetWindowText( s_wcd.hwndInputLine, \"\" );\n\n\t\t\tSys_Print( va( \"]%s\\n\", inputBuffer ) );\n\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\treturn CallWindowProc( s_wcd.SysInputLineWndProc, hWnd, uMsg, wParam, lParam );\n}\n\n/*\n** Sys_CreateConsole\n*/\nvoid Sys_CreateConsole( void )\n{\n\tHDC hDC;\n\tWNDCLASS wc;\n\tRECT rect;\n\tconst char *DEDCLASS = \"Q3 WinConsole\";\n\tint nHeight;\n\tint swidth, sheight;\n\tint DEDSTYLE = WS_POPUPWINDOW | WS_CAPTION | WS_MINIMIZEBOX;\n\n\tmemset( &wc, 0, sizeof( wc ) );\n\n\twc.style         = 0;\n\twc.lpfnWndProc   = (WNDPROC) ConWndProc;\n\twc.cbClsExtra    = 0;\n\twc.cbWndExtra    = 0;\n\twc.hInstance     = g_wv.hInstance;\n\twc.hIcon         = LoadIcon( g_wv.hInstance, MAKEINTRESOURCE(IDI_ICON1));\n\twc.hCursor       = LoadCursor (NULL,IDC_ARROW);\n\twc.hbrBackground = (HBRUSH) (void *)COLOR_WINDOW;\n\twc.lpszMenuName  = 0;\n\twc.lpszClassName = DEDCLASS;\n\n\tif ( !RegisterClass (&wc) )\n\t\treturn;\n\n\trect.left = 0;\n\trect.right = 540;\n\trect.top = 0;\n\trect.bottom = 450;\n\tAdjustWindowRect( &rect, DEDSTYLE, FALSE );\n\n\thDC = GetDC( GetDesktopWindow() );\n\tswidth = GetDeviceCaps( hDC, HORZRES );\n\tsheight = GetDeviceCaps( hDC, VERTRES );\n\tReleaseDC( GetDesktopWindow(), hDC );\n\n\ts_wcd.windowWidth = rect.right - rect.left + 1;\n\ts_wcd.windowHeight = rect.bottom - rect.top + 1;\n\n\ts_wcd.hWnd = CreateWindowEx( 0,\n\t\t\t\t\t\t\t   DEDCLASS,\n\t\t\t\t\t\t\t   \"Quake 3 Console\",\n\t\t\t\t\t\t\t   DEDSTYLE,\n\t\t\t\t\t\t\t   ( swidth - 600 ) / 2, ( sheight - 450 ) / 2 , rect.right - rect.left + 1, rect.bottom - rect.top + 1,\n\t\t\t\t\t\t\t   NULL,\n\t\t\t\t\t\t\t   NULL,\n\t\t\t\t\t\t\t   g_wv.hInstance,\n\t\t\t\t\t\t\t   NULL );\n\n\tif ( s_wcd.hWnd == NULL )\n\t{\n\t\treturn;\n\t}\n\n\t//\n\t// create fonts\n\t//\n\thDC = GetDC( s_wcd.hWnd );\n\tnHeight = -MulDiv( 8, GetDeviceCaps( hDC, LOGPIXELSY), 72);\n\n\ts_wcd.hfBufferFont = CreateFont( nHeight,\n\t\t\t\t\t\t\t\t\t  0,\n\t\t\t\t\t\t\t\t\t  0,\n\t\t\t\t\t\t\t\t\t  0,\n\t\t\t\t\t\t\t\t\t  FW_LIGHT,\n\t\t\t\t\t\t\t\t\t  0,\n\t\t\t\t\t\t\t\t\t  0,\n\t\t\t\t\t\t\t\t\t  0,\n\t\t\t\t\t\t\t\t\t  DEFAULT_CHARSET,\n\t\t\t\t\t\t\t\t\t  OUT_DEFAULT_PRECIS,\n\t\t\t\t\t\t\t\t\t  CLIP_DEFAULT_PRECIS,\n\t\t\t\t\t\t\t\t\t  DEFAULT_QUALITY,\n\t\t\t\t\t\t\t\t\t  FF_MODERN | FIXED_PITCH,\n\t\t\t\t\t\t\t\t\t  \"Courier New\" );\n\n\tReleaseDC( s_wcd.hWnd, hDC );\n\n\t//\n\t// create the input line\n\t//\n\ts_wcd.hwndInputLine = CreateWindow( \"edit\", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER | \n\t\t\t\t\t\t\t\t\t\t\t\tES_LEFT | ES_AUTOHSCROLL,\n\t\t\t\t\t\t\t\t\t\t\t\t6, 400, 528, 20,\n\t\t\t\t\t\t\t\t\t\t\t\ts_wcd.hWnd, \n\t\t\t\t\t\t\t\t\t\t\t\t( HMENU ) INPUT_ID,\t// child window ID\n\t\t\t\t\t\t\t\t\t\t\t\tg_wv.hInstance, NULL );\n\n\t//\n\t// create the buttons\n\t//\n\ts_wcd.hwndButtonCopy = CreateWindow( \"button\", NULL, BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,\n\t\t\t\t\t\t\t\t\t\t\t\t5, 425, 72, 24,\n\t\t\t\t\t\t\t\t\t\t\t\ts_wcd.hWnd, \n\t\t\t\t\t\t\t\t\t\t\t\t( HMENU ) COPY_ID,\t// child window ID\n\t\t\t\t\t\t\t\t\t\t\t\tg_wv.hInstance, NULL );\n\tSendMessage( s_wcd.hwndButtonCopy, WM_SETTEXT, 0, ( LPARAM ) \"copy\" );\n\n\ts_wcd.hwndButtonClear = CreateWindow( \"button\", NULL, BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,\n\t\t\t\t\t\t\t\t\t\t\t\t82, 425, 72, 24,\n\t\t\t\t\t\t\t\t\t\t\t\ts_wcd.hWnd, \n\t\t\t\t\t\t\t\t\t\t\t\t( HMENU ) CLEAR_ID,\t// child window ID\n\t\t\t\t\t\t\t\t\t\t\t\tg_wv.hInstance, NULL );\n\tSendMessage( s_wcd.hwndButtonClear, WM_SETTEXT, 0, ( LPARAM ) \"clear\" );\n\n\ts_wcd.hwndButtonQuit = CreateWindow( \"button\", NULL, BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,\n\t\t\t\t\t\t\t\t\t\t\t\t462, 425, 72, 24,\n\t\t\t\t\t\t\t\t\t\t\t\ts_wcd.hWnd, \n\t\t\t\t\t\t\t\t\t\t\t\t( HMENU ) QUIT_ID,\t// child window ID\n\t\t\t\t\t\t\t\t\t\t\t\tg_wv.hInstance, NULL );\n\tSendMessage( s_wcd.hwndButtonQuit, WM_SETTEXT, 0, ( LPARAM ) \"quit\" );\n\n\n\t//\n\t// create the scrollbuffer\n\t//\n\ts_wcd.hwndBuffer = CreateWindow( \"edit\", NULL, WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_BORDER | \n\t\t\t\t\t\t\t\t\t\t\t\tES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY,\n\t\t\t\t\t\t\t\t\t\t\t\t6, 40, 526, 354,\n\t\t\t\t\t\t\t\t\t\t\t\ts_wcd.hWnd, \n\t\t\t\t\t\t\t\t\t\t\t\t( HMENU ) EDIT_ID,\t// child window ID\n\t\t\t\t\t\t\t\t\t\t\t\tg_wv.hInstance, NULL );\n\tSendMessage( s_wcd.hwndBuffer, WM_SETFONT, ( WPARAM ) s_wcd.hfBufferFont, 0 );\n\n\ts_wcd.SysInputLineWndProc = (WNDPROC)SetWindowLongPtr(s_wcd.hwndInputLine, GWLP_WNDPROC, (LONG_PTR)InputLineWndProc);\n\tSendMessage( s_wcd.hwndInputLine, WM_SETFONT, ( WPARAM ) s_wcd.hfBufferFont, 0 );\n\n\tShowWindow( s_wcd.hWnd, SW_SHOWDEFAULT);\n\tUpdateWindow( s_wcd.hWnd );\n\tSetForegroundWindow( s_wcd.hWnd );\n\tSetFocus( s_wcd.hwndInputLine );\n\n\ts_wcd.visLevel = 1;\n}\n\n/*\n** Sys_DestroyConsole\n*/\nvoid Sys_DestroyConsole( void ) {\n\tif ( s_wcd.hWnd ) {\n\t\tShowWindow( s_wcd.hWnd, SW_HIDE );\n\t\tCloseWindow( s_wcd.hWnd );\n\t\tDestroyWindow( s_wcd.hWnd );\n\t\ts_wcd.hWnd = 0;\n\t}\n}\n\n/*\n** Sys_ShowConsole\n*/\nvoid Sys_ShowConsole( int visLevel, qboolean quitOnClose )\n{\n\ts_wcd.quitOnClose = quitOnClose;\n\n\tif ( visLevel == s_wcd.visLevel )\n\t{\n\t\treturn;\n\t}\n\n\ts_wcd.visLevel = visLevel;\n\n\tif ( !s_wcd.hWnd )\n\t\treturn;\n\n\tswitch ( visLevel )\n\t{\n\tcase 0:\n\t\tShowWindow( s_wcd.hWnd, SW_HIDE );\n\t\tbreak;\n\tcase 1:\n\t\tShowWindow( s_wcd.hWnd, SW_SHOWNORMAL );\n\t\tSendMessage( s_wcd.hwndBuffer, EM_LINESCROLL, 0, 0xffff );\n\t\tbreak;\n\tcase 2:\n\t\tShowWindow( s_wcd.hWnd, SW_MINIMIZE );\n\t\tbreak;\n\tdefault:\n\t\tSys_Error( \"Invalid visLevel %d sent to Sys_ShowConsole\\n\", visLevel );\n\t\tbreak;\n\t}\n}\n\n/*\n** Sys_ConsoleInput\n*/\nchar *Sys_ConsoleInput( void )\n{\n\tif ( s_wcd.consoleText[0] == 0 )\n\t{\n\t\treturn NULL;\n\t}\n\t\t\n\tstrcpy( s_wcd.returnedText, s_wcd.consoleText );\n\ts_wcd.consoleText[0] = 0;\n\t\n\treturn s_wcd.returnedText;\n}\n\n/*\n** Conbuf_AppendText\n*/\nvoid Conbuf_AppendText( const char *pMsg )\n{\n#define CONSOLE_BUFFER_SIZE\t\t16384\n\n\tchar buffer[CONSOLE_BUFFER_SIZE*2];\n\tchar *b = buffer;\n\tconst char *msg;\n\tint bufLen;\n\tint i = 0;\n\tstatic unsigned long s_totalChars;\n\n\t//\n\t// if the message is REALLY long, use just the last portion of it\n\t//\n\tif ( (int)strlen( pMsg ) > CONSOLE_BUFFER_SIZE - 1 )\n\t{\n\t\tmsg = pMsg + (int)strlen( pMsg ) - CONSOLE_BUFFER_SIZE + 1;\n\t}\n\telse\n\t{\n\t\tmsg = pMsg;\n\t}\n\n\t//\n\t// copy into an intermediate buffer\n\t//\n\twhile ( msg[i] && ( ( b - buffer ) < sizeof( buffer ) - 1 ) )\n\t{\n\t\tif ( msg[i] == '\\n' && msg[i+1] == '\\r' )\n\t\t{\n\t\t\tb[0] = '\\r';\n\t\t\tb[1] = '\\n';\n\t\t\tb += 2;\n\t\t\ti++;\n\t\t}\n\t\telse if ( msg[i] == '\\r' )\n\t\t{\n\t\t\tb[0] = '\\r';\n\t\t\tb[1] = '\\n';\n\t\t\tb += 2;\n\t\t}\n\t\telse if ( msg[i] == '\\n' )\n\t\t{\n\t\t\tb[0] = '\\r';\n\t\t\tb[1] = '\\n';\n\t\t\tb += 2;\n\t\t}\n\t\telse if ( Q_IsColorString( &msg[i] ) )\n\t\t{\n\t\t\ti++;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t*b= msg[i];\n\t\t\tb++;\n\t\t}\n\t\ti++;\n\t}\n\t*b = 0;\n\tbufLen = b - buffer;\n\n\ts_totalChars += bufLen;\n\n\t//\n\t// replace selection instead of appending if we're overflowing\n\t//\n\tif ( s_totalChars > 0x7fff )\n\t{\n\t\tSendMessage( s_wcd.hwndBuffer, EM_SETSEL, 0, -1 );\n\t\ts_totalChars = bufLen;\n\t}\n\n\t//\n\t// put this text into the windows console\n\t//\n\tSendMessage( s_wcd.hwndBuffer, EM_LINESCROLL, 0, 0xffff );\n\tSendMessage( s_wcd.hwndBuffer, EM_SCROLLCARET, 0, 0 );\n\tSendMessage( s_wcd.hwndBuffer, EM_REPLACESEL, 0, (LPARAM) buffer );\n}\n\n/*\n** Sys_SetErrorText\n*/\nvoid Sys_SetErrorText( const char *buf )\n{\n\tQ_strncpyz( s_wcd.errorString, buf, sizeof( s_wcd.errorString ) );\n\n\tif ( !s_wcd.hwndErrorBox )\n\t{\n\t\ts_wcd.hwndErrorBox = CreateWindow( \"static\", NULL, WS_CHILD | WS_VISIBLE | SS_SUNKEN,\n\t\t\t\t\t\t\t\t\t\t\t\t\t6, 5, 526, 30,\n\t\t\t\t\t\t\t\t\t\t\t\t\ts_wcd.hWnd, \n\t\t\t\t\t\t\t\t\t\t\t\t\t( HMENU ) ERRORBOX_ID,\t// child window ID\n\t\t\t\t\t\t\t\t\t\t\t\t\tg_wv.hInstance, NULL );\n\t\tSendMessage( s_wcd.hwndErrorBox, WM_SETFONT, ( WPARAM ) s_wcd.hfBufferFont, 0 );\n\t\tSetWindowText( s_wcd.hwndErrorBox, s_wcd.errorString );\n\n\t\tDestroyWindow( s_wcd.hwndInputLine );\n\t\ts_wcd.hwndInputLine = NULL;\n\t}\n}\n"
  },
  {
    "path": "src/engine/platform/win_wndproc.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n#include \"../client/client.h\"\n#include \"win_local.h\"\n\nWinVars_t\tg_wv;\n\n#ifndef WM_MOUSEWHEEL\n#define WM_MOUSEWHEEL (WM_MOUSELAST+1)  // message that will be supported by the OS \n#endif\n\n// Console variables that we need to access from this module\ncvar_t\t\t*vid_xpos;\t\t\t// X coordinate of window position\ncvar_t\t\t*vid_ypos;\t\t\t// Y coordinate of window position\nextern cvar_t *r_fullscreen;\n\n#define VID_NUM_MODES ( sizeof( vid_modes ) / sizeof( vid_modes[0] ) )\n\nLONG WINAPI MainWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );\n\n/*\n==================\nVID_AppActivate\n==================\n*/\nstatic void VID_AppActivate(BOOL fActive, BOOL minimize)\n{\n\tg_wv.isMinimized = (qboolean) minimize;\n\n\tCom_DPrintf(\"VID_AppActivate: %i\\n\", fActive );\n\n\tKey_ClearStates();\t// FIXME!!!\n\n\t// we don't want to act like we're active if we're minimized\n\tif (fActive && !g_wv.isMinimized )\n\t{\n\t\tg_wv.activeApp = qtrue;\n\t}\n\telse\n\t{\n\t\tg_wv.activeApp = qfalse;\n\t}\n\n\t// minimize/restore mouse-capture on demand\n\tif (!g_wv.activeApp )\n\t{\n\t\tIN_Activate (qfalse);\n\t}\n\telse\n\t{\n\t\tIN_Activate (qtrue);\n\t}\n}\n\n//==========================================================================\n\nstatic byte s_scantokey[128] = \n\t\t\t\t\t{ \n//  0           1       2       3       4       5       6       7 \n//  8           9       A       B       C       D       E       F \n\t0  ,    27,     '1',    '2',    '3',    '4',    '5',    '6', \n\t'7',    '8',    '9',    '0',    '-',    '=',    K_BACKSPACE, 9, // 0 \n\t'q',    'w',    'e',    'r',    't',    'y',    'u',    'i', \n\t'o',    'p',    '[',    ']',    13 ,    K_CTRL,'a',  's',      // 1 \n\t'd',    'f',    'g',    'h',    'j',    'k',    'l',    ';', \n\t'\\'' ,    '`',    K_SHIFT,'\\\\',  'z',    'x',    'c',    'v',      // 2 \n\t'b',    'n',    'm',    ',',    '.',    '/',    K_SHIFT,'*', \n\tK_ALT,' ',   K_CAPSLOCK  ,    K_F1, K_F2, K_F3, K_F4, K_F5,   // 3 \n\tK_F6, K_F7, K_F8, K_F9, K_F10,  K_PAUSE,    0  , K_HOME, \n\tK_UPARROW,K_PGUP,K_KP_MINUS,K_LEFTARROW,K_KP_5,K_RIGHTARROW, K_KP_PLUS,K_END, //4 \n\tK_DOWNARROW,K_PGDN,K_INS,K_DEL,0,0,             0,              K_F11, \n\tK_F12,0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0,        // 5\n\t0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0, \n\t0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0,        // 6 \n\t0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0, \n\t0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0         // 7 \n}; \n\n/*\n=======\nMapKey\n\nMap from windows to quake keynums\n=======\n*/\nstatic int MapKey (int key)\n{\n\tint result;\n\tint modified;\n\tqboolean is_extended;\n\n//\tCom_Printf( \"0x%x\\n\", key);\n\n\tmodified = ( key >> 16 ) & 255;\n\n\tif ( modified > 127 )\n\t\treturn 0;\n\n\tif ( key & ( 1 << 24 ) )\n\t{\n\t\tis_extended = qtrue;\n\t}\n\telse\n\t{\n\t\tis_extended = qfalse;\n\t}\n\n\tresult = s_scantokey[modified];\n\n\tif ( !is_extended )\n\t{\n\t\tswitch ( result )\n\t\t{\n\t\tcase K_HOME:\n\t\t\treturn K_KP_HOME;\n\t\tcase K_UPARROW:\n\t\t\treturn K_KP_UPARROW;\n\t\tcase K_PGUP:\n\t\t\treturn K_KP_PGUP;\n\t\tcase K_LEFTARROW:\n\t\t\treturn K_KP_LEFTARROW;\n\t\tcase K_RIGHTARROW:\n\t\t\treturn K_KP_RIGHTARROW;\n\t\tcase K_END:\n\t\t\treturn K_KP_END;\n\t\tcase K_DOWNARROW:\n\t\t\treturn K_KP_DOWNARROW;\n\t\tcase K_PGDN:\n\t\t\treturn K_KP_PGDN;\n\t\tcase K_INS:\n\t\t\treturn K_KP_INS;\n\t\tcase K_DEL:\n\t\t\treturn K_KP_DEL;\n\t\tdefault:\n\t\t\treturn result;\n\t\t}\n\t}\n\telse\n\t{\n\t\tswitch ( result )\n\t\t{\n\t\tcase K_PAUSE:\n\t\t\treturn K_KP_NUMLOCK;\n\t\tcase 0x0D:\n\t\t\treturn K_KP_ENTER;\n\t\tcase 0x2F:\n\t\t\treturn K_KP_SLASH;\n\t\tcase 0xAF:\n\t\t\treturn K_KP_PLUS;\n\t\t}\n\t\treturn result;\n\t}\n}\n\n\n/*\n====================\nMainWndProc\n\nmain window procedure\n====================\n*/\nextern cvar_t *in_mouse;\nextern cvar_t *in_logitechbug;\nLONG WINAPI MainWndProc (\n    HWND    hWnd,\n    UINT    uMsg,\n    WPARAM  wParam,\n    LPARAM  lParam)\n{\n\tstatic qboolean flip = qtrue;\n\tint zDelta, i;\n\n\tswitch (uMsg)\n\t{\n\tcase WM_MOUSEWHEEL:\n\t\t{\n\t\t\t// 120 increments, might be 240 and multiples if wheel goes too fast\n\t\t\t// NOTE Logitech: logitech drivers are screwed and send the message twice?\n\t\t\t//   could add a cvar to interpret the message as successive press/release events\n\t\t\tzDelta = ( short ) HIWORD( wParam ) / 120;\n\t\t\tif ( zDelta > 0 )\n\t\t\t{\n\t\t\t\tfor(i=0; i<zDelta; i++)\n\t\t\t\t{\n\t\t\t\t\tif (!in_logitechbug->integer)\n\t\t\t\t\t{\n\t\t\t\t\t\tSys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_MWHEELUP, qtrue, 0, NULL );\n\t\t\t\t\t\tSys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_MWHEELUP, qfalse, 0, NULL );\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tSys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_MWHEELUP, flip, 0, NULL );\n\t\t\t\t\t\tflip = (qboolean) !flip;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tfor(i=0; i<-zDelta; i++)\n\t\t\t\t{\n\t\t\t\t\tif (!in_logitechbug->integer)\n\t\t\t\t\t{\n\t\t\t\t\t\tSys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_MWHEELDOWN, qtrue, 0, NULL );\n\t\t\t\t\t\tSys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_MWHEELDOWN, qfalse, 0, NULL );\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tSys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_MWHEELDOWN, flip, 0, NULL );\n\t\t\t\t\t\tflip = (qboolean) !flip;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// when an application processes the WM_MOUSEWHEEL message, it must return zero\n\t\t\treturn 0;\n\t\t}\n\t\tbreak;\n\n\tcase WM_CREATE:\n\n\t\tg_wv.hWnd = hWnd;\n\n\t\tvid_xpos = Cvar_Get (\"vid_xpos\", \"3\", CVAR_ARCHIVE);\n\t\tvid_ypos = Cvar_Get (\"vid_ypos\", \"22\", CVAR_ARCHIVE);\n\t\tr_fullscreen = Cvar_Get (\"r_fullscreen\", \"1\", CVAR_ARCHIVE | CVAR_LATCH );\n\n\t\tbreak;\n\n\tcase WM_DESTROY:\n\t\t// let sound and input know about this?\n\t\tg_wv.hWnd = NULL;\n\t\tbreak;\n\n\tcase WM_CLOSE:\n\t\tCbuf_ExecuteText( EXEC_APPEND, \"quit\" );\n\t\tbreak;\n\n\tcase WM_ACTIVATE:\n\t\t{\n\t\t\tint\tfActive, fMinimized;\n\n\t\t\tfActive = LOWORD(wParam);\n\t\t\tfMinimized = (BOOL) HIWORD(wParam);\n\n\t\t\tVID_AppActivate( fActive != WA_INACTIVE, fMinimized);\n\t\t\tSNDDMA_Activate();\n\t\t}\n\t\tbreak;\n\n\tcase WM_MOVE:\n\t\t{\n\t\t\tint\t\txPos, yPos;\n\t\t\tRECT r;\n\t\t\tint\t\tstyle;\n\n\t\t\tif (!r_fullscreen->integer )\n\t\t\t{\n\t\t\t\txPos = (short) LOWORD(lParam);    // horizontal position \n\t\t\t\tyPos = (short) HIWORD(lParam);    // vertical position \n\n\t\t\t\tr.left   = 0;\n\t\t\t\tr.top    = 0;\n\t\t\t\tr.right  = 1;\n\t\t\t\tr.bottom = 1;\n\n\t\t\t\tstyle = GetWindowLong( hWnd, GWL_STYLE );\n\t\t\t\tAdjustWindowRect( &r, style, FALSE );\n\n\t\t\t\tCvar_SetValue( \"vid_xpos\", xPos + r.left);\n\t\t\t\tCvar_SetValue( \"vid_ypos\", yPos + r.top);\n\t\t\t\tvid_xpos->modified = qfalse;\n\t\t\t\tvid_ypos->modified = qfalse;\n\t\t\t\tif ( g_wv.activeApp )\n\t\t\t\t{\n\t\t\t\t\tIN_Activate (qtrue);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tbreak;\n\n// this is complicated because Win32 seems to pack multiple mouse events into\n// one update sometimes, so we always check all states and look for events\n\tcase WM_LBUTTONDOWN:\n\tcase WM_LBUTTONUP:\n\tcase WM_RBUTTONDOWN:\n\tcase WM_RBUTTONUP:\n\tcase WM_MBUTTONDOWN:\n\tcase WM_MBUTTONUP:\n\tcase WM_MOUSEMOVE:\n\t\t{\n\t\t\tint\ttemp;\n\n\t\t\ttemp = 0;\n\n\t\t\tif (wParam & MK_LBUTTON)\n\t\t\t\ttemp |= 1;\n\n\t\t\tif (wParam & MK_RBUTTON)\n\t\t\t\ttemp |= 2;\n\n\t\t\tif (wParam & MK_MBUTTON)\n\t\t\t\ttemp |= 4;\n\n\t\t\tIN_MouseEvent (temp);\n\t\t}\n\t\tbreak;\n\n\tcase WM_SYSCOMMAND:\n\t\tif ( wParam == SC_SCREENSAVE )\n\t\t\treturn 0;\n\t\tbreak;\n\n\tcase WM_SYSKEYDOWN:\n\t\tif ( wParam == 13 )\n\t\t{\n\t\t\tif ( r_fullscreen )\n\t\t\t{\n\t\t\t\tCvar_SetValue( \"r_fullscreen\", !r_fullscreen->integer );\n\t\t\t\tCbuf_AddText( \"vid_restart\\n\" );\n\t\t\t}\n\t\t\treturn 0;\n\t\t}\n\t\t// fall through\n\tcase WM_KEYDOWN:\n\t\tSys_QueEvent( g_wv.sysMsgTime, SE_KEY, MapKey( lParam ), qtrue, 0, NULL );\n\t\tbreak;\n\n\tcase WM_SYSKEYUP:\n\tcase WM_KEYUP:\n\t\tSys_QueEvent( g_wv.sysMsgTime, SE_KEY, MapKey( lParam ), qfalse, 0, NULL );\n\t\tbreak;\n\n\tcase WM_CHAR:\n\t\tSys_QueEvent( g_wv.sysMsgTime, SE_CHAR, wParam, 0, 0, NULL );\n\t\tbreak;\n   }\n\n    return DefWindowProc( hWnd, uMsg, wParam, lParam );\n}\n\n"
  },
  {
    "path": "src/engine/platform/winquake.rc",
    "content": "//Microsoft Developer Studio generated resource script.\n//\n#include \"resource.h\"\n\n#define APSTUDIO_READONLY_SYMBOLS\n/////////////////////////////////////////////////////////////////////////////\n//\n// Generated from the TEXTINCLUDE 2 resource.\n//\n#include \"winres.h\"\n\n/////////////////////////////////////////////////////////////////////////////\n#undef APSTUDIO_READONLY_SYMBOLS\n\n/////////////////////////////////////////////////////////////////////////////\n// English (U.S.) resources\n\n#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\n#ifdef _WIN32\nLANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\n#pragma code_page(1252)\n#endif //_WIN32\n\n#ifdef APSTUDIO_INVOKED\n/////////////////////////////////////////////////////////////////////////////\n//\n// TEXTINCLUDE\n//\n\n1 TEXTINCLUDE DISCARDABLE \nBEGIN\n    \"resource.h\\0\"\nEND\n\n2 TEXTINCLUDE DISCARDABLE \nBEGIN\n    \"#include \"\"winres.h\"\"\\r\\n\"\n    \"\\0\"\nEND\n\n3 TEXTINCLUDE DISCARDABLE \nBEGIN\n    \"\\0\"\nEND\n\n#endif    // APSTUDIO_INVOKED\n\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// Icon\n//\n\n// Icon with lowest ID value placed first to ensure application icon\n// remains consistent on all systems.\nIDI_ICON1               ICON    DISCARDABLE     \"qe3.ico\"\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// String Table\n//\n\nSTRINGTABLE DISCARDABLE \nBEGIN\n    IDS_STRING1             \"Quake3\"\nEND\n\n#endif    // English (U.S.) resources\n/////////////////////////////////////////////////////////////////////////////\n\n\n"
  },
  {
    "path": "src/engine/qcommon/cm_load.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n// cmodel.c -- model loading\n\n#include \"cm_local.h\"\n\n#ifdef BSPC\n\n#include \"../bspc/l_qfiles.h\"\n\nvoid SetPlaneSignbits (cplane_t *out) {\n\tint\tbits, j;\n\n\t// for fast box on planeside test\n\tbits = 0;\n\tfor (j=0 ; j<3 ; j++) {\n\t\tif (out->normal[j] < 0) {\n\t\t\tbits |= 1<<j;\n\t\t}\n\t}\n\tout->signbits = bits;\n}\n#endif //BSPC\n\n// to allow boxes to be treated as brush models, we allocate\n// some extra indexes along with those needed by the map\n#define\tBOX_BRUSHES\t\t1\n#define\tBOX_SIDES\t\t6\n#define\tBOX_LEAFS\t\t2\n#define\tBOX_PLANES\t\t12\n\n#define\tLL(x) x=LittleLong(x)\n\n\nclipMap_t\tcm;\nint\t\t\tc_pointcontents;\nint\t\t\tc_traces, c_brush_traces, c_patch_traces;\n\n\nbyte\t\t*cmod_base;\n\n#ifndef BSPC\ncvar_t\t\t*cm_noAreas;\ncvar_t\t\t*cm_noCurves;\ncvar_t\t\t*cm_playerCurveClip;\n#endif\n\ncmodel_t\tbox_model;\ncplane_t\t*box_planes;\ncbrush_t\t*box_brush;\n\n\n\nvoid\tCM_InitBoxHull (void);\nvoid\tCM_FloodAreaConnections (void);\n\n\n/*\n===============================================================================\n\n\t\t\t\t\tMAP LOADING\n\n===============================================================================\n*/\n\n/*\n=================\nCMod_LoadShaders\n=================\n*/\nvoid CMod_LoadShaders( lump_t *l ) {\n\tdshader_t\t*in, *out;\n\tint\t\t\ti, count;\n\n\tin = (dshader_t*) (void *)(cmod_base + l->fileofs);\n\tif (l->filelen % sizeof(*in)) {\n\t\tCom_Error (ERR_DROP, \"CMod_LoadShaders: funny lump size\");\n\t}\n\tcount = l->filelen / sizeof(*in);\n\n\tif (count < 1) {\n\t\tCom_Error (ERR_DROP, \"Map with no shaders\");\n\t}\n\tcm.shaders = (dshader_t*) Hunk_Alloc( count * sizeof( *cm.shaders ), h_high );\n\tcm.numShaders = count;\n\n\tCom_Memcpy( cm.shaders, in, count * sizeof( *cm.shaders ) );\n\n\tout = cm.shaders;\n\tfor ( i=0 ; i<count ; i++, in++, out++ ) {\n\t\tout->contentFlags = LittleLong( out->contentFlags );\n\t\tout->surfaceFlags = LittleLong( out->surfaceFlags );\n\t}\n}\n\n\n/*\n=================\nCMod_LoadSubmodels\n=================\n*/\nvoid CMod_LoadSubmodels( lump_t *l ) {\n\tdmodel_t\t*in;\n\tcmodel_t\t*out;\n\tint\t\t\ti, j, count;\n\tint\t\t\t*indexes;\n\n\tin = (dmodel_t*) (void *)(cmod_base + l->fileofs);\n\tif (l->filelen % sizeof(*in))\n\t\tCom_Error (ERR_DROP, \"CMod_LoadSubmodels: funny lump size\");\n\tcount = l->filelen / sizeof(*in);\n\n\tif (count < 1)\n\t\tCom_Error (ERR_DROP, \"Map with no models\");\n\tcm.cmodels = (cmodel_t*) Hunk_Alloc( count * sizeof( *cm.cmodels ), h_high );\n\tcm.numSubModels = count;\n\n\tif ( count > MAX_SUBMODELS ) {\n\t\tCom_Error( ERR_DROP, \"MAX_SUBMODELS exceeded\" );\n\t}\n\n\tfor ( i=0 ; i<count ; i++, in++, out++)\n\t{\n\t\tout = &cm.cmodels[i];\n\n\t\tfor (j=0 ; j<3 ; j++)\n\t\t{\t// spread the mins / maxs by a pixel\n\t\t\tout->mins[j] = LittleFloat (in->mins[j]) - 1;\n\t\t\tout->maxs[j] = LittleFloat (in->maxs[j]) + 1;\n\t\t}\n\n\t\tif ( i == 0 ) {\n\t\t\tcontinue;\t// world model doesn't need other info\n\t\t}\n\n\t\t// make a \"leaf\" just to hold the model's brushes and surfaces\n\t\tout->leaf.numLeafBrushes = LittleLong( in->numBrushes );\n\t\tindexes = (int*) Hunk_Alloc( out->leaf.numLeafBrushes * 4, h_high );\n\t\tout->leaf.firstLeafBrush = indexes - cm.leafbrushes;\n\t\tfor ( j = 0 ; j < out->leaf.numLeafBrushes ; j++ ) {\n\t\t\tindexes[j] = LittleLong( in->firstBrush ) + j;\n\t\t}\n\n\t\tout->leaf.numLeafSurfaces = LittleLong( in->numSurfaces );\n\t\tindexes = (int*) Hunk_Alloc( out->leaf.numLeafSurfaces * 4, h_high );\n\t\tout->leaf.firstLeafSurface = indexes - cm.leafsurfaces;\n\t\tfor ( j = 0 ; j < out->leaf.numLeafSurfaces ; j++ ) {\n\t\t\tindexes[j] = LittleLong( in->firstSurface ) + j;\n\t\t}\n\t}\n}\n\n\n/*\n=================\nCMod_LoadNodes\n\n=================\n*/\nvoid CMod_LoadNodes( lump_t *l ) {\n\tdnode_t\t\t*in;\n\tint\t\t\tchild;\n\tcNode_t\t\t*out;\n\tint\t\t\ti, j, count;\n\t\n\tin = (dnode_t*) (void *)(cmod_base + l->fileofs);\n\tif (l->filelen % sizeof(*in))\n\t\tCom_Error (ERR_DROP, \"MOD_LoadBmodel: funny lump size\");\n\tcount = l->filelen / sizeof(*in);\n\n\tif (count < 1)\n\t\tCom_Error (ERR_DROP, \"Map has no nodes\");\n\tcm.nodes = (cNode_t*) Hunk_Alloc( count * sizeof( *cm.nodes ), h_high );\n\tcm.numNodes = count;\n\n\tout = cm.nodes;\n\n\tfor (i=0 ; i<count ; i++, out++, in++)\n\t{\n\t\tout->plane = cm.planes + LittleLong( in->planeNum );\n\t\tfor (j=0 ; j<2 ; j++)\n\t\t{\n\t\t\tchild = LittleLong (in->children[j]);\n\t\t\tout->children[j] = child;\n\t\t}\n\t}\n\n}\n\n/*\n=================\nCM_BoundBrush\n\n=================\n*/\nvoid CM_BoundBrush( cbrush_t *b ) {\n\tb->bounds[0][0] = -b->sides[0].plane->dist;\n\tb->bounds[1][0] = b->sides[1].plane->dist;\n\n\tb->bounds[0][1] = -b->sides[2].plane->dist;\n\tb->bounds[1][1] = b->sides[3].plane->dist;\n\n\tb->bounds[0][2] = -b->sides[4].plane->dist;\n\tb->bounds[1][2] = b->sides[5].plane->dist;\n}\n\n\n/*\n=================\nCMod_LoadBrushes\n\n=================\n*/\nvoid CMod_LoadBrushes( lump_t *l ) {\n\tdbrush_t\t*in;\n\tcbrush_t\t*out;\n\tint\t\t\ti, count;\n\n\tin = (dbrush_t*) (void *)(cmod_base + l->fileofs);\n\tif (l->filelen % sizeof(*in)) {\n\t\tCom_Error (ERR_DROP, \"MOD_LoadBmodel: funny lump size\");\n\t}\n\tcount = l->filelen / sizeof(*in);\n\n\tcm.brushes = (cbrush_t*) Hunk_Alloc( ( BOX_BRUSHES + count ) * sizeof( *cm.brushes ), h_high );\n\tcm.numBrushes = count;\n\n\tout = cm.brushes;\n\n\tfor ( i=0 ; i<count ; i++, out++, in++ ) {\n\t\tout->sides = cm.brushsides + LittleLong(in->firstSide);\n\t\tout->numsides = LittleLong(in->numSides);\n\n\t\tout->shaderNum = LittleLong( in->shaderNum );\n\t\tif ( out->shaderNum < 0 || out->shaderNum >= cm.numShaders ) {\n\t\t\tCom_Error( ERR_DROP, \"CMod_LoadBrushes: bad shaderNum: %i\", out->shaderNum );\n\t\t}\n\t\tout->contents = cm.shaders[out->shaderNum].contentFlags;\n\n\t\tCM_BoundBrush( out );\n\t}\n\n}\n\n/*\n=================\nCMod_LoadLeafs\n=================\n*/\nvoid CMod_LoadLeafs (lump_t *l)\n{\n\tint\t\t\ti;\n\tcLeaf_t\t\t*out;\n\tdleaf_t \t*in;\n\tint\t\t\tcount;\n\t\n\tin = (dleaf_t*) (void *)(cmod_base + l->fileofs);\n\tif (l->filelen % sizeof(*in))\n\t\tCom_Error (ERR_DROP, \"MOD_LoadBmodel: funny lump size\");\n\tcount = l->filelen / sizeof(*in);\n\n\tif (count < 1)\n\t\tCom_Error (ERR_DROP, \"Map with no leafs\");\n\n\tcm.leafs = (cLeaf_t*) Hunk_Alloc( ( BOX_LEAFS + count ) * sizeof( *cm.leafs ), h_high );\n\tcm.numLeafs = count;\n\n\tout = cm.leafs;\t\n\tfor ( i=0 ; i<count ; i++, in++, out++)\n\t{\n\t\tout->cluster = LittleLong (in->cluster);\n\t\tout->area = LittleLong (in->area);\n\t\tout->firstLeafBrush = LittleLong (in->firstLeafBrush);\n\t\tout->numLeafBrushes = LittleLong (in->numLeafBrushes);\n\t\tout->firstLeafSurface = LittleLong (in->firstLeafSurface);\n\t\tout->numLeafSurfaces = LittleLong (in->numLeafSurfaces);\n\n\t\tif (out->cluster >= cm.numClusters)\n\t\t\tcm.numClusters = out->cluster + 1;\n\t\tif (out->area >= cm.numAreas)\n\t\t\tcm.numAreas = out->area + 1;\n\t}\n\n\tcm.areas = (cArea_t*) Hunk_Alloc( cm.numAreas * sizeof( *cm.areas ), h_high );\n\tcm.areaPortals = (int*) Hunk_Alloc( cm.numAreas * cm.numAreas * sizeof( *cm.areaPortals ), h_high );\n}\n\n/*\n=================\nCMod_LoadPlanes\n=================\n*/\nvoid CMod_LoadPlanes (lump_t *l)\n{\n\tint\t\t\ti, j;\n\tcplane_t\t*out;\n\tdplane_t \t*in;\n\tint\t\t\tcount;\n\tint\t\t\tbits;\n\t\n\tin = (dplane_t*) (void *)(cmod_base + l->fileofs);\n\tif (l->filelen % sizeof(*in))\n\t\tCom_Error (ERR_DROP, \"MOD_LoadBmodel: funny lump size\");\n\tcount = l->filelen / sizeof(*in);\n\n\tif (count < 1)\n\t\tCom_Error (ERR_DROP, \"Map with no planes\");\n\tcm.planes = (cplane_t*) Hunk_Alloc( ( BOX_PLANES + count ) * sizeof( *cm.planes ), h_high );\n\tcm.numPlanes = count;\n\n\tout = cm.planes;\t\n\n\tfor ( i=0 ; i<count ; i++, in++, out++)\n\t{\n\t\tbits = 0;\n\t\tfor (j=0 ; j<3 ; j++)\n\t\t{\n\t\t\tout->normal[j] = LittleFloat (in->normal[j]);\n\t\t\tif (out->normal[j] < 0)\n\t\t\t\tbits |= 1<<j;\n\t\t}\n\n\t\tout->dist = LittleFloat (in->dist);\n\t\tout->type = PlaneTypeForNormal( out->normal );\n\t\tout->signbits = bits;\n\t}\n}\n\n/*\n=================\nCMod_LoadLeafBrushes\n=================\n*/\nvoid CMod_LoadLeafBrushes (lump_t *l)\n{\n\tint\t\t\ti;\n\tint\t\t\t*out;\n\tint\t\t \t*in;\n\tint\t\t\tcount;\n\t\n\tin = (int*) (void *)(cmod_base + l->fileofs);\n\tif (l->filelen % sizeof(*in))\n\t\tCom_Error (ERR_DROP, \"MOD_LoadBmodel: funny lump size\");\n\tcount = l->filelen / sizeof(*in);\n\n\tcm.leafbrushes = (int*) Hunk_Alloc( (count + BOX_BRUSHES) * sizeof( *cm.leafbrushes ), h_high );\n\tcm.numLeafBrushes = count;\n\n\tout = cm.leafbrushes;\n\n\tfor ( i=0 ; i<count ; i++, in++, out++) {\n\t\t*out = LittleLong (*in);\n\t}\n}\n\n/*\n=================\nCMod_LoadLeafSurfaces\n=================\n*/\nvoid CMod_LoadLeafSurfaces( lump_t *l )\n{\n\tint\t\t\ti;\n\tint\t\t\t*out;\n\tint\t\t \t*in;\n\tint\t\t\tcount;\n\t\n\tin = (int*) (void *)(cmod_base + l->fileofs);\n\tif (l->filelen % sizeof(*in))\n\t\tCom_Error (ERR_DROP, \"MOD_LoadBmodel: funny lump size\");\n\tcount = l->filelen / sizeof(*in);\n\n\tcm.leafsurfaces = (int*) Hunk_Alloc( count * sizeof( *cm.leafsurfaces ), h_high );\n\tcm.numLeafSurfaces = count;\n\n\tout = cm.leafsurfaces;\n\n\tfor ( i=0 ; i<count ; i++, in++, out++) {\n\t\t*out = LittleLong (*in);\n\t}\n}\n\n/*\n=================\nCMod_LoadBrushSides\n=================\n*/\nvoid CMod_LoadBrushSides (lump_t *l)\n{\n\tint\t\t\t\ti;\n\tcbrushside_t\t*out;\n\tdbrushside_t \t*in;\n\tint\t\t\t\tcount;\n\tint\t\t\t\tnum;\n\n\tin = (dbrushside_t*) (void *)(cmod_base + l->fileofs);\n\tif ( l->filelen % sizeof(*in) ) {\n\t\tCom_Error (ERR_DROP, \"MOD_LoadBmodel: funny lump size\");\n\t}\n\tcount = l->filelen / sizeof(*in);\n\n\tcm.brushsides = (cbrushside_t*) Hunk_Alloc( ( BOX_SIDES + count ) * sizeof( *cm.brushsides ), h_high );\n\tcm.numBrushSides = count;\n\n\tout = cm.brushsides;\t\n\n\tfor ( i=0 ; i<count ; i++, in++, out++) {\n\t\tnum = LittleLong( in->planeNum );\n\t\tout->plane = &cm.planes[num];\n\t\tout->shaderNum = LittleLong( in->shaderNum );\n\t\tif ( out->shaderNum < 0 || out->shaderNum >= cm.numShaders ) {\n\t\t\tCom_Error( ERR_DROP, \"CMod_LoadBrushSides: bad shaderNum: %i\", out->shaderNum );\n\t\t}\n\t\tout->surfaceFlags = cm.shaders[out->shaderNum].surfaceFlags;\n\t}\n}\n\n\n/*\n=================\nCMod_LoadEntityString\n=================\n*/\nvoid CMod_LoadEntityString( lump_t *l ) {\n\tcm.entityString = (char*) Hunk_Alloc( l->filelen, h_high );\n\tcm.numEntityChars = l->filelen;\n\tCom_Memcpy (cm.entityString, cmod_base + l->fileofs, l->filelen);\n}\n\n/*\n=================\nCMod_LoadVisibility\n=================\n*/\n#define\tVIS_HEADER\t8\nvoid CMod_LoadVisibility( lump_t *l ) {\n\tint\t\tlen;\n\tbyte\t*buf;\n\n    len = l->filelen;\n\tif ( !len ) {\n\t\tcm.clusterBytes = ( cm.numClusters + 31 ) & ~31;\n\t\tcm.visibility = (byte*) Hunk_Alloc( cm.clusterBytes, h_high );\n\t\tCom_Memset( cm.visibility, 255, cm.clusterBytes );\n\t\treturn;\n\t}\n\tbuf = cmod_base + l->fileofs;\n\n\tcm.vised = qtrue;\n\tcm.visibility = (byte*) Hunk_Alloc( len, h_high );\n\tcm.numClusters = LittleLong( ((int *)buf)[0] );\n\tcm.clusterBytes = LittleLong( ((int *)buf)[1] );\n\tCom_Memcpy (cm.visibility, buf + VIS_HEADER, len - VIS_HEADER );\n}\n\n//==================================================================\n\n\n/*\n=================\nCMod_LoadPatches\n=================\n*/\n#define\tMAX_PATCH_VERTS\t\t1024\nvoid CMod_LoadPatches( lump_t *surfs, lump_t *verts ) {\n\tdrawVert_t\t*dv, *dv_p;\n\tdsurface_t\t*in;\n\tint\t\t\tcount;\n\tint\t\t\ti, j;\n\tint\t\t\tc;\n\tcPatch_t\t*patch;\n\tvec3_t\t\tpoints[MAX_PATCH_VERTS];\n\tint\t\t\twidth, height;\n\tint\t\t\tshaderNum;\n\n\tin = (dsurface_t*) (void *)(cmod_base + surfs->fileofs);\n\tif (surfs->filelen % sizeof(*in))\n\t\tCom_Error (ERR_DROP, \"MOD_LoadBmodel: funny lump size\");\n\tcm.numSurfaces = count = surfs->filelen / sizeof(*in);\n\tcm.surfaces = (cPatch_t**) Hunk_Alloc( cm.numSurfaces * sizeof( cm.surfaces[0] ), h_high );\n\n\tdv = (drawVert_t*) (void *)(cmod_base + verts->fileofs);\n\tif (verts->filelen % sizeof(*dv))\n\t\tCom_Error (ERR_DROP, \"MOD_LoadBmodel: funny lump size\");\n\n\t// scan through all the surfaces, but only load patches,\n\t// not planar faces\n\tfor ( i = 0 ; i < count ; i++, in++ ) {\n\t\tif ( LittleLong( in->surfaceType ) != MST_PATCH ) {\n\t\t\tcontinue;\t\t// ignore other surfaces\n\t\t}\n\t\t// FIXME: check for non-colliding patches\n\n\t\tcm.surfaces[ i ] = patch = (cPatch_t*) Hunk_Alloc( sizeof( *patch ), h_high );\n\n\t\t// load the full drawverts onto the stack\n\t\twidth = LittleLong( in->patchWidth );\n\t\theight = LittleLong( in->patchHeight );\n\t\tc = width * height;\n\t\tif ( c > MAX_PATCH_VERTS ) {\n\t\t\tCom_Error( ERR_DROP, \"ParseMesh: MAX_PATCH_VERTS\" );\n\t\t}\n\n\t\tdv_p = dv + LittleLong( in->firstVert );\n\t\tfor ( j = 0 ; j < c ; j++, dv_p++ ) {\n\t\t\tpoints[j][0] = LittleFloat( dv_p->xyz[0] );\n\t\t\tpoints[j][1] = LittleFloat( dv_p->xyz[1] );\n\t\t\tpoints[j][2] = LittleFloat( dv_p->xyz[2] );\n\t\t}\n\n\t\tshaderNum = LittleLong( in->shaderNum );\n\t\tpatch->contents = cm.shaders[shaderNum].contentFlags;\n\t\tpatch->surfaceFlags = cm.shaders[shaderNum].surfaceFlags;\n\n\t\t// create the internal facet structure\n\t\tpatch->pc = CM_GeneratePatchCollide( width, height, points );\n\t}\n}\n\n//==================================================================\n\nunsigned CM_LumpChecksum(lump_t *lump) {\n\treturn LittleLong (Com_BlockChecksum (cmod_base + lump->fileofs, lump->filelen));\n}\n\nunsigned CM_Checksum(dheader_t *header) {\n\tunsigned checksums[16];\n\tchecksums[0] = CM_LumpChecksum(&header->lumps[LUMP_SHADERS]);\n\tchecksums[1] = CM_LumpChecksum(&header->lumps[LUMP_LEAFS]);\n\tchecksums[2] = CM_LumpChecksum(&header->lumps[LUMP_LEAFBRUSHES]);\n\tchecksums[3] = CM_LumpChecksum(&header->lumps[LUMP_LEAFSURFACES]);\n\tchecksums[4] = CM_LumpChecksum(&header->lumps[LUMP_PLANES]);\n\tchecksums[5] = CM_LumpChecksum(&header->lumps[LUMP_BRUSHSIDES]);\n\tchecksums[6] = CM_LumpChecksum(&header->lumps[LUMP_BRUSHES]);\n\tchecksums[7] = CM_LumpChecksum(&header->lumps[LUMP_MODELS]);\n\tchecksums[8] = CM_LumpChecksum(&header->lumps[LUMP_NODES]);\n\tchecksums[9] = CM_LumpChecksum(&header->lumps[LUMP_SURFACES]);\n\tchecksums[10] = CM_LumpChecksum(&header->lumps[LUMP_DRAWVERTS]);\n\n\treturn LittleLong(Com_BlockChecksum(checksums, 11 * 4));\n}\n\n/*\n==================\nCM_LoadMap\n\nLoads in the map and all submodels\n==================\n*/\nvoid CM_LoadMap( const char *name, qboolean clientload, int *checksum ) {\n\tint\t\t\t\t*buf;\n\tint\t\t\t\ti;\n\tdheader_t\t\theader;\n\tint\t\t\t\tlength;\n\tstatic unsigned\tlast_checksum;\n\n\tif ( !name || !name[0] ) {\n\t\tCom_Error( ERR_DROP, \"CM_LoadMap: NULL name\" );\n\t}\n\n#ifndef BSPC\n\tcm_noAreas = Cvar_Get (\"cm_noAreas\", \"0\", CVAR_CHEAT);\n\tcm_noCurves = Cvar_Get (\"cm_noCurves\", \"0\", CVAR_CHEAT);\n\tcm_playerCurveClip = Cvar_Get (\"cm_playerCurveClip\", \"1\", CVAR_ARCHIVE|CVAR_CHEAT );\n#endif\n\tCom_DPrintf( \"CM_LoadMap( %s, %i )\\n\", name, clientload );\n\n\tif ( !strcmp( cm.name, name ) && clientload ) {\n\t\t*checksum = last_checksum;\n\t\treturn;\n\t}\n\n\t// free old stuff\n\tCom_Memset( &cm, 0, sizeof( cm ) );\n\tCM_ClearLevelPatches();\n\n\tif ( !name[0] ) {\n\t\tcm.numLeafs = 1;\n\t\tcm.numClusters = 1;\n\t\tcm.numAreas = 1;\n\t\tcm.cmodels = (cmodel_t*) Hunk_Alloc( sizeof( *cm.cmodels ), h_high );\n\t\t*checksum = 0;\n\t\treturn;\n\t}\n\n\t//\n\t// load the file\n\t//\n#ifndef BSPC\n\tlength = FS_ReadFile( name, (void **)&buf );\n#else\n\tlength = LoadQuakeFile((quakefile_t *) name, (void **)&buf);\n#endif\n\n\tif ( !buf ) {\n\t\tCom_Error (ERR_DROP, \"Couldn't load %s\", name);\n\t}\n\n\tlast_checksum = LittleLong (Com_BlockChecksum (buf, length));\n\t*checksum = last_checksum;\n\n\theader = *(dheader_t *)buf;\n\tfor (i=0 ; i<sizeof(dheader_t)/4 ; i++) {\n\t\t((int *)&header)[i] = LittleLong ( ((int *)&header)[i]);\n\t}\n\n\tif ( header.version != BSP_VERSION ) {\n\t\tCom_Error (ERR_DROP, \"CM_LoadMap: %s has wrong version number (%i should be %i)\"\n\t\t, name, header.version, BSP_VERSION );\n\t}\n\n\tcmod_base = (byte *)buf;\n\n\t// load into heap\n\tCMod_LoadShaders( &header.lumps[LUMP_SHADERS] );\n\tCMod_LoadLeafs (&header.lumps[LUMP_LEAFS]);\n\tCMod_LoadLeafBrushes (&header.lumps[LUMP_LEAFBRUSHES]);\n\tCMod_LoadLeafSurfaces (&header.lumps[LUMP_LEAFSURFACES]);\n\tCMod_LoadPlanes (&header.lumps[LUMP_PLANES]);\n\tCMod_LoadBrushSides (&header.lumps[LUMP_BRUSHSIDES]);\n\tCMod_LoadBrushes (&header.lumps[LUMP_BRUSHES]);\n\tCMod_LoadSubmodels (&header.lumps[LUMP_MODELS]);\n\tCMod_LoadNodes (&header.lumps[LUMP_NODES]);\n\tCMod_LoadEntityString (&header.lumps[LUMP_ENTITIES]);\n\tCMod_LoadVisibility( &header.lumps[LUMP_VISIBILITY] );\n\tCMod_LoadPatches( &header.lumps[LUMP_SURFACES], &header.lumps[LUMP_DRAWVERTS] );\n\n\t// we are NOT freeing the file, because it is cached for the ref\n\tFS_FreeFile (buf);\n\n\tCM_InitBoxHull ();\n\n\tCM_FloodAreaConnections ();\n\n\t// allow this to be cached if it is loaded by the server\n\tif ( !clientload ) {\n\t\tQ_strncpyz( cm.name, name, sizeof( cm.name ) );\n\t}\n}\n\n/*\n==================\nCM_ClearMap\n==================\n*/\nvoid CM_ClearMap( void ) {\n\tCom_Memset( &cm, 0, sizeof( cm ) );\n\tCM_ClearLevelPatches();\n}\n\n/*\n==================\nCM_ClipHandleToModel\n==================\n*/\ncmodel_t\t*CM_ClipHandleToModel( clipHandle_t handle ) {\n\tif ( handle < 0 ) {\n\t\tCom_Error( ERR_DROP, \"CM_ClipHandleToModel: bad handle %i\", handle );\n\t}\n\tif ( handle < cm.numSubModels ) {\n\t\treturn &cm.cmodels[handle];\n\t}\n\tif ( handle == BOX_MODEL_HANDLE ) {\n\t\treturn &box_model;\n\t}\n\tif ( handle < MAX_SUBMODELS ) {\n\t\tCom_Error( ERR_DROP, \"CM_ClipHandleToModel: bad handle %i < %i < %i\", \n\t\t\tcm.numSubModels, handle, MAX_SUBMODELS );\n\t}\n\tCom_Error( ERR_DROP, \"CM_ClipHandleToModel: bad handle %i\", handle + MAX_SUBMODELS );\n\n\treturn NULL;\n\n}\n\n/*\n==================\nCM_InlineModel\n==================\n*/\nclipHandle_t\tCM_InlineModel( int index ) {\n\tif ( index < 0 || index >= cm.numSubModels ) {\n\t\tCom_Error (ERR_DROP, \"CM_InlineModel: bad number\");\n\t}\n\treturn index;\n}\n\nint\t\tCM_NumClusters( void ) {\n\treturn cm.numClusters;\n}\n\nint\t\tCM_NumInlineModels( void ) {\n\treturn cm.numSubModels;\n}\n\nchar\t*CM_EntityString( void ) {\n\treturn cm.entityString;\n}\n\nint\t\tCM_LeafCluster( int leafnum ) {\n\tif (leafnum < 0 || leafnum >= cm.numLeafs) {\n\t\tCom_Error (ERR_DROP, \"CM_LeafCluster: bad number\");\n\t}\n\treturn cm.leafs[leafnum].cluster;\n}\n\nint\t\tCM_LeafArea( int leafnum ) {\n\tif ( leafnum < 0 || leafnum >= cm.numLeafs ) {\n\t\tCom_Error (ERR_DROP, \"CM_LeafArea: bad number\");\n\t}\n\treturn cm.leafs[leafnum].area;\n}\n\n//=======================================================================\n\n\n/*\n===================\nCM_InitBoxHull\n\nSet up the planes and nodes so that the six floats of a bounding box\ncan just be stored out and get a proper clipping hull structure.\n===================\n*/\nvoid CM_InitBoxHull (void)\n{\n\tint\t\t\ti;\n\tint\t\t\tside;\n\tcplane_t\t*p;\n\tcbrushside_t\t*s;\n\n\tbox_planes = &cm.planes[cm.numPlanes];\n\n\tbox_brush = &cm.brushes[cm.numBrushes];\n\tbox_brush->numsides = 6;\n\tbox_brush->sides = cm.brushsides + cm.numBrushSides;\n\tbox_brush->contents = CONTENTS_BODY;\n\n\tbox_model.leaf.numLeafBrushes = 1;\n//\tbox_model.leaf.firstLeafBrush = cm.numBrushes;\n\tbox_model.leaf.firstLeafBrush = cm.numLeafBrushes;\n\tcm.leafbrushes[cm.numLeafBrushes] = cm.numBrushes;\n\n\tfor (i=0 ; i<6 ; i++)\n\t{\n\t\tside = i&1;\n\n\t\t// brush sides\n\t\ts = &cm.brushsides[cm.numBrushSides+i];\n\t\ts->plane = \tcm.planes + (cm.numPlanes+i*2+side);\n\t\ts->surfaceFlags = 0;\n\n\t\t// planes\n\t\tp = &box_planes[i*2];\n\t\tp->type = i>>1;\n\t\tp->signbits = 0;\n\t\tVectorClear (p->normal);\n\t\tp->normal[i>>1] = 1;\n\n\t\tp = &box_planes[i*2+1];\n\t\tp->type = 3 + (i>>1);\n\t\tp->signbits = 0;\n\t\tVectorClear (p->normal);\n\t\tp->normal[i>>1] = -1;\n\n\t\tSetPlaneSignbits( p );\n\t}\t\n}\n\n/*\n===================\nCM_TempBoxModel\n\nTo keep everything totally uniform, bounding boxes are turned into small\nBSP trees instead of being compared directly.\nCapsules are handled differently though.\n===================\n*/\nclipHandle_t CM_TempBoxModel( const vec3_t mins, const vec3_t maxs, int capsule ) {\n\n\tVectorCopy( mins, box_model.mins );\n\tVectorCopy( maxs, box_model.maxs );\n\n\tif ( capsule ) {\n\t\treturn CAPSULE_MODEL_HANDLE;\n\t}\n\n\tbox_planes[0].dist = maxs[0];\n\tbox_planes[1].dist = -maxs[0];\n\tbox_planes[2].dist = mins[0];\n\tbox_planes[3].dist = -mins[0];\n\tbox_planes[4].dist = maxs[1];\n\tbox_planes[5].dist = -maxs[1];\n\tbox_planes[6].dist = mins[1];\n\tbox_planes[7].dist = -mins[1];\n\tbox_planes[8].dist = maxs[2];\n\tbox_planes[9].dist = -maxs[2];\n\tbox_planes[10].dist = mins[2];\n\tbox_planes[11].dist = -mins[2];\n\n\tVectorCopy( mins, box_brush->bounds[0] );\n\tVectorCopy( maxs, box_brush->bounds[1] );\n\n\treturn BOX_MODEL_HANDLE;\n}\n\n/*\n===================\nCM_ModelBounds\n===================\n*/\nvoid CM_ModelBounds( clipHandle_t model, vec3_t mins, vec3_t maxs ) {\n\tcmodel_t\t*cmod;\n\n\tcmod = CM_ClipHandleToModel( model );\n\tVectorCopy( cmod->mins, mins );\n\tVectorCopy( cmod->maxs, maxs );\n}\n\n\n"
  },
  {
    "path": "src/engine/qcommon/cm_local.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n#include \"../../game/q_shared.h\"\n#include \"qcommon.h\"\n#include \"cm_polylib.h\"\n\n#define\tMAX_SUBMODELS\t\t\t256\n#define\tBOX_MODEL_HANDLE\t\t255\n#define CAPSULE_MODEL_HANDLE\t254\n\n\ntypedef struct {\n\tcplane_t\t*plane;\n\tint\t\t\tchildren[2];\t\t// negative numbers are leafs\n} cNode_t;\n\ntypedef struct {\n\tint\t\t\tcluster;\n\tint\t\t\tarea;\n\n\tint\t\t\tfirstLeafBrush;\n\tint\t\t\tnumLeafBrushes;\n\n\tint\t\t\tfirstLeafSurface;\n\tint\t\t\tnumLeafSurfaces;\n} cLeaf_t;\n\ntypedef struct cmodel_s {\n\tvec3_t\t\tmins, maxs;\n\tcLeaf_t\t\tleaf;\t\t\t// submodels don't reference the main tree\n} cmodel_t;\n\ntypedef struct {\n\tcplane_t\t*plane;\n\tint\t\t\tsurfaceFlags;\n\tint\t\t\tshaderNum;\n} cbrushside_t;\n\ntypedef struct {\n\tint\t\t\tshaderNum;\t\t// the shader that determined the contents\n\tint\t\t\tcontents;\n\tvec3_t\t\tbounds[2];\n\tint\t\t\tnumsides;\n\tcbrushside_t\t*sides;\n\tint\t\t\tcheckcount;\t\t// to avoid repeated testings\n} cbrush_t;\n\n\ntypedef struct {\n\tint\t\t\tcheckcount;\t\t\t\t// to avoid repeated testings\n\tint\t\t\tsurfaceFlags;\n\tint\t\t\tcontents;\n\tstruct patchCollide_s\t*pc;\n} cPatch_t;\n\n\ntypedef struct {\n\tint\t\t\tfloodnum;\n\tint\t\t\tfloodvalid;\n} cArea_t;\n\ntypedef struct {\n\tchar\t\tname[MAX_QPATH];\n\n\tint\t\t\tnumShaders;\n\tdshader_t\t*shaders;\n\n\tint\t\t\tnumBrushSides;\n\tcbrushside_t *brushsides;\n\n\tint\t\t\tnumPlanes;\n\tcplane_t\t*planes;\n\n\tint\t\t\tnumNodes;\n\tcNode_t\t\t*nodes;\n\n\tint\t\t\tnumLeafs;\n\tcLeaf_t\t\t*leafs;\n\n\tint\t\t\tnumLeafBrushes;\n\tint\t\t\t*leafbrushes;\n\n\tint\t\t\tnumLeafSurfaces;\n\tint\t\t\t*leafsurfaces;\n\n\tint\t\t\tnumSubModels;\n\tcmodel_t\t*cmodels;\n\n\tint\t\t\tnumBrushes;\n\tcbrush_t\t*brushes;\n\n\tint\t\t\tnumClusters;\n\tint\t\t\tclusterBytes;\n\tbyte\t\t*visibility;\n\tqboolean\tvised;\t\t\t// if false, visibility is just a single cluster of ffs\n\n\tint\t\t\tnumEntityChars;\n\tchar\t\t*entityString;\n\n\tint\t\t\tnumAreas;\n\tcArea_t\t\t*areas;\n\tint\t\t\t*areaPortals;\t// [ numAreas*numAreas ] reference counts\n\n\tint\t\t\tnumSurfaces;\n\tcPatch_t\t**surfaces;\t\t\t// non-patches will be NULL\n\n\tint\t\t\tfloodvalid;\n\tint\t\t\tcheckcount;\t\t\t\t\t// incremented on each trace\n} clipMap_t;\n\n\n// keep 1/8 unit away to keep the position valid before network snapping\n// and to avoid various numeric issues\n#define\tSURFACE_CLIP_EPSILON\t(0.125)\n\nextern\tclipMap_t\tcm;\nextern\tint\t\t\tc_pointcontents;\nextern\tint\t\t\tc_traces, c_brush_traces, c_patch_traces;\nextern\tcvar_t\t\t*cm_noAreas;\nextern\tcvar_t\t\t*cm_noCurves;\nextern\tcvar_t\t\t*cm_playerCurveClip;\n\n// cm_test.c\n\n// Used for oriented capsule collision detection\ntypedef struct\n{\n\tqboolean\tuse;\n\tfloat\t\tradius;\n\tfloat\t\thalfheight;\n\tvec3_t\t\toffset;\n} sphere_t;\n\ntypedef struct {\n\tvec3_t\t\tstart;\n\tvec3_t\t\tend;\n\tvec3_t\t\tsize[2];\t// size of the box being swept through the model\n\tvec3_t\t\toffsets[8];\t// [signbits][x] = either size[0][x] or size[1][x]\n\tfloat\t\tmaxOffset;\t// longest corner length from origin\n\tvec3_t\t\textents;\t// greatest of abs(size[0]) and abs(size[1])\n\tvec3_t\t\tbounds[2];\t// enclosing box of start and end surrounding by size\n\tvec3_t\t\tmodelOrigin;// origin of the model tracing through\n\tint\t\t\tcontents;\t// ored contents of the model tracing through\n\tqboolean\tisPoint;\t// optimized case\n\ttrace_t\t\ttrace;\t\t// returned from trace call\n\tsphere_t\tsphere;\t\t// sphere for oriendted capsule collision\n} traceWork_t;\n\ntypedef struct leafList_s {\n\tint\t\tcount;\n\tint\t\tmaxcount;\n\tqboolean\toverflowed;\n\tint\t\t*list;\n\tvec3_t\tbounds[2];\n\tint\t\tlastLeaf;\t\t// for overflows where each leaf can't be stored individually\n\tvoid\t(*storeLeafs)( struct leafList_s *ll, int nodenum );\n} leafList_t;\n\n\nint CM_BoxBrushes( const vec3_t mins, const vec3_t maxs, cbrush_t **list, int listsize );\n\nvoid CM_StoreLeafs( leafList_t *ll, int nodenum );\nvoid CM_StoreBrushes( leafList_t *ll, int nodenum );\n\nvoid CM_BoxLeafnums_r( leafList_t *ll, int nodenum );\n\ncmodel_t\t*CM_ClipHandleToModel( clipHandle_t handle );\n\n// cm_patch.c\n\nstruct patchCollide_s\t*CM_GeneratePatchCollide( int width, int height, vec3_t *points );\nvoid CM_TraceThroughPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc );\nqboolean CM_PositionTestInPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc );\nvoid CM_ClearLevelPatches( void );\n"
  },
  {
    "path": "src/engine/qcommon/cm_patch.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n#include \"cm_local.h\"\n#include \"cm_patch.h\"\n\n/*\n\nThis file does not reference any globals, and has these entry points:\n\nvoid CM_ClearLevelPatches( void );\nstruct patchCollide_s\t*CM_GeneratePatchCollide( int width, int height, const vec3_t *points );\nvoid CM_TraceThroughPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc );\nqboolean CM_PositionTestInPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc );\nvoid CM_DrawDebugSurface( void (*drawPoly)(int color, int numPoints, flaot *points) );\n\n\nWARNING: this may misbehave with meshes that have rows or columns that only\ndegenerate a few triangles.  Completely degenerate rows and columns are handled\nproperly.\n*/\n\n/*\n#define\tMAX_FACETS\t\t\t1024\n#define\tMAX_PATCH_PLANES\t2048\n\ntypedef struct {\n\tfloat\tplane[4];\n\tint\t\tsignbits;\t\t// signx + (signy<<1) + (signz<<2), used as lookup during collision\n} patchPlane_t;\n\ntypedef struct {\n\tint\t\t\tsurfacePlane;\n\tint\t\t\tnumBorders;\t\t// 3 or four + 6 axial bevels + 4 or 3 * 4 edge bevels\n\tint\t\t\tborderPlanes[4+6+16];\n\tint\t\t\tborderInward[4+6+16];\n\tqboolean\tborderNoAdjust[4+6+16];\n} facet_t;\n\ntypedef struct patchCollide_s {\n\tvec3_t\tbounds[2];\n\tint\t\tnumPlanes;\t\t\t// surface planes plus edge planes\n\tpatchPlane_t\t*planes;\n\tint\t\tnumFacets;\n\tfacet_t\t*facets;\n} patchCollide_t;\n\n\n#define\tMAX_GRID_SIZE\t129\n\ntypedef struct {\n\tint\t\t\twidth;\n\tint\t\t\theight;\n\tqboolean\twrapWidth;\n\tqboolean\twrapHeight;\n\tvec3_t\tpoints[MAX_GRID_SIZE][MAX_GRID_SIZE];\t// [width][height]\n} cGrid_t;\n\n#define\tSUBDIVIDE_DISTANCE\t16\t//4\t// never more than this units away from curve\n#define\tPLANE_TRI_EPSILON\t0.1\n#define\tWRAP_POINT_EPSILON\t0.1\n*/\n\nint\tc_totalPatchBlocks;\nint\tc_totalPatchSurfaces;\nint\tc_totalPatchEdges;\n\nstatic const patchCollide_t\t*debugPatchCollide;\nstatic const facet_t\t\t*debugFacet;\nstatic qboolean\t\tdebugBlock;\nstatic vec3_t\t\tdebugBlockPoints[4];\n\n/*\n=================\nCM_ClearLevelPatches\n=================\n*/\nvoid CM_ClearLevelPatches( void ) {\n\tdebugPatchCollide = NULL;\n\tdebugFacet = NULL;\n}\n\n/*\n=================\nCM_SignbitsForNormal\n=================\n*/\nstatic int CM_SignbitsForNormal( vec3_t normal ) {\n\tint\tbits, j;\n\n\tbits = 0;\n\tfor (j=0 ; j<3 ; j++) {\n\t\tif ( normal[j] < 0 ) {\n\t\t\tbits |= 1<<j;\n\t\t}\n\t}\n\treturn bits;\n}\n\n/*\n=====================\nCM_PlaneFromPoints\n\nReturns false if the triangle is degenrate.\nThe normal will point out of the clock for clockwise ordered points\n=====================\n*/\nstatic qboolean CM_PlaneFromPoints( vec4_t plane, vec3_t a, vec3_t b, vec3_t c ) {\n\tvec3_t\td1, d2;\n\n\tVectorSubtract( b, a, d1 );\n\tVectorSubtract( c, a, d2 );\n\tCrossProduct( d2, d1, plane );\n\tif ( VectorNormalize( plane ) == 0 ) {\n\t\treturn qfalse;\n\t}\n\n\tplane[3] = DotProduct( a, plane );\n\treturn qtrue;\n}\n\n\n/*\n================================================================================\n\nGRID SUBDIVISION\n\n================================================================================\n*/\n\n/*\n=================\nCM_NeedsSubdivision\n\nReturns true if the given quadratic curve is not flat enough for our\ncollision detection purposes\n=================\n*/\nstatic qboolean\tCM_NeedsSubdivision( vec3_t a, vec3_t b, vec3_t c ) {\n\tvec3_t\t\tcmid;\n\tvec3_t\t\tlmid;\n\tvec3_t\t\tdelta;\n\tfloat\t\tdist;\n\tint\t\t\ti;\n\n\t// calculate the linear midpoint\n\tfor ( i = 0 ; i < 3 ; i++ ) {\n\t\tlmid[i] = 0.5*(a[i] + c[i]);\n\t}\n\n\t// calculate the exact curve midpoint\n\tfor ( i = 0 ; i < 3 ; i++ ) {\n\t\tcmid[i] = 0.5 * ( 0.5*(a[i] + b[i]) + 0.5*(b[i] + c[i]) );\n\t}\n\n\t// see if the curve is far enough away from the linear mid\n\tVectorSubtract( cmid, lmid, delta );\n\tdist = VectorLength( delta );\n\t\n\treturn (qboolean) (dist >= SUBDIVIDE_DISTANCE);\n}\n\n/*\n===============\nCM_Subdivide\n\na, b, and c are control points.\nthe subdivided sequence will be: a, out1, out2, out3, c\n===============\n*/\nstatic void CM_Subdivide( vec3_t a, vec3_t b, vec3_t c, vec3_t out1, vec3_t out2, vec3_t out3 ) {\n\tint\t\ti;\n\n\tfor ( i = 0 ; i < 3 ; i++ ) {\n\t\tout1[i] = 0.5 * (a[i] + b[i]);\n\t\tout3[i] = 0.5 * (b[i] + c[i]);\n\t\tout2[i] = 0.5 * (out1[i] + out3[i]);\n\t}\n}\n\n/*\n=================\nCM_TransposeGrid\n\nSwaps the rows and columns in place\n=================\n*/\nstatic void CM_TransposeGrid( cGrid_t *grid ) {\n\tint\t\t\ti, j, l;\n\tvec3_t\t\ttemp;\n\tqboolean\ttempWrap;\n\n\tif ( grid->width > grid->height ) {\n\t\tfor ( i = 0 ; i < grid->height ; i++ ) {\n\t\t\tfor ( j = i + 1 ; j < grid->width ; j++ ) {\n\t\t\t\tif ( j < grid->height ) {\n\t\t\t\t\t// swap the value\n\t\t\t\t\tVectorCopy( grid->points[i][j], temp );\n\t\t\t\t\tVectorCopy( grid->points[j][i], grid->points[i][j] );\n\t\t\t\t\tVectorCopy( temp, grid->points[j][i] );\n\t\t\t\t} else {\n\t\t\t\t\t// just copy\n\t\t\t\t\tVectorCopy( grid->points[j][i], grid->points[i][j] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} else {\n\t\tfor ( i = 0 ; i < grid->width ; i++ ) {\n\t\t\tfor ( j = i + 1 ; j < grid->height ; j++ ) {\n\t\t\t\tif ( j < grid->width ) {\n\t\t\t\t\t// swap the value\n\t\t\t\t\tVectorCopy( grid->points[j][i], temp );\n\t\t\t\t\tVectorCopy( grid->points[i][j], grid->points[j][i] );\n\t\t\t\t\tVectorCopy( temp, grid->points[i][j] );\n\t\t\t\t} else {\n\t\t\t\t\t// just copy\n\t\t\t\t\tVectorCopy( grid->points[i][j], grid->points[j][i] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tl = grid->width;\n\tgrid->width = grid->height;\n\tgrid->height = l;\n\n\ttempWrap = grid->wrapWidth;\n\tgrid->wrapWidth = grid->wrapHeight;\n\tgrid->wrapHeight = tempWrap;\n}\n\n/*\n===================\nCM_SetGridWrapWidth\n\nIf the left and right columns are exactly equal, set grid->wrapWidth qtrue\n===================\n*/\nstatic void CM_SetGridWrapWidth( cGrid_t *grid ) {\n\tint\t\ti, j;\n\tfloat\td;\n\n\tfor ( i = 0 ; i < grid->height ; i++ ) {\n\t\tfor ( j = 0 ; j < 3 ; j++ ) {\n\t\t\td = grid->points[0][i][j] - grid->points[grid->width-1][i][j];\n\t\t\tif ( d < -WRAP_POINT_EPSILON || d > WRAP_POINT_EPSILON ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif ( j != 3 ) {\n\t\t\tbreak;\n\t\t}\n\t}\n\tif ( i == grid->height ) {\n\t\tgrid->wrapWidth = qtrue;\n\t} else {\n\t\tgrid->wrapWidth = qfalse;\n\t}\n}\n\n/*\n=================\nCM_SubdivideGridColumns\n\nAdds columns as necessary to the grid until\nall the aproximating points are within SUBDIVIDE_DISTANCE\nfrom the true curve\n=================\n*/\nstatic void CM_SubdivideGridColumns( cGrid_t *grid ) {\n\tint\t\ti, j, k;\n\n\tfor ( i = 0 ; i < grid->width - 2 ;  ) {\n\t\t// grid->points[i][x] is an interpolating control point\n\t\t// grid->points[i+1][x] is an aproximating control point\n\t\t// grid->points[i+2][x] is an interpolating control point\n\n\t\t//\n\t\t// first see if we can collapse the aproximating collumn away\n\t\t//\n\t\tfor ( j = 0 ; j < grid->height ; j++ ) {\n\t\t\tif ( CM_NeedsSubdivision( grid->points[i][j], grid->points[i+1][j], grid->points[i+2][j] ) ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif ( j == grid->height ) {\n\t\t\t// all of the points were close enough to the linear midpoints\n\t\t\t// that we can collapse the entire column away\n\t\t\tfor ( j = 0 ; j < grid->height ; j++ ) {\n\t\t\t\t// remove the column\n\t\t\t\tfor ( k = i + 2 ; k < grid->width ; k++ ) {\n\t\t\t\t\tVectorCopy( grid->points[k][j], grid->points[k-1][j] );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tgrid->width--;\n\n\t\t\t// go to the next curve segment\n\t\t\ti++;\n\t\t\tcontinue;\n\t\t}\n\n\t\t//\n\t\t// we need to subdivide the curve\n\t\t//\n\t\tfor ( j = 0 ; j < grid->height ; j++ ) {\n\t\t\tvec3_t\tprev, mid, next;\n\n\t\t\t// save the control points now\n\t\t\tVectorCopy( grid->points[i][j], prev );\n\t\t\tVectorCopy( grid->points[i+1][j], mid );\n\t\t\tVectorCopy( grid->points[i+2][j], next );\n\n\t\t\t// make room for two additional columns in the grid\n\t\t\t// columns i+1 will be replaced, column i+2 will become i+4\n\t\t\t// i+1, i+2, and i+3 will be generated\n\t\t\tfor ( k = grid->width - 1 ; k > i + 1 ; k-- ) {\n\t\t\t\tVectorCopy( grid->points[k][j], grid->points[k+2][j] );\n\t\t\t}\n\n\t\t\t// generate the subdivided points\n\t\t\tCM_Subdivide( prev, mid, next, grid->points[i+1][j], grid->points[i+2][j], grid->points[i+3][j] );\n\t\t}\n\n\t\tgrid->width += 2;\n\n\t\t// the new aproximating point at i+1 may need to be removed\n\t\t// or subdivided farther, so don't advance i\n\t}\n}\n\n/*\n======================\nCM_ComparePoints\n======================\n*/\n#define\tPOINT_EPSILON\t0.1\nstatic qboolean CM_ComparePoints( float *a, float *b ) {\n\tfloat\t\td;\n\n\td = a[0] - b[0];\n\tif ( d < -POINT_EPSILON || d > POINT_EPSILON ) {\n\t\treturn qfalse;\n\t}\n\td = a[1] - b[1];\n\tif ( d < -POINT_EPSILON || d > POINT_EPSILON ) {\n\t\treturn qfalse;\n\t}\n\td = a[2] - b[2];\n\tif ( d < -POINT_EPSILON || d > POINT_EPSILON ) {\n\t\treturn qfalse;\n\t}\n\treturn qtrue;\n}\n\n/*\n=================\nCM_RemoveDegenerateColumns\n\nIf there are any identical columns, remove them\n=================\n*/\nstatic void CM_RemoveDegenerateColumns( cGrid_t *grid ) {\n\tint\t\ti, j, k;\n\n\tfor ( i = 0 ; i < grid->width - 1 ; i++ ) {\n\t\tfor ( j = 0 ; j < grid->height ; j++ ) {\n\t\t\tif ( !CM_ComparePoints( grid->points[i][j], grid->points[i+1][j] ) ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif ( j != grid->height ) {\n\t\t\tcontinue;\t// not degenerate\n\t\t}\n\n\t\tfor ( j = 0 ; j < grid->height ; j++ ) {\n\t\t\t// remove the column\n\t\t\tfor ( k = i + 2 ; k < grid->width ; k++ ) {\n\t\t\t\tVectorCopy( grid->points[k][j], grid->points[k-1][j] );\n\t\t\t}\n\t\t}\n\t\tgrid->width--;\n\n\t\t// check against the next column\n\t\ti--;\n\t}\n}\n\n/*\n================================================================================\n\nPATCH COLLIDE GENERATION\n\n================================================================================\n*/\n\nstatic\tint\t\t\t\tnumPlanes;\nstatic\tpatchPlane_t\tplanes[MAX_PATCH_PLANES];\n\nstatic\tint\t\t\t\tnumFacets;\nstatic\tfacet_t\t\t\tfacets[MAX_PATCH_PLANES]; //maybe MAX_FACETS ??\n\n#define\tNORMAL_EPSILON\t0.0001\n#define\tDIST_EPSILON\t0.02\n\n/*\n==================\nCM_PlaneEqual\n==================\n*/\nint CM_PlaneEqual(patchPlane_t *p, float plane[4], int *flipped) {\n\tfloat invplane[4];\n\n\tif (\n\t   fabs(p->plane[0] - plane[0]) < NORMAL_EPSILON\n\t&& fabs(p->plane[1] - plane[1]) < NORMAL_EPSILON\n\t&& fabs(p->plane[2] - plane[2]) < NORMAL_EPSILON\n\t&& fabs(p->plane[3] - plane[3]) < DIST_EPSILON )\n\t{\n\t\t*flipped = qfalse;\n\t\treturn qtrue;\n\t}\n\n\tVectorNegate(plane, invplane);\n\tinvplane[3] = -plane[3];\n\n\tif (\n\t   fabs(p->plane[0] - invplane[0]) < NORMAL_EPSILON\n\t&& fabs(p->plane[1] - invplane[1]) < NORMAL_EPSILON\n\t&& fabs(p->plane[2] - invplane[2]) < NORMAL_EPSILON\n\t&& fabs(p->plane[3] - invplane[3]) < DIST_EPSILON )\n\t{\n\t\t*flipped = qtrue;\n\t\treturn qtrue;\n\t}\n\n\treturn qfalse;\n}\n\n/*\n==================\nCM_SnapVector\n==================\n*/\nvoid CM_SnapVector(vec3_t normal) {\n\tint\t\ti;\n\n\tfor (i=0 ; i<3 ; i++)\n\t{\n\t\tif ( fabs(normal[i] - 1) < NORMAL_EPSILON )\n\t\t{\n\t\t\tVectorClear (normal);\n\t\t\tnormal[i] = 1;\n\t\t\tbreak;\n\t\t}\n\t\tif ( fabs(normal[i] - -1) < NORMAL_EPSILON )\n\t\t{\n\t\t\tVectorClear (normal);\n\t\t\tnormal[i] = -1;\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\n/*\n==================\nCM_FindPlane2\n==================\n*/\nint CM_FindPlane2(float plane[4], int *flipped) {\n\tint i;\n\n\t// see if the points are close enough to an existing plane\n\tfor ( i = 0 ; i < numPlanes ; i++ ) {\n\t\tif (CM_PlaneEqual(&planes[i], plane, flipped)) return i;\n\t}\n\n\t// add a new plane\n\tif ( numPlanes == MAX_PATCH_PLANES ) {\n\t\tCom_Error( ERR_DROP, \"MAX_PATCH_PLANES\" );\n\t}\n\n\tVector4Copy( plane, planes[numPlanes].plane );\n\tplanes[numPlanes].signbits = CM_SignbitsForNormal( plane );\n\n\tnumPlanes++;\n\n\t*flipped = qfalse;\n\n\treturn numPlanes-1;\n}\n\n/*\n==================\nCM_FindPlane\n==================\n*/\nstatic int CM_FindPlane( float *p1, float *p2, float *p3 ) {\n\tfloat\tplane[4];\n\tint\t\ti;\n\tfloat\td;\n\n\tif ( !CM_PlaneFromPoints( plane, p1, p2, p3 ) ) {\n\t\treturn -1;\n\t}\n\n\t// see if the points are close enough to an existing plane\n\tfor ( i = 0 ; i < numPlanes ; i++ ) {\n\t\tif ( DotProduct( plane, planes[i].plane ) < 0 ) {\n\t\t\tcontinue;\t// allow backwards planes?\n\t\t}\n\n\t\td = DotProduct( p1, planes[i].plane ) - planes[i].plane[3];\n\t\tif ( d < -PLANE_TRI_EPSILON || d > PLANE_TRI_EPSILON ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\td = DotProduct( p2, planes[i].plane ) - planes[i].plane[3];\n\t\tif ( d < -PLANE_TRI_EPSILON || d > PLANE_TRI_EPSILON ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\td = DotProduct( p3, planes[i].plane ) - planes[i].plane[3];\n\t\tif ( d < -PLANE_TRI_EPSILON || d > PLANE_TRI_EPSILON ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// found it\n\t\treturn i;\n\t}\n\n\t// add a new plane\n\tif ( numPlanes == MAX_PATCH_PLANES ) {\n\t\tCom_Error( ERR_DROP, \"MAX_PATCH_PLANES\" );\n\t}\n\n\tVector4Copy( plane, planes[numPlanes].plane );\n\tplanes[numPlanes].signbits = CM_SignbitsForNormal( plane );\n\n\tnumPlanes++;\n\n\treturn numPlanes-1;\n}\n\n/*\n==================\nCM_PointOnPlaneSide\n==================\n*/\nstatic int CM_PointOnPlaneSide( float *p, int planeNum ) {\n\tfloat\t*plane;\n\tfloat\td;\n\n\tif ( planeNum == -1 ) {\n\t\treturn SIDE_ON;\n\t}\n\tplane = planes[ planeNum ].plane;\n\n\td = DotProduct( p, plane ) - plane[3];\n\n\tif ( d > PLANE_TRI_EPSILON ) {\n\t\treturn SIDE_FRONT;\n\t}\n\n\tif ( d < -PLANE_TRI_EPSILON ) {\n\t\treturn SIDE_BACK;\n\t}\n\n\treturn SIDE_ON;\n}\n\n/*\n==================\nCM_GridPlane\n==================\n*/\nstatic int\tCM_GridPlane( int gridPlanes[MAX_GRID_SIZE][MAX_GRID_SIZE][2], int i, int j, int tri ) {\n\tint\t\tp;\n\n\tp = gridPlanes[i][j][tri];\n\tif ( p != -1 ) {\n\t\treturn p;\n\t}\n\tp = gridPlanes[i][j][!tri];\n\tif ( p != -1 ) {\n\t\treturn p;\n\t}\n\n\t// should never happen\n\tCom_Printf( \"WARNING: CM_GridPlane unresolvable\\n\" );\n\treturn -1;\n}\n\n/*\n==================\nCM_EdgePlaneNum\n==================\n*/\nstatic int CM_EdgePlaneNum( cGrid_t *grid, int gridPlanes[MAX_GRID_SIZE][MAX_GRID_SIZE][2], int i, int j, int k ) {\n\tfloat\t*p1, *p2;\n\tvec3_t\t\tup;\n\tint\t\t\tp;\n\n\tswitch ( k ) {\n\tcase 0:\t// top border\n\t\tp1 = grid->points[i][j];\n\t\tp2 = grid->points[i+1][j];\n\t\tp = CM_GridPlane( gridPlanes, i, j, 0 );\n\t\tVectorMA( p1, 4, planes[ p ].plane, up );\n\t\treturn CM_FindPlane( p1, p2, up );\n\n\tcase 2:\t// bottom border\n\t\tp1 = grid->points[i][j+1];\n\t\tp2 = grid->points[i+1][j+1];\n\t\tp = CM_GridPlane( gridPlanes, i, j, 1 );\n\t\tVectorMA( p1, 4, planes[ p ].plane, up );\n\t\treturn CM_FindPlane( p2, p1, up );\n\n\tcase 3: // left border\n\t\tp1 = grid->points[i][j];\n\t\tp2 = grid->points[i][j+1];\n\t\tp = CM_GridPlane( gridPlanes, i, j, 1 );\n\t\tVectorMA( p1, 4, planes[ p ].plane, up );\n\t\treturn CM_FindPlane( p2, p1, up );\n\n\tcase 1:\t// right border\n\t\tp1 = grid->points[i+1][j];\n\t\tp2 = grid->points[i+1][j+1];\n\t\tp = CM_GridPlane( gridPlanes, i, j, 0 );\n\t\tVectorMA( p1, 4, planes[ p ].plane, up );\n\t\treturn CM_FindPlane( p1, p2, up );\n\n\tcase 4:\t// diagonal out of triangle 0\n\t\tp1 = grid->points[i+1][j+1];\n\t\tp2 = grid->points[i][j];\n\t\tp = CM_GridPlane( gridPlanes, i, j, 0 );\n\t\tVectorMA( p1, 4, planes[ p ].plane, up );\n\t\treturn CM_FindPlane( p1, p2, up );\n\n\tcase 5:\t// diagonal out of triangle 1\n\t\tp1 = grid->points[i][j];\n\t\tp2 = grid->points[i+1][j+1];\n\t\tp = CM_GridPlane( gridPlanes, i, j, 1 );\n\t\tVectorMA( p1, 4, planes[ p ].plane, up );\n\t\treturn CM_FindPlane( p1, p2, up );\n\n\t}\n\n\tCom_Error( ERR_DROP, \"CM_EdgePlaneNum: bad k\" );\n\treturn -1;\n}\n\n/*\n===================\nCM_SetBorderInward\n===================\n*/\nstatic void CM_SetBorderInward( facet_t *facet, cGrid_t *grid, int gridPlanes[MAX_GRID_SIZE][MAX_GRID_SIZE][2],\n\t\t\t\t\t\t  int i, int j, int which ) {\n\tint\t\tk, l;\n\tfloat\t*points[4];\n\tint\t\tnumPoints;\n\n\tswitch ( which ) {\n\tcase -1:\n\t\tpoints[0] = grid->points[i][j];\n\t\tpoints[1] = grid->points[i+1][j];\n\t\tpoints[2] = grid->points[i+1][j+1];\n\t\tpoints[3] = grid->points[i][j+1];\n\t\tnumPoints = 4;\n\t\tbreak;\n\tcase 0:\n\t\tpoints[0] = grid->points[i][j];\n\t\tpoints[1] = grid->points[i+1][j];\n\t\tpoints[2] = grid->points[i+1][j+1];\n\t\tnumPoints = 3;\n\t\tbreak;\n\tcase 1:\n\t\tpoints[0] = grid->points[i+1][j+1];\n\t\tpoints[1] = grid->points[i][j+1];\n\t\tpoints[2] = grid->points[i][j];\n\t\tnumPoints = 3;\n\t\tbreak;\n\tdefault:\n\t\tCom_Error( ERR_FATAL, \"CM_SetBorderInward: bad parameter\" );\n\t\tnumPoints = 0;\n\t\tbreak;\n\t}\n\n\tfor ( k = 0 ; k < facet->numBorders ; k++ ) {\n\t\tint\t\tfront, back;\n\n\t\tfront = 0;\n\t\tback = 0;\n\n\t\tfor ( l = 0 ; l < numPoints ; l++ ) {\n\t\t\tint\t\tside;\n\n\t\t\tside = CM_PointOnPlaneSide( points[l], facet->borderPlanes[k] );\n\t\t\tif ( side == SIDE_FRONT ) {\n\t\t\t\tfront++;\n\t\t\t} if ( side == SIDE_BACK ) {\n\t\t\t\tback++;\n\t\t\t}\n\t\t}\n\n\t\tif ( front && !back ) {\n\t\t\tfacet->borderInward[k] = qtrue;\n\t\t} else if ( back && !front ) {\n\t\t\tfacet->borderInward[k] = qfalse;\n\t\t} else if ( !front && !back ) {\n\t\t\t// flat side border\n\t\t\tfacet->borderPlanes[k] = -1;\n\t\t} else {\n\t\t\t// bisecting side border\n\t\t\tCom_DPrintf( \"WARNING: CM_SetBorderInward: mixed plane sides\\n\" );\n\t\t\tfacet->borderInward[k] = qfalse;\n\t\t\tif ( !debugBlock ) {\n\t\t\t\tdebugBlock = qtrue;\n\t\t\t\tVectorCopy( grid->points[i][j], debugBlockPoints[0] );\n\t\t\t\tVectorCopy( grid->points[i+1][j], debugBlockPoints[1] );\n\t\t\t\tVectorCopy( grid->points[i+1][j+1], debugBlockPoints[2] );\n\t\t\t\tVectorCopy( grid->points[i][j+1], debugBlockPoints[3] );\n\t\t\t}\n\t\t}\n\t}\n}\n\n/*\n==================\nCM_ValidateFacet\n\nIf the facet isn't bounded by its borders, we screwed up.\n==================\n*/\nstatic qboolean CM_ValidateFacet( facet_t *facet ) {\n\tfloat\t\tplane[4];\n\tint\t\t\tj;\n\twinding_t\t*w;\n\tvec3_t\t\tbounds[2];\n\n\tif ( facet->surfacePlane == -1 ) {\n\t\treturn qfalse;\n\t}\n\n\tVector4Copy( planes[ facet->surfacePlane ].plane, plane );\n\tw = BaseWindingForPlane( plane,  plane[3] );\n\tfor ( j = 0 ; j < facet->numBorders && w ; j++ ) {\n\t\tif ( facet->borderPlanes[j] == -1 ) {\n\t\t\treturn qfalse;\n\t\t}\n\t\tVector4Copy( planes[ facet->borderPlanes[j] ].plane, plane );\n\t\tif ( !facet->borderInward[j] ) {\n\t\t\tVectorSubtract( vec3_origin, plane, plane );\n\t\t\tplane[3] = -plane[3];\n\t\t}\n\t\tChopWindingInPlace( &w, plane, plane[3], 0.1f );\n\t}\n\n\tif ( !w ) {\n\t\treturn qfalse;\t\t// winding was completely chopped away\n\t}\n\n\t// see if the facet is unreasonably large\n\tWindingBounds( w, bounds[0], bounds[1] );\n\tFreeWinding( w );\n\t\n\tfor ( j = 0 ; j < 3 ; j++ ) {\n\t\tif ( bounds[1][j] - bounds[0][j] > MAX_MAP_BOUNDS ) {\n\t\t\treturn qfalse;\t\t// we must be missing a plane\n\t\t}\n\t\tif ( bounds[0][j] >= MAX_MAP_BOUNDS ) {\n\t\t\treturn qfalse;\n\t\t}\n\t\tif ( bounds[1][j] <= -MAX_MAP_BOUNDS ) {\n\t\t\treturn qfalse;\n\t\t}\n\t}\n\treturn qtrue;\t\t// winding is fine\n}\n\n/*\n==================\nCM_AddFacetBevels\n==================\n*/\nvoid CM_AddFacetBevels( facet_t *facet ) {\n\n\tint i, j, k, l;\n\tint axis, dir, order, flipped;\n\tfloat plane[4], d, newplane[4];\n\twinding_t *w, *w2;\n\tvec3_t mins, maxs, vec, vec2;\n\n\tVector4Copy( planes[ facet->surfacePlane ].plane, plane );\n\n\tw = BaseWindingForPlane( plane,  plane[3] );\n\tfor ( j = 0 ; j < facet->numBorders && w ; j++ ) {\n\t\tif (facet->borderPlanes[j] == facet->surfacePlane) continue;\n\t\tVector4Copy( planes[ facet->borderPlanes[j] ].plane, plane );\n\n\t\tif ( !facet->borderInward[j] ) {\n\t\t\tVectorSubtract( vec3_origin, plane, plane );\n\t\t\tplane[3] = -plane[3];\n\t\t}\n\n\t\tChopWindingInPlace( &w, plane, plane[3], 0.1f );\n\t}\n\tif ( !w ) {\n\t\treturn;\n\t}\n\n\tWindingBounds(w, mins, maxs);\n\n\t// add the axial planes\n\torder = 0;\n\tfor ( axis = 0 ; axis < 3 ; axis++ )\n\t{\n\t\tfor ( dir = -1 ; dir <= 1 ; dir += 2, order++ )\n\t\t{\n\t\t\tVectorClear(plane);\n\t\t\tplane[axis] = dir;\n\t\t\tif (dir == 1) {\n\t\t\t\tplane[3] = maxs[axis];\n\t\t\t}\n\t\t\telse {\n\t\t\t\tplane[3] = -mins[axis];\n\t\t\t}\n\t\t\t//if it's the surface plane\n\t\t\tif (CM_PlaneEqual(&planes[facet->surfacePlane], plane, &flipped)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// see if the plane is allready present\n\t\t\tfor ( i = 0 ; i < facet->numBorders ; i++ ) {\n\t\t\t\tif (CM_PlaneEqual(&planes[facet->borderPlanes[i]], plane, &flipped))\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif ( i == facet->numBorders ) {\n\t\t\t\tif (facet->numBorders > 4 + 6 + 16) Com_Printf(\"ERROR: too many bevels\\n\");\n\t\t\t\tfacet->borderPlanes[facet->numBorders] = CM_FindPlane2(plane, &flipped);\n\t\t\t\tfacet->borderNoAdjust[facet->numBorders] = (qboolean) 0;\n\t\t\t\tfacet->borderInward[facet->numBorders] = flipped;\n\t\t\t\tfacet->numBorders++;\n\t\t\t}\n\t\t}\n\t}\n\t//\n\t// add the edge bevels\n\t//\n\t// test the non-axial plane edges\n\tfor ( j = 0 ; j < w->numpoints ; j++ )\n\t{\n\t\tk = (j+1)%w->numpoints;\n\t\tVectorSubtract (w->p[j], w->p[k], vec);\n\t\t//if it's a degenerate edge\n\t\tif (VectorNormalize (vec) < 0.5)\n\t\t\tcontinue;\n\t\tCM_SnapVector(vec);\n\t\tfor ( k = 0; k < 3 ; k++ )\n\t\t\tif ( vec[k] == -1 || vec[k] == 1 )\n\t\t\t\tbreak;\t// axial\n\t\tif ( k < 3 )\n\t\t\tcontinue;\t// only test non-axial edges\n\n\t\t// try the six possible slanted axials from this edge\n\t\tfor ( axis = 0 ; axis < 3 ; axis++ )\n\t\t{\n\t\t\tfor ( dir = -1 ; dir <= 1 ; dir += 2 )\n\t\t\t{\n\t\t\t\t// construct a plane\n\t\t\t\tVectorClear (vec2);\n\t\t\t\tvec2[axis] = dir;\n\t\t\t\tCrossProduct (vec, vec2, plane);\n\t\t\t\tif (VectorNormalize (plane) < 0.5)\n\t\t\t\t\tcontinue;\n\t\t\t\tplane[3] = DotProduct (w->p[j], plane);\n\n\t\t\t\t// if all the points of the facet winding are\n\t\t\t\t// behind this plane, it is a proper edge bevel\n\t\t\t\tfor ( l = 0 ; l < w->numpoints ; l++ )\n\t\t\t\t{\n\t\t\t\t\td = DotProduct (w->p[l], plane) - plane[3];\n\t\t\t\t\tif (d > 0.1)\n\t\t\t\t\t\tbreak;\t// point in front\n\t\t\t\t}\n\t\t\t\tif ( l < w->numpoints )\n\t\t\t\t\tcontinue;\n\n\t\t\t\t//if it's the surface plane\n\t\t\t\tif (CM_PlaneEqual(&planes[facet->surfacePlane], plane, &flipped)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t// see if the plane is allready present\n\t\t\t\tfor ( i = 0 ; i < facet->numBorders ; i++ ) {\n\t\t\t\t\tif (CM_PlaneEqual(&planes[facet->borderPlanes[i]], plane, &flipped)) {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ( i == facet->numBorders ) {\n\t\t\t\t\tif (facet->numBorders > 4 + 6 + 16) Com_Printf(\"ERROR: too many bevels\\n\");\n\t\t\t\t\tfacet->borderPlanes[facet->numBorders] = CM_FindPlane2(plane, &flipped);\n\n\t\t\t\t\tfor ( k = 0 ; k < facet->numBorders ; k++ ) {\n\t\t\t\t\t\tif (facet->borderPlanes[facet->numBorders] ==\n\t\t\t\t\t\t\tfacet->borderPlanes[k]) Com_Printf(\"WARNING: bevel plane already used\\n\");\n\t\t\t\t\t}\n\n\t\t\t\t\tfacet->borderNoAdjust[facet->numBorders] = (qboolean) 0;\n\t\t\t\t\tfacet->borderInward[facet->numBorders] = flipped;\n\t\t\t\t\t//\n\t\t\t\t\tw2 = CopyWinding(w);\n\t\t\t\t\tVector4Copy(planes[facet->borderPlanes[facet->numBorders]].plane, newplane);\n\t\t\t\t\tif (!facet->borderInward[facet->numBorders])\n\t\t\t\t\t{\n\t\t\t\t\t\tVectorNegate(newplane, newplane);\n\t\t\t\t\t\tnewplane[3] = -newplane[3];\n\t\t\t\t\t} //end if\n\t\t\t\t\tChopWindingInPlace( &w2, newplane, newplane[3], 0.1f );\n\t\t\t\t\tif (!w2) {\n\t\t\t\t\t\tCom_DPrintf(\"WARNING: CM_AddFacetBevels... invalid bevel\\n\");\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tFreeWinding(w2);\n\t\t\t\t\t}\n\t\t\t\t\t//\n\t\t\t\t\tfacet->numBorders++;\n\t\t\t\t\t//already got a bevel\n//\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tFreeWinding( w );\n\n#ifndef BSPC\n\t//add opposite plane\n\tfacet->borderPlanes[facet->numBorders] = facet->surfacePlane;\n\tfacet->borderNoAdjust[facet->numBorders] = (qboolean) 0;\n\tfacet->borderInward[facet->numBorders] = qtrue;\n\tfacet->numBorders++;\n#endif //BSPC\n\n}\n\ntypedef enum {\n\tEN_TOP,\n\tEN_RIGHT,\n\tEN_BOTTOM,\n\tEN_LEFT\n} edgeName_t;\n\n/*\n==================\nCM_PatchCollideFromGrid\n==================\n*/\nstatic void CM_PatchCollideFromGrid( cGrid_t *grid, patchCollide_t *pf ) {\n\tint\t\t\t\ti, j;\n\tfloat\t\t\t*p1, *p2, *p3;\n\tMAC_STATIC int\t\t\t\tgridPlanes[MAX_GRID_SIZE][MAX_GRID_SIZE][2];\n\tfacet_t\t\t\t*facet;\n\tint\t\t\t\tborders[4];\n\tint\t\t\t\tnoAdjust[4];\n\n\tnumPlanes = 0;\n\tnumFacets = 0;\n\n\t// find the planes for each triangle of the grid\n\tfor ( i = 0 ; i < grid->width - 1 ; i++ ) {\n\t\tfor ( j = 0 ; j < grid->height - 1 ; j++ ) {\n\t\t\tp1 = grid->points[i][j];\n\t\t\tp2 = grid->points[i+1][j];\n\t\t\tp3 = grid->points[i+1][j+1];\n\t\t\tgridPlanes[i][j][0] = CM_FindPlane( p1, p2, p3 );\n\n\t\t\tp1 = grid->points[i+1][j+1];\n\t\t\tp2 = grid->points[i][j+1];\n\t\t\tp3 = grid->points[i][j];\n\t\t\tgridPlanes[i][j][1] = CM_FindPlane( p1, p2, p3 );\n\t\t}\n\t}\n\n\t// create the borders for each facet\n\tfor ( i = 0 ; i < grid->width - 1 ; i++ ) {\n\t\tfor ( j = 0 ; j < grid->height - 1 ; j++ ) {\n\t\t\t \n\t\t\tborders[EN_TOP] = -1;\n\t\t\tif ( j > 0 ) {\n\t\t\t\tborders[EN_TOP] = gridPlanes[i][j-1][1];\n\t\t\t} else if ( grid->wrapHeight ) {\n\t\t\t\tborders[EN_TOP] = gridPlanes[i][grid->height-2][1];\n\t\t\t} \n\t\t\tnoAdjust[EN_TOP] = ( borders[EN_TOP] == gridPlanes[i][j][0] );\n\t\t\tif ( borders[EN_TOP] == -1 || noAdjust[EN_TOP] ) {\n\t\t\t\tborders[EN_TOP] = CM_EdgePlaneNum( grid, gridPlanes, i, j, 0 );\n\t\t\t}\n\n\t\t\tborders[EN_BOTTOM] = -1;\n\t\t\tif ( j < grid->height - 2 ) {\n\t\t\t\tborders[EN_BOTTOM] = gridPlanes[i][j+1][0];\n\t\t\t} else if ( grid->wrapHeight ) {\n\t\t\t\tborders[EN_BOTTOM] = gridPlanes[i][0][0];\n\t\t\t}\n\t\t\tnoAdjust[EN_BOTTOM] = ( borders[EN_BOTTOM] == gridPlanes[i][j][1] );\n\t\t\tif ( borders[EN_BOTTOM] == -1 || noAdjust[EN_BOTTOM] ) {\n\t\t\t\tborders[EN_BOTTOM] = CM_EdgePlaneNum( grid, gridPlanes, i, j, 2 );\n\t\t\t}\n\n\t\t\tborders[EN_LEFT] = -1;\n\t\t\tif ( i > 0 ) {\n\t\t\t\tborders[EN_LEFT] = gridPlanes[i-1][j][0];\n\t\t\t} else if ( grid->wrapWidth ) {\n\t\t\t\tborders[EN_LEFT] = gridPlanes[grid->width-2][j][0];\n\t\t\t}\n\t\t\tnoAdjust[EN_LEFT] = ( borders[EN_LEFT] == gridPlanes[i][j][1] );\n\t\t\tif ( borders[EN_LEFT] == -1 || noAdjust[EN_LEFT] ) {\n\t\t\t\tborders[EN_LEFT] = CM_EdgePlaneNum( grid, gridPlanes, i, j, 3 );\n\t\t\t}\n\n\t\t\tborders[EN_RIGHT] = -1;\n\t\t\tif ( i < grid->width - 2 ) {\n\t\t\t\tborders[EN_RIGHT] = gridPlanes[i+1][j][1];\n\t\t\t} else if ( grid->wrapWidth ) {\n\t\t\t\tborders[EN_RIGHT] = gridPlanes[0][j][1];\n\t\t\t}\n\t\t\tnoAdjust[EN_RIGHT] = ( borders[EN_RIGHT] == gridPlanes[i][j][0] );\n\t\t\tif ( borders[EN_RIGHT] == -1 || noAdjust[EN_RIGHT] ) {\n\t\t\t\tborders[EN_RIGHT] = CM_EdgePlaneNum( grid, gridPlanes, i, j, 1 );\n\t\t\t}\n\n\t\t\tif ( numFacets == MAX_FACETS ) {\n\t\t\t\tCom_Error( ERR_DROP, \"MAX_FACETS\" );\n\t\t\t}\n\t\t\tfacet = &facets[numFacets];\n\t\t\tCom_Memset( facet, 0, sizeof( *facet ) );\n\n\t\t\tif ( gridPlanes[i][j][0] == gridPlanes[i][j][1] ) {\n\t\t\t\tif ( gridPlanes[i][j][0] == -1 ) {\n\t\t\t\t\tcontinue;\t\t// degenrate\n\t\t\t\t}\n\t\t\t\tfacet->surfacePlane = gridPlanes[i][j][0];\n\t\t\t\tfacet->numBorders = 4;\n\t\t\t\tfacet->borderPlanes[0] = borders[EN_TOP];\n\t\t\t\tfacet->borderNoAdjust[0] = (qboolean) noAdjust[EN_TOP];\n\t\t\t\tfacet->borderPlanes[1] = borders[EN_RIGHT];\n\t\t\t\tfacet->borderNoAdjust[1] = (qboolean) noAdjust[EN_RIGHT];\n\t\t\t\tfacet->borderPlanes[2] = borders[EN_BOTTOM];\n\t\t\t\tfacet->borderNoAdjust[2] = (qboolean)noAdjust[EN_BOTTOM];\n\t\t\t\tfacet->borderPlanes[3] = borders[EN_LEFT];\n\t\t\t\tfacet->borderNoAdjust[3] = (qboolean) noAdjust[EN_LEFT];\n\t\t\t\tCM_SetBorderInward( facet, grid, gridPlanes, i, j, -1 );\n\t\t\t\tif ( CM_ValidateFacet( facet ) ) {\n\t\t\t\t\tCM_AddFacetBevels( facet );\n\t\t\t\t\tnumFacets++;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// two seperate triangles\n\t\t\t\tfacet->surfacePlane = gridPlanes[i][j][0];\n\t\t\t\tfacet->numBorders = 3;\n\t\t\t\tfacet->borderPlanes[0] = borders[EN_TOP];\n\t\t\t\tfacet->borderNoAdjust[0] = (qboolean)noAdjust[EN_TOP];\n\t\t\t\tfacet->borderPlanes[1] = borders[EN_RIGHT];\n\t\t\t\tfacet->borderNoAdjust[1] = (qboolean)noAdjust[EN_RIGHT];\n\t\t\t\tfacet->borderPlanes[2] = gridPlanes[i][j][1];\n\t\t\t\tif ( facet->borderPlanes[2] == -1 ) {\n\t\t\t\t\tfacet->borderPlanes[2] = borders[EN_BOTTOM];\n\t\t\t\t\tif ( facet->borderPlanes[2] == -1 ) {\n\t\t\t\t\t\tfacet->borderPlanes[2] = CM_EdgePlaneNum( grid, gridPlanes, i, j, 4 );\n\t\t\t\t\t}\n\t\t\t\t}\n \t\t\t\tCM_SetBorderInward( facet, grid, gridPlanes, i, j, 0 );\n\t\t\t\tif ( CM_ValidateFacet( facet ) ) {\n\t\t\t\t\tCM_AddFacetBevels( facet );\n\t\t\t\t\tnumFacets++;\n\t\t\t\t}\n\n\t\t\t\tif ( numFacets == MAX_FACETS ) {\n\t\t\t\t\tCom_Error( ERR_DROP, \"MAX_FACETS\" );\n\t\t\t\t}\n\t\t\t\tfacet = &facets[numFacets];\n\t\t\t\tCom_Memset( facet, 0, sizeof( *facet ) );\n\n\t\t\t\tfacet->surfacePlane = gridPlanes[i][j][1];\n\t\t\t\tfacet->numBorders = 3;\n\t\t\t\tfacet->borderPlanes[0] = borders[EN_BOTTOM];\n\t\t\t\tfacet->borderNoAdjust[0] = (qboolean)noAdjust[EN_BOTTOM];\n\t\t\t\tfacet->borderPlanes[1] = borders[EN_LEFT];\n\t\t\t\tfacet->borderNoAdjust[1] = (qboolean)noAdjust[EN_LEFT];\n\t\t\t\tfacet->borderPlanes[2] = gridPlanes[i][j][0];\n\t\t\t\tif ( facet->borderPlanes[2] == -1 ) {\n\t\t\t\t\tfacet->borderPlanes[2] = borders[EN_TOP];\n\t\t\t\t\tif ( facet->borderPlanes[2] == -1 ) {\n\t\t\t\t\t\tfacet->borderPlanes[2] = CM_EdgePlaneNum( grid, gridPlanes, i, j, 5 );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tCM_SetBorderInward( facet, grid, gridPlanes, i, j, 1 );\n\t\t\t\tif ( CM_ValidateFacet( facet ) ) {\n\t\t\t\t\tCM_AddFacetBevels( facet );\n\t\t\t\t\tnumFacets++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// copy the results out\n\tpf->numPlanes = numPlanes;\n\tpf->numFacets = numFacets;\n\tpf->facets = (facet_t*) Hunk_Alloc( numFacets * sizeof( *pf->facets ), h_high );\n\tCom_Memcpy( pf->facets, facets, numFacets * sizeof( *pf->facets ) );\n\tpf->planes = (patchPlane_t*) Hunk_Alloc( numPlanes * sizeof( *pf->planes ), h_high );\n\tCom_Memcpy( pf->planes, planes, numPlanes * sizeof( *pf->planes ) );\n}\n\n\n/*\n===================\nCM_GeneratePatchCollide\n\nCreates an internal structure that will be used to perform\ncollision detection with a patch mesh.\n\nPoints is packed as concatenated rows.\n===================\n*/\nstruct patchCollide_s\t*CM_GeneratePatchCollide( int width, int height, vec3_t *points ) {\n\tpatchCollide_t\t*pf;\n\tMAC_STATIC cGrid_t\t\t\tgrid;\n\tint\t\t\t\ti, j;\n\n\tif ( width <= 2 || height <= 2 || !points ) {\n\t\tCom_Error( ERR_DROP, \"CM_GeneratePatchFacets: bad parameters: (%i, %i, %p)\",\n\t\t\twidth, height, points );\n\t}\n\n\tif ( !(width & 1) || !(height & 1) ) {\n\t\tCom_Error( ERR_DROP, \"CM_GeneratePatchFacets: even sizes are invalid for quadratic meshes\" );\n\t}\n\n\tif ( width > MAX_GRID_SIZE || height > MAX_GRID_SIZE ) {\n\t\tCom_Error( ERR_DROP, \"CM_GeneratePatchFacets: source is > MAX_GRID_SIZE\" );\n\t}\n\n\t// build a grid\n\tgrid.width = width;\n\tgrid.height = height;\n\tgrid.wrapWidth = qfalse;\n\tgrid.wrapHeight = qfalse;\n\tfor ( i = 0 ; i < width ; i++ ) {\n\t\tfor ( j = 0 ; j < height ; j++ ) {\n\t\t\tVectorCopy( points[j*width + i], grid.points[i][j] );\n\t\t}\n\t}\n\n\t// subdivide the grid\n\tCM_SetGridWrapWidth( &grid );\n\tCM_SubdivideGridColumns( &grid );\n\tCM_RemoveDegenerateColumns( &grid );\n\n\tCM_TransposeGrid( &grid );\n\n\tCM_SetGridWrapWidth( &grid );\n\tCM_SubdivideGridColumns( &grid );\n\tCM_RemoveDegenerateColumns( &grid );\n\n\t// we now have a grid of points exactly on the curve\n\t// the aproximate surface defined by these points will be\n\t// collided against\n\tpf = (patchCollide_t*) Hunk_Alloc( sizeof( *pf ), h_high );\n\tClearBounds( pf->bounds[0], pf->bounds[1] );\n\tfor ( i = 0 ; i < grid.width ; i++ ) {\n\t\tfor ( j = 0 ; j < grid.height ; j++ ) {\n\t\t\tAddPointToBounds( grid.points[i][j], pf->bounds[0], pf->bounds[1] );\n\t\t}\n\t}\n\n\tc_totalPatchBlocks += ( grid.width - 1 ) * ( grid.height - 1 );\n\n\t// generate a bsp tree for the surface\n\tCM_PatchCollideFromGrid( &grid, pf );\n\n\t// expand by one unit for epsilon purposes\n\tpf->bounds[0][0] -= 1;\n\tpf->bounds[0][1] -= 1;\n\tpf->bounds[0][2] -= 1;\n\n\tpf->bounds[1][0] += 1;\n\tpf->bounds[1][1] += 1;\n\tpf->bounds[1][2] += 1;\n\n\treturn pf;\n}\n\n/*\n================================================================================\n\nTRACE TESTING\n\n================================================================================\n*/\n\n/*\n====================\nCM_TracePointThroughPatchCollide\n\n  special case for point traces because the patch collide \"brushes\" have no volume\n====================\n*/\nvoid CM_TracePointThroughPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc ) {\n\tqboolean\tfrontFacing[MAX_PATCH_PLANES];\n\tfloat\t\tintersection[MAX_PATCH_PLANES];\n\tfloat\t\tintersect;\n\tconst patchPlane_t\t*planes;\n\tconst facet_t\t*facet;\n\tint\t\t\ti, j, k;\n\tfloat\t\toffset;\n\tfloat\t\td1, d2;\n#ifndef BSPC\n\tstatic cvar_t *cv;\n#endif //BSPC\n\n#ifndef BSPC\n\tif ( !cm_playerCurveClip->integer || !tw->isPoint ) {\n\t\treturn;\n\t}\n#endif\n\n\t// determine the trace's relationship to all planes\n\tplanes = pc->planes;\n\tfor ( i = 0 ; i < pc->numPlanes ; i++, planes++ ) {\n\t\toffset = DotProduct( tw->offsets[ planes->signbits ], planes->plane );\n\t\td1 = DotProduct( tw->start, planes->plane ) - planes->plane[3] + offset;\n\t\td2 = DotProduct( tw->end, planes->plane ) - planes->plane[3] + offset;\n\t\tif ( d1 <= 0 ) {\n\t\t\tfrontFacing[i] = qfalse;\n\t\t} else {\n\t\t\tfrontFacing[i] = qtrue;\n\t\t}\n\t\tif ( d1 == d2 ) {\n\t\t\tintersection[i] = 99999;\n\t\t} else {\n\t\t\tintersection[i] = d1 / ( d1 - d2 );\n\t\t\tif ( intersection[i] <= 0 ) {\n\t\t\t\tintersection[i] = 99999;\n\t\t\t}\n\t\t}\n\t}\n\n\n\t// see if any of the surface planes are intersected\n\tfacet = pc->facets;\n\tfor ( i = 0 ; i < pc->numFacets ; i++, facet++ ) {\n\t\tif ( !frontFacing[facet->surfacePlane] ) {\n\t\t\tcontinue;\n\t\t}\n\t\tintersect = intersection[facet->surfacePlane];\n\t\tif ( intersect < 0 ) {\n\t\t\tcontinue;\t\t// surface is behind the starting point\n\t\t}\n\t\tif ( intersect > tw->trace.fraction ) {\n\t\t\tcontinue;\t\t// already hit something closer\n\t\t}\n\t\tfor ( j = 0 ; j < facet->numBorders ; j++ ) {\n\t\t\tk = facet->borderPlanes[j];\n\t\t\tif ( frontFacing[k] ^ facet->borderInward[j] ) {\n\t\t\t\tif ( intersection[k] > intersect ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif ( intersection[k] < intersect ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif ( j == facet->numBorders ) {\n\t\t\t// we hit this facet\n#ifndef BSPC\n\t\t\tif (!cv) {\n\t\t\t\tcv = Cvar_Get( \"r_debugSurfaceUpdate\", \"1\", 0 );\n\t\t\t}\n\t\t\tif (cv->integer) {\n\t\t\t\tdebugPatchCollide = pc;\n\t\t\t\tdebugFacet = facet;\n\t\t\t}\n#endif //BSPC\n\t\t\tplanes = &pc->planes[facet->surfacePlane];\n\n\t\t\t// calculate intersection with a slight pushoff\n\t\t\toffset = DotProduct( tw->offsets[ planes->signbits ], planes->plane );\n\t\t\td1 = DotProduct( tw->start, planes->plane ) - planes->plane[3] + offset;\n\t\t\td2 = DotProduct( tw->end, planes->plane ) - planes->plane[3] + offset;\n\t\t\ttw->trace.fraction = ( d1 - SURFACE_CLIP_EPSILON ) / ( d1 - d2 );\n\n\t\t\tif ( tw->trace.fraction < 0 ) {\n\t\t\t\ttw->trace.fraction = 0;\n\t\t\t}\n\n\t\t\tVectorCopy( planes->plane,  tw->trace.plane.normal );\n\t\t\ttw->trace.plane.dist = planes->plane[3];\n\t\t}\n\t}\n}\n\n/*\n====================\nCM_CheckFacetPlane\n====================\n*/\nint CM_CheckFacetPlane(float *plane, vec3_t start, vec3_t end, float *enterFrac, float *leaveFrac, int *hit) {\n\tfloat d1, d2, f;\n\n\t*hit = qfalse;\n\n\td1 = DotProduct( start, plane ) - plane[3];\n\td2 = DotProduct( end, plane ) - plane[3];\n\n\t// if completely in front of face, no intersection with the entire facet\n\tif (d1 > 0 && ( d2 >= SURFACE_CLIP_EPSILON || d2 >= d1 )  ) {\n\t\treturn qfalse;\n\t}\n\n\t// if it doesn't cross the plane, the plane isn't relevent\n\tif (d1 <= 0 && d2 <= 0 ) {\n\t\treturn qtrue;\n\t}\n\n\t// crosses face\n\tif (d1 > d2) {\t// enter\n\t\tf = (d1-SURFACE_CLIP_EPSILON) / (d1-d2);\n\t\tif ( f < 0 ) {\n\t\t\tf = 0;\n\t\t}\n\t\t//always favor previous plane hits and thus also the surface plane hit\n\t\tif (f > *enterFrac) {\n\t\t\t*enterFrac = f;\n\t\t\t*hit = qtrue;\n\t\t}\n\t} else {\t// leave\n\t\tf = (d1+SURFACE_CLIP_EPSILON) / (d1-d2);\n\t\tif ( f > 1 ) {\n\t\t\tf = 1;\n\t\t}\n\t\tif (f < *leaveFrac) {\n\t\t\t*leaveFrac = f;\n\t\t}\n\t}\n\treturn qtrue;\n}\n\n/*\n====================\nCM_TraceThroughPatchCollide\n====================\n*/\nvoid CM_TraceThroughPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc ) {\n\tint i, j, hit, hitnum;\n\tfloat offset, enterFrac, leaveFrac, t;\n\tpatchPlane_t *planes;\n\tfacet_t\t*facet;\n\tfloat plane[4], bestplane[4];\n\tvec3_t startp, endp;\n#ifndef BSPC\n\tstatic cvar_t *cv;\n#endif //BSPC\n\n\tif (tw->isPoint) {\n\t\tCM_TracePointThroughPatchCollide( tw, pc );\n\t\treturn;\n\t}\n\n\tfacet = pc->facets;\n\tfor ( i = 0 ; i < pc->numFacets ; i++, facet++ ) {\n\t\tenterFrac = -1.0;\n\t\tleaveFrac = 1.0;\n\t\thitnum = -1;\n\t\t//\n\t\tplanes = &pc->planes[ facet->surfacePlane ];\n\t\tVectorCopy(planes->plane, plane);\n\t\tplane[3] = planes->plane[3];\n\t\tif ( tw->sphere.use ) {\n\t\t\t// adjust the plane distance apropriately for radius\n\t\t\tplane[3] += tw->sphere.radius;\n\n\t\t\t// find the closest point on the capsule to the plane\n\t\t\tt = DotProduct( plane, tw->sphere.offset );\n\t\t\tif ( t > 0.0f ) {\n\t\t\t\tVectorSubtract( tw->start, tw->sphere.offset, startp );\n\t\t\t\tVectorSubtract( tw->end, tw->sphere.offset, endp );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tVectorAdd( tw->start, tw->sphere.offset, startp );\n\t\t\t\tVectorAdd( tw->end, tw->sphere.offset, endp );\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\toffset = DotProduct( tw->offsets[ planes->signbits ], plane);\n\t\t\tplane[3] -= offset;\n\t\t\tVectorCopy( tw->start, startp );\n\t\t\tVectorCopy( tw->end, endp );\n\t\t}\n\n\t\tif (!CM_CheckFacetPlane(plane, startp, endp, &enterFrac, &leaveFrac, &hit)) {\n\t\t\tcontinue;\n\t\t}\n\t\tif (hit) {\n\t\t\tVector4Copy(plane, bestplane);\n\t\t}\n\n\t\tfor ( j = 0; j < facet->numBorders; j++ ) {\n\t\t\tplanes = &pc->planes[ facet->borderPlanes[j] ];\n\t\t\tif (facet->borderInward[j]) {\n\t\t\t\tVectorNegate(planes->plane, plane);\n\t\t\t\tplane[3] = -planes->plane[3];\n\t\t\t}\n\t\t\telse {\n\t\t\t\tVectorCopy(planes->plane, plane);\n\t\t\t\tplane[3] = planes->plane[3];\n\t\t\t}\n\t\t\tif ( tw->sphere.use ) {\n\t\t\t\t// adjust the plane distance apropriately for radius\n\t\t\t\tplane[3] += tw->sphere.radius;\n\n\t\t\t\t// find the closest point on the capsule to the plane\n\t\t\t\tt = DotProduct( plane, tw->sphere.offset );\n\t\t\t\tif ( t > 0.0f ) {\n\t\t\t\t\tVectorSubtract( tw->start, tw->sphere.offset, startp );\n\t\t\t\t\tVectorSubtract( tw->end, tw->sphere.offset, endp );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tVectorAdd( tw->start, tw->sphere.offset, startp );\n\t\t\t\t\tVectorAdd( tw->end, tw->sphere.offset, endp );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// NOTE: this works even though the plane might be flipped because the bbox is centered\n\t\t\t\toffset = DotProduct( tw->offsets[ planes->signbits ], plane);\n\t\t\t\tplane[3] += fabs(offset);\n\t\t\t\tVectorCopy( tw->start, startp );\n\t\t\t\tVectorCopy( tw->end, endp );\n\t\t\t}\n\n\t\t\tif (!CM_CheckFacetPlane(plane, startp, endp, &enterFrac, &leaveFrac, &hit)) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (hit) {\n\t\t\t\thitnum = j;\n\t\t\t\tVector4Copy(plane, bestplane);\n\t\t\t}\n\t\t}\n\t\tif (j < facet->numBorders) continue;\n\t\t//never clip against the back side\n\t\tif (hitnum == facet->numBorders - 1) continue;\n\n\t\tif (enterFrac < leaveFrac && enterFrac >= 0) {\n\t\t\tif (enterFrac < tw->trace.fraction) {\n\t\t\t\tif (enterFrac < 0) {\n\t\t\t\t\tenterFrac = 0;\n\t\t\t\t}\n#ifndef BSPC\n\t\t\t\tif (!cv) {\n\t\t\t\t\tcv = Cvar_Get( \"r_debugSurfaceUpdate\", \"1\", 0 );\n\t\t\t\t}\n\t\t\t\tif (cv && cv->integer) {\n\t\t\t\t\tdebugPatchCollide = pc;\n\t\t\t\t\tdebugFacet = facet;\n\t\t\t\t}\n#endif //BSPC\n\n\t\t\t\ttw->trace.fraction = enterFrac;\n\t\t\t\tVectorCopy( bestplane, tw->trace.plane.normal );\n\t\t\t\ttw->trace.plane.dist = bestplane[3];\n\t\t\t}\n\t\t}\n\t}\n}\n\n\n/*\n=======================================================================\n\nPOSITION TEST\n\n=======================================================================\n*/\n\n/*\n====================\nCM_PositionTestInPatchCollide\n====================\n*/\nqboolean CM_PositionTestInPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc ) {\n\tint i, j;\n\tfloat offset, t;\n\tpatchPlane_t *planes;\n\tfacet_t\t*facet;\n\tfloat plane[4];\n\tvec3_t startp;\n\n\tif (tw->isPoint) {\n\t\treturn qfalse;\n\t}\n\t//\n\tfacet = pc->facets;\n\tfor ( i = 0 ; i < pc->numFacets ; i++, facet++ ) {\n\t\tplanes = &pc->planes[ facet->surfacePlane ];\n\t\tVectorCopy(planes->plane, plane);\n\t\tplane[3] = planes->plane[3];\n\t\tif ( tw->sphere.use ) {\n\t\t\t// adjust the plane distance apropriately for radius\n\t\t\tplane[3] += tw->sphere.radius;\n\n\t\t\t// find the closest point on the capsule to the plane\n\t\t\tt = DotProduct( plane, tw->sphere.offset );\n\t\t\tif ( t > 0 ) {\n\t\t\t\tVectorSubtract( tw->start, tw->sphere.offset, startp );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tVectorAdd( tw->start, tw->sphere.offset, startp );\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\toffset = DotProduct( tw->offsets[ planes->signbits ], plane);\n\t\t\tplane[3] -= offset;\n\t\t\tVectorCopy( tw->start, startp );\n\t\t}\n\n\t\tif ( DotProduct( plane, startp ) - plane[3] > 0.0f ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tfor ( j = 0; j < facet->numBorders; j++ ) {\n\t\t\tplanes = &pc->planes[ facet->borderPlanes[j] ];\n\t\t\tif (facet->borderInward[j]) {\n\t\t\t\tVectorNegate(planes->plane, plane);\n\t\t\t\tplane[3] = -planes->plane[3];\n\t\t\t}\n\t\t\telse {\n\t\t\t\tVectorCopy(planes->plane, plane);\n\t\t\t\tplane[3] = planes->plane[3];\n\t\t\t}\n\t\t\tif ( tw->sphere.use ) {\n\t\t\t\t// adjust the plane distance apropriately for radius\n\t\t\t\tplane[3] += tw->sphere.radius;\n\n\t\t\t\t// find the closest point on the capsule to the plane\n\t\t\t\tt = DotProduct( plane, tw->sphere.offset );\n\t\t\t\tif ( t > 0.0f ) {\n\t\t\t\t\tVectorSubtract( tw->start, tw->sphere.offset, startp );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tVectorAdd( tw->start, tw->sphere.offset, startp );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// NOTE: this works even though the plane might be flipped because the bbox is centered\n\t\t\t\toffset = DotProduct( tw->offsets[ planes->signbits ], plane);\n\t\t\t\tplane[3] += fabs(offset);\n\t\t\t\tVectorCopy( tw->start, startp );\n\t\t\t}\n\n\t\t\tif ( DotProduct( plane, startp ) - plane[3] > 0.0f ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (j < facet->numBorders) {\n\t\t\tcontinue;\n\t\t}\n\t\t// inside this patch facet\n\t\treturn qtrue;\n\t}\n\treturn qfalse;\n}\n\n/*\n=======================================================================\n\nDEBUGGING\n\n=======================================================================\n*/\n\n\n/*\n==================\nCM_DrawDebugSurface\n\nCalled from the renderer\n==================\n*/\n#ifndef BSPC\nvoid BotDrawDebugPolygons(void (*drawPoly)(int color, int numPoints, float *points), int value);\n#endif\n\nvoid CM_DrawDebugSurface( void (*drawPoly)(int color, int numPoints, float *points) ) {\n\tstatic cvar_t\t*cv;\n#ifndef BSPC\n\tstatic cvar_t\t*cv2;\n#endif\n\tconst patchCollide_t\t*pc;\n\tfacet_t\t\t\t*facet;\n\twinding_t\t\t*w;\n\tint\t\t\t\ti, j, k, n;\n\tint\t\t\t\tcurplanenum, planenum, curinward, inward;\n\tfloat\t\t\tplane[4];\n\tvec3_t mins = {-15, -15, -28}, maxs = {15, 15, 28};\n\t//vec3_t mins = {0, 0, 0}, maxs = {0, 0, 0};\n\tvec3_t v1, v2;\n\n#ifndef BSPC\n\tif ( !cv2 )\n\t{\n\t\tcv2 = Cvar_Get( \"r_debugSurface\", \"0\", 0 );\n\t}\n\n\tif (cv2->integer != 1)\n\t{\n\t\tBotDrawDebugPolygons(drawPoly, cv2->integer);\n\t\treturn;\n\t}\n#endif\n\n\tif ( !debugPatchCollide ) {\n\t\treturn;\n\t}\n\n#ifndef BSPC\n\tif ( !cv ) {\n\t\tcv = Cvar_Get( \"cm_debugSize\", \"2\", 0 );\n\t}\n#endif\n\tpc = debugPatchCollide;\n\n\tfor ( i = 0, facet = pc->facets ; i < pc->numFacets ; i++, facet++ ) {\n\n\t\tfor ( k = 0 ; k < facet->numBorders + 1; k++ ) {\n\t\t\t//\n\t\t\tif (k < facet->numBorders) {\n\t\t\t\tplanenum = facet->borderPlanes[k];\n\t\t\t\tinward = facet->borderInward[k];\n\t\t\t}\n\t\t\telse {\n\t\t\t\tplanenum = facet->surfacePlane;\n\t\t\t\tinward = qfalse;\n\t\t\t\t//continue;\n\t\t\t}\n\n\t\t\tVector4Copy( pc->planes[ planenum ].plane, plane );\n\n\t\t\t//planenum = facet->surfacePlane;\n\t\t\tif ( inward ) {\n\t\t\t\tVectorSubtract( vec3_origin, plane, plane );\n\t\t\t\tplane[3] = -plane[3];\n\t\t\t}\n\n\t\t\tplane[3] += cv->value;\n\t\t\t//*\n\t\t\tfor (n = 0; n < 3; n++)\n\t\t\t{\n\t\t\t\tif (plane[n] > 0) v1[n] = maxs[n];\n\t\t\t\telse v1[n] = mins[n];\n\t\t\t} //end for\n\t\t\tVectorNegate(plane, v2);\n\t\t\tplane[3] += fabs(DotProduct(v1, v2));\n\t\t\t//*/\n\n\t\t\tw = BaseWindingForPlane( plane,  plane[3] );\n\t\t\tfor ( j = 0 ; j < facet->numBorders + 1 && w; j++ ) {\n\t\t\t\t//\n\t\t\t\tif (j < facet->numBorders) {\n\t\t\t\t\tcurplanenum = facet->borderPlanes[j];\n\t\t\t\t\tcurinward = facet->borderInward[j];\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tcurplanenum = facet->surfacePlane;\n\t\t\t\t\tcurinward = qfalse;\n\t\t\t\t\t//continue;\n\t\t\t\t}\n\t\t\t\t//\n\t\t\t\tif (curplanenum == planenum) continue;\n\n\t\t\t\tVector4Copy( pc->planes[ curplanenum ].plane, plane );\n\t\t\t\tif ( !curinward ) {\n\t\t\t\t\tVectorSubtract( vec3_origin, plane, plane );\n\t\t\t\t\tplane[3] = -plane[3];\n\t\t\t\t}\n\t\t//\t\t\tif ( !facet->borderNoAdjust[j] ) {\n\t\t\t\t\tplane[3] -= cv->value;\n\t\t//\t\t\t}\n\t\t\t\tfor (n = 0; n < 3; n++)\n\t\t\t\t{\n\t\t\t\t\tif (plane[n] > 0) v1[n] = maxs[n];\n\t\t\t\t\telse v1[n] = mins[n];\n\t\t\t\t} //end for\n\t\t\t\tVectorNegate(plane, v2);\n\t\t\t\tplane[3] -= fabs(DotProduct(v1, v2));\n\n\t\t\t\tChopWindingInPlace( &w, plane, plane[3], 0.1f );\n\t\t\t}\n\t\t\tif ( w ) {\n\t\t\t\tif ( facet == debugFacet ) {\n\t\t\t\t\tdrawPoly( 4, w->numpoints, w->p[0] );\n\t\t\t\t\t//Com_Printf(\"blue facet has %d border planes\\n\", facet->numBorders);\n\t\t\t\t} else {\n\t\t\t\t\tdrawPoly( 1, w->numpoints, w->p[0] );\n\t\t\t\t}\n\t\t\t\tFreeWinding( w );\n\t\t\t}\n\t\t\telse\n\t\t\t\tCom_Printf(\"winding chopped away by border planes\\n\");\n\t\t}\n\t}\n\n\t// draw the debug block\n\t{\n\t\tvec3_t\t\t\tv[3];\n\n\t\tVectorCopy( debugBlockPoints[0], v[0] );\n\t\tVectorCopy( debugBlockPoints[1], v[1] );\n\t\tVectorCopy( debugBlockPoints[2], v[2] );\n\t\tdrawPoly( 2, 3, v[0] );\n\n\t\tVectorCopy( debugBlockPoints[2], v[0] );\n\t\tVectorCopy( debugBlockPoints[3], v[1] );\n\t\tVectorCopy( debugBlockPoints[0], v[2] );\n\t\tdrawPoly( 2, 3, v[0] );\n\t}\n\n#if 0\n\tvec3_t\t\t\tv[4];\n\n\tv[0][0] = pc->bounds[1][0];\n\tv[0][1] = pc->bounds[1][1];\n\tv[0][2] = pc->bounds[1][2];\n\n\tv[1][0] = pc->bounds[1][0];\n\tv[1][1] = pc->bounds[0][1];\n\tv[1][2] = pc->bounds[1][2];\n\n\tv[2][0] = pc->bounds[0][0];\n\tv[2][1] = pc->bounds[0][1];\n\tv[2][2] = pc->bounds[1][2];\n\n\tv[3][0] = pc->bounds[0][0];\n\tv[3][1] = pc->bounds[1][1];\n\tv[3][2] = pc->bounds[1][2];\n\n\tdrawPoly( 4, v[0] );\n#endif\n}\n"
  },
  {
    "path": "src/engine/qcommon/cm_patch.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n//#define\tCULL_BBOX\n\n/*\n\nThis file does not reference any globals, and has these entry points:\n\nvoid CM_ClearLevelPatches( void );\nstruct patchCollide_s\t*CM_GeneratePatchCollide( int width, int height, const vec3_t *points );\nvoid CM_TraceThroughPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc );\nqboolean CM_PositionTestInPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc );\nvoid CM_DrawDebugSurface( void (*drawPoly)(int color, int numPoints, flaot *points) );\n\n\nIssues for collision against curved surfaces:\n\nSurface edges need to be handled differently than surface planes\n\nPlane expansion causes raw surfaces to expand past expanded bounding box\n\nPosition test of a volume against a surface is tricky.\n\nPosition test of a point against a surface is not well defined, because the surface has no volume.\n\n\nTracing leading edge points instead of volumes?\nPosition test by tracing corner to corner? (8*7 traces -- ouch)\n\ncoplanar edges\ntriangulated patches\ndegenerate patches\n\n  endcaps\n  degenerate\n\nWARNING: this may misbehave with meshes that have rows or columns that only\ndegenerate a few triangles.  Completely degenerate rows and columns are handled\nproperly.\n*/\n\n\n#define\tMAX_FACETS\t\t\t1024\n#define\tMAX_PATCH_PLANES\t2048\n\ntypedef struct {\n\tfloat\tplane[4];\n\tint\t\tsignbits;\t\t// signx + (signy<<1) + (signz<<2), used as lookup during collision\n} patchPlane_t;\n\ntypedef struct {\n\tint\t\t\tsurfacePlane;\n\tint\t\t\tnumBorders;\t\t// 3 or four + 6 axial bevels + 4 or 3 * 4 edge bevels\n\tint\t\t\tborderPlanes[4+6+16];\n\tint\t\t\tborderInward[4+6+16];\n\tqboolean\tborderNoAdjust[4+6+16];\n} facet_t;\n\ntypedef struct patchCollide_s {\n\tvec3_t\tbounds[2];\n\tint\t\tnumPlanes;\t\t\t// surface planes plus edge planes\n\tpatchPlane_t\t*planes;\n\tint\t\tnumFacets;\n\tfacet_t\t*facets;\n} patchCollide_t;\n\n\n#define\tMAX_GRID_SIZE\t129\n\ntypedef struct {\n\tint\t\t\twidth;\n\tint\t\t\theight;\n\tqboolean\twrapWidth;\n\tqboolean\twrapHeight;\n\tvec3_t\tpoints[MAX_GRID_SIZE][MAX_GRID_SIZE];\t// [width][height]\n} cGrid_t;\n\n#define\tSUBDIVIDE_DISTANCE\t16\t//4\t// never more than this units away from curve\n#define\tPLANE_TRI_EPSILON\t0.1\n#define\tWRAP_POINT_EPSILON\t0.1\n\n\nstruct patchCollide_s\t*CM_GeneratePatchCollide( int width, int height, vec3_t *points );\n"
  },
  {
    "path": "src/engine/qcommon/cm_polylib.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n// this is only used for visualization tools in cm_ debug functions\n\n\n#include \"cm_local.h\"\n\n\n// counters are only bumped when running single threaded,\n// because they are an awefull coherence problem\nint\tc_active_windings;\nint\tc_peak_windings;\nint\tc_winding_allocs;\nint\tc_winding_points;\n\nvoid pw(winding_t *w)\n{\n\tint\t\ti;\n\tfor (i=0 ; i<w->numpoints ; i++)\n\t\tprintf (\"(%5.1f, %5.1f, %5.1f)\\n\",w->p[i][0], w->p[i][1],w->p[i][2]);\n}\n\n\n/*\n=============\nAllocWinding\n=============\n*/\nwinding_t\t*AllocWinding (int points)\n{\n\twinding_t\t*w;\n\tint\t\t\ts;\n\n\tc_winding_allocs++;\n\tc_winding_points += points;\n\tc_active_windings++;\n\tif (c_active_windings > c_peak_windings)\n\t\tc_peak_windings = c_active_windings;\n\n\ts = sizeof(vec_t)*3*points + sizeof(int);\n\tw = (winding_t*) Z_Malloc (s);\n\tCom_Memset (w, 0, s); \n\treturn w;\n}\n\nvoid FreeWinding (winding_t *w)\n{\n\tif (*(unsigned *)w == 0xdeaddead)\n\t\tCom_Error (ERR_FATAL, \"FreeWinding: freed a freed winding\");\n\t*(unsigned *)w = 0xdeaddead;\n\n\tc_active_windings--;\n\tZ_Free (w);\n}\n\n/*\n============\nRemoveColinearPoints\n============\n*/\nint\tc_removed;\n\nvoid\tRemoveColinearPoints (winding_t *w)\n{\n\tint\t\ti, j, k;\n\tvec3_t\tv1, v2;\n\tint\t\tnump;\n\tvec3_t\tp[MAX_POINTS_ON_WINDING];\n\n\tnump = 0;\n\tfor (i=0 ; i<w->numpoints ; i++)\n\t{\n\t\tj = (i+1)%w->numpoints;\n\t\tk = (i+w->numpoints-1)%w->numpoints;\n\t\tVectorSubtract (w->p[j], w->p[i], v1);\n\t\tVectorSubtract (w->p[i], w->p[k], v2);\n\t\tVectorNormalize2(v1,v1);\n\t\tVectorNormalize2(v2,v2);\n\t\tif (DotProduct(v1, v2) < 0.999)\n\t\t{\n\t\t\tVectorCopy (w->p[i], p[nump]);\n\t\t\tnump++;\n\t\t}\n\t}\n\n\tif (nump == w->numpoints)\n\t\treturn;\n\n\tc_removed += w->numpoints - nump;\n\tw->numpoints = nump;\n\tCom_Memcpy (w->p, p, nump*sizeof(p[0]));\n}\n\n/*\n============\nWindingPlane\n============\n*/\nvoid WindingPlane (winding_t *w, vec3_t normal, vec_t *dist)\n{\n\tvec3_t\tv1, v2;\n\n\tVectorSubtract (w->p[1], w->p[0], v1);\n\tVectorSubtract (w->p[2], w->p[0], v2);\n\tCrossProduct (v2, v1, normal);\n\tVectorNormalize2(normal, normal);\n\t*dist = DotProduct (w->p[0], normal);\n\n}\n\n/*\n=============\nWindingArea\n=============\n*/\nvec_t\tWindingArea (winding_t *w)\n{\n\tint\t\ti;\n\tvec3_t\td1, d2, cross;\n\tvec_t\ttotal;\n\n\ttotal = 0;\n\tfor (i=2 ; i<w->numpoints ; i++)\n\t{\n\t\tVectorSubtract (w->p[i-1], w->p[0], d1);\n\t\tVectorSubtract (w->p[i], w->p[0], d2);\n\t\tCrossProduct (d1, d2, cross);\n\t\ttotal += 0.5 * VectorLength ( cross );\n\t}\n\treturn total;\n}\n\n/*\n=============\nWindingBounds\n=============\n*/\nvoid\tWindingBounds (winding_t *w, vec3_t mins, vec3_t maxs)\n{\n\tvec_t\tv;\n\tint\t\ti,j;\n\n\tmins[0] = mins[1] = mins[2] = MAX_MAP_BOUNDS;\n\tmaxs[0] = maxs[1] = maxs[2] = -MAX_MAP_BOUNDS;\n\n\tfor (i=0 ; i<w->numpoints ; i++)\n\t{\n\t\tfor (j=0 ; j<3 ; j++)\n\t\t{\n\t\t\tv = w->p[i][j];\n\t\t\tif (v < mins[j])\n\t\t\t\tmins[j] = v;\n\t\t\tif (v > maxs[j])\n\t\t\t\tmaxs[j] = v;\n\t\t}\n\t}\n}\n\n/*\n=============\nWindingCenter\n=============\n*/\nvoid\tWindingCenter (winding_t *w, vec3_t center)\n{\n\tint\t\ti;\n\tfloat\tscale;\n\n\tVectorCopy (vec3_origin, center);\n\tfor (i=0 ; i<w->numpoints ; i++)\n\t\tVectorAdd (w->p[i], center, center);\n\n\tscale = 1.0/w->numpoints;\n\tVectorScale (center, scale, center);\n}\n\n/*\n=================\nBaseWindingForPlane\n=================\n*/\nwinding_t *BaseWindingForPlane (vec3_t normal, vec_t dist)\n{\n\tint\t\ti, x;\n\tvec_t\tmax, v;\n\tvec3_t\torg, vright, vup;\n\twinding_t\t*w;\n\t\n// find the major axis\n\n\tmax = -MAX_MAP_BOUNDS;\n\tx = -1;\n\tfor (i=0 ; i<3; i++)\n\t{\n\t\tv = fabs(normal[i]);\n\t\tif (v > max)\n\t\t{\n\t\t\tx = i;\n\t\t\tmax = v;\n\t\t}\n\t}\n\tif (x==-1)\n\t\tCom_Error (ERR_DROP, \"BaseWindingForPlane: no axis found\");\n\t\t\n\tVectorCopy (vec3_origin, vup);\t\n\tswitch (x)\n\t{\n\tcase 0:\n\tcase 1:\n\t\tvup[2] = 1;\n\t\tbreak;\t\t\n\tcase 2:\n\t\tvup[0] = 1;\n\t\tbreak;\t\t\n\t}\n\n\tv = DotProduct (vup, normal);\n\tVectorMA (vup, -v, normal, vup);\n\tVectorNormalize2(vup, vup);\n\t\t\n\tVectorScale (normal, dist, org);\n\t\n\tCrossProduct (vup, normal, vright);\n\t\n\tVectorScale (vup, MAX_MAP_BOUNDS, vup);\n\tVectorScale (vright, MAX_MAP_BOUNDS, vright);\n\n// project a really big\taxis aligned box onto the plane\n\tw = AllocWinding (4);\n\t\n\tVectorSubtract (org, vright, w->p[0]);\n\tVectorAdd (w->p[0], vup, w->p[0]);\n\t\n\tVectorAdd (org, vright, w->p[1]);\n\tVectorAdd (w->p[1], vup, w->p[1]);\n\t\n\tVectorAdd (org, vright, w->p[2]);\n\tVectorSubtract (w->p[2], vup, w->p[2]);\n\t\n\tVectorSubtract (org, vright, w->p[3]);\n\tVectorSubtract (w->p[3], vup, w->p[3]);\n\t\n\tw->numpoints = 4;\n\t\n\treturn w;\t\n}\n\n/*\n==================\nCopyWinding\n==================\n*/\nwinding_t\t*CopyWinding (winding_t *w)\n{\n\tint\t\t\tsize;\n\twinding_t\t*c;\n\n\tc = AllocWinding (w->numpoints);\n\tsize = (int)(intptr_t)((winding_t *)0)->p[w->numpoints];\n\tCom_Memcpy (c, w, size);\n\treturn c;\n}\n\n/*\n==================\nReverseWinding\n==================\n*/\nwinding_t\t*ReverseWinding (winding_t *w)\n{\n\tint\t\t\ti;\n\twinding_t\t*c;\n\n\tc = AllocWinding (w->numpoints);\n\tfor (i=0 ; i<w->numpoints ; i++)\n\t{\n\t\tVectorCopy (w->p[w->numpoints-1-i], c->p[i]);\n\t}\n\tc->numpoints = w->numpoints;\n\treturn c;\n}\n\n\n/*\n=============\nClipWindingEpsilon\n=============\n*/\nvoid\tClipWindingEpsilon (winding_t *in, vec3_t normal, vec_t dist, \n\t\t\t\tvec_t epsilon, winding_t **front, winding_t **back)\n{\n\tvec_t\tdists[MAX_POINTS_ON_WINDING+4];\n\tint\t\tsides[MAX_POINTS_ON_WINDING+4];\n\tint\t\tcounts[3];\n\tstatic\tvec_t\tdot;\t\t// VC 4.2 optimizer bug if not static\n\tint\t\ti, j;\n\tvec_t\t*p1, *p2;\n\tvec3_t\tmid;\n\twinding_t\t*f, *b;\n\tint\t\tmaxpts;\n\t\n\tcounts[0] = counts[1] = counts[2] = 0;\n\n// determine sides for each point\n\tfor (i=0 ; i<in->numpoints ; i++)\n\t{\n\t\tdot = DotProduct (in->p[i], normal);\n\t\tdot -= dist;\n\t\tdists[i] = dot;\n\t\tif (dot > epsilon)\n\t\t\tsides[i] = SIDE_FRONT;\n\t\telse if (dot < -epsilon)\n\t\t\tsides[i] = SIDE_BACK;\n\t\telse\n\t\t{\n\t\t\tsides[i] = SIDE_ON;\n\t\t}\n\t\tcounts[sides[i]]++;\n\t}\n\tsides[i] = sides[0];\n\tdists[i] = dists[0];\n\t\n\t*front = *back = NULL;\n\n\tif (!counts[0])\n\t{\n\t\t*back = CopyWinding (in);\n\t\treturn;\n\t}\n\tif (!counts[1])\n\t{\n\t\t*front = CopyWinding (in);\n\t\treturn;\n\t}\n\n\tmaxpts = in->numpoints+4;\t// cant use counts[0]+2 because\n\t\t\t\t\t\t\t\t// of fp grouping errors\n\n\t*front = f = AllocWinding (maxpts);\n\t*back = b = AllocWinding (maxpts);\n\t\t\n\tfor (i=0 ; i<in->numpoints ; i++)\n\t{\n\t\tp1 = in->p[i];\n\t\t\n\t\tif (sides[i] == SIDE_ON)\n\t\t{\n\t\t\tVectorCopy (p1, f->p[f->numpoints]);\n\t\t\tf->numpoints++;\n\t\t\tVectorCopy (p1, b->p[b->numpoints]);\n\t\t\tb->numpoints++;\n\t\t\tcontinue;\n\t\t}\n\t\n\t\tif (sides[i] == SIDE_FRONT)\n\t\t{\n\t\t\tVectorCopy (p1, f->p[f->numpoints]);\n\t\t\tf->numpoints++;\n\t\t}\n\t\tif (sides[i] == SIDE_BACK)\n\t\t{\n\t\t\tVectorCopy (p1, b->p[b->numpoints]);\n\t\t\tb->numpoints++;\n\t\t}\n\n\t\tif (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])\n\t\t\tcontinue;\n\t\t\t\n\t// generate a split point\n\t\tp2 = in->p[(i+1)%in->numpoints];\n\t\t\n\t\tdot = dists[i] / (dists[i]-dists[i+1]);\n\t\tfor (j=0 ; j<3 ; j++)\n\t\t{\t// avoid round off error when possible\n\t\t\tif (normal[j] == 1)\n\t\t\t\tmid[j] = dist;\n\t\t\telse if (normal[j] == -1)\n\t\t\t\tmid[j] = -dist;\n\t\t\telse\n\t\t\t\tmid[j] = p1[j] + dot*(p2[j]-p1[j]);\n\t\t}\n\t\t\t\n\t\tVectorCopy (mid, f->p[f->numpoints]);\n\t\tf->numpoints++;\n\t\tVectorCopy (mid, b->p[b->numpoints]);\n\t\tb->numpoints++;\n\t}\n\t\n\tif (f->numpoints > maxpts || b->numpoints > maxpts)\n\t\tCom_Error (ERR_DROP, \"ClipWinding: points exceeded estimate\");\n\tif (f->numpoints > MAX_POINTS_ON_WINDING || b->numpoints > MAX_POINTS_ON_WINDING)\n\t\tCom_Error (ERR_DROP, \"ClipWinding: MAX_POINTS_ON_WINDING\");\n}\n\n\n/*\n=============\nChopWindingInPlace\n=============\n*/\nvoid ChopWindingInPlace (winding_t **inout, vec3_t normal, vec_t dist, vec_t epsilon)\n{\n\twinding_t\t*in;\n\tvec_t\tdists[MAX_POINTS_ON_WINDING+4];\n\tint\t\tsides[MAX_POINTS_ON_WINDING+4];\n\tint\t\tcounts[3];\n\tstatic\tvec_t\tdot;\t\t// VC 4.2 optimizer bug if not static\n\tint\t\ti, j;\n\tvec_t\t*p1, *p2;\n\tvec3_t\tmid;\n\twinding_t\t*f;\n\tint\t\tmaxpts;\n\n\tin = *inout;\n\tcounts[0] = counts[1] = counts[2] = 0;\n\n// determine sides for each point\n\tfor (i=0 ; i<in->numpoints ; i++)\n\t{\n\t\tdot = DotProduct (in->p[i], normal);\n\t\tdot -= dist;\n\t\tdists[i] = dot;\n\t\tif (dot > epsilon)\n\t\t\tsides[i] = SIDE_FRONT;\n\t\telse if (dot < -epsilon)\n\t\t\tsides[i] = SIDE_BACK;\n\t\telse\n\t\t{\n\t\t\tsides[i] = SIDE_ON;\n\t\t}\n\t\tcounts[sides[i]]++;\n\t}\n\tsides[i] = sides[0];\n\tdists[i] = dists[0];\n\t\n\tif (!counts[0])\n\t{\n\t\tFreeWinding (in);\n\t\t*inout = NULL;\n\t\treturn;\n\t}\n\tif (!counts[1])\n\t\treturn;\t\t// inout stays the same\n\n\tmaxpts = in->numpoints+4;\t// cant use counts[0]+2 because\n\t\t\t\t\t\t\t\t// of fp grouping errors\n\n\tf = AllocWinding (maxpts);\n\t\t\n\tfor (i=0 ; i<in->numpoints ; i++)\n\t{\n\t\tp1 = in->p[i];\n\t\t\n\t\tif (sides[i] == SIDE_ON)\n\t\t{\n\t\t\tVectorCopy (p1, f->p[f->numpoints]);\n\t\t\tf->numpoints++;\n\t\t\tcontinue;\n\t\t}\n\t\n\t\tif (sides[i] == SIDE_FRONT)\n\t\t{\n\t\t\tVectorCopy (p1, f->p[f->numpoints]);\n\t\t\tf->numpoints++;\n\t\t}\n\n\t\tif (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])\n\t\t\tcontinue;\n\t\t\t\n\t// generate a split point\n\t\tp2 = in->p[(i+1)%in->numpoints];\n\t\t\n\t\tdot = dists[i] / (dists[i]-dists[i+1]);\n\t\tfor (j=0 ; j<3 ; j++)\n\t\t{\t// avoid round off error when possible\n\t\t\tif (normal[j] == 1)\n\t\t\t\tmid[j] = dist;\n\t\t\telse if (normal[j] == -1)\n\t\t\t\tmid[j] = -dist;\n\t\t\telse\n\t\t\t\tmid[j] = p1[j] + dot*(p2[j]-p1[j]);\n\t\t}\n\t\t\t\n\t\tVectorCopy (mid, f->p[f->numpoints]);\n\t\tf->numpoints++;\n\t}\n\t\n\tif (f->numpoints > maxpts)\n\t\tCom_Error (ERR_DROP, \"ClipWinding: points exceeded estimate\");\n\tif (f->numpoints > MAX_POINTS_ON_WINDING)\n\t\tCom_Error (ERR_DROP, \"ClipWinding: MAX_POINTS_ON_WINDING\");\n\n\tFreeWinding (in);\n\t*inout = f;\n}\n\n\n/*\n=================\nChopWinding\n\nReturns the fragment of in that is on the front side\nof the cliping plane.  The original is freed.\n=================\n*/\nwinding_t\t*ChopWinding (winding_t *in, vec3_t normal, vec_t dist)\n{\n\twinding_t\t*f, *b;\n\n\tClipWindingEpsilon (in, normal, dist, ON_EPSILON, &f, &b);\n\tFreeWinding (in);\n\tif (b)\n\t\tFreeWinding (b);\n\treturn f;\n}\n\n\n/*\n=================\nCheckWinding\n\n=================\n*/\nvoid CheckWinding (winding_t *w)\n{\n\tint\t\ti, j;\n\tvec_t\t*p1, *p2;\n\tvec_t\td, edgedist;\n\tvec3_t\tdir, edgenormal, facenormal;\n\tvec_t\tarea;\n\tvec_t\tfacedist;\n\n\tif (w->numpoints < 3)\n\t\tCom_Error (ERR_DROP, \"CheckWinding: %i points\",w->numpoints);\n\t\n\tarea = WindingArea(w);\n\tif (area < 1)\n\t\tCom_Error (ERR_DROP, \"CheckWinding: %f area\", area);\n\n\tWindingPlane (w, facenormal, &facedist);\n\t\n\tfor (i=0 ; i<w->numpoints ; i++)\n\t{\n\t\tp1 = w->p[i];\n\n\t\tfor (j=0 ; j<3 ; j++)\n\t\t\tif (p1[j] > MAX_MAP_BOUNDS || p1[j] < -MAX_MAP_BOUNDS)\n\t\t\t\tCom_Error (ERR_DROP, \"CheckFace: BUGUS_RANGE: %f\",p1[j]);\n\n\t\tj = i+1 == w->numpoints ? 0 : i+1;\n\t\t\n\t// check the point is on the face plane\n\t\td = DotProduct (p1, facenormal) - facedist;\n\t\tif (d < -ON_EPSILON || d > ON_EPSILON)\n\t\t\tCom_Error (ERR_DROP, \"CheckWinding: point off plane\");\n\t\n\t// check the edge isnt degenerate\n\t\tp2 = w->p[j];\n\t\tVectorSubtract (p2, p1, dir);\n\t\t\n\t\tif (VectorLength (dir) < ON_EPSILON)\n\t\t\tCom_Error (ERR_DROP, \"CheckWinding: degenerate edge\");\n\t\t\t\n\t\tCrossProduct (facenormal, dir, edgenormal);\n\t\tVectorNormalize2 (edgenormal, edgenormal);\n\t\tedgedist = DotProduct (p1, edgenormal);\n\t\tedgedist += ON_EPSILON;\n\t\t\n\t// all other points must be on front side\n\t\tfor (j=0 ; j<w->numpoints ; j++)\n\t\t{\n\t\t\tif (j == i)\n\t\t\t\tcontinue;\n\t\t\td = DotProduct (w->p[j], edgenormal);\n\t\t\tif (d > edgedist)\n\t\t\t\tCom_Error (ERR_DROP, \"CheckWinding: non-convex\");\n\t\t}\n\t}\n}\n\n\n/*\n============\nWindingOnPlaneSide\n============\n*/\nint\t\tWindingOnPlaneSide (winding_t *w, vec3_t normal, vec_t dist)\n{\n\tqboolean\tfront, back;\n\tint\t\t\ti;\n\tvec_t\t\td;\n\n\tfront = qfalse;\n\tback = qfalse;\n\tfor (i=0 ; i<w->numpoints ; i++)\n\t{\n\t\td = DotProduct (w->p[i], normal) - dist;\n\t\tif (d < -ON_EPSILON)\n\t\t{\n\t\t\tif (front)\n\t\t\t\treturn SIDE_CROSS;\n\t\t\tback = qtrue;\n\t\t\tcontinue;\n\t\t}\n\t\tif (d > ON_EPSILON)\n\t\t{\n\t\t\tif (back)\n\t\t\t\treturn SIDE_CROSS;\n\t\t\tfront = qtrue;\n\t\t\tcontinue;\n\t\t}\n\t}\n\n\tif (back)\n\t\treturn SIDE_BACK;\n\tif (front)\n\t\treturn SIDE_FRONT;\n\treturn SIDE_ON;\n}\n\n\n/*\n=================\nAddWindingToConvexHull\n\nBoth w and *hull are on the same plane\n=================\n*/\n#define\tMAX_HULL_POINTS\t\t128\nvoid\tAddWindingToConvexHull( winding_t *w, winding_t **hull, vec3_t normal ) {\n\tint\t\t\ti, j, k;\n\tfloat\t\t*p, *copy;\n\tvec3_t\t\tdir;\n\tfloat\t\td;\n\tint\t\t\tnumHullPoints, numNew;\n\tvec3_t\t\thullPoints[MAX_HULL_POINTS];\n\tvec3_t\t\tnewHullPoints[MAX_HULL_POINTS];\n\tvec3_t\t\thullDirs[MAX_HULL_POINTS];\n\tqboolean\thullSide[MAX_HULL_POINTS];\n\tqboolean\toutside;\n\n\tif ( !*hull ) {\n\t\t*hull = CopyWinding( w );\n\t\treturn;\n\t}\n\n\tnumHullPoints = (*hull)->numpoints;\n\tCom_Memcpy( hullPoints, (*hull)->p, numHullPoints * sizeof(vec3_t) );\n\n\tfor ( i = 0 ; i < w->numpoints ; i++ ) {\n\t\tp = w->p[i];\n\n\t\t// calculate hull side vectors\n\t\tfor ( j = 0 ; j < numHullPoints ; j++ ) {\n\t\t\tk = ( j + 1 ) % numHullPoints;\n\n\t\t\tVectorSubtract( hullPoints[k], hullPoints[j], dir );\n\t\t\tVectorNormalize2( dir, dir );\n\t\t\tCrossProduct( normal, dir, hullDirs[j] );\n\t\t}\n\n\t\toutside = qfalse;\n\t\tfor ( j = 0 ; j < numHullPoints ; j++ ) {\n\t\t\tVectorSubtract( p, hullPoints[j], dir );\n\t\t\td = DotProduct( dir, hullDirs[j] );\n\t\t\tif ( d >= ON_EPSILON ) {\n\t\t\t\toutside = qtrue;\n\t\t\t}\n\t\t\tif ( d >= -ON_EPSILON ) {\n\t\t\t\thullSide[j] = qtrue;\n\t\t\t} else {\n\t\t\t\thullSide[j] = qfalse;\n\t\t\t}\n\t\t}\n\n\t\t// if the point is effectively inside, do nothing\n\t\tif ( !outside ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// find the back side to front side transition\n\t\tfor ( j = 0 ; j < numHullPoints ; j++ ) {\n\t\t\tif ( !hullSide[ j % numHullPoints ] && hullSide[ (j + 1) % numHullPoints ] ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif ( j == numHullPoints ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// insert the point here\n\t\tVectorCopy( p, newHullPoints[0] );\n\t\tnumNew = 1;\n\n\t\t// copy over all points that aren't double fronts\n\t\tj = (j+1)%numHullPoints;\n\t\tfor ( k = 0 ; k < numHullPoints ; k++ ) {\n\t\t\tif ( hullSide[ (j+k) % numHullPoints ] && hullSide[ (j+k+1) % numHullPoints ] ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tcopy = hullPoints[ (j+k+1) % numHullPoints ];\n\t\t\tVectorCopy( copy, newHullPoints[numNew] );\n\t\t\tnumNew++;\n\t\t}\n\n\t\tnumHullPoints = numNew;\n\t\tCom_Memcpy( hullPoints, newHullPoints, numHullPoints * sizeof(vec3_t) );\n\t}\n\n\tFreeWinding( *hull );\n\tw = AllocWinding( numHullPoints );\n\tw->numpoints = numHullPoints;\n\t*hull = w;\n\tCom_Memcpy( w->p, hullPoints, numHullPoints * sizeof(vec3_t) );\n}\n\n\n"
  },
  {
    "path": "src/engine/qcommon/cm_polylib.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n// this is only used for visualization tools in cm_ debug functions\n\ntypedef struct\n{\n\tint\t\tnumpoints;\n\tvec3_t\tp[4];\t\t// variable sized\n} winding_t;\n\n#define\tMAX_POINTS_ON_WINDING\t64\n\n#define\tSIDE_FRONT\t0\n#define\tSIDE_BACK\t1\n#define\tSIDE_ON\t\t2\n#define\tSIDE_CROSS\t3\n\n#define\tCLIP_EPSILON\t0.1f\n\n#define MAX_MAP_BOUNDS\t\t\t65535\n\n// you can define on_epsilon in the makefile as tighter\n#ifndef\tON_EPSILON\n#define\tON_EPSILON\t0.1f\n#endif\n\nwinding_t\t*AllocWinding (int points);\nvec_t\tWindingArea (winding_t *w);\nvoid\tWindingCenter (winding_t *w, vec3_t center);\nvoid\tClipWindingEpsilon (winding_t *in, vec3_t normal, vec_t dist, \n\t\t\t\tvec_t epsilon, winding_t **front, winding_t **back);\nwinding_t\t*ChopWinding (winding_t *in, vec3_t normal, vec_t dist);\nwinding_t\t*CopyWinding (winding_t *w);\nwinding_t\t*ReverseWinding (winding_t *w);\nwinding_t\t*BaseWindingForPlane (vec3_t normal, vec_t dist);\nvoid\tCheckWinding (winding_t *w);\nvoid\tWindingPlane (winding_t *w, vec3_t normal, vec_t *dist);\nvoid\tRemoveColinearPoints (winding_t *w);\nint\t\tWindingOnPlaneSide (winding_t *w, vec3_t normal, vec_t dist);\nvoid\tFreeWinding (winding_t *w);\nvoid\tWindingBounds (winding_t *w, vec3_t mins, vec3_t maxs);\n\nvoid\tAddWindingToConvexHull( winding_t *w, winding_t **hull, vec3_t normal );\n\nvoid\tChopWindingInPlace (winding_t **w, vec3_t normal, vec_t dist, vec_t epsilon);\n// frees the original if clipped\n\nvoid pw(winding_t *w);\n"
  },
  {
    "path": "src/engine/qcommon/cm_public.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n#include \"qfiles.h\"\n\n\nvoid\t\tCM_LoadMap( const char *name, qboolean clientload, int *checksum);\nvoid\t\tCM_ClearMap( void );\nclipHandle_t CM_InlineModel( int index );\t\t// 0 = world, 1 + are bmodels\nclipHandle_t CM_TempBoxModel( const vec3_t mins, const vec3_t maxs, int capsule );\n\nvoid\t\tCM_ModelBounds( clipHandle_t model, vec3_t mins, vec3_t maxs );\n\nint\t\t\tCM_NumClusters (void);\nint\t\t\tCM_NumInlineModels( void );\nchar\t\t*CM_EntityString (void);\n\n// returns an ORed contents mask\nint\t\t\tCM_PointContents( const vec3_t p, clipHandle_t model );\nint\t\t\tCM_TransformedPointContents( const vec3_t p, clipHandle_t model, const vec3_t origin, const vec3_t angles );\n\nvoid\t\tCM_BoxTrace ( trace_t *results, const vec3_t start, const vec3_t end,\n\t\t\t\t\t\t  vec3_t mins, vec3_t maxs,\n\t\t\t\t\t\t  clipHandle_t model, int brushmask, int capsule );\nvoid\t\tCM_TransformedBoxTrace( trace_t *results, const vec3_t start, const vec3_t end,\n\t\t\t\t\t\t  vec3_t mins, vec3_t maxs,\n\t\t\t\t\t\t  clipHandle_t model, int brushmask,\n\t\t\t\t\t\t  const vec3_t origin, const vec3_t angles, int capsule );\n\nbyte\t\t*CM_ClusterPVS (int cluster);\n\nint\t\t\tCM_PointLeafnum( const vec3_t p );\n\n// only returns non-solid leafs\n// overflow if return listsize and if *lastLeaf != list[listsize-1]\nint\t\t\tCM_BoxLeafnums( const vec3_t mins, const vec3_t maxs, int *list,\n\t\t \t\t\t\t\tint listsize, int *lastLeaf );\n\nint\t\t\tCM_LeafCluster (int leafnum);\nint\t\t\tCM_LeafArea (int leafnum);\n\nvoid\t\tCM_AdjustAreaPortalState( int area1, int area2, qboolean open );\nqboolean\tCM_AreasConnected( int area1, int area2 );\n\nint\t\t\tCM_WriteAreaBits( byte *buffer, int area );\n\n// cm_tag.c\nint\t\t\tCM_LerpTag( orientation_t *tag,  clipHandle_t model, int startFrame, int endFrame, \n\t\t\t\t\t float frac, const char *tagName );\n\n\n// cm_marks.c\nint\tCM_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projection,\n\t\t\t\t   int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer );\n\n// cm_patch.c\nvoid CM_DrawDebugSurface( void (*drawPoly)(int color, int numPoints, float *points) );\n"
  },
  {
    "path": "src/engine/qcommon/cm_test.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n#include \"cm_local.h\"\n\n\n/*\n==================\nCM_PointLeafnum_r\n\n==================\n*/\nint CM_PointLeafnum_r( const vec3_t p, int num ) {\n\tfloat\t\td;\n\tcNode_t\t\t*node;\n\tcplane_t\t*plane;\n\n\twhile (num >= 0)\n\t{\n\t\tnode = cm.nodes + num;\n\t\tplane = node->plane;\n\t\t\n\t\tif (plane->type < 3)\n\t\t\td = p[plane->type] - plane->dist;\n\t\telse\n\t\t\td = DotProduct (plane->normal, p) - plane->dist;\n\t\tif (d < 0)\n\t\t\tnum = node->children[1];\n\t\telse\n\t\t\tnum = node->children[0];\n\t}\n\n\tc_pointcontents++;\t\t// optimize counter\n\n\treturn -1 - num;\n}\n\nint CM_PointLeafnum( const vec3_t p ) {\n\tif ( !cm.numNodes ) {\t// map not loaded\n\t\treturn 0;\n\t}\n\treturn CM_PointLeafnum_r (p, 0);\n}\n\n\n/*\n======================================================================\n\nLEAF LISTING\n\n======================================================================\n*/\n\n\nvoid CM_StoreLeafs( leafList_t *ll, int nodenum ) {\n\tint\t\tleafNum;\n\n\tleafNum = -1 - nodenum;\n\n\t// store the lastLeaf even if the list is overflowed\n\tif ( cm.leafs[ leafNum ].cluster != -1 ) {\n\t\tll->lastLeaf = leafNum;\n\t}\n\n\tif ( ll->count >= ll->maxcount) {\n\t\tll->overflowed = qtrue;\n\t\treturn;\n\t}\n\tll->list[ ll->count++ ] = leafNum;\n}\n\nvoid CM_StoreBrushes( leafList_t *ll, int nodenum ) {\n\tint\t\t\ti, k;\n\tint\t\t\tleafnum;\n\tint\t\t\tbrushnum;\n\tcLeaf_t\t\t*leaf;\n\tcbrush_t\t*b;\n\n\tleafnum = -1 - nodenum;\n\n\tleaf = &cm.leafs[leafnum];\n\n\tfor ( k = 0 ; k < leaf->numLeafBrushes ; k++ ) {\n\t\tbrushnum = cm.leafbrushes[leaf->firstLeafBrush+k];\n\t\tb = &cm.brushes[brushnum];\n\t\tif ( b->checkcount == cm.checkcount ) {\n\t\t\tcontinue;\t// already checked this brush in another leaf\n\t\t}\n\t\tb->checkcount = cm.checkcount;\n\t\tfor ( i = 0 ; i < 3 ; i++ ) {\n\t\t\tif ( b->bounds[0][i] >= ll->bounds[1][i] || b->bounds[1][i] <= ll->bounds[0][i] ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif ( i != 3 ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( ll->count >= ll->maxcount) {\n\t\t\tll->overflowed = qtrue;\n\t\t\treturn;\n\t\t}\n\t\t((cbrush_t **)ll->list)[ ll->count++ ] = b;\n\t}\n#if 0\n\t// store patches?\n\tfor ( k = 0 ; k < leaf->numLeafSurfaces ; k++ ) {\n\t\tpatch = cm.surfaces[ cm.leafsurfaces[ leaf->firstleafsurface + k ] ];\n\t\tif ( !patch ) {\n\t\t\tcontinue;\n\t\t}\n\t}\n#endif\n}\n\n/*\n=============\nCM_BoxLeafnums\n\nFills in a list of all the leafs touched\n=============\n*/\nvoid CM_BoxLeafnums_r( leafList_t *ll, int nodenum ) {\n\tcplane_t\t*plane;\n\tcNode_t\t\t*node;\n\tint\t\t\ts;\n\n\twhile (1) {\n\t\tif (nodenum < 0) {\n\t\t\tll->storeLeafs( ll, nodenum );\n\t\t\treturn;\n\t\t}\n\t\n\t\tnode = &cm.nodes[nodenum];\n\t\tplane = node->plane;\n\t\ts = BoxOnPlaneSide( ll->bounds[0], ll->bounds[1], plane );\n\t\tif (s == 1) {\n\t\t\tnodenum = node->children[0];\n\t\t} else if (s == 2) {\n\t\t\tnodenum = node->children[1];\n\t\t} else {\n\t\t\t// go down both\n\t\t\tCM_BoxLeafnums_r( ll, node->children[0] );\n\t\t\tnodenum = node->children[1];\n\t\t}\n\n\t}\n}\n\n/*\n==================\nCM_BoxLeafnums\n==================\n*/\nint\tCM_BoxLeafnums( const vec3_t mins, const vec3_t maxs, int *list, int listsize, int *lastLeaf) {\n\tleafList_t\tll;\n\n\tcm.checkcount++;\n\n\tVectorCopy( mins, ll.bounds[0] );\n\tVectorCopy( maxs, ll.bounds[1] );\n\tll.count = 0;\n\tll.maxcount = listsize;\n\tll.list = list;\n\tll.storeLeafs = CM_StoreLeafs;\n\tll.lastLeaf = 0;\n\tll.overflowed = qfalse;\n\n\tCM_BoxLeafnums_r( &ll, 0 );\n\n\t*lastLeaf = ll.lastLeaf;\n\treturn ll.count;\n}\n\n/*\n==================\nCM_BoxBrushes\n==================\n*/\nint CM_BoxBrushes( const vec3_t mins, const vec3_t maxs, cbrush_t **list, int listsize ) {\n\tleafList_t\tll;\n\n\tcm.checkcount++;\n\n\tVectorCopy( mins, ll.bounds[0] );\n\tVectorCopy( maxs, ll.bounds[1] );\n\tll.count = 0;\n\tll.maxcount = listsize;\n\tll.list = (int*) (void *)list;\n\tll.storeLeafs = CM_StoreBrushes;\n\tll.lastLeaf = 0;\n\tll.overflowed = qfalse;\n\t\n\tCM_BoxLeafnums_r( &ll, 0 );\n\n\treturn ll.count;\n}\n\n\n//====================================================================\n\n\n/*\n==================\nCM_PointContents\n\n==================\n*/\nint CM_PointContents( const vec3_t p, clipHandle_t model ) {\n\tint\t\t\tleafnum;\n\tint\t\t\ti, k;\n\tint\t\t\tbrushnum;\n\tcLeaf_t\t\t*leaf;\n\tcbrush_t\t*b;\n\tint\t\t\tcontents;\n\tfloat\t\td;\n\tcmodel_t\t*clipm;\n\n\tif (!cm.numNodes) {\t// map not loaded\n\t\treturn 0;\n\t}\n\n\tif ( model ) {\n\t\tclipm = CM_ClipHandleToModel( model );\n\t\tleaf = &clipm->leaf;\n\t} else {\n\t\tleafnum = CM_PointLeafnum_r (p, 0);\n\t\tleaf = &cm.leafs[leafnum];\n\t}\n\n\tcontents = 0;\n\tfor (k=0 ; k<leaf->numLeafBrushes ; k++) {\n\t\tbrushnum = cm.leafbrushes[leaf->firstLeafBrush+k];\n\t\tb = &cm.brushes[brushnum];\n\n\t\t// see if the point is in the brush\n\t\tfor ( i = 0 ; i < b->numsides ; i++ ) {\n\t\t\td = DotProduct( p, b->sides[i].plane->normal );\n// FIXME test for Cash\n//\t\t\tif ( d >= b->sides[i].plane->dist ) {\n\t\t\tif ( d > b->sides[i].plane->dist ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif ( i == b->numsides ) {\n\t\t\tcontents |= b->contents;\n\t\t}\n\t}\n\n\treturn contents;\n}\n\n/*\n==================\nCM_TransformedPointContents\n\nHandles offseting and rotation of the end points for moving and\nrotating entities\n==================\n*/\nint\tCM_TransformedPointContents( const vec3_t p, clipHandle_t model, const vec3_t origin, const vec3_t angles) {\n\tvec3_t\t\tp_l;\n\tvec3_t\t\ttemp;\n\tvec3_t\t\tforward, right, up;\n\n\t// subtract origin offset\n\tVectorSubtract (p, origin, p_l);\n\n\t// rotate start and end into the models frame of reference\n\tif ( model != BOX_MODEL_HANDLE && \n\t(angles[0] || angles[1] || angles[2]) )\n\t{\n\t\tAngleVectors (angles, forward, right, up);\n\n\t\tVectorCopy (p_l, temp);\n\t\tp_l[0] = DotProduct (temp, forward);\n\t\tp_l[1] = -DotProduct (temp, right);\n\t\tp_l[2] = DotProduct (temp, up);\n\t}\n\n\treturn CM_PointContents( p_l, model );\n}\n\n\n\n/*\n===============================================================================\n\nPVS\n\n===============================================================================\n*/\n\nbyte\t*CM_ClusterPVS (int cluster) {\n\tif (cluster < 0 || cluster >= cm.numClusters || !cm.vised ) {\n\t\treturn cm.visibility;\n\t}\n\n\treturn cm.visibility + cluster * cm.clusterBytes;\n}\n\n\n\n/*\n===============================================================================\n\nAREAPORTALS\n\n===============================================================================\n*/\n\nvoid CM_FloodArea_r( int areaNum, int floodnum) {\n\tint\t\ti;\n\tcArea_t *area;\n\tint\t\t*con;\n\n\tarea = &cm.areas[ areaNum ];\n\n\tif ( area->floodvalid == cm.floodvalid ) {\n\t\tif (area->floodnum == floodnum)\n\t\t\treturn;\n\t\tCom_Error (ERR_DROP, \"FloodArea_r: reflooded\");\n\t}\n\n\tarea->floodnum = floodnum;\n\tarea->floodvalid = cm.floodvalid;\n\tcon = cm.areaPortals + areaNum * cm.numAreas;\n\tfor ( i=0 ; i < cm.numAreas  ; i++ ) {\n\t\tif ( con[i] > 0 ) {\n\t\t\tCM_FloodArea_r( i, floodnum );\n\t\t}\n\t}\n}\n\n/*\n====================\nCM_FloodAreaConnections\n\n====================\n*/\nvoid\tCM_FloodAreaConnections( void ) {\n\tint\t\ti;\n\tcArea_t\t*area;\n\tint\t\tfloodnum;\n\n\t// all current floods are now invalid\n\tcm.floodvalid++;\n\tfloodnum = 0;\n\n\tfor (i = 0 ; i < cm.numAreas ; i++) {\n\t\tarea = &cm.areas[i];\n\t\tif (area->floodvalid == cm.floodvalid) {\n\t\t\tcontinue;\t\t// already flooded into\n\t\t}\n\t\tfloodnum++;\n\t\tCM_FloodArea_r (i, floodnum);\n\t}\n\n}\n\n/*\n====================\nCM_AdjustAreaPortalState\n\n====================\n*/\nvoid\tCM_AdjustAreaPortalState( int area1, int area2, qboolean open ) {\n\tif ( area1 < 0 || area2 < 0 ) {\n\t\treturn;\n\t}\n\n\tif ( area1 >= cm.numAreas || area2 >= cm.numAreas ) {\n\t\tCom_Error (ERR_DROP, \"CM_ChangeAreaPortalState: bad area number\");\n\t}\n\n\tif ( open ) {\n\t\tcm.areaPortals[ area1 * cm.numAreas + area2 ]++;\n\t\tcm.areaPortals[ area2 * cm.numAreas + area1 ]++;\n\t} else {\n\t\tcm.areaPortals[ area1 * cm.numAreas + area2 ]--;\n\t\tcm.areaPortals[ area2 * cm.numAreas + area1 ]--;\n\t\tif ( cm.areaPortals[ area2 * cm.numAreas + area1 ] < 0 ) {\n\t\t\tCom_Error (ERR_DROP, \"CM_AdjustAreaPortalState: negative reference count\");\n\t\t}\n\t}\n\n\tCM_FloodAreaConnections ();\n}\n\n/*\n====================\nCM_AreasConnected\n\n====================\n*/\nqboolean\tCM_AreasConnected( int area1, int area2 ) {\n#ifndef BSPC\n\tif ( cm_noAreas->integer ) {\n\t\treturn qtrue;\n\t}\n#endif\n\n\tif ( area1 < 0 || area2 < 0 ) {\n\t\treturn qfalse;\n\t}\n\n\tif (area1 >= cm.numAreas || area2 >= cm.numAreas) {\n\t\tCom_Error (ERR_DROP, \"area >= cm.numAreas\");\n\t}\n\n\tif (cm.areas[area1].floodnum == cm.areas[area2].floodnum) {\n\t\treturn qtrue;\n\t}\n\treturn qfalse;\n}\n\n\n/*\n=================\nCM_WriteAreaBits\n\nWrites a bit vector of all the areas\nthat are in the same flood as the area parameter\nReturns the number of bytes needed to hold all the bits.\n\nThe bits are OR'd in, so you can CM_WriteAreaBits from multiple\nviewpoints and get the union of all visible areas.\n\nThis is used to cull non-visible entities from snapshots\n=================\n*/\nint CM_WriteAreaBits (byte *buffer, int area)\n{\n\tint\t\ti;\n\tint\t\tfloodnum;\n\tint\t\tbytes;\n\n\tbytes = (cm.numAreas+7)>>3;\n\n#ifndef BSPC\n\tif (cm_noAreas->integer || area == -1)\n#else\n\tif ( area == -1)\n#endif\n\t{\t// for debugging, send everything\n\t\tCom_Memset (buffer, 255, bytes);\n\t}\n\telse\n\t{\n\t\tfloodnum = cm.areas[area].floodnum;\n\t\tfor (i=0 ; i<cm.numAreas ; i++)\n\t\t{\n\t\t\tif (cm.areas[i].floodnum == floodnum || area == -1)\n\t\t\t\tbuffer[i>>3] |= 1<<(i&7);\n\t\t}\n\t}\n\n\treturn bytes;\n}\n\n"
  },
  {
    "path": "src/engine/qcommon/cm_trace.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n#include \"cm_local.h\"\n\n// always use bbox vs. bbox collision and never capsule vs. bbox or vice versa\n//#define ALWAYS_BBOX_VS_BBOX\n// always use capsule vs. capsule collision and never capsule vs. bbox or vice versa\n//#define ALWAYS_CAPSULE_VS_CAPSULE\n\n//#define CAPSULE_DEBUG\n\n/*\n===============================================================================\n\nBASIC MATH\n\n===============================================================================\n*/\n\n/*\n================\nRotatePoint\n================\n*/\nvoid RotatePoint(vec3_t point, /*const*/ vec3_t matrix[3]) { // bk: FIXME \n\tvec3_t tvec;\n\n\tVectorCopy(point, tvec);\n\tpoint[0] = DotProduct(matrix[0], tvec);\n\tpoint[1] = DotProduct(matrix[1], tvec);\n\tpoint[2] = DotProduct(matrix[2], tvec);\n}\n\n/*\n================\nTransposeMatrix\n================\n*/\nvoid TransposeMatrix(/*const*/ vec3_t matrix[3], vec3_t transpose[3]) { // bk: FIXME\n\tint i, j;\n\tfor (i = 0; i < 3; i++) {\n\t\tfor (j = 0; j < 3; j++) {\n\t\t\ttranspose[i][j] = matrix[j][i];\n\t\t}\n\t}\n}\n\n/*\n================\nCreateRotationMatrix\n================\n*/\nvoid CreateRotationMatrix(const vec3_t angles, vec3_t matrix[3]) {\n\tAngleVectors(angles, matrix[0], matrix[1], matrix[2]);\n\tVectorInverse(matrix[1]);\n}\n\n/*\n================\nCM_ProjectPointOntoVector\n================\n*/\nvoid CM_ProjectPointOntoVector( vec3_t point, vec3_t vStart, vec3_t vDir, vec3_t vProj )\n{\n\tvec3_t pVec;\n\n\tVectorSubtract( point, vStart, pVec );\n\t// project onto the directional vector for this segment\n\tVectorMA( vStart, DotProduct( pVec, vDir ), vDir, vProj );\n}\n\n/*\n================\nCM_DistanceFromLineSquared\n================\n*/\nfloat CM_DistanceFromLineSquared(vec3_t p, vec3_t lp1, vec3_t lp2, vec3_t dir) {\n\tvec3_t proj, t;\n\tint j;\n\n\tCM_ProjectPointOntoVector(p, lp1, dir, proj);\n\tfor (j = 0; j < 3; j++) \n\t\tif ((proj[j] > lp1[j] && proj[j] > lp2[j]) ||\n\t\t\t(proj[j] < lp1[j] && proj[j] < lp2[j]))\n\t\t\tbreak;\n\tif (j < 3) {\n\t\tif (fabs(proj[j] - lp1[j]) < fabs(proj[j] - lp2[j]))\n\t\t\tVectorSubtract(p, lp1, t);\n\t\telse\n\t\t\tVectorSubtract(p, lp2, t);\n\t\treturn VectorLengthSquared(t);\n\t}\n\tVectorSubtract(p, proj, t);\n\treturn VectorLengthSquared(t);\n}\n\n/*\n================\nCM_VectorDistanceSquared\n================\n*/\nfloat CM_VectorDistanceSquared(vec3_t p1, vec3_t p2) {\n\tvec3_t dir;\n\n\tVectorSubtract(p2, p1, dir);\n\treturn VectorLengthSquared(dir);\n}\n\n/*\n================\nSquareRootFloat\n================\n*/\nfloat SquareRootFloat(float number) {\n\tlong i;\n\tfloat x, y;\n\tconst float f = 1.5F;\n\n\tx = number * 0.5F;\n\ty  = number;\n\ti  = * ( long * ) &y;\n\ti  = 0x5f3759df - ( i >> 1 );\n\ty  = * ( float * ) &i;\n\ty  = y * ( f - ( x * y * y ) );\n\ty  = y * ( f - ( x * y * y ) );\n\treturn number * y;\n}\n\n\n/*\n===============================================================================\n\nPOSITION TESTING\n\n===============================================================================\n*/\n\n/*\n================\nCM_TestBoxInBrush\n================\n*/\nvoid CM_TestBoxInBrush( traceWork_t *tw, cbrush_t *brush ) {\n\tint\t\t\ti;\n\tcplane_t\t*plane;\n\tfloat\t\tdist;\n\tfloat\t\td1;\n\tcbrushside_t\t*side;\n\tfloat\t\tt;\n\tvec3_t\t\tstartp;\n\n\tif (!brush->numsides) {\n\t\treturn;\n\t}\n\n\t// special test for axial\n\tif ( tw->bounds[0][0] > brush->bounds[1][0]\n\t\t|| tw->bounds[0][1] > brush->bounds[1][1]\n\t\t|| tw->bounds[0][2] > brush->bounds[1][2]\n\t\t|| tw->bounds[1][0] < brush->bounds[0][0]\n\t\t|| tw->bounds[1][1] < brush->bounds[0][1]\n\t\t|| tw->bounds[1][2] < brush->bounds[0][2]\n\t\t) {\n\t\treturn;\n\t}\n\n   if ( tw->sphere.use ) {\n\t\t// the first six planes are the axial planes, so we only\n\t\t// need to test the remainder\n\t\tfor ( i = 6 ; i < brush->numsides ; i++ ) {\n\t\t\tside = brush->sides + i;\n\t\t\tplane = side->plane;\n\n\t\t\t// adjust the plane distance apropriately for radius\n\t\t\tdist = plane->dist + tw->sphere.radius;\n\t\t\t// find the closest point on the capsule to the plane\n\t\t\tt = DotProduct( plane->normal, tw->sphere.offset );\n\t\t\tif ( t > 0 )\n\t\t\t{\n\t\t\t\tVectorSubtract( tw->start, tw->sphere.offset, startp );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tVectorAdd( tw->start, tw->sphere.offset, startp );\n\t\t\t}\n\t\t\td1 = DotProduct( startp, plane->normal ) - dist;\n\t\t\t// if completely in front of face, no intersection\n\t\t\tif ( d1 > 0 ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t} else {\n\t\t// the first six planes are the axial planes, so we only\n\t\t// need to test the remainder\n\t\tfor ( i = 6 ; i < brush->numsides ; i++ ) {\n\t\t\tside = brush->sides + i;\n\t\t\tplane = side->plane;\n\n\t\t\t// adjust the plane distance apropriately for mins/maxs\n\t\t\tdist = plane->dist - DotProduct( tw->offsets[ plane->signbits ], plane->normal );\n\n\t\t\td1 = DotProduct( tw->start, plane->normal ) - dist;\n\n\t\t\t// if completely in front of face, no intersection\n\t\t\tif ( d1 > 0 ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\t// inside this brush\n\ttw->trace.startsolid = tw->trace.allsolid = qtrue;\n\ttw->trace.fraction = 0;\n\ttw->trace.contents = brush->contents;\n}\n\n\n\n/*\n================\nCM_TestInLeaf\n================\n*/\nvoid CM_TestInLeaf( traceWork_t *tw, cLeaf_t *leaf ) {\n\tint\t\t\tk;\n\tint\t\t\tbrushnum;\n\tcbrush_t\t*b;\n\tcPatch_t\t*patch;\n\n\t// test box position against all brushes in the leaf\n\tfor (k=0 ; k<leaf->numLeafBrushes ; k++) {\n\t\tbrushnum = cm.leafbrushes[leaf->firstLeafBrush+k];\n\t\tb = &cm.brushes[brushnum];\n\t\tif (b->checkcount == cm.checkcount) {\n\t\t\tcontinue;\t// already checked this brush in another leaf\n\t\t}\n\t\tb->checkcount = cm.checkcount;\n\n\t\tif ( !(b->contents & tw->contents)) {\n\t\t\tcontinue;\n\t\t}\n\t\t\n\t\tCM_TestBoxInBrush( tw, b );\n\t\tif ( tw->trace.allsolid ) {\n\t\t\treturn;\n\t\t}\n\t}\n\n\t// test against all patches\n#ifdef BSPC\n\tif (1) {\n#else\n\tif ( !cm_noCurves->integer ) {\n#endif //BSPC\n\t\tfor ( k = 0 ; k < leaf->numLeafSurfaces ; k++ ) {\n\t\t\tpatch = cm.surfaces[ cm.leafsurfaces[ leaf->firstLeafSurface + k ] ];\n\t\t\tif ( !patch ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif ( patch->checkcount == cm.checkcount ) {\n\t\t\t\tcontinue;\t// already checked this brush in another leaf\n\t\t\t}\n\t\t\tpatch->checkcount = cm.checkcount;\n\n\t\t\tif ( !(patch->contents & tw->contents)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t\n\t\t\tif ( CM_PositionTestInPatchCollide( tw, patch->pc ) ) {\n\t\t\t\ttw->trace.startsolid = tw->trace.allsolid = qtrue;\n\t\t\t\ttw->trace.fraction = 0;\n\t\t\t\ttw->trace.contents = patch->contents;\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n}\n\n/*\n==================\nCM_TestCapsuleInCapsule\n\ncapsule inside capsule check\n==================\n*/\nvoid CM_TestCapsuleInCapsule( traceWork_t *tw, clipHandle_t model ) {\n\tint i;\n\tvec3_t mins, maxs;\n\tvec3_t top, bottom;\n\tvec3_t p1, p2, tmp;\n\tvec3_t offset, symetricSize[2];\n\tfloat radius, halfwidth, halfheight, offs, r;\n\n\tCM_ModelBounds(model, mins, maxs);\n\n\tVectorAdd(tw->start, tw->sphere.offset, top);\n\tVectorSubtract(tw->start, tw->sphere.offset, bottom);\n\tfor ( i = 0 ; i < 3 ; i++ ) {\n\t\toffset[i] = ( mins[i] + maxs[i] ) * 0.5;\n\t\tsymetricSize[0][i] = mins[i] - offset[i];\n\t\tsymetricSize[1][i] = maxs[i] - offset[i];\n\t}\n\thalfwidth = symetricSize[ 1 ][ 0 ];\n\thalfheight = symetricSize[ 1 ][ 2 ];\n\tradius = ( halfwidth > halfheight ) ? halfheight : halfwidth;\n\toffs = halfheight - radius;\n\n\tr = Square(tw->sphere.radius + radius);\n\t// check if any of the spheres overlap\n\tVectorCopy(offset, p1);\n\tp1[2] += offs;\n\tVectorSubtract(p1, top, tmp);\n\tif ( VectorLengthSquared(tmp) < r ) {\n\t\ttw->trace.startsolid = tw->trace.allsolid = qtrue;\n\t\ttw->trace.fraction = 0;\n\t}\n\tVectorSubtract(p1, bottom, tmp);\n\tif ( VectorLengthSquared(tmp) < r ) {\n\t\ttw->trace.startsolid = tw->trace.allsolid = qtrue;\n\t\ttw->trace.fraction = 0;\n\t}\n\tVectorCopy(offset, p2);\n\tp2[2] -= offs;\n\tVectorSubtract(p2, top, tmp);\n\tif ( VectorLengthSquared(tmp) < r ) {\n\t\ttw->trace.startsolid = tw->trace.allsolid = qtrue;\n\t\ttw->trace.fraction = 0;\n\t}\n\tVectorSubtract(p2, bottom, tmp);\n\tif ( VectorLengthSquared(tmp) < r ) {\n\t\ttw->trace.startsolid = tw->trace.allsolid = qtrue;\n\t\ttw->trace.fraction = 0;\n\t}\n\t// if between cylinder up and lower bounds\n\tif ( (top[2] >= p1[2] && top[2] <= p2[2]) ||\n\t\t(bottom[2] >= p1[2] && bottom[2] <= p2[2]) ) {\n\t\t// 2d coordinates\n\t\ttop[2] = p1[2] = 0;\n\t\t// if the cylinders overlap\n\t\tVectorSubtract(top, p1, tmp);\n\t\tif ( VectorLengthSquared(tmp) < r ) {\n\t\t\ttw->trace.startsolid = tw->trace.allsolid = qtrue;\n\t\t\ttw->trace.fraction = 0;\n\t\t}\n\t}\n}\n\n/*\n==================\nCM_TestBoundingBoxInCapsule\n\nbounding box inside capsule check\n==================\n*/\nvoid CM_TestBoundingBoxInCapsule( traceWork_t *tw, clipHandle_t model ) {\n\tvec3_t mins, maxs, offset, size[2];\n\tclipHandle_t h;\n\tcmodel_t *cmod;\n\tint i;\n\n\t// mins maxs of the capsule\n\tCM_ModelBounds(model, mins, maxs);\n\n\t// offset for capsule center\n\tfor ( i = 0 ; i < 3 ; i++ ) {\n\t\toffset[i] = ( mins[i] + maxs[i] ) * 0.5;\n\t\tsize[0][i] = mins[i] - offset[i];\n\t\tsize[1][i] = maxs[i] - offset[i];\n\t\ttw->start[i] -= offset[i];\n\t\ttw->end[i] -= offset[i];\n\t}\n\n\t// replace the bounding box with the capsule\n\ttw->sphere.use = qtrue;\n\ttw->sphere.radius = ( size[1][0] > size[1][2] ) ? size[1][2]: size[1][0];\n\ttw->sphere.halfheight = size[1][2];\n\tVectorSet( tw->sphere.offset, 0, 0, size[1][2] - tw->sphere.radius );\n\n\t// replace the capsule with the bounding box\n\th = CM_TempBoxModel(tw->size[0], tw->size[1], qfalse);\n\t// calculate collision\n\tcmod = CM_ClipHandleToModel( h );\n\tCM_TestInLeaf( tw, &cmod->leaf );\n}\n\n/*\n==================\nCM_PositionTest\n==================\n*/\n#define\tMAX_POSITION_LEAFS\t1024\nvoid CM_PositionTest( traceWork_t *tw ) {\n\tint\t\tleafs[MAX_POSITION_LEAFS];\n\tint\t\ti;\n\tleafList_t\tll;\n\n\t// identify the leafs we are touching\n\tVectorAdd( tw->start, tw->size[0], ll.bounds[0] );\n\tVectorAdd( tw->start, tw->size[1], ll.bounds[1] );\n\n\tfor (i=0 ; i<3 ; i++) {\n\t\tll.bounds[0][i] -= 1;\n\t\tll.bounds[1][i] += 1;\n\t}\n\n\tll.count = 0;\n\tll.maxcount = MAX_POSITION_LEAFS;\n\tll.list = leafs;\n\tll.storeLeafs = CM_StoreLeafs;\n\tll.lastLeaf = 0;\n\tll.overflowed = qfalse;\n\n\tcm.checkcount++;\n\n\tCM_BoxLeafnums_r( &ll, 0 );\n\n\n\tcm.checkcount++;\n\n\t// test the contents of the leafs\n\tfor (i=0 ; i < ll.count ; i++) {\n\t\tCM_TestInLeaf( tw, &cm.leafs[leafs[i]] );\n\t\tif ( tw->trace.allsolid ) {\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\n/*\n===============================================================================\n\nTRACING\n\n===============================================================================\n*/\n\n\n/*\n================\nCM_TraceThroughPatch\n================\n*/\n\nvoid CM_TraceThroughPatch( traceWork_t *tw, cPatch_t *patch ) {\n\tfloat\t\toldFrac;\n\n\tc_patch_traces++;\n\n\toldFrac = tw->trace.fraction;\n\n\tCM_TraceThroughPatchCollide( tw, patch->pc );\n\n\tif ( tw->trace.fraction < oldFrac ) {\n\t\ttw->trace.surfaceFlags = patch->surfaceFlags;\n\t\ttw->trace.contents = patch->contents;\n\t}\n}\n\n/*\n================\nCM_TraceThroughBrush\n================\n*/\nvoid CM_TraceThroughBrush( traceWork_t *tw, cbrush_t *brush ) {\n\tint\t\t\ti;\n\tcplane_t\t*plane, *clipplane;\n\tfloat\t\tdist;\n\tfloat\t\tenterFrac, leaveFrac;\n\tfloat\t\td1, d2;\n\tqboolean\tgetout, startout;\n\tfloat\t\tf;\n\tcbrushside_t\t*side, *leadside;\n\tfloat\t\tt;\n\tvec3_t\t\tstartp;\n\tvec3_t\t\tendp;\n\n\tenterFrac = -1.0;\n\tleaveFrac = 1.0;\n\tclipplane = NULL;\n\n\tif ( !brush->numsides ) {\n\t\treturn;\n\t}\n\n\tc_brush_traces++;\n\n\tgetout = qfalse;\n\tstartout = qfalse;\n\n\tleadside = NULL;\n\n\tif ( tw->sphere.use ) {\n\t\t//\n\t\t// compare the trace against all planes of the brush\n\t\t// find the latest time the trace crosses a plane towards the interior\n\t\t// and the earliest time the trace crosses a plane towards the exterior\n\t\t//\n\t\tfor (i = 0; i < brush->numsides; i++) {\n\t\t\tside = brush->sides + i;\n\t\t\tplane = side->plane;\n\n\t\t\t// adjust the plane distance apropriately for radius\n\t\t\tdist = plane->dist + tw->sphere.radius;\n\n\t\t\t// find the closest point on the capsule to the plane\n\t\t\tt = DotProduct( plane->normal, tw->sphere.offset );\n\t\t\tif ( t > 0 )\n\t\t\t{\n\t\t\t\tVectorSubtract( tw->start, tw->sphere.offset, startp );\n\t\t\t\tVectorSubtract( tw->end, tw->sphere.offset, endp );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tVectorAdd( tw->start, tw->sphere.offset, startp );\n\t\t\t\tVectorAdd( tw->end, tw->sphere.offset, endp );\n\t\t\t}\n\n\t\t\td1 = DotProduct( startp, plane->normal ) - dist;\n\t\t\td2 = DotProduct( endp, plane->normal ) - dist;\n\n\t\t\tif (d2 > 0) {\n\t\t\t\tgetout = qtrue;\t// endpoint is not in solid\n\t\t\t}\n\t\t\tif (d1 > 0) {\n\t\t\t\tstartout = qtrue;\n\t\t\t}\n\n\t\t\t// if completely in front of face, no intersection with the entire brush\n\t\t\tif (d1 > 0 && ( d2 >= SURFACE_CLIP_EPSILON || d2 >= d1 )  ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// if it doesn't cross the plane, the plane isn't relevent\n\t\t\tif (d1 <= 0 && d2 <= 0 ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// crosses face\n\t\t\tif (d1 > d2) {\t// enter\n\t\t\t\tf = (d1-SURFACE_CLIP_EPSILON) / (d1-d2);\n\t\t\t\tif ( f < 0 ) {\n\t\t\t\t\tf = 0;\n\t\t\t\t}\n\t\t\t\tif (f > enterFrac) {\n\t\t\t\t\tenterFrac = f;\n\t\t\t\t\tclipplane = plane;\n\t\t\t\t\tleadside = side;\n\t\t\t\t}\n\t\t\t} else {\t// leave\n\t\t\t\tf = (d1+SURFACE_CLIP_EPSILON) / (d1-d2);\n\t\t\t\tif ( f > 1 ) {\n\t\t\t\t\tf = 1;\n\t\t\t\t}\n\t\t\t\tif (f < leaveFrac) {\n\t\t\t\t\tleaveFrac = f;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} else {\n\t\t//\n\t\t// compare the trace against all planes of the brush\n\t\t// find the latest time the trace crosses a plane towards the interior\n\t\t// and the earliest time the trace crosses a plane towards the exterior\n\t\t//\n\t\tfor (i = 0; i < brush->numsides; i++) {\n\t\t\tside = brush->sides + i;\n\t\t\tplane = side->plane;\n\n\t\t\t// adjust the plane distance apropriately for mins/maxs\n\t\t\tdist = plane->dist - DotProduct( tw->offsets[ plane->signbits ], plane->normal );\n\n\t\t\td1 = DotProduct( tw->start, plane->normal ) - dist;\n\t\t\td2 = DotProduct( tw->end, plane->normal ) - dist;\n\n\t\t\tif (d2 > 0) {\n\t\t\t\tgetout = qtrue;\t// endpoint is not in solid\n\t\t\t}\n\t\t\tif (d1 > 0) {\n\t\t\t\tstartout = qtrue;\n\t\t\t}\n\n\t\t\t// if completely in front of face, no intersection with the entire brush\n\t\t\tif (d1 > 0 && ( d2 >= SURFACE_CLIP_EPSILON || d2 >= d1 )  ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// if it doesn't cross the plane, the plane isn't relevent\n\t\t\tif (d1 <= 0 && d2 <= 0 ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// crosses face\n\t\t\tif (d1 > d2) {\t// enter\n\t\t\t\tf = (d1-SURFACE_CLIP_EPSILON) / (d1-d2);\n\t\t\t\tif ( f < 0 ) {\n\t\t\t\t\tf = 0;\n\t\t\t\t}\n\t\t\t\tif (f > enterFrac) {\n\t\t\t\t\tenterFrac = f;\n\t\t\t\t\tclipplane = plane;\n\t\t\t\t\tleadside = side;\n\t\t\t\t}\n\t\t\t} else {\t// leave\n\t\t\t\tf = (d1+SURFACE_CLIP_EPSILON) / (d1-d2);\n\t\t\t\tif ( f > 1 ) {\n\t\t\t\t\tf = 1;\n\t\t\t\t}\n\t\t\t\tif (f < leaveFrac) {\n\t\t\t\t\tleaveFrac = f;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t//\n\t// all planes have been checked, and the trace was not\n\t// completely outside the brush\n\t//\n\tif (!startout) {\t// original point was inside brush\n\t\ttw->trace.startsolid = qtrue;\n\t\tif (!getout) {\n\t\t\ttw->trace.allsolid = qtrue;\n\t\t\ttw->trace.fraction = 0;\n\t\t\ttw->trace.contents = brush->contents;\n\t\t}\n\t\treturn;\n\t}\n\t\n\tif (enterFrac < leaveFrac) {\n\t\tif (enterFrac > -1 && enterFrac < tw->trace.fraction) {\n\t\t\tif (enterFrac < 0) {\n\t\t\t\tenterFrac = 0;\n\t\t\t}\n\t\t\ttw->trace.fraction = enterFrac;\n\t\t\ttw->trace.plane = *clipplane;\n\t\t\ttw->trace.surfaceFlags = leadside->surfaceFlags;\n\t\t\ttw->trace.contents = brush->contents;\n\t\t}\n\t}\n}\n\n/*\n================\nCM_TraceThroughLeaf\n================\n*/\nvoid CM_TraceThroughLeaf( traceWork_t *tw, cLeaf_t *leaf ) {\n\tint\t\t\tk;\n\tint\t\t\tbrushnum;\n\tcbrush_t\t*b;\n\tcPatch_t\t*patch;\n\n\t// trace line against all brushes in the leaf\n\tfor ( k = 0 ; k < leaf->numLeafBrushes ; k++ ) {\n\t\tbrushnum = cm.leafbrushes[leaf->firstLeafBrush+k];\n\n\t\tb = &cm.brushes[brushnum];\n\t\tif ( b->checkcount == cm.checkcount ) {\n\t\t\tcontinue;\t// already checked this brush in another leaf\n\t\t}\n\t\tb->checkcount = cm.checkcount;\n\n\t\tif ( !(b->contents & tw->contents) ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tCM_TraceThroughBrush( tw, b );\n\t\tif ( !tw->trace.fraction ) {\n\t\t\treturn;\n\t\t}\n\t}\n\n\t// trace line against all patches in the leaf\n#ifdef BSPC\n\tif (1) {\n#else\n\tif ( !cm_noCurves->integer ) {\n#endif\n\t\tfor ( k = 0 ; k < leaf->numLeafSurfaces ; k++ ) {\n\t\t\tpatch = cm.surfaces[ cm.leafsurfaces[ leaf->firstLeafSurface + k ] ];\n\t\t\tif ( !patch ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif ( patch->checkcount == cm.checkcount ) {\n\t\t\t\tcontinue;\t// already checked this patch in another leaf\n\t\t\t}\n\t\t\tpatch->checkcount = cm.checkcount;\n\n\t\t\tif ( !(patch->contents & tw->contents) ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t\n\t\t\tCM_TraceThroughPatch( tw, patch );\n\t\t\tif ( !tw->trace.fraction ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#define RADIUS_EPSILON\t\t1.0f\n\n/*\n================\nCM_TraceThroughSphere\n\nget the first intersection of the ray with the sphere\n================\n*/\nvoid CM_TraceThroughSphere( traceWork_t *tw, vec3_t origin, float radius, vec3_t start, vec3_t end ) {\n\tfloat l1, l2, length, scale, fraction;\n\tfloat a, b, c, d, sqrtd;\n\tvec3_t v1, dir, intersection;\n\n\t// if inside the sphere\n\tVectorSubtract(start, origin, dir);\n\tl1 = VectorLengthSquared(dir);\n\tif (l1 < Square(radius)) {\n\t\ttw->trace.fraction = 0;\n\t\ttw->trace.startsolid = qtrue;\n\t\t// test for allsolid\n\t\tVectorSubtract(end, origin, dir);\n\t\tl1 = VectorLengthSquared(dir);\n\t\tif (l1 < Square(radius)) {\n\t\t\ttw->trace.allsolid = qtrue;\n\t\t}\n\t\treturn;\n\t}\n\t//\n\tVectorSubtract(end, start, dir);\n\tlength = VectorNormalize(dir);\n\t//\n\tl1 = CM_DistanceFromLineSquared(origin, start, end, dir);\n\tVectorSubtract(end, origin, v1);\n\tl2 = VectorLengthSquared(v1);\n\t// if no intersection with the sphere and the end point is at least an epsilon away\n\tif (l1 >= Square(radius) && l2 > Square(radius+SURFACE_CLIP_EPSILON)) {\n\t\treturn;\n\t}\n\t//\n\t//\t| origin - (start + t * dir) | = radius\n\t//\ta = dir[0]^2 + dir[1]^2 + dir[2]^2;\n\t//\tb = 2 * (dir[0] * (start[0] - origin[0]) + dir[1] * (start[1] - origin[1]) + dir[2] * (start[2] - origin[2]));\n\t//\tc = (start[0] - origin[0])^2 + (start[1] - origin[1])^2 + (start[2] - origin[2])^2 - radius^2;\n\t//\n\tVectorSubtract(start, origin, v1);\n\t// dir is normalized so a = 1\n\ta = 1.0f;//dir[0] * dir[0] + dir[1] * dir[1] + dir[2] * dir[2];\n\tb = 2.0f * (dir[0] * v1[0] + dir[1] * v1[1] + dir[2] * v1[2]);\n\tc = v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2] - (radius+RADIUS_EPSILON) * (radius+RADIUS_EPSILON);\n\n\td = b * b - 4.0f * c;// * a;\n\tif (d > 0) {\n\t\tsqrtd = SquareRootFloat(d);\n\t\t// = (- b + sqrtd) * 0.5f; // / (2.0f * a);\n\t\tfraction = (- b - sqrtd) * 0.5f; // / (2.0f * a);\n\t\t//\n\t\tif (fraction < 0) {\n\t\t\tfraction = 0;\n\t\t}\n\t\telse {\n\t\t\tfraction /= length;\n\t\t}\n\t\tif ( fraction < tw->trace.fraction ) {\n\t\t\ttw->trace.fraction = fraction;\n\t\t\tVectorSubtract(end, start, dir);\n\t\t\tVectorMA(start, fraction, dir, intersection);\n\t\t\tVectorSubtract(intersection, origin, dir);\n\t\t\t#ifdef CAPSULE_DEBUG\n\t\t\t\tl2 = VectorLength(dir);\n\t\t\t\tif (l2 < radius) {\n\t\t\t\t\tint bah = 1;\n\t\t\t\t}\n\t\t\t#endif\n\t\t\tscale = 1 / (radius+RADIUS_EPSILON);\n\t\t\tVectorScale(dir, scale, dir);\n\t\t\tVectorCopy(dir, tw->trace.plane.normal);\n\t\t\tVectorAdd( tw->modelOrigin, intersection, intersection);\n\t\t\ttw->trace.plane.dist = DotProduct(tw->trace.plane.normal, intersection);\n\t\t\ttw->trace.contents = CONTENTS_BODY;\n\t\t}\n\t}\n\telse if (d == 0) {\n\t\t//t1 = (- b ) / 2;\n\t\t// slide along the sphere\n\t}\n\t// no intersection at all\n}\n\n/*\n================\nCM_TraceThroughVerticalCylinder\n\nget the first intersection of the ray with the cylinder\nthe cylinder extends halfheight above and below the origin\n================\n*/\nvoid CM_TraceThroughVerticalCylinder( traceWork_t *tw, vec3_t origin, float radius, float halfheight, vec3_t start, vec3_t end) {\n\tfloat length, scale, fraction, l1, l2;\n\tfloat a, b, c, d, sqrtd;\n\tvec3_t v1, dir, start2d, end2d, org2d, intersection;\n\n\t// 2d coordinates\n\tVectorSet(start2d, start[0], start[1], 0);\n\tVectorSet(end2d, end[0], end[1], 0);\n\tVectorSet(org2d, origin[0], origin[1], 0);\n\t// if between lower and upper cylinder bounds\n\tif (start[2] <= origin[2] + halfheight &&\n\t\t\t\tstart[2] >= origin[2] - halfheight) {\n\t\t// if inside the cylinder\n\t\tVectorSubtract(start2d, org2d, dir);\n\t\tl1 = VectorLengthSquared(dir);\n\t\tif (l1 < Square(radius)) {\n\t\t\ttw->trace.fraction = 0;\n\t\t\ttw->trace.startsolid = qtrue;\n\t\t\tVectorSubtract(end2d, org2d, dir);\n\t\t\tl1 = VectorLengthSquared(dir);\n\t\t\tif (l1 < Square(radius)) {\n\t\t\t\ttw->trace.allsolid = qtrue;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t}\n\t//\n\tVectorSubtract(end2d, start2d, dir);\n\tlength = VectorNormalize(dir);\n\t//\n\tl1 = CM_DistanceFromLineSquared(org2d, start2d, end2d, dir);\n\tVectorSubtract(end2d, org2d, v1);\n\tl2 = VectorLengthSquared(v1);\n\t// if no intersection with the cylinder and the end point is at least an epsilon away\n\tif (l1 >= Square(radius) && l2 > Square(radius+SURFACE_CLIP_EPSILON)) {\n\t\treturn;\n\t}\n\t//\n\t//\n\t// (start[0] - origin[0] - t * dir[0]) ^ 2 + (start[1] - origin[1] - t * dir[1]) ^ 2 = radius ^ 2\n\t// (v1[0] + t * dir[0]) ^ 2 + (v1[1] + t * dir[1]) ^ 2 = radius ^ 2;\n\t// v1[0] ^ 2 + 2 * v1[0] * t * dir[0] + (t * dir[0]) ^ 2 +\n\t//\t\t\t\t\t\tv1[1] ^ 2 + 2 * v1[1] * t * dir[1] + (t * dir[1]) ^ 2 = radius ^ 2\n\t// t ^ 2 * (dir[0] ^ 2 + dir[1] ^ 2) + t * (2 * v1[0] * dir[0] + 2 * v1[1] * dir[1]) +\n\t//\t\t\t\t\t\tv1[0] ^ 2 + v1[1] ^ 2 - radius ^ 2 = 0\n\t//\n\tVectorSubtract(start, origin, v1);\n\t// dir is normalized so we can use a = 1\n\ta = 1.0f;// * (dir[0] * dir[0] + dir[1] * dir[1]);\n\tb = 2.0f * (v1[0] * dir[0] + v1[1] * dir[1]);\n\tc = v1[0] * v1[0] + v1[1] * v1[1] - (radius+RADIUS_EPSILON) * (radius+RADIUS_EPSILON);\n\n\td = b * b - 4.0f * c;// * a;\n\tif (d > 0) {\n\t\tsqrtd = SquareRootFloat(d);\n\t\t// = (- b + sqrtd) * 0.5f;// / (2.0f * a);\n\t\tfraction = (- b - sqrtd) * 0.5f;// / (2.0f * a);\n\t\t//\n\t\tif (fraction < 0) {\n\t\t\tfraction = 0;\n\t\t}\n\t\telse {\n\t\t\tfraction /= length;\n\t\t}\n\t\tif ( fraction < tw->trace.fraction ) {\n\t\t\tVectorSubtract(end, start, dir);\n\t\t\tVectorMA(start, fraction, dir, intersection);\n\t\t\t// if the intersection is between the cylinder lower and upper bound\n\t\t\tif (intersection[2] <= origin[2] + halfheight &&\n\t\t\t\t\t\tintersection[2] >= origin[2] - halfheight) {\n\t\t\t\t//\n\t\t\t\ttw->trace.fraction = fraction;\n\t\t\t\tVectorSubtract(intersection, origin, dir);\n\t\t\t\tdir[2] = 0;\n\t\t\t\t#ifdef CAPSULE_DEBUG\n\t\t\t\t\tl2 = VectorLength(dir);\n\t\t\t\t\tif (l2 <= radius) {\n\t\t\t\t\t\tint bah = 1;\n\t\t\t\t\t}\n\t\t\t\t#endif\n\t\t\t\tscale = 1 / (radius+RADIUS_EPSILON);\n\t\t\t\tVectorScale(dir, scale, dir);\n\t\t\t\tVectorCopy(dir, tw->trace.plane.normal);\n\t\t\t\tVectorAdd( tw->modelOrigin, intersection, intersection);\n\t\t\t\ttw->trace.plane.dist = DotProduct(tw->trace.plane.normal, intersection);\n\t\t\t\ttw->trace.contents = CONTENTS_BODY;\n\t\t\t}\n\t\t}\n\t}\n\telse if (d == 0) {\n\t\t//t[0] = (- b ) / 2 * a;\n\t\t// slide along the cylinder\n\t}\n\t// no intersection at all\n}\n\n/*\n================\nCM_TraceCapsuleThroughCapsule\n\ncapsule vs. capsule collision (not rotated)\n================\n*/\nvoid CM_TraceCapsuleThroughCapsule( traceWork_t *tw, clipHandle_t model ) {\n\tint i;\n\tvec3_t mins, maxs;\n\tvec3_t top, bottom, starttop, startbottom, endtop, endbottom;\n\tvec3_t offset, symetricSize[2];\n\tfloat radius, halfwidth, halfheight, offs, h;\n\n\tCM_ModelBounds(model, mins, maxs);\n\t// test trace bounds vs. capsule bounds\n\tif ( tw->bounds[0][0] > maxs[0] + RADIUS_EPSILON\n\t\t|| tw->bounds[0][1] > maxs[1] + RADIUS_EPSILON\n\t\t|| tw->bounds[0][2] > maxs[2] + RADIUS_EPSILON\n\t\t|| tw->bounds[1][0] < mins[0] - RADIUS_EPSILON\n\t\t|| tw->bounds[1][1] < mins[1] - RADIUS_EPSILON\n\t\t|| tw->bounds[1][2] < mins[2] - RADIUS_EPSILON\n\t\t) {\n\t\treturn;\n\t}\n\t// top origin and bottom origin of each sphere at start and end of trace\n\tVectorAdd(tw->start, tw->sphere.offset, starttop);\n\tVectorSubtract(tw->start, tw->sphere.offset, startbottom);\n\tVectorAdd(tw->end, tw->sphere.offset, endtop);\n\tVectorSubtract(tw->end, tw->sphere.offset, endbottom);\n\n\t// calculate top and bottom of the capsule spheres to collide with\n\tfor ( i = 0 ; i < 3 ; i++ ) {\n\t\toffset[i] = ( mins[i] + maxs[i] ) * 0.5;\n\t\tsymetricSize[0][i] = mins[i] - offset[i];\n\t\tsymetricSize[1][i] = maxs[i] - offset[i];\n\t}\n\thalfwidth = symetricSize[ 1 ][ 0 ];\n\thalfheight = symetricSize[ 1 ][ 2 ];\n\tradius = ( halfwidth > halfheight ) ? halfheight : halfwidth;\n\toffs = halfheight - radius;\n\tVectorCopy(offset, top);\n\ttop[2] += offs;\n\tVectorCopy(offset, bottom);\n\tbottom[2] -= offs;\n\t// expand radius of spheres\n\tradius += tw->sphere.radius;\n\t// if there is horizontal movement\n\tif ( tw->start[0] != tw->end[0] || tw->start[1] != tw->end[1] ) {\n\t\t// height of the expanded cylinder is the height of both cylinders minus the radius of both spheres\n\t\th = halfheight + tw->sphere.halfheight - radius;\n\t\t// if the cylinder has a height\n\t\tif ( h > 0 ) {\n\t\t\t// test for collisions between the cylinders\n\t\t\tCM_TraceThroughVerticalCylinder(tw, offset, radius, h, tw->start, tw->end);\n\t\t}\n\t}\n\t// test for collision between the spheres\n\tCM_TraceThroughSphere(tw, top, radius, startbottom, endbottom);\n\tCM_TraceThroughSphere(tw, bottom, radius, starttop, endtop);\n}\n\n/*\n================\nCM_TraceBoundingBoxThroughCapsule\n\nbounding box vs. capsule collision\n================\n*/\nvoid CM_TraceBoundingBoxThroughCapsule( traceWork_t *tw, clipHandle_t model ) {\n\tvec3_t mins, maxs, offset, size[2];\n\tclipHandle_t h;\n\tcmodel_t *cmod;\n\tint i;\n\n\t// mins maxs of the capsule\n\tCM_ModelBounds(model, mins, maxs);\n\n\t// offset for capsule center\n\tfor ( i = 0 ; i < 3 ; i++ ) {\n\t\toffset[i] = ( mins[i] + maxs[i] ) * 0.5;\n\t\tsize[0][i] = mins[i] - offset[i];\n\t\tsize[1][i] = maxs[i] - offset[i];\n\t\ttw->start[i] -= offset[i];\n\t\ttw->end[i] -= offset[i];\n\t}\n\n\t// replace the bounding box with the capsule\n\ttw->sphere.use = qtrue;\n\ttw->sphere.radius = ( size[1][0] > size[1][2] ) ? size[1][2]: size[1][0];\n\ttw->sphere.halfheight = size[1][2];\n\tVectorSet( tw->sphere.offset, 0, 0, size[1][2] - tw->sphere.radius );\n\n\t// replace the capsule with the bounding box\n\th = CM_TempBoxModel(tw->size[0], tw->size[1], qfalse);\n\t// calculate collision\n\tcmod = CM_ClipHandleToModel( h );\n\tCM_TraceThroughLeaf( tw, &cmod->leaf );\n}\n\n//=========================================================================================\n\n/*\n==================\nCM_TraceThroughTree\n\nTraverse all the contacted leafs from the start to the end position.\nIf the trace is a point, they will be exactly in order, but for larger\ntrace volumes it is possible to hit something in a later leaf with\na smaller intercept fraction.\n==================\n*/\nvoid CM_TraceThroughTree( traceWork_t *tw, int num, float p1f, float p2f, vec3_t p1, vec3_t p2) {\n\tcNode_t\t\t*node;\n\tcplane_t\t*plane;\n\tfloat\t\tt1, t2, offset;\n\tfloat\t\tfrac, frac2;\n\tfloat\t\tidist;\n\tvec3_t\t\tmid;\n\tint\t\t\tside;\n\tfloat\t\tmidf;\n\n\tif (tw->trace.fraction <= p1f) {\n\t\treturn;\t\t// already hit something nearer\n\t}\n\n\t// if < 0, we are in a leaf node\n\tif (num < 0) {\n\t\tCM_TraceThroughLeaf( tw, &cm.leafs[-1-num] );\n\t\treturn;\n\t}\n\n\t//\n\t// find the point distances to the seperating plane\n\t// and the offset for the size of the box\n\t//\n\tnode = cm.nodes + num;\n\tplane = node->plane;\n\n\t// adjust the plane distance apropriately for mins/maxs\n\tif ( plane->type < 3 ) {\n\t\tt1 = p1[plane->type] - plane->dist;\n\t\tt2 = p2[plane->type] - plane->dist;\n\t\toffset = tw->extents[plane->type];\n\t} else {\n\t\tt1 = DotProduct (plane->normal, p1) - plane->dist;\n\t\tt2 = DotProduct (plane->normal, p2) - plane->dist;\n\t\tif ( tw->isPoint ) {\n\t\t\toffset = 0;\n\t\t} else {\n#if 0 // bk010201 - DEAD\n\t\t\t// an axial brush right behind a slanted bsp plane\n\t\t\t// will poke through when expanded, so adjust\n\t\t\t// by sqrt(3)\n\t\t\toffset = fabs(tw->extents[0]*plane->normal[0]) +\n\t\t\t\tfabs(tw->extents[1]*plane->normal[1]) +\n\t\t\t\tfabs(tw->extents[2]*plane->normal[2]);\n\n\t\t\toffset *= 2;\n\t\t\toffset = tw->maxOffset;\n#endif\n\t\t\t// this is silly\n\t\t\toffset = 2048;\n\t\t}\n\t}\n\n\t// see which sides we need to consider\n\tif ( t1 >= offset + 1 && t2 >= offset + 1 ) {\n\t\tCM_TraceThroughTree( tw, node->children[0], p1f, p2f, p1, p2 );\n\t\treturn;\n\t}\n\tif ( t1 < -offset - 1 && t2 < -offset - 1 ) {\n\t\tCM_TraceThroughTree( tw, node->children[1], p1f, p2f, p1, p2 );\n\t\treturn;\n\t}\n\n\t// put the crosspoint SURFACE_CLIP_EPSILON pixels on the near side\n\tif ( t1 < t2 ) {\n\t\tidist = 1.0/(t1-t2);\n\t\tside = 1;\n\t\tfrac2 = (t1 + offset + SURFACE_CLIP_EPSILON)*idist;\n\t\tfrac = (t1 - offset + SURFACE_CLIP_EPSILON)*idist;\n\t} else if (t1 > t2) {\n\t\tidist = 1.0/(t1-t2);\n\t\tside = 0;\n\t\tfrac2 = (t1 - offset - SURFACE_CLIP_EPSILON)*idist;\n\t\tfrac = (t1 + offset + SURFACE_CLIP_EPSILON)*idist;\n\t} else {\n\t\tside = 0;\n\t\tfrac = 1;\n\t\tfrac2 = 0;\n\t}\n\n\t// move up to the node\n\tif ( frac < 0 ) {\n\t\tfrac = 0;\n\t}\n\tif ( frac > 1 ) {\n\t\tfrac = 1;\n\t}\n\t\t\n\tmidf = p1f + (p2f - p1f)*frac;\n\n\tmid[0] = p1[0] + frac*(p2[0] - p1[0]);\n\tmid[1] = p1[1] + frac*(p2[1] - p1[1]);\n\tmid[2] = p1[2] + frac*(p2[2] - p1[2]);\n\n\tCM_TraceThroughTree( tw, node->children[side], p1f, midf, p1, mid );\n\n\n\t// go past the node\n\tif ( frac2 < 0 ) {\n\t\tfrac2 = 0;\n\t}\n\tif ( frac2 > 1 ) {\n\t\tfrac2 = 1;\n\t}\n\t\t\n\tmidf = p1f + (p2f - p1f)*frac2;\n\n\tmid[0] = p1[0] + frac2*(p2[0] - p1[0]);\n\tmid[1] = p1[1] + frac2*(p2[1] - p1[1]);\n\tmid[2] = p1[2] + frac2*(p2[2] - p1[2]);\n\n\tCM_TraceThroughTree( tw, node->children[side^1], midf, p2f, mid, p2 );\n}\n\n\n//======================================================================\n\n\n/*\n==================\nCM_Trace\n==================\n*/\nvoid CM_Trace( trace_t *results, const vec3_t start, const vec3_t end, vec3_t mins, vec3_t maxs,\n\t\t\t\t\t\t  clipHandle_t model, const vec3_t origin, int brushmask, int capsule, sphere_t *sphere ) {\n\tint\t\t\ti;\n\ttraceWork_t\ttw;\n\tvec3_t\t\toffset;\n\tcmodel_t\t*cmod;\n\n\tcmod = CM_ClipHandleToModel( model );\n\n\tcm.checkcount++;\t\t// for multi-check avoidance\n\n\tc_traces++;\t\t\t\t// for statistics, may be zeroed\n\n\t// fill in a default trace\n\tCom_Memset( &tw, 0, sizeof(tw) );\n\ttw.trace.fraction = 1;\t// assume it goes the entire distance until shown otherwise\n\tVectorCopy(origin, tw.modelOrigin);\n\n\tif (!cm.numNodes) {\n\t\t*results = tw.trace;\n\n\t\treturn;\t// map not loaded, shouldn't happen\n\t}\n\n\t// allow NULL to be passed in for 0,0,0\n\tif ( !mins ) {\n\t\tmins = vec3_origin;\n\t}\n\tif ( !maxs ) {\n\t\tmaxs = vec3_origin;\n\t}\n\n\t// set basic parms\n\ttw.contents = brushmask;\n\n\t// adjust so that mins and maxs are always symetric, which\n\t// avoids some complications with plane expanding of rotated\n\t// bmodels\n\tfor ( i = 0 ; i < 3 ; i++ ) {\n\t\toffset[i] = ( mins[i] + maxs[i] ) * 0.5;\n\t\ttw.size[0][i] = mins[i] - offset[i];\n\t\ttw.size[1][i] = maxs[i] - offset[i];\n\t\ttw.start[i] = start[i] + offset[i];\n\t\ttw.end[i] = end[i] + offset[i];\n\t}\n\n\t// if a sphere is already specified\n\tif ( sphere ) {\n\t\ttw.sphere = *sphere;\n\t}\n\telse {\n\t\ttw.sphere.use = (qboolean) capsule;\n\t\ttw.sphere.radius = ( tw.size[1][0] > tw.size[1][2] ) ? tw.size[1][2]: tw.size[1][0];\n\t\ttw.sphere.halfheight = tw.size[1][2];\n\t\tVectorSet( tw.sphere.offset, 0, 0, tw.size[1][2] - tw.sphere.radius );\n\t}\n\n\ttw.maxOffset = tw.size[1][0] + tw.size[1][1] + tw.size[1][2];\n\n\t// tw.offsets[signbits] = vector to apropriate corner from origin\n\ttw.offsets[0][0] = tw.size[0][0];\n\ttw.offsets[0][1] = tw.size[0][1];\n\ttw.offsets[0][2] = tw.size[0][2];\n\n\ttw.offsets[1][0] = tw.size[1][0];\n\ttw.offsets[1][1] = tw.size[0][1];\n\ttw.offsets[1][2] = tw.size[0][2];\n\n\ttw.offsets[2][0] = tw.size[0][0];\n\ttw.offsets[2][1] = tw.size[1][1];\n\ttw.offsets[2][2] = tw.size[0][2];\n\n\ttw.offsets[3][0] = tw.size[1][0];\n\ttw.offsets[3][1] = tw.size[1][1];\n\ttw.offsets[3][2] = tw.size[0][2];\n\n\ttw.offsets[4][0] = tw.size[0][0];\n\ttw.offsets[4][1] = tw.size[0][1];\n\ttw.offsets[4][2] = tw.size[1][2];\n\n\ttw.offsets[5][0] = tw.size[1][0];\n\ttw.offsets[5][1] = tw.size[0][1];\n\ttw.offsets[5][2] = tw.size[1][2];\n\n\ttw.offsets[6][0] = tw.size[0][0];\n\ttw.offsets[6][1] = tw.size[1][1];\n\ttw.offsets[6][2] = tw.size[1][2];\n\n\ttw.offsets[7][0] = tw.size[1][0];\n\ttw.offsets[7][1] = tw.size[1][1];\n\ttw.offsets[7][2] = tw.size[1][2];\n\n\t//\n\t// calculate bounds\n\t//\n\tif ( tw.sphere.use ) {\n\t\tfor ( i = 0 ; i < 3 ; i++ ) {\n\t\t\tif ( tw.start[i] < tw.end[i] ) {\n\t\t\t\ttw.bounds[0][i] = tw.start[i] - fabs(tw.sphere.offset[i]) - tw.sphere.radius;\n\t\t\t\ttw.bounds[1][i] = tw.end[i] + fabs(tw.sphere.offset[i]) + tw.sphere.radius;\n\t\t\t} else {\n\t\t\t\ttw.bounds[0][i] = tw.end[i] - fabs(tw.sphere.offset[i]) - tw.sphere.radius;\n\t\t\t\ttw.bounds[1][i] = tw.start[i] + fabs(tw.sphere.offset[i]) + tw.sphere.radius;\n\t\t\t}\n\t\t}\n\t}\n\telse {\n\t\tfor ( i = 0 ; i < 3 ; i++ ) {\n\t\t\tif ( tw.start[i] < tw.end[i] ) {\n\t\t\t\ttw.bounds[0][i] = tw.start[i] + tw.size[0][i];\n\t\t\t\ttw.bounds[1][i] = tw.end[i] + tw.size[1][i];\n\t\t\t} else {\n\t\t\t\ttw.bounds[0][i] = tw.end[i] + tw.size[0][i];\n\t\t\t\ttw.bounds[1][i] = tw.start[i] + tw.size[1][i];\n\t\t\t}\n\t\t}\n\t}\n\n\t//\n\t// check for position test special case\n\t//\n\tif (start[0] == end[0] && start[1] == end[1] && start[2] == end[2]) {\n\t\tif ( model ) {\n#ifdef ALWAYS_BBOX_VS_BBOX // bk010201 - FIXME - compile time flag?\n\t\t\tif ( model == BOX_MODEL_HANDLE || model == CAPSULE_MODEL_HANDLE) {\n\t\t\t\ttw.sphere.use = qfalse;\n\t\t\t\tCM_TestInLeaf( &tw, &cmod->leaf );\n\t\t\t}\n\t\t\telse\n#elif defined(ALWAYS_CAPSULE_VS_CAPSULE)\n\t\t\tif ( model == BOX_MODEL_HANDLE || model == CAPSULE_MODEL_HANDLE) {\n\t\t\t\tCM_TestCapsuleInCapsule( &tw, model );\n\t\t\t}\n\t\t\telse\n#endif\n\t\t\tif ( model == CAPSULE_MODEL_HANDLE ) {\n\t\t\t\tif ( tw.sphere.use ) {\n\t\t\t\t\tCM_TestCapsuleInCapsule( &tw, model );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tCM_TestBoundingBoxInCapsule( &tw, model );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tCM_TestInLeaf( &tw, &cmod->leaf );\n\t\t\t}\n\t\t} else {\n\t\t\tCM_PositionTest( &tw );\n\t\t}\n\t} else {\n\t\t//\n\t\t// check for point special case\n\t\t//\n\t\tif ( tw.size[0][0] == 0 && tw.size[0][1] == 0 && tw.size[0][2] == 0 ) {\n\t\t\ttw.isPoint = qtrue;\n\t\t\tVectorClear( tw.extents );\n\t\t} else {\n\t\t\ttw.isPoint = qfalse;\n\t\t\ttw.extents[0] = tw.size[1][0];\n\t\t\ttw.extents[1] = tw.size[1][1];\n\t\t\ttw.extents[2] = tw.size[1][2];\n\t\t}\n\n\t\t//\n\t\t// general sweeping through world\n\t\t//\n\t\tif ( model ) {\n#ifdef ALWAYS_BBOX_VS_BBOX\n\t\t\tif ( model == BOX_MODEL_HANDLE || model == CAPSULE_MODEL_HANDLE) {\n\t\t\t\ttw.sphere.use = qfalse;\n\t\t\t\tCM_TraceThroughLeaf( &tw, &cmod->leaf );\n\t\t\t}\n\t\t\telse\n#elif defined(ALWAYS_CAPSULE_VS_CAPSULE)\n\t\t\tif ( model == BOX_MODEL_HANDLE || model == CAPSULE_MODEL_HANDLE) {\n\t\t\t\tCM_TraceCapsuleThroughCapsule( &tw, model );\n\t\t\t}\n\t\t\telse\n#endif\n\t\t\tif ( model == CAPSULE_MODEL_HANDLE ) {\n\t\t\t\tif ( tw.sphere.use ) {\n\t\t\t\t\tCM_TraceCapsuleThroughCapsule( &tw, model );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tCM_TraceBoundingBoxThroughCapsule( &tw, model );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tCM_TraceThroughLeaf( &tw, &cmod->leaf );\n\t\t\t}\n\t\t} else {\n\t\t\tCM_TraceThroughTree( &tw, 0, 0, 1, tw.start, tw.end );\n\t\t}\n\t}\n\n\t// generate endpos from the original, unmodified start/end\n\tif ( tw.trace.fraction == 1 ) {\n\t\tVectorCopy (end, tw.trace.endpos);\n\t} else {\n\t\tfor ( i=0 ; i<3 ; i++ ) {\n\t\t\ttw.trace.endpos[i] = start[i] + tw.trace.fraction * (end[i] - start[i]);\n\t\t}\n\t}\n\n        // If allsolid is set (was entirely inside something solid), the plane is not valid.\n        // If fraction == 1.0, we never hit anything, and thus the plane is not valid.\n        // Otherwise, the normal on the plane should have unit length\n        assert(tw.trace.allsolid ||\n               tw.trace.fraction == 1.0 ||\n               VectorLengthSquared(tw.trace.plane.normal) > 0.9999);\n\t*results = tw.trace;\n}\n\n/*\n==================\nCM_BoxTrace\n==================\n*/\nvoid CM_BoxTrace( trace_t *results, const vec3_t start, const vec3_t end,\n\t\t\t\t\t\t  vec3_t mins, vec3_t maxs,\n\t\t\t\t\t\t  clipHandle_t model, int brushmask, int capsule ) {\n\tCM_Trace( results, start, end, mins, maxs, model, vec3_origin, brushmask, capsule, NULL );\n}\n\n/*\n==================\nCM_TransformedBoxTrace\n\nHandles offseting and rotation of the end points for moving and\nrotating entities\n==================\n*/\nvoid CM_TransformedBoxTrace( trace_t *results, const vec3_t start, const vec3_t end,\n\t\t\t\t\t\t  vec3_t mins, vec3_t maxs,\n\t\t\t\t\t\t  clipHandle_t model, int brushmask,\n\t\t\t\t\t\t  const vec3_t origin, const vec3_t angles, int capsule ) {\n\ttrace_t\t\ttrace;\n\tvec3_t\t\tstart_l, end_l;\n\tqboolean\trotated;\n\tvec3_t\t\toffset;\n\tvec3_t\t\tsymetricSize[2];\n\tvec3_t\t\tmatrix[3], transpose[3];\n\tint\t\t\ti;\n\tfloat\t\thalfwidth;\n\tfloat\t\thalfheight;\n\tfloat\t\tt;\n\tsphere_t\tsphere;\n\n\tif ( !mins ) {\n\t\tmins = vec3_origin;\n\t}\n\tif ( !maxs ) {\n\t\tmaxs = vec3_origin;\n\t}\n\n\t// adjust so that mins and maxs are always symetric, which\n\t// avoids some complications with plane expanding of rotated\n\t// bmodels\n\tfor ( i = 0 ; i < 3 ; i++ ) {\n\t\toffset[i] = ( mins[i] + maxs[i] ) * 0.5;\n\t\tsymetricSize[0][i] = mins[i] - offset[i];\n\t\tsymetricSize[1][i] = maxs[i] - offset[i];\n\t\tstart_l[i] = start[i] + offset[i];\n\t\tend_l[i] = end[i] + offset[i];\n\t}\n\n\t// subtract origin offset\n\tVectorSubtract( start_l, origin, start_l );\n\tVectorSubtract( end_l, origin, end_l );\n\n\t// rotate start and end into the models frame of reference\n\tif ( model != BOX_MODEL_HANDLE && \n\t\t(angles[0] || angles[1] || angles[2]) ) {\n\t\trotated = qtrue;\n\t} else {\n\t\trotated = qfalse;\n\t}\n\n\thalfwidth = symetricSize[ 1 ][ 0 ];\n\thalfheight = symetricSize[ 1 ][ 2 ];\n\n\tsphere.use = (qboolean) capsule;\n\tsphere.radius = ( halfwidth > halfheight ) ? halfheight : halfwidth;\n\tsphere.halfheight = halfheight;\n\tt = halfheight - sphere.radius;\n\n\tif (rotated) {\n\t\t// rotation on trace line (start-end) instead of rotating the bmodel\n\t\t// NOTE: This is still incorrect for bounding boxes because the actual bounding\n\t\t//\t\t box that is swept through the model is not rotated. We cannot rotate\n\t\t//\t\t the bounding box or the bmodel because that would make all the brush\n\t\t//\t\t bevels invalid.\n\t\t//\t\t However this is correct for capsules since a capsule itself is rotated too.\n\t\tCreateRotationMatrix(angles, matrix);\n\t\tRotatePoint(start_l, matrix);\n\t\tRotatePoint(end_l, matrix);\n\t\t// rotated sphere offset for capsule\n\t\tsphere.offset[0] = matrix[0][ 2 ] * t;\n\t\tsphere.offset[1] = -matrix[1][ 2 ] * t;\n\t\tsphere.offset[2] = matrix[2][ 2 ] * t;\n\t}\n\telse {\n\t\tVectorSet( sphere.offset, 0, 0, t );\n\t}\n\n\t// sweep the box through the model\n\tCM_Trace( &trace, start_l, end_l, symetricSize[0], symetricSize[1], model, origin, brushmask, capsule, &sphere );\n\n\t// if the bmodel was rotated and there was a collision\n\tif ( rotated && trace.fraction != 1.0 ) {\n\t\t// rotation of bmodel collision plane\n\t\tTransposeMatrix(matrix, transpose);\n\t\tRotatePoint(trace.plane.normal, transpose);\n\t}\n\n\t// re-calculate the end position of the trace because the trace.endpos\n\t// calculated by CM_Trace could be rotated and have an offset\n\ttrace.endpos[0] = start[0] + trace.fraction * (end[0] - start[0]);\n\ttrace.endpos[1] = start[1] + trace.fraction * (end[1] - start[1]);\n\ttrace.endpos[2] = start[2] + trace.fraction * (end[2] - start[2]);\n\n\t*results = trace;\n}\n"
  },
  {
    "path": "src/engine/qcommon/cmd.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n// cmd.c -- Quake script command processing module\n\n#include \"../../game/q_shared.h\"\n#include \"qcommon.h\"\n\n#define\tMAX_CMD_BUFFER\t16384\n#define\tMAX_CMD_LINE\t1024\n\ntypedef struct {\n\tbyte\t*data;\n\tint\t\tmaxsize;\n\tint\t\tcursize;\n} cmd_t;\n\nint\t\t\tcmd_wait;\ncmd_t\t\tcmd_text;\nbyte\t\tcmd_text_buf[MAX_CMD_BUFFER];\n\n\n//=============================================================================\n\n/*\n============\nCmd_Wait_f\n\nCauses execution of the remainder of the command buffer to be delayed until\nnext frame.  This allows commands like:\nbind g \"cmd use rocket ; +attack ; wait ; -attack ; cmd use blaster\"\n============\n*/\nvoid Cmd_Wait_f( void ) {\n\tif ( Cmd_Argc() == 2 ) {\n\t\tcmd_wait = atoi( Cmd_Argv( 1 ) );\n\t} else {\n\t\tcmd_wait = 1;\n\t}\n}\n\n\n/*\n=============================================================================\n\n\t\t\t\t\t\tCOMMAND BUFFER\n\n=============================================================================\n*/\n\n/*\n============\nCbuf_Init\n============\n*/\nvoid Cbuf_Init (void)\n{\n\tcmd_text.data = cmd_text_buf;\n\tcmd_text.maxsize = MAX_CMD_BUFFER;\n\tcmd_text.cursize = 0;\n}\n\n/*\n============\nCbuf_AddText\n\nAdds command text at the end of the buffer, does NOT add a final \\n\n============\n*/\nvoid Cbuf_AddText( const char *text ) {\n\tint\t\tl;\n\t\n\tl = (int)strlen (text);\n\n\tif (cmd_text.cursize + l >= cmd_text.maxsize)\n\t{\n\t\tCom_Printf (\"Cbuf_AddText: overflow\\n\");\n\t\treturn;\n\t}\n\tCom_Memcpy(&cmd_text.data[cmd_text.cursize], text, l);\n\tcmd_text.cursize += l;\n}\n\n\n/*\n============\nCbuf_InsertText\n\nAdds command text immediately after the current command\nAdds a \\n to the text\n============\n*/\nvoid Cbuf_InsertText( const char *text ) {\n\tint\t\tlen;\n\tint\t\ti;\n\n\tlen = (int)strlen( text ) + 1;\n\tif ( len + cmd_text.cursize > cmd_text.maxsize ) {\n\t\tCom_Printf( \"Cbuf_InsertText overflowed\\n\" );\n\t\treturn;\n\t}\n\n\t// move the existing command text\n\tfor ( i = cmd_text.cursize - 1 ; i >= 0 ; i-- ) {\n\t\tcmd_text.data[ i + len ] = cmd_text.data[ i ];\n\t}\n\n\t// copy the new text in\n\tCom_Memcpy( cmd_text.data, text, len - 1 );\n\n\t// add a \\n\n\tcmd_text.data[ len - 1 ] = '\\n';\n\n\tcmd_text.cursize += len;\n}\n\n\n/*\n============\nCbuf_ExecuteText\n============\n*/\nvoid Cbuf_ExecuteText (int exec_when, const char *text)\n{\n\tswitch (exec_when)\n\t{\n\tcase EXEC_NOW:\n\t\tif (text && (int)strlen(text) > 0) {\n\t\t\tCmd_ExecuteString (text);\n\t\t} else {\n\t\t\tCbuf_Execute();\n\t\t}\n\t\tbreak;\n\tcase EXEC_INSERT:\n\t\tCbuf_InsertText (text);\n\t\tbreak;\n\tcase EXEC_APPEND:\n\t\tCbuf_AddText (text);\n\t\tbreak;\n\tdefault:\n\t\tCom_Error (ERR_FATAL, \"Cbuf_ExecuteText: bad exec_when\");\n\t}\n}\n\n/*\n============\nCbuf_Execute\n============\n*/\nvoid Cbuf_Execute (void)\n{\n\tint\t\ti;\n\tchar\t*text;\n\tchar\tline[MAX_CMD_LINE];\n\tint\t\tquotes;\n\n\twhile (cmd_text.cursize)\n\t{\n\t\tif ( cmd_wait )\t{\n\t\t\t// skip out while text still remains in buffer, leaving it\n\t\t\t// for next frame\n\t\t\tcmd_wait--;\n\t\t\tbreak;\n\t\t}\n\n\t\t// find a \\n or ; line break\n\t\ttext = (char *)cmd_text.data;\n\n\t\tquotes = 0;\n\t\tfor (i=0 ; i< cmd_text.cursize ; i++)\n\t\t{\n\t\t\tif (text[i] == '\"')\n\t\t\t\tquotes++;\n\t\t\tif ( !(quotes&1) &&  text[i] == ';')\n\t\t\t\tbreak;\t// don't break if inside a quoted string\n\t\t\tif (text[i] == '\\n' || text[i] == '\\r' )\n\t\t\t\tbreak;\n\t\t}\n\n\t\tif( i >= (MAX_CMD_LINE - 1)) {\n\t\t\ti = MAX_CMD_LINE - 1;\n\t\t}\n\t\t\t\t\n\t\tCom_Memcpy (line, text, i);\n\t\tline[i] = 0;\n\t\t\n// delete the text from the command buffer and move remaining commands down\n// this is necessary because commands (exec) can insert data at the\n// beginning of the text buffer\n\n\t\tif (i == cmd_text.cursize)\n\t\t\tcmd_text.cursize = 0;\n\t\telse\n\t\t{\n\t\t\ti++;\n\t\t\tcmd_text.cursize -= i;\n\t\t\tmemmove (text, text+i, cmd_text.cursize);\n\t\t}\n\n// execute the command line\n\n\t\tCmd_ExecuteString (line);\t\t\n\t}\n}\n\n\n/*\n==============================================================================\n\n\t\t\t\t\t\tSCRIPT COMMANDS\n\n==============================================================================\n*/\n\n\n/*\n===============\nCmd_Exec_f\n===============\n*/\nvoid Cmd_Exec_f( void ) {\n\tchar\t*f;\n\tint\t\tlen;\n\tchar\tfilename[MAX_QPATH];\n\n\tif (Cmd_Argc () != 2) {\n\t\tCom_Printf (\"exec <filename> : execute a script file\\n\");\n\t\treturn;\n\t}\n\n\tQ_strncpyz( filename, Cmd_Argv(1), sizeof( filename ) );\n\tCOM_DefaultExtension( filename, sizeof( filename ), \".cfg\" ); \n\tlen = FS_ReadFile( filename, (void **)&f);\n\tif (!f) {\n\t\tCom_Printf (\"couldn't exec %s\\n\",Cmd_Argv(1));\n\t\treturn;\n\t}\n\tCom_Printf (\"execing %s\\n\",Cmd_Argv(1));\n\t\n\tCbuf_InsertText (f);\n\n\tFS_FreeFile (f);\n}\n\n\n/*\n===============\nCmd_Vstr_f\n\nInserts the current value of a variable as command text\n===============\n*/\nvoid Cmd_Vstr_f( void ) {\n\tchar\t*v;\n\n\tif (Cmd_Argc () != 2) {\n\t\tCom_Printf (\"vstr <variablename> : execute a variable command\\n\");\n\t\treturn;\n\t}\n\n\tv = Cvar_VariableString( Cmd_Argv( 1 ) );\n\tCbuf_InsertText( va(\"%s\\n\", v ) );\n}\n\n\n/*\n===============\nCmd_Echo_f\n\nJust prints the rest of the line to the console\n===============\n*/\nvoid Cmd_Echo_f (void)\n{\n\tint\t\ti;\n\t\n\tfor (i=1 ; i<Cmd_Argc() ; i++)\n\t\tCom_Printf (\"%s \",Cmd_Argv(i));\n\tCom_Printf (\"\\n\");\n}\n\n\n/*\n=============================================================================\n\n\t\t\t\t\tCOMMAND EXECUTION\n\n=============================================================================\n*/\n\ntypedef struct cmd_function_s\n{\n\tstruct cmd_function_s\t*next;\n\tchar\t\t\t\t\t*name;\n\txcommand_t\t\t\t\tfunction;\n} cmd_function_t;\n\n\nstatic\tint\t\t\tcmd_argc;\nstatic\tchar\t\t*cmd_argv[MAX_STRING_TOKENS];\t\t// points into cmd_tokenized\nstatic\tchar\t\tcmd_tokenized[BIG_INFO_STRING+MAX_STRING_TOKENS];\t// will have 0 bytes inserted\nstatic\tchar\t\tcmd_cmd[BIG_INFO_STRING]; // the original command we received (no token processing)\n\nstatic\tcmd_function_t\t*cmd_functions;\t\t// possible commands to execute\n\n/*\n============\nCmd_Argc\n============\n*/\nint\t\tCmd_Argc( void ) {\n\treturn cmd_argc;\n}\n\n/*\n============\nCmd_Argv\n============\n*/\nchar\t*Cmd_Argv( int arg ) {\n\tif ( (unsigned)arg >= cmd_argc ) {\n\t\treturn \"\";\n\t}\n\treturn cmd_argv[arg];\t\n}\n\n/*\n============\nCmd_ArgvBuffer\n\nThe interpreted versions use this because\nthey can't have pointers returned to them\n============\n*/\nvoid\tCmd_ArgvBuffer( int arg, char *buffer, int bufferLength ) {\n\tQ_strncpyz( buffer, Cmd_Argv( arg ), bufferLength );\n}\n\n\n/*\n============\nCmd_Args\n\nReturns a single string containing argv(1) to argv(argc()-1)\n============\n*/\nchar\t*Cmd_Args( void ) {\n\tstatic\tchar\t\tcmd_args[MAX_STRING_CHARS];\n\tint\t\ti;\n\n\tcmd_args[0] = 0;\n\tfor ( i = 1 ; i < cmd_argc ; i++ ) {\n\t\tstrcat( cmd_args, cmd_argv[i] );\n\t\tif ( i != cmd_argc-1 ) {\n\t\t\tstrcat( cmd_args, \" \" );\n\t\t}\n\t}\n\n\treturn cmd_args;\n}\n\n/*\n============\nCmd_Args\n\nReturns a single string containing argv(arg) to argv(argc()-1)\n============\n*/\nchar *Cmd_ArgsFrom( int arg ) {\n\tstatic\tchar\t\tcmd_args[BIG_INFO_STRING];\n\tint\t\ti;\n\n\tcmd_args[0] = 0;\n\tif (arg < 0)\n\t\targ = 0;\n\tfor ( i = arg ; i < cmd_argc ; i++ ) {\n\t\tstrcat( cmd_args, cmd_argv[i] );\n\t\tif ( i != cmd_argc-1 ) {\n\t\t\tstrcat( cmd_args, \" \" );\n\t\t}\n\t}\n\n\treturn cmd_args;\n}\n\n/*\n============\nCmd_ArgsBuffer\n\nThe interpreted versions use this because\nthey can't have pointers returned to them\n============\n*/\nvoid\tCmd_ArgsBuffer( char *buffer, int bufferLength ) {\n\tQ_strncpyz( buffer, Cmd_Args(), bufferLength );\n}\n\n/*\n============\nCmd_Cmd\n\nRetrieve the unmodified command string\nFor rcon use when you want to transmit without altering quoting\nhttps://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=543\n============\n*/\nchar *Cmd_Cmd()\n{\n\treturn cmd_cmd;\n}\n\n/*\n============\nCmd_TokenizeString\n\nParses the given string into command line tokens.\nThe text is copied to a seperate buffer and 0 characters\nare inserted in the apropriate place, The argv array\nwill point into this temporary buffer.\n============\n*/\n// NOTE TTimo define that to track tokenization issues\n//#define TKN_DBG\nvoid Cmd_TokenizeString( const char *text_in ) {\n\tconst char\t*text;\n\tchar\t*textOut;\n\n#ifdef TKN_DBG\n  // FIXME TTimo blunt hook to try to find the tokenization of userinfo\n  Com_DPrintf(\"Cmd_TokenizeString: %s\\n\", text_in);\n#endif\n\n\t// clear previous args\n\tcmd_argc = 0;\n\n\tif ( !text_in ) {\n\t\treturn;\n\t}\n\t\n\tQ_strncpyz( cmd_cmd, text_in, sizeof(cmd_cmd) );\n\n\ttext = text_in;\n\ttextOut = cmd_tokenized;\n\n\twhile ( 1 ) {\n\t\tif ( cmd_argc == MAX_STRING_TOKENS ) {\n\t\t\treturn;\t\t\t// this is usually something malicious\n\t\t}\n\n\t\twhile ( 1 ) {\n\t\t\t// skip whitespace\n\t\t\twhile ( *text && *text <= ' ' ) {\n\t\t\t\ttext++;\n\t\t\t}\n\t\t\tif ( !*text ) {\n\t\t\t\treturn;\t\t\t// all tokens parsed\n\t\t\t}\n\n\t\t\t// skip // comments\n\t\t\tif ( text[0] == '/' && text[1] == '/' ) {\n\t\t\t\treturn;\t\t\t// all tokens parsed\n\t\t\t}\n\n\t\t\t// skip /* */ comments\n\t\t\tif ( text[0] == '/' && text[1] =='*' ) {\n\t\t\t\twhile ( *text && ( text[0] != '*' || text[1] != '/' ) ) {\n\t\t\t\t\ttext++;\n\t\t\t\t}\n\t\t\t\tif ( !*text ) {\n\t\t\t\t\treturn;\t\t// all tokens parsed\n\t\t\t\t}\n\t\t\t\ttext += 2;\n\t\t\t} else {\n\t\t\t\tbreak;\t\t\t// we are ready to parse a token\n\t\t\t}\n\t\t}\n\n\t\t// handle quoted strings\n    // NOTE TTimo this doesn't handle \\\" escaping\n\t\tif ( *text == '\"' ) {\n\t\t\tcmd_argv[cmd_argc] = textOut;\n\t\t\tcmd_argc++;\n\t\t\ttext++;\n\t\t\twhile ( *text && *text != '\"' ) {\n\t\t\t\t*textOut++ = *text++;\n\t\t\t}\n\t\t\t*textOut++ = 0;\n\t\t\tif ( !*text ) {\n\t\t\t\treturn;\t\t// all tokens parsed\n\t\t\t}\n\t\t\ttext++;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// regular token\n\t\tcmd_argv[cmd_argc] = textOut;\n\t\tcmd_argc++;\n\n\t\t// skip until whitespace, quote, or command\n\t\twhile ( *text > ' ' ) {\n\t\t\tif ( text[0] == '\"' ) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif ( text[0] == '/' && text[1] == '/' ) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// skip /* */ comments\n\t\t\tif ( text[0] == '/' && text[1] =='*' ) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t*textOut++ = *text++;\n\t\t}\n\n\t\t*textOut++ = 0;\n\n\t\tif ( !*text ) {\n\t\t\treturn;\t\t// all tokens parsed\n\t\t}\n\t}\n\t\n}\n\n\n/*\n============\nCmd_AddCommand\n============\n*/\nvoid\tCmd_AddCommand( const char *cmd_name, xcommand_t function ) {\n\tcmd_function_t\t*cmd;\n\t\n\t// fail if the command already exists\n\tfor ( cmd = cmd_functions ; cmd ; cmd=cmd->next ) {\n\t\tif ( !strcmp( cmd_name, cmd->name ) ) {\n\t\t\t// allow completion-only commands to be silently doubled\n\t\t\tif ( function != NULL ) {\n\t\t\t\tCom_Printf (\"Cmd_AddCommand: %s already defined\\n\", cmd_name);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t}\n\n\t// use a small malloc to avoid zone fragmentation\n\tcmd = (cmd_function_t*) S_Malloc(sizeof(cmd_function_t));\n\tcmd->name = CopyString( cmd_name );\n\tcmd->function = function;\n\tcmd->next = cmd_functions;\n\tcmd_functions = cmd;\n}\n\n/*\n============\nCmd_RemoveCommand\n============\n*/\nvoid\tCmd_RemoveCommand( const char *cmd_name ) {\n\tcmd_function_t\t*cmd, **back;\n\n\tback = &cmd_functions;\n\twhile( 1 ) {\n\t\tcmd = *back;\n\t\tif ( !cmd ) {\n\t\t\t// command wasn't active\n\t\t\treturn;\n\t\t}\n\t\tif ( !strcmp( cmd_name, cmd->name ) ) {\n\t\t\t*back = cmd->next;\n\t\t\tif (cmd->name) {\n\t\t\t\tZ_Free(cmd->name);\n\t\t\t}\n\t\t\tZ_Free (cmd);\n\t\t\treturn;\n\t\t}\n\t\tback = &cmd->next;\n\t}\n}\n\n\n/*\n============\nCmd_CommandCompletion\n============\n*/\nvoid\tCmd_CommandCompletion( void(*callback)(const char *s) ) {\n\tcmd_function_t\t*cmd;\n\t\n\tfor (cmd=cmd_functions ; cmd ; cmd=cmd->next) {\n\t\tcallback( cmd->name );\n\t}\n}\n\n\n/*\n============\nCmd_ExecuteString\n\nA complete command line has been parsed, so try to execute it\n============\n*/\nvoid\tCmd_ExecuteString( const char *text ) {\t\n\tcmd_function_t\t*cmd, **prev;\n\n\t// execute the command line\n\tCmd_TokenizeString( text );\t\t\n\tif ( !Cmd_Argc() ) {\n\t\treturn;\t\t// no tokens\n\t}\n\n\t// check registered command functions\t\n\tfor ( prev = &cmd_functions ; *prev ; prev = &cmd->next ) {\n\t\tcmd = *prev;\n\t\tif ( !Q_stricmp( cmd_argv[0],cmd->name ) ) {\n\t\t\t// rearrange the links so that the command will be\n\t\t\t// near the head of the list next time it is used\n\t\t\t*prev = cmd->next;\n\t\t\tcmd->next = cmd_functions;\n\t\t\tcmd_functions = cmd;\n\n\t\t\t// perform the action\n\t\t\tif ( !cmd->function ) {\n\t\t\t\t// let the cgame or game handle it\n\t\t\t\tbreak;\n\t\t\t} else {\n\t\t\t\tcmd->function ();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t}\n\t\n\t// check cvars\n\tif ( Cvar_Command() ) {\n\t\treturn;\n\t}\n\n\t// check client game commands\n\tif ( com_cl_running && com_cl_running->integer && CL_GameCommand() ) {\n\t\treturn;\n\t}\n\n\t// check server game commands\n\tif ( com_sv_running && com_sv_running->integer && SV_GameCommand() ) {\n\t\treturn;\n\t}\n\n\t// check ui commands\n\tif ( com_cl_running && com_cl_running->integer && UI_GameCommand() ) {\n\t\treturn;\n\t}\n\n\t// send it as a server command if we are connected\n\t// this will usually result in a chat message\n\tCL_ForwardCommandToServer ( text );\n}\n\n/*\n============\nCmd_List_f\n============\n*/\nvoid Cmd_List_f (void)\n{\n\tcmd_function_t\t*cmd;\n\tint\t\t\t\ti;\n\tchar\t\t\t*match;\n\n\tif ( Cmd_Argc() > 1 ) {\n\t\tmatch = Cmd_Argv( 1 );\n\t} else {\n\t\tmatch = NULL;\n\t}\n\n\ti = 0;\n\tfor (cmd=cmd_functions ; cmd ; cmd=cmd->next) {\n\t\tif (match && !Com_Filter(match, cmd->name, qfalse)) continue;\n\n\t\tCom_Printf (\"%s\\n\", cmd->name);\n\t\ti++;\n\t}\n\tCom_Printf (\"%i commands\\n\", i);\n}\n\n/*\n============\nCmd_Init\n============\n*/\nvoid Cmd_Init (void) {\n\tCmd_AddCommand (\"cmdlist\",Cmd_List_f);\n\tCmd_AddCommand (\"exec\",Cmd_Exec_f);\n\tCmd_AddCommand (\"vstr\",Cmd_Vstr_f);\n\tCmd_AddCommand (\"echo\",Cmd_Echo_f);\n\tCmd_AddCommand (\"wait\", Cmd_Wait_f);\n}\n\n"
  },
  {
    "path": "src/engine/qcommon/common.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n// common.c -- misc functions used in client and server\n\n#include \"../../game/q_shared.h\"\n#include \"qcommon.h\"\n#include <setjmp.h>\n#ifdef __linux__\n#include <netinet/in.h>\n#else\n#if defined(MACOS_X)\n#include <netinet/in.h>\n#else\n#include <winsock.h>\n#endif\n#endif\n\nint demo_protocols[] =\n{ 66, 67, 68, 0 };\n\n#define MAX_NUM_ARGVS\t50\n\n#define MIN_DEDICATED_COMHUNKMEGS 1\n#define MIN_COMHUNKMEGS 56\n#ifdef MACOS_X\n#define DEF_COMHUNKMEGS \"64\"\n#define DEF_COMZONEMEGS \"24\"\n#else\n#define DEF_COMHUNKMEGS \"56\"\n#define DEF_COMZONEMEGS \"16\"\n#endif\n\nint\t\tcom_argc;\nchar\t*com_argv[MAX_NUM_ARGVS+1];\n\njmp_buf abortframe;\t\t// an ERR_DROP occured, exit the entire frame\n\n\nFILE *debuglogfile;\nstatic fileHandle_t logfile;\nfileHandle_t\tcom_journalFile;\t\t\t// events are written here\nfileHandle_t\tcom_journalDataFile;\t\t// config files are written here\n\ncvar_t\t*com_viewlog;\ncvar_t\t*com_speeds;\ncvar_t\t*com_developer;\ncvar_t\t*com_dedicated;\ncvar_t\t*com_timescale;\ncvar_t\t*com_fixedtime;\ncvar_t\t*com_dropsim;\t\t// 0.0 to 1.0, simulated packet drops\ncvar_t\t*com_journal;\ncvar_t\t*com_maxfps;\ncvar_t\t*com_timedemo;\ncvar_t\t*com_sv_running;\ncvar_t\t*com_cl_running;\ncvar_t\t*com_logfile;\t\t// 1 = buffer log, 2 = flush after each print\ncvar_t\t*com_showtrace;\ncvar_t\t*com_version;\ncvar_t\t*com_blood;\ncvar_t\t*com_buildScript;\t// for automated data building scripts\ncvar_t\t*com_introPlayed;\ncvar_t\t*cl_paused;\ncvar_t\t*sv_paused;\ncvar_t\t*com_cameraMode;\n#if defined(_WIN32) && defined(_DEBUG)\ncvar_t\t*com_noErrorInterrupt;\n#endif\n\n// com_speeds times\nint\t\ttime_game;\nint\t\ttime_frontend;\t\t// renderer frontend time\nint\t\ttime_backend;\t\t// renderer backend time\n\nint\t\t\tcom_frameTime;\nint\t\t\tcom_frameMsec;\nint\t\t\tcom_frameNumber;\n\nqboolean\tcom_errorEntered;\nqboolean\tcom_fullyInitialized;\n\nchar\tcom_errorMessage[MAXPRINTMSG];\n\nvoid Com_WriteConfig_f( void );\nvoid CIN_CloseAllVideos();\n\n//============================================================================\n\nstatic char\t*rd_buffer;\nstatic int\trd_buffersize;\nstatic void\t(*rd_flush)( char *buffer );\n\nvoid Com_BeginRedirect (char *buffer, int buffersize, void (*flush)( char *) )\n{\n\tif (!buffer || !buffersize || !flush)\n\t\treturn;\n\trd_buffer = buffer;\n\trd_buffersize = buffersize;\n\trd_flush = flush;\n\n\t*rd_buffer = 0;\n}\n\nvoid Com_EndRedirect (void)\n{\n\tif ( rd_flush ) {\n\t\trd_flush(rd_buffer);\n\t}\n\n\trd_buffer = NULL;\n\trd_buffersize = 0;\n\trd_flush = NULL;\n}\n\n/*\n=============\nCom_Printf\n\nBoth client and server can use this, and it will output\nto the apropriate place.\n\nA raw string should NEVER be passed as fmt, because of \"%f\" type crashers.\n=============\n*/\nvoid QDECL Com_Printf( const char *fmt, ... ) {\n\tva_list\t\targptr;\n\tchar\t\tmsg[MAXPRINTMSG];\n  static qboolean opening_qconsole = qfalse;\n\n\tva_start (argptr,fmt);\n\tQ_vsnprintf (msg, sizeof(msg), fmt, argptr);\n\tva_end (argptr);\n\n\tif ( rd_buffer ) {\n\t\tif ((strlen (msg) + (int)strlen(rd_buffer)) > (rd_buffersize - 1)) {\n\t\t\trd_flush(rd_buffer);\n\t\t\t*rd_buffer = 0;\n\t\t}\n\t\tQ_strcat(rd_buffer, rd_buffersize, msg);\n    // TTimo nooo .. that would defeat the purpose\n\t\t//rd_flush(rd_buffer);\t\t\t\n\t\t//*rd_buffer = 0;\n\t\treturn;\n\t}\n\n\t// echo to console if we're not a dedicated server\n\tif ( com_dedicated && !com_dedicated->integer ) {\n\t\tCL_ConsolePrint( msg );\n\t}\n\n\t// echo to dedicated console and early console\n\tSys_Print( msg );\n\n\t// logfile\n\tif ( com_logfile && com_logfile->integer ) {\n    // TTimo: only open the qconsole.log if the filesystem is in an initialized state\n    //   also, avoid recursing in the qconsole.log opening (i.e. if fs_debug is on)\n\t\tif ( !logfile && FS_Initialized() && !opening_qconsole) {\n\t\t\tstruct tm *newtime;\n\t\t\ttime_t aclock;\n\n      opening_qconsole = qtrue;\n\n\t\t\ttime( &aclock );\n\t\t\tnewtime = localtime( &aclock );\n\n\t\t\tlogfile = FS_FOpenFileWrite( \"qconsole.log\" );\n\t\t\tCom_Printf( \"logfile opened on %s\\n\", asctime( newtime ) );\n\t\t\tif ( com_logfile->integer > 1 ) {\n\t\t\t\t// force it to not buffer so we get valid\n\t\t\t\t// data even if we are crashing\n\t\t\t\tFS_ForceFlush(logfile);\n\t\t\t}\n\n      opening_qconsole = qfalse;\n\t\t}\n\t\tif ( logfile && FS_Initialized()) {\n\t\t\tFS_Write(msg, (int)strlen(msg), logfile);\n\t\t}\n\t}\n}\n\n\n/*\n================\nCom_DPrintf\n\nA Com_Printf that only shows up if the \"developer\" cvar is set\n================\n*/\nvoid QDECL Com_DPrintf( const char *fmt, ...) {\n\tva_list\t\targptr;\n\tchar\t\tmsg[MAXPRINTMSG];\n\t\t\n\tif ( !com_developer || !com_developer->integer ) {\n\t\treturn;\t\t\t// don't confuse non-developers with techie stuff...\n\t}\n\n\tva_start (argptr,fmt);\t\n\tQ_vsnprintf (msg, sizeof(msg), fmt, argptr);\n\tva_end (argptr);\n\t\n\tCom_Printf (\"%s\", msg);\n}\n\n/*\n=============\nCom_Error\n\nBoth client and server can use this, and it will\ndo the apropriate things.\n=============\n*/\nvoid QDECL Com_Error( int code, const char *fmt, ... ) {\n\tva_list\t\targptr;\n\tstatic int\tlastErrorTime;\n\tstatic int\terrorCount;\n\tint\t\t\tcurrentTime;\n\n#if defined(_WIN32) && defined(_DEBUG)\n\tif ( code != ERR_DISCONNECT && code != ERR_NEED_CD ) {\n\t\tif (!com_noErrorInterrupt->integer) {\n\t\t\t__debugbreak();\n\t\t}\n\t}\n#endif\n\n\t// when we are running automated scripts, make sure we\n\t// know if anything failed\n\tif ( com_buildScript && com_buildScript->integer ) {\n\t\tcode = ERR_FATAL;\n\t}\n\n\t// make sure we can get at our local stuff\n\tFS_PureServerSetLoadedPaks( \"\", \"\" );\n\n\t// if we are getting a solid stream of ERR_DROP, do an ERR_FATAL\n\tcurrentTime = Sys_Milliseconds();\n\tif ( currentTime - lastErrorTime < 100 ) {\n\t\tif ( ++errorCount > 3 ) {\n\t\t\tcode = ERR_FATAL;\n\t\t}\n\t} else {\n\t\terrorCount = 0;\n\t}\n\tlastErrorTime = currentTime;\n\n\tif ( com_errorEntered ) {\n\t\tSys_Error( \"recursive error after: %s\", com_errorMessage );\n\t}\n\tcom_errorEntered = qtrue;\n\n\tva_start (argptr,fmt);\n\tvsprintf (com_errorMessage,fmt,argptr);\n\tva_end (argptr);\n\n\tif ( code != ERR_DISCONNECT && code != ERR_NEED_CD ) {\n\t\tCvar_Set(\"com_errorMessage\", com_errorMessage);\n\t}\n\n\tif ( code == ERR_SERVERDISCONNECT ) {\n\t\tCL_Disconnect( qtrue );\n\t\tCL_FlushMemory( );\n\t\tcom_errorEntered = qfalse;\n\t\tlongjmp (abortframe, -1);\n\t} else if ( code == ERR_DROP || code == ERR_DISCONNECT ) {\n\t\tCom_Printf (\"********************\\nERROR: %s\\n********************\\n\", com_errorMessage);\n\t\tSV_Shutdown (va(\"Server crashed: %s\\n\",  com_errorMessage));\n\t\tCL_Disconnect( qtrue );\n\t\tCL_FlushMemory( );\n\t\tcom_errorEntered = qfalse;\n\t\tlongjmp (abortframe, -1);\n\t} else if ( code == ERR_NEED_CD ) {\n\t\tSV_Shutdown( \"Server didn't have CD\\n\" );\n\t\tif ( com_cl_running && com_cl_running->integer ) {\n\t\t\tCL_Disconnect( qtrue );\n\t\t\tCL_FlushMemory( );\n\t\t\tcom_errorEntered = qfalse;\n\t\t\tCL_CDDialog();\n\t\t} else {\n\t\t\tCom_Printf(\"Server didn't have CD\\n\" );\n\t\t}\n\t\tlongjmp (abortframe, -1);\n\t} else {\n\t\tCL_Shutdown ();\n\t\tSV_Shutdown (va(\"Server fatal crashed: %s\\n\", com_errorMessage));\n\t}\n\n\tCom_Shutdown ();\n\n\tSys_Error (\"%s\", com_errorMessage);\n}\n\n\n/*\n=============\nCom_Quit_f\n\nBoth client and server can use this, and it will\ndo the apropriate things.\n=============\n*/\nvoid Com_Quit_f( void ) {\n\t// don't try to shutdown if we are in a recursive error\n\tif ( !com_errorEntered ) {\n\t\tSV_Shutdown (\"Server quit\\n\");\n\t\tCL_Shutdown ();\n\t\tCom_Shutdown ();\n\t\tFS_Shutdown(qtrue);\n\t}\n\tSys_Quit ();\n}\n\n\n\n/*\n============================================================================\n\nCOMMAND LINE FUNCTIONS\n\n+ characters seperate the commandLine string into multiple console\ncommand lines.\n\nAll of these are valid:\n\nquake3 +set test blah +map test\nquake3 set test blah+map test\nquake3 set test blah + map test\n\n============================================================================\n*/\n\n#define\tMAX_CONSOLE_LINES\t32\nint\t\tcom_numConsoleLines;\nchar\t*com_consoleLines[MAX_CONSOLE_LINES];\n\n/*\n==================\nCom_ParseCommandLine\n\nBreak it up into multiple console lines\n==================\n*/\nvoid Com_ParseCommandLine( char *commandLine ) {\n    int inq = 0;\n    com_consoleLines[0] = commandLine;\n    com_numConsoleLines = 1;\n\n    while ( *commandLine ) {\n        if (*commandLine == '\"') {\n            inq = !inq;\n        }\n        // look for a + seperating character\n        // if commandLine came from a file, we might have real line seperators\n        if ( (*commandLine == '+' && !inq) || *commandLine == '\\n'  || *commandLine == '\\r' ) {\n            if ( com_numConsoleLines == MAX_CONSOLE_LINES ) {\n                return;\n            }\n            com_consoleLines[com_numConsoleLines] = commandLine + 1;\n            com_numConsoleLines++;\n            *commandLine = 0;\n        }\n        commandLine++;\n    }\n}\n\n\n/*\n===================\nCom_SafeMode\n\nCheck for \"safe\" on the command line, which will\nskip loading of q3config.cfg\n===================\n*/\nqboolean Com_SafeMode( void ) {\n\tint\t\ti;\n\n\tfor ( i = 0 ; i < com_numConsoleLines ; i++ ) {\n\t\tCmd_TokenizeString( com_consoleLines[i] );\n\t\tif ( !Q_stricmp( Cmd_Argv(0), \"safe\" )\n\t\t\t|| !Q_stricmp( Cmd_Argv(0), \"cvar_restart\" ) ) {\n\t\t\tcom_consoleLines[i][0] = 0;\n\t\t\treturn qtrue;\n\t\t}\n\t}\n\treturn qfalse;\n}\n\n\n/*\n===============\nCom_StartupVariable\n\nSearches for command line parameters that are set commands.\nIf match is not NULL, only that cvar will be looked for.\nThat is necessary because cddir and basedir need to be set\nbefore the filesystem is started, but all other sets shouls\nbe after execing the config and default.\n===============\n*/\nvoid Com_StartupVariable( const char *match ) {\n\tint\t\ti;\n\tchar\t*s;\n\tcvar_t\t*cv;\n\n\tfor (i=0 ; i < com_numConsoleLines ; i++) {\n\t\tCmd_TokenizeString( com_consoleLines[i] );\n\t\tif ( strcmp( Cmd_Argv(0), \"set\" ) ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\ts = Cmd_Argv(1);\n\t\tif ( !match || !strcmp( s, match ) ) {\n\t\t\tCvar_Set( s, Cmd_Argv(2) );\n\t\t\tcv = Cvar_Get( s, \"\", 0 );\n\t\t\tcv->flags |= CVAR_USER_CREATED;\n//\t\t\tcom_consoleLines[i] = 0;\n\t\t}\n\t}\n}\n\n\n/*\n=================\nCom_AddStartupCommands\n\nAdds command line parameters as script statements\nCommands are seperated by + signs\n\nReturns qtrue if any late commands were added, which\nwill keep the demoloop from immediately starting\n=================\n*/\nqboolean Com_AddStartupCommands( void ) {\n\tint\t\ti;\n\tqboolean\tadded;\n\n\tadded = qfalse;\n\t// quote every token, so args with semicolons can work\n\tfor (i=0 ; i < com_numConsoleLines ; i++) {\n\t\tif ( !com_consoleLines[i] || !com_consoleLines[i][0] ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// set commands won't override menu startup\n\t\tif ( Q_stricmpn( com_consoleLines[i], \"set\", 3 ) ) {\n\t\t\tadded = qtrue;\n\t\t}\n\t\tCbuf_AddText( com_consoleLines[i] );\n\t\tCbuf_AddText( \"\\n\" );\n\t}\n\n\treturn added;\n}\n\n\n//============================================================================\n\nvoid Info_Print( const char *s ) {\n\tchar\tkey[512];\n\tchar\tvalue[512];\n\tchar\t*o;\n\tint\t\tl;\n\n\tif (*s == '\\\\')\n\t\ts++;\n\twhile (*s)\n\t{\n\t\to = key;\n\t\twhile (*s && *s != '\\\\')\n\t\t\t*o++ = *s++;\n\n\t\tl = o - key;\n\t\tif (l < 20)\n\t\t{\n\t\t\tCom_Memset (o, ' ', 20-l);\n\t\t\tkey[20] = 0;\n\t\t}\n\t\telse\n\t\t\t*o = 0;\n\t\tCom_Printf (\"%s\", key);\n\n\t\tif (!*s)\n\t\t{\n\t\t\tCom_Printf (\"MISSING VALUE\\n\");\n\t\t\treturn;\n\t\t}\n\n\t\to = value;\n\t\ts++;\n\t\twhile (*s && *s != '\\\\')\n\t\t\t*o++ = *s++;\n\t\t*o = 0;\n\n\t\tif (*s)\n\t\t\ts++;\n\t\tCom_Printf (\"%s\\n\", value);\n\t}\n}\n\n/*\n============\nCom_StringContains\n============\n*/\nchar *Com_StringContains(char *str1, char *str2, int casesensitive) {\n\tint len, i, j;\n\n\tlen = (int)strlen(str1) - (int)strlen(str2);\n\tfor (i = 0; i <= len; i++, str1++) {\n\t\tfor (j = 0; str2[j]; j++) {\n\t\t\tif (casesensitive) {\n\t\t\t\tif (str1[j] != str2[j]) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (toupper(str1[j]) != toupper(str2[j])) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (!str2[j]) {\n\t\t\treturn str1;\n\t\t}\n\t}\n\treturn NULL;\n}\n\n/*\n============\nCom_Filter\n============\n*/\nint Com_Filter(char *filter, char *name, int casesensitive)\n{\n\tchar buf[MAX_TOKEN_CHARS];\n\tchar *ptr;\n\tint i, found;\n\n\twhile(*filter) {\n\t\tif (*filter == '*') {\n\t\t\tfilter++;\n\t\t\tfor (i = 0; *filter; i++) {\n\t\t\t\tif (*filter == '*' || *filter == '?') break;\n\t\t\t\tbuf[i] = *filter;\n\t\t\t\tfilter++;\n\t\t\t}\n\t\t\tbuf[i] = '\\0';\n\t\t\tif (strlen(buf)) {\n\t\t\t\tptr = Com_StringContains(name, buf, casesensitive);\n\t\t\t\tif (!ptr) return qfalse;\n\t\t\t\tname = ptr + (int)strlen(buf);\n\t\t\t}\n\t\t}\n\t\telse if (*filter == '?') {\n\t\t\tfilter++;\n\t\t\tname++;\n\t\t}\n\t\telse if (*filter == '[' && *(filter+1) == '[') {\n\t\t\tfilter++;\n\t\t}\n\t\telse if (*filter == '[') {\n\t\t\tfilter++;\n\t\t\tfound = qfalse;\n\t\t\twhile(*filter && !found) {\n\t\t\t\tif (*filter == ']' && *(filter+1) != ']') break;\n\t\t\t\tif (*(filter+1) == '-' && *(filter+2) && (*(filter+2) != ']' || *(filter+3) == ']')) {\n\t\t\t\t\tif (casesensitive) {\n\t\t\t\t\t\tif (*name >= *filter && *name <= *(filter+2)) found = qtrue;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tif (toupper(*name) >= toupper(*filter) &&\n\t\t\t\t\t\t\ttoupper(*name) <= toupper(*(filter+2))) found = qtrue;\n\t\t\t\t\t}\n\t\t\t\t\tfilter += 3;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif (casesensitive) {\n\t\t\t\t\t\tif (*filter == *name) found = qtrue;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tif (toupper(*filter) == toupper(*name)) found = qtrue;\n\t\t\t\t\t}\n\t\t\t\t\tfilter++;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!found) return qfalse;\n\t\t\twhile(*filter) {\n\t\t\t\tif (*filter == ']' && *(filter+1) != ']') break;\n\t\t\t\tfilter++;\n\t\t\t}\n\t\t\tfilter++;\n\t\t\tname++;\n\t\t}\n\t\telse {\n\t\t\tif (casesensitive) {\n\t\t\t\tif (*filter != *name) return qfalse;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (toupper(*filter) != toupper(*name)) return qfalse;\n\t\t\t}\n\t\t\tfilter++;\n\t\t\tname++;\n\t\t}\n\t}\n\treturn qtrue;\n}\n\n/*\n============\nCom_FilterPath\n============\n*/\nint Com_FilterPath(char *filter, char *name, int casesensitive)\n{\n\tint i;\n\tchar new_filter[MAX_QPATH];\n\tchar new_name[MAX_QPATH];\n\n\tfor (i = 0; i < MAX_QPATH-1 && filter[i]; i++) {\n\t\tif ( filter[i] == '\\\\' || filter[i] == ':' ) {\n\t\t\tnew_filter[i] = '/';\n\t\t}\n\t\telse {\n\t\t\tnew_filter[i] = filter[i];\n\t\t}\n\t}\n\tnew_filter[i] = '\\0';\n\tfor (i = 0; i < MAX_QPATH-1 && name[i]; i++) {\n\t\tif ( name[i] == '\\\\' || name[i] == ':' ) {\n\t\t\tnew_name[i] = '/';\n\t\t}\n\t\telse {\n\t\t\tnew_name[i] = name[i];\n\t\t}\n\t}\n\tnew_name[i] = '\\0';\n\treturn Com_Filter(new_filter, new_name, casesensitive);\n}\n\n/*\n============\nCom_HashKey\n============\n*/\nint Com_HashKey(char *string, int maxlen) {\n\tint register hash, i;\n\n\thash = 0;\n\tfor (i = 0; i < maxlen && string[i] != '\\0'; i++) {\n\t\thash += string[i] * (119 + i);\n\t}\n\thash = (hash ^ (hash >> 10) ^ (hash >> 20));\n\treturn hash;\n}\n\n/*\n================\nCom_RealTime\n================\n*/\nint Com_RealTime(qtime_t *qtime) {\n\ttime_t t;\n\tstruct tm *tms;\n\n\tt = time(NULL);\n\tif (!qtime)\n\t\treturn t;\n\ttms = localtime(&t);\n\tif (tms) {\n\t\tqtime->tm_sec = tms->tm_sec;\n\t\tqtime->tm_min = tms->tm_min;\n\t\tqtime->tm_hour = tms->tm_hour;\n\t\tqtime->tm_mday = tms->tm_mday;\n\t\tqtime->tm_mon = tms->tm_mon;\n\t\tqtime->tm_year = tms->tm_year;\n\t\tqtime->tm_wday = tms->tm_wday;\n\t\tqtime->tm_yday = tms->tm_yday;\n\t\tqtime->tm_isdst = tms->tm_isdst;\n\t}\n\treturn t;\n}\n\n\n/*\n==============================================================================\n\n\t\t\t\t\t\tZONE MEMORY ALLOCATION\n\nThere is never any space between memblocks, and there will never be two\ncontiguous free memblocks.\n\nThe rover can be left pointing at a non-empty block\n\nThe zone calls are pretty much only used for small strings and structures,\nall big things are allocated on the hunk.\n==============================================================================\n*/\n\n#define\tZONEID\t0x1d4a11\n#define MINFRAGMENT\t64\n\ntypedef struct zonedebug_s {\n\tchar *label;\n\tchar *file;\n\tint line;\n\tint allocSize;\n} zonedebug_t;\n\ntypedef struct memblock_s {\n\tint\t\tsize;           // including the header and possibly tiny fragments\n\tint     tag;            // a tag of 0 is a free block\n\tstruct memblock_s       *next, *prev;\n\tint     id;        \t\t// should be ZONEID\n#ifdef ZONE_DEBUG\n\tzonedebug_t d;\n#endif\n} memblock_t;\n\ntypedef struct {\n\tint\t\tsize;\t\t\t// total bytes malloced, including header\n\tint\t\tused;\t\t\t// total bytes used\n\tmemblock_t\tblocklist;\t// start / end cap for linked list\n\tmemblock_t\t*rover;\n} memzone_t;\n\n// main zone for all \"dynamic\" memory allocation\nmemzone_t\t*mainzone;\n// we also have a small zone for small allocations that would only\n// fragment the main zone (think of cvar and cmd strings)\nmemzone_t\t*smallzone;\n\nvoid Z_CheckHeap( void );\n\n/*\n========================\nZ_ClearZone\n========================\n*/\nvoid Z_ClearZone( memzone_t *zone, int size ) {\n\tmemblock_t\t*block;\n\t\n\t// set the entire zone to one free block\n\n\tzone->blocklist.next = zone->blocklist.prev = block =\n\t\t(memblock_t *)( (byte *)zone + sizeof(memzone_t) );\n\tzone->blocklist.tag = 1;\t// in use block\n\tzone->blocklist.id = 0;\n\tzone->blocklist.size = 0;\n\tzone->rover = block;\n\tzone->size = size;\n\tzone->used = 0;\n\t\n\tblock->prev = block->next = &zone->blocklist;\n\tblock->tag = 0;\t\t\t// free block\n\tblock->id = ZONEID;\n\tblock->size = size - sizeof(memzone_t);\n}\n\n/*\n========================\nZ_AvailableZoneMemory\n========================\n*/\nint Z_AvailableZoneMemory( memzone_t *zone ) {\n\treturn zone->size - zone->used;\n}\n\n/*\n========================\nZ_AvailableMemory\n========================\n*/\nint Z_AvailableMemory( void ) {\n\treturn Z_AvailableZoneMemory( mainzone );\n}\n\n/*\n========================\nZ_Free\n========================\n*/\nvoid Z_Free( void *ptr ) {\n\tmemblock_t\t*block, *other;\n\tmemzone_t *zone;\n\t\n\tif (!ptr) {\n\t\tCom_Error( ERR_DROP, \"Z_Free: NULL pointer\" );\n\t}\n\n\tblock = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));\n\tif (block->id != ZONEID) {\n\t\tCom_Error( ERR_FATAL, \"Z_Free: freed a pointer without ZONEID\" );\n\t}\n\tif (block->tag == 0) {\n\t\tCom_Error( ERR_FATAL, \"Z_Free: freed a freed pointer\" );\n\t}\n\t// if static memory\n\tif (block->tag == TAG_STATIC) {\n\t\treturn;\n\t}\n\n\t// check the memory trash tester\n\tif ( *(int *)((byte *)block + block->size - 4 ) != ZONEID ) {\n\t\tCom_Error( ERR_FATAL, \"Z_Free: memory block wrote past end\" );\n\t}\n\n\tif (block->tag == TAG_SMALL) {\n\t\tzone = smallzone;\n\t}\n\telse {\n\t\tzone = mainzone;\n\t}\n\n\tzone->used -= block->size;\n\t// set the block to something that should cause problems\n\t// if it is referenced...\n\tCom_Memset( ptr, 0xaa, block->size - sizeof( *block ) );\n\n\tblock->tag = 0;\t\t// mark as free\n\t\n\tother = block->prev;\n\tif (!other->tag) {\n\t\t// merge with previous free block\n\t\tother->size += block->size;\n\t\tother->next = block->next;\n\t\tother->next->prev = other;\n\t\tif (block == zone->rover) {\n\t\t\tzone->rover = other;\n\t\t}\n\t\tblock = other;\n\t}\n\n\tzone->rover = block;\n\n\tother = block->next;\n\tif ( !other->tag ) {\n\t\t// merge the next free block onto the end\n\t\tblock->size += other->size;\n\t\tblock->next = other->next;\n\t\tblock->next->prev = block;\n\t\tif (other == zone->rover) {\n\t\t\tzone->rover = block;\n\t\t}\n\t}\n}\n\n\n/*\n================\nZ_FreeTags\n================\n*/\nvoid Z_FreeTags( int tag ) {\n\tint\t\t\tcount;\n\tmemzone_t\t*zone;\n\n\tif ( tag == TAG_SMALL ) {\n\t\tzone = smallzone;\n\t}\n\telse {\n\t\tzone = mainzone;\n\t}\n\tcount = 0;\n\t// use the rover as our pointer, because\n\t// Z_Free automatically adjusts it\n\tzone->rover = zone->blocklist.next;\n\tdo {\n\t\tif ( zone->rover->tag == tag ) {\n\t\t\tcount++;\n\t\t\tZ_Free( (void *)(zone->rover + 1) );\n\t\t\tcontinue;\n\t\t}\n\t\tzone->rover = zone->rover->next;\n\t} while ( zone->rover != &zone->blocklist );\n}\n\n\n/*\n================\nZ_TagMalloc\n================\n*/\n#ifdef ZONE_DEBUG\nvoid *Z_TagMallocDebug( int size, int tag, char *label, char *file, int line ) {\n#else\nvoid *Z_TagMalloc( int size, int tag ) {\n#endif\n\tint\t\textra, allocSize;\n\tmemblock_t\t*start, *rover, *newBlock, *base;\n\tmemzone_t *zone;\n\n\tif (!tag) {\n\t\tCom_Error( ERR_FATAL, \"Z_TagMalloc: tried to use a 0 tag\" );\n\t}\n\n\tif ( tag == TAG_SMALL ) {\n\t\tzone = smallzone;\n\t}\n\telse {\n\t\tzone = mainzone;\n\t}\n\n\tallocSize = size;\n\t//\n\t// scan through the block list looking for the first free block\n\t// of sufficient size\n\t//\n\tsize += sizeof(memblock_t);\t// account for size of block header\n\tsize += 4;\t\t\t\t\t// space for memory trash tester\n\tsize = (size + 3) & ~3;\t\t// align to 32 bit boundary\n\t\n\tbase = rover = zone->rover;\n\tstart = base->prev;\n\t\n\tdo {\n\t\tif (rover == start)\t{\n#ifdef ZONE_DEBUG\n\t\t\tZ_LogHeap();\n#endif\n\t\t\t// scaned all the way around the list\n\t\t\tCom_Error( ERR_FATAL, \"Z_Malloc: failed on allocation of %i bytes from the %s zone\",\n\t\t\t\t\t\t\t\tsize, zone == smallzone ? \"small\" : \"main\");\n\t\t\treturn NULL;\n\t\t}\n\t\tif (rover->tag) {\n\t\t\tbase = rover = rover->next;\n\t\t} else {\n\t\t\trover = rover->next;\n\t\t}\n\t} while (base->tag || base->size < size);\n\t\n\t//\n\t// found a block big enough\n\t//\n\textra = base->size - size;\n\tif (extra > MINFRAGMENT) {\n\t\t// there will be a free fragment after the allocated block\n\t\tnewBlock = (memblock_t *)((byte *)base + size);\n\t\tnewBlock->size = extra;\n\t\tnewBlock->tag = 0;\t\t\t// free block\n\t\tnewBlock->prev = base;\n\t\tnewBlock->id = ZONEID;\n\t\tnewBlock->next = base->next;\n\t\tnewBlock->next->prev = newBlock;\n\t\tbase->next = newBlock;\n\t\tbase->size = size;\n\t}\n\t\n\tbase->tag = tag;\t\t\t// no longer a free block\n\t\n\tzone->rover = base->next;\t// next allocation will start looking here\n\tzone->used += base->size;\t//\n\t\n\tbase->id = ZONEID;\n\n#ifdef ZONE_DEBUG\n\tbase->d.label = label;\n\tbase->d.file = file;\n\tbase->d.line = line;\n\tbase->d.allocSize = allocSize;\n#endif\n\n\t// marker for memory trash testing\n\t*(int *)((byte *)base + base->size - 4) = ZONEID;\n\n\treturn (void *) ((byte *)base + sizeof(memblock_t));\n}\n\n/*\n========================\nZ_Malloc\n========================\n*/\n#ifdef ZONE_DEBUG\nvoid *Z_MallocDebug( int size, char *label, char *file, int line ) {\n#else\nvoid *Z_Malloc( int size ) {\n#endif\n\tvoid\t*buf;\n\t\n  //Z_CheckHeap ();\t// DEBUG\n\n#ifdef ZONE_DEBUG\n\tbuf = Z_TagMallocDebug( size, TAG_GENERAL, label, file, line );\n#else\n\tbuf = Z_TagMalloc( size, TAG_GENERAL );\n#endif\n\tCom_Memset( buf, 0, size );\n\n\treturn buf;\n}\n\n#ifdef ZONE_DEBUG\nvoid *S_MallocDebug( int size, char *label, char *file, int line ) {\n\treturn Z_TagMallocDebug( size, TAG_SMALL, label, file, line );\n}\n#else\nvoid *S_Malloc( int size ) {\n\treturn Z_TagMalloc( size, TAG_SMALL );\n}\n#endif\n\n/*\n========================\nZ_CheckHeap\n========================\n*/\nvoid Z_CheckHeap( void ) {\n\tmemblock_t\t*block;\n\t\n\tfor (block = mainzone->blocklist.next ; ; block = block->next) {\n\t\tif (block->next == &mainzone->blocklist) {\n\t\t\tbreak;\t\t\t// all blocks have been hit\n\t\t}\n\t\tif ( (byte *)block + block->size != (byte *)block->next)\n\t\t\tCom_Error( ERR_FATAL, \"Z_CheckHeap: block size does not touch the next block\\n\" );\n\t\tif ( block->next->prev != block) {\n\t\t\tCom_Error( ERR_FATAL, \"Z_CheckHeap: next block doesn't have proper back link\\n\" );\n\t\t}\n\t\tif ( !block->tag && !block->next->tag ) {\n\t\t\tCom_Error( ERR_FATAL, \"Z_CheckHeap: two consecutive free blocks\\n\" );\n\t\t}\n\t}\n}\n\n/*\n========================\nZ_LogZoneHeap\n========================\n*/\nvoid Z_LogZoneHeap( memzone_t *zone, char *name ) {\n#ifdef ZONE_DEBUG\n\tchar dump[32], *ptr;\n\tint  i, j;\n#endif\n\tmemblock_t\t*block;\n\tchar\t\tbuf[4096];\n\tint size, allocSize, numBlocks;\n\n\tif (!logfile || !FS_Initialized())\n\t\treturn;\n\tsize = allocSize = numBlocks = 0;\n\tCom_sprintf(buf, sizeof(buf), \"\\r\\n================\\r\\n%s log\\r\\n================\\r\\n\", name);\n\tFS_Write(buf, (int)strlen(buf), logfile);\n\tfor (block = zone->blocklist.next ; block->next != &zone->blocklist; block = block->next) {\n\t\tif (block->tag) {\n#ifdef ZONE_DEBUG\n\t\t\tptr = ((char *) block) + sizeof(memblock_t);\n\t\t\tj = 0;\n\t\t\tfor (i = 0; i < 20 && i < block->d.allocSize; i++) {\n\t\t\t\tif (ptr[i] >= 32 && ptr[i] < 127) {\n\t\t\t\t\tdump[j++] = ptr[i];\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tdump[j++] = '_';\n\t\t\t\t}\n\t\t\t}\n\t\t\tdump[j] = '\\0';\n\t\t\tCom_sprintf(buf, sizeof(buf), \"size = %8d: %s, line: %d (%s) [%s]\\r\\n\", block->d.allocSize, block->d.file, block->d.line, block->d.label, dump);\n\t\t\tFS_Write(buf, (int)strlen(buf), logfile);\n\t\t\tallocSize += block->d.allocSize;\n#endif\n\t\t\tsize += block->size;\n\t\t\tnumBlocks++;\n\t\t}\n\t}\n#ifdef ZONE_DEBUG\n\t// subtract debug memory\n\tsize -= numBlocks * sizeof(zonedebug_t);\n#else\n\tallocSize = numBlocks * sizeof(memblock_t); // + 32 bit alignment\n#endif\n\tCom_sprintf(buf, sizeof(buf), \"%d %s memory in %d blocks\\r\\n\", size, name, numBlocks);\n\tFS_Write(buf, (int)strlen(buf), logfile);\n\tCom_sprintf(buf, sizeof(buf), \"%d %s memory overhead\\r\\n\", size - allocSize, name);\n\tFS_Write(buf, (int)strlen(buf), logfile);\n}\n\n/*\n========================\nZ_LogHeap\n========================\n*/\nvoid Z_LogHeap( void ) {\n\tZ_LogZoneHeap( mainzone, \"MAIN\" );\n\tZ_LogZoneHeap( smallzone, \"SMALL\" );\n}\n\n// static mem blocks to reduce a lot of small zone overhead\ntypedef struct memstatic_s {\n\tmemblock_t b;\n\tbyte mem[2];\n} memstatic_t;\n\n// bk001204 - initializer brackets\nmemstatic_t emptystring =\n\t{ {(sizeof(memblock_t)+2 + 3) & ~3, TAG_STATIC, NULL, NULL, ZONEID}, {'\\0', '\\0'} };\nmemstatic_t numberstring[] = {\n\t{ {(sizeof(memstatic_t) + 3) & ~3, TAG_STATIC, NULL, NULL, ZONEID}, {'0', '\\0'} },\n\t{ {(sizeof(memstatic_t) + 3) & ~3, TAG_STATIC, NULL, NULL, ZONEID}, {'1', '\\0'} },\n\t{ {(sizeof(memstatic_t) + 3) & ~3, TAG_STATIC, NULL, NULL, ZONEID}, {'2', '\\0'} },\n\t{ {(sizeof(memstatic_t) + 3) & ~3, TAG_STATIC, NULL, NULL, ZONEID}, {'3', '\\0'} },\n\t{ {(sizeof(memstatic_t) + 3) & ~3, TAG_STATIC, NULL, NULL, ZONEID}, {'4', '\\0'} },\n\t{ {(sizeof(memstatic_t) + 3) & ~3, TAG_STATIC, NULL, NULL, ZONEID}, {'5', '\\0'} },\n\t{ {(sizeof(memstatic_t) + 3) & ~3, TAG_STATIC, NULL, NULL, ZONEID}, {'6', '\\0'} },\n\t{ {(sizeof(memstatic_t) + 3) & ~3, TAG_STATIC, NULL, NULL, ZONEID}, {'7', '\\0'} },\n\t{ {(sizeof(memstatic_t) + 3) & ~3, TAG_STATIC, NULL, NULL, ZONEID}, {'8', '\\0'} }, \n\t{ {(sizeof(memstatic_t) + 3) & ~3, TAG_STATIC, NULL, NULL, ZONEID}, {'9', '\\0'} }\n};\n\n/*\n========================\nCopyString\n\n NOTE:\tnever write over the memory CopyString returns because\n\t\tmemory from a memstatic_t might be returned\n========================\n*/\nchar *CopyString( const char *in ) {\n\tchar\t*out;\n\n\tif (!in[0]) {\n\t\treturn ((char *)&emptystring) + sizeof(memblock_t);\n\t}\n\telse if (!in[1]) {\n\t\tif (in[0] >= '0' && in[0] <= '9') {\n\t\t\treturn ((char *)&numberstring[in[0]-'0']) + sizeof(memblock_t);\n\t\t}\n\t}\n\tout = (char*) S_Malloc ((int)strlen(in)+1);\n\tstrcpy (out, in);\n\treturn out;\n}\n\n/*\n==============================================================================\n\nGoals:\n\treproducable without history effects -- no out of memory errors on weird map to map changes\n\tallow restarting of the client without fragmentation\n\tminimize total pages in use at run time\n\tminimize total pages needed during load time\n\n  Single block of memory with stack allocators coming from both ends towards the middle.\n\n  One side is designated the temporary memory allocator.\n\n  Temporary memory can be allocated and freed in any order.\n\n  A highwater mark is kept of the most in use at any time.\n\n  When there is no temporary memory allocated, the permanent and temp sides\n  can be switched, allowing the already touched temp memory to be used for\n  permanent storage.\n\n  Temp memory must never be allocated on two ends at once, or fragmentation\n  could occur.\n\n  If we have any in-use temp memory, additional temp allocations must come from\n  that side.\n\n  If not, we can choose to make either side the new temp side and push future\n  permanent allocations to the other side.  Permanent allocations should be\n  kept on the side that has the current greatest wasted highwater mark.\n\n==============================================================================\n*/\n\n\n#define\tHUNK_MAGIC\t0x89537892\n#define\tHUNK_FREE_MAGIC\t0x89537893\n\ntypedef struct {\n\tint\t\tmagic;\n\tint\t\tsize;\n} hunkHeader_t;\n\ntypedef struct {\n\tint\t\tmark;\n\tint\t\tpermanent;\n\tint\t\ttemp;\n\tint\t\ttempHighwater;\n} hunkUsed_t;\n\ntypedef struct hunkblock_s {\n\tint size;\n\tbyte printed;\n\tstruct hunkblock_s *next;\n\tchar *label;\n\tchar *file;\n\tint line;\n} hunkblock_t;\n\nstatic\thunkblock_t *hunkblocks;\n\nstatic\thunkUsed_t\thunk_low, hunk_high;\nstatic\thunkUsed_t\t*hunk_permanent, *hunk_temp;\n\nstatic\tbyte\t*s_hunkData = NULL;\nstatic\tint\t\ts_hunkTotal;\n\nstatic\tint\t\ts_zoneTotal;\nstatic\tint\t\ts_smallZoneTotal;\n\n\n/*\n=================\nCom_Meminfo_f\n=================\n*/\nvoid Com_Meminfo_f( void ) {\n\tmemblock_t\t*block;\n\tint\t\t\tzoneBytes, zoneBlocks;\n\tint\t\t\tsmallZoneBytes, smallZoneBlocks;\n\tint\t\t\tbotlibBytes, rendererBytes;\n\tint\t\t\tunused;\n\n\tzoneBytes = 0;\n\tbotlibBytes = 0;\n\trendererBytes = 0;\n\tzoneBlocks = 0;\n\tfor (block = mainzone->blocklist.next ; ; block = block->next) {\n\t\tif ( Cmd_Argc() != 1 ) {\n\t\t\tCom_Printf (\"block:%p    size:%7i    tag:%3i\\n\",\n\t\t\t\tblock, block->size, block->tag);\n\t\t}\n\t\tif ( block->tag ) {\n\t\t\tzoneBytes += block->size;\n\t\t\tzoneBlocks++;\n\t\t\tif ( block->tag == TAG_BOTLIB ) {\n\t\t\t\tbotlibBytes += block->size;\n\t\t\t} else if ( block->tag == TAG_RENDERER ) {\n\t\t\t\trendererBytes += block->size;\n\t\t\t}\n\t\t}\n\n\t\tif (block->next == &mainzone->blocklist) {\n\t\t\tbreak;\t\t\t// all blocks have been hit\t\n\t\t}\n\t\tif ( (byte *)block + block->size != (byte *)block->next) {\n\t\t\tCom_Printf (\"ERROR: block size does not touch the next block\\n\");\n\t\t}\n\t\tif ( block->next->prev != block) {\n\t\t\tCom_Printf (\"ERROR: next block doesn't have proper back link\\n\");\n\t\t}\n\t\tif ( !block->tag && !block->next->tag ) {\n\t\t\tCom_Printf (\"ERROR: two consecutive free blocks\\n\");\n\t\t}\n\t}\n\n\tsmallZoneBytes = 0;\n\tsmallZoneBlocks = 0;\n\tfor (block = smallzone->blocklist.next ; ; block = block->next) {\n\t\tif ( block->tag ) {\n\t\t\tsmallZoneBytes += block->size;\n\t\t\tsmallZoneBlocks++;\n\t\t}\n\n\t\tif (block->next == &smallzone->blocklist) {\n\t\t\tbreak;\t\t\t// all blocks have been hit\t\n\t\t}\n\t}\n\n\tCom_Printf( \"%8i bytes total hunk\\n\", s_hunkTotal );\n\tCom_Printf( \"%8i bytes total zone\\n\", s_zoneTotal );\n\tCom_Printf( \"\\n\" );\n\tCom_Printf( \"%8i low mark\\n\", hunk_low.mark );\n\tCom_Printf( \"%8i low permanent\\n\", hunk_low.permanent );\n\tif ( hunk_low.temp != hunk_low.permanent ) {\n\t\tCom_Printf( \"%8i low temp\\n\", hunk_low.temp );\n\t}\n\tCom_Printf( \"%8i low tempHighwater\\n\", hunk_low.tempHighwater );\n\tCom_Printf( \"\\n\" );\n\tCom_Printf( \"%8i high mark\\n\", hunk_high.mark );\n\tCom_Printf( \"%8i high permanent\\n\", hunk_high.permanent );\n\tif ( hunk_high.temp != hunk_high.permanent ) {\n\t\tCom_Printf( \"%8i high temp\\n\", hunk_high.temp );\n\t}\n\tCom_Printf( \"%8i high tempHighwater\\n\", hunk_high.tempHighwater );\n\tCom_Printf( \"\\n\" );\n\tCom_Printf( \"%8i total hunk in use\\n\", hunk_low.permanent + hunk_high.permanent );\n\tunused = 0;\n\tif ( hunk_low.tempHighwater > hunk_low.permanent ) {\n\t\tunused += hunk_low.tempHighwater - hunk_low.permanent;\n\t}\n\tif ( hunk_high.tempHighwater > hunk_high.permanent ) {\n\t\tunused += hunk_high.tempHighwater - hunk_high.permanent;\n\t}\n\tCom_Printf( \"%8i unused highwater\\n\", unused );\n\tCom_Printf( \"\\n\" );\n\tCom_Printf( \"%8i bytes in %i zone blocks\\n\", zoneBytes, zoneBlocks\t);\n\tCom_Printf( \"        %8i bytes in dynamic botlib\\n\", botlibBytes );\n\tCom_Printf( \"        %8i bytes in dynamic renderer\\n\", rendererBytes );\n\tCom_Printf( \"        %8i bytes in dynamic other\\n\", zoneBytes - ( botlibBytes + rendererBytes ) );\n\tCom_Printf( \"        %8i bytes in small Zone memory\\n\", smallZoneBytes );\n}\n\n/*\n===============\nCom_TouchMemory\n\nTouch all known used data to make sure it is paged in\n===============\n*/\nvoid Com_TouchMemory( void ) {\n\tint\t\tstart, end;\n\tint\t\ti, j;\n\tint\t\tsum;\n\tmemblock_t\t*block;\n\n\tZ_CheckHeap();\n\n\tstart = Sys_Milliseconds();\n\n\tsum = 0;\n\n\tj = hunk_low.permanent >> 2;\n\tfor ( i = 0 ; i < j ; i+=64 ) {\t\t\t// only need to touch each page\n\t\tsum += ((int *)s_hunkData)[i];\n\t}\n\n\ti = ( s_hunkTotal - hunk_high.permanent ) >> 2;\n\tj = hunk_high.permanent >> 2;\n\tfor (  ; i < j ; i+=64 ) {\t\t\t// only need to touch each page\n\t\tsum += ((int *)s_hunkData)[i];\n\t}\n\n\tfor (block = mainzone->blocklist.next ; ; block = block->next) {\n\t\tif ( block->tag ) {\n\t\t\tj = block->size >> 2;\n\t\t\tfor ( i = 0 ; i < j ; i+=64 ) {\t\t\t\t// only need to touch each page\n\t\t\t\tsum += ((int *)block)[i];\n\t\t\t}\n\t\t}\n\t\tif ( block->next == &mainzone->blocklist ) {\n\t\t\tbreak;\t\t\t// all blocks have been hit\t\n\t\t}\n\t}\n\n\tend = Sys_Milliseconds();\n\n\tCom_Printf( \"Com_TouchMemory: %i msec\\n\", end - start );\n}\n\n\n\n/*\n=================\nCom_InitZoneMemory\n=================\n*/\nvoid Com_InitSmallZoneMemory( void ) {\n\ts_smallZoneTotal = 512 * 1024;\n\t// bk001205 - was malloc\n\tsmallzone = (memzone_t*) calloc( s_smallZoneTotal, 1 );\n\tif ( !smallzone ) {\n\t\tCom_Error( ERR_FATAL, \"Small zone data failed to allocate %1.1f megs\", (float)s_smallZoneTotal / (1024*1024) );\n\t}\n\tZ_ClearZone( smallzone, s_smallZoneTotal );\n\t\n\treturn;\n}\n\nvoid Com_InitZoneMemory( void ) {\n\tcvar_t\t*cv;\n\t// allocate the random block zone\n\tcv = Cvar_Get( \"com_zoneMegs\", DEF_COMZONEMEGS, CVAR_LATCH | CVAR_ARCHIVE );\n\n\tif ( cv->integer < 20 ) {\n\t\ts_zoneTotal = 1024 * 1024 * 16;\n\t} else {\n\t\ts_zoneTotal = cv->integer * 1024 * 1024;\n\t}\n\n\t// bk001205 - was malloc\n\tmainzone = (memzone_t*) calloc( s_zoneTotal, 1 );\n\tif ( !mainzone ) {\n\t\tCom_Error( ERR_FATAL, \"Zone data failed to allocate %i megs\", s_zoneTotal / (1024*1024) );\n\t}\n\tZ_ClearZone( mainzone, s_zoneTotal );\n\n}\n\n/*\n=================\nHunk_Log\n=================\n*/\nvoid Hunk_Log( void) {\n\thunkblock_t\t*block;\n\tchar\t\tbuf[4096];\n\tint size, numBlocks;\n\n\tif (!logfile || !FS_Initialized())\n\t\treturn;\n\tsize = 0;\n\tnumBlocks = 0;\n\tCom_sprintf(buf, sizeof(buf), \"\\r\\n================\\r\\nHunk log\\r\\n================\\r\\n\");\n\tFS_Write(buf, (int)strlen(buf), logfile);\n\tfor (block = hunkblocks ; block; block = block->next) {\n#ifdef HUNK_DEBUG\n\t\tCom_sprintf(buf, sizeof(buf), \"size = %8d: %s, line: %d (%s)\\r\\n\", block->size, block->file, block->line, block->label);\n\t\tFS_Write(buf, (int)strlen(buf), logfile);\n#endif\n\t\tsize += block->size;\n\t\tnumBlocks++;\n\t}\n\tCom_sprintf(buf, sizeof(buf), \"%d Hunk memory\\r\\n\", size);\n\tFS_Write(buf, (int)strlen(buf), logfile);\n\tCom_sprintf(buf, sizeof(buf), \"%d hunk blocks\\r\\n\", numBlocks);\n\tFS_Write(buf, (int)strlen(buf), logfile);\n}\n\n/*\n=================\nHunk_SmallLog\n=================\n*/\nvoid Hunk_SmallLog( void) {\n\thunkblock_t\t*block, *block2;\n\tchar\t\tbuf[4096];\n\tint size, locsize, numBlocks;\n\n\tif (!logfile || !FS_Initialized())\n\t\treturn;\n\tfor (block = hunkblocks ; block; block = block->next) {\n\t\tblock->printed = qfalse;\n\t}\n\tsize = 0;\n\tnumBlocks = 0;\n\tCom_sprintf(buf, sizeof(buf), \"\\r\\n================\\r\\nHunk Small log\\r\\n================\\r\\n\");\n\tFS_Write(buf, (int)strlen(buf), logfile);\n\tfor (block = hunkblocks; block; block = block->next) {\n\t\tif (block->printed) {\n\t\t\tcontinue;\n\t\t}\n\t\tlocsize = block->size;\n\t\tfor (block2 = block->next; block2; block2 = block2->next) {\n\t\t\tif (block->line != block2->line) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (Q_stricmp(block->file, block2->file)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tsize += block2->size;\n\t\t\tlocsize += block2->size;\n\t\t\tblock2->printed = qtrue;\n\t\t}\n#ifdef HUNK_DEBUG\n\t\tCom_sprintf(buf, sizeof(buf), \"size = %8d: %s, line: %d (%s)\\r\\n\", locsize, block->file, block->line, block->label);\n\t\tFS_Write(buf, (int)strlen(buf), logfile);\n#endif\n\t\tsize += block->size;\n\t\tnumBlocks++;\n\t}\n\tCom_sprintf(buf, sizeof(buf), \"%d Hunk memory\\r\\n\", size);\n\tFS_Write(buf, (int)strlen(buf), logfile);\n\tCom_sprintf(buf, sizeof(buf), \"%d hunk blocks\\r\\n\", numBlocks);\n\tFS_Write(buf, (int)strlen(buf), logfile);\n}\n\n/*\n=================\nCom_InitZoneMemory\n=================\n*/\nvoid Com_InitHunkMemory( void ) {\n\tcvar_t\t*cv;\n\tint nMinAlloc;\n\tchar *pMsg = NULL;\n\n\t// make sure the file system has allocated and \"not\" freed any temp blocks\n\t// this allows the config and product id files ( journal files too ) to be loaded\n\t// by the file system without redunant routines in the file system utilizing different \n\t// memory systems\n\tif (FS_LoadStack() != 0) {\n\t\tCom_Error( ERR_FATAL, \"Hunk initialization failed. File system load stack not zero\");\n\t}\n\n\t// allocate the stack based hunk allocator\n\tcv = Cvar_Get( \"com_hunkMegs\", DEF_COMHUNKMEGS, CVAR_LATCH | CVAR_ARCHIVE );\n\n\t// if we are not dedicated min allocation is 56, otherwise min is 1\n\tif (com_dedicated && com_dedicated->integer) {\n\t\tnMinAlloc = MIN_DEDICATED_COMHUNKMEGS;\n\t\tpMsg = \"Minimum com_hunkMegs for a dedicated server is %i, allocating %i megs.\\n\";\n\t}\n\telse {\n\t\tnMinAlloc = MIN_COMHUNKMEGS;\n\t\tpMsg = \"Minimum com_hunkMegs is %i, allocating %i megs.\\n\";\n\t}\n\n\tif ( cv->integer < nMinAlloc ) {\n\t\ts_hunkTotal = 1024 * 1024 * nMinAlloc;\n\t    Com_Printf(pMsg, nMinAlloc, s_hunkTotal / (1024 * 1024));\n\t} else {\n\t\ts_hunkTotal = cv->integer * 1024 * 1024;\n\t}\n\n\n\t// bk001205 - was malloc\n\ts_hunkData = (byte*) calloc( s_hunkTotal + 31, 1 );\n\tif ( !s_hunkData ) {\n\t\tCom_Error( ERR_FATAL, \"Hunk data failed to allocate %i megs\", s_hunkTotal / (1024*1024) );\n\t}\n\t// cacheline align\n\ts_hunkData = (byte *) ( ( (intptr_t)s_hunkData + 31 ) & ~31 );\n\tHunk_Clear();\n\n\tCmd_AddCommand( \"meminfo\", Com_Meminfo_f );\n#ifdef ZONE_DEBUG\n\tCmd_AddCommand( \"zonelog\", Z_LogHeap );\n#endif\n#ifdef HUNK_DEBUG\n\tCmd_AddCommand( \"hunklog\", Hunk_Log );\n\tCmd_AddCommand( \"hunksmalllog\", Hunk_SmallLog );\n#endif\n}\n\n/*\n====================\nHunk_MemoryRemaining\n====================\n*/\nint\tHunk_MemoryRemaining( void ) {\n\tint\t\tlow, high;\n\n\tlow = hunk_low.permanent > hunk_low.temp ? hunk_low.permanent : hunk_low.temp;\n\thigh = hunk_high.permanent > hunk_high.temp ? hunk_high.permanent : hunk_high.temp;\n\n\treturn s_hunkTotal - ( low + high );\n}\n\n/*\n===================\nHunk_SetMark\n\nThe server calls this after the level and game VM have been loaded\n===================\n*/\nvoid Hunk_SetMark( void ) {\n\thunk_low.mark = hunk_low.permanent;\n\thunk_high.mark = hunk_high.permanent;\n}\n\n/*\n=================\nHunk_ClearToMark\n\nThe client calls this before starting a vid_restart or snd_restart\n=================\n*/\nvoid Hunk_ClearToMark( void ) {\n\thunk_low.permanent = hunk_low.temp = hunk_low.mark;\n\thunk_high.permanent = hunk_high.temp = hunk_high.mark;\n}\n\n/*\n=================\nHunk_CheckMark\n=================\n*/\nqboolean Hunk_CheckMark( void ) {\n\tif( hunk_low.mark || hunk_high.mark ) {\n\t\treturn qtrue;\n\t}\n\treturn qfalse;\n}\n\nvoid CL_ShutdownCGame( void );\nvoid CL_ShutdownUI( void );\nvoid SV_ShutdownGameProgs( void );\n\n/*\n=================\nHunk_Clear\n\nThe server calls this before shutting down or loading a new map\n=================\n*/\nvoid Hunk_Clear( void ) {\n\n#ifndef DEDICATED\n\tCL_ShutdownCGame();\n\tCL_ShutdownUI();\n#endif\n\tSV_ShutdownGameProgs();\n#ifndef DEDICATED\n\tCIN_CloseAllVideos();\n#endif\n\thunk_low.mark = 0;\n\thunk_low.permanent = 0;\n\thunk_low.temp = 0;\n\thunk_low.tempHighwater = 0;\n\n\thunk_high.mark = 0;\n\thunk_high.permanent = 0;\n\thunk_high.temp = 0;\n\thunk_high.tempHighwater = 0;\n\n\thunk_permanent = &hunk_low;\n\thunk_temp = &hunk_high;\n\n\tCom_Printf( \"Hunk_Clear: reset the hunk ok\\n\" );\n\tVM_Clear();\n#ifdef HUNK_DEBUG\n\thunkblocks = NULL;\n#endif\n}\n\nstatic void Hunk_SwapBanks( void ) {\n\thunkUsed_t\t*swap;\n\n\t// can't swap banks if there is any temp already allocated\n\tif ( hunk_temp->temp != hunk_temp->permanent ) {\n\t\treturn;\n\t}\n\n\t// if we have a larger highwater mark on this side, start making\n\t// our permanent allocations here and use the other side for temp\n\tif ( hunk_temp->tempHighwater - hunk_temp->permanent >\n\t\thunk_permanent->tempHighwater - hunk_permanent->permanent ) {\n\t\tswap = hunk_temp;\n\t\thunk_temp = hunk_permanent;\n\t\thunk_permanent = swap;\n\t}\n}\n\n/*\n=================\nHunk_Alloc\n\nAllocate permanent (until the hunk is cleared) memory\n=================\n*/\n#ifdef HUNK_DEBUG\nvoid *Hunk_AllocDebug( int size, ha_pref preference, char *label, char *file, int line ) {\n#else\nvoid *Hunk_Alloc( int size, ha_pref preference ) {\n#endif\n\tvoid\t*buf;\n\n\tif ( s_hunkData == NULL)\n\t{\n\t\tCom_Error( ERR_FATAL, \"Hunk_Alloc: Hunk memory system not initialized\" );\n\t}\n\n\t// can't do preference if there is any temp allocated\n\tif (preference == h_dontcare || hunk_temp->temp != hunk_temp->permanent) {\n\t\tHunk_SwapBanks();\n\t} else {\n\t\tif (preference == h_low && hunk_permanent != &hunk_low) {\n\t\t\tHunk_SwapBanks();\n\t\t} else if (preference == h_high && hunk_permanent != &hunk_high) {\n\t\t\tHunk_SwapBanks();\n\t\t}\n\t}\n\n#ifdef HUNK_DEBUG\n\tsize += sizeof(hunkblock_t);\n#endif\n\n\t// round to cacheline\n\tsize = (size+31)&~31;\n\n\tif ( hunk_low.temp + hunk_high.temp + size > s_hunkTotal ) {\n#ifdef HUNK_DEBUG\n\t\tHunk_Log();\n\t\tHunk_SmallLog();\n#endif\n\t\tCom_Error( ERR_DROP, \"Hunk_Alloc failed on %i\", size );\n\t}\n\n\tif ( hunk_permanent == &hunk_low ) {\n\t\tbuf = (void *)(s_hunkData + hunk_permanent->permanent);\n\t\thunk_permanent->permanent += size;\n\t} else {\n\t\thunk_permanent->permanent += size;\n\t\tbuf = (void *)(s_hunkData + s_hunkTotal - hunk_permanent->permanent );\n\t}\n\n\thunk_permanent->temp = hunk_permanent->permanent;\n\n\tCom_Memset( buf, 0, size );\n\n#ifdef HUNK_DEBUG\n\t{\n\t\thunkblock_t *block;\n\n\t\tblock = (hunkblock_t *) buf;\n\t\tblock->size = size - sizeof(hunkblock_t);\n\t\tblock->file = file;\n\t\tblock->label = label;\n\t\tblock->line = line;\n\t\tblock->next = hunkblocks;\n\t\thunkblocks = block;\n\t\tbuf = ((byte *) buf) + sizeof(hunkblock_t);\n\t}\n#endif\n\treturn buf;\n}\n\n/*\n=================\nHunk_AllocateTempMemory\n\nThis is used by the file loading system.\nMultiple files can be loaded in temporary memory.\nWhen the files-in-use count reaches zero, all temp memory will be deleted\n=================\n*/\nvoid *Hunk_AllocateTempMemory( int size ) {\n\tvoid\t\t*buf;\n\thunkHeader_t\t*hdr;\n\n\t// return a Z_Malloc'd block if the hunk has not been initialized\n\t// this allows the config and product id files ( journal files too ) to be loaded\n\t// by the file system without redunant routines in the file system utilizing different \n\t// memory systems\n\tif ( s_hunkData == NULL )\n\t{\n\t\treturn Z_Malloc(size);\n\t}\n\n\tHunk_SwapBanks();\n\n\tsize = ( (size+3)&~3 ) + sizeof( hunkHeader_t );\n\n\tif ( hunk_temp->temp + hunk_permanent->permanent + size > s_hunkTotal ) {\n\t\tCom_Error( ERR_DROP, \"Hunk_AllocateTempMemory: failed on %i\", size );\n\t}\n\n\tif ( hunk_temp == &hunk_low ) {\n\t\tbuf = (void *)(s_hunkData + hunk_temp->temp);\n\t\thunk_temp->temp += size;\n\t} else {\n\t\thunk_temp->temp += size;\n\t\tbuf = (void *)(s_hunkData + s_hunkTotal - hunk_temp->temp );\n\t}\n\n\tif ( hunk_temp->temp > hunk_temp->tempHighwater ) {\n\t\thunk_temp->tempHighwater = hunk_temp->temp;\n\t}\n\n\thdr = (hunkHeader_t *)buf;\n\tbuf = (void *)(hdr+1);\n\n\thdr->magic = HUNK_MAGIC;\n\thdr->size = size;\n\n\t// don't bother clearing, because we are going to load a file over it\n\treturn buf;\n}\n\n\n/*\n==================\nHunk_FreeTempMemory\n==================\n*/\nvoid Hunk_FreeTempMemory( void *buf ) {\n\thunkHeader_t\t*hdr;\n\n\t  // free with Z_Free if the hunk has not been initialized\n\t  // this allows the config and product id files ( journal files too ) to be loaded\n\t  // by the file system without redunant routines in the file system utilizing different \n\t  // memory systems\n\tif ( s_hunkData == NULL )\n\t{\n\t\tZ_Free(buf);\n\t\treturn;\n\t}\n\n\n\thdr = ( (hunkHeader_t *)buf ) - 1;\n\tif ( hdr->magic != HUNK_MAGIC ) {\n\t\tCom_Error( ERR_FATAL, \"Hunk_FreeTempMemory: bad magic\" );\n\t}\n\n\thdr->magic = HUNK_FREE_MAGIC;\n\n\t// this only works if the files are freed in stack order,\n\t// otherwise the memory will stay around until Hunk_ClearTempMemory\n\tif ( hunk_temp == &hunk_low ) {\n\t\tif ( hdr == (void *)(s_hunkData + hunk_temp->temp - hdr->size ) ) {\n\t\t\thunk_temp->temp -= hdr->size;\n\t\t} else {\n\t\t\tCom_Printf( \"Hunk_FreeTempMemory: not the final block\\n\" );\n\t\t}\n\t} else {\n\t\tif ( hdr == (void *)(s_hunkData + s_hunkTotal - hunk_temp->temp ) ) {\n\t\t\thunk_temp->temp -= hdr->size;\n\t\t} else {\n\t\t\tCom_Printf( \"Hunk_FreeTempMemory: not the final block\\n\" );\n\t\t}\n\t}\n}\n\n\n/*\n=================\nHunk_ClearTempMemory\n\nThe temp space is no longer needed.  If we have left more\ntouched but unused memory on this side, have future\npermanent allocs use this side.\n=================\n*/\nvoid Hunk_ClearTempMemory( void ) {\n\tif ( s_hunkData != NULL ) {\n\t\thunk_temp->temp = hunk_temp->permanent;\n\t}\n}\n\n/*\n=================\nHunk_Trash\n=================\n*/\nvoid Hunk_Trash( void ) {\n\tint length, i, rnd;\n\tchar *buf, value;\n\n\treturn;\n\n\tif ( s_hunkData == NULL )\n\t\treturn;\n\n#ifdef _DEBUG\n\tCom_Error(ERR_DROP, \"hunk trashed\\n\");\n\treturn;\n#endif\n\n\tCvar_Set(\"com_jp\", \"1\");\n\tHunk_SwapBanks();\n\n\tif ( hunk_permanent == &hunk_low ) {\n\t\tbuf = (char*) (void *)(s_hunkData + hunk_permanent->permanent);\n\t} else {\n\t\tbuf = (char*) (void *)(s_hunkData + s_hunkTotal - hunk_permanent->permanent );\n\t}\n\tlength = hunk_permanent->permanent;\n\n\tif (length > 0x7FFFF) {\n\t\t//randomly trash data within buf\n\t\trnd = random() * (length - 0x7FFFF);\n\t\tvalue = 31;\n\t\tfor (i = 0; i < 0x7FFFF; i++) {\n\t\t\tvalue *= 109;\n\t\t\tbuf[rnd+i] ^= value;\n\t\t}\n\t}\n}\n\n/*\n===================================================================\n\nEVENTS AND JOURNALING\n\nIn addition to these events, .cfg files are also copied to the\njournaled file\n===================================================================\n*/\n\n// bk001129 - here we go again: upped from 64\n// FIXME TTimo blunt upping from 256 to 1024\n// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=5\n#define\tMAX_PUSHED_EVENTS\t            1024\n// bk001129 - init, also static\nstatic int com_pushedEventsHead = 0;\nstatic int com_pushedEventsTail = 0;\n// bk001129 - static\nstatic sysEvent_t\tcom_pushedEvents[MAX_PUSHED_EVENTS];\n\n/*\n=================\nCom_InitJournaling\n=================\n*/\nvoid Com_InitJournaling( void ) {\n\tCom_StartupVariable( \"journal\" );\n\tcom_journal = Cvar_Get (\"journal\", \"0\", CVAR_INIT);\n\tif ( !com_journal->integer ) {\n\t\treturn;\n\t}\n\n\tif ( com_journal->integer == 1 ) {\n\t\tCom_Printf( \"Journaling events\\n\");\n\t\tcom_journalFile = FS_FOpenFileWrite( \"journal.dat\" );\n\t\tcom_journalDataFile = FS_FOpenFileWrite( \"journaldata.dat\" );\n\t} else if ( com_journal->integer == 2 ) {\n\t\tCom_Printf( \"Replaying journaled events\\n\");\n\t\tFS_FOpenFileRead( \"journal.dat\", &com_journalFile, qtrue );\n\t\tFS_FOpenFileRead( \"journaldata.dat\", &com_journalDataFile, qtrue );\n\t}\n\n\tif ( !com_journalFile || !com_journalDataFile ) {\n\t\tCvar_Set( \"com_journal\", \"0\" );\n\t\tcom_journalFile = 0;\n\t\tcom_journalDataFile = 0;\n\t\tCom_Printf( \"Couldn't open journal files\\n\" );\n\t}\n}\n\n/*\n=================\nCom_GetRealEvent\n=================\n*/\nsysEvent_t\tCom_GetRealEvent( void ) {\n\tint\t\t\tr;\n\tsysEvent_t\tev;\n\n\t// either get an event from the system or the journal file\n\tif ( com_journal->integer == 2 ) {\n\t\tr = FS_Read( &ev, sizeof(ev), com_journalFile );\n\t\tif ( r != sizeof(ev) ) {\n\t\t\tCom_Error( ERR_FATAL, \"Error reading from journal file\" );\n\t\t}\n\t\tif ( ev.evPtrLength ) {\n\t\t\tev.evPtr = Z_Malloc( ev.evPtrLength );\n\t\t\tr = FS_Read( ev.evPtr, ev.evPtrLength, com_journalFile );\n\t\t\tif ( r != ev.evPtrLength ) {\n\t\t\t\tCom_Error( ERR_FATAL, \"Error reading from journal file\" );\n\t\t\t}\n\t\t}\n\t} else {\n\t\tev = Sys_GetEvent();\n\n\t\t// write the journal value out if needed\n\t\tif ( com_journal->integer == 1 ) {\n\t\t\tr = FS_Write( &ev, sizeof(ev), com_journalFile );\n\t\t\tif ( r != sizeof(ev) ) {\n\t\t\t\tCom_Error( ERR_FATAL, \"Error writing to journal file\" );\n\t\t\t}\n\t\t\tif ( ev.evPtrLength ) {\n\t\t\t\tr = FS_Write( ev.evPtr, ev.evPtrLength, com_journalFile );\n\t\t\t\tif ( r != ev.evPtrLength ) {\n\t\t\t\t\tCom_Error( ERR_FATAL, \"Error writing to journal file\" );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn ev;\n}\n\n\n/*\n=================\nCom_InitPushEvent\n=================\n*/\n// bk001129 - added\nvoid Com_InitPushEvent( void ) {\n  // clear the static buffer array\n  // this requires SE_NONE to be accepted as a valid but NOP event\n  memset( com_pushedEvents, 0, sizeof(com_pushedEvents) );\n  // reset counters while we are at it\n  // beware: GetEvent might still return an SE_NONE from the buffer\n  com_pushedEventsHead = 0;\n  com_pushedEventsTail = 0;\n}\n\n\n/*\n=================\nCom_PushEvent\n=================\n*/\nvoid Com_PushEvent( sysEvent_t *event ) {\n\tsysEvent_t\t\t*ev;\n\tstatic int printedWarning = 0; // bk001129 - init, bk001204 - explicit int\n\n\tev = &com_pushedEvents[ com_pushedEventsHead & (MAX_PUSHED_EVENTS-1) ];\n\n\tif ( com_pushedEventsHead - com_pushedEventsTail >= MAX_PUSHED_EVENTS ) {\n\n\t\t// don't print the warning constantly, or it can give time for more...\n\t\tif ( !printedWarning ) {\n\t\t\tprintedWarning = qtrue;\n\t\t\tCom_Printf( \"WARNING: Com_PushEvent overflow\\n\" );\n\t\t}\n\n\t\tif ( ev->evPtr ) {\n\t\t\tZ_Free( ev->evPtr );\n\t\t}\n\t\tcom_pushedEventsTail++;\n\t} else {\n\t\tprintedWarning = qfalse;\n\t}\n\n\t*ev = *event;\n\tcom_pushedEventsHead++;\n}\n\n/*\n=================\nCom_GetEvent\n=================\n*/\nsysEvent_t\tCom_GetEvent( void ) {\n\tif ( com_pushedEventsHead > com_pushedEventsTail ) {\n\t\tcom_pushedEventsTail++;\n\t\treturn com_pushedEvents[ (com_pushedEventsTail-1) & (MAX_PUSHED_EVENTS-1) ];\n\t}\n\treturn Com_GetRealEvent();\n}\n\n/*\n=================\nCom_RunAndTimeServerPacket\n=================\n*/\nvoid Com_RunAndTimeServerPacket( netadr_t *evFrom, msg_t *buf ) {\n\tint\t\tt1, t2, msec;\n\n\tt1 = 0;\n\n\tif ( com_speeds->integer ) {\n\t\tt1 = Sys_Milliseconds ();\n\t}\n\n\tSV_PacketEvent( *evFrom, buf );\n\n\tif ( com_speeds->integer ) {\n\t\tt2 = Sys_Milliseconds ();\n\t\tmsec = t2 - t1;\n\t\tif ( com_speeds->integer == 3 ) {\n\t\t\tCom_Printf( \"SV_PacketEvent time: %i\\n\", msec );\n\t\t}\n\t}\n}\n\n/*\n=================\nCom_EventLoop\n\nReturns last event time\n=================\n*/\nint Com_EventLoop( void ) {\n\tsysEvent_t\tev;\n\tnetadr_t\tevFrom;\n\tbyte\t\tbufData[MAX_MSGLEN];\n\tmsg_t\t\tbuf;\n\n\tMSG_Init( &buf, bufData, sizeof( bufData ) );\n\n\twhile ( 1 ) {\n\t\tev = Com_GetEvent();\n\n\t\t// if no more events are available\n\t\tif ( ev.evType == SE_NONE ) {\n\t\t\t// manually send packet events for the loopback channel\n\t\t\twhile ( NET_GetLoopPacket( NS_CLIENT, &evFrom, &buf ) ) {\n\t\t\t\tCL_PacketEvent( evFrom, &buf );\n\t\t\t}\n\n\t\t\twhile ( NET_GetLoopPacket( NS_SERVER, &evFrom, &buf ) ) {\n\t\t\t\t// if the server just shut down, flush the events\n\t\t\t\tif ( com_sv_running->integer ) {\n\t\t\t\t\tCom_RunAndTimeServerPacket( &evFrom, &buf );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn ev.evTime;\n\t\t}\n\n\n\t\tswitch ( ev.evType ) {\n\t\tdefault:\n\t\t  // bk001129 - was ev.evTime\n\t\t\tCom_Error( ERR_FATAL, \"Com_EventLoop: bad event type %i\", ev.evType );\n\t\t\tbreak;\n        case SE_NONE:\n            break;\n\t\tcase SE_KEY:\n\t\t\tCL_KeyEvent( ev.evValue, (qboolean) ev.evValue2, ev.evTime );\n\t\t\tbreak;\n\t\tcase SE_CHAR:\n\t\t\tCL_CharEvent( ev.evValue );\n\t\t\tbreak;\n\t\tcase SE_MOUSE:\n\t\t\tCL_MouseEvent( ev.evValue, ev.evValue2, ev.evTime );\n\t\t\tbreak;\n\t\tcase SE_JOYSTICK_AXIS:\n\t\t\tCL_JoystickEvent( ev.evValue, ev.evValue2, ev.evTime );\n\t\t\tbreak;\n\t\tcase SE_CONSOLE:\n\t\t\tCbuf_AddText( (char *)ev.evPtr );\n\t\t\tCbuf_AddText( \"\\n\" );\n\t\t\tbreak;\n\t\tcase SE_PACKET:\n\t\t\t// this cvar allows simulation of connections that\n\t\t\t// drop a lot of packets.  Note that loopback connections\n\t\t\t// don't go through here at all.\n\t\t\tif ( com_dropsim->value > 0 ) {\n\t\t\t\tstatic int seed;\n\n\t\t\t\tif ( Q_random( &seed ) < com_dropsim->value ) {\n\t\t\t\t\tbreak;\t\t// drop this packet\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tevFrom = *(netadr_t *)ev.evPtr;\n\t\t\tbuf.cursize = ev.evPtrLength - sizeof( evFrom );\n\n\t\t\t// we must copy the contents of the message out, because\n\t\t\t// the event buffers are only large enough to hold the\n\t\t\t// exact payload, but channel messages need to be large\n\t\t\t// enough to hold fragment reassembly\n\t\t\tif ( (unsigned)buf.cursize > buf.maxsize ) {\n\t\t\t\tCom_Printf(\"Com_EventLoop: oversize packet\\n\");\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tCom_Memcpy( buf.data, (byte *)((netadr_t *)ev.evPtr + 1), buf.cursize );\n\t\t\tif ( com_sv_running->integer ) {\n\t\t\t\tCom_RunAndTimeServerPacket( &evFrom, &buf );\n\t\t\t} else {\n\t\t\t\tCL_PacketEvent( evFrom, &buf );\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\t// free any block data\n\t\tif ( ev.evPtr ) {\n\t\t\tZ_Free( ev.evPtr );\n\t\t}\n\t}\n\n\treturn 0;\t// never reached\n}\n\n/*\n================\nCom_Milliseconds\n\nCan be used for profiling, but will be journaled accurately\n================\n*/\nint Com_Milliseconds (void) {\n\tsysEvent_t\tev;\n\n\t// get events and push them until we get a null event with the current time\n\tdo {\n\n\t\tev = Com_GetRealEvent();\n\t\tif ( ev.evType != SE_NONE ) {\n\t\t\tCom_PushEvent( &ev );\n\t\t}\n\t} while ( ev.evType != SE_NONE );\n\t\n\treturn ev.evTime;\n}\n\n//============================================================================\n\n/*\n=============\nCom_Error_f\n\nJust throw a fatal error to\ntest error shutdown procedures\n=============\n*/\nstatic void Com_Error_f (void) {\n\tif ( Cmd_Argc() > 1 ) {\n\t\tCom_Error( ERR_DROP, \"Testing drop error\" );\n\t} else {\n\t\tCom_Error( ERR_FATAL, \"Testing fatal error\" );\n\t}\n}\n\n\n/*\n=============\nCom_Freeze_f\n\nJust freeze in place for a given number of seconds to test\nerror recovery\n=============\n*/\nstatic void Com_Freeze_f (void) {\n\tfloat\ts;\n\tint\t\tstart, now;\n\n\tif ( Cmd_Argc() != 2 ) {\n\t\tCom_Printf( \"freeze <seconds>\\n\" );\n\t\treturn;\n\t}\n\ts = atof( Cmd_Argv(1) );\n\n\tstart = Com_Milliseconds();\n\n\twhile ( 1 ) {\n\t\tnow = Com_Milliseconds();\n\t\tif ( ( now - start ) * 0.001 > s ) {\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\n/*\n=================\nCom_Crash_f\n\nA way to force a bus error for development reasons\n=================\n*/\nstatic void Com_Crash_f( void ) {\n\t* ( int * ) 0 = 0x12345678;\n}\n\n// TTimo: centralizing the cl_cdkey stuff after I discovered a buffer overflow problem with the dedicated server version\n//   not sure it's necessary to have different defaults for regular and dedicated, but I don't want to risk it\n//   https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=470\n#ifndef DEDICATED\nchar\tcl_cdkey[34] = \"                                \";\n#else\nchar\tcl_cdkey[34] = \"123456789\";\n#endif\n\n/*\n=================\nCom_ReadCDKey\n=================\n*/\nqboolean CL_CDKeyValidate( const char *key, const char *checksum );\nvoid Com_ReadCDKey( const char *filename ) {\n\tfileHandle_t\tf;\n\tchar\t\t\tbuffer[33];\n\tchar\t\t\tfbuffer[MAX_OSPATH];\n\n\tsprintf(fbuffer, \"%s/q3key\", filename);\n\n\tFS_SV_FOpenFileRead( fbuffer, &f );\n\tif ( !f ) {\n\t\tQ_strncpyz( cl_cdkey, \"                \", 17 );\n\t\treturn;\n\t}\n\n\tCom_Memset( buffer, 0, sizeof(buffer) );\n\n\tFS_Read( buffer, 16, f );\n\tFS_FCloseFile( f );\n\n\tif (CL_CDKeyValidate(buffer, NULL)) {\n\t\tQ_strncpyz( cl_cdkey, buffer, 17 );\n\t} else {\n\t\tQ_strncpyz( cl_cdkey, \"                \", 17 );\n\t}\n}\n\n/*\n=================\nCom_AppendCDKey\n=================\n*/\nvoid Com_AppendCDKey( const char *filename ) {\n\tfileHandle_t\tf;\n\tchar\t\t\tbuffer[33];\n\tchar\t\t\tfbuffer[MAX_OSPATH];\n\n\tsprintf(fbuffer, \"%s/q3key\", filename);\n\n\tFS_SV_FOpenFileRead( fbuffer, &f );\n\tif (!f) {\n\t\tQ_strncpyz( &cl_cdkey[16], \"                \", 17 );\n\t\treturn;\n\t}\n\n\tCom_Memset( buffer, 0, sizeof(buffer) );\n\n\tFS_Read( buffer, 16, f );\n\tFS_FCloseFile( f );\n\n\tif (CL_CDKeyValidate(buffer, NULL)) {\n\t\tstrcat( &cl_cdkey[16], buffer );\n\t} else {\n\t\tQ_strncpyz( &cl_cdkey[16], \"                \", 17 );\n\t}\n}\n\n#ifndef DEDICATED // bk001204\n/*\n=================\nCom_WriteCDKey\n=================\n*/\nstatic void Com_WriteCDKey( const char *filename, const char *ikey ) {\n\tfileHandle_t\tf;\n\tchar\t\t\tfbuffer[MAX_OSPATH];\n\tchar\t\t\tkey[17];\n\n\n\tsprintf(fbuffer, \"%s/q3key\", filename);\n\n\n\tQ_strncpyz( key, ikey, 17 );\n\n\tif(!CL_CDKeyValidate(key, NULL) ) {\n\t\treturn;\n\t}\n\n\tf = FS_SV_FOpenFileWrite( fbuffer );\n\tif ( !f ) {\n\t\tCom_Printf (\"Couldn't write %s.\\n\", filename );\n\t\treturn;\n\t}\n\n\tFS_Write( key, 16, f );\n\n\tFS_Printf( f, \"\\n// generated by quake, do not modify\\r\\n\" );\n\tFS_Printf( f, \"// Do not give this file to ANYONE.\\r\\n\" );\n\tFS_Printf( f, \"// id Software and Activision will NOT ask you to send this file to them.\\r\\n\");\n\n\tFS_FCloseFile( f );\n}\n#endif\n\n\n/*\n=================\nCom_Init\n=================\n*/\nvoid Com_Init( char *commandLine ) {\n\tchar\t*s;\n\n\tCom_Printf( \"%s %s %s\\n\", Q3_VERSION, CPUSTRING, __DATE__ );\n\n\tif ( setjmp (abortframe) ) {\n\t\tSys_Error (\"Error during initialization\");\n\t}\n\n  // bk001129 - do this before anything else decides to push events\n  Com_InitPushEvent();\n\n\tCom_InitSmallZoneMemory();\n\tCvar_Init ();\n\n\t// prepare enough of the subsystems to handle\n\t// cvar and command buffer management\n\tCom_ParseCommandLine( commandLine );\n\n//\tSwap_Init ();\n\tCbuf_Init ();\n\n\tCom_InitZoneMemory();\n\tCmd_Init ();\n\n\t// override anything from the config files with command line args\n\tCom_StartupVariable( NULL );\n\n\t// get the developer cvar set as early as possible\n\tCom_StartupVariable( \"developer\" );\n\n\t// done early so bind command exists\n\tCL_InitKeyCommands();\n\n\tFS_InitFilesystem ();\n\n\tCom_InitJournaling();\n\n\tCbuf_AddText (\"exec default.cfg\\n\");\n\n\t// skip the q3config.cfg if \"safe\" is on the command line\n\tif ( !Com_SafeMode() ) {\n\t\tCbuf_AddText (\"exec q3config.cfg\\n\");\n\t}\n\n\tCbuf_AddText (\"exec autoexec.cfg\\n\");\n\n\tCbuf_Execute ();\n\n\t// override anything from the config files with command line args\n\tCom_StartupVariable( NULL );\n\n  // get dedicated here for proper hunk megs initialization\n#ifdef DEDICATED\n\tcom_dedicated = Cvar_Get (\"dedicated\", \"1\", CVAR_ROM);\n#else\n\tcom_dedicated = Cvar_Get (\"dedicated\", \"0\", CVAR_LATCH);\n#endif\n\t// allocate the stack based hunk allocator\n\tCom_InitHunkMemory();\n\n\t// if any archived cvars are modified after this, we will trigger a writing\n\t// of the config file\n\tcvar_modifiedFlags &= ~CVAR_ARCHIVE;\n\n\t//\n\t// init commands and vars\n\t//\n\tcom_maxfps = Cvar_Get (\"com_maxfps\", \"85\", CVAR_ARCHIVE);\n\tcom_blood = Cvar_Get (\"com_blood\", \"1\", CVAR_ARCHIVE);\n\n\tcom_developer = Cvar_Get (\"developer\", \"0\", CVAR_TEMP );\n\tcom_logfile = Cvar_Get (\"logfile\", \"0\", CVAR_TEMP );\n\n\tcom_timescale = Cvar_Get (\"timescale\", \"1\", CVAR_CHEAT | CVAR_SYSTEMINFO );\n\tcom_fixedtime = Cvar_Get (\"fixedtime\", \"0\", CVAR_CHEAT);\n\tcom_showtrace = Cvar_Get (\"com_showtrace\", \"0\", CVAR_CHEAT);\n\tcom_dropsim = Cvar_Get (\"com_dropsim\", \"0\", CVAR_CHEAT);\n\tcom_viewlog = Cvar_Get( \"viewlog\", \"0\", CVAR_CHEAT );\n\tcom_speeds = Cvar_Get (\"com_speeds\", \"0\", 0);\n\tcom_timedemo = Cvar_Get (\"timedemo\", \"0\", CVAR_CHEAT);\n\tcom_cameraMode = Cvar_Get (\"com_cameraMode\", \"0\", CVAR_CHEAT);\n\n\tcl_paused = Cvar_Get (\"cl_paused\", \"0\", CVAR_ROM);\n\tsv_paused = Cvar_Get (\"sv_paused\", \"0\", CVAR_ROM);\n\tcom_sv_running = Cvar_Get (\"sv_running\", \"0\", CVAR_ROM);\n\tcom_cl_running = Cvar_Get (\"cl_running\", \"0\", CVAR_ROM);\n\tcom_buildScript = Cvar_Get( \"com_buildScript\", \"0\", 0 );\n\n\tcom_introPlayed = Cvar_Get( \"com_introplayed\", \"0\", CVAR_ARCHIVE);\n\n#if defined(_WIN32) && defined(_DEBUG)\n\tcom_noErrorInterrupt = Cvar_Get( \"com_noErrorInterrupt\", \"0\", 0 );\n#endif\n\n\tif ( com_dedicated->integer ) {\n\t\tif ( !com_viewlog->integer ) {\n\t\t\tCvar_Set( \"viewlog\", \"1\" );\n\t\t}\n\t}\n\n\tif ( com_developer && com_developer->integer ) {\n\t\tCmd_AddCommand (\"error\", Com_Error_f);\n\t\tCmd_AddCommand (\"crash\", Com_Crash_f );\n\t\tCmd_AddCommand (\"freeze\", Com_Freeze_f);\n\t}\n\tCmd_AddCommand (\"quit\", Com_Quit_f);\n\tCmd_AddCommand (\"changeVectors\", MSG_ReportChangeVectors_f );\n\tCmd_AddCommand (\"writeconfig\", Com_WriteConfig_f );\n\n\ts = va(\"%s %s %s\", Q3_VERSION, CPUSTRING, __DATE__ );\n\tcom_version = Cvar_Get (\"version\", s, CVAR_ROM | CVAR_SERVERINFO );\n\n\tSys_Init();\n\tNetchan_Init( Com_Milliseconds() & 0xffff );\t// pick a port value that should be nice and random\n\tVM_Init();\n\tSV_Init();\n\n\tcom_dedicated->modified = qfalse;\n\tif ( !com_dedicated->integer ) {\n\t\tCL_Init();\n\t\tSys_ShowConsole( com_viewlog->integer, qfalse );\n\t}\n\n\t// set com_frameTime so that if a map is started on the\n\t// command line it will still be able to count on com_frameTime\n\t// being random enough for a serverid\n\tcom_frameTime = Com_Milliseconds();\n\n\t// add + commands from command line\n\tif ( !Com_AddStartupCommands() ) {\n\t\t// if the user didn't give any commands, run default action\n\t\tif ( !com_dedicated->integer ) {\n\t\t\tCbuf_AddText (\"cinematic idlogo.RoQ\\n\");\n\t\t\tif( !com_introPlayed->integer ) {\n\t\t\t\tCvar_Set( com_introPlayed->name, \"1\" );\n\t\t\t\tCvar_Set( \"nextmap\", \"cinematic intro.RoQ\" );\n\t\t\t}\n\t\t}\n\t}\n\n\t// start in full screen ui mode\n\tCvar_Set(\"r_uiFullScreen\", \"1\");\n\n\tCL_StartHunkUsers();\n\n\t// make sure single player is off by default\n\tCvar_Set(\"ui_singlePlayerActive\", \"0\");\n\n\tcom_fullyInitialized = qtrue;\n\tCom_Printf (\"--- Common Initialization Complete ---\\n\");\t\n}\n\n//==================================================================\n\nvoid Com_WriteConfigToFile( const char *filename ) {\n\tfileHandle_t\tf;\n\n\tf = FS_FOpenFileWrite( filename );\n\tif ( !f ) {\n\t\tCom_Printf (\"Couldn't write %s.\\n\", filename );\n\t\treturn;\n\t}\n\n\tFS_Printf (f, \"// generated by quake, do not modify\\n\");\n\tKey_WriteBindings (f);\n\tCvar_WriteVariables (f);\n\tFS_FCloseFile( f );\n}\n\n\n/*\n===============\nCom_WriteConfiguration\n\nWrites key bindings and archived cvars to config file if modified\n===============\n*/\nvoid Com_WriteConfiguration( void ) {\n#ifndef DEDICATED // bk001204\n\tcvar_t\t*fs;\n#endif\n\t// if we are quiting without fully initializing, make sure\n\t// we don't write out anything\n\tif ( !com_fullyInitialized ) {\n\t\treturn;\n\t}\n\n\tif ( !(cvar_modifiedFlags & CVAR_ARCHIVE ) ) {\n\t\treturn;\n\t}\n\tcvar_modifiedFlags &= ~CVAR_ARCHIVE;\n\n\tCom_WriteConfigToFile( \"q3config.cfg\" );\n\n\t// bk001119 - tentative \"not needed for dedicated\"\n#ifndef DEDICATED\n\tfs = Cvar_Get (\"fs_game\", \"\", CVAR_INIT|CVAR_SYSTEMINFO );\n\tif (UI_usesUniqueCDKey() && fs && fs->string[0] != 0) {\n\t\tCom_WriteCDKey( fs->string, &cl_cdkey[16] );\n\t} else {\n\t\tCom_WriteCDKey( \"baseq3\", cl_cdkey );\n\t}\n#endif\n}\n\n\n/*\n===============\nCom_WriteConfig_f\n\nWrite the config file to a specific name\n===============\n*/\nvoid Com_WriteConfig_f( void ) {\n\tchar\tfilename[MAX_QPATH];\n\n\tif ( Cmd_Argc() != 2 ) {\n\t\tCom_Printf( \"Usage: writeconfig <filename>\\n\" );\n\t\treturn;\n\t}\n\n\tQ_strncpyz( filename, Cmd_Argv(1), sizeof( filename ) );\n\tCOM_DefaultExtension( filename, sizeof( filename ), \".cfg\" );\n\tCom_Printf( \"Writing %s.\\n\", filename );\n\tCom_WriteConfigToFile( filename );\n}\n\n/*\n================\nCom_ModifyMsec\n================\n*/\nint Com_ModifyMsec( int msec ) {\n\tint\t\tclampTime;\n\n\t//\n\t// modify time for debugging values\n\t//\n\tif ( com_fixedtime->integer ) {\n\t\tmsec = com_fixedtime->integer;\n\t} else if ( com_timescale->value ) {\n\t\tmsec *= com_timescale->value;\n\t} else if (com_cameraMode->integer) {\n\t\tmsec *= com_timescale->value;\n\t}\n\t\n\t// don't let it scale below 1 msec\n\tif ( msec < 1 && com_timescale->value) {\n\t\tmsec = 1;\n\t}\n\n\tif ( com_dedicated->integer ) {\n\t\t// dedicated servers don't want to clamp for a much longer\n\t\t// period, because it would mess up all the client's views\n\t\t// of time.\n\t\tif ( msec > 500 ) {\n\t\t\tCom_Printf( \"Hitch warning: %i msec frame time\\n\", msec );\n\t\t}\n\t\tclampTime = 5000;\n\t} else \n\tif ( !com_sv_running->integer ) {\n\t\t// clients of remote servers do not want to clamp time, because\n\t\t// it would skew their view of the server's time temporarily\n\t\tclampTime = 5000;\n\t} else {\n\t\t// for local single player gaming\n\t\t// we may want to clamp the time to prevent players from\n\t\t// flying off edges when something hitches.\n\t\tclampTime = 200;\n\t}\n\n\tif ( msec > clampTime ) {\n\t\tmsec = clampTime;\n\t}\n\n\treturn msec;\n}\n\n/*\n=================\nCom_Frame\n=================\n*/\nvoid Com_Frame( void ) {\n\n\tint\t\tmsec, minMsec;\n\tstatic int\tlastTime;\n\tint key;\n \n\tint\t\ttimeBeforeFirstEvents;\n\tint           timeBeforeServer;\n\tint           timeBeforeEvents;\n\tint           timeBeforeClient;\n\tint           timeAfter;\n  \n\n\n\n\n\tif ( setjmp (abortframe) ) {\n\t\treturn;\t\t\t// an ERR_DROP was thrown\n\t}\n\n\t// bk001204 - init to zero.\n\t//  also:  might be clobbered by `longjmp' or `vfork'\n\ttimeBeforeFirstEvents =0;\n\ttimeBeforeServer =0;\n\ttimeBeforeEvents =0;\n\ttimeBeforeClient = 0;\n\ttimeAfter = 0;\n\n\n\t// old net chan encryption key\n\tkey = 0x87243987;\n\n\t// write config file if anything changed\n\tCom_WriteConfiguration(); \n\n\t// if \"viewlog\" has been modified, show or hide the log console\n\tif ( com_viewlog->modified ) {\n\t\tif ( !com_dedicated->value ) {\n\t\t\tSys_ShowConsole( com_viewlog->integer, qfalse );\n\t\t}\n\t\tcom_viewlog->modified = qfalse;\n\t}\n\n\t//\n\t// main event loop\n\t//\n\tif ( com_speeds->integer ) {\n\t\ttimeBeforeFirstEvents = Sys_Milliseconds ();\n\t}\n\n\t// we may want to spin here if things are going too fast\n\tif ( !com_dedicated->integer && com_maxfps->integer > 0 && !com_timedemo->integer ) {\n\t\tminMsec = 1000 / com_maxfps->integer;\n\t} else {\n\t\tminMsec = 1;\n\t}\n\tdo {\n\t\tcom_frameTime = Com_EventLoop();\n\t\tif ( lastTime > com_frameTime ) {\n\t\t\tlastTime = com_frameTime;\t\t// possible on first frame\n\t\t}\n\t\tmsec = com_frameTime - lastTime;\n\t} while ( msec < minMsec );\n\tCbuf_Execute ();\n\n\tlastTime = com_frameTime;\n\n\t// mess with msec if needed\n\tcom_frameMsec = msec;\n\tmsec = Com_ModifyMsec( msec );\n\n\t//\n\t// server side\n\t//\n\tif ( com_speeds->integer ) {\n\t\ttimeBeforeServer = Sys_Milliseconds ();\n\t}\n\n\tSV_Frame( msec );\n\n\t// if \"dedicated\" has been modified, start up\n\t// or shut down the client system.\n\t// Do this after the server may have started,\n\t// but before the client tries to auto-connect\n\tif ( com_dedicated->modified ) {\n\t\t// get the latched value\n\t\tCvar_Get( \"dedicated\", \"0\", 0 );\n\t\tcom_dedicated->modified = qfalse;\n\t\tif ( !com_dedicated->integer ) {\n\t\t\tCL_Init();\n\t\t\tSys_ShowConsole( com_viewlog->integer, qfalse );\n\t\t} else {\n\t\t\tCL_Shutdown();\n\t\t\tSys_ShowConsole( 1, qtrue );\n\t\t}\n\t}\n\n\t//\n\t// client system\n\t//\n\tif ( !com_dedicated->integer ) {\n\t\t//\n\t\t// run event loop a second time to get server to client packets\n\t\t// without a frame of latency\n\t\t//\n\t\tif ( com_speeds->integer ) {\n\t\t\ttimeBeforeEvents = Sys_Milliseconds ();\n\t\t}\n\t\tCom_EventLoop();\n\t\tCbuf_Execute ();\n\n\n\t\t//\n\t\t// client side\n\t\t//\n\t\tif ( com_speeds->integer ) {\n\t\t\ttimeBeforeClient = Sys_Milliseconds ();\n\t\t}\n\n\t\tCL_Frame( msec );\n\n\t\tif ( com_speeds->integer ) {\n\t\t\ttimeAfter = Sys_Milliseconds ();\n\t\t}\n\t}\n\n\t//\n\t// report timing information\n\t//\n\tif ( com_speeds->integer ) {\n\t\tint\t\t\tall, sv, ev, cl;\n\n\t\tall = timeAfter - timeBeforeServer;\n\t\tsv = timeBeforeEvents - timeBeforeServer;\n\t\tev = timeBeforeServer - timeBeforeFirstEvents + timeBeforeClient - timeBeforeEvents;\n\t\tcl = timeAfter - timeBeforeClient;\n\t\tsv -= time_game;\n\t\tcl -= time_frontend + time_backend;\n\n\t\tCom_Printf (\"frame:%i all:%3i sv:%3i ev:%3i cl:%3i gm:%3i rf:%3i bk:%3i\\n\", \n\t\t\t\t\t com_frameNumber, all, sv, ev, cl, time_game, time_frontend, time_backend );\n\t}\t\n\n\t//\n\t// trace optimization tracking\n\t//\n\tif ( com_showtrace->integer ) {\n\t\n\t\textern\tint c_traces, c_brush_traces, c_patch_traces;\n\t\textern\tint\tc_pointcontents;\n\n\t\tCom_Printf (\"%4i traces  (%ib %ip) %4i points\\n\", c_traces,\n\t\t\tc_brush_traces, c_patch_traces, c_pointcontents);\n\t\tc_traces = 0;\n\t\tc_brush_traces = 0;\n\t\tc_patch_traces = 0;\n\t\tc_pointcontents = 0;\n\t}\n\n\t// old net chan encryption key\n\tkey = lastTime * 0x87243987;\n\n\tcom_frameNumber++;\n}\n\n/*\n=================\nCom_Shutdown\n=================\n*/\nvoid Com_Shutdown (void) {\n\tif (logfile) {\n\t\tFS_FCloseFile (logfile);\n\t\tlogfile = 0;\n\t}\n\n\tif ( com_journalFile ) {\n\t\tFS_FCloseFile( com_journalFile );\n\t\tcom_journalFile = 0;\n\t}\n\n}\n\n#if !( defined __VECTORC )\n#if !( defined __linux__ || defined __FreeBSD__ )  // r010123 - include FreeBSD \n#if ((!id386) && (!defined __i386__)) // rcg010212 - for PPC\n\nvoid Com_Memcpy (void* dest, const void* src, const size_t count)\n{\n\tmemcpy(dest, src, count);\n}\n\nvoid Com_Memset (void* dest, const int val, const size_t count)\n{\n\tmemset(dest, val, count);\n}\n\n#else\n\ntypedef enum\n{\n\tPRE_READ,\t\t\t\t\t\t\t\t\t// prefetch assuming that buffer is used for reading only\n\tPRE_WRITE,\t\t\t\t\t\t\t\t\t// prefetch assuming that buffer is used for writing only\n\tPRE_READ_WRITE\t\t\t\t\t\t\t\t// prefetch assuming that buffer is used for both reading and writing\n} e_prefetch;\n\nvoid Com_Prefetch (const void *s, const unsigned int bytes, e_prefetch type);\n\n#define EMMS_INSTRUCTION\t__asm emms\n\nvoid _copyDWord (unsigned int* dest, const unsigned int constant, const unsigned int count) {\n\t__asm\n\t{\n\t\t\tmov\t\tedx,dest\n\t\t\tmov\t\teax,constant\n\t\t\tmov\t\tecx,count\n\t\t\tand\t\tecx,~7\n\t\t\tjz\t\tpadding\n\t\t\tsub\t\tecx,8\n\t\t\tjmp\t\tloopu\n\t\t\talign\t16\nloopu:\t\t\n\t\t\ttest\t[edx+ecx*4 + 28],ebx\t\t// fetch next block destination to L1 cache\n\t\t\tmov\t\t[edx+ecx*4 + 0],eax\n\t\t\tmov\t\t[edx+ecx*4 + 4],eax\n\t\t\tmov\t\t[edx+ecx*4 + 8],eax\n\t\t\tmov\t\t[edx+ecx*4 + 12],eax\n\t\t\tmov\t\t[edx+ecx*4 + 16],eax\n\t\t\tmov\t\t[edx+ecx*4 + 20],eax\n\t\t\tmov\t\t[edx+ecx*4 + 24],eax\n\t\t\tmov\t\t[edx+ecx*4 + 28],eax\n\t\t\tsub\t\tecx,8\n\t\t\tjge\t\tloopu\npadding:\tmov\t\tecx,count\n\t\t\tmov\t\tebx,ecx\n\t\t\tand\t\tecx,7\n\t\t\tjz\t\toutta\n\t\t\tand\t\tebx,~7\n\t\t\tlea\t\tedx,[edx+ebx*4]\t\t\t\t// advance dest pointer\n\t\t\ttest\t[edx+0],eax\t\t\t\t\t// fetch destination to L1 cache\n\t\t\tcmp\t\tecx,4\n\t\t\tjl\t\tskip4\n\t\t\tmov\t\t[edx+0],eax\n\t\t\tmov\t\t[edx+4],eax\n\t\t\tmov\t\t[edx+8],eax\n\t\t\tmov\t\t[edx+12],eax\n\t\t\tadd\t\tedx,16\n\t\t\tsub\t\tecx,4\nskip4:\t\tcmp\t\tecx,2\n\t\t\tjl\t\tskip2\n\t\t\tmov\t\t[edx+0],eax\n\t\t\tmov\t\t[edx+4],eax\n\t\t\tadd\t\tedx,8\n\t\t\tsub\t\tecx,2\nskip2:\t\tcmp\t\tecx,1\n\t\t\tjl\t\toutta\n\t\t\tmov\t\t[edx+0],eax\noutta:\n\t}\n}\n\n// optimized memory copy routine that handles all alignment\n// cases and block sizes efficiently\nvoid Com_Memcpy (void* dest, const void* src, const size_t count) {\n\tCom_Prefetch (src, count, PRE_READ);\n\t__asm\n\t{\n\t\tpush\tedi\n\t\tpush\tesi\n\t\tmov\t\tecx,count\n\t\tcmp\t\tecx,0\t\t\t\t\t\t// count = 0 check (just to be on the safe side)\n\t\tje\t\toutta\n\t\tmov\t\tedx,dest\n\t\tmov\t\tebx,src\n\t\tcmp\t\tecx,32\t\t\t\t\t\t// padding only?\n\t\tjl\t\tpadding\n\n\t\tmov\t\tedi,ecx\t\t\t\t\t\n\t\tand\t\tedi,~31\t\t\t\t\t// edi = count&~31\n\t\tsub\t\tedi,32\n\n\t\talign 16\nloopMisAligned:\n\t\tmov\t\teax,[ebx + edi + 0 + 0*8]\n\t\tmov\t\tesi,[ebx + edi + 4 + 0*8]\n\t\tmov\t\t[edx+edi+0 + 0*8],eax\n\t\tmov\t\t[edx+edi+4 + 0*8],esi\n\t\tmov\t\teax,[ebx + edi + 0 + 1*8]\n\t\tmov\t\tesi,[ebx + edi + 4 + 1*8]\n\t\tmov\t\t[edx+edi+0 + 1*8],eax\n\t\tmov\t\t[edx+edi+4 + 1*8],esi\n\t\tmov\t\teax,[ebx + edi + 0 + 2*8]\n\t\tmov\t\tesi,[ebx + edi + 4 + 2*8]\n\t\tmov\t\t[edx+edi+0 + 2*8],eax\n\t\tmov\t\t[edx+edi+4 + 2*8],esi\n\t\tmov\t\teax,[ebx + edi + 0 + 3*8]\n\t\tmov\t\tesi,[ebx + edi + 4 + 3*8]\n\t\tmov\t\t[edx+edi+0 + 3*8],eax\n\t\tmov\t\t[edx+edi+4 + 3*8],esi\n\t\tsub\t\tedi,32\n\t\tjge\t\tloopMisAligned\n\t\t\n\t\tmov\t\tedi,ecx\n\t\tand\t\tedi,~31\n\t\tadd\t\tebx,edi\t\t\t\t\t// increase src pointer\n\t\tadd\t\tedx,edi\t\t\t\t\t// increase dst pointer\n\t\tand\t\tecx,31\t\t\t\t\t// new count\n\t\tjz\t\toutta\t\t\t\t\t// if count = 0, get outta here\n\npadding:\n\t\tcmp\t\tecx,16\n\t\tjl\t\tskip16\n\t\tmov\t\teax,dword ptr [ebx]\n\t\tmov\t\tdword ptr [edx],eax\n\t\tmov\t\teax,dword ptr [ebx+4]\n\t\tmov\t\tdword ptr [edx+4],eax\n\t\tmov\t\teax,dword ptr [ebx+8]\n\t\tmov\t\tdword ptr [edx+8],eax\n\t\tmov\t\teax,dword ptr [ebx+12]\n\t\tmov\t\tdword ptr [edx+12],eax\n\t\tsub\t\tecx,16\n\t\tadd\t\tebx,16\n\t\tadd\t\tedx,16\nskip16:\n\t\tcmp\t\tecx,8\n\t\tjl\t\tskip8\n\t\tmov\t\teax,dword ptr [ebx]\n\t\tmov\t\tdword ptr [edx],eax\n\t\tmov\t\teax,dword ptr [ebx+4]\n\t\tsub\t\tecx,8\n\t\tmov\t\tdword ptr [edx+4],eax\n\t\tadd\t\tebx,8\n\t\tadd\t\tedx,8\nskip8:\n\t\tcmp\t\tecx,4\n\t\tjl\t\tskip4\n\t\tmov\t\teax,dword ptr [ebx]\t// here 4-7 bytes\n\t\tadd\t\tebx,4\n\t\tsub\t\tecx,4\n\t\tmov\t\tdword ptr [edx],eax\n\t\tadd\t\tedx,4\nskip4:\t\t\t\t\t\t\t// 0-3 remaining bytes\n\t\tcmp\t\tecx,2\n\t\tjl\t\tskip2\n\t\tmov\t\tax,word ptr [ebx]\t// two bytes\n\t\tcmp\t\tecx,3\t\t\t\t// less than 3?\n\t\tmov\t\tword ptr [edx],ax\n\t\tjl\t\toutta\n\t\tmov\t\tal,byte ptr [ebx+2]\t// last byte\n\t\tmov\t\tbyte ptr [edx+2],al\n\t\tjmp\t\toutta\nskip2:\n\t\tcmp\t\tecx,1\n\t\tjl\t\toutta\n\t\tmov\t\tal,byte ptr [ebx]\n\t\tmov\t\tbyte ptr [edx],al\noutta:\n\t\tpop\t\tesi\n\t\tpop\t\tedi\n\t}\n}\n\nvoid Com_Memset (void* dest, const int val, const size_t count)\n{\n\tunsigned int fillval;\n\n\tif (count < 8)\n\t{\n\t\t__asm\n\t\t{\n\t\t\tmov\t\tedx,dest\n\t\t\tmov\t\teax, val\n\t\t\tmov\t\tah,al\n\t\t\tmov\t\tebx,eax\n\t\t\tand\t\tebx, 0xffff\n\t\t\tshl\t\teax,16\n\t\t\tadd\t\teax,ebx\t\t\t\t// eax now contains pattern\n\t\t\tmov\t\tecx,count\n\t\t\tcmp\t\tecx,4\n\t\t\tjl\t\tskip4\n\t\t\tmov\t\t[edx],eax\t\t\t// copy first dword\n\t\t\tadd\t\tedx,4\n\t\t\tsub\t\tecx,4\n\tskip4:\tcmp\t\tecx,2\n\t\t\tjl\t\tskip2\n\t\t\tmov\t\tword ptr [edx],ax\t// copy 2 bytes\n\t\t\tadd\t\tedx,2\n\t\t\tsub\t\tecx,2\n\tskip2:\tcmp\t\tecx,0\n\t\t\tje\t\tskip1\n\t\t\tmov\t\tbyte ptr [edx],al\t// copy single byte\n\tskip1:\n\t\t}\n\t\treturn;\n\t}\n\n\tfillval = val;\n\t\n\tfillval = fillval|(fillval<<8);\n\tfillval = fillval|(fillval<<16);\t\t// fill dword with 8-bit pattern\n\n\t_copyDWord ((unsigned int*)(dest),fillval, count/4);\n\t\n\t__asm\t\t\t\t\t\t\t\t\t// padding of 0-3 bytes\n\t{\n\t\tmov\t\tecx,count\n\t\tmov\t\teax,ecx\n\t\tand\t\tecx,3\n\t\tjz\t\tskipA\n\t\tand\t\teax,~3\n\t\tmov\t\tebx,dest\n\t\tadd\t\tebx,eax\n\t\tmov\t\teax,fillval\n\t\tcmp\t\tecx,2\n\t\tjl\t\tskipB\n\t\tmov\t\tword ptr [ebx],ax\n\t\tcmp\t\tecx,2\n\t\tje\t\tskipA\t\t\t\t\t\n\t\tmov\t\tbyte ptr [ebx+2],al\t\t\n\t\tjmp\t\tskipA\nskipB:\t\t\n\t\tcmp\t\tecx,0\n\t\tje\t\tskipA\n\t\tmov\t\tbyte ptr [ebx],al\nskipA:\n\t}\n}\n\nqboolean Com_Memcmp (const void *src0, const void *src1, const unsigned int count)\n{\n\tunsigned int i;\n\t// MMX version anyone?\n\n\tif (count >= 16)\n\t{\n\t\tunsigned int *dw = (unsigned int*)(src0);\n\t\tunsigned int *sw = (unsigned int*)(src1);\n\n\t\tunsigned int nm2 = count/16;\n\t\tfor (i = 0; i < nm2; i+=4)\n\t\t{\n\t\t\tunsigned int tmp = (dw[i+0]-sw[i+0])|(dw[i+1]-sw[i+1])|\n\t\t\t\t\t\t  (dw[i+2]-sw[i+2])|(dw[i+3]-sw[i+3]);\n\t\t\tif (tmp)\n\t\t\t\treturn qfalse;\n\t\t}\n\t}\n\tif (count & 15)\n\t{\n\t\tbyte *d = (byte*)src0;\n\t\tbyte *s = (byte*)src1;\n\t\tfor (i = count & 0xfffffff0; i < count; i++)\n\t\tif (d[i]!=s[i])\n\t\t\treturn qfalse;\n\t}\n\n\treturn qtrue;\n}\n\nvoid Com_Prefetch (const void *s, const unsigned int bytes, e_prefetch type)\n{\n\t// write buffer prefetching is performed only if\n\t// the processor benefits from it. Read and read/write\n\t// prefetching is always performed.\n\n\tswitch (type)\n\t{\n\t\tcase PRE_WRITE : break;\n\t\tcase PRE_READ:\n\t\tcase PRE_READ_WRITE:\n\n\t\t__asm\n\t\t{\n\t\t\tmov\t\tebx,s\n\t\t\tmov\t\tecx,bytes\n\t\t\tcmp\t\tecx,4096\t\t\t\t// clamp to 4kB\n\t\t\tjle\t\tskipClamp\n\t\t\tmov\t\tecx,4096\nskipClamp:\n\t\t\tadd\t\tecx,0x1f\n\t\t\tshr\t\tecx,5\t\t\t\t\t// number of cache lines\n\t\t\tjz\t\tskip\n\t\t\tjmp\t\tloopie\n\n\t\t\talign 16\n\tloopie:\ttest\tbyte ptr [ebx],al\n\t\t\tadd\t\tebx,32\n\t\t\tdec\t\tecx\n\t\t\tjnz\t\tloopie\n\tskip:\n\t\t}\n\n\t\tbreak;\n\t}\n}\n#endif\n#endif \n#endif // bk001208 - memset/memcpy assembly, Q_acos needed (RC4)\n//------------------------------------------------------------------------\n\n\n/*\n=====================\nQ_acos\n\nthe msvc acos doesn't always return a value between -PI and PI:\n\nint i;\ni = 1065353246;\nacos(*(float*) &i) == -1.#IND0\n\n\tThis should go in q_math but it is too late to add new traps\n\tto game and ui\n=====================\n*/\nfloat Q_acos(float c) {\n\tfloat angle;\n\n\tangle = acos(c);\n\n\tif (angle > M_PI) {\n\t\treturn (float)M_PI;\n\t}\n\tif (angle < -M_PI) {\n\t\treturn (float)M_PI;\n\t}\n\treturn angle;\n}\n\n/*\n===========================================\ncommand line completion\n===========================================\n*/\n\n/*\n==================\nField_Clear\n==================\n*/\nvoid Field_Clear( field_t *edit ) {\n  memset(edit->buffer, 0, MAX_EDIT_LINE);\n\tedit->cursor = 0;\n\tedit->scroll = 0;\n}\n\nstatic const char *completionString;\nstatic char shortestMatch[MAX_TOKEN_CHARS];\nstatic int\tmatchCount;\n// field we are working on, passed to Field_CompleteCommand (&g_consoleCommand for instance)\nstatic field_t *completionField;\n\n/*\n===============\nFindMatches\n\n===============\n*/\nstatic void FindMatches( const char *s ) {\n\tint\t\ti;\n\n\tif ( Q_stricmpn( s, completionString, (int)strlen( completionString ) ) ) {\n\t\treturn;\n\t}\n\tmatchCount++;\n\tif ( matchCount == 1 ) {\n\t\tQ_strncpyz( shortestMatch, s, sizeof( shortestMatch ) );\n\t\treturn;\n\t}\n\n\t// cut shortestMatch to the amount common with s\n\tfor ( i = 0 ; s[i] ; i++ ) {\n\t\tif ( tolower(shortestMatch[i]) != tolower(s[i]) ) {\n\t\t\tshortestMatch[i] = 0;\n\t\t}\n\t}\n}\n\n/*\n===============\nPrintMatches\n\n===============\n*/\nstatic void PrintMatches( const char *s ) {\n\tif ( !Q_stricmpn( s, shortestMatch, (int)strlen( shortestMatch ) ) ) {\n\t\tCom_Printf( \"    %s\\n\", s );\n\t}\n}\n\nstatic void keyConcatArgs( void ) {\n\tint\t\ti;\n\tchar\t*arg;\n\n\tfor ( i = 1 ; i < Cmd_Argc() ; i++ ) {\n\t\tQ_strcat( completionField->buffer, sizeof( completionField->buffer ), \" \" );\n\t\targ = Cmd_Argv( i );\n\t\twhile (*arg) {\n\t\t\tif (*arg == ' ') {\n\t\t\t\tQ_strcat( completionField->buffer, sizeof( completionField->buffer ),  \"\\\"\");\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\targ++;\n\t\t}\n\t\tQ_strcat( completionField->buffer, sizeof( completionField->buffer ),  Cmd_Argv( i ) );\n\t\tif (*arg == ' ') {\n\t\t\tQ_strcat( completionField->buffer, sizeof( completionField->buffer ),  \"\\\"\");\n\t\t}\n\t}\n}\n\nstatic void ConcatRemaining( const char *src, const char *start ) {\n\tchar *str;\n\n\tstr = (char*) strstr(src, start);\n\tif (!str) {\n\t\tkeyConcatArgs();\n\t\treturn;\n\t}\n\n\tstr += (int)strlen(start);\n\tQ_strcat( completionField->buffer, sizeof( completionField->buffer ), str);\n}\n\n/*\n===============\nField_CompleteCommand\n\nperform Tab expansion\nNOTE TTimo this was originally client code only\n  moved to common code when writing tty console for *nix dedicated server\n===============\n*/\nvoid Field_CompleteCommand( field_t *field ) {\n\tfield_t\t\ttemp;\n\n\tcompletionField = field;\n\n\t// only look at the first token for completion purposes\n\tCmd_TokenizeString( completionField->buffer );\n\n\tcompletionString = Cmd_Argv(0);\n\tif ( completionString[0] == '\\\\' || completionString[0] == '/' ) {\n\t\tcompletionString++;\n\t}\n\tmatchCount = 0;\n\tshortestMatch[0] = 0;\n\n\tif ( (int)strlen( completionString ) == 0 ) {\n\t\treturn;\n\t}\n\n\tCmd_CommandCompletion( FindMatches );\n\tCvar_CommandCompletion( FindMatches );\n\n\tif ( matchCount == 0 ) {\n\t\treturn;\t// no matches\n\t}\n\n\tCom_Memcpy(&temp, completionField, sizeof(field_t));\n\n\tif ( matchCount == 1 ) {\n\t\tCom_sprintf( completionField->buffer, sizeof( completionField->buffer ), \"\\\\%s\", shortestMatch );\n\t\tif ( Cmd_Argc() == 1 ) {\n\t\t\tQ_strcat( completionField->buffer, sizeof( completionField->buffer ), \" \" );\n\t\t} else {\n\t\t\tConcatRemaining( temp.buffer, completionString );\n\t\t}\n\t\tcompletionField->cursor = (int)strlen( completionField->buffer );\n\t\treturn;\n\t}\n\n\t// multiple matches, complete to shortest\n\tCom_sprintf( completionField->buffer, sizeof( completionField->buffer ), \"\\\\%s\", shortestMatch );\n\tcompletionField->cursor = (int)strlen( completionField->buffer );\n\tConcatRemaining( temp.buffer, completionString );\n\n\tCom_Printf( \"]%s\\n\", completionField->buffer );\n\n\t// run through again, printing matches\n\tCmd_CommandCompletion( PrintMatches );\n\tCvar_CommandCompletion( PrintMatches );\n}\n"
  },
  {
    "path": "src/engine/qcommon/cvar.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n// cvar.c -- dynamic variable tracking\n\n#include \"../../game/q_shared.h\"\n#include \"qcommon.h\"\n\ncvar_t\t\t*cvar_vars;\ncvar_t\t\t*cvar_cheats;\nint\t\t\tcvar_modifiedFlags;\n\n#define\tMAX_CVARS\t1024\ncvar_t\t\tcvar_indexes[MAX_CVARS];\nint\t\t\tcvar_numIndexes;\n\n#define FILE_HASH_SIZE\t\t256\nstatic\tcvar_t*\t\thashTable[FILE_HASH_SIZE];\n\ncvar_t *Cvar_Set2( const char *var_name, const char *value, qboolean force);\n\n/*\n================\nreturn a hash value for the filename\n================\n*/\nstatic long generateHashValue( const char *fname ) {\n\tint\t\ti;\n\tlong\thash;\n\tchar\tletter;\n\n\thash = 0;\n\ti = 0;\n\twhile (fname[i] != '\\0') {\n\t\tletter = tolower(fname[i]);\n\t\thash+=(long)(letter)*(i+119);\n\t\ti++;\n\t}\n\thash &= (FILE_HASH_SIZE-1);\n\treturn hash;\n}\n\n/*\n============\nCvar_ValidateString\n============\n*/\nstatic qboolean Cvar_ValidateString( const char *s ) {\n\tif ( !s ) {\n\t\treturn qfalse;\n\t}\n\tif ( strchr( s, '\\\\' ) ) {\n\t\treturn qfalse;\n\t}\n\tif ( strchr( s, '\\\"' ) ) {\n\t\treturn qfalse;\n\t}\n\tif ( strchr( s, ';' ) ) {\n\t\treturn qfalse;\n\t}\n\treturn qtrue;\n}\n\n/*\n============\nCvar_FindVar\n============\n*/\nstatic cvar_t *Cvar_FindVar( const char *var_name ) {\n\tcvar_t\t*var;\n\tlong hash;\n\n\thash = generateHashValue(var_name);\n\t\n\tfor (var=hashTable[hash] ; var ; var=var->hashNext) {\n\t\tif (!Q_stricmp(var_name, var->name)) {\n\t\t\treturn var;\n\t\t}\n\t}\n\n\treturn NULL;\n}\n\n/*\n============\nCvar_VariableValue\n============\n*/\nfloat Cvar_VariableValue( const char *var_name ) {\n\tcvar_t\t*var;\n\t\n\tvar = Cvar_FindVar (var_name);\n\tif (!var)\n\t\treturn 0;\n\treturn var->value;\n}\n\n\n/*\n============\nCvar_VariableIntegerValue\n============\n*/\nint Cvar_VariableIntegerValue( const char *var_name ) {\n\tcvar_t\t*var;\n\t\n\tvar = Cvar_FindVar (var_name);\n\tif (!var)\n\t\treturn 0;\n\treturn var->integer;\n}\n\n\n/*\n============\nCvar_VariableString\n============\n*/\nchar *Cvar_VariableString( const char *var_name ) {\n\tcvar_t *var;\n\t\n\tvar = Cvar_FindVar (var_name);\n\tif (!var)\n\t\treturn \"\";\n\treturn var->string;\n}\n\n\n/*\n============\nCvar_VariableStringBuffer\n============\n*/\nvoid Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize ) {\n\tcvar_t *var;\n\t\n\tvar = Cvar_FindVar (var_name);\n\tif (!var) {\n\t\t*buffer = 0;\n\t}\n\telse {\n\t\tQ_strncpyz( buffer, var->string, bufsize );\n\t}\n}\n\n\n/*\n============\nCvar_CommandCompletion\n============\n*/\nvoid\tCvar_CommandCompletion( void(*callback)(const char *s) ) {\n\tcvar_t\t\t*cvar;\n\t\n\tfor ( cvar = cvar_vars ; cvar ; cvar = cvar->next ) {\n\t\tcallback( cvar->name );\n\t}\n}\n\n\n/*\n============\nCvar_Get\n\nIf the variable already exists, the value will not be set unless CVAR_ROM\nThe flags will be or'ed in if the variable exists.\n============\n*/\ncvar_t *Cvar_Get( const char *var_name, const char *var_value, int flags ) {\n\tcvar_t\t*var;\n\tlong\thash;\n\n  if ( !var_name || ! var_value ) {\n\t\tCom_Error( ERR_FATAL, \"Cvar_Get: NULL parameter\" );\n  }\n\n\tif ( !Cvar_ValidateString( var_name ) ) {\n\t\tCom_Printf(\"invalid cvar name string: %s\\n\", var_name );\n\t\tvar_name = \"BADNAME\";\n\t}\n\n#if 0\t\t// FIXME: values with backslash happen\n\tif ( !Cvar_ValidateString( var_value ) ) {\n\t\tCom_Printf(\"invalid cvar value string: %s\\n\", var_value );\n\t\tvar_value = \"BADVALUE\";\n\t}\n#endif\n\n\tvar = Cvar_FindVar (var_name);\n\tif ( var ) {\n\t\t// if the C code is now specifying a variable that the user already\n\t\t// set a value for, take the new value as the reset value\n\t\tif ( ( var->flags & CVAR_USER_CREATED ) && !( flags & CVAR_USER_CREATED )\n\t\t\t&& var_value[0] ) {\n\t\t\tvar->flags &= ~CVAR_USER_CREATED;\n\t\t\tZ_Free( var->resetString );\n\t\t\tvar->resetString = CopyString( var_value );\n\n\t\t\t// ZOID--needs to be set so that cvars the game sets as \n\t\t\t// SERVERINFO get sent to clients\n\t\t\tcvar_modifiedFlags |= flags;\n\t\t}\n\n\t\tvar->flags |= flags;\n\t\t// only allow one non-empty reset string without a warning\n\t\tif ( !var->resetString[0] ) {\n\t\t\t// we don't have a reset string yet\n\t\t\tZ_Free( var->resetString );\n\t\t\tvar->resetString = CopyString( var_value );\n\t\t} else if ( var_value[0] && strcmp( var->resetString, var_value ) ) {\n\t\t\tCom_DPrintf( \"Warning: cvar \\\"%s\\\" given initial values: \\\"%s\\\" and \\\"%s\\\"\\n\",\n\t\t\t\tvar_name, var->resetString, var_value );\n\t\t}\n\t\t// if we have a latched string, take that value now\n\t\tif ( var->latchedString ) {\n\t\t\tchar *s;\n\n\t\t\ts = var->latchedString;\n\t\t\tvar->latchedString = NULL;\t// otherwise cvar_set2 would free it\n\t\t\tCvar_Set2( var_name, s, qtrue );\n\t\t\tZ_Free( s );\n\t\t}\n\n// use a CVAR_SET for rom sets, get won't override\n#if 0\n\t\t// CVAR_ROM always overrides\n\t\tif ( flags & CVAR_ROM ) {\n\t\t\tCvar_Set2( var_name, var_value, qtrue );\n\t\t}\n#endif\n\t\treturn var;\n\t}\n\n\t//\n\t// allocate a new cvar\n\t//\n\tif ( cvar_numIndexes >= MAX_CVARS ) {\n\t\tCom_Error( ERR_FATAL, \"MAX_CVARS\" );\n\t}\n\tvar = &cvar_indexes[cvar_numIndexes];\n\tcvar_numIndexes++;\n\tvar->name = CopyString (var_name);\n\tvar->string = CopyString (var_value);\n\tvar->modified = qtrue;\n\tvar->modificationCount = 1;\n\tvar->value = atof (var->string);\n\tvar->integer = atoi(var->string);\n\tvar->resetString = CopyString( var_value );\n\n\t// link the variable in\n\tvar->next = cvar_vars;\n\tcvar_vars = var;\n\n\tvar->flags = flags;\n\n\thash = generateHashValue(var_name);\n\tvar->hashNext = hashTable[hash];\n\thashTable[hash] = var;\n\n\treturn var;\n}\n\n/*\n============\nCvar_Set2\n============\n*/\ncvar_t *Cvar_Set2( const char *var_name, const char *value, qboolean force ) {\n\tcvar_t\t*var;\n\n\tCom_DPrintf( \"Cvar_Set2: %s %s\\n\", var_name, value );\n\n\tif ( !Cvar_ValidateString( var_name ) ) {\n\t\tCom_Printf(\"invalid cvar name string: %s\\n\", var_name );\n\t\tvar_name = \"BADNAME\";\n\t}\n\n#if 0\t// FIXME\n\tif ( value && !Cvar_ValidateString( value ) ) {\n\t\tCom_Printf(\"invalid cvar value string: %s\\n\", value );\n\t\tvar_value = \"BADVALUE\";\n\t}\n#endif\n\n\tvar = Cvar_FindVar (var_name);\n\tif (!var) {\n\t\tif ( !value ) {\n\t\t\treturn NULL;\n\t\t}\n\t\t// create it\n\t\tif ( !force ) {\n\t\t\treturn Cvar_Get( var_name, value, CVAR_USER_CREATED );\n\t\t} else {\n\t\t\treturn Cvar_Get (var_name, value, 0);\n\t\t}\n\t}\n\n\tif (!value ) {\n\t\tvalue = var->resetString;\n\t}\n\n\tif (!strcmp(value,var->string)) {\n\t\treturn var;\n\t}\n\t// note what types of cvars have been modified (userinfo, archive, serverinfo, systeminfo)\n\tcvar_modifiedFlags |= var->flags;\n\n\tif (!force)\n\t{\n\t\tif (var->flags & CVAR_ROM)\n\t\t{\n\t\t\tCom_Printf (\"%s is read only.\\n\", var_name);\n\t\t\treturn var;\n\t\t}\n\n\t\tif (var->flags & CVAR_INIT)\n\t\t{\n\t\t\tCom_Printf (\"%s is write protected.\\n\", var_name);\n\t\t\treturn var;\n\t\t}\n\n\t\tif (var->flags & CVAR_LATCH)\n\t\t{\n\t\t\tif (var->latchedString)\n\t\t\t{\n\t\t\t\tif (strcmp(value, var->latchedString) == 0)\n\t\t\t\t\treturn var;\n\t\t\t\tZ_Free (var->latchedString);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (strcmp(value, var->string) == 0)\n\t\t\t\t\treturn var;\n\t\t\t}\n\n\t\t\tCom_Printf (\"%s will be changed upon restarting.\\n\", var_name);\n\t\t\tvar->latchedString = CopyString(value);\n\t\t\tvar->modified = qtrue;\n\t\t\tvar->modificationCount++;\n\t\t\treturn var;\n\t\t}\n\n\t\tif ( (var->flags & CVAR_CHEAT) && !cvar_cheats->integer )\n\t\t{\n\t\t\tCom_Printf (\"%s is cheat protected.\\n\", var_name);\n\t\t\treturn var;\n\t\t}\n\n\t}\n\telse\n\t{\n\t\tif (var->latchedString)\n\t\t{\n\t\t\tZ_Free (var->latchedString);\n\t\t\tvar->latchedString = NULL;\n\t\t}\n\t}\n\n\tif (!strcmp(value, var->string))\n\t\treturn var;\t\t// not changed\n\n\tvar->modified = qtrue;\n\tvar->modificationCount++;\n\t\n\tZ_Free (var->string);\t// free the old value string\n\t\n\tvar->string = CopyString(value);\n\tvar->value = atof (var->string);\n\tvar->integer = atoi (var->string);\n\n\treturn var;\n}\n\n/*\n============\nCvar_Set\n============\n*/\nvoid Cvar_Set( const char *var_name, const char *value) {\n\tCvar_Set2 (var_name, value, qtrue);\n}\n\n/*\n============\nCvar_SetLatched\n============\n*/\nvoid Cvar_SetLatched( const char *var_name, const char *value) {\n\tCvar_Set2 (var_name, value, qfalse);\n}\n\n/*\n============\nCvar_SetValue\n============\n*/\nvoid Cvar_SetValue( const char *var_name, float value) {\n\tchar\tval[32];\n\n\tif ( value == (int)value ) {\n\t\tCom_sprintf (val, sizeof(val), \"%i\",(int)value);\n\t} else {\n\t\tCom_sprintf (val, sizeof(val), \"%f\",value);\n\t}\n\tCvar_Set (var_name, val);\n}\n\n\n/*\n============\nCvar_Reset\n============\n*/\nvoid Cvar_Reset( const char *var_name ) {\n\tCvar_Set2( var_name, NULL, qfalse );\n}\n\n\n/*\n============\nCvar_SetCheatState\n\nAny testing variables will be reset to the safe values\n============\n*/\nvoid Cvar_SetCheatState( void ) {\n\tcvar_t\t*var;\n\n\t// set all default vars to the safe value\n\tfor ( var = cvar_vars ; var ; var = var->next ) {\n\t\tif ( var->flags & CVAR_CHEAT ) {\n      // the CVAR_LATCHED|CVAR_CHEAT vars might escape the reset here \n      // because of a different var->latchedString\n      if (var->latchedString)\n      {\n        Z_Free(var->latchedString);\n        var->latchedString = NULL;\n      }\n\t\t\tif (strcmp(var->resetString,var->string)) {\n        Cvar_Set( var->name, var->resetString );\n\t\t\t}\n\t\t}\n\t}\n}\n\n/*\n============\nCvar_Command\n\nHandles variable inspection and changing from the console\n============\n*/\nqboolean Cvar_Command( void ) {\n\tcvar_t\t\t\t*v;\n\n\t// check variables\n\tv = Cvar_FindVar (Cmd_Argv(0));\n\tif (!v) {\n\t\treturn qfalse;\n\t}\n\n\t// perform a variable print or set\n\tif ( Cmd_Argc() == 1 ) {\n\t\tCom_Printf (\"\\\"%s\\\" is:\\\"%s\" S_COLOR_WHITE \"\\\" default:\\\"%s\" S_COLOR_WHITE \"\\\"\\n\", v->name, v->string, v->resetString );\n\t\tif ( v->latchedString ) {\n\t\t\tCom_Printf( \"latched: \\\"%s\\\"\\n\", v->latchedString );\n\t\t}\n\t\treturn qtrue;\n\t}\n\n\t// set the value if forcing isn't required\n\tCvar_Set2 (v->name, Cmd_Argv(1), qfalse);\n\treturn qtrue;\n}\n\n\n/*\n============\nCvar_Toggle_f\n\nToggles a cvar for easy single key binding\n============\n*/\nvoid Cvar_Toggle_f( void ) {\n\tint\t\tv;\n\n\tif ( Cmd_Argc() != 2 ) {\n\t\tCom_Printf (\"usage: toggle <variable>\\n\");\n\t\treturn;\n\t}\n\n\tv = Cvar_VariableValue( Cmd_Argv( 1 ) );\n\tv = !v;\n\n\tCvar_Set2 (Cmd_Argv(1), va(\"%i\", v), qfalse);\n}\n\n/*\n============\nCvar_Set_f\n\nAllows setting and defining of arbitrary cvars from console, even if they\nweren't declared in C code.\n============\n*/\nvoid Cvar_Set_f( void ) {\n\tint\t\ti, c, l, len;\n\tchar\tcombined[MAX_STRING_TOKENS];\n\n\tc = Cmd_Argc();\n\tif ( c < 3 ) {\n\t\tCom_Printf (\"usage: set <variable> <value>\\n\");\n\t\treturn;\n\t}\n\n\tcombined[0] = 0;\n\tl = 0;\n\tfor ( i = 2 ; i < c ; i++ ) {\n\t\tlen = (int)strlen ( Cmd_Argv( i ) + 1 );\n\t\tif ( l + len >= MAX_STRING_TOKENS - 2 ) {\n\t\t\tbreak;\n\t\t}\n\t\tstrcat( combined, Cmd_Argv( i ) );\n\t\tif ( i != c-1 ) {\n\t\t\tstrcat( combined, \" \" );\n\t\t}\n\t\tl += len;\n\t}\n\tCvar_Set2 (Cmd_Argv(1), combined, qfalse);\n}\n\n/*\n============\nCvar_SetU_f\n\nAs Cvar_Set, but also flags it as userinfo\n============\n*/\nvoid Cvar_SetU_f( void ) {\n\tcvar_t\t*v;\n\n\tif ( Cmd_Argc() != 3 ) {\n\t\tCom_Printf (\"usage: setu <variable> <value>\\n\");\n\t\treturn;\n\t}\n\tCvar_Set_f();\n\tv = Cvar_FindVar( Cmd_Argv( 1 ) );\n\tif ( !v ) {\n\t\treturn;\n\t}\n\tv->flags |= CVAR_USERINFO;\n}\n\n/*\n============\nCvar_SetS_f\n\nAs Cvar_Set, but also flags it as userinfo\n============\n*/\nvoid Cvar_SetS_f( void ) {\n\tcvar_t\t*v;\n\n\tif ( Cmd_Argc() != 3 ) {\n\t\tCom_Printf (\"usage: sets <variable> <value>\\n\");\n\t\treturn;\n\t}\n\tCvar_Set_f();\n\tv = Cvar_FindVar( Cmd_Argv( 1 ) );\n\tif ( !v ) {\n\t\treturn;\n\t}\n\tv->flags |= CVAR_SERVERINFO;\n}\n\n/*\n============\nCvar_SetA_f\n\nAs Cvar_Set, but also flags it as archived\n============\n*/\nvoid Cvar_SetA_f( void ) {\n\tcvar_t\t*v;\n\n\tif ( Cmd_Argc() != 3 ) {\n\t\tCom_Printf (\"usage: seta <variable> <value>\\n\");\n\t\treturn;\n\t}\n\tCvar_Set_f();\n\tv = Cvar_FindVar( Cmd_Argv( 1 ) );\n\tif ( !v ) {\n\t\treturn;\n\t}\n\tv->flags |= CVAR_ARCHIVE;\n}\n\n/*\n============\nCvar_Reset_f\n============\n*/\nvoid Cvar_Reset_f( void ) {\n\tif ( Cmd_Argc() != 2 ) {\n\t\tCom_Printf (\"usage: reset <variable>\\n\");\n\t\treturn;\n\t}\n\tCvar_Reset( Cmd_Argv( 1 ) );\n}\n\n/*\n============\nCvar_WriteVariables\n\nAppends lines containing \"set variable value\" for all variables\nwith the archive flag set to qtrue.\n============\n*/\nvoid Cvar_WriteVariables( fileHandle_t f ) {\n\tcvar_t\t*var;\n\tchar\tbuffer[1024];\n\n\tfor (var = cvar_vars ; var ; var = var->next) {\n\t\tif( Q_stricmp( var->name, \"cl_cdkey\" ) == 0 ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif( var->flags & CVAR_ARCHIVE ) {\n\t\t\t// write the latched value, even if it hasn't taken effect yet\n\t\t\tif ( var->latchedString ) {\n\t\t\t\tCom_sprintf (buffer, sizeof(buffer), \"seta %s \\\"%s\\\"\\n\", var->name, var->latchedString);\n\t\t\t} else {\n\t\t\t\tCom_sprintf (buffer, sizeof(buffer), \"seta %s \\\"%s\\\"\\n\", var->name, var->string);\n\t\t\t}\n\t\t\tFS_Printf (f, \"%s\", buffer);\n\t\t}\n\t}\n}\n\n/*\n============\nCvar_List_f\n============\n*/\nvoid Cvar_List_f( void ) {\n\tcvar_t\t*var;\n\tint\t\ti;\n\tchar\t*match;\n\n\tif ( Cmd_Argc() > 1 ) {\n\t\tmatch = Cmd_Argv( 1 );\n\t} else {\n\t\tmatch = NULL;\n\t}\n\n\ti = 0;\n\tfor (var = cvar_vars ; var ; var = var->next, i++)\n\t{\n\t\tif (match && !Com_Filter(match, var->name, qfalse)) continue;\n\n\t\tif (var->flags & CVAR_SERVERINFO) {\n\t\t\tCom_Printf(\"S\");\n\t\t} else {\n\t\t\tCom_Printf(\" \");\n\t\t}\n\t\tif (var->flags & CVAR_USERINFO) {\n\t\t\tCom_Printf(\"U\");\n\t\t} else {\n\t\t\tCom_Printf(\" \");\n\t\t}\n\t\tif (var->flags & CVAR_ROM) {\n\t\t\tCom_Printf(\"R\");\n\t\t} else {\n\t\t\tCom_Printf(\" \");\n\t\t}\n\t\tif (var->flags & CVAR_INIT) {\n\t\t\tCom_Printf(\"I\");\n\t\t} else {\n\t\t\tCom_Printf(\" \");\n\t\t}\n\t\tif (var->flags & CVAR_ARCHIVE) {\n\t\t\tCom_Printf(\"A\");\n\t\t} else {\n\t\t\tCom_Printf(\" \");\n\t\t}\n\t\tif (var->flags & CVAR_LATCH) {\n\t\t\tCom_Printf(\"L\");\n\t\t} else {\n\t\t\tCom_Printf(\" \");\n\t\t}\n\t\tif (var->flags & CVAR_CHEAT) {\n\t\t\tCom_Printf(\"C\");\n\t\t} else {\n\t\t\tCom_Printf(\" \");\n\t\t}\n\n\t\tCom_Printf (\" %s \\\"%s\\\"\\n\", var->name, var->string);\n\t}\n\n\tCom_Printf (\"\\n%i total cvars\\n\", i);\n\tCom_Printf (\"%i cvar indexes\\n\", cvar_numIndexes);\n}\n\n/*\n============\nCvar_Restart_f\n\nResets all cvars to their hardcoded values\n============\n*/\nvoid Cvar_Restart_f( void ) {\n\tcvar_t\t*var;\n\tcvar_t\t**prev;\n\n\tprev = &cvar_vars;\n\twhile ( 1 ) {\n\t\tvar = *prev;\n\t\tif ( !var ) {\n\t\t\tbreak;\n\t\t}\n\n\t\t// don't mess with rom values, or some inter-module\n\t\t// communication will get broken (com_cl_running, etc)\n\t\tif ( var->flags & ( CVAR_ROM | CVAR_INIT | CVAR_NORESTART ) ) {\n\t\t\tprev = &var->next;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// throw out any variables the user created\n\t\tif ( var->flags & CVAR_USER_CREATED ) {\n\t\t\t*prev = var->next;\n\t\t\tif ( var->name ) {\n\t\t\t\tZ_Free( var->name );\n\t\t\t}\n\t\t\tif ( var->string ) {\n\t\t\t\tZ_Free( var->string );\n\t\t\t}\n\t\t\tif ( var->latchedString ) {\n\t\t\t\tZ_Free( var->latchedString );\n\t\t\t}\n\t\t\tif ( var->resetString ) {\n\t\t\t\tZ_Free( var->resetString );\n\t\t\t}\n\t\t\t// clear the var completely, since we\n\t\t\t// can't remove the index from the list\n\t\t\tCom_Memset( var, 0, sizeof( var ) );\n\t\t\tcontinue;\n\t\t}\n\n\t\tCvar_Set( var->name, var->resetString );\n\n\t\tprev = &var->next;\n\t}\n}\n\n\n\n/*\n=====================\nCvar_InfoString\n=====================\n*/\nchar\t*Cvar_InfoString( int bit ) {\n\tstatic char\tinfo[MAX_INFO_STRING];\n\tcvar_t\t*var;\n\n\tinfo[0] = 0;\n\n\tfor (var = cvar_vars ; var ; var = var->next) {\n\t\tif (var->flags & bit) {\n\t\t\tInfo_SetValueForKey (info, var->name, var->string);\n\t\t}\n\t}\n\treturn info;\n}\n\n/*\n=====================\nCvar_InfoString_Big\n\n  handles large info strings ( CS_SYSTEMINFO )\n=====================\n*/\nchar\t*Cvar_InfoString_Big( int bit ) {\n\tstatic char\tinfo[BIG_INFO_STRING];\n\tcvar_t\t*var;\n\n\tinfo[0] = 0;\n\n\tfor (var = cvar_vars ; var ; var = var->next) {\n\t\tif (var->flags & bit) {\n\t\t\tInfo_SetValueForKey_Big (info, var->name, var->string);\n\t\t}\n\t}\n\treturn info;\n}\n\n\n\n/*\n=====================\nCvar_InfoStringBuffer\n=====================\n*/\nvoid Cvar_InfoStringBuffer( int bit, char* buff, int buffsize ) {\n\tQ_strncpyz(buff,Cvar_InfoString(bit),buffsize);\n}\n\n/*\n=====================\nCvar_Register\n\nbasically a slightly modified Cvar_Get for the interpreted modules\n=====================\n*/\nvoid\tCvar_Register( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags ) {\n\tcvar_t\t*cv;\n\n\tcv = Cvar_Get( varName, defaultValue, flags );\n\tif ( !vmCvar ) {\n\t\treturn;\n\t}\n\tvmCvar->handle = cv - cvar_indexes;\n\tvmCvar->modificationCount = -1;\n\tCvar_Update( vmCvar );\n}\n\n\n/*\n=====================\nCvar_Register\n\nupdates an interpreted modules' version of a cvar\n=====================\n*/\nvoid\tCvar_Update( vmCvar_t *vmCvar ) {\n\tcvar_t\t*cv = NULL; // bk001129\n\tassert(vmCvar); // bk\n\n\tif ( (unsigned)vmCvar->handle >= cvar_numIndexes ) {\n\t\tCom_Error( ERR_DROP, \"Cvar_Update: handle out of range\" );\n\t}\n\n\tcv = cvar_indexes + vmCvar->handle;\n\n\tif ( cv->modificationCount == vmCvar->modificationCount ) {\n\t\treturn;\n\t}\n\tif ( !cv->string ) {\n\t\treturn;\t\t// variable might have been cleared by a cvar_restart\n\t}\n\tvmCvar->modificationCount = cv->modificationCount;\n\t// bk001129 - mismatches.\n\tif ( (int)strlen(cv->string)+1 > MAX_CVAR_VALUE_STRING ) \n\t  Com_Error( ERR_DROP, \"Cvar_Update: src %s length %d exceeds MAX_CVAR_VALUE_STRING\",\n\t\t     cv->string, \n\t\t     (int)strlen(cv->string), \n\t\t     sizeof(vmCvar->string) );\n\t// bk001212 - Q_strncpyz guarantees zero padding and dest[MAX_CVAR_VALUE_STRING-1]==0 \n\t// bk001129 - paranoia. Never trust the destination string.\n\t// bk001129 - beware, sizeof(char*) is always 4 (for cv->string). \n\t//            sizeof(vmCvar->string) always MAX_CVAR_VALUE_STRING\n\t//Q_strncpyz( vmCvar->string, cv->string, sizeof( vmCvar->string ) ); // id\n\tQ_strncpyz( vmCvar->string, cv->string,  MAX_CVAR_VALUE_STRING ); \n\n\tvmCvar->value = cv->value;\n\tvmCvar->integer = cv->integer;\n}\n\n\n/*\n============\nCvar_Init\n\nReads in all archived cvars\n============\n*/\nvoid Cvar_Init (void) {\n\tcvar_cheats = Cvar_Get(\"sv_cheats\", \"1\", CVAR_ROM | CVAR_SYSTEMINFO );\n\n\tCmd_AddCommand (\"toggle\", Cvar_Toggle_f);\n\tCmd_AddCommand (\"set\", Cvar_Set_f);\n\tCmd_AddCommand (\"sets\", Cvar_SetS_f);\n\tCmd_AddCommand (\"setu\", Cvar_SetU_f);\n\tCmd_AddCommand (\"seta\", Cvar_SetA_f);\n\tCmd_AddCommand (\"reset\", Cvar_Reset_f);\n\tCmd_AddCommand (\"cvarlist\", Cvar_List_f);\n\tCmd_AddCommand (\"cvar_restart\", Cvar_Restart_f);\n}\n"
  },
  {
    "path": "src/engine/qcommon/files.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n/*****************************************************************************\n * name:\t\tfiles.c\n *\n * desc:\t\thandle based filesystem for Quake III Arena \n *\n * $Archive: /MissionPack/code/qcommon/files.c $\n *\n *****************************************************************************/\n\n\n#include \"../../game/q_shared.h\"\n#include \"qcommon.h\"\n#include \"unzip.h\"\n\n/*\n=============================================================================\n\nQUAKE3 FILESYSTEM\n\nAll of Quake's data access is through a hierarchical file system, but the contents of \nthe file system can be transparently merged from several sources.\n\nA \"qpath\" is a reference to game file data.  MAX_ZPATH is 256 characters, which must include\na terminating zero. \"..\", \"\\\\\", and \":\" are explicitly illegal in qpaths to prevent any\nreferences outside the quake directory system.\n\nThe \"base path\" is the path to the directory holding all the game directories and usually\nthe executable.  It defaults to \".\", but can be overridden with a \"+set fs_basepath c:\\quake3\"\ncommand line to allow code debugging in a different directory.  Basepath cannot\nbe modified at all after startup.  Any files that are created (demos, screenshots,\netc) will be created reletive to the base path, so base path should usually be writable.\n\nThe \"cd path\" is the path to an alternate hierarchy that will be searched if a file\nis not located in the base path.  A user can do a partial install that copies some\ndata to a base path created on their hard drive and leave the rest on the cd.  Files\nare never writen to the cd path.  It defaults to a value set by the installer, like\n\"e:\\quake3\", but it can be overridden with \"+set ds_cdpath g:\\quake3\".\n\nIf a user runs the game directly from a CD, the base path would be on the CD.  This\nshould still function correctly, but all file writes will fail (harmlessly).\n\nThe \"home path\" is the path used for all write access. On win32 systems we have \"base path\"\n== \"home path\", but on *nix systems the base installation is usually readonly, and\n\"home path\" points to ~/.q3a or similar\n\nThe user can also install custom mods and content in \"home path\", so it should be searched\nalong with \"home path\" and \"cd path\" for game content.\n\n\nThe \"base game\" is the directory under the paths where data comes from by default, and\ncan be either \"baseq3\" or \"demoq3\".\n\nThe \"current game\" may be the same as the base game, or it may be the name of another\ndirectory under the paths that should be searched for files before looking in the base game.\nThis is the basis for addons.\n\nClients automatically set the game directory after receiving a gamestate from a server,\nso only servers need to worry about +set fs_game.\n\nNo other directories outside of the base game and current game will ever be referenced by\nfilesystem functions.\n\nTo save disk space and speed loading, directory trees can be collapsed into zip files.\nThe files use a \".pk3\" extension to prevent users from unzipping them accidentally, but\notherwise the are simply normal uncompressed zip files.  A game directory can have multiple\nzip files of the form \"pak0.pk3\", \"pak1.pk3\", etc.  Zip files are searched in decending order\nfrom the highest number to the lowest, and will always take precedence over the filesystem.\nThis allows a pk3 distributed as a patch to override all existing data.\n\nBecause we will have updated executables freely available online, there is no point to\ntrying to restrict demo / oem versions of the game with code changes.  Demo / oem versions\nshould be exactly the same executables as release versions, but with different data that\nautomatically restricts where game media can come from to prevent add-ons from working.\n\nAfter the paths are initialized, quake will look for the product.txt file.  If not\nfound and verified, the game will run in restricted mode.  In restricted mode, only \nfiles contained in demoq3/pak0.pk3 will be available for loading, and only if the zip header is\nverified to not have been modified.  A single exception is made for q3config.cfg.  Files\ncan still be written out in restricted mode, so screenshots and demos are allowed.\nRestricted mode can be tested by setting \"+set fs_restrict 1\" on the command line, even\nif there is a valid product.txt under the basepath or cdpath.\n\nIf not running in restricted mode, and a file is not found in any local filesystem,\nan attempt will be made to download it and save it under the base path.\n\nIf the \"fs_copyfiles\" cvar is set to 1, then every time a file is sourced from the cd\npath, it will be copied over to the base path.  This is a development aid to help build\ntest releases and to copy working sets over slow network links.\n\nFile search order: when FS_FOpenFileRead gets called it will go through the fs_searchpaths\nstructure and stop on the first successful hit. fs_searchpaths is built with successive\ncalls to FS_AddGameDirectory\n\nAdditionaly, we search in several subdirectories:\ncurrent game is the current mode\nbase game is a variable to allow mods based on other mods\n(such as baseq3 + missionpack content combination in a mod for instance)\nBASEGAME is the hardcoded base game (\"baseq3\")\n\ne.g. the qpath \"sound/newstuff/test.wav\" would be searched for in the following places:\n\nhome path + current game's zip files\nhome path + current game's directory\nbase path + current game's zip files\nbase path + current game's directory\ncd path + current game's zip files\ncd path + current game's directory\n\nhome path + base game's zip file\nhome path + base game's directory\nbase path + base game's zip file\nbase path + base game's directory\ncd path + base game's zip file\ncd path + base game's directory\n\nhome path + BASEGAME's zip file\nhome path + BASEGAME's directory\nbase path + BASEGAME's zip file\nbase path + BASEGAME's directory\ncd path + BASEGAME's zip file\ncd path + BASEGAME's directory\n\nserver download, to be written to home path + current game's directory\n\n\nThe filesystem can be safely shutdown and reinitialized with different\nbasedir / cddir / game combinations, but all other subsystems that rely on it\n(sound, video) must also be forced to restart.\n\nBecause the same files are loaded by both the clip model (CM_) and renderer (TR_)\nsubsystems, a simple single-file caching scheme is used.  The CM_ subsystems will\nload the file with a request to cache.  Only one file will be kept cached at a time,\nso any models that are going to be referenced by both subsystems should alternate\nbetween the CM_ load function and the ref load function.\n\nTODO: A qpath that starts with a leading slash will always refer to the base game, even if another\ngame is currently active.  This allows character models, skins, and sounds to be downloaded\nto a common directory no matter which game is active.\n\nHow to prevent downloading zip files?\nPass pk3 file names in systeminfo, and download before FS_Restart()?\n\nAborting a download disconnects the client from the server.\n\nHow to mark files as downloadable?  Commercial add-ons won't be downloadable.\n\nNon-commercial downloads will want to download the entire zip file.\nthe game would have to be reset to actually read the zip in\n\nAuto-update information\n\nPath separators\n\nCasing\n\n  separate server gamedir and client gamedir, so if the user starts\n  a local game after having connected to a network game, it won't stick\n  with the network game.\n\n  allow menu options for game selection?\n\nRead / write config to floppy option.\n\nDifferent version coexistance?\n\nWhen building a pak file, make sure a q3config.cfg isn't present in it,\nor configs will never get loaded from disk!\n\n  todo:\n\n  downloading (outside fs?)\n  game directory passing and restarting\n\n=============================================================================\n\n*/\n\n#define\tDEMOGAME\t\t\t\"demota\"\n\n// every time a new demo pk3 file is built, this checksum must be updated.\n// the easiest way to get it is to just run the game and see what it spits out\n#define\tDEMO_PAK_CHECKSUM\t437558517u\n\n// if this is defined, the executable positively won't work with any paks other\n// than the demo pak, even if productid is present.  This is only used for our\n// last demo release to prevent the mac and linux users from using the demo\n// executable with the production windows pak before the mac/linux products\n// hit the shelves a little later\n// NOW defined in build files\n//#define PRE_RELEASE_TADEMO\n\n#define MAX_ZPATH\t\t\t256\n#define\tMAX_SEARCH_PATHS\t4096\n#define MAX_FILEHASH_SIZE\t1024\n\ntypedef struct fileInPack_s {\n\tchar\t\t\t\t\t*name;\t\t// name of the file\n\tunsigned long\t\t\tpos;\t\t// file info position in zip\n\tstruct\tfileInPack_s*\tnext;\t\t// next file in the hash\n} fileInPack_t;\n\ntypedef struct {\n\tchar\t\t\tpakFilename[MAX_OSPATH];\t// c:\\quake3\\baseq3\\pak0.pk3\n\tchar\t\t\tpakBasename[MAX_OSPATH];\t// pak0\n\tchar\t\t\tpakGamename[MAX_OSPATH];\t// baseq3\n\tunzFile\t\t\thandle;\t\t\t\t\t\t// handle to zip file\n\tint\t\t\t\tchecksum;\t\t\t\t\t// regular checksum\n\tint\t\t\t\tpure_checksum;\t\t\t\t// checksum for pure\n\tint\t\t\t\tnumfiles;\t\t\t\t\t// number of files in pk3\n\tint\t\t\t\treferenced;\t\t\t\t\t// referenced file flags\n\tint\t\t\t\thashSize;\t\t\t\t\t// hash table size (power of 2)\n\tfileInPack_t*\t*hashTable;\t\t\t\t\t// hash table\n\tfileInPack_t*\tbuildBuffer;\t\t\t\t// buffer with the filenames etc.\n} pack_t;\n\ntypedef struct {\n\tchar\t\tpath[MAX_OSPATH];\t\t// c:\\quake3\n\tchar\t\tgamedir[MAX_OSPATH];\t// baseq3\n} directory_t;\n\ntypedef struct searchpath_s {\n\tstruct searchpath_s *next;\n\n\tpack_t\t\t*pack;\t\t// only one of pack / dir will be non NULL\n\tdirectory_t\t*dir;\n} searchpath_t;\n\nstatic\tchar\t\tfs_gamedir[MAX_OSPATH];\t// this will be a single file name with no separators\nstatic\tcvar_t\t\t*fs_debug;\nstatic\tcvar_t\t\t*fs_homepath;\nstatic\tcvar_t\t\t*fs_basepath;\nstatic\tcvar_t\t\t*fs_basegame;\nstatic\tcvar_t\t\t*fs_cdpath;\nstatic\tcvar_t\t\t*fs_copyfiles;\nstatic\tcvar_t\t\t*fs_gamedirvar;\nstatic\tcvar_t\t\t*fs_restrict;\nstatic\tsearchpath_t\t*fs_searchpaths;\nstatic\tint\t\t\tfs_readCount;\t\t\t// total bytes read\nstatic\tint\t\t\tfs_loadCount;\t\t\t// total files read\nstatic\tint\t\t\tfs_loadStack;\t\t\t// total files in memory\nstatic\tint\t\t\tfs_packFiles;\t\t\t// total number of files in packs\n\nstatic int fs_fakeChkSum;\nstatic int fs_checksumFeed;\n\ntypedef union qfile_gus {\n\tFILE*\t\to;\n\tunzFile\t\tz;\n} qfile_gut;\n\ntypedef struct qfile_us {\n\tqfile_gut\tfile;\n\tqboolean\tunique;\n} qfile_ut;\n\ntypedef struct {\n\tqfile_ut\thandleFiles;\n\tqboolean\thandleSync;\n\tint\t\t\tbaseOffset;\n\tint\t\t\tfileSize;\n\tint\t\t\tzipFilePos;\n\tqboolean\tzipFile;\n\tqboolean\tstreamed;\n\tchar\t\tname[MAX_ZPATH];\n} fileHandleData_t;\n\nstatic fileHandleData_t\tfsh[MAX_FILE_HANDLES];\n\n// TTimo - https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=540\n// wether we did a reorder on the current search path when joining the server\nstatic qboolean fs_reordered;\n\n// never load anything from pk3 files that are not present at the server when pure\nstatic int\t\tfs_numServerPaks;\nstatic int\t\tfs_serverPaks[MAX_SEARCH_PATHS];\t\t\t\t// checksums\nstatic char\t\t*fs_serverPakNames[MAX_SEARCH_PATHS];\t\t\t// pk3 names\n\n// only used for autodownload, to make sure the client has at least\n// all the pk3 files that are referenced at the server side\nstatic int\t\tfs_numServerReferencedPaks;\nstatic int\t\tfs_serverReferencedPaks[MAX_SEARCH_PATHS];\t\t\t// checksums\nstatic char\t\t*fs_serverReferencedPakNames[MAX_SEARCH_PATHS];\t\t// pk3 names\n\n// last valid game folder used\nchar lastValidBase[MAX_OSPATH];\nchar lastValidGame[MAX_OSPATH];\n\n// productId: This file is copyright 1999 Id Software, and may not be duplicated except during a licensed installation of the full commercial version of Quake 3:Arena\nstatic byte fs_scrambledProductId[152] = {\n220, 129, 255, 108, 244, 163, 171, 55, 133, 65, 199, 36, 140, 222, 53, 99, 65, 171, 175, 232, 236, 193, 210, 250, 169, 104, 231, 231, 21, 201, 170, 208, 135, 175, 130, 136, 85, 215, 71, 23, 96, 32, 96, 83, 44, 240, 219, 138, 184, 215, 73, 27, 196, 247, 55, 139, 148, 68, 78, 203, 213, 238, 139, 23, 45, 205, 118, 186, 236, 230, 231, 107, 212, 1, 10, 98, 30, 20, 116, 180, 216, 248, 166, 35, 45, 22, 215, 229, 35, 116, 250, 167, 117, 3, 57, 55, 201, 229, 218, 222, 128, 12, 141, 149, 32, 110, 168, 215, 184, 53, 31, 147, 62, 12, 138, 67, 132, 54, 125, 6, 221, 148, 140, 4, 21, 44, 198, 3, 126, 12, 100, 236, 61, 42, 44, 251, 15, 135, 14, 134, 89, 92, 177, 246, 152, 106, 124, 78, 118, 80, 28, 42\n};\n\n#ifdef FS_MISSING\nFILE*\t\tmissingFiles = NULL;\n#endif\n\n/*\n==============\nFS_Initialized\n==============\n*/\n\nqboolean FS_Initialized() {\n\treturn (qboolean) (fs_searchpaths != NULL);\n}\n\n/*\n=================\nFS_PakIsPure\n=================\n*/\nqboolean FS_PakIsPure( pack_t *pack ) {\n\tint i;\n\n\tif ( fs_numServerPaks ) {\n\t\tfor ( i = 0 ; i < fs_numServerPaks ; i++ ) {\n\t\t\t// FIXME: also use hashed file names\n\t\t\t// NOTE TTimo: a pk3 with same checksum but different name would be validated too\n\t\t\t//   I don't see this as allowing for any exploit, it would only happen if the client does manips of it's file names 'not a bug'\n\t\t\tif ( pack->checksum == fs_serverPaks[i] ) {\n\t\t\t\treturn qtrue;\t\t// on the aproved list\n\t\t\t}\n\t\t}\n\t\treturn qfalse;\t// not on the pure server pak list\n\t}\n\treturn qtrue;\n}\n\n\n/*\n=================\nFS_LoadStack\nreturn load stack\n=================\n*/\nint FS_LoadStack()\n{\n\treturn fs_loadStack;\n}\n                      \n/*\n================\nreturn a hash value for the filename\n================\n*/\nstatic long FS_HashFileName( const char *fname, int hashSize ) {\n\tint\t\ti;\n\tlong\thash;\n\tchar\tletter;\n\n\thash = 0;\n\ti = 0;\n\twhile (fname[i] != '\\0') {\n\t\tletter = tolower(fname[i]);\n\t\tif (letter =='.') break;\t\t\t\t// don't include extension\n\t\tif (letter =='\\\\') letter = '/';\t\t// damn path names\n\t\tif (letter == PATH_SEP) letter = '/';\t\t// damn path names\n\t\thash+=(long)(letter)*(i+119);\n\t\ti++;\n\t}\n\thash = (hash ^ (hash >> 10) ^ (hash >> 20));\n\thash &= (hashSize-1);\n\treturn hash;\n}\n\nstatic fileHandle_t\tFS_HandleForFile(void) {\n\tint\t\ti;\n\n\tfor ( i = 1 ; i < MAX_FILE_HANDLES ; i++ ) {\n\t\tif ( fsh[i].handleFiles.file.o == NULL ) {\n\t\t\treturn i;\n\t\t}\n\t}\n\tCom_Error( ERR_DROP, \"FS_HandleForFile: none free\" );\n\treturn 0;\n}\n\nstatic FILE\t*FS_FileForHandle( fileHandle_t f ) {\n\tif ( f < 0 || f > MAX_FILE_HANDLES ) {\n\t\tCom_Error( ERR_DROP, \"FS_FileForHandle: out of reange\" );\n\t}\n\tif (fsh[f].zipFile == qtrue) {\n\t\tCom_Error( ERR_DROP, \"FS_FileForHandle: can't get FILE on zip file\" );\n\t}\n\tif ( ! fsh[f].handleFiles.file.o ) {\n\t\tCom_Error( ERR_DROP, \"FS_FileForHandle: NULL\" );\n\t}\n\t\n\treturn fsh[f].handleFiles.file.o;\n}\n\nvoid\tFS_ForceFlush( fileHandle_t f ) {\n\tFILE *file;\n\n\tfile = FS_FileForHandle(f);\n\tsetvbuf( file, NULL, _IONBF, 0 );\n}\n\n/*\n================\nFS_filelength\n\nIf this is called on a non-unique FILE (from a pak file),\nit will return the size of the pak file, not the expected\nsize of the file.\n================\n*/\nint FS_filelength( fileHandle_t f ) {\n\tint\t\tpos;\n\tint\t\tend;\n\tFILE*\th;\n\n\th = FS_FileForHandle(f);\n\tpos = ftell (h);\n\tfseek (h, 0, SEEK_END);\n\tend = ftell (h);\n\tfseek (h, pos, SEEK_SET);\n\n\treturn end;\n}\n\n/*\n====================\nFS_ReplaceSeparators\n\nFix things up differently for win/unix/mac\n====================\n*/\nstatic void FS_ReplaceSeparators( char *path ) {\n\tchar\t*s;\n\n\tfor ( s = path ; *s ; s++ ) {\n\t\tif ( *s == '/' || *s == '\\\\' ) {\n\t\t\t*s = PATH_SEP;\n\t\t}\n\t}\n}\n\n/*\n===================\nFS_BuildOSPath\n\nQpath may have either forward or backwards slashes\n===================\n*/\nchar *FS_BuildOSPath( const char *base, const char *game, const char *qpath ) {\n\tchar\ttemp[MAX_OSPATH];\n\tstatic char ospath[2][MAX_OSPATH];\n\tstatic int toggle;\n\t\n\ttoggle ^= 1;\t\t// flip-flop to allow two returns without clash\n\n\tif( !game || !game[0] ) {\n\t\tgame = fs_gamedir;\n\t}\n\n\tCom_sprintf( temp, sizeof(temp), \"/%s/%s\", game, qpath );\n\tFS_ReplaceSeparators( temp );\t\n\tCom_sprintf( ospath[toggle], sizeof( ospath[0] ), \"%s%s\", base, temp );\n\t\n\treturn ospath[toggle];\n}\n\n\n/*\n============\nFS_CreatePath\n\nCreates any directories needed to store the given filename\n============\n*/\nstatic qboolean FS_CreatePath (char *OSPath) {\n\tchar\t*ofs;\n\t\n\t// make absolutely sure that it can't back up the path\n\t// FIXME: is c: allowed???\n\tif ( strstr( OSPath, \"..\" ) || strstr( OSPath, \"::\" ) ) {\n\t\tCom_Printf( \"WARNING: refusing to create relative path \\\"%s\\\"\\n\", OSPath );\n\t\treturn qtrue;\n\t}\n\n\tfor (ofs = OSPath+1 ; *ofs ; ofs++) {\n\t\tif (*ofs == PATH_SEP) {\t\n\t\t\t// create the directory\n\t\t\t*ofs = 0;\n\t\t\tSys_Mkdir (OSPath);\n\t\t\t*ofs = PATH_SEP;\n\t\t}\n\t}\n\treturn qfalse;\n}\n\n/*\n=================\nFS_CopyFile\n\nCopy a fully specified file from one place to another\n=================\n*/\nstatic void FS_CopyFile( char *fromOSPath, char *toOSPath ) {\n\tFILE\t*f;\n\tint\t\tlen;\n\tbyte\t*buf;\n\n\tCom_Printf( \"copy %s to %s\\n\", fromOSPath, toOSPath );\n\n\tif (strstr(fromOSPath, \"journal.dat\") || strstr(fromOSPath, \"journaldata.dat\")) {\n\t\tCom_Printf( \"Ignoring journal files\\n\");\n\t\treturn;\n\t}\n\n\tf = fopen( fromOSPath, \"rb\" );\n\tif ( !f ) {\n\t\treturn;\n\t}\n\tfseek (f, 0, SEEK_END);\n\tlen = ftell (f);\n\tfseek (f, 0, SEEK_SET);\n\n\t// we are using direct malloc instead of Z_Malloc here, so it\n\t// probably won't work on a mac... Its only for developers anyway...\n\tbuf = (byte*) malloc( len );\n\tif (fread( buf, 1, len, f ) != len)\n\t\tCom_Error( ERR_FATAL, \"Short read in FS_Copyfiles()\\n\" );\n\tfclose( f );\n\n\tif( FS_CreatePath( toOSPath ) ) {\n\t\treturn;\n\t}\n\n\tf = fopen( toOSPath, \"wb\" );\n\tif ( !f ) {\n\t\treturn;\n\t}\n\tif (fwrite( buf, 1, len, f ) != len)\n\t\tCom_Error( ERR_FATAL, \"Short write in FS_Copyfiles()\\n\" );\n\tfclose( f );\n\tfree( buf );\n}\n\n/*\n===========\nFS_Remove\n\n===========\n*/\nstatic void FS_Remove( const char *osPath ) {\n\tremove( osPath );\n}\n\n/*\n================\nFS_FileExists\n\nTests if the file exists in the current gamedir, this DOES NOT\nsearch the paths.  This is to determine if opening a file to write\n(which always goes into the current gamedir) will cause any overwrites.\nNOTE TTimo: this goes with FS_FOpenFileWrite for opening the file afterwards\n================\n*/\nqboolean FS_FileExists( const char *file )\n{\n\tFILE *f;\n\tchar *testpath;\n\n\ttestpath = FS_BuildOSPath( fs_homepath->string, fs_gamedir, file );\n\n\tf = fopen( testpath, \"rb\" );\n\tif (f) {\n\t\tfclose( f );\n\t\treturn qtrue;\n\t}\n\treturn qfalse;\n}\n\n/*\n================\nFS_SV_FileExists\n\nTests if the file exists \n================\n*/\nqboolean FS_SV_FileExists( const char *file )\n{\n\tFILE *f;\n\tchar *testpath;\n\n\ttestpath = FS_BuildOSPath( fs_homepath->string, file, \"\");\n\ttestpath[strlen(testpath)-1] = '\\0';\n\n\tf = fopen( testpath, \"rb\" );\n\tif (f) {\n\t\tfclose( f );\n\t\treturn qtrue;\n\t}\n\treturn qfalse;\n}\n\n\n/*\n===========\nFS_SV_FOpenFileWrite\n\n===========\n*/\nfileHandle_t FS_SV_FOpenFileWrite( const char *filename ) {\n\tchar *ospath;\n\tfileHandle_t\tf;\n\n\tif ( !fs_searchpaths ) {\n\t\tCom_Error( ERR_FATAL, \"Filesystem call made without initialization\\n\" );\n\t}\n\n\tospath = FS_BuildOSPath( fs_homepath->string, filename, \"\" );\n\tospath[strlen(ospath)-1] = '\\0';\n\n\tf = FS_HandleForFile();\n\tfsh[f].zipFile = qfalse;\n\n\tif ( fs_debug->integer ) {\n\t\tCom_Printf( \"FS_SV_FOpenFileWrite: %s\\n\", ospath );\n\t}\n\n\tif( FS_CreatePath( ospath ) ) {\n\t\treturn 0;\n\t}\n\n\tCom_DPrintf( \"writing to: %s\\n\", ospath );\n\tfsh[f].handleFiles.file.o = fopen( ospath, \"wb\" );\n\n\tQ_strncpyz( fsh[f].name, filename, sizeof( fsh[f].name ) );\n\n\tfsh[f].handleSync = qfalse;\n\tif (!fsh[f].handleFiles.file.o) {\n\t\tf = 0;\n\t}\n\treturn f;\n}\n\n/*\n===========\nFS_SV_FOpenFileRead\nsearch for a file somewhere below the home path, base path or cd path\nwe search in that order, matching FS_SV_FOpenFileRead order\n===========\n*/\nint FS_SV_FOpenFileRead( const char *filename, fileHandle_t *fp ) {\n\tchar *ospath;\n\tfileHandle_t\tf = 0;\n\n\tif ( !fs_searchpaths ) {\n\t\tCom_Error( ERR_FATAL, \"Filesystem call made without initialization\\n\" );\n\t}\n\n\tf = FS_HandleForFile();\n\tfsh[f].zipFile = qfalse;\n\n\tQ_strncpyz( fsh[f].name, filename, sizeof( fsh[f].name ) );\n\n\t// don't let sound stutter\n\tS_ClearSoundBuffer();\n\n  // search homepath\n\tospath = FS_BuildOSPath( fs_homepath->string, filename, \"\" );\n\t// remove trailing slash\n\tospath[strlen(ospath)-1] = '\\0';\n\n\tif ( fs_debug->integer ) {\n\t\tCom_Printf( \"FS_SV_FOpenFileRead (fs_homepath): %s\\n\", ospath );\n\t}\n\n\tfsh[f].handleFiles.file.o = fopen( ospath, \"rb\" );\n\tfsh[f].handleSync = qfalse;\n  if (!fsh[f].handleFiles.file.o)\n  {\n    // NOTE TTimo on non *nix systems, fs_homepath == fs_basepath, might want to avoid\n    if (Q_stricmp(fs_homepath->string,fs_basepath->string))\n    {\n      // search basepath\n      ospath = FS_BuildOSPath( fs_basepath->string, filename, \"\" );\n      ospath[strlen(ospath)-1] = '\\0';\n\n      if ( fs_debug->integer )\n      {\n        Com_Printf( \"FS_SV_FOpenFileRead (fs_basepath): %s\\n\", ospath );\n      }\n\n      fsh[f].handleFiles.file.o = fopen( ospath, \"rb\" );\n      fsh[f].handleSync = qfalse;\n\n      if ( !fsh[f].handleFiles.file.o )\n      {\n        f = 0;\n      }\n    }\n  }\n\n\tif (!fsh[f].handleFiles.file.o) {\n    // search cd path\n    ospath = FS_BuildOSPath( fs_cdpath->string, filename, \"\" );\n    ospath[strlen(ospath)-1] = '\\0';\n\n    if (fs_debug->integer)\n    {\n      Com_Printf( \"FS_SV_FOpenFileRead (fs_cdpath) : %s\\n\", ospath );\n    }\n\n\t  fsh[f].handleFiles.file.o = fopen( ospath, \"rb\" );\n\t  fsh[f].handleSync = qfalse;\n\n\t  if( !fsh[f].handleFiles.file.o ) {\n\t    f = 0;\n\t  }\n  }\n  \n\t*fp = f;\n\tif (f) {\n\t\treturn FS_filelength(f);\n\t}\n\treturn 0;\n}\n\n\n/*\n===========\nFS_SV_Rename\n\n===========\n*/\nvoid FS_SV_Rename( const char *from, const char *to ) {\n\tchar\t\t\t*from_ospath, *to_ospath;\n\n\tif ( !fs_searchpaths ) {\n\t\tCom_Error( ERR_FATAL, \"Filesystem call made without initialization\\n\" );\n\t}\n\n\t// don't let sound stutter\n\tS_ClearSoundBuffer();\n\n\tfrom_ospath = FS_BuildOSPath( fs_homepath->string, from, \"\" );\n\tto_ospath = FS_BuildOSPath( fs_homepath->string, to, \"\" );\n\tfrom_ospath[strlen(from_ospath)-1] = '\\0';\n\tto_ospath[strlen(to_ospath)-1] = '\\0';\n\n\tif ( fs_debug->integer ) {\n\t\tCom_Printf( \"FS_SV_Rename: %s --> %s\\n\", from_ospath, to_ospath );\n\t}\n\n\tif (rename( from_ospath, to_ospath )) {\n\t\t// Failed, try copying it and deleting the original\n\t\tFS_CopyFile ( from_ospath, to_ospath );\n\t\tFS_Remove ( from_ospath );\n\t}\n}\n\n\n\n/*\n===========\nFS_Rename\n\n===========\n*/\nvoid FS_Rename( const char *from, const char *to ) {\n\tchar\t\t\t*from_ospath, *to_ospath;\n\n\tif ( !fs_searchpaths ) {\n\t\tCom_Error( ERR_FATAL, \"Filesystem call made without initialization\\n\" );\n\t}\n\n\t// don't let sound stutter\n\tS_ClearSoundBuffer();\n\n\tfrom_ospath = FS_BuildOSPath( fs_homepath->string, fs_gamedir, from );\n\tto_ospath = FS_BuildOSPath( fs_homepath->string, fs_gamedir, to );\n\n\tif ( fs_debug->integer ) {\n\t\tCom_Printf( \"FS_Rename: %s --> %s\\n\", from_ospath, to_ospath );\n\t}\n\n\tif (rename( from_ospath, to_ospath )) {\n\t\t// Failed, try copying it and deleting the original\n\t\tFS_CopyFile ( from_ospath, to_ospath );\n\t\tFS_Remove ( from_ospath );\n\t}\n}\n\n/*\n==============\nFS_FCloseFile\n\nIf the FILE pointer is an open pak file, leave it open.\n\nFor some reason, other dll's can't just cal fclose()\non files returned by FS_FOpenFile...\n==============\n*/\nvoid FS_FCloseFile( fileHandle_t f ) {\n\tif ( !fs_searchpaths ) {\n\t\tCom_Error( ERR_FATAL, \"Filesystem call made without initialization\\n\" );\n\t}\n\n\tif (fsh[f].streamed) {\n\t\tSys_EndStreamedFile(f);\n\t}\n\tif (fsh[f].zipFile == qtrue) {\n\t\tunzCloseCurrentFile( fsh[f].handleFiles.file.z );\n\t\tif ( fsh[f].handleFiles.unique ) {\n\t\t\tunzClose( fsh[f].handleFiles.file.z );\n\t\t}\n\t\tCom_Memset( &fsh[f], 0, sizeof( fsh[f] ) );\n\t\treturn;\n\t}\n\n\t// we didn't find it as a pak, so close it as a unique file\n\tif (fsh[f].handleFiles.file.o) {\n\t\tfclose (fsh[f].handleFiles.file.o);\n\t}\n\tCom_Memset( &fsh[f], 0, sizeof( fsh[f] ) );\n}\n\n/*\n===========\nFS_FOpenFileWrite\n\n===========\n*/\nfileHandle_t FS_FOpenFileWrite( const char *filename ) {\n\tchar\t\t\t*ospath;\n\tfileHandle_t\tf;\n\n\tif ( !fs_searchpaths ) {\n\t\tCom_Error( ERR_FATAL, \"Filesystem call made without initialization\\n\" );\n\t}\n\n\tf = FS_HandleForFile();\n\tfsh[f].zipFile = qfalse;\n\n\tospath = FS_BuildOSPath( fs_homepath->string, fs_gamedir, filename );\n\n\tif ( fs_debug->integer ) {\n\t\tCom_Printf( \"FS_FOpenFileWrite: %s\\n\", ospath );\n\t}\n\n\tif( FS_CreatePath( ospath ) ) {\n\t\treturn 0;\n\t}\n\n\t// enabling the following line causes a recursive function call loop\n\t// when running with +set logfile 1 +set developer 1\n\t//Com_DPrintf( \"writing to: %s\\n\", ospath );\n\tfsh[f].handleFiles.file.o = fopen( ospath, \"wb\" );\n\n\tQ_strncpyz( fsh[f].name, filename, sizeof( fsh[f].name ) );\n\n\tfsh[f].handleSync = qfalse;\n\tif (!fsh[f].handleFiles.file.o) {\n\t\tf = 0;\n\t}\n\treturn f;\n}\n\n/*\n===========\nFS_FOpenFileAppend\n\n===========\n*/\nfileHandle_t FS_FOpenFileAppend( const char *filename ) {\n\tchar\t\t\t*ospath;\n\tfileHandle_t\tf;\n\n\tif ( !fs_searchpaths ) {\n\t\tCom_Error( ERR_FATAL, \"Filesystem call made without initialization\\n\" );\n\t}\n\n\tf = FS_HandleForFile();\n\tfsh[f].zipFile = qfalse;\n\n\tQ_strncpyz( fsh[f].name, filename, sizeof( fsh[f].name ) );\n\n\t// don't let sound stutter\n\tS_ClearSoundBuffer();\n\n\tospath = FS_BuildOSPath( fs_homepath->string, fs_gamedir, filename );\n\n\tif ( fs_debug->integer ) {\n\t\tCom_Printf( \"FS_FOpenFileAppend: %s\\n\", ospath );\n\t}\n\n\tif( FS_CreatePath( ospath ) ) {\n\t\treturn 0;\n\t}\n\n\tfsh[f].handleFiles.file.o = fopen( ospath, \"ab\" );\n\tfsh[f].handleSync = qfalse;\n\tif (!fsh[f].handleFiles.file.o) {\n\t\tf = 0;\n\t}\n\treturn f;\n}\n\n/*\n===========\nFS_FilenameCompare\n\nIgnore case and seprator char distinctions\n===========\n*/\nqboolean FS_FilenameCompare( const char *s1, const char *s2 ) {\n\tint\t\tc1, c2;\n\t\n\tdo {\n\t\tc1 = *s1++;\n\t\tc2 = *s2++;\n\n\t\tif (c1 >= 'a' && c1 <= 'z') {\n\t\t\tc1 -= ('a' - 'A');\n\t\t}\n\t\tif (c2 >= 'a' && c2 <= 'z') {\n\t\t\tc2 -= ('a' - 'A');\n\t\t}\n\n\t\tif ( c1 == '\\\\' || c1 == ':' ) {\n\t\t\tc1 = '/';\n\t\t}\n\t\tif ( c2 == '\\\\' || c2 == ':' ) {\n\t\t\tc2 = '/';\n\t\t}\n\t\t\n\t\tif (c1 != c2) {\n\t\t\treturn (qboolean) -1;\t\t// strings not equal\n\t\t}\n\t} while (c1);\n\t\n\treturn (qboolean) 0;\t\t// strings are equal\n}\n\n/*\n===========\nFS_ShiftedStrStr\n===========\n*/\nchar *FS_ShiftedStrStr(const char *string, const char *substring, int shift) {\n\tchar buf[MAX_STRING_TOKENS];\n\tint i;\n\n\tfor (i = 0; substring[i]; i++) {\n\t\tbuf[i] = substring[i] + shift;\n\t}\n\tbuf[i] = '\\0';\n\treturn (char*) strstr(string, buf);\n}\n\n/*\n===========\nFS_FOpenFileRead\n\nFinds the file in the search path.\nReturns filesize and an open FILE pointer.\nUsed for streaming data out of either a\nseparate file or a ZIP file.\n===========\n*/\nextern qboolean\t\tcom_fullyInitialized;\n\nint FS_FOpenFileRead( const char *filename, fileHandle_t *file, qboolean uniqueFILE ) {\n\tsearchpath_t\t*search;\n\tchar\t\t\t*netpath;\n\tpack_t\t\t\t*pak;\n\tfileInPack_t\t*pakFile;\n\tdirectory_t\t\t*dir;\n\tlong\t\t\thash;\n\tunz_s\t\t\t*zfi;\n\tFILE\t\t\t*temp;\n\tint\t\t\t\tl;\n\tchar demoExt[16];\n\n\thash = 0;\n\n\tif ( !fs_searchpaths ) {\n\t\tCom_Error( ERR_FATAL, \"Filesystem call made without initialization\\n\" );\n\t}\n\n\tif ( file == NULL ) {\n\t\t// just wants to see if file is there\n\t\tfor ( search = fs_searchpaths ; search ; search = search->next ) {\n\t\t\t//\n\t\t\tif ( search->pack ) {\n\t\t\t\thash = FS_HashFileName(filename, search->pack->hashSize);\n\t\t\t}\n\t\t\t// is the element a pak file?\n\t\t\tif ( search->pack && search->pack->hashTable[hash] ) {\n\t\t\t\t// look through all the pak file elements\n\t\t\t\tpak = search->pack;\n\t\t\t\tpakFile = pak->hashTable[hash];\n\t\t\t\tdo {\n\t\t\t\t\t// case and separator insensitive comparisons\n\t\t\t\t\tif ( !FS_FilenameCompare( pakFile->name, filename ) ) {\n\t\t\t\t\t\t// found it!\n\t\t\t\t\t\treturn qtrue;\n\t\t\t\t\t}\n\t\t\t\t\tpakFile = pakFile->next;\n\t\t\t\t} while(pakFile != NULL);\n\t\t\t} else if ( search->dir ) {\n\t\t\t\tdir = search->dir;\n\t\t\t\n\t\t\t\tnetpath = FS_BuildOSPath( dir->path, dir->gamedir, filename );\n\t\t\t\ttemp = fopen (netpath, \"rb\");\n\t\t\t\tif ( !temp ) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tfclose(temp);\n\t\t\t\treturn qtrue;\n\t\t\t}\n\t\t}\n\t\treturn qfalse;\n\t}\n\n\tif ( !filename ) {\n\t\tCom_Error( ERR_FATAL, \"FS_FOpenFileRead: NULL 'filename' parameter passed\\n\" );\n\t}\n\n\tCom_sprintf (demoExt, sizeof(demoExt), \".dm_%d\",PROTOCOL_VERSION );\n\t// qpaths are not supposed to have a leading slash\n\tif ( filename[0] == '/' || filename[0] == '\\\\' ) {\n\t\tfilename++;\n\t}\n\n\t// make absolutely sure that it can't back up the path.\n\t// The searchpaths do guarantee that something will always\n\t// be prepended, so we don't need to worry about \"c:\" or \"//limbo\" \n\tif ( strstr( filename, \"..\" ) || strstr( filename, \"::\" ) ) {\n\t\t*file = 0;\n\t\treturn -1;\n\t}\n\n\t// make sure the q3key file is only readable by the quake3.exe at initialization\n\t// any other time the key should only be accessed in memory using the provided functions\n\tif( com_fullyInitialized && strstr( filename, \"q3key\" ) ) {\n\t\t*file = 0;\n\t\treturn -1;\n\t}\n\n\t//\n\t// search through the path, one element at a time\n\t//\n\n\t*file = FS_HandleForFile();\n\tfsh[*file].handleFiles.unique = uniqueFILE;\n\n\tfor ( search = fs_searchpaths ; search ; search = search->next ) {\n\t\t//\n\t\tif ( search->pack ) {\n\t\t\thash = FS_HashFileName(filename, search->pack->hashSize);\n\t\t}\n\t\t// is the element a pak file?\n\t\tif ( search->pack && search->pack->hashTable[hash] ) {\n\t\t\t// disregard if it doesn't match one of the allowed pure pak files\n\t\t\tif ( !FS_PakIsPure(search->pack) ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// look through all the pak file elements\n\t\t\tpak = search->pack;\n\t\t\tpakFile = pak->hashTable[hash];\n\t\t\tdo {\n\t\t\t\t// case and separator insensitive comparisons\n\t\t\t\tif ( !FS_FilenameCompare( pakFile->name, filename ) ) {\n\t\t\t\t\t// found it!\n\n\t\t\t\t\t// mark the pak as having been referenced and mark specifics on cgame and ui\n\t\t\t\t\t// shaders, txt, arena files  by themselves do not count as a reference as \n\t\t\t\t\t// these are loaded from all pk3s \n\t\t\t\t\t// from every pk3 file.. \n\t\t\t\t\tl = (int)strlen( filename );\n\t\t\t\t\tif ( !(pak->referenced & FS_GENERAL_REF)) {\n\t\t\t\t\t\tif ( Q_stricmp(filename + l - 7, \".shader\") != 0 &&\n\t\t\t\t\t\t\tQ_stricmp(filename + l - 4, \".txt\") != 0 &&\n\t\t\t\t\t\t\tQ_stricmp(filename + l - 4, \".cfg\") != 0 &&\n\t\t\t\t\t\t\tQ_stricmp(filename + l - 7, \".config\") != 0 &&\n\t\t\t\t\t\t\tstrstr(filename, \"levelshots\") == NULL &&\n\t\t\t\t\t\t\tQ_stricmp(filename + l - 4, \".bot\") != 0 &&\n\t\t\t\t\t\t\tQ_stricmp(filename + l - 6, \".arena\") != 0 &&\n\t\t\t\t\t\t\tQ_stricmp(filename + l - 5, \".menu\") != 0) {\n\t\t\t\t\t\t\tpak->referenced |= FS_GENERAL_REF;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// qagame.qvm\t- 13\n\t\t\t\t\t// dTZT`X!di`\n\t\t\t\t\tif (!(pak->referenced & FS_QAGAME_REF) && FS_ShiftedStrStr(filename, \"dTZT`X!di`\", 13)) {\n\t\t\t\t\t\tpak->referenced |= FS_QAGAME_REF;\n\t\t\t\t\t}\n\t\t\t\t\t// cgame.qvm\t- 7\n\t\t\t\t\t// \\`Zf^'jof\n\t\t\t\t\tif (!(pak->referenced & FS_CGAME_REF) && FS_ShiftedStrStr(filename , \"\\\\`Zf^'jof\", 7)) {\n\t\t\t\t\t\tpak->referenced |= FS_CGAME_REF;\n\t\t\t\t\t}\n\t\t\t\t\t// ui.qvm\t\t- 5\n\t\t\t\t\t// pd)lqh\n\t\t\t\t\tif (!(pak->referenced & FS_UI_REF) && FS_ShiftedStrStr(filename , \"pd)lqh\", 5)) {\n\t\t\t\t\t\tpak->referenced |= FS_UI_REF;\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( uniqueFILE ) {\n\t\t\t\t\t\t// open a new file on the pakfile\n\t\t\t\t\t\tfsh[*file].handleFiles.file.z = unzReOpen (pak->pakFilename, pak->handle);\n\t\t\t\t\t\tif (fsh[*file].handleFiles.file.z == NULL) {\n\t\t\t\t\t\t\tCom_Error (ERR_FATAL, \"Couldn't reopen %s\", pak->pakFilename);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tfsh[*file].handleFiles.file.z = pak->handle;\n\t\t\t\t\t}\n\t\t\t\t\tQ_strncpyz( fsh[*file].name, filename, sizeof( fsh[*file].name ) );\n\t\t\t\t\tfsh[*file].zipFile = qtrue;\n\t\t\t\t\tzfi = (unz_s *)fsh[*file].handleFiles.file.z;\n\t\t\t\t\t// in case the file was new\n\t\t\t\t\ttemp = zfi->file;\n\t\t\t\t\t// set the file position in the zip file (also sets the current file info)\n\t\t\t\t\tunzSetCurrentFileInfoPosition(pak->handle, pakFile->pos);\n\t\t\t\t\t// copy the file info into the unzip structure\n\t\t\t\t\tCom_Memcpy( zfi, pak->handle, sizeof(unz_s) );\n\t\t\t\t\t// we copy this back into the structure\n\t\t\t\t\tzfi->file = temp;\n\t\t\t\t\t// open the file in the zip\n\t\t\t\t\tunzOpenCurrentFile( fsh[*file].handleFiles.file.z );\n\t\t\t\t\tfsh[*file].zipFilePos = pakFile->pos;\n\n\t\t\t\t\tif ( fs_debug->integer ) {\n\t\t\t\t\t\tCom_Printf( \"FS_FOpenFileRead: %s (found in '%s')\\n\", \n\t\t\t\t\t\t\tfilename, pak->pakFilename );\n\t\t\t\t\t}\n\t\t\t\t\treturn zfi->cur_file_info.uncompressed_size;\n\t\t\t\t}\n\t\t\t\tpakFile = pakFile->next;\n\t\t\t} while(pakFile != NULL);\n\t\t} else if ( search->dir ) {\n\t\t\t// check a file in the directory tree\n\n\t\t\t// if we are running restricted, the only files we\n\t\t\t// will allow to come from the directory are .cfg files\n\t\t\tl = (int)strlen( filename );\n      // FIXME TTimo I'm not sure about the fs_numServerPaks test\n      // if you are using FS_ReadFile to find out if a file exists,\n      //   this test can make the search fail although the file is in the directory\n      // I had the problem on https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=8\n      // turned out I used FS_FileExists instead\n\t\t\tif ( fs_restrict->integer || fs_numServerPaks ) {\n\n\t\t\t\tif ( Q_stricmp( filename + l - 4, \".cfg\" )\t\t// for config files\n\t\t\t\t\t&& Q_stricmp( filename + l - 5, \".menu\" )\t// menu files\n\t\t\t\t\t&& Q_stricmp( filename + l - 5, \".game\" )\t// menu files\n\t\t\t\t\t&& Q_stricmp( filename + l - (int)strlen(demoExt), demoExt )\t// menu files\n\t\t\t\t\t&& Q_stricmp( filename + l - 4, \".dat\" ) ) {\t// for journal files\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tdir = search->dir;\n\t\t\t\n\t\t\tnetpath = FS_BuildOSPath( dir->path, dir->gamedir, filename );\n\t\t\tfsh[*file].handleFiles.file.o = fopen (netpath, \"rb\");\n\t\t\tif ( !fsh[*file].handleFiles.file.o ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif ( Q_stricmp( filename + l - 4, \".cfg\" )\t\t// for config files\n\t\t\t\t&& Q_stricmp( filename + l - 5, \".menu\" )\t// menu files\n\t\t\t\t&& Q_stricmp( filename + l - 5, \".game\" )\t// menu files\n\t\t\t\t&& Q_stricmp( filename + l - (int)strlen(demoExt), demoExt )\t// menu files\n\t\t\t\t&& Q_stricmp( filename + l - 4, \".dat\" ) ) {\t// for journal files\n\t\t\t\tfs_fakeChkSum = random();\n\t\t\t}\n      \n\t\t\tQ_strncpyz( fsh[*file].name, filename, sizeof( fsh[*file].name ) );\n\t\t\tfsh[*file].zipFile = qfalse;\n\t\t\tif ( fs_debug->integer ) {\n\t\t\t\tCom_Printf( \"FS_FOpenFileRead: %s (found in '%s/%s')\\n\", filename,\n\t\t\t\t\tdir->path, dir->gamedir );\n\t\t\t}\n\n\t\t\t// if we are getting it from the cdpath, optionally copy it\n\t\t\t//  to the basepath\n\t\t\tif ( fs_copyfiles->integer && !Q_stricmp( dir->path, fs_cdpath->string ) ) {\n\t\t\t\tchar\t*copypath;\n\n\t\t\t\tcopypath = FS_BuildOSPath( fs_basepath->string, dir->gamedir, filename );\n\t\t\t\tFS_CopyFile( netpath, copypath );\n\t\t\t}\n\n\t\t\treturn FS_filelength (*file);\n\t\t}\t\t\n\t}\n\t\n\tCom_DPrintf (\"Can't find %s\\n\", filename);\n#ifdef FS_MISSING\n\tif (missingFiles) {\n\t\tfprintf(missingFiles, \"%s\\n\", filename);\n\t}\n#endif\n\t*file = 0;\n\treturn -1;\n}\n\n\n/*\n=================\nFS_Read\n\nProperly handles partial reads\n=================\n*/\nint FS_Read2( void *buffer, int len, fileHandle_t f ) {\n\tif ( !fs_searchpaths ) {\n\t\tCom_Error( ERR_FATAL, \"Filesystem call made without initialization\\n\" );\n\t}\n\n\tif ( !f ) {\n\t\treturn 0;\n\t}\n\tif (fsh[f].streamed) {\n\t\tint r;\n\t\tfsh[f].streamed = qfalse;\n\t\tr = Sys_StreamedRead( buffer, len, 1, f);\n\t\tfsh[f].streamed = qtrue;\n\t\treturn r;\n\t} else {\n\t\treturn FS_Read( buffer, len, f);\n\t}\n}\n\nint FS_Read( void *buffer, int len, fileHandle_t f ) {\n\tint\t\tblock, remaining;\n\tint\t\tread;\n\tbyte\t*buf;\n\tint\t\ttries;\n\n\tif ( !fs_searchpaths ) {\n\t\tCom_Error( ERR_FATAL, \"Filesystem call made without initialization\\n\" );\n\t}\n\n\tif ( !f ) {\n\t\treturn 0;\n\t}\n\n\tbuf = (byte *)buffer;\n\tfs_readCount += len;\n\n\tif (fsh[f].zipFile == qfalse) {\n\t\tremaining = len;\n\t\ttries = 0;\n\t\twhile (remaining) {\n\t\t\tblock = remaining;\n\t\t\tread = (int)fread (buf, 1, block, fsh[f].handleFiles.file.o);\n\t\t\tif (read == 0) {\n\t\t\t\t// we might have been trying to read from a CD, which\n\t\t\t\t// sometimes returns a 0 read on windows\n\t\t\t\tif (!tries) {\n\t\t\t\t\ttries = 1;\n\t\t\t\t} else {\n\t\t\t\t\treturn len-remaining;\t//Com_Error (ERR_FATAL, \"FS_Read: 0 bytes read\");\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (read == -1) {\n\t\t\t\tCom_Error (ERR_FATAL, \"FS_Read: -1 bytes read\");\n\t\t\t}\n\n\t\t\tremaining -= read;\n\t\t\tbuf += read;\n\t\t}\n\t\treturn len;\n\t} else {\n\t\treturn unzReadCurrentFile(fsh[f].handleFiles.file.z, buffer, len);\n\t}\n}\n\n/*\n=================\nFS_Write\n\nProperly handles partial writes\n=================\n*/\nint FS_Write( const void *buffer, int len, fileHandle_t h ) {\n\tint\t\tblock, remaining;\n\tint\t\twritten;\n\tbyte\t*buf;\n\tint\t\ttries;\n\tFILE\t*f;\n\n\tif ( !fs_searchpaths ) {\n\t\tCom_Error( ERR_FATAL, \"Filesystem call made without initialization\\n\" );\n\t}\n\n\tif ( !h ) {\n\t\treturn 0;\n\t}\n\n\tf = FS_FileForHandle(h);\n\tbuf = (byte *)buffer;\n\n\tremaining = len;\n\ttries = 0;\n\twhile (remaining) {\n\t\tblock = remaining;\n\t\twritten = (int)fwrite (buf, 1, block, f);\n\t\tif (written == 0) {\n\t\t\tif (!tries) {\n\t\t\t\ttries = 1;\n\t\t\t} else {\n\t\t\t\tCom_Printf( \"FS_Write: 0 bytes written\\n\" );\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\n\t\tif (written == -1) {\n\t\t\tCom_Printf( \"FS_Write: -1 bytes written\\n\" );\n\t\t\treturn 0;\n\t\t}\n\n\t\tremaining -= written;\n\t\tbuf += written;\n\t}\n\tif ( fsh[h].handleSync ) {\n\t\tfflush( f );\n\t}\n\treturn len;\n}\n\nvoid QDECL FS_Printf( fileHandle_t h, const char *fmt, ... ) {\n\tva_list\t\targptr;\n\tchar\t\tmsg[MAXPRINTMSG];\n\n\tva_start (argptr,fmt);\n\tQ_vsnprintf (msg, sizeof(msg), fmt, argptr);\n\tva_end (argptr);\n\n\tFS_Write(msg, (int)strlen(msg), h);\n}\n\n/*\n=================\nFS_Seek\n\n=================\n*/\nint FS_Seek( fileHandle_t f, long offset, int origin ) {\n\tint\t\t_origin;\n\tchar\tfoo[65536];\n\n\tif ( !fs_searchpaths ) {\n\t\tCom_Error( ERR_FATAL, \"Filesystem call made without initialization\\n\" );\n\t\treturn -1;\n\t}\n\n\tif (fsh[f].streamed) {\n\t\tfsh[f].streamed = qfalse;\n\t\tSys_StreamSeek( f, offset, origin );\n\t\tfsh[f].streamed = qtrue;\n\t}\n\n\tif (fsh[f].zipFile == qtrue) {\n\t\tif (offset == 0 && origin == FS_SEEK_SET) {\n\t\t\t// set the file position in the zip file (also sets the current file info)\n\t\t\tunzSetCurrentFileInfoPosition(fsh[f].handleFiles.file.z, fsh[f].zipFilePos);\n\t\t\treturn unzOpenCurrentFile(fsh[f].handleFiles.file.z);\n\t\t} else if (offset<65536) {\n\t\t\t// set the file position in the zip file (also sets the current file info)\n\t\t\tunzSetCurrentFileInfoPosition(fsh[f].handleFiles.file.z, fsh[f].zipFilePos);\n\t\t\tunzOpenCurrentFile(fsh[f].handleFiles.file.z);\n\t\t\treturn FS_Read(foo, offset, f);\n\t\t} else {\n\t\t\tCom_Error( ERR_FATAL, \"ZIP FILE FSEEK NOT YET IMPLEMENTED\\n\" );\n\t\t\treturn -1;\n\t\t}\n\t} else {\n\t\tFILE *file;\n\t\tfile = FS_FileForHandle(f);\n\t\tswitch( origin ) {\n\t\tcase FS_SEEK_CUR:\n\t\t\t_origin = SEEK_CUR;\n\t\t\tbreak;\n\t\tcase FS_SEEK_END:\n\t\t\t_origin = SEEK_END;\n\t\t\tbreak;\n\t\tcase FS_SEEK_SET:\n\t\t\t_origin = SEEK_SET;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\t_origin = SEEK_CUR;\n\t\t\tCom_Error( ERR_FATAL, \"Bad origin in FS_Seek\\n\" );\n\t\t\tbreak;\n\t\t}\n\n\t\treturn fseek( file, offset, _origin );\n\t}\n}\n\n\n/*\n======================================================================================\n\nCONVENIENCE FUNCTIONS FOR ENTIRE FILES\n\n======================================================================================\n*/\n\nint\tFS_FileIsInPAK(const char *filename, int *pChecksum ) {\n\tsearchpath_t\t*search;\n\tpack_t\t\t\t*pak;\n\tfileInPack_t\t*pakFile;\n\tlong\t\t\thash = 0;\n\n\tif ( !fs_searchpaths ) {\n\t\tCom_Error( ERR_FATAL, \"Filesystem call made without initialization\\n\" );\n\t}\n\n\tif ( !filename ) {\n\t\tCom_Error( ERR_FATAL, \"FS_FOpenFileRead: NULL 'filename' parameter passed\\n\" );\n\t}\n\n\t// qpaths are not supposed to have a leading slash\n\tif ( filename[0] == '/' || filename[0] == '\\\\' ) {\n\t\tfilename++;\n\t}\n\n\t// make absolutely sure that it can't back up the path.\n\t// The searchpaths do guarantee that something will always\n\t// be prepended, so we don't need to worry about \"c:\" or \"//limbo\" \n\tif ( strstr( filename, \"..\" ) || strstr( filename, \"::\" ) ) {\n\t\treturn -1;\n\t}\n\n\t//\n\t// search through the path, one element at a time\n\t//\n\n\tfor ( search = fs_searchpaths ; search ; search = search->next ) {\n\t\t//\n\t\tif (search->pack) {\n\t\t\thash = FS_HashFileName(filename, search->pack->hashSize);\n\t\t}\n\t\t// is the element a pak file?\n\t\tif ( search->pack && search->pack->hashTable[hash] ) {\n\t\t\t// disregard if it doesn't match one of the allowed pure pak files\n\t\t\tif ( !FS_PakIsPure(search->pack) ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// look through all the pak file elements\n\t\t\tpak = search->pack;\n\t\t\tpakFile = pak->hashTable[hash];\n\t\t\tdo {\n\t\t\t\t// case and separator insensitive comparisons\n\t\t\t\tif ( !FS_FilenameCompare( pakFile->name, filename ) ) {\n\t\t\t\t\tif (pChecksum) {\n\t\t\t\t\t\t*pChecksum = pak->pure_checksum;\n\t\t\t\t\t}\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n\t\t\t\tpakFile = pakFile->next;\n\t\t\t} while(pakFile != NULL);\n\t\t}\n\t}\n\treturn -1;\n}\n\n/*\n============\nFS_ReadFile\n\nFilename are relative to the quake search path\na null buffer will just return the file length without loading\n============\n*/\nint FS_ReadFile( const char *qpath, void **buffer ) {\n\tfileHandle_t\th;\n\tbyte*\t\t\tbuf;\n\tqboolean\t\tisConfig;\n\tint\t\t\t\tlen;\n\n\tif ( !fs_searchpaths ) {\n\t\tCom_Error( ERR_FATAL, \"Filesystem call made without initialization\\n\" );\n\t}\n\n\tif ( !qpath || !qpath[0] ) {\n\t\tCom_Error( ERR_FATAL, \"FS_ReadFile with empty name\\n\" );\n\t}\n\n\tbuf = NULL;\t// quiet compiler warning\n\n\t// if this is a .cfg file and we are playing back a journal, read\n\t// it from the journal file\n\tif ( strstr( qpath, \".cfg\" ) ) {\n\t\tisConfig = qtrue;\n\t\tif ( com_journal && com_journal->integer == 2 ) {\n\t\t\tint\t\tr;\n\n\t\t\tCom_DPrintf( \"Loading %s from journal file.\\n\", qpath );\n\t\t\tr = FS_Read( &len, sizeof( len ), com_journalDataFile );\n\t\t\tif ( r != sizeof( len ) ) {\n\t\t\t\tif (buffer != NULL) *buffer = NULL;\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t\t// if the file didn't exist when the journal was created\n\t\t\tif (!len) {\n\t\t\t\tif (buffer == NULL) {\n\t\t\t\t\treturn 1;\t\t\t// hack for old journal files\n\t\t\t\t}\n\t\t\t\t*buffer = NULL;\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t\tif (buffer == NULL) {\n\t\t\t\treturn len;\n\t\t\t}\n\n\t\t\tbuf = (byte*) Hunk_AllocateTempMemory(len+1);\n\t\t\t*buffer = buf;\n\n\t\t\tr = FS_Read( buf, len, com_journalDataFile );\n\t\t\tif ( r != len ) {\n\t\t\t\tCom_Error( ERR_FATAL, \"Read from journalDataFile failed\" );\n\t\t\t}\n\n\t\t\tfs_loadCount++;\n\t\t\tfs_loadStack++;\n\n\t\t\t// guarantee that it will have a trailing 0 for string operations\n\t\t\tbuf[len] = 0;\n\n\t\t\treturn len;\n\t\t}\n\t} else {\n\t\tisConfig = qfalse;\n\t}\n\n\t// look for it in the filesystem or pack files\n\tlen = FS_FOpenFileRead( qpath, &h, qfalse );\n\tif ( h == 0 ) {\n\t\tif ( buffer ) {\n\t\t\t*buffer = NULL;\n\t\t}\n\t\t// if we are journalling and it is a config file, write a zero to the journal file\n\t\tif ( isConfig && com_journal && com_journal->integer == 1 ) {\n\t\t\tCom_DPrintf( \"Writing zero for %s to journal file.\\n\", qpath );\n\t\t\tlen = 0;\n\t\t\tFS_Write( &len, sizeof( len ), com_journalDataFile );\n\t\t\tFS_Flush( com_journalDataFile );\n\t\t}\n\t\treturn -1;\n\t}\n\t\n\tif ( !buffer ) {\n\t\tif ( isConfig && com_journal && com_journal->integer == 1 ) {\n\t\t\tCom_DPrintf( \"Writing len for %s to journal file.\\n\", qpath );\n\t\t\tFS_Write( &len, sizeof( len ), com_journalDataFile );\n\t\t\tFS_Flush( com_journalDataFile );\n\t\t}\n\t\tFS_FCloseFile( h);\n\t\treturn len;\n\t}\n\n\tfs_loadCount++;\n\tfs_loadStack++;\n\n\tbuf = (byte*) Hunk_AllocateTempMemory(len+1);\n\t*buffer = buf;\n\n\tFS_Read (buf, len, h);\n\n\t// guarantee that it will have a trailing 0 for string operations\n\tbuf[len] = 0;\n\tFS_FCloseFile( h );\n\n\t// if we are journalling and it is a config file, write it to the journal file\n\tif ( isConfig && com_journal && com_journal->integer == 1 ) {\n\t\tCom_DPrintf( \"Writing %s to journal file.\\n\", qpath );\n\t\tFS_Write( &len, sizeof( len ), com_journalDataFile );\n\t\tFS_Write( buf, len, com_journalDataFile );\n\t\tFS_Flush( com_journalDataFile );\n\t}\n\treturn len;\n}\n\n/*\n=============\nFS_FreeFile\n=============\n*/\nvoid FS_FreeFile( void *buffer ) {\n\tif ( !fs_searchpaths ) {\n\t\tCom_Error( ERR_FATAL, \"Filesystem call made without initialization\\n\" );\n\t}\n\tif ( !buffer ) {\n\t\tCom_Error( ERR_FATAL, \"FS_FreeFile( NULL )\" );\n\t}\n\tfs_loadStack--;\n\n\tHunk_FreeTempMemory( buffer );\n\n\t// if all of our temp files are free, clear all of our space\n\tif ( fs_loadStack == 0 ) {\n\t\tHunk_ClearTempMemory();\n\t}\n}\n\n/*\n============\nFS_WriteFile\n\nFilename are reletive to the quake search path\n============\n*/\nvoid FS_WriteFile( const char *qpath, const void *buffer, int size ) {\n\tfileHandle_t f;\n\n\tif ( !fs_searchpaths ) {\n\t\tCom_Error( ERR_FATAL, \"Filesystem call made without initialization\\n\" );\n\t}\n\n\tif ( !qpath || !buffer ) {\n\t\tCom_Error( ERR_FATAL, \"FS_WriteFile: NULL parameter\" );\n\t}\n\n\tf = FS_FOpenFileWrite( qpath );\n\tif ( !f ) {\n\t\tCom_Printf( \"Failed to open %s\\n\", qpath );\n\t\treturn;\n\t}\n\n\tFS_Write( buffer, size, f );\n\n\tFS_FCloseFile( f );\n}\n\n\n\n/*\n==========================================================================\n\nZIP FILE LOADING\n\n==========================================================================\n*/\n\n/*\n=================\nFS_LoadZipFile\n\nCreates a new pak_t in the search chain for the contents\nof a zip file.\n=================\n*/\nstatic pack_t *FS_LoadZipFile( char *zipfile, const char *basename )\n{\n\tfileInPack_t\t*buildBuffer;\n\tpack_t\t\t\t*pack;\n\tunzFile\t\t\tuf;\n\tint\t\t\t\terr;\n\tunz_global_info gi;\n\tchar\t\t\tfilename_inzip[MAX_ZPATH];\n\tunz_file_info\tfile_info;\n\tint\t\t\t\ti, len;\n\tlong\t\t\thash;\n\tint\t\t\t\tfs_numHeaderLongs;\n\tint\t\t\t\t*fs_headerLongs;\n\tchar\t\t\t*namePtr;\n\n\tfs_numHeaderLongs = 0;\n\n\tuf = unzOpen(zipfile);\n\terr = unzGetGlobalInfo (uf,&gi);\n\n\tif (err != UNZ_OK)\n\t\treturn NULL;\n\n\tfs_packFiles += gi.number_entry;\n\n\tlen = 0;\n\tunzGoToFirstFile(uf);\n\tfor (i = 0; i < gi.number_entry; i++)\n\t{\n\t\terr = unzGetCurrentFileInfo(uf, &file_info, filename_inzip, sizeof(filename_inzip), NULL, 0, NULL, 0);\n\t\tif (err != UNZ_OK) {\n\t\t\tbreak;\n\t\t}\n\t\tlen += (int)strlen(filename_inzip) + 1;\n\t\tunzGoToNextFile(uf);\n\t}\n\n\tbuildBuffer = (fileInPack_t*) Z_Malloc( (gi.number_entry * sizeof( fileInPack_t )) + len );\n\tnamePtr = ((char *) buildBuffer) + gi.number_entry * sizeof( fileInPack_t );\n\tfs_headerLongs = (int*) Z_Malloc( gi.number_entry * sizeof(int) );\n\n\t// get the hash table size from the number of files in the zip\n\t// because lots of custom pk3 files have less than 32 or 64 files\n\tfor (i = 1; i <= MAX_FILEHASH_SIZE; i <<= 1) {\n\t\tif (i > gi.number_entry) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tpack = (pack_t*) Z_Malloc( sizeof( pack_t ) + i * sizeof(fileInPack_t *) );\n\tpack->hashSize = i;\n\tpack->hashTable = (fileInPack_t **) (((char *) pack) + sizeof( pack_t ));\n\tfor(i = 0; i < pack->hashSize; i++) {\n\t\tpack->hashTable[i] = NULL;\n\t}\n\n\tQ_strncpyz( pack->pakFilename, zipfile, sizeof( pack->pakFilename ) );\n\tQ_strncpyz( pack->pakBasename, basename, sizeof( pack->pakBasename ) );\n\n\t// strip .pk3 if needed\n\tif ( (int)strlen( pack->pakBasename ) > 4 && !Q_stricmp( pack->pakBasename + (int)strlen( pack->pakBasename ) - 4, \".pk3\" ) ) {\n\t\tpack->pakBasename[strlen( pack->pakBasename ) - 4] = 0;\n\t}\n\n\tpack->handle = uf;\n\tpack->numfiles = gi.number_entry;\n\tunzGoToFirstFile(uf);\n\n\tfor (i = 0; i < gi.number_entry; i++)\n\t{\n\t\terr = unzGetCurrentFileInfo(uf, &file_info, filename_inzip, sizeof(filename_inzip), NULL, 0, NULL, 0);\n\t\tif (err != UNZ_OK) {\n\t\t\tbreak;\n\t\t}\n\t\tif (file_info.uncompressed_size > 0) {\n\t\t\tfs_headerLongs[fs_numHeaderLongs++] = LittleLong(file_info.crc);\n\t\t}\n\t\tQ_strlwr( filename_inzip );\n\t\thash = FS_HashFileName(filename_inzip, pack->hashSize);\n\t\tbuildBuffer[i].name = namePtr;\n\t\tstrcpy( buildBuffer[i].name, filename_inzip );\n\t\tnamePtr += (int)strlen(filename_inzip) + 1;\n\t\t// store the file position in the zip\n\t\tunzGetCurrentFileInfoPosition(uf, &buildBuffer[i].pos);\n\t\t//\n\t\tbuildBuffer[i].next = pack->hashTable[hash];\n\t\tpack->hashTable[hash] = &buildBuffer[i];\n\t\tunzGoToNextFile(uf);\n\t}\n\n\tpack->checksum = Com_BlockChecksum( fs_headerLongs, 4 * fs_numHeaderLongs );\n\tpack->pure_checksum = Com_BlockChecksumKey( fs_headerLongs, 4 * fs_numHeaderLongs, LittleLong(fs_checksumFeed) );\n\tpack->checksum = LittleLong( pack->checksum );\n\tpack->pure_checksum = LittleLong( pack->pure_checksum );\n\n\tZ_Free(fs_headerLongs);\n\n\tpack->buildBuffer = buildBuffer;\n\treturn pack;\n}\n\n/*\n=================================================================================\n\nDIRECTORY SCANNING FUNCTIONS\n\n=================================================================================\n*/\n\n#define\tMAX_FOUND_FILES\t0x1000\n\nstatic int FS_ReturnPath( const char *zname, char *zpath, int *depth ) {\n\tint len, at, newdep;\n\n\tnewdep = 0;\n\tzpath[0] = 0;\n\tlen = 0;\n\tat = 0;\n\n\twhile(zname[at] != 0)\n\t{\n\t\tif (zname[at]=='/' || zname[at]=='\\\\') {\n\t\t\tlen = at;\n\t\t\tnewdep++;\n\t\t}\n\t\tat++;\n\t}\n\tstrcpy(zpath, zname);\n\tzpath[len] = 0;\n\t*depth = newdep;\n\n\treturn len;\n}\n\n/*\n==================\nFS_AddFileToList\n==================\n*/\nstatic int FS_AddFileToList( char *name, char *list[MAX_FOUND_FILES], int nfiles ) {\n\tint\t\ti;\n\n\tif ( nfiles == MAX_FOUND_FILES - 1 ) {\n\t\treturn nfiles;\n\t}\n\tfor ( i = 0 ; i < nfiles ; i++ ) {\n\t\tif ( !Q_stricmp( name, list[i] ) ) {\n\t\t\treturn nfiles;\t\t// allready in list\n\t\t}\n\t}\n\tlist[nfiles] = CopyString( name );\n\tnfiles++;\n\n\treturn nfiles;\n}\n\n/*\n===============\nFS_ListFilteredFiles\n\nReturns a uniqued list of files that match the given criteria\nfrom all search paths\n===============\n*/\nchar **FS_ListFilteredFiles( const char *path, const char *extension, char *filter, int *numfiles ) {\n\tint\t\t\t\tnfiles;\n\tchar\t\t\t**listCopy;\n\tchar\t\t\t*list[MAX_FOUND_FILES];\n\tsearchpath_t\t*search;\n\tint\t\t\t\ti;\n\tint\t\t\t\tpathLength;\n\tint\t\t\t\textensionLength;\n\tint\t\t\t\tlength, pathDepth, temp;\n\tpack_t\t\t\t*pak;\n\tfileInPack_t\t*buildBuffer;\n\tchar\t\t\tzpath[MAX_ZPATH];\n\n\tif ( !fs_searchpaths ) {\n\t\tCom_Error( ERR_FATAL, \"Filesystem call made without initialization\\n\" );\n\t}\n\n\tif ( !path ) {\n\t\t*numfiles = 0;\n\t\treturn NULL;\n\t}\n\tif ( !extension ) {\n\t\textension = \"\";\n\t}\n\n\tpathLength = (int)strlen( path );\n\tif ( path[pathLength-1] == '\\\\' || path[pathLength-1] == '/' ) {\n\t\tpathLength--;\n\t}\n\textensionLength = (int)strlen( extension );\n\tnfiles = 0;\n\tFS_ReturnPath(path, zpath, &pathDepth);\n\n\t//\n\t// search through the path, one element at a time, adding to list\n\t//\n\tfor (search = fs_searchpaths ; search ; search = search->next) {\n\t\t// is the element a pak file?\n\t\tif (search->pack) {\n\n\t\t\t//ZOID:  If we are pure, don't search for files on paks that\n\t\t\t// aren't on the pure list\n\t\t\tif ( !FS_PakIsPure(search->pack) ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// look through all the pak file elements\n\t\t\tpak = search->pack;\n\t\t\tbuildBuffer = pak->buildBuffer;\n\t\t\tfor (i = 0; i < pak->numfiles; i++) {\n\t\t\t\tchar\t*name;\n\t\t\t\tint\t\tzpathLen, depth;\n\n\t\t\t\t// check for directory match\n\t\t\t\tname = buildBuffer[i].name;\n\t\t\t\t//\n\t\t\t\tif (filter) {\n\t\t\t\t\t// case insensitive\n\t\t\t\t\tif (!Com_FilterPath( filter, name, qfalse ))\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t// unique the match\n\t\t\t\t\tnfiles = FS_AddFileToList( name, list, nfiles );\n\t\t\t\t}\n\t\t\t\telse {\n\n\t\t\t\t\tzpathLen = FS_ReturnPath(name, zpath, &depth);\n\n\t\t\t\t\tif ( (depth-pathDepth)>2 || pathLength > zpathLen || Q_stricmpn( name, path, pathLength ) ) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\t// check for extension match\n\t\t\t\t\tlength = (int)strlen( name );\n\t\t\t\t\tif ( length < extensionLength ) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( Q_stricmp( name + length - extensionLength, extension ) ) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\t// unique the match\n\n\t\t\t\t\ttemp = pathLength;\n\t\t\t\t\tif (pathLength) {\n\t\t\t\t\t\ttemp++;\t\t// include the '/'\n\t\t\t\t\t}\n\t\t\t\t\tnfiles = FS_AddFileToList( name + temp, list, nfiles );\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (search->dir) { // scan for files in the filesystem\n\t\t\tchar\t*netpath;\n\t\t\tint\t\tnumSysFiles;\n\t\t\tchar\t**sysFiles;\n\t\t\tchar\t*name;\n\n\t\t\t// don't scan directories for files if we are pure or restricted\n\t\t\tif ( fs_restrict->integer || fs_numServerPaks ) {\n\t\t        continue;\n\t\t    } else {\n\t\t\t\tnetpath = FS_BuildOSPath( search->dir->path, search->dir->gamedir, path );\n\t\t\t\tsysFiles = Sys_ListFiles( netpath, extension, filter, &numSysFiles, qfalse );\n\t\t\t\tfor ( i = 0 ; i < numSysFiles ; i++ ) {\n\t\t\t\t\t// unique the match\n\t\t\t\t\tname = sysFiles[i];\n\t\t\t\t\tnfiles = FS_AddFileToList( name, list, nfiles );\n\t\t\t\t}\n\t\t\t\tSys_FreeFileList( sysFiles );\n\t\t\t}\n\t\t}\t\t\n\t}\n\n\t// return a copy of the list\n\t*numfiles = nfiles;\n\n\tif ( !nfiles ) {\n\t\treturn NULL;\n\t}\n\n\tlistCopy = (char**) Z_Malloc( ( nfiles + 1 ) * sizeof( *listCopy ) );\n\tfor ( i = 0 ; i < nfiles ; i++ ) {\n\t\tlistCopy[i] = list[i];\n\t}\n\tlistCopy[i] = NULL;\n\n\treturn listCopy;\n}\n\n/*\n=================\nFS_ListFiles\n=================\n*/\nchar **FS_ListFiles( const char *path, const char *extension, int *numfiles ) {\n\treturn FS_ListFilteredFiles( path, extension, NULL, numfiles );\n}\n\n/*\n=================\nFS_FreeFileList\n=================\n*/\nvoid FS_FreeFileList( char **list ) {\n\tint\t\ti;\n\n\tif ( !fs_searchpaths ) {\n\t\tCom_Error( ERR_FATAL, \"Filesystem call made without initialization\\n\" );\n\t}\n\n\tif ( !list ) {\n\t\treturn;\n\t}\n\n\tfor ( i = 0 ; list[i] ; i++ ) {\n\t\tZ_Free( list[i] );\n\t}\n\n\tZ_Free( list );\n}\n\n\n/*\n================\nFS_GetFileList\n================\n*/\nint\tFS_GetFileList(  const char *path, const char *extension, char *listbuf, int bufsize ) {\n\tint\t\tnFiles, i, nTotal, nLen;\n\tchar **pFiles = NULL;\n\n\t*listbuf = 0;\n\tnFiles = 0;\n\tnTotal = 0;\n\n\tif (Q_stricmp(path, \"$modlist\") == 0) {\n\t\treturn FS_GetModList(listbuf, bufsize);\n\t}\n\n\tpFiles = FS_ListFiles(path, extension, &nFiles);\n\n\tfor (i =0; i < nFiles; i++) {\n\t\tnLen = (int)strlen(pFiles[i]) + 1;\n\t\tif (nTotal + nLen + 1 < bufsize) {\n\t\t\tstrcpy(listbuf, pFiles[i]);\n\t\t\tlistbuf += nLen;\n\t\t\tnTotal += nLen;\n\t\t}\n\t\telse {\n\t\t\tnFiles = i;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tFS_FreeFileList(pFiles);\n\n\treturn nFiles;\n}\n\n/*\n=======================\nSys_ConcatenateFileLists\n\nmkv: Naive implementation. Concatenates three lists into a\n     new list, and frees the old lists from the heap.\nbk001129 - from cvs1.17 (mkv)\n\nFIXME TTimo those two should move to common.c next to Sys_ListFiles\n=======================\n */\nstatic unsigned int Sys_CountFileList(char **list)\n{\n  int i = 0;\n\n  if (list)\n  {\n    while (*list)\n    {\n      list++;\n      i++;\n    }\n  }\n  return i;\n}\n\nstatic char** Sys_ConcatenateFileLists( char **list0, char **list1, char **list2 )\n{\n  int totalLength = 0;\n  char** cat = NULL, **dst, **src;\n\n  totalLength += Sys_CountFileList(list0);\n  totalLength += Sys_CountFileList(list1);\n  totalLength += Sys_CountFileList(list2);\n\n  /* Create new list. */\n  dst = cat = (char**) Z_Malloc( ( totalLength + 1 ) * sizeof( char* ) );\n\n  /* Copy over lists. */\n  if (list0)\n  {\n    for (src = list0; *src; src++, dst++)\n      *dst = *src;\n  }\n  if (list1)\n  {\n    for (src = list1; *src; src++, dst++)\n      *dst = *src;\n  }\n  if (list2)\n  {\n    for (src = list2; *src; src++, dst++)\n      *dst = *src;\n  }\n\n  // Terminate the list\n  *dst = NULL;\n\n  // Free our old lists.\n  // NOTE: not freeing their content, it's been merged in dst and still being used\n  if (list0) Z_Free( list0 );\n  if (list1) Z_Free( list1 );\n  if (list2) Z_Free( list2 );\n\n  return cat;\n}\n\n/*\n================\nFS_GetModList\n\nReturns a list of mod directory names\nA mod directory is a peer to baseq3 with a pk3 in it\nThe directories are searched in base path, cd path and home path\n================\n*/\nint\tFS_GetModList( char *listbuf, int bufsize ) {\n  int\t\tnMods, i, j, nTotal, nLen, nPaks, nPotential, nDescLen;\n  char **pFiles = NULL;\n  char **pPaks = NULL;\n  char *name, *path;\n  char descPath[MAX_OSPATH];\n  fileHandle_t descHandle;\n\n  int dummy;\n  char **pFiles0 = NULL;\n  char **pFiles1 = NULL;\n  char **pFiles2 = NULL;\n  qboolean bDrop = qfalse;\n\n  *listbuf = 0;\n  nMods = nPotential = nTotal = 0;\n\n  pFiles0 = Sys_ListFiles( fs_homepath->string, NULL, NULL, &dummy, qtrue );\n  pFiles1 = Sys_ListFiles( fs_basepath->string, NULL, NULL, &dummy, qtrue );\n  pFiles2 = Sys_ListFiles( fs_cdpath->string, NULL, NULL, &dummy, qtrue );\n  // we searched for mods in the three paths\n  // it is likely that we have duplicate names now, which we will cleanup below\n  pFiles = Sys_ConcatenateFileLists( pFiles0, pFiles1, pFiles2 );\n  nPotential = Sys_CountFileList(pFiles);\n\n  for ( i = 0 ; i < nPotential ; i++ ) {\n    name = pFiles[i];\n    // NOTE: cleaner would involve more changes\n    // ignore duplicate mod directories\n    if (i!=0) {\n      bDrop = qfalse;\n      for(j=0; j<i; j++)\n      {\n        if (Q_stricmp(pFiles[j],name)==0) {\n          // this one can be dropped\n          bDrop = qtrue;\n          break;\n        }\n      }\n    }\n    if (bDrop) {\n      continue;\n    }\n    // we drop \"baseq3\" \".\" and \"..\"\n    if (Q_stricmp(name, \"baseq3\") && Q_stricmpn(name, \".\", 1)) {\n      // now we need to find some .pk3 files to validate the mod\n      // NOTE TTimo: (actually I'm not sure why .. what if it's a mod under developement with no .pk3?)\n      // we didn't keep the information when we merged the directory names, as to what OS Path it was found under\n      //   so it could be in base path, cd path or home path\n      //   we will try each three of them here (yes, it's a bit messy)\n      path = FS_BuildOSPath( fs_basepath->string, name, \"\" );\n      nPaks = 0;\n      pPaks = Sys_ListFiles(path, \".pk3\", NULL, &nPaks, qfalse); \n      Sys_FreeFileList( pPaks ); // we only use Sys_ListFiles to check wether .pk3 files are present\n\n      /* Try on cd path */\n      if( nPaks <= 0 ) {\n        path = FS_BuildOSPath( fs_cdpath->string, name, \"\" );\n        nPaks = 0;\n        pPaks = Sys_ListFiles( path, \".pk3\", NULL, &nPaks, qfalse );\n        Sys_FreeFileList( pPaks );\n      }\n\n      /* try on home path */\n      if ( nPaks <= 0 )\n      {\n        path = FS_BuildOSPath( fs_homepath->string, name, \"\" );\n        nPaks = 0;\n        pPaks = Sys_ListFiles( path, \".pk3\", NULL, &nPaks, qfalse );\n        Sys_FreeFileList( pPaks );\n      }\n\n      if (nPaks > 0) {\n        nLen = (int)strlen(name) + 1;\n        // nLen is the length of the mod path\n        // we need to see if there is a description available\n        descPath[0] = '\\0';\n        strcpy(descPath, name);\n        strcat(descPath, \"/description.txt\");\n        nDescLen = FS_SV_FOpenFileRead( descPath, &descHandle );\n        if ( nDescLen > 0 && descHandle) {\n          FILE *file;\n          file = FS_FileForHandle(descHandle);\n          Com_Memset( descPath, 0, sizeof( descPath ) );\n          nDescLen = (int)fread(descPath, 1, 48, file);\n          if (nDescLen >= 0) {\n            descPath[nDescLen] = '\\0';\n          }\n          FS_FCloseFile(descHandle);\n        } else {\n          strcpy(descPath, name);\n        }\n        nDescLen = (int)strlen(descPath) + 1;\n\n        if (nTotal + nLen + 1 + nDescLen + 1 < bufsize) {\n          strcpy(listbuf, name);\n          listbuf += nLen;\n          strcpy(listbuf, descPath);\n          listbuf += nDescLen;\n          nTotal += nLen + nDescLen;\n          nMods++;\n        }\n        else {\n          break;\n        }\n      }\n    }\n  }\n  Sys_FreeFileList( pFiles );\n\n  return nMods;\n}\n\n\n\n\n//============================================================================\n\n/*\n================\nFS_Dir_f\n================\n*/\nvoid FS_Dir_f( void ) {\n\tchar\t*path;\n\tchar\t*extension;\n\tchar\t**dirnames;\n\tint\t\tndirs;\n\tint\t\ti;\n\n\tif ( Cmd_Argc() < 2 || Cmd_Argc() > 3 ) {\n\t\tCom_Printf( \"usage: dir <directory> [extension]\\n\" );\n\t\treturn;\n\t}\n\n\tif ( Cmd_Argc() == 2 ) {\n\t\tpath = Cmd_Argv( 1 );\n\t\textension = \"\";\n\t} else {\n\t\tpath = Cmd_Argv( 1 );\n\t\textension = Cmd_Argv( 2 );\n\t}\n\n\tCom_Printf( \"Directory of %s %s\\n\", path, extension );\n\tCom_Printf( \"---------------\\n\" );\n\n\tdirnames = FS_ListFiles( path, extension, &ndirs );\n\n\tfor ( i = 0; i < ndirs; i++ ) {\n\t\tCom_Printf( \"%s\\n\", dirnames[i] );\n\t}\n\tFS_FreeFileList( dirnames );\n}\n\n/*\n===========\nFS_ConvertPath\n===========\n*/\nvoid FS_ConvertPath( char *s ) {\n\twhile (*s) {\n\t\tif ( *s == '\\\\' || *s == ':' ) {\n\t\t\t*s = '/';\n\t\t}\n\t\ts++;\n\t}\n}\n\n/*\n===========\nFS_PathCmp\n\nIgnore case and seprator char distinctions\n===========\n*/\nint FS_PathCmp( const char *s1, const char *s2 ) {\n\tint\t\tc1, c2;\n\t\n\tdo {\n\t\tc1 = *s1++;\n\t\tc2 = *s2++;\n\n\t\tif (c1 >= 'a' && c1 <= 'z') {\n\t\t\tc1 -= ('a' - 'A');\n\t\t}\n\t\tif (c2 >= 'a' && c2 <= 'z') {\n\t\t\tc2 -= ('a' - 'A');\n\t\t}\n\n\t\tif ( c1 == '\\\\' || c1 == ':' ) {\n\t\t\tc1 = '/';\n\t\t}\n\t\tif ( c2 == '\\\\' || c2 == ':' ) {\n\t\t\tc2 = '/';\n\t\t}\n\t\t\n\t\tif (c1 < c2) {\n\t\t\treturn -1;\t\t// strings not equal\n\t\t}\n\t\tif (c1 > c2) {\n\t\t\treturn 1;\n\t\t}\n\t} while (c1);\n\t\n\treturn 0;\t\t// strings are equal\n}\n\n/*\n================\nFS_SortFileList\n================\n*/\nvoid FS_SortFileList(char **filelist, int numfiles) {\n\tint i, j, k, numsortedfiles;\n\tchar **sortedlist;\n\n\tsortedlist = (char**) Z_Malloc( ( numfiles + 1 ) * sizeof( *sortedlist ) );\n\tsortedlist[0] = NULL;\n\tnumsortedfiles = 0;\n\tfor (i = 0; i < numfiles; i++) {\n\t\tfor (j = 0; j < numsortedfiles; j++) {\n\t\t\tif (FS_PathCmp(filelist[i], sortedlist[j]) < 0) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tfor (k = numsortedfiles; k > j; k--) {\n\t\t\tsortedlist[k] = sortedlist[k-1];\n\t\t}\n\t\tsortedlist[j] = filelist[i];\n\t\tnumsortedfiles++;\n\t}\n\tCom_Memcpy(filelist, sortedlist, numfiles * sizeof( *filelist ) );\n\tZ_Free(sortedlist);\n}\n\n/*\n================\nFS_NewDir_f\n================\n*/\nvoid FS_NewDir_f( void ) {\n\tchar\t*filter;\n\tchar\t**dirnames;\n\tint\t\tndirs;\n\tint\t\ti;\n\n\tif ( Cmd_Argc() < 2 ) {\n\t\tCom_Printf( \"usage: fdir <filter>\\n\" );\n\t\tCom_Printf( \"example: fdir *q3dm*.bsp\\n\");\n\t\treturn;\n\t}\n\n\tfilter = Cmd_Argv( 1 );\n\n\tCom_Printf( \"---------------\\n\" );\n\n\tdirnames = FS_ListFilteredFiles( \"\", \"\", filter, &ndirs );\n\n\tFS_SortFileList(dirnames, ndirs);\n\n\tfor ( i = 0; i < ndirs; i++ ) {\n\t\tFS_ConvertPath(dirnames[i]);\n\t\tCom_Printf( \"%s\\n\", dirnames[i] );\n\t}\n\tCom_Printf( \"%d files listed\\n\", ndirs );\n\tFS_FreeFileList( dirnames );\n}\n\n/*\n============\nFS_Path_f\n\n============\n*/\nvoid FS_Path_f( void ) {\n\tsearchpath_t\t*s;\n\tint\t\t\t\ti;\n\n\tCom_Printf (\"Current search path:\\n\");\n\tfor (s = fs_searchpaths; s; s = s->next) {\n\t\tif (s->pack) {\n\t\t\tCom_Printf (\"%s (%i files)\\n\", s->pack->pakFilename, s->pack->numfiles);\n\t\t\tif ( fs_numServerPaks ) {\n\t\t\t\tif ( !FS_PakIsPure(s->pack) ) {\n\t\t\t\t\tCom_Printf( \"    not on the pure list\\n\" );\n\t\t\t\t} else {\n\t\t\t\t\tCom_Printf( \"    on the pure list\\n\" );\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tCom_Printf (\"%s/%s\\n\", s->dir->path, s->dir->gamedir );\n\t\t}\n\t}\n\n\n\tCom_Printf( \"\\n\" );\n\tfor ( i = 1 ; i < MAX_FILE_HANDLES ; i++ ) {\n\t\tif ( fsh[i].handleFiles.file.o ) {\n\t\t\tCom_Printf( \"handle %i: %s\\n\", i, fsh[i].name );\n\t\t}\n\t}\n}\n\n/*\n============\nFS_TouchFile_f\n\nThe only purpose of this function is to allow game script files to copy\narbitrary files furing an \"fs_copyfiles 1\" run.\n============\n*/\nvoid FS_TouchFile_f( void ) {\n\tfileHandle_t\tf;\n\n\tif ( Cmd_Argc() != 2 ) {\n\t\tCom_Printf( \"Usage: touchFile <file>\\n\" );\n\t\treturn;\n\t}\n\n\tFS_FOpenFileRead( Cmd_Argv( 1 ), &f, qfalse );\n\tif ( f ) {\n\t\tFS_FCloseFile( f );\n\t}\n}\n\n//===========================================================================\n\n\nstatic int QDECL paksort( const void *a, const void *b ) {\n\tchar\t*aa, *bb;\n\n\taa = *(char **)a;\n\tbb = *(char **)b;\n\n\treturn FS_PathCmp( aa, bb );\n}\n\n/*\n================\nFS_AddGameDirectory\n\nSets fs_gamedir, adds the directory to the head of the path,\nthen loads the zip headers\n================\n*/\n#define\tMAX_PAKFILES\t1024\nstatic void FS_AddGameDirectory( const char *path, const char *dir ) {\n\tsearchpath_t\t*sp;\n\tint\t\t\t\ti;\n\tsearchpath_t\t*search;\n\tpack_t\t\t\t*pak;\n\tchar\t\t\t*pakfile;\n\tint\t\t\t\tnumfiles;\n\tchar\t\t\t**pakfiles;\n\tchar\t\t\t*sorted[MAX_PAKFILES];\n\n\t// this fixes the case where fs_basepath is the same as fs_cdpath\n\t// which happens on full installs\n\tfor ( sp = fs_searchpaths ; sp ; sp = sp->next ) {\n\t\tif ( sp->dir && !Q_stricmp(sp->dir->path, path) && !Q_stricmp(sp->dir->gamedir, dir)) {\n\t\t\treturn;\t\t\t// we've already got this one\n\t\t}\n\t}\n\t\n\tQ_strncpyz( fs_gamedir, dir, sizeof( fs_gamedir ) );\n\n\t//\n\t// add the directory to the search path\n\t//\n\tsearch = (searchpath_t*) Z_Malloc (sizeof(searchpath_t));\n\tsearch->dir = (directory_t*) Z_Malloc( sizeof( *search->dir ) );\n\n\tQ_strncpyz( search->dir->path, path, sizeof( search->dir->path ) );\n\tQ_strncpyz( search->dir->gamedir, dir, sizeof( search->dir->gamedir ) );\n\tsearch->next = fs_searchpaths;\n\tfs_searchpaths = search;\n\n\t// find all pak files in this directory\n\tpakfile = FS_BuildOSPath( path, dir, \"\" );\n\tpakfile[ (int)strlen(pakfile) - 1 ] = 0;\t// strip the trailing slash\n\n\tpakfiles = Sys_ListFiles( pakfile, \".pk3\", NULL, &numfiles, qfalse );\n\n\t// sort them so that later alphabetic matches override\n\t// earlier ones.  This makes pak1.pk3 override pak0.pk3\n\tif ( numfiles > MAX_PAKFILES ) {\n\t\tnumfiles = MAX_PAKFILES;\n\t}\n\tfor ( i = 0 ; i < numfiles ; i++ ) {\n\t\tsorted[i] = pakfiles[i];\n\t}\n\n\tqsort( sorted, numfiles, sizeof(void*), paksort );\n\n\tfor ( i = 0 ; i < numfiles ; i++ ) {\n\t\tpakfile = FS_BuildOSPath( path, dir, sorted[i] );\n\t\tif ( ( pak = FS_LoadZipFile( pakfile, sorted[i] ) ) == 0 )\n\t\t\tcontinue;\n\t\t// store the game name for downloading\n\t\tstrcpy(pak->pakGamename, dir);\n\n\t\tsearch = (searchpath_t*) Z_Malloc (sizeof(searchpath_t));\n\t\tsearch->pack = pak;\n\t\tsearch->next = fs_searchpaths;\n\t\tfs_searchpaths = search;\n\t}\n\n\t// done\n\tSys_FreeFileList( pakfiles );\n}\n\n/*\n================\nFS_idPak\n================\n*/\nqboolean FS_idPak( char *pak, char *base ) {\n\tint i;\n\n\tfor (i = 0; i < NUM_ID_PAKS; i++) {\n\t\tif ( !FS_FilenameCompare(pak, va(\"%s/pak%d\", base, i)) ) {\n\t\t\tbreak;\n\t\t}\n\t}\n\tif (i < NUM_ID_PAKS) {\n\t\treturn qtrue;\n\t}\n\treturn qfalse;\n}\n\n/*\n================\nFS_ComparePaks\n\n----------------\ndlstring == qtrue\n\nReturns a list of pak files that we should download from the server. They all get stored\nin the current gamedir and an FS_Restart will be fired up after we download them all.\n\nThe string is the format:\n\n@remotename@localname [repeat]\n\nstatic int\t\tfs_numServerReferencedPaks;\nstatic int\t\tfs_serverReferencedPaks[MAX_SEARCH_PATHS];\nstatic char\t\t*fs_serverReferencedPakNames[MAX_SEARCH_PATHS];\n\n----------------\ndlstring == qfalse\n\nwe are not interested in a download string format, we want something human-readable\n(this is used for diagnostics while connecting to a pure server)\n\n================\n*/\nqboolean FS_ComparePaks( char *neededpaks, int len, qboolean dlstring ) {\n\tsearchpath_t\t*sp;\n\tqboolean havepak, badchecksum;\n\tint i;\n\n\tif ( !fs_numServerReferencedPaks ) {\n\t\treturn qfalse; // Server didn't send any pack information along\n\t}\n\n\t*neededpaks = 0;\n\n\tfor ( i = 0 ; i < fs_numServerReferencedPaks ; i++ ) {\n\t\t// Ok, see if we have this pak file\n\t\tbadchecksum = qfalse;\n\t\thavepak = qfalse;\n\n\t\t// never autodownload any of the id paks\n\t\tif ( FS_idPak(fs_serverReferencedPakNames[i], \"baseq3\") || FS_idPak(fs_serverReferencedPakNames[i], \"missionpack\") ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tfor ( sp = fs_searchpaths ; sp ; sp = sp->next ) {\n\t\t\tif ( sp->pack && sp->pack->checksum == fs_serverReferencedPaks[i] ) {\n\t\t\t\thavepak = qtrue; // This is it!\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif ( !havepak && fs_serverReferencedPakNames[i] && *fs_serverReferencedPakNames[i] ) { \n\t\t\t// Don't got it\n\n      if (dlstring)\n      {\n        // Remote name\n        Q_strcat( neededpaks, len, \"@\");\n        Q_strcat( neededpaks, len, fs_serverReferencedPakNames[i] );\n        Q_strcat( neededpaks, len, \".pk3\" );\n\n        // Local name\n        Q_strcat( neededpaks, len, \"@\");\n        // Do we have one with the same name?\n        if ( FS_SV_FileExists( va( \"%s.pk3\", fs_serverReferencedPakNames[i] ) ) )\n        {\n          char st[MAX_ZPATH];\n          // We already have one called this, we need to download it to another name\n          // Make something up with the checksum in it\n          Com_sprintf( st, sizeof( st ), \"%s.%08x.pk3\", fs_serverReferencedPakNames[i], fs_serverReferencedPaks[i] );\n          Q_strcat( neededpaks, len, st );\n        } else\n        {\n          Q_strcat( neededpaks, len, fs_serverReferencedPakNames[i] );\n          Q_strcat( neededpaks, len, \".pk3\" );\n        }\n      }\n      else\n      {\n        Q_strcat( neededpaks, len, fs_serverReferencedPakNames[i] );\n\t\t\t  Q_strcat( neededpaks, len, \".pk3\" );\n        // Do we have one with the same name?\n        if ( FS_SV_FileExists( va( \"%s.pk3\", fs_serverReferencedPakNames[i] ) ) )\n        {\n          Q_strcat( neededpaks, len, \" (local file exists with wrong checksum)\");\n        }\n        Q_strcat( neededpaks, len, \"\\n\");\n      }\n\t\t}\n\t}\n\n\tif ( *neededpaks ) {\n\t\treturn qtrue;\n\t}\n\n\treturn qfalse; // We have them all\n}\n\n/*\n================\nFS_Shutdown\n\nFrees all resources and closes all files\n================\n*/\nvoid FS_Shutdown( qboolean closemfp ) {\n\tsearchpath_t\t*p, *next;\n\tint\ti;\n\n\tfor(i = 0; i < MAX_FILE_HANDLES; i++) {\n\t\tif (fsh[i].fileSize) {\n\t\t\tFS_FCloseFile(i);\n\t\t}\n\t}\n\n\t// free everything\n\tfor ( p = fs_searchpaths ; p ; p = next ) {\n\t\tnext = p->next;\n\n\t\tif ( p->pack ) {\n\t\t\tunzClose(p->pack->handle);\n\t\t\tZ_Free( p->pack->buildBuffer );\n\t\t\tZ_Free( p->pack );\n\t\t}\n\t\tif ( p->dir ) {\n\t\t\tZ_Free( p->dir );\n\t\t}\n\t\tZ_Free( p );\n\t}\n\n\t// any FS_ calls will now be an error until reinitialized\n\tfs_searchpaths = NULL;\n\n\tCmd_RemoveCommand( \"path\" );\n\tCmd_RemoveCommand( \"dir\" );\n\tCmd_RemoveCommand( \"fdir\" );\n\tCmd_RemoveCommand( \"touchFile\" );\n\n#ifdef FS_MISSING\n\tif (closemfp) {\n\t\tfclose(missingFiles);\n\t}\n#endif\n}\n\nvoid Com_AppendCDKey( const char *filename );\nvoid Com_ReadCDKey( const char *filename );\n \n/*\n================\nFS_ReorderPurePaks\nNOTE TTimo: the reordering that happens here is not reflected in the cvars (\\cvarlist *pak*)\n  this can lead to misleading situations, see https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=540\n================\n*/\nstatic void FS_ReorderPurePaks()\n{\n\tsearchpath_t *s;\n\tint i;\n\tsearchpath_t **p_insert_index, // for linked list reordering\n\t\t**p_previous; // when doing the scan\n\t\n\t// only relevant when connected to pure server\n\tif ( !fs_numServerPaks )\n\t\treturn;\n\t\n\tfs_reordered = qfalse;\n\t\n\tp_insert_index = &fs_searchpaths; // we insert in order at the beginning of the list \n\tfor ( i = 0 ; i < fs_numServerPaks ; i++ ) {\n\t\tp_previous = p_insert_index; // track the pointer-to-current-item\n\t\tfor (s = *p_insert_index; s; s = s->next) {\n\t\t\t// the part of the list before p_insert_index has been sorted already\n\t\t\tif (s->pack && fs_serverPaks[i] == s->pack->checksum) {\n\t\t\t\tfs_reordered = qtrue;\n\t\t\t\t// move this element to the insert list\n\t\t\t\t*p_previous = s->next;\n\t\t\t\ts->next = *p_insert_index;\n\t\t\t\t*p_insert_index = s;\n\t\t\t\t// increment insert list\n\t\t\t\tp_insert_index = &s->next;\n\t\t\t\tbreak; // iterate to next server pack\n\t\t\t}\n\t\t\tp_previous = &s->next; \n\t\t}\n\t}\n}\n\n/*\n================\nFS_Startup\n================\n*/\nstatic void FS_Startup( const char *gameName ) {\n        const char *homePath;\n\tcvar_t\t*fs;\n\n\tCom_Printf( \"----- FS_Startup -----\\n\" );\n\n\tfs_debug = Cvar_Get( \"fs_debug\", \"0\", 0 );\n\tfs_copyfiles = Cvar_Get( \"fs_copyfiles\", \"0\", CVAR_INIT );\n\tfs_cdpath = Cvar_Get (\"fs_cdpath\", Sys_DefaultCDPath(), CVAR_INIT );\n\tfs_basepath = Cvar_Get (\"fs_basepath\", Sys_DefaultInstallPath(), CVAR_INIT );\n\tfs_basegame = Cvar_Get (\"fs_basegame\", \"\", CVAR_INIT );\n  homePath = Sys_DefaultHomePath();\n  if (!homePath || !homePath[0]) {\n\t\thomePath = fs_basepath->string;\n\t}\n\tfs_homepath = Cvar_Get (\"fs_homepath\", homePath, CVAR_INIT );\n\tfs_gamedirvar = Cvar_Get (\"fs_game\", \"\", CVAR_INIT|CVAR_SYSTEMINFO );\n\tfs_restrict = Cvar_Get (\"fs_restrict\", \"\", CVAR_INIT );\n\n\t// add search path elements in reverse priority order\n\tif (fs_cdpath->string[0]) {\n\t\tFS_AddGameDirectory( fs_cdpath->string, gameName );\n\t}\n\tif (fs_basepath->string[0]) {\n\t\tFS_AddGameDirectory( fs_basepath->string, gameName );\n\t}\n  // fs_homepath is somewhat particular to *nix systems, only add if relevant\n  // NOTE: same filtering below for mods and basegame\n\tif (fs_basepath->string[0] && Q_stricmp(fs_homepath->string,fs_basepath->string)) {\n\t\tFS_AddGameDirectory ( fs_homepath->string, gameName );\n\t}\n        \n\t// check for additional base game so mods can be based upon other mods\n\tif ( fs_basegame->string[0] && !Q_stricmp( gameName, BASEGAME ) && Q_stricmp( fs_basegame->string, gameName ) ) {\n\t\tif (fs_cdpath->string[0]) {\n\t\t\tFS_AddGameDirectory(fs_cdpath->string, fs_basegame->string);\n\t\t}\n\t\tif (fs_basepath->string[0]) {\n\t\t\tFS_AddGameDirectory(fs_basepath->string, fs_basegame->string);\n\t\t}\n\t\tif (fs_homepath->string[0] && Q_stricmp(fs_homepath->string,fs_basepath->string)) {\n\t\t\tFS_AddGameDirectory(fs_homepath->string, fs_basegame->string);\n\t\t}\n\t}\n\n\t// check for additional game folder for mods\n\tif ( fs_gamedirvar->string[0] && !Q_stricmp( gameName, BASEGAME ) && Q_stricmp( fs_gamedirvar->string, gameName ) ) {\n\t\tif (fs_cdpath->string[0]) {\n\t\t\tFS_AddGameDirectory(fs_cdpath->string, fs_gamedirvar->string);\n\t\t}\n\t\tif (fs_basepath->string[0]) {\n\t\t\tFS_AddGameDirectory(fs_basepath->string, fs_gamedirvar->string);\n\t\t}\n\t\tif (fs_homepath->string[0] && Q_stricmp(fs_homepath->string,fs_basepath->string)) {\n\t\t\tFS_AddGameDirectory(fs_homepath->string, fs_gamedirvar->string);\n\t\t}\n\t}\n\n\tCom_ReadCDKey( \"baseq3\" );\n\tfs = Cvar_Get (\"fs_game\", \"\", CVAR_INIT|CVAR_SYSTEMINFO );\n\tif (fs && fs->string[0] != 0) {\n\t\tCom_AppendCDKey( fs->string );\n\t}\n\n\t// add our commands\n\tCmd_AddCommand (\"path\", FS_Path_f);\n\tCmd_AddCommand (\"dir\", FS_Dir_f );\n\tCmd_AddCommand (\"fdir\", FS_NewDir_f );\n\tCmd_AddCommand (\"touchFile\", FS_TouchFile_f );\n\n\t// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=506\n\t// reorder the pure pk3 files according to server order\n\tFS_ReorderPurePaks();\n\t\n\t// print the current search paths\n\tFS_Path_f();\n\n\tfs_gamedirvar->modified = qfalse; // We just loaded, it's not modified\n\n\tCom_Printf( \"----------------------\\n\" );\n\n#ifdef FS_MISSING\n\tif (missingFiles == NULL) {\n\t\tmissingFiles = fopen( \"\\\\missing.txt\", \"ab\" );\n\t}\n#endif\n\tCom_Printf( \"%d files in pk3 files\\n\", fs_packFiles );\n}\n\n\n/*\n===================\nFS_SetRestrictions\n\nLooks for product keys and restricts media add on ability\nif the full version is not found\n===================\n*/\nstatic void FS_SetRestrictions( void ) {\n\tsearchpath_t\t*path;\n\n#ifndef PRE_RELEASE_DEMO\n\tchar\t*productId;\n\n\t// if fs_restrict is set, don't even look for the id file,\n\t// which allows the demo release to be tested even if\n\t// the full game is present\n\tif ( !fs_restrict->integer ) {\n\t\t// look for the full game id\n\t\tFS_ReadFile( \"productid.txt\", (void **)&productId );\n\t\tif ( productId ) {\n\t\t\t// check against the hardcoded string\n\t\t\tint\t\tseed, i;\n\n\t\t\tseed = 5000;\n\t\t\tfor ( i = 0 ; i < sizeof( fs_scrambledProductId ) ; i++ ) {\n\t\t\t\tif ( ( fs_scrambledProductId[i] ^ (seed&255) ) != productId[i] ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tseed = (69069 * seed + 1);\n\t\t\t}\n\n\t\t\tFS_FreeFile( productId );\n\n\t\t\tif ( i == sizeof( fs_scrambledProductId ) ) {\n\t\t\t\treturn;\t// no restrictions\n\t\t\t}\n\t\t\tCom_Error( ERR_FATAL, \"Invalid product identification\" );\n\t\t}\n\t}\n#endif\n\tCvar_Set( \"fs_restrict\", \"1\" );\n\n\tCom_Printf( \"\\nRunning in restricted demo mode.\\n\\n\" );\n\n\t// restart the filesystem with just the demo directory\n\tFS_Shutdown(qfalse);\n\tFS_Startup( DEMOGAME );\n\n\t// make sure that the pak file has the header checksum we expect\n\tfor ( path = fs_searchpaths ; path ; path = path->next ) {\n\t\tif ( path->pack ) {\n\t\t\t// a tiny attempt to keep the checksum from being scannable from the exe\n\t\t\tif ( (path->pack->checksum ^ 0x02261994u) != (DEMO_PAK_CHECKSUM ^ 0x02261994u) ) {\n\t\t\t\tCom_Error( ERR_FATAL, \"Corrupted pak0.pk3: %u\", path->pack->checksum );\n\t\t\t}\n\t\t}\n\t}\n}\n\n/*\n=====================\nFS_GamePureChecksum\n\nReturns the checksum of the pk3 from which the server loaded the qagame.qvm\n=====================\n*/\nconst char *FS_GamePureChecksum( void ) {\n\tstatic char\tinfo[MAX_STRING_TOKENS];\n\tsearchpath_t *search;\n\n\tinfo[0] = 0;\n\n\tfor ( search = fs_searchpaths ; search ; search = search->next ) {\n\t\t// is the element a pak file?\n\t\tif ( search->pack ) {\n\t\t\tif (search->pack->referenced & FS_QAGAME_REF) {\n\t\t\t\tCom_sprintf(info, sizeof(info), \"%d\", search->pack->checksum);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn info;\n}\n\n/*\n=====================\nFS_LoadedPakChecksums\n\nReturns a space separated string containing the checksums of all loaded pk3 files.\nServers with sv_pure set will get this string and pass it to clients.\n=====================\n*/\nconst char *FS_LoadedPakChecksums( void ) {\n\tstatic char\tinfo[BIG_INFO_STRING];\n\tsearchpath_t\t*search;\n\n\tinfo[0] = 0;\n\n\tfor ( search = fs_searchpaths ; search ; search = search->next ) {\n\t\t// is the element a pak file? \n\t\tif ( !search->pack ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tQ_strcat( info, sizeof( info ), va(\"%i \", search->pack->checksum ) );\n\t}\n\n\treturn info;\n}\n\n/*\n=====================\nFS_LoadedPakNames\n\nReturns a space separated string containing the names of all loaded pk3 files.\nServers with sv_pure set will get this string and pass it to clients.\n=====================\n*/\nconst char *FS_LoadedPakNames( void ) {\n\tstatic char\tinfo[BIG_INFO_STRING];\n\tsearchpath_t\t*search;\n\n\tinfo[0] = 0;\n\n\tfor ( search = fs_searchpaths ; search ; search = search->next ) {\n\t\t// is the element a pak file?\n\t\tif ( !search->pack ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (*info) {\n\t\t\tQ_strcat(info, sizeof( info ), \" \" );\n\t\t}\n\t\tQ_strcat( info, sizeof( info ), search->pack->pakBasename );\n\t}\n\n\treturn info;\n}\n\n/*\n=====================\nFS_LoadedPakPureChecksums\n\nReturns a space separated string containing the pure checksums of all loaded pk3 files.\nServers with sv_pure use these checksums to compare with the checksums the clients send\nback to the server.\n=====================\n*/\nconst char *FS_LoadedPakPureChecksums( void ) {\n\tstatic char\tinfo[BIG_INFO_STRING];\n\tsearchpath_t\t*search;\n\n\tinfo[0] = 0;\n\n\tfor ( search = fs_searchpaths ; search ; search = search->next ) {\n\t\t// is the element a pak file? \n\t\tif ( !search->pack ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tQ_strcat( info, sizeof( info ), va(\"%i \", search->pack->pure_checksum ) );\n\t}\n\n\treturn info;\n}\n\n/*\n=====================\nFS_ReferencedPakChecksums\n\nReturns a space separated string containing the checksums of all referenced pk3 files.\nThe server will send this to the clients so they can check which files should be auto-downloaded. \n=====================\n*/\nconst char *FS_ReferencedPakChecksums( void ) {\n\tstatic char\tinfo[BIG_INFO_STRING];\n\tsearchpath_t *search;\n\n\tinfo[0] = 0;\n\n\n\tfor ( search = fs_searchpaths ; search ; search = search->next ) {\n\t\t// is the element a pak file?\n\t\tif ( search->pack ) {\n\t\t\tif (search->pack->referenced || Q_stricmpn(search->pack->pakGamename, BASEGAME, (int)strlen(BASEGAME))) {\n\t\t\t\tQ_strcat( info, sizeof( info ), va(\"%i \", search->pack->checksum ) );\n\t\t\t}\n\t\t}\n\t}\n\n\treturn info;\n}\n\n/*\n=====================\nFS_ReferencedPakPureChecksums\n\nReturns a space separated string containing the pure checksums of all referenced pk3 files.\nServers with sv_pure set will get this string back from clients for pure validation \n\nThe string has a specific order, \"cgame ui @ ref1 ref2 ref3 ...\"\n=====================\n*/\nconst char *FS_ReferencedPakPureChecksums( void ) {\n\tstatic char\tinfo[BIG_INFO_STRING];\n\tsearchpath_t\t*search;\n\tint nFlags, numPaks, checksum;\n\n\tinfo[0] = 0;\n\n\tchecksum = fs_checksumFeed;\n\tnumPaks = 0;\n\tfor (nFlags = FS_CGAME_REF; nFlags; nFlags = nFlags >> 1) {\n\t\tif (nFlags & FS_GENERAL_REF) {\n\t\t\t// add a delimter between must haves and general refs\n\t\t\t//Q_strcat(info, sizeof(info), \"@ \");\n\t\t\tinfo[strlen(info)+1] = '\\0';\n\t\t\tinfo[strlen(info)+2] = '\\0';\n\t\t\tinfo[strlen(info)] = '@';\n\t\t\tinfo[strlen(info)] = ' ';\n\t\t}\n\t\tfor ( search = fs_searchpaths ; search ; search = search->next ) {\n\t\t\t// is the element a pak file and has it been referenced based on flag?\n\t\t\tif ( search->pack && (search->pack->referenced & nFlags)) {\n\t\t\t\tQ_strcat( info, sizeof( info ), va(\"%i \", search->pack->pure_checksum ) );\n\t\t\t\tif (nFlags & (FS_CGAME_REF | FS_UI_REF)) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tchecksum ^= search->pack->pure_checksum;\n\t\t\t\tnumPaks++;\n\t\t\t}\n\t\t}\n\t\tif (fs_fakeChkSum != 0) {\n\t\t\t// only added if a non-pure file is referenced\n\t\t\tQ_strcat( info, sizeof( info ), va(\"%i \", fs_fakeChkSum ) );\n\t\t}\n\t}\n\t// last checksum is the encoded number of referenced pk3s\n\tchecksum ^= numPaks;\n\tQ_strcat( info, sizeof( info ), va(\"%i \", checksum ) );\n\n\treturn info;\n}\n\n/*\n=====================\nFS_ReferencedPakNames\n\nReturns a space separated string containing the names of all referenced pk3 files.\nThe server will send this to the clients so they can check which files should be auto-downloaded. \n=====================\n*/\nconst char *FS_ReferencedPakNames( void ) {\n\tstatic char\tinfo[BIG_INFO_STRING];\n\tsearchpath_t\t*search;\n\n\tinfo[0] = 0;\n\n\t// we want to return ALL pk3's from the fs_game path\n\t// and referenced one's from baseq3\n\tfor ( search = fs_searchpaths ; search ; search = search->next ) {\n\t\t// is the element a pak file?\n\t\tif ( search->pack ) {\n\t\t\tif (*info) {\n\t\t\t\tQ_strcat(info, sizeof( info ), \" \" );\n\t\t\t}\n\t\t\tif (search->pack->referenced || Q_stricmpn(search->pack->pakGamename, BASEGAME, (int)strlen(BASEGAME))) {\n\t\t\t\tQ_strcat( info, sizeof( info ), search->pack->pakGamename );\n\t\t\t\tQ_strcat( info, sizeof( info ), \"/\" );\n\t\t\t\tQ_strcat( info, sizeof( info ), search->pack->pakBasename );\n\t\t\t}\n\t\t}\n\t}\n\n\treturn info;\n}\n\n/*\n=====================\nFS_ClearPakReferences\n=====================\n*/\nvoid FS_ClearPakReferences( int flags ) {\n\tsearchpath_t *search;\n\n\tif ( !flags ) {\n\t\tflags = -1;\n\t}\n\tfor ( search = fs_searchpaths; search; search = search->next ) {\n\t\t// is the element a pak file and has it been referenced?\n\t\tif ( search->pack ) {\n\t\t\tsearch->pack->referenced &= ~flags;\n\t\t}\n\t}\n}\n\n\n/*\n=====================\nFS_PureServerSetLoadedPaks\n\nIf the string is empty, all data sources will be allowed.\nIf not empty, only pk3 files that match one of the space\nseparated checksums will be checked for files, with the\nexception of .cfg and .dat files.\n=====================\n*/\nvoid FS_PureServerSetLoadedPaks( const char *pakSums, const char *pakNames ) {\n\tint\t\ti, c, d;\n\n\tCmd_TokenizeString( pakSums );\n\n\tc = Cmd_Argc();\n\tif ( c > MAX_SEARCH_PATHS ) {\n\t\tc = MAX_SEARCH_PATHS;\n\t}\n\n\tfs_numServerPaks = c;\n\n\tfor ( i = 0 ; i < c ; i++ ) {\n\t\tfs_serverPaks[i] = atoi( Cmd_Argv( i ) );\n\t}\n\n\tif (fs_numServerPaks) {\n\t\tCom_DPrintf( \"Connected to a pure server.\\n\" );\n\t}\n\telse\n\t{\n\t\tif (fs_reordered)\n\t\t{\n\t\t\t// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=540\n\t\t\t// force a restart to make sure the search order will be correct\n\t\t\tCom_DPrintf( \"FS search reorder is required\\n\" );\n\t\t\tFS_Restart(fs_checksumFeed);\n\t\t\treturn;\n\t\t}\n\t}\n\n\tfor ( i = 0 ; i < c ; i++ ) {\n\t\tif (fs_serverPakNames[i]) {\n\t\t\tZ_Free(fs_serverPakNames[i]);\n\t\t}\n\t\tfs_serverPakNames[i] = NULL;\n\t}\n\tif ( pakNames && *pakNames ) {\n\t\tCmd_TokenizeString( pakNames );\n\n\t\td = Cmd_Argc();\n\t\tif ( d > MAX_SEARCH_PATHS ) {\n\t\t\td = MAX_SEARCH_PATHS;\n\t\t}\n\n\t\tfor ( i = 0 ; i < d ; i++ ) {\n\t\t\tfs_serverPakNames[i] = CopyString( Cmd_Argv( i ) );\n\t\t}\n\t}\n}\n\n/*\n=====================\nFS_PureServerSetReferencedPaks\n\nThe checksums and names of the pk3 files referenced at the server\nare sent to the client and stored here. The client will use these\nchecksums to see if any pk3 files need to be auto-downloaded. \n=====================\n*/\nvoid FS_PureServerSetReferencedPaks( const char *pakSums, const char *pakNames ) {\n\tint\t\ti, c, d;\n\n\tCmd_TokenizeString( pakSums );\n\n\tc = Cmd_Argc();\n\tif ( c > MAX_SEARCH_PATHS ) {\n\t\tc = MAX_SEARCH_PATHS;\n\t}\n\n\tfs_numServerReferencedPaks = c;\n\n\tfor ( i = 0 ; i < c ; i++ ) {\n\t\tfs_serverReferencedPaks[i] = atoi( Cmd_Argv( i ) );\n\t}\n\n\tfor ( i = 0 ; i < c ; i++ ) {\n\t\tif (fs_serverReferencedPakNames[i]) {\n\t\t\tZ_Free(fs_serverReferencedPakNames[i]);\n\t\t}\n\t\tfs_serverReferencedPakNames[i] = NULL;\n\t}\n\tif ( pakNames && *pakNames ) {\n\t\tCmd_TokenizeString( pakNames );\n\n\t\td = Cmd_Argc();\n\t\tif ( d > MAX_SEARCH_PATHS ) {\n\t\t\td = MAX_SEARCH_PATHS;\n\t\t}\n\n\t\tfor ( i = 0 ; i < d ; i++ ) {\n\t\t\tfs_serverReferencedPakNames[i] = CopyString( Cmd_Argv( i ) );\n\t\t}\n\t}\n}\n\n/*\n================\nFS_InitFilesystem\n\nCalled only at inital startup, not when the filesystem\nis resetting due to a game change\n================\n*/\nvoid FS_InitFilesystem( void ) {\n\t// allow command line parms to override our defaults\n\t// we have to specially handle this, because normal command\n\t// line variable sets don't happen until after the filesystem\n\t// has already been initialized\n\tCom_StartupVariable( \"fs_cdpath\" );\n\tCom_StartupVariable( \"fs_basepath\" );\n\tCom_StartupVariable( \"fs_homepath\" );\n\tCom_StartupVariable( \"fs_game\" );\n\tCom_StartupVariable( \"fs_copyfiles\" );\n\tCom_StartupVariable( \"fs_restrict\" );\n\n\t// try to start up normally\n\tFS_Startup( BASEGAME );\n\n\t// see if we are going to allow add-ons\n\tFS_SetRestrictions();\n\n\t// if we can't find default.cfg, assume that the paths are\n\t// busted and error out now, rather than getting an unreadable\n\t// graphics screen when the font fails to load\n\tif ( FS_ReadFile( \"default.cfg\", NULL ) <= 0 ) {\n\t\tCom_Error( ERR_FATAL, \"Couldn't load default.cfg\" );\n\t\t// bk001208 - SafeMode see below, FIXME?\n\t}\n\n\tQ_strncpyz(lastValidBase, fs_basepath->string, sizeof(lastValidBase));\n\tQ_strncpyz(lastValidGame, fs_gamedirvar->string, sizeof(lastValidGame));\n\n  // bk001208 - SafeMode see below, FIXME?\n}\n\n\n/*\n================\nFS_Restart\n================\n*/\nvoid FS_Restart( int checksumFeed ) {\n\n\t// free anything we currently have loaded\n\tFS_Shutdown(qfalse);\n\n\t// set the checksum feed\n\tfs_checksumFeed = checksumFeed;\n\n\t// clear pak references\n\tFS_ClearPakReferences(0);\n\n\t// try to start up normally\n\tFS_Startup( BASEGAME );\n\n\t// see if we are going to allow add-ons\n\tFS_SetRestrictions();\n\n\t// if we can't find default.cfg, assume that the paths are\n\t// busted and error out now, rather than getting an unreadable\n\t// graphics screen when the font fails to load\n\tif ( FS_ReadFile( \"default.cfg\", NULL ) <= 0 ) {\n\t\t// this might happen when connecting to a pure server not using BASEGAME/pak0.pk3\n\t\t// (for instance a TA demo server)\n\t\tif (lastValidBase[0]) {\n\t\t\tFS_PureServerSetLoadedPaks(\"\", \"\");\n\t\t\tCvar_Set(\"fs_basepath\", lastValidBase);\n\t\t\tCvar_Set(\"fs_gamedirvar\", lastValidGame);\n\t\t\tlastValidBase[0] = '\\0';\n\t\t\tlastValidGame[0] = '\\0';\n\t\t\tCvar_Set( \"fs_restrict\", \"0\" );\n\t\t\tFS_Restart(checksumFeed);\n\t\t\tCom_Error( ERR_DROP, \"Invalid game folder\\n\" );\n\t\t\treturn;\n\t\t}\n\t\tCom_Error( ERR_FATAL, \"Couldn't load default.cfg\" );\n\t}\n\n\t// bk010116 - new check before safeMode\n\tif ( Q_stricmp(fs_gamedirvar->string, lastValidGame) ) {\n\t\t// skip the q3config.cfg if \"safe\" is on the command line\n\t\tif ( !Com_SafeMode() ) {\n\t\t\tCbuf_AddText (\"exec q3config.cfg\\n\");\n\t\t}\n\t}\n\n\tQ_strncpyz(lastValidBase, fs_basepath->string, sizeof(lastValidBase));\n\tQ_strncpyz(lastValidGame, fs_gamedirvar->string, sizeof(lastValidGame));\n\n}\n\n/*\n=================\nFS_ConditionalRestart\nrestart if necessary\n=================\n*/\nqboolean FS_ConditionalRestart( int checksumFeed ) {\n\tif( fs_gamedirvar->modified || checksumFeed != fs_checksumFeed ) {\n\t\tFS_Restart( checksumFeed );\n\t\treturn qtrue;\n\t}\n\treturn qfalse;\n}\n\n/*\n========================================================================================\n\nHandle based file calls for virtual machines\n\n========================================================================================\n*/\n\nint\t\tFS_FOpenFileByMode( const char *qpath, fileHandle_t *f, fsMode_t mode ) {\n\tint\t\tr;\n\tqboolean\tsync;\n\n\tsync = qfalse;\n\n\tswitch( mode ) {\n\tcase FS_READ:\n\t\tr = FS_FOpenFileRead( qpath, f, qtrue );\n\t\tbreak;\n\tcase FS_WRITE:\n\t\t*f = FS_FOpenFileWrite( qpath );\n\t\tr = 0;\n\t\tif (*f == 0) {\n\t\t\tr = -1;\n\t\t}\n\t\tbreak;\n\tcase FS_APPEND_SYNC:\n\t\tsync = qtrue;\n\tcase FS_APPEND:\n\t\t*f = FS_FOpenFileAppend( qpath );\n\t\tr = 0;\n\t\tif (*f == 0) {\n\t\t\tr = -1;\n\t\t}\n\t\tbreak;\n\tdefault:\n\t\tCom_Error( ERR_FATAL, \"FSH_FOpenFile: bad mode\" );\n\t\treturn -1;\n\t}\n\n\tif (!f) {\n\t\treturn r;\n\t}\n\n\tif ( *f ) {\n\t\tif (fsh[*f].zipFile == qtrue) {\n\t\t\tfsh[*f].baseOffset = unztell(fsh[*f].handleFiles.file.z);\n\t\t} else {\n\t\t\tfsh[*f].baseOffset = ftell(fsh[*f].handleFiles.file.o);\n\t\t}\n\t\tfsh[*f].fileSize = r;\n\t\tfsh[*f].streamed = qfalse;\n\n\t\tif (mode == FS_READ) {\n\t\t\tSys_BeginStreamedFile( *f, 0x4000 );\n\t\t\tfsh[*f].streamed = qtrue;\n\t\t}\n\t}\n\tfsh[*f].handleSync = sync;\n\n\treturn r;\n}\n\nint\t\tFS_FTell( fileHandle_t f ) {\n\tint pos;\n\tif (fsh[f].zipFile == qtrue) {\n\t\tpos = unztell(fsh[f].handleFiles.file.z);\n\t} else {\n\t\tpos = ftell(fsh[f].handleFiles.file.o);\n\t}\n\treturn pos;\n}\n\nvoid\tFS_Flush( fileHandle_t f ) {\n\tfflush(fsh[f].handleFiles.file.o);\n}\n\n"
  },
  {
    "path": "src/engine/qcommon/huffman.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n/* This is based on the Adaptive Huffman algorithm described in Sayood's Data\n * Compression book.  The ranks are not actually stored, but implicitly defined\n * by the location of a node within a doubly-linked list */\n\n#include \"../../game/q_shared.h\"\n#include \"qcommon.h\"\n\nstatic int\t\t\tbloc = 0;\n\nvoid\tHuff_putBit( int bit, byte *fout, int *offset) {\n\tbloc = *offset;\n\tif ((bloc&7) == 0) {\n\t\tfout[(bloc>>3)] = 0;\n\t}\n\tfout[(bloc>>3)] |= bit << (bloc&7);\n\tbloc++;\n\t*offset = bloc;\n}\n\nint\t\tHuff_getBit( byte *fin, int *offset) {\n\tint t;\n\tbloc = *offset;\n\tt = (fin[(bloc>>3)] >> (bloc&7)) & 0x1;\n\tbloc++;\n\t*offset = bloc;\n\treturn t;\n}\n\n/* Add a bit to the output file (buffered) */\nstatic void add_bit (char bit, byte *fout) {\n\tif ((bloc&7) == 0) {\n\t\tfout[(bloc>>3)] = 0;\n\t}\n\tfout[(bloc>>3)] |= bit << (bloc&7);\n\tbloc++;\n}\n\n/* Receive one bit from the input file (buffered) */\nstatic int get_bit (byte *fin) {\n\tint t;\n\tt = (fin[(bloc>>3)] >> (bloc&7)) & 0x1;\n\tbloc++;\n\treturn t;\n}\n\nstatic node_t **get_ppnode(huff_t* huff) {\n\tnode_t **tppnode;\n\tif (!huff->freelist) {\n\t\treturn &(huff->nodePtrs[huff->blocPtrs++]);\n\t} else {\n\t\ttppnode = huff->freelist;\n\t\thuff->freelist = (node_t **)*tppnode;\n\t\treturn tppnode;\n\t}\n}\n\nstatic void free_ppnode(huff_t* huff, node_t **ppnode) {\n\t*ppnode = (node_t *)huff->freelist;\n\thuff->freelist = ppnode;\n}\n\n/* Swap the location of these two nodes in the tree */\nstatic void swap (huff_t* huff, node_t *node1, node_t *node2) { \n\tnode_t *par1, *par2;\n\n\tpar1 = node1->parent;\n\tpar2 = node2->parent;\n\n\tif (par1) {\n\t\tif (par1->left == node1) {\n\t\t\tpar1->left = node2;\n\t\t} else {\n\t      par1->right = node2;\n\t\t}\n\t} else {\n\t\thuff->tree = node2;\n\t}\n\n\tif (par2) {\n\t\tif (par2->left == node2) {\n\t\t\tpar2->left = node1;\n\t\t} else {\n\t\t\tpar2->right = node1;\n\t\t}\n\t} else {\n\t\thuff->tree = node1;\n\t}\n  \n\tnode1->parent = par2;\n\tnode2->parent = par1;\n}\n\n/* Swap these two nodes in the linked list (update ranks) */\nstatic void swaplist(node_t *node1, node_t *node2) {\n\tnode_t *par1;\n\n\tpar1 = node1->next;\n\tnode1->next = node2->next;\n\tnode2->next = par1;\n\n\tpar1 = node1->prev;\n\tnode1->prev = node2->prev;\n\tnode2->prev = par1;\n\n\tif (node1->next == node1) {\n\t\tnode1->next = node2;\n\t}\n\tif (node2->next == node2) {\n\t\tnode2->next = node1;\n\t}\n\tif (node1->next) {\n\t\tnode1->next->prev = node1;\n\t}\n\tif (node2->next) {\n\t\tnode2->next->prev = node2;\n\t}\n\tif (node1->prev) {\n\t\tnode1->prev->next = node1;\n\t}\n\tif (node2->prev) {\n\t\tnode2->prev->next = node2;\n\t}\n}\n\n/* Do the increments */\nstatic void increment(huff_t* huff, node_t *node) {\n\tnode_t *lnode;\n\n\tif (!node) {\n\t\treturn;\n\t}\n\n\tif (node->next != NULL && node->next->weight == node->weight) {\n\t    lnode = *node->head;\n\t\tif (lnode != node->parent) {\n\t\t\tswap(huff, lnode, node);\n\t\t}\n\t\tswaplist(lnode, node);\n\t}\n\tif (node->prev && node->prev->weight == node->weight) {\n\t\t*node->head = node->prev;\n\t} else {\n\t    *node->head = NULL;\n\t\tfree_ppnode(huff, node->head);\n\t}\n\tnode->weight++;\n\tif (node->next && node->next->weight == node->weight) {\n\t\tnode->head = node->next->head;\n\t} else { \n\t\tnode->head = get_ppnode(huff);\n\t\t*node->head = node;\n\t}\n\tif (node->parent) {\n\t\tincrement(huff, node->parent);\n\t\tif (node->prev == node->parent) {\n\t\t\tswaplist(node, node->parent);\n\t\t\tif (*node->head == node) {\n\t\t\t\t*node->head = node->parent;\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid Huff_addRef(huff_t* huff, byte ch) {\n\tnode_t *tnode, *tnode2;\n\tif (huff->loc[ch] == NULL) { /* if this is the first transmission of this node */\n\t\ttnode = &(huff->nodeList[huff->blocNode++]);\n\t\ttnode2 = &(huff->nodeList[huff->blocNode++]);\n\n\t\ttnode2->symbol = INTERNAL_NODE;\n\t\ttnode2->weight = 1;\n\t\ttnode2->next = huff->lhead->next;\n\t\tif (huff->lhead->next) {\n\t\t\thuff->lhead->next->prev = tnode2;\n\t\t\tif (huff->lhead->next->weight == 1) {\n\t\t\t\ttnode2->head = huff->lhead->next->head;\n\t\t\t} else {\n\t\t\t\ttnode2->head = get_ppnode(huff);\n\t\t\t\t*tnode2->head = tnode2;\n\t\t\t}\n\t\t} else {\n\t\t\ttnode2->head = get_ppnode(huff);\n\t\t\t*tnode2->head = tnode2;\n\t\t}\n\t\thuff->lhead->next = tnode2;\n\t\ttnode2->prev = huff->lhead;\n \n\t\ttnode->symbol = ch;\n\t\ttnode->weight = 1;\n\t\ttnode->next = huff->lhead->next;\n\t\tif (huff->lhead->next) {\n\t\t\thuff->lhead->next->prev = tnode;\n\t\t\tif (huff->lhead->next->weight == 1) {\n\t\t\t\ttnode->head = huff->lhead->next->head;\n\t\t\t} else {\n\t\t\t\t/* this should never happen */\n\t\t\t\ttnode->head = get_ppnode(huff);\n\t\t\t\t*tnode->head = tnode2;\n\t\t    }\n\t\t} else {\n\t\t\t/* this should never happen */\n\t\t\ttnode->head = get_ppnode(huff);\n\t\t\t*tnode->head = tnode;\n\t\t}\n\t\thuff->lhead->next = tnode;\n\t\ttnode->prev = huff->lhead;\n\t\ttnode->left = tnode->right = NULL;\n \n\t\tif (huff->lhead->parent) {\n\t\t\tif (huff->lhead->parent->left == huff->lhead) { /* lhead is guaranteed to by the NYT */\n\t\t\t\thuff->lhead->parent->left = tnode2;\n\t\t\t} else {\n\t\t\t\thuff->lhead->parent->right = tnode2;\n\t\t\t}\n\t\t} else {\n\t\t\thuff->tree = tnode2; \n\t\t}\n \n\t\ttnode2->right = tnode;\n\t\ttnode2->left = huff->lhead;\n \n\t\ttnode2->parent = huff->lhead->parent;\n\t\thuff->lhead->parent = tnode->parent = tnode2;\n     \n\t\thuff->loc[ch] = tnode;\n \n\t\tincrement(huff, tnode2->parent);\n\t} else {\n\t\tincrement(huff, huff->loc[ch]);\n\t}\n}\n\n/* Get a symbol */\nint Huff_Receive (node_t *node, int *ch, byte *fin) {\n\twhile (node && node->symbol == INTERNAL_NODE) {\n\t\tif (get_bit(fin)) {\n\t\t\tnode = node->right;\n\t\t} else {\n\t\t\tnode = node->left;\n\t\t}\n\t}\n\tif (!node) {\n\t\treturn 0;\n//\t\tCom_Error(ERR_DROP, \"Illegal tree!\\n\");\n\t}\n\treturn (*ch = node->symbol);\n}\n\n/* Get a symbol */\nvoid Huff_offsetReceive (node_t *node, int *ch, byte *fin, int *offset) {\n\tbloc = *offset;\n\twhile (node && node->symbol == INTERNAL_NODE) {\n\t\tif (get_bit(fin)) {\n\t\t\tnode = node->right;\n\t\t} else {\n\t\t\tnode = node->left;\n\t\t}\n\t}\n\tif (!node) {\n\t\t*ch = 0;\n\t\treturn;\n//\t\tCom_Error(ERR_DROP, \"Illegal tree!\\n\");\n\t}\n\t*ch = node->symbol;\n\t*offset = bloc;\n}\n\n/* Send the prefix code for this node */\nstatic void send(node_t *node, node_t *child, byte *fout) {\n\tif (node->parent) {\n\t\tsend(node->parent, node, fout);\n\t}\n\tif (child) {\n\t\tif (node->right == child) {\n\t\t\tadd_bit(1, fout);\n\t\t} else {\n\t\t\tadd_bit(0, fout);\n\t\t}\n\t}\n}\n\n/* Send a symbol */\nvoid Huff_transmit (huff_t *huff, int ch, byte *fout) {\n\tint i;\n\tif (huff->loc[ch] == NULL) { \n\t\t/* node_t hasn't been transmitted, send a NYT, then the symbol */\n\t\tHuff_transmit(huff, NYT, fout);\n\t\tfor (i = 7; i >= 0; i--) {\n\t\t\tadd_bit((char)((ch >> i) & 0x1), fout);\n\t\t}\n\t} else {\n\t\tsend(huff->loc[ch], NULL, fout);\n\t}\n}\n\nvoid Huff_offsetTransmit (huff_t *huff, int ch, byte *fout, int *offset) {\n\tbloc = *offset;\n\tsend(huff->loc[ch], NULL, fout);\n\t*offset = bloc;\n}\n\nvoid Huff_Decompress(msg_t *mbuf, int offset) {\n\tint\t\t\tch, cch, i, j, size;\n\tbyte\t\tseq[65536];\n\tbyte*\t\tbuffer;\n\thuff_t\t\thuff;\n\n\tsize = mbuf->cursize - offset;\n\tbuffer = mbuf->data + offset;\n\n\tif ( size <= 0 ) {\n\t\treturn;\n\t}\n\n\tCom_Memset(&huff, 0, sizeof(huff_t));\n\t// Initialize the tree & list with the NYT node \n\thuff.tree = huff.lhead = huff.ltail = huff.loc[NYT] = &(huff.nodeList[huff.blocNode++]);\n\thuff.tree->symbol = NYT;\n\thuff.tree->weight = 0;\n\thuff.lhead->next = huff.lhead->prev = NULL;\n\thuff.tree->parent = huff.tree->left = huff.tree->right = NULL;\n\n\tcch = buffer[0]*256 + buffer[1];\n\t// don't overflow with bad messages\n\tif ( cch > mbuf->maxsize - offset ) {\n\t\tcch = mbuf->maxsize - offset;\n\t}\n\tbloc = 16;\n\n\tfor ( j = 0; j < cch; j++ ) {\n\t\tch = 0;\n\t\t// don't overflow reading from the messages\n\t\t// FIXME: would it be better to have a overflow check in get_bit ?\n\t\tif ( (bloc >> 3) > size ) {\n\t\t\tseq[j] = 0;\n\t\t\tbreak;\n\t\t}\n\t\tHuff_Receive(huff.tree, &ch, buffer);\t\t\t\t/* Get a character */\n\t\tif ( ch == NYT ) {\t\t\t\t\t\t\t\t/* We got a NYT, get the symbol associated with it */\n\t\t\tch = 0;\n\t\t\tfor ( i = 0; i < 8; i++ ) {\n\t\t\t\tch = (ch<<1) + get_bit(buffer);\n\t\t\t}\n\t\t}\n    \n\t\tseq[j] = ch;\t\t\t\t\t\t\t\t\t/* Write symbol */\n\n\t\tHuff_addRef(&huff, (byte)ch);\t\t\t\t\t\t\t\t/* Increment node */\n\t}\n\tmbuf->cursize = cch + offset;\n\tCom_Memcpy(mbuf->data + offset, seq, cch);\n}\n\nextern \tint oldsize;\n\nvoid Huff_Compress(msg_t *mbuf, int offset) {\n\tint\t\t\ti, ch, size;\n\tbyte\t\tseq[65536];\n\tbyte*\t\tbuffer;\n\thuff_t\t\thuff;\n\n\tsize = mbuf->cursize - offset;\n\tbuffer = mbuf->data+ + offset;\n\n\tif (size<=0) {\n\t\treturn;\n\t}\n\n\tCom_Memset(&huff, 0, sizeof(huff_t));\n\t// Add the NYT (not yet transmitted) node into the tree/list */\n\thuff.tree = huff.lhead = huff.loc[NYT] =  &(huff.nodeList[huff.blocNode++]);\n\thuff.tree->symbol = NYT;\n\thuff.tree->weight = 0;\n\thuff.lhead->next = huff.lhead->prev = NULL;\n\thuff.tree->parent = huff.tree->left = huff.tree->right = NULL;\n\thuff.loc[NYT] = huff.tree;\n\n\tseq[0] = (size>>8);\n\tseq[1] = size&0xff;\n\n\tbloc = 16;\n\n\tfor (i=0; i<size; i++ ) {\n\t\tch = buffer[i];\n\t\tHuff_transmit(&huff, ch, seq);\t\t\t\t\t\t/* Transmit symbol */\n\t\tHuff_addRef(&huff, (byte)ch);\t\t\t\t\t\t\t\t/* Do update */\n\t}\n\n\tbloc += 8;\t\t\t\t\t\t\t\t\t\t\t\t// next byte\n\n\tmbuf->cursize = (bloc>>3) + offset;\n\tCom_Memcpy(mbuf->data+offset, seq, (bloc>>3));\n}\n\nvoid Huff_Init(huffman_t *huff) {\n\n\tCom_Memset(&huff->compressor, 0, sizeof(huff_t));\n\tCom_Memset(&huff->decompressor, 0, sizeof(huff_t));\n\n\t// Initialize the tree & list with the NYT node \n\thuff->decompressor.tree = huff->decompressor.lhead = huff->decompressor.ltail = huff->decompressor.loc[NYT] = &(huff->decompressor.nodeList[huff->decompressor.blocNode++]);\n\thuff->decompressor.tree->symbol = NYT;\n\thuff->decompressor.tree->weight = 0;\n\thuff->decompressor.lhead->next = huff->decompressor.lhead->prev = NULL;\n\thuff->decompressor.tree->parent = huff->decompressor.tree->left = huff->decompressor.tree->right = NULL;\n\n\t// Add the NYT (not yet transmitted) node into the tree/list */\n\thuff->compressor.tree = huff->compressor.lhead = huff->compressor.loc[NYT] =  &(huff->compressor.nodeList[huff->compressor.blocNode++]);\n\thuff->compressor.tree->symbol = NYT;\n\thuff->compressor.tree->weight = 0;\n\thuff->compressor.lhead->next = huff->compressor.lhead->prev = NULL;\n\thuff->compressor.tree->parent = huff->compressor.tree->left = huff->compressor.tree->right = NULL;\n\thuff->compressor.loc[NYT] = huff->compressor.tree;\n}\n\n"
  },
  {
    "path": "src/engine/qcommon/md4.c",
    "content": "/* GLOBAL.H - RSAREF types and constants */\n\n#include <string.h>\n#if defined(_WIN32)\n#pragma warning(disable : 4711)\t\t// selected for automatic inline expansion\n#endif\n\n/* POINTER defines a generic pointer type */\ntypedef unsigned char *POINTER;\n\n/* UINT2 defines a two byte word */\ntypedef unsigned short int UINT2;\n\n/* UINT4 defines a four byte word */\ntypedef unsigned long int UINT4;\n\n  \n/* MD4.H - header file for MD4C.C */\n\n/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. \n\nAll rights reserved.\n  \nLicense to copy and use this software is granted provided that it is identified as the RSA Data Security, Inc. MD4 Message-Digest Algorithm in all material mentioning or referencing this software or this function.\nLicense is also granted to make and use derivative works provided that such works are identified as derived from the RSA Data Security, Inc. MD4 Message-Digest Algorithm in all material mentioning or referencing the derived work.\nRSA Data Security, Inc. makes no representations concerning either the merchantability of this software or the suitability of this software for any particular purpose. It is provided as is without express or implied warranty of any kind.\n  \nThese notices must be retained in any copies of any part of this documentation and/or software. */\n\n/* MD4 context. */\ntypedef struct {\n\tUINT4 state[4];\t\t\t\t/* state (ABCD) */\n\tUINT4 count[2];\t\t\t\t/* number of bits, modulo 2^64 (lsb first) */\n\tunsigned char buffer[64]; \t\t\t/* input buffer */\n} MD4_CTX;\n\nvoid MD4Init (MD4_CTX *);\nvoid MD4Update (MD4_CTX *, const unsigned char *, unsigned int);\nvoid MD4Final (unsigned char [16], MD4_CTX *);\n\n#ifndef __VECTORC  \nvoid Com_Memset (void* dest, const int val, const size_t count);\nvoid Com_Memcpy (void* dest, const void* src, const size_t count);\n#else\n#define Com_Memset memset\n#define Com_Memcpy memcpy\n#endif\n\n/* MD4C.C - RSA Data Security, Inc., MD4 message-digest algorithm */\n/* Copyright (C) 1990-2, RSA Data Security, Inc. All rights reserved.\n  \nLicense to copy and use this software is granted provided that it is identified as the\nRSA Data Security, Inc. MD4 Message-Digest Algorithm\n in all material mentioning or referencing this software or this function.\nLicense is also granted to make and use derivative works provided that such works are identified as \nderived from the RSA Data Security, Inc. MD4 Message-Digest Algorithm\nin all material mentioning or referencing the derived work.\nRSA Data Security, Inc. makes no representations concerning either the merchantability of this software or the suitability of this software for any particular purpose. It is provided\nas is without express or implied warranty of any kind.\n  \nThese notices must be retained in any copies of any part of this documentation and/or software. */\n\n/* Constants for MD4Transform routine.  */\n#define S11 3\n#define S12 7\n#define S13 11\n#define S14 19\n#define S21 3\n#define S22 5\n#define S23 9\n#define S24 13\n#define S31 3\n#define S32 9\n#define S33 11\n#define S34 15\n\nstatic void MD4Transform (UINT4 [4], const unsigned char [64]);\nstatic void Encode (unsigned char *, UINT4 *, unsigned int);\nstatic void Decode (UINT4 *, const unsigned char *, unsigned int);\n\nstatic unsigned char PADDING[64] = {\n0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n};\n\n/* F, G and H are basic MD4 functions. */\n#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))\n#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))\n#define H(x, y, z) ((x) ^ (y) ^ (z))\n\n/* ROTATE_LEFT rotates x left n bits. */\n#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))\n\n/* FF, GG and HH are transformations for rounds 1, 2 and 3 */\n/* Rotation is separate from addition to prevent recomputation */\n#define FF(a, b, c, d, x, s) {(a) += F ((b), (c), (d)) + (x); (a) = ROTATE_LEFT ((a), (s));}\n\n#define GG(a, b, c, d, x, s) {(a) += G ((b), (c), (d)) + (x) + (UINT4)0x5a827999; (a) = ROTATE_LEFT ((a), (s));}\n\n#define HH(a, b, c, d, x, s) {(a) += H ((b), (c), (d)) + (x) + (UINT4)0x6ed9eba1; (a) = ROTATE_LEFT ((a), (s));}\n\n\n/* MD4 initialization. Begins an MD4 operation, writing a new context. */\nvoid MD4Init (MD4_CTX *context)\n{\n\tcontext->count[0] = context->count[1] = 0;\n\n/* Load magic initialization constants.*/\ncontext->state[0] = 0x67452301;\ncontext->state[1] = 0xefcdab89;\ncontext->state[2] = 0x98badcfe;\ncontext->state[3] = 0x10325476;\n}\n\n/* MD4 block update operation. Continues an MD4 message-digest operation, processing another message block, and updating the context. */\nvoid MD4Update (MD4_CTX *context, const unsigned char *input, unsigned int inputLen)\n{\n\tunsigned int i, index, partLen;\n\n\t/* Compute number of bytes mod 64 */\n\tindex = (unsigned int)((context->count[0] >> 3) & 0x3F);\n\n\t/* Update number of bits */\n\tif ((context->count[0] += ((UINT4)inputLen << 3))< ((UINT4)inputLen << 3))\n\t\tcontext->count[1]++;\n\n\tcontext->count[1] += ((UINT4)inputLen >> 29);\n\n\tpartLen = 64 - index;\n\n\t/* Transform as many times as possible.*/\n\tif (inputLen >= partLen)\n\t{\n \t\tCom_Memcpy((POINTER)&context->buffer[index], (POINTER)input, partLen);\n \t\tMD4Transform (context->state, context->buffer);\n\n \t\tfor (i = partLen; i + 63 < inputLen; i += 64)\n \t\t\tMD4Transform (context->state, &input[i]);\n\n \t\tindex = 0;\n\t}\n\telse\n \t\ti = 0;\n\n\t/* Buffer remaining input */\n\tCom_Memcpy ((POINTER)&context->buffer[index], (POINTER)&input[i], inputLen-i);\n}\n\n\n/* MD4 finalization. Ends an MD4 message-digest operation, writing the the message digest and zeroizing the context. */\nvoid MD4Final (unsigned char digest[16], MD4_CTX *context)\n{\n\tunsigned char bits[8];\n\tunsigned int index, padLen;\n\n\t/* Save number of bits */\n\tEncode (bits, context->count, 8);\n\n\t/* Pad out to 56 mod 64.*/\n\tindex = (unsigned int)((context->count[0] >> 3) & 0x3f);\n\tpadLen = (index < 56) ? (56 - index) : (120 - index);\n\tMD4Update (context, PADDING, padLen);\n\n\t/* Append length (before padding) */\n\tMD4Update (context, bits, 8);\n\t\n\t/* Store state in digest */\n\tEncode (digest, context->state, 16);\n\n\t/* Zeroize sensitive information.*/\n\tCom_Memset ((POINTER)context, 0, sizeof (*context));\n}\n\n\n/* MD4 basic transformation. Transforms state based on block. */\nstatic void MD4Transform (UINT4 state[4], const unsigned char block[64])\n{\n\tUINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];\n\n\tDecode (x, block, 64);\n\n/* Round 1 */\nFF (a, b, c, d, x[ 0], S11); \t\t\t\t/* 1 */\nFF (d, a, b, c, x[ 1], S12); \t\t\t\t/* 2 */\nFF (c, d, a, b, x[ 2], S13); \t\t\t\t/* 3 */\nFF (b, c, d, a, x[ 3], S14); \t\t\t\t/* 4 */\nFF (a, b, c, d, x[ 4], S11); \t\t\t\t/* 5 */\nFF (d, a, b, c, x[ 5], S12); \t\t\t\t/* 6 */\nFF (c, d, a, b, x[ 6], S13); \t\t\t\t/* 7 */\nFF (b, c, d, a, x[ 7], S14); \t\t\t\t/* 8 */\nFF (a, b, c, d, x[ 8], S11); \t\t\t\t/* 9 */\nFF (d, a, b, c, x[ 9], S12); \t\t\t\t/* 10 */\nFF (c, d, a, b, x[10], S13); \t\t\t/* 11 */\nFF (b, c, d, a, x[11], S14); \t\t\t/* 12 */\nFF (a, b, c, d, x[12], S11); \t\t\t/* 13 */\nFF (d, a, b, c, x[13], S12); \t\t\t/* 14 */\nFF (c, d, a, b, x[14], S13); \t\t\t/* 15 */\nFF (b, c, d, a, x[15], S14); \t\t\t/* 16 */\n\n/* Round 2 */\nGG (a, b, c, d, x[ 0], S21); \t\t\t/* 17 */\nGG (d, a, b, c, x[ 4], S22); \t\t\t/* 18 */\nGG (c, d, a, b, x[ 8], S23); \t\t\t/* 19 */\nGG (b, c, d, a, x[12], S24); \t\t\t/* 20 */\nGG (a, b, c, d, x[ 1], S21); \t\t\t/* 21 */\nGG (d, a, b, c, x[ 5], S22); \t\t\t/* 22 */\nGG (c, d, a, b, x[ 9], S23); \t\t\t/* 23 */\nGG (b, c, d, a, x[13], S24); \t\t\t/* 24 */\nGG (a, b, c, d, x[ 2], S21); \t\t\t/* 25 */\nGG (d, a, b, c, x[ 6], S22); \t\t\t/* 26 */\nGG (c, d, a, b, x[10], S23); \t\t\t/* 27 */\nGG (b, c, d, a, x[14], S24); \t\t\t/* 28 */\nGG (a, b, c, d, x[ 3], S21); \t\t\t/* 29 */\nGG (d, a, b, c, x[ 7], S22); \t\t\t/* 30 */\nGG (c, d, a, b, x[11], S23); \t\t\t/* 31 */\nGG (b, c, d, a, x[15], S24); \t\t\t/* 32 */\n\n/* Round 3 */\nHH (a, b, c, d, x[ 0], S31);\t\t\t\t/* 33 */\nHH (d, a, b, c, x[ 8], S32); \t\t\t/* 34 */\nHH (c, d, a, b, x[ 4], S33); \t\t\t/* 35 */\nHH (b, c, d, a, x[12], S34); \t\t\t/* 36 */\nHH (a, b, c, d, x[ 2], S31); \t\t\t/* 37 */\nHH (d, a, b, c, x[10], S32); \t\t\t/* 38 */\nHH (c, d, a, b, x[ 6], S33); \t\t\t/* 39 */\nHH (b, c, d, a, x[14], S34); \t\t\t/* 40 */\nHH (a, b, c, d, x[ 1], S31); \t\t\t/* 41 */\nHH (d, a, b, c, x[ 9], S32); \t\t\t/* 42 */\nHH (c, d, a, b, x[ 5], S33); \t\t\t/* 43 */\nHH (b, c, d, a, x[13], S34); \t\t\t/* 44 */\nHH (a, b, c, d, x[ 3], S31); \t\t\t/* 45 */\nHH (d, a, b, c, x[11], S32); \t\t\t/* 46 */\nHH (c, d, a, b, x[ 7], S33); \t\t\t/* 47 */\nHH (b, c, d, a, x[15], S34);\t\t\t/* 48 */\n\nstate[0] += a;\nstate[1] += b;\nstate[2] += c;\nstate[3] += d;\n\n\t/* Zeroize sensitive information.*/\n\tCom_Memset ((POINTER)x, 0, sizeof (x));\n}\n\n\n/* Encodes input (UINT4) into output (unsigned char). Assumes len is a multiple of 4. */\nstatic void Encode (unsigned char *output, UINT4 *input, unsigned int len)\n{\n\tunsigned int i, j;\n\n\tfor (i = 0, j = 0; j < len; i++, j += 4) {\n \t\toutput[j] = (unsigned char)(input[i] & 0xff);\n \t\toutput[j+1] = (unsigned char)((input[i] >> 8) & 0xff);\n \t\toutput[j+2] = (unsigned char)((input[i] >> 16) & 0xff);\n \t\toutput[j+3] = (unsigned char)((input[i] >> 24) & 0xff);\n\t}\n}\n\n\n/* Decodes input (unsigned char) into output (UINT4). Assumes len is a multiple of 4. */\nstatic void Decode (UINT4 *output, const unsigned char *input, unsigned int len)\n{\nunsigned int i, j;\n\nfor (i = 0, j = 0; j < len; i++, j += 4)\n \toutput[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);\n}\n\n//===================================================================\n\nunsigned Com_BlockChecksum (const void *buffer, int length)\n{\n\tint\t\t\tdigest[4];\n\tunsigned\tval;\n\tMD4_CTX\t\tctx;\n\n\tMD4Init (&ctx);\n\tMD4Update (&ctx, (unsigned char *)buffer, length);\n\tMD4Final ( (unsigned char *)digest, &ctx);\n\t\n\tval = digest[0] ^ digest[1] ^ digest[2] ^ digest[3];\n\n\treturn val;\n}\n\nunsigned Com_BlockChecksumKey (void *buffer, int length, int key)\n{\n\tint\t\t\tdigest[4];\n\tunsigned\tval;\n\tMD4_CTX\t\tctx;\n\n\tMD4Init (&ctx);\n\tMD4Update (&ctx, (unsigned char *)&key, 4);\n\tMD4Update (&ctx, (unsigned char *)buffer, length);\n\tMD4Final ( (unsigned char *)digest, &ctx);\n\t\n\tval = digest[0] ^ digest[1] ^ digest[2] ^ digest[3];\n\n\treturn val;\n}\n"
  },
  {
    "path": "src/engine/qcommon/msg.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n#include \"../../game/q_shared.h\"\n#include \"qcommon.h\"\n\nstatic huffman_t\t\tmsgHuff;\n\nstatic qboolean\t\t\tmsgInit = qfalse;\n\nint pcount[256];\n\n/*\n==============================================================================\n\n\t\t\tMESSAGE IO FUNCTIONS\n\nHandles byte ordering and avoids alignment errors\n==============================================================================\n*/\n\nint oldsize = 0;\n\nvoid MSG_initHuffman();\n\nvoid MSG_Init( msg_t *buf, byte *data, int length ) {\n\tif (!msgInit) {\n\t\tMSG_initHuffman();\n\t}\n\tCom_Memset (buf, 0, sizeof(*buf));\n\tbuf->data = data;\n\tbuf->maxsize = length;\n}\n\nvoid MSG_InitOOB( msg_t *buf, byte *data, int length ) {\n\tif (!msgInit) {\n\t\tMSG_initHuffman();\n\t}\n\tCom_Memset (buf, 0, sizeof(*buf));\n\tbuf->data = data;\n\tbuf->maxsize = length;\n\tbuf->oob = qtrue;\n}\n\nvoid MSG_Clear( msg_t *buf ) {\n\tbuf->cursize = 0;\n\tbuf->overflowed = qfalse;\n\tbuf->bit = 0;\t\t\t\t\t//<- in bits\n}\n\n\nvoid MSG_Bitstream( msg_t *buf ) {\n\tbuf->oob = qfalse;\n}\n\nvoid MSG_BeginReading( msg_t *msg ) {\n\tmsg->readcount = 0;\n\tmsg->bit = 0;\n\tmsg->oob = qfalse;\n}\n\nvoid MSG_BeginReadingOOB( msg_t *msg ) {\n\tmsg->readcount = 0;\n\tmsg->bit = 0;\n\tmsg->oob = qtrue;\n}\n\nvoid MSG_Copy(msg_t *buf, byte *data, int length, msg_t *src)\n{\n\tif (length<src->cursize) {\n\t\tCom_Error( ERR_DROP, \"MSG_Copy: can't copy into a smaller msg_t buffer\");\n\t}\n\tCom_Memcpy(buf, src, sizeof(msg_t));\n\tbuf->data = data;\n\tCom_Memcpy(buf->data, src->data, src->cursize);\n}\n\n/*\n=============================================================================\n\nbit functions\n  \n=============================================================================\n*/\n\nint\toverflows;\n\n// negative bit values include signs\nvoid MSG_WriteBits( msg_t *msg, int value, int bits ) {\n\tint\ti;\n//\tFILE*\tfp;\n\n\toldsize += bits;\n\n\t// this isn't an exact overflow check, but close enough\n\tif ( msg->maxsize - msg->cursize < 4 ) {\n\t\tmsg->overflowed = qtrue;\n\t\treturn;\n\t}\n\n\tif ( bits == 0 || bits < -31 || bits > 32 ) {\n\t\tCom_Error( ERR_DROP, \"MSG_WriteBits: bad bits %i\", bits );\n\t}\n\n\t// check for overflows\n\tif ( bits != 32 ) {\n\t\tif ( bits > 0 ) {\n\t\t\tif ( value > ( ( 1 << bits ) - 1 ) || value < 0 ) {\n\t\t\t\toverflows++;\n\t\t\t}\n\t\t} else {\n\t\t\tint\tr;\n\n\t\t\tr = 1 << (bits-1);\n\n\t\t\tif ( value >  r - 1 || value < -r ) {\n\t\t\t\toverflows++;\n\t\t\t}\n\t\t}\n\t}\n\tif ( bits < 0 ) {\n\t\tbits = -bits;\n\t}\n\tif (msg->oob) {\n\t\tif (bits==8) {\n\t\t\tmsg->data[msg->cursize] = value;\n\t\t\tmsg->cursize += 1;\n\t\t\tmsg->bit += 8;\n\t\t} else if (bits==16) {\n\t\t\tunsigned short *sp = (unsigned short *)&msg->data[msg->cursize];\n\t\t\t*sp = LittleShort(value);\n\t\t\tmsg->cursize += 2;\n\t\t\tmsg->bit += 16;\n\t\t} else if (bits==32) {\n\t\t\tunsigned int *ip = (unsigned int *)&msg->data[msg->cursize];\n\t\t\t*ip = LittleLong(value);\n\t\t\tmsg->cursize += 4;\n\t\t\tmsg->bit += 8;\n\t\t} else {\n\t\t\tCom_Error(ERR_DROP, \"can't read %d bits\\n\", bits);\n\t\t}\n\t} else {\n//\t\tfp = fopen(\"c:\\\\netchan.bin\", \"a\");\n\t\tvalue &= (0xffffffff>>(32-bits));\n\t\tif (bits&7) {\n\t\t\tint nbits;\n\t\t\tnbits = bits&7;\n\t\t\tfor(i=0;i<nbits;i++) {\n\t\t\t\tHuff_putBit((value&1), msg->data, &msg->bit);\n\t\t\t\tvalue = (value>>1);\n\t\t\t}\n\t\t\tbits = bits - nbits;\n\t\t}\n\t\tif (bits) {\n\t\t\tfor(i=0;i<bits;i+=8) {\n//\t\t\t\tfwrite(bp, 1, 1, fp);\n\t\t\t\tHuff_offsetTransmit (&msgHuff.compressor, (value&0xff), msg->data, &msg->bit);\n\t\t\t\tvalue = (value>>8);\n\t\t\t}\n\t\t}\n\t\tmsg->cursize = (msg->bit>>3)+1;\n//\t\tfclose(fp);\n\t}\n}\n\nint MSG_ReadBits( msg_t *msg, int bits ) {\n\tint\t\t\tvalue;\n\tint\t\t\tget;\n\tqboolean\tsgn;\n\tint\t\t\ti, nbits;\n//\tFILE*\tfp;\n\n\tvalue = 0;\n\n\tif ( bits < 0 ) {\n\t\tbits = -bits;\n\t\tsgn = qtrue;\n\t} else {\n\t\tsgn = qfalse;\n\t}\n\n\tif (msg->oob) {\n\t\tif (bits==8) {\n\t\t\tvalue = msg->data[msg->readcount];\n\t\t\tmsg->readcount += 1;\n\t\t\tmsg->bit += 8;\n\t\t} else if (bits==16) {\n\t\t\tunsigned short *sp = (unsigned short *)&msg->data[msg->readcount];\n\t\t\tvalue = LittleShort(*sp);\n\t\t\tmsg->readcount += 2;\n\t\t\tmsg->bit += 16;\n\t\t} else if (bits==32) {\n\t\t\tunsigned int *ip = (unsigned int *)&msg->data[msg->readcount];\n\t\t\tvalue = LittleLong(*ip);\n\t\t\tmsg->readcount += 4;\n\t\t\tmsg->bit += 32;\n\t\t} else {\n\t\t\tCom_Error(ERR_DROP, \"can't read %d bits\\n\", bits);\n\t\t}\n\t} else {\n\t\tnbits = 0;\n\t\tif (bits&7) {\n\t\t\tnbits = bits&7;\n\t\t\tfor(i=0;i<nbits;i++) {\n\t\t\t\tvalue |= (Huff_getBit(msg->data, &msg->bit)<<i);\n\t\t\t}\n\t\t\tbits = bits - nbits;\n\t\t}\n\t\tif (bits) {\n//\t\t\tfp = fopen(\"c:\\\\netchan.bin\", \"a\");\n\t\t\tfor(i=0;i<bits;i+=8) {\n\t\t\t\tHuff_offsetReceive (msgHuff.decompressor.tree, &get, msg->data, &msg->bit);\n//\t\t\t\tfwrite(&get, 1, 1, fp);\n\t\t\t\tvalue |= (get<<(i+nbits));\n\t\t\t}\n//\t\t\tfclose(fp);\n\t\t}\n\t\tmsg->readcount = (msg->bit>>3)+1;\n\t}\n\tif ( sgn ) {\n\t\tif ( value & ( 1 << ( bits - 1 ) ) ) {\n\t\t\tvalue |= -1 ^ ( ( 1 << bits ) - 1 );\n\t\t}\n\t}\n\n\treturn value;\n}\n\n\n\n//================================================================================\n\n//\n// writing functions\n//\n\nvoid MSG_WriteChar( msg_t *sb, int c ) {\n#ifdef PARANOID\n\tif (c < -128 || c > 127)\n\t\tCom_Error (ERR_FATAL, \"MSG_WriteChar: range error\");\n#endif\n\n\tMSG_WriteBits( sb, c, 8 );\n}\n\nvoid MSG_WriteByte( msg_t *sb, int c ) {\n#ifdef PARANOID\n\tif (c < 0 || c > 255)\n\t\tCom_Error (ERR_FATAL, \"MSG_WriteByte: range error\");\n#endif\n\n\tMSG_WriteBits( sb, c, 8 );\n}\n\nvoid MSG_WriteData( msg_t *buf, const void *data, int length ) {\n\tint i;\n\tfor(i=0;i<length;i++) {\n\t\tMSG_WriteByte(buf, ((byte *)data)[i]);\n\t}\n}\n\nvoid MSG_WriteShort( msg_t *sb, int c ) {\n#ifdef PARANOID\n\tif (c < ((short)0x8000) || c > (short)0x7fff)\n\t\tCom_Error (ERR_FATAL, \"MSG_WriteShort: range error\");\n#endif\n\n\tMSG_WriteBits( sb, c, 16 );\n}\n\nvoid MSG_WriteLong( msg_t *sb, int c ) {\n\tMSG_WriteBits( sb, c, 32 );\n}\n\nvoid MSG_WriteFloat( msg_t *sb, float f ) {\n\tunion {\n\t\tfloat\tf;\n\t\tint\tl;\n\t} dat;\n\t\n\tdat.f = f;\n\tMSG_WriteBits( sb, dat.l, 32 );\n}\n\nvoid MSG_WriteString( msg_t *sb, const char *s ) {\n\tif ( !s ) {\n\t\tMSG_WriteData (sb, \"\", 1);\n\t} else {\n\t\tint\t\tl,i;\n\t\tchar\tstring[MAX_STRING_CHARS];\n\n\t\tl = (int)strlen( s );\n\t\tif ( l >= MAX_STRING_CHARS ) {\n\t\t\tCom_Printf( \"MSG_WriteString: MAX_STRING_CHARS\" );\n\t\t\tMSG_WriteData (sb, \"\", 1);\n\t\t\treturn;\n\t\t}\n\t\tQ_strncpyz( string, s, sizeof( string ) );\n\n\t\t// get rid of 0xff chars, because old clients don't like them\n\t\tfor ( i = 0 ; i < l ; i++ ) {\n\t\t\tif ( ((byte *)string)[i] > 127 ) {\n\t\t\t\tstring[i] = '.';\n\t\t\t}\n\t\t}\n\n\t\tMSG_WriteData (sb, string, l+1);\n\t}\n}\n\nvoid MSG_WriteBigString( msg_t *sb, const char *s ) {\n\tif ( !s ) {\n\t\tMSG_WriteData (sb, \"\", 1);\n\t} else {\n\t\tint\t\tl,i;\n\t\tchar\tstring[BIG_INFO_STRING];\n\n\t\tl = (int)strlen( s );\n\t\tif ( l >= BIG_INFO_STRING ) {\n\t\t\tCom_Printf( \"MSG_WriteString: BIG_INFO_STRING\" );\n\t\t\tMSG_WriteData (sb, \"\", 1);\n\t\t\treturn;\n\t\t}\n\t\tQ_strncpyz( string, s, sizeof( string ) );\n\n\t\t// get rid of 0xff chars, because old clients don't like them\n\t\tfor ( i = 0 ; i < l ; i++ ) {\n\t\t\tif ( ((byte *)string)[i] > 127 ) {\n\t\t\t\tstring[i] = '.';\n\t\t\t}\n\t\t}\n\n\t\tMSG_WriteData (sb, string, l+1);\n\t}\n}\n\nvoid MSG_WriteAngle( msg_t *sb, float f ) {\n\tMSG_WriteByte (sb, (int)(f*256/360) & 255);\n}\n\nvoid MSG_WriteAngle16( msg_t *sb, float f ) {\n\tMSG_WriteShort (sb, ANGLE2SHORT(f));\n}\n\n\n//============================================================\n\n//\n// reading functions\n//\n\n// returns -1 if no more characters are available\nint MSG_ReadChar (msg_t *msg ) {\n\tint\tc;\n\t\n\tc = (signed char)MSG_ReadBits( msg, 8 );\n\tif ( msg->readcount > msg->cursize ) {\n\t\tc = -1;\n\t}\t\n\t\n\treturn c;\n}\n\nint MSG_ReadByte( msg_t *msg ) {\n\tint\tc;\n\t\n\tc = (unsigned char)MSG_ReadBits( msg, 8 );\n\tif ( msg->readcount > msg->cursize ) {\n\t\tc = -1;\n\t}\t\n\treturn c;\n}\n\nint MSG_ReadShort( msg_t *msg ) {\n\tint\tc;\n\t\n\tc = (short)MSG_ReadBits( msg, 16 );\n\tif ( msg->readcount > msg->cursize ) {\n\t\tc = -1;\n\t}\t\n\n\treturn c;\n}\n\nint MSG_ReadLong( msg_t *msg ) {\n\tint\tc;\n\t\n\tc = MSG_ReadBits( msg, 32 );\n\tif ( msg->readcount > msg->cursize ) {\n\t\tc = -1;\n\t}\t\n\t\n\treturn c;\n}\n\nfloat MSG_ReadFloat( msg_t *msg ) {\n\tunion {\n\t\tbyte\tb[4];\n\t\tfloat\tf;\n\t\tint\tl;\n\t} dat;\n\t\n\tdat.l = MSG_ReadBits( msg, 32 );\n\tif ( msg->readcount > msg->cursize ) {\n\t\tdat.f = -1;\n\t}\t\n\t\n\treturn dat.f;\t\n}\n\nchar *MSG_ReadString( msg_t *msg ) {\n\tstatic char\tstring[MAX_STRING_CHARS];\n\tint\t\tl,c;\n\t\n\tl = 0;\n\tdo {\n\t\tc = MSG_ReadByte(msg);\t\t// use ReadByte so -1 is out of bounds\n\t\tif ( c == -1 || c == 0 ) {\n\t\t\tbreak;\n\t\t}\n\t\t// translate all fmt spec to avoid crash bugs\n\t\tif ( c == '%' ) {\n\t\t\tc = '.';\n\t\t}\n\t\t// don't allow higher ascii values\n\t\tif ( c > 127 ) {\n\t\t\tc = '.';\n\t\t}\n\n\t\tstring[l] = c;\n\t\tl++;\n\t} while (l < sizeof(string)-1);\n\t\n\tstring[l] = 0;\n\t\n\treturn string;\n}\n\nchar *MSG_ReadBigString( msg_t *msg ) {\n\tstatic char\tstring[BIG_INFO_STRING];\n\tint\t\tl,c;\n\t\n\tl = 0;\n\tdo {\n\t\tc = MSG_ReadByte(msg);\t\t// use ReadByte so -1 is out of bounds\n\t\tif ( c == -1 || c == 0 ) {\n\t\t\tbreak;\n\t\t}\n\t\t// translate all fmt spec to avoid crash bugs\n\t\tif ( c == '%' ) {\n\t\t\tc = '.';\n\t\t}\n\n\t\tstring[l] = c;\n\t\tl++;\n\t} while (l < sizeof(string)-1);\n\t\n\tstring[l] = 0;\n\t\n\treturn string;\n}\n\nchar *MSG_ReadStringLine( msg_t *msg ) {\n\tstatic char\tstring[MAX_STRING_CHARS];\n\tint\t\tl,c;\n\n\tl = 0;\n\tdo {\n\t\tc = MSG_ReadByte(msg);\t\t// use ReadByte so -1 is out of bounds\n\t\tif (c == -1 || c == 0 || c == '\\n') {\n\t\t\tbreak;\n\t\t}\n\t\t// translate all fmt spec to avoid crash bugs\n\t\tif ( c == '%' ) {\n\t\t\tc = '.';\n\t\t}\n\t\tstring[l] = c;\n\t\tl++;\n\t} while (l < sizeof(string)-1);\n\t\n\tstring[l] = 0;\n\t\n\treturn string;\n}\n\nfloat MSG_ReadAngle16( msg_t *msg ) {\n\treturn SHORT2ANGLE(MSG_ReadShort(msg));\n}\n\nvoid MSG_ReadData( msg_t *msg, void *data, int len ) {\n\tint\t\ti;\n\n\tfor (i=0 ; i<len ; i++) {\n\t\t((byte *)data)[i] = MSG_ReadByte (msg);\n\t}\n}\n\n\n/*\n=============================================================================\n\ndelta functions\n  \n=============================================================================\n*/\n\nextern cvar_t *cl_shownet;\n\n#define\tLOG(x) if( cl_shownet->integer == 4 ) { Com_Printf(\"%s \", x ); };\n\nvoid MSG_WriteDelta( msg_t *msg, int oldV, int newV, int bits ) {\n\tif ( oldV == newV ) {\n\t\tMSG_WriteBits( msg, 0, 1 );\n\t\treturn;\n\t}\n\tMSG_WriteBits( msg, 1, 1 );\n\tMSG_WriteBits( msg, newV, bits );\n}\n\nint\tMSG_ReadDelta( msg_t *msg, int oldV, int bits ) {\n\tif ( MSG_ReadBits( msg, 1 ) ) {\n\t\treturn MSG_ReadBits( msg, bits );\n\t}\n\treturn oldV;\n}\n\nvoid MSG_WriteDeltaFloat( msg_t *msg, float oldV, float newV ) {\n\tif ( oldV == newV ) {\n\t\tMSG_WriteBits( msg, 0, 1 );\n\t\treturn;\n\t}\n\tMSG_WriteBits( msg, 1, 1 );\n\tMSG_WriteBits( msg, *(int *)&newV, 32 );\n}\n\nfloat MSG_ReadDeltaFloat( msg_t *msg, float oldV ) {\n\tif ( MSG_ReadBits( msg, 1 ) ) {\n\t\tfloat\tnewV;\n\n\t\t*(int *)&newV = MSG_ReadBits( msg, 32 );\n\t\treturn newV;\n\t}\n\treturn oldV;\n}\n\n/*\n=============================================================================\n\ndelta functions with keys\n  \n=============================================================================\n*/\n\nunsigned int kbitmask[32] = {\n\t0x00000001, 0x00000003, 0x00000007, 0x0000000F,\n\t0x0000001F,\t0x0000003F,\t0x0000007F,\t0x000000FF,\n\t0x000001FF,\t0x000003FF,\t0x000007FF,\t0x00000FFF,\n\t0x00001FFF,\t0x00003FFF,\t0x00007FFF,\t0x0000FFFF,\n\t0x0001FFFF,\t0x0003FFFF,\t0x0007FFFF,\t0x000FFFFF,\n\t0x001FFFFf,\t0x003FFFFF,\t0x007FFFFF,\t0x00FFFFFF,\n\t0x01FFFFFF,\t0x03FFFFFF,\t0x07FFFFFF,\t0x0FFFFFFF,\n\t0x1FFFFFFF,\t0x3FFFFFFF,\t0x7FFFFFFF,\t0xFFFFFFFF,\n};\n\nvoid MSG_WriteDeltaKey( msg_t *msg, int key, int oldV, int newV, int bits ) {\n\tif ( oldV == newV ) {\n\t\tMSG_WriteBits( msg, 0, 1 );\n\t\treturn;\n\t}\n\tMSG_WriteBits( msg, 1, 1 );\n\tMSG_WriteBits( msg, newV ^ key, bits );\n}\n\nint\tMSG_ReadDeltaKey( msg_t *msg, int key, int oldV, int bits ) {\n\tif ( MSG_ReadBits( msg, 1 ) ) {\n\t\treturn MSG_ReadBits( msg, bits ) ^ (key & (int)kbitmask[bits]);\n\t}\n\treturn oldV;\n}\n\nvoid MSG_WriteDeltaKeyFloat( msg_t *msg, int key, float oldV, float newV ) {\n\tif ( oldV == newV ) {\n\t\tMSG_WriteBits( msg, 0, 1 );\n\t\treturn;\n\t}\n\tMSG_WriteBits( msg, 1, 1 );\n\tMSG_WriteBits( msg, (*(int *)&newV) ^ key, 32 );\n}\n\nfloat MSG_ReadDeltaKeyFloat( msg_t *msg, int key, float oldV ) {\n\tif ( MSG_ReadBits( msg, 1 ) ) {\n\t\tfloat\tnewV;\n\n\t\t*(int *)&newV = MSG_ReadBits( msg, 32 ) ^ key;\n\t\treturn newV;\n\t}\n\treturn oldV;\n}\n\n\n/*\n============================================================================\n\nusercmd_t communication\n\n============================================================================\n*/\n\n// ms is allways sent, the others are optional\n#define\tCM_ANGLE1 \t(1<<0)\n#define\tCM_ANGLE2 \t(1<<1)\n#define\tCM_ANGLE3 \t(1<<2)\n#define\tCM_FORWARD\t(1<<3)\n#define\tCM_SIDE\t\t(1<<4)\n#define\tCM_UP\t\t(1<<5)\n#define\tCM_BUTTONS\t(1<<6)\n#define CM_WEAPON\t(1<<7)\n\n/*\n=====================\nMSG_WriteDeltaUsercmd\n=====================\n*/\nvoid MSG_WriteDeltaUsercmd( msg_t *msg, usercmd_t *from, usercmd_t *to ) {\n\tif ( to->serverTime - from->serverTime < 256 ) {\n\t\tMSG_WriteBits( msg, 1, 1 );\n\t\tMSG_WriteBits( msg, to->serverTime - from->serverTime, 8 );\n\t} else {\n\t\tMSG_WriteBits( msg, 0, 1 );\n\t\tMSG_WriteBits( msg, to->serverTime, 32 );\n\t}\n\tMSG_WriteDelta( msg, from->angles[0], to->angles[0], 16 );\n\tMSG_WriteDelta( msg, from->angles[1], to->angles[1], 16 );\n\tMSG_WriteDelta( msg, from->angles[2], to->angles[2], 16 );\n\tMSG_WriteDelta( msg, from->forwardmove, to->forwardmove, 8 );\n\tMSG_WriteDelta( msg, from->rightmove, to->rightmove, 8 );\n\tMSG_WriteDelta( msg, from->upmove, to->upmove, 8 );\n\tMSG_WriteDelta( msg, from->buttons, to->buttons, 16 );\n\tMSG_WriteDelta( msg, from->weapon, to->weapon, 8 );\n}\n\n\n/*\n=====================\nMSG_ReadDeltaUsercmd\n=====================\n*/\nvoid MSG_ReadDeltaUsercmd( msg_t *msg, usercmd_t *from, usercmd_t *to ) {\n\tif ( MSG_ReadBits( msg, 1 ) ) {\n\t\tto->serverTime = from->serverTime + MSG_ReadBits( msg, 8 );\n\t} else {\n\t\tto->serverTime = MSG_ReadBits( msg, 32 );\n\t}\n\tto->angles[0] = MSG_ReadDelta( msg, from->angles[0], 16);\n\tto->angles[1] = MSG_ReadDelta( msg, from->angles[1], 16);\n\tto->angles[2] = MSG_ReadDelta( msg, from->angles[2], 16);\n\tto->forwardmove = MSG_ReadDelta( msg, from->forwardmove, 8);\n\tto->rightmove = MSG_ReadDelta( msg, from->rightmove, 8);\n\tto->upmove = MSG_ReadDelta( msg, from->upmove, 8);\n\tto->buttons = MSG_ReadDelta( msg, from->buttons, 16);\n\tto->weapon = MSG_ReadDelta( msg, from->weapon, 8);\n}\n\n/*\n=====================\nMSG_WriteDeltaUsercmd\n=====================\n*/\nvoid MSG_WriteDeltaUsercmdKey( msg_t *msg, int key, usercmd_t *from, usercmd_t *to ) {\n\tif ( to->serverTime - from->serverTime < 256 ) {\n\t\tMSG_WriteBits( msg, 1, 1 );\n\t\tMSG_WriteBits( msg, to->serverTime - from->serverTime, 8 );\n\t} else {\n\t\tMSG_WriteBits( msg, 0, 1 );\n\t\tMSG_WriteBits( msg, to->serverTime, 32 );\n\t}\n\tif (from->angles[0] == to->angles[0] &&\n\t\tfrom->angles[1] == to->angles[1] &&\n\t\tfrom->angles[2] == to->angles[2] &&\n\t\tfrom->forwardmove == to->forwardmove &&\n\t\tfrom->rightmove == to->rightmove &&\n\t\tfrom->upmove == to->upmove &&\n\t\tfrom->buttons == to->buttons &&\n\t\tfrom->weapon == to->weapon) {\n\t\t\tMSG_WriteBits( msg, 0, 1 );\t\t\t\t// no change\n\t\t\toldsize += 7;\n\t\t\treturn;\n\t}\n\tkey ^= to->serverTime;\n\tMSG_WriteBits( msg, 1, 1 );\n\tMSG_WriteDeltaKey( msg, key, from->angles[0], to->angles[0], 16 );\n\tMSG_WriteDeltaKey( msg, key, from->angles[1], to->angles[1], 16 );\n\tMSG_WriteDeltaKey( msg, key, from->angles[2], to->angles[2], 16 );\n\tMSG_WriteDeltaKey( msg, key, from->forwardmove, to->forwardmove, 8 );\n\tMSG_WriteDeltaKey( msg, key, from->rightmove, to->rightmove, 8 );\n\tMSG_WriteDeltaKey( msg, key, from->upmove, to->upmove, 8 );\n\tMSG_WriteDeltaKey( msg, key, from->buttons, to->buttons, 16 );\n\tMSG_WriteDeltaKey( msg, key, from->weapon, to->weapon, 8 );\n}\n\n\n/*\n=====================\nMSG_ReadDeltaUsercmd\n=====================\n*/\nvoid MSG_ReadDeltaUsercmdKey( msg_t *msg, int key, usercmd_t *from, usercmd_t *to ) {\n\tif ( MSG_ReadBits( msg, 1 ) ) {\n\t\tto->serverTime = from->serverTime + MSG_ReadBits( msg, 8 );\n\t} else {\n\t\tto->serverTime = MSG_ReadBits( msg, 32 );\n\t}\n\tif ( MSG_ReadBits( msg, 1 ) ) {\n\t\tkey ^= to->serverTime;\n\t\tto->angles[0] = MSG_ReadDeltaKey( msg, key, from->angles[0], 16);\n\t\tto->angles[1] = MSG_ReadDeltaKey( msg, key, from->angles[1], 16);\n\t\tto->angles[2] = MSG_ReadDeltaKey( msg, key, from->angles[2], 16);\n\t\tto->forwardmove = MSG_ReadDeltaKey( msg, key, from->forwardmove, 8);\n\t\tto->rightmove = MSG_ReadDeltaKey( msg, key, from->rightmove, 8);\n\t\tto->upmove = MSG_ReadDeltaKey( msg, key, from->upmove, 8);\n\t\tto->buttons = MSG_ReadDeltaKey( msg, key, from->buttons, 16);\n\t\tto->weapon = MSG_ReadDeltaKey( msg, key, from->weapon, 8);\n\t} else {\n\t\tto->angles[0] = from->angles[0];\n\t\tto->angles[1] = from->angles[1];\n\t\tto->angles[2] = from->angles[2];\n\t\tto->forwardmove = from->forwardmove;\n\t\tto->rightmove = from->rightmove;\n\t\tto->upmove = from->upmove;\n\t\tto->buttons = from->buttons;\n\t\tto->weapon = from->weapon;\n\t}\n}\n\n/*\n=============================================================================\n\nentityState_t communication\n  \n=============================================================================\n*/\n\n/*\n=================\nMSG_ReportChangeVectors_f\n\nPrints out a table from the current statistics for copying to code\n=================\n*/\nvoid MSG_ReportChangeVectors_f( void ) {\n\tint i;\n\tfor(i=0;i<256;i++) {\n\t\tif (pcount[i]) {\n\t\t\tCom_Printf(\"%d used %d\\n\", i, pcount[i]);\n\t\t}\n\t}\n}\n\ntypedef struct {\n\tchar\t*name;\n\tint\t\toffset;\n\tint\t\tbits;\t\t// 0 = float\n} netField_t;\n\n// using the stringizing operator to save typing...\n#define\tNETF(x) #x,(int)(intptr_t)&((entityState_t*)0)->x\n\nnetField_t\tentityStateFields[] = \n{\n{ NETF(pos.trTime), 32 },\n{ NETF(pos.trBase[0]), 0 },\n{ NETF(pos.trBase[1]), 0 },\n{ NETF(pos.trDelta[0]), 0 },\n{ NETF(pos.trDelta[1]), 0 },\n{ NETF(pos.trBase[2]), 0 },\n{ NETF(apos.trBase[1]), 0 },\n{ NETF(pos.trDelta[2]), 0 },\n{ NETF(apos.trBase[0]), 0 },\n{ NETF(event), 10 },\n{ NETF(angles2[1]), 0 },\n{ NETF(eType), 8 },\n{ NETF(torsoAnim), 8 },\n{ NETF(eventParm), 8 },\n{ NETF(legsAnim), 8 },\n{ NETF(groundEntityNum), GENTITYNUM_BITS },\n{ NETF(pos.trType), 8 },\n{ NETF(eFlags), 19 },\n{ NETF(otherEntityNum), GENTITYNUM_BITS },\n{ NETF(weapon), 8 },\n{ NETF(clientNum), 8 },\n{ NETF(angles[1]), 0 },\n{ NETF(pos.trDuration), 32 },\n{ NETF(apos.trType), 8 },\n{ NETF(origin[0]), 0 },\n{ NETF(origin[1]), 0 },\n{ NETF(origin[2]), 0 },\n{ NETF(solid), 24 },\n{ NETF(powerups), 16 },\n{ NETF(modelindex), 8 },\n{ NETF(otherEntityNum2), GENTITYNUM_BITS },\n{ NETF(loopSound), 8 },\n{ NETF(generic1), 8 },\n{ NETF(origin2[2]), 0 },\n{ NETF(origin2[0]), 0 },\n{ NETF(origin2[1]), 0 },\n{ NETF(modelindex2), 8 },\n{ NETF(angles[0]), 0 },\n{ NETF(time), 32 },\n{ NETF(apos.trTime), 32 },\n{ NETF(apos.trDuration), 32 },\n{ NETF(apos.trBase[2]), 0 },\n{ NETF(apos.trDelta[0]), 0 },\n{ NETF(apos.trDelta[1]), 0 },\n{ NETF(apos.trDelta[2]), 0 },\n{ NETF(time2), 32 },\n{ NETF(angles[2]), 0 },\n{ NETF(angles2[0]), 0 },\n{ NETF(angles2[2]), 0 },\n{ NETF(constantLight), 32 },\n{ NETF(frame), 16 }\n};\n\n\n// if (int)f == f and (int)f + ( 1<<(FLOAT_INT_BITS-1) ) < ( 1 << FLOAT_INT_BITS )\n// the float will be sent with FLOAT_INT_BITS, otherwise all 32 bits will be sent\n#define\tFLOAT_INT_BITS\t13\n#define\tFLOAT_INT_BIAS\t(1<<(FLOAT_INT_BITS-1))\n\n/*\n==================\nMSG_WriteDeltaEntity\n\nWrites part of a packetentities message, including the entity number.\nCan delta from either a baseline or a previous packet_entity\nIf to is NULL, a remove entity update will be sent\nIf force is not set, then nothing at all will be generated if the entity is\nidentical, under the assumption that the in-order delta code will catch it.\n==================\n*/\nvoid MSG_WriteDeltaEntity( msg_t *msg, struct entityState_s *from, struct entityState_s *to, \n\t\t\t\t\t\t   qboolean force ) {\n\tint\t\t\ti, lc;\n\tint\t\t\tnumFields;\n\tnetField_t\t*field;\n\tint\t\t\ttrunc;\n\tfloat\t\tfullFloat;\n\tint\t\t\t*fromF, *toF;\n\n\tnumFields = sizeof(entityStateFields)/sizeof(entityStateFields[0]);\n\n\t// all fields should be 32 bits to avoid any compiler packing issues\n\t// the \"number\" field is not part of the field list\n\t// if this assert fails, someone added a field to the entityState_t\n\t// struct without updating the message fields\n\tassert( numFields + 1 == sizeof( *from )/4 );\n\n\t// a NULL to is a delta remove message\n\tif ( to == NULL ) {\n\t\tif ( from == NULL ) {\n\t\t\treturn;\n\t\t}\n\t\tMSG_WriteBits( msg, from->number, GENTITYNUM_BITS );\n\t\tMSG_WriteBits( msg, 1, 1 );\n\t\treturn;\n\t}\n\n\tif ( to->number < 0 || to->number >= MAX_GENTITIES ) {\n\t\tCom_Error (ERR_FATAL, \"MSG_WriteDeltaEntity: Bad entity number: %i\", to->number );\n\t}\n\n\tlc = 0;\n\t// build the change vector as bytes so it is endien independent\n\tfor ( i = 0, field = entityStateFields ; i < numFields ; i++, field++ ) {\n\t\tfromF = (int *)( (byte *)from + field->offset );\n\t\ttoF = (int *)( (byte *)to + field->offset );\n\t\tif ( *fromF != *toF ) {\n\t\t\tlc = i+1;\n\t\t}\n\t}\n\n\tif ( lc == 0 ) {\n\t\t// nothing at all changed\n\t\tif ( !force ) {\n\t\t\treturn;\t\t// nothing at all\n\t\t}\n\t\t// write two bits for no change\n\t\tMSG_WriteBits( msg, to->number, GENTITYNUM_BITS );\n\t\tMSG_WriteBits( msg, 0, 1 );\t\t// not removed\n\t\tMSG_WriteBits( msg, 0, 1 );\t\t// no delta\n\t\treturn;\n\t}\n\n\tMSG_WriteBits( msg, to->number, GENTITYNUM_BITS );\n\tMSG_WriteBits( msg, 0, 1 );\t\t\t// not removed\n\tMSG_WriteBits( msg, 1, 1 );\t\t\t// we have a delta\n\n\tMSG_WriteByte( msg, lc );\t// # of changes\n\n\toldsize += numFields;\n\n\tfor ( i = 0, field = entityStateFields ; i < lc ; i++, field++ ) {\n\t\tfromF = (int *)( (byte *)from + field->offset );\n\t\ttoF = (int *)( (byte *)to + field->offset );\n\n\t\tif ( *fromF == *toF ) {\n\t\t\tMSG_WriteBits( msg, 0, 1 );\t// no change\n\t\t\tcontinue;\n\t\t}\n\n\t\tMSG_WriteBits( msg, 1, 1 );\t// changed\n\n\t\tif ( field->bits == 0 ) {\n\t\t\t// float\n\t\t\tfullFloat = *(float *)toF;\n\t\t\ttrunc = (int)fullFloat;\n\n\t\t\tif (fullFloat == 0.0f) {\n\t\t\t\t\tMSG_WriteBits( msg, 0, 1 );\n\t\t\t\t\toldsize += FLOAT_INT_BITS;\n\t\t\t} else {\n\t\t\t\tMSG_WriteBits( msg, 1, 1 );\n\t\t\t\tif ( trunc == fullFloat && trunc + FLOAT_INT_BIAS >= 0 && \n\t\t\t\t\ttrunc + FLOAT_INT_BIAS < ( 1 << FLOAT_INT_BITS ) ) {\n\t\t\t\t\t// send as small integer\n\t\t\t\t\tMSG_WriteBits( msg, 0, 1 );\n\t\t\t\t\tMSG_WriteBits( msg, trunc + FLOAT_INT_BIAS, FLOAT_INT_BITS );\n\t\t\t\t} else {\n\t\t\t\t\t// send as full floating point value\n\t\t\t\t\tMSG_WriteBits( msg, 1, 1 );\n\t\t\t\t\tMSG_WriteBits( msg, *toF, 32 );\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tif (*toF == 0) {\n\t\t\t\tMSG_WriteBits( msg, 0, 1 );\n\t\t\t} else {\n\t\t\t\tMSG_WriteBits( msg, 1, 1 );\n\t\t\t\t// integer\n\t\t\t\tMSG_WriteBits( msg, *toF, field->bits );\n\t\t\t}\n\t\t}\n\t}\n}\n\n/*\n==================\nMSG_ReadDeltaEntity\n\nThe entity number has already been read from the message, which\nis how the from state is identified.\n\nIf the delta removes the entity, entityState_t->number will be set to MAX_GENTITIES-1\n\nCan go from either a baseline or a previous packet_entity\n==================\n*/\nextern\tcvar_t\t*cl_shownet;\n\nvoid MSG_ReadDeltaEntity( msg_t *msg, entityState_t *from, entityState_t *to, \n\t\t\t\t\t\t int number) {\n\tint\t\t\ti, lc;\n\tint\t\t\tnumFields;\n\tnetField_t\t*field;\n\tint\t\t\t*fromF, *toF;\n\tint\t\t\tprint;\n\tint\t\t\ttrunc;\n\tint\t\t\tstartBit, endBit;\n\n\tif ( number < 0 || number >= MAX_GENTITIES) {\n\t\tCom_Error( ERR_DROP, \"Bad delta entity number: %i\", number );\n\t}\n\n\tif ( msg->bit == 0 ) {\n\t\tstartBit = msg->readcount * 8 - GENTITYNUM_BITS;\n\t} else {\n\t\tstartBit = ( msg->readcount - 1 ) * 8 + msg->bit - GENTITYNUM_BITS;\n\t}\n\n\t// check for a remove\n\tif ( MSG_ReadBits( msg, 1 ) == 1 ) {\n\t\tCom_Memset( to, 0, sizeof( *to ) );\t\n\t\tto->number = MAX_GENTITIES - 1;\n\t\tif ( cl_shownet->integer >= 2 || cl_shownet->integer == -1 ) {\n\t\t\tCom_Printf( \"%3i: #%-3i remove\\n\", msg->readcount, number );\n\t\t}\n\t\treturn;\n\t}\n\n\t// check for no delta\n\tif ( MSG_ReadBits( msg, 1 ) == 0 ) {\n\t\t*to = *from;\n\t\tto->number = number;\n\t\treturn;\n\t}\n\n\tnumFields = sizeof(entityStateFields)/sizeof(entityStateFields[0]);\n\tlc = MSG_ReadByte(msg);\n\n\t// shownet 2/3 will interleave with other printed info, -1 will\n\t// just print the delta records`\n\tif ( cl_shownet->integer >= 2 || cl_shownet->integer == -1 ) {\n\t\tprint = 1;\n\t\tCom_Printf( \"%3i: #%-3i \", msg->readcount, to->number );\n\t} else {\n\t\tprint = 0;\n\t}\n\n\tto->number = number;\n\n\tfor ( i = 0, field = entityStateFields ; i < lc ; i++, field++ ) {\n\t\tfromF = (int *)( (byte *)from + field->offset );\n\t\ttoF = (int *)( (byte *)to + field->offset );\n\n\t\tif ( ! MSG_ReadBits( msg, 1 ) ) {\n\t\t\t// no change\n\t\t\t*toF = *fromF;\n\t\t} else {\n\t\t\tif ( field->bits == 0 ) {\n\t\t\t\t// float\n\t\t\t\tif ( MSG_ReadBits( msg, 1 ) == 0 ) {\n\t\t\t\t\t\t*(float *)toF = 0.0f; \n\t\t\t\t} else {\n\t\t\t\t\tif ( MSG_ReadBits( msg, 1 ) == 0 ) {\n\t\t\t\t\t\t// integral float\n\t\t\t\t\t\ttrunc = MSG_ReadBits( msg, FLOAT_INT_BITS );\n\t\t\t\t\t\t// bias to allow equal parts positive and negative\n\t\t\t\t\t\ttrunc -= FLOAT_INT_BIAS;\n\t\t\t\t\t\t*(float *)toF = trunc; \n\t\t\t\t\t\tif ( print ) {\n\t\t\t\t\t\t\tCom_Printf( \"%s:%i \", field->name, trunc );\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// full floating point value\n\t\t\t\t\t\t*toF = MSG_ReadBits( msg, 32 );\n\t\t\t\t\t\tif ( print ) {\n\t\t\t\t\t\t\tCom_Printf( \"%s:%f \", field->name, *(float *)toF );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif ( MSG_ReadBits( msg, 1 ) == 0 ) {\n\t\t\t\t\t*toF = 0;\n\t\t\t\t} else {\n\t\t\t\t\t// integer\n\t\t\t\t\t*toF = MSG_ReadBits( msg, field->bits );\n\t\t\t\t\tif ( print ) {\n\t\t\t\t\t\tCom_Printf( \"%s:%i \", field->name, *toF );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n//\t\t\tpcount[i]++;\n\t\t}\n\t}\n\tfor ( i = lc, field = &entityStateFields[lc] ; i < numFields ; i++, field++ ) {\n\t\tfromF = (int *)( (byte *)from + field->offset );\n\t\ttoF = (int *)( (byte *)to + field->offset );\n\t\t// no change\n\t\t*toF = *fromF;\n\t}\n\n\tif ( print ) {\n\t\tif ( msg->bit == 0 ) {\n\t\t\tendBit = msg->readcount * 8 - GENTITYNUM_BITS;\n\t\t} else {\n\t\t\tendBit = ( msg->readcount - 1 ) * 8 + msg->bit - GENTITYNUM_BITS;\n\t\t}\n\t\tCom_Printf( \" (%i bits)\\n\", endBit - startBit  );\n\t}\n}\n\n\n/*\n============================================================================\n\nplyer_state_t communication\n\n============================================================================\n*/\n\n// using the stringizing operator to save typing...\n#define\tPSF(x) #x,(int)(intptr_t)&((playerState_t*)0)->x\n\nnetField_t\tplayerStateFields[] = \n{\n{ PSF(commandTime), 32 },\t\t\t\t\n{ PSF(origin[0]), 0 },\n{ PSF(origin[1]), 0 },\n{ PSF(bobCycle), 8 },\n{ PSF(velocity[0]), 0 },\n{ PSF(velocity[1]), 0 },\n{ PSF(viewangles[1]), 0 },\n{ PSF(viewangles[0]), 0 },\n{ PSF(weaponTime), -16 },\n{ PSF(origin[2]), 0 },\n{ PSF(velocity[2]), 0 },\n{ PSF(legsTimer), 8 },\n{ PSF(pm_time), -16 },\n{ PSF(eventSequence), 16 },\n{ PSF(torsoAnim), 8 },\n{ PSF(movementDir), 4 },\n{ PSF(events[0]), 8 },\n{ PSF(legsAnim), 8 },\n{ PSF(events[1]), 8 },\n{ PSF(pm_flags), 16 },\n{ PSF(groundEntityNum), GENTITYNUM_BITS },\n{ PSF(weaponstate), 4 },\n{ PSF(eFlags), 16 },\n{ PSF(externalEvent), 10 },\n{ PSF(gravity), 16 },\n{ PSF(speed), 16 },\n{ PSF(delta_angles[1]), 16 },\n{ PSF(externalEventParm), 8 },\n{ PSF(viewheight), -8 },\n{ PSF(damageEvent), 8 },\n{ PSF(damageYaw), 8 },\n{ PSF(damagePitch), 8 },\n{ PSF(damageCount), 8 },\n{ PSF(generic1), 8 },\n{ PSF(pm_type), 8 },\t\t\t\t\t\n{ PSF(delta_angles[0]), 16 },\n{ PSF(delta_angles[2]), 16 },\n{ PSF(torsoTimer), 12 },\n{ PSF(eventParms[0]), 8 },\n{ PSF(eventParms[1]), 8 },\n{ PSF(clientNum), 8 },\n{ PSF(weapon), 5 },\n{ PSF(viewangles[2]), 0 },\n{ PSF(grapplePoint[0]), 0 },\n{ PSF(grapplePoint[1]), 0 },\n{ PSF(grapplePoint[2]), 0 },\n{ PSF(jumppad_ent), 10 },\n{ PSF(loopSound), 16 }\n};\n\n/*\n=============\nMSG_WriteDeltaPlayerstate\n\n=============\n*/\nvoid MSG_WriteDeltaPlayerstate( msg_t *msg, struct playerState_s *from, struct playerState_s *to ) {\n\tint\t\t\t\ti;\n\tplayerState_t\tdummy;\n\tint\t\t\t\tstatsbits;\n\tint\t\t\t\tpersistantbits;\n\tint\t\t\t\tammobits;\n\tint\t\t\t\tpowerupbits;\n\tint\t\t\t\tnumFields;\n\tint\t\t\t\tc;\n\tnetField_t\t\t*field;\n\tint\t\t\t\t*fromF, *toF;\n\tfloat\t\t\tfullFloat;\n\tint\t\t\t\ttrunc, lc;\n\n\tif (!from) {\n\t\tfrom = &dummy;\n\t\tCom_Memset (&dummy, 0, sizeof(dummy));\n\t}\n\n\tc = msg->cursize;\n\n\tnumFields = sizeof( playerStateFields ) / sizeof( playerStateFields[0] );\n\n\tlc = 0;\n\tfor ( i = 0, field = playerStateFields ; i < numFields ; i++, field++ ) {\n\t\tfromF = (int *)( (byte *)from + field->offset );\n\t\ttoF = (int *)( (byte *)to + field->offset );\n\t\tif ( *fromF != *toF ) {\n\t\t\tlc = i+1;\n\t\t}\n\t}\n\n\tMSG_WriteByte( msg, lc );\t// # of changes\n\n\toldsize += numFields - lc;\n\n\tfor ( i = 0, field = playerStateFields ; i < lc ; i++, field++ ) {\n\t\tfromF = (int *)( (byte *)from + field->offset );\n\t\ttoF = (int *)( (byte *)to + field->offset );\n\n\t\tif ( *fromF == *toF ) {\n\t\t\tMSG_WriteBits( msg, 0, 1 );\t// no change\n\t\t\tcontinue;\n\t\t}\n\n\t\tMSG_WriteBits( msg, 1, 1 );\t// changed\n//\t\tpcount[i]++;\n\n\t\tif ( field->bits == 0 ) {\n\t\t\t// float\n\t\t\tfullFloat = *(float *)toF;\n\t\t\ttrunc = (int)fullFloat;\n\n\t\t\tif ( trunc == fullFloat && trunc + FLOAT_INT_BIAS >= 0 && \n\t\t\t\ttrunc + FLOAT_INT_BIAS < ( 1 << FLOAT_INT_BITS ) ) {\n\t\t\t\t// send as small integer\n\t\t\t\tMSG_WriteBits( msg, 0, 1 );\n\t\t\t\tMSG_WriteBits( msg, trunc + FLOAT_INT_BIAS, FLOAT_INT_BITS );\n\t\t\t} else {\n\t\t\t\t// send as full floating point value\n\t\t\t\tMSG_WriteBits( msg, 1, 1 );\n\t\t\t\tMSG_WriteBits( msg, *toF, 32 );\n\t\t\t}\n\t\t} else {\n\t\t\t// integer\n\t\t\tMSG_WriteBits( msg, *toF, field->bits );\n\t\t}\n\t}\n\tc = msg->cursize - c;\n\n\n\t//\n\t// send the arrays\n\t//\n\tstatsbits = 0;\n\tfor (i=0 ; i<16 ; i++) {\n\t\tif (to->stats[i] != from->stats[i]) {\n\t\t\tstatsbits |= 1<<i;\n\t\t}\n\t}\n\tpersistantbits = 0;\n\tfor (i=0 ; i<16 ; i++) {\n\t\tif (to->persistant[i] != from->persistant[i]) {\n\t\t\tpersistantbits |= 1<<i;\n\t\t}\n\t}\n\tammobits = 0;\n\tfor (i=0 ; i<16 ; i++) {\n\t\tif (to->ammo[i] != from->ammo[i]) {\n\t\t\tammobits |= 1<<i;\n\t\t}\n\t}\n\tpowerupbits = 0;\n\tfor (i=0 ; i<16 ; i++) {\n\t\tif (to->powerups[i] != from->powerups[i]) {\n\t\t\tpowerupbits |= 1<<i;\n\t\t}\n\t}\n\n\tif (!statsbits && !persistantbits && !ammobits && !powerupbits) {\n\t\tMSG_WriteBits( msg, 0, 1 );\t// no change\n\t\toldsize += 4;\n\t\treturn;\n\t}\n\tMSG_WriteBits( msg, 1, 1 );\t// changed\n\n\tif ( statsbits ) {\n\t\tMSG_WriteBits( msg, 1, 1 );\t// changed\n\t\tMSG_WriteShort( msg, statsbits );\n\t\tfor (i=0 ; i<16 ; i++)\n\t\t\tif (statsbits & (1<<i) )\n\t\t\t\tMSG_WriteShort (msg, to->stats[i]);\n\t} else {\n\t\tMSG_WriteBits( msg, 0, 1 );\t// no change\n\t}\n\n\n\tif ( persistantbits ) {\n\t\tMSG_WriteBits( msg, 1, 1 );\t// changed\n\t\tMSG_WriteShort( msg, persistantbits );\n\t\tfor (i=0 ; i<16 ; i++)\n\t\t\tif (persistantbits & (1<<i) )\n\t\t\t\tMSG_WriteShort (msg, to->persistant[i]);\n\t} else {\n\t\tMSG_WriteBits( msg, 0, 1 );\t// no change\n\t}\n\n\n\tif ( ammobits ) {\n\t\tMSG_WriteBits( msg, 1, 1 );\t// changed\n\t\tMSG_WriteShort( msg, ammobits );\n\t\tfor (i=0 ; i<16 ; i++)\n\t\t\tif (ammobits & (1<<i) )\n\t\t\t\tMSG_WriteShort (msg, to->ammo[i]);\n\t} else {\n\t\tMSG_WriteBits( msg, 0, 1 );\t// no change\n\t}\n\n\n\tif ( powerupbits ) {\n\t\tMSG_WriteBits( msg, 1, 1 );\t// changed\n\t\tMSG_WriteShort( msg, powerupbits );\n\t\tfor (i=0 ; i<16 ; i++)\n\t\t\tif (powerupbits & (1<<i) )\n\t\t\t\tMSG_WriteLong( msg, to->powerups[i] );\n\t} else {\n\t\tMSG_WriteBits( msg, 0, 1 );\t// no change\n\t}\n}\n\n\n/*\n===================\nMSG_ReadDeltaPlayerstate\n===================\n*/\nvoid MSG_ReadDeltaPlayerstate (msg_t *msg, playerState_t *from, playerState_t *to ) {\n\tint\t\t\ti, lc;\n\tint\t\t\tbits;\n\tnetField_t\t*field;\n\tint\t\t\tnumFields;\n\tint\t\t\tstartBit, endBit;\n\tint\t\t\tprint;\n\tint\t\t\t*fromF, *toF;\n\tint\t\t\ttrunc;\n\tplayerState_t\tdummy;\n\n\tif ( !from ) {\n\t\tfrom = &dummy;\n\t\tCom_Memset( &dummy, 0, sizeof( dummy ) );\n\t}\n\t*to = *from;\n\n\tif ( msg->bit == 0 ) {\n\t\tstartBit = msg->readcount * 8 - GENTITYNUM_BITS;\n\t} else {\n\t\tstartBit = ( msg->readcount - 1 ) * 8 + msg->bit - GENTITYNUM_BITS;\n\t}\n\n\t// shownet 2/3 will interleave with other printed info, -2 will\n\t// just print the delta records\n\tif ( cl_shownet->integer >= 2 || cl_shownet->integer == -2 ) {\n\t\tprint = 1;\n\t\tCom_Printf( \"%3i: playerstate \", msg->readcount );\n\t} else {\n\t\tprint = 0;\n\t}\n\n\tnumFields = sizeof( playerStateFields ) / sizeof( playerStateFields[0] );\n\tlc = MSG_ReadByte(msg);\n\n\tfor ( i = 0, field = playerStateFields ; i < lc ; i++, field++ ) {\n\t\tfromF = (int *)( (byte *)from + field->offset );\n\t\ttoF = (int *)( (byte *)to + field->offset );\n\n\t\tif ( ! MSG_ReadBits( msg, 1 ) ) {\n\t\t\t// no change\n\t\t\t*toF = *fromF;\n\t\t} else {\n\t\t\tif ( field->bits == 0 ) {\n\t\t\t\t// float\n\t\t\t\tif ( MSG_ReadBits( msg, 1 ) == 0 ) {\n\t\t\t\t\t// integral float\n\t\t\t\t\ttrunc = MSG_ReadBits( msg, FLOAT_INT_BITS );\n\t\t\t\t\t// bias to allow equal parts positive and negative\n\t\t\t\t\ttrunc -= FLOAT_INT_BIAS;\n\t\t\t\t\t*(float *)toF = trunc; \n\t\t\t\t\tif ( print ) {\n\t\t\t\t\t\tCom_Printf( \"%s:%i \", field->name, trunc );\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// full floating point value\n\t\t\t\t\t*toF = MSG_ReadBits( msg, 32 );\n\t\t\t\t\tif ( print ) {\n\t\t\t\t\t\tCom_Printf( \"%s:%f \", field->name, *(float *)toF );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// integer\n\t\t\t\t*toF = MSG_ReadBits( msg, field->bits );\n\t\t\t\tif ( print ) {\n\t\t\t\t\tCom_Printf( \"%s:%i \", field->name, *toF );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tfor ( i=lc,field = &playerStateFields[lc];i<numFields; i++, field++) {\n\t\tfromF = (int *)( (byte *)from + field->offset );\n\t\ttoF = (int *)( (byte *)to + field->offset );\n\t\t// no change\n\t\t*toF = *fromF;\n\t}\n\n\n\t// read the arrays\n\tif (MSG_ReadBits( msg, 1 ) ) {\n\t\t// parse stats\n\t\tif ( MSG_ReadBits( msg, 1 ) ) {\n\t\t\tLOG(\"PS_STATS\");\n\t\t\tbits = MSG_ReadShort (msg);\n\t\t\tfor (i=0 ; i<16 ; i++) {\n\t\t\t\tif (bits & (1<<i) ) {\n\t\t\t\t\tto->stats[i] = MSG_ReadShort(msg);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// parse persistant stats\n\t\tif ( MSG_ReadBits( msg, 1 ) ) {\n\t\t\tLOG(\"PS_PERSISTANT\");\n\t\t\tbits = MSG_ReadShort (msg);\n\t\t\tfor (i=0 ; i<16 ; i++) {\n\t\t\t\tif (bits & (1<<i) ) {\n\t\t\t\t\tto->persistant[i] = MSG_ReadShort(msg);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// parse ammo\n\t\tif ( MSG_ReadBits( msg, 1 ) ) {\n\t\t\tLOG(\"PS_AMMO\");\n\t\t\tbits = MSG_ReadShort (msg);\n\t\t\tfor (i=0 ; i<16 ; i++) {\n\t\t\t\tif (bits & (1<<i) ) {\n\t\t\t\t\tto->ammo[i] = MSG_ReadShort(msg);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// parse powerups\n\t\tif ( MSG_ReadBits( msg, 1 ) ) {\n\t\t\tLOG(\"PS_POWERUPS\");\n\t\t\tbits = MSG_ReadShort (msg);\n\t\t\tfor (i=0 ; i<16 ; i++) {\n\t\t\t\tif (bits & (1<<i) ) {\n\t\t\t\t\tto->powerups[i] = MSG_ReadLong(msg);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif ( print ) {\n\t\tif ( msg->bit == 0 ) {\n\t\t\tendBit = msg->readcount * 8 - GENTITYNUM_BITS;\n\t\t} else {\n\t\t\tendBit = ( msg->readcount - 1 ) * 8 + msg->bit - GENTITYNUM_BITS;\n\t\t}\n\t\tCom_Printf( \" (%i bits)\\n\", endBit - startBit  );\n\t}\n}\n\nint msg_hData[256] = {\n250315,\t\t\t// 0\n41193,\t\t\t// 1\n6292,\t\t\t// 2\n7106,\t\t\t// 3\n3730,\t\t\t// 4\n3750,\t\t\t// 5\n6110,\t\t\t// 6\n23283,\t\t\t// 7\n33317,\t\t\t// 8\n6950,\t\t\t// 9\n7838,\t\t\t// 10\n9714,\t\t\t// 11\n9257,\t\t\t// 12\n17259,\t\t\t// 13\n3949,\t\t\t// 14\n1778,\t\t\t// 15\n8288,\t\t\t// 16\n1604,\t\t\t// 17\n1590,\t\t\t// 18\n1663,\t\t\t// 19\n1100,\t\t\t// 20\n1213,\t\t\t// 21\n1238,\t\t\t// 22\n1134,\t\t\t// 23\n1749,\t\t\t// 24\n1059,\t\t\t// 25\n1246,\t\t\t// 26\n1149,\t\t\t// 27\n1273,\t\t\t// 28\n4486,\t\t\t// 29\n2805,\t\t\t// 30\n3472,\t\t\t// 31\n21819,\t\t\t// 32\n1159,\t\t\t// 33\n1670,\t\t\t// 34\n1066,\t\t\t// 35\n1043,\t\t\t// 36\n1012,\t\t\t// 37\n1053,\t\t\t// 38\n1070,\t\t\t// 39\n1726,\t\t\t// 40\n888,\t\t\t// 41\n1180,\t\t\t// 42\n850,\t\t\t// 43\n960,\t\t\t// 44\n780,\t\t\t// 45\n1752,\t\t\t// 46\n3296,\t\t\t// 47\n10630,\t\t\t// 48\n4514,\t\t\t// 49\n5881,\t\t\t// 50\n2685,\t\t\t// 51\n4650,\t\t\t// 52\n3837,\t\t\t// 53\n2093,\t\t\t// 54\n1867,\t\t\t// 55\n2584,\t\t\t// 56\n1949,\t\t\t// 57\n1972,\t\t\t// 58\n940,\t\t\t// 59\n1134,\t\t\t// 60\n1788,\t\t\t// 61\n1670,\t\t\t// 62\n1206,\t\t\t// 63\n5719,\t\t\t// 64\n6128,\t\t\t// 65\n7222,\t\t\t// 66\n6654,\t\t\t// 67\n3710,\t\t\t// 68\n3795,\t\t\t// 69\n1492,\t\t\t// 70\n1524,\t\t\t// 71\n2215,\t\t\t// 72\n1140,\t\t\t// 73\n1355,\t\t\t// 74\n971,\t\t\t// 75\n2180,\t\t\t// 76\n1248,\t\t\t// 77\n1328,\t\t\t// 78\n1195,\t\t\t// 79\n1770,\t\t\t// 80\n1078,\t\t\t// 81\n1264,\t\t\t// 82\n1266,\t\t\t// 83\n1168,\t\t\t// 84\n965,\t\t\t// 85\n1155,\t\t\t// 86\n1186,\t\t\t// 87\n1347,\t\t\t// 88\n1228,\t\t\t// 89\n1529,\t\t\t// 90\n1600,\t\t\t// 91\n2617,\t\t\t// 92\n2048,\t\t\t// 93\n2546,\t\t\t// 94\n3275,\t\t\t// 95\n2410,\t\t\t// 96\n3585,\t\t\t// 97\n2504,\t\t\t// 98\n2800,\t\t\t// 99\n2675,\t\t\t// 100\n6146,\t\t\t// 101\n3663,\t\t\t// 102\n2840,\t\t\t// 103\n14253,\t\t\t// 104\n3164,\t\t\t// 105\n2221,\t\t\t// 106\n1687,\t\t\t// 107\n3208,\t\t\t// 108\n2739,\t\t\t// 109\n3512,\t\t\t// 110\n4796,\t\t\t// 111\n4091,\t\t\t// 112\n3515,\t\t\t// 113\n5288,\t\t\t// 114\n4016,\t\t\t// 115\n7937,\t\t\t// 116\n6031,\t\t\t// 117\n5360,\t\t\t// 118\n3924,\t\t\t// 119\n4892,\t\t\t// 120\n3743,\t\t\t// 121\n4566,\t\t\t// 122\n4807,\t\t\t// 123\n5852,\t\t\t// 124\n6400,\t\t\t// 125\n6225,\t\t\t// 126\n8291,\t\t\t// 127\n23243,\t\t\t// 128\n7838,\t\t\t// 129\n7073,\t\t\t// 130\n8935,\t\t\t// 131\n5437,\t\t\t// 132\n4483,\t\t\t// 133\n3641,\t\t\t// 134\n5256,\t\t\t// 135\n5312,\t\t\t// 136\n5328,\t\t\t// 137\n5370,\t\t\t// 138\n3492,\t\t\t// 139\n2458,\t\t\t// 140\n1694,\t\t\t// 141\n1821,\t\t\t// 142\n2121,\t\t\t// 143\n1916,\t\t\t// 144\n1149,\t\t\t// 145\n1516,\t\t\t// 146\n1367,\t\t\t// 147\n1236,\t\t\t// 148\n1029,\t\t\t// 149\n1258,\t\t\t// 150\n1104,\t\t\t// 151\n1245,\t\t\t// 152\n1006,\t\t\t// 153\n1149,\t\t\t// 154\n1025,\t\t\t// 155\n1241,\t\t\t// 156\n952,\t\t\t// 157\n1287,\t\t\t// 158\n997,\t\t\t// 159\n1713,\t\t\t// 160\n1009,\t\t\t// 161\n1187,\t\t\t// 162\n879,\t\t\t// 163\n1099,\t\t\t// 164\n929,\t\t\t// 165\n1078,\t\t\t// 166\n951,\t\t\t// 167\n1656,\t\t\t// 168\n930,\t\t\t// 169\n1153,\t\t\t// 170\n1030,\t\t\t// 171\n1262,\t\t\t// 172\n1062,\t\t\t// 173\n1214,\t\t\t// 174\n1060,\t\t\t// 175\n1621,\t\t\t// 176\n930,\t\t\t// 177\n1106,\t\t\t// 178\n912,\t\t\t// 179\n1034,\t\t\t// 180\n892,\t\t\t// 181\n1158,\t\t\t// 182\n990,\t\t\t// 183\n1175,\t\t\t// 184\n850,\t\t\t// 185\n1121,\t\t\t// 186\n903,\t\t\t// 187\n1087,\t\t\t// 188\n920,\t\t\t// 189\n1144,\t\t\t// 190\n1056,\t\t\t// 191\n3462,\t\t\t// 192\n2240,\t\t\t// 193\n4397,\t\t\t// 194\n12136,\t\t\t// 195\n7758,\t\t\t// 196\n1345,\t\t\t// 197\n1307,\t\t\t// 198\n3278,\t\t\t// 199\n1950,\t\t\t// 200\n886,\t\t\t// 201\n1023,\t\t\t// 202\n1112,\t\t\t// 203\n1077,\t\t\t// 204\n1042,\t\t\t// 205\n1061,\t\t\t// 206\n1071,\t\t\t// 207\n1484,\t\t\t// 208\n1001,\t\t\t// 209\n1096,\t\t\t// 210\n915,\t\t\t// 211\n1052,\t\t\t// 212\n995,\t\t\t// 213\n1070,\t\t\t// 214\n876,\t\t\t// 215\n1111,\t\t\t// 216\n851,\t\t\t// 217\n1059,\t\t\t// 218\n805,\t\t\t// 219\n1112,\t\t\t// 220\n923,\t\t\t// 221\n1103,\t\t\t// 222\n817,\t\t\t// 223\n1899,\t\t\t// 224\n1872,\t\t\t// 225\n976,\t\t\t// 226\n841,\t\t\t// 227\n1127,\t\t\t// 228\n956,\t\t\t// 229\n1159,\t\t\t// 230\n950,\t\t\t// 231\n7791,\t\t\t// 232\n954,\t\t\t// 233\n1289,\t\t\t// 234\n933,\t\t\t// 235\n1127,\t\t\t// 236\n3207,\t\t\t// 237\n1020,\t\t\t// 238\n927,\t\t\t// 239\n1355,\t\t\t// 240\n768,\t\t\t// 241\n1040,\t\t\t// 242\n745,\t\t\t// 243\n952,\t\t\t// 244\n805,\t\t\t// 245\n1073,\t\t\t// 246\n740,\t\t\t// 247\n1013,\t\t\t// 248\n805,\t\t\t// 249\n1008,\t\t\t// 250\n796,\t\t\t// 251\n996,\t\t\t// 252\n1057,\t\t\t// 253\n11457,\t\t\t// 254\n13504,\t\t\t// 255\n};\n\nvoid MSG_initHuffman() {\n\tint i,j;\n\n\tmsgInit = qtrue;\n\tHuff_Init(&msgHuff);\n\tfor(i=0;i<256;i++) {\n\t\tfor (j=0;j<msg_hData[i];j++) {\n\t\t\tHuff_addRef(&msgHuff.compressor,\t(byte)i);\t\t\t// Do update\n\t\t\tHuff_addRef(&msgHuff.decompressor,\t(byte)i);\t\t\t// Do update\n\t\t}\n\t}\n}\n\n/*\nvoid MSG_NUinitHuffman() {\n\tbyte\t*data;\n\tint\t\tsize, i, ch;\n\tint\t\tarray[256];\n\n\tmsgInit = qtrue;\n\n\tHuff_Init(&msgHuff);\n\t// load it in\n\tsize = FS_ReadFile( \"netchan/netchan.bin\", (void **)&data );\n\n\tfor(i=0;i<256;i++) {\n\t\tarray[i] = 0;\n\t}\n\tfor(i=0;i<size;i++) {\n\t\tch = data[i];\n\t\tHuff_addRef(&msgHuff.compressor,\tch);\t\t\t// Do update\n\t\tHuff_addRef(&msgHuff.decompressor,\tch);\t\t\t// Do update\n\t\tarray[ch]++;\n\t}\n\tCom_Printf(\"msg_hData {\\n\");\n\tfor(i=0;i<256;i++) {\n\t\tif (array[i] == 0) {\n\t\t\tHuff_addRef(&msgHuff.compressor,\ti);\t\t\t// Do update\n\t\t\tHuff_addRef(&msgHuff.decompressor,\ti);\t\t\t// Do update\n\t\t}\n\t\tCom_Printf(\"%d,\t\t\t// %d\\n\", array[i], i);\n\t}\n\tCom_Printf(\"};\\n\");\n\tFS_FreeFile( data );\n\tCbuf_AddText( \"condump dump.txt\\n\" );\n}\n*/\n\n//===========================================================================\n"
  },
  {
    "path": "src/engine/qcommon/net_chan.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n#include \"../../game/q_shared.h\"\n#include \"qcommon.h\"\n\n/*\n\npacket header\n-------------\n4\toutgoing sequence.  high bit will be set if this is a fragmented message\n[2\tqport (only for client to server)]\n[2\tfragment start byte]\n[2\tfragment length. if < FRAGMENT_SIZE, this is the last fragment]\n\nif the sequence number is -1, the packet should be handled as an out-of-band\nmessage instead of as part of a netcon.\n\nAll fragments will have the same sequence numbers.\n\nThe qport field is a workaround for bad address translating routers that\nsometimes remap the client's source port on a packet during gameplay.\n\nIf the base part of the net address matches and the qport matches, then the\nchannel matches even if the IP port differs.  The IP port should be updated\nto the new value before sending out any replies.\n\n*/\n\n\n#define\tMAX_PACKETLEN\t\t\t1400\t\t// max size of a network packet\n\n#define\tFRAGMENT_SIZE\t\t\t(MAX_PACKETLEN - 100)\n#define\tPACKET_HEADER\t\t\t10\t\t\t// two ints and a short\n\n#define\tFRAGMENT_BIT\t(1<<31)\n\ncvar_t\t\t*showpackets;\ncvar_t\t\t*showdrop;\ncvar_t\t\t*qport;\n\nstatic char *netsrcString[2] = {\n\t\"client\",\n\t\"server\"\n};\n\n/*\n===============\nNetchan_Init\n\n===============\n*/\nvoid Netchan_Init( int port ) {\n\tport &= 0xffff;\n\tshowpackets = Cvar_Get (\"showpackets\", \"0\", CVAR_TEMP );\n\tshowdrop = Cvar_Get (\"showdrop\", \"0\", CVAR_TEMP );\n\tqport = Cvar_Get (\"net_qport\", va(\"%i\", port), CVAR_INIT );\n}\n\n/*\n==============\nNetchan_Setup\n\ncalled to open a channel to a remote system\n==============\n*/\nvoid Netchan_Setup( netsrc_t sock, netchan_t *chan, netadr_t adr, int qport ) {\n\tCom_Memset (chan, 0, sizeof(*chan));\n\t\n\tchan->sock = sock;\n\tchan->remoteAddress = adr;\n\tchan->qport = qport;\n\tchan->incomingSequence = 0;\n\tchan->outgoingSequence = 1;\n}\n\n// TTimo: unused, commenting out to make gcc happy\n#if 0\n/*\n==============\nNetchan_ScramblePacket\n\nA probably futile attempt to make proxy hacking somewhat\nmore difficult.\n==============\n*/\n#define\tSCRAMBLE_START\t6\nstatic void Netchan_ScramblePacket( msg_t *buf ) {\n\tunsigned\tseed;\n\tint\t\t\ti, j, c, mask, temp;\n\tint\t\t\tseq[MAX_PACKETLEN];\n\n\tseed = ( LittleLong( *(unsigned *)buf->data ) * 3 ) ^ ( buf->cursize * 123 );\n\tc = buf->cursize;\n\tif ( c <= SCRAMBLE_START ) {\n\t\treturn;\n\t}\n\tif ( c > MAX_PACKETLEN ) {\n\t\tCom_Error( ERR_DROP, \"MAX_PACKETLEN\" );\n\t}\n\n\t// generate a sequence of \"random\" numbers\n\tfor (i = 0 ; i < c ; i++) {\n\t\tseed = (119 * seed + 1);\n\t\tseq[i] = seed;\n\t}\n\n\t// transpose each character\n\tfor ( mask = 1 ; mask < c-SCRAMBLE_START ; mask = ( mask << 1 ) + 1 ) {\n\t}\n\tmask >>= 1;\n\tfor (i = SCRAMBLE_START ; i < c ; i++) {\n\t\tj = SCRAMBLE_START + ( seq[i] & mask );\n\t\ttemp = buf->data[j];\n\t\tbuf->data[j] = buf->data[i];\n\t\tbuf->data[i] = temp;\n\t}\n\n\t// byte xor the data after the header\n\tfor (i = SCRAMBLE_START ; i < c ; i++) {\n\t\tbuf->data[i] ^= seq[i];\n\t}\n}\n\nstatic void Netchan_UnScramblePacket( msg_t *buf ) {\n\tunsigned\tseed;\n\tint\t\t\ti, j, c, mask, temp;\n\tint\t\t\tseq[MAX_PACKETLEN];\n\n\tseed = ( LittleLong( *(unsigned *)buf->data ) * 3 ) ^ ( buf->cursize * 123 );\n\tc = buf->cursize;\n\tif ( c <= SCRAMBLE_START ) {\n\t\treturn;\n\t}\n\tif ( c > MAX_PACKETLEN ) {\n\t\tCom_Error( ERR_DROP, \"MAX_PACKETLEN\" );\n\t}\n\n\t// generate a sequence of \"random\" numbers\n\tfor (i = 0 ; i < c ; i++) {\n\t\tseed = (119 * seed + 1);\n\t\tseq[i] = seed;\n\t}\n\n\t// byte xor the data after the header\n\tfor (i = SCRAMBLE_START ; i < c ; i++) {\n\t\tbuf->data[i] ^= seq[i];\n\t}\n\n\t// transpose each character in reverse order\n\tfor ( mask = 1 ; mask < c-SCRAMBLE_START ; mask = ( mask << 1 ) + 1 ) {\n\t}\n\tmask >>= 1;\n\tfor (i = c-1 ; i >= SCRAMBLE_START ; i--) {\n\t\tj = SCRAMBLE_START + ( seq[i] & mask );\n\t\ttemp = buf->data[j];\n\t\tbuf->data[j] = buf->data[i];\n\t\tbuf->data[i] = temp;\n\t}\n}\n#endif\n\n/*\n=================\nNetchan_TransmitNextFragment\n\nSend one fragment of the current message\n=================\n*/\nvoid Netchan_TransmitNextFragment( netchan_t *chan ) {\n\tmsg_t\t\tsend;\n\tbyte\t\tsend_buf[MAX_PACKETLEN];\n\tint\t\t\tfragmentLength;\n\n\t// write the packet header\n\tMSG_InitOOB (&send, send_buf, sizeof(send_buf));\t\t\t\t// <-- only do the oob here\n\n\tMSG_WriteLong( &send, chan->outgoingSequence | FRAGMENT_BIT );\n\n\t// send the qport if we are a client\n\tif ( chan->sock == NS_CLIENT ) {\n\t\tMSG_WriteShort( &send, qport->integer );\n\t}\n\n\t// copy the reliable message to the packet first\n\tfragmentLength = FRAGMENT_SIZE;\n\tif ( chan->unsentFragmentStart  + fragmentLength > chan->unsentLength ) {\n\t\tfragmentLength = chan->unsentLength - chan->unsentFragmentStart;\n\t}\n\n\tMSG_WriteShort( &send, chan->unsentFragmentStart );\n\tMSG_WriteShort( &send, fragmentLength );\n\tMSG_WriteData( &send, chan->unsentBuffer + chan->unsentFragmentStart, fragmentLength );\n\n\t// send the datagram\n\tNET_SendPacket( chan->sock, send.cursize, send.data, chan->remoteAddress );\n\n\tif ( showpackets->integer ) {\n\t\tCom_Printf (\"%s send %4i : s=%i fragment=%i,%i\\n\"\n\t\t\t, netsrcString[ chan->sock ]\n\t\t\t, send.cursize\n\t\t\t, chan->outgoingSequence\n\t\t\t, chan->unsentFragmentStart, fragmentLength);\n\t}\n\n\tchan->unsentFragmentStart += fragmentLength;\n\n\t// this exit condition is a little tricky, because a packet\n\t// that is exactly the fragment length still needs to send\n\t// a second packet of zero length so that the other side\n\t// can tell there aren't more to follow\n\tif ( chan->unsentFragmentStart == chan->unsentLength && fragmentLength != FRAGMENT_SIZE ) {\n\t\tchan->outgoingSequence++;\n\t\tchan->unsentFragments = qfalse;\n\t}\n}\n\n\n/*\n===============\nNetchan_Transmit\n\nSends a message to a connection, fragmenting if necessary\nA 0 length will still generate a packet.\n================\n*/\nvoid Netchan_Transmit( netchan_t *chan, int length, const byte *data ) {\n\tmsg_t\t\tsend;\n\tbyte\t\tsend_buf[MAX_PACKETLEN];\n\n\tif ( length > MAX_MSGLEN ) {\n\t\tCom_Error( ERR_DROP, \"Netchan_Transmit: length = %i\", length );\n\t}\n\tchan->unsentFragmentStart = 0;\n\n\t// fragment large reliable messages\n\tif ( length >= FRAGMENT_SIZE ) {\n\t\tchan->unsentFragments = qtrue;\n\t\tchan->unsentLength = length;\n\t\tCom_Memcpy( chan->unsentBuffer, data, length );\n\n\t\t// only send the first fragment now\n\t\tNetchan_TransmitNextFragment( chan );\n\n\t\treturn;\n\t}\n\n\t// write the packet header\n\tMSG_InitOOB (&send, send_buf, sizeof(send_buf));\n\n\tMSG_WriteLong( &send, chan->outgoingSequence );\n\tchan->outgoingSequence++;\n\n\t// send the qport if we are a client\n\tif ( chan->sock == NS_CLIENT ) {\n\t\tMSG_WriteShort( &send, qport->integer );\n\t}\n\n\tMSG_WriteData( &send, data, length );\n\n\t// send the datagram\n\tNET_SendPacket( chan->sock, send.cursize, send.data, chan->remoteAddress );\n\n\tif ( showpackets->integer ) {\n\t\tCom_Printf( \"%s send %4i : s=%i ack=%i\\n\"\n\t\t\t, netsrcString[ chan->sock ]\n\t\t\t, send.cursize\n\t\t\t, chan->outgoingSequence - 1\n\t\t\t, chan->incomingSequence );\n\t}\n}\n\n/*\n=================\nNetchan_Process\n\nReturns qfalse if the message should not be processed due to being\nout of order or a fragment.\n\nMsg must be large enough to hold MAX_MSGLEN, because if this is the\nfinal fragment of a multi-part message, the entire thing will be\ncopied out.\n=================\n*/\nqboolean Netchan_Process( netchan_t *chan, msg_t *msg ) {\n\tint\t\t\tsequence;\n\tint\t\t\tqport;\n\tint\t\t\tfragmentStart, fragmentLength;\n\tqboolean\tfragmented;\n\n\t// XOR unscramble all data in the packet after the header\n//\tNetchan_UnScramblePacket( msg );\n\n\t// get sequence numbers\t\t\n\tMSG_BeginReadingOOB( msg );\n\tsequence = MSG_ReadLong( msg );\n\n\t// check for fragment information\n\tif ( sequence & FRAGMENT_BIT ) {\n\t\tsequence &= ~FRAGMENT_BIT;\n\t\tfragmented = qtrue;\n\t} else {\n\t\tfragmented = qfalse;\n\t}\n\n\t// read the qport if we are a server\n\tif ( chan->sock == NS_SERVER ) {\n\t\tqport = MSG_ReadShort( msg );\n\t}\n\n\t// read the fragment information\n\tif ( fragmented ) {\n\t\tfragmentStart = MSG_ReadShort( msg );\n\t\tfragmentLength = MSG_ReadShort( msg );\n\t} else {\n\t\tfragmentStart = 0;\t\t// stop warning message\n\t\tfragmentLength = 0;\n\t}\n\n\tif ( showpackets->integer ) {\n\t\tif ( fragmented ) {\n\t\t\tCom_Printf( \"%s recv %4i : s=%i fragment=%i,%i\\n\"\n\t\t\t\t, netsrcString[ chan->sock ]\n\t\t\t\t, msg->cursize\n\t\t\t\t, sequence\n\t\t\t\t, fragmentStart, fragmentLength );\n\t\t} else {\n\t\t\tCom_Printf( \"%s recv %4i : s=%i\\n\"\n\t\t\t\t, netsrcString[ chan->sock ]\n\t\t\t\t, msg->cursize\n\t\t\t\t, sequence );\n\t\t}\n\t}\n\n\t//\n\t// discard out of order or duplicated packets\n\t//\n\tif ( sequence <= chan->incomingSequence ) {\n\t\tif ( showdrop->integer || showpackets->integer ) {\n\t\t\tCom_Printf( \"%s:Out of order packet %i at %i\\n\"\n\t\t\t\t, NET_AdrToString( chan->remoteAddress )\n\t\t\t\t,  sequence\n\t\t\t\t, chan->incomingSequence );\n\t\t}\n\t\treturn qfalse;\n\t}\n\n\t//\n\t// dropped packets don't keep the message from being used\n\t//\n\tchan->dropped = sequence - (chan->incomingSequence+1);\n\tif ( chan->dropped > 0 ) {\n\t\tif ( showdrop->integer || showpackets->integer ) {\n\t\t\tCom_Printf( \"%s:Dropped %i packets at %i\\n\"\n\t\t\t, NET_AdrToString( chan->remoteAddress )\n\t\t\t, chan->dropped\n\t\t\t, sequence );\n\t\t}\n\t}\n\t\n\n\t//\n\t// if this is the final framgent of a reliable message,\n\t// bump incoming_reliable_sequence \n\t//\n\tif ( fragmented ) {\n\t\t// TTimo\n\t\t// make sure we add the fragments in correct order\n\t\t// either a packet was dropped, or we received this one too soon\n\t\t// we don't reconstruct the fragments. we will wait till this fragment gets to us again\n\t\t// (NOTE: we could probably try to rebuild by out of order chunks if needed)\n\t\tif ( sequence != chan->fragmentSequence ) {\n\t\t\tchan->fragmentSequence = sequence;\n\t\t\tchan->fragmentLength = 0;\n\t\t}\n\n\t\t// if we missed a fragment, dump the message\n\t\tif ( fragmentStart != chan->fragmentLength ) {\n\t\t\tif ( showdrop->integer || showpackets->integer ) {\n\t\t\t\tCom_Printf( \"%s:Dropped a message fragment\\n\"\n\t\t\t\t, NET_AdrToString( chan->remoteAddress )\n\t\t\t\t, sequence);\n\t\t\t}\n\t\t\t// we can still keep the part that we have so far,\n\t\t\t// so we don't need to clear chan->fragmentLength\n\t\t\treturn qfalse;\n\t\t}\n\n\t\t// copy the fragment to the fragment buffer\n\t\tif ( fragmentLength < 0 || msg->readcount + fragmentLength > msg->cursize ||\n\t\t\tchan->fragmentLength + fragmentLength > sizeof( chan->fragmentBuffer ) ) {\n\t\t\tif ( showdrop->integer || showpackets->integer ) {\n\t\t\t\tCom_Printf (\"%s:illegal fragment length\\n\"\n\t\t\t\t, NET_AdrToString (chan->remoteAddress ) );\n\t\t\t}\n\t\t\treturn qfalse;\n\t\t}\n\n\t\tCom_Memcpy( chan->fragmentBuffer + chan->fragmentLength, \n\t\t\tmsg->data + msg->readcount, fragmentLength );\n\n\t\tchan->fragmentLength += fragmentLength;\n\n\t\t// if this wasn't the last fragment, don't process anything\n\t\tif ( fragmentLength == FRAGMENT_SIZE ) {\n\t\t\treturn qfalse;\n\t\t}\n\n\t\tif ( chan->fragmentLength > msg->maxsize ) {\n\t\t\tCom_Printf( \"%s:fragmentLength %i > msg->maxsize\\n\"\n\t\t\t\t, NET_AdrToString (chan->remoteAddress ),\n\t\t\t\tchan->fragmentLength );\n\t\t\treturn qfalse;\n\t\t}\n\n\t\t// copy the full message over the partial fragment\n\n\t\t// make sure the sequence number is still there\n\t\t*(int *)msg->data = LittleLong( sequence );\n\n\t\tCom_Memcpy( msg->data + 4, chan->fragmentBuffer, chan->fragmentLength );\n\t\tmsg->cursize = chan->fragmentLength + 4;\n\t\tchan->fragmentLength = 0;\n\t\tmsg->readcount = 4;\t// past the sequence number\n\t\tmsg->bit = 32;\t// past the sequence number\n\n\t\t// TTimo\n\t\t// clients were not acking fragmented messages\n\t\tchan->incomingSequence = sequence;\n\t\t\n\t\treturn qtrue;\n\t}\n\n\t//\n\t// the message can now be read from the current message pointer\n\t//\n\tchan->incomingSequence = sequence;\n\n\treturn qtrue;\n}\n\n\n//==============================================================================\n\n/*\n===================\nNET_CompareBaseAdr\n\nCompares without the port\n===================\n*/\nqboolean\tNET_CompareBaseAdr (netadr_t a, netadr_t b)\n{\n\tif (a.type != b.type)\n\t\treturn qfalse;\n\n\tif (a.type == NA_LOOPBACK)\n\t\treturn qtrue;\n\n\tif (a.type == NA_IP)\n\t{\n\t\tif (a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3])\n\t\t\treturn qtrue;\n\t\treturn qfalse;\n\t}\n\n\tif (a.type == NA_IPX)\n\t{\n\t\tif ((memcmp(a.ipx, b.ipx, 10) == 0))\n\t\t\treturn qtrue;\n\t\treturn qfalse;\n\t}\n\n\n\tCom_Printf (\"NET_CompareBaseAdr: bad address type\\n\");\n\treturn qfalse;\n}\n\nconst char\t*NET_AdrToString (netadr_t a)\n{\n\tstatic\tchar\ts[64];\n\n\tif (a.type == NA_LOOPBACK) {\n\t\tCom_sprintf (s, sizeof(s), \"loopback\");\n\t} else if (a.type == NA_BOT) {\n\t\tCom_sprintf (s, sizeof(s), \"bot\");\n\t} else if (a.type == NA_IP) {\n\t\tCom_sprintf (s, sizeof(s), \"%i.%i.%i.%i:%hu\",\n\t\t\ta.ip[0], a.ip[1], a.ip[2], a.ip[3], BigShort(a.port));\n\t} else {\n\t\tCom_sprintf (s, sizeof(s), \"%02x%02x%02x%02x.%02x%02x%02x%02x%02x%02x:%hu\",\n\t\ta.ipx[0], a.ipx[1], a.ipx[2], a.ipx[3], a.ipx[4], a.ipx[5], a.ipx[6], a.ipx[7], a.ipx[8], a.ipx[9], \n\t\tBigShort(a.port));\n\t}\n\n\treturn s;\n}\n\n\nqboolean\tNET_CompareAdr (netadr_t a, netadr_t b)\n{\n\tif (a.type != b.type)\n\t\treturn qfalse;\n\n\tif (a.type == NA_LOOPBACK)\n\t\treturn qtrue;\n\n\tif (a.type == NA_IP)\n\t{\n\t\tif (a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3] && a.port == b.port)\n\t\t\treturn qtrue;\n\t\treturn qfalse;\n\t}\n\n\tif (a.type == NA_IPX)\n\t{\n\t\tif ((memcmp(a.ipx, b.ipx, 10) == 0) && a.port == b.port)\n\t\t\treturn qtrue;\n\t\treturn qfalse;\n\t}\n\n\tCom_Printf (\"NET_CompareAdr: bad address type\\n\");\n\treturn qfalse;\n}\n\n\nqboolean\tNET_IsLocalAddress( netadr_t adr ) {\n\treturn (qboolean) (adr.type == NA_LOOPBACK);\n}\n\n\n\n/*\n=============================================================================\n\nLOOPBACK BUFFERS FOR LOCAL PLAYER\n\n=============================================================================\n*/\n\n// there needs to be enough loopback messages to hold a complete\n// gamestate of maximum size\n#define\tMAX_LOOPBACK\t16\n\ntypedef struct {\n\tbyte\tdata[MAX_PACKETLEN];\n\tint\t\tdatalen;\n} loopmsg_t;\n\ntypedef struct {\n\tloopmsg_t\tmsgs[MAX_LOOPBACK];\n\tint\t\t\tget, send;\n} loopback_t;\n\nloopback_t\tloopbacks[2];\n\n\nqboolean\tNET_GetLoopPacket (netsrc_t sock, netadr_t *net_from, msg_t *net_message)\n{\n\tint\t\ti;\n\tloopback_t\t*loop;\n\n\tloop = &loopbacks[sock];\n\n\tif (loop->send - loop->get > MAX_LOOPBACK)\n\t\tloop->get = loop->send - MAX_LOOPBACK;\n\n\tif (loop->get >= loop->send)\n\t\treturn qfalse;\n\n\ti = loop->get & (MAX_LOOPBACK-1);\n\tloop->get++;\n\n\tCom_Memcpy (net_message->data, loop->msgs[i].data, loop->msgs[i].datalen);\n\tnet_message->cursize = loop->msgs[i].datalen;\n\tCom_Memset (net_from, 0, sizeof(*net_from));\n\tnet_from->type = NA_LOOPBACK;\n\treturn qtrue;\n\n}\n\n\nvoid NET_SendLoopPacket (netsrc_t sock, int length, const void *data, netadr_t to)\n{\n\tint\t\ti;\n\tloopback_t\t*loop;\n\n\tloop = &loopbacks[sock^1];\n\n\ti = loop->send & (MAX_LOOPBACK-1);\n\tloop->send++;\n\n\tCom_Memcpy (loop->msgs[i].data, data, length);\n\tloop->msgs[i].datalen = length;\n}\n\n//=============================================================================\n\n\nvoid NET_SendPacket( netsrc_t sock, int length, const void *data, netadr_t to ) {\n\n\t// sequenced packets are shown in netchan, so just show oob\n\tif ( showpackets->integer && *(int *)data == -1 )\t{\n\t\tCom_Printf (\"send packet %4i\\n\", length);\n\t}\n\n\tif ( to.type == NA_LOOPBACK ) {\n\t\tNET_SendLoopPacket (sock, length, data, to);\n\t\treturn;\n\t}\n\tif ( to.type == NA_BOT ) {\n\t\treturn;\n\t}\n\tif ( to.type == NA_BAD ) {\n\t\treturn;\n\t}\n\n\tSys_SendPacket( length, data, to );\n}\n\n/*\n===============\nNET_OutOfBandPrint\n\nSends a text message in an out-of-band datagram\n================\n*/\nvoid QDECL NET_OutOfBandPrint( netsrc_t sock, netadr_t adr, const char *format, ... ) {\n\tva_list\t\targptr;\n\tchar\t\tstring[MAX_MSGLEN];\n\n\n\t// set the header\n\tstring[0] = -1;\n\tstring[1] = -1;\n\tstring[2] = -1;\n\tstring[3] = -1;\n\n\tva_start( argptr, format );\n\tvsprintf( string+4, format, argptr );\n\tva_end( argptr );\n\n\t// send the datagram\n\tNET_SendPacket( sock, (int)strlen( string ), string, adr );\n}\n\n/*\n===============\nNET_OutOfBandPrint\n\nSends a data message in an out-of-band datagram (only used for \"connect\")\n================\n*/\nvoid QDECL NET_OutOfBandData( netsrc_t sock, netadr_t adr, byte *format, int len ) {\n\tbyte\t\tstring[MAX_MSGLEN*2];\n\tint\t\t\ti;\n\tmsg_t\t\tmbuf;\n\n\t// set the header\n\tstring[0] = 0xff;\n\tstring[1] = 0xff;\n\tstring[2] = 0xff;\n\tstring[3] = 0xff;\n\n\tfor(i=0;i<len;i++) {\n\t\tstring[i+4] = format[i];\n\t}\n\n\tmbuf.data = string;\n\tmbuf.cursize = len+4;\n\tHuff_Compress( &mbuf, 12);\n\t// send the datagram\n\tNET_SendPacket( sock, mbuf.cursize, mbuf.data, adr );\n}\n\n/*\n=============\nNET_StringToAdr\n\nTraps \"localhost\" for loopback, passes everything else to system\n=============\n*/\nqboolean\tNET_StringToAdr( const char *s, netadr_t *a ) {\n\tqboolean\tr;\n\tchar\tbase[MAX_STRING_CHARS];\n\tchar\t*port;\n\n\tif (!strcmp (s, \"localhost\")) {\n\t\tCom_Memset (a, 0, sizeof(*a));\n\t\ta->type = NA_LOOPBACK;\n\t\treturn qtrue;\n\t}\n\n\t// look for a port number\n\tQ_strncpyz( base, s, sizeof( base ) );\n\tport = strstr( base, \":\" );\n\tif ( port ) {\n\t\t*port = 0;\n\t\tport++;\n\t}\n\n\tr = Sys_StringToAdr( base, a );\n\n\tif ( !r ) {\n\t\ta->type = NA_BAD;\n\t\treturn qfalse;\n\t}\n\n\t// inet_addr returns this if out of range\n\tif ( a->ip[0] == 255 && a->ip[1] == 255 && a->ip[2] == 255 && a->ip[3] == 255 ) {\n\t\ta->type = NA_BAD;\n\t\treturn qfalse;\n\t}\n\n\tif ( port ) {\n\t\ta->port = BigShort( (short)atoi( port ) );\n\t} else {\n\t\ta->port = BigShort( PORT_SERVER );\n\t}\n\n\treturn qtrue;\n}\n\n"
  },
  {
    "path": "src/engine/qcommon/qcommon.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n// qcommon.h -- definitions common between client and server, but not game.or ref modules\n#ifndef _QCOMMON_H_\n#define _QCOMMON_H_\n\n#include \"../qcommon/cm_public.h\"\n\n//#define\tPRE_RELEASE_DEMO\n\n//============================================================================\n\n//\n// msg.c\n//\ntypedef struct {\n\tqboolean\tallowoverflow;\t// if false, do a Com_Error\n\tqboolean\toverflowed;\t\t// set to true if the buffer size failed (with allowoverflow set)\n\tqboolean\toob;\t\t\t// set to true if the buffer size failed (with allowoverflow set)\n\tbyte\t*data;\n\tint\t\tmaxsize;\n\tint\t\tcursize;\n\tint\t\treadcount;\n\tint\t\tbit;\t\t\t\t// for bitwise reads and writes\n} msg_t;\n\nvoid MSG_Init (msg_t *buf, byte *data, int length);\nvoid MSG_InitOOB( msg_t *buf, byte *data, int length );\nvoid MSG_Clear (msg_t *buf);\nvoid MSG_WriteData (msg_t *buf, const void *data, int length);\nvoid MSG_Bitstream( msg_t *buf );\n\n// TTimo\n// copy a msg_t in case we need to store it as is for a bit\n// (as I needed this to keep an msg_t from a static var for later use)\n// sets data buffer as MSG_Init does prior to do the copy\nvoid MSG_Copy(msg_t *buf, byte *data, int length, msg_t *src);\n\nstruct usercmd_s;\nstruct entityState_s;\nstruct playerState_s;\n\nvoid MSG_WriteBits( msg_t *msg, int value, int bits );\n\nvoid MSG_WriteChar (msg_t *sb, int c);\nvoid MSG_WriteByte (msg_t *sb, int c);\nvoid MSG_WriteShort (msg_t *sb, int c);\nvoid MSG_WriteLong (msg_t *sb, int c);\nvoid MSG_WriteFloat (msg_t *sb, float f);\nvoid MSG_WriteString (msg_t *sb, const char *s);\nvoid MSG_WriteBigString (msg_t *sb, const char *s);\nvoid MSG_WriteAngle16 (msg_t *sb, float f);\n\nvoid\tMSG_BeginReading (msg_t *sb);\nvoid\tMSG_BeginReadingOOB(msg_t *sb);\n\nint\t\tMSG_ReadBits( msg_t *msg, int bits );\n\nint\t\tMSG_ReadChar (msg_t *sb);\nint\t\tMSG_ReadByte (msg_t *sb);\nint\t\tMSG_ReadShort (msg_t *sb);\nint\t\tMSG_ReadLong (msg_t *sb);\nfloat\tMSG_ReadFloat (msg_t *sb);\nchar\t*MSG_ReadString (msg_t *sb);\nchar\t*MSG_ReadBigString (msg_t *sb);\nchar\t*MSG_ReadStringLine (msg_t *sb);\nfloat\tMSG_ReadAngle16 (msg_t *sb);\nvoid\tMSG_ReadData (msg_t *sb, void *buffer, int size);\n\n\nvoid MSG_WriteDeltaUsercmd( msg_t *msg, struct usercmd_s *from, struct usercmd_s *to );\nvoid MSG_ReadDeltaUsercmd( msg_t *msg, struct usercmd_s *from, struct usercmd_s *to );\n\nvoid MSG_WriteDeltaUsercmdKey( msg_t *msg, int key, usercmd_t *from, usercmd_t *to );\nvoid MSG_ReadDeltaUsercmdKey( msg_t *msg, int key, usercmd_t *from, usercmd_t *to );\n\nvoid MSG_WriteDeltaEntity( msg_t *msg, struct entityState_s *from, struct entityState_s *to\n\t\t\t\t\t\t   , qboolean force );\nvoid MSG_ReadDeltaEntity( msg_t *msg, entityState_t *from, entityState_t *to, \n\t\t\t\t\t\t int number );\n\nvoid MSG_WriteDeltaPlayerstate( msg_t *msg, struct playerState_s *from, struct playerState_s *to );\nvoid MSG_ReadDeltaPlayerstate( msg_t *msg, struct playerState_s *from, struct playerState_s *to );\n\n\nvoid MSG_ReportChangeVectors_f( void );\n\n//============================================================================\n\n/*\n==============================================================\n\nNET\n\n==============================================================\n*/\n\n#define\tPACKET_BACKUP\t32\t// number of old messages that must be kept on client and\n\t\t\t\t\t\t\t// server for delta comrpession and ping estimation\n#define\tPACKET_MASK\t\t(PACKET_BACKUP-1)\n\n#define\tMAX_PACKET_USERCMDS\t\t32\t\t// max number of usercmd_t in a packet\n\n#define\tPORT_ANY\t\t\t-1\n\n#define\tMAX_RELIABLE_COMMANDS\t64\t\t\t// max string commands buffered for restransmit\n\ntypedef enum {\n\tNA_BOT,\n\tNA_BAD,\t\t\t\t\t// an address lookup failed\n\tNA_LOOPBACK,\n\tNA_BROADCAST,\n\tNA_IP,\n\tNA_IPX,\n\tNA_BROADCAST_IPX\n} netadrtype_t;\n\ntypedef enum {\n\tNS_CLIENT,\n\tNS_SERVER\n} netsrc_t;\n\ntypedef struct {\n\tnetadrtype_t\ttype;\n\n\tbyte\tip[4];\n\tbyte\tipx[10];\n\n\tunsigned short\tport;\n} netadr_t;\n\nvoid\t\tNET_Init( void );\nvoid\t\tNET_Shutdown( void );\nvoid\t\tNET_Restart( void );\nvoid\t\tNET_Config( qboolean enableNetworking );\n\nvoid\t\tNET_SendPacket (netsrc_t sock, int length, const void *data, netadr_t to);\nvoid\t\tQDECL NET_OutOfBandPrint( netsrc_t net_socket, netadr_t adr, const char *format, ...);\nvoid\t\tQDECL NET_OutOfBandData( netsrc_t sock, netadr_t adr, byte *format, int len );\n\nqboolean\tNET_CompareAdr (netadr_t a, netadr_t b);\nqboolean\tNET_CompareBaseAdr (netadr_t a, netadr_t b);\nqboolean\tNET_IsLocalAddress (netadr_t adr);\nconst char\t*NET_AdrToString (netadr_t a);\nqboolean\tNET_StringToAdr ( const char *s, netadr_t *a);\nqboolean\tNET_GetLoopPacket (netsrc_t sock, netadr_t *net_from, msg_t *net_message);\nvoid\t\tNET_Sleep(int msec);\n\n\n#define\tMAX_MSGLEN\t\t\t\t16384\t\t// max length of a message, which may\n\t\t\t\t\t\t\t\t\t\t\t// be fragmented into multiple packets\n\n#define MAX_DOWNLOAD_WINDOW\t\t\t8\t\t// max of eight download frames\n#define MAX_DOWNLOAD_BLKSIZE\t\t2048\t// 2048 byte block chunks\n \n\n/*\nNetchan handles packet fragmentation and out of order / duplicate suppression\n*/\n\ntypedef struct {\n\tnetsrc_t\tsock;\n\n\tint\t\t\tdropped;\t\t\t// between last packet and previous\n\n\tnetadr_t\tremoteAddress;\n\tint\t\t\tqport;\t\t\t\t// qport value to write when transmitting\n\n\t// sequencing variables\n\tint\t\t\tincomingSequence;\n\tint\t\t\toutgoingSequence;\n\n\t// incoming fragment assembly buffer\n\tint\t\t\tfragmentSequence;\n\tint\t\t\tfragmentLength;\t\n\tbyte\t\tfragmentBuffer[MAX_MSGLEN];\n\n\t// outgoing fragment buffer\n\t// we need to space out the sending of large fragmented messages\n\tqboolean\tunsentFragments;\n\tint\t\t\tunsentFragmentStart;\n\tint\t\t\tunsentLength;\n\tbyte\t\tunsentBuffer[MAX_MSGLEN];\n} netchan_t;\n\nvoid Netchan_Init( int qport );\nvoid Netchan_Setup( netsrc_t sock, netchan_t *chan, netadr_t adr, int qport );\n\nvoid Netchan_Transmit( netchan_t *chan, int length, const byte *data );\nvoid Netchan_TransmitNextFragment( netchan_t *chan );\n\nqboolean Netchan_Process( netchan_t *chan, msg_t *msg );\n\n\n/*\n==============================================================\n\nPROTOCOL\n\n==============================================================\n*/\n\n#define\tPROTOCOL_VERSION\t68\n// 1.31 - 67\n\n// maintain a list of compatible protocols for demo playing\n// NOTE: that stuff only works with two digits protocols\nextern int demo_protocols[];\n\n#define\tUPDATE_SERVER_NAME\t\"update.quake3arena.com\"\n// override on command line, config files etc.\n#ifndef MASTER_SERVER_NAME\n#define MASTER_SERVER_NAME\t\"master.quake3arena.com\"\n#endif\n#ifndef AUTHORIZE_SERVER_NAME\n#define\tAUTHORIZE_SERVER_NAME\t\"authorize.quake3arena.com\"\n#endif\n\n#define\tPORT_MASTER\t\t\t27950\n#define\tPORT_UPDATE\t\t\t27951\n#ifndef PORT_AUTHORIZE\n#define\tPORT_AUTHORIZE\t\t27952\n#endif\n#define\tPORT_SERVER\t\t\t27960\n#define\tNUM_SERVER_PORTS\t4\t\t// broadcast scan this many ports after\n\t\t\t\t\t\t\t\t\t// PORT_SERVER so a single machine can\n\t\t\t\t\t\t\t\t\t// run multiple servers\n\n\n// the svc_strings[] array in cl_parse.c should mirror this\n//\n// server to client\n//\nenum svc_ops_e {\n\tsvc_bad,\n\tsvc_nop,\n\tsvc_gamestate,\n\tsvc_configstring,\t\t\t// [short] [string] only in gamestate messages\n\tsvc_baseline,\t\t\t\t// only in gamestate messages\n\tsvc_serverCommand,\t\t\t// [string] to be executed by client game module\n\tsvc_download,\t\t\t\t// [short] size [size bytes]\n\tsvc_snapshot,\n\tsvc_EOF\n};\n\n\n//\n// client to server\n//\nenum clc_ops_e {\n\tclc_bad,\n\tclc_nop, \t\t\n\tclc_move,\t\t\t\t// [[usercmd_t]\n\tclc_moveNoDelta,\t\t// [[usercmd_t]\n\tclc_clientCommand,\t\t// [string] message\n\tclc_EOF\n};\n\n/*\n==============================================================\n\nVIRTUAL MACHINE\n\n==============================================================\n*/\n\ntypedef struct vm_s vm_t;\n\ntypedef enum {\n\tVMI_NATIVE,\n\tVMI_BYTECODE\n} vmInterpret_t;\n\ntypedef enum {\n\tTRAP_MEMSET = 100,\n\tTRAP_MEMCPY,\n\tTRAP_STRNCPY,\n\tTRAP_SIN,\n\tTRAP_COS,\n\tTRAP_ATAN2,\n\tTRAP_SQRT,\n\tTRAP_MATRIXMULTIPLY,\n\tTRAP_ANGLEVECTORS,\n\tTRAP_PERPENDICULARVECTOR,\n\tTRAP_FLOOR,\n\tTRAP_CEIL,\n\n\tTRAP_TESTPRINTINT,\n\tTRAP_TESTPRINTFLOAT\n} sharedTraps_t;\n\nvoid\tVM_Init( void );\nvm_t\t*VM_Create( const char *module, intptr_t (*systemCalls)(intptr_t *), \n\t\t\t\t   vmInterpret_t interpret );\n// module should be bare: \"cgame\", not \"cgame.dll\" or \"vm/cgame.qvm\"\n\nvoid\tVM_Free( vm_t *vm );\nvoid\tVM_Clear(void);\nvm_t\t*VM_Restart( vm_t *vm );\n\nintptr_t\t\tQDECL VM_Call( vm_t *vm, int callNum, ... );\n\nvoid\tVM_Debug( int level );\n\nvoid\t*VM_ArgPtr( intptr_t intValue );\nvoid\t*VM_ExplicitArgPtr( vm_t *vm, intptr_t intValue );\n\n\n/*\n==============================================================\n\nCMD\n\nCommand text buffering and command execution\n\n==============================================================\n*/\n\n/*\n\nAny number of commands can be added in a frame, from several different sources.\nMost commands come from either keybindings or console line input, but entire text\nfiles can be execed.\n\n*/\n\nvoid Cbuf_Init (void);\n// allocates an initial text buffer that will grow as needed\n\nvoid Cbuf_AddText( const char *text );\n// Adds command text at the end of the buffer, does NOT add a final \\n\n\nvoid Cbuf_ExecuteText( int exec_when, const char *text );\n// this can be used in place of either Cbuf_AddText or Cbuf_InsertText\n\nvoid Cbuf_Execute (void);\n// Pulls off \\n terminated lines of text from the command buffer and sends\n// them through Cmd_ExecuteString.  Stops when the buffer is empty.\n// Normally called once per frame, but may be explicitly invoked.\n// Do not call inside a command function, or current args will be destroyed.\n\n//===========================================================================\n\n/*\n\nCommand execution takes a null terminated string, breaks it into tokens,\nthen searches for a command or variable that matches the first token.\n\n*/\n\ntypedef void (*xcommand_t) (void);\n\nvoid\tCmd_Init (void);\n\nvoid\tCmd_AddCommand( const char *cmd_name, xcommand_t function );\n// called by the init functions of other parts of the program to\n// register commands and functions to call for them.\n// The cmd_name is referenced later, so it should not be in temp memory\n// if function is NULL, the command will be forwarded to the server\n// as a clc_clientCommand instead of executed locally\n\nvoid\tCmd_RemoveCommand( const char *cmd_name );\n\nvoid\tCmd_CommandCompletion( void(*callback)(const char *s) );\n// callback with each valid string\n\nint\t\tCmd_Argc (void);\nchar\t*Cmd_Argv (int arg);\nvoid\tCmd_ArgvBuffer( int arg, char *buffer, int bufferLength );\nchar\t*Cmd_Args (void);\nchar\t*Cmd_ArgsFrom( int arg );\nvoid\tCmd_ArgsBuffer( char *buffer, int bufferLength );\nchar\t*Cmd_Cmd (void);\n// The functions that execute commands get their parameters with these\n// functions. Cmd_Argv () will return an empty string, not a NULL\n// if arg > argc, so string operations are allways safe.\n\nvoid\tCmd_TokenizeString( const char *text );\n// Takes a null terminated string.  Does not need to be /n terminated.\n// breaks the string up into arg tokens.\n\nvoid\tCmd_ExecuteString( const char *text );\n// Parses a single line of text into arguments and tries to execute it\n// as if it was typed at the console\n\n\n/*\n==============================================================\n\nCVAR\n\n==============================================================\n*/\n\n/*\n\ncvar_t variables are used to hold scalar or string variables that can be changed\nor displayed at the console or prog code as well as accessed directly\nin C code.\n\nThe user can access cvars from the console in three ways:\nr_draworder\t\t\tprints the current value\nr_draworder 0\t\tsets the current value to 0\nset r_draworder 0\tas above, but creates the cvar if not present\n\nCvars are restricted from having the same names as commands to keep this\ninterface from being ambiguous.\n\nThe are also occasionally used to communicated information between different\nmodules of the program.\n\n*/\n\ncvar_t *Cvar_Get( const char *var_name, const char *value, int flags );\n// creates the variable if it doesn't exist, or returns the existing one\n// if it exists, the value will not be changed, but flags will be ORed in\n// that allows variables to be unarchived without needing bitflags\n// if value is \"\", the value will not override a previously set value.\n\nvoid\tCvar_Register( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags );\n// basically a slightly modified Cvar_Get for the interpreted modules\n\nvoid\tCvar_Update( vmCvar_t *vmCvar );\n// updates an interpreted modules' version of a cvar\n\nvoid \tCvar_Set( const char *var_name, const char *value );\n// will create the variable with no flags if it doesn't exist\n\nvoid Cvar_SetLatched( const char *var_name, const char *value);\n// don't set the cvar immediately\n\nvoid\tCvar_SetValue( const char *var_name, float value );\n// expands value to a string and calls Cvar_Set\n\nfloat\tCvar_VariableValue( const char *var_name );\nint\t\tCvar_VariableIntegerValue( const char *var_name );\n// returns 0 if not defined or non numeric\n\nchar\t*Cvar_VariableString( const char *var_name );\nvoid\tCvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize );\n// returns an empty string if not defined\n\nvoid\tCvar_CommandCompletion( void(*callback)(const char *s) );\n// callback with each valid string\n\nvoid \tCvar_Reset( const char *var_name );\n\nvoid\tCvar_SetCheatState( void );\n// reset all testing vars to a safe value\n\nqboolean Cvar_Command( void );\n// called by Cmd_ExecuteString when Cmd_Argv(0) doesn't match a known\n// command.  Returns true if the command was a variable reference that\n// was handled. (print or change)\n\nvoid \tCvar_WriteVariables( fileHandle_t f );\n// writes lines containing \"set variable value\" for all variables\n// with the archive flag set to true.\n\nvoid\tCvar_Init( void );\n\nchar\t*Cvar_InfoString( int bit );\nchar\t*Cvar_InfoString_Big( int bit );\n// returns an info string containing all the cvars that have the given bit set\n// in their flags ( CVAR_USERINFO, CVAR_SERVERINFO, CVAR_SYSTEMINFO, etc )\nvoid\tCvar_InfoStringBuffer( int bit, char *buff, int buffsize );\n\nvoid\tCvar_Restart_f( void );\n\nextern\tint\t\t\tcvar_modifiedFlags;\n// whenever a cvar is modifed, its flags will be OR'd into this, so\n// a single check can determine if any CVAR_USERINFO, CVAR_SERVERINFO,\n// etc, variables have been modified since the last check.  The bit\n// can then be cleared to allow another change detection.\n\n/*\n==============================================================\n\nFILESYSTEM\n\nNo stdio calls should be used by any part of the game, because\nwe need to deal with all sorts of directory and seperator char\nissues.\n==============================================================\n*/\n\n// referenced flags\n// these are in loop specific order so don't change the order\n#define FS_GENERAL_REF\t0x01\n#define FS_UI_REF\t\t0x02\n#define FS_CGAME_REF\t0x04\n#define FS_QAGAME_REF\t0x08\n// number of id paks that will never be autodownloaded from baseq3\n#define NUM_ID_PAKS\t\t9\n\n#define\tMAX_FILE_HANDLES\t64\n\n#define BASEGAME \"baseq3\"\n\nqboolean FS_Initialized();\n\nvoid\tFS_InitFilesystem (void);\nvoid\tFS_Shutdown( qboolean closemfp );\n\nqboolean\tFS_ConditionalRestart( int checksumFeed );\nvoid\tFS_Restart( int checksumFeed );\n// shutdown and restart the filesystem so changes to fs_gamedir can take effect\n\nchar\t**FS_ListFiles( const char *directory, const char *extension, int *numfiles );\n// directory should not have either a leading or trailing /\n// if extension is \"/\", only subdirectories will be returned\n// the returned files will not include any directories or /\n\nvoid\tFS_FreeFileList( char **list );\n\nqboolean FS_FileExists( const char *file );\n\nint\t\tFS_LoadStack();\n\nint\t\tFS_GetFileList(  const char *path, const char *extension, char *listbuf, int bufsize );\nint\t\tFS_GetModList(  char *listbuf, int bufsize );\n\nfileHandle_t\tFS_FOpenFileWrite( const char *qpath );\n// will properly create any needed paths and deal with seperater character issues\n\nint\t\tFS_filelength( fileHandle_t f );\nfileHandle_t FS_SV_FOpenFileWrite( const char *filename );\nint\t\tFS_SV_FOpenFileRead( const char *filename, fileHandle_t *fp );\nvoid\tFS_SV_Rename( const char *from, const char *to );\nint\t\tFS_FOpenFileRead( const char *qpath, fileHandle_t *file, qboolean uniqueFILE );\n// if uniqueFILE is true, then a new FILE will be fopened even if the file\n// is found in an already open pak file.  If uniqueFILE is false, you must call\n// FS_FCloseFile instead of fclose, otherwise the pak FILE would be improperly closed\n// It is generally safe to always set uniqueFILE to true, because the majority of\n// file IO goes through FS_ReadFile, which Does The Right Thing already.\n\nint\t\tFS_FileIsInPAK(const char *filename, int *pChecksum );\n// returns 1 if a file is in the PAK file, otherwise -1\n\nint\t\tFS_Write( const void *buffer, int len, fileHandle_t f );\n\nint\t\tFS_Read2( void *buffer, int len, fileHandle_t f );\nint\t\tFS_Read( void *buffer, int len, fileHandle_t f );\n// properly handles partial reads and reads from other dlls\n\nvoid\tFS_FCloseFile( fileHandle_t f );\n// note: you can't just fclose from another DLL, due to MS libc issues\n\nint\t\tFS_ReadFile( const char *qpath, void **buffer );\n// returns the length of the file\n// a null buffer will just return the file length without loading\n// as a quick check for existance. -1 length == not present\n// A 0 byte will always be appended at the end, so string ops are safe.\n// the buffer should be considered read-only, because it may be cached\n// for other uses.\n\nvoid\tFS_ForceFlush( fileHandle_t f );\n// forces flush on files we're writing to.\n\nvoid\tFS_FreeFile( void *buffer );\n// frees the memory returned by FS_ReadFile\n\nvoid\tFS_WriteFile( const char *qpath, const void *buffer, int size );\n// writes a complete file, creating any subdirectories needed\n\nint\t\tFS_filelength( fileHandle_t f );\n// doesn't work for files that are opened from a pack file\n\nint\t\tFS_FTell( fileHandle_t f );\n// where are we?\n\nvoid\tFS_Flush( fileHandle_t f );\n\nvoid \tQDECL FS_Printf( fileHandle_t f, const char *fmt, ... );\n// like fprintf\n\nint\t\tFS_FOpenFileByMode( const char *qpath, fileHandle_t *f, fsMode_t mode );\n// opens a file for reading, writing, or appending depending on the value of mode\n\nint\t\tFS_Seek( fileHandle_t f, long offset, int origin );\n// seek on a file (doesn't work for zip files!!!!!!!!)\n\nqboolean FS_FilenameCompare( const char *s1, const char *s2 );\n\nconst char *FS_GamePureChecksum( void );\n// Returns the checksum of the pk3 from which the server loaded the qagame.qvm\n\nconst char *FS_LoadedPakNames( void );\nconst char *FS_LoadedPakChecksums( void );\nconst char *FS_LoadedPakPureChecksums( void );\n// Returns a space separated string containing the checksums of all loaded pk3 files.\n// Servers with sv_pure set will get this string and pass it to clients.\n\nconst char *FS_ReferencedPakNames( void );\nconst char *FS_ReferencedPakChecksums( void );\nconst char *FS_ReferencedPakPureChecksums( void );\n// Returns a space separated string containing the checksums of all loaded \n// AND referenced pk3 files. Servers with sv_pure set will get this string \n// back from clients for pure validation \n\nvoid FS_ClearPakReferences( int flags );\n// clears referenced booleans on loaded pk3s\n\nvoid FS_PureServerSetReferencedPaks( const char *pakSums, const char *pakNames );\nvoid FS_PureServerSetLoadedPaks( const char *pakSums, const char *pakNames );\n// If the string is empty, all data sources will be allowed.\n// If not empty, only pk3 files that match one of the space\n// separated checksums will be checked for files, with the\n// sole exception of .cfg files.\n\nqboolean FS_idPak( char *pak, char *base );\nqboolean FS_ComparePaks( char *neededpaks, int len, qboolean dlstring );\n\nvoid FS_Rename( const char *from, const char *to );\n\n/*\n==============================================================\n\nEdit fields and command line history/completion\n\n==============================================================\n*/\n\n#define\tMAX_EDIT_LINE\t256\ntypedef struct {\n\tint\t\tcursor;\n\tint\t\tscroll;\n\tint\t\twidthInChars;\n\tchar\tbuffer[MAX_EDIT_LINE];\n} field_t;\n\nvoid Field_Clear( field_t *edit );\nvoid Field_CompleteCommand( field_t *edit );\n\n/*\n==============================================================\n\nMISC\n\n==============================================================\n*/\n\n// TTimo\n// vsnprintf is ISO/IEC 9899:1999\n// abstracting this to make it portable\n#ifdef WIN32\n#define Q_vsnprintf _vsnprintf\n#else\n// TODO: do we need Mac define?\n#define Q_vsnprintf vsnprintf\n#endif\n\n// centralizing the declarations for cl_cdkey\n// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=470\nextern char cl_cdkey[34];\n\n// returnbed by Sys_GetProcessorId\n#define CPUID_GENERIC\t\t\t0\t\t\t// any unrecognized processor\n\n// TTimo\n// centralized and cleaned, that's the max string you can send to a Com_Printf / Com_DPrintf (above gets truncated)\n#define\tMAXPRINTMSG\t4096\n\nchar\t\t*CopyString( const char *in );\nvoid\t\tInfo_Print( const char *s );\n\nvoid\t\tCom_BeginRedirect (char *buffer, int buffersize, void (*flush)(char *));\nvoid\t\tCom_EndRedirect( void );\nvoid \t\tQDECL Com_Printf( const char *fmt, ... );\nvoid \t\tQDECL Com_DPrintf( const char *fmt, ... );\nvoid \t\tQDECL Com_Error( int code, const char *fmt, ... );\nvoid \t\tCom_Quit_f( void );\nint\t\t\tCom_EventLoop( void );\nint\t\t\tCom_Milliseconds( void );\t// will be journaled properly\nunsigned\tCom_BlockChecksum( const void *buffer, int length );\nunsigned\tCom_BlockChecksumKey (void *buffer, int length, int key);\nint\t\t\tCom_HashKey(char *string, int maxlen);\nint\t\t\tCom_Filter(char *filter, char *name, int casesensitive);\nint\t\t\tCom_FilterPath(char *filter, char *name, int casesensitive);\nint\t\t\tCom_RealTime(qtime_t *qtime);\nqboolean\tCom_SafeMode( void );\n\nvoid\t\tCom_StartupVariable( const char *match );\n// checks for and removes command line \"+set var arg\" constructs\n// if match is NULL, all set commands will be executed, otherwise\n// only a set with the exact name.  Only used during startup.\n\n\nextern\tcvar_t\t*com_developer;\nextern\tcvar_t\t*com_dedicated;\nextern\tcvar_t\t*com_speeds;\nextern\tcvar_t\t*com_timescale;\nextern\tcvar_t\t*com_sv_running;\nextern\tcvar_t\t*com_cl_running;\nextern\tcvar_t\t*com_viewlog;\t\t\t// 0 = hidden, 1 = visible, 2 = minimized\nextern\tcvar_t\t*com_version;\nextern\tcvar_t\t*com_blood;\nextern\tcvar_t\t*com_buildScript;\t\t// for building release pak files\nextern\tcvar_t\t*com_journal;\nextern\tcvar_t\t*com_cameraMode;\n\n// both client and server must agree to pause\nextern\tcvar_t\t*cl_paused;\nextern\tcvar_t\t*sv_paused;\n\n// com_speeds times\nextern\tint\t\ttime_game;\nextern\tint\t\ttime_frontend;\nextern\tint\t\ttime_backend;\t\t// renderer backend time\n\nextern\tint\t\tcom_frameTime;\nextern\tint\t\tcom_frameMsec;\n\nextern\tqboolean\tcom_errorEntered;\n\nextern\tfileHandle_t\tcom_journalFile;\nextern\tfileHandle_t\tcom_journalDataFile;\n\ntypedef enum {\n\tTAG_FREE,\n\tTAG_GENERAL,\n\tTAG_BOTLIB,\n\tTAG_RENDERER,\n\tTAG_SMALL,\n\tTAG_STATIC\n} memtag_t;\n\n/*\n\n--- low memory ----\nserver vm\nserver clipmap\n---mark---\nrenderer initialization (shaders, etc)\nUI vm\ncgame vm\nrenderer map\nrenderer models\n\n---free---\n\ntemp file loading\n--- high memory ---\n\n*/\n\n#if defined(_DEBUG) && !defined(BSPC)\n\t#define ZONE_DEBUG\n#endif\n\n#ifdef ZONE_DEBUG\n#define Z_TagMalloc(size, tag)\t\t\tZ_TagMallocDebug(size, tag, #size, __FILE__, __LINE__)\n#define Z_Malloc(size)\t\t\t\t\tZ_MallocDebug(size, #size, __FILE__, __LINE__)\n#define S_Malloc(size)\t\t\t\t\tS_MallocDebug(size, #size, __FILE__, __LINE__)\nvoid *Z_TagMallocDebug( int size, int tag, char *label, char *file, int line );\t// NOT 0 filled memory\nvoid *Z_MallocDebug( int size, char *label, char *file, int line );\t\t\t// returns 0 filled memory\nvoid *S_MallocDebug( int size, char *label, char *file, int line );\t\t\t// returns 0 filled memory\n#else\nvoid *Z_TagMalloc( int size, int tag );\t// NOT 0 filled memory\nvoid *Z_Malloc( int size );\t\t\t// returns 0 filled memory\nvoid *S_Malloc( int size );\t\t\t// NOT 0 filled memory only for small allocations\n#endif\nvoid Z_Free( void *ptr );\nvoid Z_FreeTags( int tag );\nint Z_AvailableMemory( void );\nvoid Z_LogHeap( void );\n\nvoid Hunk_Clear( void );\nvoid Hunk_ClearToMark( void );\nvoid Hunk_SetMark( void );\nqboolean Hunk_CheckMark( void );\nvoid Hunk_ClearTempMemory( void );\nvoid *Hunk_AllocateTempMemory( int size );\nvoid Hunk_FreeTempMemory( void *buf );\nint\tHunk_MemoryRemaining( void );\nvoid Hunk_Log( void);\nvoid Hunk_Trash( void );\n\nvoid Com_TouchMemory( void );\n\n// commandLine should not include the executable name (argv[0])\nvoid Com_Init( char *commandLine );\nvoid Com_Frame( void );\nvoid Com_Shutdown( void );\n\n\n/*\n==============================================================\n\nCLIENT / SERVER SYSTEMS\n\n==============================================================\n*/\n\n//\n// client interface\n//\nvoid CL_InitKeyCommands( void );\n// the keyboard binding interface must be setup before execing\n// config files, but the rest of client startup will happen later\n\nvoid CL_Init( void );\nvoid CL_Disconnect( qboolean showMainMenu );\nvoid CL_Shutdown( void );\nvoid CL_Frame( int msec );\nqboolean CL_GameCommand( void );\nvoid CL_KeyEvent (int key, qboolean down, unsigned time);\n\nvoid CL_CharEvent( int key );\n// char events are for field typing, not game control\n\nvoid CL_MouseEvent( int dx, int dy, int time );\n\nvoid CL_JoystickEvent( int axis, int value, int time );\n\nvoid CL_PacketEvent( netadr_t from, msg_t *msg );\n\nvoid CL_ConsolePrint( char *text );\n\nvoid CL_MapLoading( void );\n// do a screen update before starting to load a map\n// when the server is going to load a new map, the entire hunk\n// will be cleared, so the client must shutdown cgame, ui, and\n// the renderer\n\nvoid\tCL_ForwardCommandToServer( const char *string );\n// adds the current command line as a clc_clientCommand to the client message.\n// things like godmode, noclip, etc, are commands directed to the server,\n// so when they are typed in at the console, they will need to be forwarded.\n\nvoid CL_CDDialog( void );\n// bring up the \"need a cd to play\" dialog\n\nvoid CL_ShutdownAll( void );\n// shutdown all the client stuff\n\nvoid CL_FlushMemory( void );\n// dump all memory on an error\n\nvoid CL_StartHunkUsers( void );\n// start all the client stuff using the hunk\n\nvoid Key_WriteBindings( fileHandle_t f );\n// for writing the config files\n\nvoid S_ClearSoundBuffer( void );\n// call before filesystem access\n\nvoid SCR_DebugGraph (float value, int color);\t// FIXME: move logging to common?\n\n\n//\n// server interface\n//\nvoid SV_Init( void );\nvoid SV_Shutdown( char *finalmsg );\nvoid SV_Frame( int msec );\nvoid SV_PacketEvent( netadr_t from, msg_t *msg );\nqboolean SV_GameCommand( void );\n\n\n//\n// UI interface\n//\nqboolean UI_GameCommand( void );\nqboolean UI_usesUniqueCDKey();\n\n/*\n==============================================================\n\nNON-PORTABLE SYSTEM SERVICES\n\n==============================================================\n*/\n\ntypedef enum {\n\tAXIS_SIDE,\n\tAXIS_FORWARD,\n\tAXIS_UP,\n\tAXIS_ROLL,\n\tAXIS_YAW,\n\tAXIS_PITCH,\n\tMAX_JOYSTICK_AXIS\n} joystickAxis_t;\n\ntypedef enum {\n  // bk001129 - make sure SE_NONE is zero\n\tSE_NONE = 0,\t// evTime is still valid\n\tSE_KEY,\t\t// evValue is a key code, evValue2 is the down flag\n\tSE_CHAR,\t// evValue is an ascii char\n\tSE_MOUSE,\t// evValue and evValue2 are reletive signed x / y moves\n\tSE_JOYSTICK_AXIS,\t// evValue is an axis number and evValue2 is the current state (-127 to 127)\n\tSE_CONSOLE,\t// evPtr is a char*\n\tSE_PACKET\t// evPtr is a netadr_t followed by data bytes to evPtrLength\n} sysEventType_t;\n\ntypedef struct {\n\tint\t\t\t\tevTime;\n\tsysEventType_t\tevType;\n\tint\t\t\t\tevValue, evValue2;\n\tint\t\t\t\tevPtrLength;\t// bytes of data pointed to by evPtr, for journaling\n\tvoid\t\t\t*evPtr;\t\t\t// this must be manually freed if not NULL\n} sysEvent_t;\n\nsysEvent_t\tSys_GetEvent( void );\n\nvoid\tSys_Init (void);\n\n// general development dll loading for virtual machine testing\n// fqpath param added 7/20/02 by T.Ray - Sys_LoadDll is only called in vm.c at this time\nvoid\t* QDECL Sys_LoadDll( const char *name, char *fqpath , intptr_t (QDECL **entryPoint)(int, ...),\n\t\t\t\t  intptr_t (QDECL *systemcalls)(intptr_t, ...) );\nvoid\tSys_UnloadDll( void *dllHandle );\n\nvoid\tSys_UnloadGame( void );\nvoid\t*Sys_GetGameAPI( void *parms );\n\nvoid\tSys_UnloadCGame( void );\nvoid\t*Sys_GetCGameAPI( void );\n\nvoid\tSys_UnloadUI( void );\nvoid\t*Sys_GetUIAPI( void );\n\n//bot libraries\nvoid\tSys_UnloadBotLib( void );\nvoid\t*Sys_GetBotLibAPI( void *parms );\n\nchar\t*Sys_GetCurrentUser( void );\n\nvoid\tQDECL Sys_Error( const char *error, ...);\nvoid\tSys_Quit (void);\nchar\t*Sys_GetClipboardData( void );\t// note that this isn't journaled...\n\nvoid\tSys_Print( const char *msg );\n\n// Sys_Milliseconds should only be used for profiling purposes,\n// any game related timing information should come from event timestamps\nint\t\tSys_Milliseconds (void);\n\nvoid\tSys_SnapVector( float *v );\n\n// the system console is shown when a dedicated server is running\nvoid\tSys_DisplaySystemConsole( qboolean show );\n\nint\t\tSys_GetProcessorId( void );\n\nvoid\tSys_BeginStreamedFile( fileHandle_t f, int readahead );\nvoid\tSys_EndStreamedFile( fileHandle_t f );\nint\t\tSys_StreamedRead( void *buffer, int size, int count, fileHandle_t f );\nvoid\tSys_StreamSeek( fileHandle_t f, int offset, int origin );\n\nvoid\tSys_ShowConsole( int level, qboolean quitOnClose );\nvoid\tSys_SetErrorText( const char *text );\n\nvoid\tSys_SendPacket( int length, const void *data, netadr_t to );\n\nqboolean\tSys_StringToAdr( const char *s, netadr_t *a );\n//Does NOT parse port numbers, only base addresses.\n\nqboolean\tSys_IsLANAddress (netadr_t adr);\nvoid\t\tSys_ShowIP(void);\n\nqboolean\tSys_CheckCD( void );\n\nvoid\tSys_Mkdir( const char *path );\nchar\t*Sys_Cwd( void );\nvoid\tSys_SetDefaultCDPath(const char *path);\nchar\t*Sys_DefaultCDPath(void);\nvoid\tSys_SetDefaultInstallPath(const char *path);\nchar\t*Sys_DefaultInstallPath(void);\nvoid  Sys_SetDefaultHomePath(const char *path);\nchar\t*Sys_DefaultHomePath(void);\n\nchar **Sys_ListFiles( const char *directory, const char *extension, char *filter, int *numfiles, qboolean wantsubs );\nvoid\tSys_FreeFileList( char **list );\n\nvoid\tSys_BeginProfiling( void );\nvoid\tSys_EndProfiling( void );\n\nqboolean Sys_LowPhysicalMemory();\nunsigned int Sys_ProcessorCount();\n\nint Sys_MonkeyShouldBeSpanked( void );\n\n/* This is based on the Adaptive Huffman algorithm described in Sayood's Data\n * Compression book.  The ranks are not actually stored, but implicitly defined\n * by the location of a node within a doubly-linked list */\n\n#define NYT HMAX\t\t\t\t\t/* NYT = Not Yet Transmitted */\n#define INTERNAL_NODE (HMAX+1)\n\ntypedef struct nodetype {\n\tstruct\tnodetype *left, *right, *parent; /* tree structure */ \n\tstruct\tnodetype *next, *prev; /* doubly-linked list */\n\tstruct\tnodetype **head; /* highest ranked node in block */\n\tint\t\tweight;\n\tint\t\tsymbol;\n} node_t;\n\n#define HMAX 256 /* Maximum symbol */\n\ntypedef struct {\n\tint\t\t\tblocNode;\n\tint\t\t\tblocPtrs;\n\n\tnode_t*\t\ttree;\n\tnode_t*\t\tlhead;\n\tnode_t*\t\tltail;\n\tnode_t*\t\tloc[HMAX+1];\n\tnode_t**\tfreelist;\n\n\tnode_t\t\tnodeList[768];\n\tnode_t*\t\tnodePtrs[768];\n} huff_t;\n\ntypedef struct {\n\thuff_t\t\tcompressor;\n\thuff_t\t\tdecompressor;\n} huffman_t;\n\nvoid\tHuff_Compress(msg_t *buf, int offset);\nvoid\tHuff_Decompress(msg_t *buf, int offset);\nvoid\tHuff_Init(huffman_t *huff);\nvoid\tHuff_addRef(huff_t* huff, byte ch);\nint\t\tHuff_Receive (node_t *node, int *ch, byte *fin);\nvoid\tHuff_transmit (huff_t *huff, int ch, byte *fout);\nvoid\tHuff_offsetReceive (node_t *node, int *ch, byte *fin, int *offset);\nvoid\tHuff_offsetTransmit (huff_t *huff, int ch, byte *fout, int *offset);\nvoid\tHuff_putBit( int bit, byte *fout, int *offset);\nint\t\tHuff_getBit( byte *fout, int *offset);\n\nextern huffman_t clientHuffTables;\n\n#define\tSV_ENCODE_START\t\t4\n#define SV_DECODE_START\t\t12\n#define\tCL_ENCODE_START\t\t12\n#define CL_DECODE_START\t\t4\n\n#endif // _QCOMMON_H_\n"
  },
  {
    "path": "src/engine/qcommon/qfiles.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n#ifndef __QFILES_H__\n#define __QFILES_H__\n\n//\n// qfiles.h: quake file formats\n// This file must be identical in the quake and utils directories\n//\n\n// surface geometry should not exceed these limits\n#define\tSHADER_MAX_VERTEXES\t1000\n#define\tSHADER_MAX_INDEXES\t(6*SHADER_MAX_VERTEXES)\n\n\n// the maximum size of game relative pathnames\n#define\tMAX_QPATH\t\t64\n\n/*\n========================================================================\n\nQVM files\n\n========================================================================\n*/\n\n#define\tVM_MAGIC\t0x12721444\ntypedef struct {\n\tint\t\tvmMagic;\n\n\tint\t\tinstructionCount;\n\n\tint\t\tcodeOffset;\n\tint\t\tcodeLength;\n\n\tint\t\tdataOffset;\n\tint\t\tdataLength;\n\tint\t\tlitLength;\t\t\t// ( dataLength - litLength ) should be byteswapped on load\n\tint\t\tbssLength;\t\t\t// zero filled memory appended to datalength\n} vmHeader_t;\n\n\n/*\n========================================================================\n\nPCX files are used for 8 bit images\n\n========================================================================\n*/\n\ntypedef struct {\n    char\tmanufacturer;\n    char\tversion;\n    char\tencoding;\n    char\tbits_per_pixel;\n    unsigned short\txmin,ymin,xmax,ymax;\n    unsigned short\thres,vres;\n    unsigned char\tpalette[48];\n    char\treserved;\n    char\tcolor_planes;\n    unsigned short\tbytes_per_line;\n    unsigned short\tpalette_type;\n    char\tfiller[58];\n    unsigned char\tdata;\t\t\t// unbounded\n} pcx_t;\n\n\n/*\n========================================================================\n\nTGA files are used for 24/32 bit images\n\n========================================================================\n*/\n\ntypedef struct _TargaHeader {\n\tunsigned char \tid_length, colormap_type, image_type;\n\tunsigned short\tcolormap_index, colormap_length;\n\tunsigned char\tcolormap_size;\n\tunsigned short\tx_origin, y_origin, width, height;\n\tunsigned char\tpixel_size, attributes;\n} TargaHeader;\n\n\n\n/*\n========================================================================\n\n.MD3 triangle model file format\n\n========================================================================\n*/\n\n#define MD3_IDENT\t\t\t(('3'<<24)+('P'<<16)+('D'<<8)+'I')\n#define MD3_VERSION\t\t\t15\n\n// limits\n#define MD3_MAX_LODS\t\t3\n#define\tMD3_MAX_TRIANGLES\t8192\t// per surface\n#define MD3_MAX_VERTS\t\t4096\t// per surface\n#define MD3_MAX_SHADERS\t\t256\t\t// per surface\n#define MD3_MAX_FRAMES\t\t1024\t// per model\n#define\tMD3_MAX_SURFACES\t32\t\t// per model\n#define MD3_MAX_TAGS\t\t16\t\t// per frame\n\n// vertex scales\n#define\tMD3_XYZ_SCALE\t\t(1.0/64)\n\ntypedef struct md3Frame_s {\n\tvec3_t\t\tbounds[2];\n\tvec3_t\t\tlocalOrigin;\n\tfloat\t\tradius;\n\tchar\t\tname[16];\n} md3Frame_t;\n\ntypedef struct md3Tag_s {\n\tchar\t\tname[MAX_QPATH];\t// tag name\n\tvec3_t\t\torigin;\n\tvec3_t\t\taxis[3];\n} md3Tag_t;\n\n/*\n** md3Surface_t\n**\n** CHUNK\t\t\tSIZE\n** header\t\t\tsizeof( md3Surface_t )\n** shaders\t\t\tsizeof( md3Shader_t ) * numShaders\n** triangles[0]\t\tsizeof( md3Triangle_t ) * numTriangles\n** st\t\t\t\tsizeof( md3St_t ) * numVerts\n** XyzNormals\t\tsizeof( md3XyzNormal_t ) * numVerts * numFrames\n*/\ntypedef struct {\n\tint\t\tident;\t\t\t\t// \n\n\tchar\tname[MAX_QPATH];\t// polyset name\n\n\tint\t\tflags;\n\tint\t\tnumFrames;\t\t\t// all surfaces in a model should have the same\n\n\tint\t\tnumShaders;\t\t\t// all surfaces in a model should have the same\n\tint\t\tnumVerts;\n\n\tint\t\tnumTriangles;\n\tint\t\tofsTriangles;\n\n\tint\t\tofsShaders;\t\t\t// offset from start of md3Surface_t\n\tint\t\tofsSt;\t\t\t\t// texture coords are common for all frames\n\tint\t\tofsXyzNormals;\t\t// numVerts * numFrames\n\n\tint\t\tofsEnd;\t\t\t\t// next surface follows\n} md3Surface_t;\n\ntypedef struct {\n\tchar\t\t\tname[MAX_QPATH];\n\tint\t\t\t\tshaderIndex;\t// for in-game use\n} md3Shader_t;\n\ntypedef struct {\n\tint\t\t\tindexes[3];\n} md3Triangle_t;\n\ntypedef struct {\n\tfloat\t\tst[2];\n} md3St_t;\n\ntypedef struct {\n\tshort\t\txyz[3];\n\tshort\t\tnormal;\n} md3XyzNormal_t;\n\ntypedef struct {\n\tint\t\t\tident;\n\tint\t\t\tversion;\n\n\tchar\t\tname[MAX_QPATH];\t// model name\n\n\tint\t\t\tflags;\n\n\tint\t\t\tnumFrames;\n\tint\t\t\tnumTags;\t\t\t\n\tint\t\t\tnumSurfaces;\n\n\tint\t\t\tnumSkins;\n\n\tint\t\t\tofsFrames;\t\t\t// offset for first frame\n\tint\t\t\tofsTags;\t\t\t// numFrames * numTags\n\tint\t\t\tofsSurfaces;\t\t// first surface, others follow\n\n\tint\t\t\tofsEnd;\t\t\t\t// end of file\n} md3Header_t;\n\n/*\n==============================================================================\n\nMD4 file format\n\n==============================================================================\n*/\n\n#define MD4_IDENT\t\t\t(('4'<<24)+('P'<<16)+('D'<<8)+'I')\n#define MD4_VERSION\t\t\t1\n#define\tMD4_MAX_BONES\t\t128\n\ntypedef struct {\n\tint\t\t\tboneIndex;\t\t// these are indexes into the boneReferences,\n\tfloat\t\t   boneWeight;\t\t// not the global per-frame bone list\n\tvec3_t\t\toffset;\n} md4Weight_t;\n\ntypedef struct {\n\tvec3_t\t\tnormal;\n\tvec2_t\t\ttexCoords;\n\tint\t\t\tnumWeights;\n\tmd4Weight_t\tweights[1];\t\t// variable sized\n} md4Vertex_t;\n\ntypedef struct {\n\tint\t\t\tindexes[3];\n} md4Triangle_t;\n\ntypedef struct {\n\tint\t\t\tident;\n\n\tchar\t\tname[MAX_QPATH];\t// polyset name\n\tchar\t\tshader[MAX_QPATH];\n\tint\t\t\tshaderIndex;\t\t// for in-game use\n\n\tint\t\t\tofsHeader;\t\t\t// this will be a negative number\n\n\tint\t\t\tnumVerts;\n\tint\t\t\tofsVerts;\n\n\tint\t\t\tnumTriangles;\n\tint\t\t\tofsTriangles;\n\n\t// Bone references are a set of ints representing all the bones\n\t// present in any vertex weights for this surface.  This is\n\t// needed because a model may have surfaces that need to be\n\t// drawn at different sort times, and we don't want to have\n\t// to re-interpolate all the bones for each surface.\n\tint\t\t\tnumBoneReferences;\n\tint\t\t\tofsBoneReferences;\n\n\tint\t\t\tofsEnd;\t\t\t\t// next surface follows\n} md4Surface_t;\n\ntypedef struct {\n\tfloat\t\tmatrix[3][4];\n} md4Bone_t;\n\ntypedef struct {\n\tvec3_t\t\tbounds[2];\t\t\t// bounds of all surfaces of all LOD's for this frame\n\tvec3_t\t\tlocalOrigin;\t\t// midpoint of bounds, used for sphere cull\n\tfloat\t\tradius;\t\t\t\t// dist from localOrigin to corner\n\tmd4Bone_t\tbones[1];\t\t\t// [numBones]\n} md4Frame_t;\n\ntypedef struct {\n\tint\t\t\tnumSurfaces;\n\tint\t\t\tofsSurfaces;\t\t// first surface, others follow\n\tint\t\t\tofsEnd;\t\t\t\t// next lod follows\n} md4LOD_t;\n\ntypedef struct {\n\tint\t\t\tident;\n\tint\t\t\tversion;\n\n\tchar\t\tname[MAX_QPATH];\t// model name\n\n\t// frames and bones are shared by all levels of detail\n\tint\t\t\tnumFrames;\n\tint\t\t\tnumBones;\n\tint\t\t\tofsBoneNames;\t\t// char\tname[ MAX_QPATH ]\n\tint\t\t\tofsFrames;\t\t\t// md4Frame_t[numFrames]\n\n\t// each level of detail has completely separate sets of surfaces\n\tint\t\t\tnumLODs;\n\tint\t\t\tofsLODs;\n\n\tint\t\t\tofsEnd;\t\t\t\t// end of file\n} md4Header_t;\n\n\n/*\n==============================================================================\n\n  .BSP file format\n\n==============================================================================\n*/\n\n\n#define BSP_IDENT\t(('P'<<24)+('S'<<16)+('B'<<8)+'I')\n\t\t// little-endian \"IBSP\"\n\n#define BSP_VERSION\t\t\t46\n\n\n// there shouldn't be any problem with increasing these values at the\n// expense of more memory allocation in the utilities\n#define\tMAX_MAP_MODELS\t\t0x400\n#define\tMAX_MAP_BRUSHES\t\t0x8000\n#define\tMAX_MAP_ENTITIES\t0x800\n#define\tMAX_MAP_ENTSTRING\t0x40000\n#define\tMAX_MAP_SHADERS\t\t0x400\n\n#define\tMAX_MAP_AREAS\t\t0x100\t// MAX_MAP_AREA_BYTES in q_shared must match!\n#define\tMAX_MAP_FOGS\t\t0x100\n#define\tMAX_MAP_PLANES\t\t0x20000\n#define\tMAX_MAP_NODES\t\t0x20000\n#define\tMAX_MAP_BRUSHSIDES\t0x20000\n#define\tMAX_MAP_LEAFS\t\t0x20000\n#define\tMAX_MAP_LEAFFACES\t0x20000\n#define\tMAX_MAP_LEAFBRUSHES 0x40000\n#define\tMAX_MAP_PORTALS\t\t0x20000\n#define\tMAX_MAP_LIGHTING\t0x800000\n#define\tMAX_MAP_LIGHTGRID\t0x800000\n#define\tMAX_MAP_VISIBILITY\t0x200000\n\n#define\tMAX_MAP_DRAW_SURFS\t0x20000\n#define\tMAX_MAP_DRAW_VERTS\t0x80000\n#define\tMAX_MAP_DRAW_INDEXES\t0x80000\n\n\n// key / value pair sizes in the entities lump\n#define\tMAX_KEY\t\t\t\t32\n#define\tMAX_VALUE\t\t\t1024\n\n// the editor uses these predefined yaw angles to orient entities up or down\n#define\tANGLE_UP\t\t\t-1\n#define\tANGLE_DOWN\t\t\t-2\n\n#define\tLIGHTMAP_WIDTH\t\t128\n#define\tLIGHTMAP_HEIGHT\t\t128\n\n#define MAX_WORLD_COORD\t\t( 128*1024 )\n#define MIN_WORLD_COORD\t\t( -128*1024 )\n#define WORLD_SIZE\t\t\t( MAX_WORLD_COORD - MIN_WORLD_COORD )\n\n//=============================================================================\n\n\ntypedef struct {\n\tint\t\tfileofs, filelen;\n} lump_t;\n\n#define\tLUMP_ENTITIES\t\t0\n#define\tLUMP_SHADERS\t\t1\n#define\tLUMP_PLANES\t\t\t2\n#define\tLUMP_NODES\t\t\t3\n#define\tLUMP_LEAFS\t\t\t4\n#define\tLUMP_LEAFSURFACES\t5\n#define\tLUMP_LEAFBRUSHES\t6\n#define\tLUMP_MODELS\t\t\t7\n#define\tLUMP_BRUSHES\t\t8\n#define\tLUMP_BRUSHSIDES\t\t9\n#define\tLUMP_DRAWVERTS\t\t10\n#define\tLUMP_DRAWINDEXES\t11\n#define\tLUMP_FOGS\t\t\t12\n#define\tLUMP_SURFACES\t\t13\n#define\tLUMP_LIGHTMAPS\t\t14\n#define\tLUMP_LIGHTGRID\t\t15\n#define\tLUMP_VISIBILITY\t\t16\n#define\tHEADER_LUMPS\t\t17\n\ntypedef struct {\n\tint\t\t\tident;\n\tint\t\t\tversion;\n\n\tlump_t\t\tlumps[HEADER_LUMPS];\n} dheader_t;\n\ntypedef struct {\n\tfloat\t\tmins[3], maxs[3];\n\tint\t\t\tfirstSurface, numSurfaces;\n\tint\t\t\tfirstBrush, numBrushes;\n} dmodel_t;\n\ntypedef struct {\n\tchar\t\tshader[MAX_QPATH];\n\tint\t\t\tsurfaceFlags;\n\tint\t\t\tcontentFlags;\n} dshader_t;\n\n// planes x^1 is allways the opposite of plane x\n\ntypedef struct {\n\tfloat\t\tnormal[3];\n\tfloat\t\tdist;\n} dplane_t;\n\ntypedef struct {\n\tint\t\t\tplaneNum;\n\tint\t\t\tchildren[2];\t// negative numbers are -(leafs+1), not nodes\n\tint\t\t\tmins[3];\t\t// for frustom culling\n\tint\t\t\tmaxs[3];\n} dnode_t;\n\ntypedef struct {\n\tint\t\t\tcluster;\t\t\t// -1 = opaque cluster (do I still store these?)\n\tint\t\t\tarea;\n\n\tint\t\t\tmins[3];\t\t\t// for frustum culling\n\tint\t\t\tmaxs[3];\n\n\tint\t\t\tfirstLeafSurface;\n\tint\t\t\tnumLeafSurfaces;\n\n\tint\t\t\tfirstLeafBrush;\n\tint\t\t\tnumLeafBrushes;\n} dleaf_t;\n\ntypedef struct {\n\tint\t\t\tplaneNum;\t\t\t// positive plane side faces out of the leaf\n\tint\t\t\tshaderNum;\n} dbrushside_t;\n\ntypedef struct {\n\tint\t\t\tfirstSide;\n\tint\t\t\tnumSides;\n\tint\t\t\tshaderNum;\t\t// the shader that determines the contents flags\n} dbrush_t;\n\ntypedef struct {\n\tchar\t\tshader[MAX_QPATH];\n\tint\t\t\tbrushNum;\n\tint\t\t\tvisibleSide;\t// the brush side that ray tests need to clip against (-1 == none)\n} dfog_t;\n\ntypedef struct {\n\tvec3_t\t\txyz;\n\tfloat\t\tst[2];\n\tfloat\t\tlightmap[2];\n\tvec3_t\t\tnormal;\n\tbyte\t\tcolor[4];\n} drawVert_t;\n\ntypedef enum {\n\tMST_BAD,\n\tMST_PLANAR,\n\tMST_PATCH,\n\tMST_TRIANGLE_SOUP,\n\tMST_FLARE\n} mapSurfaceType_t;\n\ntypedef struct {\n\tint\t\t\tshaderNum;\n\tint\t\t\tfogNum;\n\tint\t\t\tsurfaceType;\n\n\tint\t\t\tfirstVert;\n\tint\t\t\tnumVerts;\n\n\tint\t\t\tfirstIndex;\n\tint\t\t\tnumIndexes;\n\n\tint\t\t\tlightmapNum;\n\tint\t\t\tlightmapX, lightmapY;\n\tint\t\t\tlightmapWidth, lightmapHeight;\n\n\tvec3_t\t\tlightmapOrigin;\n\tvec3_t\t\tlightmapVecs[3];\t// for patches, [0] and [1] are lodbounds\n\n\tint\t\t\tpatchWidth;\n\tint\t\t\tpatchHeight;\n} dsurface_t;\n\n\n#endif\n"
  },
  {
    "path": "src/engine/qcommon/unzip.c",
    "content": "/*****************************************************************************\n * name:\t\tunzip.c\n *\n * desc:\t\tIO on .zip files using portions of zlib \n *\n * $Archive: /MissionPack/code/qcommon/unzip.c $\n *\n *****************************************************************************/\n\n#include \"../client/client.h\"\n#include \"unzip.h\"\n\n/* unzip.h -- IO for uncompress .zip files using zlib \n   Version 0.15 beta, Mar 19th, 1998,\n\n   Copyright (C) 1998 Gilles Vollant\n\n   This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g\n     WinZip, InfoZip tools and compatible.\n   Encryption and multi volume ZipFile (span) are not supported.\n   Old compressions used by old PKZip 1.x are not supported\n\n   THIS IS AN ALPHA VERSION. AT THIS STAGE OF DEVELOPPEMENT, SOMES API OR STRUCTURE\n   CAN CHANGE IN FUTURE VERSION !!\n   I WAIT FEEDBACK at mail info@winimage.com\n   Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution\n\n   Condition of use and distribution are the same than zlib :\n\n  This software is provided 'as-is', without any express or implied\n  warranty.  In no event will the authors be held liable for any damages\n  arising from the use of this software.\n\n  Permission is granted to anyone to use this software for any purpose,\n  including commercial applications, and to alter it and redistribute it\n  freely, subject to the following restrictions:\n\n  1. The origin of this software must not be misrepresented; you must not\n     claim that you wrote the original software. If you use this software\n     in a product, an acknowledgment in the product documentation would be\n     appreciated but is not required.\n  2. Altered source versions must be plainly marked as such, and must not be\n     misrepresented as being the original software.\n  3. This notice may not be removed or altered from any source distribution.\n\n\n*/\n/* for more info about .ZIP format, see \n      ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip\n   PkWare has also a specification at :\n      ftp://ftp.pkware.com/probdesc.zip */\n\n/* zlib.h -- interface of the 'zlib' general purpose compression library\n  version 1.1.3, July 9th, 1998\n\n  Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler\n\n  This software is provided 'as-is', without any express or implied\n  warranty.  In no event will the authors be held liable for any damages\n  arising from the use of this software.\n\n  Permission is granted to anyone to use this software for any purpose,\n  including commercial applications, and to alter it and redistribute it\n  freely, subject to the following restrictions:\n\n  1. The origin of this software must not be misrepresented; you must not\n     claim that you wrote the original software. If you use this software\n     in a product, an acknowledgment in the product documentation would be\n     appreciated but is not required.\n  2. Altered source versions must be plainly marked as such, and must not be\n     misrepresented as being the original software.\n  3. This notice may not be removed or altered from any source distribution.\n\n  Jean-loup Gailly        Mark Adler\n  jloup@gzip.org          madler@alumni.caltech.edu\n\n\n  The data format used by the zlib library is described by RFCs (Request for\n  Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt\n  (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).\n*/\n\n/* zconf.h -- configuration of the zlib compression library\n * Copyright (C) 1995-1998 Jean-loup Gailly.\n * For conditions of distribution and use, see copyright notice in zlib.h \n */\n\n\n#ifndef _ZCONF_H\n#define _ZCONF_H\n\n/* Maximum value for memLevel in deflateInit2 */\n#ifndef MAX_MEM_LEVEL\n#  ifdef MAXSEG_64K\n#    define MAX_MEM_LEVEL 8\n#  else\n#    define MAX_MEM_LEVEL 9\n#  endif\n#endif\n\n/* Maximum value for windowBits in deflateInit2 and inflateInit2.\n * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files\n * created by gzip. (Files created by minigzip can still be extracted by\n * gzip.)\n */\n#ifndef MAX_WBITS\n#  define MAX_WBITS   15 /* 32K LZ77 window */\n#endif\n\n/* The memory requirements for deflate are (in bytes):\n            (1 << (windowBits+2)) +  (1 << (memLevel+9))\n that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)\n plus a few kilobytes for small objects. For example, if you want to reduce\n the default memory requirements from 256K to 128K, compile with\n     make CFLAGS=\"-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7\"\n Of course this will generally degrade compression (there's no free lunch).\n\n   The memory requirements for inflate are (in bytes) 1 << windowBits\n that is, 32K for windowBits=15 (default value) plus a few kilobytes\n for small objects.\n*/\n\n                        /* Type declarations */\n\n#ifndef OF /* function prototypes */\n#define OF(args)  args\n#endif\n\ntypedef unsigned char  Byte;  /* 8 bits */\ntypedef unsigned int   uInt;  /* 16 bits or more */\ntypedef unsigned long  uLong; /* 32 bits or more */\ntypedef Byte    *voidp;\n\n#ifndef SEEK_SET\n#  define SEEK_SET        0       /* Seek from beginning of file.  */\n#  define SEEK_CUR        1       /* Seek from current position.  */\n#  define SEEK_END        2       /* Set file pointer to EOF plus \"offset\" */\n#endif\n\n#endif /* _ZCONF_H */\n\n#define ZLIB_VERSION \"1.1.3\"\n\n/* \n     The 'zlib' compression library provides in-memory compression and\n  decompression functions, including integrity checks of the uncompressed\n  data.  This version of the library supports only one compression method\n  (deflation) but other algorithms will be added later and will have the same\n  stream interface.\n\n     Compression can be done in a single step if the buffers are large\n  enough (for example if an input file is mmap'ed), or can be done by\n  repeated calls of the compression function.  In the latter case, the\n  application must provide more input and/or consume the output\n  (providing more output space) before each call.\n\n     The library also supports reading and writing files in gzip (.gz) format\n  with an interface similar to that of stdio.\n\n     The library does not install any signal handler. The decoder checks\n  the consistency of the compressed data, so the library should never\n  crash even in case of corrupted input.\n*/\n\n/*\n   The application must update next_in and avail_in when avail_in has\n   dropped to zero. It must update next_out and avail_out when avail_out\n   has dropped to zero. The application must initialize zalloc, zfree and\n   opaque before calling the init function. All other fields are set by the\n   compression library and must not be updated by the application.\n\n   The opaque value provided by the application will be passed as the first\n   parameter for calls of zalloc and zfree. This can be useful for custom\n   memory management. The compression library attaches no meaning to the\n   opaque value.\n\n   zalloc must return Z_NULL if there is not enough memory for the object.\n   If zlib is used in a multi-threaded application, zalloc and zfree must be\n   thread safe.\n\n   On 16-bit systems, the functions zalloc and zfree must be able to allocate\n   exactly 65536 bytes, but will not be required to allocate more than this\n   if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,\n   pointers returned by zalloc for objects of exactly 65536 bytes *must*\n   have their offset normalized to zero. The default allocation function\n   provided by this library ensures this (see zutil.c). To reduce memory\n   requirements and avoid any allocation of 64K objects, at the expense of\n   compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).\n\n   The fields total_in and total_out can be used for statistics or\n   progress reports. After compression, total_in holds the total size of\n   the uncompressed data and may be saved for use in the decompressor\n   (particularly if the decompressor wants to decompress everything in\n   a single step).\n*/\n\n                        /* constants */\n\n#define Z_NO_FLUSH      0\n#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */\n#define Z_SYNC_FLUSH    2\n#define Z_FULL_FLUSH    3\n#define Z_FINISH        4\n/* Allowed flush values; see deflate() below for details */\n\n#define Z_OK            0\n#define Z_STREAM_END    1\n#define Z_NEED_DICT     2\n#define Z_ERRNO        (-1)\n#define Z_STREAM_ERROR (-2)\n#define Z_DATA_ERROR   (-3)\n#define Z_MEM_ERROR    (-4)\n#define Z_BUF_ERROR    (-5)\n#define Z_VERSION_ERROR (-6)\n/* Return codes for the compression/decompression functions. Negative\n * values are errors, positive values are used for special but normal events.\n */\n\n#define Z_NO_COMPRESSION         0\n#define Z_BEST_SPEED             1\n#define Z_BEST_COMPRESSION       9\n#define Z_DEFAULT_COMPRESSION  (-1)\n/* compression levels */\n\n#define Z_FILTERED            1\n#define Z_HUFFMAN_ONLY        2\n#define Z_DEFAULT_STRATEGY    0\n/* compression strategy; see deflateInit2() below for details */\n\n#define Z_BINARY   0\n#define Z_ASCII    1\n#define Z_UNKNOWN  2\n/* Possible values of the data_type field */\n\n#define Z_DEFLATED   8\n/* The deflate compression method (the only one supported in this version) */\n\n#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */\n\n#define zlib_version zlibVersion()\n/* for compatibility with versions < 1.0.2 */\n\n                        /* basic functions */\n\n// static const char * zlibVersion OF((void));\n/* The application can compare zlibVersion and ZLIB_VERSION for consistency.\n   If the first character differs, the library code actually used is\n   not compatible with the zlib.h header file used by the application.\n   This check is automatically made by deflateInit and inflateInit.\n */\n\n/* \nint deflateInit OF((z_streamp strm, int level));\n\n     Initializes the internal stream state for compression. The fields\n   zalloc, zfree and opaque must be initialized before by the caller.\n   If zalloc and zfree are set to Z_NULL, deflateInit updates them to\n   use default allocation functions.\n\n     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:\n   1 gives best speed, 9 gives best compression, 0 gives no compression at\n   all (the input data is simply copied a block at a time).\n   Z_DEFAULT_COMPRESSION requests a default compromise between speed and\n   compression (currently equivalent to level 6).\n\n     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not\n   enough memory, Z_STREAM_ERROR if level is not a valid compression level,\n   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible\n   with the version assumed by the caller (ZLIB_VERSION).\n   msg is set to null if there is no error message.  deflateInit does not\n   perform any compression: this will be done by deflate().\n*/\n\n\n// static int deflate OF((z_streamp strm, int flush));\n/*\n    deflate compresses as much data as possible, and stops when the input\n  buffer becomes empty or the output buffer becomes full. It may introduce some\n  output latency (reading input without producing any output) except when\n  forced to flush.\n\n    The detailed semantics are as follows. deflate performs one or both of the\n  following actions:\n\n  - Compress more input starting at next_in and update next_in and avail_in\n    accordingly. If not all input can be processed (because there is not\n    enough room in the output buffer), next_in and avail_in are updated and\n    processing will resume at this point for the next call of deflate().\n\n  - Provide more output starting at next_out and update next_out and avail_out\n    accordingly. This action is forced if the parameter flush is non zero.\n    Forcing flush frequently degrades the compression ratio, so this parameter\n    should be set only when necessary (in interactive applications).\n    Some output may be provided even if flush is not set.\n\n  Before the call of deflate(), the application should ensure that at least\n  one of the actions is possible, by providing more input and/or consuming\n  more output, and updating avail_in or avail_out accordingly; avail_out\n  should never be zero before the call. The application can consume the\n  compressed output when it wants, for example when the output buffer is full\n  (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK\n  and with zero avail_out, it must be called again after making room in the\n  output buffer because there might be more output pending.\n\n    If the parameter flush is set to Z_SYNC_FLUSH, all pending output is\n  flushed to the output buffer and the output is aligned on a byte boundary, so\n  that the decompressor can get all input data available so far. (In particular\n  avail_in is zero after the call if enough output space has been provided\n  before the call.)  Flushing may degrade compression for some compression\n  algorithms and so it should be used only when necessary.\n\n    If flush is set to Z_FULL_FLUSH, all output is flushed as with\n  Z_SYNC_FLUSH, and the compression state is reset so that decompression can\n  restart from this point if previous compressed data has been damaged or if\n  random access is desired. Using Z_FULL_FLUSH too often can seriously degrade\n  the compression.\n\n    If deflate returns with avail_out == 0, this function must be called again\n  with the same value of the flush parameter and more output space (updated\n  avail_out), until the flush is complete (deflate returns with non-zero\n  avail_out).\n\n    If the parameter flush is set to Z_FINISH, pending input is processed,\n  pending output is flushed and deflate returns with Z_STREAM_END if there\n  was enough output space; if deflate returns with Z_OK, this function must be\n  called again with Z_FINISH and more output space (updated avail_out) but no\n  more input data, until it returns with Z_STREAM_END or an error. After\n  deflate has returned Z_STREAM_END, the only possible operations on the\n  stream are deflateReset or deflateEnd.\n  \n    Z_FINISH can be used immediately after deflateInit if all the compression\n  is to be done in a single step. In this case, avail_out must be at least\n  0.1% larger than avail_in plus 12 bytes.  If deflate does not return\n  Z_STREAM_END, then it must be called again as described above.\n\n    deflate() sets strm->adler to the adler32 checksum of all input read\n  so (that is, total_in bytes).\n\n    deflate() may update data_type if it can make a good guess about\n  the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered\n  binary. This field is only for information purposes and does not affect\n  the compression algorithm in any manner.\n\n    deflate() returns Z_OK if some progress has been made (more input\n  processed or more output produced), Z_STREAM_END if all input has been\n  consumed and all output has been produced (only when flush is set to\n  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example\n  if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible\n  (for example avail_in or avail_out was zero).\n*/\n\n\n// static int deflateEnd OF((z_streamp strm));\n/*\n     All dynamically allocated data structures for this stream are freed.\n   This function discards any unprocessed input and does not flush any\n   pending output.\n\n     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the\n   stream state was inconsistent, Z_DATA_ERROR if the stream was freed\n   prematurely (some input or output was discarded). In the error case,\n   msg may be set but then points to a static string (which must not be\n   deallocated).\n*/\n\n\n/* \nint inflateInit OF((z_streamp strm));\n\n     Initializes the internal stream state for decompression. The fields\n   next_in, avail_in, zalloc, zfree and opaque must be initialized before by\n   the caller. If next_in is not Z_NULL and avail_in is large enough (the exact\n   value depends on the compression method), inflateInit determines the\n   compression method from the zlib header and allocates all data structures\n   accordingly; otherwise the allocation will be deferred to the first call of\n   inflate.  If zalloc and zfree are set to Z_NULL, inflateInit updates them to\n   use default allocation functions.\n\n     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough\n   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the\n   version assumed by the caller.  msg is set to null if there is no error\n   message. inflateInit does not perform any decompression apart from reading\n   the zlib header if present: this will be done by inflate().  (So next_in and\n   avail_in may be modified, but next_out and avail_out are unchanged.)\n*/\n\n\nstatic int inflate OF((z_streamp strm, int flush));\n/*\n    inflate decompresses as much data as possible, and stops when the input\n  buffer becomes empty or the output buffer becomes full. It may some\n  introduce some output latency (reading input without producing any output)\n  except when forced to flush.\n\n  The detailed semantics are as follows. inflate performs one or both of the\n  following actions:\n\n  - Decompress more input starting at next_in and update next_in and avail_in\n    accordingly. If not all input can be processed (because there is not\n    enough room in the output buffer), next_in is updated and processing\n    will resume at this point for the next call of inflate().\n\n  - Provide more output starting at next_out and update next_out and avail_out\n    accordingly.  inflate() provides as much output as possible, until there\n    is no more input data or no more space in the output buffer (see below\n    about the flush parameter).\n\n  Before the call of inflate(), the application should ensure that at least\n  one of the actions is possible, by providing more input and/or consuming\n  more output, and updating the next_* and avail_* values accordingly.\n  The application can consume the uncompressed output when it wants, for\n  example when the output buffer is full (avail_out == 0), or after each\n  call of inflate(). If inflate returns Z_OK and with zero avail_out, it\n  must be called again after making room in the output buffer because there\n  might be more output pending.\n\n    If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much\n  output as possible to the output buffer. The flushing behavior of inflate is\n  not specified for values of the flush parameter other than Z_SYNC_FLUSH\n  and Z_FINISH, but the current implementation actually flushes as much output\n  as possible anyway.\n\n    inflate() should normally be called until it returns Z_STREAM_END or an\n  error. However if all decompression is to be performed in a single step\n  (a single call of inflate), the parameter flush should be set to\n  Z_FINISH. In this case all pending input is processed and all pending\n  output is flushed; avail_out must be large enough to hold all the\n  uncompressed data. (The size of the uncompressed data may have been saved\n  by the compressor for this purpose.) The next operation on this stream must\n  be inflateEnd to deallocate the decompression state. The use of Z_FINISH\n  is never required, but can be used to inform inflate that a faster routine\n  may be used for the single inflate() call.\n\n     If a preset dictionary is needed at this point (see inflateSetDictionary\n  below), inflate sets strm-adler to the adler32 checksum of the\n  dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise \n  it sets strm->adler to the adler32 checksum of all output produced\n  so (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or\n  an error code as described below. At the end of the stream, inflate()\n  checks that its computed adler32 checksum is equal to that saved by the\n  compressor and returns Z_STREAM_END only if the checksum is correct.\n\n    inflate() returns Z_OK if some progress has been made (more input processed\n  or more output produced), Z_STREAM_END if the end of the compressed data has\n  been reached and all uncompressed output has been produced, Z_NEED_DICT if a\n  preset dictionary is needed at this point, Z_DATA_ERROR if the input data was\n  corrupted (input stream not conforming to the zlib format or incorrect\n  adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent\n  (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not\n  enough memory, Z_BUF_ERROR if no progress is possible or if there was not\n  enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR\n  case, the application may then call inflateSync to look for a good\n  compression block.\n*/\n\n\nstatic int inflateEnd OF((z_streamp strm));\n/*\n     All dynamically allocated data structures for this stream are freed.\n   This function discards any unprocessed input and does not flush any\n   pending output.\n\n     inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state\n   was inconsistent. In the error case, msg may be set but then points to a\n   static string (which must not be deallocated).\n*/\n\n                        /* Advanced functions */\n\n/*\n    The following functions are needed only in some special applications.\n*/\n\n/*   \nint deflateInit2 OF((z_streamp strm,\n                                     int  level,\n                                     int  method,\n                                     int  windowBits,\n                                     int  memLevel,\n                                     int  strategy));\n\n     This is another version of deflateInit with more compression options. The\n   fields next_in, zalloc, zfree and opaque must be initialized before by\n   the caller.\n\n     The method parameter is the compression method. It must be Z_DEFLATED in\n   this version of the library.\n\n     The windowBits parameter is the base two logarithm of the window size\n   (the size of the history buffer).  It should be in the range 8..15 for this\n   version of the library. Larger values of this parameter result in better\n   compression at the expense of memory usage. The default value is 15 if\n   deflateInit is used instead.\n\n     The memLevel parameter specifies how much memory should be allocated\n   for the internal compression state. memLevel=1 uses minimum memory but\n   is slow and reduces compression ratio; memLevel=9 uses maximum memory\n   for optimal speed. The default value is 8. See zconf.h for total memory\n   usage as a function of windowBits and memLevel.\n\n     The strategy parameter is used to tune the compression algorithm. Use the\n   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a\n   filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no\n   string match).  Filtered data consists mostly of small values with a\n   somewhat random distribution. In this case, the compression algorithm is\n   tuned to compress them better. The effect of Z_FILTERED is to force more\n   Huffman coding and less string matching; it is somewhat intermediate\n   between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects\n   the compression ratio but not the correctness of the compressed output even\n   if it is not set appropriately.\n\n      deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough\n   memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid\n   method). msg is set to null if there is no error message.  deflateInit2 does\n   not perform any compression: this will be done by deflate().\n*/\n                            \n/*\nstatic int deflateSetDictionary OF((z_streamp strm,\n                                             const Byte *dictionary,\n                                             uInt  dictLength));\n*/\n/*\n     Initializes the compression dictionary from the given byte sequence\n   without producing any compressed output. This function must be called\n   immediately after deflateInit, deflateInit2 or deflateReset, before any\n   call of deflate. The compressor and decompressor must use exactly the same\n   dictionary (see inflateSetDictionary).\n\n     The dictionary should consist of strings (byte sequences) that are likely\n   to be encountered later in the data to be compressed, with the most commonly\n   used strings preferably put towards the end of the dictionary. Using a\n   dictionary is most useful when the data to be compressed is short and can be\n   predicted with good accuracy; the data can then be compressed better than\n   with the default empty dictionary.\n\n     Depending on the size of the compression data structures selected by\n   deflateInit or deflateInit2, a part of the dictionary may in effect be\n   discarded, for example if the dictionary is larger than the window size in\n   deflate or deflate2. Thus the strings most likely to be useful should be\n   put at the end of the dictionary, not at the front.\n\n     Upon return of this function, strm->adler is set to the Adler32 value\n   of the dictionary; the decompressor may later use this value to determine\n   which dictionary has been used by the compressor. (The Adler32 value\n   applies to the whole dictionary even if only a subset of the dictionary is\n   actually used by the compressor.)\n\n     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a\n   parameter is invalid (such as NULL dictionary) or the stream state is\n   inconsistent (for example if deflate has already been called for this stream\n   or if the compression method is bsort). deflateSetDictionary does not\n   perform any compression: this will be done by deflate().\n*/\n\n/*\nstatic int deflateCopy OF((z_streamp dest,\n                                    z_streamp source));\n*/\n/*\n     Sets the destination stream as a complete copy of the source stream.\n\n     This function can be useful when several compression strategies will be\n   tried, for example when there are several ways of pre-processing the input\n   data with a filter. The streams that will be discarded should then be freed\n   by calling deflateEnd.  Note that deflateCopy duplicates the internal\n   compression state which can be quite large, so this strategy is slow and\n   can consume lots of memory.\n\n     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not\n   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent\n   (such as zalloc being NULL). msg is left unchanged in both source and\n   destination.\n*/\n\n// static int deflateReset OF((z_streamp strm));\n/*\n     This function is equivalent to deflateEnd followed by deflateInit,\n   but does not free and reallocate all the internal compression state.\n   The stream will keep the same compression level and any other attributes\n   that may have been set by deflateInit2.\n\n      deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source\n   stream state was inconsistent (such as zalloc or state being NULL).\n*/\n\n/*\nstatic int deflateParams OF((z_streamp strm,\n\t\t\t\t      int level,\n\t\t\t\t      int strategy));\n*/\n/*\n     Dynamically update the compression level and compression strategy.  The\n   interpretation of level and strategy is as in deflateInit2.  This can be\n   used to switch between compression and straight copy of the input data, or\n   to switch to a different kind of input data requiring a different\n   strategy. If the compression level is changed, the input available so far\n   is compressed with the old level (and may be flushed); the new level will\n   take effect only at the next call of deflate().\n\n     Before the call of deflateParams, the stream state must be set as for\n   a call of deflate(), since the currently available input may have to\n   be compressed and flushed. In particular, strm->avail_out must be non-zero.\n\n     deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source\n   stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR\n   if strm->avail_out was zero.\n*/\n\n/*   \nint inflateInit2 OF((z_streamp strm,\n                                     int  windowBits));\n\n     This is another version of inflateInit with an extra parameter. The\n   fields next_in, avail_in, zalloc, zfree and opaque must be initialized\n   before by the caller.\n\n     The windowBits parameter is the base two logarithm of the maximum window\n   size (the size of the history buffer).  It should be in the range 8..15 for\n   this version of the library. The default value is 15 if inflateInit is used\n   instead. If a compressed stream with a larger window size is given as\n   input, inflate() will return with the error code Z_DATA_ERROR instead of\n   trying to allocate a larger window.\n\n      inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough\n   memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative\n   memLevel). msg is set to null if there is no error message.  inflateInit2\n   does not perform any decompression apart from reading the zlib header if\n   present: this will be done by inflate(). (So next_in and avail_in may be\n   modified, but next_out and avail_out are unchanged.)\n*/\n\n/*\nstatic int inflateSetDictionary OF((z_streamp strm,\n                                             const Byte *dictionary,\n                                             uInt  dictLength));\n*/\n/*\n     Initializes the decompression dictionary from the given uncompressed byte\n   sequence. This function must be called immediately after a call of inflate\n   if this call returned Z_NEED_DICT. The dictionary chosen by the compressor\n   can be determined from the Adler32 value returned by this call of\n   inflate. The compressor and decompressor must use exactly the same\n   dictionary (see deflateSetDictionary).\n\n     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a\n   parameter is invalid (such as NULL dictionary) or the stream state is\n   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the\n   expected one (incorrect Adler32 value). inflateSetDictionary does not\n   perform any decompression: this will be done by subsequent calls of\n   inflate().\n*/\n\n// static int inflateSync OF((z_streamp strm));\n/* \n    Skips invalid compressed data until a full flush point (see above the\n  description of deflate with Z_FULL_FLUSH) can be found, or until all\n  available input is skipped. No output is provided.\n\n    inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR\n  if no more input was provided, Z_DATA_ERROR if no flush point has been found,\n  or Z_STREAM_ERROR if the stream structure was inconsistent. In the success\n  case, the application may save the current current value of total_in which\n  indicates where valid compressed data was found. In the error case, the\n  application may repeatedly call inflateSync, providing more input each time,\n  until success or end of the input data.\n*/\n\nstatic int inflateReset OF((z_streamp strm));\n/*\n     This function is equivalent to inflateEnd followed by inflateInit,\n   but does not free and reallocate all the internal decompression state.\n   The stream will keep attributes that may have been set by inflateInit2.\n\n      inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source\n   stream state was inconsistent (such as zalloc or state being NULL).\n*/\n\n\n                        /* utility functions */\n\n/*\n     The following utility functions are implemented on top of the\n   basic stream-oriented functions. To simplify the interface, some\n   default options are assumed (compression level and memory usage,\n   standard memory allocation functions). The source code of these\n   utility functions can easily be modified if you need special options.\n*/\n\n/*\nstatic int compress OF((Byte *dest,   uLong *destLen,\n                                 const Byte *source, uLong sourceLen));\n*/\n/*\n     Compresses the source buffer into the destination buffer.  sourceLen is\n   the byte length of the source buffer. Upon entry, destLen is the total\n   size of the destination buffer, which must be at least 0.1% larger than\n   sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the\n   compressed buffer.\n     This function can be used to compress a whole file at once if the\n   input file is mmap'ed.\n     compress returns Z_OK if success, Z_MEM_ERROR if there was not\n   enough memory, Z_BUF_ERROR if there was not enough room in the output\n   buffer.\n*/\n\n/*\nstatic int compress2 OF((Byte *dest,   uLong *destLen,\n                                  const Byte *source, uLong sourceLen,\n                                  int level));\n*/\n/*\n     Compresses the source buffer into the destination buffer. The level\n   parameter has the same meaning as in deflateInit.  sourceLen is the byte\n   length of the source buffer. Upon entry, destLen is the total size of the\n   destination buffer, which must be at least 0.1% larger than sourceLen plus\n   12 bytes. Upon exit, destLen is the actual size of the compressed buffer.\n\n     compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough\n   memory, Z_BUF_ERROR if there was not enough room in the output buffer,\n   Z_STREAM_ERROR if the level parameter is invalid.\n*/\n\n/*\nstatic int uncompress OF((Byte *dest,   uLong *destLen,\n                                   const Byte *source, uLong sourceLen));\n*/                                   \n/*\n     Decompresses the source buffer into the destination buffer.  sourceLen is\n   the byte length of the source buffer. Upon entry, destLen is the total\n   size of the destination buffer, which must be large enough to hold the\n   entire uncompressed data. (The size of the uncompressed data must have\n   been saved previously by the compressor and transmitted to the decompressor\n   by some mechanism outside the scope of this compression library.)\n   Upon exit, destLen is the actual size of the compressed buffer.\n     This function can be used to decompress a whole file at once if the\n   input file is mmap'ed.\n\n     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not\n   enough memory, Z_BUF_ERROR if there was not enough room in the output\n   buffer, or Z_DATA_ERROR if the input data was corrupted.\n*/\n\n\ntypedef voidp gzFile;\n\ngzFile gzopen  OF((const char *path, const char *mode));\n/*\n     Opens a gzip (.gz) file for reading or writing. The mode parameter\n   is as in fopen (\"rb\" or \"wb\") but can also include a compression level\n   (\"wb9\") or a strategy: 'f' for filtered data as in \"wb6f\", 'h' for\n   Huffman only compression as in \"wb1h\". (See the description\n   of deflateInit2 for more information about the strategy parameter.)\n\n     gzopen can be used to read a file which is not in gzip format; in this\n   case gzread will directly read from the file without decompression.\n\n     gzopen returns NULL if the file could not be opened or if there was\n   insufficient memory to allocate the (de)compression state; errno\n   can be checked to distinguish the two cases (if errno is zero, the\n   zlib error is Z_MEM_ERROR).  */\n\ngzFile gzdopen  OF((int fd, const char *mode));\n/*\n     gzdopen() associates a gzFile with the file descriptor fd.  File\n   descriptors are obtained from calls like open, dup, creat, pipe or\n   fileno (in the file has been previously opened with fopen).\n   The mode parameter is as in gzopen.\n     The next call of gzclose on the returned gzFile will also close the\n   file descriptor fd, just like fclose(fdopen(fd), mode) closes the file\n   descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode).\n     gzdopen returns NULL if there was insufficient memory to allocate\n   the (de)compression state.\n*/\n\nint gzsetparams OF((gzFile file, int level, int strategy));\n/*\n     Dynamically update the compression level or strategy. See the description\n   of deflateInit2 for the meaning of these parameters.\n     gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not\n   opened for writing.\n*/\n\nint    gzread  OF((gzFile file, voidp buf, unsigned len));\n/*\n     Reads the given number of uncompressed bytes from the compressed file.\n   If the input file was not in gzip format, gzread copies the given number\n   of bytes into the buffer.\n     gzread returns the number of uncompressed bytes actually read (0 for\n   end of file, -1 for error). */\n\nint    gzwrite OF((gzFile file, \n\t\t\t\t   const voidp buf, unsigned len));\n/*\n     Writes the given number of uncompressed bytes into the compressed file.\n   gzwrite returns the number of uncompressed bytes actually written\n   (0 in case of error).\n*/\n\nint    QDECL gzprintf OF((gzFile file, const char *format, ...));\n/*\n     Converts, formats, and writes the args to the compressed file under\n   control of the format string, as in fprintf. gzprintf returns the number of\n   uncompressed bytes actually written (0 in case of error).\n*/\n\nint gzputs OF((gzFile file, const char *s));\n/*\n      Writes the given null-terminated string to the compressed file, excluding\n   the terminating null character.\n      gzputs returns the number of characters written, or -1 in case of error.\n*/\n\nchar * gzgets OF((gzFile file, char *buf, int len));\n/*\n      Reads bytes from the compressed file until len-1 characters are read, or\n   a newline character is read and transferred to buf, or an end-of-file\n   condition is encountered.  The string is then terminated with a null\n   character.\n      gzgets returns buf, or Z_NULL in case of error.\n*/\n\nint    gzputc OF((gzFile file, int c));\n/*\n      Writes c, converted to an unsigned char, into the compressed file.\n   gzputc returns the value that was written, or -1 in case of error.\n*/\n\nint    gzgetc OF((gzFile file));\n/*\n      Reads one byte from the compressed file. gzgetc returns this byte\n   or -1 in case of end of file or error.\n*/\n\nint    gzflush OF((gzFile file, int flush));\n/*\n     Flushes all pending output into the compressed file. The parameter\n   flush is as in the deflate() function. The return value is the zlib\n   error number (see function gzerror below). gzflush returns Z_OK if\n   the flush parameter is Z_FINISH and all output could be flushed.\n     gzflush should be called only when strictly necessary because it can\n   degrade compression.\n*/\n\nlong gzseek OF((gzFile file,\n\t\t\t\t      long offset, int whence));\n/* \n      Sets the starting position for the next gzread or gzwrite on the\n   given compressed file. The offset represents a number of bytes in the\n   uncompressed data stream. The whence parameter is defined as in lseek(2);\n   the value SEEK_END is not supported.\n     If the file is opened for reading, this function is emulated but can be\n   extremely slow. If the file is opened for writing, only forward seeks are\n   supported; gzseek then compresses a sequence of zeroes up to the new\n   starting position.\n\n      gzseek returns the resulting offset location as measured in bytes from\n   the beginning of the uncompressed stream, or -1 in case of error, in\n   particular if the file is opened for writing and the new starting position\n   would be before the current position.\n*/\n\nint    gzrewind OF((gzFile file));\n/*\n     Rewinds the given file. This function is supported only for reading.\n\n   gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)\n*/\n\nlong    gztell OF((gzFile file));\n/*\n     Returns the starting position for the next gzread or gzwrite on the\n   given compressed file. This position represents a number of bytes in the\n   uncompressed data stream.\n\n   gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)\n*/\n\nint gzeof OF((gzFile file));\n/*\n     Returns 1 when EOF has previously been detected reading the given\n   input stream, otherwise zero.\n*/\n\nint    gzclose OF((gzFile file));\n/*\n     Flushes all pending output if necessary, closes the compressed file\n   and deallocates all the (de)compression state. The return value is the zlib\n   error number (see function gzerror below).\n*/\n\n// static const char * gzerror OF((gzFile file, int *errnum));\n/*\n     Returns the error message for the last error which occurred on the\n   given compressed file. errnum is set to zlib error number. If an\n   error occurred in the file system and not in the compression library,\n   errnum is set to Z_ERRNO and the application may consult errno\n   to get the exact error code.\n*/\n\n                        /* checksum functions */\n\n/*\n     These functions are not related to compression but are exported\n   anyway because they might be useful in applications using the\n   compression library.\n*/\n\nstatic uLong adler32 OF((uLong adler, const Byte *buf, uInt len));\n\n/*\n     Update a running Adler-32 checksum with the bytes buf[0..len-1] and\n   return the updated checksum. If buf is NULL, this function returns\n   the required initial value for the checksum.\n   An Adler-32 checksum is almost as reliable as a CRC32 but can be computed\n   much faster. Usage example:\n\n     uLong adler = adler32(0L, Z_NULL, 0);\n\n     while (read_buffer(buffer, length) != EOF) {\n       adler = adler32(adler, buffer, length);\n     }\n     if (adler != original_adler) error();\n*/\n\n                        /* various hacks, don't look :) */\n\n/* deflateInit and inflateInit are macros to allow checking the zlib version\n * and the compiler's view of z_stream:\n */\n/*\nstatic int deflateInit_ OF((z_streamp strm, int level,\n                                     const char *version, int stream_size));\nstatic int inflateInit_ OF((z_streamp strm,\n                                     const char *version, int stream_size));\nstatic int deflateInit2_ OF((z_streamp strm, int  level, int  method,\n                                      int windowBits, int memLevel,\n                                      int strategy, const char *version,\n                                      int stream_size));\n*/\nstatic int inflateInit2_ OF((z_streamp strm, int  windowBits,\n                                      const char *version, int stream_size));\n\n#define deflateInit(strm, level) \\\n        deflateInit_((strm), (level),       ZLIB_VERSION, sizeof(z_stream))\n#define inflateInit(strm) \\\n        inflateInit_((strm),                ZLIB_VERSION, sizeof(z_stream))\n#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \\\n        deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\\\n                      (strategy),           ZLIB_VERSION, sizeof(z_stream))\n#define inflateInit2(strm, windowBits) \\\n        inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))\n\n\n// static const char   * zError           OF((int err));\n// static int            inflateSyncPoint OF((z_streamp z));\n// static const uLong * get_crc_table    OF((void));\n\ntypedef unsigned char  uch;\ntypedef unsigned short ush;\ntypedef unsigned long  ulg;\n\n// static const char *z_errmsg[10]; /* indexed by 2-zlib_error */\n/* (size given to avoid silly warnings with Visual C++) */\n\n#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]\n\n#define ERR_RETURN(strm,err) \\\n  return (strm->msg = (char*)ERR_MSG(err), (err))\n/* To be used only when the state is known to be valid */\n\n        /* common constants */\n\n#ifndef DEF_WBITS\n#  define DEF_WBITS MAX_WBITS\n#endif\n/* default windowBits for decompression. MAX_WBITS is for compression only */\n\n#if MAX_MEM_LEVEL >= 8\n#  define DEF_MEM_LEVEL 8\n#else\n#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL\n#endif\n/* default memLevel */\n\n#define STORED_BLOCK 0\n#define STATIC_TREES 1\n#define DYN_TREES    2\n/* The three kinds of block type */\n\n#define MIN_MATCH  3\n#define MAX_MATCH  258\n/* The minimum and maximum match lengths */\n\n#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */\n\n        /* target dependencies */\n\n        /* Common defaults */\n\n#ifndef OS_CODE\n#  define OS_CODE  0x03  /* assume Unix */\n#endif\n\n#ifndef F_OPEN\n#  define F_OPEN(name, mode) fopen((name), (mode))\n#endif\n\n         /* functions */\n\n#ifdef HAVE_STRERROR\n   extern char *strerror OF((int));\n#  define zstrerror(errnum) strerror(errnum)\n#else\n#  define zstrerror(errnum) \"\"\n#endif\n\n#define zmemcpy Com_Memcpy\n#define zmemcmp memcmp\n#define zmemzero(dest, len) Com_Memset(dest, 0, len)\n\n/* Diagnostic functions */\n#ifdef _ZIP_DEBUG_\n   int z_verbose = 0;\n#  define Assert(cond,msg) assert(cond);\n   //{if(!(cond)) Sys_Error(msg);}\n#  define Trace(x) {if (z_verbose>=0) Sys_Error x ;}\n#  define Tracev(x) {if (z_verbose>0) Sys_Error x ;}\n#  define Tracevv(x) {if (z_verbose>1) Sys_Error x ;}\n#  define Tracec(c,x) {if (z_verbose>0 && (c)) Sys_Error x ;}\n#  define Tracecv(c,x) {if (z_verbose>1 && (c)) Sys_Error x ;}\n#else\n#  define Assert(cond,msg)\n#  define Trace(x)\n#  define Tracev(x)\n#  define Tracevv(x)\n#  define Tracec(c,x)\n#  define Tracecv(c,x)\n#endif\n\n\ntypedef uLong (*check_func) OF((uLong check, const Byte *buf, uInt len));\nstatic voidp zcalloc OF((voidp opaque, unsigned items, unsigned size));\nstatic void   zcfree  OF((voidp opaque, voidp ptr));\n\n#define ZALLOC(strm, items, size) \\\n           (*((strm)->zalloc))((strm)->opaque, (items), (size))\n#define ZFREE(strm, addr)  (*((strm)->zfree))((strm)->opaque, (voidp)(addr))\n#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}\n\n\n#if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) && \\\n                      !defined(CASESENSITIVITYDEFAULT_NO)\n#define CASESENSITIVITYDEFAULT_NO\n#endif\n\n\n#ifndef UNZ_BUFSIZE\n#define UNZ_BUFSIZE (65536)\n#endif\n\n#ifndef UNZ_MAXFILENAMEINZIP\n#define UNZ_MAXFILENAMEINZIP (256)\n#endif\n\n#ifndef ALLOC\n# define ALLOC(size) (Z_Malloc(size))\n#endif\n#ifndef TRYFREE\n# define TRYFREE(p) {if (p) Z_Free(p);}\n#endif\n\n#define SIZECENTRALDIRITEM (0x2e)\n#define SIZEZIPLOCALHEADER (0x1e)\n\n\n\n/* ===========================================================================\n     Read a byte from a gz_stream; update next_in and avail_in. Return EOF\n   for end of file.\n   IN assertion: the stream s has been sucessfully opened for reading.\n*/\n\n/*\nstatic int unzlocal_getByte(FILE *fin,int *pi)\n{\n    unsigned char c;\n\tint err = fread(&c, 1, 1, fin);\n    if (err==1)\n    {\n        *pi = (int)c;\n        return UNZ_OK;\n    }\n    else\n    {\n        if (ferror(fin)) \n            return UNZ_ERRNO;\n        else\n            return UNZ_EOF;\n    }\n}\n*/\n\n/* ===========================================================================\n   Reads a long in LSB order from the given gz_stream. Sets \n*/\nstatic int unzlocal_getShort (FILE* fin, uLong *pX)\n{\n\tshort\tv;\n\n\tfread( &v, sizeof(v), 1, fin );\n\n\t*pX = LittleShort( v);\n\treturn UNZ_OK;\n\n/*\n    uLong x ;\n    int i;\n    int err;\n\n    err = unzlocal_getByte(fin,&i);\n    x = (uLong)i;\n    \n    if (err==UNZ_OK)\n        err = unzlocal_getByte(fin,&i);\n    x += ((uLong)i)<<8;\n   \n    if (err==UNZ_OK)\n        *pX = x;\n    else\n        *pX = 0;\n    return err;\n*/\n}\n\nstatic int unzlocal_getLong (FILE *fin, uLong *pX)\n{\n\tint\t\tv;\n\n\tfread( &v, sizeof(v), 1, fin );\n\n\t*pX = LittleLong( v);\n\treturn UNZ_OK;\n\n/*\n    uLong x ;\n    int i;\n    int err;\n\n    err = unzlocal_getByte(fin,&i);\n    x = (uLong)i;\n    \n    if (err==UNZ_OK)\n        err = unzlocal_getByte(fin,&i);\n    x += ((uLong)i)<<8;\n\n    if (err==UNZ_OK)\n        err = unzlocal_getByte(fin,&i);\n    x += ((uLong)i)<<16;\n\n    if (err==UNZ_OK)\n        err = unzlocal_getByte(fin,&i);\n    x += ((uLong)i)<<24;\n   \n    if (err==UNZ_OK)\n        *pX = x;\n    else\n        *pX = 0;\n    return err;\n*/\n}\n\n\n/* My own strcmpi / strcasecmp */\nstatic int strcmpcasenosensitive_internal (const char* fileName1,const char* fileName2)\n{\n\tfor (;;)\n\t{\n\t\tchar c1=*(fileName1++);\n\t\tchar c2=*(fileName2++);\n\t\tif ((c1>='a') && (c1<='z'))\n\t\t\tc1 -= 0x20;\n\t\tif ((c2>='a') && (c2<='z'))\n\t\t\tc2 -= 0x20;\n\t\tif (c1=='\\0')\n\t\t\treturn ((c2=='\\0') ? 0 : -1);\n\t\tif (c2=='\\0')\n\t\t\treturn 1;\n\t\tif (c1<c2)\n\t\t\treturn -1;\n\t\tif (c1>c2)\n\t\t\treturn 1;\n\t}\n}\n\n\n#ifdef  CASESENSITIVITYDEFAULT_NO\n#define CASESENSITIVITYDEFAULTVALUE 2\n#else\n#define CASESENSITIVITYDEFAULTVALUE 1\n#endif\n\n#ifndef STRCMPCASENOSENTIVEFUNCTION\n#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal\n#endif\n\n/* \n   Compare two filename (fileName1,fileName2).\n   If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)\n   If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi\n                                                                or strcasecmp)\n   If iCaseSenisivity = 0, case sensitivity is defaut of your operating system\n        (like 1 on Unix, 2 on Windows)\n\n*/\nextern  int unzStringFileNameCompare (const char* fileName1,const char* fileName2,int iCaseSensitivity)\n{\n\tif (iCaseSensitivity==0)\n\t\tiCaseSensitivity=CASESENSITIVITYDEFAULTVALUE;\n\n\tif (iCaseSensitivity==1)\n\t\treturn strcmp(fileName1,fileName2);\n\n\treturn STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2);\n} \n\n#define BUFREADCOMMENT (0x400)\n\n/*\n  Locate the Central directory of a zipfile (at the end, just before\n    the global comment)\n*/\nextern uLong unzlocal_SearchCentralDir(FILE *fin)\n{\n\tunsigned char* buf;\n\tuLong uSizeFile;\n\tuLong uBackRead;\n\tuLong uMaxBack=0xffff; /* maximum size of global comment */\n\tuLong uPosFound=0;\n\t\n\tif (fseek(fin,0,SEEK_END) != 0)\n\t\treturn 0;\n\n\n\tuSizeFile = ftell( fin );\n\t\n\tif (uMaxBack>uSizeFile)\n\t\tuMaxBack = uSizeFile;\n\n\tbuf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);\n\tif (buf==NULL)\n\t\treturn 0;\n\n\tuBackRead = 4;\n\twhile (uBackRead<uMaxBack)\n\t{\n\t\tuLong uReadSize,uReadPos ;\n\t\tint i;\n\t\tif (uBackRead+BUFREADCOMMENT>uMaxBack) \n\t\t\tuBackRead = uMaxBack;\n\t\telse\n\t\t\tuBackRead+=BUFREADCOMMENT;\n\t\tuReadPos = uSizeFile-uBackRead ;\n\t\t\n\t\tuReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? \n                     (BUFREADCOMMENT+4) : (uSizeFile-uReadPos);\n\t\tif (fseek(fin,uReadPos,SEEK_SET)!=0)\n\t\t\tbreak;\n\n\t\tif (fread(buf,(uInt)uReadSize,1,fin)!=1)\n\t\t\tbreak;\n\n                for (i=(int)uReadSize-3; (i--)>0;)\n\t\t\tif (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && \n\t\t\t\t((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06))\n\t\t\t{\n\t\t\t\tuPosFound = uReadPos+i;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\tif (uPosFound!=0)\n\t\t\tbreak;\n\t}\n\tTRYFREE(buf);\n\treturn uPosFound;\n}\n\nextern unzFile unzReOpen (const char* path, unzFile file)\n{\n\tunz_s *s;\n\tFILE * fin;\n\n    fin=fopen(path,\"rb\");\n\tif (fin==NULL)\n\t\treturn NULL;\n\n\ts=(unz_s*)ALLOC(sizeof(unz_s));\n\tCom_Memcpy(s, (unz_s*)file, sizeof(unz_s));\n\n\ts->file = fin;\n\treturn (unzFile)s;\t\n}\n\n/*\n  Open a Zip file. path contain the full pathname (by example,\n     on a Windows NT computer \"c:\\\\test\\\\zlib109.zip\" or on an Unix computer\n\t \"zlib/zlib109.zip\".\n\t If the zipfile cannot be opened (file don't exist or in not valid), the\n\t   return value is NULL.\n     Else, the return value is a unzFile Handle, usable with other function\n\t   of this unzip package.\n*/\nextern unzFile unzOpen (const char* path)\n{\n\tunz_s us;\n\tunz_s *s;\n\tuLong central_pos,uL;\n\tFILE * fin ;\n\n\tuLong number_disk;          /* number of the current dist, used for \n\t\t\t\t\t\t\t\t   spaning ZIP, unsupported, always 0*/\n\tuLong number_disk_with_CD;  /* number the the disk with central dir, used\n\t\t\t\t\t\t\t\t   for spaning ZIP, unsupported, always 0*/\n\tuLong number_entry_CD;      /* total number of entries in\n\t                               the central dir \n\t                               (same than number_entry on nospan) */\n\n\tint err=UNZ_OK;\n\n    fin=fopen(path,\"rb\");\n\tif (fin==NULL)\n\t\treturn NULL;\n\n\tcentral_pos = unzlocal_SearchCentralDir(fin);\n\tif (central_pos==0)\n\t\terr=UNZ_ERRNO;\n\n\tif (fseek(fin,central_pos,SEEK_SET)!=0)\n\t\terr=UNZ_ERRNO;\n\n\t/* the signature, already checked */\n\tif (unzlocal_getLong(fin,&uL)!=UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\n\t/* number of this disk */\n\tif (unzlocal_getShort(fin,&number_disk)!=UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\n\t/* number of the disk with the start of the central directory */\n\tif (unzlocal_getShort(fin,&number_disk_with_CD)!=UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\n\t/* total number of entries in the central dir on this disk */\n\tif (unzlocal_getShort(fin,&us.gi.number_entry)!=UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\n\t/* total number of entries in the central dir */\n\tif (unzlocal_getShort(fin,&number_entry_CD)!=UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\n\tif ((number_entry_CD!=us.gi.number_entry) ||\n\t\t(number_disk_with_CD!=0) ||\n\t\t(number_disk!=0))\n\t\terr=UNZ_BADZIPFILE;\n\n\t/* size of the central directory */\n\tif (unzlocal_getLong(fin,&us.size_central_dir)!=UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\n\t/* offset of start of central directory with respect to the \n\t      starting disk number */\n\tif (unzlocal_getLong(fin,&us.offset_central_dir)!=UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\n\t/* zipfile comment length */\n\tif (unzlocal_getShort(fin,&us.gi.size_comment)!=UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\n\tif ((central_pos<us.offset_central_dir+us.size_central_dir) && \n\t\t(err==UNZ_OK))\n\t\terr=UNZ_BADZIPFILE;\n\n\tif (err!=UNZ_OK)\n\t{\n\t\tfclose(fin);\n\t\treturn NULL;\n\t}\n\n\tus.file=fin;\n\tus.byte_before_the_zipfile = central_pos -\n\t\t                    (us.offset_central_dir+us.size_central_dir);\n\tus.central_pos = central_pos;\n    us.pfile_in_zip_read = NULL;\n\t\n\n\ts=(unz_s*)ALLOC(sizeof(unz_s));\n\t*s=us;\n//\tunzGoToFirstFile((unzFile)s);\t\n\treturn (unzFile)s;\t\n}\n\n\n/*\n  Close a ZipFile opened with unzipOpen.\n  If there is files inside the .Zip opened with unzipOpenCurrentFile (see later),\n    these files MUST be closed with unzipCloseCurrentFile before call unzipClose.\n  return UNZ_OK if there is no problem. */\nextern int unzClose (unzFile file)\n{\n\tunz_s* s;\n\tif (file==NULL)\n\t\treturn UNZ_PARAMERROR;\n\ts=(unz_s*)file;\n\n    if (s->pfile_in_zip_read!=NULL)\n        unzCloseCurrentFile(file);\n\n\tfclose(s->file);\n\tTRYFREE(s);\n\treturn UNZ_OK;\n}\n\n\n/*\n  Write info about the ZipFile in the *pglobal_info structure.\n  No preparation of the structure is needed\n  return UNZ_OK if there is no problem. */\nextern int unzGetGlobalInfo (unzFile file,unz_global_info *pglobal_info)\n{\n\tunz_s* s;\n\tif (file==NULL)\n\t\treturn UNZ_PARAMERROR;\n\ts=(unz_s*)file;\n\t*pglobal_info=s->gi;\n\treturn UNZ_OK;\n}\n\n\n/*\n   Translate date/time from Dos format to tm_unz (readable more easilty)\n*/\nstatic void unzlocal_DosDateToTmuDate (uLong ulDosDate, tm_unz* ptm)\n{\n    uLong uDate;\n    uDate = (uLong)(ulDosDate>>16);\n    ptm->tm_mday = (uInt)(uDate&0x1f) ;\n    ptm->tm_mon =  (uInt)((((uDate)&0x1E0)/0x20)-1) ;\n    ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ;\n\n    ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800);\n    ptm->tm_min =  (uInt) ((ulDosDate&0x7E0)/0x20) ;\n    ptm->tm_sec =  (uInt) (2*(ulDosDate&0x1f)) ;\n}\n\n/*\n  Get Info about the current file in the zipfile, with internal only info\n*/\nstatic int unzlocal_GetCurrentFileInfoInternal (unzFile file,\n                                                  unz_file_info *pfile_info,\n                                                  unz_file_info_internal \n                                                  *pfile_info_internal,\n                                                  char *szFileName,\n\t\t\t\t\t\t\t\t\t\t\t\t  uLong fileNameBufferSize,\n                                                  void *extraField,\n\t\t\t\t\t\t\t\t\t\t\t\t  uLong extraFieldBufferSize,\n                                                  char *szComment,\n\t\t\t\t\t\t\t\t\t\t\t\t  uLong commentBufferSize)\n{\n\tunz_s* s;\n\tunz_file_info file_info;\n\tunz_file_info_internal file_info_internal;\n\tint err=UNZ_OK;\n\tuLong uMagic;\n\tlong lSeek=0;\n\n\tif (file==NULL)\n\t\treturn UNZ_PARAMERROR;\n\ts=(unz_s*)file;\n\tif (fseek(s->file,s->pos_in_central_dir+s->byte_before_the_zipfile,SEEK_SET)!=0)\n\t\terr=UNZ_ERRNO;\n\n\n\t/* we check the magic */\n\tif (err==UNZ_OK) {\n\t\tif (unzlocal_getLong(s->file,&uMagic) != UNZ_OK)\n\t\t\terr=UNZ_ERRNO;\n\t\telse if (uMagic!=0x02014b50)\n\t\t\terr=UNZ_BADZIPFILE;\n\t}\n\tif (unzlocal_getShort(s->file,&file_info.version) != UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\n\tif (unzlocal_getShort(s->file,&file_info.version_needed) != UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\n\tif (unzlocal_getShort(s->file,&file_info.flag) != UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\n\tif (unzlocal_getShort(s->file,&file_info.compression_method) != UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\n\tif (unzlocal_getLong(s->file,&file_info.dosDate) != UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\n    unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date);\n\n\tif (unzlocal_getLong(s->file,&file_info.crc) != UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\n\tif (unzlocal_getLong(s->file,&file_info.compressed_size) != UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\n\tif (unzlocal_getLong(s->file,&file_info.uncompressed_size) != UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\n\tif (unzlocal_getShort(s->file,&file_info.size_filename) != UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\n\tif (unzlocal_getShort(s->file,&file_info.size_file_extra) != UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\n\tif (unzlocal_getShort(s->file,&file_info.size_file_comment) != UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\n\tif (unzlocal_getShort(s->file,&file_info.disk_num_start) != UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\n\tif (unzlocal_getShort(s->file,&file_info.internal_fa) != UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\n\tif (unzlocal_getLong(s->file,&file_info.external_fa) != UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\n\tif (unzlocal_getLong(s->file,&file_info_internal.offset_curfile) != UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\n\tlSeek+=file_info.size_filename;\n\tif ((err==UNZ_OK) && (szFileName!=NULL))\n\t{\n\t\tuLong uSizeRead ;\n\t\tif (file_info.size_filename<fileNameBufferSize)\n\t\t{\n\t\t\t*(szFileName+file_info.size_filename)='\\0';\n\t\t\tuSizeRead = file_info.size_filename;\n\t\t}\n\t\telse\n\t\t\tuSizeRead = fileNameBufferSize;\n\n\t\tif ((file_info.size_filename>0) && (fileNameBufferSize>0))\n\t\t\tif (fread(szFileName,(uInt)uSizeRead,1,s->file)!=1)\n\t\t\t\terr=UNZ_ERRNO;\n\t\tlSeek -= uSizeRead;\n\t}\n\n\t\n\tif ((err==UNZ_OK) && (extraField!=NULL))\n\t{\n\t\tuLong uSizeRead ;\n\t\tif (file_info.size_file_extra<extraFieldBufferSize)\n\t\t\tuSizeRead = file_info.size_file_extra;\n\t\telse\n\t\t\tuSizeRead = extraFieldBufferSize;\n\n\t\tif (lSeek!=0) {\n\t\t\tif (fseek(s->file,lSeek,SEEK_CUR)==0)\n\t\t\t\tlSeek=0;\n\t\t\telse\n\t\t\t\terr=UNZ_ERRNO;\n\t\t}\n\t\tif ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) {\n\t\t\tif (fread(extraField,(uInt)uSizeRead,1,s->file)!=1)\n\t\t\t\terr=UNZ_ERRNO;\n\t\t}\n\t\tlSeek += file_info.size_file_extra - uSizeRead;\n\t}\n\telse\n\t\tlSeek+=file_info.size_file_extra; \n\n\t\n\tif ((err==UNZ_OK) && (szComment!=NULL))\n\t{\n\t\tuLong uSizeRead ;\n\t\tif (file_info.size_file_comment<commentBufferSize)\n\t\t{\n\t\t\t*(szComment+file_info.size_file_comment)='\\0';\n\t\t\tuSizeRead = file_info.size_file_comment;\n\t\t}\n\t\telse\n\t\t\tuSizeRead = commentBufferSize;\n\n\t\tif (lSeek!=0) {\n\t\t\tif (fseek(s->file,lSeek,SEEK_CUR)==0)\n\t\t\t\tlSeek=0;\n\t\t\telse\n\t\t\t\terr=UNZ_ERRNO;\n\t\t}\n\t\tif ((file_info.size_file_comment>0) && (commentBufferSize>0)) {\n\t\t\tif (fread(szComment,(uInt)uSizeRead,1,s->file)!=1)\n\t\t\t\terr=UNZ_ERRNO;\n\t\t}\n\t\tlSeek+=file_info.size_file_comment - uSizeRead;\n\t}\n\telse\n\t\tlSeek+=file_info.size_file_comment;\n\n\tif ((err==UNZ_OK) && (pfile_info!=NULL))\n\t\t*pfile_info=file_info;\n\n\tif ((err==UNZ_OK) && (pfile_info_internal!=NULL))\n\t\t*pfile_info_internal=file_info_internal;\n\n\treturn err;\n}\n\n\n\n/*\n  Write info about the ZipFile in the *pglobal_info structure.\n  No preparation of the structure is needed\n  return UNZ_OK if there is no problem.\n*/\nextern int unzGetCurrentFileInfo (\tunzFile file, unz_file_info *pfile_info,\n\t\t\t\t\t\t\t\t\tchar *szFileName, uLong fileNameBufferSize,\n\t\t\t\t\t\t\t\t\tvoid *extraField, uLong extraFieldBufferSize,\n\t\t\t\t\t\t\t\t\tchar *szComment, uLong commentBufferSize)\n{\n\treturn unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL,\n\t\t\t\t\t\t\t\t\t\t\t\tszFileName,fileNameBufferSize,\n\t\t\t\t\t\t\t\t\t\t\t\textraField,extraFieldBufferSize,\n\t\t\t\t\t\t\t\t\t\t\t\tszComment,commentBufferSize);\n}\n\n/*\n  Set the current file of the zipfile to the first file.\n  return UNZ_OK if there is no problem\n*/\nextern int unzGoToFirstFile (unzFile file)\n{\n\tint err=UNZ_OK;\n\tunz_s* s;\n\tif (file==NULL)\n\t\treturn UNZ_PARAMERROR;\n\ts=(unz_s*)file;\n\ts->pos_in_central_dir=s->offset_central_dir;\n\ts->num_file=0;\n\terr=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,\n\t\t\t\t\t\t\t\t\t\t\t &s->cur_file_info_internal,\n\t\t\t\t\t\t\t\t\t\t\t NULL,0,NULL,0,NULL,0);\n\ts->current_file_ok = (err == UNZ_OK);\n\treturn err;\n}\n\n\n/*\n  Set the current file of the zipfile to the next file.\n  return UNZ_OK if there is no problem\n  return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.\n*/\nextern int unzGoToNextFile (unzFile file)\n{\n\tunz_s* s;\t\n\tint err;\n\n\tif (file==NULL)\n\t\treturn UNZ_PARAMERROR;\n\ts=(unz_s*)file;\n\tif (!s->current_file_ok)\n\t\treturn UNZ_END_OF_LIST_OF_FILE;\n\tif (s->num_file+1==s->gi.number_entry)\n\t\treturn UNZ_END_OF_LIST_OF_FILE;\n\n\ts->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename +\n\t\t\ts->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ;\n\ts->num_file++;\n\terr = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,\n\t\t\t\t\t\t\t\t\t\t\t   &s->cur_file_info_internal,\n\t\t\t\t\t\t\t\t\t\t\t   NULL,0,NULL,0,NULL,0);\n\ts->current_file_ok = (err == UNZ_OK);\n\treturn err;\n}\n\n/*\n  Get the position of the info of the current file in the zip.\n  return UNZ_OK if there is no problem\n*/\nextern int unzGetCurrentFileInfoPosition (unzFile file, unsigned long *pos )\n{\n\tunz_s* s;\t\n\n\tif (file==NULL)\n\t\treturn UNZ_PARAMERROR;\n\ts=(unz_s*)file;\n\n\t*pos = s->pos_in_central_dir;\n\treturn UNZ_OK;\n}\n\n/*\n  Set the position of the info of the current file in the zip.\n  return UNZ_OK if there is no problem\n*/\nextern int unzSetCurrentFileInfoPosition (unzFile file, unsigned long pos )\n{\n\tunz_s* s;\t\n\tint err;\n\n\tif (file==NULL)\n\t\treturn UNZ_PARAMERROR;\n\ts=(unz_s*)file;\n\n\ts->pos_in_central_dir = pos;\n\terr = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,\n\t\t\t\t\t\t\t\t\t\t\t   &s->cur_file_info_internal,\n\t\t\t\t\t\t\t\t\t\t\t   NULL,0,NULL,0,NULL,0);\n\ts->current_file_ok = (err == UNZ_OK);\n\treturn UNZ_OK;\n}\n\n/*\n  Try locate the file szFileName in the zipfile.\n  For the iCaseSensitivity signification, see unzipStringFileNameCompare\n\n  return value :\n  UNZ_OK if the file is found. It becomes the current file.\n  UNZ_END_OF_LIST_OF_FILE if the file is not found\n*/\nextern int unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity)\n{\n\tunz_s* s;\t\n\tint err;\n\n\t\n\tuLong num_fileSaved;\n\tuLong pos_in_central_dirSaved;\n\n\n\tif (file==NULL)\n\t\treturn UNZ_PARAMERROR;\n\n    if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP)\n        return UNZ_PARAMERROR;\n\n\ts=(unz_s*)file;\n\tif (!s->current_file_ok)\n\t\treturn UNZ_END_OF_LIST_OF_FILE;\n\n\tnum_fileSaved = s->num_file;\n\tpos_in_central_dirSaved = s->pos_in_central_dir;\n\n\terr = unzGoToFirstFile(file);\n\n\twhile (err == UNZ_OK)\n\t{\n\t\tchar szCurrentFileName[UNZ_MAXFILENAMEINZIP+1];\n\t\tunzGetCurrentFileInfo(file,NULL,\n\t\t\t\t\t\t\t\tszCurrentFileName,sizeof(szCurrentFileName)-1,\n\t\t\t\t\t\t\t\tNULL,0,NULL,0);\n\t\tif (unzStringFileNameCompare(szCurrentFileName,\n\t\t\t\t\t\t\t\t\t\tszFileName,iCaseSensitivity)==0)\n\t\t\treturn UNZ_OK;\n\t\terr = unzGoToNextFile(file);\n\t}\n\n\ts->num_file = num_fileSaved ;\n\ts->pos_in_central_dir = pos_in_central_dirSaved ;\n\treturn err;\n}\n\n\n/*\n  Read the static header of the current zipfile\n  Check the coherency of the static header and info in the end of central\n        directory about this file\n  store in *piSizeVar the size of extra info in static header\n        (filename and size of extra field data)\n*/\nstatic int unzlocal_CheckCurrentFileCoherencyHeader (unz_s* s, uInt* piSizeVar,\n\t\t\t\t\t\t\t\t\t\t\t\t\tuLong *poffset_local_extrafield,\n\t\t\t\t\t\t\t\t\t\t\t\t\tuInt *psize_local_extrafield)\n{\n\tuLong uMagic,uData,uFlags;\n\tuLong size_filename;\n\tuLong size_extra_field;\n\tint err=UNZ_OK;\n\n\t*piSizeVar = 0;\n\t*poffset_local_extrafield = 0;\n\t*psize_local_extrafield = 0;\n\n\tif (fseek(s->file,s->cur_file_info_internal.offset_curfile +\n\t\t\t\t\t\t\t\ts->byte_before_the_zipfile,SEEK_SET)!=0)\n\t\treturn UNZ_ERRNO;\n\n\n\tif (err==UNZ_OK) {\n\t\tif (unzlocal_getLong(s->file,&uMagic) != UNZ_OK)\n\t\t\terr=UNZ_ERRNO;\n\t\telse if (uMagic!=0x04034b50)\n\t\t\terr=UNZ_BADZIPFILE;\n\t}\n\tif (unzlocal_getShort(s->file,&uData) != UNZ_OK)\n\t\terr=UNZ_ERRNO;\n/*\n\telse if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion))\n\t\terr=UNZ_BADZIPFILE;\n*/\n\tif (unzlocal_getShort(s->file,&uFlags) != UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\n\tif (unzlocal_getShort(s->file,&uData) != UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\telse if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method))\n\t\terr=UNZ_BADZIPFILE;\n\n    if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) &&\n                         (s->cur_file_info.compression_method!=Z_DEFLATED))\n        err=UNZ_BADZIPFILE;\n\n\tif (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* date/time */\n\t\terr=UNZ_ERRNO;\n\n\tif (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* crc */\n\t\terr=UNZ_ERRNO;\n\telse if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) &&\n\t\t                      ((uFlags & 8)==0))\n\t\terr=UNZ_BADZIPFILE;\n\n\tif (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size compr */\n\t\terr=UNZ_ERRNO;\n\telse if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) &&\n\t\t\t\t\t\t\t  ((uFlags & 8)==0))\n\t\terr=UNZ_BADZIPFILE;\n\n\tif (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size uncompr */\n\t\terr=UNZ_ERRNO;\n\telse if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && \n\t\t\t\t\t\t\t  ((uFlags & 8)==0))\n\t\terr=UNZ_BADZIPFILE;\n\n\n\tif (unzlocal_getShort(s->file,&size_filename) != UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\telse if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename))\n\t\terr=UNZ_BADZIPFILE;\n\n\t*piSizeVar += (uInt)size_filename;\n\n\tif (unzlocal_getShort(s->file,&size_extra_field) != UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\t*poffset_local_extrafield= s->cur_file_info_internal.offset_curfile +\n\t\t\t\t\t\t\t\t\tSIZEZIPLOCALHEADER + size_filename;\n\t*psize_local_extrafield = (uInt)size_extra_field;\n\n\t*piSizeVar += (uInt)size_extra_field;\n\n\treturn err;\n}\n\t\t\t\t\t\t\t\t\t\t\t\t\n/*\n  Open for reading data the current file in the zipfile.\n  If there is no error and the file is opened, the return value is UNZ_OK.\n*/\nextern int unzOpenCurrentFile (unzFile file)\n{\n\tint err=UNZ_OK;\n\tint Store;\n\tuInt iSizeVar;\n\tunz_s* s;\n\tfile_in_zip_read_info_s* pfile_in_zip_read_info;\n\tuLong offset_local_extrafield;  /* offset of the static extra field */\n\tuInt  size_local_extrafield;    /* size of the static extra field */\n\n\tif (file==NULL)\n\t\treturn UNZ_PARAMERROR;\n\ts=(unz_s*)file;\n\tif (!s->current_file_ok)\n\t\treturn UNZ_PARAMERROR;\n\n    if (s->pfile_in_zip_read != NULL)\n        unzCloseCurrentFile(file);\n\n\tif (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar,\n\t\t\t\t&offset_local_extrafield,&size_local_extrafield)!=UNZ_OK)\n\t\treturn UNZ_BADZIPFILE;\n\n\tpfile_in_zip_read_info = (file_in_zip_read_info_s*)\n\t\t\t\t\t\t\t\t\t    ALLOC(sizeof(file_in_zip_read_info_s));\n\tif (pfile_in_zip_read_info==NULL)\n\t\treturn UNZ_INTERNALERROR;\n\n\tpfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE);\n\tpfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield;\n\tpfile_in_zip_read_info->size_local_extrafield = size_local_extrafield;\n\tpfile_in_zip_read_info->pos_local_extrafield=0;\n\n\tif (pfile_in_zip_read_info->read_buffer==NULL)\n\t{\n\t\tTRYFREE(pfile_in_zip_read_info);\n\t\treturn UNZ_INTERNALERROR;\n\t}\n\n\tpfile_in_zip_read_info->stream_initialised=0;\n\t\n\tif ((s->cur_file_info.compression_method!=0) &&\n        (s->cur_file_info.compression_method!=Z_DEFLATED))\n\t\terr=UNZ_BADZIPFILE;\n\tStore = s->cur_file_info.compression_method==0;\n\n\tpfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc;\n\tpfile_in_zip_read_info->crc32=0;\n\tpfile_in_zip_read_info->compression_method =\n            s->cur_file_info.compression_method;\n\tpfile_in_zip_read_info->file=s->file;\n\tpfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile;\n\n    pfile_in_zip_read_info->stream.total_out = 0;\n\n\tif (!Store)\n\t{\n\t  pfile_in_zip_read_info->stream.zalloc = (alloc_func)0;\n\t  pfile_in_zip_read_info->stream.zfree = (free_func)0;\n\t  pfile_in_zip_read_info->stream.opaque = (voidp)0; \n      \n\t  err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS);\n\t  if (err == Z_OK)\n\t    pfile_in_zip_read_info->stream_initialised=1;\n        /* windowBits is passed < 0 to tell that there is no zlib header.\n         * Note that in this case inflate *requires* an extra \"dummy\" byte\n         * after the compressed stream in order to complete decompression and\n         * return Z_STREAM_END. \n         * In unzip, i don't wait absolutely Z_STREAM_END because I known the \n         * size of both compressed and uncompressed data\n         */\n\t}\n\tpfile_in_zip_read_info->rest_read_compressed = \n            s->cur_file_info.compressed_size ;\n\tpfile_in_zip_read_info->rest_read_uncompressed = \n            s->cur_file_info.uncompressed_size ;\n\n\t\n\tpfile_in_zip_read_info->pos_in_zipfile = \n            s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + \n\t\t\t  iSizeVar;\n\t\n\tpfile_in_zip_read_info->stream.avail_in = (uInt)0;\n\n\n\ts->pfile_in_zip_read = pfile_in_zip_read_info;\n    return UNZ_OK;\n}\n\n\n/*\n  Read bytes from the current file.\n  buf contain buffer where data must be copied\n  len the size of buf.\n\n  return the number of byte copied if somes bytes are copied\n  return 0 if the end of file was reached\n  return <0 with error code if there is an error\n    (UNZ_ERRNO for IO error, or zLib error for uncompress error)\n*/\nextern int unzReadCurrentFile  (unzFile file, void *buf, unsigned len)\n{\n\tint err=UNZ_OK;\n\tuInt iRead = 0;\n\tunz_s* s;\n\tfile_in_zip_read_info_s* pfile_in_zip_read_info;\n\tif (file==NULL)\n\t\treturn UNZ_PARAMERROR;\n\ts=(unz_s*)file;\n    pfile_in_zip_read_info=s->pfile_in_zip_read;\n\n\tif (pfile_in_zip_read_info==NULL)\n\t\treturn UNZ_PARAMERROR;\n\n\n\tif ((pfile_in_zip_read_info->read_buffer == NULL))\n\t\treturn UNZ_END_OF_LIST_OF_FILE;\n\tif (len==0)\n\t\treturn 0;\n\n\tpfile_in_zip_read_info->stream.next_out = (Byte*)buf;\n\n\tpfile_in_zip_read_info->stream.avail_out = (uInt)len;\n\t\n\tif (len>pfile_in_zip_read_info->rest_read_uncompressed)\n\t\tpfile_in_zip_read_info->stream.avail_out = \n\t\t  (uInt)pfile_in_zip_read_info->rest_read_uncompressed;\n\n\twhile (pfile_in_zip_read_info->stream.avail_out>0)\n\t{\n\t\tif ((pfile_in_zip_read_info->stream.avail_in==0) &&\n            (pfile_in_zip_read_info->rest_read_compressed>0))\n\t\t{\n\t\t\tuInt uReadThis = UNZ_BUFSIZE;\n\t\t\tif (pfile_in_zip_read_info->rest_read_compressed<uReadThis)\n\t\t\t\tuReadThis = (uInt)pfile_in_zip_read_info->rest_read_compressed;\n\t\t\tif (uReadThis == 0)\n\t\t\t\treturn UNZ_EOF;\n\t\t\tif (s->cur_file_info.compressed_size == pfile_in_zip_read_info->rest_read_compressed)\n\t\t\t\tif (fseek(pfile_in_zip_read_info->file,\n\t\t\t\t\t\t  pfile_in_zip_read_info->pos_in_zipfile + \n\t\t\t\t\t\t\t pfile_in_zip_read_info->byte_before_the_zipfile,SEEK_SET)!=0)\n\t\t\t\t\treturn UNZ_ERRNO;\n\t\t\tif (fread(pfile_in_zip_read_info->read_buffer,uReadThis,1,\n                         pfile_in_zip_read_info->file)!=1)\n\t\t\t\treturn UNZ_ERRNO;\n\t\t\tpfile_in_zip_read_info->pos_in_zipfile += uReadThis;\n\n\t\t\tpfile_in_zip_read_info->rest_read_compressed-=uReadThis;\n\t\t\t\n\t\t\tpfile_in_zip_read_info->stream.next_in = \n                (Byte*)pfile_in_zip_read_info->read_buffer;\n\t\t\tpfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis;\n\t\t}\n\n\t\tif (pfile_in_zip_read_info->compression_method==0)\n\t\t{\n\t\t\tuInt uDoCopy,i ;\n\t\t\tif (pfile_in_zip_read_info->stream.avail_out < \n                            pfile_in_zip_read_info->stream.avail_in)\n\t\t\t\tuDoCopy = pfile_in_zip_read_info->stream.avail_out ;\n\t\t\telse\n\t\t\t\tuDoCopy = pfile_in_zip_read_info->stream.avail_in ;\n\t\t\t\t\n\t\t\tfor (i=0;i<uDoCopy;i++)\n\t\t\t\t*(pfile_in_zip_read_info->stream.next_out+i) =\n                        *(pfile_in_zip_read_info->stream.next_in+i);\n\t\t\t\t\t\n//\t\t\tpfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,\n//\t\t\t\t\t\t\t\tpfile_in_zip_read_info->stream.next_out,\n//\t\t\t\t\t\t\t\tuDoCopy);\n\t\t\tpfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy;\n\t\t\tpfile_in_zip_read_info->stream.avail_in -= uDoCopy;\n\t\t\tpfile_in_zip_read_info->stream.avail_out -= uDoCopy;\n\t\t\tpfile_in_zip_read_info->stream.next_out += uDoCopy;\n\t\t\tpfile_in_zip_read_info->stream.next_in += uDoCopy;\n            pfile_in_zip_read_info->stream.total_out += uDoCopy;\n\t\t\tiRead += uDoCopy;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tuLong uTotalOutBefore,uTotalOutAfter;\n\t\t\tconst Byte *bufBefore;\n\t\t\tuLong uOutThis;\n\t\t\tint flush=Z_SYNC_FLUSH;\n\n\t\t\tuTotalOutBefore = pfile_in_zip_read_info->stream.total_out;\n\t\t\tbufBefore = pfile_in_zip_read_info->stream.next_out;\n\n\t\t\t/*\n\t\t\tif ((pfile_in_zip_read_info->rest_read_uncompressed ==\n\t\t\t         pfile_in_zip_read_info->stream.avail_out) &&\n\t\t\t\t(pfile_in_zip_read_info->rest_read_compressed == 0))\n\t\t\t\tflush = Z_FINISH;\n\t\t\t*/\n\t\t\terr=inflate(&pfile_in_zip_read_info->stream,flush);\n\n\t\t\tuTotalOutAfter = pfile_in_zip_read_info->stream.total_out;\n\t\t\tuOutThis = uTotalOutAfter-uTotalOutBefore;\n\t\t\t\n//\t\t\tpfile_in_zip_read_info->crc32 = \n//                crc32(pfile_in_zip_read_info->crc32,bufBefore,\n//                        (uInt)(uOutThis));\n\n\t\t\tpfile_in_zip_read_info->rest_read_uncompressed -=\n                uOutThis;\n\n\t\t\tiRead += (uInt)(uTotalOutAfter - uTotalOutBefore);\n            \n\t\t\tif (err==Z_STREAM_END)\n\t\t\t\treturn (iRead==0) ? UNZ_EOF : iRead;\n\t\t\tif (err!=Z_OK) \n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (err==Z_OK)\n\t\treturn iRead;\n\treturn err;\n}\n\n\n/*\n  Give the current position in uncompressed data\n*/\nextern long unztell (unzFile file)\n{\n\tunz_s* s;\n\tfile_in_zip_read_info_s* pfile_in_zip_read_info;\n\tif (file==NULL)\n\t\treturn UNZ_PARAMERROR;\n\ts=(unz_s*)file;\n    pfile_in_zip_read_info=s->pfile_in_zip_read;\n\n\tif (pfile_in_zip_read_info==NULL)\n\t\treturn UNZ_PARAMERROR;\n\n\treturn (long)pfile_in_zip_read_info->stream.total_out;\n}\n\n\n/*\n  return 1 if the end of file was reached, 0 elsewhere \n*/\nextern int unzeof (unzFile file)\n{\n\tunz_s* s;\n\tfile_in_zip_read_info_s* pfile_in_zip_read_info;\n\tif (file==NULL)\n\t\treturn UNZ_PARAMERROR;\n\ts=(unz_s*)file;\n    pfile_in_zip_read_info=s->pfile_in_zip_read;\n\n\tif (pfile_in_zip_read_info==NULL)\n\t\treturn UNZ_PARAMERROR;\n\t\n\tif (pfile_in_zip_read_info->rest_read_uncompressed == 0)\n\t\treturn 1;\n\telse\n\t\treturn 0;\n}\n\n\n\n/*\n  Read extra field from the current file (opened by unzOpenCurrentFile)\n  This is the static-header version of the extra field (sometimes, there is\n    more info in the static-header version than in the central-header)\n\n  if buf==NULL, it return the size of the static extra field that can be read\n\n  if buf!=NULL, len is the size of the buffer, the extra header is copied in\n\tbuf.\n  the return value is the number of bytes copied in buf, or (if <0) \n\tthe error code\n*/\nextern int unzGetLocalExtrafield (unzFile file,void *buf,unsigned len)\n{\n\tunz_s* s;\n\tfile_in_zip_read_info_s* pfile_in_zip_read_info;\n\tuInt read_now;\n\tuLong size_to_read;\n\n\tif (file==NULL)\n\t\treturn UNZ_PARAMERROR;\n\ts=(unz_s*)file;\n    pfile_in_zip_read_info=s->pfile_in_zip_read;\n\n\tif (pfile_in_zip_read_info==NULL)\n\t\treturn UNZ_PARAMERROR;\n\n\tsize_to_read = (pfile_in_zip_read_info->size_local_extrafield - \n\t\t\t\tpfile_in_zip_read_info->pos_local_extrafield);\n\n\tif (buf==NULL)\n\t\treturn (int)size_to_read;\n\t\n\tif (len>size_to_read)\n\t\tread_now = (uInt)size_to_read;\n\telse\n\t\tread_now = (uInt)len ;\n\n\tif (read_now==0)\n\t\treturn 0;\n\t\n\tif (fseek(pfile_in_zip_read_info->file,\n              pfile_in_zip_read_info->offset_local_extrafield + \n\t\t\t  pfile_in_zip_read_info->pos_local_extrafield,SEEK_SET)!=0)\n\t\treturn UNZ_ERRNO;\n\n\tif (fread(buf,(uInt)size_to_read,1,pfile_in_zip_read_info->file)!=1)\n\t\treturn UNZ_ERRNO;\n\n\treturn (int)read_now;\n}\n\n/*\n  Close the file in zip opened with unzipOpenCurrentFile\n  Return UNZ_CRCERROR if all the file was read but the CRC is not good\n*/\nextern int unzCloseCurrentFile (unzFile file)\n{\n\tint err=UNZ_OK;\n\n\tunz_s* s;\n\tfile_in_zip_read_info_s* pfile_in_zip_read_info;\n\tif (file==NULL)\n\t\treturn UNZ_PARAMERROR;\n\ts=(unz_s*)file;\n    pfile_in_zip_read_info=s->pfile_in_zip_read;\n\n\tif (pfile_in_zip_read_info==NULL)\n\t\treturn UNZ_PARAMERROR;\n\n/*\n\tif (pfile_in_zip_read_info->rest_read_uncompressed == 0)\n\t{\n\t\tif (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait)\n\t\t\terr=UNZ_CRCERROR;\n\t}\n*/\n\n\tTRYFREE(pfile_in_zip_read_info->read_buffer);\n\tpfile_in_zip_read_info->read_buffer = NULL;\n\tif (pfile_in_zip_read_info->stream_initialised)\n\t\tinflateEnd(&pfile_in_zip_read_info->stream);\n\n\tpfile_in_zip_read_info->stream_initialised = 0;\n\tTRYFREE(pfile_in_zip_read_info);\n\n    s->pfile_in_zip_read=NULL;\n\n\treturn err;\n}\n\n\n/*\n  Get the global comment string of the ZipFile, in the szComment buffer.\n  uSizeBuf is the size of the szComment buffer.\n  return the number of byte copied or an error code <0\n*/\nextern int unzGetGlobalComment (unzFile file, char *szComment, uLong uSizeBuf)\n{\n\tunz_s* s;\n\tuLong uReadThis ;\n\tif (file==NULL)\n\t\treturn UNZ_PARAMERROR;\n\ts=(unz_s*)file;\n\n\tuReadThis = uSizeBuf;\n\tif (uReadThis>s->gi.size_comment)\n\t\tuReadThis = s->gi.size_comment;\n\n\tif (fseek(s->file,s->central_pos+22,SEEK_SET)!=0)\n\t\treturn UNZ_ERRNO;\n\n\tif (uReadThis>0)\n    {\n      *szComment='\\0';\n\t  if (fread(szComment,(uInt)uReadThis,1,s->file)!=1)\n\t\treturn UNZ_ERRNO;\n    }\n\n\tif ((szComment != NULL) && (uSizeBuf > s->gi.size_comment))\n\t\t*(szComment+s->gi.size_comment)='\\0';\n\treturn (int)uReadThis;\n}\n\n/* infblock.h -- header to use infblock.c\n * Copyright (C) 1995-1998 Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h \n */\n\n/* WARNING: this file should *not* be used by applications. It is\n   part of the implementation of the compression library and is\n   subject to change. Applications should only use zlib.h.\n */\n\nstruct inflate_blocks_state;\ntypedef struct inflate_blocks_state inflate_blocks_statef;\n\nstatic inflate_blocks_statef * inflate_blocks_new OF((\n    z_streamp z,\n    check_func c,               /* check function */\n    uInt w));                   /* window size */\n\nstatic int inflate_blocks OF((\n    inflate_blocks_statef *,\n    z_streamp ,\n    int));                      /* initial return code */\n\nstatic void inflate_blocks_reset OF((\n    inflate_blocks_statef *,\n    z_streamp ,\n    uLong *));                  /* check value on output */\n\nstatic int inflate_blocks_free OF((\n    inflate_blocks_statef *,\n    z_streamp));\n\n#if 0\nstatic void inflate_set_dictionary OF((\n    inflate_blocks_statef *s,\n    const Byte *d,  /* dictionary */\n    uInt  n));       /* dictionary length */\n\nstatic int inflate_blocks_sync_point OF((\n    inflate_blocks_statef *s));\n#endif\n\n/* simplify the use of the inflate_huft type with some defines */\n#define exop word.what.Exop\n#define bits word.what.Bits\n\n/* Table for deflate from PKZIP's appnote.txt. */\nstatic const uInt border[] = { /* Order of the bit length code lengths */\n        16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};\n\n/* inftrees.h -- header to use inftrees.c\n * Copyright (C) 1995-1998 Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h \n */\n\n/* WARNING: this file should *not* be used by applications. It is\n   part of the implementation of the compression library and is\n   subject to change. Applications should only use zlib.h.\n */\n\n/* Huffman code lookup table entry--this entry is four bytes for machines\n   that have 16-bit pointers (e.g. PC's in the small or medium model). */\n\ntypedef struct inflate_huft_s inflate_huft;\n\nstruct inflate_huft_s {\n  union {\n    struct {\n      Byte Exop;        /* number of extra bits or operation */\n      Byte Bits;        /* number of bits in this code or subcode */\n    } what;\n    uInt pad;           /* pad structure to a power of 2 (4 bytes for */\n  } word;               /*  16-bit, 8 bytes for 32-bit int's) */\n  uInt base;            /* literal, length base, distance base,\n                           or table offset */\n};\n\n/* Maximum size of dynamic tree.  The maximum found in a long but non-\n   exhaustive search was 1004 huft structures (850 for length/literals\n   and 154 for distances, the latter actually the result of an\n   exhaustive search).  The actual maximum is not known, but the\n   value below is more than safe. */\n#define MANY 1440\n\nstatic  int inflate_trees_bits OF((\n    uInt *,                    /* 19 code lengths */\n    uInt *,                    /* bits tree desired/actual depth */\n    inflate_huft * *,       /* bits tree result */\n    inflate_huft *,             /* space for trees */\n    z_streamp));                /* for messages */\n\nstatic  int inflate_trees_dynamic OF((\n    uInt,                       /* number of literal/length codes */\n    uInt,                       /* number of distance codes */\n    uInt *,                    /* that many (total) code lengths */\n    uInt *,                    /* literal desired/actual bit depth */\n    uInt *,                    /* distance desired/actual bit depth */\n    inflate_huft * *,       /* literal/length tree result */\n    inflate_huft * *,       /* distance tree result */\n    inflate_huft *,             /* space for trees */\n    z_streamp));                /* for messages */\n\nstatic  int inflate_trees_fixed OF((\n    uInt *,                    /* literal desired/actual bit depth */\n    uInt *,                    /* distance desired/actual bit depth */\n    inflate_huft * *,       /* literal/length tree result */\n    inflate_huft * *,       /* distance tree result */\n    z_streamp));                /* for memory allocation */\n\n\n/* infcodes.h -- header to use infcodes.c\n * Copyright (C) 1995-1998 Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h \n */\n\n/* WARNING: this file should *not* be used by applications. It is\n   part of the implementation of the compression library and is\n   subject to change. Applications should only use zlib.h.\n */\n\nstruct inflate_codes_state;\ntypedef struct inflate_codes_state inflate_codes_statef;\n\nstatic inflate_codes_statef *inflate_codes_new OF((\n    uInt, uInt,\n    inflate_huft *, inflate_huft *,\n    z_streamp ));\n\nstatic  int inflate_codes OF((\n    inflate_blocks_statef *,\n    z_streamp ,\n    int));\n\nstatic  void inflate_codes_free OF((\n    inflate_codes_statef *,\n    z_streamp ));\n\n/* infutil.h -- types and macros common to blocks and codes\n * Copyright (C) 1995-1998 Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h \n */\n\n/* WARNING: this file should *not* be used by applications. It is\n   part of the implementation of the compression library and is\n   subject to change. Applications should only use zlib.h.\n */\n\n#ifndef _INFUTIL_H\n#define _INFUTIL_H\n\ntypedef enum {\n      TYPE,     /* get type bits (3, including end bit) */\n      LENS,     /* get lengths for stored */\n      STORED,   /* processing stored block */\n      TABLE,    /* get table lengths */\n      BTREE,    /* get bit lengths tree for a dynamic block */\n      DTREE,    /* get length, distance trees for a dynamic block */\n      CODES,    /* processing fixed or dynamic block */\n      DRY,      /* output remaining window bytes */\n      DONE,     /* finished last block, done */\n      BAD}      /* got a data error--stuck here */\ninflate_block_mode;\n\n/* inflate blocks semi-private state */\nstruct inflate_blocks_state {\n\n  /* mode */\n  inflate_block_mode  mode;     /* current inflate_block mode */\n\n  /* mode dependent information */\n  union {\n    uInt left;          /* if STORED, bytes left to copy */\n    struct {\n      uInt table;               /* table lengths (14 bits) */\n      uInt index;               /* index into blens (or border) */\n      uInt *blens;             /* bit lengths of codes */\n      uInt bb;                  /* bit length tree depth */\n      inflate_huft *tb;         /* bit length decoding tree */\n    } trees;            /* if DTREE, decoding info for trees */\n    struct {\n      inflate_codes_statef \n         *codes;\n    } decode;           /* if CODES, current state */\n  } sub;                /* submode */\n  uInt last;            /* true if this block is the last block */\n\n  /* mode independent information */\n  uInt bitk;            /* bits in bit buffer */\n  uLong bitb;           /* bit buffer */\n  inflate_huft *hufts;  /* single malloc for tree space */\n  Byte *window;        /* sliding window */\n  Byte *end;           /* one byte after sliding window */\n  Byte *read;          /* window read pointer */\n  Byte *write;         /* window write pointer */\n  check_func checkfn;   /* check function */\n  uLong check;          /* check on output */\n\n};\n\n\n/* defines for inflate input/output */\n/*   update pointers and return */\n#define UPDBITS {s->bitb=b;s->bitk=k;}\n#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;}\n#define UPDOUT {s->write=q;}\n#define UPDATE {UPDBITS UPDIN UPDOUT}\n#define LEAVE {UPDATE return inflate_flush(s,z,r);}\n/*   get bytes and bits */\n#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;}\n#define NEEDBYTE {if(n)r=Z_OK;else LEAVE}\n#define NEXTBYTE (n--,*p++)\n#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<<k;k+=8;}}\n#define DUMPBITS(j) {b>>=(j);k-=(j);}\n/*   output bytes */\n#define WAVAIL (uInt)(q<s->read?s->read-q-1:s->end-q)\n#define LOADOUT {q=s->write;m=(uInt)WAVAIL;}\n#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}}\n#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT}\n#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;}\n#define OUTBYTE(a) {*q++=(Byte)(a);m--;}\n/*   load static pointers */\n#define LOAD {LOADIN LOADOUT}\n\n/* masks for lower bits (size given to avoid silly warnings with Visual C++) */\n//static  uInt inflate_mask[17];\nstatic uInt inflate_mask[17] = {\n\t0x0000,\n\t0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,\n\t0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff\n};\n\n/* copy as much as possible from the sliding window to the output area */\nstatic  int inflate_flush OF((\n    inflate_blocks_statef *,\n    z_streamp ,\n    int));\n\n#endif\n\n\t\t\t\t\t\t\t\t\n/*\n   Notes beyond the 1.93a appnote.txt:\n\n   1. Distance pointers never point before the beginning of the output\n      stream.\n   2. Distance pointers can point back across blocks, up to 32k away.\n   3. There is an implied maximum of 7 bits for the bit length table and\n      15 bits for the actual data.\n   4. If only one code exists, then it is encoded using one bit.  (Zero\n      would be more efficient, but perhaps a little confusing.)  If two\n      codes exist, they are coded using one bit each (0 and 1).\n   5. There is no way of sending zero distance codes--a dummy must be\n      sent if there are none.  (History: a pre 2.0 version of PKZIP would\n      store blocks with no distance codes, but this was discovered to be\n      too harsh a criterion.)  Valid only for 1.93a.  2.04c does allow\n      zero distance codes, which is sent as one code of zero bits in\n      length.\n   6. There are up to 286 literal/length codes.  Code 256 represents the\n      end-of-block.  Note however that the static length tree defines\n      288 codes just to fill out the Huffman codes.  Codes 286 and 287\n      cannot be used though, since there is no length base or extra bits\n      defined for them.  Similarily, there are up to 30 distance codes.\n      However, static trees define 32 codes (all 5 bits) to fill out the\n      Huffman codes, but the last two had better not show up in the data.\n   7. Unzip can check dynamic Huffman blocks for complete code sets.\n      The exception is that a single code would not be complete (see #4).\n   8. The five bits following the block type is really the number of\n      literal codes sent minus 257.\n   9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits\n      (1+6+6).  Therefore, to output three times the length, you output\n      three codes (1+1+1), whereas to output four times the same length,\n      you only need two codes (1+3).  Hmm.\n  10. In the tree reconstruction algorithm, Code = Code + Increment\n      only if BitLength(i) is not zero.  (Pretty obvious.)\n  11. Correction: 4 Bits: # of Bit Length codes - 4     (4 - 19)\n  12. Note: length code 284 can represent 227-258, but length code 285\n      really is 258.  The last length deserves its own, short code\n      since it gets used a lot in very redundant files.  The length\n      258 is special since 258 - 3 (the min match length) is 255.\n  13. The literal/length and distance code bit lengths are read as a\n      single stream of lengths.  It is possible (and advantageous) for\n      a repeat code (16, 17, or 18) to go across the boundary between\n      the two sets of lengths.\n */\n\n\nvoid inflate_blocks_reset(inflate_blocks_statef *s, z_streamp z, uLong *c)\n{\n  if (c != Z_NULL)\n    *c = s->check;\n  if (s->mode == BTREE || s->mode == DTREE)\n    ZFREE(z, s->sub.trees.blens);\n  if (s->mode == CODES)\n    inflate_codes_free(s->sub.decode.codes, z);\n  s->mode = TYPE;\n  s->bitk = 0;\n  s->bitb = 0;\n  s->read = s->write = s->window;\n  if (s->checkfn != Z_NULL)\n    z->adler = s->check = (*s->checkfn)(0L, (const Byte *)Z_NULL, 0);\n  Tracev((\"inflate:   blocks reset\\n\"));\n}\n\n\ninflate_blocks_statef *inflate_blocks_new(z_streamp z, check_func c, uInt w)\n{\n  inflate_blocks_statef *s;\n\n  if ((s = (inflate_blocks_statef *)ZALLOC\n       (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL)\n    return s;\n  if ((s->hufts =\n       (inflate_huft *)ZALLOC(z, sizeof(inflate_huft), MANY)) == Z_NULL)\n  {\n    ZFREE(z, s);\n    return Z_NULL;\n  }\n  if ((s->window = (Byte *)ZALLOC(z, 1, w)) == Z_NULL)\n  {\n    ZFREE(z, s->hufts);\n    ZFREE(z, s);\n    return Z_NULL;\n  }\n  s->end = s->window + w;\n  s->checkfn = c;\n  s->mode = TYPE;\n  Tracev((\"inflate:   blocks allocated\\n\"));\n  inflate_blocks_reset(s, z, Z_NULL);\n  return s;\n}\n\n\nint inflate_blocks(inflate_blocks_statef *s, z_streamp z, int r)\n{\n  uInt t;               /* temporary storage */\n  uLong b;              /* bit buffer */\n  uInt k;               /* bits in bit buffer */\n  Byte *p;             /* input data pointer */\n  uInt n;               /* bytes available there */\n  Byte *q;             /* output window write pointer */\n  uInt m;               /* bytes to end of window or read pointer */\n\n  /* copy input/output information to locals (UPDATE macro restores) */\n  LOAD\n\n  /* process input based on current state */\n  while (1) switch (s->mode)\n  {\n    case TYPE:\n      NEEDBITS(3)\n      t = (uInt)b & 7;\n      s->last = t & 1;\n      switch (t >> 1)\n      {\n        case 0:                         /* stored */\n          Tracev((\"inflate:     stored block%s\\n\",\n                 s->last ? \" (last)\" : \"\"));\n          DUMPBITS(3)\n          t = k & 7;                    /* go to byte boundary */\n          DUMPBITS(t)\n          s->mode = LENS;               /* get length of stored block */\n          break;\n        case 1:                         /* fixed */\n          Tracev((\"inflate:     fixed codes block%s\\n\",\n                 s->last ? \" (last)\" : \"\"));\n          {\n            uInt bl, bd;\n            inflate_huft *tl, *td;\n            inflate_trees_fixed(&bl, &bd, &tl, &td, z);\n            s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z);\n            if (s->sub.decode.codes == Z_NULL)\n            {\n              r = Z_MEM_ERROR;\n              LEAVE\n            }\n          }\n          DUMPBITS(3)\n          s->mode = CODES;\n          break;\n        case 2:                         /* dynamic */\n          Tracev((\"inflate:     dynamic codes block%s\\n\",\n                 s->last ? \" (last)\" : \"\"));\n          DUMPBITS(3)\n          s->mode = TABLE;\n          break;\n        case 3:                         /* illegal */\n          DUMPBITS(3)\n          s->mode = BAD;\n          z->msg = (char*)\"invalid block type\";\n          r = Z_DATA_ERROR;\n          LEAVE\n      }\n      break;\n    case LENS:\n      NEEDBITS(32)\n      if ((((~b) >> 16) & 0xffff) != (b & 0xffff))\n      {\n        s->mode = BAD;\n        z->msg = (char*)\"invalid stored block lengths\";\n        r = Z_DATA_ERROR;\n        LEAVE\n      }\n      s->sub.left = (uInt)b & 0xffff;\n      b = k = 0;                      /* dump bits */\n      Tracev((\"inflate:       stored length %u\\n\", s->sub.left));\n      s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE);\n      break;\n    case STORED:\n      if (n == 0)\n        LEAVE\n      NEEDOUT\n      t = s->sub.left;\n      if (t > n) t = n;\n      if (t > m) t = m;\n      zmemcpy(q, p, t);\n      p += t;  n -= t;\n      q += t;  m -= t;\n      if ((s->sub.left -= t) != 0)\n        break;\n      Tracev((\"inflate:       stored end, %lu total out\\n\",\n              z->total_out + (q >= s->read ? q - s->read :\n              (s->end - s->read) + (q - s->window))));\n      s->mode = s->last ? DRY : TYPE;\n      break;\n    case TABLE:\n      NEEDBITS(14)\n      s->sub.trees.table = t = (uInt)b & 0x3fff;\n#ifndef PKZIP_BUG_WORKAROUND\n      if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29)\n      {\n        s->mode = BAD;\n        z->msg = (char*)\"too many length or distance symbols\";\n        r = Z_DATA_ERROR;\n        LEAVE\n      }\n#endif\n      t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);\n      if ((s->sub.trees.blens = (uInt*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL)\n      {\n        r = Z_MEM_ERROR;\n        LEAVE\n      }\n      DUMPBITS(14)\n      s->sub.trees.index = 0;\n      Tracev((\"inflate:       table sizes ok\\n\"));\n      s->mode = BTREE;\n    case BTREE:\n      while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10))\n      {\n        NEEDBITS(3)\n        s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7;\n        DUMPBITS(3)\n      }\n      while (s->sub.trees.index < 19)\n        s->sub.trees.blens[border[s->sub.trees.index++]] = 0;\n      s->sub.trees.bb = 7;\n      t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb,\n                             &s->sub.trees.tb, s->hufts, z);\n      if (t != Z_OK)\n      {\n        ZFREE(z, s->sub.trees.blens);\n        r = t;\n        if (r == Z_DATA_ERROR)\n          s->mode = BAD;\n        LEAVE\n      }\n      s->sub.trees.index = 0;\n      Tracev((\"inflate:       bits tree ok\\n\"));\n      s->mode = DTREE;\n    case DTREE:\n      while (t = s->sub.trees.table,\n             s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))\n      {\n        inflate_huft *h;\n        uInt i, j, c;\n\n        t = s->sub.trees.bb;\n        NEEDBITS(t)\n        h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]);\n        t = h->bits;\n        c = h->base;\n        if (c < 16)\n        {\n          DUMPBITS(t)\n          s->sub.trees.blens[s->sub.trees.index++] = c;\n        }\n        else /* c == 16..18 */\n        {\n          i = c == 18 ? 7 : c - 14;\n          j = c == 18 ? 11 : 3;\n          NEEDBITS(t + i)\n          DUMPBITS(t)\n          j += (uInt)b & inflate_mask[i];\n          DUMPBITS(i)\n          i = s->sub.trees.index;\n          t = s->sub.trees.table;\n          if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) ||\n              (c == 16 && i < 1))\n          {\n            ZFREE(z, s->sub.trees.blens);\n            s->mode = BAD;\n            z->msg = (char*)\"invalid bit length repeat\";\n            r = Z_DATA_ERROR;\n            LEAVE\n          }\n          c = c == 16 ? s->sub.trees.blens[i - 1] : 0;\n          do {\n            s->sub.trees.blens[i++] = c;\n          } while (--j);\n          s->sub.trees.index = i;\n        }\n      }\n      s->sub.trees.tb = Z_NULL;\n      {\n        uInt bl, bd;\n        inflate_huft *tl, *td;\n        inflate_codes_statef *c;\n\n        tl = NULL;\n        td = NULL;\n        bl = 9;         /* must be <= 9 for lookahead assumptions */\n        bd = 6;         /* must be <= 9 for lookahead assumptions */\n        t = s->sub.trees.table;\n        t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f),\n                                  s->sub.trees.blens, &bl, &bd, &tl, &td,\n                                  s->hufts, z);\n        ZFREE(z, s->sub.trees.blens);\n        if (t != Z_OK)\n        {\n          if (t == (uInt)Z_DATA_ERROR)\n            s->mode = BAD;\n          r = t;\n          LEAVE\n        }\n        Tracev((\"inflate:       trees ok\\n\"));\n        if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL)\n        {\n          r = Z_MEM_ERROR;\n          LEAVE\n        }\n        s->sub.decode.codes = c;\n      }\n      s->mode = CODES;\n    case CODES:\n      UPDATE\n      if ((r = inflate_codes(s, z, r)) != Z_STREAM_END)\n        return inflate_flush(s, z, r);\n      r = Z_OK;\n      inflate_codes_free(s->sub.decode.codes, z);\n      LOAD\n      Tracev((\"inflate:       codes end, %lu total out\\n\",\n              z->total_out + (q >= s->read ? q - s->read :\n              (s->end - s->read) + (q - s->window))));\n      if (!s->last)\n      {\n        s->mode = TYPE;\n        break;\n      }\n      s->mode = DRY;\n    case DRY:\n      FLUSH\n      if (s->read != s->write)\n        LEAVE\n      s->mode = DONE;\n    case DONE:\n      r = Z_STREAM_END;\n      LEAVE\n    case BAD:\n      r = Z_DATA_ERROR;\n      LEAVE\n    default:\n      r = Z_STREAM_ERROR;\n      LEAVE\n  }\n}\n\n\nint inflate_blocks_free(inflate_blocks_statef *s, z_streamp z)\n{\n  inflate_blocks_reset(s, z, Z_NULL);\n  ZFREE(z, s->window);\n  ZFREE(z, s->hufts);\n  ZFREE(z, s);\n  Tracev((\"inflate:   blocks freed\\n\"));\n  return Z_OK;\n}\n\n#if 0\nvoid inflate_set_dictionary(inflate_blocks_statef *s, const Byte *d, uInt n)\n{\n  zmemcpy(s->window, d, n);\n  s->read = s->write = s->window + n;\n}\n\n/* Returns true if inflate is currently at the end of a block generated\n * by Z_SYNC_FLUSH or Z_FULL_FLUSH. \n * IN assertion: s != Z_NULL\n */\nint inflate_blocks_sync_point(inflate_blocks_statef *s)\n{\n  return s->mode == LENS;\n}\n#endif\n\n\n/* And'ing with mask[n] masks the lower n bits */\n/*\nstatic uInt inflate_mask[17] = {\n    0x0000,\n    0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,\n    0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff\n};\n*/\n\n\n/* copy as much as possible from the sliding window to the output area */\nint inflate_flush(inflate_blocks_statef *s, z_streamp z, int r)\n{\n  uInt n;\n  Byte *p;\n  Byte *q;\n\n  /* static copies of source and destination pointers */\n  p = z->next_out;\n  q = s->read;\n\n  /* compute number of bytes to copy as as end of window */\n  n = (uInt)((q <= s->write ? s->write : s->end) - q);\n  if (n > z->avail_out) n = z->avail_out;\n  if (n && r == Z_BUF_ERROR) r = Z_OK;\n\n  /* update counters */\n  z->avail_out -= n;\n  z->total_out += n;\n\n  /* update check information */\n  if (s->checkfn != Z_NULL)\n    z->adler = s->check = (*s->checkfn)(s->check, q, n);\n\n  /* copy as as end of window */\n  zmemcpy(p, q, n);\n  p += n;\n  q += n;\n\n  /* see if more to copy at beginning of window */\n  if (q == s->end)\n  {\n    /* wrap pointers */\n    q = s->window;\n    if (s->write == s->end)\n      s->write = s->window;\n\n    /* compute bytes to copy */\n    n = (uInt)(s->write - q);\n    if (n > z->avail_out) n = z->avail_out;\n    if (n && r == Z_BUF_ERROR) r = Z_OK;\n\n    /* update counters */\n    z->avail_out -= n;\n    z->total_out += n;\n\n    /* update check information */\n    if (s->checkfn != Z_NULL)\n      z->adler = s->check = (*s->checkfn)(s->check, q, n);\n\n    /* copy */\n    zmemcpy(p, q, n);\n    p += n;\n    q += n;\n  }\n\n  /* update pointers */\n  z->next_out = p;\n  s->read = q;\n\n  /* done */\n  return r;\n}\n\n/* inftrees.c -- generate Huffman trees for efficient decoding\n * Copyright (C) 1995-1998 Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h \n */\n\nstatic const char inflate_copyright[] =\n   \" inflate 1.1.3 Copyright 1995-1998 Mark Adler \";\n/*\n  If you use the zlib library in a product, an acknowledgment is welcome\n  in the documentation of your product. If for some reason you cannot\n  include such an acknowledgment, I would appreciate that you keep this\n  copyright string in the executable of your product.\n */\n\n/* simplify the use of the inflate_huft type with some defines */\n#define exop word.what.Exop\n#define bits word.what.Bits\n\n\nstatic int huft_build OF((\n    uInt *,\t\t\t\t/* code lengths in bits */\n    uInt,               /* number of codes */\n    uInt,               /* number of \"simple\" codes */\n    const uInt *,\t\t/* list of base values for non-simple codes */\n    const uInt *,\t\t/* list of extra bits for non-simple codes */\n    inflate_huft **,\t/* result: starting table */\n    uInt *,\t\t\t\t/* maximum lookup bits (returns actual) */\n    inflate_huft *,     /* space for trees */\n    uInt *,             /* hufts used in space */\n    uInt * ));\t\t\t/* space for values */\n\n/* Tables for deflate from PKZIP's appnote.txt. */\nstatic const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */\n        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,\n        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};\n        /* see note #13 above about 258 */\nstatic const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */\n        0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,\n        3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */\nstatic const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */\n        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,\n        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,\n        8193, 12289, 16385, 24577};\nstatic const uInt cpdext[30] = { /* Extra bits for distance codes */\n        0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,\n        7, 7, 8, 8, 9, 9, 10, 10, 11, 11,\n        12, 12, 13, 13};\n\n/*\n   Huffman code decoding is performed using a multi-level table lookup.\n   The fastest way to decode is to simply build a lookup table whose\n   size is determined by the longest code.  However, the time it takes\n   to build this table can also be a factor if the data being decoded\n   is not very long.  The most common codes are necessarily the\n   shortest codes, so those codes dominate the decoding time, and hence\n   the speed.  The idea is you can have a shorter table that decodes the\n   shorter, more probable codes, and then point to subsidiary tables for\n   the longer codes.  The time it costs to decode the longer codes is\n   then traded against the time it takes to make longer tables.\n\n   This results of this trade are in the variables lbits and dbits\n   below.  lbits is the number of bits the first level table for literal/\n   length codes can decode in one step, and dbits is the same thing for\n   the distance codes.  Subsequent tables are also less than or equal to\n   those sizes.  These values may be adjusted either when all of the\n   codes are shorter than that, in which case the longest code length in\n   bits is used, or when the shortest code is *longer* than the requested\n   table size, in which case the length of the shortest code in bits is\n   used.\n\n   There are two different values for the two tables, since they code a\n   different number of possibilities each.  The literal/length table\n   codes 286 possible values, or in a flat code, a little over eight\n   bits.  The distance table codes 30 possible values, or a little less\n   than five bits, flat.  The optimum values for speed end up being\n   about one bit more than those, so lbits is 8+1 and dbits is 5+1.\n   The optimum values may differ though from machine to machine, and\n   possibly even between compilers.  Your mileage may vary.\n */\n\n\n/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */\n#define BMAX 15         /* maximum bit length of any code */\n\nstatic int huft_build(uInt *b, uInt n, uInt s, const uInt *d, const uInt *e, inflate_huft ** t, uInt *m, inflate_huft *hp, uInt *hn, uInt *v)\n//uInt *b;               /* code lengths in bits (all assumed <= BMAX) */\n//uInt n;                 /* number of codes (assumed <= 288) */\n//uInt s;                 /* number of simple-valued codes (0..s-1) */\n//const uInt *d;         /* list of base values for non-simple codes */\n//const uInt *e;         /* list of extra bits for non-simple codes */\n//inflate_huft ** t;\t\t/* result: starting table */\n//uInt *m;               /* maximum lookup bits, returns actual */\n//inflate_huft *hp;       /* space for trees */\n//uInt *hn;               /* hufts used in space */\n//uInt *v;               /* working area: values in order of bit length */\n/* Given a list of code lengths and a maximum table size, make a set of\n   tables to decode that set of codes.  Return Z_OK on success, Z_BUF_ERROR\n   if the given code set is incomplete (the tables are still built in this\n   case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of\n   lengths), or Z_MEM_ERROR if not enough memory. */\n{\n\n  uInt a;                       /* counter for codes of length k */\n  uInt c[BMAX+1];               /* bit length count table */\n  uInt f;                       /* i repeats in table every f entries */\n  int g;                        /* maximum code length */\n  int h;                        /* table level */\n  register uInt i;              /* counter, current code */\n  register uInt j;              /* counter */\n  register int k;               /* number of bits in current code */\n  int l;                        /* bits per table (returned in m) */\n  uInt mask;                    /* (1 << w) - 1, to avoid cc -O bug on HP */\n  register uInt *p;            /* pointer into c[], b[], or v[] */\n  inflate_huft *q;              /* points to current table */\n  struct inflate_huft_s r;      /* table entry for structure assignment */\n  inflate_huft *u[BMAX];        /* table stack */\n  register int w;               /* bits before this table == (l * h) */\n  uInt x[BMAX+1];               /* bit offsets, then code stack */\n  uInt *xp;                    /* pointer into x */\n  int y;                        /* number of dummy codes added */\n  uInt z;                       /* number of entries in current table */\n\n\n  /* Generate counts for each bit length */\n  p = c;\n#define C0 *p++ = 0;\n#define C2 C0 C0 C0 C0\n#define C4 C2 C2 C2 C2\n  C4                            /* clear c[]--assume BMAX+1 is 16 */\n  p = b;  i = n;\n  do {\n    c[*p++]++;                  /* assume all entries <= BMAX */\n  } while (--i);\n  if (c[0] == n)                /* null input--all zero length codes */\n  {\n    *t = (inflate_huft *)Z_NULL;\n    *m = 0;\n    return Z_OK;\n  }\n\n\n  /* Find minimum and maximum length, bound *m by those */\n  l = *m;\n  for (j = 1; j <= BMAX; j++)\n    if (c[j])\n      break;\n  k = j;                        /* minimum code length */\n  if ((uInt)l < j)\n    l = j;\n  for (i = BMAX; i; i--)\n    if (c[i])\n      break;\n  g = i;                        /* maximum code length */\n  if ((uInt)l > i)\n    l = i;\n  *m = l;\n\n\n  /* Adjust last length count to fill out codes, if needed */\n  for (y = 1 << j; j < i; j++, y <<= 1)\n    if ((y -= c[j]) < 0)\n      return Z_DATA_ERROR;\n  if ((y -= c[i]) < 0)\n    return Z_DATA_ERROR;\n  c[i] += y;\n\n\n  /* Generate starting offsets into the value table for each length */\n  x[1] = j = 0;\n  p = c + 1;  xp = x + 2;\n  while (--i) {                 /* note that i == g from above */\n    *xp++ = (j += *p++);\n  }\n\n\n  /* Make a table of values in order of bit lengths */\n  p = b;  i = 0;\n  do {\n    if ((j = *p++) != 0)\n      v[x[j]++] = i;\n  } while (++i < n);\n  n = x[g];                     /* set n to length of v */\n\n\n  /* Generate the Huffman codes and for each, make the table entries */\n  x[0] = i = 0;                 /* first Huffman code is zero */\n  p = v;                        /* grab values in bit order */\n  h = -1;                       /* no tables yet--level -1 */\n  w = -l;                       /* bits decoded == (l * h) */\n  u[0] = (inflate_huft *)Z_NULL;        /* just to keep compilers happy */\n  q = (inflate_huft *)Z_NULL;   /* ditto */\n  z = 0;                        /* ditto */\n\n  /* go through the bit lengths (k already is bits in shortest code) */\n  for (; k <= g; k++)\n  {\n    a = c[k];\n    while (a--)\n    {\n      /* here i is the Huffman code of length k bits for value *p */\n      /* make tables up to required level */\n      while (k > w + l)\n      {\n        h++;\n        w += l;                 /* previous table always l bits */\n\n        /* compute minimum size table less than or equal to l bits */\n        z = g - w;\n        z = z > (uInt)l ? l : z;        /* table size upper limit */\n        if ((f = 1 << (j = k - w)) > a + 1)     /* try a k-w bit table */\n        {                       /* too few codes for k-w bit table */\n          f -= a + 1;           /* deduct codes from patterns left */\n          xp = c + k;\n          if (j < z)\n            while (++j < z)     /* try smaller tables up to z bits */\n            {\n              if ((f <<= 1) <= *++xp)\n                break;          /* enough codes to use up j bits */\n              f -= *xp;         /* else deduct codes from patterns */\n            }\n        }\n        z = 1 << j;             /* table entries for j-bit table */\n\n        /* allocate new table */\n        if (*hn + z > MANY)     /* (note: doesn't matter for fixed) */\n          return Z_MEM_ERROR;   /* not enough memory */\n        u[h] = q = hp + *hn;\n        *hn += z;\n\n        /* connect to last table, if there is one */\n        if (h)\n        {\n          x[h] = i;             /* save pattern for backing up */\n          r.bits = (Byte)l;     /* bits to dump before this table */\n          r.exop = (Byte)j;     /* bits in this table */\n          j = i >> (w - l);\n          r.base = (uInt)(q - u[h-1] - j);   /* offset to this table */\n          u[h-1][j] = r;        /* connect to last table */\n        }\n        else\n          *t = q;               /* first table is returned result */\n      }\n\n      /* set up table entry in r */\n      r.bits = (Byte)(k - w);\n      if (p >= v + n)\n        r.exop = 128 + 64;      /* out of values--invalid code */\n      else if (*p < s)\n      {\n        r.exop = (Byte)(*p < 256 ? 0 : 32 + 64);     /* 256 is end-of-block */\n        r.base = *p++;          /* simple code is just the value */\n      }\n      else\n      {\n        r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */\n        r.base = d[*p++ - s];\n      }\n\n      /* fill code-like entries with r */\n      f = 1 << (k - w);\n      for (j = i >> w; j < z; j += f)\n        q[j] = r;\n\n      /* backwards increment the k-bit code i */\n      for (j = 1 << (k - 1); i & j; j >>= 1)\n        i ^= j;\n      i ^= j;\n\n      /* backup over finished tables */\n      mask = (1 << w) - 1;      /* needed on HP, cc -O bug */\n      while ((i & mask) != x[h])\n      {\n        h--;                    /* don't need to update q */\n        w -= l;\n        mask = (1 << w) - 1;\n      }\n    }\n  }\n\n\n  /* Return Z_BUF_ERROR if we were given an incomplete table */\n  return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;\n}\n\n\nint inflate_trees_bits(uInt *c, uInt *bb, inflate_huft * *tb, inflate_huft *hp, z_streamp z)\n//uInt *c;               /* 19 code lengths */\n//uInt *bb;              /* bits tree desired/actual depth */\n//inflate_huft * *tb; /* bits tree result */\n//inflate_huft *hp;       /* space for trees */\n//z_streamp z;            /* for messages */\n{\n  int r;\n  uInt hn = 0;          /* hufts used in space */\n  uInt *v;             /* work area for huft_build */\n\n  if ((v = (uInt*)ZALLOC(z, 19, sizeof(uInt))) == Z_NULL)\n    return Z_MEM_ERROR;\n  r = huft_build(c, 19, 19, (uInt*)Z_NULL, (uInt*)Z_NULL,\n                 tb, bb, hp, &hn, v);\n  if (r == Z_DATA_ERROR)\n    z->msg = (char*)\"oversubscribed dynamic bit lengths tree\";\n  else if (r == Z_BUF_ERROR || *bb == 0)\n  {\n    z->msg = (char*)\"incomplete dynamic bit lengths tree\";\n    r = Z_DATA_ERROR;\n  }\n  ZFREE(z, v);\n  return r;\n}\n\n\nint inflate_trees_dynamic(uInt nl, uInt nd, uInt *c, uInt *bl, uInt *bd, inflate_huft * *tl, inflate_huft * *td, inflate_huft *hp, z_streamp z)\n//uInt nl;                /* number of literal/length codes */\n//uInt nd;                /* number of distance codes */\n//uInt *c;               /* that many (total) code lengths */\n//uInt *bl;              /* literal desired/actual bit depth */\n//uInt *bd;              /* distance desired/actual bit depth */\n//inflate_huft * *tl; /* literal/length tree result */\n//inflate_huft * *td; /* distance tree result */\n//inflate_huft *hp;       /* space for trees */\n//z_streamp z;            /* for messages */\n{\n  int r;\n  uInt hn = 0;          /* hufts used in space */\n  uInt *v;             /* work area for huft_build */\n\n  /* allocate work area */\n  if ((v = (uInt*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL)\n    return Z_MEM_ERROR;\n\n  /* build literal/length tree */\n  r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v);\n  if (r != Z_OK || *bl == 0)\n  {\n    if (r == Z_DATA_ERROR)\n      z->msg = (char*)\"oversubscribed literal/length tree\";\n    else if (r != Z_MEM_ERROR)\n    {\n      z->msg = (char*)\"incomplete literal/length tree\";\n      r = Z_DATA_ERROR;\n    }\n    ZFREE(z, v);\n    return r;\n  }\n\n  /* build distance tree */\n  r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v);\n  if (r != Z_OK || (*bd == 0 && nl > 257))\n  {\n    if (r == Z_DATA_ERROR)\n      z->msg = (char*)\"oversubscribed distance tree\";\n    else if (r == Z_BUF_ERROR) {\n#ifdef PKZIP_BUG_WORKAROUND\n      r = Z_OK;\n    }\n#else\n      z->msg = (char*)\"incomplete distance tree\";\n      r = Z_DATA_ERROR;\n    }\n    else if (r != Z_MEM_ERROR)\n    {\n      z->msg = (char*)\"empty distance tree with lengths\";\n      r = Z_DATA_ERROR;\n    }\n    ZFREE(z, v);\n    return r;\n#endif\n  }\n\n  /* done */\n  ZFREE(z, v);\n  return Z_OK;\n}\n\n/* inffixed.h -- table for decoding fixed codes\n * Generated automatically by the maketree.c program\n */\n\n/* WARNING: this file should *not* be used by applications. It is\n   part of the implementation of the compression library and is\n   subject to change. Applications should only use zlib.h.\n */\n\nstatic uInt fixed_bl = 9;\nstatic uInt fixed_bd = 5;\nstatic inflate_huft fixed_tl[] = {\n    {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115},\n    {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},192},\n    {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},160},\n    {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},224},\n    {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},144},\n    {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},208},\n    {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},176},\n    {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},240},\n    {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227},\n    {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},200},\n    {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},168},\n    {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},232},\n    {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},152},\n    {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},216},\n    {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},184},\n    {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},248},\n    {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163},\n    {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},196},\n    {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},164},\n    {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},228},\n    {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},148},\n    {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},212},\n    {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},180},\n    {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},244},\n    {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0},\n    {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},204},\n    {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},172},\n    {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},236},\n    {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},156},\n    {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},220},\n    {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},188},\n    {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},252},\n    {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131},\n    {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},194},\n    {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},162},\n    {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},226},\n    {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},146},\n    {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},210},\n    {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},178},\n    {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},242},\n    {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258},\n    {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},202},\n    {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},170},\n    {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},234},\n    {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},154},\n    {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},218},\n    {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},186},\n    {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},250},\n    {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195},\n    {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},198},\n    {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},166},\n    {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},230},\n    {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},150},\n    {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},214},\n    {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},182},\n    {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},246},\n    {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0},\n    {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},206},\n    {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},174},\n    {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},238},\n    {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},158},\n    {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},222},\n    {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},190},\n    {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},254},\n    {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115},\n    {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},193},\n    {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},161},\n    {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},225},\n    {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},145},\n    {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},209},\n    {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},177},\n    {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},241},\n    {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227},\n    {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},201},\n    {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},169},\n    {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},233},\n    {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},153},\n    {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},217},\n    {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},185},\n    {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},249},\n    {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163},\n    {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},197},\n    {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},165},\n    {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},229},\n    {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},149},\n    {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},213},\n    {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},181},\n    {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},245},\n    {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0},\n    {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},205},\n    {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},173},\n    {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},237},\n    {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},157},\n    {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},221},\n    {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},189},\n    {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},253},\n    {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131},\n    {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},195},\n    {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},163},\n    {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},227},\n    {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},147},\n    {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},211},\n    {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},179},\n    {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},243},\n    {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258},\n    {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},203},\n    {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},171},\n    {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},235},\n    {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},155},\n    {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},219},\n    {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},187},\n    {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},251},\n    {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195},\n    {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},199},\n    {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},167},\n    {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},231},\n    {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},151},\n    {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},215},\n    {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},183},\n    {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},247},\n    {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0},\n    {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},207},\n    {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},175},\n    {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},239},\n    {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},159},\n    {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},223},\n    {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},191},\n    {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},255}\n  };\nstatic inflate_huft fixed_td[] = {\n    {{{80,5}},1}, {{{87,5}},257}, {{{83,5}},17}, {{{91,5}},4097},\n    {{{81,5}},5}, {{{89,5}},1025}, {{{85,5}},65}, {{{93,5}},16385},\n    {{{80,5}},3}, {{{88,5}},513}, {{{84,5}},33}, {{{92,5}},8193},\n    {{{82,5}},9}, {{{90,5}},2049}, {{{86,5}},129}, {{{192,5}},24577},\n    {{{80,5}},2}, {{{87,5}},385}, {{{83,5}},25}, {{{91,5}},6145},\n    {{{81,5}},7}, {{{89,5}},1537}, {{{85,5}},97}, {{{93,5}},24577},\n    {{{80,5}},4}, {{{88,5}},769}, {{{84,5}},49}, {{{92,5}},12289},\n    {{{82,5}},13}, {{{90,5}},3073}, {{{86,5}},193}, {{{192,5}},24577}\n  };\n\nint inflate_trees_fixed(uInt *bl, uInt *bd, inflate_huft * *tl, inflate_huft * *td, z_streamp z)\n//uInt *bl;               /* literal desired/actual bit depth */\n//uInt *bd;               /* distance desired/actual bit depth */\n//inflate_huft * *tl;  /* literal/length tree result */\n//inflate_huft * *td;  /* distance tree result */\n//z_streamp z;             /* for memory allocation */\n{\n  *bl = fixed_bl;\n  *bd = fixed_bd;\n  *tl = fixed_tl;\n  *td = fixed_td;\n  return Z_OK;\n}\n\n/* simplify the use of the inflate_huft type with some defines */\n#define exop word.what.Exop\n#define bits word.what.Bits\n\n/* macros for bit input with no checking and for returning unused bytes */\n#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<<k;k+=8;}}\n#define UNGRAB {c=z->avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3;}\n\n/* Called with number of bytes left to write in window at least 258\n   (the maximum string length) and number of input bytes available\n   at least ten.  The ten bytes are six bytes for the longest length/\n   distance pair plus four bytes for overloading the bit buffer. */\n\nstatic int inflate_fast(uInt bl, uInt bd, inflate_huft *tl, inflate_huft *td, inflate_blocks_statef *s, z_streamp z)\n{\n  inflate_huft *t;      /* temporary pointer */\n  uInt e;               /* extra bits or operation */\n  uLong b;              /* bit buffer */\n  uInt k;               /* bits in bit buffer */\n  Byte *p;             /* input data pointer */\n  uInt n;               /* bytes available there */\n  Byte *q;             /* output window write pointer */\n  uInt m;               /* bytes to end of window or read pointer */\n  uInt ml;              /* mask for literal/length tree */\n  uInt md;              /* mask for distance tree */\n  uInt c;               /* bytes to copy */\n  uInt d;               /* distance back to copy from */\n  Byte *r;             /* copy source pointer */\n\n  /* load input, output, bit values */\n  LOAD\n\n  /* initialize masks */\n  ml = inflate_mask[bl];\n  md = inflate_mask[bd];\n\n  /* do until not enough input or output space for fast loop */\n  do {                          /* assume called with m >= 258 && n >= 10 */\n    /* get literal/length code */\n    GRABBITS(20)                /* max bits for literal/length code */\n    if ((e = (t = tl + ((uInt)b & ml))->exop) == 0)\n    {\n      DUMPBITS(t->bits)\n      Tracevv((t->base >= 0x20 && t->base < 0x7f ?\n                \"inflate:         * literal '%c'\\n\" :\n                \"inflate:         * literal 0x%02x\\n\", t->base));\n      *q++ = (Byte)t->base;\n      m--;\n      continue;\n    }\n    do {\n      DUMPBITS(t->bits)\n      if (e & 16)\n      {\n        /* get extra bits for length */\n        e &= 15;\n        c = t->base + ((uInt)b & inflate_mask[e]);\n        DUMPBITS(e)\n        Tracevv((\"inflate:         * length %u\\n\", c));\n\n        /* decode distance base of block to copy */\n        GRABBITS(15);           /* max bits for distance code */\n        e = (t = td + ((uInt)b & md))->exop;\n        do {\n          DUMPBITS(t->bits)\n          if (e & 16)\n          {\n            /* get extra bits to add to distance base */\n            e &= 15;\n            GRABBITS(e)         /* get extra bits (up to 13) */\n            d = t->base + ((uInt)b & inflate_mask[e]);\n            DUMPBITS(e)\n            Tracevv((\"inflate:         * distance %u\\n\", d));\n\n            /* do the copy */\n            m -= c;\n            if ((uInt)(q - s->window) >= d)     /* offset before dest */\n            {                                   /*  just copy */\n              r = q - d;\n              *q++ = *r++;  c--;        /* minimum count is three, */\n              *q++ = *r++;  c--;        /*  so unroll loop a little */\n            }\n            else                        /* else offset after destination */\n            {\n              e = d - (uInt)(q - s->window); /* bytes from offset to end */\n              r = s->end - e;           /* pointer to offset */\n              if (c > e)                /* if source crosses, */\n              {\n                c -= e;                 /* copy to end of window */\n                do {\n                  *q++ = *r++;\n                } while (--e);\n                r = s->window;          /* copy rest from start of window */\n              }\n            }\n            do {                        /* copy all or what's left */\n              *q++ = *r++;\n            } while (--c);\n            break;\n          }\n          else if ((e & 64) == 0)\n          {\n            t += t->base;\n            e = (t += ((uInt)b & inflate_mask[e]))->exop;\n          }\n          else\n          {\n            z->msg = (char*)\"invalid distance code\";\n            UNGRAB\n            UPDATE\n            return Z_DATA_ERROR;\n          }\n        } while (1);\n        break;\n      }\n      if ((e & 64) == 0)\n      {\n        t += t->base;\n        if ((e = (t += ((uInt)b & inflate_mask[e]))->exop) == 0)\n        {\n          DUMPBITS(t->bits)\n          Tracevv((t->base >= 0x20 && t->base < 0x7f ?\n                    \"inflate:         * literal '%c'\\n\" :\n                    \"inflate:         * literal 0x%02x\\n\", t->base));\n          *q++ = (Byte)t->base;\n          m--;\n          break;\n        }\n      }\n      else if (e & 32)\n      {\n        Tracevv((\"inflate:         * end of block\\n\"));\n        UNGRAB\n        UPDATE\n        return Z_STREAM_END;\n      }\n      else\n      {\n        z->msg = (char*)\"invalid literal/length code\";\n        UNGRAB\n        UPDATE\n        return Z_DATA_ERROR;\n      }\n    } while (1);\n  } while (m >= 258 && n >= 10);\n\n  /* not enough input or output--restore pointers and return */\n  UNGRAB\n  UPDATE\n  return Z_OK;\n}\n\n/* infcodes.c -- process literals and length/distance pairs\n * Copyright (C) 1995-1998 Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h \n */\n\n/* simplify the use of the inflate_huft type with some defines */\n#define exop word.what.Exop\n#define bits word.what.Bits\n\ntypedef enum {        /* waiting for \"i:\"=input, \"o:\"=output, \"x:\"=nothing */\n      START,    /* x: set up for LEN */\n      LEN,      /* i: get length/literal/eob next */\n      LENEXT,   /* i: getting length extra (have base) */\n      DIST,     /* i: get distance next */\n      DISTEXT,  /* i: getting distance extra */\n      COPY,     /* o: copying bytes in window, waiting for space */\n      LIT,      /* o: got literal, waiting for output space */\n      WASH,     /* o: got eob, possibly still output waiting */\n      END,      /* x: got eob and all data flushed */\n      BADCODE}  /* x: got error */\ninflate_codes_mode;\n\n/* inflate codes private state */\nstruct inflate_codes_state {\n\n  /* mode */\n  inflate_codes_mode mode;      /* current inflate_codes mode */\n\n  /* mode dependent information */\n  uInt len;\n  union {\n    struct {\n      inflate_huft *tree;       /* pointer into tree */\n      uInt need;                /* bits needed */\n    } code;             /* if LEN or DIST, where in tree */\n    uInt lit;           /* if LIT, literal */\n    struct {\n      uInt get;                 /* bits to get for extra */\n      uInt dist;                /* distance back to copy from */\n    } copy;             /* if EXT or COPY, where and how much */\n  } sub;                /* submode */\n\n  /* mode independent information */\n  Byte lbits;           /* ltree bits decoded per branch */\n  Byte dbits;           /* dtree bits decoder per branch */\n  inflate_huft *ltree;          /* literal/length/eob tree */\n  inflate_huft *dtree;          /* distance tree */\n\n};\n\n\ninflate_codes_statef *inflate_codes_new(uInt bl, uInt bd, inflate_huft *tl, inflate_huft *td, z_streamp z)\n{\n  inflate_codes_statef *c;\n\n  if ((c = (inflate_codes_statef *)\n       ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL)\n  {\n    c->mode = START;\n    c->lbits = (Byte)bl;\n    c->dbits = (Byte)bd;\n    c->ltree = tl;\n    c->dtree = td;\n    Tracev((\"inflate:       codes new\\n\"));\n  }\n  return c;\n}\n\n\nint inflate_codes(inflate_blocks_statef *s, z_streamp z, int r)\n{\n  uInt j;               /* temporary storage */\n  inflate_huft *t;      /* temporary pointer */\n  uInt e;               /* extra bits or operation */\n  uLong b;              /* bit buffer */\n  uInt k;               /* bits in bit buffer */\n  Byte *p;             /* input data pointer */\n  uInt n;               /* bytes available there */\n  Byte *q;             /* output window write pointer */\n  uInt m;               /* bytes to end of window or read pointer */\n  Byte *f;             /* pointer to copy strings from */\n  inflate_codes_statef *c = s->sub.decode.codes;  /* codes state */\n\n  /* copy input/output information to locals (UPDATE macro restores) */\n  LOAD\n\n  /* process input and output based on current state */\n  while (1) switch (c->mode)\n  {             /* waiting for \"i:\"=input, \"o:\"=output, \"x:\"=nothing */\n    case START:         /* x: set up for LEN */\n#ifndef SLOW\n      if (m >= 258 && n >= 10)\n      {\n        UPDATE\n        r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z);\n        LOAD\n        if (r != Z_OK)\n        {\n          c->mode = r == Z_STREAM_END ? WASH : BADCODE;\n          break;\n        }\n      }\n#endif /* !SLOW */\n      c->sub.code.need = c->lbits;\n      c->sub.code.tree = c->ltree;\n      c->mode = LEN;\n    case LEN:           /* i: get length/literal/eob next */\n      j = c->sub.code.need;\n      NEEDBITS(j)\n      t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);\n      DUMPBITS(t->bits)\n      e = (uInt)(t->exop);\n      if (e == 0)               /* literal */\n      {\n        c->sub.lit = t->base;\n        Tracevv((t->base >= 0x20 && t->base < 0x7f ?\n                 \"inflate:         literal '%c'\\n\" :\n                 \"inflate:         literal 0x%02x\\n\", t->base));\n        c->mode = LIT;\n        break;\n      }\n      if (e & 16)               /* length */\n      {\n        c->sub.copy.get = e & 15;\n        c->len = t->base;\n        c->mode = LENEXT;\n        break;\n      }\n      if ((e & 64) == 0)        /* next table */\n      {\n        c->sub.code.need = e;\n        c->sub.code.tree = t + t->base;\n        break;\n      }\n      if (e & 32)               /* end of block */\n      {\n        Tracevv((\"inflate:         end of block\\n\"));\n        c->mode = WASH;\n        break;\n      }\n      c->mode = BADCODE;        /* invalid code */\n      z->msg = (char*)\"invalid literal/length code\";\n      r = Z_DATA_ERROR;\n      LEAVE\n    case LENEXT:        /* i: getting length extra (have base) */\n      j = c->sub.copy.get;\n      NEEDBITS(j)\n      c->len += (uInt)b & inflate_mask[j];\n      DUMPBITS(j)\n      c->sub.code.need = c->dbits;\n      c->sub.code.tree = c->dtree;\n      Tracevv((\"inflate:         length %u\\n\", c->len));\n      c->mode = DIST;\n    case DIST:          /* i: get distance next */\n      j = c->sub.code.need;\n      NEEDBITS(j)\n      t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);\n      DUMPBITS(t->bits)\n      e = (uInt)(t->exop);\n      if (e & 16)               /* distance */\n      {\n        c->sub.copy.get = e & 15;\n        c->sub.copy.dist = t->base;\n        c->mode = DISTEXT;\n        break;\n      }\n      if ((e & 64) == 0)        /* next table */\n      {\n        c->sub.code.need = e;\n        c->sub.code.tree = t + t->base;\n        break;\n      }\n      c->mode = BADCODE;        /* invalid code */\n      z->msg = (char*)\"invalid distance code\";\n      r = Z_DATA_ERROR;\n      LEAVE\n    case DISTEXT:       /* i: getting distance extra */\n      j = c->sub.copy.get;\n      NEEDBITS(j)\n      c->sub.copy.dist += (uInt)b & inflate_mask[j];\n      DUMPBITS(j)\n      Tracevv((\"inflate:         distance %u\\n\", c->sub.copy.dist));\n      c->mode = COPY;\n    case COPY:          /* o: copying bytes in window, waiting for space */\n#ifndef __TURBOC__ /* Turbo C bug for following expression */\n      f = (uInt)(q - s->window) < c->sub.copy.dist ?\n          s->end - (c->sub.copy.dist - (q - s->window)) :\n          q - c->sub.copy.dist;\n#else\n      f = q - c->sub.copy.dist;\n      if ((uInt)(q - s->window) < c->sub.copy.dist)\n        f = s->end - (c->sub.copy.dist - (uInt)(q - s->window));\n#endif\n      while (c->len)\n      {\n        NEEDOUT\n        OUTBYTE(*f++)\n        if (f == s->end)\n          f = s->window;\n        c->len--;\n      }\n      c->mode = START;\n      break;\n    case LIT:           /* o: got literal, waiting for output space */\n      NEEDOUT\n      OUTBYTE(c->sub.lit)\n      c->mode = START;\n      break;\n    case WASH:          /* o: got eob, possibly more output */\n      if (k > 7)        /* return unused byte, if any */\n      {\n        Assert(k < 16, \"inflate_codes grabbed too many bytes\")\n        k -= 8;\n        n++;\n        p--;            /* can always return one */\n      }\n      FLUSH\n      if (s->read != s->write)\n        LEAVE\n      c->mode = END;\n    case END:\n      r = Z_STREAM_END;\n      LEAVE\n    case BADCODE:       /* x: got error */\n      r = Z_DATA_ERROR;\n      LEAVE\n    default:\n      r = Z_STREAM_ERROR;\n      LEAVE\n  }\n#ifdef NEED_DUMMY_RETURN\n  return Z_STREAM_ERROR;  /* Some dumb compilers complain without this */\n#endif\n}\n\n\nvoid inflate_codes_free(inflate_codes_statef *c, z_streamp z)\n{\n  ZFREE(z, c);\n  Tracev((\"inflate:       codes free\\n\"));\n}\n\n/* adler32.c -- compute the Adler-32 checksum of a data stream\n * Copyright (C) 1995-1998 Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h \n */\n\n#define BASE 65521L /* largest prime smaller than 65536 */\n#define NMAX 5552\n/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */\n\n#undef DO1\n#undef DO2\n#undef DO4\n#undef DO8\n\n#define DO1(buf,i)  {s1 += buf[i]; s2 += s1;}\n#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);\n#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);\n#define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);\n#define DO16(buf)   DO8(buf,0); DO8(buf,8);\n\n/* ========================================================================= */\nstatic uLong adler32(uLong adler, const Byte *buf, uInt len)\n{\n    unsigned long s1 = adler & 0xffff;\n    unsigned long s2 = (adler >> 16) & 0xffff;\n    int k;\n\n    if (buf == Z_NULL) return 1L;\n\n    while (len > 0) {\n        k = len < NMAX ? len : NMAX;\n        len -= k;\n        while (k >= 16) {\n            DO16(buf);\n\t    buf += 16;\n            k -= 16;\n        }\n        if (k != 0) do {\n            s1 += *buf++;\n\t    s2 += s1;\n        } while (--k);\n        s1 %= BASE;\n        s2 %= BASE;\n    }\n    return (s2 << 16) | s1;\n}\n\n\n/* infblock.h -- header to use infblock.c\n * Copyright (C) 1995-1998 Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h \n */\n\n/* WARNING: this file should *not* be used by applications. It is\n   part of the implementation of the compression library and is\n   subject to change. Applications should only use zlib.h.\n */\n\nstatic inflate_blocks_statef * inflate_blocks_new OF((\n    z_streamp z,\n    check_func c,               /* check function */\n    uInt w));                   /* window size */\n\nstatic int inflate_blocks OF((\n    inflate_blocks_statef *,\n    z_streamp ,\n    int));                      /* initial return code */\n\nstatic void inflate_blocks_reset OF((\n    inflate_blocks_statef *,\n    z_streamp ,\n    uLong *));                  /* check value on output */\n\nstatic int inflate_blocks_free OF((\n    inflate_blocks_statef *,\n    z_streamp));\n\n#if 0\nstatic void inflate_set_dictionary OF((\n    inflate_blocks_statef *s,\n    const Byte *d,  /* dictionary */\n    uInt  n));       /* dictionary length */\n\nstatic int inflate_blocks_sync_point OF((\n    inflate_blocks_statef *s));\n#endif\n\ntypedef enum {\n      imMETHOD,   /* waiting for method byte */\n      imFLAG,     /* waiting for flag byte */\n      imDICT4,    /* four dictionary check bytes to go */\n      imDICT3,    /* three dictionary check bytes to go */\n      imDICT2,    /* two dictionary check bytes to go */\n      imDICT1,    /* one dictionary check byte to go */\n      imDICT0,    /* waiting for inflateSetDictionary */\n      imBLOCKS,   /* decompressing blocks */\n      imCHECK4,   /* four check bytes to go */\n      imCHECK3,   /* three check bytes to go */\n      imCHECK2,   /* two check bytes to go */\n      imCHECK1,   /* one check byte to go */\n      imDONE,     /* finished check, done */\n      imBAD}      /* got an error--stay here */\ninflate_mode;\n\n/* inflate private state */\nstruct internal_state {\n\n  /* mode */\n  inflate_mode  mode;   /* current inflate mode */\n\n  /* mode dependent information */\n  union {\n    uInt method;        /* if FLAGS, method byte */\n    struct {\n      uLong was;                /* computed check value */\n      uLong need;               /* stream check value */\n    } check;            /* if CHECK, check values to compare */\n    uInt marker;        /* if BAD, inflateSync's marker bytes count */\n  } sub;        /* submode */\n\n  /* mode independent information */\n  int  nowrap;          /* flag for no wrapper */\n  uInt wbits;           /* log2(window size)  (8..15, defaults to 15) */\n  inflate_blocks_statef \n    *blocks;            /* current inflate_blocks state */\n\n};\n\n\nint inflateReset(z_streamp z)\n{\n  if (z == Z_NULL || z->state == Z_NULL)\n    return Z_STREAM_ERROR;\n  z->total_in = z->total_out = 0;\n  z->msg = Z_NULL;\n  z->state->mode = z->state->nowrap ? imBLOCKS : imMETHOD;\n  inflate_blocks_reset(z->state->blocks, z, Z_NULL);\n  Tracev((\"inflate: reset\\n\"));\n  return Z_OK;\n}\n\n\nint inflateEnd(z_streamp z)\n{\n  if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL)\n    return Z_STREAM_ERROR;\n  if (z->state->blocks != Z_NULL)\n    inflate_blocks_free(z->state->blocks, z);\n  ZFREE(z, z->state);\n  z->state = Z_NULL;\n  Tracev((\"inflate: end\\n\"));\n  return Z_OK;\n}\n\n\n\nint inflateInit2_(z_streamp z, int w, const char *version, int stream_size)\n{\n  if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||\n      stream_size != sizeof(z_stream))\n      return Z_VERSION_ERROR;\n\n  /* initialize state */\n  if (z == Z_NULL)\n    return Z_STREAM_ERROR;\n  z->msg = Z_NULL;\n  if (z->zalloc == Z_NULL)\n  {\n    z->zalloc = (void *(*)(void *, unsigned, unsigned))zcalloc;\n    z->opaque = (voidp)0;\n  }\n  if (z->zfree == Z_NULL) z->zfree = (void (*)(void *, void *))zcfree;\n  if ((z->state = (struct internal_state *)\n       ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL)\n    return Z_MEM_ERROR;\n  z->state->blocks = Z_NULL;\n\n  /* handle undocumented nowrap option (no zlib header or check) */\n  z->state->nowrap = 0;\n  if (w < 0)\n  {\n    w = - w;\n    z->state->nowrap = 1;\n  }\n\n  /* set window size */\n  if (w < 8 || w > 15)\n  {\n    inflateEnd(z);\n    return Z_STREAM_ERROR;\n  }\n  z->state->wbits = (uInt)w;\n\n  /* create inflate_blocks state */\n  if ((z->state->blocks =\n      inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w))\n      == Z_NULL)\n  {\n    inflateEnd(z);\n    return Z_MEM_ERROR;\n  }\n  Tracev((\"inflate: allocated\\n\"));\n\n  /* reset state */\n  inflateReset(z);\n  return Z_OK;\n}\n\n#if 0\nint inflateInit_(z_streamp z, const char *version, int stream_size)\n{\n  return inflateInit2_(z, DEF_WBITS, version, stream_size);\n}\n#endif\n\n#define iNEEDBYTE {if(z->avail_in==0)return r;r=f;}\n#define iNEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)\n\nint inflate(z_streamp z, int f)\n{\n  int r;\n  uInt b;\n\n  if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL)\n    return Z_STREAM_ERROR;\n  f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK;\n  r = Z_BUF_ERROR;\n  while (1) switch (z->state->mode)\n  {\n    case imMETHOD:\n      iNEEDBYTE\n      if (((z->state->sub.method = iNEXTBYTE) & 0xf) != Z_DEFLATED)\n      {\n        z->state->mode = imBAD;\n        z->msg = (char*)\"unknown compression method\";\n        z->state->sub.marker = 5;       /* can't try inflateSync */\n        break;\n      }\n      if ((z->state->sub.method >> 4) + 8 > z->state->wbits)\n      {\n        z->state->mode = imBAD;\n        z->msg = (char*)\"invalid window size\";\n        z->state->sub.marker = 5;       /* can't try inflateSync */\n        break;\n      }\n      z->state->mode = imFLAG;\n    case imFLAG:\n      iNEEDBYTE\n      b = iNEXTBYTE;\n      if (((z->state->sub.method << 8) + b) % 31)\n      {\n        z->state->mode = imBAD;\n        z->msg = (char*)\"incorrect header check\";\n        z->state->sub.marker = 5;       /* can't try inflateSync */\n        break;\n      }\n      Tracev((\"inflate: zlib header ok\\n\"));\n      if (!(b & PRESET_DICT))\n      {\n        z->state->mode = imBLOCKS;\n        break;\n      }\n      z->state->mode = imDICT4;\n    case imDICT4:\n      iNEEDBYTE\n      z->state->sub.check.need = (uLong)iNEXTBYTE << 24;\n      z->state->mode = imDICT3;\n    case imDICT3:\n      iNEEDBYTE\n      z->state->sub.check.need += (uLong)iNEXTBYTE << 16;\n      z->state->mode = imDICT2;\n    case imDICT2:\n      iNEEDBYTE\n      z->state->sub.check.need += (uLong)iNEXTBYTE << 8;\n      z->state->mode = imDICT1;\n    case imDICT1:\n      iNEEDBYTE\n      z->state->sub.check.need += (uLong)iNEXTBYTE;\n      z->adler = z->state->sub.check.need;\n      z->state->mode = imDICT0;\n      return Z_NEED_DICT;\n    case imDICT0:\n      z->state->mode = imBAD;\n      z->msg = (char*)\"need dictionary\";\n      z->state->sub.marker = 0;       /* can try inflateSync */\n      return Z_STREAM_ERROR;\n    case imBLOCKS:\n      r = inflate_blocks(z->state->blocks, z, r);\n      if (r == Z_DATA_ERROR)\n      {\n        z->state->mode = imBAD;\n        z->state->sub.marker = 0;       /* can try inflateSync */\n        break;\n      }\n      if (r == Z_OK)\n        r = f;\n      if (r != Z_STREAM_END)\n        return r;\n      r = f;\n      inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was);\n      if (z->state->nowrap)\n      {\n        z->state->mode = imDONE;\n        break;\n      }\n      z->state->mode = imCHECK4;\n    case imCHECK4:\n      iNEEDBYTE\n      z->state->sub.check.need = (uLong)iNEXTBYTE << 24;\n      z->state->mode = imCHECK3;\n    case imCHECK3:\n      iNEEDBYTE\n      z->state->sub.check.need += (uLong)iNEXTBYTE << 16;\n      z->state->mode = imCHECK2;\n    case imCHECK2:\n      iNEEDBYTE\n      z->state->sub.check.need += (uLong)iNEXTBYTE << 8;\n      z->state->mode = imCHECK1;\n    case imCHECK1:\n      iNEEDBYTE\n      z->state->sub.check.need += (uLong)iNEXTBYTE;\n\n      if (z->state->sub.check.was != z->state->sub.check.need)\n      {\n        z->state->mode = imBAD;\n        z->msg = (char*)\"incorrect data check\";\n        z->state->sub.marker = 5;       /* can't try inflateSync */\n        break;\n      }\n      Tracev((\"inflate: zlib check ok\\n\"));\n      z->state->mode = imDONE;\n    case imDONE:\n      return Z_STREAM_END;\n    case imBAD:\n      return Z_DATA_ERROR;\n    default:\n      return Z_STREAM_ERROR;\n  }\n#ifdef NEED_DUMMY_RETURN\n  return Z_STREAM_ERROR;  /* Some dumb compilers complain without this */\n#endif\n}\n\n// defined but not used\n#if 0\nint inflateSetDictionary(z_streamp z, const Byte *dictionary, uInt dictLength)\n{\n  uInt length = dictLength;\n\n  if (z == Z_NULL || z->state == Z_NULL || z->state->mode != imDICT0)\n    return Z_STREAM_ERROR;\n\n  if (adler32(1L, dictionary, dictLength) != z->adler) return Z_DATA_ERROR;\n  z->adler = 1L;\n\n  if (length >= ((uInt)1<<z->state->wbits))\n  {\n    length = (1<<z->state->wbits)-1;\n    dictionary += dictLength - length;\n  }\n  inflate_set_dictionary(z->state->blocks, dictionary, length);\n  z->state->mode = imBLOCKS;\n  return Z_OK;\n}\n\nint inflateSync(z_streamp z)\n{\n  uInt n;       /* number of bytes to look at */\n  Byte *p;     /* pointer to bytes */\n  uInt m;       /* number of marker bytes found in a row */\n  uLong r, w;   /* temporaries to save total_in and total_out */\n\n  /* set up */\n  if (z == Z_NULL || z->state == Z_NULL)\n    return Z_STREAM_ERROR;\n  if (z->state->mode != imBAD)\n  {\n    z->state->mode = imBAD;\n    z->state->sub.marker = 0;\n  }\n  if ((n = z->avail_in) == 0)\n    return Z_BUF_ERROR;\n  p = z->next_in;\n  m = z->state->sub.marker;\n\n  /* search */\n  while (n && m < 4)\n  {\n    static const Byte mark[4] = {0, 0, 0xff, 0xff};\n    if (*p == mark[m])\n      m++;\n    else if (*p)\n      m = 0;\n    else\n      m = 4 - m;\n    p++, n--;\n  }\n\n  /* restore */\n  z->total_in += p - z->next_in;\n  z->next_in = p;\n  z->avail_in = n;\n  z->state->sub.marker = m;\n\n  /* return no joy or set up to restart on a new block */\n  if (m != 4)\n    return Z_DATA_ERROR;\n  r = z->total_in;  w = z->total_out;\n  inflateReset(z);\n  z->total_in = r;  z->total_out = w;\n  z->state->mode = imBLOCKS;\n  return Z_OK;\n}\n\n/* Returns true if inflate is currently at the end of a block generated\n * by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP\n * implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH\n * but removes the length bytes of the resulting empty stored block. When\n * decompressing, PPP checks that at the end of input packet, inflate is\n * waiting for these length bytes.\n */\nint inflateSyncPoint(z_streamp z)\n{\n  if (z == Z_NULL || z->state == Z_NULL || z->state->blocks == Z_NULL)\n    return Z_STREAM_ERROR;\n  return inflate_blocks_sync_point(z->state->blocks);\n}\n#endif\n\nvoidp zcalloc (voidp opaque, unsigned items, unsigned size)\n{\n    if (opaque) items += size - size; /* make compiler happy */\n    return (voidp)Z_Malloc(items*size);\n}\n\nvoid  zcfree (voidp opaque, voidp ptr)\n{\n    Z_Free(ptr);\n    if (opaque) return; /* make compiler happy */\n}\n\n\n"
  },
  {
    "path": "src/engine/qcommon/unzip.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP)\n/* like the STRICT of WIN32, we define a pointer that cannot be converted\n    from (void*) without cast */\ntypedef struct TagunzFile__ { int unused; } unzFile__; \ntypedef unzFile__ *unzFile;\n#else\ntypedef void* unzFile;\n#endif\n\n/* tm_unz contain date/time info */\ntypedef struct tm_unz_s \n{\n\tunsigned int tm_sec;            /* seconds after the minute - [0,59] */\n\tunsigned int tm_min;            /* minutes after the hour - [0,59] */\n\tunsigned int tm_hour;           /* hours since midnight - [0,23] */\n\tunsigned int tm_mday;           /* day of the month - [1,31] */\n\tunsigned int tm_mon;            /* months since January - [0,11] */\n\tunsigned int tm_year;           /* years - [1980..2044] */\n} tm_unz;\n\n/* unz_global_info structure contain global data about the ZIPfile\n   These data comes from the end of central dir */\ntypedef struct unz_global_info_s\n{\n\tunsigned long number_entry;         /* total number of entries in the central dir on this disk */\n\tunsigned long size_comment;         /* size of the global comment of the zipfile */\n} unz_global_info;\n\n\n/* unz_file_info contain information about a file in the zipfile */\ntypedef struct unz_file_info_s\n{\n    unsigned long version;              /* version made by                 2 unsigned chars */\n    unsigned long version_needed;       /* version needed to extract       2 unsigned chars */\n    unsigned long flag;                 /* general purpose bit flag        2 unsigned chars */\n    unsigned long compression_method;   /* compression method              2 unsigned chars */\n    unsigned long dosDate;              /* last mod file date in Dos fmt   4 unsigned chars */\n    unsigned long crc;                  /* crc-32                          4 unsigned chars */\n    unsigned long compressed_size;      /* compressed size                 4 unsigned chars */ \n    unsigned long uncompressed_size;    /* uncompressed size               4 unsigned chars */ \n    unsigned long size_filename;        /* filename length                 2 unsigned chars */\n    unsigned long size_file_extra;      /* extra field length              2 unsigned chars */\n    unsigned long size_file_comment;    /* file comment length             2 unsigned chars */\n\n    unsigned long disk_num_start;       /* disk number start               2 unsigned chars */\n    unsigned long internal_fa;          /* internal file attributes        2 unsigned chars */\n    unsigned long external_fa;          /* external file attributes        4 unsigned chars */\n\n    tm_unz tmu_date;\n} unz_file_info;\n\n/* unz_file_info_interntal contain internal info about a file in zipfile*/\ntypedef struct unz_file_info_internal_s\n{\n    unsigned long offset_curfile;/* relative offset of static header 4 unsigned chars */\n} unz_file_info_internal;\n\ntypedef void* (*alloc_func) (void* opaque, unsigned int items, unsigned int size);\ntypedef void   (*free_func) (void* opaque, void* address);\n\nstruct internal_state;\n\ntypedef struct z_stream_s {\n    unsigned char    *next_in;  /* next input unsigned char */\n    unsigned int     avail_in;  /* number of unsigned chars available at next_in */\n    unsigned long    total_in;  /* total nb of input unsigned chars read so */\n\n    unsigned char    *next_out; /* next output unsigned char should be put there */\n    unsigned int     avail_out; /* remaining free space at next_out */\n    unsigned long    total_out; /* total nb of unsigned chars output so */\n\n    char     *msg;      /* last error message, NULL if no error */\n    struct internal_state *state; /* not visible by applications */\n\n    alloc_func zalloc;  /* used to allocate the internal state */\n    free_func  zfree;   /* used to free the internal state */\n    unsigned char*     opaque;  /* private data object passed to zalloc and zfree */\n\n    int     data_type;  /* best guess about the data type: ascii or binary */\n    unsigned long   adler;      /* adler32 value of the uncompressed data */\n    unsigned long   reserved;   /* reserved for future use */\n} z_stream;\n\ntypedef z_stream *z_streamp;\n\n\n/* file_in_zip_read_info_s contain internal information about a file in zipfile,\n    when reading and decompress it */\ntypedef struct\n{\n\tchar  *read_buffer;         /* internal buffer for compressed data */\n\tz_stream stream;            /* zLib stream structure for inflate */\n\n\tunsigned long pos_in_zipfile;       /* position in unsigned char on the zipfile, for fseek*/\n\tunsigned long stream_initialised;   /* flag set if stream structure is initialised*/\n\n\tunsigned long offset_local_extrafield;/* offset of the static extra field */\n\tunsigned int  size_local_extrafield;/* size of the static extra field */\n\tunsigned long pos_local_extrafield;   /* position in the static extra field in read*/\n\n\tunsigned long crc32;                /* crc32 of all data uncompressed */\n\tunsigned long crc32_wait;           /* crc32 we must obtain after decompress all */\n\tunsigned long rest_read_compressed; /* number of unsigned char to be decompressed */\n\tunsigned long rest_read_uncompressed;/*number of unsigned char to be obtained after decomp*/\n\tFILE* file;                 /* io structore of the zipfile */\n\tunsigned long compression_method;   /* compression method (0==store) */\n\tunsigned long byte_before_the_zipfile;/* unsigned char before the zipfile, (>0 for sfx)*/\n} file_in_zip_read_info_s;\n\n\n/* unz_s contain internal information about the zipfile\n*/\ntypedef struct\n{\n\tFILE* file;                 /* io structore of the zipfile */\n\tunz_global_info gi;       /* public global information */\n\tunsigned long byte_before_the_zipfile;/* unsigned char before the zipfile, (>0 for sfx)*/\n\tunsigned long num_file;             /* number of the current file in the zipfile*/\n\tunsigned long pos_in_central_dir;   /* pos of the current file in the central dir*/\n\tunsigned long current_file_ok;      /* flag about the usability of the current file*/\n\tunsigned long central_pos;          /* position of the beginning of the central dir*/\n\n\tunsigned long size_central_dir;     /* size of the central directory  */\n\tunsigned long offset_central_dir;   /* offset of start of central directory with\n\t\t\t\t\t\t\t\t   respect to the starting disk number */\n\n\tunz_file_info cur_file_info; /* public info about the current file in zip*/\n\tunz_file_info_internal cur_file_info_internal; /* private info about it*/\n    file_in_zip_read_info_s* pfile_in_zip_read; /* structure about the current\n\t                                    file if we are decompressing it */\n\tunsigned char*\ttmpFile;\n\tint\ttmpPos,tmpSize;\n} unz_s;\n\n#define UNZ_OK                                  (0)\n#define UNZ_END_OF_LIST_OF_FILE (-100)\n#define UNZ_ERRNO               (Z_ERRNO)\n#define UNZ_EOF                 (0)\n#define UNZ_PARAMERROR                  (-102)\n#define UNZ_BADZIPFILE                  (-103)\n#define UNZ_INTERNALERROR               (-104)\n#define UNZ_CRCERROR                    (-105)\n\n#define UNZ_CASESENSITIVE\t\t1\n#define UNZ_NOTCASESENSITIVE\t2\n#define UNZ_OSDEFAULTCASE\t\t0\n\nextern int unzStringFileNameCompare (const char* fileName1, const char* fileName2, int iCaseSensitivity);\n\n/*\n   Compare two filename (fileName1,fileName2).\n   If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)\n   If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi\n\t\t\t\t\t\t\t\tor strcasecmp)\n   If iCaseSenisivity = 0, case sensitivity is defaut of your operating system\n\t(like 1 on Unix, 2 on Windows)\n*/\n\nextern unzFile unzOpen (const char *path);\nextern unzFile unzReOpen (const char* path, unzFile file);\n\n/*\n  Open a Zip file. path contain the full pathname (by example,\n     on a Windows NT computer \"c:\\\\zlib\\\\zlib111.zip\" or on an Unix computer\n\t \"zlib/zlib111.zip\".\n\t If the zipfile cannot be opened (file don't exist or in not valid), the\n\t   return value is NULL.\n     Else, the return value is a unzFile Handle, usable with other function\n\t   of this unzip package.\n*/\n\nextern int unzClose (unzFile file);\n\n/*\n  Close a ZipFile opened with unzipOpen.\n  If there is files inside the .Zip opened with unzOpenCurrentFile (see later),\n    these files MUST be closed with unzipCloseCurrentFile before call unzipClose.\n  return UNZ_OK if there is no problem. */\n\nextern int unzGetGlobalInfo (unzFile file, unz_global_info *pglobal_info);\n\n/*\n  Write info about the ZipFile in the *pglobal_info structure.\n  No preparation of the structure is needed\n  return UNZ_OK if there is no problem. */\n\n\nextern int unzGetGlobalComment (unzFile file, char *szComment, unsigned long uSizeBuf);\n\n/*\n  Get the global comment string of the ZipFile, in the szComment buffer.\n  uSizeBuf is the size of the szComment buffer.\n  return the number of unsigned char copied or an error code <0\n*/\n\n\n/***************************************************************************/\n/* Unzip package allow you browse the directory of the zipfile */\n\nextern int unzGoToFirstFile (unzFile file);\n\n/*\n  Set the current file of the zipfile to the first file.\n  return UNZ_OK if there is no problem\n*/\n\nextern int unzGoToNextFile (unzFile file);\n\n/*\n  Set the current file of the zipfile to the next file.\n  return UNZ_OK if there is no problem\n  return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.\n*/\n\nextern int unzGetCurrentFileInfoPosition (unzFile file, unsigned long *pos );\n\n/*\n  Get the position of the info of the current file in the zip.\n  return UNZ_OK if there is no problem\n*/\n\nextern int unzSetCurrentFileInfoPosition (unzFile file, unsigned long pos );\n\n/*\n  Set the position of the info of the current file in the zip.\n  return UNZ_OK if there is no problem\n*/\n\nextern int unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity);\n\n/*\n  Try locate the file szFileName in the zipfile.\n  For the iCaseSensitivity signification, see unzStringFileNameCompare\n\n  return value :\n  UNZ_OK if the file is found. It becomes the current file.\n  UNZ_END_OF_LIST_OF_FILE if the file is not found\n*/\n\n\nextern int unzGetCurrentFileInfo (unzFile file, unz_file_info *pfile_info, char *szFileName, unsigned long fileNameBufferSize, void *extraField, unsigned long extraFieldBufferSize, char *szComment, unsigned long commentBufferSize);\n\n/*\n  Get Info about the current file\n  if pfile_info!=NULL, the *pfile_info structure will contain somes info about\n\t    the current file\n  if szFileName!=NULL, the filemane string will be copied in szFileName\n\t\t\t(fileNameBufferSize is the size of the buffer)\n  if extraField!=NULL, the extra field information will be copied in extraField\n\t\t\t(extraFieldBufferSize is the size of the buffer).\n\t\t\tThis is the Central-header version of the extra field\n  if szComment!=NULL, the comment string of the file will be copied in szComment\n\t\t\t(commentBufferSize is the size of the buffer)\n*/\n\n/***************************************************************************/\n/* for reading the content of the current zipfile, you can open it, read data\n   from it, and close it (you can close it before reading all the file)\n   */\n\nextern int unzOpenCurrentFile (unzFile file);\n\n/*\n  Open for reading data the current file in the zipfile.\n  If there is no error, the return value is UNZ_OK.\n*/\n\nextern int unzCloseCurrentFile (unzFile file);\n\n/*\n  Close the file in zip opened with unzOpenCurrentFile\n  Return UNZ_CRCERROR if all the file was read but the CRC is not good\n*/\n\n\t\t\t\t\t\t\t\t\t\t\t\t\nextern int unzReadCurrentFile (unzFile file, void* buf, unsigned len);\n\n/*\n  Read unsigned chars from the current file (opened by unzOpenCurrentFile)\n  buf contain buffer where data must be copied\n  len the size of buf.\n\n  return the number of unsigned char copied if somes unsigned chars are copied\n  return 0 if the end of file was reached\n  return <0 with error code if there is an error\n    (UNZ_ERRNO for IO error, or zLib error for uncompress error)\n*/\n\nextern long unztell(unzFile file);\n\n/*\n  Give the current position in uncompressed data\n*/\n\nextern int unzeof (unzFile file);\n\n/*\n  return 1 if the end of file was reached, 0 elsewhere \n*/\n\nextern int unzGetLocalExtrafield (unzFile file, void* buf, unsigned len);\n\n/*\n  Read extra field from the current file (opened by unzOpenCurrentFile)\n  This is the local-header version of the extra field (sometimes, there is\n    more info in the local-header version than in the central-header)\n\n  if buf==NULL, it return the size of the local extra field\n\n  if buf!=NULL, len is the size of the buffer, the extra header is copied in\n\tbuf.\n  the return value is the number of unsigned chars copied in buf, or (if <0) \n\tthe error code\n*/\n"
  },
  {
    "path": "src/engine/qcommon/vm.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n// vm.c -- virtual machine\n\n/*\n\n\nintermix code and data\nsymbol table\n\na dll has one imported function: VM_SystemCall\nand one exported function: Perform\n\n\n*/\n\n#include \"vm_local.h\"\n\n\nvm_t\t*currentVM = NULL; // bk001212\nvm_t\t*lastVM    = NULL; // bk001212\nint\t\tvm_debugLevel;\n\n#define\tMAX_VM\t\t3\nvm_t\tvmTable[MAX_VM];\n\n\nvoid VM_VmInfo_f( void );\nvoid VM_VmProfile_f( void );\n\nvoid VM_Debug( int level ) {\n\tvm_debugLevel = level;\n}\n\n/*\n==============\nVM_Init\n==============\n*/\nvoid VM_Init( void ) {\n\tCvar_Get( \"vm_cgame\", \"1\", CVAR_ARCHIVE );\n\tCvar_Get( \"vm_game\", \"1\", CVAR_ARCHIVE );\n\tCvar_Get( \"vm_ui\", \"1\", CVAR_ARCHIVE );\n\n\tCmd_AddCommand (\"vmprofile\", VM_VmProfile_f );\n\tCmd_AddCommand (\"vminfo\", VM_VmInfo_f );\n\n\tCom_Memset( vmTable, 0, sizeof( vmTable ) );\n}\n\n\n/*\n===============\nVM_ValueToSymbol\n\nAssumes a program counter value\n===============\n*/\nconst char *VM_ValueToSymbol( vm_t *vm, int value ) {\n\tvmSymbol_t\t*sym;\n\tstatic char\t\ttext[MAX_TOKEN_CHARS];\n\n\tsym = vm->symbols;\n\tif ( !sym ) {\n\t\treturn \"NO SYMBOLS\";\n\t}\n\n\t// find the symbol\n\twhile ( sym->next && sym->next->symValue <= value ) {\n\t\tsym = sym->next;\n\t}\n\n\tif ( value == sym->symValue ) {\n\t\treturn sym->symName;\n\t}\n\n\tCom_sprintf( text, sizeof( text ), \"%s+%i\", sym->symName, value - sym->symValue );\n\n\treturn text;\n}\n\n/*\n===============\nVM_ValueToFunctionSymbol\n\nFor profiling, find the symbol behind this value\n===============\n*/\nvmSymbol_t *VM_ValueToFunctionSymbol( vm_t *vm, int value ) {\n\tvmSymbol_t\t*sym;\n\tstatic vmSymbol_t\tnullSym;\n\n\tsym = vm->symbols;\n\tif ( !sym ) {\n\t\treturn &nullSym;\n\t}\n\n\twhile ( sym->next && sym->next->symValue <= value ) {\n\t\tsym = sym->next;\n\t}\n\n\treturn sym;\n}\n\n\n/*\n===============\nVM_SymbolToValue\n===============\n*/\nint VM_SymbolToValue( vm_t *vm, const char *symbol ) {\n\tvmSymbol_t\t*sym;\n\n\tfor ( sym = vm->symbols ; sym ; sym = sym->next ) {\n\t\tif ( !strcmp( symbol, sym->symName ) ) {\n\t\t\treturn sym->symValue;\n\t\t}\n\t}\n\treturn 0;\n}\n\n/*\n===============\nParseHex\n===============\n*/\nint\tParseHex( const char *text ) {\n\tint\t\tvalue;\n\tint\t\tc;\n\n\tvalue = 0;\n\twhile ( ( c = *text++ ) != 0 ) {\n\t\tif ( c >= '0' && c <= '9' ) {\n\t\t\tvalue = value * 16 + c - '0';\n\t\t\tcontinue;\n\t\t}\n\t\tif ( c >= 'a' && c <= 'f' ) {\n\t\t\tvalue = value * 16 + 10 + c - 'a';\n\t\t\tcontinue;\n\t\t}\n\t\tif ( c >= 'A' && c <= 'F' ) {\n\t\t\tvalue = value * 16 + 10 + c - 'A';\n\t\t\tcontinue;\n\t\t}\n\t}\n\n\treturn value;\n}\n\n/*\n===============\nVM_LoadSymbols\n===============\n*/\nvoid VM_LoadSymbols( vm_t *vm ) {\n\tint\t\tlen;\n\tchar\t*mapfile, *text_p, *token;\n\tchar\tname[MAX_QPATH];\n\tchar\tsymbols[MAX_QPATH];\n\tvmSymbol_t\t**prev, *sym;\n\tint\t\tcount;\n\tint\t\tvalue;\n\tint\t\tchars;\n\tint\t\tsegment;\n\tint\t\tnumInstructions;\n\n\t// don't load symbols if not developer\n\tif ( !com_developer->integer ) {\n\t\treturn;\n\t}\n\n\tCOM_StripExtension( vm->name, name );\n\tCom_sprintf( symbols, sizeof( symbols ), \"vm/%s.map\", name );\n\tlen = FS_ReadFile( symbols, (void **)&mapfile );\n\tif ( !mapfile ) {\n\t\tCom_Printf( \"Couldn't load symbol file: %s\\n\", symbols );\n\t\treturn;\n\t}\n\n\tnumInstructions = vm->instructionPointersLength >> 2;\n\n\t// parse the symbols\n\ttext_p = mapfile;\n\tprev = &vm->symbols;\n\tcount = 0;\n\n\twhile ( 1 ) {\n\t\ttoken = COM_Parse( &text_p );\n\t\tif ( !token[0] ) {\n\t\t\tbreak;\n\t\t}\n\t\tsegment = ParseHex( token );\n\t\tif ( segment ) {\n\t\t\tCOM_Parse( &text_p );\n\t\t\tCOM_Parse( &text_p );\n\t\t\tcontinue;\t\t// only load code segment values\n\t\t}\n\n\t\ttoken = COM_Parse( &text_p );\n\t\tif ( !token[0] ) {\n\t\t\tCom_Printf( \"WARNING: incomplete line at end of file\\n\" );\n\t\t\tbreak;\n\t\t}\n\t\tvalue = ParseHex( token );\n\n\t\ttoken = COM_Parse( &text_p );\n\t\tif ( !token[0] ) {\n\t\t\tCom_Printf( \"WARNING: incomplete line at end of file\\n\" );\n\t\t\tbreak;\n\t\t}\n\t\tchars = (int)strlen( token );\n\t\tsym = (vmSymbol_t*) Hunk_Alloc( sizeof( *sym ) + chars, h_high );\n\t\t*prev = sym;\n\t\tprev = &sym->next;\n\t\tsym->next = NULL;\n\n\t\t// convert value from an instruction number to a code offset\n\t\tif ( value >= 0 && value < numInstructions ) {\n\t\t\tvalue = vm->instructionPointers[value];\n\t\t}\n\n\t\tsym->symValue = value;\n\t\tQ_strncpyz( sym->symName, token, chars + 1 );\n\n\t\tcount++;\n\t}\n\n\tvm->numSymbols = count;\n\tCom_Printf( \"%i symbols parsed from %s\\n\", count, symbols );\n\tFS_FreeFile( mapfile );\n}\n\nintptr_t QDECL VM_DllSyscall( intptr_t arg, ... ) {\n  intptr_t args[MAX_VMSYSCALL_ARGS];\n  int i;\n  va_list ap;\n\n  args[0] = arg;\n  \n  va_start(ap, arg);\n  for (i = 1; i < ARRAY_LEN(args); i++)\n    args[i] = va_arg(ap, intptr_t);\n  va_end(ap);\n  \n  return currentVM->systemCall( args );\n}\n\n/*\n=================\nVM_Restart\n\nReload the data, but leave everything else in place\nThis allows a server to do a map_restart without changing memory allocation\n=================\n*/\nvm_t *VM_Restart( vm_t *vm ) {\n\tvmHeader_t\t*header;\n\tint\t\t\tlength;\n\tint\t\t\tdataLength;\n\tint\t\t\ti;\n\tchar\t\tfilename[MAX_QPATH];\n\n\t// DLL's can't be restarted in place\n\tif ( vm->dllHandle ) {\n\t\tchar\tname[MAX_QPATH];\n\t    intptr_t (*systemCall)( intptr_t *parms );\n\t\t\n\t\tsystemCall = vm->systemCall;\t\n\t\tQ_strncpyz( name, vm->name, sizeof( name ) );\n\n\t\tVM_Free( vm );\n\n\t\tvm = VM_Create( name, systemCall, VMI_NATIVE );\n\t\treturn vm;\n\t}\n\n\t// load the image\n\tCom_Printf( \"VM_Restart()\\n\", filename );\n\tCom_sprintf( filename, sizeof(filename), \"vm/%s.qvm\", vm->name );\n\tCom_Printf( \"Loading vm file %s.\\n\", filename );\n\tlength = FS_ReadFile( filename, (void **)&header );\n\tif ( !header ) {\n\t\tCom_Error( ERR_DROP, \"VM_Restart failed.\\n\" );\n\t}\n\n\t// byte swap the header\n\tfor ( i = 0 ; i < sizeof( *header ) / 4 ; i++ ) {\n\t\t((int *)header)[i] = LittleLong( ((int *)header)[i] );\n\t}\n\n\t// validate\n\tif ( header->vmMagic != VM_MAGIC\n\t\t|| header->bssLength < 0 \n\t\t|| header->dataLength < 0 \n\t\t|| header->litLength < 0 \n\t\t|| header->codeLength <= 0 ) {\n\t\tVM_Free( vm );\n\t\tCom_Error( ERR_FATAL, \"%s has bad header\", filename );\n\t}\n\n\t// round up to next power of 2 so all data operations can\n\t// be mask protected\n\tdataLength = header->dataLength + header->litLength + header->bssLength;\n\tfor ( i = 0 ; dataLength > ( 1 << i ) ; i++ ) {\n\t}\n\tdataLength = 1 << i;\n\n\t// clear the data\n\tCom_Memset( vm->dataBase, 0, dataLength );\n\n\t// copy the intialized data\n\tCom_Memcpy( vm->dataBase, (byte *)header + header->dataOffset, header->dataLength + header->litLength );\n\n\t// byte swap the longs\n\tfor ( i = 0 ; i < header->dataLength ; i += 4 ) {\n\t\t*(int *)(vm->dataBase + i) = LittleLong( *(int *)(vm->dataBase + i ) );\n\t}\n\n\t// free the original file\n\tFS_FreeFile( header );\n\n\treturn vm;\n}\n\n/*\n================\nVM_Create\n\nIf image ends in .qvm it will be interpreted, otherwise\nit will attempt to load as a system dll\n================\n*/\n\n#define\tSTACK_SIZE\t0x20000\n\nvm_t *VM_Create( const char *module, intptr_t (*systemCalls)(intptr_t *), \n\t\t\t\tvmInterpret_t interpret ) {\n\tvm_t\t\t*vm;\n\tvmHeader_t\t*header;\n\tint\t\t\tlength;\n\tint\t\t\tdataLength;\n\tint\t\t\ti, remaining;\n\tchar\t\tfilename[MAX_QPATH];\n\n\tif ( !module || !module[0] || !systemCalls ) {\n\t\tCom_Error( ERR_FATAL, \"VM_Create: bad parms\" );\n\t}\n\n\tremaining = Hunk_MemoryRemaining();\n\n\t// see if we already have the VM\n\tfor ( i = 0 ; i < MAX_VM ; i++ ) {\n\t\tif (!Q_stricmp(vmTable[i].name, module)) {\n\t\t\tvm = &vmTable[i];\n\t\t\treturn vm;\n\t\t}\n\t}\n\n\t// find a free vm\n\tfor ( i = 0 ; i < MAX_VM ; i++ ) {\n\t\tif ( !vmTable[i].name[0] ) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif ( i == MAX_VM ) {\n\t\tCom_Error( ERR_FATAL, \"VM_Create: no free vm_t\" );\n\t}\n\n\tvm = &vmTable[i];\n\n\tQ_strncpyz( vm->name, module, sizeof( vm->name ) );\n\tvm->systemCall = systemCalls;\n\n\t// never allow dll loading with a demo\n\tif ( interpret == VMI_NATIVE ) {\n\t\tif ( Cvar_VariableValue( \"fs_restrict\" ) ) {\n\t\t\tinterpret = VMI_BYTECODE;\n\t\t}\n\t}\n\n\tif ( interpret == VMI_NATIVE ) {\n\t\t// try to load as a system dll\n\t\tCom_Printf( \"Loading dll file %s.\\n\", vm->name );\n\t\tvm->dllHandle = Sys_LoadDll( module, vm->fqpath , &vm->entryPoint, VM_DllSyscall );\n\t\tif ( vm->dllHandle ) {\n\t\t\treturn vm;\n\t\t}\n\n\t\tCom_Printf( \"Failed to load dll, looking for qvm.\\n\" );\n\t}\n\n\t// load the image\n\tCom_sprintf( filename, sizeof(filename), \"vm/%s.qvm\", vm->name );\n\tCom_Printf( \"Loading vm file %s.\\n\", filename );\n\tlength = FS_ReadFile( filename, (void **)&header );\n\tif ( !header ) {\n\t\tCom_Printf( \"Failed.\\n\" );\n\t\tVM_Free( vm );\n\t\treturn NULL;\n\t}\n\n\t// byte swap the header\n\tfor ( i = 0 ; i < sizeof( *header ) / 4 ; i++ ) {\n\t\t((int *)header)[i] = LittleLong( ((int *)header)[i] );\n\t}\n\n\t// validate\n\tif ( header->vmMagic != VM_MAGIC\n\t\t|| header->bssLength < 0 \n\t\t|| header->dataLength < 0 \n\t\t|| header->litLength < 0 \n\t\t|| header->codeLength <= 0 ) {\n\t\tVM_Free( vm );\n\t\tCom_Error( ERR_FATAL, \"%s has bad header\", filename );\n\t}\n\n\t// round up to next power of 2 so all data operations can\n\t// be mask protected\n\tdataLength = header->dataLength + header->litLength + header->bssLength;\n\tfor ( i = 0 ; dataLength > ( 1 << i ) ; i++ ) {\n\t}\n\tdataLength = 1 << i;\n\n\t// allocate zero filled space for initialized and uninitialized data\n\tvm->dataBase = (byte*) Hunk_Alloc( dataLength, h_high );\n\tvm->dataMask = dataLength - 1;\n\n\t// copy the intialized data\n\tCom_Memcpy( vm->dataBase, (byte *)header + header->dataOffset, header->dataLength + header->litLength );\n\n\t// byte swap the longs\n\tfor ( i = 0 ; i < header->dataLength ; i += 4 ) {\n\t\t*(int *)(vm->dataBase + i) = LittleLong( *(int *)(vm->dataBase + i ) );\n\t}\n\n\t// allocate space for the jump targets, which will be filled in by the compile/prep functions\n\tvm->instructionPointersLength = header->instructionCount * 4;\n\tvm->instructionPointers = (int*) Hunk_Alloc( vm->instructionPointersLength, h_high );\n\n\t// copy or compile the instructions\n\tvm->codeLength = header->codeLength;\n\n\tVM_PrepareInterpreter( vm, header );\n\n\t// free the original file\n\tFS_FreeFile( header );\n\n\t// load the map file\n\tVM_LoadSymbols( vm );\n\n\t// the stack is implicitly at the end of the image\n\tvm->programStack = vm->dataMask + 1;\n\tvm->stackBottom = vm->programStack - STACK_SIZE;\n\n\tCom_Printf(\"%s loaded in %d bytes on the hunk\\n\", module, remaining - Hunk_MemoryRemaining());\n\n\treturn vm;\n}\n\n/*\n==============\nVM_Free\n==============\n*/\nvoid VM_Free( vm_t *vm ) {\n\n\tif ( vm->dllHandle ) {\n\t\tSys_UnloadDll( vm->dllHandle );\n\t\tCom_Memset( vm, 0, sizeof( *vm ) );\n\t}\n#if 0\t// now automatically freed by hunk\n\tif ( vm->codeBase ) {\n\t\tZ_Free( vm->codeBase );\n\t}\n\tif ( vm->dataBase ) {\n\t\tZ_Free( vm->dataBase );\n\t}\n\tif ( vm->instructionPointers ) {\n\t\tZ_Free( vm->instructionPointers );\n\t}\n#endif\n\tCom_Memset( vm, 0, sizeof( *vm ) );\n\n\tcurrentVM = NULL;\n\tlastVM = NULL;\n}\n\nvoid VM_Clear(void) {\n\tint i;\n\tfor (i=0;i<MAX_VM; i++) {\n\t\tif ( vmTable[i].dllHandle ) {\n\t\t\tSys_UnloadDll( vmTable[i].dllHandle );\n\t\t}\n\t\tCom_Memset( &vmTable[i], 0, sizeof( vm_t ) );\n\t}\n\tcurrentVM = NULL;\n\tlastVM = NULL;\n}\n\nvoid *VM_ArgPtr( intptr_t intValue ) {\n\tif ( !intValue ) {\n\t\treturn NULL;\n\t}\n\t// bk001220 - currentVM is missing on reconnect\n\tif ( currentVM==NULL )\n\t  return NULL;\n\n\tif ( currentVM->entryPoint ) {\n\t\treturn (void *)(currentVM->dataBase + intValue);\n\t}\n\telse {\n\t\treturn (void *)(currentVM->dataBase + (intValue & currentVM->dataMask));\n\t}\n}\n\nvoid *VM_ExplicitArgPtr( vm_t *vm, intptr_t intValue ) {\n\tif ( !intValue ) {\n\t\treturn NULL;\n\t}\n\n\t// bk010124 - currentVM is missing on reconnect here as well?\n\tif ( currentVM==NULL )\n\t  return NULL;\n\n\t//\n\tif ( vm->entryPoint ) {\n\t\treturn (void *)(vm->dataBase + intValue);\n\t}\n\telse {\n\t\treturn (void *)(vm->dataBase + (intValue & vm->dataMask));\n\t}\n}\n\n\n/*\n==============\nVM_Call\n\n\nUpon a system call, the stack will look like:\n\nsp+32\tparm1\nsp+28\tparm0\nsp+24\treturn value\nsp+20\treturn address\nsp+16\tlocal1\nsp+14\tlocal0\nsp+12\targ1\nsp+8\targ0\nsp+4\treturn stack\nsp\t\treturn address\n\nAn interpreted function will immediately execute\nan OP_ENTER instruction, which will subtract space for\nlocals from sp\n==============\n*/\n#define\tMAX_STACK\t256\n#define\tSTACK_MASK\t(MAX_STACK-1)\n\nintptr_t\tQDECL VM_Call( vm_t *vm, int callnum, ... ) {\n\tvm_t\t*oldVM;\n\tintptr_t\t\tr;\n\tint i;\n\tint args[16];\n\tva_list ap;\n\n\n\tif ( !vm ) {\n\t\tCom_Error( ERR_FATAL, \"VM_Call with NULL vm\" );\n\t}\n\n\toldVM = currentVM;\n\tcurrentVM = vm;\n\tlastVM = vm;\n\n\tif ( vm_debugLevel ) {\n\t  Com_Printf( \"VM_Call( %i )\\n\", callnum );\n\t}\n\n\t// if we have a dll loaded, call it directly\n\tif ( vm->entryPoint ) {\n\t\t//rcg010207 -  see dissertation at top of VM_DllSyscall() in this file.\n\t\tva_start(ap, callnum);\n\t\tfor (i = 0; i < sizeof (args) / sizeof (args[i]); i++) {\n\t\t\targs[i] = va_arg(ap, int);\n\t\t}\n\t\tva_end(ap);\n\n\t\tr = vm->entryPoint( callnum,  args[0],  args[1],  args[2], args[3],\n                            args[4],  args[5],  args[6], args[7],\n                            args[8],  args[9], args[10], args[11],\n                            args[12], args[13], args[14], args[15]);\n\t}\n\telse\n\t{\n\t\tstruct {\n\t\t\tint callnum;\n\t\t\tint args[10];\n\t\t} a;\n\t\ta.callnum = callnum;\n\t\tva_start(ap, callnum);\n\t\tfor (i = 0; i < sizeof (a.args) / sizeof (a.args[i]); i++) {\n\t\t\ta.args[i] = va_arg(ap, int);\n\t\t}\n\t\tva_end(ap);\n\n\t\tr = VM_CallInterpreted( vm, &a.callnum );\n\t}\n\n\tif ( oldVM != NULL ) // bk001220 - assert(currentVM!=NULL) for oldVM==NULL\n\t  currentVM = oldVM;\n\treturn r;\n}\n\n//=================================================================\n\nstatic int QDECL VM_ProfileSort( const void *a, const void *b ) {\n\tvmSymbol_t\t*sa, *sb;\n\n\tsa = *(vmSymbol_t **)a;\n\tsb = *(vmSymbol_t **)b;\n\n\tif ( sa->profileCount < sb->profileCount ) {\n\t\treturn -1;\n\t}\n\tif ( sa->profileCount > sb->profileCount ) {\n\t\treturn 1;\n\t}\n\treturn 0;\n}\n\n/*\n==============\nVM_VmProfile_f\n\n==============\n*/\nvoid VM_VmProfile_f( void ) {\n\tvm_t\t\t*vm;\n\tvmSymbol_t\t**sorted, *sym;\n\tint\t\t\ti;\n\tdouble\t\ttotal;\n\n\tif ( !lastVM ) {\n\t\treturn;\n\t}\n\n\tvm = lastVM;\n\n\tif ( !vm->numSymbols ) {\n\t\treturn;\n\t}\n\n\tsorted = (vmSymbol_t**) Z_Malloc( vm->numSymbols * sizeof( *sorted ) );\n\tsorted[0] = vm->symbols;\n\ttotal = sorted[0]->profileCount;\n\tfor ( i = 1 ; i < vm->numSymbols ; i++ ) {\n\t\tsorted[i] = sorted[i-1]->next;\n\t\ttotal += sorted[i]->profileCount;\n\t}\n\n\tqsort( sorted, vm->numSymbols, sizeof( *sorted ), VM_ProfileSort );\n\n\tfor ( i = 0 ; i < vm->numSymbols ; i++ ) {\n\t\tint\t\tperc;\n\n\t\tsym = sorted[i];\n\n\t\tperc = 100 * (float) sym->profileCount / total;\n\t\tCom_Printf( \"%2i%% %9i %s\\n\", perc, sym->profileCount, sym->symName );\n\t\tsym->profileCount = 0;\n\t}\n\n\tCom_Printf(\"    %9.0f total\\n\", total );\n\n\tZ_Free( sorted );\n}\n\n/*\n==============\nVM_VmInfo_f\n\n==============\n*/\nvoid VM_VmInfo_f( void ) {\n\tvm_t\t*vm;\n\tint\t\ti;\n\n\tCom_Printf( \"Registered virtual machines:\\n\" );\n\tfor ( i = 0 ; i < MAX_VM ; i++ ) {\n\t\tvm = &vmTable[i];\n\t\tif ( !vm->name[0] ) {\n\t\t\tbreak;\n\t\t}\n\t\tCom_Printf( \"%s : \", vm->name );\n\t\tif ( vm->dllHandle ) {\n\t\t\tCom_Printf( \"native\\n\" );\n\t\t\tcontinue;\n\t\t}\n        Com_Printf( \"interpreted\\n\" );\n\t\tCom_Printf( \"    code length : %7i\\n\", vm->codeLength );\n\t\tCom_Printf( \"    table length: %7i\\n\", vm->instructionPointersLength );\n\t\tCom_Printf( \"    data length : %7i\\n\", vm->dataMask + 1 );\n\t}\n}\n\n/*\n===============\nVM_LogSyscalls\n\nInsert calls to this while debugging the vm compiler\n===============\n*/\nvoid VM_LogSyscalls( int *args ) {\n\tstatic\tint\t\tcallnum;\n\tstatic\tFILE\t*f;\n\n\tif ( !f ) {\n\t\tf = fopen(\"syscalls.log\", \"w\" );\n\t}\n\tcallnum++;\n\tfprintf(f, \"%i: %i (%i) = %i %i %i %i\\n\", callnum, (int)(intptr_t)( args - (int *)currentVM->dataBase ),\n\t\targs[0], args[1], args[2], args[3], args[4] );\n}\n"
  },
  {
    "path": "src/engine/qcommon/vm_interpreted.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n#include \"vm_local.h\"\n\n#ifdef DEBUG_VM // bk001204\nstatic char\t*opnames[256] = {\n\t\"OP_UNDEF\", \n\n\t\"OP_IGNORE\", \n\n\t\"OP_BREAK\",\n\n\t\"OP_ENTER\",\n\t\"OP_LEAVE\",\n\t\"OP_CALL\",\n\t\"OP_PUSH\",\n\t\"OP_POP\",\n\n\t\"OP_CONST\",\n\n\t\"OP_LOCAL\",\n\n\t\"OP_JUMP\",\n\n\t//-------------------\n\n\t\"OP_EQ\",\n\t\"OP_NE\",\n\n\t\"OP_LTI\",\n\t\"OP_LEI\",\n\t\"OP_GTI\",\n\t\"OP_GEI\",\n\n\t\"OP_LTU\",\n\t\"OP_LEU\",\n\t\"OP_GTU\",\n\t\"OP_GEU\",\n\n\t\"OP_EQF\",\n\t\"OP_NEF\",\n\n\t\"OP_LTF\",\n\t\"OP_LEF\",\n\t\"OP_GTF\",\n\t\"OP_GEF\",\n\n\t//-------------------\n\n\t\"OP_LOAD1\",\n\t\"OP_LOAD2\",\n\t\"OP_LOAD4\",\n\t\"OP_STORE1\",\n\t\"OP_STORE2\",\n\t\"OP_STORE4\",\n\t\"OP_ARG\",\n\n\t\"OP_BLOCK_COPY\",\n\n\t//-------------------\n\n\t\"OP_SEX8\",\n\t\"OP_SEX16\",\n\n\t\"OP_NEGI\",\n\t\"OP_ADD\",\n\t\"OP_SUB\",\n\t\"OP_DIVI\",\n\t\"OP_DIVU\",\n\t\"OP_MODI\",\n\t\"OP_MODU\",\n\t\"OP_MULI\",\n\t\"OP_MULU\",\n\n\t\"OP_BAND\",\n\t\"OP_BOR\",\n\t\"OP_BXOR\",\n\t\"OP_BCOM\",\n\n\t\"OP_LSH\",\n\t\"OP_RSHI\",\n\t\"OP_RSHU\",\n\n\t\"OP_NEGF\",\n\t\"OP_ADDF\",\n\t\"OP_SUBF\",\n\t\"OP_DIVF\",\n\t\"OP_MULF\",\n\n\t\"OP_CVIF\",\n\t\"OP_CVFI\"\n};\n#endif\n\n#if idppc\n    #if defined(__GNUC__)\n        static inline unsigned int loadWord(void *addr) {\n            unsigned int word;\n            \n            asm(\"lwbrx %0,0,%1\" : \"=r\" (word) : \"r\" (addr));\n            return word;\n        }\n    #else\n\t#define loadWord(addr) __lwbrx(addr,0)\n    #endif\n#else\n\t#define\tloadWord(addr) *((int *)addr)\n#endif\n\nchar *VM_Indent( vm_t *vm ) {\n\tstatic char\t*string = \"                                        \";\n\tif ( vm->callLevel > 20 ) {\n\t\treturn string;\n\t}\n\treturn string + 2 * ( 20 - vm->callLevel );\n}\n\nvoid VM_StackTrace( vm_t *vm, int programCounter, int programStack ) {\n\tint\t\tcount;\n\n\tcount = 0;\n\tdo {\n\t\tCom_Printf( \"%s\\n\", VM_ValueToSymbol( vm, programCounter ) );\n\t\tprogramStack =  *(int *)&vm->dataBase[programStack+4];\n\t\tprogramCounter = *(int *)&vm->dataBase[programStack];\n\t} while ( programCounter != -1 && ++count < 32 );\n\n}\n\n\n/*\n====================\nVM_PrepareInterpreter\n====================\n*/\nvoid VM_PrepareInterpreter( vm_t *vm, vmHeader_t *header ) {\n\tint\t\top;\n\tint\t\tpc;\n\tbyte\t*code;\n\tint\t\tinstruction;\n\tint\t\t*codeBase;\n\n\tvm->codeBase = (byte*) Hunk_Alloc( vm->codeLength*4, h_high );\t\t\t// we're now int aligned\n//\tmemcpy( vm->codeBase, (byte *)header + header->codeOffset, vm->codeLength );\n\n\t// we don't need to translate the instructions, but we still need\n\t// to find each instructions starting point for jumps\n\tpc = 0;\n\tinstruction = 0;\n\tcode = (byte *)header + header->codeOffset;\n\tcodeBase = (int *)vm->codeBase;\n\n\twhile ( instruction < header->instructionCount ) {\n\t\tvm->instructionPointers[ instruction ] = pc;\n\t\tinstruction++;\n\n\t\top = code[ pc ];\n\t\tcodeBase[pc] = op;\n\t\tif ( pc > header->codeLength ) {\n\t\t\tCom_Error( ERR_FATAL, \"VM_PrepareInterpreter: pc > header->codeLength\" );\n\t\t}\n\n\t\tpc++;\n\n\t\t// these are the only opcodes that aren't a single byte\n\t\tswitch ( op ) {\n\t\tcase OP_ENTER:\n\t\tcase OP_CONST:\n\t\tcase OP_LOCAL:\n\t\tcase OP_LEAVE:\n\t\tcase OP_EQ:\n\t\tcase OP_NE:\n\t\tcase OP_LTI:\n\t\tcase OP_LEI:\n\t\tcase OP_GTI:\n\t\tcase OP_GEI:\n\t\tcase OP_LTU:\n\t\tcase OP_LEU:\n\t\tcase OP_GTU:\n\t\tcase OP_GEU:\n\t\tcase OP_EQF:\n\t\tcase OP_NEF:\n\t\tcase OP_LTF:\n\t\tcase OP_LEF:\n\t\tcase OP_GTF:\n\t\tcase OP_GEF:\n\t\tcase OP_BLOCK_COPY:\n\t\t\tcodeBase[pc+0] = loadWord(&code[pc]);\n\t\t\tpc += 4;\n\t\t\tbreak;\n\t\tcase OP_ARG:\n\t\t\tcodeBase[pc+0] = code[pc];\n\t\t\tpc += 1;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\n\t}\n\tpc = 0;\n\tinstruction = 0;\n\tcode = (byte *)header + header->codeOffset;\n\tcodeBase = (int *)vm->codeBase;\n\n\twhile ( instruction < header->instructionCount ) {\n\t\top = code[ pc ];\n\t\tinstruction++;\n\t\tpc++;\n\t\tswitch ( op ) {\n\t\tcase OP_ENTER:\n\t\tcase OP_CONST:\n\t\tcase OP_LOCAL:\n\t\tcase OP_LEAVE:\n\t\tcase OP_EQ:\n\t\tcase OP_NE:\n\t\tcase OP_LTI:\n\t\tcase OP_LEI:\n\t\tcase OP_GTI:\n\t\tcase OP_GEI:\n\t\tcase OP_LTU:\n\t\tcase OP_LEU:\n\t\tcase OP_GTU:\n\t\tcase OP_GEU:\n\t\tcase OP_EQF:\n\t\tcase OP_NEF:\n\t\tcase OP_LTF:\n\t\tcase OP_LEF:\n\t\tcase OP_GTF:\n\t\tcase OP_GEF:\n\t\tcase OP_BLOCK_COPY:\n\t\t\tswitch(op) {\n\t\t\t\tcase OP_EQ:\n\t\t\t\tcase OP_NE:\n\t\t\t\tcase OP_LTI:\n\t\t\t\tcase OP_LEI:\n\t\t\t\tcase OP_GTI:\n\t\t\t\tcase OP_GEI:\n\t\t\t\tcase OP_LTU:\n\t\t\t\tcase OP_LEU:\n\t\t\t\tcase OP_GTU:\n\t\t\t\tcase OP_GEU:\n\t\t\t\tcase OP_EQF:\n\t\t\t\tcase OP_NEF:\n\t\t\t\tcase OP_LTF:\n\t\t\t\tcase OP_LEF:\n\t\t\t\tcase OP_GTF:\n\t\t\t\tcase OP_GEF:\n\t\t\t\tcodeBase[pc] = vm->instructionPointers[codeBase[pc]];\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tpc += 4;\n\t\t\tbreak;\n\t\tcase OP_ARG:\n\t\t\tpc += 1;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\n\t}\n}\n\n/*\n==============\nVM_Call\n\n\nUpon a system call, the stack will look like:\n\nsp+32\tparm1\nsp+28\tparm0\nsp+24\treturn stack\nsp+20\treturn address\nsp+16\tlocal1\nsp+14\tlocal0\nsp+12\targ1\nsp+8\targ0\nsp+4\treturn stack\nsp\t\treturn address\n\nAn interpreted function will immediately execute\nan OP_ENTER instruction, which will subtract space for\nlocals from sp\n==============\n*/\n#define\tMAX_STACK\t256\n#define\tSTACK_MASK\t(MAX_STACK-1)\n//#define\tDEBUG_VM\n\n#define\tDEBUGSTR va(\"%s%i\", VM_Indent(vm), opStack-stack )\n\nint\tVM_CallInterpreted( vm_t *vm, int *args ) {\n\tint\t\tstack[MAX_STACK];\n\tint\t\t*opStack;\n\tint\t\tprogramCounter;\n\tint\t\tprogramStack;\n\tint\t\tstackOnEntry;\n\tbyte\t*image;\n\tint\t\t*codeImage;\n\tint\t\tv1;\n\tint\t\tdataMask;\n#ifdef DEBUG_VM\n\tvmSymbol_t\t*profileSymbol;\n#endif\n\n\t// interpret the code\n\tvm->currentlyInterpreting = qtrue;\n\n\t// we might be called recursively, so this might not be the very top\n\tprogramStack = stackOnEntry = vm->programStack;\n\n#ifdef DEBUG_VM\n\tprofileSymbol = VM_ValueToFunctionSymbol( vm, 0 );\n\t// uncomment this for debugging breakpoints\n\tvm->breakFunction = 0;\n#endif\n\t// set up the stack frame \n\n\timage = vm->dataBase;\n\tcodeImage = (int *)vm->codeBase;\n\tdataMask = vm->dataMask;\n\t\n\t// leave a free spot at start of stack so\n\t// that as long as opStack is valid, opStack-1 will\n\t// not corrupt anything\n\topStack = stack;\n\tprogramCounter = 0;\n\n\tprogramStack -= 48;\n\n\t*(int *)&image[ programStack + 44] = args[9];\n\t*(int *)&image[ programStack + 40] = args[8];\n\t*(int *)&image[ programStack + 36] = args[7];\n\t*(int *)&image[ programStack + 32] = args[6];\n\t*(int *)&image[ programStack + 28] = args[5];\n\t*(int *)&image[ programStack + 24] = args[4];\n\t*(int *)&image[ programStack + 20] = args[3];\n\t*(int *)&image[ programStack + 16] = args[2];\n\t*(int *)&image[ programStack + 12] = args[1];\n\t*(int *)&image[ programStack + 8 ] = args[0];\n\t*(int *)&image[ programStack + 4 ] = 0;\t// return stack\n\t*(int *)&image[ programStack ] = -1;\t// will terminate the loop on return\n\n\tvm->callLevel = 0;\n\t\n\tVM_Debug(0);\n\n//\tvm_debugLevel=2;\n\t// main interpreter loop, will exit when a LEAVE instruction\n\t// grabs the -1 program counter\n\n#define r2 codeImage[programCounter]\n\n\twhile ( 1 ) {\n\t\tint\t\topcode,\tr0, r1;\n//\t\tunsigned int\tr2;\n\nnextInstruction:\n\t\tr0 = ((int *)opStack)[0];\n\t\tr1 = ((int *)opStack)[-1];\nnextInstruction2:\n\t\topcode = codeImage[ programCounter++ ];\n#ifdef DEBUG_VM\n\t\tif ( (unsigned)programCounter > vm->codeLength ) {\n\t\t\tCom_Error( ERR_DROP, \"VM pc out of range\" );\n\t\t}\n\n\t\tif ( opStack < stack ) {\n\t\t\tCom_Error( ERR_DROP, \"VM opStack underflow\" );\n\t\t}\n\t\tif ( opStack >= stack+MAX_STACK ) {\n\t\t\tCom_Error( ERR_DROP, \"VM opStack overflow\" );\n\t\t}\n\n\t\tif ( programStack <= vm->stackBottom ) {\n\t\t\tCom_Error( ERR_DROP, \"VM stack overflow\" );\n\t\t}\n\n\t\tif ( programStack & 3 ) {\n\t\t\tCom_Error( ERR_DROP, \"VM program stack misaligned\" );\n\t\t}\n\n\t\tif ( vm_debugLevel > 1 ) {\n\t\t\tCom_Printf( \"%s %s\\n\", DEBUGSTR, opnames[opcode] );\n\t\t}\n\t\tprofileSymbol->profileCount++;\n#endif\n\n\t\tswitch ( opcode ) {\n#ifdef DEBUG_VM\n\t\tdefault:\n\t\t\tCom_Error( ERR_DROP, \"Bad VM instruction\" );  // this should be scanned on load!\n#endif\n\t\tcase OP_BREAK:\n\t\t\tvm->breakCount++;\n\t\t\tgoto nextInstruction2;\n\t\tcase OP_CONST:\n\t\t\topStack++;\n\t\t\tr1 = r0;\n\t\t\tr0 = *opStack = r2;\n\t\t\t\n\t\t\tprogramCounter += 4;\n\t\t\tgoto nextInstruction2;\n\t\tcase OP_LOCAL:\n\t\t\topStack++;\n\t\t\tr1 = r0;\n\t\t\tr0 = *opStack = r2+programStack;\n\n\t\t\tprogramCounter += 4;\n\t\t\tgoto nextInstruction2;\n\n\t\tcase OP_LOAD4:\n#ifdef DEBUG_VM\n\t\t\tif ( *opStack & 3 ) {\n\t\t\t\tCom_Error( ERR_DROP, \"OP_LOAD4 misaligned\" );\n\t\t\t}\n#endif\n\t\t\tr0 = *opStack = *(int *)&image[ r0&dataMask ];\n\t\t\tgoto nextInstruction2;\n\t\tcase OP_LOAD2:\n\t\t\tr0 = *opStack = *(unsigned short *)&image[ r0&dataMask ];\n\t\t\tgoto nextInstruction2;\n\t\tcase OP_LOAD1:\n\t\t\tr0 = *opStack = image[ r0&dataMask ];\n\t\t\tgoto nextInstruction2;\n\n\t\tcase OP_STORE4:\n\t\t\t*(int *)&image[ r1&(dataMask & ~3) ] = r0;\n\t\t\topStack -= 2;\n\t\t\tgoto nextInstruction;\n\t\tcase OP_STORE2:\n\t\t\t*(short *)&image[ r1&(dataMask & ~1) ] = r0;\n\t\t\topStack -= 2;\n\t\t\tgoto nextInstruction;\n\t\tcase OP_STORE1:\n\t\t\timage[ r1&dataMask ] = r0;\n\t\t\topStack -= 2;\n\t\t\tgoto nextInstruction;\n\n\t\tcase OP_ARG:\n\t\t\t// single byte offset from programStack\n\t\t\t*(int *)&image[ codeImage[programCounter] + programStack ] = r0;\n\t\t\topStack--;\n\t\t\tprogramCounter += 1;\n\t\t\tgoto nextInstruction;\n\n        case OP_BLOCK_COPY:\n            {\n                int src = r0;\n                int dest = r1;\n                size_t n = r2;\n\n                if ((dest & dataMask) != dest\n                    || (src & dataMask) != src\n                    || ((dest + n) & dataMask) != dest + n\n                    || ((src + n) & dataMask) != src + n)\n                {\n                    Com_Error(ERR_DROP, \"OP_BLOCK_COPY out of range!\");\n                }\n\n                Com_Memcpy(vm->dataBase + dest, vm->dataBase + src, n);\n                programCounter += 4;\n                opStack -= 2;\n            }\n            goto nextInstruction;\n\n\t\tcase OP_CALL:\n\t\t\t// save current program counter\n\t\t\t*(int *)&image[ programStack ] = programCounter;\n\t\t\t\n\t\t\t// jump to the location on the stack\n\t\t\tprogramCounter = r0;\n\t\t\topStack--;\n\t\t\tif ( programCounter < 0 ) {\n\t\t\t\t// system call\n\t\t\t\tint\t\tr;\n\t\t\t\tint\t\ttemp;\n#ifdef DEBUG_VM\n\t\t\t\tint\t\tstomped;\n\n\t\t\t\tif ( vm_debugLevel ) {\n\t\t\t\t\tCom_Printf( \"%s---> systemcall(%i)\\n\", DEBUGSTR, -1 - programCounter );\n\t\t\t\t}\n#endif\n\t\t\t\t// save the stack to allow recursive VM entry\n\t\t\t\ttemp = vm->callLevel;\n\t\t\t\tvm->programStack = programStack - 4;\n#ifdef DEBUG_VM\n\t\t\t\tstomped = *(int *)&image[ programStack + 4 ];\n#endif\n\t\t\t\t*(int *)&image[ programStack + 4 ] = -1 - programCounter;\n\n//VM_LogSyscalls( (int *)&image[ programStack + 4 ] );\n            {\n                intptr_t argarr[MAX_VMSYSCALL_ARGS];\n                int *imagePtr = (int *)&image[ programStack + 4 ];\n                int i;\n                for (i = 0; i < ARRAY_LEN(argarr); i++) {\n                    argarr[i] = *imagePtr;\n                    imagePtr++;\n                }\n                r = vm->systemCall( argarr );\n            }\n\n#ifdef DEBUG_VM\n\t\t\t\t// this is just our stack frame pointer, only needed\n\t\t\t\t// for debugging\n\t\t\t\t*(int *)&image[ programStack + 4 ] = stomped;\n#endif\n\n\t\t\t\t// save return value\n\t\t\t\topStack++;\n\t\t\t\t*opStack = r;\n\t\t\t\tprogramCounter = *(int *)&image[ programStack ];\n\t\t\t\tvm->callLevel = temp;\n#ifdef DEBUG_VM\n\t\t\t\tif ( vm_debugLevel ) {\n\t\t\t\t\tCom_Printf( \"%s<--- %s\\n\", DEBUGSTR, VM_ValueToSymbol( vm, programCounter ) );\n\t\t\t\t}\n#endif\n\t\t\t} else {\n\t\t\t\tprogramCounter = vm->instructionPointers[ programCounter ];\n\t\t\t}\n\t\t\tgoto nextInstruction;\n\n\t\t// push and pop are only needed for discarded or bad function return values\n\t\tcase OP_PUSH:\n\t\t\topStack++;\n\t\t\tgoto nextInstruction;\n\t\tcase OP_POP:\n\t\t\topStack--;\n\t\t\tgoto nextInstruction;\n\n\t\tcase OP_ENTER:\n#ifdef DEBUG_VM\n\t\t\tprofileSymbol = VM_ValueToFunctionSymbol( vm, programCounter );\n#endif\n\t\t\t// get size of stack frame\n\t\t\tv1 = r2;\n\n\t\t\tprogramCounter += 4;\n\t\t\tprogramStack -= v1;\n#ifdef DEBUG_VM\n\t\t\t// save old stack frame for debugging traces\n\t\t\t*(int *)&image[programStack+4] = programStack + v1;\n\t\t\tif ( vm_debugLevel ) {\n\t\t\t\tCom_Printf( \"%s---> %s\\n\", DEBUGSTR, VM_ValueToSymbol( vm, programCounter - 5 ) );\n\t\t\t\tif ( vm->breakFunction && programCounter - 5 == vm->breakFunction ) {\n\t\t\t\t\t// this is to allow setting breakpoints here in the debugger\n\t\t\t\t\tvm->breakCount++;\n//\t\t\t\t\tvm_debugLevel = 2;\n//\t\t\t\t\tVM_StackTrace( vm, programCounter, programStack );\n\t\t\t\t}\n\t\t\t\tvm->callLevel++;\n\t\t\t}\n#endif\n\t\t\tgoto nextInstruction;\n\t\tcase OP_LEAVE:\n\t\t\t// remove our stack frame\n\t\t\tv1 = r2;\n\n\t\t\tprogramStack += v1;\n\n\t\t\t// grab the saved program counter\n\t\t\tprogramCounter = *(int *)&image[ programStack ];\n#ifdef DEBUG_VM\n\t\t\tprofileSymbol = VM_ValueToFunctionSymbol( vm, programCounter );\n\t\t\tif ( vm_debugLevel ) {\n\t\t\t\tvm->callLevel--;\n\t\t\t\tCom_Printf( \"%s<--- %s\\n\", DEBUGSTR, VM_ValueToSymbol( vm, programCounter ) );\n\t\t\t}\n#endif\n\t\t\t// check for leaving the VM\n\t\t\tif ( programCounter == -1 ) {\n\t\t\t\tgoto done;\n\t\t\t}\n\t\t\tgoto nextInstruction;\n\n\t\t/*\n\t\t===================================================================\n\t\tBRANCHES\n\t\t===================================================================\n\t\t*/\n\n\t\tcase OP_JUMP:\n\t\t\tprogramCounter = r0;\n\t\t\tprogramCounter = vm->instructionPointers[ programCounter ];\n\t\t\topStack--;\n\t\t\tgoto nextInstruction;\n\n\t\tcase OP_EQ:\n\t\t\topStack -= 2;\n\t\t\tif ( r1 == r0 ) {\n\t\t\t\tprogramCounter = r2;\t//vm->instructionPointers[r2];\n\t\t\t\tgoto nextInstruction;\n\t\t\t} else {\n\t\t\t\tprogramCounter += 4;\n\t\t\t\tgoto nextInstruction;\n\t\t\t}\n\n\t\tcase OP_NE:\n\t\t\topStack -= 2;\n\t\t\tif ( r1 != r0 ) {\n\t\t\t\tprogramCounter = r2;\t//vm->instructionPointers[r2];\n\t\t\t\tgoto nextInstruction;\n\t\t\t} else {\n\t\t\t\tprogramCounter += 4;\n\t\t\t\tgoto nextInstruction;\n\t\t\t}\n\n\t\tcase OP_LTI:\n\t\t\topStack -= 2;\n\t\t\tif ( r1 < r0 ) {\n\t\t\t\tprogramCounter = r2;\t//vm->instructionPointers[r2];\n\t\t\t\tgoto nextInstruction;\n\t\t\t} else {\n\t\t\t\tprogramCounter += 4;\n\t\t\t\tgoto nextInstruction;\n\t\t\t}\n\n\t\tcase OP_LEI:\n\t\t\topStack -= 2;\n\t\t\tif ( r1 <= r0 ) {\n\t\t\t\tprogramCounter = r2;\t//vm->instructionPointers[r2];\n\t\t\t\tgoto nextInstruction;\n\t\t\t} else {\n\t\t\t\tprogramCounter += 4;\n\t\t\t\tgoto nextInstruction;\n\t\t\t}\n\n\t\tcase OP_GTI:\n\t\t\topStack -= 2;\n\t\t\tif ( r1 > r0 ) {\n\t\t\t\tprogramCounter = r2;\t//vm->instructionPointers[r2];\n\t\t\t\tgoto nextInstruction;\n\t\t\t} else {\n\t\t\t\tprogramCounter += 4;\n\t\t\t\tgoto nextInstruction;\n\t\t\t}\n\n\t\tcase OP_GEI:\n\t\t\topStack -= 2;\n\t\t\tif ( r1 >= r0 ) {\n\t\t\t\tprogramCounter = r2;\t//vm->instructionPointers[r2];\n\t\t\t\tgoto nextInstruction;\n\t\t\t} else {\n\t\t\t\tprogramCounter += 4;\n\t\t\t\tgoto nextInstruction;\n\t\t\t}\n\n\t\tcase OP_LTU:\n\t\t\topStack -= 2;\n\t\t\tif ( ((unsigned)r1) < ((unsigned)r0) ) {\n\t\t\t\tprogramCounter = r2;\t//vm->instructionPointers[r2];\n\t\t\t\tgoto nextInstruction;\n\t\t\t} else {\n\t\t\t\tprogramCounter += 4;\n\t\t\t\tgoto nextInstruction;\n\t\t\t}\n\n\t\tcase OP_LEU:\n\t\t\topStack -= 2;\n\t\t\tif ( ((unsigned)r1) <= ((unsigned)r0) ) {\n\t\t\t\tprogramCounter = r2;\t//vm->instructionPointers[r2];\n\t\t\t\tgoto nextInstruction;\n\t\t\t} else {\n\t\t\t\tprogramCounter += 4;\n\t\t\t\tgoto nextInstruction;\n\t\t\t}\n\n\t\tcase OP_GTU:\n\t\t\topStack -= 2;\n\t\t\tif ( ((unsigned)r1) > ((unsigned)r0) ) {\n\t\t\t\tprogramCounter = r2;\t//vm->instructionPointers[r2];\n\t\t\t\tgoto nextInstruction;\n\t\t\t} else {\n\t\t\t\tprogramCounter += 4;\n\t\t\t\tgoto nextInstruction;\n\t\t\t}\n\n\t\tcase OP_GEU:\n\t\t\topStack -= 2;\n\t\t\tif ( ((unsigned)r1) >= ((unsigned)r0) ) {\n\t\t\t\tprogramCounter = r2;\t//vm->instructionPointers[r2];\n\t\t\t\tgoto nextInstruction;\n\t\t\t} else {\n\t\t\t\tprogramCounter += 4;\n\t\t\t\tgoto nextInstruction;\n\t\t\t}\n\n\t\tcase OP_EQF:\n\t\t\tif ( ((float *)opStack)[-1] == *(float *)opStack ) {\n\t\t\t\tprogramCounter = r2;\t//vm->instructionPointers[r2];\n\t\t\t\topStack -= 2;\n\t\t\t\tgoto nextInstruction;\n\t\t\t} else {\n\t\t\t\tprogramCounter += 4;\n\t\t\t\topStack -= 2;\n\t\t\t\tgoto nextInstruction;\n\t\t\t}\n\n\t\tcase OP_NEF:\n\t\t\tif ( ((float *)opStack)[-1] != *(float *)opStack ) {\n\t\t\t\tprogramCounter = r2;\t//vm->instructionPointers[r2];\n\t\t\t\topStack -= 2;\n\t\t\t\tgoto nextInstruction;\n\t\t\t} else {\n\t\t\t\tprogramCounter += 4;\n\t\t\t\topStack -= 2;\n\t\t\t\tgoto nextInstruction;\n\t\t\t}\n\n\t\tcase OP_LTF:\n\t\t\tif ( ((float *)opStack)[-1] < *(float *)opStack ) {\n\t\t\t\tprogramCounter = r2;\t//vm->instructionPointers[r2];\n\t\t\t\topStack -= 2;\n\t\t\t\tgoto nextInstruction;\n\t\t\t} else {\n\t\t\t\tprogramCounter += 4;\n\t\t\t\topStack -= 2;\n\t\t\t\tgoto nextInstruction;\n\t\t\t}\n\n\t\tcase OP_LEF:\n\t\t\tif ( ((float *)opStack)[-1] <= *(float *)opStack ) {\n\t\t\t\tprogramCounter = r2;\t//vm->instructionPointers[r2];\n\t\t\t\topStack -= 2;\n\t\t\t\tgoto nextInstruction;\n\t\t\t} else {\n\t\t\t\tprogramCounter += 4;\n\t\t\t\topStack -= 2;\n\t\t\t\tgoto nextInstruction;\n\t\t\t}\n\n\t\tcase OP_GTF:\n\t\t\tif ( ((float *)opStack)[-1] > *(float *)opStack ) {\n\t\t\t\tprogramCounter = r2;\t//vm->instructionPointers[r2];\n\t\t\t\topStack -= 2;\n\t\t\t\tgoto nextInstruction;\n\t\t\t} else {\n\t\t\t\tprogramCounter += 4;\n\t\t\t\topStack -= 2;\n\t\t\t\tgoto nextInstruction;\n\t\t\t}\n\n\t\tcase OP_GEF:\n\t\t\tif ( ((float *)opStack)[-1] >= *(float *)opStack ) {\n\t\t\t\tprogramCounter = r2;\t//vm->instructionPointers[r2];\n\t\t\t\topStack -= 2;\n\t\t\t\tgoto nextInstruction;\n\t\t\t} else {\n\t\t\t\tprogramCounter += 4;\n\t\t\t\topStack -= 2;\n\t\t\t\tgoto nextInstruction;\n\t\t\t}\n\n\n\t\t//===================================================================\n\n\t\tcase OP_NEGI:\n\t\t\t*opStack = -r0;\n\t\t\tgoto nextInstruction;\n\t\tcase OP_ADD:\n\t\t\topStack[-1] = r1 + r0;\n\t\t\topStack--;\n\t\t\tgoto nextInstruction;\n\t\tcase OP_SUB:\n\t\t\topStack[-1] = r1 - r0;\n\t\t\topStack--;\n\t\t\tgoto nextInstruction;\n\t\tcase OP_DIVI:\n\t\t\topStack[-1] = r1 / r0;\n\t\t\topStack--;\n\t\t\tgoto nextInstruction;\n\t\tcase OP_DIVU:\n\t\t\topStack[-1] = ((unsigned)r1) / ((unsigned)r0);\n\t\t\topStack--;\n\t\t\tgoto nextInstruction;\n\t\tcase OP_MODI:\n\t\t\topStack[-1] = r1 % r0;\n\t\t\topStack--;\n\t\t\tgoto nextInstruction;\n\t\tcase OP_MODU:\n\t\t\topStack[-1] = ((unsigned)r1) % (unsigned)r0;\n\t\t\topStack--;\n\t\t\tgoto nextInstruction;\n\t\tcase OP_MULI:\n\t\t\topStack[-1] = r1 * r0;\n\t\t\topStack--;\n\t\t\tgoto nextInstruction;\n\t\tcase OP_MULU:\n\t\t\topStack[-1] = ((unsigned)r1) * ((unsigned)r0);\n\t\t\topStack--;\n\t\t\tgoto nextInstruction;\n\n\t\tcase OP_BAND:\n\t\t\topStack[-1] = ((unsigned)r1) & ((unsigned)r0);\n\t\t\topStack--;\n\t\t\tgoto nextInstruction;\n\t\tcase OP_BOR:\n\t\t\topStack[-1] = ((unsigned)r1) | ((unsigned)r0);\n\t\t\topStack--;\n\t\t\tgoto nextInstruction;\n\t\tcase OP_BXOR:\n\t\t\topStack[-1] = ((unsigned)r1) ^ ((unsigned)r0);\n\t\t\topStack--;\n\t\t\tgoto nextInstruction;\n\t\tcase OP_BCOM:\n\t\t\topStack[-1] = ~ ((unsigned)r0);\n\t\t\tgoto nextInstruction;\n\n\t\tcase OP_LSH:\n\t\t\topStack[-1] = r1 << r0;\n\t\t\topStack--;\n\t\t\tgoto nextInstruction;\n\t\tcase OP_RSHI:\n\t\t\topStack[-1] = r1 >> r0;\n\t\t\topStack--;\n\t\t\tgoto nextInstruction;\n\t\tcase OP_RSHU:\n\t\t\topStack[-1] = ((unsigned)r1) >> r0;\n\t\t\topStack--;\n\t\t\tgoto nextInstruction;\n\n\t\tcase OP_NEGF:\n\t\t\t*(float *)opStack =  -*(float *)opStack;\n\t\t\tgoto nextInstruction;\n\t\tcase OP_ADDF:\n\t\t\t*(float *)(opStack-1) = *(float *)(opStack-1) + *(float *)opStack;\n\t\t\topStack--;\n\t\t\tgoto nextInstruction;\n\t\tcase OP_SUBF:\n\t\t\t*(float *)(opStack-1) = *(float *)(opStack-1) - *(float *)opStack;\n\t\t\topStack--;\n\t\t\tgoto nextInstruction;\n\t\tcase OP_DIVF:\n\t\t\t*(float *)(opStack-1) = *(float *)(opStack-1) / *(float *)opStack;\n\t\t\topStack--;\n\t\t\tgoto nextInstruction;\n\t\tcase OP_MULF:\n\t\t\t*(float *)(opStack-1) = *(float *)(opStack-1) * *(float *)opStack;\n\t\t\topStack--;\n\t\t\tgoto nextInstruction;\n\n\t\tcase OP_CVIF:\n\t\t\t*(float *)opStack =  (float)*opStack;\n\t\t\tgoto nextInstruction;\n\t\tcase OP_CVFI:\n\t\t\t*opStack = (int) *(float *)opStack;\n\t\t\tgoto nextInstruction;\n\t\tcase OP_SEX8:\n\t\t\t*opStack = (signed char)*opStack;\n\t\t\tgoto nextInstruction;\n\t\tcase OP_SEX16:\n\t\t\t*opStack = (short)*opStack;\n\t\t\tgoto nextInstruction;\n\t\t}\n\t}\n\ndone:\n\tvm->currentlyInterpreting = qfalse;\n\n\tif ( opStack != &stack[1] ) {\n\t\tCom_Error( ERR_DROP, \"Interpreter error: opStack = %i\", opStack - stack );\n\t}\n\n\tvm->programStack = stackOnEntry;\n\n\t// return the result\n\treturn *opStack;\n}\n"
  },
  {
    "path": "src/engine/qcommon/vm_local.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n#include \"../../game/q_shared.h\"\n#include \"qcommon.h\"\n\n// Max number of arguments to pass from a vm to engine's syscall handler function for the vm.\n// syscall number + 15 arguments\n#define MAX_VMSYSCALL_ARGS 16\n\ntypedef enum {\n\tOP_UNDEF, \n\n\tOP_IGNORE, \n\n\tOP_BREAK,\n\n\tOP_ENTER,\n\tOP_LEAVE,\n\tOP_CALL,\n\tOP_PUSH,\n\tOP_POP,\n\n\tOP_CONST,\n\tOP_LOCAL,\n\n\tOP_JUMP,\n\n\t//-------------------\n\n\tOP_EQ,\n\tOP_NE,\n\n\tOP_LTI,\n\tOP_LEI,\n\tOP_GTI,\n\tOP_GEI,\n\n\tOP_LTU,\n\tOP_LEU,\n\tOP_GTU,\n\tOP_GEU,\n\n\tOP_EQF,\n\tOP_NEF,\n\n\tOP_LTF,\n\tOP_LEF,\n\tOP_GTF,\n\tOP_GEF,\n\n\t//-------------------\n\n\tOP_LOAD1,\n\tOP_LOAD2,\n\tOP_LOAD4,\n\tOP_STORE1,\n\tOP_STORE2,\n\tOP_STORE4,\t\t\t\t// *(stack[top-1]) = stack[top]\n\tOP_ARG,\n\n\tOP_BLOCK_COPY,\n\n\t//-------------------\n\n\tOP_SEX8,\n\tOP_SEX16,\n\n\tOP_NEGI,\n\tOP_ADD,\n\tOP_SUB,\n\tOP_DIVI,\n\tOP_DIVU,\n\tOP_MODI,\n\tOP_MODU,\n\tOP_MULI,\n\tOP_MULU,\n\n\tOP_BAND,\n\tOP_BOR,\n\tOP_BXOR,\n\tOP_BCOM,\n\n\tOP_LSH,\n\tOP_RSHI,\n\tOP_RSHU,\n\n\tOP_NEGF,\n\tOP_ADDF,\n\tOP_SUBF,\n\tOP_DIVF,\n\tOP_MULF,\n\n\tOP_CVIF,\n\tOP_CVFI\n} opcode_t;\n\n\n\ntypedef int\tvmptr_t;\n\ntypedef struct vmSymbol_s {\n\tstruct vmSymbol_s\t*next;\n\tint\t\tsymValue;\n\tint\t\tprofileCount;\n\tchar\tsymName[1];\t\t// variable sized\n} vmSymbol_t;\n\n#define\tVM_OFFSET_PROGRAM_STACK\t\t0\n#define\tVM_OFFSET_SYSTEM_CALL\t\t4\n\nstruct vm_s {\n    // DO NOT MOVE OR CHANGE THESE WITHOUT CHANGING THE VM_OFFSET_* DEFINES\n    // USED BY THE ASM CODE\n    int\t\t\tprogramStack;\t\t// the vm may be recursively entered\n    intptr_t    (*systemCall)( intptr_t *parms );\n\n\t//------------------------------------\n   \n    char\t\tname[MAX_QPATH];\n\n\t// for dynamic linked modules\n\tvoid\t\t*dllHandle;\n\tintptr_t\t\t\t(QDECL *entryPoint)( int callNum, ... );\n\n\t// for interpreted modules\n\tqboolean\tcurrentlyInterpreting;\n\n\tbyte\t\t*codeBase;\n\tint\t\t\tcodeLength;\n\n\tint\t\t\t*instructionPointers;\n\tint\t\t\tinstructionPointersLength;\n\n\tbyte\t\t*dataBase;\n\tint\t\t\tdataMask;\n\n\tint\t\t\tstackBottom;\t\t// if programStack < stackBottom, error\n\n\tint\t\t\tnumSymbols;\n\tstruct vmSymbol_s\t*symbols;\n\n\tint\t\t\tcallLevel;\t\t\t// for debug indenting\n\tint\t\t\tbreakFunction;\t\t// increment breakCount on function entry to this\n\tint\t\t\tbreakCount;\n\n// fqpath member added 7/20/02 by T.Ray\n\tchar\t\tfqpath[MAX_QPATH+1] ;\n};\n\n\nextern\tvm_t\t*currentVM;\nextern\tint\t\tvm_debugLevel;\n\nvoid VM_PrepareInterpreter( vm_t *vm, vmHeader_t *header );\nint\tVM_CallInterpreted( vm_t *vm, int *args );\n\nvmSymbol_t *VM_ValueToFunctionSymbol( vm_t *vm, int value );\nint VM_SymbolToValue( vm_t *vm, const char *symbol );\nconst char *VM_ValueToSymbol( vm_t *vm, int value );\nvoid VM_LogSyscalls( int *args );\n\n"
  },
  {
    "path": "src/engine/renderer/dx.cpp",
    "content": "#include \"tr_local.h\"\n#include \"../../engine/platform/win_local.h\"\n\n#include <chrono>\n#include <functional>\n\n#ifdef ENABLE_DX12\n\n#include \"D3d12.h\"\n#include \"DXGI1_5.h\"\n\n#pragma comment (lib, \"D3d12.lib\")\n#pragma comment (lib, \"DXGI.lib\")\n\nconst int VERTEX_CHUNK_SIZE = 512 * 1024;\n\nconst int XYZ_SIZE      = 4 * VERTEX_CHUNK_SIZE;\nconst int COLOR_SIZE    = 1 * VERTEX_CHUNK_SIZE;\nconst int ST0_SIZE      = 2 * VERTEX_CHUNK_SIZE;\nconst int ST1_SIZE      = 2 * VERTEX_CHUNK_SIZE;\n\nconst int XYZ_OFFSET    = 0;\nconst int COLOR_OFFSET  = XYZ_OFFSET + XYZ_SIZE;\nconst int ST0_OFFSET    = COLOR_OFFSET + COLOR_SIZE;\nconst int ST1_OFFSET    = ST0_OFFSET + ST0_SIZE;\n\nconst int VERTEX_BUFFER_SIZE = XYZ_SIZE + COLOR_SIZE + ST0_SIZE + ST1_SIZE;\nconst int INDEX_BUFFER_SIZE = 2 * 1024 * 1024;\n\n#define DX_CHECK(function_call) { \\\n\tHRESULT hr = function_call; \\\n\tif (FAILED(hr)) \\\n\t\tri.Error(ERR_FATAL, \"Direct3D: error returned by %s\", #function_call); \\\n}\n\nstatic DXGI_FORMAT get_depth_format() {\n\tif (r_stencilbits->integer > 0) {\n\t\tglConfig.stencilBits = 8;\n\t\treturn DXGI_FORMAT_D24_UNORM_S8_UINT;\n\t} else {\n\t\tglConfig.stencilBits = 0;\n\t\treturn DXGI_FORMAT_D32_FLOAT;\n\t}\n}\n\nstatic void get_hardware_adapter(IDXGIFactory4* factory, IDXGIAdapter1** adapter) {\n\tDXGI_ADAPTER_DESC1 desc;\n\tUINT adapter_index = 0;\n\twhile (factory->EnumAdapters1(adapter_index++, adapter) != DXGI_ERROR_NOT_FOUND) {\n\t\t(*adapter)->GetDesc1(&desc);\n\t\tif (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) {\n\t\t\tcontinue;\n\t\t}\n\t\t// check for 11_0 feature level support\n\t\tif (SUCCEEDED(D3D12CreateDevice(*adapter, D3D_FEATURE_LEVEL_11_0, _uuidof(ID3D12Device), nullptr))) {\n\t\t\treturn;\n\t\t}\n\t}\n\t*adapter = nullptr;\n}\n\nstatic void record_and_run_commands(std::function<void(ID3D12GraphicsCommandList*)> recorder) {\n\tID3D12GraphicsCommandList* command_list;\n\tDX_CHECK(dx.device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, dx.helper_command_allocator,\n\t\tnullptr, IID_PPV_ARGS(&command_list)));\n\n\trecorder(command_list);\n\tDX_CHECK(command_list->Close());\n\n\tID3D12CommandList* command_lists[] = { command_list };\n\tdx.command_queue->ExecuteCommandLists(1, command_lists);\n\tdx_wait_device_idle();\n\t\n\tcommand_list->Release();\n\tdx.helper_command_allocator->Reset();\n}\n\nstatic D3D12_RESOURCE_BARRIER get_transition_barrier(\n\tID3D12Resource* resource,\n\tD3D12_RESOURCE_STATES state_before,\n\tD3D12_RESOURCE_STATES state_after)\n{\n\tD3D12_RESOURCE_BARRIER barrier;\n\tbarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;\n\tbarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;\n\tbarrier.Transition.pResource = resource;\n\tbarrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;\n\tbarrier.Transition.StateBefore = state_before;\n\tbarrier.Transition.StateAfter = state_after;\n\treturn barrier;\n}\n\nstatic D3D12_HEAP_PROPERTIES get_heap_properties(D3D12_HEAP_TYPE heap_type) {\n\tD3D12_HEAP_PROPERTIES properties;\n\tproperties.Type = heap_type;\n\tproperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;\n\tproperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;\n\tproperties.CreationNodeMask = 1;\n\tproperties.VisibleNodeMask = 1;\n\treturn properties;\n}\n\nstatic D3D12_RESOURCE_DESC get_buffer_desc(UINT64 size) {\n\tD3D12_RESOURCE_DESC desc;\n\tdesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;\n\tdesc.Alignment = 0;\n\tdesc.Width = size;\n\tdesc.Height = 1;\n\tdesc.DepthOrArraySize = 1;\n\tdesc.MipLevels = 1;\n\tdesc.Format = DXGI_FORMAT_UNKNOWN;\n\tdesc.SampleDesc.Count = 1;\n\tdesc.SampleDesc.Quality = 0;\n\tdesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;\n\tdesc.Flags = D3D12_RESOURCE_FLAG_NONE;\n\treturn desc;\n}\n\nID3D12PipelineState* create_pipeline(const Vk_Pipeline_Def& def);\n\nvoid dx_initialize() {\n\t// enable validation in debug configuration\n#if defined(_DEBUG)\n\tID3D12Debug* debug_controller;\n\tif (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debug_controller)))) {\n\t\tdebug_controller->EnableDebugLayer();\n\t\tdebug_controller->Release();\n\t}\n#endif\n\n\tIDXGIFactory5* factory;\n\tDX_CHECK(CreateDXGIFactory1(IID_PPV_ARGS(&factory)));\n\n\t// Create device.\n\t{\n\t\tIDXGIAdapter1* hardware_adapter;\n\t\tget_hardware_adapter(factory, &hardware_adapter);\n\t\tDX_CHECK(D3D12CreateDevice(hardware_adapter, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&dx.device)));\n\t\thardware_adapter->Release();\n\t}\n\n\t// Create command queue.\n\t{\n\t\tD3D12_COMMAND_QUEUE_DESC queue_desc{};\n\t\tqueue_desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;\n\t\tqueue_desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;\n\t\tDX_CHECK(dx.device->CreateCommandQueue(&queue_desc, IID_PPV_ARGS(&dx.command_queue)));\n\t}\n\n\t//\n\t// Create swap chain.\n\t//\n\t{\n        DX_CHECK(factory->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &dx.present_allow_tearing, sizeof(dx.present_allow_tearing)));\n\n\t\tDXGI_SWAP_CHAIN_DESC1 swap_chain_desc{};\n\t\tswap_chain_desc.BufferCount = SWAPCHAIN_BUFFER_COUNT;\n\t\tswap_chain_desc.Width = glConfig.vidWidth;\n\t\tswap_chain_desc.Height = glConfig.vidHeight;\n\t\tswap_chain_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;\n\t\tswap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;\n\t\tswap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;\n\t\tswap_chain_desc.SampleDesc.Count = 1;\n        swap_chain_desc.Flags = dx.present_allow_tearing ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0;\n\n\t\tIDXGISwapChain1* swapchain;\n\t\tDX_CHECK(factory->CreateSwapChainForHwnd(\n\t\t\tdx.command_queue,\n\t\t\tg_wv.hWnd_dx,\n\t\t\t&swap_chain_desc,\n\t\t\tnullptr,\n\t\t\tnullptr,\n\t\t\t&swapchain\n\t\t\t));\n\n\t\tDX_CHECK(factory->MakeWindowAssociation(g_wv.hWnd_dx, DXGI_MWA_NO_ALT_ENTER));\n\t\tswapchain->QueryInterface(__uuidof(IDXGISwapChain3), (void**)&dx.swapchain);\n\t\tswapchain->Release();\n\n\t\tfor (int i = 0; i < SWAPCHAIN_BUFFER_COUNT; i++) {\n\t\t\tDX_CHECK(dx.swapchain->GetBuffer(i, IID_PPV_ARGS(&dx.render_targets[i])));\n\t\t}\n\t}\n\n\tfactory->Release();\n\tfactory = nullptr;\n\n\t//\n\t// Create command allocators and command list.\n\t//\n\t{\n\t\tDX_CHECK(dx.device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT,\n\t\t\tIID_PPV_ARGS(&dx.command_allocator)));\n\n\t\tDX_CHECK(dx.device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT,\n\t\t\tIID_PPV_ARGS(&dx.helper_command_allocator)));\n\n\t\tDX_CHECK(dx.device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, dx.command_allocator, nullptr,\n\t\t\tIID_PPV_ARGS(&dx.command_list)));\n\t\tDX_CHECK(dx.command_list->Close());\n\t}\n\n\t//\n\t// Create synchronization objects.\n\t//\n\t{\n\t\tDX_CHECK(dx.device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&dx.fence)));\n\t\tdx.fence_event = CreateEvent(nullptr, FALSE, FALSE, nullptr);\n\t}\n\n\t//\n\t// Create descriptor heaps.\n\t//\n\t{\n\t\t// RTV heap.\n\t\t{\n\t\t\tD3D12_DESCRIPTOR_HEAP_DESC heap_desc;\n\t\t\theap_desc.NumDescriptors = SWAPCHAIN_BUFFER_COUNT;\n\t\t\theap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;\n\t\t\theap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;\n\t\t\theap_desc.NodeMask = 0;\n\t\t\tDX_CHECK(dx.device->CreateDescriptorHeap(&heap_desc, IID_PPV_ARGS(&dx.rtv_heap)));\n\t\t\tdx.rtv_descriptor_size = dx.device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);\n\t\t}\n\n\t\t// DSV heap.\n\t\t{\n\t\t\tD3D12_DESCRIPTOR_HEAP_DESC heap_desc;\n\t\t\theap_desc.NumDescriptors = 1;\n\t\t\theap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV;\n\t\t\theap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;\n\t\t\theap_desc.NodeMask = 0;\n\t\t\tDX_CHECK(dx.device->CreateDescriptorHeap(&heap_desc, IID_PPV_ARGS(&dx.dsv_heap)));\n\t\t}\n\n\t\t// SRV heap.\n\t\t{\n\t\t\tD3D12_DESCRIPTOR_HEAP_DESC heap_desc;\n\t\t\theap_desc.NumDescriptors = MAX_DRAWIMAGES;\n\t\t\theap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;\n\t\t\theap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;\n\t\t\theap_desc.NodeMask = 0;\n\t\t\tDX_CHECK(dx.device->CreateDescriptorHeap(&heap_desc, IID_PPV_ARGS(&dx.srv_heap)));\n\t\t\tdx.srv_descriptor_size = dx.device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);\n\t\t}\n\n\t\t// Sampler heap.\n\t\t{\n\t\t\tD3D12_DESCRIPTOR_HEAP_DESC heap_desc;\n\t\t\theap_desc.NumDescriptors = SAMPLER_COUNT;\n\t\t\theap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER;\n\t\t\theap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;\n\t\t\theap_desc.NodeMask = 0;\n\t\t\tDX_CHECK(dx.device->CreateDescriptorHeap(&heap_desc, IID_PPV_ARGS(&dx.sampler_heap)));\n\t\t\tdx.sampler_descriptor_size = dx.device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);\n\t\t}\n\t}\n\n\t//\n\t// Create descriptors.\n\t//\n\t{\n\t\t// RTV descriptors.\n\t\t{\n\t\t\tD3D12_CPU_DESCRIPTOR_HANDLE rtv_handle = dx.rtv_heap->GetCPUDescriptorHandleForHeapStart();\n\t\t\tfor (int i = 0; i < SWAPCHAIN_BUFFER_COUNT; i++) {\n\t\t\t\tdx.device->CreateRenderTargetView(dx.render_targets[i], nullptr, rtv_handle);\n\t\t\t\trtv_handle.ptr += dx.rtv_descriptor_size;\n\t\t\t}\n\t\t}\n\n\t\t// Samplers.\n\t\t{\n\t\t\t{\n\t\t\t\tVk_Sampler_Def def;\n\t\t\t\tdef.repeat_texture = true;\n\t\t\t\tdef.gl_mag_filter = gl_filter_max;\n\t\t\t\tdef.gl_min_filter = gl_filter_min;\n\t\t\t\tdx_create_sampler_descriptor(def, SAMPLER_MIP_REPEAT);\n\t\t\t}\n\t\t\t{\n\t\t\t\tVk_Sampler_Def def;\n\t\t\t\tdef.repeat_texture = false;\n\t\t\t\tdef.gl_mag_filter = gl_filter_max;\n\t\t\t\tdef.gl_min_filter = gl_filter_min;\n\t\t\t\tdx_create_sampler_descriptor(def, SAMPLER_MIP_CLAMP);\n\t\t\t}\n\t\t\t{\n\t\t\t\tVk_Sampler_Def def;\n\t\t\t\tdef.repeat_texture = true;\n\t\t\t\tdef.gl_mag_filter = GL_LINEAR;\n\t\t\t\tdef.gl_min_filter = GL_LINEAR;\n\t\t\t\tdx_create_sampler_descriptor(def, SAMPLER_NOMIP_REPEAT);\n\t\t\t}\n\t\t\t{\n\t\t\t\tVk_Sampler_Def def;\n\t\t\t\tdef.repeat_texture = false;\n\t\t\t\tdef.gl_mag_filter = GL_LINEAR;\n\t\t\t\tdef.gl_min_filter = GL_LINEAR;\n\t\t\t\tdx_create_sampler_descriptor(def, SAMPLER_NOMIP_CLAMP);\n\t\t\t}\n\t\t}\n\t}\n\n\t//\n\t// Create depth buffer resources.\n\t//\n\t{\n\t\tD3D12_RESOURCE_DESC depth_desc{};\n\t\tdepth_desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;\n\t\tdepth_desc.Alignment = 0;\n\t\tdepth_desc.Width = glConfig.vidWidth;\n\t\tdepth_desc.Height = glConfig.vidHeight;\n\t\tdepth_desc.DepthOrArraySize = 1;\n\t\tdepth_desc.MipLevels = 1;\n\t\tdepth_desc.Format = get_depth_format();\n\t\tdepth_desc.SampleDesc.Count = 1;\n\t\tdepth_desc.SampleDesc.Quality = 0;\n\t\tdepth_desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;\n\t\tdepth_desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;\n\n\t\tD3D12_CLEAR_VALUE optimized_clear_value{};\n\t\toptimized_clear_value.Format = get_depth_format();\n\t\toptimized_clear_value.DepthStencil.Depth = 1.0f;\n\t\toptimized_clear_value.DepthStencil.Stencil = 0;\n\n\t\tDX_CHECK(dx.device->CreateCommittedResource(\n\t\t\t&get_heap_properties(D3D12_HEAP_TYPE_DEFAULT),\n\t\t\tD3D12_HEAP_FLAG_NONE,\n\t\t\t&depth_desc,\n\t\t\tD3D12_RESOURCE_STATE_DEPTH_WRITE,\n\t\t\t&optimized_clear_value,\n\t\t\tIID_PPV_ARGS(&dx.depth_stencil_buffer)));\n\n\t\tD3D12_DEPTH_STENCIL_VIEW_DESC view_desc{};\n\t\tview_desc.Format = get_depth_format();\n\t\tview_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;\n\t\tview_desc.Flags = D3D12_DSV_FLAG_NONE;\n\n\t\tdx.device->CreateDepthStencilView(dx.depth_stencil_buffer, &view_desc,\n\t\t\tdx.dsv_heap->GetCPUDescriptorHandleForHeapStart());\n\t}\n\n\t//\n\t// Create root signature.\n\t//\n\t{\n\t\tD3D12_DESCRIPTOR_RANGE ranges[4] = {};\n\t\tranges[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;\n\t\tranges[0].NumDescriptors = 1;\n\t\tranges[0].BaseShaderRegister = 0;\n\n\t\tranges[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER;\n\t\tranges[1].NumDescriptors = 1;\n\t\tranges[1].BaseShaderRegister = 0;\n\n\t\tranges[2].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;\n\t\tranges[2].NumDescriptors = 1;\n\t\tranges[2].BaseShaderRegister = 1;\n\n\t\tranges[3].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER;\n\t\tranges[3].NumDescriptors = 1;\n\t\tranges[3].BaseShaderRegister = 1;\n\n\t\tD3D12_ROOT_PARAMETER root_parameters[5] {};\n\n\t\troot_parameters[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;\n\t\troot_parameters[0].Constants.ShaderRegister = 0;\n\t\troot_parameters[0].Constants.Num32BitValues = 32;\n\t\troot_parameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;\n\n\t\tfor (int i = 1; i < 5; i++) {\n\t\t\troot_parameters[i].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;\n\t\t\troot_parameters[i].DescriptorTable.NumDescriptorRanges = 1;\n\t\t\troot_parameters[i].DescriptorTable.pDescriptorRanges = &ranges[i-1];\n\t\t\troot_parameters[i].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;\n\t\t}\n\n\t\tD3D12_ROOT_SIGNATURE_DESC root_signature_desc;\n\t\troot_signature_desc.NumParameters = _countof(root_parameters);\n\t\troot_signature_desc.pParameters = root_parameters;\n\t\troot_signature_desc.NumStaticSamplers = 0;\n\t\troot_signature_desc.pStaticSamplers = nullptr;\n\t\troot_signature_desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;\n\n\t\tID3DBlob* signature;\n\t\tID3DBlob* error;\n\t\tDX_CHECK(D3D12SerializeRootSignature(&root_signature_desc, D3D_ROOT_SIGNATURE_VERSION_1,\n\t\t\t&signature, &error));\n\t\tDX_CHECK(dx.device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(),\n\t\t\tIID_PPV_ARGS(&dx.root_signature)));\n\n\t\tif (signature != nullptr)\n\t\t\tsignature->Release();\n\t\tif (error != nullptr)\n\t\t\terror->Release();\n\t}\n\n\t//\n\t// Geometry buffers.\n\t//\n\t{\n\t\t// store geometry in upload heap since Q3 regenerates it every frame\n\t\tDX_CHECK(dx.device->CreateCommittedResource(\n\t\t\t&get_heap_properties(D3D12_HEAP_TYPE_UPLOAD),\n\t\t\tD3D12_HEAP_FLAG_NONE,\n\t\t\t&get_buffer_desc(VERTEX_BUFFER_SIZE + INDEX_BUFFER_SIZE),\n\t\t\tD3D12_RESOURCE_STATE_GENERIC_READ,\n\t\t\tnullptr,\n\t\t\tIID_PPV_ARGS(&dx.geometry_buffer)));\n\n\t\tvoid* p_data;\n\t\tD3D12_RANGE read_range{};\n        DX_CHECK(dx.geometry_buffer->Map(0, &read_range, &p_data));\n\n\t\tdx.vertex_buffer_ptr = static_cast<byte*>(p_data);\n\n\t\tassert((VERTEX_BUFFER_SIZE & 0xffff) == 0); // index buffer offset should be 64K aligned.\n\t\tdx.index_buffer_ptr = static_cast<byte*>(p_data) + VERTEX_BUFFER_SIZE;\n\t}\n\n\t//\n\t// Standard pipelines.\n\t//\n\t{\n\t\t// skybox\n\t\t{\n\t\t\tVk_Pipeline_Def def;\n\t\t\tdef.shader_type = Vk_Shader_Type::single_texture;\n\t\t\tdef.state_bits = 0;\n\t\t\tdef.face_culling = CT_FRONT_SIDED;\n\t\t\tdef.polygon_offset = false;\n\t\t\tdef.clipping_plane = false;\n\t\t\tdef.mirror = false;\n\t\t\tdx.skybox_pipeline = create_pipeline(def);\n\t\t}\n\n\t\t// Q3 stencil shadows\n\t\t{\n\t\t\t{\n\t\t\t\tVk_Pipeline_Def def;\n\t\t\t\tdef.polygon_offset = false;\n\t\t\t\tdef.state_bits = 0;\n\t\t\t\tdef.shader_type = Vk_Shader_Type::single_texture;\n\t\t\t\tdef.clipping_plane = false;\n\t\t\t\tdef.shadow_phase = Vk_Shadow_Phase::shadow_edges_rendering;\n\n\t\t\t\tcullType_t cull_types[2] = {CT_FRONT_SIDED, CT_BACK_SIDED};\n\t\t\t\tbool mirror_flags[2] = {false, true};\n\n\t\t\t\tfor (int i = 0; i < 2; i++) {\n\t\t\t\t\tdef.face_culling = cull_types[i];\n\t\t\t\t\tfor (int j = 0; j < 2; j++) {\n\t\t\t\t\t\tdef.mirror = mirror_flags[j];\n\t\t\t\t\t\tdx.shadow_volume_pipelines[i][j] = create_pipeline(def);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t{\n\t\t\t\tVk_Pipeline_Def def;\n\t\t\t\tdef.face_culling = CT_FRONT_SIDED;\n\t\t\t\tdef.polygon_offset = false;\n\t\t\t\tdef.state_bits = GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO;\n\t\t\t\tdef.shader_type = Vk_Shader_Type::single_texture;\n\t\t\t\tdef.clipping_plane = false;\n\t\t\t\tdef.mirror = false;\n\t\t\t\tdef.shadow_phase = Vk_Shadow_Phase::fullscreen_quad_rendering;\n\t\t\t\tdx.shadow_finish_pipeline = create_pipeline(def);\n\t\t\t}\n\t\t}\n\n\t\t// fog and dlights\n\t\t{\n\t\t\tVk_Pipeline_Def def;\n\t\t\tdef.shader_type = Vk_Shader_Type::single_texture;\n\t\t\tdef.clipping_plane = false;\n\t\t\tdef.mirror = false;\n\n\t\t\tunsigned int fog_state_bits[2] = {\n\t\t\t\tGLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_EQUAL,\n\t\t\t\tGLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA\n\t\t\t};\n\t\t\tunsigned int dlight_state_bits[2] = {\n\t\t\t\tGLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL,\n\t\t\t\tGLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL\n\t\t\t};\n\t\t\tbool polygon_offset[2] = {false, true};\n\n\t\t\tfor (int i = 0; i < 2; i++) {\n\t\t\t\tunsigned fog_state = fog_state_bits[i];\n\t\t\t\tunsigned dlight_state = dlight_state_bits[i];\n\n\t\t\t\tfor (int j = 0; j < 3; j++) {\n\t\t\t\t\tdef.face_culling = j; // cullType_t value\n\n\t\t\t\t\tfor (int k = 0; k < 2; k++) {\n\t\t\t\t\t\tdef.polygon_offset = polygon_offset[k];\n\n\t\t\t\t\t\tdef.state_bits = fog_state;\n\t\t\t\t\t\tdx.fog_pipelines[i][j][k] = create_pipeline(def);\n\n\t\t\t\t\t\tdef.state_bits = dlight_state;\n\t\t\t\t\t\tdx.dlight_pipelines[i][j][k] = create_pipeline(def);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// debug pipelines\n\t\t{\n\t\t\tVk_Pipeline_Def def;\n\t\t\tdef.state_bits = GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE;\n\t\t\tdx.tris_debug_pipeline = create_pipeline(def);\n\t\t}\n\t\t{\n\t\t\tVk_Pipeline_Def def;\n\t\t\tdef.state_bits = GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE;\n\t\t\tdef.face_culling = CT_BACK_SIDED;\n\t\t\tdx.tris_mirror_debug_pipeline = create_pipeline(def);\n\t\t}\n\t\t{\n\t\t\tVk_Pipeline_Def def;\n\t\t\tdef.state_bits = GLS_DEPTHMASK_TRUE;\n\t\t\tdef.line_primitives = true;\n\t\t\tdx.normals_debug_pipeline = create_pipeline(def);\n\t\t}\n\t\t{\n\t\t\tVk_Pipeline_Def def;\n\t\t\tdef.state_bits = GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE;\n\t\t\tdx.surface_debug_pipeline_solid = create_pipeline(def);\n\t\t}\n\t\t{\n\t\t\tVk_Pipeline_Def def;\n\t\t\tdef.state_bits = GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE;\n\t\t\tdef.line_primitives = true;\n\t\t\tdx.surface_debug_pipeline_outline = create_pipeline(def);\n\t\t}\n\t\t{\n\t\t\tVk_Pipeline_Def def;\n\t\t\tdef.state_bits = GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA;\n\t\t\tdx.images_debug_pipeline = create_pipeline(def);\n\t\t}\n\t}\n\n\tdx.active = true;\n}\n\nvoid dx_shutdown() {\n\t::CloseHandle(dx.fence_event);\n\n\tfor (int i = 0; i < SWAPCHAIN_BUFFER_COUNT; i++) {\n\t\tdx.render_targets[i]->Release();\n\t}\n\tfor (int i = 0; i < 2; i++) {\n\t\tfor (int j = 0; j < 2; j++) {\n\t\t\tdx.shadow_volume_pipelines[i][j]->Release();\n\t\t}\n\t}\n\tfor (int i = 0; i < 2; i++) {\n\t\tfor (int j = 0; j < 3; j++) {\n\t\t\tfor (int k = 0; k < 2; k++) {\n\t\t\t\tdx.fog_pipelines[i][j][k]->Release();\n\t\t\t\tdx.dlight_pipelines[i][j][k]->Release();\n\t\t\t}\n\t\t}\n\t}\n\n\tdx.swapchain->Release();\n\tdx.command_allocator->Release();\n\tdx.helper_command_allocator->Release();\n\tdx.rtv_heap->Release();\n\tdx.srv_heap->Release();\n\tdx.sampler_heap->Release();\n\tdx.root_signature->Release();\n\tdx.command_queue->Release();\n\tdx.command_list->Release();\n\tdx.fence->Release();\n\tdx.depth_stencil_buffer->Release();\n\tdx.dsv_heap->Release();\n\tdx.geometry_buffer->Release();\n\tdx.skybox_pipeline->Release();\n\tdx.shadow_finish_pipeline->Release();\n\tdx.tris_debug_pipeline->Release();\n\tdx.tris_mirror_debug_pipeline->Release();\n\tdx.normals_debug_pipeline->Release();\n\tdx.surface_debug_pipeline_solid->Release();\n\tdx.surface_debug_pipeline_outline->Release();\n\tdx.images_debug_pipeline->Release();\n\n\tdx.device->Release();\n\n\tCom_Memset(&dx, 0, sizeof(dx));\n}\n\nvoid dx_release_resources() {\n\tdx_wait_device_idle();\n\n\tdx_world.pipeline_create_time = 0.0f;\n\tfor (int i = 0; i < dx_world.num_pipelines; i++) {\n\t\tdx_world.pipelines[i]->Release();\n\t}\n\n\tfor (int i = 0; i < MAX_VK_IMAGES; i++) {\n\t\tif (dx_world.images[i].texture != nullptr) {\n\t\t\tdx_world.images[i].texture->Release();\n\t\t}\n\t}\n\n\tCom_Memset(&dx_world, 0, sizeof(dx_world));\n\n\t// Reset geometry buffer's current offsets.\n\tdx.xyz_elements = 0;\n\tdx.color_st_elements = 0;\n\tdx.index_buffer_offset = 0;\n}\n\nvoid dx_wait_device_idle() {\n\tdx.fence_value++;\n\tDX_CHECK(dx.command_queue->Signal(dx.fence, dx.fence_value));\n\tDX_CHECK(dx.fence->SetEventOnCompletion(dx.fence_value, dx.fence_event));\n\tWaitForSingleObject(dx.fence_event, INFINITE);\n}\n\nDx_Image dx_create_image(int width, int height, Dx_Image_Format format, int mip_levels,  bool repeat_texture, int image_index) {\n\tDx_Image image;\n\n\tDXGI_FORMAT dx_format;\n\tif (format == IMAGE_FORMAT_RGBA8)\n\t\tdx_format = DXGI_FORMAT_R8G8B8A8_UNORM;\n\telse if (format == IMAGE_FORMAT_BGRA4)\n\t\tdx_format = DXGI_FORMAT_B4G4R4A4_UNORM;\n\telse {\n\t\tassert(format == IMAGE_FORMAT_BGR5A1);\n\t\tdx_format = DXGI_FORMAT_B5G5R5A1_UNORM;\n\t}\n\n\t// create texture\n\t{\n\t\tD3D12_RESOURCE_DESC desc;\n\t\tdesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;\n\t\tdesc.Alignment = 0;\n\t\tdesc.Width = width;\n\t\tdesc.Height = height;\n\t\tdesc.DepthOrArraySize = 1;\n\t\tdesc.MipLevels = mip_levels;\n\t\tdesc.Format = dx_format;\n\t\tdesc.SampleDesc.Count = 1;\n\t\tdesc.SampleDesc.Quality = 0;\n\t\tdesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;\n\t\tdesc.Flags = D3D12_RESOURCE_FLAG_NONE;\n\n\t\tDX_CHECK(dx.device->CreateCommittedResource(\n\t\t\t&get_heap_properties(D3D12_HEAP_TYPE_DEFAULT),\n\t\t\tD3D12_HEAP_FLAG_NONE,\n\t\t\t&desc,\n\t\t\tD3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,\n\t\t\tnullptr,\n\t\t\tIID_PPV_ARGS(&image.texture)));\n\t}\n\n\t// create texture descriptor\n\t{\n\t\tD3D12_SHADER_RESOURCE_VIEW_DESC srv_desc{};\n\t\tsrv_desc.Format = dx_format;\n\t\tsrv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;\n\t\tsrv_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;\n\t\tsrv_desc.Texture2D.MipLevels = mip_levels;\n\n\t\tD3D12_CPU_DESCRIPTOR_HANDLE handle;\n\t\thandle.ptr = dx.srv_heap->GetCPUDescriptorHandleForHeapStart().ptr + image_index * dx.srv_descriptor_size;\n\t\tdx.device->CreateShaderResourceView(image.texture, &srv_desc, handle);\n\n\t\tdx_world.current_image_indices[glState.currenttmu] = image_index;\n\t}\n\n\tif (mip_levels > 0)\n\t\timage.sampler_index = repeat_texture ? SAMPLER_MIP_REPEAT : SAMPLER_MIP_CLAMP;\n\telse\n\t\timage.sampler_index = repeat_texture ? SAMPLER_NOMIP_REPEAT : SAMPLER_NOMIP_CLAMP;\n\n\treturn image;\n}\n\nvoid dx_upload_image_data(ID3D12Resource* texture, int width, int height, int mip_levels, const uint8_t* pixels, int bytes_per_pixel) {\n\t//\n\t// Initialize subresource layouts int the upload texture.\n\t//\n\tauto align =[](size_t value, size_t alignment) {\n\t\treturn (value + alignment - 1) & ~(alignment - 1);\n\t};\n\n\tD3D12_PLACED_SUBRESOURCE_FOOTPRINT regions[16];\n\tUINT64 buffer_size = 0;\n\n\tint w = width;\n\tint h = height;\n\tfor (int i = 0; i < mip_levels; i++) {\n\t\tregions[i].Offset = buffer_size;\n\t\tregions[i].Footprint.Format = texture->GetDesc().Format;\n\t\tregions[i].Footprint.Width = w;\n\t\tregions[i].Footprint.Height = h;\n\t\tregions[i].Footprint.Depth = 1;\n\t\tregions[i].Footprint.RowPitch = static_cast<UINT>(align(w * bytes_per_pixel, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT));\n\t\tbuffer_size += align(regions[i].Footprint.RowPitch * h, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT);\n\t\tw >>= 1;\n\t\tif (w < 1) w = 1;\n\t\th >>= 1;\n\t\tif (h < 1) h = 1;\n\t}\n\n\t//\n\t// Create upload upload texture.\n\t//\n\tID3D12Resource* upload_texture;\n\tDX_CHECK(dx.device->CreateCommittedResource(\n\t\t\t&get_heap_properties(D3D12_HEAP_TYPE_UPLOAD),\n\t\t\tD3D12_HEAP_FLAG_NONE,\n\t\t\t&get_buffer_desc(buffer_size),\n\t\t\tD3D12_RESOURCE_STATE_GENERIC_READ,\n\t\t\tnullptr,\n\t\t\tIID_PPV_ARGS(&upload_texture)));\n\n\tbyte* upload_texture_data;\n\tDX_CHECK(upload_texture->Map(0, nullptr, reinterpret_cast<void**>(&upload_texture_data)));\n\tw = width;\n\th = height;\n\tfor (int i = 0; i < mip_levels; i++) {\n\t\tbyte* upload_subresource_base = upload_texture_data + regions[i].Offset;\n\t\tfor (int y = 0; y < h; y++) {\n\t\t\tCom_Memcpy(upload_subresource_base + regions[i].Footprint.RowPitch * y, pixels, w * bytes_per_pixel);\n\t\t\tpixels += w * bytes_per_pixel;\n\t\t}\n\t\tw >>= 1;\n\t\tif (w < 1) w = 1;\n\t\th >>= 1;\n\t\tif (h < 1) h = 1;\n\t}\n\tupload_texture->Unmap(0, nullptr);\n\n\t//\n\t// Copy data from upload texture to destination texture.\n\t//\n\trecord_and_run_commands([texture, upload_texture, &regions, mip_levels]\n\t\t(ID3D12GraphicsCommandList* command_list)\n\t{\n\t\tcommand_list->ResourceBarrier(1, &get_transition_barrier(texture,\n\t\t\tD3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_COPY_DEST));\n\n\t\tfor (UINT i = 0; i < mip_levels; ++i) {\n\t\t\tD3D12_TEXTURE_COPY_LOCATION  dst;\n\t\t\tdst.pResource = texture;\n\t\t\tdst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;\n\t\t\tdst.SubresourceIndex = i;\n\n\t\t\tD3D12_TEXTURE_COPY_LOCATION src;\n\t\t\tsrc.pResource = upload_texture;\n\t\t\tsrc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;\n\t\t\tsrc.PlacedFootprint = regions[i];\n\n\t\t\tcommand_list->CopyTextureRegion(&dst, 0, 0, 0, &src, nullptr);\n\t\t}\n\n\t\tcommand_list->ResourceBarrier(1, &get_transition_barrier(texture,\n\t\t\tD3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE));\n\t});\n\n\tupload_texture->Release();\n}\n\nstatic ID3D12PipelineState* create_pipeline(const Vk_Pipeline_Def& def) {\n\t// single texture VS\n\textern unsigned char single_texture_vs[];\n\textern long long single_texture_vs_size;\n\n\textern unsigned char single_texture_clipping_plane_vs[];\n\textern long long single_texture_clipping_plane_vs_size;\n\n\t// multi texture VS\n\textern unsigned char multi_texture_vs[];\n\textern long long multi_texture_vs_size;\n\n\textern unsigned char multi_texture_clipping_plane_vs[];\n\textern long long multi_texture_clipping_plane_vs_size;\n\n\t// single texture PS\n\textern unsigned char single_texture_ps[];\n\textern long long single_texture_ps_size;\n\n\textern unsigned char single_texture_gt0_ps[];\n\textern long long single_texture_gt0_ps_size;\n\n\textern unsigned char single_texture_lt80_ps[];\n\textern long long single_texture_lt80_ps_size;\n\n\textern unsigned char single_texture_ge80_ps[];\n\textern long long single_texture_ge80_ps_size;\n\n\t// multi texture mul PS\n\textern unsigned char multi_texture_mul_ps[];\n\textern long long multi_texture_mul_ps_size;\n\n\textern unsigned char multi_texture_mul_gt0_ps[];\n\textern long long multi_texture_mul_gt0_ps_size;\n\n\textern unsigned char multi_texture_mul_lt80_ps[];\n\textern long long multi_texture_mul_lt80_ps_size;\n\n\textern unsigned char multi_texture_mul_ge80_ps[];\n\textern long long multi_texture_mul_ge80_ps_size;\n\n\t// multi texture add PS\n\textern unsigned char multi_texture_add_ps[];\n\textern long long multi_texture_add_ps_size;\n\n\textern unsigned char multi_texture_add_gt0_ps[];\n\textern long long multi_texture_add_gt0_ps_size;\n\n\textern unsigned char multi_texture_add_lt80_ps[];\n\textern long long multi_texture_add_lt80_ps_size;\n\n\textern unsigned char multi_texture_add_ge80_ps[];\n\textern long long multi_texture_add_ge80_ps_size;\n\n#define BYTECODE(name) D3D12_SHADER_BYTECODE{name, (SIZE_T)name##_size}\n\n#define GET_PS_BYTECODE(base_name) \\\n\tif ((def.state_bits & GLS_ATEST_BITS) == 0) \\\n\t\tps_bytecode = BYTECODE(base_name##_ps); \\\n\telse if (def.state_bits & GLS_ATEST_GT_0) \\\n\t\tps_bytecode = BYTECODE(base_name##_gt0_ps); \\\n\telse if (def.state_bits & GLS_ATEST_LT_80) \\\n\t\tps_bytecode = BYTECODE(base_name##_lt80_ps); \\\n\telse if (def.state_bits & GLS_ATEST_GE_80) \\\n\t\tps_bytecode = BYTECODE(base_name##_ge80_ps); \\\n\telse \\\n\t\tri.Error(ERR_DROP, \"create_pipeline: invalid alpha test state bits\\n\");\n\n\tD3D12_SHADER_BYTECODE vs_bytecode;\n\tD3D12_SHADER_BYTECODE ps_bytecode;\n\tif (def.shader_type == Vk_Shader_Type::single_texture) {\n\t\tif (def.clipping_plane) {\n\t\t\tvs_bytecode = BYTECODE(single_texture_clipping_plane_vs);\n\t\t} else {\n\t\t\tvs_bytecode = BYTECODE(single_texture_vs);\n\t\t}\n\t\tGET_PS_BYTECODE(single_texture)\n\t} else if (def.shader_type == Vk_Shader_Type::multi_texture_mul) {\n\t\tif (def.clipping_plane) {\n\t\t\tvs_bytecode = BYTECODE(multi_texture_clipping_plane_vs);\n\t\t} else {\n\t\t\tvs_bytecode = BYTECODE(multi_texture_vs);\n\t\t}\n\t\tGET_PS_BYTECODE(multi_texture_mul)\n\t} else if (def.shader_type == Vk_Shader_Type::multi_texture_add) {\n\t\tif (def.clipping_plane) {\n\t\t\tvs_bytecode = BYTECODE(multi_texture_clipping_plane_vs);\n\t\t} else {\n\t\t\tvs_bytecode = BYTECODE(multi_texture_vs);\n\t\t}\n\t\tGET_PS_BYTECODE(multi_texture_add)\n\t}\n\n#undef GET_PS_BYTECODE\n#undef BYTECODE\n\n\t// Vertex elements.\n\tD3D12_INPUT_ELEMENT_DESC input_element_desc[] =\n\t{\n\t\t{ \"POSITION\", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },\n\t\t{ \"COLOR\", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 1, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },\n\t\t{ \"TEXCOORD\", 0, DXGI_FORMAT_R32G32_FLOAT, 2, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },\n\t\t{ \"TEXCOORD\", 1, DXGI_FORMAT_R32G32_FLOAT, 3, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }\n\t};\n\n\t//\n\t// Blend.\n\t//\n\tD3D12_BLEND_DESC blend_state;\n\tblend_state.AlphaToCoverageEnable = FALSE;\n\tblend_state.IndependentBlendEnable = FALSE;\n\tauto& rt_blend_desc = blend_state.RenderTarget[0];\n\trt_blend_desc.BlendEnable = (def.state_bits & (GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS)) ? TRUE : FALSE;\n\trt_blend_desc.LogicOpEnable = FALSE;\n\n\tif (rt_blend_desc.BlendEnable) {\n\t\tswitch (def.state_bits & GLS_SRCBLEND_BITS) {\n\t\t\tcase GLS_SRCBLEND_ZERO:\n\t\t\t\trt_blend_desc.SrcBlend = D3D12_BLEND_ZERO;\n\t\t\t\trt_blend_desc.SrcBlendAlpha = D3D12_BLEND_ZERO;\n\t\t\t\tbreak;\n\t\t\tcase GLS_SRCBLEND_ONE:\n\t\t\t\trt_blend_desc.SrcBlend = D3D12_BLEND_ONE;\n\t\t\t\trt_blend_desc.SrcBlendAlpha = D3D12_BLEND_ONE;\n\t\t\t\tbreak;\n\t\t\tcase GLS_SRCBLEND_DST_COLOR:\n\t\t\t\trt_blend_desc.SrcBlend = D3D12_BLEND_DEST_COLOR;\n\t\t\t\trt_blend_desc.SrcBlendAlpha = D3D12_BLEND_DEST_ALPHA;\n\t\t\t\tbreak;\n\t\t\tcase GLS_SRCBLEND_ONE_MINUS_DST_COLOR:\n\t\t\t\trt_blend_desc.SrcBlend = D3D12_BLEND_INV_DEST_COLOR;\n\t\t\t\trt_blend_desc.SrcBlendAlpha = D3D12_BLEND_INV_DEST_ALPHA;\n\t\t\t\tbreak;\n\t\t\tcase GLS_SRCBLEND_SRC_ALPHA:\n\t\t\t\trt_blend_desc.SrcBlend = D3D12_BLEND_SRC_ALPHA;\n\t\t\t\trt_blend_desc.SrcBlendAlpha = D3D12_BLEND_SRC_ALPHA;\n\t\t\t\tbreak;\n\t\t\tcase GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA:\n\t\t\t\trt_blend_desc.SrcBlend = D3D12_BLEND_INV_SRC_ALPHA;\n\t\t\t\trt_blend_desc.SrcBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA;\n\t\t\t\tbreak;\n\t\t\tcase GLS_SRCBLEND_DST_ALPHA:\n\t\t\t\trt_blend_desc.SrcBlend = D3D12_BLEND_DEST_ALPHA;\n\t\t\t\trt_blend_desc.SrcBlendAlpha = D3D12_BLEND_DEST_ALPHA;\n\t\t\t\tbreak;\n\t\t\tcase GLS_SRCBLEND_ONE_MINUS_DST_ALPHA:\n\t\t\t\trt_blend_desc.SrcBlend = D3D12_BLEND_INV_DEST_ALPHA;\n\t\t\t\trt_blend_desc.SrcBlendAlpha = D3D12_BLEND_INV_DEST_ALPHA;\n\t\t\t\tbreak;\n\t\t\tcase GLS_SRCBLEND_ALPHA_SATURATE:\n\t\t\t\trt_blend_desc.SrcBlend = D3D12_BLEND_SRC_ALPHA_SAT;\n\t\t\t\trt_blend_desc.SrcBlendAlpha = D3D12_BLEND_SRC_ALPHA_SAT;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tri.Error( ERR_DROP, \"create_pipeline: invalid src blend state bits\\n\" );\n\t\t\t\tbreak;\n\t\t}\n\t\tswitch (def.state_bits & GLS_DSTBLEND_BITS) {\n\t\t\tcase GLS_DSTBLEND_ZERO:\n\t\t\t\trt_blend_desc.DestBlend = D3D12_BLEND_ZERO;\n\t\t\t\trt_blend_desc.DestBlendAlpha = D3D12_BLEND_ZERO;\n\t\t\t\tbreak;\n\t\t\tcase GLS_DSTBLEND_ONE:\n\t\t\t\trt_blend_desc.DestBlend = D3D12_BLEND_ONE;\n\t\t\t\trt_blend_desc.DestBlendAlpha = D3D12_BLEND_ONE;\n\t\t\t\tbreak;\n\t\t\tcase GLS_DSTBLEND_SRC_COLOR:\n\t\t\t\trt_blend_desc.DestBlend = D3D12_BLEND_SRC_COLOR;\n\t\t\t\trt_blend_desc.DestBlendAlpha = D3D12_BLEND_SRC_ALPHA;\n\t\t\t\tbreak;\n\t\t\tcase GLS_DSTBLEND_ONE_MINUS_SRC_COLOR:\n\t\t\t\trt_blend_desc.DestBlend = D3D12_BLEND_INV_SRC_COLOR;\n\t\t\t\trt_blend_desc.DestBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA;\n\t\t\t\tbreak;\n\t\t\tcase GLS_DSTBLEND_SRC_ALPHA:\n\t\t\t\trt_blend_desc.DestBlend = D3D12_BLEND_SRC_ALPHA;\n\t\t\t\trt_blend_desc.DestBlendAlpha = D3D12_BLEND_SRC_ALPHA;\n\t\t\t\tbreak;\n\t\t\tcase GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA:\n\t\t\t\trt_blend_desc.DestBlend = D3D12_BLEND_INV_SRC_ALPHA;\n\t\t\t\trt_blend_desc.DestBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA;\n\t\t\t\tbreak;\n\t\t\tcase GLS_DSTBLEND_DST_ALPHA:\n\t\t\t\trt_blend_desc.DestBlend = D3D12_BLEND_DEST_ALPHA;\n\t\t\t\trt_blend_desc.DestBlendAlpha = D3D12_BLEND_DEST_ALPHA;\n\t\t\t\tbreak;\n\t\t\tcase GLS_DSTBLEND_ONE_MINUS_DST_ALPHA:\n\t\t\t\trt_blend_desc.DestBlend = D3D12_BLEND_INV_DEST_ALPHA;\n\t\t\t\trt_blend_desc.DestBlendAlpha = D3D12_BLEND_INV_DEST_ALPHA;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tri.Error( ERR_DROP, \"create_pipeline: invalid dst blend state bits\\n\" );\n\t\t\t\tbreak;\n\t\t}\n\t}\n\trt_blend_desc.BlendOp = D3D12_BLEND_OP_ADD;\n\trt_blend_desc.BlendOpAlpha = D3D12_BLEND_OP_ADD;\n\trt_blend_desc.LogicOp = D3D12_LOGIC_OP_COPY;\n\trt_blend_desc.RenderTargetWriteMask = (def.shadow_phase == Vk_Shadow_Phase::shadow_edges_rendering) ? 0 : D3D12_COLOR_WRITE_ENABLE_ALL;\n\n\t//\n\t// Rasteriazation state.\n\t//\n\tD3D12_RASTERIZER_DESC rasterization_state = {};\n\trasterization_state.FillMode = (def.state_bits & GLS_POLYMODE_LINE) ? D3D12_FILL_MODE_WIREFRAME : D3D12_FILL_MODE_SOLID;\n\n\tif (def.face_culling == CT_TWO_SIDED)\n\t\trasterization_state.CullMode = D3D12_CULL_MODE_NONE;\n\telse if (def.face_culling == CT_FRONT_SIDED)\n\t\trasterization_state.CullMode = (def.mirror ? D3D12_CULL_MODE_FRONT : D3D12_CULL_MODE_BACK);\n\telse if (def.face_culling == CT_BACK_SIDED)\n\t\trasterization_state.CullMode = (def.mirror ? D3D12_CULL_MODE_BACK : D3D12_CULL_MODE_FRONT);\n\telse\n\t\tri.Error(ERR_DROP, \"create_pipeline: invalid face culling mode\\n\");\n\n\trasterization_state.FrontCounterClockwise = FALSE; // Q3 defaults to clockwise vertex order\n\trasterization_state.DepthBias = def.polygon_offset ? r_offsetUnits->integer : 0;\n\trasterization_state.DepthBiasClamp = 0.0f;\n\trasterization_state.SlopeScaledDepthBias = def.polygon_offset ? r_offsetFactor->value : 0.0f;\n\trasterization_state.DepthClipEnable = TRUE;\n\trasterization_state.MultisampleEnable = FALSE;\n\trasterization_state.AntialiasedLineEnable = FALSE;\n\trasterization_state.ForcedSampleCount = 0;\n\trasterization_state.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;\n\n\t//\n\t// Depth/stencil state.\n\t//\n\tD3D12_DEPTH_STENCIL_DESC depth_stencil_state = {};\n\tdepth_stencil_state.DepthEnable = (def.state_bits & GLS_DEPTHTEST_DISABLE) ? FALSE : TRUE;\n\tdepth_stencil_state.DepthWriteMask = (def.state_bits & GLS_DEPTHMASK_TRUE) ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;\n\tdepth_stencil_state.DepthFunc = (def.state_bits & GLS_DEPTHFUNC_EQUAL) ? D3D12_COMPARISON_FUNC_EQUAL : D3D12_COMPARISON_FUNC_LESS_EQUAL;\n\tdepth_stencil_state.StencilEnable = (def.shadow_phase != Vk_Shadow_Phase::disabled) ? TRUE : FALSE;\n\tdepth_stencil_state.StencilReadMask = 255;\n\tdepth_stencil_state.StencilWriteMask = 255;\n\n\tif (def.shadow_phase == Vk_Shadow_Phase::shadow_edges_rendering) {\n\t\tdepth_stencil_state.FrontFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;\n\t\tdepth_stencil_state.FrontFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;\n\t\tdepth_stencil_state.FrontFace.StencilPassOp = (def.face_culling == CT_FRONT_SIDED) ? D3D12_STENCIL_OP_INCR_SAT : D3D12_STENCIL_OP_DECR_SAT;\n\t\tdepth_stencil_state.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS;\n\n\t\tdepth_stencil_state.BackFace = depth_stencil_state.FrontFace;\n\t} else if (def.shadow_phase == Vk_Shadow_Phase::fullscreen_quad_rendering) {\n\t\tdepth_stencil_state.FrontFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;\n\t\tdepth_stencil_state.FrontFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;\n\t\tdepth_stencil_state.FrontFace.StencilPassOp = D3D12_STENCIL_OP_KEEP;\n\t\tdepth_stencil_state.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_NOT_EQUAL;\n\n\t\tdepth_stencil_state.BackFace = depth_stencil_state.FrontFace;\n\t} else {\n\t\tdepth_stencil_state.FrontFace = {};\n\t\tdepth_stencil_state.BackFace = {};\n\t}\n\n\t//\n\t// Create pipeline state.\n\t//\n\tD3D12_GRAPHICS_PIPELINE_STATE_DESC pipeline_desc = {};\n\tpipeline_desc.pRootSignature = dx.root_signature;\n\tpipeline_desc.VS = vs_bytecode;\n\tpipeline_desc.PS = ps_bytecode;\n\tpipeline_desc.BlendState = blend_state;\n\tpipeline_desc.SampleMask = UINT_MAX;\n\tpipeline_desc.RasterizerState = rasterization_state;\n\tpipeline_desc.DepthStencilState = depth_stencil_state;\n\tpipeline_desc.InputLayout = { input_element_desc, def.shader_type == Vk_Shader_Type::single_texture ? 3u : 4u };\n\tpipeline_desc.PrimitiveTopologyType = def.line_primitives ? D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE : D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;\n\tpipeline_desc.NumRenderTargets = 1;\n\tpipeline_desc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;\n\tpipeline_desc.DSVFormat = get_depth_format();\n\tpipeline_desc.SampleDesc.Count = 1;\n\tpipeline_desc.SampleDesc.Quality = 0;\n\n\tID3D12PipelineState* pipeline;\n\tDX_CHECK(dx.device->CreateGraphicsPipelineState(&pipeline_desc, IID_PPV_ARGS(&pipeline)));\n\treturn pipeline;\n}\n\nstruct Timer {\n\tusing Clock = std::chrono::high_resolution_clock;\n\tusing Second = std::chrono::duration<double, std::ratio<1>>;\n\n\tClock::time_point start = Clock::now();\n\tdouble elapsed_seconds() const {\n\t\tconst auto duration = Clock::now() - start;\n\t\tdouble seconds = std::chrono::duration_cast<Second>(duration).count();\n\t\treturn seconds;\n\t}\n};\n\nvoid dx_create_sampler_descriptor(const Vk_Sampler_Def& def, Dx_Sampler_Index sampler_index)\n{\n\tuint32_t min, mag, mip;\n\n\tif (def.gl_mag_filter == GL_NEAREST) {\n\t\tmag = 0;\n\t} else if (def.gl_mag_filter == GL_LINEAR) {\n\t\tmag = 1;\n\t} else {\n\t\tri.Error(ERR_FATAL, \"create_sampler_descriptor: invalid gl_mag_filter\");\n\t}\n\n\tbool max_lod_0_25 = false; // used to emulate OpenGL's GL_LINEAR/GL_NEAREST minification filter\n\tif (def.gl_min_filter == GL_NEAREST) {\n\t\tmin = 0;\n\t\tmip = 0;\n\t\tmax_lod_0_25 = true;\n\t} else if (def.gl_min_filter == GL_LINEAR) {\n\t\tmin = 1;\n\t\tmip = 0;\n\t\tmax_lod_0_25 = true;\n\t} else if (def.gl_min_filter == GL_NEAREST_MIPMAP_NEAREST) {\n\t\tmin = 0;\n\t\tmip = 0;\n\t} else if (def.gl_min_filter == GL_LINEAR_MIPMAP_NEAREST) {\n\t\tmin = 1;\n\t\tmip = 0;\n\t} else if (def.gl_min_filter == GL_NEAREST_MIPMAP_LINEAR) {\n\t\tmin = 0;\n\t\tmip = 1;\n\t} else if (def.gl_min_filter == GL_LINEAR_MIPMAP_LINEAR) {\n\t\tmin = 1;\n\t\tmip = 1;\n\t} else {\n\t\tri.Error(ERR_FATAL, \"vk_find_sampler: invalid gl_min_filter\");\n\t}\n\n\tD3D12_TEXTURE_ADDRESS_MODE address_mode = def.repeat_texture ? D3D12_TEXTURE_ADDRESS_MODE_WRAP : D3D12_TEXTURE_ADDRESS_MODE_CLAMP;\n\n\tD3D12_SAMPLER_DESC sampler_desc;\n\tsampler_desc.Filter = D3D12_ENCODE_BASIC_FILTER(min, mag, mip, 0);\n\tsampler_desc.AddressU = address_mode;\n\tsampler_desc.AddressV = address_mode;\n\tsampler_desc.AddressW = address_mode;\n\tsampler_desc.MipLODBias = 0.0f;\n\tsampler_desc.MaxAnisotropy = 1;\n\tsampler_desc.ComparisonFunc = D3D12_COMPARISON_FUNC_ALWAYS;\n\tsampler_desc.BorderColor[0] = 0.0f;\n\tsampler_desc.BorderColor[1] = 0.0f;\n\tsampler_desc.BorderColor[2] = 0.0f;\n\tsampler_desc.BorderColor[3] = 0.0f;\n\tsampler_desc.MinLOD = 0.0f;\n\tsampler_desc.MaxLOD = max_lod_0_25 ? 0.25f : 12.0f;\n\n\tD3D12_CPU_DESCRIPTOR_HANDLE sampler_handle = dx.sampler_heap->GetCPUDescriptorHandleForHeapStart();\n\tsampler_handle.ptr += dx.sampler_descriptor_size * sampler_index;\n\n\tdx.device->CreateSampler(&sampler_desc, sampler_handle);\n}\n\nID3D12PipelineState* dx_find_pipeline(const Vk_Pipeline_Def& def) {\n\tfor (int i = 0; i < dx_world.num_pipelines; i++) {\n\t\tconst auto& cur_def = dx_world.pipeline_defs[i];\n\n\t\tif (cur_def.shader_type == def.shader_type &&\n\t\t\tcur_def.state_bits == def.state_bits &&\n\t\t\tcur_def.face_culling == def.face_culling &&\n\t\t\tcur_def.polygon_offset == def.polygon_offset &&\n\t\t\tcur_def.clipping_plane == def.clipping_plane &&\n\t\t\tcur_def.mirror == def.mirror &&\n\t\t\tcur_def.line_primitives == def.line_primitives &&\n\t\t\tcur_def.shadow_phase == def.shadow_phase)\n\t\t{\n\t\t\treturn dx_world.pipelines[i];\n\t\t}\n\t}\n\n\tif (dx_world.num_pipelines >= MAX_VK_PIPELINES) {\n\t\tri.Error(ERR_DROP, \"dx_find_pipeline: MAX_VK_PIPELINES hit\\n\");\n\t}\n\n\tTimer t;\n\tID3D12PipelineState* pipeline = create_pipeline(def);\n\tdx_world.pipeline_create_time += t.elapsed_seconds();\n\n\tdx_world.pipeline_defs[dx_world.num_pipelines] = def;\n\tdx_world.pipelines[dx_world.num_pipelines] = pipeline;\n\tdx_world.num_pipelines++;\n\treturn pipeline;\n}\n\nstatic void get_mvp_transform(float* mvp) {\n\tif (backEnd.projection2D) {\n\t\tfloat mvp0 = 2.0f / glConfig.vidWidth;\n\t\tfloat mvp5 = 2.0f / glConfig.vidHeight;\n\n\t\tmvp[0]  =  mvp0; mvp[1]  =  0.0f; mvp[2]  = 0.0f; mvp[3]  = 0.0f;\n\t\tmvp[4]  =  0.0f; mvp[5]  = -mvp5; mvp[6]  = 0.0f; mvp[7]  = 0.0f;\n\t\tmvp[8]  =  0.0f; mvp[9]  = 0.0f; mvp[10] = 1.0f; mvp[11] = 0.0f;\n\t\tmvp[12] = -1.0f; mvp[13] = 1.0f; mvp[14] = 0.0f; mvp[15] = 1.0f;\n\n\t} else {\n\t\tconst float* p = backEnd.viewParms.projectionMatrix;\n\n\t\t// update q3's proj matrix (opengl) to d3d conventions: z - [0, 1] instead of [-1, 1]\n\t\tfloat zNear\t= r_znear->value;\n\t\tfloat zFar = backEnd.viewParms.zFar;\n\t\tfloat P10 = -zFar / (zFar - zNear);\n\t\tfloat P14 = -zFar*zNear / (zFar - zNear);\n\n\t\tfloat proj[16] = {\n\t\t\tp[0],  p[1],  p[2], p[3],\n\t\t\tp[4],  p[5],  p[6], p[7],\n\t\t\tp[8],  p[9],  P10,  p[11],\n\t\t\tp[12], p[13], P14,  p[15]\n\t\t};\n\n\t\tmyGlMultMatrix(dx_world.modelview_transform, proj, mvp);\n\t}\n}\n\nstatic D3D12_RECT get_viewport_rect() {\n\tD3D12_RECT r;\n\tif (backEnd.projection2D) {\n\t\tr.left = 0.0f;\n\t\tr.top = 0.0f;\n\t\tr.right = glConfig.vidWidth;\n\t\tr.bottom = glConfig.vidHeight;\n\t} else {\n\t\tr.left = backEnd.viewParms.viewportX;\n\t\tr.top = glConfig.vidHeight - (backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight);\n\t\tr.right = r.left + backEnd.viewParms.viewportWidth;\n\t\tr.bottom = r.top + backEnd.viewParms.viewportHeight;\n\t}\n\treturn r;\n}\n\nstatic D3D12_VIEWPORT get_viewport(Vk_Depth_Range depth_range) {\n\tD3D12_RECT r = get_viewport_rect();\n\n\tD3D12_VIEWPORT viewport;\n\tviewport.TopLeftX = (float)r.left;\n\tviewport.TopLeftY = (float)r.top;\n\tviewport.Width = (float)(r.right - r.left);\n\tviewport.Height = (float)(r.bottom - r.top);\n\n\tif (depth_range == Vk_Depth_Range::force_zero) {\n\t\tviewport.MinDepth = 0.0f;\n\t\tviewport.MaxDepth = 0.0f;\n\t} else if (depth_range == Vk_Depth_Range::force_one) {\n\t\tviewport.MinDepth = 1.0f;\n\t\tviewport.MaxDepth = 1.0f;\n\t} else if (depth_range == Vk_Depth_Range::weapon) {\n\t\tviewport.MinDepth = 0.0f;\n\t\tviewport.MaxDepth = 0.3f;\n\t} else {\n\t\tviewport.MinDepth = 0.0f;\n\t\tviewport.MaxDepth = 1.0f;\n\t}\n\treturn viewport;\n}\n\nstatic D3D12_RECT get_scissor_rect() {\n\tD3D12_RECT r = get_viewport_rect();\n\n\tif (r.left < 0)\n\t\tr.left = 0;\n\tif (r.top < 0)\n\t\tr.top = 0;\n\n\tif (r.right > glConfig.vidWidth)\n\t\tr.right = glConfig.vidWidth;\n\tif (r.bottom > glConfig.vidHeight)\n\t\tr.bottom = glConfig.vidHeight;\n\n\treturn r;\n}\n\nvoid dx_clear_attachments(bool clear_depth_stencil, bool clear_color, vec4_t color) {\n\tif (!dx.active)\n\t\treturn;\n\n\tif (!clear_depth_stencil && !clear_color)\n\t\treturn;\n\n\tD3D12_RECT clear_rect = get_scissor_rect();\n\n\tif (clear_depth_stencil) {\n\t\tD3D12_CLEAR_FLAGS flags = D3D12_CLEAR_FLAG_DEPTH;\n\t\tif (r_shadows->integer == 2)\n\t\t\tflags |= D3D12_CLEAR_FLAG_STENCIL;\n\n\t\tD3D12_CPU_DESCRIPTOR_HANDLE dsv_handle = dx.dsv_heap->GetCPUDescriptorHandleForHeapStart();\n\t\tdx.command_list->ClearDepthStencilView(dsv_handle, flags, 1.0f, 0, 1, &clear_rect);\n\t}\n\n\tif (clear_color) {\n\t\tD3D12_CPU_DESCRIPTOR_HANDLE rtv_handle = dx.rtv_heap->GetCPUDescriptorHandleForHeapStart();\n\t\trtv_handle.ptr += dx.frame_index * dx.rtv_descriptor_size;\n\t\tdx.command_list->ClearRenderTargetView(rtv_handle, color, 1, &clear_rect);\n\t}\n}\n\nvoid dx_bind_geometry() {\n\t// xyz stream\n\t{\n\t\tif ((dx.xyz_elements + tess.numVertexes) * sizeof(vec4_t) > XYZ_SIZE)\n\t\t\tri.Error(ERR_DROP, \"dx_bind_geometry: vertex buffer overflow (xyz)\\n\");\n\n\t\tbyte* dst = dx.vertex_buffer_ptr + XYZ_OFFSET + dx.xyz_elements * sizeof(vec4_t);\n\t\tCom_Memcpy(dst, tess.xyz, tess.numVertexes * sizeof(vec4_t));\n\n\t\tuint32_t xyz_offset = XYZ_OFFSET + dx.xyz_elements * sizeof(vec4_t);\n\n\t\tD3D12_VERTEX_BUFFER_VIEW xyz_view;\n\t\txyz_view.BufferLocation = dx.geometry_buffer->GetGPUVirtualAddress() + xyz_offset;\n\t\txyz_view.SizeInBytes = static_cast<UINT>(tess.numVertexes * sizeof(vec4_t));\n\t\txyz_view.StrideInBytes = static_cast<UINT>(sizeof(vec4_t));\n\t\tdx.command_list->IASetVertexBuffers(0, 1, &xyz_view);\n\n\t\tdx.xyz_elements += tess.numVertexes;\n\t}\n\n\t// indexes stream\n\t{\n\t\tstd::size_t indexes_size = tess.numIndexes * sizeof(uint32_t);        \n\n\t\tif (dx.index_buffer_offset + indexes_size > INDEX_BUFFER_SIZE)\n\t\t\tri.Error(ERR_DROP, \"dx_bind_geometry: index buffer overflow\\n\");\n\n\t\tbyte* dst = dx.index_buffer_ptr + dx.index_buffer_offset;\n\t\tCom_Memcpy(dst, tess.indexes, indexes_size);\n\n\t\tD3D12_INDEX_BUFFER_VIEW index_view;\n\t\tindex_view.BufferLocation = dx.geometry_buffer->GetGPUVirtualAddress() + VERTEX_BUFFER_SIZE + dx.index_buffer_offset;\n\t\tindex_view.SizeInBytes = static_cast<UINT>(indexes_size);\n\t\tindex_view.Format = DXGI_FORMAT_R32_UINT;\n\t\tdx.command_list->IASetIndexBuffer(&index_view);\n\n\t\tdx.index_buffer_offset += static_cast<int>(indexes_size);\n\t}\n\n\t//\n\t// Specify push constants.\n\t//\n\tfloat root_constants[16 + 12 + 4]; // mvp transform + eye transform + clipping plane in eye space\n\n\tget_mvp_transform(root_constants);\n\tint root_constant_count = 16;\n\n\tif (backEnd.viewParms.isPortal) {\n\t\t// Eye space transform.\n\t\t// NOTE: backEnd.or.modelMatrix incorporates s_flipMatrix, so it should be taken into account \n\t\t// when computing clipping plane too.\n\t\tfloat* eye_xform = root_constants + 16;\n\t\tfor (int i = 0; i < 12; i++) {\n\t\t\teye_xform[i] = backEnd.or.modelMatrix[(i%4)*4 + i/4 ];\n\t\t}\n\n\t\t// Clipping plane in eye coordinates.\n\t\tfloat world_plane[4];\n\t\tworld_plane[0] = backEnd.viewParms.portalPlane.normal[0];\n\t\tworld_plane[1] = backEnd.viewParms.portalPlane.normal[1];\n\t\tworld_plane[2] = backEnd.viewParms.portalPlane.normal[2];\n\t\tworld_plane[3] = backEnd.viewParms.portalPlane.dist;\n\n\t\tfloat eye_plane[4];\n\t\teye_plane[0] = DotProduct (backEnd.viewParms.or.axis[0], world_plane);\n\t\teye_plane[1] = DotProduct (backEnd.viewParms.or.axis[1], world_plane);\n\t\teye_plane[2] = DotProduct (backEnd.viewParms.or.axis[2], world_plane);\n\t\teye_plane[3] = DotProduct (world_plane, backEnd.viewParms.or.origin) - world_plane[3];\n\n\t\t// Apply s_flipMatrix to be in the same coordinate system as eye_xfrom.\n\t\troot_constants[28] = -eye_plane[1];\n\t\troot_constants[29] =  eye_plane[2];\n\t\troot_constants[30] = -eye_plane[0];\n\t\troot_constants[31] =  eye_plane[3];\n\n\t\troot_constant_count += 16;\n\t}\n\tdx.command_list->SetGraphicsRoot32BitConstants(0, root_constant_count, root_constants, 0);\n}\n\nvoid dx_shade_geometry(ID3D12PipelineState* pipeline, bool multitexture, Vk_Depth_Range depth_range, bool indexed, bool lines) {\n\t// color\n\t{\n\t\tif ((dx.color_st_elements + tess.numVertexes) * sizeof(color4ub_t) > COLOR_SIZE)\n\t\t\tri.Error(ERR_DROP, \"vulkan: vertex buffer overflow (color)\\n\");\n\n\t\tbyte* dst = dx.vertex_buffer_ptr + COLOR_OFFSET + dx.color_st_elements * sizeof(color4ub_t);\n\t\tCom_Memcpy(dst, tess.svars.colors, tess.numVertexes * sizeof(color4ub_t));\n\t}\n\t// st0\n\t{\n\t\tif ((dx.color_st_elements + tess.numVertexes) * sizeof(vec2_t) > ST0_SIZE)\n\t\t\tri.Error(ERR_DROP, \"vulkan: vertex buffer overflow (st0)\\n\");\n\n\t\tbyte* dst = dx.vertex_buffer_ptr + ST0_OFFSET + dx.color_st_elements * sizeof(vec2_t);\n\t\tCom_Memcpy(dst, tess.svars.texcoords[0], tess.numVertexes * sizeof(vec2_t));\n\t}\n\t// st1\n\tif (multitexture) {\n\t\tif ((dx.color_st_elements + tess.numVertexes) * sizeof(vec2_t) > ST1_SIZE)\n\t\t\tri.Error(ERR_DROP, \"vulkan: vertex buffer overflow (st1)\\n\");\n\n\t\tbyte* dst = dx.vertex_buffer_ptr + ST1_OFFSET + dx.color_st_elements * sizeof(vec2_t);\n\t\tCom_Memcpy(dst, tess.svars.texcoords[1], tess.numVertexes * sizeof(vec2_t));\n\t}\n\n\t//\n\t// Configure vertex data stream.\n\t//\n\tD3D12_VERTEX_BUFFER_VIEW color_st_views[3];\n\tcolor_st_views[0].BufferLocation = dx.geometry_buffer->GetGPUVirtualAddress() + COLOR_OFFSET + dx.color_st_elements * sizeof(color4ub_t);\n\tcolor_st_views[0].SizeInBytes = static_cast<UINT>(tess.numVertexes * sizeof(color4ub_t));\n\tcolor_st_views[0].StrideInBytes = static_cast<UINT>(sizeof(color4ub_t));\n\n\tcolor_st_views[1].BufferLocation = dx.geometry_buffer->GetGPUVirtualAddress() + ST0_OFFSET + dx.color_st_elements * sizeof(vec2_t);\n\tcolor_st_views[1].SizeInBytes = static_cast<UINT>(tess.numVertexes * sizeof(vec2_t));\n\tcolor_st_views[1].StrideInBytes = static_cast<UINT>(sizeof(vec2_t));\n\n\tcolor_st_views[2].BufferLocation = dx.geometry_buffer->GetGPUVirtualAddress() + ST1_OFFSET + dx.color_st_elements * sizeof(vec2_t);\n\tcolor_st_views[2].SizeInBytes = static_cast<UINT>(tess.numVertexes * sizeof(vec2_t));\n\tcolor_st_views[2].StrideInBytes = static_cast<UINT>(sizeof(vec2_t));\n\n\tdx.command_list->IASetVertexBuffers(1, multitexture ? 3 : 2, color_st_views);\n\tdx.color_st_elements += tess.numVertexes;\n\n\t//\n\t// Set descriptor tables.\n\t//\n\t{\n\t\tD3D12_GPU_DESCRIPTOR_HANDLE srv_handle = dx.srv_heap->GetGPUDescriptorHandleForHeapStart();\n\t\tsrv_handle.ptr += dx.srv_descriptor_size * dx_world.current_image_indices[0];\n\t\tdx.command_list->SetGraphicsRootDescriptorTable(1, srv_handle);\n\n\t\tD3D12_GPU_DESCRIPTOR_HANDLE sampler_handle = dx.sampler_heap->GetGPUDescriptorHandleForHeapStart();\n\t\tconst int sampler_index = dx_world.images[dx_world.current_image_indices[0]].sampler_index;\n\t\tsampler_handle.ptr += dx.sampler_descriptor_size * sampler_index;\n\t\tdx.command_list->SetGraphicsRootDescriptorTable(2, sampler_handle);\n\t}\n\n\tif (multitexture) {\n\t\tD3D12_GPU_DESCRIPTOR_HANDLE srv_handle = dx.srv_heap->GetGPUDescriptorHandleForHeapStart();\n\t\tsrv_handle.ptr += dx.srv_descriptor_size * dx_world.current_image_indices[1];\n\t\tdx.command_list->SetGraphicsRootDescriptorTable(3, srv_handle);\n\n\t\tD3D12_GPU_DESCRIPTOR_HANDLE sampler_handle = dx.sampler_heap->GetGPUDescriptorHandleForHeapStart();\n\t\tconst int sampler_index = dx_world.images[dx_world.current_image_indices[1]].sampler_index;\n\t\tsampler_handle.ptr += dx.sampler_descriptor_size * sampler_index;\n\t\tdx.command_list->SetGraphicsRootDescriptorTable(4, sampler_handle);\n\t}\n\n\t//\n\t// Configure pipeline.\n\t//\n\tdx.command_list->SetPipelineState(pipeline);\n\tdx.command_list->IASetPrimitiveTopology(lines ? D3D10_PRIMITIVE_TOPOLOGY_LINELIST : D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);\n\n\tD3D12_RECT scissor_rect = get_scissor_rect();\n\tdx.command_list->RSSetScissorRects(1, &scissor_rect);\n\n\tD3D12_VIEWPORT viewport = get_viewport(depth_range);\n\tdx.command_list->RSSetViewports(1, &viewport);\n\n\t//\n\t// Draw.\n\t//\n\tif (indexed)\n\t\tdx.command_list->DrawIndexedInstanced(tess.numIndexes, 1, 0, 0, 0);\n\telse\n\t\tdx.command_list->DrawInstanced(tess.numVertexes, 1, 0, 0);\n}\n\nvoid dx_begin_frame() {\n\tif (!dx.active)\n\t\treturn;\n\n\tif (dx.fence->GetCompletedValue() < dx.fence_value) {\n\t\tDX_CHECK(dx.fence->SetEventOnCompletion(dx.fence_value, dx.fence_event));\n\t\tWaitForSingleObject(dx.fence_event, INFINITE);\n\t}\n\n\tdx.frame_index = dx.swapchain->GetCurrentBackBufferIndex();\n\n\tDX_CHECK(dx.command_allocator->Reset());\n\tDX_CHECK(dx.command_list->Reset(dx.command_allocator, nullptr));\n\n\tdx.command_list->SetGraphicsRootSignature(dx.root_signature);\n\n\tID3D12DescriptorHeap* heaps[] = { dx.srv_heap, dx.sampler_heap };\n\tdx.command_list->SetDescriptorHeaps(_countof(heaps), heaps);\n\n\tdx.command_list->ResourceBarrier(1, &get_transition_barrier(dx.render_targets[dx.frame_index],\n\t\tD3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET));\n\n\tD3D12_CPU_DESCRIPTOR_HANDLE dsv_handle = dx.dsv_heap->GetCPUDescriptorHandleForHeapStart();\n\n\tD3D12_CPU_DESCRIPTOR_HANDLE rtv_handle = dx.rtv_heap->GetCPUDescriptorHandleForHeapStart();\n\trtv_handle.ptr += dx.frame_index * dx.rtv_descriptor_size;\n\n\tdx.command_list->OMSetRenderTargets(1, &rtv_handle, FALSE, &dsv_handle);\n\n\tdx.xyz_elements = 0;\n\tdx.color_st_elements = 0;\n\tdx.index_buffer_offset = 0;\n}\n\nvoid dx_end_frame() {\n\tif (!dx.active)\n\t\treturn;\n\n\tdx.command_list->ResourceBarrier(1, &get_transition_barrier(dx.render_targets[dx.frame_index],\n\t\tD3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT));\n\n\tDX_CHECK(dx.command_list->Close());\n\n\tID3D12CommandList* command_list = dx.command_list;\n\tdx.command_queue->ExecuteCommandLists(1, &command_list);\n\n\tdx.fence_value++;\n\tDX_CHECK(dx.command_queue->Signal(dx.fence, dx.fence_value));\n\n\tDX_CHECK(dx.swapchain->Present(0, dx.present_allow_tearing ? DXGI_PRESENT_ALLOW_TEARING : 0));\n}\n\n#else // ENABLE_DX12\n\nvoid dx_initialize() {}\nvoid dx_shutdown() {}\nvoid dx_release_resources() {}\nvoid dx_wait_device_idle() {}\n\nDx_Image dx_create_image(int width, int height, Dx_Image_Format format, int mip_levels,  bool repeat_texture, int image_index) { return Dx_Image{}; }\nvoid dx_upload_image_data(ID3D12Resource* texture, int width, int height, int mip_levels, const uint8_t* pixels, int bytes_per_pixel) {}\nvoid dx_create_sampler_descriptor(const Vk_Sampler_Def& def, Dx_Sampler_Index sampler_index) {}\nID3D12PipelineState* dx_find_pipeline(const Vk_Pipeline_Def& def) { return nullptr; }\n\nvoid dx_clear_attachments(bool clear_depth_stencil, bool clear_color, vec4_t color) {}\nvoid dx_bind_geometry() {}\nvoid dx_shade_geometry(ID3D12PipelineState* pipeline, bool multitexture, Vk_Depth_Range depth_range, bool indexed, bool lines) {}\nvoid dx_begin_frame() {}\nvoid dx_end_frame() {}\n\n#endif  // ENABLE_DX12\n"
  },
  {
    "path": "src/engine/renderer/dx.h",
    "content": "#pragma once\n\n//\n// DirectX 12 backend implementation is provided mostly for educational purposes and is not included in the prebuild binaries.\n// It can be enabled by uncommenting the following line.\n//\n//#define ENABLE_DX12\n\nstruct ID3D12CommandAllocator;\nstruct ID3D12GraphicsCommandList;\nstruct ID3D12CommandQueue;\nstruct ID3D12Device;\nstruct ID3D12DescriptorHeap;\nstruct ID3D12Fence;\nstruct ID3D12PipelineState;\nstruct ID3D12Resource;\nstruct ID3D12RootSignature;\nstruct IDXGISwapChain3;\n\nconstexpr int SWAPCHAIN_BUFFER_COUNT = 2;\n\nenum Dx_Sampler_Index {\n\tSAMPLER_MIP_REPEAT,\n\tSAMPLER_MIP_CLAMP,\n\tSAMPLER_NOMIP_REPEAT,\n\tSAMPLER_NOMIP_CLAMP,\n\tSAMPLER_COUNT\n};\n\nenum Dx_Image_Format {\n\tIMAGE_FORMAT_RGBA8,\n\tIMAGE_FORMAT_BGRA4,\n\tIMAGE_FORMAT_BGR5A1\n};\n\nstruct Dx_Image {\n\tID3D12Resource* texture = nullptr;\n\tDx_Sampler_Index sampler_index = SAMPLER_COUNT;\n};\n\n//\n// Initialization.\n//\nvoid dx_initialize();\nvoid dx_shutdown();\nvoid dx_release_resources();\nvoid dx_wait_device_idle();\n\n//\n// Resources allocation.\n//\nDx_Image dx_create_image(int width, int height, Dx_Image_Format format, int mip_levels,  bool repeat_texture, int image_index);\nvoid dx_upload_image_data(ID3D12Resource* texture, int width, int height, int mip_levels, const uint8_t* pixels, int bytes_per_pixel);\nvoid dx_create_sampler_descriptor(const Vk_Sampler_Def& def, Dx_Sampler_Index sampler_index);\nID3D12PipelineState* dx_find_pipeline(const Vk_Pipeline_Def& def);\n\n//\n// Rendering setup.\n//\nvoid dx_clear_attachments(bool clear_depth_stencil, bool clear_color, vec4_t color);\nvoid dx_bind_geometry();\nvoid dx_shade_geometry(ID3D12PipelineState* pipeline, bool multitexture, Vk_Depth_Range depth_range, bool indexed, bool lines);\nvoid dx_begin_frame();\nvoid dx_end_frame();\n\nstruct Dx_Instance {\n\tbool active = false;\n\n\tID3D12Device* device = nullptr;\n\tID3D12CommandQueue* command_queue = nullptr;\n\tIDXGISwapChain3* swapchain = nullptr;\n    BOOL present_allow_tearing = false;\n\tUINT frame_index = 0;\n\n\tID3D12CommandAllocator* command_allocator = nullptr;\n\tID3D12CommandAllocator* helper_command_allocator = nullptr;\n\tID3D12GraphicsCommandList* command_list = nullptr;\n\t\n\tID3D12Fence* fence = nullptr;\n\tUINT64 fence_value = 0;\n\tHANDLE fence_event = NULL;\n\n\tID3D12Resource* render_targets[SWAPCHAIN_BUFFER_COUNT];\n\tID3D12Resource* depth_stencil_buffer = nullptr;\n\n\tID3D12RootSignature* root_signature = nullptr;\n\n\t//\n\t// Descriptor heaps.\n\t//\n\tID3D12DescriptorHeap* rtv_heap = nullptr;\n\tUINT rtv_descriptor_size = 0;\n\n\tID3D12DescriptorHeap* dsv_heap = nullptr;\n\n\tID3D12DescriptorHeap* srv_heap = nullptr;\n\tUINT srv_descriptor_size = 0;\n\n\tID3D12DescriptorHeap* sampler_heap = nullptr;\n\tUINT sampler_descriptor_size = 0;\n\n\t//\n\t// Geometry buffers.\n\t//\n\tbyte* vertex_buffer_ptr = nullptr; // pointer to mapped vertex buffer\n\tint xyz_elements = 0;\n\tint color_st_elements = 0;\n\n\tbyte* index_buffer_ptr = nullptr; // pointer to mapped index buffer\n\tint index_buffer_offset = 0;\n\n\tID3D12Resource* geometry_buffer = nullptr;\n\n\t//\n\t// Standard pipelines.\n\t//\n\tID3D12PipelineState* skybox_pipeline = nullptr;\n\n\t// dim 0: 0 - front side, 1 - back size\n\t// dim 1: 0 - normal view, 1 - mirror view\n\tID3D12PipelineState* shadow_volume_pipelines[2][2];\n\tID3D12PipelineState* shadow_finish_pipeline = nullptr;\n\n\t// dim 0 is based on fogPass_t: 0 - corresponds to FP_EQUAL, 1 - corresponds to FP_LE.\n\t// dim 1 is directly a cullType_t enum value.\n\t// dim 2 is a polygon offset value (0 - off, 1 - on).\n\tID3D12PipelineState* fog_pipelines[2][3][2];\n\n\t// dim 0 is based on dlight additive flag: 0 - not additive, 1 - additive\n\t// dim 1 is directly a cullType_t enum value.\n\t// dim 2 is a polygon offset value (0 - off, 1 - on).\n\tID3D12PipelineState* dlight_pipelines[2][3][2];\n\n\t// debug visualization pipelines\n\tID3D12PipelineState* tris_debug_pipeline = nullptr;\n\tID3D12PipelineState* tris_mirror_debug_pipeline = nullptr;\n\tID3D12PipelineState* normals_debug_pipeline = nullptr;\n\tID3D12PipelineState* surface_debug_pipeline_solid = nullptr;\n\tID3D12PipelineState* surface_debug_pipeline_outline = nullptr;\n\tID3D12PipelineState* images_debug_pipeline = nullptr;\n};\n\nstruct Dx_World {\n\t//\n\t// Resources.\n\t//\n\tint num_pipelines = 0;\n\tVk_Pipeline_Def pipeline_defs[MAX_VK_PIPELINES];\n\tID3D12PipelineState* pipelines[MAX_VK_PIPELINES];\n\tfloat pipeline_create_time;\n\n\tDx_Image images[MAX_VK_IMAGES];\n\n\t//\n\t// State.\n\t//\n\tint current_image_indices[2];\n\tfloat modelview_transform[16];\n};\n"
  },
  {
    "path": "src/engine/renderer/jpeg/stb_image.h",
    "content": "/* stb_image - v2.14 - public domain image loader - http://nothings.org/stb_image.h\n                                     no warranty implied; use at your own risk\n\n   Do this:\n      #define STB_IMAGE_IMPLEMENTATION\n   before you include this file in *one* C or C++ file to create the implementation.\n\n   // i.e. it should look like this:\n   #include ...\n   #include ...\n   #include ...\n   #define STB_IMAGE_IMPLEMENTATION\n   #include \"stb_image.h\"\n\n   You can #define STBI_ASSERT(x) before the #include to avoid using assert.h.\n   And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free\n\n\n   QUICK NOTES:\n      Primarily of interest to game developers and other people who can\n          avoid problematic images and only need the trivial interface\n\n      JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib)\n      PNG 1/2/4/8/16-bit-per-channel\n\n      TGA (not sure what subset, if a subset)\n      BMP non-1bpp, non-RLE\n      PSD (composited view only, no extra channels, 8/16 bit-per-channel)\n\n      GIF (*comp always reports as 4-channel)\n      HDR (radiance rgbE format)\n      PIC (Softimage PIC)\n      PNM (PPM and PGM binary only)\n\n      Animated GIF still needs a proper API, but here's one way to do it:\n          http://gist.github.com/urraka/685d9a6340b26b830d49\n\n      - decode from memory or through FILE (define STBI_NO_STDIO to remove code)\n      - decode from arbitrary I/O callbacks\n      - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON)\n\n   Full documentation under \"DOCUMENTATION\" below.\n\n\nLICENSE\n\n  See end of file for license information.\n\nRECENT REVISION HISTORY:\n\n      2.14  (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs\n      2.13  (2016-12-04) experimental 16-bit API, only for PNG so far; fixes\n      2.12  (2016-04-02) fix typo in 2.11 PSD fix that caused crashes\n      2.11  (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64\n                         RGB-format JPEG; remove white matting in PSD;\n                         allocate large structures on the stack; \n                         correct channel count for PNG & BMP\n      2.10  (2016-01-22) avoid warning introduced in 2.09\n      2.09  (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED\n      2.08  (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA\n      2.07  (2015-09-13) partial animated GIF support\n                         limited 16-bit PSD support\n                         minor bugs, code cleanup, and compiler warnings\n\n   See end of file for full revision history.\n\n\n ============================    Contributors    =========================\n\n Image formats                          Extensions, features\n    Sean Barrett (jpeg, png, bmp)          Jetro Lauha (stbi_info)\n    Nicolas Schulz (hdr, psd)              Martin \"SpartanJ\" Golini (stbi_info)\n    Jonathan Dummer (tga)                  James \"moose2000\" Brown (iPhone PNG)\n    Jean-Marc Lienher (gif)                Ben \"Disch\" Wenger (io callbacks)\n    Tom Seddon (pic)                       Omar Cornut (1/2/4-bit PNG)\n    Thatcher Ulrich (psd)                  Nicolas Guillemot (vertical flip)\n    Ken Miller (pgm, ppm)                  Richard Mitton (16-bit PSD)\n    github:urraka (animated gif)           Junggon Kim (PNM comments)\n                                           Daniel Gibson (16-bit TGA)\n                                           socks-the-fox (16-bit TGA)\n                                           Jeremy Sawicki (handle all ImageNet JPGs)\n Optimizations & bugfixes\n    Fabian \"ryg\" Giesen\n    Arseny Kapoulkine\n\n Bug & warning fixes\n    Marc LeBlanc            David Woo          Guillaume George   Martins Mozeiko\n    Christpher Lloyd        Martin Golini      Jerry Jansson      Joseph Thomson\n    Dave Moore              Roy Eltham         Hayaki Saito       Phil Jordan\n    Won Chun                Luke Graham        Johan Duparc       Nathan Reed\n    the Horde3D community   Thomas Ruf         Ronny Chevalier    Nick Verigakis\n    Janez Zemva             John Bartholomew   Michal Cichon      github:svdijk\n    Jonathan Blow           Ken Hamada         Tero Hanninen      Baldur Karlsson\n    Laurent Gomila          Cort Stratton      Sergio Gonzalez    github:romigrou\n    Aruelien Pocheville     Thibault Reuille   Cass Everitt       Matthew Gregan\n    Ryamond Barbiero        Paul Du Bois       Engin Manap        github:snagar\n    Michaelangel007@github  Oriol Ferrer Mesia Dale Weiler        github:Zelex\n    Philipp Wiesemann       Josh Tobin         github:rlyeh       github:grim210@github\n    Blazej Dariusz Roszkowski                  github:sammyhw\n\n*/\n\n#ifndef STBI_INCLUDE_STB_IMAGE_H\n#define STBI_INCLUDE_STB_IMAGE_H\n\n// DOCUMENTATION\n//\n// Limitations:\n//    - no 16-bit-per-channel PNG\n//    - no 12-bit-per-channel JPEG\n//    - no JPEGs with arithmetic coding\n//    - no 1-bit BMP\n//    - GIF always returns *comp=4\n//\n// Basic usage (see HDR discussion below for HDR usage):\n//    int x,y,n;\n//    unsigned char *data = stbi_load(filename, &x, &y, &n, 0);\n//    // ... process data if not NULL ...\n//    // ... x = width, y = height, n = # 8-bit components per pixel ...\n//    // ... replace '0' with '1'..'4' to force that many components per pixel\n//    // ... but 'n' will always be the number that it would have been if you said 0\n//    stbi_image_free(data)\n//\n// Standard parameters:\n//    int *x                 -- outputs image width in pixels\n//    int *y                 -- outputs image height in pixels\n//    int *channels_in_file  -- outputs # of image components in image file\n//    int desired_channels   -- if non-zero, # of image components requested in result\n//\n// The return value from an image loader is an 'unsigned char *' which points\n// to the pixel data, or NULL on an allocation failure or if the image is\n// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels,\n// with each pixel consisting of N interleaved 8-bit components; the first\n// pixel pointed to is top-left-most in the image. There is no padding between\n// image scanlines or between pixels, regardless of format. The number of\n// components N is 'req_comp' if req_comp is non-zero, or *comp otherwise.\n// If req_comp is non-zero, *comp has the number of components that _would_\n// have been output otherwise. E.g. if you set req_comp to 4, you will always\n// get RGBA output, but you can check *comp to see if it's trivially opaque\n// because e.g. there were only 3 channels in the source image.\n//\n// An output image with N components has the following components interleaved\n// in this order in each pixel:\n//\n//     N=#comp     components\n//       1           grey\n//       2           grey, alpha\n//       3           red, green, blue\n//       4           red, green, blue, alpha\n//\n// If image loading fails for any reason, the return value will be NULL,\n// and *x, *y, *comp will be unchanged. The function stbi_failure_reason()\n// can be queried for an extremely brief, end-user unfriendly explanation\n// of why the load failed. Define STBI_NO_FAILURE_STRINGS to avoid\n// compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly\n// more user-friendly ones.\n//\n// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized.\n//\n// ===========================================================================\n//\n// Philosophy\n//\n// stb libraries are designed with the following priorities:\n//\n//    1. easy to use\n//    2. easy to maintain\n//    3. good performance\n//\n// Sometimes I let \"good performance\" creep up in priority over \"easy to maintain\",\n// and for best performance I may provide less-easy-to-use APIs that give higher\n// performance, in addition to the easy to use ones. Nevertheless, it's important\n// to keep in mind that from the standpoint of you, a client of this library,\n// all you care about is #1 and #3, and stb libraries DO NOT emphasize #3 above all.\n//\n// Some secondary priorities arise directly from the first two, some of which\n// make more explicit reasons why performance can't be emphasized.\n//\n//    - Portable (\"ease of use\")\n//    - Small source code footprint (\"easy to maintain\")\n//    - No dependencies (\"ease of use\")\n//\n// ===========================================================================\n//\n// I/O callbacks\n//\n// I/O callbacks allow you to read from arbitrary sources, like packaged\n// files or some other source. Data read from callbacks are processed\n// through a small internal buffer (currently 128 bytes) to try to reduce\n// overhead.\n//\n// The three functions you must define are \"read\" (reads some bytes of data),\n// \"skip\" (skips some bytes of data), \"eof\" (reports if the stream is at the end).\n//\n// ===========================================================================\n//\n// SIMD support\n//\n// The JPEG decoder will try to automatically use SIMD kernels on x86 when\n// supported by the compiler. For ARM Neon support, you must explicitly\n// request it.\n//\n// (The old do-it-yourself SIMD API is no longer supported in the current\n// code.)\n//\n// On x86, SSE2 will automatically be used when available based on a run-time\n// test; if not, the generic C versions are used as a fall-back. On ARM targets,\n// the typical path is to have separate builds for NEON and non-NEON devices\n// (at least this is true for iOS and Android). Therefore, the NEON support is\n// toggled by a build flag: define STBI_NEON to get NEON loops.\n//\n// If for some reason you do not want to use any of SIMD code, or if\n// you have issues compiling it, you can disable it entirely by\n// defining STBI_NO_SIMD.\n//\n// ===========================================================================\n//\n// HDR image support   (disable by defining STBI_NO_HDR)\n//\n// stb_image now supports loading HDR images in general, and currently\n// the Radiance .HDR file format, although the support is provided\n// generically. You can still load any file through the existing interface;\n// if you attempt to load an HDR file, it will be automatically remapped to\n// LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1;\n// both of these constants can be reconfigured through this interface:\n//\n//     stbi_hdr_to_ldr_gamma(2.2f);\n//     stbi_hdr_to_ldr_scale(1.0f);\n//\n// (note, do not use _inverse_ constants; stbi_image will invert them\n// appropriately).\n//\n// Additionally, there is a new, parallel interface for loading files as\n// (linear) floats to preserve the full dynamic range:\n//\n//    float *data = stbi_loadf(filename, &x, &y, &n, 0);\n//\n// If you load LDR images through this interface, those images will\n// be promoted to floating point values, run through the inverse of\n// constants corresponding to the above:\n//\n//     stbi_ldr_to_hdr_scale(1.0f);\n//     stbi_ldr_to_hdr_gamma(2.2f);\n//\n// Finally, given a filename (or an open file or memory block--see header\n// file for details) containing image data, you can query for the \"most\n// appropriate\" interface to use (that is, whether the image is HDR or\n// not), using:\n//\n//     stbi_is_hdr(char *filename);\n//\n// ===========================================================================\n//\n// iPhone PNG support:\n//\n// By default we convert iphone-formatted PNGs back to RGB, even though\n// they are internally encoded differently. You can disable this conversion\n// by by calling stbi_convert_iphone_png_to_rgb(0), in which case\n// you will always just get the native iphone \"format\" through (which\n// is BGR stored in RGB).\n//\n// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per\n// pixel to remove any premultiplied alpha *only* if the image file explicitly\n// says there's premultiplied data (currently only happens in iPhone images,\n// and only if iPhone convert-to-rgb processing is on).\n//\n// ===========================================================================\n//\n// ADDITIONAL CONFIGURATION\n// \n//  - You can suppress implementation of any of the decoders to reduce\n//    your code footprint by #defining one or more of the following\n//    symbols before creating the implementation.\n// \n//        STBI_NO_JPEG\n//        STBI_NO_PNG\n//        STBI_NO_BMP\n//        STBI_NO_PSD\n//        STBI_NO_TGA\n//        STBI_NO_GIF\n//        STBI_NO_HDR\n//        STBI_NO_PIC\n//        STBI_NO_PNM   (.ppm and .pgm)\n// \n//  - You can request *only* certain decoders and suppress all other ones\n//    (this will be more forward-compatible, as addition of new decoders\n//    doesn't require you to disable them explicitly):\n// \n//        STBI_ONLY_JPEG\n//        STBI_ONLY_PNG\n//        STBI_ONLY_BMP\n//        STBI_ONLY_PSD\n//        STBI_ONLY_TGA\n//        STBI_ONLY_GIF\n//        STBI_ONLY_HDR\n//        STBI_ONLY_PIC\n//        STBI_ONLY_PNM   (.ppm and .pgm)\n// \n//   - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still\n//     want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB\n//\n\n\n#ifndef STBI_NO_STDIO\n#include <stdio.h>\n#endif // STBI_NO_STDIO\n\n#define STBI_VERSION 1\n\nenum\n{\n   STBI_default = 0, // only used for req_comp\n\n   STBI_grey       = 1,\n   STBI_grey_alpha = 2,\n   STBI_rgb        = 3,\n   STBI_rgb_alpha  = 4\n};\n\ntypedef unsigned char stbi_uc;\ntypedef unsigned short stbi_us;\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#ifdef STB_IMAGE_STATIC\n#define STBIDEF static\n#else\n#define STBIDEF extern\n#endif\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// PRIMARY API - works on images of any type\n//\n\n//\n// load image by filename, open file, or memory buffer\n//\n\ntypedef struct\n{\n   int      (*read)  (void *user,char *data,int size);   // fill 'data' with 'size' bytes.  return number of bytes actually read\n   void     (*skip)  (void *user,int n);                 // skip the next 'n' bytes, or 'unget' the last -n bytes if negative\n   int      (*eof)   (void *user);                       // returns nonzero if we are at end of file/data\n} stbi_io_callbacks;\n\n////////////////////////////////////\n//\n// 8-bits-per-channel interface\n//\n\nSTBIDEF stbi_uc *stbi_load               (char              const *filename,           int *x, int *y, int *channels_in_file, int desired_channels);\nSTBIDEF stbi_uc *stbi_load_from_memory   (stbi_uc           const *buffer, int len   , int *x, int *y, int *channels_in_file, int desired_channels);\nSTBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk  , void *user, int *x, int *y, int *channels_in_file, int desired_channels);\n\n#ifndef STBI_NO_STDIO\nSTBIDEF stbi_uc *stbi_load_from_file   (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);\n// for stbi_load_from_file, file pointer is left pointing immediately after image\n#endif\n\n////////////////////////////////////\n//\n// 16-bits-per-channel interface\n//\n\nSTBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);\n#ifndef STBI_NO_STDIO\nSTBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);\n#endif\n// @TODO the other variants\n\n////////////////////////////////////\n//\n// float-per-channel interface\n//\n#ifndef STBI_NO_LINEAR\n   STBIDEF float *stbi_loadf                 (char const *filename,           int *x, int *y, int *channels_in_file, int desired_channels);\n   STBIDEF float *stbi_loadf_from_memory     (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels);\n   STBIDEF float *stbi_loadf_from_callbacks  (stbi_io_callbacks const *clbk, void *user, int *x, int *y,  int *channels_in_file, int desired_channels);\n\n   #ifndef STBI_NO_STDIO\n   STBIDEF float *stbi_loadf_from_file  (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);\n   #endif\n#endif\n\n#ifndef STBI_NO_HDR\n   STBIDEF void   stbi_hdr_to_ldr_gamma(float gamma);\n   STBIDEF void   stbi_hdr_to_ldr_scale(float scale);\n#endif // STBI_NO_HDR\n\n#ifndef STBI_NO_LINEAR\n   STBIDEF void   stbi_ldr_to_hdr_gamma(float gamma);\n   STBIDEF void   stbi_ldr_to_hdr_scale(float scale);\n#endif // STBI_NO_LINEAR\n\n// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR\nSTBIDEF int    stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user);\nSTBIDEF int    stbi_is_hdr_from_memory(stbi_uc const *buffer, int len);\n#ifndef STBI_NO_STDIO\nSTBIDEF int      stbi_is_hdr          (char const *filename);\nSTBIDEF int      stbi_is_hdr_from_file(FILE *f);\n#endif // STBI_NO_STDIO\n\n\n// get a VERY brief reason for failure\n// NOT THREADSAFE\nSTBIDEF const char *stbi_failure_reason  (void);\n\n// free the loaded image -- this is just free()\nSTBIDEF void     stbi_image_free      (void *retval_from_stbi_load);\n\n// get image dimensions & components without fully decoding\nSTBIDEF int      stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp);\nSTBIDEF int      stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp);\n\n#ifndef STBI_NO_STDIO\nSTBIDEF int      stbi_info            (char const *filename,     int *x, int *y, int *comp);\nSTBIDEF int      stbi_info_from_file  (FILE *f,                  int *x, int *y, int *comp);\n\n#endif\n\n\n\n// for image formats that explicitly notate that they have premultiplied alpha,\n// we just return the colors as stored in the file. set this flag to force\n// unpremultiplication. results are undefined if the unpremultiply overflow.\nSTBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply);\n\n// indicate whether we should process iphone images back to canonical format,\n// or just pass them through \"as-is\"\nSTBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert);\n\n// flip the image vertically, so the first pixel in the output array is the bottom left\nSTBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip);\n\n// ZLIB client - used by PNG, available for other purposes\n\nSTBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen);\nSTBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header);\nSTBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen);\nSTBIDEF int   stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);\n\nSTBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen);\nSTBIDEF int   stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);\n\n\n#ifdef __cplusplus\n}\n#endif\n\n//\n//\n////   end header file   /////////////////////////////////////////////////////\n#endif // STBI_INCLUDE_STB_IMAGE_H\n\n#ifdef STB_IMAGE_IMPLEMENTATION\n\n#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \\\n  || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \\\n  || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \\\n  || defined(STBI_ONLY_ZLIB)\n   #ifndef STBI_ONLY_JPEG\n   #define STBI_NO_JPEG\n   #endif\n   #ifndef STBI_ONLY_PNG\n   #define STBI_NO_PNG\n   #endif\n   #ifndef STBI_ONLY_BMP\n   #define STBI_NO_BMP\n   #endif\n   #ifndef STBI_ONLY_PSD\n   #define STBI_NO_PSD\n   #endif\n   #ifndef STBI_ONLY_TGA\n   #define STBI_NO_TGA\n   #endif\n   #ifndef STBI_ONLY_GIF\n   #define STBI_NO_GIF\n   #endif\n   #ifndef STBI_ONLY_HDR\n   #define STBI_NO_HDR\n   #endif\n   #ifndef STBI_ONLY_PIC\n   #define STBI_NO_PIC\n   #endif\n   #ifndef STBI_ONLY_PNM\n   #define STBI_NO_PNM\n   #endif\n#endif\n\n#if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB)\n#define STBI_NO_ZLIB\n#endif\n\n\n#include <stdarg.h>\n#include <stddef.h> // ptrdiff_t on osx\n#include <stdlib.h>\n#include <string.h>\n#include <limits.h>\n\n#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR)\n#include <math.h>  // ldexp\n#endif\n\n#ifndef STBI_NO_STDIO\n#include <stdio.h>\n#endif\n\n#ifndef STBI_ASSERT\n#include <assert.h>\n#define STBI_ASSERT(x) assert(x)\n#endif\n\n\n#ifndef _MSC_VER\n   #ifdef __cplusplus\n   #define stbi_inline inline\n   #else\n   #define stbi_inline\n   #endif\n#else\n   #define stbi_inline __forceinline\n#endif\n\n\n#ifdef _MSC_VER\ntypedef unsigned short stbi__uint16;\ntypedef   signed short stbi__int16;\ntypedef unsigned int   stbi__uint32;\ntypedef   signed int   stbi__int32;\n#else\n#include <stdint.h>\ntypedef uint16_t stbi__uint16;\ntypedef int16_t  stbi__int16;\ntypedef uint32_t stbi__uint32;\ntypedef int32_t  stbi__int32;\n#endif\n\n// should produce compiler error if size is wrong\ntypedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1];\n\n#ifdef _MSC_VER\n#define STBI_NOTUSED(v)  (void)(v)\n#else\n#define STBI_NOTUSED(v)  (void)sizeof(v)\n#endif\n\n#ifdef _MSC_VER\n#define STBI_HAS_LROTL\n#endif\n\n#ifdef STBI_HAS_LROTL\n   #define stbi_lrot(x,y)  _lrotl(x,y)\n#else\n   #define stbi_lrot(x,y)  (((x) << (y)) | ((x) >> (32 - (y))))\n#endif\n\n#if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED))\n// ok\n#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) && !defined(STBI_REALLOC_SIZED)\n// ok\n#else\n#error \"Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC (or STBI_REALLOC_SIZED).\"\n#endif\n\n#ifndef STBI_MALLOC\n#define STBI_MALLOC(sz)           malloc(sz)\n#define STBI_REALLOC(p,newsz)     realloc(p,newsz)\n#define STBI_FREE(p)              free(p)\n#endif\n\n#ifndef STBI_REALLOC_SIZED\n#define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz)\n#endif\n\n// x86/x64 detection\n#if defined(__x86_64__) || defined(_M_X64)\n#define STBI__X64_TARGET\n#elif defined(__i386) || defined(_M_IX86)\n#define STBI__X86_TARGET\n#endif\n\n#if defined(__GNUC__) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET)) && !defined(__SSE2__) && !defined(STBI_NO_SIMD)\n// NOTE: not clear do we actually need this for the 64-bit path?\n// gcc doesn't support sse2 intrinsics unless you compile with -msse2,\n// (but compiling with -msse2 allows the compiler to use SSE2 everywhere;\n// this is just broken and gcc are jerks for not fixing it properly\n// http://www.virtualdub.org/blog/pivot/entry.php?id=363 )\n#define STBI_NO_SIMD\n#endif\n\n#if defined(__MINGW32__) && defined(STBI__X86_TARGET) && !defined(STBI_MINGW_ENABLE_SSE2) && !defined(STBI_NO_SIMD)\n// Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid STBI__X64_TARGET\n//\n// 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the\n// Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant.\n// As a result, enabling SSE2 on 32-bit MinGW is dangerous when not\n// simultaneously enabling \"-mstackrealign\".\n//\n// See https://github.com/nothings/stb/issues/81 for more information.\n//\n// So default to no SSE2 on 32-bit MinGW. If you've read this far and added\n// -mstackrealign to your build settings, feel free to #define STBI_MINGW_ENABLE_SSE2.\n#define STBI_NO_SIMD\n#endif\n\n#if !defined(STBI_NO_SIMD) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET))\n#define STBI_SSE2\n#include <emmintrin.h>\n\n#ifdef _MSC_VER\n\n#if _MSC_VER >= 1400  // not VC6\n#include <intrin.h> // __cpuid\nstatic int stbi__cpuid3(void)\n{\n   int info[4];\n   __cpuid(info,1);\n   return info[3];\n}\n#else\nstatic int stbi__cpuid3(void)\n{\n   int res;\n   __asm {\n      mov  eax,1\n      cpuid\n      mov  res,edx\n   }\n   return res;\n}\n#endif\n\n#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name\n\nstatic int stbi__sse2_available()\n{\n   int info3 = stbi__cpuid3();\n   return ((info3 >> 26) & 1) != 0;\n}\n#else // assume GCC-style if not VC++\n#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16)))\n\nstatic int stbi__sse2_available()\n{\n#if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 408 // GCC 4.8 or later\n   // GCC 4.8+ has a nice way to do this\n   return __builtin_cpu_supports(\"sse2\");\n#else\n   // portable way to do this, preferably without using GCC inline ASM?\n   // just bail for now.\n   return 0;\n#endif\n}\n#endif\n#endif\n\n// ARM NEON\n#if defined(STBI_NO_SIMD) && defined(STBI_NEON)\n#undef STBI_NEON\n#endif\n\n#ifdef STBI_NEON\n#include <arm_neon.h>\n// assume GCC or Clang on ARM targets\n#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16)))\n#endif\n\n#ifndef STBI_SIMD_ALIGN\n#define STBI_SIMD_ALIGN(type, name) type name\n#endif\n\n///////////////////////////////////////////////\n//\n//  stbi__context struct and start_xxx functions\n\n// stbi__context structure is our basic context used by all images, so it\n// contains all the IO context, plus some basic image information\ntypedef struct\n{\n   stbi__uint32 img_x, img_y;\n   int img_n, img_out_n;\n\n   stbi_io_callbacks io;\n   void *io_user_data;\n\n   int read_from_callbacks;\n   int buflen;\n   stbi_uc buffer_start[128];\n\n   stbi_uc *img_buffer, *img_buffer_end;\n   stbi_uc *img_buffer_original, *img_buffer_original_end;\n} stbi__context;\n\n\nstatic void stbi__refill_buffer(stbi__context *s);\n\n// initialize a memory-decode context\nstatic void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len)\n{\n   s->io.read = NULL;\n   s->read_from_callbacks = 0;\n   s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer;\n   s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len;\n}\n\n// initialize a callback-based context\nstatic void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user)\n{\n   s->io = *c;\n   s->io_user_data = user;\n   s->buflen = sizeof(s->buffer_start);\n   s->read_from_callbacks = 1;\n   s->img_buffer_original = s->buffer_start;\n   stbi__refill_buffer(s);\n   s->img_buffer_original_end = s->img_buffer_end;\n}\n\n#ifndef STBI_NO_STDIO\n\nstatic int stbi__stdio_read(void *user, char *data, int size)\n{\n   return (int) fread(data,1,size,(FILE*) user);\n}\n\nstatic void stbi__stdio_skip(void *user, int n)\n{\n   fseek((FILE*) user, n, SEEK_CUR);\n}\n\nstatic int stbi__stdio_eof(void *user)\n{\n   return feof((FILE*) user);\n}\n\nstatic stbi_io_callbacks stbi__stdio_callbacks =\n{\n   stbi__stdio_read,\n   stbi__stdio_skip,\n   stbi__stdio_eof,\n};\n\nstatic void stbi__start_file(stbi__context *s, FILE *f)\n{\n   stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f);\n}\n\n//static void stop_file(stbi__context *s) { }\n\n#endif // !STBI_NO_STDIO\n\nstatic void stbi__rewind(stbi__context *s)\n{\n   // conceptually rewind SHOULD rewind to the beginning of the stream,\n   // but we just rewind to the beginning of the initial buffer, because\n   // we only use it after doing 'test', which only ever looks at at most 92 bytes\n   s->img_buffer = s->img_buffer_original;\n   s->img_buffer_end = s->img_buffer_original_end;\n}\n\nenum\n{\n   STBI_ORDER_RGB,\n   STBI_ORDER_BGR\n};\n\ntypedef struct\n{\n   int bits_per_channel;\n   int num_channels;\n   int channel_order;\n} stbi__result_info;\n\n#ifndef STBI_NO_JPEG\nstatic int      stbi__jpeg_test(stbi__context *s);\nstatic void    *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);\nstatic int      stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp);\n#endif\n\n#ifndef STBI_NO_PNG\nstatic int      stbi__png_test(stbi__context *s);\nstatic void    *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);\nstatic int      stbi__png_info(stbi__context *s, int *x, int *y, int *comp);\n#endif\n\n#ifndef STBI_NO_BMP\nstatic int      stbi__bmp_test(stbi__context *s);\nstatic void    *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);\nstatic int      stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp);\n#endif\n\n#ifndef STBI_NO_TGA\nstatic int      stbi__tga_test(stbi__context *s);\nstatic void    *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);\nstatic int      stbi__tga_info(stbi__context *s, int *x, int *y, int *comp);\n#endif\n\n#ifndef STBI_NO_PSD\nstatic int      stbi__psd_test(stbi__context *s);\nstatic void    *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc);\nstatic int      stbi__psd_info(stbi__context *s, int *x, int *y, int *comp);\n#endif\n\n#ifndef STBI_NO_HDR\nstatic int      stbi__hdr_test(stbi__context *s);\nstatic float   *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);\nstatic int      stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp);\n#endif\n\n#ifndef STBI_NO_PIC\nstatic int      stbi__pic_test(stbi__context *s);\nstatic void    *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);\nstatic int      stbi__pic_info(stbi__context *s, int *x, int *y, int *comp);\n#endif\n\n#ifndef STBI_NO_GIF\nstatic int      stbi__gif_test(stbi__context *s);\nstatic void    *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);\nstatic int      stbi__gif_info(stbi__context *s, int *x, int *y, int *comp);\n#endif\n\n#ifndef STBI_NO_PNM\nstatic int      stbi__pnm_test(stbi__context *s);\nstatic void    *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);\nstatic int      stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp);\n#endif\n\n// this is not threadsafe\nstatic const char *stbi__g_failure_reason;\n\nSTBIDEF const char *stbi_failure_reason(void)\n{\n   return stbi__g_failure_reason;\n}\n\nstatic int stbi__err(const char *str)\n{\n   stbi__g_failure_reason = str;\n   return 0;\n}\n\nstatic void *stbi__malloc(size_t size)\n{\n    return STBI_MALLOC(size);\n}\n\n// stb_image uses ints pervasively, including for offset calculations.\n// therefore the largest decoded image size we can support with the\n// current code, even on 64-bit targets, is INT_MAX. this is not a\n// significant limitation for the intended use case.\n//\n// we do, however, need to make sure our size calculations don't\n// overflow. hence a few helper functions for size calculations that\n// multiply integers together, making sure that they're non-negative\n// and no overflow occurs.\n\n// return 1 if the sum is valid, 0 on overflow.\n// negative terms are considered invalid.\nstatic int stbi__addsizes_valid(int a, int b)\n{\n   if (b < 0) return 0;\n   // now 0 <= b <= INT_MAX, hence also\n   // 0 <= INT_MAX - b <= INTMAX.\n   // And \"a + b <= INT_MAX\" (which might overflow) is the\n   // same as a <= INT_MAX - b (no overflow)\n   return a <= INT_MAX - b;\n}\n\n// returns 1 if the product is valid, 0 on overflow.\n// negative factors are considered invalid.\nstatic int stbi__mul2sizes_valid(int a, int b)\n{\n   if (a < 0 || b < 0) return 0;\n   if (b == 0) return 1; // mul-by-0 is always safe\n   // portable way to check for no overflows in a*b\n   return a <= INT_MAX/b;\n}\n\n// returns 1 if \"a*b + add\" has no negative terms/factors and doesn't overflow\nstatic int stbi__mad2sizes_valid(int a, int b, int add)\n{\n   return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add);\n}\n\n// returns 1 if \"a*b*c + add\" has no negative terms/factors and doesn't overflow\nstatic int stbi__mad3sizes_valid(int a, int b, int c, int add)\n{\n   return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) &&\n      stbi__addsizes_valid(a*b*c, add);\n}\n\n// returns 1 if \"a*b*c*d + add\" has no negative terms/factors and doesn't overflow\nstatic int stbi__mad4sizes_valid(int a, int b, int c, int d, int add)\n{\n   return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) &&\n      stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add);\n}\n\n// mallocs with size overflow checking\nstatic void *stbi__malloc_mad2(int a, int b, int add)\n{\n   if (!stbi__mad2sizes_valid(a, b, add)) return NULL;\n   return stbi__malloc(a*b + add);\n}\n\nstatic void *stbi__malloc_mad3(int a, int b, int c, int add)\n{\n   if (!stbi__mad3sizes_valid(a, b, c, add)) return NULL;\n   return stbi__malloc(a*b*c + add);\n}\n\nstatic void *stbi__malloc_mad4(int a, int b, int c, int d, int add)\n{\n   if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL;\n   return stbi__malloc(a*b*c*d + add);\n}\n\n// stbi__err - error\n// stbi__errpf - error returning pointer to float\n// stbi__errpuc - error returning pointer to unsigned char\n\n#ifdef STBI_NO_FAILURE_STRINGS\n   #define stbi__err(x,y)  0\n#elif defined(STBI_FAILURE_USERMSG)\n   #define stbi__err(x,y)  stbi__err(y)\n#else\n   #define stbi__err(x,y)  stbi__err(x)\n#endif\n\n#define stbi__errpf(x,y)   ((float *)(size_t) (stbi__err(x,y)?NULL:NULL))\n#define stbi__errpuc(x,y)  ((unsigned char *)(size_t) (stbi__err(x,y)?NULL:NULL))\n\nSTBIDEF void stbi_image_free(void *retval_from_stbi_load)\n{\n   STBI_FREE(retval_from_stbi_load);\n}\n\n#ifndef STBI_NO_LINEAR\nstatic float   *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp);\n#endif\n\n#ifndef STBI_NO_HDR\nstatic stbi_uc *stbi__hdr_to_ldr(float   *data, int x, int y, int comp);\n#endif\n\nstatic int stbi__vertically_flip_on_load = 0;\n\nSTBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip)\n{\n    stbi__vertically_flip_on_load = flag_true_if_should_flip;\n}\n\nstatic void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc)\n{\n   memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields\n   ri->bits_per_channel = 8; // default is 8 so most paths don't have to be changed\n   ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order\n   ri->num_channels = 0;\n\n   #ifndef STBI_NO_JPEG\n   if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri);\n   #endif\n   #ifndef STBI_NO_PNG\n   if (stbi__png_test(s))  return stbi__png_load(s,x,y,comp,req_comp, ri);\n   #endif\n   #ifndef STBI_NO_BMP\n   if (stbi__bmp_test(s))  return stbi__bmp_load(s,x,y,comp,req_comp, ri);\n   #endif\n   #ifndef STBI_NO_GIF\n   if (stbi__gif_test(s))  return stbi__gif_load(s,x,y,comp,req_comp, ri);\n   #endif\n   #ifndef STBI_NO_PSD\n   if (stbi__psd_test(s))  return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc);\n   #endif\n   #ifndef STBI_NO_PIC\n   if (stbi__pic_test(s))  return stbi__pic_load(s,x,y,comp,req_comp, ri);\n   #endif\n   #ifndef STBI_NO_PNM\n   if (stbi__pnm_test(s))  return stbi__pnm_load(s,x,y,comp,req_comp, ri);\n   #endif\n\n   #ifndef STBI_NO_HDR\n   if (stbi__hdr_test(s)) {\n      float *hdr = stbi__hdr_load(s, x,y,comp,req_comp, ri);\n      return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp);\n   }\n   #endif\n\n   #ifndef STBI_NO_TGA\n   // test tga last because it's a crappy test!\n   if (stbi__tga_test(s))\n      return stbi__tga_load(s,x,y,comp,req_comp, ri);\n   #endif\n\n   return stbi__errpuc(\"unknown image type\", \"Image not of any known type, or corrupt\");\n}\n\nstatic stbi_uc *stbi__convert_16_to_8(stbi__uint16 *orig, int w, int h, int channels)\n{\n   int i;\n   int img_len = w * h * channels;\n   stbi_uc *reduced;\n\n   reduced = (stbi_uc *) stbi__malloc(img_len);\n   if (reduced == NULL) return stbi__errpuc(\"outofmem\", \"Out of memory\");\n\n   for (i = 0; i < img_len; ++i)\n      reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is sufficient approx of 16->8 bit scaling\n\n   STBI_FREE(orig);\n   return reduced;\n}\n\nstatic stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int channels)\n{\n   int i;\n   int img_len = w * h * channels;\n   stbi__uint16 *enlarged;\n\n   enlarged = (stbi__uint16 *) stbi__malloc(img_len*2);\n   if (enlarged == NULL) return (stbi__uint16 *) stbi__errpuc(\"outofmem\", \"Out of memory\");\n\n   for (i = 0; i < img_len; ++i)\n      enlarged[i] = (stbi__uint16)((orig[i] << 8) + orig[i]); // replicate to high and low byte, maps 0->0, 255->0xffff\n\n   STBI_FREE(orig);\n   return enlarged;\n}\n\nstatic unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp)\n{\n   stbi__result_info ri;\n   void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 8);\n\n   if (result == NULL)\n      return NULL;\n\n   if (ri.bits_per_channel != 8) {\n      STBI_ASSERT(ri.bits_per_channel == 16);\n      result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp);\n      ri.bits_per_channel = 8;\n   }\n\n   // @TODO: move stbi__convert_format to here\n\n   if (stbi__vertically_flip_on_load) {\n      int w = *x, h = *y;\n      int channels = req_comp ? req_comp : *comp;\n      int row,col,z;\n      stbi_uc *image = (stbi_uc *) result;\n\n      // @OPTIMIZE: use a bigger temp buffer and memcpy multiple pixels at once\n      for (row = 0; row < (h>>1); row++) {\n         for (col = 0; col < w; col++) {\n            for (z = 0; z < channels; z++) {\n               stbi_uc temp = image[(row * w + col) * channels + z];\n               image[(row * w + col) * channels + z] = image[((h - row - 1) * w + col) * channels + z];\n               image[((h - row - 1) * w + col) * channels + z] = temp;\n            }\n         }\n      }\n   }\n\n   return (unsigned char *) result;\n}\n\nstatic stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, int *y, int *comp, int req_comp)\n{\n   stbi__result_info ri;\n   void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 16);\n\n   if (result == NULL)\n      return NULL;\n\n   if (ri.bits_per_channel != 16) {\n      STBI_ASSERT(ri.bits_per_channel == 8);\n      result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp);\n      ri.bits_per_channel = 16;\n   }\n\n   // @TODO: move stbi__convert_format16 to here\n   // @TODO: special case RGB-to-Y (and RGBA-to-YA) for 8-bit-to-16-bit case to keep more precision\n\n   if (stbi__vertically_flip_on_load) {\n      int w = *x, h = *y;\n      int channels = req_comp ? req_comp : *comp;\n      int row,col,z;\n      stbi__uint16 *image = (stbi__uint16 *) result;\n\n      // @OPTIMIZE: use a bigger temp buffer and memcpy multiple pixels at once\n      for (row = 0; row < (h>>1); row++) {\n         for (col = 0; col < w; col++) {\n            for (z = 0; z < channels; z++) {\n               stbi__uint16 temp = image[(row * w + col) * channels + z];\n               image[(row * w + col) * channels + z] = image[((h - row - 1) * w + col) * channels + z];\n               image[((h - row - 1) * w + col) * channels + z] = temp;\n            }\n         }\n      }\n   }\n\n   return (stbi__uint16 *) result;\n}\n\n#ifndef STBI_NO_HDR\nstatic void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp)\n{\n   if (stbi__vertically_flip_on_load && result != NULL) {\n      int w = *x, h = *y;\n      int depth = req_comp ? req_comp : *comp;\n      int row,col,z;\n      float temp;\n\n      // @OPTIMIZE: use a bigger temp buffer and memcpy multiple pixels at once\n      for (row = 0; row < (h>>1); row++) {\n         for (col = 0; col < w; col++) {\n            for (z = 0; z < depth; z++) {\n               temp = result[(row * w + col) * depth + z];\n               result[(row * w + col) * depth + z] = result[((h - row - 1) * w + col) * depth + z];\n               result[((h - row - 1) * w + col) * depth + z] = temp;\n            }\n         }\n      }\n   }\n}\n#endif\n\n#ifndef STBI_NO_STDIO\n\nstatic FILE *stbi__fopen(char const *filename, char const *mode)\n{\n   FILE *f;\n#if defined(_MSC_VER) && _MSC_VER >= 1400\n   if (0 != fopen_s(&f, filename, mode))\n      f=0;\n#else\n   f = fopen(filename, mode);\n#endif\n   return f;\n}\n\n\nSTBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp)\n{\n   FILE *f = stbi__fopen(filename, \"rb\");\n   unsigned char *result;\n   if (!f) return stbi__errpuc(\"can't fopen\", \"Unable to open file\");\n   result = stbi_load_from_file(f,x,y,comp,req_comp);\n   fclose(f);\n   return result;\n}\n\nSTBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp)\n{\n   unsigned char *result;\n   stbi__context s;\n   stbi__start_file(&s,f);\n   result = stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp);\n   if (result) {\n      // need to 'unget' all the characters in the IO buffer\n      fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR);\n   }\n   return result;\n}\n\nSTBIDEF stbi__uint16 *stbi_load_from_file_16(FILE *f, int *x, int *y, int *comp, int req_comp)\n{\n   stbi__uint16 *result;\n   stbi__context s;\n   stbi__start_file(&s,f);\n   result = stbi__load_and_postprocess_16bit(&s,x,y,comp,req_comp);\n   if (result) {\n      // need to 'unget' all the characters in the IO buffer\n      fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR);\n   }\n   return result;\n}\n\nSTBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, int req_comp)\n{\n   FILE *f = stbi__fopen(filename, \"rb\");\n   stbi__uint16 *result;\n   if (!f) return (stbi_us *) stbi__errpuc(\"can't fopen\", \"Unable to open file\");\n   result = stbi_load_from_file_16(f,x,y,comp,req_comp);\n   fclose(f);\n   return result;\n}\n\n\n#endif //!STBI_NO_STDIO\n\nSTBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp)\n{\n   stbi__context s;\n   stbi__start_mem(&s,buffer,len);\n   return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp);\n}\n\nSTBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)\n{\n   stbi__context s;\n   stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);\n   return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp);\n}\n\n#ifndef STBI_NO_LINEAR\nstatic float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp)\n{\n   unsigned char *data;\n   #ifndef STBI_NO_HDR\n   if (stbi__hdr_test(s)) {\n      stbi__result_info ri;\n      float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp, &ri);\n      if (hdr_data)\n         stbi__float_postprocess(hdr_data,x,y,comp,req_comp);\n      return hdr_data;\n   }\n   #endif\n   data = stbi__load_and_postprocess_8bit(s, x, y, comp, req_comp);\n   if (data)\n      return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp);\n   return stbi__errpf(\"unknown image type\", \"Image not of any known type, or corrupt\");\n}\n\nSTBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp)\n{\n   stbi__context s;\n   stbi__start_mem(&s,buffer,len);\n   return stbi__loadf_main(&s,x,y,comp,req_comp);\n}\n\nSTBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)\n{\n   stbi__context s;\n   stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);\n   return stbi__loadf_main(&s,x,y,comp,req_comp);\n}\n\n#ifndef STBI_NO_STDIO\nSTBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp)\n{\n   float *result;\n   FILE *f = stbi__fopen(filename, \"rb\");\n   if (!f) return stbi__errpf(\"can't fopen\", \"Unable to open file\");\n   result = stbi_loadf_from_file(f,x,y,comp,req_comp);\n   fclose(f);\n   return result;\n}\n\nSTBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp)\n{\n   stbi__context s;\n   stbi__start_file(&s,f);\n   return stbi__loadf_main(&s,x,y,comp,req_comp);\n}\n#endif // !STBI_NO_STDIO\n\n#endif // !STBI_NO_LINEAR\n\n// these is-hdr-or-not is defined independent of whether STBI_NO_LINEAR is\n// defined, for API simplicity; if STBI_NO_LINEAR is defined, it always\n// reports false!\n\nSTBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len)\n{\n   #ifndef STBI_NO_HDR\n   stbi__context s;\n   stbi__start_mem(&s,buffer,len);\n   return stbi__hdr_test(&s);\n   #else\n   STBI_NOTUSED(buffer);\n   STBI_NOTUSED(len);\n   return 0;\n   #endif\n}\n\n#ifndef STBI_NO_STDIO\nSTBIDEF int      stbi_is_hdr          (char const *filename)\n{\n   FILE *f = stbi__fopen(filename, \"rb\");\n   int result=0;\n   if (f) {\n      result = stbi_is_hdr_from_file(f);\n      fclose(f);\n   }\n   return result;\n}\n\nSTBIDEF int      stbi_is_hdr_from_file(FILE *f)\n{\n   #ifndef STBI_NO_HDR\n   stbi__context s;\n   stbi__start_file(&s,f);\n   return stbi__hdr_test(&s);\n   #else\n   STBI_NOTUSED(f);\n   return 0;\n   #endif\n}\n#endif // !STBI_NO_STDIO\n\nSTBIDEF int      stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user)\n{\n   #ifndef STBI_NO_HDR\n   stbi__context s;\n   stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);\n   return stbi__hdr_test(&s);\n   #else\n   STBI_NOTUSED(clbk);\n   STBI_NOTUSED(user);\n   return 0;\n   #endif\n}\n\n#ifndef STBI_NO_LINEAR\nstatic float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f;\n\nSTBIDEF void   stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; }\nSTBIDEF void   stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; }\n#endif\n\nstatic float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f;\n\nSTBIDEF void   stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; }\nSTBIDEF void   stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; }\n\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// Common code used by all image loaders\n//\n\nenum\n{\n   STBI__SCAN_load=0,\n   STBI__SCAN_type,\n   STBI__SCAN_header\n};\n\nstatic void stbi__refill_buffer(stbi__context *s)\n{\n   int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen);\n   if (n == 0) {\n      // at end of file, treat same as if from memory, but need to handle case\n      // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file\n      s->read_from_callbacks = 0;\n      s->img_buffer = s->buffer_start;\n      s->img_buffer_end = s->buffer_start+1;\n      *s->img_buffer = 0;\n   } else {\n      s->img_buffer = s->buffer_start;\n      s->img_buffer_end = s->buffer_start + n;\n   }\n}\n\nstbi_inline static stbi_uc stbi__get8(stbi__context *s)\n{\n   if (s->img_buffer < s->img_buffer_end)\n      return *s->img_buffer++;\n   if (s->read_from_callbacks) {\n      stbi__refill_buffer(s);\n      return *s->img_buffer++;\n   }\n   return 0;\n}\n\nstbi_inline static int stbi__at_eof(stbi__context *s)\n{\n   if (s->io.read) {\n      if (!(s->io.eof)(s->io_user_data)) return 0;\n      // if feof() is true, check if buffer = end\n      // special case: we've only got the special 0 character at the end\n      if (s->read_from_callbacks == 0) return 1;\n   }\n\n   return s->img_buffer >= s->img_buffer_end;\n}\n\nstatic void stbi__skip(stbi__context *s, int n)\n{\n   if (n < 0) {\n      s->img_buffer = s->img_buffer_end;\n      return;\n   }\n   if (s->io.read) {\n      int blen = (int) (s->img_buffer_end - s->img_buffer);\n      if (blen < n) {\n         s->img_buffer = s->img_buffer_end;\n         (s->io.skip)(s->io_user_data, n - blen);\n         return;\n      }\n   }\n   s->img_buffer += n;\n}\n\nstatic int stbi__getn(stbi__context *s, stbi_uc *buffer, int n)\n{\n   if (s->io.read) {\n      int blen = (int) (s->img_buffer_end - s->img_buffer);\n      if (blen < n) {\n         int res, count;\n\n         memcpy(buffer, s->img_buffer, blen);\n\n         count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen);\n         res = (count == (n-blen));\n         s->img_buffer = s->img_buffer_end;\n         return res;\n      }\n   }\n\n   if (s->img_buffer+n <= s->img_buffer_end) {\n      memcpy(buffer, s->img_buffer, n);\n      s->img_buffer += n;\n      return 1;\n   } else\n      return 0;\n}\n\nstatic int stbi__get16be(stbi__context *s)\n{\n   int z = stbi__get8(s);\n   return (z << 8) + stbi__get8(s);\n}\n\nstatic stbi__uint32 stbi__get32be(stbi__context *s)\n{\n   stbi__uint32 z = stbi__get16be(s);\n   return (z << 16) + stbi__get16be(s);\n}\n\n#if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF)\n// nothing\n#else\nstatic int stbi__get16le(stbi__context *s)\n{\n   int z = stbi__get8(s);\n   return z + (stbi__get8(s) << 8);\n}\n#endif\n\n#ifndef STBI_NO_BMP\nstatic stbi__uint32 stbi__get32le(stbi__context *s)\n{\n   stbi__uint32 z = stbi__get16le(s);\n   return z + (stbi__get16le(s) << 16);\n}\n#endif\n\n#define STBI__BYTECAST(x)  ((stbi_uc) ((x) & 255))  // truncate int to byte without warnings\n\n\n//////////////////////////////////////////////////////////////////////////////\n//\n//  generic converter from built-in img_n to req_comp\n//    individual types do this automatically as much as possible (e.g. jpeg\n//    does all cases internally since it needs to colorspace convert anyway,\n//    and it never has alpha, so very few cases ). png can automatically\n//    interleave an alpha=255 channel, but falls back to this for other cases\n//\n//  assume data buffer is malloced, so malloc a new one and free that one\n//  only failure mode is malloc failing\n\nstatic stbi_uc stbi__compute_y(int r, int g, int b)\n{\n   return (stbi_uc) (((r*77) + (g*150) +  (29*b)) >> 8);\n}\n\nstatic unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y)\n{\n   int i,j;\n   unsigned char *good;\n\n   if (req_comp == img_n) return data;\n   STBI_ASSERT(req_comp >= 1 && req_comp <= 4);\n\n   good = (unsigned char *) stbi__malloc_mad3(req_comp, x, y, 0);\n   if (good == NULL) {\n      STBI_FREE(data);\n      return stbi__errpuc(\"outofmem\", \"Out of memory\");\n   }\n\n   for (j=0; j < (int) y; ++j) {\n      unsigned char *src  = data + j * x * img_n   ;\n      unsigned char *dest = good + j * x * req_comp;\n\n      #define STBI__COMBO(a,b)  ((a)*8+(b))\n      #define STBI__CASE(a,b)   case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b)\n      // convert source image with img_n components to one with req_comp components;\n      // avoid switch per pixel, so use switch per scanline and massive macros\n      switch (STBI__COMBO(img_n, req_comp)) {\n         STBI__CASE(1,2) { dest[0]=src[0], dest[1]=255;                                     } break;\n         STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0];                                  } break;\n         STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=255;                     } break;\n         STBI__CASE(2,1) { dest[0]=src[0];                                                  } break;\n         STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0];                                  } break;\n         STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1];                  } break;\n         STBI__CASE(3,4) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=255;        } break;\n         STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]);                   } break;\n         STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = 255;    } break;\n         STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]);                   } break;\n         STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = src[3]; } break;\n         STBI__CASE(4,3) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2];                    } break;\n         default: STBI_ASSERT(0);\n      }\n      #undef STBI__CASE\n   }\n\n   STBI_FREE(data);\n   return good;\n}\n\nstatic stbi__uint16 stbi__compute_y_16(int r, int g, int b)\n{\n   return (stbi__uint16) (((r*77) + (g*150) +  (29*b)) >> 8);\n}\n\nstatic stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y)\n{\n   int i,j;\n   stbi__uint16 *good;\n\n   if (req_comp == img_n) return data;\n   STBI_ASSERT(req_comp >= 1 && req_comp <= 4);\n\n   good = (stbi__uint16 *) stbi__malloc(req_comp * x * y * 2);\n   if (good == NULL) {\n      STBI_FREE(data);\n      return (stbi__uint16 *) stbi__errpuc(\"outofmem\", \"Out of memory\");\n   }\n\n   for (j=0; j < (int) y; ++j) {\n      stbi__uint16 *src  = data + j * x * img_n   ;\n      stbi__uint16 *dest = good + j * x * req_comp;\n\n      #define STBI__COMBO(a,b)  ((a)*8+(b))\n      #define STBI__CASE(a,b)   case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b)\n      // convert source image with img_n components to one with req_comp components;\n      // avoid switch per pixel, so use switch per scanline and massive macros\n      switch (STBI__COMBO(img_n, req_comp)) {\n         STBI__CASE(1,2) { dest[0]=src[0], dest[1]=0xffff;                                     } break;\n         STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0];                                     } break;\n         STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=0xffff;                     } break;\n         STBI__CASE(2,1) { dest[0]=src[0];                                                     } break;\n         STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0];                                     } break;\n         STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1];                     } break;\n         STBI__CASE(3,4) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=0xffff;        } break;\n         STBI__CASE(3,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]);                   } break;\n         STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]), dest[1] = 0xffff; } break;\n         STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]);                   } break;\n         STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]), dest[1] = src[3]; } break;\n         STBI__CASE(4,3) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2];                       } break;\n         default: STBI_ASSERT(0);\n      }\n      #undef STBI__CASE\n   }\n\n   STBI_FREE(data);\n   return good;\n}\n\n#ifndef STBI_NO_LINEAR\nstatic float   *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp)\n{\n   int i,k,n;\n   float *output;\n   if (!data) return NULL;\n   output = (float *) stbi__malloc_mad4(x, y, comp, sizeof(float), 0);\n   if (output == NULL) { STBI_FREE(data); return stbi__errpf(\"outofmem\", \"Out of memory\"); }\n   // compute number of non-alpha components\n   if (comp & 1) n = comp; else n = comp-1;\n   for (i=0; i < x*y; ++i) {\n      for (k=0; k < n; ++k) {\n         output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale);\n      }\n      if (k < comp) output[i*comp + k] = data[i*comp+k]/255.0f;\n   }\n   STBI_FREE(data);\n   return output;\n}\n#endif\n\n#ifndef STBI_NO_HDR\n#define stbi__float2int(x)   ((int) (x))\nstatic stbi_uc *stbi__hdr_to_ldr(float   *data, int x, int y, int comp)\n{\n   int i,k,n;\n   stbi_uc *output;\n   if (!data) return NULL;\n   output = (stbi_uc *) stbi__malloc_mad3(x, y, comp, 0);\n   if (output == NULL) { STBI_FREE(data); return stbi__errpuc(\"outofmem\", \"Out of memory\"); }\n   // compute number of non-alpha components\n   if (comp & 1) n = comp; else n = comp-1;\n   for (i=0; i < x*y; ++i) {\n      for (k=0; k < n; ++k) {\n         float z = (float) pow(data[i*comp+k]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f;\n         if (z < 0) z = 0;\n         if (z > 255) z = 255;\n         output[i*comp + k] = (stbi_uc) stbi__float2int(z);\n      }\n      if (k < comp) {\n         float z = data[i*comp+k] * 255 + 0.5f;\n         if (z < 0) z = 0;\n         if (z > 255) z = 255;\n         output[i*comp + k] = (stbi_uc) stbi__float2int(z);\n      }\n   }\n   STBI_FREE(data);\n   return output;\n}\n#endif\n\n//////////////////////////////////////////////////////////////////////////////\n//\n//  \"baseline\" JPEG/JFIF decoder\n//\n//    simple implementation\n//      - doesn't support delayed output of y-dimension\n//      - simple interface (only one output format: 8-bit interleaved RGB)\n//      - doesn't try to recover corrupt jpegs\n//      - doesn't allow partial loading, loading multiple at once\n//      - still fast on x86 (copying globals into locals doesn't help x86)\n//      - allocates lots of intermediate memory (full size of all components)\n//        - non-interleaved case requires this anyway\n//        - allows good upsampling (see next)\n//    high-quality\n//      - upsampled channels are bilinearly interpolated, even across blocks\n//      - quality integer IDCT derived from IJG's 'slow'\n//    performance\n//      - fast huffman; reasonable integer IDCT\n//      - some SIMD kernels for common paths on targets with SSE2/NEON\n//      - uses a lot of intermediate memory, could cache poorly\n\n#ifndef STBI_NO_JPEG\n\n// huffman decoding acceleration\n#define FAST_BITS   9  // larger handles more cases; smaller stomps less cache\n\ntypedef struct\n{\n   stbi_uc  fast[1 << FAST_BITS];\n   // weirdly, repacking this into AoS is a 10% speed loss, instead of a win\n   stbi__uint16 code[256];\n   stbi_uc  values[256];\n   stbi_uc  size[257];\n   unsigned int maxcode[18];\n   int    delta[17];   // old 'firstsymbol' - old 'firstcode'\n} stbi__huffman;\n\ntypedef struct\n{\n   stbi__context *s;\n   stbi__huffman huff_dc[4];\n   stbi__huffman huff_ac[4];\n   stbi__uint16 dequant[4][64];\n   stbi__int16 fast_ac[4][1 << FAST_BITS];\n\n// sizes for components, interleaved MCUs\n   int img_h_max, img_v_max;\n   int img_mcu_x, img_mcu_y;\n   int img_mcu_w, img_mcu_h;\n\n// definition of jpeg image component\n   struct\n   {\n      int id;\n      int h,v;\n      int tq;\n      int hd,ha;\n      int dc_pred;\n\n      int x,y,w2,h2;\n      stbi_uc *data;\n      void *raw_data, *raw_coeff;\n      stbi_uc *linebuf;\n      short   *coeff;   // progressive only\n      int      coeff_w, coeff_h; // number of 8x8 coefficient blocks\n   } img_comp[4];\n\n   stbi__uint32   code_buffer; // jpeg entropy-coded buffer\n   int            code_bits;   // number of valid bits\n   unsigned char  marker;      // marker seen while filling entropy buffer\n   int            nomore;      // flag if we saw a marker so must stop\n\n   int            progressive;\n   int            spec_start;\n   int            spec_end;\n   int            succ_high;\n   int            succ_low;\n   int            eob_run;\n   int            rgb;\n\n   int scan_n, order[4];\n   int restart_interval, todo;\n\n// kernels\n   void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]);\n   void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step);\n   stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs);\n} stbi__jpeg;\n\nstatic int stbi__build_huffman(stbi__huffman *h, int *count)\n{\n   int i,j,k=0,code;\n   // build size list for each symbol (from JPEG spec)\n   for (i=0; i < 16; ++i)\n      for (j=0; j < count[i]; ++j)\n         h->size[k++] = (stbi_uc) (i+1);\n   h->size[k] = 0;\n\n   // compute actual symbols (from jpeg spec)\n   code = 0;\n   k = 0;\n   for(j=1; j <= 16; ++j) {\n      // compute delta to add to code to compute symbol id\n      h->delta[j] = k - code;\n      if (h->size[k] == j) {\n         while (h->size[k] == j)\n            h->code[k++] = (stbi__uint16) (code++);\n         if (code-1 >= (1 << j)) return stbi__err(\"bad code lengths\",\"Corrupt JPEG\");\n      }\n      // compute largest code + 1 for this size, preshifted as needed later\n      h->maxcode[j] = code << (16-j);\n      code <<= 1;\n   }\n   h->maxcode[j] = 0xffffffff;\n\n   // build non-spec acceleration table; 255 is flag for not-accelerated\n   memset(h->fast, 255, 1 << FAST_BITS);\n   for (i=0; i < k; ++i) {\n      int s = h->size[i];\n      if (s <= FAST_BITS) {\n         int c = h->code[i] << (FAST_BITS-s);\n         int m = 1 << (FAST_BITS-s);\n         for (j=0; j < m; ++j) {\n            h->fast[c+j] = (stbi_uc) i;\n         }\n      }\n   }\n   return 1;\n}\n\n// build a table that decodes both magnitude and value of small ACs in\n// one go.\nstatic void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h)\n{\n   int i;\n   for (i=0; i < (1 << FAST_BITS); ++i) {\n      stbi_uc fast = h->fast[i];\n      fast_ac[i] = 0;\n      if (fast < 255) {\n         int rs = h->values[fast];\n         int run = (rs >> 4) & 15;\n         int magbits = rs & 15;\n         int len = h->size[fast];\n\n         if (magbits && len + magbits <= FAST_BITS) {\n            // magnitude code followed by receive_extend code\n            int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits);\n            int m = 1 << (magbits - 1);\n            if (k < m) k += (-1 << magbits) + 1;\n            // if the result is small enough, we can fit it in fast_ac table\n            if (k >= -128 && k <= 127)\n               fast_ac[i] = (stbi__int16) ((k << 8) + (run << 4) + (len + magbits));\n         }\n      }\n   }\n}\n\nstatic void stbi__grow_buffer_unsafe(stbi__jpeg *j)\n{\n   do {\n      int b = j->nomore ? 0 : stbi__get8(j->s);\n      if (b == 0xff) {\n         int c = stbi__get8(j->s);\n         while (c == 0xff) c = stbi__get8(j->s); // consume fill bytes\n         if (c != 0) {\n            j->marker = (unsigned char) c;\n            j->nomore = 1;\n            return;\n         }\n      }\n      j->code_buffer |= b << (24 - j->code_bits);\n      j->code_bits += 8;\n   } while (j->code_bits <= 24);\n}\n\n// (1 << n) - 1\nstatic stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535};\n\n// decode a jpeg huffman value from the bitstream\nstbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h)\n{\n   unsigned int temp;\n   int c,k;\n\n   if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);\n\n   // look at the top FAST_BITS and determine what symbol ID it is,\n   // if the code is <= FAST_BITS\n   c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);\n   k = h->fast[c];\n   if (k < 255) {\n      int s = h->size[k];\n      if (s > j->code_bits)\n         return -1;\n      j->code_buffer <<= s;\n      j->code_bits -= s;\n      return h->values[k];\n   }\n\n   // naive test is to shift the code_buffer down so k bits are\n   // valid, then test against maxcode. To speed this up, we've\n   // preshifted maxcode left so that it has (16-k) 0s at the\n   // end; in other words, regardless of the number of bits, it\n   // wants to be compared against something shifted to have 16;\n   // that way we don't need to shift inside the loop.\n   temp = j->code_buffer >> 16;\n   for (k=FAST_BITS+1 ; ; ++k)\n      if (temp < h->maxcode[k])\n         break;\n   if (k == 17) {\n      // error! code not found\n      j->code_bits -= 16;\n      return -1;\n   }\n\n   if (k > j->code_bits)\n      return -1;\n\n   // convert the huffman code to the symbol id\n   c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k];\n   STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]);\n\n   // convert the id to a symbol\n   j->code_bits -= k;\n   j->code_buffer <<= k;\n   return h->values[c];\n}\n\n// bias[n] = (-1<<n) + 1\nstatic int const stbi__jbias[16] = {0,-1,-3,-7,-15,-31,-63,-127,-255,-511,-1023,-2047,-4095,-8191,-16383,-32767};\n\n// combined JPEG 'receive' and JPEG 'extend', since baseline\n// always extends everything it receives.\nstbi_inline static int stbi__extend_receive(stbi__jpeg *j, int n)\n{\n   unsigned int k;\n   int sgn;\n   if (j->code_bits < n) stbi__grow_buffer_unsafe(j);\n\n   sgn = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB\n   k = stbi_lrot(j->code_buffer, n);\n   STBI_ASSERT(n >= 0 && n < (int) (sizeof(stbi__bmask)/sizeof(*stbi__bmask)));\n   j->code_buffer = k & ~stbi__bmask[n];\n   k &= stbi__bmask[n];\n   j->code_bits -= n;\n   return k + (stbi__jbias[n] & ~sgn);\n}\n\n// get some unsigned bits\nstbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n)\n{\n   unsigned int k;\n   if (j->code_bits < n) stbi__grow_buffer_unsafe(j);\n   k = stbi_lrot(j->code_buffer, n);\n   j->code_buffer = k & ~stbi__bmask[n];\n   k &= stbi__bmask[n];\n   j->code_bits -= n;\n   return k;\n}\n\nstbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j)\n{\n   unsigned int k;\n   if (j->code_bits < 1) stbi__grow_buffer_unsafe(j);\n   k = j->code_buffer;\n   j->code_buffer <<= 1;\n   --j->code_bits;\n   return k & 0x80000000;\n}\n\n// given a value that's at position X in the zigzag stream,\n// where does it appear in the 8x8 matrix coded as row-major?\nstatic stbi_uc stbi__jpeg_dezigzag[64+15] =\n{\n    0,  1,  8, 16,  9,  2,  3, 10,\n   17, 24, 32, 25, 18, 11,  4,  5,\n   12, 19, 26, 33, 40, 48, 41, 34,\n   27, 20, 13,  6,  7, 14, 21, 28,\n   35, 42, 49, 56, 57, 50, 43, 36,\n   29, 22, 15, 23, 30, 37, 44, 51,\n   58, 59, 52, 45, 38, 31, 39, 46,\n   53, 60, 61, 54, 47, 55, 62, 63,\n   // let corrupt input sample past end\n   63, 63, 63, 63, 63, 63, 63, 63,\n   63, 63, 63, 63, 63, 63, 63\n};\n\n// decode one 64-entry block--\nstatic int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi__uint16 *dequant)\n{\n   int diff,dc,k;\n   int t;\n\n   if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);\n   t = stbi__jpeg_huff_decode(j, hdc);\n   if (t < 0) return stbi__err(\"bad huffman code\",\"Corrupt JPEG\");\n\n   // 0 all the ac values now so we can do it 32-bits at a time\n   memset(data,0,64*sizeof(data[0]));\n\n   diff = t ? stbi__extend_receive(j, t) : 0;\n   dc = j->img_comp[b].dc_pred + diff;\n   j->img_comp[b].dc_pred = dc;\n   data[0] = (short) (dc * dequant[0]);\n\n   // decode AC components, see JPEG spec\n   k = 1;\n   do {\n      unsigned int zig;\n      int c,r,s;\n      if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);\n      c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);\n      r = fac[c];\n      if (r) { // fast-AC path\n         k += (r >> 4) & 15; // run\n         s = r & 15; // combined length\n         j->code_buffer <<= s;\n         j->code_bits -= s;\n         // decode into unzigzag'd location\n         zig = stbi__jpeg_dezigzag[k++];\n         data[zig] = (short) ((r >> 8) * dequant[zig]);\n      } else {\n         int rs = stbi__jpeg_huff_decode(j, hac);\n         if (rs < 0) return stbi__err(\"bad huffman code\",\"Corrupt JPEG\");\n         s = rs & 15;\n         r = rs >> 4;\n         if (s == 0) {\n            if (rs != 0xf0) break; // end block\n            k += 16;\n         } else {\n            k += r;\n            // decode into unzigzag'd location\n            zig = stbi__jpeg_dezigzag[k++];\n            data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]);\n         }\n      }\n   } while (k < 64);\n   return 1;\n}\n\nstatic int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b)\n{\n   int diff,dc;\n   int t;\n   if (j->spec_end != 0) return stbi__err(\"can't merge dc and ac\", \"Corrupt JPEG\");\n\n   if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);\n\n   if (j->succ_high == 0) {\n      // first scan for DC coefficient, must be first\n      memset(data,0,64*sizeof(data[0])); // 0 all the ac values now\n      t = stbi__jpeg_huff_decode(j, hdc);\n      diff = t ? stbi__extend_receive(j, t) : 0;\n\n      dc = j->img_comp[b].dc_pred + diff;\n      j->img_comp[b].dc_pred = dc;\n      data[0] = (short) (dc << j->succ_low);\n   } else {\n      // refinement scan for DC coefficient\n      if (stbi__jpeg_get_bit(j))\n         data[0] += (short) (1 << j->succ_low);\n   }\n   return 1;\n}\n\n// @OPTIMIZE: store non-zigzagged during the decode passes,\n// and only de-zigzag when dequantizing\nstatic int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac)\n{\n   int k;\n   if (j->spec_start == 0) return stbi__err(\"can't merge dc and ac\", \"Corrupt JPEG\");\n\n   if (j->succ_high == 0) {\n      int shift = j->succ_low;\n\n      if (j->eob_run) {\n         --j->eob_run;\n         return 1;\n      }\n\n      k = j->spec_start;\n      do {\n         unsigned int zig;\n         int c,r,s;\n         if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);\n         c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);\n         r = fac[c];\n         if (r) { // fast-AC path\n            k += (r >> 4) & 15; // run\n            s = r & 15; // combined length\n            j->code_buffer <<= s;\n            j->code_bits -= s;\n            zig = stbi__jpeg_dezigzag[k++];\n            data[zig] = (short) ((r >> 8) << shift);\n         } else {\n            int rs = stbi__jpeg_huff_decode(j, hac);\n            if (rs < 0) return stbi__err(\"bad huffman code\",\"Corrupt JPEG\");\n            s = rs & 15;\n            r = rs >> 4;\n            if (s == 0) {\n               if (r < 15) {\n                  j->eob_run = (1 << r);\n                  if (r)\n                     j->eob_run += stbi__jpeg_get_bits(j, r);\n                  --j->eob_run;\n                  break;\n               }\n               k += 16;\n            } else {\n               k += r;\n               zig = stbi__jpeg_dezigzag[k++];\n               data[zig] = (short) (stbi__extend_receive(j,s) << shift);\n            }\n         }\n      } while (k <= j->spec_end);\n   } else {\n      // refinement scan for these AC coefficients\n\n      short bit = (short) (1 << j->succ_low);\n\n      if (j->eob_run) {\n         --j->eob_run;\n         for (k = j->spec_start; k <= j->spec_end; ++k) {\n            short *p = &data[stbi__jpeg_dezigzag[k]];\n            if (*p != 0)\n               if (stbi__jpeg_get_bit(j))\n                  if ((*p & bit)==0) {\n                     if (*p > 0)\n                        *p += bit;\n                     else\n                        *p -= bit;\n                  }\n         }\n      } else {\n         k = j->spec_start;\n         do {\n            int r,s;\n            int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh\n            if (rs < 0) return stbi__err(\"bad huffman code\",\"Corrupt JPEG\");\n            s = rs & 15;\n            r = rs >> 4;\n            if (s == 0) {\n               if (r < 15) {\n                  j->eob_run = (1 << r) - 1;\n                  if (r)\n                     j->eob_run += stbi__jpeg_get_bits(j, r);\n                  r = 64; // force end of block\n               } else {\n                  // r=15 s=0 should write 16 0s, so we just do\n                  // a run of 15 0s and then write s (which is 0),\n                  // so we don't have to do anything special here\n               }\n            } else {\n               if (s != 1) return stbi__err(\"bad huffman code\", \"Corrupt JPEG\");\n               // sign bit\n               if (stbi__jpeg_get_bit(j))\n                  s = bit;\n               else\n                  s = -bit;\n            }\n\n            // advance by r\n            while (k <= j->spec_end) {\n               short *p = &data[stbi__jpeg_dezigzag[k++]];\n               if (*p != 0) {\n                  if (stbi__jpeg_get_bit(j))\n                     if ((*p & bit)==0) {\n                        if (*p > 0)\n                           *p += bit;\n                        else\n                           *p -= bit;\n                     }\n               } else {\n                  if (r == 0) {\n                     *p = (short) s;\n                     break;\n                  }\n                  --r;\n               }\n            }\n         } while (k <= j->spec_end);\n      }\n   }\n   return 1;\n}\n\n// take a -128..127 value and stbi__clamp it and convert to 0..255\nstbi_inline static stbi_uc stbi__clamp(int x)\n{\n   // trick to use a single test to catch both cases\n   if ((unsigned int) x > 255) {\n      if (x < 0) return 0;\n      if (x > 255) return 255;\n   }\n   return (stbi_uc) x;\n}\n\n#define stbi__f2f(x)  ((int) (((x) * 4096 + 0.5)))\n#define stbi__fsh(x)  ((x) << 12)\n\n// derived from jidctint -- DCT_ISLOW\n#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \\\n   int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \\\n   p2 = s2;                                    \\\n   p3 = s6;                                    \\\n   p1 = (p2+p3) * stbi__f2f(0.5411961f);       \\\n   t2 = p1 + p3*stbi__f2f(-1.847759065f);      \\\n   t3 = p1 + p2*stbi__f2f( 0.765366865f);      \\\n   p2 = s0;                                    \\\n   p3 = s4;                                    \\\n   t0 = stbi__fsh(p2+p3);                      \\\n   t1 = stbi__fsh(p2-p3);                      \\\n   x0 = t0+t3;                                 \\\n   x3 = t0-t3;                                 \\\n   x1 = t1+t2;                                 \\\n   x2 = t1-t2;                                 \\\n   t0 = s7;                                    \\\n   t1 = s5;                                    \\\n   t2 = s3;                                    \\\n   t3 = s1;                                    \\\n   p3 = t0+t2;                                 \\\n   p4 = t1+t3;                                 \\\n   p1 = t0+t3;                                 \\\n   p2 = t1+t2;                                 \\\n   p5 = (p3+p4)*stbi__f2f( 1.175875602f);      \\\n   t0 = t0*stbi__f2f( 0.298631336f);           \\\n   t1 = t1*stbi__f2f( 2.053119869f);           \\\n   t2 = t2*stbi__f2f( 3.072711026f);           \\\n   t3 = t3*stbi__f2f( 1.501321110f);           \\\n   p1 = p5 + p1*stbi__f2f(-0.899976223f);      \\\n   p2 = p5 + p2*stbi__f2f(-2.562915447f);      \\\n   p3 = p3*stbi__f2f(-1.961570560f);           \\\n   p4 = p4*stbi__f2f(-0.390180644f);           \\\n   t3 += p1+p4;                                \\\n   t2 += p2+p3;                                \\\n   t1 += p2+p4;                                \\\n   t0 += p1+p3;\n\nstatic void stbi__idct_block(stbi_uc *out, int out_stride, short data[64])\n{\n   int i,val[64],*v=val;\n   stbi_uc *o;\n   short *d = data;\n\n   // columns\n   for (i=0; i < 8; ++i,++d, ++v) {\n      // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing\n      if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0\n           && d[40]==0 && d[48]==0 && d[56]==0) {\n         //    no shortcut                 0     seconds\n         //    (1|2|3|4|5|6|7)==0          0     seconds\n         //    all separate               -0.047 seconds\n         //    1 && 2|3 && 4|5 && 6|7:    -0.047 seconds\n         int dcterm = d[0] << 2;\n         v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm;\n      } else {\n         STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56])\n         // constants scaled things up by 1<<12; let's bring them back\n         // down, but keep 2 extra bits of precision\n         x0 += 512; x1 += 512; x2 += 512; x3 += 512;\n         v[ 0] = (x0+t3) >> 10;\n         v[56] = (x0-t3) >> 10;\n         v[ 8] = (x1+t2) >> 10;\n         v[48] = (x1-t2) >> 10;\n         v[16] = (x2+t1) >> 10;\n         v[40] = (x2-t1) >> 10;\n         v[24] = (x3+t0) >> 10;\n         v[32] = (x3-t0) >> 10;\n      }\n   }\n\n   for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) {\n      // no fast case since the first 1D IDCT spread components out\n      STBI__IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7])\n      // constants scaled things up by 1<<12, plus we had 1<<2 from first\n      // loop, plus horizontal and vertical each scale by sqrt(8) so together\n      // we've got an extra 1<<3, so 1<<17 total we need to remove.\n      // so we want to round that, which means adding 0.5 * 1<<17,\n      // aka 65536. Also, we'll end up with -128 to 127 that we want\n      // to encode as 0..255 by adding 128, so we'll add that before the shift\n      x0 += 65536 + (128<<17);\n      x1 += 65536 + (128<<17);\n      x2 += 65536 + (128<<17);\n      x3 += 65536 + (128<<17);\n      // tried computing the shifts into temps, or'ing the temps to see\n      // if any were out of range, but that was slower\n      o[0] = stbi__clamp((x0+t3) >> 17);\n      o[7] = stbi__clamp((x0-t3) >> 17);\n      o[1] = stbi__clamp((x1+t2) >> 17);\n      o[6] = stbi__clamp((x1-t2) >> 17);\n      o[2] = stbi__clamp((x2+t1) >> 17);\n      o[5] = stbi__clamp((x2-t1) >> 17);\n      o[3] = stbi__clamp((x3+t0) >> 17);\n      o[4] = stbi__clamp((x3-t0) >> 17);\n   }\n}\n\n#ifdef STBI_SSE2\n// sse2 integer IDCT. not the fastest possible implementation but it\n// produces bit-identical results to the generic C version so it's\n// fully \"transparent\".\nstatic void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64])\n{\n   // This is constructed to match our regular (generic) integer IDCT exactly.\n   __m128i row0, row1, row2, row3, row4, row5, row6, row7;\n   __m128i tmp;\n\n   // dot product constant: even elems=x, odd elems=y\n   #define dct_const(x,y)  _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y))\n\n   // out(0) = c0[even]*x + c0[odd]*y   (c0, x, y 16-bit, out 32-bit)\n   // out(1) = c1[even]*x + c1[odd]*y\n   #define dct_rot(out0,out1, x,y,c0,c1) \\\n      __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \\\n      __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \\\n      __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \\\n      __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \\\n      __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \\\n      __m128i out1##_h = _mm_madd_epi16(c0##hi, c1)\n\n   // out = in << 12  (in 16-bit, out 32-bit)\n   #define dct_widen(out, in) \\\n      __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \\\n      __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4)\n\n   // wide add\n   #define dct_wadd(out, a, b) \\\n      __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \\\n      __m128i out##_h = _mm_add_epi32(a##_h, b##_h)\n\n   // wide sub\n   #define dct_wsub(out, a, b) \\\n      __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \\\n      __m128i out##_h = _mm_sub_epi32(a##_h, b##_h)\n\n   // butterfly a/b, add bias, then shift by \"s\" and pack\n   #define dct_bfly32o(out0, out1, a,b,bias,s) \\\n      { \\\n         __m128i abiased_l = _mm_add_epi32(a##_l, bias); \\\n         __m128i abiased_h = _mm_add_epi32(a##_h, bias); \\\n         dct_wadd(sum, abiased, b); \\\n         dct_wsub(dif, abiased, b); \\\n         out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \\\n         out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \\\n      }\n\n   // 8-bit interleave step (for transposes)\n   #define dct_interleave8(a, b) \\\n      tmp = a; \\\n      a = _mm_unpacklo_epi8(a, b); \\\n      b = _mm_unpackhi_epi8(tmp, b)\n\n   // 16-bit interleave step (for transposes)\n   #define dct_interleave16(a, b) \\\n      tmp = a; \\\n      a = _mm_unpacklo_epi16(a, b); \\\n      b = _mm_unpackhi_epi16(tmp, b)\n\n   #define dct_pass(bias,shift) \\\n      { \\\n         /* even part */ \\\n         dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \\\n         __m128i sum04 = _mm_add_epi16(row0, row4); \\\n         __m128i dif04 = _mm_sub_epi16(row0, row4); \\\n         dct_widen(t0e, sum04); \\\n         dct_widen(t1e, dif04); \\\n         dct_wadd(x0, t0e, t3e); \\\n         dct_wsub(x3, t0e, t3e); \\\n         dct_wadd(x1, t1e, t2e); \\\n         dct_wsub(x2, t1e, t2e); \\\n         /* odd part */ \\\n         dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \\\n         dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \\\n         __m128i sum17 = _mm_add_epi16(row1, row7); \\\n         __m128i sum35 = _mm_add_epi16(row3, row5); \\\n         dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \\\n         dct_wadd(x4, y0o, y4o); \\\n         dct_wadd(x5, y1o, y5o); \\\n         dct_wadd(x6, y2o, y5o); \\\n         dct_wadd(x7, y3o, y4o); \\\n         dct_bfly32o(row0,row7, x0,x7,bias,shift); \\\n         dct_bfly32o(row1,row6, x1,x6,bias,shift); \\\n         dct_bfly32o(row2,row5, x2,x5,bias,shift); \\\n         dct_bfly32o(row3,row4, x3,x4,bias,shift); \\\n      }\n\n   __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f));\n   __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f( 0.765366865f), stbi__f2f(0.5411961f));\n   __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f));\n   __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f));\n   __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f( 0.298631336f), stbi__f2f(-1.961570560f));\n   __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f( 3.072711026f));\n   __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f( 2.053119869f), stbi__f2f(-0.390180644f));\n   __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f( 1.501321110f));\n\n   // rounding biases in column/row passes, see stbi__idct_block for explanation.\n   __m128i bias_0 = _mm_set1_epi32(512);\n   __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17));\n\n   // load\n   row0 = _mm_load_si128((const __m128i *) (data + 0*8));\n   row1 = _mm_load_si128((const __m128i *) (data + 1*8));\n   row2 = _mm_load_si128((const __m128i *) (data + 2*8));\n   row3 = _mm_load_si128((const __m128i *) (data + 3*8));\n   row4 = _mm_load_si128((const __m128i *) (data + 4*8));\n   row5 = _mm_load_si128((const __m128i *) (data + 5*8));\n   row6 = _mm_load_si128((const __m128i *) (data + 6*8));\n   row7 = _mm_load_si128((const __m128i *) (data + 7*8));\n\n   // column pass\n   dct_pass(bias_0, 10);\n\n   {\n      // 16bit 8x8 transpose pass 1\n      dct_interleave16(row0, row4);\n      dct_interleave16(row1, row5);\n      dct_interleave16(row2, row6);\n      dct_interleave16(row3, row7);\n\n      // transpose pass 2\n      dct_interleave16(row0, row2);\n      dct_interleave16(row1, row3);\n      dct_interleave16(row4, row6);\n      dct_interleave16(row5, row7);\n\n      // transpose pass 3\n      dct_interleave16(row0, row1);\n      dct_interleave16(row2, row3);\n      dct_interleave16(row4, row5);\n      dct_interleave16(row6, row7);\n   }\n\n   // row pass\n   dct_pass(bias_1, 17);\n\n   {\n      // pack\n      __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7\n      __m128i p1 = _mm_packus_epi16(row2, row3);\n      __m128i p2 = _mm_packus_epi16(row4, row5);\n      __m128i p3 = _mm_packus_epi16(row6, row7);\n\n      // 8bit 8x8 transpose pass 1\n      dct_interleave8(p0, p2); // a0e0a1e1...\n      dct_interleave8(p1, p3); // c0g0c1g1...\n\n      // transpose pass 2\n      dct_interleave8(p0, p1); // a0c0e0g0...\n      dct_interleave8(p2, p3); // b0d0f0h0...\n\n      // transpose pass 3\n      dct_interleave8(p0, p2); // a0b0c0d0...\n      dct_interleave8(p1, p3); // a4b4c4d4...\n\n      // store\n      _mm_storel_epi64((__m128i *) out, p0); out += out_stride;\n      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride;\n      _mm_storel_epi64((__m128i *) out, p2); out += out_stride;\n      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride;\n      _mm_storel_epi64((__m128i *) out, p1); out += out_stride;\n      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride;\n      _mm_storel_epi64((__m128i *) out, p3); out += out_stride;\n      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e));\n   }\n\n#undef dct_const\n#undef dct_rot\n#undef dct_widen\n#undef dct_wadd\n#undef dct_wsub\n#undef dct_bfly32o\n#undef dct_interleave8\n#undef dct_interleave16\n#undef dct_pass\n}\n\n#endif // STBI_SSE2\n\n#ifdef STBI_NEON\n\n// NEON integer IDCT. should produce bit-identical\n// results to the generic C version.\nstatic void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64])\n{\n   int16x8_t row0, row1, row2, row3, row4, row5, row6, row7;\n\n   int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f));\n   int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f));\n   int16x4_t rot0_2 = vdup_n_s16(stbi__f2f( 0.765366865f));\n   int16x4_t rot1_0 = vdup_n_s16(stbi__f2f( 1.175875602f));\n   int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f));\n   int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f));\n   int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f));\n   int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f));\n   int16x4_t rot3_0 = vdup_n_s16(stbi__f2f( 0.298631336f));\n   int16x4_t rot3_1 = vdup_n_s16(stbi__f2f( 2.053119869f));\n   int16x4_t rot3_2 = vdup_n_s16(stbi__f2f( 3.072711026f));\n   int16x4_t rot3_3 = vdup_n_s16(stbi__f2f( 1.501321110f));\n\n#define dct_long_mul(out, inq, coeff) \\\n   int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \\\n   int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff)\n\n#define dct_long_mac(out, acc, inq, coeff) \\\n   int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \\\n   int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff)\n\n#define dct_widen(out, inq) \\\n   int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \\\n   int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12)\n\n// wide add\n#define dct_wadd(out, a, b) \\\n   int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \\\n   int32x4_t out##_h = vaddq_s32(a##_h, b##_h)\n\n// wide sub\n#define dct_wsub(out, a, b) \\\n   int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \\\n   int32x4_t out##_h = vsubq_s32(a##_h, b##_h)\n\n// butterfly a/b, then shift using \"shiftop\" by \"s\" and pack\n#define dct_bfly32o(out0,out1, a,b,shiftop,s) \\\n   { \\\n      dct_wadd(sum, a, b); \\\n      dct_wsub(dif, a, b); \\\n      out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \\\n      out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \\\n   }\n\n#define dct_pass(shiftop, shift) \\\n   { \\\n      /* even part */ \\\n      int16x8_t sum26 = vaddq_s16(row2, row6); \\\n      dct_long_mul(p1e, sum26, rot0_0); \\\n      dct_long_mac(t2e, p1e, row6, rot0_1); \\\n      dct_long_mac(t3e, p1e, row2, rot0_2); \\\n      int16x8_t sum04 = vaddq_s16(row0, row4); \\\n      int16x8_t dif04 = vsubq_s16(row0, row4); \\\n      dct_widen(t0e, sum04); \\\n      dct_widen(t1e, dif04); \\\n      dct_wadd(x0, t0e, t3e); \\\n      dct_wsub(x3, t0e, t3e); \\\n      dct_wadd(x1, t1e, t2e); \\\n      dct_wsub(x2, t1e, t2e); \\\n      /* odd part */ \\\n      int16x8_t sum15 = vaddq_s16(row1, row5); \\\n      int16x8_t sum17 = vaddq_s16(row1, row7); \\\n      int16x8_t sum35 = vaddq_s16(row3, row5); \\\n      int16x8_t sum37 = vaddq_s16(row3, row7); \\\n      int16x8_t sumodd = vaddq_s16(sum17, sum35); \\\n      dct_long_mul(p5o, sumodd, rot1_0); \\\n      dct_long_mac(p1o, p5o, sum17, rot1_1); \\\n      dct_long_mac(p2o, p5o, sum35, rot1_2); \\\n      dct_long_mul(p3o, sum37, rot2_0); \\\n      dct_long_mul(p4o, sum15, rot2_1); \\\n      dct_wadd(sump13o, p1o, p3o); \\\n      dct_wadd(sump24o, p2o, p4o); \\\n      dct_wadd(sump23o, p2o, p3o); \\\n      dct_wadd(sump14o, p1o, p4o); \\\n      dct_long_mac(x4, sump13o, row7, rot3_0); \\\n      dct_long_mac(x5, sump24o, row5, rot3_1); \\\n      dct_long_mac(x6, sump23o, row3, rot3_2); \\\n      dct_long_mac(x7, sump14o, row1, rot3_3); \\\n      dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \\\n      dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \\\n      dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \\\n      dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \\\n   }\n\n   // load\n   row0 = vld1q_s16(data + 0*8);\n   row1 = vld1q_s16(data + 1*8);\n   row2 = vld1q_s16(data + 2*8);\n   row3 = vld1q_s16(data + 3*8);\n   row4 = vld1q_s16(data + 4*8);\n   row5 = vld1q_s16(data + 5*8);\n   row6 = vld1q_s16(data + 6*8);\n   row7 = vld1q_s16(data + 7*8);\n\n   // add DC bias\n   row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0));\n\n   // column pass\n   dct_pass(vrshrn_n_s32, 10);\n\n   // 16bit 8x8 transpose\n   {\n// these three map to a single VTRN.16, VTRN.32, and VSWP, respectively.\n// whether compilers actually get this is another story, sadly.\n#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; }\n#define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); }\n#define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); }\n\n      // pass 1\n      dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6\n      dct_trn16(row2, row3);\n      dct_trn16(row4, row5);\n      dct_trn16(row6, row7);\n\n      // pass 2\n      dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4\n      dct_trn32(row1, row3);\n      dct_trn32(row4, row6);\n      dct_trn32(row5, row7);\n\n      // pass 3\n      dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0\n      dct_trn64(row1, row5);\n      dct_trn64(row2, row6);\n      dct_trn64(row3, row7);\n\n#undef dct_trn16\n#undef dct_trn32\n#undef dct_trn64\n   }\n\n   // row pass\n   // vrshrn_n_s32 only supports shifts up to 16, we need\n   // 17. so do a non-rounding shift of 16 first then follow\n   // up with a rounding shift by 1.\n   dct_pass(vshrn_n_s32, 16);\n\n   {\n      // pack and round\n      uint8x8_t p0 = vqrshrun_n_s16(row0, 1);\n      uint8x8_t p1 = vqrshrun_n_s16(row1, 1);\n      uint8x8_t p2 = vqrshrun_n_s16(row2, 1);\n      uint8x8_t p3 = vqrshrun_n_s16(row3, 1);\n      uint8x8_t p4 = vqrshrun_n_s16(row4, 1);\n      uint8x8_t p5 = vqrshrun_n_s16(row5, 1);\n      uint8x8_t p6 = vqrshrun_n_s16(row6, 1);\n      uint8x8_t p7 = vqrshrun_n_s16(row7, 1);\n\n      // again, these can translate into one instruction, but often don't.\n#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; }\n#define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); }\n#define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); }\n\n      // sadly can't use interleaved stores here since we only write\n      // 8 bytes to each scan line!\n\n      // 8x8 8-bit transpose pass 1\n      dct_trn8_8(p0, p1);\n      dct_trn8_8(p2, p3);\n      dct_trn8_8(p4, p5);\n      dct_trn8_8(p6, p7);\n\n      // pass 2\n      dct_trn8_16(p0, p2);\n      dct_trn8_16(p1, p3);\n      dct_trn8_16(p4, p6);\n      dct_trn8_16(p5, p7);\n\n      // pass 3\n      dct_trn8_32(p0, p4);\n      dct_trn8_32(p1, p5);\n      dct_trn8_32(p2, p6);\n      dct_trn8_32(p3, p7);\n\n      // store\n      vst1_u8(out, p0); out += out_stride;\n      vst1_u8(out, p1); out += out_stride;\n      vst1_u8(out, p2); out += out_stride;\n      vst1_u8(out, p3); out += out_stride;\n      vst1_u8(out, p4); out += out_stride;\n      vst1_u8(out, p5); out += out_stride;\n      vst1_u8(out, p6); out += out_stride;\n      vst1_u8(out, p7);\n\n#undef dct_trn8_8\n#undef dct_trn8_16\n#undef dct_trn8_32\n   }\n\n#undef dct_long_mul\n#undef dct_long_mac\n#undef dct_widen\n#undef dct_wadd\n#undef dct_wsub\n#undef dct_bfly32o\n#undef dct_pass\n}\n\n#endif // STBI_NEON\n\n#define STBI__MARKER_none  0xff\n// if there's a pending marker from the entropy stream, return that\n// otherwise, fetch from the stream and get a marker. if there's no\n// marker, return 0xff, which is never a valid marker value\nstatic stbi_uc stbi__get_marker(stbi__jpeg *j)\n{\n   stbi_uc x;\n   if (j->marker != STBI__MARKER_none) { x = j->marker; j->marker = STBI__MARKER_none; return x; }\n   x = stbi__get8(j->s);\n   if (x != 0xff) return STBI__MARKER_none;\n   while (x == 0xff)\n      x = stbi__get8(j->s); // consume repeated 0xff fill bytes\n   return x;\n}\n\n// in each scan, we'll have scan_n components, and the order\n// of the components is specified by order[]\n#define STBI__RESTART(x)     ((x) >= 0xd0 && (x) <= 0xd7)\n\n// after a restart interval, stbi__jpeg_reset the entropy decoder and\n// the dc prediction\nstatic void stbi__jpeg_reset(stbi__jpeg *j)\n{\n   j->code_bits = 0;\n   j->code_buffer = 0;\n   j->nomore = 0;\n   j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = 0;\n   j->marker = STBI__MARKER_none;\n   j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff;\n   j->eob_run = 0;\n   // no more than 1<<31 MCUs if no restart_interal? that's plenty safe,\n   // since we don't even allow 1<<30 pixels\n}\n\nstatic int stbi__parse_entropy_coded_data(stbi__jpeg *z)\n{\n   stbi__jpeg_reset(z);\n   if (!z->progressive) {\n      if (z->scan_n == 1) {\n         int i,j;\n         STBI_SIMD_ALIGN(short, data[64]);\n         int n = z->order[0];\n         // non-interleaved data, we just need to process one block at a time,\n         // in trivial scanline order\n         // number of blocks to do just depends on how many actual \"pixels\" this\n         // component has, independent of interleaved MCU blocking and such\n         int w = (z->img_comp[n].x+7) >> 3;\n         int h = (z->img_comp[n].y+7) >> 3;\n         for (j=0; j < h; ++j) {\n            for (i=0; i < w; ++i) {\n               int ha = z->img_comp[n].ha;\n               if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0;\n               z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data);\n               // every data block is an MCU, so countdown the restart interval\n               if (--z->todo <= 0) {\n                  if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);\n                  // if it's NOT a restart, then just bail, so we get corrupt data\n                  // rather than no data\n                  if (!STBI__RESTART(z->marker)) return 1;\n                  stbi__jpeg_reset(z);\n               }\n            }\n         }\n         return 1;\n      } else { // interleaved\n         int i,j,k,x,y;\n         STBI_SIMD_ALIGN(short, data[64]);\n         for (j=0; j < z->img_mcu_y; ++j) {\n            for (i=0; i < z->img_mcu_x; ++i) {\n               // scan an interleaved mcu... process scan_n components in order\n               for (k=0; k < z->scan_n; ++k) {\n                  int n = z->order[k];\n                  // scan out an mcu's worth of this component; that's just determined\n                  // by the basic H and V specified for the component\n                  for (y=0; y < z->img_comp[n].v; ++y) {\n                     for (x=0; x < z->img_comp[n].h; ++x) {\n                        int x2 = (i*z->img_comp[n].h + x)*8;\n                        int y2 = (j*z->img_comp[n].v + y)*8;\n                        int ha = z->img_comp[n].ha;\n                        if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0;\n                        z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data);\n                     }\n                  }\n               }\n               // after all interleaved components, that's an interleaved MCU,\n               // so now count down the restart interval\n               if (--z->todo <= 0) {\n                  if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);\n                  if (!STBI__RESTART(z->marker)) return 1;\n                  stbi__jpeg_reset(z);\n               }\n            }\n         }\n         return 1;\n      }\n   } else {\n      if (z->scan_n == 1) {\n         int i,j;\n         int n = z->order[0];\n         // non-interleaved data, we just need to process one block at a time,\n         // in trivial scanline order\n         // number of blocks to do just depends on how many actual \"pixels\" this\n         // component has, independent of interleaved MCU blocking and such\n         int w = (z->img_comp[n].x+7) >> 3;\n         int h = (z->img_comp[n].y+7) >> 3;\n         for (j=0; j < h; ++j) {\n            for (i=0; i < w; ++i) {\n               short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w);\n               if (z->spec_start == 0) {\n                  if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n))\n                     return 0;\n               } else {\n                  int ha = z->img_comp[n].ha;\n                  if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha]))\n                     return 0;\n               }\n               // every data block is an MCU, so countdown the restart interval\n               if (--z->todo <= 0) {\n                  if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);\n                  if (!STBI__RESTART(z->marker)) return 1;\n                  stbi__jpeg_reset(z);\n               }\n            }\n         }\n         return 1;\n      } else { // interleaved\n         int i,j,k,x,y;\n         for (j=0; j < z->img_mcu_y; ++j) {\n            for (i=0; i < z->img_mcu_x; ++i) {\n               // scan an interleaved mcu... process scan_n components in order\n               for (k=0; k < z->scan_n; ++k) {\n                  int n = z->order[k];\n                  // scan out an mcu's worth of this component; that's just determined\n                  // by the basic H and V specified for the component\n                  for (y=0; y < z->img_comp[n].v; ++y) {\n                     for (x=0; x < z->img_comp[n].h; ++x) {\n                        int x2 = (i*z->img_comp[n].h + x);\n                        int y2 = (j*z->img_comp[n].v + y);\n                        short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w);\n                        if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n))\n                           return 0;\n                     }\n                  }\n               }\n               // after all interleaved components, that's an interleaved MCU,\n               // so now count down the restart interval\n               if (--z->todo <= 0) {\n                  if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);\n                  if (!STBI__RESTART(z->marker)) return 1;\n                  stbi__jpeg_reset(z);\n               }\n            }\n         }\n         return 1;\n      }\n   }\n}\n\nstatic void stbi__jpeg_dequantize(short *data, stbi__uint16 *dequant)\n{\n   int i;\n   for (i=0; i < 64; ++i)\n      data[i] *= dequant[i];\n}\n\nstatic void stbi__jpeg_finish(stbi__jpeg *z)\n{\n   if (z->progressive) {\n      // dequantize and idct the data\n      int i,j,n;\n      for (n=0; n < z->s->img_n; ++n) {\n         int w = (z->img_comp[n].x+7) >> 3;\n         int h = (z->img_comp[n].y+7) >> 3;\n         for (j=0; j < h; ++j) {\n            for (i=0; i < w; ++i) {\n               short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w);\n               stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]);\n               z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data);\n            }\n         }\n      }\n   }\n}\n\nstatic int stbi__process_marker(stbi__jpeg *z, int m)\n{\n   int L;\n   switch (m) {\n      case STBI__MARKER_none: // no marker found\n         return stbi__err(\"expected marker\",\"Corrupt JPEG\");\n\n      case 0xDD: // DRI - specify restart interval\n         if (stbi__get16be(z->s) != 4) return stbi__err(\"bad DRI len\",\"Corrupt JPEG\");\n         z->restart_interval = stbi__get16be(z->s);\n         return 1;\n\n      case 0xDB: // DQT - define quantization table\n         L = stbi__get16be(z->s)-2;\n         while (L > 0) {\n            int q = stbi__get8(z->s);\n            int p = q >> 4, sixteen = (p != 0);\n            int t = q & 15,i;\n            if (p != 0 && p != 1) return stbi__err(\"bad DQT type\",\"Corrupt JPEG\");\n            if (t > 3) return stbi__err(\"bad DQT table\",\"Corrupt JPEG\");\n\n            for (i=0; i < 64; ++i)\n               z->dequant[t][stbi__jpeg_dezigzag[i]] = sixteen ? stbi__get16be(z->s) : stbi__get8(z->s);\n            L -= (sixteen ? 129 : 65);\n         }\n         return L==0;\n\n      case 0xC4: // DHT - define huffman table\n         L = stbi__get16be(z->s)-2;\n         while (L > 0) {\n            stbi_uc *v;\n            int sizes[16],i,n=0;\n            int q = stbi__get8(z->s);\n            int tc = q >> 4;\n            int th = q & 15;\n            if (tc > 1 || th > 3) return stbi__err(\"bad DHT header\",\"Corrupt JPEG\");\n            for (i=0; i < 16; ++i) {\n               sizes[i] = stbi__get8(z->s);\n               n += sizes[i];\n            }\n            L -= 17;\n            if (tc == 0) {\n               if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0;\n               v = z->huff_dc[th].values;\n            } else {\n               if (!stbi__build_huffman(z->huff_ac+th, sizes)) return 0;\n               v = z->huff_ac[th].values;\n            }\n            for (i=0; i < n; ++i)\n               v[i] = stbi__get8(z->s);\n            if (tc != 0)\n               stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th);\n            L -= n;\n         }\n         return L==0;\n   }\n   // check for comment block or APP blocks\n   if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) {\n      stbi__skip(z->s, stbi__get16be(z->s)-2);\n      return 1;\n   }\n   return stbi__err(\"unknown marker\",\"Corrupt JPEG\");\n}\n\n// after we see SOS\nstatic int stbi__process_scan_header(stbi__jpeg *z)\n{\n   int i;\n   int Ls = stbi__get16be(z->s);\n   z->scan_n = stbi__get8(z->s);\n   if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err(\"bad SOS component count\",\"Corrupt JPEG\");\n   if (Ls != 6+2*z->scan_n) return stbi__err(\"bad SOS len\",\"Corrupt JPEG\");\n   for (i=0; i < z->scan_n; ++i) {\n      int id = stbi__get8(z->s), which;\n      int q = stbi__get8(z->s);\n      for (which = 0; which < z->s->img_n; ++which)\n         if (z->img_comp[which].id == id)\n            break;\n      if (which == z->s->img_n) return 0; // no match\n      z->img_comp[which].hd = q >> 4;   if (z->img_comp[which].hd > 3) return stbi__err(\"bad DC huff\",\"Corrupt JPEG\");\n      z->img_comp[which].ha = q & 15;   if (z->img_comp[which].ha > 3) return stbi__err(\"bad AC huff\",\"Corrupt JPEG\");\n      z->order[i] = which;\n   }\n\n   {\n      int aa;\n      z->spec_start = stbi__get8(z->s);\n      z->spec_end   = stbi__get8(z->s); // should be 63, but might be 0\n      aa = stbi__get8(z->s);\n      z->succ_high = (aa >> 4);\n      z->succ_low  = (aa & 15);\n      if (z->progressive) {\n         if (z->spec_start > 63 || z->spec_end > 63  || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13)\n            return stbi__err(\"bad SOS\", \"Corrupt JPEG\");\n      } else {\n         if (z->spec_start != 0) return stbi__err(\"bad SOS\",\"Corrupt JPEG\");\n         if (z->succ_high != 0 || z->succ_low != 0) return stbi__err(\"bad SOS\",\"Corrupt JPEG\");\n         z->spec_end = 63;\n      }\n   }\n\n   return 1;\n}\n\nstatic int stbi__free_jpeg_components(stbi__jpeg *z, int ncomp, int why)\n{\n   int i;\n   for (i=0; i < ncomp; ++i) {\n      if (z->img_comp[i].raw_data) {\n         STBI_FREE(z->img_comp[i].raw_data);\n         z->img_comp[i].raw_data = NULL;\n         z->img_comp[i].data = NULL;\n      }\n      if (z->img_comp[i].raw_coeff) {\n         STBI_FREE(z->img_comp[i].raw_coeff);\n         z->img_comp[i].raw_coeff = 0;\n         z->img_comp[i].coeff = 0;\n      }\n      if (z->img_comp[i].linebuf) {\n         STBI_FREE(z->img_comp[i].linebuf);\n         z->img_comp[i].linebuf = NULL;\n      }\n   }\n   return why;\n}\n\nstatic int stbi__process_frame_header(stbi__jpeg *z, int scan)\n{\n   stbi__context *s = z->s;\n   int Lf,p,i,q, h_max=1,v_max=1,c;\n   Lf = stbi__get16be(s);         if (Lf < 11) return stbi__err(\"bad SOF len\",\"Corrupt JPEG\"); // JPEG\n   p  = stbi__get8(s);            if (p != 8) return stbi__err(\"only 8-bit\",\"JPEG format not supported: 8-bit only\"); // JPEG baseline\n   s->img_y = stbi__get16be(s);   if (s->img_y == 0) return stbi__err(\"no header height\", \"JPEG format not supported: delayed height\"); // Legal, but we don't handle it--but neither does IJG\n   s->img_x = stbi__get16be(s);   if (s->img_x == 0) return stbi__err(\"0 width\",\"Corrupt JPEG\"); // JPEG requires\n   c = stbi__get8(s);\n   if (c != 3 && c != 1) return stbi__err(\"bad component count\",\"Corrupt JPEG\");    // JFIF requires\n   s->img_n = c;\n   for (i=0; i < c; ++i) {\n      z->img_comp[i].data = NULL;\n      z->img_comp[i].linebuf = NULL;\n   }\n\n   if (Lf != 8+3*s->img_n) return stbi__err(\"bad SOF len\",\"Corrupt JPEG\");\n\n   z->rgb = 0;\n   for (i=0; i < s->img_n; ++i) {\n      static unsigned char rgb[3] = { 'R', 'G', 'B' };\n      z->img_comp[i].id = stbi__get8(s);\n      if (z->img_comp[i].id == rgb[i])\n         ++z->rgb;\n      q = stbi__get8(s);\n      z->img_comp[i].h = (q >> 4);  if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err(\"bad H\",\"Corrupt JPEG\");\n      z->img_comp[i].v = q & 15;    if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err(\"bad V\",\"Corrupt JPEG\");\n      z->img_comp[i].tq = stbi__get8(s);  if (z->img_comp[i].tq > 3) return stbi__err(\"bad TQ\",\"Corrupt JPEG\");\n   }\n\n   if (scan != STBI__SCAN_load) return 1;\n\n   if (!stbi__mad3sizes_valid(s->img_x, s->img_y, s->img_n, 0)) return stbi__err(\"too large\", \"Image too large to decode\");\n\n   for (i=0; i < s->img_n; ++i) {\n      if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h;\n      if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v;\n   }\n\n   // compute interleaved mcu info\n   z->img_h_max = h_max;\n   z->img_v_max = v_max;\n   z->img_mcu_w = h_max * 8;\n   z->img_mcu_h = v_max * 8;\n   // these sizes can't be more than 17 bits\n   z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w;\n   z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h;\n\n   for (i=0; i < s->img_n; ++i) {\n      // number of effective pixels (e.g. for non-interleaved MCU)\n      z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max;\n      z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max;\n      // to simplify generation, we'll allocate enough memory to decode\n      // the bogus oversized data from using interleaved MCUs and their\n      // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't\n      // discard the extra data until colorspace conversion\n      //\n      // img_mcu_x, img_mcu_y: <=17 bits; comp[i].h and .v are <=4 (checked earlier)\n      // so these muls can't overflow with 32-bit ints (which we require)\n      z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8;\n      z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8;\n      z->img_comp[i].coeff = 0;\n      z->img_comp[i].raw_coeff = 0;\n      z->img_comp[i].linebuf = NULL;\n      z->img_comp[i].raw_data = stbi__malloc_mad2(z->img_comp[i].w2, z->img_comp[i].h2, 15);\n      if (z->img_comp[i].raw_data == NULL)\n         return stbi__free_jpeg_components(z, i+1, stbi__err(\"outofmem\", \"Out of memory\"));\n      // align blocks for idct using mmx/sse\n      z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15);\n      if (z->progressive) {\n         // w2, h2 are multiples of 8 (see above)\n         z->img_comp[i].coeff_w = z->img_comp[i].w2 / 8;\n         z->img_comp[i].coeff_h = z->img_comp[i].h2 / 8;\n         z->img_comp[i].raw_coeff = stbi__malloc_mad3(z->img_comp[i].w2, z->img_comp[i].h2, sizeof(short), 15);\n         if (z->img_comp[i].raw_coeff == NULL)\n            return stbi__free_jpeg_components(z, i+1, stbi__err(\"outofmem\", \"Out of memory\"));\n         z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15);\n      }\n   }\n\n   return 1;\n}\n\n// use comparisons since in some cases we handle more than one case (e.g. SOF)\n#define stbi__DNL(x)         ((x) == 0xdc)\n#define stbi__SOI(x)         ((x) == 0xd8)\n#define stbi__EOI(x)         ((x) == 0xd9)\n#define stbi__SOF(x)         ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2)\n#define stbi__SOS(x)         ((x) == 0xda)\n\n#define stbi__SOF_progressive(x)   ((x) == 0xc2)\n\nstatic int stbi__decode_jpeg_header(stbi__jpeg *z, int scan)\n{\n   int m;\n   z->marker = STBI__MARKER_none; // initialize cached marker to empty\n   m = stbi__get_marker(z);\n   if (!stbi__SOI(m)) return stbi__err(\"no SOI\",\"Corrupt JPEG\");\n   if (scan == STBI__SCAN_type) return 1;\n   m = stbi__get_marker(z);\n   while (!stbi__SOF(m)) {\n      if (!stbi__process_marker(z,m)) return 0;\n      m = stbi__get_marker(z);\n      while (m == STBI__MARKER_none) {\n         // some files have extra padding after their blocks, so ok, we'll scan\n         if (stbi__at_eof(z->s)) return stbi__err(\"no SOF\", \"Corrupt JPEG\");\n         m = stbi__get_marker(z);\n      }\n   }\n   z->progressive = stbi__SOF_progressive(m);\n   if (!stbi__process_frame_header(z, scan)) return 0;\n   return 1;\n}\n\n// decode image to YCbCr format\nstatic int stbi__decode_jpeg_image(stbi__jpeg *j)\n{\n   int m;\n   for (m = 0; m < 4; m++) {\n      j->img_comp[m].raw_data = NULL;\n      j->img_comp[m].raw_coeff = NULL;\n   }\n   j->restart_interval = 0;\n   if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0;\n   m = stbi__get_marker(j);\n   while (!stbi__EOI(m)) {\n      if (stbi__SOS(m)) {\n         if (!stbi__process_scan_header(j)) return 0;\n         if (!stbi__parse_entropy_coded_data(j)) return 0;\n         if (j->marker == STBI__MARKER_none ) {\n            // handle 0s at the end of image data from IP Kamera 9060\n            while (!stbi__at_eof(j->s)) {\n               int x = stbi__get8(j->s);\n               if (x == 255) {\n                  j->marker = stbi__get8(j->s);\n                  break;\n               }\n            }\n            // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0\n         }\n      } else if (stbi__DNL(m)) {\n         int Ld = stbi__get16be(j->s);\n         stbi__uint32 NL = stbi__get16be(j->s);\n         if (Ld != 4) stbi__err(\"bad DNL len\", \"Corrupt JPEG\");\n         if (NL != j->s->img_y) stbi__err(\"bad DNL height\", \"Corrupt JPEG\");\n      } else {\n         if (!stbi__process_marker(j, m)) return 0;\n      }\n      m = stbi__get_marker(j);\n   }\n   if (j->progressive)\n      stbi__jpeg_finish(j);\n   return 1;\n}\n\n// static jfif-centered resampling (across block boundaries)\n\ntypedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1,\n                                    int w, int hs);\n\n#define stbi__div4(x) ((stbi_uc) ((x) >> 2))\n\nstatic stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)\n{\n   STBI_NOTUSED(out);\n   STBI_NOTUSED(in_far);\n   STBI_NOTUSED(w);\n   STBI_NOTUSED(hs);\n   return in_near;\n}\n\nstatic stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)\n{\n   // need to generate two samples vertically for every one in input\n   int i;\n   STBI_NOTUSED(hs);\n   for (i=0; i < w; ++i)\n      out[i] = stbi__div4(3*in_near[i] + in_far[i] + 2);\n   return out;\n}\n\nstatic stbi_uc*  stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)\n{\n   // need to generate two samples horizontally for every one in input\n   int i;\n   stbi_uc *input = in_near;\n\n   if (w == 1) {\n      // if only one sample, can't do any interpolation\n      out[0] = out[1] = input[0];\n      return out;\n   }\n\n   out[0] = input[0];\n   out[1] = stbi__div4(input[0]*3 + input[1] + 2);\n   for (i=1; i < w-1; ++i) {\n      int n = 3*input[i]+2;\n      out[i*2+0] = stbi__div4(n+input[i-1]);\n      out[i*2+1] = stbi__div4(n+input[i+1]);\n   }\n   out[i*2+0] = stbi__div4(input[w-2]*3 + input[w-1] + 2);\n   out[i*2+1] = input[w-1];\n\n   STBI_NOTUSED(in_far);\n   STBI_NOTUSED(hs);\n\n   return out;\n}\n\n#define stbi__div16(x) ((stbi_uc) ((x) >> 4))\n\nstatic stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)\n{\n   // need to generate 2x2 samples for every one in input\n   int i,t0,t1;\n   if (w == 1) {\n      out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2);\n      return out;\n   }\n\n   t1 = 3*in_near[0] + in_far[0];\n   out[0] = stbi__div4(t1+2);\n   for (i=1; i < w; ++i) {\n      t0 = t1;\n      t1 = 3*in_near[i]+in_far[i];\n      out[i*2-1] = stbi__div16(3*t0 + t1 + 8);\n      out[i*2  ] = stbi__div16(3*t1 + t0 + 8);\n   }\n   out[w*2-1] = stbi__div4(t1+2);\n\n   STBI_NOTUSED(hs);\n\n   return out;\n}\n\n#if defined(STBI_SSE2) || defined(STBI_NEON)\nstatic stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)\n{\n   // need to generate 2x2 samples for every one in input\n   int i=0,t0,t1;\n\n   if (w == 1) {\n      out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2);\n      return out;\n   }\n\n   t1 = 3*in_near[0] + in_far[0];\n   // process groups of 8 pixels for as long as we can.\n   // note we can't handle the last pixel in a row in this loop\n   // because we need to handle the filter boundary conditions.\n   for (; i < ((w-1) & ~7); i += 8) {\n#if defined(STBI_SSE2)\n      // load and perform the vertical filtering pass\n      // this uses 3*x + y = 4*x + (y - x)\n      __m128i zero  = _mm_setzero_si128();\n      __m128i farb  = _mm_loadl_epi64((__m128i *) (in_far + i));\n      __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i));\n      __m128i farw  = _mm_unpacklo_epi8(farb, zero);\n      __m128i nearw = _mm_unpacklo_epi8(nearb, zero);\n      __m128i diff  = _mm_sub_epi16(farw, nearw);\n      __m128i nears = _mm_slli_epi16(nearw, 2);\n      __m128i curr  = _mm_add_epi16(nears, diff); // current row\n\n      // horizontal filter works the same based on shifted vers of current\n      // row. \"prev\" is current row shifted right by 1 pixel; we need to\n      // insert the previous pixel value (from t1).\n      // \"next\" is current row shifted left by 1 pixel, with first pixel\n      // of next block of 8 pixels added in.\n      __m128i prv0 = _mm_slli_si128(curr, 2);\n      __m128i nxt0 = _mm_srli_si128(curr, 2);\n      __m128i prev = _mm_insert_epi16(prv0, t1, 0);\n      __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7);\n\n      // horizontal filter, polyphase implementation since it's convenient:\n      // even pixels = 3*cur + prev = cur*4 + (prev - cur)\n      // odd  pixels = 3*cur + next = cur*4 + (next - cur)\n      // note the shared term.\n      __m128i bias  = _mm_set1_epi16(8);\n      __m128i curs = _mm_slli_epi16(curr, 2);\n      __m128i prvd = _mm_sub_epi16(prev, curr);\n      __m128i nxtd = _mm_sub_epi16(next, curr);\n      __m128i curb = _mm_add_epi16(curs, bias);\n      __m128i even = _mm_add_epi16(prvd, curb);\n      __m128i odd  = _mm_add_epi16(nxtd, curb);\n\n      // interleave even and odd pixels, then undo scaling.\n      __m128i int0 = _mm_unpacklo_epi16(even, odd);\n      __m128i int1 = _mm_unpackhi_epi16(even, odd);\n      __m128i de0  = _mm_srli_epi16(int0, 4);\n      __m128i de1  = _mm_srli_epi16(int1, 4);\n\n      // pack and write output\n      __m128i outv = _mm_packus_epi16(de0, de1);\n      _mm_storeu_si128((__m128i *) (out + i*2), outv);\n#elif defined(STBI_NEON)\n      // load and perform the vertical filtering pass\n      // this uses 3*x + y = 4*x + (y - x)\n      uint8x8_t farb  = vld1_u8(in_far + i);\n      uint8x8_t nearb = vld1_u8(in_near + i);\n      int16x8_t diff  = vreinterpretq_s16_u16(vsubl_u8(farb, nearb));\n      int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2));\n      int16x8_t curr  = vaddq_s16(nears, diff); // current row\n\n      // horizontal filter works the same based on shifted vers of current\n      // row. \"prev\" is current row shifted right by 1 pixel; we need to\n      // insert the previous pixel value (from t1).\n      // \"next\" is current row shifted left by 1 pixel, with first pixel\n      // of next block of 8 pixels added in.\n      int16x8_t prv0 = vextq_s16(curr, curr, 7);\n      int16x8_t nxt0 = vextq_s16(curr, curr, 1);\n      int16x8_t prev = vsetq_lane_s16(t1, prv0, 0);\n      int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7);\n\n      // horizontal filter, polyphase implementation since it's convenient:\n      // even pixels = 3*cur + prev = cur*4 + (prev - cur)\n      // odd  pixels = 3*cur + next = cur*4 + (next - cur)\n      // note the shared term.\n      int16x8_t curs = vshlq_n_s16(curr, 2);\n      int16x8_t prvd = vsubq_s16(prev, curr);\n      int16x8_t nxtd = vsubq_s16(next, curr);\n      int16x8_t even = vaddq_s16(curs, prvd);\n      int16x8_t odd  = vaddq_s16(curs, nxtd);\n\n      // undo scaling and round, then store with even/odd phases interleaved\n      uint8x8x2_t o;\n      o.val[0] = vqrshrun_n_s16(even, 4);\n      o.val[1] = vqrshrun_n_s16(odd,  4);\n      vst2_u8(out + i*2, o);\n#endif\n\n      // \"previous\" value for next iter\n      t1 = 3*in_near[i+7] + in_far[i+7];\n   }\n\n   t0 = t1;\n   t1 = 3*in_near[i] + in_far[i];\n   out[i*2] = stbi__div16(3*t1 + t0 + 8);\n\n   for (++i; i < w; ++i) {\n      t0 = t1;\n      t1 = 3*in_near[i]+in_far[i];\n      out[i*2-1] = stbi__div16(3*t0 + t1 + 8);\n      out[i*2  ] = stbi__div16(3*t1 + t0 + 8);\n   }\n   out[w*2-1] = stbi__div4(t1+2);\n\n   STBI_NOTUSED(hs);\n\n   return out;\n}\n#endif\n\nstatic stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)\n{\n   // resample with nearest-neighbor\n   int i,j;\n   STBI_NOTUSED(in_far);\n   for (i=0; i < w; ++i)\n      for (j=0; j < hs; ++j)\n         out[i*hs+j] = in_near[i];\n   return out;\n}\n\n// this is a reduced-precision calculation of YCbCr-to-RGB introduced\n// to make sure the code produces the same results in both SIMD and scalar\n#define stbi__float2fixed(x)  (((int) ((x) * 4096.0f + 0.5f)) << 8)\nstatic void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step)\n{\n   int i;\n   for (i=0; i < count; ++i) {\n      int y_fixed = (y[i] << 20) + (1<<19); // rounding\n      int r,g,b;\n      int cr = pcr[i] - 128;\n      int cb = pcb[i] - 128;\n      r = y_fixed +  cr* stbi__float2fixed(1.40200f);\n      g = y_fixed + (cr*-stbi__float2fixed(0.71414f)) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000);\n      b = y_fixed                                     +   cb* stbi__float2fixed(1.77200f);\n      r >>= 20;\n      g >>= 20;\n      b >>= 20;\n      if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; }\n      if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; }\n      if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; }\n      out[0] = (stbi_uc)r;\n      out[1] = (stbi_uc)g;\n      out[2] = (stbi_uc)b;\n      out[3] = 255;\n      out += step;\n   }\n}\n\n#if defined(STBI_SSE2) || defined(STBI_NEON)\nstatic void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step)\n{\n   int i = 0;\n\n#ifdef STBI_SSE2\n   // step == 3 is pretty ugly on the final interleave, and i'm not convinced\n   // it's useful in practice (you wouldn't use it for textures, for example).\n   // so just accelerate step == 4 case.\n   if (step == 4) {\n      // this is a fairly straightforward implementation and not super-optimized.\n      __m128i signflip  = _mm_set1_epi8(-0x80);\n      __m128i cr_const0 = _mm_set1_epi16(   (short) ( 1.40200f*4096.0f+0.5f));\n      __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f));\n      __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f));\n      __m128i cb_const1 = _mm_set1_epi16(   (short) ( 1.77200f*4096.0f+0.5f));\n      __m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128);\n      __m128i xw = _mm_set1_epi16(255); // alpha channel\n\n      for (; i+7 < count; i += 8) {\n         // load\n         __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i));\n         __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i));\n         __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i));\n         __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128\n         __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128\n\n         // unpack to short (and left-shift cr, cb by 8)\n         __m128i yw  = _mm_unpacklo_epi8(y_bias, y_bytes);\n         __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased);\n         __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased);\n\n         // color transform\n         __m128i yws = _mm_srli_epi16(yw, 4);\n         __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw);\n         __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw);\n         __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1);\n         __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1);\n         __m128i rws = _mm_add_epi16(cr0, yws);\n         __m128i gwt = _mm_add_epi16(cb0, yws);\n         __m128i bws = _mm_add_epi16(yws, cb1);\n         __m128i gws = _mm_add_epi16(gwt, cr1);\n\n         // descale\n         __m128i rw = _mm_srai_epi16(rws, 4);\n         __m128i bw = _mm_srai_epi16(bws, 4);\n         __m128i gw = _mm_srai_epi16(gws, 4);\n\n         // back to byte, set up for transpose\n         __m128i brb = _mm_packus_epi16(rw, bw);\n         __m128i gxb = _mm_packus_epi16(gw, xw);\n\n         // transpose to interleave channels\n         __m128i t0 = _mm_unpacklo_epi8(brb, gxb);\n         __m128i t1 = _mm_unpackhi_epi8(brb, gxb);\n         __m128i o0 = _mm_unpacklo_epi16(t0, t1);\n         __m128i o1 = _mm_unpackhi_epi16(t0, t1);\n\n         // store\n         _mm_storeu_si128((__m128i *) (out + 0), o0);\n         _mm_storeu_si128((__m128i *) (out + 16), o1);\n         out += 32;\n      }\n   }\n#endif\n\n#ifdef STBI_NEON\n   // in this version, step=3 support would be easy to add. but is there demand?\n   if (step == 4) {\n      // this is a fairly straightforward implementation and not super-optimized.\n      uint8x8_t signflip = vdup_n_u8(0x80);\n      int16x8_t cr_const0 = vdupq_n_s16(   (short) ( 1.40200f*4096.0f+0.5f));\n      int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f));\n      int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f));\n      int16x8_t cb_const1 = vdupq_n_s16(   (short) ( 1.77200f*4096.0f+0.5f));\n\n      for (; i+7 < count; i += 8) {\n         // load\n         uint8x8_t y_bytes  = vld1_u8(y + i);\n         uint8x8_t cr_bytes = vld1_u8(pcr + i);\n         uint8x8_t cb_bytes = vld1_u8(pcb + i);\n         int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip));\n         int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip));\n\n         // expand to s16\n         int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4));\n         int16x8_t crw = vshll_n_s8(cr_biased, 7);\n         int16x8_t cbw = vshll_n_s8(cb_biased, 7);\n\n         // color transform\n         int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0);\n         int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0);\n         int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1);\n         int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1);\n         int16x8_t rws = vaddq_s16(yws, cr0);\n         int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1);\n         int16x8_t bws = vaddq_s16(yws, cb1);\n\n         // undo scaling, round, convert to byte\n         uint8x8x4_t o;\n         o.val[0] = vqrshrun_n_s16(rws, 4);\n         o.val[1] = vqrshrun_n_s16(gws, 4);\n         o.val[2] = vqrshrun_n_s16(bws, 4);\n         o.val[3] = vdup_n_u8(255);\n\n         // store, interleaving r/g/b/a\n         vst4_u8(out, o);\n         out += 8*4;\n      }\n   }\n#endif\n\n   for (; i < count; ++i) {\n      int y_fixed = (y[i] << 20) + (1<<19); // rounding\n      int r,g,b;\n      int cr = pcr[i] - 128;\n      int cb = pcb[i] - 128;\n      r = y_fixed + cr* stbi__float2fixed(1.40200f);\n      g = y_fixed + cr*-stbi__float2fixed(0.71414f) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000);\n      b = y_fixed                                   +   cb* stbi__float2fixed(1.77200f);\n      r >>= 20;\n      g >>= 20;\n      b >>= 20;\n      if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; }\n      if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; }\n      if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; }\n      out[0] = (stbi_uc)r;\n      out[1] = (stbi_uc)g;\n      out[2] = (stbi_uc)b;\n      out[3] = 255;\n      out += step;\n   }\n}\n#endif\n\n// set up the kernels\nstatic void stbi__setup_jpeg(stbi__jpeg *j)\n{\n   j->idct_block_kernel = stbi__idct_block;\n   j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row;\n   j->resample_row_hv_2_kernel = stbi__resample_row_hv_2;\n\n#ifdef STBI_SSE2\n   if (stbi__sse2_available()) {\n      j->idct_block_kernel = stbi__idct_simd;\n      j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd;\n      j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd;\n   }\n#endif\n\n#ifdef STBI_NEON\n   j->idct_block_kernel = stbi__idct_simd;\n   j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd;\n   j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd;\n#endif\n}\n\n// clean up the temporary component buffers\nstatic void stbi__cleanup_jpeg(stbi__jpeg *j)\n{\n   stbi__free_jpeg_components(j, j->s->img_n, 0);\n}\n\ntypedef struct\n{\n   resample_row_func resample;\n   stbi_uc *line0,*line1;\n   int hs,vs;   // expansion factor in each axis\n   int w_lores; // horizontal pixels pre-expansion\n   int ystep;   // how far through vertical expansion we are\n   int ypos;    // which pre-expansion row we're on\n} stbi__resample;\n\nstatic stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp)\n{\n   int n, decode_n;\n   z->s->img_n = 0; // make stbi__cleanup_jpeg safe\n\n   // validate req_comp\n   if (req_comp < 0 || req_comp > 4) return stbi__errpuc(\"bad req_comp\", \"Internal error\");\n\n   // load a jpeg image from whichever source, but leave in YCbCr format\n   if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; }\n\n   // determine actual number of components to generate\n   n = req_comp ? req_comp : z->s->img_n;\n\n   if (z->s->img_n == 3 && n < 3 && z->rgb != 3)\n      decode_n = 1;\n   else\n      decode_n = z->s->img_n;\n\n   // resample and color-convert\n   {\n      int k;\n      unsigned int i,j;\n      stbi_uc *output;\n      stbi_uc *coutput[4];\n\n      stbi__resample res_comp[4];\n\n      for (k=0; k < decode_n; ++k) {\n         stbi__resample *r = &res_comp[k];\n\n         // allocate line buffer big enough for upsampling off the edges\n         // with upsample factor of 4\n         z->img_comp[k].linebuf = (stbi_uc *) stbi__malloc(z->s->img_x + 3);\n         if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc(\"outofmem\", \"Out of memory\"); }\n\n         r->hs      = z->img_h_max / z->img_comp[k].h;\n         r->vs      = z->img_v_max / z->img_comp[k].v;\n         r->ystep   = r->vs >> 1;\n         r->w_lores = (z->s->img_x + r->hs-1) / r->hs;\n         r->ypos    = 0;\n         r->line0   = r->line1 = z->img_comp[k].data;\n\n         if      (r->hs == 1 && r->vs == 1) r->resample = resample_row_1;\n         else if (r->hs == 1 && r->vs == 2) r->resample = stbi__resample_row_v_2;\n         else if (r->hs == 2 && r->vs == 1) r->resample = stbi__resample_row_h_2;\n         else if (r->hs == 2 && r->vs == 2) r->resample = z->resample_row_hv_2_kernel;\n         else                               r->resample = stbi__resample_row_generic;\n      }\n\n      // can't error after this so, this is safe\n      output = (stbi_uc *) stbi__malloc_mad3(n, z->s->img_x, z->s->img_y, 1);\n      if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc(\"outofmem\", \"Out of memory\"); }\n\n      // now go ahead and resample\n      for (j=0; j < z->s->img_y; ++j) {\n         stbi_uc *out = output + n * z->s->img_x * j;\n         for (k=0; k < decode_n; ++k) {\n            stbi__resample *r = &res_comp[k];\n            int y_bot = r->ystep >= (r->vs >> 1);\n            coutput[k] = r->resample(z->img_comp[k].linebuf,\n                                     y_bot ? r->line1 : r->line0,\n                                     y_bot ? r->line0 : r->line1,\n                                     r->w_lores, r->hs);\n            if (++r->ystep >= r->vs) {\n               r->ystep = 0;\n               r->line0 = r->line1;\n               if (++r->ypos < z->img_comp[k].y)\n                  r->line1 += z->img_comp[k].w2;\n            }\n         }\n         if (n >= 3) {\n            stbi_uc *y = coutput[0];\n            if (z->s->img_n == 3) {\n               if (z->rgb == 3) {\n                  for (i=0; i < z->s->img_x; ++i) {\n                     out[0] = y[i];\n                     out[1] = coutput[1][i];\n                     out[2] = coutput[2][i];\n                     out[3] = 255;\n                     out += n;\n                  }\n               } else {\n                  z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n);\n               }\n            } else\n               for (i=0; i < z->s->img_x; ++i) {\n                  out[0] = out[1] = out[2] = y[i];\n                  out[3] = 255; // not used if n==3\n                  out += n;\n               }\n         } else {\n            if (z->rgb == 3) {\n               if (n == 1)\n                  for (i=0; i < z->s->img_x; ++i)\n                     *out++ = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]);\n               else {\n                  for (i=0; i < z->s->img_x; ++i, out += 2) {\n                     out[0] = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]);\n                     out[1] = 255;\n                  }\n               }\n            } else {\n               stbi_uc *y = coutput[0];\n               if (n == 1)\n                  for (i=0; i < z->s->img_x; ++i) out[i] = y[i];\n               else\n                  for (i=0; i < z->s->img_x; ++i) *out++ = y[i], *out++ = 255;\n            }\n         }\n      }\n      stbi__cleanup_jpeg(z);\n      *out_x = z->s->img_x;\n      *out_y = z->s->img_y;\n      if (comp) *comp  = z->s->img_n; // report original components, not output\n      return output;\n   }\n}\n\nstatic void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)\n{\n   unsigned char* result;\n   stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg));\n   j->s = s;\n   stbi__setup_jpeg(j);\n   result = load_jpeg_image(j, x,y,comp,req_comp);\n   STBI_FREE(j);\n   return result;\n}\n\nstatic int stbi__jpeg_test(stbi__context *s)\n{\n   int r;\n   stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg));\n   j->s = s;\n   stbi__setup_jpeg(j);\n   r = stbi__decode_jpeg_header(j, STBI__SCAN_type);\n   stbi__rewind(s);\n   STBI_FREE(j);\n   return r;\n}\n\nstatic int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp)\n{\n   if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) {\n      stbi__rewind( j->s );\n      return 0;\n   }\n   if (x) *x = j->s->img_x;\n   if (y) *y = j->s->img_y;\n   if (comp) *comp = j->s->img_n;\n   return 1;\n}\n\nstatic int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp)\n{\n   int result;\n   stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg)));\n   j->s = s;\n   result = stbi__jpeg_info_raw(j, x, y, comp);\n   STBI_FREE(j);\n   return result;\n}\n#endif\n\n// public domain zlib decode    v0.2  Sean Barrett 2006-11-18\n//    simple implementation\n//      - all input must be provided in an upfront buffer\n//      - all output is written to a single output buffer (can malloc/realloc)\n//    performance\n//      - fast huffman\n\n#ifndef STBI_NO_ZLIB\n\n// fast-way is faster to check than jpeg huffman, but slow way is slower\n#define STBI__ZFAST_BITS  9 // accelerate all cases in default tables\n#define STBI__ZFAST_MASK  ((1 << STBI__ZFAST_BITS) - 1)\n\n// zlib-style huffman encoding\n// (jpegs packs from left, zlib from right, so can't share code)\ntypedef struct\n{\n   stbi__uint16 fast[1 << STBI__ZFAST_BITS];\n   stbi__uint16 firstcode[16];\n   int maxcode[17];\n   stbi__uint16 firstsymbol[16];\n   stbi_uc  size[288];\n   stbi__uint16 value[288];\n} stbi__zhuffman;\n\nstbi_inline static int stbi__bitreverse16(int n)\n{\n  n = ((n & 0xAAAA) >>  1) | ((n & 0x5555) << 1);\n  n = ((n & 0xCCCC) >>  2) | ((n & 0x3333) << 2);\n  n = ((n & 0xF0F0) >>  4) | ((n & 0x0F0F) << 4);\n  n = ((n & 0xFF00) >>  8) | ((n & 0x00FF) << 8);\n  return n;\n}\n\nstbi_inline static int stbi__bit_reverse(int v, int bits)\n{\n   STBI_ASSERT(bits <= 16);\n   // to bit reverse n bits, reverse 16 and shift\n   // e.g. 11 bits, bit reverse and shift away 5\n   return stbi__bitreverse16(v) >> (16-bits);\n}\n\nstatic int stbi__zbuild_huffman(stbi__zhuffman *z, stbi_uc *sizelist, int num)\n{\n   int i,k=0;\n   int code, next_code[16], sizes[17];\n\n   // DEFLATE spec for generating codes\n   memset(sizes, 0, sizeof(sizes));\n   memset(z->fast, 0, sizeof(z->fast));\n   for (i=0; i < num; ++i)\n      ++sizes[sizelist[i]];\n   sizes[0] = 0;\n   for (i=1; i < 16; ++i)\n      if (sizes[i] > (1 << i))\n         return stbi__err(\"bad sizes\", \"Corrupt PNG\");\n   code = 0;\n   for (i=1; i < 16; ++i) {\n      next_code[i] = code;\n      z->firstcode[i] = (stbi__uint16) code;\n      z->firstsymbol[i] = (stbi__uint16) k;\n      code = (code + sizes[i]);\n      if (sizes[i])\n         if (code-1 >= (1 << i)) return stbi__err(\"bad codelengths\",\"Corrupt PNG\");\n      z->maxcode[i] = code << (16-i); // preshift for inner loop\n      code <<= 1;\n      k += sizes[i];\n   }\n   z->maxcode[16] = 0x10000; // sentinel\n   for (i=0; i < num; ++i) {\n      int s = sizelist[i];\n      if (s) {\n         int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s];\n         stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i);\n         z->size [c] = (stbi_uc     ) s;\n         z->value[c] = (stbi__uint16) i;\n         if (s <= STBI__ZFAST_BITS) {\n            int j = stbi__bit_reverse(next_code[s],s);\n            while (j < (1 << STBI__ZFAST_BITS)) {\n               z->fast[j] = fastv;\n               j += (1 << s);\n            }\n         }\n         ++next_code[s];\n      }\n   }\n   return 1;\n}\n\n// zlib-from-memory implementation for PNG reading\n//    because PNG allows splitting the zlib stream arbitrarily,\n//    and it's annoying structurally to have PNG call ZLIB call PNG,\n//    we require PNG read all the IDATs and combine them into a single\n//    memory buffer\n\ntypedef struct\n{\n   stbi_uc *zbuffer, *zbuffer_end;\n   int num_bits;\n   stbi__uint32 code_buffer;\n\n   char *zout;\n   char *zout_start;\n   char *zout_end;\n   int   z_expandable;\n\n   stbi__zhuffman z_length, z_distance;\n} stbi__zbuf;\n\nstbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z)\n{\n   if (z->zbuffer >= z->zbuffer_end) return 0;\n   return *z->zbuffer++;\n}\n\nstatic void stbi__fill_bits(stbi__zbuf *z)\n{\n   do {\n      STBI_ASSERT(z->code_buffer < (1U << z->num_bits));\n      z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits;\n      z->num_bits += 8;\n   } while (z->num_bits <= 24);\n}\n\nstbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n)\n{\n   unsigned int k;\n   if (z->num_bits < n) stbi__fill_bits(z);\n   k = z->code_buffer & ((1 << n) - 1);\n   z->code_buffer >>= n;\n   z->num_bits -= n;\n   return k;\n}\n\nstatic int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z)\n{\n   int b,s,k;\n   // not resolved by fast table, so compute it the slow way\n   // use jpeg approach, which requires MSbits at top\n   k = stbi__bit_reverse(a->code_buffer, 16);\n   for (s=STBI__ZFAST_BITS+1; ; ++s)\n      if (k < z->maxcode[s])\n         break;\n   if (s == 16) return -1; // invalid code!\n   // code size is s, so:\n   b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s];\n   STBI_ASSERT(z->size[b] == s);\n   a->code_buffer >>= s;\n   a->num_bits -= s;\n   return z->value[b];\n}\n\nstbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z)\n{\n   int b,s;\n   if (a->num_bits < 16) stbi__fill_bits(a);\n   b = z->fast[a->code_buffer & STBI__ZFAST_MASK];\n   if (b) {\n      s = b >> 9;\n      a->code_buffer >>= s;\n      a->num_bits -= s;\n      return b & 511;\n   }\n   return stbi__zhuffman_decode_slowpath(a, z);\n}\n\nstatic int stbi__zexpand(stbi__zbuf *z, char *zout, int n)  // need to make room for n bytes\n{\n   char *q;\n   int cur, limit, old_limit;\n   z->zout = zout;\n   if (!z->z_expandable) return stbi__err(\"output buffer limit\",\"Corrupt PNG\");\n   cur   = (int) (z->zout     - z->zout_start);\n   limit = old_limit = (int) (z->zout_end - z->zout_start);\n   while (cur + n > limit)\n      limit *= 2;\n   q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit);\n   STBI_NOTUSED(old_limit);\n   if (q == NULL) return stbi__err(\"outofmem\", \"Out of memory\");\n   z->zout_start = q;\n   z->zout       = q + cur;\n   z->zout_end   = q + limit;\n   return 1;\n}\n\nstatic int stbi__zlength_base[31] = {\n   3,4,5,6,7,8,9,10,11,13,\n   15,17,19,23,27,31,35,43,51,59,\n   67,83,99,115,131,163,195,227,258,0,0 };\n\nstatic int stbi__zlength_extra[31]=\n{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 };\n\nstatic int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,\n257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0};\n\nstatic int stbi__zdist_extra[32] =\n{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};\n\nstatic int stbi__parse_huffman_block(stbi__zbuf *a)\n{\n   char *zout = a->zout;\n   for(;;) {\n      int z = stbi__zhuffman_decode(a, &a->z_length);\n      if (z < 256) {\n         if (z < 0) return stbi__err(\"bad huffman code\",\"Corrupt PNG\"); // error in huffman codes\n         if (zout >= a->zout_end) {\n            if (!stbi__zexpand(a, zout, 1)) return 0;\n            zout = a->zout;\n         }\n         *zout++ = (char) z;\n      } else {\n         stbi_uc *p;\n         int len,dist;\n         if (z == 256) {\n            a->zout = zout;\n            return 1;\n         }\n         z -= 257;\n         len = stbi__zlength_base[z];\n         if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]);\n         z = stbi__zhuffman_decode(a, &a->z_distance);\n         if (z < 0) return stbi__err(\"bad huffman code\",\"Corrupt PNG\");\n         dist = stbi__zdist_base[z];\n         if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]);\n         if (zout - a->zout_start < dist) return stbi__err(\"bad dist\",\"Corrupt PNG\");\n         if (zout + len > a->zout_end) {\n            if (!stbi__zexpand(a, zout, len)) return 0;\n            zout = a->zout;\n         }\n         p = (stbi_uc *) (zout - dist);\n         if (dist == 1) { // run of one byte; common in images.\n            stbi_uc v = *p;\n            if (len) { do *zout++ = v; while (--len); }\n         } else {\n            if (len) { do *zout++ = *p++; while (--len); }\n         }\n      }\n   }\n}\n\nstatic int stbi__compute_huffman_codes(stbi__zbuf *a)\n{\n   static stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 };\n   stbi__zhuffman z_codelength;\n   stbi_uc lencodes[286+32+137];//padding for maximum single op\n   stbi_uc codelength_sizes[19];\n   int i,n;\n\n   int hlit  = stbi__zreceive(a,5) + 257;\n   int hdist = stbi__zreceive(a,5) + 1;\n   int hclen = stbi__zreceive(a,4) + 4;\n   int ntot  = hlit + hdist;\n\n   memset(codelength_sizes, 0, sizeof(codelength_sizes));\n   for (i=0; i < hclen; ++i) {\n      int s = stbi__zreceive(a,3);\n      codelength_sizes[length_dezigzag[i]] = (stbi_uc) s;\n   }\n   if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0;\n\n   n = 0;\n   while (n < ntot) {\n      int c = stbi__zhuffman_decode(a, &z_codelength);\n      if (c < 0 || c >= 19) return stbi__err(\"bad codelengths\", \"Corrupt PNG\");\n      if (c < 16)\n         lencodes[n++] = (stbi_uc) c;\n      else {\n         stbi_uc fill = 0;\n         if (c == 16) {\n            c = stbi__zreceive(a,2)+3;\n            if (n == 0) return stbi__err(\"bad codelengths\", \"Corrupt PNG\");\n            fill = lencodes[n-1];\n         } else if (c == 17)\n            c = stbi__zreceive(a,3)+3;\n         else {\n            STBI_ASSERT(c == 18);\n            c = stbi__zreceive(a,7)+11;\n         }\n         if (ntot - n < c) return stbi__err(\"bad codelengths\", \"Corrupt PNG\");\n         memset(lencodes+n, fill, c);\n         n += c;\n      }\n   }\n   if (n != ntot) return stbi__err(\"bad codelengths\",\"Corrupt PNG\");\n   if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0;\n   if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0;\n   return 1;\n}\n\nstatic int stbi__parse_uncompressed_block(stbi__zbuf *a)\n{\n   stbi_uc header[4];\n   int len,nlen,k;\n   if (a->num_bits & 7)\n      stbi__zreceive(a, a->num_bits & 7); // discard\n   // drain the bit-packed data into header\n   k = 0;\n   while (a->num_bits > 0) {\n      header[k++] = (stbi_uc) (a->code_buffer & 255); // suppress MSVC run-time check\n      a->code_buffer >>= 8;\n      a->num_bits -= 8;\n   }\n   STBI_ASSERT(a->num_bits == 0);\n   // now fill header the normal way\n   while (k < 4)\n      header[k++] = stbi__zget8(a);\n   len  = header[1] * 256 + header[0];\n   nlen = header[3] * 256 + header[2];\n   if (nlen != (len ^ 0xffff)) return stbi__err(\"zlib corrupt\",\"Corrupt PNG\");\n   if (a->zbuffer + len > a->zbuffer_end) return stbi__err(\"read past buffer\",\"Corrupt PNG\");\n   if (a->zout + len > a->zout_end)\n      if (!stbi__zexpand(a, a->zout, len)) return 0;\n   memcpy(a->zout, a->zbuffer, len);\n   a->zbuffer += len;\n   a->zout += len;\n   return 1;\n}\n\nstatic int stbi__parse_zlib_header(stbi__zbuf *a)\n{\n   int cmf   = stbi__zget8(a);\n   int cm    = cmf & 15;\n   /* int cinfo = cmf >> 4; */\n   int flg   = stbi__zget8(a);\n   if ((cmf*256+flg) % 31 != 0) return stbi__err(\"bad zlib header\",\"Corrupt PNG\"); // zlib spec\n   if (flg & 32) return stbi__err(\"no preset dict\",\"Corrupt PNG\"); // preset dictionary not allowed in png\n   if (cm != 8) return stbi__err(\"bad compression\",\"Corrupt PNG\"); // DEFLATE required for png\n   // window = 1 << (8 + cinfo)... but who cares, we fully buffer output\n   return 1;\n}\n\n// @TODO: should statically initialize these for optimal thread safety\nstatic stbi_uc stbi__zdefault_length[288], stbi__zdefault_distance[32];\nstatic void stbi__init_zdefaults(void)\n{\n   int i;   // use <= to match clearly with spec\n   for (i=0; i <= 143; ++i)     stbi__zdefault_length[i]   = 8;\n   for (   ; i <= 255; ++i)     stbi__zdefault_length[i]   = 9;\n   for (   ; i <= 279; ++i)     stbi__zdefault_length[i]   = 7;\n   for (   ; i <= 287; ++i)     stbi__zdefault_length[i]   = 8;\n\n   for (i=0; i <=  31; ++i)     stbi__zdefault_distance[i] = 5;\n}\n\nstatic int stbi__parse_zlib(stbi__zbuf *a, int parse_header)\n{\n   int final, type;\n   if (parse_header)\n      if (!stbi__parse_zlib_header(a)) return 0;\n   a->num_bits = 0;\n   a->code_buffer = 0;\n   do {\n      final = stbi__zreceive(a,1);\n      type = stbi__zreceive(a,2);\n      if (type == 0) {\n         if (!stbi__parse_uncompressed_block(a)) return 0;\n      } else if (type == 3) {\n         return 0;\n      } else {\n         if (type == 1) {\n            // use fixed code lengths\n            if (!stbi__zdefault_distance[31]) stbi__init_zdefaults();\n            if (!stbi__zbuild_huffman(&a->z_length  , stbi__zdefault_length  , 288)) return 0;\n            if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance,  32)) return 0;\n         } else {\n            if (!stbi__compute_huffman_codes(a)) return 0;\n         }\n         if (!stbi__parse_huffman_block(a)) return 0;\n      }\n   } while (!final);\n   return 1;\n}\n\nstatic int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header)\n{\n   a->zout_start = obuf;\n   a->zout       = obuf;\n   a->zout_end   = obuf + olen;\n   a->z_expandable = exp;\n\n   return stbi__parse_zlib(a, parse_header);\n}\n\nSTBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen)\n{\n   stbi__zbuf a;\n   char *p = (char *) stbi__malloc(initial_size);\n   if (p == NULL) return NULL;\n   a.zbuffer = (stbi_uc *) buffer;\n   a.zbuffer_end = (stbi_uc *) buffer + len;\n   if (stbi__do_zlib(&a, p, initial_size, 1, 1)) {\n      if (outlen) *outlen = (int) (a.zout - a.zout_start);\n      return a.zout_start;\n   } else {\n      STBI_FREE(a.zout_start);\n      return NULL;\n   }\n}\n\nSTBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen)\n{\n   return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen);\n}\n\nSTBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header)\n{\n   stbi__zbuf a;\n   char *p = (char *) stbi__malloc(initial_size);\n   if (p == NULL) return NULL;\n   a.zbuffer = (stbi_uc *) buffer;\n   a.zbuffer_end = (stbi_uc *) buffer + len;\n   if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) {\n      if (outlen) *outlen = (int) (a.zout - a.zout_start);\n      return a.zout_start;\n   } else {\n      STBI_FREE(a.zout_start);\n      return NULL;\n   }\n}\n\nSTBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen)\n{\n   stbi__zbuf a;\n   a.zbuffer = (stbi_uc *) ibuffer;\n   a.zbuffer_end = (stbi_uc *) ibuffer + ilen;\n   if (stbi__do_zlib(&a, obuffer, olen, 0, 1))\n      return (int) (a.zout - a.zout_start);\n   else\n      return -1;\n}\n\nSTBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen)\n{\n   stbi__zbuf a;\n   char *p = (char *) stbi__malloc(16384);\n   if (p == NULL) return NULL;\n   a.zbuffer = (stbi_uc *) buffer;\n   a.zbuffer_end = (stbi_uc *) buffer+len;\n   if (stbi__do_zlib(&a, p, 16384, 1, 0)) {\n      if (outlen) *outlen = (int) (a.zout - a.zout_start);\n      return a.zout_start;\n   } else {\n      STBI_FREE(a.zout_start);\n      return NULL;\n   }\n}\n\nSTBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen)\n{\n   stbi__zbuf a;\n   a.zbuffer = (stbi_uc *) ibuffer;\n   a.zbuffer_end = (stbi_uc *) ibuffer + ilen;\n   if (stbi__do_zlib(&a, obuffer, olen, 0, 0))\n      return (int) (a.zout - a.zout_start);\n   else\n      return -1;\n}\n#endif\n\n// public domain \"baseline\" PNG decoder   v0.10  Sean Barrett 2006-11-18\n//    simple implementation\n//      - only 8-bit samples\n//      - no CRC checking\n//      - allocates lots of intermediate memory\n//        - avoids problem of streaming data between subsystems\n//        - avoids explicit window management\n//    performance\n//      - uses stb_zlib, a PD zlib implementation with fast huffman decoding\n\n#ifndef STBI_NO_PNG\ntypedef struct\n{\n   stbi__uint32 length;\n   stbi__uint32 type;\n} stbi__pngchunk;\n\nstatic stbi__pngchunk stbi__get_chunk_header(stbi__context *s)\n{\n   stbi__pngchunk c;\n   c.length = stbi__get32be(s);\n   c.type   = stbi__get32be(s);\n   return c;\n}\n\nstatic int stbi__check_png_header(stbi__context *s)\n{\n   static stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 };\n   int i;\n   for (i=0; i < 8; ++i)\n      if (stbi__get8(s) != png_sig[i]) return stbi__err(\"bad png sig\",\"Not a PNG\");\n   return 1;\n}\n\ntypedef struct\n{\n   stbi__context *s;\n   stbi_uc *idata, *expanded, *out;\n   int depth;\n} stbi__png;\n\n\nenum {\n   STBI__F_none=0,\n   STBI__F_sub=1,\n   STBI__F_up=2,\n   STBI__F_avg=3,\n   STBI__F_paeth=4,\n   // synthetic filters used for first scanline to avoid needing a dummy row of 0s\n   STBI__F_avg_first,\n   STBI__F_paeth_first\n};\n\nstatic stbi_uc first_row_filter[5] =\n{\n   STBI__F_none,\n   STBI__F_sub,\n   STBI__F_none,\n   STBI__F_avg_first,\n   STBI__F_paeth_first\n};\n\nstatic int stbi__paeth(int a, int b, int c)\n{\n   int p = a + b - c;\n   int pa = abs(p-a);\n   int pb = abs(p-b);\n   int pc = abs(p-c);\n   if (pa <= pb && pa <= pc) return a;\n   if (pb <= pc) return b;\n   return c;\n}\n\nstatic stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 };\n\n// create the png data from post-deflated data\nstatic int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color)\n{\n   int bytes = (depth == 16? 2 : 1);\n   stbi__context *s = a->s;\n   stbi__uint32 i,j,stride = x*out_n*bytes;\n   stbi__uint32 img_len, img_width_bytes;\n   int k;\n   int img_n = s->img_n; // copy it into a local for later\n\n   int output_bytes = out_n*bytes;\n   int filter_bytes = img_n*bytes;\n   int width = x;\n\n   STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1);\n   a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into\n   if (!a->out) return stbi__err(\"outofmem\", \"Out of memory\");\n\n   img_width_bytes = (((img_n * x * depth) + 7) >> 3);\n   img_len = (img_width_bytes + 1) * y;\n   if (s->img_x == x && s->img_y == y) {\n      if (raw_len != img_len) return stbi__err(\"not enough pixels\",\"Corrupt PNG\");\n   } else { // interlaced:\n      if (raw_len < img_len) return stbi__err(\"not enough pixels\",\"Corrupt PNG\");\n   }\n\n   for (j=0; j < y; ++j) {\n      stbi_uc *cur = a->out + stride*j;\n      stbi_uc *prior = cur - stride;\n      int filter = *raw++;\n\n      if (filter > 4)\n         return stbi__err(\"invalid filter\",\"Corrupt PNG\");\n\n      if (depth < 8) {\n         STBI_ASSERT(img_width_bytes <= x);\n         cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place\n         filter_bytes = 1;\n         width = img_width_bytes;\n      }\n\n      // if first row, use special filter that doesn't sample previous row\n      if (j == 0) filter = first_row_filter[filter];\n\n      // handle first byte explicitly\n      for (k=0; k < filter_bytes; ++k) {\n         switch (filter) {\n            case STBI__F_none       : cur[k] = raw[k]; break;\n            case STBI__F_sub        : cur[k] = raw[k]; break;\n            case STBI__F_up         : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break;\n            case STBI__F_avg        : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break;\n            case STBI__F_paeth      : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break;\n            case STBI__F_avg_first  : cur[k] = raw[k]; break;\n            case STBI__F_paeth_first: cur[k] = raw[k]; break;\n         }\n      }\n\n      if (depth == 8) {\n         if (img_n != out_n)\n            cur[img_n] = 255; // first pixel\n         raw += img_n;\n         cur += out_n;\n         prior += out_n;\n      } else if (depth == 16) {\n         if (img_n != out_n) {\n            cur[filter_bytes]   = 255; // first pixel top byte\n            cur[filter_bytes+1] = 255; // first pixel bottom byte\n         }\n         raw += filter_bytes;\n         cur += output_bytes;\n         prior += output_bytes;\n      } else {\n         raw += 1;\n         cur += 1;\n         prior += 1;\n      }\n\n      // this is a little gross, so that we don't switch per-pixel or per-component\n      if (depth < 8 || img_n == out_n) {\n         int nk = (width - 1)*filter_bytes;\n         #define STBI__CASE(f) \\\n             case f:     \\\n                for (k=0; k < nk; ++k)\n         switch (filter) {\n            // \"none\" filter turns into a memcpy here; make that explicit.\n            case STBI__F_none:         memcpy(cur, raw, nk); break;\n            STBI__CASE(STBI__F_sub)          { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break;\n            STBI__CASE(STBI__F_up)           { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break;\n            STBI__CASE(STBI__F_avg)          { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break;\n            STBI__CASE(STBI__F_paeth)        { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break;\n            STBI__CASE(STBI__F_avg_first)    { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break;\n            STBI__CASE(STBI__F_paeth_first)  { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); } break;\n         }\n         #undef STBI__CASE\n         raw += nk;\n      } else {\n         STBI_ASSERT(img_n+1 == out_n);\n         #define STBI__CASE(f) \\\n             case f:     \\\n                for (i=x-1; i >= 1; --i, cur[filter_bytes]=255,raw+=filter_bytes,cur+=output_bytes,prior+=output_bytes) \\\n                   for (k=0; k < filter_bytes; ++k)\n         switch (filter) {\n            STBI__CASE(STBI__F_none)         { cur[k] = raw[k]; } break;\n            STBI__CASE(STBI__F_sub)          { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break;\n            STBI__CASE(STBI__F_up)           { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break;\n            STBI__CASE(STBI__F_avg)          { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break;\n            STBI__CASE(STBI__F_paeth)        { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break;\n            STBI__CASE(STBI__F_avg_first)    { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break;\n            STBI__CASE(STBI__F_paeth_first)  { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); } break;\n         }\n         #undef STBI__CASE\n\n         // the loop above sets the high byte of the pixels' alpha, but for\n         // 16 bit png files we also need the low byte set. we'll do that here.\n         if (depth == 16) {\n            cur = a->out + stride*j; // start at the beginning of the row again\n            for (i=0; i < x; ++i,cur+=output_bytes) {\n               cur[filter_bytes+1] = 255;\n            }\n         }\n      }\n   }\n\n   // we make a separate pass to expand bits to pixels; for performance,\n   // this could run two scanlines behind the above code, so it won't\n   // intefere with filtering but will still be in the cache.\n   if (depth < 8) {\n      for (j=0; j < y; ++j) {\n         stbi_uc *cur = a->out + stride*j;\n         stbi_uc *in  = a->out + stride*j + x*out_n - img_width_bytes;\n         // unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit\n         // png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop\n         stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range\n\n         // note that the final byte might overshoot and write more data than desired.\n         // we can allocate enough data that this never writes out of memory, but it\n         // could also overwrite the next scanline. can it overwrite non-empty data\n         // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel.\n         // so we need to explicitly clamp the final ones\n\n         if (depth == 4) {\n            for (k=x*img_n; k >= 2; k-=2, ++in) {\n               *cur++ = scale * ((*in >> 4)       );\n               *cur++ = scale * ((*in     ) & 0x0f);\n            }\n            if (k > 0) *cur++ = scale * ((*in >> 4)       );\n         } else if (depth == 2) {\n            for (k=x*img_n; k >= 4; k-=4, ++in) {\n               *cur++ = scale * ((*in >> 6)       );\n               *cur++ = scale * ((*in >> 4) & 0x03);\n               *cur++ = scale * ((*in >> 2) & 0x03);\n               *cur++ = scale * ((*in     ) & 0x03);\n            }\n            if (k > 0) *cur++ = scale * ((*in >> 6)       );\n            if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03);\n            if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03);\n         } else if (depth == 1) {\n            for (k=x*img_n; k >= 8; k-=8, ++in) {\n               *cur++ = scale * ((*in >> 7)       );\n               *cur++ = scale * ((*in >> 6) & 0x01);\n               *cur++ = scale * ((*in >> 5) & 0x01);\n               *cur++ = scale * ((*in >> 4) & 0x01);\n               *cur++ = scale * ((*in >> 3) & 0x01);\n               *cur++ = scale * ((*in >> 2) & 0x01);\n               *cur++ = scale * ((*in >> 1) & 0x01);\n               *cur++ = scale * ((*in     ) & 0x01);\n            }\n            if (k > 0) *cur++ = scale * ((*in >> 7)       );\n            if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01);\n            if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01);\n            if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01);\n            if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01);\n            if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01);\n            if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01);\n         }\n         if (img_n != out_n) {\n            int q;\n            // insert alpha = 255\n            cur = a->out + stride*j;\n            if (img_n == 1) {\n               for (q=x-1; q >= 0; --q) {\n                  cur[q*2+1] = 255;\n                  cur[q*2+0] = cur[q];\n               }\n            } else {\n               STBI_ASSERT(img_n == 3);\n               for (q=x-1; q >= 0; --q) {\n                  cur[q*4+3] = 255;\n                  cur[q*4+2] = cur[q*3+2];\n                  cur[q*4+1] = cur[q*3+1];\n                  cur[q*4+0] = cur[q*3+0];\n               }\n            }\n         }\n      }\n   } else if (depth == 16) {\n      // force the image data from big-endian to platform-native.\n      // this is done in a separate pass due to the decoding relying\n      // on the data being untouched, but could probably be done\n      // per-line during decode if care is taken.\n      stbi_uc *cur = a->out;\n      stbi__uint16 *cur16 = (stbi__uint16*)cur;\n\n      for(i=0; i < x*y*out_n; ++i,cur16++,cur+=2) {\n         *cur16 = (cur[0] << 8) | cur[1];\n      }\n   }\n\n   return 1;\n}\n\nstatic int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced)\n{\n   int bytes = (depth == 16 ? 2 : 1);\n   int out_bytes = out_n * bytes;\n   stbi_uc *final;\n   int p;\n   if (!interlaced)\n      return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color);\n\n   // de-interlacing\n   final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0);\n   for (p=0; p < 7; ++p) {\n      int xorig[] = { 0,4,0,2,0,1,0 };\n      int yorig[] = { 0,0,4,0,2,0,1 };\n      int xspc[]  = { 8,8,4,4,2,2,1 };\n      int yspc[]  = { 8,8,8,4,4,2,2 };\n      int i,j,x,y;\n      // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1\n      x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p];\n      y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p];\n      if (x && y) {\n         stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y;\n         if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) {\n            STBI_FREE(final);\n            return 0;\n         }\n         for (j=0; j < y; ++j) {\n            for (i=0; i < x; ++i) {\n               int out_y = j*yspc[p]+yorig[p];\n               int out_x = i*xspc[p]+xorig[p];\n               memcpy(final + out_y*a->s->img_x*out_bytes + out_x*out_bytes,\n                      a->out + (j*x+i)*out_bytes, out_bytes);\n            }\n         }\n         STBI_FREE(a->out);\n         image_data += img_len;\n         image_data_len -= img_len;\n      }\n   }\n   a->out = final;\n\n   return 1;\n}\n\nstatic int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n)\n{\n   stbi__context *s = z->s;\n   stbi__uint32 i, pixel_count = s->img_x * s->img_y;\n   stbi_uc *p = z->out;\n\n   // compute color-based transparency, assuming we've\n   // already got 255 as the alpha value in the output\n   STBI_ASSERT(out_n == 2 || out_n == 4);\n\n   if (out_n == 2) {\n      for (i=0; i < pixel_count; ++i) {\n         p[1] = (p[0] == tc[0] ? 0 : 255);\n         p += 2;\n      }\n   } else {\n      for (i=0; i < pixel_count; ++i) {\n         if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2])\n            p[3] = 0;\n         p += 4;\n      }\n   }\n   return 1;\n}\n\nstatic int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int out_n)\n{\n   stbi__context *s = z->s;\n   stbi__uint32 i, pixel_count = s->img_x * s->img_y;\n   stbi__uint16 *p = (stbi__uint16*) z->out;\n\n   // compute color-based transparency, assuming we've\n   // already got 65535 as the alpha value in the output\n   STBI_ASSERT(out_n == 2 || out_n == 4);\n\n   if (out_n == 2) {\n      for (i = 0; i < pixel_count; ++i) {\n         p[1] = (p[0] == tc[0] ? 0 : 65535);\n         p += 2;\n      }\n   } else {\n      for (i = 0; i < pixel_count; ++i) {\n         if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2])\n            p[3] = 0;\n         p += 4;\n      }\n   }\n   return 1;\n}\n\nstatic int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n)\n{\n   stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y;\n   stbi_uc *p, *temp_out, *orig = a->out;\n\n   p = (stbi_uc *) stbi__malloc_mad2(pixel_count, pal_img_n, 0);\n   if (p == NULL) return stbi__err(\"outofmem\", \"Out of memory\");\n\n   // between here and free(out) below, exitting would leak\n   temp_out = p;\n\n   if (pal_img_n == 3) {\n      for (i=0; i < pixel_count; ++i) {\n         int n = orig[i]*4;\n         p[0] = palette[n  ];\n         p[1] = palette[n+1];\n         p[2] = palette[n+2];\n         p += 3;\n      }\n   } else {\n      for (i=0; i < pixel_count; ++i) {\n         int n = orig[i]*4;\n         p[0] = palette[n  ];\n         p[1] = palette[n+1];\n         p[2] = palette[n+2];\n         p[3] = palette[n+3];\n         p += 4;\n      }\n   }\n   STBI_FREE(a->out);\n   a->out = temp_out;\n\n   STBI_NOTUSED(len);\n\n   return 1;\n}\n\nstatic int stbi__unpremultiply_on_load = 0;\nstatic int stbi__de_iphone_flag = 0;\n\nSTBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply)\n{\n   stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply;\n}\n\nSTBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert)\n{\n   stbi__de_iphone_flag = flag_true_if_should_convert;\n}\n\nstatic void stbi__de_iphone(stbi__png *z)\n{\n   stbi__context *s = z->s;\n   stbi__uint32 i, pixel_count = s->img_x * s->img_y;\n   stbi_uc *p = z->out;\n\n   if (s->img_out_n == 3) {  // convert bgr to rgb\n      for (i=0; i < pixel_count; ++i) {\n         stbi_uc t = p[0];\n         p[0] = p[2];\n         p[2] = t;\n         p += 3;\n      }\n   } else {\n      STBI_ASSERT(s->img_out_n == 4);\n      if (stbi__unpremultiply_on_load) {\n         // convert bgr to rgb and unpremultiply\n         for (i=0; i < pixel_count; ++i) {\n            stbi_uc a = p[3];\n            stbi_uc t = p[0];\n            if (a) {\n               p[0] = p[2] * 255 / a;\n               p[1] = p[1] * 255 / a;\n               p[2] =  t   * 255 / a;\n            } else {\n               p[0] = p[2];\n               p[2] = t;\n            }\n            p += 4;\n         }\n      } else {\n         // convert bgr to rgb\n         for (i=0; i < pixel_count; ++i) {\n            stbi_uc t = p[0];\n            p[0] = p[2];\n            p[2] = t;\n            p += 4;\n         }\n      }\n   }\n}\n\n#define STBI__PNG_TYPE(a,b,c,d)  (((a) << 24) + ((b) << 16) + ((c) << 8) + (d))\n\nstatic int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)\n{\n   stbi_uc palette[1024], pal_img_n=0;\n   stbi_uc has_trans=0, tc[3];\n   stbi__uint16 tc16[3];\n   stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0;\n   int first=1,k,interlace=0, color=0, is_iphone=0;\n   stbi__context *s = z->s;\n\n   z->expanded = NULL;\n   z->idata = NULL;\n   z->out = NULL;\n\n   if (!stbi__check_png_header(s)) return 0;\n\n   if (scan == STBI__SCAN_type) return 1;\n\n   for (;;) {\n      stbi__pngchunk c = stbi__get_chunk_header(s);\n      switch (c.type) {\n         case STBI__PNG_TYPE('C','g','B','I'):\n            is_iphone = 1;\n            stbi__skip(s, c.length);\n            break;\n         case STBI__PNG_TYPE('I','H','D','R'): {\n            int comp,filter;\n            if (!first) return stbi__err(\"multiple IHDR\",\"Corrupt PNG\");\n            first = 0;\n            if (c.length != 13) return stbi__err(\"bad IHDR len\",\"Corrupt PNG\");\n            s->img_x = stbi__get32be(s); if (s->img_x > (1 << 24)) return stbi__err(\"too large\",\"Very large image (corrupt?)\");\n            s->img_y = stbi__get32be(s); if (s->img_y > (1 << 24)) return stbi__err(\"too large\",\"Very large image (corrupt?)\");\n            z->depth = stbi__get8(s);  if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16)  return stbi__err(\"1/2/4/8/16-bit only\",\"PNG not supported: 1/2/4/8/16-bit only\");\n            color = stbi__get8(s);  if (color > 6)         return stbi__err(\"bad ctype\",\"Corrupt PNG\");\n\t\t\tif (color == 3 && z->depth == 16)                  return stbi__err(\"bad ctype\",\"Corrupt PNG\");\n            if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err(\"bad ctype\",\"Corrupt PNG\");\n            comp  = stbi__get8(s);  if (comp) return stbi__err(\"bad comp method\",\"Corrupt PNG\");\n            filter= stbi__get8(s);  if (filter) return stbi__err(\"bad filter method\",\"Corrupt PNG\");\n            interlace = stbi__get8(s); if (interlace>1) return stbi__err(\"bad interlace method\",\"Corrupt PNG\");\n            if (!s->img_x || !s->img_y) return stbi__err(\"0-pixel image\",\"Corrupt PNG\");\n            if (!pal_img_n) {\n               s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0);\n               if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err(\"too large\", \"Image too large to decode\");\n               if (scan == STBI__SCAN_header) return 1;\n            } else {\n               // if paletted, then pal_n is our final components, and\n               // img_n is # components to decompress/filter.\n               s->img_n = 1;\n               if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err(\"too large\",\"Corrupt PNG\");\n               // if SCAN_header, have to scan to see if we have a tRNS\n            }\n            break;\n         }\n\n         case STBI__PNG_TYPE('P','L','T','E'):  {\n            if (first) return stbi__err(\"first not IHDR\", \"Corrupt PNG\");\n            if (c.length > 256*3) return stbi__err(\"invalid PLTE\",\"Corrupt PNG\");\n            pal_len = c.length / 3;\n            if (pal_len * 3 != c.length) return stbi__err(\"invalid PLTE\",\"Corrupt PNG\");\n            for (i=0; i < pal_len; ++i) {\n               palette[i*4+0] = stbi__get8(s);\n               palette[i*4+1] = stbi__get8(s);\n               palette[i*4+2] = stbi__get8(s);\n               palette[i*4+3] = 255;\n            }\n            break;\n         }\n\n         case STBI__PNG_TYPE('t','R','N','S'): {\n            if (first) return stbi__err(\"first not IHDR\", \"Corrupt PNG\");\n            if (z->idata) return stbi__err(\"tRNS after IDAT\",\"Corrupt PNG\");\n            if (pal_img_n) {\n               if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; }\n               if (pal_len == 0) return stbi__err(\"tRNS before PLTE\",\"Corrupt PNG\");\n               if (c.length > pal_len) return stbi__err(\"bad tRNS len\",\"Corrupt PNG\");\n               pal_img_n = 4;\n               for (i=0; i < c.length; ++i)\n                  palette[i*4+3] = stbi__get8(s);\n            } else {\n               if (!(s->img_n & 1)) return stbi__err(\"tRNS with alpha\",\"Corrupt PNG\");\n               if (c.length != (stbi__uint32) s->img_n*2) return stbi__err(\"bad tRNS len\",\"Corrupt PNG\");\n               has_trans = 1;\n               if (z->depth == 16) {\n                  for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is\n               } else {\n                  for (k = 0; k < s->img_n; ++k) tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger\n               }\n            }\n            break;\n         }\n\n         case STBI__PNG_TYPE('I','D','A','T'): {\n            if (first) return stbi__err(\"first not IHDR\", \"Corrupt PNG\");\n            if (pal_img_n && !pal_len) return stbi__err(\"no PLTE\",\"Corrupt PNG\");\n            if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; }\n            if ((int)(ioff + c.length) < (int)ioff) return 0;\n            if (ioff + c.length > idata_limit) {\n               stbi__uint32 idata_limit_old = idata_limit;\n               stbi_uc *p;\n               if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096;\n               while (ioff + c.length > idata_limit)\n                  idata_limit *= 2;\n               STBI_NOTUSED(idata_limit_old);\n               p = (stbi_uc *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return stbi__err(\"outofmem\", \"Out of memory\");\n               z->idata = p;\n            }\n            if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err(\"outofdata\",\"Corrupt PNG\");\n            ioff += c.length;\n            break;\n         }\n\n         case STBI__PNG_TYPE('I','E','N','D'): {\n            stbi__uint32 raw_len, bpl;\n            if (first) return stbi__err(\"first not IHDR\", \"Corrupt PNG\");\n            if (scan != STBI__SCAN_load) return 1;\n            if (z->idata == NULL) return stbi__err(\"no IDAT\",\"Corrupt PNG\");\n            // initial guess for decoded data size to avoid unnecessary reallocs\n            bpl = (s->img_x * z->depth + 7) / 8; // bytes per line, per component\n            raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */;\n            z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone);\n            if (z->expanded == NULL) return 0; // zlib should set error\n            STBI_FREE(z->idata); z->idata = NULL;\n            if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans)\n               s->img_out_n = s->img_n+1;\n            else\n               s->img_out_n = s->img_n;\n            if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0;\n            if (has_trans) {\n               if (z->depth == 16) {\n                  if (!stbi__compute_transparency16(z, tc16, s->img_out_n)) return 0;\n               } else {\n                  if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0;\n               }\n            }\n            if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2)\n               stbi__de_iphone(z);\n            if (pal_img_n) {\n               // pal_img_n == 3 or 4\n               s->img_n = pal_img_n; // record the actual colors we had\n               s->img_out_n = pal_img_n;\n               if (req_comp >= 3) s->img_out_n = req_comp;\n               if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n))\n                  return 0;\n            }\n            STBI_FREE(z->expanded); z->expanded = NULL;\n            return 1;\n         }\n\n         default:\n            // if critical, fail\n            if (first) return stbi__err(\"first not IHDR\", \"Corrupt PNG\");\n            if ((c.type & (1 << 29)) == 0) {\n               #ifndef STBI_NO_FAILURE_STRINGS\n               // not threadsafe\n               static char invalid_chunk[] = \"XXXX PNG chunk not known\";\n               invalid_chunk[0] = STBI__BYTECAST(c.type >> 24);\n               invalid_chunk[1] = STBI__BYTECAST(c.type >> 16);\n               invalid_chunk[2] = STBI__BYTECAST(c.type >>  8);\n               invalid_chunk[3] = STBI__BYTECAST(c.type >>  0);\n               #endif\n               return stbi__err(invalid_chunk, \"PNG not supported: unknown PNG chunk type\");\n            }\n            stbi__skip(s, c.length);\n            break;\n      }\n      // end of PNG chunk, read and skip CRC\n      stbi__get32be(s);\n   }\n}\n\nstatic void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, stbi__result_info *ri)\n{\n   void *result=NULL;\n   if (req_comp < 0 || req_comp > 4) return stbi__errpuc(\"bad req_comp\", \"Internal error\");\n   if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) {\n      if (p->depth < 8)\n         ri->bits_per_channel = 8;\n      else\n         ri->bits_per_channel = p->depth;\n      result = p->out;\n      p->out = NULL;\n      if (req_comp && req_comp != p->s->img_out_n) {\n         if (ri->bits_per_channel == 8)\n            result = stbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y);\n         else\n            result = stbi__convert_format16((stbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y);\n         p->s->img_out_n = req_comp;\n         if (result == NULL) return result;\n      }\n      *x = p->s->img_x;\n      *y = p->s->img_y;\n      if (n) *n = p->s->img_n;\n   }\n   STBI_FREE(p->out);      p->out      = NULL;\n   STBI_FREE(p->expanded); p->expanded = NULL;\n   STBI_FREE(p->idata);    p->idata    = NULL;\n\n   return result;\n}\n\nstatic void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)\n{\n   stbi__png p;\n   p.s = s;\n   return stbi__do_png(&p, x,y,comp,req_comp, ri);\n}\n\nstatic int stbi__png_test(stbi__context *s)\n{\n   int r;\n   r = stbi__check_png_header(s);\n   stbi__rewind(s);\n   return r;\n}\n\nstatic int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp)\n{\n   if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) {\n      stbi__rewind( p->s );\n      return 0;\n   }\n   if (x) *x = p->s->img_x;\n   if (y) *y = p->s->img_y;\n   if (comp) *comp = p->s->img_n;\n   return 1;\n}\n\nstatic int stbi__png_info(stbi__context *s, int *x, int *y, int *comp)\n{\n   stbi__png p;\n   p.s = s;\n   return stbi__png_info_raw(&p, x, y, comp);\n}\n#endif\n\n// Microsoft/Windows BMP image\n\n#ifndef STBI_NO_BMP\nstatic int stbi__bmp_test_raw(stbi__context *s)\n{\n   int r;\n   int sz;\n   if (stbi__get8(s) != 'B') return 0;\n   if (stbi__get8(s) != 'M') return 0;\n   stbi__get32le(s); // discard filesize\n   stbi__get16le(s); // discard reserved\n   stbi__get16le(s); // discard reserved\n   stbi__get32le(s); // discard data offset\n   sz = stbi__get32le(s);\n   r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124);\n   return r;\n}\n\nstatic int stbi__bmp_test(stbi__context *s)\n{\n   int r = stbi__bmp_test_raw(s);\n   stbi__rewind(s);\n   return r;\n}\n\n\n// returns 0..31 for the highest set bit\nstatic int stbi__high_bit(unsigned int z)\n{\n   int n=0;\n   if (z == 0) return -1;\n   if (z >= 0x10000) n += 16, z >>= 16;\n   if (z >= 0x00100) n +=  8, z >>=  8;\n   if (z >= 0x00010) n +=  4, z >>=  4;\n   if (z >= 0x00004) n +=  2, z >>=  2;\n   if (z >= 0x00002) n +=  1, z >>=  1;\n   return n;\n}\n\nstatic int stbi__bitcount(unsigned int a)\n{\n   a = (a & 0x55555555) + ((a >>  1) & 0x55555555); // max 2\n   a = (a & 0x33333333) + ((a >>  2) & 0x33333333); // max 4\n   a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits\n   a = (a + (a >> 8)); // max 16 per 8 bits\n   a = (a + (a >> 16)); // max 32 per 8 bits\n   return a & 0xff;\n}\n\nstatic int stbi__shiftsigned(int v, int shift, int bits)\n{\n   int result;\n   int z=0;\n\n   if (shift < 0) v <<= -shift;\n   else v >>= shift;\n   result = v;\n\n   z = bits;\n   while (z < 8) {\n      result += v >> z;\n      z += bits;\n   }\n   return result;\n}\n\ntypedef struct\n{\n   int bpp, offset, hsz;\n   unsigned int mr,mg,mb,ma, all_a;\n} stbi__bmp_data;\n\nstatic void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info)\n{\n   int hsz;\n   if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc(\"not BMP\", \"Corrupt BMP\");\n   stbi__get32le(s); // discard filesize\n   stbi__get16le(s); // discard reserved\n   stbi__get16le(s); // discard reserved\n   info->offset = stbi__get32le(s);\n   info->hsz = hsz = stbi__get32le(s);\n   info->mr = info->mg = info->mb = info->ma = 0;\n   \n   if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc(\"unknown BMP\", \"BMP type not supported: unknown\");\n   if (hsz == 12) {\n      s->img_x = stbi__get16le(s);\n      s->img_y = stbi__get16le(s);\n   } else {\n      s->img_x = stbi__get32le(s);\n      s->img_y = stbi__get32le(s);\n   }\n   if (stbi__get16le(s) != 1) return stbi__errpuc(\"bad BMP\", \"bad BMP\");\n   info->bpp = stbi__get16le(s);\n   if (info->bpp == 1) return stbi__errpuc(\"monochrome\", \"BMP type not supported: 1-bit\");\n   if (hsz != 12) {\n      int compress = stbi__get32le(s);\n      if (compress == 1 || compress == 2) return stbi__errpuc(\"BMP RLE\", \"BMP type not supported: RLE\");\n      stbi__get32le(s); // discard sizeof\n      stbi__get32le(s); // discard hres\n      stbi__get32le(s); // discard vres\n      stbi__get32le(s); // discard colorsused\n      stbi__get32le(s); // discard max important\n      if (hsz == 40 || hsz == 56) {\n         if (hsz == 56) {\n            stbi__get32le(s);\n            stbi__get32le(s);\n            stbi__get32le(s);\n            stbi__get32le(s);\n         }\n         if (info->bpp == 16 || info->bpp == 32) {\n            if (compress == 0) {\n               if (info->bpp == 32) {\n                  info->mr = 0xffu << 16;\n                  info->mg = 0xffu <<  8;\n                  info->mb = 0xffu <<  0;\n                  info->ma = 0xffu << 24;\n                  info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0\n               } else {\n                  info->mr = 31u << 10;\n                  info->mg = 31u <<  5;\n                  info->mb = 31u <<  0;\n               }\n            } else if (compress == 3) {\n               info->mr = stbi__get32le(s);\n               info->mg = stbi__get32le(s);\n               info->mb = stbi__get32le(s);\n               // not documented, but generated by photoshop and handled by mspaint\n               if (info->mr == info->mg && info->mg == info->mb) {\n                  // ?!?!?\n                  return stbi__errpuc(\"bad BMP\", \"bad BMP\");\n               }\n            } else\n               return stbi__errpuc(\"bad BMP\", \"bad BMP\");\n         }\n      } else {\n         int i;\n         if (hsz != 108 && hsz != 124)\n            return stbi__errpuc(\"bad BMP\", \"bad BMP\");\n         info->mr = stbi__get32le(s);\n         info->mg = stbi__get32le(s);\n         info->mb = stbi__get32le(s);\n         info->ma = stbi__get32le(s);\n         stbi__get32le(s); // discard color space\n         for (i=0; i < 12; ++i)\n            stbi__get32le(s); // discard color space parameters\n         if (hsz == 124) {\n            stbi__get32le(s); // discard rendering intent\n            stbi__get32le(s); // discard offset of profile data\n            stbi__get32le(s); // discard size of profile data\n            stbi__get32le(s); // discard reserved\n         }\n      }\n   }\n   return (void *) 1;\n}\n\n\nstatic void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)\n{\n   stbi_uc *out;\n   unsigned int mr=0,mg=0,mb=0,ma=0, all_a;\n   stbi_uc pal[256][4];\n   int psize=0,i,j,width;\n   int flip_vertically, pad, target;\n   stbi__bmp_data info;\n   STBI_NOTUSED(ri);\n\n   info.all_a = 255;   \n   if (stbi__bmp_parse_header(s, &info) == NULL)\n      return NULL; // error code already set\n\n   flip_vertically = ((int) s->img_y) > 0;\n   s->img_y = abs((int) s->img_y);\n\n   mr = info.mr;\n   mg = info.mg;\n   mb = info.mb;\n   ma = info.ma;\n   all_a = info.all_a;\n\n   if (info.hsz == 12) {\n      if (info.bpp < 24)\n         psize = (info.offset - 14 - 24) / 3;\n   } else {\n      if (info.bpp < 16)\n         psize = (info.offset - 14 - info.hsz) >> 2;\n   }\n\n   s->img_n = ma ? 4 : 3;\n   if (req_comp && req_comp >= 3) // we can directly decode 3 or 4\n      target = req_comp;\n   else\n      target = s->img_n; // if they want monochrome, we'll post-convert\n\n   // sanity-check size\n   if (!stbi__mad3sizes_valid(target, s->img_x, s->img_y, 0))\n      return stbi__errpuc(\"too large\", \"Corrupt BMP\");\n\n   out = (stbi_uc *) stbi__malloc_mad3(target, s->img_x, s->img_y, 0);\n   if (!out) return stbi__errpuc(\"outofmem\", \"Out of memory\");\n   if (info.bpp < 16) {\n      int z=0;\n      if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc(\"invalid\", \"Corrupt BMP\"); }\n      for (i=0; i < psize; ++i) {\n         pal[i][2] = stbi__get8(s);\n         pal[i][1] = stbi__get8(s);\n         pal[i][0] = stbi__get8(s);\n         if (info.hsz != 12) stbi__get8(s);\n         pal[i][3] = 255;\n      }\n      stbi__skip(s, info.offset - 14 - info.hsz - psize * (info.hsz == 12 ? 3 : 4));\n      if (info.bpp == 4) width = (s->img_x + 1) >> 1;\n      else if (info.bpp == 8) width = s->img_x;\n      else { STBI_FREE(out); return stbi__errpuc(\"bad bpp\", \"Corrupt BMP\"); }\n      pad = (-width)&3;\n      for (j=0; j < (int) s->img_y; ++j) {\n         for (i=0; i < (int) s->img_x; i += 2) {\n            int v=stbi__get8(s),v2=0;\n            if (info.bpp == 4) {\n               v2 = v & 15;\n               v >>= 4;\n            }\n            out[z++] = pal[v][0];\n            out[z++] = pal[v][1];\n            out[z++] = pal[v][2];\n            if (target == 4) out[z++] = 255;\n            if (i+1 == (int) s->img_x) break;\n            v = (info.bpp == 8) ? stbi__get8(s) : v2;\n            out[z++] = pal[v][0];\n            out[z++] = pal[v][1];\n            out[z++] = pal[v][2];\n            if (target == 4) out[z++] = 255;\n         }\n         stbi__skip(s, pad);\n      }\n   } else {\n      int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0;\n      int z = 0;\n      int easy=0;\n      stbi__skip(s, info.offset - 14 - info.hsz);\n      if (info.bpp == 24) width = 3 * s->img_x;\n      else if (info.bpp == 16) width = 2*s->img_x;\n      else /* bpp = 32 and pad = 0 */ width=0;\n      pad = (-width) & 3;\n      if (info.bpp == 24) {\n         easy = 1;\n      } else if (info.bpp == 32) {\n         if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000)\n            easy = 2;\n      }\n      if (!easy) {\n         if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc(\"bad masks\", \"Corrupt BMP\"); }\n         // right shift amt to put high bit in position #7\n         rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr);\n         gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg);\n         bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb);\n         ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma);\n      }\n      for (j=0; j < (int) s->img_y; ++j) {\n         if (easy) {\n            for (i=0; i < (int) s->img_x; ++i) {\n               unsigned char a;\n               out[z+2] = stbi__get8(s);\n               out[z+1] = stbi__get8(s);\n               out[z+0] = stbi__get8(s);\n               z += 3;\n               a = (easy == 2 ? stbi__get8(s) : 255);\n               all_a |= a;\n               if (target == 4) out[z++] = a;\n            }\n         } else {\n            int bpp = info.bpp;\n            for (i=0; i < (int) s->img_x; ++i) {\n               stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s));\n               int a;\n               out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount));\n               out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount));\n               out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount));\n               a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255);\n               all_a |= a;\n               if (target == 4) out[z++] = STBI__BYTECAST(a);\n            }\n         }\n         stbi__skip(s, pad);\n      }\n   }\n   \n   // if alpha channel is all 0s, replace with all 255s\n   if (target == 4 && all_a == 0)\n      for (i=4*s->img_x*s->img_y-1; i >= 0; i -= 4)\n         out[i] = 255;\n\n   if (flip_vertically) {\n      stbi_uc t;\n      for (j=0; j < (int) s->img_y>>1; ++j) {\n         stbi_uc *p1 = out +      j     *s->img_x*target;\n         stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target;\n         for (i=0; i < (int) s->img_x*target; ++i) {\n            t = p1[i], p1[i] = p2[i], p2[i] = t;\n         }\n      }\n   }\n\n   if (req_comp && req_comp != target) {\n      out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y);\n      if (out == NULL) return out; // stbi__convert_format frees input on failure\n   }\n\n   *x = s->img_x;\n   *y = s->img_y;\n   if (comp) *comp = s->img_n;\n   return out;\n}\n#endif\n\n// Targa Truevision - TGA\n// by Jonathan Dummer\n#ifndef STBI_NO_TGA\n// returns STBI_rgb or whatever, 0 on error\nstatic int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16)\n{\n   // only RGB or RGBA (incl. 16bit) or grey allowed\n   if(is_rgb16) *is_rgb16 = 0;\n   switch(bits_per_pixel) {\n      case 8:  return STBI_grey;\n      case 16: if(is_grey) return STBI_grey_alpha;\n            // else: fall-through\n      case 15: if(is_rgb16) *is_rgb16 = 1;\n            return STBI_rgb;\n      case 24: // fall-through\n      case 32: return bits_per_pixel/8;\n      default: return 0;\n   }\n}\n\nstatic int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp)\n{\n    int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel, tga_colormap_bpp;\n    int sz, tga_colormap_type;\n    stbi__get8(s);                   // discard Offset\n    tga_colormap_type = stbi__get8(s); // colormap type\n    if( tga_colormap_type > 1 ) {\n        stbi__rewind(s);\n        return 0;      // only RGB or indexed allowed\n    }\n    tga_image_type = stbi__get8(s); // image type\n    if ( tga_colormap_type == 1 ) { // colormapped (paletted) image\n        if (tga_image_type != 1 && tga_image_type != 9) {\n            stbi__rewind(s);\n            return 0;\n        }\n        stbi__skip(s,4);       // skip index of first colormap entry and number of entries\n        sz = stbi__get8(s);    //   check bits per palette color entry\n        if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) {\n            stbi__rewind(s);\n            return 0;\n        }\n        stbi__skip(s,4);       // skip image x and y origin\n        tga_colormap_bpp = sz;\n    } else { // \"normal\" image w/o colormap - only RGB or grey allowed, +/- RLE\n        if ( (tga_image_type != 2) && (tga_image_type != 3) && (tga_image_type != 10) && (tga_image_type != 11) ) {\n            stbi__rewind(s);\n            return 0; // only RGB or grey allowed, +/- RLE\n        }\n        stbi__skip(s,9); // skip colormap specification and image x/y origin\n        tga_colormap_bpp = 0;\n    }\n    tga_w = stbi__get16le(s);\n    if( tga_w < 1 ) {\n        stbi__rewind(s);\n        return 0;   // test width\n    }\n    tga_h = stbi__get16le(s);\n    if( tga_h < 1 ) {\n        stbi__rewind(s);\n        return 0;   // test height\n    }\n    tga_bits_per_pixel = stbi__get8(s); // bits per pixel\n    stbi__get8(s); // ignore alpha bits\n    if (tga_colormap_bpp != 0) {\n        if((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) {\n            // when using a colormap, tga_bits_per_pixel is the size of the indexes\n            // I don't think anything but 8 or 16bit indexes makes sense\n            stbi__rewind(s);\n            return 0;\n        }\n        tga_comp = stbi__tga_get_comp(tga_colormap_bpp, 0, NULL);\n    } else {\n        tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3) || (tga_image_type == 11), NULL);\n    }\n    if(!tga_comp) {\n      stbi__rewind(s);\n      return 0;\n    }\n    if (x) *x = tga_w;\n    if (y) *y = tga_h;\n    if (comp) *comp = tga_comp;\n    return 1;                   // seems to have passed everything\n}\n\nstatic int stbi__tga_test(stbi__context *s)\n{\n   int res = 0;\n   int sz, tga_color_type;\n   stbi__get8(s);      //   discard Offset\n   tga_color_type = stbi__get8(s);   //   color type\n   if ( tga_color_type > 1 ) goto errorEnd;   //   only RGB or indexed allowed\n   sz = stbi__get8(s);   //   image type\n   if ( tga_color_type == 1 ) { // colormapped (paletted) image\n      if (sz != 1 && sz != 9) goto errorEnd; // colortype 1 demands image type 1 or 9\n      stbi__skip(s,4);       // skip index of first colormap entry and number of entries\n      sz = stbi__get8(s);    //   check bits per palette color entry\n      if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd;\n      stbi__skip(s,4);       // skip image x and y origin\n   } else { // \"normal\" image w/o colormap\n      if ( (sz != 2) && (sz != 3) && (sz != 10) && (sz != 11) ) goto errorEnd; // only RGB or grey allowed, +/- RLE\n      stbi__skip(s,9); // skip colormap specification and image x/y origin\n   }\n   if ( stbi__get16le(s) < 1 ) goto errorEnd;      //   test width\n   if ( stbi__get16le(s) < 1 ) goto errorEnd;      //   test height\n   sz = stbi__get8(s);   //   bits per pixel\n   if ( (tga_color_type == 1) && (sz != 8) && (sz != 16) ) goto errorEnd; // for colormapped images, bpp is size of an index\n   if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd;\n\n   res = 1; // if we got this far, everything's good and we can return 1 instead of 0\n\nerrorEnd:\n   stbi__rewind(s);\n   return res;\n}\n\n// read 16bit value and convert to 24bit RGB\nstatic void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out)\n{\n   stbi__uint16 px = (stbi__uint16)stbi__get16le(s);\n   stbi__uint16 fiveBitMask = 31;\n   // we have 3 channels with 5bits each\n   int r = (px >> 10) & fiveBitMask;\n   int g = (px >> 5) & fiveBitMask;\n   int b = px & fiveBitMask;\n   // Note that this saves the data in RGB(A) order, so it doesn't need to be swapped later\n   out[0] = (stbi_uc)((r * 255)/31);\n   out[1] = (stbi_uc)((g * 255)/31);\n   out[2] = (stbi_uc)((b * 255)/31);\n\n   // some people claim that the most significant bit might be used for alpha\n   // (possibly if an alpha-bit is set in the \"image descriptor byte\")\n   // but that only made 16bit test images completely translucent..\n   // so let's treat all 15 and 16bit TGAs as RGB with no alpha.\n}\n\nstatic void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)\n{\n   //   read in the TGA header stuff\n   int tga_offset = stbi__get8(s);\n   int tga_indexed = stbi__get8(s);\n   int tga_image_type = stbi__get8(s);\n   int tga_is_RLE = 0;\n   int tga_palette_start = stbi__get16le(s);\n   int tga_palette_len = stbi__get16le(s);\n   int tga_palette_bits = stbi__get8(s);\n   int tga_x_origin = stbi__get16le(s);\n   int tga_y_origin = stbi__get16le(s);\n   int tga_width = stbi__get16le(s);\n   int tga_height = stbi__get16le(s);\n   int tga_bits_per_pixel = stbi__get8(s);\n   int tga_comp, tga_rgb16=0;\n   int tga_inverted = stbi__get8(s);\n   // int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits - unused (useless?)\n   //   image data\n   unsigned char *tga_data;\n   unsigned char *tga_palette = NULL;\n   int i, j;\n   unsigned char raw_data[4] = {0};\n   int RLE_count = 0;\n   int RLE_repeating = 0;\n   int read_next_pixel = 1;\n   STBI_NOTUSED(ri);\n\n   //   do a tiny bit of precessing\n   if ( tga_image_type >= 8 )\n   {\n      tga_image_type -= 8;\n      tga_is_RLE = 1;\n   }\n   tga_inverted = 1 - ((tga_inverted >> 5) & 1);\n\n   //   If I'm paletted, then I'll use the number of bits from the palette\n   if ( tga_indexed ) tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16);\n   else tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3), &tga_rgb16);\n\n   if(!tga_comp) // shouldn't really happen, stbi__tga_test() should have ensured basic consistency\n      return stbi__errpuc(\"bad format\", \"Can't find out TGA pixelformat\");\n\n   //   tga info\n   *x = tga_width;\n   *y = tga_height;\n   if (comp) *comp = tga_comp;\n\n   if (!stbi__mad3sizes_valid(tga_width, tga_height, tga_comp, 0))\n      return stbi__errpuc(\"too large\", \"Corrupt TGA\");\n\n   tga_data = (unsigned char*)stbi__malloc_mad3(tga_width, tga_height, tga_comp, 0);\n   if (!tga_data) return stbi__errpuc(\"outofmem\", \"Out of memory\");\n\n   // skip to the data's starting position (offset usually = 0)\n   stbi__skip(s, tga_offset );\n\n   if ( !tga_indexed && !tga_is_RLE && !tga_rgb16 ) {\n      for (i=0; i < tga_height; ++i) {\n         int row = tga_inverted ? tga_height -i - 1 : i;\n         stbi_uc *tga_row = tga_data + row*tga_width*tga_comp;\n         stbi__getn(s, tga_row, tga_width * tga_comp);\n      }\n   } else  {\n      //   do I need to load a palette?\n      if ( tga_indexed)\n      {\n         //   any data to skip? (offset usually = 0)\n         stbi__skip(s, tga_palette_start );\n         //   load the palette\n         tga_palette = (unsigned char*)stbi__malloc_mad2(tga_palette_len, tga_comp, 0);\n         if (!tga_palette) {\n            STBI_FREE(tga_data);\n            return stbi__errpuc(\"outofmem\", \"Out of memory\");\n         }\n         if (tga_rgb16) {\n            stbi_uc *pal_entry = tga_palette;\n            STBI_ASSERT(tga_comp == STBI_rgb);\n            for (i=0; i < tga_palette_len; ++i) {\n               stbi__tga_read_rgb16(s, pal_entry);\n               pal_entry += tga_comp;\n            }\n         } else if (!stbi__getn(s, tga_palette, tga_palette_len * tga_comp)) {\n               STBI_FREE(tga_data);\n               STBI_FREE(tga_palette);\n               return stbi__errpuc(\"bad palette\", \"Corrupt TGA\");\n         }\n      }\n      //   load the data\n      for (i=0; i < tga_width * tga_height; ++i)\n      {\n         //   if I'm in RLE mode, do I need to get a RLE stbi__pngchunk?\n         if ( tga_is_RLE )\n         {\n            if ( RLE_count == 0 )\n            {\n               //   yep, get the next byte as a RLE command\n               int RLE_cmd = stbi__get8(s);\n               RLE_count = 1 + (RLE_cmd & 127);\n               RLE_repeating = RLE_cmd >> 7;\n               read_next_pixel = 1;\n            } else if ( !RLE_repeating )\n            {\n               read_next_pixel = 1;\n            }\n         } else\n         {\n            read_next_pixel = 1;\n         }\n         //   OK, if I need to read a pixel, do it now\n         if ( read_next_pixel )\n         {\n            //   load however much data we did have\n            if ( tga_indexed )\n            {\n               // read in index, then perform the lookup\n               int pal_idx = (tga_bits_per_pixel == 8) ? stbi__get8(s) : stbi__get16le(s);\n               if ( pal_idx >= tga_palette_len ) {\n                  // invalid index\n                  pal_idx = 0;\n               }\n               pal_idx *= tga_comp;\n               for (j = 0; j < tga_comp; ++j) {\n                  raw_data[j] = tga_palette[pal_idx+j];\n               }\n            } else if(tga_rgb16) {\n               STBI_ASSERT(tga_comp == STBI_rgb);\n               stbi__tga_read_rgb16(s, raw_data);\n            } else {\n               //   read in the data raw\n               for (j = 0; j < tga_comp; ++j) {\n                  raw_data[j] = stbi__get8(s);\n               }\n            }\n            //   clear the reading flag for the next pixel\n            read_next_pixel = 0;\n         } // end of reading a pixel\n\n         // copy data\n         for (j = 0; j < tga_comp; ++j)\n           tga_data[i*tga_comp+j] = raw_data[j];\n\n         //   in case we're in RLE mode, keep counting down\n         --RLE_count;\n      }\n      //   do I need to invert the image?\n      if ( tga_inverted )\n      {\n         for (j = 0; j*2 < tga_height; ++j)\n         {\n            int index1 = j * tga_width * tga_comp;\n            int index2 = (tga_height - 1 - j) * tga_width * tga_comp;\n            for (i = tga_width * tga_comp; i > 0; --i)\n            {\n               unsigned char temp = tga_data[index1];\n               tga_data[index1] = tga_data[index2];\n               tga_data[index2] = temp;\n               ++index1;\n               ++index2;\n            }\n         }\n      }\n      //   clear my palette, if I had one\n      if ( tga_palette != NULL )\n      {\n         STBI_FREE( tga_palette );\n      }\n   }\n\n   // swap RGB - if the source data was RGB16, it already is in the right order\n   if (tga_comp >= 3 && !tga_rgb16)\n   {\n      unsigned char* tga_pixel = tga_data;\n      for (i=0; i < tga_width * tga_height; ++i)\n      {\n         unsigned char temp = tga_pixel[0];\n         tga_pixel[0] = tga_pixel[2];\n         tga_pixel[2] = temp;\n         tga_pixel += tga_comp;\n      }\n   }\n\n   // convert to target component count\n   if (req_comp && req_comp != tga_comp)\n      tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height);\n\n   //   the things I do to get rid of an error message, and yet keep\n   //   Microsoft's C compilers happy... [8^(\n   tga_palette_start = tga_palette_len = tga_palette_bits =\n         tga_x_origin = tga_y_origin = 0;\n   //   OK, done\n   return tga_data;\n}\n#endif\n\n// *************************************************************************************************\n// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB\n\n#ifndef STBI_NO_PSD\nstatic int stbi__psd_test(stbi__context *s)\n{\n   int r = (stbi__get32be(s) == 0x38425053);\n   stbi__rewind(s);\n   return r;\n}\n\nstatic int stbi__psd_decode_rle(stbi__context *s, stbi_uc *p, int pixelCount)\n{\n   int count, nleft, len;\n\n   count = 0;\n   while ((nleft = pixelCount - count) > 0) {\n      len = stbi__get8(s);\n      if (len == 128) {\n         // No-op.\n      } else if (len < 128) {\n         // Copy next len+1 bytes literally.\n         len++;\n         if (len > nleft) return 0; // corrupt data\n         count += len;\n         while (len) {\n            *p = stbi__get8(s);\n            p += 4;\n            len--;\n         }\n      } else if (len > 128) {\n         stbi_uc   val;\n         // Next -len+1 bytes in the dest are replicated from next source byte.\n         // (Interpret len as a negative 8-bit int.)\n         len = 257 - len;\n         if (len > nleft) return 0; // corrupt data\n         val = stbi__get8(s);\n         count += len;\n         while (len) {\n            *p = val;\n            p += 4;\n            len--;\n         }\n      }\n   }\n\n   return 1;\n}\n\nstatic void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc)\n{\n   int pixelCount;\n   int channelCount, compression;\n   int channel, i;\n   int bitdepth;\n   int w,h;\n   stbi_uc *out;\n   STBI_NOTUSED(ri);\n\n   // Check identifier\n   if (stbi__get32be(s) != 0x38425053)   // \"8BPS\"\n      return stbi__errpuc(\"not PSD\", \"Corrupt PSD image\");\n\n   // Check file type version.\n   if (stbi__get16be(s) != 1)\n      return stbi__errpuc(\"wrong version\", \"Unsupported version of PSD image\");\n\n   // Skip 6 reserved bytes.\n   stbi__skip(s, 6 );\n\n   // Read the number of channels (R, G, B, A, etc).\n   channelCount = stbi__get16be(s);\n   if (channelCount < 0 || channelCount > 16)\n      return stbi__errpuc(\"wrong channel count\", \"Unsupported number of channels in PSD image\");\n\n   // Read the rows and columns of the image.\n   h = stbi__get32be(s);\n   w = stbi__get32be(s);\n\n   // Make sure the depth is 8 bits.\n   bitdepth = stbi__get16be(s);\n   if (bitdepth != 8 && bitdepth != 16)\n      return stbi__errpuc(\"unsupported bit depth\", \"PSD bit depth is not 8 or 16 bit\");\n\n   // Make sure the color mode is RGB.\n   // Valid options are:\n   //   0: Bitmap\n   //   1: Grayscale\n   //   2: Indexed color\n   //   3: RGB color\n   //   4: CMYK color\n   //   7: Multichannel\n   //   8: Duotone\n   //   9: Lab color\n   if (stbi__get16be(s) != 3)\n      return stbi__errpuc(\"wrong color format\", \"PSD is not in RGB color format\");\n\n   // Skip the Mode Data.  (It's the palette for indexed color; other info for other modes.)\n   stbi__skip(s,stbi__get32be(s) );\n\n   // Skip the image resources.  (resolution, pen tool paths, etc)\n   stbi__skip(s, stbi__get32be(s) );\n\n   // Skip the reserved data.\n   stbi__skip(s, stbi__get32be(s) );\n\n   // Find out if the data is compressed.\n   // Known values:\n   //   0: no compression\n   //   1: RLE compressed\n   compression = stbi__get16be(s);\n   if (compression > 1)\n      return stbi__errpuc(\"bad compression\", \"PSD has an unknown compression format\");\n\n   // Check size\n   if (!stbi__mad3sizes_valid(4, w, h, 0))\n      return stbi__errpuc(\"too large\", \"Corrupt PSD\");\n\n   // Create the destination image.\n\n   if (!compression && bitdepth == 16 && bpc == 16) {\n      out = (stbi_uc *) stbi__malloc_mad3(8, w, h, 0);\n      ri->bits_per_channel = 16;\n   } else\n      out = (stbi_uc *) stbi__malloc(4 * w*h);\n\n   if (!out) return stbi__errpuc(\"outofmem\", \"Out of memory\");\n   pixelCount = w*h;\n\n   // Initialize the data to zero.\n   //memset( out, 0, pixelCount * 4 );\n\n   // Finally, the image data.\n   if (compression) {\n      // RLE as used by .PSD and .TIFF\n      // Loop until you get the number of unpacked bytes you are expecting:\n      //     Read the next source byte into n.\n      //     If n is between 0 and 127 inclusive, copy the next n+1 bytes literally.\n      //     Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times.\n      //     Else if n is 128, noop.\n      // Endloop\n\n      // The RLE-compressed data is preceeded by a 2-byte data count for each row in the data,\n      // which we're going to just skip.\n      stbi__skip(s, h * channelCount * 2 );\n\n      // Read the RLE data by channel.\n      for (channel = 0; channel < 4; channel++) {\n         stbi_uc *p;\n\n         p = out+channel;\n         if (channel >= channelCount) {\n            // Fill this channel with default data.\n            for (i = 0; i < pixelCount; i++, p += 4)\n               *p = (channel == 3 ? 255 : 0);\n         } else {\n            // Read the RLE data.\n            if (!stbi__psd_decode_rle(s, p, pixelCount)) {\n               STBI_FREE(out);\n               return stbi__errpuc(\"corrupt\", \"bad RLE data\");\n            }\n         }\n      }\n\n   } else {\n      // We're at the raw image data.  It's each channel in order (Red, Green, Blue, Alpha, ...)\n      // where each channel consists of an 8-bit (or 16-bit) value for each pixel in the image.\n\n      // Read the data by channel.\n      for (channel = 0; channel < 4; channel++) {\n         if (channel >= channelCount) {\n            // Fill this channel with default data.\n            if (bitdepth == 16 && bpc == 16) {\n               stbi__uint16 *q = ((stbi__uint16 *) out) + channel;\n               stbi__uint16 val = channel == 3 ? 65535 : 0;\n               for (i = 0; i < pixelCount; i++, q += 4)\n                  *q = val;\n            } else {\n               stbi_uc *p = out+channel;\n               stbi_uc val = channel == 3 ? 255 : 0;\n               for (i = 0; i < pixelCount; i++, p += 4)\n                  *p = val;\n            }\n         } else {\n            if (ri->bits_per_channel == 16) {    // output bpc\n               stbi__uint16 *q = ((stbi__uint16 *) out) + channel;\n               for (i = 0; i < pixelCount; i++, q += 4)\n                  *q = (stbi__uint16) stbi__get16be(s);\n            } else {\n               stbi_uc *p = out+channel;\n               if (bitdepth == 16) {  // input bpc\n                  for (i = 0; i < pixelCount; i++, p += 4)\n                     *p = (stbi_uc) (stbi__get16be(s) >> 8);\n               } else {\n                  for (i = 0; i < pixelCount; i++, p += 4)\n                     *p = stbi__get8(s);\n               }\n            }\n         }\n      }\n   }\n\n   // remove weird white matte from PSD\n   if (channelCount >= 4) {\n      if (ri->bits_per_channel == 16) {\n         for (i=0; i < w*h; ++i) {\n            stbi__uint16 *pixel = (stbi__uint16 *) out + 4*i;\n            if (pixel[3] != 0 && pixel[3] != 65535) {\n               float a = pixel[3] / 65535.0f;\n               float ra = 1.0f / a;\n               float inv_a = 65535.0f * (1 - ra);\n               pixel[0] = (stbi__uint16) (pixel[0]*ra + inv_a);\n               pixel[1] = (stbi__uint16) (pixel[1]*ra + inv_a);\n               pixel[2] = (stbi__uint16) (pixel[2]*ra + inv_a);\n            }\n         }\n      } else {\n         for (i=0; i < w*h; ++i) {\n            unsigned char *pixel = out + 4*i;\n            if (pixel[3] != 0 && pixel[3] != 255) {\n               float a = pixel[3] / 255.0f;\n               float ra = 1.0f / a;\n               float inv_a = 255.0f * (1 - ra);\n               pixel[0] = (unsigned char) (pixel[0]*ra + inv_a);\n               pixel[1] = (unsigned char) (pixel[1]*ra + inv_a);\n               pixel[2] = (unsigned char) (pixel[2]*ra + inv_a);\n            }\n         }\n      }\n   }\n\n   // convert to desired output format\n   if (req_comp && req_comp != 4) {\n      if (ri->bits_per_channel == 16)\n         out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, 4, req_comp, w, h);\n      else\n         out = stbi__convert_format(out, 4, req_comp, w, h);\n      if (out == NULL) return out; // stbi__convert_format frees input on failure\n   }\n\n   if (comp) *comp = 4;\n   *y = h;\n   *x = w;\n\n   return out;\n}\n#endif\n\n// *************************************************************************************************\n// Softimage PIC loader\n// by Tom Seddon\n//\n// See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format\n// See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/\n\n#ifndef STBI_NO_PIC\nstatic int stbi__pic_is4(stbi__context *s,const char *str)\n{\n   int i;\n   for (i=0; i<4; ++i)\n      if (stbi__get8(s) != (stbi_uc)str[i])\n         return 0;\n\n   return 1;\n}\n\nstatic int stbi__pic_test_core(stbi__context *s)\n{\n   int i;\n\n   if (!stbi__pic_is4(s,\"\\x53\\x80\\xF6\\x34\"))\n      return 0;\n\n   for(i=0;i<84;++i)\n      stbi__get8(s);\n\n   if (!stbi__pic_is4(s,\"PICT\"))\n      return 0;\n\n   return 1;\n}\n\ntypedef struct\n{\n   stbi_uc size,type,channel;\n} stbi__pic_packet;\n\nstatic stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest)\n{\n   int mask=0x80, i;\n\n   for (i=0; i<4; ++i, mask>>=1) {\n      if (channel & mask) {\n         if (stbi__at_eof(s)) return stbi__errpuc(\"bad file\",\"PIC file too short\");\n         dest[i]=stbi__get8(s);\n      }\n   }\n\n   return dest;\n}\n\nstatic void stbi__copyval(int channel,stbi_uc *dest,const stbi_uc *src)\n{\n   int mask=0x80,i;\n\n   for (i=0;i<4; ++i, mask>>=1)\n      if (channel&mask)\n         dest[i]=src[i];\n}\n\nstatic stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *comp, stbi_uc *result)\n{\n   int act_comp=0,num_packets=0,y,chained;\n   stbi__pic_packet packets[10];\n\n   // this will (should...) cater for even some bizarre stuff like having data\n    // for the same channel in multiple packets.\n   do {\n      stbi__pic_packet *packet;\n\n      if (num_packets==sizeof(packets)/sizeof(packets[0]))\n         return stbi__errpuc(\"bad format\",\"too many packets\");\n\n      packet = &packets[num_packets++];\n\n      chained = stbi__get8(s);\n      packet->size    = stbi__get8(s);\n      packet->type    = stbi__get8(s);\n      packet->channel = stbi__get8(s);\n\n      act_comp |= packet->channel;\n\n      if (stbi__at_eof(s))          return stbi__errpuc(\"bad file\",\"file too short (reading packets)\");\n      if (packet->size != 8)  return stbi__errpuc(\"bad format\",\"packet isn't 8bpp\");\n   } while (chained);\n\n   *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel?\n\n   for(y=0; y<height; ++y) {\n      int packet_idx;\n\n      for(packet_idx=0; packet_idx < num_packets; ++packet_idx) {\n         stbi__pic_packet *packet = &packets[packet_idx];\n         stbi_uc *dest = result+y*width*4;\n\n         switch (packet->type) {\n            default:\n               return stbi__errpuc(\"bad format\",\"packet has bad compression type\");\n\n            case 0: {//uncompressed\n               int x;\n\n               for(x=0;x<width;++x, dest+=4)\n                  if (!stbi__readval(s,packet->channel,dest))\n                     return 0;\n               break;\n            }\n\n            case 1://Pure RLE\n               {\n                  int left=width, i;\n\n                  while (left>0) {\n                     stbi_uc count,value[4];\n\n                     count=stbi__get8(s);\n                     if (stbi__at_eof(s))   return stbi__errpuc(\"bad file\",\"file too short (pure read count)\");\n\n                     if (count > left)\n                        count = (stbi_uc) left;\n\n                     if (!stbi__readval(s,packet->channel,value))  return 0;\n\n                     for(i=0; i<count; ++i,dest+=4)\n                        stbi__copyval(packet->channel,dest,value);\n                     left -= count;\n                  }\n               }\n               break;\n\n            case 2: {//Mixed RLE\n               int left=width;\n               while (left>0) {\n                  int count = stbi__get8(s), i;\n                  if (stbi__at_eof(s))  return stbi__errpuc(\"bad file\",\"file too short (mixed read count)\");\n\n                  if (count >= 128) { // Repeated\n                     stbi_uc value[4];\n\n                     if (count==128)\n                        count = stbi__get16be(s);\n                     else\n                        count -= 127;\n                     if (count > left)\n                        return stbi__errpuc(\"bad file\",\"scanline overrun\");\n\n                     if (!stbi__readval(s,packet->channel,value))\n                        return 0;\n\n                     for(i=0;i<count;++i, dest += 4)\n                        stbi__copyval(packet->channel,dest,value);\n                  } else { // Raw\n                     ++count;\n                     if (count>left) return stbi__errpuc(\"bad file\",\"scanline overrun\");\n\n                     for(i=0;i<count;++i, dest+=4)\n                        if (!stbi__readval(s,packet->channel,dest))\n                           return 0;\n                  }\n                  left-=count;\n               }\n               break;\n            }\n         }\n      }\n   }\n\n   return result;\n}\n\nstatic void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp, stbi__result_info *ri)\n{\n   stbi_uc *result;\n   int i, x,y;\n   STBI_NOTUSED(ri);\n\n   for (i=0; i<92; ++i)\n      stbi__get8(s);\n\n   x = stbi__get16be(s);\n   y = stbi__get16be(s);\n   if (stbi__at_eof(s))  return stbi__errpuc(\"bad file\",\"file too short (pic header)\");\n   if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc(\"too large\", \"PIC image too large to decode\");\n\n   stbi__get32be(s); //skip `ratio'\n   stbi__get16be(s); //skip `fields'\n   stbi__get16be(s); //skip `pad'\n\n   // intermediate buffer is RGBA\n   result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0);\n   memset(result, 0xff, x*y*4);\n\n   if (!stbi__pic_load_core(s,x,y,comp, result)) {\n      STBI_FREE(result);\n      result=0;\n   }\n   *px = x;\n   *py = y;\n   if (req_comp == 0) req_comp = *comp;\n   result=stbi__convert_format(result,4,req_comp,x,y);\n\n   return result;\n}\n\nstatic int stbi__pic_test(stbi__context *s)\n{\n   int r = stbi__pic_test_core(s);\n   stbi__rewind(s);\n   return r;\n}\n#endif\n\n// *************************************************************************************************\n// GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb\n\n#ifndef STBI_NO_GIF\ntypedef struct\n{\n   stbi__int16 prefix;\n   stbi_uc first;\n   stbi_uc suffix;\n} stbi__gif_lzw;\n\ntypedef struct\n{\n   int w,h;\n   stbi_uc *out, *old_out;             // output buffer (always 4 components)\n   int flags, bgindex, ratio, transparent, eflags, delay;\n   stbi_uc  pal[256][4];\n   stbi_uc lpal[256][4];\n   stbi__gif_lzw codes[4096];\n   stbi_uc *color_table;\n   int parse, step;\n   int lflags;\n   int start_x, start_y;\n   int max_x, max_y;\n   int cur_x, cur_y;\n   int line_size;\n} stbi__gif;\n\nstatic int stbi__gif_test_raw(stbi__context *s)\n{\n   int sz;\n   if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0;\n   sz = stbi__get8(s);\n   if (sz != '9' && sz != '7') return 0;\n   if (stbi__get8(s) != 'a') return 0;\n   return 1;\n}\n\nstatic int stbi__gif_test(stbi__context *s)\n{\n   int r = stbi__gif_test_raw(s);\n   stbi__rewind(s);\n   return r;\n}\n\nstatic void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp)\n{\n   int i;\n   for (i=0; i < num_entries; ++i) {\n      pal[i][2] = stbi__get8(s);\n      pal[i][1] = stbi__get8(s);\n      pal[i][0] = stbi__get8(s);\n      pal[i][3] = transp == i ? 0 : 255;\n   }\n}\n\nstatic int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info)\n{\n   stbi_uc version;\n   if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8')\n      return stbi__err(\"not GIF\", \"Corrupt GIF\");\n\n   version = stbi__get8(s);\n   if (version != '7' && version != '9')    return stbi__err(\"not GIF\", \"Corrupt GIF\");\n   if (stbi__get8(s) != 'a')                return stbi__err(\"not GIF\", \"Corrupt GIF\");\n\n   stbi__g_failure_reason = \"\";\n   g->w = stbi__get16le(s);\n   g->h = stbi__get16le(s);\n   g->flags = stbi__get8(s);\n   g->bgindex = stbi__get8(s);\n   g->ratio = stbi__get8(s);\n   g->transparent = -1;\n\n   if (comp != 0) *comp = 4;  // can't actually tell whether it's 3 or 4 until we parse the comments\n\n   if (is_info) return 1;\n\n   if (g->flags & 0x80)\n      stbi__gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1);\n\n   return 1;\n}\n\nstatic int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp)\n{\n   stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif));\n   if (!stbi__gif_header(s, g, comp, 1)) {\n      STBI_FREE(g);\n      stbi__rewind( s );\n      return 0;\n   }\n   if (x) *x = g->w;\n   if (y) *y = g->h;\n   STBI_FREE(g);\n   return 1;\n}\n\nstatic void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code)\n{\n   stbi_uc *p, *c;\n\n   // recurse to decode the prefixes, since the linked-list is backwards,\n   // and working backwards through an interleaved image would be nasty\n   if (g->codes[code].prefix >= 0)\n      stbi__out_gif_code(g, g->codes[code].prefix);\n\n   if (g->cur_y >= g->max_y) return;\n\n   p = &g->out[g->cur_x + g->cur_y];\n   c = &g->color_table[g->codes[code].suffix * 4];\n\n   if (c[3] >= 128) {\n      p[0] = c[2];\n      p[1] = c[1];\n      p[2] = c[0];\n      p[3] = c[3];\n   }\n   g->cur_x += 4;\n\n   if (g->cur_x >= g->max_x) {\n      g->cur_x = g->start_x;\n      g->cur_y += g->step;\n\n      while (g->cur_y >= g->max_y && g->parse > 0) {\n         g->step = (1 << g->parse) * g->line_size;\n         g->cur_y = g->start_y + (g->step >> 1);\n         --g->parse;\n      }\n   }\n}\n\nstatic stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g)\n{\n   stbi_uc lzw_cs;\n   stbi__int32 len, init_code;\n   stbi__uint32 first;\n   stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear;\n   stbi__gif_lzw *p;\n\n   lzw_cs = stbi__get8(s);\n   if (lzw_cs > 12) return NULL;\n   clear = 1 << lzw_cs;\n   first = 1;\n   codesize = lzw_cs + 1;\n   codemask = (1 << codesize) - 1;\n   bits = 0;\n   valid_bits = 0;\n   for (init_code = 0; init_code < clear; init_code++) {\n      g->codes[init_code].prefix = -1;\n      g->codes[init_code].first = (stbi_uc) init_code;\n      g->codes[init_code].suffix = (stbi_uc) init_code;\n   }\n\n   // support no starting clear code\n   avail = clear+2;\n   oldcode = -1;\n\n   len = 0;\n   for(;;) {\n      if (valid_bits < codesize) {\n         if (len == 0) {\n            len = stbi__get8(s); // start new block\n            if (len == 0)\n               return g->out;\n         }\n         --len;\n         bits |= (stbi__int32) stbi__get8(s) << valid_bits;\n         valid_bits += 8;\n      } else {\n         stbi__int32 code = bits & codemask;\n         bits >>= codesize;\n         valid_bits -= codesize;\n         // @OPTIMIZE: is there some way we can accelerate the non-clear path?\n         if (code == clear) {  // clear code\n            codesize = lzw_cs + 1;\n            codemask = (1 << codesize) - 1;\n            avail = clear + 2;\n            oldcode = -1;\n            first = 0;\n         } else if (code == clear + 1) { // end of stream code\n            stbi__skip(s, len);\n            while ((len = stbi__get8(s)) > 0)\n               stbi__skip(s,len);\n            return g->out;\n         } else if (code <= avail) {\n            if (first) return stbi__errpuc(\"no clear code\", \"Corrupt GIF\");\n\n            if (oldcode >= 0) {\n               p = &g->codes[avail++];\n               if (avail > 4096)        return stbi__errpuc(\"too many codes\", \"Corrupt GIF\");\n               p->prefix = (stbi__int16) oldcode;\n               p->first = g->codes[oldcode].first;\n               p->suffix = (code == avail) ? p->first : g->codes[code].first;\n            } else if (code == avail)\n               return stbi__errpuc(\"illegal code in raster\", \"Corrupt GIF\");\n\n            stbi__out_gif_code(g, (stbi__uint16) code);\n\n            if ((avail & codemask) == 0 && avail <= 0x0FFF) {\n               codesize++;\n               codemask = (1 << codesize) - 1;\n            }\n\n            oldcode = code;\n         } else {\n            return stbi__errpuc(\"illegal code in raster\", \"Corrupt GIF\");\n         }\n      }\n   }\n}\n\nstatic void stbi__fill_gif_background(stbi__gif *g, int x0, int y0, int x1, int y1)\n{\n   int x, y;\n   stbi_uc *c = g->pal[g->bgindex];\n   for (y = y0; y < y1; y += 4 * g->w) {\n      for (x = x0; x < x1; x += 4) {\n         stbi_uc *p  = &g->out[y + x];\n         p[0] = c[2];\n         p[1] = c[1];\n         p[2] = c[0];\n         p[3] = 0;\n      }\n   }\n}\n\n// this function is designed to support animated gifs, although stb_image doesn't support it\nstatic stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp)\n{\n   int i;\n   stbi_uc *prev_out = 0;\n\n   if (g->out == 0 && !stbi__gif_header(s, g, comp,0))\n      return 0; // stbi__g_failure_reason set by stbi__gif_header\n\n   if (!stbi__mad3sizes_valid(g->w, g->h, 4, 0))\n      return stbi__errpuc(\"too large\", \"GIF too large\");\n\n   prev_out = g->out;\n   g->out = (stbi_uc *) stbi__malloc_mad3(4, g->w, g->h, 0);\n   if (g->out == 0) return stbi__errpuc(\"outofmem\", \"Out of memory\");\n\n   switch ((g->eflags & 0x1C) >> 2) {\n      case 0: // unspecified (also always used on 1st frame)\n         stbi__fill_gif_background(g, 0, 0, 4 * g->w, 4 * g->w * g->h);\n         break;\n      case 1: // do not dispose\n         if (prev_out) memcpy(g->out, prev_out, 4 * g->w * g->h);\n         g->old_out = prev_out;\n         break;\n      case 2: // dispose to background\n         if (prev_out) memcpy(g->out, prev_out, 4 * g->w * g->h);\n         stbi__fill_gif_background(g, g->start_x, g->start_y, g->max_x, g->max_y);\n         break;\n      case 3: // dispose to previous\n         if (g->old_out) {\n            for (i = g->start_y; i < g->max_y; i += 4 * g->w)\n               memcpy(&g->out[i + g->start_x], &g->old_out[i + g->start_x], g->max_x - g->start_x);\n         }\n         break;\n   }\n\n   for (;;) {\n      switch (stbi__get8(s)) {\n         case 0x2C: /* Image Descriptor */\n         {\n            int prev_trans = -1;\n            stbi__int32 x, y, w, h;\n            stbi_uc *o;\n\n            x = stbi__get16le(s);\n            y = stbi__get16le(s);\n            w = stbi__get16le(s);\n            h = stbi__get16le(s);\n            if (((x + w) > (g->w)) || ((y + h) > (g->h)))\n               return stbi__errpuc(\"bad Image Descriptor\", \"Corrupt GIF\");\n\n            g->line_size = g->w * 4;\n            g->start_x = x * 4;\n            g->start_y = y * g->line_size;\n            g->max_x   = g->start_x + w * 4;\n            g->max_y   = g->start_y + h * g->line_size;\n            g->cur_x   = g->start_x;\n            g->cur_y   = g->start_y;\n\n            g->lflags = stbi__get8(s);\n\n            if (g->lflags & 0x40) {\n               g->step = 8 * g->line_size; // first interlaced spacing\n               g->parse = 3;\n            } else {\n               g->step = g->line_size;\n               g->parse = 0;\n            }\n\n            if (g->lflags & 0x80) {\n               stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1);\n               g->color_table = (stbi_uc *) g->lpal;\n            } else if (g->flags & 0x80) {\n               if (g->transparent >= 0 && (g->eflags & 0x01)) {\n                  prev_trans = g->pal[g->transparent][3];\n                  g->pal[g->transparent][3] = 0;\n               }\n               g->color_table = (stbi_uc *) g->pal;\n            } else\n               return stbi__errpuc(\"missing color table\", \"Corrupt GIF\");\n\n            o = stbi__process_gif_raster(s, g);\n            if (o == NULL) return NULL;\n\n            if (prev_trans != -1)\n               g->pal[g->transparent][3] = (stbi_uc) prev_trans;\n\n            return o;\n         }\n\n         case 0x21: // Comment Extension.\n         {\n            int len;\n            if (stbi__get8(s) == 0xF9) { // Graphic Control Extension.\n               len = stbi__get8(s);\n               if (len == 4) {\n                  g->eflags = stbi__get8(s);\n                  g->delay = stbi__get16le(s);\n                  g->transparent = stbi__get8(s);\n               } else {\n                  stbi__skip(s, len);\n                  break;\n               }\n            }\n            while ((len = stbi__get8(s)) != 0)\n               stbi__skip(s, len);\n            break;\n         }\n\n         case 0x3B: // gif stream termination code\n            return (stbi_uc *) s; // using '1' causes warning on some compilers\n\n         default:\n            return stbi__errpuc(\"unknown code\", \"Corrupt GIF\");\n      }\n   }\n\n   STBI_NOTUSED(req_comp);\n}\n\nstatic void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)\n{\n   stbi_uc *u = 0;\n   stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif));\n   memset(g, 0, sizeof(*g));\n   STBI_NOTUSED(ri);\n\n   u = stbi__gif_load_next(s, g, comp, req_comp);\n   if (u == (stbi_uc *) s) u = 0;  // end of animated gif marker\n   if (u) {\n      *x = g->w;\n      *y = g->h;\n      if (req_comp && req_comp != 4)\n         u = stbi__convert_format(u, 4, req_comp, g->w, g->h);\n   }\n   else if (g->out)\n      STBI_FREE(g->out);\n   STBI_FREE(g);\n   return u;\n}\n\nstatic int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp)\n{\n   return stbi__gif_info_raw(s,x,y,comp);\n}\n#endif\n\n// *************************************************************************************************\n// Radiance RGBE HDR loader\n// originally by Nicolas Schulz\n#ifndef STBI_NO_HDR\nstatic int stbi__hdr_test_core(stbi__context *s, const char *signature)\n{\n   int i;\n   for (i=0; signature[i]; ++i)\n      if (stbi__get8(s) != signature[i])\n          return 0;\n   stbi__rewind(s);\n   return 1;\n}\n\nstatic int stbi__hdr_test(stbi__context* s)\n{\n   int r = stbi__hdr_test_core(s, \"#?RADIANCE\\n\");\n   stbi__rewind(s);\n   if(!r) {\n       r = stbi__hdr_test_core(s, \"#?RGBE\\n\");\n       stbi__rewind(s);\n   }\n   return r;\n}\n\n#define STBI__HDR_BUFLEN  1024\nstatic char *stbi__hdr_gettoken(stbi__context *z, char *buffer)\n{\n   int len=0;\n   char c = '\\0';\n\n   c = (char) stbi__get8(z);\n\n   while (!stbi__at_eof(z) && c != '\\n') {\n      buffer[len++] = c;\n      if (len == STBI__HDR_BUFLEN-1) {\n         // flush to end of line\n         while (!stbi__at_eof(z) && stbi__get8(z) != '\\n')\n            ;\n         break;\n      }\n      c = (char) stbi__get8(z);\n   }\n\n   buffer[len] = 0;\n   return buffer;\n}\n\nstatic void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp)\n{\n   if ( input[3] != 0 ) {\n      float f1;\n      // Exponent\n      f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8));\n      if (req_comp <= 2)\n         output[0] = (input[0] + input[1] + input[2]) * f1 / 3;\n      else {\n         output[0] = input[0] * f1;\n         output[1] = input[1] * f1;\n         output[2] = input[2] * f1;\n      }\n      if (req_comp == 2) output[1] = 1;\n      if (req_comp == 4) output[3] = 1;\n   } else {\n      switch (req_comp) {\n         case 4: output[3] = 1; /* fallthrough */\n         case 3: output[0] = output[1] = output[2] = 0;\n                 break;\n         case 2: output[1] = 1; /* fallthrough */\n         case 1: output[0] = 0;\n                 break;\n      }\n   }\n}\n\nstatic float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)\n{\n   char buffer[STBI__HDR_BUFLEN];\n   char *token;\n   int valid = 0;\n   int width, height;\n   stbi_uc *scanline;\n   float *hdr_data;\n   int len;\n   unsigned char count, value;\n   int i, j, k, c1,c2, z;\n   const char *headerToken;\n   STBI_NOTUSED(ri);\n\n   // Check identifier\n   headerToken = stbi__hdr_gettoken(s,buffer);\n   if (strcmp(headerToken, \"#?RADIANCE\") != 0 && strcmp(headerToken, \"#?RGBE\") != 0)\n      return stbi__errpf(\"not HDR\", \"Corrupt HDR image\");\n\n   // Parse header\n   for(;;) {\n      token = stbi__hdr_gettoken(s,buffer);\n      if (token[0] == 0) break;\n      if (strcmp(token, \"FORMAT=32-bit_rle_rgbe\") == 0) valid = 1;\n   }\n\n   if (!valid)    return stbi__errpf(\"unsupported format\", \"Unsupported HDR format\");\n\n   // Parse width and height\n   // can't use sscanf() if we're not using stdio!\n   token = stbi__hdr_gettoken(s,buffer);\n   if (strncmp(token, \"-Y \", 3))  return stbi__errpf(\"unsupported data layout\", \"Unsupported HDR format\");\n   token += 3;\n   height = (int) strtol(token, &token, 10);\n   while (*token == ' ') ++token;\n   if (strncmp(token, \"+X \", 3))  return stbi__errpf(\"unsupported data layout\", \"Unsupported HDR format\");\n   token += 3;\n   width = (int) strtol(token, NULL, 10);\n\n   *x = width;\n   *y = height;\n\n   if (comp) *comp = 3;\n   if (req_comp == 0) req_comp = 3;\n\n   if (!stbi__mad4sizes_valid(width, height, req_comp, sizeof(float), 0))\n      return stbi__errpf(\"too large\", \"HDR image is too large\");\n\n   // Read data\n   hdr_data = (float *) stbi__malloc_mad4(width, height, req_comp, sizeof(float), 0);\n   if (!hdr_data)\n      return stbi__errpf(\"outofmem\", \"Out of memory\");\n\n   // Load image data\n   // image data is stored as some number of sca\n   if ( width < 8 || width >= 32768) {\n      // Read flat data\n      for (j=0; j < height; ++j) {\n         for (i=0; i < width; ++i) {\n            stbi_uc rgbe[4];\n           main_decode_loop:\n            stbi__getn(s, rgbe, 4);\n            stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp);\n         }\n      }\n   } else {\n      // Read RLE-encoded data\n      scanline = NULL;\n\n      for (j = 0; j < height; ++j) {\n         c1 = stbi__get8(s);\n         c2 = stbi__get8(s);\n         len = stbi__get8(s);\n         if (c1 != 2 || c2 != 2 || (len & 0x80)) {\n            // not run-length encoded, so we have to actually use THIS data as a decoded\n            // pixel (note this can't be a valid pixel--one of RGB must be >= 128)\n            stbi_uc rgbe[4];\n            rgbe[0] = (stbi_uc) c1;\n            rgbe[1] = (stbi_uc) c2;\n            rgbe[2] = (stbi_uc) len;\n            rgbe[3] = (stbi_uc) stbi__get8(s);\n            stbi__hdr_convert(hdr_data, rgbe, req_comp);\n            i = 1;\n            j = 0;\n            STBI_FREE(scanline);\n            goto main_decode_loop; // yes, this makes no sense\n         }\n         len <<= 8;\n         len |= stbi__get8(s);\n         if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf(\"invalid decoded scanline length\", \"corrupt HDR\"); }\n         if (scanline == NULL) {\n            scanline = (stbi_uc *) stbi__malloc_mad2(width, 4, 0);\n            if (!scanline) {\n               STBI_FREE(hdr_data);\n               return stbi__errpf(\"outofmem\", \"Out of memory\");\n            }\n         }\n\n         for (k = 0; k < 4; ++k) {\n            int nleft;\n            i = 0;\n            while ((nleft = width - i) > 0) {\n               count = stbi__get8(s);\n               if (count > 128) {\n                  // Run\n                  value = stbi__get8(s);\n                  count -= 128;\n                  if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf(\"corrupt\", \"bad RLE data in HDR\"); }\n                  for (z = 0; z < count; ++z)\n                     scanline[i++ * 4 + k] = value;\n               } else {\n                  // Dump\n                  if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf(\"corrupt\", \"bad RLE data in HDR\"); }\n                  for (z = 0; z < count; ++z)\n                     scanline[i++ * 4 + k] = stbi__get8(s);\n               }\n            }\n         }\n         for (i=0; i < width; ++i)\n            stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp);\n      }\n      if (scanline)\n         STBI_FREE(scanline);\n   }\n\n   return hdr_data;\n}\n\nstatic int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp)\n{\n   char buffer[STBI__HDR_BUFLEN];\n   char *token;\n   int valid = 0;\n\n   if (stbi__hdr_test(s) == 0) {\n       stbi__rewind( s );\n       return 0;\n   }\n\n   for(;;) {\n      token = stbi__hdr_gettoken(s,buffer);\n      if (token[0] == 0) break;\n      if (strcmp(token, \"FORMAT=32-bit_rle_rgbe\") == 0) valid = 1;\n   }\n\n   if (!valid) {\n       stbi__rewind( s );\n       return 0;\n   }\n   token = stbi__hdr_gettoken(s,buffer);\n   if (strncmp(token, \"-Y \", 3)) {\n       stbi__rewind( s );\n       return 0;\n   }\n   token += 3;\n   *y = (int) strtol(token, &token, 10);\n   while (*token == ' ') ++token;\n   if (strncmp(token, \"+X \", 3)) {\n       stbi__rewind( s );\n       return 0;\n   }\n   token += 3;\n   *x = (int) strtol(token, NULL, 10);\n   *comp = 3;\n   return 1;\n}\n#endif // STBI_NO_HDR\n\n#ifndef STBI_NO_BMP\nstatic int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp)\n{\n   void *p;\n   stbi__bmp_data info;\n\n   info.all_a = 255;   \n   p = stbi__bmp_parse_header(s, &info);\n   stbi__rewind( s );\n   if (p == NULL)\n      return 0;\n   *x = s->img_x;\n   *y = s->img_y;\n   *comp = info.ma ? 4 : 3;\n   return 1;\n}\n#endif\n\n#ifndef STBI_NO_PSD\nstatic int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp)\n{\n   int channelCount;\n   if (stbi__get32be(s) != 0x38425053) {\n       stbi__rewind( s );\n       return 0;\n   }\n   if (stbi__get16be(s) != 1) {\n       stbi__rewind( s );\n       return 0;\n   }\n   stbi__skip(s, 6);\n   channelCount = stbi__get16be(s);\n   if (channelCount < 0 || channelCount > 16) {\n       stbi__rewind( s );\n       return 0;\n   }\n   *y = stbi__get32be(s);\n   *x = stbi__get32be(s);\n   if (stbi__get16be(s) != 8) {\n       stbi__rewind( s );\n       return 0;\n   }\n   if (stbi__get16be(s) != 3) {\n       stbi__rewind( s );\n       return 0;\n   }\n   *comp = 4;\n   return 1;\n}\n#endif\n\n#ifndef STBI_NO_PIC\nstatic int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp)\n{\n   int act_comp=0,num_packets=0,chained;\n   stbi__pic_packet packets[10];\n\n   if (!stbi__pic_is4(s,\"\\x53\\x80\\xF6\\x34\")) {\n      stbi__rewind(s);\n      return 0;\n   }\n\n   stbi__skip(s, 88);\n\n   *x = stbi__get16be(s);\n   *y = stbi__get16be(s);\n   if (stbi__at_eof(s)) {\n      stbi__rewind( s);\n      return 0;\n   }\n   if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) {\n      stbi__rewind( s );\n      return 0;\n   }\n\n   stbi__skip(s, 8);\n\n   do {\n      stbi__pic_packet *packet;\n\n      if (num_packets==sizeof(packets)/sizeof(packets[0]))\n         return 0;\n\n      packet = &packets[num_packets++];\n      chained = stbi__get8(s);\n      packet->size    = stbi__get8(s);\n      packet->type    = stbi__get8(s);\n      packet->channel = stbi__get8(s);\n      act_comp |= packet->channel;\n\n      if (stbi__at_eof(s)) {\n          stbi__rewind( s );\n          return 0;\n      }\n      if (packet->size != 8) {\n          stbi__rewind( s );\n          return 0;\n      }\n   } while (chained);\n\n   *comp = (act_comp & 0x10 ? 4 : 3);\n\n   return 1;\n}\n#endif\n\n// *************************************************************************************************\n// Portable Gray Map and Portable Pixel Map loader\n// by Ken Miller\n//\n// PGM: http://netpbm.sourceforge.net/doc/pgm.html\n// PPM: http://netpbm.sourceforge.net/doc/ppm.html\n//\n// Known limitations:\n//    Does not support comments in the header section\n//    Does not support ASCII image data (formats P2 and P3)\n//    Does not support 16-bit-per-channel\n\n#ifndef STBI_NO_PNM\n\nstatic int      stbi__pnm_test(stbi__context *s)\n{\n   char p, t;\n   p = (char) stbi__get8(s);\n   t = (char) stbi__get8(s);\n   if (p != 'P' || (t != '5' && t != '6')) {\n       stbi__rewind( s );\n       return 0;\n   }\n   return 1;\n}\n\nstatic void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)\n{\n   stbi_uc *out;\n   STBI_NOTUSED(ri);\n\n   if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n))\n      return 0;\n\n   *x = s->img_x;\n   *y = s->img_y;\n   *comp = s->img_n;\n\n   if (!stbi__mad3sizes_valid(s->img_n, s->img_x, s->img_y, 0))\n      return stbi__errpuc(\"too large\", \"PNM too large\");\n\n   out = (stbi_uc *) stbi__malloc_mad3(s->img_n, s->img_x, s->img_y, 0);\n   if (!out) return stbi__errpuc(\"outofmem\", \"Out of memory\");\n   stbi__getn(s, out, s->img_n * s->img_x * s->img_y);\n\n   if (req_comp && req_comp != s->img_n) {\n      out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y);\n      if (out == NULL) return out; // stbi__convert_format frees input on failure\n   }\n   return out;\n}\n\nstatic int      stbi__pnm_isspace(char c)\n{\n   return c == ' ' || c == '\\t' || c == '\\n' || c == '\\v' || c == '\\f' || c == '\\r';\n}\n\nstatic void     stbi__pnm_skip_whitespace(stbi__context *s, char *c)\n{\n   for (;;) {\n      while (!stbi__at_eof(s) && stbi__pnm_isspace(*c))\n         *c = (char) stbi__get8(s);\n\n      if (stbi__at_eof(s) || *c != '#')\n         break;\n\n      while (!stbi__at_eof(s) && *c != '\\n' && *c != '\\r' )\n         *c = (char) stbi__get8(s);\n   }\n}\n\nstatic int      stbi__pnm_isdigit(char c)\n{\n   return c >= '0' && c <= '9';\n}\n\nstatic int      stbi__pnm_getinteger(stbi__context *s, char *c)\n{\n   int value = 0;\n\n   while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) {\n      value = value*10 + (*c - '0');\n      *c = (char) stbi__get8(s);\n   }\n\n   return value;\n}\n\nstatic int      stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp)\n{\n   int maxv;\n   char c, p, t;\n\n   stbi__rewind( s );\n\n   // Get identifier\n   p = (char) stbi__get8(s);\n   t = (char) stbi__get8(s);\n   if (p != 'P' || (t != '5' && t != '6')) {\n       stbi__rewind( s );\n       return 0;\n   }\n\n   *comp = (t == '6') ? 3 : 1;  // '5' is 1-component .pgm; '6' is 3-component .ppm\n\n   c = (char) stbi__get8(s);\n   stbi__pnm_skip_whitespace(s, &c);\n\n   *x = stbi__pnm_getinteger(s, &c); // read width\n   stbi__pnm_skip_whitespace(s, &c);\n\n   *y = stbi__pnm_getinteger(s, &c); // read height\n   stbi__pnm_skip_whitespace(s, &c);\n\n   maxv = stbi__pnm_getinteger(s, &c);  // read max value\n\n   if (maxv > 255)\n      return stbi__err(\"max value > 255\", \"PPM image not 8-bit\");\n   else\n      return 1;\n}\n#endif\n\nstatic int stbi__info_main(stbi__context *s, int *x, int *y, int *comp)\n{\n   #ifndef STBI_NO_JPEG\n   if (stbi__jpeg_info(s, x, y, comp)) return 1;\n   #endif\n\n   #ifndef STBI_NO_PNG\n   if (stbi__png_info(s, x, y, comp))  return 1;\n   #endif\n\n   #ifndef STBI_NO_GIF\n   if (stbi__gif_info(s, x, y, comp))  return 1;\n   #endif\n\n   #ifndef STBI_NO_BMP\n   if (stbi__bmp_info(s, x, y, comp))  return 1;\n   #endif\n\n   #ifndef STBI_NO_PSD\n   if (stbi__psd_info(s, x, y, comp))  return 1;\n   #endif\n\n   #ifndef STBI_NO_PIC\n   if (stbi__pic_info(s, x, y, comp))  return 1;\n   #endif\n\n   #ifndef STBI_NO_PNM\n   if (stbi__pnm_info(s, x, y, comp))  return 1;\n   #endif\n\n   #ifndef STBI_NO_HDR\n   if (stbi__hdr_info(s, x, y, comp))  return 1;\n   #endif\n\n   // test tga last because it's a crappy test!\n   #ifndef STBI_NO_TGA\n   if (stbi__tga_info(s, x, y, comp))\n       return 1;\n   #endif\n   return stbi__err(\"unknown image type\", \"Image not of any known type, or corrupt\");\n}\n\n#ifndef STBI_NO_STDIO\nSTBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp)\n{\n    FILE *f = stbi__fopen(filename, \"rb\");\n    int result;\n    if (!f) return stbi__err(\"can't fopen\", \"Unable to open file\");\n    result = stbi_info_from_file(f, x, y, comp);\n    fclose(f);\n    return result;\n}\n\nSTBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp)\n{\n   int r;\n   stbi__context s;\n   long pos = ftell(f);\n   stbi__start_file(&s, f);\n   r = stbi__info_main(&s,x,y,comp);\n   fseek(f,pos,SEEK_SET);\n   return r;\n}\n#endif // !STBI_NO_STDIO\n\nSTBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp)\n{\n   stbi__context s;\n   stbi__start_mem(&s,buffer,len);\n   return stbi__info_main(&s,x,y,comp);\n}\n\nSTBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp)\n{\n   stbi__context s;\n   stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user);\n   return stbi__info_main(&s,x,y,comp);\n}\n\n#endif // STB_IMAGE_IMPLEMENTATION\n\n/*\n   revision history:\n      2.13  (2016-11-29) add 16-bit API, only supported for PNG right now\n      2.12  (2016-04-02) fix typo in 2.11 PSD fix that caused crashes\n      2.11  (2016-04-02) allocate large structures on the stack\n                         remove white matting for transparent PSD\n                         fix reported channel count for PNG & BMP\n                         re-enable SSE2 in non-gcc 64-bit\n                         support RGB-formatted JPEG\n                         read 16-bit PNGs (only as 8-bit)\n      2.10  (2016-01-22) avoid warning introduced in 2.09 by STBI_REALLOC_SIZED\n      2.09  (2016-01-16) allow comments in PNM files\n                         16-bit-per-pixel TGA (not bit-per-component)\n                         info() for TGA could break due to .hdr handling\n                         info() for BMP to shares code instead of sloppy parse\n                         can use STBI_REALLOC_SIZED if allocator doesn't support realloc\n                         code cleanup\n      2.08  (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA\n      2.07  (2015-09-13) fix compiler warnings\n                         partial animated GIF support\n                         limited 16-bpc PSD support\n                         #ifdef unused functions\n                         bug with < 92 byte PIC,PNM,HDR,TGA\n      2.06  (2015-04-19) fix bug where PSD returns wrong '*comp' value\n      2.05  (2015-04-19) fix bug in progressive JPEG handling, fix warning\n      2.04  (2015-04-15) try to re-enable SIMD on MinGW 64-bit\n      2.03  (2015-04-12) extra corruption checking (mmozeiko)\n                         stbi_set_flip_vertically_on_load (nguillemot)\n                         fix NEON support; fix mingw support\n      2.02  (2015-01-19) fix incorrect assert, fix warning\n      2.01  (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2\n      2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG\n      2.00  (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg)\n                         progressive JPEG (stb)\n                         PGM/PPM support (Ken Miller)\n                         STBI_MALLOC,STBI_REALLOC,STBI_FREE\n                         GIF bugfix -- seemingly never worked\n                         STBI_NO_*, STBI_ONLY_*\n      1.48  (2014-12-14) fix incorrectly-named assert()\n      1.47  (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb)\n                         optimize PNG (ryg)\n                         fix bug in interlaced PNG with user-specified channel count (stb)\n      1.46  (2014-08-26)\n              fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG\n      1.45  (2014-08-16)\n              fix MSVC-ARM internal compiler error by wrapping malloc\n      1.44  (2014-08-07)\n              various warning fixes from Ronny Chevalier\n      1.43  (2014-07-15)\n              fix MSVC-only compiler problem in code changed in 1.42\n      1.42  (2014-07-09)\n              don't define _CRT_SECURE_NO_WARNINGS (affects user code)\n              fixes to stbi__cleanup_jpeg path\n              added STBI_ASSERT to avoid requiring assert.h\n      1.41  (2014-06-25)\n              fix search&replace from 1.36 that messed up comments/error messages\n      1.40  (2014-06-22)\n              fix gcc struct-initialization warning\n      1.39  (2014-06-15)\n              fix to TGA optimization when req_comp != number of components in TGA;\n              fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite)\n              add support for BMP version 5 (more ignored fields)\n      1.38  (2014-06-06)\n              suppress MSVC warnings on integer casts truncating values\n              fix accidental rename of 'skip' field of I/O\n      1.37  (2014-06-04)\n              remove duplicate typedef\n      1.36  (2014-06-03)\n              convert to header file single-file library\n              if de-iphone isn't set, load iphone images color-swapped instead of returning NULL\n      1.35  (2014-05-27)\n              various warnings\n              fix broken STBI_SIMD path\n              fix bug where stbi_load_from_file no longer left file pointer in correct place\n              fix broken non-easy path for 32-bit BMP (possibly never used)\n              TGA optimization by Arseny Kapoulkine\n      1.34  (unknown)\n              use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case\n      1.33  (2011-07-14)\n              make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements\n      1.32  (2011-07-13)\n              support for \"info\" function for all supported filetypes (SpartanJ)\n      1.31  (2011-06-20)\n              a few more leak fixes, bug in PNG handling (SpartanJ)\n      1.30  (2011-06-11)\n              added ability to load files via callbacks to accomidate custom input streams (Ben Wenger)\n              removed deprecated format-specific test/load functions\n              removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway\n              error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha)\n              fix inefficiency in decoding 32-bit BMP (David Woo)\n      1.29  (2010-08-16)\n              various warning fixes from Aurelien Pocheville\n      1.28  (2010-08-01)\n              fix bug in GIF palette transparency (SpartanJ)\n      1.27  (2010-08-01)\n              cast-to-stbi_uc to fix warnings\n      1.26  (2010-07-24)\n              fix bug in file buffering for PNG reported by SpartanJ\n      1.25  (2010-07-17)\n              refix trans_data warning (Won Chun)\n      1.24  (2010-07-12)\n              perf improvements reading from files on platforms with lock-heavy fgetc()\n              minor perf improvements for jpeg\n              deprecated type-specific functions so we'll get feedback if they're needed\n              attempt to fix trans_data warning (Won Chun)\n      1.23    fixed bug in iPhone support\n      1.22  (2010-07-10)\n              removed image *writing* support\n              stbi_info support from Jetro Lauha\n              GIF support from Jean-Marc Lienher\n              iPhone PNG-extensions from James Brown\n              warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva)\n      1.21    fix use of 'stbi_uc' in header (reported by jon blow)\n      1.20    added support for Softimage PIC, by Tom Seddon\n      1.19    bug in interlaced PNG corruption check (found by ryg)\n      1.18  (2008-08-02)\n              fix a threading bug (local mutable static)\n      1.17    support interlaced PNG\n      1.16    major bugfix - stbi__convert_format converted one too many pixels\n      1.15    initialize some fields for thread safety\n      1.14    fix threadsafe conversion bug\n              header-file-only version (#define STBI_HEADER_FILE_ONLY before including)\n      1.13    threadsafe\n      1.12    const qualifiers in the API\n      1.11    Support installable IDCT, colorspace conversion routines\n      1.10    Fixes for 64-bit (don't use \"unsigned long\")\n              optimized upsampling by Fabian \"ryg\" Giesen\n      1.09    Fix format-conversion for PSD code (bad global variables!)\n      1.08    Thatcher Ulrich's PSD code integrated by Nicolas Schulz\n      1.07    attempt to fix C++ warning/errors again\n      1.06    attempt to fix C++ warning/errors again\n      1.05    fix TGA loading to return correct *comp and use good luminance calc\n      1.04    default float alpha is 1, not 255; use 'void *' for stbi_image_free\n      1.03    bugfixes to STBI_NO_STDIO, STBI_NO_HDR\n      1.02    support for (subset of) HDR files, float interface for preferred access to them\n      1.01    fix bug: possible bug in handling right-side up bmps... not sure\n              fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all\n      1.00    interface to zlib that skips zlib header\n      0.99    correct handling of alpha in palette\n      0.98    TGA loader by lonesock; dynamically add loaders (untested)\n      0.97    jpeg errors on too large a file; also catch another malloc failure\n      0.96    fix detection of invalid v value - particleman@mollyrocket forum\n      0.95    during header scan, seek to markers in case of padding\n      0.94    STBI_NO_STDIO to disable stdio usage; rename all #defines the same\n      0.93    handle jpegtran output; verbose errors\n      0.92    read 4,8,16,24,32-bit BMP files of several formats\n      0.91    output 24-bit Windows 3.0 BMP files\n      0.90    fix a few more warnings; bump version number to approach 1.0\n      0.61    bugfixes due to Marc LeBlanc, Christopher Lloyd\n      0.60    fix compiling as c++\n      0.59    fix warnings: merge Dave Moore's -Wall fixes\n      0.58    fix bug: zlib uncompressed mode len/nlen was wrong endian\n      0.57    fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available\n      0.56    fix bug: zlib uncompressed mode len vs. nlen\n      0.55    fix bug: restart_interval not initialized to 0\n      0.54    allow NULL for 'int *comp'\n      0.53    fix bug in png 3->4; speedup png decoding\n      0.52    png handles req_comp=3,4 directly; minor cleanup; jpeg comments\n      0.51    obey req_comp requests, 1-component jpegs return as 1-component,\n              on 'test' only check type, not whether we support this variant\n      0.50  (2006-11-19)\n              first released version\n*/\n\n\n/*\n------------------------------------------------------------------------------\nThis software is available under 2 licenses -- choose whichever you prefer.\n------------------------------------------------------------------------------\nALTERNATIVE A - MIT License\nCopyright (c) 2017 Sean Barrett\nPermission is hereby granted, free of charge, to any person obtaining a copy of \nthis software and associated documentation files (the \"Software\"), to deal in \nthe Software without restriction, including without limitation the rights to \nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies \nof the Software, and to permit persons to whom the Software is furnished to do \nso, subject to the following conditions:\nThe above copyright notice and this permission notice shall be included in all \ncopies or substantial portions of the Software.\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR \nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, \nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE \nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER \nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, \nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE \nSOFTWARE.\n------------------------------------------------------------------------------\nALTERNATIVE B - Public Domain (www.unlicense.org)\nThis is free and unencumbered software released into the public domain.\nAnyone is free to copy, modify, publish, use, compile, sell, or distribute this \nsoftware, either in source code form or as a compiled binary, for any purpose, \ncommercial or non-commercial, and by any means.\nIn jurisdictions that recognize copyright laws, the author or authors of this \nsoftware dedicate any and all copyright interest in the software to the public \ndomain. We make this dedication for the benefit of the public at large and to \nthe detriment of our heirs and successors. We intend this dedication to be an \novert act of relinquishment in perpetuity of all present and future rights to \nthis software under copyright law.\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR \nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, \nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE \nAUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN \nACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION \nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n------------------------------------------------------------------------------\n*/\n"
  },
  {
    "path": "src/engine/renderer/jpeg/tiny_jpeg.h",
    "content": "/**\n * tiny_jpeg.h\n *\n * Tiny JPEG Encoder\n *  - Sergio Gonzalez\n *\n * This is a readable and simple single-header JPEG encoder.\n *\n * Features\n *  - Implements Baseline DCT JPEG compression.\n *  - No dynamic allocations.\n *\n * This library is coded in the spirit of the stb libraries and mostly follows\n * the stb guidelines.\n *\n * It is written in C99. And depends on the C standard library.\n * Works with C++11\n *\n *\n * ==== Thanks ====\n *\n *  AssociationSirius (Bug reports)\n *  Bernard van Gastel (Thread-safe defaults, BSD compilation)\n *\n *\n * ==== License ====\n *\n * This software is in the public domain. Where that dedication is not\n * recognized, you are granted a perpetual, irrevocable license to copy and\n * modify this file as you see fit.\n *\n */\n\n// ============================================================\n// Usage\n// ============================================================\n// Include \"tiny_jpeg.h\" to and use the public interface defined below.\n//\n// You *must* do:\n//\n//      #define TJE_IMPLEMENTATION\n//      #include \"tiny_jpeg.h\"\n//\n// in exactly one of your C files to actually compile the implementation.\n\n\n// Here is an example program that loads a bmp with stb_image and writes it\n// with Tiny JPEG\n\n/*\n\n#define STB_IMAGE_IMPLEMENTATION\n#include \"stb_image.h\"\n\n\n#define TJE_IMPLEMENTATION\n#include \"tiny_jpeg.h\"\n\n\nint main()\n{\n    int width, height, num_components;\n    unsigned char* data = stbi_load(\"in.bmp\", &width, &height, &num_components, 0);\n    if ( !data ) {\n        puts(\"Could not find file\");\n        return EXIT_FAILURE;\n    }\n\n    if ( !tje_encode_to_file(\"out.jpg\", width, height, num_components, data) ) {\n        fprintf(stderr, \"Could not write JPEG\\n\");\n        return EXIT_FAILURE;\n    }\n\n    return EXIT_SUCCESS;\n}\n\n*/\n\n\n\n#ifdef __cplusplus\nextern \"C\"\n{\n#endif\n\n#if defined(__GNUC__) || defined(__clang__)\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wmissing-field-initializers\"  // We use {0}, which will zero-out the struct.\n#pragma GCC diagnostic ignored \"-Wmissing-braces\"\n#pragma GCC diagnostic ignored \"-Wpadded\"\n#endif\n\n// ============================================================\n// Public interface:\n// ============================================================\n\n#ifndef TJE_HEADER_GUARD\n#define TJE_HEADER_GUARD\n\n// - tje_encode_to_file -\n//\n// Usage:\n//  Takes bitmap data and writes a JPEG-encoded image to disk.\n//\n//  PARAMETERS\n//      dest_path:          filename to which we will write. e.g. \"out.jpg\"\n//      width, height:      image size in pixels\n//      num_components:     3 is RGB. 4 is RGBA. Those are the only supported values\n//      src_data:           pointer to the pixel data.\n//\n//  RETURN:\n//      0 on error. 1 on success.\n\nint tje_encode_to_file(const char* dest_path,\n                       const int width,\n                       const int height,\n                       const int num_components,\n                       const unsigned char* src_data);\n\n// - tje_encode_to_file_at_quality -\n//\n// Usage:\n//  Takes bitmap data and writes a JPEG-encoded image to disk.\n//\n//  PARAMETERS\n//      dest_path:          filename to which we will write. e.g. \"out.jpg\"\n//      quality:            3: Highest. Compression varies wildly (between 1/3 and 1/20).\n//                          2: Very good quality. About 1/2 the size of 3.\n//                          1: Noticeable. About 1/6 the size of 3, or 1/3 the size of 2.\n//      width, height:      image size in pixels\n//      num_components:     3 is RGB. 4 is RGBA. Those are the only supported values\n//      src_data:           pointer to the pixel data.\n//\n//  RETURN:\n//      0 on error. 1 on success.\n\nint tje_encode_to_file_at_quality(const char* dest_path,\n                                  const int quality,\n                                  const int width,\n                                  const int height,\n                                  const int num_components,\n                                  const unsigned char* src_data);\n\n// - tje_encode_with_func -\n//\n// Usage\n//  Same as tje_encode_to_file_at_quality, but it takes a callback that knows\n//  how to handle (or ignore) `context`. The callback receives an array `data`\n//  of `size` bytes, which can be written directly to a file. There is no need\n//  to free the data.\n\ntypedef void tje_write_func(void* context, void* data, int size);\n\nint tje_encode_with_func(tje_write_func* func,\n                         void* context,\n                         const int quality,\n                         const int width,\n                         const int height,\n                         const int num_components,\n                         const unsigned char* src_data);\n\n#endif // TJE_HEADER_GUARD\n\n\n\n// Implementation: In exactly one of the source files of your application,\n// define TJE_IMPLEMENTATION and include tiny_jpeg.h\n\n// ============================================================\n// Internal\n// ============================================================\n#ifdef TJE_IMPLEMENTATION\n\n\n#define tjei_min(a, b) ((a) < b) ? (a) : (b);\n#define tjei_max(a, b) ((a) < b) ? (b) : (a);\n\n\n#if defined(_MSC_VER)\n#define TJEI_FORCE_INLINE __forceinline\n// #define TJEI_FORCE_INLINE __declspec(noinline)  // For profiling\n#else\n#define TJEI_FORCE_INLINE static // TODO: equivalent for gcc & clang\n#endif\n\n// Only use zero for debugging and/or inspection.\n#define TJE_USE_FAST_DCT 1\n\n// C std lib\n#include <assert.h>\n#include <inttypes.h>\n#include <math.h>   // floorf, ceilf\n#include <stdio.h>  // FILE, puts\n#include <string.h> // memcpy\n\n\n#define TJEI_BUFFER_SIZE 1024\n\n#ifdef _WIN32\n\n#include <windows.h>\n#ifndef snprintf\n#define snprintf sprintf_s\n#endif\n// Not quite the same but it works for us. If I am not mistaken, it differs\n// only in the return value.\n\n#endif\n\n#ifndef NDEBUG\n\n#ifdef _WIN32\n#define tje_log(msg) OutputDebugStringA(msg)\n#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)\n#define tje_log(msg) puts(msg)\n#else\n#warning \"need a tje_log definition for your platform for debugging purposes (not needed if compiling with NDEBUG)\"\n#endif\n\n#else  // NDEBUG\n#define tje_log(msg)\n#endif  // NDEBUG\n\n\ntypedef struct\n{\n    void*           context;\n    tje_write_func* func;\n} TJEWriteContext;\n\ntypedef struct\n{\n    // Huffman data.\n    uint8_t         ehuffsize[4][257];\n    uint16_t        ehuffcode[4][256];\n    uint8_t const * ht_bits[4];\n    uint8_t const * ht_vals[4];\n\n    // Cuantization tables.\n    uint8_t         qt_luma[64];\n    uint8_t         qt_chroma[64];\n\n    // fwrite by default. User-defined when using tje_encode_with_func.\n    TJEWriteContext write_context;\n\n    // Buffered output. Big performance win when using the usual stdlib implementations.\n    size_t          output_buffer_count;\n    uint8_t         output_buffer[TJEI_BUFFER_SIZE];\n} TJEState;\n\n// ============================================================\n// Table definitions.\n//\n// The spec defines tjei_default reasonably good quantization matrices and huffman\n// specification tables.\n//\n//\n// Instead of hard-coding the final huffman table, we only hard-code the table\n// spec suggested by the specification, and then derive the full table from\n// there.  This is only for didactic purposes but it might be useful if there\n// ever is the case that we need to swap huffman tables from various sources.\n// ============================================================\n\n\n// K.1 - suggested luminance QT\nstatic const uint8_t tjei_default_qt_luma_from_spec[] =\n{\n   16,11,10,16, 24, 40, 51, 61,\n   12,12,14,19, 26, 58, 60, 55,\n   14,13,16,24, 40, 57, 69, 56,\n   14,17,22,29, 51, 87, 80, 62,\n   18,22,37,56, 68,109,103, 77,\n   24,35,55,64, 81,104,113, 92,\n   49,64,78,87,103,121,120,101,\n   72,92,95,98,112,100,103, 99,\n};\n\n// Unused\n#if 0\nstatic const uint8_t tjei_default_qt_chroma_from_spec[] =\n{\n    // K.1 - suggested chrominance QT\n   17,18,24,47,99,99,99,99,\n   18,21,26,66,99,99,99,99,\n   24,26,56,99,99,99,99,99,\n   47,66,99,99,99,99,99,99,\n   99,99,99,99,99,99,99,99,\n   99,99,99,99,99,99,99,99,\n   99,99,99,99,99,99,99,99,\n   99,99,99,99,99,99,99,99,\n};\n#endif\n\nstatic const uint8_t tjei_default_qt_chroma_from_paper[] =\n{\n    // Example QT from JPEG paper\n    16,  12, 14,  14, 18, 24,  49,  72,\n    11,  10, 16,  24, 40, 51,  61,  12,\n    13,  17, 22,  35, 64, 92,  14,  16,\n    22,  37, 55,  78, 95, 19,  24,  29,\n    56,  64, 87,  98, 26, 40,  51,  68,\n    81, 103, 112, 58, 57, 87,  109, 104,\n    121,100, 60,  69, 80, 103, 113, 120,\n    103, 55, 56,  62, 77, 92,  101, 99,\n};\n\n// == Procedure to 'deflate' the huffman tree: JPEG spec, C.2\n\n// Number of 16 bit values for every code length. (K.3.3.1)\nstatic const uint8_t tjei_default_ht_luma_dc_len[16] =\n{\n    0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0\n};\n// values\nstatic const uint8_t tjei_default_ht_luma_dc[12] =\n{\n    0,1,2,3,4,5,6,7,8,9,10,11\n};\n\n// Number of 16 bit values for every code length. (K.3.3.1)\nstatic const uint8_t tjei_default_ht_chroma_dc_len[16] =\n{\n    0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0\n};\n// values\nstatic const uint8_t tjei_default_ht_chroma_dc[12] =\n{\n    0,1,2,3,4,5,6,7,8,9,10,11\n};\n\n// Same as above, but AC coefficients.\nstatic const uint8_t tjei_default_ht_luma_ac_len[16] =\n{\n    0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d\n};\nstatic const uint8_t tjei_default_ht_luma_ac[] =\n{\n    0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,\n    0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0,\n    0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28,\n    0x29, 0x2A, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,\n    0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,\n    0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,\n    0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,\n    0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5,\n    0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1, 0xE2,\n    0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,\n    0xF9, 0xFA\n};\n\nstatic const uint8_t tjei_default_ht_chroma_ac_len[16] =\n{\n    0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77\n};\nstatic const uint8_t tjei_default_ht_chroma_ac[] =\n{\n    0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,\n    0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33, 0x52, 0xF0,\n    0x15, 0x62, 0x72, 0xD1, 0x0A, 0x16, 0x24, 0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26,\n    0x27, 0x28, 0x29, 0x2A, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,\n    0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,\n    0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,\n    0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5,\n    0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3,\n    0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA,\n    0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,\n    0xF9, 0xFA\n};\n\n\n// ============================================================\n// Code\n// ============================================================\n\n// Zig-zag order:\nstatic const uint8_t tjei_zig_zag[64] =\n{\n    0,   1,  5,  6, 14, 15, 27, 28,\n    2,   4,  7, 13, 16, 26, 29, 42,\n    3,   8, 12, 17, 25, 30, 41, 43,\n    9,  11, 18, 24, 31, 40, 44, 53,\n    10, 19, 23, 32, 39, 45, 52, 54,\n    20, 22, 33, 38, 46, 51, 55, 60,\n    21, 34, 37, 47, 50, 56, 59, 61,\n    35, 36, 48, 49, 57, 58, 62, 63,\n};\n\n// Memory order as big endian. 0xhilo -> 0xlohi which looks as 0xhilo in memory.\nstatic uint16_t tjei_be_word(const uint16_t le_word)\n{\n    uint16_t lo = (le_word & 0x00ff);\n    uint16_t hi = ((le_word & 0xff00) >> 8);\n    return (uint16_t)((lo << 8) | hi);\n}\n\n// ============================================================\n// The following structs exist only for code clarity, debugability, and\n// readability. They are used when writing to disk, but it is useful to have\n// 1-packed-structs to document how the format works, and to inspect memory\n// while developing.\n// ============================================================\n\nstatic const uint8_t tjeik_jfif_id[] = \"JFIF\";\nstatic const uint8_t tjeik_com_str[] = \"Created by Tiny JPEG Encoder\";\n\n// TODO: Get rid of packed structs!\n#pragma pack(push)\n#pragma pack(1)\ntypedef struct\n{\n    uint16_t SOI;\n    // JFIF header.\n    uint16_t APP0;\n    uint16_t jfif_len;\n    uint8_t  jfif_id[5];\n    uint16_t version;\n    uint8_t  units;\n    uint16_t x_density;\n    uint16_t y_density;\n    uint8_t  x_thumb;\n    uint8_t  y_thumb;\n} TJEJPEGHeader;\n\ntypedef struct\n{\n    uint16_t com;\n    uint16_t com_len;\n    char     com_str[sizeof(tjeik_com_str) - 1];\n} TJEJPEGComment;\n\n// Helper struct for TJEFrameHeader (below).\ntypedef struct\n{\n    uint8_t  component_id;\n    uint8_t  sampling_factors;    // most significant 4 bits: horizontal. 4 LSB: vertical (A.1.1)\n    uint8_t  qt;                  // Quantization table selector.\n} TJEComponentSpec;\n\ntypedef struct\n{\n    uint16_t         SOF;\n    uint16_t         len;                   // 8 + 3 * frame.num_components\n    uint8_t          precision;             // Sample precision (bits per sample).\n    uint16_t         height;\n    uint16_t         width;\n    uint8_t          num_components;        // For this implementation, will be equal to 3.\n    TJEComponentSpec component_spec[3];\n} TJEFrameHeader;\n\ntypedef struct\n{\n    uint8_t component_id;                 // Just as with TJEComponentSpec\n    uint8_t dc_ac;                        // (dc|ac)\n} TJEFrameComponentSpec;\n\ntypedef struct\n{\n    uint16_t              SOS;\n    uint16_t              len;\n    uint8_t               num_components;  // 3.\n    TJEFrameComponentSpec component_spec[3];\n    uint8_t               first;  // 0\n    uint8_t               last;  // 63\n    uint8_t               ah_al;  // o\n} TJEScanHeader;\n#pragma pack(pop)\n\n\nstatic void tjei_write(TJEState* state, const void* data, size_t num_bytes, size_t num_elements)\n{\n    size_t to_write = num_bytes * num_elements;\n\n    // Cap to the buffer available size and copy memory.\n    size_t capped_count = tjei_min(to_write, TJEI_BUFFER_SIZE - 1 - state->output_buffer_count);\n\n    memcpy(state->output_buffer + state->output_buffer_count, data, capped_count);\n    state->output_buffer_count += capped_count;\n\n    assert (state->output_buffer_count <= TJEI_BUFFER_SIZE - 1);\n\n    // Flush the buffer.\n    if ( state->output_buffer_count == TJEI_BUFFER_SIZE - 1 ) {\n        state->write_context.func(state->write_context.context, state->output_buffer, (int)state->output_buffer_count);\n        state->output_buffer_count = 0;\n    }\n\n    // Recursively calling ourselves with the rest of the buffer.\n    if (capped_count < to_write) {\n        tjei_write(state, (uint8_t*)data+capped_count, to_write - capped_count, 1);\n    }\n}\n\nstatic void tjei_write_DQT(TJEState* state, const uint8_t* matrix, uint8_t id)\n{\n    uint16_t DQT = tjei_be_word(0xffdb);\n    tjei_write(state, &DQT, sizeof(uint16_t), 1);\n    uint16_t len = tjei_be_word(0x0043); // 2(len) + 1(id) + 64(matrix) = 67 = 0x43\n    tjei_write(state, &len, sizeof(uint16_t), 1);\n    assert(id < 4);\n    uint8_t precision_and_id = id;  // 0x0000 8 bits | 0x00id\n    tjei_write(state, &precision_and_id, sizeof(uint8_t), 1);\n    // Write matrix\n    tjei_write(state, matrix, 64*sizeof(uint8_t), 1);\n}\n\ntypedef enum\n{\n    TJEI_DC = 0,\n    TJEI_AC = 1\n} TJEHuffmanTableClass;\n\nstatic void tjei_write_DHT(TJEState* state,\n                           uint8_t const * matrix_len,\n                           uint8_t const * matrix_val,\n                           TJEHuffmanTableClass ht_class,\n                           uint8_t id)\n{\n    int num_values = 0;\n    for ( int i = 0; i < 16; ++i ) {\n        num_values += matrix_len[i];\n    }\n    assert(num_values <= 0xffff);\n\n    uint16_t DHT = tjei_be_word(0xffc4);\n    // 2(len) + 1(Tc|th) + 16 (num lengths) + ?? (num values)\n    uint16_t len = tjei_be_word(2 + 1 + 16 + (uint16_t)num_values);\n    assert(id < 4);\n    uint8_t tc_th = (uint8_t)((((uint8_t)ht_class) << 4) | id);\n\n    tjei_write(state, &DHT, sizeof(uint16_t), 1);\n    tjei_write(state, &len, sizeof(uint16_t), 1);\n    tjei_write(state, &tc_th, sizeof(uint8_t), 1);\n    tjei_write(state, matrix_len, sizeof(uint8_t), 16);\n    tjei_write(state, matrix_val, sizeof(uint8_t), (size_t)num_values);\n}\n// ============================================================\n//  Huffman deflation code.\n// ============================================================\n\n// Returns all code sizes from the BITS specification (JPEG C.3)\nstatic uint8_t* tjei_huff_get_code_lengths(uint8_t huffsize[/*256*/], uint8_t const * bits)\n{\n    int k = 0;\n    for ( int i = 0; i < 16; ++i ) {\n        for ( int j = 0; j < bits[i]; ++j ) {\n            huffsize[k++] = (uint8_t)(i + 1);\n        }\n        huffsize[k] = 0;\n    }\n    return huffsize;\n}\n\n// Fills out the prefixes for each code.\nstatic uint16_t* tjei_huff_get_codes(uint16_t codes[], uint8_t* huffsize, int64_t count)\n{\n    uint16_t code = 0;\n    int k = 0;\n    uint8_t sz = huffsize[0];\n    for(;;) {\n        do {\n            assert(k < count);\n            codes[k++] = code++;\n        } while (huffsize[k] == sz);\n        if (huffsize[k] == 0) {\n            return codes;\n        }\n        do {\n            code = (uint16_t)(code << 1);\n            ++sz;\n        } while( huffsize[k] != sz );\n    }\n}\n\nstatic void tjei_huff_get_extended(uint8_t* out_ehuffsize,\n                                   uint16_t* out_ehuffcode,\n                                   uint8_t const * huffval,\n                                   uint8_t* huffsize,\n                                   uint16_t* huffcode, int64_t count)\n{\n    int k = 0;\n    do {\n        uint8_t val = huffval[k];\n        out_ehuffcode[val] = huffcode[k];\n        out_ehuffsize[val] = huffsize[k];\n        k++;\n    } while ( k < count );\n}\n// ============================================================\n\n// Returns:\n//  out[1] : number of bits\n//  out[0] : bits\nTJEI_FORCE_INLINE void tjei_calculate_variable_length_int(int value, uint16_t out[2])\n{\n    int abs_val = value;\n    if ( value < 0 ) {\n        abs_val = -abs_val;\n        --value;\n    }\n    out[1] = 1;\n    while( abs_val >>= 1 ) {\n        ++out[1];\n    }\n    out[0] = (uint16_t)(value & ((1 << out[1]) - 1));\n}\n\n// Write bits to file.\nTJEI_FORCE_INLINE void tjei_write_bits(TJEState* state,\n                                       uint32_t* bitbuffer, uint32_t* location,\n                                       uint16_t num_bits, uint16_t bits)\n{\n    //   v-- location\n    //  [                     ]   <-- bit buffer\n    // 32                     0\n    //\n    // This call pushes to the bitbuffer and saves the location. Data is pushed\n    // from most significant to less significant.\n    // When we can write a full byte, we write a byte and shift.\n\n    // Push the stack.\n    uint32_t nloc = *location + num_bits;\n    *bitbuffer |= (uint32_t)(bits << (32 - nloc));\n    *location = nloc;\n    while ( *location >= 8 ) {\n        // Grab the most significant byte.\n        uint8_t c = (uint8_t)((*bitbuffer) >> 24);\n        // Write it to file.\n        tjei_write(state, &c, 1, 1);\n        if ( c == 0xff )  {\n            // Special case: tell JPEG this is not a marker.\n            char z = 0;\n            tjei_write(state, &z, 1, 1);\n        }\n        // Pop the stack.\n        *bitbuffer <<= 8;\n        *location -= 8;\n    }\n}\n\n// DCT implementation by Thomas G. Lane.\n// Obtained through NVIDIA\n//  http://developer.download.nvidia.com/SDK/9.5/Samples/vidimaging_samples.html#gpgpu_dct\n//\n// QUOTE:\n//  This implementation is based on Arai, Agui, and Nakajima's algorithm for\n//  scaled DCT.  Their original paper (Trans. IEICE E-71(11):1095) is in\n//  Japanese, but the algorithm is described in the Pennebaker & Mitchell\n//  JPEG textbook (see REFERENCES section in file README).  The following code\n//  is based directly on figure 4-8 in P&M.\n//\nstatic void tjei_fdct (float * data)\n{\n    float tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;\n    float tmp10, tmp11, tmp12, tmp13;\n    float z1, z2, z3, z4, z5, z11, z13;\n    float *dataptr;\n    int ctr;\n\n    /* Pass 1: process rows. */\n\n    dataptr = data;\n    for ( ctr = 7; ctr >= 0; ctr-- ) {\n        tmp0 = dataptr[0] + dataptr[7];\n        tmp7 = dataptr[0] - dataptr[7];\n        tmp1 = dataptr[1] + dataptr[6];\n        tmp6 = dataptr[1] - dataptr[6];\n        tmp2 = dataptr[2] + dataptr[5];\n        tmp5 = dataptr[2] - dataptr[5];\n        tmp3 = dataptr[3] + dataptr[4];\n        tmp4 = dataptr[3] - dataptr[4];\n\n        /* Even part */\n\n        tmp10 = tmp0 + tmp3;    /* phase 2 */\n        tmp13 = tmp0 - tmp3;\n        tmp11 = tmp1 + tmp2;\n        tmp12 = tmp1 - tmp2;\n\n        dataptr[0] = tmp10 + tmp11; /* phase 3 */\n        dataptr[4] = tmp10 - tmp11;\n\n        z1 = (tmp12 + tmp13) * ((float) 0.707106781); /* c4 */\n        dataptr[2] = tmp13 + z1;    /* phase 5 */\n        dataptr[6] = tmp13 - z1;\n\n        /* Odd part */\n\n        tmp10 = tmp4 + tmp5;    /* phase 2 */\n        tmp11 = tmp5 + tmp6;\n        tmp12 = tmp6 + tmp7;\n\n        /* The rotator is modified from fig 4-8 to avoid extra negations. */\n        z5 = (tmp10 - tmp12) * ((float) 0.382683433); /* c6 */\n        z2 = ((float) 0.541196100) * tmp10 + z5; /* c2-c6 */\n        z4 = ((float) 1.306562965) * tmp12 + z5; /* c2+c6 */\n        z3 = tmp11 * ((float) 0.707106781); /* c4 */\n\n        z11 = tmp7 + z3;        /* phase 5 */\n        z13 = tmp7 - z3;\n\n        dataptr[5] = z13 + z2;  /* phase 6 */\n        dataptr[3] = z13 - z2;\n        dataptr[1] = z11 + z4;\n        dataptr[7] = z11 - z4;\n\n        dataptr += 8;     /* advance pointer to next row */\n    }\n\n    /* Pass 2: process columns. */\n\n    dataptr = data;\n    for ( ctr = 8-1; ctr >= 0; ctr-- ) {\n        tmp0 = dataptr[8*0] + dataptr[8*7];\n        tmp7 = dataptr[8*0] - dataptr[8*7];\n        tmp1 = dataptr[8*1] + dataptr[8*6];\n        tmp6 = dataptr[8*1] - dataptr[8*6];\n        tmp2 = dataptr[8*2] + dataptr[8*5];\n        tmp5 = dataptr[8*2] - dataptr[8*5];\n        tmp3 = dataptr[8*3] + dataptr[8*4];\n        tmp4 = dataptr[8*3] - dataptr[8*4];\n\n        /* Even part */\n\n        tmp10 = tmp0 + tmp3;    /* phase 2 */\n        tmp13 = tmp0 - tmp3;\n        tmp11 = tmp1 + tmp2;\n        tmp12 = tmp1 - tmp2;\n\n        dataptr[8*0] = tmp10 + tmp11; /* phase 3 */\n        dataptr[8*4] = tmp10 - tmp11;\n\n        z1 = (tmp12 + tmp13) * ((float) 0.707106781); /* c4 */\n        dataptr[8*2] = tmp13 + z1; /* phase 5 */\n        dataptr[8*6] = tmp13 - z1;\n\n        /* Odd part */\n\n        tmp10 = tmp4 + tmp5;    /* phase 2 */\n        tmp11 = tmp5 + tmp6;\n        tmp12 = tmp6 + tmp7;\n\n        /* The rotator is modified from fig 4-8 to avoid extra negations. */\n        z5 = (tmp10 - tmp12) * ((float) 0.382683433); /* c6 */\n        z2 = ((float) 0.541196100) * tmp10 + z5; /* c2-c6 */\n        z4 = ((float) 1.306562965) * tmp12 + z5; /* c2+c6 */\n        z3 = tmp11 * ((float) 0.707106781); /* c4 */\n\n        z11 = tmp7 + z3;        /* phase 5 */\n        z13 = tmp7 - z3;\n\n        dataptr[8*5] = z13 + z2; /* phase 6 */\n        dataptr[8*3] = z13 - z2;\n        dataptr[8*1] = z11 + z4;\n        dataptr[8*7] = z11 - z4;\n\n        dataptr++;          /* advance pointer to next column */\n    }\n}\n#if !TJE_USE_FAST_DCT\nstatic float slow_fdct(int u, int v, float* data)\n{\n#define kPI 3.14159265f\n    float res = 0.0f;\n    float cu = (u == 0) ? 0.70710678118654f : 1;\n    float cv = (v == 0) ? 0.70710678118654f : 1;\n    for ( int y = 0; y < 8; ++y ) {\n        for ( int x = 0; x < 8; ++x ) {\n            res += (data[y * 8 + x]) *\n                    cosf(((2.0f * x + 1.0f) * u * kPI) / 16.0f) *\n                    cosf(((2.0f * y + 1.0f) * v * kPI) / 16.0f);\n        }\n    }\n    res *= 0.25f * cu * cv;\n    return res;\n#undef kPI\n}\n#endif\n\n#define ABS(x) ((x) < 0 ? -(x) : (x))\n\nstatic void tjei_encode_and_write_MCU(TJEState* state,\n                                      float* mcu,\n#if TJE_USE_FAST_DCT\n                                      float* qt,  // Pre-processed quantization matrix.\n#else\n                                      uint8_t* qt,\n#endif\n                                      uint8_t* huff_dc_len, uint16_t* huff_dc_code, // Huffman tables\n                                      uint8_t* huff_ac_len, uint16_t* huff_ac_code,\n                                      int* pred,  // Previous DC coefficient\n                                      uint32_t* bitbuffer,  // Bitstack.\n                                      uint32_t* location)\n{\n    int du[64];  // Data unit in zig-zag order\n\n    float dct_mcu[64];\n    memcpy(dct_mcu, mcu, 64 * sizeof(float));\n\n#if TJE_USE_FAST_DCT\n    tjei_fdct(dct_mcu);\n    for ( int i = 0; i < 64; ++i ) {\n        float fval = dct_mcu[i];\n        fval *= qt[i];\n#if 0\n        fval = (fval > 0) ? floorf(fval + 0.5f) : ceilf(fval - 0.5f);\n#else\n        fval = floorf(fval + 1024 + 0.5f);\n        fval -= 1024;\n#endif\n        int val = (int)fval;\n        du[tjei_zig_zag[i]] = val;\n    }\n#else\n    for ( int v = 0; v < 8; ++v ) {\n        for ( int u = 0; u < 8; ++u ) {\n            dct_mcu[v * 8 + u] = slow_fdct(u, v, mcu);\n        }\n    }\n    for ( int i = 0; i < 64; ++i ) {\n        float fval = dct_mcu[i] / (qt[i]);\n        int val = (int)((fval > 0) ? floorf(fval + 0.5f) : ceilf(fval - 0.5f));\n        du[tjei_zig_zag[i]] = val;\n    }\n#endif\n\n    uint16_t vli[2];\n\n    // Encode DC coefficient.\n    int diff = du[0] - *pred;\n    *pred = du[0];\n    if ( diff != 0 ) {\n        tjei_calculate_variable_length_int(diff, vli);\n        // Write number of bits with Huffman coding\n        tjei_write_bits(state, bitbuffer, location, huff_dc_len[vli[1]], huff_dc_code[vli[1]]);\n        // Write the bits.\n        tjei_write_bits(state, bitbuffer, location, vli[1], vli[0]);\n    } else {\n        tjei_write_bits(state, bitbuffer, location, huff_dc_len[0], huff_dc_code[0]);\n    }\n\n    // ==== Encode AC coefficients ====\n\n    int last_non_zero_i = 0;\n    // Find the last non-zero element.\n    for ( int i = 63; i > 0; --i ) {\n        if (du[i] != 0) {\n            last_non_zero_i = i;\n            break;\n        }\n    }\n\n    for ( int i = 1; i <= last_non_zero_i; ++i ) {\n        // If zero, increase count. If >=15, encode (FF,00)\n        int zero_count = 0;\n        while ( du[i] == 0 ) {\n            ++zero_count;\n            ++i;\n            if (zero_count == 16) {\n                // encode (ff,00) == 0xf0\n                tjei_write_bits(state, bitbuffer, location, huff_ac_len[0xf0], huff_ac_code[0xf0]);\n                zero_count = 0;\n            }\n        }\n        tjei_calculate_variable_length_int(du[i], vli);\n\n        assert(zero_count < 0x10);\n        assert(vli[1] <= 10);\n\n        uint16_t sym1 = (uint16_t)((uint16_t)zero_count << 4) | vli[1];\n\n        assert(huff_ac_len[sym1] != 0);\n\n        // Write symbol 1  --- (RUNLENGTH, SIZE)\n        tjei_write_bits(state, bitbuffer, location, huff_ac_len[sym1], huff_ac_code[sym1]);\n        // Write symbol 2  --- (AMPLITUDE)\n        tjei_write_bits(state, bitbuffer, location, vli[1], vli[0]);\n    }\n\n    if (last_non_zero_i != 63) {\n        // write EOB HUFF(00,00)\n        tjei_write_bits(state, bitbuffer, location, huff_ac_len[0], huff_ac_code[0]);\n    }\n    return;\n}\n\nenum {\n    TJEI_LUMA_DC,\n    TJEI_LUMA_AC,\n    TJEI_CHROMA_DC,\n    TJEI_CHROMA_AC,\n};\n\n#if TJE_USE_FAST_DCT\nstruct TJEProcessedQT\n{\n    float chroma[64];\n    float luma[64];\n};\n#endif\n\n// Set up huffman tables in state.\nstatic void tjei_huff_expand(TJEState* state)\n{\n    assert(state);\n\n    state->ht_bits[TJEI_LUMA_DC]   = tjei_default_ht_luma_dc_len;\n    state->ht_bits[TJEI_LUMA_AC]   = tjei_default_ht_luma_ac_len;\n    state->ht_bits[TJEI_CHROMA_DC] = tjei_default_ht_chroma_dc_len;\n    state->ht_bits[TJEI_CHROMA_AC] = tjei_default_ht_chroma_ac_len;\n\n    state->ht_vals[TJEI_LUMA_DC]   = tjei_default_ht_luma_dc;\n    state->ht_vals[TJEI_LUMA_AC]   = tjei_default_ht_luma_ac;\n    state->ht_vals[TJEI_CHROMA_DC] = tjei_default_ht_chroma_dc;\n    state->ht_vals[TJEI_CHROMA_AC] = tjei_default_ht_chroma_ac;\n\n    // How many codes in total for each of LUMA_(DC|AC) and CHROMA_(DC|AC)\n    int32_t spec_tables_len[4] = { 0 };\n\n    for ( int i = 0; i < 4; ++i ) {\n        for ( int k = 0; k < 16; ++k ) {\n            spec_tables_len[i] += state->ht_bits[i][k];\n        }\n    }\n\n    // Fill out the extended tables..\n    uint8_t huffsize[4][257];\n    uint16_t huffcode[4][256];\n    for ( int i = 0; i < 4; ++i ) {\n        assert (256 >= spec_tables_len[i]);\n        tjei_huff_get_code_lengths(huffsize[i], state->ht_bits[i]);\n        tjei_huff_get_codes(huffcode[i], huffsize[i], spec_tables_len[i]);\n    }\n    for ( int i = 0; i < 4; ++i ) {\n        int64_t count = spec_tables_len[i];\n        tjei_huff_get_extended(state->ehuffsize[i],\n                               state->ehuffcode[i],\n                               state->ht_vals[i],\n                               &huffsize[i][0],\n                               &huffcode[i][0], count);\n    }\n}\n\nstatic int tjei_encode_main(TJEState* state,\n                            const unsigned char* src_data,\n                            const int width,\n                            const int height,\n                            const int src_num_components)\n{\n    if (src_num_components != 3 && src_num_components != 4) {\n        return 0;\n    }\n\n    if (width > 0xffff || height > 0xffff) {\n        return 0;\n    }\n\n#if TJE_USE_FAST_DCT\n    struct TJEProcessedQT pqt;\n    // Again, taken from classic japanese implementation.\n    //\n    /* For float AA&N IDCT method, divisors are equal to quantization\n     * coefficients scaled by scalefactor[row]*scalefactor[col], where\n     *   scalefactor[0] = 1\n     *   scalefactor[k] = cos(k*PI/16) * sqrt(2)    for k=1..7\n     * We apply a further scale factor of 8.\n     * What's actually stored is 1/divisor so that the inner loop can\n     * use a multiplication rather than a division.\n     */\n    static const float aan_scales[] = {\n        1.0f, 1.387039845f, 1.306562965f, 1.175875602f,\n        1.0f, 0.785694958f, 0.541196100f, 0.275899379f\n    };\n\n    // build (de)quantization tables\n    for(int y=0; y<8; y++) {\n        for(int x=0; x<8; x++) {\n            int i = y*8 + x;\n            pqt.luma[y*8+x] = 1.0f / (8 * aan_scales[x] * aan_scales[y] * state->qt_luma[tjei_zig_zag[i]]);\n            pqt.chroma[y*8+x] = 1.0f / (8 * aan_scales[x] * aan_scales[y] * state->qt_chroma[tjei_zig_zag[i]]);\n        }\n    }\n#endif\n\n    { // Write header\n        TJEJPEGHeader header;\n        // JFIF header.\n        header.SOI = tjei_be_word(0xffd8);  // Sequential DCT\n        header.APP0 = tjei_be_word(0xffe0);\n\n        uint16_t jfif_len = sizeof(TJEJPEGHeader) - 4 /*SOI & APP0 markers*/;\n        header.jfif_len = tjei_be_word(jfif_len);\n        memcpy(header.jfif_id, (void*)tjeik_jfif_id, 5);\n        header.version = tjei_be_word(0x0102);\n        header.units = 0x01;  // Dots-per-inch\n        header.x_density = tjei_be_word(0x0060);  // 96 DPI\n        header.y_density = tjei_be_word(0x0060);  // 96 DPI\n        header.x_thumb = 0;\n        header.y_thumb = 0;\n        tjei_write(state, &header, sizeof(TJEJPEGHeader), 1);\n    }\n    {  // Write comment\n        TJEJPEGComment com;\n        uint16_t com_len = 2 + sizeof(tjeik_com_str) - 1;\n        // Comment\n        com.com = tjei_be_word(0xfffe);\n        com.com_len = tjei_be_word(com_len);\n        memcpy(com.com_str, (void*)tjeik_com_str, sizeof(tjeik_com_str)-1);\n        tjei_write(state, &com, sizeof(TJEJPEGComment), 1);\n    }\n\n    // Write quantization tables.\n    tjei_write_DQT(state, state->qt_luma, 0x00);\n    tjei_write_DQT(state, state->qt_chroma, 0x01);\n\n    {  // Write the frame marker.\n        TJEFrameHeader header;\n        header.SOF = tjei_be_word(0xffc0);\n        header.len = tjei_be_word(8 + 3 * 3);\n        header.precision = 8;\n        assert(width <= 0xffff);\n        assert(height <= 0xffff);\n        header.width = tjei_be_word((uint16_t)width);\n        header.height = tjei_be_word((uint16_t)height);\n        header.num_components = 3;\n        uint8_t tables[3] = {\n            0,  // Luma component gets luma table (see tjei_write_DQT call above.)\n            1,  // Chroma component gets chroma table\n            1,  // Chroma component gets chroma table\n        };\n        for (int i = 0; i < 3; ++i) {\n            TJEComponentSpec spec;\n            spec.component_id = (uint8_t)(i + 1);  // No particular reason. Just 1, 2, 3.\n            spec.sampling_factors = (uint8_t)0x11;\n            spec.qt = tables[i];\n\n            header.component_spec[i] = spec;\n        }\n        // Write to file.\n        tjei_write(state, &header, sizeof(TJEFrameHeader), 1);\n    }\n\n    tjei_write_DHT(state, state->ht_bits[TJEI_LUMA_DC],   state->ht_vals[TJEI_LUMA_DC], TJEI_DC, 0);\n    tjei_write_DHT(state, state->ht_bits[TJEI_LUMA_AC],   state->ht_vals[TJEI_LUMA_AC], TJEI_AC, 0);\n    tjei_write_DHT(state, state->ht_bits[TJEI_CHROMA_DC], state->ht_vals[TJEI_CHROMA_DC], TJEI_DC, 1);\n    tjei_write_DHT(state, state->ht_bits[TJEI_CHROMA_AC], state->ht_vals[TJEI_CHROMA_AC], TJEI_AC, 1);\n\n    // Write start of scan\n    {\n        TJEScanHeader header;\n        header.SOS = tjei_be_word(0xffda);\n        header.len = tjei_be_word((uint16_t)(6 + (sizeof(TJEFrameComponentSpec) * 3)));\n        header.num_components = 3;\n\n        uint8_t tables[3] = {\n            0x00,\n            0x11,\n            0x11,\n        };\n        for (int i = 0; i < 3; ++i) {\n            TJEFrameComponentSpec cs;\n            // Must be equal to component_id from frame header above.\n            cs.component_id = (uint8_t)(i + 1);\n            cs.dc_ac = (uint8_t)tables[i];\n\n            header.component_spec[i] = cs;\n        }\n        header.first = 0;\n        header.last  = 63;\n        header.ah_al = 0;\n        tjei_write(state, &header, sizeof(TJEScanHeader), 1);\n\n    }\n    // Write compressed data.\n\n    float du_y[64];\n    float du_b[64];\n    float du_r[64];\n\n    // Set diff to 0.\n    int pred_y = 0;\n    int pred_b = 0;\n    int pred_r = 0;\n\n    // Bit stack\n    uint32_t bitbuffer = 0;\n    uint32_t location = 0;\n\n\n    for ( int y = 0; y < height; y += 8 ) {\n        for ( int x = 0; x < width; x += 8 ) {\n            // Block loop: ====\n            for ( int off_y = 0; off_y < 8; ++off_y ) {\n                for ( int off_x = 0; off_x < 8; ++off_x ) {\n                    int block_index = (off_y * 8 + off_x);\n\n                    int src_index = (((y + off_y) * width) + (x + off_x)) * src_num_components;\n\n                    int col = x + off_x;\n                    int row = y + off_y;\n\n                    if(row >= height) {\n                        src_index -= (width * (row - height + 1)) * src_num_components;\n                    }\n                    if(col >= width) {\n                        src_index -= (col - width + 1) * src_num_components;\n                    }\n                    assert(src_index < width * height * src_num_components);\n\n                    uint8_t r = src_data[src_index + 0];\n                    uint8_t g = src_data[src_index + 1];\n                    uint8_t b = src_data[src_index + 2];\n\n                    float luma = 0.299f   * r + 0.587f    * g + 0.114f    * b - 128;\n                    float cb   = -0.1687f * r - 0.3313f   * g + 0.5f      * b;\n                    float cr   = 0.5f     * r - 0.4187f   * g - 0.0813f   * b;\n\n                    du_y[block_index] = luma;\n                    du_b[block_index] = cb;\n                    du_r[block_index] = cr;\n                }\n            }\n\n            tjei_encode_and_write_MCU(state, du_y,\n#if TJE_USE_FAST_DCT\n                                     pqt.luma,\n#else\n                                     state->qt_luma,\n#endif\n                                     state->ehuffsize[TJEI_LUMA_DC], state->ehuffcode[TJEI_LUMA_DC],\n                                     state->ehuffsize[TJEI_LUMA_AC], state->ehuffcode[TJEI_LUMA_AC],\n                                     &pred_y, &bitbuffer, &location);\n            tjei_encode_and_write_MCU(state, du_b,\n#if TJE_USE_FAST_DCT\n                                     pqt.chroma,\n#else\n                                     state->qt_chroma,\n#endif\n                                     state->ehuffsize[TJEI_CHROMA_DC], state->ehuffcode[TJEI_CHROMA_DC],\n                                     state->ehuffsize[TJEI_CHROMA_AC], state->ehuffcode[TJEI_CHROMA_AC],\n                                     &pred_b, &bitbuffer, &location);\n            tjei_encode_and_write_MCU(state, du_r,\n#if TJE_USE_FAST_DCT\n                                     pqt.chroma,\n#else\n                                     state->qt_chroma,\n#endif\n                                     state->ehuffsize[TJEI_CHROMA_DC], state->ehuffcode[TJEI_CHROMA_DC],\n                                     state->ehuffsize[TJEI_CHROMA_AC], state->ehuffcode[TJEI_CHROMA_AC],\n                                     &pred_r, &bitbuffer, &location);\n\n\n        }\n    }\n\n    // Finish the image.\n    { // Flush\n        if (location > 0 && location < 8) {\n            tjei_write_bits(state, &bitbuffer, &location, (uint16_t)(8 - location), 0);\n        }\n    }\n    uint16_t EOI = tjei_be_word(0xffd9);\n    tjei_write(state, &EOI, sizeof(uint16_t), 1);\n\n    if (state->output_buffer_count) {\n        state->write_context.func(state->write_context.context, state->output_buffer, (int)state->output_buffer_count);\n        state->output_buffer_count = 0;\n    }\n\n    return 1;\n}\n\nint tje_encode_to_file(const char* dest_path,\n                       const int width,\n                       const int height,\n                       const int num_components,\n                       const unsigned char* src_data)\n{\n    int res = tje_encode_to_file_at_quality(dest_path, 3, width, height, num_components, src_data);\n    return res;\n}\n\nstatic void tjei_stdlib_func(void* context, void* data, int size)\n{\n    FILE* fd = (FILE*)context;\n    fwrite(data, size, 1, fd);\n}\n\n// Define public interface.\nint tje_encode_to_file_at_quality(const char* dest_path,\n                                  const int quality,\n                                  const int width,\n                                  const int height,\n                                  const int num_components,\n                                  const unsigned char* src_data)\n{\n    FILE* fd = fopen(dest_path, \"wb\");\n    if (!fd) {\n        tje_log(\"Could not open file for writing.\");\n        return 0;\n    }\n\n    int result = tje_encode_with_func(tjei_stdlib_func, fd,\n                                      quality, width, height, num_components, src_data);\n\n    result |= 0 == fclose(fd);\n\n    return result;\n}\n\nint tje_encode_with_func(tje_write_func* func,\n                         void* context,\n                         const int quality,\n                         const int width,\n                         const int height,\n                         const int num_components,\n                         const unsigned char* src_data)\n{\n    if (quality < 1 || quality > 3) {\n        tje_log(\"[ERROR] -- Valid 'quality' values are 1 (lowest), 2, or 3 (highest)\\n\");\n        return 0;\n    }\n\n    TJEState state = { 0 };\n\n    uint8_t qt_factor = 1;\n    switch(quality) {\n    case 3:\n        for ( int i = 0; i < 64; ++i ) {\n            state.qt_luma[i]   = 1;\n            state.qt_chroma[i] = 1;\n        }\n        break;\n    case 2:\n        qt_factor = 10;\n        // don't break. fall through.\n    case 1:\n        for ( int i = 0; i < 64; ++i ) {\n            state.qt_luma[i]   = tjei_default_qt_luma_from_spec[i] / qt_factor;\n            if (state.qt_luma[i] == 0) {\n                state.qt_luma[i] = 1;\n            }\n            state.qt_chroma[i] = tjei_default_qt_chroma_from_paper[i] / qt_factor;\n            if (state.qt_chroma[i] == 0) {\n                state.qt_chroma[i] = 1;\n            }\n        }\n        break;\n    default:\n        assert(!\"invalid code path\");\n        break;\n    }\n\n    TJEWriteContext wc = { 0 };\n\n    wc.context = context;\n    wc.func = func;\n\n    state.write_context = wc;\n\n\n    tjei_huff_expand(&state);\n\n    int result = tjei_encode_main(&state, src_data, width, height, num_components);\n\n    return result;\n}\n// ============================================================\n#endif // TJE_IMPLEMENTATION\n// ============================================================\n//\n#if defined(__GNUC__) || defined(__clang__)\n#pragma GCC diagnostic pop\n#endif\n\n\n#ifdef __cplusplus\n}  // extern C\n#endif\n\n"
  },
  {
    "path": "src/engine/renderer/qgl.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n/*\n** QGL.H\n*/\n\n#ifndef __QGL_H__\n#define __QGL_H__\n\n#if defined( _WIN32 )\n#pragma warning (disable: 4201)\n#pragma warning (disable: 4214)\n#pragma warning (disable: 4514)\n#pragma warning (disable: 4032)\n#pragma warning (disable: 4201)\n#pragma warning (disable: 4214)\n#define NOMINMAX\n#include <windows.h>\n#include <gl/gl.h>\n#endif\n\n/*\n** multitexture extension definitions\n*/\n#define GL_MAX_ACTIVE_TEXTURES_ARB          0x84E2\n\n#define GL_TEXTURE0_ARB                     0x84C0\n#define GL_TEXTURE1_ARB                     0x84C1\n\n/*\n** extension constants\n*/\n\n// S3TC compression constants\n#define GL_RGB4_S3TC\t\t\t\t\t\t0x83A1\n\n// extensions will be function pointers on all platforms\nextern\tvoid ( APIENTRY * qglActiveTextureARB )( GLenum texture );\nextern\tvoid ( APIENTRY * qglClientActiveTextureARB )( GLenum texture );\n\nextern\tvoid ( APIENTRY * qglLockArraysEXT) (GLint, GLint);\nextern\tvoid ( APIENTRY * qglUnlockArraysEXT) (void);\n\n//===========================================================================\nextern  void ( APIENTRY * qglAlphaFunc )(GLenum func, GLclampf ref);\nextern  void ( APIENTRY * qglBegin )(GLenum mode);\nextern  void ( APIENTRY * qglBindTexture )(GLenum target, GLuint texture);\nextern  void ( APIENTRY * qglBlendFunc )(GLenum sfactor, GLenum dfactor);\nextern  void ( APIENTRY * qglClear )(GLbitfield mask);\nextern  void ( APIENTRY * qglClearColor )(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);\nextern  void ( APIENTRY * qglClipPlane )(GLenum plane, const GLdouble *equation);\nextern  void ( APIENTRY * qglColor3f )(GLfloat red, GLfloat green, GLfloat blue);\nextern  void ( APIENTRY * qglColorMask )(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);\nextern  void ( APIENTRY * qglColorPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);\nextern  void ( APIENTRY * qglCullFace )(GLenum mode);\nextern  void ( APIENTRY * qglDeleteTextures )(GLsizei n, const GLuint *textures);\nextern  void ( APIENTRY * qglDepthFunc )(GLenum func);\nextern  void ( APIENTRY * qglDepthMask )(GLboolean flag);\nextern  void ( APIENTRY * qglDepthRange )(GLclampd zNear, GLclampd zFar);\nextern  void ( APIENTRY * qglDisable )(GLenum cap);\nextern  void ( APIENTRY * qglDisableClientState )(GLenum array);\nextern  void ( APIENTRY * qglDrawBuffer )(GLenum mode);\nextern  void ( APIENTRY * qglDrawElements )(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices);\nextern  void ( APIENTRY * qglEnable )(GLenum cap);\nextern  void ( APIENTRY * qglEnableClientState )(GLenum array);\nextern  void ( APIENTRY * qglEnd )(void);\nextern  void ( APIENTRY * qglFinish )(void);\nextern  GLenum ( APIENTRY * qglGetError )(void);\nextern  void ( APIENTRY * qglGetIntegerv )(GLenum pname, GLint *params);\nextern  const GLubyte * ( APIENTRY * qglGetString )(GLenum name);\nextern  void ( APIENTRY * qglLineWidth )(GLfloat width);\nextern  void ( APIENTRY * qglLoadIdentity )(void);\nextern  void ( APIENTRY * qglLoadMatrixf )(const GLfloat *m);\nextern  void ( APIENTRY * qglMatrixMode )(GLenum mode);\nextern  void ( APIENTRY * qglOrtho )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);\nextern  void ( APIENTRY * qglPolygonMode )(GLenum face, GLenum mode);\nextern  void ( APIENTRY * qglPolygonOffset )(GLfloat factor, GLfloat units);\nextern  void ( APIENTRY * qglPopMatrix )(void);\nextern  void ( APIENTRY * qglPushMatrix )(void);\nextern  void ( APIENTRY * qglReadPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels);\nextern  void ( APIENTRY * qglScissor )(GLint x, GLint y, GLsizei width, GLsizei height);\nextern  void ( APIENTRY * qglStencilFunc )(GLenum func, GLint ref, GLuint mask);\nextern  void ( APIENTRY * qglStencilOp )(GLenum fail, GLenum zfail, GLenum zpass);\nextern  void ( APIENTRY * qglTexCoord2f )(GLfloat s, GLfloat t);\nextern  void ( APIENTRY * qglTexCoord2fv )(const GLfloat *v);\nextern  void ( APIENTRY * qglTexCoordPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);\nextern  void ( APIENTRY * qglTexEnvf )(GLenum target, GLenum pname, GLfloat param);\nextern  void ( APIENTRY * qglTexImage2D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);\nextern  void ( APIENTRY * qglTexParameterf )(GLenum target, GLenum pname, GLfloat param);\nextern  void ( APIENTRY * qglTexParameterfv )(GLenum target, GLenum pname, const GLfloat *params);\nextern  void ( APIENTRY * qglTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);\nextern  void ( APIENTRY * qglVertex2f )(GLfloat x, GLfloat y);\nextern  void ( APIENTRY * qglVertex3f )(GLfloat x, GLfloat y, GLfloat z);\nextern  void ( APIENTRY * qglVertex3fv )(const GLfloat *v);\nextern  void ( APIENTRY * qglVertexPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);\nextern  void ( APIENTRY * qglViewport )(GLint x, GLint y, GLsizei width, GLsizei height);\n\n#if defined( _WIN32 )\nextern HGLRC ( WINAPI * qwglCreateContext)(HDC);\nextern BOOL  ( WINAPI * qwglDeleteContext)(HGLRC);\nextern PROC  ( WINAPI * qwglGetProcAddress)(LPCSTR);\nextern BOOL  ( WINAPI * qwglMakeCurrent)(HDC, HGLRC);\nextern BOOL  ( WINAPI * qwglSwapIntervalEXT)( int interval );\n#endif\n\n#endif\n"
  },
  {
    "path": "src/engine/renderer/shaders/apply_gamma.comp",
    "content": "#version 450\n#extension GL_EXT_samplerless_texture_functions : require\n\nlayout(local_size_x = 8, local_size_y = 8) in;\n\nlayout(push_constant) uniform Push_Constants {\n    uvec2 output_size;\n    uint identity_gamma;\n};\nlayout(binding=0) uniform texture2D output_image;\nlayout(binding=1) uniform writeonly image2D swapchain_image;\nlayout(binding=2) buffer Gamma_Buffer {float data[256];} gamma_buffer;\n\nfloat apply_gamma(float c) {\n    int index = clamp(int(c * 256.0), 0, 255);\n    float cc = gamma_buffer.data[index];\n    return cc;\n}\n\nvoid main() {\n    ivec2 loc = ivec2(gl_GlobalInvocationID.xy);\n    if (loc.x < output_size.x && loc.y < output_size.y) {\n        vec4 color = texelFetch(output_image, loc, 0);\n        if (identity_gamma == 0) {\n            color.x = apply_gamma(color.x);\n            color.y = apply_gamma(color.y);\n            color.z = apply_gamma(color.z);\n        }\n        imageStore(swapchain_image, loc, color);\n    }\n}\n"
  },
  {
    "path": "src/engine/renderer/shaders/compile.bat",
    "content": "@echo off\nset \"VSCMD_START_DIR=%CD%\"\ncall \"C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\Common7\\Tools\\VsDevCmd.bat\"\n\nset tools_dir=..\\..\\..\\..\\tools\nset bin2hex=%tools_dir%\\bin2hex.exe\nset bin2hex_cpp=%tools_dir%\\bin2hex.cpp\n\nif not exist %bin2hex% (\n    cl.exe /EHsc /nologo /Fe%tools_dir%\\ /Fo%tools_dir%\\ %bin2hex_cpp%\n)\n\nset PATH=%tools_dir%;%PATH%\n\nfor %%f in (*.vert) do (\n    %VULKAN_SDK%\\Bin\\glslangValidator.exe -V %%f\n    %bin2hex% vert.spv %%~nf_vert_spv > spirv/%%~nf_vert.cpp\n    del vert.spv\n)\n\nfor %%f in (*.frag) do (\n    %VULKAN_SDK%\\Bin\\glslangValidator.exe -V %%f\n    %bin2hex% frag.spv %%~nf_frag_spv > spirv/%%~nf_frag.cpp\n    del frag.spv\n)\n\nfor %%f in (*.comp) do (\n    %VULKAN_SDK%\\Bin\\glslangValidator.exe -V %%f\n    %bin2hex% comp.spv %%~nf_comp_spv > spirv/%%~nf_comp.cpp\n    del comp.spv\n)\n"
  },
  {
    "path": "src/engine/renderer/shaders/compile_hlsl.bat",
    "content": "@echo off\nset \"VSCMD_START_DIR=%CD%\"\ncall \"C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\Common7\\Tools\\VsDevCmd.bat\"\n\nset tools_dir=..\\..\\..\\..\\tools\nset bin2hex=%tools_dir%\\bin2hex.exe\nset bin2hex_cpp=%tools_dir%\\bin2hex.cpp\n\nif not exist %bin2hex% (\n    cl.exe /EHsc /nologo /Fe%tools_dir%\\ /Fo%tools_dir%\\ %bin2hex_cpp%\n)\n\nset PATH=%tools_dir%;%PATH%\n\n@rem single texture VS\nfxc.exe /nologo /T vs_4_0 /E single_texture_vs /Fo shader.bin shaders.hlsl\n%bin2hex% shader.bin single_texture_vs > hlsl_compiled/single_texture_vs.cpp\ndel shader.bin\n\nfxc.exe /nologo /T vs_4_0 /E single_texture_clipping_plane_vs /Fo shader.bin shaders.hlsl\n%bin2hex% shader.bin single_texture_clipping_plane_vs > hlsl_compiled/single_texture_clipping_plane_vs.cpp\ndel shader.bin\n\n@rem multi texture VS\nfxc.exe /nologo /T vs_4_0 /E multi_texture_vs /Fo shader.bin shaders.hlsl\n%bin2hex% shader.bin multi_texture_vs > hlsl_compiled/multi_texture_vs.cpp\ndel shader.bin\n\nfxc.exe /nologo /T vs_4_0 /E multi_texture_clipping_plane_vs /Fo shader.bin shaders.hlsl\n%bin2hex% shader.bin multi_texture_clipping_plane_vs > hlsl_compiled/multi_texture_clipping_plane_vs.cpp\ndel shader.bin\n\n@rem signle texture PS\nfxc.exe /nologo /T ps_4_0 /E single_texture_ps /Fo shader.bin shaders.hlsl\n%bin2hex% shader.bin single_texture_ps > hlsl_compiled/single_texture_ps.cpp\ndel shader.bin\n\nfxc.exe /nologo /T ps_4_0 /E single_texture_ps /Fo shader.bin shaders.hlsl /DALPHA_TEST_GT0\n%bin2hex% shader.bin single_texture_gt0_ps > hlsl_compiled/single_texture_gt0_ps.cpp\ndel shader.bin\n\nfxc.exe /nologo /T ps_4_0 /E single_texture_ps /Fo shader.bin shaders.hlsl /DALPHA_TEST_LT80\n%bin2hex% shader.bin single_texture_lt80_ps > hlsl_compiled/single_texture_lt80_ps.cpp\ndel shader.bin\n\nfxc.exe /nologo /T ps_4_0 /E single_texture_ps /Fo shader.bin shaders.hlsl /DALPHA_TEST_GE80\n%bin2hex% shader.bin single_texture_ge80_ps > hlsl_compiled/single_texture_ge80_ps.cpp\ndel shader.bin\n\n@rem multi texture mul PS\nfxc.exe /nologo /T ps_4_0 /E multi_texture_mul_ps /Fo shader.bin shaders.hlsl\n%bin2hex% shader.bin multi_texture_mul_ps > hlsl_compiled/multi_texture_mul_ps.cpp\ndel shader.bin\n\nfxc.exe /nologo /T ps_4_0 /E multi_texture_mul_ps /Fo shader.bin shaders.hlsl /DALPHA_TEST_GT0\n%bin2hex% shader.bin multi_texture_mul_gt0_ps > hlsl_compiled/multi_texture_mul_gt0_ps.cpp\ndel shader.bin\n\nfxc.exe /nologo /T ps_4_0 /E multi_texture_mul_ps /Fo shader.bin shaders.hlsl /DALPHA_TEST_LT80\n%bin2hex% shader.bin multi_texture_mul_lt80_ps > hlsl_compiled/multi_texture_mul_lt80_ps.cpp\ndel shader.bin\n\nfxc.exe /nologo /T ps_4_0 /E multi_texture_mul_ps /Fo shader.bin shaders.hlsl /DALPHA_TEST_GE80\n%bin2hex% shader.bin multi_texture_mul_ge80_ps > hlsl_compiled/multi_texture_mul_ge80_ps.cpp\ndel shader.bin\n\n@rem multi texture add PS\nfxc.exe /nologo /T ps_4_0 /E multi_texture_add_ps /Fo shader.bin shaders.hlsl\n%bin2hex% shader.bin multi_texture_add_ps > hlsl_compiled/multi_texture_add_ps.cpp\ndel shader.bin\n\nfxc.exe /nologo /T ps_4_0 /E multi_texture_add_ps /Fo shader.bin shaders.hlsl /DALPHA_TEST_GT0\n%bin2hex% shader.bin multi_texture_add_gt0_ps > hlsl_compiled/multi_texture_add_gt0_ps.cpp\ndel shader.bin\n\nfxc.exe /nologo /T ps_4_0 /E multi_texture_add_ps /Fo shader.bin shaders.hlsl /DALPHA_TEST_LT80\n%bin2hex% shader.bin multi_texture_add_lt80_ps > hlsl_compiled/multi_texture_add_lt80_ps.cpp\ndel shader.bin\n\nfxc.exe /nologo /T ps_4_0 /E multi_texture_add_ps /Fo shader.bin shaders.hlsl /DALPHA_TEST_GE80\n%bin2hex% shader.bin multi_texture_add_ge80_ps > hlsl_compiled/multi_texture_add_ge80_ps.cpp\ndel shader.bin\n"
  },
  {
    "path": "src/engine/renderer/shaders/hlsl_compiled/multi_texture_add_ge80_ps.cpp",
    "content": "unsigned char multi_texture_add_ge80_ps[] = {\n\t0x44, 0x58, 0x42, 0x43, 0xAC, 0x4E, 0x52, 0x94, 0x46, 0xAA, 0xBC, 0x34, 0x76, 0x4F, 0x73, 0x0C, \n\t0xB5, 0x77, 0xB0, 0xB1, 0x01, 0x00, 0x00, 0x00, 0xC4, 0x03, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, \n\t0x34, 0x00, 0x00, 0x00, 0x24, 0x01, 0x00, 0x00, 0xB0, 0x01, 0x00, 0x00, 0xE4, 0x01, 0x00, 0x00, \n\t0x48, 0x03, 0x00, 0x00, 0x52, 0x44, 0x45, 0x46, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x04, 0xFF, 0xFF, \n\t0x00, 0x01, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x9C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xA5, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xAE, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0xB7, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x72, 0x30, \n\t0x00, 0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x72, 0x31, 0x00, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, \n\t0x65, 0x30, 0x00, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x31, 0x00, 0x4D, 0x69, 0x63, 0x72, \n\t0x6F, 0x73, 0x6F, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4C, 0x53, 0x4C, 0x20, 0x53, \n\t0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6F, 0x6D, 0x70, 0x69, 0x6C, 0x65, 0x72, 0x20, 0x31, \n\t0x30, 0x2E, 0x31, 0x00, 0x49, 0x53, 0x47, 0x4E, 0x84, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, \n\t0x08, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x0F, 0x0F, 0x00, 0x00, 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x7A, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x0C, 0x0C, 0x00, 0x00, 0x53, 0x56, 0x5F, 0x50, 0x4F, 0x53, 0x49, 0x54, 0x49, 0x4F, 0x4E, 0x00, \n\t0x43, 0x4F, 0x4C, 0x4F, 0x52, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4F, 0x4F, 0x52, 0x44, 0x00, 0xAB, \n\t0x4F, 0x53, 0x47, 0x4E, 0x2C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, \n\t0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x53, 0x56, 0x5F, 0x54, 0x41, 0x52, 0x47, 0x45, \n\t0x54, 0x00, 0xAB, 0xAB, 0x53, 0x48, 0x44, 0x52, 0x5C, 0x01, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, \n\t0x57, 0x00, 0x00, 0x00, 0x5A, 0x00, 0x00, 0x03, 0x00, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x5A, 0x00, 0x00, 0x03, 0x00, 0x60, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x58, 0x18, 0x00, 0x04, \n\t0x00, 0x70, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x58, 0x18, 0x00, 0x04, \n\t0x00, 0x70, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, \n\t0xF2, 0x10, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, 0x32, 0x10, 0x10, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, 0xC2, 0x10, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x65, 0x00, 0x00, 0x03, 0xF2, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x02, \n\t0x02, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x09, 0xF2, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x46, 0x10, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x46, 0x7E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x07, 0x82, 0x00, 0x10, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3A, 0x10, 0x10, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x09, 0xF2, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0xE6, 0x1A, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x46, 0x7E, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x00, 0x60, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x07, 0x82, 0x00, 0x10, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x10, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x07, 0x82, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x3A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, \n\t0x0D, 0x00, 0x04, 0x03, 0x3A, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x09, \n\t0x72, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x12, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x46, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x02, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x36, 0x00, 0x00, 0x05, 0x82, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x10, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x01, 0x53, 0x54, 0x41, 0x54, 0x74, 0x00, 0x00, 0x00, \n\t0x09, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, \n\t0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00\n};\nlong long multi_texture_add_ge80_ps_size = 964;"
  },
  {
    "path": "src/engine/renderer/shaders/hlsl_compiled/multi_texture_add_gt0_ps.cpp",
    "content": "unsigned char multi_texture_add_gt0_ps[] = {\n\t0x44, 0x58, 0x42, 0x43, 0x0D, 0x09, 0x41, 0xC2, 0x6D, 0x93, 0x9E, 0x74, 0xE5, 0xCB, 0x0D, 0x68, \n\t0xCD, 0x2F, 0x32, 0x7B, 0x01, 0x00, 0x00, 0x00, 0xC4, 0x03, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, \n\t0x34, 0x00, 0x00, 0x00, 0x24, 0x01, 0x00, 0x00, 0xB0, 0x01, 0x00, 0x00, 0xE4, 0x01, 0x00, 0x00, \n\t0x48, 0x03, 0x00, 0x00, 0x52, 0x44, 0x45, 0x46, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x04, 0xFF, 0xFF, \n\t0x00, 0x01, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x9C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xA5, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xAE, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0xB7, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x72, 0x30, \n\t0x00, 0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x72, 0x31, 0x00, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, \n\t0x65, 0x30, 0x00, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x31, 0x00, 0x4D, 0x69, 0x63, 0x72, \n\t0x6F, 0x73, 0x6F, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4C, 0x53, 0x4C, 0x20, 0x53, \n\t0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6F, 0x6D, 0x70, 0x69, 0x6C, 0x65, 0x72, 0x20, 0x31, \n\t0x30, 0x2E, 0x31, 0x00, 0x49, 0x53, 0x47, 0x4E, 0x84, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, \n\t0x08, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x0F, 0x0F, 0x00, 0x00, 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x7A, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x0C, 0x0C, 0x00, 0x00, 0x53, 0x56, 0x5F, 0x50, 0x4F, 0x53, 0x49, 0x54, 0x49, 0x4F, 0x4E, 0x00, \n\t0x43, 0x4F, 0x4C, 0x4F, 0x52, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4F, 0x4F, 0x52, 0x44, 0x00, 0xAB, \n\t0x4F, 0x53, 0x47, 0x4E, 0x2C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, \n\t0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x53, 0x56, 0x5F, 0x54, 0x41, 0x52, 0x47, 0x45, \n\t0x54, 0x00, 0xAB, 0xAB, 0x53, 0x48, 0x44, 0x52, 0x5C, 0x01, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, \n\t0x57, 0x00, 0x00, 0x00, 0x5A, 0x00, 0x00, 0x03, 0x00, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x5A, 0x00, 0x00, 0x03, 0x00, 0x60, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x58, 0x18, 0x00, 0x04, \n\t0x00, 0x70, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x58, 0x18, 0x00, 0x04, \n\t0x00, 0x70, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, \n\t0xF2, 0x10, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, 0x32, 0x10, 0x10, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, 0xC2, 0x10, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x65, 0x00, 0x00, 0x03, 0xF2, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x02, \n\t0x02, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x09, 0xF2, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x46, 0x10, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x46, 0x7E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x07, 0x82, 0x00, 0x10, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3A, 0x10, 0x10, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x09, 0xF2, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0xE6, 0x1A, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x46, 0x7E, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x00, 0x60, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x07, 0x82, 0x00, 0x10, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x10, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0x82, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x3A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x0D, 0x00, 0x04, 0x03, 0x3A, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x09, \n\t0x72, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x12, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x46, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x02, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x36, 0x00, 0x00, 0x05, 0x82, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x10, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x01, 0x53, 0x54, 0x41, 0x54, 0x74, 0x00, 0x00, 0x00, \n\t0x09, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, \n\t0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00\n};\nlong long multi_texture_add_gt0_ps_size = 964;"
  },
  {
    "path": "src/engine/renderer/shaders/hlsl_compiled/multi_texture_add_lt80_ps.cpp",
    "content": "unsigned char multi_texture_add_lt80_ps[] = {\n\t0x44, 0x58, 0x42, 0x43, 0x50, 0x45, 0xD8, 0x74, 0x74, 0x33, 0xD0, 0x77, 0x28, 0x3E, 0xBE, 0x82, \n\t0xD6, 0x6E, 0x38, 0x66, 0x01, 0x00, 0x00, 0x00, 0xC4, 0x03, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, \n\t0x34, 0x00, 0x00, 0x00, 0x24, 0x01, 0x00, 0x00, 0xB0, 0x01, 0x00, 0x00, 0xE4, 0x01, 0x00, 0x00, \n\t0x48, 0x03, 0x00, 0x00, 0x52, 0x44, 0x45, 0x46, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x04, 0xFF, 0xFF, \n\t0x00, 0x01, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x9C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xA5, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xAE, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0xB7, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x72, 0x30, \n\t0x00, 0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x72, 0x31, 0x00, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, \n\t0x65, 0x30, 0x00, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x31, 0x00, 0x4D, 0x69, 0x63, 0x72, \n\t0x6F, 0x73, 0x6F, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4C, 0x53, 0x4C, 0x20, 0x53, \n\t0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6F, 0x6D, 0x70, 0x69, 0x6C, 0x65, 0x72, 0x20, 0x31, \n\t0x30, 0x2E, 0x31, 0x00, 0x49, 0x53, 0x47, 0x4E, 0x84, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, \n\t0x08, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x0F, 0x0F, 0x00, 0x00, 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x7A, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x0C, 0x0C, 0x00, 0x00, 0x53, 0x56, 0x5F, 0x50, 0x4F, 0x53, 0x49, 0x54, 0x49, 0x4F, 0x4E, 0x00, \n\t0x43, 0x4F, 0x4C, 0x4F, 0x52, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4F, 0x4F, 0x52, 0x44, 0x00, 0xAB, \n\t0x4F, 0x53, 0x47, 0x4E, 0x2C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, \n\t0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x53, 0x56, 0x5F, 0x54, 0x41, 0x52, 0x47, 0x45, \n\t0x54, 0x00, 0xAB, 0xAB, 0x53, 0x48, 0x44, 0x52, 0x5C, 0x01, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, \n\t0x57, 0x00, 0x00, 0x00, 0x5A, 0x00, 0x00, 0x03, 0x00, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x5A, 0x00, 0x00, 0x03, 0x00, 0x60, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x58, 0x18, 0x00, 0x04, \n\t0x00, 0x70, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x58, 0x18, 0x00, 0x04, \n\t0x00, 0x70, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, \n\t0xF2, 0x10, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, 0x32, 0x10, 0x10, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, 0xC2, 0x10, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x65, 0x00, 0x00, 0x03, 0xF2, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x02, \n\t0x02, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x09, 0xF2, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x46, 0x10, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x46, 0x7E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x07, 0x82, 0x00, 0x10, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3A, 0x10, 0x10, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x09, 0xF2, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0xE6, 0x1A, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x46, 0x7E, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x00, 0x60, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x07, 0x82, 0x00, 0x10, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x10, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x07, 0x82, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x3A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, \n\t0x0D, 0x00, 0x04, 0x03, 0x3A, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x09, \n\t0x72, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x12, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x46, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x02, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x36, 0x00, 0x00, 0x05, 0x82, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x10, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x01, 0x53, 0x54, 0x41, 0x54, 0x74, 0x00, 0x00, 0x00, \n\t0x09, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, \n\t0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00\n};\nlong long multi_texture_add_lt80_ps_size = 964;"
  },
  {
    "path": "src/engine/renderer/shaders/hlsl_compiled/multi_texture_add_ps.cpp",
    "content": "unsigned char multi_texture_add_ps[] = {\n\t0x44, 0x58, 0x42, 0x43, 0x19, 0xA2, 0x34, 0xAB, 0xC2, 0x02, 0x75, 0x6D, 0xC1, 0x92, 0xFF, 0x56, \n\t0xAD, 0xD4, 0xE6, 0x0A, 0x01, 0x00, 0x00, 0x00, 0x88, 0x03, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, \n\t0x34, 0x00, 0x00, 0x00, 0x24, 0x01, 0x00, 0x00, 0xB0, 0x01, 0x00, 0x00, 0xE4, 0x01, 0x00, 0x00, \n\t0x0C, 0x03, 0x00, 0x00, 0x52, 0x44, 0x45, 0x46, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x04, 0xFF, 0xFF, \n\t0x00, 0x01, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x9C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xA5, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xAE, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0xB7, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x72, 0x30, \n\t0x00, 0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x72, 0x31, 0x00, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, \n\t0x65, 0x30, 0x00, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x31, 0x00, 0x4D, 0x69, 0x63, 0x72, \n\t0x6F, 0x73, 0x6F, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4C, 0x53, 0x4C, 0x20, 0x53, \n\t0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6F, 0x6D, 0x70, 0x69, 0x6C, 0x65, 0x72, 0x20, 0x31, \n\t0x30, 0x2E, 0x31, 0x00, 0x49, 0x53, 0x47, 0x4E, 0x84, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, \n\t0x08, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x0F, 0x0F, 0x00, 0x00, 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x7A, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x0C, 0x0C, 0x00, 0x00, 0x53, 0x56, 0x5F, 0x50, 0x4F, 0x53, 0x49, 0x54, 0x49, 0x4F, 0x4E, 0x00, \n\t0x43, 0x4F, 0x4C, 0x4F, 0x52, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4F, 0x4F, 0x52, 0x44, 0x00, 0xAB, \n\t0x4F, 0x53, 0x47, 0x4E, 0x2C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, \n\t0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x53, 0x56, 0x5F, 0x54, 0x41, 0x52, 0x47, 0x45, \n\t0x54, 0x00, 0xAB, 0xAB, 0x53, 0x48, 0x44, 0x52, 0x20, 0x01, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, \n\t0x48, 0x00, 0x00, 0x00, 0x5A, 0x00, 0x00, 0x03, 0x00, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x5A, 0x00, 0x00, 0x03, 0x00, 0x60, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x58, 0x18, 0x00, 0x04, \n\t0x00, 0x70, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x58, 0x18, 0x00, 0x04, \n\t0x00, 0x70, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, \n\t0xF2, 0x10, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, 0x32, 0x10, 0x10, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, 0xC2, 0x10, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x65, 0x00, 0x00, 0x03, 0xF2, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x02, \n\t0x02, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x09, 0xF2, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x46, 0x10, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x46, 0x7E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x07, 0x82, 0x00, 0x10, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3A, 0x10, 0x10, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x09, 0xF2, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0xE6, 0x1A, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x46, 0x7E, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x00, 0x60, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x07, 0x82, 0x20, 0x10, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x10, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x09, 0x72, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x46, 0x12, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x46, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x46, 0x02, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x01, 0x53, 0x54, 0x41, 0x54, \n\t0x74, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\n};\nlong long multi_texture_add_ps_size = 904;"
  },
  {
    "path": "src/engine/renderer/shaders/hlsl_compiled/multi_texture_clipping_plane_vs.cpp",
    "content": "unsigned char multi_texture_clipping_plane_vs[] = {\n\t0x44, 0x58, 0x42, 0x43, 0xF1, 0x59, 0xAC, 0x11, 0xC8, 0x58, 0x63, 0x10, 0x19, 0x87, 0x4B, 0xD7, \n\t0xC4, 0x11, 0x7E, 0xBF, 0x01, 0x00, 0x00, 0x00, 0x3C, 0x05, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, \n\t0x34, 0x00, 0x00, 0x00, 0x70, 0x01, 0x00, 0x00, 0xF8, 0x01, 0x00, 0x00, 0xAC, 0x02, 0x00, 0x00, \n\t0xC0, 0x04, 0x00, 0x00, 0x52, 0x44, 0x45, 0x46, 0x34, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x04, 0xFE, 0xFF, \n\t0x00, 0x01, 0x00, 0x00, 0x0C, 0x01, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x43, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74, \n\t0x73, 0x00, 0xAB, 0xAB, 0x3C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, \n\t0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA8, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xBC, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0xCC, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEC, 0x00, 0x00, 0x00, \n\t0x70, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x63, 0x6C, 0x69, 0x70, 0x5F, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5F, 0x78, \n\t0x66, 0x6F, 0x72, 0x6D, 0x00, 0xAB, 0xAB, 0xAB, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x79, 0x65, 0x5F, 0x73, 0x70, 0x61, 0x63, \n\t0x65, 0x5F, 0x78, 0x66, 0x6F, 0x72, 0x6D, 0x00, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x6C, 0x69, 0x70, 0x70, 0x69, 0x6E, 0x67, \n\t0x5F, 0x70, 0x6C, 0x61, 0x6E, 0x65, 0x00, 0xAB, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66, \n\t0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4C, 0x53, 0x4C, 0x20, 0x53, 0x68, 0x61, 0x64, 0x65, \n\t0x72, 0x20, 0x43, 0x6F, 0x6D, 0x70, 0x69, 0x6C, 0x65, 0x72, 0x20, 0x31, 0x30, 0x2E, 0x31, 0x00, \n\t0x49, 0x53, 0x47, 0x4E, 0x80, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, \n\t0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, \n\t0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, \n\t0x50, 0x4F, 0x53, 0x49, 0x54, 0x49, 0x4F, 0x4E, 0x00, 0x43, 0x4F, 0x4C, 0x4F, 0x52, 0x00, 0x54, \n\t0x45, 0x58, 0x43, 0x4F, 0x4F, 0x52, 0x44, 0x00, 0x4F, 0x53, 0x47, 0x4E, 0xAC, 0x00, 0x00, 0x00, \n\t0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, \n\t0x8C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x0C, 0x00, 0x00, \n\t0x92, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x0C, 0x03, 0x00, 0x00, 0x9B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x0E, 0x00, 0x00, \n\t0x53, 0x56, 0x5F, 0x50, 0x4F, 0x53, 0x49, 0x54, 0x49, 0x4F, 0x4E, 0x00, 0x43, 0x4F, 0x4C, 0x4F, \n\t0x52, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4F, 0x4F, 0x52, 0x44, 0x00, 0x53, 0x56, 0x5F, 0x43, 0x6C, \n\t0x69, 0x70, 0x44, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x00, 0xAB, 0x53, 0x48, 0x44, 0x52, \n\t0x0C, 0x02, 0x00, 0x00, 0x40, 0x00, 0x01, 0x00, 0x83, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x04, \n\t0x46, 0x8E, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x00, 0x03, \n\t0xF2, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x00, 0x03, 0xF2, 0x10, 0x10, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x00, 0x03, 0x32, 0x10, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x5F, 0x00, 0x00, 0x03, 0x32, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x04, \n\t0xF2, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x03, \n\t0xF2, 0x20, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x03, 0x32, 0x20, 0x10, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x03, 0xC2, 0x20, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x67, 0x00, 0x00, 0x04, 0x12, 0x20, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x68, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x08, 0xF2, 0x00, 0x10, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x56, 0x15, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x8E, 0x20, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x0A, 0xF2, 0x00, 0x10, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x46, 0x8E, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x06, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x0E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x32, 0x00, 0x00, 0x0A, 0xF2, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x8E, 0x20, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xA6, 0x1A, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x46, 0x0E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x0A, 0xF2, 0x20, 0x10, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x46, 0x8E, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0xF6, 0x1F, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x0E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x36, 0x00, 0x00, 0x05, 0xF2, 0x20, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x46, 0x1E, 0x10, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x05, 0x32, 0x20, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x46, 0x10, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x05, 0xC2, 0x20, 0x10, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x06, 0x14, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x08, \n\t0x12, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x46, 0x8E, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x08, \n\t0x22, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x46, 0x8E, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x08, \n\t0x42, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x46, 0x8E, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, \n\t0x12, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x82, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x07, 0x00, 0x00, 0x00, 0x46, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, \n\t0x12, 0x20, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x3A, 0x80, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x01, \n\t0x53, 0x54, 0x41, 0x54, 0x74, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\n};\nlong long multi_texture_clipping_plane_vs_size = 1340;"
  },
  {
    "path": "src/engine/renderer/shaders/hlsl_compiled/multi_texture_mul_ge80_ps.cpp",
    "content": "unsigned char multi_texture_mul_ge80_ps[] = {\n\t0x44, 0x58, 0x42, 0x43, 0xB4, 0x1D, 0x86, 0x5A, 0x10, 0x10, 0x46, 0x4B, 0x46, 0xFB, 0xB7, 0x04, \n\t0x73, 0x85, 0xC8, 0xF5, 0x01, 0x00, 0x00, 0x00, 0xA0, 0x03, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, \n\t0x34, 0x00, 0x00, 0x00, 0x24, 0x01, 0x00, 0x00, 0xB0, 0x01, 0x00, 0x00, 0xE4, 0x01, 0x00, 0x00, \n\t0x24, 0x03, 0x00, 0x00, 0x52, 0x44, 0x45, 0x46, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x04, 0xFF, 0xFF, \n\t0x00, 0x01, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x9C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xA5, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xAE, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0xB7, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x72, 0x30, \n\t0x00, 0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x72, 0x31, 0x00, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, \n\t0x65, 0x30, 0x00, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x31, 0x00, 0x4D, 0x69, 0x63, 0x72, \n\t0x6F, 0x73, 0x6F, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4C, 0x53, 0x4C, 0x20, 0x53, \n\t0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6F, 0x6D, 0x70, 0x69, 0x6C, 0x65, 0x72, 0x20, 0x31, \n\t0x30, 0x2E, 0x31, 0x00, 0x49, 0x53, 0x47, 0x4E, 0x84, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, \n\t0x08, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x0F, 0x0F, 0x00, 0x00, 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x7A, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x0C, 0x0C, 0x00, 0x00, 0x53, 0x56, 0x5F, 0x50, 0x4F, 0x53, 0x49, 0x54, 0x49, 0x4F, 0x4E, 0x00, \n\t0x43, 0x4F, 0x4C, 0x4F, 0x52, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4F, 0x4F, 0x52, 0x44, 0x00, 0xAB, \n\t0x4F, 0x53, 0x47, 0x4E, 0x2C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, \n\t0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x53, 0x56, 0x5F, 0x54, 0x41, 0x52, 0x47, 0x45, \n\t0x54, 0x00, 0xAB, 0xAB, 0x53, 0x48, 0x44, 0x52, 0x38, 0x01, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, \n\t0x4E, 0x00, 0x00, 0x00, 0x5A, 0x00, 0x00, 0x03, 0x00, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x5A, 0x00, 0x00, 0x03, 0x00, 0x60, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x58, 0x18, 0x00, 0x04, \n\t0x00, 0x70, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x58, 0x18, 0x00, 0x04, \n\t0x00, 0x70, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, \n\t0xF2, 0x10, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, 0x32, 0x10, 0x10, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, 0xC2, 0x10, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x65, 0x00, 0x00, 0x03, 0xF2, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x02, \n\t0x02, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x09, 0xF2, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x46, 0x10, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x46, 0x7E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x07, 0xF2, 0x00, 0x10, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x46, 0x0E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1E, 0x10, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x09, 0xF2, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0xE6, 0x1A, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x46, 0x7E, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x00, 0x60, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x07, 0xF2, 0x00, 0x10, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x46, 0x0E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x0E, 0x10, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x07, 0x12, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x3A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, \n\t0x0D, 0x00, 0x04, 0x03, 0x0A, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x05, \n\t0xF2, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x0E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x3E, 0x00, 0x00, 0x01, 0x53, 0x54, 0x41, 0x54, 0x74, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\n\t\n};\nlong long multi_texture_mul_ge80_ps_size = 928;"
  },
  {
    "path": "src/engine/renderer/shaders/hlsl_compiled/multi_texture_mul_gt0_ps.cpp",
    "content": "unsigned char multi_texture_mul_gt0_ps[] = {\n\t0x44, 0x58, 0x42, 0x43, 0x26, 0x5B, 0x38, 0x4E, 0xB1, 0x89, 0x0B, 0x4A, 0x5F, 0x1D, 0x8F, 0x1F, \n\t0x8E, 0xD9, 0x81, 0x22, 0x01, 0x00, 0x00, 0x00, 0xA0, 0x03, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, \n\t0x34, 0x00, 0x00, 0x00, 0x24, 0x01, 0x00, 0x00, 0xB0, 0x01, 0x00, 0x00, 0xE4, 0x01, 0x00, 0x00, \n\t0x24, 0x03, 0x00, 0x00, 0x52, 0x44, 0x45, 0x46, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x04, 0xFF, 0xFF, \n\t0x00, 0x01, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x9C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xA5, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xAE, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0xB7, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x72, 0x30, \n\t0x00, 0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x72, 0x31, 0x00, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, \n\t0x65, 0x30, 0x00, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x31, 0x00, 0x4D, 0x69, 0x63, 0x72, \n\t0x6F, 0x73, 0x6F, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4C, 0x53, 0x4C, 0x20, 0x53, \n\t0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6F, 0x6D, 0x70, 0x69, 0x6C, 0x65, 0x72, 0x20, 0x31, \n\t0x30, 0x2E, 0x31, 0x00, 0x49, 0x53, 0x47, 0x4E, 0x84, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, \n\t0x08, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x0F, 0x0F, 0x00, 0x00, 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x7A, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x0C, 0x0C, 0x00, 0x00, 0x53, 0x56, 0x5F, 0x50, 0x4F, 0x53, 0x49, 0x54, 0x49, 0x4F, 0x4E, 0x00, \n\t0x43, 0x4F, 0x4C, 0x4F, 0x52, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4F, 0x4F, 0x52, 0x44, 0x00, 0xAB, \n\t0x4F, 0x53, 0x47, 0x4E, 0x2C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, \n\t0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x53, 0x56, 0x5F, 0x54, 0x41, 0x52, 0x47, 0x45, \n\t0x54, 0x00, 0xAB, 0xAB, 0x53, 0x48, 0x44, 0x52, 0x38, 0x01, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, \n\t0x4E, 0x00, 0x00, 0x00, 0x5A, 0x00, 0x00, 0x03, 0x00, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x5A, 0x00, 0x00, 0x03, 0x00, 0x60, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x58, 0x18, 0x00, 0x04, \n\t0x00, 0x70, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x58, 0x18, 0x00, 0x04, \n\t0x00, 0x70, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, \n\t0xF2, 0x10, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, 0x32, 0x10, 0x10, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, 0xC2, 0x10, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x65, 0x00, 0x00, 0x03, 0xF2, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x02, \n\t0x02, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x09, 0xF2, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x46, 0x10, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x46, 0x7E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x07, 0xF2, 0x00, 0x10, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x46, 0x0E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1E, 0x10, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x09, 0xF2, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0xE6, 0x1A, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x46, 0x7E, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x00, 0x60, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x07, 0xF2, 0x00, 0x10, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x46, 0x0E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x0E, 0x10, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0x12, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x3A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x0D, 0x00, 0x04, 0x03, 0x0A, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x05, \n\t0xF2, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x0E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x3E, 0x00, 0x00, 0x01, 0x53, 0x54, 0x41, 0x54, 0x74, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\n\t\n};\nlong long multi_texture_mul_gt0_ps_size = 928;"
  },
  {
    "path": "src/engine/renderer/shaders/hlsl_compiled/multi_texture_mul_lt80_ps.cpp",
    "content": "unsigned char multi_texture_mul_lt80_ps[] = {\n\t0x44, 0x58, 0x42, 0x43, 0x64, 0x9F, 0xD8, 0x94, 0x47, 0xF5, 0x30, 0xE4, 0x04, 0x30, 0x47, 0xB3, \n\t0xEF, 0xC3, 0xAE, 0xC1, 0x01, 0x00, 0x00, 0x00, 0xA0, 0x03, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, \n\t0x34, 0x00, 0x00, 0x00, 0x24, 0x01, 0x00, 0x00, 0xB0, 0x01, 0x00, 0x00, 0xE4, 0x01, 0x00, 0x00, \n\t0x24, 0x03, 0x00, 0x00, 0x52, 0x44, 0x45, 0x46, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x04, 0xFF, 0xFF, \n\t0x00, 0x01, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x9C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xA5, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xAE, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0xB7, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x72, 0x30, \n\t0x00, 0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x72, 0x31, 0x00, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, \n\t0x65, 0x30, 0x00, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x31, 0x00, 0x4D, 0x69, 0x63, 0x72, \n\t0x6F, 0x73, 0x6F, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4C, 0x53, 0x4C, 0x20, 0x53, \n\t0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6F, 0x6D, 0x70, 0x69, 0x6C, 0x65, 0x72, 0x20, 0x31, \n\t0x30, 0x2E, 0x31, 0x00, 0x49, 0x53, 0x47, 0x4E, 0x84, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, \n\t0x08, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x0F, 0x0F, 0x00, 0x00, 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x7A, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x0C, 0x0C, 0x00, 0x00, 0x53, 0x56, 0x5F, 0x50, 0x4F, 0x53, 0x49, 0x54, 0x49, 0x4F, 0x4E, 0x00, \n\t0x43, 0x4F, 0x4C, 0x4F, 0x52, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4F, 0x4F, 0x52, 0x44, 0x00, 0xAB, \n\t0x4F, 0x53, 0x47, 0x4E, 0x2C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, \n\t0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x53, 0x56, 0x5F, 0x54, 0x41, 0x52, 0x47, 0x45, \n\t0x54, 0x00, 0xAB, 0xAB, 0x53, 0x48, 0x44, 0x52, 0x38, 0x01, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, \n\t0x4E, 0x00, 0x00, 0x00, 0x5A, 0x00, 0x00, 0x03, 0x00, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x5A, 0x00, 0x00, 0x03, 0x00, 0x60, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x58, 0x18, 0x00, 0x04, \n\t0x00, 0x70, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x58, 0x18, 0x00, 0x04, \n\t0x00, 0x70, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, \n\t0xF2, 0x10, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, 0x32, 0x10, 0x10, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, 0xC2, 0x10, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x65, 0x00, 0x00, 0x03, 0xF2, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x02, \n\t0x02, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x09, 0xF2, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x46, 0x10, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x46, 0x7E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x07, 0xF2, 0x00, 0x10, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x46, 0x0E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1E, 0x10, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x09, 0xF2, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0xE6, 0x1A, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x46, 0x7E, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x00, 0x60, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x07, 0xF2, 0x00, 0x10, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x46, 0x0E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x0E, 0x10, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x07, 0x12, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x3A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, \n\t0x0D, 0x00, 0x04, 0x03, 0x0A, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x05, \n\t0xF2, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x0E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x3E, 0x00, 0x00, 0x01, 0x53, 0x54, 0x41, 0x54, 0x74, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\n\t\n};\nlong long multi_texture_mul_lt80_ps_size = 928;"
  },
  {
    "path": "src/engine/renderer/shaders/hlsl_compiled/multi_texture_mul_ps.cpp",
    "content": "unsigned char multi_texture_mul_ps[] = {\n\t0x44, 0x58, 0x42, 0x43, 0x50, 0x19, 0x9C, 0x2F, 0x2D, 0xEE, 0xD3, 0xC4, 0xEA, 0x2F, 0x4A, 0x49, \n\t0x6E, 0x96, 0x6E, 0xF8, 0x01, 0x00, 0x00, 0x00, 0x64, 0x03, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, \n\t0x34, 0x00, 0x00, 0x00, 0x24, 0x01, 0x00, 0x00, 0xB0, 0x01, 0x00, 0x00, 0xE4, 0x01, 0x00, 0x00, \n\t0xE8, 0x02, 0x00, 0x00, 0x52, 0x44, 0x45, 0x46, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x04, 0xFF, 0xFF, \n\t0x00, 0x01, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x9C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xA5, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xAE, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0xB7, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x72, 0x30, \n\t0x00, 0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x72, 0x31, 0x00, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, \n\t0x65, 0x30, 0x00, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x31, 0x00, 0x4D, 0x69, 0x63, 0x72, \n\t0x6F, 0x73, 0x6F, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4C, 0x53, 0x4C, 0x20, 0x53, \n\t0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6F, 0x6D, 0x70, 0x69, 0x6C, 0x65, 0x72, 0x20, 0x31, \n\t0x30, 0x2E, 0x31, 0x00, 0x49, 0x53, 0x47, 0x4E, 0x84, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, \n\t0x08, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x0F, 0x0F, 0x00, 0x00, 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x7A, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x0C, 0x0C, 0x00, 0x00, 0x53, 0x56, 0x5F, 0x50, 0x4F, 0x53, 0x49, 0x54, 0x49, 0x4F, 0x4E, 0x00, \n\t0x43, 0x4F, 0x4C, 0x4F, 0x52, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4F, 0x4F, 0x52, 0x44, 0x00, 0xAB, \n\t0x4F, 0x53, 0x47, 0x4E, 0x2C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, \n\t0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x53, 0x56, 0x5F, 0x54, 0x41, 0x52, 0x47, 0x45, \n\t0x54, 0x00, 0xAB, 0xAB, 0x53, 0x48, 0x44, 0x52, 0xFC, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, \n\t0x3F, 0x00, 0x00, 0x00, 0x5A, 0x00, 0x00, 0x03, 0x00, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x5A, 0x00, 0x00, 0x03, 0x00, 0x60, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x58, 0x18, 0x00, 0x04, \n\t0x00, 0x70, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x58, 0x18, 0x00, 0x04, \n\t0x00, 0x70, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, \n\t0xF2, 0x10, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, 0x32, 0x10, 0x10, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, 0xC2, 0x10, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x65, 0x00, 0x00, 0x03, 0xF2, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x02, \n\t0x02, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x09, 0xF2, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x46, 0x10, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x46, 0x7E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x07, 0xF2, 0x00, 0x10, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x46, 0x0E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1E, 0x10, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x09, 0xF2, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0xE6, 0x1A, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x46, 0x7E, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x00, 0x60, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x07, 0xF2, 0x20, 0x10, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x46, 0x0E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x0E, 0x10, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x01, 0x53, 0x54, 0x41, 0x54, 0x74, 0x00, 0x00, 0x00, \n\t0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00\n};\nlong long multi_texture_mul_ps_size = 868;"
  },
  {
    "path": "src/engine/renderer/shaders/hlsl_compiled/multi_texture_vs.cpp",
    "content": "unsigned char multi_texture_vs[] = {\n\t0x44, 0x58, 0x42, 0x43, 0x17, 0xD0, 0x46, 0xDC, 0xB7, 0x33, 0x49, 0x2C, 0x96, 0x9D, 0x70, 0xBB, \n\t0x8A, 0xE5, 0x18, 0x13, 0x01, 0x00, 0x00, 0x00, 0x64, 0x04, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, \n\t0x34, 0x00, 0x00, 0x00, 0x70, 0x01, 0x00, 0x00, 0xF8, 0x01, 0x00, 0x00, 0x84, 0x02, 0x00, 0x00, \n\t0xE8, 0x03, 0x00, 0x00, 0x52, 0x44, 0x45, 0x46, 0x34, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x04, 0xFE, 0xFF, \n\t0x00, 0x01, 0x00, 0x00, 0x0C, 0x01, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x43, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74, \n\t0x73, 0x00, 0xAB, 0xAB, 0x3C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, \n\t0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA8, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xBC, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0xCC, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEC, 0x00, 0x00, 0x00, \n\t0x70, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x63, 0x6C, 0x69, 0x70, 0x5F, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5F, 0x78, \n\t0x66, 0x6F, 0x72, 0x6D, 0x00, 0xAB, 0xAB, 0xAB, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x79, 0x65, 0x5F, 0x73, 0x70, 0x61, 0x63, \n\t0x65, 0x5F, 0x78, 0x66, 0x6F, 0x72, 0x6D, 0x00, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x6C, 0x69, 0x70, 0x70, 0x69, 0x6E, 0x67, \n\t0x5F, 0x70, 0x6C, 0x61, 0x6E, 0x65, 0x00, 0xAB, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66, \n\t0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4C, 0x53, 0x4C, 0x20, 0x53, 0x68, 0x61, 0x64, 0x65, \n\t0x72, 0x20, 0x43, 0x6F, 0x6D, 0x70, 0x69, 0x6C, 0x65, 0x72, 0x20, 0x31, 0x30, 0x2E, 0x31, 0x00, \n\t0x49, 0x53, 0x47, 0x4E, 0x80, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, \n\t0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, \n\t0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, \n\t0x50, 0x4F, 0x53, 0x49, 0x54, 0x49, 0x4F, 0x4E, 0x00, 0x43, 0x4F, 0x4C, 0x4F, 0x52, 0x00, 0x54, \n\t0x45, 0x58, 0x43, 0x4F, 0x4F, 0x52, 0x44, 0x00, 0x4F, 0x53, 0x47, 0x4E, 0x84, 0x00, 0x00, 0x00, \n\t0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, \n\t0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x0C, 0x00, 0x00, \n\t0x7A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x0C, 0x03, 0x00, 0x00, 0x53, 0x56, 0x5F, 0x50, 0x4F, 0x53, 0x49, 0x54, \n\t0x49, 0x4F, 0x4E, 0x00, 0x43, 0x4F, 0x4C, 0x4F, 0x52, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4F, 0x4F, \n\t0x52, 0x44, 0x00, 0xAB, 0x53, 0x48, 0x44, 0x52, 0x5C, 0x01, 0x00, 0x00, 0x40, 0x00, 0x01, 0x00, \n\t0x57, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x04, 0x46, 0x8E, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x04, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x00, 0x03, 0xF2, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x5F, 0x00, 0x00, 0x03, 0xF2, 0x10, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x00, 0x03, \n\t0x32, 0x10, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x00, 0x03, 0x32, 0x10, 0x10, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x04, 0xF2, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x03, 0xF2, 0x20, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x65, 0x00, 0x00, 0x03, 0x32, 0x20, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x03, \n\t0xC2, 0x20, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, \n\t0x38, 0x00, 0x00, 0x08, 0xF2, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x15, 0x10, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x46, 0x8E, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x32, 0x00, 0x00, 0x0A, 0xF2, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x8E, 0x20, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x46, 0x0E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x0A, 0xF2, 0x00, 0x10, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x46, 0x8E, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0xA6, 0x1A, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x0E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x32, 0x00, 0x00, 0x0A, 0xF2, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x8E, 0x20, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xF6, 0x1F, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x46, 0x0E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x05, 0xF2, 0x20, 0x10, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x46, 0x1E, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x05, \n\t0x32, 0x20, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x46, 0x10, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x36, 0x00, 0x00, 0x05, 0xC2, 0x20, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x14, 0x10, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x01, 0x53, 0x54, 0x41, 0x54, 0x74, 0x00, 0x00, 0x00, \n\t0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, \n\t0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00\n};\nlong long multi_texture_vs_size = 1124;"
  },
  {
    "path": "src/engine/renderer/shaders/hlsl_compiled/single_texture_clipping_plane_vs.cpp",
    "content": "unsigned char single_texture_clipping_plane_vs[] = {\n\t0x44, 0x58, 0x42, 0x43, 0x18, 0xE4, 0x5E, 0x68, 0xE6, 0xA1, 0xD6, 0xB0, 0x1E, 0xC3, 0x9A, 0x71, \n\t0x82, 0xE8, 0x0B, 0x54, 0x01, 0x00, 0x00, 0x00, 0xE0, 0x04, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, \n\t0x34, 0x00, 0x00, 0x00, 0x70, 0x01, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0x7C, 0x02, 0x00, 0x00, \n\t0x64, 0x04, 0x00, 0x00, 0x52, 0x44, 0x45, 0x46, 0x34, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x04, 0xFE, 0xFF, \n\t0x00, 0x01, 0x00, 0x00, 0x0C, 0x01, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x43, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74, \n\t0x73, 0x00, 0xAB, 0xAB, 0x3C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, \n\t0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA8, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xBC, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0xCC, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEC, 0x00, 0x00, 0x00, \n\t0x70, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x63, 0x6C, 0x69, 0x70, 0x5F, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5F, 0x78, \n\t0x66, 0x6F, 0x72, 0x6D, 0x00, 0xAB, 0xAB, 0xAB, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x79, 0x65, 0x5F, 0x73, 0x70, 0x61, 0x63, \n\t0x65, 0x5F, 0x78, 0x66, 0x6F, 0x72, 0x6D, 0x00, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x6C, 0x69, 0x70, 0x70, 0x69, 0x6E, 0x67, \n\t0x5F, 0x70, 0x6C, 0x61, 0x6E, 0x65, 0x00, 0xAB, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66, \n\t0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4C, 0x53, 0x4C, 0x20, 0x53, 0x68, 0x61, 0x64, 0x65, \n\t0x72, 0x20, 0x43, 0x6F, 0x6D, 0x70, 0x69, 0x6C, 0x65, 0x72, 0x20, 0x31, 0x30, 0x2E, 0x31, 0x00, \n\t0x49, 0x53, 0x47, 0x4E, 0x68, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, \n\t0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, \n\t0x5F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x50, 0x4F, 0x53, 0x49, 0x54, 0x49, 0x4F, 0x4E, \n\t0x00, 0x43, 0x4F, 0x4C, 0x4F, 0x52, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4F, 0x4F, 0x52, 0x44, 0x00, \n\t0x4F, 0x53, 0x47, 0x4E, 0x94, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, \n\t0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, \n\t0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x03, 0x0C, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x0E, 0x00, 0x00, \n\t0x53, 0x56, 0x5F, 0x50, 0x4F, 0x53, 0x49, 0x54, 0x49, 0x4F, 0x4E, 0x00, 0x43, 0x4F, 0x4C, 0x4F, \n\t0x52, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4F, 0x4F, 0x52, 0x44, 0x00, 0x53, 0x56, 0x5F, 0x43, 0x6C, \n\t0x69, 0x70, 0x44, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x00, 0xAB, 0x53, 0x48, 0x44, 0x52, \n\t0xE0, 0x01, 0x00, 0x00, 0x40, 0x00, 0x01, 0x00, 0x78, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x04, \n\t0x46, 0x8E, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x00, 0x03, \n\t0xF2, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x00, 0x03, 0xF2, 0x10, 0x10, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x00, 0x03, 0x32, 0x10, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x67, 0x00, 0x00, 0x04, 0xF2, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x65, 0x00, 0x00, 0x03, 0xF2, 0x20, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x03, \n\t0x32, 0x20, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x04, 0x12, 0x20, 0x10, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, \n\t0x38, 0x00, 0x00, 0x08, 0xF2, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x15, 0x10, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x46, 0x8E, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x32, 0x00, 0x00, 0x0A, 0xF2, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x8E, 0x20, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x46, 0x0E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x0A, 0xF2, 0x00, 0x10, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x46, 0x8E, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0xA6, 0x1A, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x0E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x32, 0x00, 0x00, 0x0A, 0xF2, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x8E, 0x20, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xF6, 0x1F, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x46, 0x0E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x05, 0xF2, 0x20, 0x10, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x46, 0x1E, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x05, \n\t0x32, 0x20, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x46, 0x10, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x11, 0x00, 0x00, 0x08, 0x12, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1E, 0x10, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x46, 0x8E, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, \n\t0x11, 0x00, 0x00, 0x08, 0x22, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1E, 0x10, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x46, 0x8E, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, \n\t0x11, 0x00, 0x00, 0x08, 0x42, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1E, 0x10, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x46, 0x8E, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, \n\t0x10, 0x00, 0x00, 0x08, 0x12, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x82, 0x20, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x46, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x08, 0x12, 0x20, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x3A, 0x80, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, \n\t0x3E, 0x00, 0x00, 0x01, 0x53, 0x54, 0x41, 0x54, 0x74, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\n\t\n};\nlong long single_texture_clipping_plane_vs_size = 1248;"
  },
  {
    "path": "src/engine/renderer/shaders/hlsl_compiled/single_texture_ge80_ps.cpp",
    "content": "unsigned char single_texture_ge80_ps[] = {\n\t0x44, 0x58, 0x42, 0x43, 0xE7, 0xDE, 0xCF, 0x2D, 0xC7, 0xD8, 0xE0, 0x89, 0x9E, 0x1C, 0xA4, 0x45, \n\t0x04, 0xBF, 0x5B, 0x4D, 0x01, 0x00, 0x00, 0x00, 0xD0, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, \n\t0x34, 0x00, 0x00, 0x00, 0xD4, 0x00, 0x00, 0x00, 0x48, 0x01, 0x00, 0x00, 0x7C, 0x01, 0x00, 0x00, \n\t0x54, 0x02, 0x00, 0x00, 0x52, 0x44, 0x45, 0x46, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x04, 0xFF, 0xFF, \n\t0x00, 0x01, 0x00, 0x00, 0x6E, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x72, 0x30, \n\t0x00, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x30, 0x00, 0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, \n\t0x6F, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4C, 0x53, 0x4C, 0x20, 0x53, 0x68, 0x61, \n\t0x64, 0x65, 0x72, 0x20, 0x43, 0x6F, 0x6D, 0x70, 0x69, 0x6C, 0x65, 0x72, 0x20, 0x31, 0x30, 0x2E, \n\t0x31, 0x00, 0xAB, 0xAB, 0x49, 0x53, 0x47, 0x4E, 0x6C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x08, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x0F, 0x0F, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x53, 0x56, 0x5F, 0x50, \n\t0x4F, 0x53, 0x49, 0x54, 0x49, 0x4F, 0x4E, 0x00, 0x43, 0x4F, 0x4C, 0x4F, 0x52, 0x00, 0x54, 0x45, \n\t0x58, 0x43, 0x4F, 0x4F, 0x52, 0x44, 0x00, 0xAB, 0x4F, 0x53, 0x47, 0x4E, 0x2C, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, \n\t0x53, 0x56, 0x5F, 0x54, 0x41, 0x52, 0x47, 0x45, 0x54, 0x00, 0xAB, 0xAB, 0x53, 0x48, 0x44, 0x52, \n\t0xD0, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x5A, 0x00, 0x00, 0x03, \n\t0x00, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x18, 0x00, 0x04, 0x00, 0x70, 0x10, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, 0xF2, 0x10, 0x10, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, 0x32, 0x10, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x65, 0x00, 0x00, 0x03, 0xF2, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x02, \n\t0x02, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x09, 0xF2, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x46, 0x10, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x46, 0x7E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x07, 0xF2, 0x00, 0x10, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x46, 0x0E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1E, 0x10, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x07, 0x12, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x3A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, \n\t0x0D, 0x00, 0x04, 0x03, 0x0A, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x05, \n\t0xF2, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x0E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x3E, 0x00, 0x00, 0x01, 0x53, 0x54, 0x41, 0x54, 0x74, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\n\t\n};\nlong long single_texture_ge80_ps_size = 720;"
  },
  {
    "path": "src/engine/renderer/shaders/hlsl_compiled/single_texture_gt0_ps.cpp",
    "content": "unsigned char single_texture_gt0_ps[] = {\n\t0x44, 0x58, 0x42, 0x43, 0xB0, 0xD6, 0x4F, 0x95, 0xC6, 0xA4, 0x6B, 0x65, 0x14, 0x39, 0x26, 0xF3, \n\t0x40, 0xEA, 0x31, 0x47, 0x01, 0x00, 0x00, 0x00, 0xD0, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, \n\t0x34, 0x00, 0x00, 0x00, 0xD4, 0x00, 0x00, 0x00, 0x48, 0x01, 0x00, 0x00, 0x7C, 0x01, 0x00, 0x00, \n\t0x54, 0x02, 0x00, 0x00, 0x52, 0x44, 0x45, 0x46, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x04, 0xFF, 0xFF, \n\t0x00, 0x01, 0x00, 0x00, 0x6E, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x72, 0x30, \n\t0x00, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x30, 0x00, 0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, \n\t0x6F, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4C, 0x53, 0x4C, 0x20, 0x53, 0x68, 0x61, \n\t0x64, 0x65, 0x72, 0x20, 0x43, 0x6F, 0x6D, 0x70, 0x69, 0x6C, 0x65, 0x72, 0x20, 0x31, 0x30, 0x2E, \n\t0x31, 0x00, 0xAB, 0xAB, 0x49, 0x53, 0x47, 0x4E, 0x6C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x08, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x0F, 0x0F, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x53, 0x56, 0x5F, 0x50, \n\t0x4F, 0x53, 0x49, 0x54, 0x49, 0x4F, 0x4E, 0x00, 0x43, 0x4F, 0x4C, 0x4F, 0x52, 0x00, 0x54, 0x45, \n\t0x58, 0x43, 0x4F, 0x4F, 0x52, 0x44, 0x00, 0xAB, 0x4F, 0x53, 0x47, 0x4E, 0x2C, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, \n\t0x53, 0x56, 0x5F, 0x54, 0x41, 0x52, 0x47, 0x45, 0x54, 0x00, 0xAB, 0xAB, 0x53, 0x48, 0x44, 0x52, \n\t0xD0, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x5A, 0x00, 0x00, 0x03, \n\t0x00, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x18, 0x00, 0x04, 0x00, 0x70, 0x10, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, 0xF2, 0x10, 0x10, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, 0x32, 0x10, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x65, 0x00, 0x00, 0x03, 0xF2, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x02, \n\t0x02, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x09, 0xF2, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x46, 0x10, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x46, 0x7E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x07, 0xF2, 0x00, 0x10, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x46, 0x0E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1E, 0x10, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0x12, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x3A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x0D, 0x00, 0x04, 0x03, 0x0A, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x05, \n\t0xF2, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x0E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x3E, 0x00, 0x00, 0x01, 0x53, 0x54, 0x41, 0x54, 0x74, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\n\t\n};\nlong long single_texture_gt0_ps_size = 720;"
  },
  {
    "path": "src/engine/renderer/shaders/hlsl_compiled/single_texture_lt80_ps.cpp",
    "content": "unsigned char single_texture_lt80_ps[] = {\n\t0x44, 0x58, 0x42, 0x43, 0xAF, 0x67, 0xD3, 0x17, 0x36, 0xC1, 0x86, 0xDD, 0x1E, 0xFC, 0xEF, 0x7A, \n\t0x35, 0x8B, 0x10, 0xAB, 0x01, 0x00, 0x00, 0x00, 0xD0, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, \n\t0x34, 0x00, 0x00, 0x00, 0xD4, 0x00, 0x00, 0x00, 0x48, 0x01, 0x00, 0x00, 0x7C, 0x01, 0x00, 0x00, \n\t0x54, 0x02, 0x00, 0x00, 0x52, 0x44, 0x45, 0x46, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x04, 0xFF, 0xFF, \n\t0x00, 0x01, 0x00, 0x00, 0x6E, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x72, 0x30, \n\t0x00, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x30, 0x00, 0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, \n\t0x6F, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4C, 0x53, 0x4C, 0x20, 0x53, 0x68, 0x61, \n\t0x64, 0x65, 0x72, 0x20, 0x43, 0x6F, 0x6D, 0x70, 0x69, 0x6C, 0x65, 0x72, 0x20, 0x31, 0x30, 0x2E, \n\t0x31, 0x00, 0xAB, 0xAB, 0x49, 0x53, 0x47, 0x4E, 0x6C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x08, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x0F, 0x0F, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x53, 0x56, 0x5F, 0x50, \n\t0x4F, 0x53, 0x49, 0x54, 0x49, 0x4F, 0x4E, 0x00, 0x43, 0x4F, 0x4C, 0x4F, 0x52, 0x00, 0x54, 0x45, \n\t0x58, 0x43, 0x4F, 0x4F, 0x52, 0x44, 0x00, 0xAB, 0x4F, 0x53, 0x47, 0x4E, 0x2C, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, \n\t0x53, 0x56, 0x5F, 0x54, 0x41, 0x52, 0x47, 0x45, 0x54, 0x00, 0xAB, 0xAB, 0x53, 0x48, 0x44, 0x52, \n\t0xD0, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x5A, 0x00, 0x00, 0x03, \n\t0x00, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x18, 0x00, 0x04, 0x00, 0x70, 0x10, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, 0xF2, 0x10, 0x10, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, 0x32, 0x10, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x65, 0x00, 0x00, 0x03, 0xF2, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x02, \n\t0x02, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x09, 0xF2, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x46, 0x10, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x46, 0x7E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x07, 0xF2, 0x00, 0x10, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x46, 0x0E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1E, 0x10, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x07, 0x12, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x3A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, \n\t0x0D, 0x00, 0x04, 0x03, 0x0A, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x05, \n\t0xF2, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x0E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x3E, 0x00, 0x00, 0x01, 0x53, 0x54, 0x41, 0x54, 0x74, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\n\t\n};\nlong long single_texture_lt80_ps_size = 720;"
  },
  {
    "path": "src/engine/renderer/shaders/hlsl_compiled/single_texture_ps.cpp",
    "content": "unsigned char single_texture_ps[] = {\n\t0x44, 0x58, 0x42, 0x43, 0x70, 0x57, 0xC0, 0xFF, 0x10, 0xA3, 0x7E, 0x94, 0x79, 0xEA, 0x49, 0xFE, \n\t0x49, 0xED, 0x5A, 0x36, 0x01, 0x00, 0x00, 0x00, 0x94, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, \n\t0x34, 0x00, 0x00, 0x00, 0xD4, 0x00, 0x00, 0x00, 0x48, 0x01, 0x00, 0x00, 0x7C, 0x01, 0x00, 0x00, \n\t0x18, 0x02, 0x00, 0x00, 0x52, 0x44, 0x45, 0x46, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x04, 0xFF, 0xFF, \n\t0x00, 0x01, 0x00, 0x00, 0x6E, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x72, 0x30, \n\t0x00, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x30, 0x00, 0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, \n\t0x6F, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4C, 0x53, 0x4C, 0x20, 0x53, 0x68, 0x61, \n\t0x64, 0x65, 0x72, 0x20, 0x43, 0x6F, 0x6D, 0x70, 0x69, 0x6C, 0x65, 0x72, 0x20, 0x31, 0x30, 0x2E, \n\t0x31, 0x00, 0xAB, 0xAB, 0x49, 0x53, 0x47, 0x4E, 0x6C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x08, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x0F, 0x0F, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x53, 0x56, 0x5F, 0x50, \n\t0x4F, 0x53, 0x49, 0x54, 0x49, 0x4F, 0x4E, 0x00, 0x43, 0x4F, 0x4C, 0x4F, 0x52, 0x00, 0x54, 0x45, \n\t0x58, 0x43, 0x4F, 0x4F, 0x52, 0x44, 0x00, 0xAB, 0x4F, 0x53, 0x47, 0x4E, 0x2C, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, \n\t0x53, 0x56, 0x5F, 0x54, 0x41, 0x52, 0x47, 0x45, 0x54, 0x00, 0xAB, 0xAB, 0x53, 0x48, 0x44, 0x52, \n\t0x94, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x5A, 0x00, 0x00, 0x03, \n\t0x00, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x18, 0x00, 0x04, 0x00, 0x70, 0x10, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, 0xF2, 0x10, 0x10, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, 0x32, 0x10, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x65, 0x00, 0x00, 0x03, 0xF2, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x02, \n\t0x01, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x09, 0xF2, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x46, 0x10, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x46, 0x7E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x07, 0xF2, 0x20, 0x10, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x46, 0x0E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1E, 0x10, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x01, 0x53, 0x54, 0x41, 0x54, 0x74, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00\n};\nlong long single_texture_ps_size = 660;"
  },
  {
    "path": "src/engine/renderer/shaders/hlsl_compiled/single_texture_vs.cpp",
    "content": "unsigned char single_texture_vs[] = {\n\t0x44, 0x58, 0x42, 0x43, 0xBD, 0x59, 0x1D, 0x43, 0x84, 0x50, 0x25, 0xE8, 0x09, 0x04, 0x7B, 0x8B, \n\t0x15, 0x47, 0xA1, 0x0E, 0x01, 0x00, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, \n\t0x34, 0x00, 0x00, 0x00, 0x70, 0x01, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0x54, 0x02, 0x00, 0x00, \n\t0x8C, 0x03, 0x00, 0x00, 0x52, 0x44, 0x45, 0x46, 0x34, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x04, 0xFE, 0xFF, \n\t0x00, 0x01, 0x00, 0x00, 0x0C, 0x01, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x43, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74, \n\t0x73, 0x00, 0xAB, 0xAB, 0x3C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, \n\t0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA8, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xBC, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0xCC, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEC, 0x00, 0x00, 0x00, \n\t0x70, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x63, 0x6C, 0x69, 0x70, 0x5F, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5F, 0x78, \n\t0x66, 0x6F, 0x72, 0x6D, 0x00, 0xAB, 0xAB, 0xAB, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x79, 0x65, 0x5F, 0x73, 0x70, 0x61, 0x63, \n\t0x65, 0x5F, 0x78, 0x66, 0x6F, 0x72, 0x6D, 0x00, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x6C, 0x69, 0x70, 0x70, 0x69, 0x6E, 0x67, \n\t0x5F, 0x70, 0x6C, 0x61, 0x6E, 0x65, 0x00, 0xAB, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66, \n\t0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4C, 0x53, 0x4C, 0x20, 0x53, 0x68, 0x61, 0x64, 0x65, \n\t0x72, 0x20, 0x43, 0x6F, 0x6D, 0x70, 0x69, 0x6C, 0x65, 0x72, 0x20, 0x31, 0x30, 0x2E, 0x31, 0x00, \n\t0x49, 0x53, 0x47, 0x4E, 0x68, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, \n\t0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, \n\t0x5F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x50, 0x4F, 0x53, 0x49, 0x54, 0x49, 0x4F, 0x4E, \n\t0x00, 0x43, 0x4F, 0x4C, 0x4F, 0x52, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4F, 0x4F, 0x52, 0x44, 0x00, \n\t0x4F, 0x53, 0x47, 0x4E, 0x6C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, \n\t0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, \n\t0x62, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x03, 0x0C, 0x00, 0x00, 0x53, 0x56, 0x5F, 0x50, 0x4F, 0x53, 0x49, 0x54, \n\t0x49, 0x4F, 0x4E, 0x00, 0x43, 0x4F, 0x4C, 0x4F, 0x52, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4F, 0x4F, \n\t0x52, 0x44, 0x00, 0xAB, 0x53, 0x48, 0x44, 0x52, 0x30, 0x01, 0x00, 0x00, 0x40, 0x00, 0x01, 0x00, \n\t0x4C, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x04, 0x46, 0x8E, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x04, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x00, 0x03, 0xF2, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x5F, 0x00, 0x00, 0x03, 0xF2, 0x10, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x00, 0x03, \n\t0x32, 0x10, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x04, 0xF2, 0x20, 0x10, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x03, 0xF2, 0x20, 0x10, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x03, 0x32, 0x20, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x68, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x08, 0xF2, 0x00, 0x10, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x56, 0x15, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x8E, 0x20, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x0A, 0xF2, 0x00, 0x10, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x46, 0x8E, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x06, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x0E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x32, 0x00, 0x00, 0x0A, 0xF2, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x8E, 0x20, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xA6, 0x1A, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x46, 0x0E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x0A, 0xF2, 0x20, 0x10, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x46, 0x8E, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0xF6, 0x1F, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x0E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x36, 0x00, 0x00, 0x05, 0xF2, 0x20, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x46, 0x1E, 0x10, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x05, 0x32, 0x20, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x46, 0x10, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x01, 0x53, 0x54, 0x41, 0x54, \n\t0x74, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\n};\nlong long single_texture_vs_size = 1032;"
  },
  {
    "path": "src/engine/renderer/shaders/multi_texture.vert",
    "content": "#version 450\n\nlayout(push_constant) uniform Transform {\n    mat4 mvp;\n};\n\nlayout(location = 0) in vec3 in_position;\nlayout(location = 1) in vec4 in_color;\nlayout(location = 2) in vec2 in_tex_coord0;\nlayout(location = 3) in vec2 in_tex_coord1;\n\nlayout(location = 0) out vec4 frag_color;\nlayout(location = 1) out vec2 frag_tex_coord0;\nlayout(location = 2) out vec2 frag_tex_coord1;\n\nout gl_PerVertex {\n    vec4 gl_Position;\n};\n\nvoid main() {\n    gl_Position = mvp * vec4(in_position, 1.0);\n    frag_color = in_color;\n    frag_tex_coord0 = in_tex_coord0;\n    frag_tex_coord1 = in_tex_coord1;\n}\n"
  },
  {
    "path": "src/engine/renderer/shaders/multi_texture_add.frag",
    "content": "#version 450\n\nlayout(set = 0, binding = 0) uniform sampler2D texture0;\nlayout(set = 1, binding = 0) uniform sampler2D texture1;\n\nlayout(location = 0) in vec4 frag_color;\nlayout(location = 1) in vec2 frag_tex_coord0;\nlayout(location = 2) in vec2 frag_tex_coord1;\n\nlayout(location = 0) out vec4 out_color;\n\nlayout (constant_id = 0) const int alpha_test_func = 0;\n\nvoid main() {\n    vec4 color_a = frag_color * texture(texture0, frag_tex_coord0);\n    vec4 color_b = texture(texture1, frag_tex_coord1);\n    out_color = vec4(color_a.rgb + color_b.rgb, color_a.a * color_b.a);\n\n    if (alpha_test_func == 1) {\n        if (out_color.a == 0.0f) discard;\n    } else if (alpha_test_func == 2) {\n        if (out_color.a >= 0.5f) discard;\n    } else if (alpha_test_func == 3) {\n        if (out_color.a < 0.5f) discard;\n    }\n}\n"
  },
  {
    "path": "src/engine/renderer/shaders/multi_texture_clipping_plane.vert",
    "content": "#version 450\n\n// 128 bytes\nlayout(push_constant) uniform Transform {\n    mat4 clip_space_xform;\n    mat3x4 eye_space_xform;\n    vec4 clipping_plane; // in eye space\n};\n\nlayout(location = 0) in vec3 in_position;\nlayout(location = 1) in vec4 in_color;\nlayout(location = 2) in vec2 in_tex_coord0;\nlayout(location = 3) in vec2 in_tex_coord1;\n\nlayout(location = 0) out vec4 frag_color;\nlayout(location = 1) out vec2 frag_tex_coord0;\nlayout(location = 2) out vec2 frag_tex_coord1;\n\nout gl_PerVertex {\n    vec4 gl_Position;\n    float gl_ClipDistance[1];\n};\n\nvoid main() {\n    vec4 p = vec4(in_position, 1.0);\n\n    gl_Position = clip_space_xform *  p;\n    gl_ClipDistance[0] = dot(clipping_plane, vec4(p * eye_space_xform, 1.0));\n\n    frag_color = in_color;\n    frag_tex_coord0 = in_tex_coord0;\n    frag_tex_coord1 = in_tex_coord1;\n}\n"
  },
  {
    "path": "src/engine/renderer/shaders/multi_texture_mul.frag",
    "content": "#version 450\n\nlayout(set = 0, binding = 0) uniform sampler2D texture0;\nlayout(set = 1, binding = 0) uniform sampler2D texture1;\n\nlayout(location = 0) in vec4 frag_color;\nlayout(location = 1) in vec2 frag_tex_coord0;\nlayout(location = 2) in vec2 frag_tex_coord1;\n\nlayout(location = 0) out vec4 out_color;\n\nlayout (constant_id = 0) const int alpha_test_func = 0;\n\nvoid main() {\n    out_color = frag_color * texture(texture0, frag_tex_coord0) * texture(texture1, frag_tex_coord1);\n\n    if (alpha_test_func == 1) {\n        if (out_color.a == 0.0f) discard;\n    } else if (alpha_test_func == 2) {\n        if (out_color.a >= 0.5f) discard;\n    } else if (alpha_test_func == 3) {\n        if (out_color.a < 0.5f) discard;\n    }\n}\n"
  },
  {
    "path": "src/engine/renderer/shaders/shaders.hlsl",
    "content": "struct Single_Texture_PS_Data {\n    float4 position : SV_POSITION;\n    float4 color  : COLOR;\n    float2 uv0 : TEXCOORD;\n};\n\nstruct Multi_Texture_PS_Data {\n    float4 position : SV_POSITION;\n    float4 color  : COLOR;\n    float2 uv0 : TEXCOORD0;\n    float2 uv1 : TEXCOORD1;\n};\n\ncbuffer Constants : register(b0) {\n    float4x4 clip_space_xform;\n    float4x3 eye_space_xform;\n    float4 clipping_plane; // in eye space\n};\n\nTexture2D texture0 : register(t0);\nSamplerState sampler0 : register(s0);\n\nTexture2D texture1 : register(t1);\nSamplerState sampler1 : register(s1);\n\nSingle_Texture_PS_Data single_texture_vs(\n    float4 position : POSITION,\n    float4 color    : COLOR,\n    float2 uv0      : TEXCOORD)\n{\n    Single_Texture_PS_Data ps_data;\n    ps_data.position = mul(clip_space_xform, position);\n    ps_data.color = color;\n    ps_data.uv0 = uv0;\n    return ps_data;\n}\n\nSingle_Texture_PS_Data single_texture_clipping_plane_vs(\n    float4 position : POSITION,\n    float4 color    : COLOR,\n    float2 uv0      : TEXCOORD,\n    out float clip : SV_ClipDistance)\n{\n    clip = dot(clipping_plane.xyz, mul(position, eye_space_xform)) + clipping_plane.w;\n\n    Single_Texture_PS_Data ps_data;\n    ps_data.position = mul(clip_space_xform, position);\n    ps_data.color = color;\n    ps_data.uv0 = uv0;\n    return ps_data;\n}\n\nMulti_Texture_PS_Data multi_texture_vs(\n    float4 position : POSITION,\n    float4 color    : COLOR,\n    float2 uv0      : TEXCOORD0,\n    float2 uv1      : TEXCOORD1)\n{\n    Multi_Texture_PS_Data ps_data;\n    ps_data.position = mul(clip_space_xform, position);\n    ps_data.color = color;\n    ps_data.uv0 = uv0;\n    ps_data.uv1 = uv1;\n    return ps_data;\n}\n\nMulti_Texture_PS_Data multi_texture_clipping_plane_vs(\n    float4 position : POSITION,\n    float4 color    : COLOR,\n    float2 uv0      : TEXCOORD0,\n    float2 uv1      : TEXCOORD1,\n    out float clip : SV_ClipDistance)\n{\n    clip = dot(clipping_plane.xyz, mul(position, eye_space_xform)) + clipping_plane.w;\n\n    Multi_Texture_PS_Data ps_data;\n    ps_data.position = mul(clip_space_xform, position);\n    ps_data.color = color;\n    ps_data.uv0 = uv0;\n    ps_data.uv1 = uv1;\n    return ps_data;\n}\n\nfloat4 single_texture_ps(Single_Texture_PS_Data data) : SV_TARGET {\n    float4 out_color = data.color * texture0.Sample(sampler0, data.uv0);\n\n#if defined(ALPHA_TEST_GT0)\n    if (out_color.a == 0.0f) discard;\n#elif defined(ALPHA_TEST_LT80)\n    if (out_color.a >= 0.5f) discard;\n#elif defined(ALPHA_TEST_GE80)\n    if (out_color.a < 0.5f) discard;\n#endif\n\n    return out_color;\n}\n\nfloat4 multi_texture_mul_ps(Multi_Texture_PS_Data data) : SV_TARGET {\n    float4 out_color = data.color * texture0.Sample(sampler0, data.uv0) * texture1.Sample(sampler1, data.uv1);\n\n#if defined(ALPHA_TEST_GT0)\n    if (out_color.a == 0.0f) discard;\n#elif defined(ALPHA_TEST_LT80)\n    if (out_color.a >= 0.5f) discard;\n#elif defined(ALPHA_TEST_GE80)\n    if (out_color.a < 0.5f) discard;\n#endif\n\n    return out_color;\n}\n\nfloat4 multi_texture_add_ps(Multi_Texture_PS_Data data) : SV_TARGET {\n    float4 color_a = data.color * texture0.Sample(sampler0, data.uv0);\n    float4 color_b = texture1.Sample(sampler1, data.uv1);\n    \n    float4 out_color = float4(\n        color_a.r + color_b.r,\n        color_a.g + color_b.g,\n        color_a.b + color_b.b,\n        color_a.a * color_b.a);\n\n#if defined(ALPHA_TEST_GT0)\n    if (out_color.a == 0.0f) discard;\n#elif defined(ALPHA_TEST_LT80)\n    if (out_color.a >= 0.5f) discard;\n#elif defined(ALPHA_TEST_GE80)\n    if (out_color.a < 0.5f) discard;\n#endif\n\n    return out_color;\n}\n"
  },
  {
    "path": "src/engine/renderer/shaders/single_texture.frag",
    "content": "#version 450\n\nlayout(set = 0, binding = 0) uniform sampler2D texture0;\n\nlayout(location = 0) in vec4 frag_color;\nlayout(location = 1) in vec2 frag_tex_coord;\n\nlayout(location = 0) out vec4 out_color;\n\nlayout (constant_id = 0) const int alpha_test_func = 0;\n\nvoid main() {\n    out_color = frag_color * texture(texture0, frag_tex_coord);\n\n    if (alpha_test_func == 1) {\n        if (out_color.a == 0.0f) discard;\n    } else if (alpha_test_func == 2) {\n        if (out_color.a >= 0.5f) discard;\n    } else if (alpha_test_func == 3) {\n        if (out_color.a < 0.5f) discard;\n    }\n}\n"
  },
  {
    "path": "src/engine/renderer/shaders/single_texture.vert",
    "content": "#version 450\n\nlayout(push_constant) uniform Transform {\n    mat4 mvp;\n};\n\nlayout(location = 0) in vec3 in_position;\nlayout(location = 1) in vec4 in_color;\nlayout(location = 2) in vec2 in_tex_coord;\n\nlayout(location = 0) out vec4 frag_color;\nlayout(location = 1) out vec2 frag_tex_coord;\n\nout gl_PerVertex {\n    vec4 gl_Position;\n};\n\nvoid main() {\n    gl_Position = mvp *  vec4(in_position, 1.0);\n    frag_color = in_color;\n    frag_tex_coord = in_tex_coord;\n}\n"
  },
  {
    "path": "src/engine/renderer/shaders/single_texture_clipping_plane.vert",
    "content": "#version 450\n\n// 128 bytes\nlayout(push_constant) uniform Transform {\n    mat4 clip_space_xform;\n    mat3x4 eye_space_xform;\n    vec4 clipping_plane; // in eye space\n};\n\nlayout(location = 0) in vec3 in_position;\nlayout(location = 1) in vec4 in_color;\nlayout(location = 2) in vec2 in_tex_coord;\n\nlayout(location = 0) out vec4 frag_color;\nlayout(location = 1) out vec2 frag_tex_coord;\n\nout gl_PerVertex {\n    vec4 gl_Position;\n    float gl_ClipDistance[1];\n};\n\nvoid main() {\n    vec4 p = vec4(in_position, 1.0);\n\n    gl_Position = clip_space_xform *  p;\n    gl_ClipDistance[0] = dot(clipping_plane, vec4(p * eye_space_xform, 1.0));\n\n    frag_color = in_color;\n    frag_tex_coord = in_tex_coord;\n}\n"
  },
  {
    "path": "src/engine/renderer/shaders/spirv/apply_gamma_comp.cpp",
    "content": "unsigned char apply_gamma_comp_spv[] = {\n\t0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0B, 0x00, 0x08, 0x00, 0x6D, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, \n\t0x38, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x4C, 0x53, 0x4C, \n\t0x2E, 0x73, 0x74, 0x64, 0x2E, 0x34, 0x35, 0x30, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x03, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x06, 0x00, 0x05, 0x00, 0x00, 0x00, \n\t0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, \n\t0x10, 0x00, 0x06, 0x00, 0x04, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, \n\t0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0xC2, 0x01, 0x00, 0x00, 0x04, 0x00, 0x0B, 0x00, 0x47, 0x4C, 0x5F, 0x45, 0x58, 0x54, 0x5F, 0x73, \n\t0x61, 0x6D, 0x70, 0x6C, 0x65, 0x72, 0x6C, 0x65, 0x73, 0x73, 0x5F, 0x74, 0x65, 0x78, 0x74, 0x75, \n\t0x72, 0x65, 0x5F, 0x66, 0x75, 0x6E, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x00, 0x00, 0x00, 0x00, \n\t0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E, 0x00, 0x00, 0x00, 0x00, \n\t0x05, 0x00, 0x06, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x61, 0x70, 0x70, 0x6C, 0x79, 0x5F, 0x67, 0x61, \n\t0x6D, 0x6D, 0x61, 0x28, 0x66, 0x31, 0x3B, 0x00, 0x05, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, \n\t0x63, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x69, 0x6E, 0x64, 0x65, \n\t0x78, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x16, 0x00, 0x00, 0x00, 0x63, 0x63, 0x00, 0x00, \n\t0x05, 0x00, 0x06, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x47, 0x61, 0x6D, 0x6D, 0x61, 0x5F, 0x42, 0x75, \n\t0x66, 0x66, 0x65, 0x72, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x1A, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, \n\t0x1C, 0x00, 0x00, 0x00, 0x67, 0x61, 0x6D, 0x6D, 0x61, 0x5F, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, \n\t0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x26, 0x00, 0x00, 0x00, 0x6C, 0x6F, 0x63, 0x00, \n\t0x05, 0x00, 0x08, 0x00, 0x29, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x47, 0x6C, 0x6F, 0x62, 0x61, \n\t0x6C, 0x49, 0x6E, 0x76, 0x6F, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x49, 0x44, 0x00, 0x00, 0x00, \n\t0x05, 0x00, 0x06, 0x00, 0x33, 0x00, 0x00, 0x00, 0x50, 0x75, 0x73, 0x68, 0x5F, 0x43, 0x6F, 0x6E, \n\t0x73, 0x74, 0x61, 0x6E, 0x74, 0x73, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x33, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x6F, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5F, 0x73, 0x69, 0x7A, 0x65, 0x00, \n\t0x06, 0x00, 0x07, 0x00, 0x33, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x69, 0x64, 0x65, 0x6E, \n\t0x74, 0x69, 0x74, 0x79, 0x5F, 0x67, 0x61, 0x6D, 0x6D, 0x61, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, \n\t0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x48, 0x00, 0x00, 0x00, \n\t0x63, 0x6F, 0x6C, 0x6F, 0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x4B, 0x00, 0x00, 0x00, \n\t0x6F, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5F, 0x69, 0x6D, 0x61, 0x67, 0x65, 0x00, 0x00, 0x00, 0x00, \n\t0x05, 0x00, 0x04, 0x00, 0x55, 0x00, 0x00, 0x00, 0x70, 0x61, 0x72, 0x61, 0x6D, 0x00, 0x00, 0x00, \n\t0x05, 0x00, 0x04, 0x00, 0x5A, 0x00, 0x00, 0x00, 0x70, 0x61, 0x72, 0x61, 0x6D, 0x00, 0x00, 0x00, \n\t0x05, 0x00, 0x04, 0x00, 0x5F, 0x00, 0x00, 0x00, 0x70, 0x61, 0x72, 0x61, 0x6D, 0x00, 0x00, 0x00, \n\t0x05, 0x00, 0x06, 0x00, 0x67, 0x00, 0x00, 0x00, 0x73, 0x77, 0x61, 0x70, 0x63, 0x68, 0x61, 0x69, \n\t0x6E, 0x5F, 0x69, 0x6D, 0x61, 0x67, 0x65, 0x00, 0x47, 0x00, 0x04, 0x00, 0x19, 0x00, 0x00, 0x00, \n\t0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x1A, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x1C, 0x00, 0x00, 0x00, \n\t0x21, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x1C, 0x00, 0x00, 0x00, \n\t0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x29, 0x00, 0x00, 0x00, \n\t0x0B, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x33, 0x00, 0x00, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x33, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, \n\t0x4B, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, \n\t0x4B, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, \n\t0x67, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x67, 0x00, 0x00, 0x00, \n\t0x21, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x67, 0x00, 0x00, 0x00, \n\t0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x6C, 0x00, 0x00, 0x00, \n\t0x0B, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, \n\t0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, \n\t0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x21, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, \n\t0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x0C, 0x00, 0x00, 0x00, \n\t0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0D, 0x00, 0x00, 0x00, \n\t0x07, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, \n\t0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x43, 0x2B, 0x00, 0x04, 0x00, 0x0C, 0x00, 0x00, 0x00, \n\t0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x0C, 0x00, 0x00, 0x00, \n\t0x14, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, \n\t0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, \n\t0x18, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x1C, 0x00, 0x04, 0x00, 0x19, 0x00, 0x00, 0x00, \n\t0x06, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x03, 0x00, 0x1A, 0x00, 0x00, 0x00, \n\t0x19, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x1A, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x06, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x24, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, \n\t0x24, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x27, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x27, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, \n\t0x17, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x04, 0x00, \n\t0x33, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, \n\t0x34, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, \n\t0x34, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, \n\t0x36, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, \n\t0x17, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, \n\t0x46, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, \n\t0x47, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, \n\t0x49, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x20, 0x00, 0x04, 0x00, 0x4A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, \n\t0x3B, 0x00, 0x04, 0x00, 0x4A, 0x00, 0x00, 0x00, 0x4B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x2B, 0x00, 0x04, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x4F, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x2B, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x19, 0x00, 0x09, 0x00, 0x65, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x65, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x66, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, 0x6B, 0x00, 0x00, 0x00, \n\t0x08, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x06, 0x00, 0x27, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, \n\t0x6B, 0x00, 0x00, 0x00, 0x6B, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0xF8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, \n\t0x26, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x47, 0x00, 0x00, 0x00, \n\t0x48, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, \n\t0x55, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, \n\t0x5A, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, \n\t0x5F, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x27, 0x00, 0x00, 0x00, \n\t0x2B, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x4F, 0x00, 0x07, 0x00, 0x2A, 0x00, 0x00, 0x00, \n\t0x2C, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x04, 0x00, 0x24, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, \n\t0x2C, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x26, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, \n\t0x41, 0x00, 0x05, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, \n\t0x2F, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, \n\t0x30, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, \n\t0x31, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x36, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, \n\t0x35, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, \n\t0x17, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0xB0, 0x00, 0x05, 0x00, \n\t0x2E, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, \n\t0xF7, 0x00, 0x03, 0x00, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x04, 0x00, \n\t0x39, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, \n\t0x3A, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x00, 0x00, \n\t0x26, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x0C, 0x00, 0x00, 0x00, \n\t0x3E, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, \n\t0x3F, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x36, 0x00, 0x00, 0x00, \n\t0x40, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, \n\t0x3D, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, \n\t0xB0, 0x00, 0x05, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, \n\t0x41, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, 0x3B, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, \n\t0x3B, 0x00, 0x00, 0x00, 0xF5, 0x00, 0x07, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, \n\t0x39, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, \n\t0xF7, 0x00, 0x03, 0x00, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x04, 0x00, \n\t0x43, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, \n\t0x44, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x49, 0x00, 0x00, 0x00, 0x4C, 0x00, 0x00, 0x00, \n\t0x4B, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x24, 0x00, 0x00, 0x00, 0x4D, 0x00, 0x00, 0x00, \n\t0x26, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x07, 0x00, 0x46, 0x00, 0x00, 0x00, 0x4E, 0x00, 0x00, 0x00, \n\t0x4C, 0x00, 0x00, 0x00, 0x4D, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, \n\t0x3E, 0x00, 0x03, 0x00, 0x48, 0x00, 0x00, 0x00, 0x4E, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, \n\t0x36, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x4F, 0x00, 0x00, 0x00, \n\t0x3D, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, \n\t0xAA, 0x00, 0x05, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, \n\t0x2F, 0x00, 0x00, 0x00, 0xF7, 0x00, 0x03, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0xFA, 0x00, 0x04, 0x00, 0x52, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, \n\t0xF8, 0x00, 0x02, 0x00, 0x53, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, \n\t0x56, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, \n\t0x06, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, \n\t0x55, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x39, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, \n\t0x58, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, \n\t0x07, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, \n\t0x3E, 0x00, 0x03, 0x00, 0x59, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, \n\t0x07, 0x00, 0x00, 0x00, 0x5B, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, \n\t0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x00, 0x00, 0x5B, 0x00, 0x00, 0x00, \n\t0x3E, 0x00, 0x03, 0x00, 0x5A, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x00, 0x00, 0x39, 0x00, 0x05, 0x00, \n\t0x06, 0x00, 0x00, 0x00, 0x5D, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x5A, 0x00, 0x00, 0x00, \n\t0x41, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x5E, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, \n\t0x3C, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x5E, 0x00, 0x00, 0x00, 0x5D, 0x00, 0x00, 0x00, \n\t0x41, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, \n\t0x60, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, \n\t0x61, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x5F, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, \n\t0x39, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, \n\t0x5F, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, \n\t0x48, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x64, 0x00, 0x00, 0x00, \n\t0x63, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, 0x54, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, \n\t0x54, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x65, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, \n\t0x67, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x24, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, \n\t0x26, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x46, 0x00, 0x00, 0x00, 0x6A, 0x00, 0x00, 0x00, \n\t0x48, 0x00, 0x00, 0x00, 0x63, 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, \n\t0x6A, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, 0x45, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, \n\t0x45, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00, 0x36, 0x00, 0x05, 0x00, \n\t0x06, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, \n\t0x37, 0x00, 0x03, 0x00, 0x07, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, \n\t0x0B, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, \n\t0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, \n\t0x07, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, \n\t0x09, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, \n\t0x0F, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x6E, 0x00, 0x04, 0x00, 0x0C, 0x00, 0x00, 0x00, \n\t0x12, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x00, 0x00, \n\t0x15, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, \n\t0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x0E, 0x00, 0x00, 0x00, \n\t0x15, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, \n\t0x0E, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, \n\t0x1C, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, \n\t0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, \n\t0x16, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, \n\t0x21, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x02, 0x00, 0x21, 0x00, 0x00, 0x00, \n\t0x38, 0x00, 0x01, 0x00\n};\nlong long apply_gamma_comp_spv_size = 2852;"
  },
  {
    "path": "src/engine/renderer/shaders/spirv/multi_texture_add_frag.cpp",
    "content": "unsigned char multi_texture_add_frag_spv[] = {\n\t0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x08, 0x00, 0x58, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x06, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x47, 0x4C, 0x53, 0x4C, 0x2E, 0x73, 0x74, 0x64, 0x2E, 0x34, 0x35, 0x30, \n\t0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x0F, 0x00, 0x09, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E, \n\t0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, \n\t0x1F, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0xC2, 0x01, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, \n\t0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, \n\t0x09, 0x00, 0x00, 0x00, 0x63, 0x6F, 0x6C, 0x6F, 0x72, 0x5F, 0x61, 0x00, 0x05, 0x00, 0x05, 0x00, \n\t0x0B, 0x00, 0x00, 0x00, 0x66, 0x72, 0x61, 0x67, 0x5F, 0x63, 0x6F, 0x6C, 0x6F, 0x72, 0x00, 0x00, \n\t0x05, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x00, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x30, \n\t0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x14, 0x00, 0x00, 0x00, 0x66, 0x72, 0x61, 0x67, \n\t0x5F, 0x74, 0x65, 0x78, 0x5F, 0x63, 0x6F, 0x6F, 0x72, 0x64, 0x30, 0x00, 0x05, 0x00, 0x04, 0x00, \n\t0x18, 0x00, 0x00, 0x00, 0x63, 0x6F, 0x6C, 0x6F, 0x72, 0x5F, 0x62, 0x00, 0x05, 0x00, 0x05, 0x00, \n\t0x19, 0x00, 0x00, 0x00, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x31, 0x00, 0x00, 0x00, 0x00, \n\t0x05, 0x00, 0x06, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x66, 0x72, 0x61, 0x67, 0x5F, 0x74, 0x65, 0x78, \n\t0x5F, 0x63, 0x6F, 0x6F, 0x72, 0x64, 0x31, 0x00, 0x05, 0x00, 0x05, 0x00, 0x1F, 0x00, 0x00, 0x00, \n\t0x6F, 0x75, 0x74, 0x5F, 0x63, 0x6F, 0x6C, 0x6F, 0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, \n\t0x33, 0x00, 0x00, 0x00, 0x61, 0x6C, 0x70, 0x68, 0x61, 0x5F, 0x74, 0x65, 0x73, 0x74, 0x5F, 0x66, \n\t0x75, 0x6E, 0x63, 0x00, 0x47, 0x00, 0x04, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x33, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, \n\t0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, \n\t0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, \n\t0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x03, 0x00, 0x0E, 0x00, 0x00, 0x00, \n\t0x0D, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x0E, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x12, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x12, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x26, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x26, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, \n\t0x06, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x32, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x32, 0x00, 0x04, 0x00, 0x32, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x32, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02, 0x00, 0x35, 0x00, 0x00, 0x00, 0x34, 0x00, 0x06, 0x00, \n\t0x35, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0xAA, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, \n\t0x34, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x39, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x06, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x32, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x34, 0x00, 0x06, 0x00, 0x35, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, \n\t0xAA, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, \n\t0x06, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x2B, 0x00, 0x04, 0x00, \n\t0x32, 0x00, 0x00, 0x00, 0x4E, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x34, 0x00, 0x06, 0x00, \n\t0x35, 0x00, 0x00, 0x00, 0x4F, 0x00, 0x00, 0x00, 0xAA, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, \n\t0x4E, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, \n\t0x3B, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, \n\t0x3B, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, \n\t0x3D, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, \n\t0x3D, 0x00, 0x04, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, \n\t0x3D, 0x00, 0x04, 0x00, 0x12, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, \n\t0x57, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, \n\t0x15, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, \n\t0x0C, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, \n\t0x17, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, \n\t0x19, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x12, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, \n\t0x1B, 0x00, 0x00, 0x00, 0x57, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, \n\t0x1A, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x18, 0x00, 0x00, 0x00, \n\t0x1D, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, \n\t0x09, 0x00, 0x00, 0x00, 0x4F, 0x00, 0x08, 0x00, 0x20, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, \n\t0x21, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, \n\t0x18, 0x00, 0x00, 0x00, 0x4F, 0x00, 0x08, 0x00, 0x20, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, \n\t0x23, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, \n\t0x22, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, \n\t0x29, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, \n\t0x06, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, \n\t0x28, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, \n\t0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, \n\t0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, \n\t0x2C, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, \n\t0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, \n\t0x2F, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, \n\t0x06, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x50, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, \n\t0x2F, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, \n\t0x1F, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0xF7, 0x00, 0x03, 0x00, 0x38, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x04, 0x00, 0x36, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, \n\t0x41, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x37, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, \n\t0x39, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, \n\t0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, \n\t0xB4, 0x00, 0x05, 0x00, 0x35, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, \n\t0x3C, 0x00, 0x00, 0x00, 0xF7, 0x00, 0x03, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0xFA, 0x00, 0x04, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, \n\t0xF8, 0x00, 0x02, 0x00, 0x3E, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x01, 0x00, 0xF8, 0x00, 0x02, 0x00, \n\t0x3F, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, 0x38, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, \n\t0x41, 0x00, 0x00, 0x00, 0xF7, 0x00, 0x03, 0x00, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0xFA, 0x00, 0x04, 0x00, 0x43, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x4D, 0x00, 0x00, 0x00, \n\t0xF8, 0x00, 0x02, 0x00, 0x44, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x39, 0x00, 0x00, 0x00, \n\t0x46, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, \n\t0x06, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0xBE, 0x00, 0x05, 0x00, \n\t0x35, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, \n\t0xF7, 0x00, 0x03, 0x00, 0x4B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x04, 0x00, \n\t0x49, 0x00, 0x00, 0x00, 0x4A, 0x00, 0x00, 0x00, 0x4B, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, \n\t0x4A, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x01, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x4B, 0x00, 0x00, 0x00, \n\t0xF9, 0x00, 0x02, 0x00, 0x45, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x4D, 0x00, 0x00, 0x00, \n\t0xF7, 0x00, 0x03, 0x00, 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x04, 0x00, \n\t0x4F, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, \n\t0x50, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x39, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, \n\t0x1F, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, \n\t0x53, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0xB8, 0x00, 0x05, 0x00, 0x35, 0x00, 0x00, 0x00, \n\t0x54, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0xF7, 0x00, 0x03, 0x00, \n\t0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x04, 0x00, 0x54, 0x00, 0x00, 0x00, \n\t0x55, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x55, 0x00, 0x00, 0x00, \n\t0xFC, 0x00, 0x01, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x56, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, \n\t0x51, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x51, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, \n\t0x45, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x45, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, \n\t0x38, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x38, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x01, 0x00, \n\t0x38, 0x00, 0x01, 0x00\n};\nlong long multi_texture_add_frag_spv_size = 2068;"
  },
  {
    "path": "src/engine/renderer/shaders/spirv/multi_texture_clipping_plane_vert.cpp",
    "content": "unsigned char multi_texture_clipping_plane_vert_spv[] = {\n\t0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x08, 0x00, 0x45, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, \n\t0x20, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x4C, 0x53, 0x4C, \n\t0x2E, 0x73, 0x74, 0x64, 0x2E, 0x34, 0x35, 0x30, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x03, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, \n\t0x18, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, \n\t0x40, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0xC2, 0x01, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, \n\t0x6D, 0x61, 0x69, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, \n\t0x70, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x69, 0x6E, 0x5F, 0x70, \n\t0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x00, 0x05, 0x00, 0x06, 0x00, 0x16, 0x00, 0x00, 0x00, \n\t0x67, 0x6C, 0x5F, 0x50, 0x65, 0x72, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x00, 0x00, 0x00, 0x00, \n\t0x06, 0x00, 0x06, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x50, \n\t0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x00, 0x06, 0x00, 0x07, 0x00, 0x16, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x43, 0x6C, 0x69, 0x70, 0x44, 0x69, 0x73, 0x74, 0x61, \n\t0x6E, 0x63, 0x65, 0x00, 0x05, 0x00, 0x03, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x05, 0x00, 0x05, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x66, 0x6F, 0x72, \n\t0x6D, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x63, 0x6C, 0x69, 0x70, 0x5F, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5F, 0x78, 0x66, 0x6F, 0x72, 0x6D, \n\t0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x07, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x65, 0x79, 0x65, 0x5F, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5F, 0x78, 0x66, 0x6F, 0x72, 0x6D, 0x00, \n\t0x06, 0x00, 0x07, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x63, 0x6C, 0x69, 0x70, \n\t0x70, 0x69, 0x6E, 0x67, 0x5F, 0x70, 0x6C, 0x61, 0x6E, 0x65, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, \n\t0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x38, 0x00, 0x00, 0x00, \n\t0x66, 0x72, 0x61, 0x67, 0x5F, 0x63, 0x6F, 0x6C, 0x6F, 0x72, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, \n\t0x3A, 0x00, 0x00, 0x00, 0x69, 0x6E, 0x5F, 0x63, 0x6F, 0x6C, 0x6F, 0x72, 0x00, 0x00, 0x00, 0x00, \n\t0x05, 0x00, 0x06, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x66, 0x72, 0x61, 0x67, 0x5F, 0x74, 0x65, 0x78, \n\t0x5F, 0x63, 0x6F, 0x6F, 0x72, 0x64, 0x30, 0x00, 0x05, 0x00, 0x06, 0x00, 0x40, 0x00, 0x00, 0x00, \n\t0x69, 0x6E, 0x5F, 0x74, 0x65, 0x78, 0x5F, 0x63, 0x6F, 0x6F, 0x72, 0x64, 0x30, 0x00, 0x00, 0x00, \n\t0x05, 0x00, 0x06, 0x00, 0x42, 0x00, 0x00, 0x00, 0x66, 0x72, 0x61, 0x67, 0x5F, 0x74, 0x65, 0x78, \n\t0x5F, 0x63, 0x6F, 0x6F, 0x72, 0x64, 0x31, 0x00, 0x05, 0x00, 0x06, 0x00, 0x43, 0x00, 0x00, 0x00, \n\t0x69, 0x6E, 0x5F, 0x74, 0x65, 0x78, 0x5F, 0x63, 0x6F, 0x6F, 0x72, 0x64, 0x31, 0x00, 0x00, 0x00, \n\t0x47, 0x00, 0x04, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x48, 0x00, 0x05, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x16, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x0B, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x16, 0x00, 0x00, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x48, 0x00, 0x04, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x05, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x1D, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x04, 0x00, \n\t0x1D, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, \n\t0x1D, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, \n\t0x48, 0x00, 0x05, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, \n\t0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x23, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x1D, 0x00, 0x00, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x38, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x40, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x42, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x43, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, \n\t0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, \n\t0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, \n\t0x07, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x0A, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x80, 0x3F, 0x15, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, \n\t0x14, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, \n\t0x15, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x16, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x04, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, \n\t0x04, 0x00, 0x00, 0x00, 0x18, 0x00, 0x04, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x05, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, \n\t0x1C, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x1E, 0x00, 0x00, 0x00, \n\t0x09, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x1E, 0x00, 0x00, 0x00, \n\t0x1F, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, \n\t0x09, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x19, 0x00, 0x00, 0x00, \n\t0x27, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x19, 0x00, 0x00, 0x00, \n\t0x28, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x29, 0x00, 0x00, 0x00, \n\t0x09, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x2D, 0x00, 0x00, 0x00, \n\t0x09, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x36, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, \n\t0x38, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x39, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x39, 0x00, 0x00, 0x00, \n\t0x3A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x3C, 0x00, 0x00, 0x00, \n\t0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x3D, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x3D, 0x00, 0x00, 0x00, \n\t0x3E, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x3F, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x3F, 0x00, 0x00, 0x00, \n\t0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x3D, 0x00, 0x00, 0x00, \n\t0x42, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x3F, 0x00, 0x00, 0x00, \n\t0x43, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, \n\t0x05, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, \n\t0x07, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, \n\t0x0C, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, \n\t0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, \n\t0x10, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, \n\t0x06, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x50, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, \n\t0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, \n\t0x09, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, \n\t0x21, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, \n\t0x1B, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, \n\t0x07, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x91, 0x00, 0x05, 0x00, \n\t0x07, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, \n\t0x41, 0x00, 0x05, 0x00, 0x25, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, \n\t0x1A, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x26, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, \n\t0x41, 0x00, 0x05, 0x00, 0x29, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, \n\t0x28, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, \n\t0x2A, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, \n\t0x09, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, \n\t0x1F, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x1C, 0x00, 0x00, 0x00, \n\t0x2F, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x90, 0x00, 0x05, 0x00, 0x0A, 0x00, 0x00, 0x00, \n\t0x30, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, \n\t0x06, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, \n\t0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, \n\t0x34, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, \n\t0x0E, 0x00, 0x00, 0x00, 0x94, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, \n\t0x2B, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x36, 0x00, 0x00, 0x00, \n\t0x37, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, \n\t0x3E, 0x00, 0x03, 0x00, 0x37, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, \n\t0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, \n\t0x38, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x3C, 0x00, 0x00, 0x00, \n\t0x41, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x3E, 0x00, 0x00, 0x00, \n\t0x41, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, \n\t0x43, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x42, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, \n\t0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00\n};\nlong long multi_texture_clipping_plane_vert_spv_size = 2056;"
  },
  {
    "path": "src/engine/renderer/shaders/spirv/multi_texture_mul_frag.cpp",
    "content": "unsigned char multi_texture_mul_frag_spv[] = {\n\t0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x08, 0x00, 0x46, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x06, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x47, 0x4C, 0x53, 0x4C, 0x2E, 0x73, 0x74, 0x64, 0x2E, 0x34, 0x35, 0x30, \n\t0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x0F, 0x00, 0x09, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E, \n\t0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, \n\t0x1A, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0xC2, 0x01, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, \n\t0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, \n\t0x09, 0x00, 0x00, 0x00, 0x6F, 0x75, 0x74, 0x5F, 0x63, 0x6F, 0x6C, 0x6F, 0x72, 0x00, 0x00, 0x00, \n\t0x05, 0x00, 0x05, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x66, 0x72, 0x61, 0x67, 0x5F, 0x63, 0x6F, 0x6C, \n\t0x6F, 0x72, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x00, 0x74, 0x65, 0x78, 0x74, \n\t0x75, 0x72, 0x65, 0x30, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x14, 0x00, 0x00, 0x00, \n\t0x66, 0x72, 0x61, 0x67, 0x5F, 0x74, 0x65, 0x78, 0x5F, 0x63, 0x6F, 0x6F, 0x72, 0x64, 0x30, 0x00, \n\t0x05, 0x00, 0x05, 0x00, 0x18, 0x00, 0x00, 0x00, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x31, \n\t0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x66, 0x72, 0x61, 0x67, \n\t0x5F, 0x74, 0x65, 0x78, 0x5F, 0x63, 0x6F, 0x6F, 0x72, 0x64, 0x31, 0x00, 0x05, 0x00, 0x06, 0x00, \n\t0x1F, 0x00, 0x00, 0x00, 0x61, 0x6C, 0x70, 0x68, 0x61, 0x5F, 0x74, 0x65, 0x73, 0x74, 0x5F, 0x66, \n\t0x75, 0x6E, 0x63, 0x00, 0x47, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, \n\t0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, \n\t0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x03, 0x00, 0x0E, 0x00, 0x00, 0x00, \n\t0x0D, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x0E, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x12, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x12, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x32, 0x00, 0x04, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02, 0x00, 0x21, 0x00, 0x00, 0x00, 0x34, 0x00, 0x06, 0x00, \n\t0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0xAA, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, \n\t0x20, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x27, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x06, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x34, 0x00, 0x06, 0x00, 0x21, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, \n\t0xAA, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, \n\t0x06, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x2B, 0x00, 0x04, 0x00, \n\t0x1E, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x34, 0x00, 0x06, 0x00, \n\t0x21, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xAA, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, \n\t0x3C, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, \n\t0x3D, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, \n\t0x3D, 0x00, 0x04, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, \n\t0x3D, 0x00, 0x04, 0x00, 0x12, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, \n\t0x57, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, \n\t0x15, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, \n\t0x0C, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x0E, 0x00, 0x00, 0x00, \n\t0x19, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x12, 0x00, 0x00, 0x00, \n\t0x1B, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x57, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, \n\t0x1C, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, \n\t0x07, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, \n\t0x3E, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0xF7, 0x00, 0x03, 0x00, \n\t0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x04, 0x00, 0x22, 0x00, 0x00, 0x00, \n\t0x23, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x23, 0x00, 0x00, 0x00, \n\t0x41, 0x00, 0x05, 0x00, 0x27, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, \n\t0x26, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, \n\t0x28, 0x00, 0x00, 0x00, 0xB4, 0x00, 0x05, 0x00, 0x21, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, \n\t0x29, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0xF7, 0x00, 0x03, 0x00, 0x2D, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x04, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, \n\t0x2D, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x2C, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x01, 0x00, \n\t0xF8, 0x00, 0x02, 0x00, 0x2D, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, 0x24, 0x00, 0x00, 0x00, \n\t0xF8, 0x00, 0x02, 0x00, 0x2F, 0x00, 0x00, 0x00, 0xF7, 0x00, 0x03, 0x00, 0x33, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x04, 0x00, 0x31, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, \n\t0x3B, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x32, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, \n\t0x27, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, \n\t0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, \n\t0xBE, 0x00, 0x05, 0x00, 0x21, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, \n\t0x36, 0x00, 0x00, 0x00, 0xF7, 0x00, 0x03, 0x00, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0xFA, 0x00, 0x04, 0x00, 0x37, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, \n\t0xF8, 0x00, 0x02, 0x00, 0x38, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x01, 0x00, 0xF8, 0x00, 0x02, 0x00, \n\t0x39, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, 0x33, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, \n\t0x3B, 0x00, 0x00, 0x00, 0xF7, 0x00, 0x03, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0xFA, 0x00, 0x04, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, \n\t0xF8, 0x00, 0x02, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x27, 0x00, 0x00, 0x00, \n\t0x40, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, \n\t0x06, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0xB8, 0x00, 0x05, 0x00, \n\t0x21, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, \n\t0xF7, 0x00, 0x03, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x04, 0x00, \n\t0x42, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, \n\t0x43, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x01, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x44, 0x00, 0x00, 0x00, \n\t0xF9, 0x00, 0x02, 0x00, 0x3F, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x3F, 0x00, 0x00, 0x00, \n\t0xF9, 0x00, 0x02, 0x00, 0x33, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x33, 0x00, 0x00, 0x00, \n\t0xF9, 0x00, 0x02, 0x00, 0x24, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x24, 0x00, 0x00, 0x00, \n\t0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00\n};\nlong long multi_texture_mul_frag_spv_size = 1656;"
  },
  {
    "path": "src/engine/renderer/shaders/spirv/multi_texture_vert.cpp",
    "content": "unsigned char multi_texture_vert_spv[] = {\n\t0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x08, 0x00, 0x2D, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x06, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x47, 0x4C, 0x53, 0x4C, 0x2E, 0x73, 0x74, 0x64, 0x2E, 0x34, 0x35, 0x30, \n\t0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x0F, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E, \n\t0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, \n\t0x22, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, \n\t0x2B, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0xC2, 0x01, 0x00, 0x00, \n\t0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E, 0x00, 0x00, 0x00, 0x00, \n\t0x05, 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x50, 0x65, 0x72, 0x56, 0x65, \n\t0x72, 0x74, 0x65, 0x78, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x50, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x00, \n\t0x05, 0x00, 0x03, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, \n\t0x0E, 0x00, 0x00, 0x00, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x66, 0x6F, 0x72, 0x6D, 0x00, 0x00, 0x00, \n\t0x06, 0x00, 0x04, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6D, 0x76, 0x70, 0x00, \n\t0x05, 0x00, 0x03, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, \n\t0x16, 0x00, 0x00, 0x00, 0x69, 0x6E, 0x5F, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x00, \n\t0x05, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x66, 0x72, 0x61, 0x67, 0x5F, 0x63, 0x6F, 0x6C, \n\t0x6F, 0x72, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x22, 0x00, 0x00, 0x00, 0x69, 0x6E, 0x5F, 0x63, \n\t0x6F, 0x6C, 0x6F, 0x72, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x26, 0x00, 0x00, 0x00, \n\t0x66, 0x72, 0x61, 0x67, 0x5F, 0x74, 0x65, 0x78, 0x5F, 0x63, 0x6F, 0x6F, 0x72, 0x64, 0x30, 0x00, \n\t0x05, 0x00, 0x06, 0x00, 0x28, 0x00, 0x00, 0x00, 0x69, 0x6E, 0x5F, 0x74, 0x65, 0x78, 0x5F, 0x63, \n\t0x6F, 0x6F, 0x72, 0x64, 0x30, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x2A, 0x00, 0x00, 0x00, \n\t0x66, 0x72, 0x61, 0x67, 0x5F, 0x74, 0x65, 0x78, 0x5F, 0x63, 0x6F, 0x6F, 0x72, 0x64, 0x31, 0x00, \n\t0x05, 0x00, 0x06, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x69, 0x6E, 0x5F, 0x74, 0x65, 0x78, 0x5F, 0x63, \n\t0x6F, 0x6F, 0x72, 0x64, 0x31, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x08, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, \n\t0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x48, 0x00, 0x04, 0x00, 0x0E, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x0E, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, \n\t0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, \n\t0x47, 0x00, 0x03, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, \n\t0x16, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, \n\t0x20, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, \n\t0x22, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, \n\t0x26, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, \n\t0x28, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, \n\t0x2A, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, \n\t0x2B, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, \n\t0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x03, 0x00, \n\t0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, \n\t0x0A, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x0B, 0x00, 0x00, 0x00, \n\t0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x0B, 0x00, 0x00, 0x00, \n\t0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x04, 0x00, 0x0D, 0x00, 0x00, 0x00, \n\t0x07, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x03, 0x00, 0x0E, 0x00, 0x00, 0x00, \n\t0x0D, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, \n\t0x0E, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, \n\t0x09, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x11, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, \n\t0x0D, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x14, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x80, 0x3F, 0x20, 0x00, 0x04, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x21, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x24, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x24, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x27, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x24, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x27, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x27, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, \n\t0x41, 0x00, 0x05, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, \n\t0x0C, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, \n\t0x12, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, \n\t0x16, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, \n\t0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, \n\t0x1A, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, \n\t0x06, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x50, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, \n\t0x1A, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x91, 0x00, 0x05, 0x00, \n\t0x07, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, \n\t0x41, 0x00, 0x05, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, \n\t0x0C, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, \n\t0x3D, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, \n\t0x3E, 0x00, 0x03, 0x00, 0x20, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, \n\t0x24, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, \n\t0x26, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x24, 0x00, 0x00, 0x00, \n\t0x2C, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x2A, 0x00, 0x00, 0x00, \n\t0x2C, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00\n};\nlong long multi_texture_vert_spv_size = 1372;"
  },
  {
    "path": "src/engine/renderer/shaders/spirv/single_texture_clipping_plane_vert.cpp",
    "content": "unsigned char single_texture_clipping_plane_vert_spv[] = {\n\t0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x08, 0x00, 0x42, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, \n\t0x20, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x4C, 0x53, 0x4C, \n\t0x2E, 0x73, 0x74, 0x64, 0x2E, 0x34, 0x35, 0x30, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x03, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, \n\t0x18, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, \n\t0x40, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0xC2, 0x01, 0x00, 0x00, \n\t0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E, 0x00, 0x00, 0x00, 0x00, \n\t0x05, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, \n\t0x0C, 0x00, 0x00, 0x00, 0x69, 0x6E, 0x5F, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x00, \n\t0x05, 0x00, 0x06, 0x00, 0x16, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x50, 0x65, 0x72, 0x56, 0x65, \n\t0x72, 0x74, 0x65, 0x78, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x16, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x50, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x00, \n\t0x06, 0x00, 0x07, 0x00, 0x16, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x43, \n\t0x6C, 0x69, 0x70, 0x44, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x00, 0x05, 0x00, 0x03, 0x00, \n\t0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x1D, 0x00, 0x00, 0x00, \n\t0x54, 0x72, 0x61, 0x6E, 0x73, 0x66, 0x6F, 0x72, 0x6D, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, \n\t0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x6C, 0x69, 0x70, 0x5F, 0x73, 0x70, 0x61, \n\t0x63, 0x65, 0x5F, 0x78, 0x66, 0x6F, 0x72, 0x6D, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x07, 0x00, \n\t0x1D, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x65, 0x79, 0x65, 0x5F, 0x73, 0x70, 0x61, 0x63, \n\t0x65, 0x5F, 0x78, 0x66, 0x6F, 0x72, 0x6D, 0x00, 0x06, 0x00, 0x07, 0x00, 0x1D, 0x00, 0x00, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x63, 0x6C, 0x69, 0x70, 0x70, 0x69, 0x6E, 0x67, 0x5F, 0x70, 0x6C, 0x61, \n\t0x6E, 0x65, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x05, 0x00, 0x05, 0x00, 0x38, 0x00, 0x00, 0x00, 0x66, 0x72, 0x61, 0x67, 0x5F, 0x63, 0x6F, 0x6C, \n\t0x6F, 0x72, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x69, 0x6E, 0x5F, 0x63, \n\t0x6F, 0x6C, 0x6F, 0x72, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x3E, 0x00, 0x00, 0x00, \n\t0x66, 0x72, 0x61, 0x67, 0x5F, 0x74, 0x65, 0x78, 0x5F, 0x63, 0x6F, 0x6F, 0x72, 0x64, 0x00, 0x00, \n\t0x05, 0x00, 0x06, 0x00, 0x40, 0x00, 0x00, 0x00, 0x69, 0x6E, 0x5F, 0x74, 0x65, 0x78, 0x5F, 0x63, \n\t0x6F, 0x6F, 0x72, 0x64, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x0C, 0x00, 0x00, 0x00, \n\t0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x16, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, \n\t0x16, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x47, 0x00, 0x03, 0x00, 0x16, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x48, 0x00, 0x04, 0x00, \n\t0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, \n\t0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x48, 0x00, 0x05, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, \n\t0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x04, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x05, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x23, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x1D, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, \n\t0x1D, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, \n\t0x47, 0x00, 0x03, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, \n\t0x38, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, \n\t0x3A, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, \n\t0x3E, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, \n\t0x40, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, \n\t0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, \n\t0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, \n\t0x0A, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, \n\t0x0B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, \n\t0x0B, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, \n\t0x06, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3F, 0x15, 0x00, 0x04, 0x00, \n\t0x13, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, \n\t0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x04, 0x00, \n\t0x15, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x04, 0x00, \n\t0x16, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, \n\t0x17, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, \n\t0x17, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, \n\t0x19, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, \n\t0x19, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x04, 0x00, \n\t0x1B, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x18, 0x00, 0x04, 0x00, \n\t0x1C, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x05, 0x00, \n\t0x1D, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, \n\t0x20, 0x00, 0x04, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, \n\t0x3B, 0x00, 0x04, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, \n\t0x20, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, \n\t0x20, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, \n\t0x2B, 0x00, 0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x2B, 0x00, 0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x20, 0x00, 0x04, 0x00, 0x29, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, \n\t0x20, 0x00, 0x04, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, \n\t0x20, 0x00, 0x04, 0x00, 0x36, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, \n\t0x3B, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x20, 0x00, 0x04, 0x00, 0x39, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, \n\t0x3B, 0x00, 0x04, 0x00, 0x39, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x17, 0x00, 0x04, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x20, 0x00, 0x04, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, \n\t0x3B, 0x00, 0x04, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x20, 0x00, 0x04, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, \n\t0x3B, 0x00, 0x04, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, \n\t0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, \n\t0x0A, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, \n\t0x06, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, \n\t0x0D, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, \n\t0x12, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, \n\t0x0E, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, \n\t0x41, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, \n\t0x1A, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, \n\t0x21, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, \n\t0x09, 0x00, 0x00, 0x00, 0x91, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, \n\t0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x25, 0x00, 0x00, 0x00, \n\t0x26, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, \n\t0x26, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x29, 0x00, 0x00, 0x00, \n\t0x2A, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, \n\t0x07, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, \n\t0x07, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, \n\t0x2D, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, \n\t0x3D, 0x00, 0x04, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, \n\t0x90, 0x00, 0x05, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, \n\t0x2F, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, \n\t0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, \n\t0x32, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, \n\t0x06, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x50, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, \n\t0x32, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x94, 0x00, 0x05, 0x00, \n\t0x06, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, \n\t0x41, 0x00, 0x06, 0x00, 0x36, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, \n\t0x27, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x37, 0x00, 0x00, 0x00, \n\t0x35, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, \n\t0x3A, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x38, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, \n\t0x3D, 0x00, 0x04, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, \n\t0x3E, 0x00, 0x03, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x01, 0x00, \n\t0x38, 0x00, 0x01, 0x00\n};\nlong long single_texture_clipping_plane_vert_spv_size = 1908;"
  },
  {
    "path": "src/engine/renderer/shaders/spirv/single_texture_frag.cpp",
    "content": "unsigned char single_texture_frag_spv[] = {\n\t0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x08, 0x00, 0x40, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x06, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x47, 0x4C, 0x53, 0x4C, 0x2E, 0x73, 0x74, 0x64, 0x2E, 0x34, 0x35, 0x30, \n\t0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x0F, 0x00, 0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E, \n\t0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, \n\t0x10, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0xC2, 0x01, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, \n\t0x6D, 0x61, 0x69, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, \n\t0x6F, 0x75, 0x74, 0x5F, 0x63, 0x6F, 0x6C, 0x6F, 0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, \n\t0x0B, 0x00, 0x00, 0x00, 0x66, 0x72, 0x61, 0x67, 0x5F, 0x63, 0x6F, 0x6C, 0x6F, 0x72, 0x00, 0x00, \n\t0x05, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x00, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x30, \n\t0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x14, 0x00, 0x00, 0x00, 0x66, 0x72, 0x61, 0x67, \n\t0x5F, 0x74, 0x65, 0x78, 0x5F, 0x63, 0x6F, 0x6F, 0x72, 0x64, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, \n\t0x19, 0x00, 0x00, 0x00, 0x61, 0x6C, 0x70, 0x68, 0x61, 0x5F, 0x74, 0x65, 0x73, 0x74, 0x5F, 0x66, \n\t0x75, 0x6E, 0x63, 0x00, 0x47, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, \n\t0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, \n\t0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x03, 0x00, 0x0E, 0x00, 0x00, 0x00, \n\t0x0D, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x0E, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x12, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x12, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x32, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x34, 0x00, 0x06, 0x00, \n\t0x1B, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0xAA, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, \n\t0x1A, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x21, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x06, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x34, 0x00, 0x06, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, \n\t0xAA, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, \n\t0x06, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x2B, 0x00, 0x04, 0x00, \n\t0x18, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x34, 0x00, 0x06, 0x00, \n\t0x1B, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0xAA, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, \n\t0x36, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, \n\t0x3D, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, \n\t0x3D, 0x00, 0x04, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, \n\t0x3D, 0x00, 0x04, 0x00, 0x12, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, \n\t0x57, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, \n\t0x15, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, \n\t0x0C, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, \n\t0x17, 0x00, 0x00, 0x00, 0xF7, 0x00, 0x03, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0xFA, 0x00, 0x04, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, \n\t0xF8, 0x00, 0x02, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x21, 0x00, 0x00, 0x00, \n\t0x22, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, \n\t0x06, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0xB4, 0x00, 0x05, 0x00, \n\t0x1B, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, \n\t0xF7, 0x00, 0x03, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x04, 0x00, \n\t0x25, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, \n\t0x26, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x01, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x27, 0x00, 0x00, 0x00, \n\t0xF9, 0x00, 0x02, 0x00, 0x1E, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x29, 0x00, 0x00, 0x00, \n\t0xF7, 0x00, 0x03, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x04, 0x00, \n\t0x2B, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, \n\t0x2C, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x21, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, \n\t0x09, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, \n\t0x2F, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0xBE, 0x00, 0x05, 0x00, 0x1B, 0x00, 0x00, 0x00, \n\t0x31, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0xF7, 0x00, 0x03, 0x00, \n\t0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x04, 0x00, 0x31, 0x00, 0x00, 0x00, \n\t0x32, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x32, 0x00, 0x00, 0x00, \n\t0xFC, 0x00, 0x01, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x33, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, \n\t0x2D, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x35, 0x00, 0x00, 0x00, 0xF7, 0x00, 0x03, 0x00, \n\t0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x04, 0x00, 0x37, 0x00, 0x00, 0x00, \n\t0x38, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x38, 0x00, 0x00, 0x00, \n\t0x41, 0x00, 0x05, 0x00, 0x21, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, \n\t0x20, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, \n\t0x3A, 0x00, 0x00, 0x00, 0xB8, 0x00, 0x05, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, \n\t0x3B, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0xF7, 0x00, 0x03, 0x00, 0x3E, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x04, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x00, 0x00, \n\t0x3E, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x01, 0x00, \n\t0xF8, 0x00, 0x02, 0x00, 0x3E, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, 0x39, 0x00, 0x00, 0x00, \n\t0xF8, 0x00, 0x02, 0x00, 0x39, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, 0x2D, 0x00, 0x00, 0x00, \n\t0xF8, 0x00, 0x02, 0x00, 0x2D, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, 0x1E, 0x00, 0x00, 0x00, \n\t0xF8, 0x00, 0x02, 0x00, 0x1E, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00\n\t\n};\nlong long single_texture_frag_spv_size = 1456;"
  },
  {
    "path": "src/engine/renderer/shaders/spirv/single_texture_vert.cpp",
    "content": "unsigned char single_texture_vert_spv[] = {\n\t0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x08, 0x00, 0x2A, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x06, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x47, 0x4C, 0x53, 0x4C, 0x2E, 0x73, 0x74, 0x64, 0x2E, 0x34, 0x35, 0x30, \n\t0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x0F, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E, \n\t0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, \n\t0x22, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0xC2, 0x01, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, \n\t0x6D, 0x61, 0x69, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00, \n\t0x67, 0x6C, 0x5F, 0x50, 0x65, 0x72, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x00, 0x00, 0x00, 0x00, \n\t0x06, 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x50, \n\t0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x00, 0x05, 0x00, 0x03, 0x00, 0x0A, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x54, 0x72, 0x61, 0x6E, \n\t0x73, 0x66, 0x6F, 0x72, 0x6D, 0x00, 0x00, 0x00, 0x06, 0x00, 0x04, 0x00, 0x0E, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x6D, 0x76, 0x70, 0x00, 0x05, 0x00, 0x03, 0x00, 0x10, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x16, 0x00, 0x00, 0x00, 0x69, 0x6E, 0x5F, 0x70, \n\t0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x00, 0x05, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, \n\t0x66, 0x72, 0x61, 0x67, 0x5F, 0x63, 0x6F, 0x6C, 0x6F, 0x72, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, \n\t0x22, 0x00, 0x00, 0x00, 0x69, 0x6E, 0x5F, 0x63, 0x6F, 0x6C, 0x6F, 0x72, 0x00, 0x00, 0x00, 0x00, \n\t0x05, 0x00, 0x06, 0x00, 0x26, 0x00, 0x00, 0x00, 0x66, 0x72, 0x61, 0x67, 0x5F, 0x74, 0x65, 0x78, \n\t0x5F, 0x63, 0x6F, 0x6F, 0x72, 0x64, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x28, 0x00, 0x00, 0x00, \n\t0x69, 0x6E, 0x5F, 0x74, 0x65, 0x78, 0x5F, 0x63, 0x6F, 0x6F, 0x72, 0x64, 0x00, 0x00, 0x00, 0x00, \n\t0x48, 0x00, 0x05, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, \n\t0x48, 0x00, 0x04, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, \n\t0x48, 0x00, 0x05, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x07, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x0E, 0x00, 0x00, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, \n\t0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x22, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x26, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, \n\t0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, \n\t0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, \n\t0x04, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, \n\t0x20, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, \n\t0x3B, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0x15, 0x00, 0x04, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, \n\t0x2B, 0x00, 0x04, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x18, 0x00, 0x04, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, \n\t0x1E, 0x00, 0x03, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, \n\t0x0F, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, \n\t0x0F, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, \n\t0x11, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, \n\t0x14, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, \n\t0x15, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, \n\t0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, \n\t0x06, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3F, 0x20, 0x00, 0x04, 0x00, \n\t0x1E, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, \n\t0x1E, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, \n\t0x21, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, \n\t0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, \n\t0x24, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, \n\t0x25, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, \n\t0x25, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, \n\t0x27, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, \n\t0x27, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, \n\t0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, \n\t0xF8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x11, 0x00, 0x00, 0x00, \n\t0x12, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, \n\t0x0D, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, \n\t0x14, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, \n\t0x06, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, \n\t0x01, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, \n\t0x17, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, \n\t0x1C, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, \n\t0x18, 0x00, 0x00, 0x00, 0x91, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, \n\t0x13, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x1E, 0x00, 0x00, 0x00, \n\t0x1F, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, \n\t0x1F, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, \n\t0x23, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x20, 0x00, 0x00, 0x00, \n\t0x23, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x24, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, \n\t0x28, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x26, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, \n\t0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00\n};\nlong long single_texture_vert_spv_size = 1224;"
  },
  {
    "path": "src/engine/renderer/tr_animation.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n#include \"tr_local.h\"\n\n/*\n\nAll bones should be an identity orientation to display the mesh exactly\nas it is specified.\n\nFor all other frames, the bones represent the transformation from the \norientation of the bone in the base frame to the orientation in this\nframe.\n\n*/\n\n/*\n==============\nR_AddAnimSurfaces\n==============\n*/\nvoid R_AddAnimSurfaces( trRefEntity_t *ent ) {\n\tmd4Header_t\t\t*header;\n\tmd4Surface_t\t*surface;\n\tmd4LOD_t\t\t*lod;\n\tshader_t\t\t*shader;\n\tint\t\t\t\ti;\n\n\theader = tr.currentModel->md4;\n\tlod = (md4LOD_t *)( (byte *)header + header->ofsLODs );\n\n\tsurface = (md4Surface_t *)( (byte *)lod + lod->ofsSurfaces );\n\tfor ( i = 0 ; i < lod->numSurfaces ; i++ ) {\n\t\tshader = R_GetShaderByHandle( surface->shaderIndex );\n\t\tR_AddDrawSurf( (surfaceType_t*) (void *)surface, shader, 0 /*fogNum*/, qfalse );\n\t\tsurface = (md4Surface_t *)( (byte *)surface + surface->ofsEnd );\n\t}\n}\n\n\n/*\n==============\nRB_SurfaceAnim\n==============\n*/\nvoid RB_SurfaceAnim( md4Surface_t *surface ) {\n\tint\t\t\t\ti, j, k;\n\tfloat\t\t\tfrontlerp, backlerp;\n\tint\t\t\t\t*triangles;\n\tint\t\t\t\tindexes;\n\tint\t\t\t\tbaseIndex, baseVertex;\n\tint\t\t\t\tnumVerts;\n\tmd4Vertex_t\t\t*v;\n\tmd4Bone_t\t\tbones[MD4_MAX_BONES];\n\tmd4Bone_t\t\t*bonePtr, *bone;\n\tmd4Header_t\t\t*header;\n\tmd4Frame_t\t\t*frame;\n\tmd4Frame_t\t\t*oldFrame;\n\tint\t\t\t\tframeSize;\n\n\n\tif (  backEnd.currentEntity->e.oldframe == backEnd.currentEntity->e.frame ) {\n\t\tbacklerp = 0;\n\t\tfrontlerp = 1;\n\t} else  {\n\t\tbacklerp = backEnd.currentEntity->e.backlerp;\n\t\tfrontlerp = 1.0f - backlerp;\n\t}\n\theader = (md4Header_t *)((byte *)surface + surface->ofsHeader);\n\n\tframeSize = (int)(intptr_t)( &((md4Frame_t *)0)->bones[ header->numBones ] );\n\n\tframe = (md4Frame_t *)((byte *)header + header->ofsFrames + \n\t\tbackEnd.currentEntity->e.frame * frameSize );\n\toldFrame = (md4Frame_t *)((byte *)header + header->ofsFrames + \n\t\tbackEnd.currentEntity->e.oldframe * frameSize );\n\n\tRB_CheckOverflow( surface->numVerts, surface->numTriangles * 3 );\n\n\ttriangles = (int *) ((byte *)surface + surface->ofsTriangles);\n\tindexes = surface->numTriangles * 3;\n\tbaseIndex = tess.numIndexes;\n\tbaseVertex = tess.numVertexes;\n\tfor (j = 0 ; j < indexes ; j++) {\n\t\ttess.indexes[baseIndex + j] = baseIndex + triangles[j];\n\t}\n\ttess.numIndexes += indexes;\n\n\t//\n\t// lerp all the needed bones\n\t//\n\tif ( !backlerp ) {\n\t\t// no lerping needed\n\t\tbonePtr = frame->bones;\n\t} else {\n\t\tbonePtr = bones;\n\t\tfor ( i = 0 ; i < header->numBones*12 ; i++ ) {\n\t\t\t((float *)bonePtr)[i] = frontlerp * ((float *)frame->bones)[i]\n\t\t\t\t+ backlerp * ((float *)oldFrame->bones)[i];\n\t\t}\n\t}\n\n\t//\n\t// deform the vertexes by the lerped bones\n\t//\n\tnumVerts = surface->numVerts;\n\t// FIXME\n\t// This makes TFC's skeletons work.  Shouldn't be necessary anymore, but left\n\t// in for reference.\n\t//v = (md4Vertex_t *) ((byte *)surface + surface->ofsVerts + 12);\n\tv = (md4Vertex_t *) ((byte *)surface + surface->ofsVerts);\n\tfor ( j = 0; j < numVerts; j++ ) {\n\t\tvec3_t\ttempVert, tempNormal;\n\t\tmd4Weight_t\t*w;\n\n\t\tVectorClear( tempVert );\n\t\tVectorClear( tempNormal );\n\t\tw = v->weights;\n\t\tfor ( k = 0 ; k < v->numWeights ; k++, w++ ) {\n\t\t\tbone = bonePtr + w->boneIndex;\n\n\t\t\ttempVert[0] += w->boneWeight * ( DotProduct( bone->matrix[0], w->offset ) + bone->matrix[0][3] );\n\t\t\ttempVert[1] += w->boneWeight * ( DotProduct( bone->matrix[1], w->offset ) + bone->matrix[1][3] );\n\t\t\ttempVert[2] += w->boneWeight * ( DotProduct( bone->matrix[2], w->offset ) + bone->matrix[2][3] );\n\n\t\t\ttempNormal[0] += w->boneWeight * DotProduct( bone->matrix[0], v->normal );\n\t\t\ttempNormal[1] += w->boneWeight * DotProduct( bone->matrix[1], v->normal );\n\t\t\ttempNormal[2] += w->boneWeight * DotProduct( bone->matrix[2], v->normal );\n\t\t}\n\n\t\ttess.xyz[baseVertex + j][0] = tempVert[0];\n\t\ttess.xyz[baseVertex + j][1] = tempVert[1];\n\t\ttess.xyz[baseVertex + j][2] = tempVert[2];\n\n\t\ttess.normal[baseVertex + j][0] = tempNormal[0];\n\t\ttess.normal[baseVertex + j][1] = tempNormal[1];\n\t\ttess.normal[baseVertex + j][2] = tempNormal[2];\n\n\t\ttess.texCoords[baseVertex + j][0][0] = v->texCoords[0];\n\t\ttess.texCoords[baseVertex + j][0][1] = v->texCoords[1];\n\n\t\t// FIXME\n\t\t// This makes TFC's skeletons work.  Shouldn't be necessary anymore, but left\n\t\t// in for reference.\n\t\t//v = (md4Vertex_t *)( ( byte * )&v->weights[v->numWeights] + 12 );\n\t\tv = (md4Vertex_t *)&v->weights[v->numWeights];\n\t}\n\n\ttess.numVertexes += surface->numVerts;\n}\n\n\n"
  },
  {
    "path": "src/engine/renderer/tr_backend.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n#include \"tr_local.h\"\n\n// DX12\n#include \"d3d12.h\"\n\nbackEndData_t\t*backEndData[SMP_FRAMES];\nbackEndState_t\tbackEnd;\n\n\nstatic float\ts_flipMatrix[16] = {\n\t// convert from our coordinate system (looking down X)\n\t// to OpenGL's coordinate system (looking down -Z)\n\t0, 0, -1, 0,\n\t-1, 0, 0, 0,\n\t0, 1, 0, 0,\n\t0, 0, 0, 1\n};\n\n#ifdef _DEBUG\nstatic float fast_sky_color[4] = { 0.8f, 0.7f, 0.4f, 1.0f };\n#else\nstatic float fast_sky_color[4] = { 0.0f, 0.0f, 0.0f, 1.0f };\n#endif\n\n\n/*\n** GL_Bind\n*/\nvoid GL_Bind( image_t *image ) {\n    image_t* final_image = image;\n\n\tif (!final_image) {\n\t\tri.Printf( PRINT_WARNING, \"GL_Bind: NULL image\\n\" );\n\t\tfinal_image = tr.defaultImage;\n\t}\n\n\tif ( r_nobind->integer && tr.dlightImage ) {\t\t// performance evaluation option\n\t\tfinal_image = tr.dlightImage;\n\t}\n\n    int texnum = final_image->texnum;\n\n\tif ( glState.currenttextures[glState.currenttmu] != texnum ) {\n\t\timage->frameUsed = tr.frameCount;\n\t\tglState.currenttextures[glState.currenttmu] = texnum;\n\t\tqglBindTexture (GL_TEXTURE_2D, texnum);\n\n\t\t// VULKAN\n\t\tif (vk.active) {\n\t\t\tVkDescriptorSet set = vk_world.images[final_image->index].descriptor_set;\n\t\t\tvk_world.current_descriptor_sets[glState.currenttmu] = set;\n\t\t}\n\t\t// DX12\n\t\tif (dx.active) {\n\t\t\tdx_world.current_image_indices[glState.currenttmu] = final_image->index;\n\t\t}\n\t}\n}\n\n/*\n** GL_SelectTexture\n*/\nvoid GL_SelectTexture( int unit )\n{\n\tif ( glState.currenttmu == unit )\n\t{\n\t\treturn;\n\t}\n\n\tif ( unit == 0 )\n\t{\n\t\tqglActiveTextureARB( GL_TEXTURE0_ARB );\n\t\tGLimp_LogComment( \"glActiveTextureARB( GL_TEXTURE0_ARB )\\n\" );\n\t\tqglClientActiveTextureARB( GL_TEXTURE0_ARB );\n\t\tGLimp_LogComment( \"glClientActiveTextureARB( GL_TEXTURE0_ARB )\\n\" );\n\t}\n\telse if ( unit == 1 )\n\t{\n\t\tqglActiveTextureARB( GL_TEXTURE1_ARB );\n\t\tGLimp_LogComment( \"glActiveTextureARB( GL_TEXTURE1_ARB )\\n\" );\n\t\tqglClientActiveTextureARB( GL_TEXTURE1_ARB );\n\t\tGLimp_LogComment( \"glClientActiveTextureARB( GL_TEXTURE1_ARB )\\n\" );\n\t} else {\n\t\tri.Error( ERR_DROP, \"GL_SelectTexture: unit = %i\", unit );\n\t}\n\n\tglState.currenttmu = unit;\n}\n\n/*\n** GL_Cull\n*/\nvoid GL_Cull( int cullType ) {\n\tif ( glState.faceCulling == cullType ) {\n\t\treturn;\n\t}\n\n\tglState.faceCulling = cullType;\n\n\tif ( cullType == CT_TWO_SIDED ) \n\t{\n\t\tqglDisable( GL_CULL_FACE );\n\t} \n\telse \n\t{\n\t\tqglEnable( GL_CULL_FACE );\n\n\t\tif ( cullType == CT_BACK_SIDED )\n\t\t{\n\t\t\tif ( backEnd.viewParms.isMirror )\n\t\t\t{\n\t\t\t\tqglCullFace( GL_FRONT );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tqglCullFace( GL_BACK );\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ( backEnd.viewParms.isMirror )\n\t\t\t{\n\t\t\t\tqglCullFace( GL_BACK );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tqglCullFace( GL_FRONT );\n\t\t\t}\n\t\t}\n\t}\n}\n\n/*\n** GL_TexEnv\n*/\nvoid GL_TexEnv( int env )\n{\n\tif ( env == glState.texEnv[glState.currenttmu] )\n\t{\n\t\treturn;\n\t}\n\n\tglState.texEnv[glState.currenttmu] = env;\n\n\n\tswitch ( env )\n\t{\n\tcase GL_MODULATE:\n\t\tqglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );\n\t\tbreak;\n\tcase GL_REPLACE:\n\t\tqglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );\n\t\tbreak;\n\tcase GL_ADD:\n\t\tqglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD );\n\t\tbreak;\n\tdefault:\n\t\tri.Error( ERR_DROP, \"GL_TexEnv: invalid env '%d' passed\\n\", env );\n\t\tbreak;\n\t}\n}\n\n/*\n** GL_State\n**\n** This routine is responsible for setting the most commonly changed state\n** in Q3.\n*/\nvoid GL_State( unsigned long stateBits )\n{\n\tunsigned long diff = stateBits ^ glState.glStateBits;\n\n\tif ( !diff )\n\t{\n\t\treturn;\n\t}\n\n\t//\n\t// check depthFunc bits\n\t//\n\tif ( diff & GLS_DEPTHFUNC_EQUAL )\n\t{\n\t\tif ( stateBits & GLS_DEPTHFUNC_EQUAL )\n\t\t{\n\t\t\tqglDepthFunc( GL_EQUAL );\n\t\t}\n\t\telse\n\t\t{\n\t\t\tqglDepthFunc( GL_LEQUAL );\n\t\t}\n\t}\n\n\t//\n\t// check blend bits\n\t//\n\tif ( diff & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) )\n\t{\n\t\tGLenum srcFactor, dstFactor;\n\n\t\tif ( stateBits & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) )\n\t\t{\n\t\t\tswitch ( stateBits & GLS_SRCBLEND_BITS )\n\t\t\t{\n\t\t\tcase GLS_SRCBLEND_ZERO:\n\t\t\t\tsrcFactor = GL_ZERO;\n\t\t\t\tbreak;\n\t\t\tcase GLS_SRCBLEND_ONE:\n\t\t\t\tsrcFactor = GL_ONE;\n\t\t\t\tbreak;\n\t\t\tcase GLS_SRCBLEND_DST_COLOR:\n\t\t\t\tsrcFactor = GL_DST_COLOR;\n\t\t\t\tbreak;\n\t\t\tcase GLS_SRCBLEND_ONE_MINUS_DST_COLOR:\n\t\t\t\tsrcFactor = GL_ONE_MINUS_DST_COLOR;\n\t\t\t\tbreak;\n\t\t\tcase GLS_SRCBLEND_SRC_ALPHA:\n\t\t\t\tsrcFactor = GL_SRC_ALPHA;\n\t\t\t\tbreak;\n\t\t\tcase GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA:\n\t\t\t\tsrcFactor = GL_ONE_MINUS_SRC_ALPHA;\n\t\t\t\tbreak;\n\t\t\tcase GLS_SRCBLEND_DST_ALPHA:\n\t\t\t\tsrcFactor = GL_DST_ALPHA;\n\t\t\t\tbreak;\n\t\t\tcase GLS_SRCBLEND_ONE_MINUS_DST_ALPHA:\n\t\t\t\tsrcFactor = GL_ONE_MINUS_DST_ALPHA;\n\t\t\t\tbreak;\n\t\t\tcase GLS_SRCBLEND_ALPHA_SATURATE:\n\t\t\t\tsrcFactor = GL_SRC_ALPHA_SATURATE;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tsrcFactor = GL_ONE;\t\t// to get warning to shut up\n\t\t\t\tri.Error( ERR_DROP, \"GL_State: invalid src blend state bits\\n\" );\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tswitch ( stateBits & GLS_DSTBLEND_BITS )\n\t\t\t{\n\t\t\tcase GLS_DSTBLEND_ZERO:\n\t\t\t\tdstFactor = GL_ZERO;\n\t\t\t\tbreak;\n\t\t\tcase GLS_DSTBLEND_ONE:\n\t\t\t\tdstFactor = GL_ONE;\n\t\t\t\tbreak;\n\t\t\tcase GLS_DSTBLEND_SRC_COLOR:\n\t\t\t\tdstFactor = GL_SRC_COLOR;\n\t\t\t\tbreak;\n\t\t\tcase GLS_DSTBLEND_ONE_MINUS_SRC_COLOR:\n\t\t\t\tdstFactor = GL_ONE_MINUS_SRC_COLOR;\n\t\t\t\tbreak;\n\t\t\tcase GLS_DSTBLEND_SRC_ALPHA:\n\t\t\t\tdstFactor = GL_SRC_ALPHA;\n\t\t\t\tbreak;\n\t\t\tcase GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA:\n\t\t\t\tdstFactor = GL_ONE_MINUS_SRC_ALPHA;\n\t\t\t\tbreak;\n\t\t\tcase GLS_DSTBLEND_DST_ALPHA:\n\t\t\t\tdstFactor = GL_DST_ALPHA;\n\t\t\t\tbreak;\n\t\t\tcase GLS_DSTBLEND_ONE_MINUS_DST_ALPHA:\n\t\t\t\tdstFactor = GL_ONE_MINUS_DST_ALPHA;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tdstFactor = GL_ONE;\t\t// to get warning to shut up\n\t\t\t\tri.Error( ERR_DROP, \"GL_State: invalid dst blend state bits\\n\" );\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tqglEnable( GL_BLEND );\n\t\t\tqglBlendFunc( srcFactor, dstFactor );\n\t\t}\n\t\telse\n\t\t{\n\t\t\tqglDisable( GL_BLEND );\n\t\t}\n\t}\n\n\t//\n\t// check depthmask\n\t//\n\tif ( diff & GLS_DEPTHMASK_TRUE )\n\t{\n\t\tif ( stateBits & GLS_DEPTHMASK_TRUE )\n\t\t{\n\t\t\tqglDepthMask( GL_TRUE );\n\t\t}\n\t\telse\n\t\t{\n\t\t\tqglDepthMask( GL_FALSE );\n\t\t}\n\t}\n\n\t//\n\t// fill/line mode\n\t//\n\tif ( diff & GLS_POLYMODE_LINE )\n\t{\n\t\tif ( stateBits & GLS_POLYMODE_LINE )\n\t\t{\n\t\t\tqglPolygonMode( GL_FRONT_AND_BACK, GL_LINE );\n\t\t}\n\t\telse\n\t\t{\n\t\t\tqglPolygonMode( GL_FRONT_AND_BACK, GL_FILL );\n\t\t}\n\t}\n\n\t//\n\t// depthtest\n\t//\n\tif ( diff & GLS_DEPTHTEST_DISABLE )\n\t{\n\t\tif ( stateBits & GLS_DEPTHTEST_DISABLE )\n\t\t{\n\t\t\tqglDisable( GL_DEPTH_TEST );\n\t\t}\n\t\telse\n\t\t{\n\t\t\tqglEnable( GL_DEPTH_TEST );\n\t\t}\n\t}\n\n\t//\n\t// alpha test\n\t//\n\tif ( diff & GLS_ATEST_BITS )\n\t{\n\t\tswitch ( stateBits & GLS_ATEST_BITS )\n\t\t{\n\t\tcase 0:\n\t\t\tqglDisable( GL_ALPHA_TEST );\n\t\t\tbreak;\n\t\tcase GLS_ATEST_GT_0:\n\t\t\tqglEnable( GL_ALPHA_TEST );\n\t\t\tqglAlphaFunc( GL_GREATER, 0.0f );\n\t\t\tbreak;\n\t\tcase GLS_ATEST_LT_80:\n\t\t\tqglEnable( GL_ALPHA_TEST );\n\t\t\tqglAlphaFunc( GL_LESS, 0.5f );\n\t\t\tbreak;\n\t\tcase GLS_ATEST_GE_80:\n\t\t\tqglEnable( GL_ALPHA_TEST );\n\t\t\tqglAlphaFunc( GL_GEQUAL, 0.5f );\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tassert( 0 );\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tglState.glStateBits = stateBits;\n}\n\n\n\n/*\n================\nRB_Hyperspace\n\nA player has predicted a teleport, but hasn't arrived yet\n================\n*/\nstatic void RB_Hyperspace( void ) {\n\tfloat c = ( backEnd.refdef.time & 255 ) / 255.0f;\n\tqglClearColor( c, c, c, 1 );\n\tqglClear( GL_COLOR_BUFFER_BIT );\n\n\tfloat color[4] = { c, c, c, 1 };\n\n\t// VULKAN\n\tvk_clear_attachments(false, true, color);\n\n\t// DX12\n\tdx_clear_attachments(false, true, color);\n\n\tbackEnd.isHyperspace = qtrue;\n}\n\n\nstatic void SetViewportAndScissor( void ) {\n\tqglMatrixMode(GL_PROJECTION);\n\tqglLoadMatrixf( backEnd.viewParms.projectionMatrix );\n\tqglMatrixMode(GL_MODELVIEW);\n\n\t// set the window clipping\n\tqglViewport( backEnd.viewParms.viewportX, backEnd.viewParms.viewportY, \n\t\tbackEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight );\n\tqglScissor( backEnd.viewParms.viewportX, backEnd.viewParms.viewportY, \n\t\tbackEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight );\n}\n\n/*\n=================\nRB_BeginDrawingView\n\nAny mirrored or portaled views have already been drawn, so prepare\nto actually render the visible surfaces for this view\n=================\n*/\nvoid RB_BeginDrawingView (void) {\n\t// we will need to change the projection matrix before drawing\n\t// 2D images again\n\tbackEnd.projection2D = qfalse;\n\n\t//\n\t// set the modelview matrix for the viewer\n\t//\n\tSetViewportAndScissor();\n\n\t// ensures that depth writes are enabled for the depth clear\n\tGL_State( GLS_DEFAULT );\n\t// clear relevant buffers\n\tint clearBits = GL_DEPTH_BUFFER_BIT;\n\n    bool clear_stencil = (r_shadows->integer == 2);\n\tif ( clear_stencil )\n\t{\n\t\tclearBits |= GL_STENCIL_BUFFER_BIT;\n\t}\n\n    bool fast_sky = r_fastsky->integer && !( backEnd.refdef.rdflags & RDF_NOWORLDMODEL );\n\tif ( fast_sky )\n\t{\n\t\tclearBits |= GL_COLOR_BUFFER_BIT;\t// FIXME: only if sky shaders have been used\n        qglClearColor(fast_sky_color[0], fast_sky_color[1], fast_sky_color[2], fast_sky_color[3]);\n\t}\n\n\tqglClear( clearBits );\n\n\t// VULKAN\n\tvk_clear_attachments(vk_world.dirty_depth_attachment, fast_sky, fast_sky_color);\n\n\t// DX12\n\tdx_clear_attachments(true, fast_sky, fast_sky_color);\n\n\tif ( ( backEnd.refdef.rdflags & RDF_HYPERSPACE ) )\n\t{\n\t\tRB_Hyperspace();\n\t\treturn;\n\t}\n\telse\n\t{\n\t\tbackEnd.isHyperspace = qfalse;\n\t}\n\n\tglState.faceCulling = -1;\t\t// force face culling to set next time\n\n\t// clip to the plane of the portal\n\tif ( backEnd.viewParms.isPortal ) {\n\t\tfloat\tplane[4];\n\t\tdouble\tplane2[4];\n\n\t\tplane[0] = backEnd.viewParms.portalPlane.normal[0];\n\t\tplane[1] = backEnd.viewParms.portalPlane.normal[1];\n\t\tplane[2] = backEnd.viewParms.portalPlane.normal[2];\n\t\tplane[3] = backEnd.viewParms.portalPlane.dist;\n\n\t\tplane2[0] = DotProduct (backEnd.viewParms.or.axis[0], plane);\n\t\tplane2[1] = DotProduct (backEnd.viewParms.or.axis[1], plane);\n\t\tplane2[2] = DotProduct (backEnd.viewParms.or.axis[2], plane);\n\t\tplane2[3] = DotProduct (plane, backEnd.viewParms.or.origin) - plane[3];\n\n\t\tqglLoadMatrixf( s_flipMatrix );\n\t\tqglClipPlane (GL_CLIP_PLANE0, plane2);\n\t\tqglEnable (GL_CLIP_PLANE0);\n\t} else {\n\t\tqglDisable (GL_CLIP_PLANE0);\n\t}\n}\n\n/*\n==================\nRB_RenderDrawSurfList\n==================\n*/\nvoid RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) {\n\tshader_t\t\t*shader, *oldShader;\n\tint\t\t\t\tfogNum, oldFogNum;\n\tint\t\t\t\tentityNum, oldEntityNum;\n\tint\t\t\t\tdlighted, oldDlighted;\n\tqboolean\t\tdepthRange, oldDepthRange;\n\tint\t\t\t\ti;\n\tdrawSurf_t\t\t*drawSurf;\n\tint\t\t\t\toldSort;\n\tfloat\t\t\toriginalTime;\n\n\t// save original time for entity shader offsets\n\toriginalTime = backEnd.refdef.floatTime;\n\n\t// clear the z buffer, set the modelview, etc\n\tRB_BeginDrawingView ();\n\n\t// draw everything\n\toldEntityNum = -1;\n\tbackEnd.currentEntity = &tr.worldEntity;\n\toldShader = NULL;\n\toldFogNum = -1;\n\toldDepthRange = qfalse;\n\toldDlighted = qfalse;\n\toldSort = -1;\n\tdepthRange = qfalse;\n\n\tbackEnd.pc.c_surfaces += numDrawSurfs;\n\n\tfor (i = 0, drawSurf = drawSurfs ; i < numDrawSurfs ; i++, drawSurf++) {\n\t\tif ( (int)drawSurf->sort == oldSort ) {\n\t\t\t// fast path, same as previous sort\n\t\t\trb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface );\n\t\t\tcontinue;\n\t\t}\n\t\toldSort = drawSurf->sort;\n\t\tR_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted );\n\n\t\t//\n\t\t// change the tess parameters if needed\n\t\t// a \"entityMergable\" shader is a shader that can have surfaces from seperate\n\t\t// entities merged into a single batch, like smoke and blood puff sprites\n\t\tif (shader != oldShader || fogNum != oldFogNum || dlighted != oldDlighted \n\t\t\t|| ( entityNum != oldEntityNum && !shader->entityMergable ) ) {\n\t\t\tif (oldShader != NULL) {\n\t\t\t\tRB_EndSurface();\n\t\t\t}\n\t\t\tRB_BeginSurface( shader, fogNum );\n\t\t\toldShader = shader;\n\t\t\toldFogNum = fogNum;\n\t\t\toldDlighted = dlighted;\n\t\t}\n\n\t\t//\n\t\t// change the modelview matrix if needed\n\t\t//\n\t\tif ( entityNum != oldEntityNum ) {\n\t\t\tdepthRange = qfalse;\n\n\t\t\tif ( entityNum != ENTITYNUM_WORLD ) {\n\t\t\t\tbackEnd.currentEntity = &backEnd.refdef.entities[entityNum];\n\t\t\t\tbackEnd.refdef.floatTime = originalTime - backEnd.currentEntity->e.shaderTime;\n\t\t\t\t// we have to reset the shaderTime as well otherwise image animations start\n\t\t\t\t// from the wrong frame\n\t\t\t\ttess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset;\n\n\t\t\t\t// set up the transformation matrix\n\t\t\t\tR_RotateForEntity( backEnd.currentEntity, &backEnd.viewParms, &backEnd.or );\n\n\t\t\t\t// set up the dynamic lighting if needed\n\t\t\t\tif ( backEnd.currentEntity->needDlights ) {\n\t\t\t\t\tR_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or );\n\t\t\t\t}\n\n\t\t\t\tif ( backEnd.currentEntity->e.renderfx & RF_DEPTHHACK ) {\n\t\t\t\t\t// hack the depth range to prevent view model from poking into walls\n\t\t\t\t\tdepthRange = qtrue;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tbackEnd.currentEntity = &tr.worldEntity;\n\t\t\t\tbackEnd.refdef.floatTime = originalTime;\n\t\t\t\tbackEnd.or = backEnd.viewParms.world;\n\t\t\t\t// we have to reset the shaderTime as well otherwise image animations on\n\t\t\t\t// the world (like water) continue with the wrong frame\n\t\t\t\ttess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset;\n\t\t\t\tR_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or );\n\t\t\t}\n\n\t\t\tqglLoadMatrixf( backEnd.or.modelMatrix );\n\n\t\t\t// VULKAN\n\t\t\tCom_Memcpy(vk_world.modelview_transform, backEnd.or.modelMatrix, 64);\n\n\t\t\t// DX12\n\t\t\tCom_Memcpy(dx_world.modelview_transform, backEnd.or.modelMatrix, 64);\n\n\t\t\t//\n\t\t\t// change depthrange if needed\n\t\t\t//\n\t\t\tif ( oldDepthRange != depthRange ) {\n\t\t\t\tif ( depthRange ) {\n\t\t\t\t\tqglDepthRange (0, 0.3);\n\t\t\t\t} else {\n\t\t\t\t\tqglDepthRange (0, 1);\n\t\t\t\t}\n\t\t\t\toldDepthRange = depthRange;\n\t\t\t}\n\n\t\t\toldEntityNum = entityNum;\n\t\t}\n\n\t\t// add the triangles for this surface\n\t\trb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface );\n\t}\n\n\tbackEnd.refdef.floatTime = originalTime;\n\n\t// draw the contents of the last shader batch\n\tif (oldShader != NULL) {\n\t\tRB_EndSurface();\n\t}\n\n\t// go back to the world modelview matrix\n\tqglLoadMatrixf( backEnd.viewParms.world.modelMatrix );\n\n\t// VULKAN\n\tCom_Memcpy(vk_world.modelview_transform, backEnd.viewParms.world.modelMatrix, 64);\n\n\t// DX12\n\tCom_Memcpy(dx_world.modelview_transform, backEnd.viewParms.world.modelMatrix, 64);\n\n\tif ( depthRange ) {\n\t\tqglDepthRange (0, 1);\n\t}\n\n\t// darken down any stencil shadows\n\tRB_ShadowFinish();\t\t\n}\n\n\n/*\n============================================================================\n\nRENDER BACK END THREAD FUNCTIONS\n\n============================================================================\n*/\n\n/*\n================\nRB_SetGL2D\n\n================\n*/\nvoid\tRB_SetGL2D (void) {\n\tbackEnd.projection2D = qtrue;\n\n\t// set 2D virtual screen size\n\tqglViewport( 0, 0, glConfig.vidWidth, glConfig.vidHeight );\n\tqglScissor( 0, 0, glConfig.vidWidth, glConfig.vidHeight );\n\tqglMatrixMode(GL_PROJECTION);\n    qglLoadIdentity ();\n\tqglOrtho (0, glConfig.vidWidth, glConfig.vidHeight, 0, 0, 1);\n\tqglMatrixMode(GL_MODELVIEW);\n    qglLoadIdentity ();\n\n\tGL_State( GLS_DEPTHTEST_DISABLE |\n\t\t\t  GLS_SRCBLEND_SRC_ALPHA |\n\t\t\t  GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA );\n\n\tqglDisable( GL_CULL_FACE );\n\tqglDisable( GL_CLIP_PLANE0 );\n\n\t// set time for 2D shaders\n\tbackEnd.refdef.time = ri.Milliseconds();\n\tbackEnd.refdef.floatTime = backEnd.refdef.time * 0.001f;\n}\n\n\n/*\n=============\nRE_StretchRaw\n\nFIXME: not exactly backend\nStretches a raw 32 bit power of 2 bitmap image over the given screen rectangle.\nUsed for cinematics.\n=============\n*/\nvoid RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty) {\n\tint\t\t\ti, j;\n\tint\t\t\tstart, end;\n\n\tif ( !tr.registered ) {\n\t\treturn;\n\t}\n\tR_SyncRenderThread();\n\n\tstart = end = 0;\n\tif ( r_speeds->integer ) {\n\t\tstart = ri.Milliseconds();\n\t}\n\n\t// make sure rows and cols are powers of 2\n\tfor ( i = 0 ; ( 1 << i ) < cols ; i++ ) {\n\t}\n\tfor ( j = 0 ; ( 1 << j ) < rows ; j++ ) {\n\t}\n\tif ( ( 1 << i ) != cols || ( 1 << j ) != rows) {\n\t\tri.Error (ERR_DROP, \"Draw_StretchRaw: size not a power of 2: %i by %i\", cols, rows);\n\t}\n\n    RE_UploadCinematic(w, h, cols, rows, data, client, dirty);\n\n\tif ( r_speeds->integer ) {\n\t\tend = ri.Milliseconds();\n\t\tri.Printf( PRINT_ALL, \"qglTexSubImage2D %i, %i: %i msec\\n\", cols, rows, end - start );\n\t}\n\n    tr.cinematicShader->stages[0]->bundle[0].image[0] = tr.scratchImage[client];\n    RE_StretchPic(x, y, w, h,  0.5f / cols, 0.5f / rows,  1.0f - 0.5f / cols, 1.0f - 0.5 / rows, tr.cinematicShader->index);\n}\n\nvoid RE_UploadCinematic (int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty) {\n\n\tGL_Bind( tr.scratchImage[client] );\n\n\t// if the scratchImage isn't in the format we want, specify it as a new texture\n\tif ( cols != tr.scratchImage[client]->width || rows != tr.scratchImage[client]->height ) {\n\t\ttr.scratchImage[client]->width = tr.scratchImage[client]->uploadWidth = cols;\n\t\ttr.scratchImage[client]->height = tr.scratchImage[client]->uploadHeight = rows;\n\t\tqglTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data );\n\t\tqglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );\n\t\tqglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );\n\t\tqglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );\n\t\tqglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );\n\n\t\t// VULKAN\n\t\tif (vk.active) {\n\t\t\tVk_Image& image = vk_world.images[tr.scratchImage[client]->index];\n\t\t\tvkDestroyImage(vk.device, image.handle, nullptr);\n\t\t\tvkDestroyImageView(vk.device, image.view, nullptr);\n\t\t\tvkFreeDescriptorSets(vk.device, vk.descriptor_pool, 1, &image.descriptor_set);\n\t\t\timage = vk_create_image(cols, rows, VK_FORMAT_R8G8B8A8_UNORM, 1, false);\n\t\t\tvk_upload_image_data(image.handle, cols, rows, false, data, 4);\n\t\t}\n\t\t// DX12\n\t\tif (dx.active) {\n\t\t\tint image_index = tr.scratchImage[client]->index;\n\t\t\tDx_Image& image = dx_world.images[image_index];\n\t\t\timage.texture->Release();\n\t\t\timage = dx_create_image(cols, rows, IMAGE_FORMAT_RGBA8, 1, false, image_index);\n\t\t\tdx_upload_image_data(image.texture, cols, rows, 1, data, 4);\n\t\t}\n\t} else {\n\t\tif (dirty) {\n\t\t\t// otherwise, just subimage upload it so that drivers can tell we are going to be changing\n\t\t\t// it and don't try and do a texture compression\n\t\t\tqglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data );\n\n\t\t\t// VULKAN\n\t\t\tif (vk.active) {\n\t\t\t\tconst Vk_Image& image = vk_world.images[tr.scratchImage[client]->index];\n\t\t\t\tvk_upload_image_data(image.handle, cols, rows, false, data, 4);\n\t\t\t}\n\t\t\t// DX12\n\t\t\tif (dx.active) {\n\t\t\t\tconst Dx_Image& image = dx_world.images[tr.scratchImage[client]->index];\n\t\t\t\tdx_upload_image_data(image.texture, cols, rows, 1, data, 4);\n\t\t\t}\n\t\t}\n\t}\n}\n\n\n/*\n=============\nRB_SetColor\n\n=============\n*/\nconst void\t*RB_SetColor( const void *data ) {\n\tconst setColorCommand_t\t*cmd;\n\n\tcmd = (const setColorCommand_t *)data;\n\n\tbackEnd.color2D[0] = cmd->color[0] * 255;\n\tbackEnd.color2D[1] = cmd->color[1] * 255;\n\tbackEnd.color2D[2] = cmd->color[2] * 255;\n\tbackEnd.color2D[3] = cmd->color[3] * 255;\n\n\treturn (const void *)(cmd + 1);\n}\n\n/*\n=============\nRB_StretchPic\n=============\n*/\nconst void *RB_StretchPic ( const void *data ) {\n\tconst stretchPicCommand_t\t*cmd;\n\tshader_t *shader;\n\tint\t\tnumVerts, numIndexes;\n\n\tcmd = (const stretchPicCommand_t *)data;\n\n\tif ( !backEnd.projection2D ) {\n\t\tRB_SetGL2D();\n\t}\n\n\tshader = cmd->shader;\n\tif ( shader != tess.shader ) {\n\t\tif ( tess.numIndexes ) {\n\t\t\tRB_EndSurface();\n\t\t}\n\t\tbackEnd.currentEntity = &backEnd.entity2D;\n\t\tRB_BeginSurface( shader, 0 );\n\t}\n\n\tRB_CHECKOVERFLOW( 4, 6 );\n\tnumVerts = tess.numVertexes;\n\tnumIndexes = tess.numIndexes;\n\n\ttess.numVertexes += 4;\n\ttess.numIndexes += 6;\n\n\ttess.indexes[ numIndexes ] = numVerts + 3;\n\ttess.indexes[ numIndexes + 1 ] = numVerts + 0;\n\ttess.indexes[ numIndexes + 2 ] = numVerts + 2;\n\ttess.indexes[ numIndexes + 3 ] = numVerts + 2;\n\ttess.indexes[ numIndexes + 4 ] = numVerts + 0;\n\ttess.indexes[ numIndexes + 5 ] = numVerts + 1;\n\n\t*(int *)tess.vertexColors[ numVerts ] =\n\t\t*(int *)tess.vertexColors[ numVerts + 1 ] =\n\t\t*(int *)tess.vertexColors[ numVerts + 2 ] =\n\t\t*(int *)tess.vertexColors[ numVerts + 3 ] = *(int *)backEnd.color2D;\n\n\ttess.xyz[ numVerts ][0] = cmd->x;\n\ttess.xyz[ numVerts ][1] = cmd->y;\n\ttess.xyz[ numVerts ][2] = 0;\n\n\ttess.texCoords[ numVerts ][0][0] = cmd->s1;\n\ttess.texCoords[ numVerts ][0][1] = cmd->t1;\n\n\ttess.xyz[ numVerts + 1 ][0] = cmd->x + cmd->w;\n\ttess.xyz[ numVerts + 1 ][1] = cmd->y;\n\ttess.xyz[ numVerts + 1 ][2] = 0;\n\n\ttess.texCoords[ numVerts + 1 ][0][0] = cmd->s2;\n\ttess.texCoords[ numVerts + 1 ][0][1] = cmd->t1;\n\n\ttess.xyz[ numVerts + 2 ][0] = cmd->x + cmd->w;\n\ttess.xyz[ numVerts + 2 ][1] = cmd->y + cmd->h;\n\ttess.xyz[ numVerts + 2 ][2] = 0;\n\n\ttess.texCoords[ numVerts + 2 ][0][0] = cmd->s2;\n\ttess.texCoords[ numVerts + 2 ][0][1] = cmd->t2;\n\n\ttess.xyz[ numVerts + 3 ][0] = cmd->x;\n\ttess.xyz[ numVerts + 3 ][1] = cmd->y + cmd->h;\n\ttess.xyz[ numVerts + 3 ][2] = 0;\n\n\ttess.texCoords[ numVerts + 3 ][0][0] = cmd->s1;\n\ttess.texCoords[ numVerts + 3 ][0][1] = cmd->t2;\n\n\treturn (const void *)(cmd + 1);\n}\n\n\n/*\n=============\nRB_DrawSurfs\n\n=============\n*/\nconst void\t*RB_DrawSurfs( const void *data ) {\n\tconst drawSurfsCommand_t\t*cmd;\n\n\t// finish any 2D drawing if needed\n\tif ( tess.numIndexes ) {\n\t\tRB_EndSurface();\n\t}\n\n\tcmd = (const drawSurfsCommand_t *)data;\n\n\tbackEnd.refdef = cmd->refdef;\n\tbackEnd.viewParms = cmd->viewParms;\n\n\tRB_RenderDrawSurfList( cmd->drawSurfs, cmd->numDrawSurfs );\n\n\treturn (const void *)(cmd + 1);\n}\n\n\n/*\n=============\nRB_DrawBuffer\n\n=============\n*/\nconst void\t*RB_DrawBuffer( const void *data ) {\n\tconst drawBufferCommand_t\t*cmd;\n\n\tcmd = (const drawBufferCommand_t *)data;\n\n\tqglDrawBuffer( cmd->buffer );\n\n\t// VULKAN\n\tvk_begin_frame();\n\n\t// DX12\n\tdx_begin_frame();\n\n\t// clear screen for debugging\n\tif ( r_clear->integer ) {\n\t\tfloat color[4] = {1, 0, 0.5, 1};\n\n\t\tqglClearColor( color[0], color[1], color[2], color[3] );\n\t\tqglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );\n\n\t\t// VULKAN\n\t\t// DX12\n\t\tif (vk.active || dx.active) {\n\t\t\tRB_SetGL2D(); // to ensure we have viewport that occupies entire window\n\t\t\tvk_clear_attachments(false, true, color);\n\t\t\tdx_clear_attachments(false, true, color);\n\t\t}\n\t}\n\n\treturn (const void *)(cmd + 1);\n}\n\n/*\n===============\nRB_ShowImages\n\nDraw all the images to the screen, on top of whatever\nwas there.  This is used to test for texture thrashing.\n\nAlso called by RE_EndRegistration\n===============\n*/\nvoid RB_ShowImages( void ) {\n\tint\t\ti;\n\timage_t\t*image;\n\tfloat\tx, y, w, h;\n\tint\t\tstart, end;\n\n\tif (!gl_active)\n\t\treturn;\n\n\tif ( !backEnd.projection2D ) {\n\t\tRB_SetGL2D();\n\t}\n\n\tqglClearColor(0, 0, 0, 1);\n\tqglClear( GL_COLOR_BUFFER_BIT );\n\n\tqglFinish();\n\n\tstart = ri.Milliseconds();\n\n\tfor ( i=0 ; i<tr.numImages ; i++ ) {\n\t\timage = tr.images[i];\n\n\t\tw = glConfig.vidWidth / 20;\n\t\th = glConfig.vidHeight / 15;\n\t\tx = i % 20 * w;\n\t\ty = i / 20 * h;\n\n\t\t// show in proportional size in mode 2\n\t\tif ( r_showImages->integer == 2 ) {\n\t\t\tw *= image->uploadWidth / 512.0f;\n\t\t\th *= image->uploadHeight / 512.0f;\n\t\t}\n\n\t\tGL_Bind( image );\n\t\tqglBegin (GL_QUADS);\n\t\tqglTexCoord2f( 0, 0 );\n\t\tqglVertex2f( x, y );\n\t\tqglTexCoord2f( 1, 0 );\n\t\tqglVertex2f( x + w, y );\n\t\tqglTexCoord2f( 1, 1 );\n\t\tqglVertex2f( x + w, y + h );\n\t\tqglTexCoord2f( 0, 1 );\n\t\tqglVertex2f( x, y + h );\n\t\tqglEnd();\n\t}\n\n\tqglFinish();\n\n\tend = ri.Milliseconds();\n\tri.Printf( PRINT_ALL, \"%i msec to draw all images\\n\", end - start );\n}\n\n// VULKAN\n// DX12\nvoid RB_Show_Vk_Dx_Images() {\n\tif (!vk.active && !dx.active) {\n\t\treturn;\n\t}\n\n\tif ( !backEnd.projection2D ) {\n\t\tRB_SetGL2D();\n\t}\n\n\tfloat black[4] = {0, 0, 0, 1};\n\n\tvk_clear_attachments(false, true, black);\n\tdx_clear_attachments(false, true, black);\n\n\n\tfor (int i = 0 ; i < tr.numImages ; i++) {\n\t\tauto image = tr.images[i];\n\n\t\tfloat w = glConfig.vidWidth / 20;\n\t\tfloat h = glConfig.vidHeight / 15;\n\t\tfloat x = i % 20 * w;\n\t\tfloat y = i / 20 * h;\n\n\t\t// show in proportional size in mode 2\n\t\tif ( r_showImages->integer == 2 ) {\n\t\t\tw *= image->uploadWidth / 512.0f;\n\t\t\th *= image->uploadHeight / 512.0f;\n\t\t}\n\n\t\tGL_Bind( image );\n\n\t\tCom_Memset( tess.svars.colors, tr.identityLightByte, tess.numVertexes * 4 );\n\n\t\ttess.numIndexes = 6;\n\t\ttess.numVertexes = 4;\n\n\t\ttess.indexes[0] = 0;\n\t\ttess.indexes[1] = 1;\n\t\ttess.indexes[2] = 2;\n\t\ttess.indexes[3] = 0;\n\t\ttess.indexes[4] = 2;\n\t\ttess.indexes[5] = 3;\n\n\t\ttess.xyz[0][0] = x;\n\t\ttess.xyz[0][1] = y;\n\t\ttess.svars.texcoords[0][0][0] = 0;\n\t\ttess.svars.texcoords[0][0][1] = 0;\n\n\t\ttess.xyz[1][0] = x + w;\n\t\ttess.xyz[1][1] = y;\n\t\ttess.svars.texcoords[0][1][0] = 1;\n\t\ttess.svars.texcoords[0][1][1] = 0;\n\n\t\ttess.xyz[2][0] = x + w;\n\t\ttess.xyz[2][1] = y + h;\n\t\ttess.svars.texcoords[0][2][0] = 1;\n\t\ttess.svars.texcoords[0][2][1] = 1;\n\n\t\ttess.xyz[3][0] = x;\n\t\ttess.xyz[3][1] = y + h;\n\t\ttess.svars.texcoords[0][3][0] = 0;\n\t\ttess.svars.texcoords[0][3][1] = 1;\n\n\t\tif (vk.active) {\n\t\t\tvk_bind_geometry();\n\t\t\tvk_shade_geometry(vk.images_debug_pipeline, false, Vk_Depth_Range::normal);\n\t\t}\n\t\tif (dx.active) {\n\t\t\tdx_bind_geometry();\n\t\t\tdx_shade_geometry(dx.images_debug_pipeline, false, Vk_Depth_Range::normal, true, false);\n\t\t}\n\t}\n\ttess.numIndexes = 0;\n\ttess.numVertexes = 0;\n}\n\n\n/*\n=============\nRB_SwapBuffers\n\n=============\n*/\nconst void\t*RB_SwapBuffers( const void *data ) {\n\tconst swapBuffersCommand_t\t*cmd;\n\n\t// finish any 2D drawing if needed\n\tif ( tess.numIndexes ) {\n\t\tRB_EndSurface();\n\t}\n\n\t// texture swapping test\n\tif ( r_showImages->integer ) {\n\t\tRB_ShowImages();\n\t\tRB_Show_Vk_Dx_Images();\n\t}\n\n\tcmd = (const swapBuffersCommand_t *)data;\n\n\tGLimp_LogComment( \"***************** RB_SwapBuffers *****************\\n\\n\\n\" );\n\n\tGLimp_EndFrame();\n\n\tbackEnd.projection2D = qfalse;\n\n\t// VULKAN\n\tvk_end_frame();\n\n\t// DX12\n\tdx_end_frame();\n\n\treturn (const void *)(cmd + 1);\n}\n\n/*\n====================\nRB_ExecuteRenderCommands\n\nThis function will be called synchronously if running without\nsmp extensions, or asynchronously by another thread.\n====================\n*/\nvoid RB_ExecuteRenderCommands( const void *data ) {\n\tint\t\tt1, t2;\n\n\tt1 = ri.Milliseconds ();\n\n\tif ( !r_smp->integer || data == backEndData[0]->commands.cmds ) {\n\t\tbackEnd.smpFrame = 0;\n\t} else {\n\t\tbackEnd.smpFrame = 1;\n\t}\n\n\tbool begin_frame_called = false;\n\tbool end_frame_called = false;\n\n\twhile ( 1 ) {\n\t\tswitch ( *(const int *)data ) {\n\t\tcase RC_SET_COLOR:\n\t\t\tdata = RB_SetColor( data );\n\t\t\tbreak;\n\t\tcase RC_STRETCH_PIC:\n\t\t\tdata = RB_StretchPic( data );\n\t\t\tbreak;\n\t\tcase RC_DRAW_SURFS:\n\t\t\tdata = RB_DrawSurfs( data );\n\t\t\tbreak;\n\t\tcase RC_DRAW_BUFFER:\n\t\t\tdata = RB_DrawBuffer( data );\n\t\t\tbegin_frame_called = true;\n\t\t\tbreak;\n\t\tcase RC_SWAP_BUFFERS:\n\t\t\tdata = RB_SwapBuffers( data );\n\t\t\tend_frame_called = true;\n\t\t\tbreak;\n\t\tcase RC_SCREENSHOT:\n\t\t\tdata = RB_TakeScreenshotCmd( data );\n\t\t\tbreak;\n\n\t\tcase RC_END_OF_LIST:\n\t\tdefault:\n\t\t\t// stop rendering on this thread\n\t\t\tt2 = ri.Milliseconds ();\n\t\t\tbackEnd.pc.msec = t2 - t1;\n\n\t\t\t// VULKAN\n\t\t\t// DX12\n\t\t\tif (com_errorEntered && (begin_frame_called && !end_frame_called)) {\n\t\t\t\tvk_end_frame();\n\t\t\t\tdx_end_frame();\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\t}\n\n}\n\n\n/*\n================\nRB_RenderThread\n================\n*/\nvoid RB_RenderThread( void ) {\n\tconst void\t*data;\n\n\t// wait for either a rendering command or a quit command\n\twhile ( 1 ) {\n\t\t// sleep until we have work to do\n\t\tdata = GLimp_RendererSleep();\n\n\t\tif ( !data ) {\n\t\t\treturn;\t// all done, renderer is shutting down\n\t\t}\n\n\t\trenderThreadActive = qtrue;\n\n\t\tRB_ExecuteRenderCommands( data );\n\n\t\trenderThreadActive = qfalse;\n\t}\n}\n\n"
  },
  {
    "path": "src/engine/renderer/tr_bsp.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n// tr_map.c\n\n#include \"tr_local.h\"\n\n/*\n\nLoads and prepares a map file for scene rendering.\n\nA single entry point:\n\nvoid RE_LoadWorldMap( const char *name );\n\n*/\n\nstatic\tworld_t\t\ts_worldData;\nstatic\tbyte\t\t*fileBase;\n\nint\t\t\tc_subdivisions;\nint\t\t\tc_gridVerts;\n\n//===============================================================================\n\nstatic void HSVtoRGB( float h, float s, float v, float rgb[3] )\n{\n\tint i;\n\tfloat f;\n\tfloat p, q, t;\n\n\th *= 5;\n\n\ti = floor( h );\n\tf = h - i;\n\n\tp = v * ( 1 - s );\n\tq = v * ( 1 - s * f );\n\tt = v * ( 1 - s * ( 1 - f ) );\n\n\tswitch ( i )\n\t{\n\tcase 0:\n\t\trgb[0] = v;\n\t\trgb[1] = t;\n\t\trgb[2] = p;\n\t\tbreak;\n\tcase 1:\n\t\trgb[0] = q;\n\t\trgb[1] = v;\n\t\trgb[2] = p;\n\t\tbreak;\n\tcase 2:\n\t\trgb[0] = p;\n\t\trgb[1] = v;\n\t\trgb[2] = t;\n\t\tbreak;\n\tcase 3:\n\t\trgb[0] = p;\n\t\trgb[1] = q;\n\t\trgb[2] = v;\n\t\tbreak;\n\tcase 4:\n\t\trgb[0] = t;\n\t\trgb[1] = p;\n\t\trgb[2] = v;\n\t\tbreak;\n\tcase 5:\n\t\trgb[0] = v;\n\t\trgb[1] = p;\n\t\trgb[2] = q;\n\t\tbreak;\n\t}\n}\n\n/*\n===============\nR_ColorShiftLightingBytes\n\n===============\n*/\nstatic\tvoid R_ColorShiftLightingBytes( byte in[4], byte out[4] ) {\n\tint\t\tshift, r, g, b;\n\n\t// shift the color data based on overbright range\n\tshift = r_mapOverBrightBits->integer - tr.overbrightBits;\n\n\t// shift the data based on overbright range\n\tr = in[0] << shift;\n\tg = in[1] << shift;\n\tb = in[2] << shift;\n\t\n\t// normalize by color instead of saturating to white\n\tif ( ( r | g | b ) > 255 ) {\n\t\tint\t\tmax;\n\n\t\tmax = r > g ? r : g;\n\t\tmax = max > b ? max : b;\n\t\tr = r * 255 / max;\n\t\tg = g * 255 / max;\n\t\tb = b * 255 / max;\n\t}\n\n\tout[0] = r;\n\tout[1] = g;\n\tout[2] = b;\n\tout[3] = in[3];\n}\n\n/*\n===============\nR_LoadLightmaps\n\n===============\n*/\n#define\tLIGHTMAP_SIZE\t128\nstatic\tvoid R_LoadLightmaps( lump_t *l ) {\n\tbyte\t\t*buf, *buf_p;\n\tint\t\t\tlen;\n\tMAC_STATIC byte\t\timage[LIGHTMAP_SIZE*LIGHTMAP_SIZE*4];\n\tint\t\t\ti, j;\n\tfloat maxIntensity = 0;\n\tdouble sumIntensity = 0;\n\n    len = l->filelen;\n\tif ( !len ) {\n\t\treturn;\n\t}\n\tbuf = fileBase + l->fileofs;\n\n\t// we are about to upload textures\n\tR_SyncRenderThread();\n\n\t// create all the lightmaps\n\ttr.numLightmaps = len / (LIGHTMAP_SIZE * LIGHTMAP_SIZE * 3);\n\tif ( tr.numLightmaps == 1 ) {\n\t\t//FIXME: HACK: maps with only one lightmap turn up fullbright for some reason.\n\t\t//this avoids this, but isn't the correct solution.\n\t\ttr.numLightmaps++;\n\t}\n\n\t// if we are in r_vertexLight mode, we don't need the lightmaps at all\n\tif ( r_vertexLight->integer ) {\n\t\treturn;\n\t}\n\n\tfor ( i = 0 ; i < tr.numLightmaps ; i++ ) {\n\t\t// expand the 24 bit on-disk to 32 bit\n\t\tbuf_p = buf + i * LIGHTMAP_SIZE*LIGHTMAP_SIZE * 3;\n\n\t\tif ( r_lightmap->integer == 2 )\n\t\t{\t// color code by intensity as development tool\t(FIXME: check range)\n\t\t\tfor ( j = 0; j < LIGHTMAP_SIZE * LIGHTMAP_SIZE; j++ )\n\t\t\t{\n\t\t\t\tfloat r = buf_p[j*3+0];\n\t\t\t\tfloat g = buf_p[j*3+1];\n\t\t\t\tfloat b = buf_p[j*3+2];\n\t\t\t\tfloat intensity;\n\t\t\t\tfloat out[3];\n\n\t\t\t\tintensity = 0.33f * r + 0.685f * g + 0.063f * b;\n\n\t\t\t\tif ( intensity > 255 )\n\t\t\t\t\tintensity = 1.0f;\n\t\t\t\telse\n\t\t\t\t\tintensity /= 255.0f;\n\n\t\t\t\tif ( intensity > maxIntensity )\n\t\t\t\t\tmaxIntensity = intensity;\n\n\t\t\t\tHSVtoRGB( intensity, 1.00, 0.50, out );\n\n\t\t\t\timage[j*4+0] = out[0] * 255;\n\t\t\t\timage[j*4+1] = out[1] * 255;\n\t\t\t\timage[j*4+2] = out[2] * 255;\n\t\t\t\timage[j*4+3] = 255;\n\n\t\t\t\tsumIntensity += intensity;\n\t\t\t}\n\t\t} else {\n\t\t\tfor ( j = 0 ; j < LIGHTMAP_SIZE * LIGHTMAP_SIZE; j++ ) {\n\t\t\t\tR_ColorShiftLightingBytes( &buf_p[j*3], &image[j*4] );\n\t\t\t\timage[j*4+3] = 255;\n\t\t\t}\n\t\t}\n\t\ttr.lightmaps[i] = R_CreateImage( va(\"*lightmap%d\",i), image, \n\t\t\tLIGHTMAP_SIZE, LIGHTMAP_SIZE, qfalse, qfalse, GL_CLAMP );\n\t}\n\n\tif ( r_lightmap->integer == 2 )\t{\n\t\tri.Printf( PRINT_ALL, \"Brightest lightmap value: %d\\n\", ( int ) ( maxIntensity * 255 ) );\n\t}\n}\n\n\n/*\n=================\nRE_SetWorldVisData\n\nThis is called by the clipmodel subsystem so we can share the 1.8 megs of\nspace in big maps...\n=================\n*/\nvoid\t\tRE_SetWorldVisData( const byte *vis ) {\n\ttr.externalVisData = vis;\n}\n\n\n/*\n=================\nR_LoadVisibility\n=================\n*/\nstatic\tvoid R_LoadVisibility( lump_t *l ) {\n\tint\t\tlen;\n\tbyte\t*buf;\n\n\tlen = ( s_worldData.numClusters + 63 ) & ~63;\n\ts_worldData.novis = (byte*) ri.Hunk_Alloc( len, h_low );\n\tCom_Memset( s_worldData.novis, 0xff, len );\n\n    len = l->filelen;\n\tif ( !len ) {\n\t\treturn;\n\t}\n\tbuf = fileBase + l->fileofs;\n\n\ts_worldData.numClusters = LittleLong( ((int *)buf)[0] );\n\ts_worldData.clusterBytes = LittleLong( ((int *)buf)[1] );\n\n\t// CM_Load should have given us the vis data to share, so\n\t// we don't need to allocate another copy\n\tif ( tr.externalVisData ) {\n\t\ts_worldData.vis = tr.externalVisData;\n\t} else {\n\t\tbyte\t*dest;\n\n\t\tdest = (byte*) ri.Hunk_Alloc( len - 8, h_low );\n\t\tCom_Memcpy( dest, buf + 8, len - 8 );\n\t\ts_worldData.vis = dest;\n\t}\n}\n\n//===============================================================================\n\n\n/*\n===============\nShaderForShaderNum\n===============\n*/\nstatic shader_t *ShaderForShaderNum( int shaderNum, int lightmapNum ) {\n\tshader_t\t*shader;\n\tdshader_t\t*dsh;\n\n\tshaderNum = LittleLong( shaderNum );\n\tif ( shaderNum < 0 || shaderNum >= s_worldData.numShaders ) {\n\t\tri.Error( ERR_DROP, \"ShaderForShaderNum: bad num %i\", shaderNum );\n\t}\n\tdsh = &s_worldData.shaders[ shaderNum ];\n\n\tif ( r_vertexLight->integer ) {\n\t\tlightmapNum = LIGHTMAP_BY_VERTEX;\n\t}\n\n\tif ( r_fullbright->integer ) {\n\t\tlightmapNum = LIGHTMAP_WHITEIMAGE;\n\t}\n\n\tshader = R_FindShader( dsh->shader, lightmapNum, qtrue );\n\n\t// if the shader had errors, just use default shader\n\tif ( shader->defaultShader ) {\n\t\treturn tr.defaultShader;\n\t}\n\n\treturn shader;\n}\n\n/*\n===============\nParseFace\n===============\n*/\nstatic void ParseFace( dsurface_t *ds, drawVert_t *verts, msurface_t *surf, int *indexes  ) {\n\tint\t\t\ti, j;\n\tsrfSurfaceFace_t\t*cv;\n\tint\t\t\tnumPoints, numIndexes;\n\tint\t\t\tlightmapNum;\n\tint\t\t\tsfaceSize, ofsIndexes;\n\n\tlightmapNum = LittleLong( ds->lightmapNum );\n\n\t// get fog volume\n\tsurf->fogIndex = LittleLong( ds->fogNum ) + 1;\n\n\t// get shader value\n\tsurf->shader = ShaderForShaderNum( ds->shaderNum, lightmapNum );\n\tif ( r_singleShader->integer && !surf->shader->isSky ) {\n\t\tsurf->shader = tr.defaultShader;\n\t}\n\n\tnumPoints = LittleLong( ds->numVerts );\n\tif (numPoints > MAX_FACE_POINTS) {\n\t\tri.Printf( PRINT_WARNING, \"WARNING: MAX_FACE_POINTS exceeded: %i\\n\", numPoints);\n    numPoints = MAX_FACE_POINTS;\n    surf->shader = tr.defaultShader;\n\t}\n\n\tnumIndexes = LittleLong( ds->numIndexes );\n\n\t// create the srfSurfaceFace_t\n\tsfaceSize = (int)(intptr_t) &((srfSurfaceFace_t *)0)->points[numPoints];\n\tofsIndexes = sfaceSize;\n\tsfaceSize += sizeof( int ) * numIndexes;\n\n\tcv = (srfSurfaceFace_t*) ri.Hunk_Alloc( sfaceSize, h_low );\n\tcv->surfaceType = SF_FACE;\n\tcv->numPoints = numPoints;\n\tcv->numIndices = numIndexes;\n\tcv->ofsIndices = ofsIndexes;\n\n\tverts += LittleLong( ds->firstVert );\n\tfor ( i = 0 ; i < numPoints ; i++ ) {\n\t\tfor ( j = 0 ; j < 3 ; j++ ) {\n\t\t\tcv->points[i][j] = LittleFloat( verts[i].xyz[j] );\n\t\t}\n\t\tfor ( j = 0 ; j < 2 ; j++ ) {\n\t\t\tcv->points[i][3+j] = LittleFloat( verts[i].st[j] );\n\t\t\tcv->points[i][5+j] = LittleFloat( verts[i].lightmap[j] );\n\t\t}\n\t\tR_ColorShiftLightingBytes( verts[i].color, (byte *)&cv->points[i][7] );\n\t}\n\n\tindexes += LittleLong( ds->firstIndex );\n\tfor ( i = 0 ; i < numIndexes ; i++ ) {\n\t\t((int *)((byte *)cv + cv->ofsIndices ))[i] = LittleLong( indexes[ i ] );\n\t}\n\n\t// take the plane information from the lightmap vector\n\tfor ( i = 0 ; i < 3 ; i++ ) {\n\t\tcv->plane.normal[i] = LittleFloat( ds->lightmapVecs[2][i] );\n\t}\n\tcv->plane.dist = DotProduct( cv->points[0], cv->plane.normal );\n\tSetPlaneSignbits( &cv->plane );\n\tcv->plane.type = PlaneTypeForNormal( cv->plane.normal );\n\n\tsurf->data = (surfaceType_t *)cv;\n}\n\n\n/*\n===============\nParseMesh\n===============\n*/\nstatic void ParseMesh ( dsurface_t *ds, drawVert_t *verts, msurface_t *surf ) {\n\tsrfGridMesh_t\t*grid;\n\tint\t\t\t\ti, j;\n\tint\t\t\t\twidth, height, numPoints;\n\tMAC_STATIC drawVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE];\n\tint\t\t\t\tlightmapNum;\n\tvec3_t\t\t\tbounds[2];\n\tvec3_t\t\t\ttmpVec;\n\tstatic surfaceType_t\tskipData = SF_SKIP;\n\n\tlightmapNum = LittleLong( ds->lightmapNum );\n\n\t// get fog volume\n\tsurf->fogIndex = LittleLong( ds->fogNum ) + 1;\n\n\t// get shader value\n\tsurf->shader = ShaderForShaderNum( ds->shaderNum, lightmapNum );\n\tif ( r_singleShader->integer && !surf->shader->isSky ) {\n\t\tsurf->shader = tr.defaultShader;\n\t}\n\n\t// we may have a nodraw surface, because they might still need to\n\t// be around for movement clipping\n\tif ( s_worldData.shaders[ LittleLong( ds->shaderNum ) ].surfaceFlags & SURF_NODRAW ) {\n\t\tsurf->data = &skipData;\n\t\treturn;\n\t}\n\n\twidth = LittleLong( ds->patchWidth );\n\theight = LittleLong( ds->patchHeight );\n\n\tverts += LittleLong( ds->firstVert );\n\tnumPoints = width * height;\n\tfor ( i = 0 ; i < numPoints ; i++ ) {\n\t\tfor ( j = 0 ; j < 3 ; j++ ) {\n\t\t\tpoints[i].xyz[j] = LittleFloat( verts[i].xyz[j] );\n\t\t\tpoints[i].normal[j] = LittleFloat( verts[i].normal[j] );\n\t\t}\n\t\tfor ( j = 0 ; j < 2 ; j++ ) {\n\t\t\tpoints[i].st[j] = LittleFloat( verts[i].st[j] );\n\t\t\tpoints[i].lightmap[j] = LittleFloat( verts[i].lightmap[j] );\n\t\t}\n\t\tR_ColorShiftLightingBytes( verts[i].color, points[i].color );\n\t}\n\n\t// pre-tesseleate\n\tgrid = R_SubdividePatchToGrid( width, height, points );\n\tsurf->data = (surfaceType_t *)grid;\n\n\t// copy the level of detail origin, which is the center\n\t// of the group of all curves that must subdivide the same\n\t// to avoid cracking\n\tfor ( i = 0 ; i < 3 ; i++ ) {\n\t\tbounds[0][i] = LittleFloat( ds->lightmapVecs[0][i] );\n\t\tbounds[1][i] = LittleFloat( ds->lightmapVecs[1][i] );\n\t}\n\tVectorAdd( bounds[0], bounds[1], bounds[1] );\n\tVectorScale( bounds[1], 0.5f, grid->lodOrigin );\n\tVectorSubtract( bounds[0], grid->lodOrigin, tmpVec );\n\tgrid->lodRadius = VectorLength( tmpVec );\n}\n\n/*\n===============\nParseTriSurf\n===============\n*/\nstatic void ParseTriSurf( dsurface_t *ds, drawVert_t *verts, msurface_t *surf, int *indexes ) {\n\tsrfTriangles_t\t*tri;\n\tint\t\t\t\ti, j;\n\tint\t\t\t\tnumVerts, numIndexes;\n\n\t// get fog volume\n\tsurf->fogIndex = LittleLong( ds->fogNum ) + 1;\n\n\t// get shader\n\tsurf->shader = ShaderForShaderNum( ds->shaderNum, LIGHTMAP_BY_VERTEX );\n\tif ( r_singleShader->integer && !surf->shader->isSky ) {\n\t\tsurf->shader = tr.defaultShader;\n\t}\n\n\tnumVerts = LittleLong( ds->numVerts );\n\tnumIndexes = LittleLong( ds->numIndexes );\n\n\ttri = (srfTriangles_t*) ri.Hunk_Alloc( sizeof( *tri ) + numVerts * sizeof( tri->verts[0] ) \n\t\t+ numIndexes * sizeof( tri->indexes[0] ), h_low );\n\ttri->surfaceType = SF_TRIANGLES;\n\ttri->numVerts = numVerts;\n\ttri->numIndexes = numIndexes;\n\ttri->verts = (drawVert_t *)(tri + 1);\n\ttri->indexes = (int *)(tri->verts + tri->numVerts );\n\n\tsurf->data = (surfaceType_t *)tri;\n\n\t// copy vertexes\n\tClearBounds( tri->bounds[0], tri->bounds[1] );\n\tverts += LittleLong( ds->firstVert );\n\tfor ( i = 0 ; i < numVerts ; i++ ) {\n\t\tfor ( j = 0 ; j < 3 ; j++ ) {\n\t\t\ttri->verts[i].xyz[j] = LittleFloat( verts[i].xyz[j] );\n\t\t\ttri->verts[i].normal[j] = LittleFloat( verts[i].normal[j] );\n\t\t}\n\t\tAddPointToBounds( tri->verts[i].xyz, tri->bounds[0], tri->bounds[1] );\n\t\tfor ( j = 0 ; j < 2 ; j++ ) {\n\t\t\ttri->verts[i].st[j] = LittleFloat( verts[i].st[j] );\n\t\t\ttri->verts[i].lightmap[j] = LittleFloat( verts[i].lightmap[j] );\n\t\t}\n\n\t\tR_ColorShiftLightingBytes( verts[i].color, tri->verts[i].color );\n\t}\n\n\t// copy indexes\n\tindexes += LittleLong( ds->firstIndex );\n\tfor ( i = 0 ; i < numIndexes ; i++ ) {\n\t\ttri->indexes[i] = LittleLong( indexes[i] );\n\t\tif ( tri->indexes[i] < 0 || tri->indexes[i] >= numVerts ) {\n\t\t\tri.Error( ERR_DROP, \"Bad index in triangle surface\" );\n\t\t}\n\t}\n}\n\n/*\n===============\nParseFlare\n===============\n*/\nstatic void ParseFlare( dsurface_t *ds, drawVert_t *verts, msurface_t *surf, int *indexes ) {\n\tsrfFlare_t\t\t*flare;\n\tint\t\t\t\ti;\n\n\t// get fog volume\n\tsurf->fogIndex = LittleLong( ds->fogNum ) + 1;\n\n\t// get shader\n\tsurf->shader = ShaderForShaderNum( ds->shaderNum, LIGHTMAP_BY_VERTEX );\n\tif ( r_singleShader->integer && !surf->shader->isSky ) {\n\t\tsurf->shader = tr.defaultShader;\n\t}\n\n\tflare = (srfFlare_t*) ri.Hunk_Alloc( sizeof( *flare ), h_low );\n\tflare->surfaceType = SF_FLARE;\n\n\tsurf->data = (surfaceType_t *)flare;\n\n\tfor ( i = 0 ; i < 3 ; i++ ) {\n\t\tflare->origin[i] = LittleFloat( ds->lightmapOrigin[i] );\n\t\tflare->color[i] = LittleFloat( ds->lightmapVecs[0][i] );\n\t\tflare->normal[i] = LittleFloat( ds->lightmapVecs[2][i] );\n\t}\n}\n\n\n/*\n=================\nR_MergedWidthPoints\n\nreturns true if there are grid points merged on a width edge\n=================\n*/\nint R_MergedWidthPoints(srfGridMesh_t *grid, int offset) {\n\tint i, j;\n\n\tfor (i = 1; i < grid->width-1; i++) {\n\t\tfor (j = i + 1; j < grid->width-1; j++) {\n\t\t\tif ( fabs(grid->verts[i + offset].xyz[0] - grid->verts[j + offset].xyz[0]) > .1) continue;\n\t\t\tif ( fabs(grid->verts[i + offset].xyz[1] - grid->verts[j + offset].xyz[1]) > .1) continue;\n\t\t\tif ( fabs(grid->verts[i + offset].xyz[2] - grid->verts[j + offset].xyz[2]) > .1) continue;\n\t\t\treturn qtrue;\n\t\t}\n\t}\n\treturn qfalse;\n}\n\n/*\n=================\nR_MergedHeightPoints\n\nreturns true if there are grid points merged on a height edge\n=================\n*/\nint R_MergedHeightPoints(srfGridMesh_t *grid, int offset) {\n\tint i, j;\n\n\tfor (i = 1; i < grid->height-1; i++) {\n\t\tfor (j = i + 1; j < grid->height-1; j++) {\n\t\t\tif ( fabs(grid->verts[grid->width * i + offset].xyz[0] - grid->verts[grid->width * j + offset].xyz[0]) > .1) continue;\n\t\t\tif ( fabs(grid->verts[grid->width * i + offset].xyz[1] - grid->verts[grid->width * j + offset].xyz[1]) > .1) continue;\n\t\t\tif ( fabs(grid->verts[grid->width * i + offset].xyz[2] - grid->verts[grid->width * j + offset].xyz[2]) > .1) continue;\n\t\t\treturn qtrue;\n\t\t}\n\t}\n\treturn qfalse;\n}\n\n/*\n=================\nR_FixSharedVertexLodError_r\n\nNOTE: never sync LoD through grid edges with merged points!\n\nFIXME: write generalized version that also avoids cracks between a patch and one that meets half way?\n=================\n*/\nvoid R_FixSharedVertexLodError_r( int start, srfGridMesh_t *grid1 ) {\n\tint j, k, l, m, n, offset1, offset2, touch;\n\tsrfGridMesh_t *grid2;\n\n\tfor ( j = start; j < s_worldData.numsurfaces; j++ ) {\n\t\t//\n\t\tgrid2 = (srfGridMesh_t *) s_worldData.surfaces[j].data;\n\t\t// if this surface is not a grid\n\t\tif ( grid2->surfaceType != SF_GRID ) continue;\n\t\t// if the LOD errors are already fixed for this patch\n\t\tif ( grid2->lodFixed == 2 ) continue;\n\t\t// grids in the same LOD group should have the exact same lod radius\n\t\tif ( grid1->lodRadius != grid2->lodRadius ) continue;\n\t\t// grids in the same LOD group should have the exact same lod origin\n\t\tif ( grid1->lodOrigin[0] != grid2->lodOrigin[0] ) continue;\n\t\tif ( grid1->lodOrigin[1] != grid2->lodOrigin[1] ) continue;\n\t\tif ( grid1->lodOrigin[2] != grid2->lodOrigin[2] ) continue;\n\t\t//\n\t\ttouch = qfalse;\n\t\tfor (n = 0; n < 2; n++) {\n\t\t\t//\n\t\t\tif (n) offset1 = (grid1->height-1) * grid1->width;\n\t\t\telse offset1 = 0;\n\t\t\tif (R_MergedWidthPoints(grid1, offset1)) continue;\n\t\t\tfor (k = 1; k < grid1->width-1; k++) {\n\t\t\t\tfor (m = 0; m < 2; m++) {\n\n\t\t\t\t\tif (m) offset2 = (grid2->height-1) * grid2->width;\n\t\t\t\t\telse offset2 = 0;\n\t\t\t\t\tif (R_MergedWidthPoints(grid2, offset2)) continue;\n\t\t\t\t\tfor ( l = 1; l < grid2->width-1; l++) {\n\t\t\t\t\t//\n\t\t\t\t\t\tif ( fabs(grid1->verts[k + offset1].xyz[0] - grid2->verts[l + offset2].xyz[0]) > .1) continue;\n\t\t\t\t\t\tif ( fabs(grid1->verts[k + offset1].xyz[1] - grid2->verts[l + offset2].xyz[1]) > .1) continue;\n\t\t\t\t\t\tif ( fabs(grid1->verts[k + offset1].xyz[2] - grid2->verts[l + offset2].xyz[2]) > .1) continue;\n\t\t\t\t\t\t// ok the points are equal and should have the same lod error\n\t\t\t\t\t\tgrid2->widthLodError[l] = grid1->widthLodError[k];\n\t\t\t\t\t\ttouch = qtrue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfor (m = 0; m < 2; m++) {\n\n\t\t\t\t\tif (m) offset2 = grid2->width-1;\n\t\t\t\t\telse offset2 = 0;\n\t\t\t\t\tif (R_MergedHeightPoints(grid2, offset2)) continue;\n\t\t\t\t\tfor ( l = 1; l < grid2->height-1; l++) {\n\t\t\t\t\t//\n\t\t\t\t\t\tif ( fabs(grid1->verts[k + offset1].xyz[0] - grid2->verts[grid2->width * l + offset2].xyz[0]) > .1) continue;\n\t\t\t\t\t\tif ( fabs(grid1->verts[k + offset1].xyz[1] - grid2->verts[grid2->width * l + offset2].xyz[1]) > .1) continue;\n\t\t\t\t\t\tif ( fabs(grid1->verts[k + offset1].xyz[2] - grid2->verts[grid2->width * l + offset2].xyz[2]) > .1) continue;\n\t\t\t\t\t\t// ok the points are equal and should have the same lod error\n\t\t\t\t\t\tgrid2->heightLodError[l] = grid1->widthLodError[k];\n\t\t\t\t\t\ttouch = qtrue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfor (n = 0; n < 2; n++) {\n\t\t\t//\n\t\t\tif (n) offset1 = grid1->width-1;\n\t\t\telse offset1 = 0;\n\t\t\tif (R_MergedHeightPoints(grid1, offset1)) continue;\n\t\t\tfor (k = 1; k < grid1->height-1; k++) {\n\t\t\t\tfor (m = 0; m < 2; m++) {\n\n\t\t\t\t\tif (m) offset2 = (grid2->height-1) * grid2->width;\n\t\t\t\t\telse offset2 = 0;\n\t\t\t\t\tif (R_MergedWidthPoints(grid2, offset2)) continue;\n\t\t\t\t\tfor ( l = 1; l < grid2->width-1; l++) {\n\t\t\t\t\t//\n\t\t\t\t\t\tif ( fabs(grid1->verts[grid1->width * k + offset1].xyz[0] - grid2->verts[l + offset2].xyz[0]) > .1) continue;\n\t\t\t\t\t\tif ( fabs(grid1->verts[grid1->width * k + offset1].xyz[1] - grid2->verts[l + offset2].xyz[1]) > .1) continue;\n\t\t\t\t\t\tif ( fabs(grid1->verts[grid1->width * k + offset1].xyz[2] - grid2->verts[l + offset2].xyz[2]) > .1) continue;\n\t\t\t\t\t\t// ok the points are equal and should have the same lod error\n\t\t\t\t\t\tgrid2->widthLodError[l] = grid1->heightLodError[k];\n\t\t\t\t\t\ttouch = qtrue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfor (m = 0; m < 2; m++) {\n\n\t\t\t\t\tif (m) offset2 = grid2->width-1;\n\t\t\t\t\telse offset2 = 0;\n\t\t\t\t\tif (R_MergedHeightPoints(grid2, offset2)) continue;\n\t\t\t\t\tfor ( l = 1; l < grid2->height-1; l++) {\n\t\t\t\t\t//\n\t\t\t\t\t\tif ( fabs(grid1->verts[grid1->width * k + offset1].xyz[0] - grid2->verts[grid2->width * l + offset2].xyz[0]) > .1) continue;\n\t\t\t\t\t\tif ( fabs(grid1->verts[grid1->width * k + offset1].xyz[1] - grid2->verts[grid2->width * l + offset2].xyz[1]) > .1) continue;\n\t\t\t\t\t\tif ( fabs(grid1->verts[grid1->width * k + offset1].xyz[2] - grid2->verts[grid2->width * l + offset2].xyz[2]) > .1) continue;\n\t\t\t\t\t\t// ok the points are equal and should have the same lod error\n\t\t\t\t\t\tgrid2->heightLodError[l] = grid1->heightLodError[k];\n\t\t\t\t\t\ttouch = qtrue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (touch) {\n\t\t\tgrid2->lodFixed = 2;\n\t\t\tR_FixSharedVertexLodError_r ( start, grid2 );\n\t\t\t//NOTE: this would be correct but makes things really slow\n\t\t\t//grid2->lodFixed = 1;\n\t\t}\n\t}\n}\n\n/*\n=================\nR_FixSharedVertexLodError\n\nThis function assumes that all patches in one group are nicely stitched together for the highest LoD.\nIf this is not the case this function will still do its job but won't fix the highest LoD cracks.\n=================\n*/\nvoid R_FixSharedVertexLodError( void ) {\n\tint i;\n\tsrfGridMesh_t *grid1;\n\n\tfor ( i = 0; i < s_worldData.numsurfaces; i++ ) {\n\t\t//\n\t\tgrid1 = (srfGridMesh_t *) s_worldData.surfaces[i].data;\n\t\t// if this surface is not a grid\n\t\tif ( grid1->surfaceType != SF_GRID )\n\t\t\tcontinue;\n\t\t//\n\t\tif ( grid1->lodFixed )\n\t\t\tcontinue;\n\t\t//\n\t\tgrid1->lodFixed = 2;\n\t\t// recursively fix other patches in the same LOD group\n\t\tR_FixSharedVertexLodError_r( i + 1, grid1);\n\t}\n}\n\n\n/*\n===============\nR_StitchPatches\n===============\n*/\nint R_StitchPatches( int grid1num, int grid2num ) {\n\tfloat *v1, *v2;\n\tsrfGridMesh_t *grid1, *grid2;\n\tint k, l, m, n, offset1, offset2, row, column;\n\n\tgrid1 = (srfGridMesh_t *) s_worldData.surfaces[grid1num].data;\n\tgrid2 = (srfGridMesh_t *) s_worldData.surfaces[grid2num].data;\n\tfor (n = 0; n < 2; n++) {\n\t\t//\n\t\tif (n) offset1 = (grid1->height-1) * grid1->width;\n\t\telse offset1 = 0;\n\t\tif (R_MergedWidthPoints(grid1, offset1))\n\t\t\tcontinue;\n\t\tfor (k = 0; k < grid1->width-2; k += 2) {\n\n\t\t\tfor (m = 0; m < 2; m++) {\n\n\t\t\t\tif ( grid2->width >= MAX_GRID_SIZE )\n\t\t\t\t\tbreak;\n\t\t\t\tif (m) offset2 = (grid2->height-1) * grid2->width;\n\t\t\t\telse offset2 = 0;\n\t\t\t\tfor ( l = 0; l < grid2->width-1; l++) {\n\t\t\t\t//\n\t\t\t\t\tv1 = grid1->verts[k + offset1].xyz;\n\t\t\t\t\tv2 = grid2->verts[l + offset2].xyz;\n\t\t\t\t\tif ( fabs(v1[0] - v2[0]) > .1)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif ( fabs(v1[1] - v2[1]) > .1)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif ( fabs(v1[2] - v2[2]) > .1)\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\tv1 = grid1->verts[k + 2 + offset1].xyz;\n\t\t\t\t\tv2 = grid2->verts[l + 1 + offset2].xyz;\n\t\t\t\t\tif ( fabs(v1[0] - v2[0]) > .1)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif ( fabs(v1[1] - v2[1]) > .1)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif ( fabs(v1[2] - v2[2]) > .1)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t//\n\t\t\t\t\tv1 = grid2->verts[l + offset2].xyz;\n\t\t\t\t\tv2 = grid2->verts[l + 1 + offset2].xyz;\n\t\t\t\t\tif ( fabs(v1[0] - v2[0]) < .01 &&\n\t\t\t\t\t\t\tfabs(v1[1] - v2[1]) < .01 &&\n\t\t\t\t\t\t\tfabs(v1[2] - v2[2]) < .01)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t//\n\t\t\t\t\t//ri.Printf( PRINT_ALL, \"found highest LoD crack between two patches\\n\" );\n\t\t\t\t\t// insert column into grid2 right after after column l\n\t\t\t\t\tif (m) row = grid2->height-1;\n\t\t\t\t\telse row = 0;\n\t\t\t\t\tgrid2 = R_GridInsertColumn( grid2, l+1, row,\n\t\t\t\t\t\t\t\t\tgrid1->verts[k + 1 + offset1].xyz, grid1->widthLodError[k+1]);\n\t\t\t\t\tgrid2->lodStitched = qfalse;\n\t\t\t\t\ts_worldData.surfaces[grid2num].data = (surfaceType_t*) (void *) grid2;\n\t\t\t\t\treturn qtrue;\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (m = 0; m < 2; m++) {\n\n\t\t\t\tif (grid2->height >= MAX_GRID_SIZE)\n\t\t\t\t\tbreak;\n\t\t\t\tif (m) offset2 = grid2->width-1;\n\t\t\t\telse offset2 = 0;\n\t\t\t\tfor ( l = 0; l < grid2->height-1; l++) {\n\t\t\t\t\t//\n\t\t\t\t\tv1 = grid1->verts[k + offset1].xyz;\n\t\t\t\t\tv2 = grid2->verts[grid2->width * l + offset2].xyz;\n\t\t\t\t\tif ( fabs(v1[0] - v2[0]) > .1)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif ( fabs(v1[1] - v2[1]) > .1)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif ( fabs(v1[2] - v2[2]) > .1)\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\tv1 = grid1->verts[k + 2 + offset1].xyz;\n\t\t\t\t\tv2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;\n\t\t\t\t\tif ( fabs(v1[0] - v2[0]) > .1)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif ( fabs(v1[1] - v2[1]) > .1)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif ( fabs(v1[2] - v2[2]) > .1)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t//\n\t\t\t\t\tv1 = grid2->verts[grid2->width * l + offset2].xyz;\n\t\t\t\t\tv2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;\n\t\t\t\t\tif ( fabs(v1[0] - v2[0]) < .01 &&\n\t\t\t\t\t\t\tfabs(v1[1] - v2[1]) < .01 &&\n\t\t\t\t\t\t\tfabs(v1[2] - v2[2]) < .01)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t//\n\t\t\t\t\t//ri.Printf( PRINT_ALL, \"found highest LoD crack between two patches\\n\" );\n\t\t\t\t\t// insert row into grid2 right after after row l\n\t\t\t\t\tif (m) column = grid2->width-1;\n\t\t\t\t\telse column = 0;\n\t\t\t\t\tgrid2 = R_GridInsertRow( grid2, l+1, column,\n\t\t\t\t\t\t\t\t\t\tgrid1->verts[k + 1 + offset1].xyz, grid1->widthLodError[k+1]);\n\t\t\t\t\tgrid2->lodStitched = qfalse;\n\t\t\t\t\ts_worldData.surfaces[grid2num].data = (surfaceType_t*) (void *) grid2;\n\t\t\t\t\treturn qtrue;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tfor (n = 0; n < 2; n++) {\n\t\t//\n\t\tif (n) offset1 = grid1->width-1;\n\t\telse offset1 = 0;\n\t\tif (R_MergedHeightPoints(grid1, offset1))\n\t\t\tcontinue;\n\t\tfor (k = 0; k < grid1->height-2; k += 2) {\n\t\t\tfor (m = 0; m < 2; m++) {\n\n\t\t\t\tif ( grid2->width >= MAX_GRID_SIZE )\n\t\t\t\t\tbreak;\n\t\t\t\tif (m) offset2 = (grid2->height-1) * grid2->width;\n\t\t\t\telse offset2 = 0;\n\t\t\t\tfor ( l = 0; l < grid2->width-1; l++) {\n\t\t\t\t//\n\t\t\t\t\tv1 = grid1->verts[grid1->width * k + offset1].xyz;\n\t\t\t\t\tv2 = grid2->verts[l + offset2].xyz;\n\t\t\t\t\tif ( fabs(v1[0] - v2[0]) > .1)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif ( fabs(v1[1] - v2[1]) > .1)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif ( fabs(v1[2] - v2[2]) > .1)\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\tv1 = grid1->verts[grid1->width * (k + 2) + offset1].xyz;\n\t\t\t\t\tv2 = grid2->verts[l + 1 + offset2].xyz;\n\t\t\t\t\tif ( fabs(v1[0] - v2[0]) > .1)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif ( fabs(v1[1] - v2[1]) > .1)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif ( fabs(v1[2] - v2[2]) > .1)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t//\n\t\t\t\t\tv1 = grid2->verts[l + offset2].xyz;\n\t\t\t\t\tv2 = grid2->verts[(l + 1) + offset2].xyz;\n\t\t\t\t\tif ( fabs(v1[0] - v2[0]) < .01 &&\n\t\t\t\t\t\t\tfabs(v1[1] - v2[1]) < .01 &&\n\t\t\t\t\t\t\tfabs(v1[2] - v2[2]) < .01)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t//\n\t\t\t\t\t//ri.Printf( PRINT_ALL, \"found highest LoD crack between two patches\\n\" );\n\t\t\t\t\t// insert column into grid2 right after after column l\n\t\t\t\t\tif (m) row = grid2->height-1;\n\t\t\t\t\telse row = 0;\n\t\t\t\t\tgrid2 = R_GridInsertColumn( grid2, l+1, row,\n\t\t\t\t\t\t\t\t\tgrid1->verts[grid1->width * (k + 1) + offset1].xyz, grid1->heightLodError[k+1]);\n\t\t\t\t\tgrid2->lodStitched = qfalse;\n\t\t\t\t\ts_worldData.surfaces[grid2num].data = (surfaceType_t*) (void *) grid2;\n\t\t\t\t\treturn qtrue;\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (m = 0; m < 2; m++) {\n\n\t\t\t\tif (grid2->height >= MAX_GRID_SIZE)\n\t\t\t\t\tbreak;\n\t\t\t\tif (m) offset2 = grid2->width-1;\n\t\t\t\telse offset2 = 0;\n\t\t\t\tfor ( l = 0; l < grid2->height-1; l++) {\n\t\t\t\t//\n\t\t\t\t\tv1 = grid1->verts[grid1->width * k + offset1].xyz;\n\t\t\t\t\tv2 = grid2->verts[grid2->width * l + offset2].xyz;\n\t\t\t\t\tif ( fabs(v1[0] - v2[0]) > .1)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif ( fabs(v1[1] - v2[1]) > .1)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif ( fabs(v1[2] - v2[2]) > .1)\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\tv1 = grid1->verts[grid1->width * (k + 2) + offset1].xyz;\n\t\t\t\t\tv2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;\n\t\t\t\t\tif ( fabs(v1[0] - v2[0]) > .1)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif ( fabs(v1[1] - v2[1]) > .1)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif ( fabs(v1[2] - v2[2]) > .1)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t//\n\t\t\t\t\tv1 = grid2->verts[grid2->width * l + offset2].xyz;\n\t\t\t\t\tv2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;\n\t\t\t\t\tif ( fabs(v1[0] - v2[0]) < .01 &&\n\t\t\t\t\t\t\tfabs(v1[1] - v2[1]) < .01 &&\n\t\t\t\t\t\t\tfabs(v1[2] - v2[2]) < .01)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t//\n\t\t\t\t\t//ri.Printf( PRINT_ALL, \"found highest LoD crack between two patches\\n\" );\n\t\t\t\t\t// insert row into grid2 right after after row l\n\t\t\t\t\tif (m) column = grid2->width-1;\n\t\t\t\t\telse column = 0;\n\t\t\t\t\tgrid2 = R_GridInsertRow( grid2, l+1, column,\n\t\t\t\t\t\t\t\t\tgrid1->verts[grid1->width * (k + 1) + offset1].xyz, grid1->heightLodError[k+1]);\n\t\t\t\t\tgrid2->lodStitched = qfalse;\n\t\t\t\t\ts_worldData.surfaces[grid2num].data = (surfaceType_t*) (void *) grid2;\n\t\t\t\t\treturn qtrue;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tfor (n = 0; n < 2; n++) {\n\t\t//\n\t\tif (n) offset1 = (grid1->height-1) * grid1->width;\n\t\telse offset1 = 0;\n\t\tif (R_MergedWidthPoints(grid1, offset1))\n\t\t\tcontinue;\n\t\tfor (k = grid1->width-1; k > 1; k -= 2) {\n\n\t\t\tfor (m = 0; m < 2; m++) {\n\n\t\t\t\tif ( grid2->width >= MAX_GRID_SIZE )\n\t\t\t\t\tbreak;\n\t\t\t\tif (m) offset2 = (grid2->height-1) * grid2->width;\n\t\t\t\telse offset2 = 0;\n\t\t\t\tfor ( l = 0; l < grid2->width-1; l++) {\n\t\t\t\t//\n\t\t\t\t\tv1 = grid1->verts[k + offset1].xyz;\n\t\t\t\t\tv2 = grid2->verts[l + offset2].xyz;\n\t\t\t\t\tif ( fabs(v1[0] - v2[0]) > .1)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif ( fabs(v1[1] - v2[1]) > .1)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif ( fabs(v1[2] - v2[2]) > .1)\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\tv1 = grid1->verts[k - 2 + offset1].xyz;\n\t\t\t\t\tv2 = grid2->verts[l + 1 + offset2].xyz;\n\t\t\t\t\tif ( fabs(v1[0] - v2[0]) > .1)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif ( fabs(v1[1] - v2[1]) > .1)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif ( fabs(v1[2] - v2[2]) > .1)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t//\n\t\t\t\t\tv1 = grid2->verts[l + offset2].xyz;\n\t\t\t\t\tv2 = grid2->verts[(l + 1) + offset2].xyz;\n\t\t\t\t\tif ( fabs(v1[0] - v2[0]) < .01 &&\n\t\t\t\t\t\t\tfabs(v1[1] - v2[1]) < .01 &&\n\t\t\t\t\t\t\tfabs(v1[2] - v2[2]) < .01)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t//\n\t\t\t\t\t//ri.Printf( PRINT_ALL, \"found highest LoD crack between two patches\\n\" );\n\t\t\t\t\t// insert column into grid2 right after after column l\n\t\t\t\t\tif (m) row = grid2->height-1;\n\t\t\t\t\telse row = 0;\n\t\t\t\t\tgrid2 = R_GridInsertColumn( grid2, l+1, row,\n\t\t\t\t\t\t\t\t\t\tgrid1->verts[k - 1 + offset1].xyz, grid1->widthLodError[k+1]);\n\t\t\t\t\tgrid2->lodStitched = qfalse;\n\t\t\t\t\ts_worldData.surfaces[grid2num].data = (surfaceType_t*) (void *) grid2;\n\t\t\t\t\treturn qtrue;\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (m = 0; m < 2; m++) {\n\n\t\t\t\tif (grid2->height >= MAX_GRID_SIZE)\n\t\t\t\t\tbreak;\n\t\t\t\tif (m) offset2 = grid2->width-1;\n\t\t\t\telse offset2 = 0;\n\t\t\t\tfor ( l = 0; l < grid2->height-1; l++) {\n\t\t\t\t//\n\t\t\t\t\tv1 = grid1->verts[k + offset1].xyz;\n\t\t\t\t\tv2 = grid2->verts[grid2->width * l + offset2].xyz;\n\t\t\t\t\tif ( fabs(v1[0] - v2[0]) > .1)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif ( fabs(v1[1] - v2[1]) > .1)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif ( fabs(v1[2] - v2[2]) > .1)\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\tv1 = grid1->verts[k - 2 + offset1].xyz;\n\t\t\t\t\tv2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;\n\t\t\t\t\tif ( fabs(v1[0] - v2[0]) > .1)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif ( fabs(v1[1] - v2[1]) > .1)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif ( fabs(v1[2] - v2[2]) > .1)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t//\n\t\t\t\t\tv1 = grid2->verts[grid2->width * l + offset2].xyz;\n\t\t\t\t\tv2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;\n\t\t\t\t\tif ( fabs(v1[0] - v2[0]) < .01 &&\n\t\t\t\t\t\t\tfabs(v1[1] - v2[1]) < .01 &&\n\t\t\t\t\t\t\tfabs(v1[2] - v2[2]) < .01)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t//\n\t\t\t\t\t//ri.Printf( PRINT_ALL, \"found highest LoD crack between two patches\\n\" );\n\t\t\t\t\t// insert row into grid2 right after after row l\n\t\t\t\t\tif (m) column = grid2->width-1;\n\t\t\t\t\telse column = 0;\n\t\t\t\t\tgrid2 = R_GridInsertRow( grid2, l+1, column,\n\t\t\t\t\t\t\t\t\t\tgrid1->verts[k - 1 + offset1].xyz, grid1->widthLodError[k+1]);\n\t\t\t\t\tif (!grid2)\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tgrid2->lodStitched = qfalse;\n\t\t\t\t\ts_worldData.surfaces[grid2num].data = (surfaceType_t*)(void *)grid2;\n\t\t\t\t\treturn qtrue;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tfor (n = 0; n < 2; n++) {\n\t\t//\n\t\tif (n) offset1 = grid1->width-1;\n\t\telse offset1 = 0;\n\t\tif (R_MergedHeightPoints(grid1, offset1))\n\t\t\tcontinue;\n\t\tfor (k = grid1->height-1; k > 1; k -= 2) {\n\t\t\tfor (m = 0; m < 2; m++) {\n\n\t\t\t\tif ( grid2->width >= MAX_GRID_SIZE )\n\t\t\t\t\tbreak;\n\t\t\t\tif (m) offset2 = (grid2->height-1) * grid2->width;\n\t\t\t\telse offset2 = 0;\n\t\t\t\tfor ( l = 0; l < grid2->width-1; l++) {\n\t\t\t\t//\n\t\t\t\t\tv1 = grid1->verts[grid1->width * k + offset1].xyz;\n\t\t\t\t\tv2 = grid2->verts[l + offset2].xyz;\n\t\t\t\t\tif ( fabs(v1[0] - v2[0]) > .1)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif ( fabs(v1[1] - v2[1]) > .1)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif ( fabs(v1[2] - v2[2]) > .1)\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\tv1 = grid1->verts[grid1->width * (k - 2) + offset1].xyz;\n\t\t\t\t\tv2 = grid2->verts[l + 1 + offset2].xyz;\n\t\t\t\t\tif ( fabs(v1[0] - v2[0]) > .1)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif ( fabs(v1[1] - v2[1]) > .1)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif ( fabs(v1[2] - v2[2]) > .1)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t//\n\t\t\t\t\tv1 = grid2->verts[l + offset2].xyz;\n\t\t\t\t\tv2 = grid2->verts[(l + 1) + offset2].xyz;\n\t\t\t\t\tif ( fabs(v1[0] - v2[0]) < .01 &&\n\t\t\t\t\t\t\tfabs(v1[1] - v2[1]) < .01 &&\n\t\t\t\t\t\t\tfabs(v1[2] - v2[2]) < .01)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t//\n\t\t\t\t\t//ri.Printf( PRINT_ALL, \"found highest LoD crack between two patches\\n\" );\n\t\t\t\t\t// insert column into grid2 right after after column l\n\t\t\t\t\tif (m) row = grid2->height-1;\n\t\t\t\t\telse row = 0;\n\t\t\t\t\tgrid2 = R_GridInsertColumn( grid2, l+1, row,\n\t\t\t\t\t\t\t\t\t\tgrid1->verts[grid1->width * (k - 1) + offset1].xyz, grid1->heightLodError[k+1]);\n\t\t\t\t\tgrid2->lodStitched = qfalse;\n\t\t\t\t\ts_worldData.surfaces[grid2num].data = (surfaceType_t*)(void *)grid2;\n\t\t\t\t\treturn qtrue;\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (m = 0; m < 2; m++) {\n\n\t\t\t\tif (grid2->height >= MAX_GRID_SIZE)\n\t\t\t\t\tbreak;\n\t\t\t\tif (m) offset2 = grid2->width-1;\n\t\t\t\telse offset2 = 0;\n\t\t\t\tfor ( l = 0; l < grid2->height-1; l++) {\n\t\t\t\t//\n\t\t\t\t\tv1 = grid1->verts[grid1->width * k + offset1].xyz;\n\t\t\t\t\tv2 = grid2->verts[grid2->width * l + offset2].xyz;\n\t\t\t\t\tif ( fabs(v1[0] - v2[0]) > .1)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif ( fabs(v1[1] - v2[1]) > .1)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif ( fabs(v1[2] - v2[2]) > .1)\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\tv1 = grid1->verts[grid1->width * (k - 2) + offset1].xyz;\n\t\t\t\t\tv2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;\n\t\t\t\t\tif ( fabs(v1[0] - v2[0]) > .1)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif ( fabs(v1[1] - v2[1]) > .1)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif ( fabs(v1[2] - v2[2]) > .1)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t//\n\t\t\t\t\tv1 = grid2->verts[grid2->width * l + offset2].xyz;\n\t\t\t\t\tv2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;\n\t\t\t\t\tif ( fabs(v1[0] - v2[0]) < .01 &&\n\t\t\t\t\t\t\tfabs(v1[1] - v2[1]) < .01 &&\n\t\t\t\t\t\t\tfabs(v1[2] - v2[2]) < .01)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t//\n\t\t\t\t\t//ri.Printf( PRINT_ALL, \"found highest LoD crack between two patches\\n\" );\n\t\t\t\t\t// insert row into grid2 right after after row l\n\t\t\t\t\tif (m) column = grid2->width-1;\n\t\t\t\t\telse column = 0;\n\t\t\t\t\tgrid2 = R_GridInsertRow( grid2, l+1, column,\n\t\t\t\t\t\t\t\t\t\tgrid1->verts[grid1->width * (k - 1) + offset1].xyz, grid1->heightLodError[k+1]);\n\t\t\t\t\tgrid2->lodStitched = qfalse;\n\t\t\t\t\ts_worldData.surfaces[grid2num].data = (surfaceType_t*)(void *)grid2;\n\t\t\t\t\treturn qtrue;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn qfalse;\n}\n\n/*\n===============\nR_TryStitchPatch\n\nThis function will try to stitch patches in the same LoD group together for the highest LoD.\n\nOnly single missing vertice cracks will be fixed.\n\nVertices will be joined at the patch side a crack is first found, at the other side\nof the patch (on the same row or column) the vertices will not be joined and cracks\nmight still appear at that side.\n===============\n*/\nint R_TryStitchingPatch( int grid1num ) {\n\tint j, numstitches;\n\tsrfGridMesh_t *grid1, *grid2;\n\n\tnumstitches = 0;\n\tgrid1 = (srfGridMesh_t *) s_worldData.surfaces[grid1num].data;\n\tfor ( j = 0; j < s_worldData.numsurfaces; j++ ) {\n\t\t//\n\t\tgrid2 = (srfGridMesh_t *) s_worldData.surfaces[j].data;\n\t\t// if this surface is not a grid\n\t\tif ( grid2->surfaceType != SF_GRID ) continue;\n\t\t// grids in the same LOD group should have the exact same lod radius\n\t\tif ( grid1->lodRadius != grid2->lodRadius ) continue;\n\t\t// grids in the same LOD group should have the exact same lod origin\n\t\tif ( grid1->lodOrigin[0] != grid2->lodOrigin[0] ) continue;\n\t\tif ( grid1->lodOrigin[1] != grid2->lodOrigin[1] ) continue;\n\t\tif ( grid1->lodOrigin[2] != grid2->lodOrigin[2] ) continue;\n\t\t//\n\t\twhile (R_StitchPatches(grid1num, j))\n\t\t{\n\t\t\tnumstitches++;\n\t\t}\n\t}\n\treturn numstitches;\n}\n\n/*\n===============\nR_StitchAllPatches\n===============\n*/\nvoid R_StitchAllPatches( void ) {\n\tint i, stitched, numstitches;\n\tsrfGridMesh_t *grid1;\n\n\tnumstitches = 0;\n\tdo\n\t{\n\t\tstitched = qfalse;\n\t\tfor ( i = 0; i < s_worldData.numsurfaces; i++ ) {\n\t\t\t//\n\t\t\tgrid1 = (srfGridMesh_t *) s_worldData.surfaces[i].data;\n\t\t\t// if this surface is not a grid\n\t\t\tif ( grid1->surfaceType != SF_GRID )\n\t\t\t\tcontinue;\n\t\t\t//\n\t\t\tif ( grid1->lodStitched )\n\t\t\t\tcontinue;\n\t\t\t//\n\t\t\tgrid1->lodStitched = qtrue;\n\t\t\tstitched = qtrue;\n\t\t\t//\n\t\t\tnumstitches += R_TryStitchingPatch( i );\n\t\t}\n\t}\n\twhile (stitched);\n\tri.Printf( PRINT_ALL, \"stitched %d LoD cracks\\n\", numstitches );\n}\n\n/*\n===============\nR_MovePatchSurfacesToHunk\n===============\n*/\nvoid R_MovePatchSurfacesToHunk(void) {\n\tint i, size;\n\tsrfGridMesh_t *grid, *hunkgrid;\n\n\tfor ( i = 0; i < s_worldData.numsurfaces; i++ ) {\n\t\t//\n\t\tgrid = (srfGridMesh_t *) s_worldData.surfaces[i].data;\n\t\t// if this surface is not a grid\n\t\tif ( grid->surfaceType != SF_GRID )\n\t\t\tcontinue;\n\t\t//\n\t\tsize = (grid->width * grid->height - 1) * sizeof( drawVert_t ) + sizeof( *grid );\n\t\thunkgrid = (srfGridMesh_t*) ri.Hunk_Alloc( size, h_low );\n\t\tCom_Memcpy(hunkgrid, grid, size);\n\n\t\thunkgrid->widthLodError = (float*) ri.Hunk_Alloc( grid->width * 4, h_low );\n\t\tCom_Memcpy( hunkgrid->widthLodError, grid->widthLodError, grid->width * 4 );\n\n\t\thunkgrid->heightLodError = (float*) ri.Hunk_Alloc( grid->height * 4, h_low );\n\t\tCom_Memcpy( grid->heightLodError, grid->heightLodError, grid->height * 4 );\n\n\t\tR_FreeSurfaceGridMesh( grid );\n\n\t\ts_worldData.surfaces[i].data = (surfaceType_t*) (void *) hunkgrid;\n\t}\n}\n\n/*\n===============\nR_LoadSurfaces\n===============\n*/\nstatic\tvoid R_LoadSurfaces( lump_t *surfs, lump_t *verts, lump_t *indexLump ) {\n\tdsurface_t\t*in;\n\tmsurface_t\t*out;\n\tdrawVert_t\t*dv;\n\tint\t\t\t*indexes;\n\tint\t\t\tcount;\n\tint\t\t\tnumFaces, numMeshes, numTriSurfs, numFlares;\n\tint\t\t\ti;\n\n\tnumFaces = 0;\n\tnumMeshes = 0;\n\tnumTriSurfs = 0;\n\tnumFlares = 0;\n\n\tin = (dsurface_t*) (void *)(fileBase + surfs->fileofs);\n\tif (surfs->filelen % sizeof(*in))\n\t\tri.Error (ERR_DROP, \"LoadMap: funny lump size in %s\",s_worldData.name);\n\tcount = surfs->filelen / sizeof(*in);\n\n\tdv = (drawVert_t*) (void *)(fileBase + verts->fileofs);\n\tif (verts->filelen % sizeof(*dv))\n\t\tri.Error (ERR_DROP, \"LoadMap: funny lump size in %s\",s_worldData.name);\n\n\tindexes = (int*) (void *)(fileBase + indexLump->fileofs);\n\tif ( indexLump->filelen % sizeof(*indexes))\n\t\tri.Error (ERR_DROP, \"LoadMap: funny lump size in %s\",s_worldData.name);\n\n\tout = (msurface_t*) ri.Hunk_Alloc ( count * sizeof(*out), h_low );\t\n\n\ts_worldData.surfaces = out;\n\ts_worldData.numsurfaces = count;\n\n\tfor ( i = 0 ; i < count ; i++, in++, out++ ) {\n\t\tswitch ( LittleLong( in->surfaceType ) ) {\n\t\tcase MST_PATCH:\n\t\t\tParseMesh ( in, dv, out );\n\t\t\tnumMeshes++;\n\t\t\tbreak;\n\t\tcase MST_TRIANGLE_SOUP:\n\t\t\tParseTriSurf( in, dv, out, indexes );\n\t\t\tnumTriSurfs++;\n\t\t\tbreak;\n\t\tcase MST_PLANAR:\n\t\t\tParseFace( in, dv, out, indexes );\n\t\t\tnumFaces++;\n\t\t\tbreak;\n\t\tcase MST_FLARE:\n\t\t\tParseFlare( in, dv, out, indexes );\n\t\t\tnumFlares++;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tri.Error( ERR_DROP, \"Bad surfaceType\" );\n\t\t}\n\t}\n\n#ifdef PATCH_STITCHING\n\tR_StitchAllPatches();\n#endif\n\n\tR_FixSharedVertexLodError();\n\n#ifdef PATCH_STITCHING\n\tR_MovePatchSurfacesToHunk();\n#endif\n\n\tri.Printf( PRINT_ALL, \"...loaded %d faces, %i meshes, %i trisurfs, %i flares\\n\", \n\t\tnumFaces, numMeshes, numTriSurfs, numFlares );\n}\n\n\n\n/*\n=================\nR_LoadSubmodels\n=================\n*/\nstatic\tvoid R_LoadSubmodels( lump_t *l ) {\n\tdmodel_t\t*in;\n\tbmodel_t\t*out;\n\tint\t\t\ti, j, count;\n\n\tin = (dmodel_t*) (void *)(fileBase + l->fileofs);\n\tif (l->filelen % sizeof(*in))\n\t\tri.Error (ERR_DROP, \"LoadMap: funny lump size in %s\",s_worldData.name);\n\tcount = l->filelen / sizeof(*in);\n\n\ts_worldData.bmodels = out = (bmodel_t*) ri.Hunk_Alloc( count * sizeof(*out), h_low );\n\n\tfor ( i=0 ; i<count ; i++, in++, out++ ) {\n\t\tmodel_t *model;\n\n\t\tmodel = R_AllocModel();\n\n\t\tassert( model != NULL );\t\t\t// this should never happen\n\n\t\tmodel->type = MOD_BRUSH;\n\t\tmodel->bmodel = out;\n\t\tCom_sprintf( model->name, sizeof( model->name ), \"*%d\", i );\n\n\t\tfor (j=0 ; j<3 ; j++) {\n\t\t\tout->bounds[0][j] = LittleFloat (in->mins[j]);\n\t\t\tout->bounds[1][j] = LittleFloat (in->maxs[j]);\n\t\t}\n\n\t\tout->firstSurface = s_worldData.surfaces + LittleLong( in->firstSurface );\n\t\tout->numSurfaces = LittleLong( in->numSurfaces );\n\t}\n}\n\n\n\n//==================================================================\n\n/*\n=================\nR_SetParent\n=================\n*/\nstatic\tvoid R_SetParent (mnode_t *node, mnode_t *parent)\n{\n\tnode->parent = parent;\n\tif (node->contents != -1)\n\t\treturn;\n\tR_SetParent (node->children[0], node);\n\tR_SetParent (node->children[1], node);\n}\n\n/*\n=================\nR_LoadNodesAndLeafs\n=================\n*/\nstatic\tvoid R_LoadNodesAndLeafs (lump_t *nodeLump, lump_t *leafLump) {\n\tint\t\t\ti, j, p;\n\tdnode_t\t\t*in;\n\tdleaf_t\t\t*inLeaf;\n\tmnode_t \t*out;\n\tint\t\t\tnumNodes, numLeafs;\n\n\tin = (dnode_t*) (void *)(fileBase + nodeLump->fileofs);\n\tif (nodeLump->filelen % sizeof(dnode_t) ||\n\t\tleafLump->filelen % sizeof(dleaf_t) ) {\n\t\tri.Error (ERR_DROP, \"LoadMap: funny lump size in %s\",s_worldData.name);\n\t}\n\tnumNodes = nodeLump->filelen / sizeof(dnode_t);\n\tnumLeafs = leafLump->filelen / sizeof(dleaf_t);\n\n\tout = (mnode_t*) ri.Hunk_Alloc ( (numNodes + numLeafs) * sizeof(*out), h_low);\t\n\n\ts_worldData.nodes = out;\n\ts_worldData.numnodes = numNodes + numLeafs;\n\ts_worldData.numDecisionNodes = numNodes;\n\n\t// load nodes\n\tfor ( i=0 ; i<numNodes; i++, in++, out++)\n\t{\n\t\tfor (j=0 ; j<3 ; j++)\n\t\t{\n\t\t\tout->mins[j] = LittleLong (in->mins[j]);\n\t\t\tout->maxs[j] = LittleLong (in->maxs[j]);\n\t\t}\n\t\n\t\tp = LittleLong(in->planeNum);\n\t\tout->plane = s_worldData.planes + p;\n\n\t\tout->contents = CONTENTS_NODE;\t// differentiate from leafs\n\n\t\tfor (j=0 ; j<2 ; j++)\n\t\t{\n\t\t\tp = LittleLong (in->children[j]);\n\t\t\tif (p >= 0)\n\t\t\t\tout->children[j] = s_worldData.nodes + p;\n\t\t\telse\n\t\t\t\tout->children[j] = s_worldData.nodes + numNodes + (-1 - p);\n\t\t}\n\t}\n\t\n\t// load leafs\n\tinLeaf = (dleaf_t*) (void *)(fileBase + leafLump->fileofs);\n\tfor ( i=0 ; i<numLeafs ; i++, inLeaf++, out++)\n\t{\n\t\tfor (j=0 ; j<3 ; j++)\n\t\t{\n\t\t\tout->mins[j] = LittleLong (inLeaf->mins[j]);\n\t\t\tout->maxs[j] = LittleLong (inLeaf->maxs[j]);\n\t\t}\n\n\t\tout->cluster = LittleLong(inLeaf->cluster);\n\t\tout->area = LittleLong(inLeaf->area);\n\n\t\tif ( out->cluster >= s_worldData.numClusters ) {\n\t\t\ts_worldData.numClusters = out->cluster + 1;\n\t\t}\n\n\t\tout->firstmarksurface = s_worldData.marksurfaces +\n\t\t\tLittleLong(inLeaf->firstLeafSurface);\n\t\tout->nummarksurfaces = LittleLong(inLeaf->numLeafSurfaces);\n\t}\t\n\n\t// chain decendants\n\tR_SetParent (s_worldData.nodes, NULL);\n}\n\n//=============================================================================\n\n/*\n=================\nR_LoadShaders\n=================\n*/\nstatic\tvoid R_LoadShaders( lump_t *l ) {\t\n\tint\t\ti, count;\n\tdshader_t\t*in, *out;\n\t\n\tin = (dshader_t*) (void *)(fileBase + l->fileofs);\n\tif (l->filelen % sizeof(*in))\n\t\tri.Error (ERR_DROP, \"LoadMap: funny lump size in %s\",s_worldData.name);\n\tcount = l->filelen / sizeof(*in);\n\tout = (dshader_t*) ri.Hunk_Alloc ( count*sizeof(*out), h_low );\n\n\ts_worldData.shaders = out;\n\ts_worldData.numShaders = count;\n\n\tCom_Memcpy( out, in, count*sizeof(*out) );\n\n\tfor ( i=0 ; i<count ; i++ ) {\n\t\tout[i].surfaceFlags = LittleLong( out[i].surfaceFlags );\n\t\tout[i].contentFlags = LittleLong( out[i].contentFlags );\n\t}\n}\n\n\n/*\n=================\nR_LoadMarksurfaces\n=================\n*/\nstatic\tvoid R_LoadMarksurfaces (lump_t *l)\n{\t\n\tint\t\ti, j, count;\n\tint\t\t*in;\n\tmsurface_t **out;\n\t\n\tin = (int*) (void *)(fileBase + l->fileofs);\n\tif (l->filelen % sizeof(*in))\n\t\tri.Error (ERR_DROP, \"LoadMap: funny lump size in %s\",s_worldData.name);\n\tcount = l->filelen / sizeof(*in);\n\tout = (msurface_t**) ri.Hunk_Alloc ( count*sizeof(*out), h_low);\t\n\n\ts_worldData.marksurfaces = out;\n\ts_worldData.nummarksurfaces = count;\n\n\tfor ( i=0 ; i<count ; i++)\n\t{\n\t\tj = LittleLong(in[i]);\n\t\tout[i] = s_worldData.surfaces + j;\n\t}\n}\n\n\n/*\n=================\nR_LoadPlanes\n=================\n*/\nstatic\tvoid R_LoadPlanes( lump_t *l ) {\n\tint\t\t\ti, j;\n\tcplane_t\t*out;\n\tdplane_t \t*in;\n\tint\t\t\tcount;\n\tint\t\t\tbits;\n\t\n\tin = (dplane_t*) (void *)(fileBase + l->fileofs);\n\tif (l->filelen % sizeof(*in))\n\t\tri.Error (ERR_DROP, \"LoadMap: funny lump size in %s\",s_worldData.name);\n\tcount = l->filelen / sizeof(*in);\n\tout = (cplane_t*) ri.Hunk_Alloc ( count*2*sizeof(*out), h_low);\t\n\t\n\ts_worldData.planes = out;\n\ts_worldData.numplanes = count;\n\n\tfor ( i=0 ; i<count ; i++, in++, out++) {\n\t\tbits = 0;\n\t\tfor (j=0 ; j<3 ; j++) {\n\t\t\tout->normal[j] = LittleFloat (in->normal[j]);\n\t\t\tif (out->normal[j] < 0) {\n\t\t\t\tbits |= 1<<j;\n\t\t\t}\n\t\t}\n\n\t\tout->dist = LittleFloat (in->dist);\n\t\tout->type = PlaneTypeForNormal( out->normal );\n\t\tout->signbits = bits;\n\t}\n}\n\n/*\n=================\nR_LoadFogs\n\n=================\n*/\nstatic\tvoid R_LoadFogs( lump_t *l, lump_t *brushesLump, lump_t *sidesLump ) {\n\tint\t\t\ti;\n\tfog_t\t\t*out;\n\tdfog_t\t\t*fogs;\n\tdbrush_t \t*brushes, *brush;\n\tdbrushside_t\t*sides;\n\tint\t\t\tcount, brushesCount, sidesCount;\n\tint\t\t\tsideNum;\n\tint\t\t\tplaneNum;\n\tshader_t\t*shader;\n\tfloat\t\td;\n\tint\t\t\tfirstSide;\n\n\tfogs = (dfog_t*) (void *)(fileBase + l->fileofs);\n\tif (l->filelen % sizeof(*fogs)) {\n\t\tri.Error (ERR_DROP, \"LoadMap: funny lump size in %s\",s_worldData.name);\n\t}\n\tcount = l->filelen / sizeof(*fogs);\n\n\t// create fog strucutres for them\n\ts_worldData.numfogs = count + 1;\n\ts_worldData.fogs = (fog_t*) ri.Hunk_Alloc ( s_worldData.numfogs*sizeof(*out), h_low);\n\tout = s_worldData.fogs + 1;\n\n\tif ( !count ) {\n\t\treturn;\n\t}\n\n\tbrushes = (dbrush_t*) (void *)(fileBase + brushesLump->fileofs);\n\tif (brushesLump->filelen % sizeof(*brushes)) {\n\t\tri.Error (ERR_DROP, \"LoadMap: funny lump size in %s\",s_worldData.name);\n\t}\n\tbrushesCount = brushesLump->filelen / sizeof(*brushes);\n\n\tsides = (dbrushside_t*) (void *)(fileBase + sidesLump->fileofs);\n\tif (sidesLump->filelen % sizeof(*sides)) {\n\t\tri.Error (ERR_DROP, \"LoadMap: funny lump size in %s\",s_worldData.name);\n\t}\n\tsidesCount = sidesLump->filelen / sizeof(*sides);\n\n\tfor ( i=0 ; i<count ; i++, fogs++) {\n\t\tout->originalBrushNumber = LittleLong( fogs->brushNum );\n\n\t\tif ( (unsigned)out->originalBrushNumber >= brushesCount ) {\n\t\t\tri.Error( ERR_DROP, \"fog brushNumber out of range\" );\n\t\t}\n\t\tbrush = brushes + out->originalBrushNumber;\n\n\t\tfirstSide = LittleLong( brush->firstSide );\n\n\t\t\tif ( (unsigned)firstSide > sidesCount - 6 ) {\n\t\t\tri.Error( ERR_DROP, \"fog brush sideNumber out of range\" );\n\t\t}\n\n\t\t// brushes are always sorted with the axial sides first\n\t\tsideNum = firstSide + 0;\n\t\tplaneNum = LittleLong( sides[ sideNum ].planeNum );\n\t\tout->bounds[0][0] = -s_worldData.planes[ planeNum ].dist;\n\n\t\tsideNum = firstSide + 1;\n\t\tplaneNum = LittleLong( sides[ sideNum ].planeNum );\n\t\tout->bounds[1][0] = s_worldData.planes[ planeNum ].dist;\n\n\t\tsideNum = firstSide + 2;\n\t\tplaneNum = LittleLong( sides[ sideNum ].planeNum );\n\t\tout->bounds[0][1] = -s_worldData.planes[ planeNum ].dist;\n\n\t\tsideNum = firstSide + 3;\n\t\tplaneNum = LittleLong( sides[ sideNum ].planeNum );\n\t\tout->bounds[1][1] = s_worldData.planes[ planeNum ].dist;\n\n\t\tsideNum = firstSide + 4;\n\t\tplaneNum = LittleLong( sides[ sideNum ].planeNum );\n\t\tout->bounds[0][2] = -s_worldData.planes[ planeNum ].dist;\n\n\t\tsideNum = firstSide + 5;\n\t\tplaneNum = LittleLong( sides[ sideNum ].planeNum );\n\t\tout->bounds[1][2] = s_worldData.planes[ planeNum ].dist;\n\n\t\t// get information from the shader for fog parameters\n\t\tshader = R_FindShader( fogs->shader, LIGHTMAP_NONE, qtrue );\n\n\t\tout->parms = shader->fogParms;\n\n\t\tout->colorInt = ColorBytes4 ( shader->fogParms.color[0] * tr.identityLight, \n\t\t\t                          shader->fogParms.color[1] * tr.identityLight, \n\t\t\t                          shader->fogParms.color[2] * tr.identityLight, 1.0 );\n\n\t\td = shader->fogParms.depthForOpaque < 1 ? 1 : shader->fogParms.depthForOpaque;\n\t\tout->tcScale = 1.0f / ( d * 8 );\n\n\t\t// set the gradient vector\n\t\tsideNum = LittleLong( fogs->visibleSide );\n\n\t\tif ( sideNum == -1 ) {\n\t\t\tout->hasSurface = qfalse;\n\t\t} else {\n\t\t\tout->hasSurface = qtrue;\n\t\t\tplaneNum = LittleLong( sides[ firstSide + sideNum ].planeNum );\n\t\t\tVectorSubtract( vec3_origin, s_worldData.planes[ planeNum ].normal, out->surface );\n\t\t\tout->surface[3] = -s_worldData.planes[ planeNum ].dist;\n\t\t}\n\n\t\tout++;\n\t}\n\n}\n\n\n/*\n================\nR_LoadLightGrid\n\n================\n*/\nvoid R_LoadLightGrid( lump_t *l ) {\n\tint\t\ti;\n\tvec3_t\tmaxs;\n\tint\t\tnumGridPoints;\n\tworld_t\t*w;\n\tfloat\t*wMins, *wMaxs;\n\n\tw = &s_worldData;\n\n\tw->lightGridInverseSize[0] = 1.0f / w->lightGridSize[0];\n\tw->lightGridInverseSize[1] = 1.0f / w->lightGridSize[1];\n\tw->lightGridInverseSize[2] = 1.0f / w->lightGridSize[2];\n\n\twMins = w->bmodels[0].bounds[0];\n\twMaxs = w->bmodels[0].bounds[1];\n\n\tfor ( i = 0 ; i < 3 ; i++ ) {\n\t\tw->lightGridOrigin[i] = w->lightGridSize[i] * ceil( wMins[i] / w->lightGridSize[i] );\n\t\tmaxs[i] = w->lightGridSize[i] * floor( wMaxs[i] / w->lightGridSize[i] );\n\t\tw->lightGridBounds[i] = (maxs[i] - w->lightGridOrigin[i])/w->lightGridSize[i] + 1;\n\t}\n\n\tnumGridPoints = w->lightGridBounds[0] * w->lightGridBounds[1] * w->lightGridBounds[2];\n\n\tif ( l->filelen != numGridPoints * 8 ) {\n\t\tri.Printf( PRINT_WARNING, \"WARNING: light grid mismatch\\n\" );\n\t\tw->lightGridData = NULL;\n\t\treturn;\n\t}\n\n\tw->lightGridData = (byte*) ri.Hunk_Alloc( l->filelen, h_low );\n\tCom_Memcpy( w->lightGridData, (void *)(fileBase + l->fileofs), l->filelen );\n\n\t// deal with overbright bits\n\tfor ( i = 0 ; i < numGridPoints ; i++ ) {\n\t\tR_ColorShiftLightingBytes( &w->lightGridData[i*8], &w->lightGridData[i*8] );\n\t\tR_ColorShiftLightingBytes( &w->lightGridData[i*8+3], &w->lightGridData[i*8+3] );\n\t}\n}\n\n/*\n================\nR_LoadEntities\n================\n*/\nvoid R_LoadEntities( lump_t *l ) {\n\tchar *p, *token, *s;\n\tchar keyname[MAX_TOKEN_CHARS];\n\tchar value[MAX_TOKEN_CHARS];\n\tworld_t\t*w;\n\n\tw = &s_worldData;\n\tw->lightGridSize[0] = 64;\n\tw->lightGridSize[1] = 64;\n\tw->lightGridSize[2] = 128;\n\n\tp = (char *)(fileBase + l->fileofs);\n\n\t// store for reference by the cgame\n\tw->entityString = (char*) ri.Hunk_Alloc( l->filelen + 1, h_low );\n\tstrcpy( w->entityString, p );\n\tw->entityParsePoint = w->entityString;\n\n\ttoken = COM_ParseExt( &p, qtrue );\n\tif (!*token || *token != '{') {\n\t\treturn;\n\t}\n\n\t// only parse the world spawn\n\twhile ( 1 ) {\t\n\t\t// parse key\n\t\ttoken = COM_ParseExt( &p, qtrue );\n\n\t\tif ( !*token || *token == '}' ) {\n\t\t\tbreak;\n\t\t}\n\t\tQ_strncpyz(keyname, token, sizeof(keyname));\n\n\t\t// parse value\n\t\ttoken = COM_ParseExt( &p, qtrue );\n\n\t\tif ( !*token || *token == '}' ) {\n\t\t\tbreak;\n\t\t}\n\t\tQ_strncpyz(value, token, sizeof(value));\n\n\t\t// check for remapping of shaders for vertex lighting\n\t\ts = \"vertexremapshader\";\n\t\tif (!Q_strncmp(keyname, s, (int)strlen(s)) ) {\n\t\t\ts = strchr(value, ';');\n\t\t\tif (!s) {\n\t\t\t\tri.Printf( PRINT_WARNING, \"WARNING: no semi colon in vertexshaderremap '%s'\\n\", value );\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t*s++ = 0;\n\t\t\tif (r_vertexLight->integer) {\n\t\t\t\tR_RemapShader(value, s, \"0\");\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\t// check for remapping of shaders\n\t\ts = \"remapshader\";\n\t\tif (!Q_strncmp(keyname, s, (int)strlen(s)) ) {\n\t\t\ts = strchr(value, ';');\n\t\t\tif (!s) {\n\t\t\t\tri.Printf( PRINT_WARNING, \"WARNING: no semi colon in shaderremap '%s'\\n\", value );\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t*s++ = 0;\n\t\t\tR_RemapShader(value, s, \"0\");\n\t\t\tcontinue;\n\t\t}\n\t\t// check for a different grid size\n\t\tif (!Q_stricmp(keyname, \"gridsize\")) {\n\t\t\tsscanf(value, \"%f %f %f\", &w->lightGridSize[0], &w->lightGridSize[1], &w->lightGridSize[2] );\n\t\t\tcontinue;\n\t\t}\n\t}\n}\n\n/*\n=================\nR_GetEntityToken\n=================\n*/\nqboolean R_GetEntityToken( char *buffer, int size ) {\n\tconst char\t*s;\n\n\ts = COM_Parse( &s_worldData.entityParsePoint );\n\tQ_strncpyz( buffer, s, size );\n\tif ( !s_worldData.entityParsePoint || !s[0] ) {\n\t\ts_worldData.entityParsePoint = s_worldData.entityString;\n\t\treturn qfalse;\n\t} else {\n\t\treturn qtrue;\n\t}\n}\n\n/*\n=================\nRE_LoadWorldMap\n\nCalled directly from cgame\n=================\n*/\nvoid RE_LoadWorldMap( const char *name ) {\n\tint\t\t\ti;\n\tdheader_t\t*header;\n\tbyte\t\t*buffer;\n\tbyte\t\t*startMarker;\n\n\tif ( tr.worldMapLoaded ) {\n\t\tri.Error( ERR_DROP, \"ERROR: attempted to redundantly load world map\\n\" );\n\t}\n\n\t// set default sun direction to be used if it isn't\n\t// overridden by a shader\n\ttr.sunDirection[0] = 0.45f;\n\ttr.sunDirection[1] = 0.3f;\n\ttr.sunDirection[2] = 0.9f;\n\n\tVectorNormalize( tr.sunDirection );\n\n\ttr.worldMapLoaded = qtrue;\n\n\t// load it\n    ri.FS_ReadFile( name, (void **)&buffer );\n\tif ( !buffer ) {\n\t\tri.Error (ERR_DROP, \"RE_LoadWorldMap: %s not found\", name);\n\t}\n\n\t// clear tr.world so if the level fails to load, the next\n\t// try will not look at the partially loaded version\n\ttr.world = NULL;\n\n\tCom_Memset( &s_worldData, 0, sizeof( s_worldData ) );\n\tQ_strncpyz( s_worldData.name, name, sizeof( s_worldData.name ) );\n\n\tQ_strncpyz( s_worldData.baseName, COM_SkipPath( s_worldData.name ), sizeof( s_worldData.name ) );\n\tCOM_StripExtension( s_worldData.baseName, s_worldData.baseName );\n\n\tstartMarker = (byte*) ri.Hunk_Alloc(0, h_low);\n\tc_gridVerts = 0;\n\n\theader = (dheader_t *)buffer;\n\tfileBase = (byte *)header;\n\n\ti = LittleLong (header->version);\n\tif ( i != BSP_VERSION ) {\n\t\tri.Error (ERR_DROP, \"RE_LoadWorldMap: %s has wrong version number (%i should be %i)\", \n\t\t\tname, i, BSP_VERSION);\n\t}\n\n\t// swap all the lumps\n\tfor (i=0 ; i<sizeof(dheader_t)/4 ; i++) {\n\t\t((int *)header)[i] = LittleLong ( ((int *)header)[i]);\n\t}\n\n\t// load into heap\n\tR_LoadShaders( &header->lumps[LUMP_SHADERS] );\n\tR_LoadLightmaps( &header->lumps[LUMP_LIGHTMAPS] );\n\tR_LoadPlanes (&header->lumps[LUMP_PLANES]);\n\tR_LoadFogs( &header->lumps[LUMP_FOGS], &header->lumps[LUMP_BRUSHES], &header->lumps[LUMP_BRUSHSIDES] );\n\tR_LoadSurfaces( &header->lumps[LUMP_SURFACES], &header->lumps[LUMP_DRAWVERTS], &header->lumps[LUMP_DRAWINDEXES] );\n\tR_LoadMarksurfaces (&header->lumps[LUMP_LEAFSURFACES]);\n\tR_LoadNodesAndLeafs (&header->lumps[LUMP_NODES], &header->lumps[LUMP_LEAFS]);\n\tR_LoadSubmodels (&header->lumps[LUMP_MODELS]);\n\tR_LoadVisibility( &header->lumps[LUMP_VISIBILITY] );\n\tR_LoadEntities( &header->lumps[LUMP_ENTITIES] );\n\tR_LoadLightGrid( &header->lumps[LUMP_LIGHTGRID] );\n\n\ts_worldData.dataSize = (byte *)ri.Hunk_Alloc(0, h_low) - startMarker;\n\n\t// only set tr.world now that we know the entire level has loaded properly\n\ttr.world = &s_worldData;\n\n    ri.FS_FreeFile( buffer );\n}\n\n"
  },
  {
    "path": "src/engine/renderer/tr_cmds.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n#include \"tr_local.h\"\n\nvolatile renderCommandList_t\t*renderCommandList;\n\nvolatile qboolean\trenderThreadActive;\n\n\n/*\n=====================\nR_PerformanceCounters\n=====================\n*/\nvoid R_PerformanceCounters( void ) {\n\tif ( !r_speeds->integer ) {\n\t\t// clear the counters even if we aren't printing\n\t\tCom_Memset( &tr.pc, 0, sizeof( tr.pc ) );\n\t\tCom_Memset( &backEnd.pc, 0, sizeof( backEnd.pc ) );\n\t\treturn;\n\t}\n\n\tif (r_speeds->integer == 1) {\n\t\tri.Printf (PRINT_ALL, \"%i/%i shaders/surfs %i leafs %i verts %i/%i tris %.2f mtex\\n\",\n\t\t\tbackEnd.pc.c_shaders, backEnd.pc.c_surfaces, tr.pc.c_leafs, backEnd.pc.c_vertexes, \n\t\t\tbackEnd.pc.c_indexes/3, backEnd.pc.c_totalIndexes/3, \n\t\t\tR_SumOfUsedImages()/(1000000.0f)); \n\t} else if (r_speeds->integer == 2) {\n\t\tri.Printf (PRINT_ALL, \"(patch) %i sin %i sclip  %i sout %i bin %i bclip %i bout\\n\",\n\t\t\ttr.pc.c_sphere_cull_patch_in, tr.pc.c_sphere_cull_patch_clip, tr.pc.c_sphere_cull_patch_out, \n\t\t\ttr.pc.c_box_cull_patch_in, tr.pc.c_box_cull_patch_clip, tr.pc.c_box_cull_patch_out );\n\t\tri.Printf (PRINT_ALL, \"(md3) %i sin %i sclip  %i sout %i bin %i bclip %i bout\\n\",\n\t\t\ttr.pc.c_sphere_cull_md3_in, tr.pc.c_sphere_cull_md3_clip, tr.pc.c_sphere_cull_md3_out, \n\t\t\ttr.pc.c_box_cull_md3_in, tr.pc.c_box_cull_md3_clip, tr.pc.c_box_cull_md3_out );\n\t} else if (r_speeds->integer == 3) {\n\t\tri.Printf (PRINT_ALL, \"viewcluster: %i\\n\", tr.viewCluster );\n\t} else if (r_speeds->integer == 4) {\n\t\tif ( backEnd.pc.c_dlightVertexes ) {\n\t\t\tri.Printf (PRINT_ALL, \"dlight srf:%i  culled:%i  verts:%i  tris:%i\\n\", \n\t\t\t\ttr.pc.c_dlightSurfaces, tr.pc.c_dlightSurfacesCulled,\n\t\t\t\tbackEnd.pc.c_dlightVertexes, backEnd.pc.c_dlightIndexes / 3 );\n\t\t}\n\t} \n\telse if (r_speeds->integer == 5 )\n\t{\n\t\tri.Printf( PRINT_ALL, \"zFar: %.0f\\n\", tr.viewParms.zFar );\n\t}\n\n\tCom_Memset( &tr.pc, 0, sizeof( tr.pc ) );\n\tCom_Memset( &backEnd.pc, 0, sizeof( backEnd.pc ) );\n}\n\n\n/*\n====================\nR_InitCommandBuffers\n====================\n*/\nvoid R_InitCommandBuffers( void ) {\n\tglConfig.smpActive = qfalse;\n\tif ( r_smp->integer ) {\n\t\tri.Printf( PRINT_ALL, \"Trying SMP acceleration...\\n\" );\n\t\tif ( GLimp_SpawnRenderThread( RB_RenderThread ) ) {\n\t\t\tri.Printf( PRINT_ALL, \"...succeeded.\\n\" );\n\t\t\tglConfig.smpActive = qtrue;\n\t\t} else {\n\t\t\tri.Printf( PRINT_ALL, \"...failed.\\n\" );\n\t\t}\n\t}\n}\n\n/*\n====================\nR_ShutdownCommandBuffers\n====================\n*/\nvoid R_ShutdownCommandBuffers( void ) {\n\t// kill the rendering thread\n\tif ( glConfig.smpActive ) {\n\t\tGLimp_WakeRenderer( NULL );\n\t\tglConfig.smpActive = qfalse;\n\t}\n}\n\n/*\n====================\nR_IssueRenderCommands\n====================\n*/\nint\tc_blockedOnRender;\nint\tc_blockedOnMain;\n\nvoid R_IssueRenderCommands( qboolean runPerformanceCounters ) {\n\trenderCommandList_t\t*cmdList;\n\n\tcmdList = &backEndData[tr.smpFrame]->commands;\n\tassert(cmdList); // bk001205\n\t// add an end-of-list command\n\t*(int *)(cmdList->cmds + cmdList->used) = RC_END_OF_LIST;\n\n\t// clear it out, in case this is a sync and not a buffer flip\n\tcmdList->used = 0;\n\n\tif ( glConfig.smpActive ) {\n\t\t// if the render thread is not idle, wait for it\n\t\tif ( renderThreadActive ) {\n\t\t\tc_blockedOnRender++;\n\t\t\tif ( r_showSmp->integer ) {\n\t\t\t\tri.Printf( PRINT_ALL, \"R\" );\n\t\t\t}\n\t\t} else {\n\t\t\tc_blockedOnMain++;\n\t\t\tif ( r_showSmp->integer ) {\n\t\t\t\tri.Printf( PRINT_ALL, \".\" );\n\t\t\t}\n\t\t}\n\n\t\t// sleep until the renderer has completed\n\t\tGLimp_FrontEndSleep();\n\t}\n\n\t// at this point, the back end thread is idle, so it is ok\n\t// to look at it's performance counters\n\tif ( runPerformanceCounters ) {\n\t\tR_PerformanceCounters();\n\t}\n\n\t// actually start the commands going\n\tif ( !r_skipBackEnd->integer ) {\n\t\t// let it start on the new batch\n\t\tif ( !glConfig.smpActive ) {\n\t\t\tRB_ExecuteRenderCommands( cmdList->cmds );\n\t\t} else {\n\t\t\tGLimp_WakeRenderer( cmdList );\n\t\t}\n\t}\n}\n\n\n/*\n====================\nR_SyncRenderThread\n\nIssue any pending commands and wait for them to complete.\nAfter exiting, the render thread will have completed its work\nand will remain idle and the main thread is free to issue\nOpenGL calls until R_IssueRenderCommands is called.\n====================\n*/\nvoid R_SyncRenderThread( void ) {\n\tif ( !tr.registered ) {\n\t\treturn;\n\t}\n\tR_IssueRenderCommands( qfalse );\n\n\tif ( !glConfig.smpActive ) {\n\t\treturn;\n\t}\n\tGLimp_FrontEndSleep();\n}\n\n/*\n============\nR_GetCommandBuffer\n\nmake sure there is enough command space, waiting on the\nrender thread if needed.\n============\n*/\nvoid *R_GetCommandBuffer( int bytes ) {\n\trenderCommandList_t\t*cmdList;\n\n\tcmdList = &backEndData[tr.smpFrame]->commands;\n\n\t// always leave room for the end of list command\n\tif ( cmdList->used + bytes + 4 > MAX_RENDER_COMMANDS ) {\n\t\tif ( bytes > MAX_RENDER_COMMANDS - 4 ) {\n\t\t\tri.Error( ERR_FATAL, \"R_GetCommandBuffer: bad size %i\", bytes );\n\t\t}\n\t\t// if we run out of room, just start dropping commands\n\t\treturn NULL;\n\t}\n\n\tcmdList->used += bytes;\n\n\treturn cmdList->cmds + cmdList->used - bytes;\n}\n\n\n/*\n=============\nR_AddDrawSurfCmd\n\n=============\n*/\nvoid\tR_AddDrawSurfCmd( drawSurf_t *drawSurfs, int numDrawSurfs ) {\n\tdrawSurfsCommand_t\t*cmd;\n\n\tcmd = (drawSurfsCommand_t*) R_GetCommandBuffer(sizeof(*cmd));\n\tif ( !cmd ) {\n\t\treturn;\n\t}\n\tcmd->commandId = RC_DRAW_SURFS;\n\n\tcmd->drawSurfs = drawSurfs;\n\tcmd->numDrawSurfs = numDrawSurfs;\n\n\tcmd->refdef = tr.refdef;\n\tcmd->viewParms = tr.viewParms;\n}\n\n\n/*\n=============\nRE_SetColor\n\nPassing NULL will set the color to white\n=============\n*/\nvoid\tRE_SetColor( const float *rgba ) {\n\tsetColorCommand_t\t*cmd;\n\n  if ( !tr.registered ) {\n    return;\n  }\n  cmd = (setColorCommand_t*) R_GetCommandBuffer(sizeof(*cmd));\n\tif ( !cmd ) {\n\t\treturn;\n\t}\n\tcmd->commandId = RC_SET_COLOR;\n\tif ( !rgba ) {\n\t\tstatic float colorWhite[4] = { 1, 1, 1, 1 };\n\n\t\trgba = colorWhite;\n\t}\n\n\tcmd->color[0] = rgba[0];\n\tcmd->color[1] = rgba[1];\n\tcmd->color[2] = rgba[2];\n\tcmd->color[3] = rgba[3];\n}\n\n\n/*\n=============\nRE_StretchPic\n=============\n*/\nvoid RE_StretchPic ( float x, float y, float w, float h, \n\t\t\t\t\t  float s1, float t1, float s2, float t2, qhandle_t hShader ) {\n\tstretchPicCommand_t\t*cmd;\n\n  if (!tr.registered) {\n    return;\n  }\n  cmd = (stretchPicCommand_t*) R_GetCommandBuffer(sizeof(*cmd));\n\tif ( !cmd ) {\n\t\treturn;\n\t}\n\tcmd->commandId = RC_STRETCH_PIC;\n\tcmd->shader = R_GetShaderByHandle( hShader );\n\tcmd->x = x;\n\tcmd->y = y;\n\tcmd->w = w;\n\tcmd->h = h;\n\tcmd->s1 = s1;\n\tcmd->t1 = t1;\n\tcmd->s2 = s2;\n\tcmd->t2 = t2;\n}\n\n\n/*\n====================\nRE_BeginFrame\n\nIf running in stereo, RE_BeginFrame will be called twice\nfor each RE_EndFrame\n====================\n*/\nvoid RE_BeginFrame( stereoFrame_t stereoFrame ) {\n\tdrawBufferCommand_t\t*cmd;\n\n\tif ( !tr.registered ) {\n\t\treturn;\n\t}\n\n\ttr.frameCount++;\n\n\t//\n\t// texturemode stuff\n\t//\n\tif ( r_textureMode->modified ) {\n\t\tR_SyncRenderThread();\n\t\tGL_TextureMode( r_textureMode->string );\n\t\tr_textureMode->modified = qfalse;\n\t}\n\n\t//\n\t// gamma stuff\n\t//\n\tif ( r_gamma->modified || r_shaderGamma->modified ) {\n\t\tr_gamma->modified = qfalse;\n\n\t\tR_SyncRenderThread();\n\t\tR_SetColorMappings();\n\t\tr_shaderGamma->modified = qfalse;\n\t}\n\n    // check for errors\n    if ( !r_ignoreGLErrors->integer ) {\n        int\terr;\n\n\t\tR_SyncRenderThread();\n        if ( ( err = qglGetError() ) != GL_NO_ERROR ) {\n            ri.Error( ERR_FATAL, \"RE_BeginFrame() - glGetError() failed (0x%x)!\\n\", err );\n        }\n    }\n\n\t//\n\t// draw buffer stuff\n\t//\n\tcmd = (drawBufferCommand_t*) R_GetCommandBuffer(sizeof(*cmd));\n\tif ( !cmd ) {\n\t\treturn;\n\t}\n\tcmd->commandId = RC_DRAW_BUFFER;\n\n\tif ( glConfig.stereoEnabled ) {\n\t\tif ( stereoFrame == STEREO_LEFT ) {\n\t\t\tcmd->buffer = (int)GL_BACK_LEFT;\n\t\t} else if ( stereoFrame == STEREO_RIGHT ) {\n\t\t\tcmd->buffer = (int)GL_BACK_RIGHT;\n\t\t} else {\n\t\t\tri.Error( ERR_FATAL, \"RE_BeginFrame: Stereo is enabled, but stereoFrame was %i\", stereoFrame );\n\t\t}\n\t} else {\n\t\tif ( stereoFrame != STEREO_CENTER ) {\n\t\t\tri.Error( ERR_FATAL, \"RE_BeginFrame: Stereo is disabled, but stereoFrame was %i\", stereoFrame );\n\t\t}\n\t\tif ( !Q_stricmp( r_drawBuffer->string, \"GL_FRONT\" ) ) {\n\t\t\tcmd->buffer = (int)GL_FRONT;\n\t\t} else {\n\t\t\tcmd->buffer = (int)GL_BACK;\n\t\t}\n\t}\n}\n\n\n/*\n=============\nRE_EndFrame\n\nReturns the number of msec spent in the back end\n=============\n*/\nvoid RE_EndFrame( int *frontEndMsec, int *backEndMsec ) {\n\tswapBuffersCommand_t\t*cmd;\n\n\tif ( !tr.registered ) {\n\t\treturn;\n\t}\n\tcmd = (swapBuffersCommand_t*) R_GetCommandBuffer(sizeof(*cmd));\n\tif ( !cmd ) {\n\t\treturn;\n\t}\n\tcmd->commandId = RC_SWAP_BUFFERS;\n\n\tR_IssueRenderCommands( qtrue );\n\n\t// use the other buffers next frame, because another CPU\n\t// may still be rendering into the current ones\n\tR_ToggleSmpFrame();\n\n\tif ( frontEndMsec ) {\n\t\t*frontEndMsec = tr.frontEndMsec;\n\t}\n\ttr.frontEndMsec = 0;\n\tif ( backEndMsec ) {\n\t\t*backEndMsec = backEnd.pc.msec;\n\t}\n\tbackEnd.pc.msec = 0;\n}\n\n"
  },
  {
    "path": "src/engine/renderer/tr_curve.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n#include \"tr_local.h\"\n\n/*\n\nThis file does all of the processing necessary to turn a raw grid of points\nread from the map file into a srfGridMesh_t ready for rendering.\n\nThe level of detail solution is direction independent, based only on subdivided\ndistance from the true curve.\n\nOnly a single entry point:\n\nsrfGridMesh_t *R_SubdividePatchToGrid( int width, int height,\n\t\t\t\t\t\t\t\tdrawVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ) {\n\n*/\n\n\n/*\n============\nLerpDrawVert\n============\n*/\nstatic void LerpDrawVert( drawVert_t *a, drawVert_t *b, drawVert_t *out ) {\n\tout->xyz[0] = 0.5f * (a->xyz[0] + b->xyz[0]);\n\tout->xyz[1] = 0.5f * (a->xyz[1] + b->xyz[1]);\n\tout->xyz[2] = 0.5f * (a->xyz[2] + b->xyz[2]);\n\n\tout->st[0] = 0.5f * (a->st[0] + b->st[0]);\n\tout->st[1] = 0.5f * (a->st[1] + b->st[1]);\n\n\tout->lightmap[0] = 0.5f * (a->lightmap[0] + b->lightmap[0]);\n\tout->lightmap[1] = 0.5f * (a->lightmap[1] + b->lightmap[1]);\n\n\tout->color[0] = (a->color[0] + b->color[0]) >> 1;\n\tout->color[1] = (a->color[1] + b->color[1]) >> 1;\n\tout->color[2] = (a->color[2] + b->color[2]) >> 1;\n\tout->color[3] = (a->color[3] + b->color[3]) >> 1;\n}\n\n/*\n============\nTranspose\n============\n*/\nstatic void Transpose( int width, int height, drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) {\n\tint\t\ti, j;\n\tdrawVert_t\ttemp;\n\n\tif ( width > height ) {\n\t\tfor ( i = 0 ; i < height ; i++ ) {\n\t\t\tfor ( j = i + 1 ; j < width ; j++ ) {\n\t\t\t\tif ( j < height ) {\n\t\t\t\t\t// swap the value\n\t\t\t\t\ttemp = ctrl[j][i];\n\t\t\t\t\tctrl[j][i] = ctrl[i][j];\n\t\t\t\t\tctrl[i][j] = temp;\n\t\t\t\t} else {\n\t\t\t\t\t// just copy\n\t\t\t\t\tctrl[j][i] = ctrl[i][j];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} else {\n\t\tfor ( i = 0 ; i < width ; i++ ) {\n\t\t\tfor ( j = i + 1 ; j < height ; j++ ) {\n\t\t\t\tif ( j < width ) {\n\t\t\t\t\t// swap the value\n\t\t\t\t\ttemp = ctrl[i][j];\n\t\t\t\t\tctrl[i][j] = ctrl[j][i];\n\t\t\t\t\tctrl[j][i] = temp;\n\t\t\t\t} else {\n\t\t\t\t\t// just copy\n\t\t\t\t\tctrl[i][j] = ctrl[j][i];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n}\n\n\n/*\n=================\nMakeMeshNormals\n\nHandles all the complicated wrapping and degenerate cases\n=================\n*/\nstatic void MakeMeshNormals( int width, int height, drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) {\n\tint\t\ti, j, k, dist;\n\tvec3_t\tnormal;\n\tvec3_t\tsum;\n\tint\t\tcount;\n\tvec3_t\tbase;\n\tvec3_t\tdelta;\n\tint\t\tx, y;\n\tdrawVert_t\t*dv;\n\tvec3_t\t\taround[8], temp;\n\tqboolean\tgood[8];\n\tqboolean\twrapWidth, wrapHeight;\n\tfloat\t\tlen;\nstatic\tint\tneighbors[8][2] = {\n\t{0,1}, {1,1}, {1,0}, {1,-1}, {0,-1}, {-1,-1}, {-1,0}, {-1,1}\n\t};\n\n\twrapWidth = qfalse;\n\tfor ( i = 0 ; i < height ; i++ ) {\n\t\tVectorSubtract( ctrl[i][0].xyz, ctrl[i][width-1].xyz, delta );\n\t\tlen = VectorLengthSquared( delta );\n\t\tif ( len > 1.0 ) {\n\t\t\tbreak;\n\t\t}\n\t}\n\tif ( i == height ) {\n\t\twrapWidth = qtrue;\n\t}\n\n\twrapHeight = qfalse;\n\tfor ( i = 0 ; i < width ; i++ ) {\n\t\tVectorSubtract( ctrl[0][i].xyz, ctrl[height-1][i].xyz, delta );\n\t\tlen = VectorLengthSquared( delta );\n\t\tif ( len > 1.0 ) {\n\t\t\tbreak;\n\t\t}\n\t}\n\tif ( i == width) {\n\t\twrapHeight = qtrue;\n\t}\n\n\n\tfor ( i = 0 ; i < width ; i++ ) {\n\t\tfor ( j = 0 ; j < height ; j++ ) {\n\t\t\tcount = 0;\n\t\t\tdv = &ctrl[j][i];\n\t\t\tVectorCopy( dv->xyz, base );\n\t\t\tfor ( k = 0 ; k < 8 ; k++ ) {\n\t\t\t\tVectorClear( around[k] );\n\t\t\t\tgood[k] = qfalse;\n\n\t\t\t\tfor ( dist = 1 ; dist <= 3 ; dist++ ) {\n\t\t\t\t\tx = i + neighbors[k][0] * dist;\n\t\t\t\t\ty = j + neighbors[k][1] * dist;\n\t\t\t\t\tif ( wrapWidth ) {\n\t\t\t\t\t\tif ( x < 0 ) {\n\t\t\t\t\t\t\tx = width - 1 + x;\n\t\t\t\t\t\t} else if ( x >= width ) {\n\t\t\t\t\t\t\tx = 1 + x - width;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif ( wrapHeight ) {\n\t\t\t\t\t\tif ( y < 0 ) {\n\t\t\t\t\t\t\ty = height - 1 + y;\n\t\t\t\t\t\t} else if ( y >= height ) {\n\t\t\t\t\t\t\ty = 1 + y - height;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( x < 0 || x >= width || y < 0 || y >= height ) {\n\t\t\t\t\t\tbreak;\t\t\t\t\t// edge of patch\n\t\t\t\t\t}\n\t\t\t\t\tVectorSubtract( ctrl[y][x].xyz, base, temp );\n\t\t\t\t\tif ( VectorNormalize2( temp, temp ) == 0 ) {\n\t\t\t\t\t\tcontinue;\t\t\t\t// degenerate edge, get more dist\n\t\t\t\t\t} else {\n\t\t\t\t\t\tgood[k] = qtrue;\n\t\t\t\t\t\tVectorCopy( temp, around[k] );\n\t\t\t\t\t\tbreak;\t\t\t\t\t// good edge\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tVectorClear( sum );\n\t\t\tfor ( k = 0 ; k < 8 ; k++ ) {\n\t\t\t\tif ( !good[k] || !good[(k+1)&7] ) {\n\t\t\t\t\tcontinue;\t// didn't get two points\n\t\t\t\t}\n\t\t\t\tCrossProduct( around[(k+1)&7], around[k], normal );\n\t\t\t\tif ( VectorNormalize2( normal, normal ) == 0 ) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tVectorAdd( normal, sum, sum );\n\t\t\t\tcount++;\n\t\t\t}\n\t\t\tif ( count == 0 ) {\n//printf(\"bad normal\\n\");\n\t\t\t\tcount = 1;\n\t\t\t}\n\t\t\tVectorNormalize2( sum, dv->normal );\n\t\t}\n\t}\n}\n\n\n/*\n============\nInvertCtrl\n============\n*/\nstatic void InvertCtrl( int width, int height, drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) {\n\tint\t\ti, j;\n\tdrawVert_t\ttemp;\n\n\tfor ( i = 0 ; i < height ; i++ ) {\n\t\tfor ( j = 0 ; j < width/2 ; j++ ) {\n\t\t\ttemp = ctrl[i][j];\n\t\t\tctrl[i][j] = ctrl[i][width-1-j];\n\t\t\tctrl[i][width-1-j] = temp;\n\t\t}\n\t}\n}\n\n\n/*\n=================\nInvertErrorTable\n=================\n*/\nstatic void InvertErrorTable( float errorTable[2][MAX_GRID_SIZE], int width, int height ) {\n\tint\t\ti;\n\tfloat\tcopy[2][MAX_GRID_SIZE];\n\n\tCom_Memcpy( copy, errorTable, sizeof( copy ) );\n\n\tfor ( i = 0 ; i < width ; i++ ) {\n\t\terrorTable[1][i] = copy[0][i];\t//[width-1-i];\n\t}\n\n\tfor ( i = 0 ; i < height ; i++ ) {\n\t\terrorTable[0][i] = copy[1][height-1-i];\n\t}\n\n}\n\n/*\n==================\nPutPointsOnCurve\n==================\n*/\nstatic void PutPointsOnCurve( drawVert_t\tctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], \n\t\t\t\t\t\t\t int width, int height ) {\n\tint\t\t\ti, j;\n\tdrawVert_t\tprev, next;\n\n\tfor ( i = 0 ; i < width ; i++ ) {\n\t\tfor ( j = 1 ; j < height ; j += 2 ) {\n\t\t\tLerpDrawVert( &ctrl[j][i], &ctrl[j+1][i], &prev );\n\t\t\tLerpDrawVert( &ctrl[j][i], &ctrl[j-1][i], &next );\n\t\t\tLerpDrawVert( &prev, &next, &ctrl[j][i] );\n\t\t}\n\t}\n\n\n\tfor ( j = 0 ; j < height ; j++ ) {\n\t\tfor ( i = 1 ; i < width ; i += 2 ) {\n\t\t\tLerpDrawVert( &ctrl[j][i], &ctrl[j][i+1], &prev );\n\t\t\tLerpDrawVert( &ctrl[j][i], &ctrl[j][i-1], &next );\n\t\t\tLerpDrawVert( &prev, &next, &ctrl[j][i] );\n\t\t}\n\t}\n}\n\n/*\n=================\nR_CreateSurfaceGridMesh\n=================\n*/\nsrfGridMesh_t *R_CreateSurfaceGridMesh(int width, int height,\n\t\t\t\t\t\t\t\tdrawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], float errorTable[2][MAX_GRID_SIZE] ) {\n\tint i, j, size;\n\tdrawVert_t\t*vert;\n\tvec3_t\t\ttmpVec;\n\tsrfGridMesh_t *grid;\n\n\t// copy the results out to a grid\n\tsize = (width * height - 1) * sizeof( drawVert_t ) + sizeof( *grid );\n\n#ifdef PATCH_STITCHING\n\tgrid = /*ri.Hunk_Alloc*/ (srfGridMesh_t*) ri.Malloc( size );\n\tCom_Memset(grid, 0, size);\n\n\tgrid->widthLodError = /*ri.Hunk_Alloc*/ (float*) ri.Malloc( width * 4 );\n\tCom_Memcpy( grid->widthLodError, errorTable[0], width * 4 );\n\n\tgrid->heightLodError = /*ri.Hunk_Alloc*/ (float*) ri.Malloc( height * 4 );\n\tCom_Memcpy( grid->heightLodError, errorTable[1], height * 4 );\n#else\n\tgrid = ri.Hunk_Alloc( size );\n\tCom_Memset(grid, 0, size);\n\n\tgrid->widthLodError = ri.Hunk_Alloc( width * 4 );\n\tCom_Memcpy( grid->widthLodError, errorTable[0], width * 4 );\n\n\tgrid->heightLodError = ri.Hunk_Alloc( height * 4 );\n\tCom_Memcpy( grid->heightLodError, errorTable[1], height * 4 );\n#endif\n\n\tgrid->width = width;\n\tgrid->height = height;\n\tgrid->surfaceType = SF_GRID;\n\tClearBounds( grid->meshBounds[0], grid->meshBounds[1] );\n\tfor ( i = 0 ; i < width ; i++ ) {\n\t\tfor ( j = 0 ; j < height ; j++ ) {\n\t\t\tvert = &grid->verts[j*width+i];\n\t\t\t*vert = ctrl[j][i];\n\t\t\tAddPointToBounds( vert->xyz, grid->meshBounds[0], grid->meshBounds[1] );\n\t\t}\n\t}\n\n\t// compute local origin and bounds\n\tVectorAdd( grid->meshBounds[0], grid->meshBounds[1], grid->localOrigin );\n\tVectorScale( grid->localOrigin, 0.5f, grid->localOrigin );\n\tVectorSubtract( grid->meshBounds[0], grid->localOrigin, tmpVec );\n\tgrid->meshRadius = VectorLength( tmpVec );\n\n\tVectorCopy( grid->localOrigin, grid->lodOrigin );\n\tgrid->lodRadius = grid->meshRadius;\n\t//\n\treturn grid;\n}\n\n/*\n=================\nR_FreeSurfaceGridMesh\n=================\n*/\nvoid R_FreeSurfaceGridMesh( srfGridMesh_t *grid ) {\n\tri.Free(grid->widthLodError);\n\tri.Free(grid->heightLodError);\n\tri.Free(grid);\n}\n\n/*\n=================\nR_SubdividePatchToGrid\n=================\n*/\nsrfGridMesh_t *R_SubdividePatchToGrid( int width, int height,\n\t\t\t\t\t\t\t\tdrawVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ) {\n\tint\t\t\ti, j, k, l;\n\tdrawVert_t\tprev, next, mid;\n\tfloat\t\tlen, maxLen;\n\tint\t\t\tdir;\n\tint\t\t\tt;\n\tMAC_STATIC drawVert_t\tctrl[MAX_GRID_SIZE][MAX_GRID_SIZE];\n\tfloat\t\terrorTable[2][MAX_GRID_SIZE];\n\n\tfor ( i = 0 ; i < width ; i++ ) {\n\t\tfor ( j = 0 ; j < height ; j++ ) {\n\t\t\tctrl[j][i] = points[j*width+i];\n\t\t}\n\t}\n\n\tfor ( dir = 0 ; dir < 2 ; dir++ ) {\n\n\t\tfor ( j = 0 ; j < MAX_GRID_SIZE ; j++ ) {\n\t\t\terrorTable[dir][j] = 0;\n\t\t}\n\n\t\t// horizontal subdivisions\n\t\tfor ( j = 0 ; j + 2 < width ; j += 2 ) {\n\t\t\t// check subdivided midpoints against control points\n\n\t\t\t// FIXME: also check midpoints of adjacent patches against the control points\n\t\t\t// this would basically stitch all patches in the same LOD group together.\n\n\t\t\tmaxLen = 0;\n\t\t\tfor ( i = 0 ; i < height ; i++ ) {\n\t\t\t\tvec3_t\t\tmidxyz;\n\t\t\t\tvec3_t\t\tmidxyz2;\n\t\t\t\tvec3_t\t\tdir;\n\t\t\t\tvec3_t\t\tprojected;\n\t\t\t\tfloat\t\td;\n\n\t\t\t\t// calculate the point on the curve\n\t\t\t\tfor ( l = 0 ; l < 3 ; l++ ) {\n\t\t\t\t\tmidxyz[l] = (ctrl[i][j].xyz[l] + ctrl[i][j+1].xyz[l] * 2\n\t\t\t\t\t\t\t+ ctrl[i][j+2].xyz[l] ) * 0.25f;\n\t\t\t\t}\n\n\t\t\t\t// see how far off the line it is\n\t\t\t\t// using dist-from-line will not account for internal\n\t\t\t\t// texture warping, but it gives a lot less polygons than\n\t\t\t\t// dist-from-midpoint\n\t\t\t\tVectorSubtract( midxyz, ctrl[i][j].xyz, midxyz );\n\t\t\t\tVectorSubtract( ctrl[i][j+2].xyz, ctrl[i][j].xyz, dir );\n\t\t\t\tVectorNormalize( dir );\n\n\t\t\t\td = DotProduct( midxyz, dir );\n\t\t\t\tVectorScale( dir, d, projected );\n\t\t\t\tVectorSubtract( midxyz, projected, midxyz2);\n\t\t\t\tlen = VectorLengthSquared( midxyz2 );\t\t\t// we will do the sqrt later\n\t\t\t\tif ( len > maxLen ) {\n\t\t\t\t\tmaxLen = len;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tmaxLen = sqrt(maxLen);\n\n\t\t\t// if all the points are on the lines, remove the entire columns\n\t\t\tif ( maxLen < 0.1f ) {\n\t\t\t\terrorTable[dir][j+1] = 999;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// see if we want to insert subdivided columns\n\t\t\tif ( width + 2 > MAX_GRID_SIZE ) {\n\t\t\t\terrorTable[dir][j+1] = 1.0f/maxLen;\n\t\t\t\tcontinue;\t// can't subdivide any more\n\t\t\t}\n\n\t\t\tif ( maxLen <= r_subdivisions->value ) {\n\t\t\t\terrorTable[dir][j+1] = 1.0f/maxLen;\n\t\t\t\tcontinue;\t// didn't need subdivision\n\t\t\t}\n\n\t\t\terrorTable[dir][j+2] = 1.0f/maxLen;\n\n\t\t\t// insert two columns and replace the peak\n\t\t\twidth += 2;\n\t\t\tfor ( i = 0 ; i < height ; i++ ) {\n\t\t\t\tLerpDrawVert( &ctrl[i][j], &ctrl[i][j+1], &prev );\n\t\t\t\tLerpDrawVert( &ctrl[i][j+1], &ctrl[i][j+2], &next );\n\t\t\t\tLerpDrawVert( &prev, &next, &mid );\n\n\t\t\t\tfor ( k = width - 1 ; k > j + 3 ; k-- ) {\n\t\t\t\t\tctrl[i][k] = ctrl[i][k-2];\n\t\t\t\t}\n\t\t\t\tctrl[i][j + 1] = prev;\n\t\t\t\tctrl[i][j + 2] = mid;\n\t\t\t\tctrl[i][j + 3] = next;\n\t\t\t}\n\n\t\t\t// back up and recheck this set again, it may need more subdivision\n\t\t\tj -= 2;\n\n\t\t}\n\n\t\tTranspose( width, height, ctrl );\n\t\tt = width;\n\t\twidth = height;\n\t\theight = t;\n\t}\n\n\n\t// put all the aproximating points on the curve\n\tPutPointsOnCurve( ctrl, width, height );\n\n\t// cull out any rows or columns that are colinear\n\tfor ( i = 1 ; i < width-1 ; i++ ) {\n\t\tif ( errorTable[0][i] != 999 ) {\n\t\t\tcontinue;\n\t\t}\n\t\tfor ( j = i+1 ; j < width ; j++ ) {\n\t\t\tfor ( k = 0 ; k < height ; k++ ) {\n\t\t\t\tctrl[k][j-1] = ctrl[k][j];\n\t\t\t}\n\t\t\terrorTable[0][j-1] = errorTable[0][j];\n\t\t}\n\t\twidth--;\n\t}\n\n\tfor ( i = 1 ; i < height-1 ; i++ ) {\n\t\tif ( errorTable[1][i] != 999 ) {\n\t\t\tcontinue;\n\t\t}\n\t\tfor ( j = i+1 ; j < height ; j++ ) {\n\t\t\tfor ( k = 0 ; k < width ; k++ ) {\n\t\t\t\tctrl[j-1][k] = ctrl[j][k];\n\t\t\t}\n\t\t\terrorTable[1][j-1] = errorTable[1][j];\n\t\t}\n\t\theight--;\n\t}\n\n#if 1\n\t// flip for longest tristrips as an optimization\n\t// the results should be visually identical with or\n\t// without this step\n\tif ( height > width ) {\n\t\tTranspose( width, height, ctrl );\n\t\tInvertErrorTable( errorTable, width, height );\n\t\tt = width;\n\t\twidth = height;\n\t\theight = t;\n\t\tInvertCtrl( width, height, ctrl );\n\t}\n#endif\n\n\t// calculate normals\n\tMakeMeshNormals( width, height, ctrl );\n\n\treturn R_CreateSurfaceGridMesh( width, height, ctrl, errorTable );\n}\n\n/*\n===============\nR_GridInsertColumn\n===============\n*/\nsrfGridMesh_t *R_GridInsertColumn( srfGridMesh_t *grid, int column, int row, vec3_t point, float loderror ) {\n\tint i, j;\n\tint width, height, oldwidth;\n\tMAC_STATIC drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE];\n\tfloat errorTable[2][MAX_GRID_SIZE];\n\tfloat lodRadius;\n\tvec3_t lodOrigin;\n\n\toldwidth = 0;\n\twidth = grid->width + 1;\n\tif (width > MAX_GRID_SIZE)\n\t\treturn NULL;\n\theight = grid->height;\n\tfor (i = 0; i < width; i++) {\n\t\tif (i == column) {\n\t\t\t//insert new column\n\t\t\tfor (j = 0; j < grid->height; j++) {\n\t\t\t\tLerpDrawVert( &grid->verts[j * grid->width + i-1], &grid->verts[j * grid->width + i], &ctrl[j][i] );\n\t\t\t\tif (j == row)\n\t\t\t\t\tVectorCopy(point, ctrl[j][i].xyz);\n\t\t\t}\n\t\t\terrorTable[0][i] = loderror;\n\t\t\tcontinue;\n\t\t}\n\t\terrorTable[0][i] = grid->widthLodError[oldwidth];\n\t\tfor (j = 0; j < grid->height; j++) {\n\t\t\tctrl[j][i] = grid->verts[j * grid->width + oldwidth];\n\t\t}\n\t\toldwidth++;\n\t}\n\tfor (j = 0; j < grid->height; j++) {\n\t\terrorTable[1][j] = grid->heightLodError[j];\n\t}\n\t// put all the aproximating points on the curve\n\t//PutPointsOnCurve( ctrl, width, height );\n\t// calculate normals\n\tMakeMeshNormals( width, height, ctrl );\n\n\tVectorCopy(grid->lodOrigin, lodOrigin);\n\tlodRadius = grid->lodRadius;\n\t// free the old grid\n\tR_FreeSurfaceGridMesh(grid);\n\t// create a new grid\n\tgrid = R_CreateSurfaceGridMesh( width, height, ctrl, errorTable );\n\tgrid->lodRadius = lodRadius;\n\tVectorCopy(lodOrigin, grid->lodOrigin);\n\treturn grid;\n}\n\n/*\n===============\nR_GridInsertRow\n===============\n*/\nsrfGridMesh_t *R_GridInsertRow( srfGridMesh_t *grid, int row, int column, vec3_t point, float loderror ) {\n\tint i, j;\n\tint width, height, oldheight;\n\tMAC_STATIC drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE];\n\tfloat errorTable[2][MAX_GRID_SIZE];\n\tfloat lodRadius;\n\tvec3_t lodOrigin;\n\n\toldheight = 0;\n\twidth = grid->width;\n\theight = grid->height + 1;\n\tif (height > MAX_GRID_SIZE)\n\t\treturn NULL;\n\tfor (i = 0; i < height; i++) {\n\t\tif (i == row) {\n\t\t\t//insert new row\n\t\t\tfor (j = 0; j < grid->width; j++) {\n\t\t\t\tLerpDrawVert( &grid->verts[(i-1) * grid->width + j], &grid->verts[i * grid->width + j], &ctrl[i][j] );\n\t\t\t\tif (j == column)\n\t\t\t\t\tVectorCopy(point, ctrl[i][j].xyz);\n\t\t\t}\n\t\t\terrorTable[1][i] = loderror;\n\t\t\tcontinue;\n\t\t}\n\t\terrorTable[1][i] = grid->heightLodError[oldheight];\n\t\tfor (j = 0; j < grid->width; j++) {\n\t\t\tctrl[i][j] = grid->verts[oldheight * grid->width + j];\n\t\t}\n\t\toldheight++;\n\t}\n\tfor (j = 0; j < grid->width; j++) {\n\t\terrorTable[0][j] = grid->widthLodError[j];\n\t}\n\t// put all the aproximating points on the curve\n\t//PutPointsOnCurve( ctrl, width, height );\n\t// calculate normals\n\tMakeMeshNormals( width, height, ctrl );\n\n\tVectorCopy(grid->lodOrigin, lodOrigin);\n\tlodRadius = grid->lodRadius;\n\t// free the old grid\n\tR_FreeSurfaceGridMesh(grid);\n\t// create a new grid\n\tgrid = R_CreateSurfaceGridMesh( width, height, ctrl, errorTable );\n\tgrid->lodRadius = lodRadius;\n\tVectorCopy(lodOrigin, grid->lodOrigin);\n\treturn grid;\n}\n"
  },
  {
    "path": "src/engine/renderer/tr_font.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n// tr_font.c\n// \n//\n// The font system uses FreeType 2.x to render TrueType fonts for use within the game.\n// As of this writing ( Nov, 2000 ) Team Arena uses these fonts for all of the ui and \n// about 90% of the cgame presentation. A few areas of the CGAME were left uses the old \n// fonts since the code is shared with standard Q3A.\n//\n// If you include this font rendering code in a commercial product you MUST include the\n// following somewhere with your product, see www.freetype.org for specifics or changes.\n// The Freetype code also uses some hinting techniques that MIGHT infringe on patents \n// held by apple so be aware of that also.\n//\n// As of Q3A 1.25+ and Team Arena, we are shipping the game with the font rendering code\n// disabled. This removes any potential patent issues and it keeps us from having to \n// distribute an actual TrueTrype font which is 1. expensive to do and 2. seems to require\n// an act of god to accomplish. \n//\n// What we did was pre-render the fonts using FreeType ( which is why we leave the FreeType\n// credit in the credits ) and then saved off the glyph data and then hand touched up the \n// font bitmaps so they scale a bit better in GL.\n//\n// There are limitations in the way fonts are saved and reloaded in that it is based on \n// point size and not name. So if you pre-render Helvetica in 18 point and Impact in 18 point\n// you will end up with a single 18 point data file and image set. Typically you will want to \n// choose 3 sizes to best approximate the scaling you will be doing in the ui scripting system\n// \n// In the UI Scripting code, a scale of 1.0 is equal to a 48 point font. In Team Arena, we\n// use three or four scales, most of them exactly equaling the specific rendered size. We \n// rendered three sizes in Team Arena, 12, 16, and 20. \n//\n// To generate new font data you need to go through the following steps.\n// 1. delete the fontImage_x_xx.tga files and fontImage_xx.dat files from the fonts path.\n// 2. in a ui script, specificy a font, smallFont, and bigFont keyword with font name and \n//    point size. the original TrueType fonts must exist in fonts at this point.\n// 3. run the game, you should see things normally.\n// 4. Exit the game and there will be three dat files and at least three tga files. The \n//    tga's are in 256x256 pages so if it takes three images to render a 24 point font you \n//    will end up with fontImage_0_24.tga through fontImage_2_24.tga\n// 5. You will need to flip the tga's in Photoshop as the tga output code writes them upside\n//    down.\n// 6. In future runs of the game, the system looks for these images and data files when a s\n//    specific point sized font is rendered and loads them for use. \n// 7. Because of the original beta nature of the FreeType code you will probably want to hand\n//    touch the font bitmaps.\n// \n// Currently a define in the project turns on or off the FreeType code which is currently \n// defined out. To pre-render new fonts you need enable the define ( BUILD_FREETYPE ) and \n// uncheck the exclude from build check box in the FreeType2 area of the Renderer project. \n\n\n#include \"tr_local.h\"\n#include \"../qcommon/qcommon.h\"\n\n#ifdef BUILD_FREETYPE\n#include \"../ft2/fterrors.h\"\n#include \"../ft2/ftsystem.h\"\n#include \"../ft2/ftimage.h\"\n#include \"../ft2/freetype.h\"\n#include \"../ft2/ftoutln.h\"\n\n#define _FLOOR(x)  ((x) & -64)\n#define _CEIL(x)   (((x)+63) & -64)\n#define _TRUNC(x)  ((x) >> 6)\n\nFT_Library ftLibrary = NULL;  \n#endif\n\n#define MAX_FONTS 6\nstatic int registeredFontCount = 0;\nstatic fontInfo_t registeredFont[MAX_FONTS];\n\n#ifdef BUILD_FREETYPE\nvoid R_GetGlyphInfo(FT_GlyphSlot glyph, int *left, int *right, int *width, int *top, int *bottom, int *height, int *pitch) {\n\n  *left  = _FLOOR( glyph->metrics.horiBearingX );\n  *right = _CEIL( glyph->metrics.horiBearingX + glyph->metrics.width );\n  *width = _TRUNC(*right - *left);\n    \n  *top    = _CEIL( glyph->metrics.horiBearingY );\n  *bottom = _FLOOR( glyph->metrics.horiBearingY - glyph->metrics.height );\n  *height = _TRUNC( *top - *bottom );\n  *pitch  = ( qtrue ? (*width+3) & -4 : (*width+7) >> 3 );\n}\n\n\nFT_Bitmap *R_RenderGlyph(FT_GlyphSlot glyph, glyphInfo_t* glyphOut) {\n\n  FT_Bitmap  *bit2;\n  int left, right, width, top, bottom, height, pitch, size;\n\n  R_GetGlyphInfo(glyph, &left, &right, &width, &top, &bottom, &height, &pitch);\n\n  if ( glyph->format == ft_glyph_format_outline ) {\n    size   = pitch*height; \n\n    bit2 = Z_Malloc(sizeof(FT_Bitmap));\n\n    bit2->width      = width;\n    bit2->rows       = height;\n    bit2->pitch      = pitch;\n    bit2->pixel_mode = ft_pixel_mode_grays;\n    //bit2->pixel_mode = ft_pixel_mode_mono;\n    bit2->buffer     = Z_Malloc(pitch*height);\n    bit2->num_grays = 256;\n\n    Com_Memset( bit2->buffer, 0, size );\n\n    FT_Outline_Translate( &glyph->outline, -left, -bottom );\n\n    FT_Outline_Get_Bitmap( ftLibrary, &glyph->outline, bit2 );\n\n    glyphOut->height = height;\n    glyphOut->pitch = pitch;\n    glyphOut->top = (glyph->metrics.horiBearingY >> 6) + 1;\n    glyphOut->bottom = bottom;\n    \n    return bit2;\n  }\n  else {\n    ri.Printf(PRINT_ALL, \"Non-outline fonts are not supported\\n\");\n  }\n  return NULL;\n}\n\nvoid WriteTGA (char *filename, byte *data, int width, int height) {\n\tbyte\t*buffer;\n\tint\t\ti, c;\n\n\tbuffer = Z_Malloc(width*height*4 + 18);\n\tCom_Memset (buffer, 0, 18);\n\tbuffer[2] = 2;\t\t// uncompressed type\n\tbuffer[12] = width&255;\n\tbuffer[13] = width>>8;\n\tbuffer[14] = height&255;\n\tbuffer[15] = height>>8;\n\tbuffer[16] = 32;\t// pixel size\n\n\t// swap rgb to bgr\n\tc = 18 + width * height * 4;\n\tfor (i=18 ; i<c ; i+=4)\n\t{\n\t\tbuffer[i] = data[i-18+2];\t\t// blue\n\t\tbuffer[i+1] = data[i-18+1];\t\t// green\n\t\tbuffer[i+2] = data[i-18+0];\t\t// red\n\t\tbuffer[i+3] = data[i-18+3];\t\t// alpha\n\t}\n\n\tri.FS_WriteFile(filename, buffer, c);\n\n\t//f = fopen (filename, \"wb\");\n\t//fwrite (buffer, 1, c, f);\n\t//fclose (f);\n\n\tZ_Free (buffer);\n}\n\nstatic glyphInfo_t *RE_ConstructGlyphInfo(unsigned char *imageOut, int *xOut, int *yOut, int *maxHeight, FT_Face face, const unsigned char c, qboolean calcHeight) {\n  int i;\n  static glyphInfo_t glyph;\n  unsigned char *src, *dst;\n  float scaled_width, scaled_height;\n  FT_Bitmap *bitmap = NULL;\n\n  Com_Memset(&glyph, 0, sizeof(glyphInfo_t));\n  // make sure everything is here\n  if (face != NULL) {\n    FT_Load_Glyph(face, FT_Get_Char_Index( face, c), FT_LOAD_DEFAULT );\n    bitmap = R_RenderGlyph(face->glyph, &glyph);\n    if (bitmap) {\n      glyph.xSkip = (face->glyph->metrics.horiAdvance >> 6) + 1;\n    } else {\n      return &glyph;\n    }\n\n    if (glyph.height > *maxHeight) {\n      *maxHeight = glyph.height;\n    }\n\n    if (calcHeight) {\n      Z_Free(bitmap->buffer);\n      Z_Free(bitmap);\n      return &glyph;\n    }\n\n/*\n    // need to convert to power of 2 sizes so we do not get \n    // any scaling from the gl upload\n  \tfor (scaled_width = 1 ; scaled_width < glyph.pitch ; scaled_width<<=1)\n\t  \t;\n  \tfor (scaled_height = 1 ; scaled_height < glyph.height ; scaled_height<<=1)\n\t  \t;\n*/\n\n    scaled_width = glyph.pitch;\n    scaled_height = glyph.height;\n\n    // we need to make sure we fit\n    if (*xOut + scaled_width + 1 >= 255) {\n      if (*yOut + *maxHeight + 1 >= 255) {\n        *yOut = -1;\n        *xOut = -1;\n        Z_Free(bitmap->buffer);\n        Z_Free(bitmap);\n        return &glyph;\n      } else {\n        *xOut = 0;\n        *yOut += *maxHeight + 1;\n      }\n    } else if (*yOut + *maxHeight + 1 >= 255) {\n      *yOut = -1;\n      *xOut = -1;\n      Z_Free(bitmap->buffer);\n      Z_Free(bitmap);\n      return &glyph;\n    }\n\n\n    src = bitmap->buffer;\n    dst = imageOut + (*yOut * 256) + *xOut;\n\n\t\tif (bitmap->pixel_mode == ft_pixel_mode_mono) {\n\t\t\tfor (i = 0; i < glyph.height; i++) {\n\t\t\t\tint j;\n\t\t\t\tunsigned char *_src = src;\n\t\t\t\tunsigned char *_dst = dst;\n\t\t\t\tunsigned char mask = 0x80;\n\t\t\t\tunsigned char val = *_src;\n\t\t\t\tfor (j = 0; j < glyph.pitch; j++) {\n\t\t\t\t\tif (mask == 0x80) {\n\t\t\t\t\t\tval = *_src++;\n\t\t\t\t\t}\n\t\t\t\t\tif (val & mask) {\n\t\t\t\t\t\t*_dst = 0xff;\n\t\t\t\t\t}\n\t\t\t\t\tmask >>= 1;\n        \n\t\t\t\t\tif ( mask == 0 ) {\n\t\t\t\t\t\tmask = 0x80;\n\t\t\t\t\t}\n\t\t\t\t\t_dst++;\n\t\t\t\t}\n\n\t\t\t\tsrc += glyph.pitch;\n\t\t\t\tdst += 256;\n\n\t\t\t}\n\t\t} else {\n\t    for (i = 0; i < glyph.height; i++) {\n\t\t    Com_Memcpy(dst, src, glyph.pitch);\n\t\t\t  src += glyph.pitch;\n\t\t\t\tdst += 256;\n\t    }\n\t\t}\n\n    // we now have an 8 bit per pixel grey scale bitmap \n    // that is width wide and pf->ftSize->metrics.y_ppem tall\n\n    glyph.imageHeight = scaled_height;\n    glyph.imageWidth = scaled_width;\n    glyph.s = (float)*xOut / 256;\n    glyph.t = (float)*yOut / 256;\n    glyph.s2 = glyph.s + (float)scaled_width / 256;\n    glyph.t2 = glyph.t + (float)scaled_height / 256;\n\n    *xOut += scaled_width + 1;\n  }\n\n  Z_Free(bitmap->buffer);\n  Z_Free(bitmap);\n\n  return &glyph;\n}\n#endif\n\nstatic int fdOffset;\nstatic byte\t*fdFile;\n\nint readInt() {\n\tint i = fdFile[fdOffset]+(fdFile[fdOffset+1]<<8)+(fdFile[fdOffset+2]<<16)+(fdFile[fdOffset+3]<<24);\n\tfdOffset += 4;\n\treturn i;\n}\n\ntypedef union {\n\tbyte\tfred[4];\n\tfloat\tffred;\n} poor;\n\nfloat readFloat() {\n\tpoor\tme;\n#if idppc\n\tme.fred[0] = fdFile[fdOffset+3];\n\tme.fred[1] = fdFile[fdOffset+2];\n\tme.fred[2] = fdFile[fdOffset+1];\n\tme.fred[3] = fdFile[fdOffset+0];\n#else\n\tme.fred[0] = fdFile[fdOffset+0];\n\tme.fred[1] = fdFile[fdOffset+1];\n\tme.fred[2] = fdFile[fdOffset+2];\n\tme.fred[3] = fdFile[fdOffset+3];\n#endif\n\tfdOffset += 4;\n\treturn me.ffred;\n}\n\nvoid RE_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font) {\n#ifdef BUILD_FREETYPE\n  FT_Face face;\n  int j, k, xOut, yOut, lastStart, imageNumber;\n  int scaledSize, newSize, maxHeight, left, satLevels;\n  unsigned char *out, *imageBuff;\n  glyphInfo_t *glyph;\n  image_t *image;\n  qhandle_t h;\n\tfloat max;\n#endif\n  void *faceData;\n\tint i, len;\n  char name[1024];\n\tfloat dpi = 72;\t\t\t\t\t\t\t\t\t\t\t//\n\tfloat glyphScale =  72.0f / dpi; \t\t// change the scale to be relative to 1 based on 72 dpi ( so dpi of 144 means a scale of .5 )\n\n\tif (pointSize <= 0) {\n\t\tpointSize = 12;\n\t}\n\t// we also need to adjust the scale based on point size relative to 48 points as the ui scaling is based on a 48 point font\n\tglyphScale *= 48.0f / pointSize;\n\n\t// make sure the render thread is stopped\n\tR_SyncRenderThread();\n\n  if (registeredFontCount >= MAX_FONTS) {\n    ri.Printf(PRINT_ALL, \"RE_RegisterFont: Too many fonts registered already.\\n\");\n    return;\n  }\n\n\tCom_sprintf(name, sizeof(name), \"fonts/fontImage_%i.dat\",pointSize);\n\tfor (i = 0; i < registeredFontCount; i++) {\n\t\tif (Q_stricmp(name, registeredFont[i].name) == 0) {\n\t\t\tCom_Memcpy(font, &registeredFont[i], sizeof(fontInfo_t));\n\t\t\treturn;\n\t\t}\n\t}\n\n\tlen = ri.FS_ReadFile(name, NULL);\n\tif (len == sizeof(fontInfo_t)) {\n\t\tri.FS_ReadFile(name, &faceData);\n\t\tfdOffset = 0;\n\t\tfdFile = (byte*) faceData;\n\t\tfor(i=0; i<GLYPHS_PER_FONT; i++) {\n\t\t\tfont->glyphs[i].height\t\t= readInt();\n\t\t\tfont->glyphs[i].top\t\t\t= readInt();\n\t\t\tfont->glyphs[i].bottom\t\t= readInt();\n\t\t\tfont->glyphs[i].pitch\t\t= readInt();\n\t\t\tfont->glyphs[i].xSkip\t\t= readInt();\n\t\t\tfont->glyphs[i].imageWidth\t= readInt();\n\t\t\tfont->glyphs[i].imageHeight = readInt();\n\t\t\tfont->glyphs[i].s\t\t\t= readFloat();\n\t\t\tfont->glyphs[i].t\t\t\t= readFloat();\n\t\t\tfont->glyphs[i].s2\t\t\t= readFloat();\n\t\t\tfont->glyphs[i].t2\t\t\t= readFloat();\n\t\t\tfont->glyphs[i].glyph\t\t= readInt();\n\t\t\tCom_Memcpy(font->glyphs[i].shaderName, &fdFile[fdOffset], 32);\n\t\t\tfdOffset += 32;\n\t\t}\n\t\tfont->glyphScale = readFloat();\n\t\tCom_Memcpy(font->name, &fdFile[fdOffset], MAX_QPATH);\n\n//\t\tCom_Memcpy(font, faceData, sizeof(fontInfo_t));\n\t\tQ_strncpyz(font->name, name, sizeof(font->name));\n\t\tfor (i = GLYPH_START; i < GLYPH_END; i++) {\n\t\t\tfont->glyphs[i].glyph = RE_RegisterShaderNoMip(font->glyphs[i].shaderName);\n\t\t}\n\t  Com_Memcpy(&registeredFont[registeredFontCount++], font, sizeof(fontInfo_t));\n\t\treturn;\n\t}\n\n#ifndef BUILD_FREETYPE\n    ri.Printf(PRINT_ALL, \"RE_RegisterFont: FreeType code not available\\n\");\n#else\n  if (ftLibrary == NULL) {\n    ri.Printf(PRINT_ALL, \"RE_RegisterFont: FreeType not initialized.\\n\");\n    return;\n  }\n\n  len = ri.FS_ReadFile(fontName, &faceData);\n  if (len <= 0) {\n    ri.Printf(PRINT_ALL, \"RE_RegisterFont: Unable to read font file\\n\");\n    return;\n  }\n\n  // allocate on the stack first in case we fail\n  if (FT_New_Memory_Face( ftLibrary, faceData, len, 0, &face )) {\n    ri.Printf(PRINT_ALL, \"RE_RegisterFont: FreeType2, unable to allocate new face.\\n\");\n    return;\n  }\n\n\n  if (FT_Set_Char_Size( face, pointSize << 6, pointSize << 6, dpi, dpi)) {\n    ri.Printf(PRINT_ALL, \"RE_RegisterFont: FreeType2, Unable to set face char size.\\n\");\n    return;\n  }\n\n  //*font = &registeredFonts[registeredFontCount++];\n\n  // make a 256x256 image buffer, once it is full, register it, clean it and keep going \n  // until all glyphs are rendered\n\n  out = Z_Malloc(1024*1024);\n  if (out == NULL) {\n    ri.Printf(PRINT_ALL, \"RE_RegisterFont: Z_Malloc failure during output image creation.\\n\");\n    return;\n  }\n  Com_Memset(out, 0, 1024*1024);\n\n  maxHeight = 0;\n\n  for (i = GLYPH_START; i < GLYPH_END; i++) {\n    glyph = RE_ConstructGlyphInfo(out, &xOut, &yOut, &maxHeight, face, (unsigned char)i, qtrue);\n  }\n\n  xOut = 0;\n  yOut = 0;\n  i = GLYPH_START;\n  lastStart = i;\n  imageNumber = 0;\n\n  while ( i <= GLYPH_END ) {\n\n    glyph = RE_ConstructGlyphInfo(out, &xOut, &yOut, &maxHeight, face, (unsigned char)i, qfalse);\n\n    if (xOut == -1 || yOut == -1 || i == GLYPH_END)  {\n      // ran out of room\n      // we need to create an image from the bitmap, set all the handles in the glyphs to this point\n      // \n\n      scaledSize = 256*256;\n      newSize = scaledSize * 4;\n      imageBuff = Z_Malloc(newSize);\n      left = 0;\n      max = 0;\n      satLevels = 255;\n      for ( k = 0; k < (scaledSize) ; k++ ) {\n        if (max < out[k]) {\n          max = out[k];\n        }\n      }\n\n\t\t\tif (max > 0) {\n\t\t\t\tmax = 255/max;\n\t\t\t}\n\n      for ( k = 0; k < (scaledSize) ; k++ ) {\n        imageBuff[left++] = 255;\n        imageBuff[left++] = 255;\n        imageBuff[left++] = 255;\n\n        imageBuff[left++] = ((float)out[k] * max);\n      }\n\n\t\t\tCom_sprintf (name, sizeof(name), \"fonts/fontImage_%i_%i.tga\", imageNumber++, pointSize);\n\t\t\tif (r_saveFontData->integer) { \n\t\t\t  WriteTGA(name, imageBuff, 256, 256);\n\t\t\t}\n\n    \t//Com_sprintf (name, sizeof(name), \"fonts/fontImage_%i_%i\", imageNumber++, pointSize);\n      image = R_CreateImage(name, imageBuff, 256, 256, qfalse, qfalse, GL_CLAMP);\n      h = RE_RegisterShaderFromImage(name, LIGHTMAP_2D, image, qfalse);\n      for (j = lastStart; j < i; j++) {\n        font->glyphs[j].glyph = h;\n\t\t\t\tQ_strncpyz(font->glyphs[j].shaderName, name, sizeof(font->glyphs[j].shaderName));\n      }\n      lastStart = i;\n\t\t  Com_Memset(out, 0, 1024*1024);\n      xOut = 0;\n      yOut = 0;\n      Z_Free(imageBuff);\n\t\t\ti++;\n    } else {\n      Com_Memcpy(&font->glyphs[i], glyph, sizeof(glyphInfo_t));\n      i++;\n    }\n  }\n\n\tregisteredFont[registeredFontCount].glyphScale = glyphScale;\n\tfont->glyphScale = glyphScale;\n  Com_Memcpy(&registeredFont[registeredFontCount++], font, sizeof(fontInfo_t));\n\n\tif (r_saveFontData->integer) { \n\t\tri.FS_WriteFile(va(\"fonts/fontImage_%i.dat\", pointSize), font, sizeof(fontInfo_t));\n\t}\n\n  Z_Free(out);\n  \n  ri.FS_FreeFile(faceData);\n#endif\n}\n\n\n\nvoid R_InitFreeType() {\n#ifdef BUILD_FREETYPE\n  if (FT_Init_FreeType( &ftLibrary )) {\n    ri.Printf(PRINT_ALL, \"R_InitFreeType: Unable to initialize FreeType.\\n\");\n  }\n#endif\n  registeredFontCount = 0;\n}\n\n\nvoid R_DoneFreeType() {\n#ifdef BUILD_FREETYPE\n  if (ftLibrary) {\n    FT_Done_FreeType( ftLibrary );\n    ftLibrary = NULL;\n  }\n#endif\n\tregisteredFontCount = 0;\n}\n\n"
  },
  {
    "path": "src/engine/renderer/tr_image.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n// tr_image.c\n#include \"tr_local.h\"\n\nstatic void* q3_stbi_malloc(size_t size) {\n    return ri.Malloc((int)size);\n}\nstatic void q3_stbi_free(void* p) {\n    ri.Free(p);\n}\nstatic void* q3_stbi_realloc(void* p, size_t old_size, size_t new_size) {\n    if (p == nullptr)\n        return q3_stbi_malloc(new_size);\n\n    void* p_new;\n    if (old_size < new_size) {\n        p_new = q3_stbi_malloc(new_size);\n        memcpy(p_new, p, old_size);\n        q3_stbi_free(p);\n    } else {\n        p_new = p;\n    }\n    return p_new;\n}\n#define STBI_MALLOC q3_stbi_malloc\n#define STBI_FREE q3_stbi_free\n#define STBI_REALLOC_SIZED q3_stbi_realloc\n#define STB_IMAGE_IMPLEMENTATION\n#include \"jpeg/stb_image.h\"\n\n#define TJE_IMPLEMENTATION\n#include \"jpeg/tiny_jpeg.h\"\n\nstatic void LoadBMP( const char *name, byte **pic, int *width, int *height );\nstatic void LoadTGA( const char *name, byte **pic, int *width, int *height );\nstatic void LoadJPG( const char *name, byte **pic, int *width, int *height );\n\nstatic byte\t\t\t s_intensitytable[256];\nstatic unsigned char s_gammatable[256];\n\nint\t\tgl_filter_min = GL_LINEAR_MIPMAP_NEAREST;\nint\t\tgl_filter_max = GL_LINEAR;\n\n#define FILE_HASH_SIZE\t\t1024\nstatic\timage_t*\t\thashTable[FILE_HASH_SIZE];\n\n/*\n** R_GammaCorrect\n*/\nvoid R_GammaCorrect( byte *buffer, int bufSize ) {\n\tint i;\n\n\tfor ( i = 0; i < bufSize; i++ ) {\n\t\tbuffer[i] = s_gammatable[buffer[i]];\n\t}\n}\n\ntypedef struct {\n\tchar *name;\n\tint\tminimize, maximize;\n} textureMode_t;\n\ntextureMode_t modes[] = {\n\t{\"GL_NEAREST\", GL_NEAREST, GL_NEAREST},\n\t{\"GL_LINEAR\", GL_LINEAR, GL_LINEAR},\n\t{\"GL_NEAREST_MIPMAP_NEAREST\", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST},\n\t{\"GL_LINEAR_MIPMAP_NEAREST\", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR},\n\t{\"GL_NEAREST_MIPMAP_LINEAR\", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST},\n\t{\"GL_LINEAR_MIPMAP_LINEAR\", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}\n};\n\n/*\n================\nreturn a hash value for the filename\n================\n*/\nstatic long generateHashValue( const char *fname ) {\n\tint\t\ti;\n\tlong\thash;\n\tchar\tletter;\n\n\thash = 0;\n\ti = 0;\n\twhile (fname[i] != '\\0') {\n\t\tletter = tolower(fname[i]);\n\t\tif (letter =='.') break;\t\t\t\t// don't include extension\n\t\tif (letter =='\\\\') letter = '/';\t\t// damn path names\n\t\thash+=(long)(letter)*(i+119);\n\t\ti++;\n\t}\n\thash &= (FILE_HASH_SIZE-1);\n\treturn hash;\n}\n\n/*\n===============\nGL_TextureMode\n===============\n*/\nvoid GL_TextureMode( const char *string ) {\n\tint i;\n\n\tfor ( i=0 ; i< 6 ; i++ ) {\n\t\tif ( !Q_stricmp( modes[i].name, string ) ) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif ( i == 6 ) {\n\t\tri.Printf (PRINT_ALL, \"bad filter name\\n\");\n\t\treturn;\n\t}\n\n\tgl_filter_min = modes[i].minimize;\n\tgl_filter_max = modes[i].maximize;\n\n\t// change all the existing mipmap texture objects\n\tfor ( i = 0 ; i < tr.numImages ; i++ ) {\n        image_t* glt = tr.images[ i ];\n\t\tif ( glt->mipmap ) {\n\t\t\tGL_Bind (glt);\n\t\t\tqglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);\n\t\t\tqglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);\n\t\t}\n\t}\n\n\t// VULKAN\n\tif (vk.active) {\n\t\tVK_CHECK(vkDeviceWaitIdle(vk.device));\n\t\tfor ( i = 0 ; i < tr.numImages ; i++ ) {\n\t\t\timage_t* glt = tr.images[i];\n\t\t\tif (glt->mipmap) {\n\t\t\t\tVk_Image& image = vk_world.images[i];\n\t\t\t\tvk_update_descriptor_set(image.descriptor_set, image.view, true, glt->wrapClampMode == GL_REPEAT);\n\t\t\t}\n\t\t}\n\t}\n\n\t// DX12\n\tif (dx.active) {\n\t\tdx_wait_device_idle();\n\n\t\tVk_Sampler_Def def;\n\t\tdef.gl_mag_filter = gl_filter_max;\n\t\tdef.gl_min_filter = gl_filter_min;\n\n\t\tdef.repeat_texture = true;\n\t\tdx_create_sampler_descriptor(def, SAMPLER_MIP_REPEAT);\n\n\t\tdef.repeat_texture = false;\n\t\tdx_create_sampler_descriptor(def, SAMPLER_MIP_CLAMP);\n\t}\n}\n\n/*\n===============\nR_SumOfUsedImages\n===============\n*/\nint R_SumOfUsedImages( void ) {\n\tint\ttotal;\n\tint i;\n\n\ttotal = 0;\n\tfor ( i = 0; i < tr.numImages; i++ ) {\n\t\tif ( tr.images[i]->frameUsed == tr.frameCount ) {\n\t\t\ttotal += tr.images[i]->uploadWidth * tr.images[i]->uploadHeight;\n\t\t}\n\t}\n\n\treturn total;\n}\n\n/*\n===============\nR_ImageList_f\n===============\n*/\nvoid R_ImageList_f( void ) {\n\tint\t\ti;\n\timage_t\t*image;\n\tint\t\ttexels;\n\tconst char *yesno[] = {\n\t\t\"no \", \"yes\"\n\t};\n\n\tri.Printf (PRINT_ALL, \"\\n      -w-- -h-- -mm- -if-- wrap --name-------\\n\");\n\ttexels = 0;\n\n\tfor ( i = 0 ; i < tr.numImages ; i++ ) {\n\t\timage = tr.images[ i ];\n\n\t\ttexels += image->uploadWidth*image->uploadHeight;\n\t\tri.Printf (PRINT_ALL,  \"%4i: %4i %4i  %s  \",\n\t\t\ti, image->uploadWidth, image->uploadHeight, yesno[image->mipmap] );\n\t\tswitch ( image->internalFormat ) {\n\t\tcase 1:\n\t\t\tri.Printf( PRINT_ALL, \"I    \" );\n\t\t\tbreak;\n\t\tcase 2:\n\t\t\tri.Printf( PRINT_ALL, \"IA   \" );\n\t\t\tbreak;\n\t\tcase 3:\n\t\t\tri.Printf( PRINT_ALL, \"RGB  \" );\n\t\t\tbreak;\n\t\tcase 4:\n\t\t\tri.Printf( PRINT_ALL, \"RGBA \" );\n\t\t\tbreak;\n\t\tcase GL_RGBA8:\n\t\t\tri.Printf( PRINT_ALL, \"RGBA8\" );\n\t\t\tbreak;\n\t\tcase GL_RGB8:\n\t\t\tri.Printf( PRINT_ALL, \"RGB8\" );\n\t\t\tbreak;\n\t\tcase GL_RGB4_S3TC:\n\t\t\tri.Printf( PRINT_ALL, \"S3TC \" );\n\t\t\tbreak;\n\t\tcase GL_RGBA4:\n\t\t\tri.Printf( PRINT_ALL, \"RGBA4\" );\n\t\t\tbreak;\n\t\tcase GL_RGB5:\n\t\t\tri.Printf( PRINT_ALL, \"RGB5 \" );\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tri.Printf( PRINT_ALL, \"???? \" );\n\t\t}\n\n\t\tswitch ( image->wrapClampMode ) {\n\t\tcase GL_REPEAT:\n\t\t\tri.Printf( PRINT_ALL, \"rept \" );\n\t\t\tbreak;\n\t\tcase GL_CLAMP:\n\t\t\tri.Printf( PRINT_ALL, \"clmp \" );\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tri.Printf( PRINT_ALL, \"%4i \", image->wrapClampMode );\n\t\t\tbreak;\n\t\t}\n\t\t\n\t\tri.Printf( PRINT_ALL, \" %s\\n\", image->imgName );\n\t}\n\tri.Printf (PRINT_ALL, \" ---------\\n\");\n\tri.Printf (PRINT_ALL, \" %i total texels (not including mipmaps)\\n\", texels);\n\tri.Printf (PRINT_ALL, \" %i total images\\n\\n\", tr.numImages );\n}\n\n//=======================================================================\n\n/*\n================\nResampleTexture\n\nUsed to resample images in a more general than quartering fashion.\n\nThis will only be filtered properly if the resampled size\nis greater than half the original size.\n\nIf a larger shrinking is needed, use the mipmap function \nbefore or after.\n================\n*/\nstatic void ResampleTexture( unsigned *in, int inwidth, int inheight, unsigned *out,  \n\t\t\t\t\t\t\tint outwidth, int outheight ) {\n\tint\t\ti, j;\n\tunsigned\t*inrow, *inrow2;\n\tunsigned\tfrac, fracstep;\n\tunsigned\tp1[2048], p2[2048];\n\tbyte\t\t*pix1, *pix2, *pix3, *pix4;\n\n\tif (outwidth>2048)\n\t\tri.Error(ERR_DROP, \"ResampleTexture: max width\");\n\t\t\t\t\t\t\t\t\n\tfracstep = inwidth*0x10000/outwidth;\n\n\tfrac = fracstep>>2;\n\tfor ( i=0 ; i<outwidth ; i++ ) {\n\t\tp1[i] = 4*(frac>>16);\n\t\tfrac += fracstep;\n\t}\n\tfrac = 3*(fracstep>>2);\n\tfor ( i=0 ; i<outwidth ; i++ ) {\n\t\tp2[i] = 4*(frac>>16);\n\t\tfrac += fracstep;\n\t}\n\n\tfor (i=0 ; i<outheight ; i++, out += outwidth) {\n\t\tinrow = in + inwidth*(int)((i+0.25)*inheight/outheight);\n\t\tinrow2 = in + inwidth*(int)((i+0.75)*inheight/outheight);\n\t\tfrac = fracstep >> 1;\n\t\tfor (j=0 ; j<outwidth ; j++) {\n\t\t\tpix1 = (byte *)inrow + p1[j];\n\t\t\tpix2 = (byte *)inrow + p2[j];\n\t\t\tpix3 = (byte *)inrow2 + p1[j];\n\t\t\tpix4 = (byte *)inrow2 + p2[j];\n\t\t\t((byte *)(out+j))[0] = (pix1[0] + pix2[0] + pix3[0] + pix4[0])>>2;\n\t\t\t((byte *)(out+j))[1] = (pix1[1] + pix2[1] + pix3[1] + pix4[1])>>2;\n\t\t\t((byte *)(out+j))[2] = (pix1[2] + pix2[2] + pix3[2] + pix4[2])>>2;\n\t\t\t((byte *)(out+j))[3] = (pix1[3] + pix2[3] + pix3[3] + pix4[3])>>2;\n\t\t}\n\t}\n}\n\n/*\n================\nR_LightScaleTexture\n\nScale up the pixel values in a texture to increase the\nlighting range\n================\n*/\nvoid R_LightScaleTexture (unsigned *in, int inwidth, int inheight, qboolean only_gamma )\n{\n\tif ( only_gamma )\n\t{\n\t\tif ( !glConfig.deviceSupportsGamma )\n\t\t{\n\t\t\tint\t\ti, c;\n\t\t\tbyte\t*p;\n\n\t\t\tp = (byte *)in;\n\n\t\t\tc = inwidth*inheight;\n\t\t\tfor (i=0 ; i<c ; i++, p+=4)\n\t\t\t{\n\t\t\t\tp[0] = s_gammatable[p[0]];\n\t\t\t\tp[1] = s_gammatable[p[1]];\n\t\t\t\tp[2] = s_gammatable[p[2]];\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\tint\t\ti, c;\n\t\tbyte\t*p;\n\n\t\tp = (byte *)in;\n\n\t\tc = inwidth*inheight;\n\n\t\tif ( glConfig.deviceSupportsGamma )\n\t\t{\n\t\t\tfor (i=0 ; i<c ; i++, p+=4)\n\t\t\t{\n\t\t\t\tp[0] = s_intensitytable[p[0]];\n\t\t\t\tp[1] = s_intensitytable[p[1]];\n\t\t\t\tp[2] = s_intensitytable[p[2]];\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfor (i=0 ; i<c ; i++, p+=4)\n\t\t\t{\n\t\t\t\tp[0] = s_gammatable[s_intensitytable[p[0]]];\n\t\t\t\tp[1] = s_gammatable[s_intensitytable[p[1]]];\n\t\t\t\tp[2] = s_gammatable[s_intensitytable[p[2]]];\n\t\t\t}\n\t\t}\n\t}\n}\n\n\n/*\n================\nR_MipMap2\n\nOperates in place, quartering the size of the texture\nProper linear filter\n================\n*/\nstatic void R_MipMap2( unsigned *in, int inWidth, int inHeight ) {\n\tint\t\t\ti, j, k;\n\tbyte\t\t*outpix;\n\tint\t\t\tinWidthMask, inHeightMask;\n\tint\t\t\ttotal;\n\tint\t\t\toutWidth, outHeight;\n\tunsigned\t*temp;\n\n\toutWidth = inWidth >> 1;\n\toutHeight = inHeight >> 1;\n\ttemp = (unsigned*) ri.Hunk_AllocateTempMemory( outWidth * outHeight * 4 );\n\n\tinWidthMask = inWidth - 1;\n\tinHeightMask = inHeight - 1;\n\n\tfor ( i = 0 ; i < outHeight ; i++ ) {\n\t\tfor ( j = 0 ; j < outWidth ; j++ ) {\n\t\t\toutpix = (byte *) ( temp + i * outWidth + j );\n\t\t\tfor ( k = 0 ; k < 4 ; k++ ) {\n\t\t\t\ttotal = \n\t\t\t\t\t1 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] +\n\t\t\t\t\t2 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] +\n\t\t\t\t\t2 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] +\n\t\t\t\t\t1 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k] +\n\n\t\t\t\t\t2 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] +\n\t\t\t\t\t4 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] +\n\t\t\t\t\t4 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] +\n\t\t\t\t\t2 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k] +\n\n\t\t\t\t\t2 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] +\n\t\t\t\t\t4 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] +\n\t\t\t\t\t4 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] +\n\t\t\t\t\t2 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k] +\n\n\t\t\t\t\t1 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] +\n\t\t\t\t\t2 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] +\n\t\t\t\t\t2 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] +\n\t\t\t\t\t1 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k];\n\t\t\t\toutpix[k] = total / 36;\n\t\t\t}\n\t\t}\n\t}\n\n\tCom_Memcpy( in, temp, outWidth * outHeight * 4 );\n\tri.Hunk_FreeTempMemory( temp );\n}\n\n/*\n================\nR_MipMap\n\nOperates in place, quartering the size of the texture\n================\n*/\nstatic void R_MipMap (byte *in, int width, int height) {\n\tint\t\ti, j;\n\tbyte\t*out;\n\tint\t\trow;\n\n\tif ( !r_simpleMipMaps->integer ) {\n\t\tR_MipMap2( (unsigned *)in, width, height );\n\t\treturn;\n\t}\n\n\tif ( width == 1 && height == 1 ) {\n\t\treturn;\n\t}\n\n\trow = width * 4;\n\tout = in;\n\twidth >>= 1;\n\theight >>= 1;\n\n\tif ( width == 0 || height == 0 ) {\n\t\twidth += height;\t// get largest\n\t\tfor (i=0 ; i<width ; i++, out+=4, in+=8 ) {\n\t\t\tout[0] = ( in[0] + in[4] )>>1;\n\t\t\tout[1] = ( in[1] + in[5] )>>1;\n\t\t\tout[2] = ( in[2] + in[6] )>>1;\n\t\t\tout[3] = ( in[3] + in[7] )>>1;\n\t\t}\n\t\treturn;\n\t}\n\n\tfor (i=0 ; i<height ; i++, in+=row) {\n\t\tfor (j=0 ; j<width ; j++, out+=4, in+=8) {\n\t\t\tout[0] = (in[0] + in[4] + in[row+0] + in[row+4])>>2;\n\t\t\tout[1] = (in[1] + in[5] + in[row+1] + in[row+5])>>2;\n\t\t\tout[2] = (in[2] + in[6] + in[row+2] + in[row+6])>>2;\n\t\t\tout[3] = (in[3] + in[7] + in[row+3] + in[row+7])>>2;\n\t\t}\n\t}\n}\n\n\n/*\n==================\nR_BlendOverTexture\n\nApply a color blend over a set of pixels\n==================\n*/\nstatic void R_BlendOverTexture( byte *data, int pixelCount, byte blend[4] ) {\n\tint\t\ti;\n\tint\t\tinverseAlpha;\n\tint\t\tpremult[3];\n\n\tinverseAlpha = 255 - blend[3];\n\tpremult[0] = blend[0] * blend[3];\n\tpremult[1] = blend[1] * blend[3];\n\tpremult[2] = blend[2] * blend[3];\n\n\tfor ( i = 0 ; i < pixelCount ; i++, data+=4 ) {\n\t\tdata[0] = ( data[0] * inverseAlpha + premult[0] ) >> 9;\n\t\tdata[1] = ( data[1] * inverseAlpha + premult[1] ) >> 9;\n\t\tdata[2] = ( data[2] * inverseAlpha + premult[2] ) >> 9;\n\t}\n}\n\nbyte\tmipBlendColors[16][4] = {\n\t{0,0,0,0},\n\t{255,0,0,128},\n\t{0,255,0,128},\n\t{0,0,255,128},\n\t{255,0,0,128},\n\t{0,255,0,128},\n\t{0,0,255,128},\n\t{255,0,0,128},\n\t{0,255,0,128},\n\t{0,0,255,128},\n\t{255,0,0,128},\n\t{0,255,0,128},\n\t{0,0,255,128},\n\t{255,0,0,128},\n\t{0,255,0,128},\n\t{0,0,255,128},\n};\n\nstruct Image_Upload_Data {\n\tbyte* buffer;\n\tint buffer_size;\n\tint mip_levels;\n\tint base_level_width;\n\tint base_level_height;\n};\n\nstatic Image_Upload_Data generate_image_upload_data(const byte* data, int width, int height, qboolean mipmap, qboolean picmip) {\n\t//\n\t// convert to exact power of 2 sizes\n\t//\n\tint scaled_width, scaled_height;\n\n\tfor (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1)\n\t\t;\n\tfor (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1)\n\t\t;\n\tif ( r_roundImagesDown->integer && scaled_width > width )\n\t\tscaled_width >>= 1;\n\tif ( r_roundImagesDown->integer && scaled_height > height )\n\t\tscaled_height >>= 1;\n\n\tImage_Upload_Data upload_data;\n\tupload_data.buffer = (byte*) ri.Hunk_AllocateTempMemory(2 * 4 * scaled_width * scaled_height);\n\n\tbyte* resampled_buffer = nullptr;\n\tif ( scaled_width != width || scaled_height != height ) {\n\t\tresampled_buffer = (byte*) ri.Hunk_AllocateTempMemory( scaled_width * scaled_height * 4 );\n\t\tResampleTexture ((unsigned*)data, width, height, (unsigned*)resampled_buffer, scaled_width, scaled_height);\n\t\tdata = resampled_buffer;\n\t\twidth = scaled_width;\n\t\theight = scaled_height;\n\t}\n\n\t//\n\t// perform optional picmip operation\n\t//\n\tif ( picmip ) {\n\t\tscaled_width >>= r_picmip->integer;\n\t\tscaled_height >>= r_picmip->integer;\n\t}\n\n\t//\n\t// clamp to minimum size\n\t//\n\tif (scaled_width < 1) {\n\t\tscaled_width = 1;\n\t}\n\tif (scaled_height < 1) {\n\t\tscaled_height = 1;\n\t}\n\n\t//\n\t// clamp to the current upper OpenGL limit\n\t// scale both axis down equally so we don't have to\n\t// deal with a half mip resampling\n\t//\n\tint max_texture_size = gl_active ? glConfig.maxTextureSize : 2048;\n\twhile ( scaled_width > max_texture_size\n\t\t|| scaled_height > max_texture_size ) {\n\t\tscaled_width >>= 1;\n\t\tscaled_height >>= 1;\n\t}\n\n\tupload_data.base_level_width = scaled_width;\n\tupload_data.base_level_height = scaled_height;\n\n\tif (scaled_width == width && scaled_height == height && !mipmap) {\n\t\tupload_data.mip_levels = 1;\n\t\tupload_data.buffer_size = scaled_width * scaled_height * 4;\n\t\tCom_Memcpy(upload_data.buffer, data, upload_data.buffer_size);\n\t\tif (resampled_buffer != nullptr)\n\t\t\tri.Hunk_FreeTempMemory(resampled_buffer);\n\t\treturn upload_data;\n\t}\n\n\t// Use the normal mip-mapping to go down from [width, height] to [scaled_width, scaled_height] dimensions.\n\twhile (width > scaled_width || height > scaled_height) {\n\t\tR_MipMap((byte *)data, width, height);\n\n\t\twidth >>= 1;\n\t\tif (width < 1) width = 1;\n\n\t\theight >>= 1;\n\t\tif (height < 1) height = 1; \n\t}\n\n\t// At this point width == scaled_width and height == scaled_height.\n\n\tunsigned* scaled_buffer = (unsigned int*) ri.Hunk_AllocateTempMemory( sizeof( unsigned ) * scaled_width * scaled_height );\n\tCom_Memcpy(scaled_buffer, data, scaled_width * scaled_height * 4);\n\tR_LightScaleTexture(scaled_buffer, scaled_width, scaled_height, (qboolean) !mipmap);\n\n\tint miplevel = 0;\n\tint mip_level_size = scaled_width * scaled_height * 4;\n\n\tCom_Memcpy(upload_data.buffer, scaled_buffer, mip_level_size);\n\tupload_data.buffer_size = mip_level_size;\n\t\n\tif (mipmap) {\n\t\twhile (scaled_width > 1 || scaled_height > 1) {\n\t\t\tR_MipMap((byte *)scaled_buffer, scaled_width, scaled_height);\n\n\t\t\tscaled_width >>= 1;\n\t\t\tif (scaled_width < 1) scaled_width = 1;\n\n\t\t\tscaled_height >>= 1;\n\t\t\tif (scaled_height < 1) scaled_height = 1;\n\n\t\t\tmiplevel++;\n\t\t\tmip_level_size = scaled_width * scaled_height * 4;\n\n\t\t\tif ( r_colorMipLevels->integer ) {\n\t\t\t\tR_BlendOverTexture( (byte *)scaled_buffer, scaled_width * scaled_height, mipBlendColors[miplevel] );\n\t\t\t}\n\n\t\t\tCom_Memcpy(&upload_data.buffer[upload_data.buffer_size], scaled_buffer, mip_level_size);\n\t\t\tupload_data.buffer_size += mip_level_size;\n\t\t}\n\t}\n\tupload_data.mip_levels = miplevel + 1;\n\n\tri.Hunk_FreeTempMemory(scaled_buffer);\n\tif (resampled_buffer != nullptr)\n\t\tri.Hunk_FreeTempMemory(resampled_buffer);\n\n\treturn upload_data;\n}\n\nstatic int upload_gl_image(const Image_Upload_Data& upload_data, int texture_address_mode) {\n\tint w = upload_data.base_level_width;\n\tint h = upload_data.base_level_height;\n\n\tbool has_alpha = false;\n\tfor (int i = 0; i < w * h; i++) {\n\t\tif (upload_data.buffer[i*4 + 3] != 255)  {\n\t\t\thas_alpha = true;\n\t\t\tbreak;\n\t\t}\n\t}\n\tint internal_format = GL_RGBA8;\n\tif (glConfig.textureCompression && !has_alpha) {\n\t\tinternal_format = GL_RGB4_S3TC;\n\t} else if (r_texturebits->integer <= 16) {\n\t\tinternal_format = has_alpha ? GL_RGBA4 : GL_RGB5;\n\t}\n\n\tauto buffer = upload_data.buffer;\n\tfor (int i = 0; i < upload_data.mip_levels; i++) {\n\t\tqglTexImage2D(GL_TEXTURE_2D, i, internal_format, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);\n\t\tbuffer += w * h * 4;\n\n\t\tw >>= 1;\n\t\tif (w < 1) w = 1;\n\n\t\th >>= 1;\n\t\tif (h < 1) h = 1;\n\t}\n\n\tif (upload_data.mip_levels > 1) {\n\t\tqglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);\n\t\tqglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);\n\t} else {\n\t\tqglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );\n\t\tqglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );\n\t}\n\n\tqglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, texture_address_mode);\n\tqglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, texture_address_mode);\n\n\tGL_CheckErrors();\n\treturn internal_format;\n}\n\n// VULKAN\nstatic Vk_Image upload_vk_image(const Image_Upload_Data& upload_data, bool repeat_texture) {\n\tint w = upload_data.base_level_width;\n\tint h = upload_data.base_level_height;\n\n\tbool has_alpha = false;\n\tfor (int i = 0; i < w * h; i++) {\n\t\tif (upload_data.buffer[i*4 + 3] != 255)  {\n\t\t\thas_alpha = true;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tbyte* buffer = upload_data.buffer;\n\tVkFormat format = VK_FORMAT_R8G8B8A8_UNORM;\n\tint bytes_per_pixel = 4;\n\n\tif (r_texturebits->integer <= 16) {\n\t\tbuffer = (byte*) ri.Hunk_AllocateTempMemory( upload_data.buffer_size / 2 );\n\t\tformat = has_alpha ? VK_FORMAT_B4G4R4A4_UNORM_PACK16 : VK_FORMAT_A1R5G5B5_UNORM_PACK16;\n\t\tbytes_per_pixel = 2;\n\t}\n\n\tif (format == VK_FORMAT_A1R5G5B5_UNORM_PACK16) {\n\t\tauto p = (uint16_t*)buffer;\n\t\tfor (int i = 0; i < upload_data.buffer_size; i += 4, p++) {\n\t\t\tbyte r = upload_data.buffer[i+0];\n\t\t\tbyte g = upload_data.buffer[i+1];\n\t\t\tbyte b = upload_data.buffer[i+2];\n\n\t\t\t*p = uint32_t((b/255.0) * 31.0 + 0.5) |\n\t\t\t\t(uint32_t((g/255.0) * 31.0 + 0.5) << 5) |\n\t\t\t\t(uint32_t((r/255.0) * 31.0 + 0.5) << 10) |\n\t\t\t\t(1 << 15);\n\t\t}\n\t} else if (format == VK_FORMAT_B4G4R4A4_UNORM_PACK16) {\n\t\tauto p = (uint16_t*)buffer;\n\t\tfor (int i = 0; i < upload_data.buffer_size; i += 4, p++) {\n\t\t\tbyte r = upload_data.buffer[i+0];\n\t\t\tbyte g = upload_data.buffer[i+1];\n\t\t\tbyte b = upload_data.buffer[i+2];\n\t\t\tbyte a = upload_data.buffer[i+3];\n\n\t\t\t*p = uint32_t((a/255.0) * 15.0 + 0.5) |\n\t\t\t\t(uint32_t((r/255.0) * 15.0 + 0.5) << 4) |\n\t\t\t\t(uint32_t((g/255.0) * 15.0 + 0.5) << 8) |\n\t\t\t\t(uint32_t((b/255.0) * 15.0 + 0.5) << 12);\n\t\t}\n\t}\n\n\tVk_Image image = vk_create_image(w, h, format, upload_data.mip_levels, repeat_texture);\n\tvk_upload_image_data(image.handle, w, h, upload_data.mip_levels > 1, buffer, bytes_per_pixel);\n\n\tif (bytes_per_pixel == 2)\n\t\tri.Hunk_FreeTempMemory(buffer);\n\n\treturn image;\n}\n\n// DX12\nstatic Dx_Image upload_dx_image(const Image_Upload_Data& upload_data, bool repeat_texture, int image_index) {\n\tint w = upload_data.base_level_width;\n\tint h = upload_data.base_level_height;\n\n\tbool has_alpha = false;\n\tfor (int i = 0; i < w * h; i++) {\n\t\tif (upload_data.buffer[i*4 + 3] != 255)  {\n\t\t\thas_alpha = true;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tbyte* buffer = upload_data.buffer;\n\tDx_Image_Format format = IMAGE_FORMAT_RGBA8;\n\tint bytes_per_pixel = 4;\n\n\tif (r_texturebits->integer <= 16) {\n\t\tbuffer = (byte*) ri.Hunk_AllocateTempMemory( upload_data.buffer_size / 2 );\n\t\tformat = has_alpha ? IMAGE_FORMAT_BGRA4 : IMAGE_FORMAT_BGR5A1;\n\t\tbytes_per_pixel = 2;\n\t}\n\n\tif (format == IMAGE_FORMAT_BGR5A1) {\n\t\tauto p = (uint16_t*)buffer;\n\t\tfor (int i = 0; i < upload_data.buffer_size; i += 4, p++) {\n\t\t\tbyte r = upload_data.buffer[i+0];\n\t\t\tbyte g = upload_data.buffer[i+1];\n\t\t\tbyte b = upload_data.buffer[i+2];\n\n\t\t\t*p = (uint32_t((b/255.0) * 31.0 + 0.5) << 0)  |\n\t\t\t\t (uint32_t((g/255.0) * 31.0 + 0.5) << 5)  |\n\t\t\t\t (uint32_t((r/255.0) * 31.0 + 0.5) << 10) |\n\t\t\t\t (1 << 15);\n\t\t}\n\t} else if (format == IMAGE_FORMAT_BGRA4) {\n\t\tauto p = (uint16_t*)buffer;\n\t\tfor (int i = 0; i < upload_data.buffer_size; i += 4, p++) {\n\t\t\tbyte r = upload_data.buffer[i+0];\n\t\t\tbyte g = upload_data.buffer[i+1];\n\t\t\tbyte b = upload_data.buffer[i+2];\n\t\t\tbyte a = upload_data.buffer[i+3];\n\n\t\t\t*p =(uint32_t((b/255.0) * 15.0 + 0.5) << 0) |\n\t\t\t\t(uint32_t((g/255.0) * 15.0 + 0.5) << 4) |\n\t\t\t\t(uint32_t((r/255.0) * 15.0 + 0.5) << 8) |\n\t\t\t\t(uint32_t((a/255.0) * 15.0 + 0.5) << 12);\n\t\t}\n\t}\n\n\tDx_Image image = dx_create_image(w, h, format, upload_data.mip_levels, repeat_texture, image_index);\n\tdx_upload_image_data(image.texture, w, h, upload_data.mip_levels, buffer, bytes_per_pixel);\n\n\tif (bytes_per_pixel == 2)\n\t\tri.Hunk_FreeTempMemory(buffer);\n\n\treturn image;\n}\n\n/*\n================\nR_CreateImage\n\nThis is the only way any image_t are created\n================\n*/\nimage_t *R_CreateImage( const char *name, const byte *pic, int width, int height, \n\t\t\t\t\t   qboolean mipmap, qboolean allowPicmip, int glWrapClampMode ) {\n\n\tif (strlen(name) >= MAX_QPATH ) {\n\t\tri.Error (ERR_DROP, \"R_CreateImage: \\\"%s\\\" is too long\\n\", name);\n\t}\n\n\tif ( tr.numImages == MAX_DRAWIMAGES ) {\n\t\tri.Error( ERR_DROP, \"R_CreateImage: MAX_DRAWIMAGES hit\\n\");\n\t}\n\n\t// Create image_t object.\n\tauto image = tr.images[tr.numImages] = (image_t*) ri.Hunk_Alloc( sizeof( image_t ), h_low );\n    image->index = tr.numImages;\n\timage->texnum = 1024 + tr.numImages;\n\timage->mipmap = mipmap;\n\timage->allowPicmip = allowPicmip;\n\tstrcpy (image->imgName, name);\n\timage->width = width;\n\timage->height = height;\n\timage->wrapClampMode = glWrapClampMode;\n\n\tlong hash = generateHashValue(name);\n\timage->next = hashTable[hash];\n\thashTable[hash] = image;\n\n\ttr.numImages++;\n\n\t// Create corresponding GPU resource.\n\tbool isLightmap = (strncmp(name, \"*lightmap\", 9) == 0);\n\tGL_SelectTexture(isLightmap ? 1 : 0);\n\tGL_Bind(image);\n\t\n\tImage_Upload_Data upload_data = generate_image_upload_data(pic, width, height, mipmap, allowPicmip);\n\n\tif (gl_active) {\n\t\timage->internalFormat = upload_gl_image(upload_data, glWrapClampMode);\n\t}\n\t// VULKAN\n\tif (vk.active) {\n\t\tvk_world.images[image->index] = upload_vk_image(upload_data, glWrapClampMode == GL_REPEAT);\n\t}\n\t// DX12\n\tif (dx.active) {\n\t\tdx_world.images[image->index] = upload_dx_image(upload_data, glWrapClampMode == GL_REPEAT, image->index);\n\t}\n\n\tif (isLightmap) {\n\t\tGL_SelectTexture( 0 );\n\t}\n\tri.Hunk_FreeTempMemory(upload_data.buffer);\n\treturn image;\n}\n\n\n/*\n=========================================================\n\nBMP LOADING\n\n=========================================================\n*/\ntypedef struct\n{\n\tchar id[2];\n\tunsigned long fileSize;\n\tunsigned long reserved0;\n\tunsigned long bitmapDataOffset;\n\tunsigned long bitmapHeaderSize;\n\tunsigned long width;\n\tunsigned long height;\n\tunsigned short planes;\n\tunsigned short bitsPerPixel;\n\tunsigned long compression;\n\tunsigned long bitmapDataSize;\n\tunsigned long hRes;\n\tunsigned long vRes;\n\tunsigned long colors;\n\tunsigned long importantColors;\n\tunsigned char palette[256][4];\n} BMPHeader_t;\n\nstatic void LoadBMP( const char *name, byte **pic, int *width, int *height )\n{\n\tint\t\tcolumns, rows, numPixels;\n\tbyte\t*pixbuf;\n\tint\t\trow, column;\n\tbyte\t*buf_p;\n\tbyte\t*buffer;\n\tint\t\tlength;\n\tBMPHeader_t bmpHeader;\n\tbyte\t\t*bmpRGBA;\n\n\t*pic = NULL;\n\n\t//\n\t// load the file\n\t//\n\tlength = ri.FS_ReadFile( ( char * ) name, (void **)&buffer);\n\tif (!buffer) {\n\t\treturn;\n\t}\n\n\tbuf_p = buffer;\n\n\tbmpHeader.id[0] = *buf_p++;\n\tbmpHeader.id[1] = *buf_p++;\n\tbmpHeader.fileSize = LittleLong( * ( long * ) buf_p );\n\tbuf_p += 4;\n\tbmpHeader.reserved0 = LittleLong( * ( long * ) buf_p );\n\tbuf_p += 4;\n\tbmpHeader.bitmapDataOffset = LittleLong( * ( long * ) buf_p );\n\tbuf_p += 4;\n\tbmpHeader.bitmapHeaderSize = LittleLong( * ( long * ) buf_p );\n\tbuf_p += 4;\n\tbmpHeader.width = LittleLong( * ( long * ) buf_p );\n\tbuf_p += 4;\n\tbmpHeader.height = LittleLong( * ( long * ) buf_p );\n\tbuf_p += 4;\n\tbmpHeader.planes = LittleShort( * ( short * ) buf_p );\n\tbuf_p += 2;\n\tbmpHeader.bitsPerPixel = LittleShort( * ( short * ) buf_p );\n\tbuf_p += 2;\n\tbmpHeader.compression = LittleLong( * ( long * ) buf_p );\n\tbuf_p += 4;\n\tbmpHeader.bitmapDataSize = LittleLong( * ( long * ) buf_p );\n\tbuf_p += 4;\n\tbmpHeader.hRes = LittleLong( * ( long * ) buf_p );\n\tbuf_p += 4;\n\tbmpHeader.vRes = LittleLong( * ( long * ) buf_p );\n\tbuf_p += 4;\n\tbmpHeader.colors = LittleLong( * ( long * ) buf_p );\n\tbuf_p += 4;\n\tbmpHeader.importantColors = LittleLong( * ( long * ) buf_p );\n\tbuf_p += 4;\n\n\tCom_Memcpy( bmpHeader.palette, buf_p, sizeof( bmpHeader.palette ) );\n\n\tif ( bmpHeader.bitsPerPixel == 8 )\n\t\tbuf_p += 1024;\n\n\tif ( bmpHeader.id[0] != 'B' && bmpHeader.id[1] != 'M' ) \n\t{\n\t\tri.Error( ERR_DROP, \"LoadBMP: only Windows-style BMP files supported (%s)\\n\", name );\n\t}\n\tif ( (int)bmpHeader.fileSize != length )\n\t{\n\t\tri.Error( ERR_DROP, \"LoadBMP: header size does not match file size (%d vs. %d) (%s)\\n\", bmpHeader.fileSize, length, name );\n\t}\n\tif ( bmpHeader.compression != 0 )\n\t{\n\t\tri.Error( ERR_DROP, \"LoadBMP: only uncompressed BMP files supported (%s)\\n\", name );\n\t}\n\tif ( bmpHeader.bitsPerPixel < 8 )\n\t{\n\t\tri.Error( ERR_DROP, \"LoadBMP: monochrome and 4-bit BMP files not supported (%s)\\n\", name );\n\t}\n\n\tcolumns = bmpHeader.width;\n\trows = bmpHeader.height;\n\tif ( rows < 0 )\n\t\trows = -rows;\n\tnumPixels = columns * rows;\n\n\tif ( width ) \n\t\t*width = columns;\n\tif ( height )\n\t\t*height = rows;\n\n\tbmpRGBA = (byte*) ri.Malloc( numPixels * 4 );\n\t*pic = bmpRGBA;\n\n\n\tfor ( row = rows-1; row >= 0; row-- )\n\t{\n\t\tpixbuf = bmpRGBA + row*columns*4;\n\n\t\tfor ( column = 0; column < columns; column++ )\n\t\t{\n\t\t\tunsigned char red, green, blue, alpha;\n\t\t\tint palIndex;\n\t\t\tunsigned short shortPixel;\n\n\t\t\tswitch ( bmpHeader.bitsPerPixel )\n\t\t\t{\n\t\t\tcase 8:\n\t\t\t\tpalIndex = *buf_p++;\n\t\t\t\t*pixbuf++ = bmpHeader.palette[palIndex][2];\n\t\t\t\t*pixbuf++ = bmpHeader.palette[palIndex][1];\n\t\t\t\t*pixbuf++ = bmpHeader.palette[palIndex][0];\n\t\t\t\t*pixbuf++ = 0xff;\n\t\t\t\tbreak;\n\t\t\tcase 16:\n\t\t\t\tshortPixel = * ( unsigned short * ) pixbuf;\n\t\t\t\tpixbuf += 2;\n\t\t\t\t*pixbuf++ = ( shortPixel & ( 31 << 10 ) ) >> 7;\n\t\t\t\t*pixbuf++ = ( shortPixel & ( 31 << 5 ) ) >> 2;\n\t\t\t\t*pixbuf++ = ( shortPixel & ( 31 ) ) << 3;\n\t\t\t\t*pixbuf++ = 0xff;\n\t\t\t\tbreak;\n\n\t\t\tcase 24:\n\t\t\t\tblue = *buf_p++;\n\t\t\t\tgreen = *buf_p++;\n\t\t\t\tred = *buf_p++;\n\t\t\t\t*pixbuf++ = red;\n\t\t\t\t*pixbuf++ = green;\n\t\t\t\t*pixbuf++ = blue;\n\t\t\t\t*pixbuf++ = 255;\n\t\t\t\tbreak;\n\t\t\tcase 32:\n\t\t\t\tblue = *buf_p++;\n\t\t\t\tgreen = *buf_p++;\n\t\t\t\tred = *buf_p++;\n\t\t\t\talpha = *buf_p++;\n\t\t\t\t*pixbuf++ = red;\n\t\t\t\t*pixbuf++ = green;\n\t\t\t\t*pixbuf++ = blue;\n\t\t\t\t*pixbuf++ = alpha;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tri.Error( ERR_DROP, \"LoadBMP: illegal pixel_size '%d' in file '%s'\\n\", bmpHeader.bitsPerPixel, name );\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tri.FS_FreeFile( buffer );\n\n}\n\n\n/*\n=================================================================\n\nPCX LOADING\n\n=================================================================\n*/\n\n\n/*\n==============\nLoadPCX\n==============\n*/\nstatic void LoadPCX ( const char *filename, byte **pic, byte **palette, int *width, int *height)\n{\n\tbyte\t*raw;\n\tpcx_t\t*pcx;\n\tint\t\tx, y;\n\tint\t\tlen;\n\tint\t\tdataByte, runLength;\n\tbyte\t*out, *pix;\n\tint\t\txmax, ymax;\n\n\t*pic = NULL;\n\t*palette = NULL;\n\n\t//\n\t// load the file\n\t//\n\tlen = ri.FS_ReadFile( ( char * ) filename, (void **)&raw);\n\tif (!raw) {\n\t\treturn;\n\t}\n\n\t//\n\t// parse the PCX file\n\t//\n\tpcx = (pcx_t *)raw;\n\traw = &pcx->data;\n\n  \txmax = LittleShort(pcx->xmax);\n    ymax = LittleShort(pcx->ymax);\n\n\tif (pcx->manufacturer != 0x0a\n\t\t|| pcx->version != 5\n\t\t|| pcx->encoding != 1\n\t\t|| pcx->bits_per_pixel != 8\n\t\t|| xmax >= 1024\n\t\t|| ymax >= 1024)\n\t{\n\t\tri.Printf (PRINT_ALL, \"Bad pcx file %s (%i x %i) (%i x %i)\\n\", filename, xmax+1, ymax+1, pcx->xmax, pcx->ymax);\n\t\treturn;\n\t}\n\n\tout = (byte*) ri.Malloc ( (ymax+1) * (xmax+1) );\n\n\t*pic = out;\n\n\tpix = out;\n\n\tif (palette)\n\t{\n\t\t*palette = (byte*) ri.Malloc(768);\n\t\tCom_Memcpy (*palette, (byte *)pcx + len - 768, 768);\n\t}\n\n\tif (width)\n\t\t*width = xmax+1;\n\tif (height)\n\t\t*height = ymax+1;\n// FIXME: use bytes_per_line here?\n\n\tfor (y=0 ; y<=ymax ; y++, pix += xmax+1)\n\t{\n\t\tfor (x=0 ; x<=xmax ; )\n\t\t{\n\t\t\tdataByte = *raw++;\n\n\t\t\tif((dataByte & 0xC0) == 0xC0)\n\t\t\t{\n\t\t\t\trunLength = dataByte & 0x3F;\n\t\t\t\tdataByte = *raw++;\n\t\t\t}\n\t\t\telse\n\t\t\t\trunLength = 1;\n\n\t\t\twhile(runLength-- > 0)\n\t\t\t\tpix[x++] = dataByte;\n\t\t}\n\n\t}\n\n\tif ( raw - (byte *)pcx > len)\n\t{\n\t\tri.Printf (PRINT_DEVELOPER, \"PCX file %s was malformed\", filename);\n\t\tri.Free (*pic);\n\t\t*pic = NULL;\n\t}\n\n\tri.FS_FreeFile (pcx);\n}\n\n\n/*\n==============\nLoadPCX32\n==============\n*/\nstatic void LoadPCX32 ( const char *filename, byte **pic, int *width, int *height) {\n\tbyte\t*palette;\n\tbyte\t*pic8;\n\tint\t\ti, c, p;\n\tbyte\t*pic32;\n\n\tLoadPCX (filename, &pic8, &palette, width, height);\n\tif (!pic8) {\n\t\t*pic = NULL;\n\t\treturn;\n\t}\n\n\tc = (*width) * (*height);\n\tpic32 = *pic = (byte*) ri.Malloc(4 * c );\n\tfor (i = 0 ; i < c ; i++) {\n\t\tp = pic8[i];\n\t\tpic32[0] = palette[p*3];\n\t\tpic32[1] = palette[p*3 + 1];\n\t\tpic32[2] = palette[p*3 + 2];\n\t\tpic32[3] = 255;\n\t\tpic32 += 4;\n\t}\n\n\tri.Free (pic8);\n\tri.Free (palette);\n}\n\n/*\n=========================================================\n\nTARGA LOADING\n\n=========================================================\n*/\n\n/*\n=============\nLoadTGA\n=============\n*/\nstatic void LoadTGA ( const char *name, byte **pic, int *width, int *height)\n{\n\tint\t\tcolumns, rows, numPixels;\n\tbyte\t*pixbuf;\n\tint\t\trow, column;\n\tbyte\t*buf_p;\n\tbyte\t*buffer;\n\tTargaHeader\ttarga_header;\n\tbyte\t\t*targa_rgba;\n\n\t*pic = NULL;\n\n\t//\n\t// load the file\n\t//\n\tri.FS_ReadFile ( ( char * ) name, (void **)&buffer);\n\tif (!buffer) {\n\t\treturn;\n\t}\n\n\tbuf_p = buffer;\n\n\ttarga_header.id_length = *buf_p++;\n\ttarga_header.colormap_type = *buf_p++;\n\ttarga_header.image_type = *buf_p++;\n\t\n\ttarga_header.colormap_index = LittleShort ( *(short *)buf_p );\n\tbuf_p += 2;\n\ttarga_header.colormap_length = LittleShort ( *(short *)buf_p );\n\tbuf_p += 2;\n\ttarga_header.colormap_size = *buf_p++;\n\ttarga_header.x_origin = LittleShort ( *(short *)buf_p );\n\tbuf_p += 2;\n\ttarga_header.y_origin = LittleShort ( *(short *)buf_p );\n\tbuf_p += 2;\n\ttarga_header.width = LittleShort ( *(short *)buf_p );\n\tbuf_p += 2;\n\ttarga_header.height = LittleShort ( *(short *)buf_p );\n\tbuf_p += 2;\n\ttarga_header.pixel_size = *buf_p++;\n\ttarga_header.attributes = *buf_p++;\n\n\tif (targa_header.image_type!=2 \n\t\t&& targa_header.image_type!=10\n\t\t&& targa_header.image_type != 3 ) \n\t{\n\t\tri.Error (ERR_DROP, \"LoadTGA: Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported\\n\");\n\t}\n\n\tif ( targa_header.colormap_type != 0 )\n\t{\n\t\tri.Error( ERR_DROP, \"LoadTGA: colormaps not supported\\n\" );\n\t}\n\n\tif ( ( targa_header.pixel_size != 32 && targa_header.pixel_size != 24 ) && targa_header.image_type != 3 )\n\t{\n\t\tri.Error (ERR_DROP, \"LoadTGA: Only 32 or 24 bit images supported (no colormaps)\\n\");\n\t}\n\n\tcolumns = targa_header.width;\n\trows = targa_header.height;\n\tnumPixels = columns * rows;\n\n\tif (width)\n\t\t*width = columns;\n\tif (height)\n\t\t*height = rows;\n\n\ttarga_rgba = (byte*) ri.Malloc (numPixels*4);\n\t*pic = targa_rgba;\n\n\tif (targa_header.id_length != 0)\n\t\tbuf_p += targa_header.id_length;  // skip TARGA image comment\n\t\n\tif ( targa_header.image_type==2 || targa_header.image_type == 3 )\n\t{ \n\t\t// Uncompressed RGB or gray scale image\n\t\tfor(row=rows-1; row>=0; row--) \n\t\t{\n\t\t\tpixbuf = targa_rgba + row*columns*4;\n\t\t\tfor(column=0; column<columns; column++) \n\t\t\t{\n\t\t\t\tunsigned char red,green,blue,alphabyte;\n\t\t\t\tswitch (targa_header.pixel_size) \n\t\t\t\t{\n\t\t\t\t\t\n\t\t\t\tcase 8:\n\t\t\t\t\tblue = *buf_p++;\n\t\t\t\t\tgreen = blue;\n\t\t\t\t\tred = blue;\n\t\t\t\t\t*pixbuf++ = red;\n\t\t\t\t\t*pixbuf++ = green;\n\t\t\t\t\t*pixbuf++ = blue;\n\t\t\t\t\t*pixbuf++ = 255;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 24:\n\t\t\t\t\tblue = *buf_p++;\n\t\t\t\t\tgreen = *buf_p++;\n\t\t\t\t\tred = *buf_p++;\n\t\t\t\t\t*pixbuf++ = red;\n\t\t\t\t\t*pixbuf++ = green;\n\t\t\t\t\t*pixbuf++ = blue;\n\t\t\t\t\t*pixbuf++ = 255;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 32:\n\t\t\t\t\tblue = *buf_p++;\n\t\t\t\t\tgreen = *buf_p++;\n\t\t\t\t\tred = *buf_p++;\n\t\t\t\t\talphabyte = *buf_p++;\n\t\t\t\t\t*pixbuf++ = red;\n\t\t\t\t\t*pixbuf++ = green;\n\t\t\t\t\t*pixbuf++ = blue;\n\t\t\t\t\t*pixbuf++ = alphabyte;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tri.Error( ERR_DROP, \"LoadTGA: illegal pixel_size '%d' in file '%s'\\n\", targa_header.pixel_size, name );\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\telse if (targa_header.image_type==10) {   // Runlength encoded RGB images\n\t\tunsigned char red,green,blue,alphabyte,packetHeader,packetSize,j;\n\n\t\tred = 0;\n\t\tgreen = 0;\n\t\tblue = 0;\n\t\talphabyte = 0xff;\n\n\t\tfor(row=rows-1; row>=0; row--) {\n\t\t\tpixbuf = targa_rgba + row*columns*4;\n\t\t\tfor(column=0; column<columns; ) {\n\t\t\t\tpacketHeader= *buf_p++;\n\t\t\t\tpacketSize = 1 + (packetHeader & 0x7f);\n\t\t\t\tif (packetHeader & 0x80) {        // run-length packet\n\t\t\t\t\tswitch (targa_header.pixel_size) {\n\t\t\t\t\t\tcase 24:\n\t\t\t\t\t\t\t\tblue = *buf_p++;\n\t\t\t\t\t\t\t\tgreen = *buf_p++;\n\t\t\t\t\t\t\t\tred = *buf_p++;\n\t\t\t\t\t\t\t\talphabyte = 255;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 32:\n\t\t\t\t\t\t\t\tblue = *buf_p++;\n\t\t\t\t\t\t\t\tgreen = *buf_p++;\n\t\t\t\t\t\t\t\tred = *buf_p++;\n\t\t\t\t\t\t\t\talphabyte = *buf_p++;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\tri.Error( ERR_DROP, \"LoadTGA: illegal pixel_size '%d' in file '%s'\\n\", targa_header.pixel_size, name );\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\n\t\t\t\t\tfor(j=0;j<packetSize;j++) {\n\t\t\t\t\t\t*pixbuf++=red;\n\t\t\t\t\t\t*pixbuf++=green;\n\t\t\t\t\t\t*pixbuf++=blue;\n\t\t\t\t\t\t*pixbuf++=alphabyte;\n\t\t\t\t\t\tcolumn++;\n\t\t\t\t\t\tif (column==columns) { // run spans across rows\n\t\t\t\t\t\t\tcolumn=0;\n\t\t\t\t\t\t\tif (row>0)\n\t\t\t\t\t\t\t\trow--;\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\tgoto breakOut;\n\t\t\t\t\t\t\tpixbuf = targa_rgba + row*columns*4;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {                            // non run-length packet\n\t\t\t\t\tfor(j=0;j<packetSize;j++) {\n\t\t\t\t\t\tswitch (targa_header.pixel_size) {\n\t\t\t\t\t\t\tcase 24:\n\t\t\t\t\t\t\t\t\tblue = *buf_p++;\n\t\t\t\t\t\t\t\t\tgreen = *buf_p++;\n\t\t\t\t\t\t\t\t\tred = *buf_p++;\n\t\t\t\t\t\t\t\t\t*pixbuf++ = red;\n\t\t\t\t\t\t\t\t\t*pixbuf++ = green;\n\t\t\t\t\t\t\t\t\t*pixbuf++ = blue;\n\t\t\t\t\t\t\t\t\t*pixbuf++ = 255;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase 32:\n\t\t\t\t\t\t\t\t\tblue = *buf_p++;\n\t\t\t\t\t\t\t\t\tgreen = *buf_p++;\n\t\t\t\t\t\t\t\t\tred = *buf_p++;\n\t\t\t\t\t\t\t\t\talphabyte = *buf_p++;\n\t\t\t\t\t\t\t\t\t*pixbuf++ = red;\n\t\t\t\t\t\t\t\t\t*pixbuf++ = green;\n\t\t\t\t\t\t\t\t\t*pixbuf++ = blue;\n\t\t\t\t\t\t\t\t\t*pixbuf++ = alphabyte;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\tri.Error( ERR_DROP, \"LoadTGA: illegal pixel_size '%d' in file '%s'\\n\", targa_header.pixel_size, name );\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcolumn++;\n\t\t\t\t\t\tif (column==columns) { // pixel packet run spans across rows\n\t\t\t\t\t\t\tcolumn=0;\n\t\t\t\t\t\t\tif (row>0)\n\t\t\t\t\t\t\t\trow--;\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\tgoto breakOut;\n\t\t\t\t\t\t\tpixbuf = targa_rgba + row*columns*4;\n\t\t\t\t\t\t}\t\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreakOut:;\n\t\t}\n\t}\n\n#if 0 \n  // TTimo: this is the chunk of code to ensure a behavior that meets TGA specs \n  // bk0101024 - fix from Leonardo\n  // bit 5 set => top-down\n  if (targa_header.attributes & 0x20) {\n    unsigned char *flip = (unsigned char*)malloc (columns*4);\n    unsigned char *src, *dst;\n\n    for (row = 0; row < rows/2; row++) {\n      src = targa_rgba + row * 4 * columns;\n      dst = targa_rgba + (rows - row - 1) * 4 * columns;\n\n      memcpy (flip, src, columns*4);\n      memcpy (src, dst, columns*4);\n      memcpy (dst, flip, columns*4);\n    }\n    free (flip);\n  }\n#endif\n  // instead we just print a warning\n  if (targa_header.attributes & 0x20) {\n    ri.Printf( PRINT_WARNING, \"WARNING: '%s' TGA file header declares top-down image, ignoring\\n\", name);\n  }\n\n  ri.FS_FreeFile (buffer);\n}\n\nstatic void LoadJPG( const char *filename, byte **pic, int *width, int *height ) {\n  byte* fbuffer;\n  int len = ri.FS_ReadFile ( ( char * ) filename, (void **)&fbuffer);\n  if (!fbuffer) {\n\treturn;\n  }\n  \n  int components;\n  *pic = stbi_load_from_memory(fbuffer, len, width, height, &components, STBI_rgb_alpha);\n  if (*pic == nullptr) {\n      ri.FS_FreeFile(fbuffer);\n      return;\n  }\n\n  // clear all the alphas to 255\n  {\n      int\ti, j;\n      byte\t*buf;\n\n      buf = *pic;\n\n      j = *width * *height * 4;\n      for (i = 3; i < j; i += 4) {\n          buf[i] = 255;\n      }\n  }\n  ri.FS_FreeFile(fbuffer);\n}\n\nstruct Write_Context {\n    byte* buffer;\n    int capacity;\n    int size = 0;\n\n    Write_Context(int capacity) {\n        this->capacity = capacity;\n        buffer = (byte*)ri.Malloc(capacity);\n    }\n    ~Write_Context() {\n        if (buffer != nullptr)\n            ri.Free(buffer);\n    }\n};\n\nstatic void jpeg_write_func(void* context, void* data, int size) {\n    auto ctx = static_cast<Write_Context*>(context);\n    if (ctx->capacity < ctx->size + size) {\n        int new_capacity = 1.5 * (ctx->size + size);\n        byte* new_buffer = (byte*)ri.Malloc(new_capacity);\n        memcpy(new_buffer, ctx->buffer, ctx->size);\n        ri.Free(ctx->buffer);\n        ctx->buffer = new_buffer;\n        ctx->capacity = new_capacity;\n    }\n    memcpy(ctx->buffer + ctx->size, data, size);\n    ctx->size += size;\n}\n\nvoid SaveJPG(char * filename, int quality, int image_width, int image_height, unsigned char *image_buffer) {\n    // jpeg encoder requires top-bottom rows ordering\n    auto buffer = (byte*)ri.Hunk_AllocateTempMemory(image_width * image_height * 4);\n    int row_bytes = image_width * 4;\n    for (int i = 0; i < image_height; i++) {\n        memcpy(&buffer[i * row_bytes], &image_buffer[(image_height - 1 - i) * row_bytes], row_bytes);\n    }\n\n    Write_Context context(1024*1024);\n    if (tje_encode_with_func(jpeg_write_func, &context, 2, image_width, image_height, 4, buffer)) {\n        ri.FS_WriteFile(filename, context.buffer, context.size);\n    }\n    ri.Hunk_FreeTempMemory(buffer);\n}\n\n//===================================================================\n\n/*\n=================\nR_LoadImage\n\nLoads any of the supported image types into a cannonical\n32 bit format.\n=================\n*/\nvoid R_LoadImage( const char *name, byte **pic, int *width, int *height ) {\n\tint\t\tlen;\n\n\t*pic = NULL;\n\t*width = 0;\n\t*height = 0;\n\n\tlen = (int)strlen(name);\n\tif (len<5) {\n\t\treturn;\n\t}\n\n\tif ( !Q_stricmp( name+len-4, \".tga\" ) ) {\n\t  LoadTGA( name, pic, width, height );            // try tga first\n    if (!*pic) {                                    //\n\t\t  char altname[MAX_QPATH];                      // try jpg in place of tga \n      strcpy( altname, name );                      \n      len = (int)strlen( altname );                  \n      altname[len-3] = 'j';\n      altname[len-2] = 'p';\n      altname[len-1] = 'g';\n\t\t\tLoadJPG( altname, pic, width, height );\n\t\t}\n  } else if ( !Q_stricmp(name+len-4, \".pcx\") ) {\n    LoadPCX32( name, pic, width, height );\n\t} else if ( !Q_stricmp( name+len-4, \".bmp\" ) ) {\n\t\tLoadBMP( name, pic, width, height );\n\t} else if ( !Q_stricmp( name+len-4, \".jpg\" ) ) {\n\t\tLoadJPG( name, pic, width, height );\n\t}\n}\n\n\n/*\n===============\nR_FindImageFile\n\nFinds or loads the given image.\nReturns NULL if it fails, not a default image.\n==============\n*/\nimage_t\t*R_FindImageFile( const char *name, qboolean mipmap, qboolean allowPicmip, int glWrapClampMode ) {\n\timage_t\t*image;\n\tint\t\twidth, height;\n\tbyte\t*pic;\n\tlong\thash;\n\n\tif (!name) {\n\t\treturn NULL;\n\t}\n\n\thash = generateHashValue(name);\n\n\t//\n\t// see if the image is already loaded\n\t//\n\tfor (image=hashTable[hash]; image; image=image->next) {\n\t\tif ( !strcmp( name, image->imgName ) ) {\n\t\t\t// the white image can be used with any set of parms, but other mismatches are errors\n\t\t\tif ( strcmp( name, \"*white\" ) ) {\n\t\t\t\tif ( image->mipmap != mipmap ) {\n\t\t\t\t\tri.Printf( PRINT_DEVELOPER, \"WARNING: reused image %s with mixed mipmap parm\\n\", name );\n\t\t\t\t}\n\t\t\t\tif ( image->allowPicmip != allowPicmip ) {\n\t\t\t\t\tri.Printf( PRINT_DEVELOPER, \"WARNING: reused image %s with mixed allowPicmip parm\\n\", name );\n\t\t\t\t}\n\t\t\t\tif ( image->wrapClampMode != glWrapClampMode ) {\n\t\t\t\t\tri.Printf( PRINT_ALL, \"WARNING: reused image %s with mixed glWrapClampMode parm\\n\", name );\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn image;\n\t\t}\n\t}\n\n\t//\n\t// load the pic from disk\n\t//\n\tR_LoadImage( name, &pic, &width, &height );\n\tif ( pic == NULL ) {                                    // if we dont get a successful load\n\t  char altname[MAX_QPATH];                              // copy the name\n    int len;                                              //  \n    strcpy( altname, name );                              //\n    len = (int)strlen( altname );                              // \n    altname[len-3] = toupper(altname[len-3]);             // and try upper case extension for unix systems\n    altname[len-2] = toupper(altname[len-2]);             //\n    altname[len-1] = toupper(altname[len-1]);             //\n\t\tri.Printf( PRINT_ALL, \"trying %s...\\n\", altname );    // \n\t  R_LoadImage( altname, &pic, &width, &height );        //\n    if (pic == NULL) {                                    // if that fails\n      return NULL;                                        // bail\n    }\n\t}\n\n\timage = R_CreateImage( ( char * ) name, pic, width, height, mipmap, allowPicmip, glWrapClampMode );\n\tri.Free( pic );\n\treturn image;\n}\n\n\n/*\n================\nR_CreateDlightImage\n================\n*/\n#define\tDLIGHT_SIZE\t16\nstatic void R_CreateDlightImage( void ) {\n\tint\t\tx,y;\n\tbyte\tdata[DLIGHT_SIZE][DLIGHT_SIZE][4];\n\tint\t\tb;\n\n\t// make a centered inverse-square falloff blob for dynamic lighting\n\tfor (x=0 ; x<DLIGHT_SIZE ; x++) {\n\t\tfor (y=0 ; y<DLIGHT_SIZE ; y++) {\n\t\t\tfloat\td;\n\n\t\t\td = ( DLIGHT_SIZE/2 - 0.5f - x ) * ( DLIGHT_SIZE/2 - 0.5f - x ) +\n\t\t\t\t( DLIGHT_SIZE/2 - 0.5f - y ) * ( DLIGHT_SIZE/2 - 0.5f - y );\n\t\t\tb = 4000 / d;\n\t\t\tif (b > 255) {\n\t\t\t\tb = 255;\n\t\t\t} else if ( b < 75 ) {\n\t\t\t\tb = 0;\n\t\t\t}\n\t\t\tdata[y][x][0] = \n\t\t\tdata[y][x][1] = \n\t\t\tdata[y][x][2] = b;\n\t\t\tdata[y][x][3] = 255;\t\t\t\n\t\t}\n\t}\n\ttr.dlightImage = R_CreateImage(\"*dlight\", (byte *)data, DLIGHT_SIZE, DLIGHT_SIZE, qfalse, qfalse, GL_CLAMP );\n}\n\n\n/*\n=================\nR_InitFogTable\n=================\n*/\nvoid R_InitFogTable( void ) {\n\tint\t\ti;\n\tfloat\td;\n\tfloat\texp;\n\t\n\texp = 0.5;\n\n\tfor ( i = 0 ; i < FOG_TABLE_SIZE ; i++ ) {\n\t\td = pow ( (float)i/(FOG_TABLE_SIZE-1), exp );\n\n\t\ttr.fogTable[i] = d;\n\t}\n}\n\n/*\n================\nR_FogFactor\n\nReturns a 0.0 to 1.0 fog density value\nThis is called for each texel of the fog texture on startup\nand for each vertex of transparent shaders in fog dynamically\n================\n*/\nfloat\tR_FogFactor( float s, float t ) {\n\tfloat\td;\n\n\ts -= 1.0/512;\n\tif ( s < 0 ) {\n\t\treturn 0;\n\t}\n\tif ( t < 1.0/32 ) {\n\t\treturn 0;\n\t}\n\tif ( t < 31.0/32 ) {\n\t\ts *= (t - 1.0f/32.0f) / (30.0f/32.0f);\n\t}\n\n\t// we need to leave a lot of clamp range\n\ts *= 8;\n\n\tif ( s > 1.0 ) {\n\t\ts = 1.0;\n\t}\n\n\td = tr.fogTable[ (int)(s * (FOG_TABLE_SIZE-1)) ];\n\n\treturn d;\n}\n\n/*\n================\nR_CreateFogImage\n================\n*/\n#define\tFOG_S\t256\n#define\tFOG_T\t32\nstatic void R_CreateFogImage( void ) {\n\tint\t\tx,y;\n\tbyte\t*data;\n\tfloat\tg;\n\tfloat\td;\n\tfloat\tborderColor[4];\n\n\tdata = (byte*) ri.Hunk_AllocateTempMemory( FOG_S * FOG_T * 4 );\n\n\tg = 2.0;\n\n\t// S is distance, T is depth\n\tfor (x=0 ; x<FOG_S ; x++) {\n\t\tfor (y=0 ; y<FOG_T ; y++) {\n\t\t\td = R_FogFactor( ( x + 0.5f ) / FOG_S, ( y + 0.5f ) / FOG_T );\n\n\t\t\tdata[(y*FOG_S+x)*4+0] = \n\t\t\tdata[(y*FOG_S+x)*4+1] = \n\t\t\tdata[(y*FOG_S+x)*4+2] = 255;\n\t\t\tdata[(y*FOG_S+x)*4+3] = 255*d;\n\t\t}\n\t}\n\t// standard openGL clamping doesn't really do what we want -- it includes\n\t// the border color at the edges.  OpenGL 1.2 has clamp-to-edge, which does\n\t// what we want.\n\ttr.fogImage = R_CreateImage(\"*fog\", (byte *)data, FOG_S, FOG_T, qfalse, qfalse, GL_CLAMP );\n\tri.Hunk_FreeTempMemory( data );\n\n\tborderColor[0] = 1.0;\n\tborderColor[1] = 1.0;\n\tborderColor[2] = 1.0;\n\tborderColor[3] = 1;\n\n\tqglTexParameterfv( GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor );\n}\n\n/*\n==================\nR_CreateDefaultImage\n==================\n*/\n#define\tDEFAULT_SIZE\t16\nstatic void R_CreateDefaultImage( void ) {\n\tint\t\tx;\n\tbyte\tdata[DEFAULT_SIZE][DEFAULT_SIZE][4];\n\n\t// the default image will be a box, to allow you to see the mapping coordinates\n\tCom_Memset( data, 32, sizeof( data ) );\n\tfor ( x = 0 ; x < DEFAULT_SIZE ; x++ ) {\n\t\tdata[0][x][0] =\n\t\tdata[0][x][1] =\n\t\tdata[0][x][2] =\n\t\tdata[0][x][3] = 255;\n\n\t\tdata[x][0][0] =\n\t\tdata[x][0][1] =\n\t\tdata[x][0][2] =\n\t\tdata[x][0][3] = 255;\n\n\t\tdata[DEFAULT_SIZE-1][x][0] =\n\t\tdata[DEFAULT_SIZE-1][x][1] =\n\t\tdata[DEFAULT_SIZE-1][x][2] =\n\t\tdata[DEFAULT_SIZE-1][x][3] = 255;\n\n\t\tdata[x][DEFAULT_SIZE-1][0] =\n\t\tdata[x][DEFAULT_SIZE-1][1] =\n\t\tdata[x][DEFAULT_SIZE-1][2] =\n\t\tdata[x][DEFAULT_SIZE-1][3] = 255;\n\t}\n\ttr.defaultImage = R_CreateImage(\"*default\", (byte *)data, DEFAULT_SIZE, DEFAULT_SIZE, qtrue, qfalse, GL_REPEAT );\n}\n\n/*\n==================\nR_CreateBuiltinImages\n==================\n*/\nvoid R_CreateBuiltinImages( void ) {\n\tint\t\tx,y;\n\tbyte\tdata[DEFAULT_SIZE][DEFAULT_SIZE][4];\n\n\tR_CreateDefaultImage();\n\n\t// we use a solid white image instead of disabling texturing\n\tCom_Memset( data, 255, sizeof( data ) );\n\ttr.whiteImage = R_CreateImage(\"*white\", (byte *)data, 8, 8, qfalse, qfalse, GL_REPEAT );\n\n\t// with overbright bits active, we need an image which is some fraction of full color,\n\t// for default lightmaps, etc\n\tfor (x=0 ; x<DEFAULT_SIZE ; x++) {\n\t\tfor (y=0 ; y<DEFAULT_SIZE ; y++) {\n\t\t\tdata[y][x][0] = \n\t\t\tdata[y][x][1] = \n\t\t\tdata[y][x][2] = tr.identityLightByte;\n\t\t\tdata[y][x][3] = 255;\t\t\t\n\t\t}\n\t}\n\n\ttr.identityLightImage = R_CreateImage(\"*identityLight\", (byte *)data, 8, 8, qfalse, qfalse, GL_REPEAT );\n\n\n\tfor(x=0;x<32;x++) {\n\t\t// scratchimage is usually used for cinematic drawing\n\t\ttr.scratchImage[x] = R_CreateImage(\"*scratch\", (byte *)data, DEFAULT_SIZE, DEFAULT_SIZE, qfalse, qtrue, GL_CLAMP );\n\t}\n\n\tR_CreateDlightImage();\n\tR_CreateFogImage();\n}\n\n\n/*\n===============\nR_SetColorMappings\n===============\n*/\nvoid R_SetColorMappings( void ) {\n\tint\t\ti, j;\n\tfloat\tg;\n\tint\t\tinf;\n\tint\t\tshift;\n\n\t// setup the overbright lighting\n\ttr.overbrightBits = r_overBrightBits->integer;\n\tif ( !glConfig.deviceSupportsGamma ) {\n\t\ttr.overbrightBits = 0;\t\t// need hardware gamma for overbright\n\t}\n\n\t// never overbright in windowed mode\n\tif ( !glConfig.isFullscreen ) \n\t{\n\t\ttr.overbrightBits = 0;\n\t}\n\n\t// allow 2 overbright bits in 24 bit, but only 1 in 16 bit\n\tif ( glConfig.colorBits > 16 ) {\n\t\tif ( tr.overbrightBits > 2 ) {\n\t\t\ttr.overbrightBits = 2;\n\t\t}\n\t} else {\n\t\tif ( tr.overbrightBits > 1 ) {\n\t\t\ttr.overbrightBits = 1;\n\t\t}\n\t}\n\tif ( tr.overbrightBits < 0 ) {\n\t\ttr.overbrightBits = 0;\n\t}\n\n\ttr.identityLight = 1.0f / ( 1 << tr.overbrightBits );\n\ttr.identityLightByte = 255 * tr.identityLight;\n\n\n\tif ( r_intensity->value <= 1 ) {\n\t\tri.Cvar_Set( \"r_intensity\", \"1\" );\n\t}\n\n\tif ( r_gamma->value < 0.5f ) {\n\t\tri.Cvar_Set( \"r_gamma\", \"0.5\" );\n\t} else if ( r_gamma->value > 3.0f ) {\n\t\tri.Cvar_Set( \"r_gamma\", \"3.0\" );\n\t}\n\n\tg = r_gamma->value;\n\n\tshift = tr.overbrightBits;\n\n\tfor ( i = 0; i < 256; i++ ) {\n\t\tif ( g == 1 ) {\n\t\t\tinf = i;\n\t\t} else {\n\t\t\tinf = 255 * pow ( i/255.0f, 1.0f / g ) + 0.5f;\n\t\t}\n\t\tinf <<= shift;\n\t\tif (inf < 0) {\n\t\t\tinf = 0;\n\t\t}\n\t\tif (inf > 255) {\n\t\t\tinf = 255;\n\t\t}\n\t\ts_gammatable[i] = inf;\n\t}\n\n\tfor (i=0 ; i<256 ; i++) {\n\t\tj = i * r_intensity->value;\n\t\tif (j > 255) {\n\t\t\tj = 255;\n\t\t}\n\t\ts_intensitytable[i] = j;\n\t}\n\n\tif (vk.active && r_shaderGamma->integer) {\n\t\tif (r_ignorehwgamma->integer) {\n\t\t\treturn;\n\t\t}\n\t\tif (r_shaderGamma->modified) {\n\t\t\tGLimp_RestoreGamma();\n\t\t}\n\t\tfloat shader_gamma_table[256];\n\t\tfor (int i = 0; i < 256; i++) {\n\t\t\tshader_gamma_table[i] = float((((unsigned short)s_gammatable[i]) << 8) | s_gammatable[i]) / UINT16_MAX;\n\t\t}\n\t\tvk_update_gamma_buffer(shader_gamma_table);\n\t}\n\telse if ( glConfig.deviceSupportsGamma )\n\t{\n\t\tGLimp_SetGamma( s_gammatable );\n\t}\n}\n\n/*\n===============\nR_InitImages\n===============\n*/\nvoid\tR_InitImages( void ) {\n\tCom_Memset(hashTable, 0, sizeof(hashTable));\n\t// build brightness translation tables\n\tR_SetColorMappings();\n\n\t// create default texture and white texture\n\tR_CreateBuiltinImages();\n}\n\n/*\n===============\nR_DeleteTextures\n===============\n*/\nvoid R_DeleteTextures( void ) {\n\tfor ( int i=0; i<tr.numImages ; i++ ) {\n\t\tqglDeleteTextures( 1, &tr.images[i]->texnum );\n\t}\n\tCom_Memset( tr.images, 0, sizeof( tr.images ) );\n\n\ttr.numImages = 0;\n\n\tCom_Memset( glState.currenttextures, 0, sizeof( glState.currenttextures ) );\n\n\tif ( qglBindTexture ) {\n\t\tGL_SelectTexture( 1 );\n\t\tqglBindTexture( GL_TEXTURE_2D, 0 );\n\t\tGL_SelectTexture( 0 );\n\t\tqglBindTexture( GL_TEXTURE_2D, 0 );\n\t}\n}\n\n/*\n============================================================================\n\nSKINS\n\n============================================================================\n*/\n\n/*\n==================\nCommaParse\n\nThis is unfortunate, but the skin files aren't\ncompatable with our normal parsing rules.\n==================\n*/\nstatic char *CommaParse( char **data_p ) {\n\tint c = 0, len;\n\tchar *data;\n\tstatic\tchar\tcom_token[MAX_TOKEN_CHARS];\n\n\tdata = *data_p;\n\tlen = 0;\n\tcom_token[0] = 0;\n\n\t// make sure incoming data is valid\n\tif ( !data ) {\n\t\t*data_p = NULL;\n\t\treturn com_token;\n\t}\n\n\twhile ( 1 ) {\n\t\t// skip whitespace\n\t\twhile( (c = *data) <= ' ') {\n\t\t\tif( !c ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdata++;\n\t\t}\n\n\n\t\tc = *data;\n\n\t\t// skip double slash comments\n\t\tif ( c == '/' && data[1] == '/' )\n\t\t{\n\t\t\twhile (*data && *data != '\\n')\n\t\t\t\tdata++;\n\t\t}\n\t\t// skip /* */ comments\n\t\telse if ( c=='/' && data[1] == '*' ) \n\t\t{\n\t\t\twhile ( *data && ( *data != '*' || data[1] != '/' ) ) \n\t\t\t{\n\t\t\t\tdata++;\n\t\t\t}\n\t\t\tif ( *data ) \n\t\t\t{\n\t\t\t\tdata += 2;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif ( c == 0 ) {\n\t\treturn \"\";\n\t}\n\n\t// handle quoted strings\n\tif (c == '\\\"')\n\t{\n\t\tdata++;\n\t\twhile (1)\n\t\t{\n\t\t\tc = *data++;\n\t\t\tif (c=='\\\"' || !c)\n\t\t\t{\n\t\t\t\tcom_token[len] = 0;\n\t\t\t\t*data_p = ( char * ) data;\n\t\t\t\treturn com_token;\n\t\t\t}\n\t\t\tif (len < MAX_TOKEN_CHARS)\n\t\t\t{\n\t\t\t\tcom_token[len] = c;\n\t\t\t\tlen++;\n\t\t\t}\n\t\t}\n\t}\n\n\t// parse a regular word\n\tdo\n\t{\n\t\tif (len < MAX_TOKEN_CHARS)\n\t\t{\n\t\t\tcom_token[len] = c;\n\t\t\tlen++;\n\t\t}\n\t\tdata++;\n\t\tc = *data;\n\t} while (c>32 && c != ',' );\n\n\tif (len == MAX_TOKEN_CHARS)\n\t{\n//\t\tCom_Printf (\"Token exceeded %i chars, discarded.\\n\", MAX_TOKEN_CHARS);\n\t\tlen = 0;\n\t}\n\tcom_token[len] = 0;\n\n\t*data_p = ( char * ) data;\n\treturn com_token;\n}\n\n\n/*\n===============\nRE_RegisterSkin\n\n===============\n*/\nqhandle_t RE_RegisterSkin( const char *name ) {\n\tqhandle_t\thSkin;\n\tskin_t\t\t*skin;\n\tskinSurface_t\t*surf;\n\tchar\t\t*text, *text_p;\n\tchar\t\t*token;\n\tchar\t\tsurfName[MAX_QPATH];\n\n\tif ( !name || !name[0] ) {\n\t\tCom_Printf( \"Empty name passed to RE_RegisterSkin\\n\" );\n\t\treturn 0;\n\t}\n\n\tif ( (int)strlen( name ) >= MAX_QPATH ) {\n\t\tCom_Printf( \"Skin name exceeds MAX_QPATH\\n\" );\n\t\treturn 0;\n\t}\n\n\n\t// see if the skin is already loaded\n\tfor ( hSkin = 1; hSkin < tr.numSkins ; hSkin++ ) {\n\t\tskin = tr.skins[hSkin];\n\t\tif ( !Q_stricmp( skin->name, name ) ) {\n\t\t\tif( skin->numSurfaces == 0 ) {\n\t\t\t\treturn 0;\t\t// default skin\n\t\t\t}\n\t\t\treturn hSkin;\n\t\t}\n\t}\n\n\t// allocate a new skin\n\tif ( tr.numSkins == MAX_SKINS ) {\n\t\tri.Printf( PRINT_WARNING, \"WARNING: RE_RegisterSkin( '%s' ) MAX_SKINS hit\\n\", name );\n\t\treturn 0;\n\t}\n\ttr.numSkins++;\n\tskin = (skin_t*) ri.Hunk_Alloc( sizeof( skin_t ), h_low );\n\ttr.skins[hSkin] = skin;\n\tQ_strncpyz( skin->name, name, sizeof( skin->name ) );\n\tskin->numSurfaces = 0;\n\n\t// make sure the render thread is stopped\n\tR_SyncRenderThread();\n\n\t// If not a .skin file, load as a single shader\n\tif ( strcmp( name + (int)strlen( name ) - 5, \".skin\" ) ) {\n\t\tskin->numSurfaces = 1;\n\t\tskin->surfaces[0] = (skinSurface_t*) ri.Hunk_Alloc( sizeof(skin->surfaces[0]), h_low );\n\t\tskin->surfaces[0]->shader = R_FindShader( name, LIGHTMAP_NONE, qtrue );\n\t\treturn hSkin;\n\t}\n\n\t// load and parse the skin file\n    ri.FS_ReadFile( name, (void **)&text );\n\tif ( !text ) {\n\t\treturn 0;\n\t}\n\n\ttext_p = text;\n\twhile ( text_p && *text_p ) {\n\t\t// get surface name\n\t\ttoken = CommaParse( &text_p );\n\t\tQ_strncpyz( surfName, token, sizeof( surfName ) );\n\n\t\tif ( !token[0] ) {\n\t\t\tbreak;\n\t\t}\n\t\t// lowercase the surface name so skin compares are faster\n\t\tQ_strlwr( surfName );\n\n\t\tif ( *text_p == ',' ) {\n\t\t\ttext_p++;\n\t\t}\n\n\t\tif ( strstr( token, \"tag_\" ) ) {\n\t\t\tcontinue;\n\t\t}\n\t\t\n\t\t// parse the shader name\n\t\ttoken = CommaParse( &text_p );\n\n\t\tsurf = skin->surfaces[ skin->numSurfaces ] = (skinSurface_t*) ri.Hunk_Alloc( sizeof( *skin->surfaces[0] ), h_low );\n\t\tQ_strncpyz( surf->name, surfName, sizeof( surf->name ) );\n\t\tsurf->shader = R_FindShader( token, LIGHTMAP_NONE, qtrue );\n\t\tskin->numSurfaces++;\n\t}\n\n\tri.FS_FreeFile( text );\n\n\n\t// never let a skin have 0 shaders\n\tif ( skin->numSurfaces == 0 ) {\n\t\treturn 0;\t\t// use default skin\n\t}\n\n\treturn hSkin;\n}\n\n\n/*\n===============\nR_InitSkins\n===============\n*/\nvoid\tR_InitSkins( void ) {\n\tskin_t\t\t*skin;\n\n\ttr.numSkins = 1;\n\n\t// make the default skin have all default shaders\n\tskin = tr.skins[0] = (skin_t*) ri.Hunk_Alloc( sizeof( skin_t ), h_low );\n\tQ_strncpyz( skin->name, \"<default skin>\", sizeof( skin->name )  );\n\tskin->numSurfaces = 1;\n\tskin->surfaces[0] = (skinSurface_t*) ri.Hunk_Alloc( sizeof( *skin->surfaces ), h_low );\n\tskin->surfaces[0]->shader = tr.defaultShader;\n}\n\n/*\n===============\nR_GetSkinByHandle\n===============\n*/\nskin_t\t*R_GetSkinByHandle( qhandle_t hSkin ) {\n\tif ( hSkin < 1 || hSkin >= tr.numSkins ) {\n\t\treturn tr.skins[0];\n\t}\n\treturn tr.skins[ hSkin ];\n}\n\n/*\n===============\nR_SkinList_f\n===============\n*/\nvoid\tR_SkinList_f( void ) {\n\tint\t\t\ti, j;\n\tskin_t\t\t*skin;\n\n\tri.Printf (PRINT_ALL, \"------------------\\n\");\n\n\tfor ( i = 0 ; i < tr.numSkins ; i++ ) {\n\t\tskin = tr.skins[i];\n\n\t\tri.Printf( PRINT_ALL, \"%3i:%s\\n\", i, skin->name );\n\t\tfor ( j = 0 ; j < skin->numSurfaces ; j++ ) {\n\t\t\tri.Printf( PRINT_ALL, \"       %s = %s\\n\", \n\t\t\t\tskin->surfaces[j]->name, skin->surfaces[j]->shader->name );\n\t\t}\n\t}\n\tri.Printf (PRINT_ALL, \"------------------\\n\");\n}\n\n"
  },
  {
    "path": "src/engine/renderer/tr_init.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n// tr_init.c -- functions that are not called every frame\n\n#include \"tr_local.h\"\n\nbool\t\tgl_active;\nglconfig_t\tglConfig;\nglstate_t\tglState;\n\n// VULKAN\nVk_Instance vk;\nVk_World\tvk_world;\n\n// DX12\nDx_Instance dx;\nDx_World\tdx_world;\n\nstatic void GfxInfo_f( void );\n\ncvar_t *r_renderAPI;\ncvar_t* r_gpu;\ncvar_t* r_vsync;\ncvar_t *r_shaderGamma;\ncvar_t* r_twinMode;\n\ncvar_t\t*r_railWidth;\ncvar_t\t*r_railCoreWidth;\ncvar_t\t*r_railSegmentLength;\n\ncvar_t\t*r_verbose;\n\ncvar_t\t*r_detailTextures;\n\ncvar_t\t*r_znear;\n\ncvar_t\t*r_smp;\ncvar_t\t*r_showSmp;\ncvar_t\t*r_skipBackEnd;\n\ncvar_t\t*r_ignorehwgamma;\n\ncvar_t\t*r_inGameVideo;\ncvar_t\t*r_fastsky;\ncvar_t\t*r_dynamiclight;\n\ncvar_t\t*r_lodbias;\ncvar_t\t*r_lodscale;\n\ncvar_t\t*r_norefresh;\ncvar_t\t*r_drawentities;\ncvar_t\t*r_drawworld;\ncvar_t\t*r_speeds;\ncvar_t\t*r_fullbright;\ncvar_t\t*r_novis;\ncvar_t\t*r_nocull;\ncvar_t\t*r_facePlaneCull;\ncvar_t\t*r_showcluster;\ncvar_t\t*r_nocurves;\n\ncvar_t\t*r_ext_compressed_textures;\ncvar_t\t*r_ext_gamma_control;\ncvar_t\t*r_ext_compiled_vertex_array;\ncvar_t\t*r_ext_texture_env_add;\n\ncvar_t\t*r_ignoreGLErrors;\ncvar_t\t*r_logFile;\n\ncvar_t\t*r_stencilbits;\ncvar_t\t*r_depthbits;\ncvar_t\t*r_stereo;\ncvar_t\t*r_texturebits;\n\ncvar_t\t*r_drawBuffer;\ncvar_t  *r_glDriver;\ncvar_t\t*r_lightmap;\ncvar_t\t*r_vertexLight;\ncvar_t\t*r_uiFullScreen;\ncvar_t\t*r_shadows;\ncvar_t\t*r_mode;\ncvar_t\t*r_nobind;\ncvar_t\t*r_singleShader;\ncvar_t\t*r_roundImagesDown;\ncvar_t\t*r_colorMipLevels;\ncvar_t\t*r_picmip;\ncvar_t\t*r_showtris;\ncvar_t\t*r_showsky;\ncvar_t\t*r_shownormals;\ncvar_t\t*r_clear;\ncvar_t\t*r_swapInterval;\ncvar_t\t*r_textureMode;\ncvar_t\t*r_offsetFactor;\ncvar_t\t*r_offsetUnits;\ncvar_t\t*r_gamma;\ncvar_t\t*r_intensity;\ncvar_t\t*r_lockpvs;\ncvar_t\t*r_noportals;\ncvar_t\t*r_portalOnly;\n\ncvar_t\t*r_subdivisions;\ncvar_t\t*r_lodCurveError;\n\ncvar_t\t*r_fullscreen;\n\ncvar_t\t*r_customwidth;\ncvar_t\t*r_customheight;\ncvar_t\t*r_customaspect;\n\ncvar_t\t*r_overBrightBits;\ncvar_t\t*r_mapOverBrightBits;\n\ncvar_t\t*r_debugSurface;\ncvar_t\t*r_simpleMipMaps;\n\ncvar_t\t*r_showImages;\n\ncvar_t\t*r_ambientScale;\ncvar_t\t*r_directedScale;\ncvar_t\t*r_debugLight;\ncvar_t\t*r_debugSort;\ncvar_t\t*r_printShaders;\ncvar_t\t*r_saveFontData;\n\ncvar_t\t*r_maxpolys;\nint\t\tmax_polys;\ncvar_t\t*r_maxpolyverts;\nint\t\tmax_polyverts;\n\nvoid ( APIENTRY * qglActiveTextureARB )( GLenum texture );\nvoid ( APIENTRY * qglClientActiveTextureARB )( GLenum texture );\n\nvoid ( APIENTRY * qglLockArraysEXT)( GLint, GLint);\nvoid ( APIENTRY * qglUnlockArraysEXT) ( void );\n\nstatic void AssertCvarRange( cvar_t *cv, float minVal, float maxVal, qboolean shouldBeIntegral )\n{\n\tif ( shouldBeIntegral )\n\t{\n\t\tif ( ( int ) cv->value != cv->integer )\n\t\t{\n\t\t\tri.Printf( PRINT_WARNING, \"WARNING: cvar '%s' must be integral (%f)\\n\", cv->name, cv->value );\n\t\t\tri.Cvar_Set( cv->name, va( \"%d\", cv->integer ) );\n\t\t}\n\t}\n\n\tif ( cv->value < minVal )\n\t{\n\t\tri.Printf( PRINT_WARNING, \"WARNING: cvar '%s' out of range (%f < %f)\\n\", cv->name, cv->value, minVal );\n\t\tri.Cvar_Set( cv->name, va( \"%f\", minVal ) );\n\t}\n\telse if ( cv->value > maxVal )\n\t{\n\t\tri.Printf( PRINT_WARNING, \"WARNING: cvar '%s' out of range (%f > %f)\\n\", cv->name, cv->value, maxVal );\n\t\tri.Cvar_Set( cv->name, va( \"%f\", maxVal ) );\n\t}\n}\n\nRenderApi get_render_api() {\n\tif (r_renderAPI->integer == 0)\n\t\treturn RENDER_API_GL;\n\telse if (r_renderAPI->integer == 1)\n\t\treturn RENDER_API_VK;\n\telse if (r_renderAPI->integer == 2)\n#ifdef ENABLE_DX12\n\t\treturn RENDER_API_DX;\n#else\n\t\treturn RENDER_API_VK; // use default (Vulkan) if dx12 is disabled\n#endif\n\telse\n\t\treturn RENDER_API_VK; // use default (Vulkan) if invalid r_renderAPI value is specified\n}\n\n/*\n** This function is responsible for initializing a valid OpenGL/Vulkan subsystem.\n*/\nstatic void InitRenderAPI( void )\n{\n\t//\n\t// initialize OS specific portions of the renderer\n\t//\n\t// GLimp_Init directly or indirectly references the following cvars:\n\t//\t\t- r_fullscreen\n\t//\t\t- r_glDriver\n\t//\t\t- r_mode\n\t//\t\t- r_(depth|stencil)bits\n\t//\t\t- r_ignorehwgamma\n\t//\t\t- r_gamma\n\t//\n\tif ( glConfig.vidWidth == 0 )\n\t{\n#ifndef ENABLE_DX12\n\t\tif (r_renderAPI->integer == 2) {\n\t\t\tri.Printf(PRINT_WARNING, \"DirectX 12 backend is disabled (code was compiled without ENABLE_DX12). Vulkan backend will be used instead.\\n\");\n\t\t}\n#endif\n\n\t\t// OpenGL\n\t\tif (get_render_api() == RENDER_API_GL || r_twinMode->integer)\n\t\t{\n\t\t\tGLimp_Init();\n\n\t\t\tGLint temp;\n\t\t\tqglGetIntegerv( GL_MAX_TEXTURE_SIZE, &temp );\n\t\t\tglConfig.maxTextureSize = temp;\n\n\t\t\tgl_active = true;\n\t\t}\n\n\t\t// VULKAN\n\t\tif (get_render_api() == RENDER_API_VK || r_twinMode->integer)\n\t\t{\n\t\t\tvk_imp_init();\n\t\t\tvk_initialize();\n\t\t}\n\n\t\t// DX12\n#ifdef ENABLE_DX12\n\t\tif (get_render_api() == RENDER_API_DX || r_twinMode->integer)\n\t\t{\n\t\t\tdx_imp_init();\n\t\t\tdx_initialize();\n\t\t}\n#endif\n\t}\n\n\t// init command buffers and SMP\n\tR_InitCommandBuffers();\n\n\t// print info\n\tGfxInfo_f();\n\n\t// set default state\n\tGL_SetDefaultState();\n}\n\n/*\n==================\nGL_CheckErrors\n==================\n*/\nvoid GL_CheckErrors( void ) {\n    int\t\terr;\n    char\ts[64];\n\n    err = qglGetError();\n    if ( err == GL_NO_ERROR ) {\n        return;\n    }\n    if ( r_ignoreGLErrors->integer ) {\n        return;\n    }\n    switch( err ) {\n        case GL_INVALID_ENUM:\n            strcpy( s, \"GL_INVALID_ENUM\" );\n            break;\n        case GL_INVALID_VALUE:\n            strcpy( s, \"GL_INVALID_VALUE\" );\n            break;\n        case GL_INVALID_OPERATION:\n            strcpy( s, \"GL_INVALID_OPERATION\" );\n            break;\n        case GL_STACK_OVERFLOW:\n            strcpy( s, \"GL_STACK_OVERFLOW\" );\n            break;\n        case GL_STACK_UNDERFLOW:\n            strcpy( s, \"GL_STACK_UNDERFLOW\" );\n            break;\n        case GL_OUT_OF_MEMORY:\n            strcpy( s, \"GL_OUT_OF_MEMORY\" );\n            break;\n        default:\n            Com_sprintf( s, sizeof(s), \"%i\", err);\n            break;\n    }\n\n    ri.Error( ERR_FATAL, \"GL_CheckErrors: %s\", s );\n}\n\n\n/*\n** R_GetModeInfo\n*/\ntypedef struct vidmode_s\n{\n    const char *description;\n    int         width, height;\n\tfloat\t\tpixelAspect;\t\t// pixel width / height\n} vidmode_t;\n\nvidmode_t r_vidModes[] =\n{\n    { \"Mode  0: 320x240\",\t\t320,\t240,\t1 },\n    { \"Mode  1: 400x300\",\t\t400,\t300,\t1 },\n    { \"Mode  2: 512x384\",\t\t512,\t384,\t1 },\n    { \"Mode  3: 640x480\",\t\t640,\t480,\t1 },\n    { \"Mode  4: 800x600\",\t\t800,\t600,\t1 },\n    { \"Mode  5: 960x720\",\t\t960,\t720,\t1 },\n    { \"Mode  6: 1024x768\",\t\t1024,\t768,\t1 },\n    { \"Mode  7: 1152x864\",\t\t1152,\t864,\t1 },\n    { \"Mode  8: 1280x1024\",\t\t1280,\t1024,\t1 },\n    { \"Mode  9: 1600x1200\",\t\t1600,\t1200,\t1 },\n    { \"Mode 10: 2048x1536\",\t\t2048,\t1536,\t1 },\n    { \"Mode 11: 856x480 (wide)\",856,\t480,\t1 }\n};\nstatic int\ts_numVidModes = ( sizeof( r_vidModes ) / sizeof( r_vidModes[0] ) );\n\nqboolean R_GetModeInfo( int *width, int *height, float *windowAspect, int mode ) {\n\tvidmode_t\t*vm;\n\n    if ( mode < -1 ) {\n        return qfalse;\n\t}\n\tif ( mode >= s_numVidModes ) {\n\t\treturn qfalse;\n\t}\n\n\tif ( mode == -1 ) {\n\t\t*width = r_customwidth->integer;\n\t\t*height = r_customheight->integer;\n\t\t*windowAspect = r_customaspect->value;\n\t\treturn qtrue;\n\t}\n\n\tvm = &r_vidModes[mode];\n\n    *width  = vm->width;\n    *height = vm->height;\n    *windowAspect = (float)vm->width / ( vm->height * vm->pixelAspect );\n\n    return qtrue;\n}\n\n/*\n** R_ModeList_f\n*/\nstatic void R_ModeList_f( void )\n{\n\tint i;\n\n\tri.Printf( PRINT_ALL, \"\\n\" );\n\tfor ( i = 0; i < s_numVidModes; i++ )\n\t{\n\t\tri.Printf( PRINT_ALL, \"%s\\n\", r_vidModes[i].description );\n\t}\n\tri.Printf( PRINT_ALL, \"\\n\" );\n}\n\n\n/* \n============================================================================== \n \n\t\t\t\t\t\tSCREEN SHOTS \n\nNOTE TTimo\nsome thoughts about the screenshots system:\nscreenshots get written in fs_homepath + fs_gamedir\nvanilla q3 .. baseq3/screenshots/ *.tga\nteam arena .. missionpack/screenshots/ *.tga\n\ntwo commands: \"screenshot\" and \"screenshotJPEG\"\nwe use statics to store a count and start writing the first screenshot/screenshot????.tga (.jpg) available\n(with FS_FileExists / FS_FOpenFileWrite calls)\nFIXME: the statics don't get a reinit between fs_game changes\n\n============================================================================== \n*/ \n\n/* \n================== \nRB_TakeScreenshot\n================== \n*/  \nvoid RB_TakeScreenshot( int x, int y, int width, int height, char *fileName ) {\n\tbyte\t\t*buffer;\n\tint\t\t\ti, c, temp;\n\t\t\n\tbuffer = (byte*) ri.Hunk_AllocateTempMemory(glConfig.vidWidth*glConfig.vidHeight*3+18);\n\n\tCom_Memset (buffer, 0, 18);\n\tbuffer[2] = 2;\t\t// uncompressed type\n\tbuffer[12] = width & 255;\n\tbuffer[13] = width >> 8;\n\tbuffer[14] = height & 255;\n\tbuffer[15] = height >> 8;\n\tbuffer[16] = 24;\t// pixel size\n\n\tif (get_render_api() == RENDER_API_GL) {\n\t\tqglReadPixels( x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer+18 ); \n\t} else if (get_render_api() == RENDER_API_VK) { // VULKAN\n\t\tbyte* buffer2 = (byte*) ri.Hunk_AllocateTempMemory(glConfig.vidWidth*glConfig.vidHeight*4);\n\n\t\tvk_read_pixels(buffer2);\n\n\t\tbyte* buffer_ptr = buffer + 18;\n\t\tbyte* buffer2_ptr = buffer2;\n\t\tfor (int i = 0; i < glConfig.vidWidth * glConfig.vidHeight; i++) {\n\t\t\tbuffer_ptr[0] = buffer2_ptr[0];\n\t\t\tbuffer_ptr[1] = buffer2_ptr[1];\n\t\t\tbuffer_ptr[2] = buffer2_ptr[2];\n\t\t\tbuffer_ptr += 3;\n\t\t\tbuffer2_ptr += 4;\n\t\t}\n\t\tri.Hunk_FreeTempMemory(buffer2);\n\t} else if (get_render_api() == RENDER_API_DX) { // DX12\n\t\tri.Printf(PRINT_WARNING, \"RT_TakeScreenshot is not implemented for DX12\");\n\t}\n\n\t// swap rgb to bgr\n\tc = 18 + width * height * 3;\n\tfor (i=18 ; i<c ; i+=3) {\n\t\ttemp = buffer[i];\n\t\tbuffer[i] = buffer[i+2];\n\t\tbuffer[i+2] = temp;\n\t}\n\n\t// gamma correct\n\tif ( ( tr.overbrightBits > 0 ) && glConfig.deviceSupportsGamma ) {\n\t\tR_GammaCorrect( buffer + 18, glConfig.vidWidth * glConfig.vidHeight * 3 );\n\t}\n\n\tri.FS_WriteFile( fileName, buffer, c );\n\n\tri.Hunk_FreeTempMemory( buffer );\n}\n\n/* \n================== \nRB_TakeScreenshotJPEG\n================== \n*/  \nvoid RB_TakeScreenshotJPEG( int x, int y, int width, int height, char *fileName ) {\n\tbyte* buffer = (byte*) ri.Hunk_AllocateTempMemory(glConfig.vidWidth*glConfig.vidHeight*4);;\n\n\tif (get_render_api() == RENDER_API_GL) {\n\t\tqglReadPixels( x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer ); \n\t} else if (get_render_api() == RENDER_API_VK) { // VULKAN\n\t\tvk_read_pixels(buffer);\n\t} else if (get_render_api() == RENDER_API_DX) { // DX12\n\t\tri.Printf(PRINT_WARNING, \"RT_TakeScreenshotJPEG is not implemented for DX12\");\n\t}\n\n\t// gamma correct\n\tif ( ( tr.overbrightBits > 0 ) && glConfig.deviceSupportsGamma ) {\n\t\tR_GammaCorrect( buffer, glConfig.vidWidth * glConfig.vidHeight * 4 );\n\t}\n\n\tri.FS_WriteFile( fileName, buffer, 1 );\t\t// create path\n\tSaveJPG( fileName, 95, glConfig.vidWidth, glConfig.vidHeight, buffer);\n\n\tri.Hunk_FreeTempMemory( buffer );\n}\n\n/*\n==================\nRB_TakeScreenshotCmd\n==================\n*/\nconst void *RB_TakeScreenshotCmd( const void *data ) {\n\tconst screenshotCommand_t\t*cmd;\n\t\n\tcmd = (const screenshotCommand_t *)data;\n\t\n\tif (cmd->jpeg)\n\t\tRB_TakeScreenshotJPEG( cmd->x, cmd->y, cmd->width, cmd->height, cmd->fileName);\n\telse\n\t\tRB_TakeScreenshot( cmd->x, cmd->y, cmd->width, cmd->height, cmd->fileName);\n\t\n\treturn (const void *)(cmd + 1);\t\n}\n\n/*\n==================\nR_TakeScreenshot\n==================\n*/\nvoid R_TakeScreenshot( int x, int y, int width, int height, char *name, qboolean jpeg ) {\n\tstatic char\tfileName[MAX_OSPATH]; // bad things if two screenshots per frame?\n\tscreenshotCommand_t\t*cmd;\n\n\tcmd = (screenshotCommand_t*) R_GetCommandBuffer(sizeof(*cmd));\n\tif ( !cmd ) {\n\t\treturn;\n\t}\n\tcmd->commandId = RC_SCREENSHOT;\n\n\tcmd->x = x;\n\tcmd->y = y;\n\tcmd->width = width;\n\tcmd->height = height;\n\tQ_strncpyz( fileName, name, sizeof(fileName) );\n\tcmd->fileName = fileName;\n\tcmd->jpeg = jpeg;\n}\n\n/* \n================== \nR_ScreenshotFilename\n================== \n*/  \nvoid R_ScreenshotFilename( int lastNumber, char *fileName ) {\n\tint\t\ta,b,c,d;\n\n\tif ( lastNumber < 0 || lastNumber > 9999 ) {\n\t\tCom_sprintf( fileName, MAX_OSPATH, \"screenshots/shot9999.tga\" );\n\t\treturn;\n\t}\n\n\ta = lastNumber / 1000;\n\tlastNumber -= a*1000;\n\tb = lastNumber / 100;\n\tlastNumber -= b*100;\n\tc = lastNumber / 10;\n\tlastNumber -= c*10;\n\td = lastNumber;\n\n\tCom_sprintf( fileName, MAX_OSPATH, \"screenshots/shot%i%i%i%i.tga\"\n\t\t, a, b, c, d );\n}\n\n/* \n================== \nR_ScreenshotFilename\n================== \n*/  \nvoid R_ScreenshotFilenameJPEG( int lastNumber, char *fileName ) {\n\tint\t\ta,b,c,d;\n\n\tif ( lastNumber < 0 || lastNumber > 9999 ) {\n\t\tCom_sprintf( fileName, MAX_OSPATH, \"screenshots/shot9999.jpg\" );\n\t\treturn;\n\t}\n\n\ta = lastNumber / 1000;\n\tlastNumber -= a*1000;\n\tb = lastNumber / 100;\n\tlastNumber -= b*100;\n\tc = lastNumber / 10;\n\tlastNumber -= c*10;\n\td = lastNumber;\n\n\tCom_sprintf( fileName, MAX_OSPATH, \"screenshots/shot%i%i%i%i.jpg\"\n\t\t, a, b, c, d );\n}\n\n/*\n====================\nR_LevelShot\n\nlevelshots are specialized 128*128 thumbnails for\nthe menu system, sampled down from full screen distorted images\n====================\n*/\nvoid R_LevelShot( void ) {\n\tchar\t\tcheckname[MAX_OSPATH];\n\tbyte\t\t*buffer;\n\tbyte\t\t*source;\n\tbyte\t\t*src, *dst;\n\tint\t\t\tx, y;\n\tint\t\t\tr, g, b;\n\tfloat\t\txScale, yScale;\n\tint\t\t\txx, yy;\n\n\tsprintf( checkname, \"levelshots/%s.tga\", tr.world->baseName );\n\n\tsource = (byte*) ri.Hunk_AllocateTempMemory( glConfig.vidWidth * glConfig.vidHeight * 3 );\n\n\tbuffer = (byte*) ri.Hunk_AllocateTempMemory( 128 * 128*3 + 18);\n\tCom_Memset (buffer, 0, 18);\n\tbuffer[2] = 2;\t\t// uncompressed type\n\tbuffer[12] = 128;\n\tbuffer[14] = 128;\n\tbuffer[16] = 24;\t// pixel size\n\n\tif (get_render_api() == RENDER_API_GL) {\n\t\tqglReadPixels( 0, 0, glConfig.vidWidth, glConfig.vidHeight, GL_RGB, GL_UNSIGNED_BYTE, source ); \n\t} else if (get_render_api() == RENDER_API_VK) { // VULKAN\n\t\tbyte* buffer2 = (byte*) ri.Hunk_AllocateTempMemory(glConfig.vidWidth*glConfig.vidHeight*4);\n\t\tvk_read_pixels(buffer2);\n\n\t\tbyte* buffer_ptr = source;\n\t\tbyte* buffer2_ptr = buffer2;\n\t\tfor (int i = 0; i < glConfig.vidWidth * glConfig.vidHeight; i++) {\n\t\t\tbuffer_ptr[0] = buffer2_ptr[0];\n\t\t\tbuffer_ptr[1] = buffer2_ptr[1];\n\t\t\tbuffer_ptr[2] = buffer2_ptr[2];\n\t\t\tbuffer_ptr += 3;\n\t\t\tbuffer2_ptr += 4;\n\t\t}\n\t\tri.Hunk_FreeTempMemory(buffer2);\n\t} else if (get_render_api() == RENDER_API_DX) { // DX12\n\t\tri.Printf(PRINT_WARNING, \"R_LevelShot is not implemented for DX12\");\n\t}\n\n\t// resample from source\n\txScale = glConfig.vidWidth / 512.0f;\n\tyScale = glConfig.vidHeight / 384.0f;\n\tfor ( y = 0 ; y < 128 ; y++ ) {\n\t\tfor ( x = 0 ; x < 128 ; x++ ) {\n\t\t\tr = g = b = 0;\n\t\t\tfor ( yy = 0 ; yy < 3 ; yy++ ) {\n\t\t\t\tfor ( xx = 0 ; xx < 4 ; xx++ ) {\n\t\t\t\t\tsrc = source + 3 * ( glConfig.vidWidth * (int)( (y*3+yy)*yScale ) + (int)( (x*4+xx)*xScale ) );\n\t\t\t\t\tr += src[0];\n\t\t\t\t\tg += src[1];\n\t\t\t\t\tb += src[2];\n\t\t\t\t}\n\t\t\t}\n\t\t\tdst = buffer + 18 + 3 * ( y * 128 + x );\n\t\t\tdst[0] = b / 12;\n\t\t\tdst[1] = g / 12;\n\t\t\tdst[2] = r / 12;\n\t\t}\n\t}\n\n\t// gamma correct\n\tif ( ( tr.overbrightBits > 0 ) && glConfig.deviceSupportsGamma ) {\n\t\tR_GammaCorrect( buffer + 18, 128 * 128 * 3 );\n\t}\n\n\tri.FS_WriteFile( checkname, buffer, 128 * 128*3 + 18 );\n\n\tri.Hunk_FreeTempMemory( buffer );\n\tri.Hunk_FreeTempMemory( source );\n\n\tri.Printf( PRINT_ALL, \"Wrote %s\\n\", checkname );\n}\n\n/* \n================== \nR_ScreenShot_f\n\nscreenshot\nscreenshot [silent]\nscreenshot [levelshot]\nscreenshot [filename]\n\nDoesn't print the pacifier message if there is a second arg\n================== \n*/  \nvoid R_ScreenShot_f (void) {\n\tchar\tcheckname[MAX_OSPATH];\n\tstatic\tint\tlastNumber = -1;\n\tqboolean\tsilent;\n\n\tif ( !strcmp( ri.Cmd_Argv(1), \"levelshot\" ) ) {\n\t\tR_LevelShot();\n\t\treturn;\n\t}\n\n\tif ( !strcmp( ri.Cmd_Argv(1), \"silent\" ) ) {\n\t\tsilent = qtrue;\n\t} else {\n\t\tsilent = qfalse;\n\t}\n\n\tif ( ri.Cmd_Argc() == 2 && !silent ) {\n\t\t// explicit filename\n\t\tCom_sprintf( checkname, MAX_OSPATH, \"screenshots/%s.tga\", ri.Cmd_Argv( 1 ) );\n\t} else {\n\t\t// scan for a free filename\n\n\t\t// if we have saved a previous screenshot, don't scan\n\t\t// again, because recording demo avis can involve\n\t\t// thousands of shots\n\t\tif ( lastNumber == -1 ) {\n\t\t\tlastNumber = 0;\n\t\t}\n\t\t// scan for a free number\n\t\tfor ( ; lastNumber <= 9999 ; lastNumber++ ) {\n\t\t\tR_ScreenshotFilename( lastNumber, checkname );\n\n      if (!ri.FS_FileExists( checkname ))\n      {\n        break; // file doesn't exist\n      }\n\t\t}\n\n\t\tif ( lastNumber >= 9999 ) {\n\t\t\tri.Printf (PRINT_ALL, \"ScreenShot: Couldn't create a file\\n\"); \n\t\t\treturn;\n \t\t}\n\n\t\tlastNumber++;\n\t}\n\n\tR_TakeScreenshot( 0, 0, glConfig.vidWidth, glConfig.vidHeight, checkname, qfalse );\n\n\tif ( !silent ) {\n\t\tri.Printf (PRINT_ALL, \"Wrote %s\\n\", checkname);\n\t}\n} \n\nvoid R_ScreenShotJPEG_f (void) {\n\tchar\t\tcheckname[MAX_OSPATH];\n\tstatic\tint\tlastNumber = -1;\n\tqboolean\tsilent;\n\n\tif ( !strcmp( ri.Cmd_Argv(1), \"levelshot\" ) ) {\n\t\tR_LevelShot();\n\t\treturn;\n\t}\n\n\tif ( !strcmp( ri.Cmd_Argv(1), \"silent\" ) ) {\n\t\tsilent = qtrue;\n\t} else {\n\t\tsilent = qfalse;\n\t}\n\n\tif ( ri.Cmd_Argc() == 2 && !silent ) {\n\t\t// explicit filename\n\t\tCom_sprintf( checkname, MAX_OSPATH, \"screenshots/%s.jpg\", ri.Cmd_Argv( 1 ) );\n\t} else {\n\t\t// scan for a free filename\n\n\t\t// if we have saved a previous screenshot, don't scan\n\t\t// again, because recording demo avis can involve\n\t\t// thousands of shots\n\t\tif ( lastNumber == -1 ) {\n\t\t\tlastNumber = 0;\n\t\t}\n\t\t// scan for a free number\n\t\tfor ( ; lastNumber <= 9999 ; lastNumber++ ) {\n\t\t\tR_ScreenshotFilenameJPEG( lastNumber, checkname );\n\n      if (!ri.FS_FileExists( checkname ))\n      {\n        break; // file doesn't exist\n      }\n\t\t}\n\n\t\tif ( lastNumber == 10000 ) {\n\t\t\tri.Printf (PRINT_ALL, \"ScreenShot: Couldn't create a file\\n\"); \n\t\t\treturn;\n \t\t}\n\n\t\tlastNumber++;\n\t}\n\n\tR_TakeScreenshot( 0, 0, glConfig.vidWidth, glConfig.vidHeight, checkname, qtrue );\n\n\tif ( !silent ) {\n\t\tri.Printf (PRINT_ALL, \"Wrote %s\\n\", checkname);\n\t}\n} \n\n//============================================================================\n\n/*\n** GL_SetDefaultState\n*/\nvoid GL_SetDefaultState( void )\n{\n\tqglCullFace(GL_FRONT);\n\n\tqglColor3f (1,1,1);\n\n\t// initialize downstream texture unit\n\tGL_SelectTexture( 1 );\n\tGL_TextureMode( r_textureMode->string );\n\tGL_TexEnv( GL_MODULATE );\n\tqglDisable( GL_TEXTURE_2D );\n\tGL_SelectTexture( 0 );\n\n\tqglEnable(GL_TEXTURE_2D);\n\tGL_TextureMode( r_textureMode->string );\n\tGL_TexEnv( GL_MODULATE );\n\n\tqglDepthFunc( GL_LEQUAL );\n\n\t// the vertex array is always enabled, but the color and texture\n\t// arrays are enabled and disabled around the compiled vertex array call\n\tqglEnableClientState (GL_VERTEX_ARRAY);\n\n\t//\n\t// make sure our GL state vector is set correctly\n\t//\n\tglState.glStateBits = GLS_DEPTHTEST_DISABLE | GLS_DEPTHMASK_TRUE;\n\n\tqglPolygonMode (GL_FRONT_AND_BACK, GL_FILL);\n\tqglDepthMask( GL_TRUE );\n\tqglDisable( GL_DEPTH_TEST );\n\tqglEnable( GL_SCISSOR_TEST );\n\tqglDisable( GL_CULL_FACE );\n\tqglDisable( GL_BLEND );\n}\n\n\n/*\n================\nGfxInfo_f\n================\n*/\nvoid GfxInfo_f( void ) \n{\n\tconst char *enablestrings[] =\n\t{\n\t\t\"disabled\",\n\t\t\"enabled\"\n\t};\n\tconst char *fsstrings[] =\n\t{\n\t\t\"windowed\",\n\t\t\"fullscreen\"\n\t};\n\n\tif (gl_active) {\n\t\tri.Printf( PRINT_ALL, \"\\nActive 3D API: OpenGL\\n\" );\n\t\tri.Printf( PRINT_ALL, \"GL_VENDOR: %s\\n\", glConfig.vendor_string );\n\t\tri.Printf( PRINT_ALL, \"GL_RENDERER: %s\\n\", glConfig.renderer_string );\n\t\tri.Printf( PRINT_ALL, \"GL_VERSION: %s\\n\", glConfig.version_string );\n\t\tri.Printf( PRINT_ALL, \"GL_MAX_TEXTURE_SIZE: %d\\n\", glConfig.maxTextureSize );\n\t\tri.Printf( PRINT_ALL, \"GL_MAX_ACTIVE_TEXTURES_ARB: %d\\n\", glConfig.maxActiveTextures );\n\t\tri.Printf( PRINT_ALL, \"PIXELFORMAT: color(%d-bits) Z(%d-bit) stencil(%d-bits)\\n\", glConfig.colorBits, glConfig.depthBits, glConfig.stencilBits );\n\t\tri.Printf( PRINT_ALL, \"compiled vertex arrays: %s\\n\", enablestrings[qglLockArraysEXT != 0 ] );\n\t\tri.Printf( PRINT_ALL, \"texenv add: %s\\n\", enablestrings[glConfig.textureEnvAddAvailable != 0] );\n\t\tri.Printf( PRINT_ALL, \"compressed textures: %s\\n\", enablestrings[glConfig.textureCompression!=TC_NONE] );\n\n\t\tif (glConfig.smpActive) {\n\t\t\tri.Printf( PRINT_ALL, \"Using dual processor acceleration\\n\" );\n\t\t}\n\t}\n\n\t// VULKAN\n\tif (vk.active) {\n\t\tri.Printf( PRINT_ALL, \"\\nActive 3D API: Vulkan\\n\" );\n\t\tVkPhysicalDeviceProperties props;\n\t\tvkGetPhysicalDeviceProperties(vk.physical_device, &props);\n\n\t\tuint32_t major = VK_VERSION_MAJOR(props.apiVersion);\n\t\tuint32_t minor = VK_VERSION_MINOR(props.apiVersion);\n\t\tuint32_t patch = VK_VERSION_PATCH(props.apiVersion);\n\n\t\tconst char* device_type;\n\t\tif (props.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU)\n\t\t\tdevice_type = \"INTEGRATED_GPU\";\n\t\telse if (props.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)\n\t\t\tdevice_type = \"DISCRETE_GPU\";\n\t\telse if (props.deviceType == VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU)\n\t\t\tdevice_type = \"VIRTUAL_GPU\";\n\t\telse if (props.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU)\n\t\t\tdevice_type = \"CPU\";\n\t\telse\n\t\t\tdevice_type = \"Unknown\";\n\n\t\tconst char* vendor_name = \"unknown\";\n\t\tif (props.vendorID == 0x1002) {\n\t\t\tvendor_name = \"Advanced Micro Devices, Inc.\";\n\t\t} else if (props.vendorID == 0x10DE) {\n\t\t\tvendor_name = \"NVIDIA\";\n\t\t} else if (props.vendorID == 0x8086) {\n\t\t\tvendor_name = \"Intel Corporation\";\n\t\t}\n\n\t\tri.Printf(PRINT_ALL, \"Vk api version: %d.%d.%d\\n\", major, minor, patch);\n\t\tri.Printf(PRINT_ALL, \"Vk driver version: %d\\n\", props.driverVersion);\n\t\tri.Printf(PRINT_ALL, \"Vk vendor id: 0x%X (%s)\\n\", props.vendorID, vendor_name);\n\t\tri.Printf(PRINT_ALL, \"Vk device id: 0x%X\\n\", props.deviceID);\n\t\tri.Printf(PRINT_ALL, \"Vk device type: %s\\n\", device_type);\n\t\tri.Printf(PRINT_ALL, \"Vk device name: %s\\n\", props.deviceName);\n\t}\n\n\t// DX12\n\tif (dx.active) {\n\t\tri.Printf( PRINT_ALL, \"\\nActive 3D API: DirectX 12\\n\" );\n\t}\n\n\t//\n\t// Info that doesn't depend on r_renderAPI\n\t//\n\tri.Printf( PRINT_ALL, \"\\nMODE: %d, %d x %d %s\\n\", r_mode->integer, glConfig.vidWidth, glConfig.vidHeight, fsstrings[r_fullscreen->integer == 1] );\n\n\tif (glConfig.deviceSupportsGamma) {\n\t\tri.Printf( PRINT_ALL, \"GAMMA: hardware w/ %d overbright bits\\n\", tr.overbrightBits );\n\t} \n\telse {\n\t\tri.Printf( PRINT_ALL, \"GAMMA: software w/ %d overbright bits\\n\", tr.overbrightBits );\n\t}\n\n\tri.Printf( PRINT_ALL, \"texturemode: %s\\n\", r_textureMode->string );\n\tri.Printf( PRINT_ALL, \"picmip: %d\\n\", r_picmip->integer );\n\tri.Printf( PRINT_ALL, \"texture bits: %d\\n\", r_texturebits->integer );\n\n\tif ( r_vertexLight->integer ) {\n\t\tri.Printf( PRINT_ALL, \"HACK: using vertex lightmap approximation\\n\" );\n\t}\n}\n\n/*\n===============\nR_Register\n===============\n*/\nvoid R_Register( void ) \n{\n    r_renderAPI = ri.Cvar_Get( \"r_renderAPI\", \"1\", CVAR_ARCHIVE | CVAR_LATCH ) ;\n\tr_gpu = ri.Cvar_Get( \"r_gpu\", \"0\", CVAR_ARCHIVE | CVAR_LATCH );\n\tr_vsync = ri.Cvar_Get( \"r_vsync\", \"0\", CVAR_ARCHIVE | CVAR_LATCH );\n\tr_shaderGamma = ri.Cvar_Get(\"r_shaderGamma\", \"0\", CVAR_ARCHIVE);\n\tr_twinMode = ri.Cvar_Get( \"r_twinMode\", \"0\", CVAR_LATCH );\n\n\t//\n\t// latched and archived variables\n\t//\n\tr_glDriver = ri.Cvar_Get( \"r_glDriver\", OPENGL_DRIVER_NAME, CVAR_ARCHIVE | CVAR_LATCH );\n\tr_ext_compressed_textures = ri.Cvar_Get( \"r_ext_compressed_textures\", \"0\", CVAR_ARCHIVE | CVAR_LATCH );\n\tr_ext_gamma_control = ri.Cvar_Get( \"r_ext_gamma_control\", \"1\", CVAR_ARCHIVE | CVAR_LATCH );\n\tr_ext_compiled_vertex_array = ri.Cvar_Get( \"r_ext_compiled_vertex_array\", \"1\", CVAR_ARCHIVE | CVAR_LATCH);\n\tr_ext_texture_env_add = ri.Cvar_Get( \"r_ext_texture_env_add\", \"1\", CVAR_ARCHIVE | CVAR_LATCH);\n\tr_picmip = ri.Cvar_Get (\"r_picmip\", \"1\", CVAR_ARCHIVE | CVAR_LATCH );\n\tr_roundImagesDown = ri.Cvar_Get (\"r_roundImagesDown\", \"1\", CVAR_ARCHIVE | CVAR_LATCH );\n\tr_colorMipLevels = ri.Cvar_Get (\"r_colorMipLevels\", \"0\", CVAR_LATCH );\n\tAssertCvarRange( r_picmip, 0, 16, qtrue );\n\tr_detailTextures = ri.Cvar_Get( \"r_detailtextures\", \"1\", CVAR_ARCHIVE | CVAR_LATCH );\n\tr_texturebits = ri.Cvar_Get( \"r_texturebits\", \"0\", CVAR_ARCHIVE | CVAR_LATCH );\n\tr_stereo = ri.Cvar_Get( \"r_stereo\", \"0\", CVAR_ARCHIVE | CVAR_LATCH );\n\tr_stencilbits = ri.Cvar_Get( \"r_stencilbits\", \"8\", CVAR_ARCHIVE | CVAR_LATCH );\n\tr_depthbits = ri.Cvar_Get( \"r_depthbits\", \"0\", CVAR_ARCHIVE | CVAR_LATCH );\n\tr_overBrightBits = ri.Cvar_Get (\"r_overBrightBits\", \"1\", CVAR_ARCHIVE | CVAR_LATCH );\n\tr_ignorehwgamma = ri.Cvar_Get( \"r_ignorehwgamma\", \"0\", CVAR_ARCHIVE | CVAR_LATCH);\n\tr_mode = ri.Cvar_Get( \"r_mode\", \"3\", CVAR_ARCHIVE | CVAR_LATCH );\n\tr_fullscreen = ri.Cvar_Get( \"r_fullscreen\", \"1\", CVAR_ARCHIVE | CVAR_LATCH );\n\tr_customwidth = ri.Cvar_Get( \"r_customwidth\", \"1600\", CVAR_ARCHIVE | CVAR_LATCH );\n\tr_customheight = ri.Cvar_Get( \"r_customheight\", \"1024\", CVAR_ARCHIVE | CVAR_LATCH );\n\tr_customaspect = ri.Cvar_Get( \"r_customaspect\", \"1\", CVAR_ARCHIVE | CVAR_LATCH );\n\tr_simpleMipMaps = ri.Cvar_Get( \"r_simpleMipMaps\", \"1\", CVAR_ARCHIVE | CVAR_LATCH );\n\tr_vertexLight = ri.Cvar_Get( \"r_vertexLight\", \"0\", CVAR_ARCHIVE | CVAR_LATCH );\n\tr_uiFullScreen = ri.Cvar_Get( \"r_uifullscreen\", \"0\", 0);\n\tr_subdivisions = ri.Cvar_Get (\"r_subdivisions\", \"4\", CVAR_ARCHIVE | CVAR_LATCH);\n\tr_smp = ri.Cvar_Get( \"r_smp\", \"0\", CVAR_ARCHIVE | CVAR_LATCH);\n\n\t//\n\t// temporary latched variables that can only change over a restart\n\t//\n\tr_fullbright = ri.Cvar_Get (\"r_fullbright\", \"0\", CVAR_LATCH|CVAR_CHEAT );\n\tr_mapOverBrightBits = ri.Cvar_Get (\"r_mapOverBrightBits\", \"2\", CVAR_LATCH );\n\tr_intensity = ri.Cvar_Get (\"r_intensity\", \"1\", CVAR_LATCH );\n\tr_singleShader = ri.Cvar_Get (\"r_singleShader\", \"0\", CVAR_CHEAT | CVAR_LATCH );\n\n\t//\n\t// archived variables that can change at any time\n\t//\n\tr_lodCurveError = ri.Cvar_Get( \"r_lodCurveError\", \"250\", CVAR_ARCHIVE|CVAR_CHEAT );\n\tr_lodbias = ri.Cvar_Get( \"r_lodbias\", \"0\", CVAR_ARCHIVE );\n\tr_znear = ri.Cvar_Get( \"r_znear\", \"4\", CVAR_CHEAT );\n\tAssertCvarRange( r_znear, 0.001f, 200, qtrue );\n\tr_ignoreGLErrors = ri.Cvar_Get( \"r_ignoreGLErrors\", \"1\", CVAR_ARCHIVE );\n\tr_fastsky = ri.Cvar_Get( \"r_fastsky\", \"0\", CVAR_ARCHIVE );\n\tr_inGameVideo = ri.Cvar_Get( \"r_inGameVideo\", \"1\", CVAR_ARCHIVE );\n\tr_dynamiclight = ri.Cvar_Get( \"r_dynamiclight\", \"1\", CVAR_ARCHIVE );\n\tr_textureMode = ri.Cvar_Get( \"r_textureMode\", \"GL_LINEAR_MIPMAP_NEAREST\", CVAR_ARCHIVE );\n\tr_swapInterval = ri.Cvar_Get( \"r_swapInterval\", \"0\", CVAR_ARCHIVE );\n\tr_gamma = ri.Cvar_Get( \"r_gamma\", \"1\", CVAR_ARCHIVE );\n\tr_facePlaneCull = ri.Cvar_Get (\"r_facePlaneCull\", \"1\", CVAR_ARCHIVE );\n\n\tr_railWidth = ri.Cvar_Get( \"r_railWidth\", \"16\", CVAR_ARCHIVE );\n\tr_railCoreWidth = ri.Cvar_Get( \"r_railCoreWidth\", \"6\", CVAR_ARCHIVE );\n\tr_railSegmentLength = ri.Cvar_Get( \"r_railSegmentLength\", \"32\", CVAR_ARCHIVE );\n\n\tr_ambientScale = ri.Cvar_Get( \"r_ambientScale\", \"0.6\", CVAR_CHEAT );\n\tr_directedScale = ri.Cvar_Get( \"r_directedScale\", \"1\", CVAR_CHEAT );\n\n\t//\n\t// temporary variables that can change at any time\n\t//\n\tr_showImages = ri.Cvar_Get( \"r_showImages\", \"0\", CVAR_TEMP );\n\n\tr_debugLight = ri.Cvar_Get( \"r_debuglight\", \"0\", CVAR_TEMP );\n\tr_debugSort = ri.Cvar_Get( \"r_debugSort\", \"0\", CVAR_CHEAT );\n\tr_printShaders = ri.Cvar_Get( \"r_printShaders\", \"0\", 0 );\n\tr_saveFontData = ri.Cvar_Get( \"r_saveFontData\", \"0\", 0 );\n\n\tr_nocurves = ri.Cvar_Get (\"r_nocurves\", \"0\", CVAR_CHEAT );\n\tr_drawworld = ri.Cvar_Get (\"r_drawworld\", \"1\", CVAR_CHEAT );\n\tr_lightmap = ri.Cvar_Get (\"r_lightmap\", \"0\", 0 );\n\tr_portalOnly = ri.Cvar_Get (\"r_portalOnly\", \"0\", CVAR_CHEAT );\n\n\tr_showSmp = ri.Cvar_Get (\"r_showSmp\", \"0\", CVAR_CHEAT);\n\tr_skipBackEnd = ri.Cvar_Get (\"r_skipBackEnd\", \"0\", CVAR_CHEAT);\n\n\tr_lodscale = ri.Cvar_Get( \"r_lodscale\", \"5\", CVAR_CHEAT );\n\tr_norefresh = ri.Cvar_Get (\"r_norefresh\", \"0\", CVAR_CHEAT);\n\tr_drawentities = ri.Cvar_Get (\"r_drawentities\", \"1\", CVAR_CHEAT );\n\tr_nocull = ri.Cvar_Get (\"r_nocull\", \"0\", CVAR_CHEAT);\n\tr_novis = ri.Cvar_Get (\"r_novis\", \"0\", CVAR_CHEAT);\n\tr_showcluster = ri.Cvar_Get (\"r_showcluster\", \"0\", CVAR_CHEAT);\n\tr_speeds = ri.Cvar_Get (\"r_speeds\", \"0\", CVAR_CHEAT);\n\tr_verbose = ri.Cvar_Get( \"r_verbose\", \"0\", CVAR_CHEAT );\n\tr_logFile = ri.Cvar_Get( \"r_logFile\", \"0\", CVAR_CHEAT );\n\tr_debugSurface = ri.Cvar_Get (\"r_debugSurface\", \"0\", CVAR_CHEAT);\n\tr_nobind = ri.Cvar_Get (\"r_nobind\", \"0\", CVAR_CHEAT);\n\tr_showtris = ri.Cvar_Get (\"r_showtris\", \"0\", CVAR_CHEAT);\n\tr_showsky = ri.Cvar_Get (\"r_showsky\", \"0\", CVAR_CHEAT);\n\tr_shownormals = ri.Cvar_Get (\"r_shownormals\", \"0\", CVAR_CHEAT);\n\tr_clear = ri.Cvar_Get (\"r_clear\", \"0\", CVAR_CHEAT);\n\tr_offsetFactor = ri.Cvar_Get( \"r_offsetfactor\", \"-1\", CVAR_CHEAT );\n\tr_offsetUnits = ri.Cvar_Get( \"r_offsetunits\", \"-2\", CVAR_CHEAT );\n\tr_drawBuffer = ri.Cvar_Get( \"r_drawBuffer\", \"GL_BACK\", CVAR_CHEAT );\n\tr_lockpvs = ri.Cvar_Get (\"r_lockpvs\", \"0\", CVAR_CHEAT);\n\tr_noportals = ri.Cvar_Get (\"r_noportals\", \"0\", CVAR_CHEAT);\n\tr_shadows = ri.Cvar_Get( \"cg_shadows\", \"1\", 0 );\n\n\tr_maxpolys = ri.Cvar_Get( \"r_maxpolys\", va(\"%d\", MAX_POLYS), 0);\n\tr_maxpolyverts = ri.Cvar_Get( \"r_maxpolyverts\", va(\"%d\", MAX_POLYVERTS), 0);\n\n\t// make sure all the commands added here are also\n\t// removed in R_Shutdown\n\tri.Cmd_AddCommand( \"imagelist\", R_ImageList_f );\n\tri.Cmd_AddCommand( \"shaderlist\", R_ShaderList_f );\n\tri.Cmd_AddCommand( \"skinlist\", R_SkinList_f );\n\tri.Cmd_AddCommand( \"modellist\", R_Modellist_f );\n\tri.Cmd_AddCommand( \"modelist\", R_ModeList_f );\n\tri.Cmd_AddCommand( \"screenshot\", R_ScreenShot_f );\n\tri.Cmd_AddCommand( \"screenshotJPEG\", R_ScreenShotJPEG_f );\n\tri.Cmd_AddCommand( \"gfxinfo\", GfxInfo_f );\n}\n\n/*\n===============\nR_Init\n===============\n*/\nvoid R_Init( void ) {\t\n\tint\terr;\n\tint i;\n\tbyte *ptr;\n\n\tri.Printf( PRINT_ALL, \"----- R_Init -----\\n\" );\n\n\t// clear all our internal state\n\tCom_Memset( &tr, 0, sizeof( tr ) );\n\tCom_Memset( &backEnd, 0, sizeof( backEnd ) );\n\tCom_Memset( &tess, 0, sizeof( tess ) );\n\tCom_Memset( &vk_world, 0, sizeof( vk_world ) );\n\n\tif ( (intptr_t)tess.xyz & 15 ) {\n\t\tCom_Printf( \"WARNING: tess.xyz not 16 byte aligned\\n\" );\n\t}\n\tCom_Memset( tess.constantColor255, 255, sizeof( tess.constantColor255 ) );\n\n\t//\n\t// init function tables\n\t//\n\tfor ( i = 0; i < FUNCTABLE_SIZE; i++ )\n\t{\n\t\ttr.sinTable[i]\t\t= sin( DEG2RAD( i * 360.0f / ( ( float ) ( FUNCTABLE_SIZE - 1 ) ) ) );\n\t\ttr.squareTable[i]\t= ( i < FUNCTABLE_SIZE/2 ) ? 1.0f : -1.0f;\n\t\ttr.sawToothTable[i] = (float)i / FUNCTABLE_SIZE;\n\t\ttr.inverseSawToothTable[i] = 1.0f - tr.sawToothTable[i];\n\n\t\tif ( i < FUNCTABLE_SIZE / 2 )\n\t\t{\n\t\t\tif ( i < FUNCTABLE_SIZE / 4 )\n\t\t\t{\n\t\t\t\ttr.triangleTable[i] = ( float ) i / ( FUNCTABLE_SIZE / 4 );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttr.triangleTable[i] = 1.0f - tr.triangleTable[i-FUNCTABLE_SIZE / 4];\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttr.triangleTable[i] = -tr.triangleTable[i-FUNCTABLE_SIZE/2];\n\t\t}\n\t}\n\n\tR_InitFogTable();\n\n\tR_NoiseInit();\n\n\tR_Register();\n\n\tmax_polys = r_maxpolys->integer;\n\tif (max_polys < MAX_POLYS)\n\t\tmax_polys = MAX_POLYS;\n\n\tmax_polyverts = r_maxpolyverts->integer;\n\tif (max_polyverts < MAX_POLYVERTS)\n\t\tmax_polyverts = MAX_POLYVERTS;\n\n\tptr = (byte*) ri.Hunk_Alloc( sizeof( *backEndData[0] ) + sizeof(srfPoly_t) * max_polys + sizeof(polyVert_t) * max_polyverts, h_low);\n\tbackEndData[0] = (backEndData_t *) ptr;\n\tbackEndData[0]->polys = (srfPoly_t *) ((char *) ptr + sizeof( *backEndData[0] ));\n\tbackEndData[0]->polyVerts = (polyVert_t *) ((char *) ptr + sizeof( *backEndData[0] ) + sizeof(srfPoly_t) * max_polys);\n\tif ( r_smp->integer ) {\n\t\tptr = (byte*) ri.Hunk_Alloc( sizeof( *backEndData[1] ) + sizeof(srfPoly_t) * max_polys + sizeof(polyVert_t) * max_polyverts, h_low);\n\t\tbackEndData[1] = (backEndData_t *) ptr;\n\t\tbackEndData[1]->polys = (srfPoly_t *) ((char *) ptr + sizeof( *backEndData[1] ));\n\t\tbackEndData[1]->polyVerts = (polyVert_t *) ((char *) ptr + sizeof( *backEndData[1] ) + sizeof(srfPoly_t) * max_polys);\n\t} else {\n\t\tbackEndData[1] = NULL;\n\t}\n\tR_ToggleSmpFrame();\n\n\tInitRenderAPI();\n\n\tR_InitImages();\n\n\tR_InitShaders();\n\n\tR_InitSkins();\n\n\tR_ModelInit();\n\n\tR_InitFreeType();\n\n\terr = qglGetError();\n\tif ( err != GL_NO_ERROR )\n\t\tri.Printf (PRINT_ALL, \"glGetError() = 0x%x\\n\", err);\n\n\tri.Printf( PRINT_ALL, \"----- finished R_Init -----\\n\" );\n}\n\n/*\n===============\nRE_Shutdown\n===============\n*/\nvoid RE_Shutdown( qboolean destroyWindow ) {\t\n\n\tri.Printf( PRINT_ALL, \"RE_Shutdown( %i )\\n\", destroyWindow );\n\n\tri.Cmd_RemoveCommand (\"modellist\");\n\tri.Cmd_RemoveCommand (\"screenshotJPEG\");\n\tri.Cmd_RemoveCommand (\"screenshot\");\n\tri.Cmd_RemoveCommand (\"imagelist\");\n\tri.Cmd_RemoveCommand (\"shaderlist\");\n\tri.Cmd_RemoveCommand (\"skinlist\");\n\tri.Cmd_RemoveCommand (\"gfxinfo\");\n\tri.Cmd_RemoveCommand( \"modelist\" );\n\tri.Cmd_RemoveCommand( \"shaderstate\" );\n\n\tif ( tr.registered ) {\n\t\tR_SyncRenderThread();\n\t\tR_ShutdownCommandBuffers();\n\t\tR_DeleteTextures();\n\t}\n\n\tR_DoneFreeType();\n\n\t// shut down platform specific OpenGL stuff\n\tif ( gl_active ) {\n\t\tif (destroyWindow)\n\t\t\tGLimp_Shutdown();\n\t}\n\n\t// VULKAN\n\tif (vk.active) {\n\t\tvk_release_resources();\n\t\tif (destroyWindow) {\n\t\t\tvk_shutdown();\n\t\t\tvk_imp_shutdown();\n\t\t}\n\t}\n\n\t// DX12\n\tif (dx.active) {\n\t\tdx_release_resources();\n\t\tif (destroyWindow) {\n\t\t\tdx_shutdown();\n\t\t\tdx_imp_shutdown();\n\t\t}\n\t}\n\n\ttr.registered = qfalse;\n}\n\n\n/*\n=============\nRE_EndRegistration\n\nTouch all images to make sure they are resident\n=============\n*/\nvoid RE_EndRegistration( void ) {\n\tR_SyncRenderThread();\n\tif (!Sys_LowPhysicalMemory()) {\n\t\tRB_ShowImages();\n\t}\n\n\t// VULKAN\n\tif (vk.active) {\n\t\tri.Printf(PRINT_ALL, \"Vulkan: pipelines create time %d msec\\n\", (int)(vk_world.pipeline_create_time * 1000));\n\t}\n\n\t// DX12\n\tif (dx.active) {\n\t\tri.Printf(PRINT_ALL, \"DX12: pipelines create time %d msec\\n\", (int)(dx_world.pipeline_create_time * 1000));\n\t}\n}\n\n\n/*\n@@@@@@@@@@@@@@@@@@@@@\nGetRefAPI\n\n@@@@@@@@@@@@@@@@@@@@@\n*/\nrefexport_t *GetRefAPI ( int apiVersion, refimport_t *rimp ) {\n\tstatic refexport_t\tre;\n\n\tri = *rimp;\n\n\tCom_Memset( &re, 0, sizeof( re ) );\n\n\tif ( apiVersion != REF_API_VERSION ) {\n\t\tri.Printf(PRINT_ALL, \"Mismatched REF_API_VERSION: expected %i, got %i\\n\", \n\t\t\tREF_API_VERSION, apiVersion );\n\t\treturn NULL;\n\t}\n\n\t// the RE_ functions are Renderer Entry points\n\n\tre.Shutdown = RE_Shutdown;\n\n\tre.BeginRegistration = RE_BeginRegistration;\n\tre.RegisterModel = RE_RegisterModel;\n\tre.RegisterSkin = RE_RegisterSkin;\n\tre.RegisterShader = RE_RegisterShader;\n\tre.RegisterShaderNoMip = RE_RegisterShaderNoMip;\n\tre.LoadWorld = RE_LoadWorldMap;\n\tre.SetWorldVisData = RE_SetWorldVisData;\n\tre.EndRegistration = RE_EndRegistration;\n\n\tre.BeginFrame = RE_BeginFrame;\n\tre.EndFrame = RE_EndFrame;\n\n\tre.MarkFragments = R_MarkFragments;\n\tre.LerpTag = R_LerpTag;\n\tre.ModelBounds = R_ModelBounds;\n\n\tre.ClearScene = RE_ClearScene;\n\tre.AddRefEntityToScene = RE_AddRefEntityToScene;\n\tre.AddPolyToScene = RE_AddPolyToScene;\n\tre.LightForPoint = R_LightForPoint;\n\tre.AddLightToScene = RE_AddLightToScene;\n\tre.AddAdditiveLightToScene = RE_AddAdditiveLightToScene;\n\tre.RenderScene = RE_RenderScene;\n\n\tre.SetColor = RE_SetColor;\n\tre.DrawStretchPic = RE_StretchPic;\n\tre.DrawStretchRaw = RE_StretchRaw;\n\tre.UploadCinematic = RE_UploadCinematic;\n\n\tre.RegisterFont = RE_RegisterFont;\n\tre.RemapShader = R_RemapShader;\n\tre.GetEntityToken = R_GetEntityToken;\n\tre.inPVS = R_inPVS;\n\n\treturn &re;\n}\n"
  },
  {
    "path": "src/engine/renderer/tr_light.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n// tr_light.c\n\n#include \"tr_local.h\"\n\n#define\tDLIGHT_AT_RADIUS\t\t16\n// at the edge of a dlight's influence, this amount of light will be added\n\n#define\tDLIGHT_MINIMUM_RADIUS\t16\t\t\n// never calculate a range less than this to prevent huge light numbers\n\n\n/*\n===============\nR_TransformDlights\n\nTransforms the origins of an array of dlights.\nUsed by both the front end (for DlightBmodel) and\nthe back end (before doing the lighting calculation)\n===============\n*/\nvoid R_TransformDlights( int count, dlight_t *dl, orientationr_t *or) {\n\tint\t\ti;\n\tvec3_t\ttemp;\n\n\tfor ( i = 0 ; i < count ; i++, dl++ ) {\n\t\tVectorSubtract( dl->origin, or->origin, temp );\n\t\tdl->transformed[0] = DotProduct( temp, or->axis[0] );\n\t\tdl->transformed[1] = DotProduct( temp, or->axis[1] );\n\t\tdl->transformed[2] = DotProduct( temp, or->axis[2] );\n\t}\n}\n\n/*\n=============\nR_DlightBmodel\n\nDetermine which dynamic lights may effect this bmodel\n=============\n*/\nvoid R_DlightBmodel( bmodel_t *bmodel ) {\n\tint\t\t\ti, j;\n\tdlight_t\t*dl;\n\tint\t\t\tmask;\n\tmsurface_t\t*surf;\n\n\t// transform all the lights\n\tR_TransformDlights( tr.refdef.num_dlights, tr.refdef.dlights, &tr.or );\n\n\tmask = 0;\n\tfor ( i=0 ; i<tr.refdef.num_dlights ; i++ ) {\n\t\tdl = &tr.refdef.dlights[i];\n\n\t\t// see if the point is close enough to the bounds to matter\n\t\tfor ( j = 0 ; j < 3 ; j++ ) {\n\t\t\tif ( dl->transformed[j] - bmodel->bounds[1][j] > dl->radius ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( bmodel->bounds[0][j] - dl->transformed[j] > dl->radius ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif ( j < 3 ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// we need to check this light\n\t\tmask |= 1 << i;\n\t}\n\n\ttr.currentEntity->needDlights = (qboolean) (mask != 0);\n\n\t// set the dlight bits in all the surfaces\n\tfor ( i = 0 ; i < bmodel->numSurfaces ; i++ ) {\n\t\tsurf = bmodel->firstSurface + i;\n\n\t\tif ( *surf->data == SF_FACE ) {\n\t\t\t((srfSurfaceFace_t *)surf->data)->dlightBits[ tr.smpFrame ] = mask;\n\t\t} else if ( *surf->data == SF_GRID ) {\n\t\t\t((srfGridMesh_t *)surf->data)->dlightBits[ tr.smpFrame ] = mask;\n\t\t} else if ( *surf->data == SF_TRIANGLES ) {\n\t\t\t((srfTriangles_t *)surf->data)->dlightBits[ tr.smpFrame ] = mask;\n\t\t}\n\t}\n}\n\n\n/*\n=============================================================================\n\nLIGHT SAMPLING\n\n=============================================================================\n*/\n\nextern\tcvar_t\t*r_ambientScale;\nextern\tcvar_t\t*r_directedScale;\nextern\tcvar_t\t*r_debugLight;\n\n/*\n=================\nR_SetupEntityLightingGrid\n\n=================\n*/\nstatic void R_SetupEntityLightingGrid( trRefEntity_t *ent ) {\n\tvec3_t\tlightOrigin;\n\tint\t\tpos[3];\n\tint\t\ti, j;\n\tbyte\t*gridData;\n\tfloat\tfrac[3];\n\tint\t\tgridStep[3];\n\tvec3_t\tdirection;\n\tfloat\ttotalFactor;\n\n\tif ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) {\n\t\t// seperate lightOrigins are needed so an object that is\n\t\t// sinking into the ground can still be lit, and so\n\t\t// multi-part models can be lit identically\n\t\tVectorCopy( ent->e.lightingOrigin, lightOrigin );\n\t} else {\n\t\tVectorCopy( ent->e.origin, lightOrigin );\n\t}\n\n\tVectorSubtract( lightOrigin, tr.world->lightGridOrigin, lightOrigin );\n\tfor ( i = 0 ; i < 3 ; i++ ) {\n\t\tfloat\tv;\n\n\t\tv = lightOrigin[i]*tr.world->lightGridInverseSize[i];\n\t\tpos[i] = floor( v );\n\t\tfrac[i] = v - pos[i];\n\t\tif ( pos[i] < 0 ) {\n\t\t\tpos[i] = 0;\n\t\t} else if ( pos[i] >= tr.world->lightGridBounds[i] - 1 ) {\n\t\t\tpos[i] = tr.world->lightGridBounds[i] - 1;\n\t\t}\n\t}\n\n\tVectorClear( ent->ambientLight );\n\tVectorClear( ent->directedLight );\n\tVectorClear( direction );\n\n\tassert( tr.world->lightGridData ); // bk010103 - NULL with -nolight maps\n\n\t// trilerp the light value\n\tgridStep[0] = 8;\n\tgridStep[1] = 8 * tr.world->lightGridBounds[0];\n\tgridStep[2] = 8 * tr.world->lightGridBounds[0] * tr.world->lightGridBounds[1];\n\tgridData = tr.world->lightGridData + pos[0] * gridStep[0]\n\t\t+ pos[1] * gridStep[1] + pos[2] * gridStep[2];\n\n\ttotalFactor = 0;\n\tfor ( i = 0 ; i < 8 ; i++ ) {\n\t\tfloat\tfactor;\n\t\tbyte\t*data;\n\t\tint\t\tlat, lng;\n\t\tvec3_t\tnormal;\n\t\t#if idppc\n\t\tfloat d0, d1, d2, d3, d4, d5;\n\t\t#endif\n\t\tfactor = 1.0;\n\t\tdata = gridData;\n\t\tfor ( j = 0 ; j < 3 ; j++ ) {\n\t\t\tif ( i & (1<<j) ) {\n\t\t\t\tfactor *= frac[j];\n\t\t\t\tdata += gridStep[j];\n\t\t\t} else {\n\t\t\t\tfactor *= (1.0f - frac[j]);\n\t\t\t}\n\t\t}\n\n\t\tif ( !(data[0]+data[1]+data[2]) ) {\n\t\t\tcontinue;\t// ignore samples in walls\n\t\t}\n\t\ttotalFactor += factor;\n\t\t#if idppc\n\t\td0 = data[0]; d1 = data[1]; d2 = data[2];\n\t\td3 = data[3]; d4 = data[4]; d5 = data[5];\n\n\t\tent->ambientLight[0] += factor * d0;\n\t\tent->ambientLight[1] += factor * d1;\n\t\tent->ambientLight[2] += factor * d2;\n\n\t\tent->directedLight[0] += factor * d3;\n\t\tent->directedLight[1] += factor * d4;\n\t\tent->directedLight[2] += factor * d5;\n\t\t#else\n\t\tent->ambientLight[0] += factor * data[0];\n\t\tent->ambientLight[1] += factor * data[1];\n\t\tent->ambientLight[2] += factor * data[2];\n\n\t\tent->directedLight[0] += factor * data[3];\n\t\tent->directedLight[1] += factor * data[4];\n\t\tent->directedLight[2] += factor * data[5];\n\t\t#endif\n\t\tlat = data[7];\n\t\tlng = data[6];\n\t\tlat *= (FUNCTABLE_SIZE/256);\n\t\tlng *= (FUNCTABLE_SIZE/256);\n\n\t\t// decode X as cos( lat ) * sin( long )\n\t\t// decode Y as sin( lat ) * sin( long )\n\t\t// decode Z as cos( long )\n\n\t\tnormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];\n\t\tnormal[1] = tr.sinTable[lat] * tr.sinTable[lng];\n\t\tnormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];\n\n\t\tVectorMA( direction, factor, normal, direction );\n\t}\n\n\tif ( totalFactor > 0 && totalFactor < 0.99 ) {\n\t\ttotalFactor = 1.0f / totalFactor;\n\t\tVectorScale( ent->ambientLight, totalFactor, ent->ambientLight );\n\t\tVectorScale( ent->directedLight, totalFactor, ent->directedLight );\n\t}\n\n\tVectorScale( ent->ambientLight, r_ambientScale->value, ent->ambientLight );\n\tVectorScale( ent->directedLight, r_directedScale->value, ent->directedLight );\n\n\tVectorNormalize2( direction, ent->lightDir );\n}\n\n\n/*\n===============\nLogLight\n===============\n*/\nstatic void LogLight( trRefEntity_t *ent ) {\n\tint\tmax1, max2;\n\n\tif ( !(ent->e.renderfx & RF_FIRST_PERSON ) ) {\n\t\treturn;\n\t}\n\n\tmax1 = ent->ambientLight[0];\n\tif ( ent->ambientLight[1] > max1 ) {\n\t\tmax1 = ent->ambientLight[1];\n\t} else if ( ent->ambientLight[2] > max1 ) {\n\t\tmax1 = ent->ambientLight[2];\n\t}\n\n\tmax2 = ent->directedLight[0];\n\tif ( ent->directedLight[1] > max2 ) {\n\t\tmax2 = ent->directedLight[1];\n\t} else if ( ent->directedLight[2] > max2 ) {\n\t\tmax2 = ent->directedLight[2];\n\t}\n\n\tri.Printf( PRINT_ALL, \"amb:%i  dir:%i\\n\", max1, max2 );\n}\n\n/*\n=================\nR_SetupEntityLighting\n\nCalculates all the lighting values that will be used\nby the Calc_* functions\n=================\n*/\nvoid R_SetupEntityLighting( const trRefdef_t *refdef, trRefEntity_t *ent ) {\n\tint\t\t\t\ti;\n\tdlight_t\t\t*dl;\n\tfloat\t\t\tpower;\n\tvec3_t\t\t\tdir;\n\tfloat\t\t\td;\n\tvec3_t\t\t\tlightDir;\n\tvec3_t\t\t\tlightOrigin;\n\n\t// lighting calculations \n\tif ( ent->lightingCalculated ) {\n\t\treturn;\n\t}\n\tent->lightingCalculated = qtrue;\n\n\t//\n\t// trace a sample point down to find ambient light\n\t//\n\tif ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) {\n\t\t// seperate lightOrigins are needed so an object that is\n\t\t// sinking into the ground can still be lit, and so\n\t\t// multi-part models can be lit identically\n\t\tVectorCopy( ent->e.lightingOrigin, lightOrigin );\n\t} else {\n\t\tVectorCopy( ent->e.origin, lightOrigin );\n\t}\n\n\t// if NOWORLDMODEL, only use dynamic lights (menu system, etc)\n\tif ( !(refdef->rdflags & RDF_NOWORLDMODEL ) \n\t\t&& tr.world->lightGridData ) {\n\t\tR_SetupEntityLightingGrid( ent );\n\t} else {\n\t\tent->ambientLight[0] = ent->ambientLight[1] = \n\t\t\tent->ambientLight[2] = tr.identityLight * 150;\n\t\tent->directedLight[0] = ent->directedLight[1] = \n\t\t\tent->directedLight[2] = tr.identityLight * 150;\n\t\tVectorCopy( tr.sunDirection, ent->lightDir );\n\t}\n\n\t// bonus items and view weapons have a fixed minimum add\n\tif ( 1 /* ent->e.renderfx & RF_MINLIGHT */ ) {\n\t\t// give everything a minimum light add\n\t\tent->ambientLight[0] += tr.identityLight * 32;\n\t\tent->ambientLight[1] += tr.identityLight * 32;\n\t\tent->ambientLight[2] += tr.identityLight * 32;\n\t}\n\n\t//\n\t// modify the light by dynamic lights\n\t//\n\td = VectorLength( ent->directedLight );\n\tVectorScale( ent->lightDir, d, lightDir );\n\n\tfor ( i = 0 ; i < refdef->num_dlights ; i++ ) {\n\t\tdl = &refdef->dlights[i];\n\t\tVectorSubtract( dl->origin, lightOrigin, dir );\n\t\td = VectorNormalize( dir );\n\n\t\tpower = DLIGHT_AT_RADIUS * ( dl->radius * dl->radius );\n\t\tif ( d < DLIGHT_MINIMUM_RADIUS ) {\n\t\t\td = DLIGHT_MINIMUM_RADIUS;\n\t\t}\n\t\td = power / ( d * d );\n\n\t\tVectorMA( ent->directedLight, d, dl->color, ent->directedLight );\n\t\tVectorMA( lightDir, d, dir, lightDir );\n\t}\n\n\t// clamp ambient\n\tfor ( i = 0 ; i < 3 ; i++ ) {\n\t\tif ( ent->ambientLight[i] > tr.identityLightByte ) {\n\t\t\tent->ambientLight[i] = tr.identityLightByte;\n\t\t}\n\t}\n\n\tif ( r_debugLight->integer ) {\n\t\tLogLight( ent );\n\t}\n\n\t// save out the byte packet version\n\t((byte *)&ent->ambientLightInt)[0] = myftol( ent->ambientLight[0] );\n\t((byte *)&ent->ambientLightInt)[1] = myftol( ent->ambientLight[1] );\n\t((byte *)&ent->ambientLightInt)[2] = myftol( ent->ambientLight[2] );\n\t((byte *)&ent->ambientLightInt)[3] = 0xff;\n\t\n\t// transform the direction to local space\n\tVectorNormalize( lightDir );\n\tent->lightDir[0] = DotProduct( lightDir, ent->e.axis[0] );\n\tent->lightDir[1] = DotProduct( lightDir, ent->e.axis[1] );\n\tent->lightDir[2] = DotProduct( lightDir, ent->e.axis[2] );\n}\n\n/*\n=================\nR_LightForPoint\n=================\n*/\nint R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir )\n{\n\ttrRefEntity_t ent;\n\t\n\t// bk010103 - this segfaults with -nolight maps\n\tif ( tr.world->lightGridData == NULL )\n\t  return qfalse;\n\n\tCom_Memset(&ent, 0, sizeof(ent));\n\tVectorCopy( point, ent.e.origin );\n\tR_SetupEntityLightingGrid( &ent );\n\tVectorCopy(ent.ambientLight, ambientLight);\n\tVectorCopy(ent.directedLight, directedLight);\n\tVectorCopy(ent.lightDir, lightDir);\n\n\treturn qtrue;\n}\n"
  },
  {
    "path": "src/engine/renderer/tr_local.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n\n#ifndef TR_LOCAL_H\n#define TR_LOCAL_H\n\n#include \"../../game/q_shared.h\"\n#include \"../qcommon/qfiles.h\"\n#include \"../qcommon/qcommon.h\"\n#include \"tr_public.h\"\n\n#include \"qgl.h\"\n\n// VULKAN\n#include \"vk.h\"\n\n// DX12\n#include \"dx.h\"\n\n#define GL_INDEX_TYPE\t\tGL_UNSIGNED_INT\ntypedef unsigned int glIndex_t;\n\n// fast float to int conversion\n#if id386 && !( (defined __linux__ || defined __FreeBSD__ ) && (defined __i386__ ) ) // rb010123\nlong myftol( float f );\n#else\n#define\tmyftol(x) ((int)(x))\n#endif\n\n\n// everything that is needed by the backend needs\n// to be double buffered to allow it to run in\n// parallel on a dual cpu machine\n#define\tSMP_FRAMES\t\t2\n\n// 12 bits\n// see QSORT_SHADERNUM_SHIFT\n#define\tMAX_SHADERS\t\t\t\t16384\n\n// can't be increased without changing bit packing for drawsurfs\n\ntypedef struct dlight_s {\n\tvec3_t\torigin;\n\tvec3_t\tcolor;\t\t\t\t// range from 0.0 to 1.0, should be color normalized\n\tfloat\tradius;\n\n\tvec3_t\ttransformed;\t\t// origin in local coordinate system\n\tint\t\tadditive;\t\t\t// texture detail is lost tho when the lightmap is dark\n} dlight_t;\n\n\n// a trRefEntity_t has all the information passed in by\n// the client game, as well as some locally derived info\ntypedef struct {\n\trefEntity_t\te;\n\n\tfloat\t\taxisLength;\t\t// compensate for non-normalized axis\n\n\tqboolean\tneedDlights;\t// true for bmodels that touch a dlight\n\tqboolean\tlightingCalculated;\n\tvec3_t\t\tlightDir;\t\t// normalized direction towards light\n\tvec3_t\t\tambientLight;\t// color normalized to 0-255\n\tint\t\t\tambientLightInt;\t// 32 bit rgba packed\n\tvec3_t\t\tdirectedLight;\n} trRefEntity_t;\n\n\ntypedef struct {\n\tvec3_t\t\torigin;\t\t\t// in world coordinates\n\tvec3_t\t\taxis[3];\t\t// orientation in world\n\tvec3_t\t\tviewOrigin;\t\t// viewParms->or.origin in local coordinates\n\tfloat\t\tmodelMatrix[16];\n} orientationr_t;\n\ntypedef struct image_s {\n\tchar\t\timgName[MAX_QPATH];\t\t// game path, including extension\n\tint\t\t\twidth, height;\t\t\t\t// source image\n\tint\t\t\tuploadWidth, uploadHeight;\t// after power of two and picmip but not including clamp to MAX_TEXTURE_SIZE\n\tGLuint\t\ttexnum;\t\t\t\t\t// gl texture binding\n\n\tint\t\t\tframeUsed;\t\t\t// for texture usage in frame statistics\n\n\tint\t\t\tinternalFormat;\n\n\tqboolean\tmipmap;\n\tqboolean\tallowPicmip;\n\tint\t\t\twrapClampMode;\t\t// GL_CLAMP or GL_REPEAT\n\n    int         index; // this image == tr.images[index]\n\n\tstruct image_s*\tnext;\n} image_t;\n\n//===============================================================================\n\ntypedef enum {\n\tSS_BAD,\n\tSS_PORTAL,\t\t\t// mirrors, portals, viewscreens\n\tSS_ENVIRONMENT,\t\t// sky box\n\tSS_OPAQUE,\t\t\t// opaque\n\n\tSS_DECAL,\t\t\t// scorch marks, etc.\n\tSS_SEE_THROUGH,\t\t// ladders, grates, grills that may have small blended edges\n\t\t\t\t\t\t// in addition to alpha test\n\tSS_BANNER,\n\n\tSS_FOG,\n\n\tSS_UNDERWATER,\t\t// for items that should be drawn in front of the water plane\n\n\tSS_BLEND0,\t\t\t// regular transparency and filters\n\tSS_BLEND1,\t\t\t// generally only used for additive type effects\n\tSS_BLEND2,\n\tSS_BLEND3,\n\n\tSS_BLEND6,\n\tSS_STENCIL_SHADOW,\n\tSS_ALMOST_NEAREST,\t// gun smoke puffs\n\n\tSS_NEAREST\t\t\t// blood blobs\n} shaderSort_t;\n\n\n#define MAX_SHADER_STAGES 8\n\ntypedef enum {\n\tGF_NONE,\n\n\tGF_SIN,\n\tGF_SQUARE,\n\tGF_TRIANGLE,\n\tGF_SAWTOOTH, \n\tGF_INVERSE_SAWTOOTH, \n\n\tGF_NOISE\n\n} genFunc_t;\n\n\ntypedef enum {\n\tDEFORM_NONE,\n\tDEFORM_WAVE,\n\tDEFORM_NORMALS,\n\tDEFORM_BULGE,\n\tDEFORM_MOVE,\n\tDEFORM_PROJECTION_SHADOW,\n\tDEFORM_AUTOSPRITE,\n\tDEFORM_AUTOSPRITE2,\n\tDEFORM_TEXT0,\n\tDEFORM_TEXT1,\n\tDEFORM_TEXT2,\n\tDEFORM_TEXT3,\n\tDEFORM_TEXT4,\n\tDEFORM_TEXT5,\n\tDEFORM_TEXT6,\n\tDEFORM_TEXT7\n} deform_t;\n\ntypedef enum {\n\tAGEN_IDENTITY,\n\tAGEN_SKIP,\n\tAGEN_ENTITY,\n\tAGEN_ONE_MINUS_ENTITY,\n\tAGEN_VERTEX,\n\tAGEN_ONE_MINUS_VERTEX,\n\tAGEN_LIGHTING_SPECULAR,\n\tAGEN_WAVEFORM,\n\tAGEN_PORTAL,\n\tAGEN_CONST\n} alphaGen_t;\n\ntypedef enum {\n\tCGEN_BAD,\n\tCGEN_IDENTITY_LIGHTING,\t// tr.identityLight\n\tCGEN_IDENTITY,\t\t\t// always (1,1,1,1)\n\tCGEN_ENTITY,\t\t\t// grabbed from entity's modulate field\n\tCGEN_ONE_MINUS_ENTITY,\t// grabbed from 1 - entity.modulate\n\tCGEN_EXACT_VERTEX,\t\t// tess.vertexColors\n\tCGEN_VERTEX,\t\t\t// tess.vertexColors * tr.identityLight\n\tCGEN_ONE_MINUS_VERTEX,\n\tCGEN_WAVEFORM,\t\t\t// programmatically generated\n\tCGEN_LIGHTING_DIFFUSE,\n\tCGEN_FOG,\t\t\t\t// standard fog\n\tCGEN_CONST\t\t\t\t// fixed color\n} colorGen_t;\n\ntypedef enum {\n\tTCGEN_BAD,\n\tTCGEN_IDENTITY,\t\t\t// clear to 0,0\n\tTCGEN_LIGHTMAP,\n\tTCGEN_TEXTURE,\n\tTCGEN_ENVIRONMENT_MAPPED,\n\tTCGEN_FOG,\n\tTCGEN_VECTOR\t\t\t// S and T from world coordinates\n} texCoordGen_t;\n\ntypedef enum {\n\tACFF_NONE,\n\tACFF_MODULATE_RGB,\n\tACFF_MODULATE_RGBA,\n\tACFF_MODULATE_ALPHA\n} acff_t;\n\ntypedef struct {\n\tgenFunc_t\tfunc;\n\n\tfloat base;\n\tfloat amplitude;\n\tfloat phase;\n\tfloat frequency;\n} waveForm_t;\n\n#define TR_MAX_TEXMODS 4\n\ntypedef enum {\n\tTMOD_NONE,\n\tTMOD_TRANSFORM,\n\tTMOD_TURBULENT,\n\tTMOD_SCROLL,\n\tTMOD_SCALE,\n\tTMOD_STRETCH,\n\tTMOD_ROTATE,\n\tTMOD_ENTITY_TRANSLATE\n} texMod_t;\n\n#define\tMAX_SHADER_DEFORMS\t3\ntypedef struct {\n\tdeform_t\tdeformation;\t\t\t// vertex coordinate modification type\n\n\tvec3_t\t\tmoveVector;\n\twaveForm_t\tdeformationWave;\n\tfloat\t\tdeformationSpread;\n\n\tfloat\t\tbulgeWidth;\n\tfloat\t\tbulgeHeight;\n\tfloat\t\tbulgeSpeed;\n} deformStage_t;\n\n\ntypedef struct {\n\ttexMod_t\t\ttype;\n\n\t// used for TMOD_TURBULENT and TMOD_STRETCH\n\twaveForm_t\t\twave;\n\n\t// used for TMOD_TRANSFORM\n\tfloat\t\t\tmatrix[2][2];\t\t// s' = s * m[0][0] + t * m[1][0] + trans[0]\n\tfloat\t\t\ttranslate[2];\t\t// t' = s * m[0][1] + t * m[0][1] + trans[1]\n\n\t// used for TMOD_SCALE\n\tfloat\t\t\tscale[2];\t\t\t// s *= scale[0]\n\t                                    // t *= scale[1]\n\n\t// used for TMOD_SCROLL\n\tfloat\t\t\tscroll[2];\t\t\t// s' = s + scroll[0] * time\n\t\t\t\t\t\t\t\t\t\t// t' = t + scroll[1] * time\n\n\t// + = clockwise\n\t// - = counterclockwise\n\tfloat\t\t\trotateSpeed;\n\n} texModInfo_t;\n\n\n#define\tMAX_IMAGE_ANIMATIONS\t8\n\ntypedef struct {\n\timage_t\t\t\t*image[MAX_IMAGE_ANIMATIONS];\n\tint\t\t\t\tnumImageAnimations;\n\tfloat\t\t\timageAnimationSpeed;\n\n\ttexCoordGen_t\ttcGen;\n\tvec3_t\t\t\ttcGenVectors[2];\n\n\tint\t\t\t\tnumTexMods;\n\ttexModInfo_t\t*texMods;\n\n\tint\t\t\t\tvideoMapHandle;\n\tqboolean\t\tisLightmap;\n\tqboolean\t\tisVideoMap;\n} textureBundle_t;\n\n#define NUM_TEXTURE_BUNDLES 2\n\ntypedef struct {\n\tqboolean\t\tactive;\n\t\n\ttextureBundle_t\tbundle[NUM_TEXTURE_BUNDLES];\n\n\twaveForm_t\t\trgbWave;\n\tcolorGen_t\t\trgbGen;\n\n\twaveForm_t\t\talphaWave;\n\talphaGen_t\t\talphaGen;\n\n\tbyte\t\t\tconstantColor[4];\t\t\t// for CGEN_CONST and AGEN_CONST\n\n\tunsigned\t\tstateBits;\t\t\t\t\t// GLS_xxxx mask\n\n\tacff_t\t\t\tadjustColorsForFog;\n\n\tqboolean\t\tisDetail;\n\n\t// VULKAN\n\tVkPipeline\t\tvk_pipeline;\n\tVkPipeline\t\tvk_portal_pipeline;\n\tVkPipeline\t\tvk_mirror_pipeline;\n\n\t// DX12\n\tID3D12PipelineState* dx_pipeline;\n\tID3D12PipelineState* dx_portal_pipeline;\n\tID3D12PipelineState* dx_mirror_pipeline;\n\t\n} shaderStage_t;\n\nstruct shaderCommands_s;\n\n#define LIGHTMAP_2D\t\t\t-4\t\t// shader is for 2D rendering\n#define LIGHTMAP_BY_VERTEX\t-3\t\t// pre-lit triangle models\n#define LIGHTMAP_WHITEIMAGE\t-2\n#define\tLIGHTMAP_NONE\t\t-1\n\ntypedef enum {\n\tCT_FRONT_SIDED,\n\tCT_BACK_SIDED,\n\tCT_TWO_SIDED\n} cullType_t;\n\ntypedef enum {\n\tFP_NONE,\t\t// surface is translucent and will just be adjusted properly\n\tFP_EQUAL,\t\t// surface is opaque but possibly alpha tested\n\tFP_LE\t\t\t// surface is trnaslucent, but still needs a fog pass (fog surface)\n} fogPass_t;\n\ntypedef struct {\n\tfloat\t\tcloudHeight;\n\timage_t\t\t*outerbox[6], *innerbox[6];\n} skyParms_t;\n\ntypedef struct {\n\tvec3_t\tcolor;\n\tfloat\tdepthForOpaque;\n} fogParms_t;\n\n\ntypedef struct shader_s {\n\tchar\t\tname[MAX_QPATH];\t\t// game path, including extension\n\tint\t\t\tlightmapIndex;\t\t\t// for a shader to match, both name and lightmapIndex must match\n\n\tint\t\t\tindex;\t\t\t\t\t// this shader == tr.shaders[index]\n\tint\t\t\tsortedIndex;\t\t\t// this shader == tr.sortedShaders[sortedIndex]\n\n\tfloat\t\tsort;\t\t\t\t\t// lower numbered shaders draw before higher numbered\n\n\tqboolean\tdefaultShader;\t\t\t// we want to return index 0 if the shader failed to\n\t\t\t\t\t\t\t\t\t\t// load for some reason, but R_FindShader should\n\t\t\t\t\t\t\t\t\t\t// still keep a name allocated for it, so if\n\t\t\t\t\t\t\t\t\t\t// something calls RE_RegisterShader again with\n\t\t\t\t\t\t\t\t\t\t// the same name, we don't try looking for it again\n\n\tqboolean\texplicitlyDefined;\t\t// found in a .shader file\n\n\tint\t\t\tsurfaceFlags;\t\t\t// if explicitlyDefined, this will have SURF_* flags\n\tint\t\t\tcontentFlags;\n\n\tqboolean\tentityMergable;\t\t\t// merge across entites optimizable (smoke, blood)\n\n\tqboolean\tisSky;\n\tskyParms_t\tsky;\n\tfogParms_t\tfogParms;\n\n\tfloat\t\tportalRange;\t\t\t// distance to fog out at\n\n\tint\t\t\tmultitextureEnv;\t\t// 0, GL_MODULATE, GL_ADD (FIXME: put in stage)\n\n\tcullType_t\tcullType;\t\t\t\t// CT_FRONT_SIDED, CT_BACK_SIDED, or CT_TWO_SIDED\n\tqboolean\tpolygonOffset;\t\t\t// set for decals and other items that must be offset \n\tqboolean\tnoMipMaps;\t\t\t\t// for console fonts, 2D elements, etc.\n\tqboolean\tnoPicMip;\t\t\t\t// for images that must always be full resolution\n\n\tfogPass_t\tfogPass;\t\t\t\t// draw a blended pass, possibly with depth test equals\n\n\tqboolean\tneedsNormal;\t\t\t// not all shaders will need all data to be gathered\n\tqboolean\tneedsST1;\n\tqboolean\tneedsST2;\n\tqboolean\tneedsColor;\n\n\tint\t\t\tnumDeforms;\n\tdeformStage_t\tdeforms[MAX_SHADER_DEFORMS];\n\n\tint\t\t\tnumUnfoggedPasses;\n\tshaderStage_t\t*stages[MAX_SHADER_STAGES];\t\t\n\n    float clampTime;                                  // time this shader is clamped to\n    float timeOffset;                                 // current time offset for this shader\n\n    struct shader_s *remappedShader;                  // current shader this one is remapped too\n\n\tstruct\tshader_s\t*next;\n} shader_t;\n\n// trRefdef_t holds everything that comes in refdef_t,\n// as well as the locally generated scene information\ntypedef struct {\n\tint\t\t\tx, y, width, height;\n\tfloat\t\tfov_x, fov_y;\n\tvec3_t\t\tvieworg;\n\tvec3_t\t\tviewaxis[3];\t\t// transformation matrix\n\n\tint\t\t\ttime;\t\t\t\t// time in milliseconds for shader effects and other time dependent rendering issues\n\tint\t\t\trdflags;\t\t\t// RDF_NOWORLDMODEL, etc\n\n\t// 1 bits will prevent the associated area from rendering at all\n\tbyte\t\tareamask[MAX_MAP_AREA_BYTES];\n\tqboolean\tareamaskModified;\t// qtrue if areamask changed since last scene\n\n\tfloat\t\tfloatTime;\t\t\t// tr.refdef.time / 1000.0\n\n\t// text messages for deform text shaders\n\tchar\t\ttext[MAX_RENDER_STRINGS][MAX_RENDER_STRING_LENGTH];\n\n\tint\t\t\tnum_entities;\n\ttrRefEntity_t\t*entities;\n\n\tint\t\t\tnum_dlights;\n\tstruct dlight_s\t*dlights;\n\n\tint\t\t\tnumPolys;\n\tstruct srfPoly_s\t*polys;\n\n\tint\t\t\tnumDrawSurfs;\n\tstruct drawSurf_s\t*drawSurfs;\n\n\n} trRefdef_t;\n\n\n//=================================================================================\n\n// skins allow models to be retextured without modifying the model file\ntypedef struct {\n\tchar\t\tname[MAX_QPATH];\n\tshader_t\t*shader;\n} skinSurface_t;\n\ntypedef struct skin_s {\n\tchar\t\tname[MAX_QPATH];\t\t// game path, including extension\n\tint\t\t\tnumSurfaces;\n\tskinSurface_t\t*surfaces[MD3_MAX_SURFACES];\n} skin_t;\n\n\ntypedef struct {\n\tint\t\t\toriginalBrushNumber;\n\tvec3_t\t\tbounds[2];\n\n\tunsigned\tcolorInt;\t\t\t\t// in packed byte format\n\tfloat\t\ttcScale;\t\t\t\t// texture coordinate vector scales\n\tfogParms_t\tparms;\n\n\t// for clipping distance in fog when outside\n\tqboolean\thasSurface;\n\tfloat\t\tsurface[4];\n} fog_t;\n\ntypedef struct {\n\torientationr_t\tor;\n\torientationr_t\tworld;\n\tvec3_t\t\tpvsOrigin;\t\t\t// may be different than or.origin for portals\n\tqboolean\tisPortal;\t\t\t// true if this view is through a portal\n\tqboolean\tisMirror;\t\t\t// the portal is a mirror, invert the face culling\n\tint\t\t\tframeCount;\t\t\t// copied from tr.frameCount\n\tcplane_t\tportalPlane;\t\t// clip anything behind this if mirroring\n\tint\t\t\tviewportX, viewportY, viewportWidth, viewportHeight;\n\tfloat\t\tfovX, fovY;\n\tfloat\t\tprojectionMatrix[16];\n\tcplane_t\tfrustum[4];\n\tvec3_t\t\tvisBounds[2];\n\tfloat\t\tzFar;\n} viewParms_t;\n\n\n/*\n==============================================================================\n\nSURFACES\n\n==============================================================================\n*/\n\n// any changes in surfaceType must be mirrored in rb_surfaceTable[]\ntypedef enum {\n\tSF_BAD,\n\tSF_SKIP,\t\t\t\t// ignore\n\tSF_FACE,\n\tSF_GRID,\n\tSF_TRIANGLES,\n\tSF_POLY,\n\tSF_MD3,\n\tSF_MD4,\n\tSF_FLARE,\n\tSF_ENTITY,\t\t\t\t// beams, rails, lightning, etc that can be determined by entity\n\n\tSF_NUM_SURFACE_TYPES,\n\tSF_MAX = 0x7fffffff\t\t\t// ensures that sizeof( surfaceType_t ) == sizeof( int )\n} surfaceType_t;\n\ntypedef struct drawSurf_s {\n\tunsigned\t\t\tsort;\t\t\t// bit combination for fast compares\n\tsurfaceType_t\t\t*surface;\t\t// any of surface*_t\n} drawSurf_t;\n\n#define\tMAX_FACE_POINTS\t\t64\n\n#define\tMAX_PATCH_SIZE\t\t32\t\t\t// max dimensions of a patch mesh in map file\n#define\tMAX_GRID_SIZE\t\t65\t\t\t// max dimensions of a grid mesh in memory\n\n// when cgame directly specifies a polygon, it becomes a srfPoly_t\n// as soon as it is called\ntypedef struct srfPoly_s {\n\tsurfaceType_t\tsurfaceType;\n\tqhandle_t\t\thShader;\n\tint\t\t\t\tfogIndex;\n\tint\t\t\t\tnumVerts;\n\tpolyVert_t\t\t*verts;\n} srfPoly_t;\n\ntypedef struct srfFlare_s {\n\tsurfaceType_t\tsurfaceType;\n\tvec3_t\t\t\torigin;\n\tvec3_t\t\t\tnormal;\n\tvec3_t\t\t\tcolor;\n} srfFlare_t;\n\ntypedef struct srfGridMesh_s {\n\tsurfaceType_t\tsurfaceType;\n\n\t// dynamic lighting information\n\tint\t\t\t\tdlightBits[SMP_FRAMES];\n\n\t// culling information\n\tvec3_t\t\t\tmeshBounds[2];\n\tvec3_t\t\t\tlocalOrigin;\n\tfloat\t\t\tmeshRadius;\n\n\t// lod information, which may be different\n\t// than the culling information to allow for\n\t// groups of curves that LOD as a unit\n\tvec3_t\t\t\tlodOrigin;\n\tfloat\t\t\tlodRadius;\n\tint\t\t\t\tlodFixed;\n\tint\t\t\t\tlodStitched;\n\n\t// vertexes\n\tint\t\t\t\twidth, height;\n\tfloat\t\t\t*widthLodError;\n\tfloat\t\t\t*heightLodError;\n\tdrawVert_t\t\tverts[1];\t\t// variable sized\n} srfGridMesh_t;\n\n\n\n#define\tVERTEXSIZE\t8\ntypedef struct {\n\tsurfaceType_t\tsurfaceType;\n\tcplane_t\tplane;\n\n\t// dynamic lighting information\n\tint\t\t\tdlightBits[SMP_FRAMES];\n\n\t// triangle definitions (no normals at points)\n\tint\t\t\tnumPoints;\n\tint\t\t\tnumIndices;\n\tint\t\t\tofsIndices;\n\tfloat\t\tpoints[1][VERTEXSIZE];\t// variable sized\n\t\t\t\t\t\t\t\t\t\t// there is a variable length list of indices here also\n} srfSurfaceFace_t;\n\n\n// misc_models in maps are turned into direct geometry by q3map\ntypedef struct {\n\tsurfaceType_t\tsurfaceType;\n\n\t// dynamic lighting information\n\tint\t\t\t\tdlightBits[SMP_FRAMES];\n\n\t// culling information (FIXME: use this!)\n\tvec3_t\t\t\tbounds[2];\n\tvec3_t\t\t\tlocalOrigin;\n\tfloat\t\t\tradius;\n\n\t// triangle definitions\n\tint\t\t\t\tnumIndexes;\n\tint\t\t\t\t*indexes;\n\n\tint\t\t\t\tnumVerts;\n\tdrawVert_t\t\t*verts;\n} srfTriangles_t;\n\n\nextern\tvoid (*rb_surfaceTable[SF_NUM_SURFACE_TYPES])(void *);\n\n/*\n==============================================================================\n\nBRUSH MODELS\n\n==============================================================================\n*/\n\n\n//\n// in memory representation\n//\n\n#define\tSIDE_FRONT\t0\n#define\tSIDE_BACK\t1\n#define\tSIDE_ON\t\t2\n\ntypedef struct msurface_s {\n\tint\t\t\t\t\tviewCount;\t\t// if == tr.viewCount, already added\n\tstruct shader_s\t\t*shader;\n\tint\t\t\t\t\tfogIndex;\n\n\tsurfaceType_t\t\t*data;\t\t\t// any of srf*_t\n} msurface_t;\n\n\n\n#define\tCONTENTS_NODE\t\t-1\ntypedef struct mnode_s {\n\t// common with leaf and node\n\tint\t\t\tcontents;\t\t// -1 for nodes, to differentiate from leafs\n\tint\t\t\tvisframe;\t\t// node needs to be traversed if current\n\tvec3_t\t\tmins, maxs;\t\t// for bounding box culling\n\tstruct mnode_s\t*parent;\n\n\t// node specific\n\tcplane_t\t*plane;\n\tstruct mnode_s\t*children[2];\t\n\n\t// leaf specific\n\tint\t\t\tcluster;\n\tint\t\t\tarea;\n\n\tmsurface_t\t**firstmarksurface;\n\tint\t\t\tnummarksurfaces;\n} mnode_t;\n\ntypedef struct {\n\tvec3_t\t\tbounds[2];\t\t// for culling\n\tmsurface_t\t*firstSurface;\n\tint\t\t\tnumSurfaces;\n} bmodel_t;\n\ntypedef struct {\n\tchar\t\tname[MAX_QPATH];\t\t// ie: maps/tim_dm2.bsp\n\tchar\t\tbaseName[MAX_QPATH];\t// ie: tim_dm2\n\n\tint\t\t\tdataSize;\n\n\tint\t\t\tnumShaders;\n\tdshader_t\t*shaders;\n\n\tbmodel_t\t*bmodels;\n\n\tint\t\t\tnumplanes;\n\tcplane_t\t*planes;\n\n\tint\t\t\tnumnodes;\t\t// includes leafs\n\tint\t\t\tnumDecisionNodes;\n\tmnode_t\t\t*nodes;\n\n\tint\t\t\tnumsurfaces;\n\tmsurface_t\t*surfaces;\n\n\tint\t\t\tnummarksurfaces;\n\tmsurface_t\t**marksurfaces;\n\n\tint\t\t\tnumfogs;\n\tfog_t\t\t*fogs;\n\n\tvec3_t\t\tlightGridOrigin;\n\tvec3_t\t\tlightGridSize;\n\tvec3_t\t\tlightGridInverseSize;\n\tint\t\t\tlightGridBounds[3];\n\tbyte\t\t*lightGridData;\n\n\n\tint\t\t\tnumClusters;\n\tint\t\t\tclusterBytes;\n\tconst byte\t*vis;\t\t\t// may be passed in by CM_LoadMap to save space\n\n\tbyte\t\t*novis;\t\t\t// clusterBytes of 0xff\n\n\tchar\t\t*entityString;\n\tchar\t\t*entityParsePoint;\n} world_t;\n\n//======================================================================\n\ntypedef enum {\n\tMOD_BAD,\n\tMOD_BRUSH,\n\tMOD_MESH,\n\tMOD_MD4\n} modtype_t;\n\ntypedef struct model_s {\n\tchar\t\tname[MAX_QPATH];\n\tmodtype_t\ttype;\n\tint\t\t\tindex;\t\t\t\t// model = tr.models[model->index]\n\n\tint\t\t\tdataSize;\t\t\t// just for listing purposes\n\tbmodel_t\t*bmodel;\t\t\t// only if type == MOD_BRUSH\n\tmd3Header_t\t*md3[MD3_MAX_LODS];\t// only if type == MOD_MESH\n\tmd4Header_t\t*md4;\t\t\t\t// only if type == MOD_MD4\n\n\tint\t\t\t numLods;\n} model_t;\n\n\n#define\tMAX_MOD_KNOWN\t1024\n\nvoid\t\tR_ModelInit (void);\nmodel_t\t\t*R_GetModelByHandle( qhandle_t hModel );\nint\t\t\tR_LerpTag( orientation_t *tag, qhandle_t handle, int startFrame, int endFrame, \n\t\t\t\t\t float frac, const char *tagName );\nvoid\t\tR_ModelBounds( qhandle_t handle, vec3_t mins, vec3_t maxs );\n\nvoid\t\tR_Modellist_f (void);\n\n//====================================================\nextern\trefimport_t\t\tri;\n\n#define\tMAX_DRAWIMAGES\t\t\t2048\n#define\tMAX_LIGHTMAPS\t\t\t256\n#define\tMAX_SKINS\t\t\t\t1024\n\n\n#define\tMAX_DRAWSURFS\t\t\t0x10000\n#define\tDRAWSURF_MASK\t\t\t(MAX_DRAWSURFS-1)\n\n/*\n\nthe drawsurf sort data is packed into a single 32 bit value so it can be\ncompared quickly during the qsorting process\n\nthe bits are allocated as follows:\n\n21 - 31\t: sorted shader index\n11 - 20\t: entity index\n2 - 6\t: fog index\n//2\t\t: used to be clipped flag REMOVED - 03.21.00 rad\n0 - 1\t: dlightmap index\n\n\tTTimo - 1.32\n17-31 : sorted shader index\n7-16  : entity index\n2-6   : fog index\n0-1   : dlightmap index\n*/\n#define\tQSORT_SHADERNUM_SHIFT\t17\n#define\tQSORT_ENTITYNUM_SHIFT\t7\n#define\tQSORT_FOGNUM_SHIFT\t\t2\n\nextern\tint\t\t\tgl_filter_min, gl_filter_max;\n\n/*\n** performanceCounters_t\n*/\ntypedef struct {\n\tint\t\tc_sphere_cull_patch_in, c_sphere_cull_patch_clip, c_sphere_cull_patch_out;\n\tint\t\tc_box_cull_patch_in, c_box_cull_patch_clip, c_box_cull_patch_out;\n\tint\t\tc_sphere_cull_md3_in, c_sphere_cull_md3_clip, c_sphere_cull_md3_out;\n\tint\t\tc_box_cull_md3_in, c_box_cull_md3_clip, c_box_cull_md3_out;\n\n\tint\t\tc_leafs;\n\tint\t\tc_dlightSurfaces;\n\tint\t\tc_dlightSurfacesCulled;\n} frontEndCounters_t;\n\n#define\tFOG_TABLE_SIZE\t\t256\n#define FUNCTABLE_SIZE\t\t1024\n#define FUNCTABLE_SIZE2\t\t10\n#define FUNCTABLE_MASK\t\t(FUNCTABLE_SIZE-1)\n\n\n// the renderer front end should never modify glstate_t\ntypedef struct {\n\tint\t\t\tcurrenttextures[2];\n\tint\t\t\tcurrenttmu;\n\tint\t\t\ttexEnv[2];\n\tint\t\t\tfaceCulling;\n\tunsigned long\tglStateBits;\n} glstate_t;\n\n\ntypedef struct {\n\tint\t\tc_surfaces, c_shaders, c_vertexes, c_indexes, c_totalIndexes;\n\t\n\tint\t\tc_dlightVertexes;\n\tint\t\tc_dlightIndexes;\n\n\tint\t\tmsec;\t\t\t// total msec for backend run\n} backEndCounters_t;\n\n// all state modified by the back end is seperated\n// from the front end state\ntypedef struct {\n\tint\t\t\tsmpFrame;\n\ttrRefdef_t\trefdef;\n\tviewParms_t\tviewParms;\n\torientationr_t\tor;\n\tbackEndCounters_t\tpc;\n\tqboolean\tisHyperspace;\n\ttrRefEntity_t\t*currentEntity;\n\n\tqboolean\tprojection2D;\t// if qtrue, drawstretchpic doesn't need to change modes\n\tbyte\t\tcolor2D[4];\n\ttrRefEntity_t\tentity2D;\t// currentEntity will point at this when doing 2D rendering\n} backEndState_t;\n\n/*\n** trGlobals_t \n**\n** Most renderer globals are defined here.\n** backend functions should never modify any of these fields,\n** but may read fields that aren't dynamically modified\n** by the frontend.\n*/\ntypedef struct {\n\tqboolean\t\t\t\tregistered;\t\t// cleared at shutdown, set at beginRegistration\n\n\tint\t\t\t\t\t\tvisCount;\t\t// incremented every time a new vis cluster is entered\n\tint\t\t\t\t\t\tframeCount;\t\t// incremented every frame\n\tint\t\t\t\t\t\tviewCount;\t\t// incremented every view (twice a scene if portaled)\n\t\t\t\t\t\t\t\t\t\t\t// and every R_MarkFragments call\n\n\tint\t\t\t\t\t\tsmpFrame;\t\t// toggles from 0 to 1 every endFrame\n\n\tqboolean\t\t\t\tworldMapLoaded;\n\tworld_t\t\t\t\t\t*world;\n\n\tconst byte\t\t\t\t*externalVisData;\t// from RE_SetWorldVisData, shared with CM_Load\n\n\timage_t\t\t\t\t\t*defaultImage;\n\timage_t\t\t\t\t\t*scratchImage[32];\n\timage_t\t\t\t\t\t*fogImage;\n\timage_t\t\t\t\t\t*dlightImage;\t// inverse-quare highlight for projective adding\n\timage_t\t\t\t\t\t*whiteImage;\t\t\t// full of 0xff\n\timage_t\t\t\t\t\t*identityLightImage;\t// full of tr.identityLightByte\n\n\tshader_t\t\t\t\t*defaultShader;\n    shader_t                *cinematicShader;\n\tshader_t\t\t\t\t*shadowShader;\n\tshader_t\t\t\t\t*projectionShadowShader;\n\n\tint\t\t\t\t\t\tnumLightmaps;\n\timage_t\t\t\t\t\t*lightmaps[MAX_LIGHTMAPS];\n\n\ttrRefEntity_t\t\t\t*currentEntity;\n\ttrRefEntity_t\t\t\tworldEntity;\t\t// point currentEntity at this when rendering world\n\tint\t\t\t\t\t\tcurrentEntityNum;\n\tint\t\t\t\t\t\tshiftedEntityNum;\t// currentEntityNum << QSORT_ENTITYNUM_SHIFT\n\tmodel_t\t\t\t\t\t*currentModel;\n\n\tviewParms_t\t\t\t\tviewParms;\n\n\tfloat\t\t\t\t\tidentityLight;\t\t// 1.0 / ( 1 << overbrightBits )\n\tint\t\t\t\t\t\tidentityLightByte;\t// identityLight * 255\n\tint\t\t\t\t\t\toverbrightBits;\t\t// r_overbrightBits->integer, but set to 0 if no hw gamma\n\n\torientationr_t\t\t\tor;\t\t\t\t\t// for current entity\n\n\ttrRefdef_t\t\t\t\trefdef;\n\n\tint\t\t\t\t\t\tviewCluster;\n\n\tvec3_t\t\t\t\t\tsunLight;\t\t\t// from the sky shader for this level\n\tvec3_t\t\t\t\t\tsunDirection;\n\n\tfrontEndCounters_t\t\tpc;\n\tint\t\t\t\t\t\tfrontEndMsec;\t\t// not in pc due to clearing issue\n\n\t//\n\t// put large tables at the end, so most elements will be\n\t// within the +/32K indexed range on risc processors\n\t//\n\tmodel_t\t\t\t\t\t*models[MAX_MOD_KNOWN];\n\tint\t\t\t\t\t\tnumModels;\n\n\tint\t\t\t\t\t\tnumImages;\n\timage_t\t\t\t\t\t*images[MAX_DRAWIMAGES];\n\n\t// shader indexes from other modules will be looked up in tr.shaders[]\n\t// shader indexes from drawsurfs will be looked up in sortedShaders[]\n\t// lower indexed sortedShaders must be rendered first (opaque surfaces before translucent)\n\tint\t\t\t\t\t\tnumShaders;\n\tshader_t\t\t\t\t*shaders[MAX_SHADERS];\n\tshader_t\t\t\t\t*sortedShaders[MAX_SHADERS];\n\n\tint\t\t\t\t\t\tnumSkins;\n\tskin_t\t\t\t\t\t*skins[MAX_SKINS];\n\n\tfloat\t\t\t\t\tsinTable[FUNCTABLE_SIZE];\n\tfloat\t\t\t\t\tsquareTable[FUNCTABLE_SIZE];\n\tfloat\t\t\t\t\ttriangleTable[FUNCTABLE_SIZE];\n\tfloat\t\t\t\t\tsawToothTable[FUNCTABLE_SIZE];\n\tfloat\t\t\t\t\tinverseSawToothTable[FUNCTABLE_SIZE];\n\tfloat\t\t\t\t\tfogTable[FOG_TABLE_SIZE];\n} trGlobals_t;\n\nextern backEndState_t\tbackEnd;\nextern trGlobals_t\ttr;\nextern bool\t\t\tgl_active;\t\t// set to true if OpenGL is used for rendering\nextern glconfig_t\tglConfig;\t\t// outside of TR since it shouldn't be cleared during ref re-init\nextern glstate_t\tglState;\t\t// outside of TR since it shouldn't be cleared during ref re-init\n\n// VULKAN\nextern Vk_Instance\tvk;\t\t\t\t// shouldn't be cleared during ref re-init\nextern Vk_World\t\tvk_world;\t\t// this data is cleared during ref re-init\n\n// DX12\nextern Dx_Instance\tdx;\t\t\t\t// shouldn't be cleared during ref re-init\nextern Dx_World\t\tdx_world;\t\t// this data is cleared during ref re-init\n\nenum RenderApi {\n\tRENDER_API_GL,\n\tRENDER_API_VK,\n\tRENDER_API_DX\n};\n\nRenderApi get_render_api();\n\n//\n// cvars\n//\nextern cvar_t\t*r_renderAPI;\t\t\t// 3D API to use: 0 - OpenGL, 1 - Vulkan\nextern cvar_t\t*r_gpu;\t\t\t\t\t// Select GPU in multi-GPU system (zero-based index, only in Vulkan). By default, GPU 0 is selected.\nextern cvar_t\t*r_vsync;\t\t\t\t// Enable vsync in Vulkan (com_maxFPS may be set to 0)\nextern cvar_t\t*r_shaderGamma;\t\t\t// Use compute shader to apply gamma (only in Vulkan) instead of legacy HW gamma API.\nextern cvar_t\t*r_twinMode;\t\t\t// Debug feature to compare rendering output between OpenGL/Vulkan APIs\n\nextern cvar_t\t*r_railWidth;\nextern cvar_t\t*r_railCoreWidth;\nextern cvar_t\t*r_railSegmentLength;\n\nextern cvar_t\t*r_verbose;\t\t\t\t// used for verbose debug spew\n\nextern cvar_t\t*r_znear;\t\t\t\t// near Z clip plane\n\nextern cvar_t\t*r_stencilbits;\t\t\t// number of desired stencil bits\nextern cvar_t\t*r_depthbits;\t\t\t// number of desired depth bits\nextern cvar_t\t*r_stereo;\t\t\t\t// desired pixelformat stereo flag\nextern cvar_t\t*r_texturebits;\t\t\t// number of desired texture bits\n\t\t\t\t\t\t\t\t\t\t// 0 = use framebuffer depth\n\t\t\t\t\t\t\t\t\t\t// 16 = use 16-bit textures\n\t\t\t\t\t\t\t\t\t\t// 32 = use 32-bit textures\n\t\t\t\t\t\t\t\t\t\t// all else = error\n\nextern cvar_t\t*r_lodbias;\t\t\t\t// push/pull LOD transitions\nextern cvar_t\t*r_lodscale;\n\nextern cvar_t\t*r_inGameVideo;\t\t\t\t// controls whether in game video should be draw\nextern cvar_t\t*r_fastsky;\t\t\t\t// controls whether sky should be cleared or drawn\nextern cvar_t\t*r_dynamiclight;\t\t// dynamic lights enabled/disabled\n\nextern\tcvar_t\t*r_norefresh;\t\t\t// bypasses the ref rendering\nextern\tcvar_t\t*r_drawentities;\t\t// disable/enable entity rendering\nextern\tcvar_t\t*r_drawworld;\t\t\t// disable/enable world rendering\nextern\tcvar_t\t*r_speeds;\t\t\t\t// various levels of information display\nextern  cvar_t\t*r_detailTextures;\t\t// enables/disables detail texturing stages\nextern\tcvar_t\t*r_novis;\t\t\t\t// disable/enable usage of PVS\nextern\tcvar_t\t*r_nocull;\nextern\tcvar_t\t*r_facePlaneCull;\t\t// enables culling of planar surfaces with back side test\nextern\tcvar_t\t*r_nocurves;\nextern\tcvar_t\t*r_showcluster;\n\nextern cvar_t\t*r_mode;\t\t\t\t// video mode\nextern cvar_t\t*r_fullscreen;\nextern cvar_t\t*r_gamma;\nextern cvar_t\t*r_ignorehwgamma;\t\t// overrides hardware gamma capabilities\n\nextern cvar_t\t*r_ext_compressed_textures;\t\t// these control use of specific extensions\nextern cvar_t\t*r_ext_gamma_control;\nextern cvar_t\t*r_ext_texenv_op;\nextern cvar_t\t*r_ext_compiled_vertex_array;\nextern cvar_t\t*r_ext_texture_env_add;\n\nextern\tcvar_t\t*r_nobind;\t\t\t\t\t\t// turns off binding to appropriate textures\nextern\tcvar_t\t*r_singleShader;\t\t\t\t// make most world faces use default shader\nextern\tcvar_t\t*r_roundImagesDown;\nextern\tcvar_t\t*r_colorMipLevels;\t\t\t\t// development aid to see texture mip usage\nextern\tcvar_t\t*r_picmip;\t\t\t\t\t\t// controls picmip values\nextern\tcvar_t\t*r_drawBuffer;\nextern  cvar_t  *r_glDriver;\nextern\tcvar_t\t*r_swapInterval;\nextern\tcvar_t\t*r_textureMode;\nextern\tcvar_t\t*r_offsetFactor;\nextern\tcvar_t\t*r_offsetUnits;\n\nextern\tcvar_t\t*r_fullbright;\t\t\t\t\t// avoid lightmap pass\nextern\tcvar_t\t*r_lightmap;\t\t\t\t\t// render lightmaps only\nextern\tcvar_t\t*r_vertexLight;\t\t\t\t\t// vertex lighting mode for better performance\nextern\tcvar_t\t*r_uiFullScreen;\t\t\t\t// ui is running fullscreen\n\nextern\tcvar_t\t*r_logFile;\t\t\t\t\t\t// number of frames to emit GL logs\nextern\tcvar_t\t*r_showtris;\t\t\t\t\t// enables wireframe rendering of the world\nextern\tcvar_t\t*r_showsky;\t\t\t\t\t\t// forces sky in front of all surfaces\nextern\tcvar_t\t*r_shownormals;\t\t\t\t\t// draws wireframe normals\nextern\tcvar_t\t*r_clear;\t\t\t\t\t\t// force screen clear every frame\n\nextern\tcvar_t\t*r_shadows;\t\t\t\t\t\t// controls shadows: 0 = none, 1 = blur, 2 = stencil, 3 = black planar projection\n\nextern\tcvar_t\t*r_intensity;\n\nextern\tcvar_t\t*r_lockpvs;\nextern\tcvar_t\t*r_noportals;\nextern\tcvar_t\t*r_portalOnly;\n\nextern\tcvar_t\t*r_subdivisions;\nextern\tcvar_t\t*r_lodCurveError;\nextern\tcvar_t\t*r_smp;\nextern\tcvar_t\t*r_showSmp;\nextern\tcvar_t\t*r_skipBackEnd;\n\nextern\tcvar_t\t*r_ignoreGLErrors;\n\nextern\tcvar_t\t*r_overBrightBits;\nextern\tcvar_t\t*r_mapOverBrightBits;\n\nextern\tcvar_t\t*r_debugSurface;\nextern\tcvar_t\t*r_simpleMipMaps;\n\nextern\tcvar_t\t*r_showImages;\nextern\tcvar_t\t*r_debugSort;\n\nextern\tcvar_t\t*r_printShaders;\nextern\tcvar_t\t*r_saveFontData;\n\n//====================================================================\n\nfloat R_NoiseGet4f( float x, float y, float z, float t );\nvoid  R_NoiseInit( void );\n\nvoid R_RenderView( viewParms_t *parms );\n\nvoid R_AddMD3Surfaces( trRefEntity_t *e );\n\nvoid R_AddPolygonSurfaces( void );\n\nvoid R_DecomposeSort( unsigned sort, int *entityNum, shader_t **shader, \n\t\t\t\t\t int *fogNum, int *dlightMap );\n\nvoid R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, int fogIndex, int dlightMap );\n\n\n#define\tCULL_IN\t\t0\t\t// completely unclipped\n#define\tCULL_CLIP\t1\t\t// clipped by one or more planes\n#define\tCULL_OUT\t2\t\t// completely outside the clipping planes\nvoid R_LocalNormalToWorld (vec3_t local, vec3_t world);\nvoid R_LocalPointToWorld (vec3_t local, vec3_t world);\nint R_CullLocalBox (vec3_t bounds[2]);\nint R_CullPointAndRadius( vec3_t origin, float radius );\nint R_CullLocalPointAndRadius( vec3_t origin, float radius );\n\nvoid R_RotateForEntity( const trRefEntity_t *ent, const viewParms_t *viewParms, orientationr_t *or );\n\n/*\n** GL wrapper/helper functions\n*/\nvoid\tGL_Bind( image_t *image );\nvoid\tGL_SetDefaultState (void);\nvoid\tGL_SelectTexture( int unit );\nvoid\tGL_TextureMode( const char *string );\nvoid\tGL_CheckErrors( void );\nvoid\tGL_State( unsigned long stateVector );\nvoid\tGL_TexEnv( int env );\nvoid\tGL_Cull( int cullType );\n\n#define GLS_SRCBLEND_ZERO\t\t\t\t\t\t0x00000001\n#define GLS_SRCBLEND_ONE\t\t\t\t\t\t0x00000002\n#define GLS_SRCBLEND_DST_COLOR\t\t\t\t\t0x00000003\n#define GLS_SRCBLEND_ONE_MINUS_DST_COLOR\t\t0x00000004\n#define GLS_SRCBLEND_SRC_ALPHA\t\t\t\t\t0x00000005\n#define GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA\t\t0x00000006\n#define GLS_SRCBLEND_DST_ALPHA\t\t\t\t\t0x00000007\n#define GLS_SRCBLEND_ONE_MINUS_DST_ALPHA\t\t0x00000008\n#define GLS_SRCBLEND_ALPHA_SATURATE\t\t\t\t0x00000009\n#define\t\tGLS_SRCBLEND_BITS\t\t\t\t\t0x0000000f\n\n#define GLS_DSTBLEND_ZERO\t\t\t\t\t\t0x00000010\n#define GLS_DSTBLEND_ONE\t\t\t\t\t\t0x00000020\n#define GLS_DSTBLEND_SRC_COLOR\t\t\t\t\t0x00000030\n#define GLS_DSTBLEND_ONE_MINUS_SRC_COLOR\t\t0x00000040\n#define GLS_DSTBLEND_SRC_ALPHA\t\t\t\t\t0x00000050\n#define GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA\t\t0x00000060\n#define GLS_DSTBLEND_DST_ALPHA\t\t\t\t\t0x00000070\n#define GLS_DSTBLEND_ONE_MINUS_DST_ALPHA\t\t0x00000080\n#define\t\tGLS_DSTBLEND_BITS\t\t\t\t\t0x000000f0\n\n#define GLS_DEPTHMASK_TRUE\t\t\t\t\t\t0x00000100\n\n#define GLS_POLYMODE_LINE\t\t\t\t\t\t0x00001000\n\n#define GLS_DEPTHTEST_DISABLE\t\t\t\t\t0x00010000\n#define GLS_DEPTHFUNC_EQUAL\t\t\t\t\t\t0x00020000\n\n#define GLS_ATEST_GT_0\t\t\t\t\t\t\t0x10000000\n#define GLS_ATEST_LT_80\t\t\t\t\t\t\t0x20000000\n#define GLS_ATEST_GE_80\t\t\t\t\t\t\t0x40000000\n#define\t\tGLS_ATEST_BITS\t\t\t\t\t\t0x70000000\n\n#define GLS_DEFAULT\t\t\tGLS_DEPTHMASK_TRUE\n\nvoid\tRE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty);\nvoid\tRE_UploadCinematic (int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty);\n\nvoid\t\tRE_BeginFrame( stereoFrame_t stereoFrame );\nvoid\t\tRE_BeginRegistration( glconfig_t *glconfig );\nvoid\t\tRE_LoadWorldMap( const char *mapname );\nvoid\t\tRE_SetWorldVisData( const byte *vis );\nqhandle_t\tRE_RegisterModel( const char *name );\nqhandle_t\tRE_RegisterSkin( const char *name );\nvoid\t\tRE_Shutdown( qboolean destroyWindow );\n\nqboolean\tR_GetEntityToken( char *buffer, int size );\n\nmodel_t\t\t*R_AllocModel( void );\n\nvoid    \tR_Init( void );\nimage_t\t\t*R_FindImageFile( const char *name, qboolean mipmap, qboolean allowPicmip, int glWrapClampMode );\n\nimage_t\t\t*R_CreateImage( const char *name, const byte *pic, int width, int height, qboolean mipmap\n\t\t\t\t\t, qboolean allowPicmip, int wrapClampMode );\nqboolean\tR_GetModeInfo( int *width, int *height, float *windowAspect, int mode );\n\nvoid\t\tR_SetColorMappings( void );\nvoid\t\tR_GammaCorrect( byte *buffer, int bufSize );\n\nvoid\tR_ImageList_f( void );\nvoid\tR_SkinList_f( void );\n// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=516\nconst void *RB_TakeScreenshotCmd( const void *data );\nvoid\tR_ScreenShot_f( void );\n\nvoid\tR_InitFogTable( void );\nfloat\tR_FogFactor( float s, float t );\nvoid\tR_InitImages( void );\nvoid\tR_DeleteTextures( void );\nint\t\tR_SumOfUsedImages( void );\nvoid\tR_InitSkins( void );\nskin_t\t*R_GetSkinByHandle( qhandle_t hSkin );\n\n\n//\n// tr_shader.c\n//\nqhandle_t\t\t RE_RegisterShaderLightMap( const char *name, int lightmapIndex );\nqhandle_t\t\t RE_RegisterShader( const char *name );\nqhandle_t\t\t RE_RegisterShaderNoMip( const char *name );\nqhandle_t RE_RegisterShaderFromImage(const char *name, int lightmapIndex, image_t *image, qboolean mipRawImage);\n\nshader_t\t*R_FindShader( const char *name, int lightmapIndex, qboolean mipRawImage );\nshader_t\t*R_GetShaderByHandle( qhandle_t hShader );\nshader_t *R_FindShaderByName( const char *name );\nvoid\t\tR_InitShaders( void );\nvoid\t\tR_ShaderList_f( void );\nvoid    R_RemapShader(const char *oldShader, const char *newShader, const char *timeOffset);\n\n/*\n====================================================================\n\nIMPLEMENTATION SPECIFIC FUNCTIONS\n\n====================================================================\n*/\n\nvoid\t\tGLimp_Init( void );\nvoid\t\tGLimp_Shutdown( void );\nvoid\t\tGLimp_EndFrame( void );\nvoid\t\tGLimp_LogComment( char *comment );\n\nqboolean\tGLimp_SpawnRenderThread( void (*function)( void ) );\nvoid\t\t*GLimp_RendererSleep( void );\nvoid\t\tGLimp_FrontEndSleep( void );\nvoid\t\tGLimp_WakeRenderer( void *data );\n\nvoid vk_imp_init();\nvoid vk_imp_shutdown();\nvoid vk_imp_create_surface();\n\nvoid dx_imp_init();\nvoid dx_imp_shutdown();\n\n// NOTE TTimo linux works with float gamma value, not the gamma table\n//   the params won't be used, getting the r_gamma cvar directly\nvoid\t\tGLimp_SetGamma( unsigned char mapping[256] );\nvoid\t\tGLimp_RestoreGamma();\n\n/*\n====================================================================\n\nTESSELATOR/SHADER DECLARATIONS\n\n====================================================================\n*/\ntypedef byte color4ub_t[4];\n\ntypedef struct stageVars\n{\n\tcolor4ub_t\tcolors[SHADER_MAX_VERTEXES];\n\tvec2_t\t\ttexcoords[NUM_TEXTURE_BUNDLES][SHADER_MAX_VERTEXES];\n} stageVars_t;\n\ntypedef struct shaderCommands_s \n{\n\tglIndex_t\tindexes[SHADER_MAX_INDEXES];\n\tvec4_t\t\txyz[SHADER_MAX_VERTEXES];\n\tvec4_t\t\tnormal[SHADER_MAX_VERTEXES];\n\tvec2_t\t\ttexCoords[SHADER_MAX_VERTEXES][2];\n\tcolor4ub_t\tvertexColors[SHADER_MAX_VERTEXES];\n\tint\t\t\tvertexDlightBits[SHADER_MAX_VERTEXES];\n\n\tstageVars_t\tsvars;\n\n\tcolor4ub_t\tconstantColor255[SHADER_MAX_VERTEXES];\n\n\tshader_t\t*shader;\n  float   shaderTime;\n\tint\t\t\tfogNum;\n\n\tint\t\t\tdlightBits;\t// or together of all vertexDlightBits\n\n\tint\t\t\tnumIndexes;\n\tint\t\t\tnumVertexes;\n\n\t// info extracted from current shader\n\tint\t\t\tnumPasses;\n\tshaderStage_t\t**xstages;\n} shaderCommands_t;\n\nextern\tshaderCommands_t\ttess;\n\nvoid RB_BeginSurface(shader_t *shader, int fogNum );\nvoid RB_EndSurface(void);\nvoid RB_CheckOverflow( int verts, int indexes );\n#define RB_CHECKOVERFLOW(v,i) if (tess.numVertexes + (v) >= SHADER_MAX_VERTEXES || tess.numIndexes + (i) >= SHADER_MAX_INDEXES ) {RB_CheckOverflow(v,i);}\n\nvoid RB_StageIteratorGeneric( void );\nvoid RB_StageIteratorSky( void );\n\nvoid RB_AddQuadStamp( vec3_t origin, vec3_t left, vec3_t up, byte *color );\nvoid RB_AddQuadStampExt( vec3_t origin, vec3_t left, vec3_t up, byte *color, float s1, float t1, float s2, float t2 );\n\nvoid RB_ShowImages( void );\n\n\n/*\n============================================================\n\nWORLD MAP\n\n============================================================\n*/\n\nvoid R_AddBrushModelSurfaces( trRefEntity_t *e );\nvoid R_AddWorldSurfaces( void );\nqboolean R_inPVS( const vec3_t p1, const vec3_t p2 );\n\n/*\n============================================================\n\nLIGHTS\n\n============================================================\n*/\n\nvoid R_DlightBmodel( bmodel_t *bmodel );\nvoid R_SetupEntityLighting( const trRefdef_t *refdef, trRefEntity_t *ent );\nvoid R_TransformDlights( int count, dlight_t *dl, orientationr_t *or );\nint R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir );\n\n\n/*\n============================================================\n\nSHADOWS\n\n============================================================\n*/\n\nvoid RB_ShadowTessEnd( void );\nvoid RB_ShadowFinish( void );\nvoid RB_ProjectionShadowDeform( void );\n\n/*\n============================================================\n\nSKIES\n\n============================================================\n*/\n\nvoid R_InitSkyTexCoords( float cloudLayerHeight );\n\n/*\n============================================================\n\nCURVE TESSELATION\n\n============================================================\n*/\n\n#define PATCH_STITCHING\n\nsrfGridMesh_t *R_SubdividePatchToGrid( int width, int height,\n\t\t\t\t\t\t\t\tdrawVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] );\nsrfGridMesh_t *R_GridInsertColumn( srfGridMesh_t *grid, int column, int row, vec3_t point, float loderror );\nsrfGridMesh_t *R_GridInsertRow( srfGridMesh_t *grid, int row, int column, vec3_t point, float loderror );\nvoid R_FreeSurfaceGridMesh( srfGridMesh_t *grid );\n\n/*\n============================================================\n\nMARKERS, POLYGON PROJECTION ON WORLD POLYGONS\n\n============================================================\n*/\n\nint R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projection,\n\t\t\t\t   int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer );\n\n\n/*\n============================================================\n\nSCENE GENERATION\n\n============================================================\n*/\n\nvoid R_ToggleSmpFrame( void );\n\nvoid RE_ClearScene( void );\nvoid RE_AddRefEntityToScene( const refEntity_t *ent );\nvoid RE_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts, int num );\nvoid RE_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b );\nvoid RE_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, float g, float b );\nvoid RE_RenderScene( const refdef_t *fd );\n\n/*\n=============================================================\n\nANIMATED MODELS\n\n=============================================================\n*/\n\nvoid R_AddAnimSurfaces( trRefEntity_t *ent );\nvoid RB_SurfaceAnim( md4Surface_t *surfType );\n\n/*\n=============================================================\n=============================================================\n*/\nvoid\tR_TransformModelToClip( const vec3_t src, const float *modelMatrix, const float *projectionMatrix,\n\t\t\t\t\t\t\tvec4_t eye, vec4_t dst );\n\nvoid\tRB_DeformTessGeometry( void );\n\nvoid\tRB_CalcEnvironmentTexCoords( float *dstTexCoords );\nvoid\tRB_CalcFogTexCoords( float *dstTexCoords );\nvoid\tRB_CalcScrollTexCoords( const float scroll[2], float *dstTexCoords );\nvoid\tRB_CalcRotateTexCoords( float rotSpeed, float *dstTexCoords );\nvoid\tRB_CalcScaleTexCoords( const float scale[2], float *dstTexCoords );\nvoid\tRB_CalcTurbulentTexCoords( const waveForm_t *wf, float *dstTexCoords );\nvoid\tRB_CalcTransformTexCoords( const texModInfo_t *tmi, float *dstTexCoords );\nvoid\tRB_CalcModulateColorsByFog( unsigned char *dstColors );\nvoid\tRB_CalcModulateAlphasByFog( unsigned char *dstColors );\nvoid\tRB_CalcModulateRGBAsByFog( unsigned char *dstColors );\nvoid\tRB_CalcWaveAlpha( const waveForm_t *wf, unsigned char *dstColors );\nvoid\tRB_CalcWaveColor( const waveForm_t *wf, unsigned char *dstColors );\nvoid\tRB_CalcAlphaFromEntity( unsigned char *dstColors );\nvoid\tRB_CalcAlphaFromOneMinusEntity( unsigned char *dstColors );\nvoid\tRB_CalcStretchTexCoords( const waveForm_t *wf, float *texCoords );\nvoid\tRB_CalcColorFromEntity( unsigned char *dstColors );\nvoid\tRB_CalcColorFromOneMinusEntity( unsigned char *dstColors );\nvoid\tRB_CalcSpecularAlpha( unsigned char *alphas );\nvoid\tRB_CalcDiffuseColor( unsigned char *colors );\n\nvoid myGlMultMatrix( const float *a, const float *b, float *out );\n\n/*\n=============================================================\n\nRENDERER BACK END FUNCTIONS\n\n=============================================================\n*/\n\nvoid RB_RenderThread( void );\nvoid RB_ExecuteRenderCommands( const void *data );\n\n/*\n=============================================================\n\nRENDERER BACK END COMMAND QUEUE\n\n=============================================================\n*/\n\n#define\tMAX_RENDER_COMMANDS\t0x40000\n\ntypedef struct {\n\tbyte\tcmds[MAX_RENDER_COMMANDS];\n\tint\t\tused;\n} renderCommandList_t;\n\ntypedef struct {\n\tint\t\tcommandId;\n\tfloat\tcolor[4];\n} setColorCommand_t;\n\ntypedef struct {\n\tint\t\tcommandId;\n\tint\t\tbuffer;\n} drawBufferCommand_t;\n\ntypedef struct {\n\tint\t\tcommandId;\n\timage_t\t*image;\n\tint\t\twidth;\n\tint\t\theight;\n\tvoid\t*data;\n} subImageCommand_t;\n\ntypedef struct {\n\tint\t\tcommandId;\n} swapBuffersCommand_t;\n\ntypedef struct {\n\tint\t\tcommandId;\n\tint\t\tbuffer;\n} endFrameCommand_t;\n\ntypedef struct {\n\tint\t\tcommandId;\n\tshader_t\t*shader;\n\tfloat\tx, y;\n\tfloat\tw, h;\n\tfloat\ts1, t1;\n\tfloat\ts2, t2;\n} stretchPicCommand_t;\n\ntypedef struct {\n\tint\t\tcommandId;\n\ttrRefdef_t\trefdef;\n\tviewParms_t\tviewParms;\n\tdrawSurf_t *drawSurfs;\n\tint\t\tnumDrawSurfs;\n} drawSurfsCommand_t;\n\ntypedef struct {\n\tint commandId;\n\tint x;\n\tint y;\n\tint width;\n\tint height;\n\tchar *fileName;\n\tqboolean jpeg;\n} screenshotCommand_t;\n\ntypedef enum {\n\tRC_END_OF_LIST,\n\tRC_SET_COLOR,\n\tRC_STRETCH_PIC,\n\tRC_DRAW_SURFS,\n\tRC_DRAW_BUFFER,\n\tRC_SWAP_BUFFERS,\n\tRC_SCREENSHOT\n} renderCommand_t;\n\n\n// these are sort of arbitrary limits.\n// the limits apply to the sum of all scenes in a frame --\n// the main view, all the 3D icons, etc\n#define\tMAX_POLYS\t\t600\n#define\tMAX_POLYVERTS\t3000\n\n// all of the information needed by the back end must be\n// contained in a backEndData_t.  This entire structure is\n// duplicated so the front and back end can run in parallel\n// on an SMP machine\ntypedef struct {\n\tdrawSurf_t\tdrawSurfs[MAX_DRAWSURFS];\n\tdlight_t\tdlights[MAX_DLIGHTS];\n\ttrRefEntity_t\tentities[MAX_ENTITIES];\n\tsrfPoly_t\t*polys;//[MAX_POLYS];\n\tpolyVert_t\t*polyVerts;//[MAX_POLYVERTS];\n\trenderCommandList_t\tcommands;\n} backEndData_t;\n\nextern\tint\t\tmax_polys;\nextern\tint\t\tmax_polyverts;\n\nextern\tbackEndData_t\t*backEndData[SMP_FRAMES];\t// the second one may not be allocated\n\nextern\tvolatile renderCommandList_t\t*renderCommandList;\n\nextern\tvolatile qboolean\trenderThreadActive;\n\n\nvoid *R_GetCommandBuffer( int bytes );\nvoid RB_ExecuteRenderCommands( const void *data );\n\nvoid R_InitCommandBuffers( void );\nvoid R_ShutdownCommandBuffers( void );\n\nvoid R_SyncRenderThread( void );\n\nvoid R_AddDrawSurfCmd( drawSurf_t *drawSurfs, int numDrawSurfs );\n\nvoid RE_SetColor( const float *rgba );\nvoid RE_StretchPic ( float x, float y, float w, float h, \n\t\t\t\t\t  float s1, float t1, float s2, float t2, qhandle_t hShader );\nvoid RE_BeginFrame( stereoFrame_t stereoFrame );\nvoid RE_EndFrame( int *frontEndMsec, int *backEndMsec );\nvoid SaveJPG(char * filename, int quality, int image_width, int image_height, unsigned char *image_buffer);\n\n// font stuff\nvoid R_InitFreeType();\nvoid R_DoneFreeType();\nvoid RE_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font);\n\n\n#endif //TR_LOCAL_H\n"
  },
  {
    "path": "src/engine/renderer/tr_main.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n// tr_main.c -- main control flow for each frame\n\n#include \"tr_local.h\"\n\ntrGlobals_t\t\ttr;\n\nstatic float\ts_flipMatrix[16] = {\n\t// convert from our coordinate system (looking down X)\n\t// to OpenGL's coordinate system (looking down -Z)\n\t0, 0, -1, 0,\n\t-1, 0, 0, 0,\n\t0, 1, 0, 0,\n\t0, 0, 0, 1\n};\n\n\nrefimport_t\tri;\n\n// entities that will have procedurally generated surfaces will just\n// point at this for their sorting surface\nsurfaceType_t\tentitySurface = SF_ENTITY;\n\n/*\n=================\nR_CullLocalBox\n\nReturns CULL_IN, CULL_CLIP, or CULL_OUT\n=================\n*/\nint R_CullLocalBox (vec3_t bounds[2]) {\n\tint\t\ti, j;\n\tvec3_t\ttransformed[8];\n\tfloat\tdists[8];\n\tvec3_t\tv;\n\tcplane_t\t*frust;\n\tint\t\t\tanyBack;\n\tint\t\t\tfront, back;\n\n\tif ( r_nocull->integer ) {\n\t\treturn CULL_CLIP;\n\t}\n\n\t// transform into world space\n\tfor (i = 0 ; i < 8 ; i++) {\n\t\tv[0] = bounds[i&1][0];\n\t\tv[1] = bounds[(i>>1)&1][1];\n\t\tv[2] = bounds[(i>>2)&1][2];\n\n\t\tVectorCopy( tr.or.origin, transformed[i] );\n\t\tVectorMA( transformed[i], v[0], tr.or.axis[0], transformed[i] );\n\t\tVectorMA( transformed[i], v[1], tr.or.axis[1], transformed[i] );\n\t\tVectorMA( transformed[i], v[2], tr.or.axis[2], transformed[i] );\n\t}\n\n\t// check against frustum planes\n\tanyBack = 0;\n\tfor (i = 0 ; i < 4 ; i++) {\n\t\tfrust = &tr.viewParms.frustum[i];\n\n\t\tfront = back = 0;\n\t\tfor (j = 0 ; j < 8 ; j++) {\n\t\t\tdists[j] = DotProduct(transformed[j], frust->normal);\n\t\t\tif ( dists[j] > frust->dist ) {\n\t\t\t\tfront = 1;\n\t\t\t\tif ( back ) {\n\t\t\t\t\tbreak;\t\t// a point is in front\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tback = 1;\n\t\t\t}\n\t\t}\n\t\tif ( !front ) {\n\t\t\t// all points were behind one of the planes\n\t\t\treturn CULL_OUT;\n\t\t}\n\t\tanyBack |= back;\n\t}\n\n\tif ( !anyBack ) {\n\t\treturn CULL_IN;\t\t// completely inside frustum\n\t}\n\n\treturn CULL_CLIP;\t\t// partially clipped\n}\n\n/*\n** R_CullLocalPointAndRadius\n*/\nint R_CullLocalPointAndRadius( vec3_t pt, float radius )\n{\n\tvec3_t transformed;\n\n\tR_LocalPointToWorld( pt, transformed );\n\n\treturn R_CullPointAndRadius( transformed, radius );\n}\n\n/*\n** R_CullPointAndRadius\n*/\nint R_CullPointAndRadius( vec3_t pt, float radius )\n{\n\tint\t\ti;\n\tfloat\tdist;\n\tcplane_t\t*frust;\n\tqboolean mightBeClipped = qfalse;\n\n\tif ( r_nocull->integer ) {\n\t\treturn CULL_CLIP;\n\t}\n\n\t// check against frustum planes\n\tfor (i = 0 ; i < 4 ; i++) \n\t{\n\t\tfrust = &tr.viewParms.frustum[i];\n\n\t\tdist = DotProduct( pt, frust->normal) - frust->dist;\n\t\tif ( dist < -radius )\n\t\t{\n\t\t\treturn CULL_OUT;\n\t\t}\n\t\telse if ( dist <= radius ) \n\t\t{\n\t\t\tmightBeClipped = qtrue;\n\t\t}\n\t}\n\n\tif ( mightBeClipped )\n\t{\n\t\treturn CULL_CLIP;\n\t}\n\n\treturn CULL_IN;\t\t// completely inside frustum\n}\n\n\n/*\n=================\nR_LocalNormalToWorld\n\n=================\n*/\nvoid R_LocalNormalToWorld (vec3_t local, vec3_t world) {\n\tworld[0] = local[0] * tr.or.axis[0][0] + local[1] * tr.or.axis[1][0] + local[2] * tr.or.axis[2][0];\n\tworld[1] = local[0] * tr.or.axis[0][1] + local[1] * tr.or.axis[1][1] + local[2] * tr.or.axis[2][1];\n\tworld[2] = local[0] * tr.or.axis[0][2] + local[1] * tr.or.axis[1][2] + local[2] * tr.or.axis[2][2];\n}\n\n/*\n=================\nR_LocalPointToWorld\n\n=================\n*/\nvoid R_LocalPointToWorld (vec3_t local, vec3_t world) {\n\tworld[0] = local[0] * tr.or.axis[0][0] + local[1] * tr.or.axis[1][0] + local[2] * tr.or.axis[2][0] + tr.or.origin[0];\n\tworld[1] = local[0] * tr.or.axis[0][1] + local[1] * tr.or.axis[1][1] + local[2] * tr.or.axis[2][1] + tr.or.origin[1];\n\tworld[2] = local[0] * tr.or.axis[0][2] + local[1] * tr.or.axis[1][2] + local[2] * tr.or.axis[2][2] + tr.or.origin[2];\n}\n\n/*\n=================\nR_WorldToLocal\n\n=================\n*/\nvoid R_WorldToLocal (vec3_t world, vec3_t local) {\n\tlocal[0] = DotProduct(world, tr.or.axis[0]);\n\tlocal[1] = DotProduct(world, tr.or.axis[1]);\n\tlocal[2] = DotProduct(world, tr.or.axis[2]);\n}\n\n/*\n==========================\nR_TransformModelToClip\n\n==========================\n*/\nvoid R_TransformModelToClip( const vec3_t src, const float *modelMatrix, const float *projectionMatrix,\n\t\t\t\t\t\t\tvec4_t eye, vec4_t dst ) {\n\tint i;\n\n\tfor ( i = 0 ; i < 4 ; i++ ) {\n\t\teye[i] = \n\t\t\tsrc[0] * modelMatrix[ i + 0 * 4 ] +\n\t\t\tsrc[1] * modelMatrix[ i + 1 * 4 ] +\n\t\t\tsrc[2] * modelMatrix[ i + 2 * 4 ] +\n\t\t\t1 * modelMatrix[ i + 3 * 4 ];\n\t}\n\n\tfor ( i = 0 ; i < 4 ; i++ ) {\n\t\tdst[i] = \n\t\t\teye[0] * projectionMatrix[ i + 0 * 4 ] +\n\t\t\teye[1] * projectionMatrix[ i + 1 * 4 ] +\n\t\t\teye[2] * projectionMatrix[ i + 2 * 4 ] +\n\t\t\teye[3] * projectionMatrix[ i + 3 * 4 ];\n\t}\n}\n\n/*\n==========================\nmyGlMultMatrix\n\n==========================\n*/\n//\n// NOTE; out = b * a,\n// a, b and c are specified in column-major order\n//\nvoid myGlMultMatrix( const float *a, const float *b, float *out ) {\n\tint\t\ti, j;\n\n\tfor ( i = 0 ; i < 4 ; i++ ) {\n\t\tfor ( j = 0 ; j < 4 ; j++ ) {\n\t\t\tout[ i * 4 + j ] =\n\t\t\t\ta [ i * 4 + 0 ] * b [ 0 * 4 + j ]\n\t\t\t\t+ a [ i * 4 + 1 ] * b [ 1 * 4 + j ]\n\t\t\t\t+ a [ i * 4 + 2 ] * b [ 2 * 4 + j ]\n\t\t\t\t+ a [ i * 4 + 3 ] * b [ 3 * 4 + j ];\n\t\t}\n\t}\n}\n\n/*\n=================\nR_RotateForEntity\n\nGenerates an orientation for an entity and viewParms\nDoes NOT produce any GL calls\nCalled by both the front end and the back end\n=================\n*/\nvoid R_RotateForEntity( const trRefEntity_t *ent, const viewParms_t *viewParms,\n\t\t\t\t\t   orientationr_t *or ) {\n\tfloat\tglMatrix[16];\n\tvec3_t\tdelta;\n\tfloat\taxisLength;\n\n\tif ( ent->e.reType != RT_MODEL ) {\n\t\t*or = viewParms->world;\n\t\treturn;\n\t}\n\n\tVectorCopy( ent->e.origin, or->origin );\n\n\tVectorCopy( ent->e.axis[0], or->axis[0] );\n\tVectorCopy( ent->e.axis[1], or->axis[1] );\n\tVectorCopy( ent->e.axis[2], or->axis[2] );\n\n\tglMatrix[0] = or->axis[0][0];\n\tglMatrix[4] = or->axis[1][0];\n\tglMatrix[8] = or->axis[2][0];\n\tglMatrix[12] = or->origin[0];\n\n\tglMatrix[1] = or->axis[0][1];\n\tglMatrix[5] = or->axis[1][1];\n\tglMatrix[9] = or->axis[2][1];\n\tglMatrix[13] = or->origin[1];\n\n\tglMatrix[2] = or->axis[0][2];\n\tglMatrix[6] = or->axis[1][2];\n\tglMatrix[10] = or->axis[2][2];\n\tglMatrix[14] = or->origin[2];\n\n\tglMatrix[3] = 0;\n\tglMatrix[7] = 0;\n\tglMatrix[11] = 0;\n\tglMatrix[15] = 1;\n\n\tmyGlMultMatrix( glMatrix, viewParms->world.modelMatrix, or->modelMatrix );\n\n\t// calculate the viewer origin in the model's space\n\t// needed for fog, specular, and environment mapping\n\tVectorSubtract( viewParms->or.origin, or->origin, delta );\n\n\t// compensate for scale in the axes if necessary\n\tif ( ent->e.nonNormalizedAxes ) {\n\t\taxisLength = VectorLength( ent->e.axis[0] );\n\t\tif ( !axisLength ) {\n\t\t\taxisLength = 0;\n\t\t} else {\n\t\t\taxisLength = 1.0f / axisLength;\n\t\t}\n\t} else {\n\t\taxisLength = 1.0f;\n\t}\n\n\tor->viewOrigin[0] = DotProduct( delta, or->axis[0] ) * axisLength;\n\tor->viewOrigin[1] = DotProduct( delta, or->axis[1] ) * axisLength;\n\tor->viewOrigin[2] = DotProduct( delta, or->axis[2] ) * axisLength;\n}\n\n/*\n=================\nR_RotateForViewer\n\nSets up the modelview matrix for a given viewParm\n=================\n*/\nvoid R_RotateForViewer (void) \n{\n\tfloat\tviewerMatrix[16];\n\tvec3_t\torigin;\n\n\tCom_Memset (&tr.or, 0, sizeof(tr.or));\n\ttr.or.axis[0][0] = 1;\n\ttr.or.axis[1][1] = 1;\n\ttr.or.axis[2][2] = 1;\n\tVectorCopy (tr.viewParms.or.origin, tr.or.viewOrigin);\n\n\t// transform by the camera placement\n\tVectorCopy( tr.viewParms.or.origin, origin );\n\n\tviewerMatrix[0] = tr.viewParms.or.axis[0][0];\n\tviewerMatrix[4] = tr.viewParms.or.axis[0][1];\n\tviewerMatrix[8] = tr.viewParms.or.axis[0][2];\n\tviewerMatrix[12] = -origin[0] * viewerMatrix[0] + -origin[1] * viewerMatrix[4] + -origin[2] * viewerMatrix[8];\n\n\tviewerMatrix[1] = tr.viewParms.or.axis[1][0];\n\tviewerMatrix[5] = tr.viewParms.or.axis[1][1];\n\tviewerMatrix[9] = tr.viewParms.or.axis[1][2];\n\tviewerMatrix[13] = -origin[0] * viewerMatrix[1] + -origin[1] * viewerMatrix[5] + -origin[2] * viewerMatrix[9];\n\n\tviewerMatrix[2] = tr.viewParms.or.axis[2][0];\n\tviewerMatrix[6] = tr.viewParms.or.axis[2][1];\n\tviewerMatrix[10] = tr.viewParms.or.axis[2][2];\n\tviewerMatrix[14] = -origin[0] * viewerMatrix[2] + -origin[1] * viewerMatrix[6] + -origin[2] * viewerMatrix[10];\n\n\tviewerMatrix[3] = 0;\n\tviewerMatrix[7] = 0;\n\tviewerMatrix[11] = 0;\n\tviewerMatrix[15] = 1;\n\n\t// convert from our coordinate system (looking down X)\n\t// to OpenGL's coordinate system (looking down -Z)\n\tmyGlMultMatrix( viewerMatrix, s_flipMatrix, tr.or.modelMatrix );\n\n\ttr.viewParms.world = tr.or;\n\n}\n\n/*\n** SetFarClip\n*/\nstatic void SetFarClip( void )\n{\n\tfloat\tfarthestCornerDistance = 0;\n\tint\t\ti;\n\n\t// if not rendering the world (icons, menus, etc)\n\t// set a 2k far clip plane\n\tif ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {\n\t\ttr.viewParms.zFar = 2048;\n\t\treturn;\n\t}\n\n\t//\n\t// set far clipping planes dynamically\n\t//\n\tfarthestCornerDistance = 0;\n\tfor ( i = 0; i < 8; i++ )\n\t{\n\t\tvec3_t v;\n\t\tvec3_t vecTo;\n\t\tfloat distance;\n\n\t\tif ( i & 1 )\n\t\t{\n\t\t\tv[0] = tr.viewParms.visBounds[0][0];\n\t\t}\n\t\telse\n\t\t{\n\t\t\tv[0] = tr.viewParms.visBounds[1][0];\n\t\t}\n\n\t\tif ( i & 2 )\n\t\t{\n\t\t\tv[1] = tr.viewParms.visBounds[0][1];\n\t\t}\n\t\telse\n\t\t{\n\t\t\tv[1] = tr.viewParms.visBounds[1][1];\n\t\t}\n\n\t\tif ( i & 4 )\n\t\t{\n\t\t\tv[2] = tr.viewParms.visBounds[0][2];\n\t\t}\n\t\telse\n\t\t{\n\t\t\tv[2] = tr.viewParms.visBounds[1][2];\n\t\t}\n\n\t\tVectorSubtract( v, tr.viewParms.or.origin, vecTo );\n\n\t\tdistance = vecTo[0] * vecTo[0] + vecTo[1] * vecTo[1] + vecTo[2] * vecTo[2];\n\n\t\tif ( distance > farthestCornerDistance )\n\t\t{\n\t\t\tfarthestCornerDistance = distance;\n\t\t}\n\t}\n\ttr.viewParms.zFar = sqrt( farthestCornerDistance );\n}\n\n\n/*\n===============\nR_SetupProjection\n===============\n*/\nvoid R_SetupProjection( void ) {\n\tfloat\txmin, xmax, ymin, ymax;\n\tfloat\twidth, height, depth;\n\tfloat\tzNear, zFar;\n\n\t// dynamically compute far clip plane distance\n\tSetFarClip();\n\n\t//\n\t// set up projection matrix\n\t//\n\tzNear\t= r_znear->value;\n\tzFar\t= tr.viewParms.zFar;\n\n\tymax = zNear * tan( tr.refdef.fov_y * M_PI / 360.0f );\n\tymin = -ymax;\n\n\txmax = zNear * tan( tr.refdef.fov_x * M_PI / 360.0f );\n\txmin = -xmax;\n\n\twidth = xmax - xmin;\n\theight = ymax - ymin;\n\tdepth = zFar - zNear;\n\n\ttr.viewParms.projectionMatrix[0] = 2 * zNear / width;\n\ttr.viewParms.projectionMatrix[4] = 0;\n\ttr.viewParms.projectionMatrix[8] = ( xmax + xmin ) / width;\t// normally 0\n\ttr.viewParms.projectionMatrix[12] = 0;\n\n\ttr.viewParms.projectionMatrix[1] = 0;\n\ttr.viewParms.projectionMatrix[5] = 2 * zNear / height;\n\ttr.viewParms.projectionMatrix[9] = ( ymax + ymin ) / height;\t// normally 0\n\ttr.viewParms.projectionMatrix[13] = 0;\n\n\ttr.viewParms.projectionMatrix[2] = 0;\n\ttr.viewParms.projectionMatrix[6] = 0;\n\ttr.viewParms.projectionMatrix[10] = -( zFar + zNear ) / depth;\n\ttr.viewParms.projectionMatrix[14] = -2 * zFar * zNear / depth;\n\n\ttr.viewParms.projectionMatrix[3] = 0;\n\ttr.viewParms.projectionMatrix[7] = 0;\n\ttr.viewParms.projectionMatrix[11] = -1;\n\ttr.viewParms.projectionMatrix[15] = 0;\n}\n\n/*\n=================\nR_SetupFrustum\n\nSetup that culling frustum planes for the current view\n=================\n*/\nvoid R_SetupFrustum (void) {\n\tint\t\ti;\n\tfloat\txs, xc;\n\tfloat\tang;\n\n\tang = tr.viewParms.fovX / 180 * M_PI * 0.5f;\n\txs = sin( ang );\n\txc = cos( ang );\n\n\tVectorScale( tr.viewParms.or.axis[0], xs, tr.viewParms.frustum[0].normal );\n\tVectorMA( tr.viewParms.frustum[0].normal, xc, tr.viewParms.or.axis[1], tr.viewParms.frustum[0].normal );\n\n\tVectorScale( tr.viewParms.or.axis[0], xs, tr.viewParms.frustum[1].normal );\n\tVectorMA( tr.viewParms.frustum[1].normal, -xc, tr.viewParms.or.axis[1], tr.viewParms.frustum[1].normal );\n\n\tang = tr.viewParms.fovY / 180 * M_PI * 0.5f;\n\txs = sin( ang );\n\txc = cos( ang );\n\n\tVectorScale( tr.viewParms.or.axis[0], xs, tr.viewParms.frustum[2].normal );\n\tVectorMA( tr.viewParms.frustum[2].normal, xc, tr.viewParms.or.axis[2], tr.viewParms.frustum[2].normal );\n\n\tVectorScale( tr.viewParms.or.axis[0], xs, tr.viewParms.frustum[3].normal );\n\tVectorMA( tr.viewParms.frustum[3].normal, -xc, tr.viewParms.or.axis[2], tr.viewParms.frustum[3].normal );\n\n\tfor (i=0 ; i<4 ; i++) {\n\t\ttr.viewParms.frustum[i].type = PLANE_NON_AXIAL;\n\t\ttr.viewParms.frustum[i].dist = DotProduct (tr.viewParms.or.origin, tr.viewParms.frustum[i].normal);\n\t\tSetPlaneSignbits( &tr.viewParms.frustum[i] );\n\t}\n}\n\n\n/*\n=================\nR_MirrorPoint\n=================\n*/\nvoid R_MirrorPoint (vec3_t in, orientation_t *surface, orientation_t *camera, vec3_t out) {\n\tint\t\ti;\n\tvec3_t\tlocal;\n\tvec3_t\ttransformed;\n\tfloat\td;\n\n\tVectorSubtract( in, surface->origin, local );\n\n\tVectorClear( transformed );\n\tfor ( i = 0 ; i < 3 ; i++ ) {\n\t\td = DotProduct(local, surface->axis[i]);\n\t\tVectorMA( transformed, d, camera->axis[i], transformed );\n\t}\n\n\tVectorAdd( transformed, camera->origin, out );\n}\n\nvoid R_MirrorVector (vec3_t in, orientation_t *surface, orientation_t *camera, vec3_t out) {\n\tint\t\ti;\n\tfloat\td;\n\n\tVectorClear( out );\n\tfor ( i = 0 ; i < 3 ; i++ ) {\n\t\td = DotProduct(in, surface->axis[i]);\n\t\tVectorMA( out, d, camera->axis[i], out );\n\t}\n}\n\n\n/*\n=============\nR_PlaneForSurface\n=============\n*/\nvoid R_PlaneForSurface (surfaceType_t *surfType, cplane_t *plane) {\n\tsrfTriangles_t\t*tri;\n\tsrfPoly_t\t\t*poly;\n\tdrawVert_t\t\t*v1, *v2, *v3;\n\tvec4_t\t\t\tplane4;\n\n\tif (!surfType) {\n\t\tCom_Memset (plane, 0, sizeof(*plane));\n\t\tplane->normal[0] = 1;\n\t\treturn;\n\t}\n\tswitch (*surfType) {\n\tcase SF_FACE:\n\t\t*plane = ((srfSurfaceFace_t *)surfType)->plane;\n\t\treturn;\n\tcase SF_TRIANGLES:\n\t\ttri = (srfTriangles_t *)surfType;\n\t\tv1 = tri->verts + tri->indexes[0];\n\t\tv2 = tri->verts + tri->indexes[1];\n\t\tv3 = tri->verts + tri->indexes[2];\n\t\tPlaneFromPoints( plane4, v1->xyz, v2->xyz, v3->xyz );\n\t\tVectorCopy( plane4, plane->normal ); \n\t\tplane->dist = plane4[3];\n\t\treturn;\n\tcase SF_POLY:\n\t\tpoly = (srfPoly_t *)surfType;\n\t\tPlaneFromPoints( plane4, poly->verts[0].xyz, poly->verts[1].xyz, poly->verts[2].xyz );\n\t\tVectorCopy( plane4, plane->normal ); \n\t\tplane->dist = plane4[3];\n\t\treturn;\n\tdefault:\n\t\tCom_Memset (plane, 0, sizeof(*plane));\n\t\tplane->normal[0] = 1;\t\t\n\t\treturn;\n\t}\n}\n\n/*\n=================\nR_GetPortalOrientation\n\nentityNum is the entity that the portal surface is a part of, which may\nbe moving and rotating.\n\nReturns qtrue if it should be mirrored\n=================\n*/\nqboolean R_GetPortalOrientations( drawSurf_t *drawSurf, int entityNum, \n\t\t\t\t\t\t\t orientation_t *surface, orientation_t *camera,\n\t\t\t\t\t\t\t vec3_t pvsOrigin, qboolean *mirror ) {\n\tint\t\t\ti;\n\tcplane_t\toriginalPlane, plane;\n\ttrRefEntity_t\t*e;\n\tfloat\t\td;\n\tvec3_t\t\ttransformed;\n\n\t// create plane axis for the portal we are seeing\n\tR_PlaneForSurface( drawSurf->surface, &originalPlane );\n\n\t// rotate the plane if necessary\n\tif ( entityNum != ENTITYNUM_WORLD ) {\n\t\ttr.currentEntityNum = entityNum;\n\t\ttr.currentEntity = &tr.refdef.entities[entityNum];\n\n\t\t// get the orientation of the entity\n\t\tR_RotateForEntity( tr.currentEntity, &tr.viewParms, &tr.or );\n\n\t\t// rotate the plane, but keep the non-rotated version for matching\n\t\t// against the portalSurface entities\n\t\tR_LocalNormalToWorld( originalPlane.normal, plane.normal );\n\t\tplane.dist = originalPlane.dist + DotProduct( plane.normal, tr.or.origin );\n\n\t\t// translate the original plane\n\t\toriginalPlane.dist = originalPlane.dist + DotProduct( originalPlane.normal, tr.or.origin );\n\t} else {\n\t\tplane = originalPlane;\n\t}\n\n\tVectorCopy( plane.normal, surface->axis[0] );\n\tPerpendicularVector( surface->axis[1], surface->axis[0] );\n\tCrossProduct( surface->axis[0], surface->axis[1], surface->axis[2] );\n\n\t// locate the portal entity closest to this plane.\n\t// origin will be the origin of the portal, origin2 will be\n\t// the origin of the camera\n\tfor ( i = 0 ; i < tr.refdef.num_entities ; i++ ) {\n\t\te = &tr.refdef.entities[i];\n\t\tif ( e->e.reType != RT_PORTALSURFACE ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\td = DotProduct( e->e.origin, originalPlane.normal ) - originalPlane.dist;\n\t\tif ( d > 64 || d < -64) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// get the pvsOrigin from the entity\n\t\tVectorCopy( e->e.oldorigin, pvsOrigin );\n\n\t\t// if the entity is just a mirror, don't use as a camera point\n\t\tif ( e->e.oldorigin[0] == e->e.origin[0] && \n\t\t\te->e.oldorigin[1] == e->e.origin[1] && \n\t\t\te->e.oldorigin[2] == e->e.origin[2] ) {\n\t\t\tVectorScale( plane.normal, plane.dist, surface->origin );\n\t\t\tVectorCopy( surface->origin, camera->origin );\n\t\t\tVectorSubtract( vec3_origin, surface->axis[0], camera->axis[0] );\n\t\t\tVectorCopy( surface->axis[1], camera->axis[1] );\n\t\t\tVectorCopy( surface->axis[2], camera->axis[2] );\n\n\t\t\t*mirror = qtrue;\n\t\t\treturn qtrue;\n\t\t}\n\n\t\t// project the origin onto the surface plane to get\n\t\t// an origin point we can rotate around\n\t\td = DotProduct( e->e.origin, plane.normal ) - plane.dist;\n\t\tVectorMA( e->e.origin, -d, surface->axis[0], surface->origin );\n\t\t\t\n\t\t// now get the camera origin and orientation\n\t\tVectorCopy( e->e.oldorigin, camera->origin );\n\t\tAxisCopy( e->e.axis, camera->axis );\n\t\tVectorSubtract( vec3_origin, camera->axis[0], camera->axis[0] );\n\t\tVectorSubtract( vec3_origin, camera->axis[1], camera->axis[1] );\n\n\t\t// optionally rotate\n\t\tif ( e->e.oldframe ) {\n\t\t\t// if a speed is specified\n\t\t\tif ( e->e.frame ) {\n\t\t\t\t// continuous rotate\n\t\t\t\td = (tr.refdef.time/1000.0f) * e->e.frame;\n\t\t\t\tVectorCopy( camera->axis[1], transformed );\n\t\t\t\tRotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d );\n\t\t\t\tCrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] );\n\t\t\t} else {\n\t\t\t\t// bobbing rotate, with skinNum being the rotation offset\n\t\t\t\td = sin( tr.refdef.time * 0.003f );\n\t\t\t\td = e->e.skinNum + d * 4;\n\t\t\t\tVectorCopy( camera->axis[1], transformed );\n\t\t\t\tRotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d );\n\t\t\t\tCrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] );\n\t\t\t}\n\t\t}\n\t\telse if ( e->e.skinNum ) {\n\t\t\td = e->e.skinNum;\n\t\t\tVectorCopy( camera->axis[1], transformed );\n\t\t\tRotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d );\n\t\t\tCrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] );\n\t\t}\n\t\t*mirror = qfalse;\n\t\treturn qtrue;\n\t}\n\n\t// if we didn't locate a portal entity, don't render anything.\n\t// We don't want to just treat it as a mirror, because without a\n\t// portal entity the server won't have communicated a proper entity set\n\t// in the snapshot\n\n\t// unfortunately, with local movement prediction it is easily possible\n\t// to see a surface before the server has communicated the matching\n\t// portal surface entity, so we don't want to print anything here...\n\n\t//ri.Printf( PRINT_ALL, \"Portal surface without a portal entity\\n\" );\n\n\treturn qfalse;\n}\n\nstatic qboolean IsMirror( const drawSurf_t *drawSurf, int entityNum )\n{\n\tint\t\t\ti;\n\tcplane_t\toriginalPlane, plane;\n\ttrRefEntity_t\t*e;\n\tfloat\t\td;\n\n\t// create plane axis for the portal we are seeing\n\tR_PlaneForSurface( drawSurf->surface, &originalPlane );\n\n\t// rotate the plane if necessary\n\tif ( entityNum != ENTITYNUM_WORLD ) \n\t{\n\t\ttr.currentEntityNum = entityNum;\n\t\ttr.currentEntity = &tr.refdef.entities[entityNum];\n\n\t\t// get the orientation of the entity\n\t\tR_RotateForEntity( tr.currentEntity, &tr.viewParms, &tr.or );\n\n\t\t// rotate the plane, but keep the non-rotated version for matching\n\t\t// against the portalSurface entities\n\t\tR_LocalNormalToWorld( originalPlane.normal, plane.normal );\n\t\tplane.dist = originalPlane.dist + DotProduct( plane.normal, tr.or.origin );\n\n\t\t// translate the original plane\n\t\toriginalPlane.dist = originalPlane.dist + DotProduct( originalPlane.normal, tr.or.origin );\n\t} \n\telse \n\t{\n\t\tplane = originalPlane;\n\t}\n\n\t// locate the portal entity closest to this plane.\n\t// origin will be the origin of the portal, origin2 will be\n\t// the origin of the camera\n\tfor ( i = 0 ; i < tr.refdef.num_entities ; i++ ) \n\t{\n\t\te = &tr.refdef.entities[i];\n\t\tif ( e->e.reType != RT_PORTALSURFACE ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\td = DotProduct( e->e.origin, originalPlane.normal ) - originalPlane.dist;\n\t\tif ( d > 64 || d < -64) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// if the entity is just a mirror, don't use as a camera point\n\t\tif ( e->e.oldorigin[0] == e->e.origin[0] && \n\t\t\te->e.oldorigin[1] == e->e.origin[1] && \n\t\t\te->e.oldorigin[2] == e->e.origin[2] ) \n\t\t{\n\t\t\treturn qtrue;\n\t\t}\n\n\t\treturn qfalse;\n\t}\n\treturn qfalse;\n}\n\n/*\n** SurfIsOffscreen\n**\n** Determines if a surface is completely offscreen.\n*/\nstatic qboolean SurfIsOffscreen( const drawSurf_t *drawSurf, vec4_t clipDest[128] ) {\n\tfloat shortest = 100000000;\n\tint entityNum;\n\tint numTriangles;\n\tshader_t *shader;\n\tint\t\tfogNum;\n\tint dlighted;\n\tvec4_t clip, eye;\n\tint i;\n\tunsigned int pointOr = 0;\n\tunsigned int pointAnd = (unsigned int)~0;\n\n\tif ( glConfig.smpActive ) {\t\t// FIXME!  we can't do RB_BeginSurface/RB_EndSurface stuff with smp!\n\t\treturn qfalse;\n\t}\n\n\tR_RotateForViewer();\n\n\tR_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted );\n\tRB_BeginSurface( shader, fogNum );\n\trb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface );\n\n\tassert( tess.numVertexes < 128 );\n\n\tfor ( i = 0; i < tess.numVertexes; i++ )\n\t{\n\t\tint j;\n\t\tunsigned int pointFlags = 0;\n\n\t\tR_TransformModelToClip( tess.xyz[i], tr.or.modelMatrix, tr.viewParms.projectionMatrix, eye, clip );\n\n\t\tfor ( j = 0; j < 3; j++ )\n\t\t{\n\t\t\tif ( clip[j] >= clip[3] )\n\t\t\t{\n\t\t\t\tpointFlags |= (1 << (j*2));\n\t\t\t}\n\t\t\telse if ( clip[j] <= -clip[3] )\n\t\t\t{\n\t\t\t\tpointFlags |= ( 1 << (j*2+1));\n\t\t\t}\n\t\t}\n\t\tpointAnd &= pointFlags;\n\t\tpointOr |= pointFlags;\n\t}\n\n\t// trivially reject\n\tif ( pointAnd )\n\t{\n        tess.numIndexes = 0;\n\t\treturn qtrue;\n\t}\n\n\t// determine if this surface is backfaced and also determine the distance\n\t// to the nearest vertex so we can cull based on portal range.  Culling\n\t// based on vertex distance isn't 100% correct (we should be checking for\n\t// range to the surface), but it's good enough for the types of portals\n\t// we have in the game right now.\n\tnumTriangles = tess.numIndexes / 3;\n\n\tfor ( i = 0; i < tess.numIndexes; i += 3 )\n\t{\n\t\tvec3_t normal;\n\t\tfloat dot;\n\t\tfloat len;\n\n\t\tVectorSubtract( tess.xyz[tess.indexes[i]], tr.viewParms.or.origin, normal );\n\n\t\tlen = VectorLengthSquared( normal );\t\t\t// lose the sqrt\n\t\tif ( len < shortest )\n\t\t{\n\t\t\tshortest = len;\n\t\t}\n\n\t\tif ( ( dot = DotProduct( normal, tess.normal[tess.indexes[i]] ) ) >= 0 )\n\t\t{\n\t\t\tnumTriangles--;\n\t\t}\n\t}\n    tess.numIndexes = 0;\n\tif ( !numTriangles )\n\t{\n\t\treturn qtrue;\n\t}\n\n\t// mirrors can early out at this point, since we don't do a fade over distance\n\t// with them (although we could)\n\tif ( IsMirror( drawSurf, entityNum ) )\n\t{\n\t\treturn qfalse;\n\t}\n\n\tif ( shortest > (tess.shader->portalRange*tess.shader->portalRange) )\n\t{\n\t\treturn qtrue;\n\t}\n\n\treturn qfalse;\n}\n\n/*\n========================\nR_MirrorViewBySurface\n\nReturns qtrue if another view has been rendered\n========================\n*/\nqboolean R_MirrorViewBySurface (drawSurf_t *drawSurf, int entityNum) {\n\tvec4_t\t\t\tclipDest[128];\n\tviewParms_t\t\tnewParms;\n\tviewParms_t\t\toldParms;\n\torientation_t\tsurface, camera;\n\n\t// don't recursively mirror\n\tif (tr.viewParms.isPortal) {\n\t\tri.Printf( PRINT_DEVELOPER, \"WARNING: recursive mirror/portal found\\n\" );\n\t\treturn qfalse;\n\t}\n\n\tif ( r_noportals->integer || (r_fastsky->integer == 1) ) {\n\t\treturn qfalse;\n\t}\n\n\t// trivially reject portal/mirror\n\tif ( SurfIsOffscreen( drawSurf, clipDest ) ) {\n\t\treturn qfalse;\n\t}\n\n\t// save old viewParms so we can return to it after the mirror view\n\toldParms = tr.viewParms;\n\n\tnewParms = tr.viewParms;\n\tnewParms.isPortal = qtrue;\n\tif ( !R_GetPortalOrientations( drawSurf, entityNum, &surface, &camera, \n\t\tnewParms.pvsOrigin, &newParms.isMirror ) ) {\n\t\treturn qfalse;\t\t// bad portal, no portalentity\n\t}\n\n\tR_MirrorPoint (oldParms.or.origin, &surface, &camera, newParms.or.origin );\n\n\tVectorSubtract( vec3_origin, camera.axis[0], newParms.portalPlane.normal );\n\tnewParms.portalPlane.dist = DotProduct( camera.origin, newParms.portalPlane.normal );\n\t\n\tR_MirrorVector (oldParms.or.axis[0], &surface, &camera, newParms.or.axis[0]);\n\tR_MirrorVector (oldParms.or.axis[1], &surface, &camera, newParms.or.axis[1]);\n\tR_MirrorVector (oldParms.or.axis[2], &surface, &camera, newParms.or.axis[2]);\n\n\t// OPTIMIZE: restrict the viewport on the mirrored view\n\n\t// render the mirror view\n\tR_RenderView (&newParms);\n\n\ttr.viewParms = oldParms;\n\n\treturn qtrue;\n}\n\n/*\n=================\nR_SpriteFogNum\n\nSee if a sprite is inside a fog volume\n=================\n*/\nint R_SpriteFogNum( trRefEntity_t *ent ) {\n\tint\t\t\t\ti, j;\n\tfog_t\t\t\t*fog;\n\n\tif ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {\n\t\treturn 0;\n\t}\n\n\tfor ( i = 1 ; i < tr.world->numfogs ; i++ ) {\n\t\tfog = &tr.world->fogs[i];\n\t\tfor ( j = 0 ; j < 3 ; j++ ) {\n\t\t\tif ( ent->e.origin[j] - ent->e.radius >= fog->bounds[1][j] ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( ent->e.origin[j] + ent->e.radius <= fog->bounds[0][j] ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif ( j == 3 ) {\n\t\t\treturn i;\n\t\t}\n\t}\n\n\treturn 0;\n}\n\n/*\n==========================================================================================\n\nDRAWSURF SORTING\n\n==========================================================================================\n*/\n\n/*\n=================\nqsort replacement\n\n=================\n*/\nID_INLINE void SWAP_DRAW_SURF(void* a, void* b) {\n    char buf[sizeof(drawSurf_t)];\n    Com_Memcpy(buf, a, sizeof(drawSurf_t));\n    Com_Memcpy(a, b, sizeof(drawSurf_t));\n    Com_Memcpy(b, buf, sizeof(drawSurf_t));\n}\n\n\n/* this parameter defines the cutoff between using quick sort and\n   insertion sort for arrays; arrays with lengths shorter or equal to the\n   below value use insertion sort */\n\n#define CUTOFF 8            /* testing shows that this is good value */\n\nstatic void shortsort( drawSurf_t *lo, drawSurf_t *hi ) {\n    drawSurf_t\t*p, *max;\n\n    while (hi > lo) {\n        max = lo;\n        for (p = lo + 1; p <= hi; p++ ) {\n            if ( p->sort > max->sort ) {\n                max = p;\n            }\n        }\n        SWAP_DRAW_SURF(max, hi);\n        hi--;\n    }\n}\n\n\n/* sort the array between lo and hi (inclusive)\nFIXME: this was lifted and modified from the microsoft lib source...\n */\n\nvoid qsortFast (\n    void *base,\n    unsigned num,\n    unsigned width\n    )\n{\n    char *lo, *hi;              /* ends of sub-array currently sorting */\n    char *mid;                  /* points to middle of subarray */\n    char *loguy, *higuy;        /* traveling pointers for partition step */\n    unsigned size;              /* size of the sub-array */\n    char *lostk[30], *histk[30];\n    int stkptr;                 /* stack for saving sub-array to be processed */\n\n    /* Note: the number of stack entries required is no more than\n       1 + log2(size), so 30 is sufficient for any array */\n\n    if (num < 2 || width == 0)\n        return;                 /* nothing to do */\n\n    stkptr = 0;                 /* initialize stack */\n\n    lo = (char*) base;\n    hi = (char *)base + width * (num-1);        /* initialize limits */\n\n    /* this entry point is for pseudo-recursion calling: setting\n       lo and hi and jumping to here is like recursion, but stkptr is\n       prserved, locals aren't, so we preserve stuff on the stack */\nrecurse:\n\n    size = (hi - lo) / width + 1;        /* number of el's to sort */\n\n    /* below a certain size, it is faster to use a O(n^2) sorting method */\n    if (size <= CUTOFF) {\n         shortsort((drawSurf_t *)lo, (drawSurf_t *)hi);\n    }\n    else {\n        /* First we pick a partititioning element.  The efficiency of the\n           algorithm demands that we find one that is approximately the\n           median of the values, but also that we select one fast.  Using\n           the first one produces bad performace if the array is already\n           sorted, so we use the middle one, which would require a very\n           wierdly arranged array for worst case performance.  Testing shows\n           that a median-of-three algorithm does not, in general, increase\n           performance. */\n\n        mid = lo + (size / 2) * width;      /* find middle element */\n        SWAP_DRAW_SURF(mid, lo);               /* swap it to beginning of array */\n\n        /* We now wish to partition the array into three pieces, one\n           consisiting of elements <= partition element, one of elements\n           equal to the parition element, and one of element >= to it.  This\n           is done below; comments indicate conditions established at every\n           step. */\n\n        loguy = lo;\n        higuy = hi + width;\n\n        /* Note that higuy decreases and loguy increases on every iteration,\n           so loop must terminate. */\n        for (;;) {\n            /* lo <= loguy < hi, lo < higuy <= hi + 1,\n               A[i] <= A[lo] for lo <= i <= loguy,\n               A[i] >= A[lo] for higuy <= i <= hi */\n\n            do  {\n                loguy += width;\n            } while (loguy <= hi &&  \n\t\t\t\t( ((drawSurf_t *)loguy)->sort <= ((drawSurf_t *)lo)->sort ) );\n\n            /* lo < loguy <= hi+1, A[i] <= A[lo] for lo <= i < loguy,\n               either loguy > hi or A[loguy] > A[lo] */\n\n            do  {\n                higuy -= width;\n            } while (higuy > lo && \n\t\t\t\t( ((drawSurf_t *)higuy)->sort >= ((drawSurf_t *)lo)->sort ) );\n\n            /* lo-1 <= higuy <= hi, A[i] >= A[lo] for higuy < i <= hi,\n               either higuy <= lo or A[higuy] < A[lo] */\n\n            if (higuy < loguy)\n                break;\n\n            /* if loguy > hi or higuy <= lo, then we would have exited, so\n               A[loguy] > A[lo], A[higuy] < A[lo],\n               loguy < hi, highy > lo */\n\n            SWAP_DRAW_SURF(loguy, higuy);\n\n            /* A[loguy] < A[lo], A[higuy] > A[lo]; so condition at top\n               of loop is re-established */\n        }\n\n        /*     A[i] >= A[lo] for higuy < i <= hi,\n               A[i] <= A[lo] for lo <= i < loguy,\n               higuy < loguy, lo <= higuy <= hi\n           implying:\n               A[i] >= A[lo] for loguy <= i <= hi,\n               A[i] <= A[lo] for lo <= i <= higuy,\n               A[i] = A[lo] for higuy < i < loguy */\n\n        SWAP_DRAW_SURF(lo, higuy);     /* put partition element in place */\n\n        /* OK, now we have the following:\n              A[i] >= A[higuy] for loguy <= i <= hi,\n              A[i] <= A[higuy] for lo <= i < higuy\n              A[i] = A[lo] for higuy <= i < loguy    */\n\n        /* We've finished the partition, now we want to sort the subarrays\n           [lo, higuy-1] and [loguy, hi].\n           We do the smaller one first to minimize stack usage.\n           We only sort arrays of length 2 or more.*/\n\n        if ( higuy - 1 - lo >= hi - loguy ) {\n            if (lo + width < higuy) {\n                lostk[stkptr] = lo;\n                histk[stkptr] = higuy - width;\n                ++stkptr;\n            }                           /* save big recursion for later */\n\n            if (loguy < hi) {\n                lo = loguy;\n                goto recurse;           /* do small recursion */\n            }\n        }\n        else {\n            if (loguy < hi) {\n                lostk[stkptr] = loguy;\n                histk[stkptr] = hi;\n                ++stkptr;               /* save big recursion for later */\n            }\n\n            if (lo + width < higuy) {\n                hi = higuy - width;\n                goto recurse;           /* do small recursion */\n            }\n        }\n    }\n\n    /* We have sorted the array, except for any pending sorts on the stack.\n       Check if there are any, and do them. */\n\n    --stkptr;\n    if (stkptr >= 0) {\n        lo = lostk[stkptr];\n        hi = histk[stkptr];\n        goto recurse;           /* pop subarray from stack */\n    }\n    else\n        return;                 /* all subarrays done */\n}\n\n\n//==========================================================================================\n\n/*\n=================\nR_AddDrawSurf\n=================\n*/\nvoid R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, \n\t\t\t\t   int fogIndex, int dlightMap ) {\n\tint\t\t\tindex;\n\n\t// instead of checking for overflow, we just mask the index\n\t// so it wraps around\n\tindex = tr.refdef.numDrawSurfs & DRAWSURF_MASK;\n\t// the sort data is packed into a single 32 bit value so it can be\n\t// compared quickly during the qsorting process\n\ttr.refdef.drawSurfs[index].sort = (shader->sortedIndex << QSORT_SHADERNUM_SHIFT) \n\t\t| tr.shiftedEntityNum | ( fogIndex << QSORT_FOGNUM_SHIFT ) | (int)dlightMap;\n\ttr.refdef.drawSurfs[index].surface = surface;\n\ttr.refdef.numDrawSurfs++;\n}\n\n/*\n=================\nR_DecomposeSort\n=================\n*/\nvoid R_DecomposeSort( unsigned sort, int *entityNum, shader_t **shader, \n\t\t\t\t\t int *fogNum, int *dlightMap ) {\n\t*fogNum = ( sort >> QSORT_FOGNUM_SHIFT ) & 31;\n\t*shader = tr.sortedShaders[ ( sort >> QSORT_SHADERNUM_SHIFT ) & (MAX_SHADERS-1) ];\n\t*entityNum = ( sort >> QSORT_ENTITYNUM_SHIFT ) & 1023;\n\t*dlightMap = sort & 3;\n}\n\n/*\n=================\nR_SortDrawSurfs\n=================\n*/\nvoid R_SortDrawSurfs( drawSurf_t *drawSurfs, int numDrawSurfs ) {\n\tshader_t\t\t*shader;\n\tint\t\t\t\tfogNum;\n\tint\t\t\t\tentityNum;\n\tint\t\t\t\tdlighted;\n\tint\t\t\t\ti;\n\n\t// it is possible for some views to not have any surfaces\n\tif ( numDrawSurfs < 1 ) {\n\t\t// we still need to add it for hyperspace cases\n\t\tR_AddDrawSurfCmd( drawSurfs, numDrawSurfs );\n\t\treturn;\n\t}\n\n\t// if we overflowed MAX_DRAWSURFS, the drawsurfs\n\t// wrapped around in the buffer and we will be missing\n\t// the first surfaces, not the last ones\n\tif ( numDrawSurfs > MAX_DRAWSURFS ) {\n\t\tnumDrawSurfs = MAX_DRAWSURFS;\n\t}\n\n\t// sort the drawsurfs by sort type, then orientation, then shader\n\tqsortFast (drawSurfs, numDrawSurfs, sizeof(drawSurf_t) );\n\n\t// check for any pass through drawing, which\n\t// may cause another view to be rendered first\n\tfor ( i = 0 ; i < numDrawSurfs ; i++ ) {\n\t\tR_DecomposeSort( (drawSurfs+i)->sort, &entityNum, &shader, &fogNum, &dlighted );\n\n\t\tif ( shader->sort > SS_PORTAL ) {\n\t\t\tbreak;\n\t\t}\n\n\t\t// no shader should ever have this sort type\n\t\tif ( shader->sort == SS_BAD ) {\n\t\t\tri.Error (ERR_DROP, \"Shader '%s'with sort == SS_BAD\", shader->name );\n\t\t}\n\n\t\t// if the mirror was completely clipped away, we may need to check another surface\n\t\tif ( R_MirrorViewBySurface( (drawSurfs+i), entityNum) ) {\n\t\t\t// this is a debug option to see exactly what is being mirrored\n\t\t\tif ( r_portalOnly->integer ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tbreak;\t\t// only one mirror view at a time\n\t\t}\n\t}\n\n\tR_AddDrawSurfCmd( drawSurfs, numDrawSurfs );\n}\n\n/*\n=============\nR_AddEntitySurfaces\n=============\n*/\nvoid R_AddEntitySurfaces (void) {\n\ttrRefEntity_t\t*ent;\n\tshader_t\t\t*shader;\n\n\tif ( !r_drawentities->integer ) {\n\t\treturn;\n\t}\n\n\tfor ( tr.currentEntityNum = 0; \n\t      tr.currentEntityNum < tr.refdef.num_entities; \n\t\t  tr.currentEntityNum++ ) {\n\t\tent = tr.currentEntity = &tr.refdef.entities[tr.currentEntityNum];\n\n\t\tent->needDlights = qfalse;\n\n\t\t// preshift the value we are going to OR into the drawsurf sort\n\t\ttr.shiftedEntityNum = tr.currentEntityNum << QSORT_ENTITYNUM_SHIFT;\n\n\t\t//\n\t\t// the weapon model must be handled special --\n\t\t// we don't want the hacked weapon position showing in \n\t\t// mirrors, because the true body position will already be drawn\n\t\t//\n\t\tif ( (ent->e.renderfx & RF_FIRST_PERSON) && tr.viewParms.isPortal) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// simple generated models, like sprites and beams, are not culled\n\t\tswitch ( ent->e.reType ) {\n\t\tcase RT_PORTALSURFACE:\n\t\t\tbreak;\t\t// don't draw anything\n\t\tcase RT_SPRITE:\n\t\tcase RT_BEAM:\n\t\tcase RT_LIGHTNING:\n\t\tcase RT_RAIL_CORE:\n\t\tcase RT_RAIL_RINGS:\n\t\t\t// self blood sprites, talk balloons, etc should not be drawn in the primary\n\t\t\t// view.  We can't just do this check for all entities, because md3\n\t\t\t// entities may still want to cast shadows from them\n\t\t\tif ( (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tshader = R_GetShaderByHandle( ent->e.customShader );\n\t\t\tR_AddDrawSurf( &entitySurface, shader, R_SpriteFogNum( ent ), 0 );\n\t\t\tbreak;\n\n\t\tcase RT_MODEL:\n\t\t\t// we must set up parts of tr.or for model culling\n\t\t\tR_RotateForEntity( ent, &tr.viewParms, &tr.or );\n\n\t\t\ttr.currentModel = R_GetModelByHandle( ent->e.hModel );\n\t\t\tif (!tr.currentModel) {\n\t\t\t\tR_AddDrawSurf( &entitySurface, tr.defaultShader, 0, 0 );\n\t\t\t} else {\n\t\t\t\tswitch ( tr.currentModel->type ) {\n\t\t\t\tcase MOD_MESH:\n\t\t\t\t\tR_AddMD3Surfaces( ent );\n\t\t\t\t\tbreak;\n\t\t\t\tcase MOD_MD4:\n\t\t\t\t\tR_AddAnimSurfaces( ent );\n\t\t\t\t\tbreak;\n\t\t\t\tcase MOD_BRUSH:\n\t\t\t\t\tR_AddBrushModelSurfaces( ent );\n\t\t\t\t\tbreak;\n\t\t\t\tcase MOD_BAD:\t\t// null model axis\n\t\t\t\t\tif ( (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tshader = R_GetShaderByHandle( ent->e.customShader );\n\t\t\t\t\tR_AddDrawSurf( &entitySurface, tr.defaultShader, 0, 0 );\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tri.Error( ERR_DROP, \"R_AddEntitySurfaces: Bad modeltype\" );\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tri.Error( ERR_DROP, \"R_AddEntitySurfaces: Bad reType\" );\n\t\t}\n\t}\n\n}\n\n\n/*\n====================\nR_GenerateDrawSurfs\n====================\n*/\nvoid R_GenerateDrawSurfs( void ) {\n\tR_AddWorldSurfaces ();\n\n\tR_AddPolygonSurfaces();\n\n\t// set the projection matrix with the minimum zfar\n\t// now that we have the world bounded\n\t// this needs to be done before entities are\n\t// added, because they use the projection\n\t// matrix for lod calculation\n\tR_SetupProjection ();\n\n\tR_AddEntitySurfaces ();\n}\n\n/*\n================\nR_DebugPolygon\n================\n*/\nvoid R_DebugPolygon( int color, int numPoints, float *points ) {\n\tGL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );\n\n\t// draw solid shade\n\n\tqglColor3f( color&1, (color>>1)&1, (color>>2)&1 );\n\tqglBegin( GL_POLYGON );\n\tfor (int i = 0 ; i < numPoints ; i++ ) {\n\t\tqglVertex3fv( points + i * 3 );\n\t}\n\tqglEnd();\n\n\t// draw wireframe outline\n\tGL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );\n\tqglDepthRange( 0, 0 );\n\tqglColor3f( 1, 1, 1 );\n\tqglBegin( GL_POLYGON );\n\tfor (int i = 0 ; i < numPoints ; i++ ) {\n\t\tqglVertex3fv( points + i * 3 );\n\t}\n\tqglEnd();\n\tqglDepthRange( 0, 1 );\n\n\t// VULKAN\n\t// DX12\n\tif (!vk.active && !dx.active)\n\t\treturn;\n\tif (numPoints < 3 || numPoints >= SHADER_MAX_VERTEXES/2)\n\t\treturn;\n\n\t// In Vulkan we don't have GL_POLYGON + GLS_POLYMODE_LINE equivalent, so we use lines to draw polygon outlines.\n\t// This approach has additional implication that we need to do manual backface culling to reject outlines that\n\t// belong to back facing polygons.\n\t// The code assumes that polygons are convex.\n\n\t// Backface culling.\n\tauto transform_to_eye_space = [](vec3_t v, vec3_t v_eye) {\n\t\tauto m = vk.active ? vk_world.modelview_transform : dx_world.modelview_transform;\n\t\tv_eye[0] = m[0]*v[0] + m[4]*v[1] + m[8 ]*v[2] + m[12];\n\t\tv_eye[1] = m[1]*v[0] + m[5]*v[1] + m[9 ]*v[2] + m[13];\n\t\tv_eye[2] = m[2]*v[0] + m[6]*v[1] + m[10]*v[2] + m[14];\n\t};\n\tvec3_t pa;\n\tvec3_t pb;\n\ttransform_to_eye_space(&points[0], pa);\n\ttransform_to_eye_space(&points[3], pb);\n\tvec3_t p;\n\tVectorSubtract(pb, pa, p);\n\tvec3_t n;\n\tfor (int i = 2; i < numPoints; i++) {\n\t\ttransform_to_eye_space(&points[3*i], pb);\n\t\tvec3_t q;\n\t\tVectorSubtract(pb, pa, q);\n\t\tCrossProduct(q, p, n);\n\t\tif (VectorLength(n) > 1e-5)\n\t\t\tbreak;\n\t}\n\tif (DotProduct(n, pa) >= 0)\n\t\treturn; // discard backfacing polygon\n\n\t// Solid shade.\n\tfor (int i = 0; i < numPoints; i++) {\n\t\tVectorCopy(&points[3*i], tess.xyz[i]);\n\n\t\ttess.svars.colors[i][0] = (color&1) ? 255 : 0;\n\t\ttess.svars.colors[i][1] = (color&2) ? 255 : 0;\n\t\ttess.svars.colors[i][2] = (color&4) ? 255 : 0;\n\t\ttess.svars.colors[i][3] = 255;\n\t}\n\ttess.numVertexes = numPoints;\n\n\ttess.numIndexes = 0;\n\tfor (int i = 1; i < numPoints - 1; i++) {\n\t\ttess.indexes[tess.numIndexes + 0] = 0;\n\t\ttess.indexes[tess.numIndexes + 1] = i;\n\t\ttess.indexes[tess.numIndexes + 2] = i + 1;\n\t\ttess.numIndexes += 3;\n\t}\n\n\tif (vk.active) {\n\t\tvk_bind_geometry();\n\t\tvk_shade_geometry(vk.surface_debug_pipeline_solid, false, Vk_Depth_Range::normal);\n\t}\n\n\tif (dx.active) {\n\t\tdx_bind_geometry();\n\t\tdx_shade_geometry(dx.surface_debug_pipeline_solid, false, Vk_Depth_Range::normal, true, false);\n\t}\n\n\t// Outline.\n\tCom_Memset(tess.svars.colors, tr.identityLightByte, numPoints * 2 * sizeof(color4ub_t));\n\n\tfor (int i = 0; i < numPoints; i++) {\n\t\tVectorCopy(&points[3*i], tess.xyz[2*i]);\n\t\tVectorCopy(&points[3*((i + 1) % numPoints)], tess.xyz[2*i + 1]);\n\t}\n\ttess.numVertexes = numPoints * 2;\n\ttess.numIndexes = 0;\n\n\tif (vk.active) {\n\t\tvk_bind_geometry();\n\t\tvk_shade_geometry(vk.surface_debug_pipeline_outline, false, Vk_Depth_Range::force_zero, false);\n\t}\n\n\tif (dx.active) {\n\t\tdx_bind_geometry();\n\t\tdx_shade_geometry(dx.surface_debug_pipeline_outline, false, Vk_Depth_Range::force_zero, false, true);\n\t}\n\n\ttess.numVertexes = 0;\n}\n\n/*\n====================\nR_DebugGraphics\n\nVisualization aid for movement clipping debugging\n====================\n*/\nvoid R_DebugGraphics( void ) {\n\tif ( !r_debugSurface->integer ) {\n\t\treturn;\n\t}\n\n\t// the render thread can't make callbacks to the main thread\n\tR_SyncRenderThread();\n\n\tGL_Bind( tr.whiteImage);\n\tGL_Cull( CT_FRONT_SIDED );\n\tri.CM_DrawDebugSurface( R_DebugPolygon );\n}\n\n\n/*\n================\nR_RenderView\n\nA view may be either the actual camera view,\nor a mirror / remote location\n================\n*/\nvoid R_RenderView (viewParms_t *parms) {\n\tint\t\tfirstDrawSurf;\n\n\tif ( parms->viewportWidth <= 0 || parms->viewportHeight <= 0 ) {\n\t\treturn;\n\t}\n\n\ttr.viewCount++;\n\n\ttr.viewParms = *parms;\n\ttr.viewParms.frameCount = tr.frameCount;\n\n\tfirstDrawSurf = tr.refdef.numDrawSurfs;\n\n\ttr.viewCount++;\n\n\t// set viewParms.world\n\tR_RotateForViewer ();\n\n\tR_SetupFrustum ();\n\n\tR_GenerateDrawSurfs();\n\n\tR_SortDrawSurfs( tr.refdef.drawSurfs + firstDrawSurf, tr.refdef.numDrawSurfs - firstDrawSurf );\n\n\t// draw main system development information (surface outlines, etc)\n\tR_DebugGraphics();\n}\n\n\n\n"
  },
  {
    "path": "src/engine/renderer/tr_marks.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n// tr_marks.c -- polygon projection on the world polygons\n\n#include \"tr_local.h\"\n//#include \"assert.h\"\n\n#define MAX_VERTS_ON_POLY\t\t64\n\n#define MARKER_OFFSET\t\t\t0\t// 1\n\n/*\n=============\nR_ChopPolyBehindPlane\n\nOut must have space for two more vertexes than in\n=============\n*/\n#define\tSIDE_FRONT\t0\n#define\tSIDE_BACK\t1\n#define\tSIDE_ON\t\t2\nstatic void R_ChopPolyBehindPlane( int numInPoints, vec3_t inPoints[MAX_VERTS_ON_POLY],\n\t\t\t\t\t\t\t\t   int *numOutPoints, vec3_t outPoints[MAX_VERTS_ON_POLY], \n\t\t\t\t\t\t\tvec3_t normal, vec_t dist, vec_t epsilon) {\n\tfloat\t\tdists[MAX_VERTS_ON_POLY+4];\n\tint\t\t\tsides[MAX_VERTS_ON_POLY+4];\n\tint\t\t\tcounts[3];\n\tfloat\t\tdot;\n\tint\t\t\ti, j;\n\tfloat\t\t*p1, *p2, *clip;\n\tfloat\t\td;\n\n\t// don't clip if it might overflow\n\tif ( numInPoints >= MAX_VERTS_ON_POLY - 2 ) {\n\t\t*numOutPoints = 0;\n\t\treturn;\n\t}\n\n\tcounts[0] = counts[1] = counts[2] = 0;\n\n\t// determine sides for each point\n\tfor ( i = 0 ; i < numInPoints ; i++ ) {\n\t\tdot = DotProduct( inPoints[i], normal );\n\t\tdot -= dist;\n\t\tdists[i] = dot;\n\t\tif ( dot > epsilon ) {\n\t\t\tsides[i] = SIDE_FRONT;\n\t\t} else if ( dot < -epsilon ) {\n\t\t\tsides[i] = SIDE_BACK;\n\t\t} else {\n\t\t\tsides[i] = SIDE_ON;\n\t\t}\n\t\tcounts[sides[i]]++;\n\t}\n\tsides[i] = sides[0];\n\tdists[i] = dists[0];\n\n\t*numOutPoints = 0;\n\n\tif ( !counts[0] ) {\n\t\treturn;\n\t}\n\tif ( !counts[1] ) {\n\t\t*numOutPoints = numInPoints;\n\t\tCom_Memcpy( outPoints, inPoints, numInPoints * sizeof(vec3_t) );\n\t\treturn;\n\t}\n\n\tfor ( i = 0 ; i < numInPoints ; i++ ) {\n\t\tp1 = inPoints[i];\n\t\tclip = outPoints[ *numOutPoints ];\n\t\t\n\t\tif ( sides[i] == SIDE_ON ) {\n\t\t\tVectorCopy( p1, clip );\n\t\t\t(*numOutPoints)++;\n\t\t\tcontinue;\n\t\t}\n\t\n\t\tif ( sides[i] == SIDE_FRONT ) {\n\t\t\tVectorCopy( p1, clip );\n\t\t\t(*numOutPoints)++;\n\t\t\tclip = outPoints[ *numOutPoints ];\n\t\t}\n\n\t\tif ( sides[i+1] == SIDE_ON || sides[i+1] == sides[i] ) {\n\t\t\tcontinue;\n\t\t}\n\t\t\t\n\t\t// generate a split point\n\t\tp2 = inPoints[ (i+1) % numInPoints ];\n\n\t\td = dists[i] - dists[i+1];\n\t\tif ( d == 0 ) {\n\t\t\tdot = 0;\n\t\t} else {\n\t\t\tdot = dists[i] / d;\n\t\t}\n\n\t\t// clip xyz\n\n\t\tfor (j=0 ; j<3 ; j++) {\n\t\t\tclip[j] = p1[j] + dot * ( p2[j] - p1[j] );\n\t\t}\n\n\t\t(*numOutPoints)++;\n\t}\n}\n\n/*\n=================\nR_BoxSurfaces_r\n\n=================\n*/\nvoid R_BoxSurfaces_r(mnode_t *node, vec3_t mins, vec3_t maxs, surfaceType_t **list, int listsize, int *listlength, vec3_t dir) {\n\n\tint\t\t\ts, c;\n\tmsurface_t\t*surf, **mark;\n\n\t// do the tail recursion in a loop\n\twhile ( node->contents == -1 ) {\n\t\ts = BoxOnPlaneSide( mins, maxs, node->plane );\n\t\tif (s == 1) {\n\t\t\tnode = node->children[0];\n\t\t} else if (s == 2) {\n\t\t\tnode = node->children[1];\n\t\t} else {\n\t\t\tR_BoxSurfaces_r(node->children[0], mins, maxs, list, listsize, listlength, dir);\n\t\t\tnode = node->children[1];\n\t\t}\n\t}\n\n\t// add the individual surfaces\n\tmark = node->firstmarksurface;\n\tc = node->nummarksurfaces;\n\twhile (c--) {\n\t\t//\n\t\tif (*listlength >= listsize) break;\n\t\t//\n\t\tsurf = *mark;\n\t\t// check if the surface has NOIMPACT or NOMARKS set\n\t\tif ( ( surf->shader->surfaceFlags & ( SURF_NOIMPACT | SURF_NOMARKS ) )\n\t\t\t|| ( surf->shader->contentFlags & CONTENTS_FOG ) ) {\n\t\t\tsurf->viewCount = tr.viewCount;\n\t\t}\n\t\t// extra check for surfaces to avoid list overflows\n\t\telse if (*(surf->data) == SF_FACE) {\n\t\t\t// the face plane should go through the box\n\t\t\ts = BoxOnPlaneSide( mins, maxs, &(( srfSurfaceFace_t * ) surf->data)->plane );\n\t\t\tif (s == 1 || s == 2) {\n\t\t\t\tsurf->viewCount = tr.viewCount;\n\t\t\t} else if (DotProduct((( srfSurfaceFace_t * ) surf->data)->plane.normal, dir) > -0.5) {\n\t\t\t// don't add faces that make sharp angles with the projection direction\n\t\t\t\tsurf->viewCount = tr.viewCount;\n\t\t\t}\n\t\t}\n\t\telse if (*(surfaceType_t *) (surf->data) != SF_GRID) surf->viewCount = tr.viewCount;\n\t\t// check the viewCount because the surface may have\n\t\t// already been added if it spans multiple leafs\n\t\tif (surf->viewCount != tr.viewCount) {\n\t\t\tsurf->viewCount = tr.viewCount;\n\t\t\tlist[*listlength] = (surfaceType_t *) surf->data;\n\t\t\t(*listlength)++;\n\t\t}\n\t\tmark++;\n\t}\n}\n\n/*\n=================\nR_AddMarkFragments\n\n=================\n*/\nvoid R_AddMarkFragments(int numClipPoints, vec3_t clipPoints[2][MAX_VERTS_ON_POLY],\n\t\t\t\t   int numPlanes, vec3_t *normals, float *dists,\n\t\t\t\t   int maxPoints, vec3_t pointBuffer,\n\t\t\t\t   int maxFragments, markFragment_t *fragmentBuffer,\n\t\t\t\t   int *returnedPoints, int *returnedFragments,\n\t\t\t\t   vec3_t mins, vec3_t maxs) {\n\tint pingPong, i;\n\tmarkFragment_t\t*mf;\n\n\t// chop the surface by all the bounding planes of the to be projected polygon\n\tpingPong = 0;\n\n\tfor ( i = 0 ; i < numPlanes ; i++ ) {\n\n\t\tR_ChopPolyBehindPlane( numClipPoints, clipPoints[pingPong],\n\t\t\t\t\t\t   &numClipPoints, clipPoints[!pingPong],\n\t\t\t\t\t\t\tnormals[i], dists[i], 0.5 );\n\t\tpingPong ^= 1;\n\t\tif ( numClipPoints == 0 ) {\n\t\t\tbreak;\n\t\t}\n\t}\n\t// completely clipped away?\n\tif ( numClipPoints == 0 ) {\n\t\treturn;\n\t}\n\n\t// add this fragment to the returned list\n\tif ( numClipPoints + (*returnedPoints) > maxPoints ) {\n\t\treturn;\t// not enough space for this polygon\n\t}\n\t/*\n\t// all the clip points should be within the bounding box\n\tfor ( i = 0 ; i < numClipPoints ; i++ ) {\n\t\tint j;\n\t\tfor ( j = 0 ; j < 3 ; j++ ) {\n\t\t\tif (clipPoints[pingPong][i][j] < mins[j] - 0.5) break;\n\t\t\tif (clipPoints[pingPong][i][j] > maxs[j] + 0.5) break;\n\t\t}\n\t\tif (j < 3) break;\n\t}\n\tif (i < numClipPoints) return;\n\t*/\n\n\tmf = fragmentBuffer + (*returnedFragments);\n\tmf->firstPoint = (*returnedPoints);\n\tmf->numPoints = numClipPoints;\n\tCom_Memcpy( pointBuffer + (*returnedPoints) * 3, clipPoints[pingPong], numClipPoints * sizeof(vec3_t) );\n\n\t(*returnedPoints) += numClipPoints;\n\t(*returnedFragments)++;\n}\n\n/*\n=================\nR_MarkFragments\n\n=================\n*/\nint R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projection,\n\t\t\t\t   int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer ) {\n\tint\t\t\t\tnumsurfaces, numPlanes;\n\tint\t\t\t\ti, j, k, m, n;\n\tsurfaceType_t\t*surfaces[64];\n\tvec3_t\t\t\tmins, maxs;\n\tint\t\t\t\treturnedFragments;\n\tint\t\t\t\treturnedPoints;\n\tvec3_t\t\t\tnormals[MAX_VERTS_ON_POLY+2];\n\tfloat\t\t\tdists[MAX_VERTS_ON_POLY+2];\n\tvec3_t\t\t\tclipPoints[2][MAX_VERTS_ON_POLY];\n\tint\t\t\t\tnumClipPoints;\n\tfloat\t\t\t*v;\n\tsrfSurfaceFace_t *surf;\n\tsrfGridMesh_t\t*cv;\n\tdrawVert_t\t\t*dv;\n\tvec3_t\t\t\tnormal;\n\tvec3_t\t\t\tprojectionDir;\n\tvec3_t\t\t\tv1, v2;\n\tint\t\t\t\t*indexes;\n\n\t//increment view count for double check prevention\n\ttr.viewCount++;\n\n\t//\n\tVectorNormalize2( projection, projectionDir );\n\t// find all the brushes that are to be considered\n\tClearBounds( mins, maxs );\n\tfor ( i = 0 ; i < numPoints ; i++ ) {\n\t\tvec3_t\ttemp;\n\n\t\tAddPointToBounds( points[i], mins, maxs );\n\t\tVectorAdd( points[i], projection, temp );\n\t\tAddPointToBounds( temp, mins, maxs );\n\t\t// make sure we get all the leafs (also the one(s) in front of the hit surface)\n\t\tVectorMA( points[i], -20, projectionDir, temp );\n\t\tAddPointToBounds( temp, mins, maxs );\n\t}\n\n\tif (numPoints > MAX_VERTS_ON_POLY) numPoints = MAX_VERTS_ON_POLY;\n\t// create the bounding planes for the to be projected polygon\n\tfor ( i = 0 ; i < numPoints ; i++ ) {\n\t\tVectorSubtract(points[(i+1)%numPoints], points[i], v1);\n\t\tVectorAdd(points[i], projection, v2);\n\t\tVectorSubtract(points[i], v2, v2);\n\t\tCrossProduct(v1, v2, normals[i]);\n\t\tVectorNormalizeFast(normals[i]);\n\t\tdists[i] = DotProduct(normals[i], points[i]);\n\t}\n\t// add near and far clipping planes for projection\n\tVectorCopy(projectionDir, normals[numPoints]);\n\tdists[numPoints] = DotProduct(normals[numPoints], points[0]) - 32;\n\tVectorCopy(projectionDir, normals[numPoints+1]);\n\tVectorInverse(normals[numPoints+1]);\n\tdists[numPoints+1] = DotProduct(normals[numPoints+1], points[0]) - 20;\n\tnumPlanes = numPoints + 2;\n\n\tnumsurfaces = 0;\n\tR_BoxSurfaces_r(tr.world->nodes, mins, maxs, surfaces, 64, &numsurfaces, projectionDir);\n\t//assert(numsurfaces <= 64);\n\t//assert(numsurfaces != 64);\n\n\treturnedPoints = 0;\n\treturnedFragments = 0;\n\n\tfor ( i = 0 ; i < numsurfaces ; i++ ) {\n\n\t\tif (*surfaces[i] == SF_GRID) {\n\n\t\t\tcv = (srfGridMesh_t *) surfaces[i];\n\t\t\tfor ( m = 0 ; m < cv->height - 1 ; m++ ) {\n\t\t\t\tfor ( n = 0 ; n < cv->width - 1 ; n++ ) {\n\t\t\t\t\t// We triangulate the grid and chop all triangles within\n\t\t\t\t\t// the bounding planes of the to be projected polygon.\n\t\t\t\t\t// LOD is not taken into account, not such a big deal though.\n\t\t\t\t\t//\n\t\t\t\t\t// It's probably much nicer to chop the grid itself and deal\n\t\t\t\t\t// with this grid as a normal SF_GRID surface so LOD will\n\t\t\t\t\t// be applied. However the LOD of that chopped grid must\n\t\t\t\t\t// be synced with the LOD of the original curve.\n\t\t\t\t\t// One way to do this; the chopped grid shares vertices with\n\t\t\t\t\t// the original curve. When LOD is applied to the original\n\t\t\t\t\t// curve the unused vertices are flagged. Now the chopped curve\n\t\t\t\t\t// should skip the flagged vertices. This still leaves the\n\t\t\t\t\t// problems with the vertices at the chopped grid edges.\n\t\t\t\t\t//\n\t\t\t\t\t// To avoid issues when LOD applied to \"hollow curves\" (like\n\t\t\t\t\t// the ones around many jump pads) we now just add a 2 unit\n\t\t\t\t\t// offset to the triangle vertices.\n\t\t\t\t\t// The offset is added in the vertex normal vector direction\n\t\t\t\t\t// so all triangles will still fit together.\n\t\t\t\t\t// The 2 unit offset should avoid pretty much all LOD problems.\n\n\t\t\t\t\tnumClipPoints = 3;\n\n\t\t\t\t\tdv = cv->verts + m * cv->width + n;\n\n\t\t\t\t\tVectorCopy(dv[0].xyz, clipPoints[0][0]);\n\t\t\t\t\tVectorMA(clipPoints[0][0], MARKER_OFFSET, dv[0].normal, clipPoints[0][0]);\n\t\t\t\t\tVectorCopy(dv[cv->width].xyz, clipPoints[0][1]);\n\t\t\t\t\tVectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]);\n\t\t\t\t\tVectorCopy(dv[1].xyz, clipPoints[0][2]);\n\t\t\t\t\tVectorMA(clipPoints[0][2], MARKER_OFFSET, dv[1].normal, clipPoints[0][2]);\n\t\t\t\t\t// check the normal of this triangle\n\t\t\t\t\tVectorSubtract(clipPoints[0][0], clipPoints[0][1], v1);\n\t\t\t\t\tVectorSubtract(clipPoints[0][2], clipPoints[0][1], v2);\n\t\t\t\t\tCrossProduct(v1, v2, normal);\n\t\t\t\t\tVectorNormalizeFast(normal);\n\t\t\t\t\tif (DotProduct(normal, projectionDir) < -0.1) {\n\t\t\t\t\t\t// add the fragments of this triangle\n\t\t\t\t\t\tR_AddMarkFragments(numClipPoints, clipPoints,\n\t\t\t\t\t\t\t\t\t\t   numPlanes, normals, dists,\n\t\t\t\t\t\t\t\t\t\t   maxPoints, pointBuffer,\n\t\t\t\t\t\t\t\t\t\t   maxFragments, fragmentBuffer,\n\t\t\t\t\t\t\t\t\t\t   &returnedPoints, &returnedFragments, mins, maxs);\n\n\t\t\t\t\t\tif ( returnedFragments == maxFragments ) {\n\t\t\t\t\t\t\treturn returnedFragments;\t// not enough space for more fragments\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tVectorCopy(dv[1].xyz, clipPoints[0][0]);\n\t\t\t\t\tVectorMA(clipPoints[0][0], MARKER_OFFSET, dv[1].normal, clipPoints[0][0]);\n\t\t\t\t\tVectorCopy(dv[cv->width].xyz, clipPoints[0][1]);\n\t\t\t\t\tVectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]);\n\t\t\t\t\tVectorCopy(dv[cv->width+1].xyz, clipPoints[0][2]);\n\t\t\t\t\tVectorMA(clipPoints[0][2], MARKER_OFFSET, dv[cv->width+1].normal, clipPoints[0][2]);\n\t\t\t\t\t// check the normal of this triangle\n\t\t\t\t\tVectorSubtract(clipPoints[0][0], clipPoints[0][1], v1);\n\t\t\t\t\tVectorSubtract(clipPoints[0][2], clipPoints[0][1], v2);\n\t\t\t\t\tCrossProduct(v1, v2, normal);\n\t\t\t\t\tVectorNormalizeFast(normal);\n\t\t\t\t\tif (DotProduct(normal, projectionDir) < -0.05) {\n\t\t\t\t\t\t// add the fragments of this triangle\n\t\t\t\t\t\tR_AddMarkFragments(numClipPoints, clipPoints,\n\t\t\t\t\t\t\t\t\t\t   numPlanes, normals, dists,\n\t\t\t\t\t\t\t\t\t\t   maxPoints, pointBuffer,\n\t\t\t\t\t\t\t\t\t\t   maxFragments, fragmentBuffer,\n\t\t\t\t\t\t\t\t\t\t   &returnedPoints, &returnedFragments, mins, maxs);\n\n\t\t\t\t\t\tif ( returnedFragments == maxFragments ) {\n\t\t\t\t\t\t\treturn returnedFragments;\t// not enough space for more fragments\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (*surfaces[i] == SF_FACE) {\n\n\t\t\tsurf = ( srfSurfaceFace_t * ) surfaces[i];\n\t\t\t// check the normal of this face\n\t\t\tif (DotProduct(surf->plane.normal, projectionDir) > -0.5) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t/*\n\t\t\tVectorSubtract(clipPoints[0][0], clipPoints[0][1], v1);\n\t\t\tVectorSubtract(clipPoints[0][2], clipPoints[0][1], v2);\n\t\t\tCrossProduct(v1, v2, normal);\n\t\t\tVectorNormalize(normal);\n\t\t\tif (DotProduct(normal, projectionDir) > -0.5) continue;\n\t\t\t*/\n\t\t\tindexes = (int *)( (byte *)surf + surf->ofsIndices );\n\t\t\tfor ( k = 0 ; k < surf->numIndices ; k += 3 ) {\n\t\t\t\tfor ( j = 0 ; j < 3 ; j++ ) {\n\t\t\t\t\tv = surf->points[0] + VERTEXSIZE * indexes[k+j];;\n\t\t\t\t\tVectorMA( v, MARKER_OFFSET, surf->plane.normal, clipPoints[0][j] );\n\t\t\t\t}\n\t\t\t\t// add the fragments of this face\n\t\t\t\tR_AddMarkFragments( 3 , clipPoints,\n\t\t\t\t\t\t\t\t   numPlanes, normals, dists,\n\t\t\t\t\t\t\t\t   maxPoints, pointBuffer,\n\t\t\t\t\t\t\t\t   maxFragments, fragmentBuffer,\n\t\t\t\t\t\t\t\t   &returnedPoints, &returnedFragments, mins, maxs);\n\t\t\t\tif ( returnedFragments == maxFragments ) {\n\t\t\t\t\treturn returnedFragments;\t// not enough space for more fragments\n\t\t\t\t}\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\telse {\n\t\t\t// ignore all other world surfaces\n\t\t\t// might be cool to also project polygons on a triangle soup\n\t\t\t// however this will probably create huge amounts of extra polys\n\t\t\t// even more than the projection onto curves\n\t\t\tcontinue;\n\t\t}\n\t}\n\treturn returnedFragments;\n}\n\n"
  },
  {
    "path": "src/engine/renderer/tr_mesh.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n// tr_mesh.c: triangle model functions\n\n#include \"tr_local.h\"\n\nstatic float ProjectRadius( float r, vec3_t location )\n{\n\tfloat pr;\n\tfloat dist;\n\tfloat c;\n\tvec3_t\tp;\n\tfloat\tprojected[4];\n\n\tc = DotProduct( tr.viewParms.or.axis[0], tr.viewParms.or.origin );\n\tdist = DotProduct( tr.viewParms.or.axis[0], location ) - c;\n\n\tif ( dist <= 0 )\n\t\treturn 0;\n\n\tp[0] = 0;\n\tp[1] = fabs( r );\n\tp[2] = -dist;\n\n\tprojected[0] = p[0] * tr.viewParms.projectionMatrix[0] + \n\t\t           p[1] * tr.viewParms.projectionMatrix[4] +\n\t\t\t\t   p[2] * tr.viewParms.projectionMatrix[8] +\n\t\t\t\t   tr.viewParms.projectionMatrix[12];\n\n\tprojected[1] = p[0] * tr.viewParms.projectionMatrix[1] + \n\t\t           p[1] * tr.viewParms.projectionMatrix[5] +\n\t\t\t\t   p[2] * tr.viewParms.projectionMatrix[9] +\n\t\t\t\t   tr.viewParms.projectionMatrix[13];\n\n\tprojected[2] = p[0] * tr.viewParms.projectionMatrix[2] + \n\t\t           p[1] * tr.viewParms.projectionMatrix[6] +\n\t\t\t\t   p[2] * tr.viewParms.projectionMatrix[10] +\n\t\t\t\t   tr.viewParms.projectionMatrix[14];\n\n\tprojected[3] = p[0] * tr.viewParms.projectionMatrix[3] + \n\t\t           p[1] * tr.viewParms.projectionMatrix[7] +\n\t\t\t\t   p[2] * tr.viewParms.projectionMatrix[11] +\n\t\t\t\t   tr.viewParms.projectionMatrix[15];\n\n\n\tpr = projected[1] / projected[3];\n\n\tif ( pr > 1.0f )\n\t\tpr = 1.0f;\n\n\treturn pr;\n}\n\n/*\n=============\nR_CullModel\n=============\n*/\nstatic int R_CullModel( md3Header_t *header, trRefEntity_t *ent ) {\n\tvec3_t\t\tbounds[2];\n\tmd3Frame_t\t*oldFrame, *newFrame;\n\tint\t\t\ti;\n\n\t// compute frame pointers\n\tnewFrame = ( md3Frame_t * ) ( ( byte * ) header + header->ofsFrames ) + ent->e.frame;\n\toldFrame = ( md3Frame_t * ) ( ( byte * ) header + header->ofsFrames ) + ent->e.oldframe;\n\n\t// cull bounding sphere ONLY if this is not an upscaled entity\n\tif ( !ent->e.nonNormalizedAxes )\n\t{\n\t\tif ( ent->e.frame == ent->e.oldframe )\n\t\t{\n\t\t\tswitch ( R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius ) )\n\t\t\t{\n\t\t\tcase CULL_OUT:\n\t\t\t\ttr.pc.c_sphere_cull_md3_out++;\n\t\t\t\treturn CULL_OUT;\n\n\t\t\tcase CULL_IN:\n\t\t\t\ttr.pc.c_sphere_cull_md3_in++;\n\t\t\t\treturn CULL_IN;\n\n\t\t\tcase CULL_CLIP:\n\t\t\t\ttr.pc.c_sphere_cull_md3_clip++;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tint sphereCull, sphereCullB;\n\n\t\t\tsphereCull  = R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius );\n\t\t\tif ( newFrame == oldFrame ) {\n\t\t\t\tsphereCullB = sphereCull;\n\t\t\t} else {\n\t\t\t\tsphereCullB = R_CullLocalPointAndRadius( oldFrame->localOrigin, oldFrame->radius );\n\t\t\t}\n\n\t\t\tif ( sphereCull == sphereCullB )\n\t\t\t{\n\t\t\t\tif ( sphereCull == CULL_OUT )\n\t\t\t\t{\n\t\t\t\t\ttr.pc.c_sphere_cull_md3_out++;\n\t\t\t\t\treturn CULL_OUT;\n\t\t\t\t}\n\t\t\t\telse if ( sphereCull == CULL_IN )\n\t\t\t\t{\n\t\t\t\t\ttr.pc.c_sphere_cull_md3_in++;\n\t\t\t\t\treturn CULL_IN;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\ttr.pc.c_sphere_cull_md3_clip++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// calculate a bounding box in the current coordinate system\n\tfor (i = 0 ; i < 3 ; i++) {\n\t\tbounds[0][i] = oldFrame->bounds[0][i] < newFrame->bounds[0][i] ? oldFrame->bounds[0][i] : newFrame->bounds[0][i];\n\t\tbounds[1][i] = oldFrame->bounds[1][i] > newFrame->bounds[1][i] ? oldFrame->bounds[1][i] : newFrame->bounds[1][i];\n\t}\n\n\tswitch ( R_CullLocalBox( bounds ) )\n\t{\n\tcase CULL_IN:\n\t\ttr.pc.c_box_cull_md3_in++;\n\t\treturn CULL_IN;\n\tcase CULL_CLIP:\n\t\ttr.pc.c_box_cull_md3_clip++;\n\t\treturn CULL_CLIP;\n\tcase CULL_OUT:\n\tdefault:\n\t\ttr.pc.c_box_cull_md3_out++;\n\t\treturn CULL_OUT;\n\t}\n}\n\n\n/*\n=================\nR_ComputeLOD\n\n=================\n*/\nint R_ComputeLOD( trRefEntity_t *ent ) {\n\tfloat radius;\n\tfloat flod, lodscale;\n\tfloat projectedRadius;\n\tmd3Frame_t *frame;\n\tint lod;\n\n\tif ( tr.currentModel->numLods < 2 )\n\t{\n\t\t// model has only 1 LOD level, skip computations and bias\n\t\tlod = 0;\n\t}\n\telse\n\t{\n\t\t// multiple LODs exist, so compute projected bounding sphere\n\t\t// and use that as a criteria for selecting LOD\n\n\t\tframe = ( md3Frame_t * ) ( ( ( unsigned char * ) tr.currentModel->md3[0] ) + tr.currentModel->md3[0]->ofsFrames );\n\n\t\tframe += ent->e.frame;\n\n\t\tradius = RadiusFromBounds( frame->bounds[0], frame->bounds[1] );\n\n\t\tif ( ( projectedRadius = ProjectRadius( radius, ent->e.origin ) ) != 0 )\n\t\t{\n\t\t\tlodscale = r_lodscale->value;\n\t\t\tif (lodscale > 20) lodscale = 20;\n\t\t\tflod = 1.0f - projectedRadius * lodscale;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// object intersects near view plane, e.g. view weapon\n\t\t\tflod = 0;\n\t\t}\n\n\t\tflod *= tr.currentModel->numLods;\n\t\tlod = myftol( flod );\n\n\t\tif ( lod < 0 )\n\t\t{\n\t\t\tlod = 0;\n\t\t}\n\t\telse if ( lod >= tr.currentModel->numLods )\n\t\t{\n\t\t\tlod = tr.currentModel->numLods - 1;\n\t\t}\n\t}\n\n\tlod += r_lodbias->integer;\n\t\n\tif ( lod >= tr.currentModel->numLods )\n\t\tlod = tr.currentModel->numLods - 1;\n\tif ( lod < 0 )\n\t\tlod = 0;\n\n\treturn lod;\n}\n\n/*\n=================\nR_ComputeFogNum\n\n=================\n*/\nint R_ComputeFogNum( md3Header_t *header, trRefEntity_t *ent ) {\n\tint\t\t\t\ti, j;\n\tfog_t\t\t\t*fog;\n\tmd3Frame_t\t\t*md3Frame;\n\tvec3_t\t\t\tlocalOrigin;\n\n\tif ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {\n\t\treturn 0;\n\t}\n\n\t// FIXME: non-normalized axis issues\n\tmd3Frame = ( md3Frame_t * ) ( ( byte * ) header + header->ofsFrames ) + ent->e.frame;\n\tVectorAdd( ent->e.origin, md3Frame->localOrigin, localOrigin );\n\tfor ( i = 1 ; i < tr.world->numfogs ; i++ ) {\n\t\tfog = &tr.world->fogs[i];\n\t\tfor ( j = 0 ; j < 3 ; j++ ) {\n\t\t\tif ( localOrigin[j] - md3Frame->radius >= fog->bounds[1][j] ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( localOrigin[j] + md3Frame->radius <= fog->bounds[0][j] ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif ( j == 3 ) {\n\t\t\treturn i;\n\t\t}\n\t}\n\n\treturn 0;\n}\n\n/*\n=================\nR_AddMD3Surfaces\n\n=================\n*/\nvoid R_AddMD3Surfaces( trRefEntity_t *ent ) {\n\tint\t\t\t\ti;\n\tmd3Header_t\t\t*header = 0;\n\tmd3Surface_t\t*surface = 0;\n\tmd3Shader_t\t\t*md3Shader = 0;\n\tshader_t\t\t*shader = 0;\n\tint\t\t\t\tcull;\n\tint\t\t\t\tlod;\n\tint\t\t\t\tfogNum;\n\tqboolean\t\tpersonalModel;\n\n\t// don't add third_person objects if not in a portal\n\tpersonalModel = (qboolean) ((ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal);\n\n\tif ( ent->e.renderfx & RF_WRAP_FRAMES ) {\n\t\tent->e.frame %= tr.currentModel->md3[0]->numFrames;\n\t\tent->e.oldframe %= tr.currentModel->md3[0]->numFrames;\n\t}\n\n\t//\n\t// Validate the frames so there is no chance of a crash.\n\t// This will write directly into the entity structure, so\n\t// when the surfaces are rendered, they don't need to be\n\t// range checked again.\n\t//\n\tif ( (ent->e.frame >= tr.currentModel->md3[0]->numFrames) \n\t\t|| (ent->e.frame < 0)\n\t\t|| (ent->e.oldframe >= tr.currentModel->md3[0]->numFrames)\n\t\t|| (ent->e.oldframe < 0) ) {\n\t\t\tri.Printf( PRINT_DEVELOPER, \"R_AddMD3Surfaces: no such frame %d to %d for '%s'\\n\",\n\t\t\t\tent->e.oldframe, ent->e.frame,\n\t\t\t\ttr.currentModel->name );\n\t\t\tent->e.frame = 0;\n\t\t\tent->e.oldframe = 0;\n\t}\n\n\t//\n\t// compute LOD\n\t//\n\tlod = R_ComputeLOD( ent );\n\n\theader = tr.currentModel->md3[lod];\n\n\t//\n\t// cull the entire model if merged bounding box of both frames\n\t// is outside the view frustum.\n\t//\n\tcull = R_CullModel ( header, ent );\n\tif ( cull == CULL_OUT ) {\n\t\treturn;\n\t}\n\n\t//\n\t// set up lighting now that we know we aren't culled\n\t//\n\tif ( !personalModel || r_shadows->integer > 1 ) {\n\t\tR_SetupEntityLighting( &tr.refdef, ent );\n\t}\n\n\t//\n\t// see if we are in a fog volume\n\t//\n\tfogNum = R_ComputeFogNum( header, ent );\n\n\t//\n\t// draw all surfaces\n\t//\n\tsurface = (md3Surface_t *)( (byte *)header + header->ofsSurfaces );\n\tfor ( i = 0 ; i < header->numSurfaces ; i++ ) {\n\n\t\tif ( ent->e.customShader ) {\n\t\t\tshader = R_GetShaderByHandle( ent->e.customShader );\n\t\t} else if ( ent->e.customSkin > 0 && ent->e.customSkin < tr.numSkins ) {\n\t\t\tskin_t *skin;\n\t\t\tint\t\tj;\n\n\t\t\tskin = R_GetSkinByHandle( ent->e.customSkin );\n\n\t\t\t// match the surface name to something in the skin file\n\t\t\tshader = tr.defaultShader;\n\t\t\tfor ( j = 0 ; j < skin->numSurfaces ; j++ ) {\n\t\t\t\t// the names have both been lowercased\n\t\t\t\tif ( !strcmp( skin->surfaces[j]->name, surface->name ) ) {\n\t\t\t\t\tshader = skin->surfaces[j]->shader;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (shader == tr.defaultShader) {\n\t\t\t\tri.Printf( PRINT_DEVELOPER, \"WARNING: no shader for surface %s in skin %s\\n\", surface->name, skin->name);\n\t\t\t}\n\t\t\telse if (shader->defaultShader) {\n\t\t\t\tri.Printf( PRINT_DEVELOPER, \"WARNING: shader %s in skin %s not found\\n\", shader->name, skin->name);\n\t\t\t}\n\t\t} else if ( surface->numShaders <= 0 ) {\n\t\t\tshader = tr.defaultShader;\n\t\t} else {\n\t\t\tmd3Shader = (md3Shader_t *) ( (byte *)surface + surface->ofsShaders );\n\t\t\tmd3Shader += ent->e.skinNum % surface->numShaders;\n\t\t\tshader = tr.shaders[ md3Shader->shaderIndex ];\n\t\t}\n\n\n\t\t// we will add shadows even if the main object isn't visible in the view\n\n\t\t// stencil shadows can't do personal models unless I polyhedron clip\n\t\tif ( !personalModel\n\t\t\t&& r_shadows->integer == 2 \n\t\t\t&& fogNum == 0\n\t\t\t&& !(ent->e.renderfx & ( RF_NOSHADOW | RF_DEPTHHACK ) ) \n\t\t\t&& shader->sort == SS_OPAQUE ) {\n\t\t\tR_AddDrawSurf( (surfaceType_t*) (void *)surface, tr.shadowShader, 0, qfalse );\n\t\t}\n\n\t\t// projection shadows work fine with personal models\n\t\tif ( r_shadows->integer == 3\n\t\t\t&& fogNum == 0\n\t\t\t&& (ent->e.renderfx & RF_SHADOW_PLANE )\n\t\t\t&& shader->sort == SS_OPAQUE ) {\n\t\t\tR_AddDrawSurf((surfaceType_t*) (void *)surface, tr.projectionShadowShader, 0, qfalse);\n\t\t}\n\n\t\t// don't add third_person objects if not viewing through a portal\n\t\tif ( !personalModel ) {\n\t\t\tR_AddDrawSurf((surfaceType_t*) (void *)surface, shader, fogNum, qfalse);\n\t\t}\n\n\t\tsurface = (md3Surface_t *)( (byte *)surface + surface->ofsEnd );\n\t}\n\n}\n\n"
  },
  {
    "path": "src/engine/renderer/tr_model.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n// tr_models.c -- model loading and caching\n\n#include \"tr_local.h\"\n\n#define\tLL(x) x=LittleLong(x)\n\nstatic qboolean R_LoadMD3 (model_t *mod, int lod, void *buffer, const char *name );\nstatic qboolean R_LoadMD4 (model_t *mod, void *buffer, const char *name );\n\nmodel_t\t*loadmodel;\n\n/*\n** R_GetModelByHandle\n*/\nmodel_t\t*R_GetModelByHandle( qhandle_t index ) {\n\tmodel_t\t\t*mod;\n\n\t// out of range gets the defualt model\n\tif ( index < 1 || index >= tr.numModels ) {\n\t\treturn tr.models[0];\n\t}\n\n\tmod = tr.models[index];\n\n\treturn mod;\n}\n\n//===============================================================================\n\n/*\n** R_AllocModel\n*/\nmodel_t *R_AllocModel( void ) {\n\tmodel_t\t\t*mod;\n\n\tif ( tr.numModels == MAX_MOD_KNOWN ) {\n\t\treturn NULL;\n\t}\n\n\tmod = (model_t*) ri.Hunk_Alloc( sizeof( *tr.models[tr.numModels] ), h_low );\n\tmod->index = tr.numModels;\n\ttr.models[tr.numModels] = mod;\n\ttr.numModels++;\n\n\treturn mod;\n}\n\n/*\n====================\nRE_RegisterModel\n\nLoads in a model for the given name\n\nZero will be returned if the model fails to load.\nAn entry will be retained for failed models as an\noptimization to prevent disk rescanning if they are\nasked for again.\n====================\n*/\nqhandle_t RE_RegisterModel( const char *name ) {\n\tmodel_t\t\t*mod;\n\tunsigned\t*buf;\n\tint\t\t\tlod;\n\tint\t\t\tident;\n\tqboolean\tloaded;\n\tqhandle_t\thModel;\n\tint\t\t\tnumLoaded;\n\n\tif ( !name || !name[0] ) {\n\t\tri.Printf( PRINT_ALL, \"RE_RegisterModel: NULL name\\n\" );\n\t\treturn 0;\n\t}\n\n\tif ( (int)strlen( name ) >= MAX_QPATH ) {\n\t\tCom_Printf( \"Model name exceeds MAX_QPATH\\n\" );\n\t\treturn 0;\n\t}\n\n\t//\n\t// search the currently loaded models\n\t//\n\tfor ( hModel = 1 ; hModel < tr.numModels; hModel++ ) {\n\t\tmod = tr.models[hModel];\n\t\tif ( !strcmp( mod->name, name ) ) {\n\t\t\tif( mod->type == MOD_BAD ) {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\treturn hModel;\n\t\t}\n\t}\n\n\t// allocate a new model_t\n\n\tif ( ( mod = R_AllocModel() ) == NULL ) {\n\t\tri.Printf( PRINT_WARNING, \"RE_RegisterModel: R_AllocModel() failed for '%s'\\n\", name);\n\t\treturn 0;\n\t}\n\n\t// only set the name after the model has been successfully loaded\n\tQ_strncpyz( mod->name, name, sizeof( mod->name ) );\n\n\n\t// make sure the render thread is stopped\n\tR_SyncRenderThread();\n\n\tmod->numLods = 0;\n\n\t//\n\t// load the files\n\t//\n\tnumLoaded = 0;\n\n\tfor ( lod = MD3_MAX_LODS - 1 ; lod >= 0 ; lod-- ) {\n\t\tchar filename[1024];\n\n\t\tstrcpy( filename, name );\n\n\t\tif ( lod != 0 ) {\n\t\t\tchar namebuf[80];\n\n\t\t\tif ( strrchr( filename, '.' ) ) {\n\t\t\t\t*strrchr( filename, '.' ) = 0;\n\t\t\t}\n\t\t\tsprintf( namebuf, \"_%d.md3\", lod );\n\t\t\tstrcat( filename, namebuf );\n\t\t}\n\n\t\tri.FS_ReadFile( filename, (void **)&buf );\n\t\tif ( !buf ) {\n\t\t\tcontinue;\n\t\t}\n\t\t\n\t\tloadmodel = mod;\n\t\t\n\t\tident = LittleLong(*(unsigned *)buf);\n\t\tif ( ident == MD4_IDENT ) {\n\t\t\tloaded = R_LoadMD4( mod, buf, name );\n\t\t} else {\n\t\t\tif ( ident != MD3_IDENT ) {\n\t\t\t\tri.Printf (PRINT_WARNING,\"RE_RegisterModel: unknown fileid for %s\\n\", name);\n\t\t\t\tgoto fail;\n\t\t\t}\n\n\t\t\tloaded = R_LoadMD3( mod, lod, buf, name );\n\t\t}\n\t\t\n\t\tri.FS_FreeFile (buf);\n\n\t\tif ( !loaded ) {\n\t\t\tif ( lod == 0 ) {\n\t\t\t\tgoto fail;\n\t\t\t} else {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t} else {\n\t\t\tmod->numLods++;\n\t\t\tnumLoaded++;\n\t\t\t// if we have a valid model and are biased\n\t\t\t// so that we won't see any higher detail ones,\n\t\t\t// stop loading them\n//\t\t\tif ( lod <= r_lodbias->integer ) {\n//\t\t\t\tbreak;\n//\t\t\t}\n\t\t}\n\t}\n\n\tif ( numLoaded ) {\n\t\t// duplicate into higher lod spots that weren't\n\t\t// loaded, in case the user changes r_lodbias on the fly\n\t\tfor ( lod-- ; lod >= 0 ; lod-- ) {\n\t\t\tmod->numLods++;\n\t\t\tmod->md3[lod] = mod->md3[lod+1];\n\t\t}\n\n\t\treturn mod->index;\n\t}\n#ifdef _DEBUG\n\telse {\n\t\tri.Printf (PRINT_WARNING,\"RE_RegisterModel: couldn't load %s\\n\", name);\n\t}\n#endif\n\nfail:\n\t// we still keep the model_t around, so if the model name is asked for\n\t// again, we won't bother scanning the filesystem\n\tmod->type = MOD_BAD;\n\treturn 0;\n}\n\n\n/*\n=================\nR_LoadMD3\n=================\n*/\nstatic qboolean R_LoadMD3 (model_t *mod, int lod, void *buffer, const char *mod_name ) {\n\tint\t\t\t\t\ti, j;\n\tmd3Header_t\t\t\t*pinmodel;\n    md3Frame_t\t\t\t*frame;\n\tmd3Surface_t\t\t*surf;\n\tmd3Shader_t\t\t\t*shader;\n\tmd3Triangle_t\t\t*tri;\n\tmd3St_t\t\t\t\t*st;\n\tmd3XyzNormal_t\t\t*xyz;\n\tmd3Tag_t\t\t\t*tag;\n\tint\t\t\t\t\tversion;\n\tint\t\t\t\t\tsize;\n\n\tpinmodel = (md3Header_t *)buffer;\n\n\tversion = LittleLong (pinmodel->version);\n\tif (version != MD3_VERSION) {\n\t\tri.Printf( PRINT_WARNING, \"R_LoadMD3: %s has wrong version (%i should be %i)\\n\",\n\t\t\t\t mod_name, version, MD3_VERSION);\n\t\treturn qfalse;\n\t}\n\n\tmod->type = MOD_MESH;\n\tsize = LittleLong(pinmodel->ofsEnd);\n\tmod->dataSize += size;\n\tmod->md3[lod] = (md3Header_t*) ri.Hunk_Alloc( size, h_low );\n\n\tCom_Memcpy (mod->md3[lod], buffer, LittleLong(pinmodel->ofsEnd) );\n\n    LL(mod->md3[lod]->ident);\n    LL(mod->md3[lod]->version);\n    LL(mod->md3[lod]->numFrames);\n    LL(mod->md3[lod]->numTags);\n    LL(mod->md3[lod]->numSurfaces);\n    LL(mod->md3[lod]->ofsFrames);\n    LL(mod->md3[lod]->ofsTags);\n    LL(mod->md3[lod]->ofsSurfaces);\n    LL(mod->md3[lod]->ofsEnd);\n\n\tif ( mod->md3[lod]->numFrames < 1 ) {\n\t\tri.Printf( PRINT_WARNING, \"R_LoadMD3: %s has no frames\\n\", mod_name );\n\t\treturn qfalse;\n\t}\n    \n\t// swap all the frames\n    frame = (md3Frame_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsFrames );\n    for ( i = 0 ; i < mod->md3[lod]->numFrames ; i++, frame++) {\n    \tframe->radius = LittleFloat( frame->radius );\n        for ( j = 0 ; j < 3 ; j++ ) {\n            frame->bounds[0][j] = LittleFloat( frame->bounds[0][j] );\n            frame->bounds[1][j] = LittleFloat( frame->bounds[1][j] );\n\t    \tframe->localOrigin[j] = LittleFloat( frame->localOrigin[j] );\n        }\n\t}\n\n\t// swap all the tags\n    tag = (md3Tag_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsTags );\n    for ( i = 0 ; i < mod->md3[lod]->numTags * mod->md3[lod]->numFrames ; i++, tag++) {\n        for ( j = 0 ; j < 3 ; j++ ) {\n\t\t\ttag->origin[j] = LittleFloat( tag->origin[j] );\n\t\t\ttag->axis[0][j] = LittleFloat( tag->axis[0][j] );\n\t\t\ttag->axis[1][j] = LittleFloat( tag->axis[1][j] );\n\t\t\ttag->axis[2][j] = LittleFloat( tag->axis[2][j] );\n        }\n\t}\n\n\t// swap all the surfaces\n\tsurf = (md3Surface_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsSurfaces );\n\tfor ( i = 0 ; i < mod->md3[lod]->numSurfaces ; i++) {\n\n        LL(surf->ident);\n        LL(surf->flags);\n        LL(surf->numFrames);\n        LL(surf->numShaders);\n        LL(surf->numTriangles);\n        LL(surf->ofsTriangles);\n        LL(surf->numVerts);\n        LL(surf->ofsShaders);\n        LL(surf->ofsSt);\n        LL(surf->ofsXyzNormals);\n        LL(surf->ofsEnd);\n\t\t\n\t\tif ( surf->numVerts > SHADER_MAX_VERTEXES ) {\n\t\t\tri.Error (ERR_DROP, \"R_LoadMD3: %s has more than %i verts on a surface (%i)\",\n\t\t\t\tmod_name, SHADER_MAX_VERTEXES, surf->numVerts );\n\t\t}\n\t\tif ( surf->numTriangles*3 > SHADER_MAX_INDEXES ) {\n\t\t\tri.Error (ERR_DROP, \"R_LoadMD3: %s has more than %i triangles on a surface (%i)\",\n\t\t\t\tmod_name, SHADER_MAX_INDEXES / 3, surf->numTriangles );\n\t\t}\n\t\n\t\t// change to surface identifier\n\t\tsurf->ident = SF_MD3;\n\n\t\t// lowercase the surface name so skin compares are faster\n\t\tQ_strlwr( surf->name );\n\n\t\t// strip off a trailing _1 or _2\n\t\t// this is a crutch for q3data being a mess\n\t\tj = (int)strlen( surf->name );\n\t\tif ( j > 2 && surf->name[j-2] == '_' ) {\n\t\t\tsurf->name[j-2] = 0;\n\t\t}\n\n        // register the shaders\n        shader = (md3Shader_t *) ( (byte *)surf + surf->ofsShaders );\n        for ( j = 0 ; j < surf->numShaders ; j++, shader++ ) {\n            shader_t\t*sh;\n\n            sh = R_FindShader( shader->name, LIGHTMAP_NONE, qtrue );\n\t\t\tif ( sh->defaultShader ) {\n\t\t\t\tshader->shaderIndex = 0;\n\t\t\t} else {\n\t\t\t\tshader->shaderIndex = sh->index;\n\t\t\t}\n        }\n\n\t\t// swap all the triangles\n\t\ttri = (md3Triangle_t *) ( (byte *)surf + surf->ofsTriangles );\n\t\tfor ( j = 0 ; j < surf->numTriangles ; j++, tri++ ) {\n\t\t\tLL(tri->indexes[0]);\n\t\t\tLL(tri->indexes[1]);\n\t\t\tLL(tri->indexes[2]);\n\t\t}\n\n\t\t// swap all the ST\n        st = (md3St_t *) ( (byte *)surf + surf->ofsSt );\n        for ( j = 0 ; j < surf->numVerts ; j++, st++ ) {\n            st->st[0] = LittleFloat( st->st[0] );\n            st->st[1] = LittleFloat( st->st[1] );\n        }\n\n\t\t// swap all the XyzNormals\n        xyz = (md3XyzNormal_t *) ( (byte *)surf + surf->ofsXyzNormals );\n        for ( j = 0 ; j < surf->numVerts * surf->numFrames ; j++, xyz++ ) \n\t\t{\n            xyz->xyz[0] = LittleShort( xyz->xyz[0] );\n            xyz->xyz[1] = LittleShort( xyz->xyz[1] );\n            xyz->xyz[2] = LittleShort( xyz->xyz[2] );\n\n            xyz->normal = LittleShort( xyz->normal );\n        }\n\n\n\t\t// find the next surface\n\t\tsurf = (md3Surface_t *)( (byte *)surf + surf->ofsEnd );\n\t}\n    \n\treturn qtrue;\n}\n\n\n\n/*\n=================\nR_LoadMD4\n=================\n*/\nstatic qboolean R_LoadMD4( model_t *mod, void *buffer, const char *mod_name ) {\n\tint\t\t\t\t\ti, j, k, lodindex;\n\tmd4Header_t\t\t\t*pinmodel, *md4;\n    md4Frame_t\t\t\t*frame;\n\tmd4LOD_t\t\t\t*lod;\n\tmd4Surface_t\t\t*surf;\n\tmd4Triangle_t\t\t*tri;\n\tmd4Vertex_t\t\t\t*v;\n\tint\t\t\t\t\tversion;\n\tint\t\t\t\t\tsize;\n\tshader_t\t\t\t*sh;\n\tint\t\t\t\t\tframeSize;\n\n\tpinmodel = (md4Header_t *)buffer;\n\n\tversion = LittleLong (pinmodel->version);\n\tif (version != MD4_VERSION) {\n\t\tri.Printf( PRINT_WARNING, \"R_LoadMD4: %s has wrong version (%i should be %i)\\n\",\n\t\t\t\t mod_name, version, MD4_VERSION);\n\t\treturn qfalse;\n\t}\n\n\tmod->type = MOD_MD4;\n\tsize = LittleLong(pinmodel->ofsEnd);\n\tmod->dataSize += size;\n\tmd4 = mod->md4 = (md4Header_t*) ri.Hunk_Alloc( size, h_low );\n\n\tCom_Memcpy( md4, buffer, LittleLong(pinmodel->ofsEnd) );\n\n    LL(md4->ident);\n    LL(md4->version);\n    LL(md4->numFrames);\n    LL(md4->numBones);\n    LL(md4->numLODs);\n    LL(md4->ofsFrames);\n    LL(md4->ofsLODs);\n    LL(md4->ofsEnd);\n\n\tif ( md4->numFrames < 1 ) {\n\t\tri.Printf( PRINT_WARNING, \"R_LoadMD4: %s has no frames\\n\", mod_name );\n\t\treturn qfalse;\n\t}\n\n    // we don't need to swap tags in the renderer, they aren't used\n    \n\t// swap all the frames\n\tframeSize = (int)(intptr_t)( &((md4Frame_t *)0)->bones[ md4->numBones ] );\n    for ( i = 0 ; i < md4->numFrames ; i++, frame++) {\n\t    frame = (md4Frame_t *) ( (byte *)md4 + md4->ofsFrames + i * frameSize );\n    \tframe->radius = LittleFloat( frame->radius );\n        for ( j = 0 ; j < 3 ; j++ ) {\n            frame->bounds[0][j] = LittleFloat( frame->bounds[0][j] );\n            frame->bounds[1][j] = LittleFloat( frame->bounds[1][j] );\n\t    \tframe->localOrigin[j] = LittleFloat( frame->localOrigin[j] );\n        }\n\t\tfor ( j = 0 ; j < md4->numBones * sizeof( md4Bone_t ) / 4 ; j++ ) {\n\t\t\t((float *)frame->bones)[j] = LittleFloat( ((float *)frame->bones)[j] );\n\t\t}\n\t}\n\n\t// swap all the LOD's\n\tlod = (md4LOD_t *) ( (byte *)md4 + md4->ofsLODs );\n\tfor ( lodindex = 0 ; lodindex < md4->numLODs ; lodindex++ ) {\n\n\t\t// swap all the surfaces\n\t\tsurf = (md4Surface_t *) ( (byte *)lod + lod->ofsSurfaces );\n\t\tfor ( i = 0 ; i < lod->numSurfaces ; i++) {\n\t\t\tLL(surf->ident);\n\t\t\tLL(surf->numTriangles);\n\t\t\tLL(surf->ofsTriangles);\n\t\t\tLL(surf->numVerts);\n\t\t\tLL(surf->ofsVerts);\n\t\t\tLL(surf->ofsEnd);\n\t\t\t\n\t\t\tif ( surf->numVerts > SHADER_MAX_VERTEXES ) {\n\t\t\t\tri.Error (ERR_DROP, \"R_LoadMD3: %s has more than %i verts on a surface (%i)\",\n\t\t\t\t\tmod_name, SHADER_MAX_VERTEXES, surf->numVerts );\n\t\t\t}\n\t\t\tif ( surf->numTriangles*3 > SHADER_MAX_INDEXES ) {\n\t\t\t\tri.Error (ERR_DROP, \"R_LoadMD3: %s has more than %i triangles on a surface (%i)\",\n\t\t\t\t\tmod_name, SHADER_MAX_INDEXES / 3, surf->numTriangles );\n\t\t\t}\n\n\t\t\t// change to surface identifier\n\t\t\tsurf->ident = SF_MD4;\n\n\t\t\t// lowercase the surface name so skin compares are faster\n\t\t\tQ_strlwr( surf->name );\n\t\t\n\t\t\t// register the shaders\n\t\t\tsh = R_FindShader( surf->shader, LIGHTMAP_NONE, qtrue );\n\t\t\tif ( sh->defaultShader ) {\n\t\t\t\tsurf->shaderIndex = 0;\n\t\t\t} else {\n\t\t\t\tsurf->shaderIndex = sh->index;\n\t\t\t}\n\n\t\t\t// swap all the triangles\n\t\t\ttri = (md4Triangle_t *) ( (byte *)surf + surf->ofsTriangles );\n\t\t\tfor ( j = 0 ; j < surf->numTriangles ; j++, tri++ ) {\n\t\t\t\tLL(tri->indexes[0]);\n\t\t\t\tLL(tri->indexes[1]);\n\t\t\t\tLL(tri->indexes[2]);\n\t\t\t}\n\n\t\t\t// swap all the vertexes\n\t\t\t// FIXME\n\t\t\t// This makes TFC's skeletons work.  Shouldn't be necessary anymore, but left\n\t\t\t// in for reference.\n\t\t\t//v = (md4Vertex_t *) ( (byte *)surf + surf->ofsVerts + 12);\n\t\t\tv = (md4Vertex_t *) ( (byte *)surf + surf->ofsVerts);\n\t\t\tfor ( j = 0 ; j < surf->numVerts ; j++ ) {\n\t\t\t\tv->normal[0] = LittleFloat( v->normal[0] );\n\t\t\t\tv->normal[1] = LittleFloat( v->normal[1] );\n\t\t\t\tv->normal[2] = LittleFloat( v->normal[2] );\n\n\t\t\t\tv->texCoords[0] = LittleFloat( v->texCoords[0] );\n\t\t\t\tv->texCoords[1] = LittleFloat( v->texCoords[1] );\n\n\t\t\t\tv->numWeights = LittleLong( v->numWeights );\n\n\t\t\t\tfor ( k = 0 ; k < v->numWeights ; k++ ) {\n\t\t\t\t\tv->weights[k].boneIndex = LittleLong( v->weights[k].boneIndex );\n\t\t\t\t\tv->weights[k].boneWeight = LittleFloat( v->weights[k].boneWeight );\n\t\t\t\t   v->weights[k].offset[0] = LittleFloat( v->weights[k].offset[0] );\n\t\t\t\t   v->weights[k].offset[1] = LittleFloat( v->weights[k].offset[1] );\n\t\t\t\t   v->weights[k].offset[2] = LittleFloat( v->weights[k].offset[2] );\n\t\t\t\t}\n\t\t\t\t// FIXME\n\t\t\t\t// This makes TFC's skeletons work.  Shouldn't be necessary anymore, but left\n\t\t\t\t// in for reference.\n\t\t\t\t//v = (md4Vertex_t *)( ( byte * )&v->weights[v->numWeights] + 12 );\n\t\t\t\tv = (md4Vertex_t *)( ( byte * )&v->weights[v->numWeights]);\n\t\t\t}\n\n\t\t\t// find the next surface\n\t\t\tsurf = (md4Surface_t *)( (byte *)surf + surf->ofsEnd );\n\t\t}\n\n\t\t// find the next LOD\n\t\tlod = (md4LOD_t *)( (byte *)lod + lod->ofsEnd );\n\t}\n\n\treturn qtrue;\n}\n\n\n\n\n//=============================================================================\n\n/*\n** RE_BeginRegistration\n*/\nvoid RE_BeginRegistration( glconfig_t *glconfigOut ) {\n\n\tR_Init();\n\n\t*glconfigOut = glConfig;\n\n\tR_SyncRenderThread();\n\n\ttr.viewCluster = -1;\t\t// force markleafs to regenerate\n\tRE_ClearScene();\n\n\ttr.registered = qtrue;\n}\n\n//=============================================================================\n\n/*\n===============\nR_ModelInit\n===============\n*/\nvoid R_ModelInit( void ) {\n\tmodel_t\t\t*mod;\n\n\t// leave a space for NULL model\n\ttr.numModels = 0;\n\n\tmod = R_AllocModel();\n\tmod->type = MOD_BAD;\n}\n\n\n/*\n================\nR_Modellist_f\n================\n*/\nvoid R_Modellist_f( void ) {\n\tint\t\ti, j;\n\tmodel_t\t*mod;\n\tint\t\ttotal;\n\tint\t\tlods;\n\n\ttotal = 0;\n\tfor ( i = 1 ; i < tr.numModels; i++ ) {\n\t\tmod = tr.models[i];\n\t\tlods = 1;\n\t\tfor ( j = 1 ; j < MD3_MAX_LODS ; j++ ) {\n\t\t\tif ( mod->md3[j] && mod->md3[j] != mod->md3[j-1] ) {\n\t\t\t\tlods++;\n\t\t\t}\n\t\t}\n\t\tri.Printf( PRINT_ALL, \"%8i : (%i) %s\\n\",mod->dataSize, lods, mod->name );\n\t\ttotal += mod->dataSize;\n\t}\n\tri.Printf( PRINT_ALL, \"%8i : Total models\\n\", total );\n\n#if\t0\t\t// not working right with new hunk\n\tif ( tr.world ) {\n\t\tri.Printf( PRINT_ALL, \"\\n%8i : %s\\n\", tr.world->dataSize, tr.world->name );\n\t}\n#endif\n}\n\n\n//=============================================================================\n\n\n/*\n================\nR_GetTag\n================\n*/\nstatic md3Tag_t *R_GetTag( md3Header_t *mod, int frame, const char *tagName ) {\n\tmd3Tag_t\t\t*tag;\n\tint\t\t\t\ti;\n\n\tif ( frame >= mod->numFrames ) {\n\t\t// it is possible to have a bad frame while changing models, so don't error\n\t\tframe = mod->numFrames - 1;\n\t}\n\n\ttag = (md3Tag_t *)((byte *)mod + mod->ofsTags) + frame * mod->numTags;\n\tfor ( i = 0 ; i < mod->numTags ; i++, tag++ ) {\n\t\tif ( !strcmp( tag->name, tagName ) ) {\n\t\t\treturn tag;\t// found it\n\t\t}\n\t}\n\n\treturn NULL;\n}\n\n/*\n================\nR_LerpTag\n================\n*/\nint R_LerpTag( orientation_t *tag, qhandle_t handle, int startFrame, int endFrame, \n\t\t\t\t\t float frac, const char *tagName ) {\n\tmd3Tag_t\t*start, *end;\n\tint\t\ti;\n\tfloat\t\tfrontLerp, backLerp;\n\tmodel_t\t\t*model;\n\n\tmodel = R_GetModelByHandle( handle );\n\tif ( !model->md3[0] ) {\n\t\tAxisClear( tag->axis );\n\t\tVectorClear( tag->origin );\n\t\treturn qfalse;\n\t}\n\n\tstart = R_GetTag( model->md3[0], startFrame, tagName );\n\tend = R_GetTag( model->md3[0], endFrame, tagName );\n\tif ( !start || !end ) {\n\t\tAxisClear( tag->axis );\n\t\tVectorClear( tag->origin );\n\t\treturn qfalse;\n\t}\n\n\tfrontLerp = frac;\n\tbackLerp = 1.0f - frac;\n\n\tfor ( i = 0 ; i < 3 ; i++ ) {\n\t\ttag->origin[i] = start->origin[i] * backLerp +  end->origin[i] * frontLerp;\n\t\ttag->axis[0][i] = start->axis[0][i] * backLerp +  end->axis[0][i] * frontLerp;\n\t\ttag->axis[1][i] = start->axis[1][i] * backLerp +  end->axis[1][i] * frontLerp;\n\t\ttag->axis[2][i] = start->axis[2][i] * backLerp +  end->axis[2][i] * frontLerp;\n\t}\n\tVectorNormalize( tag->axis[0] );\n\tVectorNormalize( tag->axis[1] );\n\tVectorNormalize( tag->axis[2] );\n\treturn qtrue;\n}\n\n\n/*\n====================\nR_ModelBounds\n====================\n*/\nvoid R_ModelBounds( qhandle_t handle, vec3_t mins, vec3_t maxs ) {\n\tmodel_t\t\t*model;\n\tmd3Header_t\t*header;\n\tmd3Frame_t\t*frame;\n\n\tmodel = R_GetModelByHandle( handle );\n\n\tif ( model->bmodel ) {\n\t\tVectorCopy( model->bmodel->bounds[0], mins );\n\t\tVectorCopy( model->bmodel->bounds[1], maxs );\n\t\treturn;\n\t}\n\n\tif ( !model->md3[0] ) {\n\t\tVectorClear( mins );\n\t\tVectorClear( maxs );\n\t\treturn;\n\t}\n\n\theader = model->md3[0];\n\n\tframe = (md3Frame_t *)( (byte *)header + header->ofsFrames );\n\n\tVectorCopy( frame->bounds[0], mins );\n\tVectorCopy( frame->bounds[1], maxs );\n}\n"
  },
  {
    "path": "src/engine/renderer/tr_noise.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n// tr_noise.c\n#include \"tr_local.h\"\n\n#define NOISE_SIZE 256\n#define NOISE_MASK ( NOISE_SIZE - 1 )\n\n#define VAL( a ) s_noise_perm[ ( a ) & ( NOISE_MASK )]\n#define INDEX( x, y, z, t ) VAL( x + VAL( y + VAL( z + VAL( t ) ) ) )\n\nstatic float s_noise_table[NOISE_SIZE];\nstatic int s_noise_perm[NOISE_SIZE];\n\n#define LERP( a, b, w ) ( a * ( 1.0f - w ) + b * w )\n\nstatic float GetNoiseValue( int x, int y, int z, int t )\n{\n\tint index = INDEX( ( int ) x, ( int ) y, ( int ) z, ( int ) t );\n\n\treturn s_noise_table[index];\n}\n\nvoid R_NoiseInit( void )\n{\n\tint i;\n\n\tsrand( 1001 );\n\n\tfor ( i = 0; i < NOISE_SIZE; i++ )\n\t{\n\t\ts_noise_table[i] = ( float ) ( ( ( rand() / ( float ) RAND_MAX ) * 2.0 - 1.0 ) );\n\t\ts_noise_perm[i] = ( unsigned char ) ( rand() / ( float ) RAND_MAX * 255 );\n\t}\n}\n\nfloat R_NoiseGet4f( float x, float y, float z, float t )\n{\n\tint i;\n\tint ix, iy, iz, it;\n\tfloat fx, fy, fz, ft;\n\tfloat front[4];\n\tfloat back[4];\n\tfloat fvalue, bvalue, value[2], finalvalue;\n\n\tix = ( int ) floor( x );\n\tfx = x - ix;\n\tiy = ( int ) floor( y );\n\tfy = y - iy;\n\tiz = ( int ) floor( z );\n\tfz = z - iz;\n\tit = ( int ) floor( t );\n\tft = t - it;\n\n\tfor ( i = 0; i < 2; i++ )\n\t{\n\t\tfront[0] = GetNoiseValue( ix, iy, iz, it + i );\n\t\tfront[1] = GetNoiseValue( ix+1, iy, iz, it + i );\n\t\tfront[2] = GetNoiseValue( ix, iy+1, iz, it + i );\n\t\tfront[3] = GetNoiseValue( ix+1, iy+1, iz, it + i );\n\n\t\tback[0] = GetNoiseValue( ix, iy, iz + 1, it + i );\n\t\tback[1] = GetNoiseValue( ix+1, iy, iz + 1, it + i );\n\t\tback[2] = GetNoiseValue( ix, iy+1, iz + 1, it + i );\n\t\tback[3] = GetNoiseValue( ix+1, iy+1, iz + 1, it + i );\n\n\t\tfvalue = LERP( LERP( front[0], front[1], fx ), LERP( front[2], front[3], fx ), fy );\n\t\tbvalue = LERP( LERP( back[0], back[1], fx ), LERP( back[2], back[3], fx ), fy );\n\n\t\tvalue[i] = LERP( fvalue, bvalue, fz );\n\t}\n\n\tfinalvalue = LERP( value[0], value[1], ft );\n\n\treturn finalvalue;\n}\n"
  },
  {
    "path": "src/engine/renderer/tr_public.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n#ifndef __TR_PUBLIC_H\n#define __TR_PUBLIC_H\n\n#include \"../../cgame/tr_types.h\"\n\n#define\tREF_API_VERSION\t\t8\n\n//\n// these are the functions exported by the refresh module\n//\ntypedef struct {\n\t// called before the library is unloaded\n\t// if the system is just reconfiguring, pass destroyWindow = qfalse,\n\t// which will keep the screen from flashing to the desktop.\n\tvoid\t(*Shutdown)( qboolean destroyWindow );\n\n\t// All data that will be used in a level should be\n\t// registered before rendering any frames to prevent disk hits,\n\t// but they can still be registered at a later time\n\t// if necessary.\n\t//\n\t// BeginRegistration makes any existing media pointers invalid\n\t// and returns the current gl configuration, including screen width\n\t// and height, which can be used by the client to intelligently\n\t// size display elements\n\tvoid\t(*BeginRegistration)( glconfig_t *config );\n\tqhandle_t (*RegisterModel)( const char *name );\n\tqhandle_t (*RegisterSkin)( const char *name );\n\tqhandle_t (*RegisterShader)( const char *name );\n\tqhandle_t (*RegisterShaderNoMip)( const char *name );\n\tvoid\t(*LoadWorld)( const char *name );\n\n\t// the vis data is a large enough block of data that we go to the trouble\n\t// of sharing it with the clipmodel subsystem\n\tvoid\t(*SetWorldVisData)( const byte *vis );\n\n\t// EndRegistration will draw a tiny polygon with each texture, forcing\n\t// them to be loaded into card memory\n\tvoid\t(*EndRegistration)( void );\n\n\t// a scene is built up by calls to R_ClearScene and the various R_Add functions.\n\t// Nothing is drawn until R_RenderScene is called.\n\tvoid\t(*ClearScene)( void );\n\tvoid\t(*AddRefEntityToScene)( const refEntity_t *re );\n\tvoid\t(*AddPolyToScene)( qhandle_t hShader , int numVerts, const polyVert_t *verts, int num );\n\tint\t\t(*LightForPoint)( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir );\n\tvoid\t(*AddLightToScene)( const vec3_t org, float intensity, float r, float g, float b );\n\tvoid\t(*AddAdditiveLightToScene)( const vec3_t org, float intensity, float r, float g, float b );\n\tvoid\t(*RenderScene)( const refdef_t *fd );\n\n\tvoid\t(*SetColor)( const float *rgba );\t// NULL = 1,1,1,1\n\tvoid\t(*DrawStretchPic) ( float x, float y, float w, float h, \n\t\tfloat s1, float t1, float s2, float t2, qhandle_t hShader );\t// 0 = white\n\n\t// Draw images for cinematic rendering, pass as 32 bit rgba\n\tvoid\t(*DrawStretchRaw) (int x, int y, int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty);\n\tvoid\t(*UploadCinematic) (int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty);\n\n\tvoid\t(*BeginFrame)( stereoFrame_t stereoFrame );\n\n\t// if the pointers are not NULL, timing info will be returned\n\tvoid\t(*EndFrame)( int *frontEndMsec, int *backEndMsec );\n\n\n\tint\t\t(*MarkFragments)( int numPoints, const vec3_t *points, const vec3_t projection,\n\t\t\t\t   int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer );\n\n\tint\t\t(*LerpTag)( orientation_t *tag,  qhandle_t model, int startFrame, int endFrame, \n\t\t\t\t\t float frac, const char *tagName );\n\tvoid\t(*ModelBounds)( qhandle_t model, vec3_t mins, vec3_t maxs );\n\n#ifdef __USEA3D\n\tvoid    (*A3D_RenderGeometry) (void *pVoidA3D, void *pVoidGeom, void *pVoidMat, void *pVoidGeomStatus);\n#endif\n\tvoid\t(*RegisterFont)(const char *fontName, int pointSize, fontInfo_t *font);\n\tvoid\t(*RemapShader)(const char *oldShader, const char *newShader, const char *offsetTime);\n\tqboolean (*GetEntityToken)( char *buffer, int size );\n\tqboolean (*inPVS)( const vec3_t p1, const vec3_t p2 );\n} refexport_t;\n\n//\n// these are the functions imported by the refresh module\n//\ntypedef struct {\n\t// print message on the local console\n\tvoid\t(QDECL *Printf)( int printLevel, const char *fmt, ...);\n\n\t// abort the game\n\tvoid\t(QDECL *Error)( int errorLevel, const char *fmt, ...);\n\n\t// milliseconds should only be used for profiling, never\n\t// for anything game related.  Get time from the refdef\n\tint\t\t(*Milliseconds)( void );\n\n\t// stack based memory allocation for per-level things that\n\t// won't be freed\n#ifdef HUNK_DEBUG\n\tvoid\t*(*Hunk_AllocDebug)( int size, ha_pref pref, char *label, char *file, int line );\n#else\n\tvoid\t*(*Hunk_Alloc)( int size, ha_pref pref );\n#endif\n\tvoid\t*(*Hunk_AllocateTempMemory)( int size );\n\tvoid\t(*Hunk_FreeTempMemory)( void *block );\n\n\t// dynamic memory allocator for things that need to be freed\n\tvoid\t*(*Malloc)( int bytes );\n\tvoid\t(*Free)( void *buf );\n\n\tcvar_t\t*(*Cvar_Get)( const char *name, const char *value, int flags );\n\tvoid\t(*Cvar_Set)( const char *name, const char *value );\n\n\tvoid\t(*Cmd_AddCommand)( const char *name, void(*cmd)(void) );\n\tvoid\t(*Cmd_RemoveCommand)( const char *name );\n\n\tint\t\t(*Cmd_Argc) (void);\n\tchar\t*(*Cmd_Argv) (int i);\n\n\tvoid\t(*Cmd_ExecuteText) (int exec_when, const char *text);\n\n\t// visualization for debugging collision detection\n\tvoid\t(*CM_DrawDebugSurface)( void (*drawPoly)(int color, int numPoints, float *points) );\n\n\t// a -1 return means the file does not exist\n\t// NULL can be passed for buf to just determine existance\n\tint\t\t(*FS_FileIsInPAK)( const char *name, int *pCheckSum );\n\tint\t\t(*FS_ReadFile)( const char *name, void **buf );\n\tvoid\t(*FS_FreeFile)( void *buf );\n\tchar **\t(*FS_ListFiles)( const char *name, const char *extension, int *numfilesfound );\n\tvoid\t(*FS_FreeFileList)( char **filelist );\n\tvoid\t(*FS_WriteFile)( const char *qpath, const void *buffer, int size );\n\tqboolean (*FS_FileExists)( const char *file );\n\n\t// cinematic stuff\n\tvoid\t(*CIN_UploadCinematic)(int handle);\n\tint\t\t(*CIN_PlayCinematic)( const char *arg0, int xpos, int ypos, int width, int height, int bits);\n\te_status (*CIN_RunCinematic) (int handle);\n\n} refimport_t;\n\n\n// this is the only function actually exported at the linker level\n// If the module can't init to a valid rendering state, NULL will be\n// returned.\nrefexport_t*GetRefAPI( int apiVersion, refimport_t *rimp );\n\n#endif\t// __TR_PUBLIC_H\n"
  },
  {
    "path": "src/engine/renderer/tr_scene.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n#include \"tr_local.h\"\n\nint\t\t\tr_firstSceneDrawSurf;\n\nint\t\t\tr_numdlights;\nint\t\t\tr_firstSceneDlight;\n\nint\t\t\tr_numentities;\nint\t\t\tr_firstSceneEntity;\n\nint\t\t\tr_numpolys;\nint\t\t\tr_firstScenePoly;\n\nint\t\t\tr_numpolyverts;\n\n\n/*\n====================\nR_ToggleSmpFrame\n\n====================\n*/\nvoid R_ToggleSmpFrame( void ) {\n\tif ( r_smp->integer ) {\n\t\t// use the other buffers next frame, because another CPU\n\t\t// may still be rendering into the current ones\n\t\ttr.smpFrame ^= 1;\n\t} else {\n\t\ttr.smpFrame = 0;\n\t}\n\n\tbackEndData[tr.smpFrame]->commands.used = 0;\n\n\tr_firstSceneDrawSurf = 0;\n\n\tr_numdlights = 0;\n\tr_firstSceneDlight = 0;\n\n\tr_numentities = 0;\n\tr_firstSceneEntity = 0;\n\n\tr_numpolys = 0;\n\tr_firstScenePoly = 0;\n\n\tr_numpolyverts = 0;\n}\n\n\n/*\n====================\nRE_ClearScene\n\n====================\n*/\nvoid RE_ClearScene( void ) {\n\tr_firstSceneDlight = r_numdlights;\n\tr_firstSceneEntity = r_numentities;\n\tr_firstScenePoly = r_numpolys;\n}\n\n/*\n===========================================================================\n\nDISCRETE POLYS\n\n===========================================================================\n*/\n\n/*\n=====================\nR_AddPolygonSurfaces\n\nAdds all the scene's polys into this view's drawsurf list\n=====================\n*/\nvoid R_AddPolygonSurfaces( void ) {\n\tint\t\t\ti;\n\tshader_t\t*sh;\n\tsrfPoly_t\t*poly;\n\n\ttr.currentEntityNum = ENTITYNUM_WORLD;\n\ttr.shiftedEntityNum = tr.currentEntityNum << QSORT_ENTITYNUM_SHIFT;\n\n\tfor ( i = 0, poly = tr.refdef.polys; i < tr.refdef.numPolys ; i++, poly++ ) {\n\t\tsh = R_GetShaderByHandle( poly->hShader );\n\t\tR_AddDrawSurf( (surfaceType_t*) ( void * )poly, sh, poly->fogIndex, qfalse );\n\t}\n}\n\n/*\n=====================\nRE_AddPolyToScene\n\n=====================\n*/\nvoid RE_AddPolyToScene( qhandle_t hShader, int numVerts, const polyVert_t *verts, int numPolys ) {\n\tsrfPoly_t\t*poly;\n\tint\t\t\ti, j;\n\tint\t\t\tfogIndex;\n\tfog_t\t\t*fog;\n\tvec3_t\t\tbounds[2];\n\n\tif ( !tr.registered ) {\n\t\treturn;\n\t}\n\n\tif ( !hShader ) {\n\t\tri.Printf( PRINT_WARNING, \"WARNING: RE_AddPolyToScene: NULL poly shader\\n\");\n\t\treturn;\n\t}\n\n\tfor ( j = 0; j < numPolys; j++ ) {\n\t\tif ( r_numpolyverts + numVerts > max_polyverts || r_numpolys >= max_polys ) {\n      /*\n      NOTE TTimo this was initially a PRINT_WARNING\n      but it happens a lot with high fighting scenes and particles\n      since we don't plan on changing the const and making for room for those effects\n      simply cut this message to developer only\n      */\n\t\t\tri.Printf( PRINT_DEVELOPER, \"WARNING: RE_AddPolyToScene: r_max_polys or r_max_polyverts reached\\n\");\n\t\t\treturn;\n\t\t}\n\n\t\tpoly = &backEndData[tr.smpFrame]->polys[r_numpolys];\n\t\tpoly->surfaceType = SF_POLY;\n\t\tpoly->hShader = hShader;\n\t\tpoly->numVerts = numVerts;\n\t\tpoly->verts = &backEndData[tr.smpFrame]->polyVerts[r_numpolyverts];\n\t\t\n\t\tCom_Memcpy( poly->verts, &verts[numVerts*j], numVerts * sizeof( *verts ) );\n\n\t\t// done.\n\t\tr_numpolys++;\n\t\tr_numpolyverts += numVerts;\n\n\t\t// if no world is loaded\n\t\tif ( tr.world == NULL ) {\n\t\t\tfogIndex = 0;\n\t\t}\n\t\t// see if it is in a fog volume\n\t\telse if ( tr.world->numfogs == 1 ) {\n\t\t\tfogIndex = 0;\n\t\t} else {\n\t\t\t// find which fog volume the poly is in\n\t\t\tVectorCopy( poly->verts[0].xyz, bounds[0] );\n\t\t\tVectorCopy( poly->verts[0].xyz, bounds[1] );\n\t\t\tfor ( i = 1 ; i < poly->numVerts ; i++ ) {\n\t\t\t\tAddPointToBounds( poly->verts[i].xyz, bounds[0], bounds[1] );\n\t\t\t}\n\t\t\tfor ( fogIndex = 1 ; fogIndex < tr.world->numfogs ; fogIndex++ ) {\n\t\t\t\tfog = &tr.world->fogs[fogIndex]; \n\t\t\t\tif ( bounds[1][0] >= fog->bounds[0][0]\n\t\t\t\t\t&& bounds[1][1] >= fog->bounds[0][1]\n\t\t\t\t\t&& bounds[1][2] >= fog->bounds[0][2]\n\t\t\t\t\t&& bounds[0][0] <= fog->bounds[1][0]\n\t\t\t\t\t&& bounds[0][1] <= fog->bounds[1][1]\n\t\t\t\t\t&& bounds[0][2] <= fog->bounds[1][2] ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif ( fogIndex == tr.world->numfogs ) {\n\t\t\t\tfogIndex = 0;\n\t\t\t}\n\t\t}\n\t\tpoly->fogIndex = fogIndex;\n\t}\n}\n\n\n//=================================================================================\n\n\n/*\n=====================\nRE_AddRefEntityToScene\n\n=====================\n*/\nvoid RE_AddRefEntityToScene( const refEntity_t *ent ) {\n\tif ( !tr.registered ) {\n\t\treturn;\n\t}\n  // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=402\n\tif ( r_numentities >= ENTITYNUM_WORLD ) {\n\t\treturn;\n\t}\n\tif ( ent->reType < 0 || ent->reType >= RT_MAX_REF_ENTITY_TYPE ) {\n\t\tri.Error( ERR_DROP, \"RE_AddRefEntityToScene: bad reType %i\", ent->reType );\n\t}\n\n\tbackEndData[tr.smpFrame]->entities[r_numentities].e = *ent;\n\tbackEndData[tr.smpFrame]->entities[r_numentities].lightingCalculated = qfalse;\n\n\tr_numentities++;\n}\n\n\n/*\n=====================\nRE_AddDynamicLightToScene\n\n=====================\n*/\nvoid RE_AddDynamicLightToScene( const vec3_t org, float intensity, float r, float g, float b, int additive ) {\n\tdlight_t\t*dl;\n\n\tif ( !tr.registered ) {\n\t\treturn;\n\t}\n\tif ( r_numdlights >= MAX_DLIGHTS ) {\n\t\treturn;\n\t}\n\tif ( intensity <= 0 ) {\n\t\treturn;\n\t}\n\tdl = &backEndData[tr.smpFrame]->dlights[r_numdlights++];\n\tVectorCopy (org, dl->origin);\n\tdl->radius = intensity;\n\tdl->color[0] = r;\n\tdl->color[1] = g;\n\tdl->color[2] = b;\n\tdl->additive = additive;\n}\n\n/*\n=====================\nRE_AddLightToScene\n\n=====================\n*/\nvoid RE_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b ) {\n\tRE_AddDynamicLightToScene( org, intensity, r, g, b, qfalse );\n}\n\n/*\n=====================\nRE_AddAdditiveLightToScene\n\n=====================\n*/\nvoid RE_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, float g, float b ) {\n\tRE_AddDynamicLightToScene( org, intensity, r, g, b, qtrue );\n}\n\n/*\n@@@@@@@@@@@@@@@@@@@@@\nRE_RenderScene\n\nDraw a 3D view into a part of the window, then return\nto 2D drawing.\n\nRendering a scene may require multiple views to be rendered\nto handle mirrors,\n@@@@@@@@@@@@@@@@@@@@@\n*/\nvoid RE_RenderScene( const refdef_t *fd ) {\n\tviewParms_t\t\tparms;\n\tint\t\t\t\tstartTime;\n\n\tif ( !tr.registered ) {\n\t\treturn;\n\t}\n\tGLimp_LogComment( \"====== RE_RenderScene =====\\n\" );\n\n\tif ( r_norefresh->integer ) {\n\t\treturn;\n\t}\n\n\tstartTime = ri.Milliseconds();\n\n\tif (!tr.world && !( fd->rdflags & RDF_NOWORLDMODEL ) ) {\n\t\tri.Error (ERR_DROP, \"R_RenderScene: NULL worldmodel\");\n\t}\n\n\tCom_Memcpy( tr.refdef.text, fd->text, sizeof( tr.refdef.text ) );\n\n\ttr.refdef.x = fd->x;\n\ttr.refdef.y = fd->y;\n\ttr.refdef.width = fd->width;\n\ttr.refdef.height = fd->height;\n\ttr.refdef.fov_x = fd->fov_x;\n\ttr.refdef.fov_y = fd->fov_y;\n\n\tVectorCopy( fd->vieworg, tr.refdef.vieworg );\n\tVectorCopy( fd->viewaxis[0], tr.refdef.viewaxis[0] );\n\tVectorCopy( fd->viewaxis[1], tr.refdef.viewaxis[1] );\n\tVectorCopy( fd->viewaxis[2], tr.refdef.viewaxis[2] );\n\n\ttr.refdef.time = fd->time;\n\ttr.refdef.rdflags = fd->rdflags;\n\n\t// copy the areamask data over and note if it has changed, which\n\t// will force a reset of the visible leafs even if the view hasn't moved\n\ttr.refdef.areamaskModified = qfalse;\n\tif ( ! (tr.refdef.rdflags & RDF_NOWORLDMODEL) ) {\n\t\tint\t\tareaDiff;\n\t\tint\t\ti;\n\n\t\t// compare the area bits\n\t\tareaDiff = 0;\n\t\tfor (i = 0 ; i < MAX_MAP_AREA_BYTES/4 ; i++) {\n\t\t\tareaDiff |= ((int *)tr.refdef.areamask)[i] ^ ((int *)fd->areamask)[i];\n\t\t\t((int *)tr.refdef.areamask)[i] = ((int *)fd->areamask)[i];\n\t\t}\n\n\t\tif ( areaDiff ) {\n\t\t\t// a door just opened or something\n\t\t\ttr.refdef.areamaskModified = qtrue;\n\t\t}\n\t}\n\n\n\t// derived info\n\n\ttr.refdef.floatTime = tr.refdef.time * 0.001f;\n\n\ttr.refdef.numDrawSurfs = r_firstSceneDrawSurf;\n\ttr.refdef.drawSurfs = backEndData[tr.smpFrame]->drawSurfs;\n\n\ttr.refdef.num_entities = r_numentities - r_firstSceneEntity;\n\ttr.refdef.entities = &backEndData[tr.smpFrame]->entities[r_firstSceneEntity];\n\n\ttr.refdef.num_dlights = r_numdlights - r_firstSceneDlight;\n\ttr.refdef.dlights = &backEndData[tr.smpFrame]->dlights[r_firstSceneDlight];\n\n\ttr.refdef.numPolys = r_numpolys - r_firstScenePoly;\n\ttr.refdef.polys = &backEndData[tr.smpFrame]->polys[r_firstScenePoly];\n\n\t// turn off dynamic lighting globally by clearing all the\n\t// dlights if it needs to be disabled or if vertex lighting is enabled\n\tif ( r_dynamiclight->integer == 0 || r_vertexLight->integer == 1 ) {\n\t\ttr.refdef.num_dlights = 0;\n\t}\n\n\t// setup view parms for the initial view\n\t//\n\t// set up viewport\n\t// The refdef takes 0-at-the-top y coordinates, so\n\t// convert to GL's 0-at-the-bottom space\n\t//\n\tCom_Memset( &parms, 0, sizeof( parms ) );\n\tparms.viewportX = tr.refdef.x;\n\tparms.viewportY = glConfig.vidHeight - ( tr.refdef.y + tr.refdef.height );\n\tparms.viewportWidth = tr.refdef.width;\n\tparms.viewportHeight = tr.refdef.height;\n\tparms.isPortal = qfalse;\n\n\tparms.fovX = tr.refdef.fov_x;\n\tparms.fovY = tr.refdef.fov_y;\n\n\tVectorCopy( fd->vieworg, parms.or.origin );\n\tVectorCopy( fd->viewaxis[0], parms.or.axis[0] );\n\tVectorCopy( fd->viewaxis[1], parms.or.axis[1] );\n\tVectorCopy( fd->viewaxis[2], parms.or.axis[2] );\n\n\tVectorCopy( fd->vieworg, parms.pvsOrigin );\n\n\tR_RenderView( &parms );\n\n\t// the next scene rendered in this frame will tack on after this one\n\tr_firstSceneDrawSurf = tr.refdef.numDrawSurfs;\n\tr_firstSceneEntity = r_numentities;\n\tr_firstSceneDlight = r_numdlights;\n\tr_firstScenePoly = r_numpolys;\n\n\ttr.frontEndMsec += ri.Milliseconds() - startTime;\n}\n"
  },
  {
    "path": "src/engine/renderer/tr_shade.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n// tr_shade.c\n\n#include \"tr_local.h\"\n\n/*\n\n  THIS ENTIRE FILE IS BACK END\n\n  This file deals with applying shaders to surface data in the tess struct.\n*/\n\n/*\n==================\nR_DrawElements\n==================\n*/\nstatic void R_DrawElements( int numIndexes, const glIndex_t *indexes ) {\n    qglDrawElements(GL_TRIANGLES, numIndexes, GL_INDEX_TYPE, indexes);\n}\n\n/*\n=============================================================\n\nSURFACE SHADERS\n\n=============================================================\n*/\n\nshaderCommands_t\ttess;\nstatic qboolean\tsetArraysOnce;\n\n/*\n=================\nR_BindAnimatedImage\n\n=================\n*/\nstatic void R_BindAnimatedImage( textureBundle_t *bundle ) {\n\tint\t\tindex;\n\n\tif ( bundle->isVideoMap ) {\n\t\tri.CIN_RunCinematic(bundle->videoMapHandle);\n\t\tri.CIN_UploadCinematic(bundle->videoMapHandle);\n\t\treturn;\n\t}\n\n\tif ( bundle->numImageAnimations <= 1 ) {\n\t\tGL_Bind( bundle->image[0] );\n\t\treturn;\n\t}\n\n\t// it is necessary to do this messy calc to make sure animations line up\n\t// exactly with waveforms of the same frequency\n\tindex = myftol( tess.shaderTime * bundle->imageAnimationSpeed * FUNCTABLE_SIZE );\n\tindex >>= FUNCTABLE_SIZE2;\n\n\tif ( index < 0 ) {\n\t\tindex = 0;\t// may happen with shader time offsets\n\t}\n\tindex %= bundle->numImageAnimations;\n\n\tGL_Bind( bundle->image[ index ] );\n}\n\n/*\n================\nDrawTris\n\nDraws triangle outlines for debugging\n================\n*/\nstatic void DrawTris (shaderCommands_t *input) {\n\tGL_Bind( tr.whiteImage );\n\tqglColor3f (1,1,1);\n\n\tGL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE );\n\tqglDepthRange( 0, 0 );\n\n\tqglDisableClientState (GL_COLOR_ARRAY);\n\tqglDisableClientState (GL_TEXTURE_COORD_ARRAY);\n\n\tqglVertexPointer (3, GL_FLOAT, 16, input->xyz);\t// padded for SIMD\n\n\tif (qglLockArraysEXT) {\n\t\tqglLockArraysEXT(0, input->numVertexes);\n\t\tGLimp_LogComment( \"glLockArraysEXT\\n\" );\n\t}\n\n\tR_DrawElements( input->numIndexes, input->indexes );\n\n\tif (qglUnlockArraysEXT) {\n\t\tqglUnlockArraysEXT();\n\t\tGLimp_LogComment( \"glUnlockArraysEXT\\n\" );\n\t}\n\tqglDepthRange( 0, 1 );\n\n\t// VULKAN\n\tif (vk.active) {\n\t\tCom_Memset(tess.svars.colors, tr.identityLightByte, tess.numVertexes * 4 );\n\t\tauto pipeline = backEnd.viewParms.isMirror ? vk.tris_mirror_debug_pipeline : vk.tris_debug_pipeline;\n\t\tvk_shade_geometry(pipeline, false, Vk_Depth_Range::force_zero);\n\t}\n\n\t// DX12\n\tif (dx.active) {\n\t\tCom_Memset(tess.svars.colors, tr.identityLightByte, tess.numVertexes * 4 );\n\t\tauto pipeline = backEnd.viewParms.isMirror ? dx.tris_mirror_debug_pipeline : dx.tris_debug_pipeline;\n\t\tdx_shade_geometry(pipeline, false, Vk_Depth_Range::force_zero, true, false);\n\t}\n}\n\n\n/*\n================\nDrawNormals\n\nDraws vertex normals for debugging\n================\n*/\nstatic void DrawNormals (shaderCommands_t *input) {\n\tint\t\ti;\n\tvec3_t\ttemp;\n\n\tGL_Bind( tr.whiteImage );\n\tqglColor3f (1,1,1);\n\tqglDepthRange( 0, 0 );\t// never occluded\n\tGL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE );\n\n\tqglBegin (GL_LINES);\n\tfor (i = 0 ; i < input->numVertexes ; i++) {\n\t\tqglVertex3fv (input->xyz[i]);\n\t\tVectorMA (input->xyz[i], 2, input->normal[i], temp);\n\t\tqglVertex3fv (temp);\n\t}\n\tqglEnd ();\n\n\tqglDepthRange( 0, 1 );\n\n\t// VULKAN\n\t// DX12\n\tif (vk.active || dx.active) {\n\t\tvec4_t xyz[SHADER_MAX_VERTEXES];\n\t\tCom_Memcpy(xyz, tess.xyz, tess.numVertexes * sizeof(vec4_t));\n\t\tCom_Memset(tess.svars.colors, tr.identityLightByte, SHADER_MAX_VERTEXES * sizeof(color4ub_t));\n\n\t\tint numVertexes = tess.numVertexes;\n\t\ti = 0;\n\t\twhile (i < numVertexes) {\n\t\t\tint count = numVertexes - i;\n\t\t\tif (count >= SHADER_MAX_VERTEXES/2 - 1)\n\t\t\t\tcount = SHADER_MAX_VERTEXES/2 - 1;\n\n\t\t\tfor (int k = 0; k < count; k++) {\n\t\t\t\tVectorCopy(xyz[i + k], tess.xyz[2*k]);\n\t\t\t\tVectorMA(xyz[i + k], 2, input->normal[i + k], tess.xyz[2*k + 1]);\n\t\t\t}\n\t\t\ttess.numVertexes = 2 * count;\n\t\t\ttess.numIndexes = 0;\n\n\t\t\tif (vk.active) {\n\t\t\t\tvk_bind_geometry();\n\t\t\t\tvk_shade_geometry(vk.normals_debug_pipeline, false, Vk_Depth_Range::force_zero, false);\n\t\t\t}\n\t\t\tif (dx.active) {\n\t\t\t\tdx_bind_geometry();\n\t\t\t\tdx_shade_geometry(dx.normals_debug_pipeline, false, Vk_Depth_Range::force_zero, false, true);\n\t\t\t}\n\n\t\t\ti += count;\n\t\t}\n\t}\n}\n\n/*\n==============\nRB_BeginSurface\n\nWe must set some things up before beginning any tesselation,\nbecause a surface may be forced to perform a RB_End due\nto overflow.\n==============\n*/\nvoid RB_BeginSurface( shader_t *shader, int fogNum ) {\n\n\tshader_t *state = (shader->remappedShader) ? shader->remappedShader : shader;\n\n\ttess.numIndexes = 0;\n\ttess.numVertexes = 0;\n\ttess.shader = state;\n\ttess.fogNum = fogNum;\n\ttess.dlightBits = 0;\t\t// will be OR'd in by surface functions\n\ttess.xstages = state->stages;\n\ttess.numPasses = state->numUnfoggedPasses;\n\n\ttess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset;\n\tif (tess.shader->clampTime && tess.shaderTime >= tess.shader->clampTime) {\n\t\ttess.shaderTime = tess.shader->clampTime;\n\t}\n\n\n}\n\n/*\n===================\nDrawMultitextured\n\noutput = t0 * t1 or t0 + t1\n\nt0 = most upstream according to spec\nt1 = most downstream according to spec\n===================\n*/\nstatic void DrawMultitextured( shaderCommands_t *input, int stage ) {\n\tshaderStage_t\t*pStage;\n\n\tpStage = tess.xstages[stage];\n\n\tGL_State( pStage->stateBits );\n\n\t// this is an ugly hack to work around a GeForce driver\n\t// bug with multitexture and clip planes\n\tif ( backEnd.viewParms.isPortal ) {\n\t\tqglPolygonMode( GL_FRONT_AND_BACK, GL_FILL );\n\t}\n\n\t//\n\t// base\n\t//\n\tGL_SelectTexture( 0 );\n\tqglTexCoordPointer( 2, GL_FLOAT, 0, input->svars.texcoords[0] );\n\tR_BindAnimatedImage( &pStage->bundle[0] );\n\n\t//\n\t// lightmap/secondary pass\n\t//\n\tGL_SelectTexture( 1 );\n\tqglEnable( GL_TEXTURE_2D );\n\tqglEnableClientState( GL_TEXTURE_COORD_ARRAY );\n\n\tif ( r_lightmap->integer ) {\n\t\tGL_TexEnv( GL_REPLACE );\n\t} else {\n\t\tGL_TexEnv( tess.shader->multitextureEnv );\n\t}\n\n\tqglTexCoordPointer( 2, GL_FLOAT, 0, input->svars.texcoords[1] );\n\n\tR_BindAnimatedImage( &pStage->bundle[1] );\n\n\tR_DrawElements( input->numIndexes, input->indexes );\n\n\t//\n\t// disable texturing on TEXTURE1, then select TEXTURE0\n\t//\n\t//qglDisableClientState( GL_TEXTURE_COORD_ARRAY );\n\tqglDisable( GL_TEXTURE_2D );\n\n\tGL_SelectTexture( 0 );\n}\n\n\n\n/*\n===================\nProjectDlightTexture\n\nPerform dynamic lighting with another rendering pass\n===================\n*/\nstatic void ProjectDlightTexture( void ) {\n\tint\t\ti, l;\n\tvec3_t\torigin;\n\tfloat\t*texCoords;\n\tbyte\t*colors;\n\tbyte\tclipBits[SHADER_MAX_VERTEXES];\n\tunsigned\thitIndexes[SHADER_MAX_INDEXES];\n\tint\t\tnumIndexes;\n\tfloat\tscale;\n\tfloat\tradius;\n\tvec3_t\tfloatColor;\n\tfloat\tmodulate;\n\n\tif ( !backEnd.refdef.num_dlights ) {\n\t\treturn;\n\t}\n\n\tfor ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) {\n\t\tdlight_t\t*dl;\n\n\t\tif ( !( tess.dlightBits & ( 1 << l ) ) ) {\n\t\t\tcontinue;\t// this surface definately doesn't have any of this light\n\t\t}\n\t\ttexCoords = tess.svars.texcoords[0][0];\n\t\tcolors = tess.svars.colors[0];\n\n\t\tdl = &backEnd.refdef.dlights[l];\n\t\tVectorCopy( dl->transformed, origin );\n        radius = dl->radius;\n\t\tscale = 1.0f / radius;\n\n\t\tfloatColor[0] = dl->color[0] * 255.0f;\n\t\tfloatColor[1] = dl->color[1] * 255.0f;\n\t\tfloatColor[2] = dl->color[2] * 255.0f;\n\n\t\tfor ( i = 0 ; i < tess.numVertexes ; i++, texCoords += 2, colors += 4 ) {\n\t\t\tvec3_t\tdist;\n\t\t\tint\t\tclip;\n\n\t\t\tbackEnd.pc.c_dlightVertexes++;\n\n\t\t\tVectorSubtract( origin, tess.xyz[i], dist );\n\t\t\ttexCoords[0] = 0.5f + dist[0] * scale;\n\t\t\ttexCoords[1] = 0.5f + dist[1] * scale;\n\n\t\t\tclip = 0;\n\t\t\tif ( texCoords[0] < 0.0f ) {\n\t\t\t\tclip |= 1;\n\t\t\t} else if ( texCoords[0] > 1.0f ) {\n\t\t\t\tclip |= 2;\n\t\t\t}\n\t\t\tif ( texCoords[1] < 0.0f ) {\n\t\t\t\tclip |= 4;\n\t\t\t} else if ( texCoords[1] > 1.0f ) {\n\t\t\t\tclip |= 8;\n\t\t\t}\n\t\t\t// modulate the strength based on the height and color\n\t\t\tif ( dist[2] > radius ) {\n\t\t\t\tclip |= 16;\n\t\t\t\tmodulate = 0.0f;\n\t\t\t} else if ( dist[2] < -radius ) {\n\t\t\t\tclip |= 32;\n\t\t\t\tmodulate = 0.0f;\n\t\t\t} else {\n\t\t\t\tdist[2] = Q_fabs(dist[2]);\n\t\t\t\tif ( dist[2] < radius * 0.5f ) {\n\t\t\t\t\tmodulate = 1.0f;\n\t\t\t\t} else {\n\t\t\t\t\tmodulate = 2.0f * (radius - dist[2]) * scale;\n\t\t\t\t}\n\t\t\t}\n\t\t\tclipBits[i] = clip;\n\n\t\t\tcolors[0] = myftol(floatColor[0] * modulate);\n\t\t\tcolors[1] = myftol(floatColor[1] * modulate);\n\t\t\tcolors[2] = myftol(floatColor[2] * modulate);\n\t\t\tcolors[3] = 255;\n\t\t}\n\n\t\t// build a list of triangles that need light\n\t\tnumIndexes = 0;\n\t\tfor ( i = 0 ; i < tess.numIndexes ; i += 3 ) {\n\t\t\tint\t\ta, b, c;\n\n\t\t\ta = tess.indexes[i];\n\t\t\tb = tess.indexes[i+1];\n\t\t\tc = tess.indexes[i+2];\n\t\t\tif ( clipBits[a] & clipBits[b] & clipBits[c] ) {\n\t\t\t\tcontinue;\t// not lighted\n\t\t\t}\n\t\t\thitIndexes[numIndexes] = a;\n\t\t\thitIndexes[numIndexes+1] = b;\n\t\t\thitIndexes[numIndexes+2] = c;\n\t\t\tnumIndexes += 3;\n\t\t}\n\n\t\tif ( !numIndexes ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tqglEnableClientState( GL_TEXTURE_COORD_ARRAY );\n\t\tqglTexCoordPointer( 2, GL_FLOAT, 0, tess.svars.texcoords[0] );\n\n\t\tqglEnableClientState( GL_COLOR_ARRAY );\n\t\tqglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.svars.colors );\n\n\t\tGL_Bind( tr.dlightImage );\n\t\t// include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light\n\t\t// where they aren't rendered\n\t\tif ( dl->additive ) {\n\t\t\tGL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL );\n\t\t}\n\t\telse {\n\t\t\tGL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL );\n\t\t}\n\t\tR_DrawElements( numIndexes, hitIndexes );\n\t\tbackEnd.pc.c_totalIndexes += numIndexes;\n\t\tbackEnd.pc.c_dlightIndexes += numIndexes;\n\n\t\t// VULKAN\n\t\tif (vk.active) {\n\t\t\tVkPipeline pipeline = vk.dlight_pipelines[dl->additive > 0 ? 1 : 0][tess.shader->cullType][tess.shader->polygonOffset];\n\t\t\tvk_shade_geometry(pipeline, false, Vk_Depth_Range::normal);\n\t\t}\n\n\t\t// DX12\n\t\tif (dx.active) {\n\t\t\tauto pipeline = dx.dlight_pipelines[dl->additive > 0 ? 1 : 0][tess.shader->cullType][tess.shader->polygonOffset];\n\t\t\tdx_shade_geometry(pipeline, false, Vk_Depth_Range::normal, true, false);\n\t\t}\n\t}\n}\n\n\n/*\n===================\nRB_FogPass\n\nBlends a fog texture on top of everything else\n===================\n*/\nstatic void RB_FogPass( void ) {\n\tfog_t\t\t*fog;\n\tint\t\t\ti;\n\n\tqglEnableClientState( GL_COLOR_ARRAY );\n\tqglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.svars.colors );\n\n\tqglEnableClientState( GL_TEXTURE_COORD_ARRAY);\n\tqglTexCoordPointer( 2, GL_FLOAT, 0, tess.svars.texcoords[0] );\n\n\tfog = tr.world->fogs + tess.fogNum;\n\n\tfor ( i = 0; i < tess.numVertexes; i++ ) {\n\t\t* ( int * )&tess.svars.colors[i] = fog->colorInt;\n\t}\n\n\tRB_CalcFogTexCoords( ( float * ) tess.svars.texcoords[0] );\n\n\tGL_Bind( tr.fogImage );\n\n\tif ( tess.shader->fogPass == FP_EQUAL ) {\n\t\tGL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_EQUAL );\n\t} else {\n\t\tGL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA );\n\t}\n\n\tR_DrawElements( tess.numIndexes, tess.indexes );\n\n\t// VULKAN\n\tif (vk.active) {\n\t\tassert(tess.shader->fogPass > 0);\n\t\tVkPipeline pipeline = vk.fog_pipelines[tess.shader->fogPass - 1][tess.shader->cullType][tess.shader->polygonOffset];\n\t\tvk_shade_geometry(pipeline, false, Vk_Depth_Range::normal);\n\t}\n\n\t// DX12\n\tif (dx.active) {\n\t\tassert(tess.shader->fogPass > 0);\n\t\tauto pipeline = dx.fog_pipelines[tess.shader->fogPass - 1][tess.shader->cullType][tess.shader->polygonOffset];\n\t\tdx_shade_geometry(pipeline, false, Vk_Depth_Range::normal, true, false);\n\t}\n}\n\n/*\n===============\nComputeColors\n===============\n*/\nstatic void ComputeColors( shaderStage_t *pStage )\n{\n\tint\t\ti;\n\n\t//\n\t// rgbGen\n\t//\n\tswitch ( pStage->rgbGen )\n\t{\n\t\tcase CGEN_IDENTITY:\n\t\t\tCom_Memset( tess.svars.colors, 0xff, tess.numVertexes * 4 );\n\t\t\tbreak;\n\t\tdefault:\n\t\tcase CGEN_IDENTITY_LIGHTING:\n\t\t\tCom_Memset( tess.svars.colors, tr.identityLightByte, tess.numVertexes * 4 );\n\t\t\tbreak;\n\t\tcase CGEN_LIGHTING_DIFFUSE:\n\t\t\tRB_CalcDiffuseColor( ( unsigned char * ) tess.svars.colors );\n\t\t\tbreak;\n\t\tcase CGEN_EXACT_VERTEX:\n\t\t\tCom_Memcpy( tess.svars.colors, tess.vertexColors, tess.numVertexes * sizeof( tess.vertexColors[0] ) );\n\t\t\tbreak;\n\t\tcase CGEN_CONST:\n\t\t\tfor ( i = 0; i < tess.numVertexes; i++ ) {\n\t\t\t\t*(int *)tess.svars.colors[i] = *(int *)pStage->constantColor;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase CGEN_VERTEX:\n\t\t\tif ( tr.identityLight == 1 )\n\t\t\t{\n\t\t\t\tCom_Memcpy( tess.svars.colors, tess.vertexColors, tess.numVertexes * sizeof( tess.vertexColors[0] ) );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tfor ( i = 0; i < tess.numVertexes; i++ )\n\t\t\t\t{\n\t\t\t\t\ttess.svars.colors[i][0] = tess.vertexColors[i][0] * tr.identityLight;\n\t\t\t\t\ttess.svars.colors[i][1] = tess.vertexColors[i][1] * tr.identityLight;\n\t\t\t\t\ttess.svars.colors[i][2] = tess.vertexColors[i][2] * tr.identityLight;\n\t\t\t\t\ttess.svars.colors[i][3] = tess.vertexColors[i][3];\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\tcase CGEN_ONE_MINUS_VERTEX:\n\t\t\tif ( tr.identityLight == 1 )\n\t\t\t{\n\t\t\t\tfor ( i = 0; i < tess.numVertexes; i++ )\n\t\t\t\t{\n\t\t\t\t\ttess.svars.colors[i][0] = 255 - tess.vertexColors[i][0];\n\t\t\t\t\ttess.svars.colors[i][1] = 255 - tess.vertexColors[i][1];\n\t\t\t\t\ttess.svars.colors[i][2] = 255 - tess.vertexColors[i][2];\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tfor ( i = 0; i < tess.numVertexes; i++ )\n\t\t\t\t{\n\t\t\t\t\ttess.svars.colors[i][0] = ( 255 - tess.vertexColors[i][0] ) * tr.identityLight;\n\t\t\t\t\ttess.svars.colors[i][1] = ( 255 - tess.vertexColors[i][1] ) * tr.identityLight;\n\t\t\t\t\ttess.svars.colors[i][2] = ( 255 - tess.vertexColors[i][2] ) * tr.identityLight;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\tcase CGEN_FOG:\n\t\t\t{\n\t\t\t\tfog_t\t\t*fog;\n\n\t\t\t\tfog = tr.world->fogs + tess.fogNum;\n\n\t\t\t\tfor ( i = 0; i < tess.numVertexes; i++ ) {\n\t\t\t\t\t* ( int * )&tess.svars.colors[i] = fog->colorInt;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\tcase CGEN_WAVEFORM:\n\t\t\tRB_CalcWaveColor( &pStage->rgbWave, ( unsigned char * ) tess.svars.colors );\n\t\t\tbreak;\n\t\tcase CGEN_ENTITY:\n\t\t\tRB_CalcColorFromEntity( ( unsigned char * ) tess.svars.colors );\n\t\t\tbreak;\n\t\tcase CGEN_ONE_MINUS_ENTITY:\n\t\t\tRB_CalcColorFromOneMinusEntity( ( unsigned char * ) tess.svars.colors );\n\t\t\tbreak;\n\t}\n\n\t//\n\t// alphaGen\n\t//\n\tswitch ( pStage->alphaGen )\n\t{\n\tcase AGEN_SKIP:\n\t\tbreak;\n\tcase AGEN_IDENTITY:\n\t\tif ( pStage->rgbGen != CGEN_IDENTITY ) {\n\t\t\tif ( ( pStage->rgbGen == CGEN_VERTEX && tr.identityLight != 1 ) ||\n\t\t\t\t pStage->rgbGen != CGEN_VERTEX ) {\n\t\t\t\tfor ( i = 0; i < tess.numVertexes; i++ ) {\n\t\t\t\t\ttess.svars.colors[i][3] = 0xff;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tbreak;\n\tcase AGEN_CONST:\n\t\tif ( pStage->rgbGen != CGEN_CONST ) {\n\t\t\tfor ( i = 0; i < tess.numVertexes; i++ ) {\n\t\t\t\ttess.svars.colors[i][3] = pStage->constantColor[3];\n\t\t\t}\n\t\t}\n\t\tbreak;\n\tcase AGEN_WAVEFORM:\n\t\tRB_CalcWaveAlpha( &pStage->alphaWave, ( unsigned char * ) tess.svars.colors );\n\t\tbreak;\n\tcase AGEN_LIGHTING_SPECULAR:\n\t\tRB_CalcSpecularAlpha( ( unsigned char * ) tess.svars.colors );\n\t\tbreak;\n\tcase AGEN_ENTITY:\n\t\tRB_CalcAlphaFromEntity( ( unsigned char * ) tess.svars.colors );\n\t\tbreak;\n\tcase AGEN_ONE_MINUS_ENTITY:\n\t\tRB_CalcAlphaFromOneMinusEntity( ( unsigned char * ) tess.svars.colors );\n\t\tbreak;\n    case AGEN_VERTEX:\n\t\tif ( pStage->rgbGen != CGEN_VERTEX ) {\n\t\t\tfor ( i = 0; i < tess.numVertexes; i++ ) {\n\t\t\t\ttess.svars.colors[i][3] = tess.vertexColors[i][3];\n\t\t\t}\n\t\t}\n        break;\n    case AGEN_ONE_MINUS_VERTEX:\n        for ( i = 0; i < tess.numVertexes; i++ )\n        {\n\t\t\ttess.svars.colors[i][3] = 255 - tess.vertexColors[i][3];\n        }\n        break;\n\tcase AGEN_PORTAL:\n\t\t{\n\t\t\tunsigned char alpha;\n\n\t\t\tfor ( i = 0; i < tess.numVertexes; i++ )\n\t\t\t{\n\t\t\t\tfloat len;\n\t\t\t\tvec3_t v;\n\n\t\t\t\tVectorSubtract( tess.xyz[i], backEnd.viewParms.or.origin, v );\n\t\t\t\tlen = VectorLength( v );\n\n\t\t\t\tlen /= tess.shader->portalRange;\n\n\t\t\t\tif ( len < 0 )\n\t\t\t\t{\n\t\t\t\t\talpha = 0;\n\t\t\t\t}\n\t\t\t\telse if ( len > 1 )\n\t\t\t\t{\n\t\t\t\t\talpha = 0xff;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\talpha = len * 0xff;\n\t\t\t\t}\n\n\t\t\t\ttess.svars.colors[i][3] = alpha;\n\t\t\t}\n\t\t}\n\t\tbreak;\n\t}\n\n\t//\n\t// fog adjustment for colors to fade out as fog increases\n\t//\n\tif ( tess.fogNum )\n\t{\n\t\tswitch ( pStage->adjustColorsForFog )\n\t\t{\n\t\tcase ACFF_MODULATE_RGB:\n\t\t\tRB_CalcModulateColorsByFog( ( unsigned char * ) tess.svars.colors );\n\t\t\tbreak;\n\t\tcase ACFF_MODULATE_ALPHA:\n\t\t\tRB_CalcModulateAlphasByFog( ( unsigned char * ) tess.svars.colors );\n\t\t\tbreak;\n\t\tcase ACFF_MODULATE_RGBA:\n\t\t\tRB_CalcModulateRGBAsByFog( ( unsigned char * ) tess.svars.colors );\n\t\t\tbreak;\n\t\tcase ACFF_NONE:\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\n/*\n===============\nComputeTexCoords\n===============\n*/\nstatic void ComputeTexCoords( shaderStage_t *pStage ) {\n\tint\t\ti;\n\tint\t\tb;\n\n\tfor ( b = 0; b < NUM_TEXTURE_BUNDLES; b++ ) {\n\t\tint tm;\n\n\t\t//\n\t\t// generate the texture coordinates\n\t\t//\n\t\tswitch ( pStage->bundle[b].tcGen )\n\t\t{\n\t\tcase TCGEN_IDENTITY:\n\t\t\tCom_Memset( tess.svars.texcoords[b], 0, sizeof( float ) * 2 * tess.numVertexes );\n\t\t\tbreak;\n\t\tcase TCGEN_TEXTURE:\n\t\t\tfor ( i = 0 ; i < tess.numVertexes ; i++ ) {\n\t\t\t\ttess.svars.texcoords[b][i][0] = tess.texCoords[i][0][0];\n\t\t\t\ttess.svars.texcoords[b][i][1] = tess.texCoords[i][0][1];\n\t\t\t}\n\t\t\tbreak;\n\t\tcase TCGEN_LIGHTMAP:\n\t\t\tfor ( i = 0 ; i < tess.numVertexes ; i++ ) {\n\t\t\t\ttess.svars.texcoords[b][i][0] = tess.texCoords[i][1][0];\n\t\t\t\ttess.svars.texcoords[b][i][1] = tess.texCoords[i][1][1];\n\t\t\t}\n\t\t\tbreak;\n\t\tcase TCGEN_VECTOR:\n\t\t\tfor ( i = 0 ; i < tess.numVertexes ; i++ ) {\n\t\t\t\ttess.svars.texcoords[b][i][0] = DotProduct( tess.xyz[i], pStage->bundle[b].tcGenVectors[0] );\n\t\t\t\ttess.svars.texcoords[b][i][1] = DotProduct( tess.xyz[i], pStage->bundle[b].tcGenVectors[1] );\n\t\t\t}\n\t\t\tbreak;\n\t\tcase TCGEN_FOG:\n\t\t\tRB_CalcFogTexCoords( ( float * ) tess.svars.texcoords[b] );\n\t\t\tbreak;\n\t\tcase TCGEN_ENVIRONMENT_MAPPED:\n\t\t\tRB_CalcEnvironmentTexCoords( ( float * ) tess.svars.texcoords[b] );\n\t\t\tbreak;\n\t\tcase TCGEN_BAD:\n\t\t\treturn;\n\t\t}\n\n\t\t//\n\t\t// alter texture coordinates\n\t\t//\n\t\tfor ( tm = 0; tm < pStage->bundle[b].numTexMods ; tm++ ) {\n\t\t\tswitch ( pStage->bundle[b].texMods[tm].type )\n\t\t\t{\n\t\t\tcase TMOD_NONE:\n\t\t\t\ttm = TR_MAX_TEXMODS;\t\t// break out of for loop\n\t\t\t\tbreak;\n\n\t\t\tcase TMOD_TURBULENT:\n\t\t\t\tRB_CalcTurbulentTexCoords( &pStage->bundle[b].texMods[tm].wave, \n\t\t\t\t\t\t                 ( float * ) tess.svars.texcoords[b] );\n\t\t\t\tbreak;\n\n\t\t\tcase TMOD_ENTITY_TRANSLATE:\n\t\t\t\tRB_CalcScrollTexCoords( backEnd.currentEntity->e.shaderTexCoord,\n\t\t\t\t\t\t\t\t\t ( float * ) tess.svars.texcoords[b] );\n\t\t\t\tbreak;\n\n\t\t\tcase TMOD_SCROLL:\n\t\t\t\tRB_CalcScrollTexCoords( pStage->bundle[b].texMods[tm].scroll,\n\t\t\t\t\t\t\t\t\t\t ( float * ) tess.svars.texcoords[b] );\n\t\t\t\tbreak;\n\n\t\t\tcase TMOD_SCALE:\n\t\t\t\tRB_CalcScaleTexCoords( pStage->bundle[b].texMods[tm].scale,\n\t\t\t\t\t\t\t\t\t ( float * ) tess.svars.texcoords[b] );\n\t\t\t\tbreak;\n\t\t\t\n\t\t\tcase TMOD_STRETCH:\n\t\t\t\tRB_CalcStretchTexCoords( &pStage->bundle[b].texMods[tm].wave, \n\t\t\t\t\t\t               ( float * ) tess.svars.texcoords[b] );\n\t\t\t\tbreak;\n\n\t\t\tcase TMOD_TRANSFORM:\n\t\t\t\tRB_CalcTransformTexCoords( &pStage->bundle[b].texMods[tm],\n\t\t\t\t\t\t                 ( float * ) tess.svars.texcoords[b] );\n\t\t\t\tbreak;\n\n\t\t\tcase TMOD_ROTATE:\n\t\t\t\tRB_CalcRotateTexCoords( pStage->bundle[b].texMods[tm].rotateSpeed,\n\t\t\t\t\t\t\t\t\t\t( float * ) tess.svars.texcoords[b] );\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tri.Error( ERR_DROP, \"ERROR: unknown texmod '%d' in shader '%s'\\n\", pStage->bundle[b].texMods[tm].type, tess.shader->name );\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n}\n\n/*\n** RB_IterateStagesGeneric\n*/\nstatic void RB_IterateStagesGeneric( shaderCommands_t *input )\n{\n\t// VULKAN\n\tif (vk.active)\n\t\tvk_bind_geometry();\n\n\t// DX12\n\tif (dx.active)\n\t\tdx_bind_geometry();\n\n\tfor ( int stage = 0; stage < MAX_SHADER_STAGES; stage++ )\n\t{\n\t\tshaderStage_t *pStage = tess.xstages[stage];\n\n\t\tif ( !pStage )\n\t\t{\n\t\t\tbreak;\n\t\t}\n\n\t\tComputeColors( pStage );\n\t\tComputeTexCoords( pStage );\n\n\t\tif ( !setArraysOnce )\n\t\t{\n\t\t\tqglEnableClientState( GL_COLOR_ARRAY );\n\t\t\tqglColorPointer( 4, GL_UNSIGNED_BYTE, 0, input->svars.colors );\n\t\t}\n\n\t\t//\n\t\t// do multitexture\n\t\t//\n        bool multitexture = (pStage->bundle[1].image[0] != nullptr);\n\n\t\tif ( multitexture )\n\t\t{\n\t\t\tDrawMultitextured( input, stage );\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ( !setArraysOnce )\n\t\t\t{\n\t\t\t\tqglTexCoordPointer( 2, GL_FLOAT, 0, input->svars.texcoords[0] );\n\t\t\t}\n\n\t\t\t//\n\t\t\t// set state\n\t\t\t//\n\t\t\tR_BindAnimatedImage( &pStage->bundle[0] );\n\t\t\tGL_State( pStage->stateBits );\n\n\t\t\t//\n\t\t\t// draw\n\t\t\t//\n\t\t\tR_DrawElements( input->numIndexes, input->indexes );\n\t\t}\n\n\t\t// VULKAN\n\t\t// DX12\n\t\tif (vk.active || dx.active) {\n\t\t\tVkPipeline vk_pipeline = pStage->vk_pipeline;\n\t\t\tID3D12PipelineState* dx_pipeline = pStage->dx_pipeline;\n\n\t\t\tif (backEnd.viewParms.isMirror) {\n\t\t\t\tvk_pipeline = pStage->vk_mirror_pipeline;\n\t\t\t\tdx_pipeline = pStage->dx_mirror_pipeline;\n\t\t\t}\n\t\t\telse if (backEnd.viewParms.isPortal) {\n\t\t\t\tvk_pipeline = pStage->vk_portal_pipeline;\n\t\t\t\tdx_pipeline = pStage->dx_portal_pipeline;\n\t\t\t}\n\n\t\t\tVk_Depth_Range depth_range = Vk_Depth_Range::normal;\n\t\t\tif (input->shader->isSky) {\n\t\t\t\tdepth_range = Vk_Depth_Range::force_one;\n\t\t\t\tif (r_showsky->integer)\n\t\t\t\t\tdepth_range = Vk_Depth_Range::force_zero;\n\t\t\t} else if (backEnd.currentEntity->e.renderfx & RF_DEPTHHACK) {\n\t\t\t\tdepth_range = Vk_Depth_Range::weapon;\n\t\t\t}\n\n\t\t\tif (r_lightmap->integer && multitexture)\n\t\t\t\tGL_Bind(tr.whiteImage); // replace diffuse texture with a white one thus effectively render only lightmap\n\n\t\t\tif (vk.active)\n\t\t\t\tvk_shade_geometry(vk_pipeline, multitexture, depth_range);\n\t\t\tif (dx.active)\n\t\t\t\tdx_shade_geometry(dx_pipeline, multitexture, depth_range, true, false);\n        }\n\n\t\t// allow skipping out to show just lightmaps during development\n\t\tif ( r_lightmap->integer && ( pStage->bundle[0].isLightmap || pStage->bundle[1].isLightmap ) )\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\n\n/*\n** RB_StageIteratorGeneric\n*/\nvoid RB_StageIteratorGeneric( void )\n{\n\tshaderCommands_t *input;\n\n\tinput = &tess;\n\n\tRB_DeformTessGeometry();\n\n\t//\n\t// log this call\n\t//\n\tif ( r_logFile->integer ) \n\t{\n\t\t// don't just call LogComment, or we will get\n\t\t// a call to va() every frame!\n\t\tGLimp_LogComment( va(\"--- RB_StageIteratorGeneric( %s ) ---\\n\", tess.shader->name) );\n\t}\n\n\t//\n\t// set face culling appropriately\n\t//\n\tGL_Cull( input->shader->cullType );\n\n\t// set polygon offset if necessary\n\tif ( input->shader->polygonOffset )\n\t{\n\t\tqglEnable( GL_POLYGON_OFFSET_FILL );\n\t\tqglPolygonOffset( r_offsetFactor->value, r_offsetUnits->value );\n\t}\n\n\t//\n\t// if there is only a single pass then we can enable color\n\t// and texture arrays before we compile, otherwise we need\n\t// to avoid compiling those arrays since they will change\n\t// during multipass rendering\n\t//\n\tif ( tess.numPasses > 1 || input->shader->multitextureEnv )\n\t{\n\t\tsetArraysOnce = qfalse;\n\t\tqglDisableClientState (GL_COLOR_ARRAY);\n\t\tqglDisableClientState (GL_TEXTURE_COORD_ARRAY);\n\t}\n\telse\n\t{\n\t\tsetArraysOnce = qtrue;\n\n\t\tqglEnableClientState( GL_COLOR_ARRAY);\n\t\tqglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.svars.colors );\n\n\t\tqglEnableClientState( GL_TEXTURE_COORD_ARRAY);\n\t\tqglTexCoordPointer( 2, GL_FLOAT, 0, tess.svars.texcoords[0] );\n\t}\n\n\t//\n\t// lock XYZ\n\t//\n\tqglVertexPointer (3, GL_FLOAT, 16, input->xyz);\t// padded for SIMD\n\tif (qglLockArraysEXT)\n\t{\n\t\tqglLockArraysEXT(0, input->numVertexes);\n\t\tGLimp_LogComment( \"glLockArraysEXT\\n\" );\n\t}\n\n\t//\n\t// enable color and texcoord arrays after the lock if necessary\n\t//\n\tif ( !setArraysOnce )\n\t{\n\t\tqglEnableClientState( GL_TEXTURE_COORD_ARRAY );\n\t\tqglEnableClientState( GL_COLOR_ARRAY );\n\t}\n\n\t//\n\t// call shader function\n\t//\n\tRB_IterateStagesGeneric( input );\n\n\t// \n\t// now do any dynamic lighting needed\n\t//\n\tif ( tess.dlightBits && tess.shader->sort <= SS_OPAQUE\n\t\t&& !(tess.shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY) ) ) {\n\t\tProjectDlightTexture();\n\t}\n\n\t//\n\t// now do fog\n\t//\n\tif ( tess.fogNum && tess.shader->fogPass ) {\n\t\tRB_FogPass();\n\t}\n\n\t// \n\t// unlock arrays\n\t//\n\tif (qglUnlockArraysEXT) \n\t{\n\t\tqglUnlockArraysEXT();\n\t\tGLimp_LogComment( \"glUnlockArraysEXT\\n\" );\n\t}\n\n\t//\n\t// reset polygon offset\n\t//\n\tif ( input->shader->polygonOffset )\n\t{\n\t\tqglDisable( GL_POLYGON_OFFSET_FILL );\n\t}\n}\n\n/*\n** RB_EndSurface\n*/\nvoid RB_EndSurface( void ) {\n\tshaderCommands_t *input;\n\n\tinput = &tess;\n\n\tif (input->numIndexes == 0) {\n\t\treturn;\n\t}\n\tif (tess.shader->isSky && r_fastsky->integer) {\n\t\treturn;\n\t}\n\n\tif (input->indexes[SHADER_MAX_INDEXES-1] != 0) {\n\t\tri.Error (ERR_DROP, \"RB_EndSurface() - SHADER_MAX_INDEXES hit\");\n\t}\t\n\tif (input->xyz[SHADER_MAX_VERTEXES-1][0] != 0) {\n\t\tri.Error (ERR_DROP, \"RB_EndSurface() - SHADER_MAX_VERTEXES hit\");\n\t}\n\n\tif ( tess.shader == tr.shadowShader ) {\n\t\tRB_ShadowTessEnd();\n\t\treturn;\n\t}\n\n\t// for debugging of sort order issues, stop rendering after a given sort value\n\tif ( r_debugSort->integer && r_debugSort->integer < tess.shader->sort ) {\n\t\treturn;\n\t}\n\n\t//\n\t// update performance counters\n\t//\n\tbackEnd.pc.c_shaders++;\n\tbackEnd.pc.c_vertexes += tess.numVertexes;\n\tbackEnd.pc.c_indexes += tess.numIndexes;\n\tbackEnd.pc.c_totalIndexes += tess.numIndexes * tess.numPasses;\n\n\t//\n\t// call off to shader specific tess end function\n\t//\n\tif (tess.shader->isSky)\n\t\tRB_StageIteratorSky();\n\telse\n\t\tRB_StageIteratorGeneric();\n\n\t//\n\t// draw debugging stuff\n\t//\n\tif ( r_showtris->integer ) {\n\t\tDrawTris (input);\n\t}\n\tif ( r_shownormals->integer ) {\n\t\tDrawNormals (input);\n\t}\n\t// clear shader so we can tell we don't have any unclosed surfaces\n\ttess.numIndexes = 0;\n    tess.numVertexes = 0;\n\n\tGLimp_LogComment( \"----------\\n\" );\n}\n\n"
  },
  {
    "path": "src/engine/renderer/tr_shade_calc.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n// tr_shade_calc.c\n\n#include \"tr_local.h\"\n\n\n#define\tWAVEVALUE( table, base, amplitude, phase, freq )  ((base) + table[ myftol( ( ( (phase) + tess.shaderTime * (freq) ) * FUNCTABLE_SIZE ) ) & FUNCTABLE_MASK ] * (amplitude))\n\nstatic float *TableForFunc( genFunc_t func ) \n{\n\tswitch ( func )\n\t{\n\tcase GF_SIN:\n\t\treturn tr.sinTable;\n\tcase GF_TRIANGLE:\n\t\treturn tr.triangleTable;\n\tcase GF_SQUARE:\n\t\treturn tr.squareTable;\n\tcase GF_SAWTOOTH:\n\t\treturn tr.sawToothTable;\n\tcase GF_INVERSE_SAWTOOTH:\n\t\treturn tr.inverseSawToothTable;\n\tcase GF_NONE:\n\tdefault:\n\t\tbreak;\n\t}\n\n\tri.Error( ERR_DROP, \"TableForFunc called with invalid function '%d' in shader '%s'\\n\", func, tess.shader->name );\n\treturn NULL;\n}\n\n/*\n** EvalWaveForm\n**\n** Evaluates a given waveForm_t, referencing backEnd.refdef.time directly\n*/\nstatic float EvalWaveForm( const waveForm_t *wf ) \n{\n\tfloat\t*table;\n\n\ttable = TableForFunc( wf->func );\n\n\treturn WAVEVALUE( table, wf->base, wf->amplitude, wf->phase, wf->frequency );\n}\n\nstatic float EvalWaveFormClamped( const waveForm_t *wf )\n{\n\tfloat glow  = EvalWaveForm( wf );\n\n\tif ( glow < 0 )\n\t{\n\t\treturn 0;\n\t}\n\n\tif ( glow > 1 )\n\t{\n\t\treturn 1;\n\t}\n\n\treturn glow;\n}\n\n/*\n** RB_CalcStretchTexCoords\n*/\nvoid RB_CalcStretchTexCoords( const waveForm_t *wf, float *st )\n{\n\tfloat p;\n\ttexModInfo_t tmi;\n\n\tp = 1.0f / EvalWaveForm( wf );\n\n\ttmi.matrix[0][0] = p;\n\ttmi.matrix[1][0] = 0;\n\ttmi.translate[0] = 0.5f - 0.5f * p;\n\n\ttmi.matrix[0][1] = 0;\n\ttmi.matrix[1][1] = p;\n\ttmi.translate[1] = 0.5f - 0.5f * p;\n\n\tRB_CalcTransformTexCoords( &tmi, st );\n}\n\n/*\n====================================================================\n\nDEFORMATIONS\n\n====================================================================\n*/\n\n/*\n========================\nRB_CalcDeformVertexes\n\n========================\n*/\nvoid RB_CalcDeformVertexes( deformStage_t *ds )\n{\n\tint i;\n\tvec3_t\toffset;\n\tfloat\tscale;\n\tfloat\t*xyz = ( float * ) tess.xyz;\n\tfloat\t*normal = ( float * ) tess.normal;\n\tfloat\t*table;\n\n\tif ( ds->deformationWave.frequency == 0 )\n\t{\n\t\tscale = EvalWaveForm( &ds->deformationWave );\n\n\t\tfor ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 )\n\t\t{\n\t\t\tVectorScale( normal, scale, offset );\n\t\t\t\n\t\t\txyz[0] += offset[0];\n\t\t\txyz[1] += offset[1];\n\t\t\txyz[2] += offset[2];\n\t\t}\n\t}\n\telse\n\t{\n\t\ttable = TableForFunc( ds->deformationWave.func );\n\n\t\tfor ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 )\n\t\t{\n\t\t\tfloat off = ( xyz[0] + xyz[1] + xyz[2] ) * ds->deformationSpread;\n\n\t\t\tscale = WAVEVALUE( table, ds->deformationWave.base, \n\t\t\t\tds->deformationWave.amplitude,\n\t\t\t\tds->deformationWave.phase + off,\n\t\t\t\tds->deformationWave.frequency );\n\n\t\t\tVectorScale( normal, scale, offset );\n\t\t\t\n\t\t\txyz[0] += offset[0];\n\t\t\txyz[1] += offset[1];\n\t\t\txyz[2] += offset[2];\n\t\t}\n\t}\n}\n\n/*\n=========================\nRB_CalcDeformNormals\n\nWiggle the normals for wavy environment mapping\n=========================\n*/\nvoid RB_CalcDeformNormals( deformStage_t *ds ) {\n\tint i;\n\tfloat\tscale;\n\tfloat\t*xyz = ( float * ) tess.xyz;\n\tfloat\t*normal = ( float * ) tess.normal;\n\n\tfor ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 ) {\n\t\tscale = 0.98f;\n\t\tscale = R_NoiseGet4f( xyz[0] * scale, xyz[1] * scale, xyz[2] * scale,\n\t\t\ttess.shaderTime * ds->deformationWave.frequency );\n\t\tnormal[ 0 ] += ds->deformationWave.amplitude * scale;\n\n\t\tscale = 0.98f;\n\t\tscale = R_NoiseGet4f( 100 + xyz[0] * scale, xyz[1] * scale, xyz[2] * scale,\n\t\t\ttess.shaderTime * ds->deformationWave.frequency );\n\t\tnormal[ 1 ] += ds->deformationWave.amplitude * scale;\n\n\t\tscale = 0.98f;\n\t\tscale = R_NoiseGet4f( 200 + xyz[0] * scale, xyz[1] * scale, xyz[2] * scale,\n\t\t\ttess.shaderTime * ds->deformationWave.frequency );\n\t\tnormal[ 2 ] += ds->deformationWave.amplitude * scale;\n\n\t\tVectorNormalizeFast( normal );\n\t}\n}\n\n/*\n========================\nRB_CalcBulgeVertexes\n\n========================\n*/\nvoid RB_CalcBulgeVertexes( deformStage_t *ds ) {\n\tint i;\n\tconst float *st = ( const float * ) tess.texCoords[0];\n\tfloat\t\t*xyz = ( float * ) tess.xyz;\n\tfloat\t\t*normal = ( float * ) tess.normal;\n\tfloat\t\tnow;\n\n\tnow = backEnd.refdef.time * ds->bulgeSpeed * 0.001f;\n\n\tfor ( i = 0; i < tess.numVertexes; i++, xyz += 4, st += 4, normal += 4 ) {\n\t\tint\t\toff;\n\t\tfloat scale;\n\n\t\toff = (float)( FUNCTABLE_SIZE / (M_PI*2) ) * ( st[0] * ds->bulgeWidth + now );\n\n\t\tscale = tr.sinTable[ off & FUNCTABLE_MASK ] * ds->bulgeHeight;\n\t\t\t\n\t\txyz[0] += normal[0] * scale;\n\t\txyz[1] += normal[1] * scale;\n\t\txyz[2] += normal[2] * scale;\n\t}\n}\n\n\n/*\n======================\nRB_CalcMoveVertexes\n\nA deformation that can move an entire surface along a wave path\n======================\n*/\nvoid RB_CalcMoveVertexes( deformStage_t *ds ) {\n\tint\t\t\ti;\n\tfloat\t\t*xyz;\n\tfloat\t\t*table;\n\tfloat\t\tscale;\n\tvec3_t\t\toffset;\n\n\ttable = TableForFunc( ds->deformationWave.func );\n\n\tscale = WAVEVALUE( table, ds->deformationWave.base, \n\t\tds->deformationWave.amplitude,\n\t\tds->deformationWave.phase,\n\t\tds->deformationWave.frequency );\n\n\tVectorScale( ds->moveVector, scale, offset );\n\n\txyz = ( float * ) tess.xyz;\n\tfor ( i = 0; i < tess.numVertexes; i++, xyz += 4 ) {\n\t\tVectorAdd( xyz, offset, xyz );\n\t}\n}\n\n\n/*\n=============\nDeformText\n\nChange a polygon into a bunch of text polygons\n=============\n*/\nvoid DeformText( const char *text ) {\n\tint\t\ti;\n\tvec3_t\torigin, width, height;\n\tint\t\tlen;\n\tint\t\tch;\n\tbyte\tcolor[4];\n\tfloat\tbottom, top;\n\tvec3_t\tmid;\n\n\theight[0] = 0;\n\theight[1] = 0;\n\theight[2] = -1;\n\tCrossProduct( tess.normal[0], height, width );\n\n\t// find the midpoint of the box\n\tVectorClear( mid );\n\tbottom = 999999;\n\ttop = -999999;\n\tfor ( i = 0 ; i < 4 ; i++ ) {\n\t\tVectorAdd( tess.xyz[i], mid, mid );\n\t\tif ( tess.xyz[i][2] < bottom ) {\n\t\t\tbottom = tess.xyz[i][2];\n\t\t}\n\t\tif ( tess.xyz[i][2] > top ) {\n\t\t\ttop = tess.xyz[i][2];\n\t\t}\n\t}\n\tVectorScale( mid, 0.25f, origin );\n\n\t// determine the individual character size\n\theight[0] = 0;\n\theight[1] = 0;\n\theight[2] = ( top - bottom ) * 0.5f;\n\n\tVectorScale( width, height[2] * -0.75f, width );\n\n\t// determine the starting position\n\tlen = (int)strlen( text );\n\tVectorMA( origin, (len-1), width, origin );\n\n\t// clear the shader indexes\n\ttess.numIndexes = 0;\n\ttess.numVertexes = 0;\n\n\tcolor[0] = color[1] = color[2] = color[3] = 255;\n\n\t// draw each character\n\tfor ( i = 0 ; i < len ; i++ ) {\n\t\tch = text[i];\n\t\tch &= 255;\n\n\t\tif ( ch != ' ' ) {\n\t\t\tint\t\trow, col;\n\t\t\tfloat\tfrow, fcol, size;\n\n\t\t\trow = ch>>4;\n\t\t\tcol = ch&15;\n\n\t\t\tfrow = row*0.0625f;\n\t\t\tfcol = col*0.0625f;\n\t\t\tsize = 0.0625f;\n\n\t\t\tRB_AddQuadStampExt( origin, width, height, color, fcol, frow, fcol + size, frow + size );\n\t\t}\n\t\tVectorMA( origin, -2, width, origin );\n\t}\n}\n\n/*\n==================\nGlobalVectorToLocal\n==================\n*/\nstatic void GlobalVectorToLocal( const vec3_t in, vec3_t out ) {\n\tout[0] = DotProduct( in, backEnd.or.axis[0] );\n\tout[1] = DotProduct( in, backEnd.or.axis[1] );\n\tout[2] = DotProduct( in, backEnd.or.axis[2] );\n}\n\n/*\n=====================\nAutospriteDeform\n\nAssuming all the triangles for this shader are independant\nquads, rebuild them as forward facing sprites\n=====================\n*/\nstatic void AutospriteDeform( void ) {\n\tint\t\ti;\n\tint\t\toldVerts;\n\tfloat\t*xyz;\n\tvec3_t\tmid, delta;\n\tfloat\tradius;\n\tvec3_t\tleft, up;\n\tvec3_t\tleftDir, upDir;\n\n\tif ( tess.numVertexes & 3 ) {\n\t\tri.Printf( PRINT_WARNING, \"Autosprite shader %s had odd vertex count\", tess.shader->name );\n\t}\n\tif ( tess.numIndexes != ( tess.numVertexes >> 2 ) * 6 ) {\n\t\tri.Printf( PRINT_WARNING, \"Autosprite shader %s had odd index count\", tess.shader->name );\n\t}\n\n\toldVerts = tess.numVertexes;\n\ttess.numVertexes = 0;\n\ttess.numIndexes = 0;\n\n\tif ( backEnd.currentEntity != &tr.worldEntity ) {\n\t\tGlobalVectorToLocal( backEnd.viewParms.or.axis[1], leftDir );\n\t\tGlobalVectorToLocal( backEnd.viewParms.or.axis[2], upDir );\n\t} else {\n\t\tVectorCopy( backEnd.viewParms.or.axis[1], leftDir );\n\t\tVectorCopy( backEnd.viewParms.or.axis[2], upDir );\n\t}\n\n\tfor ( i = 0 ; i < oldVerts ; i+=4 ) {\n\t\t// find the midpoint\n\t\txyz = tess.xyz[i];\n\n\t\tmid[0] = 0.25f * (xyz[0] + xyz[4] + xyz[8] + xyz[12]);\n\t\tmid[1] = 0.25f * (xyz[1] + xyz[5] + xyz[9] + xyz[13]);\n\t\tmid[2] = 0.25f * (xyz[2] + xyz[6] + xyz[10] + xyz[14]);\n\n\t\tVectorSubtract( xyz, mid, delta );\n\t\tradius = VectorLength( delta ) * 0.707f;\t\t// / sqrt(2)\n\n\t\tVectorScale( leftDir, radius, left );\n\t\tVectorScale( upDir, radius, up );\n\n\t\tif ( backEnd.viewParms.isMirror ) {\n\t\t\tVectorSubtract( vec3_origin, left, left );\n\t\t}\n\n\t  // compensate for scale in the axes if necessary\n  \tif ( backEnd.currentEntity->e.nonNormalizedAxes ) {\n      float axisLength;\n\t\t  axisLength = VectorLength( backEnd.currentEntity->e.axis[0] );\n  \t\tif ( !axisLength ) {\n\t  \t\taxisLength = 0;\n  \t\t} else {\n\t  \t\taxisLength = 1.0f / axisLength;\n  \t\t}\n      VectorScale(left, axisLength, left);\n      VectorScale(up, axisLength, up);\n    }\n\n\t\tRB_AddQuadStamp( mid, left, up, tess.vertexColors[i] );\n\t}\n}\n\n\n/*\n=====================\nAutosprite2Deform\n\nAutosprite2 will pivot a rectangular quad along the center of its long axis\n=====================\n*/\nint edgeVerts[6][2] = {\n\t{ 0, 1 },\n\t{ 0, 2 },\n\t{ 0, 3 },\n\t{ 1, 2 },\n\t{ 1, 3 },\n\t{ 2, 3 }\n};\n\nstatic void Autosprite2Deform( void ) {\n\tint\t\ti, j, k;\n\tint\t\tindexes;\n\tfloat\t*xyz;\n\tvec3_t\tforward;\n\n\tif ( tess.numVertexes & 3 ) {\n\t\tri.Printf( PRINT_WARNING, \"Autosprite2 shader %s had odd vertex count\", tess.shader->name );\n\t}\n\tif ( tess.numIndexes != ( tess.numVertexes >> 2 ) * 6 ) {\n\t\tri.Printf( PRINT_WARNING, \"Autosprite2 shader %s had odd index count\", tess.shader->name );\n\t}\n\n\tif ( backEnd.currentEntity != &tr.worldEntity ) {\n\t\tGlobalVectorToLocal( backEnd.viewParms.or.axis[0], forward );\n\t} else {\n\t\tVectorCopy( backEnd.viewParms.or.axis[0], forward );\n\t}\n\n\t// this is a lot of work for two triangles...\n\t// we could precalculate a lot of it is an issue, but it would mess up\n\t// the shader abstraction\n\tfor ( i = 0, indexes = 0 ; i < tess.numVertexes ; i+=4, indexes+=6 ) {\n\t\tfloat\tlengths[2];\n\t\tint\t\tnums[2];\n\t\tvec3_t\tmid[2];\n\t\tvec3_t\tmajor, minor;\n\t\tfloat\t*v1, *v2;\n\n\t\t// find the midpoint\n\t\txyz = tess.xyz[i];\n\n\t\t// identify the two shortest edges\n\t\tnums[0] = nums[1] = 0;\n\t\tlengths[0] = lengths[1] = 999999;\n\n\t\tfor ( j = 0 ; j < 6 ; j++ ) {\n\t\t\tfloat\tl;\n\t\t\tvec3_t\ttemp;\n\n\t\t\tv1 = xyz + 4 * edgeVerts[j][0];\n\t\t\tv2 = xyz + 4 * edgeVerts[j][1];\n\n\t\t\tVectorSubtract( v1, v2, temp );\n\t\t\t\n\t\t\tl = DotProduct( temp, temp );\n\t\t\tif ( l < lengths[0] ) {\n\t\t\t\tnums[1] = nums[0];\n\t\t\t\tlengths[1] = lengths[0];\n\t\t\t\tnums[0] = j;\n\t\t\t\tlengths[0] = l;\n\t\t\t} else if ( l < lengths[1] ) {\n\t\t\t\tnums[1] = j;\n\t\t\t\tlengths[1] = l;\n\t\t\t}\n\t\t}\n\n\t\tfor ( j = 0 ; j < 2 ; j++ ) {\n\t\t\tv1 = xyz + 4 * edgeVerts[nums[j]][0];\n\t\t\tv2 = xyz + 4 * edgeVerts[nums[j]][1];\n\n\t\t\tmid[j][0] = 0.5f * (v1[0] + v2[0]);\n\t\t\tmid[j][1] = 0.5f * (v1[1] + v2[1]);\n\t\t\tmid[j][2] = 0.5f * (v1[2] + v2[2]);\n\t\t}\n\n\t\t// find the vector of the major axis\n\t\tVectorSubtract( mid[1], mid[0], major );\n\n\t\t// cross this with the view direction to get minor axis\n\t\tCrossProduct( major, forward, minor );\n\t\tVectorNormalize( minor );\n\t\t\n\t\t// re-project the points\n\t\tfor ( j = 0 ; j < 2 ; j++ ) {\n\t\t\tfloat\tl;\n\n\t\t\tv1 = xyz + 4 * edgeVerts[nums[j]][0];\n\t\t\tv2 = xyz + 4 * edgeVerts[nums[j]][1];\n\n\t\t\tl = 0.5 * sqrt( lengths[j] );\n\t\t\t\n\t\t\t// we need to see which direction this edge\n\t\t\t// is used to determine direction of projection\n\t\t\tfor ( k = 0 ; k < 5 ; k++ ) {\n\t\t\t\tif ( (int)tess.indexes[ indexes + k ] == i + edgeVerts[nums[j]][0]\n\t\t\t\t\t&& (int)tess.indexes[ indexes + k + 1 ] == i + edgeVerts[nums[j]][1] ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( k == 5 ) {\n\t\t\t\tVectorMA( mid[j], l, minor, v1 );\n\t\t\t\tVectorMA( mid[j], -l, minor, v2 );\n\t\t\t} else {\n\t\t\t\tVectorMA( mid[j], -l, minor, v1 );\n\t\t\t\tVectorMA( mid[j], l, minor, v2 );\n\t\t\t}\n\t\t}\n\t}\n}\n\n\n/*\n=====================\nRB_DeformTessGeometry\n\n=====================\n*/\nvoid RB_DeformTessGeometry( void ) {\n\tint\t\ti;\n\tdeformStage_t\t*ds;\n\n\tfor ( i = 0 ; i < tess.shader->numDeforms ; i++ ) {\n\t\tds = &tess.shader->deforms[ i ];\n\n\t\tswitch ( ds->deformation ) {\n        case DEFORM_NONE:\n            break;\n\t\tcase DEFORM_NORMALS:\n\t\t\tRB_CalcDeformNormals( ds );\n\t\t\tbreak;\n\t\tcase DEFORM_WAVE:\n\t\t\tRB_CalcDeformVertexes( ds );\n\t\t\tbreak;\n\t\tcase DEFORM_BULGE:\n\t\t\tRB_CalcBulgeVertexes( ds );\n\t\t\tbreak;\n\t\tcase DEFORM_MOVE:\n\t\t\tRB_CalcMoveVertexes( ds );\n\t\t\tbreak;\n\t\tcase DEFORM_PROJECTION_SHADOW:\n\t\t\tRB_ProjectionShadowDeform();\n\t\t\tbreak;\n\t\tcase DEFORM_AUTOSPRITE:\n\t\t\tAutospriteDeform();\n\t\t\tbreak;\n\t\tcase DEFORM_AUTOSPRITE2:\n\t\t\tAutosprite2Deform();\n\t\t\tbreak;\n\t\tcase DEFORM_TEXT0:\n\t\tcase DEFORM_TEXT1:\n\t\tcase DEFORM_TEXT2:\n\t\tcase DEFORM_TEXT3:\n\t\tcase DEFORM_TEXT4:\n\t\tcase DEFORM_TEXT5:\n\t\tcase DEFORM_TEXT6:\n\t\tcase DEFORM_TEXT7:\n\t\t\tDeformText( backEnd.refdef.text[ds->deformation - DEFORM_TEXT0] );\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\n/*\n====================================================================\n\nCOLORS\n\n====================================================================\n*/\n\n\n/*\n** RB_CalcColorFromEntity\n*/\nvoid RB_CalcColorFromEntity( unsigned char *dstColors )\n{\n\tint\ti;\n\tint *pColors = ( int * ) dstColors;\n\tint c;\n\n\tif ( !backEnd.currentEntity )\n\t\treturn;\n\n\tc = * ( int * ) backEnd.currentEntity->e.shaderRGBA;\n\n\tfor ( i = 0; i < tess.numVertexes; i++, pColors++ )\n\t{\n\t\t*pColors = c;\n\t}\n}\n\n/*\n** RB_CalcColorFromOneMinusEntity\n*/\nvoid RB_CalcColorFromOneMinusEntity( unsigned char *dstColors )\n{\n\tint\ti;\n\tint *pColors = ( int * ) dstColors;\n\tunsigned char invModulate[3];\n\tint c;\n\n\tif ( !backEnd.currentEntity )\n\t\treturn;\n\n\tinvModulate[0] = 255 - backEnd.currentEntity->e.shaderRGBA[0];\n\tinvModulate[1] = 255 - backEnd.currentEntity->e.shaderRGBA[1];\n\tinvModulate[2] = 255 - backEnd.currentEntity->e.shaderRGBA[2];\n\tinvModulate[3] = 255 - backEnd.currentEntity->e.shaderRGBA[3];\t// this trashes alpha, but the AGEN block fixes it\n\n\tc = * ( int * ) invModulate;\n\n\tfor ( i = 0; i < tess.numVertexes; i++, pColors++ )\n\t{\n\t\t*pColors = * ( int * ) invModulate;\n\t}\n}\n\n/*\n** RB_CalcAlphaFromEntity\n*/\nvoid RB_CalcAlphaFromEntity( unsigned char *dstColors )\n{\n\tint\ti;\n\n\tif ( !backEnd.currentEntity )\n\t\treturn;\n\n\tdstColors += 3;\n\n\tfor ( i = 0; i < tess.numVertexes; i++, dstColors += 4 )\n\t{\n\t\t*dstColors = backEnd.currentEntity->e.shaderRGBA[3];\n\t}\n}\n\n/*\n** RB_CalcAlphaFromOneMinusEntity\n*/\nvoid RB_CalcAlphaFromOneMinusEntity( unsigned char *dstColors )\n{\n\tint\ti;\n\n\tif ( !backEnd.currentEntity )\n\t\treturn;\n\n\tdstColors += 3;\n\n\tfor ( i = 0; i < tess.numVertexes; i++, dstColors += 4 )\n\t{\n\t\t*dstColors = 0xff - backEnd.currentEntity->e.shaderRGBA[3];\n\t}\n}\n\n/*\n** RB_CalcWaveColor\n*/\nvoid RB_CalcWaveColor( const waveForm_t *wf, unsigned char *dstColors )\n{\n\tint i;\n\tint v;\n\tfloat glow;\n\tint *colors = ( int * ) dstColors;\n\tbyte\tcolor[4];\n\n\n  if ( wf->func == GF_NOISE ) {\n\t\tglow = wf->base + R_NoiseGet4f( 0, 0, 0, ( tess.shaderTime + wf->phase ) * wf->frequency ) * wf->amplitude;\n\t} else {\n\t\tglow = EvalWaveForm( wf ) * tr.identityLight;\n\t}\n\t\n\tif ( glow < 0 ) {\n\t\tglow = 0;\n\t}\n\telse if ( glow > 1 ) {\n\t\tglow = 1;\n\t}\n\n\tv = myftol( 255 * glow );\n\tcolor[0] = color[1] = color[2] = v;\n\tcolor[3] = 255;\n\tv = *(int *)color;\n\t\n\tfor ( i = 0; i < tess.numVertexes; i++, colors++ ) {\n\t\t*colors = v;\n\t}\n}\n\n/*\n** RB_CalcWaveAlpha\n*/\nvoid RB_CalcWaveAlpha( const waveForm_t *wf, unsigned char *dstColors )\n{\n\tint i;\n\tint v;\n\tfloat glow;\n\n\tglow = EvalWaveFormClamped( wf );\n\n\tv = 255 * glow;\n\n\tfor ( i = 0; i < tess.numVertexes; i++, dstColors += 4 )\n\t{\n\t\tdstColors[3] = v;\n\t}\n}\n\n/*\n** RB_CalcModulateColorsByFog\n*/\nvoid RB_CalcModulateColorsByFog( unsigned char *colors ) {\n\tint\t\ti;\n\tfloat\ttexCoords[SHADER_MAX_VERTEXES][2];\n\n\t// calculate texcoords so we can derive density\n\t// this is not wasted, because it would only have\n\t// been previously called if the surface was opaque\n\tRB_CalcFogTexCoords( texCoords[0] );\n\n\tfor ( i = 0; i < tess.numVertexes; i++, colors += 4 ) {\n\t\tfloat f = 1.0 - R_FogFactor( texCoords[i][0], texCoords[i][1] );\n\t\tcolors[0] *= f;\n\t\tcolors[1] *= f;\n\t\tcolors[2] *= f;\n\t}\n}\n\n/*\n** RB_CalcModulateAlphasByFog\n*/\nvoid RB_CalcModulateAlphasByFog( unsigned char *colors ) {\n\tint\t\ti;\n\tfloat\ttexCoords[SHADER_MAX_VERTEXES][2];\n\n\t// calculate texcoords so we can derive density\n\t// this is not wasted, because it would only have\n\t// been previously called if the surface was opaque\n\tRB_CalcFogTexCoords( texCoords[0] );\n\n\tfor ( i = 0; i < tess.numVertexes; i++, colors += 4 ) {\n\t\tfloat f = 1.0 - R_FogFactor( texCoords[i][0], texCoords[i][1] );\n\t\tcolors[3] *= f;\n\t}\n}\n\n/*\n** RB_CalcModulateRGBAsByFog\n*/\nvoid RB_CalcModulateRGBAsByFog( unsigned char *colors ) {\n\tint\t\ti;\n\tfloat\ttexCoords[SHADER_MAX_VERTEXES][2];\n\n\t// calculate texcoords so we can derive density\n\t// this is not wasted, because it would only have\n\t// been previously called if the surface was opaque\n\tRB_CalcFogTexCoords( texCoords[0] );\n\n\tfor ( i = 0; i < tess.numVertexes; i++, colors += 4 ) {\n\t\tfloat f = 1.0 - R_FogFactor( texCoords[i][0], texCoords[i][1] );\n\t\tcolors[0] *= f;\n\t\tcolors[1] *= f;\n\t\tcolors[2] *= f;\n\t\tcolors[3] *= f;\n\t}\n}\n\n\n/*\n====================================================================\n\nTEX COORDS\n\n====================================================================\n*/\n\n/*\n========================\nRB_CalcFogTexCoords\n\nTo do the clipped fog plane really correctly, we should use\nprojected textures, but I don't trust the drivers and it\ndoesn't fit our shader data.\n========================\n*/\nvoid RB_CalcFogTexCoords( float *st ) {\n\tint\t\t\ti;\n\tfloat\t\t*v;\n\tfloat\t\ts, t;\n\tfloat\t\teyeT;\n\tqboolean\teyeOutside;\n\tfog_t\t\t*fog;\n\tvec3_t\t\tlocal;\n\tvec4_t\t\tfogDistanceVector, fogDepthVector;\n\n\tfog = tr.world->fogs + tess.fogNum;\n\n\t// all fogging distance is based on world Z units\n\tVectorSubtract( backEnd.or.origin, backEnd.viewParms.or.origin, local );\n\tfogDistanceVector[0] = -backEnd.or.modelMatrix[2];\n\tfogDistanceVector[1] = -backEnd.or.modelMatrix[6];\n\tfogDistanceVector[2] = -backEnd.or.modelMatrix[10];\n\tfogDistanceVector[3] = DotProduct( local, backEnd.viewParms.or.axis[0] );\n\n\t// scale the fog vectors based on the fog's thickness\n\tfogDistanceVector[0] *= fog->tcScale;\n\tfogDistanceVector[1] *= fog->tcScale;\n\tfogDistanceVector[2] *= fog->tcScale;\n\tfogDistanceVector[3] *= fog->tcScale;\n\n\t// rotate the gradient vector for this orientation\n\tif ( fog->hasSurface ) {\n\t\tfogDepthVector[0] = fog->surface[0] * backEnd.or.axis[0][0] + \n\t\t\tfog->surface[1] * backEnd.or.axis[0][1] + fog->surface[2] * backEnd.or.axis[0][2];\n\t\tfogDepthVector[1] = fog->surface[0] * backEnd.or.axis[1][0] + \n\t\t\tfog->surface[1] * backEnd.or.axis[1][1] + fog->surface[2] * backEnd.or.axis[1][2];\n\t\tfogDepthVector[2] = fog->surface[0] * backEnd.or.axis[2][0] + \n\t\t\tfog->surface[1] * backEnd.or.axis[2][1] + fog->surface[2] * backEnd.or.axis[2][2];\n\t\tfogDepthVector[3] = -fog->surface[3] + DotProduct( backEnd.or.origin, fog->surface );\n\n\t\teyeT = DotProduct( backEnd.or.viewOrigin, fogDepthVector ) + fogDepthVector[3];\n\t} else {\n\t\teyeT = 1;\t// non-surface fog always has eye inside\n\t}\n\n\t// see if the viewpoint is outside\n\t// this is needed for clipping distance even for constant fog\n\n\tif ( eyeT < 0 ) {\n\t\teyeOutside = qtrue;\n\t} else {\n\t\teyeOutside = qfalse;\n\t}\n\n\tfogDistanceVector[3] += 1.0/512;\n\n\t// calculate density for each point\n\tfor (i = 0, v = tess.xyz[0] ; i < tess.numVertexes ; i++, v += 4) {\n\t\t// calculate the length in fog\n\t\ts = DotProduct( v, fogDistanceVector ) + fogDistanceVector[3];\n\t\tt = DotProduct( v, fogDepthVector ) + fogDepthVector[3];\n\n\t\t// partially clipped fogs use the T axis\t\t\n\t\tif ( eyeOutside ) {\n\t\t\tif ( t < 1.0 ) {\n\t\t\t\tt = 1.0/32;\t// point is outside, so no fogging\n\t\t\t} else {\n\t\t\t\tt = 1.0/32 + 30.0/32 * t / ( t - eyeT );\t// cut the distance at the fog plane\n\t\t\t}\n\t\t} else {\n\t\t\tif ( t < 0 ) {\n\t\t\t\tt = 1.0/32;\t// point is outside, so no fogging\n\t\t\t} else {\n\t\t\t\tt = 31.0/32;\n\t\t\t}\n\t\t}\n\n\t\tst[0] = s;\n\t\tst[1] = t;\n\t\tst += 2;\n\t}\n}\n\n\n\n/*\n** RB_CalcEnvironmentTexCoords\n*/\nvoid RB_CalcEnvironmentTexCoords( float *st ) \n{\n\tint\t\t\ti;\n\tfloat\t\t*v, *normal;\n\tvec3_t\t\tviewer, reflected;\n\tfloat\t\td;\n\n\tv = tess.xyz[0];\n\tnormal = tess.normal[0];\n\n\tfor (i = 0 ; i < tess.numVertexes ; i++, v += 4, normal += 4, st += 2 ) \n\t{\n\t\tVectorSubtract (backEnd.or.viewOrigin, v, viewer);\n\t\tVectorNormalizeFast (viewer);\n\n\t\td = DotProduct (normal, viewer);\n\n\t\treflected[0] = normal[0]*2*d - viewer[0];\n\t\treflected[1] = normal[1]*2*d - viewer[1];\n\t\treflected[2] = normal[2]*2*d - viewer[2];\n\n\t\tst[0] = 0.5 + reflected[1] * 0.5;\n\t\tst[1] = 0.5 - reflected[2] * 0.5;\n\t}\n}\n\n/*\n** RB_CalcTurbulentTexCoords\n*/\nvoid RB_CalcTurbulentTexCoords( const waveForm_t *wf, float *st )\n{\n\tint i;\n\tfloat now;\n\n\tnow = ( wf->phase + tess.shaderTime * wf->frequency );\n\n\tfor ( i = 0; i < tess.numVertexes; i++, st += 2 )\n\t{\n\t\tfloat s = st[0];\n\t\tfloat t = st[1];\n\n\t\tst[0] = s + tr.sinTable[ ( ( int ) ( ( ( tess.xyz[i][0] + tess.xyz[i][2] )* 1.0/128 * 0.125 + now ) * FUNCTABLE_SIZE ) ) & ( FUNCTABLE_MASK ) ] * wf->amplitude;\n\t\tst[1] = t + tr.sinTable[ ( ( int ) ( ( tess.xyz[i][1] * 1.0/128 * 0.125 + now ) * FUNCTABLE_SIZE ) ) & ( FUNCTABLE_MASK ) ] * wf->amplitude;\n\t}\n}\n\n/*\n** RB_CalcScaleTexCoords\n*/\nvoid RB_CalcScaleTexCoords( const float scale[2], float *st )\n{\n\tint i;\n\n\tfor ( i = 0; i < tess.numVertexes; i++, st += 2 )\n\t{\n\t\tst[0] *= scale[0];\n\t\tst[1] *= scale[1];\n\t}\n}\n\n/*\n** RB_CalcScrollTexCoords\n*/\nvoid RB_CalcScrollTexCoords( const float scrollSpeed[2], float *st )\n{\n\tint i;\n\tfloat timeScale = tess.shaderTime;\n\tfloat adjustedScrollS, adjustedScrollT;\n\n\tadjustedScrollS = scrollSpeed[0] * timeScale;\n\tadjustedScrollT = scrollSpeed[1] * timeScale;\n\n\t// clamp so coordinates don't continuously get larger, causing problems\n\t// with hardware limits\n\tadjustedScrollS = adjustedScrollS - floor( adjustedScrollS );\n\tadjustedScrollT = adjustedScrollT - floor( adjustedScrollT );\n\n\tfor ( i = 0; i < tess.numVertexes; i++, st += 2 )\n\t{\n\t\tst[0] += adjustedScrollS;\n\t\tst[1] += adjustedScrollT;\n\t}\n}\n\n/*\n** RB_CalcTransformTexCoords\n*/\nvoid RB_CalcTransformTexCoords( const texModInfo_t *tmi, float *st  )\n{\n\tint i;\n\n\tfor ( i = 0; i < tess.numVertexes; i++, st += 2 )\n\t{\n\t\tfloat s = st[0];\n\t\tfloat t = st[1];\n\n\t\tst[0] = s * tmi->matrix[0][0] + t * tmi->matrix[1][0] + tmi->translate[0];\n\t\tst[1] = s * tmi->matrix[0][1] + t * tmi->matrix[1][1] + tmi->translate[1];\n\t}\n}\n\n/*\n** RB_CalcRotateTexCoords\n*/\nvoid RB_CalcRotateTexCoords( float degsPerSecond, float *st )\n{\n\tfloat timeScale = tess.shaderTime;\n\tfloat degs;\n\tint index;\n\tfloat sinValue, cosValue;\n\ttexModInfo_t tmi;\n\n\tdegs = -degsPerSecond * timeScale;\n\tindex = degs * ( FUNCTABLE_SIZE / 360.0f );\n\n\tsinValue = tr.sinTable[ index & FUNCTABLE_MASK ];\n\tcosValue = tr.sinTable[ ( index + FUNCTABLE_SIZE / 4 ) & FUNCTABLE_MASK ];\n\n\ttmi.matrix[0][0] = cosValue;\n\ttmi.matrix[1][0] = -sinValue;\n\ttmi.translate[0] = 0.5 - 0.5 * cosValue + 0.5 * sinValue;\n\n\ttmi.matrix[0][1] = sinValue;\n\ttmi.matrix[1][1] = cosValue;\n\ttmi.translate[1] = 0.5 - 0.5 * sinValue - 0.5 * cosValue;\n\n\tRB_CalcTransformTexCoords( &tmi, st );\n}\n\n\n\n\n\n\n#if id386 && !( (defined __linux__ || defined __FreeBSD__ ) && (defined __i386__ ) ) // rb010123\n\nlong myftol( float f ) {\n\tstatic int tmp;\n\t__asm fld f\n\t__asm fistp tmp\n\t__asm mov eax, tmp\n}\n\n#endif\n\n/*\n** RB_CalcSpecularAlpha\n**\n** Calculates specular coefficient and places it in the alpha channel\n*/\nvec3_t lightOrigin = { -960, 1980, 96 };\t\t// FIXME: track dynamically\n\nvoid RB_CalcSpecularAlpha( unsigned char *alphas ) {\n\tint\t\t\ti;\n\tfloat\t\t*v, *normal;\n\tvec3_t\t\tviewer,  reflected;\n\tfloat\t\tl, d;\n\tint\t\t\tb;\n\tvec3_t\t\tlightDir;\n\tint\t\t\tnumVertexes;\n\n\tv = tess.xyz[0];\n\tnormal = tess.normal[0];\n\n\talphas += 3;\n\n\tnumVertexes = tess.numVertexes;\n\tfor (i = 0 ; i < numVertexes ; i++, v += 4, normal += 4, alphas += 4) {\n\t\tfloat ilength;\n\n\t\tVectorSubtract( lightOrigin, v, lightDir );\n//\t\tilength = Q_rsqrt( DotProduct( lightDir, lightDir ) );\n\t\tVectorNormalizeFast( lightDir );\n\n\t\t// calculate the specular color\n\t\td = DotProduct (normal, lightDir);\n//\t\td *= ilength;\n\n\t\t// we don't optimize for the d < 0 case since this tends to\n\t\t// cause visual artifacts such as faceted \"snapping\"\n\t\treflected[0] = normal[0]*2*d - lightDir[0];\n\t\treflected[1] = normal[1]*2*d - lightDir[1];\n\t\treflected[2] = normal[2]*2*d - lightDir[2];\n\n\t\tVectorSubtract (backEnd.or.viewOrigin, v, viewer);\n\t\tilength = Q_rsqrt( DotProduct( viewer, viewer ) );\n\t\tl = DotProduct (reflected, viewer);\n\t\tl *= ilength;\n\n\t\tif (l < 0) {\n\t\t\tb = 0;\n\t\t} else {\n\t\t\tl = l*l;\n\t\t\tl = l*l;\n\t\t\tb = l * 255;\n\t\t\tif (b > 255) {\n\t\t\t\tb = 255;\n\t\t\t}\n\t\t}\n\n\t\t*alphas = b;\n\t}\n}\n\n/*\n** RB_CalcDiffuseColor\n**\n** The basic vertex lighting calc\n*/\nvoid RB_CalcDiffuseColor( unsigned char *colors )\n{\n\tint\t\t\t\ti, j;\n\tfloat\t\t\t*v, *normal;\n\tfloat\t\t\tincoming;\n\ttrRefEntity_t\t*ent;\n\tint\t\t\t\tambientLightInt;\n\tvec3_t\t\t\tambientLight;\n\tvec3_t\t\t\tlightDir;\n\tvec3_t\t\t\tdirectedLight;\n\tint\t\t\t\tnumVertexes;\n#if idppc_altivec\n\tvector unsigned char vSel = (vector unsigned char)(0x00, 0x00, 0x00, 0xff,\n\t\t\t\t\t\t\t   0x00, 0x00, 0x00, 0xff,\n\t\t\t\t\t\t\t   0x00, 0x00, 0x00, 0xff,\n\t\t\t\t\t\t\t   0x00, 0x00, 0x00, 0xff);\n\tvector float ambientLightVec;\n\tvector float directedLightVec;\n\tvector float lightDirVec;\n\tvector float normalVec0, normalVec1;\n\tvector float incomingVec0, incomingVec1, incomingVec2;\n\tvector float zero, jVec;\n\tvector signed int jVecInt;\n\tvector signed short jVecShort;\n\tvector unsigned char jVecChar, normalPerm;\n#endif\n\tent = backEnd.currentEntity;\n\tambientLightInt = ent->ambientLightInt;\n#if idppc_altivec\n\t// A lot of this could be simplified if we made sure\n\t// entities light info was 16-byte aligned.\n\tjVecChar = vec_lvsl(0, ent->ambientLight);\n\tambientLightVec = vec_ld(0, (vector float *)ent->ambientLight);\n\tjVec = vec_ld(11, (vector float *)ent->ambientLight);\n\tambientLightVec = vec_perm(ambientLightVec,jVec,jVecChar);\n\n\tjVecChar = vec_lvsl(0, ent->directedLight);\n\tdirectedLightVec = vec_ld(0,(vector float *)ent->directedLight);\n\tjVec = vec_ld(11,(vector float *)ent->directedLight);\n\tdirectedLightVec = vec_perm(directedLightVec,jVec,jVecChar);\t \n\n\tjVecChar = vec_lvsl(0, ent->lightDir);\n\tlightDirVec = vec_ld(0,(vector float *)ent->lightDir);\n\tjVec = vec_ld(11,(vector float *)ent->lightDir);\n\tlightDirVec = vec_perm(lightDirVec,jVec,jVecChar);\t \n\n\tzero = (vector float)vec_splat_s8(0);\n\tVectorCopy( ent->lightDir, lightDir );\n#else\n\tVectorCopy( ent->ambientLight, ambientLight );\n\tVectorCopy( ent->directedLight, directedLight );\n\tVectorCopy( ent->lightDir, lightDir );\n#endif\n\n\tv = tess.xyz[0];\n\tnormal = tess.normal[0];\n\n#if idppc_altivec\n\tnormalPerm = vec_lvsl(0,normal);\n#endif\n\tnumVertexes = tess.numVertexes;\n\tfor (i = 0 ; i < numVertexes ; i++, v += 4, normal += 4) {\n#if idppc_altivec\n\t\tnormalVec0 = vec_ld(0,(vector float *)normal);\n\t\tnormalVec1 = vec_ld(11,(vector float *)normal);\n\t\tnormalVec0 = vec_perm(normalVec0,normalVec1,normalPerm);\n\t\tincomingVec0 = vec_madd(normalVec0, lightDirVec, zero);\n\t\tincomingVec1 = vec_sld(incomingVec0,incomingVec0,4);\n\t\tincomingVec2 = vec_add(incomingVec0,incomingVec1);\n\t\tincomingVec1 = vec_sld(incomingVec1,incomingVec1,4);\n\t\tincomingVec2 = vec_add(incomingVec2,incomingVec1);\n\t\tincomingVec0 = vec_splat(incomingVec2,0);\n\t\tincomingVec0 = vec_max(incomingVec0,zero);\n\t\tnormalPerm = vec_lvsl(12,normal);\n\t\tjVec = vec_madd(incomingVec0, directedLightVec, ambientLightVec);\n\t\tjVecInt = vec_cts(jVec,0);\t// RGBx\n\t\tjVecShort = vec_pack(jVecInt,jVecInt);\t\t// RGBxRGBx\n\t\tjVecChar = vec_packsu(jVecShort,jVecShort);\t// RGBxRGBxRGBxRGBx\n\t\tjVecChar = vec_sel(jVecChar,vSel,vSel);\t\t// RGBARGBARGBARGBA replace alpha with 255\n\t\tvec_ste((vector unsigned int)jVecChar,0,(unsigned int *)&colors[i*4]);\t// store color\n#else\n\t\tincoming = DotProduct (normal, lightDir);\n\t\tif ( incoming <= 0 ) {\n\t\t\t*(int *)&colors[i*4] = ambientLightInt;\n\t\t\tcontinue;\n\t\t} \n\t\tj = myftol( ambientLight[0] + incoming * directedLight[0] );\n\t\tif ( j > 255 ) {\n\t\t\tj = 255;\n\t\t}\n\t\tcolors[i*4+0] = j;\n\n\t\tj = myftol( ambientLight[1] + incoming * directedLight[1] );\n\t\tif ( j > 255 ) {\n\t\t\tj = 255;\n\t\t}\n\t\tcolors[i*4+1] = j;\n\n\t\tj = myftol( ambientLight[2] + incoming * directedLight[2] );\n\t\tif ( j > 255 ) {\n\t\t\tj = 255;\n\t\t}\n\t\tcolors[i*4+2] = j;\n\n\t\tcolors[i*4+3] = 255;\n#endif\n\t}\n}\n\n"
  },
  {
    "path": "src/engine/renderer/tr_shader.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n#include \"tr_local.h\"\n\n// tr_shader.c -- this file deals with the parsing and definition of shaders\n\nstatic char *s_shaderText;\n\n// the shader is parsed into these global variables, then copied into\n// dynamically allocated memory if it is valid.\nstatic\tshaderStage_t\tstages[MAX_SHADER_STAGES];\t\t\nstatic\tshader_t\t\tshader;\nstatic\ttexModInfo_t\ttexMods[MAX_SHADER_STAGES][TR_MAX_TEXMODS];\n\n#define FILE_HASH_SIZE\t\t1024\nstatic\tshader_t*\t\thashTable[FILE_HASH_SIZE];\n\n#define MAX_SHADERTEXT_HASH\t\t2048\nstatic char **shaderTextHashTable[MAX_SHADERTEXT_HASH];\n\n/*\n================\nreturn a hash value for the filename\n================\n*/\nstatic long generateHashValue( const char *fname, const int size ) {\n\tint\t\ti;\n\tlong\thash;\n\tchar\tletter;\n\n\thash = 0;\n\ti = 0;\n\twhile (fname[i] != '\\0') {\n\t\tletter = tolower(fname[i]);\n\t\tif (letter =='.') break;\t\t\t\t// don't include extension\n\t\tif (letter =='\\\\') letter = '/';\t\t// damn path names\n\t\tif (letter == PATH_SEP) letter = '/';\t\t// damn path names\n\t\thash+=(long)(letter)*(i+119);\n\t\ti++;\n\t}\n\thash = (hash ^ (hash >> 10) ^ (hash >> 20));\n\thash &= (size-1);\n\treturn hash;\n}\n\nvoid R_RemapShader(const char *shaderName, const char *newShaderName, const char *timeOffset) {\n\tchar\t\tstrippedName[MAX_QPATH];\n\tint\t\t\thash;\n\tshader_t\t*sh, *sh2;\n\tqhandle_t\th;\n\n\tsh = R_FindShaderByName( shaderName );\n\tif (sh == NULL || sh == tr.defaultShader) {\n\t\th = RE_RegisterShaderLightMap(shaderName, 0);\n\t\tsh = R_GetShaderByHandle(h);\n\t}\n\tif (sh == NULL || sh == tr.defaultShader) {\n\t\tri.Printf( PRINT_WARNING, \"WARNING: R_RemapShader: shader %s not found\\n\", shaderName );\n\t\treturn;\n\t}\n\n\tsh2 = R_FindShaderByName( newShaderName );\n\tif (sh2 == NULL || sh2 == tr.defaultShader) {\n\t\th = RE_RegisterShaderLightMap(newShaderName, 0);\n\t\tsh2 = R_GetShaderByHandle(h);\n\t}\n\n\tif (sh2 == NULL || sh2 == tr.defaultShader) {\n\t\tri.Printf( PRINT_WARNING, \"WARNING: R_RemapShader: new shader %s not found\\n\", newShaderName );\n\t\treturn;\n\t}\n\n\t// remap all the shaders with the given name\n\t// even tho they might have different lightmaps\n\tCOM_StripExtension( shaderName, strippedName );\n\thash = generateHashValue(strippedName, FILE_HASH_SIZE);\n\tfor (sh = hashTable[hash]; sh; sh = sh->next) {\n\t\tif (Q_stricmp(sh->name, strippedName) == 0) {\n\t\t\tif (sh != sh2) {\n\t\t\t\tsh->remappedShader = sh2;\n\t\t\t} else {\n\t\t\t\tsh->remappedShader = NULL;\n\t\t\t}\n\t\t}\n\t}\n\tif (timeOffset) {\n\t\tsh2->timeOffset = atof(timeOffset);\n\t}\n}\n\n/*\n===============\nParseVector\n===============\n*/\nstatic qboolean ParseVector( char **text, int count, float *v ) {\n\tchar\t*token;\n\tint\t\ti;\n\n\t// FIXME: spaces are currently required after parens, should change parseext...\n\ttoken = COM_ParseExt( text, qfalse );\n\tif ( strcmp( token, \"(\" ) ) {\n\t\tri.Printf( PRINT_WARNING, \"WARNING: missing parenthesis in shader '%s'\\n\", shader.name );\n\t\treturn qfalse;\n\t}\n\n\tfor ( i = 0 ; i < count ; i++ ) {\n\t\ttoken = COM_ParseExt( text, qfalse );\n\t\tif ( !token[0] ) {\n\t\t\tri.Printf( PRINT_WARNING, \"WARNING: missing vector element in shader '%s'\\n\", shader.name );\n\t\t\treturn qfalse;\n\t\t}\n\t\tv[i] = atof( token );\n\t}\n\n\ttoken = COM_ParseExt( text, qfalse );\n\tif ( strcmp( token, \")\" ) ) {\n\t\tri.Printf( PRINT_WARNING, \"WARNING: missing parenthesis in shader '%s'\\n\", shader.name );\n\t\treturn qfalse;\n\t}\n\n\treturn qtrue;\n}\n\n\n/*\n===============\nNameToAFunc\n===============\n*/\nstatic unsigned NameToAFunc( const char *funcname )\n{\t\n\tif ( !Q_stricmp( funcname, \"GT0\" ) )\n\t{\n\t\treturn GLS_ATEST_GT_0;\n\t}\n\telse if ( !Q_stricmp( funcname, \"LT128\" ) )\n\t{\n\t\treturn GLS_ATEST_LT_80;\n\t}\n\telse if ( !Q_stricmp( funcname, \"GE128\" ) )\n\t{\n\t\treturn GLS_ATEST_GE_80;\n\t}\n\n\tri.Printf( PRINT_WARNING, \"WARNING: invalid alphaFunc name '%s' in shader '%s'\\n\", funcname, shader.name );\n\treturn 0;\n}\n\n\n/*\n===============\nNameToSrcBlendMode\n===============\n*/\nstatic int NameToSrcBlendMode( const char *name )\n{\n\tif ( !Q_stricmp( name, \"GL_ONE\" ) )\n\t{\n\t\treturn GLS_SRCBLEND_ONE;\n\t}\n\telse if ( !Q_stricmp( name, \"GL_ZERO\" ) )\n\t{\n\t\treturn GLS_SRCBLEND_ZERO;\n\t}\n\telse if ( !Q_stricmp( name, \"GL_DST_COLOR\" ) )\n\t{\n\t\treturn GLS_SRCBLEND_DST_COLOR;\n\t}\n\telse if ( !Q_stricmp( name, \"GL_ONE_MINUS_DST_COLOR\" ) )\n\t{\n\t\treturn GLS_SRCBLEND_ONE_MINUS_DST_COLOR;\n\t}\n\telse if ( !Q_stricmp( name, \"GL_SRC_ALPHA\" ) )\n\t{\n\t\treturn GLS_SRCBLEND_SRC_ALPHA;\n\t}\n\telse if ( !Q_stricmp( name, \"GL_ONE_MINUS_SRC_ALPHA\" ) )\n\t{\n\t\treturn GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA;\n\t}\n\telse if ( !Q_stricmp( name, \"GL_DST_ALPHA\" ) )\n\t{\n\t\treturn GLS_SRCBLEND_DST_ALPHA;\n\t}\n\telse if ( !Q_stricmp( name, \"GL_ONE_MINUS_DST_ALPHA\" ) )\n\t{\n\t\treturn GLS_SRCBLEND_ONE_MINUS_DST_ALPHA;\n\t}\n\telse if ( !Q_stricmp( name, \"GL_SRC_ALPHA_SATURATE\" ) )\n\t{\n\t\treturn GLS_SRCBLEND_ALPHA_SATURATE;\n\t}\n\n\tri.Printf( PRINT_WARNING, \"WARNING: unknown blend mode '%s' in shader '%s', substituting GL_ONE\\n\", name, shader.name );\n\treturn GLS_SRCBLEND_ONE;\n}\n\n/*\n===============\nNameToDstBlendMode\n===============\n*/\nstatic int NameToDstBlendMode( const char *name )\n{\n\tif ( !Q_stricmp( name, \"GL_ONE\" ) )\n\t{\n\t\treturn GLS_DSTBLEND_ONE;\n\t}\n\telse if ( !Q_stricmp( name, \"GL_ZERO\" ) )\n\t{\n\t\treturn GLS_DSTBLEND_ZERO;\n\t}\n\telse if ( !Q_stricmp( name, \"GL_SRC_ALPHA\" ) )\n\t{\n\t\treturn GLS_DSTBLEND_SRC_ALPHA;\n\t}\n\telse if ( !Q_stricmp( name, \"GL_ONE_MINUS_SRC_ALPHA\" ) )\n\t{\n\t\treturn GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA;\n\t}\n\telse if ( !Q_stricmp( name, \"GL_DST_ALPHA\" ) )\n\t{\n\t\treturn GLS_DSTBLEND_DST_ALPHA;\n\t}\n\telse if ( !Q_stricmp( name, \"GL_ONE_MINUS_DST_ALPHA\" ) )\n\t{\n\t\treturn GLS_DSTBLEND_ONE_MINUS_DST_ALPHA;\n\t}\n\telse if ( !Q_stricmp( name, \"GL_SRC_COLOR\" ) )\n\t{\n\t\treturn GLS_DSTBLEND_SRC_COLOR;\n\t}\n\telse if ( !Q_stricmp( name, \"GL_ONE_MINUS_SRC_COLOR\" ) )\n\t{\n\t\treturn GLS_DSTBLEND_ONE_MINUS_SRC_COLOR;\n\t}\n\n\tri.Printf( PRINT_WARNING, \"WARNING: unknown blend mode '%s' in shader '%s', substituting GL_ONE\\n\", name, shader.name );\n\treturn GLS_DSTBLEND_ONE;\n}\n\n/*\n===============\nNameToGenFunc\n===============\n*/\nstatic genFunc_t NameToGenFunc( const char *funcname )\n{\n\tif ( !Q_stricmp( funcname, \"sin\" ) )\n\t{\n\t\treturn GF_SIN;\n\t}\n\telse if ( !Q_stricmp( funcname, \"square\" ) )\n\t{\n\t\treturn GF_SQUARE;\n\t}\n\telse if ( !Q_stricmp( funcname, \"triangle\" ) )\n\t{\n\t\treturn GF_TRIANGLE;\n\t}\n\telse if ( !Q_stricmp( funcname, \"sawtooth\" ) )\n\t{\n\t\treturn GF_SAWTOOTH;\n\t}\n\telse if ( !Q_stricmp( funcname, \"inversesawtooth\" ) )\n\t{\n\t\treturn GF_INVERSE_SAWTOOTH;\n\t}\n\telse if ( !Q_stricmp( funcname, \"noise\" ) )\n\t{\n\t\treturn GF_NOISE;\n\t}\n\n\tri.Printf( PRINT_WARNING, \"WARNING: invalid genfunc name '%s' in shader '%s'\\n\", funcname, shader.name );\n\treturn GF_SIN;\n}\n\n\n/*\n===================\nParseWaveForm\n===================\n*/\nstatic void ParseWaveForm( char **text, waveForm_t *wave )\n{\n\tchar *token;\n\n\ttoken = COM_ParseExt( text, qfalse );\n\tif ( token[0] == 0 )\n\t{\n\t\tri.Printf( PRINT_WARNING, \"WARNING: missing waveform parm in shader '%s'\\n\", shader.name );\n\t\treturn;\n\t}\n\twave->func = NameToGenFunc( token );\n\n\t// BASE, AMP, PHASE, FREQ\n\ttoken = COM_ParseExt( text, qfalse );\n\tif ( token[0] == 0 )\n\t{\n\t\tri.Printf( PRINT_WARNING, \"WARNING: missing waveform parm in shader '%s'\\n\", shader.name );\n\t\treturn;\n\t}\n\twave->base = atof( token );\n\n\ttoken = COM_ParseExt( text, qfalse );\n\tif ( token[0] == 0 )\n\t{\n\t\tri.Printf( PRINT_WARNING, \"WARNING: missing waveform parm in shader '%s'\\n\", shader.name );\n\t\treturn;\n\t}\n\twave->amplitude = atof( token );\n\n\ttoken = COM_ParseExt( text, qfalse );\n\tif ( token[0] == 0 )\n\t{\n\t\tri.Printf( PRINT_WARNING, \"WARNING: missing waveform parm in shader '%s'\\n\", shader.name );\n\t\treturn;\n\t}\n\twave->phase = atof( token );\n\n\ttoken = COM_ParseExt( text, qfalse );\n\tif ( token[0] == 0 )\n\t{\n\t\tri.Printf( PRINT_WARNING, \"WARNING: missing waveform parm in shader '%s'\\n\", shader.name );\n\t\treturn;\n\t}\n\twave->frequency = atof( token );\n}\n\n\n/*\n===================\nParseTexMod\n===================\n*/\nstatic void ParseTexMod( char *_text, shaderStage_t *stage )\n{\n\tconst char *token;\n\tchar **text = &_text;\n\ttexModInfo_t *tmi;\n\n\tif ( stage->bundle[0].numTexMods == TR_MAX_TEXMODS ) {\n\t\tri.Error( ERR_DROP, \"ERROR: too many tcMod stages in shader '%s'\\n\", shader.name );\n\t\treturn;\n\t}\n\n\ttmi = &stage->bundle[0].texMods[stage->bundle[0].numTexMods];\n\tstage->bundle[0].numTexMods++;\n\n\ttoken = COM_ParseExt( text, qfalse );\n\n\t//\n\t// turb\n\t//\n\tif ( !Q_stricmp( token, \"turb\" ) )\n\t{\n\t\ttoken = COM_ParseExt( text, qfalse );\n\t\tif ( token[0] == 0 )\n\t\t{\n\t\t\tri.Printf( PRINT_WARNING, \"WARNING: missing tcMod turb parms in shader '%s'\\n\", shader.name );\n\t\t\treturn;\n\t\t}\n\t\ttmi->wave.base = atof( token );\n\t\ttoken = COM_ParseExt( text, qfalse );\n\t\tif ( token[0] == 0 )\n\t\t{\n\t\t\tri.Printf( PRINT_WARNING, \"WARNING: missing tcMod turb in shader '%s'\\n\", shader.name );\n\t\t\treturn;\n\t\t}\n\t\ttmi->wave.amplitude = atof( token );\n\t\ttoken = COM_ParseExt( text, qfalse );\n\t\tif ( token[0] == 0 )\n\t\t{\n\t\t\tri.Printf( PRINT_WARNING, \"WARNING: missing tcMod turb in shader '%s'\\n\", shader.name );\n\t\t\treturn;\n\t\t}\n\t\ttmi->wave.phase = atof( token );\n\t\ttoken = COM_ParseExt( text, qfalse );\n\t\tif ( token[0] == 0 )\n\t\t{\n\t\t\tri.Printf( PRINT_WARNING, \"WARNING: missing tcMod turb in shader '%s'\\n\", shader.name );\n\t\t\treturn;\n\t\t}\n\t\ttmi->wave.frequency = atof( token );\n\n\t\ttmi->type = TMOD_TURBULENT;\n\t}\n\t//\n\t// scale\n\t//\n\telse if ( !Q_stricmp( token, \"scale\" ) )\n\t{\n\t\ttoken = COM_ParseExt( text, qfalse );\n\t\tif ( token[0] == 0 )\n\t\t{\n\t\t\tri.Printf( PRINT_WARNING, \"WARNING: missing scale parms in shader '%s'\\n\", shader.name );\n\t\t\treturn;\n\t\t}\n\t\ttmi->scale[0] = atof( token );\n\n\t\ttoken = COM_ParseExt( text, qfalse );\n\t\tif ( token[0] == 0 )\n\t\t{\n\t\t\tri.Printf( PRINT_WARNING, \"WARNING: missing scale parms in shader '%s'\\n\", shader.name );\n\t\t\treturn;\n\t\t}\n\t\ttmi->scale[1] = atof( token );\n\t\ttmi->type = TMOD_SCALE;\n\t}\n\t//\n\t// scroll\n\t//\n\telse if ( !Q_stricmp( token, \"scroll\" ) )\n\t{\n\t\ttoken = COM_ParseExt( text, qfalse );\n\t\tif ( token[0] == 0 )\n\t\t{\n\t\t\tri.Printf( PRINT_WARNING, \"WARNING: missing scale scroll parms in shader '%s'\\n\", shader.name );\n\t\t\treturn;\n\t\t}\n\t\ttmi->scroll[0] = atof( token );\n\t\ttoken = COM_ParseExt( text, qfalse );\n\t\tif ( token[0] == 0 )\n\t\t{\n\t\t\tri.Printf( PRINT_WARNING, \"WARNING: missing scale scroll parms in shader '%s'\\n\", shader.name );\n\t\t\treturn;\n\t\t}\n\t\ttmi->scroll[1] = atof( token );\n\t\ttmi->type = TMOD_SCROLL;\n\t}\n\t//\n\t// stretch\n\t//\n\telse if ( !Q_stricmp( token, \"stretch\" ) )\n\t{\n\t\ttoken = COM_ParseExt( text, qfalse );\n\t\tif ( token[0] == 0 )\n\t\t{\n\t\t\tri.Printf( PRINT_WARNING, \"WARNING: missing stretch parms in shader '%s'\\n\", shader.name );\n\t\t\treturn;\n\t\t}\n\t\ttmi->wave.func = NameToGenFunc( token );\n\n\t\ttoken = COM_ParseExt( text, qfalse );\n\t\tif ( token[0] == 0 )\n\t\t{\n\t\t\tri.Printf( PRINT_WARNING, \"WARNING: missing stretch parms in shader '%s'\\n\", shader.name );\n\t\t\treturn;\n\t\t}\n\t\ttmi->wave.base = atof( token );\n\n\t\ttoken = COM_ParseExt( text, qfalse );\n\t\tif ( token[0] == 0 )\n\t\t{\n\t\t\tri.Printf( PRINT_WARNING, \"WARNING: missing stretch parms in shader '%s'\\n\", shader.name );\n\t\t\treturn;\n\t\t}\n\t\ttmi->wave.amplitude = atof( token );\n\n\t\ttoken = COM_ParseExt( text, qfalse );\n\t\tif ( token[0] == 0 )\n\t\t{\n\t\t\tri.Printf( PRINT_WARNING, \"WARNING: missing stretch parms in shader '%s'\\n\", shader.name );\n\t\t\treturn;\n\t\t}\n\t\ttmi->wave.phase = atof( token );\n\n\t\ttoken = COM_ParseExt( text, qfalse );\n\t\tif ( token[0] == 0 )\n\t\t{\n\t\t\tri.Printf( PRINT_WARNING, \"WARNING: missing stretch parms in shader '%s'\\n\", shader.name );\n\t\t\treturn;\n\t\t}\n\t\ttmi->wave.frequency = atof( token );\n\t\t\n\t\ttmi->type = TMOD_STRETCH;\n\t}\n\t//\n\t// transform\n\t//\n\telse if ( !Q_stricmp( token, \"transform\" ) )\n\t{\n\t\ttoken = COM_ParseExt( text, qfalse );\n\t\tif ( token[0] == 0 )\n\t\t{\n\t\t\tri.Printf( PRINT_WARNING, \"WARNING: missing transform parms in shader '%s'\\n\", shader.name );\n\t\t\treturn;\n\t\t}\n\t\ttmi->matrix[0][0] = atof( token );\n\n\t\ttoken = COM_ParseExt( text, qfalse );\n\t\tif ( token[0] == 0 )\n\t\t{\n\t\t\tri.Printf( PRINT_WARNING, \"WARNING: missing transform parms in shader '%s'\\n\", shader.name );\n\t\t\treturn;\n\t\t}\n\t\ttmi->matrix[0][1] = atof( token );\n\n\t\ttoken = COM_ParseExt( text, qfalse );\n\t\tif ( token[0] == 0 )\n\t\t{\n\t\t\tri.Printf( PRINT_WARNING, \"WARNING: missing transform parms in shader '%s'\\n\", shader.name );\n\t\t\treturn;\n\t\t}\n\t\ttmi->matrix[1][0] = atof( token );\n\n\t\ttoken = COM_ParseExt( text, qfalse );\n\t\tif ( token[0] == 0 )\n\t\t{\n\t\t\tri.Printf( PRINT_WARNING, \"WARNING: missing transform parms in shader '%s'\\n\", shader.name );\n\t\t\treturn;\n\t\t}\n\t\ttmi->matrix[1][1] = atof( token );\n\n\t\ttoken = COM_ParseExt( text, qfalse );\n\t\tif ( token[0] == 0 )\n\t\t{\n\t\t\tri.Printf( PRINT_WARNING, \"WARNING: missing transform parms in shader '%s'\\n\", shader.name );\n\t\t\treturn;\n\t\t}\n\t\ttmi->translate[0] = atof( token );\n\n\t\ttoken = COM_ParseExt( text, qfalse );\n\t\tif ( token[0] == 0 )\n\t\t{\n\t\t\tri.Printf( PRINT_WARNING, \"WARNING: missing transform parms in shader '%s'\\n\", shader.name );\n\t\t\treturn;\n\t\t}\n\t\ttmi->translate[1] = atof( token );\n\n\t\ttmi->type = TMOD_TRANSFORM;\n\t}\n\t//\n\t// rotate\n\t//\n\telse if ( !Q_stricmp( token, \"rotate\" ) )\n\t{\n\t\ttoken = COM_ParseExt( text, qfalse );\n\t\tif ( token[0] == 0 )\n\t\t{\n\t\t\tri.Printf( PRINT_WARNING, \"WARNING: missing tcMod rotate parms in shader '%s'\\n\", shader.name );\n\t\t\treturn;\n\t\t}\n\t\ttmi->rotateSpeed = atof( token );\n\t\ttmi->type = TMOD_ROTATE;\n\t}\n\t//\n\t// entityTranslate\n\t//\n\telse if ( !Q_stricmp( token, \"entityTranslate\" ) )\n\t{\n\t\ttmi->type = TMOD_ENTITY_TRANSLATE;\n\t}\n\telse\n\t{\n\t\tri.Printf( PRINT_WARNING, \"WARNING: unknown tcMod '%s' in shader '%s'\\n\", token, shader.name );\n\t}\n}\n\n\n/*\n===================\nParseStage\n===================\n*/\nstatic qboolean ParseStage( shaderStage_t *stage, char **text )\n{\n\tchar *token;\n\tint depthMaskBits = GLS_DEPTHMASK_TRUE, blendSrcBits = 0, blendDstBits = 0, atestBits = 0, depthFuncBits = 0;\n\tqboolean depthMaskExplicit = qfalse;\n\n\tstage->active = qtrue;\n\n\twhile ( 1 )\n\t{\n\t\ttoken = COM_ParseExt( text, qtrue );\n\t\tif ( !token[0] )\n\t\t{\n\t\t\tri.Printf( PRINT_WARNING, \"WARNING: no matching '}' found\\n\" );\n\t\t\treturn qfalse;\n\t\t}\n\n\t\tif ( token[0] == '}' )\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t\t//\n\t\t// map <name>\n\t\t//\n\t\telse if ( !Q_stricmp( token, \"map\" ) )\n\t\t{\n\t\t\ttoken = COM_ParseExt( text, qfalse );\n\t\t\tif ( !token[0] )\n\t\t\t{\n\t\t\t\tri.Printf( PRINT_WARNING, \"WARNING: missing parameter for 'map' keyword in shader '%s'\\n\", shader.name );\n\t\t\t\treturn qfalse;\n\t\t\t}\n\n\t\t\tif ( !Q_stricmp( token, \"$whiteimage\" ) )\n\t\t\t{\n\t\t\t\tstage->bundle[0].image[0] = tr.whiteImage;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\telse if ( !Q_stricmp( token, \"$lightmap\" ) )\n\t\t\t{\n\t\t\t\tstage->bundle[0].isLightmap = qtrue;\n\t\t\t\tif ( shader.lightmapIndex < 0 ) {\n\t\t\t\t\tstage->bundle[0].image[0] = tr.whiteImage;\n\t\t\t\t} else {\n\t\t\t\t\tstage->bundle[0].image[0] = tr.lightmaps[shader.lightmapIndex];\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tstage->bundle[0].image[0] = R_FindImageFile(token, (qboolean) !shader.noMipMaps, (qboolean)!shader.noPicMip, GL_REPEAT);\n\t\t\t\tif ( !stage->bundle[0].image[0] )\n\t\t\t\t{\n\t\t\t\t\tri.Printf( PRINT_WARNING, \"WARNING: R_FindImageFile could not find '%s' in shader '%s'\\n\", token, shader.name );\n\t\t\t\t\treturn qfalse;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t//\n\t\t// clampmap <name>\n\t\t//\n\t\telse if ( !Q_stricmp( token, \"clampmap\" ) )\n\t\t{\n\t\t\ttoken = COM_ParseExt( text, qfalse );\n\t\t\tif ( !token[0] )\n\t\t\t{\n\t\t\t\tri.Printf( PRINT_WARNING, \"WARNING: missing parameter for 'clampmap' keyword in shader '%s'\\n\", shader.name );\n\t\t\t\treturn qfalse;\n\t\t\t}\n\n\t\t\tstage->bundle[0].image[0] = R_FindImageFile(token, (qboolean)!shader.noMipMaps, (qboolean) !shader.noPicMip, GL_CLAMP);\n\t\t\tif ( !stage->bundle[0].image[0] )\n\t\t\t{\n\t\t\t\tri.Printf( PRINT_WARNING, \"WARNING: R_FindImageFile could not find '%s' in shader '%s'\\n\", token, shader.name );\n\t\t\t\treturn qfalse;\n\t\t\t}\n\t\t}\n\t\t//\n\t\t// animMap <frequency> <image1> .... <imageN>\n\t\t//\n\t\telse if ( !Q_stricmp( token, \"animMap\" ) )\n\t\t{\n\t\t\ttoken = COM_ParseExt( text, qfalse );\n\t\t\tif ( !token[0] )\n\t\t\t{\n\t\t\t\tri.Printf( PRINT_WARNING, \"WARNING: missing parameter for 'animMmap' keyword in shader '%s'\\n\", shader.name );\n\t\t\t\treturn qfalse;\n\t\t\t}\n\t\t\tstage->bundle[0].imageAnimationSpeed = atof( token );\n\n\t\t\t// parse up to MAX_IMAGE_ANIMATIONS animations\n\t\t\twhile ( 1 ) {\n\t\t\t\tint\t\tnum;\n\n\t\t\t\ttoken = COM_ParseExt( text, qfalse );\n\t\t\t\tif ( !token[0] ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tnum = stage->bundle[0].numImageAnimations;\n\t\t\t\tif ( num < MAX_IMAGE_ANIMATIONS ) {\n\t\t\t\t\tstage->bundle[0].image[num] = R_FindImageFile(token, (qboolean)!shader.noMipMaps, (qboolean) !shader.noPicMip, GL_REPEAT);\n\t\t\t\t\tif ( !stage->bundle[0].image[num] )\n\t\t\t\t\t{\n\t\t\t\t\t\tri.Printf( PRINT_WARNING, \"WARNING: R_FindImageFile could not find '%s' in shader '%s'\\n\", token, shader.name );\n\t\t\t\t\t\treturn qfalse;\n\t\t\t\t\t}\n\t\t\t\t\tstage->bundle[0].numImageAnimations++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if ( !Q_stricmp( token, \"videoMap\" ) )\n\t\t{\n\t\t\ttoken = COM_ParseExt( text, qfalse );\n\t\t\tif ( !token[0] )\n\t\t\t{\n\t\t\t\tri.Printf( PRINT_WARNING, \"WARNING: missing parameter for 'videoMmap' keyword in shader '%s'\\n\", shader.name );\n\t\t\t\treturn qfalse;\n\t\t\t}\n\t\t\tstage->bundle[0].videoMapHandle = ri.CIN_PlayCinematic( token, 0, 0, 256, 256, (CIN_loop | CIN_silent | CIN_shader));\n\t\t\tif (stage->bundle[0].videoMapHandle != -1) {\n\t\t\t\tstage->bundle[0].isVideoMap = qtrue;\n\t\t\t\tstage->bundle[0].image[0] = tr.scratchImage[stage->bundle[0].videoMapHandle];\n\t\t\t}\n\t\t}\n\t\t//\n\t\t// alphafunc <func>\n\t\t//\n\t\telse if ( !Q_stricmp( token, \"alphaFunc\" ) )\n\t\t{\n\t\t\ttoken = COM_ParseExt( text, qfalse );\n\t\t\tif ( !token[0] )\n\t\t\t{\n\t\t\t\tri.Printf( PRINT_WARNING, \"WARNING: missing parameter for 'alphaFunc' keyword in shader '%s'\\n\", shader.name );\n\t\t\t\treturn qfalse;\n\t\t\t}\n\n\t\t\tatestBits = NameToAFunc( token );\n\t\t}\n\t\t//\n\t\t// depthFunc <func>\n\t\t//\n\t\telse if ( !Q_stricmp( token, \"depthfunc\" ) )\n\t\t{\n\t\t\ttoken = COM_ParseExt( text, qfalse );\n\n\t\t\tif ( !token[0] )\n\t\t\t{\n\t\t\t\tri.Printf( PRINT_WARNING, \"WARNING: missing parameter for 'depthfunc' keyword in shader '%s'\\n\", shader.name );\n\t\t\t\treturn qfalse;\n\t\t\t}\n\n\t\t\tif ( !Q_stricmp( token, \"lequal\" ) )\n\t\t\t{\n\t\t\t\tdepthFuncBits = 0;\n\t\t\t}\n\t\t\telse if ( !Q_stricmp( token, \"equal\" ) )\n\t\t\t{\n\t\t\t\tdepthFuncBits = GLS_DEPTHFUNC_EQUAL;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tri.Printf( PRINT_WARNING, \"WARNING: unknown depthfunc '%s' in shader '%s'\\n\", token, shader.name );\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\t//\n\t\t// detail\n\t\t//\n\t\telse if ( !Q_stricmp( token, \"detail\" ) )\n\t\t{\n\t\t\tstage->isDetail = qtrue;\n\t\t}\n\t\t//\n\t\t// blendfunc <srcFactor> <dstFactor>\n\t\t// or blendfunc <add|filter|blend>\n\t\t//\n\t\telse if ( !Q_stricmp( token, \"blendfunc\" ) )\n\t\t{\n\t\t\ttoken = COM_ParseExt( text, qfalse );\n\t\t\tif ( token[0] == 0 )\n\t\t\t{\n\t\t\t\tri.Printf( PRINT_WARNING, \"WARNING: missing parm for blendFunc in shader '%s'\\n\", shader.name );\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// check for \"simple\" blends first\n\t\t\tif ( !Q_stricmp( token, \"add\" ) ) {\n\t\t\t\tblendSrcBits = GLS_SRCBLEND_ONE;\n\t\t\t\tblendDstBits = GLS_DSTBLEND_ONE;\n\t\t\t} else if ( !Q_stricmp( token, \"filter\" ) ) {\n\t\t\t\tblendSrcBits = GLS_SRCBLEND_DST_COLOR;\n\t\t\t\tblendDstBits = GLS_DSTBLEND_ZERO;\n\t\t\t} else if ( !Q_stricmp( token, \"blend\" ) ) {\n\t\t\t\tblendSrcBits = GLS_SRCBLEND_SRC_ALPHA;\n\t\t\t\tblendDstBits = GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA;\n\t\t\t} else {\n\t\t\t\t// complex double blends\n\t\t\t\tblendSrcBits = NameToSrcBlendMode( token );\n\n\t\t\t\ttoken = COM_ParseExt( text, qfalse );\n\t\t\t\tif ( token[0] == 0 )\n\t\t\t\t{\n\t\t\t\t\tri.Printf( PRINT_WARNING, \"WARNING: missing parm for blendFunc in shader '%s'\\n\", shader.name );\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tblendDstBits = NameToDstBlendMode( token );\n\t\t\t}\n\n\t\t\t// clear depth mask for blended surfaces\n\t\t\tif ( !depthMaskExplicit )\n\t\t\t{\n\t\t\t\tdepthMaskBits = 0;\n\t\t\t}\n\t\t}\n\t\t//\n\t\t// rgbGen\n\t\t//\n\t\telse if ( !Q_stricmp( token, \"rgbGen\" ) )\n\t\t{\n\t\t\ttoken = COM_ParseExt( text, qfalse );\n\t\t\tif ( token[0] == 0 )\n\t\t\t{\n\t\t\t\tri.Printf( PRINT_WARNING, \"WARNING: missing parameters for rgbGen in shader '%s'\\n\", shader.name );\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif ( !Q_stricmp( token, \"wave\" ) )\n\t\t\t{\n\t\t\t\tParseWaveForm( text, &stage->rgbWave );\n\t\t\t\tstage->rgbGen = CGEN_WAVEFORM;\n\t\t\t}\n\t\t\telse if ( !Q_stricmp( token, \"const\" ) )\n\t\t\t{\n\t\t\t\tvec3_t\tcolor;\n\n\t\t\t\tParseVector( text, 3, color );\n\t\t\t\tstage->constantColor[0] = 255 * color[0];\n\t\t\t\tstage->constantColor[1] = 255 * color[1];\n\t\t\t\tstage->constantColor[2] = 255 * color[2];\n\n\t\t\t\tstage->rgbGen = CGEN_CONST;\n\t\t\t}\n\t\t\telse if ( !Q_stricmp( token, \"identity\" ) )\n\t\t\t{\n\t\t\t\tstage->rgbGen = CGEN_IDENTITY;\n\t\t\t}\n\t\t\telse if ( !Q_stricmp( token, \"identityLighting\" ) )\n\t\t\t{\n\t\t\t\tstage->rgbGen = CGEN_IDENTITY_LIGHTING;\n\t\t\t}\n\t\t\telse if ( !Q_stricmp( token, \"entity\" ) )\n\t\t\t{\n\t\t\t\tstage->rgbGen = CGEN_ENTITY;\n\t\t\t}\n\t\t\telse if ( !Q_stricmp( token, \"oneMinusEntity\" ) )\n\t\t\t{\n\t\t\t\tstage->rgbGen = CGEN_ONE_MINUS_ENTITY;\n\t\t\t}\n\t\t\telse if ( !Q_stricmp( token, \"vertex\" ) )\n\t\t\t{\n\t\t\t\tstage->rgbGen = CGEN_VERTEX;\n\t\t\t\tif ( stage->alphaGen == 0 ) {\n\t\t\t\t\tstage->alphaGen = AGEN_VERTEX;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if ( !Q_stricmp( token, \"exactVertex\" ) )\n\t\t\t{\n\t\t\t\tstage->rgbGen = CGEN_EXACT_VERTEX;\n\t\t\t}\n\t\t\telse if ( !Q_stricmp( token, \"lightingDiffuse\" ) )\n\t\t\t{\n\t\t\t\tstage->rgbGen = CGEN_LIGHTING_DIFFUSE;\n\t\t\t}\n\t\t\telse if ( !Q_stricmp( token, \"oneMinusVertex\" ) )\n\t\t\t{\n\t\t\t\tstage->rgbGen = CGEN_ONE_MINUS_VERTEX;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tri.Printf( PRINT_WARNING, \"WARNING: unknown rgbGen parameter '%s' in shader '%s'\\n\", token, shader.name );\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\t//\n\t\t// alphaGen \n\t\t//\n\t\telse if ( !Q_stricmp( token, \"alphaGen\" ) )\n\t\t{\n\t\t\ttoken = COM_ParseExt( text, qfalse );\n\t\t\tif ( token[0] == 0 )\n\t\t\t{\n\t\t\t\tri.Printf( PRINT_WARNING, \"WARNING: missing parameters for alphaGen in shader '%s'\\n\", shader.name );\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif ( !Q_stricmp( token, \"wave\" ) )\n\t\t\t{\n\t\t\t\tParseWaveForm( text, &stage->alphaWave );\n\t\t\t\tstage->alphaGen = AGEN_WAVEFORM;\n\t\t\t}\n\t\t\telse if ( !Q_stricmp( token, \"const\" ) )\n\t\t\t{\n\t\t\t\ttoken = COM_ParseExt( text, qfalse );\n\t\t\t\tstage->constantColor[3] = 255 * atof( token );\n\t\t\t\tstage->alphaGen = AGEN_CONST;\n\t\t\t}\n\t\t\telse if ( !Q_stricmp( token, \"identity\" ) )\n\t\t\t{\n\t\t\t\tstage->alphaGen = AGEN_IDENTITY;\n\t\t\t}\n\t\t\telse if ( !Q_stricmp( token, \"entity\" ) )\n\t\t\t{\n\t\t\t\tstage->alphaGen = AGEN_ENTITY;\n\t\t\t}\n\t\t\telse if ( !Q_stricmp( token, \"oneMinusEntity\" ) )\n\t\t\t{\n\t\t\t\tstage->alphaGen = AGEN_ONE_MINUS_ENTITY;\n\t\t\t}\n\t\t\telse if ( !Q_stricmp( token, \"vertex\" ) )\n\t\t\t{\n\t\t\t\tstage->alphaGen = AGEN_VERTEX;\n\t\t\t}\n\t\t\telse if ( !Q_stricmp( token, \"lightingSpecular\" ) )\n\t\t\t{\n\t\t\t\tstage->alphaGen = AGEN_LIGHTING_SPECULAR;\n\t\t\t}\n\t\t\telse if ( !Q_stricmp( token, \"oneMinusVertex\" ) )\n\t\t\t{\n\t\t\t\tstage->alphaGen = AGEN_ONE_MINUS_VERTEX;\n\t\t\t}\n\t\t\telse if ( !Q_stricmp( token, \"portal\" ) )\n\t\t\t{\n\t\t\t\tstage->alphaGen = AGEN_PORTAL;\n\t\t\t\ttoken = COM_ParseExt( text, qfalse );\n\t\t\t\tif ( token[0] == 0 )\n\t\t\t\t{\n\t\t\t\t\tshader.portalRange = 256;\n\t\t\t\t\tri.Printf( PRINT_WARNING, \"WARNING: missing range parameter for alphaGen portal in shader '%s', defaulting to 256\\n\", shader.name );\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tshader.portalRange = atof( token );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tri.Printf( PRINT_WARNING, \"WARNING: unknown alphaGen parameter '%s' in shader '%s'\\n\", token, shader.name );\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\t//\n\t\t// tcGen <function>\n\t\t//\n\t\telse if ( !Q_stricmp(token, \"texgen\") || !Q_stricmp( token, \"tcGen\" ) ) \n\t\t{\n\t\t\ttoken = COM_ParseExt( text, qfalse );\n\t\t\tif ( token[0] == 0 )\n\t\t\t{\n\t\t\t\tri.Printf( PRINT_WARNING, \"WARNING: missing texgen parm in shader '%s'\\n\", shader.name );\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif ( !Q_stricmp( token, \"environment\" ) )\n\t\t\t{\n\t\t\t\tstage->bundle[0].tcGen = TCGEN_ENVIRONMENT_MAPPED;\n\t\t\t}\n\t\t\telse if ( !Q_stricmp( token, \"lightmap\" ) )\n\t\t\t{\n\t\t\t\tstage->bundle[0].tcGen = TCGEN_LIGHTMAP;\n\t\t\t}\n\t\t\telse if ( !Q_stricmp( token, \"texture\" ) || !Q_stricmp( token, \"base\" ) )\n\t\t\t{\n\t\t\t\tstage->bundle[0].tcGen = TCGEN_TEXTURE;\n\t\t\t}\n\t\t\telse if ( !Q_stricmp( token, \"vector\" ) )\n\t\t\t{\n\t\t\t\tParseVector( text, 3, stage->bundle[0].tcGenVectors[0] );\n\t\t\t\tParseVector( text, 3, stage->bundle[0].tcGenVectors[1] );\n\n\t\t\t\tstage->bundle[0].tcGen = TCGEN_VECTOR;\n\t\t\t}\n\t\t\telse \n\t\t\t{\n\t\t\t\tri.Printf( PRINT_WARNING, \"WARNING: unknown texgen parm in shader '%s'\\n\", shader.name );\n\t\t\t}\n\t\t}\n\t\t//\n\t\t// tcMod <type> <...>\n\t\t//\n\t\telse if ( !Q_stricmp( token, \"tcMod\" ) )\n\t\t{\n\t\t\tchar buffer[1024] = \"\";\n\n\t\t\twhile ( 1 )\n\t\t\t{\n\t\t\t\ttoken = COM_ParseExt( text, qfalse );\n\t\t\t\tif ( token[0] == 0 )\n\t\t\t\t\tbreak;\n\t\t\t\tstrcat( buffer, token );\n\t\t\t\tstrcat( buffer, \" \" );\n\t\t\t}\n\n\t\t\tParseTexMod( buffer, stage );\n\n\t\t\tcontinue;\n\t\t}\n\t\t//\n\t\t// depthmask\n\t\t//\n\t\telse if ( !Q_stricmp( token, \"depthwrite\" ) )\n\t\t{\n\t\t\tdepthMaskBits = GLS_DEPTHMASK_TRUE;\n\t\t\tdepthMaskExplicit = qtrue;\n\n\t\t\tcontinue;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tri.Printf( PRINT_WARNING, \"WARNING: unknown parameter '%s' in shader '%s'\\n\", token, shader.name );\n\t\t\treturn qfalse;\n\t\t}\n\t}\n\n\t//\n\t// if cgen isn't explicitly specified, use either identity or identitylighting\n\t//\n\tif ( stage->rgbGen == CGEN_BAD ) {\n\t\tif ( blendSrcBits == 0 ||\n\t\t\tblendSrcBits == GLS_SRCBLEND_ONE || \n\t\t\tblendSrcBits == GLS_SRCBLEND_SRC_ALPHA ) {\n\t\t\tstage->rgbGen = CGEN_IDENTITY_LIGHTING;\n\t\t} else {\n\t\t\tstage->rgbGen = CGEN_IDENTITY;\n\t\t}\n\t}\n\n\n\t//\n\t// implicitly assume that a GL_ONE GL_ZERO blend mask disables blending\n\t//\n\tif ( ( blendSrcBits == GLS_SRCBLEND_ONE ) && \n\t\t ( blendDstBits == GLS_DSTBLEND_ZERO ) )\n\t{\n\t\tblendDstBits = blendSrcBits = 0;\n\t\tdepthMaskBits = GLS_DEPTHMASK_TRUE;\n\t}\n\n\t// decide which agens we can skip\n\tif ( stage->alphaGen == CGEN_IDENTITY ) {\n\t\tif ( stage->rgbGen == CGEN_IDENTITY\n\t\t\t|| stage->rgbGen == CGEN_LIGHTING_DIFFUSE ) {\n\t\t\tstage->alphaGen = AGEN_SKIP;\n\t\t}\n\t}\n\n\t//\n\t// compute state bits\n\t//\n\tstage->stateBits = depthMaskBits | \n\t\t               blendSrcBits | blendDstBits | \n\t\t\t\t\t   atestBits | \n\t\t\t\t\t   depthFuncBits;\n\n\treturn qtrue;\n}\n\n/*\n===============\nParseDeform\n\ndeformVertexes wave <spread> <waveform> <base> <amplitude> <phase> <frequency>\ndeformVertexes normal <frequency> <amplitude>\ndeformVertexes move <vector> <waveform> <base> <amplitude> <phase> <frequency>\ndeformVertexes bulge <bulgeWidth> <bulgeHeight> <bulgeSpeed>\ndeformVertexes projectionShadow\ndeformVertexes autoSprite\ndeformVertexes autoSprite2\ndeformVertexes text[0-7]\n===============\n*/\nstatic void ParseDeform( char **text ) {\n\tchar\t*token;\n\tdeformStage_t\t*ds;\n\n\ttoken = COM_ParseExt( text, qfalse );\n\tif ( token[0] == 0 )\n\t{\n\t\tri.Printf( PRINT_WARNING, \"WARNING: missing deform parm in shader '%s'\\n\", shader.name );\n\t\treturn;\n\t}\n\n\tif ( shader.numDeforms == MAX_SHADER_DEFORMS ) {\n\t\tri.Printf( PRINT_WARNING, \"WARNING: MAX_SHADER_DEFORMS in '%s'\\n\", shader.name );\n\t\treturn;\n\t}\n\n\tds = &shader.deforms[ shader.numDeforms ];\n\tshader.numDeforms++;\n\n\tif ( !Q_stricmp( token, \"projectionShadow\" ) ) {\n\t\tds->deformation = DEFORM_PROJECTION_SHADOW;\n\t\treturn;\n\t}\n\n\tif ( !Q_stricmp( token, \"autosprite\" ) ) {\n\t\tds->deformation = DEFORM_AUTOSPRITE;\n\t\treturn;\n\t}\n\n\tif ( !Q_stricmp( token, \"autosprite2\" ) ) {\n\t\tds->deformation = DEFORM_AUTOSPRITE2;\n\t\treturn;\n\t}\n\n\tif ( !Q_stricmpn( token, \"text\", 4 ) ) {\n\t\tint\t\tn;\n\t\t\n\t\tn = token[4] - '0';\n\t\tif ( n < 0 || n > 7 ) {\n\t\t\tn = 0;\n\t\t}\n\t\tds->deformation = static_cast<deform_t>(DEFORM_TEXT0 + n);\n\t\treturn;\n\t}\n\n\tif ( !Q_stricmp( token, \"bulge\" ) )\t{\n\t\ttoken = COM_ParseExt( text, qfalse );\n\t\tif ( token[0] == 0 )\n\t\t{\n\t\t\tri.Printf( PRINT_WARNING, \"WARNING: missing deformVertexes bulge parm in shader '%s'\\n\", shader.name );\n\t\t\treturn;\n\t\t}\n\t\tds->bulgeWidth = atof( token );\n\n\t\ttoken = COM_ParseExt( text, qfalse );\n\t\tif ( token[0] == 0 )\n\t\t{\n\t\t\tri.Printf( PRINT_WARNING, \"WARNING: missing deformVertexes bulge parm in shader '%s'\\n\", shader.name );\n\t\t\treturn;\n\t\t}\n\t\tds->bulgeHeight = atof( token );\n\n\t\ttoken = COM_ParseExt( text, qfalse );\n\t\tif ( token[0] == 0 )\n\t\t{\n\t\t\tri.Printf( PRINT_WARNING, \"WARNING: missing deformVertexes bulge parm in shader '%s'\\n\", shader.name );\n\t\t\treturn;\n\t\t}\n\t\tds->bulgeSpeed = atof( token );\n\n\t\tds->deformation = DEFORM_BULGE;\n\t\treturn;\n\t}\n\n\tif ( !Q_stricmp( token, \"wave\" ) )\n\t{\n\t\ttoken = COM_ParseExt( text, qfalse );\n\t\tif ( token[0] == 0 )\n\t\t{\n\t\t\tri.Printf( PRINT_WARNING, \"WARNING: missing deformVertexes parm in shader '%s'\\n\", shader.name );\n\t\t\treturn;\n\t\t}\n\n\t\tif ( atof( token ) != 0 )\n\t\t{\n\t\t\tds->deformationSpread = 1.0f / atof( token );\n\t\t}\n\t\telse\n\t\t{\n\t\t\tds->deformationSpread = 100.0f;\n\t\t\tri.Printf( PRINT_WARNING, \"WARNING: illegal div value of 0 in deformVertexes command for shader '%s'\\n\", shader.name );\n\t\t}\n\n\t\tParseWaveForm( text, &ds->deformationWave );\n\t\tds->deformation = DEFORM_WAVE;\n\t\treturn;\n\t}\n\n\tif ( !Q_stricmp( token, \"normal\" ) )\n\t{\n\t\ttoken = COM_ParseExt( text, qfalse );\n\t\tif ( token[0] == 0 )\n\t\t{\n\t\t\tri.Printf( PRINT_WARNING, \"WARNING: missing deformVertexes parm in shader '%s'\\n\", shader.name );\n\t\t\treturn;\n\t\t}\n\t\tds->deformationWave.amplitude = atof( token );\n\n\t\ttoken = COM_ParseExt( text, qfalse );\n\t\tif ( token[0] == 0 )\n\t\t{\n\t\t\tri.Printf( PRINT_WARNING, \"WARNING: missing deformVertexes parm in shader '%s'\\n\", shader.name );\n\t\t\treturn;\n\t\t}\n\t\tds->deformationWave.frequency = atof( token );\n\n\t\tds->deformation = DEFORM_NORMALS;\n\t\treturn;\n\t}\n\n\tif ( !Q_stricmp( token, \"move\" ) ) {\n\t\tint\t\ti;\n\n\t\tfor ( i = 0 ; i < 3 ; i++ ) {\n\t\t\ttoken = COM_ParseExt( text, qfalse );\n\t\t\tif ( token[0] == 0 ) {\n\t\t\t\tri.Printf( PRINT_WARNING, \"WARNING: missing deformVertexes parm in shader '%s'\\n\", shader.name );\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tds->moveVector[i] = atof( token );\n\t\t}\n\n\t\tParseWaveForm( text, &ds->deformationWave );\n\t\tds->deformation = DEFORM_MOVE;\n\t\treturn;\n\t}\n\n\tri.Printf( PRINT_WARNING, \"WARNING: unknown deformVertexes subtype '%s' found in shader '%s'\\n\", token, shader.name );\n}\n\n\n/*\n===============\nParseSkyParms\n\nskyParms <outerbox> <cloudheight> <innerbox>\n===============\n*/\nstatic void ParseSkyParms( char **text ) {\n\tchar\t\t*token;\n\tstatic char\t*suf[6] = {\"rt\", \"bk\", \"lf\", \"ft\", \"up\", \"dn\"};\n\tchar\t\tpathname[MAX_QPATH];\n\tint\t\t\ti;\n\n\t// outerbox\n\ttoken = COM_ParseExt( text, qfalse );\n\tif ( token[0] == 0 ) {\n\t\tri.Printf( PRINT_WARNING, \"WARNING: 'skyParms' missing parameter in shader '%s'\\n\", shader.name );\n\t\treturn;\n\t}\n\tif ( strcmp( token, \"-\" ) ) {\n\t\tfor (i=0 ; i<6 ; i++) {\n\t\t\tCom_sprintf( pathname, sizeof(pathname), \"%s_%s.tga\"\n\t\t\t\t, token, suf[i] );\n\t\t\tshader.sky.outerbox[i] = R_FindImageFile( ( char * ) pathname, qtrue, qtrue, GL_CLAMP );\n\t\t\tif ( !shader.sky.outerbox[i] ) {\n\t\t\t\tshader.sky.outerbox[i] = tr.defaultImage;\n\t\t\t}\n\t\t}\n\t}\n\n\t// cloudheight\n\ttoken = COM_ParseExt( text, qfalse );\n\tif ( token[0] == 0 ) {\n\t\tri.Printf( PRINT_WARNING, \"WARNING: 'skyParms' missing parameter in shader '%s'\\n\", shader.name );\n\t\treturn;\n\t}\n\tshader.sky.cloudHeight = atof( token );\n\tif ( !shader.sky.cloudHeight ) {\n\t\tshader.sky.cloudHeight = 512;\n\t}\n\tR_InitSkyTexCoords( shader.sky.cloudHeight );\n\n\n\t// innerbox\n\ttoken = COM_ParseExt( text, qfalse );\n\tif ( token[0] == 0 ) {\n\t\tri.Printf( PRINT_WARNING, \"WARNING: 'skyParms' missing parameter in shader '%s'\\n\", shader.name );\n\t\treturn;\n\t}\n\tif ( strcmp( token, \"-\" ) ) {\n\t\tfor (i=0 ; i<6 ; i++) {\n\t\t\tCom_sprintf( pathname, sizeof(pathname), \"%s_%s.tga\"\n\t\t\t\t, token, suf[i] );\n\t\t\tshader.sky.innerbox[i] = R_FindImageFile( ( char * ) pathname, qtrue, qtrue, GL_REPEAT );\n\t\t\tif ( !shader.sky.innerbox[i] ) {\n\t\t\t\tshader.sky.innerbox[i] = tr.defaultImage;\n\t\t\t}\n\t\t}\n\t}\n\n\tshader.isSky = qtrue;\n}\n\n\n/*\n=================\nParseSort\n=================\n*/\nvoid ParseSort( char **text ) {\n\tchar\t*token;\n\n\ttoken = COM_ParseExt( text, qfalse );\n\tif ( token[0] == 0 ) {\n\t\tri.Printf( PRINT_WARNING, \"WARNING: missing sort parameter in shader '%s'\\n\", shader.name );\n\t\treturn;\n\t}\n\n\tif ( !Q_stricmp( token, \"portal\" ) ) {\n\t\tshader.sort = SS_PORTAL;\n\t} else if ( !Q_stricmp( token, \"sky\" ) ) {\n\t\tshader.sort = SS_ENVIRONMENT;\n\t} else if ( !Q_stricmp( token, \"opaque\" ) ) {\n\t\tshader.sort = SS_OPAQUE;\n\t}else if ( !Q_stricmp( token, \"decal\" ) ) {\n\t\tshader.sort = SS_DECAL;\n\t} else if ( !Q_stricmp( token, \"seeThrough\" ) ) {\n\t\tshader.sort = SS_SEE_THROUGH;\n\t} else if ( !Q_stricmp( token, \"banner\" ) ) {\n\t\tshader.sort = SS_BANNER;\n\t} else if ( !Q_stricmp( token, \"additive\" ) ) {\n\t\tshader.sort = SS_BLEND1;\n\t} else if ( !Q_stricmp( token, \"nearest\" ) ) {\n\t\tshader.sort = SS_NEAREST;\n\t} else if ( !Q_stricmp( token, \"underwater\" ) ) {\n\t\tshader.sort = SS_UNDERWATER;\n\t} else {\n\t\tshader.sort = atof( token );\n\t}\n}\n\n\n\n// this table is also present in q3map\n\ntypedef struct {\n\tchar\t*name;\n\tint\t\tclearSolid;\n    unsigned int surfaceFlags, contents;\n} infoParm_t;\n\ninfoParm_t\tinfoParms[] = {\n\t// server relevant contents\n\t{\"water\",\t\t1,\t0,\tCONTENTS_WATER },\n\t{\"slime\",\t\t1,\t0,\tCONTENTS_SLIME },\t\t// mildly damaging\n\t{\"lava\",\t\t1,\t0,\tCONTENTS_LAVA },\t\t// very damaging\n\t{\"playerclip\",\t1,\t0,\tCONTENTS_PLAYERCLIP },\n\t{\"monsterclip\",\t1,\t0,\tCONTENTS_MONSTERCLIP },\n\t{\"nodrop\",\t\t1,\t0,\tCONTENTS_NODROP },\t\t// don't drop items or leave bodies (death fog, lava, etc)\n\t{\"nonsolid\",\t1,\tSURF_NONSOLID,\t0},\t\t\t\t\t\t// clears the solid flag\n\n\t// utility relevant attributes\n\t{\"origin\",\t\t1,\t0,\tCONTENTS_ORIGIN },\t\t// center of rotating brushes\n\t{\"trans\",\t\t0,\t0,\tCONTENTS_TRANSLUCENT },\t// don't eat contained surfaces\n\t{\"detail\",\t\t0,\t0,\tCONTENTS_DETAIL },\t\t// don't include in structural bsp\n\t{\"structural\",\t0,\t0,\tCONTENTS_STRUCTURAL },\t// force into structural bsp even if trnas\n\t{\"areaportal\",\t1,\t0,\tCONTENTS_AREAPORTAL },\t// divides areas\n\t{\"clusterportal\", 1,0,  CONTENTS_CLUSTERPORTAL },\t// for bots\n\t{\"donotenter\",  1,  0,  CONTENTS_DONOTENTER },\t\t// for bots\n\n\t{\"fog\",\t\t\t1,\t0,\tCONTENTS_FOG},\t\t\t// carves surfaces entering\n\t{\"sky\",\t\t\t0,\tSURF_SKY,\t\t0 },\t\t// emit light from an environment map\n\t{\"lightfilter\",\t0,\tSURF_LIGHTFILTER, 0 },\t\t// filter light going through it\n\t{\"alphashadow\",\t0,\tSURF_ALPHASHADOW, 0 },\t\t// test light on a per-pixel basis\n\t{\"hint\",\t\t0,\tSURF_HINT,\t\t0 },\t\t// use as a primary splitter\n\n\t// server attributes\n\t{\"slick\",\t\t0,\tSURF_SLICK,\t\t0 },\n\t{\"noimpact\",\t0,\tSURF_NOIMPACT,\t0 },\t\t// don't make impact explosions or marks\n\t{\"nomarks\",\t\t0,\tSURF_NOMARKS,\t0 },\t\t// don't make impact marks, but still explode\n\t{\"ladder\",\t\t0,\tSURF_LADDER,\t0 },\n\t{\"nodamage\",\t0,\tSURF_NODAMAGE,\t0 },\n\t{\"metalsteps\",\t0,\tSURF_METALSTEPS,0 },\n\t{\"flesh\",\t\t0,\tSURF_FLESH,\t\t0 },\n\t{\"nosteps\",\t\t0,\tSURF_NOSTEPS,\t0 },\n\n\t// drawsurf attributes\n\t{\"nodraw\",\t\t0,\tSURF_NODRAW,\t0 },\t// don't generate a drawsurface (or a lightmap)\n\t{\"pointlight\",\t0,\tSURF_POINTLIGHT, 0 },\t// sample lighting at vertexes\n\t{\"nolightmap\",\t0,\tSURF_NOLIGHTMAP,0 },\t// don't generate a lightmap\n\t{\"nodlight\",\t0,\tSURF_NODLIGHT, 0 },\t\t// don't ever add dynamic lights\n\t{\"dust\",\t\t0,\tSURF_DUST, 0}\t\t\t// leave a dust trail when walking on this surface\n};\n\n\n/*\n===============\nParseSurfaceParm\n\nsurfaceparm <name>\n===============\n*/\nstatic void ParseSurfaceParm( char **text ) {\n\tchar\t*token;\n\tint\t\tnumInfoParms = sizeof(infoParms) / sizeof(infoParms[0]);\n\tint\t\ti;\n\n\ttoken = COM_ParseExt( text, qfalse );\n\tfor ( i = 0 ; i < numInfoParms ; i++ ) {\n\t\tif ( !Q_stricmp( token, infoParms[i].name ) ) {\n\t\t\tshader.surfaceFlags |= (int)infoParms[i].surfaceFlags;\n\t\t\tshader.contentFlags |= (int)infoParms[i].contents;\n#if 0\n\t\t\tif ( infoParms[i].clearSolid ) {\n\t\t\t\tsi->contents &= ~CONTENTS_SOLID;\n\t\t\t}\n#endif\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\n/*\n=================\nParseShader\n\nThe current text pointer is at the explicit text definition of the\nshader.  Parse it into the global shader variable.  Later functions\nwill optimize it.\n=================\n*/\nstatic qboolean ParseShader( char **text )\n{\n\tchar *token;\n\tint s;\n\n\ts = 0;\n\n\ttoken = COM_ParseExt( text, qtrue );\n\tif ( token[0] != '{' )\n\t{\n\t\tri.Printf( PRINT_WARNING, \"WARNING: expecting '{', found '%s' instead in shader '%s'\\n\", token, shader.name );\n\t\treturn qfalse;\n\t}\n\n\twhile ( 1 )\n\t{\n\t\ttoken = COM_ParseExt( text, qtrue );\n\t\tif ( !token[0] )\n\t\t{\n\t\t\tri.Printf( PRINT_WARNING, \"WARNING: no concluding '}' in shader %s\\n\", shader.name );\n\t\t\treturn qfalse;\n\t\t}\n\n\t\t// end of shader definition\n\t\tif ( token[0] == '}' )\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t\t// stage definition\n\t\telse if ( token[0] == '{' )\n\t\t{\n\t\t\tif ( !ParseStage( &stages[s], text ) )\n\t\t\t{\n\t\t\t\treturn qfalse;\n\t\t\t}\n\t\t\tstages[s].active = qtrue;\n\t\t\ts++;\n\t\t\tcontinue;\n\t\t}\n\t\t// skip stuff that only the QuakeEdRadient needs\n\t\telse if ( !Q_stricmpn( token, \"qer\", 3 ) ) {\n\t\t\tSkipRestOfLine( text );\n\t\t\tcontinue;\n\t\t}\n\t\t// sun parms\n\t\telse if ( !Q_stricmp( token, \"q3map_sun\" ) ) {\n\t\t\tfloat\ta, b;\n\n\t\t\ttoken = COM_ParseExt( text, qfalse );\n\t\t\ttr.sunLight[0] = atof( token );\n\t\t\ttoken = COM_ParseExt( text, qfalse );\n\t\t\ttr.sunLight[1] = atof( token );\n\t\t\ttoken = COM_ParseExt( text, qfalse );\n\t\t\ttr.sunLight[2] = atof( token );\n\t\t\t\n\t\t\tVectorNormalize( tr.sunLight );\n\n\t\t\ttoken = COM_ParseExt( text, qfalse );\n\t\t\ta = atof( token );\n\t\t\tVectorScale( tr.sunLight, a, tr.sunLight);\n\n\t\t\ttoken = COM_ParseExt( text, qfalse );\n\t\t\ta = atof( token );\n\t\t\ta = a / 180 * M_PI;\n\n\t\t\ttoken = COM_ParseExt( text, qfalse );\n\t\t\tb = atof( token );\n\t\t\tb = b / 180 * M_PI;\n\n\t\t\ttr.sunDirection[0] = cos( a ) * cos( b );\n\t\t\ttr.sunDirection[1] = sin( a ) * cos( b );\n\t\t\ttr.sunDirection[2] = sin( b );\n\t\t}\n\t\telse if ( !Q_stricmp( token, \"deformVertexes\" ) ) {\n\t\t\tParseDeform( text );\n\t\t\tcontinue;\n\t\t}\n\t\telse if ( !Q_stricmp( token, \"tesssize\" ) ) {\n\t\t\tSkipRestOfLine( text );\n\t\t\tcontinue;\n\t\t}\n\t\telse if ( !Q_stricmp( token, \"clampTime\" ) ) {\n\t\t\ttoken = COM_ParseExt( text, qfalse );\n      if (token[0]) {\n        shader.clampTime = atof(token);\n      }\n    }\n\t\t// skip stuff that only the q3map needs\n\t\telse if ( !Q_stricmpn( token, \"q3map\", 5 ) ) {\n\t\t\tSkipRestOfLine( text );\n\t\t\tcontinue;\n\t\t}\n\t\t// skip stuff that only q3map or the server needs\n\t\telse if ( !Q_stricmp( token, \"surfaceParm\" ) ) {\n\t\t\tParseSurfaceParm( text );\n\t\t\tcontinue;\n\t\t}\n\t\t// no mip maps\n\t\telse if ( !Q_stricmp( token, \"nomipmaps\" ) )\n\t\t{\n\t\t\tshader.noMipMaps = qtrue;\n\t\t\tshader.noPicMip = qtrue;\n\t\t\tcontinue;\n\t\t}\n\t\t// no picmip adjustment\n\t\telse if ( !Q_stricmp( token, \"nopicmip\" ) )\n\t\t{\n\t\t\tshader.noPicMip = qtrue;\n\t\t\tcontinue;\n\t\t}\n\t\t// polygonOffset\n\t\telse if ( !Q_stricmp( token, \"polygonOffset\" ) )\n\t\t{\n\t\t\tshader.polygonOffset = qtrue;\n\t\t\tcontinue;\n\t\t}\n\t\t// entityMergable, allowing sprite surfaces from multiple entities\n\t\t// to be merged into one batch.  This is a savings for smoke\n\t\t// puffs and blood, but can't be used for anything where the\n\t\t// shader calcs (not the surface function) reference the entity color or scroll\n\t\telse if ( !Q_stricmp( token, \"entityMergable\" ) )\n\t\t{\n\t\t\tshader.entityMergable = qtrue;\n\t\t\tcontinue;\n\t\t}\n\t\t// fogParms\n\t\telse if ( !Q_stricmp( token, \"fogParms\" ) ) \n\t\t{\n\t\t\tif ( !ParseVector( text, 3, shader.fogParms.color ) ) {\n\t\t\t\treturn qfalse;\n\t\t\t}\n\n\t\t\ttoken = COM_ParseExt( text, qfalse );\n\t\t\tif ( !token[0] ) \n\t\t\t{\n\t\t\t\tri.Printf( PRINT_WARNING, \"WARNING: missing parm for 'fogParms' keyword in shader '%s'\\n\", shader.name );\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tshader.fogParms.depthForOpaque = atof( token );\n\n\t\t\t// skip any old gradient directions\n\t\t\tSkipRestOfLine( text );\n\t\t\tcontinue;\n\t\t}\n\t\t// portal\n\t\telse if ( !Q_stricmp(token, \"portal\") )\n\t\t{\n\t\t\tshader.sort = SS_PORTAL;\n\t\t\tcontinue;\n\t\t}\n\t\t// skyparms <cloudheight> <outerbox> <innerbox>\n\t\telse if ( !Q_stricmp( token, \"skyparms\" ) )\n\t\t{\n\t\t\tParseSkyParms( text );\n\t\t\tcontinue;\n\t\t}\n\t\t// light <value> determines flaring in q3map, not needed here\n\t\telse if ( !Q_stricmp(token, \"light\") ) \n\t\t{\n\t\t\ttoken = COM_ParseExt( text, qfalse );\n\t\t\tcontinue;\n\t\t}\n\t\t// cull <face>\n\t\telse if ( !Q_stricmp( token, \"cull\") ) \n\t\t{\n\t\t\ttoken = COM_ParseExt( text, qfalse );\n\t\t\tif ( token[0] == 0 )\n\t\t\t{\n\t\t\t\tri.Printf( PRINT_WARNING, \"WARNING: missing cull parms in shader '%s'\\n\", shader.name );\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif ( !Q_stricmp( token, \"none\" ) || !Q_stricmp( token, \"twosided\" ) || !Q_stricmp( token, \"disable\" ) )\n\t\t\t{\n\t\t\t\tshader.cullType = CT_TWO_SIDED;\n\t\t\t}\n\t\t\telse if ( !Q_stricmp( token, \"back\" ) || !Q_stricmp( token, \"backside\" ) || !Q_stricmp( token, \"backsided\" ) )\n\t\t\t{\n\t\t\t\tshader.cullType = CT_BACK_SIDED;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tri.Printf( PRINT_WARNING, \"WARNING: invalid cull parm '%s' in shader '%s'\\n\", token, shader.name );\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\t// sort\n\t\telse if ( !Q_stricmp( token, \"sort\" ) )\n\t\t{\n\t\t\tParseSort( text );\n\t\t\tcontinue;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tri.Printf( PRINT_WARNING, \"WARNING: unknown general shader parameter '%s' in '%s'\\n\", token, shader.name );\n\t\t\treturn qfalse;\n\t\t}\n\t}\n\n\t//\n\t// ignore shaders that don't have any stages, unless it is a sky or fog\n\t//\n\tif ( s == 0 && !shader.isSky && !(shader.contentFlags & CONTENTS_FOG ) ) {\n\t\treturn qfalse;\n\t}\n\n\tshader.explicitlyDefined = qtrue;\n\n\treturn qtrue;\n}\n\n/*\n========================================================================================\n\nSHADER OPTIMIZATION AND FOGGING\n\n========================================================================================\n*/\n\ntypedef struct {\n\tint\t\tblendA;\n\tint\t\tblendB;\n\n\tint\t\tmultitextureEnv;\n\tint\t\tmultitextureBlend;\n} collapse_t;\n\nstatic collapse_t\tcollapse[] = {\n\t{ 0, GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO,\t\n\t\tGL_MODULATE, 0 },\n\n\t{ 0, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR,\n\t\tGL_MODULATE, 0 },\n\n\t{ GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR,\n\t\tGL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR },\n\n\t{ GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR,\n\t\tGL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR },\n\n\t{ GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR, GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO,\n\t\tGL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR },\n\n\t{ GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO, GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO,\n\t\tGL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR },\n\n\t{ 0, GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE,\n\t\tGL_ADD, 0 },\n\n\t{ GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE, GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE,\n\t\tGL_ADD, GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE },\n\n\t{ -1 }\n};\n\n/*\n================\nCollapseMultitexture\n\nAttempt to combine two stages into a single multitexture stage\nFIXME: I think modulated add + modulated add collapses incorrectly\n=================\n*/\nstatic qboolean CollapseMultitexture( void ) {\n\tint abits, bbits;\n\tint i;\n\ttextureBundle_t tmpBundle;\n\n\t// make sure both stages are active\n\tif ( !stages[0].active || !stages[1].active ) {\n\t\treturn qfalse;\n\t}\n\n\tabits = stages[0].stateBits;\n\tbbits = stages[1].stateBits;\n\n\t// make sure that both stages have identical state other than blend modes\n\tif ( ( abits & ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS | GLS_DEPTHMASK_TRUE ) ) !=\n\t\t( bbits & ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS | GLS_DEPTHMASK_TRUE ) ) ) {\n\t\treturn qfalse;\n\t}\n\n\tabits &= ( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS );\n\tbbits &= ( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS );\n\n\t// search for a valid multitexture blend function\n\tfor ( i = 0; collapse[i].blendA != -1 ; i++ ) {\n\t\tif ( abits == collapse[i].blendA\n\t\t\t&& bbits == collapse[i].blendB ) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// nothing found\n\tif ( collapse[i].blendA == -1 ) {\n\t\treturn qfalse;\n\t}\n\n\t// GL_ADD is a separate extension\n\tif ( collapse[i].multitextureEnv == GL_ADD && !glConfig.textureEnvAddAvailable ) {\n\t\treturn qfalse;\n\t}\n\n\t// make sure waveforms have identical parameters\n\tif ( ( stages[0].rgbGen != stages[1].rgbGen ) ||\n\t\t( stages[0].alphaGen != stages[1].alphaGen ) )  {\n\t\treturn qfalse;\n\t}\n\n\t// an add collapse can only have identity colors\n\tif ( collapse[i].multitextureEnv == GL_ADD && stages[0].rgbGen != CGEN_IDENTITY ) {\n\t\treturn qfalse;\n\t}\n\n\tif ( stages[0].rgbGen == CGEN_WAVEFORM )\n\t{\n\t\tif ( memcmp( &stages[0].rgbWave,\n\t\t\t\t\t &stages[1].rgbWave,\n\t\t\t\t\t sizeof( stages[0].rgbWave ) ) )\n\t\t{\n\t\t\treturn qfalse;\n\t\t}\n\t}\n\tif ( stages[0].alphaGen == CGEN_WAVEFORM )\n\t{\n\t\tif ( memcmp( &stages[0].alphaWave,\n\t\t\t\t\t &stages[1].alphaWave,\n\t\t\t\t\t sizeof( stages[0].alphaWave ) ) )\n\t\t{\n\t\t\treturn qfalse;\n\t\t}\n\t}\n\n\n\t// make sure that lightmaps are in bundle 1 for 3dfx\n\tif ( stages[0].bundle[0].isLightmap )\n\t{\n\t\ttmpBundle = stages[0].bundle[0];\n\t\tstages[0].bundle[0] = stages[1].bundle[0];\n\t\tstages[0].bundle[1] = tmpBundle;\n\t}\n\telse\n\t{\n\t\tstages[0].bundle[1] = stages[1].bundle[0];\n\t}\n\n\t// set the new blend state bits\n\tshader.multitextureEnv = collapse[i].multitextureEnv;\n\tstages[0].stateBits &= ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS );\n\tstages[0].stateBits |= collapse[i].multitextureBlend;\n\n\t//\n\t// move down subsequent shaders\n\t//\n\tmemmove( &stages[1], &stages[2], sizeof( stages[0] ) * ( MAX_SHADER_STAGES - 2 ) );\n\tCom_Memset( &stages[MAX_SHADER_STAGES-1], 0, sizeof( stages[0] ) );\n\n\treturn qtrue;\n}\n\n/*\n=============\n\nFixRenderCommandList\nhttps://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=493\nArnout: this is a nasty issue. Shaders can be registered after drawsurfaces are generated\nbut before the frame is rendered. This will, for the duration of one frame, cause drawsurfaces\nto be rendered with bad shaders. To fix this, need to go through all render commands and fix\nsortedIndex.\n==============\n*/\nstatic void FixRenderCommandList( int newShader ) {\n\trenderCommandList_t\t*cmdList = &backEndData[tr.smpFrame]->commands;\n\n\tif( cmdList ) {\n\t\tconst void *curCmd = cmdList->cmds;\n\n\t\twhile ( 1 ) {\n\t\t\tswitch ( *(const int *)curCmd ) {\n\t\t\tcase RC_SET_COLOR:\n\t\t\t\t{\n\t\t\t\tconst setColorCommand_t *sc_cmd = (const setColorCommand_t *)curCmd;\n\t\t\t\tcurCmd = (const void *)(sc_cmd + 1);\n\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\tcase RC_STRETCH_PIC:\n\t\t\t\t{\n\t\t\t\tconst stretchPicCommand_t *sp_cmd = (const stretchPicCommand_t *)curCmd;\n\t\t\t\tcurCmd = (const void *)(sp_cmd + 1);\n\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\tcase RC_DRAW_SURFS:\n\t\t\t\t{\n\t\t\t\tint i;\n\t\t\t\tdrawSurf_t\t*drawSurf;\n\t\t\t\tshader_t\t*shader;\n\t\t\t\tint\t\t\tfogNum;\n\t\t\t\tint\t\t\tentityNum;\n\t\t\t\tint\t\t\tdlightMap;\n\t\t\t\tint\t\t\tsortedIndex;\n\t\t\t\tconst drawSurfsCommand_t *ds_cmd =  (const drawSurfsCommand_t *)curCmd;\n\n\t\t\t\tfor( i = 0, drawSurf = ds_cmd->drawSurfs; i < ds_cmd->numDrawSurfs; i++, drawSurf++ ) {\n\t\t\t\t\tR_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlightMap );\n                    sortedIndex = (( drawSurf->sort >> QSORT_SHADERNUM_SHIFT ) & (MAX_SHADERS-1));\n\t\t\t\t\tif( sortedIndex >= newShader ) {\n\t\t\t\t\t\tsortedIndex++;\n\t\t\t\t\t\tdrawSurf->sort = (sortedIndex << QSORT_SHADERNUM_SHIFT) | entityNum | ( fogNum << QSORT_FOGNUM_SHIFT ) | (int)dlightMap;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcurCmd = (const void *)(ds_cmd + 1);\n\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\tcase RC_DRAW_BUFFER:\n\t\t\t\t{\n\t\t\t\tconst drawBufferCommand_t *db_cmd = (const drawBufferCommand_t *)curCmd;\n\t\t\t\tcurCmd = (const void *)(db_cmd + 1);\n\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\tcase RC_SWAP_BUFFERS:\n\t\t\t\t{\n\t\t\t\tconst swapBuffersCommand_t *sb_cmd = (const swapBuffersCommand_t *)curCmd;\n\t\t\t\tcurCmd = (const void *)(sb_cmd + 1);\n\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\tcase RC_END_OF_LIST:\n\t\t\tdefault:\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n}\n\n/*\n==============\nSortNewShader\n\nPositions the most recently created shader in the tr.sortedShaders[]\narray so that the shader->sort key is sorted reletive to the other\nshaders.\n\nSets shader->sortedIndex\n==============\n*/\nstatic void SortNewShader( void ) {\n\tint\t\ti;\n\tfloat\tsort;\n\tshader_t\t*newShader;\n\n\tnewShader = tr.shaders[ tr.numShaders - 1 ];\n\tsort = newShader->sort;\n\n\tfor ( i = tr.numShaders - 2 ; i >= 0 ; i-- ) {\n\t\tif ( tr.sortedShaders[ i ]->sort <= sort ) {\n\t\t\tbreak;\n\t\t}\n\t\ttr.sortedShaders[i+1] = tr.sortedShaders[i];\n\t\ttr.sortedShaders[i+1]->sortedIndex++;\n\t}\n\n\t// Arnout: fix rendercommandlist\n\t// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=493\n\tFixRenderCommandList( i+1 );\n\n\tnewShader->sortedIndex = i+1;\n\ttr.sortedShaders[i+1] = newShader;\n}\n\n\n/*\n====================\nGeneratePermanentShader\n====================\n*/\nstatic shader_t *GeneratePermanentShader( void ) {\n\tshader_t\t*newShader;\n\tint\t\t\ti, b;\n\tint\t\t\tsize, hash;\n\n\tif ( tr.numShaders == MAX_SHADERS ) {\n\t\tri.Printf( PRINT_WARNING, \"WARNING: GeneratePermanentShader - MAX_SHADERS hit\\n\");\n\t\treturn tr.defaultShader;\n\t}\n\n\tnewShader = (shader_t*) ri.Hunk_Alloc( sizeof( shader_t ), h_low );\n\n\t*newShader = shader;\n\n\tif ( shader.sort <= SS_OPAQUE ) {\n\t\tnewShader->fogPass = FP_EQUAL;\n\t} else if ( shader.contentFlags & CONTENTS_FOG ) {\n\t\tnewShader->fogPass = FP_LE;\n\t}\n\n\ttr.shaders[ tr.numShaders ] = newShader;\n\tnewShader->index = tr.numShaders;\n\t\n\ttr.sortedShaders[ tr.numShaders ] = newShader;\n\tnewShader->sortedIndex = tr.numShaders;\n\n\ttr.numShaders++;\n\n\tfor ( i = 0 ; i < newShader->numUnfoggedPasses ; i++ ) {\n\t\tif ( !stages[i].active ) {\n\t\t\tbreak;\n\t\t}\n\t\tnewShader->stages[i] = (shaderStage_t*) ri.Hunk_Alloc( sizeof( stages[i] ), h_low );\n\t\t*newShader->stages[i] = stages[i];\n\n\t\tfor ( b = 0 ; b < NUM_TEXTURE_BUNDLES ; b++ ) {\n\t\t\tsize = newShader->stages[i]->bundle[b].numTexMods * sizeof( texModInfo_t );\n\t\t\tnewShader->stages[i]->bundle[b].texMods = (texModInfo_t*) ri.Hunk_Alloc( size, h_low );\n\t\t\tCom_Memcpy( newShader->stages[i]->bundle[b].texMods, stages[i].bundle[b].texMods, size );\n\t\t}\n\t}\n\n\tSortNewShader();\n\n\thash = generateHashValue(newShader->name, FILE_HASH_SIZE);\n\tnewShader->next = hashTable[hash];\n\thashTable[hash] = newShader;\n\n\treturn newShader;\n}\n\n/*\n=================\nVertexLightingCollapse\n\nIf vertex lighting is enabled, only render a single\npass, trying to guess which is the correct one to best aproximate\nwhat it is supposed to look like.\n=================\n*/\nstatic void VertexLightingCollapse( void ) {\n\tint\t\tstage;\n\tshaderStage_t\t*bestStage;\n\tint\t\tbestImageRank;\n\tint\t\trank;\n\n\t// if we aren't opaque, just use the first pass\n\tif ( shader.sort == SS_OPAQUE ) {\n\n\t\t// pick the best texture for the single pass\n\t\tbestStage = &stages[0];\n\t\tbestImageRank = -999999;\n\n\t\tfor ( stage = 0; stage < MAX_SHADER_STAGES; stage++ ) {\n\t\t\tshaderStage_t *pStage = &stages[stage];\n\n\t\t\tif ( !pStage->active ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\trank = 0;\n\n\t\t\tif ( pStage->bundle[0].isLightmap ) {\n\t\t\t\trank -= 100;\n\t\t\t}\n\t\t\tif ( pStage->bundle[0].tcGen != TCGEN_TEXTURE ) {\n\t\t\t\trank -= 5;\n\t\t\t}\n\t\t\tif ( pStage->bundle[0].numTexMods ) {\n\t\t\t\trank -= 5;\n\t\t\t}\n\t\t\tif ( pStage->rgbGen != CGEN_IDENTITY && pStage->rgbGen != CGEN_IDENTITY_LIGHTING ) {\n\t\t\t\trank -= 3;\n\t\t\t}\n\n\t\t\tif ( rank > bestImageRank  ) {\n\t\t\t\tbestImageRank = rank;\n\t\t\t\tbestStage = pStage;\n\t\t\t}\n\t\t}\n\n\t\tstages[0].bundle[0] = bestStage->bundle[0];\n\t\tstages[0].stateBits &= ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS );\n\t\tstages[0].stateBits |= GLS_DEPTHMASK_TRUE;\n\t\tif ( shader.lightmapIndex == LIGHTMAP_NONE ) {\n\t\t\tstages[0].rgbGen = CGEN_LIGHTING_DIFFUSE;\n\t\t} else {\n\t\t\tstages[0].rgbGen = CGEN_EXACT_VERTEX;\n\t\t}\n\t\tstages[0].alphaGen = AGEN_SKIP;\t\t\n\t} else {\n\t\t// don't use a lightmap (tesla coils)\n\t\tif ( stages[0].bundle[0].isLightmap ) {\n\t\t\tstages[0] = stages[1];\n\t\t}\n\n\t\t// if we were in a cross-fade cgen, hack it to normal\n\t\tif ( stages[0].rgbGen == CGEN_ONE_MINUS_ENTITY || stages[1].rgbGen == CGEN_ONE_MINUS_ENTITY ) {\n\t\t\tstages[0].rgbGen = CGEN_IDENTITY_LIGHTING;\n\t\t}\n\t\tif ( ( stages[0].rgbGen == CGEN_WAVEFORM && stages[0].rgbWave.func == GF_SAWTOOTH )\n\t\t\t&& ( stages[1].rgbGen == CGEN_WAVEFORM && stages[1].rgbWave.func == GF_INVERSE_SAWTOOTH ) ) {\n\t\t\tstages[0].rgbGen = CGEN_IDENTITY_LIGHTING;\n\t\t}\n\t\tif ( ( stages[0].rgbGen == CGEN_WAVEFORM && stages[0].rgbWave.func == GF_INVERSE_SAWTOOTH )\n\t\t\t&& ( stages[1].rgbGen == CGEN_WAVEFORM && stages[1].rgbWave.func == GF_SAWTOOTH ) ) {\n\t\t\tstages[0].rgbGen = CGEN_IDENTITY_LIGHTING;\n\t\t}\n\t}\n\n\tfor ( stage = 1; stage < MAX_SHADER_STAGES; stage++ ) {\n\t\tshaderStage_t *pStage = &stages[stage];\n\n\t\tif ( !pStage->active ) {\n\t\t\tbreak;\n\t\t}\n\n\t\tCom_Memset( pStage, 0, sizeof( *pStage ) );\n\t}\n}\n\n/*\n=========================\nFinishShader\n\nReturns a freshly allocated shader with all the needed info\nfrom the current global working shader\n=========================\n*/\nstatic shader_t *FinishShader( void ) {\n\tint stage;\n\tqboolean\t\thasLightmapStage;\n\n\thasLightmapStage = qfalse;\n\n\t//\n\t// set sky stuff appropriate\n\t//\n\tif ( shader.isSky ) {\n\t\tshader.sort = SS_ENVIRONMENT;\n\t}\n\n\t//\n\t// set polygon offset\n\t//\n\tif ( shader.polygonOffset && !shader.sort ) {\n\t\tshader.sort = SS_DECAL;\n\t}\n\n\t//\n\t// set appropriate stage information\n\t//\n\tfor ( stage = 0; stage < MAX_SHADER_STAGES; stage++ ) {\n\t\tshaderStage_t *pStage = &stages[stage];\n\n\t\tif ( !pStage->active ) {\n\t\t\tbreak;\n\t\t}\n\n    // check for a missing texture\n\t\tif ( !pStage->bundle[0].image[0] ) {\n\t\t\tri.Printf( PRINT_WARNING, \"Shader %s has a stage with no image\\n\", shader.name );\n\t\t\tpStage->active = qfalse;\n\t\t\tcontinue;\n\t\t}\n\n\t\t//\n\t\t// ditch this stage if it's detail and detail textures are disabled\n\t\t//\n\t\tif ( pStage->isDetail && !r_detailTextures->integer ) {\n\t\t\tif ( stage < ( MAX_SHADER_STAGES - 1 ) ) {\n\t\t\t\tmemmove( pStage, pStage + 1, sizeof( *pStage ) * ( MAX_SHADER_STAGES - stage - 1 ) );\n\t\t\t\tCom_Memset(  pStage + 1, 0, sizeof( *pStage ) );\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\t//\n\t\t// default texture coordinate generation\n\t\t//\n\t\tif ( pStage->bundle[0].isLightmap ) {\n\t\t\tif ( pStage->bundle[0].tcGen == TCGEN_BAD ) {\n\t\t\t\tpStage->bundle[0].tcGen = TCGEN_LIGHTMAP;\n\t\t\t}\n\t\t\thasLightmapStage = qtrue;\n\t\t} else {\n\t\t\tif ( pStage->bundle[0].tcGen == TCGEN_BAD ) {\n\t\t\t\tpStage->bundle[0].tcGen = TCGEN_TEXTURE;\n\t\t\t}\n\t\t}\n\n\t\t//\n\t\t// determine sort order and fog color adjustment\n\t\t//\n\t\tif ( ( pStage->stateBits & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) &&\n\t\t\t ( stages[0].stateBits & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) ) {\n\t\t\tint blendSrcBits = pStage->stateBits & GLS_SRCBLEND_BITS;\n\t\t\tint blendDstBits = pStage->stateBits & GLS_DSTBLEND_BITS;\n\n\t\t\t// fog color adjustment only works for blend modes that have a contribution\n\t\t\t// that aproaches 0 as the modulate values aproach 0 --\n\t\t\t// GL_ONE, GL_ONE\n\t\t\t// GL_ZERO, GL_ONE_MINUS_SRC_COLOR\n\t\t\t// GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA\n\n\t\t\t// modulate, additive\n\t\t\tif ( ( ( blendSrcBits == GLS_SRCBLEND_ONE ) && ( blendDstBits == GLS_DSTBLEND_ONE ) ) ||\n\t\t\t\t( ( blendSrcBits == GLS_SRCBLEND_ZERO ) && ( blendDstBits == GLS_DSTBLEND_ONE_MINUS_SRC_COLOR ) ) ) {\n\t\t\t\tpStage->adjustColorsForFog = ACFF_MODULATE_RGB;\n\t\t\t}\n\t\t\t// strict blend\n\t\t\telse if ( ( blendSrcBits == GLS_SRCBLEND_SRC_ALPHA ) && ( blendDstBits == GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ) )\n\t\t\t{\n\t\t\t\tpStage->adjustColorsForFog = ACFF_MODULATE_ALPHA;\n\t\t\t}\n\t\t\t// premultiplied alpha\n\t\t\telse if ( ( blendSrcBits == GLS_SRCBLEND_ONE ) && ( blendDstBits == GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ) )\n\t\t\t{\n\t\t\t\tpStage->adjustColorsForFog = ACFF_MODULATE_RGBA;\n\t\t\t} else {\n\t\t\t\t// we can't adjust this one correctly, so it won't be exactly correct in fog\n\t\t\t}\n\n\t\t\t// don't screw with sort order if this is a portal or environment\n\t\t\tif ( !shader.sort ) {\n\t\t\t\t// see through item, like a grill or grate\n\t\t\t\tif ( pStage->stateBits & GLS_DEPTHMASK_TRUE ) {\n\t\t\t\t\tshader.sort = SS_SEE_THROUGH;\n\t\t\t\t} else {\n\t\t\t\t\tshader.sort = SS_BLEND0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// there are times when you will need to manually apply a sort to\n\t// opaque alpha tested shaders that have later blend passes\n\tif ( !shader.sort ) {\n\t\tshader.sort = SS_OPAQUE;\n\t}\n\n\t//\n\t// if we are in r_vertexLight mode, never use a lightmap texture\n\t//\n\tif ( stage > 1 && ( r_vertexLight->integer && !r_uiFullScreen->integer ) ) {\n\t\tVertexLightingCollapse();\n\t\tstage = 1;\n\t\thasLightmapStage = qfalse;\n\t}\n\n\t//\n\t// look for multitexture potential\n\t//\n\tif ( stage > 1 && CollapseMultitexture() ) {\n\t\tstage--;\n\t}\n\n\tif ( shader.lightmapIndex >= 0 && !hasLightmapStage ) {\n\t\tri.Printf( PRINT_DEVELOPER, \"WARNING: shader '%s' has lightmap but no lightmap stage!\\n\", shader.name );\n  \t\tshader.lightmapIndex = LIGHTMAP_NONE;\n\t}\n\n\n\t//\n\t// compute number of passes\n\t//\n\tshader.numUnfoggedPasses = stage;\n\n\t// fogonly shaders don't have any normal passes\n\tif ( stage == 0 ) {\n\t\tshader.sort = SS_FOG;\n\t}\n\n\t// VULKAN: create pipelines for each shader stage\n\t// DX12\n\tif (vk.active || dx.active) {\n\t\tVk_Pipeline_Def def;\n\t\tdef.face_culling = shader.cullType;\n\t\tdef.polygon_offset = (shader.polygonOffset == qtrue);\n\n\t\tfor (int i = 0; i < stage; i++) {\n\t\t\tshaderStage_t *pStage = &stages[i];\n\t\t\tdef.state_bits = pStage->stateBits;\n\n\t\t\tif (pStage->bundle[1].image[0] == nullptr)\n\t\t\t\tdef.shader_type = Vk_Shader_Type::single_texture;\n\t\t\telse if (shader.multitextureEnv == GL_MODULATE)\n\t\t\t\tdef.shader_type = Vk_Shader_Type::multi_texture_mul;\n\t\t\telse if (shader.multitextureEnv == GL_ADD)\n\t\t\t\tdef.shader_type = Vk_Shader_Type::multi_texture_add;\n\t\t\telse\n\t\t\t\tri.Error(ERR_FATAL, \"Vulkan: could not create pipelines for q3 shader '%s'\\n\", shader.name);\n\n\t\t\tdef.clipping_plane = false;\n\t\t\tdef.mirror = false;\n\t\t\tif (vk.active)\n\t\t\t\tpStage->vk_pipeline = vk_find_pipeline(def);\n\t\t\tif (dx.active)\n\t\t\t\tpStage->dx_pipeline = dx_find_pipeline(def);\n\n\t\t\tdef.clipping_plane = true;\n\t\t\tdef.mirror = false;\n\t\t\tif (vk.active)\n\t\t\t\tpStage->vk_portal_pipeline = vk_find_pipeline(def);\n\t\t\tif (dx.active)\n\t\t\t\tpStage->dx_portal_pipeline = dx_find_pipeline(def);\n\n\t\t\tdef.clipping_plane = true;\n\t\t\tdef.mirror = true;\n\t\t\tif (vk.active)\n\t\t\t\tpStage->vk_mirror_pipeline = vk_find_pipeline(def);\n\t\t\tif (dx.active)\n\t\t\t\tpStage->dx_mirror_pipeline = dx_find_pipeline(def);\n\t\t}\n\t}\n\n\treturn GeneratePermanentShader();\n}\n\n//========================================================================================\n\n/*\n====================\nFindShaderInShaderText\n\nScans the combined text description of all the shader files for\nthe given shader name.\n\nreturn NULL if not found\n\nIf found, it will return a valid shader\n=====================\n*/\nstatic char *FindShaderInShaderText( const char *shadername ) {\n\n\tchar *token, *p;\n\n\tint i, hash;\n\n\thash = generateHashValue(shadername, MAX_SHADERTEXT_HASH);\n\n\tfor (i = 0; shaderTextHashTable[hash][i]; i++) {\n\t\tp = shaderTextHashTable[hash][i];\n\t\ttoken = COM_ParseExt(&p, qtrue);\n\t\tif ( !Q_stricmp( token, shadername ) ) {\n\t\t\treturn p;\n\t\t}\n\t}\n\n\tp = s_shaderText;\n\n\tif ( !p ) {\n\t\treturn NULL;\n\t}\n\n\t// look for label\n\twhile ( 1 ) {\n\t\ttoken = COM_ParseExt( &p, qtrue );\n\t\tif ( token[0] == 0 ) {\n\t\t\tbreak;\n\t\t}\n\n\t\tif ( !Q_stricmp( token, shadername ) ) {\n\t\t\treturn p;\n\t\t}\n\t\telse {\n\t\t\t// skip the definition\n\t\t\tSkipBracedSection( &p );\n\t\t}\n\t}\n\n\treturn NULL;\n}\n\n\n/*\n==================\nR_FindShaderByName\n\nWill always return a valid shader, but it might be the\ndefault shader if the real one can't be found.\n==================\n*/\nshader_t *R_FindShaderByName( const char *name ) {\n\tchar\t\tstrippedName[MAX_QPATH];\n\tint\t\t\thash;\n\tshader_t\t*sh;\n\n\tif ( (name==NULL) || (name[0] == 0) ) {  // bk001205\n\t\treturn tr.defaultShader;\n\t}\n\n\tCOM_StripExtension( name, strippedName );\n\n\thash = generateHashValue(strippedName, FILE_HASH_SIZE);\n\n\t//\n\t// see if the shader is already loaded\n\t//\n\tfor (sh=hashTable[hash]; sh; sh=sh->next) {\n\t\t// NOTE: if there was no shader or image available with the name strippedName\n\t\t// then a default shader is created with lightmapIndex == LIGHTMAP_NONE, so we\n\t\t// have to check all default shaders otherwise for every call to R_FindShader\n\t\t// with that same strippedName a new default shader is created.\n\t\tif (Q_stricmp(sh->name, strippedName) == 0) {\n\t\t\t// match found\n\t\t\treturn sh;\n\t\t}\n\t}\n\n\treturn tr.defaultShader;\n}\n\n\n/*\n===============\nR_FindShader\n\nWill always return a valid shader, but it might be the\ndefault shader if the real one can't be found.\n\nIn the interest of not requiring an explicit shader text entry to\nbe defined for every single image used in the game, three default\nshader behaviors can be auto-created for any image:\n\nIf lightmapIndex == LIGHTMAP_NONE, then the image will have\ndynamic diffuse lighting applied to it, as apropriate for most\nentity skin surfaces.\n\nIf lightmapIndex == LIGHTMAP_2D, then the image will be used\nfor 2D rendering unless an explicit shader is found\n\nIf lightmapIndex == LIGHTMAP_BY_VERTEX, then the image will use\nthe vertex rgba modulate values, as apropriate for misc_model\npre-lit surfaces.\n\nOther lightmapIndex values will have a lightmap stage created\nand src*dest blending applied with the texture, as apropriate for\nmost world construction surfaces.\n\n===============\n*/\nshader_t *R_FindShader( const char *name, int lightmapIndex, qboolean mipRawImage ) {\n\tchar\t\tstrippedName[MAX_QPATH];\n\tchar\t\tfileName[MAX_QPATH];\n\tint\t\t\ti, hash;\n\tchar\t\t*shaderText;\n\timage_t\t\t*image;\n\tshader_t\t*sh;\n\n\tif ( name[0] == 0 ) {\n\t\treturn tr.defaultShader;\n\t}\n\n\t// use (fullbright) vertex lighting if the bsp file doesn't have\n\t// lightmaps\n\tif ( lightmapIndex >= 0 && lightmapIndex >= tr.numLightmaps ) {\n\t\tlightmapIndex = LIGHTMAP_BY_VERTEX;\n\t}\n\n\tCOM_StripExtension( name, strippedName );\n\n\thash = generateHashValue(strippedName, FILE_HASH_SIZE);\n\n\t//\n\t// see if the shader is already loaded\n\t//\n\tfor (sh = hashTable[hash]; sh; sh = sh->next) {\n\t\t// NOTE: if there was no shader or image available with the name strippedName\n\t\t// then a default shader is created with lightmapIndex == LIGHTMAP_NONE, so we\n\t\t// have to check all default shaders otherwise for every call to R_FindShader\n\t\t// with that same strippedName a new default shader is created.\n\t\tif ( (sh->lightmapIndex == lightmapIndex || sh->defaultShader) &&\n\t\t     !Q_stricmp(sh->name, strippedName)) {\n\t\t\t// match found\n\t\t\treturn sh;\n\t\t}\n\t}\n\n\t// make sure the render thread is stopped, because we are probably\n\t// going to have to upload an image\n\tif (r_smp->integer) {\n\t\tR_SyncRenderThread();\n\t}\n\n\t// clear the global shader\n\tCom_Memset( &shader, 0, sizeof( shader ) );\n\tCom_Memset( &stages, 0, sizeof( stages ) );\n\tQ_strncpyz(shader.name, strippedName, sizeof(shader.name));\n\tshader.lightmapIndex = lightmapIndex;\n\tfor ( i = 0 ; i < MAX_SHADER_STAGES ; i++ ) {\n\t\tstages[i].bundle[0].texMods = texMods[i];\n\t}\n\n\t// FIXME: set these \"need\" values apropriately\n\tshader.needsNormal = qtrue;\n\tshader.needsST1 = qtrue;\n\tshader.needsST2 = qtrue;\n\tshader.needsColor = qtrue;\n\n\t//\n\t// attempt to define shader from an explicit parameter file\n\t//\n\tshaderText = FindShaderInShaderText( strippedName );\n\tif ( shaderText ) {\n\t\t// enable this when building a pak file to get a global list\n\t\t// of all explicit shaders\n\t\tif ( r_printShaders->integer ) {\n\t\t\tri.Printf( PRINT_ALL, \"*SHADER* %s\\n\", name );\n\t\t}\n\n\t\tif ( !ParseShader( &shaderText ) ) {\n\t\t\t// had errors, so use default shader\n\t\t\tshader.defaultShader = qtrue;\n\t\t}\n\t\tsh = FinishShader();\n\t\treturn sh;\n\t}\n\n\n\t//\n\t// if not defined in the in-memory shader descriptions,\n\t// look for a single TGA, BMP, or PCX\n\t//\n\tQ_strncpyz( fileName, name, sizeof( fileName ) );\n\tCOM_DefaultExtension( fileName, sizeof( fileName ), \".tga\" );\n\timage = R_FindImageFile( fileName, mipRawImage, mipRawImage, mipRawImage ? GL_REPEAT : GL_CLAMP );\n\tif ( !image ) {\n\t\tri.Printf( PRINT_DEVELOPER, \"Couldn't find image for shader %s\\n\", name );\n\t\tshader.defaultShader = qtrue;\n\t\treturn FinishShader();\n\t}\n\n\t//\n\t// create the default shading commands\n\t//\n\tif ( shader.lightmapIndex == LIGHTMAP_NONE ) {\n\t\t// dynamic colors at vertexes\n\t\tstages[0].bundle[0].image[0] = image;\n\t\tstages[0].active = qtrue;\n\t\tstages[0].rgbGen = CGEN_LIGHTING_DIFFUSE;\n\t\tstages[0].stateBits = GLS_DEFAULT;\n\t} else if ( shader.lightmapIndex == LIGHTMAP_BY_VERTEX ) {\n\t\t// explicit colors at vertexes\n\t\tstages[0].bundle[0].image[0] = image;\n\t\tstages[0].active = qtrue;\n\t\tstages[0].rgbGen = CGEN_EXACT_VERTEX;\n\t\tstages[0].alphaGen = AGEN_SKIP;\n\t\tstages[0].stateBits = GLS_DEFAULT;\n\t} else if ( shader.lightmapIndex == LIGHTMAP_2D ) {\n\t\t// GUI elements\n\t\tstages[0].bundle[0].image[0] = image;\n\t\tstages[0].active = qtrue;\n\t\tstages[0].rgbGen = CGEN_VERTEX;\n\t\tstages[0].alphaGen = AGEN_VERTEX;\n\t\tstages[0].stateBits = GLS_DEPTHTEST_DISABLE |\n\t\t\t  GLS_SRCBLEND_SRC_ALPHA |\n\t\t\t  GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA;\n\t} else if ( shader.lightmapIndex == LIGHTMAP_WHITEIMAGE ) {\n\t\t// fullbright level\n\t\tstages[0].bundle[0].image[0] = tr.whiteImage;\n\t\tstages[0].active = qtrue;\n\t\tstages[0].rgbGen = CGEN_IDENTITY_LIGHTING;\n\t\tstages[0].stateBits = GLS_DEFAULT;\n\n\t\tstages[1].bundle[0].image[0] = image;\n\t\tstages[1].active = qtrue;\n\t\tstages[1].rgbGen = CGEN_IDENTITY;\n\t\tstages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO;\n\t} else {\n\t\t// two pass lightmap\n\t\tstages[0].bundle[0].image[0] = tr.lightmaps[shader.lightmapIndex];\n\t\tstages[0].bundle[0].isLightmap = qtrue;\n\t\tstages[0].active = qtrue;\n\t\tstages[0].rgbGen = CGEN_IDENTITY;\t// lightmaps are scaled on creation\n\t\t\t\t\t\t\t\t\t\t\t\t\t// for identitylight\n\t\tstages[0].stateBits = GLS_DEFAULT;\n\n\t\tstages[1].bundle[0].image[0] = image;\n\t\tstages[1].active = qtrue;\n\t\tstages[1].rgbGen = CGEN_IDENTITY;\n\t\tstages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO;\n\t}\n\n\treturn FinishShader();\n}\n\n\nqhandle_t RE_RegisterShaderFromImage(const char *name, int lightmapIndex, image_t *image, qboolean mipRawImage) {\n\tint\t\t\ti, hash;\n\tshader_t\t*sh;\n\n\thash = generateHashValue(name, FILE_HASH_SIZE);\n\t\n\t//\n\t// see if the shader is already loaded\n\t//\n\tfor (sh=hashTable[hash]; sh; sh=sh->next) {\n\t\t// NOTE: if there was no shader or image available with the name strippedName\n\t\t// then a default shader is created with lightmapIndex == LIGHTMAP_NONE, so we\n\t\t// have to check all default shaders otherwise for every call to R_FindShader\n\t\t// with that same strippedName a new default shader is created.\n\t\tif ( (sh->lightmapIndex == lightmapIndex || sh->defaultShader) &&\n\t\t\t// index by name\n\t\t\t!Q_stricmp(sh->name, name)) {\n\t\t\t// match found\n\t\t\treturn sh->index;\n\t\t}\n\t}\n\n\t// make sure the render thread is stopped, because we are probably\n\t// going to have to upload an image\n\tif (r_smp->integer) {\n\t\tR_SyncRenderThread();\n\t}\n\n\t// clear the global shader\n\tCom_Memset( &shader, 0, sizeof( shader ) );\n\tCom_Memset( &stages, 0, sizeof( stages ) );\n\tQ_strncpyz(shader.name, name, sizeof(shader.name));\n\tshader.lightmapIndex = lightmapIndex;\n\tfor ( i = 0 ; i < MAX_SHADER_STAGES ; i++ ) {\n\t\tstages[i].bundle[0].texMods = texMods[i];\n\t}\n\n\t// FIXME: set these \"need\" values apropriately\n\tshader.needsNormal = qtrue;\n\tshader.needsST1 = qtrue;\n\tshader.needsST2 = qtrue;\n\tshader.needsColor = qtrue;\n\n\t//\n\t// create the default shading commands\n\t//\n\tif ( shader.lightmapIndex == LIGHTMAP_NONE ) {\n\t\t// dynamic colors at vertexes\n\t\tstages[0].bundle[0].image[0] = image;\n\t\tstages[0].active = qtrue;\n\t\tstages[0].rgbGen = CGEN_LIGHTING_DIFFUSE;\n\t\tstages[0].stateBits = GLS_DEFAULT;\n\t} else if ( shader.lightmapIndex == LIGHTMAP_BY_VERTEX ) {\n\t\t// explicit colors at vertexes\n\t\tstages[0].bundle[0].image[0] = image;\n\t\tstages[0].active = qtrue;\n\t\tstages[0].rgbGen = CGEN_EXACT_VERTEX;\n\t\tstages[0].alphaGen = AGEN_SKIP;\n\t\tstages[0].stateBits = GLS_DEFAULT;\n\t} else if ( shader.lightmapIndex == LIGHTMAP_2D ) {\n\t\t// GUI elements\n\t\tstages[0].bundle[0].image[0] = image;\n\t\tstages[0].active = qtrue;\n\t\tstages[0].rgbGen = CGEN_VERTEX;\n\t\tstages[0].alphaGen = AGEN_VERTEX;\n\t\tstages[0].stateBits = GLS_DEPTHTEST_DISABLE |\n\t\t\t  GLS_SRCBLEND_SRC_ALPHA |\n\t\t\t  GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA;\n\t} else if ( shader.lightmapIndex == LIGHTMAP_WHITEIMAGE ) {\n\t\t// fullbright level\n\t\tstages[0].bundle[0].image[0] = tr.whiteImage;\n\t\tstages[0].active = qtrue;\n\t\tstages[0].rgbGen = CGEN_IDENTITY_LIGHTING;\n\t\tstages[0].stateBits = GLS_DEFAULT;\n\n\t\tstages[1].bundle[0].image[0] = image;\n\t\tstages[1].active = qtrue;\n\t\tstages[1].rgbGen = CGEN_IDENTITY;\n\t\tstages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO;\n\t} else {\n\t\t// two pass lightmap\n\t\tstages[0].bundle[0].image[0] = tr.lightmaps[shader.lightmapIndex];\n\t\tstages[0].bundle[0].isLightmap = qtrue;\n\t\tstages[0].active = qtrue;\n\t\tstages[0].rgbGen = CGEN_IDENTITY;\t// lightmaps are scaled on creation\n\t\t\t\t\t\t\t\t\t\t\t\t\t// for identitylight\n\t\tstages[0].stateBits = GLS_DEFAULT;\n\n\t\tstages[1].bundle[0].image[0] = image;\n\t\tstages[1].active = qtrue;\n\t\tstages[1].rgbGen = CGEN_IDENTITY;\n\t\tstages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO;\n\t}\n\n\tsh = FinishShader();\n  return sh->index; \n}\n\n\n/* \n====================\nRE_RegisterShader\n\nThis is the exported shader entry point for the rest of the system\nIt will always return an index that will be valid.\n\nThis should really only be used for explicit shaders, because there is no\nway to ask for different implicit lighting modes (vertex, lightmap, etc)\n====================\n*/\nqhandle_t RE_RegisterShaderLightMap( const char *name, int lightmapIndex ) {\n\tshader_t\t*sh;\n\n\tif ( (int)strlen( name ) >= MAX_QPATH ) {\n\t\tCom_Printf( \"Shader name exceeds MAX_QPATH\\n\" );\n\t\treturn 0;\n\t}\n\n\tsh = R_FindShader( name, lightmapIndex, qtrue );\n\n\t// we want to return 0 if the shader failed to\n\t// load for some reason, but R_FindShader should\n\t// still keep a name allocated for it, so if\n\t// something calls RE_RegisterShader again with\n\t// the same name, we don't try looking for it again\n\tif ( sh->defaultShader ) {\n\t\treturn 0;\n\t}\n\n\treturn sh->index;\n}\n\n\n/* \n====================\nRE_RegisterShader\n\nThis is the exported shader entry point for the rest of the system\nIt will always return an index that will be valid.\n\nThis should really only be used for explicit shaders, because there is no\nway to ask for different implicit lighting modes (vertex, lightmap, etc)\n====================\n*/\nqhandle_t RE_RegisterShader( const char *name ) {\n\tshader_t\t*sh;\n\n\tif ( (int)strlen( name ) >= MAX_QPATH ) {\n\t\tCom_Printf( \"Shader name exceeds MAX_QPATH\\n\" );\n\t\treturn 0;\n\t}\n\n\tsh = R_FindShader( name, LIGHTMAP_2D, qtrue );\n\n\t// we want to return 0 if the shader failed to\n\t// load for some reason, but R_FindShader should\n\t// still keep a name allocated for it, so if\n\t// something calls RE_RegisterShader again with\n\t// the same name, we don't try looking for it again\n\tif ( sh->defaultShader ) {\n\t\treturn 0;\n\t}\n\n\treturn sh->index;\n}\n\n\n/*\n====================\nRE_RegisterShaderNoMip\n\nFor menu graphics that should never be picmiped\n====================\n*/\nqhandle_t RE_RegisterShaderNoMip( const char *name ) {\n\tshader_t\t*sh;\n\n\tif ( (int)strlen( name ) >= MAX_QPATH ) {\n\t\tCom_Printf( \"Shader name exceeds MAX_QPATH\\n\" );\n\t\treturn 0;\n\t}\n\n\tsh = R_FindShader( name, LIGHTMAP_2D, qfalse );\n\n\t// we want to return 0 if the shader failed to\n\t// load for some reason, but R_FindShader should\n\t// still keep a name allocated for it, so if\n\t// something calls RE_RegisterShader again with\n\t// the same name, we don't try looking for it again\n\tif ( sh->defaultShader ) {\n\t\treturn 0;\n\t}\n\n\treturn sh->index;\n}\n\n\n/*\n====================\nR_GetShaderByHandle\n\nWhen a handle is passed in by another module, this range checks\nit and returns a valid (possibly default) shader_t to be used internally.\n====================\n*/\nshader_t *R_GetShaderByHandle( qhandle_t hShader ) {\n\tif ( hShader < 0 ) {\n\t  ri.Printf( PRINT_WARNING, \"R_GetShaderByHandle: out of range hShader '%d'\\n\", hShader ); // bk: FIXME name\n\t\treturn tr.defaultShader;\n\t}\n\tif ( hShader >= tr.numShaders ) {\n\t\tri.Printf( PRINT_WARNING, \"R_GetShaderByHandle: out of range hShader '%d'\\n\", hShader );\n\t\treturn tr.defaultShader;\n\t}\n\treturn tr.shaders[hShader];\n}\n\n/*\n===============\nR_ShaderList_f\n\nDump information on all valid shaders to the console\nA second parameter will cause it to print in sorted order\n===============\n*/\nvoid\tR_ShaderList_f (void) {\n\tint\t\t\ti;\n\tint\t\t\tcount;\n\tshader_t\t*shader;\n\n\tri.Printf (PRINT_ALL, \"-----------------------\\n\");\n\n\tcount = 0;\n\tfor ( i = 0 ; i < tr.numShaders ; i++ ) {\n\t\tif ( ri.Cmd_Argc() > 1 ) {\n\t\t\tshader = tr.sortedShaders[i];\n\t\t} else {\n\t\t\tshader = tr.shaders[i];\n\t\t}\n\n\t\tri.Printf( PRINT_ALL, \"%i \", shader->numUnfoggedPasses );\n\n\t\tif (shader->lightmapIndex >= 0 ) {\n\t\t\tri.Printf (PRINT_ALL, \"L \");\n\t\t} else {\n\t\t\tri.Printf (PRINT_ALL, \"  \");\n\t\t}\n\t\tif ( shader->multitextureEnv == GL_ADD ) {\n\t\t\tri.Printf( PRINT_ALL, \"MT(a) \" );\n\t\t} else if ( shader->multitextureEnv == GL_MODULATE ) {\n\t\t\tri.Printf( PRINT_ALL, \"MT(m) \" );\n\t\t} else {\n\t\t\tri.Printf( PRINT_ALL, \"      \" );\n\t\t}\n\t\tif ( shader->explicitlyDefined ) {\n\t\t\tri.Printf( PRINT_ALL, \"E \" );\n\t\t} else {\n\t\t\tri.Printf( PRINT_ALL, \"  \" );\n\t\t}\n\n\t\tif ( !shader->isSky ) {\n\t\t\tri.Printf( PRINT_ALL, \"gen \" );\n\t\t} else {\n\t\t\tri.Printf( PRINT_ALL, \"sky \" );\n\t\t}\n\n\t\tif ( shader->defaultShader ) {\n\t\t\tri.Printf (PRINT_ALL,  \": %s (DEFAULTED)\\n\", shader->name);\n\t\t} else {\n\t\t\tri.Printf (PRINT_ALL,  \": %s\\n\", shader->name);\n\t\t}\n\t\tcount++;\n\t}\n\tri.Printf (PRINT_ALL, \"%i total shaders\\n\", count);\n\tri.Printf (PRINT_ALL, \"------------------\\n\");\n}\n\n\n/*\n====================\nScanAndLoadShaderFiles\n\nFinds and loads all .shader files, combining them into\na single large text block that can be scanned for shader names\n=====================\n*/\n#define\tMAX_SHADER_FILES\t4096\nstatic void ScanAndLoadShaderFiles( void )\n{\n\tchar **shaderFiles;\n\tchar *buffers[MAX_SHADER_FILES];\n\tchar *p;\n\tint numShaders;\n\tint i;\n\tchar *oldp, *token, *hashMem;\n\tint shaderTextHashTableSizes[MAX_SHADERTEXT_HASH], hash, size;\n\n\tlong sum = 0;\n\t// scan for shader files\n\tshaderFiles = ri.FS_ListFiles( \"scripts\", \".shader\", &numShaders );\n\n\tif ( !shaderFiles || !numShaders )\n\t{\n\t\tri.Printf( PRINT_WARNING, \"WARNING: no shader files found\\n\" );\n\t\treturn;\n\t}\n\n\tif ( numShaders > MAX_SHADER_FILES ) {\n\t\tnumShaders = MAX_SHADER_FILES;\n\t}\n\n\t// load and parse shader files\n\tfor ( i = 0; i < numShaders; i++ )\n\t{\n\t\tchar filename[MAX_QPATH];\n\n\t\tCom_sprintf( filename, sizeof( filename ), \"scripts/%s\", shaderFiles[i] );\n\t\t// ri.Printf( PRINT_ALL, \"...loading '%s'\\n\", filename );\n\t\tsum += ri.FS_ReadFile( filename, (void **)&buffers[i] );\n\t\tif ( !buffers[i] ) {\n\t\t\tri.Error( ERR_DROP, \"Couldn't load %s\", filename );\n\t\t}\n\t}\n\n\t// build single large buffer\n\ts_shaderText = (char*) ri.Hunk_Alloc( sum + numShaders*2, h_low );\n\n\t// free in reverse order, so the temp files are all dumped\n\tfor ( i = numShaders - 1; i >= 0 ; i-- ) {\n\t\tstrcat( s_shaderText, \"\\n\" );\n\t\tp = &s_shaderText[strlen(s_shaderText)];\n\t\tstrcat( s_shaderText, buffers[i] );\n\t\tri.FS_FreeFile( buffers[i] );\n\t\tbuffers[i] = p;\n\t\tCOM_Compress(p);\n\t}\n\n\t// free up memory\n\tri.FS_FreeFileList( shaderFiles );\n\n\tCom_Memset(shaderTextHashTableSizes, 0, sizeof(shaderTextHashTableSizes));\n\tsize = 0;\n\t//\n\tfor ( i = 0; i < numShaders; i++ ) {\n\t\t// pointer to the first shader file\n\t\tp = buffers[i];\n\t\t// look for label\n\t\twhile ( 1 ) {\n\t\t\ttoken = COM_ParseExt( &p, qtrue );\n\t\t\tif ( token[0] == 0 ) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\thash = generateHashValue(token, MAX_SHADERTEXT_HASH);\n\t\t\tshaderTextHashTableSizes[hash]++;\n\t\t\tsize++;\n\t\t\tSkipBracedSection(&p);\n\t\t\t// if we passed the pointer to the next shader file\n\t\t\tif ( i < numShaders - 1 ) {\n\t\t\t\tif ( p > buffers[i+1] ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsize += MAX_SHADERTEXT_HASH;\n\n\thashMem = (char*) ri.Hunk_Alloc( size * sizeof(char *), h_low );\n\n\tfor (i = 0; i < MAX_SHADERTEXT_HASH; i++) {\n\t\tshaderTextHashTable[i] = (char **) hashMem;\n\t\thashMem = ((char *) hashMem) + ((shaderTextHashTableSizes[i] + 1) * sizeof(char *));\n\t}\n\n\tCom_Memset(shaderTextHashTableSizes, 0, sizeof(shaderTextHashTableSizes));\n\t//\n\tfor ( i = 0; i < numShaders; i++ ) {\n\t\t// pointer to the first shader file\n\t\tp = buffers[i];\n\t\t// look for label\n\t\twhile ( 1 ) {\n\t\t\toldp = p;\n\t\t\ttoken = COM_ParseExt( &p, qtrue );\n\t\t\tif ( token[0] == 0 ) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\thash = generateHashValue(token, MAX_SHADERTEXT_HASH);\n\t\t\tshaderTextHashTable[hash][shaderTextHashTableSizes[hash]++] = oldp;\n\n\t\t\tSkipBracedSection(&p);\n\t\t\t// if we passed the pointer to the next shader file\n\t\t\tif ( i < numShaders - 1 ) {\n\t\t\t\tif ( p > buffers[i+1] ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn;\n\n}\n\n\n/*\n====================\nCreateInternalShaders\n====================\n*/\nstatic void CreateInternalShaders( void ) {\n\ttr.numShaders = 0;\n\n\t// init the default shader\n\tCom_Memset( &shader, 0, sizeof( shader ) );\n\tCom_Memset( &stages, 0, sizeof( stages ) );\n\n\tQ_strncpyz( shader.name, \"<default>\", sizeof( shader.name ) );\n\tshader.lightmapIndex = LIGHTMAP_NONE;\n\n\tstages[0].bundle[0].image[0] = tr.defaultImage;\n\tstages[0].active = qtrue;\n\tstages[0].stateBits = GLS_DEFAULT;\n\n\ttr.defaultShader = FinishShader();\n\n\t// shadow shader is just a marker\n\tQ_strncpyz( shader.name, \"<stencil shadow>\", sizeof( shader.name ) );\n\tshader.sort = SS_STENCIL_SHADOW;\n\n\ttr.shadowShader = FinishShader();\n\n    // cinematic shader\n    Com_Memset( &shader, 0, sizeof( shader ) );\n    Com_Memset( &stages, 0, sizeof( stages ) );\n\n    Q_strncpyz( shader.name, \"<cinematic>\", sizeof( shader.name ) );\n    shader.lightmapIndex = LIGHTMAP_NONE;\n\n    stages[0].bundle[0].image[0] = tr.defaultImage; // will be updated by specific cinematic images\n    stages[0].active = qtrue;\n    stages[0].rgbGen = CGEN_IDENTITY_LIGHTING;\n    stages[0].stateBits = GLS_DEPTHTEST_DISABLE;\n\n    tr.cinematicShader = FinishShader();\n}\n\nstatic void CreateExternalShaders( void ) {\n\ttr.projectionShadowShader = R_FindShader( \"projectionShadow\", LIGHTMAP_NONE, qtrue );\n}\n\n/*\n==================\nR_InitShaders\n==================\n*/\nvoid R_InitShaders( void ) {\n\t//ri.Printf( PRINT_ALL, \"Initializing Shaders\\n\" );\n\n\tCom_Memset(hashTable, 0, sizeof(hashTable));\n\n\tCreateInternalShaders();\n\n\tScanAndLoadShaderFiles();\n\n\tCreateExternalShaders();\n}\n"
  },
  {
    "path": "src/engine/renderer/tr_shadows.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n#include \"tr_local.h\"\n\n\n/*\n\n  for a projection shadow:\n\n  point[x] += light vector * ( z - shadow plane )\n  point[y] +=\n  point[z] = shadow plane\n\n  1 0 light[x] / light[z]\n\n*/\n\ntypedef struct {\n\tint\t\ti2;\n\tint\t\tfacing;\n} edgeDef_t;\n\n#define\tMAX_EDGE_DEFS\t32\n\nstatic\tedgeDef_t\tedgeDefs[SHADER_MAX_VERTEXES][MAX_EDGE_DEFS];\nstatic\tint\t\t\tnumEdgeDefs[SHADER_MAX_VERTEXES];\nstatic\tint\t\t\tfacing[SHADER_MAX_INDEXES/3];\nstatic vec4_t\t\textrudedEdges[SHADER_MAX_VERTEXES * 4];\nstatic int\t\t\tnumExtrudedEdges;\n\nstatic void R_AddEdgeDef( int i1, int i2, int facing ) {\n\tint\t\tc;\n\n\tc = numEdgeDefs[ i1 ];\n\tif ( c == MAX_EDGE_DEFS ) {\n\t\treturn;\t\t// overflow\n\t}\n\tedgeDefs[ i1 ][ c ].i2 = i2;\n\tedgeDefs[ i1 ][ c ].facing = facing;\n\n\tnumEdgeDefs[ i1 ]++;\n}\n\nstatic void R_ExtrudeShadowEdges( void ) {\n\tint\t\ti;\n\tint\t\tc, c2;\n\tint\t\tj, k;\n\tint\t\ti2;\n\n\tnumExtrudedEdges = 0;\n\n\t// an edge is NOT a silhouette edge if its face doesn't face the light,\n\t// or if it has a reverse paired edge that also faces the light.\n\t// A well behaved polyhedron would have exactly two faces for each edge,\n\t// but lots of models have dangling edges or overfanned edges\n\tfor ( i = 0 ; i < tess.numVertexes ; i++ ) {\n\t\tc = numEdgeDefs[ i ];\n\t\tfor ( j = 0 ; j < c ; j++ ) {\n\t\t\tif ( !edgeDefs[ i ][ j ].facing ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tbool sil_edge = true;\n\t\t\ti2 = edgeDefs[ i ][ j ].i2;\n\t\t\tc2 = numEdgeDefs[ i2 ];\n\t\t\tfor ( k = 0 ; k < c2 ; k++ ) {\n\t\t\t\tif ( edgeDefs[ i2 ][ k ].i2 == i && edgeDefs[ i2 ][ k ].facing) {\n\t\t\t\t\tsil_edge = false;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// if it doesn't share the edge with another front facing\n\t\t\t// triangle, it is a sil edge\n\t\t\tif ( sil_edge ) {\n\t\t\t\tVectorCopy(tess.xyz[ i ],\t\t\t\t\t\textrudedEdges[numExtrudedEdges * 4 + 0]);\n\t\t\t\tVectorCopy(tess.xyz[ i + tess.numVertexes ],\textrudedEdges[numExtrudedEdges * 4 + 1]);\n\t\t\t\tVectorCopy(tess.xyz[ i2 ],\t\t\t\t\t\textrudedEdges[numExtrudedEdges * 4 + 2]);\n\t\t\t\tVectorCopy(tess.xyz[ i2 + tess.numVertexes ],\textrudedEdges[numExtrudedEdges * 4 + 3]);\n\t\t\t\tnumExtrudedEdges++;\n\t\t\t}\n\t\t}\n\t}\n}\n\nstatic void R_GL_RenderShadowEdges() {\n\tqglBegin( GL_QUADS);\n\tfor (int i = 0; i < numExtrudedEdges; i++) {\n\t\tqglVertex3fv(extrudedEdges[i*4 + 0]);\n\t\tqglVertex3fv(extrudedEdges[i*4 + 1]);\n\t\tqglVertex3fv(extrudedEdges[i*4 + 3]);\n\t\tqglVertex3fv(extrudedEdges[i*4 + 2]);\n\t}\n\tqglEnd();\n}\n\n// VULKAN\n// DX12\nstatic void R_Vk_Dx_RenderShadowEdges(VkPipeline vk_pipeline, ID3D12PipelineState* dx_pipeline) {\n\tif (!vk.active && !dx.active)\n\t\treturn;\n\n\tint i = 0;\n\twhile (i < numExtrudedEdges) {\n\t\tint count = numExtrudedEdges - i;\n\t\tif (count > (SHADER_MAX_VERTEXES - 1) / 4)\n\t\t\tcount = (SHADER_MAX_VERTEXES - 1) / 4;\n\n\t\tCom_Memcpy(tess.xyz, extrudedEdges[i*4], 4 * count * sizeof(vec4_t));\n\t\ttess.numVertexes = count * 4;\n\n\t\tfor (int k = 0; k < count; k++) {\n\t\t\ttess.indexes[k * 6 + 0] = k * 4 + 0;\n\t\t\ttess.indexes[k * 6 + 1] = k * 4 + 2;\n\t\t\ttess.indexes[k * 6 + 2] = k * 4 + 1;\n\n\t\t\ttess.indexes[k * 6 + 3] = k * 4 + 2;\n\t\t\ttess.indexes[k * 6 + 4] = k * 4 + 3;\n\t\t\ttess.indexes[k * 6 + 5] = k * 4 + 1;\n\t\t}\n\t\ttess.numIndexes = count * 6;\n\n\t\tfor (int k = 0; k < tess.numVertexes; k++) {\n\t\t\tVectorSet(tess.svars.colors[k], 50, 50, 50);\n\t\t\ttess.svars.colors[k][3] = 255;\n\t\t}\n\n\t\tif (vk.active) {\n\t\t\tvk_bind_geometry();\n\t\t\tvk_shade_geometry(vk_pipeline, false, Vk_Depth_Range::normal);\n\t\t}\n\t\tif (dx.active) {\n\t\t\tdx_bind_geometry();\n\t\t\tdx_shade_geometry(dx_pipeline, false, Vk_Depth_Range::normal, true, false);\n\t\t}\n\n\t\ti += count;\n\t}\n}\n\n/*\n=================\nRB_ShadowTessEnd\n\ntriangleFromEdge[ v1 ][ v2 ]\n\n\n  set triangle from edge( v1, v2, tri )\n  if ( facing[ triangleFromEdge[ v1 ][ v2 ] ] && !facing[ triangleFromEdge[ v2 ][ v1 ] ) {\n  }\n=================\n*/\nvoid RB_ShadowTessEnd( void ) {\n\tint\t\ti;\n\tint\t\tnumTris;\n\tvec3_t\tlightDir;\n\n\t// we can only do this if we have enough space in the vertex buffers\n\tif ( tess.numVertexes >= SHADER_MAX_VERTEXES / 2 ) {\n\t\treturn;\n\t}\n\n\tif ( glConfig.stencilBits < 4 ) {\n\t\treturn;\n\t}\n\n\tVectorCopy( backEnd.currentEntity->lightDir, lightDir );\n\n\t// project vertexes away from light direction\n\tfor ( i = 0 ; i < tess.numVertexes ; i++ ) {\n\t\tVectorMA( tess.xyz[i], -512, lightDir, tess.xyz[i+tess.numVertexes] );\n\t}\n\n\t// decide which triangles face the light\n\tCom_Memset( numEdgeDefs, 0, 4 * tess.numVertexes );\n\n\tnumTris = tess.numIndexes / 3;\n\tfor ( i = 0 ; i < numTris ; i++ ) {\n\t\tint\t\ti1, i2, i3;\n\t\tvec3_t\td1, d2, normal;\n\t\tfloat\t*v1, *v2, *v3;\n\t\tfloat\td;\n\n\t\ti1 = tess.indexes[ i*3 + 0 ];\n\t\ti2 = tess.indexes[ i*3 + 1 ];\n\t\ti3 = tess.indexes[ i*3 + 2 ];\n\n\t\tv1 = tess.xyz[ i1 ];\n\t\tv2 = tess.xyz[ i2 ];\n\t\tv3 = tess.xyz[ i3 ];\n\n\t\tVectorSubtract( v2, v1, d1 );\n\t\tVectorSubtract( v3, v1, d2 );\n\t\tCrossProduct( d1, d2, normal );\n\n\t\td = DotProduct( normal, lightDir );\n\t\tif ( d > 0 ) {\n\t\t\tfacing[ i ] = 1;\n\t\t} else {\n\t\t\tfacing[ i ] = 0;\n\t\t}\n\n\t\t// create the edges\n\t\tR_AddEdgeDef( i1, i2, facing[ i ] );\n\t\tR_AddEdgeDef( i2, i3, facing[ i ] );\n\t\tR_AddEdgeDef( i3, i1, facing[ i ] );\n\t}\n\n\t// draw the silhouette edges\n\n\tGL_Bind( tr.whiteImage );\n\tqglEnable( GL_CULL_FACE );\n\tGL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO );\n\tqglColor3f( 0.2f, 0.2f, 0.2f );\n\n\t// don't write to the color buffer\n\tqglColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );\n\n\tqglEnable( GL_STENCIL_TEST );\n\tqglStencilFunc( GL_ALWAYS, 1, 255 );\n\n\tR_ExtrudeShadowEdges();\n\n\t// mirrors have the culling order reversed\n\tif ( backEnd.viewParms.isMirror ) {\n\t\tqglCullFace( GL_FRONT );\n\t\tqglStencilOp( GL_KEEP, GL_KEEP, GL_INCR );\n\t\tR_GL_RenderShadowEdges();\n\n\t\tqglCullFace( GL_BACK );\n\t\tqglStencilOp( GL_KEEP, GL_KEEP, GL_DECR );\n\t\tR_GL_RenderShadowEdges();\n\n\t\t// VULKAN\n\t\t// DX12\n\t\tR_Vk_Dx_RenderShadowEdges(vk.shadow_volume_pipelines[0][1], dx.shadow_volume_pipelines[0][1]);\n\t\tR_Vk_Dx_RenderShadowEdges(vk.shadow_volume_pipelines[1][1], dx.shadow_volume_pipelines[1][1]);\n\t} else {\n\t\tqglCullFace( GL_BACK );\n\t\tqglStencilOp( GL_KEEP, GL_KEEP, GL_INCR );\n\t\tR_GL_RenderShadowEdges();\n\n\t\tqglCullFace( GL_FRONT );\n\t\tqglStencilOp( GL_KEEP, GL_KEEP, GL_DECR );\n\t\tR_GL_RenderShadowEdges();\n\n\t\t// VULKAN\n\t\t// DX12\n\t\tR_Vk_Dx_RenderShadowEdges(vk.shadow_volume_pipelines[0][0], dx.shadow_volume_pipelines[0][0]);\n\t\tR_Vk_Dx_RenderShadowEdges(vk.shadow_volume_pipelines[1][0], dx.shadow_volume_pipelines[1][0]);\n\t}\n\n\tqglDisable(GL_STENCIL_TEST);\n\n\t// reenable writing to the color buffer\n\tqglColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );\n}\n\n\n/*\n=================\nRB_ShadowFinish\n\nDarken everything that is is a shadow volume.\nWe have to delay this until everything has been shadowed,\nbecause otherwise shadows from different body parts would\noverlap and double darken.\n=================\n*/\nvoid RB_ShadowFinish( void ) {\n\tif ( r_shadows->integer != 2 ) {\n\t\treturn;\n\t}\n\tif ( glConfig.stencilBits < 4 ) {\n\t\treturn;\n\t}\n\tqglEnable( GL_STENCIL_TEST );\n\tqglStencilFunc( GL_NOTEQUAL, 0, 255 );\n\n\tqglDisable (GL_CLIP_PLANE0);\n\tGL_Cull(CT_TWO_SIDED);\n\n\tGL_Bind( tr.whiteImage );\n\n\tqglPushMatrix();\n    qglLoadIdentity ();\n\n\tqglColor3f( 0.6f, 0.6f, 0.6f );\n\tGL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO );\n\n\tqglBegin( GL_QUADS );\n\tqglVertex3f( -100, 100, -10 );\n\tqglVertex3f( 100, 100, -10 );\n\tqglVertex3f( 100, -100, -10 );\n\tqglVertex3f( -100, -100, -10 );\n\tqglEnd ();\n\n\tqglColor3f(1,1,1);\n\tqglDisable( GL_STENCIL_TEST );\n\tqglPopMatrix();\n\n\t// VULKAN\n\t// DX12\n\tif (vk.active || dx.active) {\n\t\ttess.indexes[0] = 0;\n\t\ttess.indexes[1] = 1;\n\t\ttess.indexes[2] = 2;\n\t\ttess.indexes[3] = 0;\n\t\ttess.indexes[4] = 2;\n\t\ttess.indexes[5] = 3;\n\t\ttess.numIndexes = 6;\n\n\t\tVectorSet(tess.xyz[0], -100,  100, -10);\n\t\tVectorSet(tess.xyz[1],  100,  100, -10);\n\t\tVectorSet(tess.xyz[2],  100, -100, -10);\n\t\tVectorSet(tess.xyz[3], -100, -100, -10);\n\t\tfor (int i = 0; i < 4; i++) {\n\t\t\tVectorSet(tess.svars.colors[i], 153, 153, 153);\n\t\t\ttess.svars.colors[i][3] = 255;\n\t\t}\n\t\ttess.numVertexes = 4;\n\n\t\tif (vk.active) {\n\t\t\t// set backEnd.or.modelMatrix to identity matrix\n\t\t\tfloat tmp[16];\n\t\t\tCom_Memcpy(tmp, vk_world.modelview_transform, 64);\n\t\t\tCom_Memset(vk_world.modelview_transform, 0, 64);\n\t\t\tvk_world.modelview_transform[0] = 1.0f;\n\t\t\tvk_world.modelview_transform[5] = 1.0f;\n\t\t\tvk_world.modelview_transform[10] = 1.0f;\n\t\t\tvk_world.modelview_transform[15] = 1.0f;\n\n\t\t\tvk_bind_geometry();\n\t\t\tvk_shade_geometry(vk.shadow_finish_pipeline, false, Vk_Depth_Range::normal);\n\n\t\t\tCom_Memcpy(vk_world.modelview_transform, tmp, 64);\n\t\t}\n\n\t\tif (dx.active) {\n\t\t\t// set backEnd.or.modelMatrix to identity matrix\n\t\t\tfloat tmp[16];\n\t\t\tCom_Memcpy(tmp, dx_world.modelview_transform, 64);\n\t\t\tCom_Memset(dx_world.modelview_transform, 0, 64);\n\t\t\tdx_world.modelview_transform[0] = 1.0f;\n\t\t\tdx_world.modelview_transform[5] = 1.0f;\n\t\t\tdx_world.modelview_transform[10] = 1.0f;\n\t\t\tdx_world.modelview_transform[15] = 1.0f;\n\n\t\t\tdx_bind_geometry();\n\t\t\tdx_shade_geometry(dx.shadow_finish_pipeline, false, Vk_Depth_Range::normal, true, false);\n\n\t\t\tCom_Memcpy(dx_world.modelview_transform, tmp, 64);\n\t\t}\n\n\t\ttess.numIndexes = 0;\n\t\ttess.numVertexes = 0;\n\t}\n}\n\n\n/*\n=================\nRB_ProjectionShadowDeform\n\n=================\n*/\nvoid RB_ProjectionShadowDeform( void ) {\n\tfloat\t*xyz;\n\tint\t\ti;\n\tfloat\th;\n\tvec3_t\tground;\n\tvec3_t\tlight;\n\tfloat\tgroundDist;\n\tfloat\td;\n\tvec3_t\tlightDir;\n\n\txyz = ( float * ) tess.xyz;\n\n\tground[0] = backEnd.or.axis[0][2];\n\tground[1] = backEnd.or.axis[1][2];\n\tground[2] = backEnd.or.axis[2][2];\n\n\tgroundDist = backEnd.or.origin[2] - backEnd.currentEntity->e.shadowPlane;\n\n\tVectorCopy( backEnd.currentEntity->lightDir, lightDir );\n\td = DotProduct( lightDir, ground );\n\t// don't let the shadows get too long or go negative\n\tif ( d < 0.5 ) {\n\t\tVectorMA( lightDir, (0.5 - d), ground, lightDir );\n\t\td = DotProduct( lightDir, ground );\n\t}\n\td = 1.0 / d;\n\n\tlight[0] = lightDir[0] * d;\n\tlight[1] = lightDir[1] * d;\n\tlight[2] = lightDir[2] * d;\n\n\tfor ( i = 0; i < tess.numVertexes; i++, xyz += 4 ) {\n\t\th = DotProduct( xyz, ground ) + groundDist;\n\n\t\txyz[0] -= light[0] * h;\n\t\txyz[1] -= light[1] * h;\n\t\txyz[2] -= light[2] * h;\n\t}\n}\n"
  },
  {
    "path": "src/engine/renderer/tr_sky.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n// tr_sky.c\n#include \"tr_local.h\"\n\n#define SKY_SUBDIVISIONS\t\t8\n#define HALF_SKY_SUBDIVISIONS\t(SKY_SUBDIVISIONS/2)\n\nstatic float s_cloudTexCoords[6][SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1][2];\n\n/*\n===================================================================================\n\nPOLYGON TO BOX SIDE PROJECTION\n\n===================================================================================\n*/\n\nstatic vec3_t sky_clip[6] = \n{\n\t{1,1,0},\n\t{1,-1,0},\n\t{0,-1,1},\n\t{0,1,1},\n\t{1,0,1},\n\t{-1,0,1} \n};\n\nstatic float\tsky_mins[2][6], sky_maxs[2][6];\nstatic float\tsky_min, sky_max;\n\n/*\n================\nAddSkyPolygon\n================\n*/\nstatic void AddSkyPolygon (int nump, vec3_t vecs) \n{\n\tint\t\ti,j;\n\tvec3_t\tv, av;\n\tfloat\ts, t, dv;\n\tint\t\taxis;\n\tfloat\t*vp;\n\t// s = [0]/[2], t = [1]/[2]\n\tstatic int\tvec_to_st[6][3] =\n\t{\n\t\t{-2,3,1},\n\t\t{2,3,-1},\n\n\t\t{1,3,2},\n\t\t{-1,3,-2},\n\n\t\t{-2,-1,3},\n\t\t{-2,1,-3}\n\n\t//\t{-1,2,3},\n\t//\t{1,2,-3}\n\t};\n\n\t// decide which face it maps to\n\tVectorCopy (vec3_origin, v);\n\tfor (i=0, vp=vecs ; i<nump ; i++, vp+=3)\n\t{\n\t\tVectorAdd (vp, v, v);\n\t}\n\tav[0] = fabs(v[0]);\n\tav[1] = fabs(v[1]);\n\tav[2] = fabs(v[2]);\n\tif (av[0] > av[1] && av[0] > av[2])\n\t{\n\t\tif (v[0] < 0)\n\t\t\taxis = 1;\n\t\telse\n\t\t\taxis = 0;\n\t}\n\telse if (av[1] > av[2] && av[1] > av[0])\n\t{\n\t\tif (v[1] < 0)\n\t\t\taxis = 3;\n\t\telse\n\t\t\taxis = 2;\n\t}\n\telse\n\t{\n\t\tif (v[2] < 0)\n\t\t\taxis = 5;\n\t\telse\n\t\t\taxis = 4;\n\t}\n\n\t// project new texture coords\n\tfor (i=0 ; i<nump ; i++, vecs+=3)\n\t{\n\t\tj = vec_to_st[axis][2];\n\t\tif (j > 0)\n\t\t\tdv = vecs[j - 1];\n\t\telse\n\t\t\tdv = -vecs[-j - 1];\n\t\tif (dv < 0.001)\n\t\t\tcontinue;\t// don't divide by zero\n\t\tj = vec_to_st[axis][0];\n\t\tif (j < 0)\n\t\t\ts = -vecs[-j -1] / dv;\n\t\telse\n\t\t\ts = vecs[j-1] / dv;\n\t\tj = vec_to_st[axis][1];\n\t\tif (j < 0)\n\t\t\tt = -vecs[-j -1] / dv;\n\t\telse\n\t\t\tt = vecs[j-1] / dv;\n\n\t\tif (s < sky_mins[0][axis])\n\t\t\tsky_mins[0][axis] = s;\n\t\tif (t < sky_mins[1][axis])\n\t\t\tsky_mins[1][axis] = t;\n\t\tif (s > sky_maxs[0][axis])\n\t\t\tsky_maxs[0][axis] = s;\n\t\tif (t > sky_maxs[1][axis])\n\t\t\tsky_maxs[1][axis] = t;\n\t}\n}\n\n#define\tON_EPSILON\t\t0.1f\t\t\t// point on plane side epsilon\n#define\tMAX_CLIP_VERTS\t64\n/*\n================\nClipSkyPolygon\n================\n*/\nstatic void ClipSkyPolygon (int nump, vec3_t vecs, int stage) \n{\n\tfloat\t*norm;\n\tfloat\t*v;\n\tqboolean\tfront, back;\n\tfloat\td, e;\n\tfloat\tdists[MAX_CLIP_VERTS];\n\tint\t\tsides[MAX_CLIP_VERTS];\n\tvec3_t\tnewv[2][MAX_CLIP_VERTS];\n\tint\t\tnewc[2];\n\tint\t\ti, j;\n\n\tif (nump > MAX_CLIP_VERTS-2)\n\t\tri.Error (ERR_DROP, \"ClipSkyPolygon: MAX_CLIP_VERTS\");\n\tif (stage == 6)\n\t{\t// fully clipped, so draw it\n\t\tAddSkyPolygon (nump, vecs);\n\t\treturn;\n\t}\n\n\tfront = back = qfalse;\n\tnorm = sky_clip[stage];\n\tfor (i=0, v = vecs ; i<nump ; i++, v+=3)\n\t{\n\t\td = DotProduct (v, norm);\n\t\tif (d > ON_EPSILON)\n\t\t{\n\t\t\tfront = qtrue;\n\t\t\tsides[i] = SIDE_FRONT;\n\t\t}\n\t\telse if (d < -ON_EPSILON)\n\t\t{\n\t\t\tback = qtrue;\n\t\t\tsides[i] = SIDE_BACK;\n\t\t}\n\t\telse\n\t\t\tsides[i] = SIDE_ON;\n\t\tdists[i] = d;\n\t}\n\n\tif (!front || !back)\n\t{\t// not clipped\n\t\tClipSkyPolygon (nump, vecs, stage+1);\n\t\treturn;\n\t}\n\n\t// clip it\n\tsides[i] = sides[0];\n\tdists[i] = dists[0];\n\tVectorCopy (vecs, (vecs+(i*3)) );\n\tnewc[0] = newc[1] = 0;\n\n\tfor (i=0, v = vecs ; i<nump ; i++, v+=3)\n\t{\n\t\tswitch (sides[i])\n\t\t{\n\t\tcase SIDE_FRONT:\n\t\t\tVectorCopy (v, newv[0][newc[0]]);\n\t\t\tnewc[0]++;\n\t\t\tbreak;\n\t\tcase SIDE_BACK:\n\t\t\tVectorCopy (v, newv[1][newc[1]]);\n\t\t\tnewc[1]++;\n\t\t\tbreak;\n\t\tcase SIDE_ON:\n\t\t\tVectorCopy (v, newv[0][newc[0]]);\n\t\t\tnewc[0]++;\n\t\t\tVectorCopy (v, newv[1][newc[1]]);\n\t\t\tnewc[1]++;\n\t\t\tbreak;\n\t\t}\n\n\t\tif (sides[i] == SIDE_ON || sides[i+1] == SIDE_ON || sides[i+1] == sides[i])\n\t\t\tcontinue;\n\n\t\td = dists[i] / (dists[i] - dists[i+1]);\n\t\tfor (j=0 ; j<3 ; j++)\n\t\t{\n\t\t\te = v[j] + d*(v[j+3] - v[j]);\n\t\t\tnewv[0][newc[0]][j] = e;\n\t\t\tnewv[1][newc[1]][j] = e;\n\t\t}\n\t\tnewc[0]++;\n\t\tnewc[1]++;\n\t}\n\n\t// continue\n\tClipSkyPolygon (newc[0], newv[0][0], stage+1);\n\tClipSkyPolygon (newc[1], newv[1][0], stage+1);\n}\n\n/*\n==============\nClearSkyBox\n==============\n*/\nstatic void ClearSkyBox (void) {\n\tint\t\ti;\n\n\tfor (i=0 ; i<6 ; i++) {\n\t\tsky_mins[0][i] = sky_mins[1][i] = 9999;\n\t\tsky_maxs[0][i] = sky_maxs[1][i] = -9999;\n\t}\n}\n\n/*\n================\nRB_ClipSkyPolygons\n================\n*/\nvoid RB_ClipSkyPolygons( shaderCommands_t *input )\n{\n\tvec3_t\t\tp[5];\t// need one extra point for clipping\n\tint\t\t\ti, j;\n\n\tClearSkyBox();\n\n\tfor ( i = 0; i < input->numIndexes; i += 3 )\n\t{\n\t\tfor (j = 0 ; j < 3 ; j++) \n\t\t{\n\t\t\tVectorSubtract( input->xyz[input->indexes[i+j]],\n\t\t\t\t\t\t\tbackEnd.viewParms.or.origin, \n\t\t\t\t\t\t\tp[j] );\n\t\t}\n\t\tClipSkyPolygon( 3, p[0], 0 );\n\t}\n}\n\n/*\n===================================================================================\n\nCLOUD VERTEX GENERATION\n\n===================================================================================\n*/\n\n/*\n** MakeSkyVec\n**\n** Parms: s, t range from -1 to 1\n*/\nstatic void MakeSkyVec( float s, float t, int axis, float outSt[2], vec3_t outXYZ )\n{\n\t// 1 = s, 2 = t, 3 = 2048\n\tstatic int\tst_to_vec[6][3] =\n\t{\n\t\t{3,-1,2},\n\t\t{-3,1,2},\n\n\t\t{1,3,2},\n\t\t{-1,-3,2},\n\n\t\t{-2,-1,3},\t\t// 0 degrees yaw, look straight up\n\t\t{2,-1,-3}\t\t// look straight down\n\t};\n\n\tvec3_t\t\tb;\n\tint\t\t\tj, k;\n\tfloat\tboxSize;\n\n\tboxSize = backEnd.viewParms.zFar / 1.75;\t\t// div sqrt(3)\n\tb[0] = s*boxSize;\n\tb[1] = t*boxSize;\n\tb[2] = boxSize;\n\n\tfor (j=0 ; j<3 ; j++)\n\t{\n\t\tk = st_to_vec[axis][j];\n\t\tif (k < 0)\n\t\t{\n\t\t\toutXYZ[j] = -b[-k - 1];\n\t\t}\n\t\telse\n\t\t{\n\t\t\toutXYZ[j] = b[k - 1];\n\t\t}\n\t}\n\n\t// avoid bilerp seam\n\ts = (s+1)*0.5;\n\tt = (t+1)*0.5;\n\tif (s < sky_min)\n\t{\n\t\ts = sky_min;\n\t}\n\telse if (s > sky_max)\n\t{\n\t\ts = sky_max;\n\t}\n\n\tif (t < sky_min)\n\t{\n\t\tt = sky_min;\n\t}\n\telse if (t > sky_max)\n\t{\n\t\tt = sky_max;\n\t}\n\n\tt = 1.0 - t;\n\n\n\tif ( outSt )\n\t{\n\t\toutSt[0] = s;\n\t\toutSt[1] = t;\n\t}\n}\n\nstatic int\tsky_texorder[6] = {0,2,1,3,4,5};\nstatic vec3_t\ts_skyPoints[SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1];\nstatic float\ts_skyTexCoords[SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1][2];\n\nstatic void DrawSkySide( struct image_s *image, const int mins[2], const int maxs[2] )\n{\n\tint s, t;\n\n\tGL_Bind( image );\n\n\tfor ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t < maxs[1]+HALF_SKY_SUBDIVISIONS; t++ )\n\t{\n\t\tqglBegin( GL_TRIANGLE_STRIP );\n\n\t\tfor ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ )\n\t\t{\n\t\t\tqglTexCoord2fv( s_skyTexCoords[t][s] );\n\t\t\tqglVertex3fv( s_skyPoints[t][s] );\n\n\t\t\tqglTexCoord2fv( s_skyTexCoords[t+1][s] );\n\t\t\tqglVertex3fv( s_skyPoints[t+1][s] );\n\t\t}\n\n\t\tqglEnd();\n\t}\n}\n\nstatic void DrawSkyBox( shader_t *shader )\n{\n\tint\t\ti;\n\n\tsky_min = 0;\n\tsky_max = 1;\n\n\tCom_Memset( s_skyTexCoords, 0, sizeof( s_skyTexCoords ) );\n\n\tfor (i=0 ; i<6 ; i++)\n\t{\n\t\tint sky_mins_subd[2], sky_maxs_subd[2];\n\t\tint s, t;\n\n\t\tsky_mins[0][i] = floor( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;\n\t\tsky_mins[1][i] = floor( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;\n\t\tsky_maxs[0][i] = ceil( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;\n\t\tsky_maxs[1][i] = ceil( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;\n\n\t\tif ( ( sky_mins[0][i] >= sky_maxs[0][i] ) ||\n\t\t\t ( sky_mins[1][i] >= sky_maxs[1][i] ) )\n\t\t{\n\t\t\tcontinue;\n\t\t}\n\n\t\tsky_mins_subd[0] = sky_mins[0][i] * HALF_SKY_SUBDIVISIONS;\n\t\tsky_mins_subd[1] = sky_mins[1][i] * HALF_SKY_SUBDIVISIONS;\n\t\tsky_maxs_subd[0] = sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS;\n\t\tsky_maxs_subd[1] = sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS;\n\n\t\tif ( sky_mins_subd[0] < -HALF_SKY_SUBDIVISIONS ) \n\t\t\tsky_mins_subd[0] = -HALF_SKY_SUBDIVISIONS;\n\t\telse if ( sky_mins_subd[0] > HALF_SKY_SUBDIVISIONS ) \n\t\t\tsky_mins_subd[0] = HALF_SKY_SUBDIVISIONS;\n\t\tif ( sky_mins_subd[1] < -HALF_SKY_SUBDIVISIONS )\n\t\t\tsky_mins_subd[1] = -HALF_SKY_SUBDIVISIONS;\n\t\telse if ( sky_mins_subd[1] > HALF_SKY_SUBDIVISIONS ) \n\t\t\tsky_mins_subd[1] = HALF_SKY_SUBDIVISIONS;\n\n\t\tif ( sky_maxs_subd[0] < -HALF_SKY_SUBDIVISIONS ) \n\t\t\tsky_maxs_subd[0] = -HALF_SKY_SUBDIVISIONS;\n\t\telse if ( sky_maxs_subd[0] > HALF_SKY_SUBDIVISIONS ) \n\t\t\tsky_maxs_subd[0] = HALF_SKY_SUBDIVISIONS;\n\t\tif ( sky_maxs_subd[1] < -HALF_SKY_SUBDIVISIONS ) \n\t\t\tsky_maxs_subd[1] = -HALF_SKY_SUBDIVISIONS;\n\t\telse if ( sky_maxs_subd[1] > HALF_SKY_SUBDIVISIONS ) \n\t\t\tsky_maxs_subd[1] = HALF_SKY_SUBDIVISIONS;\n\n\t\t//\n\t\t// iterate through the subdivisions\n\t\t//\n\t\tfor ( t = sky_mins_subd[1]+HALF_SKY_SUBDIVISIONS; t <= sky_maxs_subd[1]+HALF_SKY_SUBDIVISIONS; t++ )\n\t\t{\n\t\t\tfor ( s = sky_mins_subd[0]+HALF_SKY_SUBDIVISIONS; s <= sky_maxs_subd[0]+HALF_SKY_SUBDIVISIONS; s++ )\n\t\t\t{\n\t\t\t\tMakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, \n\t\t\t\t\t\t\t( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, \n\t\t\t\t\t\t\ti, \n\t\t\t\t\t\t\ts_skyTexCoords[t][s], \n\t\t\t\t\t\t\ts_skyPoints[t][s] );\n\t\t\t}\n\t\t}\n\n\t\tDrawSkySide( shader->sky.outerbox[sky_texorder[i]],\n\t\t\t         sky_mins_subd,\n\t\t\t\t\t sky_maxs_subd );\n\n\t\t// VULKAN: draw skybox side\n\t\t// DX12\n\t\tif (vk.active || dx.active) {\n\t\t\tGL_Bind(shader->sky.outerbox[sky_texorder[i]]);\n\n\t\t\ttess.numVertexes = 0;\n\t\t\ttess.numIndexes = 0;\n\n\t\t\tfor ( t = sky_mins_subd[1]+HALF_SKY_SUBDIVISIONS; t < sky_maxs_subd[1]+HALF_SKY_SUBDIVISIONS; t++ )\n\t\t\t{\n\t\t\t\tfor ( s = sky_mins_subd[0]+HALF_SKY_SUBDIVISIONS; s < sky_maxs_subd[0]+HALF_SKY_SUBDIVISIONS; s++ )\n\t\t\t\t{\n\t\t\t\t\tint ndx = tess.numVertexes;\n\n\t\t\t\t\ttess.indexes[ tess.numIndexes ] = ndx;\n\t\t\t\t\ttess.indexes[ tess.numIndexes + 1 ] = ndx + 1;\n\t\t\t\t\ttess.indexes[ tess.numIndexes + 2 ] = ndx + 2;\n\n\t\t\t\t\ttess.indexes[ tess.numIndexes + 3 ] = ndx + 2;\n\t\t\t\t\ttess.indexes[ tess.numIndexes + 4 ] = ndx + 1;\n\t\t\t\t\ttess.indexes[ tess.numIndexes + 5 ] = ndx + 3;\n\t\t\t\t\ttess.numIndexes += 6;\n\n\t\t\t\t\tVectorCopy(s_skyPoints[t][s], tess.xyz[ndx]);\n\t\t\t\t\ttess.svars.texcoords[0][ndx][0] = s_skyTexCoords[t][s][0];\n\t\t\t\t\ttess.svars.texcoords[0][ndx][1] = s_skyTexCoords[t][s][1];\n\n\t\t\t\t\tVectorCopy(s_skyPoints[t + 1][s], tess.xyz[ndx + 1]);\n\t\t\t\t\ttess.svars.texcoords[0][ndx + 1][0] = s_skyTexCoords[t + 1][s][0];\n\t\t\t\t\ttess.svars.texcoords[0][ndx + 1][1] = s_skyTexCoords[t + 1][s][1];\n\n\t\t\t\t\tVectorCopy(s_skyPoints[t][s + 1], tess.xyz[ndx + 2]);\n\t\t\t\t\ttess.svars.texcoords[0][ndx + 2][0] = s_skyTexCoords[t][s + 1][0];\n\t\t\t\t\ttess.svars.texcoords[0][ndx + 2][1] = s_skyTexCoords[t][s + 1][1];\n\n\t\t\t\t\tVectorCopy(s_skyPoints[t + 1][s + 1], tess.xyz[ndx + 3]);\n\t\t\t\t\ttess.svars.texcoords[0][ndx + 3][0] = s_skyTexCoords[t + 1][s + 1][0];\n\t\t\t\t\ttess.svars.texcoords[0][ndx + 3][1] = s_skyTexCoords[t + 1][s + 1][1];\n\n\t\t\t\t\ttess.numVertexes += 4;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tCom_Memset( tess.svars.colors, tr.identityLightByte, tess.numVertexes * 4 );\n\n\t\t\tif (vk.active) {\n\t\t\t\tvk_bind_geometry();\n\t\t\t\tvk_shade_geometry(vk.skybox_pipeline, false, r_showsky->integer ? Vk_Depth_Range::force_zero : Vk_Depth_Range::force_one);\n\t\t\t}\n\t\t\tif (dx.active) {\n\t\t\t\tdx_bind_geometry();\n\t\t\t\tdx_shade_geometry(dx.skybox_pipeline, false, r_showsky->integer ? Vk_Depth_Range::force_zero : Vk_Depth_Range::force_one, true, false);\n\t\t\t}\n\t\t}\n\t}\n\n}\n\nstatic void FillCloudySkySide( const int mins[2], const int maxs[2] )\n{\n\tint s, t;\n\tint vertexStart = tess.numVertexes;\n\tint tHeight, sWidth;\n\n\ttHeight = maxs[1] - mins[1] + 1;\n\tsWidth = maxs[0] - mins[0] + 1;\n\n\tfor ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t <= maxs[1]+HALF_SKY_SUBDIVISIONS; t++ )\n\t{\n\t\tfor ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ )\n\t\t{\n\t\t\tVectorAdd( s_skyPoints[t][s], backEnd.viewParms.or.origin, tess.xyz[tess.numVertexes] );\n\t\t\ttess.texCoords[tess.numVertexes][0][0] = s_skyTexCoords[t][s][0];\n\t\t\ttess.texCoords[tess.numVertexes][0][1] = s_skyTexCoords[t][s][1];\n\n\t\t\ttess.numVertexes++;\n\n\t\t\tif ( tess.numVertexes >= SHADER_MAX_VERTEXES )\n\t\t\t{\n\t\t\t\tri.Error( ERR_DROP, \"SHADER_MAX_VERTEXES hit in FillCloudySkySide()\\n\" );\n\t\t\t}\n\t\t}\n\t}\n\n\tfor ( t = 0; t < tHeight-1; t++ )\n\t{\t\n\t\tfor ( s = 0; s < sWidth-1; s++ )\n\t\t{\n\t\t\ttess.indexes[tess.numIndexes] = vertexStart + s + t * ( sWidth );\n\t\t\ttess.numIndexes++;\n\t\t\ttess.indexes[tess.numIndexes] = vertexStart + s + ( t + 1 ) * ( sWidth );\n\t\t\ttess.numIndexes++;\n\t\t\ttess.indexes[tess.numIndexes] = vertexStart + s + 1 + t * ( sWidth );\n\t\t\ttess.numIndexes++;\n\n\t\t\ttess.indexes[tess.numIndexes] = vertexStart + s + ( t + 1 ) * ( sWidth );\n\t\t\ttess.numIndexes++;\n\t\t\ttess.indexes[tess.numIndexes] = vertexStart + s + 1 + ( t + 1 ) * ( sWidth );\n\t\t\ttess.numIndexes++;\n\t\t\ttess.indexes[tess.numIndexes] = vertexStart + s + 1 + t * ( sWidth );\n\t\t\ttess.numIndexes++;\n\t\t}\n\t}\n}\n\nstatic void FillCloudBox()\n{\n\tfor ( int i = 0; i < 5; i++ )\n\t{\n\t\tint sky_mins_subd[2], sky_maxs_subd[2];\n\t\tint s, t;\n\n\t\tfloat MIN_T = -HALF_SKY_SUBDIVISIONS;\n\n\t\tsky_mins[0][i] = floor( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;\n\t\tsky_mins[1][i] = floor( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;\n\t\tsky_maxs[0][i] = ceil( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;\n\t\tsky_maxs[1][i] = ceil( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;\n\n\t\tif ( ( sky_mins[0][i] >= sky_maxs[0][i] ) ||\n\t\t\t ( sky_mins[1][i] >= sky_maxs[1][i] ) )\n\t\t{\n\t\t\tcontinue;\n\t\t}\n\n\t\tsky_mins_subd[0] = myftol( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS );\n\t\tsky_mins_subd[1] = myftol( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS );\n\t\tsky_maxs_subd[0] = myftol( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS );\n\t\tsky_maxs_subd[1] = myftol( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS );\n\n\t\tif ( sky_mins_subd[0] < -HALF_SKY_SUBDIVISIONS ) \n\t\t\tsky_mins_subd[0] = -HALF_SKY_SUBDIVISIONS;\n\t\telse if ( sky_mins_subd[0] > HALF_SKY_SUBDIVISIONS ) \n\t\t\tsky_mins_subd[0] = HALF_SKY_SUBDIVISIONS;\n\t\tif ( sky_mins_subd[1] < MIN_T )\n\t\t\tsky_mins_subd[1] = MIN_T;\n\t\telse if ( sky_mins_subd[1] > HALF_SKY_SUBDIVISIONS ) \n\t\t\tsky_mins_subd[1] = HALF_SKY_SUBDIVISIONS;\n\n\t\tif ( sky_maxs_subd[0] < -HALF_SKY_SUBDIVISIONS ) \n\t\t\tsky_maxs_subd[0] = -HALF_SKY_SUBDIVISIONS;\n\t\telse if ( sky_maxs_subd[0] > HALF_SKY_SUBDIVISIONS ) \n\t\t\tsky_maxs_subd[0] = HALF_SKY_SUBDIVISIONS;\n\t\tif ( sky_maxs_subd[1] < MIN_T )\n\t\t\tsky_maxs_subd[1] = MIN_T;\n\t\telse if ( sky_maxs_subd[1] > HALF_SKY_SUBDIVISIONS ) \n\t\t\tsky_maxs_subd[1] = HALF_SKY_SUBDIVISIONS;\n\n\t\t//\n\t\t// iterate through the subdivisions\n\t\t//\n\t\tfor ( t = sky_mins_subd[1]+HALF_SKY_SUBDIVISIONS; t <= sky_maxs_subd[1]+HALF_SKY_SUBDIVISIONS; t++ )\n\t\t{\n\t\t\tfor ( s = sky_mins_subd[0]+HALF_SKY_SUBDIVISIONS; s <= sky_maxs_subd[0]+HALF_SKY_SUBDIVISIONS; s++ )\n\t\t\t{\n\t\t\t\tMakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, \n\t\t\t\t\t\t\t( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, \n\t\t\t\t\t\t\ti, \n\t\t\t\t\t\t\tNULL,\n\t\t\t\t\t\t\ts_skyPoints[t][s] );\n\n\t\t\t\ts_skyTexCoords[t][s][0] = s_cloudTexCoords[i][t][s][0];\n\t\t\t\ts_skyTexCoords[t][s][1] = s_cloudTexCoords[i][t][s][1];\n\t\t\t}\n\t\t}\n\n\t\t// only add indexes for first stage\n\t\tFillCloudySkySide( sky_mins_subd, sky_maxs_subd);\n\t}\n}\n\n/*\n** R_BuildCloudData\n*/\nvoid R_BuildCloudData( shaderCommands_t *input )\n{\n\tshader_t\t*shader;\n\n\tshader = input->shader;\n\n\tassert( shader->isSky );\n\n\tsky_min = 1.0 / 256.0f;\t\t// FIXME: not correct?\n\tsky_max = 255.0 / 256.0f;\n\n\t// set up for drawing\n\ttess.numIndexes = 0;\n\ttess.numVertexes = 0;\n\n\tif ( input->shader->sky.cloudHeight && tess.xstages[0] )\n\t{\n        FillCloudBox();\n\t}\n}\n\n/*\n** R_InitSkyTexCoords\n** Called when a sky shader is parsed\n*/\n#define SQR( a ) ((a)*(a))\nvoid R_InitSkyTexCoords( float heightCloud )\n{\n\tint i, s, t;\n\tfloat radiusWorld = 4096;\n\tfloat p;\n\tfloat sRad, tRad;\n\tvec3_t skyVec;\n\tvec3_t v;\n\n\t// init zfar so MakeSkyVec works even though\n\t// a world hasn't been bounded\n\tbackEnd.viewParms.zFar = 1024;\n\n\tfor ( i = 0; i < 6; i++ )\n\t{\n\t\tfor ( t = 0; t <= SKY_SUBDIVISIONS; t++ )\n\t\t{\n\t\t\tfor ( s = 0; s <= SKY_SUBDIVISIONS; s++ )\n\t\t\t{\n\t\t\t\t// compute vector from view origin to sky side integral point\n\t\t\t\tMakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, \n\t\t\t\t\t\t\t( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, \n\t\t\t\t\t\t\ti, \n\t\t\t\t\t\t\tNULL,\n\t\t\t\t\t\t\tskyVec );\n\n\t\t\t\t// compute parametric value 'p' that intersects with cloud layer\n\t\t\t\tp = ( 1.0f / ( 2 * DotProduct( skyVec, skyVec ) ) ) *\n\t\t\t\t\t( -2 * skyVec[2] * radiusWorld + \n\t\t\t\t\t   2 * sqrt( SQR( skyVec[2] ) * SQR( radiusWorld ) + \n\t\t\t\t\t             2 * SQR( skyVec[0] ) * radiusWorld * heightCloud +\n\t\t\t\t\t\t\t\t SQR( skyVec[0] ) * SQR( heightCloud ) + \n\t\t\t\t\t\t\t\t 2 * SQR( skyVec[1] ) * radiusWorld * heightCloud +\n\t\t\t\t\t\t\t\t SQR( skyVec[1] ) * SQR( heightCloud ) + \n\t\t\t\t\t\t\t\t 2 * SQR( skyVec[2] ) * radiusWorld * heightCloud +\n\t\t\t\t\t\t\t\t SQR( skyVec[2] ) * SQR( heightCloud ) ) );\n\n\t\t\t\t// compute intersection point based on p\n\t\t\t\tVectorScale( skyVec, p, v );\n\t\t\t\tv[2] += radiusWorld;\n\n\t\t\t\t// compute vector from world origin to intersection point 'v'\n\t\t\t\tVectorNormalize( v );\n\n\t\t\t\tsRad = Q_acos( v[0] );\n\t\t\t\ttRad = Q_acos( v[1] );\n\n\t\t\t\ts_cloudTexCoords[i][t][s][0] = sRad;\n\t\t\t\ts_cloudTexCoords[i][t][s][1] = tRad;\n\t\t\t}\n\t\t}\n\t}\n}\n\n/*\n================\nRB_StageIteratorSky\n\nAll of the visible sky triangles are in tess\n\nOther things could be stuck in here, like birds in the sky, etc\n================\n*/\nvoid RB_StageIteratorSky( void ) {\n\t// go through all the polygons and project them onto\n\t// the sky box to see which blocks on each side need\n\t// to be drawn\n\tRB_ClipSkyPolygons( &tess );\n\n\t// r_showsky will let all the sky blocks be drawn in\n\t// front of everything to allow developers to see how\n\t// much sky is getting sucked in\n\tif ( r_showsky->integer ) {\n\t\tqglDepthRange( 0.0, 0.0 );\n\t} else {\n\t\tqglDepthRange( 1.0, 1.0 );\n\t}\n\n\t// draw the outer skybox\n\tif ( tess.shader->sky.outerbox[0] && tess.shader->sky.outerbox[0] != tr.defaultImage ) {\n        float modelMatrix_original[16];\n        Com_Memcpy(modelMatrix_original, vk_world.modelview_transform, sizeof(float[16]));\n\n        float skybox_translate[16] = {\n            1, 0, 0, 0,\n            0, 1, 0, 0,\n            0, 0, 1, 0,\n            backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2], 1\n        };\n        myGlMultMatrix(skybox_translate, modelMatrix_original, vk_world.modelview_transform);\n\t\tmyGlMultMatrix(skybox_translate, modelMatrix_original, dx_world.modelview_transform);\n\n\t\tGL_State( 0 );\n        qglColor3f( tr.identityLight, tr.identityLight, tr.identityLight );\n        qglPushMatrix ();\n        qglLoadMatrixf(vk_world.modelview_transform);\n\t\tDrawSkyBox( tess.shader );\n\t\tqglPopMatrix();\n\n        Com_Memcpy(vk_world.modelview_transform, modelMatrix_original, sizeof(float[16]));\n\t\tCom_Memcpy(dx_world.modelview_transform, modelMatrix_original, sizeof(float[16]));\n\t}\n\n\t// generate the vertexes for all the clouds, which will be drawn\n\t// by the generic shader routine\n\tR_BuildCloudData( &tess );\n\n\tRB_StageIteratorGeneric();\n\n\t// draw the inner skybox\n\n\n\t// back to normal depth range\n\tqglDepthRange( 0.0, 1.0 );\n}\n"
  },
  {
    "path": "src/engine/renderer/tr_surface.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n// tr_surf.c\n#include \"tr_local.h\"\n\n/*\n\n  THIS ENTIRE FILE IS BACK END\n\nbackEnd.currentEntity will be valid.\n\nTess_Begin has already been called for the surface's shader.\n\nThe modelview matrix will be set.\n\nIt is safe to actually issue drawing commands here if you don't want to\nuse the shader system.\n*/\n\n\n//============================================================================\n\n\n/*\n==============\nRB_CheckOverflow\n==============\n*/\nvoid RB_CheckOverflow( int verts, int indexes ) {\n\tif (tess.numVertexes + verts < SHADER_MAX_VERTEXES\n\t\t&& tess.numIndexes + indexes < SHADER_MAX_INDEXES) {\n\t\treturn;\n\t}\n\n\tRB_EndSurface();\n\n\tif ( verts >= SHADER_MAX_VERTEXES ) {\n\t\tri.Error(ERR_DROP, \"RB_CheckOverflow: verts > MAX (%d > %d)\", verts, SHADER_MAX_VERTEXES );\n\t}\n\tif ( indexes >= SHADER_MAX_INDEXES ) {\n\t\tri.Error(ERR_DROP, \"RB_CheckOverflow: indices > MAX (%d > %d)\", indexes, SHADER_MAX_INDEXES );\n\t}\n\n\tRB_BeginSurface(tess.shader, tess.fogNum );\n}\n\n\n/*\n==============\nRB_AddQuadStampExt\n==============\n*/\nvoid RB_AddQuadStampExt( vec3_t origin, vec3_t left, vec3_t up, byte *color, float s1, float t1, float s2, float t2 ) {\n\tvec3_t\t\tnormal;\n\tint\t\t\tndx;\n\n\tRB_CHECKOVERFLOW( 4, 6 );\n\n\tndx = tess.numVertexes;\n\n\t// triangle indexes for a simple quad\n\ttess.indexes[ tess.numIndexes ] = ndx;\n\ttess.indexes[ tess.numIndexes + 1 ] = ndx + 1;\n\ttess.indexes[ tess.numIndexes + 2 ] = ndx + 3;\n\n\ttess.indexes[ tess.numIndexes + 3 ] = ndx + 3;\n\ttess.indexes[ tess.numIndexes + 4 ] = ndx + 1;\n\ttess.indexes[ tess.numIndexes + 5 ] = ndx + 2;\n\n\ttess.xyz[ndx][0] = origin[0] + left[0] + up[0];\n\ttess.xyz[ndx][1] = origin[1] + left[1] + up[1];\n\ttess.xyz[ndx][2] = origin[2] + left[2] + up[2];\n\n\ttess.xyz[ndx+1][0] = origin[0] - left[0] + up[0];\n\ttess.xyz[ndx+1][1] = origin[1] - left[1] + up[1];\n\ttess.xyz[ndx+1][2] = origin[2] - left[2] + up[2];\n\n\ttess.xyz[ndx+2][0] = origin[0] - left[0] - up[0];\n\ttess.xyz[ndx+2][1] = origin[1] - left[1] - up[1];\n\ttess.xyz[ndx+2][2] = origin[2] - left[2] - up[2];\n\n\ttess.xyz[ndx+3][0] = origin[0] + left[0] - up[0];\n\ttess.xyz[ndx+3][1] = origin[1] + left[1] - up[1];\n\ttess.xyz[ndx+3][2] = origin[2] + left[2] - up[2];\n\n\n\t// constant normal all the way around\n\tVectorSubtract( vec3_origin, backEnd.viewParms.or.axis[0], normal );\n\n\ttess.normal[ndx][0] = tess.normal[ndx+1][0] = tess.normal[ndx+2][0] = tess.normal[ndx+3][0] = normal[0];\n\ttess.normal[ndx][1] = tess.normal[ndx+1][1] = tess.normal[ndx+2][1] = tess.normal[ndx+3][1] = normal[1];\n\ttess.normal[ndx][2] = tess.normal[ndx+1][2] = tess.normal[ndx+2][2] = tess.normal[ndx+3][2] = normal[2];\n\t\n\t// standard square texture coordinates\n\ttess.texCoords[ndx][0][0] = tess.texCoords[ndx][1][0] = s1;\n\ttess.texCoords[ndx][0][1] = tess.texCoords[ndx][1][1] = t1;\n\n\ttess.texCoords[ndx+1][0][0] = tess.texCoords[ndx+1][1][0] = s2;\n\ttess.texCoords[ndx+1][0][1] = tess.texCoords[ndx+1][1][1] = t1;\n\n\ttess.texCoords[ndx+2][0][0] = tess.texCoords[ndx+2][1][0] = s2;\n\ttess.texCoords[ndx+2][0][1] = tess.texCoords[ndx+2][1][1] = t2;\n\n\ttess.texCoords[ndx+3][0][0] = tess.texCoords[ndx+3][1][0] = s1;\n\ttess.texCoords[ndx+3][0][1] = tess.texCoords[ndx+3][1][1] = t2;\n\n\t// constant color all the way around\n\t// should this be identity and let the shader specify from entity?\n\t* ( unsigned int * ) &tess.vertexColors[ndx] = \n\t* ( unsigned int * ) &tess.vertexColors[ndx+1] = \n\t* ( unsigned int * ) &tess.vertexColors[ndx+2] = \n\t* ( unsigned int * ) &tess.vertexColors[ndx+3] = \n\t\t* ( unsigned int * )color;\n\n\n\ttess.numVertexes += 4;\n\ttess.numIndexes += 6;\n}\n\n/*\n==============\nRB_AddQuadStamp\n==============\n*/\nvoid RB_AddQuadStamp( vec3_t origin, vec3_t left, vec3_t up, byte *color ) {\n\tRB_AddQuadStampExt( origin, left, up, color, 0, 0, 1, 1 );\n}\n\n/*\n==============\nRB_SurfaceSprite\n==============\n*/\nstatic void RB_SurfaceSprite( void ) {\n\tvec3_t\t\tleft, up;\n\tfloat\t\tradius;\n\n\t// calculate the xyz locations for the four corners\n\tradius = backEnd.currentEntity->e.radius;\n\tif ( backEnd.currentEntity->e.rotation == 0 ) {\n\t\tVectorScale( backEnd.viewParms.or.axis[1], radius, left );\n\t\tVectorScale( backEnd.viewParms.or.axis[2], radius, up );\n\t} else {\n\t\tfloat\ts, c;\n\t\tfloat\tang;\n\t\t\n\t\tang = M_PI * backEnd.currentEntity->e.rotation / 180;\n\t\ts = sin( ang );\n\t\tc = cos( ang );\n\n\t\tVectorScale( backEnd.viewParms.or.axis[1], c * radius, left );\n\t\tVectorMA( left, -s * radius, backEnd.viewParms.or.axis[2], left );\n\n\t\tVectorScale( backEnd.viewParms.or.axis[2], c * radius, up );\n\t\tVectorMA( up, s * radius, backEnd.viewParms.or.axis[1], up );\n\t}\n\tif ( backEnd.viewParms.isMirror ) {\n\t\tVectorSubtract( vec3_origin, left, left );\n\t}\n\n\tRB_AddQuadStamp( backEnd.currentEntity->e.origin, left, up, backEnd.currentEntity->e.shaderRGBA );\n}\n\n\n/*\n=============\nRB_SurfacePolychain\n=============\n*/\nvoid RB_SurfacePolychain( srfPoly_t *p ) {\n\tint\t\ti;\n\tint\t\tnumv;\n\n\tRB_CHECKOVERFLOW( p->numVerts, 3*(p->numVerts - 2) );\n\n\t// fan triangles into the tess array\n\tnumv = tess.numVertexes;\n\tfor ( i = 0; i < p->numVerts; i++ ) {\n\t\tVectorCopy( p->verts[i].xyz, tess.xyz[numv] );\n\t\ttess.texCoords[numv][0][0] = p->verts[i].st[0];\n\t\ttess.texCoords[numv][0][1] = p->verts[i].st[1];\n\t\t*(int *)&tess.vertexColors[numv] = *(int *)p->verts[ i ].modulate;\n\n\t\tnumv++;\n\t}\n\n\t// generate fan indexes into the tess array\n\tfor ( i = 0; i < p->numVerts-2; i++ ) {\n\t\ttess.indexes[tess.numIndexes + 0] = tess.numVertexes;\n\t\ttess.indexes[tess.numIndexes + 1] = tess.numVertexes + i + 1;\n\t\ttess.indexes[tess.numIndexes + 2] = tess.numVertexes + i + 2;\n\t\ttess.numIndexes += 3;\n\t}\n\n\ttess.numVertexes = numv;\n}\n\n\n/*\n=============\nRB_SurfaceTriangles\n=============\n*/\nvoid RB_SurfaceTriangles( srfTriangles_t *srf ) {\n\tint\t\t\ti;\n\tdrawVert_t\t*dv;\n\tfloat\t\t*xyz, *normal, *texCoords;\n\tbyte\t\t*color;\n\tint\t\t\tdlightBits;\n\tqboolean\tneedsNormal;\n\n\tdlightBits = srf->dlightBits[backEnd.smpFrame];\n\ttess.dlightBits |= dlightBits;\n\n\tRB_CHECKOVERFLOW( srf->numVerts, srf->numIndexes );\n\n\tfor ( i = 0 ; i < srf->numIndexes ; i += 3 ) {\n\t\ttess.indexes[ tess.numIndexes + i + 0 ] = tess.numVertexes + srf->indexes[ i + 0 ];\n\t\ttess.indexes[ tess.numIndexes + i + 1 ] = tess.numVertexes + srf->indexes[ i + 1 ];\n\t\ttess.indexes[ tess.numIndexes + i + 2 ] = tess.numVertexes + srf->indexes[ i + 2 ];\n\t}\n\ttess.numIndexes += srf->numIndexes;\n\n\tdv = srf->verts;\n\txyz = tess.xyz[ tess.numVertexes ];\n\tnormal = tess.normal[ tess.numVertexes ];\n\ttexCoords = tess.texCoords[ tess.numVertexes ][0];\n\tcolor = tess.vertexColors[ tess.numVertexes ];\n\tneedsNormal = tess.shader->needsNormal;\n\n\tfor ( i = 0 ; i < srf->numVerts ; i++, dv++, xyz += 4, normal += 4, texCoords += 4, color += 4 ) {\n\t\txyz[0] = dv->xyz[0];\n\t\txyz[1] = dv->xyz[1];\n\t\txyz[2] = dv->xyz[2];\n\n\t\tif ( needsNormal ) {\n\t\t\tnormal[0] = dv->normal[0];\n\t\t\tnormal[1] = dv->normal[1];\n\t\t\tnormal[2] = dv->normal[2];\n\t\t}\n\n\t\ttexCoords[0] = dv->st[0];\n\t\ttexCoords[1] = dv->st[1];\n\n\t\ttexCoords[2] = dv->lightmap[0];\n\t\ttexCoords[3] = dv->lightmap[1];\n\n\t\t*(int *)color = *(int *)dv->color;\n\t}\n\n\tfor ( i = 0 ; i < srf->numVerts ; i++ ) {\n\t\ttess.vertexDlightBits[ tess.numVertexes + i] = dlightBits;\n\t}\n\n\ttess.numVertexes += srf->numVerts;\n}\n\n\n\n/*\n==============\nRB_SurfaceBeam\n==============\n*/\nvoid RB_SurfaceBeam( void ) \n{\n#define NUM_BEAM_SEGS 6\n\trefEntity_t *e;\n\tint\ti;\n\tvec3_t perpvec;\n\tvec3_t direction, normalized_direction;\n\tvec3_t\tstart_points[NUM_BEAM_SEGS], end_points[NUM_BEAM_SEGS];\n\tvec3_t oldorigin, origin;\n\n\te = &backEnd.currentEntity->e;\n\n\toldorigin[0] = e->oldorigin[0];\n\toldorigin[1] = e->oldorigin[1];\n\toldorigin[2] = e->oldorigin[2];\n\n\torigin[0] = e->origin[0];\n\torigin[1] = e->origin[1];\n\torigin[2] = e->origin[2];\n\n\tnormalized_direction[0] = direction[0] = oldorigin[0] - origin[0];\n\tnormalized_direction[1] = direction[1] = oldorigin[1] - origin[1];\n\tnormalized_direction[2] = direction[2] = oldorigin[2] - origin[2];\n\n\tif ( VectorNormalize( normalized_direction ) == 0 )\n\t\treturn;\n\n\tPerpendicularVector( perpvec, normalized_direction );\n\n\tVectorScale( perpvec, 4, perpvec );\n\n\tfor ( i = 0; i < NUM_BEAM_SEGS ; i++ )\n\t{\n\t\tRotatePointAroundVector( start_points[i], normalized_direction, perpvec, (360.0/NUM_BEAM_SEGS)*i );\n//\t\tVectorAdd( start_points[i], origin, start_points[i] );\n\t\tVectorAdd( start_points[i], direction, end_points[i] );\n\t}\n\n\tGL_Bind( tr.whiteImage );\n\n\tGL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );\n\n\tqglColor3f( 1, 0, 0 );\n\n\tqglBegin( GL_TRIANGLE_STRIP );\n\tfor ( i = 0; i <= NUM_BEAM_SEGS; i++ ) {\n\t\tqglVertex3fv( start_points[ i % NUM_BEAM_SEGS] );\n\t\tqglVertex3fv( end_points[ i % NUM_BEAM_SEGS] );\n\t}\n\tqglEnd();\n}\n\n//================================================================================\n\nstatic void DoRailCore( const vec3_t start, const vec3_t end, const vec3_t up, float len, float spanWidth )\n{\n\tfloat\t\tspanWidth2;\n\tint\t\t\tvbase;\n\tfloat\t\tt = len / 256.0f;\n\n\tvbase = tess.numVertexes;\n\n\tspanWidth2 = -spanWidth;\n\n\t// FIXME: use quad stamp?\n\tVectorMA( start, spanWidth, up, tess.xyz[tess.numVertexes] );\n\ttess.texCoords[tess.numVertexes][0][0] = 0;\n\ttess.texCoords[tess.numVertexes][0][1] = 0;\n\ttess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0] * 0.25;\n\ttess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1] * 0.25;\n\ttess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2] * 0.25;\n\ttess.numVertexes++;\n\n\tVectorMA( start, spanWidth2, up, tess.xyz[tess.numVertexes] );\n\ttess.texCoords[tess.numVertexes][0][0] = 0;\n\ttess.texCoords[tess.numVertexes][0][1] = 1;\n\ttess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0];\n\ttess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1];\n\ttess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2];\n\ttess.numVertexes++;\n\n\tVectorMA( end, spanWidth, up, tess.xyz[tess.numVertexes] );\n\n\ttess.texCoords[tess.numVertexes][0][0] = t;\n\ttess.texCoords[tess.numVertexes][0][1] = 0;\n\ttess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0];\n\ttess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1];\n\ttess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2];\n\ttess.numVertexes++;\n\n\tVectorMA( end, spanWidth2, up, tess.xyz[tess.numVertexes] );\n\ttess.texCoords[tess.numVertexes][0][0] = t;\n\ttess.texCoords[tess.numVertexes][0][1] = 1;\n\ttess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0];\n\ttess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1];\n\ttess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2];\n\ttess.numVertexes++;\n\n\ttess.indexes[tess.numIndexes++] = vbase;\n\ttess.indexes[tess.numIndexes++] = vbase + 1;\n\ttess.indexes[tess.numIndexes++] = vbase + 2;\n\n\ttess.indexes[tess.numIndexes++] = vbase + 2;\n\ttess.indexes[tess.numIndexes++] = vbase + 1;\n\ttess.indexes[tess.numIndexes++] = vbase + 3;\n}\n\nstatic void DoRailDiscs( int numSegs, const vec3_t start, const vec3_t dir, const vec3_t right, const vec3_t up )\n{\n\tint i;\n\tvec3_t\tpos[4];\n\tvec3_t\tv;\n\tint\t\tspanWidth = r_railWidth->integer;\n\tfloat c, s;\n\tfloat\t\tscale;\n\n\tif ( numSegs > 1 )\n\t\tnumSegs--;\n\tif ( !numSegs )\n\t\treturn;\n\n\tscale = 0.25;\n\n\tfor ( i = 0; i < 4; i++ )\n\t{\n\t\tc = cos( DEG2RAD( 45 + i * 90 ) );\n\t\ts = sin( DEG2RAD( 45 + i * 90 ) );\n\t\tv[0] = ( right[0] * c + up[0] * s ) * scale * spanWidth;\n\t\tv[1] = ( right[1] * c + up[1] * s ) * scale * spanWidth;\n\t\tv[2] = ( right[2] * c + up[2] * s ) * scale * spanWidth;\n\t\tVectorAdd( start, v, pos[i] );\n\n\t\tif ( numSegs > 1 )\n\t\t{\n\t\t\t// offset by 1 segment if we're doing a long distance shot\n\t\t\tVectorAdd( pos[i], dir, pos[i] );\n\t\t}\n\t}\n\n\tfor ( i = 0; i < numSegs; i++ )\n\t{\n\t\tint j;\n\n\t\tRB_CHECKOVERFLOW( 4, 6 );\n\n\t\tfor ( j = 0; j < 4; j++ )\n\t\t{\n\t\t\tVectorCopy( pos[j], tess.xyz[tess.numVertexes] );\n\t\t\ttess.texCoords[tess.numVertexes][0][0] = ( j < 2 );\n\t\t\ttess.texCoords[tess.numVertexes][0][1] = ( j && j != 3 );\n\t\t\ttess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0];\n\t\t\ttess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1];\n\t\t\ttess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2];\n\t\t\ttess.numVertexes++;\n\n\t\t\tVectorAdd( pos[j], dir, pos[j] );\n\t\t}\n\n\t\ttess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 0;\n\t\ttess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 1;\n\t\ttess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 3;\n\t\ttess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 3;\n\t\ttess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 1;\n\t\ttess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 2;\n\t}\n}\n\n/*\n** RB_SurfaceRailRinges\n*/\nvoid RB_SurfaceRailRings( void ) {\n\trefEntity_t *e;\n\tint\t\t\tnumSegs;\n\tint\t\t\tlen;\n\tvec3_t\t\tvec;\n\tvec3_t\t\tright, up;\n\tvec3_t\t\tstart, end;\n\n\te = &backEnd.currentEntity->e;\n\n\tVectorCopy( e->oldorigin, start );\n\tVectorCopy( e->origin, end );\n\n\t// compute variables\n\tVectorSubtract( end, start, vec );\n\tlen = VectorNormalize( vec );\n\tMakeNormalVectors( vec, right, up );\n\tnumSegs = ( len ) / r_railSegmentLength->value;\n\tif ( numSegs <= 0 ) {\n\t\tnumSegs = 1;\n\t}\n\n\tVectorScale( vec, r_railSegmentLength->value, vec );\n\n\tDoRailDiscs( numSegs, start, vec, right, up );\n}\n\n/*\n** RB_SurfaceRailCore\n*/\nvoid RB_SurfaceRailCore( void ) {\n\trefEntity_t *e;\n\tint\t\t\tlen;\n\tvec3_t\t\tright;\n\tvec3_t\t\tvec;\n\tvec3_t\t\tstart, end;\n\tvec3_t\t\tv1, v2;\n\n\te = &backEnd.currentEntity->e;\n\n\tVectorCopy( e->oldorigin, start );\n\tVectorCopy( e->origin, end );\n\n\tVectorSubtract( end, start, vec );\n\tlen = VectorNormalize( vec );\n\n\t// compute side vector\n\tVectorSubtract( start, backEnd.viewParms.or.origin, v1 );\n\tVectorNormalize( v1 );\n\tVectorSubtract( end, backEnd.viewParms.or.origin, v2 );\n\tVectorNormalize( v2 );\n\tCrossProduct( v1, v2, right );\n\tVectorNormalize( right );\n\n\tDoRailCore( start, end, right, len, r_railCoreWidth->integer );\n}\n\n/*\n** RB_SurfaceLightningBolt\n*/\nvoid RB_SurfaceLightningBolt( void ) {\n\trefEntity_t *e;\n\tint\t\t\tlen;\n\tvec3_t\t\tright;\n\tvec3_t\t\tvec;\n\tvec3_t\t\tstart, end;\n\tvec3_t\t\tv1, v2;\n\tint\t\t\ti;\n\n\te = &backEnd.currentEntity->e;\n\n\tVectorCopy( e->oldorigin, end );\n\tVectorCopy( e->origin, start );\n\n\t// compute variables\n\tVectorSubtract( end, start, vec );\n\tlen = VectorNormalize( vec );\n\n\t// compute side vector\n\tVectorSubtract( start, backEnd.viewParms.or.origin, v1 );\n\tVectorNormalize( v1 );\n\tVectorSubtract( end, backEnd.viewParms.or.origin, v2 );\n\tVectorNormalize( v2 );\n\tCrossProduct( v1, v2, right );\n\tVectorNormalize( right );\n\n\tfor ( i = 0 ; i < 4 ; i++ ) {\n\t\tvec3_t\ttemp;\n\n\t\tDoRailCore( start, end, right, len, 8 );\n\t\tRotatePointAroundVector( temp, vec, right, 45 );\n\t\tVectorCopy( temp, right );\n\t}\n}\n\n/*\n** VectorArrayNormalize\n*\n* The inputs to this routing seem to always be close to length = 1.0 (about 0.6 to 2.0)\n* This means that we don't have to worry about zero length or enormously long vectors.\n*/\nstatic void VectorArrayNormalize(vec4_t *normals, unsigned int count)\n{\n//    assert(count);\n        \n#if idppc\n    {\n        register float half = 0.5;\n        register float one  = 1.0;\n        float *components = (float *)normals;\n        \n        // Vanilla PPC code, but since PPC has a reciprocal square root estimate instruction,\n        // runs *much* faster than calling sqrt().  We'll use a single Newton-Raphson\n        // refinement step to get a little more precision.  This seems to yeild results\n        // that are correct to 3 decimal places and usually correct to at least 4 (sometimes 5).\n        // (That is, for the given input range of about 0.6 to 2.0).\n        do {\n            float x, y, z;\n            float B, y0, y1;\n            \n            x = components[0];\n            y = components[1];\n            z = components[2];\n            components += 4;\n            B = x*x + y*y + z*z;\n\n#ifdef __GNUC__            \n            asm(\"frsqrte %0,%1\" : \"=f\" (y0) : \"f\" (B));\n#else\n\t\t\ty0 = __frsqrte(B);\n#endif\n            y1 = y0 + half*y0*(one - B*y0*y0);\n\n            x = x * y1;\n            y = y * y1;\n            components[-4] = x;\n            z = z * y1;\n            components[-3] = y;\n            components[-2] = z;\n        } while(count--);\n    }\n#else // No assembly version for this architecture, or C_ONLY defined\n\t// given the input, it's safe to call VectorNormalizeFast\n    while (count--) {\n        VectorNormalizeFast(normals[0]);\n        normals++;\n    }\n#endif\n\n}\n\n\n\n/*\n** LerpMeshVertexes\n*/\nstatic void LerpMeshVertexes (md3Surface_t *surf, float backlerp) \n{\n\tshort\t*oldXyz, *newXyz, *oldNormals, *newNormals;\n\tfloat\t*outXyz, *outNormal;\n\tfloat\toldXyzScale, newXyzScale;\n\tfloat\toldNormalScale, newNormalScale;\n\tint\t\tvertNum;\n\tunsigned lat, lng;\n\tint\t\tnumVerts;\n\n\toutXyz = tess.xyz[tess.numVertexes];\n\toutNormal = tess.normal[tess.numVertexes];\n\n\tnewXyz = (short *)((byte *)surf + surf->ofsXyzNormals)\n\t\t+ (backEnd.currentEntity->e.frame * surf->numVerts * 4);\n\tnewNormals = newXyz + 3;\n\n\tnewXyzScale = MD3_XYZ_SCALE * (1.0 - backlerp);\n\tnewNormalScale = 1.0 - backlerp;\n\n\tnumVerts = surf->numVerts;\n\n\tif ( backlerp == 0 ) {\n#if idppc_altivec\n\t\tvector signed short newNormalsVec0;\n\t\tvector signed short newNormalsVec1;\n\t\tvector signed int newNormalsIntVec;\n\t\tvector float newNormalsFloatVec;\n\t\tvector float newXyzScaleVec;\n\t\tvector unsigned char newNormalsLoadPermute;\n\t\tvector unsigned char newNormalsStorePermute;\n\t\tvector float zero;\n\t\t\n\t\tnewNormalsStorePermute = vec_lvsl(0,(float *)&newXyzScaleVec);\n\t\tnewXyzScaleVec = *(vector float *)&newXyzScale;\n\t\tnewXyzScaleVec = vec_perm(newXyzScaleVec,newXyzScaleVec,newNormalsStorePermute);\n\t\tnewXyzScaleVec = vec_splat(newXyzScaleVec,0);\t\t\n\t\tnewNormalsLoadPermute = vec_lvsl(0,newXyz);\n\t\tnewNormalsStorePermute = vec_lvsr(0,outXyz);\n\t\tzero = (vector float)vec_splat_s8(0);\n\t\t//\n\t\t// just copy the vertexes\n\t\t//\n\t\tfor (vertNum=0 ; vertNum < numVerts ; vertNum++,\n\t\t\tnewXyz += 4, newNormals += 4,\n\t\t\toutXyz += 4, outNormal += 4) \n\t\t{\n\t\t\tnewNormalsLoadPermute = vec_lvsl(0,newXyz);\n\t\t\tnewNormalsStorePermute = vec_lvsr(0,outXyz);\n\t\t\tnewNormalsVec0 = vec_ld(0,newXyz);\n\t\t\tnewNormalsVec1 = vec_ld(16,newXyz);\n\t\t\tnewNormalsVec0 = vec_perm(newNormalsVec0,newNormalsVec1,newNormalsLoadPermute);\n\t\t\tnewNormalsIntVec = vec_unpackh(newNormalsVec0);\n\t\t\tnewNormalsFloatVec = vec_ctf(newNormalsIntVec,0);\n\t\t\tnewNormalsFloatVec = vec_madd(newNormalsFloatVec,newXyzScaleVec,zero);\n\t\t\tnewNormalsFloatVec = vec_perm(newNormalsFloatVec,newNormalsFloatVec,newNormalsStorePermute);\n\t\t\t//outXyz[0] = newXyz[0] * newXyzScale;\n\t\t\t//outXyz[1] = newXyz[1] * newXyzScale;\n\t\t\t//outXyz[2] = newXyz[2] * newXyzScale;\n\n\t\t\tlat = ( newNormals[0] >> 8 ) & 0xff;\n\t\t\tlng = ( newNormals[0] & 0xff );\n\t\t\tlat *= (FUNCTABLE_SIZE/256);\n\t\t\tlng *= (FUNCTABLE_SIZE/256);\n\n\t\t\t// decode X as cos( lat ) * sin( long )\n\t\t\t// decode Y as sin( lat ) * sin( long )\n\t\t\t// decode Z as cos( long )\n\n\t\t\toutNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];\n\t\t\toutNormal[1] = tr.sinTable[lat] * tr.sinTable[lng];\n\t\t\toutNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];\n\n\t\t\tvec_ste(newNormalsFloatVec,0,outXyz);\n\t\t\tvec_ste(newNormalsFloatVec,4,outXyz);\n\t\t\tvec_ste(newNormalsFloatVec,8,outXyz);\n\t\t}\n\t\t\n#else\n\t\t//\n\t\t// just copy the vertexes\n\t\t//\n\t\tfor (vertNum=0 ; vertNum < numVerts ; vertNum++,\n\t\t\tnewXyz += 4, newNormals += 4,\n\t\t\toutXyz += 4, outNormal += 4) \n\t\t{\n\n\t\t\toutXyz[0] = newXyz[0] * newXyzScale;\n\t\t\toutXyz[1] = newXyz[1] * newXyzScale;\n\t\t\toutXyz[2] = newXyz[2] * newXyzScale;\n\n\t\t\tlat = ( newNormals[0] >> 8 ) & 0xff;\n\t\t\tlng = ( newNormals[0] & 0xff );\n\t\t\tlat *= (FUNCTABLE_SIZE/256);\n\t\t\tlng *= (FUNCTABLE_SIZE/256);\n\n\t\t\t// decode X as cos( lat ) * sin( long )\n\t\t\t// decode Y as sin( lat ) * sin( long )\n\t\t\t// decode Z as cos( long )\n\n\t\t\toutNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];\n\t\t\toutNormal[1] = tr.sinTable[lat] * tr.sinTable[lng];\n\t\t\toutNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];\n\t\t}\n#endif\n\t} else {\n\t\t//\n\t\t// interpolate and copy the vertex and normal\n\t\t//\n\t\toldXyz = (short *)((byte *)surf + surf->ofsXyzNormals)\n\t\t\t+ (backEnd.currentEntity->e.oldframe * surf->numVerts * 4);\n\t\toldNormals = oldXyz + 3;\n\n\t\toldXyzScale = MD3_XYZ_SCALE * backlerp;\n\t\toldNormalScale = backlerp;\n\n\t\tfor (vertNum=0 ; vertNum < numVerts ; vertNum++,\n\t\t\toldXyz += 4, newXyz += 4, oldNormals += 4, newNormals += 4,\n\t\t\toutXyz += 4, outNormal += 4) \n\t\t{\n\t\t\tvec3_t uncompressedOldNormal, uncompressedNewNormal;\n\n\t\t\t// interpolate the xyz\n\t\t\toutXyz[0] = oldXyz[0] * oldXyzScale + newXyz[0] * newXyzScale;\n\t\t\toutXyz[1] = oldXyz[1] * oldXyzScale + newXyz[1] * newXyzScale;\n\t\t\toutXyz[2] = oldXyz[2] * oldXyzScale + newXyz[2] * newXyzScale;\n\n\t\t\t// FIXME: interpolate lat/long instead?\n\t\t\tlat = ( newNormals[0] >> 8 ) & 0xff;\n\t\t\tlng = ( newNormals[0] & 0xff );\n\t\t\tlat *= 4;\n\t\t\tlng *= 4;\n\t\t\tuncompressedNewNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];\n\t\t\tuncompressedNewNormal[1] = tr.sinTable[lat] * tr.sinTable[lng];\n\t\t\tuncompressedNewNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];\n\n\t\t\tlat = ( oldNormals[0] >> 8 ) & 0xff;\n\t\t\tlng = ( oldNormals[0] & 0xff );\n\t\t\tlat *= 4;\n\t\t\tlng *= 4;\n\n\t\t\tuncompressedOldNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];\n\t\t\tuncompressedOldNormal[1] = tr.sinTable[lat] * tr.sinTable[lng];\n\t\t\tuncompressedOldNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];\n\n\t\t\toutNormal[0] = uncompressedOldNormal[0] * oldNormalScale + uncompressedNewNormal[0] * newNormalScale;\n\t\t\toutNormal[1] = uncompressedOldNormal[1] * oldNormalScale + uncompressedNewNormal[1] * newNormalScale;\n\t\t\toutNormal[2] = uncompressedOldNormal[2] * oldNormalScale + uncompressedNewNormal[2] * newNormalScale;\n\n//\t\t\tVectorNormalize (outNormal);\n\t\t}\n    \tVectorArrayNormalize((vec4_t *)tess.normal[tess.numVertexes], numVerts);\n   \t}\n}\n\n/*\n=============\nRB_SurfaceMesh\n=============\n*/\nvoid RB_SurfaceMesh(md3Surface_t *surface) {\n\tint\t\t\t\tj;\n\tfloat\t\t\tbacklerp;\n\tint\t\t\t\t*triangles;\n\tfloat\t\t\t*texCoords;\n\tint\t\t\t\tindexes;\n\tint\t\t\t\tBob, Doug;\n\tint\t\t\t\tnumVerts;\n\n\tif (  backEnd.currentEntity->e.oldframe == backEnd.currentEntity->e.frame ) {\n\t\tbacklerp = 0;\n\t} else  {\n\t\tbacklerp = backEnd.currentEntity->e.backlerp;\n\t}\n\n\tRB_CHECKOVERFLOW( surface->numVerts, surface->numTriangles*3 );\n\n\tLerpMeshVertexes (surface, backlerp);\n\n\ttriangles = (int *) ((byte *)surface + surface->ofsTriangles);\n\tindexes = surface->numTriangles * 3;\n\tBob = tess.numIndexes;\n\tDoug = tess.numVertexes;\n\tfor (j = 0 ; j < indexes ; j++) {\n\t\ttess.indexes[Bob + j] = Doug + triangles[j];\n\t}\n\ttess.numIndexes += indexes;\n\n\ttexCoords = (float *) ((byte *)surface + surface->ofsSt);\n\n\tnumVerts = surface->numVerts;\n\tfor ( j = 0; j < numVerts; j++ ) {\n\t\ttess.texCoords[Doug + j][0][0] = texCoords[j*2+0];\n\t\ttess.texCoords[Doug + j][0][1] = texCoords[j*2+1];\n\t\t// FIXME: fill in lightmapST for completeness?\n\t}\n\n\ttess.numVertexes += surface->numVerts;\n\n}\n\n\n/*\n==============\nRB_SurfaceFace\n==============\n*/\nvoid RB_SurfaceFace( srfSurfaceFace_t *surf ) {\n\tint\t\t\ti;\n\tunsigned\t*indices, *tessIndexes;\n\tfloat\t\t*v;\n\tfloat\t\t*normal;\n\tint\t\t\tndx;\n\tint\t\t\tBob;\n\tint\t\t\tnumPoints;\n\tint\t\t\tdlightBits;\n\n\tRB_CHECKOVERFLOW( surf->numPoints, surf->numIndices );\n\n\tdlightBits = surf->dlightBits[backEnd.smpFrame];\n\ttess.dlightBits |= dlightBits;\n\n\tindices = ( unsigned * ) ( ( ( char  * ) surf ) + surf->ofsIndices );\n\n\tBob = tess.numVertexes;\n\ttessIndexes = tess.indexes + tess.numIndexes;\n\tfor ( i = surf->numIndices-1 ; i >= 0  ; i-- ) {\n\t\ttessIndexes[i] = indices[i] + Bob;\n\t}\n\n\ttess.numIndexes += surf->numIndices;\n\n\tv = surf->points[0];\n\n\tndx = tess.numVertexes;\n\n\tnumPoints = surf->numPoints;\n\n\tif ( tess.shader->needsNormal ) {\n\t\tnormal = surf->plane.normal;\n\t\tfor ( i = 0, ndx = tess.numVertexes; i < numPoints; i++, ndx++ ) {\n\t\t\tVectorCopy( normal, tess.normal[ndx] );\n\t\t}\n\t}\n\n\tfor ( i = 0, v = surf->points[0], ndx = tess.numVertexes; i < numPoints; i++, v += VERTEXSIZE, ndx++ ) {\n\t\tVectorCopy( v, tess.xyz[ndx]);\n\t\ttess.texCoords[ndx][0][0] = v[3];\n\t\ttess.texCoords[ndx][0][1] = v[4];\n\t\ttess.texCoords[ndx][1][0] = v[5];\n\t\ttess.texCoords[ndx][1][1] = v[6];\n\t\t* ( unsigned int * ) &tess.vertexColors[ndx] = * ( unsigned int * ) &v[7];\n\t\ttess.vertexDlightBits[ndx] = dlightBits;\n\t}\n\n\n\ttess.numVertexes += surf->numPoints;\n}\n\n\nstatic float\tLodErrorForVolume( vec3_t local, float radius ) {\n\tvec3_t\t\tworld;\n\tfloat\t\td;\n\n\t// never let it go negative\n\tif ( r_lodCurveError->value < 0 ) {\n\t\treturn 0;\n\t}\n\n\tworld[0] = local[0] * backEnd.or.axis[0][0] + local[1] * backEnd.or.axis[1][0] + \n\t\tlocal[2] * backEnd.or.axis[2][0] + backEnd.or.origin[0];\n\tworld[1] = local[0] * backEnd.or.axis[0][1] + local[1] * backEnd.or.axis[1][1] + \n\t\tlocal[2] * backEnd.or.axis[2][1] + backEnd.or.origin[1];\n\tworld[2] = local[0] * backEnd.or.axis[0][2] + local[1] * backEnd.or.axis[1][2] + \n\t\tlocal[2] * backEnd.or.axis[2][2] + backEnd.or.origin[2];\n\n\tVectorSubtract( world, backEnd.viewParms.or.origin, world );\n\td = DotProduct( world, backEnd.viewParms.or.axis[0] );\n\n\tif ( d < 0 ) {\n\t\td = -d;\n\t}\n\td -= radius;\n\tif ( d < 1 ) {\n\t\td = 1;\n\t}\n\n\treturn r_lodCurveError->value / d;\n}\n\n/*\n=============\nRB_SurfaceGrid\n\nJust copy the grid of points and triangulate\n=============\n*/\nvoid RB_SurfaceGrid( srfGridMesh_t *cv ) {\n\tint\t\ti, j;\n\tfloat\t*xyz;\n\tfloat\t*texCoords;\n\tfloat\t*normal;\n\tunsigned char *color;\n\tdrawVert_t\t*dv;\n\tint\t\trows, irows, vrows;\n\tint\t\tused;\n\tint\t\twidthTable[MAX_GRID_SIZE];\n\tint\t\theightTable[MAX_GRID_SIZE];\n\tfloat\tlodError;\n\tint\t\tlodWidth, lodHeight;\n\tint\t\tnumVertexes;\n\tint\t\tdlightBits;\n\tint\t\t*vDlightBits;\n\tqboolean\tneedsNormal;\n\n\tdlightBits = cv->dlightBits[backEnd.smpFrame];\n\ttess.dlightBits |= dlightBits;\n\n\t// determine the allowable discrepance\n\tlodError = LodErrorForVolume( cv->lodOrigin, cv->lodRadius );\n\n\t// determine which rows and columns of the subdivision\n\t// we are actually going to use\n\twidthTable[0] = 0;\n\tlodWidth = 1;\n\tfor ( i = 1 ; i < cv->width-1 ; i++ ) {\n\t\tif ( cv->widthLodError[i] <= lodError ) {\n\t\t\twidthTable[lodWidth] = i;\n\t\t\tlodWidth++;\n\t\t}\n\t}\n\twidthTable[lodWidth] = cv->width-1;\n\tlodWidth++;\n\n\theightTable[0] = 0;\n\tlodHeight = 1;\n\tfor ( i = 1 ; i < cv->height-1 ; i++ ) {\n\t\tif ( cv->heightLodError[i] <= lodError ) {\n\t\t\theightTable[lodHeight] = i;\n\t\t\tlodHeight++;\n\t\t}\n\t}\n\theightTable[lodHeight] = cv->height-1;\n\tlodHeight++;\n\n\n\t// very large grids may have more points or indexes than can be fit\n\t// in the tess structure, so we may have to issue it in multiple passes\n\n\tused = 0;\n\trows = 0;\n\twhile ( used < lodHeight - 1 ) {\n\t\t// see how many rows of both verts and indexes we can add without overflowing\n\t\tdo {\n\t\t\tvrows = ( SHADER_MAX_VERTEXES - tess.numVertexes ) / lodWidth;\n\t\t\tirows = ( SHADER_MAX_INDEXES - tess.numIndexes ) / ( lodWidth * 6 );\n\n\t\t\t// if we don't have enough space for at least one strip, flush the buffer\n\t\t\tif ( vrows < 2 || irows < 1 ) {\n\t\t\t\tRB_EndSurface();\n\t\t\t\tRB_BeginSurface(tess.shader, tess.fogNum );\n\t\t\t} else {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t} while ( 1 );\n\t\t\n\t\trows = irows;\n\t\tif ( vrows < irows + 1 ) {\n\t\t\trows = vrows - 1;\n\t\t}\n\t\tif ( used + rows > lodHeight ) {\n\t\t\trows = lodHeight - used;\n\t\t}\n\n\t\tnumVertexes = tess.numVertexes;\n\n\t\txyz = tess.xyz[numVertexes];\n\t\tnormal = tess.normal[numVertexes];\n\t\ttexCoords = tess.texCoords[numVertexes][0];\n\t\tcolor = ( unsigned char * ) &tess.vertexColors[numVertexes];\n\t\tvDlightBits = &tess.vertexDlightBits[numVertexes];\n\t\tneedsNormal = tess.shader->needsNormal;\n\n\t\tfor ( i = 0 ; i < rows ; i++ ) {\n\t\t\tfor ( j = 0 ; j < lodWidth ; j++ ) {\n\t\t\t\tdv = cv->verts + heightTable[ used + i ] * cv->width\n\t\t\t\t\t+ widthTable[ j ];\n\n\t\t\t\txyz[0] = dv->xyz[0];\n\t\t\t\txyz[1] = dv->xyz[1];\n\t\t\t\txyz[2] = dv->xyz[2];\n\t\t\t\ttexCoords[0] = dv->st[0];\n\t\t\t\ttexCoords[1] = dv->st[1];\n\t\t\t\ttexCoords[2] = dv->lightmap[0];\n\t\t\t\ttexCoords[3] = dv->lightmap[1];\n\t\t\t\tif ( needsNormal ) {\n\t\t\t\t\tnormal[0] = dv->normal[0];\n\t\t\t\t\tnormal[1] = dv->normal[1];\n\t\t\t\t\tnormal[2] = dv->normal[2];\n\t\t\t\t}\n\t\t\t\t* ( unsigned int * ) color = * ( unsigned int * ) dv->color;\n\t\t\t\t*vDlightBits++ = dlightBits;\n\t\t\t\txyz += 4;\n\t\t\t\tnormal += 4;\n\t\t\t\ttexCoords += 4;\n\t\t\t\tcolor += 4;\n\t\t\t}\n\t\t}\n\n\n\t\t// add the indexes\n\t\t{\n\t\t\tint\t\tnumIndexes;\n\t\t\tint\t\tw, h;\n\n\t\t\th = rows - 1;\n\t\t\tw = lodWidth - 1;\n\t\t\tnumIndexes = tess.numIndexes;\n\t\t\tfor (i = 0 ; i < h ; i++) {\n\t\t\t\tfor (j = 0 ; j < w ; j++) {\n\t\t\t\t\tint\t\tv1, v2, v3, v4;\n\t\t\t\n\t\t\t\t\t// vertex order to be reckognized as tristrips\n\t\t\t\t\tv1 = numVertexes + i*lodWidth + j + 1;\n\t\t\t\t\tv2 = v1 - 1;\n\t\t\t\t\tv3 = v2 + lodWidth;\n\t\t\t\t\tv4 = v3 + 1;\n\n\t\t\t\t\ttess.indexes[numIndexes] = v2;\n\t\t\t\t\ttess.indexes[numIndexes+1] = v3;\n\t\t\t\t\ttess.indexes[numIndexes+2] = v1;\n\t\t\t\t\t\n\t\t\t\t\ttess.indexes[numIndexes+3] = v1;\n\t\t\t\t\ttess.indexes[numIndexes+4] = v3;\n\t\t\t\t\ttess.indexes[numIndexes+5] = v4;\n\t\t\t\t\tnumIndexes += 6;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttess.numIndexes = numIndexes;\n\t\t}\n\n\t\ttess.numVertexes += rows * lodWidth;\n\n\t\tused += rows - 1;\n\t}\n}\n\n\n/*\n===========================================================================\n\nNULL MODEL\n\n===========================================================================\n*/\n\n/*\n===================\nRB_SurfaceAxis\n\nDraws x/y/z lines from the origin for orientation debugging\n===================\n*/\nvoid RB_SurfaceAxis( void ) {\n\tGL_Bind( tr.whiteImage );\n\tqglLineWidth( 3 );\n\tqglBegin( GL_LINES );\n\tqglColor3f( 1,0,0 );\n\tqglVertex3f( 0,0,0 );\n\tqglVertex3f( 16,0,0 );\n\tqglColor3f( 0,1,0 );\n\tqglVertex3f( 0,0,0 );\n\tqglVertex3f( 0,16,0 );\n\tqglColor3f( 0,0,1 );\n\tqglVertex3f( 0,0,0 );\n\tqglVertex3f( 0,0,16 );\n\tqglEnd();\n\tqglLineWidth( 1 );\n}\n\n//===========================================================================\n\n/*\n====================\nRB_SurfaceEntity\n\nEntities that have a single procedurally generated surface\n====================\n*/\nvoid RB_SurfaceEntity( surfaceType_t *surfType ) {\n\tswitch( backEnd.currentEntity->e.reType ) {\n\tcase RT_SPRITE:\n\t\tRB_SurfaceSprite();\n\t\tbreak;\n\tcase RT_BEAM:\n\t\tRB_SurfaceBeam();\n\t\tbreak;\n\tcase RT_RAIL_CORE:\n\t\tRB_SurfaceRailCore();\n\t\tbreak;\n\tcase RT_RAIL_RINGS:\n\t\tRB_SurfaceRailRings();\n\t\tbreak;\n\tcase RT_LIGHTNING:\n\t\tRB_SurfaceLightningBolt();\n\t\tbreak;\n\tdefault:\n\t\tRB_SurfaceAxis();\n\t\tbreak;\n\t}\n\treturn;\n}\n\nvoid RB_SurfaceBad( surfaceType_t *surfType ) {\n\tri.Printf( PRINT_ALL, \"Bad surface tesselated.\\n\" );\n}\n\nvoid RB_SurfaceSkip( void *surf ) {\n}\n\n\nvoid (*rb_surfaceTable[SF_NUM_SURFACE_TYPES])( void *) = {\n\t(void(*)(void*))RB_SurfaceBad,\t\t\t// SF_BAD, \n\t(void(*)(void*))RB_SurfaceSkip,\t\t\t// SF_SKIP, \n\t(void(*)(void*))RB_SurfaceFace,\t\t\t// SF_FACE,\n\t(void(*)(void*))RB_SurfaceGrid,\t\t\t// SF_GRID,\n\t(void(*)(void*))RB_SurfaceTriangles,\t// SF_TRIANGLES,\n\t(void(*)(void*))RB_SurfacePolychain,\t// SF_POLY,\n\t(void(*)(void*))RB_SurfaceMesh,\t\t\t// SF_MD3,\n\t(void(*)(void*))RB_SurfaceAnim,\t\t\t// SF_MD4,\n\t(void(*)(void*))RB_SurfaceSkip,\t\t    // SF_FLARE,\n\t(void(*)(void*))RB_SurfaceEntity,\t\t// SF_ENTITY\n};\n"
  },
  {
    "path": "src/engine/renderer/tr_world.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n#include \"tr_local.h\"\n\n\n\n/*\n=================\nR_CullTriSurf\n\nReturns true if the grid is completely culled away.\nAlso sets the clipped hint bit in tess\n=================\n*/\nstatic qboolean\tR_CullTriSurf( srfTriangles_t *cv ) {\n\tint \tboxCull;\n\n\tboxCull = R_CullLocalBox( cv->bounds );\n\n\tif ( boxCull == CULL_OUT ) {\n\t\treturn qtrue;\n\t}\n\treturn qfalse;\n}\n\n/*\n=================\nR_CullGrid\n\nReturns true if the grid is completely culled away.\nAlso sets the clipped hint bit in tess\n=================\n*/\nstatic qboolean\tR_CullGrid( srfGridMesh_t *cv ) {\n\tint \tboxCull;\n\tint \tsphereCull;\n\n\tif ( r_nocurves->integer ) {\n\t\treturn qtrue;\n\t}\n\n\tif ( tr.currentEntityNum != ENTITYNUM_WORLD ) {\n\t\tsphereCull = R_CullLocalPointAndRadius( cv->localOrigin, cv->meshRadius );\n\t} else {\n\t\tsphereCull = R_CullPointAndRadius( cv->localOrigin, cv->meshRadius );\n\t}\n\tboxCull = CULL_OUT;\n\t\n\t// check for trivial reject\n\tif ( sphereCull == CULL_OUT )\n\t{\n\t\ttr.pc.c_sphere_cull_patch_out++;\n\t\treturn qtrue;\n\t}\n\t// check bounding box if necessary\n\telse if ( sphereCull == CULL_CLIP )\n\t{\n\t\ttr.pc.c_sphere_cull_patch_clip++;\n\n\t\tboxCull = R_CullLocalBox( cv->meshBounds );\n\n\t\tif ( boxCull == CULL_OUT ) \n\t\t{\n\t\t\ttr.pc.c_box_cull_patch_out++;\n\t\t\treturn qtrue;\n\t\t}\n\t\telse if ( boxCull == CULL_IN )\n\t\t{\n\t\t\ttr.pc.c_box_cull_patch_in++;\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttr.pc.c_box_cull_patch_clip++;\n\t\t}\n\t}\n\telse\n\t{\n\t\ttr.pc.c_sphere_cull_patch_in++;\n\t}\n\n\treturn qfalse;\n}\n\n\n/*\n================\nR_CullSurface\n\nTries to back face cull surfaces before they are lighted or\nadded to the sorting list.\n\nThis will also allow mirrors on both sides of a model without recursion.\n================\n*/\nstatic qboolean\tR_CullSurface( surfaceType_t *surface, shader_t *shader ) {\n\tsrfSurfaceFace_t *sface;\n\tfloat\t\t\td;\n\n\tif ( r_nocull->integer ) {\n\t\treturn qfalse;\n\t}\n\n\tif ( *surface == SF_GRID ) {\n\t\treturn R_CullGrid( (srfGridMesh_t *)surface );\n\t}\n\n\tif ( *surface == SF_TRIANGLES ) {\n\t\treturn R_CullTriSurf( (srfTriangles_t *)surface );\n\t}\n\n\tif ( *surface != SF_FACE ) {\n\t\treturn qfalse;\n\t}\n\n\tif ( shader->cullType == CT_TWO_SIDED ) {\n\t\treturn qfalse;\n\t}\n\n\t// face culling\n\tif ( !r_facePlaneCull->integer ) {\n\t\treturn qfalse;\n\t}\n\n\tsface = ( srfSurfaceFace_t * ) surface;\n\td = DotProduct (tr.or.viewOrigin, sface->plane.normal);\n\n\t// don't cull exactly on the plane, because there are levels of rounding\n\t// through the BSP, ICD, and hardware that may cause pixel gaps if an\n\t// epsilon isn't allowed here \n\tif ( shader->cullType == CT_FRONT_SIDED ) {\n\t\tif ( d < sface->plane.dist - 8 ) {\n\t\t\treturn qtrue;\n\t\t}\n\t} else {\n\t\tif ( d > sface->plane.dist + 8 ) {\n\t\t\treturn qtrue;\n\t\t}\n\t}\n\n\treturn qfalse;\n}\n\n\nstatic int R_DlightFace( srfSurfaceFace_t *face, int dlightBits ) {\n\tfloat\t\td;\n\tint\t\t\ti;\n\tdlight_t\t*dl;\n\n\tfor ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) {\n\t\tif ( ! ( dlightBits & ( 1 << i ) ) ) {\n\t\t\tcontinue;\n\t\t}\n\t\tdl = &tr.refdef.dlights[i];\n\t\td = DotProduct( dl->origin, face->plane.normal ) - face->plane.dist;\n\t\tif ( d < -dl->radius || d > dl->radius ) {\n\t\t\t// dlight doesn't reach the plane\n\t\t\tdlightBits &= ~( 1 << i );\n\t\t}\n\t}\n\n\tif ( !dlightBits ) {\n\t\ttr.pc.c_dlightSurfacesCulled++;\n\t}\n\n\tface->dlightBits[ tr.smpFrame ] = dlightBits;\n\treturn dlightBits;\n}\n\nstatic int R_DlightGrid( srfGridMesh_t *grid, int dlightBits ) {\n\tint\t\t\ti;\n\tdlight_t\t*dl;\n\n\tfor ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) {\n\t\tif ( ! ( dlightBits & ( 1 << i ) ) ) {\n\t\t\tcontinue;\n\t\t}\n\t\tdl = &tr.refdef.dlights[i];\n\t\tif ( dl->origin[0] - dl->radius > grid->meshBounds[1][0]\n\t\t\t|| dl->origin[0] + dl->radius < grid->meshBounds[0][0]\n\t\t\t|| dl->origin[1] - dl->radius > grid->meshBounds[1][1]\n\t\t\t|| dl->origin[1] + dl->radius < grid->meshBounds[0][1]\n\t\t\t|| dl->origin[2] - dl->radius > grid->meshBounds[1][2]\n\t\t\t|| dl->origin[2] + dl->radius < grid->meshBounds[0][2] ) {\n\t\t\t// dlight doesn't reach the bounds\n\t\t\tdlightBits &= ~( 1 << i );\n\t\t}\n\t}\n\n\tif ( !dlightBits ) {\n\t\ttr.pc.c_dlightSurfacesCulled++;\n\t}\n\n\tgrid->dlightBits[ tr.smpFrame ] = dlightBits;\n\treturn dlightBits;\n}\n\n\nstatic int R_DlightTrisurf( srfTriangles_t *surf, int dlightBits ) {\n\t// FIXME: more dlight culling to trisurfs...\n\tsurf->dlightBits[ tr.smpFrame ] = dlightBits;\n\treturn dlightBits;\n#if 0\n\tint\t\t\ti;\n\tdlight_t\t*dl;\n\n\tfor ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) {\n\t\tif ( ! ( dlightBits & ( 1 << i ) ) ) {\n\t\t\tcontinue;\n\t\t}\n\t\tdl = &tr.refdef.dlights[i];\n\t\tif ( dl->origin[0] - dl->radius > grid->meshBounds[1][0]\n\t\t\t|| dl->origin[0] + dl->radius < grid->meshBounds[0][0]\n\t\t\t|| dl->origin[1] - dl->radius > grid->meshBounds[1][1]\n\t\t\t|| dl->origin[1] + dl->radius < grid->meshBounds[0][1]\n\t\t\t|| dl->origin[2] - dl->radius > grid->meshBounds[1][2]\n\t\t\t|| dl->origin[2] + dl->radius < grid->meshBounds[0][2] ) {\n\t\t\t// dlight doesn't reach the bounds\n\t\t\tdlightBits &= ~( 1 << i );\n\t\t}\n\t}\n\n\tif ( !dlightBits ) {\n\t\ttr.pc.c_dlightSurfacesCulled++;\n\t}\n\n\tgrid->dlightBits[ tr.smpFrame ] = dlightBits;\n\treturn dlightBits;\n#endif\n}\n\n/*\n====================\nR_DlightSurface\n\nThe given surface is going to be drawn, and it touches a leaf\nthat is touched by one or more dlights, so try to throw out\nmore dlights if possible.\n====================\n*/\nstatic int R_DlightSurface( msurface_t *surf, int dlightBits ) {\n\tif ( *surf->data == SF_FACE ) {\n\t\tdlightBits = R_DlightFace( (srfSurfaceFace_t *)surf->data, dlightBits );\n\t} else if ( *surf->data == SF_GRID ) {\n\t\tdlightBits = R_DlightGrid( (srfGridMesh_t *)surf->data, dlightBits );\n\t} else if ( *surf->data == SF_TRIANGLES ) {\n\t\tdlightBits = R_DlightTrisurf( (srfTriangles_t *)surf->data, dlightBits );\n\t} else {\n\t\tdlightBits = 0;\n\t}\n\n\tif ( dlightBits ) {\n\t\ttr.pc.c_dlightSurfaces++;\n\t}\n\n\treturn dlightBits;\n}\n\n\n\n/*\n======================\nR_AddWorldSurface\n======================\n*/\nstatic void R_AddWorldSurface( msurface_t *surf, int dlightBits ) {\n\tif ( surf->viewCount == tr.viewCount ) {\n\t\treturn;\t\t// already in this view\n\t}\n\n\tsurf->viewCount = tr.viewCount;\n\t// FIXME: bmodel fog?\n\n\t// try to cull before dlighting or adding\n\tif ( R_CullSurface( surf->data, surf->shader ) ) {\n\t\treturn;\n\t}\n\n\t// check for dlighting\n\tif ( dlightBits ) {\n\t\tdlightBits = R_DlightSurface( surf, dlightBits );\n\t\tdlightBits = ( dlightBits != 0 );\n\t}\n\n\tR_AddDrawSurf( surf->data, surf->shader, surf->fogIndex, dlightBits );\n}\n\n/*\n=============================================================\n\n\tBRUSH MODELS\n\n=============================================================\n*/\n\n/*\n=================\nR_AddBrushModelSurfaces\n=================\n*/\nvoid R_AddBrushModelSurfaces ( trRefEntity_t *ent ) {\n\tbmodel_t\t*bmodel;\n\tint\t\t\tclip;\n\tmodel_t\t\t*pModel;\n\tint\t\t\ti;\n\n\tpModel = R_GetModelByHandle( ent->e.hModel );\n\n\tbmodel = pModel->bmodel;\n\n\tclip = R_CullLocalBox( bmodel->bounds );\n\tif ( clip == CULL_OUT ) {\n\t\treturn;\n\t}\n\t\n\tR_DlightBmodel( bmodel );\n\n\tfor ( i = 0 ; i < bmodel->numSurfaces ; i++ ) {\n\t\tR_AddWorldSurface( bmodel->firstSurface + i, tr.currentEntity->needDlights );\n\t}\n}\n\n\n/*\n=============================================================\n\n\tWORLD MODEL\n\n=============================================================\n*/\n\n\n/*\n================\nR_RecursiveWorldNode\n================\n*/\nstatic void R_RecursiveWorldNode( mnode_t *node, int planeBits, int dlightBits ) {\n\n\tdo {\n\t\tint\t\t\tnewDlights[2];\n\n\t\t// if the node wasn't marked as potentially visible, exit\n\t\tif (node->visframe != tr.visCount) {\n\t\t\treturn;\n\t\t}\n\n\t\t// if the bounding volume is outside the frustum, nothing\n\t\t// inside can be visible OPTIMIZE: don't do this all the way to leafs?\n\n\t\tif ( !r_nocull->integer ) {\n\t\t\tint\t\tr;\n\n\t\t\tif ( planeBits & 1 ) {\n\t\t\t\tr = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[0]);\n\t\t\t\tif (r == 2) {\n\t\t\t\t\treturn;\t\t\t\t\t\t// culled\n\t\t\t\t}\n\t\t\t\tif ( r == 1 ) {\n\t\t\t\t\tplaneBits &= ~1;\t\t\t// all descendants will also be in front\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( planeBits & 2 ) {\n\t\t\t\tr = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[1]);\n\t\t\t\tif (r == 2) {\n\t\t\t\t\treturn;\t\t\t\t\t\t// culled\n\t\t\t\t}\n\t\t\t\tif ( r == 1 ) {\n\t\t\t\t\tplaneBits &= ~2;\t\t\t// all descendants will also be in front\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( planeBits & 4 ) {\n\t\t\t\tr = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[2]);\n\t\t\t\tif (r == 2) {\n\t\t\t\t\treturn;\t\t\t\t\t\t// culled\n\t\t\t\t}\n\t\t\t\tif ( r == 1 ) {\n\t\t\t\t\tplaneBits &= ~4;\t\t\t// all descendants will also be in front\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( planeBits & 8 ) {\n\t\t\t\tr = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[3]);\n\t\t\t\tif (r == 2) {\n\t\t\t\t\treturn;\t\t\t\t\t\t// culled\n\t\t\t\t}\n\t\t\t\tif ( r == 1 ) {\n\t\t\t\t\tplaneBits &= ~8;\t\t\t// all descendants will also be in front\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\n\t\tif ( node->contents != -1 ) {\n\t\t\tbreak;\n\t\t}\n\n\t\t// node is just a decision point, so go down both sides\n\t\t// since we don't care about sort orders, just go positive to negative\n\n\t\t// determine which dlights are needed\n\t\tnewDlights[0] = 0;\n\t\tnewDlights[1] = 0;\n\t\tif ( dlightBits ) {\n\t\t\tint\ti;\n\n\t\t\tfor ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) {\n\t\t\t\tdlight_t\t*dl;\n\t\t\t\tfloat\t\tdist;\n\n\t\t\t\tif ( dlightBits & ( 1 << i ) ) {\n\t\t\t\t\tdl = &tr.refdef.dlights[i];\n\t\t\t\t\tdist = DotProduct( dl->origin, node->plane->normal ) - node->plane->dist;\n\t\t\t\t\t\n\t\t\t\t\tif ( dist > -dl->radius ) {\n\t\t\t\t\t\tnewDlights[0] |= ( 1 << i );\n\t\t\t\t\t}\n\t\t\t\t\tif ( dist < dl->radius ) {\n\t\t\t\t\t\tnewDlights[1] |= ( 1 << i );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// recurse down the children, front side first\n\t\tR_RecursiveWorldNode (node->children[0], planeBits, newDlights[0] );\n\n\t\t// tail recurse\n\t\tnode = node->children[1];\n\t\tdlightBits = newDlights[1];\n\t} while ( 1 );\n\n\t{\n\t\t// leaf node, so add mark surfaces\n\t\tint\t\t\tc;\n\t\tmsurface_t\t*surf, **mark;\n\n\t\ttr.pc.c_leafs++;\n\n\t\t// add to z buffer bounds\n\t\tif ( node->mins[0] < tr.viewParms.visBounds[0][0] ) {\n\t\t\ttr.viewParms.visBounds[0][0] = node->mins[0];\n\t\t}\n\t\tif ( node->mins[1] < tr.viewParms.visBounds[0][1] ) {\n\t\t\ttr.viewParms.visBounds[0][1] = node->mins[1];\n\t\t}\n\t\tif ( node->mins[2] < tr.viewParms.visBounds[0][2] ) {\n\t\t\ttr.viewParms.visBounds[0][2] = node->mins[2];\n\t\t}\n\n\t\tif ( node->maxs[0] > tr.viewParms.visBounds[1][0] ) {\n\t\t\ttr.viewParms.visBounds[1][0] = node->maxs[0];\n\t\t}\n\t\tif ( node->maxs[1] > tr.viewParms.visBounds[1][1] ) {\n\t\t\ttr.viewParms.visBounds[1][1] = node->maxs[1];\n\t\t}\n\t\tif ( node->maxs[2] > tr.viewParms.visBounds[1][2] ) {\n\t\t\ttr.viewParms.visBounds[1][2] = node->maxs[2];\n\t\t}\n\n\t\t// add the individual surfaces\n\t\tmark = node->firstmarksurface;\n\t\tc = node->nummarksurfaces;\n\t\twhile (c--) {\n\t\t\t// the surface may have already been added if it\n\t\t\t// spans multiple leafs\n\t\t\tsurf = *mark;\n\t\t\tR_AddWorldSurface( surf, dlightBits );\n\t\t\tmark++;\n\t\t}\n\t}\n\n}\n\n\n/*\n===============\nR_PointInLeaf\n===============\n*/\nstatic mnode_t *R_PointInLeaf( const vec3_t p ) {\n\tmnode_t\t\t*node;\n\tfloat\t\td;\n\tcplane_t\t*plane;\n\t\n\tif ( !tr.world ) {\n\t\tri.Error (ERR_DROP, \"R_PointInLeaf: bad model\");\n\t}\n\n\tnode = tr.world->nodes;\n\twhile( 1 ) {\n\t\tif (node->contents != -1) {\n\t\t\tbreak;\n\t\t}\n\t\tplane = node->plane;\n\t\td = DotProduct (p,plane->normal) - plane->dist;\n\t\tif (d > 0) {\n\t\t\tnode = node->children[0];\n\t\t} else {\n\t\t\tnode = node->children[1];\n\t\t}\n\t}\n\t\n\treturn node;\n}\n\n/*\n==============\nR_ClusterPVS\n==============\n*/\nstatic const byte *R_ClusterPVS (int cluster) {\n\tif (!tr.world || !tr.world->vis || cluster < 0 || cluster >= tr.world->numClusters ) {\n\t\treturn tr.world->novis;\n\t}\n\n\treturn tr.world->vis + cluster * tr.world->clusterBytes;\n}\n\n/*\n=================\nR_inPVS\n=================\n*/\nqboolean R_inPVS( const vec3_t p1, const vec3_t p2 ) {\n\tmnode_t *leaf;\n\tbyte\t*vis;\n\n\tleaf = R_PointInLeaf( p1 );\n\tvis = CM_ClusterPVS( leaf->cluster );\n\tleaf = R_PointInLeaf( p2 );\n\n\tif ( !(vis[leaf->cluster>>3] & (1<<(leaf->cluster&7))) ) {\n\t\treturn qfalse;\n\t}\n\treturn qtrue;\n}\n\n/*\n===============\nR_MarkLeaves\n\nMark the leaves and nodes that are in the PVS for the current\ncluster\n===============\n*/\nstatic void R_MarkLeaves (void) {\n\tconst byte\t*vis;\n\tmnode_t\t*leaf, *parent;\n\tint\t\ti;\n\tint\t\tcluster;\n\n\t// lockpvs lets designers walk around to determine the\n\t// extent of the current pvs\n\tif ( r_lockpvs->integer ) {\n\t\treturn;\n\t}\n\n\t// current viewcluster\n\tleaf = R_PointInLeaf( tr.viewParms.pvsOrigin );\n\tcluster = leaf->cluster;\n\n\t// if the cluster is the same and the area visibility matrix\n\t// hasn't changed, we don't need to mark everything again\n\n\t// if r_showcluster was just turned on, remark everything \n\tif ( tr.viewCluster == cluster && !tr.refdef.areamaskModified \n\t\t&& !r_showcluster->modified ) {\n\t\treturn;\n\t}\n\n\tif ( r_showcluster->modified || r_showcluster->integer ) {\n\t\tr_showcluster->modified = qfalse;\n\t\tif ( r_showcluster->integer ) {\n\t\t\tri.Printf( PRINT_ALL, \"cluster:%i  area:%i\\n\", cluster, leaf->area );\n\t\t}\n\t}\n\n\ttr.visCount++;\n\ttr.viewCluster = cluster;\n\n\tif ( r_novis->integer || tr.viewCluster == -1 ) {\n\t\tfor (i=0 ; i<tr.world->numnodes ; i++) {\n\t\t\tif (tr.world->nodes[i].contents != CONTENTS_SOLID) {\n\t\t\t\ttr.world->nodes[i].visframe = tr.visCount;\n\t\t\t}\n\t\t}\n\t\treturn;\n\t}\n\n\tvis = R_ClusterPVS (tr.viewCluster);\n\t\n\tfor (i=0,leaf=tr.world->nodes ; i<tr.world->numnodes ; i++, leaf++) {\n\t\tcluster = leaf->cluster;\n\t\tif ( cluster < 0 || cluster >= tr.world->numClusters ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// check general pvs\n\t\tif ( !(vis[cluster>>3] & (1<<(cluster&7))) ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// check for door connection\n\t\tif ( (tr.refdef.areamask[leaf->area>>3] & (1<<(leaf->area&7)) ) ) {\n\t\t\tcontinue;\t\t// not visible\n\t\t}\n\n\t\tparent = leaf;\n\t\tdo {\n\t\t\tif (parent->visframe == tr.visCount)\n\t\t\t\tbreak;\n\t\t\tparent->visframe = tr.visCount;\n\t\t\tparent = parent->parent;\n\t\t} while (parent);\n\t}\n}\n\n\n/*\n=============\nR_AddWorldSurfaces\n=============\n*/\nvoid R_AddWorldSurfaces (void) {\n\tif ( !r_drawworld->integer ) {\n\t\treturn;\n\t}\n\n\tif ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {\n\t\treturn;\n\t}\n\n\ttr.currentEntityNum = ENTITYNUM_WORLD;\n\ttr.shiftedEntityNum = tr.currentEntityNum << QSORT_ENTITYNUM_SHIFT;\n\n\t// determine which leaves are in the PVS / areamask\n\tR_MarkLeaves ();\n\n\t// clear out the visible min/max\n\tClearBounds( tr.viewParms.visBounds[0], tr.viewParms.visBounds[1] );\n\n\t// perform frustum culling and add all the potentially visible surfaces\n\tif ( tr.refdef.num_dlights > 32 ) {\n\t\ttr.refdef.num_dlights = 32 ;\n\t}\n\tR_RecursiveWorldNode( tr.world->nodes, 15, ( 1 << tr.refdef.num_dlights ) - 1 );\n}\n"
  },
  {
    "path": "src/engine/renderer/vk.cpp",
    "content": "#include \"tr_local.h\"\n\n#include <algorithm>\n#include <chrono>\n#include <functional>\n#include <vector>\n\nconst int VERTEX_CHUNK_SIZE = 512 * 1024;\n\nconst int XYZ_SIZE      = 4 * VERTEX_CHUNK_SIZE;\nconst int COLOR_SIZE    = 1 * VERTEX_CHUNK_SIZE;\nconst int ST0_SIZE      = 2 * VERTEX_CHUNK_SIZE;\nconst int ST1_SIZE      = 2 * VERTEX_CHUNK_SIZE;\n\nconst int XYZ_OFFSET    = 0;\nconst int COLOR_OFFSET  = XYZ_OFFSET + XYZ_SIZE;\nconst int ST0_OFFSET    = COLOR_OFFSET + COLOR_SIZE;\nconst int ST1_OFFSET    = ST0_OFFSET + ST0_SIZE;\n\nstatic const int VERTEX_BUFFER_SIZE = XYZ_SIZE + COLOR_SIZE + ST0_SIZE + ST1_SIZE;\nstatic const int INDEX_BUFFER_SIZE = 2 * 1024 * 1024;\n\nconstexpr VkFormat output_image_format = VK_FORMAT_R8G8B8A8_UNORM;\n\n//\n// Vulkan API functions used by the renderer.\n//\nPFN_vkGetInstanceProcAddr\t\t\t\t\t\tvkGetInstanceProcAddr;\n\nPFN_vkCreateInstance\t\t\t\t\t\t\tvkCreateInstance;\nPFN_vkEnumerateInstanceExtensionProperties\t\tvkEnumerateInstanceExtensionProperties;\n\nPFN_vkCreateDevice\t\t\t\t\t\t\t\tvkCreateDevice;\nPFN_vkDestroyInstance\t\t\t\t\t\t\tvkDestroyInstance;\nPFN_vkEnumerateDeviceExtensionProperties\t\tvkEnumerateDeviceExtensionProperties;\nPFN_vkEnumeratePhysicalDevices\t\t\t\t\tvkEnumeratePhysicalDevices;\nPFN_vkGetDeviceProcAddr\t\t\t\t\t\t\tvkGetDeviceProcAddr;\nPFN_vkGetPhysicalDeviceFeatures\t\t\t\t\tvkGetPhysicalDeviceFeatures;\nPFN_vkGetPhysicalDeviceFormatProperties\t\t\tvkGetPhysicalDeviceFormatProperties;\nPFN_vkGetPhysicalDeviceMemoryProperties\t\t\tvkGetPhysicalDeviceMemoryProperties;\nPFN_vkGetPhysicalDeviceProperties\t\t\t\tvkGetPhysicalDeviceProperties;\nPFN_vkGetPhysicalDeviceQueueFamilyProperties\tvkGetPhysicalDeviceQueueFamilyProperties;\nPFN_vkCreateWin32SurfaceKHR\t\t\t\t\t\tvkCreateWin32SurfaceKHR;\nPFN_vkDestroySurfaceKHR\t\t\t\t\t\t\tvkDestroySurfaceKHR;\nPFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR\tvkGetPhysicalDeviceSurfaceCapabilitiesKHR;\nPFN_vkGetPhysicalDeviceSurfaceFormatsKHR\t\tvkGetPhysicalDeviceSurfaceFormatsKHR;\nPFN_vkGetPhysicalDeviceSurfacePresentModesKHR\tvkGetPhysicalDeviceSurfacePresentModesKHR;\nPFN_vkGetPhysicalDeviceSurfaceSupportKHR\t\tvkGetPhysicalDeviceSurfaceSupportKHR;\nPFN_vkCreateDebugReportCallbackEXT\t\t\t\tvkCreateDebugReportCallbackEXT;\nPFN_vkDestroyDebugReportCallbackEXT\t\t\t\tvkDestroyDebugReportCallbackEXT;\n\nPFN_vkAllocateCommandBuffers\t\t\t\t\tvkAllocateCommandBuffers;\nPFN_vkAllocateDescriptorSets\t\t\t\t\tvkAllocateDescriptorSets;\nPFN_vkAllocateMemory\t\t\t\t\t\t\tvkAllocateMemory;\nPFN_vkBeginCommandBuffer\t\t\t\t\t\tvkBeginCommandBuffer;\nPFN_vkBindBufferMemory\t\t\t\t\t\t\tvkBindBufferMemory;\nPFN_vkBindImageMemory\t\t\t\t\t\t\tvkBindImageMemory;\nPFN_vkCmdBeginRenderPass\t\t\t\t\t\tvkCmdBeginRenderPass;\nPFN_vkCmdBindDescriptorSets\t\t\t\t\t\tvkCmdBindDescriptorSets;\nPFN_vkCmdBindIndexBuffer\t\t\t\t\t\tvkCmdBindIndexBuffer;\nPFN_vkCmdBindPipeline\t\t\t\t\t\t\tvkCmdBindPipeline;\nPFN_vkCmdBindVertexBuffers\t\t\t\t\t\tvkCmdBindVertexBuffers;\nPFN_vkCmdBlitImage\t\t\t\t\t\t\t\tvkCmdBlitImage;\nPFN_vkCmdClearAttachments\t\t\t\t\t\tvkCmdClearAttachments;\nPFN_vkCmdCopyBuffer\t\t\t\t\t\t\t\tvkCmdCopyBuffer;\nPFN_vkCmdCopyBufferToImage\t\t\t\t\t\tvkCmdCopyBufferToImage;\nPFN_vkCmdCopyImage\t\t\t\t\t\t\t\tvkCmdCopyImage;\nPFN_vkCmdDispatch\t\t\t\t\t\t\t\tvkCmdDispatch;\nPFN_vkCmdDraw\t\t\t\t\t\t\t\t\tvkCmdDraw;\nPFN_vkCmdDrawIndexed\t\t\t\t\t\t\tvkCmdDrawIndexed;\nPFN_vkCmdEndRenderPass\t\t\t\t\t\t\tvkCmdEndRenderPass;\nPFN_vkCmdPipelineBarrier\t\t\t\t\t\tvkCmdPipelineBarrier;\nPFN_vkCmdPushConstants\t\t\t\t\t\t\tvkCmdPushConstants;\nPFN_vkCmdSetDepthBias\t\t\t\t\t\t\tvkCmdSetDepthBias;\nPFN_vkCmdSetScissor\t\t\t\t\t\t\t\tvkCmdSetScissor;\nPFN_vkCmdSetViewport\t\t\t\t\t\t\tvkCmdSetViewport;\nPFN_vkCreateBuffer\t\t\t\t\t\t\t\tvkCreateBuffer;\nPFN_vkCreateCommandPool\t\t\t\t\t\t\tvkCreateCommandPool;\nPFN_vkCreateComputePipelines\t\t\t\t\tvkCreateComputePipelines;\nPFN_vkCreateDescriptorPool\t\t\t\t\t\tvkCreateDescriptorPool;\nPFN_vkCreateDescriptorSetLayout\t\t\t\t\tvkCreateDescriptorSetLayout;\nPFN_vkCreateFence\t\t\t\t\t\t\t\tvkCreateFence;\nPFN_vkCreateFramebuffer\t\t\t\t\t\t\tvkCreateFramebuffer;\nPFN_vkCreateGraphicsPipelines\t\t\t\t\tvkCreateGraphicsPipelines;\nPFN_vkCreateImage\t\t\t\t\t\t\t\tvkCreateImage;\nPFN_vkCreateImageView\t\t\t\t\t\t\tvkCreateImageView;\nPFN_vkCreatePipelineLayout\t\t\t\t\t\tvkCreatePipelineLayout;\nPFN_vkCreateRenderPass\t\t\t\t\t\t\tvkCreateRenderPass;\nPFN_vkCreateSampler\t\t\t\t\t\t\t\tvkCreateSampler;\nPFN_vkCreateSemaphore\t\t\t\t\t\t\tvkCreateSemaphore;\nPFN_vkCreateShaderModule\t\t\t\t\t\tvkCreateShaderModule;\nPFN_vkDestroyBuffer\t\t\t\t\t\t\t\tvkDestroyBuffer;\nPFN_vkDestroyCommandPool\t\t\t\t\t\tvkDestroyCommandPool;\nPFN_vkDestroyDescriptorPool\t\t\t\t\t\tvkDestroyDescriptorPool;\nPFN_vkDestroyDescriptorSetLayout\t\t\t\tvkDestroyDescriptorSetLayout;\nPFN_vkDestroyDevice\t\t\t\t\t\t\t\tvkDestroyDevice;\nPFN_vkDestroyFence\t\t\t\t\t\t\t\tvkDestroyFence;\nPFN_vkDestroyFramebuffer\t\t\t\t\t\tvkDestroyFramebuffer;\nPFN_vkDestroyImage\t\t\t\t\t\t\t\tvkDestroyImage;\nPFN_vkDestroyImageView\t\t\t\t\t\t\tvkDestroyImageView;\nPFN_vkDestroyPipeline\t\t\t\t\t\t\tvkDestroyPipeline;\nPFN_vkDestroyPipelineLayout\t\t\t\t\t\tvkDestroyPipelineLayout;\nPFN_vkDestroyRenderPass\t\t\t\t\t\t\tvkDestroyRenderPass;\nPFN_vkDestroySampler\t\t\t\t\t\t\tvkDestroySampler;\nPFN_vkDestroySemaphore\t\t\t\t\t\t\tvkDestroySemaphore;\nPFN_vkDestroyShaderModule\t\t\t\t\t\tvkDestroyShaderModule;\nPFN_vkDeviceWaitIdle\t\t\t\t\t\t\tvkDeviceWaitIdle;\nPFN_vkEndCommandBuffer\t\t\t\t\t\t\tvkEndCommandBuffer;\nPFN_vkFreeCommandBuffers\t\t\t\t\t\tvkFreeCommandBuffers;\nPFN_vkFreeDescriptorSets\t\t\t\t\t\tvkFreeDescriptorSets;\nPFN_vkFreeMemory\t\t\t\t\t\t\t\tvkFreeMemory;\nPFN_vkGetBufferMemoryRequirements\t\t\t\tvkGetBufferMemoryRequirements;\nPFN_vkGetDeviceQueue\t\t\t\t\t\t\tvkGetDeviceQueue;\nPFN_vkGetImageMemoryRequirements\t\t\t\tvkGetImageMemoryRequirements;\nPFN_vkGetImageSubresourceLayout\t\t\t\t\tvkGetImageSubresourceLayout;\nPFN_vkMapMemory\t\t\t\t\t\t\t\t\tvkMapMemory;\nPFN_vkQueueSubmit\t\t\t\t\t\t\t\tvkQueueSubmit;\nPFN_vkQueueWaitIdle\t\t\t\t\t\t\t\tvkQueueWaitIdle;\nPFN_vkResetDescriptorPool\t\t\t\t\t\tvkResetDescriptorPool;\nPFN_vkResetFences\t\t\t\t\t\t\t\tvkResetFences;\nPFN_vkUpdateDescriptorSets\t\t\t\t\t\tvkUpdateDescriptorSets;\nPFN_vkWaitForFences\t\t\t\t\t\t\t\tvkWaitForFences;\nPFN_vkAcquireNextImageKHR\t\t\t\t\t\tvkAcquireNextImageKHR;\nPFN_vkCreateSwapchainKHR\t\t\t\t\t\tvkCreateSwapchainKHR;\nPFN_vkDestroySwapchainKHR\t\t\t\t\t\tvkDestroySwapchainKHR;\nPFN_vkGetSwapchainImagesKHR\t\t\t\t\t\tvkGetSwapchainImagesKHR;\nPFN_vkQueuePresentKHR\t\t\t\t\t\t\tvkQueuePresentKHR;\n////////////////////////////////////////////////////////////////////////////\n\n\nstatic uint32_t find_memory_type(VkPhysicalDevice physical_device, uint32_t memory_type_bits, VkMemoryPropertyFlags properties) {\n\tVkPhysicalDeviceMemoryProperties memory_properties;\n\tvkGetPhysicalDeviceMemoryProperties(physical_device, &memory_properties);\n\n\tfor (uint32_t i = 0; i < memory_properties.memoryTypeCount; i++) {\n\t\tif ((memory_type_bits & (1 << i)) != 0 &&\n\t\t\t(memory_properties.memoryTypes[i].propertyFlags & properties) == properties) {\n\t\t\treturn i;\n\t\t}\n\t}\n\tri.Error(ERR_FATAL, \"Vulkan: failed to find matching memory type with requested properties\");\n\treturn -1;\n}\n\nstatic VkFormat get_depth_format(VkPhysicalDevice physical_device) {\n\tVkFormat formats[2];\n\tif (r_stencilbits->integer > 0) {\n\t\tformats[0] = VK_FORMAT_D24_UNORM_S8_UINT;\n\t\tformats[1] = VK_FORMAT_D32_SFLOAT_S8_UINT;\n\t\tglConfig.stencilBits = 8;\n\t} else {\n\t\tformats[0] = VK_FORMAT_X8_D24_UNORM_PACK32;\n\t\tformats[1] = VK_FORMAT_D32_SFLOAT;\n\t\tglConfig.stencilBits = 0;\n\t}\n\n\tfor (int i = 0; i < 2; i++) {\n\t\tVkFormatProperties props;\n\t\tvkGetPhysicalDeviceFormatProperties(physical_device, formats[i], &props);\n\t\tif ((props.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0) {\n\t\t\treturn formats[i];\n\t\t}\n\t}\n\tri.Error(ERR_FATAL, \"get_depth_format: failed to find depth attachment format\");\n\treturn VK_FORMAT_UNDEFINED; // never get here\n}\n\nstatic VkSwapchainKHR create_swapchain(VkPhysicalDevice physical_device, VkDevice device, VkSurfaceKHR surface, VkSurfaceFormatKHR surface_format) {\n\tVkSurfaceCapabilitiesKHR surface_caps;\n\tVK_CHECK(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, surface, &surface_caps));\n\n\tVkExtent2D image_extent = surface_caps.currentExtent;\n\tif (image_extent.width == 0xffffffff && image_extent.height == 0xffffffff) {\n\t\timage_extent.width = std::min(surface_caps.maxImageExtent.width, std::max(surface_caps.minImageExtent.width, 640u));\n\t\timage_extent.height = std::min(surface_caps.maxImageExtent.height, std::max(surface_caps.minImageExtent.height, 480u));\n\t}\n\n\t// VK_IMAGE_USAGE_TRANSFER_DST_BIT is required by image clear operations.\n\tif ((surface_caps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT) == 0)\n\t\tri.Error(ERR_FATAL, \"create_swapchain: VK_IMAGE_USAGE_TRANSFER_DST_BIT is not supported by the swapchain\");\n\n\t// VK_IMAGE_USAGE_TRANSFER_SRC_BIT is required in order to take screenshots.\n\tif ((surface_caps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) == 0)\n\t\tri.Error(ERR_FATAL, \"create_swapchain: VK_IMAGE_USAGE_TRANSFER_SRC_BIT is not supported by the swapchain\");\n\n\t// determine present mode and swapchain image count\n\tuint32_t present_mode_count;\n\tVK_CHECK(vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &present_mode_count, nullptr));\n\tstd::vector<VkPresentModeKHR> present_modes(present_mode_count);\n\tVK_CHECK(vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &present_mode_count, present_modes.data()));\n\n\tbool mailbox_supported = false;\n\tbool immediate_supported = false;\n\tbool fifo_relaxed_supported = false;\n\tfor (auto pm : present_modes) {\n\t\tif (pm == VK_PRESENT_MODE_MAILBOX_KHR)\n\t\t\tmailbox_supported = true;\n\t\telse if (pm == VK_PRESENT_MODE_IMMEDIATE_KHR)\n\t\t\timmediate_supported = true;\n\t\telse if (pm == VK_PRESENT_MODE_FIFO_RELAXED_KHR)\n\t\t\tfifo_relaxed_supported = true;\n\t}\n\n    VkPresentModeKHR present_mode;\n    uint32_t image_count = surface_caps.minImageCount;\n\n\tif (!r_vsync->integer && mailbox_supported) {\n\t\tpresent_mode = VK_PRESENT_MODE_MAILBOX_KHR;\n\t\t// Additional image over reported min count is to ensure AcquireNextImage does not block\n\t\t// (check Q/A section for VK_KHR_swapchain extension in the specification)\n\t\timage_count = surface_caps.minImageCount + 1;\n\t}\n\telse if (!r_vsync->integer && immediate_supported) {\n\t\tpresent_mode = VK_PRESENT_MODE_IMMEDIATE_KHR;\n\t}\n\telse if (fifo_relaxed_supported) {\n\t\tpresent_mode = VK_PRESENT_MODE_FIFO_RELAXED_KHR;\n\t}\n\telse {\n\t\tpresent_mode = VK_PRESENT_MODE_FIFO_KHR;\n\t}\n\n\tif (surface_caps.maxImageCount > 0) {\n\t\timage_count = std::min(image_count, surface_caps.maxImageCount);\n\t}\n\n\t// create swap chain\n\tVkSwapchainCreateInfoKHR desc{VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR};\n\tdesc.surface = surface;\n\tdesc.minImageCount = image_count;\n\tdesc.imageFormat = surface_format.format;\n\tdesc.imageColorSpace = surface_format.colorSpace;\n\tdesc.imageExtent = image_extent;\n\tdesc.imageArrayLayers = 1;\n\tdesc.imageUsage = VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;\n\tdesc.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;\n\tdesc.preTransform = surface_caps.currentTransform;\n\tdesc.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;\n\tdesc.presentMode = present_mode;\n\tdesc.clipped = VK_TRUE;\n\n\tVkSwapchainKHR swapchain;\n\tVK_CHECK(vkCreateSwapchainKHR(device, &desc, nullptr, &swapchain));\n\treturn swapchain;\n}\n\nstatic VkRenderPass create_render_pass(VkDevice device, VkFormat color_format, VkFormat depth_format) {\n\tVkAttachmentDescription attachments[2];\n\tattachments[0].flags = 0;\n\tattachments[0].format = color_format;\n\tattachments[0].samples = VK_SAMPLE_COUNT_1_BIT;\n\tattachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;\n\tattachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;\n\tattachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;\n\tattachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;\n\tattachments[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;\n\tattachments[0].finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;\n\n\tattachments[1].flags = 0;\n\tattachments[1].format = depth_format;\n\tattachments[1].samples = VK_SAMPLE_COUNT_1_BIT;\n\tattachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;\n\tattachments[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;\n\tattachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;\n\tattachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;\n\tattachments[1].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;\n\tattachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;\n\n\tVkAttachmentReference color_attachment_ref;\n\tcolor_attachment_ref.attachment = 0;\n\tcolor_attachment_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;\n\n\tVkAttachmentReference depth_attachment_ref;\n\tdepth_attachment_ref.attachment = 1;\n\tdepth_attachment_ref.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;\n\n\tVkSubpassDescription subpass{};\n\tsubpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;\n\tsubpass.colorAttachmentCount = 1;\n\tsubpass.pColorAttachments = &color_attachment_ref;\n\tsubpass.pDepthStencilAttachment = &depth_attachment_ref;\n\n\t// Synchronize color attachment output stage (main rendering) and compute state (gamma shader).\n\t// This replaces Vulkan's implicit barrier that transitions output image to final layout (SHADER_READ).\n\tVkSubpassDependency dependency;\n\tdependency.srcSubpass = 0;\n\tdependency.dstSubpass = VK_SUBPASS_EXTERNAL;\n\tdependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;\n\tdependency.dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;\n\tdependency.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;\n\tdependency.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;\n\tdependency.dependencyFlags = 0;\n\n\tVkRenderPassCreateInfo desc{ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO };\n\tdesc.attachmentCount = sizeof(attachments) / sizeof(attachments[0]);\n\tdesc.pAttachments = attachments;\n\tdesc.subpassCount = 1;\n\tdesc.pSubpasses = &subpass;\n\tdesc.dependencyCount = 1;\n\tdesc.pDependencies = &dependency;\n\n\tVkRenderPass render_pass;\n\tVK_CHECK(vkCreateRenderPass(device, &desc, nullptr, &render_pass));\n\treturn render_pass;\n}\n\nstatic void record_and_run_commands(VkCommandPool command_pool, VkQueue queue, std::function<void(VkCommandBuffer)> recorder) {\n\n\tVkCommandBufferAllocateInfo alloc_info{ VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };\n\talloc_info.commandPool = command_pool;\n\talloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;\n\talloc_info.commandBufferCount = 1;\n\n\tVkCommandBuffer command_buffer;\n\tVK_CHECK(vkAllocateCommandBuffers(vk.device, &alloc_info, &command_buffer));\n\n\tVkCommandBufferBeginInfo begin_info{ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };\n\tbegin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;\n\n\tVK_CHECK(vkBeginCommandBuffer(command_buffer, &begin_info));\n\trecorder(command_buffer);\n\tVK_CHECK(vkEndCommandBuffer(command_buffer));\n\n\tVkSubmitInfo submit_info{ VK_STRUCTURE_TYPE_SUBMIT_INFO };\n\tsubmit_info.commandBufferCount = 1;\n\tsubmit_info.pCommandBuffers = &command_buffer;\n\n\tVK_CHECK(vkQueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE));\n\tVK_CHECK(vkQueueWaitIdle(queue));\n\tvkFreeCommandBuffers(vk.device, command_pool, 1, &command_buffer);\n}\n\nstatic void record_image_layout_transition(VkCommandBuffer command_buffer, VkImage image, VkImageAspectFlags image_aspect_flags,\n\tVkAccessFlags src_access_flags, VkImageLayout old_layout, VkAccessFlags dst_access_flags, VkImageLayout new_layout) {\n\n\tVkImageMemoryBarrier barrier{ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };\n\tbarrier.srcAccessMask = src_access_flags;\n\tbarrier.dstAccessMask = dst_access_flags;\n\tbarrier.oldLayout = old_layout;\n\tbarrier.newLayout = new_layout;\n\tbarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;\n\tbarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;\n\tbarrier.image = image;\n\tbarrier.subresourceRange.aspectMask = image_aspect_flags;\n\tbarrier.subresourceRange.baseMipLevel = 0;\n\tbarrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;\n\tbarrier.subresourceRange.baseArrayLayer = 0;\n\tbarrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;\n\n\tvkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0,\n\t\t0, nullptr, 0, nullptr, 1, &barrier);\n}\n\nstatic void allocate_and_bind_image_memory(VkImage image) {\n\tVkMemoryRequirements memory_requirements;\n\tvkGetImageMemoryRequirements(vk.device, image, &memory_requirements);\n\n\tif (memory_requirements.size > IMAGE_CHUNK_SIZE) {\n\t\tri.Error(ERR_FATAL, \"Vulkan: could not allocate memory, image is too large.\");\n\t}\n\n\tVk_World::Chunk* chunk = nullptr;\n\n\t// Try to find an existing chunk of sufficient capacity.\n\tconst auto mask = ~(memory_requirements.alignment - 1);\n\tfor (int i = 0; i < vk_world.num_image_chunks; i++) {\n\t\t// ensure that memory region has proper alignment\n\t\tVkDeviceSize offset = (vk_world.image_chunks[i].used + memory_requirements.alignment - 1) & mask;\n\n\t\tif (offset + memory_requirements.size <= IMAGE_CHUNK_SIZE) {\n\t\t\tchunk = &vk_world.image_chunks[i];\n\t\t\tchunk->used = offset + memory_requirements.size;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Allocate a new chunk in case we couldn't find suitable existing chunk.\n\tif (chunk == nullptr) {\n\t\tif (vk_world.num_image_chunks >= MAX_IMAGE_CHUNKS) {\n\t\t\tri.Error(ERR_FATAL, \"Vulkan: image chunk limit has been reached\");\n\t\t}\n\n\t\tVkMemoryAllocateInfo alloc_info{ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };\n\t\talloc_info.allocationSize = IMAGE_CHUNK_SIZE;\n\t\talloc_info.memoryTypeIndex = find_memory_type(vk.physical_device, memory_requirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);\n\n\t\tVkDeviceMemory memory;\n\t\tVK_CHECK(vkAllocateMemory(vk.device, &alloc_info, nullptr, &memory));\n\n\t\tchunk = &vk_world.image_chunks[vk_world.num_image_chunks];\n\t\tvk_world.num_image_chunks++;\n\t\tchunk->memory = memory;\n\t\tchunk->used = memory_requirements.size;\n\t}\n\n\tVK_CHECK(vkBindImageMemory(vk.device, image, chunk->memory, chunk->used - memory_requirements.size));\n}\n\nstatic void ensure_staging_buffer_allocation(VkDeviceSize size) {\n\tif (vk_world.staging_buffer_size >= size)\n\t\treturn;\n\n\tif (vk_world.staging_buffer != VK_NULL_HANDLE)\n\t\tvkDestroyBuffer(vk.device, vk_world.staging_buffer, nullptr);\n\n\tif (vk_world.staging_buffer_memory != VK_NULL_HANDLE)\n\t\tvkFreeMemory(vk.device, vk_world.staging_buffer_memory, nullptr);\n\n\tvk_world.staging_buffer_size = size;\n\n\tVkBufferCreateInfo buffer_desc{ VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };\n\tbuffer_desc.size = size;\n\tbuffer_desc.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;\n\tbuffer_desc.sharingMode = VK_SHARING_MODE_EXCLUSIVE;\n\tVK_CHECK(vkCreateBuffer(vk.device, &buffer_desc, nullptr, &vk_world.staging_buffer));\n\n\tVkMemoryRequirements memory_requirements;\n\tvkGetBufferMemoryRequirements(vk.device, vk_world.staging_buffer, &memory_requirements);\n\n\tuint32_t memory_type = find_memory_type(vk.physical_device, memory_requirements.memoryTypeBits,\n\t\tVK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);\n\n\tVkMemoryAllocateInfo alloc_info{ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };\n\talloc_info.allocationSize = memory_requirements.size;\n\talloc_info.memoryTypeIndex = memory_type;\n\tVK_CHECK(vkAllocateMemory(vk.device, &alloc_info, nullptr, &vk_world.staging_buffer_memory));\n\tVK_CHECK(vkBindBufferMemory(vk.device, vk_world.staging_buffer, vk_world.staging_buffer_memory, 0));\n\n\tvoid* data;\n\tVK_CHECK(vkMapMemory(vk.device, vk_world.staging_buffer_memory, 0, VK_WHOLE_SIZE, 0, &data));\n\tvk_world.staging_buffer_ptr = (byte*)data;\n}\n\nstatic VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT object_type, uint64_t object, size_t location,\n\tint32_t message_code, const char* layer_prefix, const char* message, void* user_data) {\n\t\n#ifdef _WIN32\n\tOutputDebugString(message);\n\tOutputDebugString(\"\\n\");\n\tDebugBreak();\n#endif\n\treturn VK_FALSE;\n}\n\nstatic void create_instance() {\n\tconst char* instance_extensions[] = {\n\t\tVK_KHR_SURFACE_EXTENSION_NAME,\n\t\tVK_KHR_WIN32_SURFACE_EXTENSION_NAME,\n#ifndef NDEBUG\n\t\tVK_EXT_DEBUG_REPORT_EXTENSION_NAME\n#endif\n\t};\n\n\t// check extensions availability\n\t{\n\t\tuint32_t count = 0;\n\t\tVK_CHECK(vkEnumerateInstanceExtensionProperties(nullptr, &count, nullptr));\n\t\tstd::vector<VkExtensionProperties> extension_properties(count);\n\t\tVK_CHECK(vkEnumerateInstanceExtensionProperties(nullptr, &count, extension_properties.data()));\n\n\t\tfor (auto name : instance_extensions) {\n\t\t\tbool supported = false;\n\t\t\tfor (const auto& property : extension_properties) {\n\t\t\t\tif (!strcmp(property.extensionName, name)) {\n\t\t\t\t\tsupported = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!supported)\n\t\t\t\tri.Error(ERR_FATAL, \"Vulkan: required instance extension is not available: %s\", name);\n\t\t}\n\t}\n\n\t// create instance\n\t{\n\t\tVkInstanceCreateInfo desc{ VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO };\n\t\tdesc.enabledExtensionCount = sizeof(instance_extensions)/sizeof(instance_extensions[0]);\n\t\tdesc.ppEnabledExtensionNames = instance_extensions;\n#ifndef NDEBUG\n\t\tconst char* validation_layer_name = \"VK_LAYER_KHRONOS_validation\";\n\t\tdesc.enabledLayerCount = 1;\n\t\tdesc.ppEnabledLayerNames = &validation_layer_name;\n#endif\n\t\tVK_CHECK(vkCreateInstance(&desc, nullptr, &vk.instance));\n\t}\n}\n\nstatic void create_device() {\n\t// select physical device\n\t{\n\t\tuint32_t count = 0;\n\t\tVK_CHECK(vkEnumeratePhysicalDevices(vk.instance, &count, nullptr));\n\t\tif (count == 0) {\n\t\t\tri.Error(ERR_FATAL, \"Vulkan: no physical device found\");\n\t\t}\n\t\tstd::vector<VkPhysicalDevice> physical_devices(count);\n\t\tVK_CHECK(vkEnumeratePhysicalDevices(vk.instance, &count, physical_devices.data()));\n\t\tint gpu_index = r_gpu->integer;\n        if (gpu_index >= count) {\n            ri.Printf(PRINT_WARNING, \"r_gpu %d is too large. Maximum value is %u. Vulkan backend will use GPU 0\\n\", gpu_index, count - 1);\n            gpu_index = 0;\n        }\n\t\tvk.physical_device = physical_devices[gpu_index];\n\t}\n\n\tvk_imp_create_surface();\n\n\t// select surface format\n\t{\n\t\tuint32_t format_count;\n\t\tVK_CHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(vk.physical_device, vk.surface, &format_count, nullptr));\n\t\tassert(format_count > 0);\n\n\t\tstd::vector<VkSurfaceFormatKHR> candidates(format_count);\n\t\tVK_CHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(vk.physical_device, vk.surface, &format_count, candidates.data()));\n\n\t\t\n\t\tif (candidates.size() == 1 && candidates[0].format == VK_FORMAT_UNDEFINED) { // special case that means we can choose any format\n\t\t\tvk.surface_format.format = VK_FORMAT_R8G8B8A8_UNORM;\n\t\t\tvk.surface_format.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;\n\t\t} else {\n\t\t\tvk.surface_format = candidates[0];\n\t\t}\n\t}\n\n\t// select queue family\n\t{\n\t\tuint32_t queue_family_count;\n\t\tvkGetPhysicalDeviceQueueFamilyProperties(vk.physical_device, &queue_family_count, nullptr);\n\n\t\tstd::vector<VkQueueFamilyProperties> queue_families(queue_family_count);\n\t\tvkGetPhysicalDeviceQueueFamilyProperties(vk.physical_device, &queue_family_count, queue_families.data());\n\n\t\t// select queue family with presentation and graphics support\n\t\tvk.queue_family_index = -1;\n\t\tfor (uint32_t i = 0; i < queue_family_count; i++) {\n\t\t\tVkBool32 presentation_supported;\n\t\t\tVK_CHECK(vkGetPhysicalDeviceSurfaceSupportKHR(vk.physical_device, i, vk.surface, &presentation_supported));\n\n\t\t\tif (presentation_supported && (queue_families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) {\n\t\t\t\tvk.queue_family_index = i;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (vk.queue_family_index == -1)\n\t\t\tri.Error(ERR_FATAL, \"Vulkan: failed to find queue family\");\n\t}\n\n\t// create VkDevice\n\t{\n\t\tconst char* device_extensions[] = {\n\t\t\tVK_KHR_SWAPCHAIN_EXTENSION_NAME\n\t\t};\n\n\t\tuint32_t count = 0;\n\t\tVK_CHECK(vkEnumerateDeviceExtensionProperties(vk.physical_device, nullptr, &count, nullptr));\n\t\tstd::vector<VkExtensionProperties> extension_properties(count);\n\t\tVK_CHECK(vkEnumerateDeviceExtensionProperties(vk.physical_device, nullptr, &count, extension_properties.data()));\n\n\t\tfor (auto name : device_extensions) {\n\t\t\tbool supported = false;\n\t\t\tfor (const auto& property : extension_properties) {\n\t\t\t\tif (!strcmp(property.extensionName, name)) {\n\t\t\t\t\tsupported = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!supported)\n\t\t\t\tri.Error(ERR_FATAL, \"Vulkan: required device extension is not available: %s\", name);\n\t\t}\n\n\t\tconst float priority = 1.0;\n\t\tVkDeviceQueueCreateInfo queue_desc{ VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO };\n\t\tqueue_desc.queueFamilyIndex = vk.queue_family_index;\n\t\tqueue_desc.queueCount = 1;\n\t\tqueue_desc.pQueuePriorities = &priority;\n\n\t\tVkPhysicalDeviceFeatures features{};\n\t\tfeatures.shaderClipDistance = VK_TRUE;\n\t\tfeatures.fillModeNonSolid = VK_TRUE;\n\t\tfeatures.shaderStorageImageWriteWithoutFormat = VK_TRUE;\n\n\t\tVkDeviceCreateInfo device_desc{ VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO };\n\t\tdevice_desc.queueCreateInfoCount = 1;\n\t\tdevice_desc.pQueueCreateInfos = &queue_desc;\n\t\tdevice_desc.enabledExtensionCount = sizeof(device_extensions)/sizeof(device_extensions[0]);\n\t\tdevice_desc.ppEnabledExtensionNames = device_extensions;\n\t\tdevice_desc.pEnabledFeatures = &features;\n\t\tVK_CHECK(vkCreateDevice(vk.physical_device, &device_desc, nullptr, &vk.device));\n\t}\n}\n\n#define INIT_INSTANCE_FUNCTION(func) func = (PFN_ ## func)vkGetInstanceProcAddr(vk.instance, #func);\n#define INIT_DEVICE_FUNCTION(func) func = (PFN_ ## func)vkGetDeviceProcAddr(vk.device, #func);\n\nstatic void init_vulkan_library() {\n\t//\n\t// Get functions that do not depend on VkInstance (vk.instance == nullptr at this point).\n\t//\n\tINIT_INSTANCE_FUNCTION(vkCreateInstance)\n\tINIT_INSTANCE_FUNCTION(vkEnumerateInstanceExtensionProperties)\n\n\t//\n\t// Get instance level functions.\n\t//\n\tcreate_instance();\n\tINIT_INSTANCE_FUNCTION(vkCreateDevice)\n\tINIT_INSTANCE_FUNCTION(vkDestroyInstance)\n\tINIT_INSTANCE_FUNCTION(vkEnumerateDeviceExtensionProperties)\n\tINIT_INSTANCE_FUNCTION(vkEnumeratePhysicalDevices)\n\tINIT_INSTANCE_FUNCTION(vkGetDeviceProcAddr)\n\tINIT_INSTANCE_FUNCTION(vkGetPhysicalDeviceFeatures)\n\tINIT_INSTANCE_FUNCTION(vkGetPhysicalDeviceFormatProperties)\n\tINIT_INSTANCE_FUNCTION(vkGetPhysicalDeviceMemoryProperties)\n\tINIT_INSTANCE_FUNCTION(vkGetPhysicalDeviceProperties)\n\tINIT_INSTANCE_FUNCTION(vkGetPhysicalDeviceQueueFamilyProperties)\n\tINIT_INSTANCE_FUNCTION(vkCreateWin32SurfaceKHR)\n\tINIT_INSTANCE_FUNCTION(vkDestroySurfaceKHR)\n\tINIT_INSTANCE_FUNCTION(vkGetPhysicalDeviceSurfaceCapabilitiesKHR)\n\tINIT_INSTANCE_FUNCTION(vkGetPhysicalDeviceSurfaceFormatsKHR)\n\tINIT_INSTANCE_FUNCTION(vkGetPhysicalDeviceSurfacePresentModesKHR)\n\tINIT_INSTANCE_FUNCTION(vkGetPhysicalDeviceSurfaceSupportKHR)\n\tINIT_INSTANCE_FUNCTION(vkCreateDebugReportCallbackEXT)\n\tINIT_INSTANCE_FUNCTION(vkDestroyDebugReportCallbackEXT)\n\n\t//\n\t// Create debug callback.\n\t// \n#ifndef NDEBUG\n\t{\n\t\tVkDebugReportCallbackCreateInfoEXT desc{ VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT };\n\t\tdesc.flags = VK_DEBUG_REPORT_WARNING_BIT_EXT |\n\t\t\t\t\t VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT |\n\t\t\t\t\t VK_DEBUG_REPORT_ERROR_BIT_EXT;\n\t\tdesc.pfnCallback = &debug_callback;\n\t\tVK_CHECK(vkCreateDebugReportCallbackEXT(vk.instance, &desc, nullptr, &vk.debug_callback));\n\t}\n#endif\n\n\t//\n\t// Get device level functions.\n\t//\n\tcreate_device();\n\tINIT_DEVICE_FUNCTION(vkAllocateCommandBuffers)\n\tINIT_DEVICE_FUNCTION(vkAllocateDescriptorSets)\n\tINIT_DEVICE_FUNCTION(vkAllocateMemory)\n\tINIT_DEVICE_FUNCTION(vkBeginCommandBuffer)\n\tINIT_DEVICE_FUNCTION(vkBindBufferMemory)\n\tINIT_DEVICE_FUNCTION(vkBindImageMemory)\n\tINIT_DEVICE_FUNCTION(vkCmdBeginRenderPass)\n\tINIT_DEVICE_FUNCTION(vkCmdBindDescriptorSets)\n\tINIT_DEVICE_FUNCTION(vkCmdBindIndexBuffer)\n\tINIT_DEVICE_FUNCTION(vkCmdBindPipeline)\n\tINIT_DEVICE_FUNCTION(vkCmdBindVertexBuffers)\n\tINIT_DEVICE_FUNCTION(vkCmdBlitImage)\n\tINIT_DEVICE_FUNCTION(vkCmdClearAttachments)\n\tINIT_DEVICE_FUNCTION(vkCmdCopyBuffer)\n\tINIT_DEVICE_FUNCTION(vkCmdCopyBufferToImage)\n\tINIT_DEVICE_FUNCTION(vkCmdCopyImage)\n\tINIT_DEVICE_FUNCTION(vkCmdDispatch)\n\tINIT_DEVICE_FUNCTION(vkCmdDraw)\n\tINIT_DEVICE_FUNCTION(vkCmdDrawIndexed)\n\tINIT_DEVICE_FUNCTION(vkCmdEndRenderPass)\n\tINIT_DEVICE_FUNCTION(vkCmdPipelineBarrier)\n\tINIT_DEVICE_FUNCTION(vkCmdPushConstants)\n\tINIT_DEVICE_FUNCTION(vkCmdSetDepthBias)\n\tINIT_DEVICE_FUNCTION(vkCmdSetScissor)\n\tINIT_DEVICE_FUNCTION(vkCmdSetViewport)\n\tINIT_DEVICE_FUNCTION(vkCreateBuffer)\n\tINIT_DEVICE_FUNCTION(vkCreateCommandPool)\n\tINIT_DEVICE_FUNCTION(vkCreateComputePipelines)\n\tINIT_DEVICE_FUNCTION(vkCreateDescriptorPool)\n\tINIT_DEVICE_FUNCTION(vkCreateDescriptorSetLayout)\n\tINIT_DEVICE_FUNCTION(vkCreateFence)\n\tINIT_DEVICE_FUNCTION(vkCreateFramebuffer)\n\tINIT_DEVICE_FUNCTION(vkCreateGraphicsPipelines)\n\tINIT_DEVICE_FUNCTION(vkCreateImage)\n\tINIT_DEVICE_FUNCTION(vkCreateImageView)\n\tINIT_DEVICE_FUNCTION(vkCreatePipelineLayout)\n\tINIT_DEVICE_FUNCTION(vkCreateRenderPass)\n\tINIT_DEVICE_FUNCTION(vkCreateSampler)\n\tINIT_DEVICE_FUNCTION(vkCreateSemaphore)\n\tINIT_DEVICE_FUNCTION(vkCreateShaderModule)\n\tINIT_DEVICE_FUNCTION(vkDestroyBuffer)\n\tINIT_DEVICE_FUNCTION(vkDestroyCommandPool)\n\tINIT_DEVICE_FUNCTION(vkDestroyDescriptorPool)\n\tINIT_DEVICE_FUNCTION(vkDestroyDescriptorSetLayout)\n\tINIT_DEVICE_FUNCTION(vkDestroyDevice)\n\tINIT_DEVICE_FUNCTION(vkDestroyFence)\n\tINIT_DEVICE_FUNCTION(vkDestroyFramebuffer)\n\tINIT_DEVICE_FUNCTION(vkDestroyImage)\n\tINIT_DEVICE_FUNCTION(vkDestroyImageView)\n\tINIT_DEVICE_FUNCTION(vkDestroyPipeline)\n\tINIT_DEVICE_FUNCTION(vkDestroyPipelineLayout)\n\tINIT_DEVICE_FUNCTION(vkDestroyRenderPass)\n\tINIT_DEVICE_FUNCTION(vkDestroySampler)\n\tINIT_DEVICE_FUNCTION(vkDestroySemaphore)\n\tINIT_DEVICE_FUNCTION(vkDestroyShaderModule)\n\tINIT_DEVICE_FUNCTION(vkDeviceWaitIdle)\n\tINIT_DEVICE_FUNCTION(vkEndCommandBuffer)\n\tINIT_DEVICE_FUNCTION(vkFreeCommandBuffers)\n\tINIT_DEVICE_FUNCTION(vkFreeDescriptorSets)\n\tINIT_DEVICE_FUNCTION(vkFreeMemory)\n\tINIT_DEVICE_FUNCTION(vkGetBufferMemoryRequirements)\n\tINIT_DEVICE_FUNCTION(vkGetDeviceQueue)\n\tINIT_DEVICE_FUNCTION(vkGetImageMemoryRequirements)\n\tINIT_DEVICE_FUNCTION(vkGetImageSubresourceLayout)\n\tINIT_DEVICE_FUNCTION(vkMapMemory)\n\tINIT_DEVICE_FUNCTION(vkQueueSubmit)\n\tINIT_DEVICE_FUNCTION(vkQueueWaitIdle)\n\tINIT_DEVICE_FUNCTION(vkResetDescriptorPool)\n\tINIT_DEVICE_FUNCTION(vkResetFences)\n\tINIT_DEVICE_FUNCTION(vkUpdateDescriptorSets)\n\tINIT_DEVICE_FUNCTION(vkWaitForFences)\n\tINIT_DEVICE_FUNCTION(vkAcquireNextImageKHR)\n\tINIT_DEVICE_FUNCTION(vkCreateSwapchainKHR)\n\tINIT_DEVICE_FUNCTION(vkDestroySwapchainKHR)\n\tINIT_DEVICE_FUNCTION(vkGetSwapchainImagesKHR)\n\tINIT_DEVICE_FUNCTION(vkQueuePresentKHR)\n}\n\n#undef INIT_INSTANCE_FUNCTION\n#undef INIT_DEVICE_FUNCTION\n\nstatic void deinit_vulkan_library() {\n\tvkCreateInstance                            = nullptr;\n\tvkEnumerateInstanceExtensionProperties\t\t= nullptr;\n\n\tvkCreateDevice\t\t\t\t\t\t\t\t= nullptr;\n\tvkDestroyInstance\t\t\t\t\t\t\t= nullptr;\n\tvkEnumerateDeviceExtensionProperties\t\t= nullptr;\n\tvkEnumeratePhysicalDevices\t\t\t\t\t= nullptr;\n\tvkGetDeviceProcAddr\t\t\t\t\t\t\t= nullptr;\n\tvkGetPhysicalDeviceFeatures\t\t\t\t\t= nullptr;\n\tvkGetPhysicalDeviceFormatProperties\t\t\t= nullptr;\n\tvkGetPhysicalDeviceMemoryProperties\t\t\t= nullptr;\n\tvkGetPhysicalDeviceProperties\t\t\t\t= nullptr;\n\tvkGetPhysicalDeviceQueueFamilyProperties\t= nullptr;\n\tvkCreateWin32SurfaceKHR\t\t\t\t\t\t= nullptr;\n\tvkDestroySurfaceKHR\t\t\t\t\t\t\t= nullptr;\n\tvkGetPhysicalDeviceSurfaceCapabilitiesKHR\t= nullptr;\n\tvkGetPhysicalDeviceSurfaceFormatsKHR\t\t= nullptr;\n\tvkGetPhysicalDeviceSurfacePresentModesKHR\t= nullptr;\n\tvkGetPhysicalDeviceSurfaceSupportKHR\t\t= nullptr;\n#ifndef NDEBUG\n\tvkCreateDebugReportCallbackEXT\t\t\t\t= nullptr;\n\tvkDestroyDebugReportCallbackEXT\t\t\t\t= nullptr;\n#endif\n\n\tvkAllocateCommandBuffers\t\t\t\t\t= nullptr;\n\tvkAllocateDescriptorSets\t\t\t\t\t= nullptr;\n\tvkAllocateMemory\t\t\t\t\t\t\t= nullptr;\n\tvkBeginCommandBuffer\t\t\t\t\t\t= nullptr;\n\tvkBindBufferMemory\t\t\t\t\t\t\t= nullptr;\n\tvkBindImageMemory\t\t\t\t\t\t\t= nullptr;\n\tvkCmdBeginRenderPass\t\t\t\t\t\t= nullptr;\n\tvkCmdBindDescriptorSets\t\t\t\t\t\t= nullptr;\n\tvkCmdBindIndexBuffer\t\t\t\t\t\t= nullptr;\n\tvkCmdBindPipeline\t\t\t\t\t\t\t= nullptr;\n\tvkCmdBindVertexBuffers\t\t\t\t\t\t= nullptr;\n\tvkCmdBlitImage\t\t\t\t\t\t\t\t= nullptr;\n\tvkCmdClearAttachments\t\t\t\t\t\t= nullptr;\n\tvkCmdCopyBuffer\t\t\t\t\t\t\t\t= nullptr;\n\tvkCmdCopyBufferToImage\t\t\t\t\t\t= nullptr;\n\tvkCmdCopyImage\t\t\t\t\t\t\t\t= nullptr;\n\tvkCmdDispatch\t\t\t\t\t\t\t\t= nullptr;\n\tvkCmdDraw\t\t\t\t\t\t\t\t\t= nullptr;\n\tvkCmdDrawIndexed\t\t\t\t\t\t\t= nullptr;\n\tvkCmdEndRenderPass\t\t\t\t\t\t\t= nullptr;\n\tvkCmdPipelineBarrier\t\t\t\t\t\t= nullptr;\n\tvkCmdPushConstants\t\t\t\t\t\t\t= nullptr;\n\tvkCmdSetDepthBias\t\t\t\t\t\t\t= nullptr;\n\tvkCmdSetScissor\t\t\t\t\t\t\t\t= nullptr;\n\tvkCmdSetViewport\t\t\t\t\t\t\t= nullptr;\n\tvkCreateBuffer\t\t\t\t\t\t\t\t= nullptr;\n\tvkCreateCommandPool\t\t\t\t\t\t\t= nullptr;\n\tvkCreateComputePipelines\t\t\t\t\t= nullptr;\n\tvkCreateDescriptorPool\t\t\t\t\t\t= nullptr;\n\tvkCreateDescriptorSetLayout\t\t\t\t\t= nullptr;\n\tvkCreateFence\t\t\t\t\t\t\t\t= nullptr;\n\tvkCreateFramebuffer\t\t\t\t\t\t\t= nullptr;\n\tvkCreateGraphicsPipelines\t\t\t\t\t= nullptr;\n\tvkCreateImage\t\t\t\t\t\t\t\t= nullptr;\n\tvkCreateImageView\t\t\t\t\t\t\t= nullptr;\n\tvkCreatePipelineLayout\t\t\t\t\t\t= nullptr;\n\tvkCreateRenderPass\t\t\t\t\t\t\t= nullptr;\n\tvkCreateSampler\t\t\t\t\t\t\t\t= nullptr;\n\tvkCreateSemaphore\t\t\t\t\t\t\t= nullptr;\n\tvkCreateShaderModule\t\t\t\t\t\t= nullptr;\n\tvkDestroyBuffer\t\t\t\t\t\t\t\t= nullptr;\n\tvkDestroyCommandPool\t\t\t\t\t\t= nullptr;\n\tvkDestroyDescriptorPool\t\t\t\t\t\t= nullptr;\n\tvkDestroyDescriptorSetLayout\t\t\t\t= nullptr;\n\tvkDestroyDevice\t\t\t\t\t\t\t\t= nullptr;\n\tvkDestroyFence\t\t\t\t\t\t\t\t= nullptr;\n\tvkDestroyFramebuffer\t\t\t\t\t\t= nullptr;\n\tvkDestroyImage\t\t\t\t\t\t\t\t= nullptr;\n\tvkDestroyImageView\t\t\t\t\t\t\t= nullptr;\n\tvkDestroyPipeline\t\t\t\t\t\t\t= nullptr;\n\tvkDestroyPipelineLayout\t\t\t\t\t\t= nullptr;\n\tvkDestroyRenderPass\t\t\t\t\t\t\t= nullptr;\n\tvkDestroySampler\t\t\t\t\t\t\t= nullptr;\n\tvkDestroySemaphore\t\t\t\t\t\t\t= nullptr;\n\tvkDestroyShaderModule\t\t\t\t\t\t= nullptr;\n\tvkDeviceWaitIdle\t\t\t\t\t\t\t= nullptr;\n\tvkEndCommandBuffer\t\t\t\t\t\t\t= nullptr;\n\tvkFreeCommandBuffers\t\t\t\t\t\t= nullptr;\n\tvkFreeDescriptorSets\t\t\t\t\t\t= nullptr;\n\tvkFreeMemory\t\t\t\t\t\t\t\t= nullptr;\n\tvkGetBufferMemoryRequirements\t\t\t\t= nullptr;\n\tvkGetDeviceQueue\t\t\t\t\t\t\t= nullptr;\n\tvkGetImageMemoryRequirements\t\t\t\t= nullptr;\n\tvkGetImageSubresourceLayout\t\t\t\t\t= nullptr;\n\tvkMapMemory\t\t\t\t\t\t\t\t\t= nullptr;\n\tvkQueueSubmit\t\t\t\t\t\t\t\t= nullptr;\n\tvkQueueWaitIdle\t\t\t\t\t\t\t\t= nullptr;\n\tvkResetDescriptorPool\t\t\t\t\t\t= nullptr;\n\tvkResetFences\t\t\t\t\t\t\t\t= nullptr;\n\tvkUpdateDescriptorSets\t\t\t\t\t\t= nullptr;\n\tvkWaitForFences\t\t\t\t\t\t\t\t= nullptr;\n\tvkAcquireNextImageKHR\t\t\t\t\t\t= nullptr;\n\tvkCreateSwapchainKHR\t\t\t\t\t\t= nullptr;\n\tvkDestroySwapchainKHR\t\t\t\t\t\t= nullptr;\n\tvkGetSwapchainImagesKHR\t\t\t\t\t\t= nullptr;\n\tvkQueuePresentKHR\t\t\t\t\t\t\t= nullptr;\n}\n\nVkPipeline create_pipeline(const Vk_Pipeline_Def&);\nvoid create_gamma_pipeline();\n\nvoid vk_initialize() {\n\tinit_vulkan_library();\n\n    VkPhysicalDeviceFeatures features;\n    vkGetPhysicalDeviceFeatures(vk.physical_device, &features);\n    if (features.shaderClipDistance == VK_FALSE)\n        ri.Error(ERR_FATAL, \"vk_create_instance: shaderClipDistance feature is not supported\");\n    if (features.fillModeNonSolid == VK_FALSE)\n        ri.Error(ERR_FATAL, \"vk_create_instance: fillModeNonSolid feature is not supported\");\n    if (features.shaderStorageImageWriteWithoutFormat == VK_FALSE)\n        ri.Error(ERR_FATAL, \"vk_create_instance: shaderStorageImageWriteWithoutFormat feature is not supported\");\n\n\tvkGetDeviceQueue(vk.device, vk.queue_family_index, 0, &vk.queue);\n\n\t//\n\t// Swapchain.\n\t//\n\t{\n\t\tvk.swapchain = create_swapchain(vk.physical_device, vk.device, vk.surface, vk.surface_format);\n\n\t\tVK_CHECK(vkGetSwapchainImagesKHR(vk.device, vk.swapchain, &vk.swapchain_image_count, nullptr));\n\t\tvk.swapchain_image_count = std::min(vk.swapchain_image_count, (uint32_t)MAX_SWAPCHAIN_IMAGES);\n\t\tVK_CHECK(vkGetSwapchainImagesKHR(vk.device, vk.swapchain, &vk.swapchain_image_count, vk.swapchain_images));\n\n\t\tfor (uint32_t i = 0; i < vk.swapchain_image_count; i++) {\n\t\t\tVkImageViewCreateInfo desc{ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };\n\t\t\tdesc.image = vk.swapchain_images[i];\n\t\t\tdesc.viewType = VK_IMAGE_VIEW_TYPE_2D;\n\t\t\tdesc.format = vk.surface_format.format;\n\t\t\tdesc.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;\n\t\t\tdesc.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;\n\t\t\tdesc.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;\n\t\t\tdesc.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;\n\t\t\tdesc.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;\n\t\t\tdesc.subresourceRange.baseMipLevel = 0;\n\t\t\tdesc.subresourceRange.levelCount = 1;\n\t\t\tdesc.subresourceRange.baseArrayLayer = 0;\n\t\t\tdesc.subresourceRange.layerCount = 1;\n\t\t\tVK_CHECK(vkCreateImageView(vk.device, &desc, nullptr, &vk.swapchain_image_views[i]));\n\t\t}\n\t}\n\n\t//\n\t// Sync primitives.\n\t//\n\t{\n        VkSemaphoreCreateInfo desc{ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO };\n        for (uint32_t i = 0; i < vk.swapchain_image_count; i++) {\n            VK_CHECK(vkCreateSemaphore(vk.device, &desc, nullptr, &vk.rendering_finished[i]));\n        }\n        VK_CHECK(vkCreateSemaphore(vk.device, &desc, nullptr, &vk.image_acquired));\n\n\t\tVkFenceCreateInfo fence_desc{ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO };\n\t\tfence_desc.flags = VK_FENCE_CREATE_SIGNALED_BIT;\n\t\tVK_CHECK(vkCreateFence(vk.device, &fence_desc, nullptr, &vk.rendering_finished_fence));\n\t}\n\n\t//\n\t// Command pool.\n\t//\n\t{\n\t\tVkCommandPoolCreateInfo desc{ VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO };\n\t\tdesc.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;\n\t\tdesc.queueFamilyIndex = vk.queue_family_index;\n\t\tVK_CHECK(vkCreateCommandPool(vk.device, &desc, nullptr, &vk.command_pool));\n\t}\n\n\t//\n\t// Command buffer.\n\t//\n\t{\n\t\tVkCommandBufferAllocateInfo alloc_info{ VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };\n\t\talloc_info.commandPool = vk.command_pool;\n\t\talloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;\n\t\talloc_info.commandBufferCount = 1;\n\t\tVK_CHECK(vkAllocateCommandBuffers(vk.device, &alloc_info, &vk.command_buffer));\n\t}\n\n\t//\n\t// Output image.\n\t//\n\t{\n\t\tVkImageCreateInfo image_ci{ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };\n\t\timage_ci.imageType = VK_IMAGE_TYPE_2D;\n\t\timage_ci.format = output_image_format;;\n\t\timage_ci.extent.width = glConfig.vidWidth;\n\t\timage_ci.extent.height = glConfig.vidHeight;\n\t\timage_ci.extent.depth = 1;\n\t\timage_ci.mipLevels = 1;\n\t\timage_ci.arrayLayers = 1;\n\t\timage_ci.samples = VK_SAMPLE_COUNT_1_BIT;\n\t\timage_ci.tiling = VK_IMAGE_TILING_OPTIMAL;\n\t\timage_ci.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;\n\t\timage_ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE;\n\t\timage_ci.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;\n\t\tVK_CHECK(vkCreateImage(vk.device, &image_ci, nullptr, &vk.output_image));\n\n\t\tVkMemoryRequirements memory_requirements;\n\t\tvkGetImageMemoryRequirements(vk.device, vk.output_image, &memory_requirements);\n\t\tVkMemoryAllocateInfo alloc_info{ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };\n\t\talloc_info.allocationSize = memory_requirements.size;\n\t\talloc_info.memoryTypeIndex = find_memory_type(vk.physical_device, memory_requirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);\n\t\tVK_CHECK(vkAllocateMemory(vk.device, &alloc_info, nullptr, &vk.output_image_memory));\n\t\tVK_CHECK(vkBindImageMemory(vk.device, vk.output_image, vk.output_image_memory, 0));\n\n\t\tVkImageViewCreateInfo image_view_ci{ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };\n\t\timage_view_ci.image = vk.output_image;\n\t\timage_view_ci.viewType = VK_IMAGE_VIEW_TYPE_2D;\n\t\timage_view_ci.format = output_image_format;\n\t\timage_view_ci.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };\n\t\tVK_CHECK(vkCreateImageView(vk.device, &image_view_ci, nullptr, &vk.output_image_view));\n\t}\n\n\t//\n\t// Depth attachment image.\n\t// \n\t{\n\t\tVkFormat depth_format = get_depth_format(vk.physical_device);\n\n\t\t// create depth image\n\t\t{\n\t\t\tVkImageCreateInfo desc{ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };\n\t\t\tdesc.imageType = VK_IMAGE_TYPE_2D;\n\t\t\tdesc.format = depth_format;\n\t\t\tdesc.extent.width = glConfig.vidWidth;\n\t\t\tdesc.extent.height = glConfig.vidHeight;\n\t\t\tdesc.extent.depth = 1;\n\t\t\tdesc.mipLevels = 1;\n\t\t\tdesc.arrayLayers = 1;\n\t\t\tdesc.samples = VK_SAMPLE_COUNT_1_BIT;\n\t\t\tdesc.tiling = VK_IMAGE_TILING_OPTIMAL;\n\t\t\tdesc.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;\n\t\t\tdesc.sharingMode = VK_SHARING_MODE_EXCLUSIVE;\n\t\t\tdesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;\n\t\t\tVK_CHECK(vkCreateImage(vk.device, &desc, nullptr, &vk.depth_image));\n\t\t}\n\n\t\t// allocate depth image memory\n\t\t{\n\t\t\tVkMemoryRequirements memory_requirements;\n\t\t\tvkGetImageMemoryRequirements(vk.device, vk.depth_image, &memory_requirements);\n\n\t\t\tVkMemoryAllocateInfo alloc_info{ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };\n\t\t\talloc_info.allocationSize = memory_requirements.size;\n\t\t\talloc_info.memoryTypeIndex = find_memory_type(vk.physical_device, memory_requirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);\n\n\t\t\tVK_CHECK(vkAllocateMemory(vk.device, &alloc_info, nullptr, &vk.depth_image_memory));\n\t\t\tVK_CHECK(vkBindImageMemory(vk.device, vk.depth_image, vk.depth_image_memory, 0));\n\t\t}\n\n\t\t// create depth image view\n\t\t{\n\t\t\tVkImageViewCreateInfo desc{ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };\n\t\t\tdesc.image = vk.depth_image;\n\t\t\tdesc.viewType = VK_IMAGE_VIEW_TYPE_2D;\n\t\t\tdesc.format = depth_format;\n\t\t\tdesc.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;\n\t\t\tdesc.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;\n\t\t\tdesc.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;\n\t\t\tdesc.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;\n\t\t\tdesc.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;\n\t\t\tdesc.subresourceRange.baseMipLevel = 0;\n\t\t\tdesc.subresourceRange.levelCount = 1;\n\t\t\tdesc.subresourceRange.baseArrayLayer = 0;\n\t\t\tdesc.subresourceRange.layerCount = 1;\n\t\t\tVK_CHECK(vkCreateImageView(vk.device, &desc, nullptr, &vk.depth_image_view));\n\t\t}\n\n\t\tVkImageAspectFlags image_aspect_flags = VK_IMAGE_ASPECT_DEPTH_BIT;\n\t\tif (r_stencilbits->integer)\n\t\t\timage_aspect_flags |= VK_IMAGE_ASPECT_STENCIL_BIT;\n\n\t\trecord_and_run_commands(vk.command_pool, vk.queue, [&image_aspect_flags](VkCommandBuffer command_buffer) {\n\t\t\trecord_image_layout_transition(command_buffer, vk.depth_image, image_aspect_flags, 0, VK_IMAGE_LAYOUT_UNDEFINED,\n\t\t\t\tVK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);\n\t\t});\n\t}\n\n\t//\n\t// Renderpass.\n\t//\n\t{\n\t\tVkFormat depth_format = get_depth_format(vk.physical_device);\n\t\tvk.render_pass = create_render_pass(vk.device, output_image_format, depth_format);\n\t}\n\n\t//\n\t// Framebuffer for output image rendering.\n\t//\n\t{\n\t\tVkImageView attachments[2] = { vk.output_image_view, vk.depth_image_view };\n\t\tVkFramebufferCreateInfo create_info{ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO };\n\t\tcreate_info.renderPass = vk.render_pass;\n\t\tcreate_info.attachmentCount = 2;\n\t\tcreate_info.pAttachments = attachments;\n\t\tcreate_info.width = glConfig.vidWidth;\n\t\tcreate_info.height = glConfig.vidHeight;\n\t\tcreate_info.layers = 1;\n\t\tVK_CHECK(vkCreateFramebuffer(vk.device, &create_info, nullptr, &vk.framebuffer));\n\t}\n\n\t// Descriptor pool.\n\t{\n\t\tVkDescriptorPoolSize pool_size;\n\t\tpool_size.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;\n\t\tpool_size.descriptorCount = MAX_DRAWIMAGES;\n\n\t\tVkDescriptorPoolCreateInfo create_info{ VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };\n\t\tcreate_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; // used by the cinematic images\n\t\tcreate_info.maxSets = MAX_DRAWIMAGES;\n\t\tcreate_info.poolSizeCount = 1;\n\t\tcreate_info.pPoolSizes = &pool_size;\n\t\tVK_CHECK(vkCreateDescriptorPool(vk.device, &create_info, nullptr, &vk.descriptor_pool));\n\t}\n\n\t// Gamma descriptor pool\n\t{\n\t\tVkDescriptorPoolSize pool_sizes[3];\n\t\tpool_sizes[0].type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;\n\t\tpool_sizes[0].descriptorCount = 1;\n\t\tpool_sizes[1].type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;\n\t\tpool_sizes[1].descriptorCount = 1;\n\t\tpool_sizes[2].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;\n\t\tpool_sizes[2].descriptorCount = 1;\n\n\t\tVkDescriptorPoolCreateInfo create_info{ VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };\n\t\tcreate_info.maxSets = 1;\n\t\tcreate_info.poolSizeCount = 3;\n\t\tcreate_info.pPoolSizes = pool_sizes;\n\t\tVK_CHECK(vkCreateDescriptorPool(vk.device, &create_info, nullptr, &vk.gamma_descriptor_pool));\n\n\t}\n\n\t// Main set layout\n\t{\n\t\tVkDescriptorSetLayoutBinding binding;\n\t\tbinding.binding = 0;\n\t\tbinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;\n\t\tbinding.descriptorCount = 1;\n\t\tbinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;\n\t\tbinding.pImmutableSamplers = nullptr;\n\n        VkDescriptorSetLayoutCreateInfo set_layout_ci{ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };\n        set_layout_ci.bindingCount = 1;\n        set_layout_ci.pBindings = &binding;\n        VK_CHECK(vkCreateDescriptorSetLayout(vk.device, &set_layout_ci, nullptr, &vk.set_layout));\n\t}\n\n\t// Gamma set layout\n\t{\n\t\tVkDescriptorSetLayoutBinding bindings[3];\n\t\tbindings[0].binding = 0;\n\t\tbindings[0].descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;\n\t\tbindings[0].descriptorCount = 1;\n\t\tbindings[0].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;\n\t\tbindings[0].pImmutableSamplers = nullptr;\n\n\t\tbindings[1].binding = 1;\n\t\tbindings[1].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;\n\t\tbindings[1].descriptorCount = 1;\n\t\tbindings[1].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;\n\t\tbindings[1].pImmutableSamplers = nullptr;\n\n\t\tbindings[2].binding = 2;\n\t\tbindings[2].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;\n\t\tbindings[2].descriptorCount = 1;\n\t\tbindings[2].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;\n\t\tbindings[2].pImmutableSamplers = nullptr;\n\n        VkDescriptorSetLayoutCreateInfo set_layout_ci{ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };\n\t\tset_layout_ci.bindingCount = 3;\n\t\tset_layout_ci.pBindings = bindings;\n        VK_CHECK(vkCreateDescriptorSetLayout(vk.device, &set_layout_ci, nullptr, &vk.gamma_set_layout));\n\t}\n\n\t// Main pipeline layout\n\t{\n\t\tVkPushConstantRange push_range;\n\t\tpush_range.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;\n\t\tpush_range.offset = 0;\n\t\tpush_range.size = 128; // 32 floats\n\n\t\tVkDescriptorSetLayout set_layouts[2] = {vk.set_layout, vk.set_layout};\n\n\t\tVkPipelineLayoutCreateInfo pipeline_layout_ci{ VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO };\n\t\tpipeline_layout_ci.setLayoutCount = 2;\n\t\tpipeline_layout_ci.pSetLayouts = set_layouts;\n\t\tpipeline_layout_ci.pushConstantRangeCount = 1;\n\t\tpipeline_layout_ci.pPushConstantRanges = &push_range;\n\t\tVK_CHECK(vkCreatePipelineLayout(vk.device, &pipeline_layout_ci, nullptr, &vk.pipeline_layout));\n\t}\n\n\t// Gamma pipeline layout\n\t{\n\t\tVkPushConstantRange push_constants;\n\t\tpush_constants.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;\n\t\tpush_constants.offset = 0;\n\t\tpush_constants.size = 12; // 3 uint\n\n\t\tVkPipelineLayoutCreateInfo pipeline_layout_ci{ VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO };\n\t\tpipeline_layout_ci.setLayoutCount = 1;\n\t\tpipeline_layout_ci.pSetLayouts = &vk.gamma_set_layout;\n\t\tpipeline_layout_ci.pushConstantRangeCount = 1;\n\t\tpipeline_layout_ci.pPushConstantRanges = &push_constants;\n\t\tVK_CHECK(vkCreatePipelineLayout(vk.device, &pipeline_layout_ci, nullptr, &vk.gamma_pipeline_layout));\n\t}\n\n\t//\n\t// Geometry buffers.\n\t//\n\t{\n\t\tVkBufferCreateInfo desc{ VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };\n\t\tdesc.sharingMode = VK_SHARING_MODE_EXCLUSIVE;\n\t\tdesc.size = VERTEX_BUFFER_SIZE;\n\t\tdesc.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;\n\t\tVK_CHECK(vkCreateBuffer(vk.device, &desc, nullptr, &vk.vertex_buffer));\n\n\t\tdesc.size = INDEX_BUFFER_SIZE;\n\t\tdesc.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT;\n\t\tVK_CHECK(vkCreateBuffer(vk.device, &desc, nullptr, &vk.index_buffer));\n\n\t\tVkMemoryRequirements vb_memory_requirements;\n\t\tvkGetBufferMemoryRequirements(vk.device, vk.vertex_buffer, &vb_memory_requirements);\n\n\t\tVkMemoryRequirements ib_memory_requirements;\n\t\tvkGetBufferMemoryRequirements(vk.device, vk.index_buffer, &ib_memory_requirements);\n\n\t\tVkDeviceSize mask = ~(ib_memory_requirements.alignment - 1);\n\t\tVkDeviceSize index_buffer_offset = (vb_memory_requirements.size + ib_memory_requirements.alignment - 1) & mask;\n\n\t\tuint32_t memory_type_bits = vb_memory_requirements.memoryTypeBits & ib_memory_requirements.memoryTypeBits;\n\t\tuint32_t memory_type = find_memory_type(vk.physical_device, memory_type_bits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);\n\n\t\tVkMemoryAllocateInfo alloc_info{ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };\n\t\talloc_info.allocationSize = index_buffer_offset + ib_memory_requirements.size;\n\t\talloc_info.memoryTypeIndex = memory_type;\n\t\tVK_CHECK(vkAllocateMemory(vk.device, &alloc_info, nullptr, &vk.geometry_buffer_memory));\n\n\t\tvkBindBufferMemory(vk.device, vk.vertex_buffer, vk.geometry_buffer_memory, 0);\n\t\tvkBindBufferMemory(vk.device, vk.index_buffer, vk.geometry_buffer_memory, index_buffer_offset);\n\n\t\tvoid* data;\n\t\tVK_CHECK(vkMapMemory(vk.device, vk.geometry_buffer_memory, 0, VK_WHOLE_SIZE, 0, &data));\n\t\tvk.vertex_buffer_ptr = (byte*)data;\n\t\tvk.index_buffer_ptr = (byte*)data + index_buffer_offset;\n\t}\n\n\t//\n\t// Gamma buffer.\n\t//\n\t{\n        VkBufferCreateInfo desc{ VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };\n\t\tdesc.size = 256 * sizeof(float);\n\t\tdesc.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;\n\t\tVK_CHECK(vkCreateBuffer(vk.device, &desc, nullptr, &vk.gamma_buffer));\n\n\t\tVkMemoryRequirements memory_requirements;\n\t\tvkGetBufferMemoryRequirements(vk.device, vk.gamma_buffer, &memory_requirements);\n\n        uint32_t memory_type = find_memory_type(vk.physical_device, memory_requirements.memoryTypeBits,\n            VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);\n\n\t\tVkMemoryAllocateInfo alloc_info{ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };\n\t\talloc_info.allocationSize = memory_requirements.size;\n\t\talloc_info.memoryTypeIndex = memory_type;\n\t\tVK_CHECK(vkAllocateMemory(vk.device, &alloc_info, nullptr, &vk.gamma_buffer_memory));\n\n\t\tvkBindBufferMemory(vk.device, vk.gamma_buffer, vk.gamma_buffer_memory, 0);\n\t}\n\n\t//\n\t// Shader modules.\n\t//\n\t{\n\t\tauto create_shader_module = [](uint8_t* bytes, int count) {\n\t\t\tif (count % 4 != 0) {\n\t\t\t\tri.Error(ERR_FATAL, \"Vulkan: SPIR-V binary buffer size is not multiple of 4\");\n\t\t\t}\n\t\t\tVkShaderModuleCreateInfo desc{ VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO };\n\t\t\tdesc.codeSize = count;\n\t\t\tdesc.pCode = reinterpret_cast<const uint32_t*>(bytes);\n\t\t\t   \n\t\t\tVkShaderModule module;\n\t\t\tVK_CHECK(vkCreateShaderModule(vk.device, &desc, nullptr, &module));\n\t\t\treturn module;\n\t\t};\n\n\t\textern unsigned char single_texture_vert_spv[];\n\t\textern long long single_texture_vert_spv_size;\n\t\tvk.single_texture_vs = create_shader_module(single_texture_vert_spv, single_texture_vert_spv_size);\n\n\t\textern unsigned char single_texture_clipping_plane_vert_spv[];\n\t\textern long long single_texture_clipping_plane_vert_spv_size;\n\t\tvk.single_texture_clipping_plane_vs = create_shader_module(single_texture_clipping_plane_vert_spv, single_texture_clipping_plane_vert_spv_size);\n\n\t\textern unsigned char single_texture_frag_spv[];\n\t\textern long long single_texture_frag_spv_size;\n\t\tvk.single_texture_fs = create_shader_module(single_texture_frag_spv, single_texture_frag_spv_size);\n\n\t\textern unsigned char multi_texture_vert_spv[];\n\t\textern long long multi_texture_vert_spv_size;\n\t\tvk.multi_texture_vs = create_shader_module(multi_texture_vert_spv, multi_texture_vert_spv_size);\n\n\t\textern unsigned char multi_texture_clipping_plane_vert_spv[];\n\t\textern long long multi_texture_clipping_plane_vert_spv_size;\n\t\tvk.multi_texture_clipping_plane_vs = create_shader_module(multi_texture_clipping_plane_vert_spv, multi_texture_clipping_plane_vert_spv_size);\n\n\t\textern unsigned char multi_texture_mul_frag_spv[];\n\t\textern long long multi_texture_mul_frag_spv_size;\n\t\tvk.multi_texture_mul_fs = create_shader_module(multi_texture_mul_frag_spv, multi_texture_mul_frag_spv_size);\n\n\t\textern unsigned char multi_texture_add_frag_spv[];\n\t\textern long long multi_texture_add_frag_spv_size;\n\t\tvk.multi_texture_add_fs = create_shader_module(multi_texture_add_frag_spv, multi_texture_add_frag_spv_size);\n\t}\n\n\t//\n\t// Standard pipelines.\n\t//\n\t{\n\t\tcreate_gamma_pipeline();\n\n\t\t// skybox\n\t\t{\n\t\t\tVk_Pipeline_Def def;\n\t\t\tdef.shader_type = Vk_Shader_Type::single_texture;\n\t\t\tdef.state_bits = 0;\n\t\t\tdef.face_culling = CT_FRONT_SIDED;\n\t\t\tdef.polygon_offset = false;\n\t\t\tdef.clipping_plane = false;\n\t\t\tdef.mirror = false;\n\t\t\tvk.skybox_pipeline = create_pipeline(def);\n\t\t}\n\n\t\t// Q3 stencil shadows\n\t\t{\n\t\t\t{\n\t\t\t\tVk_Pipeline_Def def;\n\t\t\t\tdef.polygon_offset = false;\n\t\t\t\tdef.state_bits = 0;\n\t\t\t\tdef.shader_type = Vk_Shader_Type::single_texture;\n\t\t\t\tdef.clipping_plane = false;\n\t\t\t\tdef.shadow_phase = Vk_Shadow_Phase::shadow_edges_rendering;\n\n\t\t\t\tcullType_t cull_types[2] = {CT_FRONT_SIDED, CT_BACK_SIDED};\n\t\t\t\tbool mirror_flags[2] = {false, true};\n\n\t\t\t\tfor (int i = 0; i < 2; i++) {\n\t\t\t\t\tdef.face_culling = cull_types[i];\n\t\t\t\t\tfor (int j = 0; j < 2; j++) {\n\t\t\t\t\t\tdef.mirror = mirror_flags[j];\n\t\t\t\t\t\tvk.shadow_volume_pipelines[i][j] = create_pipeline(def);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t{\n\t\t\t\tVk_Pipeline_Def def;\n\t\t\t\tdef.face_culling = CT_FRONT_SIDED;\n\t\t\t\tdef.polygon_offset = false;\n\t\t\t\tdef.state_bits = GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO;\n\t\t\t\tdef.shader_type = Vk_Shader_Type::single_texture;\n\t\t\t\tdef.clipping_plane = false;\n\t\t\t\tdef.mirror = false;\n\t\t\t\tdef.shadow_phase = Vk_Shadow_Phase::fullscreen_quad_rendering;\n\t\t\t\tvk.shadow_finish_pipeline = create_pipeline(def);\n\t\t\t}\n\t\t}\n\n\t\t// fog and dlights\n\t\t{\n\t\t\tVk_Pipeline_Def def;\n\t\t\tdef.shader_type = Vk_Shader_Type::single_texture;\n\t\t\tdef.clipping_plane = false;\n\t\t\tdef.mirror = false;\n\n\t\t\tunsigned int fog_state_bits[2] = {\n\t\t\t\tGLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_EQUAL,\n\t\t\t\tGLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA\n\t\t\t};\n\t\t\tunsigned int dlight_state_bits[2] = {\n\t\t\t\tGLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL,\n\t\t\t\tGLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL\n\t\t\t};\n\t\t\tbool polygon_offset[2] = {false, true};\n\n\t\t\tfor (int i = 0; i < 2; i++) {\n\t\t\t\tunsigned fog_state = fog_state_bits[i];\n\t\t\t\tunsigned dlight_state = dlight_state_bits[i];\n\n\t\t\t\tfor (int j = 0; j < 3; j++) {\n\t\t\t\t\tdef.face_culling = j; // cullType_t value\n\n\t\t\t\t\tfor (int k = 0; k < 2; k++) {\n\t\t\t\t\t\tdef.polygon_offset = polygon_offset[k];\n\n\t\t\t\t\t\tdef.state_bits = fog_state;\n\t\t\t\t\t\tvk.fog_pipelines[i][j][k] = create_pipeline(def);\n\n\t\t\t\t\t\tdef.state_bits = dlight_state;\n\t\t\t\t\t\tvk.dlight_pipelines[i][j][k] = create_pipeline(def);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// debug pipelines\n\t\t{\n\t\t\tVk_Pipeline_Def def;\n\t\t\tdef.state_bits = GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE;\n\t\t\tvk.tris_debug_pipeline = create_pipeline(def);\n\t\t}\n\t\t{\n\t\t\tVk_Pipeline_Def def;\n\t\t\tdef.state_bits = GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE;\n\t\t\tdef.face_culling = CT_BACK_SIDED;\n\t\t\tvk.tris_mirror_debug_pipeline = create_pipeline(def);\n\t\t}\n\t\t{\n\t\t\tVk_Pipeline_Def def;\n\t\t\tdef.state_bits = GLS_DEPTHMASK_TRUE;\n\t\t\tdef.line_primitives = true;\n\t\t\tvk.normals_debug_pipeline = create_pipeline(def);\n\t\t}\n\t\t{\n\t\t\tVk_Pipeline_Def def;\n\t\t\tdef.state_bits = GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE;\n\t\t\tvk.surface_debug_pipeline_solid = create_pipeline(def);\n\t\t}\n\t\t{\n\t\t\tVk_Pipeline_Def def;\n\t\t\tdef.state_bits = GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE;\n\t\t\tdef.line_primitives = true;\n\t\t\tvk.surface_debug_pipeline_outline = create_pipeline(def);\n\t\t}\n\t\t{\n\t\t\tVk_Pipeline_Def def;\n\t\t\tdef.state_bits = GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA;\n\t\t\tvk.images_debug_pipeline = create_pipeline(def);\n\t\t}\n\t}\n\tvk.active = true;\n}\n\nvoid vk_shutdown() {\n\tvkDestroyImage(vk.device, vk.output_image, nullptr);\n\tvkFreeMemory(vk.device, vk.output_image_memory, nullptr);\n\tvkDestroyImageView(vk.device, vk.output_image_view, nullptr);\n\n\tvkDestroyImage(vk.device, vk.depth_image, nullptr);\n\tvkFreeMemory(vk.device, vk.depth_image_memory, nullptr);\n\tvkDestroyImageView(vk.device, vk.depth_image_view, nullptr);\n\n\tvkDestroyFramebuffer(vk.device, vk.framebuffer, nullptr);\n\tvkDestroyRenderPass(vk.device, vk.render_pass, nullptr);\n\n\tvkDestroyCommandPool(vk.device, vk.command_pool, nullptr);\n\n\tfor (uint32_t i = 0; i < vk.swapchain_image_count; i++) {\n\t\tvkDestroyImageView(vk.device, vk.swapchain_image_views[i], nullptr);\n\t\tvkDestroySemaphore(vk.device, vk.rendering_finished[i], nullptr);\n\t}\n\n\tvkDestroyDescriptorPool(vk.device, vk.descriptor_pool, nullptr);\n\tvkDestroyDescriptorPool(vk.device, vk.gamma_descriptor_pool, nullptr);\n\tvkDestroyDescriptorSetLayout(vk.device, vk.set_layout, nullptr);\n\tvkDestroyDescriptorSetLayout(vk.device, vk.gamma_set_layout, nullptr);\n\tvkDestroyPipelineLayout(vk.device, vk.pipeline_layout, nullptr);\n\tvkDestroyPipelineLayout(vk.device, vk.gamma_pipeline_layout, nullptr);\n\tvkDestroyBuffer(vk.device, vk.vertex_buffer, nullptr);\n\tvkDestroyBuffer(vk.device, vk.index_buffer, nullptr);\n\tvkFreeMemory(vk.device, vk.geometry_buffer_memory, nullptr);\n\tvkDestroyBuffer(vk.device, vk.gamma_buffer, nullptr);\n\tvkFreeMemory(vk.device, vk.gamma_buffer_memory, nullptr);\n\tvkDestroySemaphore(vk.device, vk.image_acquired, nullptr);\n\tvkDestroyFence(vk.device, vk.rendering_finished_fence, nullptr);\n\n\tvkDestroyShaderModule(vk.device, vk.single_texture_vs, nullptr);\n\tvkDestroyShaderModule(vk.device, vk.single_texture_clipping_plane_vs, nullptr);\n\tvkDestroyShaderModule(vk.device, vk.single_texture_fs, nullptr);\n\tvkDestroyShaderModule(vk.device, vk.multi_texture_vs, nullptr);\n\tvkDestroyShaderModule(vk.device, vk.multi_texture_clipping_plane_vs, nullptr);\n\tvkDestroyShaderModule(vk.device, vk.multi_texture_mul_fs, nullptr);\n\tvkDestroyShaderModule(vk.device, vk.multi_texture_add_fs, nullptr);\n\n\tvkDestroyPipeline(vk.device, vk.gamma_pipeline, nullptr);\n\tvkDestroyPipeline(vk.device, vk.skybox_pipeline, nullptr);\n\tfor (int i = 0; i < 2; i++)\n\t\tfor (int j = 0; j < 2; j++) {\n\t\t\tvkDestroyPipeline(vk.device, vk.shadow_volume_pipelines[i][j], nullptr);\n\t\t}\n\tvkDestroyPipeline(vk.device, vk.shadow_finish_pipeline, nullptr);\n\tfor (int i = 0; i < 2; i++)\n\t\tfor (int j = 0; j < 3; j++)\n\t\t\tfor (int k = 0; k < 2; k++) {\n\t\t\t\tvkDestroyPipeline(vk.device, vk.fog_pipelines[i][j][k], nullptr);\n\t\t\t\tvkDestroyPipeline(vk.device, vk.dlight_pipelines[i][j][k], nullptr);\n\t\t\t}\n\tvkDestroyPipeline(vk.device, vk.tris_debug_pipeline, nullptr);\n\tvkDestroyPipeline(vk.device, vk.tris_mirror_debug_pipeline, nullptr);\n\tvkDestroyPipeline(vk.device, vk.normals_debug_pipeline, nullptr);\n\tvkDestroyPipeline(vk.device, vk.surface_debug_pipeline_solid, nullptr);\n\tvkDestroyPipeline(vk.device, vk.surface_debug_pipeline_outline, nullptr);\n\tvkDestroyPipeline(vk.device, vk.images_debug_pipeline, nullptr);\n\n\tvkDestroySwapchainKHR(vk.device, vk.swapchain, nullptr);\n\tvkDestroyDevice(vk.device, nullptr);\n\tvkDestroySurfaceKHR(vk.instance, vk.surface, nullptr);\n\n#ifndef NDEBUG\n\tvkDestroyDebugReportCallbackEXT(vk.instance, vk.debug_callback, nullptr);\n#endif\n\n\tvkDestroyInstance(vk.instance, nullptr);\n\n\tCom_Memset(&vk, 0, sizeof(vk));\n\tdeinit_vulkan_library();\n}\n\nvoid vk_release_resources() {\n\tvkDeviceWaitIdle(vk.device);\n\n\tfor (int i = 0; i < vk_world.num_image_chunks; i++)\n\t\tvkFreeMemory(vk.device, vk_world.image_chunks[i].memory, nullptr);\n\n\tif (vk_world.staging_buffer != VK_NULL_HANDLE)\n\t\tvkDestroyBuffer(vk.device, vk_world.staging_buffer, nullptr);\n\n\tif (vk_world.staging_buffer_memory != VK_NULL_HANDLE)\n\t\tvkFreeMemory(vk.device, vk_world.staging_buffer_memory, nullptr);\n\n\tfor (int i = 0; i < vk_world.num_samplers; i++)\n\t\tvkDestroySampler(vk.device, vk_world.samplers[i], nullptr);\n\n\tfor (int i = 0; i < vk_world.num_pipelines; i++)\n\t\tvkDestroyPipeline(vk.device, vk_world.pipelines[i], nullptr);\n\n\tvk_world.pipeline_create_time = 0.0f;\n\n\tfor (int i = 0; i < MAX_VK_IMAGES; i++) {\n\t\tVk_Image& image = vk_world.images[i];\n\n\t\tif (image.handle != VK_NULL_HANDLE) {\n\t\t\tvkDestroyImage(vk.device, image.handle, nullptr);\n\t\t\tvkDestroyImageView(vk.device, image.view, nullptr);\n\t\t}\n\t}\n\n\tCom_Memset(&vk_world, 0, sizeof(vk_world));\n\n\tVK_CHECK(vkResetDescriptorPool(vk.device, vk.descriptor_pool, 0));\n\n\t// Reset geometry buffer's current offsets.\n\tvk.xyz_elements = 0;\n\tvk.color_st_elements = 0;\n\tvk.index_buffer_offset = 0;\n}\n\nVk_Image vk_create_image(int width, int height, VkFormat format, int mip_levels, bool repeat_texture) {\n\tVk_Image image;\n\n\t// create image\n\t{\n\t\tVkImageCreateInfo desc{ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };\n\t\tdesc.imageType = VK_IMAGE_TYPE_2D;\n\t\tdesc.format = format;\n\t\tdesc.extent.width = width;\n\t\tdesc.extent.height = height;\n\t\tdesc.extent.depth = 1;\n\t\tdesc.mipLevels = mip_levels;\n\t\tdesc.arrayLayers = 1;\n\t\tdesc.samples = VK_SAMPLE_COUNT_1_BIT;\n\t\tdesc.tiling = VK_IMAGE_TILING_OPTIMAL;\n\t\tdesc.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;\n\t\tdesc.sharingMode = VK_SHARING_MODE_EXCLUSIVE;\n\t\tdesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;\n\n\t\tVK_CHECK(vkCreateImage(vk.device, &desc, nullptr, &image.handle));\n\t\tallocate_and_bind_image_memory(image.handle);\n\t}\n\n\t// create image view\n\t{\n\t\tVkImageViewCreateInfo desc{ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };\n\t\tdesc.image = image.handle;\n\t\tdesc.viewType = VK_IMAGE_VIEW_TYPE_2D;\n\t\tdesc.format = format;\n\t\tdesc.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;\n\t\tdesc.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;\n\t\tdesc.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;\n\t\tdesc.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;\n\t\tdesc.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;\n\t\tdesc.subresourceRange.baseMipLevel = 0;\n\t\tdesc.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;\n\t\tdesc.subresourceRange.baseArrayLayer = 0;\n\t\tdesc.subresourceRange.layerCount = 1;\n\t\tVK_CHECK(vkCreateImageView(vk.device, &desc, nullptr, &image.view));\n\t}\n\n\t// create associated descriptor set\n\t{\n\t\tVkDescriptorSetAllocateInfo desc{ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO };\n\t\tdesc.descriptorPool = vk.descriptor_pool;\n\t\tdesc.descriptorSetCount = 1;\n\t\tdesc.pSetLayouts = &vk.set_layout;\n\t\tVK_CHECK(vkAllocateDescriptorSets(vk.device, &desc, &image.descriptor_set));\n\n\t\tvk_update_descriptor_set(image.descriptor_set, image.view, mip_levels > 1, repeat_texture);\n\t\tvk_world.current_descriptor_sets[glState.currenttmu] = image.descriptor_set;\n\t}\n\n\treturn image;\n}\n\nvoid vk_upload_image_data(VkImage image, int width, int height, bool mipmap, const uint8_t* pixels, int bytes_per_pixel) {\n\tVkBufferImageCopy regions[16];\n\tint num_regions = 0;\n\n\tint buffer_size = 0;\n\n\twhile (true) {\n\t\tVkBufferImageCopy region;\n\t\tregion.bufferOffset = buffer_size;\n\t\tregion.bufferRowLength = 0;\n\t\tregion.bufferImageHeight = 0;\n\t\tregion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;\n\t\tregion.imageSubresource.mipLevel = num_regions;\n\t\tregion.imageSubresource.baseArrayLayer = 0;\n\t\tregion.imageSubresource.layerCount = 1;\n\t\tregion.imageOffset = VkOffset3D{ 0, 0, 0 };\n\t\tregion.imageExtent = VkExtent3D{ (uint32_t)width, (uint32_t)height, 1 };\n\n\t\tregions[num_regions] = region;\n\t\tnum_regions++;\n\n\t\tbuffer_size += width * height * bytes_per_pixel;\n\n\t\tif (!mipmap || (width == 1 && height == 1))\n\t\t\tbreak;\n\n\t\twidth >>= 1;\n\t\tif (width < 1) width = 1;\n\n\t\theight >>= 1;\n\t\tif (height < 1) height = 1;\n\t}\n\n\tensure_staging_buffer_allocation(buffer_size);\n\tCom_Memcpy(vk_world.staging_buffer_ptr, pixels, buffer_size);\n\n\trecord_and_run_commands(vk.command_pool, vk.queue,\n\t\t[&image, &num_regions, &regions](VkCommandBuffer command_buffer) {\n\n\t\trecord_image_layout_transition(command_buffer, image, VK_IMAGE_ASPECT_COLOR_BIT,\n\t\t\t0, VK_IMAGE_LAYOUT_UNDEFINED, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);\n\n\t\tvkCmdCopyBufferToImage(command_buffer, vk_world.staging_buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, num_regions, regions);\n\n\t\trecord_image_layout_transition(command_buffer, image, VK_IMAGE_ASPECT_COLOR_BIT,\n\t\t\tVK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);\n\t});\n}\n\nvoid vk_update_descriptor_set(VkDescriptorSet set, VkImageView image_view, bool mipmap, bool repeat_texture) {\n\tVk_Sampler_Def sampler_def;\n\tsampler_def.repeat_texture = repeat_texture;\n\tif (mipmap) {\n\t\tsampler_def.gl_mag_filter = gl_filter_max;\n\t\tsampler_def.gl_min_filter = gl_filter_min;\n\t} else {\n\t\tsampler_def.gl_mag_filter = GL_LINEAR;\n\t\tsampler_def.gl_min_filter = GL_LINEAR;\n\t}\n\n\tVkDescriptorImageInfo image_info;\n\timage_info.sampler = vk_find_sampler(sampler_def);\n\timage_info.imageView = image_view;\n\timage_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;\n\n\tVkWriteDescriptorSet descriptor_write{ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };\n\tdescriptor_write.dstSet = set;\n\tdescriptor_write.dstBinding = 0;\n\tdescriptor_write.dstArrayElement = 0;\n\tdescriptor_write.descriptorCount = 1;\n\tdescriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;\n\tdescriptor_write.pImageInfo = &image_info;\n\tvkUpdateDescriptorSets(vk.device, 1, &descriptor_write, 0, nullptr);\n}\n\nstatic void create_gamma_pipeline() {\n    extern unsigned char apply_gamma_comp_spv[];\n\textern long long apply_gamma_comp_spv_size;\n\n    VkShaderModuleCreateInfo shader_ci{ VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO };\n    shader_ci.codeSize = apply_gamma_comp_spv_size;\n    shader_ci.pCode = reinterpret_cast<const uint32_t*>(apply_gamma_comp_spv);\n    VkShaderModule apply_gamma_shader;\n    VK_CHECK(vkCreateShaderModule(vk.device, &shader_ci, nullptr, &apply_gamma_shader));\n\n\tVkComputePipelineCreateInfo pipeline_ci{ VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO };\n\tpipeline_ci.stage = VkPipelineShaderStageCreateInfo{ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO };\n\tpipeline_ci.stage.stage = VK_SHADER_STAGE_COMPUTE_BIT;\n\tpipeline_ci.stage.module = apply_gamma_shader;\n\tpipeline_ci.stage.pName = \"main\";\n\tpipeline_ci.layout = vk.gamma_pipeline_layout;\n\tVK_CHECK(vkCreateComputePipelines(vk.device, VK_NULL_HANDLE, 1, &pipeline_ci, nullptr, &vk.gamma_pipeline));\n\tvkDestroyShaderModule(vk.device, apply_gamma_shader, nullptr);\n\n\tVkDescriptorSetAllocateInfo set_alloc_info{ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO };\n\tset_alloc_info.descriptorPool = vk.gamma_descriptor_pool;\n\tset_alloc_info.descriptorSetCount = 1;\n\tset_alloc_info.pSetLayouts = &vk.gamma_set_layout;\n\tVK_CHECK(vkAllocateDescriptorSets(vk.device, &set_alloc_info, &vk.gamma_descriptor_set));\n\n\t// Write output image descriptor\n\t{\n\t\tVkDescriptorImageInfo image_info{};\n\t\timage_info.imageView = vk.output_image_view;\n\t\timage_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;\n\t\tVkWriteDescriptorSet descriptor_write{ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };\n\t\tdescriptor_write.dstSet = vk.gamma_descriptor_set;\n\t\tdescriptor_write.dstBinding = 0;\n\t\tdescriptor_write.dstArrayElement = 0;\n\t\tdescriptor_write.descriptorCount = 1;\n\t\tdescriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;\n\t\tdescriptor_write.pImageInfo = &image_info;\n\t\tvkUpdateDescriptorSets(vk.device, 1, &descriptor_write, 0, nullptr);\n\t}\n\t// Write gamma buffer descriptor\n\t{\n\t\tVkDescriptorBufferInfo buffer_info{};\n\t\tbuffer_info.buffer = vk.gamma_buffer;\n\t\tbuffer_info.range = VK_WHOLE_SIZE;\n\t\tVkWriteDescriptorSet descriptor_write{ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };\n\t\tdescriptor_write.dstSet = vk.gamma_descriptor_set;\n\t\tdescriptor_write.dstBinding = 2;\n\t\tdescriptor_write.dstArrayElement = 0;\n\t\tdescriptor_write.descriptorCount = 1;\n\t\tdescriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;\n\t\tdescriptor_write.pBufferInfo = &buffer_info;\n\t\tvkUpdateDescriptorSets(vk.device, 1, &descriptor_write, 0, nullptr);\n\t}\n}\n\nstatic VkPipeline create_pipeline(const Vk_Pipeline_Def& def) {\n\tauto get_shader_stage_desc = [](VkShaderStageFlagBits stage, VkShaderModule shader_module, const char* entry) {\n\t\tVkPipelineShaderStageCreateInfo desc{ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO };\n\t\tdesc.stage = stage;\n\t\tdesc.module = shader_module;\n\t\tdesc.pName = entry;\n\t\treturn desc;\n\t};\n\n\tstruct Specialization_Data {\n\t\tint32_t alpha_test_func;\n\t} specialization_data;\n\n\tif ((def.state_bits & GLS_ATEST_BITS) == 0)\n\t\tspecialization_data.alpha_test_func = 0;\n\telse if (def.state_bits & GLS_ATEST_GT_0)\n\t\tspecialization_data.alpha_test_func = 1;\n\telse if (def.state_bits & GLS_ATEST_LT_80)\n\t\tspecialization_data.alpha_test_func = 2;\n\telse if (def.state_bits & GLS_ATEST_GE_80)\n\t\tspecialization_data.alpha_test_func = 3;\n\telse\n\t\tri.Error(ERR_DROP, \"create_pipeline: invalid alpha test state bits\\n\");\n\n\tVkSpecializationMapEntry specialization_entries[1];\n\tspecialization_entries[0].constantID = 0;\n\tspecialization_entries[0].offset = offsetof(struct Specialization_Data, alpha_test_func);\n\tspecialization_entries[0].size = sizeof(int32_t);\n\n\tVkSpecializationInfo specialization_info;\n\tspecialization_info.mapEntryCount = 1;\n\tspecialization_info.pMapEntries = specialization_entries;\n\tspecialization_info.dataSize = sizeof(Specialization_Data);\n\tspecialization_info.pData = &specialization_data;\n\n\tstd::vector<VkPipelineShaderStageCreateInfo> shader_stages_state;\n\n\tVkShaderModule* vs_module, *fs_module;\n\tif (def.shader_type == Vk_Shader_Type::single_texture) {\n\t\tvs_module = def.clipping_plane ? &vk.single_texture_clipping_plane_vs :  &vk.single_texture_vs;\n\t\tfs_module = &vk.single_texture_fs;\n\t} else if (def.shader_type == Vk_Shader_Type::multi_texture_mul) {\n\t\tvs_module = def.clipping_plane ? &vk.multi_texture_clipping_plane_vs : &vk.multi_texture_vs;\n\t\tfs_module = &vk.multi_texture_mul_fs;\n\t} else if (def.shader_type == Vk_Shader_Type::multi_texture_add) {\n\t\tvs_module = def.clipping_plane ? &vk.multi_texture_clipping_plane_vs : &vk.multi_texture_vs;\n\t\tfs_module = &vk.multi_texture_add_fs;\n\t}\n\tshader_stages_state.push_back(get_shader_stage_desc(VK_SHADER_STAGE_VERTEX_BIT, *vs_module, \"main\"));\n\tshader_stages_state.push_back(get_shader_stage_desc(VK_SHADER_STAGE_FRAGMENT_BIT, *fs_module, \"main\"));\n\n\tif (def.state_bits & GLS_ATEST_BITS)\n\t\tshader_stages_state.back().pSpecializationInfo = &specialization_info;\n\n\t//\n\t// Vertex input\n\t//\n\tVkVertexInputBindingDescription bindings[4];\n\t// xyz array\n\tbindings[0].binding = 0;\n\tbindings[0].stride = sizeof(vec4_t);\n\tbindings[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;\n\n\t// color array\n\tbindings[1].binding = 1;\n\tbindings[1].stride = sizeof(color4ub_t);\n\tbindings[1].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;\n\n\t// st0 array\n\tbindings[2].binding = 2;\n\tbindings[2].stride = sizeof(vec2_t);\n\tbindings[2].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;\n\n\t// st1 array\n\tbindings[3].binding = 3;\n\tbindings[3].stride = sizeof(vec2_t);\n\tbindings[3].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;\n\n\tVkVertexInputAttributeDescription attribs[4];\n\t// xyz\n\tattribs[0].location = 0;\n\tattribs[0].binding = 0;\n\tattribs[0].format = VK_FORMAT_R32G32B32A32_SFLOAT;\n\tattribs[0].offset = 0;\n\n\t// color\n\tattribs[1].location = 1;\n\tattribs[1].binding = 1;\n\tattribs[1].format = VK_FORMAT_R8G8B8A8_UNORM;\n\tattribs[1].offset = 0;\n\n\t// st0\n\tattribs[2].location = 2;\n\tattribs[2].binding = 2;\n\tattribs[2].format = VK_FORMAT_R32G32_SFLOAT;\n\tattribs[2].offset = 0;\n\n\t// st1\n\tattribs[3].location = 3;\n\tattribs[3].binding = 3;\n\tattribs[3].format = VK_FORMAT_R32G32_SFLOAT;\n\tattribs[3].offset = 0;\n\n\tVkPipelineVertexInputStateCreateInfo vertex_input_state{ VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO };\n\tvertex_input_state.vertexBindingDescriptionCount = (def.shader_type == Vk_Shader_Type::single_texture) ? 3 : 4;\n\tvertex_input_state.pVertexBindingDescriptions = bindings;\n\tvertex_input_state.vertexAttributeDescriptionCount = (def.shader_type == Vk_Shader_Type::single_texture) ? 3 : 4;\n\tvertex_input_state.pVertexAttributeDescriptions = attribs;\n\n\t//\n\t// Primitive assembly.\n\t//\n\tVkPipelineInputAssemblyStateCreateInfo input_assembly_state{ VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO };\n\tinput_assembly_state.topology = def.line_primitives ? VK_PRIMITIVE_TOPOLOGY_LINE_LIST : VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;\n\tinput_assembly_state.primitiveRestartEnable = VK_FALSE;\n\n\t//\n\t// Viewport.\n\t//\n\tVkPipelineViewportStateCreateInfo viewport_state{ VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO };\n\tviewport_state.viewportCount = 1;\n\tviewport_state.pViewports = nullptr; // dynamic viewport state\n\tviewport_state.scissorCount = 1;\n\tviewport_state.pScissors = nullptr; // dynamic scissor state\n\n\t//\n\t// Rasterization.\n\t//\n\tVkPipelineRasterizationStateCreateInfo rasterization_state{ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO };\n\trasterization_state.depthClampEnable = VK_FALSE;\n\trasterization_state.rasterizerDiscardEnable = VK_FALSE;\n\trasterization_state.polygonMode = (def.state_bits & GLS_POLYMODE_LINE) ? VK_POLYGON_MODE_LINE : VK_POLYGON_MODE_FILL;\n\n\tif (def.face_culling == CT_TWO_SIDED)\n\t\trasterization_state.cullMode = VK_CULL_MODE_NONE;\n\telse if (def.face_culling == CT_FRONT_SIDED)\n\t\trasterization_state.cullMode = (def.mirror ? VK_CULL_MODE_FRONT_BIT : VK_CULL_MODE_BACK_BIT);\n\telse if (def.face_culling == CT_BACK_SIDED)\n\t\trasterization_state.cullMode = (def.mirror ? VK_CULL_MODE_BACK_BIT : VK_CULL_MODE_FRONT_BIT);\n\telse\n\t\tri.Error(ERR_DROP, \"create_pipeline: invalid face culling mode\\n\");\n\n\trasterization_state.frontFace = VK_FRONT_FACE_CLOCKWISE; // Q3 defaults to clockwise vertex order\n\n\trasterization_state.depthBiasEnable = def.polygon_offset ? VK_TRUE : VK_FALSE;\n\trasterization_state.depthBiasConstantFactor = 0.0f; // dynamic depth bias state\n\trasterization_state.depthBiasClamp = 0.0f; // dynamic depth bias state\n\trasterization_state.depthBiasSlopeFactor = 0.0f; // dynamic depth bias state\n\trasterization_state.lineWidth = 1.0f;\n\n\tVkPipelineMultisampleStateCreateInfo multisample_state{ VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO };\n\tmultisample_state.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;\n\tmultisample_state.sampleShadingEnable = VK_FALSE;\n\tmultisample_state.minSampleShading = 1.0f;\n\tmultisample_state.pSampleMask = nullptr;\n\tmultisample_state.alphaToCoverageEnable = VK_FALSE;\n\tmultisample_state.alphaToOneEnable = VK_FALSE;\n\n\tVkPipelineDepthStencilStateCreateInfo depth_stencil_state{ VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO };\n\tdepth_stencil_state.depthTestEnable = (def.state_bits & GLS_DEPTHTEST_DISABLE) ? VK_FALSE : VK_TRUE;\n\tdepth_stencil_state.depthWriteEnable = (def.state_bits & GLS_DEPTHMASK_TRUE) ? VK_TRUE : VK_FALSE;\n\tdepth_stencil_state.depthCompareOp = (def.state_bits & GLS_DEPTHFUNC_EQUAL) ? VK_COMPARE_OP_EQUAL : VK_COMPARE_OP_LESS_OR_EQUAL;\n\tdepth_stencil_state.depthBoundsTestEnable = VK_FALSE;\n\tdepth_stencil_state.stencilTestEnable = (def.shadow_phase != Vk_Shadow_Phase::disabled) ? VK_TRUE : VK_FALSE;\n\n\tif (def.shadow_phase == Vk_Shadow_Phase::shadow_edges_rendering) {\n\t\tdepth_stencil_state.front.failOp = VK_STENCIL_OP_KEEP;\n\t\tdepth_stencil_state.front.passOp = (def.face_culling == CT_FRONT_SIDED) ? VK_STENCIL_OP_INCREMENT_AND_CLAMP : VK_STENCIL_OP_DECREMENT_AND_CLAMP;\n\t\tdepth_stencil_state.front.depthFailOp = VK_STENCIL_OP_KEEP;\n\t\tdepth_stencil_state.front.compareOp = VK_COMPARE_OP_ALWAYS;\n\t\tdepth_stencil_state.front.compareMask = 255;\n\t\tdepth_stencil_state.front.writeMask = 255;\n\t\tdepth_stencil_state.front.reference = 0;\n\n\t\tdepth_stencil_state.back = depth_stencil_state.front;\n\n\t}  else if (def.shadow_phase == Vk_Shadow_Phase::fullscreen_quad_rendering) {\n\t\tdepth_stencil_state.front.failOp = VK_STENCIL_OP_KEEP;\n\t\tdepth_stencil_state.front.passOp = VK_STENCIL_OP_KEEP;\n\t\tdepth_stencil_state.front.depthFailOp = VK_STENCIL_OP_KEEP;\n\t\tdepth_stencil_state.front.compareOp = VK_COMPARE_OP_NOT_EQUAL;\n\t\tdepth_stencil_state.front.compareMask = 255;\n\t\tdepth_stencil_state.front.writeMask = 255;\n\t\tdepth_stencil_state.front.reference = 0;\n\n\t\tdepth_stencil_state.back = depth_stencil_state.front;\n\n\t} else {\n\t\tdepth_stencil_state.front = {};\n\t\tdepth_stencil_state.back = {};\n\t}\n\n\tdepth_stencil_state.minDepthBounds = 0.0;\n\tdepth_stencil_state.maxDepthBounds = 0.0;\n\n\tVkPipelineColorBlendAttachmentState attachment_blend_state = {};\n\tattachment_blend_state.blendEnable = (def.state_bits & (GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS)) ? VK_TRUE : VK_FALSE;\n\n\tif (def.shadow_phase == Vk_Shadow_Phase::shadow_edges_rendering)\n\t\tattachment_blend_state.colorWriteMask = 0;\n\telse\n\t\tattachment_blend_state.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;\n\t\n\tif (attachment_blend_state.blendEnable) {\n\t\tswitch (def.state_bits & GLS_SRCBLEND_BITS) {\n\t\t\tcase GLS_SRCBLEND_ZERO:\n\t\t\t\tattachment_blend_state.srcColorBlendFactor = VK_BLEND_FACTOR_ZERO;\n\t\t\t\tbreak;\n\t\t\tcase GLS_SRCBLEND_ONE:\n\t\t\t\tattachment_blend_state.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;\n\t\t\t\tbreak;\n\t\t\tcase GLS_SRCBLEND_DST_COLOR:\n\t\t\t\tattachment_blend_state.srcColorBlendFactor = VK_BLEND_FACTOR_DST_COLOR;\n\t\t\t\tbreak;\n\t\t\tcase GLS_SRCBLEND_ONE_MINUS_DST_COLOR:\n\t\t\t\tattachment_blend_state.srcColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR;\n\t\t\t\tbreak;\n\t\t\tcase GLS_SRCBLEND_SRC_ALPHA:\n\t\t\t\tattachment_blend_state.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;\n\t\t\t\tbreak;\n\t\t\tcase GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA:\n\t\t\t\tattachment_blend_state.srcColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;\n\t\t\t\tbreak;\n\t\t\tcase GLS_SRCBLEND_DST_ALPHA:\n\t\t\t\tattachment_blend_state.srcColorBlendFactor = VK_BLEND_FACTOR_DST_ALPHA;\n\t\t\t\tbreak;\n\t\t\tcase GLS_SRCBLEND_ONE_MINUS_DST_ALPHA:\n\t\t\t\tattachment_blend_state.srcColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA;\n\t\t\t\tbreak;\n\t\t\tcase GLS_SRCBLEND_ALPHA_SATURATE:\n\t\t\t\tattachment_blend_state.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA_SATURATE;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tri.Error( ERR_DROP, \"create_pipeline: invalid src blend state bits\\n\" );\n\t\t\t\tbreak;\n\t\t}\n\t\tswitch (def.state_bits & GLS_DSTBLEND_BITS) {\n\t\t\tcase GLS_DSTBLEND_ZERO:\n\t\t\t\tattachment_blend_state.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO;\n\t\t\t\tbreak;\n\t\t\tcase GLS_DSTBLEND_ONE:\n\t\t\t\tattachment_blend_state.dstColorBlendFactor = VK_BLEND_FACTOR_ONE;\n\t\t\t\tbreak;\n\t\t\tcase GLS_DSTBLEND_SRC_COLOR:\n\t\t\t\tattachment_blend_state.dstColorBlendFactor = VK_BLEND_FACTOR_SRC_COLOR;\n\t\t\t\tbreak;\n\t\t\tcase GLS_DSTBLEND_ONE_MINUS_SRC_COLOR:\n\t\t\t\tattachment_blend_state.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR;\n\t\t\t\tbreak;\n\t\t\tcase GLS_DSTBLEND_SRC_ALPHA:\n\t\t\t\tattachment_blend_state.dstColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;\n\t\t\t\tbreak;\n\t\t\tcase GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA:\n\t\t\t\tattachment_blend_state.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;\n\t\t\t\tbreak;\n\t\t\tcase GLS_DSTBLEND_DST_ALPHA:\n\t\t\t\tattachment_blend_state.dstColorBlendFactor = VK_BLEND_FACTOR_DST_ALPHA;\n\t\t\t\tbreak;\n\t\t\tcase GLS_DSTBLEND_ONE_MINUS_DST_ALPHA:\n\t\t\t\tattachment_blend_state.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tri.Error( ERR_DROP, \"create_pipeline: invalid dst blend state bits\\n\" );\n\t\t\t\tbreak;\n\t\t}\n\n\t\tattachment_blend_state.srcAlphaBlendFactor = attachment_blend_state.srcColorBlendFactor;\n\t\tattachment_blend_state.dstAlphaBlendFactor = attachment_blend_state.dstColorBlendFactor;\n\t\tattachment_blend_state.colorBlendOp = VK_BLEND_OP_ADD;\n\t\tattachment_blend_state.alphaBlendOp = VK_BLEND_OP_ADD;\n\t}\n\n\tVkPipelineColorBlendStateCreateInfo blend_state{ VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO };\n\tblend_state.logicOpEnable = VK_FALSE;\n\tblend_state.logicOp = VK_LOGIC_OP_COPY;\n\tblend_state.attachmentCount = 1;\n\tblend_state.pAttachments = &attachment_blend_state;\n\tblend_state.blendConstants[0] = 0.0f;\n\tblend_state.blendConstants[1] = 0.0f;\n\tblend_state.blendConstants[2] = 0.0f;\n\tblend_state.blendConstants[3] = 0.0f;\n\n\tVkPipelineDynamicStateCreateInfo dynamic_state{ VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO };\n\tdynamic_state.dynamicStateCount = 3;\n\tVkDynamicState dynamic_state_array[3] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR, VK_DYNAMIC_STATE_DEPTH_BIAS };\n\tdynamic_state.pDynamicStates = dynamic_state_array;\n\n\tVkGraphicsPipelineCreateInfo create_info{ VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO };\n\tcreate_info.stageCount = static_cast<uint32_t>(shader_stages_state.size());\n\tcreate_info.pStages = shader_stages_state.data();\n\tcreate_info.pVertexInputState = &vertex_input_state;\n\tcreate_info.pInputAssemblyState = &input_assembly_state;\n\tcreate_info.pViewportState = &viewport_state;\n\tcreate_info.pRasterizationState = &rasterization_state;\n\tcreate_info.pMultisampleState = &multisample_state;\n\tcreate_info.pDepthStencilState = &depth_stencil_state;\n\tcreate_info.pColorBlendState = &blend_state;\n\tcreate_info.pDynamicState = &dynamic_state;\n\tcreate_info.layout = vk.pipeline_layout;\n\tcreate_info.renderPass = vk.render_pass;\n\tcreate_info.subpass = 0;\n\tcreate_info.basePipelineHandle = VK_NULL_HANDLE;\n\tcreate_info.basePipelineIndex = -1;\n\n\tVkPipeline pipeline;\n\tVK_CHECK(vkCreateGraphicsPipelines(vk.device, VK_NULL_HANDLE, 1, &create_info, nullptr, &pipeline));\n\treturn pipeline;\n}\n\nVkSampler vk_find_sampler(const Vk_Sampler_Def& def) {\n\t// Look for sampler among existing samplers.\n\tfor (int i = 0; i < vk_world.num_samplers; i++) {\n\t\tconst auto& cur_def = vk_world.sampler_defs[i];\n\n\t\tif (cur_def.repeat_texture == def.repeat_texture &&\n\t\t\tcur_def.gl_mag_filter == def.gl_mag_filter && \n\t\t\tcur_def.gl_min_filter == def.gl_min_filter)\n\t\t{\n\t\t\treturn vk_world.samplers[i];\n\t\t}\n\t}\n\n\t// Create new sampler.\n\tif (vk_world.num_samplers >= MAX_VK_SAMPLERS) {\n\t\tri.Error(ERR_DROP, \"vk_find_sampler: MAX_VK_SAMPLERS hit\\n\");\n\t}\n\n\tVkSamplerAddressMode address_mode = def.repeat_texture ? VK_SAMPLER_ADDRESS_MODE_REPEAT : VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;\n\n\tVkFilter mag_filter;\n\tif (def.gl_mag_filter == GL_NEAREST) {\n\t\tmag_filter = VK_FILTER_NEAREST;\n\t} else if (def.gl_mag_filter == GL_LINEAR) {\n\t\tmag_filter = VK_FILTER_LINEAR;\n\t} else {\n\t\tri.Error(ERR_FATAL, \"vk_find_sampler: invalid gl_mag_filter\");\n\t}\n\n\tVkFilter min_filter;\n\tVkSamplerMipmapMode mipmap_mode;\n\tbool max_lod_0_25 = false; // used to emulate OpenGL's GL_LINEAR/GL_NEAREST minification filter\n\tif (def.gl_min_filter == GL_NEAREST) {\n\t\tmin_filter = VK_FILTER_NEAREST;\n\t\tmipmap_mode = VK_SAMPLER_MIPMAP_MODE_NEAREST;\n\t\tmax_lod_0_25 = true;\n\t} else if (def.gl_min_filter == GL_LINEAR) {\n\t\tmin_filter = VK_FILTER_LINEAR;\n\t\tmipmap_mode = VK_SAMPLER_MIPMAP_MODE_NEAREST;\n\t\tmax_lod_0_25 = true;\n\t} else if (def.gl_min_filter == GL_NEAREST_MIPMAP_NEAREST) {\n\t\tmin_filter = VK_FILTER_NEAREST;\n\t\tmipmap_mode = VK_SAMPLER_MIPMAP_MODE_NEAREST;\n\t} else if (def.gl_min_filter == GL_LINEAR_MIPMAP_NEAREST) {\n\t\tmin_filter = VK_FILTER_LINEAR;\n\t\tmipmap_mode = VK_SAMPLER_MIPMAP_MODE_NEAREST;\n\t} else if (def.gl_min_filter == GL_NEAREST_MIPMAP_LINEAR) {\n\t\tmin_filter = VK_FILTER_NEAREST;\n\t\tmipmap_mode = VK_SAMPLER_MIPMAP_MODE_LINEAR;\n\t} else if (def.gl_min_filter == GL_LINEAR_MIPMAP_LINEAR) {\n\t\tmin_filter = VK_FILTER_LINEAR;\n\t\tmipmap_mode = VK_SAMPLER_MIPMAP_MODE_LINEAR;\n\t} else {\n\t\tri.Error(ERR_FATAL, \"vk_find_sampler: invalid gl_min_filter\");\n\t}\n\n\tVkSamplerCreateInfo desc{ VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };\n\tdesc.magFilter = mag_filter;\n\tdesc.minFilter = min_filter;\n\tdesc.mipmapMode = mipmap_mode;\n\tdesc.addressModeU = address_mode;\n\tdesc.addressModeV = address_mode;\n\tdesc.addressModeW = address_mode;\n\tdesc.mipLodBias = 0.0f;\n\tdesc.anisotropyEnable = VK_FALSE;\n\tdesc.maxAnisotropy = 1;\n\tdesc.compareEnable = VK_FALSE;\n\tdesc.compareOp = VK_COMPARE_OP_ALWAYS;\n\tdesc.minLod = 0.0f;\n\tdesc.maxLod = max_lod_0_25 ? 0.25f : 12.0f;\n\tdesc.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;\n\tdesc.unnormalizedCoordinates = VK_FALSE;\n\n\tVkSampler sampler;\n\tVK_CHECK(vkCreateSampler(vk.device, &desc, nullptr, &sampler));\n\n\tvk_world.sampler_defs[vk_world.num_samplers] = def;\n\tvk_world.samplers[vk_world.num_samplers] = sampler;\n\tvk_world.num_samplers++;\n\treturn sampler;\n}\n\nstruct Timer {\n\tusing Clock = std::chrono::high_resolution_clock;\n\tusing Second = std::chrono::duration<double, std::ratio<1>>;\n\n\tClock::time_point start = Clock::now();\n\tdouble elapsed_seconds() const {\n\t\tconst auto duration = Clock::now() - start;\n\t\tdouble seconds = std::chrono::duration_cast<Second>(duration).count();\n\t\treturn seconds;\n\t}\n};\n\nVkPipeline vk_find_pipeline(const Vk_Pipeline_Def& def) {\n\tfor (int i = 0; i < vk_world.num_pipelines; i++) {\n\t\tconst auto& cur_def = vk_world.pipeline_defs[i];\n\n\t\tif (cur_def.shader_type == def.shader_type &&\n\t\t\tcur_def.state_bits == def.state_bits &&\n\t\t\tcur_def.face_culling == def.face_culling &&\n\t\t\tcur_def.polygon_offset == def.polygon_offset &&\n\t\t\tcur_def.clipping_plane == def.clipping_plane &&\n\t\t\tcur_def.mirror == def.mirror &&\n\t\t\tcur_def.line_primitives == def.line_primitives &&\n\t\t\tcur_def.shadow_phase == def.shadow_phase)\n\t\t{\n\t\t\treturn vk_world.pipelines[i];\n\t\t}\n\t}\n\n\tif (vk_world.num_pipelines >= MAX_VK_PIPELINES) {\n\t\tri.Error(ERR_DROP, \"vk_find_pipeline: MAX_VK_PIPELINES hit\\n\");\n\t}\n\n\tTimer t;\n\tVkPipeline pipeline = create_pipeline(def);\n\tvk_world.pipeline_create_time += t.elapsed_seconds();\n\n\tvk_world.pipeline_defs[vk_world.num_pipelines] = def;\n\tvk_world.pipelines[vk_world.num_pipelines] = pipeline;\n\tvk_world.num_pipelines++;\n\treturn pipeline;\n}\n\nstatic VkRect2D get_viewport_rect() {\n\tVkRect2D r;\n\tif (backEnd.projection2D) {\n\t\tr.offset.x = 0.0f;\n\t\tr.offset.y = 0.0f;\n\t\tr.extent.width = glConfig.vidWidth;\n\t\tr.extent.height = glConfig.vidHeight;\n\t} else {\n\t\tr.offset.x = backEnd.viewParms.viewportX;\n\t\tr.offset.y = glConfig.vidHeight - (backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight);\n\t\tr.extent.width = backEnd.viewParms.viewportWidth;\n\t\tr.extent.height = backEnd.viewParms.viewportHeight;\n\t}\n\treturn r;\n}\n\nstatic VkViewport get_viewport(Vk_Depth_Range depth_range) {\n\tVkRect2D r = get_viewport_rect();\n\n\tVkViewport viewport;\n\tviewport.x = (float)r.offset.x;\n\tviewport.y = (float)r.offset.y;\n\tviewport.width = (float)r.extent.width;\n\tviewport.height = (float)r.extent.height;\n\n\tif (depth_range == Vk_Depth_Range::force_zero) {\n\t\tviewport.minDepth = 0.0f;\n\t\tviewport.maxDepth = 0.0f;\n\t} else if (depth_range == Vk_Depth_Range::force_one) {\n\t\tviewport.minDepth = 1.0f;\n\t\tviewport.maxDepth = 1.0f;\n\t} else if (depth_range == Vk_Depth_Range::weapon) {\n\t\tviewport.minDepth = 0.0f;\n\t\tviewport.maxDepth = 0.3f;\n\t} else {\n\t\tviewport.minDepth = 0.0f;\n\t\tviewport.maxDepth = 1.0f;\n\t}\n\treturn viewport;\n}\n\nstatic VkRect2D get_scissor_rect() {\n\tVkRect2D r = get_viewport_rect();\n\n\tif (r.offset.x < 0)\n\t\tr.offset.x = 0;\n\tif (r.offset.y < 0)\n\t\tr.offset.y = 0;\n\n\tif (r.offset.x + r.extent.width > glConfig.vidWidth)\n\t\tr.extent.width = glConfig.vidWidth - r.offset.x;\n\tif (r.offset.y + r.extent.height > glConfig.vidHeight)\n\t\tr.extent.height = glConfig.vidHeight - r.offset.y;\n\n\treturn r;\n}\n\nstatic void get_mvp_transform(float* mvp) {\n\tif (backEnd.projection2D) {\n\t\tfloat mvp0 = 2.0f / glConfig.vidWidth;\n\t\tfloat mvp5 = 2.0f / glConfig.vidHeight;\n\n\t\tmvp[0]  =  mvp0; mvp[1]  =  0.0f; mvp[2]  = 0.0f; mvp[3]  = 0.0f;\n\t\tmvp[4]  =  0.0f; mvp[5]  =  mvp5; mvp[6]  = 0.0f; mvp[7]  = 0.0f;\n\t\tmvp[8]  =  0.0f; mvp[9]  =  0.0f; mvp[10] = 1.0f; mvp[11] = 0.0f;\n\t\tmvp[12] = -1.0f; mvp[13] = -1.0f; mvp[14] = 0.0f; mvp[15] = 1.0f;\n\n\t} else {\n\t\tconst float* p = backEnd.viewParms.projectionMatrix;\n\n\t\t// update q3's proj matrix (opengl) to vulkan conventions: z - [0, 1] instead of [-1, 1] and invert y direction\n\t\tfloat zNear\t= r_znear->value;\n\t\tfloat zFar = backEnd.viewParms.zFar;\n\t\tfloat P10 = -zFar / (zFar - zNear);\n\t\tfloat P14 = -zFar*zNear / (zFar - zNear);\n\t\tfloat P5 = -p[5];\n\n\t\tfloat proj[16] = {\n\t\t\tp[0],  p[1],  p[2], p[3],\n\t\t\tp[4],  P5,    p[6], p[7],\n\t\t\tp[8],  p[9],  P10,  p[11],\n\t\t\tp[12], p[13], P14,  p[15]\n\t\t};\n\n\t\tmyGlMultMatrix(vk_world.modelview_transform, proj, mvp);\n\t}\n}\n\nvoid vk_clear_attachments(bool clear_depth_stencil, bool clear_color, vec4_t color) {\n\tif (!vk.active)\n\t\treturn;\n\n\tif (!clear_depth_stencil && !clear_color)\n\t\treturn;\n\n\tVkClearAttachment attachments[2];\n\tuint32_t attachment_count = 0;\n\n\tif (clear_depth_stencil) {\n\t\tattachments[0].aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;\n\t\tattachments[0].clearValue.depthStencil.depth = 1.0f;\n\n\t\tif (r_shadows->integer == 2) {\n\t\t\tattachments[0].aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;\n\t\t\tattachments[0].clearValue.depthStencil.stencil = 0;\n\t\t}\n\t\tattachment_count = 1;\n\t}\n\n\tif (clear_color) {\n\t\tattachments[attachment_count].aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;\n\t\tattachments[attachment_count].colorAttachment = 0;\n\t\tattachments[attachment_count].clearValue.color = { color[0], color[1], color[2], color[3] };\n\t\tattachment_count++;\n\t}\n\n\tVkClearRect clear_rect{};\n\tclear_rect.rect = get_scissor_rect();\n\tclear_rect.baseArrayLayer = 0;\n\tclear_rect.layerCount = 1;\n\tvkCmdClearAttachments(vk.command_buffer, attachment_count, attachments, 1, &clear_rect);\n}\n\nvoid vk_bind_geometry() {\n\t// xyz stream\n\t{\n\t\tif ((vk.xyz_elements + tess.numVertexes) * sizeof(vec4_t) > XYZ_SIZE)\n\t\t\tri.Error(ERR_DROP, \"vk_bind_geometry: vertex buffer overflow (xyz)\\n\");\n\n\t\tbyte* dst = vk.vertex_buffer_ptr + XYZ_OFFSET + vk.xyz_elements * sizeof(vec4_t);\n\t\tCom_Memcpy(dst, tess.xyz, tess.numVertexes * sizeof(vec4_t));\n\n\t\tVkDeviceSize xyz_offset = XYZ_OFFSET + vk.xyz_elements * sizeof(vec4_t);\n\t\tvkCmdBindVertexBuffers(vk.command_buffer, 0, 1, &vk.vertex_buffer, &xyz_offset);\n\t\tvk.xyz_elements += tess.numVertexes;\n\t}\n\n\t// indexes stream\n\t{\n\t\tstd::size_t indexes_size = tess.numIndexes * sizeof(uint32_t);        \n\n\t\tif (vk.index_buffer_offset + indexes_size > INDEX_BUFFER_SIZE)\n\t\t\tri.Error(ERR_DROP, \"vk_bind_geometry: index buffer overflow\\n\");\n\n\t\tbyte* dst = vk.index_buffer_ptr + vk.index_buffer_offset;\n\t\tCom_Memcpy(dst, tess.indexes, indexes_size);\n\n\t\tvkCmdBindIndexBuffer(vk.command_buffer, vk.index_buffer, vk.index_buffer_offset, VK_INDEX_TYPE_UINT32);\n\t\tvk.index_buffer_offset += indexes_size;\n\t}\n\n\t//\n\t// Specify push constants.\n\t//\n\tfloat push_constants[16 + 12 + 4]; // mvp transform + eye transform + clipping plane in eye space\n\n\tget_mvp_transform(push_constants);\n\tint push_constants_size = 64;\n\n\tif (backEnd.viewParms.isPortal) {\n\t\t// Eye space transform.\n\t\t// NOTE: backEnd.or.modelMatrix incorporates s_flipMatrix, so it should be taken into account \n\t\t// when computing clipping plane too.\n\t\tfloat* eye_xform = push_constants + 16;\n\t\tfor (int i = 0; i < 12; i++) {\n\t\t\teye_xform[i] = backEnd.or.modelMatrix[(i%4)*4 + i/4 ];\n\t\t}\n\n\t\t// Clipping plane in eye coordinates.\n\t\tfloat world_plane[4];\n\t\tworld_plane[0] = backEnd.viewParms.portalPlane.normal[0];\n\t\tworld_plane[1] = backEnd.viewParms.portalPlane.normal[1];\n\t\tworld_plane[2] = backEnd.viewParms.portalPlane.normal[2];\n\t\tworld_plane[3] = backEnd.viewParms.portalPlane.dist;\n\n\t\tfloat eye_plane[4];\n\t\teye_plane[0] = DotProduct (backEnd.viewParms.or.axis[0], world_plane);\n\t\teye_plane[1] = DotProduct (backEnd.viewParms.or.axis[1], world_plane);\n\t\teye_plane[2] = DotProduct (backEnd.viewParms.or.axis[2], world_plane);\n\t\teye_plane[3] = DotProduct (world_plane, backEnd.viewParms.or.origin) - world_plane[3];\n\n\t\t// Apply s_flipMatrix to be in the same coordinate system as eye_xfrom.\n\t\tpush_constants[28] = -eye_plane[1];\n\t\tpush_constants[29] =  eye_plane[2];\n\t\tpush_constants[30] = -eye_plane[0];\n\t\tpush_constants[31] =  eye_plane[3];\n\n\t\tpush_constants_size += 64;\n\t}\n\tvkCmdPushConstants(vk.command_buffer, vk.pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT, 0, push_constants_size, push_constants);\n}\n\nvoid vk_shade_geometry(VkPipeline pipeline, bool multitexture, Vk_Depth_Range depth_range, bool indexed) {\n\t// color\n\t{\n\t\tif ((vk.color_st_elements + tess.numVertexes) * sizeof(color4ub_t) > COLOR_SIZE)\n\t\t\tri.Error(ERR_DROP, \"vulkan: vertex buffer overflow (color)\\n\");\n\n\t\tbyte* dst = vk.vertex_buffer_ptr + COLOR_OFFSET + vk.color_st_elements * sizeof(color4ub_t);\n\t\tCom_Memcpy(dst, tess.svars.colors, tess.numVertexes * sizeof(color4ub_t));\n\t}\n\t// st0\n\t{\n\t\tif ((vk.color_st_elements + tess.numVertexes) * sizeof(vec2_t) > ST0_SIZE)\n\t\t\tri.Error(ERR_DROP, \"vulkan: vertex buffer overflow (st0)\\n\");\n\n\t\tbyte* dst = vk.vertex_buffer_ptr + ST0_OFFSET + vk.color_st_elements * sizeof(vec2_t);\n\t\tCom_Memcpy(dst, tess.svars.texcoords[0], tess.numVertexes * sizeof(vec2_t));\n\t}\n\t// st1\n\tif (multitexture) {\n\t\tif ((vk.color_st_elements + tess.numVertexes) * sizeof(vec2_t) > ST1_SIZE)\n\t\t\tri.Error(ERR_DROP, \"vulkan: vertex buffer overflow (st1)\\n\");\n\n\t\tbyte* dst = vk.vertex_buffer_ptr + ST1_OFFSET + vk.color_st_elements * sizeof(vec2_t);\n\t\tCom_Memcpy(dst, tess.svars.texcoords[1], tess.numVertexes * sizeof(vec2_t));\n\t}\n\n\t// configure vertex data stream\n\tVkBuffer bufs[3] = { vk.vertex_buffer, vk.vertex_buffer, vk.vertex_buffer };\n\tVkDeviceSize offs[3] = {\n\t\tCOLOR_OFFSET + vk.color_st_elements * sizeof(color4ub_t),\n\t\tST0_OFFSET   + vk.color_st_elements * sizeof(vec2_t),\n\t\tST1_OFFSET   + vk.color_st_elements * sizeof(vec2_t)\n\t};\n\tvkCmdBindVertexBuffers(vk.command_buffer, 1, multitexture ? 3 : 2, bufs, offs);\n\tvk.color_st_elements += tess.numVertexes;\n\n\t// bind descriptor sets\n\tuint32_t set_count = multitexture ? 2 : 1;\n\tvkCmdBindDescriptorSets(vk.command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, vk.pipeline_layout, 0, set_count, vk_world.current_descriptor_sets, 0, nullptr);\n\n\t// bind pipeline\n\tvkCmdBindPipeline(vk.command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);\n\n\t// configure pipeline's dynamic state\n\tVkRect2D scissor_rect = get_scissor_rect();\n\tvkCmdSetScissor(vk.command_buffer, 0, 1, &scissor_rect);\n\n\tVkViewport viewport = get_viewport(depth_range);\n\tvkCmdSetViewport(vk.command_buffer, 0, 1, &viewport);\n\n\tif (tess.shader->polygonOffset) {\n\t\tvkCmdSetDepthBias(vk.command_buffer, r_offsetUnits->value, 0.0f, r_offsetFactor->value);\n\t}\n\n\t// issue draw call\n\tif (indexed)\n\t\tvkCmdDrawIndexed(vk.command_buffer, tess.numIndexes, 1, 0, 0, 0);\n\telse\n\t\tvkCmdDraw(vk.command_buffer, tess.numVertexes, 1, 0, 0);\n\n\tvk_world.dirty_depth_attachment = true;\n}\n\nvoid vk_begin_frame() {\n\tif (!vk.active)\n\t\treturn;\n\n\tVK_CHECK(vkWaitForFences(vk.device, 1, &vk.rendering_finished_fence, VK_FALSE, 1e9));\n\tVK_CHECK(vkResetFences(vk.device, 1, &vk.rendering_finished_fence));\n\tVK_CHECK(vkAcquireNextImageKHR(vk.device, vk.swapchain, UINT64_MAX, vk.image_acquired, VK_NULL_HANDLE, &vk.swapchain_image_index));\n\n\t// Write swapchain image descriptor for gamma shader\n\tVkDescriptorImageInfo image_info{};\n\timage_info.imageView = vk.swapchain_image_views[vk.swapchain_image_index];\n\timage_info.imageLayout = VK_IMAGE_LAYOUT_GENERAL;\n\tVkWriteDescriptorSet descriptor_write{ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };\n\tdescriptor_write.dstSet = vk.gamma_descriptor_set;\n\tdescriptor_write.dstBinding = 1;\n\tdescriptor_write.dstArrayElement = 0;\n\tdescriptor_write.descriptorCount = 1;\n\tdescriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;\n\tdescriptor_write.pImageInfo = &image_info;\n\tvkUpdateDescriptorSets(vk.device, 1, &descriptor_write, 0, nullptr);\n\n\tVkCommandBufferBeginInfo begin_info{ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };\n\tbegin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;\n\tVK_CHECK(vkBeginCommandBuffer(vk.command_buffer, &begin_info));\n\n\t// Begin render pass.\n\tVkClearValue clear_values[2];\n\t/// ignore clear_values[0] which corresponds to color attachment\n\tclear_values[1].depthStencil.depth = 1.0;\n\tclear_values[1].depthStencil.stencil = 0;\n\n\tVkRenderPassBeginInfo render_pass_begin_info{ VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO };\n\trender_pass_begin_info.renderPass = vk.render_pass;\n\trender_pass_begin_info.framebuffer = vk.framebuffer;\n\trender_pass_begin_info.renderArea.offset = { 0, 0 };\n\trender_pass_begin_info.renderArea.extent = { (uint32_t)glConfig.vidWidth, (uint32_t)glConfig.vidHeight };\n\trender_pass_begin_info.clearValueCount = 2;\n\trender_pass_begin_info.pClearValues = clear_values;\n\n\tvkCmdBeginRenderPass(vk.command_buffer, &render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE);\n\n\tvk_world.dirty_depth_attachment = false;\n\tvk.xyz_elements = 0;\n\tvk.color_st_elements = 0;\n\tvk.index_buffer_offset = 0;\n}\n\nvoid vk_end_frame() {\n\tif (!vk.active)\n\t\treturn;\n\n\tvkCmdEndRenderPass(vk.command_buffer);\n\n\trecord_image_layout_transition(vk.command_buffer, vk.swapchain_images[vk.swapchain_image_index], VK_IMAGE_ASPECT_COLOR_BIT,\n\t\t0, VK_IMAGE_LAYOUT_UNDEFINED,\n\t\tVK_ACCESS_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL);\n\n\tconst uint32_t group_size_x = 8; // according to shader\n\tconst uint32_t group_size_y = 8;\n\tuint32_t group_count_x = ((uint32_t)glConfig.vidWidth + group_size_x - 1) / group_size_x;\n\tuint32_t group_count_y = ((uint32_t)glConfig.vidHeight + group_size_y - 1) / group_size_y;\n\tconst uint32_t push_constants[3] = {\n\t\t(uint32_t)glConfig.vidWidth,\n\t\t(uint32_t)glConfig.vidHeight,\n\t\tr_shaderGamma->integer && !r_ignorehwgamma->integer ? 0u : 1u // identity_gamma\n\t};\n\n    vkCmdBindDescriptorSets(vk.command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, vk.gamma_pipeline_layout, 0, 1, &vk.gamma_descriptor_set, 0, nullptr);\n    vkCmdPushConstants(vk.command_buffer, vk.gamma_pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, 12, push_constants);\n\tvkCmdBindPipeline(vk.command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, vk.gamma_pipeline);\n\tvkCmdDispatch(vk.command_buffer, group_count_x, group_count_y, 1);\n\n    record_image_layout_transition(vk.command_buffer, vk.swapchain_images[vk.swapchain_image_index], VK_IMAGE_ASPECT_COLOR_BIT,\n        VK_ACCESS_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL,\n        0, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);\n\n\tVK_CHECK(vkEndCommandBuffer(vk.command_buffer));\n\n\t// Compute shader generates final swapchain image by applying gamma shader to the output image.\n\t// Ensure that compute stage waits for image acquire semaphore.\n\tconst VkPipelineStageFlags wait_dst_stage_mask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;\n\n\tVkSubmitInfo submit_info{ VK_STRUCTURE_TYPE_SUBMIT_INFO };\n\tsubmit_info.waitSemaphoreCount = 1;\n\tsubmit_info.pWaitSemaphores = &vk.image_acquired;\n\tsubmit_info.pWaitDstStageMask = &wait_dst_stage_mask;\n\tsubmit_info.commandBufferCount = 1;\n\tsubmit_info.pCommandBuffers = &vk.command_buffer;\n\tsubmit_info.signalSemaphoreCount = 1;\n\tsubmit_info.pSignalSemaphores = &vk.rendering_finished[vk.swapchain_image_index];\n\tVK_CHECK(vkQueueSubmit(vk.queue, 1, &submit_info, vk.rendering_finished_fence));\n\n    VkPresentInfoKHR present_info{ VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };\n    present_info.waitSemaphoreCount = 1;\n    present_info.pWaitSemaphores = &vk.rendering_finished[vk.swapchain_image_index];\n    present_info.swapchainCount = 1;\n    present_info.pSwapchains = &vk.swapchain;\n    present_info.pImageIndices = &vk.swapchain_image_index;\n    VK_CHECK(vkQueuePresentKHR(vk.queue, &present_info));\n}\n\nvoid vk_read_pixels(byte* buffer) {\n\tvkDeviceWaitIdle(vk.device);\n\n\t// Create image in host visible memory to serve as a destination for framebuffer pixels.\n\tVkImageCreateInfo desc{ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };\n\tdesc.imageType = VK_IMAGE_TYPE_2D;\n\tdesc.format = VK_FORMAT_R8G8B8A8_UNORM;\n\tdesc.extent.width = glConfig.vidWidth;\n\tdesc.extent.height = glConfig.vidHeight;\n\tdesc.extent.depth = 1;\n\tdesc.mipLevels = 1;\n\tdesc.arrayLayers = 1;\n\tdesc.samples = VK_SAMPLE_COUNT_1_BIT;\n\tdesc.tiling = VK_IMAGE_TILING_LINEAR;\n\tdesc.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT;\n\tdesc.sharingMode = VK_SHARING_MODE_EXCLUSIVE;\n\tdesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;\n\tVkImage image;\n\tVK_CHECK(vkCreateImage(vk.device, &desc, nullptr, &image));\n\n\tVkMemoryRequirements memory_requirements;\n\tvkGetImageMemoryRequirements(vk.device, image, &memory_requirements);\n\tVkMemoryAllocateInfo alloc_info{ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };\n\talloc_info.allocationSize = memory_requirements.size;\n\talloc_info.memoryTypeIndex = find_memory_type(vk.physical_device, memory_requirements.memoryTypeBits,\n\t\tVK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);\n\tVkDeviceMemory memory;\n\tVK_CHECK(vkAllocateMemory(vk.device, &alloc_info, nullptr, &memory));\n\tVK_CHECK(vkBindImageMemory(vk.device, image, memory, 0));\n\n\trecord_and_run_commands(vk.command_pool, vk.queue, [&image](VkCommandBuffer command_buffer) {\n\t\trecord_image_layout_transition(command_buffer, vk.swapchain_images[vk.swapchain_image_index], VK_IMAGE_ASPECT_COLOR_BIT,\n\t\t\tVK_ACCESS_MEMORY_READ_BIT, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, \n\t\t\tVK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);\n\n\t\trecord_image_layout_transition(command_buffer, image, VK_IMAGE_ASPECT_COLOR_BIT,\n\t\t\t0, VK_IMAGE_LAYOUT_UNDEFINED,\n\t\t\tVK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL);\n\t});\n\n\t// Check if we can use vkCmdBlitImage for the given source and destination image formats.\n\tbool blit_enabled = true;\n\t{\n\t\tVkFormatProperties formatProps;\n\t\tvkGetPhysicalDeviceFormatProperties(vk.physical_device, vk.surface_format.format, &formatProps);\n\t\tif ((formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT) == 0)\n\t\t\tblit_enabled = false;\n\n\t\tvkGetPhysicalDeviceFormatProperties(vk.physical_device, VK_FORMAT_R8G8B8A8_UNORM, &formatProps);\n\t\tif ((formatProps.linearTilingFeatures & VK_FORMAT_FEATURE_BLIT_DST_BIT) == 0)\n\t\t\tblit_enabled = false;\n\t}\n\n\tif (blit_enabled) {\n\t\trecord_and_run_commands(vk.command_pool, vk.queue, [&image](VkCommandBuffer command_buffer) {\n\t\t\tVkImageBlit region;\n\t\t\tregion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;\n\t\t\tregion.srcSubresource.mipLevel = 0;\n\t\t\tregion.srcSubresource.baseArrayLayer = 0;\n\t\t\tregion.srcSubresource.layerCount = 1;\n\t\t\tregion.srcOffsets[0] = {0, 0, 0};\n\t\t\tregion.srcOffsets[1] = {glConfig.vidWidth, glConfig.vidHeight, 1};\n\t\t\tregion.dstSubresource = region.srcSubresource;\n\t\t\tregion.dstOffsets[0] = region.srcOffsets[0];\n\t\t\tregion.dstOffsets[1] = region.srcOffsets[1];\n\n\t\t\tvkCmdBlitImage(command_buffer, vk.swapchain_images[vk.swapchain_image_index], VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,\n\t\t\t\timage, VK_IMAGE_LAYOUT_GENERAL, 1, &region, VK_FILTER_NEAREST);\n\t\t});\n\t} else {\n\t\trecord_and_run_commands(vk.command_pool, vk.queue, [&image](VkCommandBuffer command_buffer) {\n\t\t\tVkImageCopy region;\n\t\t\tregion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;\n\t\t\tregion.srcSubresource.mipLevel = 0;\n\t\t\tregion.srcSubresource.baseArrayLayer = 0;\n\t\t\tregion.srcSubresource.layerCount = 1;\n\t\t\tregion.srcOffset = {0, 0, 0};\n\t\t\tregion.dstSubresource = region.srcSubresource;\n\t\t\tregion.dstOffset = region.srcOffset;\n\t\t\tregion.extent = {(uint32_t)glConfig.vidWidth, (uint32_t)glConfig.vidHeight, 1};\n\n\t\t\tvkCmdCopyImage(command_buffer, vk.swapchain_images[vk.swapchain_image_index], VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,\n\t\t\t\timage, VK_IMAGE_LAYOUT_GENERAL, 1, &region);\n\t\t});\n\t}\n\n\t// Copy data from destination image to memory buffer.\n\tVkImageSubresource subresource;\n\tsubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;\n\tsubresource.mipLevel = 0;\n\tsubresource.arrayLayer = 0;\n\tVkSubresourceLayout layout;\n\tvkGetImageSubresourceLayout(vk.device, image, &subresource, &layout);\n\n\tbyte* data;\n\tVK_CHECK(vkMapMemory(vk.device, memory, 0, VK_WHOLE_SIZE, 0, (void**)&data));\n\tdata += layout.offset;\n\n\tbyte* buffer_ptr = buffer + glConfig.vidWidth * (glConfig.vidHeight - 1) * 4;\n\tfor (int i = 0; i < glConfig.vidHeight; i++) {\n\t\tCom_Memcpy(buffer_ptr, data, glConfig.vidWidth * 4);\n\t\tbuffer_ptr -= glConfig.vidWidth * 4;\n\t\tdata += layout.rowPitch;\n\t}\n\n\tif (!blit_enabled) {\n\t\tauto fmt = vk.surface_format.format;\n\t\tbool swizzle_components = (fmt == VK_FORMAT_B8G8R8A8_SRGB || fmt == VK_FORMAT_B8G8R8A8_UNORM || fmt == VK_FORMAT_B8G8R8A8_SNORM);\n\t\tif (swizzle_components) {\n\t\t\tbuffer_ptr = buffer;\n\t\t\tfor (int i = 0; i < glConfig.vidWidth * glConfig.vidHeight; i++) {\n\t\t\t\tbyte tmp = buffer_ptr[0];\n\t\t\t\tbuffer_ptr[0] = buffer_ptr[2];\n\t\t\t\tbuffer_ptr[2] = tmp;\n\t\t\t\tbuffer_ptr += 4;\n\t\t\t}\n\t\t}\n\t}\n\n\tvkDestroyImage(vk.device, image, nullptr);\n\tvkFreeMemory(vk.device, memory, nullptr);\n}\n\nvoid vk_update_gamma_buffer(float gamma_table[256]) {\n\tvkDeviceWaitIdle(vk.device);\n\tensure_staging_buffer_allocation(256 * sizeof(float));\n\tCom_Memcpy(vk_world.staging_buffer_ptr, gamma_table, 256 * sizeof(float));\n\trecord_and_run_commands(vk.command_pool, vk.queue, [](VkCommandBuffer command_buffer) {\n\t\tVkBufferCopy region{};\n\t\tregion.size = 256 * sizeof(float);\n\t\tvkCmdCopyBuffer(command_buffer, vk_world.staging_buffer, vk.gamma_buffer, 1, &region);\n\t});\n}\n"
  },
  {
    "path": "src/engine/renderer/vk.h",
    "content": "#pragma once\n\n#ifdef _WIN32\n#define VK_USE_PLATFORM_WIN32_KHR\n#define NOMINMAX\n#endif\n\n#define VK_NO_PROTOTYPES\n#include \"vulkan/vulkan.h\"\n\nconst int MAX_SWAPCHAIN_IMAGES = 8;\nconst int MAX_VK_SAMPLERS = 32;\nconst int MAX_VK_PIPELINES = 1024;\nconst int MAX_VK_IMAGES = 2048; // should be the same as MAX_DRAWIMAGES\n\nconst int IMAGE_CHUNK_SIZE = 32 * 1024 * 1024;\nconst int MAX_IMAGE_CHUNKS = 16;\n\n#define VK_CHECK(function_call) { \\\n\tVkResult result = function_call; \\\n\tif (result < 0) \\\n\t\tri.Error(ERR_FATAL, \"Vulkan: error code %d returned by %s\", result, #function_call); \\\n}\n\nenum class Vk_Shader_Type {\n\tsingle_texture,\n\tmulti_texture_mul,\n\tmulti_texture_add\n};\n\n// used with cg_shadows == 2\nenum class Vk_Shadow_Phase {\n\tdisabled,\n\tshadow_edges_rendering,\n\tfullscreen_quad_rendering\n};\n\nenum class Vk_Depth_Range {\n\tnormal, // [0..1]\n\tforce_zero, // [0..0]\n\tforce_one, // [1..1]\n\tweapon // [0..0.3]\n};\n\nstruct Vk_Sampler_Def {\n\tbool repeat_texture = false; // clamp/repeat texture addressing mode\n\tint gl_mag_filter = 0; // GL_XXX mag filter\n\tint gl_min_filter = 0; // GL_XXX min filter\n};\n\nstruct Vk_Pipeline_Def {\n\tVk_Shader_Type shader_type = Vk_Shader_Type::single_texture;\n\tunsigned int state_bits = 0; // GLS_XXX flags\n\tint face_culling = 0;// cullType_t\n\tbool polygon_offset = false;\n\tbool clipping_plane = false;\n\tbool mirror = false;\n\tbool line_primitives = false;\n\tVk_Shadow_Phase shadow_phase = Vk_Shadow_Phase::disabled;\n};\n\nstruct Vk_Image {\n\tVkImage handle = VK_NULL_HANDLE;\n\tVkImageView view = VK_NULL_HANDLE;\n\n\t// Descriptor set that contains single descriptor used to access the given image.\n\t// It is updated only once during image initialization.\n\tVkDescriptorSet descriptor_set = VK_NULL_HANDLE;\n};\n\n//\n// Initialization.\n//\n\n// Initializes VK_Instance structure.\n// After calling this function we get fully functional vulkan subsystem.\nvoid vk_initialize();\n\n// Shutdown vulkan subsystem by releasing resources acquired by Vk_Instance.\nvoid vk_shutdown();\n\n// Releases vulkan resources allocated during program execution.\n// This effectively puts vulkan subsystem into initial state (the state we have after vk_initialize call).\nvoid vk_release_resources();\n\n//\n// Resources allocation.\n//\nVk_Image vk_create_image(int width, int height, VkFormat format, int mip_levels, bool repeat_texture);\nvoid vk_upload_image_data(VkImage image, int width, int height, bool mipmap, const uint8_t* pixels, int bytes_per_pixel);\nvoid vk_update_descriptor_set(VkDescriptorSet set, VkImageView image_view, bool mipmap, bool repeat_texture);\nVkSampler vk_find_sampler(const Vk_Sampler_Def& def);\nVkPipeline vk_find_pipeline(const Vk_Pipeline_Def& def);\n\n//\n// Rendering setup.\n//\nvoid vk_clear_attachments(bool clear_depth_stencil, bool clear_color, vec4_t color);\nvoid vk_bind_geometry();\nvoid vk_shade_geometry(VkPipeline pipeline, bool multitexture, Vk_Depth_Range depth_range, bool indexed = true);\nvoid vk_begin_frame();\nvoid vk_end_frame();\n\nvoid vk_read_pixels(byte* buffer); // screenshots\n\nvoid vk_update_gamma_buffer(float gamma_table[256]);\n\n// Vk_Instance contains engine-specific vulkan resources that persist entire renderer lifetime.\n// This structure is initialized/deinitialized by vk_initialize/vk_shutdown functions correspondingly.\nstruct Vk_Instance {\n\tbool active = false;\n\tVkInstance instance = VK_NULL_HANDLE;\n\tVkPhysicalDevice physical_device = VK_NULL_HANDLE;\n\tVkSurfaceKHR surface = VK_NULL_HANDLE;\n\tVkSurfaceFormatKHR surface_format = {};\n\n\tuint32_t queue_family_index = 0;\n\tVkDevice device = VK_NULL_HANDLE;\n\tVkQueue queue = VK_NULL_HANDLE;\n\n\tVkSwapchainKHR swapchain = VK_NULL_HANDLE;\n\tuint32_t swapchain_image_count = 0;\n\tVkImage swapchain_images[MAX_SWAPCHAIN_IMAGES];\n\tVkImageView swapchain_image_views[MAX_SWAPCHAIN_IMAGES];\n\tVkSemaphore rendering_finished[MAX_SWAPCHAIN_IMAGES];\n\tuint32_t swapchain_image_index = -1;\n\n\tVkSemaphore image_acquired = VK_NULL_HANDLE;\n\tVkFence rendering_finished_fence = VK_NULL_HANDLE;\n\n\tVkCommandPool command_pool = VK_NULL_HANDLE;\n\tVkCommandBuffer command_buffer = VK_NULL_HANDLE;\n\n\tVkImage output_image = VK_NULL_HANDLE;\n\tVkDeviceMemory output_image_memory = VK_NULL_HANDLE;\n\tVkImageView output_image_view = VK_NULL_HANDLE;\n\n\tVkImage depth_image = VK_NULL_HANDLE;\n\tVkDeviceMemory depth_image_memory = VK_NULL_HANDLE;\n\tVkImageView depth_image_view = VK_NULL_HANDLE;\n\n\tVkRenderPass render_pass = VK_NULL_HANDLE;\n\tVkFramebuffer framebuffer = VK_NULL_HANDLE;\n\n\tVkDescriptorPool descriptor_pool = VK_NULL_HANDLE;\n\tVkDescriptorSetLayout set_layout = VK_NULL_HANDLE;\n\tVkPipelineLayout pipeline_layout = VK_NULL_HANDLE;\n\n\tVkBuffer vertex_buffer = VK_NULL_HANDLE;\n\tbyte* vertex_buffer_ptr = nullptr; // pointer to mapped vertex buffer\n\tint xyz_elements = 0;\n\tint color_st_elements = 0;\n\n\tVkBuffer index_buffer = VK_NULL_HANDLE;\n\tbyte* index_buffer_ptr = nullptr; // pointer to mapped index buffer\n\tVkDeviceSize index_buffer_offset = 0;\n\n\t// host visible memory that holds both vertex and index data\n\tVkDeviceMemory geometry_buffer_memory = VK_NULL_HANDLE;\n\n\tVkDescriptorPool gamma_descriptor_pool = VK_NULL_HANDLE;\n\tVkDescriptorSetLayout gamma_set_layout = VK_NULL_HANDLE;\n\tVkPipelineLayout gamma_pipeline_layout = VK_NULL_HANDLE;\n\tVkDescriptorSet gamma_descriptor_set = VK_NULL_HANDLE;\n\tVkPipeline gamma_pipeline = VK_NULL_HANDLE;\n\tVkBuffer gamma_buffer = VK_NULL_HANDLE;\n\tVkDeviceMemory gamma_buffer_memory = VK_NULL_HANDLE;\n\n\t//\n\t// Shader modules.\n\t//\n\tVkShaderModule single_texture_vs = VK_NULL_HANDLE;\n\tVkShaderModule single_texture_clipping_plane_vs = VK_NULL_HANDLE;\n\tVkShaderModule single_texture_fs = VK_NULL_HANDLE;\n\tVkShaderModule multi_texture_vs = VK_NULL_HANDLE;\n\tVkShaderModule multi_texture_clipping_plane_vs = VK_NULL_HANDLE;\n\tVkShaderModule multi_texture_mul_fs = VK_NULL_HANDLE;\n\tVkShaderModule multi_texture_add_fs = VK_NULL_HANDLE;\n\n\t//\n\t// Standard pipelines.\n\t//\n\tVkPipeline skybox_pipeline = VK_NULL_HANDLE;\n\n\t// dim 0: 0 - front side, 1 - back size\n\t// dim 1: 0 - normal view, 1 - mirror view\n\tVkPipeline shadow_volume_pipelines[2][2];\n\tVkPipeline shadow_finish_pipeline;\n\n\t// dim 0 is based on fogPass_t: 0 - corresponds to FP_EQUAL, 1 - corresponds to FP_LE.\n\t// dim 1 is directly a cullType_t enum value.\n\t// dim 2 is a polygon offset value (0 - off, 1 - on).\n\tVkPipeline fog_pipelines[2][3][2];\n\n\t// dim 0 is based on dlight additive flag: 0 - not additive, 1 - additive\n\t// dim 1 is directly a cullType_t enum value.\n\t// dim 2 is a polygon offset value (0 - off, 1 - on).\n\tVkPipeline dlight_pipelines[2][3][2];\n\n\t// debug visualization pipelines\n\tVkPipeline tris_debug_pipeline;\n\tVkPipeline tris_mirror_debug_pipeline;\n\tVkPipeline normals_debug_pipeline;\n\tVkPipeline surface_debug_pipeline_solid;\n\tVkPipeline surface_debug_pipeline_outline;\n\tVkPipeline images_debug_pipeline;\n\n#ifndef NDEBUG\n\tVkDebugReportCallbackEXT debug_callback;\n#endif\n};\n\n// Vk_World contains vulkan resources/state requested by the game code.\n// It is reinitialized on a map change.\nstruct Vk_World {\n\t//\n\t// Resources.\n\t//\n\tint num_samplers = 0;\n\tVk_Sampler_Def sampler_defs[MAX_VK_SAMPLERS];\n\tVkSampler samplers[MAX_VK_SAMPLERS];\n\n\tint num_pipelines = 0;\n\tVk_Pipeline_Def pipeline_defs[MAX_VK_PIPELINES];\n\tVkPipeline pipelines[MAX_VK_PIPELINES];\n\tfloat pipeline_create_time;\n\n\tVk_Image images[MAX_VK_IMAGES];\n\n\t//\n\t// Memory allocations.\n\t//\n\tstruct Chunk {\n\t\tVkDeviceMemory memory = VK_NULL_HANDLE;\n\t\tVkDeviceSize used = 0;\n\t};\n\n\tint num_image_chunks = 0;\n\tChunk image_chunks[MAX_IMAGE_CHUNKS];\n\n\t// Host visible memory used to copy image data to device local memory.\n\tVkBuffer staging_buffer = VK_NULL_HANDLE;\n\tVkDeviceMemory staging_buffer_memory = VK_NULL_HANDLE;\n\tVkDeviceSize staging_buffer_size = 0;\n\tbyte* staging_buffer_ptr = nullptr; // pointer to mapped staging buffer\n\n\t//\n\t// State.\n\t//\n\n\t// Descriptor sets corresponding to bound texture images.\n\tVkDescriptorSet current_descriptor_sets[2];\n\n\t// This flag is used to decide whether framebuffer's depth attachment should be cleared\n\t// with vmCmdClearAttachment (dirty_depth_attachment == true), or it have just been\n\t// cleared by render pass instance clear op (dirty_depth_attachment == false).\n\tbool dirty_depth_attachment;\n\n\tfloat modelview_transform[16];\n};\n\n// Most of the renderer's code uses Vulkan API via function provides in this file but \n// there are few places outside of vk.cpp where we use Vulkan commands directly.\nextern PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR;\nextern PFN_vkFreeDescriptorSets vkFreeDescriptorSets;\nextern PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr;\nextern PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties;\nextern PFN_vkDestroyImage vkDestroyImage;\nextern PFN_vkDestroyImageView vkDestroyImageView;\nextern PFN_vkDeviceWaitIdle vkDeviceWaitIdle;\n"
  },
  {
    "path": "src/engine/renderer/vulkan/GLSL.std.450.h",
    "content": "/*\n** Copyright (c) 2014-2016 The Khronos Group Inc.\n**\n** Permission is hereby granted, free of charge, to any person obtaining a copy\n** of this software and/or associated documentation files (the \"Materials\"),\n** to deal in the Materials without restriction, including without limitation\n** the rights to use, copy, modify, merge, publish, distribute, sublicense,\n** and/or sell copies of the Materials, and to permit persons to whom the\n** Materials are furnished to do so, subject to the following conditions:\n**\n** The above copyright notice and this permission notice shall be included in\n** all copies or substantial portions of the Materials.\n**\n** MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS\n** STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND\n** HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ \n**\n** THE MATERIALS ARE PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n** THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n** FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS\n** IN THE MATERIALS.\n*/\n\n#ifndef GLSLstd450_H\n#define GLSLstd450_H\n\nstatic const int GLSLstd450Version = 100;\nstatic const int GLSLstd450Revision = 3;\n\nenum GLSLstd450 {\n    GLSLstd450Bad = 0,              // Don't use\n\n    GLSLstd450Round = 1,\n    GLSLstd450RoundEven = 2,\n    GLSLstd450Trunc = 3,\n    GLSLstd450FAbs = 4,\n    GLSLstd450SAbs = 5,\n    GLSLstd450FSign = 6,\n    GLSLstd450SSign = 7,\n    GLSLstd450Floor = 8,\n    GLSLstd450Ceil = 9,\n    GLSLstd450Fract = 10,\n\n    GLSLstd450Radians = 11,\n    GLSLstd450Degrees = 12,\n    GLSLstd450Sin = 13,\n    GLSLstd450Cos = 14,\n    GLSLstd450Tan = 15,\n    GLSLstd450Asin = 16,\n    GLSLstd450Acos = 17,\n    GLSLstd450Atan = 18,\n    GLSLstd450Sinh = 19,\n    GLSLstd450Cosh = 20,\n    GLSLstd450Tanh = 21,\n    GLSLstd450Asinh = 22,\n    GLSLstd450Acosh = 23,\n    GLSLstd450Atanh = 24,\n    GLSLstd450Atan2 = 25,\n\n    GLSLstd450Pow = 26,\n    GLSLstd450Exp = 27,\n    GLSLstd450Log = 28,\n    GLSLstd450Exp2 = 29,\n    GLSLstd450Log2 = 30,\n    GLSLstd450Sqrt = 31,\n    GLSLstd450InverseSqrt = 32,\n\n    GLSLstd450Determinant = 33,\n    GLSLstd450MatrixInverse = 34,\n\n    GLSLstd450Modf = 35,            // second operand needs an OpVariable to write to\n    GLSLstd450ModfStruct = 36,      // no OpVariable operand\n    GLSLstd450FMin = 37,\n    GLSLstd450UMin = 38,\n    GLSLstd450SMin = 39,\n    GLSLstd450FMax = 40,\n    GLSLstd450UMax = 41,\n    GLSLstd450SMax = 42,\n    GLSLstd450FClamp = 43,\n    GLSLstd450UClamp = 44,\n    GLSLstd450SClamp = 45,\n    GLSLstd450FMix = 46,\n    GLSLstd450IMix = 47,            // Reserved\n    GLSLstd450Step = 48,\n    GLSLstd450SmoothStep = 49,\n\n    GLSLstd450Fma = 50,\n    GLSLstd450Frexp = 51,            // second operand needs an OpVariable to write to\n    GLSLstd450FrexpStruct = 52,      // no OpVariable operand\n    GLSLstd450Ldexp = 53,\n\n    GLSLstd450PackSnorm4x8 = 54,\n    GLSLstd450PackUnorm4x8 = 55,\n    GLSLstd450PackSnorm2x16 = 56,\n    GLSLstd450PackUnorm2x16 = 57,\n    GLSLstd450PackHalf2x16 = 58,\n    GLSLstd450PackDouble2x32 = 59,\n    GLSLstd450UnpackSnorm2x16 = 60,\n    GLSLstd450UnpackUnorm2x16 = 61,\n    GLSLstd450UnpackHalf2x16 = 62,\n    GLSLstd450UnpackSnorm4x8 = 63,\n    GLSLstd450UnpackUnorm4x8 = 64,\n    GLSLstd450UnpackDouble2x32 = 65,\n\n    GLSLstd450Length = 66,\n    GLSLstd450Distance = 67,\n    GLSLstd450Cross = 68,\n    GLSLstd450Normalize = 69,\n    GLSLstd450FaceForward = 70,\n    GLSLstd450Reflect = 71,\n    GLSLstd450Refract = 72,\n\n    GLSLstd450FindILsb = 73,\n    GLSLstd450FindSMsb = 74,\n    GLSLstd450FindUMsb = 75,\n\n    GLSLstd450InterpolateAtCentroid = 76,\n    GLSLstd450InterpolateAtSample = 77,\n    GLSLstd450InterpolateAtOffset = 78,\n\n    GLSLstd450NMin = 79,\n    GLSLstd450NMax = 80,\n    GLSLstd450NClamp = 81,\n\n    GLSLstd450Count\n};\n\n#endif  // #ifndef GLSLstd450_H\n"
  },
  {
    "path": "src/engine/renderer/vulkan/spirv.h",
    "content": "/*\n** Copyright (c) 2014-2017 The Khronos Group Inc.\n** \n** Permission is hereby granted, free of charge, to any person obtaining a copy\n** of this software and/or associated documentation files (the \"Materials\"),\n** to deal in the Materials without restriction, including without limitation\n** the rights to use, copy, modify, merge, publish, distribute, sublicense,\n** and/or sell copies of the Materials, and to permit persons to whom the\n** Materials are furnished to do so, subject to the following conditions:\n** \n** The above copyright notice and this permission notice shall be included in\n** all copies or substantial portions of the Materials.\n** \n** MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS\n** STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND\n** HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ \n** \n** THE MATERIALS ARE PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n** THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n** FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS\n** IN THE MATERIALS.\n*/\n\n/*\n** This header is automatically generated by the same tool that creates\n** the Binary Section of the SPIR-V specification.\n*/\n\n/*\n** Enumeration tokens for SPIR-V, in various styles:\n**   C, C++, C++11, JSON, Lua, Python\n** \n** - C will have tokens with a \"Spv\" prefix, e.g.: SpvSourceLanguageGLSL\n** - C++ will have tokens in the \"spv\" name space, e.g.: spv::SourceLanguageGLSL\n** - C++11 will use enum classes in the spv namespace, e.g.: spv::SourceLanguage::GLSL\n** - Lua will use tables, e.g.: spv.SourceLanguage.GLSL\n** - Python will use dictionaries, e.g.: spv['SourceLanguage']['GLSL']\n** \n** Some tokens act like mask values, which can be OR'd together,\n** while others are mutually exclusive.  The mask-like ones have\n** \"Mask\" in their name, and a parallel enum that has the shift\n** amount (1 << x) for each corresponding enumerant.\n*/\n\n#ifndef spirv_H\n#define spirv_H\n\ntypedef unsigned int SpvId;\n\n#define SPV_VERSION 0x10100\n#define SPV_REVISION 6\n\nstatic const unsigned int SpvMagicNumber = 0x07230203;\nstatic const unsigned int SpvVersion = 0x00010100;\nstatic const unsigned int SpvRevision = 6;\nstatic const unsigned int SpvOpCodeMask = 0xffff;\nstatic const unsigned int SpvWordCountShift = 16;\n\ntypedef enum SpvSourceLanguage_ {\n    SpvSourceLanguageUnknown = 0,\n    SpvSourceLanguageESSL = 1,\n    SpvSourceLanguageGLSL = 2,\n    SpvSourceLanguageOpenCL_C = 3,\n    SpvSourceLanguageOpenCL_CPP = 4,\n    SpvSourceLanguageHLSL = 5,\n    SpvSourceLanguageMax = 0x7fffffff,\n} SpvSourceLanguage;\n\ntypedef enum SpvExecutionModel_ {\n    SpvExecutionModelVertex = 0,\n    SpvExecutionModelTessellationControl = 1,\n    SpvExecutionModelTessellationEvaluation = 2,\n    SpvExecutionModelGeometry = 3,\n    SpvExecutionModelFragment = 4,\n    SpvExecutionModelGLCompute = 5,\n    SpvExecutionModelKernel = 6,\n    SpvExecutionModelMax = 0x7fffffff,\n} SpvExecutionModel;\n\ntypedef enum SpvAddressingModel_ {\n    SpvAddressingModelLogical = 0,\n    SpvAddressingModelPhysical32 = 1,\n    SpvAddressingModelPhysical64 = 2,\n    SpvAddressingModelMax = 0x7fffffff,\n} SpvAddressingModel;\n\ntypedef enum SpvMemoryModel_ {\n    SpvMemoryModelSimple = 0,\n    SpvMemoryModelGLSL450 = 1,\n    SpvMemoryModelOpenCL = 2,\n    SpvMemoryModelMax = 0x7fffffff,\n} SpvMemoryModel;\n\ntypedef enum SpvExecutionMode_ {\n    SpvExecutionModeInvocations = 0,\n    SpvExecutionModeSpacingEqual = 1,\n    SpvExecutionModeSpacingFractionalEven = 2,\n    SpvExecutionModeSpacingFractionalOdd = 3,\n    SpvExecutionModeVertexOrderCw = 4,\n    SpvExecutionModeVertexOrderCcw = 5,\n    SpvExecutionModePixelCenterInteger = 6,\n    SpvExecutionModeOriginUpperLeft = 7,\n    SpvExecutionModeOriginLowerLeft = 8,\n    SpvExecutionModeEarlyFragmentTests = 9,\n    SpvExecutionModePointMode = 10,\n    SpvExecutionModeXfb = 11,\n    SpvExecutionModeDepthReplacing = 12,\n    SpvExecutionModeDepthGreater = 14,\n    SpvExecutionModeDepthLess = 15,\n    SpvExecutionModeDepthUnchanged = 16,\n    SpvExecutionModeLocalSize = 17,\n    SpvExecutionModeLocalSizeHint = 18,\n    SpvExecutionModeInputPoints = 19,\n    SpvExecutionModeInputLines = 20,\n    SpvExecutionModeInputLinesAdjacency = 21,\n    SpvExecutionModeTriangles = 22,\n    SpvExecutionModeInputTrianglesAdjacency = 23,\n    SpvExecutionModeQuads = 24,\n    SpvExecutionModeIsolines = 25,\n    SpvExecutionModeOutputVertices = 26,\n    SpvExecutionModeOutputPoints = 27,\n    SpvExecutionModeOutputLineStrip = 28,\n    SpvExecutionModeOutputTriangleStrip = 29,\n    SpvExecutionModeVecTypeHint = 30,\n    SpvExecutionModeContractionOff = 31,\n    SpvExecutionModeInitializer = 33,\n    SpvExecutionModeFinalizer = 34,\n    SpvExecutionModeSubgroupSize = 35,\n    SpvExecutionModeSubgroupsPerWorkgroup = 36,\n    SpvExecutionModeMax = 0x7fffffff,\n} SpvExecutionMode;\n\ntypedef enum SpvStorageClass_ {\n    SpvStorageClassUniformConstant = 0,\n    SpvStorageClassInput = 1,\n    SpvStorageClassUniform = 2,\n    SpvStorageClassOutput = 3,\n    SpvStorageClassWorkgroup = 4,\n    SpvStorageClassCrossWorkgroup = 5,\n    SpvStorageClassPrivate = 6,\n    SpvStorageClassFunction = 7,\n    SpvStorageClassGeneric = 8,\n    SpvStorageClassPushConstant = 9,\n    SpvStorageClassAtomicCounter = 10,\n    SpvStorageClassImage = 11,\n    SpvStorageClassStorageBuffer = 12,\n    SpvStorageClassMax = 0x7fffffff,\n} SpvStorageClass;\n\ntypedef enum SpvDim_ {\n    SpvDim1D = 0,\n    SpvDim2D = 1,\n    SpvDim3D = 2,\n    SpvDimCube = 3,\n    SpvDimRect = 4,\n    SpvDimBuffer = 5,\n    SpvDimSubpassData = 6,\n    SpvDimMax = 0x7fffffff,\n} SpvDim;\n\ntypedef enum SpvSamplerAddressingMode_ {\n    SpvSamplerAddressingModeNone = 0,\n    SpvSamplerAddressingModeClampToEdge = 1,\n    SpvSamplerAddressingModeClamp = 2,\n    SpvSamplerAddressingModeRepeat = 3,\n    SpvSamplerAddressingModeRepeatMirrored = 4,\n    SpvSamplerAddressingModeMax = 0x7fffffff,\n} SpvSamplerAddressingMode;\n\ntypedef enum SpvSamplerFilterMode_ {\n    SpvSamplerFilterModeNearest = 0,\n    SpvSamplerFilterModeLinear = 1,\n    SpvSamplerFilterModeMax = 0x7fffffff,\n} SpvSamplerFilterMode;\n\ntypedef enum SpvImageFormat_ {\n    SpvImageFormatUnknown = 0,\n    SpvImageFormatRgba32f = 1,\n    SpvImageFormatRgba16f = 2,\n    SpvImageFormatR32f = 3,\n    SpvImageFormatRgba8 = 4,\n    SpvImageFormatRgba8Snorm = 5,\n    SpvImageFormatRg32f = 6,\n    SpvImageFormatRg16f = 7,\n    SpvImageFormatR11fG11fB10f = 8,\n    SpvImageFormatR16f = 9,\n    SpvImageFormatRgba16 = 10,\n    SpvImageFormatRgb10A2 = 11,\n    SpvImageFormatRg16 = 12,\n    SpvImageFormatRg8 = 13,\n    SpvImageFormatR16 = 14,\n    SpvImageFormatR8 = 15,\n    SpvImageFormatRgba16Snorm = 16,\n    SpvImageFormatRg16Snorm = 17,\n    SpvImageFormatRg8Snorm = 18,\n    SpvImageFormatR16Snorm = 19,\n    SpvImageFormatR8Snorm = 20,\n    SpvImageFormatRgba32i = 21,\n    SpvImageFormatRgba16i = 22,\n    SpvImageFormatRgba8i = 23,\n    SpvImageFormatR32i = 24,\n    SpvImageFormatRg32i = 25,\n    SpvImageFormatRg16i = 26,\n    SpvImageFormatRg8i = 27,\n    SpvImageFormatR16i = 28,\n    SpvImageFormatR8i = 29,\n    SpvImageFormatRgba32ui = 30,\n    SpvImageFormatRgba16ui = 31,\n    SpvImageFormatRgba8ui = 32,\n    SpvImageFormatR32ui = 33,\n    SpvImageFormatRgb10a2ui = 34,\n    SpvImageFormatRg32ui = 35,\n    SpvImageFormatRg16ui = 36,\n    SpvImageFormatRg8ui = 37,\n    SpvImageFormatR16ui = 38,\n    SpvImageFormatR8ui = 39,\n    SpvImageFormatMax = 0x7fffffff,\n} SpvImageFormat;\n\ntypedef enum SpvImageChannelOrder_ {\n    SpvImageChannelOrderR = 0,\n    SpvImageChannelOrderA = 1,\n    SpvImageChannelOrderRG = 2,\n    SpvImageChannelOrderRA = 3,\n    SpvImageChannelOrderRGB = 4,\n    SpvImageChannelOrderRGBA = 5,\n    SpvImageChannelOrderBGRA = 6,\n    SpvImageChannelOrderARGB = 7,\n    SpvImageChannelOrderIntensity = 8,\n    SpvImageChannelOrderLuminance = 9,\n    SpvImageChannelOrderRx = 10,\n    SpvImageChannelOrderRGx = 11,\n    SpvImageChannelOrderRGBx = 12,\n    SpvImageChannelOrderDepth = 13,\n    SpvImageChannelOrderDepthStencil = 14,\n    SpvImageChannelOrdersRGB = 15,\n    SpvImageChannelOrdersRGBx = 16,\n    SpvImageChannelOrdersRGBA = 17,\n    SpvImageChannelOrdersBGRA = 18,\n    SpvImageChannelOrderABGR = 19,\n    SpvImageChannelOrderMax = 0x7fffffff,\n} SpvImageChannelOrder;\n\ntypedef enum SpvImageChannelDataType_ {\n    SpvImageChannelDataTypeSnormInt8 = 0,\n    SpvImageChannelDataTypeSnormInt16 = 1,\n    SpvImageChannelDataTypeUnormInt8 = 2,\n    SpvImageChannelDataTypeUnormInt16 = 3,\n    SpvImageChannelDataTypeUnormShort565 = 4,\n    SpvImageChannelDataTypeUnormShort555 = 5,\n    SpvImageChannelDataTypeUnormInt101010 = 6,\n    SpvImageChannelDataTypeSignedInt8 = 7,\n    SpvImageChannelDataTypeSignedInt16 = 8,\n    SpvImageChannelDataTypeSignedInt32 = 9,\n    SpvImageChannelDataTypeUnsignedInt8 = 10,\n    SpvImageChannelDataTypeUnsignedInt16 = 11,\n    SpvImageChannelDataTypeUnsignedInt32 = 12,\n    SpvImageChannelDataTypeHalfFloat = 13,\n    SpvImageChannelDataTypeFloat = 14,\n    SpvImageChannelDataTypeUnormInt24 = 15,\n    SpvImageChannelDataTypeUnormInt101010_2 = 16,\n    SpvImageChannelDataTypeMax = 0x7fffffff,\n} SpvImageChannelDataType;\n\ntypedef enum SpvImageOperandsShift_ {\n    SpvImageOperandsBiasShift = 0,\n    SpvImageOperandsLodShift = 1,\n    SpvImageOperandsGradShift = 2,\n    SpvImageOperandsConstOffsetShift = 3,\n    SpvImageOperandsOffsetShift = 4,\n    SpvImageOperandsConstOffsetsShift = 5,\n    SpvImageOperandsSampleShift = 6,\n    SpvImageOperandsMinLodShift = 7,\n    SpvImageOperandsMax = 0x7fffffff,\n} SpvImageOperandsShift;\n\ntypedef enum SpvImageOperandsMask_ {\n    SpvImageOperandsMaskNone = 0,\n    SpvImageOperandsBiasMask = 0x00000001,\n    SpvImageOperandsLodMask = 0x00000002,\n    SpvImageOperandsGradMask = 0x00000004,\n    SpvImageOperandsConstOffsetMask = 0x00000008,\n    SpvImageOperandsOffsetMask = 0x00000010,\n    SpvImageOperandsConstOffsetsMask = 0x00000020,\n    SpvImageOperandsSampleMask = 0x00000040,\n    SpvImageOperandsMinLodMask = 0x00000080,\n} SpvImageOperandsMask;\n\ntypedef enum SpvFPFastMathModeShift_ {\n    SpvFPFastMathModeNotNaNShift = 0,\n    SpvFPFastMathModeNotInfShift = 1,\n    SpvFPFastMathModeNSZShift = 2,\n    SpvFPFastMathModeAllowRecipShift = 3,\n    SpvFPFastMathModeFastShift = 4,\n    SpvFPFastMathModeMax = 0x7fffffff,\n} SpvFPFastMathModeShift;\n\ntypedef enum SpvFPFastMathModeMask_ {\n    SpvFPFastMathModeMaskNone = 0,\n    SpvFPFastMathModeNotNaNMask = 0x00000001,\n    SpvFPFastMathModeNotInfMask = 0x00000002,\n    SpvFPFastMathModeNSZMask = 0x00000004,\n    SpvFPFastMathModeAllowRecipMask = 0x00000008,\n    SpvFPFastMathModeFastMask = 0x00000010,\n} SpvFPFastMathModeMask;\n\ntypedef enum SpvFPRoundingMode_ {\n    SpvFPRoundingModeRTE = 0,\n    SpvFPRoundingModeRTZ = 1,\n    SpvFPRoundingModeRTP = 2,\n    SpvFPRoundingModeRTN = 3,\n    SpvFPRoundingModeMax = 0x7fffffff,\n} SpvFPRoundingMode;\n\ntypedef enum SpvLinkageType_ {\n    SpvLinkageTypeExport = 0,\n    SpvLinkageTypeImport = 1,\n    SpvLinkageTypeMax = 0x7fffffff,\n} SpvLinkageType;\n\ntypedef enum SpvAccessQualifier_ {\n    SpvAccessQualifierReadOnly = 0,\n    SpvAccessQualifierWriteOnly = 1,\n    SpvAccessQualifierReadWrite = 2,\n    SpvAccessQualifierMax = 0x7fffffff,\n} SpvAccessQualifier;\n\ntypedef enum SpvFunctionParameterAttribute_ {\n    SpvFunctionParameterAttributeZext = 0,\n    SpvFunctionParameterAttributeSext = 1,\n    SpvFunctionParameterAttributeByVal = 2,\n    SpvFunctionParameterAttributeSret = 3,\n    SpvFunctionParameterAttributeNoAlias = 4,\n    SpvFunctionParameterAttributeNoCapture = 5,\n    SpvFunctionParameterAttributeNoWrite = 6,\n    SpvFunctionParameterAttributeNoReadWrite = 7,\n    SpvFunctionParameterAttributeMax = 0x7fffffff,\n} SpvFunctionParameterAttribute;\n\ntypedef enum SpvDecoration_ {\n    SpvDecorationRelaxedPrecision = 0,\n    SpvDecorationSpecId = 1,\n    SpvDecorationBlock = 2,\n    SpvDecorationBufferBlock = 3,\n    SpvDecorationRowMajor = 4,\n    SpvDecorationColMajor = 5,\n    SpvDecorationArrayStride = 6,\n    SpvDecorationMatrixStride = 7,\n    SpvDecorationGLSLShared = 8,\n    SpvDecorationGLSLPacked = 9,\n    SpvDecorationCPacked = 10,\n    SpvDecorationBuiltIn = 11,\n    SpvDecorationNoPerspective = 13,\n    SpvDecorationFlat = 14,\n    SpvDecorationPatch = 15,\n    SpvDecorationCentroid = 16,\n    SpvDecorationSample = 17,\n    SpvDecorationInvariant = 18,\n    SpvDecorationRestrict = 19,\n    SpvDecorationAliased = 20,\n    SpvDecorationVolatile = 21,\n    SpvDecorationConstant = 22,\n    SpvDecorationCoherent = 23,\n    SpvDecorationNonWritable = 24,\n    SpvDecorationNonReadable = 25,\n    SpvDecorationUniform = 26,\n    SpvDecorationSaturatedConversion = 28,\n    SpvDecorationStream = 29,\n    SpvDecorationLocation = 30,\n    SpvDecorationComponent = 31,\n    SpvDecorationIndex = 32,\n    SpvDecorationBinding = 33,\n    SpvDecorationDescriptorSet = 34,\n    SpvDecorationOffset = 35,\n    SpvDecorationXfbBuffer = 36,\n    SpvDecorationXfbStride = 37,\n    SpvDecorationFuncParamAttr = 38,\n    SpvDecorationFPRoundingMode = 39,\n    SpvDecorationFPFastMathMode = 40,\n    SpvDecorationLinkageAttributes = 41,\n    SpvDecorationNoContraction = 42,\n    SpvDecorationInputAttachmentIndex = 43,\n    SpvDecorationAlignment = 44,\n    SpvDecorationMaxByteOffset = 45,\n    SpvDecorationOverrideCoverageNV = 5248,\n    SpvDecorationPassthroughNV = 5250,\n    SpvDecorationViewportRelativeNV = 5252,\n    SpvDecorationSecondaryViewportRelativeNV = 5256,\n    SpvDecorationMax = 0x7fffffff,\n} SpvDecoration;\n\ntypedef enum SpvBuiltIn_ {\n    SpvBuiltInPosition = 0,\n    SpvBuiltInPointSize = 1,\n    SpvBuiltInClipDistance = 3,\n    SpvBuiltInCullDistance = 4,\n    SpvBuiltInVertexId = 5,\n    SpvBuiltInInstanceId = 6,\n    SpvBuiltInPrimitiveId = 7,\n    SpvBuiltInInvocationId = 8,\n    SpvBuiltInLayer = 9,\n    SpvBuiltInViewportIndex = 10,\n    SpvBuiltInTessLevelOuter = 11,\n    SpvBuiltInTessLevelInner = 12,\n    SpvBuiltInTessCoord = 13,\n    SpvBuiltInPatchVertices = 14,\n    SpvBuiltInFragCoord = 15,\n    SpvBuiltInPointCoord = 16,\n    SpvBuiltInFrontFacing = 17,\n    SpvBuiltInSampleId = 18,\n    SpvBuiltInSamplePosition = 19,\n    SpvBuiltInSampleMask = 20,\n    SpvBuiltInFragDepth = 22,\n    SpvBuiltInHelperInvocation = 23,\n    SpvBuiltInNumWorkgroups = 24,\n    SpvBuiltInWorkgroupSize = 25,\n    SpvBuiltInWorkgroupId = 26,\n    SpvBuiltInLocalInvocationId = 27,\n    SpvBuiltInGlobalInvocationId = 28,\n    SpvBuiltInLocalInvocationIndex = 29,\n    SpvBuiltInWorkDim = 30,\n    SpvBuiltInGlobalSize = 31,\n    SpvBuiltInEnqueuedWorkgroupSize = 32,\n    SpvBuiltInGlobalOffset = 33,\n    SpvBuiltInGlobalLinearId = 34,\n    SpvBuiltInSubgroupSize = 36,\n    SpvBuiltInSubgroupMaxSize = 37,\n    SpvBuiltInNumSubgroups = 38,\n    SpvBuiltInNumEnqueuedSubgroups = 39,\n    SpvBuiltInSubgroupId = 40,\n    SpvBuiltInSubgroupLocalInvocationId = 41,\n    SpvBuiltInVertexIndex = 42,\n    SpvBuiltInInstanceIndex = 43,\n    SpvBuiltInSubgroupEqMaskKHR = 4416,\n    SpvBuiltInSubgroupGeMaskKHR = 4417,\n    SpvBuiltInSubgroupGtMaskKHR = 4418,\n    SpvBuiltInSubgroupLeMaskKHR = 4419,\n    SpvBuiltInSubgroupLtMaskKHR = 4420,\n    SpvBuiltInBaseVertex = 4424,\n    SpvBuiltInBaseInstance = 4425,\n    SpvBuiltInDrawIndex = 4426,\n    SpvBuiltInDeviceIndex = 4438,\n    SpvBuiltInViewIndex = 4440,\n    SpvBuiltInViewportMaskNV = 5253,\n    SpvBuiltInSecondaryPositionNV = 5257,\n    SpvBuiltInSecondaryViewportMaskNV = 5258,\n    SpvBuiltInPositionPerViewNV = 5261,\n    SpvBuiltInViewportMaskPerViewNV = 5262,\n    SpvBuiltInMax = 0x7fffffff,\n} SpvBuiltIn;\n\ntypedef enum SpvSelectionControlShift_ {\n    SpvSelectionControlFlattenShift = 0,\n    SpvSelectionControlDontFlattenShift = 1,\n    SpvSelectionControlMax = 0x7fffffff,\n} SpvSelectionControlShift;\n\ntypedef enum SpvSelectionControlMask_ {\n    SpvSelectionControlMaskNone = 0,\n    SpvSelectionControlFlattenMask = 0x00000001,\n    SpvSelectionControlDontFlattenMask = 0x00000002,\n} SpvSelectionControlMask;\n\ntypedef enum SpvLoopControlShift_ {\n    SpvLoopControlUnrollShift = 0,\n    SpvLoopControlDontUnrollShift = 1,\n    SpvLoopControlDependencyInfiniteShift = 2,\n    SpvLoopControlDependencyLengthShift = 3,\n    SpvLoopControlMax = 0x7fffffff,\n} SpvLoopControlShift;\n\ntypedef enum SpvLoopControlMask_ {\n    SpvLoopControlMaskNone = 0,\n    SpvLoopControlUnrollMask = 0x00000001,\n    SpvLoopControlDontUnrollMask = 0x00000002,\n    SpvLoopControlDependencyInfiniteMask = 0x00000004,\n    SpvLoopControlDependencyLengthMask = 0x00000008,\n} SpvLoopControlMask;\n\ntypedef enum SpvFunctionControlShift_ {\n    SpvFunctionControlInlineShift = 0,\n    SpvFunctionControlDontInlineShift = 1,\n    SpvFunctionControlPureShift = 2,\n    SpvFunctionControlConstShift = 3,\n    SpvFunctionControlMax = 0x7fffffff,\n} SpvFunctionControlShift;\n\ntypedef enum SpvFunctionControlMask_ {\n    SpvFunctionControlMaskNone = 0,\n    SpvFunctionControlInlineMask = 0x00000001,\n    SpvFunctionControlDontInlineMask = 0x00000002,\n    SpvFunctionControlPureMask = 0x00000004,\n    SpvFunctionControlConstMask = 0x00000008,\n} SpvFunctionControlMask;\n\ntypedef enum SpvMemorySemanticsShift_ {\n    SpvMemorySemanticsAcquireShift = 1,\n    SpvMemorySemanticsReleaseShift = 2,\n    SpvMemorySemanticsAcquireReleaseShift = 3,\n    SpvMemorySemanticsSequentiallyConsistentShift = 4,\n    SpvMemorySemanticsUniformMemoryShift = 6,\n    SpvMemorySemanticsSubgroupMemoryShift = 7,\n    SpvMemorySemanticsWorkgroupMemoryShift = 8,\n    SpvMemorySemanticsCrossWorkgroupMemoryShift = 9,\n    SpvMemorySemanticsAtomicCounterMemoryShift = 10,\n    SpvMemorySemanticsImageMemoryShift = 11,\n    SpvMemorySemanticsMax = 0x7fffffff,\n} SpvMemorySemanticsShift;\n\ntypedef enum SpvMemorySemanticsMask_ {\n    SpvMemorySemanticsMaskNone = 0,\n    SpvMemorySemanticsAcquireMask = 0x00000002,\n    SpvMemorySemanticsReleaseMask = 0x00000004,\n    SpvMemorySemanticsAcquireReleaseMask = 0x00000008,\n    SpvMemorySemanticsSequentiallyConsistentMask = 0x00000010,\n    SpvMemorySemanticsUniformMemoryMask = 0x00000040,\n    SpvMemorySemanticsSubgroupMemoryMask = 0x00000080,\n    SpvMemorySemanticsWorkgroupMemoryMask = 0x00000100,\n    SpvMemorySemanticsCrossWorkgroupMemoryMask = 0x00000200,\n    SpvMemorySemanticsAtomicCounterMemoryMask = 0x00000400,\n    SpvMemorySemanticsImageMemoryMask = 0x00000800,\n} SpvMemorySemanticsMask;\n\ntypedef enum SpvMemoryAccessShift_ {\n    SpvMemoryAccessVolatileShift = 0,\n    SpvMemoryAccessAlignedShift = 1,\n    SpvMemoryAccessNontemporalShift = 2,\n    SpvMemoryAccessMax = 0x7fffffff,\n} SpvMemoryAccessShift;\n\ntypedef enum SpvMemoryAccessMask_ {\n    SpvMemoryAccessMaskNone = 0,\n    SpvMemoryAccessVolatileMask = 0x00000001,\n    SpvMemoryAccessAlignedMask = 0x00000002,\n    SpvMemoryAccessNontemporalMask = 0x00000004,\n} SpvMemoryAccessMask;\n\ntypedef enum SpvScope_ {\n    SpvScopeCrossDevice = 0,\n    SpvScopeDevice = 1,\n    SpvScopeWorkgroup = 2,\n    SpvScopeSubgroup = 3,\n    SpvScopeInvocation = 4,\n    SpvScopeMax = 0x7fffffff,\n} SpvScope;\n\ntypedef enum SpvGroupOperation_ {\n    SpvGroupOperationReduce = 0,\n    SpvGroupOperationInclusiveScan = 1,\n    SpvGroupOperationExclusiveScan = 2,\n    SpvGroupOperationMax = 0x7fffffff,\n} SpvGroupOperation;\n\ntypedef enum SpvKernelEnqueueFlags_ {\n    SpvKernelEnqueueFlagsNoWait = 0,\n    SpvKernelEnqueueFlagsWaitKernel = 1,\n    SpvKernelEnqueueFlagsWaitWorkGroup = 2,\n    SpvKernelEnqueueFlagsMax = 0x7fffffff,\n} SpvKernelEnqueueFlags;\n\ntypedef enum SpvKernelProfilingInfoShift_ {\n    SpvKernelProfilingInfoCmdExecTimeShift = 0,\n    SpvKernelProfilingInfoMax = 0x7fffffff,\n} SpvKernelProfilingInfoShift;\n\ntypedef enum SpvKernelProfilingInfoMask_ {\n    SpvKernelProfilingInfoMaskNone = 0,\n    SpvKernelProfilingInfoCmdExecTimeMask = 0x00000001,\n} SpvKernelProfilingInfoMask;\n\ntypedef enum SpvCapability_ {\n    SpvCapabilityMatrix = 0,\n    SpvCapabilityShader = 1,\n    SpvCapabilityGeometry = 2,\n    SpvCapabilityTessellation = 3,\n    SpvCapabilityAddresses = 4,\n    SpvCapabilityLinkage = 5,\n    SpvCapabilityKernel = 6,\n    SpvCapabilityVector16 = 7,\n    SpvCapabilityFloat16Buffer = 8,\n    SpvCapabilityFloat16 = 9,\n    SpvCapabilityFloat64 = 10,\n    SpvCapabilityInt64 = 11,\n    SpvCapabilityInt64Atomics = 12,\n    SpvCapabilityImageBasic = 13,\n    SpvCapabilityImageReadWrite = 14,\n    SpvCapabilityImageMipmap = 15,\n    SpvCapabilityPipes = 17,\n    SpvCapabilityGroups = 18,\n    SpvCapabilityDeviceEnqueue = 19,\n    SpvCapabilityLiteralSampler = 20,\n    SpvCapabilityAtomicStorage = 21,\n    SpvCapabilityInt16 = 22,\n    SpvCapabilityTessellationPointSize = 23,\n    SpvCapabilityGeometryPointSize = 24,\n    SpvCapabilityImageGatherExtended = 25,\n    SpvCapabilityStorageImageMultisample = 27,\n    SpvCapabilityUniformBufferArrayDynamicIndexing = 28,\n    SpvCapabilitySampledImageArrayDynamicIndexing = 29,\n    SpvCapabilityStorageBufferArrayDynamicIndexing = 30,\n    SpvCapabilityStorageImageArrayDynamicIndexing = 31,\n    SpvCapabilityClipDistance = 32,\n    SpvCapabilityCullDistance = 33,\n    SpvCapabilityImageCubeArray = 34,\n    SpvCapabilitySampleRateShading = 35,\n    SpvCapabilityImageRect = 36,\n    SpvCapabilitySampledRect = 37,\n    SpvCapabilityGenericPointer = 38,\n    SpvCapabilityInt8 = 39,\n    SpvCapabilityInputAttachment = 40,\n    SpvCapabilitySparseResidency = 41,\n    SpvCapabilityMinLod = 42,\n    SpvCapabilitySampled1D = 43,\n    SpvCapabilityImage1D = 44,\n    SpvCapabilitySampledCubeArray = 45,\n    SpvCapabilitySampledBuffer = 46,\n    SpvCapabilityImageBuffer = 47,\n    SpvCapabilityImageMSArray = 48,\n    SpvCapabilityStorageImageExtendedFormats = 49,\n    SpvCapabilityImageQuery = 50,\n    SpvCapabilityDerivativeControl = 51,\n    SpvCapabilityInterpolationFunction = 52,\n    SpvCapabilityTransformFeedback = 53,\n    SpvCapabilityGeometryStreams = 54,\n    SpvCapabilityStorageImageReadWithoutFormat = 55,\n    SpvCapabilityStorageImageWriteWithoutFormat = 56,\n    SpvCapabilityMultiViewport = 57,\n    SpvCapabilitySubgroupDispatch = 58,\n    SpvCapabilityNamedBarrier = 59,\n    SpvCapabilityPipeStorage = 60,\n    SpvCapabilitySubgroupBallotKHR = 4423,\n    SpvCapabilityDrawParameters = 4427,\n    SpvCapabilitySubgroupVoteKHR = 4431,\n    SpvCapabilityStorageBuffer16BitAccess = 4433,\n    SpvCapabilityStorageUniformBufferBlock16 = 4433,\n    SpvCapabilityStorageUniform16 = 4434,\n    SpvCapabilityUniformAndStorageBuffer16BitAccess = 4434,\n    SpvCapabilityStoragePushConstant16 = 4435,\n    SpvCapabilityStorageInputOutput16 = 4436,\n    SpvCapabilityDeviceGroup = 4437,\n    SpvCapabilityMultiView = 4439,\n    SpvCapabilityVariablePointersStorageBuffer = 4441,\n    SpvCapabilityVariablePointers = 4442,\n    SpvCapabilitySampleMaskOverrideCoverageNV = 5249,\n    SpvCapabilityGeometryShaderPassthroughNV = 5251,\n    SpvCapabilityShaderViewportIndexLayerNV = 5254,\n    SpvCapabilityShaderViewportMaskNV = 5255,\n    SpvCapabilityShaderStereoViewNV = 5259,\n    SpvCapabilityPerViewAttributesNV = 5260,\n    SpvCapabilityMax = 0x7fffffff,\n} SpvCapability;\n\ntypedef enum SpvOp_ {\n    SpvOpNop = 0,\n    SpvOpUndef = 1,\n    SpvOpSourceContinued = 2,\n    SpvOpSource = 3,\n    SpvOpSourceExtension = 4,\n    SpvOpName = 5,\n    SpvOpMemberName = 6,\n    SpvOpString = 7,\n    SpvOpLine = 8,\n    SpvOpExtension = 10,\n    SpvOpExtInstImport = 11,\n    SpvOpExtInst = 12,\n    SpvOpMemoryModel = 14,\n    SpvOpEntryPoint = 15,\n    SpvOpExecutionMode = 16,\n    SpvOpCapability = 17,\n    SpvOpTypeVoid = 19,\n    SpvOpTypeBool = 20,\n    SpvOpTypeInt = 21,\n    SpvOpTypeFloat = 22,\n    SpvOpTypeVector = 23,\n    SpvOpTypeMatrix = 24,\n    SpvOpTypeImage = 25,\n    SpvOpTypeSampler = 26,\n    SpvOpTypeSampledImage = 27,\n    SpvOpTypeArray = 28,\n    SpvOpTypeRuntimeArray = 29,\n    SpvOpTypeStruct = 30,\n    SpvOpTypeOpaque = 31,\n    SpvOpTypePointer = 32,\n    SpvOpTypeFunction = 33,\n    SpvOpTypeEvent = 34,\n    SpvOpTypeDeviceEvent = 35,\n    SpvOpTypeReserveId = 36,\n    SpvOpTypeQueue = 37,\n    SpvOpTypePipe = 38,\n    SpvOpTypeForwardPointer = 39,\n    SpvOpConstantTrue = 41,\n    SpvOpConstantFalse = 42,\n    SpvOpConstant = 43,\n    SpvOpConstantComposite = 44,\n    SpvOpConstantSampler = 45,\n    SpvOpConstantNull = 46,\n    SpvOpSpecConstantTrue = 48,\n    SpvOpSpecConstantFalse = 49,\n    SpvOpSpecConstant = 50,\n    SpvOpSpecConstantComposite = 51,\n    SpvOpSpecConstantOp = 52,\n    SpvOpFunction = 54,\n    SpvOpFunctionParameter = 55,\n    SpvOpFunctionEnd = 56,\n    SpvOpFunctionCall = 57,\n    SpvOpVariable = 59,\n    SpvOpImageTexelPointer = 60,\n    SpvOpLoad = 61,\n    SpvOpStore = 62,\n    SpvOpCopyMemory = 63,\n    SpvOpCopyMemorySized = 64,\n    SpvOpAccessChain = 65,\n    SpvOpInBoundsAccessChain = 66,\n    SpvOpPtrAccessChain = 67,\n    SpvOpArrayLength = 68,\n    SpvOpGenericPtrMemSemantics = 69,\n    SpvOpInBoundsPtrAccessChain = 70,\n    SpvOpDecorate = 71,\n    SpvOpMemberDecorate = 72,\n    SpvOpDecorationGroup = 73,\n    SpvOpGroupDecorate = 74,\n    SpvOpGroupMemberDecorate = 75,\n    SpvOpVectorExtractDynamic = 77,\n    SpvOpVectorInsertDynamic = 78,\n    SpvOpVectorShuffle = 79,\n    SpvOpCompositeConstruct = 80,\n    SpvOpCompositeExtract = 81,\n    SpvOpCompositeInsert = 82,\n    SpvOpCopyObject = 83,\n    SpvOpTranspose = 84,\n    SpvOpSampledImage = 86,\n    SpvOpImageSampleImplicitLod = 87,\n    SpvOpImageSampleExplicitLod = 88,\n    SpvOpImageSampleDrefImplicitLod = 89,\n    SpvOpImageSampleDrefExplicitLod = 90,\n    SpvOpImageSampleProjImplicitLod = 91,\n    SpvOpImageSampleProjExplicitLod = 92,\n    SpvOpImageSampleProjDrefImplicitLod = 93,\n    SpvOpImageSampleProjDrefExplicitLod = 94,\n    SpvOpImageFetch = 95,\n    SpvOpImageGather = 96,\n    SpvOpImageDrefGather = 97,\n    SpvOpImageRead = 98,\n    SpvOpImageWrite = 99,\n    SpvOpImage = 100,\n    SpvOpImageQueryFormat = 101,\n    SpvOpImageQueryOrder = 102,\n    SpvOpImageQuerySizeLod = 103,\n    SpvOpImageQuerySize = 104,\n    SpvOpImageQueryLod = 105,\n    SpvOpImageQueryLevels = 106,\n    SpvOpImageQuerySamples = 107,\n    SpvOpConvertFToU = 109,\n    SpvOpConvertFToS = 110,\n    SpvOpConvertSToF = 111,\n    SpvOpConvertUToF = 112,\n    SpvOpUConvert = 113,\n    SpvOpSConvert = 114,\n    SpvOpFConvert = 115,\n    SpvOpQuantizeToF16 = 116,\n    SpvOpConvertPtrToU = 117,\n    SpvOpSatConvertSToU = 118,\n    SpvOpSatConvertUToS = 119,\n    SpvOpConvertUToPtr = 120,\n    SpvOpPtrCastToGeneric = 121,\n    SpvOpGenericCastToPtr = 122,\n    SpvOpGenericCastToPtrExplicit = 123,\n    SpvOpBitcast = 124,\n    SpvOpSNegate = 126,\n    SpvOpFNegate = 127,\n    SpvOpIAdd = 128,\n    SpvOpFAdd = 129,\n    SpvOpISub = 130,\n    SpvOpFSub = 131,\n    SpvOpIMul = 132,\n    SpvOpFMul = 133,\n    SpvOpUDiv = 134,\n    SpvOpSDiv = 135,\n    SpvOpFDiv = 136,\n    SpvOpUMod = 137,\n    SpvOpSRem = 138,\n    SpvOpSMod = 139,\n    SpvOpFRem = 140,\n    SpvOpFMod = 141,\n    SpvOpVectorTimesScalar = 142,\n    SpvOpMatrixTimesScalar = 143,\n    SpvOpVectorTimesMatrix = 144,\n    SpvOpMatrixTimesVector = 145,\n    SpvOpMatrixTimesMatrix = 146,\n    SpvOpOuterProduct = 147,\n    SpvOpDot = 148,\n    SpvOpIAddCarry = 149,\n    SpvOpISubBorrow = 150,\n    SpvOpUMulExtended = 151,\n    SpvOpSMulExtended = 152,\n    SpvOpAny = 154,\n    SpvOpAll = 155,\n    SpvOpIsNan = 156,\n    SpvOpIsInf = 157,\n    SpvOpIsFinite = 158,\n    SpvOpIsNormal = 159,\n    SpvOpSignBitSet = 160,\n    SpvOpLessOrGreater = 161,\n    SpvOpOrdered = 162,\n    SpvOpUnordered = 163,\n    SpvOpLogicalEqual = 164,\n    SpvOpLogicalNotEqual = 165,\n    SpvOpLogicalOr = 166,\n    SpvOpLogicalAnd = 167,\n    SpvOpLogicalNot = 168,\n    SpvOpSelect = 169,\n    SpvOpIEqual = 170,\n    SpvOpINotEqual = 171,\n    SpvOpUGreaterThan = 172,\n    SpvOpSGreaterThan = 173,\n    SpvOpUGreaterThanEqual = 174,\n    SpvOpSGreaterThanEqual = 175,\n    SpvOpULessThan = 176,\n    SpvOpSLessThan = 177,\n    SpvOpULessThanEqual = 178,\n    SpvOpSLessThanEqual = 179,\n    SpvOpFOrdEqual = 180,\n    SpvOpFUnordEqual = 181,\n    SpvOpFOrdNotEqual = 182,\n    SpvOpFUnordNotEqual = 183,\n    SpvOpFOrdLessThan = 184,\n    SpvOpFUnordLessThan = 185,\n    SpvOpFOrdGreaterThan = 186,\n    SpvOpFUnordGreaterThan = 187,\n    SpvOpFOrdLessThanEqual = 188,\n    SpvOpFUnordLessThanEqual = 189,\n    SpvOpFOrdGreaterThanEqual = 190,\n    SpvOpFUnordGreaterThanEqual = 191,\n    SpvOpShiftRightLogical = 194,\n    SpvOpShiftRightArithmetic = 195,\n    SpvOpShiftLeftLogical = 196,\n    SpvOpBitwiseOr = 197,\n    SpvOpBitwiseXor = 198,\n    SpvOpBitwiseAnd = 199,\n    SpvOpNot = 200,\n    SpvOpBitFieldInsert = 201,\n    SpvOpBitFieldSExtract = 202,\n    SpvOpBitFieldUExtract = 203,\n    SpvOpBitReverse = 204,\n    SpvOpBitCount = 205,\n    SpvOpDPdx = 207,\n    SpvOpDPdy = 208,\n    SpvOpFwidth = 209,\n    SpvOpDPdxFine = 210,\n    SpvOpDPdyFine = 211,\n    SpvOpFwidthFine = 212,\n    SpvOpDPdxCoarse = 213,\n    SpvOpDPdyCoarse = 214,\n    SpvOpFwidthCoarse = 215,\n    SpvOpEmitVertex = 218,\n    SpvOpEndPrimitive = 219,\n    SpvOpEmitStreamVertex = 220,\n    SpvOpEndStreamPrimitive = 221,\n    SpvOpControlBarrier = 224,\n    SpvOpMemoryBarrier = 225,\n    SpvOpAtomicLoad = 227,\n    SpvOpAtomicStore = 228,\n    SpvOpAtomicExchange = 229,\n    SpvOpAtomicCompareExchange = 230,\n    SpvOpAtomicCompareExchangeWeak = 231,\n    SpvOpAtomicIIncrement = 232,\n    SpvOpAtomicIDecrement = 233,\n    SpvOpAtomicIAdd = 234,\n    SpvOpAtomicISub = 235,\n    SpvOpAtomicSMin = 236,\n    SpvOpAtomicUMin = 237,\n    SpvOpAtomicSMax = 238,\n    SpvOpAtomicUMax = 239,\n    SpvOpAtomicAnd = 240,\n    SpvOpAtomicOr = 241,\n    SpvOpAtomicXor = 242,\n    SpvOpPhi = 245,\n    SpvOpLoopMerge = 246,\n    SpvOpSelectionMerge = 247,\n    SpvOpLabel = 248,\n    SpvOpBranch = 249,\n    SpvOpBranchConditional = 250,\n    SpvOpSwitch = 251,\n    SpvOpKill = 252,\n    SpvOpReturn = 253,\n    SpvOpReturnValue = 254,\n    SpvOpUnreachable = 255,\n    SpvOpLifetimeStart = 256,\n    SpvOpLifetimeStop = 257,\n    SpvOpGroupAsyncCopy = 259,\n    SpvOpGroupWaitEvents = 260,\n    SpvOpGroupAll = 261,\n    SpvOpGroupAny = 262,\n    SpvOpGroupBroadcast = 263,\n    SpvOpGroupIAdd = 264,\n    SpvOpGroupFAdd = 265,\n    SpvOpGroupFMin = 266,\n    SpvOpGroupUMin = 267,\n    SpvOpGroupSMin = 268,\n    SpvOpGroupFMax = 269,\n    SpvOpGroupUMax = 270,\n    SpvOpGroupSMax = 271,\n    SpvOpReadPipe = 274,\n    SpvOpWritePipe = 275,\n    SpvOpReservedReadPipe = 276,\n    SpvOpReservedWritePipe = 277,\n    SpvOpReserveReadPipePackets = 278,\n    SpvOpReserveWritePipePackets = 279,\n    SpvOpCommitReadPipe = 280,\n    SpvOpCommitWritePipe = 281,\n    SpvOpIsValidReserveId = 282,\n    SpvOpGetNumPipePackets = 283,\n    SpvOpGetMaxPipePackets = 284,\n    SpvOpGroupReserveReadPipePackets = 285,\n    SpvOpGroupReserveWritePipePackets = 286,\n    SpvOpGroupCommitReadPipe = 287,\n    SpvOpGroupCommitWritePipe = 288,\n    SpvOpEnqueueMarker = 291,\n    SpvOpEnqueueKernel = 292,\n    SpvOpGetKernelNDrangeSubGroupCount = 293,\n    SpvOpGetKernelNDrangeMaxSubGroupSize = 294,\n    SpvOpGetKernelWorkGroupSize = 295,\n    SpvOpGetKernelPreferredWorkGroupSizeMultiple = 296,\n    SpvOpRetainEvent = 297,\n    SpvOpReleaseEvent = 298,\n    SpvOpCreateUserEvent = 299,\n    SpvOpIsValidEvent = 300,\n    SpvOpSetUserEventStatus = 301,\n    SpvOpCaptureEventProfilingInfo = 302,\n    SpvOpGetDefaultQueue = 303,\n    SpvOpBuildNDRange = 304,\n    SpvOpImageSparseSampleImplicitLod = 305,\n    SpvOpImageSparseSampleExplicitLod = 306,\n    SpvOpImageSparseSampleDrefImplicitLod = 307,\n    SpvOpImageSparseSampleDrefExplicitLod = 308,\n    SpvOpImageSparseSampleProjImplicitLod = 309,\n    SpvOpImageSparseSampleProjExplicitLod = 310,\n    SpvOpImageSparseSampleProjDrefImplicitLod = 311,\n    SpvOpImageSparseSampleProjDrefExplicitLod = 312,\n    SpvOpImageSparseFetch = 313,\n    SpvOpImageSparseGather = 314,\n    SpvOpImageSparseDrefGather = 315,\n    SpvOpImageSparseTexelsResident = 316,\n    SpvOpNoLine = 317,\n    SpvOpAtomicFlagTestAndSet = 318,\n    SpvOpAtomicFlagClear = 319,\n    SpvOpImageSparseRead = 320,\n    SpvOpSizeOf = 321,\n    SpvOpTypePipeStorage = 322,\n    SpvOpConstantPipeStorage = 323,\n    SpvOpCreatePipeFromPipeStorage = 324,\n    SpvOpGetKernelLocalSizeForSubgroupCount = 325,\n    SpvOpGetKernelMaxNumSubgroups = 326,\n    SpvOpTypeNamedBarrier = 327,\n    SpvOpNamedBarrierInitialize = 328,\n    SpvOpMemoryNamedBarrier = 329,\n    SpvOpModuleProcessed = 330,\n    SpvOpSubgroupBallotKHR = 4421,\n    SpvOpSubgroupFirstInvocationKHR = 4422,\n    SpvOpSubgroupAllKHR = 4428,\n    SpvOpSubgroupAnyKHR = 4429,\n    SpvOpSubgroupAllEqualKHR = 4430,\n    SpvOpSubgroupReadInvocationKHR = 4432,\n    SpvOpMax = 0x7fffffff,\n} SpvOp;\n\n#endif  // #ifndef spirv_H\n\n"
  },
  {
    "path": "src/engine/renderer/vulkan/spirv.hpp",
    "content": "// Copyright (c) 2014-2017 The Khronos Group Inc.\n// \n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and/or associated documentation files (the \"Materials\"),\n// to deal in the Materials without restriction, including without limitation\n// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n// and/or sell copies of the Materials, and to permit persons to whom the\n// Materials are furnished to do so, subject to the following conditions:\n// \n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Materials.\n// \n// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS\n// STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND\n// HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ \n// \n// THE MATERIALS ARE PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n// FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS\n// IN THE MATERIALS.\n\n// This header is automatically generated by the same tool that creates\n// the Binary Section of the SPIR-V specification.\n\n// Enumeration tokens for SPIR-V, in various styles:\n//   C, C++, C++11, JSON, Lua, Python\n// \n// - C will have tokens with a \"Spv\" prefix, e.g.: SpvSourceLanguageGLSL\n// - C++ will have tokens in the \"spv\" name space, e.g.: spv::SourceLanguageGLSL\n// - C++11 will use enum classes in the spv namespace, e.g.: spv::SourceLanguage::GLSL\n// - Lua will use tables, e.g.: spv.SourceLanguage.GLSL\n// - Python will use dictionaries, e.g.: spv['SourceLanguage']['GLSL']\n// \n// Some tokens act like mask values, which can be OR'd together,\n// while others are mutually exclusive.  The mask-like ones have\n// \"Mask\" in their name, and a parallel enum that has the shift\n// amount (1 << x) for each corresponding enumerant.\n\n#ifndef spirv_HPP\n#define spirv_HPP\n\nnamespace spv {\n\ntypedef unsigned int Id;\n\n#define SPV_VERSION 0x10100\n#define SPV_REVISION 6\n\nstatic const unsigned int MagicNumber = 0x07230203;\nstatic const unsigned int Version = 0x00010100;\nstatic const unsigned int Revision = 6;\nstatic const unsigned int OpCodeMask = 0xffff;\nstatic const unsigned int WordCountShift = 16;\n\nenum SourceLanguage {\n    SourceLanguageUnknown = 0,\n    SourceLanguageESSL = 1,\n    SourceLanguageGLSL = 2,\n    SourceLanguageOpenCL_C = 3,\n    SourceLanguageOpenCL_CPP = 4,\n    SourceLanguageHLSL = 5,\n    SourceLanguageMax = 0x7fffffff,\n};\n\nenum ExecutionModel {\n    ExecutionModelVertex = 0,\n    ExecutionModelTessellationControl = 1,\n    ExecutionModelTessellationEvaluation = 2,\n    ExecutionModelGeometry = 3,\n    ExecutionModelFragment = 4,\n    ExecutionModelGLCompute = 5,\n    ExecutionModelKernel = 6,\n    ExecutionModelMax = 0x7fffffff,\n};\n\nenum AddressingModel {\n    AddressingModelLogical = 0,\n    AddressingModelPhysical32 = 1,\n    AddressingModelPhysical64 = 2,\n    AddressingModelMax = 0x7fffffff,\n};\n\nenum MemoryModel {\n    MemoryModelSimple = 0,\n    MemoryModelGLSL450 = 1,\n    MemoryModelOpenCL = 2,\n    MemoryModelMax = 0x7fffffff,\n};\n\nenum ExecutionMode {\n    ExecutionModeInvocations = 0,\n    ExecutionModeSpacingEqual = 1,\n    ExecutionModeSpacingFractionalEven = 2,\n    ExecutionModeSpacingFractionalOdd = 3,\n    ExecutionModeVertexOrderCw = 4,\n    ExecutionModeVertexOrderCcw = 5,\n    ExecutionModePixelCenterInteger = 6,\n    ExecutionModeOriginUpperLeft = 7,\n    ExecutionModeOriginLowerLeft = 8,\n    ExecutionModeEarlyFragmentTests = 9,\n    ExecutionModePointMode = 10,\n    ExecutionModeXfb = 11,\n    ExecutionModeDepthReplacing = 12,\n    ExecutionModeDepthGreater = 14,\n    ExecutionModeDepthLess = 15,\n    ExecutionModeDepthUnchanged = 16,\n    ExecutionModeLocalSize = 17,\n    ExecutionModeLocalSizeHint = 18,\n    ExecutionModeInputPoints = 19,\n    ExecutionModeInputLines = 20,\n    ExecutionModeInputLinesAdjacency = 21,\n    ExecutionModeTriangles = 22,\n    ExecutionModeInputTrianglesAdjacency = 23,\n    ExecutionModeQuads = 24,\n    ExecutionModeIsolines = 25,\n    ExecutionModeOutputVertices = 26,\n    ExecutionModeOutputPoints = 27,\n    ExecutionModeOutputLineStrip = 28,\n    ExecutionModeOutputTriangleStrip = 29,\n    ExecutionModeVecTypeHint = 30,\n    ExecutionModeContractionOff = 31,\n    ExecutionModeInitializer = 33,\n    ExecutionModeFinalizer = 34,\n    ExecutionModeSubgroupSize = 35,\n    ExecutionModeSubgroupsPerWorkgroup = 36,\n    ExecutionModeMax = 0x7fffffff,\n};\n\nenum StorageClass {\n    StorageClassUniformConstant = 0,\n    StorageClassInput = 1,\n    StorageClassUniform = 2,\n    StorageClassOutput = 3,\n    StorageClassWorkgroup = 4,\n    StorageClassCrossWorkgroup = 5,\n    StorageClassPrivate = 6,\n    StorageClassFunction = 7,\n    StorageClassGeneric = 8,\n    StorageClassPushConstant = 9,\n    StorageClassAtomicCounter = 10,\n    StorageClassImage = 11,\n    StorageClassStorageBuffer = 12,\n    StorageClassMax = 0x7fffffff,\n};\n\nenum Dim {\n    Dim1D = 0,\n    Dim2D = 1,\n    Dim3D = 2,\n    DimCube = 3,\n    DimRect = 4,\n    DimBuffer = 5,\n    DimSubpassData = 6,\n    DimMax = 0x7fffffff,\n};\n\nenum SamplerAddressingMode {\n    SamplerAddressingModeNone = 0,\n    SamplerAddressingModeClampToEdge = 1,\n    SamplerAddressingModeClamp = 2,\n    SamplerAddressingModeRepeat = 3,\n    SamplerAddressingModeRepeatMirrored = 4,\n    SamplerAddressingModeMax = 0x7fffffff,\n};\n\nenum SamplerFilterMode {\n    SamplerFilterModeNearest = 0,\n    SamplerFilterModeLinear = 1,\n    SamplerFilterModeMax = 0x7fffffff,\n};\n\nenum ImageFormat {\n    ImageFormatUnknown = 0,\n    ImageFormatRgba32f = 1,\n    ImageFormatRgba16f = 2,\n    ImageFormatR32f = 3,\n    ImageFormatRgba8 = 4,\n    ImageFormatRgba8Snorm = 5,\n    ImageFormatRg32f = 6,\n    ImageFormatRg16f = 7,\n    ImageFormatR11fG11fB10f = 8,\n    ImageFormatR16f = 9,\n    ImageFormatRgba16 = 10,\n    ImageFormatRgb10A2 = 11,\n    ImageFormatRg16 = 12,\n    ImageFormatRg8 = 13,\n    ImageFormatR16 = 14,\n    ImageFormatR8 = 15,\n    ImageFormatRgba16Snorm = 16,\n    ImageFormatRg16Snorm = 17,\n    ImageFormatRg8Snorm = 18,\n    ImageFormatR16Snorm = 19,\n    ImageFormatR8Snorm = 20,\n    ImageFormatRgba32i = 21,\n    ImageFormatRgba16i = 22,\n    ImageFormatRgba8i = 23,\n    ImageFormatR32i = 24,\n    ImageFormatRg32i = 25,\n    ImageFormatRg16i = 26,\n    ImageFormatRg8i = 27,\n    ImageFormatR16i = 28,\n    ImageFormatR8i = 29,\n    ImageFormatRgba32ui = 30,\n    ImageFormatRgba16ui = 31,\n    ImageFormatRgba8ui = 32,\n    ImageFormatR32ui = 33,\n    ImageFormatRgb10a2ui = 34,\n    ImageFormatRg32ui = 35,\n    ImageFormatRg16ui = 36,\n    ImageFormatRg8ui = 37,\n    ImageFormatR16ui = 38,\n    ImageFormatR8ui = 39,\n    ImageFormatMax = 0x7fffffff,\n};\n\nenum ImageChannelOrder {\n    ImageChannelOrderR = 0,\n    ImageChannelOrderA = 1,\n    ImageChannelOrderRG = 2,\n    ImageChannelOrderRA = 3,\n    ImageChannelOrderRGB = 4,\n    ImageChannelOrderRGBA = 5,\n    ImageChannelOrderBGRA = 6,\n    ImageChannelOrderARGB = 7,\n    ImageChannelOrderIntensity = 8,\n    ImageChannelOrderLuminance = 9,\n    ImageChannelOrderRx = 10,\n    ImageChannelOrderRGx = 11,\n    ImageChannelOrderRGBx = 12,\n    ImageChannelOrderDepth = 13,\n    ImageChannelOrderDepthStencil = 14,\n    ImageChannelOrdersRGB = 15,\n    ImageChannelOrdersRGBx = 16,\n    ImageChannelOrdersRGBA = 17,\n    ImageChannelOrdersBGRA = 18,\n    ImageChannelOrderABGR = 19,\n    ImageChannelOrderMax = 0x7fffffff,\n};\n\nenum ImageChannelDataType {\n    ImageChannelDataTypeSnormInt8 = 0,\n    ImageChannelDataTypeSnormInt16 = 1,\n    ImageChannelDataTypeUnormInt8 = 2,\n    ImageChannelDataTypeUnormInt16 = 3,\n    ImageChannelDataTypeUnormShort565 = 4,\n    ImageChannelDataTypeUnormShort555 = 5,\n    ImageChannelDataTypeUnormInt101010 = 6,\n    ImageChannelDataTypeSignedInt8 = 7,\n    ImageChannelDataTypeSignedInt16 = 8,\n    ImageChannelDataTypeSignedInt32 = 9,\n    ImageChannelDataTypeUnsignedInt8 = 10,\n    ImageChannelDataTypeUnsignedInt16 = 11,\n    ImageChannelDataTypeUnsignedInt32 = 12,\n    ImageChannelDataTypeHalfFloat = 13,\n    ImageChannelDataTypeFloat = 14,\n    ImageChannelDataTypeUnormInt24 = 15,\n    ImageChannelDataTypeUnormInt101010_2 = 16,\n    ImageChannelDataTypeMax = 0x7fffffff,\n};\n\nenum ImageOperandsShift {\n    ImageOperandsBiasShift = 0,\n    ImageOperandsLodShift = 1,\n    ImageOperandsGradShift = 2,\n    ImageOperandsConstOffsetShift = 3,\n    ImageOperandsOffsetShift = 4,\n    ImageOperandsConstOffsetsShift = 5,\n    ImageOperandsSampleShift = 6,\n    ImageOperandsMinLodShift = 7,\n    ImageOperandsMax = 0x7fffffff,\n};\n\nenum ImageOperandsMask {\n    ImageOperandsMaskNone = 0,\n    ImageOperandsBiasMask = 0x00000001,\n    ImageOperandsLodMask = 0x00000002,\n    ImageOperandsGradMask = 0x00000004,\n    ImageOperandsConstOffsetMask = 0x00000008,\n    ImageOperandsOffsetMask = 0x00000010,\n    ImageOperandsConstOffsetsMask = 0x00000020,\n    ImageOperandsSampleMask = 0x00000040,\n    ImageOperandsMinLodMask = 0x00000080,\n};\n\nenum FPFastMathModeShift {\n    FPFastMathModeNotNaNShift = 0,\n    FPFastMathModeNotInfShift = 1,\n    FPFastMathModeNSZShift = 2,\n    FPFastMathModeAllowRecipShift = 3,\n    FPFastMathModeFastShift = 4,\n    FPFastMathModeMax = 0x7fffffff,\n};\n\nenum FPFastMathModeMask {\n    FPFastMathModeMaskNone = 0,\n    FPFastMathModeNotNaNMask = 0x00000001,\n    FPFastMathModeNotInfMask = 0x00000002,\n    FPFastMathModeNSZMask = 0x00000004,\n    FPFastMathModeAllowRecipMask = 0x00000008,\n    FPFastMathModeFastMask = 0x00000010,\n};\n\nenum FPRoundingMode {\n    FPRoundingModeRTE = 0,\n    FPRoundingModeRTZ = 1,\n    FPRoundingModeRTP = 2,\n    FPRoundingModeRTN = 3,\n    FPRoundingModeMax = 0x7fffffff,\n};\n\nenum LinkageType {\n    LinkageTypeExport = 0,\n    LinkageTypeImport = 1,\n    LinkageTypeMax = 0x7fffffff,\n};\n\nenum AccessQualifier {\n    AccessQualifierReadOnly = 0,\n    AccessQualifierWriteOnly = 1,\n    AccessQualifierReadWrite = 2,\n    AccessQualifierMax = 0x7fffffff,\n};\n\nenum FunctionParameterAttribute {\n    FunctionParameterAttributeZext = 0,\n    FunctionParameterAttributeSext = 1,\n    FunctionParameterAttributeByVal = 2,\n    FunctionParameterAttributeSret = 3,\n    FunctionParameterAttributeNoAlias = 4,\n    FunctionParameterAttributeNoCapture = 5,\n    FunctionParameterAttributeNoWrite = 6,\n    FunctionParameterAttributeNoReadWrite = 7,\n    FunctionParameterAttributeMax = 0x7fffffff,\n};\n\nenum Decoration {\n    DecorationRelaxedPrecision = 0,\n    DecorationSpecId = 1,\n    DecorationBlock = 2,\n    DecorationBufferBlock = 3,\n    DecorationRowMajor = 4,\n    DecorationColMajor = 5,\n    DecorationArrayStride = 6,\n    DecorationMatrixStride = 7,\n    DecorationGLSLShared = 8,\n    DecorationGLSLPacked = 9,\n    DecorationCPacked = 10,\n    DecorationBuiltIn = 11,\n    DecorationNoPerspective = 13,\n    DecorationFlat = 14,\n    DecorationPatch = 15,\n    DecorationCentroid = 16,\n    DecorationSample = 17,\n    DecorationInvariant = 18,\n    DecorationRestrict = 19,\n    DecorationAliased = 20,\n    DecorationVolatile = 21,\n    DecorationConstant = 22,\n    DecorationCoherent = 23,\n    DecorationNonWritable = 24,\n    DecorationNonReadable = 25,\n    DecorationUniform = 26,\n    DecorationSaturatedConversion = 28,\n    DecorationStream = 29,\n    DecorationLocation = 30,\n    DecorationComponent = 31,\n    DecorationIndex = 32,\n    DecorationBinding = 33,\n    DecorationDescriptorSet = 34,\n    DecorationOffset = 35,\n    DecorationXfbBuffer = 36,\n    DecorationXfbStride = 37,\n    DecorationFuncParamAttr = 38,\n    DecorationFPRoundingMode = 39,\n    DecorationFPFastMathMode = 40,\n    DecorationLinkageAttributes = 41,\n    DecorationNoContraction = 42,\n    DecorationInputAttachmentIndex = 43,\n    DecorationAlignment = 44,\n    DecorationMaxByteOffset = 45,\n    DecorationOverrideCoverageNV = 5248,\n    DecorationPassthroughNV = 5250,\n    DecorationViewportRelativeNV = 5252,\n    DecorationSecondaryViewportRelativeNV = 5256,\n    DecorationMax = 0x7fffffff,\n};\n\nenum BuiltIn {\n    BuiltInPosition = 0,\n    BuiltInPointSize = 1,\n    BuiltInClipDistance = 3,\n    BuiltInCullDistance = 4,\n    BuiltInVertexId = 5,\n    BuiltInInstanceId = 6,\n    BuiltInPrimitiveId = 7,\n    BuiltInInvocationId = 8,\n    BuiltInLayer = 9,\n    BuiltInViewportIndex = 10,\n    BuiltInTessLevelOuter = 11,\n    BuiltInTessLevelInner = 12,\n    BuiltInTessCoord = 13,\n    BuiltInPatchVertices = 14,\n    BuiltInFragCoord = 15,\n    BuiltInPointCoord = 16,\n    BuiltInFrontFacing = 17,\n    BuiltInSampleId = 18,\n    BuiltInSamplePosition = 19,\n    BuiltInSampleMask = 20,\n    BuiltInFragDepth = 22,\n    BuiltInHelperInvocation = 23,\n    BuiltInNumWorkgroups = 24,\n    BuiltInWorkgroupSize = 25,\n    BuiltInWorkgroupId = 26,\n    BuiltInLocalInvocationId = 27,\n    BuiltInGlobalInvocationId = 28,\n    BuiltInLocalInvocationIndex = 29,\n    BuiltInWorkDim = 30,\n    BuiltInGlobalSize = 31,\n    BuiltInEnqueuedWorkgroupSize = 32,\n    BuiltInGlobalOffset = 33,\n    BuiltInGlobalLinearId = 34,\n    BuiltInSubgroupSize = 36,\n    BuiltInSubgroupMaxSize = 37,\n    BuiltInNumSubgroups = 38,\n    BuiltInNumEnqueuedSubgroups = 39,\n    BuiltInSubgroupId = 40,\n    BuiltInSubgroupLocalInvocationId = 41,\n    BuiltInVertexIndex = 42,\n    BuiltInInstanceIndex = 43,\n    BuiltInSubgroupEqMaskKHR = 4416,\n    BuiltInSubgroupGeMaskKHR = 4417,\n    BuiltInSubgroupGtMaskKHR = 4418,\n    BuiltInSubgroupLeMaskKHR = 4419,\n    BuiltInSubgroupLtMaskKHR = 4420,\n    BuiltInBaseVertex = 4424,\n    BuiltInBaseInstance = 4425,\n    BuiltInDrawIndex = 4426,\n    BuiltInDeviceIndex = 4438,\n    BuiltInViewIndex = 4440,\n    BuiltInViewportMaskNV = 5253,\n    BuiltInSecondaryPositionNV = 5257,\n    BuiltInSecondaryViewportMaskNV = 5258,\n    BuiltInPositionPerViewNV = 5261,\n    BuiltInViewportMaskPerViewNV = 5262,\n    BuiltInMax = 0x7fffffff,\n};\n\nenum SelectionControlShift {\n    SelectionControlFlattenShift = 0,\n    SelectionControlDontFlattenShift = 1,\n    SelectionControlMax = 0x7fffffff,\n};\n\nenum SelectionControlMask {\n    SelectionControlMaskNone = 0,\n    SelectionControlFlattenMask = 0x00000001,\n    SelectionControlDontFlattenMask = 0x00000002,\n};\n\nenum LoopControlShift {\n    LoopControlUnrollShift = 0,\n    LoopControlDontUnrollShift = 1,\n    LoopControlDependencyInfiniteShift = 2,\n    LoopControlDependencyLengthShift = 3,\n    LoopControlMax = 0x7fffffff,\n};\n\nenum LoopControlMask {\n    LoopControlMaskNone = 0,\n    LoopControlUnrollMask = 0x00000001,\n    LoopControlDontUnrollMask = 0x00000002,\n    LoopControlDependencyInfiniteMask = 0x00000004,\n    LoopControlDependencyLengthMask = 0x00000008,\n};\n\nenum FunctionControlShift {\n    FunctionControlInlineShift = 0,\n    FunctionControlDontInlineShift = 1,\n    FunctionControlPureShift = 2,\n    FunctionControlConstShift = 3,\n    FunctionControlMax = 0x7fffffff,\n};\n\nenum FunctionControlMask {\n    FunctionControlMaskNone = 0,\n    FunctionControlInlineMask = 0x00000001,\n    FunctionControlDontInlineMask = 0x00000002,\n    FunctionControlPureMask = 0x00000004,\n    FunctionControlConstMask = 0x00000008,\n};\n\nenum MemorySemanticsShift {\n    MemorySemanticsAcquireShift = 1,\n    MemorySemanticsReleaseShift = 2,\n    MemorySemanticsAcquireReleaseShift = 3,\n    MemorySemanticsSequentiallyConsistentShift = 4,\n    MemorySemanticsUniformMemoryShift = 6,\n    MemorySemanticsSubgroupMemoryShift = 7,\n    MemorySemanticsWorkgroupMemoryShift = 8,\n    MemorySemanticsCrossWorkgroupMemoryShift = 9,\n    MemorySemanticsAtomicCounterMemoryShift = 10,\n    MemorySemanticsImageMemoryShift = 11,\n    MemorySemanticsMax = 0x7fffffff,\n};\n\nenum MemorySemanticsMask {\n    MemorySemanticsMaskNone = 0,\n    MemorySemanticsAcquireMask = 0x00000002,\n    MemorySemanticsReleaseMask = 0x00000004,\n    MemorySemanticsAcquireReleaseMask = 0x00000008,\n    MemorySemanticsSequentiallyConsistentMask = 0x00000010,\n    MemorySemanticsUniformMemoryMask = 0x00000040,\n    MemorySemanticsSubgroupMemoryMask = 0x00000080,\n    MemorySemanticsWorkgroupMemoryMask = 0x00000100,\n    MemorySemanticsCrossWorkgroupMemoryMask = 0x00000200,\n    MemorySemanticsAtomicCounterMemoryMask = 0x00000400,\n    MemorySemanticsImageMemoryMask = 0x00000800,\n};\n\nenum MemoryAccessShift {\n    MemoryAccessVolatileShift = 0,\n    MemoryAccessAlignedShift = 1,\n    MemoryAccessNontemporalShift = 2,\n    MemoryAccessMax = 0x7fffffff,\n};\n\nenum MemoryAccessMask {\n    MemoryAccessMaskNone = 0,\n    MemoryAccessVolatileMask = 0x00000001,\n    MemoryAccessAlignedMask = 0x00000002,\n    MemoryAccessNontemporalMask = 0x00000004,\n};\n\nenum Scope {\n    ScopeCrossDevice = 0,\n    ScopeDevice = 1,\n    ScopeWorkgroup = 2,\n    ScopeSubgroup = 3,\n    ScopeInvocation = 4,\n    ScopeMax = 0x7fffffff,\n};\n\nenum GroupOperation {\n    GroupOperationReduce = 0,\n    GroupOperationInclusiveScan = 1,\n    GroupOperationExclusiveScan = 2,\n    GroupOperationMax = 0x7fffffff,\n};\n\nenum KernelEnqueueFlags {\n    KernelEnqueueFlagsNoWait = 0,\n    KernelEnqueueFlagsWaitKernel = 1,\n    KernelEnqueueFlagsWaitWorkGroup = 2,\n    KernelEnqueueFlagsMax = 0x7fffffff,\n};\n\nenum KernelProfilingInfoShift {\n    KernelProfilingInfoCmdExecTimeShift = 0,\n    KernelProfilingInfoMax = 0x7fffffff,\n};\n\nenum KernelProfilingInfoMask {\n    KernelProfilingInfoMaskNone = 0,\n    KernelProfilingInfoCmdExecTimeMask = 0x00000001,\n};\n\nenum Capability {\n    CapabilityMatrix = 0,\n    CapabilityShader = 1,\n    CapabilityGeometry = 2,\n    CapabilityTessellation = 3,\n    CapabilityAddresses = 4,\n    CapabilityLinkage = 5,\n    CapabilityKernel = 6,\n    CapabilityVector16 = 7,\n    CapabilityFloat16Buffer = 8,\n    CapabilityFloat16 = 9,\n    CapabilityFloat64 = 10,\n    CapabilityInt64 = 11,\n    CapabilityInt64Atomics = 12,\n    CapabilityImageBasic = 13,\n    CapabilityImageReadWrite = 14,\n    CapabilityImageMipmap = 15,\n    CapabilityPipes = 17,\n    CapabilityGroups = 18,\n    CapabilityDeviceEnqueue = 19,\n    CapabilityLiteralSampler = 20,\n    CapabilityAtomicStorage = 21,\n    CapabilityInt16 = 22,\n    CapabilityTessellationPointSize = 23,\n    CapabilityGeometryPointSize = 24,\n    CapabilityImageGatherExtended = 25,\n    CapabilityStorageImageMultisample = 27,\n    CapabilityUniformBufferArrayDynamicIndexing = 28,\n    CapabilitySampledImageArrayDynamicIndexing = 29,\n    CapabilityStorageBufferArrayDynamicIndexing = 30,\n    CapabilityStorageImageArrayDynamicIndexing = 31,\n    CapabilityClipDistance = 32,\n    CapabilityCullDistance = 33,\n    CapabilityImageCubeArray = 34,\n    CapabilitySampleRateShading = 35,\n    CapabilityImageRect = 36,\n    CapabilitySampledRect = 37,\n    CapabilityGenericPointer = 38,\n    CapabilityInt8 = 39,\n    CapabilityInputAttachment = 40,\n    CapabilitySparseResidency = 41,\n    CapabilityMinLod = 42,\n    CapabilitySampled1D = 43,\n    CapabilityImage1D = 44,\n    CapabilitySampledCubeArray = 45,\n    CapabilitySampledBuffer = 46,\n    CapabilityImageBuffer = 47,\n    CapabilityImageMSArray = 48,\n    CapabilityStorageImageExtendedFormats = 49,\n    CapabilityImageQuery = 50,\n    CapabilityDerivativeControl = 51,\n    CapabilityInterpolationFunction = 52,\n    CapabilityTransformFeedback = 53,\n    CapabilityGeometryStreams = 54,\n    CapabilityStorageImageReadWithoutFormat = 55,\n    CapabilityStorageImageWriteWithoutFormat = 56,\n    CapabilityMultiViewport = 57,\n    CapabilitySubgroupDispatch = 58,\n    CapabilityNamedBarrier = 59,\n    CapabilityPipeStorage = 60,\n    CapabilitySubgroupBallotKHR = 4423,\n    CapabilityDrawParameters = 4427,\n    CapabilitySubgroupVoteKHR = 4431,\n    CapabilityStorageBuffer16BitAccess = 4433,\n    CapabilityStorageUniformBufferBlock16 = 4433,\n    CapabilityStorageUniform16 = 4434,\n    CapabilityUniformAndStorageBuffer16BitAccess = 4434,\n    CapabilityStoragePushConstant16 = 4435,\n    CapabilityStorageInputOutput16 = 4436,\n    CapabilityDeviceGroup = 4437,\n    CapabilityMultiView = 4439,\n    CapabilityVariablePointersStorageBuffer = 4441,\n    CapabilityVariablePointers = 4442,\n    CapabilitySampleMaskOverrideCoverageNV = 5249,\n    CapabilityGeometryShaderPassthroughNV = 5251,\n    CapabilityShaderViewportIndexLayerNV = 5254,\n    CapabilityShaderViewportMaskNV = 5255,\n    CapabilityShaderStereoViewNV = 5259,\n    CapabilityPerViewAttributesNV = 5260,\n    CapabilityMax = 0x7fffffff,\n};\n\nenum Op {\n    OpNop = 0,\n    OpUndef = 1,\n    OpSourceContinued = 2,\n    OpSource = 3,\n    OpSourceExtension = 4,\n    OpName = 5,\n    OpMemberName = 6,\n    OpString = 7,\n    OpLine = 8,\n    OpExtension = 10,\n    OpExtInstImport = 11,\n    OpExtInst = 12,\n    OpMemoryModel = 14,\n    OpEntryPoint = 15,\n    OpExecutionMode = 16,\n    OpCapability = 17,\n    OpTypeVoid = 19,\n    OpTypeBool = 20,\n    OpTypeInt = 21,\n    OpTypeFloat = 22,\n    OpTypeVector = 23,\n    OpTypeMatrix = 24,\n    OpTypeImage = 25,\n    OpTypeSampler = 26,\n    OpTypeSampledImage = 27,\n    OpTypeArray = 28,\n    OpTypeRuntimeArray = 29,\n    OpTypeStruct = 30,\n    OpTypeOpaque = 31,\n    OpTypePointer = 32,\n    OpTypeFunction = 33,\n    OpTypeEvent = 34,\n    OpTypeDeviceEvent = 35,\n    OpTypeReserveId = 36,\n    OpTypeQueue = 37,\n    OpTypePipe = 38,\n    OpTypeForwardPointer = 39,\n    OpConstantTrue = 41,\n    OpConstantFalse = 42,\n    OpConstant = 43,\n    OpConstantComposite = 44,\n    OpConstantSampler = 45,\n    OpConstantNull = 46,\n    OpSpecConstantTrue = 48,\n    OpSpecConstantFalse = 49,\n    OpSpecConstant = 50,\n    OpSpecConstantComposite = 51,\n    OpSpecConstantOp = 52,\n    OpFunction = 54,\n    OpFunctionParameter = 55,\n    OpFunctionEnd = 56,\n    OpFunctionCall = 57,\n    OpVariable = 59,\n    OpImageTexelPointer = 60,\n    OpLoad = 61,\n    OpStore = 62,\n    OpCopyMemory = 63,\n    OpCopyMemorySized = 64,\n    OpAccessChain = 65,\n    OpInBoundsAccessChain = 66,\n    OpPtrAccessChain = 67,\n    OpArrayLength = 68,\n    OpGenericPtrMemSemantics = 69,\n    OpInBoundsPtrAccessChain = 70,\n    OpDecorate = 71,\n    OpMemberDecorate = 72,\n    OpDecorationGroup = 73,\n    OpGroupDecorate = 74,\n    OpGroupMemberDecorate = 75,\n    OpVectorExtractDynamic = 77,\n    OpVectorInsertDynamic = 78,\n    OpVectorShuffle = 79,\n    OpCompositeConstruct = 80,\n    OpCompositeExtract = 81,\n    OpCompositeInsert = 82,\n    OpCopyObject = 83,\n    OpTranspose = 84,\n    OpSampledImage = 86,\n    OpImageSampleImplicitLod = 87,\n    OpImageSampleExplicitLod = 88,\n    OpImageSampleDrefImplicitLod = 89,\n    OpImageSampleDrefExplicitLod = 90,\n    OpImageSampleProjImplicitLod = 91,\n    OpImageSampleProjExplicitLod = 92,\n    OpImageSampleProjDrefImplicitLod = 93,\n    OpImageSampleProjDrefExplicitLod = 94,\n    OpImageFetch = 95,\n    OpImageGather = 96,\n    OpImageDrefGather = 97,\n    OpImageRead = 98,\n    OpImageWrite = 99,\n    OpImage = 100,\n    OpImageQueryFormat = 101,\n    OpImageQueryOrder = 102,\n    OpImageQuerySizeLod = 103,\n    OpImageQuerySize = 104,\n    OpImageQueryLod = 105,\n    OpImageQueryLevels = 106,\n    OpImageQuerySamples = 107,\n    OpConvertFToU = 109,\n    OpConvertFToS = 110,\n    OpConvertSToF = 111,\n    OpConvertUToF = 112,\n    OpUConvert = 113,\n    OpSConvert = 114,\n    OpFConvert = 115,\n    OpQuantizeToF16 = 116,\n    OpConvertPtrToU = 117,\n    OpSatConvertSToU = 118,\n    OpSatConvertUToS = 119,\n    OpConvertUToPtr = 120,\n    OpPtrCastToGeneric = 121,\n    OpGenericCastToPtr = 122,\n    OpGenericCastToPtrExplicit = 123,\n    OpBitcast = 124,\n    OpSNegate = 126,\n    OpFNegate = 127,\n    OpIAdd = 128,\n    OpFAdd = 129,\n    OpISub = 130,\n    OpFSub = 131,\n    OpIMul = 132,\n    OpFMul = 133,\n    OpUDiv = 134,\n    OpSDiv = 135,\n    OpFDiv = 136,\n    OpUMod = 137,\n    OpSRem = 138,\n    OpSMod = 139,\n    OpFRem = 140,\n    OpFMod = 141,\n    OpVectorTimesScalar = 142,\n    OpMatrixTimesScalar = 143,\n    OpVectorTimesMatrix = 144,\n    OpMatrixTimesVector = 145,\n    OpMatrixTimesMatrix = 146,\n    OpOuterProduct = 147,\n    OpDot = 148,\n    OpIAddCarry = 149,\n    OpISubBorrow = 150,\n    OpUMulExtended = 151,\n    OpSMulExtended = 152,\n    OpAny = 154,\n    OpAll = 155,\n    OpIsNan = 156,\n    OpIsInf = 157,\n    OpIsFinite = 158,\n    OpIsNormal = 159,\n    OpSignBitSet = 160,\n    OpLessOrGreater = 161,\n    OpOrdered = 162,\n    OpUnordered = 163,\n    OpLogicalEqual = 164,\n    OpLogicalNotEqual = 165,\n    OpLogicalOr = 166,\n    OpLogicalAnd = 167,\n    OpLogicalNot = 168,\n    OpSelect = 169,\n    OpIEqual = 170,\n    OpINotEqual = 171,\n    OpUGreaterThan = 172,\n    OpSGreaterThan = 173,\n    OpUGreaterThanEqual = 174,\n    OpSGreaterThanEqual = 175,\n    OpULessThan = 176,\n    OpSLessThan = 177,\n    OpULessThanEqual = 178,\n    OpSLessThanEqual = 179,\n    OpFOrdEqual = 180,\n    OpFUnordEqual = 181,\n    OpFOrdNotEqual = 182,\n    OpFUnordNotEqual = 183,\n    OpFOrdLessThan = 184,\n    OpFUnordLessThan = 185,\n    OpFOrdGreaterThan = 186,\n    OpFUnordGreaterThan = 187,\n    OpFOrdLessThanEqual = 188,\n    OpFUnordLessThanEqual = 189,\n    OpFOrdGreaterThanEqual = 190,\n    OpFUnordGreaterThanEqual = 191,\n    OpShiftRightLogical = 194,\n    OpShiftRightArithmetic = 195,\n    OpShiftLeftLogical = 196,\n    OpBitwiseOr = 197,\n    OpBitwiseXor = 198,\n    OpBitwiseAnd = 199,\n    OpNot = 200,\n    OpBitFieldInsert = 201,\n    OpBitFieldSExtract = 202,\n    OpBitFieldUExtract = 203,\n    OpBitReverse = 204,\n    OpBitCount = 205,\n    OpDPdx = 207,\n    OpDPdy = 208,\n    OpFwidth = 209,\n    OpDPdxFine = 210,\n    OpDPdyFine = 211,\n    OpFwidthFine = 212,\n    OpDPdxCoarse = 213,\n    OpDPdyCoarse = 214,\n    OpFwidthCoarse = 215,\n    OpEmitVertex = 218,\n    OpEndPrimitive = 219,\n    OpEmitStreamVertex = 220,\n    OpEndStreamPrimitive = 221,\n    OpControlBarrier = 224,\n    OpMemoryBarrier = 225,\n    OpAtomicLoad = 227,\n    OpAtomicStore = 228,\n    OpAtomicExchange = 229,\n    OpAtomicCompareExchange = 230,\n    OpAtomicCompareExchangeWeak = 231,\n    OpAtomicIIncrement = 232,\n    OpAtomicIDecrement = 233,\n    OpAtomicIAdd = 234,\n    OpAtomicISub = 235,\n    OpAtomicSMin = 236,\n    OpAtomicUMin = 237,\n    OpAtomicSMax = 238,\n    OpAtomicUMax = 239,\n    OpAtomicAnd = 240,\n    OpAtomicOr = 241,\n    OpAtomicXor = 242,\n    OpPhi = 245,\n    OpLoopMerge = 246,\n    OpSelectionMerge = 247,\n    OpLabel = 248,\n    OpBranch = 249,\n    OpBranchConditional = 250,\n    OpSwitch = 251,\n    OpKill = 252,\n    OpReturn = 253,\n    OpReturnValue = 254,\n    OpUnreachable = 255,\n    OpLifetimeStart = 256,\n    OpLifetimeStop = 257,\n    OpGroupAsyncCopy = 259,\n    OpGroupWaitEvents = 260,\n    OpGroupAll = 261,\n    OpGroupAny = 262,\n    OpGroupBroadcast = 263,\n    OpGroupIAdd = 264,\n    OpGroupFAdd = 265,\n    OpGroupFMin = 266,\n    OpGroupUMin = 267,\n    OpGroupSMin = 268,\n    OpGroupFMax = 269,\n    OpGroupUMax = 270,\n    OpGroupSMax = 271,\n    OpReadPipe = 274,\n    OpWritePipe = 275,\n    OpReservedReadPipe = 276,\n    OpReservedWritePipe = 277,\n    OpReserveReadPipePackets = 278,\n    OpReserveWritePipePackets = 279,\n    OpCommitReadPipe = 280,\n    OpCommitWritePipe = 281,\n    OpIsValidReserveId = 282,\n    OpGetNumPipePackets = 283,\n    OpGetMaxPipePackets = 284,\n    OpGroupReserveReadPipePackets = 285,\n    OpGroupReserveWritePipePackets = 286,\n    OpGroupCommitReadPipe = 287,\n    OpGroupCommitWritePipe = 288,\n    OpEnqueueMarker = 291,\n    OpEnqueueKernel = 292,\n    OpGetKernelNDrangeSubGroupCount = 293,\n    OpGetKernelNDrangeMaxSubGroupSize = 294,\n    OpGetKernelWorkGroupSize = 295,\n    OpGetKernelPreferredWorkGroupSizeMultiple = 296,\n    OpRetainEvent = 297,\n    OpReleaseEvent = 298,\n    OpCreateUserEvent = 299,\n    OpIsValidEvent = 300,\n    OpSetUserEventStatus = 301,\n    OpCaptureEventProfilingInfo = 302,\n    OpGetDefaultQueue = 303,\n    OpBuildNDRange = 304,\n    OpImageSparseSampleImplicitLod = 305,\n    OpImageSparseSampleExplicitLod = 306,\n    OpImageSparseSampleDrefImplicitLod = 307,\n    OpImageSparseSampleDrefExplicitLod = 308,\n    OpImageSparseSampleProjImplicitLod = 309,\n    OpImageSparseSampleProjExplicitLod = 310,\n    OpImageSparseSampleProjDrefImplicitLod = 311,\n    OpImageSparseSampleProjDrefExplicitLod = 312,\n    OpImageSparseFetch = 313,\n    OpImageSparseGather = 314,\n    OpImageSparseDrefGather = 315,\n    OpImageSparseTexelsResident = 316,\n    OpNoLine = 317,\n    OpAtomicFlagTestAndSet = 318,\n    OpAtomicFlagClear = 319,\n    OpImageSparseRead = 320,\n    OpSizeOf = 321,\n    OpTypePipeStorage = 322,\n    OpConstantPipeStorage = 323,\n    OpCreatePipeFromPipeStorage = 324,\n    OpGetKernelLocalSizeForSubgroupCount = 325,\n    OpGetKernelMaxNumSubgroups = 326,\n    OpTypeNamedBarrier = 327,\n    OpNamedBarrierInitialize = 328,\n    OpMemoryNamedBarrier = 329,\n    OpModuleProcessed = 330,\n    OpSubgroupBallotKHR = 4421,\n    OpSubgroupFirstInvocationKHR = 4422,\n    OpSubgroupAllKHR = 4428,\n    OpSubgroupAnyKHR = 4429,\n    OpSubgroupAllEqualKHR = 4430,\n    OpSubgroupReadInvocationKHR = 4432,\n    OpMax = 0x7fffffff,\n};\n\n// Overload operator| for mask bit combining\n\ninline ImageOperandsMask operator|(ImageOperandsMask a, ImageOperandsMask b) { return ImageOperandsMask(unsigned(a) | unsigned(b)); }\ninline FPFastMathModeMask operator|(FPFastMathModeMask a, FPFastMathModeMask b) { return FPFastMathModeMask(unsigned(a) | unsigned(b)); }\ninline SelectionControlMask operator|(SelectionControlMask a, SelectionControlMask b) { return SelectionControlMask(unsigned(a) | unsigned(b)); }\ninline LoopControlMask operator|(LoopControlMask a, LoopControlMask b) { return LoopControlMask(unsigned(a) | unsigned(b)); }\ninline FunctionControlMask operator|(FunctionControlMask a, FunctionControlMask b) { return FunctionControlMask(unsigned(a) | unsigned(b)); }\ninline MemorySemanticsMask operator|(MemorySemanticsMask a, MemorySemanticsMask b) { return MemorySemanticsMask(unsigned(a) | unsigned(b)); }\ninline MemoryAccessMask operator|(MemoryAccessMask a, MemoryAccessMask b) { return MemoryAccessMask(unsigned(a) | unsigned(b)); }\ninline KernelProfilingInfoMask operator|(KernelProfilingInfoMask a, KernelProfilingInfoMask b) { return KernelProfilingInfoMask(unsigned(a) | unsigned(b)); }\n\n}  // end namespace spv\n\n#endif  // #ifndef spirv_HPP\n\n"
  },
  {
    "path": "src/engine/renderer/vulkan/spirv.hpp11",
    "content": "// Copyright (c) 2014-2017 The Khronos Group Inc.\n// \n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and/or associated documentation files (the \"Materials\"),\n// to deal in the Materials without restriction, including without limitation\n// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n// and/or sell copies of the Materials, and to permit persons to whom the\n// Materials are furnished to do so, subject to the following conditions:\n// \n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Materials.\n// \n// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS\n// STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND\n// HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ \n// \n// THE MATERIALS ARE PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n// FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS\n// IN THE MATERIALS.\n\n// This header is automatically generated by the same tool that creates\n// the Binary Section of the SPIR-V specification.\n\n// Enumeration tokens for SPIR-V, in various styles:\n//   C, C++, C++11, JSON, Lua, Python\n// \n// - C will have tokens with a \"Spv\" prefix, e.g.: SpvSourceLanguageGLSL\n// - C++ will have tokens in the \"spv\" name space, e.g.: spv::SourceLanguageGLSL\n// - C++11 will use enum classes in the spv namespace, e.g.: spv::SourceLanguage::GLSL\n// - Lua will use tables, e.g.: spv.SourceLanguage.GLSL\n// - Python will use dictionaries, e.g.: spv['SourceLanguage']['GLSL']\n// \n// Some tokens act like mask values, which can be OR'd together,\n// while others are mutually exclusive.  The mask-like ones have\n// \"Mask\" in their name, and a parallel enum that has the shift\n// amount (1 << x) for each corresponding enumerant.\n\n#ifndef spirv_HPP\n#define spirv_HPP\n\nnamespace spv {\n\ntypedef unsigned int Id;\n\n#define SPV_VERSION 0x10100\n#define SPV_REVISION 6\n\nstatic const unsigned int MagicNumber = 0x07230203;\nstatic const unsigned int Version = 0x00010100;\nstatic const unsigned int Revision = 6;\nstatic const unsigned int OpCodeMask = 0xffff;\nstatic const unsigned int WordCountShift = 16;\n\nenum class SourceLanguage : unsigned {\n    Unknown = 0,\n    ESSL = 1,\n    GLSL = 2,\n    OpenCL_C = 3,\n    OpenCL_CPP = 4,\n    HLSL = 5,\n    Max = 0x7fffffff,\n};\n\nenum class ExecutionModel : unsigned {\n    Vertex = 0,\n    TessellationControl = 1,\n    TessellationEvaluation = 2,\n    Geometry = 3,\n    Fragment = 4,\n    GLCompute = 5,\n    Kernel = 6,\n    Max = 0x7fffffff,\n};\n\nenum class AddressingModel : unsigned {\n    Logical = 0,\n    Physical32 = 1,\n    Physical64 = 2,\n    Max = 0x7fffffff,\n};\n\nenum class MemoryModel : unsigned {\n    Simple = 0,\n    GLSL450 = 1,\n    OpenCL = 2,\n    Max = 0x7fffffff,\n};\n\nenum class ExecutionMode : unsigned {\n    Invocations = 0,\n    SpacingEqual = 1,\n    SpacingFractionalEven = 2,\n    SpacingFractionalOdd = 3,\n    VertexOrderCw = 4,\n    VertexOrderCcw = 5,\n    PixelCenterInteger = 6,\n    OriginUpperLeft = 7,\n    OriginLowerLeft = 8,\n    EarlyFragmentTests = 9,\n    PointMode = 10,\n    Xfb = 11,\n    DepthReplacing = 12,\n    DepthGreater = 14,\n    DepthLess = 15,\n    DepthUnchanged = 16,\n    LocalSize = 17,\n    LocalSizeHint = 18,\n    InputPoints = 19,\n    InputLines = 20,\n    InputLinesAdjacency = 21,\n    Triangles = 22,\n    InputTrianglesAdjacency = 23,\n    Quads = 24,\n    Isolines = 25,\n    OutputVertices = 26,\n    OutputPoints = 27,\n    OutputLineStrip = 28,\n    OutputTriangleStrip = 29,\n    VecTypeHint = 30,\n    ContractionOff = 31,\n    Initializer = 33,\n    Finalizer = 34,\n    SubgroupSize = 35,\n    SubgroupsPerWorkgroup = 36,\n    Max = 0x7fffffff,\n};\n\nenum class StorageClass : unsigned {\n    UniformConstant = 0,\n    Input = 1,\n    Uniform = 2,\n    Output = 3,\n    Workgroup = 4,\n    CrossWorkgroup = 5,\n    Private = 6,\n    Function = 7,\n    Generic = 8,\n    PushConstant = 9,\n    AtomicCounter = 10,\n    Image = 11,\n    StorageBuffer = 12,\n    Max = 0x7fffffff,\n};\n\nenum class Dim : unsigned {\n    Dim1D = 0,\n    Dim2D = 1,\n    Dim3D = 2,\n    Cube = 3,\n    Rect = 4,\n    Buffer = 5,\n    SubpassData = 6,\n    Max = 0x7fffffff,\n};\n\nenum class SamplerAddressingMode : unsigned {\n    None = 0,\n    ClampToEdge = 1,\n    Clamp = 2,\n    Repeat = 3,\n    RepeatMirrored = 4,\n    Max = 0x7fffffff,\n};\n\nenum class SamplerFilterMode : unsigned {\n    Nearest = 0,\n    Linear = 1,\n    Max = 0x7fffffff,\n};\n\nenum class ImageFormat : unsigned {\n    Unknown = 0,\n    Rgba32f = 1,\n    Rgba16f = 2,\n    R32f = 3,\n    Rgba8 = 4,\n    Rgba8Snorm = 5,\n    Rg32f = 6,\n    Rg16f = 7,\n    R11fG11fB10f = 8,\n    R16f = 9,\n    Rgba16 = 10,\n    Rgb10A2 = 11,\n    Rg16 = 12,\n    Rg8 = 13,\n    R16 = 14,\n    R8 = 15,\n    Rgba16Snorm = 16,\n    Rg16Snorm = 17,\n    Rg8Snorm = 18,\n    R16Snorm = 19,\n    R8Snorm = 20,\n    Rgba32i = 21,\n    Rgba16i = 22,\n    Rgba8i = 23,\n    R32i = 24,\n    Rg32i = 25,\n    Rg16i = 26,\n    Rg8i = 27,\n    R16i = 28,\n    R8i = 29,\n    Rgba32ui = 30,\n    Rgba16ui = 31,\n    Rgba8ui = 32,\n    R32ui = 33,\n    Rgb10a2ui = 34,\n    Rg32ui = 35,\n    Rg16ui = 36,\n    Rg8ui = 37,\n    R16ui = 38,\n    R8ui = 39,\n    Max = 0x7fffffff,\n};\n\nenum class ImageChannelOrder : unsigned {\n    R = 0,\n    A = 1,\n    RG = 2,\n    RA = 3,\n    RGB = 4,\n    RGBA = 5,\n    BGRA = 6,\n    ARGB = 7,\n    Intensity = 8,\n    Luminance = 9,\n    Rx = 10,\n    RGx = 11,\n    RGBx = 12,\n    Depth = 13,\n    DepthStencil = 14,\n    sRGB = 15,\n    sRGBx = 16,\n    sRGBA = 17,\n    sBGRA = 18,\n    ABGR = 19,\n    Max = 0x7fffffff,\n};\n\nenum class ImageChannelDataType : unsigned {\n    SnormInt8 = 0,\n    SnormInt16 = 1,\n    UnormInt8 = 2,\n    UnormInt16 = 3,\n    UnormShort565 = 4,\n    UnormShort555 = 5,\n    UnormInt101010 = 6,\n    SignedInt8 = 7,\n    SignedInt16 = 8,\n    SignedInt32 = 9,\n    UnsignedInt8 = 10,\n    UnsignedInt16 = 11,\n    UnsignedInt32 = 12,\n    HalfFloat = 13,\n    Float = 14,\n    UnormInt24 = 15,\n    UnormInt101010_2 = 16,\n    Max = 0x7fffffff,\n};\n\nenum class ImageOperandsShift : unsigned {\n    Bias = 0,\n    Lod = 1,\n    Grad = 2,\n    ConstOffset = 3,\n    Offset = 4,\n    ConstOffsets = 5,\n    Sample = 6,\n    MinLod = 7,\n    Max = 0x7fffffff,\n};\n\nenum class ImageOperandsMask : unsigned {\n    MaskNone = 0,\n    Bias = 0x00000001,\n    Lod = 0x00000002,\n    Grad = 0x00000004,\n    ConstOffset = 0x00000008,\n    Offset = 0x00000010,\n    ConstOffsets = 0x00000020,\n    Sample = 0x00000040,\n    MinLod = 0x00000080,\n};\n\nenum class FPFastMathModeShift : unsigned {\n    NotNaN = 0,\n    NotInf = 1,\n    NSZ = 2,\n    AllowRecip = 3,\n    Fast = 4,\n    Max = 0x7fffffff,\n};\n\nenum class FPFastMathModeMask : unsigned {\n    MaskNone = 0,\n    NotNaN = 0x00000001,\n    NotInf = 0x00000002,\n    NSZ = 0x00000004,\n    AllowRecip = 0x00000008,\n    Fast = 0x00000010,\n};\n\nenum class FPRoundingMode : unsigned {\n    RTE = 0,\n    RTZ = 1,\n    RTP = 2,\n    RTN = 3,\n    Max = 0x7fffffff,\n};\n\nenum class LinkageType : unsigned {\n    Export = 0,\n    Import = 1,\n    Max = 0x7fffffff,\n};\n\nenum class AccessQualifier : unsigned {\n    ReadOnly = 0,\n    WriteOnly = 1,\n    ReadWrite = 2,\n    Max = 0x7fffffff,\n};\n\nenum class FunctionParameterAttribute : unsigned {\n    Zext = 0,\n    Sext = 1,\n    ByVal = 2,\n    Sret = 3,\n    NoAlias = 4,\n    NoCapture = 5,\n    NoWrite = 6,\n    NoReadWrite = 7,\n    Max = 0x7fffffff,\n};\n\nenum class Decoration : unsigned {\n    RelaxedPrecision = 0,\n    SpecId = 1,\n    Block = 2,\n    BufferBlock = 3,\n    RowMajor = 4,\n    ColMajor = 5,\n    ArrayStride = 6,\n    MatrixStride = 7,\n    GLSLShared = 8,\n    GLSLPacked = 9,\n    CPacked = 10,\n    BuiltIn = 11,\n    NoPerspective = 13,\n    Flat = 14,\n    Patch = 15,\n    Centroid = 16,\n    Sample = 17,\n    Invariant = 18,\n    Restrict = 19,\n    Aliased = 20,\n    Volatile = 21,\n    Constant = 22,\n    Coherent = 23,\n    NonWritable = 24,\n    NonReadable = 25,\n    Uniform = 26,\n    SaturatedConversion = 28,\n    Stream = 29,\n    Location = 30,\n    Component = 31,\n    Index = 32,\n    Binding = 33,\n    DescriptorSet = 34,\n    Offset = 35,\n    XfbBuffer = 36,\n    XfbStride = 37,\n    FuncParamAttr = 38,\n    FPRoundingMode = 39,\n    FPFastMathMode = 40,\n    LinkageAttributes = 41,\n    NoContraction = 42,\n    InputAttachmentIndex = 43,\n    Alignment = 44,\n    MaxByteOffset = 45,\n    OverrideCoverageNV = 5248,\n    PassthroughNV = 5250,\n    ViewportRelativeNV = 5252,\n    SecondaryViewportRelativeNV = 5256,\n    Max = 0x7fffffff,\n};\n\nenum class BuiltIn : unsigned {\n    Position = 0,\n    PointSize = 1,\n    ClipDistance = 3,\n    CullDistance = 4,\n    VertexId = 5,\n    InstanceId = 6,\n    PrimitiveId = 7,\n    InvocationId = 8,\n    Layer = 9,\n    ViewportIndex = 10,\n    TessLevelOuter = 11,\n    TessLevelInner = 12,\n    TessCoord = 13,\n    PatchVertices = 14,\n    FragCoord = 15,\n    PointCoord = 16,\n    FrontFacing = 17,\n    SampleId = 18,\n    SamplePosition = 19,\n    SampleMask = 20,\n    FragDepth = 22,\n    HelperInvocation = 23,\n    NumWorkgroups = 24,\n    WorkgroupSize = 25,\n    WorkgroupId = 26,\n    LocalInvocationId = 27,\n    GlobalInvocationId = 28,\n    LocalInvocationIndex = 29,\n    WorkDim = 30,\n    GlobalSize = 31,\n    EnqueuedWorkgroupSize = 32,\n    GlobalOffset = 33,\n    GlobalLinearId = 34,\n    SubgroupSize = 36,\n    SubgroupMaxSize = 37,\n    NumSubgroups = 38,\n    NumEnqueuedSubgroups = 39,\n    SubgroupId = 40,\n    SubgroupLocalInvocationId = 41,\n    VertexIndex = 42,\n    InstanceIndex = 43,\n    SubgroupEqMaskKHR = 4416,\n    SubgroupGeMaskKHR = 4417,\n    SubgroupGtMaskKHR = 4418,\n    SubgroupLeMaskKHR = 4419,\n    SubgroupLtMaskKHR = 4420,\n    BaseVertex = 4424,\n    BaseInstance = 4425,\n    DrawIndex = 4426,\n    DeviceIndex = 4438,\n    ViewIndex = 4440,\n    ViewportMaskNV = 5253,\n    SecondaryPositionNV = 5257,\n    SecondaryViewportMaskNV = 5258,\n    PositionPerViewNV = 5261,\n    ViewportMaskPerViewNV = 5262,\n    Max = 0x7fffffff,\n};\n\nenum class SelectionControlShift : unsigned {\n    Flatten = 0,\n    DontFlatten = 1,\n    Max = 0x7fffffff,\n};\n\nenum class SelectionControlMask : unsigned {\n    MaskNone = 0,\n    Flatten = 0x00000001,\n    DontFlatten = 0x00000002,\n};\n\nenum class LoopControlShift : unsigned {\n    Unroll = 0,\n    DontUnroll = 1,\n    DependencyInfinite = 2,\n    DependencyLength = 3,\n    Max = 0x7fffffff,\n};\n\nenum class LoopControlMask : unsigned {\n    MaskNone = 0,\n    Unroll = 0x00000001,\n    DontUnroll = 0x00000002,\n    DependencyInfinite = 0x00000004,\n    DependencyLength = 0x00000008,\n};\n\nenum class FunctionControlShift : unsigned {\n    Inline = 0,\n    DontInline = 1,\n    Pure = 2,\n    Const = 3,\n    Max = 0x7fffffff,\n};\n\nenum class FunctionControlMask : unsigned {\n    MaskNone = 0,\n    Inline = 0x00000001,\n    DontInline = 0x00000002,\n    Pure = 0x00000004,\n    Const = 0x00000008,\n};\n\nenum class MemorySemanticsShift : unsigned {\n    Acquire = 1,\n    Release = 2,\n    AcquireRelease = 3,\n    SequentiallyConsistent = 4,\n    UniformMemory = 6,\n    SubgroupMemory = 7,\n    WorkgroupMemory = 8,\n    CrossWorkgroupMemory = 9,\n    AtomicCounterMemory = 10,\n    ImageMemory = 11,\n    Max = 0x7fffffff,\n};\n\nenum class MemorySemanticsMask : unsigned {\n    MaskNone = 0,\n    Acquire = 0x00000002,\n    Release = 0x00000004,\n    AcquireRelease = 0x00000008,\n    SequentiallyConsistent = 0x00000010,\n    UniformMemory = 0x00000040,\n    SubgroupMemory = 0x00000080,\n    WorkgroupMemory = 0x00000100,\n    CrossWorkgroupMemory = 0x00000200,\n    AtomicCounterMemory = 0x00000400,\n    ImageMemory = 0x00000800,\n};\n\nenum class MemoryAccessShift : unsigned {\n    Volatile = 0,\n    Aligned = 1,\n    Nontemporal = 2,\n    Max = 0x7fffffff,\n};\n\nenum class MemoryAccessMask : unsigned {\n    MaskNone = 0,\n    Volatile = 0x00000001,\n    Aligned = 0x00000002,\n    Nontemporal = 0x00000004,\n};\n\nenum class Scope : unsigned {\n    CrossDevice = 0,\n    Device = 1,\n    Workgroup = 2,\n    Subgroup = 3,\n    Invocation = 4,\n    Max = 0x7fffffff,\n};\n\nenum class GroupOperation : unsigned {\n    Reduce = 0,\n    InclusiveScan = 1,\n    ExclusiveScan = 2,\n    Max = 0x7fffffff,\n};\n\nenum class KernelEnqueueFlags : unsigned {\n    NoWait = 0,\n    WaitKernel = 1,\n    WaitWorkGroup = 2,\n    Max = 0x7fffffff,\n};\n\nenum class KernelProfilingInfoShift : unsigned {\n    CmdExecTime = 0,\n    Max = 0x7fffffff,\n};\n\nenum class KernelProfilingInfoMask : unsigned {\n    MaskNone = 0,\n    CmdExecTime = 0x00000001,\n};\n\nenum class Capability : unsigned {\n    Matrix = 0,\n    Shader = 1,\n    Geometry = 2,\n    Tessellation = 3,\n    Addresses = 4,\n    Linkage = 5,\n    Kernel = 6,\n    Vector16 = 7,\n    Float16Buffer = 8,\n    Float16 = 9,\n    Float64 = 10,\n    Int64 = 11,\n    Int64Atomics = 12,\n    ImageBasic = 13,\n    ImageReadWrite = 14,\n    ImageMipmap = 15,\n    Pipes = 17,\n    Groups = 18,\n    DeviceEnqueue = 19,\n    LiteralSampler = 20,\n    AtomicStorage = 21,\n    Int16 = 22,\n    TessellationPointSize = 23,\n    GeometryPointSize = 24,\n    ImageGatherExtended = 25,\n    StorageImageMultisample = 27,\n    UniformBufferArrayDynamicIndexing = 28,\n    SampledImageArrayDynamicIndexing = 29,\n    StorageBufferArrayDynamicIndexing = 30,\n    StorageImageArrayDynamicIndexing = 31,\n    ClipDistance = 32,\n    CullDistance = 33,\n    ImageCubeArray = 34,\n    SampleRateShading = 35,\n    ImageRect = 36,\n    SampledRect = 37,\n    GenericPointer = 38,\n    Int8 = 39,\n    InputAttachment = 40,\n    SparseResidency = 41,\n    MinLod = 42,\n    Sampled1D = 43,\n    Image1D = 44,\n    SampledCubeArray = 45,\n    SampledBuffer = 46,\n    ImageBuffer = 47,\n    ImageMSArray = 48,\n    StorageImageExtendedFormats = 49,\n    ImageQuery = 50,\n    DerivativeControl = 51,\n    InterpolationFunction = 52,\n    TransformFeedback = 53,\n    GeometryStreams = 54,\n    StorageImageReadWithoutFormat = 55,\n    StorageImageWriteWithoutFormat = 56,\n    MultiViewport = 57,\n    SubgroupDispatch = 58,\n    NamedBarrier = 59,\n    PipeStorage = 60,\n    SubgroupBallotKHR = 4423,\n    DrawParameters = 4427,\n    SubgroupVoteKHR = 4431,\n    StorageBuffer16BitAccess = 4433,\n    StorageUniformBufferBlock16 = 4433,\n    StorageUniform16 = 4434,\n    UniformAndStorageBuffer16BitAccess = 4434,\n    StoragePushConstant16 = 4435,\n    StorageInputOutput16 = 4436,\n    DeviceGroup = 4437,\n    MultiView = 4439,\n    VariablePointersStorageBuffer = 4441,\n    VariablePointers = 4442,\n    SampleMaskOverrideCoverageNV = 5249,\n    GeometryShaderPassthroughNV = 5251,\n    ShaderViewportIndexLayerNV = 5254,\n    ShaderViewportMaskNV = 5255,\n    ShaderStereoViewNV = 5259,\n    PerViewAttributesNV = 5260,\n    Max = 0x7fffffff,\n};\n\nenum class Op : unsigned {\n    OpNop = 0,\n    OpUndef = 1,\n    OpSourceContinued = 2,\n    OpSource = 3,\n    OpSourceExtension = 4,\n    OpName = 5,\n    OpMemberName = 6,\n    OpString = 7,\n    OpLine = 8,\n    OpExtension = 10,\n    OpExtInstImport = 11,\n    OpExtInst = 12,\n    OpMemoryModel = 14,\n    OpEntryPoint = 15,\n    OpExecutionMode = 16,\n    OpCapability = 17,\n    OpTypeVoid = 19,\n    OpTypeBool = 20,\n    OpTypeInt = 21,\n    OpTypeFloat = 22,\n    OpTypeVector = 23,\n    OpTypeMatrix = 24,\n    OpTypeImage = 25,\n    OpTypeSampler = 26,\n    OpTypeSampledImage = 27,\n    OpTypeArray = 28,\n    OpTypeRuntimeArray = 29,\n    OpTypeStruct = 30,\n    OpTypeOpaque = 31,\n    OpTypePointer = 32,\n    OpTypeFunction = 33,\n    OpTypeEvent = 34,\n    OpTypeDeviceEvent = 35,\n    OpTypeReserveId = 36,\n    OpTypeQueue = 37,\n    OpTypePipe = 38,\n    OpTypeForwardPointer = 39,\n    OpConstantTrue = 41,\n    OpConstantFalse = 42,\n    OpConstant = 43,\n    OpConstantComposite = 44,\n    OpConstantSampler = 45,\n    OpConstantNull = 46,\n    OpSpecConstantTrue = 48,\n    OpSpecConstantFalse = 49,\n    OpSpecConstant = 50,\n    OpSpecConstantComposite = 51,\n    OpSpecConstantOp = 52,\n    OpFunction = 54,\n    OpFunctionParameter = 55,\n    OpFunctionEnd = 56,\n    OpFunctionCall = 57,\n    OpVariable = 59,\n    OpImageTexelPointer = 60,\n    OpLoad = 61,\n    OpStore = 62,\n    OpCopyMemory = 63,\n    OpCopyMemorySized = 64,\n    OpAccessChain = 65,\n    OpInBoundsAccessChain = 66,\n    OpPtrAccessChain = 67,\n    OpArrayLength = 68,\n    OpGenericPtrMemSemantics = 69,\n    OpInBoundsPtrAccessChain = 70,\n    OpDecorate = 71,\n    OpMemberDecorate = 72,\n    OpDecorationGroup = 73,\n    OpGroupDecorate = 74,\n    OpGroupMemberDecorate = 75,\n    OpVectorExtractDynamic = 77,\n    OpVectorInsertDynamic = 78,\n    OpVectorShuffle = 79,\n    OpCompositeConstruct = 80,\n    OpCompositeExtract = 81,\n    OpCompositeInsert = 82,\n    OpCopyObject = 83,\n    OpTranspose = 84,\n    OpSampledImage = 86,\n    OpImageSampleImplicitLod = 87,\n    OpImageSampleExplicitLod = 88,\n    OpImageSampleDrefImplicitLod = 89,\n    OpImageSampleDrefExplicitLod = 90,\n    OpImageSampleProjImplicitLod = 91,\n    OpImageSampleProjExplicitLod = 92,\n    OpImageSampleProjDrefImplicitLod = 93,\n    OpImageSampleProjDrefExplicitLod = 94,\n    OpImageFetch = 95,\n    OpImageGather = 96,\n    OpImageDrefGather = 97,\n    OpImageRead = 98,\n    OpImageWrite = 99,\n    OpImage = 100,\n    OpImageQueryFormat = 101,\n    OpImageQueryOrder = 102,\n    OpImageQuerySizeLod = 103,\n    OpImageQuerySize = 104,\n    OpImageQueryLod = 105,\n    OpImageQueryLevels = 106,\n    OpImageQuerySamples = 107,\n    OpConvertFToU = 109,\n    OpConvertFToS = 110,\n    OpConvertSToF = 111,\n    OpConvertUToF = 112,\n    OpUConvert = 113,\n    OpSConvert = 114,\n    OpFConvert = 115,\n    OpQuantizeToF16 = 116,\n    OpConvertPtrToU = 117,\n    OpSatConvertSToU = 118,\n    OpSatConvertUToS = 119,\n    OpConvertUToPtr = 120,\n    OpPtrCastToGeneric = 121,\n    OpGenericCastToPtr = 122,\n    OpGenericCastToPtrExplicit = 123,\n    OpBitcast = 124,\n    OpSNegate = 126,\n    OpFNegate = 127,\n    OpIAdd = 128,\n    OpFAdd = 129,\n    OpISub = 130,\n    OpFSub = 131,\n    OpIMul = 132,\n    OpFMul = 133,\n    OpUDiv = 134,\n    OpSDiv = 135,\n    OpFDiv = 136,\n    OpUMod = 137,\n    OpSRem = 138,\n    OpSMod = 139,\n    OpFRem = 140,\n    OpFMod = 141,\n    OpVectorTimesScalar = 142,\n    OpMatrixTimesScalar = 143,\n    OpVectorTimesMatrix = 144,\n    OpMatrixTimesVector = 145,\n    OpMatrixTimesMatrix = 146,\n    OpOuterProduct = 147,\n    OpDot = 148,\n    OpIAddCarry = 149,\n    OpISubBorrow = 150,\n    OpUMulExtended = 151,\n    OpSMulExtended = 152,\n    OpAny = 154,\n    OpAll = 155,\n    OpIsNan = 156,\n    OpIsInf = 157,\n    OpIsFinite = 158,\n    OpIsNormal = 159,\n    OpSignBitSet = 160,\n    OpLessOrGreater = 161,\n    OpOrdered = 162,\n    OpUnordered = 163,\n    OpLogicalEqual = 164,\n    OpLogicalNotEqual = 165,\n    OpLogicalOr = 166,\n    OpLogicalAnd = 167,\n    OpLogicalNot = 168,\n    OpSelect = 169,\n    OpIEqual = 170,\n    OpINotEqual = 171,\n    OpUGreaterThan = 172,\n    OpSGreaterThan = 173,\n    OpUGreaterThanEqual = 174,\n    OpSGreaterThanEqual = 175,\n    OpULessThan = 176,\n    OpSLessThan = 177,\n    OpULessThanEqual = 178,\n    OpSLessThanEqual = 179,\n    OpFOrdEqual = 180,\n    OpFUnordEqual = 181,\n    OpFOrdNotEqual = 182,\n    OpFUnordNotEqual = 183,\n    OpFOrdLessThan = 184,\n    OpFUnordLessThan = 185,\n    OpFOrdGreaterThan = 186,\n    OpFUnordGreaterThan = 187,\n    OpFOrdLessThanEqual = 188,\n    OpFUnordLessThanEqual = 189,\n    OpFOrdGreaterThanEqual = 190,\n    OpFUnordGreaterThanEqual = 191,\n    OpShiftRightLogical = 194,\n    OpShiftRightArithmetic = 195,\n    OpShiftLeftLogical = 196,\n    OpBitwiseOr = 197,\n    OpBitwiseXor = 198,\n    OpBitwiseAnd = 199,\n    OpNot = 200,\n    OpBitFieldInsert = 201,\n    OpBitFieldSExtract = 202,\n    OpBitFieldUExtract = 203,\n    OpBitReverse = 204,\n    OpBitCount = 205,\n    OpDPdx = 207,\n    OpDPdy = 208,\n    OpFwidth = 209,\n    OpDPdxFine = 210,\n    OpDPdyFine = 211,\n    OpFwidthFine = 212,\n    OpDPdxCoarse = 213,\n    OpDPdyCoarse = 214,\n    OpFwidthCoarse = 215,\n    OpEmitVertex = 218,\n    OpEndPrimitive = 219,\n    OpEmitStreamVertex = 220,\n    OpEndStreamPrimitive = 221,\n    OpControlBarrier = 224,\n    OpMemoryBarrier = 225,\n    OpAtomicLoad = 227,\n    OpAtomicStore = 228,\n    OpAtomicExchange = 229,\n    OpAtomicCompareExchange = 230,\n    OpAtomicCompareExchangeWeak = 231,\n    OpAtomicIIncrement = 232,\n    OpAtomicIDecrement = 233,\n    OpAtomicIAdd = 234,\n    OpAtomicISub = 235,\n    OpAtomicSMin = 236,\n    OpAtomicUMin = 237,\n    OpAtomicSMax = 238,\n    OpAtomicUMax = 239,\n    OpAtomicAnd = 240,\n    OpAtomicOr = 241,\n    OpAtomicXor = 242,\n    OpPhi = 245,\n    OpLoopMerge = 246,\n    OpSelectionMerge = 247,\n    OpLabel = 248,\n    OpBranch = 249,\n    OpBranchConditional = 250,\n    OpSwitch = 251,\n    OpKill = 252,\n    OpReturn = 253,\n    OpReturnValue = 254,\n    OpUnreachable = 255,\n    OpLifetimeStart = 256,\n    OpLifetimeStop = 257,\n    OpGroupAsyncCopy = 259,\n    OpGroupWaitEvents = 260,\n    OpGroupAll = 261,\n    OpGroupAny = 262,\n    OpGroupBroadcast = 263,\n    OpGroupIAdd = 264,\n    OpGroupFAdd = 265,\n    OpGroupFMin = 266,\n    OpGroupUMin = 267,\n    OpGroupSMin = 268,\n    OpGroupFMax = 269,\n    OpGroupUMax = 270,\n    OpGroupSMax = 271,\n    OpReadPipe = 274,\n    OpWritePipe = 275,\n    OpReservedReadPipe = 276,\n    OpReservedWritePipe = 277,\n    OpReserveReadPipePackets = 278,\n    OpReserveWritePipePackets = 279,\n    OpCommitReadPipe = 280,\n    OpCommitWritePipe = 281,\n    OpIsValidReserveId = 282,\n    OpGetNumPipePackets = 283,\n    OpGetMaxPipePackets = 284,\n    OpGroupReserveReadPipePackets = 285,\n    OpGroupReserveWritePipePackets = 286,\n    OpGroupCommitReadPipe = 287,\n    OpGroupCommitWritePipe = 288,\n    OpEnqueueMarker = 291,\n    OpEnqueueKernel = 292,\n    OpGetKernelNDrangeSubGroupCount = 293,\n    OpGetKernelNDrangeMaxSubGroupSize = 294,\n    OpGetKernelWorkGroupSize = 295,\n    OpGetKernelPreferredWorkGroupSizeMultiple = 296,\n    OpRetainEvent = 297,\n    OpReleaseEvent = 298,\n    OpCreateUserEvent = 299,\n    OpIsValidEvent = 300,\n    OpSetUserEventStatus = 301,\n    OpCaptureEventProfilingInfo = 302,\n    OpGetDefaultQueue = 303,\n    OpBuildNDRange = 304,\n    OpImageSparseSampleImplicitLod = 305,\n    OpImageSparseSampleExplicitLod = 306,\n    OpImageSparseSampleDrefImplicitLod = 307,\n    OpImageSparseSampleDrefExplicitLod = 308,\n    OpImageSparseSampleProjImplicitLod = 309,\n    OpImageSparseSampleProjExplicitLod = 310,\n    OpImageSparseSampleProjDrefImplicitLod = 311,\n    OpImageSparseSampleProjDrefExplicitLod = 312,\n    OpImageSparseFetch = 313,\n    OpImageSparseGather = 314,\n    OpImageSparseDrefGather = 315,\n    OpImageSparseTexelsResident = 316,\n    OpNoLine = 317,\n    OpAtomicFlagTestAndSet = 318,\n    OpAtomicFlagClear = 319,\n    OpImageSparseRead = 320,\n    OpSizeOf = 321,\n    OpTypePipeStorage = 322,\n    OpConstantPipeStorage = 323,\n    OpCreatePipeFromPipeStorage = 324,\n    OpGetKernelLocalSizeForSubgroupCount = 325,\n    OpGetKernelMaxNumSubgroups = 326,\n    OpTypeNamedBarrier = 327,\n    OpNamedBarrierInitialize = 328,\n    OpMemoryNamedBarrier = 329,\n    OpModuleProcessed = 330,\n    OpSubgroupBallotKHR = 4421,\n    OpSubgroupFirstInvocationKHR = 4422,\n    OpSubgroupAllKHR = 4428,\n    OpSubgroupAnyKHR = 4429,\n    OpSubgroupAllEqualKHR = 4430,\n    OpSubgroupReadInvocationKHR = 4432,\n    Max = 0x7fffffff,\n};\n\n// Overload operator| for mask bit combining\n\ninline ImageOperandsMask operator|(ImageOperandsMask a, ImageOperandsMask b) { return ImageOperandsMask(unsigned(a) | unsigned(b)); }\ninline FPFastMathModeMask operator|(FPFastMathModeMask a, FPFastMathModeMask b) { return FPFastMathModeMask(unsigned(a) | unsigned(b)); }\ninline SelectionControlMask operator|(SelectionControlMask a, SelectionControlMask b) { return SelectionControlMask(unsigned(a) | unsigned(b)); }\ninline LoopControlMask operator|(LoopControlMask a, LoopControlMask b) { return LoopControlMask(unsigned(a) | unsigned(b)); }\ninline FunctionControlMask operator|(FunctionControlMask a, FunctionControlMask b) { return FunctionControlMask(unsigned(a) | unsigned(b)); }\ninline MemorySemanticsMask operator|(MemorySemanticsMask a, MemorySemanticsMask b) { return MemorySemanticsMask(unsigned(a) | unsigned(b)); }\ninline MemoryAccessMask operator|(MemoryAccessMask a, MemoryAccessMask b) { return MemoryAccessMask(unsigned(a) | unsigned(b)); }\ninline KernelProfilingInfoMask operator|(KernelProfilingInfoMask a, KernelProfilingInfoMask b) { return KernelProfilingInfoMask(unsigned(a) | unsigned(b)); }\n\n}  // end namespace spv\n\n#endif  // #ifndef spirv_HPP\n\n"
  },
  {
    "path": "src/engine/renderer/vulkan/spirv.json",
    "content": "{\n    \"spv\":\n    {\n        \"meta\":\n        {\n            \"Comment\":\n            [\n                [\n                    \"Copyright (c) 2014-2017 The Khronos Group Inc.\",\n                    \"\",\n                    \"Permission is hereby granted, free of charge, to any person obtaining a copy\",\n                    \"of this software and/or associated documentation files (the \\\"Materials\\\"),\",\n                    \"to deal in the Materials without restriction, including without limitation\",\n                    \"the rights to use, copy, modify, merge, publish, distribute, sublicense,\",\n                    \"and/or sell copies of the Materials, and to permit persons to whom the\",\n                    \"Materials are furnished to do so, subject to the following conditions:\",\n                    \"\",\n                    \"The above copyright notice and this permission notice shall be included in\",\n                    \"all copies or substantial portions of the Materials.\",\n                    \"\",\n                    \"MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS\",\n                    \"STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND\",\n                    \"HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ \",\n                    \"\",\n                    \"THE MATERIALS ARE PROVIDED \\\"AS IS\\\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\",\n                    \"OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\",\n                    \"FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\",\n                    \"THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\",\n                    \"LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\",\n                    \"FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS\",\n                    \"IN THE MATERIALS.\"\n                ],\n                [\n                    \"This header is automatically generated by the same tool that creates\",\n                    \"the Binary Section of the SPIR-V specification.\"\n                ],\n                [\n                    \"Enumeration tokens for SPIR-V, in various styles:\",\n                    \"  C, C++, C++11, JSON, Lua, Python\",\n                    \"\",\n                    \"- C will have tokens with a \\\"Spv\\\" prefix, e.g.: SpvSourceLanguageGLSL\",\n                    \"- C++ will have tokens in the \\\"spv\\\" name space, e.g.: spv::SourceLanguageGLSL\",\n                    \"- C++11 will use enum classes in the spv namespace, e.g.: spv::SourceLanguage::GLSL\",\n                    \"- Lua will use tables, e.g.: spv.SourceLanguage.GLSL\",\n                    \"- Python will use dictionaries, e.g.: spv['SourceLanguage']['GLSL']\",\n                    \"\",\n                    \"Some tokens act like mask values, which can be OR'd together,\",\n                    \"while others are mutually exclusive.  The mask-like ones have\",\n                    \"\\\"Mask\\\" in their name, and a parallel enum that has the shift\",\n                    \"amount (1 << x) for each corresponding enumerant.\"\n                ]\n            ],\n            \"MagicNumber\": 119734787,\n            \"Version\": 65792,\n            \"Revision\": 6,\n            \"OpCodeMask\": 65535,\n            \"WordCountShift\": 16\n        },\n        \"enum\":\n        [\n            {\n                \"Name\": \"SourceLanguage\",\n                \"Type\": \"Value\",\n                \"Values\":\n                {\n                    \"Unknown\": 0,\n                    \"ESSL\": 1,\n                    \"GLSL\": 2,\n                    \"OpenCL_C\": 3,\n                    \"OpenCL_CPP\": 4,\n                    \"HLSL\": 5\n                }\n            },\n            {\n                \"Name\": \"ExecutionModel\",\n                \"Type\": \"Value\",\n                \"Values\":\n                {\n                    \"Vertex\": 0,\n                    \"TessellationControl\": 1,\n                    \"TessellationEvaluation\": 2,\n                    \"Geometry\": 3,\n                    \"Fragment\": 4,\n                    \"GLCompute\": 5,\n                    \"Kernel\": 6\n                }\n            },\n            {\n                \"Name\": \"AddressingModel\",\n                \"Type\": \"Value\",\n                \"Values\":\n                {\n                    \"Logical\": 0,\n                    \"Physical32\": 1,\n                    \"Physical64\": 2\n                }\n            },\n            {\n                \"Name\": \"MemoryModel\",\n                \"Type\": \"Value\",\n                \"Values\":\n                {\n                    \"Simple\": 0,\n                    \"GLSL450\": 1,\n                    \"OpenCL\": 2\n                }\n            },\n            {\n                \"Name\": \"ExecutionMode\",\n                \"Type\": \"Value\",\n                \"Values\":\n                {\n                    \"Invocations\": 0,\n                    \"SpacingEqual\": 1,\n                    \"SpacingFractionalEven\": 2,\n                    \"SpacingFractionalOdd\": 3,\n                    \"VertexOrderCw\": 4,\n                    \"VertexOrderCcw\": 5,\n                    \"PixelCenterInteger\": 6,\n                    \"OriginUpperLeft\": 7,\n                    \"OriginLowerLeft\": 8,\n                    \"EarlyFragmentTests\": 9,\n                    \"PointMode\": 10,\n                    \"Xfb\": 11,\n                    \"DepthReplacing\": 12,\n                    \"DepthGreater\": 14,\n                    \"DepthLess\": 15,\n                    \"DepthUnchanged\": 16,\n                    \"LocalSize\": 17,\n                    \"LocalSizeHint\": 18,\n                    \"InputPoints\": 19,\n                    \"InputLines\": 20,\n                    \"InputLinesAdjacency\": 21,\n                    \"Triangles\": 22,\n                    \"InputTrianglesAdjacency\": 23,\n                    \"Quads\": 24,\n                    \"Isolines\": 25,\n                    \"OutputVertices\": 26,\n                    \"OutputPoints\": 27,\n                    \"OutputLineStrip\": 28,\n                    \"OutputTriangleStrip\": 29,\n                    \"VecTypeHint\": 30,\n                    \"ContractionOff\": 31,\n                    \"Initializer\": 33,\n                    \"Finalizer\": 34,\n                    \"SubgroupSize\": 35,\n                    \"SubgroupsPerWorkgroup\": 36\n                }\n            },\n            {\n                \"Name\": \"StorageClass\",\n                \"Type\": \"Value\",\n                \"Values\":\n                {\n                    \"UniformConstant\": 0,\n                    \"Input\": 1,\n                    \"Uniform\": 2,\n                    \"Output\": 3,\n                    \"Workgroup\": 4,\n                    \"CrossWorkgroup\": 5,\n                    \"Private\": 6,\n                    \"Function\": 7,\n                    \"Generic\": 8,\n                    \"PushConstant\": 9,\n                    \"AtomicCounter\": 10,\n                    \"Image\": 11,\n                    \"StorageBuffer\": 12\n                }\n            },\n            {\n                \"Name\": \"Dim\",\n                \"Type\": \"Value\",\n                \"Values\":\n                {\n                    \"Dim1D\": 0,\n                    \"Dim2D\": 1,\n                    \"Dim3D\": 2,\n                    \"Cube\": 3,\n                    \"Rect\": 4,\n                    \"Buffer\": 5,\n                    \"SubpassData\": 6\n                }\n            },\n            {\n                \"Name\": \"SamplerAddressingMode\",\n                \"Type\": \"Value\",\n                \"Values\":\n                {\n                    \"None\": 0,\n                    \"ClampToEdge\": 1,\n                    \"Clamp\": 2,\n                    \"Repeat\": 3,\n                    \"RepeatMirrored\": 4\n                }\n            },\n            {\n                \"Name\": \"SamplerFilterMode\",\n                \"Type\": \"Value\",\n                \"Values\":\n                {\n                    \"Nearest\": 0,\n                    \"Linear\": 1\n                }\n            },\n            {\n                \"Name\": \"ImageFormat\",\n                \"Type\": \"Value\",\n                \"Values\":\n                {\n                    \"Unknown\": 0,\n                    \"Rgba32f\": 1,\n                    \"Rgba16f\": 2,\n                    \"R32f\": 3,\n                    \"Rgba8\": 4,\n                    \"Rgba8Snorm\": 5,\n                    \"Rg32f\": 6,\n                    \"Rg16f\": 7,\n                    \"R11fG11fB10f\": 8,\n                    \"R16f\": 9,\n                    \"Rgba16\": 10,\n                    \"Rgb10A2\": 11,\n                    \"Rg16\": 12,\n                    \"Rg8\": 13,\n                    \"R16\": 14,\n                    \"R8\": 15,\n                    \"Rgba16Snorm\": 16,\n                    \"Rg16Snorm\": 17,\n                    \"Rg8Snorm\": 18,\n                    \"R16Snorm\": 19,\n                    \"R8Snorm\": 20,\n                    \"Rgba32i\": 21,\n                    \"Rgba16i\": 22,\n                    \"Rgba8i\": 23,\n                    \"R32i\": 24,\n                    \"Rg32i\": 25,\n                    \"Rg16i\": 26,\n                    \"Rg8i\": 27,\n                    \"R16i\": 28,\n                    \"R8i\": 29,\n                    \"Rgba32ui\": 30,\n                    \"Rgba16ui\": 31,\n                    \"Rgba8ui\": 32,\n                    \"R32ui\": 33,\n                    \"Rgb10a2ui\": 34,\n                    \"Rg32ui\": 35,\n                    \"Rg16ui\": 36,\n                    \"Rg8ui\": 37,\n                    \"R16ui\": 38,\n                    \"R8ui\": 39\n                }\n            },\n            {\n                \"Name\": \"ImageChannelOrder\",\n                \"Type\": \"Value\",\n                \"Values\":\n                {\n                    \"R\": 0,\n                    \"A\": 1,\n                    \"RG\": 2,\n                    \"RA\": 3,\n                    \"RGB\": 4,\n                    \"RGBA\": 5,\n                    \"BGRA\": 6,\n                    \"ARGB\": 7,\n                    \"Intensity\": 8,\n                    \"Luminance\": 9,\n                    \"Rx\": 10,\n                    \"RGx\": 11,\n                    \"RGBx\": 12,\n                    \"Depth\": 13,\n                    \"DepthStencil\": 14,\n                    \"sRGB\": 15,\n                    \"sRGBx\": 16,\n                    \"sRGBA\": 17,\n                    \"sBGRA\": 18,\n                    \"ABGR\": 19\n                }\n            },\n            {\n                \"Name\": \"ImageChannelDataType\",\n                \"Type\": \"Value\",\n                \"Values\":\n                {\n                    \"SnormInt8\": 0,\n                    \"SnormInt16\": 1,\n                    \"UnormInt8\": 2,\n                    \"UnormInt16\": 3,\n                    \"UnormShort565\": 4,\n                    \"UnormShort555\": 5,\n                    \"UnormInt101010\": 6,\n                    \"SignedInt8\": 7,\n                    \"SignedInt16\": 8,\n                    \"SignedInt32\": 9,\n                    \"UnsignedInt8\": 10,\n                    \"UnsignedInt16\": 11,\n                    \"UnsignedInt32\": 12,\n                    \"HalfFloat\": 13,\n                    \"Float\": 14,\n                    \"UnormInt24\": 15,\n                    \"UnormInt101010_2\": 16\n                }\n            },\n            {\n                \"Name\": \"ImageOperands\",\n                \"Type\": \"Bit\",\n                \"Values\":\n                {\n                    \"Bias\": 0,\n                    \"Lod\": 1,\n                    \"Grad\": 2,\n                    \"ConstOffset\": 3,\n                    \"Offset\": 4,\n                    \"ConstOffsets\": 5,\n                    \"Sample\": 6,\n                    \"MinLod\": 7\n                }\n            },\n            {\n                \"Name\": \"FPFastMathMode\",\n                \"Type\": \"Bit\",\n                \"Values\":\n                {\n                    \"NotNaN\": 0,\n                    \"NotInf\": 1,\n                    \"NSZ\": 2,\n                    \"AllowRecip\": 3,\n                    \"Fast\": 4\n                }\n            },\n            {\n                \"Name\": \"FPRoundingMode\",\n                \"Type\": \"Value\",\n                \"Values\":\n                {\n                    \"RTE\": 0,\n                    \"RTZ\": 1,\n                    \"RTP\": 2,\n                    \"RTN\": 3\n                }\n            },\n            {\n                \"Name\": \"LinkageType\",\n                \"Type\": \"Value\",\n                \"Values\":\n                {\n                    \"Export\": 0,\n                    \"Import\": 1\n                }\n            },\n            {\n                \"Name\": \"AccessQualifier\",\n                \"Type\": \"Value\",\n                \"Values\":\n                {\n                    \"ReadOnly\": 0,\n                    \"WriteOnly\": 1,\n                    \"ReadWrite\": 2\n                }\n            },\n            {\n                \"Name\": \"FunctionParameterAttribute\",\n                \"Type\": \"Value\",\n                \"Values\":\n                {\n                    \"Zext\": 0,\n                    \"Sext\": 1,\n                    \"ByVal\": 2,\n                    \"Sret\": 3,\n                    \"NoAlias\": 4,\n                    \"NoCapture\": 5,\n                    \"NoWrite\": 6,\n                    \"NoReadWrite\": 7\n                }\n            },\n            {\n                \"Name\": \"Decoration\",\n                \"Type\": \"Value\",\n                \"Values\":\n                {\n                    \"RelaxedPrecision\": 0,\n                    \"SpecId\": 1,\n                    \"Block\": 2,\n                    \"BufferBlock\": 3,\n                    \"RowMajor\": 4,\n                    \"ColMajor\": 5,\n                    \"ArrayStride\": 6,\n                    \"MatrixStride\": 7,\n                    \"GLSLShared\": 8,\n                    \"GLSLPacked\": 9,\n                    \"CPacked\": 10,\n                    \"BuiltIn\": 11,\n                    \"NoPerspective\": 13,\n                    \"Flat\": 14,\n                    \"Patch\": 15,\n                    \"Centroid\": 16,\n                    \"Sample\": 17,\n                    \"Invariant\": 18,\n                    \"Restrict\": 19,\n                    \"Aliased\": 20,\n                    \"Volatile\": 21,\n                    \"Constant\": 22,\n                    \"Coherent\": 23,\n                    \"NonWritable\": 24,\n                    \"NonReadable\": 25,\n                    \"Uniform\": 26,\n                    \"SaturatedConversion\": 28,\n                    \"Stream\": 29,\n                    \"Location\": 30,\n                    \"Component\": 31,\n                    \"Index\": 32,\n                    \"Binding\": 33,\n                    \"DescriptorSet\": 34,\n                    \"Offset\": 35,\n                    \"XfbBuffer\": 36,\n                    \"XfbStride\": 37,\n                    \"FuncParamAttr\": 38,\n                    \"FPRoundingMode\": 39,\n                    \"FPFastMathMode\": 40,\n                    \"LinkageAttributes\": 41,\n                    \"NoContraction\": 42,\n                    \"InputAttachmentIndex\": 43,\n                    \"Alignment\": 44,\n                    \"MaxByteOffset\": 45,\n                    \"OverrideCoverageNV\": 5248,\n                    \"PassthroughNV\": 5250,\n                    \"ViewportRelativeNV\": 5252,\n                    \"SecondaryViewportRelativeNV\": 5256\n                }\n            },\n            {\n                \"Name\": \"BuiltIn\",\n                \"Type\": \"Value\",\n                \"Values\":\n                {\n                    \"Position\": 0,\n                    \"PointSize\": 1,\n                    \"ClipDistance\": 3,\n                    \"CullDistance\": 4,\n                    \"VertexId\": 5,\n                    \"InstanceId\": 6,\n                    \"PrimitiveId\": 7,\n                    \"InvocationId\": 8,\n                    \"Layer\": 9,\n                    \"ViewportIndex\": 10,\n                    \"TessLevelOuter\": 11,\n                    \"TessLevelInner\": 12,\n                    \"TessCoord\": 13,\n                    \"PatchVertices\": 14,\n                    \"FragCoord\": 15,\n                    \"PointCoord\": 16,\n                    \"FrontFacing\": 17,\n                    \"SampleId\": 18,\n                    \"SamplePosition\": 19,\n                    \"SampleMask\": 20,\n                    \"FragDepth\": 22,\n                    \"HelperInvocation\": 23,\n                    \"NumWorkgroups\": 24,\n                    \"WorkgroupSize\": 25,\n                    \"WorkgroupId\": 26,\n                    \"LocalInvocationId\": 27,\n                    \"GlobalInvocationId\": 28,\n                    \"LocalInvocationIndex\": 29,\n                    \"WorkDim\": 30,\n                    \"GlobalSize\": 31,\n                    \"EnqueuedWorkgroupSize\": 32,\n                    \"GlobalOffset\": 33,\n                    \"GlobalLinearId\": 34,\n                    \"SubgroupSize\": 36,\n                    \"SubgroupMaxSize\": 37,\n                    \"NumSubgroups\": 38,\n                    \"NumEnqueuedSubgroups\": 39,\n                    \"SubgroupId\": 40,\n                    \"SubgroupLocalInvocationId\": 41,\n                    \"VertexIndex\": 42,\n                    \"InstanceIndex\": 43,\n                    \"SubgroupEqMaskKHR\": 4416,\n                    \"SubgroupGeMaskKHR\": 4417,\n                    \"SubgroupGtMaskKHR\": 4418,\n                    \"SubgroupLeMaskKHR\": 4419,\n                    \"SubgroupLtMaskKHR\": 4420,\n                    \"BaseVertex\": 4424,\n                    \"BaseInstance\": 4425,\n                    \"DrawIndex\": 4426,\n                    \"DeviceIndex\": 4438,\n                    \"ViewIndex\": 4440,\n                    \"ViewportMaskNV\": 5253,\n                    \"SecondaryPositionNV\": 5257,\n                    \"SecondaryViewportMaskNV\": 5258,\n                    \"PositionPerViewNV\": 5261,\n                    \"ViewportMaskPerViewNV\": 5262\n                }\n            },\n            {\n                \"Name\": \"SelectionControl\",\n                \"Type\": \"Bit\",\n                \"Values\":\n                {\n                    \"Flatten\": 0,\n                    \"DontFlatten\": 1\n                }\n            },\n            {\n                \"Name\": \"LoopControl\",\n                \"Type\": \"Bit\",\n                \"Values\":\n                {\n                    \"Unroll\": 0,\n                    \"DontUnroll\": 1,\n                    \"DependencyInfinite\": 2,\n                    \"DependencyLength\": 3\n                }\n            },\n            {\n                \"Name\": \"FunctionControl\",\n                \"Type\": \"Bit\",\n                \"Values\":\n                {\n                    \"Inline\": 0,\n                    \"DontInline\": 1,\n                    \"Pure\": 2,\n                    \"Const\": 3\n                }\n            },\n            {\n                \"Name\": \"MemorySemantics\",\n                \"Type\": \"Bit\",\n                \"Values\":\n                {\n                    \"Acquire\": 1,\n                    \"Release\": 2,\n                    \"AcquireRelease\": 3,\n                    \"SequentiallyConsistent\": 4,\n                    \"UniformMemory\": 6,\n                    \"SubgroupMemory\": 7,\n                    \"WorkgroupMemory\": 8,\n                    \"CrossWorkgroupMemory\": 9,\n                    \"AtomicCounterMemory\": 10,\n                    \"ImageMemory\": 11\n                }\n            },\n            {\n                \"Name\": \"MemoryAccess\",\n                \"Type\": \"Bit\",\n                \"Values\":\n                {\n                    \"Volatile\": 0,\n                    \"Aligned\": 1,\n                    \"Nontemporal\": 2\n                }\n            },\n            {\n                \"Name\": \"Scope\",\n                \"Type\": \"Value\",\n                \"Values\":\n                {\n                    \"CrossDevice\": 0,\n                    \"Device\": 1,\n                    \"Workgroup\": 2,\n                    \"Subgroup\": 3,\n                    \"Invocation\": 4\n                }\n            },\n            {\n                \"Name\": \"GroupOperation\",\n                \"Type\": \"Value\",\n                \"Values\":\n                {\n                    \"Reduce\": 0,\n                    \"InclusiveScan\": 1,\n                    \"ExclusiveScan\": 2\n                }\n            },\n            {\n                \"Name\": \"KernelEnqueueFlags\",\n                \"Type\": \"Value\",\n                \"Values\":\n                {\n                    \"NoWait\": 0,\n                    \"WaitKernel\": 1,\n                    \"WaitWorkGroup\": 2\n                }\n            },\n            {\n                \"Name\": \"KernelProfilingInfo\",\n                \"Type\": \"Bit\",\n                \"Values\":\n                {\n                    \"CmdExecTime\": 0\n                }\n            },\n            {\n                \"Name\": \"Capability\",\n                \"Type\": \"Value\",\n                \"Values\":\n                {\n                    \"Matrix\": 0,\n                    \"Shader\": 1,\n                    \"Geometry\": 2,\n                    \"Tessellation\": 3,\n                    \"Addresses\": 4,\n                    \"Linkage\": 5,\n                    \"Kernel\": 6,\n                    \"Vector16\": 7,\n                    \"Float16Buffer\": 8,\n                    \"Float16\": 9,\n                    \"Float64\": 10,\n                    \"Int64\": 11,\n                    \"Int64Atomics\": 12,\n                    \"ImageBasic\": 13,\n                    \"ImageReadWrite\": 14,\n                    \"ImageMipmap\": 15,\n                    \"Pipes\": 17,\n                    \"Groups\": 18,\n                    \"DeviceEnqueue\": 19,\n                    \"LiteralSampler\": 20,\n                    \"AtomicStorage\": 21,\n                    \"Int16\": 22,\n                    \"TessellationPointSize\": 23,\n                    \"GeometryPointSize\": 24,\n                    \"ImageGatherExtended\": 25,\n                    \"StorageImageMultisample\": 27,\n                    \"UniformBufferArrayDynamicIndexing\": 28,\n                    \"SampledImageArrayDynamicIndexing\": 29,\n                    \"StorageBufferArrayDynamicIndexing\": 30,\n                    \"StorageImageArrayDynamicIndexing\": 31,\n                    \"ClipDistance\": 32,\n                    \"CullDistance\": 33,\n                    \"ImageCubeArray\": 34,\n                    \"SampleRateShading\": 35,\n                    \"ImageRect\": 36,\n                    \"SampledRect\": 37,\n                    \"GenericPointer\": 38,\n                    \"Int8\": 39,\n                    \"InputAttachment\": 40,\n                    \"SparseResidency\": 41,\n                    \"MinLod\": 42,\n                    \"Sampled1D\": 43,\n                    \"Image1D\": 44,\n                    \"SampledCubeArray\": 45,\n                    \"SampledBuffer\": 46,\n                    \"ImageBuffer\": 47,\n                    \"ImageMSArray\": 48,\n                    \"StorageImageExtendedFormats\": 49,\n                    \"ImageQuery\": 50,\n                    \"DerivativeControl\": 51,\n                    \"InterpolationFunction\": 52,\n                    \"TransformFeedback\": 53,\n                    \"GeometryStreams\": 54,\n                    \"StorageImageReadWithoutFormat\": 55,\n                    \"StorageImageWriteWithoutFormat\": 56,\n                    \"MultiViewport\": 57,\n                    \"SubgroupDispatch\": 58,\n                    \"NamedBarrier\": 59,\n                    \"PipeStorage\": 60,\n                    \"SubgroupBallotKHR\": 4423,\n                    \"DrawParameters\": 4427,\n                    \"SubgroupVoteKHR\": 4431,\n                    \"StorageBuffer16BitAccess\": 4433,\n                    \"StorageUniformBufferBlock16\": 4433,\n                    \"StorageUniform16\": 4434,\n                    \"UniformAndStorageBuffer16BitAccess\": 4434,\n                    \"StoragePushConstant16\": 4435,\n                    \"StorageInputOutput16\": 4436,\n                    \"DeviceGroup\": 4437,\n                    \"MultiView\": 4439,\n                    \"VariablePointersStorageBuffer\": 4441,\n                    \"VariablePointers\": 4442,\n                    \"SampleMaskOverrideCoverageNV\": 5249,\n                    \"GeometryShaderPassthroughNV\": 5251,\n                    \"ShaderViewportIndexLayerNV\": 5254,\n                    \"ShaderViewportMaskNV\": 5255,\n                    \"ShaderStereoViewNV\": 5259,\n                    \"PerViewAttributesNV\": 5260\n                }\n            },\n            {\n                \"Name\": \"Op\",\n                \"Type\": \"Value\",\n                \"Values\":\n                {\n                    \"OpNop\": 0,\n                    \"OpUndef\": 1,\n                    \"OpSourceContinued\": 2,\n                    \"OpSource\": 3,\n                    \"OpSourceExtension\": 4,\n                    \"OpName\": 5,\n                    \"OpMemberName\": 6,\n                    \"OpString\": 7,\n                    \"OpLine\": 8,\n                    \"OpExtension\": 10,\n                    \"OpExtInstImport\": 11,\n                    \"OpExtInst\": 12,\n                    \"OpMemoryModel\": 14,\n                    \"OpEntryPoint\": 15,\n                    \"OpExecutionMode\": 16,\n                    \"OpCapability\": 17,\n                    \"OpTypeVoid\": 19,\n                    \"OpTypeBool\": 20,\n                    \"OpTypeInt\": 21,\n                    \"OpTypeFloat\": 22,\n                    \"OpTypeVector\": 23,\n                    \"OpTypeMatrix\": 24,\n                    \"OpTypeImage\": 25,\n                    \"OpTypeSampler\": 26,\n                    \"OpTypeSampledImage\": 27,\n                    \"OpTypeArray\": 28,\n                    \"OpTypeRuntimeArray\": 29,\n                    \"OpTypeStruct\": 30,\n                    \"OpTypeOpaque\": 31,\n                    \"OpTypePointer\": 32,\n                    \"OpTypeFunction\": 33,\n                    \"OpTypeEvent\": 34,\n                    \"OpTypeDeviceEvent\": 35,\n                    \"OpTypeReserveId\": 36,\n                    \"OpTypeQueue\": 37,\n                    \"OpTypePipe\": 38,\n                    \"OpTypeForwardPointer\": 39,\n                    \"OpConstantTrue\": 41,\n                    \"OpConstantFalse\": 42,\n                    \"OpConstant\": 43,\n                    \"OpConstantComposite\": 44,\n                    \"OpConstantSampler\": 45,\n                    \"OpConstantNull\": 46,\n                    \"OpSpecConstantTrue\": 48,\n                    \"OpSpecConstantFalse\": 49,\n                    \"OpSpecConstant\": 50,\n                    \"OpSpecConstantComposite\": 51,\n                    \"OpSpecConstantOp\": 52,\n                    \"OpFunction\": 54,\n                    \"OpFunctionParameter\": 55,\n                    \"OpFunctionEnd\": 56,\n                    \"OpFunctionCall\": 57,\n                    \"OpVariable\": 59,\n                    \"OpImageTexelPointer\": 60,\n                    \"OpLoad\": 61,\n                    \"OpStore\": 62,\n                    \"OpCopyMemory\": 63,\n                    \"OpCopyMemorySized\": 64,\n                    \"OpAccessChain\": 65,\n                    \"OpInBoundsAccessChain\": 66,\n                    \"OpPtrAccessChain\": 67,\n                    \"OpArrayLength\": 68,\n                    \"OpGenericPtrMemSemantics\": 69,\n                    \"OpInBoundsPtrAccessChain\": 70,\n                    \"OpDecorate\": 71,\n                    \"OpMemberDecorate\": 72,\n                    \"OpDecorationGroup\": 73,\n                    \"OpGroupDecorate\": 74,\n                    \"OpGroupMemberDecorate\": 75,\n                    \"OpVectorExtractDynamic\": 77,\n                    \"OpVectorInsertDynamic\": 78,\n                    \"OpVectorShuffle\": 79,\n                    \"OpCompositeConstruct\": 80,\n                    \"OpCompositeExtract\": 81,\n                    \"OpCompositeInsert\": 82,\n                    \"OpCopyObject\": 83,\n                    \"OpTranspose\": 84,\n                    \"OpSampledImage\": 86,\n                    \"OpImageSampleImplicitLod\": 87,\n                    \"OpImageSampleExplicitLod\": 88,\n                    \"OpImageSampleDrefImplicitLod\": 89,\n                    \"OpImageSampleDrefExplicitLod\": 90,\n                    \"OpImageSampleProjImplicitLod\": 91,\n                    \"OpImageSampleProjExplicitLod\": 92,\n                    \"OpImageSampleProjDrefImplicitLod\": 93,\n                    \"OpImageSampleProjDrefExplicitLod\": 94,\n                    \"OpImageFetch\": 95,\n                    \"OpImageGather\": 96,\n                    \"OpImageDrefGather\": 97,\n                    \"OpImageRead\": 98,\n                    \"OpImageWrite\": 99,\n                    \"OpImage\": 100,\n                    \"OpImageQueryFormat\": 101,\n                    \"OpImageQueryOrder\": 102,\n                    \"OpImageQuerySizeLod\": 103,\n                    \"OpImageQuerySize\": 104,\n                    \"OpImageQueryLod\": 105,\n                    \"OpImageQueryLevels\": 106,\n                    \"OpImageQuerySamples\": 107,\n                    \"OpConvertFToU\": 109,\n                    \"OpConvertFToS\": 110,\n                    \"OpConvertSToF\": 111,\n                    \"OpConvertUToF\": 112,\n                    \"OpUConvert\": 113,\n                    \"OpSConvert\": 114,\n                    \"OpFConvert\": 115,\n                    \"OpQuantizeToF16\": 116,\n                    \"OpConvertPtrToU\": 117,\n                    \"OpSatConvertSToU\": 118,\n                    \"OpSatConvertUToS\": 119,\n                    \"OpConvertUToPtr\": 120,\n                    \"OpPtrCastToGeneric\": 121,\n                    \"OpGenericCastToPtr\": 122,\n                    \"OpGenericCastToPtrExplicit\": 123,\n                    \"OpBitcast\": 124,\n                    \"OpSNegate\": 126,\n                    \"OpFNegate\": 127,\n                    \"OpIAdd\": 128,\n                    \"OpFAdd\": 129,\n                    \"OpISub\": 130,\n                    \"OpFSub\": 131,\n                    \"OpIMul\": 132,\n                    \"OpFMul\": 133,\n                    \"OpUDiv\": 134,\n                    \"OpSDiv\": 135,\n                    \"OpFDiv\": 136,\n                    \"OpUMod\": 137,\n                    \"OpSRem\": 138,\n                    \"OpSMod\": 139,\n                    \"OpFRem\": 140,\n                    \"OpFMod\": 141,\n                    \"OpVectorTimesScalar\": 142,\n                    \"OpMatrixTimesScalar\": 143,\n                    \"OpVectorTimesMatrix\": 144,\n                    \"OpMatrixTimesVector\": 145,\n                    \"OpMatrixTimesMatrix\": 146,\n                    \"OpOuterProduct\": 147,\n                    \"OpDot\": 148,\n                    \"OpIAddCarry\": 149,\n                    \"OpISubBorrow\": 150,\n                    \"OpUMulExtended\": 151,\n                    \"OpSMulExtended\": 152,\n                    \"OpAny\": 154,\n                    \"OpAll\": 155,\n                    \"OpIsNan\": 156,\n                    \"OpIsInf\": 157,\n                    \"OpIsFinite\": 158,\n                    \"OpIsNormal\": 159,\n                    \"OpSignBitSet\": 160,\n                    \"OpLessOrGreater\": 161,\n                    \"OpOrdered\": 162,\n                    \"OpUnordered\": 163,\n                    \"OpLogicalEqual\": 164,\n                    \"OpLogicalNotEqual\": 165,\n                    \"OpLogicalOr\": 166,\n                    \"OpLogicalAnd\": 167,\n                    \"OpLogicalNot\": 168,\n                    \"OpSelect\": 169,\n                    \"OpIEqual\": 170,\n                    \"OpINotEqual\": 171,\n                    \"OpUGreaterThan\": 172,\n                    \"OpSGreaterThan\": 173,\n                    \"OpUGreaterThanEqual\": 174,\n                    \"OpSGreaterThanEqual\": 175,\n                    \"OpULessThan\": 176,\n                    \"OpSLessThan\": 177,\n                    \"OpULessThanEqual\": 178,\n                    \"OpSLessThanEqual\": 179,\n                    \"OpFOrdEqual\": 180,\n                    \"OpFUnordEqual\": 181,\n                    \"OpFOrdNotEqual\": 182,\n                    \"OpFUnordNotEqual\": 183,\n                    \"OpFOrdLessThan\": 184,\n                    \"OpFUnordLessThan\": 185,\n                    \"OpFOrdGreaterThan\": 186,\n                    \"OpFUnordGreaterThan\": 187,\n                    \"OpFOrdLessThanEqual\": 188,\n                    \"OpFUnordLessThanEqual\": 189,\n                    \"OpFOrdGreaterThanEqual\": 190,\n                    \"OpFUnordGreaterThanEqual\": 191,\n                    \"OpShiftRightLogical\": 194,\n                    \"OpShiftRightArithmetic\": 195,\n                    \"OpShiftLeftLogical\": 196,\n                    \"OpBitwiseOr\": 197,\n                    \"OpBitwiseXor\": 198,\n                    \"OpBitwiseAnd\": 199,\n                    \"OpNot\": 200,\n                    \"OpBitFieldInsert\": 201,\n                    \"OpBitFieldSExtract\": 202,\n                    \"OpBitFieldUExtract\": 203,\n                    \"OpBitReverse\": 204,\n                    \"OpBitCount\": 205,\n                    \"OpDPdx\": 207,\n                    \"OpDPdy\": 208,\n                    \"OpFwidth\": 209,\n                    \"OpDPdxFine\": 210,\n                    \"OpDPdyFine\": 211,\n                    \"OpFwidthFine\": 212,\n                    \"OpDPdxCoarse\": 213,\n                    \"OpDPdyCoarse\": 214,\n                    \"OpFwidthCoarse\": 215,\n                    \"OpEmitVertex\": 218,\n                    \"OpEndPrimitive\": 219,\n                    \"OpEmitStreamVertex\": 220,\n                    \"OpEndStreamPrimitive\": 221,\n                    \"OpControlBarrier\": 224,\n                    \"OpMemoryBarrier\": 225,\n                    \"OpAtomicLoad\": 227,\n                    \"OpAtomicStore\": 228,\n                    \"OpAtomicExchange\": 229,\n                    \"OpAtomicCompareExchange\": 230,\n                    \"OpAtomicCompareExchangeWeak\": 231,\n                    \"OpAtomicIIncrement\": 232,\n                    \"OpAtomicIDecrement\": 233,\n                    \"OpAtomicIAdd\": 234,\n                    \"OpAtomicISub\": 235,\n                    \"OpAtomicSMin\": 236,\n                    \"OpAtomicUMin\": 237,\n                    \"OpAtomicSMax\": 238,\n                    \"OpAtomicUMax\": 239,\n                    \"OpAtomicAnd\": 240,\n                    \"OpAtomicOr\": 241,\n                    \"OpAtomicXor\": 242,\n                    \"OpPhi\": 245,\n                    \"OpLoopMerge\": 246,\n                    \"OpSelectionMerge\": 247,\n                    \"OpLabel\": 248,\n                    \"OpBranch\": 249,\n                    \"OpBranchConditional\": 250,\n                    \"OpSwitch\": 251,\n                    \"OpKill\": 252,\n                    \"OpReturn\": 253,\n                    \"OpReturnValue\": 254,\n                    \"OpUnreachable\": 255,\n                    \"OpLifetimeStart\": 256,\n                    \"OpLifetimeStop\": 257,\n                    \"OpGroupAsyncCopy\": 259,\n                    \"OpGroupWaitEvents\": 260,\n                    \"OpGroupAll\": 261,\n                    \"OpGroupAny\": 262,\n                    \"OpGroupBroadcast\": 263,\n                    \"OpGroupIAdd\": 264,\n                    \"OpGroupFAdd\": 265,\n                    \"OpGroupFMin\": 266,\n                    \"OpGroupUMin\": 267,\n                    \"OpGroupSMin\": 268,\n                    \"OpGroupFMax\": 269,\n                    \"OpGroupUMax\": 270,\n                    \"OpGroupSMax\": 271,\n                    \"OpReadPipe\": 274,\n                    \"OpWritePipe\": 275,\n                    \"OpReservedReadPipe\": 276,\n                    \"OpReservedWritePipe\": 277,\n                    \"OpReserveReadPipePackets\": 278,\n                    \"OpReserveWritePipePackets\": 279,\n                    \"OpCommitReadPipe\": 280,\n                    \"OpCommitWritePipe\": 281,\n                    \"OpIsValidReserveId\": 282,\n                    \"OpGetNumPipePackets\": 283,\n                    \"OpGetMaxPipePackets\": 284,\n                    \"OpGroupReserveReadPipePackets\": 285,\n                    \"OpGroupReserveWritePipePackets\": 286,\n                    \"OpGroupCommitReadPipe\": 287,\n                    \"OpGroupCommitWritePipe\": 288,\n                    \"OpEnqueueMarker\": 291,\n                    \"OpEnqueueKernel\": 292,\n                    \"OpGetKernelNDrangeSubGroupCount\": 293,\n                    \"OpGetKernelNDrangeMaxSubGroupSize\": 294,\n                    \"OpGetKernelWorkGroupSize\": 295,\n                    \"OpGetKernelPreferredWorkGroupSizeMultiple\": 296,\n                    \"OpRetainEvent\": 297,\n                    \"OpReleaseEvent\": 298,\n                    \"OpCreateUserEvent\": 299,\n                    \"OpIsValidEvent\": 300,\n                    \"OpSetUserEventStatus\": 301,\n                    \"OpCaptureEventProfilingInfo\": 302,\n                    \"OpGetDefaultQueue\": 303,\n                    \"OpBuildNDRange\": 304,\n                    \"OpImageSparseSampleImplicitLod\": 305,\n                    \"OpImageSparseSampleExplicitLod\": 306,\n                    \"OpImageSparseSampleDrefImplicitLod\": 307,\n                    \"OpImageSparseSampleDrefExplicitLod\": 308,\n                    \"OpImageSparseSampleProjImplicitLod\": 309,\n                    \"OpImageSparseSampleProjExplicitLod\": 310,\n                    \"OpImageSparseSampleProjDrefImplicitLod\": 311,\n                    \"OpImageSparseSampleProjDrefExplicitLod\": 312,\n                    \"OpImageSparseFetch\": 313,\n                    \"OpImageSparseGather\": 314,\n                    \"OpImageSparseDrefGather\": 315,\n                    \"OpImageSparseTexelsResident\": 316,\n                    \"OpNoLine\": 317,\n                    \"OpAtomicFlagTestAndSet\": 318,\n                    \"OpAtomicFlagClear\": 319,\n                    \"OpImageSparseRead\": 320,\n                    \"OpSizeOf\": 321,\n                    \"OpTypePipeStorage\": 322,\n                    \"OpConstantPipeStorage\": 323,\n                    \"OpCreatePipeFromPipeStorage\": 324,\n                    \"OpGetKernelLocalSizeForSubgroupCount\": 325,\n                    \"OpGetKernelMaxNumSubgroups\": 326,\n                    \"OpTypeNamedBarrier\": 327,\n                    \"OpNamedBarrierInitialize\": 328,\n                    \"OpMemoryNamedBarrier\": 329,\n                    \"OpModuleProcessed\": 330,\n                    \"OpSubgroupBallotKHR\": 4421,\n                    \"OpSubgroupFirstInvocationKHR\": 4422,\n                    \"OpSubgroupAllKHR\": 4428,\n                    \"OpSubgroupAnyKHR\": 4429,\n                    \"OpSubgroupAllEqualKHR\": 4430,\n                    \"OpSubgroupReadInvocationKHR\": 4432\n                }\n            }\n        ]\n    }\n}\n\n"
  },
  {
    "path": "src/engine/renderer/vulkan/spirv.lua",
    "content": "-- Copyright (c) 2014-2017 The Khronos Group Inc.\n-- \n-- Permission is hereby granted, free of charge, to any person obtaining a copy\n-- of this software and/or associated documentation files (the \"Materials\"),\n-- to deal in the Materials without restriction, including without limitation\n-- the rights to use, copy, modify, merge, publish, distribute, sublicense,\n-- and/or sell copies of the Materials, and to permit persons to whom the\n-- Materials are furnished to do so, subject to the following conditions:\n-- \n-- The above copyright notice and this permission notice shall be included in\n-- all copies or substantial portions of the Materials.\n-- \n-- MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS\n-- STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND\n-- HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ \n-- \n-- THE MATERIALS ARE PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n-- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n-- THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n-- FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS\n-- IN THE MATERIALS.\n\n-- This header is automatically generated by the same tool that creates\n-- the Binary Section of the SPIR-V specification.\n\n-- Enumeration tokens for SPIR-V, in various styles:\n--   C, C++, C++11, JSON, Lua, Python\n-- \n-- - C will have tokens with a \"Spv\" prefix, e.g.: SpvSourceLanguageGLSL\n-- - C++ will have tokens in the \"spv\" name space, e.g.: spv::SourceLanguageGLSL\n-- - C++11 will use enum classes in the spv namespace, e.g.: spv::SourceLanguage::GLSL\n-- - Lua will use tables, e.g.: spv.SourceLanguage.GLSL\n-- - Python will use dictionaries, e.g.: spv['SourceLanguage']['GLSL']\n-- \n-- Some tokens act like mask values, which can be OR'd together,\n-- while others are mutually exclusive.  The mask-like ones have\n-- \"Mask\" in their name, and a parallel enum that has the shift\n-- amount (1 << x) for each corresponding enumerant.\n\nspv = {\n    MagicNumber = 0x07230203,\n    Version = 0x00010100,\n    Revision = 6,\n    OpCodeMask = 0xffff,\n    WordCountShift = 16,\n\n    SourceLanguage = {\n        Unknown = 0,\n        ESSL = 1,\n        GLSL = 2,\n        OpenCL_C = 3,\n        OpenCL_CPP = 4,\n        HLSL = 5,\n    },\n\n    ExecutionModel = {\n        Vertex = 0,\n        TessellationControl = 1,\n        TessellationEvaluation = 2,\n        Geometry = 3,\n        Fragment = 4,\n        GLCompute = 5,\n        Kernel = 6,\n    },\n\n    AddressingModel = {\n        Logical = 0,\n        Physical32 = 1,\n        Physical64 = 2,\n    },\n\n    MemoryModel = {\n        Simple = 0,\n        GLSL450 = 1,\n        OpenCL = 2,\n    },\n\n    ExecutionMode = {\n        Invocations = 0,\n        SpacingEqual = 1,\n        SpacingFractionalEven = 2,\n        SpacingFractionalOdd = 3,\n        VertexOrderCw = 4,\n        VertexOrderCcw = 5,\n        PixelCenterInteger = 6,\n        OriginUpperLeft = 7,\n        OriginLowerLeft = 8,\n        EarlyFragmentTests = 9,\n        PointMode = 10,\n        Xfb = 11,\n        DepthReplacing = 12,\n        DepthGreater = 14,\n        DepthLess = 15,\n        DepthUnchanged = 16,\n        LocalSize = 17,\n        LocalSizeHint = 18,\n        InputPoints = 19,\n        InputLines = 20,\n        InputLinesAdjacency = 21,\n        Triangles = 22,\n        InputTrianglesAdjacency = 23,\n        Quads = 24,\n        Isolines = 25,\n        OutputVertices = 26,\n        OutputPoints = 27,\n        OutputLineStrip = 28,\n        OutputTriangleStrip = 29,\n        VecTypeHint = 30,\n        ContractionOff = 31,\n        Initializer = 33,\n        Finalizer = 34,\n        SubgroupSize = 35,\n        SubgroupsPerWorkgroup = 36,\n    },\n\n    StorageClass = {\n        UniformConstant = 0,\n        Input = 1,\n        Uniform = 2,\n        Output = 3,\n        Workgroup = 4,\n        CrossWorkgroup = 5,\n        Private = 6,\n        Function = 7,\n        Generic = 8,\n        PushConstant = 9,\n        AtomicCounter = 10,\n        Image = 11,\n        StorageBuffer = 12,\n    },\n\n    Dim = {\n        Dim1D = 0,\n        Dim2D = 1,\n        Dim3D = 2,\n        Cube = 3,\n        Rect = 4,\n        Buffer = 5,\n        SubpassData = 6,\n    },\n\n    SamplerAddressingMode = {\n        None = 0,\n        ClampToEdge = 1,\n        Clamp = 2,\n        Repeat = 3,\n        RepeatMirrored = 4,\n    },\n\n    SamplerFilterMode = {\n        Nearest = 0,\n        Linear = 1,\n    },\n\n    ImageFormat = {\n        Unknown = 0,\n        Rgba32f = 1,\n        Rgba16f = 2,\n        R32f = 3,\n        Rgba8 = 4,\n        Rgba8Snorm = 5,\n        Rg32f = 6,\n        Rg16f = 7,\n        R11fG11fB10f = 8,\n        R16f = 9,\n        Rgba16 = 10,\n        Rgb10A2 = 11,\n        Rg16 = 12,\n        Rg8 = 13,\n        R16 = 14,\n        R8 = 15,\n        Rgba16Snorm = 16,\n        Rg16Snorm = 17,\n        Rg8Snorm = 18,\n        R16Snorm = 19,\n        R8Snorm = 20,\n        Rgba32i = 21,\n        Rgba16i = 22,\n        Rgba8i = 23,\n        R32i = 24,\n        Rg32i = 25,\n        Rg16i = 26,\n        Rg8i = 27,\n        R16i = 28,\n        R8i = 29,\n        Rgba32ui = 30,\n        Rgba16ui = 31,\n        Rgba8ui = 32,\n        R32ui = 33,\n        Rgb10a2ui = 34,\n        Rg32ui = 35,\n        Rg16ui = 36,\n        Rg8ui = 37,\n        R16ui = 38,\n        R8ui = 39,\n    },\n\n    ImageChannelOrder = {\n        R = 0,\n        A = 1,\n        RG = 2,\n        RA = 3,\n        RGB = 4,\n        RGBA = 5,\n        BGRA = 6,\n        ARGB = 7,\n        Intensity = 8,\n        Luminance = 9,\n        Rx = 10,\n        RGx = 11,\n        RGBx = 12,\n        Depth = 13,\n        DepthStencil = 14,\n        sRGB = 15,\n        sRGBx = 16,\n        sRGBA = 17,\n        sBGRA = 18,\n        ABGR = 19,\n    },\n\n    ImageChannelDataType = {\n        SnormInt8 = 0,\n        SnormInt16 = 1,\n        UnormInt8 = 2,\n        UnormInt16 = 3,\n        UnormShort565 = 4,\n        UnormShort555 = 5,\n        UnormInt101010 = 6,\n        SignedInt8 = 7,\n        SignedInt16 = 8,\n        SignedInt32 = 9,\n        UnsignedInt8 = 10,\n        UnsignedInt16 = 11,\n        UnsignedInt32 = 12,\n        HalfFloat = 13,\n        Float = 14,\n        UnormInt24 = 15,\n        UnormInt101010_2 = 16,\n    },\n\n    ImageOperandsShift = {\n        Bias = 0,\n        Lod = 1,\n        Grad = 2,\n        ConstOffset = 3,\n        Offset = 4,\n        ConstOffsets = 5,\n        Sample = 6,\n        MinLod = 7,\n    },\n\n    ImageOperandsMask = {\n        MaskNone = 0,\n        Bias = 0x00000001,\n        Lod = 0x00000002,\n        Grad = 0x00000004,\n        ConstOffset = 0x00000008,\n        Offset = 0x00000010,\n        ConstOffsets = 0x00000020,\n        Sample = 0x00000040,\n        MinLod = 0x00000080,\n    },\n\n    FPFastMathModeShift = {\n        NotNaN = 0,\n        NotInf = 1,\n        NSZ = 2,\n        AllowRecip = 3,\n        Fast = 4,\n    },\n\n    FPFastMathModeMask = {\n        MaskNone = 0,\n        NotNaN = 0x00000001,\n        NotInf = 0x00000002,\n        NSZ = 0x00000004,\n        AllowRecip = 0x00000008,\n        Fast = 0x00000010,\n    },\n\n    FPRoundingMode = {\n        RTE = 0,\n        RTZ = 1,\n        RTP = 2,\n        RTN = 3,\n    },\n\n    LinkageType = {\n        Export = 0,\n        Import = 1,\n    },\n\n    AccessQualifier = {\n        ReadOnly = 0,\n        WriteOnly = 1,\n        ReadWrite = 2,\n    },\n\n    FunctionParameterAttribute = {\n        Zext = 0,\n        Sext = 1,\n        ByVal = 2,\n        Sret = 3,\n        NoAlias = 4,\n        NoCapture = 5,\n        NoWrite = 6,\n        NoReadWrite = 7,\n    },\n\n    Decoration = {\n        RelaxedPrecision = 0,\n        SpecId = 1,\n        Block = 2,\n        BufferBlock = 3,\n        RowMajor = 4,\n        ColMajor = 5,\n        ArrayStride = 6,\n        MatrixStride = 7,\n        GLSLShared = 8,\n        GLSLPacked = 9,\n        CPacked = 10,\n        BuiltIn = 11,\n        NoPerspective = 13,\n        Flat = 14,\n        Patch = 15,\n        Centroid = 16,\n        Sample = 17,\n        Invariant = 18,\n        Restrict = 19,\n        Aliased = 20,\n        Volatile = 21,\n        Constant = 22,\n        Coherent = 23,\n        NonWritable = 24,\n        NonReadable = 25,\n        Uniform = 26,\n        SaturatedConversion = 28,\n        Stream = 29,\n        Location = 30,\n        Component = 31,\n        Index = 32,\n        Binding = 33,\n        DescriptorSet = 34,\n        Offset = 35,\n        XfbBuffer = 36,\n        XfbStride = 37,\n        FuncParamAttr = 38,\n        FPRoundingMode = 39,\n        FPFastMathMode = 40,\n        LinkageAttributes = 41,\n        NoContraction = 42,\n        InputAttachmentIndex = 43,\n        Alignment = 44,\n        MaxByteOffset = 45,\n        OverrideCoverageNV = 5248,\n        PassthroughNV = 5250,\n        ViewportRelativeNV = 5252,\n        SecondaryViewportRelativeNV = 5256,\n    },\n\n    BuiltIn = {\n        Position = 0,\n        PointSize = 1,\n        ClipDistance = 3,\n        CullDistance = 4,\n        VertexId = 5,\n        InstanceId = 6,\n        PrimitiveId = 7,\n        InvocationId = 8,\n        Layer = 9,\n        ViewportIndex = 10,\n        TessLevelOuter = 11,\n        TessLevelInner = 12,\n        TessCoord = 13,\n        PatchVertices = 14,\n        FragCoord = 15,\n        PointCoord = 16,\n        FrontFacing = 17,\n        SampleId = 18,\n        SamplePosition = 19,\n        SampleMask = 20,\n        FragDepth = 22,\n        HelperInvocation = 23,\n        NumWorkgroups = 24,\n        WorkgroupSize = 25,\n        WorkgroupId = 26,\n        LocalInvocationId = 27,\n        GlobalInvocationId = 28,\n        LocalInvocationIndex = 29,\n        WorkDim = 30,\n        GlobalSize = 31,\n        EnqueuedWorkgroupSize = 32,\n        GlobalOffset = 33,\n        GlobalLinearId = 34,\n        SubgroupSize = 36,\n        SubgroupMaxSize = 37,\n        NumSubgroups = 38,\n        NumEnqueuedSubgroups = 39,\n        SubgroupId = 40,\n        SubgroupLocalInvocationId = 41,\n        VertexIndex = 42,\n        InstanceIndex = 43,\n        SubgroupEqMaskKHR = 4416,\n        SubgroupGeMaskKHR = 4417,\n        SubgroupGtMaskKHR = 4418,\n        SubgroupLeMaskKHR = 4419,\n        SubgroupLtMaskKHR = 4420,\n        BaseVertex = 4424,\n        BaseInstance = 4425,\n        DrawIndex = 4426,\n        DeviceIndex = 4438,\n        ViewIndex = 4440,\n        ViewportMaskNV = 5253,\n        SecondaryPositionNV = 5257,\n        SecondaryViewportMaskNV = 5258,\n        PositionPerViewNV = 5261,\n        ViewportMaskPerViewNV = 5262,\n    },\n\n    SelectionControlShift = {\n        Flatten = 0,\n        DontFlatten = 1,\n    },\n\n    SelectionControlMask = {\n        MaskNone = 0,\n        Flatten = 0x00000001,\n        DontFlatten = 0x00000002,\n    },\n\n    LoopControlShift = {\n        Unroll = 0,\n        DontUnroll = 1,\n        DependencyInfinite = 2,\n        DependencyLength = 3,\n    },\n\n    LoopControlMask = {\n        MaskNone = 0,\n        Unroll = 0x00000001,\n        DontUnroll = 0x00000002,\n        DependencyInfinite = 0x00000004,\n        DependencyLength = 0x00000008,\n    },\n\n    FunctionControlShift = {\n        Inline = 0,\n        DontInline = 1,\n        Pure = 2,\n        Const = 3,\n    },\n\n    FunctionControlMask = {\n        MaskNone = 0,\n        Inline = 0x00000001,\n        DontInline = 0x00000002,\n        Pure = 0x00000004,\n        Const = 0x00000008,\n    },\n\n    MemorySemanticsShift = {\n        Acquire = 1,\n        Release = 2,\n        AcquireRelease = 3,\n        SequentiallyConsistent = 4,\n        UniformMemory = 6,\n        SubgroupMemory = 7,\n        WorkgroupMemory = 8,\n        CrossWorkgroupMemory = 9,\n        AtomicCounterMemory = 10,\n        ImageMemory = 11,\n    },\n\n    MemorySemanticsMask = {\n        MaskNone = 0,\n        Acquire = 0x00000002,\n        Release = 0x00000004,\n        AcquireRelease = 0x00000008,\n        SequentiallyConsistent = 0x00000010,\n        UniformMemory = 0x00000040,\n        SubgroupMemory = 0x00000080,\n        WorkgroupMemory = 0x00000100,\n        CrossWorkgroupMemory = 0x00000200,\n        AtomicCounterMemory = 0x00000400,\n        ImageMemory = 0x00000800,\n    },\n\n    MemoryAccessShift = {\n        Volatile = 0,\n        Aligned = 1,\n        Nontemporal = 2,\n    },\n\n    MemoryAccessMask = {\n        MaskNone = 0,\n        Volatile = 0x00000001,\n        Aligned = 0x00000002,\n        Nontemporal = 0x00000004,\n    },\n\n    Scope = {\n        CrossDevice = 0,\n        Device = 1,\n        Workgroup = 2,\n        Subgroup = 3,\n        Invocation = 4,\n    },\n\n    GroupOperation = {\n        Reduce = 0,\n        InclusiveScan = 1,\n        ExclusiveScan = 2,\n    },\n\n    KernelEnqueueFlags = {\n        NoWait = 0,\n        WaitKernel = 1,\n        WaitWorkGroup = 2,\n    },\n\n    KernelProfilingInfoShift = {\n        CmdExecTime = 0,\n    },\n\n    KernelProfilingInfoMask = {\n        MaskNone = 0,\n        CmdExecTime = 0x00000001,\n    },\n\n    Capability = {\n        Matrix = 0,\n        Shader = 1,\n        Geometry = 2,\n        Tessellation = 3,\n        Addresses = 4,\n        Linkage = 5,\n        Kernel = 6,\n        Vector16 = 7,\n        Float16Buffer = 8,\n        Float16 = 9,\n        Float64 = 10,\n        Int64 = 11,\n        Int64Atomics = 12,\n        ImageBasic = 13,\n        ImageReadWrite = 14,\n        ImageMipmap = 15,\n        Pipes = 17,\n        Groups = 18,\n        DeviceEnqueue = 19,\n        LiteralSampler = 20,\n        AtomicStorage = 21,\n        Int16 = 22,\n        TessellationPointSize = 23,\n        GeometryPointSize = 24,\n        ImageGatherExtended = 25,\n        StorageImageMultisample = 27,\n        UniformBufferArrayDynamicIndexing = 28,\n        SampledImageArrayDynamicIndexing = 29,\n        StorageBufferArrayDynamicIndexing = 30,\n        StorageImageArrayDynamicIndexing = 31,\n        ClipDistance = 32,\n        CullDistance = 33,\n        ImageCubeArray = 34,\n        SampleRateShading = 35,\n        ImageRect = 36,\n        SampledRect = 37,\n        GenericPointer = 38,\n        Int8 = 39,\n        InputAttachment = 40,\n        SparseResidency = 41,\n        MinLod = 42,\n        Sampled1D = 43,\n        Image1D = 44,\n        SampledCubeArray = 45,\n        SampledBuffer = 46,\n        ImageBuffer = 47,\n        ImageMSArray = 48,\n        StorageImageExtendedFormats = 49,\n        ImageQuery = 50,\n        DerivativeControl = 51,\n        InterpolationFunction = 52,\n        TransformFeedback = 53,\n        GeometryStreams = 54,\n        StorageImageReadWithoutFormat = 55,\n        StorageImageWriteWithoutFormat = 56,\n        MultiViewport = 57,\n        SubgroupDispatch = 58,\n        NamedBarrier = 59,\n        PipeStorage = 60,\n        SubgroupBallotKHR = 4423,\n        DrawParameters = 4427,\n        SubgroupVoteKHR = 4431,\n        StorageBuffer16BitAccess = 4433,\n        StorageUniformBufferBlock16 = 4433,\n        StorageUniform16 = 4434,\n        UniformAndStorageBuffer16BitAccess = 4434,\n        StoragePushConstant16 = 4435,\n        StorageInputOutput16 = 4436,\n        DeviceGroup = 4437,\n        MultiView = 4439,\n        VariablePointersStorageBuffer = 4441,\n        VariablePointers = 4442,\n        SampleMaskOverrideCoverageNV = 5249,\n        GeometryShaderPassthroughNV = 5251,\n        ShaderViewportIndexLayerNV = 5254,\n        ShaderViewportMaskNV = 5255,\n        ShaderStereoViewNV = 5259,\n        PerViewAttributesNV = 5260,\n    },\n\n    Op = {\n        OpNop = 0,\n        OpUndef = 1,\n        OpSourceContinued = 2,\n        OpSource = 3,\n        OpSourceExtension = 4,\n        OpName = 5,\n        OpMemberName = 6,\n        OpString = 7,\n        OpLine = 8,\n        OpExtension = 10,\n        OpExtInstImport = 11,\n        OpExtInst = 12,\n        OpMemoryModel = 14,\n        OpEntryPoint = 15,\n        OpExecutionMode = 16,\n        OpCapability = 17,\n        OpTypeVoid = 19,\n        OpTypeBool = 20,\n        OpTypeInt = 21,\n        OpTypeFloat = 22,\n        OpTypeVector = 23,\n        OpTypeMatrix = 24,\n        OpTypeImage = 25,\n        OpTypeSampler = 26,\n        OpTypeSampledImage = 27,\n        OpTypeArray = 28,\n        OpTypeRuntimeArray = 29,\n        OpTypeStruct = 30,\n        OpTypeOpaque = 31,\n        OpTypePointer = 32,\n        OpTypeFunction = 33,\n        OpTypeEvent = 34,\n        OpTypeDeviceEvent = 35,\n        OpTypeReserveId = 36,\n        OpTypeQueue = 37,\n        OpTypePipe = 38,\n        OpTypeForwardPointer = 39,\n        OpConstantTrue = 41,\n        OpConstantFalse = 42,\n        OpConstant = 43,\n        OpConstantComposite = 44,\n        OpConstantSampler = 45,\n        OpConstantNull = 46,\n        OpSpecConstantTrue = 48,\n        OpSpecConstantFalse = 49,\n        OpSpecConstant = 50,\n        OpSpecConstantComposite = 51,\n        OpSpecConstantOp = 52,\n        OpFunction = 54,\n        OpFunctionParameter = 55,\n        OpFunctionEnd = 56,\n        OpFunctionCall = 57,\n        OpVariable = 59,\n        OpImageTexelPointer = 60,\n        OpLoad = 61,\n        OpStore = 62,\n        OpCopyMemory = 63,\n        OpCopyMemorySized = 64,\n        OpAccessChain = 65,\n        OpInBoundsAccessChain = 66,\n        OpPtrAccessChain = 67,\n        OpArrayLength = 68,\n        OpGenericPtrMemSemantics = 69,\n        OpInBoundsPtrAccessChain = 70,\n        OpDecorate = 71,\n        OpMemberDecorate = 72,\n        OpDecorationGroup = 73,\n        OpGroupDecorate = 74,\n        OpGroupMemberDecorate = 75,\n        OpVectorExtractDynamic = 77,\n        OpVectorInsertDynamic = 78,\n        OpVectorShuffle = 79,\n        OpCompositeConstruct = 80,\n        OpCompositeExtract = 81,\n        OpCompositeInsert = 82,\n        OpCopyObject = 83,\n        OpTranspose = 84,\n        OpSampledImage = 86,\n        OpImageSampleImplicitLod = 87,\n        OpImageSampleExplicitLod = 88,\n        OpImageSampleDrefImplicitLod = 89,\n        OpImageSampleDrefExplicitLod = 90,\n        OpImageSampleProjImplicitLod = 91,\n        OpImageSampleProjExplicitLod = 92,\n        OpImageSampleProjDrefImplicitLod = 93,\n        OpImageSampleProjDrefExplicitLod = 94,\n        OpImageFetch = 95,\n        OpImageGather = 96,\n        OpImageDrefGather = 97,\n        OpImageRead = 98,\n        OpImageWrite = 99,\n        OpImage = 100,\n        OpImageQueryFormat = 101,\n        OpImageQueryOrder = 102,\n        OpImageQuerySizeLod = 103,\n        OpImageQuerySize = 104,\n        OpImageQueryLod = 105,\n        OpImageQueryLevels = 106,\n        OpImageQuerySamples = 107,\n        OpConvertFToU = 109,\n        OpConvertFToS = 110,\n        OpConvertSToF = 111,\n        OpConvertUToF = 112,\n        OpUConvert = 113,\n        OpSConvert = 114,\n        OpFConvert = 115,\n        OpQuantizeToF16 = 116,\n        OpConvertPtrToU = 117,\n        OpSatConvertSToU = 118,\n        OpSatConvertUToS = 119,\n        OpConvertUToPtr = 120,\n        OpPtrCastToGeneric = 121,\n        OpGenericCastToPtr = 122,\n        OpGenericCastToPtrExplicit = 123,\n        OpBitcast = 124,\n        OpSNegate = 126,\n        OpFNegate = 127,\n        OpIAdd = 128,\n        OpFAdd = 129,\n        OpISub = 130,\n        OpFSub = 131,\n        OpIMul = 132,\n        OpFMul = 133,\n        OpUDiv = 134,\n        OpSDiv = 135,\n        OpFDiv = 136,\n        OpUMod = 137,\n        OpSRem = 138,\n        OpSMod = 139,\n        OpFRem = 140,\n        OpFMod = 141,\n        OpVectorTimesScalar = 142,\n        OpMatrixTimesScalar = 143,\n        OpVectorTimesMatrix = 144,\n        OpMatrixTimesVector = 145,\n        OpMatrixTimesMatrix = 146,\n        OpOuterProduct = 147,\n        OpDot = 148,\n        OpIAddCarry = 149,\n        OpISubBorrow = 150,\n        OpUMulExtended = 151,\n        OpSMulExtended = 152,\n        OpAny = 154,\n        OpAll = 155,\n        OpIsNan = 156,\n        OpIsInf = 157,\n        OpIsFinite = 158,\n        OpIsNormal = 159,\n        OpSignBitSet = 160,\n        OpLessOrGreater = 161,\n        OpOrdered = 162,\n        OpUnordered = 163,\n        OpLogicalEqual = 164,\n        OpLogicalNotEqual = 165,\n        OpLogicalOr = 166,\n        OpLogicalAnd = 167,\n        OpLogicalNot = 168,\n        OpSelect = 169,\n        OpIEqual = 170,\n        OpINotEqual = 171,\n        OpUGreaterThan = 172,\n        OpSGreaterThan = 173,\n        OpUGreaterThanEqual = 174,\n        OpSGreaterThanEqual = 175,\n        OpULessThan = 176,\n        OpSLessThan = 177,\n        OpULessThanEqual = 178,\n        OpSLessThanEqual = 179,\n        OpFOrdEqual = 180,\n        OpFUnordEqual = 181,\n        OpFOrdNotEqual = 182,\n        OpFUnordNotEqual = 183,\n        OpFOrdLessThan = 184,\n        OpFUnordLessThan = 185,\n        OpFOrdGreaterThan = 186,\n        OpFUnordGreaterThan = 187,\n        OpFOrdLessThanEqual = 188,\n        OpFUnordLessThanEqual = 189,\n        OpFOrdGreaterThanEqual = 190,\n        OpFUnordGreaterThanEqual = 191,\n        OpShiftRightLogical = 194,\n        OpShiftRightArithmetic = 195,\n        OpShiftLeftLogical = 196,\n        OpBitwiseOr = 197,\n        OpBitwiseXor = 198,\n        OpBitwiseAnd = 199,\n        OpNot = 200,\n        OpBitFieldInsert = 201,\n        OpBitFieldSExtract = 202,\n        OpBitFieldUExtract = 203,\n        OpBitReverse = 204,\n        OpBitCount = 205,\n        OpDPdx = 207,\n        OpDPdy = 208,\n        OpFwidth = 209,\n        OpDPdxFine = 210,\n        OpDPdyFine = 211,\n        OpFwidthFine = 212,\n        OpDPdxCoarse = 213,\n        OpDPdyCoarse = 214,\n        OpFwidthCoarse = 215,\n        OpEmitVertex = 218,\n        OpEndPrimitive = 219,\n        OpEmitStreamVertex = 220,\n        OpEndStreamPrimitive = 221,\n        OpControlBarrier = 224,\n        OpMemoryBarrier = 225,\n        OpAtomicLoad = 227,\n        OpAtomicStore = 228,\n        OpAtomicExchange = 229,\n        OpAtomicCompareExchange = 230,\n        OpAtomicCompareExchangeWeak = 231,\n        OpAtomicIIncrement = 232,\n        OpAtomicIDecrement = 233,\n        OpAtomicIAdd = 234,\n        OpAtomicISub = 235,\n        OpAtomicSMin = 236,\n        OpAtomicUMin = 237,\n        OpAtomicSMax = 238,\n        OpAtomicUMax = 239,\n        OpAtomicAnd = 240,\n        OpAtomicOr = 241,\n        OpAtomicXor = 242,\n        OpPhi = 245,\n        OpLoopMerge = 246,\n        OpSelectionMerge = 247,\n        OpLabel = 248,\n        OpBranch = 249,\n        OpBranchConditional = 250,\n        OpSwitch = 251,\n        OpKill = 252,\n        OpReturn = 253,\n        OpReturnValue = 254,\n        OpUnreachable = 255,\n        OpLifetimeStart = 256,\n        OpLifetimeStop = 257,\n        OpGroupAsyncCopy = 259,\n        OpGroupWaitEvents = 260,\n        OpGroupAll = 261,\n        OpGroupAny = 262,\n        OpGroupBroadcast = 263,\n        OpGroupIAdd = 264,\n        OpGroupFAdd = 265,\n        OpGroupFMin = 266,\n        OpGroupUMin = 267,\n        OpGroupSMin = 268,\n        OpGroupFMax = 269,\n        OpGroupUMax = 270,\n        OpGroupSMax = 271,\n        OpReadPipe = 274,\n        OpWritePipe = 275,\n        OpReservedReadPipe = 276,\n        OpReservedWritePipe = 277,\n        OpReserveReadPipePackets = 278,\n        OpReserveWritePipePackets = 279,\n        OpCommitReadPipe = 280,\n        OpCommitWritePipe = 281,\n        OpIsValidReserveId = 282,\n        OpGetNumPipePackets = 283,\n        OpGetMaxPipePackets = 284,\n        OpGroupReserveReadPipePackets = 285,\n        OpGroupReserveWritePipePackets = 286,\n        OpGroupCommitReadPipe = 287,\n        OpGroupCommitWritePipe = 288,\n        OpEnqueueMarker = 291,\n        OpEnqueueKernel = 292,\n        OpGetKernelNDrangeSubGroupCount = 293,\n        OpGetKernelNDrangeMaxSubGroupSize = 294,\n        OpGetKernelWorkGroupSize = 295,\n        OpGetKernelPreferredWorkGroupSizeMultiple = 296,\n        OpRetainEvent = 297,\n        OpReleaseEvent = 298,\n        OpCreateUserEvent = 299,\n        OpIsValidEvent = 300,\n        OpSetUserEventStatus = 301,\n        OpCaptureEventProfilingInfo = 302,\n        OpGetDefaultQueue = 303,\n        OpBuildNDRange = 304,\n        OpImageSparseSampleImplicitLod = 305,\n        OpImageSparseSampleExplicitLod = 306,\n        OpImageSparseSampleDrefImplicitLod = 307,\n        OpImageSparseSampleDrefExplicitLod = 308,\n        OpImageSparseSampleProjImplicitLod = 309,\n        OpImageSparseSampleProjExplicitLod = 310,\n        OpImageSparseSampleProjDrefImplicitLod = 311,\n        OpImageSparseSampleProjDrefExplicitLod = 312,\n        OpImageSparseFetch = 313,\n        OpImageSparseGather = 314,\n        OpImageSparseDrefGather = 315,\n        OpImageSparseTexelsResident = 316,\n        OpNoLine = 317,\n        OpAtomicFlagTestAndSet = 318,\n        OpAtomicFlagClear = 319,\n        OpImageSparseRead = 320,\n        OpSizeOf = 321,\n        OpTypePipeStorage = 322,\n        OpConstantPipeStorage = 323,\n        OpCreatePipeFromPipeStorage = 324,\n        OpGetKernelLocalSizeForSubgroupCount = 325,\n        OpGetKernelMaxNumSubgroups = 326,\n        OpTypeNamedBarrier = 327,\n        OpNamedBarrierInitialize = 328,\n        OpMemoryNamedBarrier = 329,\n        OpModuleProcessed = 330,\n        OpSubgroupBallotKHR = 4421,\n        OpSubgroupFirstInvocationKHR = 4422,\n        OpSubgroupAllKHR = 4428,\n        OpSubgroupAnyKHR = 4429,\n        OpSubgroupAllEqualKHR = 4430,\n        OpSubgroupReadInvocationKHR = 4432,\n    },\n\n}\n\n"
  },
  {
    "path": "src/engine/renderer/vulkan/spirv.py",
    "content": "# Copyright (c) 2014-2017 The Khronos Group Inc.\n# \n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and/or associated documentation files (the \"Materials\"),\n# to deal in the Materials without restriction, including without limitation\n# the rights to use, copy, modify, merge, publish, distribute, sublicense,\n# and/or sell copies of the Materials, and to permit persons to whom the\n# Materials are furnished to do so, subject to the following conditions:\n# \n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Materials.\n# \n# MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS\n# STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND\n# HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ \n# \n# THE MATERIALS ARE PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n# FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS\n# IN THE MATERIALS.\n\n# This header is automatically generated by the same tool that creates\n# the Binary Section of the SPIR-V specification.\n\n# Enumeration tokens for SPIR-V, in various styles:\n#   C, C++, C++11, JSON, Lua, Python\n# \n# - C will have tokens with a \"Spv\" prefix, e.g.: SpvSourceLanguageGLSL\n# - C++ will have tokens in the \"spv\" name space, e.g.: spv::SourceLanguageGLSL\n# - C++11 will use enum classes in the spv namespace, e.g.: spv::SourceLanguage::GLSL\n# - Lua will use tables, e.g.: spv.SourceLanguage.GLSL\n# - Python will use dictionaries, e.g.: spv['SourceLanguage']['GLSL']\n# \n# Some tokens act like mask values, which can be OR'd together,\n# while others are mutually exclusive.  The mask-like ones have\n# \"Mask\" in their name, and a parallel enum that has the shift\n# amount (1 << x) for each corresponding enumerant.\n\nspv = {\n    'MagicNumber' : 0x07230203,\n    'Version' : 0x00010100,\n    'Revision' : 6,\n    'OpCodeMask' : 0xffff,\n    'WordCountShift' : 16,\n\n    'SourceLanguage' : {\n        'Unknown' : 0,\n        'ESSL' : 1,\n        'GLSL' : 2,\n        'OpenCL_C' : 3,\n        'OpenCL_CPP' : 4,\n        'HLSL' : 5,\n    },\n\n    'ExecutionModel' : {\n        'Vertex' : 0,\n        'TessellationControl' : 1,\n        'TessellationEvaluation' : 2,\n        'Geometry' : 3,\n        'Fragment' : 4,\n        'GLCompute' : 5,\n        'Kernel' : 6,\n    },\n\n    'AddressingModel' : {\n        'Logical' : 0,\n        'Physical32' : 1,\n        'Physical64' : 2,\n    },\n\n    'MemoryModel' : {\n        'Simple' : 0,\n        'GLSL450' : 1,\n        'OpenCL' : 2,\n    },\n\n    'ExecutionMode' : {\n        'Invocations' : 0,\n        'SpacingEqual' : 1,\n        'SpacingFractionalEven' : 2,\n        'SpacingFractionalOdd' : 3,\n        'VertexOrderCw' : 4,\n        'VertexOrderCcw' : 5,\n        'PixelCenterInteger' : 6,\n        'OriginUpperLeft' : 7,\n        'OriginLowerLeft' : 8,\n        'EarlyFragmentTests' : 9,\n        'PointMode' : 10,\n        'Xfb' : 11,\n        'DepthReplacing' : 12,\n        'DepthGreater' : 14,\n        'DepthLess' : 15,\n        'DepthUnchanged' : 16,\n        'LocalSize' : 17,\n        'LocalSizeHint' : 18,\n        'InputPoints' : 19,\n        'InputLines' : 20,\n        'InputLinesAdjacency' : 21,\n        'Triangles' : 22,\n        'InputTrianglesAdjacency' : 23,\n        'Quads' : 24,\n        'Isolines' : 25,\n        'OutputVertices' : 26,\n        'OutputPoints' : 27,\n        'OutputLineStrip' : 28,\n        'OutputTriangleStrip' : 29,\n        'VecTypeHint' : 30,\n        'ContractionOff' : 31,\n        'Initializer' : 33,\n        'Finalizer' : 34,\n        'SubgroupSize' : 35,\n        'SubgroupsPerWorkgroup' : 36,\n    },\n\n    'StorageClass' : {\n        'UniformConstant' : 0,\n        'Input' : 1,\n        'Uniform' : 2,\n        'Output' : 3,\n        'Workgroup' : 4,\n        'CrossWorkgroup' : 5,\n        'Private' : 6,\n        'Function' : 7,\n        'Generic' : 8,\n        'PushConstant' : 9,\n        'AtomicCounter' : 10,\n        'Image' : 11,\n        'StorageBuffer' : 12,\n    },\n\n    'Dim' : {\n        'Dim1D' : 0,\n        'Dim2D' : 1,\n        'Dim3D' : 2,\n        'Cube' : 3,\n        'Rect' : 4,\n        'Buffer' : 5,\n        'SubpassData' : 6,\n    },\n\n    'SamplerAddressingMode' : {\n        'None' : 0,\n        'ClampToEdge' : 1,\n        'Clamp' : 2,\n        'Repeat' : 3,\n        'RepeatMirrored' : 4,\n    },\n\n    'SamplerFilterMode' : {\n        'Nearest' : 0,\n        'Linear' : 1,\n    },\n\n    'ImageFormat' : {\n        'Unknown' : 0,\n        'Rgba32f' : 1,\n        'Rgba16f' : 2,\n        'R32f' : 3,\n        'Rgba8' : 4,\n        'Rgba8Snorm' : 5,\n        'Rg32f' : 6,\n        'Rg16f' : 7,\n        'R11fG11fB10f' : 8,\n        'R16f' : 9,\n        'Rgba16' : 10,\n        'Rgb10A2' : 11,\n        'Rg16' : 12,\n        'Rg8' : 13,\n        'R16' : 14,\n        'R8' : 15,\n        'Rgba16Snorm' : 16,\n        'Rg16Snorm' : 17,\n        'Rg8Snorm' : 18,\n        'R16Snorm' : 19,\n        'R8Snorm' : 20,\n        'Rgba32i' : 21,\n        'Rgba16i' : 22,\n        'Rgba8i' : 23,\n        'R32i' : 24,\n        'Rg32i' : 25,\n        'Rg16i' : 26,\n        'Rg8i' : 27,\n        'R16i' : 28,\n        'R8i' : 29,\n        'Rgba32ui' : 30,\n        'Rgba16ui' : 31,\n        'Rgba8ui' : 32,\n        'R32ui' : 33,\n        'Rgb10a2ui' : 34,\n        'Rg32ui' : 35,\n        'Rg16ui' : 36,\n        'Rg8ui' : 37,\n        'R16ui' : 38,\n        'R8ui' : 39,\n    },\n\n    'ImageChannelOrder' : {\n        'R' : 0,\n        'A' : 1,\n        'RG' : 2,\n        'RA' : 3,\n        'RGB' : 4,\n        'RGBA' : 5,\n        'BGRA' : 6,\n        'ARGB' : 7,\n        'Intensity' : 8,\n        'Luminance' : 9,\n        'Rx' : 10,\n        'RGx' : 11,\n        'RGBx' : 12,\n        'Depth' : 13,\n        'DepthStencil' : 14,\n        'sRGB' : 15,\n        'sRGBx' : 16,\n        'sRGBA' : 17,\n        'sBGRA' : 18,\n        'ABGR' : 19,\n    },\n\n    'ImageChannelDataType' : {\n        'SnormInt8' : 0,\n        'SnormInt16' : 1,\n        'UnormInt8' : 2,\n        'UnormInt16' : 3,\n        'UnormShort565' : 4,\n        'UnormShort555' : 5,\n        'UnormInt101010' : 6,\n        'SignedInt8' : 7,\n        'SignedInt16' : 8,\n        'SignedInt32' : 9,\n        'UnsignedInt8' : 10,\n        'UnsignedInt16' : 11,\n        'UnsignedInt32' : 12,\n        'HalfFloat' : 13,\n        'Float' : 14,\n        'UnormInt24' : 15,\n        'UnormInt101010_2' : 16,\n    },\n\n    'ImageOperandsShift' : {\n        'Bias' : 0,\n        'Lod' : 1,\n        'Grad' : 2,\n        'ConstOffset' : 3,\n        'Offset' : 4,\n        'ConstOffsets' : 5,\n        'Sample' : 6,\n        'MinLod' : 7,\n    },\n\n    'ImageOperandsMask' : {\n        'MaskNone' : 0,\n        'Bias' : 0x00000001,\n        'Lod' : 0x00000002,\n        'Grad' : 0x00000004,\n        'ConstOffset' : 0x00000008,\n        'Offset' : 0x00000010,\n        'ConstOffsets' : 0x00000020,\n        'Sample' : 0x00000040,\n        'MinLod' : 0x00000080,\n    },\n\n    'FPFastMathModeShift' : {\n        'NotNaN' : 0,\n        'NotInf' : 1,\n        'NSZ' : 2,\n        'AllowRecip' : 3,\n        'Fast' : 4,\n    },\n\n    'FPFastMathModeMask' : {\n        'MaskNone' : 0,\n        'NotNaN' : 0x00000001,\n        'NotInf' : 0x00000002,\n        'NSZ' : 0x00000004,\n        'AllowRecip' : 0x00000008,\n        'Fast' : 0x00000010,\n    },\n\n    'FPRoundingMode' : {\n        'RTE' : 0,\n        'RTZ' : 1,\n        'RTP' : 2,\n        'RTN' : 3,\n    },\n\n    'LinkageType' : {\n        'Export' : 0,\n        'Import' : 1,\n    },\n\n    'AccessQualifier' : {\n        'ReadOnly' : 0,\n        'WriteOnly' : 1,\n        'ReadWrite' : 2,\n    },\n\n    'FunctionParameterAttribute' : {\n        'Zext' : 0,\n        'Sext' : 1,\n        'ByVal' : 2,\n        'Sret' : 3,\n        'NoAlias' : 4,\n        'NoCapture' : 5,\n        'NoWrite' : 6,\n        'NoReadWrite' : 7,\n    },\n\n    'Decoration' : {\n        'RelaxedPrecision' : 0,\n        'SpecId' : 1,\n        'Block' : 2,\n        'BufferBlock' : 3,\n        'RowMajor' : 4,\n        'ColMajor' : 5,\n        'ArrayStride' : 6,\n        'MatrixStride' : 7,\n        'GLSLShared' : 8,\n        'GLSLPacked' : 9,\n        'CPacked' : 10,\n        'BuiltIn' : 11,\n        'NoPerspective' : 13,\n        'Flat' : 14,\n        'Patch' : 15,\n        'Centroid' : 16,\n        'Sample' : 17,\n        'Invariant' : 18,\n        'Restrict' : 19,\n        'Aliased' : 20,\n        'Volatile' : 21,\n        'Constant' : 22,\n        'Coherent' : 23,\n        'NonWritable' : 24,\n        'NonReadable' : 25,\n        'Uniform' : 26,\n        'SaturatedConversion' : 28,\n        'Stream' : 29,\n        'Location' : 30,\n        'Component' : 31,\n        'Index' : 32,\n        'Binding' : 33,\n        'DescriptorSet' : 34,\n        'Offset' : 35,\n        'XfbBuffer' : 36,\n        'XfbStride' : 37,\n        'FuncParamAttr' : 38,\n        'FPRoundingMode' : 39,\n        'FPFastMathMode' : 40,\n        'LinkageAttributes' : 41,\n        'NoContraction' : 42,\n        'InputAttachmentIndex' : 43,\n        'Alignment' : 44,\n        'MaxByteOffset' : 45,\n        'OverrideCoverageNV' : 5248,\n        'PassthroughNV' : 5250,\n        'ViewportRelativeNV' : 5252,\n        'SecondaryViewportRelativeNV' : 5256,\n    },\n\n    'BuiltIn' : {\n        'Position' : 0,\n        'PointSize' : 1,\n        'ClipDistance' : 3,\n        'CullDistance' : 4,\n        'VertexId' : 5,\n        'InstanceId' : 6,\n        'PrimitiveId' : 7,\n        'InvocationId' : 8,\n        'Layer' : 9,\n        'ViewportIndex' : 10,\n        'TessLevelOuter' : 11,\n        'TessLevelInner' : 12,\n        'TessCoord' : 13,\n        'PatchVertices' : 14,\n        'FragCoord' : 15,\n        'PointCoord' : 16,\n        'FrontFacing' : 17,\n        'SampleId' : 18,\n        'SamplePosition' : 19,\n        'SampleMask' : 20,\n        'FragDepth' : 22,\n        'HelperInvocation' : 23,\n        'NumWorkgroups' : 24,\n        'WorkgroupSize' : 25,\n        'WorkgroupId' : 26,\n        'LocalInvocationId' : 27,\n        'GlobalInvocationId' : 28,\n        'LocalInvocationIndex' : 29,\n        'WorkDim' : 30,\n        'GlobalSize' : 31,\n        'EnqueuedWorkgroupSize' : 32,\n        'GlobalOffset' : 33,\n        'GlobalLinearId' : 34,\n        'SubgroupSize' : 36,\n        'SubgroupMaxSize' : 37,\n        'NumSubgroups' : 38,\n        'NumEnqueuedSubgroups' : 39,\n        'SubgroupId' : 40,\n        'SubgroupLocalInvocationId' : 41,\n        'VertexIndex' : 42,\n        'InstanceIndex' : 43,\n        'SubgroupEqMaskKHR' : 4416,\n        'SubgroupGeMaskKHR' : 4417,\n        'SubgroupGtMaskKHR' : 4418,\n        'SubgroupLeMaskKHR' : 4419,\n        'SubgroupLtMaskKHR' : 4420,\n        'BaseVertex' : 4424,\n        'BaseInstance' : 4425,\n        'DrawIndex' : 4426,\n        'DeviceIndex' : 4438,\n        'ViewIndex' : 4440,\n        'ViewportMaskNV' : 5253,\n        'SecondaryPositionNV' : 5257,\n        'SecondaryViewportMaskNV' : 5258,\n        'PositionPerViewNV' : 5261,\n        'ViewportMaskPerViewNV' : 5262,\n    },\n\n    'SelectionControlShift' : {\n        'Flatten' : 0,\n        'DontFlatten' : 1,\n    },\n\n    'SelectionControlMask' : {\n        'MaskNone' : 0,\n        'Flatten' : 0x00000001,\n        'DontFlatten' : 0x00000002,\n    },\n\n    'LoopControlShift' : {\n        'Unroll' : 0,\n        'DontUnroll' : 1,\n        'DependencyInfinite' : 2,\n        'DependencyLength' : 3,\n    },\n\n    'LoopControlMask' : {\n        'MaskNone' : 0,\n        'Unroll' : 0x00000001,\n        'DontUnroll' : 0x00000002,\n        'DependencyInfinite' : 0x00000004,\n        'DependencyLength' : 0x00000008,\n    },\n\n    'FunctionControlShift' : {\n        'Inline' : 0,\n        'DontInline' : 1,\n        'Pure' : 2,\n        'Const' : 3,\n    },\n\n    'FunctionControlMask' : {\n        'MaskNone' : 0,\n        'Inline' : 0x00000001,\n        'DontInline' : 0x00000002,\n        'Pure' : 0x00000004,\n        'Const' : 0x00000008,\n    },\n\n    'MemorySemanticsShift' : {\n        'Acquire' : 1,\n        'Release' : 2,\n        'AcquireRelease' : 3,\n        'SequentiallyConsistent' : 4,\n        'UniformMemory' : 6,\n        'SubgroupMemory' : 7,\n        'WorkgroupMemory' : 8,\n        'CrossWorkgroupMemory' : 9,\n        'AtomicCounterMemory' : 10,\n        'ImageMemory' : 11,\n    },\n\n    'MemorySemanticsMask' : {\n        'MaskNone' : 0,\n        'Acquire' : 0x00000002,\n        'Release' : 0x00000004,\n        'AcquireRelease' : 0x00000008,\n        'SequentiallyConsistent' : 0x00000010,\n        'UniformMemory' : 0x00000040,\n        'SubgroupMemory' : 0x00000080,\n        'WorkgroupMemory' : 0x00000100,\n        'CrossWorkgroupMemory' : 0x00000200,\n        'AtomicCounterMemory' : 0x00000400,\n        'ImageMemory' : 0x00000800,\n    },\n\n    'MemoryAccessShift' : {\n        'Volatile' : 0,\n        'Aligned' : 1,\n        'Nontemporal' : 2,\n    },\n\n    'MemoryAccessMask' : {\n        'MaskNone' : 0,\n        'Volatile' : 0x00000001,\n        'Aligned' : 0x00000002,\n        'Nontemporal' : 0x00000004,\n    },\n\n    'Scope' : {\n        'CrossDevice' : 0,\n        'Device' : 1,\n        'Workgroup' : 2,\n        'Subgroup' : 3,\n        'Invocation' : 4,\n    },\n\n    'GroupOperation' : {\n        'Reduce' : 0,\n        'InclusiveScan' : 1,\n        'ExclusiveScan' : 2,\n    },\n\n    'KernelEnqueueFlags' : {\n        'NoWait' : 0,\n        'WaitKernel' : 1,\n        'WaitWorkGroup' : 2,\n    },\n\n    'KernelProfilingInfoShift' : {\n        'CmdExecTime' : 0,\n    },\n\n    'KernelProfilingInfoMask' : {\n        'MaskNone' : 0,\n        'CmdExecTime' : 0x00000001,\n    },\n\n    'Capability' : {\n        'Matrix' : 0,\n        'Shader' : 1,\n        'Geometry' : 2,\n        'Tessellation' : 3,\n        'Addresses' : 4,\n        'Linkage' : 5,\n        'Kernel' : 6,\n        'Vector16' : 7,\n        'Float16Buffer' : 8,\n        'Float16' : 9,\n        'Float64' : 10,\n        'Int64' : 11,\n        'Int64Atomics' : 12,\n        'ImageBasic' : 13,\n        'ImageReadWrite' : 14,\n        'ImageMipmap' : 15,\n        'Pipes' : 17,\n        'Groups' : 18,\n        'DeviceEnqueue' : 19,\n        'LiteralSampler' : 20,\n        'AtomicStorage' : 21,\n        'Int16' : 22,\n        'TessellationPointSize' : 23,\n        'GeometryPointSize' : 24,\n        'ImageGatherExtended' : 25,\n        'StorageImageMultisample' : 27,\n        'UniformBufferArrayDynamicIndexing' : 28,\n        'SampledImageArrayDynamicIndexing' : 29,\n        'StorageBufferArrayDynamicIndexing' : 30,\n        'StorageImageArrayDynamicIndexing' : 31,\n        'ClipDistance' : 32,\n        'CullDistance' : 33,\n        'ImageCubeArray' : 34,\n        'SampleRateShading' : 35,\n        'ImageRect' : 36,\n        'SampledRect' : 37,\n        'GenericPointer' : 38,\n        'Int8' : 39,\n        'InputAttachment' : 40,\n        'SparseResidency' : 41,\n        'MinLod' : 42,\n        'Sampled1D' : 43,\n        'Image1D' : 44,\n        'SampledCubeArray' : 45,\n        'SampledBuffer' : 46,\n        'ImageBuffer' : 47,\n        'ImageMSArray' : 48,\n        'StorageImageExtendedFormats' : 49,\n        'ImageQuery' : 50,\n        'DerivativeControl' : 51,\n        'InterpolationFunction' : 52,\n        'TransformFeedback' : 53,\n        'GeometryStreams' : 54,\n        'StorageImageReadWithoutFormat' : 55,\n        'StorageImageWriteWithoutFormat' : 56,\n        'MultiViewport' : 57,\n        'SubgroupDispatch' : 58,\n        'NamedBarrier' : 59,\n        'PipeStorage' : 60,\n        'SubgroupBallotKHR' : 4423,\n        'DrawParameters' : 4427,\n        'SubgroupVoteKHR' : 4431,\n        'StorageBuffer16BitAccess' : 4433,\n        'StorageUniformBufferBlock16' : 4433,\n        'StorageUniform16' : 4434,\n        'UniformAndStorageBuffer16BitAccess' : 4434,\n        'StoragePushConstant16' : 4435,\n        'StorageInputOutput16' : 4436,\n        'DeviceGroup' : 4437,\n        'MultiView' : 4439,\n        'VariablePointersStorageBuffer' : 4441,\n        'VariablePointers' : 4442,\n        'SampleMaskOverrideCoverageNV' : 5249,\n        'GeometryShaderPassthroughNV' : 5251,\n        'ShaderViewportIndexLayerNV' : 5254,\n        'ShaderViewportMaskNV' : 5255,\n        'ShaderStereoViewNV' : 5259,\n        'PerViewAttributesNV' : 5260,\n    },\n\n    'Op' : {\n        'OpNop' : 0,\n        'OpUndef' : 1,\n        'OpSourceContinued' : 2,\n        'OpSource' : 3,\n        'OpSourceExtension' : 4,\n        'OpName' : 5,\n        'OpMemberName' : 6,\n        'OpString' : 7,\n        'OpLine' : 8,\n        'OpExtension' : 10,\n        'OpExtInstImport' : 11,\n        'OpExtInst' : 12,\n        'OpMemoryModel' : 14,\n        'OpEntryPoint' : 15,\n        'OpExecutionMode' : 16,\n        'OpCapability' : 17,\n        'OpTypeVoid' : 19,\n        'OpTypeBool' : 20,\n        'OpTypeInt' : 21,\n        'OpTypeFloat' : 22,\n        'OpTypeVector' : 23,\n        'OpTypeMatrix' : 24,\n        'OpTypeImage' : 25,\n        'OpTypeSampler' : 26,\n        'OpTypeSampledImage' : 27,\n        'OpTypeArray' : 28,\n        'OpTypeRuntimeArray' : 29,\n        'OpTypeStruct' : 30,\n        'OpTypeOpaque' : 31,\n        'OpTypePointer' : 32,\n        'OpTypeFunction' : 33,\n        'OpTypeEvent' : 34,\n        'OpTypeDeviceEvent' : 35,\n        'OpTypeReserveId' : 36,\n        'OpTypeQueue' : 37,\n        'OpTypePipe' : 38,\n        'OpTypeForwardPointer' : 39,\n        'OpConstantTrue' : 41,\n        'OpConstantFalse' : 42,\n        'OpConstant' : 43,\n        'OpConstantComposite' : 44,\n        'OpConstantSampler' : 45,\n        'OpConstantNull' : 46,\n        'OpSpecConstantTrue' : 48,\n        'OpSpecConstantFalse' : 49,\n        'OpSpecConstant' : 50,\n        'OpSpecConstantComposite' : 51,\n        'OpSpecConstantOp' : 52,\n        'OpFunction' : 54,\n        'OpFunctionParameter' : 55,\n        'OpFunctionEnd' : 56,\n        'OpFunctionCall' : 57,\n        'OpVariable' : 59,\n        'OpImageTexelPointer' : 60,\n        'OpLoad' : 61,\n        'OpStore' : 62,\n        'OpCopyMemory' : 63,\n        'OpCopyMemorySized' : 64,\n        'OpAccessChain' : 65,\n        'OpInBoundsAccessChain' : 66,\n        'OpPtrAccessChain' : 67,\n        'OpArrayLength' : 68,\n        'OpGenericPtrMemSemantics' : 69,\n        'OpInBoundsPtrAccessChain' : 70,\n        'OpDecorate' : 71,\n        'OpMemberDecorate' : 72,\n        'OpDecorationGroup' : 73,\n        'OpGroupDecorate' : 74,\n        'OpGroupMemberDecorate' : 75,\n        'OpVectorExtractDynamic' : 77,\n        'OpVectorInsertDynamic' : 78,\n        'OpVectorShuffle' : 79,\n        'OpCompositeConstruct' : 80,\n        'OpCompositeExtract' : 81,\n        'OpCompositeInsert' : 82,\n        'OpCopyObject' : 83,\n        'OpTranspose' : 84,\n        'OpSampledImage' : 86,\n        'OpImageSampleImplicitLod' : 87,\n        'OpImageSampleExplicitLod' : 88,\n        'OpImageSampleDrefImplicitLod' : 89,\n        'OpImageSampleDrefExplicitLod' : 90,\n        'OpImageSampleProjImplicitLod' : 91,\n        'OpImageSampleProjExplicitLod' : 92,\n        'OpImageSampleProjDrefImplicitLod' : 93,\n        'OpImageSampleProjDrefExplicitLod' : 94,\n        'OpImageFetch' : 95,\n        'OpImageGather' : 96,\n        'OpImageDrefGather' : 97,\n        'OpImageRead' : 98,\n        'OpImageWrite' : 99,\n        'OpImage' : 100,\n        'OpImageQueryFormat' : 101,\n        'OpImageQueryOrder' : 102,\n        'OpImageQuerySizeLod' : 103,\n        'OpImageQuerySize' : 104,\n        'OpImageQueryLod' : 105,\n        'OpImageQueryLevels' : 106,\n        'OpImageQuerySamples' : 107,\n        'OpConvertFToU' : 109,\n        'OpConvertFToS' : 110,\n        'OpConvertSToF' : 111,\n        'OpConvertUToF' : 112,\n        'OpUConvert' : 113,\n        'OpSConvert' : 114,\n        'OpFConvert' : 115,\n        'OpQuantizeToF16' : 116,\n        'OpConvertPtrToU' : 117,\n        'OpSatConvertSToU' : 118,\n        'OpSatConvertUToS' : 119,\n        'OpConvertUToPtr' : 120,\n        'OpPtrCastToGeneric' : 121,\n        'OpGenericCastToPtr' : 122,\n        'OpGenericCastToPtrExplicit' : 123,\n        'OpBitcast' : 124,\n        'OpSNegate' : 126,\n        'OpFNegate' : 127,\n        'OpIAdd' : 128,\n        'OpFAdd' : 129,\n        'OpISub' : 130,\n        'OpFSub' : 131,\n        'OpIMul' : 132,\n        'OpFMul' : 133,\n        'OpUDiv' : 134,\n        'OpSDiv' : 135,\n        'OpFDiv' : 136,\n        'OpUMod' : 137,\n        'OpSRem' : 138,\n        'OpSMod' : 139,\n        'OpFRem' : 140,\n        'OpFMod' : 141,\n        'OpVectorTimesScalar' : 142,\n        'OpMatrixTimesScalar' : 143,\n        'OpVectorTimesMatrix' : 144,\n        'OpMatrixTimesVector' : 145,\n        'OpMatrixTimesMatrix' : 146,\n        'OpOuterProduct' : 147,\n        'OpDot' : 148,\n        'OpIAddCarry' : 149,\n        'OpISubBorrow' : 150,\n        'OpUMulExtended' : 151,\n        'OpSMulExtended' : 152,\n        'OpAny' : 154,\n        'OpAll' : 155,\n        'OpIsNan' : 156,\n        'OpIsInf' : 157,\n        'OpIsFinite' : 158,\n        'OpIsNormal' : 159,\n        'OpSignBitSet' : 160,\n        'OpLessOrGreater' : 161,\n        'OpOrdered' : 162,\n        'OpUnordered' : 163,\n        'OpLogicalEqual' : 164,\n        'OpLogicalNotEqual' : 165,\n        'OpLogicalOr' : 166,\n        'OpLogicalAnd' : 167,\n        'OpLogicalNot' : 168,\n        'OpSelect' : 169,\n        'OpIEqual' : 170,\n        'OpINotEqual' : 171,\n        'OpUGreaterThan' : 172,\n        'OpSGreaterThan' : 173,\n        'OpUGreaterThanEqual' : 174,\n        'OpSGreaterThanEqual' : 175,\n        'OpULessThan' : 176,\n        'OpSLessThan' : 177,\n        'OpULessThanEqual' : 178,\n        'OpSLessThanEqual' : 179,\n        'OpFOrdEqual' : 180,\n        'OpFUnordEqual' : 181,\n        'OpFOrdNotEqual' : 182,\n        'OpFUnordNotEqual' : 183,\n        'OpFOrdLessThan' : 184,\n        'OpFUnordLessThan' : 185,\n        'OpFOrdGreaterThan' : 186,\n        'OpFUnordGreaterThan' : 187,\n        'OpFOrdLessThanEqual' : 188,\n        'OpFUnordLessThanEqual' : 189,\n        'OpFOrdGreaterThanEqual' : 190,\n        'OpFUnordGreaterThanEqual' : 191,\n        'OpShiftRightLogical' : 194,\n        'OpShiftRightArithmetic' : 195,\n        'OpShiftLeftLogical' : 196,\n        'OpBitwiseOr' : 197,\n        'OpBitwiseXor' : 198,\n        'OpBitwiseAnd' : 199,\n        'OpNot' : 200,\n        'OpBitFieldInsert' : 201,\n        'OpBitFieldSExtract' : 202,\n        'OpBitFieldUExtract' : 203,\n        'OpBitReverse' : 204,\n        'OpBitCount' : 205,\n        'OpDPdx' : 207,\n        'OpDPdy' : 208,\n        'OpFwidth' : 209,\n        'OpDPdxFine' : 210,\n        'OpDPdyFine' : 211,\n        'OpFwidthFine' : 212,\n        'OpDPdxCoarse' : 213,\n        'OpDPdyCoarse' : 214,\n        'OpFwidthCoarse' : 215,\n        'OpEmitVertex' : 218,\n        'OpEndPrimitive' : 219,\n        'OpEmitStreamVertex' : 220,\n        'OpEndStreamPrimitive' : 221,\n        'OpControlBarrier' : 224,\n        'OpMemoryBarrier' : 225,\n        'OpAtomicLoad' : 227,\n        'OpAtomicStore' : 228,\n        'OpAtomicExchange' : 229,\n        'OpAtomicCompareExchange' : 230,\n        'OpAtomicCompareExchangeWeak' : 231,\n        'OpAtomicIIncrement' : 232,\n        'OpAtomicIDecrement' : 233,\n        'OpAtomicIAdd' : 234,\n        'OpAtomicISub' : 235,\n        'OpAtomicSMin' : 236,\n        'OpAtomicUMin' : 237,\n        'OpAtomicSMax' : 238,\n        'OpAtomicUMax' : 239,\n        'OpAtomicAnd' : 240,\n        'OpAtomicOr' : 241,\n        'OpAtomicXor' : 242,\n        'OpPhi' : 245,\n        'OpLoopMerge' : 246,\n        'OpSelectionMerge' : 247,\n        'OpLabel' : 248,\n        'OpBranch' : 249,\n        'OpBranchConditional' : 250,\n        'OpSwitch' : 251,\n        'OpKill' : 252,\n        'OpReturn' : 253,\n        'OpReturnValue' : 254,\n        'OpUnreachable' : 255,\n        'OpLifetimeStart' : 256,\n        'OpLifetimeStop' : 257,\n        'OpGroupAsyncCopy' : 259,\n        'OpGroupWaitEvents' : 260,\n        'OpGroupAll' : 261,\n        'OpGroupAny' : 262,\n        'OpGroupBroadcast' : 263,\n        'OpGroupIAdd' : 264,\n        'OpGroupFAdd' : 265,\n        'OpGroupFMin' : 266,\n        'OpGroupUMin' : 267,\n        'OpGroupSMin' : 268,\n        'OpGroupFMax' : 269,\n        'OpGroupUMax' : 270,\n        'OpGroupSMax' : 271,\n        'OpReadPipe' : 274,\n        'OpWritePipe' : 275,\n        'OpReservedReadPipe' : 276,\n        'OpReservedWritePipe' : 277,\n        'OpReserveReadPipePackets' : 278,\n        'OpReserveWritePipePackets' : 279,\n        'OpCommitReadPipe' : 280,\n        'OpCommitWritePipe' : 281,\n        'OpIsValidReserveId' : 282,\n        'OpGetNumPipePackets' : 283,\n        'OpGetMaxPipePackets' : 284,\n        'OpGroupReserveReadPipePackets' : 285,\n        'OpGroupReserveWritePipePackets' : 286,\n        'OpGroupCommitReadPipe' : 287,\n        'OpGroupCommitWritePipe' : 288,\n        'OpEnqueueMarker' : 291,\n        'OpEnqueueKernel' : 292,\n        'OpGetKernelNDrangeSubGroupCount' : 293,\n        'OpGetKernelNDrangeMaxSubGroupSize' : 294,\n        'OpGetKernelWorkGroupSize' : 295,\n        'OpGetKernelPreferredWorkGroupSizeMultiple' : 296,\n        'OpRetainEvent' : 297,\n        'OpReleaseEvent' : 298,\n        'OpCreateUserEvent' : 299,\n        'OpIsValidEvent' : 300,\n        'OpSetUserEventStatus' : 301,\n        'OpCaptureEventProfilingInfo' : 302,\n        'OpGetDefaultQueue' : 303,\n        'OpBuildNDRange' : 304,\n        'OpImageSparseSampleImplicitLod' : 305,\n        'OpImageSparseSampleExplicitLod' : 306,\n        'OpImageSparseSampleDrefImplicitLod' : 307,\n        'OpImageSparseSampleDrefExplicitLod' : 308,\n        'OpImageSparseSampleProjImplicitLod' : 309,\n        'OpImageSparseSampleProjExplicitLod' : 310,\n        'OpImageSparseSampleProjDrefImplicitLod' : 311,\n        'OpImageSparseSampleProjDrefExplicitLod' : 312,\n        'OpImageSparseFetch' : 313,\n        'OpImageSparseGather' : 314,\n        'OpImageSparseDrefGather' : 315,\n        'OpImageSparseTexelsResident' : 316,\n        'OpNoLine' : 317,\n        'OpAtomicFlagTestAndSet' : 318,\n        'OpAtomicFlagClear' : 319,\n        'OpImageSparseRead' : 320,\n        'OpSizeOf' : 321,\n        'OpTypePipeStorage' : 322,\n        'OpConstantPipeStorage' : 323,\n        'OpCreatePipeFromPipeStorage' : 324,\n        'OpGetKernelLocalSizeForSubgroupCount' : 325,\n        'OpGetKernelMaxNumSubgroups' : 326,\n        'OpTypeNamedBarrier' : 327,\n        'OpNamedBarrierInitialize' : 328,\n        'OpMemoryNamedBarrier' : 329,\n        'OpModuleProcessed' : 330,\n        'OpSubgroupBallotKHR' : 4421,\n        'OpSubgroupFirstInvocationKHR' : 4422,\n        'OpSubgroupAllKHR' : 4428,\n        'OpSubgroupAnyKHR' : 4429,\n        'OpSubgroupAllEqualKHR' : 4430,\n        'OpSubgroupReadInvocationKHR' : 4432,\n    },\n\n}\n\n"
  },
  {
    "path": "src/engine/renderer/vulkan/vk_icd.h",
    "content": "//\n// File: vk_icd.h\n//\n/*\n * Copyright (c) 2015-2016 The Khronos Group Inc.\n * Copyright (c) 2015-2016 Valve Corporation\n * Copyright (c) 2015-2016 LunarG, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\n#ifndef VKICD_H\n#define VKICD_H\n\n#include \"vulkan.h\"\n#include <stdbool.h>\n\n// Loader-ICD version negotiation API.  Versions add the following features:\n//   Version 0 - Initial.  Doesn't support vk_icdGetInstanceProcAddr\n//               or vk_icdNegotiateLoaderICDInterfaceVersion.\n//   Version 1 - Add support for vk_icdGetInstanceProcAddr.\n//   Version 2 - Add Loader/ICD Interface version negotiation\n//               via vk_icdNegotiateLoaderICDInterfaceVersion.\n//   Version 3 - Add ICD creation/destruction of KHR_surface objects.\n//   Version 4 - Add unknown physical device extension qyering via\n//               vk_icdGetPhysicalDeviceProcAddr.\n#define CURRENT_LOADER_ICD_INTERFACE_VERSION 4\n#define MIN_SUPPORTED_LOADER_ICD_INTERFACE_VERSION 0\n#define MIN_PHYS_DEV_EXTENSION_ICD_INTERFACE_VERSION 4\ntypedef VkResult (VKAPI_PTR *PFN_vkNegotiateLoaderICDInterfaceVersion)(uint32_t *pVersion);\n\n// This is defined in vk_layer.h which will be found by the loader, but if an ICD is building against this\n// flie directly, it won't be found.\n#ifndef PFN_GetPhysicalDeviceProcAddr\ntypedef PFN_vkVoidFunction (VKAPI_PTR *PFN_GetPhysicalDeviceProcAddr)(VkInstance instance, const char* pName);\n#endif\n\n/*\n * The ICD must reserve space for a pointer for the loader's dispatch\n * table, at the start of <each object>.\n * The ICD must initialize this variable using the SET_LOADER_MAGIC_VALUE macro.\n */\n\n#define ICD_LOADER_MAGIC 0x01CDC0DE\n\ntypedef union {\n    uintptr_t loaderMagic;\n    void *loaderData;\n} VK_LOADER_DATA;\n\nstatic inline void set_loader_magic_value(void *pNewObject) {\n    VK_LOADER_DATA *loader_info = (VK_LOADER_DATA *)pNewObject;\n    loader_info->loaderMagic = ICD_LOADER_MAGIC;\n}\n\nstatic inline bool valid_loader_magic_value(void *pNewObject) {\n    const VK_LOADER_DATA *loader_info = (VK_LOADER_DATA *)pNewObject;\n    return (loader_info->loaderMagic & 0xffffffff) == ICD_LOADER_MAGIC;\n}\n\n/*\n * Windows and Linux ICDs will treat VkSurfaceKHR as a pointer to a struct that\n * contains the platform-specific connection and surface information.\n */\ntypedef enum {\n    VK_ICD_WSI_PLATFORM_MIR,\n    VK_ICD_WSI_PLATFORM_WAYLAND,\n    VK_ICD_WSI_PLATFORM_WIN32,\n    VK_ICD_WSI_PLATFORM_XCB,\n    VK_ICD_WSI_PLATFORM_XLIB,\n    VK_ICD_WSI_PLATFORM_DISPLAY\n} VkIcdWsiPlatform;\n\ntypedef struct {\n    VkIcdWsiPlatform platform;\n} VkIcdSurfaceBase;\n\n#ifdef VK_USE_PLATFORM_MIR_KHR\ntypedef struct {\n    VkIcdSurfaceBase base;\n    MirConnection *connection;\n    MirSurface *mirSurface;\n} VkIcdSurfaceMir;\n#endif // VK_USE_PLATFORM_MIR_KHR\n\n#ifdef VK_USE_PLATFORM_WAYLAND_KHR\ntypedef struct {\n    VkIcdSurfaceBase base;\n    struct wl_display *display;\n    struct wl_surface *surface;\n} VkIcdSurfaceWayland;\n#endif // VK_USE_PLATFORM_WAYLAND_KHR\n\n#ifdef VK_USE_PLATFORM_WIN32_KHR\ntypedef struct {\n    VkIcdSurfaceBase base;\n    HINSTANCE hinstance;\n    HWND hwnd;\n} VkIcdSurfaceWin32;\n#endif // VK_USE_PLATFORM_WIN32_KHR\n\n#ifdef VK_USE_PLATFORM_XCB_KHR\ntypedef struct {\n    VkIcdSurfaceBase base;\n    xcb_connection_t *connection;\n    xcb_window_t window;\n} VkIcdSurfaceXcb;\n#endif // VK_USE_PLATFORM_XCB_KHR\n\n#ifdef VK_USE_PLATFORM_XLIB_KHR\ntypedef struct {\n    VkIcdSurfaceBase base;\n    Display *dpy;\n    Window window;\n} VkIcdSurfaceXlib;\n#endif // VK_USE_PLATFORM_XLIB_KHR\n\n#ifdef VK_USE_PLATFORM_ANDROID_KHR\ntypedef struct {\n    ANativeWindow* window;\n} VkIcdSurfaceAndroid;\n#endif //VK_USE_PLATFORM_ANDROID_KHR\n\ntypedef struct {\n    VkIcdSurfaceBase base;\n    VkDisplayModeKHR displayMode;\n    uint32_t planeIndex;\n    uint32_t planeStackIndex;\n    VkSurfaceTransformFlagBitsKHR transform;\n    float globalAlpha;\n    VkDisplayPlaneAlphaFlagBitsKHR alphaMode;\n    VkExtent2D imageExtent;\n} VkIcdSurfaceDisplay;\n\n#endif // VKICD_H\n"
  },
  {
    "path": "src/engine/renderer/vulkan/vk_layer.h",
    "content": "//\n// File: vk_layer.h\n//\n/*\n * Copyright (c) 2015-2017 The Khronos Group Inc.\n * Copyright (c) 2015-2017 Valve Corporation\n * Copyright (c) 2015-2017 LunarG, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\n/* Need to define dispatch table\n * Core struct can then have ptr to dispatch table at the top\n * Along with object ptrs for current and next OBJ\n */\n#pragma once\n\n#include \"vulkan.h\"\n#if defined(__GNUC__) && __GNUC__ >= 4\n#define VK_LAYER_EXPORT __attribute__((visibility(\"default\")))\n#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590)\n#define VK_LAYER_EXPORT __attribute__((visibility(\"default\")))\n#else\n#define VK_LAYER_EXPORT\n#endif\n\n// Definition for VkLayerDispatchTable and VkLayerInstanceDispatchTable now appear in externally generated header\n#include \"vk_layer_dispatch_table.h\"\n\n#define MAX_NUM_UNKNOWN_EXTS 250\n\n // Loader-Layer version negotiation API.  Versions add the following features:\n //   Versions 0/1 - Initial.  Doesn't support vk_layerGetPhysicalDeviceProcAddr\n //                  or vk_icdNegotiateLoaderLayerInterfaceVersion.\n //   Version 2    - Add support for vk_layerGetPhysicalDeviceProcAddr and\n //                  vk_icdNegotiateLoaderLayerInterfaceVersion.\n#define CURRENT_LOADER_LAYER_INTERFACE_VERSION 2\n#define MIN_SUPPORTED_LOADER_LAYER_INTERFACE_VERSION 1\n\n// Version negotiation values\ntypedef enum VkNegotiateLayerStructType {\n    LAYER_NEGOTIATE_UNINTIALIZED = 0,\n    LAYER_NEGOTIATE_INTERFACE_STRUCT = 1,\n} VkNegotiateLayerStructType;\n\n// Version negotiation structures\ntypedef struct VkNegotiateLayerInterface {\n    VkNegotiateLayerStructType sType;\n    void *pNext;\n    uint32_t loaderLayerInterfaceVersion;\n    PFN_vkGetInstanceProcAddr pfnGetInstanceProcAddr;\n    PFN_vkGetDeviceProcAddr pfnGetDeviceProcAddr;\n    PFN_GetPhysicalDeviceProcAddr pfnGetPhysicalDeviceProcAddr;\n} VkNegotiateLayerInterface;\n\n// Version negotiation functions\ntypedef VkResult (VKAPI_PTR *PFN_vkNegotiateLoaderLayerInterfaceVersion)(VkNegotiateLayerInterface *pVersionStruct);\n\n// Function prototype for unknown physical device extension command\ntypedef VkResult(VKAPI_PTR *PFN_PhysDevExt)(VkPhysicalDevice phys_device, ...);\n\n// ------------------------------------------------------------------------------------------------\n// CreateInstance and CreateDevice support structures\n\n/* Sub type of structure for instance and device loader ext of CreateInfo.\n * When sType == VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO\n * or sType == VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO\n * then VkLayerFunction indicates struct type pointed to by pNext\n */\ntypedef enum VkLayerFunction_ {\n    VK_LAYER_LINK_INFO = 0,\n    VK_LOADER_DATA_CALLBACK = 1\n} VkLayerFunction;\n\ntypedef struct VkLayerInstanceLink_ {\n    struct VkLayerInstanceLink_ *pNext;\n    PFN_vkGetInstanceProcAddr pfnNextGetInstanceProcAddr;\n    PFN_GetPhysicalDeviceProcAddr pfnNextGetPhysicalDeviceProcAddr;\n} VkLayerInstanceLink;\n\n/*\n * When creating the device chain the loader needs to pass\n * down information about it's device structure needed at\n * the end of the chain. Passing the data via the\n * VkLayerDeviceInfo avoids issues with finding the\n * exact instance being used.\n */\ntypedef struct VkLayerDeviceInfo_ {\n    void *device_info;\n    PFN_vkGetInstanceProcAddr pfnNextGetInstanceProcAddr;\n} VkLayerDeviceInfo;\n\ntypedef VkResult (VKAPI_PTR *PFN_vkSetInstanceLoaderData)(VkInstance instance,\n        void *object);\ntypedef VkResult (VKAPI_PTR *PFN_vkSetDeviceLoaderData)(VkDevice device,\n        void *object);\n\ntypedef struct {\n    VkStructureType sType; // VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO\n    const void *pNext;\n    VkLayerFunction function;\n    union {\n        VkLayerInstanceLink *pLayerInfo;\n        PFN_vkSetInstanceLoaderData pfnSetInstanceLoaderData;\n    } u;\n} VkLayerInstanceCreateInfo;\n\ntypedef struct VkLayerDeviceLink_ {\n    struct VkLayerDeviceLink_ *pNext;\n    PFN_vkGetInstanceProcAddr pfnNextGetInstanceProcAddr;\n    PFN_vkGetDeviceProcAddr pfnNextGetDeviceProcAddr;\n} VkLayerDeviceLink;\n\ntypedef struct {\n    VkStructureType sType; // VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO\n    const void *pNext;\n    VkLayerFunction function;\n    union {\n        VkLayerDeviceLink *pLayerInfo;\n        PFN_vkSetDeviceLoaderData pfnSetDeviceLoaderData;\n    } u;\n} VkLayerDeviceCreateInfo;\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nVKAPI_ATTR VkResult VKAPI_CALL vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface *pVersionStruct);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "src/engine/renderer/vulkan/vk_layer_dispatch_table.h",
    "content": "// *** THIS FILE IS GENERATED - DO NOT EDIT ***\n// See loader_extension_generator.py for modifications\n\n/*\n * Copyright (c) 2015-2017 The Khronos Group Inc.\n * Copyright (c) 2015-2017 Valve Corporation\n * Copyright (c) 2015-2017 LunarG, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Author: Mark Lobodzinski <mark@lunarg.com>\n * Author: Mark Young <marky@lunarg.com>\n */\n\n#pragma once\n\ntypedef PFN_vkVoidFunction (VKAPI_PTR *PFN_GetPhysicalDeviceProcAddr)(VkInstance instance, const char* pName);\n\n// Instance function pointer dispatch table\ntypedef struct VkLayerInstanceDispatchTable_ {\n    // Manually add in GetPhysicalDeviceProcAddr entry\n    PFN_GetPhysicalDeviceProcAddr GetPhysicalDeviceProcAddr;\n\n    // ---- Core 1_0 commands\n    PFN_vkCreateInstance CreateInstance;\n    PFN_vkDestroyInstance DestroyInstance;\n    PFN_vkEnumeratePhysicalDevices EnumeratePhysicalDevices;\n    PFN_vkGetPhysicalDeviceFeatures GetPhysicalDeviceFeatures;\n    PFN_vkGetPhysicalDeviceFormatProperties GetPhysicalDeviceFormatProperties;\n    PFN_vkGetPhysicalDeviceImageFormatProperties GetPhysicalDeviceImageFormatProperties;\n    PFN_vkGetPhysicalDeviceProperties GetPhysicalDeviceProperties;\n    PFN_vkGetPhysicalDeviceQueueFamilyProperties GetPhysicalDeviceQueueFamilyProperties;\n    PFN_vkGetPhysicalDeviceMemoryProperties GetPhysicalDeviceMemoryProperties;\n    PFN_vkGetInstanceProcAddr GetInstanceProcAddr;\n    PFN_vkCreateDevice CreateDevice;\n    PFN_vkEnumerateInstanceExtensionProperties EnumerateInstanceExtensionProperties;\n    PFN_vkEnumerateDeviceExtensionProperties EnumerateDeviceExtensionProperties;\n    PFN_vkEnumerateInstanceLayerProperties EnumerateInstanceLayerProperties;\n    PFN_vkEnumerateDeviceLayerProperties EnumerateDeviceLayerProperties;\n    PFN_vkGetPhysicalDeviceSparseImageFormatProperties GetPhysicalDeviceSparseImageFormatProperties;\n\n    // ---- VK_KHR_surface extension commands\n    PFN_vkDestroySurfaceKHR DestroySurfaceKHR;\n    PFN_vkGetPhysicalDeviceSurfaceSupportKHR GetPhysicalDeviceSurfaceSupportKHR;\n    PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR GetPhysicalDeviceSurfaceCapabilitiesKHR;\n    PFN_vkGetPhysicalDeviceSurfaceFormatsKHR GetPhysicalDeviceSurfaceFormatsKHR;\n    PFN_vkGetPhysicalDeviceSurfacePresentModesKHR GetPhysicalDeviceSurfacePresentModesKHR;\n\n    // ---- VK_KHR_display extension commands\n    PFN_vkGetPhysicalDeviceDisplayPropertiesKHR GetPhysicalDeviceDisplayPropertiesKHR;\n    PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR GetPhysicalDeviceDisplayPlanePropertiesKHR;\n    PFN_vkGetDisplayPlaneSupportedDisplaysKHR GetDisplayPlaneSupportedDisplaysKHR;\n    PFN_vkGetDisplayModePropertiesKHR GetDisplayModePropertiesKHR;\n    PFN_vkCreateDisplayModeKHR CreateDisplayModeKHR;\n    PFN_vkGetDisplayPlaneCapabilitiesKHR GetDisplayPlaneCapabilitiesKHR;\n    PFN_vkCreateDisplayPlaneSurfaceKHR CreateDisplayPlaneSurfaceKHR;\n\n    // ---- VK_KHR_xlib_surface extension commands\n#ifdef VK_USE_PLATFORM_XLIB_KHR\n    PFN_vkCreateXlibSurfaceKHR CreateXlibSurfaceKHR;\n#endif // VK_USE_PLATFORM_XLIB_KHR\n#ifdef VK_USE_PLATFORM_XLIB_KHR\n    PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR GetPhysicalDeviceXlibPresentationSupportKHR;\n#endif // VK_USE_PLATFORM_XLIB_KHR\n\n    // ---- VK_KHR_xcb_surface extension commands\n#ifdef VK_USE_PLATFORM_XCB_KHR\n    PFN_vkCreateXcbSurfaceKHR CreateXcbSurfaceKHR;\n#endif // VK_USE_PLATFORM_XCB_KHR\n#ifdef VK_USE_PLATFORM_XCB_KHR\n    PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR GetPhysicalDeviceXcbPresentationSupportKHR;\n#endif // VK_USE_PLATFORM_XCB_KHR\n\n    // ---- VK_KHR_wayland_surface extension commands\n#ifdef VK_USE_PLATFORM_WAYLAND_KHR\n    PFN_vkCreateWaylandSurfaceKHR CreateWaylandSurfaceKHR;\n#endif // VK_USE_PLATFORM_WAYLAND_KHR\n#ifdef VK_USE_PLATFORM_WAYLAND_KHR\n    PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR GetPhysicalDeviceWaylandPresentationSupportKHR;\n#endif // VK_USE_PLATFORM_WAYLAND_KHR\n\n    // ---- VK_KHR_mir_surface extension commands\n#ifdef VK_USE_PLATFORM_MIR_KHR\n    PFN_vkCreateMirSurfaceKHR CreateMirSurfaceKHR;\n#endif // VK_USE_PLATFORM_MIR_KHR\n#ifdef VK_USE_PLATFORM_MIR_KHR\n    PFN_vkGetPhysicalDeviceMirPresentationSupportKHR GetPhysicalDeviceMirPresentationSupportKHR;\n#endif // VK_USE_PLATFORM_MIR_KHR\n\n    // ---- VK_KHR_android_surface extension commands\n#ifdef VK_USE_PLATFORM_ANDROID_KHR\n    PFN_vkCreateAndroidSurfaceKHR CreateAndroidSurfaceKHR;\n#endif // VK_USE_PLATFORM_ANDROID_KHR\n\n    // ---- VK_KHR_win32_surface extension commands\n#ifdef VK_USE_PLATFORM_WIN32_KHR\n    PFN_vkCreateWin32SurfaceKHR CreateWin32SurfaceKHR;\n#endif // VK_USE_PLATFORM_WIN32_KHR\n#ifdef VK_USE_PLATFORM_WIN32_KHR\n    PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR GetPhysicalDeviceWin32PresentationSupportKHR;\n#endif // VK_USE_PLATFORM_WIN32_KHR\n\n    // ---- VK_KHR_get_physical_device_properties2 extension commands\n    PFN_vkGetPhysicalDeviceFeatures2KHR GetPhysicalDeviceFeatures2KHR;\n    PFN_vkGetPhysicalDeviceProperties2KHR GetPhysicalDeviceProperties2KHR;\n    PFN_vkGetPhysicalDeviceFormatProperties2KHR GetPhysicalDeviceFormatProperties2KHR;\n    PFN_vkGetPhysicalDeviceImageFormatProperties2KHR GetPhysicalDeviceImageFormatProperties2KHR;\n    PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR GetPhysicalDeviceQueueFamilyProperties2KHR;\n    PFN_vkGetPhysicalDeviceMemoryProperties2KHR GetPhysicalDeviceMemoryProperties2KHR;\n    PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR GetPhysicalDeviceSparseImageFormatProperties2KHR;\n\n    // ---- VK_KHR_get_surface_capabilities2 extension commands\n    PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR GetPhysicalDeviceSurfaceCapabilities2KHR;\n    PFN_vkGetPhysicalDeviceSurfaceFormats2KHR GetPhysicalDeviceSurfaceFormats2KHR;\n\n    // ---- VK_EXT_debug_report extension commands\n    PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallbackEXT;\n    PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT;\n    PFN_vkDebugReportMessageEXT DebugReportMessageEXT;\n\n    // ---- VK_NV_external_memory_capabilities extension commands\n    PFN_vkGetPhysicalDeviceExternalImageFormatPropertiesNV GetPhysicalDeviceExternalImageFormatPropertiesNV;\n\n    // ---- VK_KHX_device_group extension commands\n    PFN_vkGetPhysicalDevicePresentRectanglesKHX GetPhysicalDevicePresentRectanglesKHX;\n\n    // ---- VK_NN_vi_surface extension commands\n#ifdef VK_USE_PLATFORM_VI_NN\n    PFN_vkCreateViSurfaceNN CreateViSurfaceNN;\n#endif // VK_USE_PLATFORM_VI_NN\n\n    // ---- VK_KHX_device_group_creation extension commands\n    PFN_vkEnumeratePhysicalDeviceGroupsKHX EnumeratePhysicalDeviceGroupsKHX;\n\n    // ---- VK_KHX_external_memory_capabilities extension commands\n    PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHX GetPhysicalDeviceExternalBufferPropertiesKHX;\n\n    // ---- VK_KHX_external_semaphore_capabilities extension commands\n    PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHX GetPhysicalDeviceExternalSemaphorePropertiesKHX;\n\n    // ---- VK_NVX_device_generated_commands extension commands\n    PFN_vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX GetPhysicalDeviceGeneratedCommandsPropertiesNVX;\n\n    // ---- VK_EXT_direct_mode_display extension commands\n    PFN_vkReleaseDisplayEXT ReleaseDisplayEXT;\n\n    // ---- VK_EXT_acquire_xlib_display extension commands\n#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT\n    PFN_vkAcquireXlibDisplayEXT AcquireXlibDisplayEXT;\n#endif // VK_USE_PLATFORM_XLIB_XRANDR_EXT\n#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT\n    PFN_vkGetRandROutputDisplayEXT GetRandROutputDisplayEXT;\n#endif // VK_USE_PLATFORM_XLIB_XRANDR_EXT\n\n    // ---- VK_EXT_display_surface_counter extension commands\n    PFN_vkGetPhysicalDeviceSurfaceCapabilities2EXT GetPhysicalDeviceSurfaceCapabilities2EXT;\n\n    // ---- VK_MVK_ios_surface extension commands\n#ifdef VK_USE_PLATFORM_IOS_MVK\n    PFN_vkCreateIOSSurfaceMVK CreateIOSSurfaceMVK;\n#endif // VK_USE_PLATFORM_IOS_MVK\n\n    // ---- VK_MVK_macos_surface extension commands\n#ifdef VK_USE_PLATFORM_MACOS_MVK\n    PFN_vkCreateMacOSSurfaceMVK CreateMacOSSurfaceMVK;\n#endif // VK_USE_PLATFORM_MACOS_MVK\n} VkLayerInstanceDispatchTable;\n\n// Device function pointer dispatch table\ntypedef struct VkLayerDispatchTable_ {\n\n    // ---- Core 1_0 commands\n    PFN_vkGetDeviceProcAddr GetDeviceProcAddr;\n    PFN_vkDestroyDevice DestroyDevice;\n    PFN_vkGetDeviceQueue GetDeviceQueue;\n    PFN_vkQueueSubmit QueueSubmit;\n    PFN_vkQueueWaitIdle QueueWaitIdle;\n    PFN_vkDeviceWaitIdle DeviceWaitIdle;\n    PFN_vkAllocateMemory AllocateMemory;\n    PFN_vkFreeMemory FreeMemory;\n    PFN_vkMapMemory MapMemory;\n    PFN_vkUnmapMemory UnmapMemory;\n    PFN_vkFlushMappedMemoryRanges FlushMappedMemoryRanges;\n    PFN_vkInvalidateMappedMemoryRanges InvalidateMappedMemoryRanges;\n    PFN_vkGetDeviceMemoryCommitment GetDeviceMemoryCommitment;\n    PFN_vkBindBufferMemory BindBufferMemory;\n    PFN_vkBindImageMemory BindImageMemory;\n    PFN_vkGetBufferMemoryRequirements GetBufferMemoryRequirements;\n    PFN_vkGetImageMemoryRequirements GetImageMemoryRequirements;\n    PFN_vkGetImageSparseMemoryRequirements GetImageSparseMemoryRequirements;\n    PFN_vkQueueBindSparse QueueBindSparse;\n    PFN_vkCreateFence CreateFence;\n    PFN_vkDestroyFence DestroyFence;\n    PFN_vkResetFences ResetFences;\n    PFN_vkGetFenceStatus GetFenceStatus;\n    PFN_vkWaitForFences WaitForFences;\n    PFN_vkCreateSemaphore CreateSemaphore;\n    PFN_vkDestroySemaphore DestroySemaphore;\n    PFN_vkCreateEvent CreateEvent;\n    PFN_vkDestroyEvent DestroyEvent;\n    PFN_vkGetEventStatus GetEventStatus;\n    PFN_vkSetEvent SetEvent;\n    PFN_vkResetEvent ResetEvent;\n    PFN_vkCreateQueryPool CreateQueryPool;\n    PFN_vkDestroyQueryPool DestroyQueryPool;\n    PFN_vkGetQueryPoolResults GetQueryPoolResults;\n    PFN_vkCreateBuffer CreateBuffer;\n    PFN_vkDestroyBuffer DestroyBuffer;\n    PFN_vkCreateBufferView CreateBufferView;\n    PFN_vkDestroyBufferView DestroyBufferView;\n    PFN_vkCreateImage CreateImage;\n    PFN_vkDestroyImage DestroyImage;\n    PFN_vkGetImageSubresourceLayout GetImageSubresourceLayout;\n    PFN_vkCreateImageView CreateImageView;\n    PFN_vkDestroyImageView DestroyImageView;\n    PFN_vkCreateShaderModule CreateShaderModule;\n    PFN_vkDestroyShaderModule DestroyShaderModule;\n    PFN_vkCreatePipelineCache CreatePipelineCache;\n    PFN_vkDestroyPipelineCache DestroyPipelineCache;\n    PFN_vkGetPipelineCacheData GetPipelineCacheData;\n    PFN_vkMergePipelineCaches MergePipelineCaches;\n    PFN_vkCreateGraphicsPipelines CreateGraphicsPipelines;\n    PFN_vkCreateComputePipelines CreateComputePipelines;\n    PFN_vkDestroyPipeline DestroyPipeline;\n    PFN_vkCreatePipelineLayout CreatePipelineLayout;\n    PFN_vkDestroyPipelineLayout DestroyPipelineLayout;\n    PFN_vkCreateSampler CreateSampler;\n    PFN_vkDestroySampler DestroySampler;\n    PFN_vkCreateDescriptorSetLayout CreateDescriptorSetLayout;\n    PFN_vkDestroyDescriptorSetLayout DestroyDescriptorSetLayout;\n    PFN_vkCreateDescriptorPool CreateDescriptorPool;\n    PFN_vkDestroyDescriptorPool DestroyDescriptorPool;\n    PFN_vkResetDescriptorPool ResetDescriptorPool;\n    PFN_vkAllocateDescriptorSets AllocateDescriptorSets;\n    PFN_vkFreeDescriptorSets FreeDescriptorSets;\n    PFN_vkUpdateDescriptorSets UpdateDescriptorSets;\n    PFN_vkCreateFramebuffer CreateFramebuffer;\n    PFN_vkDestroyFramebuffer DestroyFramebuffer;\n    PFN_vkCreateRenderPass CreateRenderPass;\n    PFN_vkDestroyRenderPass DestroyRenderPass;\n    PFN_vkGetRenderAreaGranularity GetRenderAreaGranularity;\n    PFN_vkCreateCommandPool CreateCommandPool;\n    PFN_vkDestroyCommandPool DestroyCommandPool;\n    PFN_vkResetCommandPool ResetCommandPool;\n    PFN_vkAllocateCommandBuffers AllocateCommandBuffers;\n    PFN_vkFreeCommandBuffers FreeCommandBuffers;\n    PFN_vkBeginCommandBuffer BeginCommandBuffer;\n    PFN_vkEndCommandBuffer EndCommandBuffer;\n    PFN_vkResetCommandBuffer ResetCommandBuffer;\n    PFN_vkCmdBindPipeline CmdBindPipeline;\n    PFN_vkCmdSetViewport CmdSetViewport;\n    PFN_vkCmdSetScissor CmdSetScissor;\n    PFN_vkCmdSetLineWidth CmdSetLineWidth;\n    PFN_vkCmdSetDepthBias CmdSetDepthBias;\n    PFN_vkCmdSetBlendConstants CmdSetBlendConstants;\n    PFN_vkCmdSetDepthBounds CmdSetDepthBounds;\n    PFN_vkCmdSetStencilCompareMask CmdSetStencilCompareMask;\n    PFN_vkCmdSetStencilWriteMask CmdSetStencilWriteMask;\n    PFN_vkCmdSetStencilReference CmdSetStencilReference;\n    PFN_vkCmdBindDescriptorSets CmdBindDescriptorSets;\n    PFN_vkCmdBindIndexBuffer CmdBindIndexBuffer;\n    PFN_vkCmdBindVertexBuffers CmdBindVertexBuffers;\n    PFN_vkCmdDraw CmdDraw;\n    PFN_vkCmdDrawIndexed CmdDrawIndexed;\n    PFN_vkCmdDrawIndirect CmdDrawIndirect;\n    PFN_vkCmdDrawIndexedIndirect CmdDrawIndexedIndirect;\n    PFN_vkCmdDispatch CmdDispatch;\n    PFN_vkCmdDispatchIndirect CmdDispatchIndirect;\n    PFN_vkCmdCopyBuffer CmdCopyBuffer;\n    PFN_vkCmdCopyImage CmdCopyImage;\n    PFN_vkCmdBlitImage CmdBlitImage;\n    PFN_vkCmdCopyBufferToImage CmdCopyBufferToImage;\n    PFN_vkCmdCopyImageToBuffer CmdCopyImageToBuffer;\n    PFN_vkCmdUpdateBuffer CmdUpdateBuffer;\n    PFN_vkCmdFillBuffer CmdFillBuffer;\n    PFN_vkCmdClearColorImage CmdClearColorImage;\n    PFN_vkCmdClearDepthStencilImage CmdClearDepthStencilImage;\n    PFN_vkCmdClearAttachments CmdClearAttachments;\n    PFN_vkCmdResolveImage CmdResolveImage;\n    PFN_vkCmdSetEvent CmdSetEvent;\n    PFN_vkCmdResetEvent CmdResetEvent;\n    PFN_vkCmdWaitEvents CmdWaitEvents;\n    PFN_vkCmdPipelineBarrier CmdPipelineBarrier;\n    PFN_vkCmdBeginQuery CmdBeginQuery;\n    PFN_vkCmdEndQuery CmdEndQuery;\n    PFN_vkCmdResetQueryPool CmdResetQueryPool;\n    PFN_vkCmdWriteTimestamp CmdWriteTimestamp;\n    PFN_vkCmdCopyQueryPoolResults CmdCopyQueryPoolResults;\n    PFN_vkCmdPushConstants CmdPushConstants;\n    PFN_vkCmdBeginRenderPass CmdBeginRenderPass;\n    PFN_vkCmdNextSubpass CmdNextSubpass;\n    PFN_vkCmdEndRenderPass CmdEndRenderPass;\n    PFN_vkCmdExecuteCommands CmdExecuteCommands;\n\n    // ---- VK_KHR_swapchain extension commands\n    PFN_vkCreateSwapchainKHR CreateSwapchainKHR;\n    PFN_vkDestroySwapchainKHR DestroySwapchainKHR;\n    PFN_vkGetSwapchainImagesKHR GetSwapchainImagesKHR;\n    PFN_vkAcquireNextImageKHR AcquireNextImageKHR;\n    PFN_vkQueuePresentKHR QueuePresentKHR;\n\n    // ---- VK_KHR_display_swapchain extension commands\n    PFN_vkCreateSharedSwapchainsKHR CreateSharedSwapchainsKHR;\n\n    // ---- VK_KHR_maintenance1 extension commands\n    PFN_vkTrimCommandPoolKHR TrimCommandPoolKHR;\n\n    // ---- VK_KHR_push_descriptor extension commands\n    PFN_vkCmdPushDescriptorSetKHR CmdPushDescriptorSetKHR;\n\n    // ---- VK_KHR_descriptor_update_template extension commands\n    PFN_vkCreateDescriptorUpdateTemplateKHR CreateDescriptorUpdateTemplateKHR;\n    PFN_vkDestroyDescriptorUpdateTemplateKHR DestroyDescriptorUpdateTemplateKHR;\n    PFN_vkUpdateDescriptorSetWithTemplateKHR UpdateDescriptorSetWithTemplateKHR;\n    PFN_vkCmdPushDescriptorSetWithTemplateKHR CmdPushDescriptorSetWithTemplateKHR;\n\n    // ---- VK_KHR_shared_presentable_image extension commands\n    PFN_vkGetSwapchainStatusKHR GetSwapchainStatusKHR;\n\n    // ---- VK_EXT_debug_marker extension commands\n    PFN_vkDebugMarkerSetObjectTagEXT DebugMarkerSetObjectTagEXT;\n    PFN_vkDebugMarkerSetObjectNameEXT DebugMarkerSetObjectNameEXT;\n    PFN_vkCmdDebugMarkerBeginEXT CmdDebugMarkerBeginEXT;\n    PFN_vkCmdDebugMarkerEndEXT CmdDebugMarkerEndEXT;\n    PFN_vkCmdDebugMarkerInsertEXT CmdDebugMarkerInsertEXT;\n\n    // ---- VK_AMD_draw_indirect_count extension commands\n    PFN_vkCmdDrawIndirectCountAMD CmdDrawIndirectCountAMD;\n    PFN_vkCmdDrawIndexedIndirectCountAMD CmdDrawIndexedIndirectCountAMD;\n\n    // ---- VK_NV_external_memory_win32 extension commands\n#ifdef VK_USE_PLATFORM_WIN32_KHR\n    PFN_vkGetMemoryWin32HandleNV GetMemoryWin32HandleNV;\n#endif // VK_USE_PLATFORM_WIN32_KHR\n\n    // ---- VK_KHX_device_group extension commands\n    PFN_vkGetDeviceGroupPeerMemoryFeaturesKHX GetDeviceGroupPeerMemoryFeaturesKHX;\n    PFN_vkBindBufferMemory2KHX BindBufferMemory2KHX;\n    PFN_vkBindImageMemory2KHX BindImageMemory2KHX;\n    PFN_vkCmdSetDeviceMaskKHX CmdSetDeviceMaskKHX;\n    PFN_vkGetDeviceGroupPresentCapabilitiesKHX GetDeviceGroupPresentCapabilitiesKHX;\n    PFN_vkGetDeviceGroupSurfacePresentModesKHX GetDeviceGroupSurfacePresentModesKHX;\n    PFN_vkAcquireNextImage2KHX AcquireNextImage2KHX;\n    PFN_vkCmdDispatchBaseKHX CmdDispatchBaseKHX;\n\n    // ---- VK_KHX_external_memory_win32 extension commands\n#ifdef VK_USE_PLATFORM_WIN32_KHX\n    PFN_vkGetMemoryWin32HandleKHX GetMemoryWin32HandleKHX;\n#endif // VK_USE_PLATFORM_WIN32_KHX\n#ifdef VK_USE_PLATFORM_WIN32_KHX\n    PFN_vkGetMemoryWin32HandlePropertiesKHX GetMemoryWin32HandlePropertiesKHX;\n#endif // VK_USE_PLATFORM_WIN32_KHX\n\n    // ---- VK_KHX_external_memory_fd extension commands\n    PFN_vkGetMemoryFdKHX GetMemoryFdKHX;\n    PFN_vkGetMemoryFdPropertiesKHX GetMemoryFdPropertiesKHX;\n\n    // ---- VK_KHX_external_semaphore_win32 extension commands\n#ifdef VK_USE_PLATFORM_WIN32_KHX\n    PFN_vkImportSemaphoreWin32HandleKHX ImportSemaphoreWin32HandleKHX;\n#endif // VK_USE_PLATFORM_WIN32_KHX\n#ifdef VK_USE_PLATFORM_WIN32_KHX\n    PFN_vkGetSemaphoreWin32HandleKHX GetSemaphoreWin32HandleKHX;\n#endif // VK_USE_PLATFORM_WIN32_KHX\n\n    // ---- VK_KHX_external_semaphore_fd extension commands\n    PFN_vkImportSemaphoreFdKHX ImportSemaphoreFdKHX;\n    PFN_vkGetSemaphoreFdKHX GetSemaphoreFdKHX;\n\n    // ---- VK_NVX_device_generated_commands extension commands\n    PFN_vkCmdProcessCommandsNVX CmdProcessCommandsNVX;\n    PFN_vkCmdReserveSpaceForCommandsNVX CmdReserveSpaceForCommandsNVX;\n    PFN_vkCreateIndirectCommandsLayoutNVX CreateIndirectCommandsLayoutNVX;\n    PFN_vkDestroyIndirectCommandsLayoutNVX DestroyIndirectCommandsLayoutNVX;\n    PFN_vkCreateObjectTableNVX CreateObjectTableNVX;\n    PFN_vkDestroyObjectTableNVX DestroyObjectTableNVX;\n    PFN_vkRegisterObjectsNVX RegisterObjectsNVX;\n    PFN_vkUnregisterObjectsNVX UnregisterObjectsNVX;\n\n    // ---- VK_NV_clip_space_w_scaling extension commands\n    PFN_vkCmdSetViewportWScalingNV CmdSetViewportWScalingNV;\n\n    // ---- VK_EXT_display_control extension commands\n    PFN_vkDisplayPowerControlEXT DisplayPowerControlEXT;\n    PFN_vkRegisterDeviceEventEXT RegisterDeviceEventEXT;\n    PFN_vkRegisterDisplayEventEXT RegisterDisplayEventEXT;\n    PFN_vkGetSwapchainCounterEXT GetSwapchainCounterEXT;\n\n    // ---- VK_GOOGLE_display_timing extension commands\n    PFN_vkGetRefreshCycleDurationGOOGLE GetRefreshCycleDurationGOOGLE;\n    PFN_vkGetPastPresentationTimingGOOGLE GetPastPresentationTimingGOOGLE;\n\n    // ---- VK_EXT_discard_rectangles extension commands\n    PFN_vkCmdSetDiscardRectangleEXT CmdSetDiscardRectangleEXT;\n\n    // ---- VK_EXT_hdr_metadata extension commands\n    PFN_vkSetHdrMetadataEXT SetHdrMetadataEXT;\n} VkLayerDispatchTable;\n\n\n"
  },
  {
    "path": "src/engine/renderer/vulkan/vk_platform.h",
    "content": "//\n// File: vk_platform.h\n//\n/*\n** Copyright (c) 2014-2017 The Khronos Group Inc.\n**\n** Licensed under the Apache License, Version 2.0 (the \"License\");\n** you may not use this file except in compliance with the License.\n** You may obtain a copy of the License at\n**\n**     http://www.apache.org/licenses/LICENSE-2.0\n**\n** Unless required by applicable law or agreed to in writing, software\n** distributed under the License is distributed on an \"AS IS\" BASIS,\n** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n** See the License for the specific language governing permissions and\n** limitations under the License.\n*/\n\n\n#ifndef VK_PLATFORM_H_\n#define VK_PLATFORM_H_\n\n#ifdef __cplusplus\nextern \"C\"\n{\n#endif // __cplusplus\n\n/*\n***************************************************************************************************\n*   Platform-specific directives and type declarations\n***************************************************************************************************\n*/\n\n/* Platform-specific calling convention macros.\n *\n * Platforms should define these so that Vulkan clients call Vulkan commands\n * with the same calling conventions that the Vulkan implementation expects.\n *\n * VKAPI_ATTR - Placed before the return type in function declarations.\n *              Useful for C++11 and GCC/Clang-style function attribute syntax.\n * VKAPI_CALL - Placed after the return type in function declarations.\n *              Useful for MSVC-style calling convention syntax.\n * VKAPI_PTR  - Placed between the '(' and '*' in function pointer types.\n *\n * Function declaration:  VKAPI_ATTR void VKAPI_CALL vkCommand(void);\n * Function pointer type: typedef void (VKAPI_PTR *PFN_vkCommand)(void);\n */\n#if defined(_WIN32)\n    // On Windows, Vulkan commands use the stdcall convention\n    #define VKAPI_ATTR\n    #define VKAPI_CALL __stdcall\n    #define VKAPI_PTR  VKAPI_CALL\n#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH < 7\n    #error \"Vulkan isn't supported for the 'armeabi' NDK ABI\"\n#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7 && defined(__ARM_32BIT_STATE)\n    // On Android 32-bit ARM targets, Vulkan functions use the \"hardfloat\"\n    // calling convention, i.e. float parameters are passed in registers. This\n    // is true even if the rest of the application passes floats on the stack,\n    // as it does by default when compiling for the armeabi-v7a NDK ABI.\n    #define VKAPI_ATTR __attribute__((pcs(\"aapcs-vfp\")))\n    #define VKAPI_CALL\n    #define VKAPI_PTR  VKAPI_ATTR\n#else\n    // On other platforms, use the default calling convention\n    #define VKAPI_ATTR\n    #define VKAPI_CALL\n    #define VKAPI_PTR\n#endif\n\n#include <stddef.h>\n\n#if !defined(VK_NO_STDINT_H)\n    #if defined(_MSC_VER) && (_MSC_VER < 1600)\n        typedef signed   __int8  int8_t;\n        typedef unsigned __int8  uint8_t;\n        typedef signed   __int16 int16_t;\n        typedef unsigned __int16 uint16_t;\n        typedef signed   __int32 int32_t;\n        typedef unsigned __int32 uint32_t;\n        typedef signed   __int64 int64_t;\n        typedef unsigned __int64 uint64_t;\n    #else\n        #include <stdint.h>\n    #endif\n#endif // !defined(VK_NO_STDINT_H)\n\n#ifdef __cplusplus\n} // extern \"C\"\n#endif // __cplusplus\n\n// Platform-specific headers required by platform window system extensions.\n// These are enabled prior to #including \"vulkan.h\". The same enable then\n// controls inclusion of the extension interfaces in vulkan.h.\n\n#ifdef VK_USE_PLATFORM_ANDROID_KHR\n#include <android/native_window.h>\n#endif\n\n#ifdef VK_USE_PLATFORM_MIR_KHR\n#include <mir_toolkit/client_types.h>\n#endif\n\n#ifdef VK_USE_PLATFORM_WAYLAND_KHR\n#include <wayland-client.h>\n#endif\n\n#ifdef VK_USE_PLATFORM_WIN32_KHR\n#include <windows.h>\n#endif\n\n#ifdef VK_USE_PLATFORM_XLIB_KHR\n#include <X11/Xlib.h>\n#endif\n\n#ifdef VK_USE_PLATFORM_XCB_KHR\n#include <xcb/xcb.h>\n#endif\n\n#endif\n"
  },
  {
    "path": "src/engine/renderer/vulkan/vk_sdk_platform.h",
    "content": "//\n// File: vk_sdk_platform.h\n//\n/*\n * Copyright (c) 2015-2016 The Khronos Group Inc.\n * Copyright (c) 2015-2016 Valve Corporation\n * Copyright (c) 2015-2016 LunarG, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef VK_SDK_PLATFORM_H\n#define VK_SDK_PLATFORM_H\n\n#if defined(_WIN32)\n#define NOMINMAX\n#ifndef __cplusplus\n#undef inline\n#define inline __inline\n#endif // __cplusplus\n\n#if (defined(_MSC_VER) && _MSC_VER < 1900 /*vs2015*/)\n// C99:\n// Microsoft didn't implement C99 in Visual Studio; but started adding it with\n// VS2013.  However, VS2013 still didn't have snprintf().  The following is a\n// work-around (Note: The _CRT_SECURE_NO_WARNINGS macro must be set in the\n// \"CMakeLists.txt\" file).\n// NOTE: This is fixed in Visual Studio 2015.\n#define snprintf _snprintf\n#endif\n\n#define strdup _strdup\n\n#endif // _WIN32\n\n#endif // VK_SDK_PLATFORM_H\n"
  },
  {
    "path": "src/engine/renderer/vulkan/vulkan.h",
    "content": "#ifndef VULKAN_H_\n#define VULKAN_H_ 1\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*\n** Copyright (c) 2015-2017 The Khronos Group Inc.\n**\n** Licensed under the Apache License, Version 2.0 (the \"License\");\n** you may not use this file except in compliance with the License.\n** You may obtain a copy of the License at\n**\n**     http://www.apache.org/licenses/LICENSE-2.0\n**\n** Unless required by applicable law or agreed to in writing, software\n** distributed under the License is distributed on an \"AS IS\" BASIS,\n** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n** See the License for the specific language governing permissions and\n** limitations under the License.\n*/\n\n/*\n** This header is generated from the Khronos Vulkan XML API Registry.\n**\n*/\n\n\n#define VK_VERSION_1_0 1\n#include \"vk_platform.h\"\n\n#define VK_MAKE_VERSION(major, minor, patch) \\\n    (((major) << 22) | ((minor) << 12) | (patch))\n\n// DEPRECATED: This define has been removed. Specific version defines (e.g. VK_API_VERSION_1_0), or the VK_MAKE_VERSION macro, should be used instead.\n//#define VK_API_VERSION VK_MAKE_VERSION(1, 0, 0)\n\n// Vulkan 1.0 version number\n#define VK_API_VERSION_1_0 VK_MAKE_VERSION(1, 0, 0)\n\n#define VK_VERSION_MAJOR(version) ((uint32_t)(version) >> 22)\n#define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff)\n#define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff)\n// Version of this file\n#define VK_HEADER_VERSION 49\n\n\n#define VK_NULL_HANDLE 0\n        \n\n\n#define VK_DEFINE_HANDLE(object) typedef struct object##_T* object;\n\n\n#if !defined(VK_DEFINE_NON_DISPATCHABLE_HANDLE)\n#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)\n        #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object;\n#else\n        #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object;\n#endif\n#endif\n        \n\n\ntypedef uint32_t VkFlags;\ntypedef uint32_t VkBool32;\ntypedef uint64_t VkDeviceSize;\ntypedef uint32_t VkSampleMask;\n\nVK_DEFINE_HANDLE(VkInstance)\nVK_DEFINE_HANDLE(VkPhysicalDevice)\nVK_DEFINE_HANDLE(VkDevice)\nVK_DEFINE_HANDLE(VkQueue)\nVK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSemaphore)\nVK_DEFINE_HANDLE(VkCommandBuffer)\nVK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFence)\nVK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDeviceMemory)\nVK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBuffer)\nVK_DEFINE_NON_DISPATCHABLE_HANDLE(VkImage)\nVK_DEFINE_NON_DISPATCHABLE_HANDLE(VkEvent)\nVK_DEFINE_NON_DISPATCHABLE_HANDLE(VkQueryPool)\nVK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBufferView)\nVK_DEFINE_NON_DISPATCHABLE_HANDLE(VkImageView)\nVK_DEFINE_NON_DISPATCHABLE_HANDLE(VkShaderModule)\nVK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipelineCache)\nVK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipelineLayout)\nVK_DEFINE_NON_DISPATCHABLE_HANDLE(VkRenderPass)\nVK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipeline)\nVK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorSetLayout)\nVK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSampler)\nVK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorPool)\nVK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorSet)\nVK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFramebuffer)\nVK_DEFINE_NON_DISPATCHABLE_HANDLE(VkCommandPool)\n\n#define VK_LOD_CLAMP_NONE                 1000.0f\n#define VK_REMAINING_MIP_LEVELS           (~0U)\n#define VK_REMAINING_ARRAY_LAYERS         (~0U)\n#define VK_WHOLE_SIZE                     (~0ULL)\n#define VK_ATTACHMENT_UNUSED              (~0U)\n#define VK_TRUE                           1\n#define VK_FALSE                          0\n#define VK_QUEUE_FAMILY_IGNORED           (~0U)\n#define VK_SUBPASS_EXTERNAL               (~0U)\n#define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE  256\n#define VK_UUID_SIZE                      16\n#define VK_MAX_MEMORY_TYPES               32\n#define VK_MAX_MEMORY_HEAPS               16\n#define VK_MAX_EXTENSION_NAME_SIZE        256\n#define VK_MAX_DESCRIPTION_SIZE           256\n\n\ntypedef enum VkPipelineCacheHeaderVersion {\n    VK_PIPELINE_CACHE_HEADER_VERSION_ONE = 1,\n    VK_PIPELINE_CACHE_HEADER_VERSION_BEGIN_RANGE = VK_PIPELINE_CACHE_HEADER_VERSION_ONE,\n    VK_PIPELINE_CACHE_HEADER_VERSION_END_RANGE = VK_PIPELINE_CACHE_HEADER_VERSION_ONE,\n    VK_PIPELINE_CACHE_HEADER_VERSION_RANGE_SIZE = (VK_PIPELINE_CACHE_HEADER_VERSION_ONE - VK_PIPELINE_CACHE_HEADER_VERSION_ONE + 1),\n    VK_PIPELINE_CACHE_HEADER_VERSION_MAX_ENUM = 0x7FFFFFFF\n} VkPipelineCacheHeaderVersion;\n\ntypedef enum VkResult {\n    VK_SUCCESS = 0,\n    VK_NOT_READY = 1,\n    VK_TIMEOUT = 2,\n    VK_EVENT_SET = 3,\n    VK_EVENT_RESET = 4,\n    VK_INCOMPLETE = 5,\n    VK_ERROR_OUT_OF_HOST_MEMORY = -1,\n    VK_ERROR_OUT_OF_DEVICE_MEMORY = -2,\n    VK_ERROR_INITIALIZATION_FAILED = -3,\n    VK_ERROR_DEVICE_LOST = -4,\n    VK_ERROR_MEMORY_MAP_FAILED = -5,\n    VK_ERROR_LAYER_NOT_PRESENT = -6,\n    VK_ERROR_EXTENSION_NOT_PRESENT = -7,\n    VK_ERROR_FEATURE_NOT_PRESENT = -8,\n    VK_ERROR_INCOMPATIBLE_DRIVER = -9,\n    VK_ERROR_TOO_MANY_OBJECTS = -10,\n    VK_ERROR_FORMAT_NOT_SUPPORTED = -11,\n    VK_ERROR_FRAGMENTED_POOL = -12,\n    VK_ERROR_SURFACE_LOST_KHR = -1000000000,\n    VK_ERROR_NATIVE_WINDOW_IN_USE_KHR = -1000000001,\n    VK_SUBOPTIMAL_KHR = 1000001003,\n    VK_ERROR_OUT_OF_DATE_KHR = -1000001004,\n    VK_ERROR_INCOMPATIBLE_DISPLAY_KHR = -1000003001,\n    VK_ERROR_VALIDATION_FAILED_EXT = -1000011001,\n    VK_ERROR_INVALID_SHADER_NV = -1000012000,\n    VK_ERROR_OUT_OF_POOL_MEMORY_KHR = -1000069000,\n    VK_ERROR_INVALID_EXTERNAL_HANDLE_KHX = -1000072003,\n    VK_RESULT_BEGIN_RANGE = VK_ERROR_FRAGMENTED_POOL,\n    VK_RESULT_END_RANGE = VK_INCOMPLETE,\n    VK_RESULT_RANGE_SIZE = (VK_INCOMPLETE - VK_ERROR_FRAGMENTED_POOL + 1),\n    VK_RESULT_MAX_ENUM = 0x7FFFFFFF\n} VkResult;\n\ntypedef enum VkStructureType {\n    VK_STRUCTURE_TYPE_APPLICATION_INFO = 0,\n    VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO = 1,\n    VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO = 2,\n    VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO = 3,\n    VK_STRUCTURE_TYPE_SUBMIT_INFO = 4,\n    VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO = 5,\n    VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE = 6,\n    VK_STRUCTURE_TYPE_BIND_SPARSE_INFO = 7,\n    VK_STRUCTURE_TYPE_FENCE_CREATE_INFO = 8,\n    VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO = 9,\n    VK_STRUCTURE_TYPE_EVENT_CREATE_INFO = 10,\n    VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO = 11,\n    VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO = 12,\n    VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO = 13,\n    VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO = 14,\n    VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO = 15,\n    VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO = 16,\n    VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO = 17,\n    VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO = 18,\n    VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO = 19,\n    VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO = 20,\n    VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO = 21,\n    VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO = 22,\n    VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO = 23,\n    VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO = 24,\n    VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO = 25,\n    VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO = 26,\n    VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO = 27,\n    VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO = 28,\n    VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO = 29,\n    VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO = 30,\n    VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO = 31,\n    VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO = 32,\n    VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO = 33,\n    VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO = 34,\n    VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET = 35,\n    VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET = 36,\n    VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO = 37,\n    VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO = 38,\n    VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO = 39,\n    VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO = 40,\n    VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO = 41,\n    VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO = 42,\n    VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO = 43,\n    VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER = 44,\n    VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER = 45,\n    VK_STRUCTURE_TYPE_MEMORY_BARRIER = 46,\n    VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO = 47,\n    VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO = 48,\n    VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR = 1000001000,\n    VK_STRUCTURE_TYPE_PRESENT_INFO_KHR = 1000001001,\n    VK_STRUCTURE_TYPE_DISPLAY_MODE_CREATE_INFO_KHR = 1000002000,\n    VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR = 1000002001,\n    VK_STRUCTURE_TYPE_DISPLAY_PRESENT_INFO_KHR = 1000003000,\n    VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR = 1000004000,\n    VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR = 1000005000,\n    VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR = 1000006000,\n    VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR = 1000007000,\n    VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR = 1000008000,\n    VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR = 1000009000,\n    VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT = 1000011000,\n    VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_RASTERIZATION_ORDER_AMD = 1000018000,\n    VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_NAME_INFO_EXT = 1000022000,\n    VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_TAG_INFO_EXT = 1000022001,\n    VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT = 1000022002,\n    VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_IMAGE_CREATE_INFO_NV = 1000026000,\n    VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_BUFFER_CREATE_INFO_NV = 1000026001,\n    VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV = 1000026002,\n    VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO_KHX = 1000053000,\n    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHX = 1000053001,\n    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHX = 1000053002,\n    VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_NV = 1000056000,\n    VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_NV = 1000056001,\n    VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_NV = 1000057000,\n    VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_NV = 1000057001,\n    VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_NV = 1000058000,\n    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR = 1000059000,\n    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR = 1000059001,\n    VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2_KHR = 1000059002,\n    VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHR = 1000059003,\n    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHR = 1000059004,\n    VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR = 1000059005,\n    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR = 1000059006,\n    VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2_KHR = 1000059007,\n    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2_KHR = 1000059008,\n    VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHX = 1000060000,\n    VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO_KHX = 1000060001,\n    VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHX = 1000060002,\n    VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO_KHX = 1000060003,\n    VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO_KHX = 1000060004,\n    VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO_KHX = 1000060005,\n    VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO_KHX = 1000060006,\n    VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHX = 1000060007,\n    VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHX = 1000060008,\n    VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHX = 1000060009,\n    VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHX = 1000060010,\n    VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_INFO_KHX = 1000060011,\n    VK_STRUCTURE_TYPE_DEVICE_GROUP_SWAPCHAIN_CREATE_INFO_KHX = 1000060012,\n    VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT = 1000061000,\n    VK_STRUCTURE_TYPE_VI_SURFACE_CREATE_INFO_NN = 1000062000,\n    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES_KHX = 1000070000,\n    VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHX = 1000070001,\n    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO_KHX = 1000071000,\n    VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHX = 1000071001,\n    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO_KHX = 1000071002,\n    VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES_KHX = 1000071003,\n    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHX = 1000071004,\n    VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHX = 1000072000,\n    VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHX = 1000072001,\n    VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHX = 1000072002,\n    VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHX = 1000073000,\n    VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHX = 1000073001,\n    VK_STRUCTURE_TYPE_MEMORY_WIN32_HANDLE_PROPERTIES_KHX = 1000073002,\n    VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHX = 1000074000,\n    VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHX = 1000074001,\n    VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_KHX = 1000075000,\n    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO_KHX = 1000076000,\n    VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES_KHX = 1000076001,\n    VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO_KHX = 1000077000,\n    VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHX = 1000078000,\n    VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHX = 1000078001,\n    VK_STRUCTURE_TYPE_D3D12_FENCE_SUBMIT_INFO_KHX = 1000078002,\n    VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHX = 1000079000,\n    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR = 1000080000,\n    VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR = 1000084000,\n    VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR = 1000085000,\n    VK_STRUCTURE_TYPE_OBJECT_TABLE_CREATE_INFO_NVX = 1000086000,\n    VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_CREATE_INFO_NVX = 1000086001,\n    VK_STRUCTURE_TYPE_CMD_PROCESS_COMMANDS_INFO_NVX = 1000086002,\n    VK_STRUCTURE_TYPE_CMD_RESERVE_SPACE_FOR_COMMANDS_INFO_NVX = 1000086003,\n    VK_STRUCTURE_TYPE_DEVICE_GENERATED_COMMANDS_LIMITS_NVX = 1000086004,\n    VK_STRUCTURE_TYPE_DEVICE_GENERATED_COMMANDS_FEATURES_NVX = 1000086005,\n    VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_W_SCALING_STATE_CREATE_INFO_NV = 1000087000,\n    VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES2_EXT = 1000090000,\n    VK_STRUCTURE_TYPE_DISPLAY_POWER_INFO_EXT = 1000091000,\n    VK_STRUCTURE_TYPE_DEVICE_EVENT_INFO_EXT = 1000091001,\n    VK_STRUCTURE_TYPE_DISPLAY_EVENT_INFO_EXT = 1000091002,\n    VK_STRUCTURE_TYPE_SWAPCHAIN_COUNTER_CREATE_INFO_EXT = 1000091003,\n    VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE = 1000092000,\n    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_ATTRIBUTES_PROPERTIES_NVX = 1000097000,\n    VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV = 1000098000,\n    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT = 1000099000,\n    VK_STRUCTURE_TYPE_PIPELINE_DISCARD_RECTANGLE_STATE_CREATE_INFO_EXT = 1000099001,\n    VK_STRUCTURE_TYPE_HDR_METADATA_EXT = 1000105000,\n    VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR = 1000111000,\n    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR = 1000119000,\n    VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR = 1000119001,\n    VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR = 1000119002,\n    VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK = 1000122000,\n    VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK = 1000123000,\n    VK_STRUCTURE_TYPE_BEGIN_RANGE = VK_STRUCTURE_TYPE_APPLICATION_INFO,\n    VK_STRUCTURE_TYPE_END_RANGE = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO,\n    VK_STRUCTURE_TYPE_RANGE_SIZE = (VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO - VK_STRUCTURE_TYPE_APPLICATION_INFO + 1),\n    VK_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF\n} VkStructureType;\n\ntypedef enum VkSystemAllocationScope {\n    VK_SYSTEM_ALLOCATION_SCOPE_COMMAND = 0,\n    VK_SYSTEM_ALLOCATION_SCOPE_OBJECT = 1,\n    VK_SYSTEM_ALLOCATION_SCOPE_CACHE = 2,\n    VK_SYSTEM_ALLOCATION_SCOPE_DEVICE = 3,\n    VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE = 4,\n    VK_SYSTEM_ALLOCATION_SCOPE_BEGIN_RANGE = VK_SYSTEM_ALLOCATION_SCOPE_COMMAND,\n    VK_SYSTEM_ALLOCATION_SCOPE_END_RANGE = VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE,\n    VK_SYSTEM_ALLOCATION_SCOPE_RANGE_SIZE = (VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE - VK_SYSTEM_ALLOCATION_SCOPE_COMMAND + 1),\n    VK_SYSTEM_ALLOCATION_SCOPE_MAX_ENUM = 0x7FFFFFFF\n} VkSystemAllocationScope;\n\ntypedef enum VkInternalAllocationType {\n    VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE = 0,\n    VK_INTERNAL_ALLOCATION_TYPE_BEGIN_RANGE = VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE,\n    VK_INTERNAL_ALLOCATION_TYPE_END_RANGE = VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE,\n    VK_INTERNAL_ALLOCATION_TYPE_RANGE_SIZE = (VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE - VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE + 1),\n    VK_INTERNAL_ALLOCATION_TYPE_MAX_ENUM = 0x7FFFFFFF\n} VkInternalAllocationType;\n\ntypedef enum VkFormat {\n    VK_FORMAT_UNDEFINED = 0,\n    VK_FORMAT_R4G4_UNORM_PACK8 = 1,\n    VK_FORMAT_R4G4B4A4_UNORM_PACK16 = 2,\n    VK_FORMAT_B4G4R4A4_UNORM_PACK16 = 3,\n    VK_FORMAT_R5G6B5_UNORM_PACK16 = 4,\n    VK_FORMAT_B5G6R5_UNORM_PACK16 = 5,\n    VK_FORMAT_R5G5B5A1_UNORM_PACK16 = 6,\n    VK_FORMAT_B5G5R5A1_UNORM_PACK16 = 7,\n    VK_FORMAT_A1R5G5B5_UNORM_PACK16 = 8,\n    VK_FORMAT_R8_UNORM = 9,\n    VK_FORMAT_R8_SNORM = 10,\n    VK_FORMAT_R8_USCALED = 11,\n    VK_FORMAT_R8_SSCALED = 12,\n    VK_FORMAT_R8_UINT = 13,\n    VK_FORMAT_R8_SINT = 14,\n    VK_FORMAT_R8_SRGB = 15,\n    VK_FORMAT_R8G8_UNORM = 16,\n    VK_FORMAT_R8G8_SNORM = 17,\n    VK_FORMAT_R8G8_USCALED = 18,\n    VK_FORMAT_R8G8_SSCALED = 19,\n    VK_FORMAT_R8G8_UINT = 20,\n    VK_FORMAT_R8G8_SINT = 21,\n    VK_FORMAT_R8G8_SRGB = 22,\n    VK_FORMAT_R8G8B8_UNORM = 23,\n    VK_FORMAT_R8G8B8_SNORM = 24,\n    VK_FORMAT_R8G8B8_USCALED = 25,\n    VK_FORMAT_R8G8B8_SSCALED = 26,\n    VK_FORMAT_R8G8B8_UINT = 27,\n    VK_FORMAT_R8G8B8_SINT = 28,\n    VK_FORMAT_R8G8B8_SRGB = 29,\n    VK_FORMAT_B8G8R8_UNORM = 30,\n    VK_FORMAT_B8G8R8_SNORM = 31,\n    VK_FORMAT_B8G8R8_USCALED = 32,\n    VK_FORMAT_B8G8R8_SSCALED = 33,\n    VK_FORMAT_B8G8R8_UINT = 34,\n    VK_FORMAT_B8G8R8_SINT = 35,\n    VK_FORMAT_B8G8R8_SRGB = 36,\n    VK_FORMAT_R8G8B8A8_UNORM = 37,\n    VK_FORMAT_R8G8B8A8_SNORM = 38,\n    VK_FORMAT_R8G8B8A8_USCALED = 39,\n    VK_FORMAT_R8G8B8A8_SSCALED = 40,\n    VK_FORMAT_R8G8B8A8_UINT = 41,\n    VK_FORMAT_R8G8B8A8_SINT = 42,\n    VK_FORMAT_R8G8B8A8_SRGB = 43,\n    VK_FORMAT_B8G8R8A8_UNORM = 44,\n    VK_FORMAT_B8G8R8A8_SNORM = 45,\n    VK_FORMAT_B8G8R8A8_USCALED = 46,\n    VK_FORMAT_B8G8R8A8_SSCALED = 47,\n    VK_FORMAT_B8G8R8A8_UINT = 48,\n    VK_FORMAT_B8G8R8A8_SINT = 49,\n    VK_FORMAT_B8G8R8A8_SRGB = 50,\n    VK_FORMAT_A8B8G8R8_UNORM_PACK32 = 51,\n    VK_FORMAT_A8B8G8R8_SNORM_PACK32 = 52,\n    VK_FORMAT_A8B8G8R8_USCALED_PACK32 = 53,\n    VK_FORMAT_A8B8G8R8_SSCALED_PACK32 = 54,\n    VK_FORMAT_A8B8G8R8_UINT_PACK32 = 55,\n    VK_FORMAT_A8B8G8R8_SINT_PACK32 = 56,\n    VK_FORMAT_A8B8G8R8_SRGB_PACK32 = 57,\n    VK_FORMAT_A2R10G10B10_UNORM_PACK32 = 58,\n    VK_FORMAT_A2R10G10B10_SNORM_PACK32 = 59,\n    VK_FORMAT_A2R10G10B10_USCALED_PACK32 = 60,\n    VK_FORMAT_A2R10G10B10_SSCALED_PACK32 = 61,\n    VK_FORMAT_A2R10G10B10_UINT_PACK32 = 62,\n    VK_FORMAT_A2R10G10B10_SINT_PACK32 = 63,\n    VK_FORMAT_A2B10G10R10_UNORM_PACK32 = 64,\n    VK_FORMAT_A2B10G10R10_SNORM_PACK32 = 65,\n    VK_FORMAT_A2B10G10R10_USCALED_PACK32 = 66,\n    VK_FORMAT_A2B10G10R10_SSCALED_PACK32 = 67,\n    VK_FORMAT_A2B10G10R10_UINT_PACK32 = 68,\n    VK_FORMAT_A2B10G10R10_SINT_PACK32 = 69,\n    VK_FORMAT_R16_UNORM = 70,\n    VK_FORMAT_R16_SNORM = 71,\n    VK_FORMAT_R16_USCALED = 72,\n    VK_FORMAT_R16_SSCALED = 73,\n    VK_FORMAT_R16_UINT = 74,\n    VK_FORMAT_R16_SINT = 75,\n    VK_FORMAT_R16_SFLOAT = 76,\n    VK_FORMAT_R16G16_UNORM = 77,\n    VK_FORMAT_R16G16_SNORM = 78,\n    VK_FORMAT_R16G16_USCALED = 79,\n    VK_FORMAT_R16G16_SSCALED = 80,\n    VK_FORMAT_R16G16_UINT = 81,\n    VK_FORMAT_R16G16_SINT = 82,\n    VK_FORMAT_R16G16_SFLOAT = 83,\n    VK_FORMAT_R16G16B16_UNORM = 84,\n    VK_FORMAT_R16G16B16_SNORM = 85,\n    VK_FORMAT_R16G16B16_USCALED = 86,\n    VK_FORMAT_R16G16B16_SSCALED = 87,\n    VK_FORMAT_R16G16B16_UINT = 88,\n    VK_FORMAT_R16G16B16_SINT = 89,\n    VK_FORMAT_R16G16B16_SFLOAT = 90,\n    VK_FORMAT_R16G16B16A16_UNORM = 91,\n    VK_FORMAT_R16G16B16A16_SNORM = 92,\n    VK_FORMAT_R16G16B16A16_USCALED = 93,\n    VK_FORMAT_R16G16B16A16_SSCALED = 94,\n    VK_FORMAT_R16G16B16A16_UINT = 95,\n    VK_FORMAT_R16G16B16A16_SINT = 96,\n    VK_FORMAT_R16G16B16A16_SFLOAT = 97,\n    VK_FORMAT_R32_UINT = 98,\n    VK_FORMAT_R32_SINT = 99,\n    VK_FORMAT_R32_SFLOAT = 100,\n    VK_FORMAT_R32G32_UINT = 101,\n    VK_FORMAT_R32G32_SINT = 102,\n    VK_FORMAT_R32G32_SFLOAT = 103,\n    VK_FORMAT_R32G32B32_UINT = 104,\n    VK_FORMAT_R32G32B32_SINT = 105,\n    VK_FORMAT_R32G32B32_SFLOAT = 106,\n    VK_FORMAT_R32G32B32A32_UINT = 107,\n    VK_FORMAT_R32G32B32A32_SINT = 108,\n    VK_FORMAT_R32G32B32A32_SFLOAT = 109,\n    VK_FORMAT_R64_UINT = 110,\n    VK_FORMAT_R64_SINT = 111,\n    VK_FORMAT_R64_SFLOAT = 112,\n    VK_FORMAT_R64G64_UINT = 113,\n    VK_FORMAT_R64G64_SINT = 114,\n    VK_FORMAT_R64G64_SFLOAT = 115,\n    VK_FORMAT_R64G64B64_UINT = 116,\n    VK_FORMAT_R64G64B64_SINT = 117,\n    VK_FORMAT_R64G64B64_SFLOAT = 118,\n    VK_FORMAT_R64G64B64A64_UINT = 119,\n    VK_FORMAT_R64G64B64A64_SINT = 120,\n    VK_FORMAT_R64G64B64A64_SFLOAT = 121,\n    VK_FORMAT_B10G11R11_UFLOAT_PACK32 = 122,\n    VK_FORMAT_E5B9G9R9_UFLOAT_PACK32 = 123,\n    VK_FORMAT_D16_UNORM = 124,\n    VK_FORMAT_X8_D24_UNORM_PACK32 = 125,\n    VK_FORMAT_D32_SFLOAT = 126,\n    VK_FORMAT_S8_UINT = 127,\n    VK_FORMAT_D16_UNORM_S8_UINT = 128,\n    VK_FORMAT_D24_UNORM_S8_UINT = 129,\n    VK_FORMAT_D32_SFLOAT_S8_UINT = 130,\n    VK_FORMAT_BC1_RGB_UNORM_BLOCK = 131,\n    VK_FORMAT_BC1_RGB_SRGB_BLOCK = 132,\n    VK_FORMAT_BC1_RGBA_UNORM_BLOCK = 133,\n    VK_FORMAT_BC1_RGBA_SRGB_BLOCK = 134,\n    VK_FORMAT_BC2_UNORM_BLOCK = 135,\n    VK_FORMAT_BC2_SRGB_BLOCK = 136,\n    VK_FORMAT_BC3_UNORM_BLOCK = 137,\n    VK_FORMAT_BC3_SRGB_BLOCK = 138,\n    VK_FORMAT_BC4_UNORM_BLOCK = 139,\n    VK_FORMAT_BC4_SNORM_BLOCK = 140,\n    VK_FORMAT_BC5_UNORM_BLOCK = 141,\n    VK_FORMAT_BC5_SNORM_BLOCK = 142,\n    VK_FORMAT_BC6H_UFLOAT_BLOCK = 143,\n    VK_FORMAT_BC6H_SFLOAT_BLOCK = 144,\n    VK_FORMAT_BC7_UNORM_BLOCK = 145,\n    VK_FORMAT_BC7_SRGB_BLOCK = 146,\n    VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK = 147,\n    VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK = 148,\n    VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK = 149,\n    VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK = 150,\n    VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK = 151,\n    VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK = 152,\n    VK_FORMAT_EAC_R11_UNORM_BLOCK = 153,\n    VK_FORMAT_EAC_R11_SNORM_BLOCK = 154,\n    VK_FORMAT_EAC_R11G11_UNORM_BLOCK = 155,\n    VK_FORMAT_EAC_R11G11_SNORM_BLOCK = 156,\n    VK_FORMAT_ASTC_4x4_UNORM_BLOCK = 157,\n    VK_FORMAT_ASTC_4x4_SRGB_BLOCK = 158,\n    VK_FORMAT_ASTC_5x4_UNORM_BLOCK = 159,\n    VK_FORMAT_ASTC_5x4_SRGB_BLOCK = 160,\n    VK_FORMAT_ASTC_5x5_UNORM_BLOCK = 161,\n    VK_FORMAT_ASTC_5x5_SRGB_BLOCK = 162,\n    VK_FORMAT_ASTC_6x5_UNORM_BLOCK = 163,\n    VK_FORMAT_ASTC_6x5_SRGB_BLOCK = 164,\n    VK_FORMAT_ASTC_6x6_UNORM_BLOCK = 165,\n    VK_FORMAT_ASTC_6x6_SRGB_BLOCK = 166,\n    VK_FORMAT_ASTC_8x5_UNORM_BLOCK = 167,\n    VK_FORMAT_ASTC_8x5_SRGB_BLOCK = 168,\n    VK_FORMAT_ASTC_8x6_UNORM_BLOCK = 169,\n    VK_FORMAT_ASTC_8x6_SRGB_BLOCK = 170,\n    VK_FORMAT_ASTC_8x8_UNORM_BLOCK = 171,\n    VK_FORMAT_ASTC_8x8_SRGB_BLOCK = 172,\n    VK_FORMAT_ASTC_10x5_UNORM_BLOCK = 173,\n    VK_FORMAT_ASTC_10x5_SRGB_BLOCK = 174,\n    VK_FORMAT_ASTC_10x6_UNORM_BLOCK = 175,\n    VK_FORMAT_ASTC_10x6_SRGB_BLOCK = 176,\n    VK_FORMAT_ASTC_10x8_UNORM_BLOCK = 177,\n    VK_FORMAT_ASTC_10x8_SRGB_BLOCK = 178,\n    VK_FORMAT_ASTC_10x10_UNORM_BLOCK = 179,\n    VK_FORMAT_ASTC_10x10_SRGB_BLOCK = 180,\n    VK_FORMAT_ASTC_12x10_UNORM_BLOCK = 181,\n    VK_FORMAT_ASTC_12x10_SRGB_BLOCK = 182,\n    VK_FORMAT_ASTC_12x12_UNORM_BLOCK = 183,\n    VK_FORMAT_ASTC_12x12_SRGB_BLOCK = 184,\n    VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG = 1000054000,\n    VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG = 1000054001,\n    VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG = 1000054002,\n    VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG = 1000054003,\n    VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG = 1000054004,\n    VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG = 1000054005,\n    VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG = 1000054006,\n    VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG = 1000054007,\n    VK_FORMAT_BEGIN_RANGE = VK_FORMAT_UNDEFINED,\n    VK_FORMAT_END_RANGE = VK_FORMAT_ASTC_12x12_SRGB_BLOCK,\n    VK_FORMAT_RANGE_SIZE = (VK_FORMAT_ASTC_12x12_SRGB_BLOCK - VK_FORMAT_UNDEFINED + 1),\n    VK_FORMAT_MAX_ENUM = 0x7FFFFFFF\n} VkFormat;\n\ntypedef enum VkImageType {\n    VK_IMAGE_TYPE_1D = 0,\n    VK_IMAGE_TYPE_2D = 1,\n    VK_IMAGE_TYPE_3D = 2,\n    VK_IMAGE_TYPE_BEGIN_RANGE = VK_IMAGE_TYPE_1D,\n    VK_IMAGE_TYPE_END_RANGE = VK_IMAGE_TYPE_3D,\n    VK_IMAGE_TYPE_RANGE_SIZE = (VK_IMAGE_TYPE_3D - VK_IMAGE_TYPE_1D + 1),\n    VK_IMAGE_TYPE_MAX_ENUM = 0x7FFFFFFF\n} VkImageType;\n\ntypedef enum VkImageTiling {\n    VK_IMAGE_TILING_OPTIMAL = 0,\n    VK_IMAGE_TILING_LINEAR = 1,\n    VK_IMAGE_TILING_BEGIN_RANGE = VK_IMAGE_TILING_OPTIMAL,\n    VK_IMAGE_TILING_END_RANGE = VK_IMAGE_TILING_LINEAR,\n    VK_IMAGE_TILING_RANGE_SIZE = (VK_IMAGE_TILING_LINEAR - VK_IMAGE_TILING_OPTIMAL + 1),\n    VK_IMAGE_TILING_MAX_ENUM = 0x7FFFFFFF\n} VkImageTiling;\n\ntypedef enum VkPhysicalDeviceType {\n    VK_PHYSICAL_DEVICE_TYPE_OTHER = 0,\n    VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU = 1,\n    VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU = 2,\n    VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU = 3,\n    VK_PHYSICAL_DEVICE_TYPE_CPU = 4,\n    VK_PHYSICAL_DEVICE_TYPE_BEGIN_RANGE = VK_PHYSICAL_DEVICE_TYPE_OTHER,\n    VK_PHYSICAL_DEVICE_TYPE_END_RANGE = VK_PHYSICAL_DEVICE_TYPE_CPU,\n    VK_PHYSICAL_DEVICE_TYPE_RANGE_SIZE = (VK_PHYSICAL_DEVICE_TYPE_CPU - VK_PHYSICAL_DEVICE_TYPE_OTHER + 1),\n    VK_PHYSICAL_DEVICE_TYPE_MAX_ENUM = 0x7FFFFFFF\n} VkPhysicalDeviceType;\n\ntypedef enum VkQueryType {\n    VK_QUERY_TYPE_OCCLUSION = 0,\n    VK_QUERY_TYPE_PIPELINE_STATISTICS = 1,\n    VK_QUERY_TYPE_TIMESTAMP = 2,\n    VK_QUERY_TYPE_BEGIN_RANGE = VK_QUERY_TYPE_OCCLUSION,\n    VK_QUERY_TYPE_END_RANGE = VK_QUERY_TYPE_TIMESTAMP,\n    VK_QUERY_TYPE_RANGE_SIZE = (VK_QUERY_TYPE_TIMESTAMP - VK_QUERY_TYPE_OCCLUSION + 1),\n    VK_QUERY_TYPE_MAX_ENUM = 0x7FFFFFFF\n} VkQueryType;\n\ntypedef enum VkSharingMode {\n    VK_SHARING_MODE_EXCLUSIVE = 0,\n    VK_SHARING_MODE_CONCURRENT = 1,\n    VK_SHARING_MODE_BEGIN_RANGE = VK_SHARING_MODE_EXCLUSIVE,\n    VK_SHARING_MODE_END_RANGE = VK_SHARING_MODE_CONCURRENT,\n    VK_SHARING_MODE_RANGE_SIZE = (VK_SHARING_MODE_CONCURRENT - VK_SHARING_MODE_EXCLUSIVE + 1),\n    VK_SHARING_MODE_MAX_ENUM = 0x7FFFFFFF\n} VkSharingMode;\n\ntypedef enum VkImageLayout {\n    VK_IMAGE_LAYOUT_UNDEFINED = 0,\n    VK_IMAGE_LAYOUT_GENERAL = 1,\n    VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL = 2,\n    VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL = 3,\n    VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL = 4,\n    VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL = 5,\n    VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL = 6,\n    VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL = 7,\n    VK_IMAGE_LAYOUT_PREINITIALIZED = 8,\n    VK_IMAGE_LAYOUT_PRESENT_SRC_KHR = 1000001002,\n    VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR = 1000111000,\n    VK_IMAGE_LAYOUT_BEGIN_RANGE = VK_IMAGE_LAYOUT_UNDEFINED,\n    VK_IMAGE_LAYOUT_END_RANGE = VK_IMAGE_LAYOUT_PREINITIALIZED,\n    VK_IMAGE_LAYOUT_RANGE_SIZE = (VK_IMAGE_LAYOUT_PREINITIALIZED - VK_IMAGE_LAYOUT_UNDEFINED + 1),\n    VK_IMAGE_LAYOUT_MAX_ENUM = 0x7FFFFFFF\n} VkImageLayout;\n\ntypedef enum VkImageViewType {\n    VK_IMAGE_VIEW_TYPE_1D = 0,\n    VK_IMAGE_VIEW_TYPE_2D = 1,\n    VK_IMAGE_VIEW_TYPE_3D = 2,\n    VK_IMAGE_VIEW_TYPE_CUBE = 3,\n    VK_IMAGE_VIEW_TYPE_1D_ARRAY = 4,\n    VK_IMAGE_VIEW_TYPE_2D_ARRAY = 5,\n    VK_IMAGE_VIEW_TYPE_CUBE_ARRAY = 6,\n    VK_IMAGE_VIEW_TYPE_BEGIN_RANGE = VK_IMAGE_VIEW_TYPE_1D,\n    VK_IMAGE_VIEW_TYPE_END_RANGE = VK_IMAGE_VIEW_TYPE_CUBE_ARRAY,\n    VK_IMAGE_VIEW_TYPE_RANGE_SIZE = (VK_IMAGE_VIEW_TYPE_CUBE_ARRAY - VK_IMAGE_VIEW_TYPE_1D + 1),\n    VK_IMAGE_VIEW_TYPE_MAX_ENUM = 0x7FFFFFFF\n} VkImageViewType;\n\ntypedef enum VkComponentSwizzle {\n    VK_COMPONENT_SWIZZLE_IDENTITY = 0,\n    VK_COMPONENT_SWIZZLE_ZERO = 1,\n    VK_COMPONENT_SWIZZLE_ONE = 2,\n    VK_COMPONENT_SWIZZLE_R = 3,\n    VK_COMPONENT_SWIZZLE_G = 4,\n    VK_COMPONENT_SWIZZLE_B = 5,\n    VK_COMPONENT_SWIZZLE_A = 6,\n    VK_COMPONENT_SWIZZLE_BEGIN_RANGE = VK_COMPONENT_SWIZZLE_IDENTITY,\n    VK_COMPONENT_SWIZZLE_END_RANGE = VK_COMPONENT_SWIZZLE_A,\n    VK_COMPONENT_SWIZZLE_RANGE_SIZE = (VK_COMPONENT_SWIZZLE_A - VK_COMPONENT_SWIZZLE_IDENTITY + 1),\n    VK_COMPONENT_SWIZZLE_MAX_ENUM = 0x7FFFFFFF\n} VkComponentSwizzle;\n\ntypedef enum VkVertexInputRate {\n    VK_VERTEX_INPUT_RATE_VERTEX = 0,\n    VK_VERTEX_INPUT_RATE_INSTANCE = 1,\n    VK_VERTEX_INPUT_RATE_BEGIN_RANGE = VK_VERTEX_INPUT_RATE_VERTEX,\n    VK_VERTEX_INPUT_RATE_END_RANGE = VK_VERTEX_INPUT_RATE_INSTANCE,\n    VK_VERTEX_INPUT_RATE_RANGE_SIZE = (VK_VERTEX_INPUT_RATE_INSTANCE - VK_VERTEX_INPUT_RATE_VERTEX + 1),\n    VK_VERTEX_INPUT_RATE_MAX_ENUM = 0x7FFFFFFF\n} VkVertexInputRate;\n\ntypedef enum VkPrimitiveTopology {\n    VK_PRIMITIVE_TOPOLOGY_POINT_LIST = 0,\n    VK_PRIMITIVE_TOPOLOGY_LINE_LIST = 1,\n    VK_PRIMITIVE_TOPOLOGY_LINE_STRIP = 2,\n    VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST = 3,\n    VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP = 4,\n    VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN = 5,\n    VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY = 6,\n    VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY = 7,\n    VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY = 8,\n    VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY = 9,\n    VK_PRIMITIVE_TOPOLOGY_PATCH_LIST = 10,\n    VK_PRIMITIVE_TOPOLOGY_BEGIN_RANGE = VK_PRIMITIVE_TOPOLOGY_POINT_LIST,\n    VK_PRIMITIVE_TOPOLOGY_END_RANGE = VK_PRIMITIVE_TOPOLOGY_PATCH_LIST,\n    VK_PRIMITIVE_TOPOLOGY_RANGE_SIZE = (VK_PRIMITIVE_TOPOLOGY_PATCH_LIST - VK_PRIMITIVE_TOPOLOGY_POINT_LIST + 1),\n    VK_PRIMITIVE_TOPOLOGY_MAX_ENUM = 0x7FFFFFFF\n} VkPrimitiveTopology;\n\ntypedef enum VkPolygonMode {\n    VK_POLYGON_MODE_FILL = 0,\n    VK_POLYGON_MODE_LINE = 1,\n    VK_POLYGON_MODE_POINT = 2,\n    VK_POLYGON_MODE_BEGIN_RANGE = VK_POLYGON_MODE_FILL,\n    VK_POLYGON_MODE_END_RANGE = VK_POLYGON_MODE_POINT,\n    VK_POLYGON_MODE_RANGE_SIZE = (VK_POLYGON_MODE_POINT - VK_POLYGON_MODE_FILL + 1),\n    VK_POLYGON_MODE_MAX_ENUM = 0x7FFFFFFF\n} VkPolygonMode;\n\ntypedef enum VkFrontFace {\n    VK_FRONT_FACE_COUNTER_CLOCKWISE = 0,\n    VK_FRONT_FACE_CLOCKWISE = 1,\n    VK_FRONT_FACE_BEGIN_RANGE = VK_FRONT_FACE_COUNTER_CLOCKWISE,\n    VK_FRONT_FACE_END_RANGE = VK_FRONT_FACE_CLOCKWISE,\n    VK_FRONT_FACE_RANGE_SIZE = (VK_FRONT_FACE_CLOCKWISE - VK_FRONT_FACE_COUNTER_CLOCKWISE + 1),\n    VK_FRONT_FACE_MAX_ENUM = 0x7FFFFFFF\n} VkFrontFace;\n\ntypedef enum VkCompareOp {\n    VK_COMPARE_OP_NEVER = 0,\n    VK_COMPARE_OP_LESS = 1,\n    VK_COMPARE_OP_EQUAL = 2,\n    VK_COMPARE_OP_LESS_OR_EQUAL = 3,\n    VK_COMPARE_OP_GREATER = 4,\n    VK_COMPARE_OP_NOT_EQUAL = 5,\n    VK_COMPARE_OP_GREATER_OR_EQUAL = 6,\n    VK_COMPARE_OP_ALWAYS = 7,\n    VK_COMPARE_OP_BEGIN_RANGE = VK_COMPARE_OP_NEVER,\n    VK_COMPARE_OP_END_RANGE = VK_COMPARE_OP_ALWAYS,\n    VK_COMPARE_OP_RANGE_SIZE = (VK_COMPARE_OP_ALWAYS - VK_COMPARE_OP_NEVER + 1),\n    VK_COMPARE_OP_MAX_ENUM = 0x7FFFFFFF\n} VkCompareOp;\n\ntypedef enum VkStencilOp {\n    VK_STENCIL_OP_KEEP = 0,\n    VK_STENCIL_OP_ZERO = 1,\n    VK_STENCIL_OP_REPLACE = 2,\n    VK_STENCIL_OP_INCREMENT_AND_CLAMP = 3,\n    VK_STENCIL_OP_DECREMENT_AND_CLAMP = 4,\n    VK_STENCIL_OP_INVERT = 5,\n    VK_STENCIL_OP_INCREMENT_AND_WRAP = 6,\n    VK_STENCIL_OP_DECREMENT_AND_WRAP = 7,\n    VK_STENCIL_OP_BEGIN_RANGE = VK_STENCIL_OP_KEEP,\n    VK_STENCIL_OP_END_RANGE = VK_STENCIL_OP_DECREMENT_AND_WRAP,\n    VK_STENCIL_OP_RANGE_SIZE = (VK_STENCIL_OP_DECREMENT_AND_WRAP - VK_STENCIL_OP_KEEP + 1),\n    VK_STENCIL_OP_MAX_ENUM = 0x7FFFFFFF\n} VkStencilOp;\n\ntypedef enum VkLogicOp {\n    VK_LOGIC_OP_CLEAR = 0,\n    VK_LOGIC_OP_AND = 1,\n    VK_LOGIC_OP_AND_REVERSE = 2,\n    VK_LOGIC_OP_COPY = 3,\n    VK_LOGIC_OP_AND_INVERTED = 4,\n    VK_LOGIC_OP_NO_OP = 5,\n    VK_LOGIC_OP_XOR = 6,\n    VK_LOGIC_OP_OR = 7,\n    VK_LOGIC_OP_NOR = 8,\n    VK_LOGIC_OP_EQUIVALENT = 9,\n    VK_LOGIC_OP_INVERT = 10,\n    VK_LOGIC_OP_OR_REVERSE = 11,\n    VK_LOGIC_OP_COPY_INVERTED = 12,\n    VK_LOGIC_OP_OR_INVERTED = 13,\n    VK_LOGIC_OP_NAND = 14,\n    VK_LOGIC_OP_SET = 15,\n    VK_LOGIC_OP_BEGIN_RANGE = VK_LOGIC_OP_CLEAR,\n    VK_LOGIC_OP_END_RANGE = VK_LOGIC_OP_SET,\n    VK_LOGIC_OP_RANGE_SIZE = (VK_LOGIC_OP_SET - VK_LOGIC_OP_CLEAR + 1),\n    VK_LOGIC_OP_MAX_ENUM = 0x7FFFFFFF\n} VkLogicOp;\n\ntypedef enum VkBlendFactor {\n    VK_BLEND_FACTOR_ZERO = 0,\n    VK_BLEND_FACTOR_ONE = 1,\n    VK_BLEND_FACTOR_SRC_COLOR = 2,\n    VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR = 3,\n    VK_BLEND_FACTOR_DST_COLOR = 4,\n    VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR = 5,\n    VK_BLEND_FACTOR_SRC_ALPHA = 6,\n    VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA = 7,\n    VK_BLEND_FACTOR_DST_ALPHA = 8,\n    VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA = 9,\n    VK_BLEND_FACTOR_CONSTANT_COLOR = 10,\n    VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR = 11,\n    VK_BLEND_FACTOR_CONSTANT_ALPHA = 12,\n    VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA = 13,\n    VK_BLEND_FACTOR_SRC_ALPHA_SATURATE = 14,\n    VK_BLEND_FACTOR_SRC1_COLOR = 15,\n    VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR = 16,\n    VK_BLEND_FACTOR_SRC1_ALPHA = 17,\n    VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA = 18,\n    VK_BLEND_FACTOR_BEGIN_RANGE = VK_BLEND_FACTOR_ZERO,\n    VK_BLEND_FACTOR_END_RANGE = VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA,\n    VK_BLEND_FACTOR_RANGE_SIZE = (VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA - VK_BLEND_FACTOR_ZERO + 1),\n    VK_BLEND_FACTOR_MAX_ENUM = 0x7FFFFFFF\n} VkBlendFactor;\n\ntypedef enum VkBlendOp {\n    VK_BLEND_OP_ADD = 0,\n    VK_BLEND_OP_SUBTRACT = 1,\n    VK_BLEND_OP_REVERSE_SUBTRACT = 2,\n    VK_BLEND_OP_MIN = 3,\n    VK_BLEND_OP_MAX = 4,\n    VK_BLEND_OP_BEGIN_RANGE = VK_BLEND_OP_ADD,\n    VK_BLEND_OP_END_RANGE = VK_BLEND_OP_MAX,\n    VK_BLEND_OP_RANGE_SIZE = (VK_BLEND_OP_MAX - VK_BLEND_OP_ADD + 1),\n    VK_BLEND_OP_MAX_ENUM = 0x7FFFFFFF\n} VkBlendOp;\n\ntypedef enum VkDynamicState {\n    VK_DYNAMIC_STATE_VIEWPORT = 0,\n    VK_DYNAMIC_STATE_SCISSOR = 1,\n    VK_DYNAMIC_STATE_LINE_WIDTH = 2,\n    VK_DYNAMIC_STATE_DEPTH_BIAS = 3,\n    VK_DYNAMIC_STATE_BLEND_CONSTANTS = 4,\n    VK_DYNAMIC_STATE_DEPTH_BOUNDS = 5,\n    VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK = 6,\n    VK_DYNAMIC_STATE_STENCIL_WRITE_MASK = 7,\n    VK_DYNAMIC_STATE_STENCIL_REFERENCE = 8,\n    VK_DYNAMIC_STATE_VIEWPORT_W_SCALING_NV = 1000087000,\n    VK_DYNAMIC_STATE_DISCARD_RECTANGLE_EXT = 1000099000,\n    VK_DYNAMIC_STATE_BEGIN_RANGE = VK_DYNAMIC_STATE_VIEWPORT,\n    VK_DYNAMIC_STATE_END_RANGE = VK_DYNAMIC_STATE_STENCIL_REFERENCE,\n    VK_DYNAMIC_STATE_RANGE_SIZE = (VK_DYNAMIC_STATE_STENCIL_REFERENCE - VK_DYNAMIC_STATE_VIEWPORT + 1),\n    VK_DYNAMIC_STATE_MAX_ENUM = 0x7FFFFFFF\n} VkDynamicState;\n\ntypedef enum VkFilter {\n    VK_FILTER_NEAREST = 0,\n    VK_FILTER_LINEAR = 1,\n    VK_FILTER_CUBIC_IMG = 1000015000,\n    VK_FILTER_BEGIN_RANGE = VK_FILTER_NEAREST,\n    VK_FILTER_END_RANGE = VK_FILTER_LINEAR,\n    VK_FILTER_RANGE_SIZE = (VK_FILTER_LINEAR - VK_FILTER_NEAREST + 1),\n    VK_FILTER_MAX_ENUM = 0x7FFFFFFF\n} VkFilter;\n\ntypedef enum VkSamplerMipmapMode {\n    VK_SAMPLER_MIPMAP_MODE_NEAREST = 0,\n    VK_SAMPLER_MIPMAP_MODE_LINEAR = 1,\n    VK_SAMPLER_MIPMAP_MODE_BEGIN_RANGE = VK_SAMPLER_MIPMAP_MODE_NEAREST,\n    VK_SAMPLER_MIPMAP_MODE_END_RANGE = VK_SAMPLER_MIPMAP_MODE_LINEAR,\n    VK_SAMPLER_MIPMAP_MODE_RANGE_SIZE = (VK_SAMPLER_MIPMAP_MODE_LINEAR - VK_SAMPLER_MIPMAP_MODE_NEAREST + 1),\n    VK_SAMPLER_MIPMAP_MODE_MAX_ENUM = 0x7FFFFFFF\n} VkSamplerMipmapMode;\n\ntypedef enum VkSamplerAddressMode {\n    VK_SAMPLER_ADDRESS_MODE_REPEAT = 0,\n    VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT = 1,\n    VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE = 2,\n    VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER = 3,\n    VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE = 4,\n    VK_SAMPLER_ADDRESS_MODE_BEGIN_RANGE = VK_SAMPLER_ADDRESS_MODE_REPEAT,\n    VK_SAMPLER_ADDRESS_MODE_END_RANGE = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,\n    VK_SAMPLER_ADDRESS_MODE_RANGE_SIZE = (VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER - VK_SAMPLER_ADDRESS_MODE_REPEAT + 1),\n    VK_SAMPLER_ADDRESS_MODE_MAX_ENUM = 0x7FFFFFFF\n} VkSamplerAddressMode;\n\ntypedef enum VkBorderColor {\n    VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK = 0,\n    VK_BORDER_COLOR_INT_TRANSPARENT_BLACK = 1,\n    VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK = 2,\n    VK_BORDER_COLOR_INT_OPAQUE_BLACK = 3,\n    VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE = 4,\n    VK_BORDER_COLOR_INT_OPAQUE_WHITE = 5,\n    VK_BORDER_COLOR_BEGIN_RANGE = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,\n    VK_BORDER_COLOR_END_RANGE = VK_BORDER_COLOR_INT_OPAQUE_WHITE,\n    VK_BORDER_COLOR_RANGE_SIZE = (VK_BORDER_COLOR_INT_OPAQUE_WHITE - VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK + 1),\n    VK_BORDER_COLOR_MAX_ENUM = 0x7FFFFFFF\n} VkBorderColor;\n\ntypedef enum VkDescriptorType {\n    VK_DESCRIPTOR_TYPE_SAMPLER = 0,\n    VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER = 1,\n    VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE = 2,\n    VK_DESCRIPTOR_TYPE_STORAGE_IMAGE = 3,\n    VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER = 4,\n    VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER = 5,\n    VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER = 6,\n    VK_DESCRIPTOR_TYPE_STORAGE_BUFFER = 7,\n    VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC = 8,\n    VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC = 9,\n    VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT = 10,\n    VK_DESCRIPTOR_TYPE_BEGIN_RANGE = VK_DESCRIPTOR_TYPE_SAMPLER,\n    VK_DESCRIPTOR_TYPE_END_RANGE = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,\n    VK_DESCRIPTOR_TYPE_RANGE_SIZE = (VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT - VK_DESCRIPTOR_TYPE_SAMPLER + 1),\n    VK_DESCRIPTOR_TYPE_MAX_ENUM = 0x7FFFFFFF\n} VkDescriptorType;\n\ntypedef enum VkAttachmentLoadOp {\n    VK_ATTACHMENT_LOAD_OP_LOAD = 0,\n    VK_ATTACHMENT_LOAD_OP_CLEAR = 1,\n    VK_ATTACHMENT_LOAD_OP_DONT_CARE = 2,\n    VK_ATTACHMENT_LOAD_OP_BEGIN_RANGE = VK_ATTACHMENT_LOAD_OP_LOAD,\n    VK_ATTACHMENT_LOAD_OP_END_RANGE = VK_ATTACHMENT_LOAD_OP_DONT_CARE,\n    VK_ATTACHMENT_LOAD_OP_RANGE_SIZE = (VK_ATTACHMENT_LOAD_OP_DONT_CARE - VK_ATTACHMENT_LOAD_OP_LOAD + 1),\n    VK_ATTACHMENT_LOAD_OP_MAX_ENUM = 0x7FFFFFFF\n} VkAttachmentLoadOp;\n\ntypedef enum VkAttachmentStoreOp {\n    VK_ATTACHMENT_STORE_OP_STORE = 0,\n    VK_ATTACHMENT_STORE_OP_DONT_CARE = 1,\n    VK_ATTACHMENT_STORE_OP_BEGIN_RANGE = VK_ATTACHMENT_STORE_OP_STORE,\n    VK_ATTACHMENT_STORE_OP_END_RANGE = VK_ATTACHMENT_STORE_OP_DONT_CARE,\n    VK_ATTACHMENT_STORE_OP_RANGE_SIZE = (VK_ATTACHMENT_STORE_OP_DONT_CARE - VK_ATTACHMENT_STORE_OP_STORE + 1),\n    VK_ATTACHMENT_STORE_OP_MAX_ENUM = 0x7FFFFFFF\n} VkAttachmentStoreOp;\n\ntypedef enum VkPipelineBindPoint {\n    VK_PIPELINE_BIND_POINT_GRAPHICS = 0,\n    VK_PIPELINE_BIND_POINT_COMPUTE = 1,\n    VK_PIPELINE_BIND_POINT_BEGIN_RANGE = VK_PIPELINE_BIND_POINT_GRAPHICS,\n    VK_PIPELINE_BIND_POINT_END_RANGE = VK_PIPELINE_BIND_POINT_COMPUTE,\n    VK_PIPELINE_BIND_POINT_RANGE_SIZE = (VK_PIPELINE_BIND_POINT_COMPUTE - VK_PIPELINE_BIND_POINT_GRAPHICS + 1),\n    VK_PIPELINE_BIND_POINT_MAX_ENUM = 0x7FFFFFFF\n} VkPipelineBindPoint;\n\ntypedef enum VkCommandBufferLevel {\n    VK_COMMAND_BUFFER_LEVEL_PRIMARY = 0,\n    VK_COMMAND_BUFFER_LEVEL_SECONDARY = 1,\n    VK_COMMAND_BUFFER_LEVEL_BEGIN_RANGE = VK_COMMAND_BUFFER_LEVEL_PRIMARY,\n    VK_COMMAND_BUFFER_LEVEL_END_RANGE = VK_COMMAND_BUFFER_LEVEL_SECONDARY,\n    VK_COMMAND_BUFFER_LEVEL_RANGE_SIZE = (VK_COMMAND_BUFFER_LEVEL_SECONDARY - VK_COMMAND_BUFFER_LEVEL_PRIMARY + 1),\n    VK_COMMAND_BUFFER_LEVEL_MAX_ENUM = 0x7FFFFFFF\n} VkCommandBufferLevel;\n\ntypedef enum VkIndexType {\n    VK_INDEX_TYPE_UINT16 = 0,\n    VK_INDEX_TYPE_UINT32 = 1,\n    VK_INDEX_TYPE_BEGIN_RANGE = VK_INDEX_TYPE_UINT16,\n    VK_INDEX_TYPE_END_RANGE = VK_INDEX_TYPE_UINT32,\n    VK_INDEX_TYPE_RANGE_SIZE = (VK_INDEX_TYPE_UINT32 - VK_INDEX_TYPE_UINT16 + 1),\n    VK_INDEX_TYPE_MAX_ENUM = 0x7FFFFFFF\n} VkIndexType;\n\ntypedef enum VkSubpassContents {\n    VK_SUBPASS_CONTENTS_INLINE = 0,\n    VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS = 1,\n    VK_SUBPASS_CONTENTS_BEGIN_RANGE = VK_SUBPASS_CONTENTS_INLINE,\n    VK_SUBPASS_CONTENTS_END_RANGE = VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS,\n    VK_SUBPASS_CONTENTS_RANGE_SIZE = (VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS - VK_SUBPASS_CONTENTS_INLINE + 1),\n    VK_SUBPASS_CONTENTS_MAX_ENUM = 0x7FFFFFFF\n} VkSubpassContents;\n\ntypedef enum VkObjectType {\n    VK_OBJECT_TYPE_UNKNOWN = 0,\n    VK_OBJECT_TYPE_INSTANCE = 1,\n    VK_OBJECT_TYPE_PHYSICAL_DEVICE = 2,\n    VK_OBJECT_TYPE_DEVICE = 3,\n    VK_OBJECT_TYPE_QUEUE = 4,\n    VK_OBJECT_TYPE_SEMAPHORE = 5,\n    VK_OBJECT_TYPE_COMMAND_BUFFER = 6,\n    VK_OBJECT_TYPE_FENCE = 7,\n    VK_OBJECT_TYPE_DEVICE_MEMORY = 8,\n    VK_OBJECT_TYPE_BUFFER = 9,\n    VK_OBJECT_TYPE_IMAGE = 10,\n    VK_OBJECT_TYPE_EVENT = 11,\n    VK_OBJECT_TYPE_QUERY_POOL = 12,\n    VK_OBJECT_TYPE_BUFFER_VIEW = 13,\n    VK_OBJECT_TYPE_IMAGE_VIEW = 14,\n    VK_OBJECT_TYPE_SHADER_MODULE = 15,\n    VK_OBJECT_TYPE_PIPELINE_CACHE = 16,\n    VK_OBJECT_TYPE_PIPELINE_LAYOUT = 17,\n    VK_OBJECT_TYPE_RENDER_PASS = 18,\n    VK_OBJECT_TYPE_PIPELINE = 19,\n    VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT = 20,\n    VK_OBJECT_TYPE_SAMPLER = 21,\n    VK_OBJECT_TYPE_DESCRIPTOR_POOL = 22,\n    VK_OBJECT_TYPE_DESCRIPTOR_SET = 23,\n    VK_OBJECT_TYPE_FRAMEBUFFER = 24,\n    VK_OBJECT_TYPE_COMMAND_POOL = 25,\n    VK_OBJECT_TYPE_SURFACE_KHR = 1000000000,\n    VK_OBJECT_TYPE_SWAPCHAIN_KHR = 1000001000,\n    VK_OBJECT_TYPE_DISPLAY_KHR = 1000002000,\n    VK_OBJECT_TYPE_DISPLAY_MODE_KHR = 1000002001,\n    VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT = 1000011000,\n    VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR = 1000085000,\n    VK_OBJECT_TYPE_OBJECT_TABLE_NVX = 1000086000,\n    VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX = 1000086001,\n    VK_OBJECT_TYPE_BEGIN_RANGE = VK_OBJECT_TYPE_UNKNOWN,\n    VK_OBJECT_TYPE_END_RANGE = VK_OBJECT_TYPE_COMMAND_POOL,\n    VK_OBJECT_TYPE_RANGE_SIZE = (VK_OBJECT_TYPE_COMMAND_POOL - VK_OBJECT_TYPE_UNKNOWN + 1),\n    VK_OBJECT_TYPE_MAX_ENUM = 0x7FFFFFFF\n} VkObjectType;\n\ntypedef VkFlags VkInstanceCreateFlags;\n\ntypedef enum VkFormatFeatureFlagBits {\n    VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT = 0x00000001,\n    VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT = 0x00000002,\n    VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT = 0x00000004,\n    VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT = 0x00000008,\n    VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT = 0x00000010,\n    VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT = 0x00000020,\n    VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT = 0x00000040,\n    VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT = 0x00000080,\n    VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT = 0x00000100,\n    VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000200,\n    VK_FORMAT_FEATURE_BLIT_SRC_BIT = 0x00000400,\n    VK_FORMAT_FEATURE_BLIT_DST_BIT = 0x00000800,\n    VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT = 0x00001000,\n    VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG = 0x00002000,\n    VK_FORMAT_FEATURE_TRANSFER_SRC_BIT_KHR = 0x00004000,\n    VK_FORMAT_FEATURE_TRANSFER_DST_BIT_KHR = 0x00008000,\n    VK_FORMAT_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF\n} VkFormatFeatureFlagBits;\ntypedef VkFlags VkFormatFeatureFlags;\n\ntypedef enum VkImageUsageFlagBits {\n    VK_IMAGE_USAGE_TRANSFER_SRC_BIT = 0x00000001,\n    VK_IMAGE_USAGE_TRANSFER_DST_BIT = 0x00000002,\n    VK_IMAGE_USAGE_SAMPLED_BIT = 0x00000004,\n    VK_IMAGE_USAGE_STORAGE_BIT = 0x00000008,\n    VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT = 0x00000010,\n    VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000020,\n    VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT = 0x00000040,\n    VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT = 0x00000080,\n    VK_IMAGE_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF\n} VkImageUsageFlagBits;\ntypedef VkFlags VkImageUsageFlags;\n\ntypedef enum VkImageCreateFlagBits {\n    VK_IMAGE_CREATE_SPARSE_BINDING_BIT = 0x00000001,\n    VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT = 0x00000002,\n    VK_IMAGE_CREATE_SPARSE_ALIASED_BIT = 0x00000004,\n    VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT = 0x00000008,\n    VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT = 0x00000010,\n    VK_IMAGE_CREATE_BIND_SFR_BIT_KHX = 0x00000040,\n    VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR = 0x00000020,\n    VK_IMAGE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF\n} VkImageCreateFlagBits;\ntypedef VkFlags VkImageCreateFlags;\n\ntypedef enum VkSampleCountFlagBits {\n    VK_SAMPLE_COUNT_1_BIT = 0x00000001,\n    VK_SAMPLE_COUNT_2_BIT = 0x00000002,\n    VK_SAMPLE_COUNT_4_BIT = 0x00000004,\n    VK_SAMPLE_COUNT_8_BIT = 0x00000008,\n    VK_SAMPLE_COUNT_16_BIT = 0x00000010,\n    VK_SAMPLE_COUNT_32_BIT = 0x00000020,\n    VK_SAMPLE_COUNT_64_BIT = 0x00000040,\n    VK_SAMPLE_COUNT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF\n} VkSampleCountFlagBits;\ntypedef VkFlags VkSampleCountFlags;\n\ntypedef enum VkQueueFlagBits {\n    VK_QUEUE_GRAPHICS_BIT = 0x00000001,\n    VK_QUEUE_COMPUTE_BIT = 0x00000002,\n    VK_QUEUE_TRANSFER_BIT = 0x00000004,\n    VK_QUEUE_SPARSE_BINDING_BIT = 0x00000008,\n    VK_QUEUE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF\n} VkQueueFlagBits;\ntypedef VkFlags VkQueueFlags;\n\ntypedef enum VkMemoryPropertyFlagBits {\n    VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT = 0x00000001,\n    VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT = 0x00000002,\n    VK_MEMORY_PROPERTY_HOST_COHERENT_BIT = 0x00000004,\n    VK_MEMORY_PROPERTY_HOST_CACHED_BIT = 0x00000008,\n    VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT = 0x00000010,\n    VK_MEMORY_PROPERTY_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF\n} VkMemoryPropertyFlagBits;\ntypedef VkFlags VkMemoryPropertyFlags;\n\ntypedef enum VkMemoryHeapFlagBits {\n    VK_MEMORY_HEAP_DEVICE_LOCAL_BIT = 0x00000001,\n    VK_MEMORY_HEAP_MULTI_INSTANCE_BIT_KHX = 0x00000002,\n    VK_MEMORY_HEAP_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF\n} VkMemoryHeapFlagBits;\ntypedef VkFlags VkMemoryHeapFlags;\ntypedef VkFlags VkDeviceCreateFlags;\ntypedef VkFlags VkDeviceQueueCreateFlags;\n\ntypedef enum VkPipelineStageFlagBits {\n    VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT = 0x00000001,\n    VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT = 0x00000002,\n    VK_PIPELINE_STAGE_VERTEX_INPUT_BIT = 0x00000004,\n    VK_PIPELINE_STAGE_VERTEX_SHADER_BIT = 0x00000008,\n    VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT = 0x00000010,\n    VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT = 0x00000020,\n    VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT = 0x00000040,\n    VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT = 0x00000080,\n    VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT = 0x00000100,\n    VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT = 0x00000200,\n    VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT = 0x00000400,\n    VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT = 0x00000800,\n    VK_PIPELINE_STAGE_TRANSFER_BIT = 0x00001000,\n    VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT = 0x00002000,\n    VK_PIPELINE_STAGE_HOST_BIT = 0x00004000,\n    VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT = 0x00008000,\n    VK_PIPELINE_STAGE_ALL_COMMANDS_BIT = 0x00010000,\n    VK_PIPELINE_STAGE_COMMAND_PROCESS_BIT_NVX = 0x00020000,\n    VK_PIPELINE_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF\n} VkPipelineStageFlagBits;\ntypedef VkFlags VkPipelineStageFlags;\ntypedef VkFlags VkMemoryMapFlags;\n\ntypedef enum VkImageAspectFlagBits {\n    VK_IMAGE_ASPECT_COLOR_BIT = 0x00000001,\n    VK_IMAGE_ASPECT_DEPTH_BIT = 0x00000002,\n    VK_IMAGE_ASPECT_STENCIL_BIT = 0x00000004,\n    VK_IMAGE_ASPECT_METADATA_BIT = 0x00000008,\n    VK_IMAGE_ASPECT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF\n} VkImageAspectFlagBits;\ntypedef VkFlags VkImageAspectFlags;\n\ntypedef enum VkSparseImageFormatFlagBits {\n    VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT = 0x00000001,\n    VK_SPARSE_IMAGE_FORMAT_ALIGNED_MIP_SIZE_BIT = 0x00000002,\n    VK_SPARSE_IMAGE_FORMAT_NONSTANDARD_BLOCK_SIZE_BIT = 0x00000004,\n    VK_SPARSE_IMAGE_FORMAT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF\n} VkSparseImageFormatFlagBits;\ntypedef VkFlags VkSparseImageFormatFlags;\n\ntypedef enum VkSparseMemoryBindFlagBits {\n    VK_SPARSE_MEMORY_BIND_METADATA_BIT = 0x00000001,\n    VK_SPARSE_MEMORY_BIND_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF\n} VkSparseMemoryBindFlagBits;\ntypedef VkFlags VkSparseMemoryBindFlags;\n\ntypedef enum VkFenceCreateFlagBits {\n    VK_FENCE_CREATE_SIGNALED_BIT = 0x00000001,\n    VK_FENCE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF\n} VkFenceCreateFlagBits;\ntypedef VkFlags VkFenceCreateFlags;\ntypedef VkFlags VkSemaphoreCreateFlags;\ntypedef VkFlags VkEventCreateFlags;\ntypedef VkFlags VkQueryPoolCreateFlags;\n\ntypedef enum VkQueryPipelineStatisticFlagBits {\n    VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT = 0x00000001,\n    VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT = 0x00000002,\n    VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT = 0x00000004,\n    VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_INVOCATIONS_BIT = 0x00000008,\n    VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT = 0x00000010,\n    VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT = 0x00000020,\n    VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT = 0x00000040,\n    VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT = 0x00000080,\n    VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT = 0x00000100,\n    VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT = 0x00000200,\n    VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT = 0x00000400,\n    VK_QUERY_PIPELINE_STATISTIC_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF\n} VkQueryPipelineStatisticFlagBits;\ntypedef VkFlags VkQueryPipelineStatisticFlags;\n\ntypedef enum VkQueryResultFlagBits {\n    VK_QUERY_RESULT_64_BIT = 0x00000001,\n    VK_QUERY_RESULT_WAIT_BIT = 0x00000002,\n    VK_QUERY_RESULT_WITH_AVAILABILITY_BIT = 0x00000004,\n    VK_QUERY_RESULT_PARTIAL_BIT = 0x00000008,\n    VK_QUERY_RESULT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF\n} VkQueryResultFlagBits;\ntypedef VkFlags VkQueryResultFlags;\n\ntypedef enum VkBufferCreateFlagBits {\n    VK_BUFFER_CREATE_SPARSE_BINDING_BIT = 0x00000001,\n    VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT = 0x00000002,\n    VK_BUFFER_CREATE_SPARSE_ALIASED_BIT = 0x00000004,\n    VK_BUFFER_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF\n} VkBufferCreateFlagBits;\ntypedef VkFlags VkBufferCreateFlags;\n\ntypedef enum VkBufferUsageFlagBits {\n    VK_BUFFER_USAGE_TRANSFER_SRC_BIT = 0x00000001,\n    VK_BUFFER_USAGE_TRANSFER_DST_BIT = 0x00000002,\n    VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT = 0x00000004,\n    VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT = 0x00000008,\n    VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT = 0x00000010,\n    VK_BUFFER_USAGE_STORAGE_BUFFER_BIT = 0x00000020,\n    VK_BUFFER_USAGE_INDEX_BUFFER_BIT = 0x00000040,\n    VK_BUFFER_USAGE_VERTEX_BUFFER_BIT = 0x00000080,\n    VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT = 0x00000100,\n    VK_BUFFER_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF\n} VkBufferUsageFlagBits;\ntypedef VkFlags VkBufferUsageFlags;\ntypedef VkFlags VkBufferViewCreateFlags;\ntypedef VkFlags VkImageViewCreateFlags;\ntypedef VkFlags VkShaderModuleCreateFlags;\ntypedef VkFlags VkPipelineCacheCreateFlags;\n\ntypedef enum VkPipelineCreateFlagBits {\n    VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT = 0x00000001,\n    VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT = 0x00000002,\n    VK_PIPELINE_CREATE_DERIVATIVE_BIT = 0x00000004,\n    VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT_KHX = 0x00000008,\n    VK_PIPELINE_CREATE_DISPATCH_BASE_KHX = 0x00000010,\n    VK_PIPELINE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF\n} VkPipelineCreateFlagBits;\ntypedef VkFlags VkPipelineCreateFlags;\ntypedef VkFlags VkPipelineShaderStageCreateFlags;\n\ntypedef enum VkShaderStageFlagBits {\n    VK_SHADER_STAGE_VERTEX_BIT = 0x00000001,\n    VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT = 0x00000002,\n    VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT = 0x00000004,\n    VK_SHADER_STAGE_GEOMETRY_BIT = 0x00000008,\n    VK_SHADER_STAGE_FRAGMENT_BIT = 0x00000010,\n    VK_SHADER_STAGE_COMPUTE_BIT = 0x00000020,\n    VK_SHADER_STAGE_ALL_GRAPHICS = 0x0000001F,\n    VK_SHADER_STAGE_ALL = 0x7FFFFFFF,\n    VK_SHADER_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF\n} VkShaderStageFlagBits;\ntypedef VkFlags VkPipelineVertexInputStateCreateFlags;\ntypedef VkFlags VkPipelineInputAssemblyStateCreateFlags;\ntypedef VkFlags VkPipelineTessellationStateCreateFlags;\ntypedef VkFlags VkPipelineViewportStateCreateFlags;\ntypedef VkFlags VkPipelineRasterizationStateCreateFlags;\n\ntypedef enum VkCullModeFlagBits {\n    VK_CULL_MODE_NONE = 0,\n    VK_CULL_MODE_FRONT_BIT = 0x00000001,\n    VK_CULL_MODE_BACK_BIT = 0x00000002,\n    VK_CULL_MODE_FRONT_AND_BACK = 0x00000003,\n    VK_CULL_MODE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF\n} VkCullModeFlagBits;\ntypedef VkFlags VkCullModeFlags;\ntypedef VkFlags VkPipelineMultisampleStateCreateFlags;\ntypedef VkFlags VkPipelineDepthStencilStateCreateFlags;\ntypedef VkFlags VkPipelineColorBlendStateCreateFlags;\n\ntypedef enum VkColorComponentFlagBits {\n    VK_COLOR_COMPONENT_R_BIT = 0x00000001,\n    VK_COLOR_COMPONENT_G_BIT = 0x00000002,\n    VK_COLOR_COMPONENT_B_BIT = 0x00000004,\n    VK_COLOR_COMPONENT_A_BIT = 0x00000008,\n    VK_COLOR_COMPONENT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF\n} VkColorComponentFlagBits;\ntypedef VkFlags VkColorComponentFlags;\ntypedef VkFlags VkPipelineDynamicStateCreateFlags;\ntypedef VkFlags VkPipelineLayoutCreateFlags;\ntypedef VkFlags VkShaderStageFlags;\ntypedef VkFlags VkSamplerCreateFlags;\n\ntypedef enum VkDescriptorSetLayoutCreateFlagBits {\n    VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR = 0x00000001,\n    VK_DESCRIPTOR_SET_LAYOUT_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF\n} VkDescriptorSetLayoutCreateFlagBits;\ntypedef VkFlags VkDescriptorSetLayoutCreateFlags;\n\ntypedef enum VkDescriptorPoolCreateFlagBits {\n    VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT = 0x00000001,\n    VK_DESCRIPTOR_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF\n} VkDescriptorPoolCreateFlagBits;\ntypedef VkFlags VkDescriptorPoolCreateFlags;\ntypedef VkFlags VkDescriptorPoolResetFlags;\ntypedef VkFlags VkFramebufferCreateFlags;\ntypedef VkFlags VkRenderPassCreateFlags;\n\ntypedef enum VkAttachmentDescriptionFlagBits {\n    VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT = 0x00000001,\n    VK_ATTACHMENT_DESCRIPTION_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF\n} VkAttachmentDescriptionFlagBits;\ntypedef VkFlags VkAttachmentDescriptionFlags;\n\ntypedef enum VkSubpassDescriptionFlagBits {\n    VK_SUBPASS_DESCRIPTION_PER_VIEW_ATTRIBUTES_BIT_NVX = 0x00000001,\n    VK_SUBPASS_DESCRIPTION_PER_VIEW_POSITION_X_ONLY_BIT_NVX = 0x00000002,\n    VK_SUBPASS_DESCRIPTION_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF\n} VkSubpassDescriptionFlagBits;\ntypedef VkFlags VkSubpassDescriptionFlags;\n\ntypedef enum VkAccessFlagBits {\n    VK_ACCESS_INDIRECT_COMMAND_READ_BIT = 0x00000001,\n    VK_ACCESS_INDEX_READ_BIT = 0x00000002,\n    VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT = 0x00000004,\n    VK_ACCESS_UNIFORM_READ_BIT = 0x00000008,\n    VK_ACCESS_INPUT_ATTACHMENT_READ_BIT = 0x00000010,\n    VK_ACCESS_SHADER_READ_BIT = 0x00000020,\n    VK_ACCESS_SHADER_WRITE_BIT = 0x00000040,\n    VK_ACCESS_COLOR_ATTACHMENT_READ_BIT = 0x00000080,\n    VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT = 0x00000100,\n    VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT = 0x00000200,\n    VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT = 0x00000400,\n    VK_ACCESS_TRANSFER_READ_BIT = 0x00000800,\n    VK_ACCESS_TRANSFER_WRITE_BIT = 0x00001000,\n    VK_ACCESS_HOST_READ_BIT = 0x00002000,\n    VK_ACCESS_HOST_WRITE_BIT = 0x00004000,\n    VK_ACCESS_MEMORY_READ_BIT = 0x00008000,\n    VK_ACCESS_MEMORY_WRITE_BIT = 0x00010000,\n    VK_ACCESS_COMMAND_PROCESS_READ_BIT_NVX = 0x00020000,\n    VK_ACCESS_COMMAND_PROCESS_WRITE_BIT_NVX = 0x00040000,\n    VK_ACCESS_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF\n} VkAccessFlagBits;\ntypedef VkFlags VkAccessFlags;\n\ntypedef enum VkDependencyFlagBits {\n    VK_DEPENDENCY_BY_REGION_BIT = 0x00000001,\n    VK_DEPENDENCY_VIEW_LOCAL_BIT_KHX = 0x00000002,\n    VK_DEPENDENCY_DEVICE_GROUP_BIT_KHX = 0x00000004,\n    VK_DEPENDENCY_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF\n} VkDependencyFlagBits;\ntypedef VkFlags VkDependencyFlags;\n\ntypedef enum VkCommandPoolCreateFlagBits {\n    VK_COMMAND_POOL_CREATE_TRANSIENT_BIT = 0x00000001,\n    VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT = 0x00000002,\n    VK_COMMAND_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF\n} VkCommandPoolCreateFlagBits;\ntypedef VkFlags VkCommandPoolCreateFlags;\n\ntypedef enum VkCommandPoolResetFlagBits {\n    VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT = 0x00000001,\n    VK_COMMAND_POOL_RESET_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF\n} VkCommandPoolResetFlagBits;\ntypedef VkFlags VkCommandPoolResetFlags;\n\ntypedef enum VkCommandBufferUsageFlagBits {\n    VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT = 0x00000001,\n    VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT = 0x00000002,\n    VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT = 0x00000004,\n    VK_COMMAND_BUFFER_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF\n} VkCommandBufferUsageFlagBits;\ntypedef VkFlags VkCommandBufferUsageFlags;\n\ntypedef enum VkQueryControlFlagBits {\n    VK_QUERY_CONTROL_PRECISE_BIT = 0x00000001,\n    VK_QUERY_CONTROL_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF\n} VkQueryControlFlagBits;\ntypedef VkFlags VkQueryControlFlags;\n\ntypedef enum VkCommandBufferResetFlagBits {\n    VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT = 0x00000001,\n    VK_COMMAND_BUFFER_RESET_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF\n} VkCommandBufferResetFlagBits;\ntypedef VkFlags VkCommandBufferResetFlags;\n\ntypedef enum VkStencilFaceFlagBits {\n    VK_STENCIL_FACE_FRONT_BIT = 0x00000001,\n    VK_STENCIL_FACE_BACK_BIT = 0x00000002,\n    VK_STENCIL_FRONT_AND_BACK = 0x00000003,\n    VK_STENCIL_FACE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF\n} VkStencilFaceFlagBits;\ntypedef VkFlags VkStencilFaceFlags;\n\ntypedef void* (VKAPI_PTR *PFN_vkAllocationFunction)(\n    void*                                       pUserData,\n    size_t                                      size,\n    size_t                                      alignment,\n    VkSystemAllocationScope                     allocationScope);\n\ntypedef void* (VKAPI_PTR *PFN_vkReallocationFunction)(\n    void*                                       pUserData,\n    void*                                       pOriginal,\n    size_t                                      size,\n    size_t                                      alignment,\n    VkSystemAllocationScope                     allocationScope);\n\ntypedef void (VKAPI_PTR *PFN_vkFreeFunction)(\n    void*                                       pUserData,\n    void*                                       pMemory);\n\ntypedef void (VKAPI_PTR *PFN_vkInternalAllocationNotification)(\n    void*                                       pUserData,\n    size_t                                      size,\n    VkInternalAllocationType                    allocationType,\n    VkSystemAllocationScope                     allocationScope);\n\ntypedef void (VKAPI_PTR *PFN_vkInternalFreeNotification)(\n    void*                                       pUserData,\n    size_t                                      size,\n    VkInternalAllocationType                    allocationType,\n    VkSystemAllocationScope                     allocationScope);\n\ntypedef void (VKAPI_PTR *PFN_vkVoidFunction)(void);\n\ntypedef struct VkApplicationInfo {\n    VkStructureType    sType;\n    const void*        pNext;\n    const char*        pApplicationName;\n    uint32_t           applicationVersion;\n    const char*        pEngineName;\n    uint32_t           engineVersion;\n    uint32_t           apiVersion;\n} VkApplicationInfo;\n\ntypedef struct VkInstanceCreateInfo {\n    VkStructureType             sType;\n    const void*                 pNext;\n    VkInstanceCreateFlags       flags;\n    const VkApplicationInfo*    pApplicationInfo;\n    uint32_t                    enabledLayerCount;\n    const char* const*          ppEnabledLayerNames;\n    uint32_t                    enabledExtensionCount;\n    const char* const*          ppEnabledExtensionNames;\n} VkInstanceCreateInfo;\n\ntypedef struct VkAllocationCallbacks {\n    void*                                   pUserData;\n    PFN_vkAllocationFunction                pfnAllocation;\n    PFN_vkReallocationFunction              pfnReallocation;\n    PFN_vkFreeFunction                      pfnFree;\n    PFN_vkInternalAllocationNotification    pfnInternalAllocation;\n    PFN_vkInternalFreeNotification          pfnInternalFree;\n} VkAllocationCallbacks;\n\ntypedef struct VkPhysicalDeviceFeatures {\n    VkBool32    robustBufferAccess;\n    VkBool32    fullDrawIndexUint32;\n    VkBool32    imageCubeArray;\n    VkBool32    independentBlend;\n    VkBool32    geometryShader;\n    VkBool32    tessellationShader;\n    VkBool32    sampleRateShading;\n    VkBool32    dualSrcBlend;\n    VkBool32    logicOp;\n    VkBool32    multiDrawIndirect;\n    VkBool32    drawIndirectFirstInstance;\n    VkBool32    depthClamp;\n    VkBool32    depthBiasClamp;\n    VkBool32    fillModeNonSolid;\n    VkBool32    depthBounds;\n    VkBool32    wideLines;\n    VkBool32    largePoints;\n    VkBool32    alphaToOne;\n    VkBool32    multiViewport;\n    VkBool32    samplerAnisotropy;\n    VkBool32    textureCompressionETC2;\n    VkBool32    textureCompressionASTC_LDR;\n    VkBool32    textureCompressionBC;\n    VkBool32    occlusionQueryPrecise;\n    VkBool32    pipelineStatisticsQuery;\n    VkBool32    vertexPipelineStoresAndAtomics;\n    VkBool32    fragmentStoresAndAtomics;\n    VkBool32    shaderTessellationAndGeometryPointSize;\n    VkBool32    shaderImageGatherExtended;\n    VkBool32    shaderStorageImageExtendedFormats;\n    VkBool32    shaderStorageImageMultisample;\n    VkBool32    shaderStorageImageReadWithoutFormat;\n    VkBool32    shaderStorageImageWriteWithoutFormat;\n    VkBool32    shaderUniformBufferArrayDynamicIndexing;\n    VkBool32    shaderSampledImageArrayDynamicIndexing;\n    VkBool32    shaderStorageBufferArrayDynamicIndexing;\n    VkBool32    shaderStorageImageArrayDynamicIndexing;\n    VkBool32    shaderClipDistance;\n    VkBool32    shaderCullDistance;\n    VkBool32    shaderFloat64;\n    VkBool32    shaderInt64;\n    VkBool32    shaderInt16;\n    VkBool32    shaderResourceResidency;\n    VkBool32    shaderResourceMinLod;\n    VkBool32    sparseBinding;\n    VkBool32    sparseResidencyBuffer;\n    VkBool32    sparseResidencyImage2D;\n    VkBool32    sparseResidencyImage3D;\n    VkBool32    sparseResidency2Samples;\n    VkBool32    sparseResidency4Samples;\n    VkBool32    sparseResidency8Samples;\n    VkBool32    sparseResidency16Samples;\n    VkBool32    sparseResidencyAliased;\n    VkBool32    variableMultisampleRate;\n    VkBool32    inheritedQueries;\n} VkPhysicalDeviceFeatures;\n\ntypedef struct VkFormatProperties {\n    VkFormatFeatureFlags    linearTilingFeatures;\n    VkFormatFeatureFlags    optimalTilingFeatures;\n    VkFormatFeatureFlags    bufferFeatures;\n} VkFormatProperties;\n\ntypedef struct VkExtent3D {\n    uint32_t    width;\n    uint32_t    height;\n    uint32_t    depth;\n} VkExtent3D;\n\ntypedef struct VkImageFormatProperties {\n    VkExtent3D            maxExtent;\n    uint32_t              maxMipLevels;\n    uint32_t              maxArrayLayers;\n    VkSampleCountFlags    sampleCounts;\n    VkDeviceSize          maxResourceSize;\n} VkImageFormatProperties;\n\ntypedef struct VkPhysicalDeviceLimits {\n    uint32_t              maxImageDimension1D;\n    uint32_t              maxImageDimension2D;\n    uint32_t              maxImageDimension3D;\n    uint32_t              maxImageDimensionCube;\n    uint32_t              maxImageArrayLayers;\n    uint32_t              maxTexelBufferElements;\n    uint32_t              maxUniformBufferRange;\n    uint32_t              maxStorageBufferRange;\n    uint32_t              maxPushConstantsSize;\n    uint32_t              maxMemoryAllocationCount;\n    uint32_t              maxSamplerAllocationCount;\n    VkDeviceSize          bufferImageGranularity;\n    VkDeviceSize          sparseAddressSpaceSize;\n    uint32_t              maxBoundDescriptorSets;\n    uint32_t              maxPerStageDescriptorSamplers;\n    uint32_t              maxPerStageDescriptorUniformBuffers;\n    uint32_t              maxPerStageDescriptorStorageBuffers;\n    uint32_t              maxPerStageDescriptorSampledImages;\n    uint32_t              maxPerStageDescriptorStorageImages;\n    uint32_t              maxPerStageDescriptorInputAttachments;\n    uint32_t              maxPerStageResources;\n    uint32_t              maxDescriptorSetSamplers;\n    uint32_t              maxDescriptorSetUniformBuffers;\n    uint32_t              maxDescriptorSetUniformBuffersDynamic;\n    uint32_t              maxDescriptorSetStorageBuffers;\n    uint32_t              maxDescriptorSetStorageBuffersDynamic;\n    uint32_t              maxDescriptorSetSampledImages;\n    uint32_t              maxDescriptorSetStorageImages;\n    uint32_t              maxDescriptorSetInputAttachments;\n    uint32_t              maxVertexInputAttributes;\n    uint32_t              maxVertexInputBindings;\n    uint32_t              maxVertexInputAttributeOffset;\n    uint32_t              maxVertexInputBindingStride;\n    uint32_t              maxVertexOutputComponents;\n    uint32_t              maxTessellationGenerationLevel;\n    uint32_t              maxTessellationPatchSize;\n    uint32_t              maxTessellationControlPerVertexInputComponents;\n    uint32_t              maxTessellationControlPerVertexOutputComponents;\n    uint32_t              maxTessellationControlPerPatchOutputComponents;\n    uint32_t              maxTessellationControlTotalOutputComponents;\n    uint32_t              maxTessellationEvaluationInputComponents;\n    uint32_t              maxTessellationEvaluationOutputComponents;\n    uint32_t              maxGeometryShaderInvocations;\n    uint32_t              maxGeometryInputComponents;\n    uint32_t              maxGeometryOutputComponents;\n    uint32_t              maxGeometryOutputVertices;\n    uint32_t              maxGeometryTotalOutputComponents;\n    uint32_t              maxFragmentInputComponents;\n    uint32_t              maxFragmentOutputAttachments;\n    uint32_t              maxFragmentDualSrcAttachments;\n    uint32_t              maxFragmentCombinedOutputResources;\n    uint32_t              maxComputeSharedMemorySize;\n    uint32_t              maxComputeWorkGroupCount[3];\n    uint32_t              maxComputeWorkGroupInvocations;\n    uint32_t              maxComputeWorkGroupSize[3];\n    uint32_t              subPixelPrecisionBits;\n    uint32_t              subTexelPrecisionBits;\n    uint32_t              mipmapPrecisionBits;\n    uint32_t              maxDrawIndexedIndexValue;\n    uint32_t              maxDrawIndirectCount;\n    float                 maxSamplerLodBias;\n    float                 maxSamplerAnisotropy;\n    uint32_t              maxViewports;\n    uint32_t              maxViewportDimensions[2];\n    float                 viewportBoundsRange[2];\n    uint32_t              viewportSubPixelBits;\n    size_t                minMemoryMapAlignment;\n    VkDeviceSize          minTexelBufferOffsetAlignment;\n    VkDeviceSize          minUniformBufferOffsetAlignment;\n    VkDeviceSize          minStorageBufferOffsetAlignment;\n    int32_t               minTexelOffset;\n    uint32_t              maxTexelOffset;\n    int32_t               minTexelGatherOffset;\n    uint32_t              maxTexelGatherOffset;\n    float                 minInterpolationOffset;\n    float                 maxInterpolationOffset;\n    uint32_t              subPixelInterpolationOffsetBits;\n    uint32_t              maxFramebufferWidth;\n    uint32_t              maxFramebufferHeight;\n    uint32_t              maxFramebufferLayers;\n    VkSampleCountFlags    framebufferColorSampleCounts;\n    VkSampleCountFlags    framebufferDepthSampleCounts;\n    VkSampleCountFlags    framebufferStencilSampleCounts;\n    VkSampleCountFlags    framebufferNoAttachmentsSampleCounts;\n    uint32_t              maxColorAttachments;\n    VkSampleCountFlags    sampledImageColorSampleCounts;\n    VkSampleCountFlags    sampledImageIntegerSampleCounts;\n    VkSampleCountFlags    sampledImageDepthSampleCounts;\n    VkSampleCountFlags    sampledImageStencilSampleCounts;\n    VkSampleCountFlags    storageImageSampleCounts;\n    uint32_t              maxSampleMaskWords;\n    VkBool32              timestampComputeAndGraphics;\n    float                 timestampPeriod;\n    uint32_t              maxClipDistances;\n    uint32_t              maxCullDistances;\n    uint32_t              maxCombinedClipAndCullDistances;\n    uint32_t              discreteQueuePriorities;\n    float                 pointSizeRange[2];\n    float                 lineWidthRange[2];\n    float                 pointSizeGranularity;\n    float                 lineWidthGranularity;\n    VkBool32              strictLines;\n    VkBool32              standardSampleLocations;\n    VkDeviceSize          optimalBufferCopyOffsetAlignment;\n    VkDeviceSize          optimalBufferCopyRowPitchAlignment;\n    VkDeviceSize          nonCoherentAtomSize;\n} VkPhysicalDeviceLimits;\n\ntypedef struct VkPhysicalDeviceSparseProperties {\n    VkBool32    residencyStandard2DBlockShape;\n    VkBool32    residencyStandard2DMultisampleBlockShape;\n    VkBool32    residencyStandard3DBlockShape;\n    VkBool32    residencyAlignedMipSize;\n    VkBool32    residencyNonResidentStrict;\n} VkPhysicalDeviceSparseProperties;\n\ntypedef struct VkPhysicalDeviceProperties {\n    uint32_t                            apiVersion;\n    uint32_t                            driverVersion;\n    uint32_t                            vendorID;\n    uint32_t                            deviceID;\n    VkPhysicalDeviceType                deviceType;\n    char                                deviceName[VK_MAX_PHYSICAL_DEVICE_NAME_SIZE];\n    uint8_t                             pipelineCacheUUID[VK_UUID_SIZE];\n    VkPhysicalDeviceLimits              limits;\n    VkPhysicalDeviceSparseProperties    sparseProperties;\n} VkPhysicalDeviceProperties;\n\ntypedef struct VkQueueFamilyProperties {\n    VkQueueFlags    queueFlags;\n    uint32_t        queueCount;\n    uint32_t        timestampValidBits;\n    VkExtent3D      minImageTransferGranularity;\n} VkQueueFamilyProperties;\n\ntypedef struct VkMemoryType {\n    VkMemoryPropertyFlags    propertyFlags;\n    uint32_t                 heapIndex;\n} VkMemoryType;\n\ntypedef struct VkMemoryHeap {\n    VkDeviceSize         size;\n    VkMemoryHeapFlags    flags;\n} VkMemoryHeap;\n\ntypedef struct VkPhysicalDeviceMemoryProperties {\n    uint32_t        memoryTypeCount;\n    VkMemoryType    memoryTypes[VK_MAX_MEMORY_TYPES];\n    uint32_t        memoryHeapCount;\n    VkMemoryHeap    memoryHeaps[VK_MAX_MEMORY_HEAPS];\n} VkPhysicalDeviceMemoryProperties;\n\ntypedef struct VkDeviceQueueCreateInfo {\n    VkStructureType             sType;\n    const void*                 pNext;\n    VkDeviceQueueCreateFlags    flags;\n    uint32_t                    queueFamilyIndex;\n    uint32_t                    queueCount;\n    const float*                pQueuePriorities;\n} VkDeviceQueueCreateInfo;\n\ntypedef struct VkDeviceCreateInfo {\n    VkStructureType                    sType;\n    const void*                        pNext;\n    VkDeviceCreateFlags                flags;\n    uint32_t                           queueCreateInfoCount;\n    const VkDeviceQueueCreateInfo*     pQueueCreateInfos;\n    uint32_t                           enabledLayerCount;\n    const char* const*                 ppEnabledLayerNames;\n    uint32_t                           enabledExtensionCount;\n    const char* const*                 ppEnabledExtensionNames;\n    const VkPhysicalDeviceFeatures*    pEnabledFeatures;\n} VkDeviceCreateInfo;\n\ntypedef struct VkExtensionProperties {\n    char        extensionName[VK_MAX_EXTENSION_NAME_SIZE];\n    uint32_t    specVersion;\n} VkExtensionProperties;\n\ntypedef struct VkLayerProperties {\n    char        layerName[VK_MAX_EXTENSION_NAME_SIZE];\n    uint32_t    specVersion;\n    uint32_t    implementationVersion;\n    char        description[VK_MAX_DESCRIPTION_SIZE];\n} VkLayerProperties;\n\ntypedef struct VkSubmitInfo {\n    VkStructureType                sType;\n    const void*                    pNext;\n    uint32_t                       waitSemaphoreCount;\n    const VkSemaphore*             pWaitSemaphores;\n    const VkPipelineStageFlags*    pWaitDstStageMask;\n    uint32_t                       commandBufferCount;\n    const VkCommandBuffer*         pCommandBuffers;\n    uint32_t                       signalSemaphoreCount;\n    const VkSemaphore*             pSignalSemaphores;\n} VkSubmitInfo;\n\ntypedef struct VkMemoryAllocateInfo {\n    VkStructureType    sType;\n    const void*        pNext;\n    VkDeviceSize       allocationSize;\n    uint32_t           memoryTypeIndex;\n} VkMemoryAllocateInfo;\n\ntypedef struct VkMappedMemoryRange {\n    VkStructureType    sType;\n    const void*        pNext;\n    VkDeviceMemory     memory;\n    VkDeviceSize       offset;\n    VkDeviceSize       size;\n} VkMappedMemoryRange;\n\ntypedef struct VkMemoryRequirements {\n    VkDeviceSize    size;\n    VkDeviceSize    alignment;\n    uint32_t        memoryTypeBits;\n} VkMemoryRequirements;\n\ntypedef struct VkSparseImageFormatProperties {\n    VkImageAspectFlags          aspectMask;\n    VkExtent3D                  imageGranularity;\n    VkSparseImageFormatFlags    flags;\n} VkSparseImageFormatProperties;\n\ntypedef struct VkSparseImageMemoryRequirements {\n    VkSparseImageFormatProperties    formatProperties;\n    uint32_t                         imageMipTailFirstLod;\n    VkDeviceSize                     imageMipTailSize;\n    VkDeviceSize                     imageMipTailOffset;\n    VkDeviceSize                     imageMipTailStride;\n} VkSparseImageMemoryRequirements;\n\ntypedef struct VkSparseMemoryBind {\n    VkDeviceSize               resourceOffset;\n    VkDeviceSize               size;\n    VkDeviceMemory             memory;\n    VkDeviceSize               memoryOffset;\n    VkSparseMemoryBindFlags    flags;\n} VkSparseMemoryBind;\n\ntypedef struct VkSparseBufferMemoryBindInfo {\n    VkBuffer                     buffer;\n    uint32_t                     bindCount;\n    const VkSparseMemoryBind*    pBinds;\n} VkSparseBufferMemoryBindInfo;\n\ntypedef struct VkSparseImageOpaqueMemoryBindInfo {\n    VkImage                      image;\n    uint32_t                     bindCount;\n    const VkSparseMemoryBind*    pBinds;\n} VkSparseImageOpaqueMemoryBindInfo;\n\ntypedef struct VkImageSubresource {\n    VkImageAspectFlags    aspectMask;\n    uint32_t              mipLevel;\n    uint32_t              arrayLayer;\n} VkImageSubresource;\n\ntypedef struct VkOffset3D {\n    int32_t    x;\n    int32_t    y;\n    int32_t    z;\n} VkOffset3D;\n\ntypedef struct VkSparseImageMemoryBind {\n    VkImageSubresource         subresource;\n    VkOffset3D                 offset;\n    VkExtent3D                 extent;\n    VkDeviceMemory             memory;\n    VkDeviceSize               memoryOffset;\n    VkSparseMemoryBindFlags    flags;\n} VkSparseImageMemoryBind;\n\ntypedef struct VkSparseImageMemoryBindInfo {\n    VkImage                           image;\n    uint32_t                          bindCount;\n    const VkSparseImageMemoryBind*    pBinds;\n} VkSparseImageMemoryBindInfo;\n\ntypedef struct VkBindSparseInfo {\n    VkStructureType                             sType;\n    const void*                                 pNext;\n    uint32_t                                    waitSemaphoreCount;\n    const VkSemaphore*                          pWaitSemaphores;\n    uint32_t                                    bufferBindCount;\n    const VkSparseBufferMemoryBindInfo*         pBufferBinds;\n    uint32_t                                    imageOpaqueBindCount;\n    const VkSparseImageOpaqueMemoryBindInfo*    pImageOpaqueBinds;\n    uint32_t                                    imageBindCount;\n    const VkSparseImageMemoryBindInfo*          pImageBinds;\n    uint32_t                                    signalSemaphoreCount;\n    const VkSemaphore*                          pSignalSemaphores;\n} VkBindSparseInfo;\n\ntypedef struct VkFenceCreateInfo {\n    VkStructureType       sType;\n    const void*           pNext;\n    VkFenceCreateFlags    flags;\n} VkFenceCreateInfo;\n\ntypedef struct VkSemaphoreCreateInfo {\n    VkStructureType           sType;\n    const void*               pNext;\n    VkSemaphoreCreateFlags    flags;\n} VkSemaphoreCreateInfo;\n\ntypedef struct VkEventCreateInfo {\n    VkStructureType       sType;\n    const void*           pNext;\n    VkEventCreateFlags    flags;\n} VkEventCreateInfo;\n\ntypedef struct VkQueryPoolCreateInfo {\n    VkStructureType                  sType;\n    const void*                      pNext;\n    VkQueryPoolCreateFlags           flags;\n    VkQueryType                      queryType;\n    uint32_t                         queryCount;\n    VkQueryPipelineStatisticFlags    pipelineStatistics;\n} VkQueryPoolCreateInfo;\n\ntypedef struct VkBufferCreateInfo {\n    VkStructureType        sType;\n    const void*            pNext;\n    VkBufferCreateFlags    flags;\n    VkDeviceSize           size;\n    VkBufferUsageFlags     usage;\n    VkSharingMode          sharingMode;\n    uint32_t               queueFamilyIndexCount;\n    const uint32_t*        pQueueFamilyIndices;\n} VkBufferCreateInfo;\n\ntypedef struct VkBufferViewCreateInfo {\n    VkStructureType            sType;\n    const void*                pNext;\n    VkBufferViewCreateFlags    flags;\n    VkBuffer                   buffer;\n    VkFormat                   format;\n    VkDeviceSize               offset;\n    VkDeviceSize               range;\n} VkBufferViewCreateInfo;\n\ntypedef struct VkImageCreateInfo {\n    VkStructureType          sType;\n    const void*              pNext;\n    VkImageCreateFlags       flags;\n    VkImageType              imageType;\n    VkFormat                 format;\n    VkExtent3D               extent;\n    uint32_t                 mipLevels;\n    uint32_t                 arrayLayers;\n    VkSampleCountFlagBits    samples;\n    VkImageTiling            tiling;\n    VkImageUsageFlags        usage;\n    VkSharingMode            sharingMode;\n    uint32_t                 queueFamilyIndexCount;\n    const uint32_t*          pQueueFamilyIndices;\n    VkImageLayout            initialLayout;\n} VkImageCreateInfo;\n\ntypedef struct VkSubresourceLayout {\n    VkDeviceSize    offset;\n    VkDeviceSize    size;\n    VkDeviceSize    rowPitch;\n    VkDeviceSize    arrayPitch;\n    VkDeviceSize    depthPitch;\n} VkSubresourceLayout;\n\ntypedef struct VkComponentMapping {\n    VkComponentSwizzle    r;\n    VkComponentSwizzle    g;\n    VkComponentSwizzle    b;\n    VkComponentSwizzle    a;\n} VkComponentMapping;\n\ntypedef struct VkImageSubresourceRange {\n    VkImageAspectFlags    aspectMask;\n    uint32_t              baseMipLevel;\n    uint32_t              levelCount;\n    uint32_t              baseArrayLayer;\n    uint32_t              layerCount;\n} VkImageSubresourceRange;\n\ntypedef struct VkImageViewCreateInfo {\n    VkStructureType            sType;\n    const void*                pNext;\n    VkImageViewCreateFlags     flags;\n    VkImage                    image;\n    VkImageViewType            viewType;\n    VkFormat                   format;\n    VkComponentMapping         components;\n    VkImageSubresourceRange    subresourceRange;\n} VkImageViewCreateInfo;\n\ntypedef struct VkShaderModuleCreateInfo {\n    VkStructureType              sType;\n    const void*                  pNext;\n    VkShaderModuleCreateFlags    flags;\n    size_t                       codeSize;\n    const uint32_t*              pCode;\n} VkShaderModuleCreateInfo;\n\ntypedef struct VkPipelineCacheCreateInfo {\n    VkStructureType               sType;\n    const void*                   pNext;\n    VkPipelineCacheCreateFlags    flags;\n    size_t                        initialDataSize;\n    const void*                   pInitialData;\n} VkPipelineCacheCreateInfo;\n\ntypedef struct VkSpecializationMapEntry {\n    uint32_t    constantID;\n    uint32_t    offset;\n    size_t      size;\n} VkSpecializationMapEntry;\n\ntypedef struct VkSpecializationInfo {\n    uint32_t                           mapEntryCount;\n    const VkSpecializationMapEntry*    pMapEntries;\n    size_t                             dataSize;\n    const void*                        pData;\n} VkSpecializationInfo;\n\ntypedef struct VkPipelineShaderStageCreateInfo {\n    VkStructureType                     sType;\n    const void*                         pNext;\n    VkPipelineShaderStageCreateFlags    flags;\n    VkShaderStageFlagBits               stage;\n    VkShaderModule                      module;\n    const char*                         pName;\n    const VkSpecializationInfo*         pSpecializationInfo;\n} VkPipelineShaderStageCreateInfo;\n\ntypedef struct VkVertexInputBindingDescription {\n    uint32_t             binding;\n    uint32_t             stride;\n    VkVertexInputRate    inputRate;\n} VkVertexInputBindingDescription;\n\ntypedef struct VkVertexInputAttributeDescription {\n    uint32_t    location;\n    uint32_t    binding;\n    VkFormat    format;\n    uint32_t    offset;\n} VkVertexInputAttributeDescription;\n\ntypedef struct VkPipelineVertexInputStateCreateInfo {\n    VkStructureType                             sType;\n    const void*                                 pNext;\n    VkPipelineVertexInputStateCreateFlags       flags;\n    uint32_t                                    vertexBindingDescriptionCount;\n    const VkVertexInputBindingDescription*      pVertexBindingDescriptions;\n    uint32_t                                    vertexAttributeDescriptionCount;\n    const VkVertexInputAttributeDescription*    pVertexAttributeDescriptions;\n} VkPipelineVertexInputStateCreateInfo;\n\ntypedef struct VkPipelineInputAssemblyStateCreateInfo {\n    VkStructureType                            sType;\n    const void*                                pNext;\n    VkPipelineInputAssemblyStateCreateFlags    flags;\n    VkPrimitiveTopology                        topology;\n    VkBool32                                   primitiveRestartEnable;\n} VkPipelineInputAssemblyStateCreateInfo;\n\ntypedef struct VkPipelineTessellationStateCreateInfo {\n    VkStructureType                           sType;\n    const void*                               pNext;\n    VkPipelineTessellationStateCreateFlags    flags;\n    uint32_t                                  patchControlPoints;\n} VkPipelineTessellationStateCreateInfo;\n\ntypedef struct VkViewport {\n    float    x;\n    float    y;\n    float    width;\n    float    height;\n    float    minDepth;\n    float    maxDepth;\n} VkViewport;\n\ntypedef struct VkOffset2D {\n    int32_t    x;\n    int32_t    y;\n} VkOffset2D;\n\ntypedef struct VkExtent2D {\n    uint32_t    width;\n    uint32_t    height;\n} VkExtent2D;\n\ntypedef struct VkRect2D {\n    VkOffset2D    offset;\n    VkExtent2D    extent;\n} VkRect2D;\n\ntypedef struct VkPipelineViewportStateCreateInfo {\n    VkStructureType                       sType;\n    const void*                           pNext;\n    VkPipelineViewportStateCreateFlags    flags;\n    uint32_t                              viewportCount;\n    const VkViewport*                     pViewports;\n    uint32_t                              scissorCount;\n    const VkRect2D*                       pScissors;\n} VkPipelineViewportStateCreateInfo;\n\ntypedef struct VkPipelineRasterizationStateCreateInfo {\n    VkStructureType                            sType;\n    const void*                                pNext;\n    VkPipelineRasterizationStateCreateFlags    flags;\n    VkBool32                                   depthClampEnable;\n    VkBool32                                   rasterizerDiscardEnable;\n    VkPolygonMode                              polygonMode;\n    VkCullModeFlags                            cullMode;\n    VkFrontFace                                frontFace;\n    VkBool32                                   depthBiasEnable;\n    float                                      depthBiasConstantFactor;\n    float                                      depthBiasClamp;\n    float                                      depthBiasSlopeFactor;\n    float                                      lineWidth;\n} VkPipelineRasterizationStateCreateInfo;\n\ntypedef struct VkPipelineMultisampleStateCreateInfo {\n    VkStructureType                          sType;\n    const void*                              pNext;\n    VkPipelineMultisampleStateCreateFlags    flags;\n    VkSampleCountFlagBits                    rasterizationSamples;\n    VkBool32                                 sampleShadingEnable;\n    float                                    minSampleShading;\n    const VkSampleMask*                      pSampleMask;\n    VkBool32                                 alphaToCoverageEnable;\n    VkBool32                                 alphaToOneEnable;\n} VkPipelineMultisampleStateCreateInfo;\n\ntypedef struct VkStencilOpState {\n    VkStencilOp    failOp;\n    VkStencilOp    passOp;\n    VkStencilOp    depthFailOp;\n    VkCompareOp    compareOp;\n    uint32_t       compareMask;\n    uint32_t       writeMask;\n    uint32_t       reference;\n} VkStencilOpState;\n\ntypedef struct VkPipelineDepthStencilStateCreateInfo {\n    VkStructureType                           sType;\n    const void*                               pNext;\n    VkPipelineDepthStencilStateCreateFlags    flags;\n    VkBool32                                  depthTestEnable;\n    VkBool32                                  depthWriteEnable;\n    VkCompareOp                               depthCompareOp;\n    VkBool32                                  depthBoundsTestEnable;\n    VkBool32                                  stencilTestEnable;\n    VkStencilOpState                          front;\n    VkStencilOpState                          back;\n    float                                     minDepthBounds;\n    float                                     maxDepthBounds;\n} VkPipelineDepthStencilStateCreateInfo;\n\ntypedef struct VkPipelineColorBlendAttachmentState {\n    VkBool32                 blendEnable;\n    VkBlendFactor            srcColorBlendFactor;\n    VkBlendFactor            dstColorBlendFactor;\n    VkBlendOp                colorBlendOp;\n    VkBlendFactor            srcAlphaBlendFactor;\n    VkBlendFactor            dstAlphaBlendFactor;\n    VkBlendOp                alphaBlendOp;\n    VkColorComponentFlags    colorWriteMask;\n} VkPipelineColorBlendAttachmentState;\n\ntypedef struct VkPipelineColorBlendStateCreateInfo {\n    VkStructureType                               sType;\n    const void*                                   pNext;\n    VkPipelineColorBlendStateCreateFlags          flags;\n    VkBool32                                      logicOpEnable;\n    VkLogicOp                                     logicOp;\n    uint32_t                                      attachmentCount;\n    const VkPipelineColorBlendAttachmentState*    pAttachments;\n    float                                         blendConstants[4];\n} VkPipelineColorBlendStateCreateInfo;\n\ntypedef struct VkPipelineDynamicStateCreateInfo {\n    VkStructureType                      sType;\n    const void*                          pNext;\n    VkPipelineDynamicStateCreateFlags    flags;\n    uint32_t                             dynamicStateCount;\n    const VkDynamicState*                pDynamicStates;\n} VkPipelineDynamicStateCreateInfo;\n\ntypedef struct VkGraphicsPipelineCreateInfo {\n    VkStructureType                                  sType;\n    const void*                                      pNext;\n    VkPipelineCreateFlags                            flags;\n    uint32_t                                         stageCount;\n    const VkPipelineShaderStageCreateInfo*           pStages;\n    const VkPipelineVertexInputStateCreateInfo*      pVertexInputState;\n    const VkPipelineInputAssemblyStateCreateInfo*    pInputAssemblyState;\n    const VkPipelineTessellationStateCreateInfo*     pTessellationState;\n    const VkPipelineViewportStateCreateInfo*         pViewportState;\n    const VkPipelineRasterizationStateCreateInfo*    pRasterizationState;\n    const VkPipelineMultisampleStateCreateInfo*      pMultisampleState;\n    const VkPipelineDepthStencilStateCreateInfo*     pDepthStencilState;\n    const VkPipelineColorBlendStateCreateInfo*       pColorBlendState;\n    const VkPipelineDynamicStateCreateInfo*          pDynamicState;\n    VkPipelineLayout                                 layout;\n    VkRenderPass                                     renderPass;\n    uint32_t                                         subpass;\n    VkPipeline                                       basePipelineHandle;\n    int32_t                                          basePipelineIndex;\n} VkGraphicsPipelineCreateInfo;\n\ntypedef struct VkComputePipelineCreateInfo {\n    VkStructureType                    sType;\n    const void*                        pNext;\n    VkPipelineCreateFlags              flags;\n    VkPipelineShaderStageCreateInfo    stage;\n    VkPipelineLayout                   layout;\n    VkPipeline                         basePipelineHandle;\n    int32_t                            basePipelineIndex;\n} VkComputePipelineCreateInfo;\n\ntypedef struct VkPushConstantRange {\n    VkShaderStageFlags    stageFlags;\n    uint32_t              offset;\n    uint32_t              size;\n} VkPushConstantRange;\n\ntypedef struct VkPipelineLayoutCreateInfo {\n    VkStructureType                 sType;\n    const void*                     pNext;\n    VkPipelineLayoutCreateFlags     flags;\n    uint32_t                        setLayoutCount;\n    const VkDescriptorSetLayout*    pSetLayouts;\n    uint32_t                        pushConstantRangeCount;\n    const VkPushConstantRange*      pPushConstantRanges;\n} VkPipelineLayoutCreateInfo;\n\ntypedef struct VkSamplerCreateInfo {\n    VkStructureType         sType;\n    const void*             pNext;\n    VkSamplerCreateFlags    flags;\n    VkFilter                magFilter;\n    VkFilter                minFilter;\n    VkSamplerMipmapMode     mipmapMode;\n    VkSamplerAddressMode    addressModeU;\n    VkSamplerAddressMode    addressModeV;\n    VkSamplerAddressMode    addressModeW;\n    float                   mipLodBias;\n    VkBool32                anisotropyEnable;\n    float                   maxAnisotropy;\n    VkBool32                compareEnable;\n    VkCompareOp             compareOp;\n    float                   minLod;\n    float                   maxLod;\n    VkBorderColor           borderColor;\n    VkBool32                unnormalizedCoordinates;\n} VkSamplerCreateInfo;\n\ntypedef struct VkDescriptorSetLayoutBinding {\n    uint32_t              binding;\n    VkDescriptorType      descriptorType;\n    uint32_t              descriptorCount;\n    VkShaderStageFlags    stageFlags;\n    const VkSampler*      pImmutableSamplers;\n} VkDescriptorSetLayoutBinding;\n\ntypedef struct VkDescriptorSetLayoutCreateInfo {\n    VkStructureType                        sType;\n    const void*                            pNext;\n    VkDescriptorSetLayoutCreateFlags       flags;\n    uint32_t                               bindingCount;\n    const VkDescriptorSetLayoutBinding*    pBindings;\n} VkDescriptorSetLayoutCreateInfo;\n\ntypedef struct VkDescriptorPoolSize {\n    VkDescriptorType    type;\n    uint32_t            descriptorCount;\n} VkDescriptorPoolSize;\n\ntypedef struct VkDescriptorPoolCreateInfo {\n    VkStructureType                sType;\n    const void*                    pNext;\n    VkDescriptorPoolCreateFlags    flags;\n    uint32_t                       maxSets;\n    uint32_t                       poolSizeCount;\n    const VkDescriptorPoolSize*    pPoolSizes;\n} VkDescriptorPoolCreateInfo;\n\ntypedef struct VkDescriptorSetAllocateInfo {\n    VkStructureType                 sType;\n    const void*                     pNext;\n    VkDescriptorPool                descriptorPool;\n    uint32_t                        descriptorSetCount;\n    const VkDescriptorSetLayout*    pSetLayouts;\n} VkDescriptorSetAllocateInfo;\n\ntypedef struct VkDescriptorImageInfo {\n    VkSampler        sampler;\n    VkImageView      imageView;\n    VkImageLayout    imageLayout;\n} VkDescriptorImageInfo;\n\ntypedef struct VkDescriptorBufferInfo {\n    VkBuffer        buffer;\n    VkDeviceSize    offset;\n    VkDeviceSize    range;\n} VkDescriptorBufferInfo;\n\ntypedef struct VkWriteDescriptorSet {\n    VkStructureType                  sType;\n    const void*                      pNext;\n    VkDescriptorSet                  dstSet;\n    uint32_t                         dstBinding;\n    uint32_t                         dstArrayElement;\n    uint32_t                         descriptorCount;\n    VkDescriptorType                 descriptorType;\n    const VkDescriptorImageInfo*     pImageInfo;\n    const VkDescriptorBufferInfo*    pBufferInfo;\n    const VkBufferView*              pTexelBufferView;\n} VkWriteDescriptorSet;\n\ntypedef struct VkCopyDescriptorSet {\n    VkStructureType    sType;\n    const void*        pNext;\n    VkDescriptorSet    srcSet;\n    uint32_t           srcBinding;\n    uint32_t           srcArrayElement;\n    VkDescriptorSet    dstSet;\n    uint32_t           dstBinding;\n    uint32_t           dstArrayElement;\n    uint32_t           descriptorCount;\n} VkCopyDescriptorSet;\n\ntypedef struct VkFramebufferCreateInfo {\n    VkStructureType             sType;\n    const void*                 pNext;\n    VkFramebufferCreateFlags    flags;\n    VkRenderPass                renderPass;\n    uint32_t                    attachmentCount;\n    const VkImageView*          pAttachments;\n    uint32_t                    width;\n    uint32_t                    height;\n    uint32_t                    layers;\n} VkFramebufferCreateInfo;\n\ntypedef struct VkAttachmentDescription {\n    VkAttachmentDescriptionFlags    flags;\n    VkFormat                        format;\n    VkSampleCountFlagBits           samples;\n    VkAttachmentLoadOp              loadOp;\n    VkAttachmentStoreOp             storeOp;\n    VkAttachmentLoadOp              stencilLoadOp;\n    VkAttachmentStoreOp             stencilStoreOp;\n    VkImageLayout                   initialLayout;\n    VkImageLayout                   finalLayout;\n} VkAttachmentDescription;\n\ntypedef struct VkAttachmentReference {\n    uint32_t         attachment;\n    VkImageLayout    layout;\n} VkAttachmentReference;\n\ntypedef struct VkSubpassDescription {\n    VkSubpassDescriptionFlags       flags;\n    VkPipelineBindPoint             pipelineBindPoint;\n    uint32_t                        inputAttachmentCount;\n    const VkAttachmentReference*    pInputAttachments;\n    uint32_t                        colorAttachmentCount;\n    const VkAttachmentReference*    pColorAttachments;\n    const VkAttachmentReference*    pResolveAttachments;\n    const VkAttachmentReference*    pDepthStencilAttachment;\n    uint32_t                        preserveAttachmentCount;\n    const uint32_t*                 pPreserveAttachments;\n} VkSubpassDescription;\n\ntypedef struct VkSubpassDependency {\n    uint32_t                srcSubpass;\n    uint32_t                dstSubpass;\n    VkPipelineStageFlags    srcStageMask;\n    VkPipelineStageFlags    dstStageMask;\n    VkAccessFlags           srcAccessMask;\n    VkAccessFlags           dstAccessMask;\n    VkDependencyFlags       dependencyFlags;\n} VkSubpassDependency;\n\ntypedef struct VkRenderPassCreateInfo {\n    VkStructureType                   sType;\n    const void*                       pNext;\n    VkRenderPassCreateFlags           flags;\n    uint32_t                          attachmentCount;\n    const VkAttachmentDescription*    pAttachments;\n    uint32_t                          subpassCount;\n    const VkSubpassDescription*       pSubpasses;\n    uint32_t                          dependencyCount;\n    const VkSubpassDependency*        pDependencies;\n} VkRenderPassCreateInfo;\n\ntypedef struct VkCommandPoolCreateInfo {\n    VkStructureType             sType;\n    const void*                 pNext;\n    VkCommandPoolCreateFlags    flags;\n    uint32_t                    queueFamilyIndex;\n} VkCommandPoolCreateInfo;\n\ntypedef struct VkCommandBufferAllocateInfo {\n    VkStructureType         sType;\n    const void*             pNext;\n    VkCommandPool           commandPool;\n    VkCommandBufferLevel    level;\n    uint32_t                commandBufferCount;\n} VkCommandBufferAllocateInfo;\n\ntypedef struct VkCommandBufferInheritanceInfo {\n    VkStructureType                  sType;\n    const void*                      pNext;\n    VkRenderPass                     renderPass;\n    uint32_t                         subpass;\n    VkFramebuffer                    framebuffer;\n    VkBool32                         occlusionQueryEnable;\n    VkQueryControlFlags              queryFlags;\n    VkQueryPipelineStatisticFlags    pipelineStatistics;\n} VkCommandBufferInheritanceInfo;\n\ntypedef struct VkCommandBufferBeginInfo {\n    VkStructureType                          sType;\n    const void*                              pNext;\n    VkCommandBufferUsageFlags                flags;\n    const VkCommandBufferInheritanceInfo*    pInheritanceInfo;\n} VkCommandBufferBeginInfo;\n\ntypedef struct VkBufferCopy {\n    VkDeviceSize    srcOffset;\n    VkDeviceSize    dstOffset;\n    VkDeviceSize    size;\n} VkBufferCopy;\n\ntypedef struct VkImageSubresourceLayers {\n    VkImageAspectFlags    aspectMask;\n    uint32_t              mipLevel;\n    uint32_t              baseArrayLayer;\n    uint32_t              layerCount;\n} VkImageSubresourceLayers;\n\ntypedef struct VkImageCopy {\n    VkImageSubresourceLayers    srcSubresource;\n    VkOffset3D                  srcOffset;\n    VkImageSubresourceLayers    dstSubresource;\n    VkOffset3D                  dstOffset;\n    VkExtent3D                  extent;\n} VkImageCopy;\n\ntypedef struct VkImageBlit {\n    VkImageSubresourceLayers    srcSubresource;\n    VkOffset3D                  srcOffsets[2];\n    VkImageSubresourceLayers    dstSubresource;\n    VkOffset3D                  dstOffsets[2];\n} VkImageBlit;\n\ntypedef struct VkBufferImageCopy {\n    VkDeviceSize                bufferOffset;\n    uint32_t                    bufferRowLength;\n    uint32_t                    bufferImageHeight;\n    VkImageSubresourceLayers    imageSubresource;\n    VkOffset3D                  imageOffset;\n    VkExtent3D                  imageExtent;\n} VkBufferImageCopy;\n\ntypedef union VkClearColorValue {\n    float       float32[4];\n    int32_t     int32[4];\n    uint32_t    uint32[4];\n} VkClearColorValue;\n\ntypedef struct VkClearDepthStencilValue {\n    float       depth;\n    uint32_t    stencil;\n} VkClearDepthStencilValue;\n\ntypedef union VkClearValue {\n    VkClearColorValue           color;\n    VkClearDepthStencilValue    depthStencil;\n} VkClearValue;\n\ntypedef struct VkClearAttachment {\n    VkImageAspectFlags    aspectMask;\n    uint32_t              colorAttachment;\n    VkClearValue          clearValue;\n} VkClearAttachment;\n\ntypedef struct VkClearRect {\n    VkRect2D    rect;\n    uint32_t    baseArrayLayer;\n    uint32_t    layerCount;\n} VkClearRect;\n\ntypedef struct VkImageResolve {\n    VkImageSubresourceLayers    srcSubresource;\n    VkOffset3D                  srcOffset;\n    VkImageSubresourceLayers    dstSubresource;\n    VkOffset3D                  dstOffset;\n    VkExtent3D                  extent;\n} VkImageResolve;\n\ntypedef struct VkMemoryBarrier {\n    VkStructureType    sType;\n    const void*        pNext;\n    VkAccessFlags      srcAccessMask;\n    VkAccessFlags      dstAccessMask;\n} VkMemoryBarrier;\n\ntypedef struct VkBufferMemoryBarrier {\n    VkStructureType    sType;\n    const void*        pNext;\n    VkAccessFlags      srcAccessMask;\n    VkAccessFlags      dstAccessMask;\n    uint32_t           srcQueueFamilyIndex;\n    uint32_t           dstQueueFamilyIndex;\n    VkBuffer           buffer;\n    VkDeviceSize       offset;\n    VkDeviceSize       size;\n} VkBufferMemoryBarrier;\n\ntypedef struct VkImageMemoryBarrier {\n    VkStructureType            sType;\n    const void*                pNext;\n    VkAccessFlags              srcAccessMask;\n    VkAccessFlags              dstAccessMask;\n    VkImageLayout              oldLayout;\n    VkImageLayout              newLayout;\n    uint32_t                   srcQueueFamilyIndex;\n    uint32_t                   dstQueueFamilyIndex;\n    VkImage                    image;\n    VkImageSubresourceRange    subresourceRange;\n} VkImageMemoryBarrier;\n\ntypedef struct VkRenderPassBeginInfo {\n    VkStructureType        sType;\n    const void*            pNext;\n    VkRenderPass           renderPass;\n    VkFramebuffer          framebuffer;\n    VkRect2D               renderArea;\n    uint32_t               clearValueCount;\n    const VkClearValue*    pClearValues;\n} VkRenderPassBeginInfo;\n\ntypedef struct VkDispatchIndirectCommand {\n    uint32_t    x;\n    uint32_t    y;\n    uint32_t    z;\n} VkDispatchIndirectCommand;\n\ntypedef struct VkDrawIndexedIndirectCommand {\n    uint32_t    indexCount;\n    uint32_t    instanceCount;\n    uint32_t    firstIndex;\n    int32_t     vertexOffset;\n    uint32_t    firstInstance;\n} VkDrawIndexedIndirectCommand;\n\ntypedef struct VkDrawIndirectCommand {\n    uint32_t    vertexCount;\n    uint32_t    instanceCount;\n    uint32_t    firstVertex;\n    uint32_t    firstInstance;\n} VkDrawIndirectCommand;\n\n\ntypedef VkResult (VKAPI_PTR *PFN_vkCreateInstance)(const VkInstanceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkInstance* pInstance);\ntypedef void (VKAPI_PTR *PFN_vkDestroyInstance)(VkInstance instance, const VkAllocationCallbacks* pAllocator);\ntypedef VkResult (VKAPI_PTR *PFN_vkEnumeratePhysicalDevices)(VkInstance instance, uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices);\ntypedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFeatures)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures* pFeatures);\ntypedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties* pFormatProperties);\ntypedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties* pImageFormatProperties);\ntypedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceProperties)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties* pProperties);\ntypedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties)(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties* pQueueFamilyProperties);\ntypedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMemoryProperties)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties* pMemoryProperties);\ntypedef PFN_vkVoidFunction (VKAPI_PTR *PFN_vkGetInstanceProcAddr)(VkInstance instance, const char* pName);\ntypedef PFN_vkVoidFunction (VKAPI_PTR *PFN_vkGetDeviceProcAddr)(VkDevice device, const char* pName);\ntypedef VkResult (VKAPI_PTR *PFN_vkCreateDevice)(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDevice* pDevice);\ntypedef void (VKAPI_PTR *PFN_vkDestroyDevice)(VkDevice device, const VkAllocationCallbacks* pAllocator);\ntypedef VkResult (VKAPI_PTR *PFN_vkEnumerateInstanceExtensionProperties)(const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties);\ntypedef VkResult (VKAPI_PTR *PFN_vkEnumerateDeviceExtensionProperties)(VkPhysicalDevice physicalDevice, const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties);\ntypedef VkResult (VKAPI_PTR *PFN_vkEnumerateInstanceLayerProperties)(uint32_t* pPropertyCount, VkLayerProperties* pProperties);\ntypedef VkResult (VKAPI_PTR *PFN_vkEnumerateDeviceLayerProperties)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkLayerProperties* pProperties);\ntypedef void (VKAPI_PTR *PFN_vkGetDeviceQueue)(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue* pQueue);\ntypedef VkResult (VKAPI_PTR *PFN_vkQueueSubmit)(VkQueue queue, uint32_t submitCount, const VkSubmitInfo* pSubmits, VkFence fence);\ntypedef VkResult (VKAPI_PTR *PFN_vkQueueWaitIdle)(VkQueue queue);\ntypedef VkResult (VKAPI_PTR *PFN_vkDeviceWaitIdle)(VkDevice device);\ntypedef VkResult (VKAPI_PTR *PFN_vkAllocateMemory)(VkDevice device, const VkMemoryAllocateInfo* pAllocateInfo, const VkAllocationCallbacks* pAllocator, VkDeviceMemory* pMemory);\ntypedef void (VKAPI_PTR *PFN_vkFreeMemory)(VkDevice device, VkDeviceMemory memory, const VkAllocationCallbacks* pAllocator);\ntypedef VkResult (VKAPI_PTR *PFN_vkMapMemory)(VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void** ppData);\ntypedef void (VKAPI_PTR *PFN_vkUnmapMemory)(VkDevice device, VkDeviceMemory memory);\ntypedef VkResult (VKAPI_PTR *PFN_vkFlushMappedMemoryRanges)(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange* pMemoryRanges);\ntypedef VkResult (VKAPI_PTR *PFN_vkInvalidateMappedMemoryRanges)(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange* pMemoryRanges);\ntypedef void (VKAPI_PTR *PFN_vkGetDeviceMemoryCommitment)(VkDevice device, VkDeviceMemory memory, VkDeviceSize* pCommittedMemoryInBytes);\ntypedef VkResult (VKAPI_PTR *PFN_vkBindBufferMemory)(VkDevice device, VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize memoryOffset);\ntypedef VkResult (VKAPI_PTR *PFN_vkBindImageMemory)(VkDevice device, VkImage image, VkDeviceMemory memory, VkDeviceSize memoryOffset);\ntypedef void (VKAPI_PTR *PFN_vkGetBufferMemoryRequirements)(VkDevice device, VkBuffer buffer, VkMemoryRequirements* pMemoryRequirements);\ntypedef void (VKAPI_PTR *PFN_vkGetImageMemoryRequirements)(VkDevice device, VkImage image, VkMemoryRequirements* pMemoryRequirements);\ntypedef void (VKAPI_PTR *PFN_vkGetImageSparseMemoryRequirements)(VkDevice device, VkImage image, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements* pSparseMemoryRequirements);\ntypedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkSampleCountFlagBits samples, VkImageUsageFlags usage, VkImageTiling tiling, uint32_t* pPropertyCount, VkSparseImageFormatProperties* pProperties);\ntypedef VkResult (VKAPI_PTR *PFN_vkQueueBindSparse)(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo* pBindInfo, VkFence fence);\ntypedef VkResult (VKAPI_PTR *PFN_vkCreateFence)(VkDevice device, const VkFenceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence);\ntypedef void (VKAPI_PTR *PFN_vkDestroyFence)(VkDevice device, VkFence fence, const VkAllocationCallbacks* pAllocator);\ntypedef VkResult (VKAPI_PTR *PFN_vkResetFences)(VkDevice device, uint32_t fenceCount, const VkFence* pFences);\ntypedef VkResult (VKAPI_PTR *PFN_vkGetFenceStatus)(VkDevice device, VkFence fence);\ntypedef VkResult (VKAPI_PTR *PFN_vkWaitForFences)(VkDevice device, uint32_t fenceCount, const VkFence* pFences, VkBool32 waitAll, uint64_t timeout);\ntypedef VkResult (VKAPI_PTR *PFN_vkCreateSemaphore)(VkDevice device, const VkSemaphoreCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSemaphore* pSemaphore);\ntypedef void (VKAPI_PTR *PFN_vkDestroySemaphore)(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks* pAllocator);\ntypedef VkResult (VKAPI_PTR *PFN_vkCreateEvent)(VkDevice device, const VkEventCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkEvent* pEvent);\ntypedef void (VKAPI_PTR *PFN_vkDestroyEvent)(VkDevice device, VkEvent event, const VkAllocationCallbacks* pAllocator);\ntypedef VkResult (VKAPI_PTR *PFN_vkGetEventStatus)(VkDevice device, VkEvent event);\ntypedef VkResult (VKAPI_PTR *PFN_vkSetEvent)(VkDevice device, VkEvent event);\ntypedef VkResult (VKAPI_PTR *PFN_vkResetEvent)(VkDevice device, VkEvent event);\ntypedef VkResult (VKAPI_PTR *PFN_vkCreateQueryPool)(VkDevice device, const VkQueryPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkQueryPool* pQueryPool);\ntypedef void (VKAPI_PTR *PFN_vkDestroyQueryPool)(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks* pAllocator);\ntypedef VkResult (VKAPI_PTR *PFN_vkGetQueryPoolResults)(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, size_t dataSize, void* pData, VkDeviceSize stride, VkQueryResultFlags flags);\ntypedef VkResult (VKAPI_PTR *PFN_vkCreateBuffer)(VkDevice device, const VkBufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBuffer* pBuffer);\ntypedef void (VKAPI_PTR *PFN_vkDestroyBuffer)(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks* pAllocator);\ntypedef VkResult (VKAPI_PTR *PFN_vkCreateBufferView)(VkDevice device, const VkBufferViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBufferView* pView);\ntypedef void (VKAPI_PTR *PFN_vkDestroyBufferView)(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks* pAllocator);\ntypedef VkResult (VKAPI_PTR *PFN_vkCreateImage)(VkDevice device, const VkImageCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImage* pImage);\ntypedef void (VKAPI_PTR *PFN_vkDestroyImage)(VkDevice device, VkImage image, const VkAllocationCallbacks* pAllocator);\ntypedef void (VKAPI_PTR *PFN_vkGetImageSubresourceLayout)(VkDevice device, VkImage image, const VkImageSubresource* pSubresource, VkSubresourceLayout* pLayout);\ntypedef VkResult (VKAPI_PTR *PFN_vkCreateImageView)(VkDevice device, const VkImageViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImageView* pView);\ntypedef void (VKAPI_PTR *PFN_vkDestroyImageView)(VkDevice device, VkImageView imageView, const VkAllocationCallbacks* pAllocator);\ntypedef VkResult (VKAPI_PTR *PFN_vkCreateShaderModule)(VkDevice device, const VkShaderModuleCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkShaderModule* pShaderModule);\ntypedef void (VKAPI_PTR *PFN_vkDestroyShaderModule)(VkDevice device, VkShaderModule shaderModule, const VkAllocationCallbacks* pAllocator);\ntypedef VkResult (VKAPI_PTR *PFN_vkCreatePipelineCache)(VkDevice device, const VkPipelineCacheCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPipelineCache* pPipelineCache);\ntypedef void (VKAPI_PTR *PFN_vkDestroyPipelineCache)(VkDevice device, VkPipelineCache pipelineCache, const VkAllocationCallbacks* pAllocator);\ntypedef VkResult (VKAPI_PTR *PFN_vkGetPipelineCacheData)(VkDevice device, VkPipelineCache pipelineCache, size_t* pDataSize, void* pData);\ntypedef VkResult (VKAPI_PTR *PFN_vkMergePipelineCaches)(VkDevice device, VkPipelineCache dstCache, uint32_t srcCacheCount, const VkPipelineCache* pSrcCaches);\ntypedef VkResult (VKAPI_PTR *PFN_vkCreateGraphicsPipelines)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkGraphicsPipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines);\ntypedef VkResult (VKAPI_PTR *PFN_vkCreateComputePipelines)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkComputePipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines);\ntypedef void (VKAPI_PTR *PFN_vkDestroyPipeline)(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks* pAllocator);\ntypedef VkResult (VKAPI_PTR *PFN_vkCreatePipelineLayout)(VkDevice device, const VkPipelineLayoutCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPipelineLayout* pPipelineLayout);\ntypedef void (VKAPI_PTR *PFN_vkDestroyPipelineLayout)(VkDevice device, VkPipelineLayout pipelineLayout, const VkAllocationCallbacks* pAllocator);\ntypedef VkResult (VKAPI_PTR *PFN_vkCreateSampler)(VkDevice device, const VkSamplerCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSampler* pSampler);\ntypedef void (VKAPI_PTR *PFN_vkDestroySampler)(VkDevice device, VkSampler sampler, const VkAllocationCallbacks* pAllocator);\ntypedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorSetLayout)(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorSetLayout* pSetLayout);\ntypedef void (VKAPI_PTR *PFN_vkDestroyDescriptorSetLayout)(VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const VkAllocationCallbacks* pAllocator);\ntypedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorPool)(VkDevice device, const VkDescriptorPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorPool* pDescriptorPool);\ntypedef void (VKAPI_PTR *PFN_vkDestroyDescriptorPool)(VkDevice device, VkDescriptorPool descriptorPool, const VkAllocationCallbacks* pAllocator);\ntypedef VkResult (VKAPI_PTR *PFN_vkResetDescriptorPool)(VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorPoolResetFlags flags);\ntypedef VkResult (VKAPI_PTR *PFN_vkAllocateDescriptorSets)(VkDevice device, const VkDescriptorSetAllocateInfo* pAllocateInfo, VkDescriptorSet* pDescriptorSets);\ntypedef VkResult (VKAPI_PTR *PFN_vkFreeDescriptorSets)(VkDevice device, VkDescriptorPool descriptorPool, uint32_t descriptorSetCount, const VkDescriptorSet* pDescriptorSets);\ntypedef void (VKAPI_PTR *PFN_vkUpdateDescriptorSets)(VkDevice device, uint32_t descriptorWriteCount, const VkWriteDescriptorSet* pDescriptorWrites, uint32_t descriptorCopyCount, const VkCopyDescriptorSet* pDescriptorCopies);\ntypedef VkResult (VKAPI_PTR *PFN_vkCreateFramebuffer)(VkDevice device, const VkFramebufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkFramebuffer* pFramebuffer);\ntypedef void (VKAPI_PTR *PFN_vkDestroyFramebuffer)(VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks* pAllocator);\ntypedef VkResult (VKAPI_PTR *PFN_vkCreateRenderPass)(VkDevice device, const VkRenderPassCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass);\ntypedef void (VKAPI_PTR *PFN_vkDestroyRenderPass)(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks* pAllocator);\ntypedef void (VKAPI_PTR *PFN_vkGetRenderAreaGranularity)(VkDevice device, VkRenderPass renderPass, VkExtent2D* pGranularity);\ntypedef VkResult (VKAPI_PTR *PFN_vkCreateCommandPool)(VkDevice device, const VkCommandPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkCommandPool* pCommandPool);\ntypedef void (VKAPI_PTR *PFN_vkDestroyCommandPool)(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks* pAllocator);\ntypedef VkResult (VKAPI_PTR *PFN_vkResetCommandPool)(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags);\ntypedef VkResult (VKAPI_PTR *PFN_vkAllocateCommandBuffers)(VkDevice device, const VkCommandBufferAllocateInfo* pAllocateInfo, VkCommandBuffer* pCommandBuffers);\ntypedef void (VKAPI_PTR *PFN_vkFreeCommandBuffers)(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers);\ntypedef VkResult (VKAPI_PTR *PFN_vkBeginCommandBuffer)(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo* pBeginInfo);\ntypedef VkResult (VKAPI_PTR *PFN_vkEndCommandBuffer)(VkCommandBuffer commandBuffer);\ntypedef VkResult (VKAPI_PTR *PFN_vkResetCommandBuffer)(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags);\ntypedef void (VKAPI_PTR *PFN_vkCmdBindPipeline)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline);\ntypedef void (VKAPI_PTR *PFN_vkCmdSetViewport)(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewport* pViewports);\ntypedef void (VKAPI_PTR *PFN_vkCmdSetScissor)(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount, const VkRect2D* pScissors);\ntypedef void (VKAPI_PTR *PFN_vkCmdSetLineWidth)(VkCommandBuffer commandBuffer, float lineWidth);\ntypedef void (VKAPI_PTR *PFN_vkCmdSetDepthBias)(VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp, float depthBiasSlopeFactor);\ntypedef void (VKAPI_PTR *PFN_vkCmdSetBlendConstants)(VkCommandBuffer commandBuffer, const float blendConstants[4]);\ntypedef void (VKAPI_PTR *PFN_vkCmdSetDepthBounds)(VkCommandBuffer commandBuffer, float minDepthBounds, float maxDepthBounds);\ntypedef void (VKAPI_PTR *PFN_vkCmdSetStencilCompareMask)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t compareMask);\ntypedef void (VKAPI_PTR *PFN_vkCmdSetStencilWriteMask)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t writeMask);\ntypedef void (VKAPI_PTR *PFN_vkCmdSetStencilReference)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t reference);\ntypedef void (VKAPI_PTR *PFN_vkCmdBindDescriptorSets)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t firstSet, uint32_t descriptorSetCount, const VkDescriptorSet* pDescriptorSets, uint32_t dynamicOffsetCount, const uint32_t* pDynamicOffsets);\ntypedef void (VKAPI_PTR *PFN_vkCmdBindIndexBuffer)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType);\ntypedef void (VKAPI_PTR *PFN_vkCmdBindVertexBuffers)(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets);\ntypedef void (VKAPI_PTR *PFN_vkCmdDraw)(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance);\ntypedef void (VKAPI_PTR *PFN_vkCmdDrawIndexed)(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance);\ntypedef void (VKAPI_PTR *PFN_vkCmdDrawIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride);\ntypedef void (VKAPI_PTR *PFN_vkCmdDrawIndexedIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride);\ntypedef void (VKAPI_PTR *PFN_vkCmdDispatch)(VkCommandBuffer commandBuffer, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ);\ntypedef void (VKAPI_PTR *PFN_vkCmdDispatchIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset);\ntypedef void (VKAPI_PTR *PFN_vkCmdCopyBuffer)(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferCopy* pRegions);\ntypedef void (VKAPI_PTR *PFN_vkCmdCopyImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageCopy* pRegions);\ntypedef void (VKAPI_PTR *PFN_vkCmdBlitImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit* pRegions, VkFilter filter);\ntypedef void (VKAPI_PTR *PFN_vkCmdCopyBufferToImage)(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkBufferImageCopy* pRegions);\ntypedef void (VKAPI_PTR *PFN_vkCmdCopyImageToBuffer)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy* pRegions);\ntypedef void (VKAPI_PTR *PFN_vkCmdUpdateBuffer)(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const void* pData);\ntypedef void (VKAPI_PTR *PFN_vkCmdFillBuffer)(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data);\ntypedef void (VKAPI_PTR *PFN_vkCmdClearColorImage)(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearColorValue* pColor, uint32_t rangeCount, const VkImageSubresourceRange* pRanges);\ntypedef void (VKAPI_PTR *PFN_vkCmdClearDepthStencilImage)(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue* pDepthStencil, uint32_t rangeCount, const VkImageSubresourceRange* pRanges);\ntypedef void (VKAPI_PTR *PFN_vkCmdClearAttachments)(VkCommandBuffer commandBuffer, uint32_t attachmentCount, const VkClearAttachment* pAttachments, uint32_t rectCount, const VkClearRect* pRects);\ntypedef void (VKAPI_PTR *PFN_vkCmdResolveImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageResolve* pRegions);\ntypedef void (VKAPI_PTR *PFN_vkCmdSetEvent)(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask);\ntypedef void (VKAPI_PTR *PFN_vkCmdResetEvent)(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask);\ntypedef void (VKAPI_PTR *PFN_vkCmdWaitEvents)(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent* pEvents, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers);\ntypedef void (VKAPI_PTR *PFN_vkCmdPipelineBarrier)(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers);\ntypedef void (VKAPI_PTR *PFN_vkCmdBeginQuery)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags);\ntypedef void (VKAPI_PTR *PFN_vkCmdEndQuery)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query);\ntypedef void (VKAPI_PTR *PFN_vkCmdResetQueryPool)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount);\ntypedef void (VKAPI_PTR *PFN_vkCmdWriteTimestamp)(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage, VkQueryPool queryPool, uint32_t query);\ntypedef void (VKAPI_PTR *PFN_vkCmdCopyQueryPoolResults)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize stride, VkQueryResultFlags flags);\ntypedef void (VKAPI_PTR *PFN_vkCmdPushConstants)(VkCommandBuffer commandBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size, const void* pValues);\ntypedef void (VKAPI_PTR *PFN_vkCmdBeginRenderPass)(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, VkSubpassContents contents);\ntypedef void (VKAPI_PTR *PFN_vkCmdNextSubpass)(VkCommandBuffer commandBuffer, VkSubpassContents contents);\ntypedef void (VKAPI_PTR *PFN_vkCmdEndRenderPass)(VkCommandBuffer commandBuffer);\ntypedef void (VKAPI_PTR *PFN_vkCmdExecuteCommands)(VkCommandBuffer commandBuffer, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers);\n\n#ifndef VK_NO_PROTOTYPES\nVKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance(\n    const VkInstanceCreateInfo*                 pCreateInfo,\n    const VkAllocationCallbacks*                pAllocator,\n    VkInstance*                                 pInstance);\n\nVKAPI_ATTR void VKAPI_CALL vkDestroyInstance(\n    VkInstance                                  instance,\n    const VkAllocationCallbacks*                pAllocator);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDevices(\n    VkInstance                                  instance,\n    uint32_t*                                   pPhysicalDeviceCount,\n    VkPhysicalDevice*                           pPhysicalDevices);\n\nVKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFeatures(\n    VkPhysicalDevice                            physicalDevice,\n    VkPhysicalDeviceFeatures*                   pFeatures);\n\nVKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFormatProperties(\n    VkPhysicalDevice                            physicalDevice,\n    VkFormat                                    format,\n    VkFormatProperties*                         pFormatProperties);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceImageFormatProperties(\n    VkPhysicalDevice                            physicalDevice,\n    VkFormat                                    format,\n    VkImageType                                 type,\n    VkImageTiling                               tiling,\n    VkImageUsageFlags                           usage,\n    VkImageCreateFlags                          flags,\n    VkImageFormatProperties*                    pImageFormatProperties);\n\nVKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceProperties(\n    VkPhysicalDevice                            physicalDevice,\n    VkPhysicalDeviceProperties*                 pProperties);\n\nVKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyProperties(\n    VkPhysicalDevice                            physicalDevice,\n    uint32_t*                                   pQueueFamilyPropertyCount,\n    VkQueueFamilyProperties*                    pQueueFamilyProperties);\n\nVKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties(\n    VkPhysicalDevice                            physicalDevice,\n    VkPhysicalDeviceMemoryProperties*           pMemoryProperties);\n\nVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(\n    VkInstance                                  instance,\n    const char*                                 pName);\n\nVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(\n    VkDevice                                    device,\n    const char*                                 pName);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkCreateDevice(\n    VkPhysicalDevice                            physicalDevice,\n    const VkDeviceCreateInfo*                   pCreateInfo,\n    const VkAllocationCallbacks*                pAllocator,\n    VkDevice*                                   pDevice);\n\nVKAPI_ATTR void VKAPI_CALL vkDestroyDevice(\n    VkDevice                                    device,\n    const VkAllocationCallbacks*                pAllocator);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties(\n    const char*                                 pLayerName,\n    uint32_t*                                   pPropertyCount,\n    VkExtensionProperties*                      pProperties);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties(\n    VkPhysicalDevice                            physicalDevice,\n    const char*                                 pLayerName,\n    uint32_t*                                   pPropertyCount,\n    VkExtensionProperties*                      pProperties);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties(\n    uint32_t*                                   pPropertyCount,\n    VkLayerProperties*                          pProperties);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceLayerProperties(\n    VkPhysicalDevice                            physicalDevice,\n    uint32_t*                                   pPropertyCount,\n    VkLayerProperties*                          pProperties);\n\nVKAPI_ATTR void VKAPI_CALL vkGetDeviceQueue(\n    VkDevice                                    device,\n    uint32_t                                    queueFamilyIndex,\n    uint32_t                                    queueIndex,\n    VkQueue*                                    pQueue);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkQueueSubmit(\n    VkQueue                                     queue,\n    uint32_t                                    submitCount,\n    const VkSubmitInfo*                         pSubmits,\n    VkFence                                     fence);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkQueueWaitIdle(\n    VkQueue                                     queue);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkDeviceWaitIdle(\n    VkDevice                                    device);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkAllocateMemory(\n    VkDevice                                    device,\n    const VkMemoryAllocateInfo*                 pAllocateInfo,\n    const VkAllocationCallbacks*                pAllocator,\n    VkDeviceMemory*                             pMemory);\n\nVKAPI_ATTR void VKAPI_CALL vkFreeMemory(\n    VkDevice                                    device,\n    VkDeviceMemory                              memory,\n    const VkAllocationCallbacks*                pAllocator);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkMapMemory(\n    VkDevice                                    device,\n    VkDeviceMemory                              memory,\n    VkDeviceSize                                offset,\n    VkDeviceSize                                size,\n    VkMemoryMapFlags                            flags,\n    void**                                      ppData);\n\nVKAPI_ATTR void VKAPI_CALL vkUnmapMemory(\n    VkDevice                                    device,\n    VkDeviceMemory                              memory);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkFlushMappedMemoryRanges(\n    VkDevice                                    device,\n    uint32_t                                    memoryRangeCount,\n    const VkMappedMemoryRange*                  pMemoryRanges);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkInvalidateMappedMemoryRanges(\n    VkDevice                                    device,\n    uint32_t                                    memoryRangeCount,\n    const VkMappedMemoryRange*                  pMemoryRanges);\n\nVKAPI_ATTR void VKAPI_CALL vkGetDeviceMemoryCommitment(\n    VkDevice                                    device,\n    VkDeviceMemory                              memory,\n    VkDeviceSize*                               pCommittedMemoryInBytes);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkBindBufferMemory(\n    VkDevice                                    device,\n    VkBuffer                                    buffer,\n    VkDeviceMemory                              memory,\n    VkDeviceSize                                memoryOffset);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory(\n    VkDevice                                    device,\n    VkImage                                     image,\n    VkDeviceMemory                              memory,\n    VkDeviceSize                                memoryOffset);\n\nVKAPI_ATTR void VKAPI_CALL vkGetBufferMemoryRequirements(\n    VkDevice                                    device,\n    VkBuffer                                    buffer,\n    VkMemoryRequirements*                       pMemoryRequirements);\n\nVKAPI_ATTR void VKAPI_CALL vkGetImageMemoryRequirements(\n    VkDevice                                    device,\n    VkImage                                     image,\n    VkMemoryRequirements*                       pMemoryRequirements);\n\nVKAPI_ATTR void VKAPI_CALL vkGetImageSparseMemoryRequirements(\n    VkDevice                                    device,\n    VkImage                                     image,\n    uint32_t*                                   pSparseMemoryRequirementCount,\n    VkSparseImageMemoryRequirements*            pSparseMemoryRequirements);\n\nVKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceSparseImageFormatProperties(\n    VkPhysicalDevice                            physicalDevice,\n    VkFormat                                    format,\n    VkImageType                                 type,\n    VkSampleCountFlagBits                       samples,\n    VkImageUsageFlags                           usage,\n    VkImageTiling                               tiling,\n    uint32_t*                                   pPropertyCount,\n    VkSparseImageFormatProperties*              pProperties);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkQueueBindSparse(\n    VkQueue                                     queue,\n    uint32_t                                    bindInfoCount,\n    const VkBindSparseInfo*                     pBindInfo,\n    VkFence                                     fence);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkCreateFence(\n    VkDevice                                    device,\n    const VkFenceCreateInfo*                    pCreateInfo,\n    const VkAllocationCallbacks*                pAllocator,\n    VkFence*                                    pFence);\n\nVKAPI_ATTR void VKAPI_CALL vkDestroyFence(\n    VkDevice                                    device,\n    VkFence                                     fence,\n    const VkAllocationCallbacks*                pAllocator);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkResetFences(\n    VkDevice                                    device,\n    uint32_t                                    fenceCount,\n    const VkFence*                              pFences);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkGetFenceStatus(\n    VkDevice                                    device,\n    VkFence                                     fence);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkWaitForFences(\n    VkDevice                                    device,\n    uint32_t                                    fenceCount,\n    const VkFence*                              pFences,\n    VkBool32                                    waitAll,\n    uint64_t                                    timeout);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkCreateSemaphore(\n    VkDevice                                    device,\n    const VkSemaphoreCreateInfo*                pCreateInfo,\n    const VkAllocationCallbacks*                pAllocator,\n    VkSemaphore*                                pSemaphore);\n\nVKAPI_ATTR void VKAPI_CALL vkDestroySemaphore(\n    VkDevice                                    device,\n    VkSemaphore                                 semaphore,\n    const VkAllocationCallbacks*                pAllocator);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkCreateEvent(\n    VkDevice                                    device,\n    const VkEventCreateInfo*                    pCreateInfo,\n    const VkAllocationCallbacks*                pAllocator,\n    VkEvent*                                    pEvent);\n\nVKAPI_ATTR void VKAPI_CALL vkDestroyEvent(\n    VkDevice                                    device,\n    VkEvent                                     event,\n    const VkAllocationCallbacks*                pAllocator);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkGetEventStatus(\n    VkDevice                                    device,\n    VkEvent                                     event);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkSetEvent(\n    VkDevice                                    device,\n    VkEvent                                     event);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkResetEvent(\n    VkDevice                                    device,\n    VkEvent                                     event);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkCreateQueryPool(\n    VkDevice                                    device,\n    const VkQueryPoolCreateInfo*                pCreateInfo,\n    const VkAllocationCallbacks*                pAllocator,\n    VkQueryPool*                                pQueryPool);\n\nVKAPI_ATTR void VKAPI_CALL vkDestroyQueryPool(\n    VkDevice                                    device,\n    VkQueryPool                                 queryPool,\n    const VkAllocationCallbacks*                pAllocator);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkGetQueryPoolResults(\n    VkDevice                                    device,\n    VkQueryPool                                 queryPool,\n    uint32_t                                    firstQuery,\n    uint32_t                                    queryCount,\n    size_t                                      dataSize,\n    void*                                       pData,\n    VkDeviceSize                                stride,\n    VkQueryResultFlags                          flags);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkCreateBuffer(\n    VkDevice                                    device,\n    const VkBufferCreateInfo*                   pCreateInfo,\n    const VkAllocationCallbacks*                pAllocator,\n    VkBuffer*                                   pBuffer);\n\nVKAPI_ATTR void VKAPI_CALL vkDestroyBuffer(\n    VkDevice                                    device,\n    VkBuffer                                    buffer,\n    const VkAllocationCallbacks*                pAllocator);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkCreateBufferView(\n    VkDevice                                    device,\n    const VkBufferViewCreateInfo*               pCreateInfo,\n    const VkAllocationCallbacks*                pAllocator,\n    VkBufferView*                               pView);\n\nVKAPI_ATTR void VKAPI_CALL vkDestroyBufferView(\n    VkDevice                                    device,\n    VkBufferView                                bufferView,\n    const VkAllocationCallbacks*                pAllocator);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkCreateImage(\n    VkDevice                                    device,\n    const VkImageCreateInfo*                    pCreateInfo,\n    const VkAllocationCallbacks*                pAllocator,\n    VkImage*                                    pImage);\n\nVKAPI_ATTR void VKAPI_CALL vkDestroyImage(\n    VkDevice                                    device,\n    VkImage                                     image,\n    const VkAllocationCallbacks*                pAllocator);\n\nVKAPI_ATTR void VKAPI_CALL vkGetImageSubresourceLayout(\n    VkDevice                                    device,\n    VkImage                                     image,\n    const VkImageSubresource*                   pSubresource,\n    VkSubresourceLayout*                        pLayout);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkCreateImageView(\n    VkDevice                                    device,\n    const VkImageViewCreateInfo*                pCreateInfo,\n    const VkAllocationCallbacks*                pAllocator,\n    VkImageView*                                pView);\n\nVKAPI_ATTR void VKAPI_CALL vkDestroyImageView(\n    VkDevice                                    device,\n    VkImageView                                 imageView,\n    const VkAllocationCallbacks*                pAllocator);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkCreateShaderModule(\n    VkDevice                                    device,\n    const VkShaderModuleCreateInfo*             pCreateInfo,\n    const VkAllocationCallbacks*                pAllocator,\n    VkShaderModule*                             pShaderModule);\n\nVKAPI_ATTR void VKAPI_CALL vkDestroyShaderModule(\n    VkDevice                                    device,\n    VkShaderModule                              shaderModule,\n    const VkAllocationCallbacks*                pAllocator);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkCreatePipelineCache(\n    VkDevice                                    device,\n    const VkPipelineCacheCreateInfo*            pCreateInfo,\n    const VkAllocationCallbacks*                pAllocator,\n    VkPipelineCache*                            pPipelineCache);\n\nVKAPI_ATTR void VKAPI_CALL vkDestroyPipelineCache(\n    VkDevice                                    device,\n    VkPipelineCache                             pipelineCache,\n    const VkAllocationCallbacks*                pAllocator);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkGetPipelineCacheData(\n    VkDevice                                    device,\n    VkPipelineCache                             pipelineCache,\n    size_t*                                     pDataSize,\n    void*                                       pData);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkMergePipelineCaches(\n    VkDevice                                    device,\n    VkPipelineCache                             dstCache,\n    uint32_t                                    srcCacheCount,\n    const VkPipelineCache*                      pSrcCaches);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkCreateGraphicsPipelines(\n    VkDevice                                    device,\n    VkPipelineCache                             pipelineCache,\n    uint32_t                                    createInfoCount,\n    const VkGraphicsPipelineCreateInfo*         pCreateInfos,\n    const VkAllocationCallbacks*                pAllocator,\n    VkPipeline*                                 pPipelines);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkCreateComputePipelines(\n    VkDevice                                    device,\n    VkPipelineCache                             pipelineCache,\n    uint32_t                                    createInfoCount,\n    const VkComputePipelineCreateInfo*          pCreateInfos,\n    const VkAllocationCallbacks*                pAllocator,\n    VkPipeline*                                 pPipelines);\n\nVKAPI_ATTR void VKAPI_CALL vkDestroyPipeline(\n    VkDevice                                    device,\n    VkPipeline                                  pipeline,\n    const VkAllocationCallbacks*                pAllocator);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkCreatePipelineLayout(\n    VkDevice                                    device,\n    const VkPipelineLayoutCreateInfo*           pCreateInfo,\n    const VkAllocationCallbacks*                pAllocator,\n    VkPipelineLayout*                           pPipelineLayout);\n\nVKAPI_ATTR void VKAPI_CALL vkDestroyPipelineLayout(\n    VkDevice                                    device,\n    VkPipelineLayout                            pipelineLayout,\n    const VkAllocationCallbacks*                pAllocator);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkCreateSampler(\n    VkDevice                                    device,\n    const VkSamplerCreateInfo*                  pCreateInfo,\n    const VkAllocationCallbacks*                pAllocator,\n    VkSampler*                                  pSampler);\n\nVKAPI_ATTR void VKAPI_CALL vkDestroySampler(\n    VkDevice                                    device,\n    VkSampler                                   sampler,\n    const VkAllocationCallbacks*                pAllocator);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorSetLayout(\n    VkDevice                                    device,\n    const VkDescriptorSetLayoutCreateInfo*      pCreateInfo,\n    const VkAllocationCallbacks*                pAllocator,\n    VkDescriptorSetLayout*                      pSetLayout);\n\nVKAPI_ATTR void VKAPI_CALL vkDestroyDescriptorSetLayout(\n    VkDevice                                    device,\n    VkDescriptorSetLayout                       descriptorSetLayout,\n    const VkAllocationCallbacks*                pAllocator);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorPool(\n    VkDevice                                    device,\n    const VkDescriptorPoolCreateInfo*           pCreateInfo,\n    const VkAllocationCallbacks*                pAllocator,\n    VkDescriptorPool*                           pDescriptorPool);\n\nVKAPI_ATTR void VKAPI_CALL vkDestroyDescriptorPool(\n    VkDevice                                    device,\n    VkDescriptorPool                            descriptorPool,\n    const VkAllocationCallbacks*                pAllocator);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkResetDescriptorPool(\n    VkDevice                                    device,\n    VkDescriptorPool                            descriptorPool,\n    VkDescriptorPoolResetFlags                  flags);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkAllocateDescriptorSets(\n    VkDevice                                    device,\n    const VkDescriptorSetAllocateInfo*          pAllocateInfo,\n    VkDescriptorSet*                            pDescriptorSets);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkFreeDescriptorSets(\n    VkDevice                                    device,\n    VkDescriptorPool                            descriptorPool,\n    uint32_t                                    descriptorSetCount,\n    const VkDescriptorSet*                      pDescriptorSets);\n\nVKAPI_ATTR void VKAPI_CALL vkUpdateDescriptorSets(\n    VkDevice                                    device,\n    uint32_t                                    descriptorWriteCount,\n    const VkWriteDescriptorSet*                 pDescriptorWrites,\n    uint32_t                                    descriptorCopyCount,\n    const VkCopyDescriptorSet*                  pDescriptorCopies);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkCreateFramebuffer(\n    VkDevice                                    device,\n    const VkFramebufferCreateInfo*              pCreateInfo,\n    const VkAllocationCallbacks*                pAllocator,\n    VkFramebuffer*                              pFramebuffer);\n\nVKAPI_ATTR void VKAPI_CALL vkDestroyFramebuffer(\n    VkDevice                                    device,\n    VkFramebuffer                               framebuffer,\n    const VkAllocationCallbacks*                pAllocator);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkCreateRenderPass(\n    VkDevice                                    device,\n    const VkRenderPassCreateInfo*               pCreateInfo,\n    const VkAllocationCallbacks*                pAllocator,\n    VkRenderPass*                               pRenderPass);\n\nVKAPI_ATTR void VKAPI_CALL vkDestroyRenderPass(\n    VkDevice                                    device,\n    VkRenderPass                                renderPass,\n    const VkAllocationCallbacks*                pAllocator);\n\nVKAPI_ATTR void VKAPI_CALL vkGetRenderAreaGranularity(\n    VkDevice                                    device,\n    VkRenderPass                                renderPass,\n    VkExtent2D*                                 pGranularity);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkCreateCommandPool(\n    VkDevice                                    device,\n    const VkCommandPoolCreateInfo*              pCreateInfo,\n    const VkAllocationCallbacks*                pAllocator,\n    VkCommandPool*                              pCommandPool);\n\nVKAPI_ATTR void VKAPI_CALL vkDestroyCommandPool(\n    VkDevice                                    device,\n    VkCommandPool                               commandPool,\n    const VkAllocationCallbacks*                pAllocator);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkResetCommandPool(\n    VkDevice                                    device,\n    VkCommandPool                               commandPool,\n    VkCommandPoolResetFlags                     flags);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkAllocateCommandBuffers(\n    VkDevice                                    device,\n    const VkCommandBufferAllocateInfo*          pAllocateInfo,\n    VkCommandBuffer*                            pCommandBuffers);\n\nVKAPI_ATTR void VKAPI_CALL vkFreeCommandBuffers(\n    VkDevice                                    device,\n    VkCommandPool                               commandPool,\n    uint32_t                                    commandBufferCount,\n    const VkCommandBuffer*                      pCommandBuffers);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkBeginCommandBuffer(\n    VkCommandBuffer                             commandBuffer,\n    const VkCommandBufferBeginInfo*             pBeginInfo);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkEndCommandBuffer(\n    VkCommandBuffer                             commandBuffer);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkResetCommandBuffer(\n    VkCommandBuffer                             commandBuffer,\n    VkCommandBufferResetFlags                   flags);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdBindPipeline(\n    VkCommandBuffer                             commandBuffer,\n    VkPipelineBindPoint                         pipelineBindPoint,\n    VkPipeline                                  pipeline);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdSetViewport(\n    VkCommandBuffer                             commandBuffer,\n    uint32_t                                    firstViewport,\n    uint32_t                                    viewportCount,\n    const VkViewport*                           pViewports);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdSetScissor(\n    VkCommandBuffer                             commandBuffer,\n    uint32_t                                    firstScissor,\n    uint32_t                                    scissorCount,\n    const VkRect2D*                             pScissors);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdSetLineWidth(\n    VkCommandBuffer                             commandBuffer,\n    float                                       lineWidth);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdSetDepthBias(\n    VkCommandBuffer                             commandBuffer,\n    float                                       depthBiasConstantFactor,\n    float                                       depthBiasClamp,\n    float                                       depthBiasSlopeFactor);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdSetBlendConstants(\n    VkCommandBuffer                             commandBuffer,\n    const float                                 blendConstants[4]);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdSetDepthBounds(\n    VkCommandBuffer                             commandBuffer,\n    float                                       minDepthBounds,\n    float                                       maxDepthBounds);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdSetStencilCompareMask(\n    VkCommandBuffer                             commandBuffer,\n    VkStencilFaceFlags                          faceMask,\n    uint32_t                                    compareMask);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdSetStencilWriteMask(\n    VkCommandBuffer                             commandBuffer,\n    VkStencilFaceFlags                          faceMask,\n    uint32_t                                    writeMask);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdSetStencilReference(\n    VkCommandBuffer                             commandBuffer,\n    VkStencilFaceFlags                          faceMask,\n    uint32_t                                    reference);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdBindDescriptorSets(\n    VkCommandBuffer                             commandBuffer,\n    VkPipelineBindPoint                         pipelineBindPoint,\n    VkPipelineLayout                            layout,\n    uint32_t                                    firstSet,\n    uint32_t                                    descriptorSetCount,\n    const VkDescriptorSet*                      pDescriptorSets,\n    uint32_t                                    dynamicOffsetCount,\n    const uint32_t*                             pDynamicOffsets);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdBindIndexBuffer(\n    VkCommandBuffer                             commandBuffer,\n    VkBuffer                                    buffer,\n    VkDeviceSize                                offset,\n    VkIndexType                                 indexType);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdBindVertexBuffers(\n    VkCommandBuffer                             commandBuffer,\n    uint32_t                                    firstBinding,\n    uint32_t                                    bindingCount,\n    const VkBuffer*                             pBuffers,\n    const VkDeviceSize*                         pOffsets);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdDraw(\n    VkCommandBuffer                             commandBuffer,\n    uint32_t                                    vertexCount,\n    uint32_t                                    instanceCount,\n    uint32_t                                    firstVertex,\n    uint32_t                                    firstInstance);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexed(\n    VkCommandBuffer                             commandBuffer,\n    uint32_t                                    indexCount,\n    uint32_t                                    instanceCount,\n    uint32_t                                    firstIndex,\n    int32_t                                     vertexOffset,\n    uint32_t                                    firstInstance);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirect(\n    VkCommandBuffer                             commandBuffer,\n    VkBuffer                                    buffer,\n    VkDeviceSize                                offset,\n    uint32_t                                    drawCount,\n    uint32_t                                    stride);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexedIndirect(\n    VkCommandBuffer                             commandBuffer,\n    VkBuffer                                    buffer,\n    VkDeviceSize                                offset,\n    uint32_t                                    drawCount,\n    uint32_t                                    stride);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdDispatch(\n    VkCommandBuffer                             commandBuffer,\n    uint32_t                                    groupCountX,\n    uint32_t                                    groupCountY,\n    uint32_t                                    groupCountZ);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdDispatchIndirect(\n    VkCommandBuffer                             commandBuffer,\n    VkBuffer                                    buffer,\n    VkDeviceSize                                offset);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdCopyBuffer(\n    VkCommandBuffer                             commandBuffer,\n    VkBuffer                                    srcBuffer,\n    VkBuffer                                    dstBuffer,\n    uint32_t                                    regionCount,\n    const VkBufferCopy*                         pRegions);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdCopyImage(\n    VkCommandBuffer                             commandBuffer,\n    VkImage                                     srcImage,\n    VkImageLayout                               srcImageLayout,\n    VkImage                                     dstImage,\n    VkImageLayout                               dstImageLayout,\n    uint32_t                                    regionCount,\n    const VkImageCopy*                          pRegions);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdBlitImage(\n    VkCommandBuffer                             commandBuffer,\n    VkImage                                     srcImage,\n    VkImageLayout                               srcImageLayout,\n    VkImage                                     dstImage,\n    VkImageLayout                               dstImageLayout,\n    uint32_t                                    regionCount,\n    const VkImageBlit*                          pRegions,\n    VkFilter                                    filter);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdCopyBufferToImage(\n    VkCommandBuffer                             commandBuffer,\n    VkBuffer                                    srcBuffer,\n    VkImage                                     dstImage,\n    VkImageLayout                               dstImageLayout,\n    uint32_t                                    regionCount,\n    const VkBufferImageCopy*                    pRegions);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdCopyImageToBuffer(\n    VkCommandBuffer                             commandBuffer,\n    VkImage                                     srcImage,\n    VkImageLayout                               srcImageLayout,\n    VkBuffer                                    dstBuffer,\n    uint32_t                                    regionCount,\n    const VkBufferImageCopy*                    pRegions);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdUpdateBuffer(\n    VkCommandBuffer                             commandBuffer,\n    VkBuffer                                    dstBuffer,\n    VkDeviceSize                                dstOffset,\n    VkDeviceSize                                dataSize,\n    const void*                                 pData);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdFillBuffer(\n    VkCommandBuffer                             commandBuffer,\n    VkBuffer                                    dstBuffer,\n    VkDeviceSize                                dstOffset,\n    VkDeviceSize                                size,\n    uint32_t                                    data);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdClearColorImage(\n    VkCommandBuffer                             commandBuffer,\n    VkImage                                     image,\n    VkImageLayout                               imageLayout,\n    const VkClearColorValue*                    pColor,\n    uint32_t                                    rangeCount,\n    const VkImageSubresourceRange*              pRanges);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdClearDepthStencilImage(\n    VkCommandBuffer                             commandBuffer,\n    VkImage                                     image,\n    VkImageLayout                               imageLayout,\n    const VkClearDepthStencilValue*             pDepthStencil,\n    uint32_t                                    rangeCount,\n    const VkImageSubresourceRange*              pRanges);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdClearAttachments(\n    VkCommandBuffer                             commandBuffer,\n    uint32_t                                    attachmentCount,\n    const VkClearAttachment*                    pAttachments,\n    uint32_t                                    rectCount,\n    const VkClearRect*                          pRects);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdResolveImage(\n    VkCommandBuffer                             commandBuffer,\n    VkImage                                     srcImage,\n    VkImageLayout                               srcImageLayout,\n    VkImage                                     dstImage,\n    VkImageLayout                               dstImageLayout,\n    uint32_t                                    regionCount,\n    const VkImageResolve*                       pRegions);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdSetEvent(\n    VkCommandBuffer                             commandBuffer,\n    VkEvent                                     event,\n    VkPipelineStageFlags                        stageMask);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdResetEvent(\n    VkCommandBuffer                             commandBuffer,\n    VkEvent                                     event,\n    VkPipelineStageFlags                        stageMask);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdWaitEvents(\n    VkCommandBuffer                             commandBuffer,\n    uint32_t                                    eventCount,\n    const VkEvent*                              pEvents,\n    VkPipelineStageFlags                        srcStageMask,\n    VkPipelineStageFlags                        dstStageMask,\n    uint32_t                                    memoryBarrierCount,\n    const VkMemoryBarrier*                      pMemoryBarriers,\n    uint32_t                                    bufferMemoryBarrierCount,\n    const VkBufferMemoryBarrier*                pBufferMemoryBarriers,\n    uint32_t                                    imageMemoryBarrierCount,\n    const VkImageMemoryBarrier*                 pImageMemoryBarriers);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdPipelineBarrier(\n    VkCommandBuffer                             commandBuffer,\n    VkPipelineStageFlags                        srcStageMask,\n    VkPipelineStageFlags                        dstStageMask,\n    VkDependencyFlags                           dependencyFlags,\n    uint32_t                                    memoryBarrierCount,\n    const VkMemoryBarrier*                      pMemoryBarriers,\n    uint32_t                                    bufferMemoryBarrierCount,\n    const VkBufferMemoryBarrier*                pBufferMemoryBarriers,\n    uint32_t                                    imageMemoryBarrierCount,\n    const VkImageMemoryBarrier*                 pImageMemoryBarriers);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdBeginQuery(\n    VkCommandBuffer                             commandBuffer,\n    VkQueryPool                                 queryPool,\n    uint32_t                                    query,\n    VkQueryControlFlags                         flags);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdEndQuery(\n    VkCommandBuffer                             commandBuffer,\n    VkQueryPool                                 queryPool,\n    uint32_t                                    query);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdResetQueryPool(\n    VkCommandBuffer                             commandBuffer,\n    VkQueryPool                                 queryPool,\n    uint32_t                                    firstQuery,\n    uint32_t                                    queryCount);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdWriteTimestamp(\n    VkCommandBuffer                             commandBuffer,\n    VkPipelineStageFlagBits                     pipelineStage,\n    VkQueryPool                                 queryPool,\n    uint32_t                                    query);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdCopyQueryPoolResults(\n    VkCommandBuffer                             commandBuffer,\n    VkQueryPool                                 queryPool,\n    uint32_t                                    firstQuery,\n    uint32_t                                    queryCount,\n    VkBuffer                                    dstBuffer,\n    VkDeviceSize                                dstOffset,\n    VkDeviceSize                                stride,\n    VkQueryResultFlags                          flags);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdPushConstants(\n    VkCommandBuffer                             commandBuffer,\n    VkPipelineLayout                            layout,\n    VkShaderStageFlags                          stageFlags,\n    uint32_t                                    offset,\n    uint32_t                                    size,\n    const void*                                 pValues);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdBeginRenderPass(\n    VkCommandBuffer                             commandBuffer,\n    const VkRenderPassBeginInfo*                pRenderPassBegin,\n    VkSubpassContents                           contents);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdNextSubpass(\n    VkCommandBuffer                             commandBuffer,\n    VkSubpassContents                           contents);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdEndRenderPass(\n    VkCommandBuffer                             commandBuffer);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdExecuteCommands(\n    VkCommandBuffer                             commandBuffer,\n    uint32_t                                    commandBufferCount,\n    const VkCommandBuffer*                      pCommandBuffers);\n#endif\n\n#define VK_KHR_surface 1\nVK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSurfaceKHR)\n\n#define VK_KHR_SURFACE_SPEC_VERSION       25\n#define VK_KHR_SURFACE_EXTENSION_NAME     \"VK_KHR_surface\"\n#define VK_COLORSPACE_SRGB_NONLINEAR_KHR  VK_COLOR_SPACE_SRGB_NONLINEAR_KHR\n\n\ntypedef enum VkColorSpaceKHR {\n    VK_COLOR_SPACE_SRGB_NONLINEAR_KHR = 0,\n    VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT = 1000104001,\n    VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT = 1000104002,\n    VK_COLOR_SPACE_DCI_P3_LINEAR_EXT = 1000104003,\n    VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT = 1000104004,\n    VK_COLOR_SPACE_BT709_LINEAR_EXT = 1000104005,\n    VK_COLOR_SPACE_BT709_NONLINEAR_EXT = 1000104006,\n    VK_COLOR_SPACE_BT2020_LINEAR_EXT = 1000104007,\n    VK_COLOR_SPACE_HDR10_ST2084_EXT = 1000104008,\n    VK_COLOR_SPACE_DOLBYVISION_EXT = 1000104009,\n    VK_COLOR_SPACE_HDR10_HLG_EXT = 1000104010,\n    VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT = 1000104011,\n    VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT = 1000104012,\n    VK_COLOR_SPACE_PASS_THROUGH_EXT = 1000104013,\n    VK_COLOR_SPACE_BEGIN_RANGE_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,\n    VK_COLOR_SPACE_END_RANGE_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,\n    VK_COLOR_SPACE_RANGE_SIZE_KHR = (VK_COLOR_SPACE_SRGB_NONLINEAR_KHR - VK_COLOR_SPACE_SRGB_NONLINEAR_KHR + 1),\n    VK_COLOR_SPACE_MAX_ENUM_KHR = 0x7FFFFFFF\n} VkColorSpaceKHR;\n\ntypedef enum VkPresentModeKHR {\n    VK_PRESENT_MODE_IMMEDIATE_KHR = 0,\n    VK_PRESENT_MODE_MAILBOX_KHR = 1,\n    VK_PRESENT_MODE_FIFO_KHR = 2,\n    VK_PRESENT_MODE_FIFO_RELAXED_KHR = 3,\n    VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR = 1000111000,\n    VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR = 1000111001,\n    VK_PRESENT_MODE_BEGIN_RANGE_KHR = VK_PRESENT_MODE_IMMEDIATE_KHR,\n    VK_PRESENT_MODE_END_RANGE_KHR = VK_PRESENT_MODE_FIFO_RELAXED_KHR,\n    VK_PRESENT_MODE_RANGE_SIZE_KHR = (VK_PRESENT_MODE_FIFO_RELAXED_KHR - VK_PRESENT_MODE_IMMEDIATE_KHR + 1),\n    VK_PRESENT_MODE_MAX_ENUM_KHR = 0x7FFFFFFF\n} VkPresentModeKHR;\n\n\ntypedef enum VkSurfaceTransformFlagBitsKHR {\n    VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR = 0x00000001,\n    VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR = 0x00000002,\n    VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR = 0x00000004,\n    VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR = 0x00000008,\n    VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR = 0x00000010,\n    VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR = 0x00000020,\n    VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR = 0x00000040,\n    VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR = 0x00000080,\n    VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR = 0x00000100,\n    VK_SURFACE_TRANSFORM_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF\n} VkSurfaceTransformFlagBitsKHR;\ntypedef VkFlags VkSurfaceTransformFlagsKHR;\n\ntypedef enum VkCompositeAlphaFlagBitsKHR {\n    VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR = 0x00000001,\n    VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR = 0x00000002,\n    VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR = 0x00000004,\n    VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR = 0x00000008,\n    VK_COMPOSITE_ALPHA_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF\n} VkCompositeAlphaFlagBitsKHR;\ntypedef VkFlags VkCompositeAlphaFlagsKHR;\n\ntypedef struct VkSurfaceCapabilitiesKHR {\n    uint32_t                         minImageCount;\n    uint32_t                         maxImageCount;\n    VkExtent2D                       currentExtent;\n    VkExtent2D                       minImageExtent;\n    VkExtent2D                       maxImageExtent;\n    uint32_t                         maxImageArrayLayers;\n    VkSurfaceTransformFlagsKHR       supportedTransforms;\n    VkSurfaceTransformFlagBitsKHR    currentTransform;\n    VkCompositeAlphaFlagsKHR         supportedCompositeAlpha;\n    VkImageUsageFlags                supportedUsageFlags;\n} VkSurfaceCapabilitiesKHR;\n\ntypedef struct VkSurfaceFormatKHR {\n    VkFormat           format;\n    VkColorSpaceKHR    colorSpace;\n} VkSurfaceFormatKHR;\n\n\ntypedef void (VKAPI_PTR *PFN_vkDestroySurfaceKHR)(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks* pAllocator);\ntypedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, VkSurfaceKHR surface, VkBool32* pSupported);\ntypedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR* pSurfaceCapabilities);\ntypedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceFormatsKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pSurfaceFormatCount, VkSurfaceFormatKHR* pSurfaceFormats);\ntypedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfacePresentModesKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pPresentModeCount, VkPresentModeKHR* pPresentModes);\n\n#ifndef VK_NO_PROTOTYPES\nVKAPI_ATTR void VKAPI_CALL vkDestroySurfaceKHR(\n    VkInstance                                  instance,\n    VkSurfaceKHR                                surface,\n    const VkAllocationCallbacks*                pAllocator);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceSupportKHR(\n    VkPhysicalDevice                            physicalDevice,\n    uint32_t                                    queueFamilyIndex,\n    VkSurfaceKHR                                surface,\n    VkBool32*                                   pSupported);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilitiesKHR(\n    VkPhysicalDevice                            physicalDevice,\n    VkSurfaceKHR                                surface,\n    VkSurfaceCapabilitiesKHR*                   pSurfaceCapabilities);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceFormatsKHR(\n    VkPhysicalDevice                            physicalDevice,\n    VkSurfaceKHR                                surface,\n    uint32_t*                                   pSurfaceFormatCount,\n    VkSurfaceFormatKHR*                         pSurfaceFormats);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfacePresentModesKHR(\n    VkPhysicalDevice                            physicalDevice,\n    VkSurfaceKHR                                surface,\n    uint32_t*                                   pPresentModeCount,\n    VkPresentModeKHR*                           pPresentModes);\n#endif\n\n#define VK_KHR_swapchain 1\nVK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSwapchainKHR)\n\n#define VK_KHR_SWAPCHAIN_SPEC_VERSION     68\n#define VK_KHR_SWAPCHAIN_EXTENSION_NAME   \"VK_KHR_swapchain\"\n\n\ntypedef enum VkSwapchainCreateFlagBitsKHR {\n    VK_SWAPCHAIN_CREATE_BIND_SFR_BIT_KHX = 0x00000001,\n    VK_SWAPCHAIN_CREATE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF\n} VkSwapchainCreateFlagBitsKHR;\ntypedef VkFlags VkSwapchainCreateFlagsKHR;\n\ntypedef struct VkSwapchainCreateInfoKHR {\n    VkStructureType                  sType;\n    const void*                      pNext;\n    VkSwapchainCreateFlagsKHR        flags;\n    VkSurfaceKHR                     surface;\n    uint32_t                         minImageCount;\n    VkFormat                         imageFormat;\n    VkColorSpaceKHR                  imageColorSpace;\n    VkExtent2D                       imageExtent;\n    uint32_t                         imageArrayLayers;\n    VkImageUsageFlags                imageUsage;\n    VkSharingMode                    imageSharingMode;\n    uint32_t                         queueFamilyIndexCount;\n    const uint32_t*                  pQueueFamilyIndices;\n    VkSurfaceTransformFlagBitsKHR    preTransform;\n    VkCompositeAlphaFlagBitsKHR      compositeAlpha;\n    VkPresentModeKHR                 presentMode;\n    VkBool32                         clipped;\n    VkSwapchainKHR                   oldSwapchain;\n} VkSwapchainCreateInfoKHR;\n\ntypedef struct VkPresentInfoKHR {\n    VkStructureType          sType;\n    const void*              pNext;\n    uint32_t                 waitSemaphoreCount;\n    const VkSemaphore*       pWaitSemaphores;\n    uint32_t                 swapchainCount;\n    const VkSwapchainKHR*    pSwapchains;\n    const uint32_t*          pImageIndices;\n    VkResult*                pResults;\n} VkPresentInfoKHR;\n\n\ntypedef VkResult (VKAPI_PTR *PFN_vkCreateSwapchainKHR)(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchain);\ntypedef void (VKAPI_PTR *PFN_vkDestroySwapchainKHR)(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks* pAllocator);\ntypedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainImagesKHR)(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pSwapchainImageCount, VkImage* pSwapchainImages);\ntypedef VkResult (VKAPI_PTR *PFN_vkAcquireNextImageKHR)(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t* pImageIndex);\ntypedef VkResult (VKAPI_PTR *PFN_vkQueuePresentKHR)(VkQueue queue, const VkPresentInfoKHR* pPresentInfo);\n\n#ifndef VK_NO_PROTOTYPES\nVKAPI_ATTR VkResult VKAPI_CALL vkCreateSwapchainKHR(\n    VkDevice                                    device,\n    const VkSwapchainCreateInfoKHR*             pCreateInfo,\n    const VkAllocationCallbacks*                pAllocator,\n    VkSwapchainKHR*                             pSwapchain);\n\nVKAPI_ATTR void VKAPI_CALL vkDestroySwapchainKHR(\n    VkDevice                                    device,\n    VkSwapchainKHR                              swapchain,\n    const VkAllocationCallbacks*                pAllocator);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainImagesKHR(\n    VkDevice                                    device,\n    VkSwapchainKHR                              swapchain,\n    uint32_t*                                   pSwapchainImageCount,\n    VkImage*                                    pSwapchainImages);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkAcquireNextImageKHR(\n    VkDevice                                    device,\n    VkSwapchainKHR                              swapchain,\n    uint64_t                                    timeout,\n    VkSemaphore                                 semaphore,\n    VkFence                                     fence,\n    uint32_t*                                   pImageIndex);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkQueuePresentKHR(\n    VkQueue                                     queue,\n    const VkPresentInfoKHR*                     pPresentInfo);\n#endif\n\n#define VK_KHR_display 1\nVK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDisplayKHR)\nVK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDisplayModeKHR)\n\n#define VK_KHR_DISPLAY_SPEC_VERSION       21\n#define VK_KHR_DISPLAY_EXTENSION_NAME     \"VK_KHR_display\"\n\n\ntypedef enum VkDisplayPlaneAlphaFlagBitsKHR {\n    VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR = 0x00000001,\n    VK_DISPLAY_PLANE_ALPHA_GLOBAL_BIT_KHR = 0x00000002,\n    VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR = 0x00000004,\n    VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR = 0x00000008,\n    VK_DISPLAY_PLANE_ALPHA_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF\n} VkDisplayPlaneAlphaFlagBitsKHR;\ntypedef VkFlags VkDisplayPlaneAlphaFlagsKHR;\ntypedef VkFlags VkDisplayModeCreateFlagsKHR;\ntypedef VkFlags VkDisplaySurfaceCreateFlagsKHR;\n\ntypedef struct VkDisplayPropertiesKHR {\n    VkDisplayKHR                  display;\n    const char*                   displayName;\n    VkExtent2D                    physicalDimensions;\n    VkExtent2D                    physicalResolution;\n    VkSurfaceTransformFlagsKHR    supportedTransforms;\n    VkBool32                      planeReorderPossible;\n    VkBool32                      persistentContent;\n} VkDisplayPropertiesKHR;\n\ntypedef struct VkDisplayModeParametersKHR {\n    VkExtent2D    visibleRegion;\n    uint32_t      refreshRate;\n} VkDisplayModeParametersKHR;\n\ntypedef struct VkDisplayModePropertiesKHR {\n    VkDisplayModeKHR              displayMode;\n    VkDisplayModeParametersKHR    parameters;\n} VkDisplayModePropertiesKHR;\n\ntypedef struct VkDisplayModeCreateInfoKHR {\n    VkStructureType                sType;\n    const void*                    pNext;\n    VkDisplayModeCreateFlagsKHR    flags;\n    VkDisplayModeParametersKHR     parameters;\n} VkDisplayModeCreateInfoKHR;\n\ntypedef struct VkDisplayPlaneCapabilitiesKHR {\n    VkDisplayPlaneAlphaFlagsKHR    supportedAlpha;\n    VkOffset2D                     minSrcPosition;\n    VkOffset2D                     maxSrcPosition;\n    VkExtent2D                     minSrcExtent;\n    VkExtent2D                     maxSrcExtent;\n    VkOffset2D                     minDstPosition;\n    VkOffset2D                     maxDstPosition;\n    VkExtent2D                     minDstExtent;\n    VkExtent2D                     maxDstExtent;\n} VkDisplayPlaneCapabilitiesKHR;\n\ntypedef struct VkDisplayPlanePropertiesKHR {\n    VkDisplayKHR    currentDisplay;\n    uint32_t        currentStackIndex;\n} VkDisplayPlanePropertiesKHR;\n\ntypedef struct VkDisplaySurfaceCreateInfoKHR {\n    VkStructureType                   sType;\n    const void*                       pNext;\n    VkDisplaySurfaceCreateFlagsKHR    flags;\n    VkDisplayModeKHR                  displayMode;\n    uint32_t                          planeIndex;\n    uint32_t                          planeStackIndex;\n    VkSurfaceTransformFlagBitsKHR     transform;\n    float                             globalAlpha;\n    VkDisplayPlaneAlphaFlagBitsKHR    alphaMode;\n    VkExtent2D                        imageExtent;\n} VkDisplaySurfaceCreateInfoKHR;\n\n\ntypedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceDisplayPropertiesKHR)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkDisplayPropertiesKHR* pProperties);\ntypedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkDisplayPlanePropertiesKHR* pProperties);\ntypedef VkResult (VKAPI_PTR *PFN_vkGetDisplayPlaneSupportedDisplaysKHR)(VkPhysicalDevice physicalDevice, uint32_t planeIndex, uint32_t* pDisplayCount, VkDisplayKHR* pDisplays);\ntypedef VkResult (VKAPI_PTR *PFN_vkGetDisplayModePropertiesKHR)(VkPhysicalDevice physicalDevice, VkDisplayKHR display, uint32_t* pPropertyCount, VkDisplayModePropertiesKHR* pProperties);\ntypedef VkResult (VKAPI_PTR *PFN_vkCreateDisplayModeKHR)(VkPhysicalDevice physicalDevice, VkDisplayKHR display, const VkDisplayModeCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDisplayModeKHR* pMode);\ntypedef VkResult (VKAPI_PTR *PFN_vkGetDisplayPlaneCapabilitiesKHR)(VkPhysicalDevice physicalDevice, VkDisplayModeKHR mode, uint32_t planeIndex, VkDisplayPlaneCapabilitiesKHR* pCapabilities);\ntypedef VkResult (VKAPI_PTR *PFN_vkCreateDisplayPlaneSurfaceKHR)(VkInstance instance, const VkDisplaySurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);\n\n#ifndef VK_NO_PROTOTYPES\nVKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceDisplayPropertiesKHR(\n    VkPhysicalDevice                            physicalDevice,\n    uint32_t*                                   pPropertyCount,\n    VkDisplayPropertiesKHR*                     pProperties);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceDisplayPlanePropertiesKHR(\n    VkPhysicalDevice                            physicalDevice,\n    uint32_t*                                   pPropertyCount,\n    VkDisplayPlanePropertiesKHR*                pProperties);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayPlaneSupportedDisplaysKHR(\n    VkPhysicalDevice                            physicalDevice,\n    uint32_t                                    planeIndex,\n    uint32_t*                                   pDisplayCount,\n    VkDisplayKHR*                               pDisplays);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayModePropertiesKHR(\n    VkPhysicalDevice                            physicalDevice,\n    VkDisplayKHR                                display,\n    uint32_t*                                   pPropertyCount,\n    VkDisplayModePropertiesKHR*                 pProperties);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkCreateDisplayModeKHR(\n    VkPhysicalDevice                            physicalDevice,\n    VkDisplayKHR                                display,\n    const VkDisplayModeCreateInfoKHR*           pCreateInfo,\n    const VkAllocationCallbacks*                pAllocator,\n    VkDisplayModeKHR*                           pMode);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayPlaneCapabilitiesKHR(\n    VkPhysicalDevice                            physicalDevice,\n    VkDisplayModeKHR                            mode,\n    uint32_t                                    planeIndex,\n    VkDisplayPlaneCapabilitiesKHR*              pCapabilities);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkCreateDisplayPlaneSurfaceKHR(\n    VkInstance                                  instance,\n    const VkDisplaySurfaceCreateInfoKHR*        pCreateInfo,\n    const VkAllocationCallbacks*                pAllocator,\n    VkSurfaceKHR*                               pSurface);\n#endif\n\n#define VK_KHR_display_swapchain 1\n#define VK_KHR_DISPLAY_SWAPCHAIN_SPEC_VERSION 9\n#define VK_KHR_DISPLAY_SWAPCHAIN_EXTENSION_NAME \"VK_KHR_display_swapchain\"\n\ntypedef struct VkDisplayPresentInfoKHR {\n    VkStructureType    sType;\n    const void*        pNext;\n    VkRect2D           srcRect;\n    VkRect2D           dstRect;\n    VkBool32           persistent;\n} VkDisplayPresentInfoKHR;\n\n\ntypedef VkResult (VKAPI_PTR *PFN_vkCreateSharedSwapchainsKHR)(VkDevice device, uint32_t swapchainCount, const VkSwapchainCreateInfoKHR* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchains);\n\n#ifndef VK_NO_PROTOTYPES\nVKAPI_ATTR VkResult VKAPI_CALL vkCreateSharedSwapchainsKHR(\n    VkDevice                                    device,\n    uint32_t                                    swapchainCount,\n    const VkSwapchainCreateInfoKHR*             pCreateInfos,\n    const VkAllocationCallbacks*                pAllocator,\n    VkSwapchainKHR*                             pSwapchains);\n#endif\n\n#ifdef VK_USE_PLATFORM_XLIB_KHR\n#define VK_KHR_xlib_surface 1\n#include <X11/Xlib.h>\n\n#define VK_KHR_XLIB_SURFACE_SPEC_VERSION  6\n#define VK_KHR_XLIB_SURFACE_EXTENSION_NAME \"VK_KHR_xlib_surface\"\n\ntypedef VkFlags VkXlibSurfaceCreateFlagsKHR;\n\ntypedef struct VkXlibSurfaceCreateInfoKHR {\n    VkStructureType                sType;\n    const void*                    pNext;\n    VkXlibSurfaceCreateFlagsKHR    flags;\n    Display*                       dpy;\n    Window                         window;\n} VkXlibSurfaceCreateInfoKHR;\n\n\ntypedef VkResult (VKAPI_PTR *PFN_vkCreateXlibSurfaceKHR)(VkInstance instance, const VkXlibSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);\ntypedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, Display* dpy, VisualID visualID);\n\n#ifndef VK_NO_PROTOTYPES\nVKAPI_ATTR VkResult VKAPI_CALL vkCreateXlibSurfaceKHR(\n    VkInstance                                  instance,\n    const VkXlibSurfaceCreateInfoKHR*           pCreateInfo,\n    const VkAllocationCallbacks*                pAllocator,\n    VkSurfaceKHR*                               pSurface);\n\nVKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceXlibPresentationSupportKHR(\n    VkPhysicalDevice                            physicalDevice,\n    uint32_t                                    queueFamilyIndex,\n    Display*                                    dpy,\n    VisualID                                    visualID);\n#endif\n#endif /* VK_USE_PLATFORM_XLIB_KHR */\n\n#ifdef VK_USE_PLATFORM_XCB_KHR\n#define VK_KHR_xcb_surface 1\n#include <xcb/xcb.h>\n\n#define VK_KHR_XCB_SURFACE_SPEC_VERSION   6\n#define VK_KHR_XCB_SURFACE_EXTENSION_NAME \"VK_KHR_xcb_surface\"\n\ntypedef VkFlags VkXcbSurfaceCreateFlagsKHR;\n\ntypedef struct VkXcbSurfaceCreateInfoKHR {\n    VkStructureType               sType;\n    const void*                   pNext;\n    VkXcbSurfaceCreateFlagsKHR    flags;\n    xcb_connection_t*             connection;\n    xcb_window_t                  window;\n} VkXcbSurfaceCreateInfoKHR;\n\n\ntypedef VkResult (VKAPI_PTR *PFN_vkCreateXcbSurfaceKHR)(VkInstance instance, const VkXcbSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);\ntypedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, xcb_connection_t* connection, xcb_visualid_t visual_id);\n\n#ifndef VK_NO_PROTOTYPES\nVKAPI_ATTR VkResult VKAPI_CALL vkCreateXcbSurfaceKHR(\n    VkInstance                                  instance,\n    const VkXcbSurfaceCreateInfoKHR*            pCreateInfo,\n    const VkAllocationCallbacks*                pAllocator,\n    VkSurfaceKHR*                               pSurface);\n\nVKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceXcbPresentationSupportKHR(\n    VkPhysicalDevice                            physicalDevice,\n    uint32_t                                    queueFamilyIndex,\n    xcb_connection_t*                           connection,\n    xcb_visualid_t                              visual_id);\n#endif\n#endif /* VK_USE_PLATFORM_XCB_KHR */\n\n#ifdef VK_USE_PLATFORM_WAYLAND_KHR\n#define VK_KHR_wayland_surface 1\n#include <wayland-client.h>\n\n#define VK_KHR_WAYLAND_SURFACE_SPEC_VERSION 6\n#define VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME \"VK_KHR_wayland_surface\"\n\ntypedef VkFlags VkWaylandSurfaceCreateFlagsKHR;\n\ntypedef struct VkWaylandSurfaceCreateInfoKHR {\n    VkStructureType                   sType;\n    const void*                       pNext;\n    VkWaylandSurfaceCreateFlagsKHR    flags;\n    struct wl_display*                display;\n    struct wl_surface*                surface;\n} VkWaylandSurfaceCreateInfoKHR;\n\n\ntypedef VkResult (VKAPI_PTR *PFN_vkCreateWaylandSurfaceKHR)(VkInstance instance, const VkWaylandSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);\ntypedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, struct wl_display* display);\n\n#ifndef VK_NO_PROTOTYPES\nVKAPI_ATTR VkResult VKAPI_CALL vkCreateWaylandSurfaceKHR(\n    VkInstance                                  instance,\n    const VkWaylandSurfaceCreateInfoKHR*        pCreateInfo,\n    const VkAllocationCallbacks*                pAllocator,\n    VkSurfaceKHR*                               pSurface);\n\nVKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceWaylandPresentationSupportKHR(\n    VkPhysicalDevice                            physicalDevice,\n    uint32_t                                    queueFamilyIndex,\n    struct wl_display*                          display);\n#endif\n#endif /* VK_USE_PLATFORM_WAYLAND_KHR */\n\n#ifdef VK_USE_PLATFORM_MIR_KHR\n#define VK_KHR_mir_surface 1\n#include <mir_toolkit/client_types.h>\n\n#define VK_KHR_MIR_SURFACE_SPEC_VERSION   4\n#define VK_KHR_MIR_SURFACE_EXTENSION_NAME \"VK_KHR_mir_surface\"\n\ntypedef VkFlags VkMirSurfaceCreateFlagsKHR;\n\ntypedef struct VkMirSurfaceCreateInfoKHR {\n    VkStructureType               sType;\n    const void*                   pNext;\n    VkMirSurfaceCreateFlagsKHR    flags;\n    MirConnection*                connection;\n    MirSurface*                   mirSurface;\n} VkMirSurfaceCreateInfoKHR;\n\n\ntypedef VkResult (VKAPI_PTR *PFN_vkCreateMirSurfaceKHR)(VkInstance instance, const VkMirSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);\ntypedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceMirPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, MirConnection* connection);\n\n#ifndef VK_NO_PROTOTYPES\nVKAPI_ATTR VkResult VKAPI_CALL vkCreateMirSurfaceKHR(\n    VkInstance                                  instance,\n    const VkMirSurfaceCreateInfoKHR*            pCreateInfo,\n    const VkAllocationCallbacks*                pAllocator,\n    VkSurfaceKHR*                               pSurface);\n\nVKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceMirPresentationSupportKHR(\n    VkPhysicalDevice                            physicalDevice,\n    uint32_t                                    queueFamilyIndex,\n    MirConnection*                              connection);\n#endif\n#endif /* VK_USE_PLATFORM_MIR_KHR */\n\n#ifdef VK_USE_PLATFORM_ANDROID_KHR\n#define VK_KHR_android_surface 1\n#include <android/native_window.h>\n\n#define VK_KHR_ANDROID_SURFACE_SPEC_VERSION 6\n#define VK_KHR_ANDROID_SURFACE_EXTENSION_NAME \"VK_KHR_android_surface\"\n\ntypedef VkFlags VkAndroidSurfaceCreateFlagsKHR;\n\ntypedef struct VkAndroidSurfaceCreateInfoKHR {\n    VkStructureType                   sType;\n    const void*                       pNext;\n    VkAndroidSurfaceCreateFlagsKHR    flags;\n    ANativeWindow*                    window;\n} VkAndroidSurfaceCreateInfoKHR;\n\n\ntypedef VkResult (VKAPI_PTR *PFN_vkCreateAndroidSurfaceKHR)(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);\n\n#ifndef VK_NO_PROTOTYPES\nVKAPI_ATTR VkResult VKAPI_CALL vkCreateAndroidSurfaceKHR(\n    VkInstance                                  instance,\n    const VkAndroidSurfaceCreateInfoKHR*        pCreateInfo,\n    const VkAllocationCallbacks*                pAllocator,\n    VkSurfaceKHR*                               pSurface);\n#endif\n#endif /* VK_USE_PLATFORM_ANDROID_KHR */\n\n#ifdef VK_USE_PLATFORM_WIN32_KHR\n#define VK_KHR_win32_surface 1\n#include <windows.h>\n\n#define VK_KHR_WIN32_SURFACE_SPEC_VERSION 5\n#define VK_KHR_WIN32_SURFACE_EXTENSION_NAME \"VK_KHR_win32_surface\"\n\ntypedef VkFlags VkWin32SurfaceCreateFlagsKHR;\n\ntypedef struct VkWin32SurfaceCreateInfoKHR {\n    VkStructureType                 sType;\n    const void*                     pNext;\n    VkWin32SurfaceCreateFlagsKHR    flags;\n    HINSTANCE                       hinstance;\n    HWND                            hwnd;\n} VkWin32SurfaceCreateInfoKHR;\n\n\ntypedef VkResult (VKAPI_PTR *PFN_vkCreateWin32SurfaceKHR)(VkInstance instance, const VkWin32SurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);\ntypedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex);\n\n#ifndef VK_NO_PROTOTYPES\nVKAPI_ATTR VkResult VKAPI_CALL vkCreateWin32SurfaceKHR(\n    VkInstance                                  instance,\n    const VkWin32SurfaceCreateInfoKHR*          pCreateInfo,\n    const VkAllocationCallbacks*                pAllocator,\n    VkSurfaceKHR*                               pSurface);\n\nVKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceWin32PresentationSupportKHR(\n    VkPhysicalDevice                            physicalDevice,\n    uint32_t                                    queueFamilyIndex);\n#endif\n#endif /* VK_USE_PLATFORM_WIN32_KHR */\n\n#define VK_KHR_sampler_mirror_clamp_to_edge 1\n#define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_SPEC_VERSION 1\n#define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME \"VK_KHR_sampler_mirror_clamp_to_edge\"\n\n\n#define VK_KHR_get_physical_device_properties2 1\n#define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_SPEC_VERSION 1\n#define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME \"VK_KHR_get_physical_device_properties2\"\n\ntypedef struct VkPhysicalDeviceFeatures2KHR {\n    VkStructureType             sType;\n    void*                       pNext;\n    VkPhysicalDeviceFeatures    features;\n} VkPhysicalDeviceFeatures2KHR;\n\ntypedef struct VkPhysicalDeviceProperties2KHR {\n    VkStructureType               sType;\n    void*                         pNext;\n    VkPhysicalDeviceProperties    properties;\n} VkPhysicalDeviceProperties2KHR;\n\ntypedef struct VkFormatProperties2KHR {\n    VkStructureType       sType;\n    void*                 pNext;\n    VkFormatProperties    formatProperties;\n} VkFormatProperties2KHR;\n\ntypedef struct VkImageFormatProperties2KHR {\n    VkStructureType            sType;\n    void*                      pNext;\n    VkImageFormatProperties    imageFormatProperties;\n} VkImageFormatProperties2KHR;\n\ntypedef struct VkPhysicalDeviceImageFormatInfo2KHR {\n    VkStructureType       sType;\n    const void*           pNext;\n    VkFormat              format;\n    VkImageType           type;\n    VkImageTiling         tiling;\n    VkImageUsageFlags     usage;\n    VkImageCreateFlags    flags;\n} VkPhysicalDeviceImageFormatInfo2KHR;\n\ntypedef struct VkQueueFamilyProperties2KHR {\n    VkStructureType            sType;\n    void*                      pNext;\n    VkQueueFamilyProperties    queueFamilyProperties;\n} VkQueueFamilyProperties2KHR;\n\ntypedef struct VkPhysicalDeviceMemoryProperties2KHR {\n    VkStructureType                     sType;\n    void*                               pNext;\n    VkPhysicalDeviceMemoryProperties    memoryProperties;\n} VkPhysicalDeviceMemoryProperties2KHR;\n\ntypedef struct VkSparseImageFormatProperties2KHR {\n    VkStructureType                  sType;\n    void*                            pNext;\n    VkSparseImageFormatProperties    properties;\n} VkSparseImageFormatProperties2KHR;\n\ntypedef struct VkPhysicalDeviceSparseImageFormatInfo2KHR {\n    VkStructureType          sType;\n    const void*              pNext;\n    VkFormat                 format;\n    VkImageType              type;\n    VkSampleCountFlagBits    samples;\n    VkImageUsageFlags        usage;\n    VkImageTiling            tiling;\n} VkPhysicalDeviceSparseImageFormatInfo2KHR;\n\n\ntypedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFeatures2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2KHR* pFeatures);\ntypedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceProperties2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2KHR* pProperties);\ntypedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFormatProperties2KHR)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2KHR* pFormatProperties);\ntypedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2KHR* pImageFormatInfo, VkImageFormatProperties2KHR* pImageFormatProperties);\ntypedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR)(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2KHR* pQueueFamilyProperties);\ntypedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMemoryProperties2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2KHR* pMemoryProperties);\ntypedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2KHR* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2KHR* pProperties);\n\n#ifndef VK_NO_PROTOTYPES\nVKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFeatures2KHR(\n    VkPhysicalDevice                            physicalDevice,\n    VkPhysicalDeviceFeatures2KHR*               pFeatures);\n\nVKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceProperties2KHR(\n    VkPhysicalDevice                            physicalDevice,\n    VkPhysicalDeviceProperties2KHR*             pProperties);\n\nVKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFormatProperties2KHR(\n    VkPhysicalDevice                            physicalDevice,\n    VkFormat                                    format,\n    VkFormatProperties2KHR*                     pFormatProperties);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceImageFormatProperties2KHR(\n    VkPhysicalDevice                            physicalDevice,\n    const VkPhysicalDeviceImageFormatInfo2KHR*  pImageFormatInfo,\n    VkImageFormatProperties2KHR*                pImageFormatProperties);\n\nVKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyProperties2KHR(\n    VkPhysicalDevice                            physicalDevice,\n    uint32_t*                                   pQueueFamilyPropertyCount,\n    VkQueueFamilyProperties2KHR*                pQueueFamilyProperties);\n\nVKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties2KHR(\n    VkPhysicalDevice                            physicalDevice,\n    VkPhysicalDeviceMemoryProperties2KHR*       pMemoryProperties);\n\nVKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceSparseImageFormatProperties2KHR(\n    VkPhysicalDevice                            physicalDevice,\n    const VkPhysicalDeviceSparseImageFormatInfo2KHR* pFormatInfo,\n    uint32_t*                                   pPropertyCount,\n    VkSparseImageFormatProperties2KHR*          pProperties);\n#endif\n\n#define VK_KHR_shader_draw_parameters 1\n#define VK_KHR_SHADER_DRAW_PARAMETERS_SPEC_VERSION 1\n#define VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME \"VK_KHR_shader_draw_parameters\"\n\n\n#define VK_KHR_maintenance1 1\n#define VK_KHR_MAINTENANCE1_SPEC_VERSION  1\n#define VK_KHR_MAINTENANCE1_EXTENSION_NAME \"VK_KHR_maintenance1\"\n\ntypedef VkFlags VkCommandPoolTrimFlagsKHR;\n\ntypedef void (VKAPI_PTR *PFN_vkTrimCommandPoolKHR)(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlagsKHR flags);\n\n#ifndef VK_NO_PROTOTYPES\nVKAPI_ATTR void VKAPI_CALL vkTrimCommandPoolKHR(\n    VkDevice                                    device,\n    VkCommandPool                               commandPool,\n    VkCommandPoolTrimFlagsKHR                   flags);\n#endif\n\n#define VK_KHR_push_descriptor 1\n#define VK_KHR_PUSH_DESCRIPTOR_SPEC_VERSION 1\n#define VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME \"VK_KHR_push_descriptor\"\n\ntypedef struct VkPhysicalDevicePushDescriptorPropertiesKHR {\n    VkStructureType    sType;\n    void*              pNext;\n    uint32_t           maxPushDescriptors;\n} VkPhysicalDevicePushDescriptorPropertiesKHR;\n\n\ntypedef void (VKAPI_PTR *PFN_vkCmdPushDescriptorSetKHR)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t set, uint32_t descriptorWriteCount, const VkWriteDescriptorSet* pDescriptorWrites);\n\n#ifndef VK_NO_PROTOTYPES\nVKAPI_ATTR void VKAPI_CALL vkCmdPushDescriptorSetKHR(\n    VkCommandBuffer                             commandBuffer,\n    VkPipelineBindPoint                         pipelineBindPoint,\n    VkPipelineLayout                            layout,\n    uint32_t                                    set,\n    uint32_t                                    descriptorWriteCount,\n    const VkWriteDescriptorSet*                 pDescriptorWrites);\n#endif\n\n#define VK_KHR_incremental_present 1\n#define VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION 1\n#define VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME \"VK_KHR_incremental_present\"\n\ntypedef struct VkRectLayerKHR {\n    VkOffset2D    offset;\n    VkExtent2D    extent;\n    uint32_t      layer;\n} VkRectLayerKHR;\n\ntypedef struct VkPresentRegionKHR {\n    uint32_t                 rectangleCount;\n    const VkRectLayerKHR*    pRectangles;\n} VkPresentRegionKHR;\n\ntypedef struct VkPresentRegionsKHR {\n    VkStructureType              sType;\n    const void*                  pNext;\n    uint32_t                     swapchainCount;\n    const VkPresentRegionKHR*    pRegions;\n} VkPresentRegionsKHR;\n\n\n\n#define VK_KHR_descriptor_update_template 1\nVK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorUpdateTemplateKHR)\n\n#define VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_SPEC_VERSION 1\n#define VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME \"VK_KHR_descriptor_update_template\"\n\n\ntypedef enum VkDescriptorUpdateTemplateTypeKHR {\n    VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR = 0,\n    VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR = 1,\n    VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_BEGIN_RANGE_KHR = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR,\n    VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_END_RANGE_KHR = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR,\n    VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_RANGE_SIZE_KHR = (VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR + 1),\n    VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF\n} VkDescriptorUpdateTemplateTypeKHR;\n\ntypedef VkFlags VkDescriptorUpdateTemplateCreateFlagsKHR;\n\ntypedef struct VkDescriptorUpdateTemplateEntryKHR {\n    uint32_t            dstBinding;\n    uint32_t            dstArrayElement;\n    uint32_t            descriptorCount;\n    VkDescriptorType    descriptorType;\n    size_t              offset;\n    size_t              stride;\n} VkDescriptorUpdateTemplateEntryKHR;\n\ntypedef struct VkDescriptorUpdateTemplateCreateInfoKHR {\n    VkStructureType                              sType;\n    void*                                        pNext;\n    VkDescriptorUpdateTemplateCreateFlagsKHR     flags;\n    uint32_t                                     descriptorUpdateEntryCount;\n    const VkDescriptorUpdateTemplateEntryKHR*    pDescriptorUpdateEntries;\n    VkDescriptorUpdateTemplateTypeKHR            templateType;\n    VkDescriptorSetLayout                        descriptorSetLayout;\n    VkPipelineBindPoint                          pipelineBindPoint;\n    VkPipelineLayout                             pipelineLayout;\n    uint32_t                                     set;\n} VkDescriptorUpdateTemplateCreateInfoKHR;\n\n\ntypedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorUpdateTemplateKHR)(VkDevice device, const VkDescriptorUpdateTemplateCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplateKHR* pDescriptorUpdateTemplate);\ntypedef void (VKAPI_PTR *PFN_vkDestroyDescriptorUpdateTemplateKHR)(VkDevice device, VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator);\ntypedef void (VKAPI_PTR *PFN_vkUpdateDescriptorSetWithTemplateKHR)(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, const void* pData);\ntypedef void (VKAPI_PTR *PFN_vkCmdPushDescriptorSetWithTemplateKHR)(VkCommandBuffer commandBuffer, VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, VkPipelineLayout layout, uint32_t set, const void* pData);\n\n#ifndef VK_NO_PROTOTYPES\nVKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorUpdateTemplateKHR(\n    VkDevice                                    device,\n    const VkDescriptorUpdateTemplateCreateInfoKHR* pCreateInfo,\n    const VkAllocationCallbacks*                pAllocator,\n    VkDescriptorUpdateTemplateKHR*              pDescriptorUpdateTemplate);\n\nVKAPI_ATTR void VKAPI_CALL vkDestroyDescriptorUpdateTemplateKHR(\n    VkDevice                                    device,\n    VkDescriptorUpdateTemplateKHR               descriptorUpdateTemplate,\n    const VkAllocationCallbacks*                pAllocator);\n\nVKAPI_ATTR void VKAPI_CALL vkUpdateDescriptorSetWithTemplateKHR(\n    VkDevice                                    device,\n    VkDescriptorSet                             descriptorSet,\n    VkDescriptorUpdateTemplateKHR               descriptorUpdateTemplate,\n    const void*                                 pData);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdPushDescriptorSetWithTemplateKHR(\n    VkCommandBuffer                             commandBuffer,\n    VkDescriptorUpdateTemplateKHR               descriptorUpdateTemplate,\n    VkPipelineLayout                            layout,\n    uint32_t                                    set,\n    const void*                                 pData);\n#endif\n\n#define VK_KHR_shared_presentable_image 1\n#define VK_KHR_SHARED_PRESENTABLE_IMAGE_SPEC_VERSION 1\n#define VK_KHR_SHARED_PRESENTABLE_IMAGE_EXTENSION_NAME \"VK_KHR_shared_presentable_image\"\n\ntypedef struct VkSharedPresentSurfaceCapabilitiesKHR {\n    VkStructureType      sType;\n    void*                pNext;\n    VkImageUsageFlags    sharedPresentSupportedUsageFlags;\n} VkSharedPresentSurfaceCapabilitiesKHR;\n\n\ntypedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainStatusKHR)(VkDevice device, VkSwapchainKHR swapchain);\n\n#ifndef VK_NO_PROTOTYPES\nVKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainStatusKHR(\n    VkDevice                                    device,\n    VkSwapchainKHR                              swapchain);\n#endif\n\n#define VK_KHR_get_surface_capabilities2 1\n#define VK_KHR_GET_SURFACE_CAPABILITIES_2_SPEC_VERSION 1\n#define VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME \"VK_KHR_get_surface_capabilities2\"\n\ntypedef struct VkPhysicalDeviceSurfaceInfo2KHR {\n    VkStructureType    sType;\n    const void*        pNext;\n    VkSurfaceKHR       surface;\n} VkPhysicalDeviceSurfaceInfo2KHR;\n\ntypedef struct VkSurfaceCapabilities2KHR {\n    VkStructureType             sType;\n    void*                       pNext;\n    VkSurfaceCapabilitiesKHR    surfaceCapabilities;\n} VkSurfaceCapabilities2KHR;\n\ntypedef struct VkSurfaceFormat2KHR {\n    VkStructureType       sType;\n    void*                 pNext;\n    VkSurfaceFormatKHR    surfaceFormat;\n} VkSurfaceFormat2KHR;\n\n\ntypedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, VkSurfaceCapabilities2KHR* pSurfaceCapabilities);\ntypedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceFormats2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, uint32_t* pSurfaceFormatCount, VkSurfaceFormat2KHR* pSurfaceFormats);\n\n#ifndef VK_NO_PROTOTYPES\nVKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilities2KHR(\n    VkPhysicalDevice                            physicalDevice,\n    const VkPhysicalDeviceSurfaceInfo2KHR*      pSurfaceInfo,\n    VkSurfaceCapabilities2KHR*                  pSurfaceCapabilities);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceFormats2KHR(\n    VkPhysicalDevice                            physicalDevice,\n    const VkPhysicalDeviceSurfaceInfo2KHR*      pSurfaceInfo,\n    uint32_t*                                   pSurfaceFormatCount,\n    VkSurfaceFormat2KHR*                        pSurfaceFormats);\n#endif\n\n#define VK_EXT_debug_report 1\nVK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugReportCallbackEXT)\n\n#define VK_EXT_DEBUG_REPORT_SPEC_VERSION  6\n#define VK_EXT_DEBUG_REPORT_EXTENSION_NAME \"VK_EXT_debug_report\"\n#define VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT\n\n\ntypedef enum VkDebugReportObjectTypeEXT {\n    VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT = 0,\n    VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT = 1,\n    VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT = 2,\n    VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT = 3,\n    VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT = 4,\n    VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT = 5,\n    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT = 6,\n    VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT = 7,\n    VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT = 8,\n    VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT = 9,\n    VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT = 10,\n    VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT = 11,\n    VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT = 12,\n    VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT = 13,\n    VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT = 14,\n    VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT = 15,\n    VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_CACHE_EXT = 16,\n    VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT = 17,\n    VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT = 18,\n    VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT = 19,\n    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT = 20,\n    VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT = 21,\n    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT = 22,\n    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT = 23,\n    VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT = 24,\n    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT = 25,\n    VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT = 26,\n    VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT = 27,\n    VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT = 28,\n    VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_KHR_EXT = 29,\n    VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_MODE_KHR_EXT = 30,\n    VK_DEBUG_REPORT_OBJECT_TYPE_OBJECT_TABLE_NVX_EXT = 31,\n    VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT = 32,\n    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR_EXT = 1000085000,\n    VK_DEBUG_REPORT_OBJECT_TYPE_BEGIN_RANGE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,\n    VK_DEBUG_REPORT_OBJECT_TYPE_END_RANGE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT,\n    VK_DEBUG_REPORT_OBJECT_TYPE_RANGE_SIZE_EXT = (VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT - VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT + 1),\n    VK_DEBUG_REPORT_OBJECT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF\n} VkDebugReportObjectTypeEXT;\n\ntypedef enum VkDebugReportErrorEXT {\n    VK_DEBUG_REPORT_ERROR_NONE_EXT = 0,\n    VK_DEBUG_REPORT_ERROR_CALLBACK_REF_EXT = 1,\n    VK_DEBUG_REPORT_ERROR_BEGIN_RANGE_EXT = VK_DEBUG_REPORT_ERROR_NONE_EXT,\n    VK_DEBUG_REPORT_ERROR_END_RANGE_EXT = VK_DEBUG_REPORT_ERROR_CALLBACK_REF_EXT,\n    VK_DEBUG_REPORT_ERROR_RANGE_SIZE_EXT = (VK_DEBUG_REPORT_ERROR_CALLBACK_REF_EXT - VK_DEBUG_REPORT_ERROR_NONE_EXT + 1),\n    VK_DEBUG_REPORT_ERROR_MAX_ENUM_EXT = 0x7FFFFFFF\n} VkDebugReportErrorEXT;\n\n\ntypedef enum VkDebugReportFlagBitsEXT {\n    VK_DEBUG_REPORT_INFORMATION_BIT_EXT = 0x00000001,\n    VK_DEBUG_REPORT_WARNING_BIT_EXT = 0x00000002,\n    VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT = 0x00000004,\n    VK_DEBUG_REPORT_ERROR_BIT_EXT = 0x00000008,\n    VK_DEBUG_REPORT_DEBUG_BIT_EXT = 0x00000010,\n    VK_DEBUG_REPORT_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF\n} VkDebugReportFlagBitsEXT;\ntypedef VkFlags VkDebugReportFlagsEXT;\n\ntypedef VkBool32 (VKAPI_PTR *PFN_vkDebugReportCallbackEXT)(\n    VkDebugReportFlagsEXT                       flags,\n    VkDebugReportObjectTypeEXT                  objectType,\n    uint64_t                                    object,\n    size_t                                      location,\n    int32_t                                     messageCode,\n    const char*                                 pLayerPrefix,\n    const char*                                 pMessage,\n    void*                                       pUserData);\n\n\ntypedef struct VkDebugReportCallbackCreateInfoEXT {\n    VkStructureType                 sType;\n    const void*                     pNext;\n    VkDebugReportFlagsEXT           flags;\n    PFN_vkDebugReportCallbackEXT    pfnCallback;\n    void*                           pUserData;\n} VkDebugReportCallbackCreateInfoEXT;\n\n\ntypedef VkResult (VKAPI_PTR *PFN_vkCreateDebugReportCallbackEXT)(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugReportCallbackEXT* pCallback);\ntypedef void (VKAPI_PTR *PFN_vkDestroyDebugReportCallbackEXT)(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks* pAllocator);\ntypedef void (VKAPI_PTR *PFN_vkDebugReportMessageEXT)(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage);\n\n#ifndef VK_NO_PROTOTYPES\nVKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugReportCallbackEXT(\n    VkInstance                                  instance,\n    const VkDebugReportCallbackCreateInfoEXT*   pCreateInfo,\n    const VkAllocationCallbacks*                pAllocator,\n    VkDebugReportCallbackEXT*                   pCallback);\n\nVKAPI_ATTR void VKAPI_CALL vkDestroyDebugReportCallbackEXT(\n    VkInstance                                  instance,\n    VkDebugReportCallbackEXT                    callback,\n    const VkAllocationCallbacks*                pAllocator);\n\nVKAPI_ATTR void VKAPI_CALL vkDebugReportMessageEXT(\n    VkInstance                                  instance,\n    VkDebugReportFlagsEXT                       flags,\n    VkDebugReportObjectTypeEXT                  objectType,\n    uint64_t                                    object,\n    size_t                                      location,\n    int32_t                                     messageCode,\n    const char*                                 pLayerPrefix,\n    const char*                                 pMessage);\n#endif\n\n#define VK_NV_glsl_shader 1\n#define VK_NV_GLSL_SHADER_SPEC_VERSION    1\n#define VK_NV_GLSL_SHADER_EXTENSION_NAME  \"VK_NV_glsl_shader\"\n\n\n#define VK_IMG_filter_cubic 1\n#define VK_IMG_FILTER_CUBIC_SPEC_VERSION  1\n#define VK_IMG_FILTER_CUBIC_EXTENSION_NAME \"VK_IMG_filter_cubic\"\n\n\n#define VK_AMD_rasterization_order 1\n#define VK_AMD_RASTERIZATION_ORDER_SPEC_VERSION 1\n#define VK_AMD_RASTERIZATION_ORDER_EXTENSION_NAME \"VK_AMD_rasterization_order\"\n\n\ntypedef enum VkRasterizationOrderAMD {\n    VK_RASTERIZATION_ORDER_STRICT_AMD = 0,\n    VK_RASTERIZATION_ORDER_RELAXED_AMD = 1,\n    VK_RASTERIZATION_ORDER_BEGIN_RANGE_AMD = VK_RASTERIZATION_ORDER_STRICT_AMD,\n    VK_RASTERIZATION_ORDER_END_RANGE_AMD = VK_RASTERIZATION_ORDER_RELAXED_AMD,\n    VK_RASTERIZATION_ORDER_RANGE_SIZE_AMD = (VK_RASTERIZATION_ORDER_RELAXED_AMD - VK_RASTERIZATION_ORDER_STRICT_AMD + 1),\n    VK_RASTERIZATION_ORDER_MAX_ENUM_AMD = 0x7FFFFFFF\n} VkRasterizationOrderAMD;\n\ntypedef struct VkPipelineRasterizationStateRasterizationOrderAMD {\n    VkStructureType            sType;\n    const void*                pNext;\n    VkRasterizationOrderAMD    rasterizationOrder;\n} VkPipelineRasterizationStateRasterizationOrderAMD;\n\n\n\n#define VK_AMD_shader_trinary_minmax 1\n#define VK_AMD_SHADER_TRINARY_MINMAX_SPEC_VERSION 1\n#define VK_AMD_SHADER_TRINARY_MINMAX_EXTENSION_NAME \"VK_AMD_shader_trinary_minmax\"\n\n\n#define VK_AMD_shader_explicit_vertex_parameter 1\n#define VK_AMD_SHADER_EXPLICIT_VERTEX_PARAMETER_SPEC_VERSION 1\n#define VK_AMD_SHADER_EXPLICIT_VERTEX_PARAMETER_EXTENSION_NAME \"VK_AMD_shader_explicit_vertex_parameter\"\n\n\n#define VK_EXT_debug_marker 1\n#define VK_EXT_DEBUG_MARKER_SPEC_VERSION  4\n#define VK_EXT_DEBUG_MARKER_EXTENSION_NAME \"VK_EXT_debug_marker\"\n\ntypedef struct VkDebugMarkerObjectNameInfoEXT {\n    VkStructureType               sType;\n    const void*                   pNext;\n    VkDebugReportObjectTypeEXT    objectType;\n    uint64_t                      object;\n    const char*                   pObjectName;\n} VkDebugMarkerObjectNameInfoEXT;\n\ntypedef struct VkDebugMarkerObjectTagInfoEXT {\n    VkStructureType               sType;\n    const void*                   pNext;\n    VkDebugReportObjectTypeEXT    objectType;\n    uint64_t                      object;\n    uint64_t                      tagName;\n    size_t                        tagSize;\n    const void*                   pTag;\n} VkDebugMarkerObjectTagInfoEXT;\n\ntypedef struct VkDebugMarkerMarkerInfoEXT {\n    VkStructureType    sType;\n    const void*        pNext;\n    const char*        pMarkerName;\n    float              color[4];\n} VkDebugMarkerMarkerInfoEXT;\n\n\ntypedef VkResult (VKAPI_PTR *PFN_vkDebugMarkerSetObjectTagEXT)(VkDevice device, VkDebugMarkerObjectTagInfoEXT* pTagInfo);\ntypedef VkResult (VKAPI_PTR *PFN_vkDebugMarkerSetObjectNameEXT)(VkDevice device, VkDebugMarkerObjectNameInfoEXT* pNameInfo);\ntypedef void (VKAPI_PTR *PFN_vkCmdDebugMarkerBeginEXT)(VkCommandBuffer commandBuffer, VkDebugMarkerMarkerInfoEXT* pMarkerInfo);\ntypedef void (VKAPI_PTR *PFN_vkCmdDebugMarkerEndEXT)(VkCommandBuffer commandBuffer);\ntypedef void (VKAPI_PTR *PFN_vkCmdDebugMarkerInsertEXT)(VkCommandBuffer commandBuffer, VkDebugMarkerMarkerInfoEXT* pMarkerInfo);\n\n#ifndef VK_NO_PROTOTYPES\nVKAPI_ATTR VkResult VKAPI_CALL vkDebugMarkerSetObjectTagEXT(\n    VkDevice                                    device,\n    VkDebugMarkerObjectTagInfoEXT*              pTagInfo);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkDebugMarkerSetObjectNameEXT(\n    VkDevice                                    device,\n    VkDebugMarkerObjectNameInfoEXT*             pNameInfo);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdDebugMarkerBeginEXT(\n    VkCommandBuffer                             commandBuffer,\n    VkDebugMarkerMarkerInfoEXT*                 pMarkerInfo);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdDebugMarkerEndEXT(\n    VkCommandBuffer                             commandBuffer);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdDebugMarkerInsertEXT(\n    VkCommandBuffer                             commandBuffer,\n    VkDebugMarkerMarkerInfoEXT*                 pMarkerInfo);\n#endif\n\n#define VK_AMD_gcn_shader 1\n#define VK_AMD_GCN_SHADER_SPEC_VERSION    1\n#define VK_AMD_GCN_SHADER_EXTENSION_NAME  \"VK_AMD_gcn_shader\"\n\n\n#define VK_NV_dedicated_allocation 1\n#define VK_NV_DEDICATED_ALLOCATION_SPEC_VERSION 1\n#define VK_NV_DEDICATED_ALLOCATION_EXTENSION_NAME \"VK_NV_dedicated_allocation\"\n\ntypedef struct VkDedicatedAllocationImageCreateInfoNV {\n    VkStructureType    sType;\n    const void*        pNext;\n    VkBool32           dedicatedAllocation;\n} VkDedicatedAllocationImageCreateInfoNV;\n\ntypedef struct VkDedicatedAllocationBufferCreateInfoNV {\n    VkStructureType    sType;\n    const void*        pNext;\n    VkBool32           dedicatedAllocation;\n} VkDedicatedAllocationBufferCreateInfoNV;\n\ntypedef struct VkDedicatedAllocationMemoryAllocateInfoNV {\n    VkStructureType    sType;\n    const void*        pNext;\n    VkImage            image;\n    VkBuffer           buffer;\n} VkDedicatedAllocationMemoryAllocateInfoNV;\n\n\n\n#define VK_AMD_draw_indirect_count 1\n#define VK_AMD_DRAW_INDIRECT_COUNT_SPEC_VERSION 1\n#define VK_AMD_DRAW_INDIRECT_COUNT_EXTENSION_NAME \"VK_AMD_draw_indirect_count\"\n\ntypedef void (VKAPI_PTR *PFN_vkCmdDrawIndirectCountAMD)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride);\ntypedef void (VKAPI_PTR *PFN_vkCmdDrawIndexedIndirectCountAMD)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride);\n\n#ifndef VK_NO_PROTOTYPES\nVKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirectCountAMD(\n    VkCommandBuffer                             commandBuffer,\n    VkBuffer                                    buffer,\n    VkDeviceSize                                offset,\n    VkBuffer                                    countBuffer,\n    VkDeviceSize                                countBufferOffset,\n    uint32_t                                    maxDrawCount,\n    uint32_t                                    stride);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexedIndirectCountAMD(\n    VkCommandBuffer                             commandBuffer,\n    VkBuffer                                    buffer,\n    VkDeviceSize                                offset,\n    VkBuffer                                    countBuffer,\n    VkDeviceSize                                countBufferOffset,\n    uint32_t                                    maxDrawCount,\n    uint32_t                                    stride);\n#endif\n\n#define VK_AMD_negative_viewport_height 1\n#define VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_SPEC_VERSION 1\n#define VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_EXTENSION_NAME \"VK_AMD_negative_viewport_height\"\n\n\n#define VK_AMD_gpu_shader_half_float 1\n#define VK_AMD_GPU_SHADER_HALF_FLOAT_SPEC_VERSION 1\n#define VK_AMD_GPU_SHADER_HALF_FLOAT_EXTENSION_NAME \"VK_AMD_gpu_shader_half_float\"\n\n\n#define VK_AMD_shader_ballot 1\n#define VK_AMD_SHADER_BALLOT_SPEC_VERSION 1\n#define VK_AMD_SHADER_BALLOT_EXTENSION_NAME \"VK_AMD_shader_ballot\"\n\n\n#define VK_KHX_multiview 1\n#define VK_KHX_MULTIVIEW_SPEC_VERSION     1\n#define VK_KHX_MULTIVIEW_EXTENSION_NAME   \"VK_KHX_multiview\"\n\ntypedef struct VkRenderPassMultiviewCreateInfoKHX {\n    VkStructureType    sType;\n    const void*        pNext;\n    uint32_t           subpassCount;\n    const uint32_t*    pViewMasks;\n    uint32_t           dependencyCount;\n    const int32_t*     pViewOffsets;\n    uint32_t           correlationMaskCount;\n    const uint32_t*    pCorrelationMasks;\n} VkRenderPassMultiviewCreateInfoKHX;\n\ntypedef struct VkPhysicalDeviceMultiviewFeaturesKHX {\n    VkStructureType    sType;\n    void*              pNext;\n    VkBool32           multiview;\n    VkBool32           multiviewGeometryShader;\n    VkBool32           multiviewTessellationShader;\n} VkPhysicalDeviceMultiviewFeaturesKHX;\n\ntypedef struct VkPhysicalDeviceMultiviewPropertiesKHX {\n    VkStructureType    sType;\n    void*              pNext;\n    uint32_t           maxMultiviewViewCount;\n    uint32_t           maxMultiviewInstanceIndex;\n} VkPhysicalDeviceMultiviewPropertiesKHX;\n\n\n\n#define VK_IMG_format_pvrtc 1\n#define VK_IMG_FORMAT_PVRTC_SPEC_VERSION  1\n#define VK_IMG_FORMAT_PVRTC_EXTENSION_NAME \"VK_IMG_format_pvrtc\"\n\n\n#define VK_NV_external_memory_capabilities 1\n#define VK_NV_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION 1\n#define VK_NV_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME \"VK_NV_external_memory_capabilities\"\n\n\ntypedef enum VkExternalMemoryHandleTypeFlagBitsNV {\n    VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_NV = 0x00000001,\n    VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_NV = 0x00000002,\n    VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_BIT_NV = 0x00000004,\n    VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_KMT_BIT_NV = 0x00000008,\n    VK_EXTERNAL_MEMORY_HANDLE_TYPE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF\n} VkExternalMemoryHandleTypeFlagBitsNV;\ntypedef VkFlags VkExternalMemoryHandleTypeFlagsNV;\n\ntypedef enum VkExternalMemoryFeatureFlagBitsNV {\n    VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_NV = 0x00000001,\n    VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_NV = 0x00000002,\n    VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_NV = 0x00000004,\n    VK_EXTERNAL_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF\n} VkExternalMemoryFeatureFlagBitsNV;\ntypedef VkFlags VkExternalMemoryFeatureFlagsNV;\n\ntypedef struct VkExternalImageFormatPropertiesNV {\n    VkImageFormatProperties              imageFormatProperties;\n    VkExternalMemoryFeatureFlagsNV       externalMemoryFeatures;\n    VkExternalMemoryHandleTypeFlagsNV    exportFromImportedHandleTypes;\n    VkExternalMemoryHandleTypeFlagsNV    compatibleHandleTypes;\n} VkExternalImageFormatPropertiesNV;\n\n\ntypedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalImageFormatPropertiesNV)(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkExternalMemoryHandleTypeFlagsNV externalHandleType, VkExternalImageFormatPropertiesNV* pExternalImageFormatProperties);\n\n#ifndef VK_NO_PROTOTYPES\nVKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceExternalImageFormatPropertiesNV(\n    VkPhysicalDevice                            physicalDevice,\n    VkFormat                                    format,\n    VkImageType                                 type,\n    VkImageTiling                               tiling,\n    VkImageUsageFlags                           usage,\n    VkImageCreateFlags                          flags,\n    VkExternalMemoryHandleTypeFlagsNV           externalHandleType,\n    VkExternalImageFormatPropertiesNV*          pExternalImageFormatProperties);\n#endif\n\n#define VK_NV_external_memory 1\n#define VK_NV_EXTERNAL_MEMORY_SPEC_VERSION 1\n#define VK_NV_EXTERNAL_MEMORY_EXTENSION_NAME \"VK_NV_external_memory\"\n\ntypedef struct VkExternalMemoryImageCreateInfoNV {\n    VkStructureType                      sType;\n    const void*                          pNext;\n    VkExternalMemoryHandleTypeFlagsNV    handleTypes;\n} VkExternalMemoryImageCreateInfoNV;\n\ntypedef struct VkExportMemoryAllocateInfoNV {\n    VkStructureType                      sType;\n    const void*                          pNext;\n    VkExternalMemoryHandleTypeFlagsNV    handleTypes;\n} VkExportMemoryAllocateInfoNV;\n\n\n\n#ifdef VK_USE_PLATFORM_WIN32_KHR\n#define VK_NV_external_memory_win32 1\n#define VK_NV_EXTERNAL_MEMORY_WIN32_SPEC_VERSION 1\n#define VK_NV_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME \"VK_NV_external_memory_win32\"\n\ntypedef struct VkImportMemoryWin32HandleInfoNV {\n    VkStructureType                      sType;\n    const void*                          pNext;\n    VkExternalMemoryHandleTypeFlagsNV    handleType;\n    HANDLE                               handle;\n} VkImportMemoryWin32HandleInfoNV;\n\ntypedef struct VkExportMemoryWin32HandleInfoNV {\n    VkStructureType               sType;\n    const void*                   pNext;\n    const SECURITY_ATTRIBUTES*    pAttributes;\n    DWORD                         dwAccess;\n} VkExportMemoryWin32HandleInfoNV;\n\n\ntypedef VkResult (VKAPI_PTR *PFN_vkGetMemoryWin32HandleNV)(VkDevice device, VkDeviceMemory memory, VkExternalMemoryHandleTypeFlagsNV handleType, HANDLE* pHandle);\n\n#ifndef VK_NO_PROTOTYPES\nVKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryWin32HandleNV(\n    VkDevice                                    device,\n    VkDeviceMemory                              memory,\n    VkExternalMemoryHandleTypeFlagsNV           handleType,\n    HANDLE*                                     pHandle);\n#endif\n#endif /* VK_USE_PLATFORM_WIN32_KHR */\n\n#ifdef VK_USE_PLATFORM_WIN32_KHR\n#define VK_NV_win32_keyed_mutex 1\n#define VK_NV_WIN32_KEYED_MUTEX_SPEC_VERSION 1\n#define VK_NV_WIN32_KEYED_MUTEX_EXTENSION_NAME \"VK_NV_win32_keyed_mutex\"\n\ntypedef struct VkWin32KeyedMutexAcquireReleaseInfoNV {\n    VkStructureType          sType;\n    const void*              pNext;\n    uint32_t                 acquireCount;\n    const VkDeviceMemory*    pAcquireSyncs;\n    const uint64_t*          pAcquireKeys;\n    const uint32_t*          pAcquireTimeoutMilliseconds;\n    uint32_t                 releaseCount;\n    const VkDeviceMemory*    pReleaseSyncs;\n    const uint64_t*          pReleaseKeys;\n} VkWin32KeyedMutexAcquireReleaseInfoNV;\n\n\n#endif /* VK_USE_PLATFORM_WIN32_KHR */\n\n#define VK_KHX_device_group 1\n#define VK_MAX_DEVICE_GROUP_SIZE_KHX      32\n#define VK_KHX_DEVICE_GROUP_SPEC_VERSION  1\n#define VK_KHX_DEVICE_GROUP_EXTENSION_NAME \"VK_KHX_device_group\"\n\n\ntypedef enum VkPeerMemoryFeatureFlagBitsKHX {\n    VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT_KHX = 0x00000001,\n    VK_PEER_MEMORY_FEATURE_COPY_DST_BIT_KHX = 0x00000002,\n    VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT_KHX = 0x00000004,\n    VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT_KHX = 0x00000008,\n    VK_PEER_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM_KHX = 0x7FFFFFFF\n} VkPeerMemoryFeatureFlagBitsKHX;\ntypedef VkFlags VkPeerMemoryFeatureFlagsKHX;\n\ntypedef enum VkMemoryAllocateFlagBitsKHX {\n    VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT_KHX = 0x00000001,\n    VK_MEMORY_ALLOCATE_FLAG_BITS_MAX_ENUM_KHX = 0x7FFFFFFF\n} VkMemoryAllocateFlagBitsKHX;\ntypedef VkFlags VkMemoryAllocateFlagsKHX;\n\ntypedef enum VkDeviceGroupPresentModeFlagBitsKHX {\n    VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHX = 0x00000001,\n    VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHX = 0x00000002,\n    VK_DEVICE_GROUP_PRESENT_MODE_SUM_BIT_KHX = 0x00000004,\n    VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHX = 0x00000008,\n    VK_DEVICE_GROUP_PRESENT_MODE_FLAG_BITS_MAX_ENUM_KHX = 0x7FFFFFFF\n} VkDeviceGroupPresentModeFlagBitsKHX;\ntypedef VkFlags VkDeviceGroupPresentModeFlagsKHX;\n\ntypedef struct VkMemoryAllocateFlagsInfoKHX {\n    VkStructureType             sType;\n    const void*                 pNext;\n    VkMemoryAllocateFlagsKHX    flags;\n    uint32_t                    deviceMask;\n} VkMemoryAllocateFlagsInfoKHX;\n\ntypedef struct VkBindBufferMemoryInfoKHX {\n    VkStructureType    sType;\n    const void*        pNext;\n    VkBuffer           buffer;\n    VkDeviceMemory     memory;\n    VkDeviceSize       memoryOffset;\n    uint32_t           deviceIndexCount;\n    const uint32_t*    pDeviceIndices;\n} VkBindBufferMemoryInfoKHX;\n\ntypedef struct VkBindImageMemoryInfoKHX {\n    VkStructureType    sType;\n    const void*        pNext;\n    VkImage            image;\n    VkDeviceMemory     memory;\n    VkDeviceSize       memoryOffset;\n    uint32_t           deviceIndexCount;\n    const uint32_t*    pDeviceIndices;\n    uint32_t           SFRRectCount;\n    const VkRect2D*    pSFRRects;\n} VkBindImageMemoryInfoKHX;\n\ntypedef struct VkDeviceGroupRenderPassBeginInfoKHX {\n    VkStructureType    sType;\n    const void*        pNext;\n    uint32_t           deviceMask;\n    uint32_t           deviceRenderAreaCount;\n    const VkRect2D*    pDeviceRenderAreas;\n} VkDeviceGroupRenderPassBeginInfoKHX;\n\ntypedef struct VkDeviceGroupCommandBufferBeginInfoKHX {\n    VkStructureType    sType;\n    const void*        pNext;\n    uint32_t           deviceMask;\n} VkDeviceGroupCommandBufferBeginInfoKHX;\n\ntypedef struct VkDeviceGroupSubmitInfoKHX {\n    VkStructureType    sType;\n    const void*        pNext;\n    uint32_t           waitSemaphoreCount;\n    const uint32_t*    pWaitSemaphoreDeviceIndices;\n    uint32_t           commandBufferCount;\n    const uint32_t*    pCommandBufferDeviceMasks;\n    uint32_t           signalSemaphoreCount;\n    const uint32_t*    pSignalSemaphoreDeviceIndices;\n} VkDeviceGroupSubmitInfoKHX;\n\ntypedef struct VkDeviceGroupBindSparseInfoKHX {\n    VkStructureType    sType;\n    const void*        pNext;\n    uint32_t           resourceDeviceIndex;\n    uint32_t           memoryDeviceIndex;\n} VkDeviceGroupBindSparseInfoKHX;\n\ntypedef struct VkDeviceGroupPresentCapabilitiesKHX {\n    VkStructureType                     sType;\n    const void*                         pNext;\n    uint32_t                            presentMask[VK_MAX_DEVICE_GROUP_SIZE_KHX];\n    VkDeviceGroupPresentModeFlagsKHX    modes;\n} VkDeviceGroupPresentCapabilitiesKHX;\n\ntypedef struct VkImageSwapchainCreateInfoKHX {\n    VkStructureType    sType;\n    const void*        pNext;\n    VkSwapchainKHR     swapchain;\n} VkImageSwapchainCreateInfoKHX;\n\ntypedef struct VkBindImageMemorySwapchainInfoKHX {\n    VkStructureType    sType;\n    const void*        pNext;\n    VkSwapchainKHR     swapchain;\n    uint32_t           imageIndex;\n} VkBindImageMemorySwapchainInfoKHX;\n\ntypedef struct VkAcquireNextImageInfoKHX {\n    VkStructureType    sType;\n    const void*        pNext;\n    VkSwapchainKHR     swapchain;\n    uint64_t           timeout;\n    VkSemaphore        semaphore;\n    VkFence            fence;\n    uint32_t           deviceMask;\n} VkAcquireNextImageInfoKHX;\n\ntypedef struct VkDeviceGroupPresentInfoKHX {\n    VkStructureType                        sType;\n    const void*                            pNext;\n    uint32_t                               swapchainCount;\n    const uint32_t*                        pDeviceMasks;\n    VkDeviceGroupPresentModeFlagBitsKHX    mode;\n} VkDeviceGroupPresentInfoKHX;\n\ntypedef struct VkDeviceGroupSwapchainCreateInfoKHX {\n    VkStructureType                     sType;\n    const void*                         pNext;\n    VkDeviceGroupPresentModeFlagsKHX    modes;\n} VkDeviceGroupSwapchainCreateInfoKHX;\n\n\ntypedef void (VKAPI_PTR *PFN_vkGetDeviceGroupPeerMemoryFeaturesKHX)(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlagsKHX* pPeerMemoryFeatures);\ntypedef VkResult (VKAPI_PTR *PFN_vkBindBufferMemory2KHX)(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfoKHX* pBindInfos);\ntypedef VkResult (VKAPI_PTR *PFN_vkBindImageMemory2KHX)(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfoKHX* pBindInfos);\ntypedef void (VKAPI_PTR *PFN_vkCmdSetDeviceMaskKHX)(VkCommandBuffer commandBuffer, uint32_t deviceMask);\ntypedef VkResult (VKAPI_PTR *PFN_vkGetDeviceGroupPresentCapabilitiesKHX)(VkDevice device, VkDeviceGroupPresentCapabilitiesKHX* pDeviceGroupPresentCapabilities);\ntypedef VkResult (VKAPI_PTR *PFN_vkGetDeviceGroupSurfacePresentModesKHX)(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHX* pModes);\ntypedef VkResult (VKAPI_PTR *PFN_vkAcquireNextImage2KHX)(VkDevice device, const VkAcquireNextImageInfoKHX* pAcquireInfo, uint32_t* pImageIndex);\ntypedef void (VKAPI_PTR *PFN_vkCmdDispatchBaseKHX)(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ);\ntypedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDevicePresentRectanglesKHX)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pRectCount, VkRect2D* pRects);\n\n#ifndef VK_NO_PROTOTYPES\nVKAPI_ATTR void VKAPI_CALL vkGetDeviceGroupPeerMemoryFeaturesKHX(\n    VkDevice                                    device,\n    uint32_t                                    heapIndex,\n    uint32_t                                    localDeviceIndex,\n    uint32_t                                    remoteDeviceIndex,\n    VkPeerMemoryFeatureFlagsKHX*                pPeerMemoryFeatures);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkBindBufferMemory2KHX(\n    VkDevice                                    device,\n    uint32_t                                    bindInfoCount,\n    const VkBindBufferMemoryInfoKHX*            pBindInfos);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory2KHX(\n    VkDevice                                    device,\n    uint32_t                                    bindInfoCount,\n    const VkBindImageMemoryInfoKHX*             pBindInfos);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdSetDeviceMaskKHX(\n    VkCommandBuffer                             commandBuffer,\n    uint32_t                                    deviceMask);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkGetDeviceGroupPresentCapabilitiesKHX(\n    VkDevice                                    device,\n    VkDeviceGroupPresentCapabilitiesKHX*        pDeviceGroupPresentCapabilities);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkGetDeviceGroupSurfacePresentModesKHX(\n    VkDevice                                    device,\n    VkSurfaceKHR                                surface,\n    VkDeviceGroupPresentModeFlagsKHX*           pModes);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkAcquireNextImage2KHX(\n    VkDevice                                    device,\n    const VkAcquireNextImageInfoKHX*            pAcquireInfo,\n    uint32_t*                                   pImageIndex);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdDispatchBaseKHX(\n    VkCommandBuffer                             commandBuffer,\n    uint32_t                                    baseGroupX,\n    uint32_t                                    baseGroupY,\n    uint32_t                                    baseGroupZ,\n    uint32_t                                    groupCountX,\n    uint32_t                                    groupCountY,\n    uint32_t                                    groupCountZ);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDevicePresentRectanglesKHX(\n    VkPhysicalDevice                            physicalDevice,\n    VkSurfaceKHR                                surface,\n    uint32_t*                                   pRectCount,\n    VkRect2D*                                   pRects);\n#endif\n\n#define VK_EXT_validation_flags 1\n#define VK_EXT_VALIDATION_FLAGS_SPEC_VERSION 1\n#define VK_EXT_VALIDATION_FLAGS_EXTENSION_NAME \"VK_EXT_validation_flags\"\n\n\ntypedef enum VkValidationCheckEXT {\n    VK_VALIDATION_CHECK_ALL_EXT = 0,\n    VK_VALIDATION_CHECK_BEGIN_RANGE_EXT = VK_VALIDATION_CHECK_ALL_EXT,\n    VK_VALIDATION_CHECK_END_RANGE_EXT = VK_VALIDATION_CHECK_ALL_EXT,\n    VK_VALIDATION_CHECK_RANGE_SIZE_EXT = (VK_VALIDATION_CHECK_ALL_EXT - VK_VALIDATION_CHECK_ALL_EXT + 1),\n    VK_VALIDATION_CHECK_MAX_ENUM_EXT = 0x7FFFFFFF\n} VkValidationCheckEXT;\n\ntypedef struct VkValidationFlagsEXT {\n    VkStructureType          sType;\n    const void*              pNext;\n    uint32_t                 disabledValidationCheckCount;\n    VkValidationCheckEXT*    pDisabledValidationChecks;\n} VkValidationFlagsEXT;\n\n\n\n#ifdef VK_USE_PLATFORM_VI_NN\n#define VK_NN_vi_surface 1\n#define VK_NN_VI_SURFACE_SPEC_VERSION     1\n#define VK_NN_VI_SURFACE_EXTENSION_NAME   \"VK_NN_vi_surface\"\n\ntypedef VkFlags VkViSurfaceCreateFlagsNN;\n\ntypedef struct VkViSurfaceCreateInfoNN {\n    VkStructureType             sType;\n    const void*                 pNext;\n    VkViSurfaceCreateFlagsNN    flags;\n    void*                       window;\n} VkViSurfaceCreateInfoNN;\n\n\ntypedef VkResult (VKAPI_PTR *PFN_vkCreateViSurfaceNN)(VkInstance instance, const VkViSurfaceCreateInfoNN* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);\n\n#ifndef VK_NO_PROTOTYPES\nVKAPI_ATTR VkResult VKAPI_CALL vkCreateViSurfaceNN(\n    VkInstance                                  instance,\n    const VkViSurfaceCreateInfoNN*              pCreateInfo,\n    const VkAllocationCallbacks*                pAllocator,\n    VkSurfaceKHR*                               pSurface);\n#endif\n#endif /* VK_USE_PLATFORM_VI_NN */\n\n#define VK_EXT_shader_subgroup_ballot 1\n#define VK_EXT_SHADER_SUBGROUP_BALLOT_SPEC_VERSION 1\n#define VK_EXT_SHADER_SUBGROUP_BALLOT_EXTENSION_NAME \"VK_EXT_shader_subgroup_ballot\"\n\n\n#define VK_EXT_shader_subgroup_vote 1\n#define VK_EXT_SHADER_SUBGROUP_VOTE_SPEC_VERSION 1\n#define VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME \"VK_EXT_shader_subgroup_vote\"\n\n\n#define VK_KHX_device_group_creation 1\n#define VK_KHX_DEVICE_GROUP_CREATION_SPEC_VERSION 1\n#define VK_KHX_DEVICE_GROUP_CREATION_EXTENSION_NAME \"VK_KHX_device_group_creation\"\n\ntypedef struct VkPhysicalDeviceGroupPropertiesKHX {\n    VkStructureType     sType;\n    void*               pNext;\n    uint32_t            physicalDeviceCount;\n    VkPhysicalDevice    physicalDevices[VK_MAX_DEVICE_GROUP_SIZE_KHX];\n    VkBool32            subsetAllocation;\n} VkPhysicalDeviceGroupPropertiesKHX;\n\ntypedef struct VkDeviceGroupDeviceCreateInfoKHX {\n    VkStructureType            sType;\n    const void*                pNext;\n    uint32_t                   physicalDeviceCount;\n    const VkPhysicalDevice*    pPhysicalDevices;\n} VkDeviceGroupDeviceCreateInfoKHX;\n\n\ntypedef VkResult (VKAPI_PTR *PFN_vkEnumeratePhysicalDeviceGroupsKHX)(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupPropertiesKHX* pPhysicalDeviceGroupProperties);\n\n#ifndef VK_NO_PROTOTYPES\nVKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDeviceGroupsKHX(\n    VkInstance                                  instance,\n    uint32_t*                                   pPhysicalDeviceGroupCount,\n    VkPhysicalDeviceGroupPropertiesKHX*         pPhysicalDeviceGroupProperties);\n#endif\n\n#define VK_KHX_external_memory_capabilities 1\n#define VK_LUID_SIZE_KHX                  8\n#define VK_KHX_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION 1\n#define VK_KHX_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME \"VK_KHX_external_memory_capabilities\"\n\n\ntypedef enum VkExternalMemoryHandleTypeFlagBitsKHX {\n    VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHX = 0x00000001,\n    VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHX = 0x00000002,\n    VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHX = 0x00000004,\n    VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT_KHX = 0x00000008,\n    VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT_KHX = 0x00000010,\n    VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT_KHX = 0x00000020,\n    VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT_KHX = 0x00000040,\n    VK_EXTERNAL_MEMORY_HANDLE_TYPE_FLAG_BITS_MAX_ENUM_KHX = 0x7FFFFFFF\n} VkExternalMemoryHandleTypeFlagBitsKHX;\ntypedef VkFlags VkExternalMemoryHandleTypeFlagsKHX;\n\ntypedef enum VkExternalMemoryFeatureFlagBitsKHX {\n    VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_KHX = 0x00000001,\n    VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHX = 0x00000002,\n    VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHX = 0x00000004,\n    VK_EXTERNAL_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM_KHX = 0x7FFFFFFF\n} VkExternalMemoryFeatureFlagBitsKHX;\ntypedef VkFlags VkExternalMemoryFeatureFlagsKHX;\n\ntypedef struct VkExternalMemoryPropertiesKHX {\n    VkExternalMemoryFeatureFlagsKHX       externalMemoryFeatures;\n    VkExternalMemoryHandleTypeFlagsKHX    exportFromImportedHandleTypes;\n    VkExternalMemoryHandleTypeFlagsKHX    compatibleHandleTypes;\n} VkExternalMemoryPropertiesKHX;\n\ntypedef struct VkPhysicalDeviceExternalImageFormatInfoKHX {\n    VkStructureType                          sType;\n    const void*                              pNext;\n    VkExternalMemoryHandleTypeFlagBitsKHX    handleType;\n} VkPhysicalDeviceExternalImageFormatInfoKHX;\n\ntypedef struct VkExternalImageFormatPropertiesKHX {\n    VkStructureType                  sType;\n    void*                            pNext;\n    VkExternalMemoryPropertiesKHX    externalMemoryProperties;\n} VkExternalImageFormatPropertiesKHX;\n\ntypedef struct VkPhysicalDeviceExternalBufferInfoKHX {\n    VkStructureType                          sType;\n    const void*                              pNext;\n    VkBufferCreateFlags                      flags;\n    VkBufferUsageFlags                       usage;\n    VkExternalMemoryHandleTypeFlagBitsKHX    handleType;\n} VkPhysicalDeviceExternalBufferInfoKHX;\n\ntypedef struct VkExternalBufferPropertiesKHX {\n    VkStructureType                  sType;\n    void*                            pNext;\n    VkExternalMemoryPropertiesKHX    externalMemoryProperties;\n} VkExternalBufferPropertiesKHX;\n\ntypedef struct VkPhysicalDeviceIDPropertiesKHX {\n    VkStructureType    sType;\n    void*              pNext;\n    uint8_t            deviceUUID[VK_UUID_SIZE];\n    uint8_t            driverUUID[VK_UUID_SIZE];\n    uint8_t            deviceLUID[VK_LUID_SIZE_KHX];\n    VkBool32           deviceLUIDValid;\n} VkPhysicalDeviceIDPropertiesKHX;\n\n\ntypedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHX)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfoKHX* pExternalBufferInfo, VkExternalBufferPropertiesKHX* pExternalBufferProperties);\n\n#ifndef VK_NO_PROTOTYPES\nVKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalBufferPropertiesKHX(\n    VkPhysicalDevice                            physicalDevice,\n    const VkPhysicalDeviceExternalBufferInfoKHX* pExternalBufferInfo,\n    VkExternalBufferPropertiesKHX*              pExternalBufferProperties);\n#endif\n\n#define VK_KHX_external_memory 1\n#define VK_KHX_EXTERNAL_MEMORY_SPEC_VERSION 1\n#define VK_KHX_EXTERNAL_MEMORY_EXTENSION_NAME \"VK_KHX_external_memory\"\n#define VK_QUEUE_FAMILY_EXTERNAL_KHX      (~0U-1)\n\ntypedef struct VkExternalMemoryImageCreateInfoKHX {\n    VkStructureType                       sType;\n    const void*                           pNext;\n    VkExternalMemoryHandleTypeFlagsKHX    handleTypes;\n} VkExternalMemoryImageCreateInfoKHX;\n\ntypedef struct VkExternalMemoryBufferCreateInfoKHX {\n    VkStructureType                       sType;\n    const void*                           pNext;\n    VkExternalMemoryHandleTypeFlagsKHX    handleTypes;\n} VkExternalMemoryBufferCreateInfoKHX;\n\ntypedef struct VkExportMemoryAllocateInfoKHX {\n    VkStructureType                       sType;\n    const void*                           pNext;\n    VkExternalMemoryHandleTypeFlagsKHX    handleTypes;\n} VkExportMemoryAllocateInfoKHX;\n\n\n\n#ifdef VK_USE_PLATFORM_WIN32_KHX\n#define VK_KHX_external_memory_win32 1\n#define VK_KHX_EXTERNAL_MEMORY_WIN32_SPEC_VERSION 1\n#define VK_KHX_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME \"VK_KHX_external_memory_win32\"\n\ntypedef struct VkImportMemoryWin32HandleInfoKHX {\n    VkStructureType                          sType;\n    const void*                              pNext;\n    VkExternalMemoryHandleTypeFlagBitsKHX    handleType;\n    HANDLE                                   handle;\n} VkImportMemoryWin32HandleInfoKHX;\n\ntypedef struct VkExportMemoryWin32HandleInfoKHX {\n    VkStructureType               sType;\n    const void*                   pNext;\n    const SECURITY_ATTRIBUTES*    pAttributes;\n    DWORD                         dwAccess;\n    LPCWSTR                       name;\n} VkExportMemoryWin32HandleInfoKHX;\n\ntypedef struct VkMemoryWin32HandlePropertiesKHX {\n    VkStructureType    sType;\n    void*              pNext;\n    uint32_t           memoryTypeBits;\n} VkMemoryWin32HandlePropertiesKHX;\n\n\ntypedef VkResult (VKAPI_PTR *PFN_vkGetMemoryWin32HandleKHX)(VkDevice device, VkDeviceMemory memory, VkExternalMemoryHandleTypeFlagBitsKHX handleType, HANDLE* pHandle);\ntypedef VkResult (VKAPI_PTR *PFN_vkGetMemoryWin32HandlePropertiesKHX)(VkDevice device, VkExternalMemoryHandleTypeFlagBitsKHX handleType, HANDLE handle, VkMemoryWin32HandlePropertiesKHX* pMemoryWin32HandleProperties);\n\n#ifndef VK_NO_PROTOTYPES\nVKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryWin32HandleKHX(\n    VkDevice                                    device,\n    VkDeviceMemory                              memory,\n    VkExternalMemoryHandleTypeFlagBitsKHX       handleType,\n    HANDLE*                                     pHandle);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryWin32HandlePropertiesKHX(\n    VkDevice                                    device,\n    VkExternalMemoryHandleTypeFlagBitsKHX       handleType,\n    HANDLE                                      handle,\n    VkMemoryWin32HandlePropertiesKHX*           pMemoryWin32HandleProperties);\n#endif\n#endif /* VK_USE_PLATFORM_WIN32_KHX */\n\n#define VK_KHX_external_memory_fd 1\n#define VK_KHX_EXTERNAL_MEMORY_FD_SPEC_VERSION 1\n#define VK_KHX_EXTERNAL_MEMORY_FD_EXTENSION_NAME \"VK_KHX_external_memory_fd\"\n\ntypedef struct VkImportMemoryFdInfoKHX {\n    VkStructureType                          sType;\n    const void*                              pNext;\n    VkExternalMemoryHandleTypeFlagBitsKHX    handleType;\n    int                                      fd;\n} VkImportMemoryFdInfoKHX;\n\ntypedef struct VkMemoryFdPropertiesKHX {\n    VkStructureType    sType;\n    void*              pNext;\n    uint32_t           memoryTypeBits;\n} VkMemoryFdPropertiesKHX;\n\n\ntypedef VkResult (VKAPI_PTR *PFN_vkGetMemoryFdKHX)(VkDevice device, VkDeviceMemory memory, VkExternalMemoryHandleTypeFlagBitsKHX handleType, int* pFd);\ntypedef VkResult (VKAPI_PTR *PFN_vkGetMemoryFdPropertiesKHX)(VkDevice device, VkExternalMemoryHandleTypeFlagBitsKHX handleType, int fd, VkMemoryFdPropertiesKHX* pMemoryFdProperties);\n\n#ifndef VK_NO_PROTOTYPES\nVKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryFdKHX(\n    VkDevice                                    device,\n    VkDeviceMemory                              memory,\n    VkExternalMemoryHandleTypeFlagBitsKHX       handleType,\n    int*                                        pFd);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryFdPropertiesKHX(\n    VkDevice                                    device,\n    VkExternalMemoryHandleTypeFlagBitsKHX       handleType,\n    int                                         fd,\n    VkMemoryFdPropertiesKHX*                    pMemoryFdProperties);\n#endif\n\n#ifdef VK_USE_PLATFORM_WIN32_KHR\n#define VK_KHX_win32_keyed_mutex 1\n#define VK_KHX_WIN32_KEYED_MUTEX_SPEC_VERSION 1\n#define VK_KHX_WIN32_KEYED_MUTEX_EXTENSION_NAME \"VK_KHX_win32_keyed_mutex\"\n\ntypedef struct VkWin32KeyedMutexAcquireReleaseInfoKHX {\n    VkStructureType          sType;\n    const void*              pNext;\n    uint32_t                 acquireCount;\n    const VkDeviceMemory*    pAcquireSyncs;\n    const uint64_t*          pAcquireKeys;\n    const uint32_t*          pAcquireTimeouts;\n    uint32_t                 releaseCount;\n    const VkDeviceMemory*    pReleaseSyncs;\n    const uint64_t*          pReleaseKeys;\n} VkWin32KeyedMutexAcquireReleaseInfoKHX;\n\n\n#endif /* VK_USE_PLATFORM_WIN32_KHR */\n\n#define VK_KHX_external_semaphore_capabilities 1\n#define VK_KHX_EXTERNAL_SEMAPHORE_CAPABILITIES_SPEC_VERSION 1\n#define VK_KHX_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME \"VK_KHX_external_semaphore_capabilities\"\n\n\ntypedef enum VkExternalSemaphoreHandleTypeFlagBitsKHX {\n    VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHX = 0x00000001,\n    VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHX = 0x00000002,\n    VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHX = 0x00000004,\n    VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT_KHX = 0x00000008,\n    VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FENCE_FD_BIT_KHX = 0x00000010,\n    VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FLAG_BITS_MAX_ENUM_KHX = 0x7FFFFFFF\n} VkExternalSemaphoreHandleTypeFlagBitsKHX;\ntypedef VkFlags VkExternalSemaphoreHandleTypeFlagsKHX;\n\ntypedef enum VkExternalSemaphoreFeatureFlagBitsKHX {\n    VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT_KHX = 0x00000001,\n    VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT_KHX = 0x00000002,\n    VK_EXTERNAL_SEMAPHORE_FEATURE_FLAG_BITS_MAX_ENUM_KHX = 0x7FFFFFFF\n} VkExternalSemaphoreFeatureFlagBitsKHX;\ntypedef VkFlags VkExternalSemaphoreFeatureFlagsKHX;\n\ntypedef struct VkPhysicalDeviceExternalSemaphoreInfoKHX {\n    VkStructureType                             sType;\n    const void*                                 pNext;\n    VkExternalSemaphoreHandleTypeFlagBitsKHX    handleType;\n} VkPhysicalDeviceExternalSemaphoreInfoKHX;\n\ntypedef struct VkExternalSemaphorePropertiesKHX {\n    VkStructureType                          sType;\n    void*                                    pNext;\n    VkExternalSemaphoreHandleTypeFlagsKHX    exportFromImportedHandleTypes;\n    VkExternalSemaphoreHandleTypeFlagsKHX    compatibleHandleTypes;\n    VkExternalSemaphoreFeatureFlagsKHX       externalSemaphoreFeatures;\n} VkExternalSemaphorePropertiesKHX;\n\n\ntypedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHX)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfoKHX* pExternalSemaphoreInfo, VkExternalSemaphorePropertiesKHX* pExternalSemaphoreProperties);\n\n#ifndef VK_NO_PROTOTYPES\nVKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalSemaphorePropertiesKHX(\n    VkPhysicalDevice                            physicalDevice,\n    const VkPhysicalDeviceExternalSemaphoreInfoKHX* pExternalSemaphoreInfo,\n    VkExternalSemaphorePropertiesKHX*           pExternalSemaphoreProperties);\n#endif\n\n#define VK_KHX_external_semaphore 1\n#define VK_KHX_EXTERNAL_SEMAPHORE_SPEC_VERSION 1\n#define VK_KHX_EXTERNAL_SEMAPHORE_EXTENSION_NAME \"VK_KHX_external_semaphore\"\n\ntypedef struct VkExportSemaphoreCreateInfoKHX {\n    VkStructureType                          sType;\n    const void*                              pNext;\n    VkExternalSemaphoreHandleTypeFlagsKHX    handleTypes;\n} VkExportSemaphoreCreateInfoKHX;\n\n\n\n#ifdef VK_USE_PLATFORM_WIN32_KHX\n#define VK_KHX_external_semaphore_win32 1\n#define VK_KHX_EXTERNAL_SEMAPHORE_WIN32_SPEC_VERSION 1\n#define VK_KHX_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME \"VK_KHX_external_semaphore_win32\"\n\ntypedef struct VkImportSemaphoreWin32HandleInfoKHX {\n    VkStructureType                          sType;\n    const void*                              pNext;\n    VkSemaphore                              semaphore;\n    VkExternalSemaphoreHandleTypeFlagsKHX    handleType;\n    HANDLE                                   handle;\n} VkImportSemaphoreWin32HandleInfoKHX;\n\ntypedef struct VkExportSemaphoreWin32HandleInfoKHX {\n    VkStructureType               sType;\n    const void*                   pNext;\n    const SECURITY_ATTRIBUTES*    pAttributes;\n    DWORD                         dwAccess;\n    LPCWSTR                       name;\n} VkExportSemaphoreWin32HandleInfoKHX;\n\ntypedef struct VkD3D12FenceSubmitInfoKHX {\n    VkStructureType    sType;\n    const void*        pNext;\n    uint32_t           waitSemaphoreValuesCount;\n    const uint64_t*    pWaitSemaphoreValues;\n    uint32_t           signalSemaphoreValuesCount;\n    const uint64_t*    pSignalSemaphoreValues;\n} VkD3D12FenceSubmitInfoKHX;\n\n\ntypedef VkResult (VKAPI_PTR *PFN_vkImportSemaphoreWin32HandleKHX)(VkDevice device, const VkImportSemaphoreWin32HandleInfoKHX* pImportSemaphoreWin32HandleInfo);\ntypedef VkResult (VKAPI_PTR *PFN_vkGetSemaphoreWin32HandleKHX)(VkDevice device, VkSemaphore semaphore, VkExternalSemaphoreHandleTypeFlagBitsKHX handleType, HANDLE* pHandle);\n\n#ifndef VK_NO_PROTOTYPES\nVKAPI_ATTR VkResult VKAPI_CALL vkImportSemaphoreWin32HandleKHX(\n    VkDevice                                    device,\n    const VkImportSemaphoreWin32HandleInfoKHX*  pImportSemaphoreWin32HandleInfo);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkGetSemaphoreWin32HandleKHX(\n    VkDevice                                    device,\n    VkSemaphore                                 semaphore,\n    VkExternalSemaphoreHandleTypeFlagBitsKHX    handleType,\n    HANDLE*                                     pHandle);\n#endif\n#endif /* VK_USE_PLATFORM_WIN32_KHX */\n\n#define VK_KHX_external_semaphore_fd 1\n#define VK_KHX_EXTERNAL_SEMAPHORE_FD_SPEC_VERSION 1\n#define VK_KHX_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME \"VK_KHX_external_semaphore_fd\"\n\ntypedef struct VkImportSemaphoreFdInfoKHX {\n    VkStructureType                             sType;\n    const void*                                 pNext;\n    VkSemaphore                                 semaphore;\n    VkExternalSemaphoreHandleTypeFlagBitsKHX    handleType;\n    int                                         fd;\n} VkImportSemaphoreFdInfoKHX;\n\n\ntypedef VkResult (VKAPI_PTR *PFN_vkImportSemaphoreFdKHX)(VkDevice device, const VkImportSemaphoreFdInfoKHX* pImportSemaphoreFdInfo);\ntypedef VkResult (VKAPI_PTR *PFN_vkGetSemaphoreFdKHX)(VkDevice device, VkSemaphore semaphore, VkExternalSemaphoreHandleTypeFlagBitsKHX handleType, int* pFd);\n\n#ifndef VK_NO_PROTOTYPES\nVKAPI_ATTR VkResult VKAPI_CALL vkImportSemaphoreFdKHX(\n    VkDevice                                    device,\n    const VkImportSemaphoreFdInfoKHX*           pImportSemaphoreFdInfo);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkGetSemaphoreFdKHX(\n    VkDevice                                    device,\n    VkSemaphore                                 semaphore,\n    VkExternalSemaphoreHandleTypeFlagBitsKHX    handleType,\n    int*                                        pFd);\n#endif\n\n#define VK_NVX_device_generated_commands 1\nVK_DEFINE_NON_DISPATCHABLE_HANDLE(VkObjectTableNVX)\nVK_DEFINE_NON_DISPATCHABLE_HANDLE(VkIndirectCommandsLayoutNVX)\n\n#define VK_NVX_DEVICE_GENERATED_COMMANDS_SPEC_VERSION 1\n#define VK_NVX_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME \"VK_NVX_device_generated_commands\"\n\n\ntypedef enum VkIndirectCommandsTokenTypeNVX {\n    VK_INDIRECT_COMMANDS_TOKEN_PIPELINE_NVX = 0,\n    VK_INDIRECT_COMMANDS_TOKEN_DESCRIPTOR_SET_NVX = 1,\n    VK_INDIRECT_COMMANDS_TOKEN_INDEX_BUFFER_NVX = 2,\n    VK_INDIRECT_COMMANDS_TOKEN_VERTEX_BUFFER_NVX = 3,\n    VK_INDIRECT_COMMANDS_TOKEN_PUSH_CONSTANT_NVX = 4,\n    VK_INDIRECT_COMMANDS_TOKEN_DRAW_INDEXED_NVX = 5,\n    VK_INDIRECT_COMMANDS_TOKEN_DRAW_NVX = 6,\n    VK_INDIRECT_COMMANDS_TOKEN_DISPATCH_NVX = 7,\n    VK_INDIRECT_COMMANDS_TOKEN_TYPE_BEGIN_RANGE_NVX = VK_INDIRECT_COMMANDS_TOKEN_PIPELINE_NVX,\n    VK_INDIRECT_COMMANDS_TOKEN_TYPE_END_RANGE_NVX = VK_INDIRECT_COMMANDS_TOKEN_DISPATCH_NVX,\n    VK_INDIRECT_COMMANDS_TOKEN_TYPE_RANGE_SIZE_NVX = (VK_INDIRECT_COMMANDS_TOKEN_DISPATCH_NVX - VK_INDIRECT_COMMANDS_TOKEN_PIPELINE_NVX + 1),\n    VK_INDIRECT_COMMANDS_TOKEN_TYPE_MAX_ENUM_NVX = 0x7FFFFFFF\n} VkIndirectCommandsTokenTypeNVX;\n\ntypedef enum VkObjectEntryTypeNVX {\n    VK_OBJECT_ENTRY_DESCRIPTOR_SET_NVX = 0,\n    VK_OBJECT_ENTRY_PIPELINE_NVX = 1,\n    VK_OBJECT_ENTRY_INDEX_BUFFER_NVX = 2,\n    VK_OBJECT_ENTRY_VERTEX_BUFFER_NVX = 3,\n    VK_OBJECT_ENTRY_PUSH_CONSTANT_NVX = 4,\n    VK_OBJECT_ENTRY_TYPE_BEGIN_RANGE_NVX = VK_OBJECT_ENTRY_DESCRIPTOR_SET_NVX,\n    VK_OBJECT_ENTRY_TYPE_END_RANGE_NVX = VK_OBJECT_ENTRY_PUSH_CONSTANT_NVX,\n    VK_OBJECT_ENTRY_TYPE_RANGE_SIZE_NVX = (VK_OBJECT_ENTRY_PUSH_CONSTANT_NVX - VK_OBJECT_ENTRY_DESCRIPTOR_SET_NVX + 1),\n    VK_OBJECT_ENTRY_TYPE_MAX_ENUM_NVX = 0x7FFFFFFF\n} VkObjectEntryTypeNVX;\n\n\ntypedef enum VkIndirectCommandsLayoutUsageFlagBitsNVX {\n    VK_INDIRECT_COMMANDS_LAYOUT_USAGE_UNORDERED_SEQUENCES_BIT_NVX = 0x00000001,\n    VK_INDIRECT_COMMANDS_LAYOUT_USAGE_SPARSE_SEQUENCES_BIT_NVX = 0x00000002,\n    VK_INDIRECT_COMMANDS_LAYOUT_USAGE_EMPTY_EXECUTIONS_BIT_NVX = 0x00000004,\n    VK_INDIRECT_COMMANDS_LAYOUT_USAGE_INDEXED_SEQUENCES_BIT_NVX = 0x00000008,\n    VK_INDIRECT_COMMANDS_LAYOUT_USAGE_FLAG_BITS_MAX_ENUM_NVX = 0x7FFFFFFF\n} VkIndirectCommandsLayoutUsageFlagBitsNVX;\ntypedef VkFlags VkIndirectCommandsLayoutUsageFlagsNVX;\n\ntypedef enum VkObjectEntryUsageFlagBitsNVX {\n    VK_OBJECT_ENTRY_USAGE_GRAPHICS_BIT_NVX = 0x00000001,\n    VK_OBJECT_ENTRY_USAGE_COMPUTE_BIT_NVX = 0x00000002,\n    VK_OBJECT_ENTRY_USAGE_FLAG_BITS_MAX_ENUM_NVX = 0x7FFFFFFF\n} VkObjectEntryUsageFlagBitsNVX;\ntypedef VkFlags VkObjectEntryUsageFlagsNVX;\n\ntypedef struct VkDeviceGeneratedCommandsFeaturesNVX {\n    VkStructureType    sType;\n    const void*        pNext;\n    VkBool32           computeBindingPointSupport;\n} VkDeviceGeneratedCommandsFeaturesNVX;\n\ntypedef struct VkDeviceGeneratedCommandsLimitsNVX {\n    VkStructureType    sType;\n    const void*        pNext;\n    uint32_t           maxIndirectCommandsLayoutTokenCount;\n    uint32_t           maxObjectEntryCounts;\n    uint32_t           minSequenceCountBufferOffsetAlignment;\n    uint32_t           minSequenceIndexBufferOffsetAlignment;\n    uint32_t           minCommandsTokenBufferOffsetAlignment;\n} VkDeviceGeneratedCommandsLimitsNVX;\n\ntypedef struct VkIndirectCommandsTokenNVX {\n    VkIndirectCommandsTokenTypeNVX    tokenType;\n    VkBuffer                          buffer;\n    VkDeviceSize                      offset;\n} VkIndirectCommandsTokenNVX;\n\ntypedef struct VkIndirectCommandsLayoutTokenNVX {\n    VkIndirectCommandsTokenTypeNVX    tokenType;\n    uint32_t                          bindingUnit;\n    uint32_t                          dynamicCount;\n    uint32_t                          divisor;\n} VkIndirectCommandsLayoutTokenNVX;\n\ntypedef struct VkIndirectCommandsLayoutCreateInfoNVX {\n    VkStructureType                            sType;\n    const void*                                pNext;\n    VkPipelineBindPoint                        pipelineBindPoint;\n    VkIndirectCommandsLayoutUsageFlagsNVX      flags;\n    uint32_t                                   tokenCount;\n    const VkIndirectCommandsLayoutTokenNVX*    pTokens;\n} VkIndirectCommandsLayoutCreateInfoNVX;\n\ntypedef struct VkCmdProcessCommandsInfoNVX {\n    VkStructureType                      sType;\n    const void*                          pNext;\n    VkObjectTableNVX                     objectTable;\n    VkIndirectCommandsLayoutNVX          indirectCommandsLayout;\n    uint32_t                             indirectCommandsTokenCount;\n    const VkIndirectCommandsTokenNVX*    pIndirectCommandsTokens;\n    uint32_t                             maxSequencesCount;\n    VkCommandBuffer                      targetCommandBuffer;\n    VkBuffer                             sequencesCountBuffer;\n    VkDeviceSize                         sequencesCountOffset;\n    VkBuffer                             sequencesIndexBuffer;\n    VkDeviceSize                         sequencesIndexOffset;\n} VkCmdProcessCommandsInfoNVX;\n\ntypedef struct VkCmdReserveSpaceForCommandsInfoNVX {\n    VkStructureType                sType;\n    const void*                    pNext;\n    VkObjectTableNVX               objectTable;\n    VkIndirectCommandsLayoutNVX    indirectCommandsLayout;\n    uint32_t                       maxSequencesCount;\n} VkCmdReserveSpaceForCommandsInfoNVX;\n\ntypedef struct VkObjectTableCreateInfoNVX {\n    VkStructureType                      sType;\n    const void*                          pNext;\n    uint32_t                             objectCount;\n    const VkObjectEntryTypeNVX*          pObjectEntryTypes;\n    const uint32_t*                      pObjectEntryCounts;\n    const VkObjectEntryUsageFlagsNVX*    pObjectEntryUsageFlags;\n    uint32_t                             maxUniformBuffersPerDescriptor;\n    uint32_t                             maxStorageBuffersPerDescriptor;\n    uint32_t                             maxStorageImagesPerDescriptor;\n    uint32_t                             maxSampledImagesPerDescriptor;\n    uint32_t                             maxPipelineLayouts;\n} VkObjectTableCreateInfoNVX;\n\ntypedef struct VkObjectTableEntryNVX {\n    VkObjectEntryTypeNVX          type;\n    VkObjectEntryUsageFlagsNVX    flags;\n} VkObjectTableEntryNVX;\n\ntypedef struct VkObjectTablePipelineEntryNVX {\n    VkObjectEntryTypeNVX          type;\n    VkObjectEntryUsageFlagsNVX    flags;\n    VkPipeline                    pipeline;\n} VkObjectTablePipelineEntryNVX;\n\ntypedef struct VkObjectTableDescriptorSetEntryNVX {\n    VkObjectEntryTypeNVX          type;\n    VkObjectEntryUsageFlagsNVX    flags;\n    VkPipelineLayout              pipelineLayout;\n    VkDescriptorSet               descriptorSet;\n} VkObjectTableDescriptorSetEntryNVX;\n\ntypedef struct VkObjectTableVertexBufferEntryNVX {\n    VkObjectEntryTypeNVX          type;\n    VkObjectEntryUsageFlagsNVX    flags;\n    VkBuffer                      buffer;\n} VkObjectTableVertexBufferEntryNVX;\n\ntypedef struct VkObjectTableIndexBufferEntryNVX {\n    VkObjectEntryTypeNVX          type;\n    VkObjectEntryUsageFlagsNVX    flags;\n    VkBuffer                      buffer;\n    VkIndexType                   indexType;\n} VkObjectTableIndexBufferEntryNVX;\n\ntypedef struct VkObjectTablePushConstantEntryNVX {\n    VkObjectEntryTypeNVX          type;\n    VkObjectEntryUsageFlagsNVX    flags;\n    VkPipelineLayout              pipelineLayout;\n    VkShaderStageFlags            stageFlags;\n} VkObjectTablePushConstantEntryNVX;\n\n\ntypedef void (VKAPI_PTR *PFN_vkCmdProcessCommandsNVX)(VkCommandBuffer commandBuffer, const VkCmdProcessCommandsInfoNVX* pProcessCommandsInfo);\ntypedef void (VKAPI_PTR *PFN_vkCmdReserveSpaceForCommandsNVX)(VkCommandBuffer commandBuffer, const VkCmdReserveSpaceForCommandsInfoNVX* pReserveSpaceInfo);\ntypedef VkResult (VKAPI_PTR *PFN_vkCreateIndirectCommandsLayoutNVX)(VkDevice device, const VkIndirectCommandsLayoutCreateInfoNVX* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkIndirectCommandsLayoutNVX* pIndirectCommandsLayout);\ntypedef void (VKAPI_PTR *PFN_vkDestroyIndirectCommandsLayoutNVX)(VkDevice device, VkIndirectCommandsLayoutNVX indirectCommandsLayout, const VkAllocationCallbacks* pAllocator);\ntypedef VkResult (VKAPI_PTR *PFN_vkCreateObjectTableNVX)(VkDevice device, const VkObjectTableCreateInfoNVX* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkObjectTableNVX* pObjectTable);\ntypedef void (VKAPI_PTR *PFN_vkDestroyObjectTableNVX)(VkDevice device, VkObjectTableNVX objectTable, const VkAllocationCallbacks* pAllocator);\ntypedef VkResult (VKAPI_PTR *PFN_vkRegisterObjectsNVX)(VkDevice device, VkObjectTableNVX objectTable, uint32_t objectCount, const VkObjectTableEntryNVX* const*    ppObjectTableEntries, const uint32_t* pObjectIndices);\ntypedef VkResult (VKAPI_PTR *PFN_vkUnregisterObjectsNVX)(VkDevice device, VkObjectTableNVX objectTable, uint32_t objectCount, const VkObjectEntryTypeNVX* pObjectEntryTypes, const uint32_t* pObjectIndices);\ntypedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX)(VkPhysicalDevice physicalDevice, VkDeviceGeneratedCommandsFeaturesNVX* pFeatures, VkDeviceGeneratedCommandsLimitsNVX* pLimits);\n\n#ifndef VK_NO_PROTOTYPES\nVKAPI_ATTR void VKAPI_CALL vkCmdProcessCommandsNVX(\n    VkCommandBuffer                             commandBuffer,\n    const VkCmdProcessCommandsInfoNVX*          pProcessCommandsInfo);\n\nVKAPI_ATTR void VKAPI_CALL vkCmdReserveSpaceForCommandsNVX(\n    VkCommandBuffer                             commandBuffer,\n    const VkCmdReserveSpaceForCommandsInfoNVX*  pReserveSpaceInfo);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkCreateIndirectCommandsLayoutNVX(\n    VkDevice                                    device,\n    const VkIndirectCommandsLayoutCreateInfoNVX* pCreateInfo,\n    const VkAllocationCallbacks*                pAllocator,\n    VkIndirectCommandsLayoutNVX*                pIndirectCommandsLayout);\n\nVKAPI_ATTR void VKAPI_CALL vkDestroyIndirectCommandsLayoutNVX(\n    VkDevice                                    device,\n    VkIndirectCommandsLayoutNVX                 indirectCommandsLayout,\n    const VkAllocationCallbacks*                pAllocator);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkCreateObjectTableNVX(\n    VkDevice                                    device,\n    const VkObjectTableCreateInfoNVX*           pCreateInfo,\n    const VkAllocationCallbacks*                pAllocator,\n    VkObjectTableNVX*                           pObjectTable);\n\nVKAPI_ATTR void VKAPI_CALL vkDestroyObjectTableNVX(\n    VkDevice                                    device,\n    VkObjectTableNVX                            objectTable,\n    const VkAllocationCallbacks*                pAllocator);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkRegisterObjectsNVX(\n    VkDevice                                    device,\n    VkObjectTableNVX                            objectTable,\n    uint32_t                                    objectCount,\n    const VkObjectTableEntryNVX* const*         ppObjectTableEntries,\n    const uint32_t*                             pObjectIndices);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkUnregisterObjectsNVX(\n    VkDevice                                    device,\n    VkObjectTableNVX                            objectTable,\n    uint32_t                                    objectCount,\n    const VkObjectEntryTypeNVX*                 pObjectEntryTypes,\n    const uint32_t*                             pObjectIndices);\n\nVKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX(\n    VkPhysicalDevice                            physicalDevice,\n    VkDeviceGeneratedCommandsFeaturesNVX*       pFeatures,\n    VkDeviceGeneratedCommandsLimitsNVX*         pLimits);\n#endif\n\n#define VK_NV_clip_space_w_scaling 1\n#define VK_NV_CLIP_SPACE_W_SCALING_SPEC_VERSION 1\n#define VK_NV_CLIP_SPACE_W_SCALING_EXTENSION_NAME \"VK_NV_clip_space_w_scaling\"\n\ntypedef struct VkViewportWScalingNV {\n    float    xcoeff;\n    float    ycoeff;\n} VkViewportWScalingNV;\n\ntypedef struct VkPipelineViewportWScalingStateCreateInfoNV {\n    VkStructureType                sType;\n    const void*                    pNext;\n    VkBool32                       viewportWScalingEnable;\n    uint32_t                       viewportCount;\n    const VkViewportWScalingNV*    pViewportWScalings;\n} VkPipelineViewportWScalingStateCreateInfoNV;\n\n\ntypedef void (VKAPI_PTR *PFN_vkCmdSetViewportWScalingNV)(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewportWScalingNV* pViewportWScalings);\n\n#ifndef VK_NO_PROTOTYPES\nVKAPI_ATTR void VKAPI_CALL vkCmdSetViewportWScalingNV(\n    VkCommandBuffer                             commandBuffer,\n    uint32_t                                    firstViewport,\n    uint32_t                                    viewportCount,\n    const VkViewportWScalingNV*                 pViewportWScalings);\n#endif\n\n#define VK_EXT_direct_mode_display 1\n#define VK_EXT_DIRECT_MODE_DISPLAY_SPEC_VERSION 1\n#define VK_EXT_DIRECT_MODE_DISPLAY_EXTENSION_NAME \"VK_EXT_direct_mode_display\"\n\ntypedef VkResult (VKAPI_PTR *PFN_vkReleaseDisplayEXT)(VkPhysicalDevice physicalDevice, VkDisplayKHR display);\n\n#ifndef VK_NO_PROTOTYPES\nVKAPI_ATTR VkResult VKAPI_CALL vkReleaseDisplayEXT(\n    VkPhysicalDevice                            physicalDevice,\n    VkDisplayKHR                                display);\n#endif\n\n#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT\n#define VK_EXT_acquire_xlib_display 1\n#include <X11/extensions/Xrandr.h>\n\n#define VK_EXT_ACQUIRE_XLIB_DISPLAY_SPEC_VERSION 1\n#define VK_EXT_ACQUIRE_XLIB_DISPLAY_EXTENSION_NAME \"VK_EXT_acquire_xlib_display\"\n\ntypedef VkResult (VKAPI_PTR *PFN_vkAcquireXlibDisplayEXT)(VkPhysicalDevice physicalDevice, Display* dpy, VkDisplayKHR display);\ntypedef VkResult (VKAPI_PTR *PFN_vkGetRandROutputDisplayEXT)(VkPhysicalDevice physicalDevice, Display* dpy, RROutput rrOutput, VkDisplayKHR* pDisplay);\n\n#ifndef VK_NO_PROTOTYPES\nVKAPI_ATTR VkResult VKAPI_CALL vkAcquireXlibDisplayEXT(\n    VkPhysicalDevice                            physicalDevice,\n    Display*                                    dpy,\n    VkDisplayKHR                                display);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkGetRandROutputDisplayEXT(\n    VkPhysicalDevice                            physicalDevice,\n    Display*                                    dpy,\n    RROutput                                    rrOutput,\n    VkDisplayKHR*                               pDisplay);\n#endif\n#endif /* VK_USE_PLATFORM_XLIB_XRANDR_EXT */\n\n#define VK_EXT_display_surface_counter 1\n#define VK_EXT_DISPLAY_SURFACE_COUNTER_SPEC_VERSION 1\n#define VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME \"VK_EXT_display_surface_counter\"\n\n\ntypedef enum VkSurfaceCounterFlagBitsEXT {\n    VK_SURFACE_COUNTER_VBLANK_EXT = 0x00000001,\n    VK_SURFACE_COUNTER_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF\n} VkSurfaceCounterFlagBitsEXT;\ntypedef VkFlags VkSurfaceCounterFlagsEXT;\n\ntypedef struct VkSurfaceCapabilities2EXT {\n    VkStructureType                  sType;\n    void*                            pNext;\n    uint32_t                         minImageCount;\n    uint32_t                         maxImageCount;\n    VkExtent2D                       currentExtent;\n    VkExtent2D                       minImageExtent;\n    VkExtent2D                       maxImageExtent;\n    uint32_t                         maxImageArrayLayers;\n    VkSurfaceTransformFlagsKHR       supportedTransforms;\n    VkSurfaceTransformFlagBitsKHR    currentTransform;\n    VkCompositeAlphaFlagsKHR         supportedCompositeAlpha;\n    VkImageUsageFlags                supportedUsageFlags;\n    VkSurfaceCounterFlagsEXT         supportedSurfaceCounters;\n} VkSurfaceCapabilities2EXT;\n\n\ntypedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceCapabilities2EXT)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilities2EXT* pSurfaceCapabilities);\n\n#ifndef VK_NO_PROTOTYPES\nVKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilities2EXT(\n    VkPhysicalDevice                            physicalDevice,\n    VkSurfaceKHR                                surface,\n    VkSurfaceCapabilities2EXT*                  pSurfaceCapabilities);\n#endif\n\n#define VK_EXT_display_control 1\n#define VK_EXT_DISPLAY_CONTROL_SPEC_VERSION 1\n#define VK_EXT_DISPLAY_CONTROL_EXTENSION_NAME \"VK_EXT_display_control\"\n\n\ntypedef enum VkDisplayPowerStateEXT {\n    VK_DISPLAY_POWER_STATE_OFF_EXT = 0,\n    VK_DISPLAY_POWER_STATE_SUSPEND_EXT = 1,\n    VK_DISPLAY_POWER_STATE_ON_EXT = 2,\n    VK_DISPLAY_POWER_STATE_BEGIN_RANGE_EXT = VK_DISPLAY_POWER_STATE_OFF_EXT,\n    VK_DISPLAY_POWER_STATE_END_RANGE_EXT = VK_DISPLAY_POWER_STATE_ON_EXT,\n    VK_DISPLAY_POWER_STATE_RANGE_SIZE_EXT = (VK_DISPLAY_POWER_STATE_ON_EXT - VK_DISPLAY_POWER_STATE_OFF_EXT + 1),\n    VK_DISPLAY_POWER_STATE_MAX_ENUM_EXT = 0x7FFFFFFF\n} VkDisplayPowerStateEXT;\n\ntypedef enum VkDeviceEventTypeEXT {\n    VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT = 0,\n    VK_DEVICE_EVENT_TYPE_BEGIN_RANGE_EXT = VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT,\n    VK_DEVICE_EVENT_TYPE_END_RANGE_EXT = VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT,\n    VK_DEVICE_EVENT_TYPE_RANGE_SIZE_EXT = (VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT - VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT + 1),\n    VK_DEVICE_EVENT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF\n} VkDeviceEventTypeEXT;\n\ntypedef enum VkDisplayEventTypeEXT {\n    VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT = 0,\n    VK_DISPLAY_EVENT_TYPE_BEGIN_RANGE_EXT = VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT,\n    VK_DISPLAY_EVENT_TYPE_END_RANGE_EXT = VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT,\n    VK_DISPLAY_EVENT_TYPE_RANGE_SIZE_EXT = (VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT - VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT + 1),\n    VK_DISPLAY_EVENT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF\n} VkDisplayEventTypeEXT;\n\ntypedef struct VkDisplayPowerInfoEXT {\n    VkStructureType           sType;\n    const void*               pNext;\n    VkDisplayPowerStateEXT    powerState;\n} VkDisplayPowerInfoEXT;\n\ntypedef struct VkDeviceEventInfoEXT {\n    VkStructureType         sType;\n    const void*             pNext;\n    VkDeviceEventTypeEXT    deviceEvent;\n} VkDeviceEventInfoEXT;\n\ntypedef struct VkDisplayEventInfoEXT {\n    VkStructureType          sType;\n    const void*              pNext;\n    VkDisplayEventTypeEXT    displayEvent;\n} VkDisplayEventInfoEXT;\n\ntypedef struct VkSwapchainCounterCreateInfoEXT {\n    VkStructureType             sType;\n    const void*                 pNext;\n    VkSurfaceCounterFlagsEXT    surfaceCounters;\n} VkSwapchainCounterCreateInfoEXT;\n\n\ntypedef VkResult (VKAPI_PTR *PFN_vkDisplayPowerControlEXT)(VkDevice device, VkDisplayKHR display, const VkDisplayPowerInfoEXT* pDisplayPowerInfo);\ntypedef VkResult (VKAPI_PTR *PFN_vkRegisterDeviceEventEXT)(VkDevice device, const VkDeviceEventInfoEXT* pDeviceEventInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence);\ntypedef VkResult (VKAPI_PTR *PFN_vkRegisterDisplayEventEXT)(VkDevice device, VkDisplayKHR display, const VkDisplayEventInfoEXT* pDisplayEventInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence);\ntypedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainCounterEXT)(VkDevice device, VkSwapchainKHR swapchain, VkSurfaceCounterFlagBitsEXT counter, uint64_t* pCounterValue);\n\n#ifndef VK_NO_PROTOTYPES\nVKAPI_ATTR VkResult VKAPI_CALL vkDisplayPowerControlEXT(\n    VkDevice                                    device,\n    VkDisplayKHR                                display,\n    const VkDisplayPowerInfoEXT*                pDisplayPowerInfo);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkRegisterDeviceEventEXT(\n    VkDevice                                    device,\n    const VkDeviceEventInfoEXT*                 pDeviceEventInfo,\n    const VkAllocationCallbacks*                pAllocator,\n    VkFence*                                    pFence);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkRegisterDisplayEventEXT(\n    VkDevice                                    device,\n    VkDisplayKHR                                display,\n    const VkDisplayEventInfoEXT*                pDisplayEventInfo,\n    const VkAllocationCallbacks*                pAllocator,\n    VkFence*                                    pFence);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainCounterEXT(\n    VkDevice                                    device,\n    VkSwapchainKHR                              swapchain,\n    VkSurfaceCounterFlagBitsEXT                 counter,\n    uint64_t*                                   pCounterValue);\n#endif\n\n#define VK_GOOGLE_display_timing 1\n#define VK_GOOGLE_DISPLAY_TIMING_SPEC_VERSION 1\n#define VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME \"VK_GOOGLE_display_timing\"\n\ntypedef struct VkRefreshCycleDurationGOOGLE {\n    uint64_t    refreshDuration;\n} VkRefreshCycleDurationGOOGLE;\n\ntypedef struct VkPastPresentationTimingGOOGLE {\n    uint32_t    presentID;\n    uint64_t    desiredPresentTime;\n    uint64_t    actualPresentTime;\n    uint64_t    earliestPresentTime;\n    uint64_t    presentMargin;\n} VkPastPresentationTimingGOOGLE;\n\ntypedef struct VkPresentTimeGOOGLE {\n    uint32_t    presentID;\n    uint64_t    desiredPresentTime;\n} VkPresentTimeGOOGLE;\n\ntypedef struct VkPresentTimesInfoGOOGLE {\n    VkStructureType               sType;\n    const void*                   pNext;\n    uint32_t                      swapchainCount;\n    const VkPresentTimeGOOGLE*    pTimes;\n} VkPresentTimesInfoGOOGLE;\n\n\ntypedef VkResult (VKAPI_PTR *PFN_vkGetRefreshCycleDurationGOOGLE)(VkDevice device, VkSwapchainKHR swapchain, VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties);\ntypedef VkResult (VKAPI_PTR *PFN_vkGetPastPresentationTimingGOOGLE)(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pPresentationTimingCount, VkPastPresentationTimingGOOGLE* pPresentationTimings);\n\n#ifndef VK_NO_PROTOTYPES\nVKAPI_ATTR VkResult VKAPI_CALL vkGetRefreshCycleDurationGOOGLE(\n    VkDevice                                    device,\n    VkSwapchainKHR                              swapchain,\n    VkRefreshCycleDurationGOOGLE*               pDisplayTimingProperties);\n\nVKAPI_ATTR VkResult VKAPI_CALL vkGetPastPresentationTimingGOOGLE(\n    VkDevice                                    device,\n    VkSwapchainKHR                              swapchain,\n    uint32_t*                                   pPresentationTimingCount,\n    VkPastPresentationTimingGOOGLE*             pPresentationTimings);\n#endif\n\n#define VK_NV_sample_mask_override_coverage 1\n#define VK_NV_SAMPLE_MASK_OVERRIDE_COVERAGE_SPEC_VERSION 1\n#define VK_NV_SAMPLE_MASK_OVERRIDE_COVERAGE_EXTENSION_NAME \"VK_NV_sample_mask_override_coverage\"\n\n\n#define VK_NV_geometry_shader_passthrough 1\n#define VK_NV_GEOMETRY_SHADER_PASSTHROUGH_SPEC_VERSION 1\n#define VK_NV_GEOMETRY_SHADER_PASSTHROUGH_EXTENSION_NAME \"VK_NV_geometry_shader_passthrough\"\n\n\n#define VK_NV_viewport_array2 1\n#define VK_NV_VIEWPORT_ARRAY2_SPEC_VERSION 1\n#define VK_NV_VIEWPORT_ARRAY2_EXTENSION_NAME \"VK_NV_viewport_array2\"\n\n\n#define VK_NVX_multiview_per_view_attributes 1\n#define VK_NVX_MULTIVIEW_PER_VIEW_ATTRIBUTES_SPEC_VERSION 1\n#define VK_NVX_MULTIVIEW_PER_VIEW_ATTRIBUTES_EXTENSION_NAME \"VK_NVX_multiview_per_view_attributes\"\n\ntypedef struct VkPhysicalDeviceMultiviewPerViewAttributesPropertiesNVX {\n    VkStructureType    sType;\n    void*              pNext;\n    VkBool32           perViewPositionAllComponents;\n} VkPhysicalDeviceMultiviewPerViewAttributesPropertiesNVX;\n\n\n\n#define VK_NV_viewport_swizzle 1\n#define VK_NV_VIEWPORT_SWIZZLE_SPEC_VERSION 1\n#define VK_NV_VIEWPORT_SWIZZLE_EXTENSION_NAME \"VK_NV_viewport_swizzle\"\n\n\ntypedef enum VkViewportCoordinateSwizzleNV {\n    VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_X_NV = 0,\n    VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_X_NV = 1,\n    VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Y_NV = 2,\n    VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_Y_NV = 3,\n    VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Z_NV = 4,\n    VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_Z_NV = 5,\n    VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_W_NV = 6,\n    VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV = 7,\n    VK_VIEWPORT_COORDINATE_SWIZZLE_BEGIN_RANGE_NV = VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_X_NV,\n    VK_VIEWPORT_COORDINATE_SWIZZLE_END_RANGE_NV = VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV,\n    VK_VIEWPORT_COORDINATE_SWIZZLE_RANGE_SIZE_NV = (VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV - VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_X_NV + 1),\n    VK_VIEWPORT_COORDINATE_SWIZZLE_MAX_ENUM_NV = 0x7FFFFFFF\n} VkViewportCoordinateSwizzleNV;\n\ntypedef VkFlags VkPipelineViewportSwizzleStateCreateFlagsNV;\n\ntypedef struct VkViewportSwizzleNV {\n    VkViewportCoordinateSwizzleNV    x;\n    VkViewportCoordinateSwizzleNV    y;\n    VkViewportCoordinateSwizzleNV    z;\n    VkViewportCoordinateSwizzleNV    w;\n} VkViewportSwizzleNV;\n\ntypedef struct VkPipelineViewportSwizzleStateCreateInfoNV {\n    VkStructureType                                sType;\n    const void*                                    pNext;\n    VkPipelineViewportSwizzleStateCreateFlagsNV    flags;\n    uint32_t                                       viewportCount;\n    const VkViewportSwizzleNV*                     pViewportSwizzles;\n} VkPipelineViewportSwizzleStateCreateInfoNV;\n\n\n\n#define VK_EXT_discard_rectangles 1\n#define VK_EXT_DISCARD_RECTANGLES_SPEC_VERSION 1\n#define VK_EXT_DISCARD_RECTANGLES_EXTENSION_NAME \"VK_EXT_discard_rectangles\"\n\n\ntypedef enum VkDiscardRectangleModeEXT {\n    VK_DISCARD_RECTANGLE_MODE_INCLUSIVE_EXT = 0,\n    VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT = 1,\n    VK_DISCARD_RECTANGLE_MODE_BEGIN_RANGE_EXT = VK_DISCARD_RECTANGLE_MODE_INCLUSIVE_EXT,\n    VK_DISCARD_RECTANGLE_MODE_END_RANGE_EXT = VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT,\n    VK_DISCARD_RECTANGLE_MODE_RANGE_SIZE_EXT = (VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT - VK_DISCARD_RECTANGLE_MODE_INCLUSIVE_EXT + 1),\n    VK_DISCARD_RECTANGLE_MODE_MAX_ENUM_EXT = 0x7FFFFFFF\n} VkDiscardRectangleModeEXT;\n\ntypedef VkFlags VkPipelineDiscardRectangleStateCreateFlagsEXT;\n\ntypedef struct VkPhysicalDeviceDiscardRectanglePropertiesEXT {\n    VkStructureType    sType;\n    void*              pNext;\n    uint32_t           maxDiscardRectangles;\n} VkPhysicalDeviceDiscardRectanglePropertiesEXT;\n\ntypedef struct VkPipelineDiscardRectangleStateCreateInfoEXT {\n    VkStructureType                                  sType;\n    const void*                                      pNext;\n    VkPipelineDiscardRectangleStateCreateFlagsEXT    flags;\n    VkDiscardRectangleModeEXT                        discardRectangleMode;\n    uint32_t                                         discardRectangleCount;\n    const VkRect2D*                                  pDiscardRectangles;\n} VkPipelineDiscardRectangleStateCreateInfoEXT;\n\n\ntypedef void (VKAPI_PTR *PFN_vkCmdSetDiscardRectangleEXT)(VkCommandBuffer commandBuffer, uint32_t firstDiscardRectangle, uint32_t discardRectangleCount, const VkRect2D* pDiscardRectangles);\n\n#ifndef VK_NO_PROTOTYPES\nVKAPI_ATTR void VKAPI_CALL vkCmdSetDiscardRectangleEXT(\n    VkCommandBuffer                             commandBuffer,\n    uint32_t                                    firstDiscardRectangle,\n    uint32_t                                    discardRectangleCount,\n    const VkRect2D*                             pDiscardRectangles);\n#endif\n\n#define VK_EXT_swapchain_colorspace 1\n#define VK_EXT_SWAPCHAIN_COLOR_SPACE_SPEC_VERSION 2\n#define VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME \"VK_EXT_swapchain_colorspace\"\n\n\n#define VK_EXT_hdr_metadata 1\n#define VK_EXT_HDR_METADATA_SPEC_VERSION  1\n#define VK_EXT_HDR_METADATA_EXTENSION_NAME \"VK_EXT_hdr_metadata\"\n\ntypedef struct VkXYColorEXT {\n    float    x;\n    float    y;\n} VkXYColorEXT;\n\ntypedef struct VkHdrMetadataEXT {\n    VkStructureType    sType;\n    const void*        pNext;\n    VkXYColorEXT       displayPrimaryRed;\n    VkXYColorEXT       displayPrimaryGreen;\n    VkXYColorEXT       displayPrimaryBlue;\n    VkXYColorEXT       whitePoint;\n    float              maxLuminance;\n    float              minLuminance;\n    float              maxContentLightLevel;\n    float              maxFrameAverageLightLevel;\n} VkHdrMetadataEXT;\n\n\ntypedef void (VKAPI_PTR *PFN_vkSetHdrMetadataEXT)(VkDevice device, uint32_t swapchainCount, const VkSwapchainKHR* pSwapchains, const VkHdrMetadataEXT* pMetadata);\n\n#ifndef VK_NO_PROTOTYPES\nVKAPI_ATTR void VKAPI_CALL vkSetHdrMetadataEXT(\n    VkDevice                                    device,\n    uint32_t                                    swapchainCount,\n    const VkSwapchainKHR*                       pSwapchains,\n    const VkHdrMetadataEXT*                     pMetadata);\n#endif\n\n#ifdef VK_USE_PLATFORM_IOS_MVK\n#define VK_MVK_ios_surface 1\n#define VK_MVK_IOS_SURFACE_SPEC_VERSION   2\n#define VK_MVK_IOS_SURFACE_EXTENSION_NAME \"VK_MVK_ios_surface\"\n\ntypedef VkFlags VkIOSSurfaceCreateFlagsMVK;\n\ntypedef struct VkIOSSurfaceCreateInfoMVK {\n    VkStructureType               sType;\n    const void*                   pNext;\n    VkIOSSurfaceCreateFlagsMVK    flags;\n    const void*                   pView;\n} VkIOSSurfaceCreateInfoMVK;\n\n\ntypedef VkResult (VKAPI_PTR *PFN_vkCreateIOSSurfaceMVK)(VkInstance instance, const VkIOSSurfaceCreateInfoMVK* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);\n\n#ifndef VK_NO_PROTOTYPES\nVKAPI_ATTR VkResult VKAPI_CALL vkCreateIOSSurfaceMVK(\n    VkInstance                                  instance,\n    const VkIOSSurfaceCreateInfoMVK*            pCreateInfo,\n    const VkAllocationCallbacks*                pAllocator,\n    VkSurfaceKHR*                               pSurface);\n#endif\n#endif /* VK_USE_PLATFORM_IOS_MVK */\n\n#ifdef VK_USE_PLATFORM_MACOS_MVK\n#define VK_MVK_macos_surface 1\n#define VK_MVK_MACOS_SURFACE_SPEC_VERSION 2\n#define VK_MVK_MACOS_SURFACE_EXTENSION_NAME \"VK_MVK_macos_surface\"\n\ntypedef VkFlags VkMacOSSurfaceCreateFlagsMVK;\n\ntypedef struct VkMacOSSurfaceCreateInfoMVK {\n    VkStructureType                 sType;\n    const void*                     pNext;\n    VkMacOSSurfaceCreateFlagsMVK    flags;\n    const void*                     pView;\n} VkMacOSSurfaceCreateInfoMVK;\n\n\ntypedef VkResult (VKAPI_PTR *PFN_vkCreateMacOSSurfaceMVK)(VkInstance instance, const VkMacOSSurfaceCreateInfoMVK* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);\n\n#ifndef VK_NO_PROTOTYPES\nVKAPI_ATTR VkResult VKAPI_CALL vkCreateMacOSSurfaceMVK(\n    VkInstance                                  instance,\n    const VkMacOSSurfaceCreateInfoMVK*          pCreateInfo,\n    const VkAllocationCallbacks*                pAllocator,\n    VkSurfaceKHR*                               pSurface);\n#endif\n#endif /* VK_USE_PLATFORM_MACOS_MVK */\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "src/engine/renderer/vulkan/vulkan.hpp",
    "content": "// Copyright (c) 2015-2017 The Khronos Group Inc.\n// \n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and/or associated documentation files (the\n// \"Materials\"), to deal in the Materials without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Materials, and to\n// permit persons to whom the Materials are furnished to do so, subject to\n// the following conditions:\n// \n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Materials.\n// \n// THE MATERIALS ARE PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.\n\n// This header is generated from the Khronos Vulkan XML API Registry.\n\n\n#ifndef VULKAN_HPP\n#define VULKAN_HPP\n\n#include <algorithm>\n#include <array>\n#include <cassert>\n#include <cstddef>\n#include <cstdint>\n#include <cstring>\n#include <initializer_list>\n#include <string>\n#include <system_error>\n#include <tuple>\n#include <type_traits>\n#include <vulkan/vulkan.h>\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n# include <memory>\n# include <vector>\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\nstatic_assert( VK_HEADER_VERSION ==  49 , \"Wrong VK_HEADER_VERSION!\" );\n\n// 32-bit vulkan is not typesafe for handles, so don't allow copy constructors on this platform by default.\n// To enable this feature on 32-bit platforms please define VULKAN_HPP_TYPESAFE_CONVERSION\n#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)\n# if !defined( VULKAN_HPP_TYPESAFE_CONVERSION )\n#  define VULKAN_HPP_TYPESAFE_CONVERSION\n# endif\n#endif\n\n#if !defined(VULKAN_HPP_HAS_UNRESTRICTED_UNIONS)\n# if defined(__clang__)\n#  if __has_feature(cxx_unrestricted_unions)\n#   define VULKAN_HPP_HAS_UNRESTRICTED_UNIONS\n#  endif\n# elif defined(__GNUC__)\n#  define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)\n#  if 40600 <= GCC_VERSION\n#   define VULKAN_HPP_HAS_UNRESTRICTED_UNIONS\n#  endif\n# elif defined(_MSC_VER)\n#  if 1900 <= _MSC_VER\n#   define VULKAN_HPP_HAS_UNRESTRICTED_UNIONS\n#  endif\n# endif\n#endif\n\n#if !defined(VULKAN_HPP_INLINE)\n# if defined(__clang___)\n#  if __has_attribute(always_inline)\n#   define VULKAN_HPP_INLINE __attribute__((always_inline)) __inline__\n#  else\n#    define VULKAN_HPP_INLINE inline\n#  endif\n# elif defined(__GNUC__)\n#  define VULKAN_HPP_INLINE __attribute__((always_inline)) __inline__\n# elif defined(_MSC_VER)\n#  define VULKAN_HPP_INLINE __forceinline\n# else\n#  define VULKAN_HPP_INLINE inline\n# endif\n#endif\n\n#if defined(VULKAN_HPP_TYPESAFE_CONVERSION)\n# define VULKAN_HPP_TYPESAFE_EXPLICIT\n#else\n# define VULKAN_HPP_TYPESAFE_EXPLICIT explicit\n#endif\n\nnamespace vk\n{\n  template <typename FlagBitsType> struct FlagTraits\n  {\n    enum { allFlags = 0 };\n  };\n\n  template <typename BitType, typename MaskType = VkFlags>\n  class Flags\n  {\n  public:\n    Flags()\n      : m_mask(0)\n    {\n    }\n\n    Flags(BitType bit)\n      : m_mask(static_cast<MaskType>(bit))\n    {\n    }\n\n    Flags(Flags<BitType> const& rhs)\n      : m_mask(rhs.m_mask)\n    {\n    }\n\n    Flags<BitType> & operator=(Flags<BitType> const& rhs)\n    {\n      m_mask = rhs.m_mask;\n      return *this;\n    }\n\n    Flags<BitType> & operator|=(Flags<BitType> const& rhs)\n    {\n      m_mask |= rhs.m_mask;\n      return *this;\n    }\n\n    Flags<BitType> & operator&=(Flags<BitType> const& rhs)\n    {\n      m_mask &= rhs.m_mask;\n      return *this;\n    }\n\n    Flags<BitType> & operator^=(Flags<BitType> const& rhs)\n    {\n      m_mask ^= rhs.m_mask;\n      return *this;\n    }\n\n    Flags<BitType> operator|(Flags<BitType> const& rhs) const\n    {\n      Flags<BitType> result(*this);\n      result |= rhs;\n      return result;\n    }\n\n    Flags<BitType> operator&(Flags<BitType> const& rhs) const\n    {\n      Flags<BitType> result(*this);\n      result &= rhs;\n      return result;\n    }\n\n    Flags<BitType> operator^(Flags<BitType> const& rhs) const\n    {\n      Flags<BitType> result(*this);\n      result ^= rhs;\n      return result;\n    }\n\n    bool operator!() const\n    {\n      return !m_mask;\n    }\n\n    Flags<BitType> operator~() const\n    {\n      Flags<BitType> result(*this);\n      result.m_mask ^= FlagTraits<BitType>::allFlags;\n      return result;\n    }\n\n    bool operator==(Flags<BitType> const& rhs) const\n    {\n      return m_mask == rhs.m_mask;\n    }\n\n    bool operator!=(Flags<BitType> const& rhs) const\n    {\n      return m_mask != rhs.m_mask;\n    }\n\n    explicit operator bool() const\n    {\n      return !!m_mask;\n    }\n\n    explicit operator MaskType() const\n    {\n        return m_mask;\n    }\n\n  private:\n    MaskType  m_mask;\n  };\n  \n  template <typename BitType>\n  Flags<BitType> operator|(BitType bit, Flags<BitType> const& flags)\n  {\n    return flags | bit;\n  }\n  \n  template <typename BitType>\n  Flags<BitType> operator&(BitType bit, Flags<BitType> const& flags)\n  {\n    return flags & bit;\n  }\n  \n  template <typename BitType>\n  Flags<BitType> operator^(BitType bit, Flags<BitType> const& flags)\n  {\n    return flags ^ bit;\n  }\n\n\n  template <typename RefType>\n  class Optional\n  {\n  public:\n    Optional(RefType & reference) { m_ptr = &reference; }\n    Optional(RefType * ptr) { m_ptr = ptr; }\n    Optional(std::nullptr_t) { m_ptr = nullptr; }\n\n    operator RefType*() const { return m_ptr; }\n    RefType const* operator->() const { return m_ptr; }\n    explicit operator bool() const { return !!m_ptr; }\n\n  private:\n    RefType *m_ptr;\n  };\n\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  template <typename T>\n  class ArrayProxy\n  {\n  public:\n    ArrayProxy(std::nullptr_t)\n      : m_count(0)\n      , m_ptr(nullptr)\n    {}\n\n    ArrayProxy(T & ptr)\n      : m_count(1)\n      , m_ptr(&ptr)\n    {}\n\n    ArrayProxy(uint32_t count, T * ptr)\n      : m_count(count)\n      , m_ptr(ptr)\n    {}\n\n    template <size_t N>\n    ArrayProxy(std::array<typename std::remove_const<T>::type, N> & data)\n      : m_count(N)\n      , m_ptr(data.data())\n    {}\n\n    template <size_t N>\n    ArrayProxy(std::array<typename std::remove_const<T>::type, N> const& data)\n      : m_count(N)\n      , m_ptr(data.data())\n    {}\n\n    template <class Allocator = std::allocator<typename std::remove_const<T>::type>>\n    ArrayProxy(std::vector<typename std::remove_const<T>::type, Allocator> & data)\n      : m_count(static_cast<uint32_t>(data.size()))\n      , m_ptr(data.data())\n    {}\n\n    template <class Allocator = std::allocator<typename std::remove_const<T>::type>>\n    ArrayProxy(std::vector<typename std::remove_const<T>::type, Allocator> const& data)\n      : m_count(static_cast<uint32_t>(data.size()))\n      , m_ptr(data.data())\n    {}\n\n    ArrayProxy(std::initializer_list<T> const& data)\n      : m_count(static_cast<uint32_t>(data.end() - data.begin()))\n      , m_ptr(data.begin())\n    {}\n\n    const T * begin() const\n    {\n      return m_ptr;\n    }\n\n    const T * end() const\n    {\n      return m_ptr + m_count;\n    }\n\n    const T & front() const\n    {\n      assert(m_count && m_ptr);\n      return *m_ptr;\n    }\n\n    const T & back() const\n    {\n      assert(m_count && m_ptr);\n      return *(m_ptr + m_count - 1);\n    }\n\n    bool empty() const\n    {\n      return (m_count == 0);\n    }\n\n    uint32_t size() const\n    {\n      return m_count;\n    }\n\n    T * data() const\n    {\n      return m_ptr;\n    }\n\n  private:\n    uint32_t  m_count;\n    T *       m_ptr;\n  };\n#endif\n\n\n#if defined(VULKAN_HPP_NO_EXCEPTIONS) && !defined(VULKAN_HPP_NO_SMART_HANDLE)\n#  define VULKAN_HPP_NO_SMART_HANDLE\n#endif\n\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  template <typename Type, typename Deleter>\n  class UniqueHandle\n  {\n  public:\n    explicit UniqueHandle( Type const& value = Type(), Deleter const& deleter = Deleter() )\n      : m_value( value )\n      , m_deleter( deleter )\n    {}\n\n    UniqueHandle( UniqueHandle const& ) = delete;\n\n    UniqueHandle( UniqueHandle && other )\n      : m_value( other.release() )\n      , m_deleter( std::move( other.m_deleter ) )\n    {}\n\n    ~UniqueHandle()\n    {\n      destroy();\n    }\n\n    UniqueHandle & operator=( UniqueHandle const& ) = delete;\n\n    UniqueHandle & operator=( UniqueHandle && other )\n    {\n      reset( other.release() );\n      m_deleter = std::move( other.m_deleter );\n      return *this;\n    }\n\n    explicit operator bool() const\n    {\n      return m_value.operator bool();\n    }\n\n    Type const* operator->() const\n    {\n      return &m_value;\n    }\n\n    Type const& operator*() const\n    {\n      return m_value;\n    }\n\n    Type get() const\n    {\n      return m_value;\n    }\n\n    Deleter & getDeleter()\n    {\n      return m_deleter;\n    }\n\n    Deleter const& getDeleter() const\n    {\n      return m_deleter;\n    }\n\n    void reset( Type const& value = Type() )\n    {\n      if ( m_value != value )\n      {\n        destroy();\n        m_value = value;\n      }\n    }\n\n    Type release()\n    {\n      Type value = m_value;\n      m_value = nullptr;\n      return value;\n    }\n\n    void swap( UniqueHandle<Type, Deleter> & rhs )\n    {\n      std::swap(m_value, rhs.m_value);\n      std::swap(m_deleter, rhs.m_deleter);\n    }\n\n  private:\n    void destroy()\n    {\n      if ( m_value )\n      {\n        m_deleter( m_value );\n      }\n    }\n\n  private:\n    Type    m_value;\n    Deleter m_deleter;\n  };\n\n  template <typename Type, typename Deleter>\n  VULKAN_HPP_INLINE void swap( UniqueHandle<Type,Deleter> & lhs, UniqueHandle<Type,Deleter> & rhs )\n  {\n    lhs.swap( rhs );\n  }\n#endif\n\n  enum class Result\n  {\n    eSuccess = VK_SUCCESS,\n    eNotReady = VK_NOT_READY,\n    eTimeout = VK_TIMEOUT,\n    eEventSet = VK_EVENT_SET,\n    eEventReset = VK_EVENT_RESET,\n    eIncomplete = VK_INCOMPLETE,\n    eErrorOutOfHostMemory = VK_ERROR_OUT_OF_HOST_MEMORY,\n    eErrorOutOfDeviceMemory = VK_ERROR_OUT_OF_DEVICE_MEMORY,\n    eErrorInitializationFailed = VK_ERROR_INITIALIZATION_FAILED,\n    eErrorDeviceLost = VK_ERROR_DEVICE_LOST,\n    eErrorMemoryMapFailed = VK_ERROR_MEMORY_MAP_FAILED,\n    eErrorLayerNotPresent = VK_ERROR_LAYER_NOT_PRESENT,\n    eErrorExtensionNotPresent = VK_ERROR_EXTENSION_NOT_PRESENT,\n    eErrorFeatureNotPresent = VK_ERROR_FEATURE_NOT_PRESENT,\n    eErrorIncompatibleDriver = VK_ERROR_INCOMPATIBLE_DRIVER,\n    eErrorTooManyObjects = VK_ERROR_TOO_MANY_OBJECTS,\n    eErrorFormatNotSupported = VK_ERROR_FORMAT_NOT_SUPPORTED,\n    eErrorFragmentedPool = VK_ERROR_FRAGMENTED_POOL,\n    eErrorSurfaceLostKHR = VK_ERROR_SURFACE_LOST_KHR,\n    eErrorNativeWindowInUseKHR = VK_ERROR_NATIVE_WINDOW_IN_USE_KHR,\n    eSuboptimalKHR = VK_SUBOPTIMAL_KHR,\n    eErrorOutOfDateKHR = VK_ERROR_OUT_OF_DATE_KHR,\n    eErrorIncompatibleDisplayKHR = VK_ERROR_INCOMPATIBLE_DISPLAY_KHR,\n    eErrorValidationFailedEXT = VK_ERROR_VALIDATION_FAILED_EXT,\n    eErrorInvalidShaderNV = VK_ERROR_INVALID_SHADER_NV,\n    eErrorOutOfPoolMemoryKHR = VK_ERROR_OUT_OF_POOL_MEMORY_KHR,\n    eErrorInvalidExternalHandleKHX = VK_ERROR_INVALID_EXTERNAL_HANDLE_KHX\n  };\n\n  VULKAN_HPP_INLINE std::string to_string(Result value)\n  {\n    switch (value)\n    {\n    case Result::eSuccess: return \"Success\";\n    case Result::eNotReady: return \"NotReady\";\n    case Result::eTimeout: return \"Timeout\";\n    case Result::eEventSet: return \"EventSet\";\n    case Result::eEventReset: return \"EventReset\";\n    case Result::eIncomplete: return \"Incomplete\";\n    case Result::eErrorOutOfHostMemory: return \"ErrorOutOfHostMemory\";\n    case Result::eErrorOutOfDeviceMemory: return \"ErrorOutOfDeviceMemory\";\n    case Result::eErrorInitializationFailed: return \"ErrorInitializationFailed\";\n    case Result::eErrorDeviceLost: return \"ErrorDeviceLost\";\n    case Result::eErrorMemoryMapFailed: return \"ErrorMemoryMapFailed\";\n    case Result::eErrorLayerNotPresent: return \"ErrorLayerNotPresent\";\n    case Result::eErrorExtensionNotPresent: return \"ErrorExtensionNotPresent\";\n    case Result::eErrorFeatureNotPresent: return \"ErrorFeatureNotPresent\";\n    case Result::eErrorIncompatibleDriver: return \"ErrorIncompatibleDriver\";\n    case Result::eErrorTooManyObjects: return \"ErrorTooManyObjects\";\n    case Result::eErrorFormatNotSupported: return \"ErrorFormatNotSupported\";\n    case Result::eErrorFragmentedPool: return \"ErrorFragmentedPool\";\n    case Result::eErrorSurfaceLostKHR: return \"ErrorSurfaceLostKHR\";\n    case Result::eErrorNativeWindowInUseKHR: return \"ErrorNativeWindowInUseKHR\";\n    case Result::eSuboptimalKHR: return \"SuboptimalKHR\";\n    case Result::eErrorOutOfDateKHR: return \"ErrorOutOfDateKHR\";\n    case Result::eErrorIncompatibleDisplayKHR: return \"ErrorIncompatibleDisplayKHR\";\n    case Result::eErrorValidationFailedEXT: return \"ErrorValidationFailedEXT\";\n    case Result::eErrorInvalidShaderNV: return \"ErrorInvalidShaderNV\";\n    case Result::eErrorOutOfPoolMemoryKHR: return \"ErrorOutOfPoolMemoryKHR\";\n    case Result::eErrorInvalidExternalHandleKHX: return \"ErrorInvalidExternalHandleKHX\";\n    default: return \"invalid\";\n    }\n  }\n\n#if defined(_MSC_VER) && (_MSC_VER == 1800)\n# define noexcept _NOEXCEPT\n#endif\n\n  class ErrorCategoryImpl : public std::error_category\n  {\n    public:\n    virtual const char* name() const noexcept override { return \"vk::Result\"; }\n    virtual std::string message(int ev) const override { return to_string(static_cast<Result>(ev)); }\n  };\n\n#if defined(_MSC_VER) && (_MSC_VER == 1800)\n# undef noexcept\n#endif\n\n  VULKAN_HPP_INLINE const std::error_category& errorCategory()\n  {\n    static ErrorCategoryImpl instance;\n    return instance;\n  }\n\n  VULKAN_HPP_INLINE std::error_code make_error_code(Result e)\n  {\n    return std::error_code(static_cast<int>(e), errorCategory());\n  }\n\n  VULKAN_HPP_INLINE std::error_condition make_error_condition(Result e)\n  {\n    return std::error_condition(static_cast<int>(e), errorCategory());\n  }\n\n} // namespace vk\n\nnamespace std\n{\n  template <>\n  struct is_error_code_enum<vk::Result> : public true_type\n  {};\n}\n\nnamespace vk\n{\n  template <typename T>\n  struct ResultValue\n  {\n    ResultValue( Result r, T & v )\n      : result( r )\n      , value( v )\n    {}\n\n    Result  result;\n    T       value;\n\n    operator std::tuple<Result&, T&>() { return std::tuple<Result&, T&>(result, value); }\n  };\n\n  template <typename T>\n  struct ResultValueType\n  {\n#ifdef VULKAN_HPP_NO_EXCEPTIONS\n    typedef ResultValue<T>  type;\n#else\n    typedef T              type;\n#endif\n  };\n\n  template <>  struct ResultValueType<void>\n  {\n#ifdef VULKAN_HPP_NO_EXCEPTIONS\n    typedef Result type;\n#else\n    typedef void   type;\n#endif\n  };\n\n  VULKAN_HPP_INLINE ResultValueType<void>::type createResultValue( Result result, char const * message )\n  {\n#ifdef VULKAN_HPP_NO_EXCEPTIONS\n    assert( result == Result::eSuccess );\n    return result;\n#else\n    if ( result != Result::eSuccess )\n    {\n      throw std::system_error( result, message );\n    }\n#endif\n  }\n\n  template <typename T>\n  VULKAN_HPP_INLINE typename ResultValueType<T>::type createResultValue( Result result, T & data, char const * message )\n  {\n#ifdef VULKAN_HPP_NO_EXCEPTIONS\n    assert( result == Result::eSuccess );\n    return ResultValue<T>( result, data );\n#else\n    if ( result != Result::eSuccess )\n    {\n      throw std::system_error( result, message );\n    }\n    return data;\n#endif\n  }\n\n  VULKAN_HPP_INLINE Result createResultValue( Result result, char const * message, std::initializer_list<Result> successCodes )\n  {\n#ifdef VULKAN_HPP_NO_EXCEPTIONS\n    assert( std::find( successCodes.begin(), successCodes.end(), result ) != successCodes.end() );\n#else\n    if ( std::find( successCodes.begin(), successCodes.end(), result ) == successCodes.end() )\n    {\n      throw std::system_error( result, message );\n    }\n#endif\n    return result;\n  }\n\n  template <typename T>\n  VULKAN_HPP_INLINE ResultValue<T> createResultValue( Result result, T & data, char const * message, std::initializer_list<Result> successCodes )\n  {\n#ifdef VULKAN_HPP_NO_EXCEPTIONS\n    assert( std::find( successCodes.begin(), successCodes.end(), result ) != successCodes.end() );\n#else\n    if ( std::find( successCodes.begin(), successCodes.end(), result ) == successCodes.end() )\n    {\n      throw std::system_error( result, message );\n    }\n#endif\n    return ResultValue<T>( result, data );\n  }\n\n  using SampleMask = uint32_t;\n\n  using Bool32 = uint32_t;\n\n  using DeviceSize = uint64_t;\n\n  enum class FramebufferCreateFlagBits\n  {\n  };\n\n  using FramebufferCreateFlags = Flags<FramebufferCreateFlagBits, VkFramebufferCreateFlags>;\n\n  VULKAN_HPP_INLINE FramebufferCreateFlags operator|( FramebufferCreateFlagBits bit0, FramebufferCreateFlagBits bit1 )\n  {\n    return FramebufferCreateFlags( bit0 ) | bit1;\n  }\n\n  enum class QueryPoolCreateFlagBits\n  {\n  };\n\n  using QueryPoolCreateFlags = Flags<QueryPoolCreateFlagBits, VkQueryPoolCreateFlags>;\n\n  VULKAN_HPP_INLINE QueryPoolCreateFlags operator|( QueryPoolCreateFlagBits bit0, QueryPoolCreateFlagBits bit1 )\n  {\n    return QueryPoolCreateFlags( bit0 ) | bit1;\n  }\n\n  enum class RenderPassCreateFlagBits\n  {\n  };\n\n  using RenderPassCreateFlags = Flags<RenderPassCreateFlagBits, VkRenderPassCreateFlags>;\n\n  VULKAN_HPP_INLINE RenderPassCreateFlags operator|( RenderPassCreateFlagBits bit0, RenderPassCreateFlagBits bit1 )\n  {\n    return RenderPassCreateFlags( bit0 ) | bit1;\n  }\n\n  enum class SamplerCreateFlagBits\n  {\n  };\n\n  using SamplerCreateFlags = Flags<SamplerCreateFlagBits, VkSamplerCreateFlags>;\n\n  VULKAN_HPP_INLINE SamplerCreateFlags operator|( SamplerCreateFlagBits bit0, SamplerCreateFlagBits bit1 )\n  {\n    return SamplerCreateFlags( bit0 ) | bit1;\n  }\n\n  enum class PipelineLayoutCreateFlagBits\n  {\n  };\n\n  using PipelineLayoutCreateFlags = Flags<PipelineLayoutCreateFlagBits, VkPipelineLayoutCreateFlags>;\n\n  VULKAN_HPP_INLINE PipelineLayoutCreateFlags operator|( PipelineLayoutCreateFlagBits bit0, PipelineLayoutCreateFlagBits bit1 )\n  {\n    return PipelineLayoutCreateFlags( bit0 ) | bit1;\n  }\n\n  enum class PipelineCacheCreateFlagBits\n  {\n  };\n\n  using PipelineCacheCreateFlags = Flags<PipelineCacheCreateFlagBits, VkPipelineCacheCreateFlags>;\n\n  VULKAN_HPP_INLINE PipelineCacheCreateFlags operator|( PipelineCacheCreateFlagBits bit0, PipelineCacheCreateFlagBits bit1 )\n  {\n    return PipelineCacheCreateFlags( bit0 ) | bit1;\n  }\n\n  enum class PipelineDepthStencilStateCreateFlagBits\n  {\n  };\n\n  using PipelineDepthStencilStateCreateFlags = Flags<PipelineDepthStencilStateCreateFlagBits, VkPipelineDepthStencilStateCreateFlags>;\n\n  VULKAN_HPP_INLINE PipelineDepthStencilStateCreateFlags operator|( PipelineDepthStencilStateCreateFlagBits bit0, PipelineDepthStencilStateCreateFlagBits bit1 )\n  {\n    return PipelineDepthStencilStateCreateFlags( bit0 ) | bit1;\n  }\n\n  enum class PipelineDynamicStateCreateFlagBits\n  {\n  };\n\n  using PipelineDynamicStateCreateFlags = Flags<PipelineDynamicStateCreateFlagBits, VkPipelineDynamicStateCreateFlags>;\n\n  VULKAN_HPP_INLINE PipelineDynamicStateCreateFlags operator|( PipelineDynamicStateCreateFlagBits bit0, PipelineDynamicStateCreateFlagBits bit1 )\n  {\n    return PipelineDynamicStateCreateFlags( bit0 ) | bit1;\n  }\n\n  enum class PipelineColorBlendStateCreateFlagBits\n  {\n  };\n\n  using PipelineColorBlendStateCreateFlags = Flags<PipelineColorBlendStateCreateFlagBits, VkPipelineColorBlendStateCreateFlags>;\n\n  VULKAN_HPP_INLINE PipelineColorBlendStateCreateFlags operator|( PipelineColorBlendStateCreateFlagBits bit0, PipelineColorBlendStateCreateFlagBits bit1 )\n  {\n    return PipelineColorBlendStateCreateFlags( bit0 ) | bit1;\n  }\n\n  enum class PipelineMultisampleStateCreateFlagBits\n  {\n  };\n\n  using PipelineMultisampleStateCreateFlags = Flags<PipelineMultisampleStateCreateFlagBits, VkPipelineMultisampleStateCreateFlags>;\n\n  VULKAN_HPP_INLINE PipelineMultisampleStateCreateFlags operator|( PipelineMultisampleStateCreateFlagBits bit0, PipelineMultisampleStateCreateFlagBits bit1 )\n  {\n    return PipelineMultisampleStateCreateFlags( bit0 ) | bit1;\n  }\n\n  enum class PipelineRasterizationStateCreateFlagBits\n  {\n  };\n\n  using PipelineRasterizationStateCreateFlags = Flags<PipelineRasterizationStateCreateFlagBits, VkPipelineRasterizationStateCreateFlags>;\n\n  VULKAN_HPP_INLINE PipelineRasterizationStateCreateFlags operator|( PipelineRasterizationStateCreateFlagBits bit0, PipelineRasterizationStateCreateFlagBits bit1 )\n  {\n    return PipelineRasterizationStateCreateFlags( bit0 ) | bit1;\n  }\n\n  enum class PipelineViewportStateCreateFlagBits\n  {\n  };\n\n  using PipelineViewportStateCreateFlags = Flags<PipelineViewportStateCreateFlagBits, VkPipelineViewportStateCreateFlags>;\n\n  VULKAN_HPP_INLINE PipelineViewportStateCreateFlags operator|( PipelineViewportStateCreateFlagBits bit0, PipelineViewportStateCreateFlagBits bit1 )\n  {\n    return PipelineViewportStateCreateFlags( bit0 ) | bit1;\n  }\n\n  enum class PipelineTessellationStateCreateFlagBits\n  {\n  };\n\n  using PipelineTessellationStateCreateFlags = Flags<PipelineTessellationStateCreateFlagBits, VkPipelineTessellationStateCreateFlags>;\n\n  VULKAN_HPP_INLINE PipelineTessellationStateCreateFlags operator|( PipelineTessellationStateCreateFlagBits bit0, PipelineTessellationStateCreateFlagBits bit1 )\n  {\n    return PipelineTessellationStateCreateFlags( bit0 ) | bit1;\n  }\n\n  enum class PipelineInputAssemblyStateCreateFlagBits\n  {\n  };\n\n  using PipelineInputAssemblyStateCreateFlags = Flags<PipelineInputAssemblyStateCreateFlagBits, VkPipelineInputAssemblyStateCreateFlags>;\n\n  VULKAN_HPP_INLINE PipelineInputAssemblyStateCreateFlags operator|( PipelineInputAssemblyStateCreateFlagBits bit0, PipelineInputAssemblyStateCreateFlagBits bit1 )\n  {\n    return PipelineInputAssemblyStateCreateFlags( bit0 ) | bit1;\n  }\n\n  enum class PipelineVertexInputStateCreateFlagBits\n  {\n  };\n\n  using PipelineVertexInputStateCreateFlags = Flags<PipelineVertexInputStateCreateFlagBits, VkPipelineVertexInputStateCreateFlags>;\n\n  VULKAN_HPP_INLINE PipelineVertexInputStateCreateFlags operator|( PipelineVertexInputStateCreateFlagBits bit0, PipelineVertexInputStateCreateFlagBits bit1 )\n  {\n    return PipelineVertexInputStateCreateFlags( bit0 ) | bit1;\n  }\n\n  enum class PipelineShaderStageCreateFlagBits\n  {\n  };\n\n  using PipelineShaderStageCreateFlags = Flags<PipelineShaderStageCreateFlagBits, VkPipelineShaderStageCreateFlags>;\n\n  VULKAN_HPP_INLINE PipelineShaderStageCreateFlags operator|( PipelineShaderStageCreateFlagBits bit0, PipelineShaderStageCreateFlagBits bit1 )\n  {\n    return PipelineShaderStageCreateFlags( bit0 ) | bit1;\n  }\n\n  enum class BufferViewCreateFlagBits\n  {\n  };\n\n  using BufferViewCreateFlags = Flags<BufferViewCreateFlagBits, VkBufferViewCreateFlags>;\n\n  VULKAN_HPP_INLINE BufferViewCreateFlags operator|( BufferViewCreateFlagBits bit0, BufferViewCreateFlagBits bit1 )\n  {\n    return BufferViewCreateFlags( bit0 ) | bit1;\n  }\n\n  enum class InstanceCreateFlagBits\n  {\n  };\n\n  using InstanceCreateFlags = Flags<InstanceCreateFlagBits, VkInstanceCreateFlags>;\n\n  VULKAN_HPP_INLINE InstanceCreateFlags operator|( InstanceCreateFlagBits bit0, InstanceCreateFlagBits bit1 )\n  {\n    return InstanceCreateFlags( bit0 ) | bit1;\n  }\n\n  enum class DeviceCreateFlagBits\n  {\n  };\n\n  using DeviceCreateFlags = Flags<DeviceCreateFlagBits, VkDeviceCreateFlags>;\n\n  VULKAN_HPP_INLINE DeviceCreateFlags operator|( DeviceCreateFlagBits bit0, DeviceCreateFlagBits bit1 )\n  {\n    return DeviceCreateFlags( bit0 ) | bit1;\n  }\n\n  enum class DeviceQueueCreateFlagBits\n  {\n  };\n\n  using DeviceQueueCreateFlags = Flags<DeviceQueueCreateFlagBits, VkDeviceQueueCreateFlags>;\n\n  VULKAN_HPP_INLINE DeviceQueueCreateFlags operator|( DeviceQueueCreateFlagBits bit0, DeviceQueueCreateFlagBits bit1 )\n  {\n    return DeviceQueueCreateFlags( bit0 ) | bit1;\n  }\n\n  enum class ImageViewCreateFlagBits\n  {\n  };\n\n  using ImageViewCreateFlags = Flags<ImageViewCreateFlagBits, VkImageViewCreateFlags>;\n\n  VULKAN_HPP_INLINE ImageViewCreateFlags operator|( ImageViewCreateFlagBits bit0, ImageViewCreateFlagBits bit1 )\n  {\n    return ImageViewCreateFlags( bit0 ) | bit1;\n  }\n\n  enum class SemaphoreCreateFlagBits\n  {\n  };\n\n  using SemaphoreCreateFlags = Flags<SemaphoreCreateFlagBits, VkSemaphoreCreateFlags>;\n\n  VULKAN_HPP_INLINE SemaphoreCreateFlags operator|( SemaphoreCreateFlagBits bit0, SemaphoreCreateFlagBits bit1 )\n  {\n    return SemaphoreCreateFlags( bit0 ) | bit1;\n  }\n\n  enum class ShaderModuleCreateFlagBits\n  {\n  };\n\n  using ShaderModuleCreateFlags = Flags<ShaderModuleCreateFlagBits, VkShaderModuleCreateFlags>;\n\n  VULKAN_HPP_INLINE ShaderModuleCreateFlags operator|( ShaderModuleCreateFlagBits bit0, ShaderModuleCreateFlagBits bit1 )\n  {\n    return ShaderModuleCreateFlags( bit0 ) | bit1;\n  }\n\n  enum class EventCreateFlagBits\n  {\n  };\n\n  using EventCreateFlags = Flags<EventCreateFlagBits, VkEventCreateFlags>;\n\n  VULKAN_HPP_INLINE EventCreateFlags operator|( EventCreateFlagBits bit0, EventCreateFlagBits bit1 )\n  {\n    return EventCreateFlags( bit0 ) | bit1;\n  }\n\n  enum class MemoryMapFlagBits\n  {\n  };\n\n  using MemoryMapFlags = Flags<MemoryMapFlagBits, VkMemoryMapFlags>;\n\n  VULKAN_HPP_INLINE MemoryMapFlags operator|( MemoryMapFlagBits bit0, MemoryMapFlagBits bit1 )\n  {\n    return MemoryMapFlags( bit0 ) | bit1;\n  }\n\n  enum class DescriptorPoolResetFlagBits\n  {\n  };\n\n  using DescriptorPoolResetFlags = Flags<DescriptorPoolResetFlagBits, VkDescriptorPoolResetFlags>;\n\n  VULKAN_HPP_INLINE DescriptorPoolResetFlags operator|( DescriptorPoolResetFlagBits bit0, DescriptorPoolResetFlagBits bit1 )\n  {\n    return DescriptorPoolResetFlags( bit0 ) | bit1;\n  }\n\n  enum class DescriptorUpdateTemplateCreateFlagBitsKHR\n  {\n  };\n\n  using DescriptorUpdateTemplateCreateFlagsKHR = Flags<DescriptorUpdateTemplateCreateFlagBitsKHR, VkDescriptorUpdateTemplateCreateFlagsKHR>;\n\n  VULKAN_HPP_INLINE DescriptorUpdateTemplateCreateFlagsKHR operator|( DescriptorUpdateTemplateCreateFlagBitsKHR bit0, DescriptorUpdateTemplateCreateFlagBitsKHR bit1 )\n  {\n    return DescriptorUpdateTemplateCreateFlagsKHR( bit0 ) | bit1;\n  }\n\n  enum class DisplayModeCreateFlagBitsKHR\n  {\n  };\n\n  using DisplayModeCreateFlagsKHR = Flags<DisplayModeCreateFlagBitsKHR, VkDisplayModeCreateFlagsKHR>;\n\n  VULKAN_HPP_INLINE DisplayModeCreateFlagsKHR operator|( DisplayModeCreateFlagBitsKHR bit0, DisplayModeCreateFlagBitsKHR bit1 )\n  {\n    return DisplayModeCreateFlagsKHR( bit0 ) | bit1;\n  }\n\n  enum class DisplaySurfaceCreateFlagBitsKHR\n  {\n  };\n\n  using DisplaySurfaceCreateFlagsKHR = Flags<DisplaySurfaceCreateFlagBitsKHR, VkDisplaySurfaceCreateFlagsKHR>;\n\n  VULKAN_HPP_INLINE DisplaySurfaceCreateFlagsKHR operator|( DisplaySurfaceCreateFlagBitsKHR bit0, DisplaySurfaceCreateFlagBitsKHR bit1 )\n  {\n    return DisplaySurfaceCreateFlagsKHR( bit0 ) | bit1;\n  }\n\n#ifdef VK_USE_PLATFORM_ANDROID_KHR\n  enum class AndroidSurfaceCreateFlagBitsKHR\n  {\n  };\n#endif /*VK_USE_PLATFORM_ANDROID_KHR*/\n\n#ifdef VK_USE_PLATFORM_ANDROID_KHR\n  using AndroidSurfaceCreateFlagsKHR = Flags<AndroidSurfaceCreateFlagBitsKHR, VkAndroidSurfaceCreateFlagsKHR>;\n\n  VULKAN_HPP_INLINE AndroidSurfaceCreateFlagsKHR operator|( AndroidSurfaceCreateFlagBitsKHR bit0, AndroidSurfaceCreateFlagBitsKHR bit1 )\n  {\n    return AndroidSurfaceCreateFlagsKHR( bit0 ) | bit1;\n  }\n#endif /*VK_USE_PLATFORM_ANDROID_KHR*/\n\n#ifdef VK_USE_PLATFORM_MIR_KHR\n  enum class MirSurfaceCreateFlagBitsKHR\n  {\n  };\n#endif /*VK_USE_PLATFORM_MIR_KHR*/\n\n#ifdef VK_USE_PLATFORM_MIR_KHR\n  using MirSurfaceCreateFlagsKHR = Flags<MirSurfaceCreateFlagBitsKHR, VkMirSurfaceCreateFlagsKHR>;\n\n  VULKAN_HPP_INLINE MirSurfaceCreateFlagsKHR operator|( MirSurfaceCreateFlagBitsKHR bit0, MirSurfaceCreateFlagBitsKHR bit1 )\n  {\n    return MirSurfaceCreateFlagsKHR( bit0 ) | bit1;\n  }\n#endif /*VK_USE_PLATFORM_MIR_KHR*/\n\n#ifdef VK_USE_PLATFORM_VI_NN\n  enum class ViSurfaceCreateFlagBitsNN\n  {\n  };\n#endif /*VK_USE_PLATFORM_VI_NN*/\n\n#ifdef VK_USE_PLATFORM_VI_NN\n  using ViSurfaceCreateFlagsNN = Flags<ViSurfaceCreateFlagBitsNN, VkViSurfaceCreateFlagsNN>;\n\n  VULKAN_HPP_INLINE ViSurfaceCreateFlagsNN operator|( ViSurfaceCreateFlagBitsNN bit0, ViSurfaceCreateFlagBitsNN bit1 )\n  {\n    return ViSurfaceCreateFlagsNN( bit0 ) | bit1;\n  }\n#endif /*VK_USE_PLATFORM_VI_NN*/\n\n#ifdef VK_USE_PLATFORM_WAYLAND_KHR\n  enum class WaylandSurfaceCreateFlagBitsKHR\n  {\n  };\n#endif /*VK_USE_PLATFORM_WAYLAND_KHR*/\n\n#ifdef VK_USE_PLATFORM_WAYLAND_KHR\n  using WaylandSurfaceCreateFlagsKHR = Flags<WaylandSurfaceCreateFlagBitsKHR, VkWaylandSurfaceCreateFlagsKHR>;\n\n  VULKAN_HPP_INLINE WaylandSurfaceCreateFlagsKHR operator|( WaylandSurfaceCreateFlagBitsKHR bit0, WaylandSurfaceCreateFlagBitsKHR bit1 )\n  {\n    return WaylandSurfaceCreateFlagsKHR( bit0 ) | bit1;\n  }\n#endif /*VK_USE_PLATFORM_WAYLAND_KHR*/\n\n#ifdef VK_USE_PLATFORM_WIN32_KHR\n  enum class Win32SurfaceCreateFlagBitsKHR\n  {\n  };\n#endif /*VK_USE_PLATFORM_WIN32_KHR*/\n\n#ifdef VK_USE_PLATFORM_WIN32_KHR\n  using Win32SurfaceCreateFlagsKHR = Flags<Win32SurfaceCreateFlagBitsKHR, VkWin32SurfaceCreateFlagsKHR>;\n\n  VULKAN_HPP_INLINE Win32SurfaceCreateFlagsKHR operator|( Win32SurfaceCreateFlagBitsKHR bit0, Win32SurfaceCreateFlagBitsKHR bit1 )\n  {\n    return Win32SurfaceCreateFlagsKHR( bit0 ) | bit1;\n  }\n#endif /*VK_USE_PLATFORM_WIN32_KHR*/\n\n#ifdef VK_USE_PLATFORM_XLIB_KHR\n  enum class XlibSurfaceCreateFlagBitsKHR\n  {\n  };\n#endif /*VK_USE_PLATFORM_XLIB_KHR*/\n\n#ifdef VK_USE_PLATFORM_XLIB_KHR\n  using XlibSurfaceCreateFlagsKHR = Flags<XlibSurfaceCreateFlagBitsKHR, VkXlibSurfaceCreateFlagsKHR>;\n\n  VULKAN_HPP_INLINE XlibSurfaceCreateFlagsKHR operator|( XlibSurfaceCreateFlagBitsKHR bit0, XlibSurfaceCreateFlagBitsKHR bit1 )\n  {\n    return XlibSurfaceCreateFlagsKHR( bit0 ) | bit1;\n  }\n#endif /*VK_USE_PLATFORM_XLIB_KHR*/\n\n#ifdef VK_USE_PLATFORM_XCB_KHR\n  enum class XcbSurfaceCreateFlagBitsKHR\n  {\n  };\n#endif /*VK_USE_PLATFORM_XCB_KHR*/\n\n#ifdef VK_USE_PLATFORM_XCB_KHR\n  using XcbSurfaceCreateFlagsKHR = Flags<XcbSurfaceCreateFlagBitsKHR, VkXcbSurfaceCreateFlagsKHR>;\n\n  VULKAN_HPP_INLINE XcbSurfaceCreateFlagsKHR operator|( XcbSurfaceCreateFlagBitsKHR bit0, XcbSurfaceCreateFlagBitsKHR bit1 )\n  {\n    return XcbSurfaceCreateFlagsKHR( bit0 ) | bit1;\n  }\n#endif /*VK_USE_PLATFORM_XCB_KHR*/\n\n#ifdef VK_USE_PLATFORM_IOS_MVK\n  enum class IOSSurfaceCreateFlagBitsMVK\n  {\n  };\n#endif /*VK_USE_PLATFORM_IOS_MVK*/\n\n#ifdef VK_USE_PLATFORM_IOS_MVK\n  using IOSSurfaceCreateFlagsMVK = Flags<IOSSurfaceCreateFlagBitsMVK, VkIOSSurfaceCreateFlagsMVK>;\n\n  VULKAN_HPP_INLINE IOSSurfaceCreateFlagsMVK operator|( IOSSurfaceCreateFlagBitsMVK bit0, IOSSurfaceCreateFlagBitsMVK bit1 )\n  {\n    return IOSSurfaceCreateFlagsMVK( bit0 ) | bit1;\n  }\n#endif /*VK_USE_PLATFORM_IOS_MVK*/\n\n#ifdef VK_USE_PLATFORM_MACOS_MVK\n  enum class MacOSSurfaceCreateFlagBitsMVK\n  {\n  };\n#endif /*VK_USE_PLATFORM_MACOS_MVK*/\n\n#ifdef VK_USE_PLATFORM_MACOS_MVK\n  using MacOSSurfaceCreateFlagsMVK = Flags<MacOSSurfaceCreateFlagBitsMVK, VkMacOSSurfaceCreateFlagsMVK>;\n\n  VULKAN_HPP_INLINE MacOSSurfaceCreateFlagsMVK operator|( MacOSSurfaceCreateFlagBitsMVK bit0, MacOSSurfaceCreateFlagBitsMVK bit1 )\n  {\n    return MacOSSurfaceCreateFlagsMVK( bit0 ) | bit1;\n  }\n#endif /*VK_USE_PLATFORM_MACOS_MVK*/\n\n  enum class CommandPoolTrimFlagBitsKHR\n  {\n  };\n\n  using CommandPoolTrimFlagsKHR = Flags<CommandPoolTrimFlagBitsKHR, VkCommandPoolTrimFlagsKHR>;\n\n  VULKAN_HPP_INLINE CommandPoolTrimFlagsKHR operator|( CommandPoolTrimFlagBitsKHR bit0, CommandPoolTrimFlagBitsKHR bit1 )\n  {\n    return CommandPoolTrimFlagsKHR( bit0 ) | bit1;\n  }\n\n  enum class PipelineViewportSwizzleStateCreateFlagBitsNV\n  {\n  };\n\n  using PipelineViewportSwizzleStateCreateFlagsNV = Flags<PipelineViewportSwizzleStateCreateFlagBitsNV, VkPipelineViewportSwizzleStateCreateFlagsNV>;\n\n  VULKAN_HPP_INLINE PipelineViewportSwizzleStateCreateFlagsNV operator|( PipelineViewportSwizzleStateCreateFlagBitsNV bit0, PipelineViewportSwizzleStateCreateFlagBitsNV bit1 )\n  {\n    return PipelineViewportSwizzleStateCreateFlagsNV( bit0 ) | bit1;\n  }\n\n  enum class PipelineDiscardRectangleStateCreateFlagBitsEXT\n  {\n  };\n\n  using PipelineDiscardRectangleStateCreateFlagsEXT = Flags<PipelineDiscardRectangleStateCreateFlagBitsEXT, VkPipelineDiscardRectangleStateCreateFlagsEXT>;\n\n  VULKAN_HPP_INLINE PipelineDiscardRectangleStateCreateFlagsEXT operator|( PipelineDiscardRectangleStateCreateFlagBitsEXT bit0, PipelineDiscardRectangleStateCreateFlagBitsEXT bit1 )\n  {\n    return PipelineDiscardRectangleStateCreateFlagsEXT( bit0 ) | bit1;\n  }\n\n  class DeviceMemory\n  {\n  public:\n    DeviceMemory()\n      : m_deviceMemory(VK_NULL_HANDLE)\n    {}\n\n    DeviceMemory( std::nullptr_t )\n      : m_deviceMemory(VK_NULL_HANDLE)\n    {}\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT DeviceMemory(VkDeviceMemory deviceMemory)\n       : m_deviceMemory(deviceMemory)\n    {}\n\n#if defined(VULKAN_HPP_TYPESAFE_CONVERSION)\n    DeviceMemory& operator=(VkDeviceMemory deviceMemory)\n    {\n      m_deviceMemory = deviceMemory;\n      return *this;\n    }\n#endif\n\n    DeviceMemory& operator=( std::nullptr_t )\n    {\n      m_deviceMemory = VK_NULL_HANDLE;\n      return *this;\n    }\n\n    bool operator==(DeviceMemory const &rhs) const\n    {\n      return m_deviceMemory == rhs.m_deviceMemory;\n    }\n\n    bool operator!=(DeviceMemory const &rhs) const\n    {\n      return m_deviceMemory != rhs.m_deviceMemory;\n    }\n\n    bool operator<(DeviceMemory const &rhs) const\n    {\n      return m_deviceMemory < rhs.m_deviceMemory;\n    }\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT operator VkDeviceMemory() const\n    {\n      return m_deviceMemory;\n    }\n\n    explicit operator bool() const\n    {\n      return m_deviceMemory != VK_NULL_HANDLE;\n    }\n\n    bool operator!() const\n    {\n      return m_deviceMemory == VK_NULL_HANDLE;\n    }\n\n  private:\n    VkDeviceMemory m_deviceMemory;\n  };\n  static_assert( sizeof( DeviceMemory ) == sizeof( VkDeviceMemory ), \"handle and wrapper have different size!\" );\n\n  class CommandPool\n  {\n  public:\n    CommandPool()\n      : m_commandPool(VK_NULL_HANDLE)\n    {}\n\n    CommandPool( std::nullptr_t )\n      : m_commandPool(VK_NULL_HANDLE)\n    {}\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT CommandPool(VkCommandPool commandPool)\n       : m_commandPool(commandPool)\n    {}\n\n#if defined(VULKAN_HPP_TYPESAFE_CONVERSION)\n    CommandPool& operator=(VkCommandPool commandPool)\n    {\n      m_commandPool = commandPool;\n      return *this;\n    }\n#endif\n\n    CommandPool& operator=( std::nullptr_t )\n    {\n      m_commandPool = VK_NULL_HANDLE;\n      return *this;\n    }\n\n    bool operator==(CommandPool const &rhs) const\n    {\n      return m_commandPool == rhs.m_commandPool;\n    }\n\n    bool operator!=(CommandPool const &rhs) const\n    {\n      return m_commandPool != rhs.m_commandPool;\n    }\n\n    bool operator<(CommandPool const &rhs) const\n    {\n      return m_commandPool < rhs.m_commandPool;\n    }\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT operator VkCommandPool() const\n    {\n      return m_commandPool;\n    }\n\n    explicit operator bool() const\n    {\n      return m_commandPool != VK_NULL_HANDLE;\n    }\n\n    bool operator!() const\n    {\n      return m_commandPool == VK_NULL_HANDLE;\n    }\n\n  private:\n    VkCommandPool m_commandPool;\n  };\n  static_assert( sizeof( CommandPool ) == sizeof( VkCommandPool ), \"handle and wrapper have different size!\" );\n\n  class Buffer\n  {\n  public:\n    Buffer()\n      : m_buffer(VK_NULL_HANDLE)\n    {}\n\n    Buffer( std::nullptr_t )\n      : m_buffer(VK_NULL_HANDLE)\n    {}\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT Buffer(VkBuffer buffer)\n       : m_buffer(buffer)\n    {}\n\n#if defined(VULKAN_HPP_TYPESAFE_CONVERSION)\n    Buffer& operator=(VkBuffer buffer)\n    {\n      m_buffer = buffer;\n      return *this;\n    }\n#endif\n\n    Buffer& operator=( std::nullptr_t )\n    {\n      m_buffer = VK_NULL_HANDLE;\n      return *this;\n    }\n\n    bool operator==(Buffer const &rhs) const\n    {\n      return m_buffer == rhs.m_buffer;\n    }\n\n    bool operator!=(Buffer const &rhs) const\n    {\n      return m_buffer != rhs.m_buffer;\n    }\n\n    bool operator<(Buffer const &rhs) const\n    {\n      return m_buffer < rhs.m_buffer;\n    }\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT operator VkBuffer() const\n    {\n      return m_buffer;\n    }\n\n    explicit operator bool() const\n    {\n      return m_buffer != VK_NULL_HANDLE;\n    }\n\n    bool operator!() const\n    {\n      return m_buffer == VK_NULL_HANDLE;\n    }\n\n  private:\n    VkBuffer m_buffer;\n  };\n  static_assert( sizeof( Buffer ) == sizeof( VkBuffer ), \"handle and wrapper have different size!\" );\n\n  class BufferView\n  {\n  public:\n    BufferView()\n      : m_bufferView(VK_NULL_HANDLE)\n    {}\n\n    BufferView( std::nullptr_t )\n      : m_bufferView(VK_NULL_HANDLE)\n    {}\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT BufferView(VkBufferView bufferView)\n       : m_bufferView(bufferView)\n    {}\n\n#if defined(VULKAN_HPP_TYPESAFE_CONVERSION)\n    BufferView& operator=(VkBufferView bufferView)\n    {\n      m_bufferView = bufferView;\n      return *this;\n    }\n#endif\n\n    BufferView& operator=( std::nullptr_t )\n    {\n      m_bufferView = VK_NULL_HANDLE;\n      return *this;\n    }\n\n    bool operator==(BufferView const &rhs) const\n    {\n      return m_bufferView == rhs.m_bufferView;\n    }\n\n    bool operator!=(BufferView const &rhs) const\n    {\n      return m_bufferView != rhs.m_bufferView;\n    }\n\n    bool operator<(BufferView const &rhs) const\n    {\n      return m_bufferView < rhs.m_bufferView;\n    }\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT operator VkBufferView() const\n    {\n      return m_bufferView;\n    }\n\n    explicit operator bool() const\n    {\n      return m_bufferView != VK_NULL_HANDLE;\n    }\n\n    bool operator!() const\n    {\n      return m_bufferView == VK_NULL_HANDLE;\n    }\n\n  private:\n    VkBufferView m_bufferView;\n  };\n  static_assert( sizeof( BufferView ) == sizeof( VkBufferView ), \"handle and wrapper have different size!\" );\n\n  class Image\n  {\n  public:\n    Image()\n      : m_image(VK_NULL_HANDLE)\n    {}\n\n    Image( std::nullptr_t )\n      : m_image(VK_NULL_HANDLE)\n    {}\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT Image(VkImage image)\n       : m_image(image)\n    {}\n\n#if defined(VULKAN_HPP_TYPESAFE_CONVERSION)\n    Image& operator=(VkImage image)\n    {\n      m_image = image;\n      return *this;\n    }\n#endif\n\n    Image& operator=( std::nullptr_t )\n    {\n      m_image = VK_NULL_HANDLE;\n      return *this;\n    }\n\n    bool operator==(Image const &rhs) const\n    {\n      return m_image == rhs.m_image;\n    }\n\n    bool operator!=(Image const &rhs) const\n    {\n      return m_image != rhs.m_image;\n    }\n\n    bool operator<(Image const &rhs) const\n    {\n      return m_image < rhs.m_image;\n    }\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT operator VkImage() const\n    {\n      return m_image;\n    }\n\n    explicit operator bool() const\n    {\n      return m_image != VK_NULL_HANDLE;\n    }\n\n    bool operator!() const\n    {\n      return m_image == VK_NULL_HANDLE;\n    }\n\n  private:\n    VkImage m_image;\n  };\n  static_assert( sizeof( Image ) == sizeof( VkImage ), \"handle and wrapper have different size!\" );\n\n  class ImageView\n  {\n  public:\n    ImageView()\n      : m_imageView(VK_NULL_HANDLE)\n    {}\n\n    ImageView( std::nullptr_t )\n      : m_imageView(VK_NULL_HANDLE)\n    {}\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT ImageView(VkImageView imageView)\n       : m_imageView(imageView)\n    {}\n\n#if defined(VULKAN_HPP_TYPESAFE_CONVERSION)\n    ImageView& operator=(VkImageView imageView)\n    {\n      m_imageView = imageView;\n      return *this;\n    }\n#endif\n\n    ImageView& operator=( std::nullptr_t )\n    {\n      m_imageView = VK_NULL_HANDLE;\n      return *this;\n    }\n\n    bool operator==(ImageView const &rhs) const\n    {\n      return m_imageView == rhs.m_imageView;\n    }\n\n    bool operator!=(ImageView const &rhs) const\n    {\n      return m_imageView != rhs.m_imageView;\n    }\n\n    bool operator<(ImageView const &rhs) const\n    {\n      return m_imageView < rhs.m_imageView;\n    }\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT operator VkImageView() const\n    {\n      return m_imageView;\n    }\n\n    explicit operator bool() const\n    {\n      return m_imageView != VK_NULL_HANDLE;\n    }\n\n    bool operator!() const\n    {\n      return m_imageView == VK_NULL_HANDLE;\n    }\n\n  private:\n    VkImageView m_imageView;\n  };\n  static_assert( sizeof( ImageView ) == sizeof( VkImageView ), \"handle and wrapper have different size!\" );\n\n  class ShaderModule\n  {\n  public:\n    ShaderModule()\n      : m_shaderModule(VK_NULL_HANDLE)\n    {}\n\n    ShaderModule( std::nullptr_t )\n      : m_shaderModule(VK_NULL_HANDLE)\n    {}\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT ShaderModule(VkShaderModule shaderModule)\n       : m_shaderModule(shaderModule)\n    {}\n\n#if defined(VULKAN_HPP_TYPESAFE_CONVERSION)\n    ShaderModule& operator=(VkShaderModule shaderModule)\n    {\n      m_shaderModule = shaderModule;\n      return *this;\n    }\n#endif\n\n    ShaderModule& operator=( std::nullptr_t )\n    {\n      m_shaderModule = VK_NULL_HANDLE;\n      return *this;\n    }\n\n    bool operator==(ShaderModule const &rhs) const\n    {\n      return m_shaderModule == rhs.m_shaderModule;\n    }\n\n    bool operator!=(ShaderModule const &rhs) const\n    {\n      return m_shaderModule != rhs.m_shaderModule;\n    }\n\n    bool operator<(ShaderModule const &rhs) const\n    {\n      return m_shaderModule < rhs.m_shaderModule;\n    }\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT operator VkShaderModule() const\n    {\n      return m_shaderModule;\n    }\n\n    explicit operator bool() const\n    {\n      return m_shaderModule != VK_NULL_HANDLE;\n    }\n\n    bool operator!() const\n    {\n      return m_shaderModule == VK_NULL_HANDLE;\n    }\n\n  private:\n    VkShaderModule m_shaderModule;\n  };\n  static_assert( sizeof( ShaderModule ) == sizeof( VkShaderModule ), \"handle and wrapper have different size!\" );\n\n  class Pipeline\n  {\n  public:\n    Pipeline()\n      : m_pipeline(VK_NULL_HANDLE)\n    {}\n\n    Pipeline( std::nullptr_t )\n      : m_pipeline(VK_NULL_HANDLE)\n    {}\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT Pipeline(VkPipeline pipeline)\n       : m_pipeline(pipeline)\n    {}\n\n#if defined(VULKAN_HPP_TYPESAFE_CONVERSION)\n    Pipeline& operator=(VkPipeline pipeline)\n    {\n      m_pipeline = pipeline;\n      return *this;\n    }\n#endif\n\n    Pipeline& operator=( std::nullptr_t )\n    {\n      m_pipeline = VK_NULL_HANDLE;\n      return *this;\n    }\n\n    bool operator==(Pipeline const &rhs) const\n    {\n      return m_pipeline == rhs.m_pipeline;\n    }\n\n    bool operator!=(Pipeline const &rhs) const\n    {\n      return m_pipeline != rhs.m_pipeline;\n    }\n\n    bool operator<(Pipeline const &rhs) const\n    {\n      return m_pipeline < rhs.m_pipeline;\n    }\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT operator VkPipeline() const\n    {\n      return m_pipeline;\n    }\n\n    explicit operator bool() const\n    {\n      return m_pipeline != VK_NULL_HANDLE;\n    }\n\n    bool operator!() const\n    {\n      return m_pipeline == VK_NULL_HANDLE;\n    }\n\n  private:\n    VkPipeline m_pipeline;\n  };\n  static_assert( sizeof( Pipeline ) == sizeof( VkPipeline ), \"handle and wrapper have different size!\" );\n\n  class PipelineLayout\n  {\n  public:\n    PipelineLayout()\n      : m_pipelineLayout(VK_NULL_HANDLE)\n    {}\n\n    PipelineLayout( std::nullptr_t )\n      : m_pipelineLayout(VK_NULL_HANDLE)\n    {}\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT PipelineLayout(VkPipelineLayout pipelineLayout)\n       : m_pipelineLayout(pipelineLayout)\n    {}\n\n#if defined(VULKAN_HPP_TYPESAFE_CONVERSION)\n    PipelineLayout& operator=(VkPipelineLayout pipelineLayout)\n    {\n      m_pipelineLayout = pipelineLayout;\n      return *this;\n    }\n#endif\n\n    PipelineLayout& operator=( std::nullptr_t )\n    {\n      m_pipelineLayout = VK_NULL_HANDLE;\n      return *this;\n    }\n\n    bool operator==(PipelineLayout const &rhs) const\n    {\n      return m_pipelineLayout == rhs.m_pipelineLayout;\n    }\n\n    bool operator!=(PipelineLayout const &rhs) const\n    {\n      return m_pipelineLayout != rhs.m_pipelineLayout;\n    }\n\n    bool operator<(PipelineLayout const &rhs) const\n    {\n      return m_pipelineLayout < rhs.m_pipelineLayout;\n    }\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT operator VkPipelineLayout() const\n    {\n      return m_pipelineLayout;\n    }\n\n    explicit operator bool() const\n    {\n      return m_pipelineLayout != VK_NULL_HANDLE;\n    }\n\n    bool operator!() const\n    {\n      return m_pipelineLayout == VK_NULL_HANDLE;\n    }\n\n  private:\n    VkPipelineLayout m_pipelineLayout;\n  };\n  static_assert( sizeof( PipelineLayout ) == sizeof( VkPipelineLayout ), \"handle and wrapper have different size!\" );\n\n  class Sampler\n  {\n  public:\n    Sampler()\n      : m_sampler(VK_NULL_HANDLE)\n    {}\n\n    Sampler( std::nullptr_t )\n      : m_sampler(VK_NULL_HANDLE)\n    {}\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT Sampler(VkSampler sampler)\n       : m_sampler(sampler)\n    {}\n\n#if defined(VULKAN_HPP_TYPESAFE_CONVERSION)\n    Sampler& operator=(VkSampler sampler)\n    {\n      m_sampler = sampler;\n      return *this;\n    }\n#endif\n\n    Sampler& operator=( std::nullptr_t )\n    {\n      m_sampler = VK_NULL_HANDLE;\n      return *this;\n    }\n\n    bool operator==(Sampler const &rhs) const\n    {\n      return m_sampler == rhs.m_sampler;\n    }\n\n    bool operator!=(Sampler const &rhs) const\n    {\n      return m_sampler != rhs.m_sampler;\n    }\n\n    bool operator<(Sampler const &rhs) const\n    {\n      return m_sampler < rhs.m_sampler;\n    }\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT operator VkSampler() const\n    {\n      return m_sampler;\n    }\n\n    explicit operator bool() const\n    {\n      return m_sampler != VK_NULL_HANDLE;\n    }\n\n    bool operator!() const\n    {\n      return m_sampler == VK_NULL_HANDLE;\n    }\n\n  private:\n    VkSampler m_sampler;\n  };\n  static_assert( sizeof( Sampler ) == sizeof( VkSampler ), \"handle and wrapper have different size!\" );\n\n  class DescriptorSet\n  {\n  public:\n    DescriptorSet()\n      : m_descriptorSet(VK_NULL_HANDLE)\n    {}\n\n    DescriptorSet( std::nullptr_t )\n      : m_descriptorSet(VK_NULL_HANDLE)\n    {}\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT DescriptorSet(VkDescriptorSet descriptorSet)\n       : m_descriptorSet(descriptorSet)\n    {}\n\n#if defined(VULKAN_HPP_TYPESAFE_CONVERSION)\n    DescriptorSet& operator=(VkDescriptorSet descriptorSet)\n    {\n      m_descriptorSet = descriptorSet;\n      return *this;\n    }\n#endif\n\n    DescriptorSet& operator=( std::nullptr_t )\n    {\n      m_descriptorSet = VK_NULL_HANDLE;\n      return *this;\n    }\n\n    bool operator==(DescriptorSet const &rhs) const\n    {\n      return m_descriptorSet == rhs.m_descriptorSet;\n    }\n\n    bool operator!=(DescriptorSet const &rhs) const\n    {\n      return m_descriptorSet != rhs.m_descriptorSet;\n    }\n\n    bool operator<(DescriptorSet const &rhs) const\n    {\n      return m_descriptorSet < rhs.m_descriptorSet;\n    }\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT operator VkDescriptorSet() const\n    {\n      return m_descriptorSet;\n    }\n\n    explicit operator bool() const\n    {\n      return m_descriptorSet != VK_NULL_HANDLE;\n    }\n\n    bool operator!() const\n    {\n      return m_descriptorSet == VK_NULL_HANDLE;\n    }\n\n  private:\n    VkDescriptorSet m_descriptorSet;\n  };\n  static_assert( sizeof( DescriptorSet ) == sizeof( VkDescriptorSet ), \"handle and wrapper have different size!\" );\n\n  class DescriptorSetLayout\n  {\n  public:\n    DescriptorSetLayout()\n      : m_descriptorSetLayout(VK_NULL_HANDLE)\n    {}\n\n    DescriptorSetLayout( std::nullptr_t )\n      : m_descriptorSetLayout(VK_NULL_HANDLE)\n    {}\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT DescriptorSetLayout(VkDescriptorSetLayout descriptorSetLayout)\n       : m_descriptorSetLayout(descriptorSetLayout)\n    {}\n\n#if defined(VULKAN_HPP_TYPESAFE_CONVERSION)\n    DescriptorSetLayout& operator=(VkDescriptorSetLayout descriptorSetLayout)\n    {\n      m_descriptorSetLayout = descriptorSetLayout;\n      return *this;\n    }\n#endif\n\n    DescriptorSetLayout& operator=( std::nullptr_t )\n    {\n      m_descriptorSetLayout = VK_NULL_HANDLE;\n      return *this;\n    }\n\n    bool operator==(DescriptorSetLayout const &rhs) const\n    {\n      return m_descriptorSetLayout == rhs.m_descriptorSetLayout;\n    }\n\n    bool operator!=(DescriptorSetLayout const &rhs) const\n    {\n      return m_descriptorSetLayout != rhs.m_descriptorSetLayout;\n    }\n\n    bool operator<(DescriptorSetLayout const &rhs) const\n    {\n      return m_descriptorSetLayout < rhs.m_descriptorSetLayout;\n    }\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT operator VkDescriptorSetLayout() const\n    {\n      return m_descriptorSetLayout;\n    }\n\n    explicit operator bool() const\n    {\n      return m_descriptorSetLayout != VK_NULL_HANDLE;\n    }\n\n    bool operator!() const\n    {\n      return m_descriptorSetLayout == VK_NULL_HANDLE;\n    }\n\n  private:\n    VkDescriptorSetLayout m_descriptorSetLayout;\n  };\n  static_assert( sizeof( DescriptorSetLayout ) == sizeof( VkDescriptorSetLayout ), \"handle and wrapper have different size!\" );\n\n  class DescriptorPool\n  {\n  public:\n    DescriptorPool()\n      : m_descriptorPool(VK_NULL_HANDLE)\n    {}\n\n    DescriptorPool( std::nullptr_t )\n      : m_descriptorPool(VK_NULL_HANDLE)\n    {}\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT DescriptorPool(VkDescriptorPool descriptorPool)\n       : m_descriptorPool(descriptorPool)\n    {}\n\n#if defined(VULKAN_HPP_TYPESAFE_CONVERSION)\n    DescriptorPool& operator=(VkDescriptorPool descriptorPool)\n    {\n      m_descriptorPool = descriptorPool;\n      return *this;\n    }\n#endif\n\n    DescriptorPool& operator=( std::nullptr_t )\n    {\n      m_descriptorPool = VK_NULL_HANDLE;\n      return *this;\n    }\n\n    bool operator==(DescriptorPool const &rhs) const\n    {\n      return m_descriptorPool == rhs.m_descriptorPool;\n    }\n\n    bool operator!=(DescriptorPool const &rhs) const\n    {\n      return m_descriptorPool != rhs.m_descriptorPool;\n    }\n\n    bool operator<(DescriptorPool const &rhs) const\n    {\n      return m_descriptorPool < rhs.m_descriptorPool;\n    }\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT operator VkDescriptorPool() const\n    {\n      return m_descriptorPool;\n    }\n\n    explicit operator bool() const\n    {\n      return m_descriptorPool != VK_NULL_HANDLE;\n    }\n\n    bool operator!() const\n    {\n      return m_descriptorPool == VK_NULL_HANDLE;\n    }\n\n  private:\n    VkDescriptorPool m_descriptorPool;\n  };\n  static_assert( sizeof( DescriptorPool ) == sizeof( VkDescriptorPool ), \"handle and wrapper have different size!\" );\n\n  class Fence\n  {\n  public:\n    Fence()\n      : m_fence(VK_NULL_HANDLE)\n    {}\n\n    Fence( std::nullptr_t )\n      : m_fence(VK_NULL_HANDLE)\n    {}\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT Fence(VkFence fence)\n       : m_fence(fence)\n    {}\n\n#if defined(VULKAN_HPP_TYPESAFE_CONVERSION)\n    Fence& operator=(VkFence fence)\n    {\n      m_fence = fence;\n      return *this;\n    }\n#endif\n\n    Fence& operator=( std::nullptr_t )\n    {\n      m_fence = VK_NULL_HANDLE;\n      return *this;\n    }\n\n    bool operator==(Fence const &rhs) const\n    {\n      return m_fence == rhs.m_fence;\n    }\n\n    bool operator!=(Fence const &rhs) const\n    {\n      return m_fence != rhs.m_fence;\n    }\n\n    bool operator<(Fence const &rhs) const\n    {\n      return m_fence < rhs.m_fence;\n    }\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT operator VkFence() const\n    {\n      return m_fence;\n    }\n\n    explicit operator bool() const\n    {\n      return m_fence != VK_NULL_HANDLE;\n    }\n\n    bool operator!() const\n    {\n      return m_fence == VK_NULL_HANDLE;\n    }\n\n  private:\n    VkFence m_fence;\n  };\n  static_assert( sizeof( Fence ) == sizeof( VkFence ), \"handle and wrapper have different size!\" );\n\n  class Semaphore\n  {\n  public:\n    Semaphore()\n      : m_semaphore(VK_NULL_HANDLE)\n    {}\n\n    Semaphore( std::nullptr_t )\n      : m_semaphore(VK_NULL_HANDLE)\n    {}\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT Semaphore(VkSemaphore semaphore)\n       : m_semaphore(semaphore)\n    {}\n\n#if defined(VULKAN_HPP_TYPESAFE_CONVERSION)\n    Semaphore& operator=(VkSemaphore semaphore)\n    {\n      m_semaphore = semaphore;\n      return *this;\n    }\n#endif\n\n    Semaphore& operator=( std::nullptr_t )\n    {\n      m_semaphore = VK_NULL_HANDLE;\n      return *this;\n    }\n\n    bool operator==(Semaphore const &rhs) const\n    {\n      return m_semaphore == rhs.m_semaphore;\n    }\n\n    bool operator!=(Semaphore const &rhs) const\n    {\n      return m_semaphore != rhs.m_semaphore;\n    }\n\n    bool operator<(Semaphore const &rhs) const\n    {\n      return m_semaphore < rhs.m_semaphore;\n    }\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT operator VkSemaphore() const\n    {\n      return m_semaphore;\n    }\n\n    explicit operator bool() const\n    {\n      return m_semaphore != VK_NULL_HANDLE;\n    }\n\n    bool operator!() const\n    {\n      return m_semaphore == VK_NULL_HANDLE;\n    }\n\n  private:\n    VkSemaphore m_semaphore;\n  };\n  static_assert( sizeof( Semaphore ) == sizeof( VkSemaphore ), \"handle and wrapper have different size!\" );\n\n  class Event\n  {\n  public:\n    Event()\n      : m_event(VK_NULL_HANDLE)\n    {}\n\n    Event( std::nullptr_t )\n      : m_event(VK_NULL_HANDLE)\n    {}\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT Event(VkEvent event)\n       : m_event(event)\n    {}\n\n#if defined(VULKAN_HPP_TYPESAFE_CONVERSION)\n    Event& operator=(VkEvent event)\n    {\n      m_event = event;\n      return *this;\n    }\n#endif\n\n    Event& operator=( std::nullptr_t )\n    {\n      m_event = VK_NULL_HANDLE;\n      return *this;\n    }\n\n    bool operator==(Event const &rhs) const\n    {\n      return m_event == rhs.m_event;\n    }\n\n    bool operator!=(Event const &rhs) const\n    {\n      return m_event != rhs.m_event;\n    }\n\n    bool operator<(Event const &rhs) const\n    {\n      return m_event < rhs.m_event;\n    }\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT operator VkEvent() const\n    {\n      return m_event;\n    }\n\n    explicit operator bool() const\n    {\n      return m_event != VK_NULL_HANDLE;\n    }\n\n    bool operator!() const\n    {\n      return m_event == VK_NULL_HANDLE;\n    }\n\n  private:\n    VkEvent m_event;\n  };\n  static_assert( sizeof( Event ) == sizeof( VkEvent ), \"handle and wrapper have different size!\" );\n\n  class QueryPool\n  {\n  public:\n    QueryPool()\n      : m_queryPool(VK_NULL_HANDLE)\n    {}\n\n    QueryPool( std::nullptr_t )\n      : m_queryPool(VK_NULL_HANDLE)\n    {}\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT QueryPool(VkQueryPool queryPool)\n       : m_queryPool(queryPool)\n    {}\n\n#if defined(VULKAN_HPP_TYPESAFE_CONVERSION)\n    QueryPool& operator=(VkQueryPool queryPool)\n    {\n      m_queryPool = queryPool;\n      return *this;\n    }\n#endif\n\n    QueryPool& operator=( std::nullptr_t )\n    {\n      m_queryPool = VK_NULL_HANDLE;\n      return *this;\n    }\n\n    bool operator==(QueryPool const &rhs) const\n    {\n      return m_queryPool == rhs.m_queryPool;\n    }\n\n    bool operator!=(QueryPool const &rhs) const\n    {\n      return m_queryPool != rhs.m_queryPool;\n    }\n\n    bool operator<(QueryPool const &rhs) const\n    {\n      return m_queryPool < rhs.m_queryPool;\n    }\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT operator VkQueryPool() const\n    {\n      return m_queryPool;\n    }\n\n    explicit operator bool() const\n    {\n      return m_queryPool != VK_NULL_HANDLE;\n    }\n\n    bool operator!() const\n    {\n      return m_queryPool == VK_NULL_HANDLE;\n    }\n\n  private:\n    VkQueryPool m_queryPool;\n  };\n  static_assert( sizeof( QueryPool ) == sizeof( VkQueryPool ), \"handle and wrapper have different size!\" );\n\n  class Framebuffer\n  {\n  public:\n    Framebuffer()\n      : m_framebuffer(VK_NULL_HANDLE)\n    {}\n\n    Framebuffer( std::nullptr_t )\n      : m_framebuffer(VK_NULL_HANDLE)\n    {}\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT Framebuffer(VkFramebuffer framebuffer)\n       : m_framebuffer(framebuffer)\n    {}\n\n#if defined(VULKAN_HPP_TYPESAFE_CONVERSION)\n    Framebuffer& operator=(VkFramebuffer framebuffer)\n    {\n      m_framebuffer = framebuffer;\n      return *this;\n    }\n#endif\n\n    Framebuffer& operator=( std::nullptr_t )\n    {\n      m_framebuffer = VK_NULL_HANDLE;\n      return *this;\n    }\n\n    bool operator==(Framebuffer const &rhs) const\n    {\n      return m_framebuffer == rhs.m_framebuffer;\n    }\n\n    bool operator!=(Framebuffer const &rhs) const\n    {\n      return m_framebuffer != rhs.m_framebuffer;\n    }\n\n    bool operator<(Framebuffer const &rhs) const\n    {\n      return m_framebuffer < rhs.m_framebuffer;\n    }\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT operator VkFramebuffer() const\n    {\n      return m_framebuffer;\n    }\n\n    explicit operator bool() const\n    {\n      return m_framebuffer != VK_NULL_HANDLE;\n    }\n\n    bool operator!() const\n    {\n      return m_framebuffer == VK_NULL_HANDLE;\n    }\n\n  private:\n    VkFramebuffer m_framebuffer;\n  };\n  static_assert( sizeof( Framebuffer ) == sizeof( VkFramebuffer ), \"handle and wrapper have different size!\" );\n\n  class RenderPass\n  {\n  public:\n    RenderPass()\n      : m_renderPass(VK_NULL_HANDLE)\n    {}\n\n    RenderPass( std::nullptr_t )\n      : m_renderPass(VK_NULL_HANDLE)\n    {}\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT RenderPass(VkRenderPass renderPass)\n       : m_renderPass(renderPass)\n    {}\n\n#if defined(VULKAN_HPP_TYPESAFE_CONVERSION)\n    RenderPass& operator=(VkRenderPass renderPass)\n    {\n      m_renderPass = renderPass;\n      return *this;\n    }\n#endif\n\n    RenderPass& operator=( std::nullptr_t )\n    {\n      m_renderPass = VK_NULL_HANDLE;\n      return *this;\n    }\n\n    bool operator==(RenderPass const &rhs) const\n    {\n      return m_renderPass == rhs.m_renderPass;\n    }\n\n    bool operator!=(RenderPass const &rhs) const\n    {\n      return m_renderPass != rhs.m_renderPass;\n    }\n\n    bool operator<(RenderPass const &rhs) const\n    {\n      return m_renderPass < rhs.m_renderPass;\n    }\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT operator VkRenderPass() const\n    {\n      return m_renderPass;\n    }\n\n    explicit operator bool() const\n    {\n      return m_renderPass != VK_NULL_HANDLE;\n    }\n\n    bool operator!() const\n    {\n      return m_renderPass == VK_NULL_HANDLE;\n    }\n\n  private:\n    VkRenderPass m_renderPass;\n  };\n  static_assert( sizeof( RenderPass ) == sizeof( VkRenderPass ), \"handle and wrapper have different size!\" );\n\n  class PipelineCache\n  {\n  public:\n    PipelineCache()\n      : m_pipelineCache(VK_NULL_HANDLE)\n    {}\n\n    PipelineCache( std::nullptr_t )\n      : m_pipelineCache(VK_NULL_HANDLE)\n    {}\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT PipelineCache(VkPipelineCache pipelineCache)\n       : m_pipelineCache(pipelineCache)\n    {}\n\n#if defined(VULKAN_HPP_TYPESAFE_CONVERSION)\n    PipelineCache& operator=(VkPipelineCache pipelineCache)\n    {\n      m_pipelineCache = pipelineCache;\n      return *this;\n    }\n#endif\n\n    PipelineCache& operator=( std::nullptr_t )\n    {\n      m_pipelineCache = VK_NULL_HANDLE;\n      return *this;\n    }\n\n    bool operator==(PipelineCache const &rhs) const\n    {\n      return m_pipelineCache == rhs.m_pipelineCache;\n    }\n\n    bool operator!=(PipelineCache const &rhs) const\n    {\n      return m_pipelineCache != rhs.m_pipelineCache;\n    }\n\n    bool operator<(PipelineCache const &rhs) const\n    {\n      return m_pipelineCache < rhs.m_pipelineCache;\n    }\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT operator VkPipelineCache() const\n    {\n      return m_pipelineCache;\n    }\n\n    explicit operator bool() const\n    {\n      return m_pipelineCache != VK_NULL_HANDLE;\n    }\n\n    bool operator!() const\n    {\n      return m_pipelineCache == VK_NULL_HANDLE;\n    }\n\n  private:\n    VkPipelineCache m_pipelineCache;\n  };\n  static_assert( sizeof( PipelineCache ) == sizeof( VkPipelineCache ), \"handle and wrapper have different size!\" );\n\n  class ObjectTableNVX\n  {\n  public:\n    ObjectTableNVX()\n      : m_objectTableNVX(VK_NULL_HANDLE)\n    {}\n\n    ObjectTableNVX( std::nullptr_t )\n      : m_objectTableNVX(VK_NULL_HANDLE)\n    {}\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT ObjectTableNVX(VkObjectTableNVX objectTableNVX)\n       : m_objectTableNVX(objectTableNVX)\n    {}\n\n#if defined(VULKAN_HPP_TYPESAFE_CONVERSION)\n    ObjectTableNVX& operator=(VkObjectTableNVX objectTableNVX)\n    {\n      m_objectTableNVX = objectTableNVX;\n      return *this;\n    }\n#endif\n\n    ObjectTableNVX& operator=( std::nullptr_t )\n    {\n      m_objectTableNVX = VK_NULL_HANDLE;\n      return *this;\n    }\n\n    bool operator==(ObjectTableNVX const &rhs) const\n    {\n      return m_objectTableNVX == rhs.m_objectTableNVX;\n    }\n\n    bool operator!=(ObjectTableNVX const &rhs) const\n    {\n      return m_objectTableNVX != rhs.m_objectTableNVX;\n    }\n\n    bool operator<(ObjectTableNVX const &rhs) const\n    {\n      return m_objectTableNVX < rhs.m_objectTableNVX;\n    }\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT operator VkObjectTableNVX() const\n    {\n      return m_objectTableNVX;\n    }\n\n    explicit operator bool() const\n    {\n      return m_objectTableNVX != VK_NULL_HANDLE;\n    }\n\n    bool operator!() const\n    {\n      return m_objectTableNVX == VK_NULL_HANDLE;\n    }\n\n  private:\n    VkObjectTableNVX m_objectTableNVX;\n  };\n  static_assert( sizeof( ObjectTableNVX ) == sizeof( VkObjectTableNVX ), \"handle and wrapper have different size!\" );\n\n  class IndirectCommandsLayoutNVX\n  {\n  public:\n    IndirectCommandsLayoutNVX()\n      : m_indirectCommandsLayoutNVX(VK_NULL_HANDLE)\n    {}\n\n    IndirectCommandsLayoutNVX( std::nullptr_t )\n      : m_indirectCommandsLayoutNVX(VK_NULL_HANDLE)\n    {}\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT IndirectCommandsLayoutNVX(VkIndirectCommandsLayoutNVX indirectCommandsLayoutNVX)\n       : m_indirectCommandsLayoutNVX(indirectCommandsLayoutNVX)\n    {}\n\n#if defined(VULKAN_HPP_TYPESAFE_CONVERSION)\n    IndirectCommandsLayoutNVX& operator=(VkIndirectCommandsLayoutNVX indirectCommandsLayoutNVX)\n    {\n      m_indirectCommandsLayoutNVX = indirectCommandsLayoutNVX;\n      return *this;\n    }\n#endif\n\n    IndirectCommandsLayoutNVX& operator=( std::nullptr_t )\n    {\n      m_indirectCommandsLayoutNVX = VK_NULL_HANDLE;\n      return *this;\n    }\n\n    bool operator==(IndirectCommandsLayoutNVX const &rhs) const\n    {\n      return m_indirectCommandsLayoutNVX == rhs.m_indirectCommandsLayoutNVX;\n    }\n\n    bool operator!=(IndirectCommandsLayoutNVX const &rhs) const\n    {\n      return m_indirectCommandsLayoutNVX != rhs.m_indirectCommandsLayoutNVX;\n    }\n\n    bool operator<(IndirectCommandsLayoutNVX const &rhs) const\n    {\n      return m_indirectCommandsLayoutNVX < rhs.m_indirectCommandsLayoutNVX;\n    }\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT operator VkIndirectCommandsLayoutNVX() const\n    {\n      return m_indirectCommandsLayoutNVX;\n    }\n\n    explicit operator bool() const\n    {\n      return m_indirectCommandsLayoutNVX != VK_NULL_HANDLE;\n    }\n\n    bool operator!() const\n    {\n      return m_indirectCommandsLayoutNVX == VK_NULL_HANDLE;\n    }\n\n  private:\n    VkIndirectCommandsLayoutNVX m_indirectCommandsLayoutNVX;\n  };\n  static_assert( sizeof( IndirectCommandsLayoutNVX ) == sizeof( VkIndirectCommandsLayoutNVX ), \"handle and wrapper have different size!\" );\n\n  class DescriptorUpdateTemplateKHR\n  {\n  public:\n    DescriptorUpdateTemplateKHR()\n      : m_descriptorUpdateTemplateKHR(VK_NULL_HANDLE)\n    {}\n\n    DescriptorUpdateTemplateKHR( std::nullptr_t )\n      : m_descriptorUpdateTemplateKHR(VK_NULL_HANDLE)\n    {}\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT DescriptorUpdateTemplateKHR(VkDescriptorUpdateTemplateKHR descriptorUpdateTemplateKHR)\n       : m_descriptorUpdateTemplateKHR(descriptorUpdateTemplateKHR)\n    {}\n\n#if defined(VULKAN_HPP_TYPESAFE_CONVERSION)\n    DescriptorUpdateTemplateKHR& operator=(VkDescriptorUpdateTemplateKHR descriptorUpdateTemplateKHR)\n    {\n      m_descriptorUpdateTemplateKHR = descriptorUpdateTemplateKHR;\n      return *this;\n    }\n#endif\n\n    DescriptorUpdateTemplateKHR& operator=( std::nullptr_t )\n    {\n      m_descriptorUpdateTemplateKHR = VK_NULL_HANDLE;\n      return *this;\n    }\n\n    bool operator==(DescriptorUpdateTemplateKHR const &rhs) const\n    {\n      return m_descriptorUpdateTemplateKHR == rhs.m_descriptorUpdateTemplateKHR;\n    }\n\n    bool operator!=(DescriptorUpdateTemplateKHR const &rhs) const\n    {\n      return m_descriptorUpdateTemplateKHR != rhs.m_descriptorUpdateTemplateKHR;\n    }\n\n    bool operator<(DescriptorUpdateTemplateKHR const &rhs) const\n    {\n      return m_descriptorUpdateTemplateKHR < rhs.m_descriptorUpdateTemplateKHR;\n    }\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT operator VkDescriptorUpdateTemplateKHR() const\n    {\n      return m_descriptorUpdateTemplateKHR;\n    }\n\n    explicit operator bool() const\n    {\n      return m_descriptorUpdateTemplateKHR != VK_NULL_HANDLE;\n    }\n\n    bool operator!() const\n    {\n      return m_descriptorUpdateTemplateKHR == VK_NULL_HANDLE;\n    }\n\n  private:\n    VkDescriptorUpdateTemplateKHR m_descriptorUpdateTemplateKHR;\n  };\n  static_assert( sizeof( DescriptorUpdateTemplateKHR ) == sizeof( VkDescriptorUpdateTemplateKHR ), \"handle and wrapper have different size!\" );\n\n  class DisplayKHR\n  {\n  public:\n    DisplayKHR()\n      : m_displayKHR(VK_NULL_HANDLE)\n    {}\n\n    DisplayKHR( std::nullptr_t )\n      : m_displayKHR(VK_NULL_HANDLE)\n    {}\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT DisplayKHR(VkDisplayKHR displayKHR)\n       : m_displayKHR(displayKHR)\n    {}\n\n#if defined(VULKAN_HPP_TYPESAFE_CONVERSION)\n    DisplayKHR& operator=(VkDisplayKHR displayKHR)\n    {\n      m_displayKHR = displayKHR;\n      return *this;\n    }\n#endif\n\n    DisplayKHR& operator=( std::nullptr_t )\n    {\n      m_displayKHR = VK_NULL_HANDLE;\n      return *this;\n    }\n\n    bool operator==(DisplayKHR const &rhs) const\n    {\n      return m_displayKHR == rhs.m_displayKHR;\n    }\n\n    bool operator!=(DisplayKHR const &rhs) const\n    {\n      return m_displayKHR != rhs.m_displayKHR;\n    }\n\n    bool operator<(DisplayKHR const &rhs) const\n    {\n      return m_displayKHR < rhs.m_displayKHR;\n    }\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT operator VkDisplayKHR() const\n    {\n      return m_displayKHR;\n    }\n\n    explicit operator bool() const\n    {\n      return m_displayKHR != VK_NULL_HANDLE;\n    }\n\n    bool operator!() const\n    {\n      return m_displayKHR == VK_NULL_HANDLE;\n    }\n\n  private:\n    VkDisplayKHR m_displayKHR;\n  };\n  static_assert( sizeof( DisplayKHR ) == sizeof( VkDisplayKHR ), \"handle and wrapper have different size!\" );\n\n  class DisplayModeKHR\n  {\n  public:\n    DisplayModeKHR()\n      : m_displayModeKHR(VK_NULL_HANDLE)\n    {}\n\n    DisplayModeKHR( std::nullptr_t )\n      : m_displayModeKHR(VK_NULL_HANDLE)\n    {}\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT DisplayModeKHR(VkDisplayModeKHR displayModeKHR)\n       : m_displayModeKHR(displayModeKHR)\n    {}\n\n#if defined(VULKAN_HPP_TYPESAFE_CONVERSION)\n    DisplayModeKHR& operator=(VkDisplayModeKHR displayModeKHR)\n    {\n      m_displayModeKHR = displayModeKHR;\n      return *this;\n    }\n#endif\n\n    DisplayModeKHR& operator=( std::nullptr_t )\n    {\n      m_displayModeKHR = VK_NULL_HANDLE;\n      return *this;\n    }\n\n    bool operator==(DisplayModeKHR const &rhs) const\n    {\n      return m_displayModeKHR == rhs.m_displayModeKHR;\n    }\n\n    bool operator!=(DisplayModeKHR const &rhs) const\n    {\n      return m_displayModeKHR != rhs.m_displayModeKHR;\n    }\n\n    bool operator<(DisplayModeKHR const &rhs) const\n    {\n      return m_displayModeKHR < rhs.m_displayModeKHR;\n    }\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT operator VkDisplayModeKHR() const\n    {\n      return m_displayModeKHR;\n    }\n\n    explicit operator bool() const\n    {\n      return m_displayModeKHR != VK_NULL_HANDLE;\n    }\n\n    bool operator!() const\n    {\n      return m_displayModeKHR == VK_NULL_HANDLE;\n    }\n\n  private:\n    VkDisplayModeKHR m_displayModeKHR;\n  };\n  static_assert( sizeof( DisplayModeKHR ) == sizeof( VkDisplayModeKHR ), \"handle and wrapper have different size!\" );\n\n  class SurfaceKHR\n  {\n  public:\n    SurfaceKHR()\n      : m_surfaceKHR(VK_NULL_HANDLE)\n    {}\n\n    SurfaceKHR( std::nullptr_t )\n      : m_surfaceKHR(VK_NULL_HANDLE)\n    {}\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT SurfaceKHR(VkSurfaceKHR surfaceKHR)\n       : m_surfaceKHR(surfaceKHR)\n    {}\n\n#if defined(VULKAN_HPP_TYPESAFE_CONVERSION)\n    SurfaceKHR& operator=(VkSurfaceKHR surfaceKHR)\n    {\n      m_surfaceKHR = surfaceKHR;\n      return *this;\n    }\n#endif\n\n    SurfaceKHR& operator=( std::nullptr_t )\n    {\n      m_surfaceKHR = VK_NULL_HANDLE;\n      return *this;\n    }\n\n    bool operator==(SurfaceKHR const &rhs) const\n    {\n      return m_surfaceKHR == rhs.m_surfaceKHR;\n    }\n\n    bool operator!=(SurfaceKHR const &rhs) const\n    {\n      return m_surfaceKHR != rhs.m_surfaceKHR;\n    }\n\n    bool operator<(SurfaceKHR const &rhs) const\n    {\n      return m_surfaceKHR < rhs.m_surfaceKHR;\n    }\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT operator VkSurfaceKHR() const\n    {\n      return m_surfaceKHR;\n    }\n\n    explicit operator bool() const\n    {\n      return m_surfaceKHR != VK_NULL_HANDLE;\n    }\n\n    bool operator!() const\n    {\n      return m_surfaceKHR == VK_NULL_HANDLE;\n    }\n\n  private:\n    VkSurfaceKHR m_surfaceKHR;\n  };\n  static_assert( sizeof( SurfaceKHR ) == sizeof( VkSurfaceKHR ), \"handle and wrapper have different size!\" );\n\n  class SwapchainKHR\n  {\n  public:\n    SwapchainKHR()\n      : m_swapchainKHR(VK_NULL_HANDLE)\n    {}\n\n    SwapchainKHR( std::nullptr_t )\n      : m_swapchainKHR(VK_NULL_HANDLE)\n    {}\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT SwapchainKHR(VkSwapchainKHR swapchainKHR)\n       : m_swapchainKHR(swapchainKHR)\n    {}\n\n#if defined(VULKAN_HPP_TYPESAFE_CONVERSION)\n    SwapchainKHR& operator=(VkSwapchainKHR swapchainKHR)\n    {\n      m_swapchainKHR = swapchainKHR;\n      return *this;\n    }\n#endif\n\n    SwapchainKHR& operator=( std::nullptr_t )\n    {\n      m_swapchainKHR = VK_NULL_HANDLE;\n      return *this;\n    }\n\n    bool operator==(SwapchainKHR const &rhs) const\n    {\n      return m_swapchainKHR == rhs.m_swapchainKHR;\n    }\n\n    bool operator!=(SwapchainKHR const &rhs) const\n    {\n      return m_swapchainKHR != rhs.m_swapchainKHR;\n    }\n\n    bool operator<(SwapchainKHR const &rhs) const\n    {\n      return m_swapchainKHR < rhs.m_swapchainKHR;\n    }\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT operator VkSwapchainKHR() const\n    {\n      return m_swapchainKHR;\n    }\n\n    explicit operator bool() const\n    {\n      return m_swapchainKHR != VK_NULL_HANDLE;\n    }\n\n    bool operator!() const\n    {\n      return m_swapchainKHR == VK_NULL_HANDLE;\n    }\n\n  private:\n    VkSwapchainKHR m_swapchainKHR;\n  };\n  static_assert( sizeof( SwapchainKHR ) == sizeof( VkSwapchainKHR ), \"handle and wrapper have different size!\" );\n\n  class DebugReportCallbackEXT\n  {\n  public:\n    DebugReportCallbackEXT()\n      : m_debugReportCallbackEXT(VK_NULL_HANDLE)\n    {}\n\n    DebugReportCallbackEXT( std::nullptr_t )\n      : m_debugReportCallbackEXT(VK_NULL_HANDLE)\n    {}\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT DebugReportCallbackEXT(VkDebugReportCallbackEXT debugReportCallbackEXT)\n       : m_debugReportCallbackEXT(debugReportCallbackEXT)\n    {}\n\n#if defined(VULKAN_HPP_TYPESAFE_CONVERSION)\n    DebugReportCallbackEXT& operator=(VkDebugReportCallbackEXT debugReportCallbackEXT)\n    {\n      m_debugReportCallbackEXT = debugReportCallbackEXT;\n      return *this;\n    }\n#endif\n\n    DebugReportCallbackEXT& operator=( std::nullptr_t )\n    {\n      m_debugReportCallbackEXT = VK_NULL_HANDLE;\n      return *this;\n    }\n\n    bool operator==(DebugReportCallbackEXT const &rhs) const\n    {\n      return m_debugReportCallbackEXT == rhs.m_debugReportCallbackEXT;\n    }\n\n    bool operator!=(DebugReportCallbackEXT const &rhs) const\n    {\n      return m_debugReportCallbackEXT != rhs.m_debugReportCallbackEXT;\n    }\n\n    bool operator<(DebugReportCallbackEXT const &rhs) const\n    {\n      return m_debugReportCallbackEXT < rhs.m_debugReportCallbackEXT;\n    }\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT operator VkDebugReportCallbackEXT() const\n    {\n      return m_debugReportCallbackEXT;\n    }\n\n    explicit operator bool() const\n    {\n      return m_debugReportCallbackEXT != VK_NULL_HANDLE;\n    }\n\n    bool operator!() const\n    {\n      return m_debugReportCallbackEXT == VK_NULL_HANDLE;\n    }\n\n  private:\n    VkDebugReportCallbackEXT m_debugReportCallbackEXT;\n  };\n  static_assert( sizeof( DebugReportCallbackEXT ) == sizeof( VkDebugReportCallbackEXT ), \"handle and wrapper have different size!\" );\n\n  struct Offset2D\n  {\n    Offset2D( int32_t x_ = 0, int32_t y_ = 0 )\n      : x( x_ )\n      , y( y_ )\n    {\n    }\n\n    Offset2D( VkOffset2D const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(Offset2D) );\n    }\n\n    Offset2D& operator=( VkOffset2D const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(Offset2D) );\n      return *this;\n    }\n\n    Offset2D& setX( int32_t x_ )\n    {\n      x = x_;\n      return *this;\n    }\n\n    Offset2D& setY( int32_t y_ )\n    {\n      y = y_;\n      return *this;\n    }\n\n    operator const VkOffset2D&() const\n    {\n      return *reinterpret_cast<const VkOffset2D*>(this);\n    }\n\n    bool operator==( Offset2D const& rhs ) const\n    {\n      return ( x == rhs.x )\n          && ( y == rhs.y );\n    }\n\n    bool operator!=( Offset2D const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    int32_t x;\n    int32_t y;\n  };\n  static_assert( sizeof( Offset2D ) == sizeof( VkOffset2D ), \"struct and wrapper have different size!\" );\n\n  struct Offset3D\n  {\n    Offset3D( int32_t x_ = 0, int32_t y_ = 0, int32_t z_ = 0 )\n      : x( x_ )\n      , y( y_ )\n      , z( z_ )\n    {\n    }\n\n    Offset3D( VkOffset3D const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(Offset3D) );\n    }\n\n    Offset3D& operator=( VkOffset3D const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(Offset3D) );\n      return *this;\n    }\n\n    Offset3D& setX( int32_t x_ )\n    {\n      x = x_;\n      return *this;\n    }\n\n    Offset3D& setY( int32_t y_ )\n    {\n      y = y_;\n      return *this;\n    }\n\n    Offset3D& setZ( int32_t z_ )\n    {\n      z = z_;\n      return *this;\n    }\n\n    operator const VkOffset3D&() const\n    {\n      return *reinterpret_cast<const VkOffset3D*>(this);\n    }\n\n    bool operator==( Offset3D const& rhs ) const\n    {\n      return ( x == rhs.x )\n          && ( y == rhs.y )\n          && ( z == rhs.z );\n    }\n\n    bool operator!=( Offset3D const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    int32_t x;\n    int32_t y;\n    int32_t z;\n  };\n  static_assert( sizeof( Offset3D ) == sizeof( VkOffset3D ), \"struct and wrapper have different size!\" );\n\n  struct Extent2D\n  {\n    Extent2D( uint32_t width_ = 0, uint32_t height_ = 0 )\n      : width( width_ )\n      , height( height_ )\n    {\n    }\n\n    Extent2D( VkExtent2D const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(Extent2D) );\n    }\n\n    Extent2D& operator=( VkExtent2D const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(Extent2D) );\n      return *this;\n    }\n\n    Extent2D& setWidth( uint32_t width_ )\n    {\n      width = width_;\n      return *this;\n    }\n\n    Extent2D& setHeight( uint32_t height_ )\n    {\n      height = height_;\n      return *this;\n    }\n\n    operator const VkExtent2D&() const\n    {\n      return *reinterpret_cast<const VkExtent2D*>(this);\n    }\n\n    bool operator==( Extent2D const& rhs ) const\n    {\n      return ( width == rhs.width )\n          && ( height == rhs.height );\n    }\n\n    bool operator!=( Extent2D const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    uint32_t width;\n    uint32_t height;\n  };\n  static_assert( sizeof( Extent2D ) == sizeof( VkExtent2D ), \"struct and wrapper have different size!\" );\n\n  struct Extent3D\n  {\n    Extent3D( uint32_t width_ = 0, uint32_t height_ = 0, uint32_t depth_ = 0 )\n      : width( width_ )\n      , height( height_ )\n      , depth( depth_ )\n    {\n    }\n\n    Extent3D( VkExtent3D const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(Extent3D) );\n    }\n\n    Extent3D& operator=( VkExtent3D const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(Extent3D) );\n      return *this;\n    }\n\n    Extent3D& setWidth( uint32_t width_ )\n    {\n      width = width_;\n      return *this;\n    }\n\n    Extent3D& setHeight( uint32_t height_ )\n    {\n      height = height_;\n      return *this;\n    }\n\n    Extent3D& setDepth( uint32_t depth_ )\n    {\n      depth = depth_;\n      return *this;\n    }\n\n    operator const VkExtent3D&() const\n    {\n      return *reinterpret_cast<const VkExtent3D*>(this);\n    }\n\n    bool operator==( Extent3D const& rhs ) const\n    {\n      return ( width == rhs.width )\n          && ( height == rhs.height )\n          && ( depth == rhs.depth );\n    }\n\n    bool operator!=( Extent3D const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    uint32_t width;\n    uint32_t height;\n    uint32_t depth;\n  };\n  static_assert( sizeof( Extent3D ) == sizeof( VkExtent3D ), \"struct and wrapper have different size!\" );\n\n  struct Viewport\n  {\n    Viewport( float x_ = 0, float y_ = 0, float width_ = 0, float height_ = 0, float minDepth_ = 0, float maxDepth_ = 0 )\n      : x( x_ )\n      , y( y_ )\n      , width( width_ )\n      , height( height_ )\n      , minDepth( minDepth_ )\n      , maxDepth( maxDepth_ )\n    {\n    }\n\n    Viewport( VkViewport const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(Viewport) );\n    }\n\n    Viewport& operator=( VkViewport const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(Viewport) );\n      return *this;\n    }\n\n    Viewport& setX( float x_ )\n    {\n      x = x_;\n      return *this;\n    }\n\n    Viewport& setY( float y_ )\n    {\n      y = y_;\n      return *this;\n    }\n\n    Viewport& setWidth( float width_ )\n    {\n      width = width_;\n      return *this;\n    }\n\n    Viewport& setHeight( float height_ )\n    {\n      height = height_;\n      return *this;\n    }\n\n    Viewport& setMinDepth( float minDepth_ )\n    {\n      minDepth = minDepth_;\n      return *this;\n    }\n\n    Viewport& setMaxDepth( float maxDepth_ )\n    {\n      maxDepth = maxDepth_;\n      return *this;\n    }\n\n    operator const VkViewport&() const\n    {\n      return *reinterpret_cast<const VkViewport*>(this);\n    }\n\n    bool operator==( Viewport const& rhs ) const\n    {\n      return ( x == rhs.x )\n          && ( y == rhs.y )\n          && ( width == rhs.width )\n          && ( height == rhs.height )\n          && ( minDepth == rhs.minDepth )\n          && ( maxDepth == rhs.maxDepth );\n    }\n\n    bool operator!=( Viewport const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    float x;\n    float y;\n    float width;\n    float height;\n    float minDepth;\n    float maxDepth;\n  };\n  static_assert( sizeof( Viewport ) == sizeof( VkViewport ), \"struct and wrapper have different size!\" );\n\n  struct Rect2D\n  {\n    Rect2D( Offset2D offset_ = Offset2D(), Extent2D extent_ = Extent2D() )\n      : offset( offset_ )\n      , extent( extent_ )\n    {\n    }\n\n    Rect2D( VkRect2D const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(Rect2D) );\n    }\n\n    Rect2D& operator=( VkRect2D const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(Rect2D) );\n      return *this;\n    }\n\n    Rect2D& setOffset( Offset2D offset_ )\n    {\n      offset = offset_;\n      return *this;\n    }\n\n    Rect2D& setExtent( Extent2D extent_ )\n    {\n      extent = extent_;\n      return *this;\n    }\n\n    operator const VkRect2D&() const\n    {\n      return *reinterpret_cast<const VkRect2D*>(this);\n    }\n\n    bool operator==( Rect2D const& rhs ) const\n    {\n      return ( offset == rhs.offset )\n          && ( extent == rhs.extent );\n    }\n\n    bool operator!=( Rect2D const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    Offset2D offset;\n    Extent2D extent;\n  };\n  static_assert( sizeof( Rect2D ) == sizeof( VkRect2D ), \"struct and wrapper have different size!\" );\n\n  struct ClearRect\n  {\n    ClearRect( Rect2D rect_ = Rect2D(), uint32_t baseArrayLayer_ = 0, uint32_t layerCount_ = 0 )\n      : rect( rect_ )\n      , baseArrayLayer( baseArrayLayer_ )\n      , layerCount( layerCount_ )\n    {\n    }\n\n    ClearRect( VkClearRect const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ClearRect) );\n    }\n\n    ClearRect& operator=( VkClearRect const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ClearRect) );\n      return *this;\n    }\n\n    ClearRect& setRect( Rect2D rect_ )\n    {\n      rect = rect_;\n      return *this;\n    }\n\n    ClearRect& setBaseArrayLayer( uint32_t baseArrayLayer_ )\n    {\n      baseArrayLayer = baseArrayLayer_;\n      return *this;\n    }\n\n    ClearRect& setLayerCount( uint32_t layerCount_ )\n    {\n      layerCount = layerCount_;\n      return *this;\n    }\n\n    operator const VkClearRect&() const\n    {\n      return *reinterpret_cast<const VkClearRect*>(this);\n    }\n\n    bool operator==( ClearRect const& rhs ) const\n    {\n      return ( rect == rhs.rect )\n          && ( baseArrayLayer == rhs.baseArrayLayer )\n          && ( layerCount == rhs.layerCount );\n    }\n\n    bool operator!=( ClearRect const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    Rect2D rect;\n    uint32_t baseArrayLayer;\n    uint32_t layerCount;\n  };\n  static_assert( sizeof( ClearRect ) == sizeof( VkClearRect ), \"struct and wrapper have different size!\" );\n\n  struct ExtensionProperties\n  {\n    operator const VkExtensionProperties&() const\n    {\n      return *reinterpret_cast<const VkExtensionProperties*>(this);\n    }\n\n    bool operator==( ExtensionProperties const& rhs ) const\n    {\n      return ( memcmp( extensionName, rhs.extensionName, VK_MAX_EXTENSION_NAME_SIZE * sizeof( char ) ) == 0 )\n          && ( specVersion == rhs.specVersion );\n    }\n\n    bool operator!=( ExtensionProperties const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    char extensionName[VK_MAX_EXTENSION_NAME_SIZE];\n    uint32_t specVersion;\n  };\n  static_assert( sizeof( ExtensionProperties ) == sizeof( VkExtensionProperties ), \"struct and wrapper have different size!\" );\n\n  struct LayerProperties\n  {\n    operator const VkLayerProperties&() const\n    {\n      return *reinterpret_cast<const VkLayerProperties*>(this);\n    }\n\n    bool operator==( LayerProperties const& rhs ) const\n    {\n      return ( memcmp( layerName, rhs.layerName, VK_MAX_EXTENSION_NAME_SIZE * sizeof( char ) ) == 0 )\n          && ( specVersion == rhs.specVersion )\n          && ( implementationVersion == rhs.implementationVersion )\n          && ( memcmp( description, rhs.description, VK_MAX_DESCRIPTION_SIZE * sizeof( char ) ) == 0 );\n    }\n\n    bool operator!=( LayerProperties const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    char layerName[VK_MAX_EXTENSION_NAME_SIZE];\n    uint32_t specVersion;\n    uint32_t implementationVersion;\n    char description[VK_MAX_DESCRIPTION_SIZE];\n  };\n  static_assert( sizeof( LayerProperties ) == sizeof( VkLayerProperties ), \"struct and wrapper have different size!\" );\n\n  struct AllocationCallbacks\n  {\n    AllocationCallbacks( void* pUserData_ = nullptr, PFN_vkAllocationFunction pfnAllocation_ = nullptr, PFN_vkReallocationFunction pfnReallocation_ = nullptr, PFN_vkFreeFunction pfnFree_ = nullptr, PFN_vkInternalAllocationNotification pfnInternalAllocation_ = nullptr, PFN_vkInternalFreeNotification pfnInternalFree_ = nullptr )\n      : pUserData( pUserData_ )\n      , pfnAllocation( pfnAllocation_ )\n      , pfnReallocation( pfnReallocation_ )\n      , pfnFree( pfnFree_ )\n      , pfnInternalAllocation( pfnInternalAllocation_ )\n      , pfnInternalFree( pfnInternalFree_ )\n    {\n    }\n\n    AllocationCallbacks( VkAllocationCallbacks const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(AllocationCallbacks) );\n    }\n\n    AllocationCallbacks& operator=( VkAllocationCallbacks const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(AllocationCallbacks) );\n      return *this;\n    }\n\n    AllocationCallbacks& setPUserData( void* pUserData_ )\n    {\n      pUserData = pUserData_;\n      return *this;\n    }\n\n    AllocationCallbacks& setPfnAllocation( PFN_vkAllocationFunction pfnAllocation_ )\n    {\n      pfnAllocation = pfnAllocation_;\n      return *this;\n    }\n\n    AllocationCallbacks& setPfnReallocation( PFN_vkReallocationFunction pfnReallocation_ )\n    {\n      pfnReallocation = pfnReallocation_;\n      return *this;\n    }\n\n    AllocationCallbacks& setPfnFree( PFN_vkFreeFunction pfnFree_ )\n    {\n      pfnFree = pfnFree_;\n      return *this;\n    }\n\n    AllocationCallbacks& setPfnInternalAllocation( PFN_vkInternalAllocationNotification pfnInternalAllocation_ )\n    {\n      pfnInternalAllocation = pfnInternalAllocation_;\n      return *this;\n    }\n\n    AllocationCallbacks& setPfnInternalFree( PFN_vkInternalFreeNotification pfnInternalFree_ )\n    {\n      pfnInternalFree = pfnInternalFree_;\n      return *this;\n    }\n\n    operator const VkAllocationCallbacks&() const\n    {\n      return *reinterpret_cast<const VkAllocationCallbacks*>(this);\n    }\n\n    bool operator==( AllocationCallbacks const& rhs ) const\n    {\n      return ( pUserData == rhs.pUserData )\n          && ( pfnAllocation == rhs.pfnAllocation )\n          && ( pfnReallocation == rhs.pfnReallocation )\n          && ( pfnFree == rhs.pfnFree )\n          && ( pfnInternalAllocation == rhs.pfnInternalAllocation )\n          && ( pfnInternalFree == rhs.pfnInternalFree );\n    }\n\n    bool operator!=( AllocationCallbacks const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    void* pUserData;\n    PFN_vkAllocationFunction pfnAllocation;\n    PFN_vkReallocationFunction pfnReallocation;\n    PFN_vkFreeFunction pfnFree;\n    PFN_vkInternalAllocationNotification pfnInternalAllocation;\n    PFN_vkInternalFreeNotification pfnInternalFree;\n  };\n  static_assert( sizeof( AllocationCallbacks ) == sizeof( VkAllocationCallbacks ), \"struct and wrapper have different size!\" );\n\n  struct MemoryRequirements\n  {\n    operator const VkMemoryRequirements&() const\n    {\n      return *reinterpret_cast<const VkMemoryRequirements*>(this);\n    }\n\n    bool operator==( MemoryRequirements const& rhs ) const\n    {\n      return ( size == rhs.size )\n          && ( alignment == rhs.alignment )\n          && ( memoryTypeBits == rhs.memoryTypeBits );\n    }\n\n    bool operator!=( MemoryRequirements const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    DeviceSize size;\n    DeviceSize alignment;\n    uint32_t memoryTypeBits;\n  };\n  static_assert( sizeof( MemoryRequirements ) == sizeof( VkMemoryRequirements ), \"struct and wrapper have different size!\" );\n\n  struct DescriptorBufferInfo\n  {\n    DescriptorBufferInfo( Buffer buffer_ = Buffer(), DeviceSize offset_ = 0, DeviceSize range_ = 0 )\n      : buffer( buffer_ )\n      , offset( offset_ )\n      , range( range_ )\n    {\n    }\n\n    DescriptorBufferInfo( VkDescriptorBufferInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DescriptorBufferInfo) );\n    }\n\n    DescriptorBufferInfo& operator=( VkDescriptorBufferInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DescriptorBufferInfo) );\n      return *this;\n    }\n\n    DescriptorBufferInfo& setBuffer( Buffer buffer_ )\n    {\n      buffer = buffer_;\n      return *this;\n    }\n\n    DescriptorBufferInfo& setOffset( DeviceSize offset_ )\n    {\n      offset = offset_;\n      return *this;\n    }\n\n    DescriptorBufferInfo& setRange( DeviceSize range_ )\n    {\n      range = range_;\n      return *this;\n    }\n\n    operator const VkDescriptorBufferInfo&() const\n    {\n      return *reinterpret_cast<const VkDescriptorBufferInfo*>(this);\n    }\n\n    bool operator==( DescriptorBufferInfo const& rhs ) const\n    {\n      return ( buffer == rhs.buffer )\n          && ( offset == rhs.offset )\n          && ( range == rhs.range );\n    }\n\n    bool operator!=( DescriptorBufferInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    Buffer buffer;\n    DeviceSize offset;\n    DeviceSize range;\n  };\n  static_assert( sizeof( DescriptorBufferInfo ) == sizeof( VkDescriptorBufferInfo ), \"struct and wrapper have different size!\" );\n\n  struct SubresourceLayout\n  {\n    operator const VkSubresourceLayout&() const\n    {\n      return *reinterpret_cast<const VkSubresourceLayout*>(this);\n    }\n\n    bool operator==( SubresourceLayout const& rhs ) const\n    {\n      return ( offset == rhs.offset )\n          && ( size == rhs.size )\n          && ( rowPitch == rhs.rowPitch )\n          && ( arrayPitch == rhs.arrayPitch )\n          && ( depthPitch == rhs.depthPitch );\n    }\n\n    bool operator!=( SubresourceLayout const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    DeviceSize offset;\n    DeviceSize size;\n    DeviceSize rowPitch;\n    DeviceSize arrayPitch;\n    DeviceSize depthPitch;\n  };\n  static_assert( sizeof( SubresourceLayout ) == sizeof( VkSubresourceLayout ), \"struct and wrapper have different size!\" );\n\n  struct BufferCopy\n  {\n    BufferCopy( DeviceSize srcOffset_ = 0, DeviceSize dstOffset_ = 0, DeviceSize size_ = 0 )\n      : srcOffset( srcOffset_ )\n      , dstOffset( dstOffset_ )\n      , size( size_ )\n    {\n    }\n\n    BufferCopy( VkBufferCopy const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(BufferCopy) );\n    }\n\n    BufferCopy& operator=( VkBufferCopy const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(BufferCopy) );\n      return *this;\n    }\n\n    BufferCopy& setSrcOffset( DeviceSize srcOffset_ )\n    {\n      srcOffset = srcOffset_;\n      return *this;\n    }\n\n    BufferCopy& setDstOffset( DeviceSize dstOffset_ )\n    {\n      dstOffset = dstOffset_;\n      return *this;\n    }\n\n    BufferCopy& setSize( DeviceSize size_ )\n    {\n      size = size_;\n      return *this;\n    }\n\n    operator const VkBufferCopy&() const\n    {\n      return *reinterpret_cast<const VkBufferCopy*>(this);\n    }\n\n    bool operator==( BufferCopy const& rhs ) const\n    {\n      return ( srcOffset == rhs.srcOffset )\n          && ( dstOffset == rhs.dstOffset )\n          && ( size == rhs.size );\n    }\n\n    bool operator!=( BufferCopy const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    DeviceSize srcOffset;\n    DeviceSize dstOffset;\n    DeviceSize size;\n  };\n  static_assert( sizeof( BufferCopy ) == sizeof( VkBufferCopy ), \"struct and wrapper have different size!\" );\n\n  struct SpecializationMapEntry\n  {\n    SpecializationMapEntry( uint32_t constantID_ = 0, uint32_t offset_ = 0, size_t size_ = 0 )\n      : constantID( constantID_ )\n      , offset( offset_ )\n      , size( size_ )\n    {\n    }\n\n    SpecializationMapEntry( VkSpecializationMapEntry const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(SpecializationMapEntry) );\n    }\n\n    SpecializationMapEntry& operator=( VkSpecializationMapEntry const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(SpecializationMapEntry) );\n      return *this;\n    }\n\n    SpecializationMapEntry& setConstantID( uint32_t constantID_ )\n    {\n      constantID = constantID_;\n      return *this;\n    }\n\n    SpecializationMapEntry& setOffset( uint32_t offset_ )\n    {\n      offset = offset_;\n      return *this;\n    }\n\n    SpecializationMapEntry& setSize( size_t size_ )\n    {\n      size = size_;\n      return *this;\n    }\n\n    operator const VkSpecializationMapEntry&() const\n    {\n      return *reinterpret_cast<const VkSpecializationMapEntry*>(this);\n    }\n\n    bool operator==( SpecializationMapEntry const& rhs ) const\n    {\n      return ( constantID == rhs.constantID )\n          && ( offset == rhs.offset )\n          && ( size == rhs.size );\n    }\n\n    bool operator!=( SpecializationMapEntry const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    uint32_t constantID;\n    uint32_t offset;\n    size_t size;\n  };\n  static_assert( sizeof( SpecializationMapEntry ) == sizeof( VkSpecializationMapEntry ), \"struct and wrapper have different size!\" );\n\n  struct SpecializationInfo\n  {\n    SpecializationInfo( uint32_t mapEntryCount_ = 0, const SpecializationMapEntry* pMapEntries_ = nullptr, size_t dataSize_ = 0, const void* pData_ = nullptr )\n      : mapEntryCount( mapEntryCount_ )\n      , pMapEntries( pMapEntries_ )\n      , dataSize( dataSize_ )\n      , pData( pData_ )\n    {\n    }\n\n    SpecializationInfo( VkSpecializationInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(SpecializationInfo) );\n    }\n\n    SpecializationInfo& operator=( VkSpecializationInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(SpecializationInfo) );\n      return *this;\n    }\n\n    SpecializationInfo& setMapEntryCount( uint32_t mapEntryCount_ )\n    {\n      mapEntryCount = mapEntryCount_;\n      return *this;\n    }\n\n    SpecializationInfo& setPMapEntries( const SpecializationMapEntry* pMapEntries_ )\n    {\n      pMapEntries = pMapEntries_;\n      return *this;\n    }\n\n    SpecializationInfo& setDataSize( size_t dataSize_ )\n    {\n      dataSize = dataSize_;\n      return *this;\n    }\n\n    SpecializationInfo& setPData( const void* pData_ )\n    {\n      pData = pData_;\n      return *this;\n    }\n\n    operator const VkSpecializationInfo&() const\n    {\n      return *reinterpret_cast<const VkSpecializationInfo*>(this);\n    }\n\n    bool operator==( SpecializationInfo const& rhs ) const\n    {\n      return ( mapEntryCount == rhs.mapEntryCount )\n          && ( pMapEntries == rhs.pMapEntries )\n          && ( dataSize == rhs.dataSize )\n          && ( pData == rhs.pData );\n    }\n\n    bool operator!=( SpecializationInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    uint32_t mapEntryCount;\n    const SpecializationMapEntry* pMapEntries;\n    size_t dataSize;\n    const void* pData;\n  };\n  static_assert( sizeof( SpecializationInfo ) == sizeof( VkSpecializationInfo ), \"struct and wrapper have different size!\" );\n\n  union ClearColorValue\n  {\n    ClearColorValue( const std::array<float,4>& float32_ = { {0} } )\n    {\n      memcpy( &float32, float32_.data(), 4 * sizeof( float ) );\n    }\n\n    ClearColorValue( const std::array<int32_t,4>& int32_ )\n    {\n      memcpy( &int32, int32_.data(), 4 * sizeof( int32_t ) );\n    }\n\n    ClearColorValue( const std::array<uint32_t,4>& uint32_ )\n    {\n      memcpy( &uint32, uint32_.data(), 4 * sizeof( uint32_t ) );\n    }\n\n    ClearColorValue& setFloat32( std::array<float,4> float32_ )\n    {\n      memcpy( &float32, float32_.data(), 4 * sizeof( float ) );\n      return *this;\n    }\n\n    ClearColorValue& setInt32( std::array<int32_t,4> int32_ )\n    {\n      memcpy( &int32, int32_.data(), 4 * sizeof( int32_t ) );\n      return *this;\n    }\n\n    ClearColorValue& setUint32( std::array<uint32_t,4> uint32_ )\n    {\n      memcpy( &uint32, uint32_.data(), 4 * sizeof( uint32_t ) );\n      return *this;\n    }\n\n    operator VkClearColorValue const& () const\n    {\n      return *reinterpret_cast<const VkClearColorValue*>(this);\n    }\n\n    float float32[4];\n    int32_t int32[4];\n    uint32_t uint32[4];\n  };\n\n  struct ClearDepthStencilValue\n  {\n    ClearDepthStencilValue( float depth_ = 0, uint32_t stencil_ = 0 )\n      : depth( depth_ )\n      , stencil( stencil_ )\n    {\n    }\n\n    ClearDepthStencilValue( VkClearDepthStencilValue const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ClearDepthStencilValue) );\n    }\n\n    ClearDepthStencilValue& operator=( VkClearDepthStencilValue const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ClearDepthStencilValue) );\n      return *this;\n    }\n\n    ClearDepthStencilValue& setDepth( float depth_ )\n    {\n      depth = depth_;\n      return *this;\n    }\n\n    ClearDepthStencilValue& setStencil( uint32_t stencil_ )\n    {\n      stencil = stencil_;\n      return *this;\n    }\n\n    operator const VkClearDepthStencilValue&() const\n    {\n      return *reinterpret_cast<const VkClearDepthStencilValue*>(this);\n    }\n\n    bool operator==( ClearDepthStencilValue const& rhs ) const\n    {\n      return ( depth == rhs.depth )\n          && ( stencil == rhs.stencil );\n    }\n\n    bool operator!=( ClearDepthStencilValue const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    float depth;\n    uint32_t stencil;\n  };\n  static_assert( sizeof( ClearDepthStencilValue ) == sizeof( VkClearDepthStencilValue ), \"struct and wrapper have different size!\" );\n\n  union ClearValue\n  {\n    ClearValue( ClearColorValue color_ = ClearColorValue() )\n    {\n      color = color_;\n    }\n\n    ClearValue( ClearDepthStencilValue depthStencil_ )\n    {\n      depthStencil = depthStencil_;\n    }\n\n    ClearValue& setColor( ClearColorValue color_ )\n    {\n      color = color_;\n      return *this;\n    }\n\n    ClearValue& setDepthStencil( ClearDepthStencilValue depthStencil_ )\n    {\n      depthStencil = depthStencil_;\n      return *this;\n    }\n\n    operator VkClearValue const& () const\n    {\n      return *reinterpret_cast<const VkClearValue*>(this);\n    }\n\n#ifdef VULKAN_HPP_HAS_UNRESTRICTED_UNIONS\n    ClearColorValue color;\n    ClearDepthStencilValue depthStencil;\n#else\n    VkClearColorValue color;\n    VkClearDepthStencilValue depthStencil;\n#endif  // VULKAN_HPP_HAS_UNRESTRICTED_UNIONS\n  };\n\n  struct PhysicalDeviceFeatures\n  {\n    PhysicalDeviceFeatures( Bool32 robustBufferAccess_ = 0, Bool32 fullDrawIndexUint32_ = 0, Bool32 imageCubeArray_ = 0, Bool32 independentBlend_ = 0, Bool32 geometryShader_ = 0, Bool32 tessellationShader_ = 0, Bool32 sampleRateShading_ = 0, Bool32 dualSrcBlend_ = 0, Bool32 logicOp_ = 0, Bool32 multiDrawIndirect_ = 0, Bool32 drawIndirectFirstInstance_ = 0, Bool32 depthClamp_ = 0, Bool32 depthBiasClamp_ = 0, Bool32 fillModeNonSolid_ = 0, Bool32 depthBounds_ = 0, Bool32 wideLines_ = 0, Bool32 largePoints_ = 0, Bool32 alphaToOne_ = 0, Bool32 multiViewport_ = 0, Bool32 samplerAnisotropy_ = 0, Bool32 textureCompressionETC2_ = 0, Bool32 textureCompressionASTC_LDR_ = 0, Bool32 textureCompressionBC_ = 0, Bool32 occlusionQueryPrecise_ = 0, Bool32 pipelineStatisticsQuery_ = 0, Bool32 vertexPipelineStoresAndAtomics_ = 0, Bool32 fragmentStoresAndAtomics_ = 0, Bool32 shaderTessellationAndGeometryPointSize_ = 0, Bool32 shaderImageGatherExtended_ = 0, Bool32 shaderStorageImageExtendedFormats_ = 0, Bool32 shaderStorageImageMultisample_ = 0, Bool32 shaderStorageImageReadWithoutFormat_ = 0, Bool32 shaderStorageImageWriteWithoutFormat_ = 0, Bool32 shaderUniformBufferArrayDynamicIndexing_ = 0, Bool32 shaderSampledImageArrayDynamicIndexing_ = 0, Bool32 shaderStorageBufferArrayDynamicIndexing_ = 0, Bool32 shaderStorageImageArrayDynamicIndexing_ = 0, Bool32 shaderClipDistance_ = 0, Bool32 shaderCullDistance_ = 0, Bool32 shaderFloat64_ = 0, Bool32 shaderInt64_ = 0, Bool32 shaderInt16_ = 0, Bool32 shaderResourceResidency_ = 0, Bool32 shaderResourceMinLod_ = 0, Bool32 sparseBinding_ = 0, Bool32 sparseResidencyBuffer_ = 0, Bool32 sparseResidencyImage2D_ = 0, Bool32 sparseResidencyImage3D_ = 0, Bool32 sparseResidency2Samples_ = 0, Bool32 sparseResidency4Samples_ = 0, Bool32 sparseResidency8Samples_ = 0, Bool32 sparseResidency16Samples_ = 0, Bool32 sparseResidencyAliased_ = 0, Bool32 variableMultisampleRate_ = 0, Bool32 inheritedQueries_ = 0 )\n      : robustBufferAccess( robustBufferAccess_ )\n      , fullDrawIndexUint32( fullDrawIndexUint32_ )\n      , imageCubeArray( imageCubeArray_ )\n      , independentBlend( independentBlend_ )\n      , geometryShader( geometryShader_ )\n      , tessellationShader( tessellationShader_ )\n      , sampleRateShading( sampleRateShading_ )\n      , dualSrcBlend( dualSrcBlend_ )\n      , logicOp( logicOp_ )\n      , multiDrawIndirect( multiDrawIndirect_ )\n      , drawIndirectFirstInstance( drawIndirectFirstInstance_ )\n      , depthClamp( depthClamp_ )\n      , depthBiasClamp( depthBiasClamp_ )\n      , fillModeNonSolid( fillModeNonSolid_ )\n      , depthBounds( depthBounds_ )\n      , wideLines( wideLines_ )\n      , largePoints( largePoints_ )\n      , alphaToOne( alphaToOne_ )\n      , multiViewport( multiViewport_ )\n      , samplerAnisotropy( samplerAnisotropy_ )\n      , textureCompressionETC2( textureCompressionETC2_ )\n      , textureCompressionASTC_LDR( textureCompressionASTC_LDR_ )\n      , textureCompressionBC( textureCompressionBC_ )\n      , occlusionQueryPrecise( occlusionQueryPrecise_ )\n      , pipelineStatisticsQuery( pipelineStatisticsQuery_ )\n      , vertexPipelineStoresAndAtomics( vertexPipelineStoresAndAtomics_ )\n      , fragmentStoresAndAtomics( fragmentStoresAndAtomics_ )\n      , shaderTessellationAndGeometryPointSize( shaderTessellationAndGeometryPointSize_ )\n      , shaderImageGatherExtended( shaderImageGatherExtended_ )\n      , shaderStorageImageExtendedFormats( shaderStorageImageExtendedFormats_ )\n      , shaderStorageImageMultisample( shaderStorageImageMultisample_ )\n      , shaderStorageImageReadWithoutFormat( shaderStorageImageReadWithoutFormat_ )\n      , shaderStorageImageWriteWithoutFormat( shaderStorageImageWriteWithoutFormat_ )\n      , shaderUniformBufferArrayDynamicIndexing( shaderUniformBufferArrayDynamicIndexing_ )\n      , shaderSampledImageArrayDynamicIndexing( shaderSampledImageArrayDynamicIndexing_ )\n      , shaderStorageBufferArrayDynamicIndexing( shaderStorageBufferArrayDynamicIndexing_ )\n      , shaderStorageImageArrayDynamicIndexing( shaderStorageImageArrayDynamicIndexing_ )\n      , shaderClipDistance( shaderClipDistance_ )\n      , shaderCullDistance( shaderCullDistance_ )\n      , shaderFloat64( shaderFloat64_ )\n      , shaderInt64( shaderInt64_ )\n      , shaderInt16( shaderInt16_ )\n      , shaderResourceResidency( shaderResourceResidency_ )\n      , shaderResourceMinLod( shaderResourceMinLod_ )\n      , sparseBinding( sparseBinding_ )\n      , sparseResidencyBuffer( sparseResidencyBuffer_ )\n      , sparseResidencyImage2D( sparseResidencyImage2D_ )\n      , sparseResidencyImage3D( sparseResidencyImage3D_ )\n      , sparseResidency2Samples( sparseResidency2Samples_ )\n      , sparseResidency4Samples( sparseResidency4Samples_ )\n      , sparseResidency8Samples( sparseResidency8Samples_ )\n      , sparseResidency16Samples( sparseResidency16Samples_ )\n      , sparseResidencyAliased( sparseResidencyAliased_ )\n      , variableMultisampleRate( variableMultisampleRate_ )\n      , inheritedQueries( inheritedQueries_ )\n    {\n    }\n\n    PhysicalDeviceFeatures( VkPhysicalDeviceFeatures const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PhysicalDeviceFeatures) );\n    }\n\n    PhysicalDeviceFeatures& operator=( VkPhysicalDeviceFeatures const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PhysicalDeviceFeatures) );\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setRobustBufferAccess( Bool32 robustBufferAccess_ )\n    {\n      robustBufferAccess = robustBufferAccess_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setFullDrawIndexUint32( Bool32 fullDrawIndexUint32_ )\n    {\n      fullDrawIndexUint32 = fullDrawIndexUint32_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setImageCubeArray( Bool32 imageCubeArray_ )\n    {\n      imageCubeArray = imageCubeArray_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setIndependentBlend( Bool32 independentBlend_ )\n    {\n      independentBlend = independentBlend_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setGeometryShader( Bool32 geometryShader_ )\n    {\n      geometryShader = geometryShader_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setTessellationShader( Bool32 tessellationShader_ )\n    {\n      tessellationShader = tessellationShader_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setSampleRateShading( Bool32 sampleRateShading_ )\n    {\n      sampleRateShading = sampleRateShading_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setDualSrcBlend( Bool32 dualSrcBlend_ )\n    {\n      dualSrcBlend = dualSrcBlend_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setLogicOp( Bool32 logicOp_ )\n    {\n      logicOp = logicOp_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setMultiDrawIndirect( Bool32 multiDrawIndirect_ )\n    {\n      multiDrawIndirect = multiDrawIndirect_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setDrawIndirectFirstInstance( Bool32 drawIndirectFirstInstance_ )\n    {\n      drawIndirectFirstInstance = drawIndirectFirstInstance_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setDepthClamp( Bool32 depthClamp_ )\n    {\n      depthClamp = depthClamp_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setDepthBiasClamp( Bool32 depthBiasClamp_ )\n    {\n      depthBiasClamp = depthBiasClamp_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setFillModeNonSolid( Bool32 fillModeNonSolid_ )\n    {\n      fillModeNonSolid = fillModeNonSolid_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setDepthBounds( Bool32 depthBounds_ )\n    {\n      depthBounds = depthBounds_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setWideLines( Bool32 wideLines_ )\n    {\n      wideLines = wideLines_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setLargePoints( Bool32 largePoints_ )\n    {\n      largePoints = largePoints_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setAlphaToOne( Bool32 alphaToOne_ )\n    {\n      alphaToOne = alphaToOne_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setMultiViewport( Bool32 multiViewport_ )\n    {\n      multiViewport = multiViewport_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setSamplerAnisotropy( Bool32 samplerAnisotropy_ )\n    {\n      samplerAnisotropy = samplerAnisotropy_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setTextureCompressionETC2( Bool32 textureCompressionETC2_ )\n    {\n      textureCompressionETC2 = textureCompressionETC2_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setTextureCompressionASTC_LDR( Bool32 textureCompressionASTC_LDR_ )\n    {\n      textureCompressionASTC_LDR = textureCompressionASTC_LDR_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setTextureCompressionBC( Bool32 textureCompressionBC_ )\n    {\n      textureCompressionBC = textureCompressionBC_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setOcclusionQueryPrecise( Bool32 occlusionQueryPrecise_ )\n    {\n      occlusionQueryPrecise = occlusionQueryPrecise_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setPipelineStatisticsQuery( Bool32 pipelineStatisticsQuery_ )\n    {\n      pipelineStatisticsQuery = pipelineStatisticsQuery_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setVertexPipelineStoresAndAtomics( Bool32 vertexPipelineStoresAndAtomics_ )\n    {\n      vertexPipelineStoresAndAtomics = vertexPipelineStoresAndAtomics_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setFragmentStoresAndAtomics( Bool32 fragmentStoresAndAtomics_ )\n    {\n      fragmentStoresAndAtomics = fragmentStoresAndAtomics_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setShaderTessellationAndGeometryPointSize( Bool32 shaderTessellationAndGeometryPointSize_ )\n    {\n      shaderTessellationAndGeometryPointSize = shaderTessellationAndGeometryPointSize_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setShaderImageGatherExtended( Bool32 shaderImageGatherExtended_ )\n    {\n      shaderImageGatherExtended = shaderImageGatherExtended_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setShaderStorageImageExtendedFormats( Bool32 shaderStorageImageExtendedFormats_ )\n    {\n      shaderStorageImageExtendedFormats = shaderStorageImageExtendedFormats_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setShaderStorageImageMultisample( Bool32 shaderStorageImageMultisample_ )\n    {\n      shaderStorageImageMultisample = shaderStorageImageMultisample_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setShaderStorageImageReadWithoutFormat( Bool32 shaderStorageImageReadWithoutFormat_ )\n    {\n      shaderStorageImageReadWithoutFormat = shaderStorageImageReadWithoutFormat_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setShaderStorageImageWriteWithoutFormat( Bool32 shaderStorageImageWriteWithoutFormat_ )\n    {\n      shaderStorageImageWriteWithoutFormat = shaderStorageImageWriteWithoutFormat_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setShaderUniformBufferArrayDynamicIndexing( Bool32 shaderUniformBufferArrayDynamicIndexing_ )\n    {\n      shaderUniformBufferArrayDynamicIndexing = shaderUniformBufferArrayDynamicIndexing_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setShaderSampledImageArrayDynamicIndexing( Bool32 shaderSampledImageArrayDynamicIndexing_ )\n    {\n      shaderSampledImageArrayDynamicIndexing = shaderSampledImageArrayDynamicIndexing_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setShaderStorageBufferArrayDynamicIndexing( Bool32 shaderStorageBufferArrayDynamicIndexing_ )\n    {\n      shaderStorageBufferArrayDynamicIndexing = shaderStorageBufferArrayDynamicIndexing_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setShaderStorageImageArrayDynamicIndexing( Bool32 shaderStorageImageArrayDynamicIndexing_ )\n    {\n      shaderStorageImageArrayDynamicIndexing = shaderStorageImageArrayDynamicIndexing_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setShaderClipDistance( Bool32 shaderClipDistance_ )\n    {\n      shaderClipDistance = shaderClipDistance_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setShaderCullDistance( Bool32 shaderCullDistance_ )\n    {\n      shaderCullDistance = shaderCullDistance_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setShaderFloat64( Bool32 shaderFloat64_ )\n    {\n      shaderFloat64 = shaderFloat64_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setShaderInt64( Bool32 shaderInt64_ )\n    {\n      shaderInt64 = shaderInt64_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setShaderInt16( Bool32 shaderInt16_ )\n    {\n      shaderInt16 = shaderInt16_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setShaderResourceResidency( Bool32 shaderResourceResidency_ )\n    {\n      shaderResourceResidency = shaderResourceResidency_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setShaderResourceMinLod( Bool32 shaderResourceMinLod_ )\n    {\n      shaderResourceMinLod = shaderResourceMinLod_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setSparseBinding( Bool32 sparseBinding_ )\n    {\n      sparseBinding = sparseBinding_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setSparseResidencyBuffer( Bool32 sparseResidencyBuffer_ )\n    {\n      sparseResidencyBuffer = sparseResidencyBuffer_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setSparseResidencyImage2D( Bool32 sparseResidencyImage2D_ )\n    {\n      sparseResidencyImage2D = sparseResidencyImage2D_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setSparseResidencyImage3D( Bool32 sparseResidencyImage3D_ )\n    {\n      sparseResidencyImage3D = sparseResidencyImage3D_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setSparseResidency2Samples( Bool32 sparseResidency2Samples_ )\n    {\n      sparseResidency2Samples = sparseResidency2Samples_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setSparseResidency4Samples( Bool32 sparseResidency4Samples_ )\n    {\n      sparseResidency4Samples = sparseResidency4Samples_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setSparseResidency8Samples( Bool32 sparseResidency8Samples_ )\n    {\n      sparseResidency8Samples = sparseResidency8Samples_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setSparseResidency16Samples( Bool32 sparseResidency16Samples_ )\n    {\n      sparseResidency16Samples = sparseResidency16Samples_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setSparseResidencyAliased( Bool32 sparseResidencyAliased_ )\n    {\n      sparseResidencyAliased = sparseResidencyAliased_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setVariableMultisampleRate( Bool32 variableMultisampleRate_ )\n    {\n      variableMultisampleRate = variableMultisampleRate_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures& setInheritedQueries( Bool32 inheritedQueries_ )\n    {\n      inheritedQueries = inheritedQueries_;\n      return *this;\n    }\n\n    operator const VkPhysicalDeviceFeatures&() const\n    {\n      return *reinterpret_cast<const VkPhysicalDeviceFeatures*>(this);\n    }\n\n    bool operator==( PhysicalDeviceFeatures const& rhs ) const\n    {\n      return ( robustBufferAccess == rhs.robustBufferAccess )\n          && ( fullDrawIndexUint32 == rhs.fullDrawIndexUint32 )\n          && ( imageCubeArray == rhs.imageCubeArray )\n          && ( independentBlend == rhs.independentBlend )\n          && ( geometryShader == rhs.geometryShader )\n          && ( tessellationShader == rhs.tessellationShader )\n          && ( sampleRateShading == rhs.sampleRateShading )\n          && ( dualSrcBlend == rhs.dualSrcBlend )\n          && ( logicOp == rhs.logicOp )\n          && ( multiDrawIndirect == rhs.multiDrawIndirect )\n          && ( drawIndirectFirstInstance == rhs.drawIndirectFirstInstance )\n          && ( depthClamp == rhs.depthClamp )\n          && ( depthBiasClamp == rhs.depthBiasClamp )\n          && ( fillModeNonSolid == rhs.fillModeNonSolid )\n          && ( depthBounds == rhs.depthBounds )\n          && ( wideLines == rhs.wideLines )\n          && ( largePoints == rhs.largePoints )\n          && ( alphaToOne == rhs.alphaToOne )\n          && ( multiViewport == rhs.multiViewport )\n          && ( samplerAnisotropy == rhs.samplerAnisotropy )\n          && ( textureCompressionETC2 == rhs.textureCompressionETC2 )\n          && ( textureCompressionASTC_LDR == rhs.textureCompressionASTC_LDR )\n          && ( textureCompressionBC == rhs.textureCompressionBC )\n          && ( occlusionQueryPrecise == rhs.occlusionQueryPrecise )\n          && ( pipelineStatisticsQuery == rhs.pipelineStatisticsQuery )\n          && ( vertexPipelineStoresAndAtomics == rhs.vertexPipelineStoresAndAtomics )\n          && ( fragmentStoresAndAtomics == rhs.fragmentStoresAndAtomics )\n          && ( shaderTessellationAndGeometryPointSize == rhs.shaderTessellationAndGeometryPointSize )\n          && ( shaderImageGatherExtended == rhs.shaderImageGatherExtended )\n          && ( shaderStorageImageExtendedFormats == rhs.shaderStorageImageExtendedFormats )\n          && ( shaderStorageImageMultisample == rhs.shaderStorageImageMultisample )\n          && ( shaderStorageImageReadWithoutFormat == rhs.shaderStorageImageReadWithoutFormat )\n          && ( shaderStorageImageWriteWithoutFormat == rhs.shaderStorageImageWriteWithoutFormat )\n          && ( shaderUniformBufferArrayDynamicIndexing == rhs.shaderUniformBufferArrayDynamicIndexing )\n          && ( shaderSampledImageArrayDynamicIndexing == rhs.shaderSampledImageArrayDynamicIndexing )\n          && ( shaderStorageBufferArrayDynamicIndexing == rhs.shaderStorageBufferArrayDynamicIndexing )\n          && ( shaderStorageImageArrayDynamicIndexing == rhs.shaderStorageImageArrayDynamicIndexing )\n          && ( shaderClipDistance == rhs.shaderClipDistance )\n          && ( shaderCullDistance == rhs.shaderCullDistance )\n          && ( shaderFloat64 == rhs.shaderFloat64 )\n          && ( shaderInt64 == rhs.shaderInt64 )\n          && ( shaderInt16 == rhs.shaderInt16 )\n          && ( shaderResourceResidency == rhs.shaderResourceResidency )\n          && ( shaderResourceMinLod == rhs.shaderResourceMinLod )\n          && ( sparseBinding == rhs.sparseBinding )\n          && ( sparseResidencyBuffer == rhs.sparseResidencyBuffer )\n          && ( sparseResidencyImage2D == rhs.sparseResidencyImage2D )\n          && ( sparseResidencyImage3D == rhs.sparseResidencyImage3D )\n          && ( sparseResidency2Samples == rhs.sparseResidency2Samples )\n          && ( sparseResidency4Samples == rhs.sparseResidency4Samples )\n          && ( sparseResidency8Samples == rhs.sparseResidency8Samples )\n          && ( sparseResidency16Samples == rhs.sparseResidency16Samples )\n          && ( sparseResidencyAliased == rhs.sparseResidencyAliased )\n          && ( variableMultisampleRate == rhs.variableMultisampleRate )\n          && ( inheritedQueries == rhs.inheritedQueries );\n    }\n\n    bool operator!=( PhysicalDeviceFeatures const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    Bool32 robustBufferAccess;\n    Bool32 fullDrawIndexUint32;\n    Bool32 imageCubeArray;\n    Bool32 independentBlend;\n    Bool32 geometryShader;\n    Bool32 tessellationShader;\n    Bool32 sampleRateShading;\n    Bool32 dualSrcBlend;\n    Bool32 logicOp;\n    Bool32 multiDrawIndirect;\n    Bool32 drawIndirectFirstInstance;\n    Bool32 depthClamp;\n    Bool32 depthBiasClamp;\n    Bool32 fillModeNonSolid;\n    Bool32 depthBounds;\n    Bool32 wideLines;\n    Bool32 largePoints;\n    Bool32 alphaToOne;\n    Bool32 multiViewport;\n    Bool32 samplerAnisotropy;\n    Bool32 textureCompressionETC2;\n    Bool32 textureCompressionASTC_LDR;\n    Bool32 textureCompressionBC;\n    Bool32 occlusionQueryPrecise;\n    Bool32 pipelineStatisticsQuery;\n    Bool32 vertexPipelineStoresAndAtomics;\n    Bool32 fragmentStoresAndAtomics;\n    Bool32 shaderTessellationAndGeometryPointSize;\n    Bool32 shaderImageGatherExtended;\n    Bool32 shaderStorageImageExtendedFormats;\n    Bool32 shaderStorageImageMultisample;\n    Bool32 shaderStorageImageReadWithoutFormat;\n    Bool32 shaderStorageImageWriteWithoutFormat;\n    Bool32 shaderUniformBufferArrayDynamicIndexing;\n    Bool32 shaderSampledImageArrayDynamicIndexing;\n    Bool32 shaderStorageBufferArrayDynamicIndexing;\n    Bool32 shaderStorageImageArrayDynamicIndexing;\n    Bool32 shaderClipDistance;\n    Bool32 shaderCullDistance;\n    Bool32 shaderFloat64;\n    Bool32 shaderInt64;\n    Bool32 shaderInt16;\n    Bool32 shaderResourceResidency;\n    Bool32 shaderResourceMinLod;\n    Bool32 sparseBinding;\n    Bool32 sparseResidencyBuffer;\n    Bool32 sparseResidencyImage2D;\n    Bool32 sparseResidencyImage3D;\n    Bool32 sparseResidency2Samples;\n    Bool32 sparseResidency4Samples;\n    Bool32 sparseResidency8Samples;\n    Bool32 sparseResidency16Samples;\n    Bool32 sparseResidencyAliased;\n    Bool32 variableMultisampleRate;\n    Bool32 inheritedQueries;\n  };\n  static_assert( sizeof( PhysicalDeviceFeatures ) == sizeof( VkPhysicalDeviceFeatures ), \"struct and wrapper have different size!\" );\n\n  struct PhysicalDeviceSparseProperties\n  {\n    operator const VkPhysicalDeviceSparseProperties&() const\n    {\n      return *reinterpret_cast<const VkPhysicalDeviceSparseProperties*>(this);\n    }\n\n    bool operator==( PhysicalDeviceSparseProperties const& rhs ) const\n    {\n      return ( residencyStandard2DBlockShape == rhs.residencyStandard2DBlockShape )\n          && ( residencyStandard2DMultisampleBlockShape == rhs.residencyStandard2DMultisampleBlockShape )\n          && ( residencyStandard3DBlockShape == rhs.residencyStandard3DBlockShape )\n          && ( residencyAlignedMipSize == rhs.residencyAlignedMipSize )\n          && ( residencyNonResidentStrict == rhs.residencyNonResidentStrict );\n    }\n\n    bool operator!=( PhysicalDeviceSparseProperties const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    Bool32 residencyStandard2DBlockShape;\n    Bool32 residencyStandard2DMultisampleBlockShape;\n    Bool32 residencyStandard3DBlockShape;\n    Bool32 residencyAlignedMipSize;\n    Bool32 residencyNonResidentStrict;\n  };\n  static_assert( sizeof( PhysicalDeviceSparseProperties ) == sizeof( VkPhysicalDeviceSparseProperties ), \"struct and wrapper have different size!\" );\n\n  struct DrawIndirectCommand\n  {\n    DrawIndirectCommand( uint32_t vertexCount_ = 0, uint32_t instanceCount_ = 0, uint32_t firstVertex_ = 0, uint32_t firstInstance_ = 0 )\n      : vertexCount( vertexCount_ )\n      , instanceCount( instanceCount_ )\n      , firstVertex( firstVertex_ )\n      , firstInstance( firstInstance_ )\n    {\n    }\n\n    DrawIndirectCommand( VkDrawIndirectCommand const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DrawIndirectCommand) );\n    }\n\n    DrawIndirectCommand& operator=( VkDrawIndirectCommand const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DrawIndirectCommand) );\n      return *this;\n    }\n\n    DrawIndirectCommand& setVertexCount( uint32_t vertexCount_ )\n    {\n      vertexCount = vertexCount_;\n      return *this;\n    }\n\n    DrawIndirectCommand& setInstanceCount( uint32_t instanceCount_ )\n    {\n      instanceCount = instanceCount_;\n      return *this;\n    }\n\n    DrawIndirectCommand& setFirstVertex( uint32_t firstVertex_ )\n    {\n      firstVertex = firstVertex_;\n      return *this;\n    }\n\n    DrawIndirectCommand& setFirstInstance( uint32_t firstInstance_ )\n    {\n      firstInstance = firstInstance_;\n      return *this;\n    }\n\n    operator const VkDrawIndirectCommand&() const\n    {\n      return *reinterpret_cast<const VkDrawIndirectCommand*>(this);\n    }\n\n    bool operator==( DrawIndirectCommand const& rhs ) const\n    {\n      return ( vertexCount == rhs.vertexCount )\n          && ( instanceCount == rhs.instanceCount )\n          && ( firstVertex == rhs.firstVertex )\n          && ( firstInstance == rhs.firstInstance );\n    }\n\n    bool operator!=( DrawIndirectCommand const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    uint32_t vertexCount;\n    uint32_t instanceCount;\n    uint32_t firstVertex;\n    uint32_t firstInstance;\n  };\n  static_assert( sizeof( DrawIndirectCommand ) == sizeof( VkDrawIndirectCommand ), \"struct and wrapper have different size!\" );\n\n  struct DrawIndexedIndirectCommand\n  {\n    DrawIndexedIndirectCommand( uint32_t indexCount_ = 0, uint32_t instanceCount_ = 0, uint32_t firstIndex_ = 0, int32_t vertexOffset_ = 0, uint32_t firstInstance_ = 0 )\n      : indexCount( indexCount_ )\n      , instanceCount( instanceCount_ )\n      , firstIndex( firstIndex_ )\n      , vertexOffset( vertexOffset_ )\n      , firstInstance( firstInstance_ )\n    {\n    }\n\n    DrawIndexedIndirectCommand( VkDrawIndexedIndirectCommand const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DrawIndexedIndirectCommand) );\n    }\n\n    DrawIndexedIndirectCommand& operator=( VkDrawIndexedIndirectCommand const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DrawIndexedIndirectCommand) );\n      return *this;\n    }\n\n    DrawIndexedIndirectCommand& setIndexCount( uint32_t indexCount_ )\n    {\n      indexCount = indexCount_;\n      return *this;\n    }\n\n    DrawIndexedIndirectCommand& setInstanceCount( uint32_t instanceCount_ )\n    {\n      instanceCount = instanceCount_;\n      return *this;\n    }\n\n    DrawIndexedIndirectCommand& setFirstIndex( uint32_t firstIndex_ )\n    {\n      firstIndex = firstIndex_;\n      return *this;\n    }\n\n    DrawIndexedIndirectCommand& setVertexOffset( int32_t vertexOffset_ )\n    {\n      vertexOffset = vertexOffset_;\n      return *this;\n    }\n\n    DrawIndexedIndirectCommand& setFirstInstance( uint32_t firstInstance_ )\n    {\n      firstInstance = firstInstance_;\n      return *this;\n    }\n\n    operator const VkDrawIndexedIndirectCommand&() const\n    {\n      return *reinterpret_cast<const VkDrawIndexedIndirectCommand*>(this);\n    }\n\n    bool operator==( DrawIndexedIndirectCommand const& rhs ) const\n    {\n      return ( indexCount == rhs.indexCount )\n          && ( instanceCount == rhs.instanceCount )\n          && ( firstIndex == rhs.firstIndex )\n          && ( vertexOffset == rhs.vertexOffset )\n          && ( firstInstance == rhs.firstInstance );\n    }\n\n    bool operator!=( DrawIndexedIndirectCommand const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    uint32_t indexCount;\n    uint32_t instanceCount;\n    uint32_t firstIndex;\n    int32_t vertexOffset;\n    uint32_t firstInstance;\n  };\n  static_assert( sizeof( DrawIndexedIndirectCommand ) == sizeof( VkDrawIndexedIndirectCommand ), \"struct and wrapper have different size!\" );\n\n  struct DispatchIndirectCommand\n  {\n    DispatchIndirectCommand( uint32_t x_ = 0, uint32_t y_ = 0, uint32_t z_ = 0 )\n      : x( x_ )\n      , y( y_ )\n      , z( z_ )\n    {\n    }\n\n    DispatchIndirectCommand( VkDispatchIndirectCommand const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DispatchIndirectCommand) );\n    }\n\n    DispatchIndirectCommand& operator=( VkDispatchIndirectCommand const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DispatchIndirectCommand) );\n      return *this;\n    }\n\n    DispatchIndirectCommand& setX( uint32_t x_ )\n    {\n      x = x_;\n      return *this;\n    }\n\n    DispatchIndirectCommand& setY( uint32_t y_ )\n    {\n      y = y_;\n      return *this;\n    }\n\n    DispatchIndirectCommand& setZ( uint32_t z_ )\n    {\n      z = z_;\n      return *this;\n    }\n\n    operator const VkDispatchIndirectCommand&() const\n    {\n      return *reinterpret_cast<const VkDispatchIndirectCommand*>(this);\n    }\n\n    bool operator==( DispatchIndirectCommand const& rhs ) const\n    {\n      return ( x == rhs.x )\n          && ( y == rhs.y )\n          && ( z == rhs.z );\n    }\n\n    bool operator!=( DispatchIndirectCommand const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    uint32_t x;\n    uint32_t y;\n    uint32_t z;\n  };\n  static_assert( sizeof( DispatchIndirectCommand ) == sizeof( VkDispatchIndirectCommand ), \"struct and wrapper have different size!\" );\n\n  struct DisplayPlanePropertiesKHR\n  {\n    operator const VkDisplayPlanePropertiesKHR&() const\n    {\n      return *reinterpret_cast<const VkDisplayPlanePropertiesKHR*>(this);\n    }\n\n    bool operator==( DisplayPlanePropertiesKHR const& rhs ) const\n    {\n      return ( currentDisplay == rhs.currentDisplay )\n          && ( currentStackIndex == rhs.currentStackIndex );\n    }\n\n    bool operator!=( DisplayPlanePropertiesKHR const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    DisplayKHR currentDisplay;\n    uint32_t currentStackIndex;\n  };\n  static_assert( sizeof( DisplayPlanePropertiesKHR ) == sizeof( VkDisplayPlanePropertiesKHR ), \"struct and wrapper have different size!\" );\n\n  struct DisplayModeParametersKHR\n  {\n    DisplayModeParametersKHR( Extent2D visibleRegion_ = Extent2D(), uint32_t refreshRate_ = 0 )\n      : visibleRegion( visibleRegion_ )\n      , refreshRate( refreshRate_ )\n    {\n    }\n\n    DisplayModeParametersKHR( VkDisplayModeParametersKHR const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DisplayModeParametersKHR) );\n    }\n\n    DisplayModeParametersKHR& operator=( VkDisplayModeParametersKHR const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DisplayModeParametersKHR) );\n      return *this;\n    }\n\n    DisplayModeParametersKHR& setVisibleRegion( Extent2D visibleRegion_ )\n    {\n      visibleRegion = visibleRegion_;\n      return *this;\n    }\n\n    DisplayModeParametersKHR& setRefreshRate( uint32_t refreshRate_ )\n    {\n      refreshRate = refreshRate_;\n      return *this;\n    }\n\n    operator const VkDisplayModeParametersKHR&() const\n    {\n      return *reinterpret_cast<const VkDisplayModeParametersKHR*>(this);\n    }\n\n    bool operator==( DisplayModeParametersKHR const& rhs ) const\n    {\n      return ( visibleRegion == rhs.visibleRegion )\n          && ( refreshRate == rhs.refreshRate );\n    }\n\n    bool operator!=( DisplayModeParametersKHR const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    Extent2D visibleRegion;\n    uint32_t refreshRate;\n  };\n  static_assert( sizeof( DisplayModeParametersKHR ) == sizeof( VkDisplayModeParametersKHR ), \"struct and wrapper have different size!\" );\n\n  struct DisplayModePropertiesKHR\n  {\n    operator const VkDisplayModePropertiesKHR&() const\n    {\n      return *reinterpret_cast<const VkDisplayModePropertiesKHR*>(this);\n    }\n\n    bool operator==( DisplayModePropertiesKHR const& rhs ) const\n    {\n      return ( displayMode == rhs.displayMode )\n          && ( parameters == rhs.parameters );\n    }\n\n    bool operator!=( DisplayModePropertiesKHR const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    DisplayModeKHR displayMode;\n    DisplayModeParametersKHR parameters;\n  };\n  static_assert( sizeof( DisplayModePropertiesKHR ) == sizeof( VkDisplayModePropertiesKHR ), \"struct and wrapper have different size!\" );\n\n  struct RectLayerKHR\n  {\n    RectLayerKHR( Offset2D offset_ = Offset2D(), Extent2D extent_ = Extent2D(), uint32_t layer_ = 0 )\n      : offset( offset_ )\n      , extent( extent_ )\n      , layer( layer_ )\n    {\n    }\n\n    RectLayerKHR( VkRectLayerKHR const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(RectLayerKHR) );\n    }\n\n    RectLayerKHR& operator=( VkRectLayerKHR const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(RectLayerKHR) );\n      return *this;\n    }\n\n    RectLayerKHR& setOffset( Offset2D offset_ )\n    {\n      offset = offset_;\n      return *this;\n    }\n\n    RectLayerKHR& setExtent( Extent2D extent_ )\n    {\n      extent = extent_;\n      return *this;\n    }\n\n    RectLayerKHR& setLayer( uint32_t layer_ )\n    {\n      layer = layer_;\n      return *this;\n    }\n\n    operator const VkRectLayerKHR&() const\n    {\n      return *reinterpret_cast<const VkRectLayerKHR*>(this);\n    }\n\n    bool operator==( RectLayerKHR const& rhs ) const\n    {\n      return ( offset == rhs.offset )\n          && ( extent == rhs.extent )\n          && ( layer == rhs.layer );\n    }\n\n    bool operator!=( RectLayerKHR const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    Offset2D offset;\n    Extent2D extent;\n    uint32_t layer;\n  };\n  static_assert( sizeof( RectLayerKHR ) == sizeof( VkRectLayerKHR ), \"struct and wrapper have different size!\" );\n\n  struct PresentRegionKHR\n  {\n    PresentRegionKHR( uint32_t rectangleCount_ = 0, const RectLayerKHR* pRectangles_ = nullptr )\n      : rectangleCount( rectangleCount_ )\n      , pRectangles( pRectangles_ )\n    {\n    }\n\n    PresentRegionKHR( VkPresentRegionKHR const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PresentRegionKHR) );\n    }\n\n    PresentRegionKHR& operator=( VkPresentRegionKHR const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PresentRegionKHR) );\n      return *this;\n    }\n\n    PresentRegionKHR& setRectangleCount( uint32_t rectangleCount_ )\n    {\n      rectangleCount = rectangleCount_;\n      return *this;\n    }\n\n    PresentRegionKHR& setPRectangles( const RectLayerKHR* pRectangles_ )\n    {\n      pRectangles = pRectangles_;\n      return *this;\n    }\n\n    operator const VkPresentRegionKHR&() const\n    {\n      return *reinterpret_cast<const VkPresentRegionKHR*>(this);\n    }\n\n    bool operator==( PresentRegionKHR const& rhs ) const\n    {\n      return ( rectangleCount == rhs.rectangleCount )\n          && ( pRectangles == rhs.pRectangles );\n    }\n\n    bool operator!=( PresentRegionKHR const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    uint32_t rectangleCount;\n    const RectLayerKHR* pRectangles;\n  };\n  static_assert( sizeof( PresentRegionKHR ) == sizeof( VkPresentRegionKHR ), \"struct and wrapper have different size!\" );\n\n  struct XYColorEXT\n  {\n    XYColorEXT( float x_ = 0, float y_ = 0 )\n      : x( x_ )\n      , y( y_ )\n    {\n    }\n\n    XYColorEXT( VkXYColorEXT const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(XYColorEXT) );\n    }\n\n    XYColorEXT& operator=( VkXYColorEXT const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(XYColorEXT) );\n      return *this;\n    }\n\n    XYColorEXT& setX( float x_ )\n    {\n      x = x_;\n      return *this;\n    }\n\n    XYColorEXT& setY( float y_ )\n    {\n      y = y_;\n      return *this;\n    }\n\n    operator const VkXYColorEXT&() const\n    {\n      return *reinterpret_cast<const VkXYColorEXT*>(this);\n    }\n\n    bool operator==( XYColorEXT const& rhs ) const\n    {\n      return ( x == rhs.x )\n          && ( y == rhs.y );\n    }\n\n    bool operator!=( XYColorEXT const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    float x;\n    float y;\n  };\n  static_assert( sizeof( XYColorEXT ) == sizeof( VkXYColorEXT ), \"struct and wrapper have different size!\" );\n\n  struct RefreshCycleDurationGOOGLE\n  {\n    RefreshCycleDurationGOOGLE( uint64_t refreshDuration_ = 0 )\n      : refreshDuration( refreshDuration_ )\n    {\n    }\n\n    RefreshCycleDurationGOOGLE( VkRefreshCycleDurationGOOGLE const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(RefreshCycleDurationGOOGLE) );\n    }\n\n    RefreshCycleDurationGOOGLE& operator=( VkRefreshCycleDurationGOOGLE const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(RefreshCycleDurationGOOGLE) );\n      return *this;\n    }\n\n    RefreshCycleDurationGOOGLE& setRefreshDuration( uint64_t refreshDuration_ )\n    {\n      refreshDuration = refreshDuration_;\n      return *this;\n    }\n\n    operator const VkRefreshCycleDurationGOOGLE&() const\n    {\n      return *reinterpret_cast<const VkRefreshCycleDurationGOOGLE*>(this);\n    }\n\n    bool operator==( RefreshCycleDurationGOOGLE const& rhs ) const\n    {\n      return ( refreshDuration == rhs.refreshDuration );\n    }\n\n    bool operator!=( RefreshCycleDurationGOOGLE const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    uint64_t refreshDuration;\n  };\n  static_assert( sizeof( RefreshCycleDurationGOOGLE ) == sizeof( VkRefreshCycleDurationGOOGLE ), \"struct and wrapper have different size!\" );\n\n  struct PastPresentationTimingGOOGLE\n  {\n    PastPresentationTimingGOOGLE( uint32_t presentID_ = 0, uint64_t desiredPresentTime_ = 0, uint64_t actualPresentTime_ = 0, uint64_t earliestPresentTime_ = 0, uint64_t presentMargin_ = 0 )\n      : presentID( presentID_ )\n      , desiredPresentTime( desiredPresentTime_ )\n      , actualPresentTime( actualPresentTime_ )\n      , earliestPresentTime( earliestPresentTime_ )\n      , presentMargin( presentMargin_ )\n    {\n    }\n\n    PastPresentationTimingGOOGLE( VkPastPresentationTimingGOOGLE const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PastPresentationTimingGOOGLE) );\n    }\n\n    PastPresentationTimingGOOGLE& operator=( VkPastPresentationTimingGOOGLE const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PastPresentationTimingGOOGLE) );\n      return *this;\n    }\n\n    PastPresentationTimingGOOGLE& setPresentID( uint32_t presentID_ )\n    {\n      presentID = presentID_;\n      return *this;\n    }\n\n    PastPresentationTimingGOOGLE& setDesiredPresentTime( uint64_t desiredPresentTime_ )\n    {\n      desiredPresentTime = desiredPresentTime_;\n      return *this;\n    }\n\n    PastPresentationTimingGOOGLE& setActualPresentTime( uint64_t actualPresentTime_ )\n    {\n      actualPresentTime = actualPresentTime_;\n      return *this;\n    }\n\n    PastPresentationTimingGOOGLE& setEarliestPresentTime( uint64_t earliestPresentTime_ )\n    {\n      earliestPresentTime = earliestPresentTime_;\n      return *this;\n    }\n\n    PastPresentationTimingGOOGLE& setPresentMargin( uint64_t presentMargin_ )\n    {\n      presentMargin = presentMargin_;\n      return *this;\n    }\n\n    operator const VkPastPresentationTimingGOOGLE&() const\n    {\n      return *reinterpret_cast<const VkPastPresentationTimingGOOGLE*>(this);\n    }\n\n    bool operator==( PastPresentationTimingGOOGLE const& rhs ) const\n    {\n      return ( presentID == rhs.presentID )\n          && ( desiredPresentTime == rhs.desiredPresentTime )\n          && ( actualPresentTime == rhs.actualPresentTime )\n          && ( earliestPresentTime == rhs.earliestPresentTime )\n          && ( presentMargin == rhs.presentMargin );\n    }\n\n    bool operator!=( PastPresentationTimingGOOGLE const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    uint32_t presentID;\n    uint64_t desiredPresentTime;\n    uint64_t actualPresentTime;\n    uint64_t earliestPresentTime;\n    uint64_t presentMargin;\n  };\n  static_assert( sizeof( PastPresentationTimingGOOGLE ) == sizeof( VkPastPresentationTimingGOOGLE ), \"struct and wrapper have different size!\" );\n\n  struct PresentTimeGOOGLE\n  {\n    PresentTimeGOOGLE( uint32_t presentID_ = 0, uint64_t desiredPresentTime_ = 0 )\n      : presentID( presentID_ )\n      , desiredPresentTime( desiredPresentTime_ )\n    {\n    }\n\n    PresentTimeGOOGLE( VkPresentTimeGOOGLE const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PresentTimeGOOGLE) );\n    }\n\n    PresentTimeGOOGLE& operator=( VkPresentTimeGOOGLE const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PresentTimeGOOGLE) );\n      return *this;\n    }\n\n    PresentTimeGOOGLE& setPresentID( uint32_t presentID_ )\n    {\n      presentID = presentID_;\n      return *this;\n    }\n\n    PresentTimeGOOGLE& setDesiredPresentTime( uint64_t desiredPresentTime_ )\n    {\n      desiredPresentTime = desiredPresentTime_;\n      return *this;\n    }\n\n    operator const VkPresentTimeGOOGLE&() const\n    {\n      return *reinterpret_cast<const VkPresentTimeGOOGLE*>(this);\n    }\n\n    bool operator==( PresentTimeGOOGLE const& rhs ) const\n    {\n      return ( presentID == rhs.presentID )\n          && ( desiredPresentTime == rhs.desiredPresentTime );\n    }\n\n    bool operator!=( PresentTimeGOOGLE const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    uint32_t presentID;\n    uint64_t desiredPresentTime;\n  };\n  static_assert( sizeof( PresentTimeGOOGLE ) == sizeof( VkPresentTimeGOOGLE ), \"struct and wrapper have different size!\" );\n\n  struct ViewportWScalingNV\n  {\n    ViewportWScalingNV( float xcoeff_ = 0, float ycoeff_ = 0 )\n      : xcoeff( xcoeff_ )\n      , ycoeff( ycoeff_ )\n    {\n    }\n\n    ViewportWScalingNV( VkViewportWScalingNV const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ViewportWScalingNV) );\n    }\n\n    ViewportWScalingNV& operator=( VkViewportWScalingNV const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ViewportWScalingNV) );\n      return *this;\n    }\n\n    ViewportWScalingNV& setXcoeff( float xcoeff_ )\n    {\n      xcoeff = xcoeff_;\n      return *this;\n    }\n\n    ViewportWScalingNV& setYcoeff( float ycoeff_ )\n    {\n      ycoeff = ycoeff_;\n      return *this;\n    }\n\n    operator const VkViewportWScalingNV&() const\n    {\n      return *reinterpret_cast<const VkViewportWScalingNV*>(this);\n    }\n\n    bool operator==( ViewportWScalingNV const& rhs ) const\n    {\n      return ( xcoeff == rhs.xcoeff )\n          && ( ycoeff == rhs.ycoeff );\n    }\n\n    bool operator!=( ViewportWScalingNV const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    float xcoeff;\n    float ycoeff;\n  };\n  static_assert( sizeof( ViewportWScalingNV ) == sizeof( VkViewportWScalingNV ), \"struct and wrapper have different size!\" );\n\n  enum class ImageLayout\n  {\n    eUndefined = VK_IMAGE_LAYOUT_UNDEFINED,\n    eGeneral = VK_IMAGE_LAYOUT_GENERAL,\n    eColorAttachmentOptimal = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,\n    eDepthStencilAttachmentOptimal = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,\n    eDepthStencilReadOnlyOptimal = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,\n    eShaderReadOnlyOptimal = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,\n    eTransferSrcOptimal = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,\n    eTransferDstOptimal = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,\n    ePreinitialized = VK_IMAGE_LAYOUT_PREINITIALIZED,\n    ePresentSrcKHR = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,\n    eSharedPresentKHR = VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR\n  };\n\n  struct DescriptorImageInfo\n  {\n    DescriptorImageInfo( Sampler sampler_ = Sampler(), ImageView imageView_ = ImageView(), ImageLayout imageLayout_ = ImageLayout::eUndefined )\n      : sampler( sampler_ )\n      , imageView( imageView_ )\n      , imageLayout( imageLayout_ )\n    {\n    }\n\n    DescriptorImageInfo( VkDescriptorImageInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DescriptorImageInfo) );\n    }\n\n    DescriptorImageInfo& operator=( VkDescriptorImageInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DescriptorImageInfo) );\n      return *this;\n    }\n\n    DescriptorImageInfo& setSampler( Sampler sampler_ )\n    {\n      sampler = sampler_;\n      return *this;\n    }\n\n    DescriptorImageInfo& setImageView( ImageView imageView_ )\n    {\n      imageView = imageView_;\n      return *this;\n    }\n\n    DescriptorImageInfo& setImageLayout( ImageLayout imageLayout_ )\n    {\n      imageLayout = imageLayout_;\n      return *this;\n    }\n\n    operator const VkDescriptorImageInfo&() const\n    {\n      return *reinterpret_cast<const VkDescriptorImageInfo*>(this);\n    }\n\n    bool operator==( DescriptorImageInfo const& rhs ) const\n    {\n      return ( sampler == rhs.sampler )\n          && ( imageView == rhs.imageView )\n          && ( imageLayout == rhs.imageLayout );\n    }\n\n    bool operator!=( DescriptorImageInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    Sampler sampler;\n    ImageView imageView;\n    ImageLayout imageLayout;\n  };\n  static_assert( sizeof( DescriptorImageInfo ) == sizeof( VkDescriptorImageInfo ), \"struct and wrapper have different size!\" );\n\n  struct AttachmentReference\n  {\n    AttachmentReference( uint32_t attachment_ = 0, ImageLayout layout_ = ImageLayout::eUndefined )\n      : attachment( attachment_ )\n      , layout( layout_ )\n    {\n    }\n\n    AttachmentReference( VkAttachmentReference const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(AttachmentReference) );\n    }\n\n    AttachmentReference& operator=( VkAttachmentReference const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(AttachmentReference) );\n      return *this;\n    }\n\n    AttachmentReference& setAttachment( uint32_t attachment_ )\n    {\n      attachment = attachment_;\n      return *this;\n    }\n\n    AttachmentReference& setLayout( ImageLayout layout_ )\n    {\n      layout = layout_;\n      return *this;\n    }\n\n    operator const VkAttachmentReference&() const\n    {\n      return *reinterpret_cast<const VkAttachmentReference*>(this);\n    }\n\n    bool operator==( AttachmentReference const& rhs ) const\n    {\n      return ( attachment == rhs.attachment )\n          && ( layout == rhs.layout );\n    }\n\n    bool operator!=( AttachmentReference const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    uint32_t attachment;\n    ImageLayout layout;\n  };\n  static_assert( sizeof( AttachmentReference ) == sizeof( VkAttachmentReference ), \"struct and wrapper have different size!\" );\n\n  enum class AttachmentLoadOp\n  {\n    eLoad = VK_ATTACHMENT_LOAD_OP_LOAD,\n    eClear = VK_ATTACHMENT_LOAD_OP_CLEAR,\n    eDontCare = VK_ATTACHMENT_LOAD_OP_DONT_CARE\n  };\n\n  enum class AttachmentStoreOp\n  {\n    eStore = VK_ATTACHMENT_STORE_OP_STORE,\n    eDontCare = VK_ATTACHMENT_STORE_OP_DONT_CARE\n  };\n\n  enum class ImageType\n  {\n    e1D = VK_IMAGE_TYPE_1D,\n    e2D = VK_IMAGE_TYPE_2D,\n    e3D = VK_IMAGE_TYPE_3D\n  };\n\n  enum class ImageTiling\n  {\n    eOptimal = VK_IMAGE_TILING_OPTIMAL,\n    eLinear = VK_IMAGE_TILING_LINEAR\n  };\n\n  enum class ImageViewType\n  {\n    e1D = VK_IMAGE_VIEW_TYPE_1D,\n    e2D = VK_IMAGE_VIEW_TYPE_2D,\n    e3D = VK_IMAGE_VIEW_TYPE_3D,\n    eCube = VK_IMAGE_VIEW_TYPE_CUBE,\n    e1DArray = VK_IMAGE_VIEW_TYPE_1D_ARRAY,\n    e2DArray = VK_IMAGE_VIEW_TYPE_2D_ARRAY,\n    eCubeArray = VK_IMAGE_VIEW_TYPE_CUBE_ARRAY\n  };\n\n  enum class CommandBufferLevel\n  {\n    ePrimary = VK_COMMAND_BUFFER_LEVEL_PRIMARY,\n    eSecondary = VK_COMMAND_BUFFER_LEVEL_SECONDARY\n  };\n\n  enum class ComponentSwizzle\n  {\n    eIdentity = VK_COMPONENT_SWIZZLE_IDENTITY,\n    eZero = VK_COMPONENT_SWIZZLE_ZERO,\n    eOne = VK_COMPONENT_SWIZZLE_ONE,\n    eR = VK_COMPONENT_SWIZZLE_R,\n    eG = VK_COMPONENT_SWIZZLE_G,\n    eB = VK_COMPONENT_SWIZZLE_B,\n    eA = VK_COMPONENT_SWIZZLE_A\n  };\n\n  struct ComponentMapping\n  {\n    ComponentMapping( ComponentSwizzle r_ = ComponentSwizzle::eIdentity, ComponentSwizzle g_ = ComponentSwizzle::eIdentity, ComponentSwizzle b_ = ComponentSwizzle::eIdentity, ComponentSwizzle a_ = ComponentSwizzle::eIdentity )\n      : r( r_ )\n      , g( g_ )\n      , b( b_ )\n      , a( a_ )\n    {\n    }\n\n    ComponentMapping( VkComponentMapping const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ComponentMapping) );\n    }\n\n    ComponentMapping& operator=( VkComponentMapping const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ComponentMapping) );\n      return *this;\n    }\n\n    ComponentMapping& setR( ComponentSwizzle r_ )\n    {\n      r = r_;\n      return *this;\n    }\n\n    ComponentMapping& setG( ComponentSwizzle g_ )\n    {\n      g = g_;\n      return *this;\n    }\n\n    ComponentMapping& setB( ComponentSwizzle b_ )\n    {\n      b = b_;\n      return *this;\n    }\n\n    ComponentMapping& setA( ComponentSwizzle a_ )\n    {\n      a = a_;\n      return *this;\n    }\n\n    operator const VkComponentMapping&() const\n    {\n      return *reinterpret_cast<const VkComponentMapping*>(this);\n    }\n\n    bool operator==( ComponentMapping const& rhs ) const\n    {\n      return ( r == rhs.r )\n          && ( g == rhs.g )\n          && ( b == rhs.b )\n          && ( a == rhs.a );\n    }\n\n    bool operator!=( ComponentMapping const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    ComponentSwizzle r;\n    ComponentSwizzle g;\n    ComponentSwizzle b;\n    ComponentSwizzle a;\n  };\n  static_assert( sizeof( ComponentMapping ) == sizeof( VkComponentMapping ), \"struct and wrapper have different size!\" );\n\n  enum class DescriptorType\n  {\n    eSampler = VK_DESCRIPTOR_TYPE_SAMPLER,\n    eCombinedImageSampler = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,\n    eSampledImage = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,\n    eStorageImage = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,\n    eUniformTexelBuffer = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,\n    eStorageTexelBuffer = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,\n    eUniformBuffer = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,\n    eStorageBuffer = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,\n    eUniformBufferDynamic = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,\n    eStorageBufferDynamic = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC,\n    eInputAttachment = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT\n  };\n\n  struct DescriptorPoolSize\n  {\n    DescriptorPoolSize( DescriptorType type_ = DescriptorType::eSampler, uint32_t descriptorCount_ = 0 )\n      : type( type_ )\n      , descriptorCount( descriptorCount_ )\n    {\n    }\n\n    DescriptorPoolSize( VkDescriptorPoolSize const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DescriptorPoolSize) );\n    }\n\n    DescriptorPoolSize& operator=( VkDescriptorPoolSize const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DescriptorPoolSize) );\n      return *this;\n    }\n\n    DescriptorPoolSize& setType( DescriptorType type_ )\n    {\n      type = type_;\n      return *this;\n    }\n\n    DescriptorPoolSize& setDescriptorCount( uint32_t descriptorCount_ )\n    {\n      descriptorCount = descriptorCount_;\n      return *this;\n    }\n\n    operator const VkDescriptorPoolSize&() const\n    {\n      return *reinterpret_cast<const VkDescriptorPoolSize*>(this);\n    }\n\n    bool operator==( DescriptorPoolSize const& rhs ) const\n    {\n      return ( type == rhs.type )\n          && ( descriptorCount == rhs.descriptorCount );\n    }\n\n    bool operator!=( DescriptorPoolSize const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    DescriptorType type;\n    uint32_t descriptorCount;\n  };\n  static_assert( sizeof( DescriptorPoolSize ) == sizeof( VkDescriptorPoolSize ), \"struct and wrapper have different size!\" );\n\n  struct DescriptorUpdateTemplateEntryKHR\n  {\n    DescriptorUpdateTemplateEntryKHR( uint32_t dstBinding_ = 0, uint32_t dstArrayElement_ = 0, uint32_t descriptorCount_ = 0, DescriptorType descriptorType_ = DescriptorType::eSampler, size_t offset_ = 0, size_t stride_ = 0 )\n      : dstBinding( dstBinding_ )\n      , dstArrayElement( dstArrayElement_ )\n      , descriptorCount( descriptorCount_ )\n      , descriptorType( descriptorType_ )\n      , offset( offset_ )\n      , stride( stride_ )\n    {\n    }\n\n    DescriptorUpdateTemplateEntryKHR( VkDescriptorUpdateTemplateEntryKHR const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DescriptorUpdateTemplateEntryKHR) );\n    }\n\n    DescriptorUpdateTemplateEntryKHR& operator=( VkDescriptorUpdateTemplateEntryKHR const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DescriptorUpdateTemplateEntryKHR) );\n      return *this;\n    }\n\n    DescriptorUpdateTemplateEntryKHR& setDstBinding( uint32_t dstBinding_ )\n    {\n      dstBinding = dstBinding_;\n      return *this;\n    }\n\n    DescriptorUpdateTemplateEntryKHR& setDstArrayElement( uint32_t dstArrayElement_ )\n    {\n      dstArrayElement = dstArrayElement_;\n      return *this;\n    }\n\n    DescriptorUpdateTemplateEntryKHR& setDescriptorCount( uint32_t descriptorCount_ )\n    {\n      descriptorCount = descriptorCount_;\n      return *this;\n    }\n\n    DescriptorUpdateTemplateEntryKHR& setDescriptorType( DescriptorType descriptorType_ )\n    {\n      descriptorType = descriptorType_;\n      return *this;\n    }\n\n    DescriptorUpdateTemplateEntryKHR& setOffset( size_t offset_ )\n    {\n      offset = offset_;\n      return *this;\n    }\n\n    DescriptorUpdateTemplateEntryKHR& setStride( size_t stride_ )\n    {\n      stride = stride_;\n      return *this;\n    }\n\n    operator const VkDescriptorUpdateTemplateEntryKHR&() const\n    {\n      return *reinterpret_cast<const VkDescriptorUpdateTemplateEntryKHR*>(this);\n    }\n\n    bool operator==( DescriptorUpdateTemplateEntryKHR const& rhs ) const\n    {\n      return ( dstBinding == rhs.dstBinding )\n          && ( dstArrayElement == rhs.dstArrayElement )\n          && ( descriptorCount == rhs.descriptorCount )\n          && ( descriptorType == rhs.descriptorType )\n          && ( offset == rhs.offset )\n          && ( stride == rhs.stride );\n    }\n\n    bool operator!=( DescriptorUpdateTemplateEntryKHR const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    uint32_t dstBinding;\n    uint32_t dstArrayElement;\n    uint32_t descriptorCount;\n    DescriptorType descriptorType;\n    size_t offset;\n    size_t stride;\n  };\n  static_assert( sizeof( DescriptorUpdateTemplateEntryKHR ) == sizeof( VkDescriptorUpdateTemplateEntryKHR ), \"struct and wrapper have different size!\" );\n\n  enum class QueryType\n  {\n    eOcclusion = VK_QUERY_TYPE_OCCLUSION,\n    ePipelineStatistics = VK_QUERY_TYPE_PIPELINE_STATISTICS,\n    eTimestamp = VK_QUERY_TYPE_TIMESTAMP\n  };\n\n  enum class BorderColor\n  {\n    eFloatTransparentBlack = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,\n    eIntTransparentBlack = VK_BORDER_COLOR_INT_TRANSPARENT_BLACK,\n    eFloatOpaqueBlack = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK,\n    eIntOpaqueBlack = VK_BORDER_COLOR_INT_OPAQUE_BLACK,\n    eFloatOpaqueWhite = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE,\n    eIntOpaqueWhite = VK_BORDER_COLOR_INT_OPAQUE_WHITE\n  };\n\n  enum class PipelineBindPoint\n  {\n    eGraphics = VK_PIPELINE_BIND_POINT_GRAPHICS,\n    eCompute = VK_PIPELINE_BIND_POINT_COMPUTE\n  };\n\n  enum class PipelineCacheHeaderVersion\n  {\n    eOne = VK_PIPELINE_CACHE_HEADER_VERSION_ONE\n  };\n\n  enum class PrimitiveTopology\n  {\n    ePointList = VK_PRIMITIVE_TOPOLOGY_POINT_LIST,\n    eLineList = VK_PRIMITIVE_TOPOLOGY_LINE_LIST,\n    eLineStrip = VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,\n    eTriangleList = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,\n    eTriangleStrip = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,\n    eTriangleFan = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN,\n    eLineListWithAdjacency = VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY,\n    eLineStripWithAdjacency = VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY,\n    eTriangleListWithAdjacency = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY,\n    eTriangleStripWithAdjacency = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY,\n    ePatchList = VK_PRIMITIVE_TOPOLOGY_PATCH_LIST\n  };\n\n  enum class SharingMode\n  {\n    eExclusive = VK_SHARING_MODE_EXCLUSIVE,\n    eConcurrent = VK_SHARING_MODE_CONCURRENT\n  };\n\n  enum class IndexType\n  {\n    eUint16 = VK_INDEX_TYPE_UINT16,\n    eUint32 = VK_INDEX_TYPE_UINT32\n  };\n\n  enum class Filter\n  {\n    eNearest = VK_FILTER_NEAREST,\n    eLinear = VK_FILTER_LINEAR,\n    eCubicIMG = VK_FILTER_CUBIC_IMG\n  };\n\n  enum class SamplerMipmapMode\n  {\n    eNearest = VK_SAMPLER_MIPMAP_MODE_NEAREST,\n    eLinear = VK_SAMPLER_MIPMAP_MODE_LINEAR\n  };\n\n  enum class SamplerAddressMode\n  {\n    eRepeat = VK_SAMPLER_ADDRESS_MODE_REPEAT,\n    eMirroredRepeat = VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT,\n    eClampToEdge = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,\n    eClampToBorder = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,\n    eMirrorClampToEdge = VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE\n  };\n\n  enum class CompareOp\n  {\n    eNever = VK_COMPARE_OP_NEVER,\n    eLess = VK_COMPARE_OP_LESS,\n    eEqual = VK_COMPARE_OP_EQUAL,\n    eLessOrEqual = VK_COMPARE_OP_LESS_OR_EQUAL,\n    eGreater = VK_COMPARE_OP_GREATER,\n    eNotEqual = VK_COMPARE_OP_NOT_EQUAL,\n    eGreaterOrEqual = VK_COMPARE_OP_GREATER_OR_EQUAL,\n    eAlways = VK_COMPARE_OP_ALWAYS\n  };\n\n  enum class PolygonMode\n  {\n    eFill = VK_POLYGON_MODE_FILL,\n    eLine = VK_POLYGON_MODE_LINE,\n    ePoint = VK_POLYGON_MODE_POINT\n  };\n\n  enum class CullModeFlagBits\n  {\n    eNone = VK_CULL_MODE_NONE,\n    eFront = VK_CULL_MODE_FRONT_BIT,\n    eBack = VK_CULL_MODE_BACK_BIT,\n    eFrontAndBack = VK_CULL_MODE_FRONT_AND_BACK\n  };\n\n  using CullModeFlags = Flags<CullModeFlagBits, VkCullModeFlags>;\n\n  VULKAN_HPP_INLINE CullModeFlags operator|( CullModeFlagBits bit0, CullModeFlagBits bit1 )\n  {\n    return CullModeFlags( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE CullModeFlags operator~( CullModeFlagBits bits )\n  {\n    return ~( CullModeFlags( bits ) );\n  }\n\n  template <> struct FlagTraits<CullModeFlagBits>\n  {\n    enum\n    {\n      allFlags = VkFlags(CullModeFlagBits::eNone) | VkFlags(CullModeFlagBits::eFront) | VkFlags(CullModeFlagBits::eBack) | VkFlags(CullModeFlagBits::eFrontAndBack)\n    };\n  };\n\n  enum class FrontFace\n  {\n    eCounterClockwise = VK_FRONT_FACE_COUNTER_CLOCKWISE,\n    eClockwise = VK_FRONT_FACE_CLOCKWISE\n  };\n\n  enum class BlendFactor\n  {\n    eZero = VK_BLEND_FACTOR_ZERO,\n    eOne = VK_BLEND_FACTOR_ONE,\n    eSrcColor = VK_BLEND_FACTOR_SRC_COLOR,\n    eOneMinusSrcColor = VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR,\n    eDstColor = VK_BLEND_FACTOR_DST_COLOR,\n    eOneMinusDstColor = VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR,\n    eSrcAlpha = VK_BLEND_FACTOR_SRC_ALPHA,\n    eOneMinusSrcAlpha = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,\n    eDstAlpha = VK_BLEND_FACTOR_DST_ALPHA,\n    eOneMinusDstAlpha = VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA,\n    eConstantColor = VK_BLEND_FACTOR_CONSTANT_COLOR,\n    eOneMinusConstantColor = VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR,\n    eConstantAlpha = VK_BLEND_FACTOR_CONSTANT_ALPHA,\n    eOneMinusConstantAlpha = VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA,\n    eSrcAlphaSaturate = VK_BLEND_FACTOR_SRC_ALPHA_SATURATE,\n    eSrc1Color = VK_BLEND_FACTOR_SRC1_COLOR,\n    eOneMinusSrc1Color = VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR,\n    eSrc1Alpha = VK_BLEND_FACTOR_SRC1_ALPHA,\n    eOneMinusSrc1Alpha = VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA\n  };\n\n  enum class BlendOp\n  {\n    eAdd = VK_BLEND_OP_ADD,\n    eSubtract = VK_BLEND_OP_SUBTRACT,\n    eReverseSubtract = VK_BLEND_OP_REVERSE_SUBTRACT,\n    eMin = VK_BLEND_OP_MIN,\n    eMax = VK_BLEND_OP_MAX\n  };\n\n  enum class StencilOp\n  {\n    eKeep = VK_STENCIL_OP_KEEP,\n    eZero = VK_STENCIL_OP_ZERO,\n    eReplace = VK_STENCIL_OP_REPLACE,\n    eIncrementAndClamp = VK_STENCIL_OP_INCREMENT_AND_CLAMP,\n    eDecrementAndClamp = VK_STENCIL_OP_DECREMENT_AND_CLAMP,\n    eInvert = VK_STENCIL_OP_INVERT,\n    eIncrementAndWrap = VK_STENCIL_OP_INCREMENT_AND_WRAP,\n    eDecrementAndWrap = VK_STENCIL_OP_DECREMENT_AND_WRAP\n  };\n\n  struct StencilOpState\n  {\n    StencilOpState( StencilOp failOp_ = StencilOp::eKeep, StencilOp passOp_ = StencilOp::eKeep, StencilOp depthFailOp_ = StencilOp::eKeep, CompareOp compareOp_ = CompareOp::eNever, uint32_t compareMask_ = 0, uint32_t writeMask_ = 0, uint32_t reference_ = 0 )\n      : failOp( failOp_ )\n      , passOp( passOp_ )\n      , depthFailOp( depthFailOp_ )\n      , compareOp( compareOp_ )\n      , compareMask( compareMask_ )\n      , writeMask( writeMask_ )\n      , reference( reference_ )\n    {\n    }\n\n    StencilOpState( VkStencilOpState const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(StencilOpState) );\n    }\n\n    StencilOpState& operator=( VkStencilOpState const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(StencilOpState) );\n      return *this;\n    }\n\n    StencilOpState& setFailOp( StencilOp failOp_ )\n    {\n      failOp = failOp_;\n      return *this;\n    }\n\n    StencilOpState& setPassOp( StencilOp passOp_ )\n    {\n      passOp = passOp_;\n      return *this;\n    }\n\n    StencilOpState& setDepthFailOp( StencilOp depthFailOp_ )\n    {\n      depthFailOp = depthFailOp_;\n      return *this;\n    }\n\n    StencilOpState& setCompareOp( CompareOp compareOp_ )\n    {\n      compareOp = compareOp_;\n      return *this;\n    }\n\n    StencilOpState& setCompareMask( uint32_t compareMask_ )\n    {\n      compareMask = compareMask_;\n      return *this;\n    }\n\n    StencilOpState& setWriteMask( uint32_t writeMask_ )\n    {\n      writeMask = writeMask_;\n      return *this;\n    }\n\n    StencilOpState& setReference( uint32_t reference_ )\n    {\n      reference = reference_;\n      return *this;\n    }\n\n    operator const VkStencilOpState&() const\n    {\n      return *reinterpret_cast<const VkStencilOpState*>(this);\n    }\n\n    bool operator==( StencilOpState const& rhs ) const\n    {\n      return ( failOp == rhs.failOp )\n          && ( passOp == rhs.passOp )\n          && ( depthFailOp == rhs.depthFailOp )\n          && ( compareOp == rhs.compareOp )\n          && ( compareMask == rhs.compareMask )\n          && ( writeMask == rhs.writeMask )\n          && ( reference == rhs.reference );\n    }\n\n    bool operator!=( StencilOpState const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    StencilOp failOp;\n    StencilOp passOp;\n    StencilOp depthFailOp;\n    CompareOp compareOp;\n    uint32_t compareMask;\n    uint32_t writeMask;\n    uint32_t reference;\n  };\n  static_assert( sizeof( StencilOpState ) == sizeof( VkStencilOpState ), \"struct and wrapper have different size!\" );\n\n  enum class LogicOp\n  {\n    eClear = VK_LOGIC_OP_CLEAR,\n    eAnd = VK_LOGIC_OP_AND,\n    eAndReverse = VK_LOGIC_OP_AND_REVERSE,\n    eCopy = VK_LOGIC_OP_COPY,\n    eAndInverted = VK_LOGIC_OP_AND_INVERTED,\n    eNoOp = VK_LOGIC_OP_NO_OP,\n    eXor = VK_LOGIC_OP_XOR,\n    eOr = VK_LOGIC_OP_OR,\n    eNor = VK_LOGIC_OP_NOR,\n    eEquivalent = VK_LOGIC_OP_EQUIVALENT,\n    eInvert = VK_LOGIC_OP_INVERT,\n    eOrReverse = VK_LOGIC_OP_OR_REVERSE,\n    eCopyInverted = VK_LOGIC_OP_COPY_INVERTED,\n    eOrInverted = VK_LOGIC_OP_OR_INVERTED,\n    eNand = VK_LOGIC_OP_NAND,\n    eSet = VK_LOGIC_OP_SET\n  };\n\n  enum class InternalAllocationType\n  {\n    eExecutable = VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE\n  };\n\n  enum class SystemAllocationScope\n  {\n    eCommand = VK_SYSTEM_ALLOCATION_SCOPE_COMMAND,\n    eObject = VK_SYSTEM_ALLOCATION_SCOPE_OBJECT,\n    eCache = VK_SYSTEM_ALLOCATION_SCOPE_CACHE,\n    eDevice = VK_SYSTEM_ALLOCATION_SCOPE_DEVICE,\n    eInstance = VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE\n  };\n\n  enum class PhysicalDeviceType\n  {\n    eOther = VK_PHYSICAL_DEVICE_TYPE_OTHER,\n    eIntegratedGpu = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU,\n    eDiscreteGpu = VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU,\n    eVirtualGpu = VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU,\n    eCpu = VK_PHYSICAL_DEVICE_TYPE_CPU\n  };\n\n  enum class VertexInputRate\n  {\n    eVertex = VK_VERTEX_INPUT_RATE_VERTEX,\n    eInstance = VK_VERTEX_INPUT_RATE_INSTANCE\n  };\n\n  struct VertexInputBindingDescription\n  {\n    VertexInputBindingDescription( uint32_t binding_ = 0, uint32_t stride_ = 0, VertexInputRate inputRate_ = VertexInputRate::eVertex )\n      : binding( binding_ )\n      , stride( stride_ )\n      , inputRate( inputRate_ )\n    {\n    }\n\n    VertexInputBindingDescription( VkVertexInputBindingDescription const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(VertexInputBindingDescription) );\n    }\n\n    VertexInputBindingDescription& operator=( VkVertexInputBindingDescription const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(VertexInputBindingDescription) );\n      return *this;\n    }\n\n    VertexInputBindingDescription& setBinding( uint32_t binding_ )\n    {\n      binding = binding_;\n      return *this;\n    }\n\n    VertexInputBindingDescription& setStride( uint32_t stride_ )\n    {\n      stride = stride_;\n      return *this;\n    }\n\n    VertexInputBindingDescription& setInputRate( VertexInputRate inputRate_ )\n    {\n      inputRate = inputRate_;\n      return *this;\n    }\n\n    operator const VkVertexInputBindingDescription&() const\n    {\n      return *reinterpret_cast<const VkVertexInputBindingDescription*>(this);\n    }\n\n    bool operator==( VertexInputBindingDescription const& rhs ) const\n    {\n      return ( binding == rhs.binding )\n          && ( stride == rhs.stride )\n          && ( inputRate == rhs.inputRate );\n    }\n\n    bool operator!=( VertexInputBindingDescription const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    uint32_t binding;\n    uint32_t stride;\n    VertexInputRate inputRate;\n  };\n  static_assert( sizeof( VertexInputBindingDescription ) == sizeof( VkVertexInputBindingDescription ), \"struct and wrapper have different size!\" );\n\n  enum class Format\n  {\n    eUndefined = VK_FORMAT_UNDEFINED,\n    eR4G4UnormPack8 = VK_FORMAT_R4G4_UNORM_PACK8,\n    eR4G4B4A4UnormPack16 = VK_FORMAT_R4G4B4A4_UNORM_PACK16,\n    eB4G4R4A4UnormPack16 = VK_FORMAT_B4G4R4A4_UNORM_PACK16,\n    eR5G6B5UnormPack16 = VK_FORMAT_R5G6B5_UNORM_PACK16,\n    eB5G6R5UnormPack16 = VK_FORMAT_B5G6R5_UNORM_PACK16,\n    eR5G5B5A1UnormPack16 = VK_FORMAT_R5G5B5A1_UNORM_PACK16,\n    eB5G5R5A1UnormPack16 = VK_FORMAT_B5G5R5A1_UNORM_PACK16,\n    eA1R5G5B5UnormPack16 = VK_FORMAT_A1R5G5B5_UNORM_PACK16,\n    eR8Unorm = VK_FORMAT_R8_UNORM,\n    eR8Snorm = VK_FORMAT_R8_SNORM,\n    eR8Uscaled = VK_FORMAT_R8_USCALED,\n    eR8Sscaled = VK_FORMAT_R8_SSCALED,\n    eR8Uint = VK_FORMAT_R8_UINT,\n    eR8Sint = VK_FORMAT_R8_SINT,\n    eR8Srgb = VK_FORMAT_R8_SRGB,\n    eR8G8Unorm = VK_FORMAT_R8G8_UNORM,\n    eR8G8Snorm = VK_FORMAT_R8G8_SNORM,\n    eR8G8Uscaled = VK_FORMAT_R8G8_USCALED,\n    eR8G8Sscaled = VK_FORMAT_R8G8_SSCALED,\n    eR8G8Uint = VK_FORMAT_R8G8_UINT,\n    eR8G8Sint = VK_FORMAT_R8G8_SINT,\n    eR8G8Srgb = VK_FORMAT_R8G8_SRGB,\n    eR8G8B8Unorm = VK_FORMAT_R8G8B8_UNORM,\n    eR8G8B8Snorm = VK_FORMAT_R8G8B8_SNORM,\n    eR8G8B8Uscaled = VK_FORMAT_R8G8B8_USCALED,\n    eR8G8B8Sscaled = VK_FORMAT_R8G8B8_SSCALED,\n    eR8G8B8Uint = VK_FORMAT_R8G8B8_UINT,\n    eR8G8B8Sint = VK_FORMAT_R8G8B8_SINT,\n    eR8G8B8Srgb = VK_FORMAT_R8G8B8_SRGB,\n    eB8G8R8Unorm = VK_FORMAT_B8G8R8_UNORM,\n    eB8G8R8Snorm = VK_FORMAT_B8G8R8_SNORM,\n    eB8G8R8Uscaled = VK_FORMAT_B8G8R8_USCALED,\n    eB8G8R8Sscaled = VK_FORMAT_B8G8R8_SSCALED,\n    eB8G8R8Uint = VK_FORMAT_B8G8R8_UINT,\n    eB8G8R8Sint = VK_FORMAT_B8G8R8_SINT,\n    eB8G8R8Srgb = VK_FORMAT_B8G8R8_SRGB,\n    eR8G8B8A8Unorm = VK_FORMAT_R8G8B8A8_UNORM,\n    eR8G8B8A8Snorm = VK_FORMAT_R8G8B8A8_SNORM,\n    eR8G8B8A8Uscaled = VK_FORMAT_R8G8B8A8_USCALED,\n    eR8G8B8A8Sscaled = VK_FORMAT_R8G8B8A8_SSCALED,\n    eR8G8B8A8Uint = VK_FORMAT_R8G8B8A8_UINT,\n    eR8G8B8A8Sint = VK_FORMAT_R8G8B8A8_SINT,\n    eR8G8B8A8Srgb = VK_FORMAT_R8G8B8A8_SRGB,\n    eB8G8R8A8Unorm = VK_FORMAT_B8G8R8A8_UNORM,\n    eB8G8R8A8Snorm = VK_FORMAT_B8G8R8A8_SNORM,\n    eB8G8R8A8Uscaled = VK_FORMAT_B8G8R8A8_USCALED,\n    eB8G8R8A8Sscaled = VK_FORMAT_B8G8R8A8_SSCALED,\n    eB8G8R8A8Uint = VK_FORMAT_B8G8R8A8_UINT,\n    eB8G8R8A8Sint = VK_FORMAT_B8G8R8A8_SINT,\n    eB8G8R8A8Srgb = VK_FORMAT_B8G8R8A8_SRGB,\n    eA8B8G8R8UnormPack32 = VK_FORMAT_A8B8G8R8_UNORM_PACK32,\n    eA8B8G8R8SnormPack32 = VK_FORMAT_A8B8G8R8_SNORM_PACK32,\n    eA8B8G8R8UscaledPack32 = VK_FORMAT_A8B8G8R8_USCALED_PACK32,\n    eA8B8G8R8SscaledPack32 = VK_FORMAT_A8B8G8R8_SSCALED_PACK32,\n    eA8B8G8R8UintPack32 = VK_FORMAT_A8B8G8R8_UINT_PACK32,\n    eA8B8G8R8SintPack32 = VK_FORMAT_A8B8G8R8_SINT_PACK32,\n    eA8B8G8R8SrgbPack32 = VK_FORMAT_A8B8G8R8_SRGB_PACK32,\n    eA2R10G10B10UnormPack32 = VK_FORMAT_A2R10G10B10_UNORM_PACK32,\n    eA2R10G10B10SnormPack32 = VK_FORMAT_A2R10G10B10_SNORM_PACK32,\n    eA2R10G10B10UscaledPack32 = VK_FORMAT_A2R10G10B10_USCALED_PACK32,\n    eA2R10G10B10SscaledPack32 = VK_FORMAT_A2R10G10B10_SSCALED_PACK32,\n    eA2R10G10B10UintPack32 = VK_FORMAT_A2R10G10B10_UINT_PACK32,\n    eA2R10G10B10SintPack32 = VK_FORMAT_A2R10G10B10_SINT_PACK32,\n    eA2B10G10R10UnormPack32 = VK_FORMAT_A2B10G10R10_UNORM_PACK32,\n    eA2B10G10R10SnormPack32 = VK_FORMAT_A2B10G10R10_SNORM_PACK32,\n    eA2B10G10R10UscaledPack32 = VK_FORMAT_A2B10G10R10_USCALED_PACK32,\n    eA2B10G10R10SscaledPack32 = VK_FORMAT_A2B10G10R10_SSCALED_PACK32,\n    eA2B10G10R10UintPack32 = VK_FORMAT_A2B10G10R10_UINT_PACK32,\n    eA2B10G10R10SintPack32 = VK_FORMAT_A2B10G10R10_SINT_PACK32,\n    eR16Unorm = VK_FORMAT_R16_UNORM,\n    eR16Snorm = VK_FORMAT_R16_SNORM,\n    eR16Uscaled = VK_FORMAT_R16_USCALED,\n    eR16Sscaled = VK_FORMAT_R16_SSCALED,\n    eR16Uint = VK_FORMAT_R16_UINT,\n    eR16Sint = VK_FORMAT_R16_SINT,\n    eR16Sfloat = VK_FORMAT_R16_SFLOAT,\n    eR16G16Unorm = VK_FORMAT_R16G16_UNORM,\n    eR16G16Snorm = VK_FORMAT_R16G16_SNORM,\n    eR16G16Uscaled = VK_FORMAT_R16G16_USCALED,\n    eR16G16Sscaled = VK_FORMAT_R16G16_SSCALED,\n    eR16G16Uint = VK_FORMAT_R16G16_UINT,\n    eR16G16Sint = VK_FORMAT_R16G16_SINT,\n    eR16G16Sfloat = VK_FORMAT_R16G16_SFLOAT,\n    eR16G16B16Unorm = VK_FORMAT_R16G16B16_UNORM,\n    eR16G16B16Snorm = VK_FORMAT_R16G16B16_SNORM,\n    eR16G16B16Uscaled = VK_FORMAT_R16G16B16_USCALED,\n    eR16G16B16Sscaled = VK_FORMAT_R16G16B16_SSCALED,\n    eR16G16B16Uint = VK_FORMAT_R16G16B16_UINT,\n    eR16G16B16Sint = VK_FORMAT_R16G16B16_SINT,\n    eR16G16B16Sfloat = VK_FORMAT_R16G16B16_SFLOAT,\n    eR16G16B16A16Unorm = VK_FORMAT_R16G16B16A16_UNORM,\n    eR16G16B16A16Snorm = VK_FORMAT_R16G16B16A16_SNORM,\n    eR16G16B16A16Uscaled = VK_FORMAT_R16G16B16A16_USCALED,\n    eR16G16B16A16Sscaled = VK_FORMAT_R16G16B16A16_SSCALED,\n    eR16G16B16A16Uint = VK_FORMAT_R16G16B16A16_UINT,\n    eR16G16B16A16Sint = VK_FORMAT_R16G16B16A16_SINT,\n    eR16G16B16A16Sfloat = VK_FORMAT_R16G16B16A16_SFLOAT,\n    eR32Uint = VK_FORMAT_R32_UINT,\n    eR32Sint = VK_FORMAT_R32_SINT,\n    eR32Sfloat = VK_FORMAT_R32_SFLOAT,\n    eR32G32Uint = VK_FORMAT_R32G32_UINT,\n    eR32G32Sint = VK_FORMAT_R32G32_SINT,\n    eR32G32Sfloat = VK_FORMAT_R32G32_SFLOAT,\n    eR32G32B32Uint = VK_FORMAT_R32G32B32_UINT,\n    eR32G32B32Sint = VK_FORMAT_R32G32B32_SINT,\n    eR32G32B32Sfloat = VK_FORMAT_R32G32B32_SFLOAT,\n    eR32G32B32A32Uint = VK_FORMAT_R32G32B32A32_UINT,\n    eR32G32B32A32Sint = VK_FORMAT_R32G32B32A32_SINT,\n    eR32G32B32A32Sfloat = VK_FORMAT_R32G32B32A32_SFLOAT,\n    eR64Uint = VK_FORMAT_R64_UINT,\n    eR64Sint = VK_FORMAT_R64_SINT,\n    eR64Sfloat = VK_FORMAT_R64_SFLOAT,\n    eR64G64Uint = VK_FORMAT_R64G64_UINT,\n    eR64G64Sint = VK_FORMAT_R64G64_SINT,\n    eR64G64Sfloat = VK_FORMAT_R64G64_SFLOAT,\n    eR64G64B64Uint = VK_FORMAT_R64G64B64_UINT,\n    eR64G64B64Sint = VK_FORMAT_R64G64B64_SINT,\n    eR64G64B64Sfloat = VK_FORMAT_R64G64B64_SFLOAT,\n    eR64G64B64A64Uint = VK_FORMAT_R64G64B64A64_UINT,\n    eR64G64B64A64Sint = VK_FORMAT_R64G64B64A64_SINT,\n    eR64G64B64A64Sfloat = VK_FORMAT_R64G64B64A64_SFLOAT,\n    eB10G11R11UfloatPack32 = VK_FORMAT_B10G11R11_UFLOAT_PACK32,\n    eE5B9G9R9UfloatPack32 = VK_FORMAT_E5B9G9R9_UFLOAT_PACK32,\n    eD16Unorm = VK_FORMAT_D16_UNORM,\n    eX8D24UnormPack32 = VK_FORMAT_X8_D24_UNORM_PACK32,\n    eD32Sfloat = VK_FORMAT_D32_SFLOAT,\n    eS8Uint = VK_FORMAT_S8_UINT,\n    eD16UnormS8Uint = VK_FORMAT_D16_UNORM_S8_UINT,\n    eD24UnormS8Uint = VK_FORMAT_D24_UNORM_S8_UINT,\n    eD32SfloatS8Uint = VK_FORMAT_D32_SFLOAT_S8_UINT,\n    eBc1RgbUnormBlock = VK_FORMAT_BC1_RGB_UNORM_BLOCK,\n    eBc1RgbSrgbBlock = VK_FORMAT_BC1_RGB_SRGB_BLOCK,\n    eBc1RgbaUnormBlock = VK_FORMAT_BC1_RGBA_UNORM_BLOCK,\n    eBc1RgbaSrgbBlock = VK_FORMAT_BC1_RGBA_SRGB_BLOCK,\n    eBc2UnormBlock = VK_FORMAT_BC2_UNORM_BLOCK,\n    eBc2SrgbBlock = VK_FORMAT_BC2_SRGB_BLOCK,\n    eBc3UnormBlock = VK_FORMAT_BC3_UNORM_BLOCK,\n    eBc3SrgbBlock = VK_FORMAT_BC3_SRGB_BLOCK,\n    eBc4UnormBlock = VK_FORMAT_BC4_UNORM_BLOCK,\n    eBc4SnormBlock = VK_FORMAT_BC4_SNORM_BLOCK,\n    eBc5UnormBlock = VK_FORMAT_BC5_UNORM_BLOCK,\n    eBc5SnormBlock = VK_FORMAT_BC5_SNORM_BLOCK,\n    eBc6HUfloatBlock = VK_FORMAT_BC6H_UFLOAT_BLOCK,\n    eBc6HSfloatBlock = VK_FORMAT_BC6H_SFLOAT_BLOCK,\n    eBc7UnormBlock = VK_FORMAT_BC7_UNORM_BLOCK,\n    eBc7SrgbBlock = VK_FORMAT_BC7_SRGB_BLOCK,\n    eEtc2R8G8B8UnormBlock = VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK,\n    eEtc2R8G8B8SrgbBlock = VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK,\n    eEtc2R8G8B8A1UnormBlock = VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK,\n    eEtc2R8G8B8A1SrgbBlock = VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK,\n    eEtc2R8G8B8A8UnormBlock = VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK,\n    eEtc2R8G8B8A8SrgbBlock = VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK,\n    eEacR11UnormBlock = VK_FORMAT_EAC_R11_UNORM_BLOCK,\n    eEacR11SnormBlock = VK_FORMAT_EAC_R11_SNORM_BLOCK,\n    eEacR11G11UnormBlock = VK_FORMAT_EAC_R11G11_UNORM_BLOCK,\n    eEacR11G11SnormBlock = VK_FORMAT_EAC_R11G11_SNORM_BLOCK,\n    eAstc4x4UnormBlock = VK_FORMAT_ASTC_4x4_UNORM_BLOCK,\n    eAstc4x4SrgbBlock = VK_FORMAT_ASTC_4x4_SRGB_BLOCK,\n    eAstc5x4UnormBlock = VK_FORMAT_ASTC_5x4_UNORM_BLOCK,\n    eAstc5x4SrgbBlock = VK_FORMAT_ASTC_5x4_SRGB_BLOCK,\n    eAstc5x5UnormBlock = VK_FORMAT_ASTC_5x5_UNORM_BLOCK,\n    eAstc5x5SrgbBlock = VK_FORMAT_ASTC_5x5_SRGB_BLOCK,\n    eAstc6x5UnormBlock = VK_FORMAT_ASTC_6x5_UNORM_BLOCK,\n    eAstc6x5SrgbBlock = VK_FORMAT_ASTC_6x5_SRGB_BLOCK,\n    eAstc6x6UnormBlock = VK_FORMAT_ASTC_6x6_UNORM_BLOCK,\n    eAstc6x6SrgbBlock = VK_FORMAT_ASTC_6x6_SRGB_BLOCK,\n    eAstc8x5UnormBlock = VK_FORMAT_ASTC_8x5_UNORM_BLOCK,\n    eAstc8x5SrgbBlock = VK_FORMAT_ASTC_8x5_SRGB_BLOCK,\n    eAstc8x6UnormBlock = VK_FORMAT_ASTC_8x6_UNORM_BLOCK,\n    eAstc8x6SrgbBlock = VK_FORMAT_ASTC_8x6_SRGB_BLOCK,\n    eAstc8x8UnormBlock = VK_FORMAT_ASTC_8x8_UNORM_BLOCK,\n    eAstc8x8SrgbBlock = VK_FORMAT_ASTC_8x8_SRGB_BLOCK,\n    eAstc10x5UnormBlock = VK_FORMAT_ASTC_10x5_UNORM_BLOCK,\n    eAstc10x5SrgbBlock = VK_FORMAT_ASTC_10x5_SRGB_BLOCK,\n    eAstc10x6UnormBlock = VK_FORMAT_ASTC_10x6_UNORM_BLOCK,\n    eAstc10x6SrgbBlock = VK_FORMAT_ASTC_10x6_SRGB_BLOCK,\n    eAstc10x8UnormBlock = VK_FORMAT_ASTC_10x8_UNORM_BLOCK,\n    eAstc10x8SrgbBlock = VK_FORMAT_ASTC_10x8_SRGB_BLOCK,\n    eAstc10x10UnormBlock = VK_FORMAT_ASTC_10x10_UNORM_BLOCK,\n    eAstc10x10SrgbBlock = VK_FORMAT_ASTC_10x10_SRGB_BLOCK,\n    eAstc12x10UnormBlock = VK_FORMAT_ASTC_12x10_UNORM_BLOCK,\n    eAstc12x10SrgbBlock = VK_FORMAT_ASTC_12x10_SRGB_BLOCK,\n    eAstc12x12UnormBlock = VK_FORMAT_ASTC_12x12_UNORM_BLOCK,\n    eAstc12x12SrgbBlock = VK_FORMAT_ASTC_12x12_SRGB_BLOCK,\n    ePvrtc12BppUnormBlockIMG = VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG,\n    ePvrtc14BppUnormBlockIMG = VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG,\n    ePvrtc22BppUnormBlockIMG = VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG,\n    ePvrtc24BppUnormBlockIMG = VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG,\n    ePvrtc12BppSrgbBlockIMG = VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG,\n    ePvrtc14BppSrgbBlockIMG = VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG,\n    ePvrtc22BppSrgbBlockIMG = VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG,\n    ePvrtc24BppSrgbBlockIMG = VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG\n  };\n\n  struct VertexInputAttributeDescription\n  {\n    VertexInputAttributeDescription( uint32_t location_ = 0, uint32_t binding_ = 0, Format format_ = Format::eUndefined, uint32_t offset_ = 0 )\n      : location( location_ )\n      , binding( binding_ )\n      , format( format_ )\n      , offset( offset_ )\n    {\n    }\n\n    VertexInputAttributeDescription( VkVertexInputAttributeDescription const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(VertexInputAttributeDescription) );\n    }\n\n    VertexInputAttributeDescription& operator=( VkVertexInputAttributeDescription const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(VertexInputAttributeDescription) );\n      return *this;\n    }\n\n    VertexInputAttributeDescription& setLocation( uint32_t location_ )\n    {\n      location = location_;\n      return *this;\n    }\n\n    VertexInputAttributeDescription& setBinding( uint32_t binding_ )\n    {\n      binding = binding_;\n      return *this;\n    }\n\n    VertexInputAttributeDescription& setFormat( Format format_ )\n    {\n      format = format_;\n      return *this;\n    }\n\n    VertexInputAttributeDescription& setOffset( uint32_t offset_ )\n    {\n      offset = offset_;\n      return *this;\n    }\n\n    operator const VkVertexInputAttributeDescription&() const\n    {\n      return *reinterpret_cast<const VkVertexInputAttributeDescription*>(this);\n    }\n\n    bool operator==( VertexInputAttributeDescription const& rhs ) const\n    {\n      return ( location == rhs.location )\n          && ( binding == rhs.binding )\n          && ( format == rhs.format )\n          && ( offset == rhs.offset );\n    }\n\n    bool operator!=( VertexInputAttributeDescription const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    uint32_t location;\n    uint32_t binding;\n    Format format;\n    uint32_t offset;\n  };\n  static_assert( sizeof( VertexInputAttributeDescription ) == sizeof( VkVertexInputAttributeDescription ), \"struct and wrapper have different size!\" );\n\n  enum class StructureType\n  {\n    eApplicationInfo = VK_STRUCTURE_TYPE_APPLICATION_INFO,\n    eInstanceCreateInfo = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,\n    eDeviceQueueCreateInfo = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,\n    eDeviceCreateInfo = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,\n    eSubmitInfo = VK_STRUCTURE_TYPE_SUBMIT_INFO,\n    eMemoryAllocateInfo = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,\n    eMappedMemoryRange = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,\n    eBindSparseInfo = VK_STRUCTURE_TYPE_BIND_SPARSE_INFO,\n    eFenceCreateInfo = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,\n    eSemaphoreCreateInfo = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,\n    eEventCreateInfo = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO,\n    eQueryPoolCreateInfo = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO,\n    eBufferCreateInfo = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,\n    eBufferViewCreateInfo = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO,\n    eImageCreateInfo = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,\n    eImageViewCreateInfo = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,\n    eShaderModuleCreateInfo = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,\n    ePipelineCacheCreateInfo = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO,\n    ePipelineShaderStageCreateInfo = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,\n    ePipelineVertexInputStateCreateInfo = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,\n    ePipelineInputAssemblyStateCreateInfo = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,\n    ePipelineTessellationStateCreateInfo = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO,\n    ePipelineViewportStateCreateInfo = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,\n    ePipelineRasterizationStateCreateInfo = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,\n    ePipelineMultisampleStateCreateInfo = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,\n    ePipelineDepthStencilStateCreateInfo = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,\n    ePipelineColorBlendStateCreateInfo = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,\n    ePipelineDynamicStateCreateInfo = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,\n    eGraphicsPipelineCreateInfo = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,\n    eComputePipelineCreateInfo = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,\n    ePipelineLayoutCreateInfo = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,\n    eSamplerCreateInfo = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,\n    eDescriptorSetLayoutCreateInfo = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,\n    eDescriptorPoolCreateInfo = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,\n    eDescriptorSetAllocateInfo = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,\n    eWriteDescriptorSet = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,\n    eCopyDescriptorSet = VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET,\n    eFramebufferCreateInfo = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,\n    eRenderPassCreateInfo = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,\n    eCommandPoolCreateInfo = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,\n    eCommandBufferAllocateInfo = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,\n    eCommandBufferInheritanceInfo = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,\n    eCommandBufferBeginInfo = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,\n    eRenderPassBeginInfo = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,\n    eBufferMemoryBarrier = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,\n    eImageMemoryBarrier = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,\n    eMemoryBarrier = VK_STRUCTURE_TYPE_MEMORY_BARRIER,\n    eLoaderInstanceCreateInfo = VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO,\n    eLoaderDeviceCreateInfo = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO,\n    eSwapchainCreateInfoKHR = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,\n    ePresentInfoKHR = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,\n    eDisplayModeCreateInfoKHR = VK_STRUCTURE_TYPE_DISPLAY_MODE_CREATE_INFO_KHR,\n    eDisplaySurfaceCreateInfoKHR = VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR,\n    eDisplayPresentInfoKHR = VK_STRUCTURE_TYPE_DISPLAY_PRESENT_INFO_KHR,\n    eXlibSurfaceCreateInfoKHR = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR,\n    eXcbSurfaceCreateInfoKHR = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR,\n    eWaylandSurfaceCreateInfoKHR = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR,\n    eMirSurfaceCreateInfoKHR = VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR,\n    eAndroidSurfaceCreateInfoKHR = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR,\n    eWin32SurfaceCreateInfoKHR = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR,\n    eDebugReportCallbackCreateInfoEXT = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT,\n    ePipelineRasterizationStateRasterizationOrderAMD = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_RASTERIZATION_ORDER_AMD,\n    eDebugMarkerObjectNameInfoEXT = VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_NAME_INFO_EXT,\n    eDebugMarkerObjectTagInfoEXT = VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_TAG_INFO_EXT,\n    eDebugMarkerMarkerInfoEXT = VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT,\n    eDedicatedAllocationImageCreateInfoNV = VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_IMAGE_CREATE_INFO_NV,\n    eDedicatedAllocationBufferCreateInfoNV = VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_BUFFER_CREATE_INFO_NV,\n    eDedicatedAllocationMemoryAllocateInfoNV = VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV,\n    eRenderPassMultiviewCreateInfoKHX = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO_KHX,\n    ePhysicalDeviceMultiviewFeaturesKHX = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHX,\n    ePhysicalDeviceMultiviewPropertiesKHX = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHX,\n    eExternalMemoryImageCreateInfoNV = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_NV,\n    eExportMemoryAllocateInfoNV = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_NV,\n    eImportMemoryWin32HandleInfoNV = VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_NV,\n    eExportMemoryWin32HandleInfoNV = VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_NV,\n    eWin32KeyedMutexAcquireReleaseInfoNV = VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_NV,\n    ePhysicalDeviceFeatures2KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR,\n    ePhysicalDeviceProperties2KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR,\n    eFormatProperties2KHR = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2_KHR,\n    eImageFormatProperties2KHR = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHR,\n    ePhysicalDeviceImageFormatInfo2KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHR,\n    eQueueFamilyProperties2KHR = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR,\n    ePhysicalDeviceMemoryProperties2KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR,\n    eSparseImageFormatProperties2KHR = VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2_KHR,\n    ePhysicalDeviceSparseImageFormatInfo2KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2_KHR,\n    eMemoryAllocateFlagsInfoKHX = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHX,\n    eBindBufferMemoryInfoKHX = VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO_KHX,\n    eBindImageMemoryInfoKHX = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHX,\n    eDeviceGroupRenderPassBeginInfoKHX = VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO_KHX,\n    eDeviceGroupCommandBufferBeginInfoKHX = VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO_KHX,\n    eDeviceGroupSubmitInfoKHX = VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO_KHX,\n    eDeviceGroupBindSparseInfoKHX = VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO_KHX,\n    eDeviceGroupPresentCapabilitiesKHX = VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHX,\n    eImageSwapchainCreateInfoKHX = VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHX,\n    eBindImageMemorySwapchainInfoKHX = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHX,\n    eAcquireNextImageInfoKHX = VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHX,\n    eDeviceGroupPresentInfoKHX = VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_INFO_KHX,\n    eDeviceGroupSwapchainCreateInfoKHX = VK_STRUCTURE_TYPE_DEVICE_GROUP_SWAPCHAIN_CREATE_INFO_KHX,\n    eValidationFlagsEXT = VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT,\n    eViSurfaceCreateInfoNN = VK_STRUCTURE_TYPE_VI_SURFACE_CREATE_INFO_NN,\n    ePhysicalDeviceGroupPropertiesKHX = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES_KHX,\n    eDeviceGroupDeviceCreateInfoKHX = VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHX,\n    ePhysicalDeviceExternalImageFormatInfoKHX = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO_KHX,\n    eExternalImageFormatPropertiesKHX = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHX,\n    ePhysicalDeviceExternalBufferInfoKHX = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO_KHX,\n    eExternalBufferPropertiesKHX = VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES_KHX,\n    ePhysicalDeviceIdPropertiesKHX = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHX,\n    eExternalMemoryBufferCreateInfoKHX = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHX,\n    eExternalMemoryImageCreateInfoKHX = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHX,\n    eExportMemoryAllocateInfoKHX = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHX,\n    eImportMemoryWin32HandleInfoKHX = VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHX,\n    eExportMemoryWin32HandleInfoKHX = VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHX,\n    eMemoryWin32HandlePropertiesKHX = VK_STRUCTURE_TYPE_MEMORY_WIN32_HANDLE_PROPERTIES_KHX,\n    eImportMemoryFdInfoKHX = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHX,\n    eMemoryFdPropertiesKHX = VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHX,\n    eWin32KeyedMutexAcquireReleaseInfoKHX = VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_KHX,\n    ePhysicalDeviceExternalSemaphoreInfoKHX = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO_KHX,\n    eExternalSemaphorePropertiesKHX = VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES_KHX,\n    eExportSemaphoreCreateInfoKHX = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO_KHX,\n    eImportSemaphoreWin32HandleInfoKHX = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHX,\n    eExportSemaphoreWin32HandleInfoKHX = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHX,\n    eD3D12FenceSubmitInfoKHX = VK_STRUCTURE_TYPE_D3D12_FENCE_SUBMIT_INFO_KHX,\n    eImportSemaphoreFdInfoKHX = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHX,\n    ePhysicalDevicePushDescriptorPropertiesKHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR,\n    ePresentRegionsKHR = VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR,\n    eDescriptorUpdateTemplateCreateInfoKHR = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR,\n    eObjectTableCreateInfoNVX = VK_STRUCTURE_TYPE_OBJECT_TABLE_CREATE_INFO_NVX,\n    eIndirectCommandsLayoutCreateInfoNVX = VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_CREATE_INFO_NVX,\n    eCmdProcessCommandsInfoNVX = VK_STRUCTURE_TYPE_CMD_PROCESS_COMMANDS_INFO_NVX,\n    eCmdReserveSpaceForCommandsInfoNVX = VK_STRUCTURE_TYPE_CMD_RESERVE_SPACE_FOR_COMMANDS_INFO_NVX,\n    eDeviceGeneratedCommandsLimitsNVX = VK_STRUCTURE_TYPE_DEVICE_GENERATED_COMMANDS_LIMITS_NVX,\n    eDeviceGeneratedCommandsFeaturesNVX = VK_STRUCTURE_TYPE_DEVICE_GENERATED_COMMANDS_FEATURES_NVX,\n    ePipelineViewportWScalingStateCreateInfoNV = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_W_SCALING_STATE_CREATE_INFO_NV,\n    eSurfaceCapabilities2EXT = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES2_EXT,\n    eDisplayPowerInfoEXT = VK_STRUCTURE_TYPE_DISPLAY_POWER_INFO_EXT,\n    eDeviceEventInfoEXT = VK_STRUCTURE_TYPE_DEVICE_EVENT_INFO_EXT,\n    eDisplayEventInfoEXT = VK_STRUCTURE_TYPE_DISPLAY_EVENT_INFO_EXT,\n    eSwapchainCounterCreateInfoEXT = VK_STRUCTURE_TYPE_SWAPCHAIN_COUNTER_CREATE_INFO_EXT,\n    ePresentTimesInfoGOOGLE = VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE,\n    ePhysicalDeviceMultiviewPerViewAttributesPropertiesNVX = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_ATTRIBUTES_PROPERTIES_NVX,\n    ePipelineViewportSwizzleStateCreateInfoNV = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV,\n    ePhysicalDeviceDiscardRectanglePropertiesEXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT,\n    ePipelineDiscardRectangleStateCreateInfoEXT = VK_STRUCTURE_TYPE_PIPELINE_DISCARD_RECTANGLE_STATE_CREATE_INFO_EXT,\n    eHdrMetadataEXT = VK_STRUCTURE_TYPE_HDR_METADATA_EXT,\n    eSharedPresentSurfaceCapabilitiesKHR = VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR,\n    ePhysicalDeviceSurfaceInfo2KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR,\n    eSurfaceCapabilities2KHR = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR,\n    eSurfaceFormat2KHR = VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR,\n    eIosSurfaceCreateInfoMVK = VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK,\n    eMacosSurfaceCreateInfoMVK = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK\n  };\n\n  struct ApplicationInfo\n  {\n    ApplicationInfo( const char* pApplicationName_ = nullptr, uint32_t applicationVersion_ = 0, const char* pEngineName_ = nullptr, uint32_t engineVersion_ = 0, uint32_t apiVersion_ = 0 )\n      : sType( StructureType::eApplicationInfo )\n      , pNext( nullptr )\n      , pApplicationName( pApplicationName_ )\n      , applicationVersion( applicationVersion_ )\n      , pEngineName( pEngineName_ )\n      , engineVersion( engineVersion_ )\n      , apiVersion( apiVersion_ )\n    {\n    }\n\n    ApplicationInfo( VkApplicationInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ApplicationInfo) );\n    }\n\n    ApplicationInfo& operator=( VkApplicationInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ApplicationInfo) );\n      return *this;\n    }\n\n    ApplicationInfo& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    ApplicationInfo& setPApplicationName( const char* pApplicationName_ )\n    {\n      pApplicationName = pApplicationName_;\n      return *this;\n    }\n\n    ApplicationInfo& setApplicationVersion( uint32_t applicationVersion_ )\n    {\n      applicationVersion = applicationVersion_;\n      return *this;\n    }\n\n    ApplicationInfo& setPEngineName( const char* pEngineName_ )\n    {\n      pEngineName = pEngineName_;\n      return *this;\n    }\n\n    ApplicationInfo& setEngineVersion( uint32_t engineVersion_ )\n    {\n      engineVersion = engineVersion_;\n      return *this;\n    }\n\n    ApplicationInfo& setApiVersion( uint32_t apiVersion_ )\n    {\n      apiVersion = apiVersion_;\n      return *this;\n    }\n\n    operator const VkApplicationInfo&() const\n    {\n      return *reinterpret_cast<const VkApplicationInfo*>(this);\n    }\n\n    bool operator==( ApplicationInfo const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( pApplicationName == rhs.pApplicationName )\n          && ( applicationVersion == rhs.applicationVersion )\n          && ( pEngineName == rhs.pEngineName )\n          && ( engineVersion == rhs.engineVersion )\n          && ( apiVersion == rhs.apiVersion );\n    }\n\n    bool operator!=( ApplicationInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    const char* pApplicationName;\n    uint32_t applicationVersion;\n    const char* pEngineName;\n    uint32_t engineVersion;\n    uint32_t apiVersion;\n  };\n  static_assert( sizeof( ApplicationInfo ) == sizeof( VkApplicationInfo ), \"struct and wrapper have different size!\" );\n\n  struct DeviceQueueCreateInfo\n  {\n    DeviceQueueCreateInfo( DeviceQueueCreateFlags flags_ = DeviceQueueCreateFlags(), uint32_t queueFamilyIndex_ = 0, uint32_t queueCount_ = 0, const float* pQueuePriorities_ = nullptr )\n      : sType( StructureType::eDeviceQueueCreateInfo )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , queueFamilyIndex( queueFamilyIndex_ )\n      , queueCount( queueCount_ )\n      , pQueuePriorities( pQueuePriorities_ )\n    {\n    }\n\n    DeviceQueueCreateInfo( VkDeviceQueueCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DeviceQueueCreateInfo) );\n    }\n\n    DeviceQueueCreateInfo& operator=( VkDeviceQueueCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DeviceQueueCreateInfo) );\n      return *this;\n    }\n\n    DeviceQueueCreateInfo& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    DeviceQueueCreateInfo& setFlags( DeviceQueueCreateFlags flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    DeviceQueueCreateInfo& setQueueFamilyIndex( uint32_t queueFamilyIndex_ )\n    {\n      queueFamilyIndex = queueFamilyIndex_;\n      return *this;\n    }\n\n    DeviceQueueCreateInfo& setQueueCount( uint32_t queueCount_ )\n    {\n      queueCount = queueCount_;\n      return *this;\n    }\n\n    DeviceQueueCreateInfo& setPQueuePriorities( const float* pQueuePriorities_ )\n    {\n      pQueuePriorities = pQueuePriorities_;\n      return *this;\n    }\n\n    operator const VkDeviceQueueCreateInfo&() const\n    {\n      return *reinterpret_cast<const VkDeviceQueueCreateInfo*>(this);\n    }\n\n    bool operator==( DeviceQueueCreateInfo const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( queueFamilyIndex == rhs.queueFamilyIndex )\n          && ( queueCount == rhs.queueCount )\n          && ( pQueuePriorities == rhs.pQueuePriorities );\n    }\n\n    bool operator!=( DeviceQueueCreateInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    DeviceQueueCreateFlags flags;\n    uint32_t queueFamilyIndex;\n    uint32_t queueCount;\n    const float* pQueuePriorities;\n  };\n  static_assert( sizeof( DeviceQueueCreateInfo ) == sizeof( VkDeviceQueueCreateInfo ), \"struct and wrapper have different size!\" );\n\n  struct DeviceCreateInfo\n  {\n    DeviceCreateInfo( DeviceCreateFlags flags_ = DeviceCreateFlags(), uint32_t queueCreateInfoCount_ = 0, const DeviceQueueCreateInfo* pQueueCreateInfos_ = nullptr, uint32_t enabledLayerCount_ = 0, const char* const* ppEnabledLayerNames_ = nullptr, uint32_t enabledExtensionCount_ = 0, const char* const* ppEnabledExtensionNames_ = nullptr, const PhysicalDeviceFeatures* pEnabledFeatures_ = nullptr )\n      : sType( StructureType::eDeviceCreateInfo )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , queueCreateInfoCount( queueCreateInfoCount_ )\n      , pQueueCreateInfos( pQueueCreateInfos_ )\n      , enabledLayerCount( enabledLayerCount_ )\n      , ppEnabledLayerNames( ppEnabledLayerNames_ )\n      , enabledExtensionCount( enabledExtensionCount_ )\n      , ppEnabledExtensionNames( ppEnabledExtensionNames_ )\n      , pEnabledFeatures( pEnabledFeatures_ )\n    {\n    }\n\n    DeviceCreateInfo( VkDeviceCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DeviceCreateInfo) );\n    }\n\n    DeviceCreateInfo& operator=( VkDeviceCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DeviceCreateInfo) );\n      return *this;\n    }\n\n    DeviceCreateInfo& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    DeviceCreateInfo& setFlags( DeviceCreateFlags flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    DeviceCreateInfo& setQueueCreateInfoCount( uint32_t queueCreateInfoCount_ )\n    {\n      queueCreateInfoCount = queueCreateInfoCount_;\n      return *this;\n    }\n\n    DeviceCreateInfo& setPQueueCreateInfos( const DeviceQueueCreateInfo* pQueueCreateInfos_ )\n    {\n      pQueueCreateInfos = pQueueCreateInfos_;\n      return *this;\n    }\n\n    DeviceCreateInfo& setEnabledLayerCount( uint32_t enabledLayerCount_ )\n    {\n      enabledLayerCount = enabledLayerCount_;\n      return *this;\n    }\n\n    DeviceCreateInfo& setPpEnabledLayerNames( const char* const* ppEnabledLayerNames_ )\n    {\n      ppEnabledLayerNames = ppEnabledLayerNames_;\n      return *this;\n    }\n\n    DeviceCreateInfo& setEnabledExtensionCount( uint32_t enabledExtensionCount_ )\n    {\n      enabledExtensionCount = enabledExtensionCount_;\n      return *this;\n    }\n\n    DeviceCreateInfo& setPpEnabledExtensionNames( const char* const* ppEnabledExtensionNames_ )\n    {\n      ppEnabledExtensionNames = ppEnabledExtensionNames_;\n      return *this;\n    }\n\n    DeviceCreateInfo& setPEnabledFeatures( const PhysicalDeviceFeatures* pEnabledFeatures_ )\n    {\n      pEnabledFeatures = pEnabledFeatures_;\n      return *this;\n    }\n\n    operator const VkDeviceCreateInfo&() const\n    {\n      return *reinterpret_cast<const VkDeviceCreateInfo*>(this);\n    }\n\n    bool operator==( DeviceCreateInfo const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( queueCreateInfoCount == rhs.queueCreateInfoCount )\n          && ( pQueueCreateInfos == rhs.pQueueCreateInfos )\n          && ( enabledLayerCount == rhs.enabledLayerCount )\n          && ( ppEnabledLayerNames == rhs.ppEnabledLayerNames )\n          && ( enabledExtensionCount == rhs.enabledExtensionCount )\n          && ( ppEnabledExtensionNames == rhs.ppEnabledExtensionNames )\n          && ( pEnabledFeatures == rhs.pEnabledFeatures );\n    }\n\n    bool operator!=( DeviceCreateInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    DeviceCreateFlags flags;\n    uint32_t queueCreateInfoCount;\n    const DeviceQueueCreateInfo* pQueueCreateInfos;\n    uint32_t enabledLayerCount;\n    const char* const* ppEnabledLayerNames;\n    uint32_t enabledExtensionCount;\n    const char* const* ppEnabledExtensionNames;\n    const PhysicalDeviceFeatures* pEnabledFeatures;\n  };\n  static_assert( sizeof( DeviceCreateInfo ) == sizeof( VkDeviceCreateInfo ), \"struct and wrapper have different size!\" );\n\n  struct InstanceCreateInfo\n  {\n    InstanceCreateInfo( InstanceCreateFlags flags_ = InstanceCreateFlags(), const ApplicationInfo* pApplicationInfo_ = nullptr, uint32_t enabledLayerCount_ = 0, const char* const* ppEnabledLayerNames_ = nullptr, uint32_t enabledExtensionCount_ = 0, const char* const* ppEnabledExtensionNames_ = nullptr )\n      : sType( StructureType::eInstanceCreateInfo )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , pApplicationInfo( pApplicationInfo_ )\n      , enabledLayerCount( enabledLayerCount_ )\n      , ppEnabledLayerNames( ppEnabledLayerNames_ )\n      , enabledExtensionCount( enabledExtensionCount_ )\n      , ppEnabledExtensionNames( ppEnabledExtensionNames_ )\n    {\n    }\n\n    InstanceCreateInfo( VkInstanceCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(InstanceCreateInfo) );\n    }\n\n    InstanceCreateInfo& operator=( VkInstanceCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(InstanceCreateInfo) );\n      return *this;\n    }\n\n    InstanceCreateInfo& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    InstanceCreateInfo& setFlags( InstanceCreateFlags flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    InstanceCreateInfo& setPApplicationInfo( const ApplicationInfo* pApplicationInfo_ )\n    {\n      pApplicationInfo = pApplicationInfo_;\n      return *this;\n    }\n\n    InstanceCreateInfo& setEnabledLayerCount( uint32_t enabledLayerCount_ )\n    {\n      enabledLayerCount = enabledLayerCount_;\n      return *this;\n    }\n\n    InstanceCreateInfo& setPpEnabledLayerNames( const char* const* ppEnabledLayerNames_ )\n    {\n      ppEnabledLayerNames = ppEnabledLayerNames_;\n      return *this;\n    }\n\n    InstanceCreateInfo& setEnabledExtensionCount( uint32_t enabledExtensionCount_ )\n    {\n      enabledExtensionCount = enabledExtensionCount_;\n      return *this;\n    }\n\n    InstanceCreateInfo& setPpEnabledExtensionNames( const char* const* ppEnabledExtensionNames_ )\n    {\n      ppEnabledExtensionNames = ppEnabledExtensionNames_;\n      return *this;\n    }\n\n    operator const VkInstanceCreateInfo&() const\n    {\n      return *reinterpret_cast<const VkInstanceCreateInfo*>(this);\n    }\n\n    bool operator==( InstanceCreateInfo const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( pApplicationInfo == rhs.pApplicationInfo )\n          && ( enabledLayerCount == rhs.enabledLayerCount )\n          && ( ppEnabledLayerNames == rhs.ppEnabledLayerNames )\n          && ( enabledExtensionCount == rhs.enabledExtensionCount )\n          && ( ppEnabledExtensionNames == rhs.ppEnabledExtensionNames );\n    }\n\n    bool operator!=( InstanceCreateInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    InstanceCreateFlags flags;\n    const ApplicationInfo* pApplicationInfo;\n    uint32_t enabledLayerCount;\n    const char* const* ppEnabledLayerNames;\n    uint32_t enabledExtensionCount;\n    const char* const* ppEnabledExtensionNames;\n  };\n  static_assert( sizeof( InstanceCreateInfo ) == sizeof( VkInstanceCreateInfo ), \"struct and wrapper have different size!\" );\n\n  struct MemoryAllocateInfo\n  {\n    MemoryAllocateInfo( DeviceSize allocationSize_ = 0, uint32_t memoryTypeIndex_ = 0 )\n      : sType( StructureType::eMemoryAllocateInfo )\n      , pNext( nullptr )\n      , allocationSize( allocationSize_ )\n      , memoryTypeIndex( memoryTypeIndex_ )\n    {\n    }\n\n    MemoryAllocateInfo( VkMemoryAllocateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(MemoryAllocateInfo) );\n    }\n\n    MemoryAllocateInfo& operator=( VkMemoryAllocateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(MemoryAllocateInfo) );\n      return *this;\n    }\n\n    MemoryAllocateInfo& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    MemoryAllocateInfo& setAllocationSize( DeviceSize allocationSize_ )\n    {\n      allocationSize = allocationSize_;\n      return *this;\n    }\n\n    MemoryAllocateInfo& setMemoryTypeIndex( uint32_t memoryTypeIndex_ )\n    {\n      memoryTypeIndex = memoryTypeIndex_;\n      return *this;\n    }\n\n    operator const VkMemoryAllocateInfo&() const\n    {\n      return *reinterpret_cast<const VkMemoryAllocateInfo*>(this);\n    }\n\n    bool operator==( MemoryAllocateInfo const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( allocationSize == rhs.allocationSize )\n          && ( memoryTypeIndex == rhs.memoryTypeIndex );\n    }\n\n    bool operator!=( MemoryAllocateInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    DeviceSize allocationSize;\n    uint32_t memoryTypeIndex;\n  };\n  static_assert( sizeof( MemoryAllocateInfo ) == sizeof( VkMemoryAllocateInfo ), \"struct and wrapper have different size!\" );\n\n  struct MappedMemoryRange\n  {\n    MappedMemoryRange( DeviceMemory memory_ = DeviceMemory(), DeviceSize offset_ = 0, DeviceSize size_ = 0 )\n      : sType( StructureType::eMappedMemoryRange )\n      , pNext( nullptr )\n      , memory( memory_ )\n      , offset( offset_ )\n      , size( size_ )\n    {\n    }\n\n    MappedMemoryRange( VkMappedMemoryRange const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(MappedMemoryRange) );\n    }\n\n    MappedMemoryRange& operator=( VkMappedMemoryRange const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(MappedMemoryRange) );\n      return *this;\n    }\n\n    MappedMemoryRange& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    MappedMemoryRange& setMemory( DeviceMemory memory_ )\n    {\n      memory = memory_;\n      return *this;\n    }\n\n    MappedMemoryRange& setOffset( DeviceSize offset_ )\n    {\n      offset = offset_;\n      return *this;\n    }\n\n    MappedMemoryRange& setSize( DeviceSize size_ )\n    {\n      size = size_;\n      return *this;\n    }\n\n    operator const VkMappedMemoryRange&() const\n    {\n      return *reinterpret_cast<const VkMappedMemoryRange*>(this);\n    }\n\n    bool operator==( MappedMemoryRange const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( memory == rhs.memory )\n          && ( offset == rhs.offset )\n          && ( size == rhs.size );\n    }\n\n    bool operator!=( MappedMemoryRange const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    DeviceMemory memory;\n    DeviceSize offset;\n    DeviceSize size;\n  };\n  static_assert( sizeof( MappedMemoryRange ) == sizeof( VkMappedMemoryRange ), \"struct and wrapper have different size!\" );\n\n  struct WriteDescriptorSet\n  {\n    WriteDescriptorSet( DescriptorSet dstSet_ = DescriptorSet(), uint32_t dstBinding_ = 0, uint32_t dstArrayElement_ = 0, uint32_t descriptorCount_ = 0, DescriptorType descriptorType_ = DescriptorType::eSampler, const DescriptorImageInfo* pImageInfo_ = nullptr, const DescriptorBufferInfo* pBufferInfo_ = nullptr, const BufferView* pTexelBufferView_ = nullptr )\n      : sType( StructureType::eWriteDescriptorSet )\n      , pNext( nullptr )\n      , dstSet( dstSet_ )\n      , dstBinding( dstBinding_ )\n      , dstArrayElement( dstArrayElement_ )\n      , descriptorCount( descriptorCount_ )\n      , descriptorType( descriptorType_ )\n      , pImageInfo( pImageInfo_ )\n      , pBufferInfo( pBufferInfo_ )\n      , pTexelBufferView( pTexelBufferView_ )\n    {\n    }\n\n    WriteDescriptorSet( VkWriteDescriptorSet const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(WriteDescriptorSet) );\n    }\n\n    WriteDescriptorSet& operator=( VkWriteDescriptorSet const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(WriteDescriptorSet) );\n      return *this;\n    }\n\n    WriteDescriptorSet& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    WriteDescriptorSet& setDstSet( DescriptorSet dstSet_ )\n    {\n      dstSet = dstSet_;\n      return *this;\n    }\n\n    WriteDescriptorSet& setDstBinding( uint32_t dstBinding_ )\n    {\n      dstBinding = dstBinding_;\n      return *this;\n    }\n\n    WriteDescriptorSet& setDstArrayElement( uint32_t dstArrayElement_ )\n    {\n      dstArrayElement = dstArrayElement_;\n      return *this;\n    }\n\n    WriteDescriptorSet& setDescriptorCount( uint32_t descriptorCount_ )\n    {\n      descriptorCount = descriptorCount_;\n      return *this;\n    }\n\n    WriteDescriptorSet& setDescriptorType( DescriptorType descriptorType_ )\n    {\n      descriptorType = descriptorType_;\n      return *this;\n    }\n\n    WriteDescriptorSet& setPImageInfo( const DescriptorImageInfo* pImageInfo_ )\n    {\n      pImageInfo = pImageInfo_;\n      return *this;\n    }\n\n    WriteDescriptorSet& setPBufferInfo( const DescriptorBufferInfo* pBufferInfo_ )\n    {\n      pBufferInfo = pBufferInfo_;\n      return *this;\n    }\n\n    WriteDescriptorSet& setPTexelBufferView( const BufferView* pTexelBufferView_ )\n    {\n      pTexelBufferView = pTexelBufferView_;\n      return *this;\n    }\n\n    operator const VkWriteDescriptorSet&() const\n    {\n      return *reinterpret_cast<const VkWriteDescriptorSet*>(this);\n    }\n\n    bool operator==( WriteDescriptorSet const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( dstSet == rhs.dstSet )\n          && ( dstBinding == rhs.dstBinding )\n          && ( dstArrayElement == rhs.dstArrayElement )\n          && ( descriptorCount == rhs.descriptorCount )\n          && ( descriptorType == rhs.descriptorType )\n          && ( pImageInfo == rhs.pImageInfo )\n          && ( pBufferInfo == rhs.pBufferInfo )\n          && ( pTexelBufferView == rhs.pTexelBufferView );\n    }\n\n    bool operator!=( WriteDescriptorSet const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    DescriptorSet dstSet;\n    uint32_t dstBinding;\n    uint32_t dstArrayElement;\n    uint32_t descriptorCount;\n    DescriptorType descriptorType;\n    const DescriptorImageInfo* pImageInfo;\n    const DescriptorBufferInfo* pBufferInfo;\n    const BufferView* pTexelBufferView;\n  };\n  static_assert( sizeof( WriteDescriptorSet ) == sizeof( VkWriteDescriptorSet ), \"struct and wrapper have different size!\" );\n\n  struct CopyDescriptorSet\n  {\n    CopyDescriptorSet( DescriptorSet srcSet_ = DescriptorSet(), uint32_t srcBinding_ = 0, uint32_t srcArrayElement_ = 0, DescriptorSet dstSet_ = DescriptorSet(), uint32_t dstBinding_ = 0, uint32_t dstArrayElement_ = 0, uint32_t descriptorCount_ = 0 )\n      : sType( StructureType::eCopyDescriptorSet )\n      , pNext( nullptr )\n      , srcSet( srcSet_ )\n      , srcBinding( srcBinding_ )\n      , srcArrayElement( srcArrayElement_ )\n      , dstSet( dstSet_ )\n      , dstBinding( dstBinding_ )\n      , dstArrayElement( dstArrayElement_ )\n      , descriptorCount( descriptorCount_ )\n    {\n    }\n\n    CopyDescriptorSet( VkCopyDescriptorSet const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(CopyDescriptorSet) );\n    }\n\n    CopyDescriptorSet& operator=( VkCopyDescriptorSet const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(CopyDescriptorSet) );\n      return *this;\n    }\n\n    CopyDescriptorSet& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    CopyDescriptorSet& setSrcSet( DescriptorSet srcSet_ )\n    {\n      srcSet = srcSet_;\n      return *this;\n    }\n\n    CopyDescriptorSet& setSrcBinding( uint32_t srcBinding_ )\n    {\n      srcBinding = srcBinding_;\n      return *this;\n    }\n\n    CopyDescriptorSet& setSrcArrayElement( uint32_t srcArrayElement_ )\n    {\n      srcArrayElement = srcArrayElement_;\n      return *this;\n    }\n\n    CopyDescriptorSet& setDstSet( DescriptorSet dstSet_ )\n    {\n      dstSet = dstSet_;\n      return *this;\n    }\n\n    CopyDescriptorSet& setDstBinding( uint32_t dstBinding_ )\n    {\n      dstBinding = dstBinding_;\n      return *this;\n    }\n\n    CopyDescriptorSet& setDstArrayElement( uint32_t dstArrayElement_ )\n    {\n      dstArrayElement = dstArrayElement_;\n      return *this;\n    }\n\n    CopyDescriptorSet& setDescriptorCount( uint32_t descriptorCount_ )\n    {\n      descriptorCount = descriptorCount_;\n      return *this;\n    }\n\n    operator const VkCopyDescriptorSet&() const\n    {\n      return *reinterpret_cast<const VkCopyDescriptorSet*>(this);\n    }\n\n    bool operator==( CopyDescriptorSet const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( srcSet == rhs.srcSet )\n          && ( srcBinding == rhs.srcBinding )\n          && ( srcArrayElement == rhs.srcArrayElement )\n          && ( dstSet == rhs.dstSet )\n          && ( dstBinding == rhs.dstBinding )\n          && ( dstArrayElement == rhs.dstArrayElement )\n          && ( descriptorCount == rhs.descriptorCount );\n    }\n\n    bool operator!=( CopyDescriptorSet const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    DescriptorSet srcSet;\n    uint32_t srcBinding;\n    uint32_t srcArrayElement;\n    DescriptorSet dstSet;\n    uint32_t dstBinding;\n    uint32_t dstArrayElement;\n    uint32_t descriptorCount;\n  };\n  static_assert( sizeof( CopyDescriptorSet ) == sizeof( VkCopyDescriptorSet ), \"struct and wrapper have different size!\" );\n\n  struct BufferViewCreateInfo\n  {\n    BufferViewCreateInfo( BufferViewCreateFlags flags_ = BufferViewCreateFlags(), Buffer buffer_ = Buffer(), Format format_ = Format::eUndefined, DeviceSize offset_ = 0, DeviceSize range_ = 0 )\n      : sType( StructureType::eBufferViewCreateInfo )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , buffer( buffer_ )\n      , format( format_ )\n      , offset( offset_ )\n      , range( range_ )\n    {\n    }\n\n    BufferViewCreateInfo( VkBufferViewCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(BufferViewCreateInfo) );\n    }\n\n    BufferViewCreateInfo& operator=( VkBufferViewCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(BufferViewCreateInfo) );\n      return *this;\n    }\n\n    BufferViewCreateInfo& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    BufferViewCreateInfo& setFlags( BufferViewCreateFlags flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    BufferViewCreateInfo& setBuffer( Buffer buffer_ )\n    {\n      buffer = buffer_;\n      return *this;\n    }\n\n    BufferViewCreateInfo& setFormat( Format format_ )\n    {\n      format = format_;\n      return *this;\n    }\n\n    BufferViewCreateInfo& setOffset( DeviceSize offset_ )\n    {\n      offset = offset_;\n      return *this;\n    }\n\n    BufferViewCreateInfo& setRange( DeviceSize range_ )\n    {\n      range = range_;\n      return *this;\n    }\n\n    operator const VkBufferViewCreateInfo&() const\n    {\n      return *reinterpret_cast<const VkBufferViewCreateInfo*>(this);\n    }\n\n    bool operator==( BufferViewCreateInfo const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( buffer == rhs.buffer )\n          && ( format == rhs.format )\n          && ( offset == rhs.offset )\n          && ( range == rhs.range );\n    }\n\n    bool operator!=( BufferViewCreateInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    BufferViewCreateFlags flags;\n    Buffer buffer;\n    Format format;\n    DeviceSize offset;\n    DeviceSize range;\n  };\n  static_assert( sizeof( BufferViewCreateInfo ) == sizeof( VkBufferViewCreateInfo ), \"struct and wrapper have different size!\" );\n\n  struct ShaderModuleCreateInfo\n  {\n    ShaderModuleCreateInfo( ShaderModuleCreateFlags flags_ = ShaderModuleCreateFlags(), size_t codeSize_ = 0, const uint32_t* pCode_ = nullptr )\n      : sType( StructureType::eShaderModuleCreateInfo )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , codeSize( codeSize_ )\n      , pCode( pCode_ )\n    {\n    }\n\n    ShaderModuleCreateInfo( VkShaderModuleCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ShaderModuleCreateInfo) );\n    }\n\n    ShaderModuleCreateInfo& operator=( VkShaderModuleCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ShaderModuleCreateInfo) );\n      return *this;\n    }\n\n    ShaderModuleCreateInfo& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    ShaderModuleCreateInfo& setFlags( ShaderModuleCreateFlags flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    ShaderModuleCreateInfo& setCodeSize( size_t codeSize_ )\n    {\n      codeSize = codeSize_;\n      return *this;\n    }\n\n    ShaderModuleCreateInfo& setPCode( const uint32_t* pCode_ )\n    {\n      pCode = pCode_;\n      return *this;\n    }\n\n    operator const VkShaderModuleCreateInfo&() const\n    {\n      return *reinterpret_cast<const VkShaderModuleCreateInfo*>(this);\n    }\n\n    bool operator==( ShaderModuleCreateInfo const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( codeSize == rhs.codeSize )\n          && ( pCode == rhs.pCode );\n    }\n\n    bool operator!=( ShaderModuleCreateInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    ShaderModuleCreateFlags flags;\n    size_t codeSize;\n    const uint32_t* pCode;\n  };\n  static_assert( sizeof( ShaderModuleCreateInfo ) == sizeof( VkShaderModuleCreateInfo ), \"struct and wrapper have different size!\" );\n\n  struct DescriptorSetAllocateInfo\n  {\n    DescriptorSetAllocateInfo( DescriptorPool descriptorPool_ = DescriptorPool(), uint32_t descriptorSetCount_ = 0, const DescriptorSetLayout* pSetLayouts_ = nullptr )\n      : sType( StructureType::eDescriptorSetAllocateInfo )\n      , pNext( nullptr )\n      , descriptorPool( descriptorPool_ )\n      , descriptorSetCount( descriptorSetCount_ )\n      , pSetLayouts( pSetLayouts_ )\n    {\n    }\n\n    DescriptorSetAllocateInfo( VkDescriptorSetAllocateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DescriptorSetAllocateInfo) );\n    }\n\n    DescriptorSetAllocateInfo& operator=( VkDescriptorSetAllocateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DescriptorSetAllocateInfo) );\n      return *this;\n    }\n\n    DescriptorSetAllocateInfo& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    DescriptorSetAllocateInfo& setDescriptorPool( DescriptorPool descriptorPool_ )\n    {\n      descriptorPool = descriptorPool_;\n      return *this;\n    }\n\n    DescriptorSetAllocateInfo& setDescriptorSetCount( uint32_t descriptorSetCount_ )\n    {\n      descriptorSetCount = descriptorSetCount_;\n      return *this;\n    }\n\n    DescriptorSetAllocateInfo& setPSetLayouts( const DescriptorSetLayout* pSetLayouts_ )\n    {\n      pSetLayouts = pSetLayouts_;\n      return *this;\n    }\n\n    operator const VkDescriptorSetAllocateInfo&() const\n    {\n      return *reinterpret_cast<const VkDescriptorSetAllocateInfo*>(this);\n    }\n\n    bool operator==( DescriptorSetAllocateInfo const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( descriptorPool == rhs.descriptorPool )\n          && ( descriptorSetCount == rhs.descriptorSetCount )\n          && ( pSetLayouts == rhs.pSetLayouts );\n    }\n\n    bool operator!=( DescriptorSetAllocateInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    DescriptorPool descriptorPool;\n    uint32_t descriptorSetCount;\n    const DescriptorSetLayout* pSetLayouts;\n  };\n  static_assert( sizeof( DescriptorSetAllocateInfo ) == sizeof( VkDescriptorSetAllocateInfo ), \"struct and wrapper have different size!\" );\n\n  struct PipelineVertexInputStateCreateInfo\n  {\n    PipelineVertexInputStateCreateInfo( PipelineVertexInputStateCreateFlags flags_ = PipelineVertexInputStateCreateFlags(), uint32_t vertexBindingDescriptionCount_ = 0, const VertexInputBindingDescription* pVertexBindingDescriptions_ = nullptr, uint32_t vertexAttributeDescriptionCount_ = 0, const VertexInputAttributeDescription* pVertexAttributeDescriptions_ = nullptr )\n      : sType( StructureType::ePipelineVertexInputStateCreateInfo )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , vertexBindingDescriptionCount( vertexBindingDescriptionCount_ )\n      , pVertexBindingDescriptions( pVertexBindingDescriptions_ )\n      , vertexAttributeDescriptionCount( vertexAttributeDescriptionCount_ )\n      , pVertexAttributeDescriptions( pVertexAttributeDescriptions_ )\n    {\n    }\n\n    PipelineVertexInputStateCreateInfo( VkPipelineVertexInputStateCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PipelineVertexInputStateCreateInfo) );\n    }\n\n    PipelineVertexInputStateCreateInfo& operator=( VkPipelineVertexInputStateCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PipelineVertexInputStateCreateInfo) );\n      return *this;\n    }\n\n    PipelineVertexInputStateCreateInfo& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    PipelineVertexInputStateCreateInfo& setFlags( PipelineVertexInputStateCreateFlags flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    PipelineVertexInputStateCreateInfo& setVertexBindingDescriptionCount( uint32_t vertexBindingDescriptionCount_ )\n    {\n      vertexBindingDescriptionCount = vertexBindingDescriptionCount_;\n      return *this;\n    }\n\n    PipelineVertexInputStateCreateInfo& setPVertexBindingDescriptions( const VertexInputBindingDescription* pVertexBindingDescriptions_ )\n    {\n      pVertexBindingDescriptions = pVertexBindingDescriptions_;\n      return *this;\n    }\n\n    PipelineVertexInputStateCreateInfo& setVertexAttributeDescriptionCount( uint32_t vertexAttributeDescriptionCount_ )\n    {\n      vertexAttributeDescriptionCount = vertexAttributeDescriptionCount_;\n      return *this;\n    }\n\n    PipelineVertexInputStateCreateInfo& setPVertexAttributeDescriptions( const VertexInputAttributeDescription* pVertexAttributeDescriptions_ )\n    {\n      pVertexAttributeDescriptions = pVertexAttributeDescriptions_;\n      return *this;\n    }\n\n    operator const VkPipelineVertexInputStateCreateInfo&() const\n    {\n      return *reinterpret_cast<const VkPipelineVertexInputStateCreateInfo*>(this);\n    }\n\n    bool operator==( PipelineVertexInputStateCreateInfo const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( vertexBindingDescriptionCount == rhs.vertexBindingDescriptionCount )\n          && ( pVertexBindingDescriptions == rhs.pVertexBindingDescriptions )\n          && ( vertexAttributeDescriptionCount == rhs.vertexAttributeDescriptionCount )\n          && ( pVertexAttributeDescriptions == rhs.pVertexAttributeDescriptions );\n    }\n\n    bool operator!=( PipelineVertexInputStateCreateInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    PipelineVertexInputStateCreateFlags flags;\n    uint32_t vertexBindingDescriptionCount;\n    const VertexInputBindingDescription* pVertexBindingDescriptions;\n    uint32_t vertexAttributeDescriptionCount;\n    const VertexInputAttributeDescription* pVertexAttributeDescriptions;\n  };\n  static_assert( sizeof( PipelineVertexInputStateCreateInfo ) == sizeof( VkPipelineVertexInputStateCreateInfo ), \"struct and wrapper have different size!\" );\n\n  struct PipelineInputAssemblyStateCreateInfo\n  {\n    PipelineInputAssemblyStateCreateInfo( PipelineInputAssemblyStateCreateFlags flags_ = PipelineInputAssemblyStateCreateFlags(), PrimitiveTopology topology_ = PrimitiveTopology::ePointList, Bool32 primitiveRestartEnable_ = 0 )\n      : sType( StructureType::ePipelineInputAssemblyStateCreateInfo )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , topology( topology_ )\n      , primitiveRestartEnable( primitiveRestartEnable_ )\n    {\n    }\n\n    PipelineInputAssemblyStateCreateInfo( VkPipelineInputAssemblyStateCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PipelineInputAssemblyStateCreateInfo) );\n    }\n\n    PipelineInputAssemblyStateCreateInfo& operator=( VkPipelineInputAssemblyStateCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PipelineInputAssemblyStateCreateInfo) );\n      return *this;\n    }\n\n    PipelineInputAssemblyStateCreateInfo& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    PipelineInputAssemblyStateCreateInfo& setFlags( PipelineInputAssemblyStateCreateFlags flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    PipelineInputAssemblyStateCreateInfo& setTopology( PrimitiveTopology topology_ )\n    {\n      topology = topology_;\n      return *this;\n    }\n\n    PipelineInputAssemblyStateCreateInfo& setPrimitiveRestartEnable( Bool32 primitiveRestartEnable_ )\n    {\n      primitiveRestartEnable = primitiveRestartEnable_;\n      return *this;\n    }\n\n    operator const VkPipelineInputAssemblyStateCreateInfo&() const\n    {\n      return *reinterpret_cast<const VkPipelineInputAssemblyStateCreateInfo*>(this);\n    }\n\n    bool operator==( PipelineInputAssemblyStateCreateInfo const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( topology == rhs.topology )\n          && ( primitiveRestartEnable == rhs.primitiveRestartEnable );\n    }\n\n    bool operator!=( PipelineInputAssemblyStateCreateInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    PipelineInputAssemblyStateCreateFlags flags;\n    PrimitiveTopology topology;\n    Bool32 primitiveRestartEnable;\n  };\n  static_assert( sizeof( PipelineInputAssemblyStateCreateInfo ) == sizeof( VkPipelineInputAssemblyStateCreateInfo ), \"struct and wrapper have different size!\" );\n\n  struct PipelineTessellationStateCreateInfo\n  {\n    PipelineTessellationStateCreateInfo( PipelineTessellationStateCreateFlags flags_ = PipelineTessellationStateCreateFlags(), uint32_t patchControlPoints_ = 0 )\n      : sType( StructureType::ePipelineTessellationStateCreateInfo )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , patchControlPoints( patchControlPoints_ )\n    {\n    }\n\n    PipelineTessellationStateCreateInfo( VkPipelineTessellationStateCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PipelineTessellationStateCreateInfo) );\n    }\n\n    PipelineTessellationStateCreateInfo& operator=( VkPipelineTessellationStateCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PipelineTessellationStateCreateInfo) );\n      return *this;\n    }\n\n    PipelineTessellationStateCreateInfo& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    PipelineTessellationStateCreateInfo& setFlags( PipelineTessellationStateCreateFlags flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    PipelineTessellationStateCreateInfo& setPatchControlPoints( uint32_t patchControlPoints_ )\n    {\n      patchControlPoints = patchControlPoints_;\n      return *this;\n    }\n\n    operator const VkPipelineTessellationStateCreateInfo&() const\n    {\n      return *reinterpret_cast<const VkPipelineTessellationStateCreateInfo*>(this);\n    }\n\n    bool operator==( PipelineTessellationStateCreateInfo const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( patchControlPoints == rhs.patchControlPoints );\n    }\n\n    bool operator!=( PipelineTessellationStateCreateInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    PipelineTessellationStateCreateFlags flags;\n    uint32_t patchControlPoints;\n  };\n  static_assert( sizeof( PipelineTessellationStateCreateInfo ) == sizeof( VkPipelineTessellationStateCreateInfo ), \"struct and wrapper have different size!\" );\n\n  struct PipelineViewportStateCreateInfo\n  {\n    PipelineViewportStateCreateInfo( PipelineViewportStateCreateFlags flags_ = PipelineViewportStateCreateFlags(), uint32_t viewportCount_ = 0, const Viewport* pViewports_ = nullptr, uint32_t scissorCount_ = 0, const Rect2D* pScissors_ = nullptr )\n      : sType( StructureType::ePipelineViewportStateCreateInfo )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , viewportCount( viewportCount_ )\n      , pViewports( pViewports_ )\n      , scissorCount( scissorCount_ )\n      , pScissors( pScissors_ )\n    {\n    }\n\n    PipelineViewportStateCreateInfo( VkPipelineViewportStateCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PipelineViewportStateCreateInfo) );\n    }\n\n    PipelineViewportStateCreateInfo& operator=( VkPipelineViewportStateCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PipelineViewportStateCreateInfo) );\n      return *this;\n    }\n\n    PipelineViewportStateCreateInfo& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    PipelineViewportStateCreateInfo& setFlags( PipelineViewportStateCreateFlags flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    PipelineViewportStateCreateInfo& setViewportCount( uint32_t viewportCount_ )\n    {\n      viewportCount = viewportCount_;\n      return *this;\n    }\n\n    PipelineViewportStateCreateInfo& setPViewports( const Viewport* pViewports_ )\n    {\n      pViewports = pViewports_;\n      return *this;\n    }\n\n    PipelineViewportStateCreateInfo& setScissorCount( uint32_t scissorCount_ )\n    {\n      scissorCount = scissorCount_;\n      return *this;\n    }\n\n    PipelineViewportStateCreateInfo& setPScissors( const Rect2D* pScissors_ )\n    {\n      pScissors = pScissors_;\n      return *this;\n    }\n\n    operator const VkPipelineViewportStateCreateInfo&() const\n    {\n      return *reinterpret_cast<const VkPipelineViewportStateCreateInfo*>(this);\n    }\n\n    bool operator==( PipelineViewportStateCreateInfo const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( viewportCount == rhs.viewportCount )\n          && ( pViewports == rhs.pViewports )\n          && ( scissorCount == rhs.scissorCount )\n          && ( pScissors == rhs.pScissors );\n    }\n\n    bool operator!=( PipelineViewportStateCreateInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    PipelineViewportStateCreateFlags flags;\n    uint32_t viewportCount;\n    const Viewport* pViewports;\n    uint32_t scissorCount;\n    const Rect2D* pScissors;\n  };\n  static_assert( sizeof( PipelineViewportStateCreateInfo ) == sizeof( VkPipelineViewportStateCreateInfo ), \"struct and wrapper have different size!\" );\n\n  struct PipelineRasterizationStateCreateInfo\n  {\n    PipelineRasterizationStateCreateInfo( PipelineRasterizationStateCreateFlags flags_ = PipelineRasterizationStateCreateFlags(), Bool32 depthClampEnable_ = 0, Bool32 rasterizerDiscardEnable_ = 0, PolygonMode polygonMode_ = PolygonMode::eFill, CullModeFlags cullMode_ = CullModeFlags(), FrontFace frontFace_ = FrontFace::eCounterClockwise, Bool32 depthBiasEnable_ = 0, float depthBiasConstantFactor_ = 0, float depthBiasClamp_ = 0, float depthBiasSlopeFactor_ = 0, float lineWidth_ = 0 )\n      : sType( StructureType::ePipelineRasterizationStateCreateInfo )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , depthClampEnable( depthClampEnable_ )\n      , rasterizerDiscardEnable( rasterizerDiscardEnable_ )\n      , polygonMode( polygonMode_ )\n      , cullMode( cullMode_ )\n      , frontFace( frontFace_ )\n      , depthBiasEnable( depthBiasEnable_ )\n      , depthBiasConstantFactor( depthBiasConstantFactor_ )\n      , depthBiasClamp( depthBiasClamp_ )\n      , depthBiasSlopeFactor( depthBiasSlopeFactor_ )\n      , lineWidth( lineWidth_ )\n    {\n    }\n\n    PipelineRasterizationStateCreateInfo( VkPipelineRasterizationStateCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PipelineRasterizationStateCreateInfo) );\n    }\n\n    PipelineRasterizationStateCreateInfo& operator=( VkPipelineRasterizationStateCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PipelineRasterizationStateCreateInfo) );\n      return *this;\n    }\n\n    PipelineRasterizationStateCreateInfo& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    PipelineRasterizationStateCreateInfo& setFlags( PipelineRasterizationStateCreateFlags flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    PipelineRasterizationStateCreateInfo& setDepthClampEnable( Bool32 depthClampEnable_ )\n    {\n      depthClampEnable = depthClampEnable_;\n      return *this;\n    }\n\n    PipelineRasterizationStateCreateInfo& setRasterizerDiscardEnable( Bool32 rasterizerDiscardEnable_ )\n    {\n      rasterizerDiscardEnable = rasterizerDiscardEnable_;\n      return *this;\n    }\n\n    PipelineRasterizationStateCreateInfo& setPolygonMode( PolygonMode polygonMode_ )\n    {\n      polygonMode = polygonMode_;\n      return *this;\n    }\n\n    PipelineRasterizationStateCreateInfo& setCullMode( CullModeFlags cullMode_ )\n    {\n      cullMode = cullMode_;\n      return *this;\n    }\n\n    PipelineRasterizationStateCreateInfo& setFrontFace( FrontFace frontFace_ )\n    {\n      frontFace = frontFace_;\n      return *this;\n    }\n\n    PipelineRasterizationStateCreateInfo& setDepthBiasEnable( Bool32 depthBiasEnable_ )\n    {\n      depthBiasEnable = depthBiasEnable_;\n      return *this;\n    }\n\n    PipelineRasterizationStateCreateInfo& setDepthBiasConstantFactor( float depthBiasConstantFactor_ )\n    {\n      depthBiasConstantFactor = depthBiasConstantFactor_;\n      return *this;\n    }\n\n    PipelineRasterizationStateCreateInfo& setDepthBiasClamp( float depthBiasClamp_ )\n    {\n      depthBiasClamp = depthBiasClamp_;\n      return *this;\n    }\n\n    PipelineRasterizationStateCreateInfo& setDepthBiasSlopeFactor( float depthBiasSlopeFactor_ )\n    {\n      depthBiasSlopeFactor = depthBiasSlopeFactor_;\n      return *this;\n    }\n\n    PipelineRasterizationStateCreateInfo& setLineWidth( float lineWidth_ )\n    {\n      lineWidth = lineWidth_;\n      return *this;\n    }\n\n    operator const VkPipelineRasterizationStateCreateInfo&() const\n    {\n      return *reinterpret_cast<const VkPipelineRasterizationStateCreateInfo*>(this);\n    }\n\n    bool operator==( PipelineRasterizationStateCreateInfo const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( depthClampEnable == rhs.depthClampEnable )\n          && ( rasterizerDiscardEnable == rhs.rasterizerDiscardEnable )\n          && ( polygonMode == rhs.polygonMode )\n          && ( cullMode == rhs.cullMode )\n          && ( frontFace == rhs.frontFace )\n          && ( depthBiasEnable == rhs.depthBiasEnable )\n          && ( depthBiasConstantFactor == rhs.depthBiasConstantFactor )\n          && ( depthBiasClamp == rhs.depthBiasClamp )\n          && ( depthBiasSlopeFactor == rhs.depthBiasSlopeFactor )\n          && ( lineWidth == rhs.lineWidth );\n    }\n\n    bool operator!=( PipelineRasterizationStateCreateInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    PipelineRasterizationStateCreateFlags flags;\n    Bool32 depthClampEnable;\n    Bool32 rasterizerDiscardEnable;\n    PolygonMode polygonMode;\n    CullModeFlags cullMode;\n    FrontFace frontFace;\n    Bool32 depthBiasEnable;\n    float depthBiasConstantFactor;\n    float depthBiasClamp;\n    float depthBiasSlopeFactor;\n    float lineWidth;\n  };\n  static_assert( sizeof( PipelineRasterizationStateCreateInfo ) == sizeof( VkPipelineRasterizationStateCreateInfo ), \"struct and wrapper have different size!\" );\n\n  struct PipelineDepthStencilStateCreateInfo\n  {\n    PipelineDepthStencilStateCreateInfo( PipelineDepthStencilStateCreateFlags flags_ = PipelineDepthStencilStateCreateFlags(), Bool32 depthTestEnable_ = 0, Bool32 depthWriteEnable_ = 0, CompareOp depthCompareOp_ = CompareOp::eNever, Bool32 depthBoundsTestEnable_ = 0, Bool32 stencilTestEnable_ = 0, StencilOpState front_ = StencilOpState(), StencilOpState back_ = StencilOpState(), float minDepthBounds_ = 0, float maxDepthBounds_ = 0 )\n      : sType( StructureType::ePipelineDepthStencilStateCreateInfo )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , depthTestEnable( depthTestEnable_ )\n      , depthWriteEnable( depthWriteEnable_ )\n      , depthCompareOp( depthCompareOp_ )\n      , depthBoundsTestEnable( depthBoundsTestEnable_ )\n      , stencilTestEnable( stencilTestEnable_ )\n      , front( front_ )\n      , back( back_ )\n      , minDepthBounds( minDepthBounds_ )\n      , maxDepthBounds( maxDepthBounds_ )\n    {\n    }\n\n    PipelineDepthStencilStateCreateInfo( VkPipelineDepthStencilStateCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PipelineDepthStencilStateCreateInfo) );\n    }\n\n    PipelineDepthStencilStateCreateInfo& operator=( VkPipelineDepthStencilStateCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PipelineDepthStencilStateCreateInfo) );\n      return *this;\n    }\n\n    PipelineDepthStencilStateCreateInfo& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    PipelineDepthStencilStateCreateInfo& setFlags( PipelineDepthStencilStateCreateFlags flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    PipelineDepthStencilStateCreateInfo& setDepthTestEnable( Bool32 depthTestEnable_ )\n    {\n      depthTestEnable = depthTestEnable_;\n      return *this;\n    }\n\n    PipelineDepthStencilStateCreateInfo& setDepthWriteEnable( Bool32 depthWriteEnable_ )\n    {\n      depthWriteEnable = depthWriteEnable_;\n      return *this;\n    }\n\n    PipelineDepthStencilStateCreateInfo& setDepthCompareOp( CompareOp depthCompareOp_ )\n    {\n      depthCompareOp = depthCompareOp_;\n      return *this;\n    }\n\n    PipelineDepthStencilStateCreateInfo& setDepthBoundsTestEnable( Bool32 depthBoundsTestEnable_ )\n    {\n      depthBoundsTestEnable = depthBoundsTestEnable_;\n      return *this;\n    }\n\n    PipelineDepthStencilStateCreateInfo& setStencilTestEnable( Bool32 stencilTestEnable_ )\n    {\n      stencilTestEnable = stencilTestEnable_;\n      return *this;\n    }\n\n    PipelineDepthStencilStateCreateInfo& setFront( StencilOpState front_ )\n    {\n      front = front_;\n      return *this;\n    }\n\n    PipelineDepthStencilStateCreateInfo& setBack( StencilOpState back_ )\n    {\n      back = back_;\n      return *this;\n    }\n\n    PipelineDepthStencilStateCreateInfo& setMinDepthBounds( float minDepthBounds_ )\n    {\n      minDepthBounds = minDepthBounds_;\n      return *this;\n    }\n\n    PipelineDepthStencilStateCreateInfo& setMaxDepthBounds( float maxDepthBounds_ )\n    {\n      maxDepthBounds = maxDepthBounds_;\n      return *this;\n    }\n\n    operator const VkPipelineDepthStencilStateCreateInfo&() const\n    {\n      return *reinterpret_cast<const VkPipelineDepthStencilStateCreateInfo*>(this);\n    }\n\n    bool operator==( PipelineDepthStencilStateCreateInfo const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( depthTestEnable == rhs.depthTestEnable )\n          && ( depthWriteEnable == rhs.depthWriteEnable )\n          && ( depthCompareOp == rhs.depthCompareOp )\n          && ( depthBoundsTestEnable == rhs.depthBoundsTestEnable )\n          && ( stencilTestEnable == rhs.stencilTestEnable )\n          && ( front == rhs.front )\n          && ( back == rhs.back )\n          && ( minDepthBounds == rhs.minDepthBounds )\n          && ( maxDepthBounds == rhs.maxDepthBounds );\n    }\n\n    bool operator!=( PipelineDepthStencilStateCreateInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    PipelineDepthStencilStateCreateFlags flags;\n    Bool32 depthTestEnable;\n    Bool32 depthWriteEnable;\n    CompareOp depthCompareOp;\n    Bool32 depthBoundsTestEnable;\n    Bool32 stencilTestEnable;\n    StencilOpState front;\n    StencilOpState back;\n    float minDepthBounds;\n    float maxDepthBounds;\n  };\n  static_assert( sizeof( PipelineDepthStencilStateCreateInfo ) == sizeof( VkPipelineDepthStencilStateCreateInfo ), \"struct and wrapper have different size!\" );\n\n  struct PipelineCacheCreateInfo\n  {\n    PipelineCacheCreateInfo( PipelineCacheCreateFlags flags_ = PipelineCacheCreateFlags(), size_t initialDataSize_ = 0, const void* pInitialData_ = nullptr )\n      : sType( StructureType::ePipelineCacheCreateInfo )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , initialDataSize( initialDataSize_ )\n      , pInitialData( pInitialData_ )\n    {\n    }\n\n    PipelineCacheCreateInfo( VkPipelineCacheCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PipelineCacheCreateInfo) );\n    }\n\n    PipelineCacheCreateInfo& operator=( VkPipelineCacheCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PipelineCacheCreateInfo) );\n      return *this;\n    }\n\n    PipelineCacheCreateInfo& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    PipelineCacheCreateInfo& setFlags( PipelineCacheCreateFlags flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    PipelineCacheCreateInfo& setInitialDataSize( size_t initialDataSize_ )\n    {\n      initialDataSize = initialDataSize_;\n      return *this;\n    }\n\n    PipelineCacheCreateInfo& setPInitialData( const void* pInitialData_ )\n    {\n      pInitialData = pInitialData_;\n      return *this;\n    }\n\n    operator const VkPipelineCacheCreateInfo&() const\n    {\n      return *reinterpret_cast<const VkPipelineCacheCreateInfo*>(this);\n    }\n\n    bool operator==( PipelineCacheCreateInfo const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( initialDataSize == rhs.initialDataSize )\n          && ( pInitialData == rhs.pInitialData );\n    }\n\n    bool operator!=( PipelineCacheCreateInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    PipelineCacheCreateFlags flags;\n    size_t initialDataSize;\n    const void* pInitialData;\n  };\n  static_assert( sizeof( PipelineCacheCreateInfo ) == sizeof( VkPipelineCacheCreateInfo ), \"struct and wrapper have different size!\" );\n\n  struct SamplerCreateInfo\n  {\n    SamplerCreateInfo( SamplerCreateFlags flags_ = SamplerCreateFlags(), Filter magFilter_ = Filter::eNearest, Filter minFilter_ = Filter::eNearest, SamplerMipmapMode mipmapMode_ = SamplerMipmapMode::eNearest, SamplerAddressMode addressModeU_ = SamplerAddressMode::eRepeat, SamplerAddressMode addressModeV_ = SamplerAddressMode::eRepeat, SamplerAddressMode addressModeW_ = SamplerAddressMode::eRepeat, float mipLodBias_ = 0, Bool32 anisotropyEnable_ = 0, float maxAnisotropy_ = 0, Bool32 compareEnable_ = 0, CompareOp compareOp_ = CompareOp::eNever, float minLod_ = 0, float maxLod_ = 0, BorderColor borderColor_ = BorderColor::eFloatTransparentBlack, Bool32 unnormalizedCoordinates_ = 0 )\n      : sType( StructureType::eSamplerCreateInfo )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , magFilter( magFilter_ )\n      , minFilter( minFilter_ )\n      , mipmapMode( mipmapMode_ )\n      , addressModeU( addressModeU_ )\n      , addressModeV( addressModeV_ )\n      , addressModeW( addressModeW_ )\n      , mipLodBias( mipLodBias_ )\n      , anisotropyEnable( anisotropyEnable_ )\n      , maxAnisotropy( maxAnisotropy_ )\n      , compareEnable( compareEnable_ )\n      , compareOp( compareOp_ )\n      , minLod( minLod_ )\n      , maxLod( maxLod_ )\n      , borderColor( borderColor_ )\n      , unnormalizedCoordinates( unnormalizedCoordinates_ )\n    {\n    }\n\n    SamplerCreateInfo( VkSamplerCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(SamplerCreateInfo) );\n    }\n\n    SamplerCreateInfo& operator=( VkSamplerCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(SamplerCreateInfo) );\n      return *this;\n    }\n\n    SamplerCreateInfo& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    SamplerCreateInfo& setFlags( SamplerCreateFlags flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    SamplerCreateInfo& setMagFilter( Filter magFilter_ )\n    {\n      magFilter = magFilter_;\n      return *this;\n    }\n\n    SamplerCreateInfo& setMinFilter( Filter minFilter_ )\n    {\n      minFilter = minFilter_;\n      return *this;\n    }\n\n    SamplerCreateInfo& setMipmapMode( SamplerMipmapMode mipmapMode_ )\n    {\n      mipmapMode = mipmapMode_;\n      return *this;\n    }\n\n    SamplerCreateInfo& setAddressModeU( SamplerAddressMode addressModeU_ )\n    {\n      addressModeU = addressModeU_;\n      return *this;\n    }\n\n    SamplerCreateInfo& setAddressModeV( SamplerAddressMode addressModeV_ )\n    {\n      addressModeV = addressModeV_;\n      return *this;\n    }\n\n    SamplerCreateInfo& setAddressModeW( SamplerAddressMode addressModeW_ )\n    {\n      addressModeW = addressModeW_;\n      return *this;\n    }\n\n    SamplerCreateInfo& setMipLodBias( float mipLodBias_ )\n    {\n      mipLodBias = mipLodBias_;\n      return *this;\n    }\n\n    SamplerCreateInfo& setAnisotropyEnable( Bool32 anisotropyEnable_ )\n    {\n      anisotropyEnable = anisotropyEnable_;\n      return *this;\n    }\n\n    SamplerCreateInfo& setMaxAnisotropy( float maxAnisotropy_ )\n    {\n      maxAnisotropy = maxAnisotropy_;\n      return *this;\n    }\n\n    SamplerCreateInfo& setCompareEnable( Bool32 compareEnable_ )\n    {\n      compareEnable = compareEnable_;\n      return *this;\n    }\n\n    SamplerCreateInfo& setCompareOp( CompareOp compareOp_ )\n    {\n      compareOp = compareOp_;\n      return *this;\n    }\n\n    SamplerCreateInfo& setMinLod( float minLod_ )\n    {\n      minLod = minLod_;\n      return *this;\n    }\n\n    SamplerCreateInfo& setMaxLod( float maxLod_ )\n    {\n      maxLod = maxLod_;\n      return *this;\n    }\n\n    SamplerCreateInfo& setBorderColor( BorderColor borderColor_ )\n    {\n      borderColor = borderColor_;\n      return *this;\n    }\n\n    SamplerCreateInfo& setUnnormalizedCoordinates( Bool32 unnormalizedCoordinates_ )\n    {\n      unnormalizedCoordinates = unnormalizedCoordinates_;\n      return *this;\n    }\n\n    operator const VkSamplerCreateInfo&() const\n    {\n      return *reinterpret_cast<const VkSamplerCreateInfo*>(this);\n    }\n\n    bool operator==( SamplerCreateInfo const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( magFilter == rhs.magFilter )\n          && ( minFilter == rhs.minFilter )\n          && ( mipmapMode == rhs.mipmapMode )\n          && ( addressModeU == rhs.addressModeU )\n          && ( addressModeV == rhs.addressModeV )\n          && ( addressModeW == rhs.addressModeW )\n          && ( mipLodBias == rhs.mipLodBias )\n          && ( anisotropyEnable == rhs.anisotropyEnable )\n          && ( maxAnisotropy == rhs.maxAnisotropy )\n          && ( compareEnable == rhs.compareEnable )\n          && ( compareOp == rhs.compareOp )\n          && ( minLod == rhs.minLod )\n          && ( maxLod == rhs.maxLod )\n          && ( borderColor == rhs.borderColor )\n          && ( unnormalizedCoordinates == rhs.unnormalizedCoordinates );\n    }\n\n    bool operator!=( SamplerCreateInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    SamplerCreateFlags flags;\n    Filter magFilter;\n    Filter minFilter;\n    SamplerMipmapMode mipmapMode;\n    SamplerAddressMode addressModeU;\n    SamplerAddressMode addressModeV;\n    SamplerAddressMode addressModeW;\n    float mipLodBias;\n    Bool32 anisotropyEnable;\n    float maxAnisotropy;\n    Bool32 compareEnable;\n    CompareOp compareOp;\n    float minLod;\n    float maxLod;\n    BorderColor borderColor;\n    Bool32 unnormalizedCoordinates;\n  };\n  static_assert( sizeof( SamplerCreateInfo ) == sizeof( VkSamplerCreateInfo ), \"struct and wrapper have different size!\" );\n\n  struct CommandBufferAllocateInfo\n  {\n    CommandBufferAllocateInfo( CommandPool commandPool_ = CommandPool(), CommandBufferLevel level_ = CommandBufferLevel::ePrimary, uint32_t commandBufferCount_ = 0 )\n      : sType( StructureType::eCommandBufferAllocateInfo )\n      , pNext( nullptr )\n      , commandPool( commandPool_ )\n      , level( level_ )\n      , commandBufferCount( commandBufferCount_ )\n    {\n    }\n\n    CommandBufferAllocateInfo( VkCommandBufferAllocateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(CommandBufferAllocateInfo) );\n    }\n\n    CommandBufferAllocateInfo& operator=( VkCommandBufferAllocateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(CommandBufferAllocateInfo) );\n      return *this;\n    }\n\n    CommandBufferAllocateInfo& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    CommandBufferAllocateInfo& setCommandPool( CommandPool commandPool_ )\n    {\n      commandPool = commandPool_;\n      return *this;\n    }\n\n    CommandBufferAllocateInfo& setLevel( CommandBufferLevel level_ )\n    {\n      level = level_;\n      return *this;\n    }\n\n    CommandBufferAllocateInfo& setCommandBufferCount( uint32_t commandBufferCount_ )\n    {\n      commandBufferCount = commandBufferCount_;\n      return *this;\n    }\n\n    operator const VkCommandBufferAllocateInfo&() const\n    {\n      return *reinterpret_cast<const VkCommandBufferAllocateInfo*>(this);\n    }\n\n    bool operator==( CommandBufferAllocateInfo const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( commandPool == rhs.commandPool )\n          && ( level == rhs.level )\n          && ( commandBufferCount == rhs.commandBufferCount );\n    }\n\n    bool operator!=( CommandBufferAllocateInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    CommandPool commandPool;\n    CommandBufferLevel level;\n    uint32_t commandBufferCount;\n  };\n  static_assert( sizeof( CommandBufferAllocateInfo ) == sizeof( VkCommandBufferAllocateInfo ), \"struct and wrapper have different size!\" );\n\n  struct RenderPassBeginInfo\n  {\n    RenderPassBeginInfo( RenderPass renderPass_ = RenderPass(), Framebuffer framebuffer_ = Framebuffer(), Rect2D renderArea_ = Rect2D(), uint32_t clearValueCount_ = 0, const ClearValue* pClearValues_ = nullptr )\n      : sType( StructureType::eRenderPassBeginInfo )\n      , pNext( nullptr )\n      , renderPass( renderPass_ )\n      , framebuffer( framebuffer_ )\n      , renderArea( renderArea_ )\n      , clearValueCount( clearValueCount_ )\n      , pClearValues( pClearValues_ )\n    {\n    }\n\n    RenderPassBeginInfo( VkRenderPassBeginInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(RenderPassBeginInfo) );\n    }\n\n    RenderPassBeginInfo& operator=( VkRenderPassBeginInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(RenderPassBeginInfo) );\n      return *this;\n    }\n\n    RenderPassBeginInfo& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    RenderPassBeginInfo& setRenderPass( RenderPass renderPass_ )\n    {\n      renderPass = renderPass_;\n      return *this;\n    }\n\n    RenderPassBeginInfo& setFramebuffer( Framebuffer framebuffer_ )\n    {\n      framebuffer = framebuffer_;\n      return *this;\n    }\n\n    RenderPassBeginInfo& setRenderArea( Rect2D renderArea_ )\n    {\n      renderArea = renderArea_;\n      return *this;\n    }\n\n    RenderPassBeginInfo& setClearValueCount( uint32_t clearValueCount_ )\n    {\n      clearValueCount = clearValueCount_;\n      return *this;\n    }\n\n    RenderPassBeginInfo& setPClearValues( const ClearValue* pClearValues_ )\n    {\n      pClearValues = pClearValues_;\n      return *this;\n    }\n\n    operator const VkRenderPassBeginInfo&() const\n    {\n      return *reinterpret_cast<const VkRenderPassBeginInfo*>(this);\n    }\n\n    bool operator==( RenderPassBeginInfo const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( renderPass == rhs.renderPass )\n          && ( framebuffer == rhs.framebuffer )\n          && ( renderArea == rhs.renderArea )\n          && ( clearValueCount == rhs.clearValueCount )\n          && ( pClearValues == rhs.pClearValues );\n    }\n\n    bool operator!=( RenderPassBeginInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    RenderPass renderPass;\n    Framebuffer framebuffer;\n    Rect2D renderArea;\n    uint32_t clearValueCount;\n    const ClearValue* pClearValues;\n  };\n  static_assert( sizeof( RenderPassBeginInfo ) == sizeof( VkRenderPassBeginInfo ), \"struct and wrapper have different size!\" );\n\n  struct EventCreateInfo\n  {\n    EventCreateInfo( EventCreateFlags flags_ = EventCreateFlags() )\n      : sType( StructureType::eEventCreateInfo )\n      , pNext( nullptr )\n      , flags( flags_ )\n    {\n    }\n\n    EventCreateInfo( VkEventCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(EventCreateInfo) );\n    }\n\n    EventCreateInfo& operator=( VkEventCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(EventCreateInfo) );\n      return *this;\n    }\n\n    EventCreateInfo& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    EventCreateInfo& setFlags( EventCreateFlags flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    operator const VkEventCreateInfo&() const\n    {\n      return *reinterpret_cast<const VkEventCreateInfo*>(this);\n    }\n\n    bool operator==( EventCreateInfo const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags );\n    }\n\n    bool operator!=( EventCreateInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    EventCreateFlags flags;\n  };\n  static_assert( sizeof( EventCreateInfo ) == sizeof( VkEventCreateInfo ), \"struct and wrapper have different size!\" );\n\n  struct SemaphoreCreateInfo\n  {\n    SemaphoreCreateInfo( SemaphoreCreateFlags flags_ = SemaphoreCreateFlags() )\n      : sType( StructureType::eSemaphoreCreateInfo )\n      , pNext( nullptr )\n      , flags( flags_ )\n    {\n    }\n\n    SemaphoreCreateInfo( VkSemaphoreCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(SemaphoreCreateInfo) );\n    }\n\n    SemaphoreCreateInfo& operator=( VkSemaphoreCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(SemaphoreCreateInfo) );\n      return *this;\n    }\n\n    SemaphoreCreateInfo& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    SemaphoreCreateInfo& setFlags( SemaphoreCreateFlags flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    operator const VkSemaphoreCreateInfo&() const\n    {\n      return *reinterpret_cast<const VkSemaphoreCreateInfo*>(this);\n    }\n\n    bool operator==( SemaphoreCreateInfo const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags );\n    }\n\n    bool operator!=( SemaphoreCreateInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    SemaphoreCreateFlags flags;\n  };\n  static_assert( sizeof( SemaphoreCreateInfo ) == sizeof( VkSemaphoreCreateInfo ), \"struct and wrapper have different size!\" );\n\n  struct FramebufferCreateInfo\n  {\n    FramebufferCreateInfo( FramebufferCreateFlags flags_ = FramebufferCreateFlags(), RenderPass renderPass_ = RenderPass(), uint32_t attachmentCount_ = 0, const ImageView* pAttachments_ = nullptr, uint32_t width_ = 0, uint32_t height_ = 0, uint32_t layers_ = 0 )\n      : sType( StructureType::eFramebufferCreateInfo )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , renderPass( renderPass_ )\n      , attachmentCount( attachmentCount_ )\n      , pAttachments( pAttachments_ )\n      , width( width_ )\n      , height( height_ )\n      , layers( layers_ )\n    {\n    }\n\n    FramebufferCreateInfo( VkFramebufferCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(FramebufferCreateInfo) );\n    }\n\n    FramebufferCreateInfo& operator=( VkFramebufferCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(FramebufferCreateInfo) );\n      return *this;\n    }\n\n    FramebufferCreateInfo& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    FramebufferCreateInfo& setFlags( FramebufferCreateFlags flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    FramebufferCreateInfo& setRenderPass( RenderPass renderPass_ )\n    {\n      renderPass = renderPass_;\n      return *this;\n    }\n\n    FramebufferCreateInfo& setAttachmentCount( uint32_t attachmentCount_ )\n    {\n      attachmentCount = attachmentCount_;\n      return *this;\n    }\n\n    FramebufferCreateInfo& setPAttachments( const ImageView* pAttachments_ )\n    {\n      pAttachments = pAttachments_;\n      return *this;\n    }\n\n    FramebufferCreateInfo& setWidth( uint32_t width_ )\n    {\n      width = width_;\n      return *this;\n    }\n\n    FramebufferCreateInfo& setHeight( uint32_t height_ )\n    {\n      height = height_;\n      return *this;\n    }\n\n    FramebufferCreateInfo& setLayers( uint32_t layers_ )\n    {\n      layers = layers_;\n      return *this;\n    }\n\n    operator const VkFramebufferCreateInfo&() const\n    {\n      return *reinterpret_cast<const VkFramebufferCreateInfo*>(this);\n    }\n\n    bool operator==( FramebufferCreateInfo const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( renderPass == rhs.renderPass )\n          && ( attachmentCount == rhs.attachmentCount )\n          && ( pAttachments == rhs.pAttachments )\n          && ( width == rhs.width )\n          && ( height == rhs.height )\n          && ( layers == rhs.layers );\n    }\n\n    bool operator!=( FramebufferCreateInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    FramebufferCreateFlags flags;\n    RenderPass renderPass;\n    uint32_t attachmentCount;\n    const ImageView* pAttachments;\n    uint32_t width;\n    uint32_t height;\n    uint32_t layers;\n  };\n  static_assert( sizeof( FramebufferCreateInfo ) == sizeof( VkFramebufferCreateInfo ), \"struct and wrapper have different size!\" );\n\n  struct DisplayModeCreateInfoKHR\n  {\n    DisplayModeCreateInfoKHR( DisplayModeCreateFlagsKHR flags_ = DisplayModeCreateFlagsKHR(), DisplayModeParametersKHR parameters_ = DisplayModeParametersKHR() )\n      : sType( StructureType::eDisplayModeCreateInfoKHR )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , parameters( parameters_ )\n    {\n    }\n\n    DisplayModeCreateInfoKHR( VkDisplayModeCreateInfoKHR const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DisplayModeCreateInfoKHR) );\n    }\n\n    DisplayModeCreateInfoKHR& operator=( VkDisplayModeCreateInfoKHR const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DisplayModeCreateInfoKHR) );\n      return *this;\n    }\n\n    DisplayModeCreateInfoKHR& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    DisplayModeCreateInfoKHR& setFlags( DisplayModeCreateFlagsKHR flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    DisplayModeCreateInfoKHR& setParameters( DisplayModeParametersKHR parameters_ )\n    {\n      parameters = parameters_;\n      return *this;\n    }\n\n    operator const VkDisplayModeCreateInfoKHR&() const\n    {\n      return *reinterpret_cast<const VkDisplayModeCreateInfoKHR*>(this);\n    }\n\n    bool operator==( DisplayModeCreateInfoKHR const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( parameters == rhs.parameters );\n    }\n\n    bool operator!=( DisplayModeCreateInfoKHR const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    DisplayModeCreateFlagsKHR flags;\n    DisplayModeParametersKHR parameters;\n  };\n  static_assert( sizeof( DisplayModeCreateInfoKHR ) == sizeof( VkDisplayModeCreateInfoKHR ), \"struct and wrapper have different size!\" );\n\n  struct DisplayPresentInfoKHR\n  {\n    DisplayPresentInfoKHR( Rect2D srcRect_ = Rect2D(), Rect2D dstRect_ = Rect2D(), Bool32 persistent_ = 0 )\n      : sType( StructureType::eDisplayPresentInfoKHR )\n      , pNext( nullptr )\n      , srcRect( srcRect_ )\n      , dstRect( dstRect_ )\n      , persistent( persistent_ )\n    {\n    }\n\n    DisplayPresentInfoKHR( VkDisplayPresentInfoKHR const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DisplayPresentInfoKHR) );\n    }\n\n    DisplayPresentInfoKHR& operator=( VkDisplayPresentInfoKHR const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DisplayPresentInfoKHR) );\n      return *this;\n    }\n\n    DisplayPresentInfoKHR& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    DisplayPresentInfoKHR& setSrcRect( Rect2D srcRect_ )\n    {\n      srcRect = srcRect_;\n      return *this;\n    }\n\n    DisplayPresentInfoKHR& setDstRect( Rect2D dstRect_ )\n    {\n      dstRect = dstRect_;\n      return *this;\n    }\n\n    DisplayPresentInfoKHR& setPersistent( Bool32 persistent_ )\n    {\n      persistent = persistent_;\n      return *this;\n    }\n\n    operator const VkDisplayPresentInfoKHR&() const\n    {\n      return *reinterpret_cast<const VkDisplayPresentInfoKHR*>(this);\n    }\n\n    bool operator==( DisplayPresentInfoKHR const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( srcRect == rhs.srcRect )\n          && ( dstRect == rhs.dstRect )\n          && ( persistent == rhs.persistent );\n    }\n\n    bool operator!=( DisplayPresentInfoKHR const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    Rect2D srcRect;\n    Rect2D dstRect;\n    Bool32 persistent;\n  };\n  static_assert( sizeof( DisplayPresentInfoKHR ) == sizeof( VkDisplayPresentInfoKHR ), \"struct and wrapper have different size!\" );\n\n#ifdef VK_USE_PLATFORM_ANDROID_KHR\n  struct AndroidSurfaceCreateInfoKHR\n  {\n    AndroidSurfaceCreateInfoKHR( AndroidSurfaceCreateFlagsKHR flags_ = AndroidSurfaceCreateFlagsKHR(), ANativeWindow* window_ = nullptr )\n      : sType( StructureType::eAndroidSurfaceCreateInfoKHR )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , window( window_ )\n    {\n    }\n\n    AndroidSurfaceCreateInfoKHR( VkAndroidSurfaceCreateInfoKHR const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(AndroidSurfaceCreateInfoKHR) );\n    }\n\n    AndroidSurfaceCreateInfoKHR& operator=( VkAndroidSurfaceCreateInfoKHR const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(AndroidSurfaceCreateInfoKHR) );\n      return *this;\n    }\n\n    AndroidSurfaceCreateInfoKHR& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    AndroidSurfaceCreateInfoKHR& setFlags( AndroidSurfaceCreateFlagsKHR flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    AndroidSurfaceCreateInfoKHR& setWindow( ANativeWindow* window_ )\n    {\n      window = window_;\n      return *this;\n    }\n\n    operator const VkAndroidSurfaceCreateInfoKHR&() const\n    {\n      return *reinterpret_cast<const VkAndroidSurfaceCreateInfoKHR*>(this);\n    }\n\n    bool operator==( AndroidSurfaceCreateInfoKHR const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( window == rhs.window );\n    }\n\n    bool operator!=( AndroidSurfaceCreateInfoKHR const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    AndroidSurfaceCreateFlagsKHR flags;\n    ANativeWindow* window;\n  };\n  static_assert( sizeof( AndroidSurfaceCreateInfoKHR ) == sizeof( VkAndroidSurfaceCreateInfoKHR ), \"struct and wrapper have different size!\" );\n#endif /*VK_USE_PLATFORM_ANDROID_KHR*/\n\n#ifdef VK_USE_PLATFORM_MIR_KHR\n  struct MirSurfaceCreateInfoKHR\n  {\n    MirSurfaceCreateInfoKHR( MirSurfaceCreateFlagsKHR flags_ = MirSurfaceCreateFlagsKHR(), MirConnection* connection_ = nullptr, MirSurface* mirSurface_ = nullptr )\n      : sType( StructureType::eMirSurfaceCreateInfoKHR )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , connection( connection_ )\n      , mirSurface( mirSurface_ )\n    {\n    }\n\n    MirSurfaceCreateInfoKHR( VkMirSurfaceCreateInfoKHR const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(MirSurfaceCreateInfoKHR) );\n    }\n\n    MirSurfaceCreateInfoKHR& operator=( VkMirSurfaceCreateInfoKHR const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(MirSurfaceCreateInfoKHR) );\n      return *this;\n    }\n\n    MirSurfaceCreateInfoKHR& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    MirSurfaceCreateInfoKHR& setFlags( MirSurfaceCreateFlagsKHR flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    MirSurfaceCreateInfoKHR& setConnection( MirConnection* connection_ )\n    {\n      connection = connection_;\n      return *this;\n    }\n\n    MirSurfaceCreateInfoKHR& setMirSurface( MirSurface* mirSurface_ )\n    {\n      mirSurface = mirSurface_;\n      return *this;\n    }\n\n    operator const VkMirSurfaceCreateInfoKHR&() const\n    {\n      return *reinterpret_cast<const VkMirSurfaceCreateInfoKHR*>(this);\n    }\n\n    bool operator==( MirSurfaceCreateInfoKHR const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( connection == rhs.connection )\n          && ( mirSurface == rhs.mirSurface );\n    }\n\n    bool operator!=( MirSurfaceCreateInfoKHR const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    MirSurfaceCreateFlagsKHR flags;\n    MirConnection* connection;\n    MirSurface* mirSurface;\n  };\n  static_assert( sizeof( MirSurfaceCreateInfoKHR ) == sizeof( VkMirSurfaceCreateInfoKHR ), \"struct and wrapper have different size!\" );\n#endif /*VK_USE_PLATFORM_MIR_KHR*/\n\n#ifdef VK_USE_PLATFORM_VI_NN\n  struct ViSurfaceCreateInfoNN\n  {\n    ViSurfaceCreateInfoNN( ViSurfaceCreateFlagsNN flags_ = ViSurfaceCreateFlagsNN(), void* window_ = nullptr )\n      : sType( StructureType::eViSurfaceCreateInfoNN )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , window( window_ )\n    {\n    }\n\n    ViSurfaceCreateInfoNN( VkViSurfaceCreateInfoNN const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ViSurfaceCreateInfoNN) );\n    }\n\n    ViSurfaceCreateInfoNN& operator=( VkViSurfaceCreateInfoNN const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ViSurfaceCreateInfoNN) );\n      return *this;\n    }\n\n    ViSurfaceCreateInfoNN& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    ViSurfaceCreateInfoNN& setFlags( ViSurfaceCreateFlagsNN flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    ViSurfaceCreateInfoNN& setWindow( void* window_ )\n    {\n      window = window_;\n      return *this;\n    }\n\n    operator const VkViSurfaceCreateInfoNN&() const\n    {\n      return *reinterpret_cast<const VkViSurfaceCreateInfoNN*>(this);\n    }\n\n    bool operator==( ViSurfaceCreateInfoNN const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( window == rhs.window );\n    }\n\n    bool operator!=( ViSurfaceCreateInfoNN const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    ViSurfaceCreateFlagsNN flags;\n    void* window;\n  };\n  static_assert( sizeof( ViSurfaceCreateInfoNN ) == sizeof( VkViSurfaceCreateInfoNN ), \"struct and wrapper have different size!\" );\n#endif /*VK_USE_PLATFORM_VI_NN*/\n\n#ifdef VK_USE_PLATFORM_WAYLAND_KHR\n  struct WaylandSurfaceCreateInfoKHR\n  {\n    WaylandSurfaceCreateInfoKHR( WaylandSurfaceCreateFlagsKHR flags_ = WaylandSurfaceCreateFlagsKHR(), struct wl_display* display_ = nullptr, struct wl_surface* surface_ = nullptr )\n      : sType( StructureType::eWaylandSurfaceCreateInfoKHR )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , display( display_ )\n      , surface( surface_ )\n    {\n    }\n\n    WaylandSurfaceCreateInfoKHR( VkWaylandSurfaceCreateInfoKHR const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(WaylandSurfaceCreateInfoKHR) );\n    }\n\n    WaylandSurfaceCreateInfoKHR& operator=( VkWaylandSurfaceCreateInfoKHR const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(WaylandSurfaceCreateInfoKHR) );\n      return *this;\n    }\n\n    WaylandSurfaceCreateInfoKHR& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    WaylandSurfaceCreateInfoKHR& setFlags( WaylandSurfaceCreateFlagsKHR flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    WaylandSurfaceCreateInfoKHR& setDisplay( struct wl_display* display_ )\n    {\n      display = display_;\n      return *this;\n    }\n\n    WaylandSurfaceCreateInfoKHR& setSurface( struct wl_surface* surface_ )\n    {\n      surface = surface_;\n      return *this;\n    }\n\n    operator const VkWaylandSurfaceCreateInfoKHR&() const\n    {\n      return *reinterpret_cast<const VkWaylandSurfaceCreateInfoKHR*>(this);\n    }\n\n    bool operator==( WaylandSurfaceCreateInfoKHR const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( display == rhs.display )\n          && ( surface == rhs.surface );\n    }\n\n    bool operator!=( WaylandSurfaceCreateInfoKHR const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    WaylandSurfaceCreateFlagsKHR flags;\n    struct wl_display* display;\n    struct wl_surface* surface;\n  };\n  static_assert( sizeof( WaylandSurfaceCreateInfoKHR ) == sizeof( VkWaylandSurfaceCreateInfoKHR ), \"struct and wrapper have different size!\" );\n#endif /*VK_USE_PLATFORM_WAYLAND_KHR*/\n\n#ifdef VK_USE_PLATFORM_WIN32_KHR\n  struct Win32SurfaceCreateInfoKHR\n  {\n    Win32SurfaceCreateInfoKHR( Win32SurfaceCreateFlagsKHR flags_ = Win32SurfaceCreateFlagsKHR(), HINSTANCE hinstance_ = 0, HWND hwnd_ = 0 )\n      : sType( StructureType::eWin32SurfaceCreateInfoKHR )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , hinstance( hinstance_ )\n      , hwnd( hwnd_ )\n    {\n    }\n\n    Win32SurfaceCreateInfoKHR( VkWin32SurfaceCreateInfoKHR const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(Win32SurfaceCreateInfoKHR) );\n    }\n\n    Win32SurfaceCreateInfoKHR& operator=( VkWin32SurfaceCreateInfoKHR const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(Win32SurfaceCreateInfoKHR) );\n      return *this;\n    }\n\n    Win32SurfaceCreateInfoKHR& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    Win32SurfaceCreateInfoKHR& setFlags( Win32SurfaceCreateFlagsKHR flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    Win32SurfaceCreateInfoKHR& setHinstance( HINSTANCE hinstance_ )\n    {\n      hinstance = hinstance_;\n      return *this;\n    }\n\n    Win32SurfaceCreateInfoKHR& setHwnd( HWND hwnd_ )\n    {\n      hwnd = hwnd_;\n      return *this;\n    }\n\n    operator const VkWin32SurfaceCreateInfoKHR&() const\n    {\n      return *reinterpret_cast<const VkWin32SurfaceCreateInfoKHR*>(this);\n    }\n\n    bool operator==( Win32SurfaceCreateInfoKHR const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( hinstance == rhs.hinstance )\n          && ( hwnd == rhs.hwnd );\n    }\n\n    bool operator!=( Win32SurfaceCreateInfoKHR const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    Win32SurfaceCreateFlagsKHR flags;\n    HINSTANCE hinstance;\n    HWND hwnd;\n  };\n  static_assert( sizeof( Win32SurfaceCreateInfoKHR ) == sizeof( VkWin32SurfaceCreateInfoKHR ), \"struct and wrapper have different size!\" );\n#endif /*VK_USE_PLATFORM_WIN32_KHR*/\n\n#ifdef VK_USE_PLATFORM_XLIB_KHR\n  struct XlibSurfaceCreateInfoKHR\n  {\n    XlibSurfaceCreateInfoKHR( XlibSurfaceCreateFlagsKHR flags_ = XlibSurfaceCreateFlagsKHR(), Display* dpy_ = nullptr, Window window_ = 0 )\n      : sType( StructureType::eXlibSurfaceCreateInfoKHR )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , dpy( dpy_ )\n      , window( window_ )\n    {\n    }\n\n    XlibSurfaceCreateInfoKHR( VkXlibSurfaceCreateInfoKHR const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(XlibSurfaceCreateInfoKHR) );\n    }\n\n    XlibSurfaceCreateInfoKHR& operator=( VkXlibSurfaceCreateInfoKHR const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(XlibSurfaceCreateInfoKHR) );\n      return *this;\n    }\n\n    XlibSurfaceCreateInfoKHR& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    XlibSurfaceCreateInfoKHR& setFlags( XlibSurfaceCreateFlagsKHR flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    XlibSurfaceCreateInfoKHR& setDpy( Display* dpy_ )\n    {\n      dpy = dpy_;\n      return *this;\n    }\n\n    XlibSurfaceCreateInfoKHR& setWindow( Window window_ )\n    {\n      window = window_;\n      return *this;\n    }\n\n    operator const VkXlibSurfaceCreateInfoKHR&() const\n    {\n      return *reinterpret_cast<const VkXlibSurfaceCreateInfoKHR*>(this);\n    }\n\n    bool operator==( XlibSurfaceCreateInfoKHR const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( dpy == rhs.dpy )\n          && ( window == rhs.window );\n    }\n\n    bool operator!=( XlibSurfaceCreateInfoKHR const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    XlibSurfaceCreateFlagsKHR flags;\n    Display* dpy;\n    Window window;\n  };\n  static_assert( sizeof( XlibSurfaceCreateInfoKHR ) == sizeof( VkXlibSurfaceCreateInfoKHR ), \"struct and wrapper have different size!\" );\n#endif /*VK_USE_PLATFORM_XLIB_KHR*/\n\n#ifdef VK_USE_PLATFORM_XCB_KHR\n  struct XcbSurfaceCreateInfoKHR\n  {\n    XcbSurfaceCreateInfoKHR( XcbSurfaceCreateFlagsKHR flags_ = XcbSurfaceCreateFlagsKHR(), xcb_connection_t* connection_ = nullptr, xcb_window_t window_ = 0 )\n      : sType( StructureType::eXcbSurfaceCreateInfoKHR )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , connection( connection_ )\n      , window( window_ )\n    {\n    }\n\n    XcbSurfaceCreateInfoKHR( VkXcbSurfaceCreateInfoKHR const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(XcbSurfaceCreateInfoKHR) );\n    }\n\n    XcbSurfaceCreateInfoKHR& operator=( VkXcbSurfaceCreateInfoKHR const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(XcbSurfaceCreateInfoKHR) );\n      return *this;\n    }\n\n    XcbSurfaceCreateInfoKHR& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    XcbSurfaceCreateInfoKHR& setFlags( XcbSurfaceCreateFlagsKHR flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    XcbSurfaceCreateInfoKHR& setConnection( xcb_connection_t* connection_ )\n    {\n      connection = connection_;\n      return *this;\n    }\n\n    XcbSurfaceCreateInfoKHR& setWindow( xcb_window_t window_ )\n    {\n      window = window_;\n      return *this;\n    }\n\n    operator const VkXcbSurfaceCreateInfoKHR&() const\n    {\n      return *reinterpret_cast<const VkXcbSurfaceCreateInfoKHR*>(this);\n    }\n\n    bool operator==( XcbSurfaceCreateInfoKHR const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( connection == rhs.connection )\n          && ( window == rhs.window );\n    }\n\n    bool operator!=( XcbSurfaceCreateInfoKHR const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    XcbSurfaceCreateFlagsKHR flags;\n    xcb_connection_t* connection;\n    xcb_window_t window;\n  };\n  static_assert( sizeof( XcbSurfaceCreateInfoKHR ) == sizeof( VkXcbSurfaceCreateInfoKHR ), \"struct and wrapper have different size!\" );\n#endif /*VK_USE_PLATFORM_XCB_KHR*/\n\n  struct DebugMarkerMarkerInfoEXT\n  {\n    DebugMarkerMarkerInfoEXT( const char* pMarkerName_ = nullptr, std::array<float,4> const& color_ = { { 0, 0, 0, 0 } } )\n      : sType( StructureType::eDebugMarkerMarkerInfoEXT )\n      , pNext( nullptr )\n      , pMarkerName( pMarkerName_ )\n    {\n      memcpy( &color, color_.data(), 4 * sizeof( float ) );\n    }\n\n    DebugMarkerMarkerInfoEXT( VkDebugMarkerMarkerInfoEXT const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DebugMarkerMarkerInfoEXT) );\n    }\n\n    DebugMarkerMarkerInfoEXT& operator=( VkDebugMarkerMarkerInfoEXT const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DebugMarkerMarkerInfoEXT) );\n      return *this;\n    }\n\n    DebugMarkerMarkerInfoEXT& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    DebugMarkerMarkerInfoEXT& setPMarkerName( const char* pMarkerName_ )\n    {\n      pMarkerName = pMarkerName_;\n      return *this;\n    }\n\n    DebugMarkerMarkerInfoEXT& setColor( std::array<float,4> color_ )\n    {\n      memcpy( &color, color_.data(), 4 * sizeof( float ) );\n      return *this;\n    }\n\n    operator const VkDebugMarkerMarkerInfoEXT&() const\n    {\n      return *reinterpret_cast<const VkDebugMarkerMarkerInfoEXT*>(this);\n    }\n\n    bool operator==( DebugMarkerMarkerInfoEXT const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( pMarkerName == rhs.pMarkerName )\n          && ( memcmp( color, rhs.color, 4 * sizeof( float ) ) == 0 );\n    }\n\n    bool operator!=( DebugMarkerMarkerInfoEXT const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    const char* pMarkerName;\n    float color[4];\n  };\n  static_assert( sizeof( DebugMarkerMarkerInfoEXT ) == sizeof( VkDebugMarkerMarkerInfoEXT ), \"struct and wrapper have different size!\" );\n\n  struct DedicatedAllocationImageCreateInfoNV\n  {\n    DedicatedAllocationImageCreateInfoNV( Bool32 dedicatedAllocation_ = 0 )\n      : sType( StructureType::eDedicatedAllocationImageCreateInfoNV )\n      , pNext( nullptr )\n      , dedicatedAllocation( dedicatedAllocation_ )\n    {\n    }\n\n    DedicatedAllocationImageCreateInfoNV( VkDedicatedAllocationImageCreateInfoNV const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DedicatedAllocationImageCreateInfoNV) );\n    }\n\n    DedicatedAllocationImageCreateInfoNV& operator=( VkDedicatedAllocationImageCreateInfoNV const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DedicatedAllocationImageCreateInfoNV) );\n      return *this;\n    }\n\n    DedicatedAllocationImageCreateInfoNV& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    DedicatedAllocationImageCreateInfoNV& setDedicatedAllocation( Bool32 dedicatedAllocation_ )\n    {\n      dedicatedAllocation = dedicatedAllocation_;\n      return *this;\n    }\n\n    operator const VkDedicatedAllocationImageCreateInfoNV&() const\n    {\n      return *reinterpret_cast<const VkDedicatedAllocationImageCreateInfoNV*>(this);\n    }\n\n    bool operator==( DedicatedAllocationImageCreateInfoNV const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( dedicatedAllocation == rhs.dedicatedAllocation );\n    }\n\n    bool operator!=( DedicatedAllocationImageCreateInfoNV const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    Bool32 dedicatedAllocation;\n  };\n  static_assert( sizeof( DedicatedAllocationImageCreateInfoNV ) == sizeof( VkDedicatedAllocationImageCreateInfoNV ), \"struct and wrapper have different size!\" );\n\n  struct DedicatedAllocationBufferCreateInfoNV\n  {\n    DedicatedAllocationBufferCreateInfoNV( Bool32 dedicatedAllocation_ = 0 )\n      : sType( StructureType::eDedicatedAllocationBufferCreateInfoNV )\n      , pNext( nullptr )\n      , dedicatedAllocation( dedicatedAllocation_ )\n    {\n    }\n\n    DedicatedAllocationBufferCreateInfoNV( VkDedicatedAllocationBufferCreateInfoNV const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DedicatedAllocationBufferCreateInfoNV) );\n    }\n\n    DedicatedAllocationBufferCreateInfoNV& operator=( VkDedicatedAllocationBufferCreateInfoNV const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DedicatedAllocationBufferCreateInfoNV) );\n      return *this;\n    }\n\n    DedicatedAllocationBufferCreateInfoNV& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    DedicatedAllocationBufferCreateInfoNV& setDedicatedAllocation( Bool32 dedicatedAllocation_ )\n    {\n      dedicatedAllocation = dedicatedAllocation_;\n      return *this;\n    }\n\n    operator const VkDedicatedAllocationBufferCreateInfoNV&() const\n    {\n      return *reinterpret_cast<const VkDedicatedAllocationBufferCreateInfoNV*>(this);\n    }\n\n    bool operator==( DedicatedAllocationBufferCreateInfoNV const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( dedicatedAllocation == rhs.dedicatedAllocation );\n    }\n\n    bool operator!=( DedicatedAllocationBufferCreateInfoNV const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    Bool32 dedicatedAllocation;\n  };\n  static_assert( sizeof( DedicatedAllocationBufferCreateInfoNV ) == sizeof( VkDedicatedAllocationBufferCreateInfoNV ), \"struct and wrapper have different size!\" );\n\n  struct DedicatedAllocationMemoryAllocateInfoNV\n  {\n    DedicatedAllocationMemoryAllocateInfoNV( Image image_ = Image(), Buffer buffer_ = Buffer() )\n      : sType( StructureType::eDedicatedAllocationMemoryAllocateInfoNV )\n      , pNext( nullptr )\n      , image( image_ )\n      , buffer( buffer_ )\n    {\n    }\n\n    DedicatedAllocationMemoryAllocateInfoNV( VkDedicatedAllocationMemoryAllocateInfoNV const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DedicatedAllocationMemoryAllocateInfoNV) );\n    }\n\n    DedicatedAllocationMemoryAllocateInfoNV& operator=( VkDedicatedAllocationMemoryAllocateInfoNV const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DedicatedAllocationMemoryAllocateInfoNV) );\n      return *this;\n    }\n\n    DedicatedAllocationMemoryAllocateInfoNV& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    DedicatedAllocationMemoryAllocateInfoNV& setImage( Image image_ )\n    {\n      image = image_;\n      return *this;\n    }\n\n    DedicatedAllocationMemoryAllocateInfoNV& setBuffer( Buffer buffer_ )\n    {\n      buffer = buffer_;\n      return *this;\n    }\n\n    operator const VkDedicatedAllocationMemoryAllocateInfoNV&() const\n    {\n      return *reinterpret_cast<const VkDedicatedAllocationMemoryAllocateInfoNV*>(this);\n    }\n\n    bool operator==( DedicatedAllocationMemoryAllocateInfoNV const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( image == rhs.image )\n          && ( buffer == rhs.buffer );\n    }\n\n    bool operator!=( DedicatedAllocationMemoryAllocateInfoNV const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    Image image;\n    Buffer buffer;\n  };\n  static_assert( sizeof( DedicatedAllocationMemoryAllocateInfoNV ) == sizeof( VkDedicatedAllocationMemoryAllocateInfoNV ), \"struct and wrapper have different size!\" );\n\n#ifdef VK_USE_PLATFORM_WIN32_KHR\n  struct ExportMemoryWin32HandleInfoNV\n  {\n    ExportMemoryWin32HandleInfoNV( const SECURITY_ATTRIBUTES* pAttributes_ = nullptr, DWORD dwAccess_ = 0 )\n      : sType( StructureType::eExportMemoryWin32HandleInfoNV )\n      , pNext( nullptr )\n      , pAttributes( pAttributes_ )\n      , dwAccess( dwAccess_ )\n    {\n    }\n\n    ExportMemoryWin32HandleInfoNV( VkExportMemoryWin32HandleInfoNV const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ExportMemoryWin32HandleInfoNV) );\n    }\n\n    ExportMemoryWin32HandleInfoNV& operator=( VkExportMemoryWin32HandleInfoNV const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ExportMemoryWin32HandleInfoNV) );\n      return *this;\n    }\n\n    ExportMemoryWin32HandleInfoNV& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    ExportMemoryWin32HandleInfoNV& setPAttributes( const SECURITY_ATTRIBUTES* pAttributes_ )\n    {\n      pAttributes = pAttributes_;\n      return *this;\n    }\n\n    ExportMemoryWin32HandleInfoNV& setDwAccess( DWORD dwAccess_ )\n    {\n      dwAccess = dwAccess_;\n      return *this;\n    }\n\n    operator const VkExportMemoryWin32HandleInfoNV&() const\n    {\n      return *reinterpret_cast<const VkExportMemoryWin32HandleInfoNV*>(this);\n    }\n\n    bool operator==( ExportMemoryWin32HandleInfoNV const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( pAttributes == rhs.pAttributes )\n          && ( dwAccess == rhs.dwAccess );\n    }\n\n    bool operator!=( ExportMemoryWin32HandleInfoNV const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    const SECURITY_ATTRIBUTES* pAttributes;\n    DWORD dwAccess;\n  };\n  static_assert( sizeof( ExportMemoryWin32HandleInfoNV ) == sizeof( VkExportMemoryWin32HandleInfoNV ), \"struct and wrapper have different size!\" );\n#endif /*VK_USE_PLATFORM_WIN32_KHR*/\n\n#ifdef VK_USE_PLATFORM_WIN32_KHR\n  struct Win32KeyedMutexAcquireReleaseInfoNV\n  {\n    Win32KeyedMutexAcquireReleaseInfoNV( uint32_t acquireCount_ = 0, const DeviceMemory* pAcquireSyncs_ = nullptr, const uint64_t* pAcquireKeys_ = nullptr, const uint32_t* pAcquireTimeoutMilliseconds_ = nullptr, uint32_t releaseCount_ = 0, const DeviceMemory* pReleaseSyncs_ = nullptr, const uint64_t* pReleaseKeys_ = nullptr )\n      : sType( StructureType::eWin32KeyedMutexAcquireReleaseInfoNV )\n      , pNext( nullptr )\n      , acquireCount( acquireCount_ )\n      , pAcquireSyncs( pAcquireSyncs_ )\n      , pAcquireKeys( pAcquireKeys_ )\n      , pAcquireTimeoutMilliseconds( pAcquireTimeoutMilliseconds_ )\n      , releaseCount( releaseCount_ )\n      , pReleaseSyncs( pReleaseSyncs_ )\n      , pReleaseKeys( pReleaseKeys_ )\n    {\n    }\n\n    Win32KeyedMutexAcquireReleaseInfoNV( VkWin32KeyedMutexAcquireReleaseInfoNV const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(Win32KeyedMutexAcquireReleaseInfoNV) );\n    }\n\n    Win32KeyedMutexAcquireReleaseInfoNV& operator=( VkWin32KeyedMutexAcquireReleaseInfoNV const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(Win32KeyedMutexAcquireReleaseInfoNV) );\n      return *this;\n    }\n\n    Win32KeyedMutexAcquireReleaseInfoNV& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    Win32KeyedMutexAcquireReleaseInfoNV& setAcquireCount( uint32_t acquireCount_ )\n    {\n      acquireCount = acquireCount_;\n      return *this;\n    }\n\n    Win32KeyedMutexAcquireReleaseInfoNV& setPAcquireSyncs( const DeviceMemory* pAcquireSyncs_ )\n    {\n      pAcquireSyncs = pAcquireSyncs_;\n      return *this;\n    }\n\n    Win32KeyedMutexAcquireReleaseInfoNV& setPAcquireKeys( const uint64_t* pAcquireKeys_ )\n    {\n      pAcquireKeys = pAcquireKeys_;\n      return *this;\n    }\n\n    Win32KeyedMutexAcquireReleaseInfoNV& setPAcquireTimeoutMilliseconds( const uint32_t* pAcquireTimeoutMilliseconds_ )\n    {\n      pAcquireTimeoutMilliseconds = pAcquireTimeoutMilliseconds_;\n      return *this;\n    }\n\n    Win32KeyedMutexAcquireReleaseInfoNV& setReleaseCount( uint32_t releaseCount_ )\n    {\n      releaseCount = releaseCount_;\n      return *this;\n    }\n\n    Win32KeyedMutexAcquireReleaseInfoNV& setPReleaseSyncs( const DeviceMemory* pReleaseSyncs_ )\n    {\n      pReleaseSyncs = pReleaseSyncs_;\n      return *this;\n    }\n\n    Win32KeyedMutexAcquireReleaseInfoNV& setPReleaseKeys( const uint64_t* pReleaseKeys_ )\n    {\n      pReleaseKeys = pReleaseKeys_;\n      return *this;\n    }\n\n    operator const VkWin32KeyedMutexAcquireReleaseInfoNV&() const\n    {\n      return *reinterpret_cast<const VkWin32KeyedMutexAcquireReleaseInfoNV*>(this);\n    }\n\n    bool operator==( Win32KeyedMutexAcquireReleaseInfoNV const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( acquireCount == rhs.acquireCount )\n          && ( pAcquireSyncs == rhs.pAcquireSyncs )\n          && ( pAcquireKeys == rhs.pAcquireKeys )\n          && ( pAcquireTimeoutMilliseconds == rhs.pAcquireTimeoutMilliseconds )\n          && ( releaseCount == rhs.releaseCount )\n          && ( pReleaseSyncs == rhs.pReleaseSyncs )\n          && ( pReleaseKeys == rhs.pReleaseKeys );\n    }\n\n    bool operator!=( Win32KeyedMutexAcquireReleaseInfoNV const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    uint32_t acquireCount;\n    const DeviceMemory* pAcquireSyncs;\n    const uint64_t* pAcquireKeys;\n    const uint32_t* pAcquireTimeoutMilliseconds;\n    uint32_t releaseCount;\n    const DeviceMemory* pReleaseSyncs;\n    const uint64_t* pReleaseKeys;\n  };\n  static_assert( sizeof( Win32KeyedMutexAcquireReleaseInfoNV ) == sizeof( VkWin32KeyedMutexAcquireReleaseInfoNV ), \"struct and wrapper have different size!\" );\n#endif /*VK_USE_PLATFORM_WIN32_KHR*/\n\n  struct DeviceGeneratedCommandsFeaturesNVX\n  {\n    DeviceGeneratedCommandsFeaturesNVX( Bool32 computeBindingPointSupport_ = 0 )\n      : sType( StructureType::eDeviceGeneratedCommandsFeaturesNVX )\n      , pNext( nullptr )\n      , computeBindingPointSupport( computeBindingPointSupport_ )\n    {\n    }\n\n    DeviceGeneratedCommandsFeaturesNVX( VkDeviceGeneratedCommandsFeaturesNVX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DeviceGeneratedCommandsFeaturesNVX) );\n    }\n\n    DeviceGeneratedCommandsFeaturesNVX& operator=( VkDeviceGeneratedCommandsFeaturesNVX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DeviceGeneratedCommandsFeaturesNVX) );\n      return *this;\n    }\n\n    DeviceGeneratedCommandsFeaturesNVX& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    DeviceGeneratedCommandsFeaturesNVX& setComputeBindingPointSupport( Bool32 computeBindingPointSupport_ )\n    {\n      computeBindingPointSupport = computeBindingPointSupport_;\n      return *this;\n    }\n\n    operator const VkDeviceGeneratedCommandsFeaturesNVX&() const\n    {\n      return *reinterpret_cast<const VkDeviceGeneratedCommandsFeaturesNVX*>(this);\n    }\n\n    bool operator==( DeviceGeneratedCommandsFeaturesNVX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( computeBindingPointSupport == rhs.computeBindingPointSupport );\n    }\n\n    bool operator!=( DeviceGeneratedCommandsFeaturesNVX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    Bool32 computeBindingPointSupport;\n  };\n  static_assert( sizeof( DeviceGeneratedCommandsFeaturesNVX ) == sizeof( VkDeviceGeneratedCommandsFeaturesNVX ), \"struct and wrapper have different size!\" );\n\n  struct DeviceGeneratedCommandsLimitsNVX\n  {\n    DeviceGeneratedCommandsLimitsNVX( uint32_t maxIndirectCommandsLayoutTokenCount_ = 0, uint32_t maxObjectEntryCounts_ = 0, uint32_t minSequenceCountBufferOffsetAlignment_ = 0, uint32_t minSequenceIndexBufferOffsetAlignment_ = 0, uint32_t minCommandsTokenBufferOffsetAlignment_ = 0 )\n      : sType( StructureType::eDeviceGeneratedCommandsLimitsNVX )\n      , pNext( nullptr )\n      , maxIndirectCommandsLayoutTokenCount( maxIndirectCommandsLayoutTokenCount_ )\n      , maxObjectEntryCounts( maxObjectEntryCounts_ )\n      , minSequenceCountBufferOffsetAlignment( minSequenceCountBufferOffsetAlignment_ )\n      , minSequenceIndexBufferOffsetAlignment( minSequenceIndexBufferOffsetAlignment_ )\n      , minCommandsTokenBufferOffsetAlignment( minCommandsTokenBufferOffsetAlignment_ )\n    {\n    }\n\n    DeviceGeneratedCommandsLimitsNVX( VkDeviceGeneratedCommandsLimitsNVX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DeviceGeneratedCommandsLimitsNVX) );\n    }\n\n    DeviceGeneratedCommandsLimitsNVX& operator=( VkDeviceGeneratedCommandsLimitsNVX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DeviceGeneratedCommandsLimitsNVX) );\n      return *this;\n    }\n\n    DeviceGeneratedCommandsLimitsNVX& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    DeviceGeneratedCommandsLimitsNVX& setMaxIndirectCommandsLayoutTokenCount( uint32_t maxIndirectCommandsLayoutTokenCount_ )\n    {\n      maxIndirectCommandsLayoutTokenCount = maxIndirectCommandsLayoutTokenCount_;\n      return *this;\n    }\n\n    DeviceGeneratedCommandsLimitsNVX& setMaxObjectEntryCounts( uint32_t maxObjectEntryCounts_ )\n    {\n      maxObjectEntryCounts = maxObjectEntryCounts_;\n      return *this;\n    }\n\n    DeviceGeneratedCommandsLimitsNVX& setMinSequenceCountBufferOffsetAlignment( uint32_t minSequenceCountBufferOffsetAlignment_ )\n    {\n      minSequenceCountBufferOffsetAlignment = minSequenceCountBufferOffsetAlignment_;\n      return *this;\n    }\n\n    DeviceGeneratedCommandsLimitsNVX& setMinSequenceIndexBufferOffsetAlignment( uint32_t minSequenceIndexBufferOffsetAlignment_ )\n    {\n      minSequenceIndexBufferOffsetAlignment = minSequenceIndexBufferOffsetAlignment_;\n      return *this;\n    }\n\n    DeviceGeneratedCommandsLimitsNVX& setMinCommandsTokenBufferOffsetAlignment( uint32_t minCommandsTokenBufferOffsetAlignment_ )\n    {\n      minCommandsTokenBufferOffsetAlignment = minCommandsTokenBufferOffsetAlignment_;\n      return *this;\n    }\n\n    operator const VkDeviceGeneratedCommandsLimitsNVX&() const\n    {\n      return *reinterpret_cast<const VkDeviceGeneratedCommandsLimitsNVX*>(this);\n    }\n\n    bool operator==( DeviceGeneratedCommandsLimitsNVX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( maxIndirectCommandsLayoutTokenCount == rhs.maxIndirectCommandsLayoutTokenCount )\n          && ( maxObjectEntryCounts == rhs.maxObjectEntryCounts )\n          && ( minSequenceCountBufferOffsetAlignment == rhs.minSequenceCountBufferOffsetAlignment )\n          && ( minSequenceIndexBufferOffsetAlignment == rhs.minSequenceIndexBufferOffsetAlignment )\n          && ( minCommandsTokenBufferOffsetAlignment == rhs.minCommandsTokenBufferOffsetAlignment );\n    }\n\n    bool operator!=( DeviceGeneratedCommandsLimitsNVX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    uint32_t maxIndirectCommandsLayoutTokenCount;\n    uint32_t maxObjectEntryCounts;\n    uint32_t minSequenceCountBufferOffsetAlignment;\n    uint32_t minSequenceIndexBufferOffsetAlignment;\n    uint32_t minCommandsTokenBufferOffsetAlignment;\n  };\n  static_assert( sizeof( DeviceGeneratedCommandsLimitsNVX ) == sizeof( VkDeviceGeneratedCommandsLimitsNVX ), \"struct and wrapper have different size!\" );\n\n  struct CmdReserveSpaceForCommandsInfoNVX\n  {\n    CmdReserveSpaceForCommandsInfoNVX( ObjectTableNVX objectTable_ = ObjectTableNVX(), IndirectCommandsLayoutNVX indirectCommandsLayout_ = IndirectCommandsLayoutNVX(), uint32_t maxSequencesCount_ = 0 )\n      : sType( StructureType::eCmdReserveSpaceForCommandsInfoNVX )\n      , pNext( nullptr )\n      , objectTable( objectTable_ )\n      , indirectCommandsLayout( indirectCommandsLayout_ )\n      , maxSequencesCount( maxSequencesCount_ )\n    {\n    }\n\n    CmdReserveSpaceForCommandsInfoNVX( VkCmdReserveSpaceForCommandsInfoNVX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(CmdReserveSpaceForCommandsInfoNVX) );\n    }\n\n    CmdReserveSpaceForCommandsInfoNVX& operator=( VkCmdReserveSpaceForCommandsInfoNVX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(CmdReserveSpaceForCommandsInfoNVX) );\n      return *this;\n    }\n\n    CmdReserveSpaceForCommandsInfoNVX& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    CmdReserveSpaceForCommandsInfoNVX& setObjectTable( ObjectTableNVX objectTable_ )\n    {\n      objectTable = objectTable_;\n      return *this;\n    }\n\n    CmdReserveSpaceForCommandsInfoNVX& setIndirectCommandsLayout( IndirectCommandsLayoutNVX indirectCommandsLayout_ )\n    {\n      indirectCommandsLayout = indirectCommandsLayout_;\n      return *this;\n    }\n\n    CmdReserveSpaceForCommandsInfoNVX& setMaxSequencesCount( uint32_t maxSequencesCount_ )\n    {\n      maxSequencesCount = maxSequencesCount_;\n      return *this;\n    }\n\n    operator const VkCmdReserveSpaceForCommandsInfoNVX&() const\n    {\n      return *reinterpret_cast<const VkCmdReserveSpaceForCommandsInfoNVX*>(this);\n    }\n\n    bool operator==( CmdReserveSpaceForCommandsInfoNVX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( objectTable == rhs.objectTable )\n          && ( indirectCommandsLayout == rhs.indirectCommandsLayout )\n          && ( maxSequencesCount == rhs.maxSequencesCount );\n    }\n\n    bool operator!=( CmdReserveSpaceForCommandsInfoNVX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    ObjectTableNVX objectTable;\n    IndirectCommandsLayoutNVX indirectCommandsLayout;\n    uint32_t maxSequencesCount;\n  };\n  static_assert( sizeof( CmdReserveSpaceForCommandsInfoNVX ) == sizeof( VkCmdReserveSpaceForCommandsInfoNVX ), \"struct and wrapper have different size!\" );\n\n  struct PhysicalDeviceFeatures2KHR\n  {\n    PhysicalDeviceFeatures2KHR( PhysicalDeviceFeatures features_ = PhysicalDeviceFeatures() )\n      : sType( StructureType::ePhysicalDeviceFeatures2KHR )\n      , pNext( nullptr )\n      , features( features_ )\n    {\n    }\n\n    PhysicalDeviceFeatures2KHR( VkPhysicalDeviceFeatures2KHR const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PhysicalDeviceFeatures2KHR) );\n    }\n\n    PhysicalDeviceFeatures2KHR& operator=( VkPhysicalDeviceFeatures2KHR const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PhysicalDeviceFeatures2KHR) );\n      return *this;\n    }\n\n    PhysicalDeviceFeatures2KHR& setPNext( void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    PhysicalDeviceFeatures2KHR& setFeatures( PhysicalDeviceFeatures features_ )\n    {\n      features = features_;\n      return *this;\n    }\n\n    operator const VkPhysicalDeviceFeatures2KHR&() const\n    {\n      return *reinterpret_cast<const VkPhysicalDeviceFeatures2KHR*>(this);\n    }\n\n    bool operator==( PhysicalDeviceFeatures2KHR const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( features == rhs.features );\n    }\n\n    bool operator!=( PhysicalDeviceFeatures2KHR const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    void* pNext;\n    PhysicalDeviceFeatures features;\n  };\n  static_assert( sizeof( PhysicalDeviceFeatures2KHR ) == sizeof( VkPhysicalDeviceFeatures2KHR ), \"struct and wrapper have different size!\" );\n\n  struct PhysicalDevicePushDescriptorPropertiesKHR\n  {\n    PhysicalDevicePushDescriptorPropertiesKHR( uint32_t maxPushDescriptors_ = 0 )\n      : sType( StructureType::ePhysicalDevicePushDescriptorPropertiesKHR )\n      , pNext( nullptr )\n      , maxPushDescriptors( maxPushDescriptors_ )\n    {\n    }\n\n    PhysicalDevicePushDescriptorPropertiesKHR( VkPhysicalDevicePushDescriptorPropertiesKHR const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PhysicalDevicePushDescriptorPropertiesKHR) );\n    }\n\n    PhysicalDevicePushDescriptorPropertiesKHR& operator=( VkPhysicalDevicePushDescriptorPropertiesKHR const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PhysicalDevicePushDescriptorPropertiesKHR) );\n      return *this;\n    }\n\n    PhysicalDevicePushDescriptorPropertiesKHR& setPNext( void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    PhysicalDevicePushDescriptorPropertiesKHR& setMaxPushDescriptors( uint32_t maxPushDescriptors_ )\n    {\n      maxPushDescriptors = maxPushDescriptors_;\n      return *this;\n    }\n\n    operator const VkPhysicalDevicePushDescriptorPropertiesKHR&() const\n    {\n      return *reinterpret_cast<const VkPhysicalDevicePushDescriptorPropertiesKHR*>(this);\n    }\n\n    bool operator==( PhysicalDevicePushDescriptorPropertiesKHR const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( maxPushDescriptors == rhs.maxPushDescriptors );\n    }\n\n    bool operator!=( PhysicalDevicePushDescriptorPropertiesKHR const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    void* pNext;\n    uint32_t maxPushDescriptors;\n  };\n  static_assert( sizeof( PhysicalDevicePushDescriptorPropertiesKHR ) == sizeof( VkPhysicalDevicePushDescriptorPropertiesKHR ), \"struct and wrapper have different size!\" );\n\n  struct PresentRegionsKHR\n  {\n    PresentRegionsKHR( uint32_t swapchainCount_ = 0, const PresentRegionKHR* pRegions_ = nullptr )\n      : sType( StructureType::ePresentRegionsKHR )\n      , pNext( nullptr )\n      , swapchainCount( swapchainCount_ )\n      , pRegions( pRegions_ )\n    {\n    }\n\n    PresentRegionsKHR( VkPresentRegionsKHR const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PresentRegionsKHR) );\n    }\n\n    PresentRegionsKHR& operator=( VkPresentRegionsKHR const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PresentRegionsKHR) );\n      return *this;\n    }\n\n    PresentRegionsKHR& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    PresentRegionsKHR& setSwapchainCount( uint32_t swapchainCount_ )\n    {\n      swapchainCount = swapchainCount_;\n      return *this;\n    }\n\n    PresentRegionsKHR& setPRegions( const PresentRegionKHR* pRegions_ )\n    {\n      pRegions = pRegions_;\n      return *this;\n    }\n\n    operator const VkPresentRegionsKHR&() const\n    {\n      return *reinterpret_cast<const VkPresentRegionsKHR*>(this);\n    }\n\n    bool operator==( PresentRegionsKHR const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( swapchainCount == rhs.swapchainCount )\n          && ( pRegions == rhs.pRegions );\n    }\n\n    bool operator!=( PresentRegionsKHR const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    uint32_t swapchainCount;\n    const PresentRegionKHR* pRegions;\n  };\n  static_assert( sizeof( PresentRegionsKHR ) == sizeof( VkPresentRegionsKHR ), \"struct and wrapper have different size!\" );\n\n  struct PhysicalDeviceIDPropertiesKHX\n  {\n    operator const VkPhysicalDeviceIDPropertiesKHX&() const\n    {\n      return *reinterpret_cast<const VkPhysicalDeviceIDPropertiesKHX*>(this);\n    }\n\n    bool operator==( PhysicalDeviceIDPropertiesKHX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( memcmp( deviceUUID, rhs.deviceUUID, VK_UUID_SIZE * sizeof( uint8_t ) ) == 0 )\n          && ( memcmp( driverUUID, rhs.driverUUID, VK_UUID_SIZE * sizeof( uint8_t ) ) == 0 )\n          && ( memcmp( deviceLUID, rhs.deviceLUID, VK_LUID_SIZE_KHX * sizeof( uint8_t ) ) == 0 )\n          && ( deviceLUIDValid == rhs.deviceLUIDValid );\n    }\n\n    bool operator!=( PhysicalDeviceIDPropertiesKHX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    void* pNext;\n    uint8_t deviceUUID[VK_UUID_SIZE];\n    uint8_t driverUUID[VK_UUID_SIZE];\n    uint8_t deviceLUID[VK_LUID_SIZE_KHX];\n    Bool32 deviceLUIDValid;\n  };\n  static_assert( sizeof( PhysicalDeviceIDPropertiesKHX ) == sizeof( VkPhysicalDeviceIDPropertiesKHX ), \"struct and wrapper have different size!\" );\n\n#ifdef VK_USE_PLATFORM_WIN32_KHX\n  struct ExportMemoryWin32HandleInfoKHX\n  {\n    ExportMemoryWin32HandleInfoKHX( const SECURITY_ATTRIBUTES* pAttributes_ = nullptr, DWORD dwAccess_ = 0, LPCWSTR name_ = 0 )\n      : sType( StructureType::eExportMemoryWin32HandleInfoKHX )\n      , pNext( nullptr )\n      , pAttributes( pAttributes_ )\n      , dwAccess( dwAccess_ )\n      , name( name_ )\n    {\n    }\n\n    ExportMemoryWin32HandleInfoKHX( VkExportMemoryWin32HandleInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ExportMemoryWin32HandleInfoKHX) );\n    }\n\n    ExportMemoryWin32HandleInfoKHX& operator=( VkExportMemoryWin32HandleInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ExportMemoryWin32HandleInfoKHX) );\n      return *this;\n    }\n\n    ExportMemoryWin32HandleInfoKHX& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    ExportMemoryWin32HandleInfoKHX& setPAttributes( const SECURITY_ATTRIBUTES* pAttributes_ )\n    {\n      pAttributes = pAttributes_;\n      return *this;\n    }\n\n    ExportMemoryWin32HandleInfoKHX& setDwAccess( DWORD dwAccess_ )\n    {\n      dwAccess = dwAccess_;\n      return *this;\n    }\n\n    ExportMemoryWin32HandleInfoKHX& setName( LPCWSTR name_ )\n    {\n      name = name_;\n      return *this;\n    }\n\n    operator const VkExportMemoryWin32HandleInfoKHX&() const\n    {\n      return *reinterpret_cast<const VkExportMemoryWin32HandleInfoKHX*>(this);\n    }\n\n    bool operator==( ExportMemoryWin32HandleInfoKHX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( pAttributes == rhs.pAttributes )\n          && ( dwAccess == rhs.dwAccess )\n          && ( name == rhs.name );\n    }\n\n    bool operator!=( ExportMemoryWin32HandleInfoKHX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    const SECURITY_ATTRIBUTES* pAttributes;\n    DWORD dwAccess;\n    LPCWSTR name;\n  };\n  static_assert( sizeof( ExportMemoryWin32HandleInfoKHX ) == sizeof( VkExportMemoryWin32HandleInfoKHX ), \"struct and wrapper have different size!\" );\n#endif /*VK_USE_PLATFORM_WIN32_KHX*/\n\n#ifdef VK_USE_PLATFORM_WIN32_KHX\n  struct MemoryWin32HandlePropertiesKHX\n  {\n    operator const VkMemoryWin32HandlePropertiesKHX&() const\n    {\n      return *reinterpret_cast<const VkMemoryWin32HandlePropertiesKHX*>(this);\n    }\n\n    bool operator==( MemoryWin32HandlePropertiesKHX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( memoryTypeBits == rhs.memoryTypeBits );\n    }\n\n    bool operator!=( MemoryWin32HandlePropertiesKHX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    void* pNext;\n    uint32_t memoryTypeBits;\n  };\n  static_assert( sizeof( MemoryWin32HandlePropertiesKHX ) == sizeof( VkMemoryWin32HandlePropertiesKHX ), \"struct and wrapper have different size!\" );\n#endif /*VK_USE_PLATFORM_WIN32_KHX*/\n\n  struct MemoryFdPropertiesKHX\n  {\n    operator const VkMemoryFdPropertiesKHX&() const\n    {\n      return *reinterpret_cast<const VkMemoryFdPropertiesKHX*>(this);\n    }\n\n    bool operator==( MemoryFdPropertiesKHX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( memoryTypeBits == rhs.memoryTypeBits );\n    }\n\n    bool operator!=( MemoryFdPropertiesKHX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    void* pNext;\n    uint32_t memoryTypeBits;\n  };\n  static_assert( sizeof( MemoryFdPropertiesKHX ) == sizeof( VkMemoryFdPropertiesKHX ), \"struct and wrapper have different size!\" );\n\n#ifdef VK_USE_PLATFORM_WIN32_KHR\n  struct Win32KeyedMutexAcquireReleaseInfoKHX\n  {\n    Win32KeyedMutexAcquireReleaseInfoKHX( uint32_t acquireCount_ = 0, const DeviceMemory* pAcquireSyncs_ = nullptr, const uint64_t* pAcquireKeys_ = nullptr, const uint32_t* pAcquireTimeouts_ = nullptr, uint32_t releaseCount_ = 0, const DeviceMemory* pReleaseSyncs_ = nullptr, const uint64_t* pReleaseKeys_ = nullptr )\n      : sType( StructureType::eWin32KeyedMutexAcquireReleaseInfoKHX )\n      , pNext( nullptr )\n      , acquireCount( acquireCount_ )\n      , pAcquireSyncs( pAcquireSyncs_ )\n      , pAcquireKeys( pAcquireKeys_ )\n      , pAcquireTimeouts( pAcquireTimeouts_ )\n      , releaseCount( releaseCount_ )\n      , pReleaseSyncs( pReleaseSyncs_ )\n      , pReleaseKeys( pReleaseKeys_ )\n    {\n    }\n\n    Win32KeyedMutexAcquireReleaseInfoKHX( VkWin32KeyedMutexAcquireReleaseInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(Win32KeyedMutexAcquireReleaseInfoKHX) );\n    }\n\n    Win32KeyedMutexAcquireReleaseInfoKHX& operator=( VkWin32KeyedMutexAcquireReleaseInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(Win32KeyedMutexAcquireReleaseInfoKHX) );\n      return *this;\n    }\n\n    Win32KeyedMutexAcquireReleaseInfoKHX& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    Win32KeyedMutexAcquireReleaseInfoKHX& setAcquireCount( uint32_t acquireCount_ )\n    {\n      acquireCount = acquireCount_;\n      return *this;\n    }\n\n    Win32KeyedMutexAcquireReleaseInfoKHX& setPAcquireSyncs( const DeviceMemory* pAcquireSyncs_ )\n    {\n      pAcquireSyncs = pAcquireSyncs_;\n      return *this;\n    }\n\n    Win32KeyedMutexAcquireReleaseInfoKHX& setPAcquireKeys( const uint64_t* pAcquireKeys_ )\n    {\n      pAcquireKeys = pAcquireKeys_;\n      return *this;\n    }\n\n    Win32KeyedMutexAcquireReleaseInfoKHX& setPAcquireTimeouts( const uint32_t* pAcquireTimeouts_ )\n    {\n      pAcquireTimeouts = pAcquireTimeouts_;\n      return *this;\n    }\n\n    Win32KeyedMutexAcquireReleaseInfoKHX& setReleaseCount( uint32_t releaseCount_ )\n    {\n      releaseCount = releaseCount_;\n      return *this;\n    }\n\n    Win32KeyedMutexAcquireReleaseInfoKHX& setPReleaseSyncs( const DeviceMemory* pReleaseSyncs_ )\n    {\n      pReleaseSyncs = pReleaseSyncs_;\n      return *this;\n    }\n\n    Win32KeyedMutexAcquireReleaseInfoKHX& setPReleaseKeys( const uint64_t* pReleaseKeys_ )\n    {\n      pReleaseKeys = pReleaseKeys_;\n      return *this;\n    }\n\n    operator const VkWin32KeyedMutexAcquireReleaseInfoKHX&() const\n    {\n      return *reinterpret_cast<const VkWin32KeyedMutexAcquireReleaseInfoKHX*>(this);\n    }\n\n    bool operator==( Win32KeyedMutexAcquireReleaseInfoKHX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( acquireCount == rhs.acquireCount )\n          && ( pAcquireSyncs == rhs.pAcquireSyncs )\n          && ( pAcquireKeys == rhs.pAcquireKeys )\n          && ( pAcquireTimeouts == rhs.pAcquireTimeouts )\n          && ( releaseCount == rhs.releaseCount )\n          && ( pReleaseSyncs == rhs.pReleaseSyncs )\n          && ( pReleaseKeys == rhs.pReleaseKeys );\n    }\n\n    bool operator!=( Win32KeyedMutexAcquireReleaseInfoKHX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    uint32_t acquireCount;\n    const DeviceMemory* pAcquireSyncs;\n    const uint64_t* pAcquireKeys;\n    const uint32_t* pAcquireTimeouts;\n    uint32_t releaseCount;\n    const DeviceMemory* pReleaseSyncs;\n    const uint64_t* pReleaseKeys;\n  };\n  static_assert( sizeof( Win32KeyedMutexAcquireReleaseInfoKHX ) == sizeof( VkWin32KeyedMutexAcquireReleaseInfoKHX ), \"struct and wrapper have different size!\" );\n#endif /*VK_USE_PLATFORM_WIN32_KHR*/\n\n#ifdef VK_USE_PLATFORM_WIN32_KHX\n  struct ExportSemaphoreWin32HandleInfoKHX\n  {\n    ExportSemaphoreWin32HandleInfoKHX( const SECURITY_ATTRIBUTES* pAttributes_ = nullptr, DWORD dwAccess_ = 0, LPCWSTR name_ = 0 )\n      : sType( StructureType::eExportSemaphoreWin32HandleInfoKHX )\n      , pNext( nullptr )\n      , pAttributes( pAttributes_ )\n      , dwAccess( dwAccess_ )\n      , name( name_ )\n    {\n    }\n\n    ExportSemaphoreWin32HandleInfoKHX( VkExportSemaphoreWin32HandleInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ExportSemaphoreWin32HandleInfoKHX) );\n    }\n\n    ExportSemaphoreWin32HandleInfoKHX& operator=( VkExportSemaphoreWin32HandleInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ExportSemaphoreWin32HandleInfoKHX) );\n      return *this;\n    }\n\n    ExportSemaphoreWin32HandleInfoKHX& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    ExportSemaphoreWin32HandleInfoKHX& setPAttributes( const SECURITY_ATTRIBUTES* pAttributes_ )\n    {\n      pAttributes = pAttributes_;\n      return *this;\n    }\n\n    ExportSemaphoreWin32HandleInfoKHX& setDwAccess( DWORD dwAccess_ )\n    {\n      dwAccess = dwAccess_;\n      return *this;\n    }\n\n    ExportSemaphoreWin32HandleInfoKHX& setName( LPCWSTR name_ )\n    {\n      name = name_;\n      return *this;\n    }\n\n    operator const VkExportSemaphoreWin32HandleInfoKHX&() const\n    {\n      return *reinterpret_cast<const VkExportSemaphoreWin32HandleInfoKHX*>(this);\n    }\n\n    bool operator==( ExportSemaphoreWin32HandleInfoKHX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( pAttributes == rhs.pAttributes )\n          && ( dwAccess == rhs.dwAccess )\n          && ( name == rhs.name );\n    }\n\n    bool operator!=( ExportSemaphoreWin32HandleInfoKHX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    const SECURITY_ATTRIBUTES* pAttributes;\n    DWORD dwAccess;\n    LPCWSTR name;\n  };\n  static_assert( sizeof( ExportSemaphoreWin32HandleInfoKHX ) == sizeof( VkExportSemaphoreWin32HandleInfoKHX ), \"struct and wrapper have different size!\" );\n#endif /*VK_USE_PLATFORM_WIN32_KHX*/\n\n#ifdef VK_USE_PLATFORM_WIN32_KHX\n  struct D3D12FenceSubmitInfoKHX\n  {\n    D3D12FenceSubmitInfoKHX( uint32_t waitSemaphoreValuesCount_ = 0, const uint64_t* pWaitSemaphoreValues_ = nullptr, uint32_t signalSemaphoreValuesCount_ = 0, const uint64_t* pSignalSemaphoreValues_ = nullptr )\n      : sType( StructureType::eD3D12FenceSubmitInfoKHX )\n      , pNext( nullptr )\n      , waitSemaphoreValuesCount( waitSemaphoreValuesCount_ )\n      , pWaitSemaphoreValues( pWaitSemaphoreValues_ )\n      , signalSemaphoreValuesCount( signalSemaphoreValuesCount_ )\n      , pSignalSemaphoreValues( pSignalSemaphoreValues_ )\n    {\n    }\n\n    D3D12FenceSubmitInfoKHX( VkD3D12FenceSubmitInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(D3D12FenceSubmitInfoKHX) );\n    }\n\n    D3D12FenceSubmitInfoKHX& operator=( VkD3D12FenceSubmitInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(D3D12FenceSubmitInfoKHX) );\n      return *this;\n    }\n\n    D3D12FenceSubmitInfoKHX& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    D3D12FenceSubmitInfoKHX& setWaitSemaphoreValuesCount( uint32_t waitSemaphoreValuesCount_ )\n    {\n      waitSemaphoreValuesCount = waitSemaphoreValuesCount_;\n      return *this;\n    }\n\n    D3D12FenceSubmitInfoKHX& setPWaitSemaphoreValues( const uint64_t* pWaitSemaphoreValues_ )\n    {\n      pWaitSemaphoreValues = pWaitSemaphoreValues_;\n      return *this;\n    }\n\n    D3D12FenceSubmitInfoKHX& setSignalSemaphoreValuesCount( uint32_t signalSemaphoreValuesCount_ )\n    {\n      signalSemaphoreValuesCount = signalSemaphoreValuesCount_;\n      return *this;\n    }\n\n    D3D12FenceSubmitInfoKHX& setPSignalSemaphoreValues( const uint64_t* pSignalSemaphoreValues_ )\n    {\n      pSignalSemaphoreValues = pSignalSemaphoreValues_;\n      return *this;\n    }\n\n    operator const VkD3D12FenceSubmitInfoKHX&() const\n    {\n      return *reinterpret_cast<const VkD3D12FenceSubmitInfoKHX*>(this);\n    }\n\n    bool operator==( D3D12FenceSubmitInfoKHX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( waitSemaphoreValuesCount == rhs.waitSemaphoreValuesCount )\n          && ( pWaitSemaphoreValues == rhs.pWaitSemaphoreValues )\n          && ( signalSemaphoreValuesCount == rhs.signalSemaphoreValuesCount )\n          && ( pSignalSemaphoreValues == rhs.pSignalSemaphoreValues );\n    }\n\n    bool operator!=( D3D12FenceSubmitInfoKHX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    uint32_t waitSemaphoreValuesCount;\n    const uint64_t* pWaitSemaphoreValues;\n    uint32_t signalSemaphoreValuesCount;\n    const uint64_t* pSignalSemaphoreValues;\n  };\n  static_assert( sizeof( D3D12FenceSubmitInfoKHX ) == sizeof( VkD3D12FenceSubmitInfoKHX ), \"struct and wrapper have different size!\" );\n#endif /*VK_USE_PLATFORM_WIN32_KHX*/\n\n  struct PhysicalDeviceMultiviewFeaturesKHX\n  {\n    PhysicalDeviceMultiviewFeaturesKHX( Bool32 multiview_ = 0, Bool32 multiviewGeometryShader_ = 0, Bool32 multiviewTessellationShader_ = 0 )\n      : sType( StructureType::ePhysicalDeviceMultiviewFeaturesKHX )\n      , pNext( nullptr )\n      , multiview( multiview_ )\n      , multiviewGeometryShader( multiviewGeometryShader_ )\n      , multiviewTessellationShader( multiviewTessellationShader_ )\n    {\n    }\n\n    PhysicalDeviceMultiviewFeaturesKHX( VkPhysicalDeviceMultiviewFeaturesKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PhysicalDeviceMultiviewFeaturesKHX) );\n    }\n\n    PhysicalDeviceMultiviewFeaturesKHX& operator=( VkPhysicalDeviceMultiviewFeaturesKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PhysicalDeviceMultiviewFeaturesKHX) );\n      return *this;\n    }\n\n    PhysicalDeviceMultiviewFeaturesKHX& setPNext( void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    PhysicalDeviceMultiviewFeaturesKHX& setMultiview( Bool32 multiview_ )\n    {\n      multiview = multiview_;\n      return *this;\n    }\n\n    PhysicalDeviceMultiviewFeaturesKHX& setMultiviewGeometryShader( Bool32 multiviewGeometryShader_ )\n    {\n      multiviewGeometryShader = multiviewGeometryShader_;\n      return *this;\n    }\n\n    PhysicalDeviceMultiviewFeaturesKHX& setMultiviewTessellationShader( Bool32 multiviewTessellationShader_ )\n    {\n      multiviewTessellationShader = multiviewTessellationShader_;\n      return *this;\n    }\n\n    operator const VkPhysicalDeviceMultiviewFeaturesKHX&() const\n    {\n      return *reinterpret_cast<const VkPhysicalDeviceMultiviewFeaturesKHX*>(this);\n    }\n\n    bool operator==( PhysicalDeviceMultiviewFeaturesKHX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( multiview == rhs.multiview )\n          && ( multiviewGeometryShader == rhs.multiviewGeometryShader )\n          && ( multiviewTessellationShader == rhs.multiviewTessellationShader );\n    }\n\n    bool operator!=( PhysicalDeviceMultiviewFeaturesKHX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    void* pNext;\n    Bool32 multiview;\n    Bool32 multiviewGeometryShader;\n    Bool32 multiviewTessellationShader;\n  };\n  static_assert( sizeof( PhysicalDeviceMultiviewFeaturesKHX ) == sizeof( VkPhysicalDeviceMultiviewFeaturesKHX ), \"struct and wrapper have different size!\" );\n\n  struct PhysicalDeviceMultiviewPropertiesKHX\n  {\n    operator const VkPhysicalDeviceMultiviewPropertiesKHX&() const\n    {\n      return *reinterpret_cast<const VkPhysicalDeviceMultiviewPropertiesKHX*>(this);\n    }\n\n    bool operator==( PhysicalDeviceMultiviewPropertiesKHX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( maxMultiviewViewCount == rhs.maxMultiviewViewCount )\n          && ( maxMultiviewInstanceIndex == rhs.maxMultiviewInstanceIndex );\n    }\n\n    bool operator!=( PhysicalDeviceMultiviewPropertiesKHX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    void* pNext;\n    uint32_t maxMultiviewViewCount;\n    uint32_t maxMultiviewInstanceIndex;\n  };\n  static_assert( sizeof( PhysicalDeviceMultiviewPropertiesKHX ) == sizeof( VkPhysicalDeviceMultiviewPropertiesKHX ), \"struct and wrapper have different size!\" );\n\n  struct RenderPassMultiviewCreateInfoKHX\n  {\n    RenderPassMultiviewCreateInfoKHX( uint32_t subpassCount_ = 0, const uint32_t* pViewMasks_ = nullptr, uint32_t dependencyCount_ = 0, const int32_t* pViewOffsets_ = nullptr, uint32_t correlationMaskCount_ = 0, const uint32_t* pCorrelationMasks_ = nullptr )\n      : sType( StructureType::eRenderPassMultiviewCreateInfoKHX )\n      , pNext( nullptr )\n      , subpassCount( subpassCount_ )\n      , pViewMasks( pViewMasks_ )\n      , dependencyCount( dependencyCount_ )\n      , pViewOffsets( pViewOffsets_ )\n      , correlationMaskCount( correlationMaskCount_ )\n      , pCorrelationMasks( pCorrelationMasks_ )\n    {\n    }\n\n    RenderPassMultiviewCreateInfoKHX( VkRenderPassMultiviewCreateInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(RenderPassMultiviewCreateInfoKHX) );\n    }\n\n    RenderPassMultiviewCreateInfoKHX& operator=( VkRenderPassMultiviewCreateInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(RenderPassMultiviewCreateInfoKHX) );\n      return *this;\n    }\n\n    RenderPassMultiviewCreateInfoKHX& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    RenderPassMultiviewCreateInfoKHX& setSubpassCount( uint32_t subpassCount_ )\n    {\n      subpassCount = subpassCount_;\n      return *this;\n    }\n\n    RenderPassMultiviewCreateInfoKHX& setPViewMasks( const uint32_t* pViewMasks_ )\n    {\n      pViewMasks = pViewMasks_;\n      return *this;\n    }\n\n    RenderPassMultiviewCreateInfoKHX& setDependencyCount( uint32_t dependencyCount_ )\n    {\n      dependencyCount = dependencyCount_;\n      return *this;\n    }\n\n    RenderPassMultiviewCreateInfoKHX& setPViewOffsets( const int32_t* pViewOffsets_ )\n    {\n      pViewOffsets = pViewOffsets_;\n      return *this;\n    }\n\n    RenderPassMultiviewCreateInfoKHX& setCorrelationMaskCount( uint32_t correlationMaskCount_ )\n    {\n      correlationMaskCount = correlationMaskCount_;\n      return *this;\n    }\n\n    RenderPassMultiviewCreateInfoKHX& setPCorrelationMasks( const uint32_t* pCorrelationMasks_ )\n    {\n      pCorrelationMasks = pCorrelationMasks_;\n      return *this;\n    }\n\n    operator const VkRenderPassMultiviewCreateInfoKHX&() const\n    {\n      return *reinterpret_cast<const VkRenderPassMultiviewCreateInfoKHX*>(this);\n    }\n\n    bool operator==( RenderPassMultiviewCreateInfoKHX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( subpassCount == rhs.subpassCount )\n          && ( pViewMasks == rhs.pViewMasks )\n          && ( dependencyCount == rhs.dependencyCount )\n          && ( pViewOffsets == rhs.pViewOffsets )\n          && ( correlationMaskCount == rhs.correlationMaskCount )\n          && ( pCorrelationMasks == rhs.pCorrelationMasks );\n    }\n\n    bool operator!=( RenderPassMultiviewCreateInfoKHX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    uint32_t subpassCount;\n    const uint32_t* pViewMasks;\n    uint32_t dependencyCount;\n    const int32_t* pViewOffsets;\n    uint32_t correlationMaskCount;\n    const uint32_t* pCorrelationMasks;\n  };\n  static_assert( sizeof( RenderPassMultiviewCreateInfoKHX ) == sizeof( VkRenderPassMultiviewCreateInfoKHX ), \"struct and wrapper have different size!\" );\n\n  struct BindBufferMemoryInfoKHX\n  {\n    BindBufferMemoryInfoKHX( Buffer buffer_ = Buffer(), DeviceMemory memory_ = DeviceMemory(), DeviceSize memoryOffset_ = 0, uint32_t deviceIndexCount_ = 0, const uint32_t* pDeviceIndices_ = nullptr )\n      : sType( StructureType::eBindBufferMemoryInfoKHX )\n      , pNext( nullptr )\n      , buffer( buffer_ )\n      , memory( memory_ )\n      , memoryOffset( memoryOffset_ )\n      , deviceIndexCount( deviceIndexCount_ )\n      , pDeviceIndices( pDeviceIndices_ )\n    {\n    }\n\n    BindBufferMemoryInfoKHX( VkBindBufferMemoryInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(BindBufferMemoryInfoKHX) );\n    }\n\n    BindBufferMemoryInfoKHX& operator=( VkBindBufferMemoryInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(BindBufferMemoryInfoKHX) );\n      return *this;\n    }\n\n    BindBufferMemoryInfoKHX& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    BindBufferMemoryInfoKHX& setBuffer( Buffer buffer_ )\n    {\n      buffer = buffer_;\n      return *this;\n    }\n\n    BindBufferMemoryInfoKHX& setMemory( DeviceMemory memory_ )\n    {\n      memory = memory_;\n      return *this;\n    }\n\n    BindBufferMemoryInfoKHX& setMemoryOffset( DeviceSize memoryOffset_ )\n    {\n      memoryOffset = memoryOffset_;\n      return *this;\n    }\n\n    BindBufferMemoryInfoKHX& setDeviceIndexCount( uint32_t deviceIndexCount_ )\n    {\n      deviceIndexCount = deviceIndexCount_;\n      return *this;\n    }\n\n    BindBufferMemoryInfoKHX& setPDeviceIndices( const uint32_t* pDeviceIndices_ )\n    {\n      pDeviceIndices = pDeviceIndices_;\n      return *this;\n    }\n\n    operator const VkBindBufferMemoryInfoKHX&() const\n    {\n      return *reinterpret_cast<const VkBindBufferMemoryInfoKHX*>(this);\n    }\n\n    bool operator==( BindBufferMemoryInfoKHX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( buffer == rhs.buffer )\n          && ( memory == rhs.memory )\n          && ( memoryOffset == rhs.memoryOffset )\n          && ( deviceIndexCount == rhs.deviceIndexCount )\n          && ( pDeviceIndices == rhs.pDeviceIndices );\n    }\n\n    bool operator!=( BindBufferMemoryInfoKHX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    Buffer buffer;\n    DeviceMemory memory;\n    DeviceSize memoryOffset;\n    uint32_t deviceIndexCount;\n    const uint32_t* pDeviceIndices;\n  };\n  static_assert( sizeof( BindBufferMemoryInfoKHX ) == sizeof( VkBindBufferMemoryInfoKHX ), \"struct and wrapper have different size!\" );\n\n  struct BindImageMemoryInfoKHX\n  {\n    BindImageMemoryInfoKHX( Image image_ = Image(), DeviceMemory memory_ = DeviceMemory(), DeviceSize memoryOffset_ = 0, uint32_t deviceIndexCount_ = 0, const uint32_t* pDeviceIndices_ = nullptr, uint32_t SFRRectCount_ = 0, const Rect2D* pSFRRects_ = nullptr )\n      : sType( StructureType::eBindImageMemoryInfoKHX )\n      , pNext( nullptr )\n      , image( image_ )\n      , memory( memory_ )\n      , memoryOffset( memoryOffset_ )\n      , deviceIndexCount( deviceIndexCount_ )\n      , pDeviceIndices( pDeviceIndices_ )\n      , SFRRectCount( SFRRectCount_ )\n      , pSFRRects( pSFRRects_ )\n    {\n    }\n\n    BindImageMemoryInfoKHX( VkBindImageMemoryInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(BindImageMemoryInfoKHX) );\n    }\n\n    BindImageMemoryInfoKHX& operator=( VkBindImageMemoryInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(BindImageMemoryInfoKHX) );\n      return *this;\n    }\n\n    BindImageMemoryInfoKHX& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    BindImageMemoryInfoKHX& setImage( Image image_ )\n    {\n      image = image_;\n      return *this;\n    }\n\n    BindImageMemoryInfoKHX& setMemory( DeviceMemory memory_ )\n    {\n      memory = memory_;\n      return *this;\n    }\n\n    BindImageMemoryInfoKHX& setMemoryOffset( DeviceSize memoryOffset_ )\n    {\n      memoryOffset = memoryOffset_;\n      return *this;\n    }\n\n    BindImageMemoryInfoKHX& setDeviceIndexCount( uint32_t deviceIndexCount_ )\n    {\n      deviceIndexCount = deviceIndexCount_;\n      return *this;\n    }\n\n    BindImageMemoryInfoKHX& setPDeviceIndices( const uint32_t* pDeviceIndices_ )\n    {\n      pDeviceIndices = pDeviceIndices_;\n      return *this;\n    }\n\n    BindImageMemoryInfoKHX& setSFRRectCount( uint32_t SFRRectCount_ )\n    {\n      SFRRectCount = SFRRectCount_;\n      return *this;\n    }\n\n    BindImageMemoryInfoKHX& setPSFRRects( const Rect2D* pSFRRects_ )\n    {\n      pSFRRects = pSFRRects_;\n      return *this;\n    }\n\n    operator const VkBindImageMemoryInfoKHX&() const\n    {\n      return *reinterpret_cast<const VkBindImageMemoryInfoKHX*>(this);\n    }\n\n    bool operator==( BindImageMemoryInfoKHX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( image == rhs.image )\n          && ( memory == rhs.memory )\n          && ( memoryOffset == rhs.memoryOffset )\n          && ( deviceIndexCount == rhs.deviceIndexCount )\n          && ( pDeviceIndices == rhs.pDeviceIndices )\n          && ( SFRRectCount == rhs.SFRRectCount )\n          && ( pSFRRects == rhs.pSFRRects );\n    }\n\n    bool operator!=( BindImageMemoryInfoKHX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    Image image;\n    DeviceMemory memory;\n    DeviceSize memoryOffset;\n    uint32_t deviceIndexCount;\n    const uint32_t* pDeviceIndices;\n    uint32_t SFRRectCount;\n    const Rect2D* pSFRRects;\n  };\n  static_assert( sizeof( BindImageMemoryInfoKHX ) == sizeof( VkBindImageMemoryInfoKHX ), \"struct and wrapper have different size!\" );\n\n  struct DeviceGroupRenderPassBeginInfoKHX\n  {\n    DeviceGroupRenderPassBeginInfoKHX( uint32_t deviceMask_ = 0, uint32_t deviceRenderAreaCount_ = 0, const Rect2D* pDeviceRenderAreas_ = nullptr )\n      : sType( StructureType::eDeviceGroupRenderPassBeginInfoKHX )\n      , pNext( nullptr )\n      , deviceMask( deviceMask_ )\n      , deviceRenderAreaCount( deviceRenderAreaCount_ )\n      , pDeviceRenderAreas( pDeviceRenderAreas_ )\n    {\n    }\n\n    DeviceGroupRenderPassBeginInfoKHX( VkDeviceGroupRenderPassBeginInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DeviceGroupRenderPassBeginInfoKHX) );\n    }\n\n    DeviceGroupRenderPassBeginInfoKHX& operator=( VkDeviceGroupRenderPassBeginInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DeviceGroupRenderPassBeginInfoKHX) );\n      return *this;\n    }\n\n    DeviceGroupRenderPassBeginInfoKHX& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    DeviceGroupRenderPassBeginInfoKHX& setDeviceMask( uint32_t deviceMask_ )\n    {\n      deviceMask = deviceMask_;\n      return *this;\n    }\n\n    DeviceGroupRenderPassBeginInfoKHX& setDeviceRenderAreaCount( uint32_t deviceRenderAreaCount_ )\n    {\n      deviceRenderAreaCount = deviceRenderAreaCount_;\n      return *this;\n    }\n\n    DeviceGroupRenderPassBeginInfoKHX& setPDeviceRenderAreas( const Rect2D* pDeviceRenderAreas_ )\n    {\n      pDeviceRenderAreas = pDeviceRenderAreas_;\n      return *this;\n    }\n\n    operator const VkDeviceGroupRenderPassBeginInfoKHX&() const\n    {\n      return *reinterpret_cast<const VkDeviceGroupRenderPassBeginInfoKHX*>(this);\n    }\n\n    bool operator==( DeviceGroupRenderPassBeginInfoKHX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( deviceMask == rhs.deviceMask )\n          && ( deviceRenderAreaCount == rhs.deviceRenderAreaCount )\n          && ( pDeviceRenderAreas == rhs.pDeviceRenderAreas );\n    }\n\n    bool operator!=( DeviceGroupRenderPassBeginInfoKHX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    uint32_t deviceMask;\n    uint32_t deviceRenderAreaCount;\n    const Rect2D* pDeviceRenderAreas;\n  };\n  static_assert( sizeof( DeviceGroupRenderPassBeginInfoKHX ) == sizeof( VkDeviceGroupRenderPassBeginInfoKHX ), \"struct and wrapper have different size!\" );\n\n  struct DeviceGroupCommandBufferBeginInfoKHX\n  {\n    DeviceGroupCommandBufferBeginInfoKHX( uint32_t deviceMask_ = 0 )\n      : sType( StructureType::eDeviceGroupCommandBufferBeginInfoKHX )\n      , pNext( nullptr )\n      , deviceMask( deviceMask_ )\n    {\n    }\n\n    DeviceGroupCommandBufferBeginInfoKHX( VkDeviceGroupCommandBufferBeginInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DeviceGroupCommandBufferBeginInfoKHX) );\n    }\n\n    DeviceGroupCommandBufferBeginInfoKHX& operator=( VkDeviceGroupCommandBufferBeginInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DeviceGroupCommandBufferBeginInfoKHX) );\n      return *this;\n    }\n\n    DeviceGroupCommandBufferBeginInfoKHX& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    DeviceGroupCommandBufferBeginInfoKHX& setDeviceMask( uint32_t deviceMask_ )\n    {\n      deviceMask = deviceMask_;\n      return *this;\n    }\n\n    operator const VkDeviceGroupCommandBufferBeginInfoKHX&() const\n    {\n      return *reinterpret_cast<const VkDeviceGroupCommandBufferBeginInfoKHX*>(this);\n    }\n\n    bool operator==( DeviceGroupCommandBufferBeginInfoKHX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( deviceMask == rhs.deviceMask );\n    }\n\n    bool operator!=( DeviceGroupCommandBufferBeginInfoKHX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    uint32_t deviceMask;\n  };\n  static_assert( sizeof( DeviceGroupCommandBufferBeginInfoKHX ) == sizeof( VkDeviceGroupCommandBufferBeginInfoKHX ), \"struct and wrapper have different size!\" );\n\n  struct DeviceGroupSubmitInfoKHX\n  {\n    DeviceGroupSubmitInfoKHX( uint32_t waitSemaphoreCount_ = 0, const uint32_t* pWaitSemaphoreDeviceIndices_ = nullptr, uint32_t commandBufferCount_ = 0, const uint32_t* pCommandBufferDeviceMasks_ = nullptr, uint32_t signalSemaphoreCount_ = 0, const uint32_t* pSignalSemaphoreDeviceIndices_ = nullptr )\n      : sType( StructureType::eDeviceGroupSubmitInfoKHX )\n      , pNext( nullptr )\n      , waitSemaphoreCount( waitSemaphoreCount_ )\n      , pWaitSemaphoreDeviceIndices( pWaitSemaphoreDeviceIndices_ )\n      , commandBufferCount( commandBufferCount_ )\n      , pCommandBufferDeviceMasks( pCommandBufferDeviceMasks_ )\n      , signalSemaphoreCount( signalSemaphoreCount_ )\n      , pSignalSemaphoreDeviceIndices( pSignalSemaphoreDeviceIndices_ )\n    {\n    }\n\n    DeviceGroupSubmitInfoKHX( VkDeviceGroupSubmitInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DeviceGroupSubmitInfoKHX) );\n    }\n\n    DeviceGroupSubmitInfoKHX& operator=( VkDeviceGroupSubmitInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DeviceGroupSubmitInfoKHX) );\n      return *this;\n    }\n\n    DeviceGroupSubmitInfoKHX& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    DeviceGroupSubmitInfoKHX& setWaitSemaphoreCount( uint32_t waitSemaphoreCount_ )\n    {\n      waitSemaphoreCount = waitSemaphoreCount_;\n      return *this;\n    }\n\n    DeviceGroupSubmitInfoKHX& setPWaitSemaphoreDeviceIndices( const uint32_t* pWaitSemaphoreDeviceIndices_ )\n    {\n      pWaitSemaphoreDeviceIndices = pWaitSemaphoreDeviceIndices_;\n      return *this;\n    }\n\n    DeviceGroupSubmitInfoKHX& setCommandBufferCount( uint32_t commandBufferCount_ )\n    {\n      commandBufferCount = commandBufferCount_;\n      return *this;\n    }\n\n    DeviceGroupSubmitInfoKHX& setPCommandBufferDeviceMasks( const uint32_t* pCommandBufferDeviceMasks_ )\n    {\n      pCommandBufferDeviceMasks = pCommandBufferDeviceMasks_;\n      return *this;\n    }\n\n    DeviceGroupSubmitInfoKHX& setSignalSemaphoreCount( uint32_t signalSemaphoreCount_ )\n    {\n      signalSemaphoreCount = signalSemaphoreCount_;\n      return *this;\n    }\n\n    DeviceGroupSubmitInfoKHX& setPSignalSemaphoreDeviceIndices( const uint32_t* pSignalSemaphoreDeviceIndices_ )\n    {\n      pSignalSemaphoreDeviceIndices = pSignalSemaphoreDeviceIndices_;\n      return *this;\n    }\n\n    operator const VkDeviceGroupSubmitInfoKHX&() const\n    {\n      return *reinterpret_cast<const VkDeviceGroupSubmitInfoKHX*>(this);\n    }\n\n    bool operator==( DeviceGroupSubmitInfoKHX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( waitSemaphoreCount == rhs.waitSemaphoreCount )\n          && ( pWaitSemaphoreDeviceIndices == rhs.pWaitSemaphoreDeviceIndices )\n          && ( commandBufferCount == rhs.commandBufferCount )\n          && ( pCommandBufferDeviceMasks == rhs.pCommandBufferDeviceMasks )\n          && ( signalSemaphoreCount == rhs.signalSemaphoreCount )\n          && ( pSignalSemaphoreDeviceIndices == rhs.pSignalSemaphoreDeviceIndices );\n    }\n\n    bool operator!=( DeviceGroupSubmitInfoKHX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    uint32_t waitSemaphoreCount;\n    const uint32_t* pWaitSemaphoreDeviceIndices;\n    uint32_t commandBufferCount;\n    const uint32_t* pCommandBufferDeviceMasks;\n    uint32_t signalSemaphoreCount;\n    const uint32_t* pSignalSemaphoreDeviceIndices;\n  };\n  static_assert( sizeof( DeviceGroupSubmitInfoKHX ) == sizeof( VkDeviceGroupSubmitInfoKHX ), \"struct and wrapper have different size!\" );\n\n  struct DeviceGroupBindSparseInfoKHX\n  {\n    DeviceGroupBindSparseInfoKHX( uint32_t resourceDeviceIndex_ = 0, uint32_t memoryDeviceIndex_ = 0 )\n      : sType( StructureType::eDeviceGroupBindSparseInfoKHX )\n      , pNext( nullptr )\n      , resourceDeviceIndex( resourceDeviceIndex_ )\n      , memoryDeviceIndex( memoryDeviceIndex_ )\n    {\n    }\n\n    DeviceGroupBindSparseInfoKHX( VkDeviceGroupBindSparseInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DeviceGroupBindSparseInfoKHX) );\n    }\n\n    DeviceGroupBindSparseInfoKHX& operator=( VkDeviceGroupBindSparseInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DeviceGroupBindSparseInfoKHX) );\n      return *this;\n    }\n\n    DeviceGroupBindSparseInfoKHX& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    DeviceGroupBindSparseInfoKHX& setResourceDeviceIndex( uint32_t resourceDeviceIndex_ )\n    {\n      resourceDeviceIndex = resourceDeviceIndex_;\n      return *this;\n    }\n\n    DeviceGroupBindSparseInfoKHX& setMemoryDeviceIndex( uint32_t memoryDeviceIndex_ )\n    {\n      memoryDeviceIndex = memoryDeviceIndex_;\n      return *this;\n    }\n\n    operator const VkDeviceGroupBindSparseInfoKHX&() const\n    {\n      return *reinterpret_cast<const VkDeviceGroupBindSparseInfoKHX*>(this);\n    }\n\n    bool operator==( DeviceGroupBindSparseInfoKHX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( resourceDeviceIndex == rhs.resourceDeviceIndex )\n          && ( memoryDeviceIndex == rhs.memoryDeviceIndex );\n    }\n\n    bool operator!=( DeviceGroupBindSparseInfoKHX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    uint32_t resourceDeviceIndex;\n    uint32_t memoryDeviceIndex;\n  };\n  static_assert( sizeof( DeviceGroupBindSparseInfoKHX ) == sizeof( VkDeviceGroupBindSparseInfoKHX ), \"struct and wrapper have different size!\" );\n\n  struct ImageSwapchainCreateInfoKHX\n  {\n    ImageSwapchainCreateInfoKHX( SwapchainKHR swapchain_ = SwapchainKHR() )\n      : sType( StructureType::eImageSwapchainCreateInfoKHX )\n      , pNext( nullptr )\n      , swapchain( swapchain_ )\n    {\n    }\n\n    ImageSwapchainCreateInfoKHX( VkImageSwapchainCreateInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ImageSwapchainCreateInfoKHX) );\n    }\n\n    ImageSwapchainCreateInfoKHX& operator=( VkImageSwapchainCreateInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ImageSwapchainCreateInfoKHX) );\n      return *this;\n    }\n\n    ImageSwapchainCreateInfoKHX& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    ImageSwapchainCreateInfoKHX& setSwapchain( SwapchainKHR swapchain_ )\n    {\n      swapchain = swapchain_;\n      return *this;\n    }\n\n    operator const VkImageSwapchainCreateInfoKHX&() const\n    {\n      return *reinterpret_cast<const VkImageSwapchainCreateInfoKHX*>(this);\n    }\n\n    bool operator==( ImageSwapchainCreateInfoKHX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( swapchain == rhs.swapchain );\n    }\n\n    bool operator!=( ImageSwapchainCreateInfoKHX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    SwapchainKHR swapchain;\n  };\n  static_assert( sizeof( ImageSwapchainCreateInfoKHX ) == sizeof( VkImageSwapchainCreateInfoKHX ), \"struct and wrapper have different size!\" );\n\n  struct BindImageMemorySwapchainInfoKHX\n  {\n    BindImageMemorySwapchainInfoKHX( SwapchainKHR swapchain_ = SwapchainKHR(), uint32_t imageIndex_ = 0 )\n      : sType( StructureType::eBindImageMemorySwapchainInfoKHX )\n      , pNext( nullptr )\n      , swapchain( swapchain_ )\n      , imageIndex( imageIndex_ )\n    {\n    }\n\n    BindImageMemorySwapchainInfoKHX( VkBindImageMemorySwapchainInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(BindImageMemorySwapchainInfoKHX) );\n    }\n\n    BindImageMemorySwapchainInfoKHX& operator=( VkBindImageMemorySwapchainInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(BindImageMemorySwapchainInfoKHX) );\n      return *this;\n    }\n\n    BindImageMemorySwapchainInfoKHX& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    BindImageMemorySwapchainInfoKHX& setSwapchain( SwapchainKHR swapchain_ )\n    {\n      swapchain = swapchain_;\n      return *this;\n    }\n\n    BindImageMemorySwapchainInfoKHX& setImageIndex( uint32_t imageIndex_ )\n    {\n      imageIndex = imageIndex_;\n      return *this;\n    }\n\n    operator const VkBindImageMemorySwapchainInfoKHX&() const\n    {\n      return *reinterpret_cast<const VkBindImageMemorySwapchainInfoKHX*>(this);\n    }\n\n    bool operator==( BindImageMemorySwapchainInfoKHX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( swapchain == rhs.swapchain )\n          && ( imageIndex == rhs.imageIndex );\n    }\n\n    bool operator!=( BindImageMemorySwapchainInfoKHX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    SwapchainKHR swapchain;\n    uint32_t imageIndex;\n  };\n  static_assert( sizeof( BindImageMemorySwapchainInfoKHX ) == sizeof( VkBindImageMemorySwapchainInfoKHX ), \"struct and wrapper have different size!\" );\n\n  struct AcquireNextImageInfoKHX\n  {\n    AcquireNextImageInfoKHX( SwapchainKHR swapchain_ = SwapchainKHR(), uint64_t timeout_ = 0, Semaphore semaphore_ = Semaphore(), Fence fence_ = Fence(), uint32_t deviceMask_ = 0 )\n      : sType( StructureType::eAcquireNextImageInfoKHX )\n      , pNext( nullptr )\n      , swapchain( swapchain_ )\n      , timeout( timeout_ )\n      , semaphore( semaphore_ )\n      , fence( fence_ )\n      , deviceMask( deviceMask_ )\n    {\n    }\n\n    AcquireNextImageInfoKHX( VkAcquireNextImageInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(AcquireNextImageInfoKHX) );\n    }\n\n    AcquireNextImageInfoKHX& operator=( VkAcquireNextImageInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(AcquireNextImageInfoKHX) );\n      return *this;\n    }\n\n    AcquireNextImageInfoKHX& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    AcquireNextImageInfoKHX& setSwapchain( SwapchainKHR swapchain_ )\n    {\n      swapchain = swapchain_;\n      return *this;\n    }\n\n    AcquireNextImageInfoKHX& setTimeout( uint64_t timeout_ )\n    {\n      timeout = timeout_;\n      return *this;\n    }\n\n    AcquireNextImageInfoKHX& setSemaphore( Semaphore semaphore_ )\n    {\n      semaphore = semaphore_;\n      return *this;\n    }\n\n    AcquireNextImageInfoKHX& setFence( Fence fence_ )\n    {\n      fence = fence_;\n      return *this;\n    }\n\n    AcquireNextImageInfoKHX& setDeviceMask( uint32_t deviceMask_ )\n    {\n      deviceMask = deviceMask_;\n      return *this;\n    }\n\n    operator const VkAcquireNextImageInfoKHX&() const\n    {\n      return *reinterpret_cast<const VkAcquireNextImageInfoKHX*>(this);\n    }\n\n    bool operator==( AcquireNextImageInfoKHX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( swapchain == rhs.swapchain )\n          && ( timeout == rhs.timeout )\n          && ( semaphore == rhs.semaphore )\n          && ( fence == rhs.fence )\n          && ( deviceMask == rhs.deviceMask );\n    }\n\n    bool operator!=( AcquireNextImageInfoKHX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    SwapchainKHR swapchain;\n    uint64_t timeout;\n    Semaphore semaphore;\n    Fence fence;\n    uint32_t deviceMask;\n  };\n  static_assert( sizeof( AcquireNextImageInfoKHX ) == sizeof( VkAcquireNextImageInfoKHX ), \"struct and wrapper have different size!\" );\n\n  struct HdrMetadataEXT\n  {\n    HdrMetadataEXT( XYColorEXT displayPrimaryRed_ = XYColorEXT(), XYColorEXT displayPrimaryGreen_ = XYColorEXT(), XYColorEXT displayPrimaryBlue_ = XYColorEXT(), XYColorEXT whitePoint_ = XYColorEXT(), float maxLuminance_ = 0, float minLuminance_ = 0, float maxContentLightLevel_ = 0, float maxFrameAverageLightLevel_ = 0 )\n      : sType( StructureType::eHdrMetadataEXT )\n      , pNext( nullptr )\n      , displayPrimaryRed( displayPrimaryRed_ )\n      , displayPrimaryGreen( displayPrimaryGreen_ )\n      , displayPrimaryBlue( displayPrimaryBlue_ )\n      , whitePoint( whitePoint_ )\n      , maxLuminance( maxLuminance_ )\n      , minLuminance( minLuminance_ )\n      , maxContentLightLevel( maxContentLightLevel_ )\n      , maxFrameAverageLightLevel( maxFrameAverageLightLevel_ )\n    {\n    }\n\n    HdrMetadataEXT( VkHdrMetadataEXT const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(HdrMetadataEXT) );\n    }\n\n    HdrMetadataEXT& operator=( VkHdrMetadataEXT const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(HdrMetadataEXT) );\n      return *this;\n    }\n\n    HdrMetadataEXT& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    HdrMetadataEXT& setDisplayPrimaryRed( XYColorEXT displayPrimaryRed_ )\n    {\n      displayPrimaryRed = displayPrimaryRed_;\n      return *this;\n    }\n\n    HdrMetadataEXT& setDisplayPrimaryGreen( XYColorEXT displayPrimaryGreen_ )\n    {\n      displayPrimaryGreen = displayPrimaryGreen_;\n      return *this;\n    }\n\n    HdrMetadataEXT& setDisplayPrimaryBlue( XYColorEXT displayPrimaryBlue_ )\n    {\n      displayPrimaryBlue = displayPrimaryBlue_;\n      return *this;\n    }\n\n    HdrMetadataEXT& setWhitePoint( XYColorEXT whitePoint_ )\n    {\n      whitePoint = whitePoint_;\n      return *this;\n    }\n\n    HdrMetadataEXT& setMaxLuminance( float maxLuminance_ )\n    {\n      maxLuminance = maxLuminance_;\n      return *this;\n    }\n\n    HdrMetadataEXT& setMinLuminance( float minLuminance_ )\n    {\n      minLuminance = minLuminance_;\n      return *this;\n    }\n\n    HdrMetadataEXT& setMaxContentLightLevel( float maxContentLightLevel_ )\n    {\n      maxContentLightLevel = maxContentLightLevel_;\n      return *this;\n    }\n\n    HdrMetadataEXT& setMaxFrameAverageLightLevel( float maxFrameAverageLightLevel_ )\n    {\n      maxFrameAverageLightLevel = maxFrameAverageLightLevel_;\n      return *this;\n    }\n\n    operator const VkHdrMetadataEXT&() const\n    {\n      return *reinterpret_cast<const VkHdrMetadataEXT*>(this);\n    }\n\n    bool operator==( HdrMetadataEXT const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( displayPrimaryRed == rhs.displayPrimaryRed )\n          && ( displayPrimaryGreen == rhs.displayPrimaryGreen )\n          && ( displayPrimaryBlue == rhs.displayPrimaryBlue )\n          && ( whitePoint == rhs.whitePoint )\n          && ( maxLuminance == rhs.maxLuminance )\n          && ( minLuminance == rhs.minLuminance )\n          && ( maxContentLightLevel == rhs.maxContentLightLevel )\n          && ( maxFrameAverageLightLevel == rhs.maxFrameAverageLightLevel );\n    }\n\n    bool operator!=( HdrMetadataEXT const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    XYColorEXT displayPrimaryRed;\n    XYColorEXT displayPrimaryGreen;\n    XYColorEXT displayPrimaryBlue;\n    XYColorEXT whitePoint;\n    float maxLuminance;\n    float minLuminance;\n    float maxContentLightLevel;\n    float maxFrameAverageLightLevel;\n  };\n  static_assert( sizeof( HdrMetadataEXT ) == sizeof( VkHdrMetadataEXT ), \"struct and wrapper have different size!\" );\n\n  struct PresentTimesInfoGOOGLE\n  {\n    PresentTimesInfoGOOGLE( uint32_t swapchainCount_ = 0, const PresentTimeGOOGLE* pTimes_ = nullptr )\n      : sType( StructureType::ePresentTimesInfoGOOGLE )\n      , pNext( nullptr )\n      , swapchainCount( swapchainCount_ )\n      , pTimes( pTimes_ )\n    {\n    }\n\n    PresentTimesInfoGOOGLE( VkPresentTimesInfoGOOGLE const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PresentTimesInfoGOOGLE) );\n    }\n\n    PresentTimesInfoGOOGLE& operator=( VkPresentTimesInfoGOOGLE const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PresentTimesInfoGOOGLE) );\n      return *this;\n    }\n\n    PresentTimesInfoGOOGLE& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    PresentTimesInfoGOOGLE& setSwapchainCount( uint32_t swapchainCount_ )\n    {\n      swapchainCount = swapchainCount_;\n      return *this;\n    }\n\n    PresentTimesInfoGOOGLE& setPTimes( const PresentTimeGOOGLE* pTimes_ )\n    {\n      pTimes = pTimes_;\n      return *this;\n    }\n\n    operator const VkPresentTimesInfoGOOGLE&() const\n    {\n      return *reinterpret_cast<const VkPresentTimesInfoGOOGLE*>(this);\n    }\n\n    bool operator==( PresentTimesInfoGOOGLE const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( swapchainCount == rhs.swapchainCount )\n          && ( pTimes == rhs.pTimes );\n    }\n\n    bool operator!=( PresentTimesInfoGOOGLE const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    uint32_t swapchainCount;\n    const PresentTimeGOOGLE* pTimes;\n  };\n  static_assert( sizeof( PresentTimesInfoGOOGLE ) == sizeof( VkPresentTimesInfoGOOGLE ), \"struct and wrapper have different size!\" );\n\n#ifdef VK_USE_PLATFORM_IOS_MVK\n  struct IOSSurfaceCreateInfoMVK\n  {\n    IOSSurfaceCreateInfoMVK( IOSSurfaceCreateFlagsMVK flags_ = IOSSurfaceCreateFlagsMVK(), const void* pView_ = nullptr )\n      : sType( StructureType::eIOSSurfaceCreateInfoMVK )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , pView( pView_ )\n    {\n    }\n\n    IOSSurfaceCreateInfoMVK( VkIOSSurfaceCreateInfoMVK const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(IOSSurfaceCreateInfoMVK) );\n    }\n\n    IOSSurfaceCreateInfoMVK& operator=( VkIOSSurfaceCreateInfoMVK const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(IOSSurfaceCreateInfoMVK) );\n      return *this;\n    }\n\n    IOSSurfaceCreateInfoMVK& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    IOSSurfaceCreateInfoMVK& setFlags( IOSSurfaceCreateFlagsMVK flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    IOSSurfaceCreateInfoMVK& setPView( const void* pView_ )\n    {\n      pView = pView_;\n      return *this;\n    }\n\n    operator const VkIOSSurfaceCreateInfoMVK&() const\n    {\n      return *reinterpret_cast<const VkIOSSurfaceCreateInfoMVK*>(this);\n    }\n\n    bool operator==( IOSSurfaceCreateInfoMVK const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( pView == rhs.pView );\n    }\n\n    bool operator!=( IOSSurfaceCreateInfoMVK const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    IOSSurfaceCreateFlagsMVK flags;\n    const void* pView;\n  };\n  static_assert( sizeof( IOSSurfaceCreateInfoMVK ) == sizeof( VkIOSSurfaceCreateInfoMVK ), \"struct and wrapper have different size!\" );\n#endif /*VK_USE_PLATFORM_IOS_MVK*/\n\n#ifdef VK_USE_PLATFORM_MACOS_MVK\n  struct MacOSSurfaceCreateInfoMVK\n  {\n    MacOSSurfaceCreateInfoMVK( MacOSSurfaceCreateFlagsMVK flags_ = MacOSSurfaceCreateFlagsMVK(), const void* pView_ = nullptr )\n      : sType( StructureType::eMacOSSurfaceCreateInfoMVK )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , pView( pView_ )\n    {\n    }\n\n    MacOSSurfaceCreateInfoMVK( VkMacOSSurfaceCreateInfoMVK const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(MacOSSurfaceCreateInfoMVK) );\n    }\n\n    MacOSSurfaceCreateInfoMVK& operator=( VkMacOSSurfaceCreateInfoMVK const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(MacOSSurfaceCreateInfoMVK) );\n      return *this;\n    }\n\n    MacOSSurfaceCreateInfoMVK& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    MacOSSurfaceCreateInfoMVK& setFlags( MacOSSurfaceCreateFlagsMVK flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    MacOSSurfaceCreateInfoMVK& setPView( const void* pView_ )\n    {\n      pView = pView_;\n      return *this;\n    }\n\n    operator const VkMacOSSurfaceCreateInfoMVK&() const\n    {\n      return *reinterpret_cast<const VkMacOSSurfaceCreateInfoMVK*>(this);\n    }\n\n    bool operator==( MacOSSurfaceCreateInfoMVK const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( pView == rhs.pView );\n    }\n\n    bool operator!=( MacOSSurfaceCreateInfoMVK const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    MacOSSurfaceCreateFlagsMVK flags;\n    const void* pView;\n  };\n  static_assert( sizeof( MacOSSurfaceCreateInfoMVK ) == sizeof( VkMacOSSurfaceCreateInfoMVK ), \"struct and wrapper have different size!\" );\n#endif /*VK_USE_PLATFORM_MACOS_MVK*/\n\n  struct PipelineViewportWScalingStateCreateInfoNV\n  {\n    PipelineViewportWScalingStateCreateInfoNV( Bool32 viewportWScalingEnable_ = 0, uint32_t viewportCount_ = 0, const ViewportWScalingNV* pViewportWScalings_ = nullptr )\n      : sType( StructureType::ePipelineViewportWScalingStateCreateInfoNV )\n      , pNext( nullptr )\n      , viewportWScalingEnable( viewportWScalingEnable_ )\n      , viewportCount( viewportCount_ )\n      , pViewportWScalings( pViewportWScalings_ )\n    {\n    }\n\n    PipelineViewportWScalingStateCreateInfoNV( VkPipelineViewportWScalingStateCreateInfoNV const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PipelineViewportWScalingStateCreateInfoNV) );\n    }\n\n    PipelineViewportWScalingStateCreateInfoNV& operator=( VkPipelineViewportWScalingStateCreateInfoNV const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PipelineViewportWScalingStateCreateInfoNV) );\n      return *this;\n    }\n\n    PipelineViewportWScalingStateCreateInfoNV& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    PipelineViewportWScalingStateCreateInfoNV& setViewportWScalingEnable( Bool32 viewportWScalingEnable_ )\n    {\n      viewportWScalingEnable = viewportWScalingEnable_;\n      return *this;\n    }\n\n    PipelineViewportWScalingStateCreateInfoNV& setViewportCount( uint32_t viewportCount_ )\n    {\n      viewportCount = viewportCount_;\n      return *this;\n    }\n\n    PipelineViewportWScalingStateCreateInfoNV& setPViewportWScalings( const ViewportWScalingNV* pViewportWScalings_ )\n    {\n      pViewportWScalings = pViewportWScalings_;\n      return *this;\n    }\n\n    operator const VkPipelineViewportWScalingStateCreateInfoNV&() const\n    {\n      return *reinterpret_cast<const VkPipelineViewportWScalingStateCreateInfoNV*>(this);\n    }\n\n    bool operator==( PipelineViewportWScalingStateCreateInfoNV const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( viewportWScalingEnable == rhs.viewportWScalingEnable )\n          && ( viewportCount == rhs.viewportCount )\n          && ( pViewportWScalings == rhs.pViewportWScalings );\n    }\n\n    bool operator!=( PipelineViewportWScalingStateCreateInfoNV const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    Bool32 viewportWScalingEnable;\n    uint32_t viewportCount;\n    const ViewportWScalingNV* pViewportWScalings;\n  };\n  static_assert( sizeof( PipelineViewportWScalingStateCreateInfoNV ) == sizeof( VkPipelineViewportWScalingStateCreateInfoNV ), \"struct and wrapper have different size!\" );\n\n  struct PhysicalDeviceDiscardRectanglePropertiesEXT\n  {\n    PhysicalDeviceDiscardRectanglePropertiesEXT( uint32_t maxDiscardRectangles_ = 0 )\n      : sType( StructureType::ePhysicalDeviceDiscardRectanglePropertiesEXT )\n      , pNext( nullptr )\n      , maxDiscardRectangles( maxDiscardRectangles_ )\n    {\n    }\n\n    PhysicalDeviceDiscardRectanglePropertiesEXT( VkPhysicalDeviceDiscardRectanglePropertiesEXT const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PhysicalDeviceDiscardRectanglePropertiesEXT) );\n    }\n\n    PhysicalDeviceDiscardRectanglePropertiesEXT& operator=( VkPhysicalDeviceDiscardRectanglePropertiesEXT const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PhysicalDeviceDiscardRectanglePropertiesEXT) );\n      return *this;\n    }\n\n    PhysicalDeviceDiscardRectanglePropertiesEXT& setPNext( void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    PhysicalDeviceDiscardRectanglePropertiesEXT& setMaxDiscardRectangles( uint32_t maxDiscardRectangles_ )\n    {\n      maxDiscardRectangles = maxDiscardRectangles_;\n      return *this;\n    }\n\n    operator const VkPhysicalDeviceDiscardRectanglePropertiesEXT&() const\n    {\n      return *reinterpret_cast<const VkPhysicalDeviceDiscardRectanglePropertiesEXT*>(this);\n    }\n\n    bool operator==( PhysicalDeviceDiscardRectanglePropertiesEXT const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( maxDiscardRectangles == rhs.maxDiscardRectangles );\n    }\n\n    bool operator!=( PhysicalDeviceDiscardRectanglePropertiesEXT const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    void* pNext;\n    uint32_t maxDiscardRectangles;\n  };\n  static_assert( sizeof( PhysicalDeviceDiscardRectanglePropertiesEXT ) == sizeof( VkPhysicalDeviceDiscardRectanglePropertiesEXT ), \"struct and wrapper have different size!\" );\n\n  struct PhysicalDeviceMultiviewPerViewAttributesPropertiesNVX\n  {\n    operator const VkPhysicalDeviceMultiviewPerViewAttributesPropertiesNVX&() const\n    {\n      return *reinterpret_cast<const VkPhysicalDeviceMultiviewPerViewAttributesPropertiesNVX*>(this);\n    }\n\n    bool operator==( PhysicalDeviceMultiviewPerViewAttributesPropertiesNVX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( perViewPositionAllComponents == rhs.perViewPositionAllComponents );\n    }\n\n    bool operator!=( PhysicalDeviceMultiviewPerViewAttributesPropertiesNVX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    void* pNext;\n    Bool32 perViewPositionAllComponents;\n  };\n  static_assert( sizeof( PhysicalDeviceMultiviewPerViewAttributesPropertiesNVX ) == sizeof( VkPhysicalDeviceMultiviewPerViewAttributesPropertiesNVX ), \"struct and wrapper have different size!\" );\n\n  struct PhysicalDeviceSurfaceInfo2KHR\n  {\n    PhysicalDeviceSurfaceInfo2KHR( SurfaceKHR surface_ = SurfaceKHR() )\n      : sType( StructureType::ePhysicalDeviceSurfaceInfo2KHR )\n      , pNext( nullptr )\n      , surface( surface_ )\n    {\n    }\n\n    PhysicalDeviceSurfaceInfo2KHR( VkPhysicalDeviceSurfaceInfo2KHR const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PhysicalDeviceSurfaceInfo2KHR) );\n    }\n\n    PhysicalDeviceSurfaceInfo2KHR& operator=( VkPhysicalDeviceSurfaceInfo2KHR const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PhysicalDeviceSurfaceInfo2KHR) );\n      return *this;\n    }\n\n    PhysicalDeviceSurfaceInfo2KHR& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    PhysicalDeviceSurfaceInfo2KHR& setSurface( SurfaceKHR surface_ )\n    {\n      surface = surface_;\n      return *this;\n    }\n\n    operator const VkPhysicalDeviceSurfaceInfo2KHR&() const\n    {\n      return *reinterpret_cast<const VkPhysicalDeviceSurfaceInfo2KHR*>(this);\n    }\n\n    bool operator==( PhysicalDeviceSurfaceInfo2KHR const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( surface == rhs.surface );\n    }\n\n    bool operator!=( PhysicalDeviceSurfaceInfo2KHR const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    SurfaceKHR surface;\n  };\n  static_assert( sizeof( PhysicalDeviceSurfaceInfo2KHR ) == sizeof( VkPhysicalDeviceSurfaceInfo2KHR ), \"struct and wrapper have different size!\" );\n\n  enum class SubpassContents\n  {\n    eInline = VK_SUBPASS_CONTENTS_INLINE,\n    eSecondaryCommandBuffers = VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS\n  };\n\n  struct PresentInfoKHR\n  {\n    PresentInfoKHR( uint32_t waitSemaphoreCount_ = 0, const Semaphore* pWaitSemaphores_ = nullptr, uint32_t swapchainCount_ = 0, const SwapchainKHR* pSwapchains_ = nullptr, const uint32_t* pImageIndices_ = nullptr, Result* pResults_ = nullptr )\n      : sType( StructureType::ePresentInfoKHR )\n      , pNext( nullptr )\n      , waitSemaphoreCount( waitSemaphoreCount_ )\n      , pWaitSemaphores( pWaitSemaphores_ )\n      , swapchainCount( swapchainCount_ )\n      , pSwapchains( pSwapchains_ )\n      , pImageIndices( pImageIndices_ )\n      , pResults( pResults_ )\n    {\n    }\n\n    PresentInfoKHR( VkPresentInfoKHR const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PresentInfoKHR) );\n    }\n\n    PresentInfoKHR& operator=( VkPresentInfoKHR const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PresentInfoKHR) );\n      return *this;\n    }\n\n    PresentInfoKHR& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    PresentInfoKHR& setWaitSemaphoreCount( uint32_t waitSemaphoreCount_ )\n    {\n      waitSemaphoreCount = waitSemaphoreCount_;\n      return *this;\n    }\n\n    PresentInfoKHR& setPWaitSemaphores( const Semaphore* pWaitSemaphores_ )\n    {\n      pWaitSemaphores = pWaitSemaphores_;\n      return *this;\n    }\n\n    PresentInfoKHR& setSwapchainCount( uint32_t swapchainCount_ )\n    {\n      swapchainCount = swapchainCount_;\n      return *this;\n    }\n\n    PresentInfoKHR& setPSwapchains( const SwapchainKHR* pSwapchains_ )\n    {\n      pSwapchains = pSwapchains_;\n      return *this;\n    }\n\n    PresentInfoKHR& setPImageIndices( const uint32_t* pImageIndices_ )\n    {\n      pImageIndices = pImageIndices_;\n      return *this;\n    }\n\n    PresentInfoKHR& setPResults( Result* pResults_ )\n    {\n      pResults = pResults_;\n      return *this;\n    }\n\n    operator const VkPresentInfoKHR&() const\n    {\n      return *reinterpret_cast<const VkPresentInfoKHR*>(this);\n    }\n\n    bool operator==( PresentInfoKHR const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( waitSemaphoreCount == rhs.waitSemaphoreCount )\n          && ( pWaitSemaphores == rhs.pWaitSemaphores )\n          && ( swapchainCount == rhs.swapchainCount )\n          && ( pSwapchains == rhs.pSwapchains )\n          && ( pImageIndices == rhs.pImageIndices )\n          && ( pResults == rhs.pResults );\n    }\n\n    bool operator!=( PresentInfoKHR const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    uint32_t waitSemaphoreCount;\n    const Semaphore* pWaitSemaphores;\n    uint32_t swapchainCount;\n    const SwapchainKHR* pSwapchains;\n    const uint32_t* pImageIndices;\n    Result* pResults;\n  };\n  static_assert( sizeof( PresentInfoKHR ) == sizeof( VkPresentInfoKHR ), \"struct and wrapper have different size!\" );\n\n  enum class DynamicState\n  {\n    eViewport = VK_DYNAMIC_STATE_VIEWPORT,\n    eScissor = VK_DYNAMIC_STATE_SCISSOR,\n    eLineWidth = VK_DYNAMIC_STATE_LINE_WIDTH,\n    eDepthBias = VK_DYNAMIC_STATE_DEPTH_BIAS,\n    eBlendConstants = VK_DYNAMIC_STATE_BLEND_CONSTANTS,\n    eDepthBounds = VK_DYNAMIC_STATE_DEPTH_BOUNDS,\n    eStencilCompareMask = VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK,\n    eStencilWriteMask = VK_DYNAMIC_STATE_STENCIL_WRITE_MASK,\n    eStencilReference = VK_DYNAMIC_STATE_STENCIL_REFERENCE,\n    eViewportWScalingNV = VK_DYNAMIC_STATE_VIEWPORT_W_SCALING_NV,\n    eDiscardRectangleEXT = VK_DYNAMIC_STATE_DISCARD_RECTANGLE_EXT\n  };\n\n  struct PipelineDynamicStateCreateInfo\n  {\n    PipelineDynamicStateCreateInfo( PipelineDynamicStateCreateFlags flags_ = PipelineDynamicStateCreateFlags(), uint32_t dynamicStateCount_ = 0, const DynamicState* pDynamicStates_ = nullptr )\n      : sType( StructureType::ePipelineDynamicStateCreateInfo )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , dynamicStateCount( dynamicStateCount_ )\n      , pDynamicStates( pDynamicStates_ )\n    {\n    }\n\n    PipelineDynamicStateCreateInfo( VkPipelineDynamicStateCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PipelineDynamicStateCreateInfo) );\n    }\n\n    PipelineDynamicStateCreateInfo& operator=( VkPipelineDynamicStateCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PipelineDynamicStateCreateInfo) );\n      return *this;\n    }\n\n    PipelineDynamicStateCreateInfo& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    PipelineDynamicStateCreateInfo& setFlags( PipelineDynamicStateCreateFlags flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    PipelineDynamicStateCreateInfo& setDynamicStateCount( uint32_t dynamicStateCount_ )\n    {\n      dynamicStateCount = dynamicStateCount_;\n      return *this;\n    }\n\n    PipelineDynamicStateCreateInfo& setPDynamicStates( const DynamicState* pDynamicStates_ )\n    {\n      pDynamicStates = pDynamicStates_;\n      return *this;\n    }\n\n    operator const VkPipelineDynamicStateCreateInfo&() const\n    {\n      return *reinterpret_cast<const VkPipelineDynamicStateCreateInfo*>(this);\n    }\n\n    bool operator==( PipelineDynamicStateCreateInfo const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( dynamicStateCount == rhs.dynamicStateCount )\n          && ( pDynamicStates == rhs.pDynamicStates );\n    }\n\n    bool operator!=( PipelineDynamicStateCreateInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    PipelineDynamicStateCreateFlags flags;\n    uint32_t dynamicStateCount;\n    const DynamicState* pDynamicStates;\n  };\n  static_assert( sizeof( PipelineDynamicStateCreateInfo ) == sizeof( VkPipelineDynamicStateCreateInfo ), \"struct and wrapper have different size!\" );\n\n  enum class DescriptorUpdateTemplateTypeKHR\n  {\n    eDescriptorSet = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR,\n    ePushDescriptors = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR\n  };\n\n  struct DescriptorUpdateTemplateCreateInfoKHR\n  {\n    DescriptorUpdateTemplateCreateInfoKHR( DescriptorUpdateTemplateCreateFlagsKHR flags_ = DescriptorUpdateTemplateCreateFlagsKHR(), uint32_t descriptorUpdateEntryCount_ = 0, const DescriptorUpdateTemplateEntryKHR* pDescriptorUpdateEntries_ = nullptr, DescriptorUpdateTemplateTypeKHR templateType_ = DescriptorUpdateTemplateTypeKHR::eDescriptorSet, DescriptorSetLayout descriptorSetLayout_ = DescriptorSetLayout(), PipelineBindPoint pipelineBindPoint_ = PipelineBindPoint::eGraphics, PipelineLayout pipelineLayout_ = PipelineLayout(), uint32_t set_ = 0 )\n      : sType( StructureType::eDescriptorUpdateTemplateCreateInfoKHR )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , descriptorUpdateEntryCount( descriptorUpdateEntryCount_ )\n      , pDescriptorUpdateEntries( pDescriptorUpdateEntries_ )\n      , templateType( templateType_ )\n      , descriptorSetLayout( descriptorSetLayout_ )\n      , pipelineBindPoint( pipelineBindPoint_ )\n      , pipelineLayout( pipelineLayout_ )\n      , set( set_ )\n    {\n    }\n\n    DescriptorUpdateTemplateCreateInfoKHR( VkDescriptorUpdateTemplateCreateInfoKHR const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DescriptorUpdateTemplateCreateInfoKHR) );\n    }\n\n    DescriptorUpdateTemplateCreateInfoKHR& operator=( VkDescriptorUpdateTemplateCreateInfoKHR const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DescriptorUpdateTemplateCreateInfoKHR) );\n      return *this;\n    }\n\n    DescriptorUpdateTemplateCreateInfoKHR& setPNext( void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    DescriptorUpdateTemplateCreateInfoKHR& setFlags( DescriptorUpdateTemplateCreateFlagsKHR flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    DescriptorUpdateTemplateCreateInfoKHR& setDescriptorUpdateEntryCount( uint32_t descriptorUpdateEntryCount_ )\n    {\n      descriptorUpdateEntryCount = descriptorUpdateEntryCount_;\n      return *this;\n    }\n\n    DescriptorUpdateTemplateCreateInfoKHR& setPDescriptorUpdateEntries( const DescriptorUpdateTemplateEntryKHR* pDescriptorUpdateEntries_ )\n    {\n      pDescriptorUpdateEntries = pDescriptorUpdateEntries_;\n      return *this;\n    }\n\n    DescriptorUpdateTemplateCreateInfoKHR& setTemplateType( DescriptorUpdateTemplateTypeKHR templateType_ )\n    {\n      templateType = templateType_;\n      return *this;\n    }\n\n    DescriptorUpdateTemplateCreateInfoKHR& setDescriptorSetLayout( DescriptorSetLayout descriptorSetLayout_ )\n    {\n      descriptorSetLayout = descriptorSetLayout_;\n      return *this;\n    }\n\n    DescriptorUpdateTemplateCreateInfoKHR& setPipelineBindPoint( PipelineBindPoint pipelineBindPoint_ )\n    {\n      pipelineBindPoint = pipelineBindPoint_;\n      return *this;\n    }\n\n    DescriptorUpdateTemplateCreateInfoKHR& setPipelineLayout( PipelineLayout pipelineLayout_ )\n    {\n      pipelineLayout = pipelineLayout_;\n      return *this;\n    }\n\n    DescriptorUpdateTemplateCreateInfoKHR& setSet( uint32_t set_ )\n    {\n      set = set_;\n      return *this;\n    }\n\n    operator const VkDescriptorUpdateTemplateCreateInfoKHR&() const\n    {\n      return *reinterpret_cast<const VkDescriptorUpdateTemplateCreateInfoKHR*>(this);\n    }\n\n    bool operator==( DescriptorUpdateTemplateCreateInfoKHR const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( descriptorUpdateEntryCount == rhs.descriptorUpdateEntryCount )\n          && ( pDescriptorUpdateEntries == rhs.pDescriptorUpdateEntries )\n          && ( templateType == rhs.templateType )\n          && ( descriptorSetLayout == rhs.descriptorSetLayout )\n          && ( pipelineBindPoint == rhs.pipelineBindPoint )\n          && ( pipelineLayout == rhs.pipelineLayout )\n          && ( set == rhs.set );\n    }\n\n    bool operator!=( DescriptorUpdateTemplateCreateInfoKHR const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    void* pNext;\n    DescriptorUpdateTemplateCreateFlagsKHR flags;\n    uint32_t descriptorUpdateEntryCount;\n    const DescriptorUpdateTemplateEntryKHR* pDescriptorUpdateEntries;\n    DescriptorUpdateTemplateTypeKHR templateType;\n    DescriptorSetLayout descriptorSetLayout;\n    PipelineBindPoint pipelineBindPoint;\n    PipelineLayout pipelineLayout;\n    uint32_t set;\n  };\n  static_assert( sizeof( DescriptorUpdateTemplateCreateInfoKHR ) == sizeof( VkDescriptorUpdateTemplateCreateInfoKHR ), \"struct and wrapper have different size!\" );\n\n  enum class ObjectType\n  {\n    eUnknown = VK_OBJECT_TYPE_UNKNOWN,\n    eInstance = VK_OBJECT_TYPE_INSTANCE,\n    ePhysicalDevice = VK_OBJECT_TYPE_PHYSICAL_DEVICE,\n    eDevice = VK_OBJECT_TYPE_DEVICE,\n    eQueue = VK_OBJECT_TYPE_QUEUE,\n    eSemaphore = VK_OBJECT_TYPE_SEMAPHORE,\n    eCommandBuffer = VK_OBJECT_TYPE_COMMAND_BUFFER,\n    eFence = VK_OBJECT_TYPE_FENCE,\n    eDeviceMemory = VK_OBJECT_TYPE_DEVICE_MEMORY,\n    eBuffer = VK_OBJECT_TYPE_BUFFER,\n    eImage = VK_OBJECT_TYPE_IMAGE,\n    eEvent = VK_OBJECT_TYPE_EVENT,\n    eQueryPool = VK_OBJECT_TYPE_QUERY_POOL,\n    eBufferView = VK_OBJECT_TYPE_BUFFER_VIEW,\n    eImageView = VK_OBJECT_TYPE_IMAGE_VIEW,\n    eShaderModule = VK_OBJECT_TYPE_SHADER_MODULE,\n    ePipelineCache = VK_OBJECT_TYPE_PIPELINE_CACHE,\n    ePipelineLayout = VK_OBJECT_TYPE_PIPELINE_LAYOUT,\n    eRenderPass = VK_OBJECT_TYPE_RENDER_PASS,\n    ePipeline = VK_OBJECT_TYPE_PIPELINE,\n    eDescriptorSetLayout = VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT,\n    eSampler = VK_OBJECT_TYPE_SAMPLER,\n    eDescriptorPool = VK_OBJECT_TYPE_DESCRIPTOR_POOL,\n    eDescriptorSet = VK_OBJECT_TYPE_DESCRIPTOR_SET,\n    eFramebuffer = VK_OBJECT_TYPE_FRAMEBUFFER,\n    eCommandPool = VK_OBJECT_TYPE_COMMAND_POOL,\n    eSurfaceKHR = VK_OBJECT_TYPE_SURFACE_KHR,\n    eSwapchainKHR = VK_OBJECT_TYPE_SWAPCHAIN_KHR,\n    eDisplayKHR = VK_OBJECT_TYPE_DISPLAY_KHR,\n    eDisplayModeKHR = VK_OBJECT_TYPE_DISPLAY_MODE_KHR,\n    eDebugReportCallbackEXT = VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT,\n    eDescriptorUpdateTemplateKHR = VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR,\n    eObjectTableNVX = VK_OBJECT_TYPE_OBJECT_TABLE_NVX,\n    eIndirectCommandsLayoutNVX = VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX\n  };\n\n  enum class QueueFlagBits\n  {\n    eGraphics = VK_QUEUE_GRAPHICS_BIT,\n    eCompute = VK_QUEUE_COMPUTE_BIT,\n    eTransfer = VK_QUEUE_TRANSFER_BIT,\n    eSparseBinding = VK_QUEUE_SPARSE_BINDING_BIT\n  };\n\n  using QueueFlags = Flags<QueueFlagBits, VkQueueFlags>;\n\n  VULKAN_HPP_INLINE QueueFlags operator|( QueueFlagBits bit0, QueueFlagBits bit1 )\n  {\n    return QueueFlags( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE QueueFlags operator~( QueueFlagBits bits )\n  {\n    return ~( QueueFlags( bits ) );\n  }\n\n  template <> struct FlagTraits<QueueFlagBits>\n  {\n    enum\n    {\n      allFlags = VkFlags(QueueFlagBits::eGraphics) | VkFlags(QueueFlagBits::eCompute) | VkFlags(QueueFlagBits::eTransfer) | VkFlags(QueueFlagBits::eSparseBinding)\n    };\n  };\n\n  struct QueueFamilyProperties\n  {\n    operator const VkQueueFamilyProperties&() const\n    {\n      return *reinterpret_cast<const VkQueueFamilyProperties*>(this);\n    }\n\n    bool operator==( QueueFamilyProperties const& rhs ) const\n    {\n      return ( queueFlags == rhs.queueFlags )\n          && ( queueCount == rhs.queueCount )\n          && ( timestampValidBits == rhs.timestampValidBits )\n          && ( minImageTransferGranularity == rhs.minImageTransferGranularity );\n    }\n\n    bool operator!=( QueueFamilyProperties const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    QueueFlags queueFlags;\n    uint32_t queueCount;\n    uint32_t timestampValidBits;\n    Extent3D minImageTransferGranularity;\n  };\n  static_assert( sizeof( QueueFamilyProperties ) == sizeof( VkQueueFamilyProperties ), \"struct and wrapper have different size!\" );\n\n  struct QueueFamilyProperties2KHR\n  {\n    operator const VkQueueFamilyProperties2KHR&() const\n    {\n      return *reinterpret_cast<const VkQueueFamilyProperties2KHR*>(this);\n    }\n\n    bool operator==( QueueFamilyProperties2KHR const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( queueFamilyProperties == rhs.queueFamilyProperties );\n    }\n\n    bool operator!=( QueueFamilyProperties2KHR const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    void* pNext;\n    QueueFamilyProperties queueFamilyProperties;\n  };\n  static_assert( sizeof( QueueFamilyProperties2KHR ) == sizeof( VkQueueFamilyProperties2KHR ), \"struct and wrapper have different size!\" );\n\n  enum class MemoryPropertyFlagBits\n  {\n    eDeviceLocal = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,\n    eHostVisible = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,\n    eHostCoherent = VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,\n    eHostCached = VK_MEMORY_PROPERTY_HOST_CACHED_BIT,\n    eLazilyAllocated = VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT\n  };\n\n  using MemoryPropertyFlags = Flags<MemoryPropertyFlagBits, VkMemoryPropertyFlags>;\n\n  VULKAN_HPP_INLINE MemoryPropertyFlags operator|( MemoryPropertyFlagBits bit0, MemoryPropertyFlagBits bit1 )\n  {\n    return MemoryPropertyFlags( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE MemoryPropertyFlags operator~( MemoryPropertyFlagBits bits )\n  {\n    return ~( MemoryPropertyFlags( bits ) );\n  }\n\n  template <> struct FlagTraits<MemoryPropertyFlagBits>\n  {\n    enum\n    {\n      allFlags = VkFlags(MemoryPropertyFlagBits::eDeviceLocal) | VkFlags(MemoryPropertyFlagBits::eHostVisible) | VkFlags(MemoryPropertyFlagBits::eHostCoherent) | VkFlags(MemoryPropertyFlagBits::eHostCached) | VkFlags(MemoryPropertyFlagBits::eLazilyAllocated)\n    };\n  };\n\n  struct MemoryType\n  {\n    operator const VkMemoryType&() const\n    {\n      return *reinterpret_cast<const VkMemoryType*>(this);\n    }\n\n    bool operator==( MemoryType const& rhs ) const\n    {\n      return ( propertyFlags == rhs.propertyFlags )\n          && ( heapIndex == rhs.heapIndex );\n    }\n\n    bool operator!=( MemoryType const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    MemoryPropertyFlags propertyFlags;\n    uint32_t heapIndex;\n  };\n  static_assert( sizeof( MemoryType ) == sizeof( VkMemoryType ), \"struct and wrapper have different size!\" );\n\n  enum class MemoryHeapFlagBits\n  {\n    eDeviceLocal = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT,\n    eMultiInstanceKHX = VK_MEMORY_HEAP_MULTI_INSTANCE_BIT_KHX\n  };\n\n  using MemoryHeapFlags = Flags<MemoryHeapFlagBits, VkMemoryHeapFlags>;\n\n  VULKAN_HPP_INLINE MemoryHeapFlags operator|( MemoryHeapFlagBits bit0, MemoryHeapFlagBits bit1 )\n  {\n    return MemoryHeapFlags( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE MemoryHeapFlags operator~( MemoryHeapFlagBits bits )\n  {\n    return ~( MemoryHeapFlags( bits ) );\n  }\n\n  template <> struct FlagTraits<MemoryHeapFlagBits>\n  {\n    enum\n    {\n      allFlags = VkFlags(MemoryHeapFlagBits::eDeviceLocal) | VkFlags(MemoryHeapFlagBits::eMultiInstanceKHX)\n    };\n  };\n\n  struct MemoryHeap\n  {\n    operator const VkMemoryHeap&() const\n    {\n      return *reinterpret_cast<const VkMemoryHeap*>(this);\n    }\n\n    bool operator==( MemoryHeap const& rhs ) const\n    {\n      return ( size == rhs.size )\n          && ( flags == rhs.flags );\n    }\n\n    bool operator!=( MemoryHeap const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    DeviceSize size;\n    MemoryHeapFlags flags;\n  };\n  static_assert( sizeof( MemoryHeap ) == sizeof( VkMemoryHeap ), \"struct and wrapper have different size!\" );\n\n  struct PhysicalDeviceMemoryProperties\n  {\n    operator const VkPhysicalDeviceMemoryProperties&() const\n    {\n      return *reinterpret_cast<const VkPhysicalDeviceMemoryProperties*>(this);\n    }\n\n    bool operator==( PhysicalDeviceMemoryProperties const& rhs ) const\n    {\n      return ( memoryTypeCount == rhs.memoryTypeCount )\n          && ( memcmp( memoryTypes, rhs.memoryTypes, VK_MAX_MEMORY_TYPES * sizeof( MemoryType ) ) == 0 )\n          && ( memoryHeapCount == rhs.memoryHeapCount )\n          && ( memcmp( memoryHeaps, rhs.memoryHeaps, VK_MAX_MEMORY_HEAPS * sizeof( MemoryHeap ) ) == 0 );\n    }\n\n    bool operator!=( PhysicalDeviceMemoryProperties const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    uint32_t memoryTypeCount;\n    MemoryType memoryTypes[VK_MAX_MEMORY_TYPES];\n    uint32_t memoryHeapCount;\n    MemoryHeap memoryHeaps[VK_MAX_MEMORY_HEAPS];\n  };\n  static_assert( sizeof( PhysicalDeviceMemoryProperties ) == sizeof( VkPhysicalDeviceMemoryProperties ), \"struct and wrapper have different size!\" );\n\n  struct PhysicalDeviceMemoryProperties2KHR\n  {\n    operator const VkPhysicalDeviceMemoryProperties2KHR&() const\n    {\n      return *reinterpret_cast<const VkPhysicalDeviceMemoryProperties2KHR*>(this);\n    }\n\n    bool operator==( PhysicalDeviceMemoryProperties2KHR const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( memoryProperties == rhs.memoryProperties );\n    }\n\n    bool operator!=( PhysicalDeviceMemoryProperties2KHR const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    void* pNext;\n    PhysicalDeviceMemoryProperties memoryProperties;\n  };\n  static_assert( sizeof( PhysicalDeviceMemoryProperties2KHR ) == sizeof( VkPhysicalDeviceMemoryProperties2KHR ), \"struct and wrapper have different size!\" );\n\n  enum class AccessFlagBits\n  {\n    eIndirectCommandRead = VK_ACCESS_INDIRECT_COMMAND_READ_BIT,\n    eIndexRead = VK_ACCESS_INDEX_READ_BIT,\n    eVertexAttributeRead = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT,\n    eUniformRead = VK_ACCESS_UNIFORM_READ_BIT,\n    eInputAttachmentRead = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT,\n    eShaderRead = VK_ACCESS_SHADER_READ_BIT,\n    eShaderWrite = VK_ACCESS_SHADER_WRITE_BIT,\n    eColorAttachmentRead = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT,\n    eColorAttachmentWrite = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,\n    eDepthStencilAttachmentRead = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT,\n    eDepthStencilAttachmentWrite = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,\n    eTransferRead = VK_ACCESS_TRANSFER_READ_BIT,\n    eTransferWrite = VK_ACCESS_TRANSFER_WRITE_BIT,\n    eHostRead = VK_ACCESS_HOST_READ_BIT,\n    eHostWrite = VK_ACCESS_HOST_WRITE_BIT,\n    eMemoryRead = VK_ACCESS_MEMORY_READ_BIT,\n    eMemoryWrite = VK_ACCESS_MEMORY_WRITE_BIT,\n    eCommandProcessReadNVX = VK_ACCESS_COMMAND_PROCESS_READ_BIT_NVX,\n    eCommandProcessWriteNVX = VK_ACCESS_COMMAND_PROCESS_WRITE_BIT_NVX\n  };\n\n  using AccessFlags = Flags<AccessFlagBits, VkAccessFlags>;\n\n  VULKAN_HPP_INLINE AccessFlags operator|( AccessFlagBits bit0, AccessFlagBits bit1 )\n  {\n    return AccessFlags( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE AccessFlags operator~( AccessFlagBits bits )\n  {\n    return ~( AccessFlags( bits ) );\n  }\n\n  template <> struct FlagTraits<AccessFlagBits>\n  {\n    enum\n    {\n      allFlags = VkFlags(AccessFlagBits::eIndirectCommandRead) | VkFlags(AccessFlagBits::eIndexRead) | VkFlags(AccessFlagBits::eVertexAttributeRead) | VkFlags(AccessFlagBits::eUniformRead) | VkFlags(AccessFlagBits::eInputAttachmentRead) | VkFlags(AccessFlagBits::eShaderRead) | VkFlags(AccessFlagBits::eShaderWrite) | VkFlags(AccessFlagBits::eColorAttachmentRead) | VkFlags(AccessFlagBits::eColorAttachmentWrite) | VkFlags(AccessFlagBits::eDepthStencilAttachmentRead) | VkFlags(AccessFlagBits::eDepthStencilAttachmentWrite) | VkFlags(AccessFlagBits::eTransferRead) | VkFlags(AccessFlagBits::eTransferWrite) | VkFlags(AccessFlagBits::eHostRead) | VkFlags(AccessFlagBits::eHostWrite) | VkFlags(AccessFlagBits::eMemoryRead) | VkFlags(AccessFlagBits::eMemoryWrite) | VkFlags(AccessFlagBits::eCommandProcessReadNVX) | VkFlags(AccessFlagBits::eCommandProcessWriteNVX)\n    };\n  };\n\n  struct MemoryBarrier\n  {\n    MemoryBarrier( AccessFlags srcAccessMask_ = AccessFlags(), AccessFlags dstAccessMask_ = AccessFlags() )\n      : sType( StructureType::eMemoryBarrier )\n      , pNext( nullptr )\n      , srcAccessMask( srcAccessMask_ )\n      , dstAccessMask( dstAccessMask_ )\n    {\n    }\n\n    MemoryBarrier( VkMemoryBarrier const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(MemoryBarrier) );\n    }\n\n    MemoryBarrier& operator=( VkMemoryBarrier const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(MemoryBarrier) );\n      return *this;\n    }\n\n    MemoryBarrier& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    MemoryBarrier& setSrcAccessMask( AccessFlags srcAccessMask_ )\n    {\n      srcAccessMask = srcAccessMask_;\n      return *this;\n    }\n\n    MemoryBarrier& setDstAccessMask( AccessFlags dstAccessMask_ )\n    {\n      dstAccessMask = dstAccessMask_;\n      return *this;\n    }\n\n    operator const VkMemoryBarrier&() const\n    {\n      return *reinterpret_cast<const VkMemoryBarrier*>(this);\n    }\n\n    bool operator==( MemoryBarrier const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( srcAccessMask == rhs.srcAccessMask )\n          && ( dstAccessMask == rhs.dstAccessMask );\n    }\n\n    bool operator!=( MemoryBarrier const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    AccessFlags srcAccessMask;\n    AccessFlags dstAccessMask;\n  };\n  static_assert( sizeof( MemoryBarrier ) == sizeof( VkMemoryBarrier ), \"struct and wrapper have different size!\" );\n\n  struct BufferMemoryBarrier\n  {\n    BufferMemoryBarrier( AccessFlags srcAccessMask_ = AccessFlags(), AccessFlags dstAccessMask_ = AccessFlags(), uint32_t srcQueueFamilyIndex_ = 0, uint32_t dstQueueFamilyIndex_ = 0, Buffer buffer_ = Buffer(), DeviceSize offset_ = 0, DeviceSize size_ = 0 )\n      : sType( StructureType::eBufferMemoryBarrier )\n      , pNext( nullptr )\n      , srcAccessMask( srcAccessMask_ )\n      , dstAccessMask( dstAccessMask_ )\n      , srcQueueFamilyIndex( srcQueueFamilyIndex_ )\n      , dstQueueFamilyIndex( dstQueueFamilyIndex_ )\n      , buffer( buffer_ )\n      , offset( offset_ )\n      , size( size_ )\n    {\n    }\n\n    BufferMemoryBarrier( VkBufferMemoryBarrier const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(BufferMemoryBarrier) );\n    }\n\n    BufferMemoryBarrier& operator=( VkBufferMemoryBarrier const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(BufferMemoryBarrier) );\n      return *this;\n    }\n\n    BufferMemoryBarrier& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    BufferMemoryBarrier& setSrcAccessMask( AccessFlags srcAccessMask_ )\n    {\n      srcAccessMask = srcAccessMask_;\n      return *this;\n    }\n\n    BufferMemoryBarrier& setDstAccessMask( AccessFlags dstAccessMask_ )\n    {\n      dstAccessMask = dstAccessMask_;\n      return *this;\n    }\n\n    BufferMemoryBarrier& setSrcQueueFamilyIndex( uint32_t srcQueueFamilyIndex_ )\n    {\n      srcQueueFamilyIndex = srcQueueFamilyIndex_;\n      return *this;\n    }\n\n    BufferMemoryBarrier& setDstQueueFamilyIndex( uint32_t dstQueueFamilyIndex_ )\n    {\n      dstQueueFamilyIndex = dstQueueFamilyIndex_;\n      return *this;\n    }\n\n    BufferMemoryBarrier& setBuffer( Buffer buffer_ )\n    {\n      buffer = buffer_;\n      return *this;\n    }\n\n    BufferMemoryBarrier& setOffset( DeviceSize offset_ )\n    {\n      offset = offset_;\n      return *this;\n    }\n\n    BufferMemoryBarrier& setSize( DeviceSize size_ )\n    {\n      size = size_;\n      return *this;\n    }\n\n    operator const VkBufferMemoryBarrier&() const\n    {\n      return *reinterpret_cast<const VkBufferMemoryBarrier*>(this);\n    }\n\n    bool operator==( BufferMemoryBarrier const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( srcAccessMask == rhs.srcAccessMask )\n          && ( dstAccessMask == rhs.dstAccessMask )\n          && ( srcQueueFamilyIndex == rhs.srcQueueFamilyIndex )\n          && ( dstQueueFamilyIndex == rhs.dstQueueFamilyIndex )\n          && ( buffer == rhs.buffer )\n          && ( offset == rhs.offset )\n          && ( size == rhs.size );\n    }\n\n    bool operator!=( BufferMemoryBarrier const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    AccessFlags srcAccessMask;\n    AccessFlags dstAccessMask;\n    uint32_t srcQueueFamilyIndex;\n    uint32_t dstQueueFamilyIndex;\n    Buffer buffer;\n    DeviceSize offset;\n    DeviceSize size;\n  };\n  static_assert( sizeof( BufferMemoryBarrier ) == sizeof( VkBufferMemoryBarrier ), \"struct and wrapper have different size!\" );\n\n  enum class BufferUsageFlagBits\n  {\n    eTransferSrc = VK_BUFFER_USAGE_TRANSFER_SRC_BIT,\n    eTransferDst = VK_BUFFER_USAGE_TRANSFER_DST_BIT,\n    eUniformTexelBuffer = VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT,\n    eStorageTexelBuffer = VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT,\n    eUniformBuffer = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,\n    eStorageBuffer = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,\n    eIndexBuffer = VK_BUFFER_USAGE_INDEX_BUFFER_BIT,\n    eVertexBuffer = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,\n    eIndirectBuffer = VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT\n  };\n\n  using BufferUsageFlags = Flags<BufferUsageFlagBits, VkBufferUsageFlags>;\n\n  VULKAN_HPP_INLINE BufferUsageFlags operator|( BufferUsageFlagBits bit0, BufferUsageFlagBits bit1 )\n  {\n    return BufferUsageFlags( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE BufferUsageFlags operator~( BufferUsageFlagBits bits )\n  {\n    return ~( BufferUsageFlags( bits ) );\n  }\n\n  template <> struct FlagTraits<BufferUsageFlagBits>\n  {\n    enum\n    {\n      allFlags = VkFlags(BufferUsageFlagBits::eTransferSrc) | VkFlags(BufferUsageFlagBits::eTransferDst) | VkFlags(BufferUsageFlagBits::eUniformTexelBuffer) | VkFlags(BufferUsageFlagBits::eStorageTexelBuffer) | VkFlags(BufferUsageFlagBits::eUniformBuffer) | VkFlags(BufferUsageFlagBits::eStorageBuffer) | VkFlags(BufferUsageFlagBits::eIndexBuffer) | VkFlags(BufferUsageFlagBits::eVertexBuffer) | VkFlags(BufferUsageFlagBits::eIndirectBuffer)\n    };\n  };\n\n  enum class BufferCreateFlagBits\n  {\n    eSparseBinding = VK_BUFFER_CREATE_SPARSE_BINDING_BIT,\n    eSparseResidency = VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT,\n    eSparseAliased = VK_BUFFER_CREATE_SPARSE_ALIASED_BIT\n  };\n\n  using BufferCreateFlags = Flags<BufferCreateFlagBits, VkBufferCreateFlags>;\n\n  VULKAN_HPP_INLINE BufferCreateFlags operator|( BufferCreateFlagBits bit0, BufferCreateFlagBits bit1 )\n  {\n    return BufferCreateFlags( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE BufferCreateFlags operator~( BufferCreateFlagBits bits )\n  {\n    return ~( BufferCreateFlags( bits ) );\n  }\n\n  template <> struct FlagTraits<BufferCreateFlagBits>\n  {\n    enum\n    {\n      allFlags = VkFlags(BufferCreateFlagBits::eSparseBinding) | VkFlags(BufferCreateFlagBits::eSparseResidency) | VkFlags(BufferCreateFlagBits::eSparseAliased)\n    };\n  };\n\n  struct BufferCreateInfo\n  {\n    BufferCreateInfo( BufferCreateFlags flags_ = BufferCreateFlags(), DeviceSize size_ = 0, BufferUsageFlags usage_ = BufferUsageFlags(), SharingMode sharingMode_ = SharingMode::eExclusive, uint32_t queueFamilyIndexCount_ = 0, const uint32_t* pQueueFamilyIndices_ = nullptr )\n      : sType( StructureType::eBufferCreateInfo )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , size( size_ )\n      , usage( usage_ )\n      , sharingMode( sharingMode_ )\n      , queueFamilyIndexCount( queueFamilyIndexCount_ )\n      , pQueueFamilyIndices( pQueueFamilyIndices_ )\n    {\n    }\n\n    BufferCreateInfo( VkBufferCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(BufferCreateInfo) );\n    }\n\n    BufferCreateInfo& operator=( VkBufferCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(BufferCreateInfo) );\n      return *this;\n    }\n\n    BufferCreateInfo& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    BufferCreateInfo& setFlags( BufferCreateFlags flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    BufferCreateInfo& setSize( DeviceSize size_ )\n    {\n      size = size_;\n      return *this;\n    }\n\n    BufferCreateInfo& setUsage( BufferUsageFlags usage_ )\n    {\n      usage = usage_;\n      return *this;\n    }\n\n    BufferCreateInfo& setSharingMode( SharingMode sharingMode_ )\n    {\n      sharingMode = sharingMode_;\n      return *this;\n    }\n\n    BufferCreateInfo& setQueueFamilyIndexCount( uint32_t queueFamilyIndexCount_ )\n    {\n      queueFamilyIndexCount = queueFamilyIndexCount_;\n      return *this;\n    }\n\n    BufferCreateInfo& setPQueueFamilyIndices( const uint32_t* pQueueFamilyIndices_ )\n    {\n      pQueueFamilyIndices = pQueueFamilyIndices_;\n      return *this;\n    }\n\n    operator const VkBufferCreateInfo&() const\n    {\n      return *reinterpret_cast<const VkBufferCreateInfo*>(this);\n    }\n\n    bool operator==( BufferCreateInfo const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( size == rhs.size )\n          && ( usage == rhs.usage )\n          && ( sharingMode == rhs.sharingMode )\n          && ( queueFamilyIndexCount == rhs.queueFamilyIndexCount )\n          && ( pQueueFamilyIndices == rhs.pQueueFamilyIndices );\n    }\n\n    bool operator!=( BufferCreateInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    BufferCreateFlags flags;\n    DeviceSize size;\n    BufferUsageFlags usage;\n    SharingMode sharingMode;\n    uint32_t queueFamilyIndexCount;\n    const uint32_t* pQueueFamilyIndices;\n  };\n  static_assert( sizeof( BufferCreateInfo ) == sizeof( VkBufferCreateInfo ), \"struct and wrapper have different size!\" );\n\n  enum class ShaderStageFlagBits\n  {\n    eVertex = VK_SHADER_STAGE_VERTEX_BIT,\n    eTessellationControl = VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,\n    eTessellationEvaluation = VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,\n    eGeometry = VK_SHADER_STAGE_GEOMETRY_BIT,\n    eFragment = VK_SHADER_STAGE_FRAGMENT_BIT,\n    eCompute = VK_SHADER_STAGE_COMPUTE_BIT,\n    eAllGraphics = VK_SHADER_STAGE_ALL_GRAPHICS,\n    eAll = VK_SHADER_STAGE_ALL\n  };\n\n  using ShaderStageFlags = Flags<ShaderStageFlagBits, VkShaderStageFlags>;\n\n  VULKAN_HPP_INLINE ShaderStageFlags operator|( ShaderStageFlagBits bit0, ShaderStageFlagBits bit1 )\n  {\n    return ShaderStageFlags( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE ShaderStageFlags operator~( ShaderStageFlagBits bits )\n  {\n    return ~( ShaderStageFlags( bits ) );\n  }\n\n  template <> struct FlagTraits<ShaderStageFlagBits>\n  {\n    enum\n    {\n      allFlags = VkFlags(ShaderStageFlagBits::eVertex) | VkFlags(ShaderStageFlagBits::eTessellationControl) | VkFlags(ShaderStageFlagBits::eTessellationEvaluation) | VkFlags(ShaderStageFlagBits::eGeometry) | VkFlags(ShaderStageFlagBits::eFragment) | VkFlags(ShaderStageFlagBits::eCompute) | VkFlags(ShaderStageFlagBits::eAllGraphics) | VkFlags(ShaderStageFlagBits::eAll)\n    };\n  };\n\n  struct DescriptorSetLayoutBinding\n  {\n    DescriptorSetLayoutBinding( uint32_t binding_ = 0, DescriptorType descriptorType_ = DescriptorType::eSampler, uint32_t descriptorCount_ = 0, ShaderStageFlags stageFlags_ = ShaderStageFlags(), const Sampler* pImmutableSamplers_ = nullptr )\n      : binding( binding_ )\n      , descriptorType( descriptorType_ )\n      , descriptorCount( descriptorCount_ )\n      , stageFlags( stageFlags_ )\n      , pImmutableSamplers( pImmutableSamplers_ )\n    {\n    }\n\n    DescriptorSetLayoutBinding( VkDescriptorSetLayoutBinding const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DescriptorSetLayoutBinding) );\n    }\n\n    DescriptorSetLayoutBinding& operator=( VkDescriptorSetLayoutBinding const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DescriptorSetLayoutBinding) );\n      return *this;\n    }\n\n    DescriptorSetLayoutBinding& setBinding( uint32_t binding_ )\n    {\n      binding = binding_;\n      return *this;\n    }\n\n    DescriptorSetLayoutBinding& setDescriptorType( DescriptorType descriptorType_ )\n    {\n      descriptorType = descriptorType_;\n      return *this;\n    }\n\n    DescriptorSetLayoutBinding& setDescriptorCount( uint32_t descriptorCount_ )\n    {\n      descriptorCount = descriptorCount_;\n      return *this;\n    }\n\n    DescriptorSetLayoutBinding& setStageFlags( ShaderStageFlags stageFlags_ )\n    {\n      stageFlags = stageFlags_;\n      return *this;\n    }\n\n    DescriptorSetLayoutBinding& setPImmutableSamplers( const Sampler* pImmutableSamplers_ )\n    {\n      pImmutableSamplers = pImmutableSamplers_;\n      return *this;\n    }\n\n    operator const VkDescriptorSetLayoutBinding&() const\n    {\n      return *reinterpret_cast<const VkDescriptorSetLayoutBinding*>(this);\n    }\n\n    bool operator==( DescriptorSetLayoutBinding const& rhs ) const\n    {\n      return ( binding == rhs.binding )\n          && ( descriptorType == rhs.descriptorType )\n          && ( descriptorCount == rhs.descriptorCount )\n          && ( stageFlags == rhs.stageFlags )\n          && ( pImmutableSamplers == rhs.pImmutableSamplers );\n    }\n\n    bool operator!=( DescriptorSetLayoutBinding const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    uint32_t binding;\n    DescriptorType descriptorType;\n    uint32_t descriptorCount;\n    ShaderStageFlags stageFlags;\n    const Sampler* pImmutableSamplers;\n  };\n  static_assert( sizeof( DescriptorSetLayoutBinding ) == sizeof( VkDescriptorSetLayoutBinding ), \"struct and wrapper have different size!\" );\n\n  struct PipelineShaderStageCreateInfo\n  {\n    PipelineShaderStageCreateInfo( PipelineShaderStageCreateFlags flags_ = PipelineShaderStageCreateFlags(), ShaderStageFlagBits stage_ = ShaderStageFlagBits::eVertex, ShaderModule module_ = ShaderModule(), const char* pName_ = nullptr, const SpecializationInfo* pSpecializationInfo_ = nullptr )\n      : sType( StructureType::ePipelineShaderStageCreateInfo )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , stage( stage_ )\n      , module( module_ )\n      , pName( pName_ )\n      , pSpecializationInfo( pSpecializationInfo_ )\n    {\n    }\n\n    PipelineShaderStageCreateInfo( VkPipelineShaderStageCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PipelineShaderStageCreateInfo) );\n    }\n\n    PipelineShaderStageCreateInfo& operator=( VkPipelineShaderStageCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PipelineShaderStageCreateInfo) );\n      return *this;\n    }\n\n    PipelineShaderStageCreateInfo& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    PipelineShaderStageCreateInfo& setFlags( PipelineShaderStageCreateFlags flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    PipelineShaderStageCreateInfo& setStage( ShaderStageFlagBits stage_ )\n    {\n      stage = stage_;\n      return *this;\n    }\n\n    PipelineShaderStageCreateInfo& setModule( ShaderModule module_ )\n    {\n      module = module_;\n      return *this;\n    }\n\n    PipelineShaderStageCreateInfo& setPName( const char* pName_ )\n    {\n      pName = pName_;\n      return *this;\n    }\n\n    PipelineShaderStageCreateInfo& setPSpecializationInfo( const SpecializationInfo* pSpecializationInfo_ )\n    {\n      pSpecializationInfo = pSpecializationInfo_;\n      return *this;\n    }\n\n    operator const VkPipelineShaderStageCreateInfo&() const\n    {\n      return *reinterpret_cast<const VkPipelineShaderStageCreateInfo*>(this);\n    }\n\n    bool operator==( PipelineShaderStageCreateInfo const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( stage == rhs.stage )\n          && ( module == rhs.module )\n          && ( pName == rhs.pName )\n          && ( pSpecializationInfo == rhs.pSpecializationInfo );\n    }\n\n    bool operator!=( PipelineShaderStageCreateInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    PipelineShaderStageCreateFlags flags;\n    ShaderStageFlagBits stage;\n    ShaderModule module;\n    const char* pName;\n    const SpecializationInfo* pSpecializationInfo;\n  };\n  static_assert( sizeof( PipelineShaderStageCreateInfo ) == sizeof( VkPipelineShaderStageCreateInfo ), \"struct and wrapper have different size!\" );\n\n  struct PushConstantRange\n  {\n    PushConstantRange( ShaderStageFlags stageFlags_ = ShaderStageFlags(), uint32_t offset_ = 0, uint32_t size_ = 0 )\n      : stageFlags( stageFlags_ )\n      , offset( offset_ )\n      , size( size_ )\n    {\n    }\n\n    PushConstantRange( VkPushConstantRange const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PushConstantRange) );\n    }\n\n    PushConstantRange& operator=( VkPushConstantRange const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PushConstantRange) );\n      return *this;\n    }\n\n    PushConstantRange& setStageFlags( ShaderStageFlags stageFlags_ )\n    {\n      stageFlags = stageFlags_;\n      return *this;\n    }\n\n    PushConstantRange& setOffset( uint32_t offset_ )\n    {\n      offset = offset_;\n      return *this;\n    }\n\n    PushConstantRange& setSize( uint32_t size_ )\n    {\n      size = size_;\n      return *this;\n    }\n\n    operator const VkPushConstantRange&() const\n    {\n      return *reinterpret_cast<const VkPushConstantRange*>(this);\n    }\n\n    bool operator==( PushConstantRange const& rhs ) const\n    {\n      return ( stageFlags == rhs.stageFlags )\n          && ( offset == rhs.offset )\n          && ( size == rhs.size );\n    }\n\n    bool operator!=( PushConstantRange const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    ShaderStageFlags stageFlags;\n    uint32_t offset;\n    uint32_t size;\n  };\n  static_assert( sizeof( PushConstantRange ) == sizeof( VkPushConstantRange ), \"struct and wrapper have different size!\" );\n\n  struct PipelineLayoutCreateInfo\n  {\n    PipelineLayoutCreateInfo( PipelineLayoutCreateFlags flags_ = PipelineLayoutCreateFlags(), uint32_t setLayoutCount_ = 0, const DescriptorSetLayout* pSetLayouts_ = nullptr, uint32_t pushConstantRangeCount_ = 0, const PushConstantRange* pPushConstantRanges_ = nullptr )\n      : sType( StructureType::ePipelineLayoutCreateInfo )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , setLayoutCount( setLayoutCount_ )\n      , pSetLayouts( pSetLayouts_ )\n      , pushConstantRangeCount( pushConstantRangeCount_ )\n      , pPushConstantRanges( pPushConstantRanges_ )\n    {\n    }\n\n    PipelineLayoutCreateInfo( VkPipelineLayoutCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PipelineLayoutCreateInfo) );\n    }\n\n    PipelineLayoutCreateInfo& operator=( VkPipelineLayoutCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PipelineLayoutCreateInfo) );\n      return *this;\n    }\n\n    PipelineLayoutCreateInfo& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    PipelineLayoutCreateInfo& setFlags( PipelineLayoutCreateFlags flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    PipelineLayoutCreateInfo& setSetLayoutCount( uint32_t setLayoutCount_ )\n    {\n      setLayoutCount = setLayoutCount_;\n      return *this;\n    }\n\n    PipelineLayoutCreateInfo& setPSetLayouts( const DescriptorSetLayout* pSetLayouts_ )\n    {\n      pSetLayouts = pSetLayouts_;\n      return *this;\n    }\n\n    PipelineLayoutCreateInfo& setPushConstantRangeCount( uint32_t pushConstantRangeCount_ )\n    {\n      pushConstantRangeCount = pushConstantRangeCount_;\n      return *this;\n    }\n\n    PipelineLayoutCreateInfo& setPPushConstantRanges( const PushConstantRange* pPushConstantRanges_ )\n    {\n      pPushConstantRanges = pPushConstantRanges_;\n      return *this;\n    }\n\n    operator const VkPipelineLayoutCreateInfo&() const\n    {\n      return *reinterpret_cast<const VkPipelineLayoutCreateInfo*>(this);\n    }\n\n    bool operator==( PipelineLayoutCreateInfo const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( setLayoutCount == rhs.setLayoutCount )\n          && ( pSetLayouts == rhs.pSetLayouts )\n          && ( pushConstantRangeCount == rhs.pushConstantRangeCount )\n          && ( pPushConstantRanges == rhs.pPushConstantRanges );\n    }\n\n    bool operator!=( PipelineLayoutCreateInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    PipelineLayoutCreateFlags flags;\n    uint32_t setLayoutCount;\n    const DescriptorSetLayout* pSetLayouts;\n    uint32_t pushConstantRangeCount;\n    const PushConstantRange* pPushConstantRanges;\n  };\n  static_assert( sizeof( PipelineLayoutCreateInfo ) == sizeof( VkPipelineLayoutCreateInfo ), \"struct and wrapper have different size!\" );\n\n  enum class ImageUsageFlagBits\n  {\n    eTransferSrc = VK_IMAGE_USAGE_TRANSFER_SRC_BIT,\n    eTransferDst = VK_IMAGE_USAGE_TRANSFER_DST_BIT,\n    eSampled = VK_IMAGE_USAGE_SAMPLED_BIT,\n    eStorage = VK_IMAGE_USAGE_STORAGE_BIT,\n    eColorAttachment = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,\n    eDepthStencilAttachment = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,\n    eTransientAttachment = VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT,\n    eInputAttachment = VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT\n  };\n\n  using ImageUsageFlags = Flags<ImageUsageFlagBits, VkImageUsageFlags>;\n\n  VULKAN_HPP_INLINE ImageUsageFlags operator|( ImageUsageFlagBits bit0, ImageUsageFlagBits bit1 )\n  {\n    return ImageUsageFlags( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE ImageUsageFlags operator~( ImageUsageFlagBits bits )\n  {\n    return ~( ImageUsageFlags( bits ) );\n  }\n\n  template <> struct FlagTraits<ImageUsageFlagBits>\n  {\n    enum\n    {\n      allFlags = VkFlags(ImageUsageFlagBits::eTransferSrc) | VkFlags(ImageUsageFlagBits::eTransferDst) | VkFlags(ImageUsageFlagBits::eSampled) | VkFlags(ImageUsageFlagBits::eStorage) | VkFlags(ImageUsageFlagBits::eColorAttachment) | VkFlags(ImageUsageFlagBits::eDepthStencilAttachment) | VkFlags(ImageUsageFlagBits::eTransientAttachment) | VkFlags(ImageUsageFlagBits::eInputAttachment)\n    };\n  };\n\n  struct SharedPresentSurfaceCapabilitiesKHR\n  {\n    operator const VkSharedPresentSurfaceCapabilitiesKHR&() const\n    {\n      return *reinterpret_cast<const VkSharedPresentSurfaceCapabilitiesKHR*>(this);\n    }\n\n    bool operator==( SharedPresentSurfaceCapabilitiesKHR const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( sharedPresentSupportedUsageFlags == rhs.sharedPresentSupportedUsageFlags );\n    }\n\n    bool operator!=( SharedPresentSurfaceCapabilitiesKHR const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    void* pNext;\n    ImageUsageFlags sharedPresentSupportedUsageFlags;\n  };\n  static_assert( sizeof( SharedPresentSurfaceCapabilitiesKHR ) == sizeof( VkSharedPresentSurfaceCapabilitiesKHR ), \"struct and wrapper have different size!\" );\n\n  enum class ImageCreateFlagBits\n  {\n    eSparseBinding = VK_IMAGE_CREATE_SPARSE_BINDING_BIT,\n    eSparseResidency = VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT,\n    eSparseAliased = VK_IMAGE_CREATE_SPARSE_ALIASED_BIT,\n    eMutableFormat = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT,\n    eCubeCompatible = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT,\n    eBindSfrKHX = VK_IMAGE_CREATE_BIND_SFR_BIT_KHX,\n    e2DArrayCompatibleKHR = VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR\n  };\n\n  using ImageCreateFlags = Flags<ImageCreateFlagBits, VkImageCreateFlags>;\n\n  VULKAN_HPP_INLINE ImageCreateFlags operator|( ImageCreateFlagBits bit0, ImageCreateFlagBits bit1 )\n  {\n    return ImageCreateFlags( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE ImageCreateFlags operator~( ImageCreateFlagBits bits )\n  {\n    return ~( ImageCreateFlags( bits ) );\n  }\n\n  template <> struct FlagTraits<ImageCreateFlagBits>\n  {\n    enum\n    {\n      allFlags = VkFlags(ImageCreateFlagBits::eSparseBinding) | VkFlags(ImageCreateFlagBits::eSparseResidency) | VkFlags(ImageCreateFlagBits::eSparseAliased) | VkFlags(ImageCreateFlagBits::eMutableFormat) | VkFlags(ImageCreateFlagBits::eCubeCompatible) | VkFlags(ImageCreateFlagBits::eBindSfrKHX) | VkFlags(ImageCreateFlagBits::e2DArrayCompatibleKHR)\n    };\n  };\n\n  struct PhysicalDeviceImageFormatInfo2KHR\n  {\n    PhysicalDeviceImageFormatInfo2KHR( Format format_ = Format::eUndefined, ImageType type_ = ImageType::e1D, ImageTiling tiling_ = ImageTiling::eOptimal, ImageUsageFlags usage_ = ImageUsageFlags(), ImageCreateFlags flags_ = ImageCreateFlags() )\n      : sType( StructureType::ePhysicalDeviceImageFormatInfo2KHR )\n      , pNext( nullptr )\n      , format( format_ )\n      , type( type_ )\n      , tiling( tiling_ )\n      , usage( usage_ )\n      , flags( flags_ )\n    {\n    }\n\n    PhysicalDeviceImageFormatInfo2KHR( VkPhysicalDeviceImageFormatInfo2KHR const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PhysicalDeviceImageFormatInfo2KHR) );\n    }\n\n    PhysicalDeviceImageFormatInfo2KHR& operator=( VkPhysicalDeviceImageFormatInfo2KHR const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PhysicalDeviceImageFormatInfo2KHR) );\n      return *this;\n    }\n\n    PhysicalDeviceImageFormatInfo2KHR& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    PhysicalDeviceImageFormatInfo2KHR& setFormat( Format format_ )\n    {\n      format = format_;\n      return *this;\n    }\n\n    PhysicalDeviceImageFormatInfo2KHR& setType( ImageType type_ )\n    {\n      type = type_;\n      return *this;\n    }\n\n    PhysicalDeviceImageFormatInfo2KHR& setTiling( ImageTiling tiling_ )\n    {\n      tiling = tiling_;\n      return *this;\n    }\n\n    PhysicalDeviceImageFormatInfo2KHR& setUsage( ImageUsageFlags usage_ )\n    {\n      usage = usage_;\n      return *this;\n    }\n\n    PhysicalDeviceImageFormatInfo2KHR& setFlags( ImageCreateFlags flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    operator const VkPhysicalDeviceImageFormatInfo2KHR&() const\n    {\n      return *reinterpret_cast<const VkPhysicalDeviceImageFormatInfo2KHR*>(this);\n    }\n\n    bool operator==( PhysicalDeviceImageFormatInfo2KHR const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( format == rhs.format )\n          && ( type == rhs.type )\n          && ( tiling == rhs.tiling )\n          && ( usage == rhs.usage )\n          && ( flags == rhs.flags );\n    }\n\n    bool operator!=( PhysicalDeviceImageFormatInfo2KHR const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    Format format;\n    ImageType type;\n    ImageTiling tiling;\n    ImageUsageFlags usage;\n    ImageCreateFlags flags;\n  };\n  static_assert( sizeof( PhysicalDeviceImageFormatInfo2KHR ) == sizeof( VkPhysicalDeviceImageFormatInfo2KHR ), \"struct and wrapper have different size!\" );\n\n  enum class PipelineCreateFlagBits\n  {\n    eDisableOptimization = VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT,\n    eAllowDerivatives = VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT,\n    eDerivative = VK_PIPELINE_CREATE_DERIVATIVE_BIT,\n    eViewIndexFromDeviceIndexKHX = VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT_KHX,\n    eDispatchBaseKHX = VK_PIPELINE_CREATE_DISPATCH_BASE_KHX\n  };\n\n  using PipelineCreateFlags = Flags<PipelineCreateFlagBits, VkPipelineCreateFlags>;\n\n  VULKAN_HPP_INLINE PipelineCreateFlags operator|( PipelineCreateFlagBits bit0, PipelineCreateFlagBits bit1 )\n  {\n    return PipelineCreateFlags( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE PipelineCreateFlags operator~( PipelineCreateFlagBits bits )\n  {\n    return ~( PipelineCreateFlags( bits ) );\n  }\n\n  template <> struct FlagTraits<PipelineCreateFlagBits>\n  {\n    enum\n    {\n      allFlags = VkFlags(PipelineCreateFlagBits::eDisableOptimization) | VkFlags(PipelineCreateFlagBits::eAllowDerivatives) | VkFlags(PipelineCreateFlagBits::eDerivative) | VkFlags(PipelineCreateFlagBits::eViewIndexFromDeviceIndexKHX) | VkFlags(PipelineCreateFlagBits::eDispatchBaseKHX)\n    };\n  };\n\n  struct ComputePipelineCreateInfo\n  {\n    ComputePipelineCreateInfo( PipelineCreateFlags flags_ = PipelineCreateFlags(), PipelineShaderStageCreateInfo stage_ = PipelineShaderStageCreateInfo(), PipelineLayout layout_ = PipelineLayout(), Pipeline basePipelineHandle_ = Pipeline(), int32_t basePipelineIndex_ = 0 )\n      : sType( StructureType::eComputePipelineCreateInfo )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , stage( stage_ )\n      , layout( layout_ )\n      , basePipelineHandle( basePipelineHandle_ )\n      , basePipelineIndex( basePipelineIndex_ )\n    {\n    }\n\n    ComputePipelineCreateInfo( VkComputePipelineCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ComputePipelineCreateInfo) );\n    }\n\n    ComputePipelineCreateInfo& operator=( VkComputePipelineCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ComputePipelineCreateInfo) );\n      return *this;\n    }\n\n    ComputePipelineCreateInfo& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    ComputePipelineCreateInfo& setFlags( PipelineCreateFlags flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    ComputePipelineCreateInfo& setStage( PipelineShaderStageCreateInfo stage_ )\n    {\n      stage = stage_;\n      return *this;\n    }\n\n    ComputePipelineCreateInfo& setLayout( PipelineLayout layout_ )\n    {\n      layout = layout_;\n      return *this;\n    }\n\n    ComputePipelineCreateInfo& setBasePipelineHandle( Pipeline basePipelineHandle_ )\n    {\n      basePipelineHandle = basePipelineHandle_;\n      return *this;\n    }\n\n    ComputePipelineCreateInfo& setBasePipelineIndex( int32_t basePipelineIndex_ )\n    {\n      basePipelineIndex = basePipelineIndex_;\n      return *this;\n    }\n\n    operator const VkComputePipelineCreateInfo&() const\n    {\n      return *reinterpret_cast<const VkComputePipelineCreateInfo*>(this);\n    }\n\n    bool operator==( ComputePipelineCreateInfo const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( stage == rhs.stage )\n          && ( layout == rhs.layout )\n          && ( basePipelineHandle == rhs.basePipelineHandle )\n          && ( basePipelineIndex == rhs.basePipelineIndex );\n    }\n\n    bool operator!=( ComputePipelineCreateInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    PipelineCreateFlags flags;\n    PipelineShaderStageCreateInfo stage;\n    PipelineLayout layout;\n    Pipeline basePipelineHandle;\n    int32_t basePipelineIndex;\n  };\n  static_assert( sizeof( ComputePipelineCreateInfo ) == sizeof( VkComputePipelineCreateInfo ), \"struct and wrapper have different size!\" );\n\n  enum class ColorComponentFlagBits\n  {\n    eR = VK_COLOR_COMPONENT_R_BIT,\n    eG = VK_COLOR_COMPONENT_G_BIT,\n    eB = VK_COLOR_COMPONENT_B_BIT,\n    eA = VK_COLOR_COMPONENT_A_BIT\n  };\n\n  using ColorComponentFlags = Flags<ColorComponentFlagBits, VkColorComponentFlags>;\n\n  VULKAN_HPP_INLINE ColorComponentFlags operator|( ColorComponentFlagBits bit0, ColorComponentFlagBits bit1 )\n  {\n    return ColorComponentFlags( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE ColorComponentFlags operator~( ColorComponentFlagBits bits )\n  {\n    return ~( ColorComponentFlags( bits ) );\n  }\n\n  template <> struct FlagTraits<ColorComponentFlagBits>\n  {\n    enum\n    {\n      allFlags = VkFlags(ColorComponentFlagBits::eR) | VkFlags(ColorComponentFlagBits::eG) | VkFlags(ColorComponentFlagBits::eB) | VkFlags(ColorComponentFlagBits::eA)\n    };\n  };\n\n  struct PipelineColorBlendAttachmentState\n  {\n    PipelineColorBlendAttachmentState( Bool32 blendEnable_ = 0, BlendFactor srcColorBlendFactor_ = BlendFactor::eZero, BlendFactor dstColorBlendFactor_ = BlendFactor::eZero, BlendOp colorBlendOp_ = BlendOp::eAdd, BlendFactor srcAlphaBlendFactor_ = BlendFactor::eZero, BlendFactor dstAlphaBlendFactor_ = BlendFactor::eZero, BlendOp alphaBlendOp_ = BlendOp::eAdd, ColorComponentFlags colorWriteMask_ = ColorComponentFlags() )\n      : blendEnable( blendEnable_ )\n      , srcColorBlendFactor( srcColorBlendFactor_ )\n      , dstColorBlendFactor( dstColorBlendFactor_ )\n      , colorBlendOp( colorBlendOp_ )\n      , srcAlphaBlendFactor( srcAlphaBlendFactor_ )\n      , dstAlphaBlendFactor( dstAlphaBlendFactor_ )\n      , alphaBlendOp( alphaBlendOp_ )\n      , colorWriteMask( colorWriteMask_ )\n    {\n    }\n\n    PipelineColorBlendAttachmentState( VkPipelineColorBlendAttachmentState const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PipelineColorBlendAttachmentState) );\n    }\n\n    PipelineColorBlendAttachmentState& operator=( VkPipelineColorBlendAttachmentState const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PipelineColorBlendAttachmentState) );\n      return *this;\n    }\n\n    PipelineColorBlendAttachmentState& setBlendEnable( Bool32 blendEnable_ )\n    {\n      blendEnable = blendEnable_;\n      return *this;\n    }\n\n    PipelineColorBlendAttachmentState& setSrcColorBlendFactor( BlendFactor srcColorBlendFactor_ )\n    {\n      srcColorBlendFactor = srcColorBlendFactor_;\n      return *this;\n    }\n\n    PipelineColorBlendAttachmentState& setDstColorBlendFactor( BlendFactor dstColorBlendFactor_ )\n    {\n      dstColorBlendFactor = dstColorBlendFactor_;\n      return *this;\n    }\n\n    PipelineColorBlendAttachmentState& setColorBlendOp( BlendOp colorBlendOp_ )\n    {\n      colorBlendOp = colorBlendOp_;\n      return *this;\n    }\n\n    PipelineColorBlendAttachmentState& setSrcAlphaBlendFactor( BlendFactor srcAlphaBlendFactor_ )\n    {\n      srcAlphaBlendFactor = srcAlphaBlendFactor_;\n      return *this;\n    }\n\n    PipelineColorBlendAttachmentState& setDstAlphaBlendFactor( BlendFactor dstAlphaBlendFactor_ )\n    {\n      dstAlphaBlendFactor = dstAlphaBlendFactor_;\n      return *this;\n    }\n\n    PipelineColorBlendAttachmentState& setAlphaBlendOp( BlendOp alphaBlendOp_ )\n    {\n      alphaBlendOp = alphaBlendOp_;\n      return *this;\n    }\n\n    PipelineColorBlendAttachmentState& setColorWriteMask( ColorComponentFlags colorWriteMask_ )\n    {\n      colorWriteMask = colorWriteMask_;\n      return *this;\n    }\n\n    operator const VkPipelineColorBlendAttachmentState&() const\n    {\n      return *reinterpret_cast<const VkPipelineColorBlendAttachmentState*>(this);\n    }\n\n    bool operator==( PipelineColorBlendAttachmentState const& rhs ) const\n    {\n      return ( blendEnable == rhs.blendEnable )\n          && ( srcColorBlendFactor == rhs.srcColorBlendFactor )\n          && ( dstColorBlendFactor == rhs.dstColorBlendFactor )\n          && ( colorBlendOp == rhs.colorBlendOp )\n          && ( srcAlphaBlendFactor == rhs.srcAlphaBlendFactor )\n          && ( dstAlphaBlendFactor == rhs.dstAlphaBlendFactor )\n          && ( alphaBlendOp == rhs.alphaBlendOp )\n          && ( colorWriteMask == rhs.colorWriteMask );\n    }\n\n    bool operator!=( PipelineColorBlendAttachmentState const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    Bool32 blendEnable;\n    BlendFactor srcColorBlendFactor;\n    BlendFactor dstColorBlendFactor;\n    BlendOp colorBlendOp;\n    BlendFactor srcAlphaBlendFactor;\n    BlendFactor dstAlphaBlendFactor;\n    BlendOp alphaBlendOp;\n    ColorComponentFlags colorWriteMask;\n  };\n  static_assert( sizeof( PipelineColorBlendAttachmentState ) == sizeof( VkPipelineColorBlendAttachmentState ), \"struct and wrapper have different size!\" );\n\n  struct PipelineColorBlendStateCreateInfo\n  {\n    PipelineColorBlendStateCreateInfo( PipelineColorBlendStateCreateFlags flags_ = PipelineColorBlendStateCreateFlags(), Bool32 logicOpEnable_ = 0, LogicOp logicOp_ = LogicOp::eClear, uint32_t attachmentCount_ = 0, const PipelineColorBlendAttachmentState* pAttachments_ = nullptr, std::array<float,4> const& blendConstants_ = { { 0, 0, 0, 0 } } )\n      : sType( StructureType::ePipelineColorBlendStateCreateInfo )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , logicOpEnable( logicOpEnable_ )\n      , logicOp( logicOp_ )\n      , attachmentCount( attachmentCount_ )\n      , pAttachments( pAttachments_ )\n    {\n      memcpy( &blendConstants, blendConstants_.data(), 4 * sizeof( float ) );\n    }\n\n    PipelineColorBlendStateCreateInfo( VkPipelineColorBlendStateCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PipelineColorBlendStateCreateInfo) );\n    }\n\n    PipelineColorBlendStateCreateInfo& operator=( VkPipelineColorBlendStateCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PipelineColorBlendStateCreateInfo) );\n      return *this;\n    }\n\n    PipelineColorBlendStateCreateInfo& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    PipelineColorBlendStateCreateInfo& setFlags( PipelineColorBlendStateCreateFlags flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    PipelineColorBlendStateCreateInfo& setLogicOpEnable( Bool32 logicOpEnable_ )\n    {\n      logicOpEnable = logicOpEnable_;\n      return *this;\n    }\n\n    PipelineColorBlendStateCreateInfo& setLogicOp( LogicOp logicOp_ )\n    {\n      logicOp = logicOp_;\n      return *this;\n    }\n\n    PipelineColorBlendStateCreateInfo& setAttachmentCount( uint32_t attachmentCount_ )\n    {\n      attachmentCount = attachmentCount_;\n      return *this;\n    }\n\n    PipelineColorBlendStateCreateInfo& setPAttachments( const PipelineColorBlendAttachmentState* pAttachments_ )\n    {\n      pAttachments = pAttachments_;\n      return *this;\n    }\n\n    PipelineColorBlendStateCreateInfo& setBlendConstants( std::array<float,4> blendConstants_ )\n    {\n      memcpy( &blendConstants, blendConstants_.data(), 4 * sizeof( float ) );\n      return *this;\n    }\n\n    operator const VkPipelineColorBlendStateCreateInfo&() const\n    {\n      return *reinterpret_cast<const VkPipelineColorBlendStateCreateInfo*>(this);\n    }\n\n    bool operator==( PipelineColorBlendStateCreateInfo const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( logicOpEnable == rhs.logicOpEnable )\n          && ( logicOp == rhs.logicOp )\n          && ( attachmentCount == rhs.attachmentCount )\n          && ( pAttachments == rhs.pAttachments )\n          && ( memcmp( blendConstants, rhs.blendConstants, 4 * sizeof( float ) ) == 0 );\n    }\n\n    bool operator!=( PipelineColorBlendStateCreateInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    PipelineColorBlendStateCreateFlags flags;\n    Bool32 logicOpEnable;\n    LogicOp logicOp;\n    uint32_t attachmentCount;\n    const PipelineColorBlendAttachmentState* pAttachments;\n    float blendConstants[4];\n  };\n  static_assert( sizeof( PipelineColorBlendStateCreateInfo ) == sizeof( VkPipelineColorBlendStateCreateInfo ), \"struct and wrapper have different size!\" );\n\n  enum class FenceCreateFlagBits\n  {\n    eSignaled = VK_FENCE_CREATE_SIGNALED_BIT\n  };\n\n  using FenceCreateFlags = Flags<FenceCreateFlagBits, VkFenceCreateFlags>;\n\n  VULKAN_HPP_INLINE FenceCreateFlags operator|( FenceCreateFlagBits bit0, FenceCreateFlagBits bit1 )\n  {\n    return FenceCreateFlags( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE FenceCreateFlags operator~( FenceCreateFlagBits bits )\n  {\n    return ~( FenceCreateFlags( bits ) );\n  }\n\n  template <> struct FlagTraits<FenceCreateFlagBits>\n  {\n    enum\n    {\n      allFlags = VkFlags(FenceCreateFlagBits::eSignaled)\n    };\n  };\n\n  struct FenceCreateInfo\n  {\n    FenceCreateInfo( FenceCreateFlags flags_ = FenceCreateFlags() )\n      : sType( StructureType::eFenceCreateInfo )\n      , pNext( nullptr )\n      , flags( flags_ )\n    {\n    }\n\n    FenceCreateInfo( VkFenceCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(FenceCreateInfo) );\n    }\n\n    FenceCreateInfo& operator=( VkFenceCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(FenceCreateInfo) );\n      return *this;\n    }\n\n    FenceCreateInfo& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    FenceCreateInfo& setFlags( FenceCreateFlags flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    operator const VkFenceCreateInfo&() const\n    {\n      return *reinterpret_cast<const VkFenceCreateInfo*>(this);\n    }\n\n    bool operator==( FenceCreateInfo const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags );\n    }\n\n    bool operator!=( FenceCreateInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    FenceCreateFlags flags;\n  };\n  static_assert( sizeof( FenceCreateInfo ) == sizeof( VkFenceCreateInfo ), \"struct and wrapper have different size!\" );\n\n  enum class FormatFeatureFlagBits\n  {\n    eSampledImage = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT,\n    eStorageImage = VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT,\n    eStorageImageAtomic = VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT,\n    eUniformTexelBuffer = VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT,\n    eStorageTexelBuffer = VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT,\n    eStorageTexelBufferAtomic = VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT,\n    eVertexBuffer = VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT,\n    eColorAttachment = VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT,\n    eColorAttachmentBlend = VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT,\n    eDepthStencilAttachment = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT,\n    eBlitSrc = VK_FORMAT_FEATURE_BLIT_SRC_BIT,\n    eBlitDst = VK_FORMAT_FEATURE_BLIT_DST_BIT,\n    eSampledImageFilterLinear = VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT,\n    eSampledImageFilterCubicIMG = VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG,\n    eTransferSrcKHR = VK_FORMAT_FEATURE_TRANSFER_SRC_BIT_KHR,\n    eTransferDstKHR = VK_FORMAT_FEATURE_TRANSFER_DST_BIT_KHR\n  };\n\n  using FormatFeatureFlags = Flags<FormatFeatureFlagBits, VkFormatFeatureFlags>;\n\n  VULKAN_HPP_INLINE FormatFeatureFlags operator|( FormatFeatureFlagBits bit0, FormatFeatureFlagBits bit1 )\n  {\n    return FormatFeatureFlags( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE FormatFeatureFlags operator~( FormatFeatureFlagBits bits )\n  {\n    return ~( FormatFeatureFlags( bits ) );\n  }\n\n  template <> struct FlagTraits<FormatFeatureFlagBits>\n  {\n    enum\n    {\n      allFlags = VkFlags(FormatFeatureFlagBits::eSampledImage) | VkFlags(FormatFeatureFlagBits::eStorageImage) | VkFlags(FormatFeatureFlagBits::eStorageImageAtomic) | VkFlags(FormatFeatureFlagBits::eUniformTexelBuffer) | VkFlags(FormatFeatureFlagBits::eStorageTexelBuffer) | VkFlags(FormatFeatureFlagBits::eStorageTexelBufferAtomic) | VkFlags(FormatFeatureFlagBits::eVertexBuffer) | VkFlags(FormatFeatureFlagBits::eColorAttachment) | VkFlags(FormatFeatureFlagBits::eColorAttachmentBlend) | VkFlags(FormatFeatureFlagBits::eDepthStencilAttachment) | VkFlags(FormatFeatureFlagBits::eBlitSrc) | VkFlags(FormatFeatureFlagBits::eBlitDst) | VkFlags(FormatFeatureFlagBits::eSampledImageFilterLinear) | VkFlags(FormatFeatureFlagBits::eSampledImageFilterCubicIMG) | VkFlags(FormatFeatureFlagBits::eTransferSrcKHR) | VkFlags(FormatFeatureFlagBits::eTransferDstKHR)\n    };\n  };\n\n  struct FormatProperties\n  {\n    operator const VkFormatProperties&() const\n    {\n      return *reinterpret_cast<const VkFormatProperties*>(this);\n    }\n\n    bool operator==( FormatProperties const& rhs ) const\n    {\n      return ( linearTilingFeatures == rhs.linearTilingFeatures )\n          && ( optimalTilingFeatures == rhs.optimalTilingFeatures )\n          && ( bufferFeatures == rhs.bufferFeatures );\n    }\n\n    bool operator!=( FormatProperties const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    FormatFeatureFlags linearTilingFeatures;\n    FormatFeatureFlags optimalTilingFeatures;\n    FormatFeatureFlags bufferFeatures;\n  };\n  static_assert( sizeof( FormatProperties ) == sizeof( VkFormatProperties ), \"struct and wrapper have different size!\" );\n\n  struct FormatProperties2KHR\n  {\n    operator const VkFormatProperties2KHR&() const\n    {\n      return *reinterpret_cast<const VkFormatProperties2KHR*>(this);\n    }\n\n    bool operator==( FormatProperties2KHR const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( formatProperties == rhs.formatProperties );\n    }\n\n    bool operator!=( FormatProperties2KHR const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    void* pNext;\n    FormatProperties formatProperties;\n  };\n  static_assert( sizeof( FormatProperties2KHR ) == sizeof( VkFormatProperties2KHR ), \"struct and wrapper have different size!\" );\n\n  enum class QueryControlFlagBits\n  {\n    ePrecise = VK_QUERY_CONTROL_PRECISE_BIT\n  };\n\n  using QueryControlFlags = Flags<QueryControlFlagBits, VkQueryControlFlags>;\n\n  VULKAN_HPP_INLINE QueryControlFlags operator|( QueryControlFlagBits bit0, QueryControlFlagBits bit1 )\n  {\n    return QueryControlFlags( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE QueryControlFlags operator~( QueryControlFlagBits bits )\n  {\n    return ~( QueryControlFlags( bits ) );\n  }\n\n  template <> struct FlagTraits<QueryControlFlagBits>\n  {\n    enum\n    {\n      allFlags = VkFlags(QueryControlFlagBits::ePrecise)\n    };\n  };\n\n  enum class QueryResultFlagBits\n  {\n    e64 = VK_QUERY_RESULT_64_BIT,\n    eWait = VK_QUERY_RESULT_WAIT_BIT,\n    eWithAvailability = VK_QUERY_RESULT_WITH_AVAILABILITY_BIT,\n    ePartial = VK_QUERY_RESULT_PARTIAL_BIT\n  };\n\n  using QueryResultFlags = Flags<QueryResultFlagBits, VkQueryResultFlags>;\n\n  VULKAN_HPP_INLINE QueryResultFlags operator|( QueryResultFlagBits bit0, QueryResultFlagBits bit1 )\n  {\n    return QueryResultFlags( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE QueryResultFlags operator~( QueryResultFlagBits bits )\n  {\n    return ~( QueryResultFlags( bits ) );\n  }\n\n  template <> struct FlagTraits<QueryResultFlagBits>\n  {\n    enum\n    {\n      allFlags = VkFlags(QueryResultFlagBits::e64) | VkFlags(QueryResultFlagBits::eWait) | VkFlags(QueryResultFlagBits::eWithAvailability) | VkFlags(QueryResultFlagBits::ePartial)\n    };\n  };\n\n  enum class CommandBufferUsageFlagBits\n  {\n    eOneTimeSubmit = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,\n    eRenderPassContinue = VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT,\n    eSimultaneousUse = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT\n  };\n\n  using CommandBufferUsageFlags = Flags<CommandBufferUsageFlagBits, VkCommandBufferUsageFlags>;\n\n  VULKAN_HPP_INLINE CommandBufferUsageFlags operator|( CommandBufferUsageFlagBits bit0, CommandBufferUsageFlagBits bit1 )\n  {\n    return CommandBufferUsageFlags( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE CommandBufferUsageFlags operator~( CommandBufferUsageFlagBits bits )\n  {\n    return ~( CommandBufferUsageFlags( bits ) );\n  }\n\n  template <> struct FlagTraits<CommandBufferUsageFlagBits>\n  {\n    enum\n    {\n      allFlags = VkFlags(CommandBufferUsageFlagBits::eOneTimeSubmit) | VkFlags(CommandBufferUsageFlagBits::eRenderPassContinue) | VkFlags(CommandBufferUsageFlagBits::eSimultaneousUse)\n    };\n  };\n\n  enum class QueryPipelineStatisticFlagBits\n  {\n    eInputAssemblyVertices = VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT,\n    eInputAssemblyPrimitives = VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT,\n    eVertexShaderInvocations = VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT,\n    eGeometryShaderInvocations = VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_INVOCATIONS_BIT,\n    eGeometryShaderPrimitives = VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT,\n    eClippingInvocations = VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT,\n    eClippingPrimitives = VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT,\n    eFragmentShaderInvocations = VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT,\n    eTessellationControlShaderPatches = VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT,\n    eTessellationEvaluationShaderInvocations = VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT,\n    eComputeShaderInvocations = VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT\n  };\n\n  using QueryPipelineStatisticFlags = Flags<QueryPipelineStatisticFlagBits, VkQueryPipelineStatisticFlags>;\n\n  VULKAN_HPP_INLINE QueryPipelineStatisticFlags operator|( QueryPipelineStatisticFlagBits bit0, QueryPipelineStatisticFlagBits bit1 )\n  {\n    return QueryPipelineStatisticFlags( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE QueryPipelineStatisticFlags operator~( QueryPipelineStatisticFlagBits bits )\n  {\n    return ~( QueryPipelineStatisticFlags( bits ) );\n  }\n\n  template <> struct FlagTraits<QueryPipelineStatisticFlagBits>\n  {\n    enum\n    {\n      allFlags = VkFlags(QueryPipelineStatisticFlagBits::eInputAssemblyVertices) | VkFlags(QueryPipelineStatisticFlagBits::eInputAssemblyPrimitives) | VkFlags(QueryPipelineStatisticFlagBits::eVertexShaderInvocations) | VkFlags(QueryPipelineStatisticFlagBits::eGeometryShaderInvocations) | VkFlags(QueryPipelineStatisticFlagBits::eGeometryShaderPrimitives) | VkFlags(QueryPipelineStatisticFlagBits::eClippingInvocations) | VkFlags(QueryPipelineStatisticFlagBits::eClippingPrimitives) | VkFlags(QueryPipelineStatisticFlagBits::eFragmentShaderInvocations) | VkFlags(QueryPipelineStatisticFlagBits::eTessellationControlShaderPatches) | VkFlags(QueryPipelineStatisticFlagBits::eTessellationEvaluationShaderInvocations) | VkFlags(QueryPipelineStatisticFlagBits::eComputeShaderInvocations)\n    };\n  };\n\n  struct CommandBufferInheritanceInfo\n  {\n    CommandBufferInheritanceInfo( RenderPass renderPass_ = RenderPass(), uint32_t subpass_ = 0, Framebuffer framebuffer_ = Framebuffer(), Bool32 occlusionQueryEnable_ = 0, QueryControlFlags queryFlags_ = QueryControlFlags(), QueryPipelineStatisticFlags pipelineStatistics_ = QueryPipelineStatisticFlags() )\n      : sType( StructureType::eCommandBufferInheritanceInfo )\n      , pNext( nullptr )\n      , renderPass( renderPass_ )\n      , subpass( subpass_ )\n      , framebuffer( framebuffer_ )\n      , occlusionQueryEnable( occlusionQueryEnable_ )\n      , queryFlags( queryFlags_ )\n      , pipelineStatistics( pipelineStatistics_ )\n    {\n    }\n\n    CommandBufferInheritanceInfo( VkCommandBufferInheritanceInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(CommandBufferInheritanceInfo) );\n    }\n\n    CommandBufferInheritanceInfo& operator=( VkCommandBufferInheritanceInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(CommandBufferInheritanceInfo) );\n      return *this;\n    }\n\n    CommandBufferInheritanceInfo& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    CommandBufferInheritanceInfo& setRenderPass( RenderPass renderPass_ )\n    {\n      renderPass = renderPass_;\n      return *this;\n    }\n\n    CommandBufferInheritanceInfo& setSubpass( uint32_t subpass_ )\n    {\n      subpass = subpass_;\n      return *this;\n    }\n\n    CommandBufferInheritanceInfo& setFramebuffer( Framebuffer framebuffer_ )\n    {\n      framebuffer = framebuffer_;\n      return *this;\n    }\n\n    CommandBufferInheritanceInfo& setOcclusionQueryEnable( Bool32 occlusionQueryEnable_ )\n    {\n      occlusionQueryEnable = occlusionQueryEnable_;\n      return *this;\n    }\n\n    CommandBufferInheritanceInfo& setQueryFlags( QueryControlFlags queryFlags_ )\n    {\n      queryFlags = queryFlags_;\n      return *this;\n    }\n\n    CommandBufferInheritanceInfo& setPipelineStatistics( QueryPipelineStatisticFlags pipelineStatistics_ )\n    {\n      pipelineStatistics = pipelineStatistics_;\n      return *this;\n    }\n\n    operator const VkCommandBufferInheritanceInfo&() const\n    {\n      return *reinterpret_cast<const VkCommandBufferInheritanceInfo*>(this);\n    }\n\n    bool operator==( CommandBufferInheritanceInfo const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( renderPass == rhs.renderPass )\n          && ( subpass == rhs.subpass )\n          && ( framebuffer == rhs.framebuffer )\n          && ( occlusionQueryEnable == rhs.occlusionQueryEnable )\n          && ( queryFlags == rhs.queryFlags )\n          && ( pipelineStatistics == rhs.pipelineStatistics );\n    }\n\n    bool operator!=( CommandBufferInheritanceInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    RenderPass renderPass;\n    uint32_t subpass;\n    Framebuffer framebuffer;\n    Bool32 occlusionQueryEnable;\n    QueryControlFlags queryFlags;\n    QueryPipelineStatisticFlags pipelineStatistics;\n  };\n  static_assert( sizeof( CommandBufferInheritanceInfo ) == sizeof( VkCommandBufferInheritanceInfo ), \"struct and wrapper have different size!\" );\n\n  struct CommandBufferBeginInfo\n  {\n    CommandBufferBeginInfo( CommandBufferUsageFlags flags_ = CommandBufferUsageFlags(), const CommandBufferInheritanceInfo* pInheritanceInfo_ = nullptr )\n      : sType( StructureType::eCommandBufferBeginInfo )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , pInheritanceInfo( pInheritanceInfo_ )\n    {\n    }\n\n    CommandBufferBeginInfo( VkCommandBufferBeginInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(CommandBufferBeginInfo) );\n    }\n\n    CommandBufferBeginInfo& operator=( VkCommandBufferBeginInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(CommandBufferBeginInfo) );\n      return *this;\n    }\n\n    CommandBufferBeginInfo& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    CommandBufferBeginInfo& setFlags( CommandBufferUsageFlags flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    CommandBufferBeginInfo& setPInheritanceInfo( const CommandBufferInheritanceInfo* pInheritanceInfo_ )\n    {\n      pInheritanceInfo = pInheritanceInfo_;\n      return *this;\n    }\n\n    operator const VkCommandBufferBeginInfo&() const\n    {\n      return *reinterpret_cast<const VkCommandBufferBeginInfo*>(this);\n    }\n\n    bool operator==( CommandBufferBeginInfo const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( pInheritanceInfo == rhs.pInheritanceInfo );\n    }\n\n    bool operator!=( CommandBufferBeginInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    CommandBufferUsageFlags flags;\n    const CommandBufferInheritanceInfo* pInheritanceInfo;\n  };\n  static_assert( sizeof( CommandBufferBeginInfo ) == sizeof( VkCommandBufferBeginInfo ), \"struct and wrapper have different size!\" );\n\n  struct QueryPoolCreateInfo\n  {\n    QueryPoolCreateInfo( QueryPoolCreateFlags flags_ = QueryPoolCreateFlags(), QueryType queryType_ = QueryType::eOcclusion, uint32_t queryCount_ = 0, QueryPipelineStatisticFlags pipelineStatistics_ = QueryPipelineStatisticFlags() )\n      : sType( StructureType::eQueryPoolCreateInfo )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , queryType( queryType_ )\n      , queryCount( queryCount_ )\n      , pipelineStatistics( pipelineStatistics_ )\n    {\n    }\n\n    QueryPoolCreateInfo( VkQueryPoolCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(QueryPoolCreateInfo) );\n    }\n\n    QueryPoolCreateInfo& operator=( VkQueryPoolCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(QueryPoolCreateInfo) );\n      return *this;\n    }\n\n    QueryPoolCreateInfo& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    QueryPoolCreateInfo& setFlags( QueryPoolCreateFlags flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    QueryPoolCreateInfo& setQueryType( QueryType queryType_ )\n    {\n      queryType = queryType_;\n      return *this;\n    }\n\n    QueryPoolCreateInfo& setQueryCount( uint32_t queryCount_ )\n    {\n      queryCount = queryCount_;\n      return *this;\n    }\n\n    QueryPoolCreateInfo& setPipelineStatistics( QueryPipelineStatisticFlags pipelineStatistics_ )\n    {\n      pipelineStatistics = pipelineStatistics_;\n      return *this;\n    }\n\n    operator const VkQueryPoolCreateInfo&() const\n    {\n      return *reinterpret_cast<const VkQueryPoolCreateInfo*>(this);\n    }\n\n    bool operator==( QueryPoolCreateInfo const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( queryType == rhs.queryType )\n          && ( queryCount == rhs.queryCount )\n          && ( pipelineStatistics == rhs.pipelineStatistics );\n    }\n\n    bool operator!=( QueryPoolCreateInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    QueryPoolCreateFlags flags;\n    QueryType queryType;\n    uint32_t queryCount;\n    QueryPipelineStatisticFlags pipelineStatistics;\n  };\n  static_assert( sizeof( QueryPoolCreateInfo ) == sizeof( VkQueryPoolCreateInfo ), \"struct and wrapper have different size!\" );\n\n  enum class ImageAspectFlagBits\n  {\n    eColor = VK_IMAGE_ASPECT_COLOR_BIT,\n    eDepth = VK_IMAGE_ASPECT_DEPTH_BIT,\n    eStencil = VK_IMAGE_ASPECT_STENCIL_BIT,\n    eMetadata = VK_IMAGE_ASPECT_METADATA_BIT\n  };\n\n  using ImageAspectFlags = Flags<ImageAspectFlagBits, VkImageAspectFlags>;\n\n  VULKAN_HPP_INLINE ImageAspectFlags operator|( ImageAspectFlagBits bit0, ImageAspectFlagBits bit1 )\n  {\n    return ImageAspectFlags( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE ImageAspectFlags operator~( ImageAspectFlagBits bits )\n  {\n    return ~( ImageAspectFlags( bits ) );\n  }\n\n  template <> struct FlagTraits<ImageAspectFlagBits>\n  {\n    enum\n    {\n      allFlags = VkFlags(ImageAspectFlagBits::eColor) | VkFlags(ImageAspectFlagBits::eDepth) | VkFlags(ImageAspectFlagBits::eStencil) | VkFlags(ImageAspectFlagBits::eMetadata)\n    };\n  };\n\n  struct ImageSubresource\n  {\n    ImageSubresource( ImageAspectFlags aspectMask_ = ImageAspectFlags(), uint32_t mipLevel_ = 0, uint32_t arrayLayer_ = 0 )\n      : aspectMask( aspectMask_ )\n      , mipLevel( mipLevel_ )\n      , arrayLayer( arrayLayer_ )\n    {\n    }\n\n    ImageSubresource( VkImageSubresource const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ImageSubresource) );\n    }\n\n    ImageSubresource& operator=( VkImageSubresource const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ImageSubresource) );\n      return *this;\n    }\n\n    ImageSubresource& setAspectMask( ImageAspectFlags aspectMask_ )\n    {\n      aspectMask = aspectMask_;\n      return *this;\n    }\n\n    ImageSubresource& setMipLevel( uint32_t mipLevel_ )\n    {\n      mipLevel = mipLevel_;\n      return *this;\n    }\n\n    ImageSubresource& setArrayLayer( uint32_t arrayLayer_ )\n    {\n      arrayLayer = arrayLayer_;\n      return *this;\n    }\n\n    operator const VkImageSubresource&() const\n    {\n      return *reinterpret_cast<const VkImageSubresource*>(this);\n    }\n\n    bool operator==( ImageSubresource const& rhs ) const\n    {\n      return ( aspectMask == rhs.aspectMask )\n          && ( mipLevel == rhs.mipLevel )\n          && ( arrayLayer == rhs.arrayLayer );\n    }\n\n    bool operator!=( ImageSubresource const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    ImageAspectFlags aspectMask;\n    uint32_t mipLevel;\n    uint32_t arrayLayer;\n  };\n  static_assert( sizeof( ImageSubresource ) == sizeof( VkImageSubresource ), \"struct and wrapper have different size!\" );\n\n  struct ImageSubresourceLayers\n  {\n    ImageSubresourceLayers( ImageAspectFlags aspectMask_ = ImageAspectFlags(), uint32_t mipLevel_ = 0, uint32_t baseArrayLayer_ = 0, uint32_t layerCount_ = 0 )\n      : aspectMask( aspectMask_ )\n      , mipLevel( mipLevel_ )\n      , baseArrayLayer( baseArrayLayer_ )\n      , layerCount( layerCount_ )\n    {\n    }\n\n    ImageSubresourceLayers( VkImageSubresourceLayers const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ImageSubresourceLayers) );\n    }\n\n    ImageSubresourceLayers& operator=( VkImageSubresourceLayers const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ImageSubresourceLayers) );\n      return *this;\n    }\n\n    ImageSubresourceLayers& setAspectMask( ImageAspectFlags aspectMask_ )\n    {\n      aspectMask = aspectMask_;\n      return *this;\n    }\n\n    ImageSubresourceLayers& setMipLevel( uint32_t mipLevel_ )\n    {\n      mipLevel = mipLevel_;\n      return *this;\n    }\n\n    ImageSubresourceLayers& setBaseArrayLayer( uint32_t baseArrayLayer_ )\n    {\n      baseArrayLayer = baseArrayLayer_;\n      return *this;\n    }\n\n    ImageSubresourceLayers& setLayerCount( uint32_t layerCount_ )\n    {\n      layerCount = layerCount_;\n      return *this;\n    }\n\n    operator const VkImageSubresourceLayers&() const\n    {\n      return *reinterpret_cast<const VkImageSubresourceLayers*>(this);\n    }\n\n    bool operator==( ImageSubresourceLayers const& rhs ) const\n    {\n      return ( aspectMask == rhs.aspectMask )\n          && ( mipLevel == rhs.mipLevel )\n          && ( baseArrayLayer == rhs.baseArrayLayer )\n          && ( layerCount == rhs.layerCount );\n    }\n\n    bool operator!=( ImageSubresourceLayers const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    ImageAspectFlags aspectMask;\n    uint32_t mipLevel;\n    uint32_t baseArrayLayer;\n    uint32_t layerCount;\n  };\n  static_assert( sizeof( ImageSubresourceLayers ) == sizeof( VkImageSubresourceLayers ), \"struct and wrapper have different size!\" );\n\n  struct ImageSubresourceRange\n  {\n    ImageSubresourceRange( ImageAspectFlags aspectMask_ = ImageAspectFlags(), uint32_t baseMipLevel_ = 0, uint32_t levelCount_ = 0, uint32_t baseArrayLayer_ = 0, uint32_t layerCount_ = 0 )\n      : aspectMask( aspectMask_ )\n      , baseMipLevel( baseMipLevel_ )\n      , levelCount( levelCount_ )\n      , baseArrayLayer( baseArrayLayer_ )\n      , layerCount( layerCount_ )\n    {\n    }\n\n    ImageSubresourceRange( VkImageSubresourceRange const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ImageSubresourceRange) );\n    }\n\n    ImageSubresourceRange& operator=( VkImageSubresourceRange const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ImageSubresourceRange) );\n      return *this;\n    }\n\n    ImageSubresourceRange& setAspectMask( ImageAspectFlags aspectMask_ )\n    {\n      aspectMask = aspectMask_;\n      return *this;\n    }\n\n    ImageSubresourceRange& setBaseMipLevel( uint32_t baseMipLevel_ )\n    {\n      baseMipLevel = baseMipLevel_;\n      return *this;\n    }\n\n    ImageSubresourceRange& setLevelCount( uint32_t levelCount_ )\n    {\n      levelCount = levelCount_;\n      return *this;\n    }\n\n    ImageSubresourceRange& setBaseArrayLayer( uint32_t baseArrayLayer_ )\n    {\n      baseArrayLayer = baseArrayLayer_;\n      return *this;\n    }\n\n    ImageSubresourceRange& setLayerCount( uint32_t layerCount_ )\n    {\n      layerCount = layerCount_;\n      return *this;\n    }\n\n    operator const VkImageSubresourceRange&() const\n    {\n      return *reinterpret_cast<const VkImageSubresourceRange*>(this);\n    }\n\n    bool operator==( ImageSubresourceRange const& rhs ) const\n    {\n      return ( aspectMask == rhs.aspectMask )\n          && ( baseMipLevel == rhs.baseMipLevel )\n          && ( levelCount == rhs.levelCount )\n          && ( baseArrayLayer == rhs.baseArrayLayer )\n          && ( layerCount == rhs.layerCount );\n    }\n\n    bool operator!=( ImageSubresourceRange const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    ImageAspectFlags aspectMask;\n    uint32_t baseMipLevel;\n    uint32_t levelCount;\n    uint32_t baseArrayLayer;\n    uint32_t layerCount;\n  };\n  static_assert( sizeof( ImageSubresourceRange ) == sizeof( VkImageSubresourceRange ), \"struct and wrapper have different size!\" );\n\n  struct ImageMemoryBarrier\n  {\n    ImageMemoryBarrier( AccessFlags srcAccessMask_ = AccessFlags(), AccessFlags dstAccessMask_ = AccessFlags(), ImageLayout oldLayout_ = ImageLayout::eUndefined, ImageLayout newLayout_ = ImageLayout::eUndefined, uint32_t srcQueueFamilyIndex_ = 0, uint32_t dstQueueFamilyIndex_ = 0, Image image_ = Image(), ImageSubresourceRange subresourceRange_ = ImageSubresourceRange() )\n      : sType( StructureType::eImageMemoryBarrier )\n      , pNext( nullptr )\n      , srcAccessMask( srcAccessMask_ )\n      , dstAccessMask( dstAccessMask_ )\n      , oldLayout( oldLayout_ )\n      , newLayout( newLayout_ )\n      , srcQueueFamilyIndex( srcQueueFamilyIndex_ )\n      , dstQueueFamilyIndex( dstQueueFamilyIndex_ )\n      , image( image_ )\n      , subresourceRange( subresourceRange_ )\n    {\n    }\n\n    ImageMemoryBarrier( VkImageMemoryBarrier const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ImageMemoryBarrier) );\n    }\n\n    ImageMemoryBarrier& operator=( VkImageMemoryBarrier const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ImageMemoryBarrier) );\n      return *this;\n    }\n\n    ImageMemoryBarrier& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    ImageMemoryBarrier& setSrcAccessMask( AccessFlags srcAccessMask_ )\n    {\n      srcAccessMask = srcAccessMask_;\n      return *this;\n    }\n\n    ImageMemoryBarrier& setDstAccessMask( AccessFlags dstAccessMask_ )\n    {\n      dstAccessMask = dstAccessMask_;\n      return *this;\n    }\n\n    ImageMemoryBarrier& setOldLayout( ImageLayout oldLayout_ )\n    {\n      oldLayout = oldLayout_;\n      return *this;\n    }\n\n    ImageMemoryBarrier& setNewLayout( ImageLayout newLayout_ )\n    {\n      newLayout = newLayout_;\n      return *this;\n    }\n\n    ImageMemoryBarrier& setSrcQueueFamilyIndex( uint32_t srcQueueFamilyIndex_ )\n    {\n      srcQueueFamilyIndex = srcQueueFamilyIndex_;\n      return *this;\n    }\n\n    ImageMemoryBarrier& setDstQueueFamilyIndex( uint32_t dstQueueFamilyIndex_ )\n    {\n      dstQueueFamilyIndex = dstQueueFamilyIndex_;\n      return *this;\n    }\n\n    ImageMemoryBarrier& setImage( Image image_ )\n    {\n      image = image_;\n      return *this;\n    }\n\n    ImageMemoryBarrier& setSubresourceRange( ImageSubresourceRange subresourceRange_ )\n    {\n      subresourceRange = subresourceRange_;\n      return *this;\n    }\n\n    operator const VkImageMemoryBarrier&() const\n    {\n      return *reinterpret_cast<const VkImageMemoryBarrier*>(this);\n    }\n\n    bool operator==( ImageMemoryBarrier const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( srcAccessMask == rhs.srcAccessMask )\n          && ( dstAccessMask == rhs.dstAccessMask )\n          && ( oldLayout == rhs.oldLayout )\n          && ( newLayout == rhs.newLayout )\n          && ( srcQueueFamilyIndex == rhs.srcQueueFamilyIndex )\n          && ( dstQueueFamilyIndex == rhs.dstQueueFamilyIndex )\n          && ( image == rhs.image )\n          && ( subresourceRange == rhs.subresourceRange );\n    }\n\n    bool operator!=( ImageMemoryBarrier const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    AccessFlags srcAccessMask;\n    AccessFlags dstAccessMask;\n    ImageLayout oldLayout;\n    ImageLayout newLayout;\n    uint32_t srcQueueFamilyIndex;\n    uint32_t dstQueueFamilyIndex;\n    Image image;\n    ImageSubresourceRange subresourceRange;\n  };\n  static_assert( sizeof( ImageMemoryBarrier ) == sizeof( VkImageMemoryBarrier ), \"struct and wrapper have different size!\" );\n\n  struct ImageViewCreateInfo\n  {\n    ImageViewCreateInfo( ImageViewCreateFlags flags_ = ImageViewCreateFlags(), Image image_ = Image(), ImageViewType viewType_ = ImageViewType::e1D, Format format_ = Format::eUndefined, ComponentMapping components_ = ComponentMapping(), ImageSubresourceRange subresourceRange_ = ImageSubresourceRange() )\n      : sType( StructureType::eImageViewCreateInfo )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , image( image_ )\n      , viewType( viewType_ )\n      , format( format_ )\n      , components( components_ )\n      , subresourceRange( subresourceRange_ )\n    {\n    }\n\n    ImageViewCreateInfo( VkImageViewCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ImageViewCreateInfo) );\n    }\n\n    ImageViewCreateInfo& operator=( VkImageViewCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ImageViewCreateInfo) );\n      return *this;\n    }\n\n    ImageViewCreateInfo& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    ImageViewCreateInfo& setFlags( ImageViewCreateFlags flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    ImageViewCreateInfo& setImage( Image image_ )\n    {\n      image = image_;\n      return *this;\n    }\n\n    ImageViewCreateInfo& setViewType( ImageViewType viewType_ )\n    {\n      viewType = viewType_;\n      return *this;\n    }\n\n    ImageViewCreateInfo& setFormat( Format format_ )\n    {\n      format = format_;\n      return *this;\n    }\n\n    ImageViewCreateInfo& setComponents( ComponentMapping components_ )\n    {\n      components = components_;\n      return *this;\n    }\n\n    ImageViewCreateInfo& setSubresourceRange( ImageSubresourceRange subresourceRange_ )\n    {\n      subresourceRange = subresourceRange_;\n      return *this;\n    }\n\n    operator const VkImageViewCreateInfo&() const\n    {\n      return *reinterpret_cast<const VkImageViewCreateInfo*>(this);\n    }\n\n    bool operator==( ImageViewCreateInfo const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( image == rhs.image )\n          && ( viewType == rhs.viewType )\n          && ( format == rhs.format )\n          && ( components == rhs.components )\n          && ( subresourceRange == rhs.subresourceRange );\n    }\n\n    bool operator!=( ImageViewCreateInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    ImageViewCreateFlags flags;\n    Image image;\n    ImageViewType viewType;\n    Format format;\n    ComponentMapping components;\n    ImageSubresourceRange subresourceRange;\n  };\n  static_assert( sizeof( ImageViewCreateInfo ) == sizeof( VkImageViewCreateInfo ), \"struct and wrapper have different size!\" );\n\n  struct ImageCopy\n  {\n    ImageCopy( ImageSubresourceLayers srcSubresource_ = ImageSubresourceLayers(), Offset3D srcOffset_ = Offset3D(), ImageSubresourceLayers dstSubresource_ = ImageSubresourceLayers(), Offset3D dstOffset_ = Offset3D(), Extent3D extent_ = Extent3D() )\n      : srcSubresource( srcSubresource_ )\n      , srcOffset( srcOffset_ )\n      , dstSubresource( dstSubresource_ )\n      , dstOffset( dstOffset_ )\n      , extent( extent_ )\n    {\n    }\n\n    ImageCopy( VkImageCopy const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ImageCopy) );\n    }\n\n    ImageCopy& operator=( VkImageCopy const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ImageCopy) );\n      return *this;\n    }\n\n    ImageCopy& setSrcSubresource( ImageSubresourceLayers srcSubresource_ )\n    {\n      srcSubresource = srcSubresource_;\n      return *this;\n    }\n\n    ImageCopy& setSrcOffset( Offset3D srcOffset_ )\n    {\n      srcOffset = srcOffset_;\n      return *this;\n    }\n\n    ImageCopy& setDstSubresource( ImageSubresourceLayers dstSubresource_ )\n    {\n      dstSubresource = dstSubresource_;\n      return *this;\n    }\n\n    ImageCopy& setDstOffset( Offset3D dstOffset_ )\n    {\n      dstOffset = dstOffset_;\n      return *this;\n    }\n\n    ImageCopy& setExtent( Extent3D extent_ )\n    {\n      extent = extent_;\n      return *this;\n    }\n\n    operator const VkImageCopy&() const\n    {\n      return *reinterpret_cast<const VkImageCopy*>(this);\n    }\n\n    bool operator==( ImageCopy const& rhs ) const\n    {\n      return ( srcSubresource == rhs.srcSubresource )\n          && ( srcOffset == rhs.srcOffset )\n          && ( dstSubresource == rhs.dstSubresource )\n          && ( dstOffset == rhs.dstOffset )\n          && ( extent == rhs.extent );\n    }\n\n    bool operator!=( ImageCopy const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    ImageSubresourceLayers srcSubresource;\n    Offset3D srcOffset;\n    ImageSubresourceLayers dstSubresource;\n    Offset3D dstOffset;\n    Extent3D extent;\n  };\n  static_assert( sizeof( ImageCopy ) == sizeof( VkImageCopy ), \"struct and wrapper have different size!\" );\n\n  struct ImageBlit\n  {\n    ImageBlit( ImageSubresourceLayers srcSubresource_ = ImageSubresourceLayers(), std::array<Offset3D,2> const& srcOffsets_ = { { Offset3D(), Offset3D() } }, ImageSubresourceLayers dstSubresource_ = ImageSubresourceLayers(), std::array<Offset3D,2> const& dstOffsets_ = { { Offset3D(), Offset3D() } } )\n      : srcSubresource( srcSubresource_ )\n      , dstSubresource( dstSubresource_ )\n    {\n      memcpy( &srcOffsets, srcOffsets_.data(), 2 * sizeof( Offset3D ) );\n      memcpy( &dstOffsets, dstOffsets_.data(), 2 * sizeof( Offset3D ) );\n    }\n\n    ImageBlit( VkImageBlit const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ImageBlit) );\n    }\n\n    ImageBlit& operator=( VkImageBlit const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ImageBlit) );\n      return *this;\n    }\n\n    ImageBlit& setSrcSubresource( ImageSubresourceLayers srcSubresource_ )\n    {\n      srcSubresource = srcSubresource_;\n      return *this;\n    }\n\n    ImageBlit& setSrcOffsets( std::array<Offset3D,2> srcOffsets_ )\n    {\n      memcpy( &srcOffsets, srcOffsets_.data(), 2 * sizeof( Offset3D ) );\n      return *this;\n    }\n\n    ImageBlit& setDstSubresource( ImageSubresourceLayers dstSubresource_ )\n    {\n      dstSubresource = dstSubresource_;\n      return *this;\n    }\n\n    ImageBlit& setDstOffsets( std::array<Offset3D,2> dstOffsets_ )\n    {\n      memcpy( &dstOffsets, dstOffsets_.data(), 2 * sizeof( Offset3D ) );\n      return *this;\n    }\n\n    operator const VkImageBlit&() const\n    {\n      return *reinterpret_cast<const VkImageBlit*>(this);\n    }\n\n    bool operator==( ImageBlit const& rhs ) const\n    {\n      return ( srcSubresource == rhs.srcSubresource )\n          && ( memcmp( srcOffsets, rhs.srcOffsets, 2 * sizeof( Offset3D ) ) == 0 )\n          && ( dstSubresource == rhs.dstSubresource )\n          && ( memcmp( dstOffsets, rhs.dstOffsets, 2 * sizeof( Offset3D ) ) == 0 );\n    }\n\n    bool operator!=( ImageBlit const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    ImageSubresourceLayers srcSubresource;\n    Offset3D srcOffsets[2];\n    ImageSubresourceLayers dstSubresource;\n    Offset3D dstOffsets[2];\n  };\n  static_assert( sizeof( ImageBlit ) == sizeof( VkImageBlit ), \"struct and wrapper have different size!\" );\n\n  struct BufferImageCopy\n  {\n    BufferImageCopy( DeviceSize bufferOffset_ = 0, uint32_t bufferRowLength_ = 0, uint32_t bufferImageHeight_ = 0, ImageSubresourceLayers imageSubresource_ = ImageSubresourceLayers(), Offset3D imageOffset_ = Offset3D(), Extent3D imageExtent_ = Extent3D() )\n      : bufferOffset( bufferOffset_ )\n      , bufferRowLength( bufferRowLength_ )\n      , bufferImageHeight( bufferImageHeight_ )\n      , imageSubresource( imageSubresource_ )\n      , imageOffset( imageOffset_ )\n      , imageExtent( imageExtent_ )\n    {\n    }\n\n    BufferImageCopy( VkBufferImageCopy const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(BufferImageCopy) );\n    }\n\n    BufferImageCopy& operator=( VkBufferImageCopy const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(BufferImageCopy) );\n      return *this;\n    }\n\n    BufferImageCopy& setBufferOffset( DeviceSize bufferOffset_ )\n    {\n      bufferOffset = bufferOffset_;\n      return *this;\n    }\n\n    BufferImageCopy& setBufferRowLength( uint32_t bufferRowLength_ )\n    {\n      bufferRowLength = bufferRowLength_;\n      return *this;\n    }\n\n    BufferImageCopy& setBufferImageHeight( uint32_t bufferImageHeight_ )\n    {\n      bufferImageHeight = bufferImageHeight_;\n      return *this;\n    }\n\n    BufferImageCopy& setImageSubresource( ImageSubresourceLayers imageSubresource_ )\n    {\n      imageSubresource = imageSubresource_;\n      return *this;\n    }\n\n    BufferImageCopy& setImageOffset( Offset3D imageOffset_ )\n    {\n      imageOffset = imageOffset_;\n      return *this;\n    }\n\n    BufferImageCopy& setImageExtent( Extent3D imageExtent_ )\n    {\n      imageExtent = imageExtent_;\n      return *this;\n    }\n\n    operator const VkBufferImageCopy&() const\n    {\n      return *reinterpret_cast<const VkBufferImageCopy*>(this);\n    }\n\n    bool operator==( BufferImageCopy const& rhs ) const\n    {\n      return ( bufferOffset == rhs.bufferOffset )\n          && ( bufferRowLength == rhs.bufferRowLength )\n          && ( bufferImageHeight == rhs.bufferImageHeight )\n          && ( imageSubresource == rhs.imageSubresource )\n          && ( imageOffset == rhs.imageOffset )\n          && ( imageExtent == rhs.imageExtent );\n    }\n\n    bool operator!=( BufferImageCopy const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    DeviceSize bufferOffset;\n    uint32_t bufferRowLength;\n    uint32_t bufferImageHeight;\n    ImageSubresourceLayers imageSubresource;\n    Offset3D imageOffset;\n    Extent3D imageExtent;\n  };\n  static_assert( sizeof( BufferImageCopy ) == sizeof( VkBufferImageCopy ), \"struct and wrapper have different size!\" );\n\n  struct ImageResolve\n  {\n    ImageResolve( ImageSubresourceLayers srcSubresource_ = ImageSubresourceLayers(), Offset3D srcOffset_ = Offset3D(), ImageSubresourceLayers dstSubresource_ = ImageSubresourceLayers(), Offset3D dstOffset_ = Offset3D(), Extent3D extent_ = Extent3D() )\n      : srcSubresource( srcSubresource_ )\n      , srcOffset( srcOffset_ )\n      , dstSubresource( dstSubresource_ )\n      , dstOffset( dstOffset_ )\n      , extent( extent_ )\n    {\n    }\n\n    ImageResolve( VkImageResolve const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ImageResolve) );\n    }\n\n    ImageResolve& operator=( VkImageResolve const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ImageResolve) );\n      return *this;\n    }\n\n    ImageResolve& setSrcSubresource( ImageSubresourceLayers srcSubresource_ )\n    {\n      srcSubresource = srcSubresource_;\n      return *this;\n    }\n\n    ImageResolve& setSrcOffset( Offset3D srcOffset_ )\n    {\n      srcOffset = srcOffset_;\n      return *this;\n    }\n\n    ImageResolve& setDstSubresource( ImageSubresourceLayers dstSubresource_ )\n    {\n      dstSubresource = dstSubresource_;\n      return *this;\n    }\n\n    ImageResolve& setDstOffset( Offset3D dstOffset_ )\n    {\n      dstOffset = dstOffset_;\n      return *this;\n    }\n\n    ImageResolve& setExtent( Extent3D extent_ )\n    {\n      extent = extent_;\n      return *this;\n    }\n\n    operator const VkImageResolve&() const\n    {\n      return *reinterpret_cast<const VkImageResolve*>(this);\n    }\n\n    bool operator==( ImageResolve const& rhs ) const\n    {\n      return ( srcSubresource == rhs.srcSubresource )\n          && ( srcOffset == rhs.srcOffset )\n          && ( dstSubresource == rhs.dstSubresource )\n          && ( dstOffset == rhs.dstOffset )\n          && ( extent == rhs.extent );\n    }\n\n    bool operator!=( ImageResolve const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    ImageSubresourceLayers srcSubresource;\n    Offset3D srcOffset;\n    ImageSubresourceLayers dstSubresource;\n    Offset3D dstOffset;\n    Extent3D extent;\n  };\n  static_assert( sizeof( ImageResolve ) == sizeof( VkImageResolve ), \"struct and wrapper have different size!\" );\n\n  struct ClearAttachment\n  {\n    ClearAttachment( ImageAspectFlags aspectMask_ = ImageAspectFlags(), uint32_t colorAttachment_ = 0, ClearValue clearValue_ = ClearValue() )\n      : aspectMask( aspectMask_ )\n      , colorAttachment( colorAttachment_ )\n      , clearValue( clearValue_ )\n    {\n    }\n\n    ClearAttachment( VkClearAttachment const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ClearAttachment) );\n    }\n\n    ClearAttachment& operator=( VkClearAttachment const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ClearAttachment) );\n      return *this;\n    }\n\n    ClearAttachment& setAspectMask( ImageAspectFlags aspectMask_ )\n    {\n      aspectMask = aspectMask_;\n      return *this;\n    }\n\n    ClearAttachment& setColorAttachment( uint32_t colorAttachment_ )\n    {\n      colorAttachment = colorAttachment_;\n      return *this;\n    }\n\n    ClearAttachment& setClearValue( ClearValue clearValue_ )\n    {\n      clearValue = clearValue_;\n      return *this;\n    }\n\n    operator const VkClearAttachment&() const\n    {\n      return *reinterpret_cast<const VkClearAttachment*>(this);\n    }\n\n    ImageAspectFlags aspectMask;\n    uint32_t colorAttachment;\n    ClearValue clearValue;\n  };\n  static_assert( sizeof( ClearAttachment ) == sizeof( VkClearAttachment ), \"struct and wrapper have different size!\" );\n\n  enum class SparseImageFormatFlagBits\n  {\n    eSingleMiptail = VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT,\n    eAlignedMipSize = VK_SPARSE_IMAGE_FORMAT_ALIGNED_MIP_SIZE_BIT,\n    eNonstandardBlockSize = VK_SPARSE_IMAGE_FORMAT_NONSTANDARD_BLOCK_SIZE_BIT\n  };\n\n  using SparseImageFormatFlags = Flags<SparseImageFormatFlagBits, VkSparseImageFormatFlags>;\n\n  VULKAN_HPP_INLINE SparseImageFormatFlags operator|( SparseImageFormatFlagBits bit0, SparseImageFormatFlagBits bit1 )\n  {\n    return SparseImageFormatFlags( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE SparseImageFormatFlags operator~( SparseImageFormatFlagBits bits )\n  {\n    return ~( SparseImageFormatFlags( bits ) );\n  }\n\n  template <> struct FlagTraits<SparseImageFormatFlagBits>\n  {\n    enum\n    {\n      allFlags = VkFlags(SparseImageFormatFlagBits::eSingleMiptail) | VkFlags(SparseImageFormatFlagBits::eAlignedMipSize) | VkFlags(SparseImageFormatFlagBits::eNonstandardBlockSize)\n    };\n  };\n\n  struct SparseImageFormatProperties\n  {\n    operator const VkSparseImageFormatProperties&() const\n    {\n      return *reinterpret_cast<const VkSparseImageFormatProperties*>(this);\n    }\n\n    bool operator==( SparseImageFormatProperties const& rhs ) const\n    {\n      return ( aspectMask == rhs.aspectMask )\n          && ( imageGranularity == rhs.imageGranularity )\n          && ( flags == rhs.flags );\n    }\n\n    bool operator!=( SparseImageFormatProperties const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    ImageAspectFlags aspectMask;\n    Extent3D imageGranularity;\n    SparseImageFormatFlags flags;\n  };\n  static_assert( sizeof( SparseImageFormatProperties ) == sizeof( VkSparseImageFormatProperties ), \"struct and wrapper have different size!\" );\n\n  struct SparseImageMemoryRequirements\n  {\n    operator const VkSparseImageMemoryRequirements&() const\n    {\n      return *reinterpret_cast<const VkSparseImageMemoryRequirements*>(this);\n    }\n\n    bool operator==( SparseImageMemoryRequirements const& rhs ) const\n    {\n      return ( formatProperties == rhs.formatProperties )\n          && ( imageMipTailFirstLod == rhs.imageMipTailFirstLod )\n          && ( imageMipTailSize == rhs.imageMipTailSize )\n          && ( imageMipTailOffset == rhs.imageMipTailOffset )\n          && ( imageMipTailStride == rhs.imageMipTailStride );\n    }\n\n    bool operator!=( SparseImageMemoryRequirements const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    SparseImageFormatProperties formatProperties;\n    uint32_t imageMipTailFirstLod;\n    DeviceSize imageMipTailSize;\n    DeviceSize imageMipTailOffset;\n    DeviceSize imageMipTailStride;\n  };\n  static_assert( sizeof( SparseImageMemoryRequirements ) == sizeof( VkSparseImageMemoryRequirements ), \"struct and wrapper have different size!\" );\n\n  struct SparseImageFormatProperties2KHR\n  {\n    operator const VkSparseImageFormatProperties2KHR&() const\n    {\n      return *reinterpret_cast<const VkSparseImageFormatProperties2KHR*>(this);\n    }\n\n    bool operator==( SparseImageFormatProperties2KHR const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( properties == rhs.properties );\n    }\n\n    bool operator!=( SparseImageFormatProperties2KHR const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    void* pNext;\n    SparseImageFormatProperties properties;\n  };\n  static_assert( sizeof( SparseImageFormatProperties2KHR ) == sizeof( VkSparseImageFormatProperties2KHR ), \"struct and wrapper have different size!\" );\n\n  enum class SparseMemoryBindFlagBits\n  {\n    eMetadata = VK_SPARSE_MEMORY_BIND_METADATA_BIT\n  };\n\n  using SparseMemoryBindFlags = Flags<SparseMemoryBindFlagBits, VkSparseMemoryBindFlags>;\n\n  VULKAN_HPP_INLINE SparseMemoryBindFlags operator|( SparseMemoryBindFlagBits bit0, SparseMemoryBindFlagBits bit1 )\n  {\n    return SparseMemoryBindFlags( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE SparseMemoryBindFlags operator~( SparseMemoryBindFlagBits bits )\n  {\n    return ~( SparseMemoryBindFlags( bits ) );\n  }\n\n  template <> struct FlagTraits<SparseMemoryBindFlagBits>\n  {\n    enum\n    {\n      allFlags = VkFlags(SparseMemoryBindFlagBits::eMetadata)\n    };\n  };\n\n  struct SparseMemoryBind\n  {\n    SparseMemoryBind( DeviceSize resourceOffset_ = 0, DeviceSize size_ = 0, DeviceMemory memory_ = DeviceMemory(), DeviceSize memoryOffset_ = 0, SparseMemoryBindFlags flags_ = SparseMemoryBindFlags() )\n      : resourceOffset( resourceOffset_ )\n      , size( size_ )\n      , memory( memory_ )\n      , memoryOffset( memoryOffset_ )\n      , flags( flags_ )\n    {\n    }\n\n    SparseMemoryBind( VkSparseMemoryBind const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(SparseMemoryBind) );\n    }\n\n    SparseMemoryBind& operator=( VkSparseMemoryBind const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(SparseMemoryBind) );\n      return *this;\n    }\n\n    SparseMemoryBind& setResourceOffset( DeviceSize resourceOffset_ )\n    {\n      resourceOffset = resourceOffset_;\n      return *this;\n    }\n\n    SparseMemoryBind& setSize( DeviceSize size_ )\n    {\n      size = size_;\n      return *this;\n    }\n\n    SparseMemoryBind& setMemory( DeviceMemory memory_ )\n    {\n      memory = memory_;\n      return *this;\n    }\n\n    SparseMemoryBind& setMemoryOffset( DeviceSize memoryOffset_ )\n    {\n      memoryOffset = memoryOffset_;\n      return *this;\n    }\n\n    SparseMemoryBind& setFlags( SparseMemoryBindFlags flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    operator const VkSparseMemoryBind&() const\n    {\n      return *reinterpret_cast<const VkSparseMemoryBind*>(this);\n    }\n\n    bool operator==( SparseMemoryBind const& rhs ) const\n    {\n      return ( resourceOffset == rhs.resourceOffset )\n          && ( size == rhs.size )\n          && ( memory == rhs.memory )\n          && ( memoryOffset == rhs.memoryOffset )\n          && ( flags == rhs.flags );\n    }\n\n    bool operator!=( SparseMemoryBind const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    DeviceSize resourceOffset;\n    DeviceSize size;\n    DeviceMemory memory;\n    DeviceSize memoryOffset;\n    SparseMemoryBindFlags flags;\n  };\n  static_assert( sizeof( SparseMemoryBind ) == sizeof( VkSparseMemoryBind ), \"struct and wrapper have different size!\" );\n\n  struct SparseImageMemoryBind\n  {\n    SparseImageMemoryBind( ImageSubresource subresource_ = ImageSubresource(), Offset3D offset_ = Offset3D(), Extent3D extent_ = Extent3D(), DeviceMemory memory_ = DeviceMemory(), DeviceSize memoryOffset_ = 0, SparseMemoryBindFlags flags_ = SparseMemoryBindFlags() )\n      : subresource( subresource_ )\n      , offset( offset_ )\n      , extent( extent_ )\n      , memory( memory_ )\n      , memoryOffset( memoryOffset_ )\n      , flags( flags_ )\n    {\n    }\n\n    SparseImageMemoryBind( VkSparseImageMemoryBind const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(SparseImageMemoryBind) );\n    }\n\n    SparseImageMemoryBind& operator=( VkSparseImageMemoryBind const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(SparseImageMemoryBind) );\n      return *this;\n    }\n\n    SparseImageMemoryBind& setSubresource( ImageSubresource subresource_ )\n    {\n      subresource = subresource_;\n      return *this;\n    }\n\n    SparseImageMemoryBind& setOffset( Offset3D offset_ )\n    {\n      offset = offset_;\n      return *this;\n    }\n\n    SparseImageMemoryBind& setExtent( Extent3D extent_ )\n    {\n      extent = extent_;\n      return *this;\n    }\n\n    SparseImageMemoryBind& setMemory( DeviceMemory memory_ )\n    {\n      memory = memory_;\n      return *this;\n    }\n\n    SparseImageMemoryBind& setMemoryOffset( DeviceSize memoryOffset_ )\n    {\n      memoryOffset = memoryOffset_;\n      return *this;\n    }\n\n    SparseImageMemoryBind& setFlags( SparseMemoryBindFlags flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    operator const VkSparseImageMemoryBind&() const\n    {\n      return *reinterpret_cast<const VkSparseImageMemoryBind*>(this);\n    }\n\n    bool operator==( SparseImageMemoryBind const& rhs ) const\n    {\n      return ( subresource == rhs.subresource )\n          && ( offset == rhs.offset )\n          && ( extent == rhs.extent )\n          && ( memory == rhs.memory )\n          && ( memoryOffset == rhs.memoryOffset )\n          && ( flags == rhs.flags );\n    }\n\n    bool operator!=( SparseImageMemoryBind const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    ImageSubresource subresource;\n    Offset3D offset;\n    Extent3D extent;\n    DeviceMemory memory;\n    DeviceSize memoryOffset;\n    SparseMemoryBindFlags flags;\n  };\n  static_assert( sizeof( SparseImageMemoryBind ) == sizeof( VkSparseImageMemoryBind ), \"struct and wrapper have different size!\" );\n\n  struct SparseBufferMemoryBindInfo\n  {\n    SparseBufferMemoryBindInfo( Buffer buffer_ = Buffer(), uint32_t bindCount_ = 0, const SparseMemoryBind* pBinds_ = nullptr )\n      : buffer( buffer_ )\n      , bindCount( bindCount_ )\n      , pBinds( pBinds_ )\n    {\n    }\n\n    SparseBufferMemoryBindInfo( VkSparseBufferMemoryBindInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(SparseBufferMemoryBindInfo) );\n    }\n\n    SparseBufferMemoryBindInfo& operator=( VkSparseBufferMemoryBindInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(SparseBufferMemoryBindInfo) );\n      return *this;\n    }\n\n    SparseBufferMemoryBindInfo& setBuffer( Buffer buffer_ )\n    {\n      buffer = buffer_;\n      return *this;\n    }\n\n    SparseBufferMemoryBindInfo& setBindCount( uint32_t bindCount_ )\n    {\n      bindCount = bindCount_;\n      return *this;\n    }\n\n    SparseBufferMemoryBindInfo& setPBinds( const SparseMemoryBind* pBinds_ )\n    {\n      pBinds = pBinds_;\n      return *this;\n    }\n\n    operator const VkSparseBufferMemoryBindInfo&() const\n    {\n      return *reinterpret_cast<const VkSparseBufferMemoryBindInfo*>(this);\n    }\n\n    bool operator==( SparseBufferMemoryBindInfo const& rhs ) const\n    {\n      return ( buffer == rhs.buffer )\n          && ( bindCount == rhs.bindCount )\n          && ( pBinds == rhs.pBinds );\n    }\n\n    bool operator!=( SparseBufferMemoryBindInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    Buffer buffer;\n    uint32_t bindCount;\n    const SparseMemoryBind* pBinds;\n  };\n  static_assert( sizeof( SparseBufferMemoryBindInfo ) == sizeof( VkSparseBufferMemoryBindInfo ), \"struct and wrapper have different size!\" );\n\n  struct SparseImageOpaqueMemoryBindInfo\n  {\n    SparseImageOpaqueMemoryBindInfo( Image image_ = Image(), uint32_t bindCount_ = 0, const SparseMemoryBind* pBinds_ = nullptr )\n      : image( image_ )\n      , bindCount( bindCount_ )\n      , pBinds( pBinds_ )\n    {\n    }\n\n    SparseImageOpaqueMemoryBindInfo( VkSparseImageOpaqueMemoryBindInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(SparseImageOpaqueMemoryBindInfo) );\n    }\n\n    SparseImageOpaqueMemoryBindInfo& operator=( VkSparseImageOpaqueMemoryBindInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(SparseImageOpaqueMemoryBindInfo) );\n      return *this;\n    }\n\n    SparseImageOpaqueMemoryBindInfo& setImage( Image image_ )\n    {\n      image = image_;\n      return *this;\n    }\n\n    SparseImageOpaqueMemoryBindInfo& setBindCount( uint32_t bindCount_ )\n    {\n      bindCount = bindCount_;\n      return *this;\n    }\n\n    SparseImageOpaqueMemoryBindInfo& setPBinds( const SparseMemoryBind* pBinds_ )\n    {\n      pBinds = pBinds_;\n      return *this;\n    }\n\n    operator const VkSparseImageOpaqueMemoryBindInfo&() const\n    {\n      return *reinterpret_cast<const VkSparseImageOpaqueMemoryBindInfo*>(this);\n    }\n\n    bool operator==( SparseImageOpaqueMemoryBindInfo const& rhs ) const\n    {\n      return ( image == rhs.image )\n          && ( bindCount == rhs.bindCount )\n          && ( pBinds == rhs.pBinds );\n    }\n\n    bool operator!=( SparseImageOpaqueMemoryBindInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    Image image;\n    uint32_t bindCount;\n    const SparseMemoryBind* pBinds;\n  };\n  static_assert( sizeof( SparseImageOpaqueMemoryBindInfo ) == sizeof( VkSparseImageOpaqueMemoryBindInfo ), \"struct and wrapper have different size!\" );\n\n  struct SparseImageMemoryBindInfo\n  {\n    SparseImageMemoryBindInfo( Image image_ = Image(), uint32_t bindCount_ = 0, const SparseImageMemoryBind* pBinds_ = nullptr )\n      : image( image_ )\n      , bindCount( bindCount_ )\n      , pBinds( pBinds_ )\n    {\n    }\n\n    SparseImageMemoryBindInfo( VkSparseImageMemoryBindInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(SparseImageMemoryBindInfo) );\n    }\n\n    SparseImageMemoryBindInfo& operator=( VkSparseImageMemoryBindInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(SparseImageMemoryBindInfo) );\n      return *this;\n    }\n\n    SparseImageMemoryBindInfo& setImage( Image image_ )\n    {\n      image = image_;\n      return *this;\n    }\n\n    SparseImageMemoryBindInfo& setBindCount( uint32_t bindCount_ )\n    {\n      bindCount = bindCount_;\n      return *this;\n    }\n\n    SparseImageMemoryBindInfo& setPBinds( const SparseImageMemoryBind* pBinds_ )\n    {\n      pBinds = pBinds_;\n      return *this;\n    }\n\n    operator const VkSparseImageMemoryBindInfo&() const\n    {\n      return *reinterpret_cast<const VkSparseImageMemoryBindInfo*>(this);\n    }\n\n    bool operator==( SparseImageMemoryBindInfo const& rhs ) const\n    {\n      return ( image == rhs.image )\n          && ( bindCount == rhs.bindCount )\n          && ( pBinds == rhs.pBinds );\n    }\n\n    bool operator!=( SparseImageMemoryBindInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    Image image;\n    uint32_t bindCount;\n    const SparseImageMemoryBind* pBinds;\n  };\n  static_assert( sizeof( SparseImageMemoryBindInfo ) == sizeof( VkSparseImageMemoryBindInfo ), \"struct and wrapper have different size!\" );\n\n  struct BindSparseInfo\n  {\n    BindSparseInfo( uint32_t waitSemaphoreCount_ = 0, const Semaphore* pWaitSemaphores_ = nullptr, uint32_t bufferBindCount_ = 0, const SparseBufferMemoryBindInfo* pBufferBinds_ = nullptr, uint32_t imageOpaqueBindCount_ = 0, const SparseImageOpaqueMemoryBindInfo* pImageOpaqueBinds_ = nullptr, uint32_t imageBindCount_ = 0, const SparseImageMemoryBindInfo* pImageBinds_ = nullptr, uint32_t signalSemaphoreCount_ = 0, const Semaphore* pSignalSemaphores_ = nullptr )\n      : sType( StructureType::eBindSparseInfo )\n      , pNext( nullptr )\n      , waitSemaphoreCount( waitSemaphoreCount_ )\n      , pWaitSemaphores( pWaitSemaphores_ )\n      , bufferBindCount( bufferBindCount_ )\n      , pBufferBinds( pBufferBinds_ )\n      , imageOpaqueBindCount( imageOpaqueBindCount_ )\n      , pImageOpaqueBinds( pImageOpaqueBinds_ )\n      , imageBindCount( imageBindCount_ )\n      , pImageBinds( pImageBinds_ )\n      , signalSemaphoreCount( signalSemaphoreCount_ )\n      , pSignalSemaphores( pSignalSemaphores_ )\n    {\n    }\n\n    BindSparseInfo( VkBindSparseInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(BindSparseInfo) );\n    }\n\n    BindSparseInfo& operator=( VkBindSparseInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(BindSparseInfo) );\n      return *this;\n    }\n\n    BindSparseInfo& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    BindSparseInfo& setWaitSemaphoreCount( uint32_t waitSemaphoreCount_ )\n    {\n      waitSemaphoreCount = waitSemaphoreCount_;\n      return *this;\n    }\n\n    BindSparseInfo& setPWaitSemaphores( const Semaphore* pWaitSemaphores_ )\n    {\n      pWaitSemaphores = pWaitSemaphores_;\n      return *this;\n    }\n\n    BindSparseInfo& setBufferBindCount( uint32_t bufferBindCount_ )\n    {\n      bufferBindCount = bufferBindCount_;\n      return *this;\n    }\n\n    BindSparseInfo& setPBufferBinds( const SparseBufferMemoryBindInfo* pBufferBinds_ )\n    {\n      pBufferBinds = pBufferBinds_;\n      return *this;\n    }\n\n    BindSparseInfo& setImageOpaqueBindCount( uint32_t imageOpaqueBindCount_ )\n    {\n      imageOpaqueBindCount = imageOpaqueBindCount_;\n      return *this;\n    }\n\n    BindSparseInfo& setPImageOpaqueBinds( const SparseImageOpaqueMemoryBindInfo* pImageOpaqueBinds_ )\n    {\n      pImageOpaqueBinds = pImageOpaqueBinds_;\n      return *this;\n    }\n\n    BindSparseInfo& setImageBindCount( uint32_t imageBindCount_ )\n    {\n      imageBindCount = imageBindCount_;\n      return *this;\n    }\n\n    BindSparseInfo& setPImageBinds( const SparseImageMemoryBindInfo* pImageBinds_ )\n    {\n      pImageBinds = pImageBinds_;\n      return *this;\n    }\n\n    BindSparseInfo& setSignalSemaphoreCount( uint32_t signalSemaphoreCount_ )\n    {\n      signalSemaphoreCount = signalSemaphoreCount_;\n      return *this;\n    }\n\n    BindSparseInfo& setPSignalSemaphores( const Semaphore* pSignalSemaphores_ )\n    {\n      pSignalSemaphores = pSignalSemaphores_;\n      return *this;\n    }\n\n    operator const VkBindSparseInfo&() const\n    {\n      return *reinterpret_cast<const VkBindSparseInfo*>(this);\n    }\n\n    bool operator==( BindSparseInfo const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( waitSemaphoreCount == rhs.waitSemaphoreCount )\n          && ( pWaitSemaphores == rhs.pWaitSemaphores )\n          && ( bufferBindCount == rhs.bufferBindCount )\n          && ( pBufferBinds == rhs.pBufferBinds )\n          && ( imageOpaqueBindCount == rhs.imageOpaqueBindCount )\n          && ( pImageOpaqueBinds == rhs.pImageOpaqueBinds )\n          && ( imageBindCount == rhs.imageBindCount )\n          && ( pImageBinds == rhs.pImageBinds )\n          && ( signalSemaphoreCount == rhs.signalSemaphoreCount )\n          && ( pSignalSemaphores == rhs.pSignalSemaphores );\n    }\n\n    bool operator!=( BindSparseInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    uint32_t waitSemaphoreCount;\n    const Semaphore* pWaitSemaphores;\n    uint32_t bufferBindCount;\n    const SparseBufferMemoryBindInfo* pBufferBinds;\n    uint32_t imageOpaqueBindCount;\n    const SparseImageOpaqueMemoryBindInfo* pImageOpaqueBinds;\n    uint32_t imageBindCount;\n    const SparseImageMemoryBindInfo* pImageBinds;\n    uint32_t signalSemaphoreCount;\n    const Semaphore* pSignalSemaphores;\n  };\n  static_assert( sizeof( BindSparseInfo ) == sizeof( VkBindSparseInfo ), \"struct and wrapper have different size!\" );\n\n  enum class PipelineStageFlagBits\n  {\n    eTopOfPipe = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,\n    eDrawIndirect = VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT,\n    eVertexInput = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,\n    eVertexShader = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,\n    eTessellationControlShader = VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT,\n    eTessellationEvaluationShader = VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT,\n    eGeometryShader = VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT,\n    eFragmentShader = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,\n    eEarlyFragmentTests = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,\n    eLateFragmentTests = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,\n    eColorAttachmentOutput = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,\n    eComputeShader = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,\n    eTransfer = VK_PIPELINE_STAGE_TRANSFER_BIT,\n    eBottomOfPipe = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,\n    eHost = VK_PIPELINE_STAGE_HOST_BIT,\n    eAllGraphics = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,\n    eAllCommands = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,\n    eCommandProcessNVX = VK_PIPELINE_STAGE_COMMAND_PROCESS_BIT_NVX\n  };\n\n  using PipelineStageFlags = Flags<PipelineStageFlagBits, VkPipelineStageFlags>;\n\n  VULKAN_HPP_INLINE PipelineStageFlags operator|( PipelineStageFlagBits bit0, PipelineStageFlagBits bit1 )\n  {\n    return PipelineStageFlags( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE PipelineStageFlags operator~( PipelineStageFlagBits bits )\n  {\n    return ~( PipelineStageFlags( bits ) );\n  }\n\n  template <> struct FlagTraits<PipelineStageFlagBits>\n  {\n    enum\n    {\n      allFlags = VkFlags(PipelineStageFlagBits::eTopOfPipe) | VkFlags(PipelineStageFlagBits::eDrawIndirect) | VkFlags(PipelineStageFlagBits::eVertexInput) | VkFlags(PipelineStageFlagBits::eVertexShader) | VkFlags(PipelineStageFlagBits::eTessellationControlShader) | VkFlags(PipelineStageFlagBits::eTessellationEvaluationShader) | VkFlags(PipelineStageFlagBits::eGeometryShader) | VkFlags(PipelineStageFlagBits::eFragmentShader) | VkFlags(PipelineStageFlagBits::eEarlyFragmentTests) | VkFlags(PipelineStageFlagBits::eLateFragmentTests) | VkFlags(PipelineStageFlagBits::eColorAttachmentOutput) | VkFlags(PipelineStageFlagBits::eComputeShader) | VkFlags(PipelineStageFlagBits::eTransfer) | VkFlags(PipelineStageFlagBits::eBottomOfPipe) | VkFlags(PipelineStageFlagBits::eHost) | VkFlags(PipelineStageFlagBits::eAllGraphics) | VkFlags(PipelineStageFlagBits::eAllCommands) | VkFlags(PipelineStageFlagBits::eCommandProcessNVX)\n    };\n  };\n\n  enum class CommandPoolCreateFlagBits\n  {\n    eTransient = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT,\n    eResetCommandBuffer = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT\n  };\n\n  using CommandPoolCreateFlags = Flags<CommandPoolCreateFlagBits, VkCommandPoolCreateFlags>;\n\n  VULKAN_HPP_INLINE CommandPoolCreateFlags operator|( CommandPoolCreateFlagBits bit0, CommandPoolCreateFlagBits bit1 )\n  {\n    return CommandPoolCreateFlags( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE CommandPoolCreateFlags operator~( CommandPoolCreateFlagBits bits )\n  {\n    return ~( CommandPoolCreateFlags( bits ) );\n  }\n\n  template <> struct FlagTraits<CommandPoolCreateFlagBits>\n  {\n    enum\n    {\n      allFlags = VkFlags(CommandPoolCreateFlagBits::eTransient) | VkFlags(CommandPoolCreateFlagBits::eResetCommandBuffer)\n    };\n  };\n\n  struct CommandPoolCreateInfo\n  {\n    CommandPoolCreateInfo( CommandPoolCreateFlags flags_ = CommandPoolCreateFlags(), uint32_t queueFamilyIndex_ = 0 )\n      : sType( StructureType::eCommandPoolCreateInfo )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , queueFamilyIndex( queueFamilyIndex_ )\n    {\n    }\n\n    CommandPoolCreateInfo( VkCommandPoolCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(CommandPoolCreateInfo) );\n    }\n\n    CommandPoolCreateInfo& operator=( VkCommandPoolCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(CommandPoolCreateInfo) );\n      return *this;\n    }\n\n    CommandPoolCreateInfo& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    CommandPoolCreateInfo& setFlags( CommandPoolCreateFlags flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    CommandPoolCreateInfo& setQueueFamilyIndex( uint32_t queueFamilyIndex_ )\n    {\n      queueFamilyIndex = queueFamilyIndex_;\n      return *this;\n    }\n\n    operator const VkCommandPoolCreateInfo&() const\n    {\n      return *reinterpret_cast<const VkCommandPoolCreateInfo*>(this);\n    }\n\n    bool operator==( CommandPoolCreateInfo const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( queueFamilyIndex == rhs.queueFamilyIndex );\n    }\n\n    bool operator!=( CommandPoolCreateInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    CommandPoolCreateFlags flags;\n    uint32_t queueFamilyIndex;\n  };\n  static_assert( sizeof( CommandPoolCreateInfo ) == sizeof( VkCommandPoolCreateInfo ), \"struct and wrapper have different size!\" );\n\n  enum class CommandPoolResetFlagBits\n  {\n    eReleaseResources = VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT\n  };\n\n  using CommandPoolResetFlags = Flags<CommandPoolResetFlagBits, VkCommandPoolResetFlags>;\n\n  VULKAN_HPP_INLINE CommandPoolResetFlags operator|( CommandPoolResetFlagBits bit0, CommandPoolResetFlagBits bit1 )\n  {\n    return CommandPoolResetFlags( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE CommandPoolResetFlags operator~( CommandPoolResetFlagBits bits )\n  {\n    return ~( CommandPoolResetFlags( bits ) );\n  }\n\n  template <> struct FlagTraits<CommandPoolResetFlagBits>\n  {\n    enum\n    {\n      allFlags = VkFlags(CommandPoolResetFlagBits::eReleaseResources)\n    };\n  };\n\n  enum class CommandBufferResetFlagBits\n  {\n    eReleaseResources = VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT\n  };\n\n  using CommandBufferResetFlags = Flags<CommandBufferResetFlagBits, VkCommandBufferResetFlags>;\n\n  VULKAN_HPP_INLINE CommandBufferResetFlags operator|( CommandBufferResetFlagBits bit0, CommandBufferResetFlagBits bit1 )\n  {\n    return CommandBufferResetFlags( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE CommandBufferResetFlags operator~( CommandBufferResetFlagBits bits )\n  {\n    return ~( CommandBufferResetFlags( bits ) );\n  }\n\n  template <> struct FlagTraits<CommandBufferResetFlagBits>\n  {\n    enum\n    {\n      allFlags = VkFlags(CommandBufferResetFlagBits::eReleaseResources)\n    };\n  };\n\n  enum class SampleCountFlagBits\n  {\n    e1 = VK_SAMPLE_COUNT_1_BIT,\n    e2 = VK_SAMPLE_COUNT_2_BIT,\n    e4 = VK_SAMPLE_COUNT_4_BIT,\n    e8 = VK_SAMPLE_COUNT_8_BIT,\n    e16 = VK_SAMPLE_COUNT_16_BIT,\n    e32 = VK_SAMPLE_COUNT_32_BIT,\n    e64 = VK_SAMPLE_COUNT_64_BIT\n  };\n\n  using SampleCountFlags = Flags<SampleCountFlagBits, VkSampleCountFlags>;\n\n  VULKAN_HPP_INLINE SampleCountFlags operator|( SampleCountFlagBits bit0, SampleCountFlagBits bit1 )\n  {\n    return SampleCountFlags( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE SampleCountFlags operator~( SampleCountFlagBits bits )\n  {\n    return ~( SampleCountFlags( bits ) );\n  }\n\n  template <> struct FlagTraits<SampleCountFlagBits>\n  {\n    enum\n    {\n      allFlags = VkFlags(SampleCountFlagBits::e1) | VkFlags(SampleCountFlagBits::e2) | VkFlags(SampleCountFlagBits::e4) | VkFlags(SampleCountFlagBits::e8) | VkFlags(SampleCountFlagBits::e16) | VkFlags(SampleCountFlagBits::e32) | VkFlags(SampleCountFlagBits::e64)\n    };\n  };\n\n  struct ImageFormatProperties\n  {\n    operator const VkImageFormatProperties&() const\n    {\n      return *reinterpret_cast<const VkImageFormatProperties*>(this);\n    }\n\n    bool operator==( ImageFormatProperties const& rhs ) const\n    {\n      return ( maxExtent == rhs.maxExtent )\n          && ( maxMipLevels == rhs.maxMipLevels )\n          && ( maxArrayLayers == rhs.maxArrayLayers )\n          && ( sampleCounts == rhs.sampleCounts )\n          && ( maxResourceSize == rhs.maxResourceSize );\n    }\n\n    bool operator!=( ImageFormatProperties const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    Extent3D maxExtent;\n    uint32_t maxMipLevels;\n    uint32_t maxArrayLayers;\n    SampleCountFlags sampleCounts;\n    DeviceSize maxResourceSize;\n  };\n  static_assert( sizeof( ImageFormatProperties ) == sizeof( VkImageFormatProperties ), \"struct and wrapper have different size!\" );\n\n  struct ImageCreateInfo\n  {\n    ImageCreateInfo( ImageCreateFlags flags_ = ImageCreateFlags(), ImageType imageType_ = ImageType::e1D, Format format_ = Format::eUndefined, Extent3D extent_ = Extent3D(), uint32_t mipLevels_ = 0, uint32_t arrayLayers_ = 0, SampleCountFlagBits samples_ = SampleCountFlagBits::e1, ImageTiling tiling_ = ImageTiling::eOptimal, ImageUsageFlags usage_ = ImageUsageFlags(), SharingMode sharingMode_ = SharingMode::eExclusive, uint32_t queueFamilyIndexCount_ = 0, const uint32_t* pQueueFamilyIndices_ = nullptr, ImageLayout initialLayout_ = ImageLayout::eUndefined )\n      : sType( StructureType::eImageCreateInfo )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , imageType( imageType_ )\n      , format( format_ )\n      , extent( extent_ )\n      , mipLevels( mipLevels_ )\n      , arrayLayers( arrayLayers_ )\n      , samples( samples_ )\n      , tiling( tiling_ )\n      , usage( usage_ )\n      , sharingMode( sharingMode_ )\n      , queueFamilyIndexCount( queueFamilyIndexCount_ )\n      , pQueueFamilyIndices( pQueueFamilyIndices_ )\n      , initialLayout( initialLayout_ )\n    {\n    }\n\n    ImageCreateInfo( VkImageCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ImageCreateInfo) );\n    }\n\n    ImageCreateInfo& operator=( VkImageCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ImageCreateInfo) );\n      return *this;\n    }\n\n    ImageCreateInfo& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    ImageCreateInfo& setFlags( ImageCreateFlags flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    ImageCreateInfo& setImageType( ImageType imageType_ )\n    {\n      imageType = imageType_;\n      return *this;\n    }\n\n    ImageCreateInfo& setFormat( Format format_ )\n    {\n      format = format_;\n      return *this;\n    }\n\n    ImageCreateInfo& setExtent( Extent3D extent_ )\n    {\n      extent = extent_;\n      return *this;\n    }\n\n    ImageCreateInfo& setMipLevels( uint32_t mipLevels_ )\n    {\n      mipLevels = mipLevels_;\n      return *this;\n    }\n\n    ImageCreateInfo& setArrayLayers( uint32_t arrayLayers_ )\n    {\n      arrayLayers = arrayLayers_;\n      return *this;\n    }\n\n    ImageCreateInfo& setSamples( SampleCountFlagBits samples_ )\n    {\n      samples = samples_;\n      return *this;\n    }\n\n    ImageCreateInfo& setTiling( ImageTiling tiling_ )\n    {\n      tiling = tiling_;\n      return *this;\n    }\n\n    ImageCreateInfo& setUsage( ImageUsageFlags usage_ )\n    {\n      usage = usage_;\n      return *this;\n    }\n\n    ImageCreateInfo& setSharingMode( SharingMode sharingMode_ )\n    {\n      sharingMode = sharingMode_;\n      return *this;\n    }\n\n    ImageCreateInfo& setQueueFamilyIndexCount( uint32_t queueFamilyIndexCount_ )\n    {\n      queueFamilyIndexCount = queueFamilyIndexCount_;\n      return *this;\n    }\n\n    ImageCreateInfo& setPQueueFamilyIndices( const uint32_t* pQueueFamilyIndices_ )\n    {\n      pQueueFamilyIndices = pQueueFamilyIndices_;\n      return *this;\n    }\n\n    ImageCreateInfo& setInitialLayout( ImageLayout initialLayout_ )\n    {\n      initialLayout = initialLayout_;\n      return *this;\n    }\n\n    operator const VkImageCreateInfo&() const\n    {\n      return *reinterpret_cast<const VkImageCreateInfo*>(this);\n    }\n\n    bool operator==( ImageCreateInfo const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( imageType == rhs.imageType )\n          && ( format == rhs.format )\n          && ( extent == rhs.extent )\n          && ( mipLevels == rhs.mipLevels )\n          && ( arrayLayers == rhs.arrayLayers )\n          && ( samples == rhs.samples )\n          && ( tiling == rhs.tiling )\n          && ( usage == rhs.usage )\n          && ( sharingMode == rhs.sharingMode )\n          && ( queueFamilyIndexCount == rhs.queueFamilyIndexCount )\n          && ( pQueueFamilyIndices == rhs.pQueueFamilyIndices )\n          && ( initialLayout == rhs.initialLayout );\n    }\n\n    bool operator!=( ImageCreateInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    ImageCreateFlags flags;\n    ImageType imageType;\n    Format format;\n    Extent3D extent;\n    uint32_t mipLevels;\n    uint32_t arrayLayers;\n    SampleCountFlagBits samples;\n    ImageTiling tiling;\n    ImageUsageFlags usage;\n    SharingMode sharingMode;\n    uint32_t queueFamilyIndexCount;\n    const uint32_t* pQueueFamilyIndices;\n    ImageLayout initialLayout;\n  };\n  static_assert( sizeof( ImageCreateInfo ) == sizeof( VkImageCreateInfo ), \"struct and wrapper have different size!\" );\n\n  struct PipelineMultisampleStateCreateInfo\n  {\n    PipelineMultisampleStateCreateInfo( PipelineMultisampleStateCreateFlags flags_ = PipelineMultisampleStateCreateFlags(), SampleCountFlagBits rasterizationSamples_ = SampleCountFlagBits::e1, Bool32 sampleShadingEnable_ = 0, float minSampleShading_ = 0, const SampleMask* pSampleMask_ = nullptr, Bool32 alphaToCoverageEnable_ = 0, Bool32 alphaToOneEnable_ = 0 )\n      : sType( StructureType::ePipelineMultisampleStateCreateInfo )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , rasterizationSamples( rasterizationSamples_ )\n      , sampleShadingEnable( sampleShadingEnable_ )\n      , minSampleShading( minSampleShading_ )\n      , pSampleMask( pSampleMask_ )\n      , alphaToCoverageEnable( alphaToCoverageEnable_ )\n      , alphaToOneEnable( alphaToOneEnable_ )\n    {\n    }\n\n    PipelineMultisampleStateCreateInfo( VkPipelineMultisampleStateCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PipelineMultisampleStateCreateInfo) );\n    }\n\n    PipelineMultisampleStateCreateInfo& operator=( VkPipelineMultisampleStateCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PipelineMultisampleStateCreateInfo) );\n      return *this;\n    }\n\n    PipelineMultisampleStateCreateInfo& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    PipelineMultisampleStateCreateInfo& setFlags( PipelineMultisampleStateCreateFlags flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    PipelineMultisampleStateCreateInfo& setRasterizationSamples( SampleCountFlagBits rasterizationSamples_ )\n    {\n      rasterizationSamples = rasterizationSamples_;\n      return *this;\n    }\n\n    PipelineMultisampleStateCreateInfo& setSampleShadingEnable( Bool32 sampleShadingEnable_ )\n    {\n      sampleShadingEnable = sampleShadingEnable_;\n      return *this;\n    }\n\n    PipelineMultisampleStateCreateInfo& setMinSampleShading( float minSampleShading_ )\n    {\n      minSampleShading = minSampleShading_;\n      return *this;\n    }\n\n    PipelineMultisampleStateCreateInfo& setPSampleMask( const SampleMask* pSampleMask_ )\n    {\n      pSampleMask = pSampleMask_;\n      return *this;\n    }\n\n    PipelineMultisampleStateCreateInfo& setAlphaToCoverageEnable( Bool32 alphaToCoverageEnable_ )\n    {\n      alphaToCoverageEnable = alphaToCoverageEnable_;\n      return *this;\n    }\n\n    PipelineMultisampleStateCreateInfo& setAlphaToOneEnable( Bool32 alphaToOneEnable_ )\n    {\n      alphaToOneEnable = alphaToOneEnable_;\n      return *this;\n    }\n\n    operator const VkPipelineMultisampleStateCreateInfo&() const\n    {\n      return *reinterpret_cast<const VkPipelineMultisampleStateCreateInfo*>(this);\n    }\n\n    bool operator==( PipelineMultisampleStateCreateInfo const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( rasterizationSamples == rhs.rasterizationSamples )\n          && ( sampleShadingEnable == rhs.sampleShadingEnable )\n          && ( minSampleShading == rhs.minSampleShading )\n          && ( pSampleMask == rhs.pSampleMask )\n          && ( alphaToCoverageEnable == rhs.alphaToCoverageEnable )\n          && ( alphaToOneEnable == rhs.alphaToOneEnable );\n    }\n\n    bool operator!=( PipelineMultisampleStateCreateInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    PipelineMultisampleStateCreateFlags flags;\n    SampleCountFlagBits rasterizationSamples;\n    Bool32 sampleShadingEnable;\n    float minSampleShading;\n    const SampleMask* pSampleMask;\n    Bool32 alphaToCoverageEnable;\n    Bool32 alphaToOneEnable;\n  };\n  static_assert( sizeof( PipelineMultisampleStateCreateInfo ) == sizeof( VkPipelineMultisampleStateCreateInfo ), \"struct and wrapper have different size!\" );\n\n  struct GraphicsPipelineCreateInfo\n  {\n    GraphicsPipelineCreateInfo( PipelineCreateFlags flags_ = PipelineCreateFlags(), uint32_t stageCount_ = 0, const PipelineShaderStageCreateInfo* pStages_ = nullptr, const PipelineVertexInputStateCreateInfo* pVertexInputState_ = nullptr, const PipelineInputAssemblyStateCreateInfo* pInputAssemblyState_ = nullptr, const PipelineTessellationStateCreateInfo* pTessellationState_ = nullptr, const PipelineViewportStateCreateInfo* pViewportState_ = nullptr, const PipelineRasterizationStateCreateInfo* pRasterizationState_ = nullptr, const PipelineMultisampleStateCreateInfo* pMultisampleState_ = nullptr, const PipelineDepthStencilStateCreateInfo* pDepthStencilState_ = nullptr, const PipelineColorBlendStateCreateInfo* pColorBlendState_ = nullptr, const PipelineDynamicStateCreateInfo* pDynamicState_ = nullptr, PipelineLayout layout_ = PipelineLayout(), RenderPass renderPass_ = RenderPass(), uint32_t subpass_ = 0, Pipeline basePipelineHandle_ = Pipeline(), int32_t basePipelineIndex_ = 0 )\n      : sType( StructureType::eGraphicsPipelineCreateInfo )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , stageCount( stageCount_ )\n      , pStages( pStages_ )\n      , pVertexInputState( pVertexInputState_ )\n      , pInputAssemblyState( pInputAssemblyState_ )\n      , pTessellationState( pTessellationState_ )\n      , pViewportState( pViewportState_ )\n      , pRasterizationState( pRasterizationState_ )\n      , pMultisampleState( pMultisampleState_ )\n      , pDepthStencilState( pDepthStencilState_ )\n      , pColorBlendState( pColorBlendState_ )\n      , pDynamicState( pDynamicState_ )\n      , layout( layout_ )\n      , renderPass( renderPass_ )\n      , subpass( subpass_ )\n      , basePipelineHandle( basePipelineHandle_ )\n      , basePipelineIndex( basePipelineIndex_ )\n    {\n    }\n\n    GraphicsPipelineCreateInfo( VkGraphicsPipelineCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(GraphicsPipelineCreateInfo) );\n    }\n\n    GraphicsPipelineCreateInfo& operator=( VkGraphicsPipelineCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(GraphicsPipelineCreateInfo) );\n      return *this;\n    }\n\n    GraphicsPipelineCreateInfo& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    GraphicsPipelineCreateInfo& setFlags( PipelineCreateFlags flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    GraphicsPipelineCreateInfo& setStageCount( uint32_t stageCount_ )\n    {\n      stageCount = stageCount_;\n      return *this;\n    }\n\n    GraphicsPipelineCreateInfo& setPStages( const PipelineShaderStageCreateInfo* pStages_ )\n    {\n      pStages = pStages_;\n      return *this;\n    }\n\n    GraphicsPipelineCreateInfo& setPVertexInputState( const PipelineVertexInputStateCreateInfo* pVertexInputState_ )\n    {\n      pVertexInputState = pVertexInputState_;\n      return *this;\n    }\n\n    GraphicsPipelineCreateInfo& setPInputAssemblyState( const PipelineInputAssemblyStateCreateInfo* pInputAssemblyState_ )\n    {\n      pInputAssemblyState = pInputAssemblyState_;\n      return *this;\n    }\n\n    GraphicsPipelineCreateInfo& setPTessellationState( const PipelineTessellationStateCreateInfo* pTessellationState_ )\n    {\n      pTessellationState = pTessellationState_;\n      return *this;\n    }\n\n    GraphicsPipelineCreateInfo& setPViewportState( const PipelineViewportStateCreateInfo* pViewportState_ )\n    {\n      pViewportState = pViewportState_;\n      return *this;\n    }\n\n    GraphicsPipelineCreateInfo& setPRasterizationState( const PipelineRasterizationStateCreateInfo* pRasterizationState_ )\n    {\n      pRasterizationState = pRasterizationState_;\n      return *this;\n    }\n\n    GraphicsPipelineCreateInfo& setPMultisampleState( const PipelineMultisampleStateCreateInfo* pMultisampleState_ )\n    {\n      pMultisampleState = pMultisampleState_;\n      return *this;\n    }\n\n    GraphicsPipelineCreateInfo& setPDepthStencilState( const PipelineDepthStencilStateCreateInfo* pDepthStencilState_ )\n    {\n      pDepthStencilState = pDepthStencilState_;\n      return *this;\n    }\n\n    GraphicsPipelineCreateInfo& setPColorBlendState( const PipelineColorBlendStateCreateInfo* pColorBlendState_ )\n    {\n      pColorBlendState = pColorBlendState_;\n      return *this;\n    }\n\n    GraphicsPipelineCreateInfo& setPDynamicState( const PipelineDynamicStateCreateInfo* pDynamicState_ )\n    {\n      pDynamicState = pDynamicState_;\n      return *this;\n    }\n\n    GraphicsPipelineCreateInfo& setLayout( PipelineLayout layout_ )\n    {\n      layout = layout_;\n      return *this;\n    }\n\n    GraphicsPipelineCreateInfo& setRenderPass( RenderPass renderPass_ )\n    {\n      renderPass = renderPass_;\n      return *this;\n    }\n\n    GraphicsPipelineCreateInfo& setSubpass( uint32_t subpass_ )\n    {\n      subpass = subpass_;\n      return *this;\n    }\n\n    GraphicsPipelineCreateInfo& setBasePipelineHandle( Pipeline basePipelineHandle_ )\n    {\n      basePipelineHandle = basePipelineHandle_;\n      return *this;\n    }\n\n    GraphicsPipelineCreateInfo& setBasePipelineIndex( int32_t basePipelineIndex_ )\n    {\n      basePipelineIndex = basePipelineIndex_;\n      return *this;\n    }\n\n    operator const VkGraphicsPipelineCreateInfo&() const\n    {\n      return *reinterpret_cast<const VkGraphicsPipelineCreateInfo*>(this);\n    }\n\n    bool operator==( GraphicsPipelineCreateInfo const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( stageCount == rhs.stageCount )\n          && ( pStages == rhs.pStages )\n          && ( pVertexInputState == rhs.pVertexInputState )\n          && ( pInputAssemblyState == rhs.pInputAssemblyState )\n          && ( pTessellationState == rhs.pTessellationState )\n          && ( pViewportState == rhs.pViewportState )\n          && ( pRasterizationState == rhs.pRasterizationState )\n          && ( pMultisampleState == rhs.pMultisampleState )\n          && ( pDepthStencilState == rhs.pDepthStencilState )\n          && ( pColorBlendState == rhs.pColorBlendState )\n          && ( pDynamicState == rhs.pDynamicState )\n          && ( layout == rhs.layout )\n          && ( renderPass == rhs.renderPass )\n          && ( subpass == rhs.subpass )\n          && ( basePipelineHandle == rhs.basePipelineHandle )\n          && ( basePipelineIndex == rhs.basePipelineIndex );\n    }\n\n    bool operator!=( GraphicsPipelineCreateInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    PipelineCreateFlags flags;\n    uint32_t stageCount;\n    const PipelineShaderStageCreateInfo* pStages;\n    const PipelineVertexInputStateCreateInfo* pVertexInputState;\n    const PipelineInputAssemblyStateCreateInfo* pInputAssemblyState;\n    const PipelineTessellationStateCreateInfo* pTessellationState;\n    const PipelineViewportStateCreateInfo* pViewportState;\n    const PipelineRasterizationStateCreateInfo* pRasterizationState;\n    const PipelineMultisampleStateCreateInfo* pMultisampleState;\n    const PipelineDepthStencilStateCreateInfo* pDepthStencilState;\n    const PipelineColorBlendStateCreateInfo* pColorBlendState;\n    const PipelineDynamicStateCreateInfo* pDynamicState;\n    PipelineLayout layout;\n    RenderPass renderPass;\n    uint32_t subpass;\n    Pipeline basePipelineHandle;\n    int32_t basePipelineIndex;\n  };\n  static_assert( sizeof( GraphicsPipelineCreateInfo ) == sizeof( VkGraphicsPipelineCreateInfo ), \"struct and wrapper have different size!\" );\n\n  struct PhysicalDeviceLimits\n  {\n    operator const VkPhysicalDeviceLimits&() const\n    {\n      return *reinterpret_cast<const VkPhysicalDeviceLimits*>(this);\n    }\n\n    bool operator==( PhysicalDeviceLimits const& rhs ) const\n    {\n      return ( maxImageDimension1D == rhs.maxImageDimension1D )\n          && ( maxImageDimension2D == rhs.maxImageDimension2D )\n          && ( maxImageDimension3D == rhs.maxImageDimension3D )\n          && ( maxImageDimensionCube == rhs.maxImageDimensionCube )\n          && ( maxImageArrayLayers == rhs.maxImageArrayLayers )\n          && ( maxTexelBufferElements == rhs.maxTexelBufferElements )\n          && ( maxUniformBufferRange == rhs.maxUniformBufferRange )\n          && ( maxStorageBufferRange == rhs.maxStorageBufferRange )\n          && ( maxPushConstantsSize == rhs.maxPushConstantsSize )\n          && ( maxMemoryAllocationCount == rhs.maxMemoryAllocationCount )\n          && ( maxSamplerAllocationCount == rhs.maxSamplerAllocationCount )\n          && ( bufferImageGranularity == rhs.bufferImageGranularity )\n          && ( sparseAddressSpaceSize == rhs.sparseAddressSpaceSize )\n          && ( maxBoundDescriptorSets == rhs.maxBoundDescriptorSets )\n          && ( maxPerStageDescriptorSamplers == rhs.maxPerStageDescriptorSamplers )\n          && ( maxPerStageDescriptorUniformBuffers == rhs.maxPerStageDescriptorUniformBuffers )\n          && ( maxPerStageDescriptorStorageBuffers == rhs.maxPerStageDescriptorStorageBuffers )\n          && ( maxPerStageDescriptorSampledImages == rhs.maxPerStageDescriptorSampledImages )\n          && ( maxPerStageDescriptorStorageImages == rhs.maxPerStageDescriptorStorageImages )\n          && ( maxPerStageDescriptorInputAttachments == rhs.maxPerStageDescriptorInputAttachments )\n          && ( maxPerStageResources == rhs.maxPerStageResources )\n          && ( maxDescriptorSetSamplers == rhs.maxDescriptorSetSamplers )\n          && ( maxDescriptorSetUniformBuffers == rhs.maxDescriptorSetUniformBuffers )\n          && ( maxDescriptorSetUniformBuffersDynamic == rhs.maxDescriptorSetUniformBuffersDynamic )\n          && ( maxDescriptorSetStorageBuffers == rhs.maxDescriptorSetStorageBuffers )\n          && ( maxDescriptorSetStorageBuffersDynamic == rhs.maxDescriptorSetStorageBuffersDynamic )\n          && ( maxDescriptorSetSampledImages == rhs.maxDescriptorSetSampledImages )\n          && ( maxDescriptorSetStorageImages == rhs.maxDescriptorSetStorageImages )\n          && ( maxDescriptorSetInputAttachments == rhs.maxDescriptorSetInputAttachments )\n          && ( maxVertexInputAttributes == rhs.maxVertexInputAttributes )\n          && ( maxVertexInputBindings == rhs.maxVertexInputBindings )\n          && ( maxVertexInputAttributeOffset == rhs.maxVertexInputAttributeOffset )\n          && ( maxVertexInputBindingStride == rhs.maxVertexInputBindingStride )\n          && ( maxVertexOutputComponents == rhs.maxVertexOutputComponents )\n          && ( maxTessellationGenerationLevel == rhs.maxTessellationGenerationLevel )\n          && ( maxTessellationPatchSize == rhs.maxTessellationPatchSize )\n          && ( maxTessellationControlPerVertexInputComponents == rhs.maxTessellationControlPerVertexInputComponents )\n          && ( maxTessellationControlPerVertexOutputComponents == rhs.maxTessellationControlPerVertexOutputComponents )\n          && ( maxTessellationControlPerPatchOutputComponents == rhs.maxTessellationControlPerPatchOutputComponents )\n          && ( maxTessellationControlTotalOutputComponents == rhs.maxTessellationControlTotalOutputComponents )\n          && ( maxTessellationEvaluationInputComponents == rhs.maxTessellationEvaluationInputComponents )\n          && ( maxTessellationEvaluationOutputComponents == rhs.maxTessellationEvaluationOutputComponents )\n          && ( maxGeometryShaderInvocations == rhs.maxGeometryShaderInvocations )\n          && ( maxGeometryInputComponents == rhs.maxGeometryInputComponents )\n          && ( maxGeometryOutputComponents == rhs.maxGeometryOutputComponents )\n          && ( maxGeometryOutputVertices == rhs.maxGeometryOutputVertices )\n          && ( maxGeometryTotalOutputComponents == rhs.maxGeometryTotalOutputComponents )\n          && ( maxFragmentInputComponents == rhs.maxFragmentInputComponents )\n          && ( maxFragmentOutputAttachments == rhs.maxFragmentOutputAttachments )\n          && ( maxFragmentDualSrcAttachments == rhs.maxFragmentDualSrcAttachments )\n          && ( maxFragmentCombinedOutputResources == rhs.maxFragmentCombinedOutputResources )\n          && ( maxComputeSharedMemorySize == rhs.maxComputeSharedMemorySize )\n          && ( memcmp( maxComputeWorkGroupCount, rhs.maxComputeWorkGroupCount, 3 * sizeof( uint32_t ) ) == 0 )\n          && ( maxComputeWorkGroupInvocations == rhs.maxComputeWorkGroupInvocations )\n          && ( memcmp( maxComputeWorkGroupSize, rhs.maxComputeWorkGroupSize, 3 * sizeof( uint32_t ) ) == 0 )\n          && ( subPixelPrecisionBits == rhs.subPixelPrecisionBits )\n          && ( subTexelPrecisionBits == rhs.subTexelPrecisionBits )\n          && ( mipmapPrecisionBits == rhs.mipmapPrecisionBits )\n          && ( maxDrawIndexedIndexValue == rhs.maxDrawIndexedIndexValue )\n          && ( maxDrawIndirectCount == rhs.maxDrawIndirectCount )\n          && ( maxSamplerLodBias == rhs.maxSamplerLodBias )\n          && ( maxSamplerAnisotropy == rhs.maxSamplerAnisotropy )\n          && ( maxViewports == rhs.maxViewports )\n          && ( memcmp( maxViewportDimensions, rhs.maxViewportDimensions, 2 * sizeof( uint32_t ) ) == 0 )\n          && ( memcmp( viewportBoundsRange, rhs.viewportBoundsRange, 2 * sizeof( float ) ) == 0 )\n          && ( viewportSubPixelBits == rhs.viewportSubPixelBits )\n          && ( minMemoryMapAlignment == rhs.minMemoryMapAlignment )\n          && ( minTexelBufferOffsetAlignment == rhs.minTexelBufferOffsetAlignment )\n          && ( minUniformBufferOffsetAlignment == rhs.minUniformBufferOffsetAlignment )\n          && ( minStorageBufferOffsetAlignment == rhs.minStorageBufferOffsetAlignment )\n          && ( minTexelOffset == rhs.minTexelOffset )\n          && ( maxTexelOffset == rhs.maxTexelOffset )\n          && ( minTexelGatherOffset == rhs.minTexelGatherOffset )\n          && ( maxTexelGatherOffset == rhs.maxTexelGatherOffset )\n          && ( minInterpolationOffset == rhs.minInterpolationOffset )\n          && ( maxInterpolationOffset == rhs.maxInterpolationOffset )\n          && ( subPixelInterpolationOffsetBits == rhs.subPixelInterpolationOffsetBits )\n          && ( maxFramebufferWidth == rhs.maxFramebufferWidth )\n          && ( maxFramebufferHeight == rhs.maxFramebufferHeight )\n          && ( maxFramebufferLayers == rhs.maxFramebufferLayers )\n          && ( framebufferColorSampleCounts == rhs.framebufferColorSampleCounts )\n          && ( framebufferDepthSampleCounts == rhs.framebufferDepthSampleCounts )\n          && ( framebufferStencilSampleCounts == rhs.framebufferStencilSampleCounts )\n          && ( framebufferNoAttachmentsSampleCounts == rhs.framebufferNoAttachmentsSampleCounts )\n          && ( maxColorAttachments == rhs.maxColorAttachments )\n          && ( sampledImageColorSampleCounts == rhs.sampledImageColorSampleCounts )\n          && ( sampledImageIntegerSampleCounts == rhs.sampledImageIntegerSampleCounts )\n          && ( sampledImageDepthSampleCounts == rhs.sampledImageDepthSampleCounts )\n          && ( sampledImageStencilSampleCounts == rhs.sampledImageStencilSampleCounts )\n          && ( storageImageSampleCounts == rhs.storageImageSampleCounts )\n          && ( maxSampleMaskWords == rhs.maxSampleMaskWords )\n          && ( timestampComputeAndGraphics == rhs.timestampComputeAndGraphics )\n          && ( timestampPeriod == rhs.timestampPeriod )\n          && ( maxClipDistances == rhs.maxClipDistances )\n          && ( maxCullDistances == rhs.maxCullDistances )\n          && ( maxCombinedClipAndCullDistances == rhs.maxCombinedClipAndCullDistances )\n          && ( discreteQueuePriorities == rhs.discreteQueuePriorities )\n          && ( memcmp( pointSizeRange, rhs.pointSizeRange, 2 * sizeof( float ) ) == 0 )\n          && ( memcmp( lineWidthRange, rhs.lineWidthRange, 2 * sizeof( float ) ) == 0 )\n          && ( pointSizeGranularity == rhs.pointSizeGranularity )\n          && ( lineWidthGranularity == rhs.lineWidthGranularity )\n          && ( strictLines == rhs.strictLines )\n          && ( standardSampleLocations == rhs.standardSampleLocations )\n          && ( optimalBufferCopyOffsetAlignment == rhs.optimalBufferCopyOffsetAlignment )\n          && ( optimalBufferCopyRowPitchAlignment == rhs.optimalBufferCopyRowPitchAlignment )\n          && ( nonCoherentAtomSize == rhs.nonCoherentAtomSize );\n    }\n\n    bool operator!=( PhysicalDeviceLimits const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    uint32_t maxImageDimension1D;\n    uint32_t maxImageDimension2D;\n    uint32_t maxImageDimension3D;\n    uint32_t maxImageDimensionCube;\n    uint32_t maxImageArrayLayers;\n    uint32_t maxTexelBufferElements;\n    uint32_t maxUniformBufferRange;\n    uint32_t maxStorageBufferRange;\n    uint32_t maxPushConstantsSize;\n    uint32_t maxMemoryAllocationCount;\n    uint32_t maxSamplerAllocationCount;\n    DeviceSize bufferImageGranularity;\n    DeviceSize sparseAddressSpaceSize;\n    uint32_t maxBoundDescriptorSets;\n    uint32_t maxPerStageDescriptorSamplers;\n    uint32_t maxPerStageDescriptorUniformBuffers;\n    uint32_t maxPerStageDescriptorStorageBuffers;\n    uint32_t maxPerStageDescriptorSampledImages;\n    uint32_t maxPerStageDescriptorStorageImages;\n    uint32_t maxPerStageDescriptorInputAttachments;\n    uint32_t maxPerStageResources;\n    uint32_t maxDescriptorSetSamplers;\n    uint32_t maxDescriptorSetUniformBuffers;\n    uint32_t maxDescriptorSetUniformBuffersDynamic;\n    uint32_t maxDescriptorSetStorageBuffers;\n    uint32_t maxDescriptorSetStorageBuffersDynamic;\n    uint32_t maxDescriptorSetSampledImages;\n    uint32_t maxDescriptorSetStorageImages;\n    uint32_t maxDescriptorSetInputAttachments;\n    uint32_t maxVertexInputAttributes;\n    uint32_t maxVertexInputBindings;\n    uint32_t maxVertexInputAttributeOffset;\n    uint32_t maxVertexInputBindingStride;\n    uint32_t maxVertexOutputComponents;\n    uint32_t maxTessellationGenerationLevel;\n    uint32_t maxTessellationPatchSize;\n    uint32_t maxTessellationControlPerVertexInputComponents;\n    uint32_t maxTessellationControlPerVertexOutputComponents;\n    uint32_t maxTessellationControlPerPatchOutputComponents;\n    uint32_t maxTessellationControlTotalOutputComponents;\n    uint32_t maxTessellationEvaluationInputComponents;\n    uint32_t maxTessellationEvaluationOutputComponents;\n    uint32_t maxGeometryShaderInvocations;\n    uint32_t maxGeometryInputComponents;\n    uint32_t maxGeometryOutputComponents;\n    uint32_t maxGeometryOutputVertices;\n    uint32_t maxGeometryTotalOutputComponents;\n    uint32_t maxFragmentInputComponents;\n    uint32_t maxFragmentOutputAttachments;\n    uint32_t maxFragmentDualSrcAttachments;\n    uint32_t maxFragmentCombinedOutputResources;\n    uint32_t maxComputeSharedMemorySize;\n    uint32_t maxComputeWorkGroupCount[3];\n    uint32_t maxComputeWorkGroupInvocations;\n    uint32_t maxComputeWorkGroupSize[3];\n    uint32_t subPixelPrecisionBits;\n    uint32_t subTexelPrecisionBits;\n    uint32_t mipmapPrecisionBits;\n    uint32_t maxDrawIndexedIndexValue;\n    uint32_t maxDrawIndirectCount;\n    float maxSamplerLodBias;\n    float maxSamplerAnisotropy;\n    uint32_t maxViewports;\n    uint32_t maxViewportDimensions[2];\n    float viewportBoundsRange[2];\n    uint32_t viewportSubPixelBits;\n    size_t minMemoryMapAlignment;\n    DeviceSize minTexelBufferOffsetAlignment;\n    DeviceSize minUniformBufferOffsetAlignment;\n    DeviceSize minStorageBufferOffsetAlignment;\n    int32_t minTexelOffset;\n    uint32_t maxTexelOffset;\n    int32_t minTexelGatherOffset;\n    uint32_t maxTexelGatherOffset;\n    float minInterpolationOffset;\n    float maxInterpolationOffset;\n    uint32_t subPixelInterpolationOffsetBits;\n    uint32_t maxFramebufferWidth;\n    uint32_t maxFramebufferHeight;\n    uint32_t maxFramebufferLayers;\n    SampleCountFlags framebufferColorSampleCounts;\n    SampleCountFlags framebufferDepthSampleCounts;\n    SampleCountFlags framebufferStencilSampleCounts;\n    SampleCountFlags framebufferNoAttachmentsSampleCounts;\n    uint32_t maxColorAttachments;\n    SampleCountFlags sampledImageColorSampleCounts;\n    SampleCountFlags sampledImageIntegerSampleCounts;\n    SampleCountFlags sampledImageDepthSampleCounts;\n    SampleCountFlags sampledImageStencilSampleCounts;\n    SampleCountFlags storageImageSampleCounts;\n    uint32_t maxSampleMaskWords;\n    Bool32 timestampComputeAndGraphics;\n    float timestampPeriod;\n    uint32_t maxClipDistances;\n    uint32_t maxCullDistances;\n    uint32_t maxCombinedClipAndCullDistances;\n    uint32_t discreteQueuePriorities;\n    float pointSizeRange[2];\n    float lineWidthRange[2];\n    float pointSizeGranularity;\n    float lineWidthGranularity;\n    Bool32 strictLines;\n    Bool32 standardSampleLocations;\n    DeviceSize optimalBufferCopyOffsetAlignment;\n    DeviceSize optimalBufferCopyRowPitchAlignment;\n    DeviceSize nonCoherentAtomSize;\n  };\n  static_assert( sizeof( PhysicalDeviceLimits ) == sizeof( VkPhysicalDeviceLimits ), \"struct and wrapper have different size!\" );\n\n  struct PhysicalDeviceProperties\n  {\n    operator const VkPhysicalDeviceProperties&() const\n    {\n      return *reinterpret_cast<const VkPhysicalDeviceProperties*>(this);\n    }\n\n    bool operator==( PhysicalDeviceProperties const& rhs ) const\n    {\n      return ( apiVersion == rhs.apiVersion )\n          && ( driverVersion == rhs.driverVersion )\n          && ( vendorID == rhs.vendorID )\n          && ( deviceID == rhs.deviceID )\n          && ( deviceType == rhs.deviceType )\n          && ( memcmp( deviceName, rhs.deviceName, VK_MAX_PHYSICAL_DEVICE_NAME_SIZE * sizeof( char ) ) == 0 )\n          && ( memcmp( pipelineCacheUUID, rhs.pipelineCacheUUID, VK_UUID_SIZE * sizeof( uint8_t ) ) == 0 )\n          && ( limits == rhs.limits )\n          && ( sparseProperties == rhs.sparseProperties );\n    }\n\n    bool operator!=( PhysicalDeviceProperties const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    uint32_t apiVersion;\n    uint32_t driverVersion;\n    uint32_t vendorID;\n    uint32_t deviceID;\n    PhysicalDeviceType deviceType;\n    char deviceName[VK_MAX_PHYSICAL_DEVICE_NAME_SIZE];\n    uint8_t pipelineCacheUUID[VK_UUID_SIZE];\n    PhysicalDeviceLimits limits;\n    PhysicalDeviceSparseProperties sparseProperties;\n  };\n  static_assert( sizeof( PhysicalDeviceProperties ) == sizeof( VkPhysicalDeviceProperties ), \"struct and wrapper have different size!\" );\n\n  struct PhysicalDeviceProperties2KHR\n  {\n    operator const VkPhysicalDeviceProperties2KHR&() const\n    {\n      return *reinterpret_cast<const VkPhysicalDeviceProperties2KHR*>(this);\n    }\n\n    bool operator==( PhysicalDeviceProperties2KHR const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( properties == rhs.properties );\n    }\n\n    bool operator!=( PhysicalDeviceProperties2KHR const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    void* pNext;\n    PhysicalDeviceProperties properties;\n  };\n  static_assert( sizeof( PhysicalDeviceProperties2KHR ) == sizeof( VkPhysicalDeviceProperties2KHR ), \"struct and wrapper have different size!\" );\n\n  struct ImageFormatProperties2KHR\n  {\n    operator const VkImageFormatProperties2KHR&() const\n    {\n      return *reinterpret_cast<const VkImageFormatProperties2KHR*>(this);\n    }\n\n    bool operator==( ImageFormatProperties2KHR const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( imageFormatProperties == rhs.imageFormatProperties );\n    }\n\n    bool operator!=( ImageFormatProperties2KHR const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    void* pNext;\n    ImageFormatProperties imageFormatProperties;\n  };\n  static_assert( sizeof( ImageFormatProperties2KHR ) == sizeof( VkImageFormatProperties2KHR ), \"struct and wrapper have different size!\" );\n\n  struct PhysicalDeviceSparseImageFormatInfo2KHR\n  {\n    PhysicalDeviceSparseImageFormatInfo2KHR( Format format_ = Format::eUndefined, ImageType type_ = ImageType::e1D, SampleCountFlagBits samples_ = SampleCountFlagBits::e1, ImageUsageFlags usage_ = ImageUsageFlags(), ImageTiling tiling_ = ImageTiling::eOptimal )\n      : sType( StructureType::ePhysicalDeviceSparseImageFormatInfo2KHR )\n      , pNext( nullptr )\n      , format( format_ )\n      , type( type_ )\n      , samples( samples_ )\n      , usage( usage_ )\n      , tiling( tiling_ )\n    {\n    }\n\n    PhysicalDeviceSparseImageFormatInfo2KHR( VkPhysicalDeviceSparseImageFormatInfo2KHR const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PhysicalDeviceSparseImageFormatInfo2KHR) );\n    }\n\n    PhysicalDeviceSparseImageFormatInfo2KHR& operator=( VkPhysicalDeviceSparseImageFormatInfo2KHR const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PhysicalDeviceSparseImageFormatInfo2KHR) );\n      return *this;\n    }\n\n    PhysicalDeviceSparseImageFormatInfo2KHR& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    PhysicalDeviceSparseImageFormatInfo2KHR& setFormat( Format format_ )\n    {\n      format = format_;\n      return *this;\n    }\n\n    PhysicalDeviceSparseImageFormatInfo2KHR& setType( ImageType type_ )\n    {\n      type = type_;\n      return *this;\n    }\n\n    PhysicalDeviceSparseImageFormatInfo2KHR& setSamples( SampleCountFlagBits samples_ )\n    {\n      samples = samples_;\n      return *this;\n    }\n\n    PhysicalDeviceSparseImageFormatInfo2KHR& setUsage( ImageUsageFlags usage_ )\n    {\n      usage = usage_;\n      return *this;\n    }\n\n    PhysicalDeviceSparseImageFormatInfo2KHR& setTiling( ImageTiling tiling_ )\n    {\n      tiling = tiling_;\n      return *this;\n    }\n\n    operator const VkPhysicalDeviceSparseImageFormatInfo2KHR&() const\n    {\n      return *reinterpret_cast<const VkPhysicalDeviceSparseImageFormatInfo2KHR*>(this);\n    }\n\n    bool operator==( PhysicalDeviceSparseImageFormatInfo2KHR const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( format == rhs.format )\n          && ( type == rhs.type )\n          && ( samples == rhs.samples )\n          && ( usage == rhs.usage )\n          && ( tiling == rhs.tiling );\n    }\n\n    bool operator!=( PhysicalDeviceSparseImageFormatInfo2KHR const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    Format format;\n    ImageType type;\n    SampleCountFlagBits samples;\n    ImageUsageFlags usage;\n    ImageTiling tiling;\n  };\n  static_assert( sizeof( PhysicalDeviceSparseImageFormatInfo2KHR ) == sizeof( VkPhysicalDeviceSparseImageFormatInfo2KHR ), \"struct and wrapper have different size!\" );\n\n  enum class AttachmentDescriptionFlagBits\n  {\n    eMayAlias = VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT\n  };\n\n  using AttachmentDescriptionFlags = Flags<AttachmentDescriptionFlagBits, VkAttachmentDescriptionFlags>;\n\n  VULKAN_HPP_INLINE AttachmentDescriptionFlags operator|( AttachmentDescriptionFlagBits bit0, AttachmentDescriptionFlagBits bit1 )\n  {\n    return AttachmentDescriptionFlags( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE AttachmentDescriptionFlags operator~( AttachmentDescriptionFlagBits bits )\n  {\n    return ~( AttachmentDescriptionFlags( bits ) );\n  }\n\n  template <> struct FlagTraits<AttachmentDescriptionFlagBits>\n  {\n    enum\n    {\n      allFlags = VkFlags(AttachmentDescriptionFlagBits::eMayAlias)\n    };\n  };\n\n  struct AttachmentDescription\n  {\n    AttachmentDescription( AttachmentDescriptionFlags flags_ = AttachmentDescriptionFlags(), Format format_ = Format::eUndefined, SampleCountFlagBits samples_ = SampleCountFlagBits::e1, AttachmentLoadOp loadOp_ = AttachmentLoadOp::eLoad, AttachmentStoreOp storeOp_ = AttachmentStoreOp::eStore, AttachmentLoadOp stencilLoadOp_ = AttachmentLoadOp::eLoad, AttachmentStoreOp stencilStoreOp_ = AttachmentStoreOp::eStore, ImageLayout initialLayout_ = ImageLayout::eUndefined, ImageLayout finalLayout_ = ImageLayout::eUndefined )\n      : flags( flags_ )\n      , format( format_ )\n      , samples( samples_ )\n      , loadOp( loadOp_ )\n      , storeOp( storeOp_ )\n      , stencilLoadOp( stencilLoadOp_ )\n      , stencilStoreOp( stencilStoreOp_ )\n      , initialLayout( initialLayout_ )\n      , finalLayout( finalLayout_ )\n    {\n    }\n\n    AttachmentDescription( VkAttachmentDescription const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(AttachmentDescription) );\n    }\n\n    AttachmentDescription& operator=( VkAttachmentDescription const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(AttachmentDescription) );\n      return *this;\n    }\n\n    AttachmentDescription& setFlags( AttachmentDescriptionFlags flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    AttachmentDescription& setFormat( Format format_ )\n    {\n      format = format_;\n      return *this;\n    }\n\n    AttachmentDescription& setSamples( SampleCountFlagBits samples_ )\n    {\n      samples = samples_;\n      return *this;\n    }\n\n    AttachmentDescription& setLoadOp( AttachmentLoadOp loadOp_ )\n    {\n      loadOp = loadOp_;\n      return *this;\n    }\n\n    AttachmentDescription& setStoreOp( AttachmentStoreOp storeOp_ )\n    {\n      storeOp = storeOp_;\n      return *this;\n    }\n\n    AttachmentDescription& setStencilLoadOp( AttachmentLoadOp stencilLoadOp_ )\n    {\n      stencilLoadOp = stencilLoadOp_;\n      return *this;\n    }\n\n    AttachmentDescription& setStencilStoreOp( AttachmentStoreOp stencilStoreOp_ )\n    {\n      stencilStoreOp = stencilStoreOp_;\n      return *this;\n    }\n\n    AttachmentDescription& setInitialLayout( ImageLayout initialLayout_ )\n    {\n      initialLayout = initialLayout_;\n      return *this;\n    }\n\n    AttachmentDescription& setFinalLayout( ImageLayout finalLayout_ )\n    {\n      finalLayout = finalLayout_;\n      return *this;\n    }\n\n    operator const VkAttachmentDescription&() const\n    {\n      return *reinterpret_cast<const VkAttachmentDescription*>(this);\n    }\n\n    bool operator==( AttachmentDescription const& rhs ) const\n    {\n      return ( flags == rhs.flags )\n          && ( format == rhs.format )\n          && ( samples == rhs.samples )\n          && ( loadOp == rhs.loadOp )\n          && ( storeOp == rhs.storeOp )\n          && ( stencilLoadOp == rhs.stencilLoadOp )\n          && ( stencilStoreOp == rhs.stencilStoreOp )\n          && ( initialLayout == rhs.initialLayout )\n          && ( finalLayout == rhs.finalLayout );\n    }\n\n    bool operator!=( AttachmentDescription const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    AttachmentDescriptionFlags flags;\n    Format format;\n    SampleCountFlagBits samples;\n    AttachmentLoadOp loadOp;\n    AttachmentStoreOp storeOp;\n    AttachmentLoadOp stencilLoadOp;\n    AttachmentStoreOp stencilStoreOp;\n    ImageLayout initialLayout;\n    ImageLayout finalLayout;\n  };\n  static_assert( sizeof( AttachmentDescription ) == sizeof( VkAttachmentDescription ), \"struct and wrapper have different size!\" );\n\n  enum class StencilFaceFlagBits\n  {\n    eFront = VK_STENCIL_FACE_FRONT_BIT,\n    eBack = VK_STENCIL_FACE_BACK_BIT,\n    eVkStencilFrontAndBack = VK_STENCIL_FRONT_AND_BACK\n  };\n\n  using StencilFaceFlags = Flags<StencilFaceFlagBits, VkStencilFaceFlags>;\n\n  VULKAN_HPP_INLINE StencilFaceFlags operator|( StencilFaceFlagBits bit0, StencilFaceFlagBits bit1 )\n  {\n    return StencilFaceFlags( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE StencilFaceFlags operator~( StencilFaceFlagBits bits )\n  {\n    return ~( StencilFaceFlags( bits ) );\n  }\n\n  template <> struct FlagTraits<StencilFaceFlagBits>\n  {\n    enum\n    {\n      allFlags = VkFlags(StencilFaceFlagBits::eFront) | VkFlags(StencilFaceFlagBits::eBack) | VkFlags(StencilFaceFlagBits::eVkStencilFrontAndBack)\n    };\n  };\n\n  enum class DescriptorPoolCreateFlagBits\n  {\n    eFreeDescriptorSet = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT\n  };\n\n  using DescriptorPoolCreateFlags = Flags<DescriptorPoolCreateFlagBits, VkDescriptorPoolCreateFlags>;\n\n  VULKAN_HPP_INLINE DescriptorPoolCreateFlags operator|( DescriptorPoolCreateFlagBits bit0, DescriptorPoolCreateFlagBits bit1 )\n  {\n    return DescriptorPoolCreateFlags( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE DescriptorPoolCreateFlags operator~( DescriptorPoolCreateFlagBits bits )\n  {\n    return ~( DescriptorPoolCreateFlags( bits ) );\n  }\n\n  template <> struct FlagTraits<DescriptorPoolCreateFlagBits>\n  {\n    enum\n    {\n      allFlags = VkFlags(DescriptorPoolCreateFlagBits::eFreeDescriptorSet)\n    };\n  };\n\n  struct DescriptorPoolCreateInfo\n  {\n    DescriptorPoolCreateInfo( DescriptorPoolCreateFlags flags_ = DescriptorPoolCreateFlags(), uint32_t maxSets_ = 0, uint32_t poolSizeCount_ = 0, const DescriptorPoolSize* pPoolSizes_ = nullptr )\n      : sType( StructureType::eDescriptorPoolCreateInfo )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , maxSets( maxSets_ )\n      , poolSizeCount( poolSizeCount_ )\n      , pPoolSizes( pPoolSizes_ )\n    {\n    }\n\n    DescriptorPoolCreateInfo( VkDescriptorPoolCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DescriptorPoolCreateInfo) );\n    }\n\n    DescriptorPoolCreateInfo& operator=( VkDescriptorPoolCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DescriptorPoolCreateInfo) );\n      return *this;\n    }\n\n    DescriptorPoolCreateInfo& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    DescriptorPoolCreateInfo& setFlags( DescriptorPoolCreateFlags flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    DescriptorPoolCreateInfo& setMaxSets( uint32_t maxSets_ )\n    {\n      maxSets = maxSets_;\n      return *this;\n    }\n\n    DescriptorPoolCreateInfo& setPoolSizeCount( uint32_t poolSizeCount_ )\n    {\n      poolSizeCount = poolSizeCount_;\n      return *this;\n    }\n\n    DescriptorPoolCreateInfo& setPPoolSizes( const DescriptorPoolSize* pPoolSizes_ )\n    {\n      pPoolSizes = pPoolSizes_;\n      return *this;\n    }\n\n    operator const VkDescriptorPoolCreateInfo&() const\n    {\n      return *reinterpret_cast<const VkDescriptorPoolCreateInfo*>(this);\n    }\n\n    bool operator==( DescriptorPoolCreateInfo const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( maxSets == rhs.maxSets )\n          && ( poolSizeCount == rhs.poolSizeCount )\n          && ( pPoolSizes == rhs.pPoolSizes );\n    }\n\n    bool operator!=( DescriptorPoolCreateInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    DescriptorPoolCreateFlags flags;\n    uint32_t maxSets;\n    uint32_t poolSizeCount;\n    const DescriptorPoolSize* pPoolSizes;\n  };\n  static_assert( sizeof( DescriptorPoolCreateInfo ) == sizeof( VkDescriptorPoolCreateInfo ), \"struct and wrapper have different size!\" );\n\n  enum class DependencyFlagBits\n  {\n    eByRegion = VK_DEPENDENCY_BY_REGION_BIT,\n    eViewLocalKHX = VK_DEPENDENCY_VIEW_LOCAL_BIT_KHX,\n    eDeviceGroupKHX = VK_DEPENDENCY_DEVICE_GROUP_BIT_KHX\n  };\n\n  using DependencyFlags = Flags<DependencyFlagBits, VkDependencyFlags>;\n\n  VULKAN_HPP_INLINE DependencyFlags operator|( DependencyFlagBits bit0, DependencyFlagBits bit1 )\n  {\n    return DependencyFlags( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE DependencyFlags operator~( DependencyFlagBits bits )\n  {\n    return ~( DependencyFlags( bits ) );\n  }\n\n  template <> struct FlagTraits<DependencyFlagBits>\n  {\n    enum\n    {\n      allFlags = VkFlags(DependencyFlagBits::eByRegion) | VkFlags(DependencyFlagBits::eViewLocalKHX) | VkFlags(DependencyFlagBits::eDeviceGroupKHX)\n    };\n  };\n\n  struct SubpassDependency\n  {\n    SubpassDependency( uint32_t srcSubpass_ = 0, uint32_t dstSubpass_ = 0, PipelineStageFlags srcStageMask_ = PipelineStageFlags(), PipelineStageFlags dstStageMask_ = PipelineStageFlags(), AccessFlags srcAccessMask_ = AccessFlags(), AccessFlags dstAccessMask_ = AccessFlags(), DependencyFlags dependencyFlags_ = DependencyFlags() )\n      : srcSubpass( srcSubpass_ )\n      , dstSubpass( dstSubpass_ )\n      , srcStageMask( srcStageMask_ )\n      , dstStageMask( dstStageMask_ )\n      , srcAccessMask( srcAccessMask_ )\n      , dstAccessMask( dstAccessMask_ )\n      , dependencyFlags( dependencyFlags_ )\n    {\n    }\n\n    SubpassDependency( VkSubpassDependency const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(SubpassDependency) );\n    }\n\n    SubpassDependency& operator=( VkSubpassDependency const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(SubpassDependency) );\n      return *this;\n    }\n\n    SubpassDependency& setSrcSubpass( uint32_t srcSubpass_ )\n    {\n      srcSubpass = srcSubpass_;\n      return *this;\n    }\n\n    SubpassDependency& setDstSubpass( uint32_t dstSubpass_ )\n    {\n      dstSubpass = dstSubpass_;\n      return *this;\n    }\n\n    SubpassDependency& setSrcStageMask( PipelineStageFlags srcStageMask_ )\n    {\n      srcStageMask = srcStageMask_;\n      return *this;\n    }\n\n    SubpassDependency& setDstStageMask( PipelineStageFlags dstStageMask_ )\n    {\n      dstStageMask = dstStageMask_;\n      return *this;\n    }\n\n    SubpassDependency& setSrcAccessMask( AccessFlags srcAccessMask_ )\n    {\n      srcAccessMask = srcAccessMask_;\n      return *this;\n    }\n\n    SubpassDependency& setDstAccessMask( AccessFlags dstAccessMask_ )\n    {\n      dstAccessMask = dstAccessMask_;\n      return *this;\n    }\n\n    SubpassDependency& setDependencyFlags( DependencyFlags dependencyFlags_ )\n    {\n      dependencyFlags = dependencyFlags_;\n      return *this;\n    }\n\n    operator const VkSubpassDependency&() const\n    {\n      return *reinterpret_cast<const VkSubpassDependency*>(this);\n    }\n\n    bool operator==( SubpassDependency const& rhs ) const\n    {\n      return ( srcSubpass == rhs.srcSubpass )\n          && ( dstSubpass == rhs.dstSubpass )\n          && ( srcStageMask == rhs.srcStageMask )\n          && ( dstStageMask == rhs.dstStageMask )\n          && ( srcAccessMask == rhs.srcAccessMask )\n          && ( dstAccessMask == rhs.dstAccessMask )\n          && ( dependencyFlags == rhs.dependencyFlags );\n    }\n\n    bool operator!=( SubpassDependency const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    uint32_t srcSubpass;\n    uint32_t dstSubpass;\n    PipelineStageFlags srcStageMask;\n    PipelineStageFlags dstStageMask;\n    AccessFlags srcAccessMask;\n    AccessFlags dstAccessMask;\n    DependencyFlags dependencyFlags;\n  };\n  static_assert( sizeof( SubpassDependency ) == sizeof( VkSubpassDependency ), \"struct and wrapper have different size!\" );\n\n  enum class PresentModeKHR\n  {\n    eImmediate = VK_PRESENT_MODE_IMMEDIATE_KHR,\n    eMailbox = VK_PRESENT_MODE_MAILBOX_KHR,\n    eFifo = VK_PRESENT_MODE_FIFO_KHR,\n    eFifoRelaxed = VK_PRESENT_MODE_FIFO_RELAXED_KHR,\n    eSharedDemandRefresh = VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR,\n    eSharedContinuousRefresh = VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR\n  };\n\n  enum class ColorSpaceKHR\n  {\n    eSrgbNonlinear = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,\n    eDisplayP3NonlinearEXT = VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT,\n    eExtendedSrgbLinearEXT = VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT,\n    eDciP3LinearEXT = VK_COLOR_SPACE_DCI_P3_LINEAR_EXT,\n    eDciP3NonlinearEXT = VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT,\n    eBt709LinearEXT = VK_COLOR_SPACE_BT709_LINEAR_EXT,\n    eBt709NonlinearEXT = VK_COLOR_SPACE_BT709_NONLINEAR_EXT,\n    eBt2020LinearEXT = VK_COLOR_SPACE_BT2020_LINEAR_EXT,\n    eHdr10St2084EXT = VK_COLOR_SPACE_HDR10_ST2084_EXT,\n    eDolbyvisionEXT = VK_COLOR_SPACE_DOLBYVISION_EXT,\n    eHdr10HlgEXT = VK_COLOR_SPACE_HDR10_HLG_EXT,\n    eAdobergbLinearEXT = VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT,\n    eAdobergbNonlinearEXT = VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT,\n    ePassThroughEXT = VK_COLOR_SPACE_PASS_THROUGH_EXT\n  };\n\n  struct SurfaceFormatKHR\n  {\n    operator const VkSurfaceFormatKHR&() const\n    {\n      return *reinterpret_cast<const VkSurfaceFormatKHR*>(this);\n    }\n\n    bool operator==( SurfaceFormatKHR const& rhs ) const\n    {\n      return ( format == rhs.format )\n          && ( colorSpace == rhs.colorSpace );\n    }\n\n    bool operator!=( SurfaceFormatKHR const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    Format format;\n    ColorSpaceKHR colorSpace;\n  };\n  static_assert( sizeof( SurfaceFormatKHR ) == sizeof( VkSurfaceFormatKHR ), \"struct and wrapper have different size!\" );\n\n  struct SurfaceFormat2KHR\n  {\n    operator const VkSurfaceFormat2KHR&() const\n    {\n      return *reinterpret_cast<const VkSurfaceFormat2KHR*>(this);\n    }\n\n    bool operator==( SurfaceFormat2KHR const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( surfaceFormat == rhs.surfaceFormat );\n    }\n\n    bool operator!=( SurfaceFormat2KHR const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    void* pNext;\n    SurfaceFormatKHR surfaceFormat;\n  };\n  static_assert( sizeof( SurfaceFormat2KHR ) == sizeof( VkSurfaceFormat2KHR ), \"struct and wrapper have different size!\" );\n\n  enum class DisplayPlaneAlphaFlagBitsKHR\n  {\n    eOpaque = VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR,\n    eGlobal = VK_DISPLAY_PLANE_ALPHA_GLOBAL_BIT_KHR,\n    ePerPixel = VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR,\n    ePerPixelPremultiplied = VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR\n  };\n\n  using DisplayPlaneAlphaFlagsKHR = Flags<DisplayPlaneAlphaFlagBitsKHR, VkDisplayPlaneAlphaFlagsKHR>;\n\n  VULKAN_HPP_INLINE DisplayPlaneAlphaFlagsKHR operator|( DisplayPlaneAlphaFlagBitsKHR bit0, DisplayPlaneAlphaFlagBitsKHR bit1 )\n  {\n    return DisplayPlaneAlphaFlagsKHR( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE DisplayPlaneAlphaFlagsKHR operator~( DisplayPlaneAlphaFlagBitsKHR bits )\n  {\n    return ~( DisplayPlaneAlphaFlagsKHR( bits ) );\n  }\n\n  template <> struct FlagTraits<DisplayPlaneAlphaFlagBitsKHR>\n  {\n    enum\n    {\n      allFlags = VkFlags(DisplayPlaneAlphaFlagBitsKHR::eOpaque) | VkFlags(DisplayPlaneAlphaFlagBitsKHR::eGlobal) | VkFlags(DisplayPlaneAlphaFlagBitsKHR::ePerPixel) | VkFlags(DisplayPlaneAlphaFlagBitsKHR::ePerPixelPremultiplied)\n    };\n  };\n\n  struct DisplayPlaneCapabilitiesKHR\n  {\n    operator const VkDisplayPlaneCapabilitiesKHR&() const\n    {\n      return *reinterpret_cast<const VkDisplayPlaneCapabilitiesKHR*>(this);\n    }\n\n    bool operator==( DisplayPlaneCapabilitiesKHR const& rhs ) const\n    {\n      return ( supportedAlpha == rhs.supportedAlpha )\n          && ( minSrcPosition == rhs.minSrcPosition )\n          && ( maxSrcPosition == rhs.maxSrcPosition )\n          && ( minSrcExtent == rhs.minSrcExtent )\n          && ( maxSrcExtent == rhs.maxSrcExtent )\n          && ( minDstPosition == rhs.minDstPosition )\n          && ( maxDstPosition == rhs.maxDstPosition )\n          && ( minDstExtent == rhs.minDstExtent )\n          && ( maxDstExtent == rhs.maxDstExtent );\n    }\n\n    bool operator!=( DisplayPlaneCapabilitiesKHR const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    DisplayPlaneAlphaFlagsKHR supportedAlpha;\n    Offset2D minSrcPosition;\n    Offset2D maxSrcPosition;\n    Extent2D minSrcExtent;\n    Extent2D maxSrcExtent;\n    Offset2D minDstPosition;\n    Offset2D maxDstPosition;\n    Extent2D minDstExtent;\n    Extent2D maxDstExtent;\n  };\n  static_assert( sizeof( DisplayPlaneCapabilitiesKHR ) == sizeof( VkDisplayPlaneCapabilitiesKHR ), \"struct and wrapper have different size!\" );\n\n  enum class CompositeAlphaFlagBitsKHR\n  {\n    eOpaque = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,\n    ePreMultiplied = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR,\n    ePostMultiplied = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR,\n    eInherit = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR\n  };\n\n  using CompositeAlphaFlagsKHR = Flags<CompositeAlphaFlagBitsKHR, VkCompositeAlphaFlagsKHR>;\n\n  VULKAN_HPP_INLINE CompositeAlphaFlagsKHR operator|( CompositeAlphaFlagBitsKHR bit0, CompositeAlphaFlagBitsKHR bit1 )\n  {\n    return CompositeAlphaFlagsKHR( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE CompositeAlphaFlagsKHR operator~( CompositeAlphaFlagBitsKHR bits )\n  {\n    return ~( CompositeAlphaFlagsKHR( bits ) );\n  }\n\n  template <> struct FlagTraits<CompositeAlphaFlagBitsKHR>\n  {\n    enum\n    {\n      allFlags = VkFlags(CompositeAlphaFlagBitsKHR::eOpaque) | VkFlags(CompositeAlphaFlagBitsKHR::ePreMultiplied) | VkFlags(CompositeAlphaFlagBitsKHR::ePostMultiplied) | VkFlags(CompositeAlphaFlagBitsKHR::eInherit)\n    };\n  };\n\n  enum class SurfaceTransformFlagBitsKHR\n  {\n    eIdentity = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR,\n    eRotate90 = VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR,\n    eRotate180 = VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR,\n    eRotate270 = VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR,\n    eHorizontalMirror = VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR,\n    eHorizontalMirrorRotate90 = VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR,\n    eHorizontalMirrorRotate180 = VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR,\n    eHorizontalMirrorRotate270 = VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR,\n    eInherit = VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR\n  };\n\n  using SurfaceTransformFlagsKHR = Flags<SurfaceTransformFlagBitsKHR, VkSurfaceTransformFlagsKHR>;\n\n  VULKAN_HPP_INLINE SurfaceTransformFlagsKHR operator|( SurfaceTransformFlagBitsKHR bit0, SurfaceTransformFlagBitsKHR bit1 )\n  {\n    return SurfaceTransformFlagsKHR( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE SurfaceTransformFlagsKHR operator~( SurfaceTransformFlagBitsKHR bits )\n  {\n    return ~( SurfaceTransformFlagsKHR( bits ) );\n  }\n\n  template <> struct FlagTraits<SurfaceTransformFlagBitsKHR>\n  {\n    enum\n    {\n      allFlags = VkFlags(SurfaceTransformFlagBitsKHR::eIdentity) | VkFlags(SurfaceTransformFlagBitsKHR::eRotate90) | VkFlags(SurfaceTransformFlagBitsKHR::eRotate180) | VkFlags(SurfaceTransformFlagBitsKHR::eRotate270) | VkFlags(SurfaceTransformFlagBitsKHR::eHorizontalMirror) | VkFlags(SurfaceTransformFlagBitsKHR::eHorizontalMirrorRotate90) | VkFlags(SurfaceTransformFlagBitsKHR::eHorizontalMirrorRotate180) | VkFlags(SurfaceTransformFlagBitsKHR::eHorizontalMirrorRotate270) | VkFlags(SurfaceTransformFlagBitsKHR::eInherit)\n    };\n  };\n\n  struct DisplayPropertiesKHR\n  {\n    operator const VkDisplayPropertiesKHR&() const\n    {\n      return *reinterpret_cast<const VkDisplayPropertiesKHR*>(this);\n    }\n\n    bool operator==( DisplayPropertiesKHR const& rhs ) const\n    {\n      return ( display == rhs.display )\n          && ( displayName == rhs.displayName )\n          && ( physicalDimensions == rhs.physicalDimensions )\n          && ( physicalResolution == rhs.physicalResolution )\n          && ( supportedTransforms == rhs.supportedTransforms )\n          && ( planeReorderPossible == rhs.planeReorderPossible )\n          && ( persistentContent == rhs.persistentContent );\n    }\n\n    bool operator!=( DisplayPropertiesKHR const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    DisplayKHR display;\n    const char* displayName;\n    Extent2D physicalDimensions;\n    Extent2D physicalResolution;\n    SurfaceTransformFlagsKHR supportedTransforms;\n    Bool32 planeReorderPossible;\n    Bool32 persistentContent;\n  };\n  static_assert( sizeof( DisplayPropertiesKHR ) == sizeof( VkDisplayPropertiesKHR ), \"struct and wrapper have different size!\" );\n\n  struct DisplaySurfaceCreateInfoKHR\n  {\n    DisplaySurfaceCreateInfoKHR( DisplaySurfaceCreateFlagsKHR flags_ = DisplaySurfaceCreateFlagsKHR(), DisplayModeKHR displayMode_ = DisplayModeKHR(), uint32_t planeIndex_ = 0, uint32_t planeStackIndex_ = 0, SurfaceTransformFlagBitsKHR transform_ = SurfaceTransformFlagBitsKHR::eIdentity, float globalAlpha_ = 0, DisplayPlaneAlphaFlagBitsKHR alphaMode_ = DisplayPlaneAlphaFlagBitsKHR::eOpaque, Extent2D imageExtent_ = Extent2D() )\n      : sType( StructureType::eDisplaySurfaceCreateInfoKHR )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , displayMode( displayMode_ )\n      , planeIndex( planeIndex_ )\n      , planeStackIndex( planeStackIndex_ )\n      , transform( transform_ )\n      , globalAlpha( globalAlpha_ )\n      , alphaMode( alphaMode_ )\n      , imageExtent( imageExtent_ )\n    {\n    }\n\n    DisplaySurfaceCreateInfoKHR( VkDisplaySurfaceCreateInfoKHR const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DisplaySurfaceCreateInfoKHR) );\n    }\n\n    DisplaySurfaceCreateInfoKHR& operator=( VkDisplaySurfaceCreateInfoKHR const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DisplaySurfaceCreateInfoKHR) );\n      return *this;\n    }\n\n    DisplaySurfaceCreateInfoKHR& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    DisplaySurfaceCreateInfoKHR& setFlags( DisplaySurfaceCreateFlagsKHR flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    DisplaySurfaceCreateInfoKHR& setDisplayMode( DisplayModeKHR displayMode_ )\n    {\n      displayMode = displayMode_;\n      return *this;\n    }\n\n    DisplaySurfaceCreateInfoKHR& setPlaneIndex( uint32_t planeIndex_ )\n    {\n      planeIndex = planeIndex_;\n      return *this;\n    }\n\n    DisplaySurfaceCreateInfoKHR& setPlaneStackIndex( uint32_t planeStackIndex_ )\n    {\n      planeStackIndex = planeStackIndex_;\n      return *this;\n    }\n\n    DisplaySurfaceCreateInfoKHR& setTransform( SurfaceTransformFlagBitsKHR transform_ )\n    {\n      transform = transform_;\n      return *this;\n    }\n\n    DisplaySurfaceCreateInfoKHR& setGlobalAlpha( float globalAlpha_ )\n    {\n      globalAlpha = globalAlpha_;\n      return *this;\n    }\n\n    DisplaySurfaceCreateInfoKHR& setAlphaMode( DisplayPlaneAlphaFlagBitsKHR alphaMode_ )\n    {\n      alphaMode = alphaMode_;\n      return *this;\n    }\n\n    DisplaySurfaceCreateInfoKHR& setImageExtent( Extent2D imageExtent_ )\n    {\n      imageExtent = imageExtent_;\n      return *this;\n    }\n\n    operator const VkDisplaySurfaceCreateInfoKHR&() const\n    {\n      return *reinterpret_cast<const VkDisplaySurfaceCreateInfoKHR*>(this);\n    }\n\n    bool operator==( DisplaySurfaceCreateInfoKHR const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( displayMode == rhs.displayMode )\n          && ( planeIndex == rhs.planeIndex )\n          && ( planeStackIndex == rhs.planeStackIndex )\n          && ( transform == rhs.transform )\n          && ( globalAlpha == rhs.globalAlpha )\n          && ( alphaMode == rhs.alphaMode )\n          && ( imageExtent == rhs.imageExtent );\n    }\n\n    bool operator!=( DisplaySurfaceCreateInfoKHR const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    DisplaySurfaceCreateFlagsKHR flags;\n    DisplayModeKHR displayMode;\n    uint32_t planeIndex;\n    uint32_t planeStackIndex;\n    SurfaceTransformFlagBitsKHR transform;\n    float globalAlpha;\n    DisplayPlaneAlphaFlagBitsKHR alphaMode;\n    Extent2D imageExtent;\n  };\n  static_assert( sizeof( DisplaySurfaceCreateInfoKHR ) == sizeof( VkDisplaySurfaceCreateInfoKHR ), \"struct and wrapper have different size!\" );\n\n  struct SurfaceCapabilitiesKHR\n  {\n    operator const VkSurfaceCapabilitiesKHR&() const\n    {\n      return *reinterpret_cast<const VkSurfaceCapabilitiesKHR*>(this);\n    }\n\n    bool operator==( SurfaceCapabilitiesKHR const& rhs ) const\n    {\n      return ( minImageCount == rhs.minImageCount )\n          && ( maxImageCount == rhs.maxImageCount )\n          && ( currentExtent == rhs.currentExtent )\n          && ( minImageExtent == rhs.minImageExtent )\n          && ( maxImageExtent == rhs.maxImageExtent )\n          && ( maxImageArrayLayers == rhs.maxImageArrayLayers )\n          && ( supportedTransforms == rhs.supportedTransforms )\n          && ( currentTransform == rhs.currentTransform )\n          && ( supportedCompositeAlpha == rhs.supportedCompositeAlpha )\n          && ( supportedUsageFlags == rhs.supportedUsageFlags );\n    }\n\n    bool operator!=( SurfaceCapabilitiesKHR const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    uint32_t minImageCount;\n    uint32_t maxImageCount;\n    Extent2D currentExtent;\n    Extent2D minImageExtent;\n    Extent2D maxImageExtent;\n    uint32_t maxImageArrayLayers;\n    SurfaceTransformFlagsKHR supportedTransforms;\n    SurfaceTransformFlagBitsKHR currentTransform;\n    CompositeAlphaFlagsKHR supportedCompositeAlpha;\n    ImageUsageFlags supportedUsageFlags;\n  };\n  static_assert( sizeof( SurfaceCapabilitiesKHR ) == sizeof( VkSurfaceCapabilitiesKHR ), \"struct and wrapper have different size!\" );\n\n  struct SurfaceCapabilities2KHR\n  {\n    operator const VkSurfaceCapabilities2KHR&() const\n    {\n      return *reinterpret_cast<const VkSurfaceCapabilities2KHR*>(this);\n    }\n\n    bool operator==( SurfaceCapabilities2KHR const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( surfaceCapabilities == rhs.surfaceCapabilities );\n    }\n\n    bool operator!=( SurfaceCapabilities2KHR const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    void* pNext;\n    SurfaceCapabilitiesKHR surfaceCapabilities;\n  };\n  static_assert( sizeof( SurfaceCapabilities2KHR ) == sizeof( VkSurfaceCapabilities2KHR ), \"struct and wrapper have different size!\" );\n\n  enum class DebugReportFlagBitsEXT\n  {\n    eInformation = VK_DEBUG_REPORT_INFORMATION_BIT_EXT,\n    eWarning = VK_DEBUG_REPORT_WARNING_BIT_EXT,\n    ePerformanceWarning = VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,\n    eError = VK_DEBUG_REPORT_ERROR_BIT_EXT,\n    eDebug = VK_DEBUG_REPORT_DEBUG_BIT_EXT\n  };\n\n  using DebugReportFlagsEXT = Flags<DebugReportFlagBitsEXT, VkDebugReportFlagsEXT>;\n\n  VULKAN_HPP_INLINE DebugReportFlagsEXT operator|( DebugReportFlagBitsEXT bit0, DebugReportFlagBitsEXT bit1 )\n  {\n    return DebugReportFlagsEXT( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE DebugReportFlagsEXT operator~( DebugReportFlagBitsEXT bits )\n  {\n    return ~( DebugReportFlagsEXT( bits ) );\n  }\n\n  template <> struct FlagTraits<DebugReportFlagBitsEXT>\n  {\n    enum\n    {\n      allFlags = VkFlags(DebugReportFlagBitsEXT::eInformation) | VkFlags(DebugReportFlagBitsEXT::eWarning) | VkFlags(DebugReportFlagBitsEXT::ePerformanceWarning) | VkFlags(DebugReportFlagBitsEXT::eError) | VkFlags(DebugReportFlagBitsEXT::eDebug)\n    };\n  };\n\n  struct DebugReportCallbackCreateInfoEXT\n  {\n    DebugReportCallbackCreateInfoEXT( DebugReportFlagsEXT flags_ = DebugReportFlagsEXT(), PFN_vkDebugReportCallbackEXT pfnCallback_ = nullptr, void* pUserData_ = nullptr )\n      : sType( StructureType::eDebugReportCallbackCreateInfoEXT )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , pfnCallback( pfnCallback_ )\n      , pUserData( pUserData_ )\n    {\n    }\n\n    DebugReportCallbackCreateInfoEXT( VkDebugReportCallbackCreateInfoEXT const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DebugReportCallbackCreateInfoEXT) );\n    }\n\n    DebugReportCallbackCreateInfoEXT& operator=( VkDebugReportCallbackCreateInfoEXT const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DebugReportCallbackCreateInfoEXT) );\n      return *this;\n    }\n\n    DebugReportCallbackCreateInfoEXT& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    DebugReportCallbackCreateInfoEXT& setFlags( DebugReportFlagsEXT flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    DebugReportCallbackCreateInfoEXT& setPfnCallback( PFN_vkDebugReportCallbackEXT pfnCallback_ )\n    {\n      pfnCallback = pfnCallback_;\n      return *this;\n    }\n\n    DebugReportCallbackCreateInfoEXT& setPUserData( void* pUserData_ )\n    {\n      pUserData = pUserData_;\n      return *this;\n    }\n\n    operator const VkDebugReportCallbackCreateInfoEXT&() const\n    {\n      return *reinterpret_cast<const VkDebugReportCallbackCreateInfoEXT*>(this);\n    }\n\n    bool operator==( DebugReportCallbackCreateInfoEXT const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( pfnCallback == rhs.pfnCallback )\n          && ( pUserData == rhs.pUserData );\n    }\n\n    bool operator!=( DebugReportCallbackCreateInfoEXT const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    DebugReportFlagsEXT flags;\n    PFN_vkDebugReportCallbackEXT pfnCallback;\n    void* pUserData;\n  };\n  static_assert( sizeof( DebugReportCallbackCreateInfoEXT ) == sizeof( VkDebugReportCallbackCreateInfoEXT ), \"struct and wrapper have different size!\" );\n\n  enum class DebugReportObjectTypeEXT\n  {\n    eUnknown = VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,\n    eInstance = VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT,\n    ePhysicalDevice = VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,\n    eDevice = VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,\n    eQueue = VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT,\n    eSemaphore = VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,\n    eCommandBuffer = VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,\n    eFence = VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,\n    eDeviceMemory = VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,\n    eBuffer = VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,\n    eImage = VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,\n    eEvent = VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT,\n    eQueryPool = VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT,\n    eBufferView = VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT,\n    eImageView = VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT,\n    eShaderModule = VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT,\n    ePipelineCache = VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_CACHE_EXT,\n    ePipelineLayout = VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT,\n    eRenderPass = VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,\n    ePipeline = VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,\n    eDescriptorSetLayout = VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT,\n    eSampler = VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT,\n    eDescriptorPool = VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,\n    eDescriptorSet = VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,\n    eFramebuffer = VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT,\n    eCommandPool = VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT,\n    eSurfaceKhr = VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT,\n    eSwapchainKhr = VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,\n    eDebugReport = VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT,\n    eDisplayKhr = VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_KHR_EXT,\n    eDisplayModeKhr = VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_MODE_KHR_EXT,\n    eObjectTableNvx = VK_DEBUG_REPORT_OBJECT_TYPE_OBJECT_TABLE_NVX_EXT,\n    eIndirectCommandsLayoutNvx = VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT,\n    eDescriptorUpdateTemplateKHR = VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR_EXT\n  };\n\n  struct DebugMarkerObjectNameInfoEXT\n  {\n    DebugMarkerObjectNameInfoEXT( DebugReportObjectTypeEXT objectType_ = DebugReportObjectTypeEXT::eUnknown, uint64_t object_ = 0, const char* pObjectName_ = nullptr )\n      : sType( StructureType::eDebugMarkerObjectNameInfoEXT )\n      , pNext( nullptr )\n      , objectType( objectType_ )\n      , object( object_ )\n      , pObjectName( pObjectName_ )\n    {\n    }\n\n    DebugMarkerObjectNameInfoEXT( VkDebugMarkerObjectNameInfoEXT const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DebugMarkerObjectNameInfoEXT) );\n    }\n\n    DebugMarkerObjectNameInfoEXT& operator=( VkDebugMarkerObjectNameInfoEXT const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DebugMarkerObjectNameInfoEXT) );\n      return *this;\n    }\n\n    DebugMarkerObjectNameInfoEXT& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    DebugMarkerObjectNameInfoEXT& setObjectType( DebugReportObjectTypeEXT objectType_ )\n    {\n      objectType = objectType_;\n      return *this;\n    }\n\n    DebugMarkerObjectNameInfoEXT& setObject( uint64_t object_ )\n    {\n      object = object_;\n      return *this;\n    }\n\n    DebugMarkerObjectNameInfoEXT& setPObjectName( const char* pObjectName_ )\n    {\n      pObjectName = pObjectName_;\n      return *this;\n    }\n\n    operator const VkDebugMarkerObjectNameInfoEXT&() const\n    {\n      return *reinterpret_cast<const VkDebugMarkerObjectNameInfoEXT*>(this);\n    }\n\n    bool operator==( DebugMarkerObjectNameInfoEXT const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( objectType == rhs.objectType )\n          && ( object == rhs.object )\n          && ( pObjectName == rhs.pObjectName );\n    }\n\n    bool operator!=( DebugMarkerObjectNameInfoEXT const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    DebugReportObjectTypeEXT objectType;\n    uint64_t object;\n    const char* pObjectName;\n  };\n  static_assert( sizeof( DebugMarkerObjectNameInfoEXT ) == sizeof( VkDebugMarkerObjectNameInfoEXT ), \"struct and wrapper have different size!\" );\n\n  struct DebugMarkerObjectTagInfoEXT\n  {\n    DebugMarkerObjectTagInfoEXT( DebugReportObjectTypeEXT objectType_ = DebugReportObjectTypeEXT::eUnknown, uint64_t object_ = 0, uint64_t tagName_ = 0, size_t tagSize_ = 0, const void* pTag_ = nullptr )\n      : sType( StructureType::eDebugMarkerObjectTagInfoEXT )\n      , pNext( nullptr )\n      , objectType( objectType_ )\n      , object( object_ )\n      , tagName( tagName_ )\n      , tagSize( tagSize_ )\n      , pTag( pTag_ )\n    {\n    }\n\n    DebugMarkerObjectTagInfoEXT( VkDebugMarkerObjectTagInfoEXT const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DebugMarkerObjectTagInfoEXT) );\n    }\n\n    DebugMarkerObjectTagInfoEXT& operator=( VkDebugMarkerObjectTagInfoEXT const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DebugMarkerObjectTagInfoEXT) );\n      return *this;\n    }\n\n    DebugMarkerObjectTagInfoEXT& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    DebugMarkerObjectTagInfoEXT& setObjectType( DebugReportObjectTypeEXT objectType_ )\n    {\n      objectType = objectType_;\n      return *this;\n    }\n\n    DebugMarkerObjectTagInfoEXT& setObject( uint64_t object_ )\n    {\n      object = object_;\n      return *this;\n    }\n\n    DebugMarkerObjectTagInfoEXT& setTagName( uint64_t tagName_ )\n    {\n      tagName = tagName_;\n      return *this;\n    }\n\n    DebugMarkerObjectTagInfoEXT& setTagSize( size_t tagSize_ )\n    {\n      tagSize = tagSize_;\n      return *this;\n    }\n\n    DebugMarkerObjectTagInfoEXT& setPTag( const void* pTag_ )\n    {\n      pTag = pTag_;\n      return *this;\n    }\n\n    operator const VkDebugMarkerObjectTagInfoEXT&() const\n    {\n      return *reinterpret_cast<const VkDebugMarkerObjectTagInfoEXT*>(this);\n    }\n\n    bool operator==( DebugMarkerObjectTagInfoEXT const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( objectType == rhs.objectType )\n          && ( object == rhs.object )\n          && ( tagName == rhs.tagName )\n          && ( tagSize == rhs.tagSize )\n          && ( pTag == rhs.pTag );\n    }\n\n    bool operator!=( DebugMarkerObjectTagInfoEXT const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    DebugReportObjectTypeEXT objectType;\n    uint64_t object;\n    uint64_t tagName;\n    size_t tagSize;\n    const void* pTag;\n  };\n  static_assert( sizeof( DebugMarkerObjectTagInfoEXT ) == sizeof( VkDebugMarkerObjectTagInfoEXT ), \"struct and wrapper have different size!\" );\n\n  enum class DebugReportErrorEXT\n  {\n    eNone = VK_DEBUG_REPORT_ERROR_NONE_EXT,\n    eCallbackRef = VK_DEBUG_REPORT_ERROR_CALLBACK_REF_EXT\n  };\n\n  enum class RasterizationOrderAMD\n  {\n    eStrict = VK_RASTERIZATION_ORDER_STRICT_AMD,\n    eRelaxed = VK_RASTERIZATION_ORDER_RELAXED_AMD\n  };\n\n  struct PipelineRasterizationStateRasterizationOrderAMD\n  {\n    PipelineRasterizationStateRasterizationOrderAMD( RasterizationOrderAMD rasterizationOrder_ = RasterizationOrderAMD::eStrict )\n      : sType( StructureType::ePipelineRasterizationStateRasterizationOrderAMD )\n      , pNext( nullptr )\n      , rasterizationOrder( rasterizationOrder_ )\n    {\n    }\n\n    PipelineRasterizationStateRasterizationOrderAMD( VkPipelineRasterizationStateRasterizationOrderAMD const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PipelineRasterizationStateRasterizationOrderAMD) );\n    }\n\n    PipelineRasterizationStateRasterizationOrderAMD& operator=( VkPipelineRasterizationStateRasterizationOrderAMD const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PipelineRasterizationStateRasterizationOrderAMD) );\n      return *this;\n    }\n\n    PipelineRasterizationStateRasterizationOrderAMD& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    PipelineRasterizationStateRasterizationOrderAMD& setRasterizationOrder( RasterizationOrderAMD rasterizationOrder_ )\n    {\n      rasterizationOrder = rasterizationOrder_;\n      return *this;\n    }\n\n    operator const VkPipelineRasterizationStateRasterizationOrderAMD&() const\n    {\n      return *reinterpret_cast<const VkPipelineRasterizationStateRasterizationOrderAMD*>(this);\n    }\n\n    bool operator==( PipelineRasterizationStateRasterizationOrderAMD const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( rasterizationOrder == rhs.rasterizationOrder );\n    }\n\n    bool operator!=( PipelineRasterizationStateRasterizationOrderAMD const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    RasterizationOrderAMD rasterizationOrder;\n  };\n  static_assert( sizeof( PipelineRasterizationStateRasterizationOrderAMD ) == sizeof( VkPipelineRasterizationStateRasterizationOrderAMD ), \"struct and wrapper have different size!\" );\n\n  enum class ExternalMemoryHandleTypeFlagBitsNV\n  {\n    eOpaqueWin32 = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_NV,\n    eOpaqueWin32Kmt = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_NV,\n    eD3D11Image = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_BIT_NV,\n    eD3D11ImageKmt = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_KMT_BIT_NV\n  };\n\n  using ExternalMemoryHandleTypeFlagsNV = Flags<ExternalMemoryHandleTypeFlagBitsNV, VkExternalMemoryHandleTypeFlagsNV>;\n\n  VULKAN_HPP_INLINE ExternalMemoryHandleTypeFlagsNV operator|( ExternalMemoryHandleTypeFlagBitsNV bit0, ExternalMemoryHandleTypeFlagBitsNV bit1 )\n  {\n    return ExternalMemoryHandleTypeFlagsNV( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE ExternalMemoryHandleTypeFlagsNV operator~( ExternalMemoryHandleTypeFlagBitsNV bits )\n  {\n    return ~( ExternalMemoryHandleTypeFlagsNV( bits ) );\n  }\n\n  template <> struct FlagTraits<ExternalMemoryHandleTypeFlagBitsNV>\n  {\n    enum\n    {\n      allFlags = VkFlags(ExternalMemoryHandleTypeFlagBitsNV::eOpaqueWin32) | VkFlags(ExternalMemoryHandleTypeFlagBitsNV::eOpaqueWin32Kmt) | VkFlags(ExternalMemoryHandleTypeFlagBitsNV::eD3D11Image) | VkFlags(ExternalMemoryHandleTypeFlagBitsNV::eD3D11ImageKmt)\n    };\n  };\n\n  struct ExternalMemoryImageCreateInfoNV\n  {\n    ExternalMemoryImageCreateInfoNV( ExternalMemoryHandleTypeFlagsNV handleTypes_ = ExternalMemoryHandleTypeFlagsNV() )\n      : sType( StructureType::eExternalMemoryImageCreateInfoNV )\n      , pNext( nullptr )\n      , handleTypes( handleTypes_ )\n    {\n    }\n\n    ExternalMemoryImageCreateInfoNV( VkExternalMemoryImageCreateInfoNV const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ExternalMemoryImageCreateInfoNV) );\n    }\n\n    ExternalMemoryImageCreateInfoNV& operator=( VkExternalMemoryImageCreateInfoNV const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ExternalMemoryImageCreateInfoNV) );\n      return *this;\n    }\n\n    ExternalMemoryImageCreateInfoNV& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    ExternalMemoryImageCreateInfoNV& setHandleTypes( ExternalMemoryHandleTypeFlagsNV handleTypes_ )\n    {\n      handleTypes = handleTypes_;\n      return *this;\n    }\n\n    operator const VkExternalMemoryImageCreateInfoNV&() const\n    {\n      return *reinterpret_cast<const VkExternalMemoryImageCreateInfoNV*>(this);\n    }\n\n    bool operator==( ExternalMemoryImageCreateInfoNV const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( handleTypes == rhs.handleTypes );\n    }\n\n    bool operator!=( ExternalMemoryImageCreateInfoNV const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    ExternalMemoryHandleTypeFlagsNV handleTypes;\n  };\n  static_assert( sizeof( ExternalMemoryImageCreateInfoNV ) == sizeof( VkExternalMemoryImageCreateInfoNV ), \"struct and wrapper have different size!\" );\n\n  struct ExportMemoryAllocateInfoNV\n  {\n    ExportMemoryAllocateInfoNV( ExternalMemoryHandleTypeFlagsNV handleTypes_ = ExternalMemoryHandleTypeFlagsNV() )\n      : sType( StructureType::eExportMemoryAllocateInfoNV )\n      , pNext( nullptr )\n      , handleTypes( handleTypes_ )\n    {\n    }\n\n    ExportMemoryAllocateInfoNV( VkExportMemoryAllocateInfoNV const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ExportMemoryAllocateInfoNV) );\n    }\n\n    ExportMemoryAllocateInfoNV& operator=( VkExportMemoryAllocateInfoNV const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ExportMemoryAllocateInfoNV) );\n      return *this;\n    }\n\n    ExportMemoryAllocateInfoNV& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    ExportMemoryAllocateInfoNV& setHandleTypes( ExternalMemoryHandleTypeFlagsNV handleTypes_ )\n    {\n      handleTypes = handleTypes_;\n      return *this;\n    }\n\n    operator const VkExportMemoryAllocateInfoNV&() const\n    {\n      return *reinterpret_cast<const VkExportMemoryAllocateInfoNV*>(this);\n    }\n\n    bool operator==( ExportMemoryAllocateInfoNV const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( handleTypes == rhs.handleTypes );\n    }\n\n    bool operator!=( ExportMemoryAllocateInfoNV const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    ExternalMemoryHandleTypeFlagsNV handleTypes;\n  };\n  static_assert( sizeof( ExportMemoryAllocateInfoNV ) == sizeof( VkExportMemoryAllocateInfoNV ), \"struct and wrapper have different size!\" );\n\n#ifdef VK_USE_PLATFORM_WIN32_KHR\n  struct ImportMemoryWin32HandleInfoNV\n  {\n    ImportMemoryWin32HandleInfoNV( ExternalMemoryHandleTypeFlagsNV handleType_ = ExternalMemoryHandleTypeFlagsNV(), HANDLE handle_ = 0 )\n      : sType( StructureType::eImportMemoryWin32HandleInfoNV )\n      , pNext( nullptr )\n      , handleType( handleType_ )\n      , handle( handle_ )\n    {\n    }\n\n    ImportMemoryWin32HandleInfoNV( VkImportMemoryWin32HandleInfoNV const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ImportMemoryWin32HandleInfoNV) );\n    }\n\n    ImportMemoryWin32HandleInfoNV& operator=( VkImportMemoryWin32HandleInfoNV const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ImportMemoryWin32HandleInfoNV) );\n      return *this;\n    }\n\n    ImportMemoryWin32HandleInfoNV& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    ImportMemoryWin32HandleInfoNV& setHandleType( ExternalMemoryHandleTypeFlagsNV handleType_ )\n    {\n      handleType = handleType_;\n      return *this;\n    }\n\n    ImportMemoryWin32HandleInfoNV& setHandle( HANDLE handle_ )\n    {\n      handle = handle_;\n      return *this;\n    }\n\n    operator const VkImportMemoryWin32HandleInfoNV&() const\n    {\n      return *reinterpret_cast<const VkImportMemoryWin32HandleInfoNV*>(this);\n    }\n\n    bool operator==( ImportMemoryWin32HandleInfoNV const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( handleType == rhs.handleType )\n          && ( handle == rhs.handle );\n    }\n\n    bool operator!=( ImportMemoryWin32HandleInfoNV const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    ExternalMemoryHandleTypeFlagsNV handleType;\n    HANDLE handle;\n  };\n  static_assert( sizeof( ImportMemoryWin32HandleInfoNV ) == sizeof( VkImportMemoryWin32HandleInfoNV ), \"struct and wrapper have different size!\" );\n#endif /*VK_USE_PLATFORM_WIN32_KHR*/\n\n  enum class ExternalMemoryFeatureFlagBitsNV\n  {\n    eDedicatedOnly = VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_NV,\n    eExportable = VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_NV,\n    eImportable = VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_NV\n  };\n\n  using ExternalMemoryFeatureFlagsNV = Flags<ExternalMemoryFeatureFlagBitsNV, VkExternalMemoryFeatureFlagsNV>;\n\n  VULKAN_HPP_INLINE ExternalMemoryFeatureFlagsNV operator|( ExternalMemoryFeatureFlagBitsNV bit0, ExternalMemoryFeatureFlagBitsNV bit1 )\n  {\n    return ExternalMemoryFeatureFlagsNV( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE ExternalMemoryFeatureFlagsNV operator~( ExternalMemoryFeatureFlagBitsNV bits )\n  {\n    return ~( ExternalMemoryFeatureFlagsNV( bits ) );\n  }\n\n  template <> struct FlagTraits<ExternalMemoryFeatureFlagBitsNV>\n  {\n    enum\n    {\n      allFlags = VkFlags(ExternalMemoryFeatureFlagBitsNV::eDedicatedOnly) | VkFlags(ExternalMemoryFeatureFlagBitsNV::eExportable) | VkFlags(ExternalMemoryFeatureFlagBitsNV::eImportable)\n    };\n  };\n\n  struct ExternalImageFormatPropertiesNV\n  {\n    operator const VkExternalImageFormatPropertiesNV&() const\n    {\n      return *reinterpret_cast<const VkExternalImageFormatPropertiesNV*>(this);\n    }\n\n    bool operator==( ExternalImageFormatPropertiesNV const& rhs ) const\n    {\n      return ( imageFormatProperties == rhs.imageFormatProperties )\n          && ( externalMemoryFeatures == rhs.externalMemoryFeatures )\n          && ( exportFromImportedHandleTypes == rhs.exportFromImportedHandleTypes )\n          && ( compatibleHandleTypes == rhs.compatibleHandleTypes );\n    }\n\n    bool operator!=( ExternalImageFormatPropertiesNV const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    ImageFormatProperties imageFormatProperties;\n    ExternalMemoryFeatureFlagsNV externalMemoryFeatures;\n    ExternalMemoryHandleTypeFlagsNV exportFromImportedHandleTypes;\n    ExternalMemoryHandleTypeFlagsNV compatibleHandleTypes;\n  };\n  static_assert( sizeof( ExternalImageFormatPropertiesNV ) == sizeof( VkExternalImageFormatPropertiesNV ), \"struct and wrapper have different size!\" );\n\n  enum class ValidationCheckEXT\n  {\n    eAll = VK_VALIDATION_CHECK_ALL_EXT\n  };\n\n  struct ValidationFlagsEXT\n  {\n    ValidationFlagsEXT( uint32_t disabledValidationCheckCount_ = 0, ValidationCheckEXT* pDisabledValidationChecks_ = nullptr )\n      : sType( StructureType::eValidationFlagsEXT )\n      , pNext( nullptr )\n      , disabledValidationCheckCount( disabledValidationCheckCount_ )\n      , pDisabledValidationChecks( pDisabledValidationChecks_ )\n    {\n    }\n\n    ValidationFlagsEXT( VkValidationFlagsEXT const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ValidationFlagsEXT) );\n    }\n\n    ValidationFlagsEXT& operator=( VkValidationFlagsEXT const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ValidationFlagsEXT) );\n      return *this;\n    }\n\n    ValidationFlagsEXT& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    ValidationFlagsEXT& setDisabledValidationCheckCount( uint32_t disabledValidationCheckCount_ )\n    {\n      disabledValidationCheckCount = disabledValidationCheckCount_;\n      return *this;\n    }\n\n    ValidationFlagsEXT& setPDisabledValidationChecks( ValidationCheckEXT* pDisabledValidationChecks_ )\n    {\n      pDisabledValidationChecks = pDisabledValidationChecks_;\n      return *this;\n    }\n\n    operator const VkValidationFlagsEXT&() const\n    {\n      return *reinterpret_cast<const VkValidationFlagsEXT*>(this);\n    }\n\n    bool operator==( ValidationFlagsEXT const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( disabledValidationCheckCount == rhs.disabledValidationCheckCount )\n          && ( pDisabledValidationChecks == rhs.pDisabledValidationChecks );\n    }\n\n    bool operator!=( ValidationFlagsEXT const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    uint32_t disabledValidationCheckCount;\n    ValidationCheckEXT* pDisabledValidationChecks;\n  };\n  static_assert( sizeof( ValidationFlagsEXT ) == sizeof( VkValidationFlagsEXT ), \"struct and wrapper have different size!\" );\n\n  enum class IndirectCommandsLayoutUsageFlagBitsNVX\n  {\n    eUnorderedSequences = VK_INDIRECT_COMMANDS_LAYOUT_USAGE_UNORDERED_SEQUENCES_BIT_NVX,\n    eSparseSequences = VK_INDIRECT_COMMANDS_LAYOUT_USAGE_SPARSE_SEQUENCES_BIT_NVX,\n    eEmptyExecutions = VK_INDIRECT_COMMANDS_LAYOUT_USAGE_EMPTY_EXECUTIONS_BIT_NVX,\n    eIndexedSequences = VK_INDIRECT_COMMANDS_LAYOUT_USAGE_INDEXED_SEQUENCES_BIT_NVX\n  };\n\n  using IndirectCommandsLayoutUsageFlagsNVX = Flags<IndirectCommandsLayoutUsageFlagBitsNVX, VkIndirectCommandsLayoutUsageFlagsNVX>;\n\n  VULKAN_HPP_INLINE IndirectCommandsLayoutUsageFlagsNVX operator|( IndirectCommandsLayoutUsageFlagBitsNVX bit0, IndirectCommandsLayoutUsageFlagBitsNVX bit1 )\n  {\n    return IndirectCommandsLayoutUsageFlagsNVX( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE IndirectCommandsLayoutUsageFlagsNVX operator~( IndirectCommandsLayoutUsageFlagBitsNVX bits )\n  {\n    return ~( IndirectCommandsLayoutUsageFlagsNVX( bits ) );\n  }\n\n  template <> struct FlagTraits<IndirectCommandsLayoutUsageFlagBitsNVX>\n  {\n    enum\n    {\n      allFlags = VkFlags(IndirectCommandsLayoutUsageFlagBitsNVX::eUnorderedSequences) | VkFlags(IndirectCommandsLayoutUsageFlagBitsNVX::eSparseSequences) | VkFlags(IndirectCommandsLayoutUsageFlagBitsNVX::eEmptyExecutions) | VkFlags(IndirectCommandsLayoutUsageFlagBitsNVX::eIndexedSequences)\n    };\n  };\n\n  enum class ObjectEntryUsageFlagBitsNVX\n  {\n    eGraphics = VK_OBJECT_ENTRY_USAGE_GRAPHICS_BIT_NVX,\n    eCompute = VK_OBJECT_ENTRY_USAGE_COMPUTE_BIT_NVX\n  };\n\n  using ObjectEntryUsageFlagsNVX = Flags<ObjectEntryUsageFlagBitsNVX, VkObjectEntryUsageFlagsNVX>;\n\n  VULKAN_HPP_INLINE ObjectEntryUsageFlagsNVX operator|( ObjectEntryUsageFlagBitsNVX bit0, ObjectEntryUsageFlagBitsNVX bit1 )\n  {\n    return ObjectEntryUsageFlagsNVX( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE ObjectEntryUsageFlagsNVX operator~( ObjectEntryUsageFlagBitsNVX bits )\n  {\n    return ~( ObjectEntryUsageFlagsNVX( bits ) );\n  }\n\n  template <> struct FlagTraits<ObjectEntryUsageFlagBitsNVX>\n  {\n    enum\n    {\n      allFlags = VkFlags(ObjectEntryUsageFlagBitsNVX::eGraphics) | VkFlags(ObjectEntryUsageFlagBitsNVX::eCompute)\n    };\n  };\n\n  enum class IndirectCommandsTokenTypeNVX\n  {\n    eVkIndirectCommandsTokenPipeline = VK_INDIRECT_COMMANDS_TOKEN_PIPELINE_NVX,\n    eVkIndirectCommandsTokenDescriptorSet = VK_INDIRECT_COMMANDS_TOKEN_DESCRIPTOR_SET_NVX,\n    eVkIndirectCommandsTokenIndexBuffer = VK_INDIRECT_COMMANDS_TOKEN_INDEX_BUFFER_NVX,\n    eVkIndirectCommandsTokenVertexBuffer = VK_INDIRECT_COMMANDS_TOKEN_VERTEX_BUFFER_NVX,\n    eVkIndirectCommandsTokenPushConstant = VK_INDIRECT_COMMANDS_TOKEN_PUSH_CONSTANT_NVX,\n    eVkIndirectCommandsTokenDrawIndexed = VK_INDIRECT_COMMANDS_TOKEN_DRAW_INDEXED_NVX,\n    eVkIndirectCommandsTokenDraw = VK_INDIRECT_COMMANDS_TOKEN_DRAW_NVX,\n    eVkIndirectCommandsTokenDispatch = VK_INDIRECT_COMMANDS_TOKEN_DISPATCH_NVX\n  };\n\n  struct IndirectCommandsTokenNVX\n  {\n    IndirectCommandsTokenNVX( IndirectCommandsTokenTypeNVX tokenType_ = IndirectCommandsTokenTypeNVX::eVkIndirectCommandsTokenPipeline, Buffer buffer_ = Buffer(), DeviceSize offset_ = 0 )\n      : tokenType( tokenType_ )\n      , buffer( buffer_ )\n      , offset( offset_ )\n    {\n    }\n\n    IndirectCommandsTokenNVX( VkIndirectCommandsTokenNVX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(IndirectCommandsTokenNVX) );\n    }\n\n    IndirectCommandsTokenNVX& operator=( VkIndirectCommandsTokenNVX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(IndirectCommandsTokenNVX) );\n      return *this;\n    }\n\n    IndirectCommandsTokenNVX& setTokenType( IndirectCommandsTokenTypeNVX tokenType_ )\n    {\n      tokenType = tokenType_;\n      return *this;\n    }\n\n    IndirectCommandsTokenNVX& setBuffer( Buffer buffer_ )\n    {\n      buffer = buffer_;\n      return *this;\n    }\n\n    IndirectCommandsTokenNVX& setOffset( DeviceSize offset_ )\n    {\n      offset = offset_;\n      return *this;\n    }\n\n    operator const VkIndirectCommandsTokenNVX&() const\n    {\n      return *reinterpret_cast<const VkIndirectCommandsTokenNVX*>(this);\n    }\n\n    bool operator==( IndirectCommandsTokenNVX const& rhs ) const\n    {\n      return ( tokenType == rhs.tokenType )\n          && ( buffer == rhs.buffer )\n          && ( offset == rhs.offset );\n    }\n\n    bool operator!=( IndirectCommandsTokenNVX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    IndirectCommandsTokenTypeNVX tokenType;\n    Buffer buffer;\n    DeviceSize offset;\n  };\n  static_assert( sizeof( IndirectCommandsTokenNVX ) == sizeof( VkIndirectCommandsTokenNVX ), \"struct and wrapper have different size!\" );\n\n  struct IndirectCommandsLayoutTokenNVX\n  {\n    IndirectCommandsLayoutTokenNVX( IndirectCommandsTokenTypeNVX tokenType_ = IndirectCommandsTokenTypeNVX::eVkIndirectCommandsTokenPipeline, uint32_t bindingUnit_ = 0, uint32_t dynamicCount_ = 0, uint32_t divisor_ = 0 )\n      : tokenType( tokenType_ )\n      , bindingUnit( bindingUnit_ )\n      , dynamicCount( dynamicCount_ )\n      , divisor( divisor_ )\n    {\n    }\n\n    IndirectCommandsLayoutTokenNVX( VkIndirectCommandsLayoutTokenNVX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(IndirectCommandsLayoutTokenNVX) );\n    }\n\n    IndirectCommandsLayoutTokenNVX& operator=( VkIndirectCommandsLayoutTokenNVX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(IndirectCommandsLayoutTokenNVX) );\n      return *this;\n    }\n\n    IndirectCommandsLayoutTokenNVX& setTokenType( IndirectCommandsTokenTypeNVX tokenType_ )\n    {\n      tokenType = tokenType_;\n      return *this;\n    }\n\n    IndirectCommandsLayoutTokenNVX& setBindingUnit( uint32_t bindingUnit_ )\n    {\n      bindingUnit = bindingUnit_;\n      return *this;\n    }\n\n    IndirectCommandsLayoutTokenNVX& setDynamicCount( uint32_t dynamicCount_ )\n    {\n      dynamicCount = dynamicCount_;\n      return *this;\n    }\n\n    IndirectCommandsLayoutTokenNVX& setDivisor( uint32_t divisor_ )\n    {\n      divisor = divisor_;\n      return *this;\n    }\n\n    operator const VkIndirectCommandsLayoutTokenNVX&() const\n    {\n      return *reinterpret_cast<const VkIndirectCommandsLayoutTokenNVX*>(this);\n    }\n\n    bool operator==( IndirectCommandsLayoutTokenNVX const& rhs ) const\n    {\n      return ( tokenType == rhs.tokenType )\n          && ( bindingUnit == rhs.bindingUnit )\n          && ( dynamicCount == rhs.dynamicCount )\n          && ( divisor == rhs.divisor );\n    }\n\n    bool operator!=( IndirectCommandsLayoutTokenNVX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    IndirectCommandsTokenTypeNVX tokenType;\n    uint32_t bindingUnit;\n    uint32_t dynamicCount;\n    uint32_t divisor;\n  };\n  static_assert( sizeof( IndirectCommandsLayoutTokenNVX ) == sizeof( VkIndirectCommandsLayoutTokenNVX ), \"struct and wrapper have different size!\" );\n\n  struct IndirectCommandsLayoutCreateInfoNVX\n  {\n    IndirectCommandsLayoutCreateInfoNVX( PipelineBindPoint pipelineBindPoint_ = PipelineBindPoint::eGraphics, IndirectCommandsLayoutUsageFlagsNVX flags_ = IndirectCommandsLayoutUsageFlagsNVX(), uint32_t tokenCount_ = 0, const IndirectCommandsLayoutTokenNVX* pTokens_ = nullptr )\n      : sType( StructureType::eIndirectCommandsLayoutCreateInfoNVX )\n      , pNext( nullptr )\n      , pipelineBindPoint( pipelineBindPoint_ )\n      , flags( flags_ )\n      , tokenCount( tokenCount_ )\n      , pTokens( pTokens_ )\n    {\n    }\n\n    IndirectCommandsLayoutCreateInfoNVX( VkIndirectCommandsLayoutCreateInfoNVX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(IndirectCommandsLayoutCreateInfoNVX) );\n    }\n\n    IndirectCommandsLayoutCreateInfoNVX& operator=( VkIndirectCommandsLayoutCreateInfoNVX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(IndirectCommandsLayoutCreateInfoNVX) );\n      return *this;\n    }\n\n    IndirectCommandsLayoutCreateInfoNVX& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    IndirectCommandsLayoutCreateInfoNVX& setPipelineBindPoint( PipelineBindPoint pipelineBindPoint_ )\n    {\n      pipelineBindPoint = pipelineBindPoint_;\n      return *this;\n    }\n\n    IndirectCommandsLayoutCreateInfoNVX& setFlags( IndirectCommandsLayoutUsageFlagsNVX flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    IndirectCommandsLayoutCreateInfoNVX& setTokenCount( uint32_t tokenCount_ )\n    {\n      tokenCount = tokenCount_;\n      return *this;\n    }\n\n    IndirectCommandsLayoutCreateInfoNVX& setPTokens( const IndirectCommandsLayoutTokenNVX* pTokens_ )\n    {\n      pTokens = pTokens_;\n      return *this;\n    }\n\n    operator const VkIndirectCommandsLayoutCreateInfoNVX&() const\n    {\n      return *reinterpret_cast<const VkIndirectCommandsLayoutCreateInfoNVX*>(this);\n    }\n\n    bool operator==( IndirectCommandsLayoutCreateInfoNVX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( pipelineBindPoint == rhs.pipelineBindPoint )\n          && ( flags == rhs.flags )\n          && ( tokenCount == rhs.tokenCount )\n          && ( pTokens == rhs.pTokens );\n    }\n\n    bool operator!=( IndirectCommandsLayoutCreateInfoNVX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    PipelineBindPoint pipelineBindPoint;\n    IndirectCommandsLayoutUsageFlagsNVX flags;\n    uint32_t tokenCount;\n    const IndirectCommandsLayoutTokenNVX* pTokens;\n  };\n  static_assert( sizeof( IndirectCommandsLayoutCreateInfoNVX ) == sizeof( VkIndirectCommandsLayoutCreateInfoNVX ), \"struct and wrapper have different size!\" );\n\n  enum class ObjectEntryTypeNVX\n  {\n    eVkObjectEntryDescriptorSet = VK_OBJECT_ENTRY_DESCRIPTOR_SET_NVX,\n    eVkObjectEntryPipeline = VK_OBJECT_ENTRY_PIPELINE_NVX,\n    eVkObjectEntryIndexBuffer = VK_OBJECT_ENTRY_INDEX_BUFFER_NVX,\n    eVkObjectEntryVertexBuffer = VK_OBJECT_ENTRY_VERTEX_BUFFER_NVX,\n    eVkObjectEntryPushConstant = VK_OBJECT_ENTRY_PUSH_CONSTANT_NVX\n  };\n\n  struct ObjectTableCreateInfoNVX\n  {\n    ObjectTableCreateInfoNVX( uint32_t objectCount_ = 0, const ObjectEntryTypeNVX* pObjectEntryTypes_ = nullptr, const uint32_t* pObjectEntryCounts_ = nullptr, const ObjectEntryUsageFlagsNVX* pObjectEntryUsageFlags_ = nullptr, uint32_t maxUniformBuffersPerDescriptor_ = 0, uint32_t maxStorageBuffersPerDescriptor_ = 0, uint32_t maxStorageImagesPerDescriptor_ = 0, uint32_t maxSampledImagesPerDescriptor_ = 0, uint32_t maxPipelineLayouts_ = 0 )\n      : sType( StructureType::eObjectTableCreateInfoNVX )\n      , pNext( nullptr )\n      , objectCount( objectCount_ )\n      , pObjectEntryTypes( pObjectEntryTypes_ )\n      , pObjectEntryCounts( pObjectEntryCounts_ )\n      , pObjectEntryUsageFlags( pObjectEntryUsageFlags_ )\n      , maxUniformBuffersPerDescriptor( maxUniformBuffersPerDescriptor_ )\n      , maxStorageBuffersPerDescriptor( maxStorageBuffersPerDescriptor_ )\n      , maxStorageImagesPerDescriptor( maxStorageImagesPerDescriptor_ )\n      , maxSampledImagesPerDescriptor( maxSampledImagesPerDescriptor_ )\n      , maxPipelineLayouts( maxPipelineLayouts_ )\n    {\n    }\n\n    ObjectTableCreateInfoNVX( VkObjectTableCreateInfoNVX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ObjectTableCreateInfoNVX) );\n    }\n\n    ObjectTableCreateInfoNVX& operator=( VkObjectTableCreateInfoNVX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ObjectTableCreateInfoNVX) );\n      return *this;\n    }\n\n    ObjectTableCreateInfoNVX& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    ObjectTableCreateInfoNVX& setObjectCount( uint32_t objectCount_ )\n    {\n      objectCount = objectCount_;\n      return *this;\n    }\n\n    ObjectTableCreateInfoNVX& setPObjectEntryTypes( const ObjectEntryTypeNVX* pObjectEntryTypes_ )\n    {\n      pObjectEntryTypes = pObjectEntryTypes_;\n      return *this;\n    }\n\n    ObjectTableCreateInfoNVX& setPObjectEntryCounts( const uint32_t* pObjectEntryCounts_ )\n    {\n      pObjectEntryCounts = pObjectEntryCounts_;\n      return *this;\n    }\n\n    ObjectTableCreateInfoNVX& setPObjectEntryUsageFlags( const ObjectEntryUsageFlagsNVX* pObjectEntryUsageFlags_ )\n    {\n      pObjectEntryUsageFlags = pObjectEntryUsageFlags_;\n      return *this;\n    }\n\n    ObjectTableCreateInfoNVX& setMaxUniformBuffersPerDescriptor( uint32_t maxUniformBuffersPerDescriptor_ )\n    {\n      maxUniformBuffersPerDescriptor = maxUniformBuffersPerDescriptor_;\n      return *this;\n    }\n\n    ObjectTableCreateInfoNVX& setMaxStorageBuffersPerDescriptor( uint32_t maxStorageBuffersPerDescriptor_ )\n    {\n      maxStorageBuffersPerDescriptor = maxStorageBuffersPerDescriptor_;\n      return *this;\n    }\n\n    ObjectTableCreateInfoNVX& setMaxStorageImagesPerDescriptor( uint32_t maxStorageImagesPerDescriptor_ )\n    {\n      maxStorageImagesPerDescriptor = maxStorageImagesPerDescriptor_;\n      return *this;\n    }\n\n    ObjectTableCreateInfoNVX& setMaxSampledImagesPerDescriptor( uint32_t maxSampledImagesPerDescriptor_ )\n    {\n      maxSampledImagesPerDescriptor = maxSampledImagesPerDescriptor_;\n      return *this;\n    }\n\n    ObjectTableCreateInfoNVX& setMaxPipelineLayouts( uint32_t maxPipelineLayouts_ )\n    {\n      maxPipelineLayouts = maxPipelineLayouts_;\n      return *this;\n    }\n\n    operator const VkObjectTableCreateInfoNVX&() const\n    {\n      return *reinterpret_cast<const VkObjectTableCreateInfoNVX*>(this);\n    }\n\n    bool operator==( ObjectTableCreateInfoNVX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( objectCount == rhs.objectCount )\n          && ( pObjectEntryTypes == rhs.pObjectEntryTypes )\n          && ( pObjectEntryCounts == rhs.pObjectEntryCounts )\n          && ( pObjectEntryUsageFlags == rhs.pObjectEntryUsageFlags )\n          && ( maxUniformBuffersPerDescriptor == rhs.maxUniformBuffersPerDescriptor )\n          && ( maxStorageBuffersPerDescriptor == rhs.maxStorageBuffersPerDescriptor )\n          && ( maxStorageImagesPerDescriptor == rhs.maxStorageImagesPerDescriptor )\n          && ( maxSampledImagesPerDescriptor == rhs.maxSampledImagesPerDescriptor )\n          && ( maxPipelineLayouts == rhs.maxPipelineLayouts );\n    }\n\n    bool operator!=( ObjectTableCreateInfoNVX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    uint32_t objectCount;\n    const ObjectEntryTypeNVX* pObjectEntryTypes;\n    const uint32_t* pObjectEntryCounts;\n    const ObjectEntryUsageFlagsNVX* pObjectEntryUsageFlags;\n    uint32_t maxUniformBuffersPerDescriptor;\n    uint32_t maxStorageBuffersPerDescriptor;\n    uint32_t maxStorageImagesPerDescriptor;\n    uint32_t maxSampledImagesPerDescriptor;\n    uint32_t maxPipelineLayouts;\n  };\n  static_assert( sizeof( ObjectTableCreateInfoNVX ) == sizeof( VkObjectTableCreateInfoNVX ), \"struct and wrapper have different size!\" );\n\n  struct ObjectTableEntryNVX\n  {\n    ObjectTableEntryNVX( ObjectEntryTypeNVX type_ = ObjectEntryTypeNVX::eVkObjectEntryDescriptorSet, ObjectEntryUsageFlagsNVX flags_ = ObjectEntryUsageFlagsNVX() )\n      : type( type_ )\n      , flags( flags_ )\n    {\n    }\n\n    ObjectTableEntryNVX( VkObjectTableEntryNVX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ObjectTableEntryNVX) );\n    }\n\n    ObjectTableEntryNVX& operator=( VkObjectTableEntryNVX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ObjectTableEntryNVX) );\n      return *this;\n    }\n\n    ObjectTableEntryNVX& setType( ObjectEntryTypeNVX type_ )\n    {\n      type = type_;\n      return *this;\n    }\n\n    ObjectTableEntryNVX& setFlags( ObjectEntryUsageFlagsNVX flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    operator const VkObjectTableEntryNVX&() const\n    {\n      return *reinterpret_cast<const VkObjectTableEntryNVX*>(this);\n    }\n\n    bool operator==( ObjectTableEntryNVX const& rhs ) const\n    {\n      return ( type == rhs.type )\n          && ( flags == rhs.flags );\n    }\n\n    bool operator!=( ObjectTableEntryNVX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    ObjectEntryTypeNVX type;\n    ObjectEntryUsageFlagsNVX flags;\n  };\n  static_assert( sizeof( ObjectTableEntryNVX ) == sizeof( VkObjectTableEntryNVX ), \"struct and wrapper have different size!\" );\n\n  struct ObjectTablePipelineEntryNVX\n  {\n    ObjectTablePipelineEntryNVX( ObjectEntryTypeNVX type_ = ObjectEntryTypeNVX::eVkObjectEntryDescriptorSet, ObjectEntryUsageFlagsNVX flags_ = ObjectEntryUsageFlagsNVX(), Pipeline pipeline_ = Pipeline() )\n      : type( type_ )\n      , flags( flags_ )\n      , pipeline( pipeline_ )\n    {\n    }\n\n    ObjectTablePipelineEntryNVX( VkObjectTablePipelineEntryNVX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ObjectTablePipelineEntryNVX) );\n    }\n\n    ObjectTablePipelineEntryNVX& operator=( VkObjectTablePipelineEntryNVX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ObjectTablePipelineEntryNVX) );\n      return *this;\n    }\n\n    ObjectTablePipelineEntryNVX& setType( ObjectEntryTypeNVX type_ )\n    {\n      type = type_;\n      return *this;\n    }\n\n    ObjectTablePipelineEntryNVX& setFlags( ObjectEntryUsageFlagsNVX flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    ObjectTablePipelineEntryNVX& setPipeline( Pipeline pipeline_ )\n    {\n      pipeline = pipeline_;\n      return *this;\n    }\n\n    operator const VkObjectTablePipelineEntryNVX&() const\n    {\n      return *reinterpret_cast<const VkObjectTablePipelineEntryNVX*>(this);\n    }\n\n    bool operator==( ObjectTablePipelineEntryNVX const& rhs ) const\n    {\n      return ( type == rhs.type )\n          && ( flags == rhs.flags )\n          && ( pipeline == rhs.pipeline );\n    }\n\n    bool operator!=( ObjectTablePipelineEntryNVX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    ObjectEntryTypeNVX type;\n    ObjectEntryUsageFlagsNVX flags;\n    Pipeline pipeline;\n  };\n  static_assert( sizeof( ObjectTablePipelineEntryNVX ) == sizeof( VkObjectTablePipelineEntryNVX ), \"struct and wrapper have different size!\" );\n\n  struct ObjectTableDescriptorSetEntryNVX\n  {\n    ObjectTableDescriptorSetEntryNVX( ObjectEntryTypeNVX type_ = ObjectEntryTypeNVX::eVkObjectEntryDescriptorSet, ObjectEntryUsageFlagsNVX flags_ = ObjectEntryUsageFlagsNVX(), PipelineLayout pipelineLayout_ = PipelineLayout(), DescriptorSet descriptorSet_ = DescriptorSet() )\n      : type( type_ )\n      , flags( flags_ )\n      , pipelineLayout( pipelineLayout_ )\n      , descriptorSet( descriptorSet_ )\n    {\n    }\n\n    ObjectTableDescriptorSetEntryNVX( VkObjectTableDescriptorSetEntryNVX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ObjectTableDescriptorSetEntryNVX) );\n    }\n\n    ObjectTableDescriptorSetEntryNVX& operator=( VkObjectTableDescriptorSetEntryNVX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ObjectTableDescriptorSetEntryNVX) );\n      return *this;\n    }\n\n    ObjectTableDescriptorSetEntryNVX& setType( ObjectEntryTypeNVX type_ )\n    {\n      type = type_;\n      return *this;\n    }\n\n    ObjectTableDescriptorSetEntryNVX& setFlags( ObjectEntryUsageFlagsNVX flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    ObjectTableDescriptorSetEntryNVX& setPipelineLayout( PipelineLayout pipelineLayout_ )\n    {\n      pipelineLayout = pipelineLayout_;\n      return *this;\n    }\n\n    ObjectTableDescriptorSetEntryNVX& setDescriptorSet( DescriptorSet descriptorSet_ )\n    {\n      descriptorSet = descriptorSet_;\n      return *this;\n    }\n\n    operator const VkObjectTableDescriptorSetEntryNVX&() const\n    {\n      return *reinterpret_cast<const VkObjectTableDescriptorSetEntryNVX*>(this);\n    }\n\n    bool operator==( ObjectTableDescriptorSetEntryNVX const& rhs ) const\n    {\n      return ( type == rhs.type )\n          && ( flags == rhs.flags )\n          && ( pipelineLayout == rhs.pipelineLayout )\n          && ( descriptorSet == rhs.descriptorSet );\n    }\n\n    bool operator!=( ObjectTableDescriptorSetEntryNVX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    ObjectEntryTypeNVX type;\n    ObjectEntryUsageFlagsNVX flags;\n    PipelineLayout pipelineLayout;\n    DescriptorSet descriptorSet;\n  };\n  static_assert( sizeof( ObjectTableDescriptorSetEntryNVX ) == sizeof( VkObjectTableDescriptorSetEntryNVX ), \"struct and wrapper have different size!\" );\n\n  struct ObjectTableVertexBufferEntryNVX\n  {\n    ObjectTableVertexBufferEntryNVX( ObjectEntryTypeNVX type_ = ObjectEntryTypeNVX::eVkObjectEntryDescriptorSet, ObjectEntryUsageFlagsNVX flags_ = ObjectEntryUsageFlagsNVX(), Buffer buffer_ = Buffer() )\n      : type( type_ )\n      , flags( flags_ )\n      , buffer( buffer_ )\n    {\n    }\n\n    ObjectTableVertexBufferEntryNVX( VkObjectTableVertexBufferEntryNVX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ObjectTableVertexBufferEntryNVX) );\n    }\n\n    ObjectTableVertexBufferEntryNVX& operator=( VkObjectTableVertexBufferEntryNVX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ObjectTableVertexBufferEntryNVX) );\n      return *this;\n    }\n\n    ObjectTableVertexBufferEntryNVX& setType( ObjectEntryTypeNVX type_ )\n    {\n      type = type_;\n      return *this;\n    }\n\n    ObjectTableVertexBufferEntryNVX& setFlags( ObjectEntryUsageFlagsNVX flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    ObjectTableVertexBufferEntryNVX& setBuffer( Buffer buffer_ )\n    {\n      buffer = buffer_;\n      return *this;\n    }\n\n    operator const VkObjectTableVertexBufferEntryNVX&() const\n    {\n      return *reinterpret_cast<const VkObjectTableVertexBufferEntryNVX*>(this);\n    }\n\n    bool operator==( ObjectTableVertexBufferEntryNVX const& rhs ) const\n    {\n      return ( type == rhs.type )\n          && ( flags == rhs.flags )\n          && ( buffer == rhs.buffer );\n    }\n\n    bool operator!=( ObjectTableVertexBufferEntryNVX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    ObjectEntryTypeNVX type;\n    ObjectEntryUsageFlagsNVX flags;\n    Buffer buffer;\n  };\n  static_assert( sizeof( ObjectTableVertexBufferEntryNVX ) == sizeof( VkObjectTableVertexBufferEntryNVX ), \"struct and wrapper have different size!\" );\n\n  struct ObjectTableIndexBufferEntryNVX\n  {\n    ObjectTableIndexBufferEntryNVX( ObjectEntryTypeNVX type_ = ObjectEntryTypeNVX::eVkObjectEntryDescriptorSet, ObjectEntryUsageFlagsNVX flags_ = ObjectEntryUsageFlagsNVX(), Buffer buffer_ = Buffer(), IndexType indexType_ = IndexType::eUint16 )\n      : type( type_ )\n      , flags( flags_ )\n      , buffer( buffer_ )\n      , indexType( indexType_ )\n    {\n    }\n\n    ObjectTableIndexBufferEntryNVX( VkObjectTableIndexBufferEntryNVX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ObjectTableIndexBufferEntryNVX) );\n    }\n\n    ObjectTableIndexBufferEntryNVX& operator=( VkObjectTableIndexBufferEntryNVX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ObjectTableIndexBufferEntryNVX) );\n      return *this;\n    }\n\n    ObjectTableIndexBufferEntryNVX& setType( ObjectEntryTypeNVX type_ )\n    {\n      type = type_;\n      return *this;\n    }\n\n    ObjectTableIndexBufferEntryNVX& setFlags( ObjectEntryUsageFlagsNVX flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    ObjectTableIndexBufferEntryNVX& setBuffer( Buffer buffer_ )\n    {\n      buffer = buffer_;\n      return *this;\n    }\n\n    ObjectTableIndexBufferEntryNVX& setIndexType( IndexType indexType_ )\n    {\n      indexType = indexType_;\n      return *this;\n    }\n\n    operator const VkObjectTableIndexBufferEntryNVX&() const\n    {\n      return *reinterpret_cast<const VkObjectTableIndexBufferEntryNVX*>(this);\n    }\n\n    bool operator==( ObjectTableIndexBufferEntryNVX const& rhs ) const\n    {\n      return ( type == rhs.type )\n          && ( flags == rhs.flags )\n          && ( buffer == rhs.buffer )\n          && ( indexType == rhs.indexType );\n    }\n\n    bool operator!=( ObjectTableIndexBufferEntryNVX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    ObjectEntryTypeNVX type;\n    ObjectEntryUsageFlagsNVX flags;\n    Buffer buffer;\n    IndexType indexType;\n  };\n  static_assert( sizeof( ObjectTableIndexBufferEntryNVX ) == sizeof( VkObjectTableIndexBufferEntryNVX ), \"struct and wrapper have different size!\" );\n\n  struct ObjectTablePushConstantEntryNVX\n  {\n    ObjectTablePushConstantEntryNVX( ObjectEntryTypeNVX type_ = ObjectEntryTypeNVX::eVkObjectEntryDescriptorSet, ObjectEntryUsageFlagsNVX flags_ = ObjectEntryUsageFlagsNVX(), PipelineLayout pipelineLayout_ = PipelineLayout(), ShaderStageFlags stageFlags_ = ShaderStageFlags() )\n      : type( type_ )\n      , flags( flags_ )\n      , pipelineLayout( pipelineLayout_ )\n      , stageFlags( stageFlags_ )\n    {\n    }\n\n    ObjectTablePushConstantEntryNVX( VkObjectTablePushConstantEntryNVX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ObjectTablePushConstantEntryNVX) );\n    }\n\n    ObjectTablePushConstantEntryNVX& operator=( VkObjectTablePushConstantEntryNVX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ObjectTablePushConstantEntryNVX) );\n      return *this;\n    }\n\n    ObjectTablePushConstantEntryNVX& setType( ObjectEntryTypeNVX type_ )\n    {\n      type = type_;\n      return *this;\n    }\n\n    ObjectTablePushConstantEntryNVX& setFlags( ObjectEntryUsageFlagsNVX flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    ObjectTablePushConstantEntryNVX& setPipelineLayout( PipelineLayout pipelineLayout_ )\n    {\n      pipelineLayout = pipelineLayout_;\n      return *this;\n    }\n\n    ObjectTablePushConstantEntryNVX& setStageFlags( ShaderStageFlags stageFlags_ )\n    {\n      stageFlags = stageFlags_;\n      return *this;\n    }\n\n    operator const VkObjectTablePushConstantEntryNVX&() const\n    {\n      return *reinterpret_cast<const VkObjectTablePushConstantEntryNVX*>(this);\n    }\n\n    bool operator==( ObjectTablePushConstantEntryNVX const& rhs ) const\n    {\n      return ( type == rhs.type )\n          && ( flags == rhs.flags )\n          && ( pipelineLayout == rhs.pipelineLayout )\n          && ( stageFlags == rhs.stageFlags );\n    }\n\n    bool operator!=( ObjectTablePushConstantEntryNVX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    ObjectEntryTypeNVX type;\n    ObjectEntryUsageFlagsNVX flags;\n    PipelineLayout pipelineLayout;\n    ShaderStageFlags stageFlags;\n  };\n  static_assert( sizeof( ObjectTablePushConstantEntryNVX ) == sizeof( VkObjectTablePushConstantEntryNVX ), \"struct and wrapper have different size!\" );\n\n  enum class DescriptorSetLayoutCreateFlagBits\n  {\n    ePushDescriptorKHR = VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR\n  };\n\n  using DescriptorSetLayoutCreateFlags = Flags<DescriptorSetLayoutCreateFlagBits, VkDescriptorSetLayoutCreateFlags>;\n\n  VULKAN_HPP_INLINE DescriptorSetLayoutCreateFlags operator|( DescriptorSetLayoutCreateFlagBits bit0, DescriptorSetLayoutCreateFlagBits bit1 )\n  {\n    return DescriptorSetLayoutCreateFlags( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE DescriptorSetLayoutCreateFlags operator~( DescriptorSetLayoutCreateFlagBits bits )\n  {\n    return ~( DescriptorSetLayoutCreateFlags( bits ) );\n  }\n\n  template <> struct FlagTraits<DescriptorSetLayoutCreateFlagBits>\n  {\n    enum\n    {\n      allFlags = VkFlags(DescriptorSetLayoutCreateFlagBits::ePushDescriptorKHR)\n    };\n  };\n\n  struct DescriptorSetLayoutCreateInfo\n  {\n    DescriptorSetLayoutCreateInfo( DescriptorSetLayoutCreateFlags flags_ = DescriptorSetLayoutCreateFlags(), uint32_t bindingCount_ = 0, const DescriptorSetLayoutBinding* pBindings_ = nullptr )\n      : sType( StructureType::eDescriptorSetLayoutCreateInfo )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , bindingCount( bindingCount_ )\n      , pBindings( pBindings_ )\n    {\n    }\n\n    DescriptorSetLayoutCreateInfo( VkDescriptorSetLayoutCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DescriptorSetLayoutCreateInfo) );\n    }\n\n    DescriptorSetLayoutCreateInfo& operator=( VkDescriptorSetLayoutCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DescriptorSetLayoutCreateInfo) );\n      return *this;\n    }\n\n    DescriptorSetLayoutCreateInfo& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    DescriptorSetLayoutCreateInfo& setFlags( DescriptorSetLayoutCreateFlags flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    DescriptorSetLayoutCreateInfo& setBindingCount( uint32_t bindingCount_ )\n    {\n      bindingCount = bindingCount_;\n      return *this;\n    }\n\n    DescriptorSetLayoutCreateInfo& setPBindings( const DescriptorSetLayoutBinding* pBindings_ )\n    {\n      pBindings = pBindings_;\n      return *this;\n    }\n\n    operator const VkDescriptorSetLayoutCreateInfo&() const\n    {\n      return *reinterpret_cast<const VkDescriptorSetLayoutCreateInfo*>(this);\n    }\n\n    bool operator==( DescriptorSetLayoutCreateInfo const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( bindingCount == rhs.bindingCount )\n          && ( pBindings == rhs.pBindings );\n    }\n\n    bool operator!=( DescriptorSetLayoutCreateInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    DescriptorSetLayoutCreateFlags flags;\n    uint32_t bindingCount;\n    const DescriptorSetLayoutBinding* pBindings;\n  };\n  static_assert( sizeof( DescriptorSetLayoutCreateInfo ) == sizeof( VkDescriptorSetLayoutCreateInfo ), \"struct and wrapper have different size!\" );\n\n  enum class ExternalMemoryHandleTypeFlagBitsKHX\n  {\n    eOpaqueFd = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHX,\n    eOpaqueWin32 = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHX,\n    eOpaqueWin32Kmt = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHX,\n    eD3D11Texture = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT_KHX,\n    eD3D11TextureKmt = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT_KHX,\n    eD3D12Heap = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT_KHX,\n    eD3D12Resource = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT_KHX\n  };\n\n  using ExternalMemoryHandleTypeFlagsKHX = Flags<ExternalMemoryHandleTypeFlagBitsKHX, VkExternalMemoryHandleTypeFlagsKHX>;\n\n  VULKAN_HPP_INLINE ExternalMemoryHandleTypeFlagsKHX operator|( ExternalMemoryHandleTypeFlagBitsKHX bit0, ExternalMemoryHandleTypeFlagBitsKHX bit1 )\n  {\n    return ExternalMemoryHandleTypeFlagsKHX( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE ExternalMemoryHandleTypeFlagsKHX operator~( ExternalMemoryHandleTypeFlagBitsKHX bits )\n  {\n    return ~( ExternalMemoryHandleTypeFlagsKHX( bits ) );\n  }\n\n  template <> struct FlagTraits<ExternalMemoryHandleTypeFlagBitsKHX>\n  {\n    enum\n    {\n      allFlags = VkFlags(ExternalMemoryHandleTypeFlagBitsKHX::eOpaqueFd) | VkFlags(ExternalMemoryHandleTypeFlagBitsKHX::eOpaqueWin32) | VkFlags(ExternalMemoryHandleTypeFlagBitsKHX::eOpaqueWin32Kmt) | VkFlags(ExternalMemoryHandleTypeFlagBitsKHX::eD3D11Texture) | VkFlags(ExternalMemoryHandleTypeFlagBitsKHX::eD3D11TextureKmt) | VkFlags(ExternalMemoryHandleTypeFlagBitsKHX::eD3D12Heap) | VkFlags(ExternalMemoryHandleTypeFlagBitsKHX::eD3D12Resource)\n    };\n  };\n\n  struct PhysicalDeviceExternalImageFormatInfoKHX\n  {\n    PhysicalDeviceExternalImageFormatInfoKHX( ExternalMemoryHandleTypeFlagBitsKHX handleType_ = ExternalMemoryHandleTypeFlagBitsKHX::eOpaqueFd )\n      : sType( StructureType::ePhysicalDeviceExternalImageFormatInfoKHX )\n      , pNext( nullptr )\n      , handleType( handleType_ )\n    {\n    }\n\n    PhysicalDeviceExternalImageFormatInfoKHX( VkPhysicalDeviceExternalImageFormatInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PhysicalDeviceExternalImageFormatInfoKHX) );\n    }\n\n    PhysicalDeviceExternalImageFormatInfoKHX& operator=( VkPhysicalDeviceExternalImageFormatInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PhysicalDeviceExternalImageFormatInfoKHX) );\n      return *this;\n    }\n\n    PhysicalDeviceExternalImageFormatInfoKHX& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    PhysicalDeviceExternalImageFormatInfoKHX& setHandleType( ExternalMemoryHandleTypeFlagBitsKHX handleType_ )\n    {\n      handleType = handleType_;\n      return *this;\n    }\n\n    operator const VkPhysicalDeviceExternalImageFormatInfoKHX&() const\n    {\n      return *reinterpret_cast<const VkPhysicalDeviceExternalImageFormatInfoKHX*>(this);\n    }\n\n    bool operator==( PhysicalDeviceExternalImageFormatInfoKHX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( handleType == rhs.handleType );\n    }\n\n    bool operator!=( PhysicalDeviceExternalImageFormatInfoKHX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    ExternalMemoryHandleTypeFlagBitsKHX handleType;\n  };\n  static_assert( sizeof( PhysicalDeviceExternalImageFormatInfoKHX ) == sizeof( VkPhysicalDeviceExternalImageFormatInfoKHX ), \"struct and wrapper have different size!\" );\n\n  struct PhysicalDeviceExternalBufferInfoKHX\n  {\n    PhysicalDeviceExternalBufferInfoKHX( BufferCreateFlags flags_ = BufferCreateFlags(), BufferUsageFlags usage_ = BufferUsageFlags(), ExternalMemoryHandleTypeFlagBitsKHX handleType_ = ExternalMemoryHandleTypeFlagBitsKHX::eOpaqueFd )\n      : sType( StructureType::ePhysicalDeviceExternalBufferInfoKHX )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , usage( usage_ )\n      , handleType( handleType_ )\n    {\n    }\n\n    PhysicalDeviceExternalBufferInfoKHX( VkPhysicalDeviceExternalBufferInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PhysicalDeviceExternalBufferInfoKHX) );\n    }\n\n    PhysicalDeviceExternalBufferInfoKHX& operator=( VkPhysicalDeviceExternalBufferInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PhysicalDeviceExternalBufferInfoKHX) );\n      return *this;\n    }\n\n    PhysicalDeviceExternalBufferInfoKHX& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    PhysicalDeviceExternalBufferInfoKHX& setFlags( BufferCreateFlags flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    PhysicalDeviceExternalBufferInfoKHX& setUsage( BufferUsageFlags usage_ )\n    {\n      usage = usage_;\n      return *this;\n    }\n\n    PhysicalDeviceExternalBufferInfoKHX& setHandleType( ExternalMemoryHandleTypeFlagBitsKHX handleType_ )\n    {\n      handleType = handleType_;\n      return *this;\n    }\n\n    operator const VkPhysicalDeviceExternalBufferInfoKHX&() const\n    {\n      return *reinterpret_cast<const VkPhysicalDeviceExternalBufferInfoKHX*>(this);\n    }\n\n    bool operator==( PhysicalDeviceExternalBufferInfoKHX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( usage == rhs.usage )\n          && ( handleType == rhs.handleType );\n    }\n\n    bool operator!=( PhysicalDeviceExternalBufferInfoKHX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    BufferCreateFlags flags;\n    BufferUsageFlags usage;\n    ExternalMemoryHandleTypeFlagBitsKHX handleType;\n  };\n  static_assert( sizeof( PhysicalDeviceExternalBufferInfoKHX ) == sizeof( VkPhysicalDeviceExternalBufferInfoKHX ), \"struct and wrapper have different size!\" );\n\n  struct ExternalMemoryImageCreateInfoKHX\n  {\n    ExternalMemoryImageCreateInfoKHX( ExternalMemoryHandleTypeFlagsKHX handleTypes_ = ExternalMemoryHandleTypeFlagsKHX() )\n      : sType( StructureType::eExternalMemoryImageCreateInfoKHX )\n      , pNext( nullptr )\n      , handleTypes( handleTypes_ )\n    {\n    }\n\n    ExternalMemoryImageCreateInfoKHX( VkExternalMemoryImageCreateInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ExternalMemoryImageCreateInfoKHX) );\n    }\n\n    ExternalMemoryImageCreateInfoKHX& operator=( VkExternalMemoryImageCreateInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ExternalMemoryImageCreateInfoKHX) );\n      return *this;\n    }\n\n    ExternalMemoryImageCreateInfoKHX& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    ExternalMemoryImageCreateInfoKHX& setHandleTypes( ExternalMemoryHandleTypeFlagsKHX handleTypes_ )\n    {\n      handleTypes = handleTypes_;\n      return *this;\n    }\n\n    operator const VkExternalMemoryImageCreateInfoKHX&() const\n    {\n      return *reinterpret_cast<const VkExternalMemoryImageCreateInfoKHX*>(this);\n    }\n\n    bool operator==( ExternalMemoryImageCreateInfoKHX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( handleTypes == rhs.handleTypes );\n    }\n\n    bool operator!=( ExternalMemoryImageCreateInfoKHX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    ExternalMemoryHandleTypeFlagsKHX handleTypes;\n  };\n  static_assert( sizeof( ExternalMemoryImageCreateInfoKHX ) == sizeof( VkExternalMemoryImageCreateInfoKHX ), \"struct and wrapper have different size!\" );\n\n  struct ExternalMemoryBufferCreateInfoKHX\n  {\n    ExternalMemoryBufferCreateInfoKHX( ExternalMemoryHandleTypeFlagsKHX handleTypes_ = ExternalMemoryHandleTypeFlagsKHX() )\n      : sType( StructureType::eExternalMemoryBufferCreateInfoKHX )\n      , pNext( nullptr )\n      , handleTypes( handleTypes_ )\n    {\n    }\n\n    ExternalMemoryBufferCreateInfoKHX( VkExternalMemoryBufferCreateInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ExternalMemoryBufferCreateInfoKHX) );\n    }\n\n    ExternalMemoryBufferCreateInfoKHX& operator=( VkExternalMemoryBufferCreateInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ExternalMemoryBufferCreateInfoKHX) );\n      return *this;\n    }\n\n    ExternalMemoryBufferCreateInfoKHX& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    ExternalMemoryBufferCreateInfoKHX& setHandleTypes( ExternalMemoryHandleTypeFlagsKHX handleTypes_ )\n    {\n      handleTypes = handleTypes_;\n      return *this;\n    }\n\n    operator const VkExternalMemoryBufferCreateInfoKHX&() const\n    {\n      return *reinterpret_cast<const VkExternalMemoryBufferCreateInfoKHX*>(this);\n    }\n\n    bool operator==( ExternalMemoryBufferCreateInfoKHX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( handleTypes == rhs.handleTypes );\n    }\n\n    bool operator!=( ExternalMemoryBufferCreateInfoKHX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    ExternalMemoryHandleTypeFlagsKHX handleTypes;\n  };\n  static_assert( sizeof( ExternalMemoryBufferCreateInfoKHX ) == sizeof( VkExternalMemoryBufferCreateInfoKHX ), \"struct and wrapper have different size!\" );\n\n  struct ExportMemoryAllocateInfoKHX\n  {\n    ExportMemoryAllocateInfoKHX( ExternalMemoryHandleTypeFlagsKHX handleTypes_ = ExternalMemoryHandleTypeFlagsKHX() )\n      : sType( StructureType::eExportMemoryAllocateInfoKHX )\n      , pNext( nullptr )\n      , handleTypes( handleTypes_ )\n    {\n    }\n\n    ExportMemoryAllocateInfoKHX( VkExportMemoryAllocateInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ExportMemoryAllocateInfoKHX) );\n    }\n\n    ExportMemoryAllocateInfoKHX& operator=( VkExportMemoryAllocateInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ExportMemoryAllocateInfoKHX) );\n      return *this;\n    }\n\n    ExportMemoryAllocateInfoKHX& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    ExportMemoryAllocateInfoKHX& setHandleTypes( ExternalMemoryHandleTypeFlagsKHX handleTypes_ )\n    {\n      handleTypes = handleTypes_;\n      return *this;\n    }\n\n    operator const VkExportMemoryAllocateInfoKHX&() const\n    {\n      return *reinterpret_cast<const VkExportMemoryAllocateInfoKHX*>(this);\n    }\n\n    bool operator==( ExportMemoryAllocateInfoKHX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( handleTypes == rhs.handleTypes );\n    }\n\n    bool operator!=( ExportMemoryAllocateInfoKHX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    ExternalMemoryHandleTypeFlagsKHX handleTypes;\n  };\n  static_assert( sizeof( ExportMemoryAllocateInfoKHX ) == sizeof( VkExportMemoryAllocateInfoKHX ), \"struct and wrapper have different size!\" );\n\n#ifdef VK_USE_PLATFORM_WIN32_KHX\n  struct ImportMemoryWin32HandleInfoKHX\n  {\n    ImportMemoryWin32HandleInfoKHX( ExternalMemoryHandleTypeFlagBitsKHX handleType_ = ExternalMemoryHandleTypeFlagBitsKHX::eOpaqueFd, HANDLE handle_ = 0 )\n      : sType( StructureType::eImportMemoryWin32HandleInfoKHX )\n      , pNext( nullptr )\n      , handleType( handleType_ )\n      , handle( handle_ )\n    {\n    }\n\n    ImportMemoryWin32HandleInfoKHX( VkImportMemoryWin32HandleInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ImportMemoryWin32HandleInfoKHX) );\n    }\n\n    ImportMemoryWin32HandleInfoKHX& operator=( VkImportMemoryWin32HandleInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ImportMemoryWin32HandleInfoKHX) );\n      return *this;\n    }\n\n    ImportMemoryWin32HandleInfoKHX& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    ImportMemoryWin32HandleInfoKHX& setHandleType( ExternalMemoryHandleTypeFlagBitsKHX handleType_ )\n    {\n      handleType = handleType_;\n      return *this;\n    }\n\n    ImportMemoryWin32HandleInfoKHX& setHandle( HANDLE handle_ )\n    {\n      handle = handle_;\n      return *this;\n    }\n\n    operator const VkImportMemoryWin32HandleInfoKHX&() const\n    {\n      return *reinterpret_cast<const VkImportMemoryWin32HandleInfoKHX*>(this);\n    }\n\n    bool operator==( ImportMemoryWin32HandleInfoKHX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( handleType == rhs.handleType )\n          && ( handle == rhs.handle );\n    }\n\n    bool operator!=( ImportMemoryWin32HandleInfoKHX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    ExternalMemoryHandleTypeFlagBitsKHX handleType;\n    HANDLE handle;\n  };\n  static_assert( sizeof( ImportMemoryWin32HandleInfoKHX ) == sizeof( VkImportMemoryWin32HandleInfoKHX ), \"struct and wrapper have different size!\" );\n#endif /*VK_USE_PLATFORM_WIN32_KHX*/\n\n  struct ImportMemoryFdInfoKHX\n  {\n    ImportMemoryFdInfoKHX( ExternalMemoryHandleTypeFlagBitsKHX handleType_ = ExternalMemoryHandleTypeFlagBitsKHX::eOpaqueFd, int fd_ = 0 )\n      : sType( StructureType::eImportMemoryFdInfoKHX )\n      , pNext( nullptr )\n      , handleType( handleType_ )\n      , fd( fd_ )\n    {\n    }\n\n    ImportMemoryFdInfoKHX( VkImportMemoryFdInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ImportMemoryFdInfoKHX) );\n    }\n\n    ImportMemoryFdInfoKHX& operator=( VkImportMemoryFdInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ImportMemoryFdInfoKHX) );\n      return *this;\n    }\n\n    ImportMemoryFdInfoKHX& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    ImportMemoryFdInfoKHX& setHandleType( ExternalMemoryHandleTypeFlagBitsKHX handleType_ )\n    {\n      handleType = handleType_;\n      return *this;\n    }\n\n    ImportMemoryFdInfoKHX& setFd( int fd_ )\n    {\n      fd = fd_;\n      return *this;\n    }\n\n    operator const VkImportMemoryFdInfoKHX&() const\n    {\n      return *reinterpret_cast<const VkImportMemoryFdInfoKHX*>(this);\n    }\n\n    bool operator==( ImportMemoryFdInfoKHX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( handleType == rhs.handleType )\n          && ( fd == rhs.fd );\n    }\n\n    bool operator!=( ImportMemoryFdInfoKHX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    ExternalMemoryHandleTypeFlagBitsKHX handleType;\n    int fd;\n  };\n  static_assert( sizeof( ImportMemoryFdInfoKHX ) == sizeof( VkImportMemoryFdInfoKHX ), \"struct and wrapper have different size!\" );\n\n  enum class ExternalMemoryFeatureFlagBitsKHX\n  {\n    eDedicatedOnly = VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_KHX,\n    eExportable = VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHX,\n    eImportable = VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHX\n  };\n\n  using ExternalMemoryFeatureFlagsKHX = Flags<ExternalMemoryFeatureFlagBitsKHX, VkExternalMemoryFeatureFlagsKHX>;\n\n  VULKAN_HPP_INLINE ExternalMemoryFeatureFlagsKHX operator|( ExternalMemoryFeatureFlagBitsKHX bit0, ExternalMemoryFeatureFlagBitsKHX bit1 )\n  {\n    return ExternalMemoryFeatureFlagsKHX( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE ExternalMemoryFeatureFlagsKHX operator~( ExternalMemoryFeatureFlagBitsKHX bits )\n  {\n    return ~( ExternalMemoryFeatureFlagsKHX( bits ) );\n  }\n\n  template <> struct FlagTraits<ExternalMemoryFeatureFlagBitsKHX>\n  {\n    enum\n    {\n      allFlags = VkFlags(ExternalMemoryFeatureFlagBitsKHX::eDedicatedOnly) | VkFlags(ExternalMemoryFeatureFlagBitsKHX::eExportable) | VkFlags(ExternalMemoryFeatureFlagBitsKHX::eImportable)\n    };\n  };\n\n  struct ExternalMemoryPropertiesKHX\n  {\n    operator const VkExternalMemoryPropertiesKHX&() const\n    {\n      return *reinterpret_cast<const VkExternalMemoryPropertiesKHX*>(this);\n    }\n\n    bool operator==( ExternalMemoryPropertiesKHX const& rhs ) const\n    {\n      return ( externalMemoryFeatures == rhs.externalMemoryFeatures )\n          && ( exportFromImportedHandleTypes == rhs.exportFromImportedHandleTypes )\n          && ( compatibleHandleTypes == rhs.compatibleHandleTypes );\n    }\n\n    bool operator!=( ExternalMemoryPropertiesKHX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    ExternalMemoryFeatureFlagsKHX externalMemoryFeatures;\n    ExternalMemoryHandleTypeFlagsKHX exportFromImportedHandleTypes;\n    ExternalMemoryHandleTypeFlagsKHX compatibleHandleTypes;\n  };\n  static_assert( sizeof( ExternalMemoryPropertiesKHX ) == sizeof( VkExternalMemoryPropertiesKHX ), \"struct and wrapper have different size!\" );\n\n  struct ExternalImageFormatPropertiesKHX\n  {\n    operator const VkExternalImageFormatPropertiesKHX&() const\n    {\n      return *reinterpret_cast<const VkExternalImageFormatPropertiesKHX*>(this);\n    }\n\n    bool operator==( ExternalImageFormatPropertiesKHX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( externalMemoryProperties == rhs.externalMemoryProperties );\n    }\n\n    bool operator!=( ExternalImageFormatPropertiesKHX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    void* pNext;\n    ExternalMemoryPropertiesKHX externalMemoryProperties;\n  };\n  static_assert( sizeof( ExternalImageFormatPropertiesKHX ) == sizeof( VkExternalImageFormatPropertiesKHX ), \"struct and wrapper have different size!\" );\n\n  struct ExternalBufferPropertiesKHX\n  {\n    operator const VkExternalBufferPropertiesKHX&() const\n    {\n      return *reinterpret_cast<const VkExternalBufferPropertiesKHX*>(this);\n    }\n\n    bool operator==( ExternalBufferPropertiesKHX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( externalMemoryProperties == rhs.externalMemoryProperties );\n    }\n\n    bool operator!=( ExternalBufferPropertiesKHX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    void* pNext;\n    ExternalMemoryPropertiesKHX externalMemoryProperties;\n  };\n  static_assert( sizeof( ExternalBufferPropertiesKHX ) == sizeof( VkExternalBufferPropertiesKHX ), \"struct and wrapper have different size!\" );\n\n  enum class ExternalSemaphoreHandleTypeFlagBitsKHX\n  {\n    eOpaqueFd = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHX,\n    eOpaqueWin32 = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHX,\n    eOpaqueWin32Kmt = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHX,\n    eD3D12Fence = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT_KHX,\n    eFenceFd = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FENCE_FD_BIT_KHX\n  };\n\n  using ExternalSemaphoreHandleTypeFlagsKHX = Flags<ExternalSemaphoreHandleTypeFlagBitsKHX, VkExternalSemaphoreHandleTypeFlagsKHX>;\n\n  VULKAN_HPP_INLINE ExternalSemaphoreHandleTypeFlagsKHX operator|( ExternalSemaphoreHandleTypeFlagBitsKHX bit0, ExternalSemaphoreHandleTypeFlagBitsKHX bit1 )\n  {\n    return ExternalSemaphoreHandleTypeFlagsKHX( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE ExternalSemaphoreHandleTypeFlagsKHX operator~( ExternalSemaphoreHandleTypeFlagBitsKHX bits )\n  {\n    return ~( ExternalSemaphoreHandleTypeFlagsKHX( bits ) );\n  }\n\n  template <> struct FlagTraits<ExternalSemaphoreHandleTypeFlagBitsKHX>\n  {\n    enum\n    {\n      allFlags = VkFlags(ExternalSemaphoreHandleTypeFlagBitsKHX::eOpaqueFd) | VkFlags(ExternalSemaphoreHandleTypeFlagBitsKHX::eOpaqueWin32) | VkFlags(ExternalSemaphoreHandleTypeFlagBitsKHX::eOpaqueWin32Kmt) | VkFlags(ExternalSemaphoreHandleTypeFlagBitsKHX::eD3D12Fence) | VkFlags(ExternalSemaphoreHandleTypeFlagBitsKHX::eFenceFd)\n    };\n  };\n\n  struct PhysicalDeviceExternalSemaphoreInfoKHX\n  {\n    PhysicalDeviceExternalSemaphoreInfoKHX( ExternalSemaphoreHandleTypeFlagBitsKHX handleType_ = ExternalSemaphoreHandleTypeFlagBitsKHX::eOpaqueFd )\n      : sType( StructureType::ePhysicalDeviceExternalSemaphoreInfoKHX )\n      , pNext( nullptr )\n      , handleType( handleType_ )\n    {\n    }\n\n    PhysicalDeviceExternalSemaphoreInfoKHX( VkPhysicalDeviceExternalSemaphoreInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PhysicalDeviceExternalSemaphoreInfoKHX) );\n    }\n\n    PhysicalDeviceExternalSemaphoreInfoKHX& operator=( VkPhysicalDeviceExternalSemaphoreInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PhysicalDeviceExternalSemaphoreInfoKHX) );\n      return *this;\n    }\n\n    PhysicalDeviceExternalSemaphoreInfoKHX& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    PhysicalDeviceExternalSemaphoreInfoKHX& setHandleType( ExternalSemaphoreHandleTypeFlagBitsKHX handleType_ )\n    {\n      handleType = handleType_;\n      return *this;\n    }\n\n    operator const VkPhysicalDeviceExternalSemaphoreInfoKHX&() const\n    {\n      return *reinterpret_cast<const VkPhysicalDeviceExternalSemaphoreInfoKHX*>(this);\n    }\n\n    bool operator==( PhysicalDeviceExternalSemaphoreInfoKHX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( handleType == rhs.handleType );\n    }\n\n    bool operator!=( PhysicalDeviceExternalSemaphoreInfoKHX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    ExternalSemaphoreHandleTypeFlagBitsKHX handleType;\n  };\n  static_assert( sizeof( PhysicalDeviceExternalSemaphoreInfoKHX ) == sizeof( VkPhysicalDeviceExternalSemaphoreInfoKHX ), \"struct and wrapper have different size!\" );\n\n  struct ExportSemaphoreCreateInfoKHX\n  {\n    ExportSemaphoreCreateInfoKHX( ExternalSemaphoreHandleTypeFlagsKHX handleTypes_ = ExternalSemaphoreHandleTypeFlagsKHX() )\n      : sType( StructureType::eExportSemaphoreCreateInfoKHX )\n      , pNext( nullptr )\n      , handleTypes( handleTypes_ )\n    {\n    }\n\n    ExportSemaphoreCreateInfoKHX( VkExportSemaphoreCreateInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ExportSemaphoreCreateInfoKHX) );\n    }\n\n    ExportSemaphoreCreateInfoKHX& operator=( VkExportSemaphoreCreateInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ExportSemaphoreCreateInfoKHX) );\n      return *this;\n    }\n\n    ExportSemaphoreCreateInfoKHX& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    ExportSemaphoreCreateInfoKHX& setHandleTypes( ExternalSemaphoreHandleTypeFlagsKHX handleTypes_ )\n    {\n      handleTypes = handleTypes_;\n      return *this;\n    }\n\n    operator const VkExportSemaphoreCreateInfoKHX&() const\n    {\n      return *reinterpret_cast<const VkExportSemaphoreCreateInfoKHX*>(this);\n    }\n\n    bool operator==( ExportSemaphoreCreateInfoKHX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( handleTypes == rhs.handleTypes );\n    }\n\n    bool operator!=( ExportSemaphoreCreateInfoKHX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    ExternalSemaphoreHandleTypeFlagsKHX handleTypes;\n  };\n  static_assert( sizeof( ExportSemaphoreCreateInfoKHX ) == sizeof( VkExportSemaphoreCreateInfoKHX ), \"struct and wrapper have different size!\" );\n\n#ifdef VK_USE_PLATFORM_WIN32_KHX\n  struct ImportSemaphoreWin32HandleInfoKHX\n  {\n    ImportSemaphoreWin32HandleInfoKHX( Semaphore semaphore_ = Semaphore(), ExternalSemaphoreHandleTypeFlagsKHX handleType_ = ExternalSemaphoreHandleTypeFlagsKHX(), HANDLE handle_ = 0 )\n      : sType( StructureType::eImportSemaphoreWin32HandleInfoKHX )\n      , pNext( nullptr )\n      , semaphore( semaphore_ )\n      , handleType( handleType_ )\n      , handle( handle_ )\n    {\n    }\n\n    ImportSemaphoreWin32HandleInfoKHX( VkImportSemaphoreWin32HandleInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ImportSemaphoreWin32HandleInfoKHX) );\n    }\n\n    ImportSemaphoreWin32HandleInfoKHX& operator=( VkImportSemaphoreWin32HandleInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ImportSemaphoreWin32HandleInfoKHX) );\n      return *this;\n    }\n\n    ImportSemaphoreWin32HandleInfoKHX& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    ImportSemaphoreWin32HandleInfoKHX& setSemaphore( Semaphore semaphore_ )\n    {\n      semaphore = semaphore_;\n      return *this;\n    }\n\n    ImportSemaphoreWin32HandleInfoKHX& setHandleType( ExternalSemaphoreHandleTypeFlagsKHX handleType_ )\n    {\n      handleType = handleType_;\n      return *this;\n    }\n\n    ImportSemaphoreWin32HandleInfoKHX& setHandle( HANDLE handle_ )\n    {\n      handle = handle_;\n      return *this;\n    }\n\n    operator const VkImportSemaphoreWin32HandleInfoKHX&() const\n    {\n      return *reinterpret_cast<const VkImportSemaphoreWin32HandleInfoKHX*>(this);\n    }\n\n    bool operator==( ImportSemaphoreWin32HandleInfoKHX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( semaphore == rhs.semaphore )\n          && ( handleType == rhs.handleType )\n          && ( handle == rhs.handle );\n    }\n\n    bool operator!=( ImportSemaphoreWin32HandleInfoKHX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    Semaphore semaphore;\n    ExternalSemaphoreHandleTypeFlagsKHX handleType;\n    HANDLE handle;\n  };\n  static_assert( sizeof( ImportSemaphoreWin32HandleInfoKHX ) == sizeof( VkImportSemaphoreWin32HandleInfoKHX ), \"struct and wrapper have different size!\" );\n#endif /*VK_USE_PLATFORM_WIN32_KHX*/\n\n  struct ImportSemaphoreFdInfoKHX\n  {\n    ImportSemaphoreFdInfoKHX( Semaphore semaphore_ = Semaphore(), ExternalSemaphoreHandleTypeFlagBitsKHX handleType_ = ExternalSemaphoreHandleTypeFlagBitsKHX::eOpaqueFd, int fd_ = 0 )\n      : sType( StructureType::eImportSemaphoreFdInfoKHX )\n      , pNext( nullptr )\n      , semaphore( semaphore_ )\n      , handleType( handleType_ )\n      , fd( fd_ )\n    {\n    }\n\n    ImportSemaphoreFdInfoKHX( VkImportSemaphoreFdInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ImportSemaphoreFdInfoKHX) );\n    }\n\n    ImportSemaphoreFdInfoKHX& operator=( VkImportSemaphoreFdInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ImportSemaphoreFdInfoKHX) );\n      return *this;\n    }\n\n    ImportSemaphoreFdInfoKHX& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    ImportSemaphoreFdInfoKHX& setSemaphore( Semaphore semaphore_ )\n    {\n      semaphore = semaphore_;\n      return *this;\n    }\n\n    ImportSemaphoreFdInfoKHX& setHandleType( ExternalSemaphoreHandleTypeFlagBitsKHX handleType_ )\n    {\n      handleType = handleType_;\n      return *this;\n    }\n\n    ImportSemaphoreFdInfoKHX& setFd( int fd_ )\n    {\n      fd = fd_;\n      return *this;\n    }\n\n    operator const VkImportSemaphoreFdInfoKHX&() const\n    {\n      return *reinterpret_cast<const VkImportSemaphoreFdInfoKHX*>(this);\n    }\n\n    bool operator==( ImportSemaphoreFdInfoKHX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( semaphore == rhs.semaphore )\n          && ( handleType == rhs.handleType )\n          && ( fd == rhs.fd );\n    }\n\n    bool operator!=( ImportSemaphoreFdInfoKHX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    Semaphore semaphore;\n    ExternalSemaphoreHandleTypeFlagBitsKHX handleType;\n    int fd;\n  };\n  static_assert( sizeof( ImportSemaphoreFdInfoKHX ) == sizeof( VkImportSemaphoreFdInfoKHX ), \"struct and wrapper have different size!\" );\n\n  enum class ExternalSemaphoreFeatureFlagBitsKHX\n  {\n    eExportable = VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT_KHX,\n    eImportable = VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT_KHX\n  };\n\n  using ExternalSemaphoreFeatureFlagsKHX = Flags<ExternalSemaphoreFeatureFlagBitsKHX, VkExternalSemaphoreFeatureFlagsKHX>;\n\n  VULKAN_HPP_INLINE ExternalSemaphoreFeatureFlagsKHX operator|( ExternalSemaphoreFeatureFlagBitsKHX bit0, ExternalSemaphoreFeatureFlagBitsKHX bit1 )\n  {\n    return ExternalSemaphoreFeatureFlagsKHX( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE ExternalSemaphoreFeatureFlagsKHX operator~( ExternalSemaphoreFeatureFlagBitsKHX bits )\n  {\n    return ~( ExternalSemaphoreFeatureFlagsKHX( bits ) );\n  }\n\n  template <> struct FlagTraits<ExternalSemaphoreFeatureFlagBitsKHX>\n  {\n    enum\n    {\n      allFlags = VkFlags(ExternalSemaphoreFeatureFlagBitsKHX::eExportable) | VkFlags(ExternalSemaphoreFeatureFlagBitsKHX::eImportable)\n    };\n  };\n\n  struct ExternalSemaphorePropertiesKHX\n  {\n    operator const VkExternalSemaphorePropertiesKHX&() const\n    {\n      return *reinterpret_cast<const VkExternalSemaphorePropertiesKHX*>(this);\n    }\n\n    bool operator==( ExternalSemaphorePropertiesKHX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( exportFromImportedHandleTypes == rhs.exportFromImportedHandleTypes )\n          && ( compatibleHandleTypes == rhs.compatibleHandleTypes )\n          && ( externalSemaphoreFeatures == rhs.externalSemaphoreFeatures );\n    }\n\n    bool operator!=( ExternalSemaphorePropertiesKHX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    void* pNext;\n    ExternalSemaphoreHandleTypeFlagsKHX exportFromImportedHandleTypes;\n    ExternalSemaphoreHandleTypeFlagsKHX compatibleHandleTypes;\n    ExternalSemaphoreFeatureFlagsKHX externalSemaphoreFeatures;\n  };\n  static_assert( sizeof( ExternalSemaphorePropertiesKHX ) == sizeof( VkExternalSemaphorePropertiesKHX ), \"struct and wrapper have different size!\" );\n\n  enum class SurfaceCounterFlagBitsEXT\n  {\n    eVblank = VK_SURFACE_COUNTER_VBLANK_EXT\n  };\n\n  using SurfaceCounterFlagsEXT = Flags<SurfaceCounterFlagBitsEXT, VkSurfaceCounterFlagsEXT>;\n\n  VULKAN_HPP_INLINE SurfaceCounterFlagsEXT operator|( SurfaceCounterFlagBitsEXT bit0, SurfaceCounterFlagBitsEXT bit1 )\n  {\n    return SurfaceCounterFlagsEXT( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE SurfaceCounterFlagsEXT operator~( SurfaceCounterFlagBitsEXT bits )\n  {\n    return ~( SurfaceCounterFlagsEXT( bits ) );\n  }\n\n  template <> struct FlagTraits<SurfaceCounterFlagBitsEXT>\n  {\n    enum\n    {\n      allFlags = VkFlags(SurfaceCounterFlagBitsEXT::eVblank)\n    };\n  };\n\n  struct SurfaceCapabilities2EXT\n  {\n    operator const VkSurfaceCapabilities2EXT&() const\n    {\n      return *reinterpret_cast<const VkSurfaceCapabilities2EXT*>(this);\n    }\n\n    bool operator==( SurfaceCapabilities2EXT const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( minImageCount == rhs.minImageCount )\n          && ( maxImageCount == rhs.maxImageCount )\n          && ( currentExtent == rhs.currentExtent )\n          && ( minImageExtent == rhs.minImageExtent )\n          && ( maxImageExtent == rhs.maxImageExtent )\n          && ( maxImageArrayLayers == rhs.maxImageArrayLayers )\n          && ( supportedTransforms == rhs.supportedTransforms )\n          && ( currentTransform == rhs.currentTransform )\n          && ( supportedCompositeAlpha == rhs.supportedCompositeAlpha )\n          && ( supportedUsageFlags == rhs.supportedUsageFlags )\n          && ( supportedSurfaceCounters == rhs.supportedSurfaceCounters );\n    }\n\n    bool operator!=( SurfaceCapabilities2EXT const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    void* pNext;\n    uint32_t minImageCount;\n    uint32_t maxImageCount;\n    Extent2D currentExtent;\n    Extent2D minImageExtent;\n    Extent2D maxImageExtent;\n    uint32_t maxImageArrayLayers;\n    SurfaceTransformFlagsKHR supportedTransforms;\n    SurfaceTransformFlagBitsKHR currentTransform;\n    CompositeAlphaFlagsKHR supportedCompositeAlpha;\n    ImageUsageFlags supportedUsageFlags;\n    SurfaceCounterFlagsEXT supportedSurfaceCounters;\n  };\n  static_assert( sizeof( SurfaceCapabilities2EXT ) == sizeof( VkSurfaceCapabilities2EXT ), \"struct and wrapper have different size!\" );\n\n  struct SwapchainCounterCreateInfoEXT\n  {\n    SwapchainCounterCreateInfoEXT( SurfaceCounterFlagsEXT surfaceCounters_ = SurfaceCounterFlagsEXT() )\n      : sType( StructureType::eSwapchainCounterCreateInfoEXT )\n      , pNext( nullptr )\n      , surfaceCounters( surfaceCounters_ )\n    {\n    }\n\n    SwapchainCounterCreateInfoEXT( VkSwapchainCounterCreateInfoEXT const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(SwapchainCounterCreateInfoEXT) );\n    }\n\n    SwapchainCounterCreateInfoEXT& operator=( VkSwapchainCounterCreateInfoEXT const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(SwapchainCounterCreateInfoEXT) );\n      return *this;\n    }\n\n    SwapchainCounterCreateInfoEXT& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    SwapchainCounterCreateInfoEXT& setSurfaceCounters( SurfaceCounterFlagsEXT surfaceCounters_ )\n    {\n      surfaceCounters = surfaceCounters_;\n      return *this;\n    }\n\n    operator const VkSwapchainCounterCreateInfoEXT&() const\n    {\n      return *reinterpret_cast<const VkSwapchainCounterCreateInfoEXT*>(this);\n    }\n\n    bool operator==( SwapchainCounterCreateInfoEXT const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( surfaceCounters == rhs.surfaceCounters );\n    }\n\n    bool operator!=( SwapchainCounterCreateInfoEXT const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    SurfaceCounterFlagsEXT surfaceCounters;\n  };\n  static_assert( sizeof( SwapchainCounterCreateInfoEXT ) == sizeof( VkSwapchainCounterCreateInfoEXT ), \"struct and wrapper have different size!\" );\n\n  enum class DisplayPowerStateEXT\n  {\n    eOff = VK_DISPLAY_POWER_STATE_OFF_EXT,\n    eSuspend = VK_DISPLAY_POWER_STATE_SUSPEND_EXT,\n    eOn = VK_DISPLAY_POWER_STATE_ON_EXT\n  };\n\n  struct DisplayPowerInfoEXT\n  {\n    DisplayPowerInfoEXT( DisplayPowerStateEXT powerState_ = DisplayPowerStateEXT::eOff )\n      : sType( StructureType::eDisplayPowerInfoEXT )\n      , pNext( nullptr )\n      , powerState( powerState_ )\n    {\n    }\n\n    DisplayPowerInfoEXT( VkDisplayPowerInfoEXT const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DisplayPowerInfoEXT) );\n    }\n\n    DisplayPowerInfoEXT& operator=( VkDisplayPowerInfoEXT const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DisplayPowerInfoEXT) );\n      return *this;\n    }\n\n    DisplayPowerInfoEXT& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    DisplayPowerInfoEXT& setPowerState( DisplayPowerStateEXT powerState_ )\n    {\n      powerState = powerState_;\n      return *this;\n    }\n\n    operator const VkDisplayPowerInfoEXT&() const\n    {\n      return *reinterpret_cast<const VkDisplayPowerInfoEXT*>(this);\n    }\n\n    bool operator==( DisplayPowerInfoEXT const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( powerState == rhs.powerState );\n    }\n\n    bool operator!=( DisplayPowerInfoEXT const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    DisplayPowerStateEXT powerState;\n  };\n  static_assert( sizeof( DisplayPowerInfoEXT ) == sizeof( VkDisplayPowerInfoEXT ), \"struct and wrapper have different size!\" );\n\n  enum class DeviceEventTypeEXT\n  {\n    eDisplayHotplug = VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT\n  };\n\n  struct DeviceEventInfoEXT\n  {\n    DeviceEventInfoEXT( DeviceEventTypeEXT deviceEvent_ = DeviceEventTypeEXT::eDisplayHotplug )\n      : sType( StructureType::eDeviceEventInfoEXT )\n      , pNext( nullptr )\n      , deviceEvent( deviceEvent_ )\n    {\n    }\n\n    DeviceEventInfoEXT( VkDeviceEventInfoEXT const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DeviceEventInfoEXT) );\n    }\n\n    DeviceEventInfoEXT& operator=( VkDeviceEventInfoEXT const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DeviceEventInfoEXT) );\n      return *this;\n    }\n\n    DeviceEventInfoEXT& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    DeviceEventInfoEXT& setDeviceEvent( DeviceEventTypeEXT deviceEvent_ )\n    {\n      deviceEvent = deviceEvent_;\n      return *this;\n    }\n\n    operator const VkDeviceEventInfoEXT&() const\n    {\n      return *reinterpret_cast<const VkDeviceEventInfoEXT*>(this);\n    }\n\n    bool operator==( DeviceEventInfoEXT const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( deviceEvent == rhs.deviceEvent );\n    }\n\n    bool operator!=( DeviceEventInfoEXT const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    DeviceEventTypeEXT deviceEvent;\n  };\n  static_assert( sizeof( DeviceEventInfoEXT ) == sizeof( VkDeviceEventInfoEXT ), \"struct and wrapper have different size!\" );\n\n  enum class DisplayEventTypeEXT\n  {\n    eFirstPixelOut = VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT\n  };\n\n  struct DisplayEventInfoEXT\n  {\n    DisplayEventInfoEXT( DisplayEventTypeEXT displayEvent_ = DisplayEventTypeEXT::eFirstPixelOut )\n      : sType( StructureType::eDisplayEventInfoEXT )\n      , pNext( nullptr )\n      , displayEvent( displayEvent_ )\n    {\n    }\n\n    DisplayEventInfoEXT( VkDisplayEventInfoEXT const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DisplayEventInfoEXT) );\n    }\n\n    DisplayEventInfoEXT& operator=( VkDisplayEventInfoEXT const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DisplayEventInfoEXT) );\n      return *this;\n    }\n\n    DisplayEventInfoEXT& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    DisplayEventInfoEXT& setDisplayEvent( DisplayEventTypeEXT displayEvent_ )\n    {\n      displayEvent = displayEvent_;\n      return *this;\n    }\n\n    operator const VkDisplayEventInfoEXT&() const\n    {\n      return *reinterpret_cast<const VkDisplayEventInfoEXT*>(this);\n    }\n\n    bool operator==( DisplayEventInfoEXT const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( displayEvent == rhs.displayEvent );\n    }\n\n    bool operator!=( DisplayEventInfoEXT const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    DisplayEventTypeEXT displayEvent;\n  };\n  static_assert( sizeof( DisplayEventInfoEXT ) == sizeof( VkDisplayEventInfoEXT ), \"struct and wrapper have different size!\" );\n\n  enum class PeerMemoryFeatureFlagBitsKHX\n  {\n    eCopySrc = VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT_KHX,\n    eCopyDst = VK_PEER_MEMORY_FEATURE_COPY_DST_BIT_KHX,\n    eGenericSrc = VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT_KHX,\n    eGenericDst = VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT_KHX\n  };\n\n  using PeerMemoryFeatureFlagsKHX = Flags<PeerMemoryFeatureFlagBitsKHX, VkPeerMemoryFeatureFlagsKHX>;\n\n  VULKAN_HPP_INLINE PeerMemoryFeatureFlagsKHX operator|( PeerMemoryFeatureFlagBitsKHX bit0, PeerMemoryFeatureFlagBitsKHX bit1 )\n  {\n    return PeerMemoryFeatureFlagsKHX( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE PeerMemoryFeatureFlagsKHX operator~( PeerMemoryFeatureFlagBitsKHX bits )\n  {\n    return ~( PeerMemoryFeatureFlagsKHX( bits ) );\n  }\n\n  template <> struct FlagTraits<PeerMemoryFeatureFlagBitsKHX>\n  {\n    enum\n    {\n      allFlags = VkFlags(PeerMemoryFeatureFlagBitsKHX::eCopySrc) | VkFlags(PeerMemoryFeatureFlagBitsKHX::eCopyDst) | VkFlags(PeerMemoryFeatureFlagBitsKHX::eGenericSrc) | VkFlags(PeerMemoryFeatureFlagBitsKHX::eGenericDst)\n    };\n  };\n\n  enum class MemoryAllocateFlagBitsKHX\n  {\n    eDeviceMask = VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT_KHX\n  };\n\n  using MemoryAllocateFlagsKHX = Flags<MemoryAllocateFlagBitsKHX, VkMemoryAllocateFlagsKHX>;\n\n  VULKAN_HPP_INLINE MemoryAllocateFlagsKHX operator|( MemoryAllocateFlagBitsKHX bit0, MemoryAllocateFlagBitsKHX bit1 )\n  {\n    return MemoryAllocateFlagsKHX( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE MemoryAllocateFlagsKHX operator~( MemoryAllocateFlagBitsKHX bits )\n  {\n    return ~( MemoryAllocateFlagsKHX( bits ) );\n  }\n\n  template <> struct FlagTraits<MemoryAllocateFlagBitsKHX>\n  {\n    enum\n    {\n      allFlags = VkFlags(MemoryAllocateFlagBitsKHX::eDeviceMask)\n    };\n  };\n\n  struct MemoryAllocateFlagsInfoKHX\n  {\n    MemoryAllocateFlagsInfoKHX( MemoryAllocateFlagsKHX flags_ = MemoryAllocateFlagsKHX(), uint32_t deviceMask_ = 0 )\n      : sType( StructureType::eMemoryAllocateFlagsInfoKHX )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , deviceMask( deviceMask_ )\n    {\n    }\n\n    MemoryAllocateFlagsInfoKHX( VkMemoryAllocateFlagsInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(MemoryAllocateFlagsInfoKHX) );\n    }\n\n    MemoryAllocateFlagsInfoKHX& operator=( VkMemoryAllocateFlagsInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(MemoryAllocateFlagsInfoKHX) );\n      return *this;\n    }\n\n    MemoryAllocateFlagsInfoKHX& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    MemoryAllocateFlagsInfoKHX& setFlags( MemoryAllocateFlagsKHX flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    MemoryAllocateFlagsInfoKHX& setDeviceMask( uint32_t deviceMask_ )\n    {\n      deviceMask = deviceMask_;\n      return *this;\n    }\n\n    operator const VkMemoryAllocateFlagsInfoKHX&() const\n    {\n      return *reinterpret_cast<const VkMemoryAllocateFlagsInfoKHX*>(this);\n    }\n\n    bool operator==( MemoryAllocateFlagsInfoKHX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( deviceMask == rhs.deviceMask );\n    }\n\n    bool operator!=( MemoryAllocateFlagsInfoKHX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    MemoryAllocateFlagsKHX flags;\n    uint32_t deviceMask;\n  };\n  static_assert( sizeof( MemoryAllocateFlagsInfoKHX ) == sizeof( VkMemoryAllocateFlagsInfoKHX ), \"struct and wrapper have different size!\" );\n\n  enum class DeviceGroupPresentModeFlagBitsKHX\n  {\n    eLocal = VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHX,\n    eRemote = VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHX,\n    eSum = VK_DEVICE_GROUP_PRESENT_MODE_SUM_BIT_KHX,\n    eLocalMultiDevice = VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHX\n  };\n\n  using DeviceGroupPresentModeFlagsKHX = Flags<DeviceGroupPresentModeFlagBitsKHX, VkDeviceGroupPresentModeFlagsKHX>;\n\n  VULKAN_HPP_INLINE DeviceGroupPresentModeFlagsKHX operator|( DeviceGroupPresentModeFlagBitsKHX bit0, DeviceGroupPresentModeFlagBitsKHX bit1 )\n  {\n    return DeviceGroupPresentModeFlagsKHX( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE DeviceGroupPresentModeFlagsKHX operator~( DeviceGroupPresentModeFlagBitsKHX bits )\n  {\n    return ~( DeviceGroupPresentModeFlagsKHX( bits ) );\n  }\n\n  template <> struct FlagTraits<DeviceGroupPresentModeFlagBitsKHX>\n  {\n    enum\n    {\n      allFlags = VkFlags(DeviceGroupPresentModeFlagBitsKHX::eLocal) | VkFlags(DeviceGroupPresentModeFlagBitsKHX::eRemote) | VkFlags(DeviceGroupPresentModeFlagBitsKHX::eSum) | VkFlags(DeviceGroupPresentModeFlagBitsKHX::eLocalMultiDevice)\n    };\n  };\n\n  struct DeviceGroupPresentCapabilitiesKHX\n  {\n    operator const VkDeviceGroupPresentCapabilitiesKHX&() const\n    {\n      return *reinterpret_cast<const VkDeviceGroupPresentCapabilitiesKHX*>(this);\n    }\n\n    bool operator==( DeviceGroupPresentCapabilitiesKHX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( memcmp( presentMask, rhs.presentMask, VK_MAX_DEVICE_GROUP_SIZE_KHX * sizeof( uint32_t ) ) == 0 )\n          && ( modes == rhs.modes );\n    }\n\n    bool operator!=( DeviceGroupPresentCapabilitiesKHX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    uint32_t presentMask[VK_MAX_DEVICE_GROUP_SIZE_KHX];\n    DeviceGroupPresentModeFlagsKHX modes;\n  };\n  static_assert( sizeof( DeviceGroupPresentCapabilitiesKHX ) == sizeof( VkDeviceGroupPresentCapabilitiesKHX ), \"struct and wrapper have different size!\" );\n\n  struct DeviceGroupPresentInfoKHX\n  {\n    DeviceGroupPresentInfoKHX( uint32_t swapchainCount_ = 0, const uint32_t* pDeviceMasks_ = nullptr, DeviceGroupPresentModeFlagBitsKHX mode_ = DeviceGroupPresentModeFlagBitsKHX::eLocal )\n      : sType( StructureType::eDeviceGroupPresentInfoKHX )\n      , pNext( nullptr )\n      , swapchainCount( swapchainCount_ )\n      , pDeviceMasks( pDeviceMasks_ )\n      , mode( mode_ )\n    {\n    }\n\n    DeviceGroupPresentInfoKHX( VkDeviceGroupPresentInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DeviceGroupPresentInfoKHX) );\n    }\n\n    DeviceGroupPresentInfoKHX& operator=( VkDeviceGroupPresentInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DeviceGroupPresentInfoKHX) );\n      return *this;\n    }\n\n    DeviceGroupPresentInfoKHX& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    DeviceGroupPresentInfoKHX& setSwapchainCount( uint32_t swapchainCount_ )\n    {\n      swapchainCount = swapchainCount_;\n      return *this;\n    }\n\n    DeviceGroupPresentInfoKHX& setPDeviceMasks( const uint32_t* pDeviceMasks_ )\n    {\n      pDeviceMasks = pDeviceMasks_;\n      return *this;\n    }\n\n    DeviceGroupPresentInfoKHX& setMode( DeviceGroupPresentModeFlagBitsKHX mode_ )\n    {\n      mode = mode_;\n      return *this;\n    }\n\n    operator const VkDeviceGroupPresentInfoKHX&() const\n    {\n      return *reinterpret_cast<const VkDeviceGroupPresentInfoKHX*>(this);\n    }\n\n    bool operator==( DeviceGroupPresentInfoKHX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( swapchainCount == rhs.swapchainCount )\n          && ( pDeviceMasks == rhs.pDeviceMasks )\n          && ( mode == rhs.mode );\n    }\n\n    bool operator!=( DeviceGroupPresentInfoKHX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    uint32_t swapchainCount;\n    const uint32_t* pDeviceMasks;\n    DeviceGroupPresentModeFlagBitsKHX mode;\n  };\n  static_assert( sizeof( DeviceGroupPresentInfoKHX ) == sizeof( VkDeviceGroupPresentInfoKHX ), \"struct and wrapper have different size!\" );\n\n  struct DeviceGroupSwapchainCreateInfoKHX\n  {\n    DeviceGroupSwapchainCreateInfoKHX( DeviceGroupPresentModeFlagsKHX modes_ = DeviceGroupPresentModeFlagsKHX() )\n      : sType( StructureType::eDeviceGroupSwapchainCreateInfoKHX )\n      , pNext( nullptr )\n      , modes( modes_ )\n    {\n    }\n\n    DeviceGroupSwapchainCreateInfoKHX( VkDeviceGroupSwapchainCreateInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DeviceGroupSwapchainCreateInfoKHX) );\n    }\n\n    DeviceGroupSwapchainCreateInfoKHX& operator=( VkDeviceGroupSwapchainCreateInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DeviceGroupSwapchainCreateInfoKHX) );\n      return *this;\n    }\n\n    DeviceGroupSwapchainCreateInfoKHX& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    DeviceGroupSwapchainCreateInfoKHX& setModes( DeviceGroupPresentModeFlagsKHX modes_ )\n    {\n      modes = modes_;\n      return *this;\n    }\n\n    operator const VkDeviceGroupSwapchainCreateInfoKHX&() const\n    {\n      return *reinterpret_cast<const VkDeviceGroupSwapchainCreateInfoKHX*>(this);\n    }\n\n    bool operator==( DeviceGroupSwapchainCreateInfoKHX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( modes == rhs.modes );\n    }\n\n    bool operator!=( DeviceGroupSwapchainCreateInfoKHX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    DeviceGroupPresentModeFlagsKHX modes;\n  };\n  static_assert( sizeof( DeviceGroupSwapchainCreateInfoKHX ) == sizeof( VkDeviceGroupSwapchainCreateInfoKHX ), \"struct and wrapper have different size!\" );\n\n  enum class SwapchainCreateFlagBitsKHR\n  {\n    eBindSfrKHX = VK_SWAPCHAIN_CREATE_BIND_SFR_BIT_KHX\n  };\n\n  using SwapchainCreateFlagsKHR = Flags<SwapchainCreateFlagBitsKHR, VkSwapchainCreateFlagsKHR>;\n\n  VULKAN_HPP_INLINE SwapchainCreateFlagsKHR operator|( SwapchainCreateFlagBitsKHR bit0, SwapchainCreateFlagBitsKHR bit1 )\n  {\n    return SwapchainCreateFlagsKHR( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE SwapchainCreateFlagsKHR operator~( SwapchainCreateFlagBitsKHR bits )\n  {\n    return ~( SwapchainCreateFlagsKHR( bits ) );\n  }\n\n  template <> struct FlagTraits<SwapchainCreateFlagBitsKHR>\n  {\n    enum\n    {\n      allFlags = VkFlags(SwapchainCreateFlagBitsKHR::eBindSfrKHX)\n    };\n  };\n\n  struct SwapchainCreateInfoKHR\n  {\n    SwapchainCreateInfoKHR( SwapchainCreateFlagsKHR flags_ = SwapchainCreateFlagsKHR(), SurfaceKHR surface_ = SurfaceKHR(), uint32_t minImageCount_ = 0, Format imageFormat_ = Format::eUndefined, ColorSpaceKHR imageColorSpace_ = ColorSpaceKHR::eSrgbNonlinear, Extent2D imageExtent_ = Extent2D(), uint32_t imageArrayLayers_ = 0, ImageUsageFlags imageUsage_ = ImageUsageFlags(), SharingMode imageSharingMode_ = SharingMode::eExclusive, uint32_t queueFamilyIndexCount_ = 0, const uint32_t* pQueueFamilyIndices_ = nullptr, SurfaceTransformFlagBitsKHR preTransform_ = SurfaceTransformFlagBitsKHR::eIdentity, CompositeAlphaFlagBitsKHR compositeAlpha_ = CompositeAlphaFlagBitsKHR::eOpaque, PresentModeKHR presentMode_ = PresentModeKHR::eImmediate, Bool32 clipped_ = 0, SwapchainKHR oldSwapchain_ = SwapchainKHR() )\n      : sType( StructureType::eSwapchainCreateInfoKHR )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , surface( surface_ )\n      , minImageCount( minImageCount_ )\n      , imageFormat( imageFormat_ )\n      , imageColorSpace( imageColorSpace_ )\n      , imageExtent( imageExtent_ )\n      , imageArrayLayers( imageArrayLayers_ )\n      , imageUsage( imageUsage_ )\n      , imageSharingMode( imageSharingMode_ )\n      , queueFamilyIndexCount( queueFamilyIndexCount_ )\n      , pQueueFamilyIndices( pQueueFamilyIndices_ )\n      , preTransform( preTransform_ )\n      , compositeAlpha( compositeAlpha_ )\n      , presentMode( presentMode_ )\n      , clipped( clipped_ )\n      , oldSwapchain( oldSwapchain_ )\n    {\n    }\n\n    SwapchainCreateInfoKHR( VkSwapchainCreateInfoKHR const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(SwapchainCreateInfoKHR) );\n    }\n\n    SwapchainCreateInfoKHR& operator=( VkSwapchainCreateInfoKHR const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(SwapchainCreateInfoKHR) );\n      return *this;\n    }\n\n    SwapchainCreateInfoKHR& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    SwapchainCreateInfoKHR& setFlags( SwapchainCreateFlagsKHR flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    SwapchainCreateInfoKHR& setSurface( SurfaceKHR surface_ )\n    {\n      surface = surface_;\n      return *this;\n    }\n\n    SwapchainCreateInfoKHR& setMinImageCount( uint32_t minImageCount_ )\n    {\n      minImageCount = minImageCount_;\n      return *this;\n    }\n\n    SwapchainCreateInfoKHR& setImageFormat( Format imageFormat_ )\n    {\n      imageFormat = imageFormat_;\n      return *this;\n    }\n\n    SwapchainCreateInfoKHR& setImageColorSpace( ColorSpaceKHR imageColorSpace_ )\n    {\n      imageColorSpace = imageColorSpace_;\n      return *this;\n    }\n\n    SwapchainCreateInfoKHR& setImageExtent( Extent2D imageExtent_ )\n    {\n      imageExtent = imageExtent_;\n      return *this;\n    }\n\n    SwapchainCreateInfoKHR& setImageArrayLayers( uint32_t imageArrayLayers_ )\n    {\n      imageArrayLayers = imageArrayLayers_;\n      return *this;\n    }\n\n    SwapchainCreateInfoKHR& setImageUsage( ImageUsageFlags imageUsage_ )\n    {\n      imageUsage = imageUsage_;\n      return *this;\n    }\n\n    SwapchainCreateInfoKHR& setImageSharingMode( SharingMode imageSharingMode_ )\n    {\n      imageSharingMode = imageSharingMode_;\n      return *this;\n    }\n\n    SwapchainCreateInfoKHR& setQueueFamilyIndexCount( uint32_t queueFamilyIndexCount_ )\n    {\n      queueFamilyIndexCount = queueFamilyIndexCount_;\n      return *this;\n    }\n\n    SwapchainCreateInfoKHR& setPQueueFamilyIndices( const uint32_t* pQueueFamilyIndices_ )\n    {\n      pQueueFamilyIndices = pQueueFamilyIndices_;\n      return *this;\n    }\n\n    SwapchainCreateInfoKHR& setPreTransform( SurfaceTransformFlagBitsKHR preTransform_ )\n    {\n      preTransform = preTransform_;\n      return *this;\n    }\n\n    SwapchainCreateInfoKHR& setCompositeAlpha( CompositeAlphaFlagBitsKHR compositeAlpha_ )\n    {\n      compositeAlpha = compositeAlpha_;\n      return *this;\n    }\n\n    SwapchainCreateInfoKHR& setPresentMode( PresentModeKHR presentMode_ )\n    {\n      presentMode = presentMode_;\n      return *this;\n    }\n\n    SwapchainCreateInfoKHR& setClipped( Bool32 clipped_ )\n    {\n      clipped = clipped_;\n      return *this;\n    }\n\n    SwapchainCreateInfoKHR& setOldSwapchain( SwapchainKHR oldSwapchain_ )\n    {\n      oldSwapchain = oldSwapchain_;\n      return *this;\n    }\n\n    operator const VkSwapchainCreateInfoKHR&() const\n    {\n      return *reinterpret_cast<const VkSwapchainCreateInfoKHR*>(this);\n    }\n\n    bool operator==( SwapchainCreateInfoKHR const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( surface == rhs.surface )\n          && ( minImageCount == rhs.minImageCount )\n          && ( imageFormat == rhs.imageFormat )\n          && ( imageColorSpace == rhs.imageColorSpace )\n          && ( imageExtent == rhs.imageExtent )\n          && ( imageArrayLayers == rhs.imageArrayLayers )\n          && ( imageUsage == rhs.imageUsage )\n          && ( imageSharingMode == rhs.imageSharingMode )\n          && ( queueFamilyIndexCount == rhs.queueFamilyIndexCount )\n          && ( pQueueFamilyIndices == rhs.pQueueFamilyIndices )\n          && ( preTransform == rhs.preTransform )\n          && ( compositeAlpha == rhs.compositeAlpha )\n          && ( presentMode == rhs.presentMode )\n          && ( clipped == rhs.clipped )\n          && ( oldSwapchain == rhs.oldSwapchain );\n    }\n\n    bool operator!=( SwapchainCreateInfoKHR const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    SwapchainCreateFlagsKHR flags;\n    SurfaceKHR surface;\n    uint32_t minImageCount;\n    Format imageFormat;\n    ColorSpaceKHR imageColorSpace;\n    Extent2D imageExtent;\n    uint32_t imageArrayLayers;\n    ImageUsageFlags imageUsage;\n    SharingMode imageSharingMode;\n    uint32_t queueFamilyIndexCount;\n    const uint32_t* pQueueFamilyIndices;\n    SurfaceTransformFlagBitsKHR preTransform;\n    CompositeAlphaFlagBitsKHR compositeAlpha;\n    PresentModeKHR presentMode;\n    Bool32 clipped;\n    SwapchainKHR oldSwapchain;\n  };\n  static_assert( sizeof( SwapchainCreateInfoKHR ) == sizeof( VkSwapchainCreateInfoKHR ), \"struct and wrapper have different size!\" );\n\n  enum class ViewportCoordinateSwizzleNV\n  {\n    ePositiveX = VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_X_NV,\n    eNegativeX = VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_X_NV,\n    ePositiveY = VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Y_NV,\n    eNegativeY = VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_Y_NV,\n    ePositiveZ = VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Z_NV,\n    eNegativeZ = VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_Z_NV,\n    ePositiveW = VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_W_NV,\n    eNegativeW = VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV\n  };\n\n  struct ViewportSwizzleNV\n  {\n    ViewportSwizzleNV( ViewportCoordinateSwizzleNV x_ = ViewportCoordinateSwizzleNV::ePositiveX, ViewportCoordinateSwizzleNV y_ = ViewportCoordinateSwizzleNV::ePositiveX, ViewportCoordinateSwizzleNV z_ = ViewportCoordinateSwizzleNV::ePositiveX, ViewportCoordinateSwizzleNV w_ = ViewportCoordinateSwizzleNV::ePositiveX )\n      : x( x_ )\n      , y( y_ )\n      , z( z_ )\n      , w( w_ )\n    {\n    }\n\n    ViewportSwizzleNV( VkViewportSwizzleNV const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ViewportSwizzleNV) );\n    }\n\n    ViewportSwizzleNV& operator=( VkViewportSwizzleNV const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(ViewportSwizzleNV) );\n      return *this;\n    }\n\n    ViewportSwizzleNV& setX( ViewportCoordinateSwizzleNV x_ )\n    {\n      x = x_;\n      return *this;\n    }\n\n    ViewportSwizzleNV& setY( ViewportCoordinateSwizzleNV y_ )\n    {\n      y = y_;\n      return *this;\n    }\n\n    ViewportSwizzleNV& setZ( ViewportCoordinateSwizzleNV z_ )\n    {\n      z = z_;\n      return *this;\n    }\n\n    ViewportSwizzleNV& setW( ViewportCoordinateSwizzleNV w_ )\n    {\n      w = w_;\n      return *this;\n    }\n\n    operator const VkViewportSwizzleNV&() const\n    {\n      return *reinterpret_cast<const VkViewportSwizzleNV*>(this);\n    }\n\n    bool operator==( ViewportSwizzleNV const& rhs ) const\n    {\n      return ( x == rhs.x )\n          && ( y == rhs.y )\n          && ( z == rhs.z )\n          && ( w == rhs.w );\n    }\n\n    bool operator!=( ViewportSwizzleNV const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    ViewportCoordinateSwizzleNV x;\n    ViewportCoordinateSwizzleNV y;\n    ViewportCoordinateSwizzleNV z;\n    ViewportCoordinateSwizzleNV w;\n  };\n  static_assert( sizeof( ViewportSwizzleNV ) == sizeof( VkViewportSwizzleNV ), \"struct and wrapper have different size!\" );\n\n  struct PipelineViewportSwizzleStateCreateInfoNV\n  {\n    PipelineViewportSwizzleStateCreateInfoNV( PipelineViewportSwizzleStateCreateFlagsNV flags_ = PipelineViewportSwizzleStateCreateFlagsNV(), uint32_t viewportCount_ = 0, const ViewportSwizzleNV* pViewportSwizzles_ = nullptr )\n      : sType( StructureType::ePipelineViewportSwizzleStateCreateInfoNV )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , viewportCount( viewportCount_ )\n      , pViewportSwizzles( pViewportSwizzles_ )\n    {\n    }\n\n    PipelineViewportSwizzleStateCreateInfoNV( VkPipelineViewportSwizzleStateCreateInfoNV const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PipelineViewportSwizzleStateCreateInfoNV) );\n    }\n\n    PipelineViewportSwizzleStateCreateInfoNV& operator=( VkPipelineViewportSwizzleStateCreateInfoNV const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PipelineViewportSwizzleStateCreateInfoNV) );\n      return *this;\n    }\n\n    PipelineViewportSwizzleStateCreateInfoNV& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    PipelineViewportSwizzleStateCreateInfoNV& setFlags( PipelineViewportSwizzleStateCreateFlagsNV flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    PipelineViewportSwizzleStateCreateInfoNV& setViewportCount( uint32_t viewportCount_ )\n    {\n      viewportCount = viewportCount_;\n      return *this;\n    }\n\n    PipelineViewportSwizzleStateCreateInfoNV& setPViewportSwizzles( const ViewportSwizzleNV* pViewportSwizzles_ )\n    {\n      pViewportSwizzles = pViewportSwizzles_;\n      return *this;\n    }\n\n    operator const VkPipelineViewportSwizzleStateCreateInfoNV&() const\n    {\n      return *reinterpret_cast<const VkPipelineViewportSwizzleStateCreateInfoNV*>(this);\n    }\n\n    bool operator==( PipelineViewportSwizzleStateCreateInfoNV const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( viewportCount == rhs.viewportCount )\n          && ( pViewportSwizzles == rhs.pViewportSwizzles );\n    }\n\n    bool operator!=( PipelineViewportSwizzleStateCreateInfoNV const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    PipelineViewportSwizzleStateCreateFlagsNV flags;\n    uint32_t viewportCount;\n    const ViewportSwizzleNV* pViewportSwizzles;\n  };\n  static_assert( sizeof( PipelineViewportSwizzleStateCreateInfoNV ) == sizeof( VkPipelineViewportSwizzleStateCreateInfoNV ), \"struct and wrapper have different size!\" );\n\n  enum class DiscardRectangleModeEXT\n  {\n    eInclusive = VK_DISCARD_RECTANGLE_MODE_INCLUSIVE_EXT,\n    eExclusive = VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT\n  };\n\n  struct PipelineDiscardRectangleStateCreateInfoEXT\n  {\n    PipelineDiscardRectangleStateCreateInfoEXT( PipelineDiscardRectangleStateCreateFlagsEXT flags_ = PipelineDiscardRectangleStateCreateFlagsEXT(), DiscardRectangleModeEXT discardRectangleMode_ = DiscardRectangleModeEXT::eInclusive, uint32_t discardRectangleCount_ = 0, const Rect2D* pDiscardRectangles_ = nullptr )\n      : sType( StructureType::ePipelineDiscardRectangleStateCreateInfoEXT )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , discardRectangleMode( discardRectangleMode_ )\n      , discardRectangleCount( discardRectangleCount_ )\n      , pDiscardRectangles( pDiscardRectangles_ )\n    {\n    }\n\n    PipelineDiscardRectangleStateCreateInfoEXT( VkPipelineDiscardRectangleStateCreateInfoEXT const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PipelineDiscardRectangleStateCreateInfoEXT) );\n    }\n\n    PipelineDiscardRectangleStateCreateInfoEXT& operator=( VkPipelineDiscardRectangleStateCreateInfoEXT const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(PipelineDiscardRectangleStateCreateInfoEXT) );\n      return *this;\n    }\n\n    PipelineDiscardRectangleStateCreateInfoEXT& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    PipelineDiscardRectangleStateCreateInfoEXT& setFlags( PipelineDiscardRectangleStateCreateFlagsEXT flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    PipelineDiscardRectangleStateCreateInfoEXT& setDiscardRectangleMode( DiscardRectangleModeEXT discardRectangleMode_ )\n    {\n      discardRectangleMode = discardRectangleMode_;\n      return *this;\n    }\n\n    PipelineDiscardRectangleStateCreateInfoEXT& setDiscardRectangleCount( uint32_t discardRectangleCount_ )\n    {\n      discardRectangleCount = discardRectangleCount_;\n      return *this;\n    }\n\n    PipelineDiscardRectangleStateCreateInfoEXT& setPDiscardRectangles( const Rect2D* pDiscardRectangles_ )\n    {\n      pDiscardRectangles = pDiscardRectangles_;\n      return *this;\n    }\n\n    operator const VkPipelineDiscardRectangleStateCreateInfoEXT&() const\n    {\n      return *reinterpret_cast<const VkPipelineDiscardRectangleStateCreateInfoEXT*>(this);\n    }\n\n    bool operator==( PipelineDiscardRectangleStateCreateInfoEXT const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( discardRectangleMode == rhs.discardRectangleMode )\n          && ( discardRectangleCount == rhs.discardRectangleCount )\n          && ( pDiscardRectangles == rhs.pDiscardRectangles );\n    }\n\n    bool operator!=( PipelineDiscardRectangleStateCreateInfoEXT const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    PipelineDiscardRectangleStateCreateFlagsEXT flags;\n    DiscardRectangleModeEXT discardRectangleMode;\n    uint32_t discardRectangleCount;\n    const Rect2D* pDiscardRectangles;\n  };\n  static_assert( sizeof( PipelineDiscardRectangleStateCreateInfoEXT ) == sizeof( VkPipelineDiscardRectangleStateCreateInfoEXT ), \"struct and wrapper have different size!\" );\n\n  enum class SubpassDescriptionFlagBits\n  {\n    ePerViewAttributesNVX = VK_SUBPASS_DESCRIPTION_PER_VIEW_ATTRIBUTES_BIT_NVX,\n    ePerViewPositionXOnlyNVX = VK_SUBPASS_DESCRIPTION_PER_VIEW_POSITION_X_ONLY_BIT_NVX\n  };\n\n  using SubpassDescriptionFlags = Flags<SubpassDescriptionFlagBits, VkSubpassDescriptionFlags>;\n\n  VULKAN_HPP_INLINE SubpassDescriptionFlags operator|( SubpassDescriptionFlagBits bit0, SubpassDescriptionFlagBits bit1 )\n  {\n    return SubpassDescriptionFlags( bit0 ) | bit1;\n  }\n\n  VULKAN_HPP_INLINE SubpassDescriptionFlags operator~( SubpassDescriptionFlagBits bits )\n  {\n    return ~( SubpassDescriptionFlags( bits ) );\n  }\n\n  template <> struct FlagTraits<SubpassDescriptionFlagBits>\n  {\n    enum\n    {\n      allFlags = VkFlags(SubpassDescriptionFlagBits::ePerViewAttributesNVX) | VkFlags(SubpassDescriptionFlagBits::ePerViewPositionXOnlyNVX)\n    };\n  };\n\n  struct SubpassDescription\n  {\n    SubpassDescription( SubpassDescriptionFlags flags_ = SubpassDescriptionFlags(), PipelineBindPoint pipelineBindPoint_ = PipelineBindPoint::eGraphics, uint32_t inputAttachmentCount_ = 0, const AttachmentReference* pInputAttachments_ = nullptr, uint32_t colorAttachmentCount_ = 0, const AttachmentReference* pColorAttachments_ = nullptr, const AttachmentReference* pResolveAttachments_ = nullptr, const AttachmentReference* pDepthStencilAttachment_ = nullptr, uint32_t preserveAttachmentCount_ = 0, const uint32_t* pPreserveAttachments_ = nullptr )\n      : flags( flags_ )\n      , pipelineBindPoint( pipelineBindPoint_ )\n      , inputAttachmentCount( inputAttachmentCount_ )\n      , pInputAttachments( pInputAttachments_ )\n      , colorAttachmentCount( colorAttachmentCount_ )\n      , pColorAttachments( pColorAttachments_ )\n      , pResolveAttachments( pResolveAttachments_ )\n      , pDepthStencilAttachment( pDepthStencilAttachment_ )\n      , preserveAttachmentCount( preserveAttachmentCount_ )\n      , pPreserveAttachments( pPreserveAttachments_ )\n    {\n    }\n\n    SubpassDescription( VkSubpassDescription const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(SubpassDescription) );\n    }\n\n    SubpassDescription& operator=( VkSubpassDescription const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(SubpassDescription) );\n      return *this;\n    }\n\n    SubpassDescription& setFlags( SubpassDescriptionFlags flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    SubpassDescription& setPipelineBindPoint( PipelineBindPoint pipelineBindPoint_ )\n    {\n      pipelineBindPoint = pipelineBindPoint_;\n      return *this;\n    }\n\n    SubpassDescription& setInputAttachmentCount( uint32_t inputAttachmentCount_ )\n    {\n      inputAttachmentCount = inputAttachmentCount_;\n      return *this;\n    }\n\n    SubpassDescription& setPInputAttachments( const AttachmentReference* pInputAttachments_ )\n    {\n      pInputAttachments = pInputAttachments_;\n      return *this;\n    }\n\n    SubpassDescription& setColorAttachmentCount( uint32_t colorAttachmentCount_ )\n    {\n      colorAttachmentCount = colorAttachmentCount_;\n      return *this;\n    }\n\n    SubpassDescription& setPColorAttachments( const AttachmentReference* pColorAttachments_ )\n    {\n      pColorAttachments = pColorAttachments_;\n      return *this;\n    }\n\n    SubpassDescription& setPResolveAttachments( const AttachmentReference* pResolveAttachments_ )\n    {\n      pResolveAttachments = pResolveAttachments_;\n      return *this;\n    }\n\n    SubpassDescription& setPDepthStencilAttachment( const AttachmentReference* pDepthStencilAttachment_ )\n    {\n      pDepthStencilAttachment = pDepthStencilAttachment_;\n      return *this;\n    }\n\n    SubpassDescription& setPreserveAttachmentCount( uint32_t preserveAttachmentCount_ )\n    {\n      preserveAttachmentCount = preserveAttachmentCount_;\n      return *this;\n    }\n\n    SubpassDescription& setPPreserveAttachments( const uint32_t* pPreserveAttachments_ )\n    {\n      pPreserveAttachments = pPreserveAttachments_;\n      return *this;\n    }\n\n    operator const VkSubpassDescription&() const\n    {\n      return *reinterpret_cast<const VkSubpassDescription*>(this);\n    }\n\n    bool operator==( SubpassDescription const& rhs ) const\n    {\n      return ( flags == rhs.flags )\n          && ( pipelineBindPoint == rhs.pipelineBindPoint )\n          && ( inputAttachmentCount == rhs.inputAttachmentCount )\n          && ( pInputAttachments == rhs.pInputAttachments )\n          && ( colorAttachmentCount == rhs.colorAttachmentCount )\n          && ( pColorAttachments == rhs.pColorAttachments )\n          && ( pResolveAttachments == rhs.pResolveAttachments )\n          && ( pDepthStencilAttachment == rhs.pDepthStencilAttachment )\n          && ( preserveAttachmentCount == rhs.preserveAttachmentCount )\n          && ( pPreserveAttachments == rhs.pPreserveAttachments );\n    }\n\n    bool operator!=( SubpassDescription const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n    SubpassDescriptionFlags flags;\n    PipelineBindPoint pipelineBindPoint;\n    uint32_t inputAttachmentCount;\n    const AttachmentReference* pInputAttachments;\n    uint32_t colorAttachmentCount;\n    const AttachmentReference* pColorAttachments;\n    const AttachmentReference* pResolveAttachments;\n    const AttachmentReference* pDepthStencilAttachment;\n    uint32_t preserveAttachmentCount;\n    const uint32_t* pPreserveAttachments;\n  };\n  static_assert( sizeof( SubpassDescription ) == sizeof( VkSubpassDescription ), \"struct and wrapper have different size!\" );\n\n  struct RenderPassCreateInfo\n  {\n    RenderPassCreateInfo( RenderPassCreateFlags flags_ = RenderPassCreateFlags(), uint32_t attachmentCount_ = 0, const AttachmentDescription* pAttachments_ = nullptr, uint32_t subpassCount_ = 0, const SubpassDescription* pSubpasses_ = nullptr, uint32_t dependencyCount_ = 0, const SubpassDependency* pDependencies_ = nullptr )\n      : sType( StructureType::eRenderPassCreateInfo )\n      , pNext( nullptr )\n      , flags( flags_ )\n      , attachmentCount( attachmentCount_ )\n      , pAttachments( pAttachments_ )\n      , subpassCount( subpassCount_ )\n      , pSubpasses( pSubpasses_ )\n      , dependencyCount( dependencyCount_ )\n      , pDependencies( pDependencies_ )\n    {\n    }\n\n    RenderPassCreateInfo( VkRenderPassCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(RenderPassCreateInfo) );\n    }\n\n    RenderPassCreateInfo& operator=( VkRenderPassCreateInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(RenderPassCreateInfo) );\n      return *this;\n    }\n\n    RenderPassCreateInfo& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    RenderPassCreateInfo& setFlags( RenderPassCreateFlags flags_ )\n    {\n      flags = flags_;\n      return *this;\n    }\n\n    RenderPassCreateInfo& setAttachmentCount( uint32_t attachmentCount_ )\n    {\n      attachmentCount = attachmentCount_;\n      return *this;\n    }\n\n    RenderPassCreateInfo& setPAttachments( const AttachmentDescription* pAttachments_ )\n    {\n      pAttachments = pAttachments_;\n      return *this;\n    }\n\n    RenderPassCreateInfo& setSubpassCount( uint32_t subpassCount_ )\n    {\n      subpassCount = subpassCount_;\n      return *this;\n    }\n\n    RenderPassCreateInfo& setPSubpasses( const SubpassDescription* pSubpasses_ )\n    {\n      pSubpasses = pSubpasses_;\n      return *this;\n    }\n\n    RenderPassCreateInfo& setDependencyCount( uint32_t dependencyCount_ )\n    {\n      dependencyCount = dependencyCount_;\n      return *this;\n    }\n\n    RenderPassCreateInfo& setPDependencies( const SubpassDependency* pDependencies_ )\n    {\n      pDependencies = pDependencies_;\n      return *this;\n    }\n\n    operator const VkRenderPassCreateInfo&() const\n    {\n      return *reinterpret_cast<const VkRenderPassCreateInfo*>(this);\n    }\n\n    bool operator==( RenderPassCreateInfo const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( flags == rhs.flags )\n          && ( attachmentCount == rhs.attachmentCount )\n          && ( pAttachments == rhs.pAttachments )\n          && ( subpassCount == rhs.subpassCount )\n          && ( pSubpasses == rhs.pSubpasses )\n          && ( dependencyCount == rhs.dependencyCount )\n          && ( pDependencies == rhs.pDependencies );\n    }\n\n    bool operator!=( RenderPassCreateInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    RenderPassCreateFlags flags;\n    uint32_t attachmentCount;\n    const AttachmentDescription* pAttachments;\n    uint32_t subpassCount;\n    const SubpassDescription* pSubpasses;\n    uint32_t dependencyCount;\n    const SubpassDependency* pDependencies;\n  };\n  static_assert( sizeof( RenderPassCreateInfo ) == sizeof( VkRenderPassCreateInfo ), \"struct and wrapper have different size!\" );\n\n    Result enumerateInstanceLayerProperties( uint32_t* pPropertyCount, LayerProperties* pProperties );\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    template <typename Allocator = std::allocator<LayerProperties>> \n    typename ResultValueType<std::vector<LayerProperties,Allocator>>::type enumerateInstanceLayerProperties();\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result enumerateInstanceLayerProperties( uint32_t* pPropertyCount, LayerProperties* pProperties )\n  {\n    return static_cast<Result>( vkEnumerateInstanceLayerProperties( pPropertyCount, reinterpret_cast<VkLayerProperties*>( pProperties ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  template <typename Allocator> \n  VULKAN_HPP_INLINE typename ResultValueType<std::vector<LayerProperties,Allocator>>::type enumerateInstanceLayerProperties()\n  {\n    std::vector<LayerProperties,Allocator> properties;\n    uint32_t propertyCount;\n    Result result;\n    do\n    {\n      result = static_cast<Result>( vkEnumerateInstanceLayerProperties( &propertyCount, nullptr ) );\n      if ( ( result == Result::eSuccess ) && propertyCount )\n      {\n        properties.resize( propertyCount );\n        result = static_cast<Result>( vkEnumerateInstanceLayerProperties( &propertyCount, reinterpret_cast<VkLayerProperties*>( properties.data() ) ) );\n      }\n    } while ( result == Result::eIncomplete );\n    assert( propertyCount <= properties.size() ); \n    properties.resize( propertyCount ); \n    return createResultValue( result, properties, \"vk::enumerateInstanceLayerProperties\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n\n    Result enumerateInstanceExtensionProperties( const char* pLayerName, uint32_t* pPropertyCount, ExtensionProperties* pProperties );\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    template <typename Allocator = std::allocator<ExtensionProperties>> \n    typename ResultValueType<std::vector<ExtensionProperties,Allocator>>::type enumerateInstanceExtensionProperties( Optional<const std::string> layerName = nullptr );\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result enumerateInstanceExtensionProperties( const char* pLayerName, uint32_t* pPropertyCount, ExtensionProperties* pProperties )\n  {\n    return static_cast<Result>( vkEnumerateInstanceExtensionProperties( pLayerName, pPropertyCount, reinterpret_cast<VkExtensionProperties*>( pProperties ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  template <typename Allocator> \n  VULKAN_HPP_INLINE typename ResultValueType<std::vector<ExtensionProperties,Allocator>>::type enumerateInstanceExtensionProperties( Optional<const std::string> layerName )\n  {\n    std::vector<ExtensionProperties,Allocator> properties;\n    uint32_t propertyCount;\n    Result result;\n    do\n    {\n      result = static_cast<Result>( vkEnumerateInstanceExtensionProperties( layerName ? layerName->c_str() : nullptr, &propertyCount, nullptr ) );\n      if ( ( result == Result::eSuccess ) && propertyCount )\n      {\n        properties.resize( propertyCount );\n        result = static_cast<Result>( vkEnumerateInstanceExtensionProperties( layerName ? layerName->c_str() : nullptr, &propertyCount, reinterpret_cast<VkExtensionProperties*>( properties.data() ) ) );\n      }\n    } while ( result == Result::eIncomplete );\n    assert( propertyCount <= properties.size() ); \n    properties.resize( propertyCount ); \n    return createResultValue( result, properties, \"vk::enumerateInstanceExtensionProperties\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n\n  // forward declarations\n  struct CmdProcessCommandsInfoNVX;\n\n  class CommandBuffer\n  {\n  public:\n    CommandBuffer()\n      : m_commandBuffer(VK_NULL_HANDLE)\n    {}\n\n    CommandBuffer( std::nullptr_t )\n      : m_commandBuffer(VK_NULL_HANDLE)\n    {}\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT CommandBuffer(VkCommandBuffer commandBuffer)\n       : m_commandBuffer(commandBuffer)\n    {}\n\n#if defined(VULKAN_HPP_TYPESAFE_CONVERSION)\n    CommandBuffer& operator=(VkCommandBuffer commandBuffer)\n    {\n      m_commandBuffer = commandBuffer;\n      return *this;\n    }\n#endif\n\n    CommandBuffer& operator=( std::nullptr_t )\n    {\n      m_commandBuffer = VK_NULL_HANDLE;\n      return *this;\n    }\n\n    bool operator==(CommandBuffer const &rhs) const\n    {\n      return m_commandBuffer == rhs.m_commandBuffer;\n    }\n\n    bool operator!=(CommandBuffer const &rhs) const\n    {\n      return m_commandBuffer != rhs.m_commandBuffer;\n    }\n\n    bool operator<(CommandBuffer const &rhs) const\n    {\n      return m_commandBuffer < rhs.m_commandBuffer;\n    }\n\n    Result begin( const CommandBufferBeginInfo* pBeginInfo ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<void>::type begin( const CommandBufferBeginInfo & beginInfo ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifdef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    Result end() const;\n#else\n    ResultValueType<void>::type end() const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifdef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    Result reset( CommandBufferResetFlags flags ) const;\n#else\n    ResultValueType<void>::type reset( CommandBufferResetFlags flags ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void bindPipeline( PipelineBindPoint pipelineBindPoint, Pipeline pipeline ) const;\n\n    void setViewport( uint32_t firstViewport, uint32_t viewportCount, const Viewport* pViewports ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void setViewport( uint32_t firstViewport, ArrayProxy<const Viewport> viewports ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void setScissor( uint32_t firstScissor, uint32_t scissorCount, const Rect2D* pScissors ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void setScissor( uint32_t firstScissor, ArrayProxy<const Rect2D> scissors ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void setLineWidth( float lineWidth ) const;\n\n    void setDepthBias( float depthBiasConstantFactor, float depthBiasClamp, float depthBiasSlopeFactor ) const;\n\n    void setBlendConstants( const float blendConstants[4] ) const;\n\n    void setDepthBounds( float minDepthBounds, float maxDepthBounds ) const;\n\n    void setStencilCompareMask( StencilFaceFlags faceMask, uint32_t compareMask ) const;\n\n    void setStencilWriteMask( StencilFaceFlags faceMask, uint32_t writeMask ) const;\n\n    void setStencilReference( StencilFaceFlags faceMask, uint32_t reference ) const;\n\n    void bindDescriptorSets( PipelineBindPoint pipelineBindPoint, PipelineLayout layout, uint32_t firstSet, uint32_t descriptorSetCount, const DescriptorSet* pDescriptorSets, uint32_t dynamicOffsetCount, const uint32_t* pDynamicOffsets ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void bindDescriptorSets( PipelineBindPoint pipelineBindPoint, PipelineLayout layout, uint32_t firstSet, ArrayProxy<const DescriptorSet> descriptorSets, ArrayProxy<const uint32_t> dynamicOffsets ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void bindIndexBuffer( Buffer buffer, DeviceSize offset, IndexType indexType ) const;\n\n    void bindVertexBuffers( uint32_t firstBinding, uint32_t bindingCount, const Buffer* pBuffers, const DeviceSize* pOffsets ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void bindVertexBuffers( uint32_t firstBinding, ArrayProxy<const Buffer> buffers, ArrayProxy<const DeviceSize> offsets ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void draw( uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance ) const;\n\n    void drawIndexed( uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance ) const;\n\n    void drawIndirect( Buffer buffer, DeviceSize offset, uint32_t drawCount, uint32_t stride ) const;\n\n    void drawIndexedIndirect( Buffer buffer, DeviceSize offset, uint32_t drawCount, uint32_t stride ) const;\n\n    void dispatch( uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ ) const;\n\n    void dispatchIndirect( Buffer buffer, DeviceSize offset ) const;\n\n    void copyBuffer( Buffer srcBuffer, Buffer dstBuffer, uint32_t regionCount, const BufferCopy* pRegions ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void copyBuffer( Buffer srcBuffer, Buffer dstBuffer, ArrayProxy<const BufferCopy> regions ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void copyImage( Image srcImage, ImageLayout srcImageLayout, Image dstImage, ImageLayout dstImageLayout, uint32_t regionCount, const ImageCopy* pRegions ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void copyImage( Image srcImage, ImageLayout srcImageLayout, Image dstImage, ImageLayout dstImageLayout, ArrayProxy<const ImageCopy> regions ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void blitImage( Image srcImage, ImageLayout srcImageLayout, Image dstImage, ImageLayout dstImageLayout, uint32_t regionCount, const ImageBlit* pRegions, Filter filter ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void blitImage( Image srcImage, ImageLayout srcImageLayout, Image dstImage, ImageLayout dstImageLayout, ArrayProxy<const ImageBlit> regions, Filter filter ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void copyBufferToImage( Buffer srcBuffer, Image dstImage, ImageLayout dstImageLayout, uint32_t regionCount, const BufferImageCopy* pRegions ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void copyBufferToImage( Buffer srcBuffer, Image dstImage, ImageLayout dstImageLayout, ArrayProxy<const BufferImageCopy> regions ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void copyImageToBuffer( Image srcImage, ImageLayout srcImageLayout, Buffer dstBuffer, uint32_t regionCount, const BufferImageCopy* pRegions ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void copyImageToBuffer( Image srcImage, ImageLayout srcImageLayout, Buffer dstBuffer, ArrayProxy<const BufferImageCopy> regions ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void updateBuffer( Buffer dstBuffer, DeviceSize dstOffset, DeviceSize dataSize, const void* pData ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    template <typename T>\n    void updateBuffer( Buffer dstBuffer, DeviceSize dstOffset, ArrayProxy<const T> data ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void fillBuffer( Buffer dstBuffer, DeviceSize dstOffset, DeviceSize size, uint32_t data ) const;\n\n    void clearColorImage( Image image, ImageLayout imageLayout, const ClearColorValue* pColor, uint32_t rangeCount, const ImageSubresourceRange* pRanges ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void clearColorImage( Image image, ImageLayout imageLayout, const ClearColorValue & color, ArrayProxy<const ImageSubresourceRange> ranges ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void clearDepthStencilImage( Image image, ImageLayout imageLayout, const ClearDepthStencilValue* pDepthStencil, uint32_t rangeCount, const ImageSubresourceRange* pRanges ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void clearDepthStencilImage( Image image, ImageLayout imageLayout, const ClearDepthStencilValue & depthStencil, ArrayProxy<const ImageSubresourceRange> ranges ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void clearAttachments( uint32_t attachmentCount, const ClearAttachment* pAttachments, uint32_t rectCount, const ClearRect* pRects ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void clearAttachments( ArrayProxy<const ClearAttachment> attachments, ArrayProxy<const ClearRect> rects ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void resolveImage( Image srcImage, ImageLayout srcImageLayout, Image dstImage, ImageLayout dstImageLayout, uint32_t regionCount, const ImageResolve* pRegions ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void resolveImage( Image srcImage, ImageLayout srcImageLayout, Image dstImage, ImageLayout dstImageLayout, ArrayProxy<const ImageResolve> regions ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void setEvent( Event event, PipelineStageFlags stageMask ) const;\n\n    void resetEvent( Event event, PipelineStageFlags stageMask ) const;\n\n    void waitEvents( uint32_t eventCount, const Event* pEvents, PipelineStageFlags srcStageMask, PipelineStageFlags dstStageMask, uint32_t memoryBarrierCount, const MemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const BufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const ImageMemoryBarrier* pImageMemoryBarriers ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void waitEvents( ArrayProxy<const Event> events, PipelineStageFlags srcStageMask, PipelineStageFlags dstStageMask, ArrayProxy<const MemoryBarrier> memoryBarriers, ArrayProxy<const BufferMemoryBarrier> bufferMemoryBarriers, ArrayProxy<const ImageMemoryBarrier> imageMemoryBarriers ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void pipelineBarrier( PipelineStageFlags srcStageMask, PipelineStageFlags dstStageMask, DependencyFlags dependencyFlags, uint32_t memoryBarrierCount, const MemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const BufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const ImageMemoryBarrier* pImageMemoryBarriers ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void pipelineBarrier( PipelineStageFlags srcStageMask, PipelineStageFlags dstStageMask, DependencyFlags dependencyFlags, ArrayProxy<const MemoryBarrier> memoryBarriers, ArrayProxy<const BufferMemoryBarrier> bufferMemoryBarriers, ArrayProxy<const ImageMemoryBarrier> imageMemoryBarriers ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void beginQuery( QueryPool queryPool, uint32_t query, QueryControlFlags flags ) const;\n\n    void endQuery( QueryPool queryPool, uint32_t query ) const;\n\n    void resetQueryPool( QueryPool queryPool, uint32_t firstQuery, uint32_t queryCount ) const;\n\n    void writeTimestamp( PipelineStageFlagBits pipelineStage, QueryPool queryPool, uint32_t query ) const;\n\n    void copyQueryPoolResults( QueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, Buffer dstBuffer, DeviceSize dstOffset, DeviceSize stride, QueryResultFlags flags ) const;\n\n    void pushConstants( PipelineLayout layout, ShaderStageFlags stageFlags, uint32_t offset, uint32_t size, const void* pValues ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    template <typename T>\n    void pushConstants( PipelineLayout layout, ShaderStageFlags stageFlags, uint32_t offset, ArrayProxy<const T> values ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void beginRenderPass( const RenderPassBeginInfo* pRenderPassBegin, SubpassContents contents ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void beginRenderPass( const RenderPassBeginInfo & renderPassBegin, SubpassContents contents ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void nextSubpass( SubpassContents contents ) const;\n\n    void endRenderPass() const;\n\n    void executeCommands( uint32_t commandBufferCount, const CommandBuffer* pCommandBuffers ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void executeCommands( ArrayProxy<const CommandBuffer> commandBuffers ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void debugMarkerBeginEXT( DebugMarkerMarkerInfoEXT* pMarkerInfo ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    DebugMarkerMarkerInfoEXT debugMarkerBeginEXT() const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void debugMarkerEndEXT() const;\n\n    void debugMarkerInsertEXT( DebugMarkerMarkerInfoEXT* pMarkerInfo ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    DebugMarkerMarkerInfoEXT debugMarkerInsertEXT() const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void drawIndirectCountAMD( Buffer buffer, DeviceSize offset, Buffer countBuffer, DeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride ) const;\n\n    void drawIndexedIndirectCountAMD( Buffer buffer, DeviceSize offset, Buffer countBuffer, DeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride ) const;\n\n    void processCommandsNVX( const CmdProcessCommandsInfoNVX* pProcessCommandsInfo ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void processCommandsNVX( const CmdProcessCommandsInfoNVX & processCommandsInfo ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void reserveSpaceForCommandsNVX( const CmdReserveSpaceForCommandsInfoNVX* pReserveSpaceInfo ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void reserveSpaceForCommandsNVX( const CmdReserveSpaceForCommandsInfoNVX & reserveSpaceInfo ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void pushDescriptorSetKHR( PipelineBindPoint pipelineBindPoint, PipelineLayout layout, uint32_t set, uint32_t descriptorWriteCount, const WriteDescriptorSet* pDescriptorWrites ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void pushDescriptorSetKHR( PipelineBindPoint pipelineBindPoint, PipelineLayout layout, uint32_t set, ArrayProxy<const WriteDescriptorSet> descriptorWrites ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void setDeviceMaskKHX( uint32_t deviceMask ) const;\n\n    void dispatchBaseKHX( uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ ) const;\n\n    void pushDescriptorSetWithTemplateKHR( DescriptorUpdateTemplateKHR descriptorUpdateTemplate, PipelineLayout layout, uint32_t set, const void* pData ) const;\n\n    void setViewportWScalingNV( uint32_t firstViewport, uint32_t viewportCount, const ViewportWScalingNV* pViewportWScalings ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void setViewportWScalingNV( uint32_t firstViewport, ArrayProxy<const ViewportWScalingNV> viewportWScalings ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void setDiscardRectangleEXT( uint32_t firstDiscardRectangle, uint32_t discardRectangleCount, const Rect2D* pDiscardRectangles ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void setDiscardRectangleEXT( uint32_t firstDiscardRectangle, ArrayProxy<const Rect2D> discardRectangles ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT operator VkCommandBuffer() const\n    {\n      return m_commandBuffer;\n    }\n\n    explicit operator bool() const\n    {\n      return m_commandBuffer != VK_NULL_HANDLE;\n    }\n\n    bool operator!() const\n    {\n      return m_commandBuffer == VK_NULL_HANDLE;\n    }\n\n  private:\n    VkCommandBuffer m_commandBuffer;\n  };\n  static_assert( sizeof( CommandBuffer ) == sizeof( VkCommandBuffer ), \"handle and wrapper have different size!\" );\n\n  VULKAN_HPP_INLINE Result CommandBuffer::begin( const CommandBufferBeginInfo* pBeginInfo ) const\n  {\n    return static_cast<Result>( vkBeginCommandBuffer( m_commandBuffer, reinterpret_cast<const VkCommandBufferBeginInfo*>( pBeginInfo ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<void>::type CommandBuffer::begin( const CommandBufferBeginInfo & beginInfo ) const\n  {\n    Result result = static_cast<Result>( vkBeginCommandBuffer( m_commandBuffer, reinterpret_cast<const VkCommandBufferBeginInfo*>( &beginInfo ) ) );\n    return createResultValue( result, \"vk::CommandBuffer::begin\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifdef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE Result CommandBuffer::end() const\n  {\n    return static_cast<Result>( vkEndCommandBuffer( m_commandBuffer ) );\n  }\n#else\n  VULKAN_HPP_INLINE ResultValueType<void>::type CommandBuffer::end() const\n  {\n    Result result = static_cast<Result>( vkEndCommandBuffer( m_commandBuffer ) );\n    return createResultValue( result, \"vk::CommandBuffer::end\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifdef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE Result CommandBuffer::reset( CommandBufferResetFlags flags ) const\n  {\n    return static_cast<Result>( vkResetCommandBuffer( m_commandBuffer, static_cast<VkCommandBufferResetFlags>( flags ) ) );\n  }\n#else\n  VULKAN_HPP_INLINE ResultValueType<void>::type CommandBuffer::reset( CommandBufferResetFlags flags ) const\n  {\n    Result result = static_cast<Result>( vkResetCommandBuffer( m_commandBuffer, static_cast<VkCommandBufferResetFlags>( flags ) ) );\n    return createResultValue( result, \"vk::CommandBuffer::reset\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void CommandBuffer::bindPipeline( PipelineBindPoint pipelineBindPoint, Pipeline pipeline ) const\n  {\n    vkCmdBindPipeline( m_commandBuffer, static_cast<VkPipelineBindPoint>( pipelineBindPoint ), static_cast<VkPipeline>( pipeline ) );\n  }\n\n  VULKAN_HPP_INLINE void CommandBuffer::setViewport( uint32_t firstViewport, uint32_t viewportCount, const Viewport* pViewports ) const\n  {\n    vkCmdSetViewport( m_commandBuffer, firstViewport, viewportCount, reinterpret_cast<const VkViewport*>( pViewports ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void CommandBuffer::setViewport( uint32_t firstViewport, ArrayProxy<const Viewport> viewports ) const\n  {\n    vkCmdSetViewport( m_commandBuffer, firstViewport, viewports.size() , reinterpret_cast<const VkViewport*>( viewports.data() ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void CommandBuffer::setScissor( uint32_t firstScissor, uint32_t scissorCount, const Rect2D* pScissors ) const\n  {\n    vkCmdSetScissor( m_commandBuffer, firstScissor, scissorCount, reinterpret_cast<const VkRect2D*>( pScissors ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void CommandBuffer::setScissor( uint32_t firstScissor, ArrayProxy<const Rect2D> scissors ) const\n  {\n    vkCmdSetScissor( m_commandBuffer, firstScissor, scissors.size() , reinterpret_cast<const VkRect2D*>( scissors.data() ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void CommandBuffer::setLineWidth( float lineWidth ) const\n  {\n    vkCmdSetLineWidth( m_commandBuffer, lineWidth );\n  }\n\n  VULKAN_HPP_INLINE void CommandBuffer::setDepthBias( float depthBiasConstantFactor, float depthBiasClamp, float depthBiasSlopeFactor ) const\n  {\n    vkCmdSetDepthBias( m_commandBuffer, depthBiasConstantFactor, depthBiasClamp, depthBiasSlopeFactor );\n  }\n\n  VULKAN_HPP_INLINE void CommandBuffer::setBlendConstants( const float blendConstants[4] ) const\n  {\n    vkCmdSetBlendConstants( m_commandBuffer, blendConstants );\n  }\n\n  VULKAN_HPP_INLINE void CommandBuffer::setDepthBounds( float minDepthBounds, float maxDepthBounds ) const\n  {\n    vkCmdSetDepthBounds( m_commandBuffer, minDepthBounds, maxDepthBounds );\n  }\n\n  VULKAN_HPP_INLINE void CommandBuffer::setStencilCompareMask( StencilFaceFlags faceMask, uint32_t compareMask ) const\n  {\n    vkCmdSetStencilCompareMask( m_commandBuffer, static_cast<VkStencilFaceFlags>( faceMask ), compareMask );\n  }\n\n  VULKAN_HPP_INLINE void CommandBuffer::setStencilWriteMask( StencilFaceFlags faceMask, uint32_t writeMask ) const\n  {\n    vkCmdSetStencilWriteMask( m_commandBuffer, static_cast<VkStencilFaceFlags>( faceMask ), writeMask );\n  }\n\n  VULKAN_HPP_INLINE void CommandBuffer::setStencilReference( StencilFaceFlags faceMask, uint32_t reference ) const\n  {\n    vkCmdSetStencilReference( m_commandBuffer, static_cast<VkStencilFaceFlags>( faceMask ), reference );\n  }\n\n  VULKAN_HPP_INLINE void CommandBuffer::bindDescriptorSets( PipelineBindPoint pipelineBindPoint, PipelineLayout layout, uint32_t firstSet, uint32_t descriptorSetCount, const DescriptorSet* pDescriptorSets, uint32_t dynamicOffsetCount, const uint32_t* pDynamicOffsets ) const\n  {\n    vkCmdBindDescriptorSets( m_commandBuffer, static_cast<VkPipelineBindPoint>( pipelineBindPoint ), static_cast<VkPipelineLayout>( layout ), firstSet, descriptorSetCount, reinterpret_cast<const VkDescriptorSet*>( pDescriptorSets ), dynamicOffsetCount, pDynamicOffsets );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void CommandBuffer::bindDescriptorSets( PipelineBindPoint pipelineBindPoint, PipelineLayout layout, uint32_t firstSet, ArrayProxy<const DescriptorSet> descriptorSets, ArrayProxy<const uint32_t> dynamicOffsets ) const\n  {\n    vkCmdBindDescriptorSets( m_commandBuffer, static_cast<VkPipelineBindPoint>( pipelineBindPoint ), static_cast<VkPipelineLayout>( layout ), firstSet, descriptorSets.size() , reinterpret_cast<const VkDescriptorSet*>( descriptorSets.data() ), dynamicOffsets.size() , dynamicOffsets.data() );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void CommandBuffer::bindIndexBuffer( Buffer buffer, DeviceSize offset, IndexType indexType ) const\n  {\n    vkCmdBindIndexBuffer( m_commandBuffer, static_cast<VkBuffer>( buffer ), offset, static_cast<VkIndexType>( indexType ) );\n  }\n\n  VULKAN_HPP_INLINE void CommandBuffer::bindVertexBuffers( uint32_t firstBinding, uint32_t bindingCount, const Buffer* pBuffers, const DeviceSize* pOffsets ) const\n  {\n    vkCmdBindVertexBuffers( m_commandBuffer, firstBinding, bindingCount, reinterpret_cast<const VkBuffer*>( pBuffers ), pOffsets );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void CommandBuffer::bindVertexBuffers( uint32_t firstBinding, ArrayProxy<const Buffer> buffers, ArrayProxy<const DeviceSize> offsets ) const\n  {\n#ifdef VULKAN_HPP_NO_EXCEPTIONS\n    assert( buffers.size() == offsets.size() );\n#else\n    if ( buffers.size() != offsets.size() )\n    {\n      throw std::logic_error( \"vk::CommandBuffer::bindVertexBuffers: buffers.size() != offsets.size()\" );\n    }\n#endif  // VULKAN_HPP_NO_EXCEPTIONS\n    vkCmdBindVertexBuffers( m_commandBuffer, firstBinding, buffers.size() , reinterpret_cast<const VkBuffer*>( buffers.data() ), offsets.data() );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void CommandBuffer::draw( uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance ) const\n  {\n    vkCmdDraw( m_commandBuffer, vertexCount, instanceCount, firstVertex, firstInstance );\n  }\n\n  VULKAN_HPP_INLINE void CommandBuffer::drawIndexed( uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance ) const\n  {\n    vkCmdDrawIndexed( m_commandBuffer, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance );\n  }\n\n  VULKAN_HPP_INLINE void CommandBuffer::drawIndirect( Buffer buffer, DeviceSize offset, uint32_t drawCount, uint32_t stride ) const\n  {\n    vkCmdDrawIndirect( m_commandBuffer, static_cast<VkBuffer>( buffer ), offset, drawCount, stride );\n  }\n\n  VULKAN_HPP_INLINE void CommandBuffer::drawIndexedIndirect( Buffer buffer, DeviceSize offset, uint32_t drawCount, uint32_t stride ) const\n  {\n    vkCmdDrawIndexedIndirect( m_commandBuffer, static_cast<VkBuffer>( buffer ), offset, drawCount, stride );\n  }\n\n  VULKAN_HPP_INLINE void CommandBuffer::dispatch( uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ ) const\n  {\n    vkCmdDispatch( m_commandBuffer, groupCountX, groupCountY, groupCountZ );\n  }\n\n  VULKAN_HPP_INLINE void CommandBuffer::dispatchIndirect( Buffer buffer, DeviceSize offset ) const\n  {\n    vkCmdDispatchIndirect( m_commandBuffer, static_cast<VkBuffer>( buffer ), offset );\n  }\n\n  VULKAN_HPP_INLINE void CommandBuffer::copyBuffer( Buffer srcBuffer, Buffer dstBuffer, uint32_t regionCount, const BufferCopy* pRegions ) const\n  {\n    vkCmdCopyBuffer( m_commandBuffer, static_cast<VkBuffer>( srcBuffer ), static_cast<VkBuffer>( dstBuffer ), regionCount, reinterpret_cast<const VkBufferCopy*>( pRegions ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void CommandBuffer::copyBuffer( Buffer srcBuffer, Buffer dstBuffer, ArrayProxy<const BufferCopy> regions ) const\n  {\n    vkCmdCopyBuffer( m_commandBuffer, static_cast<VkBuffer>( srcBuffer ), static_cast<VkBuffer>( dstBuffer ), regions.size() , reinterpret_cast<const VkBufferCopy*>( regions.data() ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void CommandBuffer::copyImage( Image srcImage, ImageLayout srcImageLayout, Image dstImage, ImageLayout dstImageLayout, uint32_t regionCount, const ImageCopy* pRegions ) const\n  {\n    vkCmdCopyImage( m_commandBuffer, static_cast<VkImage>( srcImage ), static_cast<VkImageLayout>( srcImageLayout ), static_cast<VkImage>( dstImage ), static_cast<VkImageLayout>( dstImageLayout ), regionCount, reinterpret_cast<const VkImageCopy*>( pRegions ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void CommandBuffer::copyImage( Image srcImage, ImageLayout srcImageLayout, Image dstImage, ImageLayout dstImageLayout, ArrayProxy<const ImageCopy> regions ) const\n  {\n    vkCmdCopyImage( m_commandBuffer, static_cast<VkImage>( srcImage ), static_cast<VkImageLayout>( srcImageLayout ), static_cast<VkImage>( dstImage ), static_cast<VkImageLayout>( dstImageLayout ), regions.size() , reinterpret_cast<const VkImageCopy*>( regions.data() ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void CommandBuffer::blitImage( Image srcImage, ImageLayout srcImageLayout, Image dstImage, ImageLayout dstImageLayout, uint32_t regionCount, const ImageBlit* pRegions, Filter filter ) const\n  {\n    vkCmdBlitImage( m_commandBuffer, static_cast<VkImage>( srcImage ), static_cast<VkImageLayout>( srcImageLayout ), static_cast<VkImage>( dstImage ), static_cast<VkImageLayout>( dstImageLayout ), regionCount, reinterpret_cast<const VkImageBlit*>( pRegions ), static_cast<VkFilter>( filter ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void CommandBuffer::blitImage( Image srcImage, ImageLayout srcImageLayout, Image dstImage, ImageLayout dstImageLayout, ArrayProxy<const ImageBlit> regions, Filter filter ) const\n  {\n    vkCmdBlitImage( m_commandBuffer, static_cast<VkImage>( srcImage ), static_cast<VkImageLayout>( srcImageLayout ), static_cast<VkImage>( dstImage ), static_cast<VkImageLayout>( dstImageLayout ), regions.size() , reinterpret_cast<const VkImageBlit*>( regions.data() ), static_cast<VkFilter>( filter ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void CommandBuffer::copyBufferToImage( Buffer srcBuffer, Image dstImage, ImageLayout dstImageLayout, uint32_t regionCount, const BufferImageCopy* pRegions ) const\n  {\n    vkCmdCopyBufferToImage( m_commandBuffer, static_cast<VkBuffer>( srcBuffer ), static_cast<VkImage>( dstImage ), static_cast<VkImageLayout>( dstImageLayout ), regionCount, reinterpret_cast<const VkBufferImageCopy*>( pRegions ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void CommandBuffer::copyBufferToImage( Buffer srcBuffer, Image dstImage, ImageLayout dstImageLayout, ArrayProxy<const BufferImageCopy> regions ) const\n  {\n    vkCmdCopyBufferToImage( m_commandBuffer, static_cast<VkBuffer>( srcBuffer ), static_cast<VkImage>( dstImage ), static_cast<VkImageLayout>( dstImageLayout ), regions.size() , reinterpret_cast<const VkBufferImageCopy*>( regions.data() ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void CommandBuffer::copyImageToBuffer( Image srcImage, ImageLayout srcImageLayout, Buffer dstBuffer, uint32_t regionCount, const BufferImageCopy* pRegions ) const\n  {\n    vkCmdCopyImageToBuffer( m_commandBuffer, static_cast<VkImage>( srcImage ), static_cast<VkImageLayout>( srcImageLayout ), static_cast<VkBuffer>( dstBuffer ), regionCount, reinterpret_cast<const VkBufferImageCopy*>( pRegions ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void CommandBuffer::copyImageToBuffer( Image srcImage, ImageLayout srcImageLayout, Buffer dstBuffer, ArrayProxy<const BufferImageCopy> regions ) const\n  {\n    vkCmdCopyImageToBuffer( m_commandBuffer, static_cast<VkImage>( srcImage ), static_cast<VkImageLayout>( srcImageLayout ), static_cast<VkBuffer>( dstBuffer ), regions.size() , reinterpret_cast<const VkBufferImageCopy*>( regions.data() ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void CommandBuffer::updateBuffer( Buffer dstBuffer, DeviceSize dstOffset, DeviceSize dataSize, const void* pData ) const\n  {\n    vkCmdUpdateBuffer( m_commandBuffer, static_cast<VkBuffer>( dstBuffer ), dstOffset, dataSize, pData );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  template <typename T>\n  VULKAN_HPP_INLINE void CommandBuffer::updateBuffer( Buffer dstBuffer, DeviceSize dstOffset, ArrayProxy<const T> data ) const\n  {\n    vkCmdUpdateBuffer( m_commandBuffer, static_cast<VkBuffer>( dstBuffer ), dstOffset, data.size() * sizeof( T ) , reinterpret_cast<const void*>( data.data() ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void CommandBuffer::fillBuffer( Buffer dstBuffer, DeviceSize dstOffset, DeviceSize size, uint32_t data ) const\n  {\n    vkCmdFillBuffer( m_commandBuffer, static_cast<VkBuffer>( dstBuffer ), dstOffset, size, data );\n  }\n\n  VULKAN_HPP_INLINE void CommandBuffer::clearColorImage( Image image, ImageLayout imageLayout, const ClearColorValue* pColor, uint32_t rangeCount, const ImageSubresourceRange* pRanges ) const\n  {\n    vkCmdClearColorImage( m_commandBuffer, static_cast<VkImage>( image ), static_cast<VkImageLayout>( imageLayout ), reinterpret_cast<const VkClearColorValue*>( pColor ), rangeCount, reinterpret_cast<const VkImageSubresourceRange*>( pRanges ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void CommandBuffer::clearColorImage( Image image, ImageLayout imageLayout, const ClearColorValue & color, ArrayProxy<const ImageSubresourceRange> ranges ) const\n  {\n    vkCmdClearColorImage( m_commandBuffer, static_cast<VkImage>( image ), static_cast<VkImageLayout>( imageLayout ), reinterpret_cast<const VkClearColorValue*>( &color ), ranges.size() , reinterpret_cast<const VkImageSubresourceRange*>( ranges.data() ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void CommandBuffer::clearDepthStencilImage( Image image, ImageLayout imageLayout, const ClearDepthStencilValue* pDepthStencil, uint32_t rangeCount, const ImageSubresourceRange* pRanges ) const\n  {\n    vkCmdClearDepthStencilImage( m_commandBuffer, static_cast<VkImage>( image ), static_cast<VkImageLayout>( imageLayout ), reinterpret_cast<const VkClearDepthStencilValue*>( pDepthStencil ), rangeCount, reinterpret_cast<const VkImageSubresourceRange*>( pRanges ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void CommandBuffer::clearDepthStencilImage( Image image, ImageLayout imageLayout, const ClearDepthStencilValue & depthStencil, ArrayProxy<const ImageSubresourceRange> ranges ) const\n  {\n    vkCmdClearDepthStencilImage( m_commandBuffer, static_cast<VkImage>( image ), static_cast<VkImageLayout>( imageLayout ), reinterpret_cast<const VkClearDepthStencilValue*>( &depthStencil ), ranges.size() , reinterpret_cast<const VkImageSubresourceRange*>( ranges.data() ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void CommandBuffer::clearAttachments( uint32_t attachmentCount, const ClearAttachment* pAttachments, uint32_t rectCount, const ClearRect* pRects ) const\n  {\n    vkCmdClearAttachments( m_commandBuffer, attachmentCount, reinterpret_cast<const VkClearAttachment*>( pAttachments ), rectCount, reinterpret_cast<const VkClearRect*>( pRects ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void CommandBuffer::clearAttachments( ArrayProxy<const ClearAttachment> attachments, ArrayProxy<const ClearRect> rects ) const\n  {\n    vkCmdClearAttachments( m_commandBuffer, attachments.size() , reinterpret_cast<const VkClearAttachment*>( attachments.data() ), rects.size() , reinterpret_cast<const VkClearRect*>( rects.data() ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void CommandBuffer::resolveImage( Image srcImage, ImageLayout srcImageLayout, Image dstImage, ImageLayout dstImageLayout, uint32_t regionCount, const ImageResolve* pRegions ) const\n  {\n    vkCmdResolveImage( m_commandBuffer, static_cast<VkImage>( srcImage ), static_cast<VkImageLayout>( srcImageLayout ), static_cast<VkImage>( dstImage ), static_cast<VkImageLayout>( dstImageLayout ), regionCount, reinterpret_cast<const VkImageResolve*>( pRegions ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void CommandBuffer::resolveImage( Image srcImage, ImageLayout srcImageLayout, Image dstImage, ImageLayout dstImageLayout, ArrayProxy<const ImageResolve> regions ) const\n  {\n    vkCmdResolveImage( m_commandBuffer, static_cast<VkImage>( srcImage ), static_cast<VkImageLayout>( srcImageLayout ), static_cast<VkImage>( dstImage ), static_cast<VkImageLayout>( dstImageLayout ), regions.size() , reinterpret_cast<const VkImageResolve*>( regions.data() ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void CommandBuffer::setEvent( Event event, PipelineStageFlags stageMask ) const\n  {\n    vkCmdSetEvent( m_commandBuffer, static_cast<VkEvent>( event ), static_cast<VkPipelineStageFlags>( stageMask ) );\n  }\n\n  VULKAN_HPP_INLINE void CommandBuffer::resetEvent( Event event, PipelineStageFlags stageMask ) const\n  {\n    vkCmdResetEvent( m_commandBuffer, static_cast<VkEvent>( event ), static_cast<VkPipelineStageFlags>( stageMask ) );\n  }\n\n  VULKAN_HPP_INLINE void CommandBuffer::waitEvents( uint32_t eventCount, const Event* pEvents, PipelineStageFlags srcStageMask, PipelineStageFlags dstStageMask, uint32_t memoryBarrierCount, const MemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const BufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const ImageMemoryBarrier* pImageMemoryBarriers ) const\n  {\n    vkCmdWaitEvents( m_commandBuffer, eventCount, reinterpret_cast<const VkEvent*>( pEvents ), static_cast<VkPipelineStageFlags>( srcStageMask ), static_cast<VkPipelineStageFlags>( dstStageMask ), memoryBarrierCount, reinterpret_cast<const VkMemoryBarrier*>( pMemoryBarriers ), bufferMemoryBarrierCount, reinterpret_cast<const VkBufferMemoryBarrier*>( pBufferMemoryBarriers ), imageMemoryBarrierCount, reinterpret_cast<const VkImageMemoryBarrier*>( pImageMemoryBarriers ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void CommandBuffer::waitEvents( ArrayProxy<const Event> events, PipelineStageFlags srcStageMask, PipelineStageFlags dstStageMask, ArrayProxy<const MemoryBarrier> memoryBarriers, ArrayProxy<const BufferMemoryBarrier> bufferMemoryBarriers, ArrayProxy<const ImageMemoryBarrier> imageMemoryBarriers ) const\n  {\n    vkCmdWaitEvents( m_commandBuffer, events.size() , reinterpret_cast<const VkEvent*>( events.data() ), static_cast<VkPipelineStageFlags>( srcStageMask ), static_cast<VkPipelineStageFlags>( dstStageMask ), memoryBarriers.size() , reinterpret_cast<const VkMemoryBarrier*>( memoryBarriers.data() ), bufferMemoryBarriers.size() , reinterpret_cast<const VkBufferMemoryBarrier*>( bufferMemoryBarriers.data() ), imageMemoryBarriers.size() , reinterpret_cast<const VkImageMemoryBarrier*>( imageMemoryBarriers.data() ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void CommandBuffer::pipelineBarrier( PipelineStageFlags srcStageMask, PipelineStageFlags dstStageMask, DependencyFlags dependencyFlags, uint32_t memoryBarrierCount, const MemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const BufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const ImageMemoryBarrier* pImageMemoryBarriers ) const\n  {\n    vkCmdPipelineBarrier( m_commandBuffer, static_cast<VkPipelineStageFlags>( srcStageMask ), static_cast<VkPipelineStageFlags>( dstStageMask ), static_cast<VkDependencyFlags>( dependencyFlags ), memoryBarrierCount, reinterpret_cast<const VkMemoryBarrier*>( pMemoryBarriers ), bufferMemoryBarrierCount, reinterpret_cast<const VkBufferMemoryBarrier*>( pBufferMemoryBarriers ), imageMemoryBarrierCount, reinterpret_cast<const VkImageMemoryBarrier*>( pImageMemoryBarriers ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void CommandBuffer::pipelineBarrier( PipelineStageFlags srcStageMask, PipelineStageFlags dstStageMask, DependencyFlags dependencyFlags, ArrayProxy<const MemoryBarrier> memoryBarriers, ArrayProxy<const BufferMemoryBarrier> bufferMemoryBarriers, ArrayProxy<const ImageMemoryBarrier> imageMemoryBarriers ) const\n  {\n    vkCmdPipelineBarrier( m_commandBuffer, static_cast<VkPipelineStageFlags>( srcStageMask ), static_cast<VkPipelineStageFlags>( dstStageMask ), static_cast<VkDependencyFlags>( dependencyFlags ), memoryBarriers.size() , reinterpret_cast<const VkMemoryBarrier*>( memoryBarriers.data() ), bufferMemoryBarriers.size() , reinterpret_cast<const VkBufferMemoryBarrier*>( bufferMemoryBarriers.data() ), imageMemoryBarriers.size() , reinterpret_cast<const VkImageMemoryBarrier*>( imageMemoryBarriers.data() ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void CommandBuffer::beginQuery( QueryPool queryPool, uint32_t query, QueryControlFlags flags ) const\n  {\n    vkCmdBeginQuery( m_commandBuffer, static_cast<VkQueryPool>( queryPool ), query, static_cast<VkQueryControlFlags>( flags ) );\n  }\n\n  VULKAN_HPP_INLINE void CommandBuffer::endQuery( QueryPool queryPool, uint32_t query ) const\n  {\n    vkCmdEndQuery( m_commandBuffer, static_cast<VkQueryPool>( queryPool ), query );\n  }\n\n  VULKAN_HPP_INLINE void CommandBuffer::resetQueryPool( QueryPool queryPool, uint32_t firstQuery, uint32_t queryCount ) const\n  {\n    vkCmdResetQueryPool( m_commandBuffer, static_cast<VkQueryPool>( queryPool ), firstQuery, queryCount );\n  }\n\n  VULKAN_HPP_INLINE void CommandBuffer::writeTimestamp( PipelineStageFlagBits pipelineStage, QueryPool queryPool, uint32_t query ) const\n  {\n    vkCmdWriteTimestamp( m_commandBuffer, static_cast<VkPipelineStageFlagBits>( pipelineStage ), static_cast<VkQueryPool>( queryPool ), query );\n  }\n\n  VULKAN_HPP_INLINE void CommandBuffer::copyQueryPoolResults( QueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, Buffer dstBuffer, DeviceSize dstOffset, DeviceSize stride, QueryResultFlags flags ) const\n  {\n    vkCmdCopyQueryPoolResults( m_commandBuffer, static_cast<VkQueryPool>( queryPool ), firstQuery, queryCount, static_cast<VkBuffer>( dstBuffer ), dstOffset, stride, static_cast<VkQueryResultFlags>( flags ) );\n  }\n\n  VULKAN_HPP_INLINE void CommandBuffer::pushConstants( PipelineLayout layout, ShaderStageFlags stageFlags, uint32_t offset, uint32_t size, const void* pValues ) const\n  {\n    vkCmdPushConstants( m_commandBuffer, static_cast<VkPipelineLayout>( layout ), static_cast<VkShaderStageFlags>( stageFlags ), offset, size, pValues );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  template <typename T>\n  VULKAN_HPP_INLINE void CommandBuffer::pushConstants( PipelineLayout layout, ShaderStageFlags stageFlags, uint32_t offset, ArrayProxy<const T> values ) const\n  {\n    vkCmdPushConstants( m_commandBuffer, static_cast<VkPipelineLayout>( layout ), static_cast<VkShaderStageFlags>( stageFlags ), offset, values.size() * sizeof( T ) , reinterpret_cast<const void*>( values.data() ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void CommandBuffer::beginRenderPass( const RenderPassBeginInfo* pRenderPassBegin, SubpassContents contents ) const\n  {\n    vkCmdBeginRenderPass( m_commandBuffer, reinterpret_cast<const VkRenderPassBeginInfo*>( pRenderPassBegin ), static_cast<VkSubpassContents>( contents ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void CommandBuffer::beginRenderPass( const RenderPassBeginInfo & renderPassBegin, SubpassContents contents ) const\n  {\n    vkCmdBeginRenderPass( m_commandBuffer, reinterpret_cast<const VkRenderPassBeginInfo*>( &renderPassBegin ), static_cast<VkSubpassContents>( contents ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void CommandBuffer::nextSubpass( SubpassContents contents ) const\n  {\n    vkCmdNextSubpass( m_commandBuffer, static_cast<VkSubpassContents>( contents ) );\n  }\n\n  VULKAN_HPP_INLINE void CommandBuffer::endRenderPass() const\n  {\n    vkCmdEndRenderPass( m_commandBuffer );\n  }\n\n  VULKAN_HPP_INLINE void CommandBuffer::executeCommands( uint32_t commandBufferCount, const CommandBuffer* pCommandBuffers ) const\n  {\n    vkCmdExecuteCommands( m_commandBuffer, commandBufferCount, reinterpret_cast<const VkCommandBuffer*>( pCommandBuffers ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void CommandBuffer::executeCommands( ArrayProxy<const CommandBuffer> commandBuffers ) const\n  {\n    vkCmdExecuteCommands( m_commandBuffer, commandBuffers.size() , reinterpret_cast<const VkCommandBuffer*>( commandBuffers.data() ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void CommandBuffer::debugMarkerBeginEXT( DebugMarkerMarkerInfoEXT* pMarkerInfo ) const\n  {\n    vkCmdDebugMarkerBeginEXT( m_commandBuffer, reinterpret_cast<VkDebugMarkerMarkerInfoEXT*>( pMarkerInfo ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE DebugMarkerMarkerInfoEXT CommandBuffer::debugMarkerBeginEXT() const\n  {\n    DebugMarkerMarkerInfoEXT markerInfo;\n    vkCmdDebugMarkerBeginEXT( m_commandBuffer, reinterpret_cast<VkDebugMarkerMarkerInfoEXT*>( &markerInfo ) );\n    return markerInfo;\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void CommandBuffer::debugMarkerEndEXT() const\n  {\n    vkCmdDebugMarkerEndEXT( m_commandBuffer );\n  }\n\n  VULKAN_HPP_INLINE void CommandBuffer::debugMarkerInsertEXT( DebugMarkerMarkerInfoEXT* pMarkerInfo ) const\n  {\n    vkCmdDebugMarkerInsertEXT( m_commandBuffer, reinterpret_cast<VkDebugMarkerMarkerInfoEXT*>( pMarkerInfo ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE DebugMarkerMarkerInfoEXT CommandBuffer::debugMarkerInsertEXT() const\n  {\n    DebugMarkerMarkerInfoEXT markerInfo;\n    vkCmdDebugMarkerInsertEXT( m_commandBuffer, reinterpret_cast<VkDebugMarkerMarkerInfoEXT*>( &markerInfo ) );\n    return markerInfo;\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void CommandBuffer::drawIndirectCountAMD( Buffer buffer, DeviceSize offset, Buffer countBuffer, DeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride ) const\n  {\n    vkCmdDrawIndirectCountAMD( m_commandBuffer, static_cast<VkBuffer>( buffer ), offset, static_cast<VkBuffer>( countBuffer ), countBufferOffset, maxDrawCount, stride );\n  }\n\n  VULKAN_HPP_INLINE void CommandBuffer::drawIndexedIndirectCountAMD( Buffer buffer, DeviceSize offset, Buffer countBuffer, DeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride ) const\n  {\n    vkCmdDrawIndexedIndirectCountAMD( m_commandBuffer, static_cast<VkBuffer>( buffer ), offset, static_cast<VkBuffer>( countBuffer ), countBufferOffset, maxDrawCount, stride );\n  }\n\n  VULKAN_HPP_INLINE void CommandBuffer::processCommandsNVX( const CmdProcessCommandsInfoNVX* pProcessCommandsInfo ) const\n  {\n    vkCmdProcessCommandsNVX( m_commandBuffer, reinterpret_cast<const VkCmdProcessCommandsInfoNVX*>( pProcessCommandsInfo ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void CommandBuffer::processCommandsNVX( const CmdProcessCommandsInfoNVX & processCommandsInfo ) const\n  {\n    vkCmdProcessCommandsNVX( m_commandBuffer, reinterpret_cast<const VkCmdProcessCommandsInfoNVX*>( &processCommandsInfo ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void CommandBuffer::reserveSpaceForCommandsNVX( const CmdReserveSpaceForCommandsInfoNVX* pReserveSpaceInfo ) const\n  {\n    vkCmdReserveSpaceForCommandsNVX( m_commandBuffer, reinterpret_cast<const VkCmdReserveSpaceForCommandsInfoNVX*>( pReserveSpaceInfo ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void CommandBuffer::reserveSpaceForCommandsNVX( const CmdReserveSpaceForCommandsInfoNVX & reserveSpaceInfo ) const\n  {\n    vkCmdReserveSpaceForCommandsNVX( m_commandBuffer, reinterpret_cast<const VkCmdReserveSpaceForCommandsInfoNVX*>( &reserveSpaceInfo ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void CommandBuffer::pushDescriptorSetKHR( PipelineBindPoint pipelineBindPoint, PipelineLayout layout, uint32_t set, uint32_t descriptorWriteCount, const WriteDescriptorSet* pDescriptorWrites ) const\n  {\n    vkCmdPushDescriptorSetKHR( m_commandBuffer, static_cast<VkPipelineBindPoint>( pipelineBindPoint ), static_cast<VkPipelineLayout>( layout ), set, descriptorWriteCount, reinterpret_cast<const VkWriteDescriptorSet*>( pDescriptorWrites ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void CommandBuffer::pushDescriptorSetKHR( PipelineBindPoint pipelineBindPoint, PipelineLayout layout, uint32_t set, ArrayProxy<const WriteDescriptorSet> descriptorWrites ) const\n  {\n    vkCmdPushDescriptorSetKHR( m_commandBuffer, static_cast<VkPipelineBindPoint>( pipelineBindPoint ), static_cast<VkPipelineLayout>( layout ), set, descriptorWrites.size() , reinterpret_cast<const VkWriteDescriptorSet*>( descriptorWrites.data() ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void CommandBuffer::setDeviceMaskKHX( uint32_t deviceMask ) const\n  {\n    vkCmdSetDeviceMaskKHX( m_commandBuffer, deviceMask );\n  }\n\n  VULKAN_HPP_INLINE void CommandBuffer::dispatchBaseKHX( uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ ) const\n  {\n    vkCmdDispatchBaseKHX( m_commandBuffer, baseGroupX, baseGroupY, baseGroupZ, groupCountX, groupCountY, groupCountZ );\n  }\n\n  VULKAN_HPP_INLINE void CommandBuffer::pushDescriptorSetWithTemplateKHR( DescriptorUpdateTemplateKHR descriptorUpdateTemplate, PipelineLayout layout, uint32_t set, const void* pData ) const\n  {\n    vkCmdPushDescriptorSetWithTemplateKHR( m_commandBuffer, static_cast<VkDescriptorUpdateTemplateKHR>( descriptorUpdateTemplate ), static_cast<VkPipelineLayout>( layout ), set, pData );\n  }\n\n  VULKAN_HPP_INLINE void CommandBuffer::setViewportWScalingNV( uint32_t firstViewport, uint32_t viewportCount, const ViewportWScalingNV* pViewportWScalings ) const\n  {\n    vkCmdSetViewportWScalingNV( m_commandBuffer, firstViewport, viewportCount, reinterpret_cast<const VkViewportWScalingNV*>( pViewportWScalings ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void CommandBuffer::setViewportWScalingNV( uint32_t firstViewport, ArrayProxy<const ViewportWScalingNV> viewportWScalings ) const\n  {\n    vkCmdSetViewportWScalingNV( m_commandBuffer, firstViewport, viewportWScalings.size() , reinterpret_cast<const VkViewportWScalingNV*>( viewportWScalings.data() ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void CommandBuffer::setDiscardRectangleEXT( uint32_t firstDiscardRectangle, uint32_t discardRectangleCount, const Rect2D* pDiscardRectangles ) const\n  {\n    vkCmdSetDiscardRectangleEXT( m_commandBuffer, firstDiscardRectangle, discardRectangleCount, reinterpret_cast<const VkRect2D*>( pDiscardRectangles ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void CommandBuffer::setDiscardRectangleEXT( uint32_t firstDiscardRectangle, ArrayProxy<const Rect2D> discardRectangles ) const\n  {\n    vkCmdSetDiscardRectangleEXT( m_commandBuffer, firstDiscardRectangle, discardRectangles.size() , reinterpret_cast<const VkRect2D*>( discardRectangles.data() ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  struct SubmitInfo\n  {\n    SubmitInfo( uint32_t waitSemaphoreCount_ = 0, const Semaphore* pWaitSemaphores_ = nullptr, const PipelineStageFlags* pWaitDstStageMask_ = nullptr, uint32_t commandBufferCount_ = 0, const CommandBuffer* pCommandBuffers_ = nullptr, uint32_t signalSemaphoreCount_ = 0, const Semaphore* pSignalSemaphores_ = nullptr )\n      : sType( StructureType::eSubmitInfo )\n      , pNext( nullptr )\n      , waitSemaphoreCount( waitSemaphoreCount_ )\n      , pWaitSemaphores( pWaitSemaphores_ )\n      , pWaitDstStageMask( pWaitDstStageMask_ )\n      , commandBufferCount( commandBufferCount_ )\n      , pCommandBuffers( pCommandBuffers_ )\n      , signalSemaphoreCount( signalSemaphoreCount_ )\n      , pSignalSemaphores( pSignalSemaphores_ )\n    {\n    }\n\n    SubmitInfo( VkSubmitInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(SubmitInfo) );\n    }\n\n    SubmitInfo& operator=( VkSubmitInfo const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(SubmitInfo) );\n      return *this;\n    }\n\n    SubmitInfo& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    SubmitInfo& setWaitSemaphoreCount( uint32_t waitSemaphoreCount_ )\n    {\n      waitSemaphoreCount = waitSemaphoreCount_;\n      return *this;\n    }\n\n    SubmitInfo& setPWaitSemaphores( const Semaphore* pWaitSemaphores_ )\n    {\n      pWaitSemaphores = pWaitSemaphores_;\n      return *this;\n    }\n\n    SubmitInfo& setPWaitDstStageMask( const PipelineStageFlags* pWaitDstStageMask_ )\n    {\n      pWaitDstStageMask = pWaitDstStageMask_;\n      return *this;\n    }\n\n    SubmitInfo& setCommandBufferCount( uint32_t commandBufferCount_ )\n    {\n      commandBufferCount = commandBufferCount_;\n      return *this;\n    }\n\n    SubmitInfo& setPCommandBuffers( const CommandBuffer* pCommandBuffers_ )\n    {\n      pCommandBuffers = pCommandBuffers_;\n      return *this;\n    }\n\n    SubmitInfo& setSignalSemaphoreCount( uint32_t signalSemaphoreCount_ )\n    {\n      signalSemaphoreCount = signalSemaphoreCount_;\n      return *this;\n    }\n\n    SubmitInfo& setPSignalSemaphores( const Semaphore* pSignalSemaphores_ )\n    {\n      pSignalSemaphores = pSignalSemaphores_;\n      return *this;\n    }\n\n    operator const VkSubmitInfo&() const\n    {\n      return *reinterpret_cast<const VkSubmitInfo*>(this);\n    }\n\n    bool operator==( SubmitInfo const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( waitSemaphoreCount == rhs.waitSemaphoreCount )\n          && ( pWaitSemaphores == rhs.pWaitSemaphores )\n          && ( pWaitDstStageMask == rhs.pWaitDstStageMask )\n          && ( commandBufferCount == rhs.commandBufferCount )\n          && ( pCommandBuffers == rhs.pCommandBuffers )\n          && ( signalSemaphoreCount == rhs.signalSemaphoreCount )\n          && ( pSignalSemaphores == rhs.pSignalSemaphores );\n    }\n\n    bool operator!=( SubmitInfo const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    uint32_t waitSemaphoreCount;\n    const Semaphore* pWaitSemaphores;\n    const PipelineStageFlags* pWaitDstStageMask;\n    uint32_t commandBufferCount;\n    const CommandBuffer* pCommandBuffers;\n    uint32_t signalSemaphoreCount;\n    const Semaphore* pSignalSemaphores;\n  };\n  static_assert( sizeof( SubmitInfo ) == sizeof( VkSubmitInfo ), \"struct and wrapper have different size!\" );\n\n  class Queue\n  {\n  public:\n    Queue()\n      : m_queue(VK_NULL_HANDLE)\n    {}\n\n    Queue( std::nullptr_t )\n      : m_queue(VK_NULL_HANDLE)\n    {}\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT Queue(VkQueue queue)\n       : m_queue(queue)\n    {}\n\n#if defined(VULKAN_HPP_TYPESAFE_CONVERSION)\n    Queue& operator=(VkQueue queue)\n    {\n      m_queue = queue;\n      return *this;\n    }\n#endif\n\n    Queue& operator=( std::nullptr_t )\n    {\n      m_queue = VK_NULL_HANDLE;\n      return *this;\n    }\n\n    bool operator==(Queue const &rhs) const\n    {\n      return m_queue == rhs.m_queue;\n    }\n\n    bool operator!=(Queue const &rhs) const\n    {\n      return m_queue != rhs.m_queue;\n    }\n\n    bool operator<(Queue const &rhs) const\n    {\n      return m_queue < rhs.m_queue;\n    }\n\n    Result submit( uint32_t submitCount, const SubmitInfo* pSubmits, Fence fence ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<void>::type submit( ArrayProxy<const SubmitInfo> submits, Fence fence ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifdef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    Result waitIdle() const;\n#else\n    ResultValueType<void>::type waitIdle() const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result bindSparse( uint32_t bindInfoCount, const BindSparseInfo* pBindInfo, Fence fence ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<void>::type bindSparse( ArrayProxy<const BindSparseInfo> bindInfo, Fence fence ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result presentKHR( const PresentInfoKHR* pPresentInfo ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    Result presentKHR( const PresentInfoKHR & presentInfo ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT operator VkQueue() const\n    {\n      return m_queue;\n    }\n\n    explicit operator bool() const\n    {\n      return m_queue != VK_NULL_HANDLE;\n    }\n\n    bool operator!() const\n    {\n      return m_queue == VK_NULL_HANDLE;\n    }\n\n  private:\n    VkQueue m_queue;\n  };\n  static_assert( sizeof( Queue ) == sizeof( VkQueue ), \"handle and wrapper have different size!\" );\n\n  VULKAN_HPP_INLINE Result Queue::submit( uint32_t submitCount, const SubmitInfo* pSubmits, Fence fence ) const\n  {\n    return static_cast<Result>( vkQueueSubmit( m_queue, submitCount, reinterpret_cast<const VkSubmitInfo*>( pSubmits ), static_cast<VkFence>( fence ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<void>::type Queue::submit( ArrayProxy<const SubmitInfo> submits, Fence fence ) const\n  {\n    Result result = static_cast<Result>( vkQueueSubmit( m_queue, submits.size() , reinterpret_cast<const VkSubmitInfo*>( submits.data() ), static_cast<VkFence>( fence ) ) );\n    return createResultValue( result, \"vk::Queue::submit\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifdef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE Result Queue::waitIdle() const\n  {\n    return static_cast<Result>( vkQueueWaitIdle( m_queue ) );\n  }\n#else\n  VULKAN_HPP_INLINE ResultValueType<void>::type Queue::waitIdle() const\n  {\n    Result result = static_cast<Result>( vkQueueWaitIdle( m_queue ) );\n    return createResultValue( result, \"vk::Queue::waitIdle\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Queue::bindSparse( uint32_t bindInfoCount, const BindSparseInfo* pBindInfo, Fence fence ) const\n  {\n    return static_cast<Result>( vkQueueBindSparse( m_queue, bindInfoCount, reinterpret_cast<const VkBindSparseInfo*>( pBindInfo ), static_cast<VkFence>( fence ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<void>::type Queue::bindSparse( ArrayProxy<const BindSparseInfo> bindInfo, Fence fence ) const\n  {\n    Result result = static_cast<Result>( vkQueueBindSparse( m_queue, bindInfo.size() , reinterpret_cast<const VkBindSparseInfo*>( bindInfo.data() ), static_cast<VkFence>( fence ) ) );\n    return createResultValue( result, \"vk::Queue::bindSparse\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Queue::presentKHR( const PresentInfoKHR* pPresentInfo ) const\n  {\n    return static_cast<Result>( vkQueuePresentKHR( m_queue, reinterpret_cast<const VkPresentInfoKHR*>( pPresentInfo ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE Result Queue::presentKHR( const PresentInfoKHR & presentInfo ) const\n  {\n    Result result = static_cast<Result>( vkQueuePresentKHR( m_queue, reinterpret_cast<const VkPresentInfoKHR*>( &presentInfo ) ) );\n    return createResultValue( result, \"vk::Queue::presentKHR\", { Result::eSuccess, Result::eSuboptimalKHR } );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  class BufferDeleter;\n  using UniqueBuffer = UniqueHandle<Buffer, BufferDeleter>;\n  class BufferViewDeleter;\n  using UniqueBufferView = UniqueHandle<BufferView, BufferViewDeleter>;\n  class CommandBufferDeleter;\n  using UniqueCommandBuffer = UniqueHandle<CommandBuffer, CommandBufferDeleter>;\n  class CommandPoolDeleter;\n  using UniqueCommandPool = UniqueHandle<CommandPool, CommandPoolDeleter>;\n  class DescriptorPoolDeleter;\n  using UniqueDescriptorPool = UniqueHandle<DescriptorPool, DescriptorPoolDeleter>;\n  class DescriptorSetDeleter;\n  using UniqueDescriptorSet = UniqueHandle<DescriptorSet, DescriptorSetDeleter>;\n  class DescriptorSetLayoutDeleter;\n  using UniqueDescriptorSetLayout = UniqueHandle<DescriptorSetLayout, DescriptorSetLayoutDeleter>;\n  class DescriptorUpdateTemplateKHRDeleter;\n  using UniqueDescriptorUpdateTemplateKHR = UniqueHandle<DescriptorUpdateTemplateKHR, DescriptorUpdateTemplateKHRDeleter>;\n  class DeviceMemoryDeleter;\n  using UniqueDeviceMemory = UniqueHandle<DeviceMemory, DeviceMemoryDeleter>;\n  class EventDeleter;\n  using UniqueEvent = UniqueHandle<Event, EventDeleter>;\n  class FenceDeleter;\n  using UniqueFence = UniqueHandle<Fence, FenceDeleter>;\n  class FramebufferDeleter;\n  using UniqueFramebuffer = UniqueHandle<Framebuffer, FramebufferDeleter>;\n  class ImageDeleter;\n  using UniqueImage = UniqueHandle<Image, ImageDeleter>;\n  class ImageViewDeleter;\n  using UniqueImageView = UniqueHandle<ImageView, ImageViewDeleter>;\n  class IndirectCommandsLayoutNVXDeleter;\n  using UniqueIndirectCommandsLayoutNVX = UniqueHandle<IndirectCommandsLayoutNVX, IndirectCommandsLayoutNVXDeleter>;\n  class ObjectTableNVXDeleter;\n  using UniqueObjectTableNVX = UniqueHandle<ObjectTableNVX, ObjectTableNVXDeleter>;\n  class PipelineDeleter;\n  using UniquePipeline = UniqueHandle<Pipeline, PipelineDeleter>;\n  class PipelineCacheDeleter;\n  using UniquePipelineCache = UniqueHandle<PipelineCache, PipelineCacheDeleter>;\n  class PipelineLayoutDeleter;\n  using UniquePipelineLayout = UniqueHandle<PipelineLayout, PipelineLayoutDeleter>;\n  class QueryPoolDeleter;\n  using UniqueQueryPool = UniqueHandle<QueryPool, QueryPoolDeleter>;\n  class RenderPassDeleter;\n  using UniqueRenderPass = UniqueHandle<RenderPass, RenderPassDeleter>;\n  class SamplerDeleter;\n  using UniqueSampler = UniqueHandle<Sampler, SamplerDeleter>;\n  class SemaphoreDeleter;\n  using UniqueSemaphore = UniqueHandle<Semaphore, SemaphoreDeleter>;\n  class ShaderModuleDeleter;\n  using UniqueShaderModule = UniqueHandle<ShaderModule, ShaderModuleDeleter>;\n  class SwapchainKHRDeleter;\n  using UniqueSwapchainKHR = UniqueHandle<SwapchainKHR, SwapchainKHRDeleter>;\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n\n  class Device\n  {\n  public:\n    Device()\n      : m_device(VK_NULL_HANDLE)\n    {}\n\n    Device( std::nullptr_t )\n      : m_device(VK_NULL_HANDLE)\n    {}\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT Device(VkDevice device)\n       : m_device(device)\n    {}\n\n#if defined(VULKAN_HPP_TYPESAFE_CONVERSION)\n    Device& operator=(VkDevice device)\n    {\n      m_device = device;\n      return *this;\n    }\n#endif\n\n    Device& operator=( std::nullptr_t )\n    {\n      m_device = VK_NULL_HANDLE;\n      return *this;\n    }\n\n    bool operator==(Device const &rhs) const\n    {\n      return m_device == rhs.m_device;\n    }\n\n    bool operator!=(Device const &rhs) const\n    {\n      return m_device != rhs.m_device;\n    }\n\n    bool operator<(Device const &rhs) const\n    {\n      return m_device < rhs.m_device;\n    }\n\n    PFN_vkVoidFunction getProcAddr( const char* pName ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    PFN_vkVoidFunction getProcAddr( const std::string & name ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void destroy( const AllocationCallbacks* pAllocator ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void destroy( Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void getQueue( uint32_t queueFamilyIndex, uint32_t queueIndex, Queue* pQueue ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    Queue getQueue( uint32_t queueFamilyIndex, uint32_t queueIndex ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifdef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    Result waitIdle() const;\n#else\n    ResultValueType<void>::type waitIdle() const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result allocateMemory( const MemoryAllocateInfo* pAllocateInfo, const AllocationCallbacks* pAllocator, DeviceMemory* pMemory ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<DeviceMemory>::type allocateMemory( const MemoryAllocateInfo & allocateInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n    UniqueDeviceMemory allocateMemoryUnique( const MemoryAllocateInfo & allocateInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void freeMemory( DeviceMemory memory, const AllocationCallbacks* pAllocator ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void freeMemory( DeviceMemory memory, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result mapMemory( DeviceMemory memory, DeviceSize offset, DeviceSize size, MemoryMapFlags flags, void** ppData ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<void*>::type mapMemory( DeviceMemory memory, DeviceSize offset, DeviceSize size, MemoryMapFlags flags = MemoryMapFlags() ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void unmapMemory( DeviceMemory memory ) const;\n\n    Result flushMappedMemoryRanges( uint32_t memoryRangeCount, const MappedMemoryRange* pMemoryRanges ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<void>::type flushMappedMemoryRanges( ArrayProxy<const MappedMemoryRange> memoryRanges ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result invalidateMappedMemoryRanges( uint32_t memoryRangeCount, const MappedMemoryRange* pMemoryRanges ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<void>::type invalidateMappedMemoryRanges( ArrayProxy<const MappedMemoryRange> memoryRanges ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void getMemoryCommitment( DeviceMemory memory, DeviceSize* pCommittedMemoryInBytes ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    DeviceSize getMemoryCommitment( DeviceMemory memory ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void getBufferMemoryRequirements( Buffer buffer, MemoryRequirements* pMemoryRequirements ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    MemoryRequirements getBufferMemoryRequirements( Buffer buffer ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifdef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    Result bindBufferMemory( Buffer buffer, DeviceMemory memory, DeviceSize memoryOffset ) const;\n#else\n    ResultValueType<void>::type bindBufferMemory( Buffer buffer, DeviceMemory memory, DeviceSize memoryOffset ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void getImageMemoryRequirements( Image image, MemoryRequirements* pMemoryRequirements ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    MemoryRequirements getImageMemoryRequirements( Image image ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifdef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    Result bindImageMemory( Image image, DeviceMemory memory, DeviceSize memoryOffset ) const;\n#else\n    ResultValueType<void>::type bindImageMemory( Image image, DeviceMemory memory, DeviceSize memoryOffset ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void getImageSparseMemoryRequirements( Image image, uint32_t* pSparseMemoryRequirementCount, SparseImageMemoryRequirements* pSparseMemoryRequirements ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    template <typename Allocator = std::allocator<SparseImageMemoryRequirements>> \n    std::vector<SparseImageMemoryRequirements,Allocator> getImageSparseMemoryRequirements( Image image ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result createFence( const FenceCreateInfo* pCreateInfo, const AllocationCallbacks* pAllocator, Fence* pFence ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<Fence>::type createFence( const FenceCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n    UniqueFence createFenceUnique( const FenceCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void destroyFence( Fence fence, const AllocationCallbacks* pAllocator ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void destroyFence( Fence fence, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result resetFences( uint32_t fenceCount, const Fence* pFences ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<void>::type resetFences( ArrayProxy<const Fence> fences ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result getFenceStatus( Fence fence ) const;\n\n    Result waitForFences( uint32_t fenceCount, const Fence* pFences, Bool32 waitAll, uint64_t timeout ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    Result waitForFences( ArrayProxy<const Fence> fences, Bool32 waitAll, uint64_t timeout ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result createSemaphore( const SemaphoreCreateInfo* pCreateInfo, const AllocationCallbacks* pAllocator, Semaphore* pSemaphore ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<Semaphore>::type createSemaphore( const SemaphoreCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n    UniqueSemaphore createSemaphoreUnique( const SemaphoreCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void destroySemaphore( Semaphore semaphore, const AllocationCallbacks* pAllocator ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void destroySemaphore( Semaphore semaphore, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result createEvent( const EventCreateInfo* pCreateInfo, const AllocationCallbacks* pAllocator, Event* pEvent ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<Event>::type createEvent( const EventCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n    UniqueEvent createEventUnique( const EventCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void destroyEvent( Event event, const AllocationCallbacks* pAllocator ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void destroyEvent( Event event, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result getEventStatus( Event event ) const;\n\n#ifdef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    Result setEvent( Event event ) const;\n#else\n    ResultValueType<void>::type setEvent( Event event ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifdef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    Result resetEvent( Event event ) const;\n#else\n    ResultValueType<void>::type resetEvent( Event event ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result createQueryPool( const QueryPoolCreateInfo* pCreateInfo, const AllocationCallbacks* pAllocator, QueryPool* pQueryPool ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<QueryPool>::type createQueryPool( const QueryPoolCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n    UniqueQueryPool createQueryPoolUnique( const QueryPoolCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void destroyQueryPool( QueryPool queryPool, const AllocationCallbacks* pAllocator ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void destroyQueryPool( QueryPool queryPool, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result getQueryPoolResults( QueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, size_t dataSize, void* pData, DeviceSize stride, QueryResultFlags flags ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    template <typename T>\n    Result getQueryPoolResults( QueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, ArrayProxy<T> data, DeviceSize stride, QueryResultFlags flags ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result createBuffer( const BufferCreateInfo* pCreateInfo, const AllocationCallbacks* pAllocator, Buffer* pBuffer ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<Buffer>::type createBuffer( const BufferCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n    UniqueBuffer createBufferUnique( const BufferCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void destroyBuffer( Buffer buffer, const AllocationCallbacks* pAllocator ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void destroyBuffer( Buffer buffer, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result createBufferView( const BufferViewCreateInfo* pCreateInfo, const AllocationCallbacks* pAllocator, BufferView* pView ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<BufferView>::type createBufferView( const BufferViewCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n    UniqueBufferView createBufferViewUnique( const BufferViewCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void destroyBufferView( BufferView bufferView, const AllocationCallbacks* pAllocator ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void destroyBufferView( BufferView bufferView, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result createImage( const ImageCreateInfo* pCreateInfo, const AllocationCallbacks* pAllocator, Image* pImage ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<Image>::type createImage( const ImageCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n    UniqueImage createImageUnique( const ImageCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void destroyImage( Image image, const AllocationCallbacks* pAllocator ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void destroyImage( Image image, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void getImageSubresourceLayout( Image image, const ImageSubresource* pSubresource, SubresourceLayout* pLayout ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    SubresourceLayout getImageSubresourceLayout( Image image, const ImageSubresource & subresource ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result createImageView( const ImageViewCreateInfo* pCreateInfo, const AllocationCallbacks* pAllocator, ImageView* pView ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<ImageView>::type createImageView( const ImageViewCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n    UniqueImageView createImageViewUnique( const ImageViewCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void destroyImageView( ImageView imageView, const AllocationCallbacks* pAllocator ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void destroyImageView( ImageView imageView, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result createShaderModule( const ShaderModuleCreateInfo* pCreateInfo, const AllocationCallbacks* pAllocator, ShaderModule* pShaderModule ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<ShaderModule>::type createShaderModule( const ShaderModuleCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n    UniqueShaderModule createShaderModuleUnique( const ShaderModuleCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void destroyShaderModule( ShaderModule shaderModule, const AllocationCallbacks* pAllocator ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void destroyShaderModule( ShaderModule shaderModule, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result createPipelineCache( const PipelineCacheCreateInfo* pCreateInfo, const AllocationCallbacks* pAllocator, PipelineCache* pPipelineCache ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<PipelineCache>::type createPipelineCache( const PipelineCacheCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n    UniquePipelineCache createPipelineCacheUnique( const PipelineCacheCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void destroyPipelineCache( PipelineCache pipelineCache, const AllocationCallbacks* pAllocator ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void destroyPipelineCache( PipelineCache pipelineCache, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result getPipelineCacheData( PipelineCache pipelineCache, size_t* pDataSize, void* pData ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    template <typename Allocator = std::allocator<uint8_t>> \n    typename ResultValueType<std::vector<uint8_t,Allocator>>::type getPipelineCacheData( PipelineCache pipelineCache ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result mergePipelineCaches( PipelineCache dstCache, uint32_t srcCacheCount, const PipelineCache* pSrcCaches ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<void>::type mergePipelineCaches( PipelineCache dstCache, ArrayProxy<const PipelineCache> srcCaches ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result createGraphicsPipelines( PipelineCache pipelineCache, uint32_t createInfoCount, const GraphicsPipelineCreateInfo* pCreateInfos, const AllocationCallbacks* pAllocator, Pipeline* pPipelines ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    template <typename Allocator = std::allocator<Pipeline>> \n    typename ResultValueType<std::vector<Pipeline,Allocator>>::type createGraphicsPipelines( PipelineCache pipelineCache, ArrayProxy<const GraphicsPipelineCreateInfo> createInfos, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n    ResultValueType<Pipeline>::type createGraphicsPipeline( PipelineCache pipelineCache, const GraphicsPipelineCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n    template <typename Allocator = std::allocator<Pipeline>> \n    std::vector<UniquePipeline> createGraphicsPipelinesUnique( PipelineCache pipelineCache, ArrayProxy<const GraphicsPipelineCreateInfo> createInfos, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n    UniquePipeline createGraphicsPipelineUnique( PipelineCache pipelineCache, const GraphicsPipelineCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result createComputePipelines( PipelineCache pipelineCache, uint32_t createInfoCount, const ComputePipelineCreateInfo* pCreateInfos, const AllocationCallbacks* pAllocator, Pipeline* pPipelines ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    template <typename Allocator = std::allocator<Pipeline>> \n    typename ResultValueType<std::vector<Pipeline,Allocator>>::type createComputePipelines( PipelineCache pipelineCache, ArrayProxy<const ComputePipelineCreateInfo> createInfos, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n    ResultValueType<Pipeline>::type createComputePipeline( PipelineCache pipelineCache, const ComputePipelineCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n    template <typename Allocator = std::allocator<Pipeline>> \n    std::vector<UniquePipeline> createComputePipelinesUnique( PipelineCache pipelineCache, ArrayProxy<const ComputePipelineCreateInfo> createInfos, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n    UniquePipeline createComputePipelineUnique( PipelineCache pipelineCache, const ComputePipelineCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void destroyPipeline( Pipeline pipeline, const AllocationCallbacks* pAllocator ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void destroyPipeline( Pipeline pipeline, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result createPipelineLayout( const PipelineLayoutCreateInfo* pCreateInfo, const AllocationCallbacks* pAllocator, PipelineLayout* pPipelineLayout ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<PipelineLayout>::type createPipelineLayout( const PipelineLayoutCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n    UniquePipelineLayout createPipelineLayoutUnique( const PipelineLayoutCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void destroyPipelineLayout( PipelineLayout pipelineLayout, const AllocationCallbacks* pAllocator ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void destroyPipelineLayout( PipelineLayout pipelineLayout, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result createSampler( const SamplerCreateInfo* pCreateInfo, const AllocationCallbacks* pAllocator, Sampler* pSampler ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<Sampler>::type createSampler( const SamplerCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n    UniqueSampler createSamplerUnique( const SamplerCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void destroySampler( Sampler sampler, const AllocationCallbacks* pAllocator ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void destroySampler( Sampler sampler, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result createDescriptorSetLayout( const DescriptorSetLayoutCreateInfo* pCreateInfo, const AllocationCallbacks* pAllocator, DescriptorSetLayout* pSetLayout ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<DescriptorSetLayout>::type createDescriptorSetLayout( const DescriptorSetLayoutCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n    UniqueDescriptorSetLayout createDescriptorSetLayoutUnique( const DescriptorSetLayoutCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void destroyDescriptorSetLayout( DescriptorSetLayout descriptorSetLayout, const AllocationCallbacks* pAllocator ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void destroyDescriptorSetLayout( DescriptorSetLayout descriptorSetLayout, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result createDescriptorPool( const DescriptorPoolCreateInfo* pCreateInfo, const AllocationCallbacks* pAllocator, DescriptorPool* pDescriptorPool ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<DescriptorPool>::type createDescriptorPool( const DescriptorPoolCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n    UniqueDescriptorPool createDescriptorPoolUnique( const DescriptorPoolCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void destroyDescriptorPool( DescriptorPool descriptorPool, const AllocationCallbacks* pAllocator ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void destroyDescriptorPool( DescriptorPool descriptorPool, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifdef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    Result resetDescriptorPool( DescriptorPool descriptorPool, DescriptorPoolResetFlags flags ) const;\n#else\n    ResultValueType<void>::type resetDescriptorPool( DescriptorPool descriptorPool, DescriptorPoolResetFlags flags = DescriptorPoolResetFlags() ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result allocateDescriptorSets( const DescriptorSetAllocateInfo* pAllocateInfo, DescriptorSet* pDescriptorSets ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    template <typename Allocator = std::allocator<DescriptorSet>> \n    typename ResultValueType<std::vector<DescriptorSet,Allocator>>::type allocateDescriptorSets( const DescriptorSetAllocateInfo & allocateInfo ) const;\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n    template <typename Allocator = std::allocator<DescriptorSet>> \n    std::vector<UniqueDescriptorSet> allocateDescriptorSetsUnique( const DescriptorSetAllocateInfo & allocateInfo ) const;\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result freeDescriptorSets( DescriptorPool descriptorPool, uint32_t descriptorSetCount, const DescriptorSet* pDescriptorSets ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<void>::type freeDescriptorSets( DescriptorPool descriptorPool, ArrayProxy<const DescriptorSet> descriptorSets ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void updateDescriptorSets( uint32_t descriptorWriteCount, const WriteDescriptorSet* pDescriptorWrites, uint32_t descriptorCopyCount, const CopyDescriptorSet* pDescriptorCopies ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void updateDescriptorSets( ArrayProxy<const WriteDescriptorSet> descriptorWrites, ArrayProxy<const CopyDescriptorSet> descriptorCopies ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result createFramebuffer( const FramebufferCreateInfo* pCreateInfo, const AllocationCallbacks* pAllocator, Framebuffer* pFramebuffer ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<Framebuffer>::type createFramebuffer( const FramebufferCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n    UniqueFramebuffer createFramebufferUnique( const FramebufferCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void destroyFramebuffer( Framebuffer framebuffer, const AllocationCallbacks* pAllocator ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void destroyFramebuffer( Framebuffer framebuffer, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result createRenderPass( const RenderPassCreateInfo* pCreateInfo, const AllocationCallbacks* pAllocator, RenderPass* pRenderPass ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<RenderPass>::type createRenderPass( const RenderPassCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n    UniqueRenderPass createRenderPassUnique( const RenderPassCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void destroyRenderPass( RenderPass renderPass, const AllocationCallbacks* pAllocator ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void destroyRenderPass( RenderPass renderPass, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void getRenderAreaGranularity( RenderPass renderPass, Extent2D* pGranularity ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    Extent2D getRenderAreaGranularity( RenderPass renderPass ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result createCommandPool( const CommandPoolCreateInfo* pCreateInfo, const AllocationCallbacks* pAllocator, CommandPool* pCommandPool ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<CommandPool>::type createCommandPool( const CommandPoolCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n    UniqueCommandPool createCommandPoolUnique( const CommandPoolCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void destroyCommandPool( CommandPool commandPool, const AllocationCallbacks* pAllocator ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void destroyCommandPool( CommandPool commandPool, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifdef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    Result resetCommandPool( CommandPool commandPool, CommandPoolResetFlags flags ) const;\n#else\n    ResultValueType<void>::type resetCommandPool( CommandPool commandPool, CommandPoolResetFlags flags ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result allocateCommandBuffers( const CommandBufferAllocateInfo* pAllocateInfo, CommandBuffer* pCommandBuffers ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    template <typename Allocator = std::allocator<CommandBuffer>> \n    typename ResultValueType<std::vector<CommandBuffer,Allocator>>::type allocateCommandBuffers( const CommandBufferAllocateInfo & allocateInfo ) const;\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n    template <typename Allocator = std::allocator<CommandBuffer>> \n    std::vector<UniqueCommandBuffer> allocateCommandBuffersUnique( const CommandBufferAllocateInfo & allocateInfo ) const;\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void freeCommandBuffers( CommandPool commandPool, uint32_t commandBufferCount, const CommandBuffer* pCommandBuffers ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void freeCommandBuffers( CommandPool commandPool, ArrayProxy<const CommandBuffer> commandBuffers ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result createSharedSwapchainsKHR( uint32_t swapchainCount, const SwapchainCreateInfoKHR* pCreateInfos, const AllocationCallbacks* pAllocator, SwapchainKHR* pSwapchains ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    template <typename Allocator = std::allocator<SwapchainKHR>> \n    typename ResultValueType<std::vector<SwapchainKHR,Allocator>>::type createSharedSwapchainsKHR( ArrayProxy<const SwapchainCreateInfoKHR> createInfos, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n    ResultValueType<SwapchainKHR>::type createSharedSwapchainKHR( const SwapchainCreateInfoKHR & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n    template <typename Allocator = std::allocator<SwapchainKHR>> \n    std::vector<UniqueSwapchainKHR> createSharedSwapchainsKHRUnique( ArrayProxy<const SwapchainCreateInfoKHR> createInfos, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n    UniqueSwapchainKHR createSharedSwapchainKHRUnique( const SwapchainCreateInfoKHR & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result createSwapchainKHR( const SwapchainCreateInfoKHR* pCreateInfo, const AllocationCallbacks* pAllocator, SwapchainKHR* pSwapchain ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<SwapchainKHR>::type createSwapchainKHR( const SwapchainCreateInfoKHR & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n    UniqueSwapchainKHR createSwapchainKHRUnique( const SwapchainCreateInfoKHR & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void destroySwapchainKHR( SwapchainKHR swapchain, const AllocationCallbacks* pAllocator ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void destroySwapchainKHR( SwapchainKHR swapchain, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result getSwapchainImagesKHR( SwapchainKHR swapchain, uint32_t* pSwapchainImageCount, Image* pSwapchainImages ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    template <typename Allocator = std::allocator<Image>> \n    typename ResultValueType<std::vector<Image,Allocator>>::type getSwapchainImagesKHR( SwapchainKHR swapchain ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result acquireNextImageKHR( SwapchainKHR swapchain, uint64_t timeout, Semaphore semaphore, Fence fence, uint32_t* pImageIndex ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValue<uint32_t> acquireNextImageKHR( SwapchainKHR swapchain, uint64_t timeout, Semaphore semaphore, Fence fence ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result debugMarkerSetObjectNameEXT( DebugMarkerObjectNameInfoEXT* pNameInfo ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<DebugMarkerObjectNameInfoEXT>::type debugMarkerSetObjectNameEXT() const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result debugMarkerSetObjectTagEXT( DebugMarkerObjectTagInfoEXT* pTagInfo ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<DebugMarkerObjectTagInfoEXT>::type debugMarkerSetObjectTagEXT() const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifdef VK_USE_PLATFORM_WIN32_KHR\n    Result getMemoryWin32HandleNV( DeviceMemory memory, ExternalMemoryHandleTypeFlagsNV handleType, HANDLE* pHandle ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<HANDLE>::type getMemoryWin32HandleNV( DeviceMemory memory, ExternalMemoryHandleTypeFlagsNV handleType ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n#endif /*VK_USE_PLATFORM_WIN32_KHR*/\n\n    Result createIndirectCommandsLayoutNVX( const IndirectCommandsLayoutCreateInfoNVX* pCreateInfo, const AllocationCallbacks* pAllocator, IndirectCommandsLayoutNVX* pIndirectCommandsLayout ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<IndirectCommandsLayoutNVX>::type createIndirectCommandsLayoutNVX( const IndirectCommandsLayoutCreateInfoNVX & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n    UniqueIndirectCommandsLayoutNVX createIndirectCommandsLayoutNVXUnique( const IndirectCommandsLayoutCreateInfoNVX & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void destroyIndirectCommandsLayoutNVX( IndirectCommandsLayoutNVX indirectCommandsLayout, const AllocationCallbacks* pAllocator ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void destroyIndirectCommandsLayoutNVX( IndirectCommandsLayoutNVX indirectCommandsLayout, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result createObjectTableNVX( const ObjectTableCreateInfoNVX* pCreateInfo, const AllocationCallbacks* pAllocator, ObjectTableNVX* pObjectTable ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<ObjectTableNVX>::type createObjectTableNVX( const ObjectTableCreateInfoNVX & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n    UniqueObjectTableNVX createObjectTableNVXUnique( const ObjectTableCreateInfoNVX & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void destroyObjectTableNVX( ObjectTableNVX objectTable, const AllocationCallbacks* pAllocator ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void destroyObjectTableNVX( ObjectTableNVX objectTable, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result registerObjectsNVX( ObjectTableNVX objectTable, uint32_t objectCount, const ObjectTableEntryNVX* const* ppObjectTableEntries, const uint32_t* pObjectIndices ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<void>::type registerObjectsNVX( ObjectTableNVX objectTable, ArrayProxy<const ObjectTableEntryNVX* const> pObjectTableEntries, ArrayProxy<const uint32_t> objectIndices ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result unregisterObjectsNVX( ObjectTableNVX objectTable, uint32_t objectCount, const ObjectEntryTypeNVX* pObjectEntryTypes, const uint32_t* pObjectIndices ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<void>::type unregisterObjectsNVX( ObjectTableNVX objectTable, ArrayProxy<const ObjectEntryTypeNVX> objectEntryTypes, ArrayProxy<const uint32_t> objectIndices ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifdef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void trimCommandPoolKHR( CommandPool commandPool, CommandPoolTrimFlagsKHR flags ) const;\n#else\n    void trimCommandPoolKHR( CommandPool commandPool, CommandPoolTrimFlagsKHR flags = CommandPoolTrimFlagsKHR() ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifdef VK_USE_PLATFORM_WIN32_KHX\n    Result getMemoryWin32HandleKHX( DeviceMemory memory, ExternalMemoryHandleTypeFlagBitsKHX handleType, HANDLE* pHandle ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<HANDLE>::type getMemoryWin32HandleKHX( DeviceMemory memory, ExternalMemoryHandleTypeFlagBitsKHX handleType ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n#endif /*VK_USE_PLATFORM_WIN32_KHX*/\n\n#ifdef VK_USE_PLATFORM_WIN32_KHX\n    Result getMemoryWin32HandlePropertiesKHX( ExternalMemoryHandleTypeFlagBitsKHX handleType, HANDLE handle, MemoryWin32HandlePropertiesKHX* pMemoryWin32HandleProperties ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<MemoryWin32HandlePropertiesKHX>::type getMemoryWin32HandlePropertiesKHX( ExternalMemoryHandleTypeFlagBitsKHX handleType, HANDLE handle ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n#endif /*VK_USE_PLATFORM_WIN32_KHX*/\n\n    Result getMemoryFdKHX( DeviceMemory memory, ExternalMemoryHandleTypeFlagBitsKHX handleType, int* pFd ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<int>::type getMemoryFdKHX( DeviceMemory memory, ExternalMemoryHandleTypeFlagBitsKHX handleType ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result getMemoryFdPropertiesKHX( ExternalMemoryHandleTypeFlagBitsKHX handleType, int fd, MemoryFdPropertiesKHX* pMemoryFdProperties ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<MemoryFdPropertiesKHX>::type getMemoryFdPropertiesKHX( ExternalMemoryHandleTypeFlagBitsKHX handleType, int fd ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifdef VK_USE_PLATFORM_WIN32_KHX\n    Result getSemaphoreWin32HandleKHX( Semaphore semaphore, ExternalSemaphoreHandleTypeFlagBitsKHX handleType, HANDLE* pHandle ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<HANDLE>::type getSemaphoreWin32HandleKHX( Semaphore semaphore, ExternalSemaphoreHandleTypeFlagBitsKHX handleType ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n#endif /*VK_USE_PLATFORM_WIN32_KHX*/\n\n#ifdef VK_USE_PLATFORM_WIN32_KHX\n    Result importSemaphoreWin32HandleKHX( const ImportSemaphoreWin32HandleInfoKHX* pImportSemaphoreWin32HandleInfo ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<void>::type importSemaphoreWin32HandleKHX( const ImportSemaphoreWin32HandleInfoKHX & importSemaphoreWin32HandleInfo ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n#endif /*VK_USE_PLATFORM_WIN32_KHX*/\n\n    Result getSemaphoreFdKHX( Semaphore semaphore, ExternalSemaphoreHandleTypeFlagBitsKHX handleType, int* pFd ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<int>::type getSemaphoreFdKHX( Semaphore semaphore, ExternalSemaphoreHandleTypeFlagBitsKHX handleType ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result importSemaphoreFdKHX( const ImportSemaphoreFdInfoKHX* pImportSemaphoreFdInfo ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<void>::type importSemaphoreFdKHX( const ImportSemaphoreFdInfoKHX & importSemaphoreFdInfo ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result displayPowerControlEXT( DisplayKHR display, const DisplayPowerInfoEXT* pDisplayPowerInfo ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<void>::type displayPowerControlEXT( DisplayKHR display, const DisplayPowerInfoEXT & displayPowerInfo ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result registerEventEXT( const DeviceEventInfoEXT* pDeviceEventInfo, const AllocationCallbacks* pAllocator, Fence* pFence ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<Fence>::type registerEventEXT( const DeviceEventInfoEXT & deviceEventInfo, const AllocationCallbacks & allocator ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result registerDisplayEventEXT( DisplayKHR display, const DisplayEventInfoEXT* pDisplayEventInfo, const AllocationCallbacks* pAllocator, Fence* pFence ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<Fence>::type registerDisplayEventEXT( DisplayKHR display, const DisplayEventInfoEXT & displayEventInfo, const AllocationCallbacks & allocator ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result getSwapchainCounterEXT( SwapchainKHR swapchain, SurfaceCounterFlagBitsEXT counter, uint64_t* pCounterValue ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValue<uint64_t> getSwapchainCounterEXT( SwapchainKHR swapchain, SurfaceCounterFlagBitsEXT counter ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void getGroupPeerMemoryFeaturesKHX( uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, PeerMemoryFeatureFlagsKHX* pPeerMemoryFeatures ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    PeerMemoryFeatureFlagsKHX getGroupPeerMemoryFeaturesKHX( uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result bindBufferMemory2KHX( uint32_t bindInfoCount, const BindBufferMemoryInfoKHX* pBindInfos ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<void>::type bindBufferMemory2KHX( ArrayProxy<const BindBufferMemoryInfoKHX> bindInfos ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result bindImageMemory2KHX( uint32_t bindInfoCount, const BindImageMemoryInfoKHX* pBindInfos ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<void>::type bindImageMemory2KHX( ArrayProxy<const BindImageMemoryInfoKHX> bindInfos ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result getGroupPresentCapabilitiesKHX( DeviceGroupPresentCapabilitiesKHX* pDeviceGroupPresentCapabilities ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<DeviceGroupPresentCapabilitiesKHX>::type getGroupPresentCapabilitiesKHX() const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result getGroupSurfacePresentModesKHX( SurfaceKHR surface, DeviceGroupPresentModeFlagsKHX* pModes ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<DeviceGroupPresentModeFlagsKHX>::type getGroupSurfacePresentModesKHX( SurfaceKHR surface ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result acquireNextImage2KHX( const AcquireNextImageInfoKHX* pAcquireInfo, uint32_t* pImageIndex ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValue<uint32_t> acquireNextImage2KHX( const AcquireNextImageInfoKHX & acquireInfo ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result createDescriptorUpdateTemplateKHR( const DescriptorUpdateTemplateCreateInfoKHR* pCreateInfo, const AllocationCallbacks* pAllocator, DescriptorUpdateTemplateKHR* pDescriptorUpdateTemplate ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<DescriptorUpdateTemplateKHR>::type createDescriptorUpdateTemplateKHR( const DescriptorUpdateTemplateCreateInfoKHR & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n    UniqueDescriptorUpdateTemplateKHR createDescriptorUpdateTemplateKHRUnique( const DescriptorUpdateTemplateCreateInfoKHR & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void destroyDescriptorUpdateTemplateKHR( DescriptorUpdateTemplateKHR descriptorUpdateTemplate, const AllocationCallbacks* pAllocator ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void destroyDescriptorUpdateTemplateKHR( DescriptorUpdateTemplateKHR descriptorUpdateTemplate, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void updateDescriptorSetWithTemplateKHR( DescriptorSet descriptorSet, DescriptorUpdateTemplateKHR descriptorUpdateTemplate, const void* pData ) const;\n\n    void setHdrMetadataEXT( uint32_t swapchainCount, const SwapchainKHR* pSwapchains, const HdrMetadataEXT* pMetadata ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void setHdrMetadataEXT( ArrayProxy<const SwapchainKHR> swapchains, ArrayProxy<const HdrMetadataEXT> metadata ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result getSwapchainStatusKHR( SwapchainKHR swapchain ) const;\n\n    Result getRefreshCycleDurationGOOGLE( SwapchainKHR swapchain, RefreshCycleDurationGOOGLE* pDisplayTimingProperties ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<RefreshCycleDurationGOOGLE>::type getRefreshCycleDurationGOOGLE( SwapchainKHR swapchain ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result getPastPresentationTimingGOOGLE( SwapchainKHR swapchain, uint32_t* pPresentationTimingCount, PastPresentationTimingGOOGLE* pPresentationTimings ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    template <typename Allocator = std::allocator<PastPresentationTimingGOOGLE>> \n    typename ResultValueType<std::vector<PastPresentationTimingGOOGLE,Allocator>>::type getPastPresentationTimingGOOGLE( SwapchainKHR swapchain ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT operator VkDevice() const\n    {\n      return m_device;\n    }\n\n    explicit operator bool() const\n    {\n      return m_device != VK_NULL_HANDLE;\n    }\n\n    bool operator!() const\n    {\n      return m_device == VK_NULL_HANDLE;\n    }\n\n  private:\n    VkDevice m_device;\n  };\n  static_assert( sizeof( Device ) == sizeof( VkDevice ), \"handle and wrapper have different size!\" );\n\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  class BufferDeleter\n  {\n  public:\n    BufferDeleter( Device device = Device(), Optional<const AllocationCallbacks> allocator = nullptr )\n      : m_device( device )\n      , m_allocator( allocator )\n    {}\n\n    void operator()( Buffer buffer )\n    {\n      m_device.destroyBuffer( buffer, m_allocator );\n    }\n\n  private:\n    Device m_device;\n    Optional<const AllocationCallbacks> m_allocator;\n  };\n\n  class BufferViewDeleter\n  {\n  public:\n    BufferViewDeleter( Device device = Device(), Optional<const AllocationCallbacks> allocator = nullptr )\n      : m_device( device )\n      , m_allocator( allocator )\n    {}\n\n    void operator()( BufferView bufferView )\n    {\n      m_device.destroyBufferView( bufferView, m_allocator );\n    }\n\n  private:\n    Device m_device;\n    Optional<const AllocationCallbacks> m_allocator;\n  };\n\n  class CommandBufferDeleter\n  {\n  public:\n    CommandBufferDeleter( Device device = Device(), CommandPool commandPool = CommandPool() )\n      : m_device( device )\n      , m_commandPool( commandPool )\n    {}\n\n    void operator()( CommandBuffer commandBuffer )\n    {\n      m_device.freeCommandBuffers( m_commandPool, commandBuffer );\n    }\n\n  private:\n    Device m_device;\n    CommandPool m_commandPool;\n  };\n\n  class CommandPoolDeleter\n  {\n  public:\n    CommandPoolDeleter( Device device = Device(), Optional<const AllocationCallbacks> allocator = nullptr )\n      : m_device( device )\n      , m_allocator( allocator )\n    {}\n\n    void operator()( CommandPool commandPool )\n    {\n      m_device.destroyCommandPool( commandPool, m_allocator );\n    }\n\n  private:\n    Device m_device;\n    Optional<const AllocationCallbacks> m_allocator;\n  };\n\n  class DescriptorPoolDeleter\n  {\n  public:\n    DescriptorPoolDeleter( Device device = Device(), Optional<const AllocationCallbacks> allocator = nullptr )\n      : m_device( device )\n      , m_allocator( allocator )\n    {}\n\n    void operator()( DescriptorPool descriptorPool )\n    {\n      m_device.destroyDescriptorPool( descriptorPool, m_allocator );\n    }\n\n  private:\n    Device m_device;\n    Optional<const AllocationCallbacks> m_allocator;\n  };\n\n  class DescriptorSetDeleter\n  {\n  public:\n    DescriptorSetDeleter( Device device = Device(), DescriptorPool descriptorPool = DescriptorPool() )\n      : m_device( device )\n      , m_descriptorPool( descriptorPool )\n    {}\n\n    void operator()( DescriptorSet descriptorSet )\n    {\n      m_device.freeDescriptorSets( m_descriptorPool, descriptorSet );\n    }\n\n  private:\n    Device m_device;\n    DescriptorPool m_descriptorPool;\n  };\n\n  class DescriptorSetLayoutDeleter\n  {\n  public:\n    DescriptorSetLayoutDeleter( Device device = Device(), Optional<const AllocationCallbacks> allocator = nullptr )\n      : m_device( device )\n      , m_allocator( allocator )\n    {}\n\n    void operator()( DescriptorSetLayout descriptorSetLayout )\n    {\n      m_device.destroyDescriptorSetLayout( descriptorSetLayout, m_allocator );\n    }\n\n  private:\n    Device m_device;\n    Optional<const AllocationCallbacks> m_allocator;\n  };\n\n  class DescriptorUpdateTemplateKHRDeleter\n  {\n  public:\n    DescriptorUpdateTemplateKHRDeleter( Device device = Device(), Optional<const AllocationCallbacks> allocator = nullptr )\n      : m_device( device )\n      , m_allocator( allocator )\n    {}\n\n    void operator()( DescriptorUpdateTemplateKHR descriptorUpdateTemplateKHR )\n    {\n      m_device.destroyDescriptorUpdateTemplateKHR( descriptorUpdateTemplateKHR, m_allocator );\n    }\n\n  private:\n    Device m_device;\n    Optional<const AllocationCallbacks> m_allocator;\n  };\n\n  class DeviceMemoryDeleter\n  {\n  public:\n    DeviceMemoryDeleter( Device device = Device(), Optional<const AllocationCallbacks> allocator = nullptr )\n      : m_device( device )\n      , m_allocator( allocator )\n    {}\n\n    void operator()( DeviceMemory deviceMemory )\n    {\n      m_device.freeMemory( deviceMemory, m_allocator );\n    }\n\n  private:\n    Device m_device;\n    Optional<const AllocationCallbacks> m_allocator;\n  };\n\n  class EventDeleter\n  {\n  public:\n    EventDeleter( Device device = Device(), Optional<const AllocationCallbacks> allocator = nullptr )\n      : m_device( device )\n      , m_allocator( allocator )\n    {}\n\n    void operator()( Event event )\n    {\n      m_device.destroyEvent( event, m_allocator );\n    }\n\n  private:\n    Device m_device;\n    Optional<const AllocationCallbacks> m_allocator;\n  };\n\n  class FenceDeleter\n  {\n  public:\n    FenceDeleter( Device device = Device(), Optional<const AllocationCallbacks> allocator = nullptr )\n      : m_device( device )\n      , m_allocator( allocator )\n    {}\n\n    void operator()( Fence fence )\n    {\n      m_device.destroyFence( fence, m_allocator );\n    }\n\n  private:\n    Device m_device;\n    Optional<const AllocationCallbacks> m_allocator;\n  };\n\n  class FramebufferDeleter\n  {\n  public:\n    FramebufferDeleter( Device device = Device(), Optional<const AllocationCallbacks> allocator = nullptr )\n      : m_device( device )\n      , m_allocator( allocator )\n    {}\n\n    void operator()( Framebuffer framebuffer )\n    {\n      m_device.destroyFramebuffer( framebuffer, m_allocator );\n    }\n\n  private:\n    Device m_device;\n    Optional<const AllocationCallbacks> m_allocator;\n  };\n\n  class ImageDeleter\n  {\n  public:\n    ImageDeleter( Device device = Device(), Optional<const AllocationCallbacks> allocator = nullptr )\n      : m_device( device )\n      , m_allocator( allocator )\n    {}\n\n    void operator()( Image image )\n    {\n      m_device.destroyImage( image, m_allocator );\n    }\n\n  private:\n    Device m_device;\n    Optional<const AllocationCallbacks> m_allocator;\n  };\n\n  class ImageViewDeleter\n  {\n  public:\n    ImageViewDeleter( Device device = Device(), Optional<const AllocationCallbacks> allocator = nullptr )\n      : m_device( device )\n      , m_allocator( allocator )\n    {}\n\n    void operator()( ImageView imageView )\n    {\n      m_device.destroyImageView( imageView, m_allocator );\n    }\n\n  private:\n    Device m_device;\n    Optional<const AllocationCallbacks> m_allocator;\n  };\n\n  class IndirectCommandsLayoutNVXDeleter\n  {\n  public:\n    IndirectCommandsLayoutNVXDeleter( Device device = Device(), Optional<const AllocationCallbacks> allocator = nullptr )\n      : m_device( device )\n      , m_allocator( allocator )\n    {}\n\n    void operator()( IndirectCommandsLayoutNVX indirectCommandsLayoutNVX )\n    {\n      m_device.destroyIndirectCommandsLayoutNVX( indirectCommandsLayoutNVX, m_allocator );\n    }\n\n  private:\n    Device m_device;\n    Optional<const AllocationCallbacks> m_allocator;\n  };\n\n  class ObjectTableNVXDeleter\n  {\n  public:\n    ObjectTableNVXDeleter( Device device = Device(), Optional<const AllocationCallbacks> allocator = nullptr )\n      : m_device( device )\n      , m_allocator( allocator )\n    {}\n\n    void operator()( ObjectTableNVX objectTableNVX )\n    {\n      m_device.destroyObjectTableNVX( objectTableNVX, m_allocator );\n    }\n\n  private:\n    Device m_device;\n    Optional<const AllocationCallbacks> m_allocator;\n  };\n\n  class PipelineDeleter\n  {\n  public:\n    PipelineDeleter( Device device = Device(), Optional<const AllocationCallbacks> allocator = nullptr )\n      : m_device( device )\n      , m_allocator( allocator )\n    {}\n\n    void operator()( Pipeline pipeline )\n    {\n      m_device.destroyPipeline( pipeline, m_allocator );\n    }\n\n  private:\n    Device m_device;\n    Optional<const AllocationCallbacks> m_allocator;\n  };\n\n  class PipelineCacheDeleter\n  {\n  public:\n    PipelineCacheDeleter( Device device = Device(), Optional<const AllocationCallbacks> allocator = nullptr )\n      : m_device( device )\n      , m_allocator( allocator )\n    {}\n\n    void operator()( PipelineCache pipelineCache )\n    {\n      m_device.destroyPipelineCache( pipelineCache, m_allocator );\n    }\n\n  private:\n    Device m_device;\n    Optional<const AllocationCallbacks> m_allocator;\n  };\n\n  class PipelineLayoutDeleter\n  {\n  public:\n    PipelineLayoutDeleter( Device device = Device(), Optional<const AllocationCallbacks> allocator = nullptr )\n      : m_device( device )\n      , m_allocator( allocator )\n    {}\n\n    void operator()( PipelineLayout pipelineLayout )\n    {\n      m_device.destroyPipelineLayout( pipelineLayout, m_allocator );\n    }\n\n  private:\n    Device m_device;\n    Optional<const AllocationCallbacks> m_allocator;\n  };\n\n  class QueryPoolDeleter\n  {\n  public:\n    QueryPoolDeleter( Device device = Device(), Optional<const AllocationCallbacks> allocator = nullptr )\n      : m_device( device )\n      , m_allocator( allocator )\n    {}\n\n    void operator()( QueryPool queryPool )\n    {\n      m_device.destroyQueryPool( queryPool, m_allocator );\n    }\n\n  private:\n    Device m_device;\n    Optional<const AllocationCallbacks> m_allocator;\n  };\n\n  class RenderPassDeleter\n  {\n  public:\n    RenderPassDeleter( Device device = Device(), Optional<const AllocationCallbacks> allocator = nullptr )\n      : m_device( device )\n      , m_allocator( allocator )\n    {}\n\n    void operator()( RenderPass renderPass )\n    {\n      m_device.destroyRenderPass( renderPass, m_allocator );\n    }\n\n  private:\n    Device m_device;\n    Optional<const AllocationCallbacks> m_allocator;\n  };\n\n  class SamplerDeleter\n  {\n  public:\n    SamplerDeleter( Device device = Device(), Optional<const AllocationCallbacks> allocator = nullptr )\n      : m_device( device )\n      , m_allocator( allocator )\n    {}\n\n    void operator()( Sampler sampler )\n    {\n      m_device.destroySampler( sampler, m_allocator );\n    }\n\n  private:\n    Device m_device;\n    Optional<const AllocationCallbacks> m_allocator;\n  };\n\n  class SemaphoreDeleter\n  {\n  public:\n    SemaphoreDeleter( Device device = Device(), Optional<const AllocationCallbacks> allocator = nullptr )\n      : m_device( device )\n      , m_allocator( allocator )\n    {}\n\n    void operator()( Semaphore semaphore )\n    {\n      m_device.destroySemaphore( semaphore, m_allocator );\n    }\n\n  private:\n    Device m_device;\n    Optional<const AllocationCallbacks> m_allocator;\n  };\n\n  class ShaderModuleDeleter\n  {\n  public:\n    ShaderModuleDeleter( Device device = Device(), Optional<const AllocationCallbacks> allocator = nullptr )\n      : m_device( device )\n      , m_allocator( allocator )\n    {}\n\n    void operator()( ShaderModule shaderModule )\n    {\n      m_device.destroyShaderModule( shaderModule, m_allocator );\n    }\n\n  private:\n    Device m_device;\n    Optional<const AllocationCallbacks> m_allocator;\n  };\n\n  class SwapchainKHRDeleter\n  {\n  public:\n    SwapchainKHRDeleter( Device device = Device(), Optional<const AllocationCallbacks> allocator = nullptr )\n      : m_device( device )\n      , m_allocator( allocator )\n    {}\n\n    void operator()( SwapchainKHR swapchainKHR )\n    {\n      m_device.destroySwapchainKHR( swapchainKHR, m_allocator );\n    }\n\n  private:\n    Device m_device;\n    Optional<const AllocationCallbacks> m_allocator;\n  };\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n\n  VULKAN_HPP_INLINE PFN_vkVoidFunction Device::getProcAddr( const char* pName ) const\n  {\n    return vkGetDeviceProcAddr( m_device, pName );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE PFN_vkVoidFunction Device::getProcAddr( const std::string & name ) const\n  {\n    return vkGetDeviceProcAddr( m_device, name.c_str() );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void Device::destroy( const AllocationCallbacks* pAllocator ) const\n  {\n    vkDestroyDevice( m_device, reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void Device::destroy( Optional<const AllocationCallbacks> allocator ) const\n  {\n    vkDestroyDevice( m_device, reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void Device::getQueue( uint32_t queueFamilyIndex, uint32_t queueIndex, Queue* pQueue ) const\n  {\n    vkGetDeviceQueue( m_device, queueFamilyIndex, queueIndex, reinterpret_cast<VkQueue*>( pQueue ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE Queue Device::getQueue( uint32_t queueFamilyIndex, uint32_t queueIndex ) const\n  {\n    Queue queue;\n    vkGetDeviceQueue( m_device, queueFamilyIndex, queueIndex, reinterpret_cast<VkQueue*>( &queue ) );\n    return queue;\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifdef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE Result Device::waitIdle() const\n  {\n    return static_cast<Result>( vkDeviceWaitIdle( m_device ) );\n  }\n#else\n  VULKAN_HPP_INLINE ResultValueType<void>::type Device::waitIdle() const\n  {\n    Result result = static_cast<Result>( vkDeviceWaitIdle( m_device ) );\n    return createResultValue( result, \"vk::Device::waitIdle\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::allocateMemory( const MemoryAllocateInfo* pAllocateInfo, const AllocationCallbacks* pAllocator, DeviceMemory* pMemory ) const\n  {\n    return static_cast<Result>( vkAllocateMemory( m_device, reinterpret_cast<const VkMemoryAllocateInfo*>( pAllocateInfo ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ), reinterpret_cast<VkDeviceMemory*>( pMemory ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<DeviceMemory>::type Device::allocateMemory( const MemoryAllocateInfo & allocateInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    DeviceMemory memory;\n    Result result = static_cast<Result>( vkAllocateMemory( m_device, reinterpret_cast<const VkMemoryAllocateInfo*>( &allocateInfo ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkDeviceMemory*>( &memory ) ) );\n    return createResultValue( result, memory, \"vk::Device::allocateMemory\" );\n  }\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  VULKAN_HPP_INLINE UniqueDeviceMemory Device::allocateMemoryUnique( const MemoryAllocateInfo & allocateInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    DeviceMemoryDeleter deleter( *this, allocator );\n    return UniqueDeviceMemory( allocateMemory( allocateInfo, allocator ), deleter );\n  }\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void Device::freeMemory( DeviceMemory memory, const AllocationCallbacks* pAllocator ) const\n  {\n    vkFreeMemory( m_device, static_cast<VkDeviceMemory>( memory ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void Device::freeMemory( DeviceMemory memory, Optional<const AllocationCallbacks> allocator ) const\n  {\n    vkFreeMemory( m_device, static_cast<VkDeviceMemory>( memory ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::mapMemory( DeviceMemory memory, DeviceSize offset, DeviceSize size, MemoryMapFlags flags, void** ppData ) const\n  {\n    return static_cast<Result>( vkMapMemory( m_device, static_cast<VkDeviceMemory>( memory ), offset, size, static_cast<VkMemoryMapFlags>( flags ), ppData ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<void*>::type Device::mapMemory( DeviceMemory memory, DeviceSize offset, DeviceSize size, MemoryMapFlags flags ) const\n  {\n    void* pData;\n    Result result = static_cast<Result>( vkMapMemory( m_device, static_cast<VkDeviceMemory>( memory ), offset, size, static_cast<VkMemoryMapFlags>( flags ), &pData ) );\n    return createResultValue( result, pData, \"vk::Device::mapMemory\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void Device::unmapMemory( DeviceMemory memory ) const\n  {\n    vkUnmapMemory( m_device, static_cast<VkDeviceMemory>( memory ) );\n  }\n\n  VULKAN_HPP_INLINE Result Device::flushMappedMemoryRanges( uint32_t memoryRangeCount, const MappedMemoryRange* pMemoryRanges ) const\n  {\n    return static_cast<Result>( vkFlushMappedMemoryRanges( m_device, memoryRangeCount, reinterpret_cast<const VkMappedMemoryRange*>( pMemoryRanges ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<void>::type Device::flushMappedMemoryRanges( ArrayProxy<const MappedMemoryRange> memoryRanges ) const\n  {\n    Result result = static_cast<Result>( vkFlushMappedMemoryRanges( m_device, memoryRanges.size() , reinterpret_cast<const VkMappedMemoryRange*>( memoryRanges.data() ) ) );\n    return createResultValue( result, \"vk::Device::flushMappedMemoryRanges\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::invalidateMappedMemoryRanges( uint32_t memoryRangeCount, const MappedMemoryRange* pMemoryRanges ) const\n  {\n    return static_cast<Result>( vkInvalidateMappedMemoryRanges( m_device, memoryRangeCount, reinterpret_cast<const VkMappedMemoryRange*>( pMemoryRanges ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<void>::type Device::invalidateMappedMemoryRanges( ArrayProxy<const MappedMemoryRange> memoryRanges ) const\n  {\n    Result result = static_cast<Result>( vkInvalidateMappedMemoryRanges( m_device, memoryRanges.size() , reinterpret_cast<const VkMappedMemoryRange*>( memoryRanges.data() ) ) );\n    return createResultValue( result, \"vk::Device::invalidateMappedMemoryRanges\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void Device::getMemoryCommitment( DeviceMemory memory, DeviceSize* pCommittedMemoryInBytes ) const\n  {\n    vkGetDeviceMemoryCommitment( m_device, static_cast<VkDeviceMemory>( memory ), pCommittedMemoryInBytes );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE DeviceSize Device::getMemoryCommitment( DeviceMemory memory ) const\n  {\n    DeviceSize committedMemoryInBytes;\n    vkGetDeviceMemoryCommitment( m_device, static_cast<VkDeviceMemory>( memory ), &committedMemoryInBytes );\n    return committedMemoryInBytes;\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void Device::getBufferMemoryRequirements( Buffer buffer, MemoryRequirements* pMemoryRequirements ) const\n  {\n    vkGetBufferMemoryRequirements( m_device, static_cast<VkBuffer>( buffer ), reinterpret_cast<VkMemoryRequirements*>( pMemoryRequirements ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE MemoryRequirements Device::getBufferMemoryRequirements( Buffer buffer ) const\n  {\n    MemoryRequirements memoryRequirements;\n    vkGetBufferMemoryRequirements( m_device, static_cast<VkBuffer>( buffer ), reinterpret_cast<VkMemoryRequirements*>( &memoryRequirements ) );\n    return memoryRequirements;\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifdef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE Result Device::bindBufferMemory( Buffer buffer, DeviceMemory memory, DeviceSize memoryOffset ) const\n  {\n    return static_cast<Result>( vkBindBufferMemory( m_device, static_cast<VkBuffer>( buffer ), static_cast<VkDeviceMemory>( memory ), memoryOffset ) );\n  }\n#else\n  VULKAN_HPP_INLINE ResultValueType<void>::type Device::bindBufferMemory( Buffer buffer, DeviceMemory memory, DeviceSize memoryOffset ) const\n  {\n    Result result = static_cast<Result>( vkBindBufferMemory( m_device, static_cast<VkBuffer>( buffer ), static_cast<VkDeviceMemory>( memory ), memoryOffset ) );\n    return createResultValue( result, \"vk::Device::bindBufferMemory\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void Device::getImageMemoryRequirements( Image image, MemoryRequirements* pMemoryRequirements ) const\n  {\n    vkGetImageMemoryRequirements( m_device, static_cast<VkImage>( image ), reinterpret_cast<VkMemoryRequirements*>( pMemoryRequirements ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE MemoryRequirements Device::getImageMemoryRequirements( Image image ) const\n  {\n    MemoryRequirements memoryRequirements;\n    vkGetImageMemoryRequirements( m_device, static_cast<VkImage>( image ), reinterpret_cast<VkMemoryRequirements*>( &memoryRequirements ) );\n    return memoryRequirements;\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifdef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE Result Device::bindImageMemory( Image image, DeviceMemory memory, DeviceSize memoryOffset ) const\n  {\n    return static_cast<Result>( vkBindImageMemory( m_device, static_cast<VkImage>( image ), static_cast<VkDeviceMemory>( memory ), memoryOffset ) );\n  }\n#else\n  VULKAN_HPP_INLINE ResultValueType<void>::type Device::bindImageMemory( Image image, DeviceMemory memory, DeviceSize memoryOffset ) const\n  {\n    Result result = static_cast<Result>( vkBindImageMemory( m_device, static_cast<VkImage>( image ), static_cast<VkDeviceMemory>( memory ), memoryOffset ) );\n    return createResultValue( result, \"vk::Device::bindImageMemory\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void Device::getImageSparseMemoryRequirements( Image image, uint32_t* pSparseMemoryRequirementCount, SparseImageMemoryRequirements* pSparseMemoryRequirements ) const\n  {\n    vkGetImageSparseMemoryRequirements( m_device, static_cast<VkImage>( image ), pSparseMemoryRequirementCount, reinterpret_cast<VkSparseImageMemoryRequirements*>( pSparseMemoryRequirements ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  template <typename Allocator> \n  VULKAN_HPP_INLINE std::vector<SparseImageMemoryRequirements,Allocator> Device::getImageSparseMemoryRequirements( Image image ) const\n  {\n    std::vector<SparseImageMemoryRequirements,Allocator> sparseMemoryRequirements;\n    uint32_t sparseMemoryRequirementCount;\n    vkGetImageSparseMemoryRequirements( m_device, static_cast<VkImage>( image ), &sparseMemoryRequirementCount, nullptr );\n    sparseMemoryRequirements.resize( sparseMemoryRequirementCount );\n    vkGetImageSparseMemoryRequirements( m_device, static_cast<VkImage>( image ), &sparseMemoryRequirementCount, reinterpret_cast<VkSparseImageMemoryRequirements*>( sparseMemoryRequirements.data() ) );\n    return sparseMemoryRequirements;\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::createFence( const FenceCreateInfo* pCreateInfo, const AllocationCallbacks* pAllocator, Fence* pFence ) const\n  {\n    return static_cast<Result>( vkCreateFence( m_device, reinterpret_cast<const VkFenceCreateInfo*>( pCreateInfo ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ), reinterpret_cast<VkFence*>( pFence ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<Fence>::type Device::createFence( const FenceCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    Fence fence;\n    Result result = static_cast<Result>( vkCreateFence( m_device, reinterpret_cast<const VkFenceCreateInfo*>( &createInfo ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkFence*>( &fence ) ) );\n    return createResultValue( result, fence, \"vk::Device::createFence\" );\n  }\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  VULKAN_HPP_INLINE UniqueFence Device::createFenceUnique( const FenceCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    FenceDeleter deleter( *this, allocator );\n    return UniqueFence( createFence( createInfo, allocator ), deleter );\n  }\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void Device::destroyFence( Fence fence, const AllocationCallbacks* pAllocator ) const\n  {\n    vkDestroyFence( m_device, static_cast<VkFence>( fence ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void Device::destroyFence( Fence fence, Optional<const AllocationCallbacks> allocator ) const\n  {\n    vkDestroyFence( m_device, static_cast<VkFence>( fence ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::resetFences( uint32_t fenceCount, const Fence* pFences ) const\n  {\n    return static_cast<Result>( vkResetFences( m_device, fenceCount, reinterpret_cast<const VkFence*>( pFences ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<void>::type Device::resetFences( ArrayProxy<const Fence> fences ) const\n  {\n    Result result = static_cast<Result>( vkResetFences( m_device, fences.size() , reinterpret_cast<const VkFence*>( fences.data() ) ) );\n    return createResultValue( result, \"vk::Device::resetFences\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifdef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE Result Device::getFenceStatus( Fence fence ) const\n  {\n    return static_cast<Result>( vkGetFenceStatus( m_device, static_cast<VkFence>( fence ) ) );\n  }\n#else\n  VULKAN_HPP_INLINE Result Device::getFenceStatus( Fence fence ) const\n  {\n    Result result = static_cast<Result>( vkGetFenceStatus( m_device, static_cast<VkFence>( fence ) ) );\n    return createResultValue( result, \"vk::Device::getFenceStatus\", { Result::eSuccess, Result::eNotReady } );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::waitForFences( uint32_t fenceCount, const Fence* pFences, Bool32 waitAll, uint64_t timeout ) const\n  {\n    return static_cast<Result>( vkWaitForFences( m_device, fenceCount, reinterpret_cast<const VkFence*>( pFences ), waitAll, timeout ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE Result Device::waitForFences( ArrayProxy<const Fence> fences, Bool32 waitAll, uint64_t timeout ) const\n  {\n    Result result = static_cast<Result>( vkWaitForFences( m_device, fences.size() , reinterpret_cast<const VkFence*>( fences.data() ), waitAll, timeout ) );\n    return createResultValue( result, \"vk::Device::waitForFences\", { Result::eSuccess, Result::eTimeout } );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::createSemaphore( const SemaphoreCreateInfo* pCreateInfo, const AllocationCallbacks* pAllocator, Semaphore* pSemaphore ) const\n  {\n    return static_cast<Result>( vkCreateSemaphore( m_device, reinterpret_cast<const VkSemaphoreCreateInfo*>( pCreateInfo ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ), reinterpret_cast<VkSemaphore*>( pSemaphore ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<Semaphore>::type Device::createSemaphore( const SemaphoreCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    Semaphore semaphore;\n    Result result = static_cast<Result>( vkCreateSemaphore( m_device, reinterpret_cast<const VkSemaphoreCreateInfo*>( &createInfo ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkSemaphore*>( &semaphore ) ) );\n    return createResultValue( result, semaphore, \"vk::Device::createSemaphore\" );\n  }\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  VULKAN_HPP_INLINE UniqueSemaphore Device::createSemaphoreUnique( const SemaphoreCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    SemaphoreDeleter deleter( *this, allocator );\n    return UniqueSemaphore( createSemaphore( createInfo, allocator ), deleter );\n  }\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void Device::destroySemaphore( Semaphore semaphore, const AllocationCallbacks* pAllocator ) const\n  {\n    vkDestroySemaphore( m_device, static_cast<VkSemaphore>( semaphore ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void Device::destroySemaphore( Semaphore semaphore, Optional<const AllocationCallbacks> allocator ) const\n  {\n    vkDestroySemaphore( m_device, static_cast<VkSemaphore>( semaphore ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::createEvent( const EventCreateInfo* pCreateInfo, const AllocationCallbacks* pAllocator, Event* pEvent ) const\n  {\n    return static_cast<Result>( vkCreateEvent( m_device, reinterpret_cast<const VkEventCreateInfo*>( pCreateInfo ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ), reinterpret_cast<VkEvent*>( pEvent ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<Event>::type Device::createEvent( const EventCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    Event event;\n    Result result = static_cast<Result>( vkCreateEvent( m_device, reinterpret_cast<const VkEventCreateInfo*>( &createInfo ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkEvent*>( &event ) ) );\n    return createResultValue( result, event, \"vk::Device::createEvent\" );\n  }\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  VULKAN_HPP_INLINE UniqueEvent Device::createEventUnique( const EventCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    EventDeleter deleter( *this, allocator );\n    return UniqueEvent( createEvent( createInfo, allocator ), deleter );\n  }\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void Device::destroyEvent( Event event, const AllocationCallbacks* pAllocator ) const\n  {\n    vkDestroyEvent( m_device, static_cast<VkEvent>( event ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void Device::destroyEvent( Event event, Optional<const AllocationCallbacks> allocator ) const\n  {\n    vkDestroyEvent( m_device, static_cast<VkEvent>( event ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifdef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE Result Device::getEventStatus( Event event ) const\n  {\n    return static_cast<Result>( vkGetEventStatus( m_device, static_cast<VkEvent>( event ) ) );\n  }\n#else\n  VULKAN_HPP_INLINE Result Device::getEventStatus( Event event ) const\n  {\n    Result result = static_cast<Result>( vkGetEventStatus( m_device, static_cast<VkEvent>( event ) ) );\n    return createResultValue( result, \"vk::Device::getEventStatus\", { Result::eEventSet, Result::eEventReset } );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifdef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE Result Device::setEvent( Event event ) const\n  {\n    return static_cast<Result>( vkSetEvent( m_device, static_cast<VkEvent>( event ) ) );\n  }\n#else\n  VULKAN_HPP_INLINE ResultValueType<void>::type Device::setEvent( Event event ) const\n  {\n    Result result = static_cast<Result>( vkSetEvent( m_device, static_cast<VkEvent>( event ) ) );\n    return createResultValue( result, \"vk::Device::setEvent\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifdef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE Result Device::resetEvent( Event event ) const\n  {\n    return static_cast<Result>( vkResetEvent( m_device, static_cast<VkEvent>( event ) ) );\n  }\n#else\n  VULKAN_HPP_INLINE ResultValueType<void>::type Device::resetEvent( Event event ) const\n  {\n    Result result = static_cast<Result>( vkResetEvent( m_device, static_cast<VkEvent>( event ) ) );\n    return createResultValue( result, \"vk::Device::resetEvent\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::createQueryPool( const QueryPoolCreateInfo* pCreateInfo, const AllocationCallbacks* pAllocator, QueryPool* pQueryPool ) const\n  {\n    return static_cast<Result>( vkCreateQueryPool( m_device, reinterpret_cast<const VkQueryPoolCreateInfo*>( pCreateInfo ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ), reinterpret_cast<VkQueryPool*>( pQueryPool ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<QueryPool>::type Device::createQueryPool( const QueryPoolCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    QueryPool queryPool;\n    Result result = static_cast<Result>( vkCreateQueryPool( m_device, reinterpret_cast<const VkQueryPoolCreateInfo*>( &createInfo ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkQueryPool*>( &queryPool ) ) );\n    return createResultValue( result, queryPool, \"vk::Device::createQueryPool\" );\n  }\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  VULKAN_HPP_INLINE UniqueQueryPool Device::createQueryPoolUnique( const QueryPoolCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    QueryPoolDeleter deleter( *this, allocator );\n    return UniqueQueryPool( createQueryPool( createInfo, allocator ), deleter );\n  }\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void Device::destroyQueryPool( QueryPool queryPool, const AllocationCallbacks* pAllocator ) const\n  {\n    vkDestroyQueryPool( m_device, static_cast<VkQueryPool>( queryPool ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void Device::destroyQueryPool( QueryPool queryPool, Optional<const AllocationCallbacks> allocator ) const\n  {\n    vkDestroyQueryPool( m_device, static_cast<VkQueryPool>( queryPool ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::getQueryPoolResults( QueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, size_t dataSize, void* pData, DeviceSize stride, QueryResultFlags flags ) const\n  {\n    return static_cast<Result>( vkGetQueryPoolResults( m_device, static_cast<VkQueryPool>( queryPool ), firstQuery, queryCount, dataSize, pData, stride, static_cast<VkQueryResultFlags>( flags ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  template <typename T>\n  VULKAN_HPP_INLINE Result Device::getQueryPoolResults( QueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, ArrayProxy<T> data, DeviceSize stride, QueryResultFlags flags ) const\n  {\n    Result result = static_cast<Result>( vkGetQueryPoolResults( m_device, static_cast<VkQueryPool>( queryPool ), firstQuery, queryCount, data.size() * sizeof( T ) , reinterpret_cast<void*>( data.data() ), stride, static_cast<VkQueryResultFlags>( flags ) ) );\n    return createResultValue( result, \"vk::Device::getQueryPoolResults\", { Result::eSuccess, Result::eNotReady } );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::createBuffer( const BufferCreateInfo* pCreateInfo, const AllocationCallbacks* pAllocator, Buffer* pBuffer ) const\n  {\n    return static_cast<Result>( vkCreateBuffer( m_device, reinterpret_cast<const VkBufferCreateInfo*>( pCreateInfo ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ), reinterpret_cast<VkBuffer*>( pBuffer ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<Buffer>::type Device::createBuffer( const BufferCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    Buffer buffer;\n    Result result = static_cast<Result>( vkCreateBuffer( m_device, reinterpret_cast<const VkBufferCreateInfo*>( &createInfo ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkBuffer*>( &buffer ) ) );\n    return createResultValue( result, buffer, \"vk::Device::createBuffer\" );\n  }\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  VULKAN_HPP_INLINE UniqueBuffer Device::createBufferUnique( const BufferCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    BufferDeleter deleter( *this, allocator );\n    return UniqueBuffer( createBuffer( createInfo, allocator ), deleter );\n  }\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void Device::destroyBuffer( Buffer buffer, const AllocationCallbacks* pAllocator ) const\n  {\n    vkDestroyBuffer( m_device, static_cast<VkBuffer>( buffer ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void Device::destroyBuffer( Buffer buffer, Optional<const AllocationCallbacks> allocator ) const\n  {\n    vkDestroyBuffer( m_device, static_cast<VkBuffer>( buffer ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::createBufferView( const BufferViewCreateInfo* pCreateInfo, const AllocationCallbacks* pAllocator, BufferView* pView ) const\n  {\n    return static_cast<Result>( vkCreateBufferView( m_device, reinterpret_cast<const VkBufferViewCreateInfo*>( pCreateInfo ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ), reinterpret_cast<VkBufferView*>( pView ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<BufferView>::type Device::createBufferView( const BufferViewCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    BufferView view;\n    Result result = static_cast<Result>( vkCreateBufferView( m_device, reinterpret_cast<const VkBufferViewCreateInfo*>( &createInfo ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkBufferView*>( &view ) ) );\n    return createResultValue( result, view, \"vk::Device::createBufferView\" );\n  }\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  VULKAN_HPP_INLINE UniqueBufferView Device::createBufferViewUnique( const BufferViewCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    BufferViewDeleter deleter( *this, allocator );\n    return UniqueBufferView( createBufferView( createInfo, allocator ), deleter );\n  }\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void Device::destroyBufferView( BufferView bufferView, const AllocationCallbacks* pAllocator ) const\n  {\n    vkDestroyBufferView( m_device, static_cast<VkBufferView>( bufferView ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void Device::destroyBufferView( BufferView bufferView, Optional<const AllocationCallbacks> allocator ) const\n  {\n    vkDestroyBufferView( m_device, static_cast<VkBufferView>( bufferView ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::createImage( const ImageCreateInfo* pCreateInfo, const AllocationCallbacks* pAllocator, Image* pImage ) const\n  {\n    return static_cast<Result>( vkCreateImage( m_device, reinterpret_cast<const VkImageCreateInfo*>( pCreateInfo ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ), reinterpret_cast<VkImage*>( pImage ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<Image>::type Device::createImage( const ImageCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    Image image;\n    Result result = static_cast<Result>( vkCreateImage( m_device, reinterpret_cast<const VkImageCreateInfo*>( &createInfo ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkImage*>( &image ) ) );\n    return createResultValue( result, image, \"vk::Device::createImage\" );\n  }\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  VULKAN_HPP_INLINE UniqueImage Device::createImageUnique( const ImageCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    ImageDeleter deleter( *this, allocator );\n    return UniqueImage( createImage( createInfo, allocator ), deleter );\n  }\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void Device::destroyImage( Image image, const AllocationCallbacks* pAllocator ) const\n  {\n    vkDestroyImage( m_device, static_cast<VkImage>( image ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void Device::destroyImage( Image image, Optional<const AllocationCallbacks> allocator ) const\n  {\n    vkDestroyImage( m_device, static_cast<VkImage>( image ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void Device::getImageSubresourceLayout( Image image, const ImageSubresource* pSubresource, SubresourceLayout* pLayout ) const\n  {\n    vkGetImageSubresourceLayout( m_device, static_cast<VkImage>( image ), reinterpret_cast<const VkImageSubresource*>( pSubresource ), reinterpret_cast<VkSubresourceLayout*>( pLayout ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE SubresourceLayout Device::getImageSubresourceLayout( Image image, const ImageSubresource & subresource ) const\n  {\n    SubresourceLayout layout;\n    vkGetImageSubresourceLayout( m_device, static_cast<VkImage>( image ), reinterpret_cast<const VkImageSubresource*>( &subresource ), reinterpret_cast<VkSubresourceLayout*>( &layout ) );\n    return layout;\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::createImageView( const ImageViewCreateInfo* pCreateInfo, const AllocationCallbacks* pAllocator, ImageView* pView ) const\n  {\n    return static_cast<Result>( vkCreateImageView( m_device, reinterpret_cast<const VkImageViewCreateInfo*>( pCreateInfo ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ), reinterpret_cast<VkImageView*>( pView ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<ImageView>::type Device::createImageView( const ImageViewCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    ImageView view;\n    Result result = static_cast<Result>( vkCreateImageView( m_device, reinterpret_cast<const VkImageViewCreateInfo*>( &createInfo ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkImageView*>( &view ) ) );\n    return createResultValue( result, view, \"vk::Device::createImageView\" );\n  }\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  VULKAN_HPP_INLINE UniqueImageView Device::createImageViewUnique( const ImageViewCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    ImageViewDeleter deleter( *this, allocator );\n    return UniqueImageView( createImageView( createInfo, allocator ), deleter );\n  }\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void Device::destroyImageView( ImageView imageView, const AllocationCallbacks* pAllocator ) const\n  {\n    vkDestroyImageView( m_device, static_cast<VkImageView>( imageView ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void Device::destroyImageView( ImageView imageView, Optional<const AllocationCallbacks> allocator ) const\n  {\n    vkDestroyImageView( m_device, static_cast<VkImageView>( imageView ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::createShaderModule( const ShaderModuleCreateInfo* pCreateInfo, const AllocationCallbacks* pAllocator, ShaderModule* pShaderModule ) const\n  {\n    return static_cast<Result>( vkCreateShaderModule( m_device, reinterpret_cast<const VkShaderModuleCreateInfo*>( pCreateInfo ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ), reinterpret_cast<VkShaderModule*>( pShaderModule ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<ShaderModule>::type Device::createShaderModule( const ShaderModuleCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    ShaderModule shaderModule;\n    Result result = static_cast<Result>( vkCreateShaderModule( m_device, reinterpret_cast<const VkShaderModuleCreateInfo*>( &createInfo ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkShaderModule*>( &shaderModule ) ) );\n    return createResultValue( result, shaderModule, \"vk::Device::createShaderModule\" );\n  }\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  VULKAN_HPP_INLINE UniqueShaderModule Device::createShaderModuleUnique( const ShaderModuleCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    ShaderModuleDeleter deleter( *this, allocator );\n    return UniqueShaderModule( createShaderModule( createInfo, allocator ), deleter );\n  }\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void Device::destroyShaderModule( ShaderModule shaderModule, const AllocationCallbacks* pAllocator ) const\n  {\n    vkDestroyShaderModule( m_device, static_cast<VkShaderModule>( shaderModule ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void Device::destroyShaderModule( ShaderModule shaderModule, Optional<const AllocationCallbacks> allocator ) const\n  {\n    vkDestroyShaderModule( m_device, static_cast<VkShaderModule>( shaderModule ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::createPipelineCache( const PipelineCacheCreateInfo* pCreateInfo, const AllocationCallbacks* pAllocator, PipelineCache* pPipelineCache ) const\n  {\n    return static_cast<Result>( vkCreatePipelineCache( m_device, reinterpret_cast<const VkPipelineCacheCreateInfo*>( pCreateInfo ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ), reinterpret_cast<VkPipelineCache*>( pPipelineCache ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<PipelineCache>::type Device::createPipelineCache( const PipelineCacheCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    PipelineCache pipelineCache;\n    Result result = static_cast<Result>( vkCreatePipelineCache( m_device, reinterpret_cast<const VkPipelineCacheCreateInfo*>( &createInfo ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkPipelineCache*>( &pipelineCache ) ) );\n    return createResultValue( result, pipelineCache, \"vk::Device::createPipelineCache\" );\n  }\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  VULKAN_HPP_INLINE UniquePipelineCache Device::createPipelineCacheUnique( const PipelineCacheCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    PipelineCacheDeleter deleter( *this, allocator );\n    return UniquePipelineCache( createPipelineCache( createInfo, allocator ), deleter );\n  }\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void Device::destroyPipelineCache( PipelineCache pipelineCache, const AllocationCallbacks* pAllocator ) const\n  {\n    vkDestroyPipelineCache( m_device, static_cast<VkPipelineCache>( pipelineCache ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void Device::destroyPipelineCache( PipelineCache pipelineCache, Optional<const AllocationCallbacks> allocator ) const\n  {\n    vkDestroyPipelineCache( m_device, static_cast<VkPipelineCache>( pipelineCache ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::getPipelineCacheData( PipelineCache pipelineCache, size_t* pDataSize, void* pData ) const\n  {\n    return static_cast<Result>( vkGetPipelineCacheData( m_device, static_cast<VkPipelineCache>( pipelineCache ), pDataSize, pData ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  template <typename Allocator> \n  VULKAN_HPP_INLINE typename ResultValueType<std::vector<uint8_t,Allocator>>::type Device::getPipelineCacheData( PipelineCache pipelineCache ) const\n  {\n    std::vector<uint8_t,Allocator> data;\n    size_t dataSize;\n    Result result;\n    do\n    {\n      result = static_cast<Result>( vkGetPipelineCacheData( m_device, static_cast<VkPipelineCache>( pipelineCache ), &dataSize, nullptr ) );\n      if ( ( result == Result::eSuccess ) && dataSize )\n      {\n        data.resize( dataSize );\n        result = static_cast<Result>( vkGetPipelineCacheData( m_device, static_cast<VkPipelineCache>( pipelineCache ), &dataSize, reinterpret_cast<void*>( data.data() ) ) );\n      }\n    } while ( result == Result::eIncomplete );\n    assert( dataSize <= data.size() ); \n    data.resize( dataSize ); \n    return createResultValue( result, data, \"vk::Device::getPipelineCacheData\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::mergePipelineCaches( PipelineCache dstCache, uint32_t srcCacheCount, const PipelineCache* pSrcCaches ) const\n  {\n    return static_cast<Result>( vkMergePipelineCaches( m_device, static_cast<VkPipelineCache>( dstCache ), srcCacheCount, reinterpret_cast<const VkPipelineCache*>( pSrcCaches ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<void>::type Device::mergePipelineCaches( PipelineCache dstCache, ArrayProxy<const PipelineCache> srcCaches ) const\n  {\n    Result result = static_cast<Result>( vkMergePipelineCaches( m_device, static_cast<VkPipelineCache>( dstCache ), srcCaches.size() , reinterpret_cast<const VkPipelineCache*>( srcCaches.data() ) ) );\n    return createResultValue( result, \"vk::Device::mergePipelineCaches\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::createGraphicsPipelines( PipelineCache pipelineCache, uint32_t createInfoCount, const GraphicsPipelineCreateInfo* pCreateInfos, const AllocationCallbacks* pAllocator, Pipeline* pPipelines ) const\n  {\n    return static_cast<Result>( vkCreateGraphicsPipelines( m_device, static_cast<VkPipelineCache>( pipelineCache ), createInfoCount, reinterpret_cast<const VkGraphicsPipelineCreateInfo*>( pCreateInfos ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ), reinterpret_cast<VkPipeline*>( pPipelines ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  template <typename Allocator> \n  VULKAN_HPP_INLINE typename ResultValueType<std::vector<Pipeline,Allocator>>::type Device::createGraphicsPipelines( PipelineCache pipelineCache, ArrayProxy<const GraphicsPipelineCreateInfo> createInfos, Optional<const AllocationCallbacks> allocator ) const\n  {\n    std::vector<Pipeline,Allocator> pipelines( createInfos.size() );\n    Result result = static_cast<Result>( vkCreateGraphicsPipelines( m_device, static_cast<VkPipelineCache>( pipelineCache ), createInfos.size() , reinterpret_cast<const VkGraphicsPipelineCreateInfo*>( createInfos.data() ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkPipeline*>( pipelines.data() ) ) );\n    return createResultValue( result, pipelines, \"vk::Device::createGraphicsPipelines\" );\n  }\n  VULKAN_HPP_INLINE ResultValueType<Pipeline>::type Device::createGraphicsPipeline( PipelineCache pipelineCache, const GraphicsPipelineCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    Pipeline pipeline;\n    Result result = static_cast<Result>( vkCreateGraphicsPipelines( m_device, static_cast<VkPipelineCache>( pipelineCache ), 1 , reinterpret_cast<const VkGraphicsPipelineCreateInfo*>( &createInfo ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkPipeline*>( &pipeline ) ) );\n    return createResultValue( result, pipeline, \"vk::Device::createGraphicsPipeline\" );\n  }\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  template <typename Allocator> \n  VULKAN_HPP_INLINE std::vector<UniquePipeline> Device::createGraphicsPipelinesUnique( PipelineCache pipelineCache, ArrayProxy<const GraphicsPipelineCreateInfo> createInfos, Optional<const AllocationCallbacks> allocator ) const\n  {\n    PipelineDeleter deleter( *this, allocator );\n    std::vector<Pipeline,Allocator> pipelines = createGraphicsPipelines( pipelineCache, createInfos, allocator );\n    std::vector<UniquePipeline> uniquePipelines;\n    uniquePipelines.reserve( pipelines.size() );\n    for ( auto pipeline : pipelines )\n    {\n      uniquePipelines.push_back( UniquePipeline( pipeline, deleter ) );\n    }\n    return uniquePipelines;\n  }\n  VULKAN_HPP_INLINE UniquePipeline Device::createGraphicsPipelineUnique( PipelineCache pipelineCache, const GraphicsPipelineCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    PipelineDeleter deleter( *this, allocator );\n    return UniquePipeline( createGraphicsPipeline( pipelineCache, createInfo, allocator ), deleter );\n  }\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::createComputePipelines( PipelineCache pipelineCache, uint32_t createInfoCount, const ComputePipelineCreateInfo* pCreateInfos, const AllocationCallbacks* pAllocator, Pipeline* pPipelines ) const\n  {\n    return static_cast<Result>( vkCreateComputePipelines( m_device, static_cast<VkPipelineCache>( pipelineCache ), createInfoCount, reinterpret_cast<const VkComputePipelineCreateInfo*>( pCreateInfos ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ), reinterpret_cast<VkPipeline*>( pPipelines ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  template <typename Allocator> \n  VULKAN_HPP_INLINE typename ResultValueType<std::vector<Pipeline,Allocator>>::type Device::createComputePipelines( PipelineCache pipelineCache, ArrayProxy<const ComputePipelineCreateInfo> createInfos, Optional<const AllocationCallbacks> allocator ) const\n  {\n    std::vector<Pipeline,Allocator> pipelines( createInfos.size() );\n    Result result = static_cast<Result>( vkCreateComputePipelines( m_device, static_cast<VkPipelineCache>( pipelineCache ), createInfos.size() , reinterpret_cast<const VkComputePipelineCreateInfo*>( createInfos.data() ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkPipeline*>( pipelines.data() ) ) );\n    return createResultValue( result, pipelines, \"vk::Device::createComputePipelines\" );\n  }\n  VULKAN_HPP_INLINE ResultValueType<Pipeline>::type Device::createComputePipeline( PipelineCache pipelineCache, const ComputePipelineCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    Pipeline pipeline;\n    Result result = static_cast<Result>( vkCreateComputePipelines( m_device, static_cast<VkPipelineCache>( pipelineCache ), 1 , reinterpret_cast<const VkComputePipelineCreateInfo*>( &createInfo ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkPipeline*>( &pipeline ) ) );\n    return createResultValue( result, pipeline, \"vk::Device::createComputePipeline\" );\n  }\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  template <typename Allocator> \n  VULKAN_HPP_INLINE std::vector<UniquePipeline> Device::createComputePipelinesUnique( PipelineCache pipelineCache, ArrayProxy<const ComputePipelineCreateInfo> createInfos, Optional<const AllocationCallbacks> allocator ) const\n  {\n    PipelineDeleter deleter( *this, allocator );\n    std::vector<Pipeline,Allocator> pipelines = createComputePipelines( pipelineCache, createInfos, allocator );\n    std::vector<UniquePipeline> uniquePipelines;\n    uniquePipelines.reserve( pipelines.size() );\n    for ( auto pipeline : pipelines )\n    {\n      uniquePipelines.push_back( UniquePipeline( pipeline, deleter ) );\n    }\n    return uniquePipelines;\n  }\n  VULKAN_HPP_INLINE UniquePipeline Device::createComputePipelineUnique( PipelineCache pipelineCache, const ComputePipelineCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    PipelineDeleter deleter( *this, allocator );\n    return UniquePipeline( createComputePipeline( pipelineCache, createInfo, allocator ), deleter );\n  }\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void Device::destroyPipeline( Pipeline pipeline, const AllocationCallbacks* pAllocator ) const\n  {\n    vkDestroyPipeline( m_device, static_cast<VkPipeline>( pipeline ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void Device::destroyPipeline( Pipeline pipeline, Optional<const AllocationCallbacks> allocator ) const\n  {\n    vkDestroyPipeline( m_device, static_cast<VkPipeline>( pipeline ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::createPipelineLayout( const PipelineLayoutCreateInfo* pCreateInfo, const AllocationCallbacks* pAllocator, PipelineLayout* pPipelineLayout ) const\n  {\n    return static_cast<Result>( vkCreatePipelineLayout( m_device, reinterpret_cast<const VkPipelineLayoutCreateInfo*>( pCreateInfo ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ), reinterpret_cast<VkPipelineLayout*>( pPipelineLayout ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<PipelineLayout>::type Device::createPipelineLayout( const PipelineLayoutCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    PipelineLayout pipelineLayout;\n    Result result = static_cast<Result>( vkCreatePipelineLayout( m_device, reinterpret_cast<const VkPipelineLayoutCreateInfo*>( &createInfo ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkPipelineLayout*>( &pipelineLayout ) ) );\n    return createResultValue( result, pipelineLayout, \"vk::Device::createPipelineLayout\" );\n  }\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  VULKAN_HPP_INLINE UniquePipelineLayout Device::createPipelineLayoutUnique( const PipelineLayoutCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    PipelineLayoutDeleter deleter( *this, allocator );\n    return UniquePipelineLayout( createPipelineLayout( createInfo, allocator ), deleter );\n  }\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void Device::destroyPipelineLayout( PipelineLayout pipelineLayout, const AllocationCallbacks* pAllocator ) const\n  {\n    vkDestroyPipelineLayout( m_device, static_cast<VkPipelineLayout>( pipelineLayout ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void Device::destroyPipelineLayout( PipelineLayout pipelineLayout, Optional<const AllocationCallbacks> allocator ) const\n  {\n    vkDestroyPipelineLayout( m_device, static_cast<VkPipelineLayout>( pipelineLayout ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::createSampler( const SamplerCreateInfo* pCreateInfo, const AllocationCallbacks* pAllocator, Sampler* pSampler ) const\n  {\n    return static_cast<Result>( vkCreateSampler( m_device, reinterpret_cast<const VkSamplerCreateInfo*>( pCreateInfo ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ), reinterpret_cast<VkSampler*>( pSampler ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<Sampler>::type Device::createSampler( const SamplerCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    Sampler sampler;\n    Result result = static_cast<Result>( vkCreateSampler( m_device, reinterpret_cast<const VkSamplerCreateInfo*>( &createInfo ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkSampler*>( &sampler ) ) );\n    return createResultValue( result, sampler, \"vk::Device::createSampler\" );\n  }\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  VULKAN_HPP_INLINE UniqueSampler Device::createSamplerUnique( const SamplerCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    SamplerDeleter deleter( *this, allocator );\n    return UniqueSampler( createSampler( createInfo, allocator ), deleter );\n  }\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void Device::destroySampler( Sampler sampler, const AllocationCallbacks* pAllocator ) const\n  {\n    vkDestroySampler( m_device, static_cast<VkSampler>( sampler ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void Device::destroySampler( Sampler sampler, Optional<const AllocationCallbacks> allocator ) const\n  {\n    vkDestroySampler( m_device, static_cast<VkSampler>( sampler ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::createDescriptorSetLayout( const DescriptorSetLayoutCreateInfo* pCreateInfo, const AllocationCallbacks* pAllocator, DescriptorSetLayout* pSetLayout ) const\n  {\n    return static_cast<Result>( vkCreateDescriptorSetLayout( m_device, reinterpret_cast<const VkDescriptorSetLayoutCreateInfo*>( pCreateInfo ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ), reinterpret_cast<VkDescriptorSetLayout*>( pSetLayout ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<DescriptorSetLayout>::type Device::createDescriptorSetLayout( const DescriptorSetLayoutCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    DescriptorSetLayout setLayout;\n    Result result = static_cast<Result>( vkCreateDescriptorSetLayout( m_device, reinterpret_cast<const VkDescriptorSetLayoutCreateInfo*>( &createInfo ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkDescriptorSetLayout*>( &setLayout ) ) );\n    return createResultValue( result, setLayout, \"vk::Device::createDescriptorSetLayout\" );\n  }\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  VULKAN_HPP_INLINE UniqueDescriptorSetLayout Device::createDescriptorSetLayoutUnique( const DescriptorSetLayoutCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    DescriptorSetLayoutDeleter deleter( *this, allocator );\n    return UniqueDescriptorSetLayout( createDescriptorSetLayout( createInfo, allocator ), deleter );\n  }\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void Device::destroyDescriptorSetLayout( DescriptorSetLayout descriptorSetLayout, const AllocationCallbacks* pAllocator ) const\n  {\n    vkDestroyDescriptorSetLayout( m_device, static_cast<VkDescriptorSetLayout>( descriptorSetLayout ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void Device::destroyDescriptorSetLayout( DescriptorSetLayout descriptorSetLayout, Optional<const AllocationCallbacks> allocator ) const\n  {\n    vkDestroyDescriptorSetLayout( m_device, static_cast<VkDescriptorSetLayout>( descriptorSetLayout ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::createDescriptorPool( const DescriptorPoolCreateInfo* pCreateInfo, const AllocationCallbacks* pAllocator, DescriptorPool* pDescriptorPool ) const\n  {\n    return static_cast<Result>( vkCreateDescriptorPool( m_device, reinterpret_cast<const VkDescriptorPoolCreateInfo*>( pCreateInfo ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ), reinterpret_cast<VkDescriptorPool*>( pDescriptorPool ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<DescriptorPool>::type Device::createDescriptorPool( const DescriptorPoolCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    DescriptorPool descriptorPool;\n    Result result = static_cast<Result>( vkCreateDescriptorPool( m_device, reinterpret_cast<const VkDescriptorPoolCreateInfo*>( &createInfo ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkDescriptorPool*>( &descriptorPool ) ) );\n    return createResultValue( result, descriptorPool, \"vk::Device::createDescriptorPool\" );\n  }\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  VULKAN_HPP_INLINE UniqueDescriptorPool Device::createDescriptorPoolUnique( const DescriptorPoolCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    DescriptorPoolDeleter deleter( *this, allocator );\n    return UniqueDescriptorPool( createDescriptorPool( createInfo, allocator ), deleter );\n  }\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void Device::destroyDescriptorPool( DescriptorPool descriptorPool, const AllocationCallbacks* pAllocator ) const\n  {\n    vkDestroyDescriptorPool( m_device, static_cast<VkDescriptorPool>( descriptorPool ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void Device::destroyDescriptorPool( DescriptorPool descriptorPool, Optional<const AllocationCallbacks> allocator ) const\n  {\n    vkDestroyDescriptorPool( m_device, static_cast<VkDescriptorPool>( descriptorPool ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifdef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE Result Device::resetDescriptorPool( DescriptorPool descriptorPool, DescriptorPoolResetFlags flags ) const\n  {\n    return static_cast<Result>( vkResetDescriptorPool( m_device, static_cast<VkDescriptorPool>( descriptorPool ), static_cast<VkDescriptorPoolResetFlags>( flags ) ) );\n  }\n#else\n  VULKAN_HPP_INLINE ResultValueType<void>::type Device::resetDescriptorPool( DescriptorPool descriptorPool, DescriptorPoolResetFlags flags ) const\n  {\n    Result result = static_cast<Result>( vkResetDescriptorPool( m_device, static_cast<VkDescriptorPool>( descriptorPool ), static_cast<VkDescriptorPoolResetFlags>( flags ) ) );\n    return createResultValue( result, \"vk::Device::resetDescriptorPool\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::allocateDescriptorSets( const DescriptorSetAllocateInfo* pAllocateInfo, DescriptorSet* pDescriptorSets ) const\n  {\n    return static_cast<Result>( vkAllocateDescriptorSets( m_device, reinterpret_cast<const VkDescriptorSetAllocateInfo*>( pAllocateInfo ), reinterpret_cast<VkDescriptorSet*>( pDescriptorSets ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  template <typename Allocator> \n  VULKAN_HPP_INLINE typename ResultValueType<std::vector<DescriptorSet,Allocator>>::type Device::allocateDescriptorSets( const DescriptorSetAllocateInfo & allocateInfo ) const\n  {\n    std::vector<DescriptorSet,Allocator> descriptorSets( allocateInfo.descriptorSetCount );\n    Result result = static_cast<Result>( vkAllocateDescriptorSets( m_device, reinterpret_cast<const VkDescriptorSetAllocateInfo*>( &allocateInfo ), reinterpret_cast<VkDescriptorSet*>( descriptorSets.data() ) ) );\n    return createResultValue( result, descriptorSets, \"vk::Device::allocateDescriptorSets\" );\n  }\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  template <typename Allocator> \n  VULKAN_HPP_INLINE std::vector<UniqueDescriptorSet> Device::allocateDescriptorSetsUnique( const DescriptorSetAllocateInfo & allocateInfo ) const\n  {\n    DescriptorSetDeleter deleter( *this, allocateInfo.descriptorPool );\n    std::vector<DescriptorSet,Allocator> descriptorSets = allocateDescriptorSets( allocateInfo );\n    std::vector<UniqueDescriptorSet> uniqueDescriptorSets;\n    uniqueDescriptorSets.reserve( descriptorSets.size() );\n    for ( auto descriptorSet : descriptorSets )\n    {\n      uniqueDescriptorSets.push_back( UniqueDescriptorSet( descriptorSet, deleter ) );\n    }\n    return uniqueDescriptorSets;\n  }\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::freeDescriptorSets( DescriptorPool descriptorPool, uint32_t descriptorSetCount, const DescriptorSet* pDescriptorSets ) const\n  {\n    return static_cast<Result>( vkFreeDescriptorSets( m_device, static_cast<VkDescriptorPool>( descriptorPool ), descriptorSetCount, reinterpret_cast<const VkDescriptorSet*>( pDescriptorSets ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<void>::type Device::freeDescriptorSets( DescriptorPool descriptorPool, ArrayProxy<const DescriptorSet> descriptorSets ) const\n  {\n    Result result = static_cast<Result>( vkFreeDescriptorSets( m_device, static_cast<VkDescriptorPool>( descriptorPool ), descriptorSets.size() , reinterpret_cast<const VkDescriptorSet*>( descriptorSets.data() ) ) );\n    return createResultValue( result, \"vk::Device::freeDescriptorSets\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void Device::updateDescriptorSets( uint32_t descriptorWriteCount, const WriteDescriptorSet* pDescriptorWrites, uint32_t descriptorCopyCount, const CopyDescriptorSet* pDescriptorCopies ) const\n  {\n    vkUpdateDescriptorSets( m_device, descriptorWriteCount, reinterpret_cast<const VkWriteDescriptorSet*>( pDescriptorWrites ), descriptorCopyCount, reinterpret_cast<const VkCopyDescriptorSet*>( pDescriptorCopies ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void Device::updateDescriptorSets( ArrayProxy<const WriteDescriptorSet> descriptorWrites, ArrayProxy<const CopyDescriptorSet> descriptorCopies ) const\n  {\n    vkUpdateDescriptorSets( m_device, descriptorWrites.size() , reinterpret_cast<const VkWriteDescriptorSet*>( descriptorWrites.data() ), descriptorCopies.size() , reinterpret_cast<const VkCopyDescriptorSet*>( descriptorCopies.data() ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::createFramebuffer( const FramebufferCreateInfo* pCreateInfo, const AllocationCallbacks* pAllocator, Framebuffer* pFramebuffer ) const\n  {\n    return static_cast<Result>( vkCreateFramebuffer( m_device, reinterpret_cast<const VkFramebufferCreateInfo*>( pCreateInfo ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ), reinterpret_cast<VkFramebuffer*>( pFramebuffer ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<Framebuffer>::type Device::createFramebuffer( const FramebufferCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    Framebuffer framebuffer;\n    Result result = static_cast<Result>( vkCreateFramebuffer( m_device, reinterpret_cast<const VkFramebufferCreateInfo*>( &createInfo ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkFramebuffer*>( &framebuffer ) ) );\n    return createResultValue( result, framebuffer, \"vk::Device::createFramebuffer\" );\n  }\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  VULKAN_HPP_INLINE UniqueFramebuffer Device::createFramebufferUnique( const FramebufferCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    FramebufferDeleter deleter( *this, allocator );\n    return UniqueFramebuffer( createFramebuffer( createInfo, allocator ), deleter );\n  }\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void Device::destroyFramebuffer( Framebuffer framebuffer, const AllocationCallbacks* pAllocator ) const\n  {\n    vkDestroyFramebuffer( m_device, static_cast<VkFramebuffer>( framebuffer ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void Device::destroyFramebuffer( Framebuffer framebuffer, Optional<const AllocationCallbacks> allocator ) const\n  {\n    vkDestroyFramebuffer( m_device, static_cast<VkFramebuffer>( framebuffer ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::createRenderPass( const RenderPassCreateInfo* pCreateInfo, const AllocationCallbacks* pAllocator, RenderPass* pRenderPass ) const\n  {\n    return static_cast<Result>( vkCreateRenderPass( m_device, reinterpret_cast<const VkRenderPassCreateInfo*>( pCreateInfo ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ), reinterpret_cast<VkRenderPass*>( pRenderPass ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<RenderPass>::type Device::createRenderPass( const RenderPassCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    RenderPass renderPass;\n    Result result = static_cast<Result>( vkCreateRenderPass( m_device, reinterpret_cast<const VkRenderPassCreateInfo*>( &createInfo ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkRenderPass*>( &renderPass ) ) );\n    return createResultValue( result, renderPass, \"vk::Device::createRenderPass\" );\n  }\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  VULKAN_HPP_INLINE UniqueRenderPass Device::createRenderPassUnique( const RenderPassCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    RenderPassDeleter deleter( *this, allocator );\n    return UniqueRenderPass( createRenderPass( createInfo, allocator ), deleter );\n  }\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void Device::destroyRenderPass( RenderPass renderPass, const AllocationCallbacks* pAllocator ) const\n  {\n    vkDestroyRenderPass( m_device, static_cast<VkRenderPass>( renderPass ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void Device::destroyRenderPass( RenderPass renderPass, Optional<const AllocationCallbacks> allocator ) const\n  {\n    vkDestroyRenderPass( m_device, static_cast<VkRenderPass>( renderPass ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void Device::getRenderAreaGranularity( RenderPass renderPass, Extent2D* pGranularity ) const\n  {\n    vkGetRenderAreaGranularity( m_device, static_cast<VkRenderPass>( renderPass ), reinterpret_cast<VkExtent2D*>( pGranularity ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE Extent2D Device::getRenderAreaGranularity( RenderPass renderPass ) const\n  {\n    Extent2D granularity;\n    vkGetRenderAreaGranularity( m_device, static_cast<VkRenderPass>( renderPass ), reinterpret_cast<VkExtent2D*>( &granularity ) );\n    return granularity;\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::createCommandPool( const CommandPoolCreateInfo* pCreateInfo, const AllocationCallbacks* pAllocator, CommandPool* pCommandPool ) const\n  {\n    return static_cast<Result>( vkCreateCommandPool( m_device, reinterpret_cast<const VkCommandPoolCreateInfo*>( pCreateInfo ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ), reinterpret_cast<VkCommandPool*>( pCommandPool ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<CommandPool>::type Device::createCommandPool( const CommandPoolCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    CommandPool commandPool;\n    Result result = static_cast<Result>( vkCreateCommandPool( m_device, reinterpret_cast<const VkCommandPoolCreateInfo*>( &createInfo ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkCommandPool*>( &commandPool ) ) );\n    return createResultValue( result, commandPool, \"vk::Device::createCommandPool\" );\n  }\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  VULKAN_HPP_INLINE UniqueCommandPool Device::createCommandPoolUnique( const CommandPoolCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    CommandPoolDeleter deleter( *this, allocator );\n    return UniqueCommandPool( createCommandPool( createInfo, allocator ), deleter );\n  }\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void Device::destroyCommandPool( CommandPool commandPool, const AllocationCallbacks* pAllocator ) const\n  {\n    vkDestroyCommandPool( m_device, static_cast<VkCommandPool>( commandPool ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void Device::destroyCommandPool( CommandPool commandPool, Optional<const AllocationCallbacks> allocator ) const\n  {\n    vkDestroyCommandPool( m_device, static_cast<VkCommandPool>( commandPool ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifdef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE Result Device::resetCommandPool( CommandPool commandPool, CommandPoolResetFlags flags ) const\n  {\n    return static_cast<Result>( vkResetCommandPool( m_device, static_cast<VkCommandPool>( commandPool ), static_cast<VkCommandPoolResetFlags>( flags ) ) );\n  }\n#else\n  VULKAN_HPP_INLINE ResultValueType<void>::type Device::resetCommandPool( CommandPool commandPool, CommandPoolResetFlags flags ) const\n  {\n    Result result = static_cast<Result>( vkResetCommandPool( m_device, static_cast<VkCommandPool>( commandPool ), static_cast<VkCommandPoolResetFlags>( flags ) ) );\n    return createResultValue( result, \"vk::Device::resetCommandPool\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::allocateCommandBuffers( const CommandBufferAllocateInfo* pAllocateInfo, CommandBuffer* pCommandBuffers ) const\n  {\n    return static_cast<Result>( vkAllocateCommandBuffers( m_device, reinterpret_cast<const VkCommandBufferAllocateInfo*>( pAllocateInfo ), reinterpret_cast<VkCommandBuffer*>( pCommandBuffers ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  template <typename Allocator> \n  VULKAN_HPP_INLINE typename ResultValueType<std::vector<CommandBuffer,Allocator>>::type Device::allocateCommandBuffers( const CommandBufferAllocateInfo & allocateInfo ) const\n  {\n    std::vector<CommandBuffer,Allocator> commandBuffers( allocateInfo.commandBufferCount );\n    Result result = static_cast<Result>( vkAllocateCommandBuffers( m_device, reinterpret_cast<const VkCommandBufferAllocateInfo*>( &allocateInfo ), reinterpret_cast<VkCommandBuffer*>( commandBuffers.data() ) ) );\n    return createResultValue( result, commandBuffers, \"vk::Device::allocateCommandBuffers\" );\n  }\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  template <typename Allocator> \n  VULKAN_HPP_INLINE std::vector<UniqueCommandBuffer> Device::allocateCommandBuffersUnique( const CommandBufferAllocateInfo & allocateInfo ) const\n  {\n    CommandBufferDeleter deleter( *this, allocateInfo.commandPool );\n    std::vector<CommandBuffer,Allocator> commandBuffers = allocateCommandBuffers( allocateInfo );\n    std::vector<UniqueCommandBuffer> uniqueCommandBuffers;\n    uniqueCommandBuffers.reserve( commandBuffers.size() );\n    for ( auto commandBuffer : commandBuffers )\n    {\n      uniqueCommandBuffers.push_back( UniqueCommandBuffer( commandBuffer, deleter ) );\n    }\n    return uniqueCommandBuffers;\n  }\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void Device::freeCommandBuffers( CommandPool commandPool, uint32_t commandBufferCount, const CommandBuffer* pCommandBuffers ) const\n  {\n    vkFreeCommandBuffers( m_device, static_cast<VkCommandPool>( commandPool ), commandBufferCount, reinterpret_cast<const VkCommandBuffer*>( pCommandBuffers ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void Device::freeCommandBuffers( CommandPool commandPool, ArrayProxy<const CommandBuffer> commandBuffers ) const\n  {\n    vkFreeCommandBuffers( m_device, static_cast<VkCommandPool>( commandPool ), commandBuffers.size() , reinterpret_cast<const VkCommandBuffer*>( commandBuffers.data() ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::createSharedSwapchainsKHR( uint32_t swapchainCount, const SwapchainCreateInfoKHR* pCreateInfos, const AllocationCallbacks* pAllocator, SwapchainKHR* pSwapchains ) const\n  {\n    return static_cast<Result>( vkCreateSharedSwapchainsKHR( m_device, swapchainCount, reinterpret_cast<const VkSwapchainCreateInfoKHR*>( pCreateInfos ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ), reinterpret_cast<VkSwapchainKHR*>( pSwapchains ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  template <typename Allocator> \n  VULKAN_HPP_INLINE typename ResultValueType<std::vector<SwapchainKHR,Allocator>>::type Device::createSharedSwapchainsKHR( ArrayProxy<const SwapchainCreateInfoKHR> createInfos, Optional<const AllocationCallbacks> allocator ) const\n  {\n    std::vector<SwapchainKHR,Allocator> swapchains( createInfos.size() );\n    Result result = static_cast<Result>( vkCreateSharedSwapchainsKHR( m_device, createInfos.size() , reinterpret_cast<const VkSwapchainCreateInfoKHR*>( createInfos.data() ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkSwapchainKHR*>( swapchains.data() ) ) );\n    return createResultValue( result, swapchains, \"vk::Device::createSharedSwapchainsKHR\" );\n  }\n  VULKAN_HPP_INLINE ResultValueType<SwapchainKHR>::type Device::createSharedSwapchainKHR( const SwapchainCreateInfoKHR & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    SwapchainKHR swapchain;\n    Result result = static_cast<Result>( vkCreateSharedSwapchainsKHR( m_device, 1 , reinterpret_cast<const VkSwapchainCreateInfoKHR*>( &createInfo ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkSwapchainKHR*>( &swapchain ) ) );\n    return createResultValue( result, swapchain, \"vk::Device::createSharedSwapchainKHR\" );\n  }\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  template <typename Allocator> \n  VULKAN_HPP_INLINE std::vector<UniqueSwapchainKHR> Device::createSharedSwapchainsKHRUnique( ArrayProxy<const SwapchainCreateInfoKHR> createInfos, Optional<const AllocationCallbacks> allocator ) const\n  {\n    SwapchainKHRDeleter deleter( *this, allocator );\n    std::vector<SwapchainKHR,Allocator> swapchainKHRs = createSharedSwapchainsKHR( createInfos, allocator );\n    std::vector<UniqueSwapchainKHR> uniqueSwapchainKHRs;\n    uniqueSwapchainKHRs.reserve( swapchainKHRs.size() );\n    for ( auto swapchainKHR : swapchainKHRs )\n    {\n      uniqueSwapchainKHRs.push_back( UniqueSwapchainKHR( swapchainKHR, deleter ) );\n    }\n    return uniqueSwapchainKHRs;\n  }\n  VULKAN_HPP_INLINE UniqueSwapchainKHR Device::createSharedSwapchainKHRUnique( const SwapchainCreateInfoKHR & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    SwapchainKHRDeleter deleter( *this, allocator );\n    return UniqueSwapchainKHR( createSharedSwapchainKHR( createInfo, allocator ), deleter );\n  }\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::createSwapchainKHR( const SwapchainCreateInfoKHR* pCreateInfo, const AllocationCallbacks* pAllocator, SwapchainKHR* pSwapchain ) const\n  {\n    return static_cast<Result>( vkCreateSwapchainKHR( m_device, reinterpret_cast<const VkSwapchainCreateInfoKHR*>( pCreateInfo ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ), reinterpret_cast<VkSwapchainKHR*>( pSwapchain ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<SwapchainKHR>::type Device::createSwapchainKHR( const SwapchainCreateInfoKHR & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    SwapchainKHR swapchain;\n    Result result = static_cast<Result>( vkCreateSwapchainKHR( m_device, reinterpret_cast<const VkSwapchainCreateInfoKHR*>( &createInfo ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkSwapchainKHR*>( &swapchain ) ) );\n    return createResultValue( result, swapchain, \"vk::Device::createSwapchainKHR\" );\n  }\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  VULKAN_HPP_INLINE UniqueSwapchainKHR Device::createSwapchainKHRUnique( const SwapchainCreateInfoKHR & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    SwapchainKHRDeleter deleter( *this, allocator );\n    return UniqueSwapchainKHR( createSwapchainKHR( createInfo, allocator ), deleter );\n  }\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void Device::destroySwapchainKHR( SwapchainKHR swapchain, const AllocationCallbacks* pAllocator ) const\n  {\n    vkDestroySwapchainKHR( m_device, static_cast<VkSwapchainKHR>( swapchain ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void Device::destroySwapchainKHR( SwapchainKHR swapchain, Optional<const AllocationCallbacks> allocator ) const\n  {\n    vkDestroySwapchainKHR( m_device, static_cast<VkSwapchainKHR>( swapchain ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::getSwapchainImagesKHR( SwapchainKHR swapchain, uint32_t* pSwapchainImageCount, Image* pSwapchainImages ) const\n  {\n    return static_cast<Result>( vkGetSwapchainImagesKHR( m_device, static_cast<VkSwapchainKHR>( swapchain ), pSwapchainImageCount, reinterpret_cast<VkImage*>( pSwapchainImages ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  template <typename Allocator> \n  VULKAN_HPP_INLINE typename ResultValueType<std::vector<Image,Allocator>>::type Device::getSwapchainImagesKHR( SwapchainKHR swapchain ) const\n  {\n    std::vector<Image,Allocator> swapchainImages;\n    uint32_t swapchainImageCount;\n    Result result;\n    do\n    {\n      result = static_cast<Result>( vkGetSwapchainImagesKHR( m_device, static_cast<VkSwapchainKHR>( swapchain ), &swapchainImageCount, nullptr ) );\n      if ( ( result == Result::eSuccess ) && swapchainImageCount )\n      {\n        swapchainImages.resize( swapchainImageCount );\n        result = static_cast<Result>( vkGetSwapchainImagesKHR( m_device, static_cast<VkSwapchainKHR>( swapchain ), &swapchainImageCount, reinterpret_cast<VkImage*>( swapchainImages.data() ) ) );\n      }\n    } while ( result == Result::eIncomplete );\n    assert( swapchainImageCount <= swapchainImages.size() ); \n    swapchainImages.resize( swapchainImageCount ); \n    return createResultValue( result, swapchainImages, \"vk::Device::getSwapchainImagesKHR\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::acquireNextImageKHR( SwapchainKHR swapchain, uint64_t timeout, Semaphore semaphore, Fence fence, uint32_t* pImageIndex ) const\n  {\n    return static_cast<Result>( vkAcquireNextImageKHR( m_device, static_cast<VkSwapchainKHR>( swapchain ), timeout, static_cast<VkSemaphore>( semaphore ), static_cast<VkFence>( fence ), pImageIndex ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValue<uint32_t> Device::acquireNextImageKHR( SwapchainKHR swapchain, uint64_t timeout, Semaphore semaphore, Fence fence ) const\n  {\n    uint32_t imageIndex;\n    Result result = static_cast<Result>( vkAcquireNextImageKHR( m_device, static_cast<VkSwapchainKHR>( swapchain ), timeout, static_cast<VkSemaphore>( semaphore ), static_cast<VkFence>( fence ), &imageIndex ) );\n    return createResultValue( result, imageIndex, \"vk::Device::acquireNextImageKHR\", { Result::eSuccess, Result::eTimeout, Result::eNotReady, Result::eSuboptimalKHR } );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::debugMarkerSetObjectNameEXT( DebugMarkerObjectNameInfoEXT* pNameInfo ) const\n  {\n    return static_cast<Result>( vkDebugMarkerSetObjectNameEXT( m_device, reinterpret_cast<VkDebugMarkerObjectNameInfoEXT*>( pNameInfo ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<DebugMarkerObjectNameInfoEXT>::type Device::debugMarkerSetObjectNameEXT() const\n  {\n    DebugMarkerObjectNameInfoEXT nameInfo;\n    Result result = static_cast<Result>( vkDebugMarkerSetObjectNameEXT( m_device, reinterpret_cast<VkDebugMarkerObjectNameInfoEXT*>( &nameInfo ) ) );\n    return createResultValue( result, nameInfo, \"vk::Device::debugMarkerSetObjectNameEXT\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::debugMarkerSetObjectTagEXT( DebugMarkerObjectTagInfoEXT* pTagInfo ) const\n  {\n    return static_cast<Result>( vkDebugMarkerSetObjectTagEXT( m_device, reinterpret_cast<VkDebugMarkerObjectTagInfoEXT*>( pTagInfo ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<DebugMarkerObjectTagInfoEXT>::type Device::debugMarkerSetObjectTagEXT() const\n  {\n    DebugMarkerObjectTagInfoEXT tagInfo;\n    Result result = static_cast<Result>( vkDebugMarkerSetObjectTagEXT( m_device, reinterpret_cast<VkDebugMarkerObjectTagInfoEXT*>( &tagInfo ) ) );\n    return createResultValue( result, tagInfo, \"vk::Device::debugMarkerSetObjectTagEXT\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifdef VK_USE_PLATFORM_WIN32_KHR\n  VULKAN_HPP_INLINE Result Device::getMemoryWin32HandleNV( DeviceMemory memory, ExternalMemoryHandleTypeFlagsNV handleType, HANDLE* pHandle ) const\n  {\n    return static_cast<Result>( vkGetMemoryWin32HandleNV( m_device, static_cast<VkDeviceMemory>( memory ), static_cast<VkExternalMemoryHandleTypeFlagsNV>( handleType ), pHandle ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<HANDLE>::type Device::getMemoryWin32HandleNV( DeviceMemory memory, ExternalMemoryHandleTypeFlagsNV handleType ) const\n  {\n    HANDLE handle;\n    Result result = static_cast<Result>( vkGetMemoryWin32HandleNV( m_device, static_cast<VkDeviceMemory>( memory ), static_cast<VkExternalMemoryHandleTypeFlagsNV>( handleType ), &handle ) );\n    return createResultValue( result, handle, \"vk::Device::getMemoryWin32HandleNV\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n#endif /*VK_USE_PLATFORM_WIN32_KHR*/\n\n  VULKAN_HPP_INLINE Result Device::createIndirectCommandsLayoutNVX( const IndirectCommandsLayoutCreateInfoNVX* pCreateInfo, const AllocationCallbacks* pAllocator, IndirectCommandsLayoutNVX* pIndirectCommandsLayout ) const\n  {\n    return static_cast<Result>( vkCreateIndirectCommandsLayoutNVX( m_device, reinterpret_cast<const VkIndirectCommandsLayoutCreateInfoNVX*>( pCreateInfo ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ), reinterpret_cast<VkIndirectCommandsLayoutNVX*>( pIndirectCommandsLayout ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<IndirectCommandsLayoutNVX>::type Device::createIndirectCommandsLayoutNVX( const IndirectCommandsLayoutCreateInfoNVX & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    IndirectCommandsLayoutNVX indirectCommandsLayout;\n    Result result = static_cast<Result>( vkCreateIndirectCommandsLayoutNVX( m_device, reinterpret_cast<const VkIndirectCommandsLayoutCreateInfoNVX*>( &createInfo ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkIndirectCommandsLayoutNVX*>( &indirectCommandsLayout ) ) );\n    return createResultValue( result, indirectCommandsLayout, \"vk::Device::createIndirectCommandsLayoutNVX\" );\n  }\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  VULKAN_HPP_INLINE UniqueIndirectCommandsLayoutNVX Device::createIndirectCommandsLayoutNVXUnique( const IndirectCommandsLayoutCreateInfoNVX & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    IndirectCommandsLayoutNVXDeleter deleter( *this, allocator );\n    return UniqueIndirectCommandsLayoutNVX( createIndirectCommandsLayoutNVX( createInfo, allocator ), deleter );\n  }\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void Device::destroyIndirectCommandsLayoutNVX( IndirectCommandsLayoutNVX indirectCommandsLayout, const AllocationCallbacks* pAllocator ) const\n  {\n    vkDestroyIndirectCommandsLayoutNVX( m_device, static_cast<VkIndirectCommandsLayoutNVX>( indirectCommandsLayout ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void Device::destroyIndirectCommandsLayoutNVX( IndirectCommandsLayoutNVX indirectCommandsLayout, Optional<const AllocationCallbacks> allocator ) const\n  {\n    vkDestroyIndirectCommandsLayoutNVX( m_device, static_cast<VkIndirectCommandsLayoutNVX>( indirectCommandsLayout ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::createObjectTableNVX( const ObjectTableCreateInfoNVX* pCreateInfo, const AllocationCallbacks* pAllocator, ObjectTableNVX* pObjectTable ) const\n  {\n    return static_cast<Result>( vkCreateObjectTableNVX( m_device, reinterpret_cast<const VkObjectTableCreateInfoNVX*>( pCreateInfo ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ), reinterpret_cast<VkObjectTableNVX*>( pObjectTable ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<ObjectTableNVX>::type Device::createObjectTableNVX( const ObjectTableCreateInfoNVX & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    ObjectTableNVX objectTable;\n    Result result = static_cast<Result>( vkCreateObjectTableNVX( m_device, reinterpret_cast<const VkObjectTableCreateInfoNVX*>( &createInfo ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkObjectTableNVX*>( &objectTable ) ) );\n    return createResultValue( result, objectTable, \"vk::Device::createObjectTableNVX\" );\n  }\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  VULKAN_HPP_INLINE UniqueObjectTableNVX Device::createObjectTableNVXUnique( const ObjectTableCreateInfoNVX & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    ObjectTableNVXDeleter deleter( *this, allocator );\n    return UniqueObjectTableNVX( createObjectTableNVX( createInfo, allocator ), deleter );\n  }\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void Device::destroyObjectTableNVX( ObjectTableNVX objectTable, const AllocationCallbacks* pAllocator ) const\n  {\n    vkDestroyObjectTableNVX( m_device, static_cast<VkObjectTableNVX>( objectTable ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void Device::destroyObjectTableNVX( ObjectTableNVX objectTable, Optional<const AllocationCallbacks> allocator ) const\n  {\n    vkDestroyObjectTableNVX( m_device, static_cast<VkObjectTableNVX>( objectTable ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::registerObjectsNVX( ObjectTableNVX objectTable, uint32_t objectCount, const ObjectTableEntryNVX* const* ppObjectTableEntries, const uint32_t* pObjectIndices ) const\n  {\n    return static_cast<Result>( vkRegisterObjectsNVX( m_device, static_cast<VkObjectTableNVX>( objectTable ), objectCount, reinterpret_cast<const VkObjectTableEntryNVX* const*>( ppObjectTableEntries ), pObjectIndices ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<void>::type Device::registerObjectsNVX( ObjectTableNVX objectTable, ArrayProxy<const ObjectTableEntryNVX* const> pObjectTableEntries, ArrayProxy<const uint32_t> objectIndices ) const\n  {\n#ifdef VULKAN_HPP_NO_EXCEPTIONS\n    assert( pObjectTableEntries.size() == objectIndices.size() );\n#else\n    if ( pObjectTableEntries.size() != objectIndices.size() )\n    {\n      throw std::logic_error( \"vk::Device::registerObjectsNVX: pObjectTableEntries.size() != objectIndices.size()\" );\n    }\n#endif  // VULKAN_HPP_NO_EXCEPTIONS\n    Result result = static_cast<Result>( vkRegisterObjectsNVX( m_device, static_cast<VkObjectTableNVX>( objectTable ), pObjectTableEntries.size() , reinterpret_cast<const VkObjectTableEntryNVX* const*>( pObjectTableEntries.data() ), objectIndices.data() ) );\n    return createResultValue( result, \"vk::Device::registerObjectsNVX\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::unregisterObjectsNVX( ObjectTableNVX objectTable, uint32_t objectCount, const ObjectEntryTypeNVX* pObjectEntryTypes, const uint32_t* pObjectIndices ) const\n  {\n    return static_cast<Result>( vkUnregisterObjectsNVX( m_device, static_cast<VkObjectTableNVX>( objectTable ), objectCount, reinterpret_cast<const VkObjectEntryTypeNVX*>( pObjectEntryTypes ), pObjectIndices ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<void>::type Device::unregisterObjectsNVX( ObjectTableNVX objectTable, ArrayProxy<const ObjectEntryTypeNVX> objectEntryTypes, ArrayProxy<const uint32_t> objectIndices ) const\n  {\n#ifdef VULKAN_HPP_NO_EXCEPTIONS\n    assert( objectEntryTypes.size() == objectIndices.size() );\n#else\n    if ( objectEntryTypes.size() != objectIndices.size() )\n    {\n      throw std::logic_error( \"vk::Device::unregisterObjectsNVX: objectEntryTypes.size() != objectIndices.size()\" );\n    }\n#endif  // VULKAN_HPP_NO_EXCEPTIONS\n    Result result = static_cast<Result>( vkUnregisterObjectsNVX( m_device, static_cast<VkObjectTableNVX>( objectTable ), objectEntryTypes.size() , reinterpret_cast<const VkObjectEntryTypeNVX*>( objectEntryTypes.data() ), objectIndices.data() ) );\n    return createResultValue( result, \"vk::Device::unregisterObjectsNVX\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void Device::trimCommandPoolKHR( CommandPool commandPool, CommandPoolTrimFlagsKHR flags ) const\n  {\n    vkTrimCommandPoolKHR( m_device, static_cast<VkCommandPool>( commandPool ), static_cast<VkCommandPoolTrimFlagsKHR>( flags ) );\n  }\n\n#ifdef VK_USE_PLATFORM_WIN32_KHX\n  VULKAN_HPP_INLINE Result Device::getMemoryWin32HandleKHX( DeviceMemory memory, ExternalMemoryHandleTypeFlagBitsKHX handleType, HANDLE* pHandle ) const\n  {\n    return static_cast<Result>( vkGetMemoryWin32HandleKHX( m_device, static_cast<VkDeviceMemory>( memory ), static_cast<VkExternalMemoryHandleTypeFlagBitsKHX>( handleType ), pHandle ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<HANDLE>::type Device::getMemoryWin32HandleKHX( DeviceMemory memory, ExternalMemoryHandleTypeFlagBitsKHX handleType ) const\n  {\n    HANDLE handle;\n    Result result = static_cast<Result>( vkGetMemoryWin32HandleKHX( m_device, static_cast<VkDeviceMemory>( memory ), static_cast<VkExternalMemoryHandleTypeFlagBitsKHX>( handleType ), &handle ) );\n    return createResultValue( result, handle, \"vk::Device::getMemoryWin32HandleKHX\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n#endif /*VK_USE_PLATFORM_WIN32_KHX*/\n\n#ifdef VK_USE_PLATFORM_WIN32_KHX\n  VULKAN_HPP_INLINE Result Device::getMemoryWin32HandlePropertiesKHX( ExternalMemoryHandleTypeFlagBitsKHX handleType, HANDLE handle, MemoryWin32HandlePropertiesKHX* pMemoryWin32HandleProperties ) const\n  {\n    return static_cast<Result>( vkGetMemoryWin32HandlePropertiesKHX( m_device, static_cast<VkExternalMemoryHandleTypeFlagBitsKHX>( handleType ), handle, reinterpret_cast<VkMemoryWin32HandlePropertiesKHX*>( pMemoryWin32HandleProperties ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<MemoryWin32HandlePropertiesKHX>::type Device::getMemoryWin32HandlePropertiesKHX( ExternalMemoryHandleTypeFlagBitsKHX handleType, HANDLE handle ) const\n  {\n    MemoryWin32HandlePropertiesKHX memoryWin32HandleProperties;\n    Result result = static_cast<Result>( vkGetMemoryWin32HandlePropertiesKHX( m_device, static_cast<VkExternalMemoryHandleTypeFlagBitsKHX>( handleType ), handle, reinterpret_cast<VkMemoryWin32HandlePropertiesKHX*>( &memoryWin32HandleProperties ) ) );\n    return createResultValue( result, memoryWin32HandleProperties, \"vk::Device::getMemoryWin32HandlePropertiesKHX\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n#endif /*VK_USE_PLATFORM_WIN32_KHX*/\n\n  VULKAN_HPP_INLINE Result Device::getMemoryFdKHX( DeviceMemory memory, ExternalMemoryHandleTypeFlagBitsKHX handleType, int* pFd ) const\n  {\n    return static_cast<Result>( vkGetMemoryFdKHX( m_device, static_cast<VkDeviceMemory>( memory ), static_cast<VkExternalMemoryHandleTypeFlagBitsKHX>( handleType ), pFd ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<int>::type Device::getMemoryFdKHX( DeviceMemory memory, ExternalMemoryHandleTypeFlagBitsKHX handleType ) const\n  {\n    int fd;\n    Result result = static_cast<Result>( vkGetMemoryFdKHX( m_device, static_cast<VkDeviceMemory>( memory ), static_cast<VkExternalMemoryHandleTypeFlagBitsKHX>( handleType ), &fd ) );\n    return createResultValue( result, fd, \"vk::Device::getMemoryFdKHX\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::getMemoryFdPropertiesKHX( ExternalMemoryHandleTypeFlagBitsKHX handleType, int fd, MemoryFdPropertiesKHX* pMemoryFdProperties ) const\n  {\n    return static_cast<Result>( vkGetMemoryFdPropertiesKHX( m_device, static_cast<VkExternalMemoryHandleTypeFlagBitsKHX>( handleType ), fd, reinterpret_cast<VkMemoryFdPropertiesKHX*>( pMemoryFdProperties ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<MemoryFdPropertiesKHX>::type Device::getMemoryFdPropertiesKHX( ExternalMemoryHandleTypeFlagBitsKHX handleType, int fd ) const\n  {\n    MemoryFdPropertiesKHX memoryFdProperties;\n    Result result = static_cast<Result>( vkGetMemoryFdPropertiesKHX( m_device, static_cast<VkExternalMemoryHandleTypeFlagBitsKHX>( handleType ), fd, reinterpret_cast<VkMemoryFdPropertiesKHX*>( &memoryFdProperties ) ) );\n    return createResultValue( result, memoryFdProperties, \"vk::Device::getMemoryFdPropertiesKHX\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifdef VK_USE_PLATFORM_WIN32_KHX\n  VULKAN_HPP_INLINE Result Device::getSemaphoreWin32HandleKHX( Semaphore semaphore, ExternalSemaphoreHandleTypeFlagBitsKHX handleType, HANDLE* pHandle ) const\n  {\n    return static_cast<Result>( vkGetSemaphoreWin32HandleKHX( m_device, static_cast<VkSemaphore>( semaphore ), static_cast<VkExternalSemaphoreHandleTypeFlagBitsKHX>( handleType ), pHandle ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<HANDLE>::type Device::getSemaphoreWin32HandleKHX( Semaphore semaphore, ExternalSemaphoreHandleTypeFlagBitsKHX handleType ) const\n  {\n    HANDLE handle;\n    Result result = static_cast<Result>( vkGetSemaphoreWin32HandleKHX( m_device, static_cast<VkSemaphore>( semaphore ), static_cast<VkExternalSemaphoreHandleTypeFlagBitsKHX>( handleType ), &handle ) );\n    return createResultValue( result, handle, \"vk::Device::getSemaphoreWin32HandleKHX\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n#endif /*VK_USE_PLATFORM_WIN32_KHX*/\n\n#ifdef VK_USE_PLATFORM_WIN32_KHX\n  VULKAN_HPP_INLINE Result Device::importSemaphoreWin32HandleKHX( const ImportSemaphoreWin32HandleInfoKHX* pImportSemaphoreWin32HandleInfo ) const\n  {\n    return static_cast<Result>( vkImportSemaphoreWin32HandleKHX( m_device, reinterpret_cast<const VkImportSemaphoreWin32HandleInfoKHX*>( pImportSemaphoreWin32HandleInfo ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<void>::type Device::importSemaphoreWin32HandleKHX( const ImportSemaphoreWin32HandleInfoKHX & importSemaphoreWin32HandleInfo ) const\n  {\n    Result result = static_cast<Result>( vkImportSemaphoreWin32HandleKHX( m_device, reinterpret_cast<const VkImportSemaphoreWin32HandleInfoKHX*>( &importSemaphoreWin32HandleInfo ) ) );\n    return createResultValue( result, \"vk::Device::importSemaphoreWin32HandleKHX\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n#endif /*VK_USE_PLATFORM_WIN32_KHX*/\n\n  VULKAN_HPP_INLINE Result Device::getSemaphoreFdKHX( Semaphore semaphore, ExternalSemaphoreHandleTypeFlagBitsKHX handleType, int* pFd ) const\n  {\n    return static_cast<Result>( vkGetSemaphoreFdKHX( m_device, static_cast<VkSemaphore>( semaphore ), static_cast<VkExternalSemaphoreHandleTypeFlagBitsKHX>( handleType ), pFd ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<int>::type Device::getSemaphoreFdKHX( Semaphore semaphore, ExternalSemaphoreHandleTypeFlagBitsKHX handleType ) const\n  {\n    int fd;\n    Result result = static_cast<Result>( vkGetSemaphoreFdKHX( m_device, static_cast<VkSemaphore>( semaphore ), static_cast<VkExternalSemaphoreHandleTypeFlagBitsKHX>( handleType ), &fd ) );\n    return createResultValue( result, fd, \"vk::Device::getSemaphoreFdKHX\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::importSemaphoreFdKHX( const ImportSemaphoreFdInfoKHX* pImportSemaphoreFdInfo ) const\n  {\n    return static_cast<Result>( vkImportSemaphoreFdKHX( m_device, reinterpret_cast<const VkImportSemaphoreFdInfoKHX*>( pImportSemaphoreFdInfo ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<void>::type Device::importSemaphoreFdKHX( const ImportSemaphoreFdInfoKHX & importSemaphoreFdInfo ) const\n  {\n    Result result = static_cast<Result>( vkImportSemaphoreFdKHX( m_device, reinterpret_cast<const VkImportSemaphoreFdInfoKHX*>( &importSemaphoreFdInfo ) ) );\n    return createResultValue( result, \"vk::Device::importSemaphoreFdKHX\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::displayPowerControlEXT( DisplayKHR display, const DisplayPowerInfoEXT* pDisplayPowerInfo ) const\n  {\n    return static_cast<Result>( vkDisplayPowerControlEXT( m_device, static_cast<VkDisplayKHR>( display ), reinterpret_cast<const VkDisplayPowerInfoEXT*>( pDisplayPowerInfo ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<void>::type Device::displayPowerControlEXT( DisplayKHR display, const DisplayPowerInfoEXT & displayPowerInfo ) const\n  {\n    Result result = static_cast<Result>( vkDisplayPowerControlEXT( m_device, static_cast<VkDisplayKHR>( display ), reinterpret_cast<const VkDisplayPowerInfoEXT*>( &displayPowerInfo ) ) );\n    return createResultValue( result, \"vk::Device::displayPowerControlEXT\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::registerEventEXT( const DeviceEventInfoEXT* pDeviceEventInfo, const AllocationCallbacks* pAllocator, Fence* pFence ) const\n  {\n    return static_cast<Result>( vkRegisterDeviceEventEXT( m_device, reinterpret_cast<const VkDeviceEventInfoEXT*>( pDeviceEventInfo ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ), reinterpret_cast<VkFence*>( pFence ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<Fence>::type Device::registerEventEXT( const DeviceEventInfoEXT & deviceEventInfo, const AllocationCallbacks & allocator ) const\n  {\n    Fence fence;\n    Result result = static_cast<Result>( vkRegisterDeviceEventEXT( m_device, reinterpret_cast<const VkDeviceEventInfoEXT*>( &deviceEventInfo ), reinterpret_cast<const VkAllocationCallbacks*>( &allocator ), reinterpret_cast<VkFence*>( &fence ) ) );\n    return createResultValue( result, fence, \"vk::Device::registerEventEXT\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::registerDisplayEventEXT( DisplayKHR display, const DisplayEventInfoEXT* pDisplayEventInfo, const AllocationCallbacks* pAllocator, Fence* pFence ) const\n  {\n    return static_cast<Result>( vkRegisterDisplayEventEXT( m_device, static_cast<VkDisplayKHR>( display ), reinterpret_cast<const VkDisplayEventInfoEXT*>( pDisplayEventInfo ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ), reinterpret_cast<VkFence*>( pFence ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<Fence>::type Device::registerDisplayEventEXT( DisplayKHR display, const DisplayEventInfoEXT & displayEventInfo, const AllocationCallbacks & allocator ) const\n  {\n    Fence fence;\n    Result result = static_cast<Result>( vkRegisterDisplayEventEXT( m_device, static_cast<VkDisplayKHR>( display ), reinterpret_cast<const VkDisplayEventInfoEXT*>( &displayEventInfo ), reinterpret_cast<const VkAllocationCallbacks*>( &allocator ), reinterpret_cast<VkFence*>( &fence ) ) );\n    return createResultValue( result, fence, \"vk::Device::registerDisplayEventEXT\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::getSwapchainCounterEXT( SwapchainKHR swapchain, SurfaceCounterFlagBitsEXT counter, uint64_t* pCounterValue ) const\n  {\n    return static_cast<Result>( vkGetSwapchainCounterEXT( m_device, static_cast<VkSwapchainKHR>( swapchain ), static_cast<VkSurfaceCounterFlagBitsEXT>( counter ), pCounterValue ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValue<uint64_t> Device::getSwapchainCounterEXT( SwapchainKHR swapchain, SurfaceCounterFlagBitsEXT counter ) const\n  {\n    uint64_t counterValue;\n    Result result = static_cast<Result>( vkGetSwapchainCounterEXT( m_device, static_cast<VkSwapchainKHR>( swapchain ), static_cast<VkSurfaceCounterFlagBitsEXT>( counter ), &counterValue ) );\n    return createResultValue( result, counterValue, \"vk::Device::getSwapchainCounterEXT\", { Result::eSuccess, Result::eErrorDeviceLost, Result::eErrorOutOfDateKHR } );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void Device::getGroupPeerMemoryFeaturesKHX( uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, PeerMemoryFeatureFlagsKHX* pPeerMemoryFeatures ) const\n  {\n    vkGetDeviceGroupPeerMemoryFeaturesKHX( m_device, heapIndex, localDeviceIndex, remoteDeviceIndex, reinterpret_cast<VkPeerMemoryFeatureFlagsKHX*>( pPeerMemoryFeatures ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE PeerMemoryFeatureFlagsKHX Device::getGroupPeerMemoryFeaturesKHX( uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex ) const\n  {\n    PeerMemoryFeatureFlagsKHX peerMemoryFeatures;\n    vkGetDeviceGroupPeerMemoryFeaturesKHX( m_device, heapIndex, localDeviceIndex, remoteDeviceIndex, reinterpret_cast<VkPeerMemoryFeatureFlagsKHX*>( &peerMemoryFeatures ) );\n    return peerMemoryFeatures;\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::bindBufferMemory2KHX( uint32_t bindInfoCount, const BindBufferMemoryInfoKHX* pBindInfos ) const\n  {\n    return static_cast<Result>( vkBindBufferMemory2KHX( m_device, bindInfoCount, reinterpret_cast<const VkBindBufferMemoryInfoKHX*>( pBindInfos ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<void>::type Device::bindBufferMemory2KHX( ArrayProxy<const BindBufferMemoryInfoKHX> bindInfos ) const\n  {\n    Result result = static_cast<Result>( vkBindBufferMemory2KHX( m_device, bindInfos.size() , reinterpret_cast<const VkBindBufferMemoryInfoKHX*>( bindInfos.data() ) ) );\n    return createResultValue( result, \"vk::Device::bindBufferMemory2KHX\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::bindImageMemory2KHX( uint32_t bindInfoCount, const BindImageMemoryInfoKHX* pBindInfos ) const\n  {\n    return static_cast<Result>( vkBindImageMemory2KHX( m_device, bindInfoCount, reinterpret_cast<const VkBindImageMemoryInfoKHX*>( pBindInfos ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<void>::type Device::bindImageMemory2KHX( ArrayProxy<const BindImageMemoryInfoKHX> bindInfos ) const\n  {\n    Result result = static_cast<Result>( vkBindImageMemory2KHX( m_device, bindInfos.size() , reinterpret_cast<const VkBindImageMemoryInfoKHX*>( bindInfos.data() ) ) );\n    return createResultValue( result, \"vk::Device::bindImageMemory2KHX\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::getGroupPresentCapabilitiesKHX( DeviceGroupPresentCapabilitiesKHX* pDeviceGroupPresentCapabilities ) const\n  {\n    return static_cast<Result>( vkGetDeviceGroupPresentCapabilitiesKHX( m_device, reinterpret_cast<VkDeviceGroupPresentCapabilitiesKHX*>( pDeviceGroupPresentCapabilities ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<DeviceGroupPresentCapabilitiesKHX>::type Device::getGroupPresentCapabilitiesKHX() const\n  {\n    DeviceGroupPresentCapabilitiesKHX deviceGroupPresentCapabilities;\n    Result result = static_cast<Result>( vkGetDeviceGroupPresentCapabilitiesKHX( m_device, reinterpret_cast<VkDeviceGroupPresentCapabilitiesKHX*>( &deviceGroupPresentCapabilities ) ) );\n    return createResultValue( result, deviceGroupPresentCapabilities, \"vk::Device::getGroupPresentCapabilitiesKHX\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::getGroupSurfacePresentModesKHX( SurfaceKHR surface, DeviceGroupPresentModeFlagsKHX* pModes ) const\n  {\n    return static_cast<Result>( vkGetDeviceGroupSurfacePresentModesKHX( m_device, static_cast<VkSurfaceKHR>( surface ), reinterpret_cast<VkDeviceGroupPresentModeFlagsKHX*>( pModes ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<DeviceGroupPresentModeFlagsKHX>::type Device::getGroupSurfacePresentModesKHX( SurfaceKHR surface ) const\n  {\n    DeviceGroupPresentModeFlagsKHX modes;\n    Result result = static_cast<Result>( vkGetDeviceGroupSurfacePresentModesKHX( m_device, static_cast<VkSurfaceKHR>( surface ), reinterpret_cast<VkDeviceGroupPresentModeFlagsKHX*>( &modes ) ) );\n    return createResultValue( result, modes, \"vk::Device::getGroupSurfacePresentModesKHX\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::acquireNextImage2KHX( const AcquireNextImageInfoKHX* pAcquireInfo, uint32_t* pImageIndex ) const\n  {\n    return static_cast<Result>( vkAcquireNextImage2KHX( m_device, reinterpret_cast<const VkAcquireNextImageInfoKHX*>( pAcquireInfo ), pImageIndex ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValue<uint32_t> Device::acquireNextImage2KHX( const AcquireNextImageInfoKHX & acquireInfo ) const\n  {\n    uint32_t imageIndex;\n    Result result = static_cast<Result>( vkAcquireNextImage2KHX( m_device, reinterpret_cast<const VkAcquireNextImageInfoKHX*>( &acquireInfo ), &imageIndex ) );\n    return createResultValue( result, imageIndex, \"vk::Device::acquireNextImage2KHX\", { Result::eSuccess, Result::eTimeout, Result::eNotReady, Result::eSuboptimalKHR } );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::createDescriptorUpdateTemplateKHR( const DescriptorUpdateTemplateCreateInfoKHR* pCreateInfo, const AllocationCallbacks* pAllocator, DescriptorUpdateTemplateKHR* pDescriptorUpdateTemplate ) const\n  {\n    return static_cast<Result>( vkCreateDescriptorUpdateTemplateKHR( m_device, reinterpret_cast<const VkDescriptorUpdateTemplateCreateInfoKHR*>( pCreateInfo ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ), reinterpret_cast<VkDescriptorUpdateTemplateKHR*>( pDescriptorUpdateTemplate ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<DescriptorUpdateTemplateKHR>::type Device::createDescriptorUpdateTemplateKHR( const DescriptorUpdateTemplateCreateInfoKHR & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    DescriptorUpdateTemplateKHR descriptorUpdateTemplate;\n    Result result = static_cast<Result>( vkCreateDescriptorUpdateTemplateKHR( m_device, reinterpret_cast<const VkDescriptorUpdateTemplateCreateInfoKHR*>( &createInfo ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkDescriptorUpdateTemplateKHR*>( &descriptorUpdateTemplate ) ) );\n    return createResultValue( result, descriptorUpdateTemplate, \"vk::Device::createDescriptorUpdateTemplateKHR\" );\n  }\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  VULKAN_HPP_INLINE UniqueDescriptorUpdateTemplateKHR Device::createDescriptorUpdateTemplateKHRUnique( const DescriptorUpdateTemplateCreateInfoKHR & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    DescriptorUpdateTemplateKHRDeleter deleter( *this, allocator );\n    return UniqueDescriptorUpdateTemplateKHR( createDescriptorUpdateTemplateKHR( createInfo, allocator ), deleter );\n  }\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void Device::destroyDescriptorUpdateTemplateKHR( DescriptorUpdateTemplateKHR descriptorUpdateTemplate, const AllocationCallbacks* pAllocator ) const\n  {\n    vkDestroyDescriptorUpdateTemplateKHR( m_device, static_cast<VkDescriptorUpdateTemplateKHR>( descriptorUpdateTemplate ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void Device::destroyDescriptorUpdateTemplateKHR( DescriptorUpdateTemplateKHR descriptorUpdateTemplate, Optional<const AllocationCallbacks> allocator ) const\n  {\n    vkDestroyDescriptorUpdateTemplateKHR( m_device, static_cast<VkDescriptorUpdateTemplateKHR>( descriptorUpdateTemplate ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void Device::updateDescriptorSetWithTemplateKHR( DescriptorSet descriptorSet, DescriptorUpdateTemplateKHR descriptorUpdateTemplate, const void* pData ) const\n  {\n    vkUpdateDescriptorSetWithTemplateKHR( m_device, static_cast<VkDescriptorSet>( descriptorSet ), static_cast<VkDescriptorUpdateTemplateKHR>( descriptorUpdateTemplate ), pData );\n  }\n\n  VULKAN_HPP_INLINE void Device::setHdrMetadataEXT( uint32_t swapchainCount, const SwapchainKHR* pSwapchains, const HdrMetadataEXT* pMetadata ) const\n  {\n    vkSetHdrMetadataEXT( m_device, swapchainCount, reinterpret_cast<const VkSwapchainKHR*>( pSwapchains ), reinterpret_cast<const VkHdrMetadataEXT*>( pMetadata ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void Device::setHdrMetadataEXT( ArrayProxy<const SwapchainKHR> swapchains, ArrayProxy<const HdrMetadataEXT> metadata ) const\n  {\n#ifdef VULKAN_HPP_NO_EXCEPTIONS\n    assert( swapchains.size() == metadata.size() );\n#else\n    if ( swapchains.size() != metadata.size() )\n    {\n      throw std::logic_error( \"vk::Device::setHdrMetadataEXT: swapchains.size() != metadata.size()\" );\n    }\n#endif  // VULKAN_HPP_NO_EXCEPTIONS\n    vkSetHdrMetadataEXT( m_device, swapchains.size() , reinterpret_cast<const VkSwapchainKHR*>( swapchains.data() ), reinterpret_cast<const VkHdrMetadataEXT*>( metadata.data() ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifdef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE Result Device::getSwapchainStatusKHR( SwapchainKHR swapchain ) const\n  {\n    return static_cast<Result>( vkGetSwapchainStatusKHR( m_device, static_cast<VkSwapchainKHR>( swapchain ) ) );\n  }\n#else\n  VULKAN_HPP_INLINE Result Device::getSwapchainStatusKHR( SwapchainKHR swapchain ) const\n  {\n    Result result = static_cast<Result>( vkGetSwapchainStatusKHR( m_device, static_cast<VkSwapchainKHR>( swapchain ) ) );\n    return createResultValue( result, \"vk::Device::getSwapchainStatusKHR\", { Result::eSuccess, Result::eSuboptimalKHR } );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::getRefreshCycleDurationGOOGLE( SwapchainKHR swapchain, RefreshCycleDurationGOOGLE* pDisplayTimingProperties ) const\n  {\n    return static_cast<Result>( vkGetRefreshCycleDurationGOOGLE( m_device, static_cast<VkSwapchainKHR>( swapchain ), reinterpret_cast<VkRefreshCycleDurationGOOGLE*>( pDisplayTimingProperties ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<RefreshCycleDurationGOOGLE>::type Device::getRefreshCycleDurationGOOGLE( SwapchainKHR swapchain ) const\n  {\n    RefreshCycleDurationGOOGLE displayTimingProperties;\n    Result result = static_cast<Result>( vkGetRefreshCycleDurationGOOGLE( m_device, static_cast<VkSwapchainKHR>( swapchain ), reinterpret_cast<VkRefreshCycleDurationGOOGLE*>( &displayTimingProperties ) ) );\n    return createResultValue( result, displayTimingProperties, \"vk::Device::getRefreshCycleDurationGOOGLE\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Device::getPastPresentationTimingGOOGLE( SwapchainKHR swapchain, uint32_t* pPresentationTimingCount, PastPresentationTimingGOOGLE* pPresentationTimings ) const\n  {\n    return static_cast<Result>( vkGetPastPresentationTimingGOOGLE( m_device, static_cast<VkSwapchainKHR>( swapchain ), pPresentationTimingCount, reinterpret_cast<VkPastPresentationTimingGOOGLE*>( pPresentationTimings ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  template <typename Allocator> \n  VULKAN_HPP_INLINE typename ResultValueType<std::vector<PastPresentationTimingGOOGLE,Allocator>>::type Device::getPastPresentationTimingGOOGLE( SwapchainKHR swapchain ) const\n  {\n    std::vector<PastPresentationTimingGOOGLE,Allocator> presentationTimings;\n    uint32_t presentationTimingCount;\n    Result result = static_cast<Result>( vkGetPastPresentationTimingGOOGLE( m_device, static_cast<VkSwapchainKHR>( swapchain ), &presentationTimingCount, nullptr ) );\n    if ( ( result == Result::eSuccess ) && presentationTimingCount )\n    {\n      presentationTimings.resize( presentationTimingCount );\n      result = static_cast<Result>( vkGetPastPresentationTimingGOOGLE( m_device, static_cast<VkSwapchainKHR>( swapchain ), &presentationTimingCount, reinterpret_cast<VkPastPresentationTimingGOOGLE*>( presentationTimings.data() ) ) );\n    }\n    return createResultValue( result, presentationTimings, \"vk::Device::getPastPresentationTimingGOOGLE\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  class DeviceDeleter;\n  using UniqueDevice = UniqueHandle<Device, DeviceDeleter>;\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n\n  class PhysicalDevice\n  {\n  public:\n    PhysicalDevice()\n      : m_physicalDevice(VK_NULL_HANDLE)\n    {}\n\n    PhysicalDevice( std::nullptr_t )\n      : m_physicalDevice(VK_NULL_HANDLE)\n    {}\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT PhysicalDevice(VkPhysicalDevice physicalDevice)\n       : m_physicalDevice(physicalDevice)\n    {}\n\n#if defined(VULKAN_HPP_TYPESAFE_CONVERSION)\n    PhysicalDevice& operator=(VkPhysicalDevice physicalDevice)\n    {\n      m_physicalDevice = physicalDevice;\n      return *this;\n    }\n#endif\n\n    PhysicalDevice& operator=( std::nullptr_t )\n    {\n      m_physicalDevice = VK_NULL_HANDLE;\n      return *this;\n    }\n\n    bool operator==(PhysicalDevice const &rhs) const\n    {\n      return m_physicalDevice == rhs.m_physicalDevice;\n    }\n\n    bool operator!=(PhysicalDevice const &rhs) const\n    {\n      return m_physicalDevice != rhs.m_physicalDevice;\n    }\n\n    bool operator<(PhysicalDevice const &rhs) const\n    {\n      return m_physicalDevice < rhs.m_physicalDevice;\n    }\n\n    void getProperties( PhysicalDeviceProperties* pProperties ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    PhysicalDeviceProperties getProperties() const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void getQueueFamilyProperties( uint32_t* pQueueFamilyPropertyCount, QueueFamilyProperties* pQueueFamilyProperties ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    template <typename Allocator = std::allocator<QueueFamilyProperties>> \n    std::vector<QueueFamilyProperties,Allocator> getQueueFamilyProperties() const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void getMemoryProperties( PhysicalDeviceMemoryProperties* pMemoryProperties ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    PhysicalDeviceMemoryProperties getMemoryProperties() const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void getFeatures( PhysicalDeviceFeatures* pFeatures ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    PhysicalDeviceFeatures getFeatures() const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void getFormatProperties( Format format, FormatProperties* pFormatProperties ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    FormatProperties getFormatProperties( Format format ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result getImageFormatProperties( Format format, ImageType type, ImageTiling tiling, ImageUsageFlags usage, ImageCreateFlags flags, ImageFormatProperties* pImageFormatProperties ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<ImageFormatProperties>::type getImageFormatProperties( Format format, ImageType type, ImageTiling tiling, ImageUsageFlags usage, ImageCreateFlags flags ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result createDevice( const DeviceCreateInfo* pCreateInfo, const AllocationCallbacks* pAllocator, Device* pDevice ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<Device>::type createDevice( const DeviceCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n    UniqueDevice createDeviceUnique( const DeviceCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result enumerateDeviceLayerProperties( uint32_t* pPropertyCount, LayerProperties* pProperties ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    template <typename Allocator = std::allocator<LayerProperties>> \n    typename ResultValueType<std::vector<LayerProperties,Allocator>>::type enumerateDeviceLayerProperties() const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result enumerateDeviceExtensionProperties( const char* pLayerName, uint32_t* pPropertyCount, ExtensionProperties* pProperties ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    template <typename Allocator = std::allocator<ExtensionProperties>> \n    typename ResultValueType<std::vector<ExtensionProperties,Allocator>>::type enumerateDeviceExtensionProperties( Optional<const std::string> layerName = nullptr ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void getSparseImageFormatProperties( Format format, ImageType type, SampleCountFlagBits samples, ImageUsageFlags usage, ImageTiling tiling, uint32_t* pPropertyCount, SparseImageFormatProperties* pProperties ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    template <typename Allocator = std::allocator<SparseImageFormatProperties>> \n    std::vector<SparseImageFormatProperties,Allocator> getSparseImageFormatProperties( Format format, ImageType type, SampleCountFlagBits samples, ImageUsageFlags usage, ImageTiling tiling ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result getDisplayPropertiesKHR( uint32_t* pPropertyCount, DisplayPropertiesKHR* pProperties ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    template <typename Allocator = std::allocator<DisplayPropertiesKHR>> \n    typename ResultValueType<std::vector<DisplayPropertiesKHR,Allocator>>::type getDisplayPropertiesKHR() const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result getDisplayPlanePropertiesKHR( uint32_t* pPropertyCount, DisplayPlanePropertiesKHR* pProperties ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    template <typename Allocator = std::allocator<DisplayPlanePropertiesKHR>> \n    typename ResultValueType<std::vector<DisplayPlanePropertiesKHR,Allocator>>::type getDisplayPlanePropertiesKHR() const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result getDisplayPlaneSupportedDisplaysKHR( uint32_t planeIndex, uint32_t* pDisplayCount, DisplayKHR* pDisplays ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    template <typename Allocator = std::allocator<DisplayKHR>> \n    typename ResultValueType<std::vector<DisplayKHR,Allocator>>::type getDisplayPlaneSupportedDisplaysKHR( uint32_t planeIndex ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result getDisplayModePropertiesKHR( DisplayKHR display, uint32_t* pPropertyCount, DisplayModePropertiesKHR* pProperties ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    template <typename Allocator = std::allocator<DisplayModePropertiesKHR>> \n    typename ResultValueType<std::vector<DisplayModePropertiesKHR,Allocator>>::type getDisplayModePropertiesKHR( DisplayKHR display ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result createDisplayModeKHR( DisplayKHR display, const DisplayModeCreateInfoKHR* pCreateInfo, const AllocationCallbacks* pAllocator, DisplayModeKHR* pMode ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<DisplayModeKHR>::type createDisplayModeKHR( DisplayKHR display, const DisplayModeCreateInfoKHR & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result getDisplayPlaneCapabilitiesKHR( DisplayModeKHR mode, uint32_t planeIndex, DisplayPlaneCapabilitiesKHR* pCapabilities ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<DisplayPlaneCapabilitiesKHR>::type getDisplayPlaneCapabilitiesKHR( DisplayModeKHR mode, uint32_t planeIndex ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifdef VK_USE_PLATFORM_MIR_KHR\n    Bool32 getMirPresentationSupportKHR( uint32_t queueFamilyIndex, MirConnection* connection ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    Bool32 getMirPresentationSupportKHR( uint32_t queueFamilyIndex, MirConnection & connection ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n#endif /*VK_USE_PLATFORM_MIR_KHR*/\n\n    Result getSurfaceSupportKHR( uint32_t queueFamilyIndex, SurfaceKHR surface, Bool32* pSupported ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<Bool32>::type getSurfaceSupportKHR( uint32_t queueFamilyIndex, SurfaceKHR surface ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result getSurfaceCapabilitiesKHR( SurfaceKHR surface, SurfaceCapabilitiesKHR* pSurfaceCapabilities ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<SurfaceCapabilitiesKHR>::type getSurfaceCapabilitiesKHR( SurfaceKHR surface ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result getSurfaceFormatsKHR( SurfaceKHR surface, uint32_t* pSurfaceFormatCount, SurfaceFormatKHR* pSurfaceFormats ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    template <typename Allocator = std::allocator<SurfaceFormatKHR>> \n    typename ResultValueType<std::vector<SurfaceFormatKHR,Allocator>>::type getSurfaceFormatsKHR( SurfaceKHR surface ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result getSurfacePresentModesKHR( SurfaceKHR surface, uint32_t* pPresentModeCount, PresentModeKHR* pPresentModes ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    template <typename Allocator = std::allocator<PresentModeKHR>> \n    typename ResultValueType<std::vector<PresentModeKHR,Allocator>>::type getSurfacePresentModesKHR( SurfaceKHR surface ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifdef VK_USE_PLATFORM_WAYLAND_KHR\n    Bool32 getWaylandPresentationSupportKHR( uint32_t queueFamilyIndex, struct wl_display* display ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    Bool32 getWaylandPresentationSupportKHR( uint32_t queueFamilyIndex, struct wl_display & display ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n#endif /*VK_USE_PLATFORM_WAYLAND_KHR*/\n\n#ifdef VK_USE_PLATFORM_WIN32_KHR\n    Bool32 getWin32PresentationSupportKHR( uint32_t queueFamilyIndex ) const;\n#endif /*VK_USE_PLATFORM_WIN32_KHR*/\n\n#ifdef VK_USE_PLATFORM_XLIB_KHR\n    Bool32 getXlibPresentationSupportKHR( uint32_t queueFamilyIndex, Display* dpy, VisualID visualID ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    Bool32 getXlibPresentationSupportKHR( uint32_t queueFamilyIndex, Display & dpy, VisualID visualID ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n#endif /*VK_USE_PLATFORM_XLIB_KHR*/\n\n#ifdef VK_USE_PLATFORM_XCB_KHR\n    Bool32 getXcbPresentationSupportKHR( uint32_t queueFamilyIndex, xcb_connection_t* connection, xcb_visualid_t visual_id ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    Bool32 getXcbPresentationSupportKHR( uint32_t queueFamilyIndex, xcb_connection_t & connection, xcb_visualid_t visual_id ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n#endif /*VK_USE_PLATFORM_XCB_KHR*/\n\n    Result getExternalImageFormatPropertiesNV( Format format, ImageType type, ImageTiling tiling, ImageUsageFlags usage, ImageCreateFlags flags, ExternalMemoryHandleTypeFlagsNV externalHandleType, ExternalImageFormatPropertiesNV* pExternalImageFormatProperties ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<ExternalImageFormatPropertiesNV>::type getExternalImageFormatPropertiesNV( Format format, ImageType type, ImageTiling tiling, ImageUsageFlags usage, ImageCreateFlags flags, ExternalMemoryHandleTypeFlagsNV externalHandleType ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void getGeneratedCommandsPropertiesNVX( DeviceGeneratedCommandsFeaturesNVX* pFeatures, DeviceGeneratedCommandsLimitsNVX* pLimits ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    DeviceGeneratedCommandsLimitsNVX getGeneratedCommandsPropertiesNVX( DeviceGeneratedCommandsFeaturesNVX & features ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void getFeatures2KHR( PhysicalDeviceFeatures2KHR* pFeatures ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    PhysicalDeviceFeatures2KHR getFeatures2KHR() const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void getProperties2KHR( PhysicalDeviceProperties2KHR* pProperties ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    PhysicalDeviceProperties2KHR getProperties2KHR() const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void getFormatProperties2KHR( Format format, FormatProperties2KHR* pFormatProperties ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    FormatProperties2KHR getFormatProperties2KHR( Format format ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result getImageFormatProperties2KHR( const PhysicalDeviceImageFormatInfo2KHR* pImageFormatInfo, ImageFormatProperties2KHR* pImageFormatProperties ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<ImageFormatProperties2KHR>::type getImageFormatProperties2KHR( const PhysicalDeviceImageFormatInfo2KHR & imageFormatInfo ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void getQueueFamilyProperties2KHR( uint32_t* pQueueFamilyPropertyCount, QueueFamilyProperties2KHR* pQueueFamilyProperties ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    template <typename Allocator = std::allocator<QueueFamilyProperties2KHR>> \n    std::vector<QueueFamilyProperties2KHR,Allocator> getQueueFamilyProperties2KHR() const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void getMemoryProperties2KHR( PhysicalDeviceMemoryProperties2KHR* pMemoryProperties ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    PhysicalDeviceMemoryProperties2KHR getMemoryProperties2KHR() const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void getSparseImageFormatProperties2KHR( const PhysicalDeviceSparseImageFormatInfo2KHR* pFormatInfo, uint32_t* pPropertyCount, SparseImageFormatProperties2KHR* pProperties ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    template <typename Allocator = std::allocator<SparseImageFormatProperties2KHR>> \n    std::vector<SparseImageFormatProperties2KHR,Allocator> getSparseImageFormatProperties2KHR( const PhysicalDeviceSparseImageFormatInfo2KHR & formatInfo ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void getExternalBufferPropertiesKHX( const PhysicalDeviceExternalBufferInfoKHX* pExternalBufferInfo, ExternalBufferPropertiesKHX* pExternalBufferProperties ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ExternalBufferPropertiesKHX getExternalBufferPropertiesKHX( const PhysicalDeviceExternalBufferInfoKHX & externalBufferInfo ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void getExternalSemaphorePropertiesKHX( const PhysicalDeviceExternalSemaphoreInfoKHX* pExternalSemaphoreInfo, ExternalSemaphorePropertiesKHX* pExternalSemaphoreProperties ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ExternalSemaphorePropertiesKHX getExternalSemaphorePropertiesKHX( const PhysicalDeviceExternalSemaphoreInfoKHX & externalSemaphoreInfo ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifdef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    Result releaseDisplayEXT( DisplayKHR display ) const;\n#else\n    ResultValueType<void>::type releaseDisplayEXT( DisplayKHR display ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT\n    Result acquireXlibDisplayEXT( Display* dpy, DisplayKHR display ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<Display>::type acquireXlibDisplayEXT( DisplayKHR display ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n#endif /*VK_USE_PLATFORM_XLIB_XRANDR_EXT*/\n\n#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT\n    Result getRandROutputDisplayEXT( Display* dpy, RROutput rrOutput, DisplayKHR* pDisplay ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<DisplayKHR>::type getRandROutputDisplayEXT( Display & dpy, RROutput rrOutput ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n#endif /*VK_USE_PLATFORM_XLIB_XRANDR_EXT*/\n\n    Result getSurfaceCapabilities2EXT( SurfaceKHR surface, SurfaceCapabilities2EXT* pSurfaceCapabilities ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<SurfaceCapabilities2EXT>::type getSurfaceCapabilities2EXT( SurfaceKHR surface ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result getPresentRectanglesKHX( SurfaceKHR surface, uint32_t* pRectCount, Rect2D* pRects ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    template <typename Allocator = std::allocator<Rect2D>> \n    typename ResultValueType<std::vector<Rect2D,Allocator>>::type getPresentRectanglesKHX( SurfaceKHR surface ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result getSurfaceCapabilities2KHR( const PhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, SurfaceCapabilities2KHR* pSurfaceCapabilities ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    Result getSurfaceCapabilities2KHR( const PhysicalDeviceSurfaceInfo2KHR & surfaceInfo ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result getSurfaceFormats2KHR( const PhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, uint32_t* pSurfaceFormatCount, SurfaceFormat2KHR* pSurfaceFormats ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    template <typename Allocator = std::allocator<SurfaceFormat2KHR>> \n    typename ResultValueType<std::vector<SurfaceFormat2KHR,Allocator>>::type getSurfaceFormats2KHR( const PhysicalDeviceSurfaceInfo2KHR & surfaceInfo ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT operator VkPhysicalDevice() const\n    {\n      return m_physicalDevice;\n    }\n\n    explicit operator bool() const\n    {\n      return m_physicalDevice != VK_NULL_HANDLE;\n    }\n\n    bool operator!() const\n    {\n      return m_physicalDevice == VK_NULL_HANDLE;\n    }\n\n  private:\n    VkPhysicalDevice m_physicalDevice;\n  };\n  static_assert( sizeof( PhysicalDevice ) == sizeof( VkPhysicalDevice ), \"handle and wrapper have different size!\" );\n\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  class DeviceDeleter\n  {\n  public:\n    DeviceDeleter( Optional<const AllocationCallbacks> allocator = nullptr )\n      : m_allocator( allocator )\n    {}\n\n    void operator()( Device device )\n    {\n      device.destroy( m_allocator );\n    }\n\n  private:\n    Optional<const AllocationCallbacks> m_allocator;\n  };\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n\n  VULKAN_HPP_INLINE void PhysicalDevice::getProperties( PhysicalDeviceProperties* pProperties ) const\n  {\n    vkGetPhysicalDeviceProperties( m_physicalDevice, reinterpret_cast<VkPhysicalDeviceProperties*>( pProperties ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE PhysicalDeviceProperties PhysicalDevice::getProperties() const\n  {\n    PhysicalDeviceProperties properties;\n    vkGetPhysicalDeviceProperties( m_physicalDevice, reinterpret_cast<VkPhysicalDeviceProperties*>( &properties ) );\n    return properties;\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void PhysicalDevice::getQueueFamilyProperties( uint32_t* pQueueFamilyPropertyCount, QueueFamilyProperties* pQueueFamilyProperties ) const\n  {\n    vkGetPhysicalDeviceQueueFamilyProperties( m_physicalDevice, pQueueFamilyPropertyCount, reinterpret_cast<VkQueueFamilyProperties*>( pQueueFamilyProperties ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  template <typename Allocator> \n  VULKAN_HPP_INLINE std::vector<QueueFamilyProperties,Allocator> PhysicalDevice::getQueueFamilyProperties() const\n  {\n    std::vector<QueueFamilyProperties,Allocator> queueFamilyProperties;\n    uint32_t queueFamilyPropertyCount;\n    vkGetPhysicalDeviceQueueFamilyProperties( m_physicalDevice, &queueFamilyPropertyCount, nullptr );\n    queueFamilyProperties.resize( queueFamilyPropertyCount );\n    vkGetPhysicalDeviceQueueFamilyProperties( m_physicalDevice, &queueFamilyPropertyCount, reinterpret_cast<VkQueueFamilyProperties*>( queueFamilyProperties.data() ) );\n    return queueFamilyProperties;\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void PhysicalDevice::getMemoryProperties( PhysicalDeviceMemoryProperties* pMemoryProperties ) const\n  {\n    vkGetPhysicalDeviceMemoryProperties( m_physicalDevice, reinterpret_cast<VkPhysicalDeviceMemoryProperties*>( pMemoryProperties ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE PhysicalDeviceMemoryProperties PhysicalDevice::getMemoryProperties() const\n  {\n    PhysicalDeviceMemoryProperties memoryProperties;\n    vkGetPhysicalDeviceMemoryProperties( m_physicalDevice, reinterpret_cast<VkPhysicalDeviceMemoryProperties*>( &memoryProperties ) );\n    return memoryProperties;\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void PhysicalDevice::getFeatures( PhysicalDeviceFeatures* pFeatures ) const\n  {\n    vkGetPhysicalDeviceFeatures( m_physicalDevice, reinterpret_cast<VkPhysicalDeviceFeatures*>( pFeatures ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE PhysicalDeviceFeatures PhysicalDevice::getFeatures() const\n  {\n    PhysicalDeviceFeatures features;\n    vkGetPhysicalDeviceFeatures( m_physicalDevice, reinterpret_cast<VkPhysicalDeviceFeatures*>( &features ) );\n    return features;\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void PhysicalDevice::getFormatProperties( Format format, FormatProperties* pFormatProperties ) const\n  {\n    vkGetPhysicalDeviceFormatProperties( m_physicalDevice, static_cast<VkFormat>( format ), reinterpret_cast<VkFormatProperties*>( pFormatProperties ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE FormatProperties PhysicalDevice::getFormatProperties( Format format ) const\n  {\n    FormatProperties formatProperties;\n    vkGetPhysicalDeviceFormatProperties( m_physicalDevice, static_cast<VkFormat>( format ), reinterpret_cast<VkFormatProperties*>( &formatProperties ) );\n    return formatProperties;\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result PhysicalDevice::getImageFormatProperties( Format format, ImageType type, ImageTiling tiling, ImageUsageFlags usage, ImageCreateFlags flags, ImageFormatProperties* pImageFormatProperties ) const\n  {\n    return static_cast<Result>( vkGetPhysicalDeviceImageFormatProperties( m_physicalDevice, static_cast<VkFormat>( format ), static_cast<VkImageType>( type ), static_cast<VkImageTiling>( tiling ), static_cast<VkImageUsageFlags>( usage ), static_cast<VkImageCreateFlags>( flags ), reinterpret_cast<VkImageFormatProperties*>( pImageFormatProperties ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<ImageFormatProperties>::type PhysicalDevice::getImageFormatProperties( Format format, ImageType type, ImageTiling tiling, ImageUsageFlags usage, ImageCreateFlags flags ) const\n  {\n    ImageFormatProperties imageFormatProperties;\n    Result result = static_cast<Result>( vkGetPhysicalDeviceImageFormatProperties( m_physicalDevice, static_cast<VkFormat>( format ), static_cast<VkImageType>( type ), static_cast<VkImageTiling>( tiling ), static_cast<VkImageUsageFlags>( usage ), static_cast<VkImageCreateFlags>( flags ), reinterpret_cast<VkImageFormatProperties*>( &imageFormatProperties ) ) );\n    return createResultValue( result, imageFormatProperties, \"vk::PhysicalDevice::getImageFormatProperties\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result PhysicalDevice::createDevice( const DeviceCreateInfo* pCreateInfo, const AllocationCallbacks* pAllocator, Device* pDevice ) const\n  {\n    return static_cast<Result>( vkCreateDevice( m_physicalDevice, reinterpret_cast<const VkDeviceCreateInfo*>( pCreateInfo ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ), reinterpret_cast<VkDevice*>( pDevice ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<Device>::type PhysicalDevice::createDevice( const DeviceCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    Device device;\n    Result result = static_cast<Result>( vkCreateDevice( m_physicalDevice, reinterpret_cast<const VkDeviceCreateInfo*>( &createInfo ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkDevice*>( &device ) ) );\n    return createResultValue( result, device, \"vk::PhysicalDevice::createDevice\" );\n  }\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  VULKAN_HPP_INLINE UniqueDevice PhysicalDevice::createDeviceUnique( const DeviceCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    DeviceDeleter deleter( allocator );\n    return UniqueDevice( createDevice( createInfo, allocator ), deleter );\n  }\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result PhysicalDevice::enumerateDeviceLayerProperties( uint32_t* pPropertyCount, LayerProperties* pProperties ) const\n  {\n    return static_cast<Result>( vkEnumerateDeviceLayerProperties( m_physicalDevice, pPropertyCount, reinterpret_cast<VkLayerProperties*>( pProperties ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  template <typename Allocator> \n  VULKAN_HPP_INLINE typename ResultValueType<std::vector<LayerProperties,Allocator>>::type PhysicalDevice::enumerateDeviceLayerProperties() const\n  {\n    std::vector<LayerProperties,Allocator> properties;\n    uint32_t propertyCount;\n    Result result;\n    do\n    {\n      result = static_cast<Result>( vkEnumerateDeviceLayerProperties( m_physicalDevice, &propertyCount, nullptr ) );\n      if ( ( result == Result::eSuccess ) && propertyCount )\n      {\n        properties.resize( propertyCount );\n        result = static_cast<Result>( vkEnumerateDeviceLayerProperties( m_physicalDevice, &propertyCount, reinterpret_cast<VkLayerProperties*>( properties.data() ) ) );\n      }\n    } while ( result == Result::eIncomplete );\n    assert( propertyCount <= properties.size() ); \n    properties.resize( propertyCount ); \n    return createResultValue( result, properties, \"vk::PhysicalDevice::enumerateDeviceLayerProperties\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result PhysicalDevice::enumerateDeviceExtensionProperties( const char* pLayerName, uint32_t* pPropertyCount, ExtensionProperties* pProperties ) const\n  {\n    return static_cast<Result>( vkEnumerateDeviceExtensionProperties( m_physicalDevice, pLayerName, pPropertyCount, reinterpret_cast<VkExtensionProperties*>( pProperties ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  template <typename Allocator> \n  VULKAN_HPP_INLINE typename ResultValueType<std::vector<ExtensionProperties,Allocator>>::type PhysicalDevice::enumerateDeviceExtensionProperties( Optional<const std::string> layerName ) const\n  {\n    std::vector<ExtensionProperties,Allocator> properties;\n    uint32_t propertyCount;\n    Result result;\n    do\n    {\n      result = static_cast<Result>( vkEnumerateDeviceExtensionProperties( m_physicalDevice, layerName ? layerName->c_str() : nullptr, &propertyCount, nullptr ) );\n      if ( ( result == Result::eSuccess ) && propertyCount )\n      {\n        properties.resize( propertyCount );\n        result = static_cast<Result>( vkEnumerateDeviceExtensionProperties( m_physicalDevice, layerName ? layerName->c_str() : nullptr, &propertyCount, reinterpret_cast<VkExtensionProperties*>( properties.data() ) ) );\n      }\n    } while ( result == Result::eIncomplete );\n    assert( propertyCount <= properties.size() ); \n    properties.resize( propertyCount ); \n    return createResultValue( result, properties, \"vk::PhysicalDevice::enumerateDeviceExtensionProperties\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void PhysicalDevice::getSparseImageFormatProperties( Format format, ImageType type, SampleCountFlagBits samples, ImageUsageFlags usage, ImageTiling tiling, uint32_t* pPropertyCount, SparseImageFormatProperties* pProperties ) const\n  {\n    vkGetPhysicalDeviceSparseImageFormatProperties( m_physicalDevice, static_cast<VkFormat>( format ), static_cast<VkImageType>( type ), static_cast<VkSampleCountFlagBits>( samples ), static_cast<VkImageUsageFlags>( usage ), static_cast<VkImageTiling>( tiling ), pPropertyCount, reinterpret_cast<VkSparseImageFormatProperties*>( pProperties ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  template <typename Allocator> \n  VULKAN_HPP_INLINE std::vector<SparseImageFormatProperties,Allocator> PhysicalDevice::getSparseImageFormatProperties( Format format, ImageType type, SampleCountFlagBits samples, ImageUsageFlags usage, ImageTiling tiling ) const\n  {\n    std::vector<SparseImageFormatProperties,Allocator> properties;\n    uint32_t propertyCount;\n    vkGetPhysicalDeviceSparseImageFormatProperties( m_physicalDevice, static_cast<VkFormat>( format ), static_cast<VkImageType>( type ), static_cast<VkSampleCountFlagBits>( samples ), static_cast<VkImageUsageFlags>( usage ), static_cast<VkImageTiling>( tiling ), &propertyCount, nullptr );\n    properties.resize( propertyCount );\n    vkGetPhysicalDeviceSparseImageFormatProperties( m_physicalDevice, static_cast<VkFormat>( format ), static_cast<VkImageType>( type ), static_cast<VkSampleCountFlagBits>( samples ), static_cast<VkImageUsageFlags>( usage ), static_cast<VkImageTiling>( tiling ), &propertyCount, reinterpret_cast<VkSparseImageFormatProperties*>( properties.data() ) );\n    return properties;\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result PhysicalDevice::getDisplayPropertiesKHR( uint32_t* pPropertyCount, DisplayPropertiesKHR* pProperties ) const\n  {\n    return static_cast<Result>( vkGetPhysicalDeviceDisplayPropertiesKHR( m_physicalDevice, pPropertyCount, reinterpret_cast<VkDisplayPropertiesKHR*>( pProperties ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  template <typename Allocator> \n  VULKAN_HPP_INLINE typename ResultValueType<std::vector<DisplayPropertiesKHR,Allocator>>::type PhysicalDevice::getDisplayPropertiesKHR() const\n  {\n    std::vector<DisplayPropertiesKHR,Allocator> properties;\n    uint32_t propertyCount;\n    Result result;\n    do\n    {\n      result = static_cast<Result>( vkGetPhysicalDeviceDisplayPropertiesKHR( m_physicalDevice, &propertyCount, nullptr ) );\n      if ( ( result == Result::eSuccess ) && propertyCount )\n      {\n        properties.resize( propertyCount );\n        result = static_cast<Result>( vkGetPhysicalDeviceDisplayPropertiesKHR( m_physicalDevice, &propertyCount, reinterpret_cast<VkDisplayPropertiesKHR*>( properties.data() ) ) );\n      }\n    } while ( result == Result::eIncomplete );\n    assert( propertyCount <= properties.size() ); \n    properties.resize( propertyCount ); \n    return createResultValue( result, properties, \"vk::PhysicalDevice::getDisplayPropertiesKHR\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result PhysicalDevice::getDisplayPlanePropertiesKHR( uint32_t* pPropertyCount, DisplayPlanePropertiesKHR* pProperties ) const\n  {\n    return static_cast<Result>( vkGetPhysicalDeviceDisplayPlanePropertiesKHR( m_physicalDevice, pPropertyCount, reinterpret_cast<VkDisplayPlanePropertiesKHR*>( pProperties ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  template <typename Allocator> \n  VULKAN_HPP_INLINE typename ResultValueType<std::vector<DisplayPlanePropertiesKHR,Allocator>>::type PhysicalDevice::getDisplayPlanePropertiesKHR() const\n  {\n    std::vector<DisplayPlanePropertiesKHR,Allocator> properties;\n    uint32_t propertyCount;\n    Result result;\n    do\n    {\n      result = static_cast<Result>( vkGetPhysicalDeviceDisplayPlanePropertiesKHR( m_physicalDevice, &propertyCount, nullptr ) );\n      if ( ( result == Result::eSuccess ) && propertyCount )\n      {\n        properties.resize( propertyCount );\n        result = static_cast<Result>( vkGetPhysicalDeviceDisplayPlanePropertiesKHR( m_physicalDevice, &propertyCount, reinterpret_cast<VkDisplayPlanePropertiesKHR*>( properties.data() ) ) );\n      }\n    } while ( result == Result::eIncomplete );\n    assert( propertyCount <= properties.size() ); \n    properties.resize( propertyCount ); \n    return createResultValue( result, properties, \"vk::PhysicalDevice::getDisplayPlanePropertiesKHR\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result PhysicalDevice::getDisplayPlaneSupportedDisplaysKHR( uint32_t planeIndex, uint32_t* pDisplayCount, DisplayKHR* pDisplays ) const\n  {\n    return static_cast<Result>( vkGetDisplayPlaneSupportedDisplaysKHR( m_physicalDevice, planeIndex, pDisplayCount, reinterpret_cast<VkDisplayKHR*>( pDisplays ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  template <typename Allocator> \n  VULKAN_HPP_INLINE typename ResultValueType<std::vector<DisplayKHR,Allocator>>::type PhysicalDevice::getDisplayPlaneSupportedDisplaysKHR( uint32_t planeIndex ) const\n  {\n    std::vector<DisplayKHR,Allocator> displays;\n    uint32_t displayCount;\n    Result result;\n    do\n    {\n      result = static_cast<Result>( vkGetDisplayPlaneSupportedDisplaysKHR( m_physicalDevice, planeIndex, &displayCount, nullptr ) );\n      if ( ( result == Result::eSuccess ) && displayCount )\n      {\n        displays.resize( displayCount );\n        result = static_cast<Result>( vkGetDisplayPlaneSupportedDisplaysKHR( m_physicalDevice, planeIndex, &displayCount, reinterpret_cast<VkDisplayKHR*>( displays.data() ) ) );\n      }\n    } while ( result == Result::eIncomplete );\n    assert( displayCount <= displays.size() ); \n    displays.resize( displayCount ); \n    return createResultValue( result, displays, \"vk::PhysicalDevice::getDisplayPlaneSupportedDisplaysKHR\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result PhysicalDevice::getDisplayModePropertiesKHR( DisplayKHR display, uint32_t* pPropertyCount, DisplayModePropertiesKHR* pProperties ) const\n  {\n    return static_cast<Result>( vkGetDisplayModePropertiesKHR( m_physicalDevice, static_cast<VkDisplayKHR>( display ), pPropertyCount, reinterpret_cast<VkDisplayModePropertiesKHR*>( pProperties ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  template <typename Allocator> \n  VULKAN_HPP_INLINE typename ResultValueType<std::vector<DisplayModePropertiesKHR,Allocator>>::type PhysicalDevice::getDisplayModePropertiesKHR( DisplayKHR display ) const\n  {\n    std::vector<DisplayModePropertiesKHR,Allocator> properties;\n    uint32_t propertyCount;\n    Result result;\n    do\n    {\n      result = static_cast<Result>( vkGetDisplayModePropertiesKHR( m_physicalDevice, static_cast<VkDisplayKHR>( display ), &propertyCount, nullptr ) );\n      if ( ( result == Result::eSuccess ) && propertyCount )\n      {\n        properties.resize( propertyCount );\n        result = static_cast<Result>( vkGetDisplayModePropertiesKHR( m_physicalDevice, static_cast<VkDisplayKHR>( display ), &propertyCount, reinterpret_cast<VkDisplayModePropertiesKHR*>( properties.data() ) ) );\n      }\n    } while ( result == Result::eIncomplete );\n    assert( propertyCount <= properties.size() ); \n    properties.resize( propertyCount ); \n    return createResultValue( result, properties, \"vk::PhysicalDevice::getDisplayModePropertiesKHR\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result PhysicalDevice::createDisplayModeKHR( DisplayKHR display, const DisplayModeCreateInfoKHR* pCreateInfo, const AllocationCallbacks* pAllocator, DisplayModeKHR* pMode ) const\n  {\n    return static_cast<Result>( vkCreateDisplayModeKHR( m_physicalDevice, static_cast<VkDisplayKHR>( display ), reinterpret_cast<const VkDisplayModeCreateInfoKHR*>( pCreateInfo ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ), reinterpret_cast<VkDisplayModeKHR*>( pMode ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<DisplayModeKHR>::type PhysicalDevice::createDisplayModeKHR( DisplayKHR display, const DisplayModeCreateInfoKHR & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    DisplayModeKHR mode;\n    Result result = static_cast<Result>( vkCreateDisplayModeKHR( m_physicalDevice, static_cast<VkDisplayKHR>( display ), reinterpret_cast<const VkDisplayModeCreateInfoKHR*>( &createInfo ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkDisplayModeKHR*>( &mode ) ) );\n    return createResultValue( result, mode, \"vk::PhysicalDevice::createDisplayModeKHR\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result PhysicalDevice::getDisplayPlaneCapabilitiesKHR( DisplayModeKHR mode, uint32_t planeIndex, DisplayPlaneCapabilitiesKHR* pCapabilities ) const\n  {\n    return static_cast<Result>( vkGetDisplayPlaneCapabilitiesKHR( m_physicalDevice, static_cast<VkDisplayModeKHR>( mode ), planeIndex, reinterpret_cast<VkDisplayPlaneCapabilitiesKHR*>( pCapabilities ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<DisplayPlaneCapabilitiesKHR>::type PhysicalDevice::getDisplayPlaneCapabilitiesKHR( DisplayModeKHR mode, uint32_t planeIndex ) const\n  {\n    DisplayPlaneCapabilitiesKHR capabilities;\n    Result result = static_cast<Result>( vkGetDisplayPlaneCapabilitiesKHR( m_physicalDevice, static_cast<VkDisplayModeKHR>( mode ), planeIndex, reinterpret_cast<VkDisplayPlaneCapabilitiesKHR*>( &capabilities ) ) );\n    return createResultValue( result, capabilities, \"vk::PhysicalDevice::getDisplayPlaneCapabilitiesKHR\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifdef VK_USE_PLATFORM_MIR_KHR\n  VULKAN_HPP_INLINE Bool32 PhysicalDevice::getMirPresentationSupportKHR( uint32_t queueFamilyIndex, MirConnection* connection ) const\n  {\n    return vkGetPhysicalDeviceMirPresentationSupportKHR( m_physicalDevice, queueFamilyIndex, connection );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE Bool32 PhysicalDevice::getMirPresentationSupportKHR( uint32_t queueFamilyIndex, MirConnection & connection ) const\n  {\n    return vkGetPhysicalDeviceMirPresentationSupportKHR( m_physicalDevice, queueFamilyIndex, &connection );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n#endif /*VK_USE_PLATFORM_MIR_KHR*/\n\n  VULKAN_HPP_INLINE Result PhysicalDevice::getSurfaceSupportKHR( uint32_t queueFamilyIndex, SurfaceKHR surface, Bool32* pSupported ) const\n  {\n    return static_cast<Result>( vkGetPhysicalDeviceSurfaceSupportKHR( m_physicalDevice, queueFamilyIndex, static_cast<VkSurfaceKHR>( surface ), pSupported ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<Bool32>::type PhysicalDevice::getSurfaceSupportKHR( uint32_t queueFamilyIndex, SurfaceKHR surface ) const\n  {\n    Bool32 supported;\n    Result result = static_cast<Result>( vkGetPhysicalDeviceSurfaceSupportKHR( m_physicalDevice, queueFamilyIndex, static_cast<VkSurfaceKHR>( surface ), &supported ) );\n    return createResultValue( result, supported, \"vk::PhysicalDevice::getSurfaceSupportKHR\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result PhysicalDevice::getSurfaceCapabilitiesKHR( SurfaceKHR surface, SurfaceCapabilitiesKHR* pSurfaceCapabilities ) const\n  {\n    return static_cast<Result>( vkGetPhysicalDeviceSurfaceCapabilitiesKHR( m_physicalDevice, static_cast<VkSurfaceKHR>( surface ), reinterpret_cast<VkSurfaceCapabilitiesKHR*>( pSurfaceCapabilities ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<SurfaceCapabilitiesKHR>::type PhysicalDevice::getSurfaceCapabilitiesKHR( SurfaceKHR surface ) const\n  {\n    SurfaceCapabilitiesKHR surfaceCapabilities;\n    Result result = static_cast<Result>( vkGetPhysicalDeviceSurfaceCapabilitiesKHR( m_physicalDevice, static_cast<VkSurfaceKHR>( surface ), reinterpret_cast<VkSurfaceCapabilitiesKHR*>( &surfaceCapabilities ) ) );\n    return createResultValue( result, surfaceCapabilities, \"vk::PhysicalDevice::getSurfaceCapabilitiesKHR\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result PhysicalDevice::getSurfaceFormatsKHR( SurfaceKHR surface, uint32_t* pSurfaceFormatCount, SurfaceFormatKHR* pSurfaceFormats ) const\n  {\n    return static_cast<Result>( vkGetPhysicalDeviceSurfaceFormatsKHR( m_physicalDevice, static_cast<VkSurfaceKHR>( surface ), pSurfaceFormatCount, reinterpret_cast<VkSurfaceFormatKHR*>( pSurfaceFormats ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  template <typename Allocator> \n  VULKAN_HPP_INLINE typename ResultValueType<std::vector<SurfaceFormatKHR,Allocator>>::type PhysicalDevice::getSurfaceFormatsKHR( SurfaceKHR surface ) const\n  {\n    std::vector<SurfaceFormatKHR,Allocator> surfaceFormats;\n    uint32_t surfaceFormatCount;\n    Result result;\n    do\n    {\n      result = static_cast<Result>( vkGetPhysicalDeviceSurfaceFormatsKHR( m_physicalDevice, static_cast<VkSurfaceKHR>( surface ), &surfaceFormatCount, nullptr ) );\n      if ( ( result == Result::eSuccess ) && surfaceFormatCount )\n      {\n        surfaceFormats.resize( surfaceFormatCount );\n        result = static_cast<Result>( vkGetPhysicalDeviceSurfaceFormatsKHR( m_physicalDevice, static_cast<VkSurfaceKHR>( surface ), &surfaceFormatCount, reinterpret_cast<VkSurfaceFormatKHR*>( surfaceFormats.data() ) ) );\n      }\n    } while ( result == Result::eIncomplete );\n    assert( surfaceFormatCount <= surfaceFormats.size() ); \n    surfaceFormats.resize( surfaceFormatCount ); \n    return createResultValue( result, surfaceFormats, \"vk::PhysicalDevice::getSurfaceFormatsKHR\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result PhysicalDevice::getSurfacePresentModesKHR( SurfaceKHR surface, uint32_t* pPresentModeCount, PresentModeKHR* pPresentModes ) const\n  {\n    return static_cast<Result>( vkGetPhysicalDeviceSurfacePresentModesKHR( m_physicalDevice, static_cast<VkSurfaceKHR>( surface ), pPresentModeCount, reinterpret_cast<VkPresentModeKHR*>( pPresentModes ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  template <typename Allocator> \n  VULKAN_HPP_INLINE typename ResultValueType<std::vector<PresentModeKHR,Allocator>>::type PhysicalDevice::getSurfacePresentModesKHR( SurfaceKHR surface ) const\n  {\n    std::vector<PresentModeKHR,Allocator> presentModes;\n    uint32_t presentModeCount;\n    Result result;\n    do\n    {\n      result = static_cast<Result>( vkGetPhysicalDeviceSurfacePresentModesKHR( m_physicalDevice, static_cast<VkSurfaceKHR>( surface ), &presentModeCount, nullptr ) );\n      if ( ( result == Result::eSuccess ) && presentModeCount )\n      {\n        presentModes.resize( presentModeCount );\n        result = static_cast<Result>( vkGetPhysicalDeviceSurfacePresentModesKHR( m_physicalDevice, static_cast<VkSurfaceKHR>( surface ), &presentModeCount, reinterpret_cast<VkPresentModeKHR*>( presentModes.data() ) ) );\n      }\n    } while ( result == Result::eIncomplete );\n    assert( presentModeCount <= presentModes.size() ); \n    presentModes.resize( presentModeCount ); \n    return createResultValue( result, presentModes, \"vk::PhysicalDevice::getSurfacePresentModesKHR\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifdef VK_USE_PLATFORM_WAYLAND_KHR\n  VULKAN_HPP_INLINE Bool32 PhysicalDevice::getWaylandPresentationSupportKHR( uint32_t queueFamilyIndex, struct wl_display* display ) const\n  {\n    return vkGetPhysicalDeviceWaylandPresentationSupportKHR( m_physicalDevice, queueFamilyIndex, display );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE Bool32 PhysicalDevice::getWaylandPresentationSupportKHR( uint32_t queueFamilyIndex, struct wl_display & display ) const\n  {\n    return vkGetPhysicalDeviceWaylandPresentationSupportKHR( m_physicalDevice, queueFamilyIndex, &display );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n#endif /*VK_USE_PLATFORM_WAYLAND_KHR*/\n\n#ifdef VK_USE_PLATFORM_WIN32_KHR\n  VULKAN_HPP_INLINE Bool32 PhysicalDevice::getWin32PresentationSupportKHR( uint32_t queueFamilyIndex ) const\n  {\n    return vkGetPhysicalDeviceWin32PresentationSupportKHR( m_physicalDevice, queueFamilyIndex );\n  }\n#endif /*VK_USE_PLATFORM_WIN32_KHR*/\n\n#ifdef VK_USE_PLATFORM_XLIB_KHR\n  VULKAN_HPP_INLINE Bool32 PhysicalDevice::getXlibPresentationSupportKHR( uint32_t queueFamilyIndex, Display* dpy, VisualID visualID ) const\n  {\n    return vkGetPhysicalDeviceXlibPresentationSupportKHR( m_physicalDevice, queueFamilyIndex, dpy, visualID );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE Bool32 PhysicalDevice::getXlibPresentationSupportKHR( uint32_t queueFamilyIndex, Display & dpy, VisualID visualID ) const\n  {\n    return vkGetPhysicalDeviceXlibPresentationSupportKHR( m_physicalDevice, queueFamilyIndex, &dpy, visualID );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n#endif /*VK_USE_PLATFORM_XLIB_KHR*/\n\n#ifdef VK_USE_PLATFORM_XCB_KHR\n  VULKAN_HPP_INLINE Bool32 PhysicalDevice::getXcbPresentationSupportKHR( uint32_t queueFamilyIndex, xcb_connection_t* connection, xcb_visualid_t visual_id ) const\n  {\n    return vkGetPhysicalDeviceXcbPresentationSupportKHR( m_physicalDevice, queueFamilyIndex, connection, visual_id );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE Bool32 PhysicalDevice::getXcbPresentationSupportKHR( uint32_t queueFamilyIndex, xcb_connection_t & connection, xcb_visualid_t visual_id ) const\n  {\n    return vkGetPhysicalDeviceXcbPresentationSupportKHR( m_physicalDevice, queueFamilyIndex, &connection, visual_id );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n#endif /*VK_USE_PLATFORM_XCB_KHR*/\n\n  VULKAN_HPP_INLINE Result PhysicalDevice::getExternalImageFormatPropertiesNV( Format format, ImageType type, ImageTiling tiling, ImageUsageFlags usage, ImageCreateFlags flags, ExternalMemoryHandleTypeFlagsNV externalHandleType, ExternalImageFormatPropertiesNV* pExternalImageFormatProperties ) const\n  {\n    return static_cast<Result>( vkGetPhysicalDeviceExternalImageFormatPropertiesNV( m_physicalDevice, static_cast<VkFormat>( format ), static_cast<VkImageType>( type ), static_cast<VkImageTiling>( tiling ), static_cast<VkImageUsageFlags>( usage ), static_cast<VkImageCreateFlags>( flags ), static_cast<VkExternalMemoryHandleTypeFlagsNV>( externalHandleType ), reinterpret_cast<VkExternalImageFormatPropertiesNV*>( pExternalImageFormatProperties ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<ExternalImageFormatPropertiesNV>::type PhysicalDevice::getExternalImageFormatPropertiesNV( Format format, ImageType type, ImageTiling tiling, ImageUsageFlags usage, ImageCreateFlags flags, ExternalMemoryHandleTypeFlagsNV externalHandleType ) const\n  {\n    ExternalImageFormatPropertiesNV externalImageFormatProperties;\n    Result result = static_cast<Result>( vkGetPhysicalDeviceExternalImageFormatPropertiesNV( m_physicalDevice, static_cast<VkFormat>( format ), static_cast<VkImageType>( type ), static_cast<VkImageTiling>( tiling ), static_cast<VkImageUsageFlags>( usage ), static_cast<VkImageCreateFlags>( flags ), static_cast<VkExternalMemoryHandleTypeFlagsNV>( externalHandleType ), reinterpret_cast<VkExternalImageFormatPropertiesNV*>( &externalImageFormatProperties ) ) );\n    return createResultValue( result, externalImageFormatProperties, \"vk::PhysicalDevice::getExternalImageFormatPropertiesNV\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void PhysicalDevice::getGeneratedCommandsPropertiesNVX( DeviceGeneratedCommandsFeaturesNVX* pFeatures, DeviceGeneratedCommandsLimitsNVX* pLimits ) const\n  {\n    vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX( m_physicalDevice, reinterpret_cast<VkDeviceGeneratedCommandsFeaturesNVX*>( pFeatures ), reinterpret_cast<VkDeviceGeneratedCommandsLimitsNVX*>( pLimits ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE DeviceGeneratedCommandsLimitsNVX PhysicalDevice::getGeneratedCommandsPropertiesNVX( DeviceGeneratedCommandsFeaturesNVX & features ) const\n  {\n    DeviceGeneratedCommandsLimitsNVX limits;\n    vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX( m_physicalDevice, reinterpret_cast<VkDeviceGeneratedCommandsFeaturesNVX*>( &features ), reinterpret_cast<VkDeviceGeneratedCommandsLimitsNVX*>( &limits ) );\n    return limits;\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void PhysicalDevice::getFeatures2KHR( PhysicalDeviceFeatures2KHR* pFeatures ) const\n  {\n    vkGetPhysicalDeviceFeatures2KHR( m_physicalDevice, reinterpret_cast<VkPhysicalDeviceFeatures2KHR*>( pFeatures ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE PhysicalDeviceFeatures2KHR PhysicalDevice::getFeatures2KHR() const\n  {\n    PhysicalDeviceFeatures2KHR features;\n    vkGetPhysicalDeviceFeatures2KHR( m_physicalDevice, reinterpret_cast<VkPhysicalDeviceFeatures2KHR*>( &features ) );\n    return features;\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void PhysicalDevice::getProperties2KHR( PhysicalDeviceProperties2KHR* pProperties ) const\n  {\n    vkGetPhysicalDeviceProperties2KHR( m_physicalDevice, reinterpret_cast<VkPhysicalDeviceProperties2KHR*>( pProperties ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE PhysicalDeviceProperties2KHR PhysicalDevice::getProperties2KHR() const\n  {\n    PhysicalDeviceProperties2KHR properties;\n    vkGetPhysicalDeviceProperties2KHR( m_physicalDevice, reinterpret_cast<VkPhysicalDeviceProperties2KHR*>( &properties ) );\n    return properties;\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void PhysicalDevice::getFormatProperties2KHR( Format format, FormatProperties2KHR* pFormatProperties ) const\n  {\n    vkGetPhysicalDeviceFormatProperties2KHR( m_physicalDevice, static_cast<VkFormat>( format ), reinterpret_cast<VkFormatProperties2KHR*>( pFormatProperties ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE FormatProperties2KHR PhysicalDevice::getFormatProperties2KHR( Format format ) const\n  {\n    FormatProperties2KHR formatProperties;\n    vkGetPhysicalDeviceFormatProperties2KHR( m_physicalDevice, static_cast<VkFormat>( format ), reinterpret_cast<VkFormatProperties2KHR*>( &formatProperties ) );\n    return formatProperties;\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result PhysicalDevice::getImageFormatProperties2KHR( const PhysicalDeviceImageFormatInfo2KHR* pImageFormatInfo, ImageFormatProperties2KHR* pImageFormatProperties ) const\n  {\n    return static_cast<Result>( vkGetPhysicalDeviceImageFormatProperties2KHR( m_physicalDevice, reinterpret_cast<const VkPhysicalDeviceImageFormatInfo2KHR*>( pImageFormatInfo ), reinterpret_cast<VkImageFormatProperties2KHR*>( pImageFormatProperties ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<ImageFormatProperties2KHR>::type PhysicalDevice::getImageFormatProperties2KHR( const PhysicalDeviceImageFormatInfo2KHR & imageFormatInfo ) const\n  {\n    ImageFormatProperties2KHR imageFormatProperties;\n    Result result = static_cast<Result>( vkGetPhysicalDeviceImageFormatProperties2KHR( m_physicalDevice, reinterpret_cast<const VkPhysicalDeviceImageFormatInfo2KHR*>( &imageFormatInfo ), reinterpret_cast<VkImageFormatProperties2KHR*>( &imageFormatProperties ) ) );\n    return createResultValue( result, imageFormatProperties, \"vk::PhysicalDevice::getImageFormatProperties2KHR\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void PhysicalDevice::getQueueFamilyProperties2KHR( uint32_t* pQueueFamilyPropertyCount, QueueFamilyProperties2KHR* pQueueFamilyProperties ) const\n  {\n    vkGetPhysicalDeviceQueueFamilyProperties2KHR( m_physicalDevice, pQueueFamilyPropertyCount, reinterpret_cast<VkQueueFamilyProperties2KHR*>( pQueueFamilyProperties ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  template <typename Allocator> \n  VULKAN_HPP_INLINE std::vector<QueueFamilyProperties2KHR,Allocator> PhysicalDevice::getQueueFamilyProperties2KHR() const\n  {\n    std::vector<QueueFamilyProperties2KHR,Allocator> queueFamilyProperties;\n    uint32_t queueFamilyPropertyCount;\n    vkGetPhysicalDeviceQueueFamilyProperties2KHR( m_physicalDevice, &queueFamilyPropertyCount, nullptr );\n    queueFamilyProperties.resize( queueFamilyPropertyCount );\n    vkGetPhysicalDeviceQueueFamilyProperties2KHR( m_physicalDevice, &queueFamilyPropertyCount, reinterpret_cast<VkQueueFamilyProperties2KHR*>( queueFamilyProperties.data() ) );\n    return queueFamilyProperties;\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void PhysicalDevice::getMemoryProperties2KHR( PhysicalDeviceMemoryProperties2KHR* pMemoryProperties ) const\n  {\n    vkGetPhysicalDeviceMemoryProperties2KHR( m_physicalDevice, reinterpret_cast<VkPhysicalDeviceMemoryProperties2KHR*>( pMemoryProperties ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE PhysicalDeviceMemoryProperties2KHR PhysicalDevice::getMemoryProperties2KHR() const\n  {\n    PhysicalDeviceMemoryProperties2KHR memoryProperties;\n    vkGetPhysicalDeviceMemoryProperties2KHR( m_physicalDevice, reinterpret_cast<VkPhysicalDeviceMemoryProperties2KHR*>( &memoryProperties ) );\n    return memoryProperties;\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void PhysicalDevice::getSparseImageFormatProperties2KHR( const PhysicalDeviceSparseImageFormatInfo2KHR* pFormatInfo, uint32_t* pPropertyCount, SparseImageFormatProperties2KHR* pProperties ) const\n  {\n    vkGetPhysicalDeviceSparseImageFormatProperties2KHR( m_physicalDevice, reinterpret_cast<const VkPhysicalDeviceSparseImageFormatInfo2KHR*>( pFormatInfo ), pPropertyCount, reinterpret_cast<VkSparseImageFormatProperties2KHR*>( pProperties ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  template <typename Allocator> \n  VULKAN_HPP_INLINE std::vector<SparseImageFormatProperties2KHR,Allocator> PhysicalDevice::getSparseImageFormatProperties2KHR( const PhysicalDeviceSparseImageFormatInfo2KHR & formatInfo ) const\n  {\n    std::vector<SparseImageFormatProperties2KHR,Allocator> properties;\n    uint32_t propertyCount;\n    vkGetPhysicalDeviceSparseImageFormatProperties2KHR( m_physicalDevice, reinterpret_cast<const VkPhysicalDeviceSparseImageFormatInfo2KHR*>( &formatInfo ), &propertyCount, nullptr );\n    properties.resize( propertyCount );\n    vkGetPhysicalDeviceSparseImageFormatProperties2KHR( m_physicalDevice, reinterpret_cast<const VkPhysicalDeviceSparseImageFormatInfo2KHR*>( &formatInfo ), &propertyCount, reinterpret_cast<VkSparseImageFormatProperties2KHR*>( properties.data() ) );\n    return properties;\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void PhysicalDevice::getExternalBufferPropertiesKHX( const PhysicalDeviceExternalBufferInfoKHX* pExternalBufferInfo, ExternalBufferPropertiesKHX* pExternalBufferProperties ) const\n  {\n    vkGetPhysicalDeviceExternalBufferPropertiesKHX( m_physicalDevice, reinterpret_cast<const VkPhysicalDeviceExternalBufferInfoKHX*>( pExternalBufferInfo ), reinterpret_cast<VkExternalBufferPropertiesKHX*>( pExternalBufferProperties ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ExternalBufferPropertiesKHX PhysicalDevice::getExternalBufferPropertiesKHX( const PhysicalDeviceExternalBufferInfoKHX & externalBufferInfo ) const\n  {\n    ExternalBufferPropertiesKHX externalBufferProperties;\n    vkGetPhysicalDeviceExternalBufferPropertiesKHX( m_physicalDevice, reinterpret_cast<const VkPhysicalDeviceExternalBufferInfoKHX*>( &externalBufferInfo ), reinterpret_cast<VkExternalBufferPropertiesKHX*>( &externalBufferProperties ) );\n    return externalBufferProperties;\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void PhysicalDevice::getExternalSemaphorePropertiesKHX( const PhysicalDeviceExternalSemaphoreInfoKHX* pExternalSemaphoreInfo, ExternalSemaphorePropertiesKHX* pExternalSemaphoreProperties ) const\n  {\n    vkGetPhysicalDeviceExternalSemaphorePropertiesKHX( m_physicalDevice, reinterpret_cast<const VkPhysicalDeviceExternalSemaphoreInfoKHX*>( pExternalSemaphoreInfo ), reinterpret_cast<VkExternalSemaphorePropertiesKHX*>( pExternalSemaphoreProperties ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ExternalSemaphorePropertiesKHX PhysicalDevice::getExternalSemaphorePropertiesKHX( const PhysicalDeviceExternalSemaphoreInfoKHX & externalSemaphoreInfo ) const\n  {\n    ExternalSemaphorePropertiesKHX externalSemaphoreProperties;\n    vkGetPhysicalDeviceExternalSemaphorePropertiesKHX( m_physicalDevice, reinterpret_cast<const VkPhysicalDeviceExternalSemaphoreInfoKHX*>( &externalSemaphoreInfo ), reinterpret_cast<VkExternalSemaphorePropertiesKHX*>( &externalSemaphoreProperties ) );\n    return externalSemaphoreProperties;\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifdef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE Result PhysicalDevice::releaseDisplayEXT( DisplayKHR display ) const\n  {\n    return static_cast<Result>( vkReleaseDisplayEXT( m_physicalDevice, static_cast<VkDisplayKHR>( display ) ) );\n  }\n#else\n  VULKAN_HPP_INLINE ResultValueType<void>::type PhysicalDevice::releaseDisplayEXT( DisplayKHR display ) const\n  {\n    Result result = static_cast<Result>( vkReleaseDisplayEXT( m_physicalDevice, static_cast<VkDisplayKHR>( display ) ) );\n    return createResultValue( result, \"vk::PhysicalDevice::releaseDisplayEXT\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT\n  VULKAN_HPP_INLINE Result PhysicalDevice::acquireXlibDisplayEXT( Display* dpy, DisplayKHR display ) const\n  {\n    return static_cast<Result>( vkAcquireXlibDisplayEXT( m_physicalDevice, dpy, static_cast<VkDisplayKHR>( display ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<Display>::type PhysicalDevice::acquireXlibDisplayEXT( DisplayKHR display ) const\n  {\n    Display dpy;\n    Result result = static_cast<Result>( vkAcquireXlibDisplayEXT( m_physicalDevice, &dpy, static_cast<VkDisplayKHR>( display ) ) );\n    return createResultValue( result, dpy, \"vk::PhysicalDevice::acquireXlibDisplayEXT\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n#endif /*VK_USE_PLATFORM_XLIB_XRANDR_EXT*/\n\n#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT\n  VULKAN_HPP_INLINE Result PhysicalDevice::getRandROutputDisplayEXT( Display* dpy, RROutput rrOutput, DisplayKHR* pDisplay ) const\n  {\n    return static_cast<Result>( vkGetRandROutputDisplayEXT( m_physicalDevice, dpy, rrOutput, reinterpret_cast<VkDisplayKHR*>( pDisplay ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<DisplayKHR>::type PhysicalDevice::getRandROutputDisplayEXT( Display & dpy, RROutput rrOutput ) const\n  {\n    DisplayKHR display;\n    Result result = static_cast<Result>( vkGetRandROutputDisplayEXT( m_physicalDevice, &dpy, rrOutput, reinterpret_cast<VkDisplayKHR*>( &display ) ) );\n    return createResultValue( result, display, \"vk::PhysicalDevice::getRandROutputDisplayEXT\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n#endif /*VK_USE_PLATFORM_XLIB_XRANDR_EXT*/\n\n  VULKAN_HPP_INLINE Result PhysicalDevice::getSurfaceCapabilities2EXT( SurfaceKHR surface, SurfaceCapabilities2EXT* pSurfaceCapabilities ) const\n  {\n    return static_cast<Result>( vkGetPhysicalDeviceSurfaceCapabilities2EXT( m_physicalDevice, static_cast<VkSurfaceKHR>( surface ), reinterpret_cast<VkSurfaceCapabilities2EXT*>( pSurfaceCapabilities ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<SurfaceCapabilities2EXT>::type PhysicalDevice::getSurfaceCapabilities2EXT( SurfaceKHR surface ) const\n  {\n    SurfaceCapabilities2EXT surfaceCapabilities;\n    Result result = static_cast<Result>( vkGetPhysicalDeviceSurfaceCapabilities2EXT( m_physicalDevice, static_cast<VkSurfaceKHR>( surface ), reinterpret_cast<VkSurfaceCapabilities2EXT*>( &surfaceCapabilities ) ) );\n    return createResultValue( result, surfaceCapabilities, \"vk::PhysicalDevice::getSurfaceCapabilities2EXT\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result PhysicalDevice::getPresentRectanglesKHX( SurfaceKHR surface, uint32_t* pRectCount, Rect2D* pRects ) const\n  {\n    return static_cast<Result>( vkGetPhysicalDevicePresentRectanglesKHX( m_physicalDevice, static_cast<VkSurfaceKHR>( surface ), pRectCount, reinterpret_cast<VkRect2D*>( pRects ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  template <typename Allocator> \n  VULKAN_HPP_INLINE typename ResultValueType<std::vector<Rect2D,Allocator>>::type PhysicalDevice::getPresentRectanglesKHX( SurfaceKHR surface ) const\n  {\n    std::vector<Rect2D,Allocator> rects;\n    uint32_t rectCount;\n    Result result;\n    do\n    {\n      result = static_cast<Result>( vkGetPhysicalDevicePresentRectanglesKHX( m_physicalDevice, static_cast<VkSurfaceKHR>( surface ), &rectCount, nullptr ) );\n      if ( ( result == Result::eSuccess ) && rectCount )\n      {\n        rects.resize( rectCount );\n        result = static_cast<Result>( vkGetPhysicalDevicePresentRectanglesKHX( m_physicalDevice, static_cast<VkSurfaceKHR>( surface ), &rectCount, reinterpret_cast<VkRect2D*>( rects.data() ) ) );\n      }\n    } while ( result == Result::eIncomplete );\n    assert( rectCount <= rects.size() ); \n    rects.resize( rectCount ); \n    return createResultValue( result, rects, \"vk::PhysicalDevice::getPresentRectanglesKHX\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result PhysicalDevice::getSurfaceCapabilities2KHR( const PhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, SurfaceCapabilities2KHR* pSurfaceCapabilities ) const\n  {\n    return static_cast<Result>( vkGetPhysicalDeviceSurfaceCapabilities2KHR( m_physicalDevice, reinterpret_cast<const VkPhysicalDeviceSurfaceInfo2KHR*>( pSurfaceInfo ), reinterpret_cast<VkSurfaceCapabilities2KHR*>( pSurfaceCapabilities ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n#if 0   // LunarG 1.0.48 header update workaround\n  VULKAN_HPP_INLINE Result PhysicalDevice::getSurfaceCapabilities2KHR( const PhysicalDeviceSurfaceInfo2KHR & surfaceInfo ) const\n  {\n    Result result = static_cast<Result>( vkGetPhysicalDeviceSurfaceCapabilities2KHR( m_physicalDevice, reinterpret_cast<const VkPhysicalDeviceSurfaceInfo2KHR*>( &surfaceInfo ), reinterpret_cast<VkSurfaceCapabilities2KHR*>( &surfaceCapabilities ) ) );\n    return createResultValue( result, surfaceCapabilities, \"vk::PhysicalDevice::getSurfaceCapabilities2KHR\" );\n  }\n#endif\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result PhysicalDevice::getSurfaceFormats2KHR( const PhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, uint32_t* pSurfaceFormatCount, SurfaceFormat2KHR* pSurfaceFormats ) const\n  {\n    return static_cast<Result>( vkGetPhysicalDeviceSurfaceFormats2KHR( m_physicalDevice, reinterpret_cast<const VkPhysicalDeviceSurfaceInfo2KHR*>( pSurfaceInfo ), pSurfaceFormatCount, reinterpret_cast<VkSurfaceFormat2KHR*>( pSurfaceFormats ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  template <typename Allocator> \n  VULKAN_HPP_INLINE typename ResultValueType<std::vector<SurfaceFormat2KHR,Allocator>>::type PhysicalDevice::getSurfaceFormats2KHR( const PhysicalDeviceSurfaceInfo2KHR & surfaceInfo ) const\n  {\n    std::vector<SurfaceFormat2KHR,Allocator> surfaceFormats;\n    uint32_t surfaceFormatCount;\n    Result result;\n    do\n    {\n      result = static_cast<Result>( vkGetPhysicalDeviceSurfaceFormats2KHR( m_physicalDevice, reinterpret_cast<const VkPhysicalDeviceSurfaceInfo2KHR*>( &surfaceInfo ), &surfaceFormatCount, nullptr ) );\n      if ( ( result == Result::eSuccess ) && surfaceFormatCount )\n      {\n        surfaceFormats.resize( surfaceFormatCount );\n        result = static_cast<Result>( vkGetPhysicalDeviceSurfaceFormats2KHR( m_physicalDevice, reinterpret_cast<const VkPhysicalDeviceSurfaceInfo2KHR*>( &surfaceInfo ), &surfaceFormatCount, reinterpret_cast<VkSurfaceFormat2KHR*>( surfaceFormats.data() ) ) );\n      }\n    } while ( result == Result::eIncomplete );\n    assert( surfaceFormatCount <= surfaceFormats.size() ); \n    surfaceFormats.resize( surfaceFormatCount ); \n    return createResultValue( result, surfaceFormats, \"vk::PhysicalDevice::getSurfaceFormats2KHR\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  struct CmdProcessCommandsInfoNVX\n  {\n    CmdProcessCommandsInfoNVX( ObjectTableNVX objectTable_ = ObjectTableNVX(), IndirectCommandsLayoutNVX indirectCommandsLayout_ = IndirectCommandsLayoutNVX(), uint32_t indirectCommandsTokenCount_ = 0, const IndirectCommandsTokenNVX* pIndirectCommandsTokens_ = nullptr, uint32_t maxSequencesCount_ = 0, CommandBuffer targetCommandBuffer_ = CommandBuffer(), Buffer sequencesCountBuffer_ = Buffer(), DeviceSize sequencesCountOffset_ = 0, Buffer sequencesIndexBuffer_ = Buffer(), DeviceSize sequencesIndexOffset_ = 0 )\n      : sType( StructureType::eCmdProcessCommandsInfoNVX )\n      , pNext( nullptr )\n      , objectTable( objectTable_ )\n      , indirectCommandsLayout( indirectCommandsLayout_ )\n      , indirectCommandsTokenCount( indirectCommandsTokenCount_ )\n      , pIndirectCommandsTokens( pIndirectCommandsTokens_ )\n      , maxSequencesCount( maxSequencesCount_ )\n      , targetCommandBuffer( targetCommandBuffer_ )\n      , sequencesCountBuffer( sequencesCountBuffer_ )\n      , sequencesCountOffset( sequencesCountOffset_ )\n      , sequencesIndexBuffer( sequencesIndexBuffer_ )\n      , sequencesIndexOffset( sequencesIndexOffset_ )\n    {\n    }\n\n    CmdProcessCommandsInfoNVX( VkCmdProcessCommandsInfoNVX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(CmdProcessCommandsInfoNVX) );\n    }\n\n    CmdProcessCommandsInfoNVX& operator=( VkCmdProcessCommandsInfoNVX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(CmdProcessCommandsInfoNVX) );\n      return *this;\n    }\n\n    CmdProcessCommandsInfoNVX& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    CmdProcessCommandsInfoNVX& setObjectTable( ObjectTableNVX objectTable_ )\n    {\n      objectTable = objectTable_;\n      return *this;\n    }\n\n    CmdProcessCommandsInfoNVX& setIndirectCommandsLayout( IndirectCommandsLayoutNVX indirectCommandsLayout_ )\n    {\n      indirectCommandsLayout = indirectCommandsLayout_;\n      return *this;\n    }\n\n    CmdProcessCommandsInfoNVX& setIndirectCommandsTokenCount( uint32_t indirectCommandsTokenCount_ )\n    {\n      indirectCommandsTokenCount = indirectCommandsTokenCount_;\n      return *this;\n    }\n\n    CmdProcessCommandsInfoNVX& setPIndirectCommandsTokens( const IndirectCommandsTokenNVX* pIndirectCommandsTokens_ )\n    {\n      pIndirectCommandsTokens = pIndirectCommandsTokens_;\n      return *this;\n    }\n\n    CmdProcessCommandsInfoNVX& setMaxSequencesCount( uint32_t maxSequencesCount_ )\n    {\n      maxSequencesCount = maxSequencesCount_;\n      return *this;\n    }\n\n    CmdProcessCommandsInfoNVX& setTargetCommandBuffer( CommandBuffer targetCommandBuffer_ )\n    {\n      targetCommandBuffer = targetCommandBuffer_;\n      return *this;\n    }\n\n    CmdProcessCommandsInfoNVX& setSequencesCountBuffer( Buffer sequencesCountBuffer_ )\n    {\n      sequencesCountBuffer = sequencesCountBuffer_;\n      return *this;\n    }\n\n    CmdProcessCommandsInfoNVX& setSequencesCountOffset( DeviceSize sequencesCountOffset_ )\n    {\n      sequencesCountOffset = sequencesCountOffset_;\n      return *this;\n    }\n\n    CmdProcessCommandsInfoNVX& setSequencesIndexBuffer( Buffer sequencesIndexBuffer_ )\n    {\n      sequencesIndexBuffer = sequencesIndexBuffer_;\n      return *this;\n    }\n\n    CmdProcessCommandsInfoNVX& setSequencesIndexOffset( DeviceSize sequencesIndexOffset_ )\n    {\n      sequencesIndexOffset = sequencesIndexOffset_;\n      return *this;\n    }\n\n    operator const VkCmdProcessCommandsInfoNVX&() const\n    {\n      return *reinterpret_cast<const VkCmdProcessCommandsInfoNVX*>(this);\n    }\n\n    bool operator==( CmdProcessCommandsInfoNVX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( objectTable == rhs.objectTable )\n          && ( indirectCommandsLayout == rhs.indirectCommandsLayout )\n          && ( indirectCommandsTokenCount == rhs.indirectCommandsTokenCount )\n          && ( pIndirectCommandsTokens == rhs.pIndirectCommandsTokens )\n          && ( maxSequencesCount == rhs.maxSequencesCount )\n          && ( targetCommandBuffer == rhs.targetCommandBuffer )\n          && ( sequencesCountBuffer == rhs.sequencesCountBuffer )\n          && ( sequencesCountOffset == rhs.sequencesCountOffset )\n          && ( sequencesIndexBuffer == rhs.sequencesIndexBuffer )\n          && ( sequencesIndexOffset == rhs.sequencesIndexOffset );\n    }\n\n    bool operator!=( CmdProcessCommandsInfoNVX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    ObjectTableNVX objectTable;\n    IndirectCommandsLayoutNVX indirectCommandsLayout;\n    uint32_t indirectCommandsTokenCount;\n    const IndirectCommandsTokenNVX* pIndirectCommandsTokens;\n    uint32_t maxSequencesCount;\n    CommandBuffer targetCommandBuffer;\n    Buffer sequencesCountBuffer;\n    DeviceSize sequencesCountOffset;\n    Buffer sequencesIndexBuffer;\n    DeviceSize sequencesIndexOffset;\n  };\n  static_assert( sizeof( CmdProcessCommandsInfoNVX ) == sizeof( VkCmdProcessCommandsInfoNVX ), \"struct and wrapper have different size!\" );\n\n  struct PhysicalDeviceGroupPropertiesKHX\n  {\n    operator const VkPhysicalDeviceGroupPropertiesKHX&() const\n    {\n      return *reinterpret_cast<const VkPhysicalDeviceGroupPropertiesKHX*>(this);\n    }\n\n    bool operator==( PhysicalDeviceGroupPropertiesKHX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( physicalDeviceCount == rhs.physicalDeviceCount )\n          && ( memcmp( physicalDevices, rhs.physicalDevices, VK_MAX_DEVICE_GROUP_SIZE_KHX * sizeof( PhysicalDevice ) ) == 0 )\n          && ( subsetAllocation == rhs.subsetAllocation );\n    }\n\n    bool operator!=( PhysicalDeviceGroupPropertiesKHX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    void* pNext;\n    uint32_t physicalDeviceCount;\n    PhysicalDevice physicalDevices[VK_MAX_DEVICE_GROUP_SIZE_KHX];\n    Bool32 subsetAllocation;\n  };\n  static_assert( sizeof( PhysicalDeviceGroupPropertiesKHX ) == sizeof( VkPhysicalDeviceGroupPropertiesKHX ), \"struct and wrapper have different size!\" );\n\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  class DebugReportCallbackEXTDeleter;\n  using UniqueDebugReportCallbackEXT = UniqueHandle<DebugReportCallbackEXT, DebugReportCallbackEXTDeleter>;\n  class SurfaceKHRDeleter;\n  using UniqueSurfaceKHR = UniqueHandle<SurfaceKHR, SurfaceKHRDeleter>;\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n\n  class Instance\n  {\n  public:\n    Instance()\n      : m_instance(VK_NULL_HANDLE)\n    {}\n\n    Instance( std::nullptr_t )\n      : m_instance(VK_NULL_HANDLE)\n    {}\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT Instance(VkInstance instance)\n       : m_instance(instance)\n    {}\n\n#if defined(VULKAN_HPP_TYPESAFE_CONVERSION)\n    Instance& operator=(VkInstance instance)\n    {\n      m_instance = instance;\n      return *this;\n    }\n#endif\n\n    Instance& operator=( std::nullptr_t )\n    {\n      m_instance = VK_NULL_HANDLE;\n      return *this;\n    }\n\n    bool operator==(Instance const &rhs) const\n    {\n      return m_instance == rhs.m_instance;\n    }\n\n    bool operator!=(Instance const &rhs) const\n    {\n      return m_instance != rhs.m_instance;\n    }\n\n    bool operator<(Instance const &rhs) const\n    {\n      return m_instance < rhs.m_instance;\n    }\n\n    void destroy( const AllocationCallbacks* pAllocator ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void destroy( Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result enumeratePhysicalDevices( uint32_t* pPhysicalDeviceCount, PhysicalDevice* pPhysicalDevices ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    template <typename Allocator = std::allocator<PhysicalDevice>> \n    typename ResultValueType<std::vector<PhysicalDevice,Allocator>>::type enumeratePhysicalDevices() const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    PFN_vkVoidFunction getProcAddr( const char* pName ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    PFN_vkVoidFunction getProcAddr( const std::string & name ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifdef VK_USE_PLATFORM_ANDROID_KHR\n    Result createAndroidSurfaceKHR( const AndroidSurfaceCreateInfoKHR* pCreateInfo, const AllocationCallbacks* pAllocator, SurfaceKHR* pSurface ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<SurfaceKHR>::type createAndroidSurfaceKHR( const AndroidSurfaceCreateInfoKHR & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n    UniqueSurfaceKHR createAndroidSurfaceKHRUnique( const AndroidSurfaceCreateInfoKHR & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n#endif /*VK_USE_PLATFORM_ANDROID_KHR*/\n\n    Result createDisplayPlaneSurfaceKHR( const DisplaySurfaceCreateInfoKHR* pCreateInfo, const AllocationCallbacks* pAllocator, SurfaceKHR* pSurface ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<SurfaceKHR>::type createDisplayPlaneSurfaceKHR( const DisplaySurfaceCreateInfoKHR & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n    UniqueSurfaceKHR createDisplayPlaneSurfaceKHRUnique( const DisplaySurfaceCreateInfoKHR & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifdef VK_USE_PLATFORM_MIR_KHR\n    Result createMirSurfaceKHR( const MirSurfaceCreateInfoKHR* pCreateInfo, const AllocationCallbacks* pAllocator, SurfaceKHR* pSurface ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<SurfaceKHR>::type createMirSurfaceKHR( const MirSurfaceCreateInfoKHR & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n    UniqueSurfaceKHR createMirSurfaceKHRUnique( const MirSurfaceCreateInfoKHR & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n#endif /*VK_USE_PLATFORM_MIR_KHR*/\n\n    void destroySurfaceKHR( SurfaceKHR surface, const AllocationCallbacks* pAllocator ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void destroySurfaceKHR( SurfaceKHR surface, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifdef VK_USE_PLATFORM_VI_NN\n    Result createViSurfaceNN( const ViSurfaceCreateInfoNN* pCreateInfo, const AllocationCallbacks* pAllocator, SurfaceKHR* pSurface ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<SurfaceKHR>::type createViSurfaceNN( const ViSurfaceCreateInfoNN & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n    UniqueSurfaceKHR createViSurfaceNNUnique( const ViSurfaceCreateInfoNN & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n#endif /*VK_USE_PLATFORM_VI_NN*/\n\n#ifdef VK_USE_PLATFORM_WAYLAND_KHR\n    Result createWaylandSurfaceKHR( const WaylandSurfaceCreateInfoKHR* pCreateInfo, const AllocationCallbacks* pAllocator, SurfaceKHR* pSurface ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<SurfaceKHR>::type createWaylandSurfaceKHR( const WaylandSurfaceCreateInfoKHR & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n    UniqueSurfaceKHR createWaylandSurfaceKHRUnique( const WaylandSurfaceCreateInfoKHR & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n#endif /*VK_USE_PLATFORM_WAYLAND_KHR*/\n\n#ifdef VK_USE_PLATFORM_WIN32_KHR\n    Result createWin32SurfaceKHR( const Win32SurfaceCreateInfoKHR* pCreateInfo, const AllocationCallbacks* pAllocator, SurfaceKHR* pSurface ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<SurfaceKHR>::type createWin32SurfaceKHR( const Win32SurfaceCreateInfoKHR & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n    UniqueSurfaceKHR createWin32SurfaceKHRUnique( const Win32SurfaceCreateInfoKHR & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n#endif /*VK_USE_PLATFORM_WIN32_KHR*/\n\n#ifdef VK_USE_PLATFORM_XLIB_KHR\n    Result createXlibSurfaceKHR( const XlibSurfaceCreateInfoKHR* pCreateInfo, const AllocationCallbacks* pAllocator, SurfaceKHR* pSurface ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<SurfaceKHR>::type createXlibSurfaceKHR( const XlibSurfaceCreateInfoKHR & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n    UniqueSurfaceKHR createXlibSurfaceKHRUnique( const XlibSurfaceCreateInfoKHR & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n#endif /*VK_USE_PLATFORM_XLIB_KHR*/\n\n#ifdef VK_USE_PLATFORM_XCB_KHR\n    Result createXcbSurfaceKHR( const XcbSurfaceCreateInfoKHR* pCreateInfo, const AllocationCallbacks* pAllocator, SurfaceKHR* pSurface ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<SurfaceKHR>::type createXcbSurfaceKHR( const XcbSurfaceCreateInfoKHR & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n    UniqueSurfaceKHR createXcbSurfaceKHRUnique( const XcbSurfaceCreateInfoKHR & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n#endif /*VK_USE_PLATFORM_XCB_KHR*/\n\n    Result createDebugReportCallbackEXT( const DebugReportCallbackCreateInfoEXT* pCreateInfo, const AllocationCallbacks* pAllocator, DebugReportCallbackEXT* pCallback ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<DebugReportCallbackEXT>::type createDebugReportCallbackEXT( const DebugReportCallbackCreateInfoEXT & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n    UniqueDebugReportCallbackEXT createDebugReportCallbackEXTUnique( const DebugReportCallbackCreateInfoEXT & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void destroyDebugReportCallbackEXT( DebugReportCallbackEXT callback, const AllocationCallbacks* pAllocator ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void destroyDebugReportCallbackEXT( DebugReportCallbackEXT callback, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    void debugReportMessageEXT( DebugReportFlagsEXT flags, DebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    void debugReportMessageEXT( DebugReportFlagsEXT flags, DebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const std::string & layerPrefix, const std::string & message ) const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n    Result enumeratePhysicalDeviceGroupsKHX( uint32_t* pPhysicalDeviceGroupCount, PhysicalDeviceGroupPropertiesKHX* pPhysicalDeviceGroupProperties ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    template <typename Allocator = std::allocator<PhysicalDeviceGroupPropertiesKHX>> \n    typename ResultValueType<std::vector<PhysicalDeviceGroupPropertiesKHX,Allocator>>::type enumeratePhysicalDeviceGroupsKHX() const;\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifdef VK_USE_PLATFORM_IOS_MVK\n    Result createIOSSurfaceMVK( const IOSSurfaceCreateInfoMVK* pCreateInfo, const AllocationCallbacks* pAllocator, SurfaceKHR* pSurface ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<SurfaceKHR>::type createIOSSurfaceMVK( const IOSSurfaceCreateInfoMVK & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n    UniqueSurfaceKHR createIOSSurfaceMVKUnique( const IOSSurfaceCreateInfoMVK & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n#endif /*VK_USE_PLATFORM_IOS_MVK*/\n\n#ifdef VK_USE_PLATFORM_MACOS_MVK\n    Result createMacOSSurfaceMVK( const MacOSSurfaceCreateInfoMVK* pCreateInfo, const AllocationCallbacks* pAllocator, SurfaceKHR* pSurface ) const;\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<SurfaceKHR>::type createMacOSSurfaceMVK( const MacOSSurfaceCreateInfoMVK & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n    UniqueSurfaceKHR createMacOSSurfaceMVKUnique( const MacOSSurfaceCreateInfoMVK & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const;\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n#endif /*VK_USE_PLATFORM_MACOS_MVK*/\n\n    VULKAN_HPP_TYPESAFE_EXPLICIT operator VkInstance() const\n    {\n      return m_instance;\n    }\n\n    explicit operator bool() const\n    {\n      return m_instance != VK_NULL_HANDLE;\n    }\n\n    bool operator!() const\n    {\n      return m_instance == VK_NULL_HANDLE;\n    }\n\n  private:\n    VkInstance m_instance;\n  };\n  static_assert( sizeof( Instance ) == sizeof( VkInstance ), \"handle and wrapper have different size!\" );\n\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  class DebugReportCallbackEXTDeleter\n  {\n  public:\n    DebugReportCallbackEXTDeleter( Instance instance = Instance(), Optional<const AllocationCallbacks> allocator = nullptr )\n      : m_instance( instance )\n      , m_allocator( allocator )\n    {}\n\n    void operator()( DebugReportCallbackEXT debugReportCallbackEXT )\n    {\n      m_instance.destroyDebugReportCallbackEXT( debugReportCallbackEXT, m_allocator );\n    }\n\n  private:\n    Instance m_instance;\n    Optional<const AllocationCallbacks> m_allocator;\n  };\n\n  class SurfaceKHRDeleter\n  {\n  public:\n    SurfaceKHRDeleter( Instance instance = Instance(), Optional<const AllocationCallbacks> allocator = nullptr )\n      : m_instance( instance )\n      , m_allocator( allocator )\n    {}\n\n    void operator()( SurfaceKHR surfaceKHR )\n    {\n      m_instance.destroySurfaceKHR( surfaceKHR, m_allocator );\n    }\n\n  private:\n    Instance m_instance;\n    Optional<const AllocationCallbacks> m_allocator;\n  };\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n\n  VULKAN_HPP_INLINE void Instance::destroy( const AllocationCallbacks* pAllocator ) const\n  {\n    vkDestroyInstance( m_instance, reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void Instance::destroy( Optional<const AllocationCallbacks> allocator ) const\n  {\n    vkDestroyInstance( m_instance, reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Instance::enumeratePhysicalDevices( uint32_t* pPhysicalDeviceCount, PhysicalDevice* pPhysicalDevices ) const\n  {\n    return static_cast<Result>( vkEnumeratePhysicalDevices( m_instance, pPhysicalDeviceCount, reinterpret_cast<VkPhysicalDevice*>( pPhysicalDevices ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  template <typename Allocator> \n  VULKAN_HPP_INLINE typename ResultValueType<std::vector<PhysicalDevice,Allocator>>::type Instance::enumeratePhysicalDevices() const\n  {\n    std::vector<PhysicalDevice,Allocator> physicalDevices;\n    uint32_t physicalDeviceCount;\n    Result result;\n    do\n    {\n      result = static_cast<Result>( vkEnumeratePhysicalDevices( m_instance, &physicalDeviceCount, nullptr ) );\n      if ( ( result == Result::eSuccess ) && physicalDeviceCount )\n      {\n        physicalDevices.resize( physicalDeviceCount );\n        result = static_cast<Result>( vkEnumeratePhysicalDevices( m_instance, &physicalDeviceCount, reinterpret_cast<VkPhysicalDevice*>( physicalDevices.data() ) ) );\n      }\n    } while ( result == Result::eIncomplete );\n    assert( physicalDeviceCount <= physicalDevices.size() ); \n    physicalDevices.resize( physicalDeviceCount ); \n    return createResultValue( result, physicalDevices, \"vk::Instance::enumeratePhysicalDevices\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE PFN_vkVoidFunction Instance::getProcAddr( const char* pName ) const\n  {\n    return vkGetInstanceProcAddr( m_instance, pName );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE PFN_vkVoidFunction Instance::getProcAddr( const std::string & name ) const\n  {\n    return vkGetInstanceProcAddr( m_instance, name.c_str() );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifdef VK_USE_PLATFORM_ANDROID_KHR\n  VULKAN_HPP_INLINE Result Instance::createAndroidSurfaceKHR( const AndroidSurfaceCreateInfoKHR* pCreateInfo, const AllocationCallbacks* pAllocator, SurfaceKHR* pSurface ) const\n  {\n    return static_cast<Result>( vkCreateAndroidSurfaceKHR( m_instance, reinterpret_cast<const VkAndroidSurfaceCreateInfoKHR*>( pCreateInfo ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ), reinterpret_cast<VkSurfaceKHR*>( pSurface ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<SurfaceKHR>::type Instance::createAndroidSurfaceKHR( const AndroidSurfaceCreateInfoKHR & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    SurfaceKHR surface;\n    Result result = static_cast<Result>( vkCreateAndroidSurfaceKHR( m_instance, reinterpret_cast<const VkAndroidSurfaceCreateInfoKHR*>( &createInfo ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkSurfaceKHR*>( &surface ) ) );\n    return createResultValue( result, surface, \"vk::Instance::createAndroidSurfaceKHR\" );\n  }\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  VULKAN_HPP_INLINE UniqueSurfaceKHR Instance::createAndroidSurfaceKHRUnique( const AndroidSurfaceCreateInfoKHR & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    SurfaceKHRDeleter deleter( *this, allocator );\n    return UniqueSurfaceKHR( createAndroidSurfaceKHR( createInfo, allocator ), deleter );\n  }\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n#endif /*VK_USE_PLATFORM_ANDROID_KHR*/\n\n  VULKAN_HPP_INLINE Result Instance::createDisplayPlaneSurfaceKHR( const DisplaySurfaceCreateInfoKHR* pCreateInfo, const AllocationCallbacks* pAllocator, SurfaceKHR* pSurface ) const\n  {\n    return static_cast<Result>( vkCreateDisplayPlaneSurfaceKHR( m_instance, reinterpret_cast<const VkDisplaySurfaceCreateInfoKHR*>( pCreateInfo ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ), reinterpret_cast<VkSurfaceKHR*>( pSurface ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<SurfaceKHR>::type Instance::createDisplayPlaneSurfaceKHR( const DisplaySurfaceCreateInfoKHR & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    SurfaceKHR surface;\n    Result result = static_cast<Result>( vkCreateDisplayPlaneSurfaceKHR( m_instance, reinterpret_cast<const VkDisplaySurfaceCreateInfoKHR*>( &createInfo ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkSurfaceKHR*>( &surface ) ) );\n    return createResultValue( result, surface, \"vk::Instance::createDisplayPlaneSurfaceKHR\" );\n  }\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  VULKAN_HPP_INLINE UniqueSurfaceKHR Instance::createDisplayPlaneSurfaceKHRUnique( const DisplaySurfaceCreateInfoKHR & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    SurfaceKHRDeleter deleter( *this, allocator );\n    return UniqueSurfaceKHR( createDisplayPlaneSurfaceKHR( createInfo, allocator ), deleter );\n  }\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifdef VK_USE_PLATFORM_MIR_KHR\n  VULKAN_HPP_INLINE Result Instance::createMirSurfaceKHR( const MirSurfaceCreateInfoKHR* pCreateInfo, const AllocationCallbacks* pAllocator, SurfaceKHR* pSurface ) const\n  {\n    return static_cast<Result>( vkCreateMirSurfaceKHR( m_instance, reinterpret_cast<const VkMirSurfaceCreateInfoKHR*>( pCreateInfo ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ), reinterpret_cast<VkSurfaceKHR*>( pSurface ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<SurfaceKHR>::type Instance::createMirSurfaceKHR( const MirSurfaceCreateInfoKHR & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    SurfaceKHR surface;\n    Result result = static_cast<Result>( vkCreateMirSurfaceKHR( m_instance, reinterpret_cast<const VkMirSurfaceCreateInfoKHR*>( &createInfo ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkSurfaceKHR*>( &surface ) ) );\n    return createResultValue( result, surface, \"vk::Instance::createMirSurfaceKHR\" );\n  }\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  VULKAN_HPP_INLINE UniqueSurfaceKHR Instance::createMirSurfaceKHRUnique( const MirSurfaceCreateInfoKHR & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    SurfaceKHRDeleter deleter( *this, allocator );\n    return UniqueSurfaceKHR( createMirSurfaceKHR( createInfo, allocator ), deleter );\n  }\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n#endif /*VK_USE_PLATFORM_MIR_KHR*/\n\n  VULKAN_HPP_INLINE void Instance::destroySurfaceKHR( SurfaceKHR surface, const AllocationCallbacks* pAllocator ) const\n  {\n    vkDestroySurfaceKHR( m_instance, static_cast<VkSurfaceKHR>( surface ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void Instance::destroySurfaceKHR( SurfaceKHR surface, Optional<const AllocationCallbacks> allocator ) const\n  {\n    vkDestroySurfaceKHR( m_instance, static_cast<VkSurfaceKHR>( surface ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifdef VK_USE_PLATFORM_VI_NN\n  VULKAN_HPP_INLINE Result Instance::createViSurfaceNN( const ViSurfaceCreateInfoNN* pCreateInfo, const AllocationCallbacks* pAllocator, SurfaceKHR* pSurface ) const\n  {\n    return static_cast<Result>( vkCreateViSurfaceNN( m_instance, reinterpret_cast<const VkViSurfaceCreateInfoNN*>( pCreateInfo ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ), reinterpret_cast<VkSurfaceKHR*>( pSurface ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<SurfaceKHR>::type Instance::createViSurfaceNN( const ViSurfaceCreateInfoNN & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    SurfaceKHR surface;\n    Result result = static_cast<Result>( vkCreateViSurfaceNN( m_instance, reinterpret_cast<const VkViSurfaceCreateInfoNN*>( &createInfo ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkSurfaceKHR*>( &surface ) ) );\n    return createResultValue( result, surface, \"vk::Instance::createViSurfaceNN\" );\n  }\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  VULKAN_HPP_INLINE UniqueSurfaceKHR Instance::createViSurfaceNNUnique( const ViSurfaceCreateInfoNN & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    SurfaceKHRDeleter deleter( *this, allocator );\n    return UniqueSurfaceKHR( createViSurfaceNN( createInfo, allocator ), deleter );\n  }\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n#endif /*VK_USE_PLATFORM_VI_NN*/\n\n#ifdef VK_USE_PLATFORM_WAYLAND_KHR\n  VULKAN_HPP_INLINE Result Instance::createWaylandSurfaceKHR( const WaylandSurfaceCreateInfoKHR* pCreateInfo, const AllocationCallbacks* pAllocator, SurfaceKHR* pSurface ) const\n  {\n    return static_cast<Result>( vkCreateWaylandSurfaceKHR( m_instance, reinterpret_cast<const VkWaylandSurfaceCreateInfoKHR*>( pCreateInfo ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ), reinterpret_cast<VkSurfaceKHR*>( pSurface ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<SurfaceKHR>::type Instance::createWaylandSurfaceKHR( const WaylandSurfaceCreateInfoKHR & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    SurfaceKHR surface;\n    Result result = static_cast<Result>( vkCreateWaylandSurfaceKHR( m_instance, reinterpret_cast<const VkWaylandSurfaceCreateInfoKHR*>( &createInfo ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkSurfaceKHR*>( &surface ) ) );\n    return createResultValue( result, surface, \"vk::Instance::createWaylandSurfaceKHR\" );\n  }\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  VULKAN_HPP_INLINE UniqueSurfaceKHR Instance::createWaylandSurfaceKHRUnique( const WaylandSurfaceCreateInfoKHR & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    SurfaceKHRDeleter deleter( *this, allocator );\n    return UniqueSurfaceKHR( createWaylandSurfaceKHR( createInfo, allocator ), deleter );\n  }\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n#endif /*VK_USE_PLATFORM_WAYLAND_KHR*/\n\n#ifdef VK_USE_PLATFORM_WIN32_KHR\n  VULKAN_HPP_INLINE Result Instance::createWin32SurfaceKHR( const Win32SurfaceCreateInfoKHR* pCreateInfo, const AllocationCallbacks* pAllocator, SurfaceKHR* pSurface ) const\n  {\n    return static_cast<Result>( vkCreateWin32SurfaceKHR( m_instance, reinterpret_cast<const VkWin32SurfaceCreateInfoKHR*>( pCreateInfo ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ), reinterpret_cast<VkSurfaceKHR*>( pSurface ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<SurfaceKHR>::type Instance::createWin32SurfaceKHR( const Win32SurfaceCreateInfoKHR & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    SurfaceKHR surface;\n    Result result = static_cast<Result>( vkCreateWin32SurfaceKHR( m_instance, reinterpret_cast<const VkWin32SurfaceCreateInfoKHR*>( &createInfo ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkSurfaceKHR*>( &surface ) ) );\n    return createResultValue( result, surface, \"vk::Instance::createWin32SurfaceKHR\" );\n  }\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  VULKAN_HPP_INLINE UniqueSurfaceKHR Instance::createWin32SurfaceKHRUnique( const Win32SurfaceCreateInfoKHR & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    SurfaceKHRDeleter deleter( *this, allocator );\n    return UniqueSurfaceKHR( createWin32SurfaceKHR( createInfo, allocator ), deleter );\n  }\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n#endif /*VK_USE_PLATFORM_WIN32_KHR*/\n\n#ifdef VK_USE_PLATFORM_XLIB_KHR\n  VULKAN_HPP_INLINE Result Instance::createXlibSurfaceKHR( const XlibSurfaceCreateInfoKHR* pCreateInfo, const AllocationCallbacks* pAllocator, SurfaceKHR* pSurface ) const\n  {\n    return static_cast<Result>( vkCreateXlibSurfaceKHR( m_instance, reinterpret_cast<const VkXlibSurfaceCreateInfoKHR*>( pCreateInfo ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ), reinterpret_cast<VkSurfaceKHR*>( pSurface ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<SurfaceKHR>::type Instance::createXlibSurfaceKHR( const XlibSurfaceCreateInfoKHR & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    SurfaceKHR surface;\n    Result result = static_cast<Result>( vkCreateXlibSurfaceKHR( m_instance, reinterpret_cast<const VkXlibSurfaceCreateInfoKHR*>( &createInfo ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkSurfaceKHR*>( &surface ) ) );\n    return createResultValue( result, surface, \"vk::Instance::createXlibSurfaceKHR\" );\n  }\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  VULKAN_HPP_INLINE UniqueSurfaceKHR Instance::createXlibSurfaceKHRUnique( const XlibSurfaceCreateInfoKHR & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    SurfaceKHRDeleter deleter( *this, allocator );\n    return UniqueSurfaceKHR( createXlibSurfaceKHR( createInfo, allocator ), deleter );\n  }\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n#endif /*VK_USE_PLATFORM_XLIB_KHR*/\n\n#ifdef VK_USE_PLATFORM_XCB_KHR\n  VULKAN_HPP_INLINE Result Instance::createXcbSurfaceKHR( const XcbSurfaceCreateInfoKHR* pCreateInfo, const AllocationCallbacks* pAllocator, SurfaceKHR* pSurface ) const\n  {\n    return static_cast<Result>( vkCreateXcbSurfaceKHR( m_instance, reinterpret_cast<const VkXcbSurfaceCreateInfoKHR*>( pCreateInfo ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ), reinterpret_cast<VkSurfaceKHR*>( pSurface ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<SurfaceKHR>::type Instance::createXcbSurfaceKHR( const XcbSurfaceCreateInfoKHR & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    SurfaceKHR surface;\n    Result result = static_cast<Result>( vkCreateXcbSurfaceKHR( m_instance, reinterpret_cast<const VkXcbSurfaceCreateInfoKHR*>( &createInfo ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkSurfaceKHR*>( &surface ) ) );\n    return createResultValue( result, surface, \"vk::Instance::createXcbSurfaceKHR\" );\n  }\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  VULKAN_HPP_INLINE UniqueSurfaceKHR Instance::createXcbSurfaceKHRUnique( const XcbSurfaceCreateInfoKHR & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    SurfaceKHRDeleter deleter( *this, allocator );\n    return UniqueSurfaceKHR( createXcbSurfaceKHR( createInfo, allocator ), deleter );\n  }\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n#endif /*VK_USE_PLATFORM_XCB_KHR*/\n\n  VULKAN_HPP_INLINE Result Instance::createDebugReportCallbackEXT( const DebugReportCallbackCreateInfoEXT* pCreateInfo, const AllocationCallbacks* pAllocator, DebugReportCallbackEXT* pCallback ) const\n  {\n    return static_cast<Result>( vkCreateDebugReportCallbackEXT( m_instance, reinterpret_cast<const VkDebugReportCallbackCreateInfoEXT*>( pCreateInfo ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ), reinterpret_cast<VkDebugReportCallbackEXT*>( pCallback ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<DebugReportCallbackEXT>::type Instance::createDebugReportCallbackEXT( const DebugReportCallbackCreateInfoEXT & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    DebugReportCallbackEXT callback;\n    Result result = static_cast<Result>( vkCreateDebugReportCallbackEXT( m_instance, reinterpret_cast<const VkDebugReportCallbackCreateInfoEXT*>( &createInfo ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkDebugReportCallbackEXT*>( &callback ) ) );\n    return createResultValue( result, callback, \"vk::Instance::createDebugReportCallbackEXT\" );\n  }\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  VULKAN_HPP_INLINE UniqueDebugReportCallbackEXT Instance::createDebugReportCallbackEXTUnique( const DebugReportCallbackCreateInfoEXT & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    DebugReportCallbackEXTDeleter deleter( *this, allocator );\n    return UniqueDebugReportCallbackEXT( createDebugReportCallbackEXT( createInfo, allocator ), deleter );\n  }\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void Instance::destroyDebugReportCallbackEXT( DebugReportCallbackEXT callback, const AllocationCallbacks* pAllocator ) const\n  {\n    vkDestroyDebugReportCallbackEXT( m_instance, static_cast<VkDebugReportCallbackEXT>( callback ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void Instance::destroyDebugReportCallbackEXT( DebugReportCallbackEXT callback, Optional<const AllocationCallbacks> allocator ) const\n  {\n    vkDestroyDebugReportCallbackEXT( m_instance, static_cast<VkDebugReportCallbackEXT>( callback ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ) );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE void Instance::debugReportMessageEXT( DebugReportFlagsEXT flags, DebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage ) const\n  {\n    vkDebugReportMessageEXT( m_instance, static_cast<VkDebugReportFlagsEXT>( flags ), static_cast<VkDebugReportObjectTypeEXT>( objectType ), object, location, messageCode, pLayerPrefix, pMessage );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE void Instance::debugReportMessageEXT( DebugReportFlagsEXT flags, DebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const std::string & layerPrefix, const std::string & message ) const\n  {\n#ifdef VULKAN_HPP_NO_EXCEPTIONS\n    assert( layerPrefix.size() == message.size() );\n#else\n    if ( layerPrefix.size() != message.size() )\n    {\n      throw std::logic_error( \"vk::Instance::debugReportMessageEXT: layerPrefix.size() != message.size()\" );\n    }\n#endif  // VULKAN_HPP_NO_EXCEPTIONS\n    vkDebugReportMessageEXT( m_instance, static_cast<VkDebugReportFlagsEXT>( flags ), static_cast<VkDebugReportObjectTypeEXT>( objectType ), object, location, messageCode, layerPrefix.c_str(), message.c_str() );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n  VULKAN_HPP_INLINE Result Instance::enumeratePhysicalDeviceGroupsKHX( uint32_t* pPhysicalDeviceGroupCount, PhysicalDeviceGroupPropertiesKHX* pPhysicalDeviceGroupProperties ) const\n  {\n    return static_cast<Result>( vkEnumeratePhysicalDeviceGroupsKHX( m_instance, pPhysicalDeviceGroupCount, reinterpret_cast<VkPhysicalDeviceGroupPropertiesKHX*>( pPhysicalDeviceGroupProperties ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  template <typename Allocator> \n  VULKAN_HPP_INLINE typename ResultValueType<std::vector<PhysicalDeviceGroupPropertiesKHX,Allocator>>::type Instance::enumeratePhysicalDeviceGroupsKHX() const\n  {\n    std::vector<PhysicalDeviceGroupPropertiesKHX,Allocator> physicalDeviceGroupProperties;\n    uint32_t physicalDeviceGroupCount;\n    Result result;\n    do\n    {\n      result = static_cast<Result>( vkEnumeratePhysicalDeviceGroupsKHX( m_instance, &physicalDeviceGroupCount, nullptr ) );\n      if ( ( result == Result::eSuccess ) && physicalDeviceGroupCount )\n      {\n        physicalDeviceGroupProperties.resize( physicalDeviceGroupCount );\n        result = static_cast<Result>( vkEnumeratePhysicalDeviceGroupsKHX( m_instance, &physicalDeviceGroupCount, reinterpret_cast<VkPhysicalDeviceGroupPropertiesKHX*>( physicalDeviceGroupProperties.data() ) ) );\n      }\n    } while ( result == Result::eIncomplete );\n    assert( physicalDeviceGroupCount <= physicalDeviceGroupProperties.size() ); \n    physicalDeviceGroupProperties.resize( physicalDeviceGroupCount ); \n    return createResultValue( result, physicalDeviceGroupProperties, \"vk::Instance::enumeratePhysicalDeviceGroupsKHX\" );\n  }\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifdef VK_USE_PLATFORM_IOS_MVK\n  VULKAN_HPP_INLINE Result Instance::createIOSSurfaceMVK( const IOSSurfaceCreateInfoMVK* pCreateInfo, const AllocationCallbacks* pAllocator, SurfaceKHR* pSurface ) const\n  {\n    return static_cast<Result>( vkCreateIOSSurfaceMVK( m_instance, reinterpret_cast<const VkIOSSurfaceCreateInfoMVK*>( pCreateInfo ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ), reinterpret_cast<VkSurfaceKHR*>( pSurface ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<SurfaceKHR>::type Instance::createIOSSurfaceMVK( const IOSSurfaceCreateInfoMVK & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    SurfaceKHR surface;\n    Result result = static_cast<Result>( vkCreateIOSSurfaceMVK( m_instance, reinterpret_cast<const VkIOSSurfaceCreateInfoMVK*>( &createInfo ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkSurfaceKHR*>( &surface ) ) );\n    return createResultValue( result, surface, \"vk::Instance::createIOSSurfaceMVK\" );\n  }\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  VULKAN_HPP_INLINE UniqueSurfaceKHR Instance::createIOSSurfaceMVKUnique( const IOSSurfaceCreateInfoMVK & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    SurfaceKHRDeleter deleter( *this, allocator );\n    return UniqueSurfaceKHR( createIOSSurfaceMVK( createInfo, allocator ), deleter );\n  }\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n#endif /*VK_USE_PLATFORM_IOS_MVK*/\n\n#ifdef VK_USE_PLATFORM_MACOS_MVK\n  VULKAN_HPP_INLINE Result Instance::createMacOSSurfaceMVK( const MacOSSurfaceCreateInfoMVK* pCreateInfo, const AllocationCallbacks* pAllocator, SurfaceKHR* pSurface ) const\n  {\n    return static_cast<Result>( vkCreateMacOSSurfaceMVK( m_instance, reinterpret_cast<const VkMacOSSurfaceCreateInfoMVK*>( pCreateInfo ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ), reinterpret_cast<VkSurfaceKHR*>( pSurface ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<SurfaceKHR>::type Instance::createMacOSSurfaceMVK( const MacOSSurfaceCreateInfoMVK & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    SurfaceKHR surface;\n    Result result = static_cast<Result>( vkCreateMacOSSurfaceMVK( m_instance, reinterpret_cast<const VkMacOSSurfaceCreateInfoMVK*>( &createInfo ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkSurfaceKHR*>( &surface ) ) );\n    return createResultValue( result, surface, \"vk::Instance::createMacOSSurfaceMVK\" );\n  }\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  VULKAN_HPP_INLINE UniqueSurfaceKHR Instance::createMacOSSurfaceMVKUnique( const MacOSSurfaceCreateInfoMVK & createInfo, Optional<const AllocationCallbacks> allocator ) const\n  {\n    SurfaceKHRDeleter deleter( *this, allocator );\n    return UniqueSurfaceKHR( createMacOSSurfaceMVK( createInfo, allocator ), deleter );\n  }\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n#endif /*VK_USE_PLATFORM_MACOS_MVK*/\n\n  struct DeviceGroupDeviceCreateInfoKHX\n  {\n    DeviceGroupDeviceCreateInfoKHX( uint32_t physicalDeviceCount_ = 0, const PhysicalDevice* pPhysicalDevices_ = nullptr )\n      : sType( StructureType::eDeviceGroupDeviceCreateInfoKHX )\n      , pNext( nullptr )\n      , physicalDeviceCount( physicalDeviceCount_ )\n      , pPhysicalDevices( pPhysicalDevices_ )\n    {\n    }\n\n    DeviceGroupDeviceCreateInfoKHX( VkDeviceGroupDeviceCreateInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DeviceGroupDeviceCreateInfoKHX) );\n    }\n\n    DeviceGroupDeviceCreateInfoKHX& operator=( VkDeviceGroupDeviceCreateInfoKHX const & rhs )\n    {\n      memcpy( this, &rhs, sizeof(DeviceGroupDeviceCreateInfoKHX) );\n      return *this;\n    }\n\n    DeviceGroupDeviceCreateInfoKHX& setPNext( const void* pNext_ )\n    {\n      pNext = pNext_;\n      return *this;\n    }\n\n    DeviceGroupDeviceCreateInfoKHX& setPhysicalDeviceCount( uint32_t physicalDeviceCount_ )\n    {\n      physicalDeviceCount = physicalDeviceCount_;\n      return *this;\n    }\n\n    DeviceGroupDeviceCreateInfoKHX& setPPhysicalDevices( const PhysicalDevice* pPhysicalDevices_ )\n    {\n      pPhysicalDevices = pPhysicalDevices_;\n      return *this;\n    }\n\n    operator const VkDeviceGroupDeviceCreateInfoKHX&() const\n    {\n      return *reinterpret_cast<const VkDeviceGroupDeviceCreateInfoKHX*>(this);\n    }\n\n    bool operator==( DeviceGroupDeviceCreateInfoKHX const& rhs ) const\n    {\n      return ( sType == rhs.sType )\n          && ( pNext == rhs.pNext )\n          && ( physicalDeviceCount == rhs.physicalDeviceCount )\n          && ( pPhysicalDevices == rhs.pPhysicalDevices );\n    }\n\n    bool operator!=( DeviceGroupDeviceCreateInfoKHX const& rhs ) const\n    {\n      return !operator==( rhs );\n    }\n\n  private:\n    StructureType sType;\n\n  public:\n    const void* pNext;\n    uint32_t physicalDeviceCount;\n    const PhysicalDevice* pPhysicalDevices;\n  };\n  static_assert( sizeof( DeviceGroupDeviceCreateInfoKHX ) == sizeof( VkDeviceGroupDeviceCreateInfoKHX ), \"struct and wrapper have different size!\" );\n\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  class InstanceDeleter;\n  using UniqueInstance = UniqueHandle<Instance, InstanceDeleter>;\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n\n    Result createInstance( const InstanceCreateInfo* pCreateInfo, const AllocationCallbacks* pAllocator, Instance* pInstance );\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n    ResultValueType<Instance>::type createInstance( const InstanceCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator = nullptr );\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n    UniqueInstance createInstanceUnique( const InstanceCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator = nullptr );\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  class InstanceDeleter\n  {\n  public:\n    InstanceDeleter( Optional<const AllocationCallbacks> allocator = nullptr )\n      : m_allocator( allocator )\n    {}\n\n    void operator()( Instance instance )\n    {\n      instance.destroy( m_allocator );\n    }\n\n  private:\n    Optional<const AllocationCallbacks> m_allocator;\n  };\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n\n  VULKAN_HPP_INLINE Result createInstance( const InstanceCreateInfo* pCreateInfo, const AllocationCallbacks* pAllocator, Instance* pInstance )\n  {\n    return static_cast<Result>( vkCreateInstance( reinterpret_cast<const VkInstanceCreateInfo*>( pCreateInfo ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ), reinterpret_cast<VkInstance*>( pInstance ) ) );\n  }\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n  VULKAN_HPP_INLINE ResultValueType<Instance>::type createInstance( const InstanceCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator )\n  {\n    Instance instance;\n    Result result = static_cast<Result>( vkCreateInstance( reinterpret_cast<const VkInstanceCreateInfo*>( &createInfo ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkInstance*>( &instance ) ) );\n    return createResultValue( result, instance, \"vk::createInstance\" );\n  }\n#ifndef VULKAN_HPP_NO_SMART_HANDLE\n  VULKAN_HPP_INLINE UniqueInstance createInstanceUnique( const InstanceCreateInfo & createInfo, Optional<const AllocationCallbacks> allocator )\n  {\n    InstanceDeleter deleter( allocator );\n    return UniqueInstance( createInstance( createInfo, allocator ), deleter );\n  }\n#endif /*VULKAN_HPP_NO_SMART_HANDLE*/\n#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/\n\n\n  VULKAN_HPP_INLINE std::string to_string(FramebufferCreateFlagBits)\n  {\n    return \"(void)\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(FramebufferCreateFlags)\n  {\n    return \"{}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(QueryPoolCreateFlagBits)\n  {\n    return \"(void)\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(QueryPoolCreateFlags)\n  {\n    return \"{}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(RenderPassCreateFlagBits)\n  {\n    return \"(void)\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(RenderPassCreateFlags)\n  {\n    return \"{}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(SamplerCreateFlagBits)\n  {\n    return \"(void)\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(SamplerCreateFlags)\n  {\n    return \"{}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(PipelineLayoutCreateFlagBits)\n  {\n    return \"(void)\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(PipelineLayoutCreateFlags)\n  {\n    return \"{}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(PipelineCacheCreateFlagBits)\n  {\n    return \"(void)\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(PipelineCacheCreateFlags)\n  {\n    return \"{}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(PipelineDepthStencilStateCreateFlagBits)\n  {\n    return \"(void)\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(PipelineDepthStencilStateCreateFlags)\n  {\n    return \"{}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(PipelineDynamicStateCreateFlagBits)\n  {\n    return \"(void)\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(PipelineDynamicStateCreateFlags)\n  {\n    return \"{}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(PipelineColorBlendStateCreateFlagBits)\n  {\n    return \"(void)\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(PipelineColorBlendStateCreateFlags)\n  {\n    return \"{}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(PipelineMultisampleStateCreateFlagBits)\n  {\n    return \"(void)\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(PipelineMultisampleStateCreateFlags)\n  {\n    return \"{}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(PipelineRasterizationStateCreateFlagBits)\n  {\n    return \"(void)\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(PipelineRasterizationStateCreateFlags)\n  {\n    return \"{}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(PipelineViewportStateCreateFlagBits)\n  {\n    return \"(void)\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(PipelineViewportStateCreateFlags)\n  {\n    return \"{}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(PipelineTessellationStateCreateFlagBits)\n  {\n    return \"(void)\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(PipelineTessellationStateCreateFlags)\n  {\n    return \"{}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(PipelineInputAssemblyStateCreateFlagBits)\n  {\n    return \"(void)\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(PipelineInputAssemblyStateCreateFlags)\n  {\n    return \"{}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(PipelineVertexInputStateCreateFlagBits)\n  {\n    return \"(void)\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(PipelineVertexInputStateCreateFlags)\n  {\n    return \"{}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(PipelineShaderStageCreateFlagBits)\n  {\n    return \"(void)\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(PipelineShaderStageCreateFlags)\n  {\n    return \"{}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(BufferViewCreateFlagBits)\n  {\n    return \"(void)\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(BufferViewCreateFlags)\n  {\n    return \"{}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(InstanceCreateFlagBits)\n  {\n    return \"(void)\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(InstanceCreateFlags)\n  {\n    return \"{}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(DeviceCreateFlagBits)\n  {\n    return \"(void)\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(DeviceCreateFlags)\n  {\n    return \"{}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(DeviceQueueCreateFlagBits)\n  {\n    return \"(void)\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(DeviceQueueCreateFlags)\n  {\n    return \"{}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(ImageViewCreateFlagBits)\n  {\n    return \"(void)\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(ImageViewCreateFlags)\n  {\n    return \"{}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(SemaphoreCreateFlagBits)\n  {\n    return \"(void)\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(SemaphoreCreateFlags)\n  {\n    return \"{}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(ShaderModuleCreateFlagBits)\n  {\n    return \"(void)\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(ShaderModuleCreateFlags)\n  {\n    return \"{}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(EventCreateFlagBits)\n  {\n    return \"(void)\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(EventCreateFlags)\n  {\n    return \"{}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(MemoryMapFlagBits)\n  {\n    return \"(void)\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(MemoryMapFlags)\n  {\n    return \"{}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(DescriptorPoolResetFlagBits)\n  {\n    return \"(void)\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(DescriptorPoolResetFlags)\n  {\n    return \"{}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(DescriptorUpdateTemplateCreateFlagBitsKHR)\n  {\n    return \"(void)\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(DescriptorUpdateTemplateCreateFlagsKHR)\n  {\n    return \"{}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(DisplayModeCreateFlagBitsKHR)\n  {\n    return \"(void)\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(DisplayModeCreateFlagsKHR)\n  {\n    return \"{}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(DisplaySurfaceCreateFlagBitsKHR)\n  {\n    return \"(void)\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(DisplaySurfaceCreateFlagsKHR)\n  {\n    return \"{}\";\n  }\n\n#ifdef VK_USE_PLATFORM_ANDROID_KHR\n  VULKAN_HPP_INLINE std::string to_string(AndroidSurfaceCreateFlagBitsKHR)\n  {\n    return \"(void)\";\n  }\n#endif /*VK_USE_PLATFORM_ANDROID_KHR*/\n\n#ifdef VK_USE_PLATFORM_ANDROID_KHR\n  VULKAN_HPP_INLINE std::string to_string(AndroidSurfaceCreateFlagsKHR)\n  {\n    return \"{}\";\n  }\n#endif /*VK_USE_PLATFORM_ANDROID_KHR*/\n\n#ifdef VK_USE_PLATFORM_MIR_KHR\n  VULKAN_HPP_INLINE std::string to_string(MirSurfaceCreateFlagBitsKHR)\n  {\n    return \"(void)\";\n  }\n#endif /*VK_USE_PLATFORM_MIR_KHR*/\n\n#ifdef VK_USE_PLATFORM_MIR_KHR\n  VULKAN_HPP_INLINE std::string to_string(MirSurfaceCreateFlagsKHR)\n  {\n    return \"{}\";\n  }\n#endif /*VK_USE_PLATFORM_MIR_KHR*/\n\n#ifdef VK_USE_PLATFORM_VI_NN\n  VULKAN_HPP_INLINE std::string to_string(ViSurfaceCreateFlagBitsNN)\n  {\n    return \"(void)\";\n  }\n#endif /*VK_USE_PLATFORM_VI_NN*/\n\n#ifdef VK_USE_PLATFORM_VI_NN\n  VULKAN_HPP_INLINE std::string to_string(ViSurfaceCreateFlagsNN)\n  {\n    return \"{}\";\n  }\n#endif /*VK_USE_PLATFORM_VI_NN*/\n\n#ifdef VK_USE_PLATFORM_WAYLAND_KHR\n  VULKAN_HPP_INLINE std::string to_string(WaylandSurfaceCreateFlagBitsKHR)\n  {\n    return \"(void)\";\n  }\n#endif /*VK_USE_PLATFORM_WAYLAND_KHR*/\n\n#ifdef VK_USE_PLATFORM_WAYLAND_KHR\n  VULKAN_HPP_INLINE std::string to_string(WaylandSurfaceCreateFlagsKHR)\n  {\n    return \"{}\";\n  }\n#endif /*VK_USE_PLATFORM_WAYLAND_KHR*/\n\n#ifdef VK_USE_PLATFORM_WIN32_KHR\n  VULKAN_HPP_INLINE std::string to_string(Win32SurfaceCreateFlagBitsKHR)\n  {\n    return \"(void)\";\n  }\n#endif /*VK_USE_PLATFORM_WIN32_KHR*/\n\n#ifdef VK_USE_PLATFORM_WIN32_KHR\n  VULKAN_HPP_INLINE std::string to_string(Win32SurfaceCreateFlagsKHR)\n  {\n    return \"{}\";\n  }\n#endif /*VK_USE_PLATFORM_WIN32_KHR*/\n\n#ifdef VK_USE_PLATFORM_XLIB_KHR\n  VULKAN_HPP_INLINE std::string to_string(XlibSurfaceCreateFlagBitsKHR)\n  {\n    return \"(void)\";\n  }\n#endif /*VK_USE_PLATFORM_XLIB_KHR*/\n\n#ifdef VK_USE_PLATFORM_XLIB_KHR\n  VULKAN_HPP_INLINE std::string to_string(XlibSurfaceCreateFlagsKHR)\n  {\n    return \"{}\";\n  }\n#endif /*VK_USE_PLATFORM_XLIB_KHR*/\n\n#ifdef VK_USE_PLATFORM_XCB_KHR\n  VULKAN_HPP_INLINE std::string to_string(XcbSurfaceCreateFlagBitsKHR)\n  {\n    return \"(void)\";\n  }\n#endif /*VK_USE_PLATFORM_XCB_KHR*/\n\n#ifdef VK_USE_PLATFORM_XCB_KHR\n  VULKAN_HPP_INLINE std::string to_string(XcbSurfaceCreateFlagsKHR)\n  {\n    return \"{}\";\n  }\n#endif /*VK_USE_PLATFORM_XCB_KHR*/\n\n#ifdef VK_USE_PLATFORM_IOS_MVK\n  VULKAN_HPP_INLINE std::string to_string(IOSSurfaceCreateFlagBitsMVK)\n  {\n    return \"(void)\";\n  }\n#endif /*VK_USE_PLATFORM_IOS_MVK*/\n\n#ifdef VK_USE_PLATFORM_IOS_MVK\n  VULKAN_HPP_INLINE std::string to_string(IOSSurfaceCreateFlagsMVK)\n  {\n    return \"{}\";\n  }\n#endif /*VK_USE_PLATFORM_IOS_MVK*/\n\n#ifdef VK_USE_PLATFORM_MACOS_MVK\n  VULKAN_HPP_INLINE std::string to_string(MacOSSurfaceCreateFlagBitsMVK)\n  {\n    return \"(void)\";\n  }\n#endif /*VK_USE_PLATFORM_MACOS_MVK*/\n\n#ifdef VK_USE_PLATFORM_MACOS_MVK\n  VULKAN_HPP_INLINE std::string to_string(MacOSSurfaceCreateFlagsMVK)\n  {\n    return \"{}\";\n  }\n#endif /*VK_USE_PLATFORM_MACOS_MVK*/\n\n  VULKAN_HPP_INLINE std::string to_string(CommandPoolTrimFlagBitsKHR)\n  {\n    return \"(void)\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(CommandPoolTrimFlagsKHR)\n  {\n    return \"{}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(PipelineViewportSwizzleStateCreateFlagBitsNV)\n  {\n    return \"(void)\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(PipelineViewportSwizzleStateCreateFlagsNV)\n  {\n    return \"{}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(PipelineDiscardRectangleStateCreateFlagBitsEXT)\n  {\n    return \"(void)\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(PipelineDiscardRectangleStateCreateFlagsEXT)\n  {\n    return \"{}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(ImageLayout value)\n  {\n    switch (value)\n    {\n    case ImageLayout::eUndefined: return \"Undefined\";\n    case ImageLayout::eGeneral: return \"General\";\n    case ImageLayout::eColorAttachmentOptimal: return \"ColorAttachmentOptimal\";\n    case ImageLayout::eDepthStencilAttachmentOptimal: return \"DepthStencilAttachmentOptimal\";\n    case ImageLayout::eDepthStencilReadOnlyOptimal: return \"DepthStencilReadOnlyOptimal\";\n    case ImageLayout::eShaderReadOnlyOptimal: return \"ShaderReadOnlyOptimal\";\n    case ImageLayout::eTransferSrcOptimal: return \"TransferSrcOptimal\";\n    case ImageLayout::eTransferDstOptimal: return \"TransferDstOptimal\";\n    case ImageLayout::ePreinitialized: return \"Preinitialized\";\n    case ImageLayout::ePresentSrcKHR: return \"PresentSrcKHR\";\n    case ImageLayout::eSharedPresentKHR: return \"SharedPresentKHR\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(AttachmentLoadOp value)\n  {\n    switch (value)\n    {\n    case AttachmentLoadOp::eLoad: return \"Load\";\n    case AttachmentLoadOp::eClear: return \"Clear\";\n    case AttachmentLoadOp::eDontCare: return \"DontCare\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(AttachmentStoreOp value)\n  {\n    switch (value)\n    {\n    case AttachmentStoreOp::eStore: return \"Store\";\n    case AttachmentStoreOp::eDontCare: return \"DontCare\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(ImageType value)\n  {\n    switch (value)\n    {\n    case ImageType::e1D: return \"1D\";\n    case ImageType::e2D: return \"2D\";\n    case ImageType::e3D: return \"3D\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(ImageTiling value)\n  {\n    switch (value)\n    {\n    case ImageTiling::eOptimal: return \"Optimal\";\n    case ImageTiling::eLinear: return \"Linear\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(ImageViewType value)\n  {\n    switch (value)\n    {\n    case ImageViewType::e1D: return \"1D\";\n    case ImageViewType::e2D: return \"2D\";\n    case ImageViewType::e3D: return \"3D\";\n    case ImageViewType::eCube: return \"Cube\";\n    case ImageViewType::e1DArray: return \"1DArray\";\n    case ImageViewType::e2DArray: return \"2DArray\";\n    case ImageViewType::eCubeArray: return \"CubeArray\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(CommandBufferLevel value)\n  {\n    switch (value)\n    {\n    case CommandBufferLevel::ePrimary: return \"Primary\";\n    case CommandBufferLevel::eSecondary: return \"Secondary\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(ComponentSwizzle value)\n  {\n    switch (value)\n    {\n    case ComponentSwizzle::eIdentity: return \"Identity\";\n    case ComponentSwizzle::eZero: return \"Zero\";\n    case ComponentSwizzle::eOne: return \"One\";\n    case ComponentSwizzle::eR: return \"R\";\n    case ComponentSwizzle::eG: return \"G\";\n    case ComponentSwizzle::eB: return \"B\";\n    case ComponentSwizzle::eA: return \"A\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(DescriptorType value)\n  {\n    switch (value)\n    {\n    case DescriptorType::eSampler: return \"Sampler\";\n    case DescriptorType::eCombinedImageSampler: return \"CombinedImageSampler\";\n    case DescriptorType::eSampledImage: return \"SampledImage\";\n    case DescriptorType::eStorageImage: return \"StorageImage\";\n    case DescriptorType::eUniformTexelBuffer: return \"UniformTexelBuffer\";\n    case DescriptorType::eStorageTexelBuffer: return \"StorageTexelBuffer\";\n    case DescriptorType::eUniformBuffer: return \"UniformBuffer\";\n    case DescriptorType::eStorageBuffer: return \"StorageBuffer\";\n    case DescriptorType::eUniformBufferDynamic: return \"UniformBufferDynamic\";\n    case DescriptorType::eStorageBufferDynamic: return \"StorageBufferDynamic\";\n    case DescriptorType::eInputAttachment: return \"InputAttachment\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(QueryType value)\n  {\n    switch (value)\n    {\n    case QueryType::eOcclusion: return \"Occlusion\";\n    case QueryType::ePipelineStatistics: return \"PipelineStatistics\";\n    case QueryType::eTimestamp: return \"Timestamp\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(BorderColor value)\n  {\n    switch (value)\n    {\n    case BorderColor::eFloatTransparentBlack: return \"FloatTransparentBlack\";\n    case BorderColor::eIntTransparentBlack: return \"IntTransparentBlack\";\n    case BorderColor::eFloatOpaqueBlack: return \"FloatOpaqueBlack\";\n    case BorderColor::eIntOpaqueBlack: return \"IntOpaqueBlack\";\n    case BorderColor::eFloatOpaqueWhite: return \"FloatOpaqueWhite\";\n    case BorderColor::eIntOpaqueWhite: return \"IntOpaqueWhite\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(PipelineBindPoint value)\n  {\n    switch (value)\n    {\n    case PipelineBindPoint::eGraphics: return \"Graphics\";\n    case PipelineBindPoint::eCompute: return \"Compute\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(PipelineCacheHeaderVersion value)\n  {\n    switch (value)\n    {\n    case PipelineCacheHeaderVersion::eOne: return \"One\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(PrimitiveTopology value)\n  {\n    switch (value)\n    {\n    case PrimitiveTopology::ePointList: return \"PointList\";\n    case PrimitiveTopology::eLineList: return \"LineList\";\n    case PrimitiveTopology::eLineStrip: return \"LineStrip\";\n    case PrimitiveTopology::eTriangleList: return \"TriangleList\";\n    case PrimitiveTopology::eTriangleStrip: return \"TriangleStrip\";\n    case PrimitiveTopology::eTriangleFan: return \"TriangleFan\";\n    case PrimitiveTopology::eLineListWithAdjacency: return \"LineListWithAdjacency\";\n    case PrimitiveTopology::eLineStripWithAdjacency: return \"LineStripWithAdjacency\";\n    case PrimitiveTopology::eTriangleListWithAdjacency: return \"TriangleListWithAdjacency\";\n    case PrimitiveTopology::eTriangleStripWithAdjacency: return \"TriangleStripWithAdjacency\";\n    case PrimitiveTopology::ePatchList: return \"PatchList\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(SharingMode value)\n  {\n    switch (value)\n    {\n    case SharingMode::eExclusive: return \"Exclusive\";\n    case SharingMode::eConcurrent: return \"Concurrent\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(IndexType value)\n  {\n    switch (value)\n    {\n    case IndexType::eUint16: return \"Uint16\";\n    case IndexType::eUint32: return \"Uint32\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(Filter value)\n  {\n    switch (value)\n    {\n    case Filter::eNearest: return \"Nearest\";\n    case Filter::eLinear: return \"Linear\";\n    case Filter::eCubicIMG: return \"CubicIMG\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(SamplerMipmapMode value)\n  {\n    switch (value)\n    {\n    case SamplerMipmapMode::eNearest: return \"Nearest\";\n    case SamplerMipmapMode::eLinear: return \"Linear\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(SamplerAddressMode value)\n  {\n    switch (value)\n    {\n    case SamplerAddressMode::eRepeat: return \"Repeat\";\n    case SamplerAddressMode::eMirroredRepeat: return \"MirroredRepeat\";\n    case SamplerAddressMode::eClampToEdge: return \"ClampToEdge\";\n    case SamplerAddressMode::eClampToBorder: return \"ClampToBorder\";\n    case SamplerAddressMode::eMirrorClampToEdge: return \"MirrorClampToEdge\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(CompareOp value)\n  {\n    switch (value)\n    {\n    case CompareOp::eNever: return \"Never\";\n    case CompareOp::eLess: return \"Less\";\n    case CompareOp::eEqual: return \"Equal\";\n    case CompareOp::eLessOrEqual: return \"LessOrEqual\";\n    case CompareOp::eGreater: return \"Greater\";\n    case CompareOp::eNotEqual: return \"NotEqual\";\n    case CompareOp::eGreaterOrEqual: return \"GreaterOrEqual\";\n    case CompareOp::eAlways: return \"Always\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(PolygonMode value)\n  {\n    switch (value)\n    {\n    case PolygonMode::eFill: return \"Fill\";\n    case PolygonMode::eLine: return \"Line\";\n    case PolygonMode::ePoint: return \"Point\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(CullModeFlagBits value)\n  {\n    switch (value)\n    {\n    case CullModeFlagBits::eNone: return \"None\";\n    case CullModeFlagBits::eFront: return \"Front\";\n    case CullModeFlagBits::eBack: return \"Back\";\n    case CullModeFlagBits::eFrontAndBack: return \"FrontAndBack\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(CullModeFlags value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & CullModeFlagBits::eNone) result += \"None | \";\n    if (value & CullModeFlagBits::eFront) result += \"Front | \";\n    if (value & CullModeFlagBits::eBack) result += \"Back | \";\n    if (value & CullModeFlagBits::eFrontAndBack) result += \"FrontAndBack | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(FrontFace value)\n  {\n    switch (value)\n    {\n    case FrontFace::eCounterClockwise: return \"CounterClockwise\";\n    case FrontFace::eClockwise: return \"Clockwise\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(BlendFactor value)\n  {\n    switch (value)\n    {\n    case BlendFactor::eZero: return \"Zero\";\n    case BlendFactor::eOne: return \"One\";\n    case BlendFactor::eSrcColor: return \"SrcColor\";\n    case BlendFactor::eOneMinusSrcColor: return \"OneMinusSrcColor\";\n    case BlendFactor::eDstColor: return \"DstColor\";\n    case BlendFactor::eOneMinusDstColor: return \"OneMinusDstColor\";\n    case BlendFactor::eSrcAlpha: return \"SrcAlpha\";\n    case BlendFactor::eOneMinusSrcAlpha: return \"OneMinusSrcAlpha\";\n    case BlendFactor::eDstAlpha: return \"DstAlpha\";\n    case BlendFactor::eOneMinusDstAlpha: return \"OneMinusDstAlpha\";\n    case BlendFactor::eConstantColor: return \"ConstantColor\";\n    case BlendFactor::eOneMinusConstantColor: return \"OneMinusConstantColor\";\n    case BlendFactor::eConstantAlpha: return \"ConstantAlpha\";\n    case BlendFactor::eOneMinusConstantAlpha: return \"OneMinusConstantAlpha\";\n    case BlendFactor::eSrcAlphaSaturate: return \"SrcAlphaSaturate\";\n    case BlendFactor::eSrc1Color: return \"Src1Color\";\n    case BlendFactor::eOneMinusSrc1Color: return \"OneMinusSrc1Color\";\n    case BlendFactor::eSrc1Alpha: return \"Src1Alpha\";\n    case BlendFactor::eOneMinusSrc1Alpha: return \"OneMinusSrc1Alpha\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(BlendOp value)\n  {\n    switch (value)\n    {\n    case BlendOp::eAdd: return \"Add\";\n    case BlendOp::eSubtract: return \"Subtract\";\n    case BlendOp::eReverseSubtract: return \"ReverseSubtract\";\n    case BlendOp::eMin: return \"Min\";\n    case BlendOp::eMax: return \"Max\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(StencilOp value)\n  {\n    switch (value)\n    {\n    case StencilOp::eKeep: return \"Keep\";\n    case StencilOp::eZero: return \"Zero\";\n    case StencilOp::eReplace: return \"Replace\";\n    case StencilOp::eIncrementAndClamp: return \"IncrementAndClamp\";\n    case StencilOp::eDecrementAndClamp: return \"DecrementAndClamp\";\n    case StencilOp::eInvert: return \"Invert\";\n    case StencilOp::eIncrementAndWrap: return \"IncrementAndWrap\";\n    case StencilOp::eDecrementAndWrap: return \"DecrementAndWrap\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(LogicOp value)\n  {\n    switch (value)\n    {\n    case LogicOp::eClear: return \"Clear\";\n    case LogicOp::eAnd: return \"And\";\n    case LogicOp::eAndReverse: return \"AndReverse\";\n    case LogicOp::eCopy: return \"Copy\";\n    case LogicOp::eAndInverted: return \"AndInverted\";\n    case LogicOp::eNoOp: return \"NoOp\";\n    case LogicOp::eXor: return \"Xor\";\n    case LogicOp::eOr: return \"Or\";\n    case LogicOp::eNor: return \"Nor\";\n    case LogicOp::eEquivalent: return \"Equivalent\";\n    case LogicOp::eInvert: return \"Invert\";\n    case LogicOp::eOrReverse: return \"OrReverse\";\n    case LogicOp::eCopyInverted: return \"CopyInverted\";\n    case LogicOp::eOrInverted: return \"OrInverted\";\n    case LogicOp::eNand: return \"Nand\";\n    case LogicOp::eSet: return \"Set\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(InternalAllocationType value)\n  {\n    switch (value)\n    {\n    case InternalAllocationType::eExecutable: return \"Executable\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(SystemAllocationScope value)\n  {\n    switch (value)\n    {\n    case SystemAllocationScope::eCommand: return \"Command\";\n    case SystemAllocationScope::eObject: return \"Object\";\n    case SystemAllocationScope::eCache: return \"Cache\";\n    case SystemAllocationScope::eDevice: return \"Device\";\n    case SystemAllocationScope::eInstance: return \"Instance\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(PhysicalDeviceType value)\n  {\n    switch (value)\n    {\n    case PhysicalDeviceType::eOther: return \"Other\";\n    case PhysicalDeviceType::eIntegratedGpu: return \"IntegratedGpu\";\n    case PhysicalDeviceType::eDiscreteGpu: return \"DiscreteGpu\";\n    case PhysicalDeviceType::eVirtualGpu: return \"VirtualGpu\";\n    case PhysicalDeviceType::eCpu: return \"Cpu\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(VertexInputRate value)\n  {\n    switch (value)\n    {\n    case VertexInputRate::eVertex: return \"Vertex\";\n    case VertexInputRate::eInstance: return \"Instance\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(Format value)\n  {\n    switch (value)\n    {\n    case Format::eUndefined: return \"Undefined\";\n    case Format::eR4G4UnormPack8: return \"R4G4UnormPack8\";\n    case Format::eR4G4B4A4UnormPack16: return \"R4G4B4A4UnormPack16\";\n    case Format::eB4G4R4A4UnormPack16: return \"B4G4R4A4UnormPack16\";\n    case Format::eR5G6B5UnormPack16: return \"R5G6B5UnormPack16\";\n    case Format::eB5G6R5UnormPack16: return \"B5G6R5UnormPack16\";\n    case Format::eR5G5B5A1UnormPack16: return \"R5G5B5A1UnormPack16\";\n    case Format::eB5G5R5A1UnormPack16: return \"B5G5R5A1UnormPack16\";\n    case Format::eA1R5G5B5UnormPack16: return \"A1R5G5B5UnormPack16\";\n    case Format::eR8Unorm: return \"R8Unorm\";\n    case Format::eR8Snorm: return \"R8Snorm\";\n    case Format::eR8Uscaled: return \"R8Uscaled\";\n    case Format::eR8Sscaled: return \"R8Sscaled\";\n    case Format::eR8Uint: return \"R8Uint\";\n    case Format::eR8Sint: return \"R8Sint\";\n    case Format::eR8Srgb: return \"R8Srgb\";\n    case Format::eR8G8Unorm: return \"R8G8Unorm\";\n    case Format::eR8G8Snorm: return \"R8G8Snorm\";\n    case Format::eR8G8Uscaled: return \"R8G8Uscaled\";\n    case Format::eR8G8Sscaled: return \"R8G8Sscaled\";\n    case Format::eR8G8Uint: return \"R8G8Uint\";\n    case Format::eR8G8Sint: return \"R8G8Sint\";\n    case Format::eR8G8Srgb: return \"R8G8Srgb\";\n    case Format::eR8G8B8Unorm: return \"R8G8B8Unorm\";\n    case Format::eR8G8B8Snorm: return \"R8G8B8Snorm\";\n    case Format::eR8G8B8Uscaled: return \"R8G8B8Uscaled\";\n    case Format::eR8G8B8Sscaled: return \"R8G8B8Sscaled\";\n    case Format::eR8G8B8Uint: return \"R8G8B8Uint\";\n    case Format::eR8G8B8Sint: return \"R8G8B8Sint\";\n    case Format::eR8G8B8Srgb: return \"R8G8B8Srgb\";\n    case Format::eB8G8R8Unorm: return \"B8G8R8Unorm\";\n    case Format::eB8G8R8Snorm: return \"B8G8R8Snorm\";\n    case Format::eB8G8R8Uscaled: return \"B8G8R8Uscaled\";\n    case Format::eB8G8R8Sscaled: return \"B8G8R8Sscaled\";\n    case Format::eB8G8R8Uint: return \"B8G8R8Uint\";\n    case Format::eB8G8R8Sint: return \"B8G8R8Sint\";\n    case Format::eB8G8R8Srgb: return \"B8G8R8Srgb\";\n    case Format::eR8G8B8A8Unorm: return \"R8G8B8A8Unorm\";\n    case Format::eR8G8B8A8Snorm: return \"R8G8B8A8Snorm\";\n    case Format::eR8G8B8A8Uscaled: return \"R8G8B8A8Uscaled\";\n    case Format::eR8G8B8A8Sscaled: return \"R8G8B8A8Sscaled\";\n    case Format::eR8G8B8A8Uint: return \"R8G8B8A8Uint\";\n    case Format::eR8G8B8A8Sint: return \"R8G8B8A8Sint\";\n    case Format::eR8G8B8A8Srgb: return \"R8G8B8A8Srgb\";\n    case Format::eB8G8R8A8Unorm: return \"B8G8R8A8Unorm\";\n    case Format::eB8G8R8A8Snorm: return \"B8G8R8A8Snorm\";\n    case Format::eB8G8R8A8Uscaled: return \"B8G8R8A8Uscaled\";\n    case Format::eB8G8R8A8Sscaled: return \"B8G8R8A8Sscaled\";\n    case Format::eB8G8R8A8Uint: return \"B8G8R8A8Uint\";\n    case Format::eB8G8R8A8Sint: return \"B8G8R8A8Sint\";\n    case Format::eB8G8R8A8Srgb: return \"B8G8R8A8Srgb\";\n    case Format::eA8B8G8R8UnormPack32: return \"A8B8G8R8UnormPack32\";\n    case Format::eA8B8G8R8SnormPack32: return \"A8B8G8R8SnormPack32\";\n    case Format::eA8B8G8R8UscaledPack32: return \"A8B8G8R8UscaledPack32\";\n    case Format::eA8B8G8R8SscaledPack32: return \"A8B8G8R8SscaledPack32\";\n    case Format::eA8B8G8R8UintPack32: return \"A8B8G8R8UintPack32\";\n    case Format::eA8B8G8R8SintPack32: return \"A8B8G8R8SintPack32\";\n    case Format::eA8B8G8R8SrgbPack32: return \"A8B8G8R8SrgbPack32\";\n    case Format::eA2R10G10B10UnormPack32: return \"A2R10G10B10UnormPack32\";\n    case Format::eA2R10G10B10SnormPack32: return \"A2R10G10B10SnormPack32\";\n    case Format::eA2R10G10B10UscaledPack32: return \"A2R10G10B10UscaledPack32\";\n    case Format::eA2R10G10B10SscaledPack32: return \"A2R10G10B10SscaledPack32\";\n    case Format::eA2R10G10B10UintPack32: return \"A2R10G10B10UintPack32\";\n    case Format::eA2R10G10B10SintPack32: return \"A2R10G10B10SintPack32\";\n    case Format::eA2B10G10R10UnormPack32: return \"A2B10G10R10UnormPack32\";\n    case Format::eA2B10G10R10SnormPack32: return \"A2B10G10R10SnormPack32\";\n    case Format::eA2B10G10R10UscaledPack32: return \"A2B10G10R10UscaledPack32\";\n    case Format::eA2B10G10R10SscaledPack32: return \"A2B10G10R10SscaledPack32\";\n    case Format::eA2B10G10R10UintPack32: return \"A2B10G10R10UintPack32\";\n    case Format::eA2B10G10R10SintPack32: return \"A2B10G10R10SintPack32\";\n    case Format::eR16Unorm: return \"R16Unorm\";\n    case Format::eR16Snorm: return \"R16Snorm\";\n    case Format::eR16Uscaled: return \"R16Uscaled\";\n    case Format::eR16Sscaled: return \"R16Sscaled\";\n    case Format::eR16Uint: return \"R16Uint\";\n    case Format::eR16Sint: return \"R16Sint\";\n    case Format::eR16Sfloat: return \"R16Sfloat\";\n    case Format::eR16G16Unorm: return \"R16G16Unorm\";\n    case Format::eR16G16Snorm: return \"R16G16Snorm\";\n    case Format::eR16G16Uscaled: return \"R16G16Uscaled\";\n    case Format::eR16G16Sscaled: return \"R16G16Sscaled\";\n    case Format::eR16G16Uint: return \"R16G16Uint\";\n    case Format::eR16G16Sint: return \"R16G16Sint\";\n    case Format::eR16G16Sfloat: return \"R16G16Sfloat\";\n    case Format::eR16G16B16Unorm: return \"R16G16B16Unorm\";\n    case Format::eR16G16B16Snorm: return \"R16G16B16Snorm\";\n    case Format::eR16G16B16Uscaled: return \"R16G16B16Uscaled\";\n    case Format::eR16G16B16Sscaled: return \"R16G16B16Sscaled\";\n    case Format::eR16G16B16Uint: return \"R16G16B16Uint\";\n    case Format::eR16G16B16Sint: return \"R16G16B16Sint\";\n    case Format::eR16G16B16Sfloat: return \"R16G16B16Sfloat\";\n    case Format::eR16G16B16A16Unorm: return \"R16G16B16A16Unorm\";\n    case Format::eR16G16B16A16Snorm: return \"R16G16B16A16Snorm\";\n    case Format::eR16G16B16A16Uscaled: return \"R16G16B16A16Uscaled\";\n    case Format::eR16G16B16A16Sscaled: return \"R16G16B16A16Sscaled\";\n    case Format::eR16G16B16A16Uint: return \"R16G16B16A16Uint\";\n    case Format::eR16G16B16A16Sint: return \"R16G16B16A16Sint\";\n    case Format::eR16G16B16A16Sfloat: return \"R16G16B16A16Sfloat\";\n    case Format::eR32Uint: return \"R32Uint\";\n    case Format::eR32Sint: return \"R32Sint\";\n    case Format::eR32Sfloat: return \"R32Sfloat\";\n    case Format::eR32G32Uint: return \"R32G32Uint\";\n    case Format::eR32G32Sint: return \"R32G32Sint\";\n    case Format::eR32G32Sfloat: return \"R32G32Sfloat\";\n    case Format::eR32G32B32Uint: return \"R32G32B32Uint\";\n    case Format::eR32G32B32Sint: return \"R32G32B32Sint\";\n    case Format::eR32G32B32Sfloat: return \"R32G32B32Sfloat\";\n    case Format::eR32G32B32A32Uint: return \"R32G32B32A32Uint\";\n    case Format::eR32G32B32A32Sint: return \"R32G32B32A32Sint\";\n    case Format::eR32G32B32A32Sfloat: return \"R32G32B32A32Sfloat\";\n    case Format::eR64Uint: return \"R64Uint\";\n    case Format::eR64Sint: return \"R64Sint\";\n    case Format::eR64Sfloat: return \"R64Sfloat\";\n    case Format::eR64G64Uint: return \"R64G64Uint\";\n    case Format::eR64G64Sint: return \"R64G64Sint\";\n    case Format::eR64G64Sfloat: return \"R64G64Sfloat\";\n    case Format::eR64G64B64Uint: return \"R64G64B64Uint\";\n    case Format::eR64G64B64Sint: return \"R64G64B64Sint\";\n    case Format::eR64G64B64Sfloat: return \"R64G64B64Sfloat\";\n    case Format::eR64G64B64A64Uint: return \"R64G64B64A64Uint\";\n    case Format::eR64G64B64A64Sint: return \"R64G64B64A64Sint\";\n    case Format::eR64G64B64A64Sfloat: return \"R64G64B64A64Sfloat\";\n    case Format::eB10G11R11UfloatPack32: return \"B10G11R11UfloatPack32\";\n    case Format::eE5B9G9R9UfloatPack32: return \"E5B9G9R9UfloatPack32\";\n    case Format::eD16Unorm: return \"D16Unorm\";\n    case Format::eX8D24UnormPack32: return \"X8D24UnormPack32\";\n    case Format::eD32Sfloat: return \"D32Sfloat\";\n    case Format::eS8Uint: return \"S8Uint\";\n    case Format::eD16UnormS8Uint: return \"D16UnormS8Uint\";\n    case Format::eD24UnormS8Uint: return \"D24UnormS8Uint\";\n    case Format::eD32SfloatS8Uint: return \"D32SfloatS8Uint\";\n    case Format::eBc1RgbUnormBlock: return \"Bc1RgbUnormBlock\";\n    case Format::eBc1RgbSrgbBlock: return \"Bc1RgbSrgbBlock\";\n    case Format::eBc1RgbaUnormBlock: return \"Bc1RgbaUnormBlock\";\n    case Format::eBc1RgbaSrgbBlock: return \"Bc1RgbaSrgbBlock\";\n    case Format::eBc2UnormBlock: return \"Bc2UnormBlock\";\n    case Format::eBc2SrgbBlock: return \"Bc2SrgbBlock\";\n    case Format::eBc3UnormBlock: return \"Bc3UnormBlock\";\n    case Format::eBc3SrgbBlock: return \"Bc3SrgbBlock\";\n    case Format::eBc4UnormBlock: return \"Bc4UnormBlock\";\n    case Format::eBc4SnormBlock: return \"Bc4SnormBlock\";\n    case Format::eBc5UnormBlock: return \"Bc5UnormBlock\";\n    case Format::eBc5SnormBlock: return \"Bc5SnormBlock\";\n    case Format::eBc6HUfloatBlock: return \"Bc6HUfloatBlock\";\n    case Format::eBc6HSfloatBlock: return \"Bc6HSfloatBlock\";\n    case Format::eBc7UnormBlock: return \"Bc7UnormBlock\";\n    case Format::eBc7SrgbBlock: return \"Bc7SrgbBlock\";\n    case Format::eEtc2R8G8B8UnormBlock: return \"Etc2R8G8B8UnormBlock\";\n    case Format::eEtc2R8G8B8SrgbBlock: return \"Etc2R8G8B8SrgbBlock\";\n    case Format::eEtc2R8G8B8A1UnormBlock: return \"Etc2R8G8B8A1UnormBlock\";\n    case Format::eEtc2R8G8B8A1SrgbBlock: return \"Etc2R8G8B8A1SrgbBlock\";\n    case Format::eEtc2R8G8B8A8UnormBlock: return \"Etc2R8G8B8A8UnormBlock\";\n    case Format::eEtc2R8G8B8A8SrgbBlock: return \"Etc2R8G8B8A8SrgbBlock\";\n    case Format::eEacR11UnormBlock: return \"EacR11UnormBlock\";\n    case Format::eEacR11SnormBlock: return \"EacR11SnormBlock\";\n    case Format::eEacR11G11UnormBlock: return \"EacR11G11UnormBlock\";\n    case Format::eEacR11G11SnormBlock: return \"EacR11G11SnormBlock\";\n    case Format::eAstc4x4UnormBlock: return \"Astc4x4UnormBlock\";\n    case Format::eAstc4x4SrgbBlock: return \"Astc4x4SrgbBlock\";\n    case Format::eAstc5x4UnormBlock: return \"Astc5x4UnormBlock\";\n    case Format::eAstc5x4SrgbBlock: return \"Astc5x4SrgbBlock\";\n    case Format::eAstc5x5UnormBlock: return \"Astc5x5UnormBlock\";\n    case Format::eAstc5x5SrgbBlock: return \"Astc5x5SrgbBlock\";\n    case Format::eAstc6x5UnormBlock: return \"Astc6x5UnormBlock\";\n    case Format::eAstc6x5SrgbBlock: return \"Astc6x5SrgbBlock\";\n    case Format::eAstc6x6UnormBlock: return \"Astc6x6UnormBlock\";\n    case Format::eAstc6x6SrgbBlock: return \"Astc6x6SrgbBlock\";\n    case Format::eAstc8x5UnormBlock: return \"Astc8x5UnormBlock\";\n    case Format::eAstc8x5SrgbBlock: return \"Astc8x5SrgbBlock\";\n    case Format::eAstc8x6UnormBlock: return \"Astc8x6UnormBlock\";\n    case Format::eAstc8x6SrgbBlock: return \"Astc8x6SrgbBlock\";\n    case Format::eAstc8x8UnormBlock: return \"Astc8x8UnormBlock\";\n    case Format::eAstc8x8SrgbBlock: return \"Astc8x8SrgbBlock\";\n    case Format::eAstc10x5UnormBlock: return \"Astc10x5UnormBlock\";\n    case Format::eAstc10x5SrgbBlock: return \"Astc10x5SrgbBlock\";\n    case Format::eAstc10x6UnormBlock: return \"Astc10x6UnormBlock\";\n    case Format::eAstc10x6SrgbBlock: return \"Astc10x6SrgbBlock\";\n    case Format::eAstc10x8UnormBlock: return \"Astc10x8UnormBlock\";\n    case Format::eAstc10x8SrgbBlock: return \"Astc10x8SrgbBlock\";\n    case Format::eAstc10x10UnormBlock: return \"Astc10x10UnormBlock\";\n    case Format::eAstc10x10SrgbBlock: return \"Astc10x10SrgbBlock\";\n    case Format::eAstc12x10UnormBlock: return \"Astc12x10UnormBlock\";\n    case Format::eAstc12x10SrgbBlock: return \"Astc12x10SrgbBlock\";\n    case Format::eAstc12x12UnormBlock: return \"Astc12x12UnormBlock\";\n    case Format::eAstc12x12SrgbBlock: return \"Astc12x12SrgbBlock\";\n    case Format::ePvrtc12BppUnormBlockIMG: return \"Pvrtc12BppUnormBlockIMG\";\n    case Format::ePvrtc14BppUnormBlockIMG: return \"Pvrtc14BppUnormBlockIMG\";\n    case Format::ePvrtc22BppUnormBlockIMG: return \"Pvrtc22BppUnormBlockIMG\";\n    case Format::ePvrtc24BppUnormBlockIMG: return \"Pvrtc24BppUnormBlockIMG\";\n    case Format::ePvrtc12BppSrgbBlockIMG: return \"Pvrtc12BppSrgbBlockIMG\";\n    case Format::ePvrtc14BppSrgbBlockIMG: return \"Pvrtc14BppSrgbBlockIMG\";\n    case Format::ePvrtc22BppSrgbBlockIMG: return \"Pvrtc22BppSrgbBlockIMG\";\n    case Format::ePvrtc24BppSrgbBlockIMG: return \"Pvrtc24BppSrgbBlockIMG\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(StructureType value)\n  {\n    switch (value)\n    {\n    case StructureType::eApplicationInfo: return \"ApplicationInfo\";\n    case StructureType::eInstanceCreateInfo: return \"InstanceCreateInfo\";\n    case StructureType::eDeviceQueueCreateInfo: return \"DeviceQueueCreateInfo\";\n    case StructureType::eDeviceCreateInfo: return \"DeviceCreateInfo\";\n    case StructureType::eSubmitInfo: return \"SubmitInfo\";\n    case StructureType::eMemoryAllocateInfo: return \"MemoryAllocateInfo\";\n    case StructureType::eMappedMemoryRange: return \"MappedMemoryRange\";\n    case StructureType::eBindSparseInfo: return \"BindSparseInfo\";\n    case StructureType::eFenceCreateInfo: return \"FenceCreateInfo\";\n    case StructureType::eSemaphoreCreateInfo: return \"SemaphoreCreateInfo\";\n    case StructureType::eEventCreateInfo: return \"EventCreateInfo\";\n    case StructureType::eQueryPoolCreateInfo: return \"QueryPoolCreateInfo\";\n    case StructureType::eBufferCreateInfo: return \"BufferCreateInfo\";\n    case StructureType::eBufferViewCreateInfo: return \"BufferViewCreateInfo\";\n    case StructureType::eImageCreateInfo: return \"ImageCreateInfo\";\n    case StructureType::eImageViewCreateInfo: return \"ImageViewCreateInfo\";\n    case StructureType::eShaderModuleCreateInfo: return \"ShaderModuleCreateInfo\";\n    case StructureType::ePipelineCacheCreateInfo: return \"PipelineCacheCreateInfo\";\n    case StructureType::ePipelineShaderStageCreateInfo: return \"PipelineShaderStageCreateInfo\";\n    case StructureType::ePipelineVertexInputStateCreateInfo: return \"PipelineVertexInputStateCreateInfo\";\n    case StructureType::ePipelineInputAssemblyStateCreateInfo: return \"PipelineInputAssemblyStateCreateInfo\";\n    case StructureType::ePipelineTessellationStateCreateInfo: return \"PipelineTessellationStateCreateInfo\";\n    case StructureType::ePipelineViewportStateCreateInfo: return \"PipelineViewportStateCreateInfo\";\n    case StructureType::ePipelineRasterizationStateCreateInfo: return \"PipelineRasterizationStateCreateInfo\";\n    case StructureType::ePipelineMultisampleStateCreateInfo: return \"PipelineMultisampleStateCreateInfo\";\n    case StructureType::ePipelineDepthStencilStateCreateInfo: return \"PipelineDepthStencilStateCreateInfo\";\n    case StructureType::ePipelineColorBlendStateCreateInfo: return \"PipelineColorBlendStateCreateInfo\";\n    case StructureType::ePipelineDynamicStateCreateInfo: return \"PipelineDynamicStateCreateInfo\";\n    case StructureType::eGraphicsPipelineCreateInfo: return \"GraphicsPipelineCreateInfo\";\n    case StructureType::eComputePipelineCreateInfo: return \"ComputePipelineCreateInfo\";\n    case StructureType::ePipelineLayoutCreateInfo: return \"PipelineLayoutCreateInfo\";\n    case StructureType::eSamplerCreateInfo: return \"SamplerCreateInfo\";\n    case StructureType::eDescriptorSetLayoutCreateInfo: return \"DescriptorSetLayoutCreateInfo\";\n    case StructureType::eDescriptorPoolCreateInfo: return \"DescriptorPoolCreateInfo\";\n    case StructureType::eDescriptorSetAllocateInfo: return \"DescriptorSetAllocateInfo\";\n    case StructureType::eWriteDescriptorSet: return \"WriteDescriptorSet\";\n    case StructureType::eCopyDescriptorSet: return \"CopyDescriptorSet\";\n    case StructureType::eFramebufferCreateInfo: return \"FramebufferCreateInfo\";\n    case StructureType::eRenderPassCreateInfo: return \"RenderPassCreateInfo\";\n    case StructureType::eCommandPoolCreateInfo: return \"CommandPoolCreateInfo\";\n    case StructureType::eCommandBufferAllocateInfo: return \"CommandBufferAllocateInfo\";\n    case StructureType::eCommandBufferInheritanceInfo: return \"CommandBufferInheritanceInfo\";\n    case StructureType::eCommandBufferBeginInfo: return \"CommandBufferBeginInfo\";\n    case StructureType::eRenderPassBeginInfo: return \"RenderPassBeginInfo\";\n    case StructureType::eBufferMemoryBarrier: return \"BufferMemoryBarrier\";\n    case StructureType::eImageMemoryBarrier: return \"ImageMemoryBarrier\";\n    case StructureType::eMemoryBarrier: return \"MemoryBarrier\";\n    case StructureType::eLoaderInstanceCreateInfo: return \"LoaderInstanceCreateInfo\";\n    case StructureType::eLoaderDeviceCreateInfo: return \"LoaderDeviceCreateInfo\";\n    case StructureType::eSwapchainCreateInfoKHR: return \"SwapchainCreateInfoKHR\";\n    case StructureType::ePresentInfoKHR: return \"PresentInfoKHR\";\n    case StructureType::eDisplayModeCreateInfoKHR: return \"DisplayModeCreateInfoKHR\";\n    case StructureType::eDisplaySurfaceCreateInfoKHR: return \"DisplaySurfaceCreateInfoKHR\";\n    case StructureType::eDisplayPresentInfoKHR: return \"DisplayPresentInfoKHR\";\n    case StructureType::eXlibSurfaceCreateInfoKHR: return \"XlibSurfaceCreateInfoKHR\";\n    case StructureType::eXcbSurfaceCreateInfoKHR: return \"XcbSurfaceCreateInfoKHR\";\n    case StructureType::eWaylandSurfaceCreateInfoKHR: return \"WaylandSurfaceCreateInfoKHR\";\n    case StructureType::eMirSurfaceCreateInfoKHR: return \"MirSurfaceCreateInfoKHR\";\n    case StructureType::eAndroidSurfaceCreateInfoKHR: return \"AndroidSurfaceCreateInfoKHR\";\n    case StructureType::eWin32SurfaceCreateInfoKHR: return \"Win32SurfaceCreateInfoKHR\";\n    case StructureType::eDebugReportCallbackCreateInfoEXT: return \"DebugReportCallbackCreateInfoEXT\";\n    case StructureType::ePipelineRasterizationStateRasterizationOrderAMD: return \"PipelineRasterizationStateRasterizationOrderAMD\";\n    case StructureType::eDebugMarkerObjectNameInfoEXT: return \"DebugMarkerObjectNameInfoEXT\";\n    case StructureType::eDebugMarkerObjectTagInfoEXT: return \"DebugMarkerObjectTagInfoEXT\";\n    case StructureType::eDebugMarkerMarkerInfoEXT: return \"DebugMarkerMarkerInfoEXT\";\n    case StructureType::eDedicatedAllocationImageCreateInfoNV: return \"DedicatedAllocationImageCreateInfoNV\";\n    case StructureType::eDedicatedAllocationBufferCreateInfoNV: return \"DedicatedAllocationBufferCreateInfoNV\";\n    case StructureType::eDedicatedAllocationMemoryAllocateInfoNV: return \"DedicatedAllocationMemoryAllocateInfoNV\";\n    case StructureType::eRenderPassMultiviewCreateInfoKHX: return \"RenderPassMultiviewCreateInfoKHX\";\n    case StructureType::ePhysicalDeviceMultiviewFeaturesKHX: return \"PhysicalDeviceMultiviewFeaturesKHX\";\n    case StructureType::ePhysicalDeviceMultiviewPropertiesKHX: return \"PhysicalDeviceMultiviewPropertiesKHX\";\n    case StructureType::eExternalMemoryImageCreateInfoNV: return \"ExternalMemoryImageCreateInfoNV\";\n    case StructureType::eExportMemoryAllocateInfoNV: return \"ExportMemoryAllocateInfoNV\";\n    case StructureType::eImportMemoryWin32HandleInfoNV: return \"ImportMemoryWin32HandleInfoNV\";\n    case StructureType::eExportMemoryWin32HandleInfoNV: return \"ExportMemoryWin32HandleInfoNV\";\n    case StructureType::eWin32KeyedMutexAcquireReleaseInfoNV: return \"Win32KeyedMutexAcquireReleaseInfoNV\";\n    case StructureType::ePhysicalDeviceFeatures2KHR: return \"PhysicalDeviceFeatures2KHR\";\n    case StructureType::ePhysicalDeviceProperties2KHR: return \"PhysicalDeviceProperties2KHR\";\n    case StructureType::eFormatProperties2KHR: return \"FormatProperties2KHR\";\n    case StructureType::eImageFormatProperties2KHR: return \"ImageFormatProperties2KHR\";\n    case StructureType::ePhysicalDeviceImageFormatInfo2KHR: return \"PhysicalDeviceImageFormatInfo2KHR\";\n    case StructureType::eQueueFamilyProperties2KHR: return \"QueueFamilyProperties2KHR\";\n    case StructureType::ePhysicalDeviceMemoryProperties2KHR: return \"PhysicalDeviceMemoryProperties2KHR\";\n    case StructureType::eSparseImageFormatProperties2KHR: return \"SparseImageFormatProperties2KHR\";\n    case StructureType::ePhysicalDeviceSparseImageFormatInfo2KHR: return \"PhysicalDeviceSparseImageFormatInfo2KHR\";\n    case StructureType::eMemoryAllocateFlagsInfoKHX: return \"MemoryAllocateFlagsInfoKHX\";\n    case StructureType::eBindBufferMemoryInfoKHX: return \"BindBufferMemoryInfoKHX\";\n    case StructureType::eBindImageMemoryInfoKHX: return \"BindImageMemoryInfoKHX\";\n    case StructureType::eDeviceGroupRenderPassBeginInfoKHX: return \"DeviceGroupRenderPassBeginInfoKHX\";\n    case StructureType::eDeviceGroupCommandBufferBeginInfoKHX: return \"DeviceGroupCommandBufferBeginInfoKHX\";\n    case StructureType::eDeviceGroupSubmitInfoKHX: return \"DeviceGroupSubmitInfoKHX\";\n    case StructureType::eDeviceGroupBindSparseInfoKHX: return \"DeviceGroupBindSparseInfoKHX\";\n    case StructureType::eDeviceGroupPresentCapabilitiesKHX: return \"DeviceGroupPresentCapabilitiesKHX\";\n    case StructureType::eImageSwapchainCreateInfoKHX: return \"ImageSwapchainCreateInfoKHX\";\n    case StructureType::eBindImageMemorySwapchainInfoKHX: return \"BindImageMemorySwapchainInfoKHX\";\n    case StructureType::eAcquireNextImageInfoKHX: return \"AcquireNextImageInfoKHX\";\n    case StructureType::eDeviceGroupPresentInfoKHX: return \"DeviceGroupPresentInfoKHX\";\n    case StructureType::eDeviceGroupSwapchainCreateInfoKHX: return \"DeviceGroupSwapchainCreateInfoKHX\";\n    case StructureType::eValidationFlagsEXT: return \"ValidationFlagsEXT\";\n    case StructureType::eViSurfaceCreateInfoNN: return \"ViSurfaceCreateInfoNN\";\n    case StructureType::ePhysicalDeviceGroupPropertiesKHX: return \"PhysicalDeviceGroupPropertiesKHX\";\n    case StructureType::eDeviceGroupDeviceCreateInfoKHX: return \"DeviceGroupDeviceCreateInfoKHX\";\n    case StructureType::ePhysicalDeviceExternalImageFormatInfoKHX: return \"PhysicalDeviceExternalImageFormatInfoKHX\";\n    case StructureType::eExternalImageFormatPropertiesKHX: return \"ExternalImageFormatPropertiesKHX\";\n    case StructureType::ePhysicalDeviceExternalBufferInfoKHX: return \"PhysicalDeviceExternalBufferInfoKHX\";\n    case StructureType::eExternalBufferPropertiesKHX: return \"ExternalBufferPropertiesKHX\";\n    case StructureType::ePhysicalDeviceIdPropertiesKHX: return \"PhysicalDeviceIdPropertiesKHX\";\n    case StructureType::eExternalMemoryBufferCreateInfoKHX: return \"ExternalMemoryBufferCreateInfoKHX\";\n    case StructureType::eExternalMemoryImageCreateInfoKHX: return \"ExternalMemoryImageCreateInfoKHX\";\n    case StructureType::eExportMemoryAllocateInfoKHX: return \"ExportMemoryAllocateInfoKHX\";\n    case StructureType::eImportMemoryWin32HandleInfoKHX: return \"ImportMemoryWin32HandleInfoKHX\";\n    case StructureType::eExportMemoryWin32HandleInfoKHX: return \"ExportMemoryWin32HandleInfoKHX\";\n    case StructureType::eMemoryWin32HandlePropertiesKHX: return \"MemoryWin32HandlePropertiesKHX\";\n    case StructureType::eImportMemoryFdInfoKHX: return \"ImportMemoryFdInfoKHX\";\n    case StructureType::eMemoryFdPropertiesKHX: return \"MemoryFdPropertiesKHX\";\n    case StructureType::eWin32KeyedMutexAcquireReleaseInfoKHX: return \"Win32KeyedMutexAcquireReleaseInfoKHX\";\n    case StructureType::ePhysicalDeviceExternalSemaphoreInfoKHX: return \"PhysicalDeviceExternalSemaphoreInfoKHX\";\n    case StructureType::eExternalSemaphorePropertiesKHX: return \"ExternalSemaphorePropertiesKHX\";\n    case StructureType::eExportSemaphoreCreateInfoKHX: return \"ExportSemaphoreCreateInfoKHX\";\n    case StructureType::eImportSemaphoreWin32HandleInfoKHX: return \"ImportSemaphoreWin32HandleInfoKHX\";\n    case StructureType::eExportSemaphoreWin32HandleInfoKHX: return \"ExportSemaphoreWin32HandleInfoKHX\";\n    case StructureType::eD3D12FenceSubmitInfoKHX: return \"D3D12FenceSubmitInfoKHX\";\n    case StructureType::eImportSemaphoreFdInfoKHX: return \"ImportSemaphoreFdInfoKHX\";\n    case StructureType::ePhysicalDevicePushDescriptorPropertiesKHR: return \"PhysicalDevicePushDescriptorPropertiesKHR\";\n    case StructureType::ePresentRegionsKHR: return \"PresentRegionsKHR\";\n    case StructureType::eDescriptorUpdateTemplateCreateInfoKHR: return \"DescriptorUpdateTemplateCreateInfoKHR\";\n    case StructureType::eObjectTableCreateInfoNVX: return \"ObjectTableCreateInfoNVX\";\n    case StructureType::eIndirectCommandsLayoutCreateInfoNVX: return \"IndirectCommandsLayoutCreateInfoNVX\";\n    case StructureType::eCmdProcessCommandsInfoNVX: return \"CmdProcessCommandsInfoNVX\";\n    case StructureType::eCmdReserveSpaceForCommandsInfoNVX: return \"CmdReserveSpaceForCommandsInfoNVX\";\n    case StructureType::eDeviceGeneratedCommandsLimitsNVX: return \"DeviceGeneratedCommandsLimitsNVX\";\n    case StructureType::eDeviceGeneratedCommandsFeaturesNVX: return \"DeviceGeneratedCommandsFeaturesNVX\";\n    case StructureType::ePipelineViewportWScalingStateCreateInfoNV: return \"PipelineViewportWScalingStateCreateInfoNV\";\n    case StructureType::eSurfaceCapabilities2EXT: return \"SurfaceCapabilities2EXT\";\n    case StructureType::eDisplayPowerInfoEXT: return \"DisplayPowerInfoEXT\";\n    case StructureType::eDeviceEventInfoEXT: return \"DeviceEventInfoEXT\";\n    case StructureType::eDisplayEventInfoEXT: return \"DisplayEventInfoEXT\";\n    case StructureType::eSwapchainCounterCreateInfoEXT: return \"SwapchainCounterCreateInfoEXT\";\n    case StructureType::ePresentTimesInfoGOOGLE: return \"PresentTimesInfoGOOGLE\";\n    case StructureType::ePhysicalDeviceMultiviewPerViewAttributesPropertiesNVX: return \"PhysicalDeviceMultiviewPerViewAttributesPropertiesNVX\";\n    case StructureType::ePipelineViewportSwizzleStateCreateInfoNV: return \"PipelineViewportSwizzleStateCreateInfoNV\";\n    case StructureType::ePhysicalDeviceDiscardRectanglePropertiesEXT: return \"PhysicalDeviceDiscardRectanglePropertiesEXT\";\n    case StructureType::ePipelineDiscardRectangleStateCreateInfoEXT: return \"PipelineDiscardRectangleStateCreateInfoEXT\";\n    case StructureType::eHdrMetadataEXT: return \"HdrMetadataEXT\";\n    case StructureType::eSharedPresentSurfaceCapabilitiesKHR: return \"SharedPresentSurfaceCapabilitiesKHR\";\n    case StructureType::ePhysicalDeviceSurfaceInfo2KHR: return \"PhysicalDeviceSurfaceInfo2KHR\";\n    case StructureType::eSurfaceCapabilities2KHR: return \"SurfaceCapabilities2KHR\";\n    case StructureType::eSurfaceFormat2KHR: return \"SurfaceFormat2KHR\";\n    case StructureType::eIosSurfaceCreateInfoMVK: return \"IosSurfaceCreateInfoMVK\";\n    case StructureType::eMacosSurfaceCreateInfoMVK: return \"MacosSurfaceCreateInfoMVK\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(SubpassContents value)\n  {\n    switch (value)\n    {\n    case SubpassContents::eInline: return \"Inline\";\n    case SubpassContents::eSecondaryCommandBuffers: return \"SecondaryCommandBuffers\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(DynamicState value)\n  {\n    switch (value)\n    {\n    case DynamicState::eViewport: return \"Viewport\";\n    case DynamicState::eScissor: return \"Scissor\";\n    case DynamicState::eLineWidth: return \"LineWidth\";\n    case DynamicState::eDepthBias: return \"DepthBias\";\n    case DynamicState::eBlendConstants: return \"BlendConstants\";\n    case DynamicState::eDepthBounds: return \"DepthBounds\";\n    case DynamicState::eStencilCompareMask: return \"StencilCompareMask\";\n    case DynamicState::eStencilWriteMask: return \"StencilWriteMask\";\n    case DynamicState::eStencilReference: return \"StencilReference\";\n    case DynamicState::eViewportWScalingNV: return \"ViewportWScalingNV\";\n    case DynamicState::eDiscardRectangleEXT: return \"DiscardRectangleEXT\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(DescriptorUpdateTemplateTypeKHR value)\n  {\n    switch (value)\n    {\n    case DescriptorUpdateTemplateTypeKHR::eDescriptorSet: return \"DescriptorSet\";\n    case DescriptorUpdateTemplateTypeKHR::ePushDescriptors: return \"PushDescriptors\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(ObjectType value)\n  {\n    switch (value)\n    {\n    case ObjectType::eUnknown: return \"Unknown\";\n    case ObjectType::eInstance: return \"Instance\";\n    case ObjectType::ePhysicalDevice: return \"PhysicalDevice\";\n    case ObjectType::eDevice: return \"Device\";\n    case ObjectType::eQueue: return \"Queue\";\n    case ObjectType::eSemaphore: return \"Semaphore\";\n    case ObjectType::eCommandBuffer: return \"CommandBuffer\";\n    case ObjectType::eFence: return \"Fence\";\n    case ObjectType::eDeviceMemory: return \"DeviceMemory\";\n    case ObjectType::eBuffer: return \"Buffer\";\n    case ObjectType::eImage: return \"Image\";\n    case ObjectType::eEvent: return \"Event\";\n    case ObjectType::eQueryPool: return \"QueryPool\";\n    case ObjectType::eBufferView: return \"BufferView\";\n    case ObjectType::eImageView: return \"ImageView\";\n    case ObjectType::eShaderModule: return \"ShaderModule\";\n    case ObjectType::ePipelineCache: return \"PipelineCache\";\n    case ObjectType::ePipelineLayout: return \"PipelineLayout\";\n    case ObjectType::eRenderPass: return \"RenderPass\";\n    case ObjectType::ePipeline: return \"Pipeline\";\n    case ObjectType::eDescriptorSetLayout: return \"DescriptorSetLayout\";\n    case ObjectType::eSampler: return \"Sampler\";\n    case ObjectType::eDescriptorPool: return \"DescriptorPool\";\n    case ObjectType::eDescriptorSet: return \"DescriptorSet\";\n    case ObjectType::eFramebuffer: return \"Framebuffer\";\n    case ObjectType::eCommandPool: return \"CommandPool\";\n    case ObjectType::eSurfaceKHR: return \"SurfaceKHR\";\n    case ObjectType::eSwapchainKHR: return \"SwapchainKHR\";\n    case ObjectType::eDisplayKHR: return \"DisplayKHR\";\n    case ObjectType::eDisplayModeKHR: return \"DisplayModeKHR\";\n    case ObjectType::eDebugReportCallbackEXT: return \"DebugReportCallbackEXT\";\n    case ObjectType::eDescriptorUpdateTemplateKHR: return \"DescriptorUpdateTemplateKHR\";\n    case ObjectType::eObjectTableNVX: return \"ObjectTableNVX\";\n    case ObjectType::eIndirectCommandsLayoutNVX: return \"IndirectCommandsLayoutNVX\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(QueueFlagBits value)\n  {\n    switch (value)\n    {\n    case QueueFlagBits::eGraphics: return \"Graphics\";\n    case QueueFlagBits::eCompute: return \"Compute\";\n    case QueueFlagBits::eTransfer: return \"Transfer\";\n    case QueueFlagBits::eSparseBinding: return \"SparseBinding\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(QueueFlags value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & QueueFlagBits::eGraphics) result += \"Graphics | \";\n    if (value & QueueFlagBits::eCompute) result += \"Compute | \";\n    if (value & QueueFlagBits::eTransfer) result += \"Transfer | \";\n    if (value & QueueFlagBits::eSparseBinding) result += \"SparseBinding | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(MemoryPropertyFlagBits value)\n  {\n    switch (value)\n    {\n    case MemoryPropertyFlagBits::eDeviceLocal: return \"DeviceLocal\";\n    case MemoryPropertyFlagBits::eHostVisible: return \"HostVisible\";\n    case MemoryPropertyFlagBits::eHostCoherent: return \"HostCoherent\";\n    case MemoryPropertyFlagBits::eHostCached: return \"HostCached\";\n    case MemoryPropertyFlagBits::eLazilyAllocated: return \"LazilyAllocated\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(MemoryPropertyFlags value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & MemoryPropertyFlagBits::eDeviceLocal) result += \"DeviceLocal | \";\n    if (value & MemoryPropertyFlagBits::eHostVisible) result += \"HostVisible | \";\n    if (value & MemoryPropertyFlagBits::eHostCoherent) result += \"HostCoherent | \";\n    if (value & MemoryPropertyFlagBits::eHostCached) result += \"HostCached | \";\n    if (value & MemoryPropertyFlagBits::eLazilyAllocated) result += \"LazilyAllocated | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(MemoryHeapFlagBits value)\n  {\n    switch (value)\n    {\n    case MemoryHeapFlagBits::eDeviceLocal: return \"DeviceLocal\";\n    case MemoryHeapFlagBits::eMultiInstanceKHX: return \"MultiInstanceKHX\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(MemoryHeapFlags value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & MemoryHeapFlagBits::eDeviceLocal) result += \"DeviceLocal | \";\n    if (value & MemoryHeapFlagBits::eMultiInstanceKHX) result += \"MultiInstanceKHX | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(AccessFlagBits value)\n  {\n    switch (value)\n    {\n    case AccessFlagBits::eIndirectCommandRead: return \"IndirectCommandRead\";\n    case AccessFlagBits::eIndexRead: return \"IndexRead\";\n    case AccessFlagBits::eVertexAttributeRead: return \"VertexAttributeRead\";\n    case AccessFlagBits::eUniformRead: return \"UniformRead\";\n    case AccessFlagBits::eInputAttachmentRead: return \"InputAttachmentRead\";\n    case AccessFlagBits::eShaderRead: return \"ShaderRead\";\n    case AccessFlagBits::eShaderWrite: return \"ShaderWrite\";\n    case AccessFlagBits::eColorAttachmentRead: return \"ColorAttachmentRead\";\n    case AccessFlagBits::eColorAttachmentWrite: return \"ColorAttachmentWrite\";\n    case AccessFlagBits::eDepthStencilAttachmentRead: return \"DepthStencilAttachmentRead\";\n    case AccessFlagBits::eDepthStencilAttachmentWrite: return \"DepthStencilAttachmentWrite\";\n    case AccessFlagBits::eTransferRead: return \"TransferRead\";\n    case AccessFlagBits::eTransferWrite: return \"TransferWrite\";\n    case AccessFlagBits::eHostRead: return \"HostRead\";\n    case AccessFlagBits::eHostWrite: return \"HostWrite\";\n    case AccessFlagBits::eMemoryRead: return \"MemoryRead\";\n    case AccessFlagBits::eMemoryWrite: return \"MemoryWrite\";\n    case AccessFlagBits::eCommandProcessReadNVX: return \"CommandProcessReadNVX\";\n    case AccessFlagBits::eCommandProcessWriteNVX: return \"CommandProcessWriteNVX\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(AccessFlags value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & AccessFlagBits::eIndirectCommandRead) result += \"IndirectCommandRead | \";\n    if (value & AccessFlagBits::eIndexRead) result += \"IndexRead | \";\n    if (value & AccessFlagBits::eVertexAttributeRead) result += \"VertexAttributeRead | \";\n    if (value & AccessFlagBits::eUniformRead) result += \"UniformRead | \";\n    if (value & AccessFlagBits::eInputAttachmentRead) result += \"InputAttachmentRead | \";\n    if (value & AccessFlagBits::eShaderRead) result += \"ShaderRead | \";\n    if (value & AccessFlagBits::eShaderWrite) result += \"ShaderWrite | \";\n    if (value & AccessFlagBits::eColorAttachmentRead) result += \"ColorAttachmentRead | \";\n    if (value & AccessFlagBits::eColorAttachmentWrite) result += \"ColorAttachmentWrite | \";\n    if (value & AccessFlagBits::eDepthStencilAttachmentRead) result += \"DepthStencilAttachmentRead | \";\n    if (value & AccessFlagBits::eDepthStencilAttachmentWrite) result += \"DepthStencilAttachmentWrite | \";\n    if (value & AccessFlagBits::eTransferRead) result += \"TransferRead | \";\n    if (value & AccessFlagBits::eTransferWrite) result += \"TransferWrite | \";\n    if (value & AccessFlagBits::eHostRead) result += \"HostRead | \";\n    if (value & AccessFlagBits::eHostWrite) result += \"HostWrite | \";\n    if (value & AccessFlagBits::eMemoryRead) result += \"MemoryRead | \";\n    if (value & AccessFlagBits::eMemoryWrite) result += \"MemoryWrite | \";\n    if (value & AccessFlagBits::eCommandProcessReadNVX) result += \"CommandProcessReadNVX | \";\n    if (value & AccessFlagBits::eCommandProcessWriteNVX) result += \"CommandProcessWriteNVX | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(BufferUsageFlagBits value)\n  {\n    switch (value)\n    {\n    case BufferUsageFlagBits::eTransferSrc: return \"TransferSrc\";\n    case BufferUsageFlagBits::eTransferDst: return \"TransferDst\";\n    case BufferUsageFlagBits::eUniformTexelBuffer: return \"UniformTexelBuffer\";\n    case BufferUsageFlagBits::eStorageTexelBuffer: return \"StorageTexelBuffer\";\n    case BufferUsageFlagBits::eUniformBuffer: return \"UniformBuffer\";\n    case BufferUsageFlagBits::eStorageBuffer: return \"StorageBuffer\";\n    case BufferUsageFlagBits::eIndexBuffer: return \"IndexBuffer\";\n    case BufferUsageFlagBits::eVertexBuffer: return \"VertexBuffer\";\n    case BufferUsageFlagBits::eIndirectBuffer: return \"IndirectBuffer\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(BufferUsageFlags value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & BufferUsageFlagBits::eTransferSrc) result += \"TransferSrc | \";\n    if (value & BufferUsageFlagBits::eTransferDst) result += \"TransferDst | \";\n    if (value & BufferUsageFlagBits::eUniformTexelBuffer) result += \"UniformTexelBuffer | \";\n    if (value & BufferUsageFlagBits::eStorageTexelBuffer) result += \"StorageTexelBuffer | \";\n    if (value & BufferUsageFlagBits::eUniformBuffer) result += \"UniformBuffer | \";\n    if (value & BufferUsageFlagBits::eStorageBuffer) result += \"StorageBuffer | \";\n    if (value & BufferUsageFlagBits::eIndexBuffer) result += \"IndexBuffer | \";\n    if (value & BufferUsageFlagBits::eVertexBuffer) result += \"VertexBuffer | \";\n    if (value & BufferUsageFlagBits::eIndirectBuffer) result += \"IndirectBuffer | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(BufferCreateFlagBits value)\n  {\n    switch (value)\n    {\n    case BufferCreateFlagBits::eSparseBinding: return \"SparseBinding\";\n    case BufferCreateFlagBits::eSparseResidency: return \"SparseResidency\";\n    case BufferCreateFlagBits::eSparseAliased: return \"SparseAliased\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(BufferCreateFlags value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & BufferCreateFlagBits::eSparseBinding) result += \"SparseBinding | \";\n    if (value & BufferCreateFlagBits::eSparseResidency) result += \"SparseResidency | \";\n    if (value & BufferCreateFlagBits::eSparseAliased) result += \"SparseAliased | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(ShaderStageFlagBits value)\n  {\n    switch (value)\n    {\n    case ShaderStageFlagBits::eVertex: return \"Vertex\";\n    case ShaderStageFlagBits::eTessellationControl: return \"TessellationControl\";\n    case ShaderStageFlagBits::eTessellationEvaluation: return \"TessellationEvaluation\";\n    case ShaderStageFlagBits::eGeometry: return \"Geometry\";\n    case ShaderStageFlagBits::eFragment: return \"Fragment\";\n    case ShaderStageFlagBits::eCompute: return \"Compute\";\n    case ShaderStageFlagBits::eAllGraphics: return \"AllGraphics\";\n    case ShaderStageFlagBits::eAll: return \"All\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(ShaderStageFlags value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & ShaderStageFlagBits::eVertex) result += \"Vertex | \";\n    if (value & ShaderStageFlagBits::eTessellationControl) result += \"TessellationControl | \";\n    if (value & ShaderStageFlagBits::eTessellationEvaluation) result += \"TessellationEvaluation | \";\n    if (value & ShaderStageFlagBits::eGeometry) result += \"Geometry | \";\n    if (value & ShaderStageFlagBits::eFragment) result += \"Fragment | \";\n    if (value & ShaderStageFlagBits::eCompute) result += \"Compute | \";\n    if (value & ShaderStageFlagBits::eAllGraphics) result += \"AllGraphics | \";\n    if (value & ShaderStageFlagBits::eAll) result += \"All | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(ImageUsageFlagBits value)\n  {\n    switch (value)\n    {\n    case ImageUsageFlagBits::eTransferSrc: return \"TransferSrc\";\n    case ImageUsageFlagBits::eTransferDst: return \"TransferDst\";\n    case ImageUsageFlagBits::eSampled: return \"Sampled\";\n    case ImageUsageFlagBits::eStorage: return \"Storage\";\n    case ImageUsageFlagBits::eColorAttachment: return \"ColorAttachment\";\n    case ImageUsageFlagBits::eDepthStencilAttachment: return \"DepthStencilAttachment\";\n    case ImageUsageFlagBits::eTransientAttachment: return \"TransientAttachment\";\n    case ImageUsageFlagBits::eInputAttachment: return \"InputAttachment\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(ImageUsageFlags value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & ImageUsageFlagBits::eTransferSrc) result += \"TransferSrc | \";\n    if (value & ImageUsageFlagBits::eTransferDst) result += \"TransferDst | \";\n    if (value & ImageUsageFlagBits::eSampled) result += \"Sampled | \";\n    if (value & ImageUsageFlagBits::eStorage) result += \"Storage | \";\n    if (value & ImageUsageFlagBits::eColorAttachment) result += \"ColorAttachment | \";\n    if (value & ImageUsageFlagBits::eDepthStencilAttachment) result += \"DepthStencilAttachment | \";\n    if (value & ImageUsageFlagBits::eTransientAttachment) result += \"TransientAttachment | \";\n    if (value & ImageUsageFlagBits::eInputAttachment) result += \"InputAttachment | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(ImageCreateFlagBits value)\n  {\n    switch (value)\n    {\n    case ImageCreateFlagBits::eSparseBinding: return \"SparseBinding\";\n    case ImageCreateFlagBits::eSparseResidency: return \"SparseResidency\";\n    case ImageCreateFlagBits::eSparseAliased: return \"SparseAliased\";\n    case ImageCreateFlagBits::eMutableFormat: return \"MutableFormat\";\n    case ImageCreateFlagBits::eCubeCompatible: return \"CubeCompatible\";\n    case ImageCreateFlagBits::eBindSfrKHX: return \"BindSfrKHX\";\n    case ImageCreateFlagBits::e2DArrayCompatibleKHR: return \"2DArrayCompatibleKHR\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(ImageCreateFlags value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & ImageCreateFlagBits::eSparseBinding) result += \"SparseBinding | \";\n    if (value & ImageCreateFlagBits::eSparseResidency) result += \"SparseResidency | \";\n    if (value & ImageCreateFlagBits::eSparseAliased) result += \"SparseAliased | \";\n    if (value & ImageCreateFlagBits::eMutableFormat) result += \"MutableFormat | \";\n    if (value & ImageCreateFlagBits::eCubeCompatible) result += \"CubeCompatible | \";\n    if (value & ImageCreateFlagBits::eBindSfrKHX) result += \"BindSfrKHX | \";\n    if (value & ImageCreateFlagBits::e2DArrayCompatibleKHR) result += \"2DArrayCompatibleKHR | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(PipelineCreateFlagBits value)\n  {\n    switch (value)\n    {\n    case PipelineCreateFlagBits::eDisableOptimization: return \"DisableOptimization\";\n    case PipelineCreateFlagBits::eAllowDerivatives: return \"AllowDerivatives\";\n    case PipelineCreateFlagBits::eDerivative: return \"Derivative\";\n    case PipelineCreateFlagBits::eViewIndexFromDeviceIndexKHX: return \"ViewIndexFromDeviceIndexKHX\";\n    case PipelineCreateFlagBits::eDispatchBaseKHX: return \"DispatchBaseKHX\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(PipelineCreateFlags value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & PipelineCreateFlagBits::eDisableOptimization) result += \"DisableOptimization | \";\n    if (value & PipelineCreateFlagBits::eAllowDerivatives) result += \"AllowDerivatives | \";\n    if (value & PipelineCreateFlagBits::eDerivative) result += \"Derivative | \";\n    if (value & PipelineCreateFlagBits::eViewIndexFromDeviceIndexKHX) result += \"ViewIndexFromDeviceIndexKHX | \";\n    if (value & PipelineCreateFlagBits::eDispatchBaseKHX) result += \"DispatchBaseKHX | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(ColorComponentFlagBits value)\n  {\n    switch (value)\n    {\n    case ColorComponentFlagBits::eR: return \"R\";\n    case ColorComponentFlagBits::eG: return \"G\";\n    case ColorComponentFlagBits::eB: return \"B\";\n    case ColorComponentFlagBits::eA: return \"A\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(ColorComponentFlags value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & ColorComponentFlagBits::eR) result += \"R | \";\n    if (value & ColorComponentFlagBits::eG) result += \"G | \";\n    if (value & ColorComponentFlagBits::eB) result += \"B | \";\n    if (value & ColorComponentFlagBits::eA) result += \"A | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(FenceCreateFlagBits value)\n  {\n    switch (value)\n    {\n    case FenceCreateFlagBits::eSignaled: return \"Signaled\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(FenceCreateFlags value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & FenceCreateFlagBits::eSignaled) result += \"Signaled | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(FormatFeatureFlagBits value)\n  {\n    switch (value)\n    {\n    case FormatFeatureFlagBits::eSampledImage: return \"SampledImage\";\n    case FormatFeatureFlagBits::eStorageImage: return \"StorageImage\";\n    case FormatFeatureFlagBits::eStorageImageAtomic: return \"StorageImageAtomic\";\n    case FormatFeatureFlagBits::eUniformTexelBuffer: return \"UniformTexelBuffer\";\n    case FormatFeatureFlagBits::eStorageTexelBuffer: return \"StorageTexelBuffer\";\n    case FormatFeatureFlagBits::eStorageTexelBufferAtomic: return \"StorageTexelBufferAtomic\";\n    case FormatFeatureFlagBits::eVertexBuffer: return \"VertexBuffer\";\n    case FormatFeatureFlagBits::eColorAttachment: return \"ColorAttachment\";\n    case FormatFeatureFlagBits::eColorAttachmentBlend: return \"ColorAttachmentBlend\";\n    case FormatFeatureFlagBits::eDepthStencilAttachment: return \"DepthStencilAttachment\";\n    case FormatFeatureFlagBits::eBlitSrc: return \"BlitSrc\";\n    case FormatFeatureFlagBits::eBlitDst: return \"BlitDst\";\n    case FormatFeatureFlagBits::eSampledImageFilterLinear: return \"SampledImageFilterLinear\";\n    case FormatFeatureFlagBits::eSampledImageFilterCubicIMG: return \"SampledImageFilterCubicIMG\";\n    case FormatFeatureFlagBits::eTransferSrcKHR: return \"TransferSrcKHR\";\n    case FormatFeatureFlagBits::eTransferDstKHR: return \"TransferDstKHR\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(FormatFeatureFlags value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & FormatFeatureFlagBits::eSampledImage) result += \"SampledImage | \";\n    if (value & FormatFeatureFlagBits::eStorageImage) result += \"StorageImage | \";\n    if (value & FormatFeatureFlagBits::eStorageImageAtomic) result += \"StorageImageAtomic | \";\n    if (value & FormatFeatureFlagBits::eUniformTexelBuffer) result += \"UniformTexelBuffer | \";\n    if (value & FormatFeatureFlagBits::eStorageTexelBuffer) result += \"StorageTexelBuffer | \";\n    if (value & FormatFeatureFlagBits::eStorageTexelBufferAtomic) result += \"StorageTexelBufferAtomic | \";\n    if (value & FormatFeatureFlagBits::eVertexBuffer) result += \"VertexBuffer | \";\n    if (value & FormatFeatureFlagBits::eColorAttachment) result += \"ColorAttachment | \";\n    if (value & FormatFeatureFlagBits::eColorAttachmentBlend) result += \"ColorAttachmentBlend | \";\n    if (value & FormatFeatureFlagBits::eDepthStencilAttachment) result += \"DepthStencilAttachment | \";\n    if (value & FormatFeatureFlagBits::eBlitSrc) result += \"BlitSrc | \";\n    if (value & FormatFeatureFlagBits::eBlitDst) result += \"BlitDst | \";\n    if (value & FormatFeatureFlagBits::eSampledImageFilterLinear) result += \"SampledImageFilterLinear | \";\n    if (value & FormatFeatureFlagBits::eSampledImageFilterCubicIMG) result += \"SampledImageFilterCubicIMG | \";\n    if (value & FormatFeatureFlagBits::eTransferSrcKHR) result += \"TransferSrcKHR | \";\n    if (value & FormatFeatureFlagBits::eTransferDstKHR) result += \"TransferDstKHR | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(QueryControlFlagBits value)\n  {\n    switch (value)\n    {\n    case QueryControlFlagBits::ePrecise: return \"Precise\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(QueryControlFlags value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & QueryControlFlagBits::ePrecise) result += \"Precise | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(QueryResultFlagBits value)\n  {\n    switch (value)\n    {\n    case QueryResultFlagBits::e64: return \"64\";\n    case QueryResultFlagBits::eWait: return \"Wait\";\n    case QueryResultFlagBits::eWithAvailability: return \"WithAvailability\";\n    case QueryResultFlagBits::ePartial: return \"Partial\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(QueryResultFlags value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & QueryResultFlagBits::e64) result += \"64 | \";\n    if (value & QueryResultFlagBits::eWait) result += \"Wait | \";\n    if (value & QueryResultFlagBits::eWithAvailability) result += \"WithAvailability | \";\n    if (value & QueryResultFlagBits::ePartial) result += \"Partial | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(CommandBufferUsageFlagBits value)\n  {\n    switch (value)\n    {\n    case CommandBufferUsageFlagBits::eOneTimeSubmit: return \"OneTimeSubmit\";\n    case CommandBufferUsageFlagBits::eRenderPassContinue: return \"RenderPassContinue\";\n    case CommandBufferUsageFlagBits::eSimultaneousUse: return \"SimultaneousUse\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(CommandBufferUsageFlags value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & CommandBufferUsageFlagBits::eOneTimeSubmit) result += \"OneTimeSubmit | \";\n    if (value & CommandBufferUsageFlagBits::eRenderPassContinue) result += \"RenderPassContinue | \";\n    if (value & CommandBufferUsageFlagBits::eSimultaneousUse) result += \"SimultaneousUse | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(QueryPipelineStatisticFlagBits value)\n  {\n    switch (value)\n    {\n    case QueryPipelineStatisticFlagBits::eInputAssemblyVertices: return \"InputAssemblyVertices\";\n    case QueryPipelineStatisticFlagBits::eInputAssemblyPrimitives: return \"InputAssemblyPrimitives\";\n    case QueryPipelineStatisticFlagBits::eVertexShaderInvocations: return \"VertexShaderInvocations\";\n    case QueryPipelineStatisticFlagBits::eGeometryShaderInvocations: return \"GeometryShaderInvocations\";\n    case QueryPipelineStatisticFlagBits::eGeometryShaderPrimitives: return \"GeometryShaderPrimitives\";\n    case QueryPipelineStatisticFlagBits::eClippingInvocations: return \"ClippingInvocations\";\n    case QueryPipelineStatisticFlagBits::eClippingPrimitives: return \"ClippingPrimitives\";\n    case QueryPipelineStatisticFlagBits::eFragmentShaderInvocations: return \"FragmentShaderInvocations\";\n    case QueryPipelineStatisticFlagBits::eTessellationControlShaderPatches: return \"TessellationControlShaderPatches\";\n    case QueryPipelineStatisticFlagBits::eTessellationEvaluationShaderInvocations: return \"TessellationEvaluationShaderInvocations\";\n    case QueryPipelineStatisticFlagBits::eComputeShaderInvocations: return \"ComputeShaderInvocations\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(QueryPipelineStatisticFlags value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & QueryPipelineStatisticFlagBits::eInputAssemblyVertices) result += \"InputAssemblyVertices | \";\n    if (value & QueryPipelineStatisticFlagBits::eInputAssemblyPrimitives) result += \"InputAssemblyPrimitives | \";\n    if (value & QueryPipelineStatisticFlagBits::eVertexShaderInvocations) result += \"VertexShaderInvocations | \";\n    if (value & QueryPipelineStatisticFlagBits::eGeometryShaderInvocations) result += \"GeometryShaderInvocations | \";\n    if (value & QueryPipelineStatisticFlagBits::eGeometryShaderPrimitives) result += \"GeometryShaderPrimitives | \";\n    if (value & QueryPipelineStatisticFlagBits::eClippingInvocations) result += \"ClippingInvocations | \";\n    if (value & QueryPipelineStatisticFlagBits::eClippingPrimitives) result += \"ClippingPrimitives | \";\n    if (value & QueryPipelineStatisticFlagBits::eFragmentShaderInvocations) result += \"FragmentShaderInvocations | \";\n    if (value & QueryPipelineStatisticFlagBits::eTessellationControlShaderPatches) result += \"TessellationControlShaderPatches | \";\n    if (value & QueryPipelineStatisticFlagBits::eTessellationEvaluationShaderInvocations) result += \"TessellationEvaluationShaderInvocations | \";\n    if (value & QueryPipelineStatisticFlagBits::eComputeShaderInvocations) result += \"ComputeShaderInvocations | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(ImageAspectFlagBits value)\n  {\n    switch (value)\n    {\n    case ImageAspectFlagBits::eColor: return \"Color\";\n    case ImageAspectFlagBits::eDepth: return \"Depth\";\n    case ImageAspectFlagBits::eStencil: return \"Stencil\";\n    case ImageAspectFlagBits::eMetadata: return \"Metadata\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(ImageAspectFlags value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & ImageAspectFlagBits::eColor) result += \"Color | \";\n    if (value & ImageAspectFlagBits::eDepth) result += \"Depth | \";\n    if (value & ImageAspectFlagBits::eStencil) result += \"Stencil | \";\n    if (value & ImageAspectFlagBits::eMetadata) result += \"Metadata | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(SparseImageFormatFlagBits value)\n  {\n    switch (value)\n    {\n    case SparseImageFormatFlagBits::eSingleMiptail: return \"SingleMiptail\";\n    case SparseImageFormatFlagBits::eAlignedMipSize: return \"AlignedMipSize\";\n    case SparseImageFormatFlagBits::eNonstandardBlockSize: return \"NonstandardBlockSize\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(SparseImageFormatFlags value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & SparseImageFormatFlagBits::eSingleMiptail) result += \"SingleMiptail | \";\n    if (value & SparseImageFormatFlagBits::eAlignedMipSize) result += \"AlignedMipSize | \";\n    if (value & SparseImageFormatFlagBits::eNonstandardBlockSize) result += \"NonstandardBlockSize | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(SparseMemoryBindFlagBits value)\n  {\n    switch (value)\n    {\n    case SparseMemoryBindFlagBits::eMetadata: return \"Metadata\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(SparseMemoryBindFlags value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & SparseMemoryBindFlagBits::eMetadata) result += \"Metadata | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(PipelineStageFlagBits value)\n  {\n    switch (value)\n    {\n    case PipelineStageFlagBits::eTopOfPipe: return \"TopOfPipe\";\n    case PipelineStageFlagBits::eDrawIndirect: return \"DrawIndirect\";\n    case PipelineStageFlagBits::eVertexInput: return \"VertexInput\";\n    case PipelineStageFlagBits::eVertexShader: return \"VertexShader\";\n    case PipelineStageFlagBits::eTessellationControlShader: return \"TessellationControlShader\";\n    case PipelineStageFlagBits::eTessellationEvaluationShader: return \"TessellationEvaluationShader\";\n    case PipelineStageFlagBits::eGeometryShader: return \"GeometryShader\";\n    case PipelineStageFlagBits::eFragmentShader: return \"FragmentShader\";\n    case PipelineStageFlagBits::eEarlyFragmentTests: return \"EarlyFragmentTests\";\n    case PipelineStageFlagBits::eLateFragmentTests: return \"LateFragmentTests\";\n    case PipelineStageFlagBits::eColorAttachmentOutput: return \"ColorAttachmentOutput\";\n    case PipelineStageFlagBits::eComputeShader: return \"ComputeShader\";\n    case PipelineStageFlagBits::eTransfer: return \"Transfer\";\n    case PipelineStageFlagBits::eBottomOfPipe: return \"BottomOfPipe\";\n    case PipelineStageFlagBits::eHost: return \"Host\";\n    case PipelineStageFlagBits::eAllGraphics: return \"AllGraphics\";\n    case PipelineStageFlagBits::eAllCommands: return \"AllCommands\";\n    case PipelineStageFlagBits::eCommandProcessNVX: return \"CommandProcessNVX\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(PipelineStageFlags value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & PipelineStageFlagBits::eTopOfPipe) result += \"TopOfPipe | \";\n    if (value & PipelineStageFlagBits::eDrawIndirect) result += \"DrawIndirect | \";\n    if (value & PipelineStageFlagBits::eVertexInput) result += \"VertexInput | \";\n    if (value & PipelineStageFlagBits::eVertexShader) result += \"VertexShader | \";\n    if (value & PipelineStageFlagBits::eTessellationControlShader) result += \"TessellationControlShader | \";\n    if (value & PipelineStageFlagBits::eTessellationEvaluationShader) result += \"TessellationEvaluationShader | \";\n    if (value & PipelineStageFlagBits::eGeometryShader) result += \"GeometryShader | \";\n    if (value & PipelineStageFlagBits::eFragmentShader) result += \"FragmentShader | \";\n    if (value & PipelineStageFlagBits::eEarlyFragmentTests) result += \"EarlyFragmentTests | \";\n    if (value & PipelineStageFlagBits::eLateFragmentTests) result += \"LateFragmentTests | \";\n    if (value & PipelineStageFlagBits::eColorAttachmentOutput) result += \"ColorAttachmentOutput | \";\n    if (value & PipelineStageFlagBits::eComputeShader) result += \"ComputeShader | \";\n    if (value & PipelineStageFlagBits::eTransfer) result += \"Transfer | \";\n    if (value & PipelineStageFlagBits::eBottomOfPipe) result += \"BottomOfPipe | \";\n    if (value & PipelineStageFlagBits::eHost) result += \"Host | \";\n    if (value & PipelineStageFlagBits::eAllGraphics) result += \"AllGraphics | \";\n    if (value & PipelineStageFlagBits::eAllCommands) result += \"AllCommands | \";\n    if (value & PipelineStageFlagBits::eCommandProcessNVX) result += \"CommandProcessNVX | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(CommandPoolCreateFlagBits value)\n  {\n    switch (value)\n    {\n    case CommandPoolCreateFlagBits::eTransient: return \"Transient\";\n    case CommandPoolCreateFlagBits::eResetCommandBuffer: return \"ResetCommandBuffer\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(CommandPoolCreateFlags value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & CommandPoolCreateFlagBits::eTransient) result += \"Transient | \";\n    if (value & CommandPoolCreateFlagBits::eResetCommandBuffer) result += \"ResetCommandBuffer | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(CommandPoolResetFlagBits value)\n  {\n    switch (value)\n    {\n    case CommandPoolResetFlagBits::eReleaseResources: return \"ReleaseResources\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(CommandPoolResetFlags value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & CommandPoolResetFlagBits::eReleaseResources) result += \"ReleaseResources | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(CommandBufferResetFlagBits value)\n  {\n    switch (value)\n    {\n    case CommandBufferResetFlagBits::eReleaseResources: return \"ReleaseResources\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(CommandBufferResetFlags value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & CommandBufferResetFlagBits::eReleaseResources) result += \"ReleaseResources | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(SampleCountFlagBits value)\n  {\n    switch (value)\n    {\n    case SampleCountFlagBits::e1: return \"1\";\n    case SampleCountFlagBits::e2: return \"2\";\n    case SampleCountFlagBits::e4: return \"4\";\n    case SampleCountFlagBits::e8: return \"8\";\n    case SampleCountFlagBits::e16: return \"16\";\n    case SampleCountFlagBits::e32: return \"32\";\n    case SampleCountFlagBits::e64: return \"64\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(SampleCountFlags value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & SampleCountFlagBits::e1) result += \"1 | \";\n    if (value & SampleCountFlagBits::e2) result += \"2 | \";\n    if (value & SampleCountFlagBits::e4) result += \"4 | \";\n    if (value & SampleCountFlagBits::e8) result += \"8 | \";\n    if (value & SampleCountFlagBits::e16) result += \"16 | \";\n    if (value & SampleCountFlagBits::e32) result += \"32 | \";\n    if (value & SampleCountFlagBits::e64) result += \"64 | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(AttachmentDescriptionFlagBits value)\n  {\n    switch (value)\n    {\n    case AttachmentDescriptionFlagBits::eMayAlias: return \"MayAlias\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(AttachmentDescriptionFlags value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & AttachmentDescriptionFlagBits::eMayAlias) result += \"MayAlias | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(StencilFaceFlagBits value)\n  {\n    switch (value)\n    {\n    case StencilFaceFlagBits::eFront: return \"Front\";\n    case StencilFaceFlagBits::eBack: return \"Back\";\n    case StencilFaceFlagBits::eVkStencilFrontAndBack: return \"VkStencilFrontAndBack\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(StencilFaceFlags value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & StencilFaceFlagBits::eFront) result += \"Front | \";\n    if (value & StencilFaceFlagBits::eBack) result += \"Back | \";\n    if (value & StencilFaceFlagBits::eVkStencilFrontAndBack) result += \"VkStencilFrontAndBack | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(DescriptorPoolCreateFlagBits value)\n  {\n    switch (value)\n    {\n    case DescriptorPoolCreateFlagBits::eFreeDescriptorSet: return \"FreeDescriptorSet\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(DescriptorPoolCreateFlags value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & DescriptorPoolCreateFlagBits::eFreeDescriptorSet) result += \"FreeDescriptorSet | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(DependencyFlagBits value)\n  {\n    switch (value)\n    {\n    case DependencyFlagBits::eByRegion: return \"ByRegion\";\n    case DependencyFlagBits::eViewLocalKHX: return \"ViewLocalKHX\";\n    case DependencyFlagBits::eDeviceGroupKHX: return \"DeviceGroupKHX\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(DependencyFlags value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & DependencyFlagBits::eByRegion) result += \"ByRegion | \";\n    if (value & DependencyFlagBits::eViewLocalKHX) result += \"ViewLocalKHX | \";\n    if (value & DependencyFlagBits::eDeviceGroupKHX) result += \"DeviceGroupKHX | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(PresentModeKHR value)\n  {\n    switch (value)\n    {\n    case PresentModeKHR::eImmediate: return \"Immediate\";\n    case PresentModeKHR::eMailbox: return \"Mailbox\";\n    case PresentModeKHR::eFifo: return \"Fifo\";\n    case PresentModeKHR::eFifoRelaxed: return \"FifoRelaxed\";\n    case PresentModeKHR::eSharedDemandRefresh: return \"SharedDemandRefresh\";\n    case PresentModeKHR::eSharedContinuousRefresh: return \"SharedContinuousRefresh\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(ColorSpaceKHR value)\n  {\n    switch (value)\n    {\n    case ColorSpaceKHR::eSrgbNonlinear: return \"SrgbNonlinear\";\n    case ColorSpaceKHR::eDisplayP3NonlinearEXT: return \"DisplayP3NonlinearEXT\";\n    case ColorSpaceKHR::eExtendedSrgbLinearEXT: return \"ExtendedSrgbLinearEXT\";\n    case ColorSpaceKHR::eDciP3LinearEXT: return \"DciP3LinearEXT\";\n    case ColorSpaceKHR::eDciP3NonlinearEXT: return \"DciP3NonlinearEXT\";\n    case ColorSpaceKHR::eBt709LinearEXT: return \"Bt709LinearEXT\";\n    case ColorSpaceKHR::eBt709NonlinearEXT: return \"Bt709NonlinearEXT\";\n    case ColorSpaceKHR::eBt2020LinearEXT: return \"Bt2020LinearEXT\";\n    case ColorSpaceKHR::eHdr10St2084EXT: return \"Hdr10St2084EXT\";\n    case ColorSpaceKHR::eDolbyvisionEXT: return \"DolbyvisionEXT\";\n    case ColorSpaceKHR::eHdr10HlgEXT: return \"Hdr10HlgEXT\";\n    case ColorSpaceKHR::eAdobergbLinearEXT: return \"AdobergbLinearEXT\";\n    case ColorSpaceKHR::eAdobergbNonlinearEXT: return \"AdobergbNonlinearEXT\";\n    case ColorSpaceKHR::ePassThroughEXT: return \"PassThroughEXT\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(DisplayPlaneAlphaFlagBitsKHR value)\n  {\n    switch (value)\n    {\n    case DisplayPlaneAlphaFlagBitsKHR::eOpaque: return \"Opaque\";\n    case DisplayPlaneAlphaFlagBitsKHR::eGlobal: return \"Global\";\n    case DisplayPlaneAlphaFlagBitsKHR::ePerPixel: return \"PerPixel\";\n    case DisplayPlaneAlphaFlagBitsKHR::ePerPixelPremultiplied: return \"PerPixelPremultiplied\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(DisplayPlaneAlphaFlagsKHR value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & DisplayPlaneAlphaFlagBitsKHR::eOpaque) result += \"Opaque | \";\n    if (value & DisplayPlaneAlphaFlagBitsKHR::eGlobal) result += \"Global | \";\n    if (value & DisplayPlaneAlphaFlagBitsKHR::ePerPixel) result += \"PerPixel | \";\n    if (value & DisplayPlaneAlphaFlagBitsKHR::ePerPixelPremultiplied) result += \"PerPixelPremultiplied | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(CompositeAlphaFlagBitsKHR value)\n  {\n    switch (value)\n    {\n    case CompositeAlphaFlagBitsKHR::eOpaque: return \"Opaque\";\n    case CompositeAlphaFlagBitsKHR::ePreMultiplied: return \"PreMultiplied\";\n    case CompositeAlphaFlagBitsKHR::ePostMultiplied: return \"PostMultiplied\";\n    case CompositeAlphaFlagBitsKHR::eInherit: return \"Inherit\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(CompositeAlphaFlagsKHR value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & CompositeAlphaFlagBitsKHR::eOpaque) result += \"Opaque | \";\n    if (value & CompositeAlphaFlagBitsKHR::ePreMultiplied) result += \"PreMultiplied | \";\n    if (value & CompositeAlphaFlagBitsKHR::ePostMultiplied) result += \"PostMultiplied | \";\n    if (value & CompositeAlphaFlagBitsKHR::eInherit) result += \"Inherit | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(SurfaceTransformFlagBitsKHR value)\n  {\n    switch (value)\n    {\n    case SurfaceTransformFlagBitsKHR::eIdentity: return \"Identity\";\n    case SurfaceTransformFlagBitsKHR::eRotate90: return \"Rotate90\";\n    case SurfaceTransformFlagBitsKHR::eRotate180: return \"Rotate180\";\n    case SurfaceTransformFlagBitsKHR::eRotate270: return \"Rotate270\";\n    case SurfaceTransformFlagBitsKHR::eHorizontalMirror: return \"HorizontalMirror\";\n    case SurfaceTransformFlagBitsKHR::eHorizontalMirrorRotate90: return \"HorizontalMirrorRotate90\";\n    case SurfaceTransformFlagBitsKHR::eHorizontalMirrorRotate180: return \"HorizontalMirrorRotate180\";\n    case SurfaceTransformFlagBitsKHR::eHorizontalMirrorRotate270: return \"HorizontalMirrorRotate270\";\n    case SurfaceTransformFlagBitsKHR::eInherit: return \"Inherit\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(SurfaceTransformFlagsKHR value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & SurfaceTransformFlagBitsKHR::eIdentity) result += \"Identity | \";\n    if (value & SurfaceTransformFlagBitsKHR::eRotate90) result += \"Rotate90 | \";\n    if (value & SurfaceTransformFlagBitsKHR::eRotate180) result += \"Rotate180 | \";\n    if (value & SurfaceTransformFlagBitsKHR::eRotate270) result += \"Rotate270 | \";\n    if (value & SurfaceTransformFlagBitsKHR::eHorizontalMirror) result += \"HorizontalMirror | \";\n    if (value & SurfaceTransformFlagBitsKHR::eHorizontalMirrorRotate90) result += \"HorizontalMirrorRotate90 | \";\n    if (value & SurfaceTransformFlagBitsKHR::eHorizontalMirrorRotate180) result += \"HorizontalMirrorRotate180 | \";\n    if (value & SurfaceTransformFlagBitsKHR::eHorizontalMirrorRotate270) result += \"HorizontalMirrorRotate270 | \";\n    if (value & SurfaceTransformFlagBitsKHR::eInherit) result += \"Inherit | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(DebugReportFlagBitsEXT value)\n  {\n    switch (value)\n    {\n    case DebugReportFlagBitsEXT::eInformation: return \"Information\";\n    case DebugReportFlagBitsEXT::eWarning: return \"Warning\";\n    case DebugReportFlagBitsEXT::ePerformanceWarning: return \"PerformanceWarning\";\n    case DebugReportFlagBitsEXT::eError: return \"Error\";\n    case DebugReportFlagBitsEXT::eDebug: return \"Debug\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(DebugReportFlagsEXT value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & DebugReportFlagBitsEXT::eInformation) result += \"Information | \";\n    if (value & DebugReportFlagBitsEXT::eWarning) result += \"Warning | \";\n    if (value & DebugReportFlagBitsEXT::ePerformanceWarning) result += \"PerformanceWarning | \";\n    if (value & DebugReportFlagBitsEXT::eError) result += \"Error | \";\n    if (value & DebugReportFlagBitsEXT::eDebug) result += \"Debug | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(DebugReportObjectTypeEXT value)\n  {\n    switch (value)\n    {\n    case DebugReportObjectTypeEXT::eUnknown: return \"Unknown\";\n    case DebugReportObjectTypeEXT::eInstance: return \"Instance\";\n    case DebugReportObjectTypeEXT::ePhysicalDevice: return \"PhysicalDevice\";\n    case DebugReportObjectTypeEXT::eDevice: return \"Device\";\n    case DebugReportObjectTypeEXT::eQueue: return \"Queue\";\n    case DebugReportObjectTypeEXT::eSemaphore: return \"Semaphore\";\n    case DebugReportObjectTypeEXT::eCommandBuffer: return \"CommandBuffer\";\n    case DebugReportObjectTypeEXT::eFence: return \"Fence\";\n    case DebugReportObjectTypeEXT::eDeviceMemory: return \"DeviceMemory\";\n    case DebugReportObjectTypeEXT::eBuffer: return \"Buffer\";\n    case DebugReportObjectTypeEXT::eImage: return \"Image\";\n    case DebugReportObjectTypeEXT::eEvent: return \"Event\";\n    case DebugReportObjectTypeEXT::eQueryPool: return \"QueryPool\";\n    case DebugReportObjectTypeEXT::eBufferView: return \"BufferView\";\n    case DebugReportObjectTypeEXT::eImageView: return \"ImageView\";\n    case DebugReportObjectTypeEXT::eShaderModule: return \"ShaderModule\";\n    case DebugReportObjectTypeEXT::ePipelineCache: return \"PipelineCache\";\n    case DebugReportObjectTypeEXT::ePipelineLayout: return \"PipelineLayout\";\n    case DebugReportObjectTypeEXT::eRenderPass: return \"RenderPass\";\n    case DebugReportObjectTypeEXT::ePipeline: return \"Pipeline\";\n    case DebugReportObjectTypeEXT::eDescriptorSetLayout: return \"DescriptorSetLayout\";\n    case DebugReportObjectTypeEXT::eSampler: return \"Sampler\";\n    case DebugReportObjectTypeEXT::eDescriptorPool: return \"DescriptorPool\";\n    case DebugReportObjectTypeEXT::eDescriptorSet: return \"DescriptorSet\";\n    case DebugReportObjectTypeEXT::eFramebuffer: return \"Framebuffer\";\n    case DebugReportObjectTypeEXT::eCommandPool: return \"CommandPool\";\n    case DebugReportObjectTypeEXT::eSurfaceKhr: return \"SurfaceKhr\";\n    case DebugReportObjectTypeEXT::eSwapchainKhr: return \"SwapchainKhr\";\n    case DebugReportObjectTypeEXT::eDebugReport: return \"DebugReport\";\n    case DebugReportObjectTypeEXT::eDisplayKhr: return \"DisplayKhr\";\n    case DebugReportObjectTypeEXT::eDisplayModeKhr: return \"DisplayModeKhr\";\n    case DebugReportObjectTypeEXT::eObjectTableNvx: return \"ObjectTableNvx\";\n    case DebugReportObjectTypeEXT::eIndirectCommandsLayoutNvx: return \"IndirectCommandsLayoutNvx\";\n    case DebugReportObjectTypeEXT::eDescriptorUpdateTemplateKHR: return \"DescriptorUpdateTemplateKHR\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(DebugReportErrorEXT value)\n  {\n    switch (value)\n    {\n    case DebugReportErrorEXT::eNone: return \"None\";\n    case DebugReportErrorEXT::eCallbackRef: return \"CallbackRef\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(RasterizationOrderAMD value)\n  {\n    switch (value)\n    {\n    case RasterizationOrderAMD::eStrict: return \"Strict\";\n    case RasterizationOrderAMD::eRelaxed: return \"Relaxed\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(ExternalMemoryHandleTypeFlagBitsNV value)\n  {\n    switch (value)\n    {\n    case ExternalMemoryHandleTypeFlagBitsNV::eOpaqueWin32: return \"OpaqueWin32\";\n    case ExternalMemoryHandleTypeFlagBitsNV::eOpaqueWin32Kmt: return \"OpaqueWin32Kmt\";\n    case ExternalMemoryHandleTypeFlagBitsNV::eD3D11Image: return \"D3D11Image\";\n    case ExternalMemoryHandleTypeFlagBitsNV::eD3D11ImageKmt: return \"D3D11ImageKmt\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(ExternalMemoryHandleTypeFlagsNV value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & ExternalMemoryHandleTypeFlagBitsNV::eOpaqueWin32) result += \"OpaqueWin32 | \";\n    if (value & ExternalMemoryHandleTypeFlagBitsNV::eOpaqueWin32Kmt) result += \"OpaqueWin32Kmt | \";\n    if (value & ExternalMemoryHandleTypeFlagBitsNV::eD3D11Image) result += \"D3D11Image | \";\n    if (value & ExternalMemoryHandleTypeFlagBitsNV::eD3D11ImageKmt) result += \"D3D11ImageKmt | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(ExternalMemoryFeatureFlagBitsNV value)\n  {\n    switch (value)\n    {\n    case ExternalMemoryFeatureFlagBitsNV::eDedicatedOnly: return \"DedicatedOnly\";\n    case ExternalMemoryFeatureFlagBitsNV::eExportable: return \"Exportable\";\n    case ExternalMemoryFeatureFlagBitsNV::eImportable: return \"Importable\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(ExternalMemoryFeatureFlagsNV value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & ExternalMemoryFeatureFlagBitsNV::eDedicatedOnly) result += \"DedicatedOnly | \";\n    if (value & ExternalMemoryFeatureFlagBitsNV::eExportable) result += \"Exportable | \";\n    if (value & ExternalMemoryFeatureFlagBitsNV::eImportable) result += \"Importable | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(ValidationCheckEXT value)\n  {\n    switch (value)\n    {\n    case ValidationCheckEXT::eAll: return \"All\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(IndirectCommandsLayoutUsageFlagBitsNVX value)\n  {\n    switch (value)\n    {\n    case IndirectCommandsLayoutUsageFlagBitsNVX::eUnorderedSequences: return \"UnorderedSequences\";\n    case IndirectCommandsLayoutUsageFlagBitsNVX::eSparseSequences: return \"SparseSequences\";\n    case IndirectCommandsLayoutUsageFlagBitsNVX::eEmptyExecutions: return \"EmptyExecutions\";\n    case IndirectCommandsLayoutUsageFlagBitsNVX::eIndexedSequences: return \"IndexedSequences\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(IndirectCommandsLayoutUsageFlagsNVX value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & IndirectCommandsLayoutUsageFlagBitsNVX::eUnorderedSequences) result += \"UnorderedSequences | \";\n    if (value & IndirectCommandsLayoutUsageFlagBitsNVX::eSparseSequences) result += \"SparseSequences | \";\n    if (value & IndirectCommandsLayoutUsageFlagBitsNVX::eEmptyExecutions) result += \"EmptyExecutions | \";\n    if (value & IndirectCommandsLayoutUsageFlagBitsNVX::eIndexedSequences) result += \"IndexedSequences | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(ObjectEntryUsageFlagBitsNVX value)\n  {\n    switch (value)\n    {\n    case ObjectEntryUsageFlagBitsNVX::eGraphics: return \"Graphics\";\n    case ObjectEntryUsageFlagBitsNVX::eCompute: return \"Compute\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(ObjectEntryUsageFlagsNVX value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & ObjectEntryUsageFlagBitsNVX::eGraphics) result += \"Graphics | \";\n    if (value & ObjectEntryUsageFlagBitsNVX::eCompute) result += \"Compute | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(IndirectCommandsTokenTypeNVX value)\n  {\n    switch (value)\n    {\n    case IndirectCommandsTokenTypeNVX::eVkIndirectCommandsTokenPipeline: return \"VkIndirectCommandsTokenPipeline\";\n    case IndirectCommandsTokenTypeNVX::eVkIndirectCommandsTokenDescriptorSet: return \"VkIndirectCommandsTokenDescriptorSet\";\n    case IndirectCommandsTokenTypeNVX::eVkIndirectCommandsTokenIndexBuffer: return \"VkIndirectCommandsTokenIndexBuffer\";\n    case IndirectCommandsTokenTypeNVX::eVkIndirectCommandsTokenVertexBuffer: return \"VkIndirectCommandsTokenVertexBuffer\";\n    case IndirectCommandsTokenTypeNVX::eVkIndirectCommandsTokenPushConstant: return \"VkIndirectCommandsTokenPushConstant\";\n    case IndirectCommandsTokenTypeNVX::eVkIndirectCommandsTokenDrawIndexed: return \"VkIndirectCommandsTokenDrawIndexed\";\n    case IndirectCommandsTokenTypeNVX::eVkIndirectCommandsTokenDraw: return \"VkIndirectCommandsTokenDraw\";\n    case IndirectCommandsTokenTypeNVX::eVkIndirectCommandsTokenDispatch: return \"VkIndirectCommandsTokenDispatch\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(ObjectEntryTypeNVX value)\n  {\n    switch (value)\n    {\n    case ObjectEntryTypeNVX::eVkObjectEntryDescriptorSet: return \"VkObjectEntryDescriptorSet\";\n    case ObjectEntryTypeNVX::eVkObjectEntryPipeline: return \"VkObjectEntryPipeline\";\n    case ObjectEntryTypeNVX::eVkObjectEntryIndexBuffer: return \"VkObjectEntryIndexBuffer\";\n    case ObjectEntryTypeNVX::eVkObjectEntryVertexBuffer: return \"VkObjectEntryVertexBuffer\";\n    case ObjectEntryTypeNVX::eVkObjectEntryPushConstant: return \"VkObjectEntryPushConstant\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(DescriptorSetLayoutCreateFlagBits value)\n  {\n    switch (value)\n    {\n    case DescriptorSetLayoutCreateFlagBits::ePushDescriptorKHR: return \"PushDescriptorKHR\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(DescriptorSetLayoutCreateFlags value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & DescriptorSetLayoutCreateFlagBits::ePushDescriptorKHR) result += \"PushDescriptorKHR | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(ExternalMemoryHandleTypeFlagBitsKHX value)\n  {\n    switch (value)\n    {\n    case ExternalMemoryHandleTypeFlagBitsKHX::eOpaqueFd: return \"OpaqueFd\";\n    case ExternalMemoryHandleTypeFlagBitsKHX::eOpaqueWin32: return \"OpaqueWin32\";\n    case ExternalMemoryHandleTypeFlagBitsKHX::eOpaqueWin32Kmt: return \"OpaqueWin32Kmt\";\n    case ExternalMemoryHandleTypeFlagBitsKHX::eD3D11Texture: return \"D3D11Texture\";\n    case ExternalMemoryHandleTypeFlagBitsKHX::eD3D11TextureKmt: return \"D3D11TextureKmt\";\n    case ExternalMemoryHandleTypeFlagBitsKHX::eD3D12Heap: return \"D3D12Heap\";\n    case ExternalMemoryHandleTypeFlagBitsKHX::eD3D12Resource: return \"D3D12Resource\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(ExternalMemoryHandleTypeFlagsKHX value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & ExternalMemoryHandleTypeFlagBitsKHX::eOpaqueFd) result += \"OpaqueFd | \";\n    if (value & ExternalMemoryHandleTypeFlagBitsKHX::eOpaqueWin32) result += \"OpaqueWin32 | \";\n    if (value & ExternalMemoryHandleTypeFlagBitsKHX::eOpaqueWin32Kmt) result += \"OpaqueWin32Kmt | \";\n    if (value & ExternalMemoryHandleTypeFlagBitsKHX::eD3D11Texture) result += \"D3D11Texture | \";\n    if (value & ExternalMemoryHandleTypeFlagBitsKHX::eD3D11TextureKmt) result += \"D3D11TextureKmt | \";\n    if (value & ExternalMemoryHandleTypeFlagBitsKHX::eD3D12Heap) result += \"D3D12Heap | \";\n    if (value & ExternalMemoryHandleTypeFlagBitsKHX::eD3D12Resource) result += \"D3D12Resource | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(ExternalMemoryFeatureFlagBitsKHX value)\n  {\n    switch (value)\n    {\n    case ExternalMemoryFeatureFlagBitsKHX::eDedicatedOnly: return \"DedicatedOnly\";\n    case ExternalMemoryFeatureFlagBitsKHX::eExportable: return \"Exportable\";\n    case ExternalMemoryFeatureFlagBitsKHX::eImportable: return \"Importable\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(ExternalMemoryFeatureFlagsKHX value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & ExternalMemoryFeatureFlagBitsKHX::eDedicatedOnly) result += \"DedicatedOnly | \";\n    if (value & ExternalMemoryFeatureFlagBitsKHX::eExportable) result += \"Exportable | \";\n    if (value & ExternalMemoryFeatureFlagBitsKHX::eImportable) result += \"Importable | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(ExternalSemaphoreHandleTypeFlagBitsKHX value)\n  {\n    switch (value)\n    {\n    case ExternalSemaphoreHandleTypeFlagBitsKHX::eOpaqueFd: return \"OpaqueFd\";\n    case ExternalSemaphoreHandleTypeFlagBitsKHX::eOpaqueWin32: return \"OpaqueWin32\";\n    case ExternalSemaphoreHandleTypeFlagBitsKHX::eOpaqueWin32Kmt: return \"OpaqueWin32Kmt\";\n    case ExternalSemaphoreHandleTypeFlagBitsKHX::eD3D12Fence: return \"D3D12Fence\";\n    case ExternalSemaphoreHandleTypeFlagBitsKHX::eFenceFd: return \"FenceFd\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(ExternalSemaphoreHandleTypeFlagsKHX value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & ExternalSemaphoreHandleTypeFlagBitsKHX::eOpaqueFd) result += \"OpaqueFd | \";\n    if (value & ExternalSemaphoreHandleTypeFlagBitsKHX::eOpaqueWin32) result += \"OpaqueWin32 | \";\n    if (value & ExternalSemaphoreHandleTypeFlagBitsKHX::eOpaqueWin32Kmt) result += \"OpaqueWin32Kmt | \";\n    if (value & ExternalSemaphoreHandleTypeFlagBitsKHX::eD3D12Fence) result += \"D3D12Fence | \";\n    if (value & ExternalSemaphoreHandleTypeFlagBitsKHX::eFenceFd) result += \"FenceFd | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(ExternalSemaphoreFeatureFlagBitsKHX value)\n  {\n    switch (value)\n    {\n    case ExternalSemaphoreFeatureFlagBitsKHX::eExportable: return \"Exportable\";\n    case ExternalSemaphoreFeatureFlagBitsKHX::eImportable: return \"Importable\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(ExternalSemaphoreFeatureFlagsKHX value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & ExternalSemaphoreFeatureFlagBitsKHX::eExportable) result += \"Exportable | \";\n    if (value & ExternalSemaphoreFeatureFlagBitsKHX::eImportable) result += \"Importable | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(SurfaceCounterFlagBitsEXT value)\n  {\n    switch (value)\n    {\n    case SurfaceCounterFlagBitsEXT::eVblank: return \"Vblank\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(SurfaceCounterFlagsEXT value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & SurfaceCounterFlagBitsEXT::eVblank) result += \"Vblank | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(DisplayPowerStateEXT value)\n  {\n    switch (value)\n    {\n    case DisplayPowerStateEXT::eOff: return \"Off\";\n    case DisplayPowerStateEXT::eSuspend: return \"Suspend\";\n    case DisplayPowerStateEXT::eOn: return \"On\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(DeviceEventTypeEXT value)\n  {\n    switch (value)\n    {\n    case DeviceEventTypeEXT::eDisplayHotplug: return \"DisplayHotplug\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(DisplayEventTypeEXT value)\n  {\n    switch (value)\n    {\n    case DisplayEventTypeEXT::eFirstPixelOut: return \"FirstPixelOut\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(PeerMemoryFeatureFlagBitsKHX value)\n  {\n    switch (value)\n    {\n    case PeerMemoryFeatureFlagBitsKHX::eCopySrc: return \"CopySrc\";\n    case PeerMemoryFeatureFlagBitsKHX::eCopyDst: return \"CopyDst\";\n    case PeerMemoryFeatureFlagBitsKHX::eGenericSrc: return \"GenericSrc\";\n    case PeerMemoryFeatureFlagBitsKHX::eGenericDst: return \"GenericDst\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(PeerMemoryFeatureFlagsKHX value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & PeerMemoryFeatureFlagBitsKHX::eCopySrc) result += \"CopySrc | \";\n    if (value & PeerMemoryFeatureFlagBitsKHX::eCopyDst) result += \"CopyDst | \";\n    if (value & PeerMemoryFeatureFlagBitsKHX::eGenericSrc) result += \"GenericSrc | \";\n    if (value & PeerMemoryFeatureFlagBitsKHX::eGenericDst) result += \"GenericDst | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(MemoryAllocateFlagBitsKHX value)\n  {\n    switch (value)\n    {\n    case MemoryAllocateFlagBitsKHX::eDeviceMask: return \"DeviceMask\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(MemoryAllocateFlagsKHX value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & MemoryAllocateFlagBitsKHX::eDeviceMask) result += \"DeviceMask | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(DeviceGroupPresentModeFlagBitsKHX value)\n  {\n    switch (value)\n    {\n    case DeviceGroupPresentModeFlagBitsKHX::eLocal: return \"Local\";\n    case DeviceGroupPresentModeFlagBitsKHX::eRemote: return \"Remote\";\n    case DeviceGroupPresentModeFlagBitsKHX::eSum: return \"Sum\";\n    case DeviceGroupPresentModeFlagBitsKHX::eLocalMultiDevice: return \"LocalMultiDevice\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(DeviceGroupPresentModeFlagsKHX value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & DeviceGroupPresentModeFlagBitsKHX::eLocal) result += \"Local | \";\n    if (value & DeviceGroupPresentModeFlagBitsKHX::eRemote) result += \"Remote | \";\n    if (value & DeviceGroupPresentModeFlagBitsKHX::eSum) result += \"Sum | \";\n    if (value & DeviceGroupPresentModeFlagBitsKHX::eLocalMultiDevice) result += \"LocalMultiDevice | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(SwapchainCreateFlagBitsKHR value)\n  {\n    switch (value)\n    {\n    case SwapchainCreateFlagBitsKHR::eBindSfrKHX: return \"BindSfrKHX\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(SwapchainCreateFlagsKHR value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & SwapchainCreateFlagBitsKHR::eBindSfrKHX) result += \"BindSfrKHX | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(ViewportCoordinateSwizzleNV value)\n  {\n    switch (value)\n    {\n    case ViewportCoordinateSwizzleNV::ePositiveX: return \"PositiveX\";\n    case ViewportCoordinateSwizzleNV::eNegativeX: return \"NegativeX\";\n    case ViewportCoordinateSwizzleNV::ePositiveY: return \"PositiveY\";\n    case ViewportCoordinateSwizzleNV::eNegativeY: return \"NegativeY\";\n    case ViewportCoordinateSwizzleNV::ePositiveZ: return \"PositiveZ\";\n    case ViewportCoordinateSwizzleNV::eNegativeZ: return \"NegativeZ\";\n    case ViewportCoordinateSwizzleNV::ePositiveW: return \"PositiveW\";\n    case ViewportCoordinateSwizzleNV::eNegativeW: return \"NegativeW\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(DiscardRectangleModeEXT value)\n  {\n    switch (value)\n    {\n    case DiscardRectangleModeEXT::eInclusive: return \"Inclusive\";\n    case DiscardRectangleModeEXT::eExclusive: return \"Exclusive\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(SubpassDescriptionFlagBits value)\n  {\n    switch (value)\n    {\n    case SubpassDescriptionFlagBits::ePerViewAttributesNVX: return \"PerViewAttributesNVX\";\n    case SubpassDescriptionFlagBits::ePerViewPositionXOnlyNVX: return \"PerViewPositionXOnlyNVX\";\n    default: return \"invalid\";\n    }\n  }\n\n  VULKAN_HPP_INLINE std::string to_string(SubpassDescriptionFlags value)\n  {\n    if (!value) return \"{}\";\n    std::string result;\n    if (value & SubpassDescriptionFlagBits::ePerViewAttributesNVX) result += \"PerViewAttributesNVX | \";\n    if (value & SubpassDescriptionFlagBits::ePerViewPositionXOnlyNVX) result += \"PerViewPositionXOnlyNVX | \";\n    return \"{\" + result.substr(0, result.size() - 3) + \"}\";\n  }\n\n} // namespace vk\n\n#endif\n"
  },
  {
    "path": "src/engine/server/server.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n// server.h\n\n#include \"../../game/q_shared.h\"\n#include \"../qcommon/qcommon.h\"\n#include \"../../game/g_public.h\"\n#include \"../../game/bg_public.h\"\n\n//=============================================================================\n\n#define\tPERS_SCORE\t\t\t\t0\t\t// !!! MUST NOT CHANGE, SERVER AND\n\t\t\t\t\t\t\t\t\t\t// GAME BOTH REFERENCE !!!\n\n#define\tMAX_ENT_CLUSTERS\t16\n\ntypedef struct svEntity_s {\n\tstruct worldSector_s *worldSector;\n\tstruct svEntity_s *nextEntityInWorldSector;\n\t\n\tentityState_t\tbaseline;\t\t// for delta compression of initial sighting\n\tint\t\t\tnumClusters;\t\t// if -1, use headnode instead\n\tint\t\t\tclusternums[MAX_ENT_CLUSTERS];\n\tint\t\t\tlastCluster;\t\t// if all the clusters don't fit in clusternums\n\tint\t\t\tareanum, areanum2;\n\tint\t\t\tsnapshotCounter;\t// used to prevent double adding from portal views\n} svEntity_t;\n\ntypedef enum {\n\tSS_DEAD,\t\t\t// no map loaded\n\tSS_LOADING,\t\t\t// spawning level entities\n\tSS_GAME\t\t\t\t// actively running\n} serverState_t;\n\ntypedef struct {\n\tserverState_t\tstate;\n\tqboolean\t\trestarting;\t\t\t// if true, send configstring changes during SS_LOADING\n\tint\t\t\t\tserverId;\t\t\t// changes each server start\n\tint\t\t\t\trestartedServerId;\t// serverId before a map_restart\n\tint\t\t\t\tchecksumFeed;\t\t// the feed key that we use to compute the pure checksum strings\n\t// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=475\n\t// the serverId associated with the current checksumFeed (always <= serverId)\n\tint       checksumFeedServerId;\t\n\tint\t\t\t\tsnapshotCounter;\t// incremented for each snapshot built\n\tint\t\t\t\ttimeResidual;\t\t// <= 1000 / sv_frame->value\n\tint\t\t\t\tnextFrameTime;\t\t// when time > nextFrameTime, process world\n\tstruct cmodel_s\t*models[MAX_MODELS];\n\tchar\t\t\t*configstrings[MAX_CONFIGSTRINGS];\n\tsvEntity_t\t\tsvEntities[MAX_GENTITIES];\n\n\tchar\t\t\t*entityParsePoint;\t// used during game VM init\n\n\t// the game virtual machine will update these on init and changes\n\tsharedEntity_t\t*gentities;\n\tint\t\t\t\tgentitySize;\n\tint\t\t\t\tnum_entities;\t\t// current number, <= MAX_GENTITIES\n\n\tplayerState_t\t*gameClients;\n\tint\t\t\t\tgameClientSize;\t\t// will be > sizeof(playerState_t) due to game private data\n\n\tint\t\t\t\trestartTime;\n} server_t;\n\n\n\n\n\ntypedef struct {\n\tint\t\t\t\tareabytes;\n\tbyte\t\t\tareabits[MAX_MAP_AREA_BYTES];\t\t// portalarea visibility bits\n\tplayerState_t\tps;\n\tint\t\t\t\tnum_entities;\n\tint\t\t\t\tfirst_entity;\t\t// into the circular sv_packet_entities[]\n\t\t\t\t\t\t\t\t\t\t// the entities MUST be in increasing state number\n\t\t\t\t\t\t\t\t\t\t// order, otherwise the delta compression will fail\n\tint\t\t\t\tmessageSent;\t\t// time the message was transmitted\n\tint\t\t\t\tmessageAcked;\t\t// time the message was acked\n\tint\t\t\t\tmessageSize;\t\t// used to rate drop packets\n} clientSnapshot_t;\n\ntypedef enum {\n\tCS_FREE,\t\t// can be reused for a new connection\n\tCS_ZOMBIE,\t\t// client has been disconnected, but don't reuse\n\t\t\t\t\t// connection for a couple seconds\n\tCS_CONNECTED,\t// has been assigned to a client_t, but no gamestate yet\n\tCS_PRIMED,\t\t// gamestate has been sent, but client hasn't sent a usercmd\n\tCS_ACTIVE\t\t// client is fully in game\n} clientState_t;\n\ntypedef struct netchan_buffer_s {\n\tmsg_t           msg;\n\tbyte            msgBuffer[MAX_MSGLEN];\n\tstruct netchan_buffer_s *next;\n} netchan_buffer_t;\n\ntypedef struct client_s {\n\tclientState_t\tstate;\n\tchar\t\t\tuserinfo[MAX_INFO_STRING];\t\t// name, etc\n\n\tchar\t\t\treliableCommands[MAX_RELIABLE_COMMANDS][MAX_STRING_CHARS];\n\tint\t\t\t\treliableSequence;\t\t// last added reliable message, not necesarily sent or acknowledged yet\n\tint\t\t\t\treliableAcknowledge;\t// last acknowledged reliable message\n\tint\t\t\t\treliableSent;\t\t\t// last sent reliable message, not necesarily acknowledged yet\n\tint\t\t\t\tmessageAcknowledge;\n\n\tint\t\t\t\tgamestateMessageNum;\t// netchan->outgoingSequence of gamestate\n\tint\t\t\t\tchallenge;\n\n\tusercmd_t\t\tlastUsercmd;\n\tint\t\t\t\tlastMessageNum;\t\t// for delta compression\n\tint\t\t\t\tlastClientCommand;\t// reliable client message sequence\n\tchar\t\t\tlastClientCommandString[MAX_STRING_CHARS];\n\tsharedEntity_t\t*gentity;\t\t\t// SV_GentityNum(clientnum)\n\tchar\t\t\tname[MAX_NAME_LENGTH];\t\t\t// extracted from userinfo, high bits masked\n\n\t// downloading\n\tchar\t\t\tdownloadName[MAX_QPATH]; // if not empty string, we are downloading\n\tfileHandle_t\tdownload;\t\t\t// file being downloaded\n \tint\t\t\t\tdownloadSize;\t\t// total bytes (can't use EOF because of paks)\n \tint\t\t\t\tdownloadCount;\t\t// bytes sent\n\tint\t\t\t\tdownloadClientBlock;\t// last block we sent to the client, awaiting ack\n\tint\t\t\t\tdownloadCurrentBlock;\t// current block number\n\tint\t\t\t\tdownloadXmitBlock;\t// last block we xmited\n\tunsigned char\t*downloadBlocks[MAX_DOWNLOAD_WINDOW];\t// the buffers for the download blocks\n\tint\t\t\t\tdownloadBlockSize[MAX_DOWNLOAD_WINDOW];\n\tqboolean\t\tdownloadEOF;\t\t// We have sent the EOF block\n\tint\t\t\t\tdownloadSendTime;\t// time we last got an ack from the client\n\n\tint\t\t\t\tdeltaMessage;\t\t// frame last client usercmd message\n\tint\t\t\t\tnextReliableTime;\t// svs.time when another reliable command will be allowed\n\tint\t\t\t\tlastPacketTime;\t\t// svs.time when packet was last received\n\tint\t\t\t\tlastConnectTime;\t// svs.time when connection started\n\tint\t\t\t\tnextSnapshotTime;\t// send another snapshot when svs.time >= nextSnapshotTime\n\tqboolean\t\trateDelayed;\t\t// true if nextSnapshotTime was set based on rate instead of snapshotMsec\n\tint\t\t\t\ttimeoutCount;\t\t// must timeout a few frames in a row so debugging doesn't break\n\tclientSnapshot_t\tframes[PACKET_BACKUP];\t// updates can be delta'd from here\n\tint\t\t\t\tping;\n\tint\t\t\t\trate;\t\t\t\t// bytes / second\n\tint\t\t\t\tsnapshotMsec;\t\t// requests a snapshot every snapshotMsec unless rate choked\n\tint\t\t\t\tpureAuthentic;\n\tqboolean  gotCP; // TTimo - additional flag to distinguish between a bad pure checksum, and no cp command at all\n\tnetchan_t\t\tnetchan;\n\t// TTimo\n\t// queuing outgoing fragmented messages to send them properly, without udp packet bursts\n\t// in case large fragmented messages are stacking up\n\t// buffer them into this queue, and hand them out to netchan as needed\n\tnetchan_buffer_t *netchan_start_queue;\n\tnetchan_buffer_t **netchan_end_queue;\n} client_t;\n\n//=============================================================================\n\n\n// MAX_CHALLENGES is made large to prevent a denial\n// of service attack that could cycle all of them\n// out before legitimate users connected\n#define\tMAX_CHALLENGES\t1024\n\n#define\tAUTHORIZE_TIMEOUT\t5000\n\ntypedef struct {\n\tnetadr_t\tadr;\n\tint\t\t\tchallenge;\n\tint\t\t\ttime;\t\t\t\t// time the last packet was sent to the autherize server\n\tint\t\t\tpingTime;\t\t\t// time the challenge response was sent to client\n\tint\t\t\tfirstTime;\t\t\t// time the adr was first used, for authorize timeout checks\n\tqboolean\tconnected;\n} challenge_t;\n\n\n#define\tMAX_MASTERS\t8\t\t\t\t// max recipients for heartbeat packets\n\n\n// this structure will be cleared only when the game dll changes\ntypedef struct {\n\tqboolean\tinitialized;\t\t\t\t// sv_init has completed\n\n\tint\t\t\ttime;\t\t\t\t\t\t// will be strictly increasing across level changes\n\n\tint\t\t\tsnapFlagServerBit;\t\t\t// ^= SNAPFLAG_SERVERCOUNT every SV_SpawnServer()\n\n\tclient_t\t*clients;\t\t\t\t\t// [sv_maxclients->integer];\n\tint\t\t\tnumSnapshotEntities;\t\t// sv_maxclients->integer*PACKET_BACKUP*MAX_PACKET_ENTITIES\n\tint\t\t\tnextSnapshotEntities;\t\t// next snapshotEntities to use\n\tentityState_t\t*snapshotEntities;\t\t// [numSnapshotEntities]\n\tint\t\t\tnextHeartbeatTime;\n\tchallenge_t\tchallenges[MAX_CHALLENGES];\t// to prevent invalid IPs from connecting\n\tnetadr_t\tredirectAddress;\t\t\t// for rcon return messages\n\n\tnetadr_t\tauthorizeAddress;\t\t\t// for rcon return messages\n} serverStatic_t;\n\n//=============================================================================\n\nextern\tserverStatic_t\tsvs;\t\t\t\t// persistant server info across maps\nextern\tserver_t\t\tsv;\t\t\t\t\t// cleared each map\nextern\tvm_t\t\t\t*gvm;\t\t\t\t// game virtual machine\n\n#define\tMAX_MASTER_SERVERS\t5\n\nextern\tcvar_t\t*sv_fps;\nextern\tcvar_t\t*sv_timeout;\nextern\tcvar_t\t*sv_zombietime;\nextern\tcvar_t\t*sv_rconPassword;\nextern\tcvar_t\t*sv_privatePassword;\nextern\tcvar_t\t*sv_allowDownload;\nextern\tcvar_t\t*sv_maxclients;\n\nextern\tcvar_t\t*sv_privateClients;\nextern\tcvar_t\t*sv_hostname;\nextern\tcvar_t\t*sv_master[MAX_MASTER_SERVERS];\nextern\tcvar_t\t*sv_reconnectlimit;\nextern\tcvar_t\t*sv_showloss;\nextern\tcvar_t\t*sv_padPackets;\nextern\tcvar_t\t*sv_killserver;\nextern\tcvar_t\t*sv_mapname;\nextern\tcvar_t\t*sv_mapChecksum;\nextern\tcvar_t\t*sv_serverid;\nextern\tcvar_t\t*sv_maxRate;\nextern\tcvar_t\t*sv_minPing;\nextern\tcvar_t\t*sv_maxPing;\nextern\tcvar_t\t*sv_gametype;\nextern\tcvar_t\t*sv_pure;\nextern\tcvar_t\t*sv_floodProtect;\nextern\tcvar_t\t*sv_lanForceRate;\nextern\tcvar_t\t*sv_strictAuth;\n\n//===========================================================\n\n//\n// sv_main.c\n//\nvoid SV_FinalMessage (char *message);\nvoid QDECL SV_SendServerCommand( client_t *cl, const char *fmt, ...);\n\n\nvoid SV_AddOperatorCommands (void);\nvoid SV_RemoveOperatorCommands (void);\n\n\nvoid SV_MasterHeartbeat (void);\nvoid SV_MasterShutdown (void);\n\n\n\n\n//\n// sv_init.c\n//\nvoid SV_SetConfigstring( int index, const char *val );\nvoid SV_GetConfigstring( int index, char *buffer, int bufferSize );\n\nvoid SV_SetUserinfo( int index, const char *val );\nvoid SV_GetUserinfo( int index, char *buffer, int bufferSize );\n\nvoid SV_ChangeMaxClients( void );\nvoid SV_SpawnServer( char *server, qboolean killBots );\n\n\n\n//\n// sv_client.c\n//\nvoid SV_GetChallenge( netadr_t from );\n\nvoid SV_DirectConnect( netadr_t from );\n\nvoid SV_AuthorizeIpPacket( netadr_t from );\n\nvoid SV_ExecuteClientMessage( client_t *cl, msg_t *msg );\nvoid SV_UserinfoChanged( client_t *cl );\n\nvoid SV_ClientEnterWorld( client_t *client, usercmd_t *cmd );\nvoid SV_DropClient( client_t *drop, const char *reason );\n\nvoid SV_ExecuteClientCommand( client_t *cl, const char *s, qboolean clientOK );\nvoid SV_ClientThink (client_t *cl, usercmd_t *cmd);\n\nvoid SV_WriteDownloadToClient( client_t *cl , msg_t *msg );\n\n//\n// sv_ccmds.c\n//\nvoid SV_Heartbeat_f( void );\n\n//\n// sv_snapshot.c\n//\nvoid SV_AddServerCommand( client_t *client, const char *cmd );\nvoid SV_UpdateServerCommandsToClient( client_t *client, msg_t *msg );\nvoid SV_WriteFrameToClient (client_t *client, msg_t *msg);\nvoid SV_SendMessageToClient( msg_t *msg, client_t *client );\nvoid SV_SendClientMessages( void );\nvoid SV_SendClientSnapshot( client_t *client );\n\n//\n// sv_game.c\n//\nint\tSV_NumForGentity( sharedEntity_t *ent );\nsharedEntity_t *SV_GentityNum( int num );\nplayerState_t *SV_GameClientNum( int num );\nsvEntity_t\t*SV_SvEntityForGentity( sharedEntity_t *gEnt );\nsharedEntity_t *SV_GEntityForSvEntity( svEntity_t *svEnt );\nvoid\t\tSV_InitGameProgs ( void );\nvoid\t\tSV_ShutdownGameProgs ( void );\nvoid\t\tSV_RestartGameProgs( void );\nqboolean\tSV_inPVS (const vec3_t p1, const vec3_t p2);\n\n//\n// sv_bot.c\n//\nvoid\t\tSV_BotFrame( int time );\nint\t\t\tSV_BotAllocateClient(void);\nvoid\t\tSV_BotFreeClient( int clientNum );\n\nvoid\t\tSV_BotInitCvars(void);\nint\t\t\tSV_BotLibSetup( void );\nint\t\t\tSV_BotLibShutdown( void );\nint\t\t\tSV_BotGetSnapshotEntity( int client, int ent );\nint\t\t\tSV_BotGetConsoleMessage( int client, char *buf, int size );\n\nint BotImport_DebugPolygonCreate(int color, int numPoints, vec3_t *points);\nvoid BotImport_DebugPolygonDelete(int id);\n\n//============================================================\n//\n// high level object sorting to reduce interaction tests\n//\n\nvoid SV_ClearWorld (void);\n// called after the world model has been loaded, before linking any entities\n\nvoid SV_UnlinkEntity( sharedEntity_t *ent );\n// call before removing an entity, and before trying to move one,\n// so it doesn't clip against itself\n\nvoid SV_LinkEntity( sharedEntity_t *ent );\n// Needs to be called any time an entity changes origin, mins, maxs,\n// or solid.  Automatically unlinks if needed.\n// sets ent->v.absmin and ent->v.absmax\n// sets ent->leafnums[] for pvs determination even if the entity\n// is not solid\n\n\nclipHandle_t SV_ClipHandleForEntity( const sharedEntity_t *ent );\n\n\nvoid SV_SectorList_f( void );\n\n\nint SV_AreaEntities( const vec3_t mins, const vec3_t maxs, int *entityList, int maxcount );\n// fills in a table of entity numbers with entities that have bounding boxes\n// that intersect the given area.  It is possible for a non-axial bmodel\n// to be returned that doesn't actually intersect the area on an exact\n// test.\n// returns the number of pointers filled in\n// The world entity is never returned in this list.\n\n\nint SV_PointContents( const vec3_t p, int passEntityNum );\n// returns the CONTENTS_* value from the world and all entities at the given point.\n\n\nvoid SV_Trace( trace_t *results, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, int passEntityNum, int contentmask, int capsule );\n// mins and maxs are relative\n\n// if the entire move stays in a solid volume, trace.allsolid will be set,\n// trace.startsolid will be set, and trace.fraction will be 0\n\n// if the starting point is in a solid, it will be allowed to move out\n// to an open area\n\n// passEntityNum is explicitly excluded from clipping checks (normally ENTITYNUM_NONE)\n\n\nvoid SV_ClipToEntity( trace_t *trace, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int entityNum, int contentmask, int capsule );\n// clip to a specific entity\n\n//\n// sv_net_chan.c\n//\nvoid SV_Netchan_Transmit( client_t *client, msg_t *msg);\nvoid SV_Netchan_TransmitNextFragment( client_t *client );\nqboolean SV_Netchan_Process( client_t *client, msg_t *msg );\n\n"
  },
  {
    "path": "src/engine/server/sv_bot.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n// sv_bot.c\n\n#include \"server.h\"\n#include \"../../game/botlib.h\"\n\ntypedef struct bot_debugpoly_s\n{\n\tint inuse;\n\tint color;\n\tint numPoints;\n\tvec3_t points[128];\n} bot_debugpoly_t;\n\nstatic bot_debugpoly_t *debugpolygons;\nint bot_maxdebugpolys;\n\nextern botlib_export_t\t*botlib_export;\nint\tbot_enable;\n\n\n/*\n==================\nSV_BotAllocateClient\n==================\n*/\nint SV_BotAllocateClient(void) {\n\tint\t\t\ti;\n\tclient_t\t*cl;\n\n\t// find a client slot\n\tfor ( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ ) {\n\t\tif ( cl->state == CS_FREE ) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif ( i == sv_maxclients->integer ) {\n\t\treturn -1;\n\t}\n\n\tcl->gentity = SV_GentityNum( i );\n\tcl->gentity->s.number = i;\n\tcl->state = CS_ACTIVE;\n\tcl->lastPacketTime = svs.time;\n\tcl->netchan.remoteAddress.type = NA_BOT;\n\tcl->rate = 16384;\n\n\treturn i;\n}\n\n/*\n==================\nSV_BotFreeClient\n==================\n*/\nvoid SV_BotFreeClient( int clientNum ) {\n\tclient_t\t*cl;\n\n\tif ( clientNum < 0 || clientNum >= sv_maxclients->integer ) {\n\t\tCom_Error( ERR_DROP, \"SV_BotFreeClient: bad clientNum: %i\", clientNum );\n\t}\n\tcl = &svs.clients[clientNum];\n\tcl->state = CS_FREE;\n\tcl->name[0] = 0;\n\tif ( cl->gentity ) {\n\t\tcl->gentity->r.svFlags &= ~SVF_BOT;\n\t}\n}\n\n/*\n==================\nBotDrawDebugPolygons\n==================\n*/\nvoid BotDrawDebugPolygons(void (*drawPoly)(int color, int numPoints, float *points), int value) {\n\tstatic cvar_t *bot_debug, *bot_groundonly, *bot_reachability, *bot_highlightarea;\n\tbot_debugpoly_t *poly;\n\tint i, parm0;\n\n\tif (!debugpolygons)\n\t\treturn;\n\t//bot debugging\n\tif (!bot_debug) bot_debug = Cvar_Get(\"bot_debug\", \"0\", 0);\n\t//\n\tif (bot_enable && bot_debug->integer) {\n\t\t//show reachabilities\n\t\tif (!bot_reachability) bot_reachability = Cvar_Get(\"bot_reachability\", \"0\", 0);\n\t\t//show ground faces only\n\t\tif (!bot_groundonly) bot_groundonly = Cvar_Get(\"bot_groundonly\", \"1\", 0);\n\t\t//get the hightlight area\n\t\tif (!bot_highlightarea) bot_highlightarea = Cvar_Get(\"bot_highlightarea\", \"0\", 0);\n\t\t//\n\t\tparm0 = 0;\n\t\tif (svs.clients[0].lastUsercmd.buttons & BUTTON_ATTACK) parm0 |= 1;\n\t\tif (bot_reachability->integer) parm0 |= 2;\n\t\tif (bot_groundonly->integer) parm0 |= 4;\n\t\tbotlib_export->BotLibVarSet(\"bot_highlightarea\", bot_highlightarea->string);\n\t\tbotlib_export->Test(parm0, NULL, svs.clients[0].gentity->r.currentOrigin, \n\t\t\tsvs.clients[0].gentity->r.currentAngles);\n\t} //end if\n\t//draw all debug polys\n\tfor (i = 0; i < bot_maxdebugpolys; i++) {\n\t\tpoly = &debugpolygons[i];\n\t\tif (!poly->inuse) continue;\n\t\tdrawPoly(poly->color, poly->numPoints, (float *) poly->points);\n\t\t//Com_Printf(\"poly %i, numpoints = %d\\n\", i, poly->numPoints);\n\t}\n}\n\n/*\n==================\nBotImport_Print\n==================\n*/\nvoid QDECL BotImport_Print(int type, char *fmt, ...)\n{\n\tchar str[2048];\n\tva_list ap;\n\n\tva_start(ap, fmt);\n\tvsprintf(str, fmt, ap);\n\tva_end(ap);\n\n\tswitch(type) {\n\t\tcase PRT_MESSAGE: {\n\t\t\tCom_Printf(\"%s\", str);\n\t\t\tbreak;\n\t\t}\n\t\tcase PRT_WARNING: {\n\t\t\tCom_Printf(S_COLOR_YELLOW \"Warning: %s\", str);\n\t\t\tbreak;\n\t\t}\n\t\tcase PRT_ERROR: {\n\t\t\tCom_Printf(S_COLOR_RED \"Error: %s\", str);\n\t\t\tbreak;\n\t\t}\n\t\tcase PRT_FATAL: {\n\t\t\tCom_Printf(S_COLOR_RED \"Fatal: %s\", str);\n\t\t\tbreak;\n\t\t}\n\t\tcase PRT_EXIT: {\n\t\t\tCom_Error(ERR_DROP, S_COLOR_RED \"Exit: %s\", str);\n\t\t\tbreak;\n\t\t}\n\t\tdefault: {\n\t\t\tCom_Printf(\"unknown print type\\n\");\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\n/*\n==================\nBotImport_Trace\n==================\n*/\nvoid BotImport_Trace(bsp_trace_t *bsptrace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int passent, int contentmask) {\n\ttrace_t trace;\n\n\tSV_Trace(&trace, start, mins, maxs, end, passent, contentmask, qfalse);\n\t//copy the trace information\n\tbsptrace->allsolid = trace.allsolid;\n\tbsptrace->startsolid = trace.startsolid;\n\tbsptrace->fraction = trace.fraction;\n\tVectorCopy(trace.endpos, bsptrace->endpos);\n\tbsptrace->plane.dist = trace.plane.dist;\n\tVectorCopy(trace.plane.normal, bsptrace->plane.normal);\n\tbsptrace->plane.signbits = trace.plane.signbits;\n\tbsptrace->plane.type = trace.plane.type;\n\tbsptrace->surface.value = trace.surfaceFlags;\n\tbsptrace->ent = trace.entityNum;\n\tbsptrace->exp_dist = 0;\n\tbsptrace->sidenum = 0;\n\tbsptrace->contents = 0;\n}\n\n/*\n==================\nBotImport_EntityTrace\n==================\n*/\nvoid BotImport_EntityTrace(bsp_trace_t *bsptrace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int entnum, int contentmask) {\n\ttrace_t trace;\n\n\tSV_ClipToEntity(&trace, start, mins, maxs, end, entnum, contentmask, qfalse);\n\t//copy the trace information\n\tbsptrace->allsolid = trace.allsolid;\n\tbsptrace->startsolid = trace.startsolid;\n\tbsptrace->fraction = trace.fraction;\n\tVectorCopy(trace.endpos, bsptrace->endpos);\n\tbsptrace->plane.dist = trace.plane.dist;\n\tVectorCopy(trace.plane.normal, bsptrace->plane.normal);\n\tbsptrace->plane.signbits = trace.plane.signbits;\n\tbsptrace->plane.type = trace.plane.type;\n\tbsptrace->surface.value = trace.surfaceFlags;\n\tbsptrace->ent = trace.entityNum;\n\tbsptrace->exp_dist = 0;\n\tbsptrace->sidenum = 0;\n\tbsptrace->contents = 0;\n}\n\n\n/*\n==================\nBotImport_PointContents\n==================\n*/\nint BotImport_PointContents(vec3_t point) {\n\treturn SV_PointContents(point, -1);\n}\n\n/*\n==================\nBotImport_inPVS\n==================\n*/\nint BotImport_inPVS(vec3_t p1, vec3_t p2) {\n\treturn SV_inPVS (p1, p2);\n}\n\n/*\n==================\nBotImport_BSPEntityData\n==================\n*/\nchar *BotImport_BSPEntityData(void) {\n\treturn CM_EntityString();\n}\n\n/*\n==================\nBotImport_BSPModelMinsMaxsOrigin\n==================\n*/\nvoid BotImport_BSPModelMinsMaxsOrigin(int modelnum, vec3_t angles, vec3_t outmins, vec3_t outmaxs, vec3_t origin) {\n\tclipHandle_t h;\n\tvec3_t mins, maxs;\n\tfloat max;\n\tint\ti;\n\n\th = CM_InlineModel(modelnum);\n\tCM_ModelBounds(h, mins, maxs);\n\t//if the model is rotated\n\tif ((angles[0] || angles[1] || angles[2])) {\n\t\t// expand for rotation\n\n\t\tmax = RadiusFromBounds(mins, maxs);\n\t\tfor (i = 0; i < 3; i++) {\n\t\t\tmins[i] = -max;\n\t\t\tmaxs[i] = max;\n\t\t}\n\t}\n\tif (outmins) VectorCopy(mins, outmins);\n\tif (outmaxs) VectorCopy(maxs, outmaxs);\n\tif (origin) VectorClear(origin);\n}\n\n/*\n==================\nBotImport_GetMemory\n==================\n*/\nvoid *BotImport_GetMemory(int size) {\n\tvoid *ptr;\n\n\tptr = Z_TagMalloc( size, TAG_BOTLIB );\n\treturn ptr;\n}\n\n/*\n==================\nBotImport_FreeMemory\n==================\n*/\nvoid BotImport_FreeMemory(void *ptr) {\n\tZ_Free(ptr);\n}\n\n/*\n=================\nBotImport_HunkAlloc\n=================\n*/\nvoid *BotImport_HunkAlloc( int size ) {\n\tif( Hunk_CheckMark() ) {\n\t\tCom_Error( ERR_DROP, \"SV_Bot_HunkAlloc: Alloc with marks already set\\n\" );\n\t}\n\treturn Hunk_Alloc( size, h_high );\n}\n\n/*\n==================\nBotImport_DebugPolygonCreate\n==================\n*/\nint BotImport_DebugPolygonCreate(int color, int numPoints, vec3_t *points) {\n\tbot_debugpoly_t *poly;\n\tint i;\n\n\tif (!debugpolygons)\n\t\treturn 0;\n\n\tfor (i = 1; i < bot_maxdebugpolys; i++) \t{\n\t\tif (!debugpolygons[i].inuse)\n\t\t\tbreak;\n\t}\n\tif (i >= bot_maxdebugpolys)\n\t\treturn 0;\n\tpoly = &debugpolygons[i];\n\tpoly->inuse = qtrue;\n\tpoly->color = color;\n\tpoly->numPoints = numPoints;\n\tCom_Memcpy(poly->points, points, numPoints * sizeof(vec3_t));\n\t//\n\treturn i;\n}\n\n/*\n==================\nBotImport_DebugPolygonShow\n==================\n*/\nvoid BotImport_DebugPolygonShow(int id, int color, int numPoints, vec3_t *points) {\n\tbot_debugpoly_t *poly;\n\n\tif (!debugpolygons) return;\n\tpoly = &debugpolygons[id];\n\tpoly->inuse = qtrue;\n\tpoly->color = color;\n\tpoly->numPoints = numPoints;\n\tCom_Memcpy(poly->points, points, numPoints * sizeof(vec3_t));\n}\n\n/*\n==================\nBotImport_DebugPolygonDelete\n==================\n*/\nvoid BotImport_DebugPolygonDelete(int id)\n{\n\tif (!debugpolygons) return;\n\tdebugpolygons[id].inuse = qfalse;\n}\n\n/*\n==================\nBotImport_DebugLineCreate\n==================\n*/\nint BotImport_DebugLineCreate(void) {\n\tvec3_t points[1];\n\treturn BotImport_DebugPolygonCreate(0, 0, points);\n}\n\n/*\n==================\nBotImport_DebugLineDelete\n==================\n*/\nvoid BotImport_DebugLineDelete(int line) {\n\tBotImport_DebugPolygonDelete(line);\n}\n\n/*\n==================\nBotImport_DebugLineShow\n==================\n*/\nvoid BotImport_DebugLineShow(int line, vec3_t start, vec3_t end, int color) {\n\tvec3_t points[4], dir, cross, up = {0, 0, 1};\n\tfloat dot;\n\n\tVectorCopy(start, points[0]);\n\tVectorCopy(start, points[1]);\n\t//points[1][2] -= 2;\n\tVectorCopy(end, points[2]);\n\t//points[2][2] -= 2;\n\tVectorCopy(end, points[3]);\n\n\n\tVectorSubtract(end, start, dir);\n\tVectorNormalize(dir);\n\tdot = DotProduct(dir, up);\n\tif (dot > 0.99 || dot < -0.99) VectorSet(cross, 1, 0, 0);\n\telse CrossProduct(dir, up, cross);\n\n\tVectorNormalize(cross);\n\n\tVectorMA(points[0], 2, cross, points[0]);\n\tVectorMA(points[1], -2, cross, points[1]);\n\tVectorMA(points[2], -2, cross, points[2]);\n\tVectorMA(points[3], 2, cross, points[3]);\n\n\tBotImport_DebugPolygonShow(line, color, 4, points);\n}\n\n/*\n==================\nSV_BotClientCommand\n==================\n*/\nvoid BotClientCommand( int client, char *command ) {\n\tSV_ExecuteClientCommand( &svs.clients[client], command, qtrue );\n}\n\n/*\n==================\nSV_BotFrame\n==================\n*/\nvoid SV_BotFrame( int time ) {\n\tif (!bot_enable) return;\n\t//NOTE: maybe the game is already shutdown\n\tif (!gvm) return;\n\tVM_Call( gvm, BOTAI_START_FRAME, time );\n}\n\n/*\n===============\nSV_BotLibSetup\n===============\n*/\nint SV_BotLibSetup( void ) {\n\tif (!bot_enable) {\n\t\treturn 0;\n\t}\n\n\tif ( !botlib_export ) {\n\t\tCom_Printf( S_COLOR_RED \"Error: SV_BotLibSetup without SV_BotInitBotLib\\n\" );\n\t\treturn -1;\n\t}\n\n\treturn botlib_export->BotLibSetup();\n}\n\n/*\n===============\nSV_ShutdownBotLib\n\nCalled when either the entire server is being killed, or\nit is changing to a different game directory.\n===============\n*/\nint SV_BotLibShutdown( void ) {\n\n\tif ( !botlib_export ) {\n\t\treturn -1;\n\t}\n\n\treturn botlib_export->BotLibShutdown();\n}\n\n/*\n==================\nSV_BotInitCvars\n==================\n*/\nvoid SV_BotInitCvars(void) {\n\n\tCvar_Get(\"bot_enable\", \"1\", 0);\t\t\t\t\t\t//enable the bot\n\tCvar_Get(\"bot_developer\", \"0\", CVAR_CHEAT);\t\t\t//bot developer mode\n\tCvar_Get(\"bot_debug\", \"0\", CVAR_CHEAT);\t\t\t\t//enable bot debugging\n\tCvar_Get(\"bot_maxdebugpolys\", \"2\", 0);\t\t\t\t//maximum number of debug polys\n\tCvar_Get(\"bot_groundonly\", \"1\", 0);\t\t\t\t\t//only show ground faces of areas\n\tCvar_Get(\"bot_reachability\", \"0\", 0);\t\t\t\t//show all reachabilities to other areas\n\tCvar_Get(\"bot_visualizejumppads\", \"0\", CVAR_CHEAT);\t//show jumppads\n\tCvar_Get(\"bot_forceclustering\", \"0\", 0);\t\t\t//force cluster calculations\n\tCvar_Get(\"bot_forcereachability\", \"0\", 0);\t\t\t//force reachability calculations\n\tCvar_Get(\"bot_forcewrite\", \"0\", 0);\t\t\t\t\t//force writing aas file\n\tCvar_Get(\"bot_aasoptimize\", \"0\", 0);\t\t\t\t//no aas file optimisation\n\tCvar_Get(\"bot_saveroutingcache\", \"0\", 0);\t\t\t//save routing cache\n\tCvar_Get(\"bot_thinktime\", \"100\", CVAR_CHEAT);\t\t//msec the bots thinks\n\tCvar_Get(\"bot_reloadcharacters\", \"0\", 0);\t\t\t//reload the bot characters each time\n\tCvar_Get(\"bot_testichat\", \"0\", 0);\t\t\t\t\t//test ichats\n\tCvar_Get(\"bot_testrchat\", \"0\", 0);\t\t\t\t\t//test rchats\n\tCvar_Get(\"bot_testsolid\", \"0\", CVAR_CHEAT);\t\t\t//test for solid areas\n\tCvar_Get(\"bot_testclusters\", \"0\", CVAR_CHEAT);\t\t//test the AAS clusters\n\tCvar_Get(\"bot_fastchat\", \"0\", 0);\t\t\t\t\t//fast chatting bots\n\tCvar_Get(\"bot_nochat\", \"0\", 0);\t\t\t\t\t\t//disable chats\n\tCvar_Get(\"bot_pause\", \"0\", CVAR_CHEAT);\t\t\t\t//pause the bots thinking\n\tCvar_Get(\"bot_report\", \"0\", CVAR_CHEAT);\t\t\t//get a full report in ctf\n\tCvar_Get(\"bot_grapple\", \"0\", 0);\t\t\t\t\t//enable grapple\n\tCvar_Get(\"bot_rocketjump\", \"1\", 0);\t\t\t\t\t//enable rocket jumping\n\tCvar_Get(\"bot_challenge\", \"0\", 0);\t\t\t\t\t//challenging bot\n\tCvar_Get(\"bot_minplayers\", \"0\", 0);\t\t\t\t\t//minimum players in a team or the game\n\tCvar_Get(\"bot_interbreedchar\", \"\", CVAR_CHEAT);\t\t//bot character used for interbreeding\n\tCvar_Get(\"bot_interbreedbots\", \"10\", CVAR_CHEAT);\t//number of bots used for interbreeding\n\tCvar_Get(\"bot_interbreedcycle\", \"20\", CVAR_CHEAT);\t//bot interbreeding cycle\n\tCvar_Get(\"bot_interbreedwrite\", \"\", CVAR_CHEAT);\t//write interbreeded bots to this file\n}\n\n/*\n==================\nSV_BotInitBotLib\n==================\n*/\nvoid SV_BotInitBotLib(void) {\n\tbotlib_import_t\tbotlib_import;\n\n\tif ( !Cvar_VariableValue(\"fs_restrict\") && !Sys_CheckCD() ) {\n\t\tCom_Error( ERR_NEED_CD, \"Game CD not in drive\" );\n\t}\n\n\tif (debugpolygons) Z_Free(debugpolygons);\n\tbot_maxdebugpolys = Cvar_VariableIntegerValue(\"bot_maxdebugpolys\");\n\tdebugpolygons = (bot_debugpoly_t*) Z_Malloc(sizeof(bot_debugpoly_t)* bot_maxdebugpolys);\n\n\tbotlib_import.Print = BotImport_Print;\n\tbotlib_import.Trace = BotImport_Trace;\n\tbotlib_import.EntityTrace = BotImport_EntityTrace;\n\tbotlib_import.PointContents = BotImport_PointContents;\n\tbotlib_import.inPVS = BotImport_inPVS;\n\tbotlib_import.BSPEntityData = BotImport_BSPEntityData;\n\tbotlib_import.BSPModelMinsMaxsOrigin = BotImport_BSPModelMinsMaxsOrigin;\n\tbotlib_import.BotClientCommand = BotClientCommand;\n\n\t//memory management\n\tbotlib_import.GetMemory = BotImport_GetMemory;\n\tbotlib_import.FreeMemory = BotImport_FreeMemory;\n\tbotlib_import.AvailableMemory = Z_AvailableMemory;\n\tbotlib_import.HunkAlloc = BotImport_HunkAlloc;\n\n\t// file system access\n\tbotlib_import.FS_FOpenFile = FS_FOpenFileByMode;\n\tbotlib_import.FS_Read = FS_Read2;\n\tbotlib_import.FS_Write = FS_Write;\n\tbotlib_import.FS_FCloseFile = FS_FCloseFile;\n\tbotlib_import.FS_Seek = FS_Seek;\n\n\t//debug lines\n\tbotlib_import.DebugLineCreate = BotImport_DebugLineCreate;\n\tbotlib_import.DebugLineDelete = BotImport_DebugLineDelete;\n\tbotlib_import.DebugLineShow = BotImport_DebugLineShow;\n\n\t//debug polygons\n\tbotlib_import.DebugPolygonCreate = BotImport_DebugPolygonCreate;\n\tbotlib_import.DebugPolygonDelete = BotImport_DebugPolygonDelete;\n\n\tbotlib_export = (botlib_export_t *)GetBotLibAPI( BOTLIB_API_VERSION, &botlib_import );\n\tassert(botlib_export); \t// bk001129 - somehow we end up with a zero import.\n}\n\n\n//\n//  * * * BOT AI CODE IS BELOW THIS POINT * * *\n//\n\n/*\n==================\nSV_BotGetConsoleMessage\n==================\n*/\nint SV_BotGetConsoleMessage( int client, char *buf, int size )\n{\n\tclient_t\t*cl;\n\tint\t\t\tindex;\n\n\tcl = &svs.clients[client];\n\tcl->lastPacketTime = svs.time;\n\n\tif ( cl->reliableAcknowledge == cl->reliableSequence ) {\n\t\treturn qfalse;\n\t}\n\n\tcl->reliableAcknowledge++;\n\tindex = cl->reliableAcknowledge & ( MAX_RELIABLE_COMMANDS - 1 );\n\n\tif ( !cl->reliableCommands[index][0] ) {\n\t\treturn qfalse;\n\t}\n\n\tQ_strncpyz( buf, cl->reliableCommands[index], size );\n\treturn qtrue;\n}\n\n#if 0\n/*\n==================\nEntityInPVS\n==================\n*/\nint EntityInPVS( int client, int entityNum ) {\n\tclient_t\t\t\t*cl;\n\tclientSnapshot_t\t*frame;\n\tint\t\t\t\t\ti;\n\n\tcl = &svs.clients[client];\n\tframe = &cl->frames[cl->netchan.outgoingSequence & PACKET_MASK];\n\tfor ( i = 0; i < frame->num_entities; i++ )\t{\n\t\tif ( svs.snapshotEntities[(frame->first_entity + i) % svs.numSnapshotEntities].number == entityNum ) {\n\t\t\treturn qtrue;\n\t\t}\n\t}\n\treturn qfalse;\n}\n#endif\n\n/*\n==================\nSV_BotGetSnapshotEntity\n==================\n*/\nint SV_BotGetSnapshotEntity( int client, int sequence ) {\n\tclient_t\t\t\t*cl;\n\tclientSnapshot_t\t*frame;\n\n\tcl = &svs.clients[client];\n\tframe = &cl->frames[cl->netchan.outgoingSequence & PACKET_MASK];\n\tif (sequence < 0 || sequence >= frame->num_entities) {\n\t\treturn -1;\n\t}\n\treturn svs.snapshotEntities[(frame->first_entity + sequence) % svs.numSnapshotEntities].number;\n}\n\n"
  },
  {
    "path": "src/engine/server/sv_ccmds.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n#include \"server.h\"\n\n/*\n===============================================================================\n\nOPERATOR CONSOLE ONLY COMMANDS\n\nThese commands can only be entered from stdin or by a remote operator datagram\n===============================================================================\n*/\n\n\n/*\n==================\nSV_GetPlayerByName\n\nReturns the player with name from Cmd_Argv(1)\n==================\n*/\nstatic client_t *SV_GetPlayerByName( void ) {\n\tclient_t\t*cl;\n\tint\t\t\ti;\n\tchar\t\t*s;\n\tchar\t\tcleanName[64];\n\n\t// make sure server is running\n\tif ( !com_sv_running->integer ) {\n\t\treturn NULL;\n\t}\n\n\tif ( Cmd_Argc() < 2 ) {\n\t\tCom_Printf( \"No player specified.\\n\" );\n\t\treturn NULL;\n\t}\n\n\ts = Cmd_Argv(1);\n\n\t// check for a name match\n\tfor ( i=0, cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++ ) {\n\t\tif ( !cl->state ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( !Q_stricmp( cl->name, s ) ) {\n\t\t\treturn cl;\n\t\t}\n\n\t\tQ_strncpyz( cleanName, cl->name, sizeof(cleanName) );\n\t\tQ_CleanStr( cleanName );\n\t\tif ( !Q_stricmp( cleanName, s ) ) {\n\t\t\treturn cl;\n\t\t}\n\t}\n\n\tCom_Printf( \"Player %s is not on the server\\n\", s );\n\n\treturn NULL;\n}\n\n/*\n==================\nSV_GetPlayerByNum\n\nReturns the player with idnum from Cmd_Argv(1)\n==================\n*/\nstatic client_t *SV_GetPlayerByNum( void ) {\n\tclient_t\t*cl;\n\tint\t\t\ti;\n\tint\t\t\tidnum;\n\tchar\t\t*s;\n\n\t// make sure server is running\n\tif ( !com_sv_running->integer ) {\n\t\treturn NULL;\n\t}\n\n\tif ( Cmd_Argc() < 2 ) {\n\t\tCom_Printf( \"No player specified.\\n\" );\n\t\treturn NULL;\n\t}\n\n\ts = Cmd_Argv(1);\n\n\tfor (i = 0; s[i]; i++) {\n\t\tif (s[i] < '0' || s[i] > '9') {\n\t\t\tCom_Printf( \"Bad slot number: %s\\n\", s);\n\t\t\treturn NULL;\n\t\t}\n\t}\n\tidnum = atoi( s );\n\tif ( idnum < 0 || idnum >= sv_maxclients->integer ) {\n\t\tCom_Printf( \"Bad client slot: %i\\n\", idnum );\n\t\treturn NULL;\n\t}\n\n\tcl = &svs.clients[idnum];\n\tif ( !cl->state ) {\n\t\tCom_Printf( \"Client %i is not active\\n\", idnum );\n\t\treturn NULL;\n\t}\n\treturn cl;\n\n\treturn NULL;\n}\n\n//=========================================================\n\n\n/*\n==================\nSV_Map_f\n\nRestart the server on a different map\n==================\n*/\nstatic void SV_Map_f( void ) {\n\tchar\t\t*cmd;\n\tchar\t\t*map;\n\tqboolean\tkillBots, cheat;\n\tchar\t\texpanded[MAX_QPATH];\n\tchar\t\tmapname[MAX_QPATH];\n\n\tmap = Cmd_Argv(1);\n\tif ( !map ) {\n\t\treturn;\n\t}\n\n\t// make sure the level exists before trying to change, so that\n\t// a typo at the server console won't end the game\n\tCom_sprintf (expanded, sizeof(expanded), \"maps/%s.bsp\", map);\n\tif ( FS_ReadFile (expanded, NULL) == -1 ) {\n\t\tCom_Printf (\"Can't find map %s\\n\", expanded);\n\t\treturn;\n\t}\n\n\t// force latched values to get set\n\tCvar_Get (\"g_gametype\", \"0\", CVAR_SERVERINFO | CVAR_USERINFO | CVAR_LATCH );\n\n\tcmd = Cmd_Argv(0);\n\tif( Q_stricmpn( cmd, \"sp\", 2 ) == 0 ) {\n\t\tCvar_SetValue( \"g_gametype\", GT_SINGLE_PLAYER );\n\t\tCvar_SetValue( \"g_doWarmup\", 0 );\n\t\t// may not set sv_maxclients directly, always set latched\n\t\tCvar_SetLatched( \"sv_maxclients\", \"8\" );\n\t\tcmd += 2;\n\t\tcheat = qfalse;\n\t\tkillBots = qtrue;\n\t}\n\telse {\n\t\tif ( !Q_stricmp( cmd, \"devmap\" ) || !Q_stricmp( cmd, \"spdevmap\" ) ) {\n\t\t\tcheat = qtrue;\n\t\t\tkillBots = qtrue;\n\t\t} else {\n\t\t\tcheat = qfalse;\n\t\t\tkillBots = qfalse;\n\t\t}\n\t\tif( sv_gametype->integer == GT_SINGLE_PLAYER ) {\n\t\t\tCvar_SetValue( \"g_gametype\", GT_FFA );\n\t\t}\n\t}\n\n\t// save the map name here cause on a map restart we reload the q3config.cfg\n\t// and thus nuke the arguments of the map command\n\tQ_strncpyz(mapname, map, sizeof(mapname));\n\n\t// start up the map\n\tSV_SpawnServer( mapname, killBots );\n\n\t// set the cheat value\n\t// if the level was started with \"map <levelname>\", then\n\t// cheats will not be allowed.  If started with \"devmap <levelname>\"\n\t// then cheats will be allowed\n\tif ( cheat ) {\n\t\tCvar_Set( \"sv_cheats\", \"1\" );\n\t} else {\n\t\tCvar_Set( \"sv_cheats\", \"0\" );\n\t}\n}\n\n/*\n================\nSV_MapRestart_f\n\nCompletely restarts a level, but doesn't send a new gamestate to the clients.\nThis allows fair starts with variable load times.\n================\n*/\nstatic void SV_MapRestart_f( void ) {\n\tint\t\t\ti;\n\tclient_t\t*client;\n\tchar\t\t*denied;\n\tqboolean\tisBot;\n\tint\t\t\tdelay;\n\n\t// make sure we aren't restarting twice in the same frame\n\tif ( com_frameTime == sv.serverId ) {\n\t\treturn;\n\t}\n\n\t// make sure server is running\n\tif ( !com_sv_running->integer ) {\n\t\tCom_Printf( \"Server is not running.\\n\" );\n\t\treturn;\n\t}\n\n\tif ( sv.restartTime ) {\n\t\treturn;\n\t}\n\n\tif (Cmd_Argc() > 1 ) {\n\t\tdelay = atoi( Cmd_Argv(1) );\n\t}\n\telse {\n\t\tdelay = 5;\n\t}\n\tif( delay && !Cvar_VariableValue(\"g_doWarmup\") ) {\n\t\tsv.restartTime = svs.time + delay * 1000;\n\t\tSV_SetConfigstring( CS_WARMUP, va(\"%i\", sv.restartTime) );\n\t\treturn;\n\t}\n\n\t// check for changes in variables that can't just be restarted\n\t// check for maxclients change\n\tif ( sv_maxclients->modified || sv_gametype->modified ) {\n\t\tchar\tmapname[MAX_QPATH];\n\n\t\tCom_Printf( \"variable change -- restarting.\\n\" );\n\t\t// restart the map the slow way\n\t\tQ_strncpyz( mapname, Cvar_VariableString( \"mapname\" ), sizeof( mapname ) );\n\n\t\tSV_SpawnServer( mapname, qfalse );\n\t\treturn;\n\t}\n\n\t// toggle the server bit so clients can detect that a\n\t// map_restart has happened\n\tsvs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT;\n\n\t// generate a new serverid\t\n\t// TTimo - don't update restartedserverId there, otherwise we won't deal correctly with multiple map_restart\n\tsv.serverId = com_frameTime;\n\tCvar_Set( \"sv_serverid\", va(\"%i\", sv.serverId ) );\n\n\t// reset all the vm data in place without changing memory allocation\n\t// note that we do NOT set sv.state = SS_LOADING, so configstrings that\n\t// had been changed from their default values will generate broadcast updates\n\tsv.state = SS_LOADING;\n\tsv.restarting = qtrue;\n\n\tSV_RestartGameProgs();\n\n\t// run a few frames to allow everything to settle\n\tfor ( i = 0 ;i < 3 ; i++ ) {\n\t\tVM_Call( gvm, GAME_RUN_FRAME, svs.time );\n\t\tsvs.time += 100;\n\t}\n\n\tsv.state = SS_GAME;\n\tsv.restarting = qfalse;\n\n\t// connect and begin all the clients\n\tfor (i=0 ; i<sv_maxclients->integer ; i++) {\n\t\tclient = &svs.clients[i];\n\n\t\t// send the new gamestate to all connected clients\n\t\tif ( client->state < CS_CONNECTED) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif ( client->netchan.remoteAddress.type == NA_BOT ) {\n\t\t\tisBot = qtrue;\n\t\t} else {\n\t\t\tisBot = qfalse;\n\t\t}\n\n\t\t// add the map_restart command\n\t\tSV_AddServerCommand( client, \"map_restart\\n\" );\n\n\t\t// connect the client again, without the firstTime flag\n\t\tdenied = (char*) VM_ExplicitArgPtr( gvm, VM_Call( gvm, GAME_CLIENT_CONNECT, i, qfalse, isBot ) );\n\t\tif ( denied ) {\n\t\t\t// this generally shouldn't happen, because the client\n\t\t\t// was connected before the level change\n\t\t\tSV_DropClient( client, denied );\n\t\t\tCom_Printf( \"SV_MapRestart_f(%d): dropped client %i - denied!\\n\", delay, i ); // bk010125\n\t\t\tcontinue;\n\t\t}\n\n\t\tclient->state = CS_ACTIVE;\n\n\t\tSV_ClientEnterWorld( client, &client->lastUsercmd );\n\t}\t\n\n\t// run another frame to allow things to look at all the players\n\tVM_Call( gvm, GAME_RUN_FRAME, svs.time );\n\tsvs.time += 100;\n}\n\n//===============================================================\n\n/*\n==================\nSV_Kick_f\n\nKick a user off of the server  FIXME: move to game\n==================\n*/\nstatic void SV_Kick_f( void ) {\n\tclient_t\t*cl;\n\tint\t\t\ti;\n\n\t// make sure server is running\n\tif ( !com_sv_running->integer ) {\n\t\tCom_Printf( \"Server is not running.\\n\" );\n\t\treturn;\n\t}\n\n\tif ( Cmd_Argc() != 2 ) {\n\t\tCom_Printf (\"Usage: kick <player name>\\nkick all = kick everyone\\nkick allbots = kick all bots\\n\");\n\t\treturn;\n\t}\n\n\tcl = SV_GetPlayerByName();\n\tif ( !cl ) {\n\t\tif ( !Q_stricmp(Cmd_Argv(1), \"all\") ) {\n\t\t\tfor ( i=0, cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++ ) {\n\t\t\t\tif ( !cl->state ) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif( cl->netchan.remoteAddress.type == NA_LOOPBACK ) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tSV_DropClient( cl, \"was kicked\" );\n\t\t\t\tcl->lastPacketTime = svs.time;\t// in case there is a funny zombie\n\t\t\t}\n\t\t}\n\t\telse if ( !Q_stricmp(Cmd_Argv(1), \"allbots\") ) {\n\t\t\tfor ( i=0, cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++ ) {\n\t\t\t\tif ( !cl->state ) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif( cl->netchan.remoteAddress.type != NA_BOT ) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tSV_DropClient( cl, \"was kicked\" );\n\t\t\t\tcl->lastPacketTime = svs.time;\t// in case there is a funny zombie\n\t\t\t}\n\t\t}\n\t\treturn;\n\t}\n\tif( cl->netchan.remoteAddress.type == NA_LOOPBACK ) {\n\t\tSV_SendServerCommand(NULL, \"print \\\"%s\\\"\", \"Cannot kick host player\\n\");\n\t\treturn;\n\t}\n\n\tSV_DropClient( cl, \"was kicked\" );\n\tcl->lastPacketTime = svs.time;\t// in case there is a funny zombie\n}\n\n/*\n==================\nSV_Ban_f\n\nBan a user from being able to play on this server through the auth\nserver\n==================\n*/\nstatic void SV_Ban_f( void ) {\n\tclient_t\t*cl;\n\n\t// make sure server is running\n\tif ( !com_sv_running->integer ) {\n\t\tCom_Printf( \"Server is not running.\\n\" );\n\t\treturn;\n\t}\n\n\tif ( Cmd_Argc() != 2 ) {\n\t\tCom_Printf (\"Usage: banUser <player name>\\n\");\n\t\treturn;\n\t}\n\n\tcl = SV_GetPlayerByName();\n\n\tif (!cl) {\n\t\treturn;\n\t}\n\n\tif( cl->netchan.remoteAddress.type == NA_LOOPBACK ) {\n\t\tSV_SendServerCommand(NULL, \"print \\\"%s\\\"\", \"Cannot kick host player\\n\");\n\t\treturn;\n\t}\n\n\t// look up the authorize server's IP\n\tif ( !svs.authorizeAddress.ip[0] && svs.authorizeAddress.type != NA_BAD ) {\n\t\tCom_Printf( \"Resolving %s\\n\", AUTHORIZE_SERVER_NAME );\n\t\tif ( !NET_StringToAdr( AUTHORIZE_SERVER_NAME, &svs.authorizeAddress ) ) {\n\t\t\tCom_Printf( \"Couldn't resolve address\\n\" );\n\t\t\treturn;\n\t\t}\n\t\tsvs.authorizeAddress.port = BigShort( PORT_AUTHORIZE );\n\t\tCom_Printf( \"%s resolved to %i.%i.%i.%i:%i\\n\", AUTHORIZE_SERVER_NAME,\n\t\t\tsvs.authorizeAddress.ip[0], svs.authorizeAddress.ip[1],\n\t\t\tsvs.authorizeAddress.ip[2], svs.authorizeAddress.ip[3],\n\t\t\tBigShort( svs.authorizeAddress.port ) );\n\t}\n\n\t// otherwise send their ip to the authorize server\n\tif ( svs.authorizeAddress.type != NA_BAD ) {\n\t\tNET_OutOfBandPrint( NS_SERVER, svs.authorizeAddress,\n\t\t\t\"banUser %i.%i.%i.%i\", cl->netchan.remoteAddress.ip[0], cl->netchan.remoteAddress.ip[1], \n\t\t\t\t\t\t\t\t   cl->netchan.remoteAddress.ip[2], cl->netchan.remoteAddress.ip[3] );\n\t\tCom_Printf(\"%s was banned from coming back\\n\", cl->name);\n\t}\n}\n\n/*\n==================\nSV_BanNum_f\n\nBan a user from being able to play on this server through the auth\nserver\n==================\n*/\nstatic void SV_BanNum_f( void ) {\n\tclient_t\t*cl;\n\n\t// make sure server is running\n\tif ( !com_sv_running->integer ) {\n\t\tCom_Printf( \"Server is not running.\\n\" );\n\t\treturn;\n\t}\n\n\tif ( Cmd_Argc() != 2 ) {\n\t\tCom_Printf (\"Usage: banClient <client number>\\n\");\n\t\treturn;\n\t}\n\n\tcl = SV_GetPlayerByNum();\n\tif ( !cl ) {\n\t\treturn;\n\t}\n\tif( cl->netchan.remoteAddress.type == NA_LOOPBACK ) {\n\t\tSV_SendServerCommand(NULL, \"print \\\"%s\\\"\", \"Cannot kick host player\\n\");\n\t\treturn;\n\t}\n\n\t// look up the authorize server's IP\n\tif ( !svs.authorizeAddress.ip[0] && svs.authorizeAddress.type != NA_BAD ) {\n\t\tCom_Printf( \"Resolving %s\\n\", AUTHORIZE_SERVER_NAME );\n\t\tif ( !NET_StringToAdr( AUTHORIZE_SERVER_NAME, &svs.authorizeAddress ) ) {\n\t\t\tCom_Printf( \"Couldn't resolve address\\n\" );\n\t\t\treturn;\n\t\t}\n\t\tsvs.authorizeAddress.port = BigShort( PORT_AUTHORIZE );\n\t\tCom_Printf( \"%s resolved to %i.%i.%i.%i:%i\\n\", AUTHORIZE_SERVER_NAME,\n\t\t\tsvs.authorizeAddress.ip[0], svs.authorizeAddress.ip[1],\n\t\t\tsvs.authorizeAddress.ip[2], svs.authorizeAddress.ip[3],\n\t\t\tBigShort( svs.authorizeAddress.port ) );\n\t}\n\n\t// otherwise send their ip to the authorize server\n\tif ( svs.authorizeAddress.type != NA_BAD ) {\n\t\tNET_OutOfBandPrint( NS_SERVER, svs.authorizeAddress,\n\t\t\t\"banUser %i.%i.%i.%i\", cl->netchan.remoteAddress.ip[0], cl->netchan.remoteAddress.ip[1], \n\t\t\t\t\t\t\t\t   cl->netchan.remoteAddress.ip[2], cl->netchan.remoteAddress.ip[3] );\n\t\tCom_Printf(\"%s was banned from coming back\\n\", cl->name);\n\t}\n}\n\n/*\n==================\nSV_KickNum_f\n\nKick a user off of the server  FIXME: move to game\n==================\n*/\nstatic void SV_KickNum_f( void ) {\n\tclient_t\t*cl;\n\n\t// make sure server is running\n\tif ( !com_sv_running->integer ) {\n\t\tCom_Printf( \"Server is not running.\\n\" );\n\t\treturn;\n\t}\n\n\tif ( Cmd_Argc() != 2 ) {\n\t\tCom_Printf (\"Usage: kicknum <client number>\\n\");\n\t\treturn;\n\t}\n\n\tcl = SV_GetPlayerByNum();\n\tif ( !cl ) {\n\t\treturn;\n\t}\n\tif( cl->netchan.remoteAddress.type == NA_LOOPBACK ) {\n\t\tSV_SendServerCommand(NULL, \"print \\\"%s\\\"\", \"Cannot kick host player\\n\");\n\t\treturn;\n\t}\n\n\tSV_DropClient( cl, \"was kicked\" );\n\tcl->lastPacketTime = svs.time;\t// in case there is a funny zombie\n}\n\n/*\n================\nSV_Status_f\n================\n*/\nstatic void SV_Status_f( void ) {\n\tint\t\t\ti, j, l;\n\tclient_t\t*cl;\n\tplayerState_t\t*ps;\n\tconst char\t\t*s;\n\tint\t\t\tping;\n\n\t// make sure server is running\n\tif ( !com_sv_running->integer ) {\n\t\tCom_Printf( \"Server is not running.\\n\" );\n\t\treturn;\n\t}\n\n\tCom_Printf (\"map: %s\\n\", sv_mapname->string );\n\n\tCom_Printf (\"num score ping name            lastmsg address               qport rate\\n\");\n\tCom_Printf (\"--- ----- ---- --------------- ------- --------------------- ----- -----\\n\");\n\tfor (i=0,cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++)\n\t{\n\t\tif (!cl->state)\n\t\t\tcontinue;\n\t\tCom_Printf (\"%3i \", i);\n\t\tps = SV_GameClientNum( i );\n\t\tCom_Printf (\"%5i \", ps->persistant[PERS_SCORE]);\n\n\t\tif (cl->state == CS_CONNECTED)\n\t\t\tCom_Printf (\"CNCT \");\n\t\telse if (cl->state == CS_ZOMBIE)\n\t\t\tCom_Printf (\"ZMBI \");\n\t\telse\n\t\t{\n\t\t\tping = cl->ping < 9999 ? cl->ping : 9999;\n\t\t\tCom_Printf (\"%4i \", ping);\n\t\t}\n\n\t\tCom_Printf (\"%s\", cl->name);\n    // TTimo adding a ^7 to reset the color\n    // NOTE: colored names in status breaks the padding (WONTFIX)\n    Com_Printf (\"^7\");\n\t\tl = 16 - (int)strlen(cl->name);\n\t\tfor (j=0 ; j<l ; j++)\n\t\t\tCom_Printf (\" \");\n\n\t\tCom_Printf (\"%7i \", svs.time - cl->lastPacketTime );\n\n\t\ts = NET_AdrToString( cl->netchan.remoteAddress );\n\t\tCom_Printf (\"%s\", s);\n\t\tl = 22 - (int)strlen(s);\n\t\tfor (j=0 ; j<l ; j++)\n\t\t\tCom_Printf (\" \");\n\t\t\n\t\tCom_Printf (\"%5i\", cl->netchan.qport);\n\n\t\tCom_Printf (\" %5i\", cl->rate);\n\n\t\tCom_Printf (\"\\n\");\n\t}\n\tCom_Printf (\"\\n\");\n}\n\n/*\n==================\nSV_ConSay_f\n==================\n*/\nstatic void SV_ConSay_f(void) {\n\tchar\t*p;\n\tchar\ttext[1024];\n\n\t// make sure server is running\n\tif ( !com_sv_running->integer ) {\n\t\tCom_Printf( \"Server is not running.\\n\" );\n\t\treturn;\n\t}\n\n\tif ( Cmd_Argc () < 2 ) {\n\t\treturn;\n\t}\n\n\tstrcpy (text, \"console: \");\n\tp = Cmd_Args();\n\n\tif ( *p == '\"' ) {\n\t\tp++;\n\t\tp[strlen(p)-1] = 0;\n\t}\n\n\tstrcat(text, p);\n\n\tSV_SendServerCommand(NULL, \"chat \\\"%s\\n\\\"\", text);\n}\n\n\n/*\n==================\nSV_Heartbeat_f\n\nAlso called by SV_DropClient, SV_DirectConnect, and SV_SpawnServer\n==================\n*/\nvoid SV_Heartbeat_f( void ) {\n\tsvs.nextHeartbeatTime = -9999999;\n}\n\n\n/*\n===========\nSV_Serverinfo_f\n\nExamine the serverinfo string\n===========\n*/\nstatic void SV_Serverinfo_f( void ) {\n\tCom_Printf (\"Server info settings:\\n\");\n\tInfo_Print ( Cvar_InfoString( CVAR_SERVERINFO ) );\n}\n\n\n/*\n===========\nSV_Systeminfo_f\n\nExamine or change the serverinfo string\n===========\n*/\nstatic void SV_Systeminfo_f( void ) {\n\tCom_Printf (\"System info settings:\\n\");\n\tInfo_Print ( Cvar_InfoString( CVAR_SYSTEMINFO ) );\n}\n\n\n/*\n===========\nSV_DumpUser_f\n\nExamine all a users info strings FIXME: move to game\n===========\n*/\nstatic void SV_DumpUser_f( void ) {\n\tclient_t\t*cl;\n\n\t// make sure server is running\n\tif ( !com_sv_running->integer ) {\n\t\tCom_Printf( \"Server is not running.\\n\" );\n\t\treturn;\n\t}\n\n\tif ( Cmd_Argc() != 2 ) {\n\t\tCom_Printf (\"Usage: info <userid>\\n\");\n\t\treturn;\n\t}\n\n\tcl = SV_GetPlayerByName();\n\tif ( !cl ) {\n\t\treturn;\n\t}\n\n\tCom_Printf( \"userinfo\\n\" );\n\tCom_Printf( \"--------\\n\" );\n\tInfo_Print( cl->userinfo );\n}\n\n\n/*\n=================\nSV_KillServer\n=================\n*/\nstatic void SV_KillServer_f( void ) {\n\tSV_Shutdown( \"killserver\" );\n}\n\n//===========================================================\n\n/*\n==================\nSV_AddOperatorCommands\n==================\n*/\nvoid SV_AddOperatorCommands( void ) {\n\tstatic qboolean\tinitialized;\n\n\tif ( initialized ) {\n\t\treturn;\n\t}\n\tinitialized = qtrue;\n\n\tCmd_AddCommand (\"heartbeat\", SV_Heartbeat_f);\n\tCmd_AddCommand (\"kick\", SV_Kick_f);\n\tCmd_AddCommand (\"banUser\", SV_Ban_f);\n\tCmd_AddCommand (\"banClient\", SV_BanNum_f);\n\tCmd_AddCommand (\"clientkick\", SV_KickNum_f);\n\tCmd_AddCommand (\"status\", SV_Status_f);\n\tCmd_AddCommand (\"serverinfo\", SV_Serverinfo_f);\n\tCmd_AddCommand (\"systeminfo\", SV_Systeminfo_f);\n\tCmd_AddCommand (\"dumpuser\", SV_DumpUser_f);\n\tCmd_AddCommand (\"map_restart\", SV_MapRestart_f);\n\tCmd_AddCommand (\"sectorlist\", SV_SectorList_f);\n\tCmd_AddCommand (\"map\", SV_Map_f);\n#ifndef PRE_RELEASE_DEMO\n\tCmd_AddCommand (\"devmap\", SV_Map_f);\n\tCmd_AddCommand (\"spmap\", SV_Map_f);\n\tCmd_AddCommand (\"spdevmap\", SV_Map_f);\n#endif\n\tCmd_AddCommand (\"killserver\", SV_KillServer_f);\n\tif( com_dedicated->integer ) {\n\t\tCmd_AddCommand (\"say\", SV_ConSay_f);\n\t}\n}\n\n/*\n==================\nSV_RemoveOperatorCommands\n==================\n*/\nvoid SV_RemoveOperatorCommands( void ) {\n#if 0\n\t// removing these won't let the server start again\n\tCmd_RemoveCommand (\"heartbeat\");\n\tCmd_RemoveCommand (\"kick\");\n\tCmd_RemoveCommand (\"banUser\");\n\tCmd_RemoveCommand (\"banClient\");\n\tCmd_RemoveCommand (\"status\");\n\tCmd_RemoveCommand (\"serverinfo\");\n\tCmd_RemoveCommand (\"systeminfo\");\n\tCmd_RemoveCommand (\"dumpuser\");\n\tCmd_RemoveCommand (\"map_restart\");\n\tCmd_RemoveCommand (\"sectorlist\");\n\tCmd_RemoveCommand (\"say\");\n#endif\n}\n\n"
  },
  {
    "path": "src/engine/server/sv_client.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n// sv_client.c -- server code for dealing with clients\n\n#include \"server.h\"\n\nstatic void SV_CloseDownload( client_t *cl );\n\n/*\n=================\nSV_GetChallenge\n\nA \"getchallenge\" OOB command has been received\nReturns a challenge number that can be used\nin a subsequent connectResponse command.\nWe do this to prevent denial of service attacks that\nflood the server with invalid connection IPs.  With a\nchallenge, they must give a valid IP address.\n\nIf we are authorizing, a challenge request will cause a packet\nto be sent to the authorize server.\n\nWhen an authorizeip is returned, a challenge response will be\nsent to that ip.\n=================\n*/\nvoid SV_GetChallenge( netadr_t from ) {\n\tint\t\ti;\n\tint\t\toldest;\n\tint\t\toldestTime;\n\tchallenge_t\t*challenge;\n\n\t// ignore if we are in single player\n\tif ( Cvar_VariableValue( \"g_gametype\" ) == GT_SINGLE_PLAYER || Cvar_VariableValue(\"ui_singlePlayerActive\")) {\n\t\treturn;\n\t}\n\n\toldest = 0;\n\toldestTime = 0x7fffffff;\n\n\t// see if we already have a challenge for this ip\n\tchallenge = &svs.challenges[0];\n\tfor (i = 0 ; i < MAX_CHALLENGES ; i++, challenge++) {\n\t\tif ( !challenge->connected && NET_CompareAdr( from, challenge->adr ) ) {\n\t\t\tbreak;\n\t\t}\n\t\tif ( challenge->time < oldestTime ) {\n\t\t\toldestTime = challenge->time;\n\t\t\toldest = i;\n\t\t}\n\t}\n\n\tif (i == MAX_CHALLENGES) {\n\t\t// this is the first time this client has asked for a challenge\n\t\tchallenge = &svs.challenges[oldest];\n\n\t\tchallenge->challenge = ( (rand() << 16) ^ rand() ) ^ svs.time;\n\t\tchallenge->adr = from;\n\t\tchallenge->firstTime = svs.time;\n\t\tchallenge->time = svs.time;\n\t\tchallenge->connected = qfalse;\n\t\ti = oldest;\n\t}\n\n\t// if they are on a lan address, send the challengeResponse immediately\n\tif ( Sys_IsLANAddress( from ) ) {\n\t\tchallenge->pingTime = svs.time;\n\t\tNET_OutOfBandPrint( NS_SERVER, from, \"challengeResponse %i\", challenge->challenge );\n\t\treturn;\n\t}\n\n\t// look up the authorize server's IP\n\tif ( !svs.authorizeAddress.ip[0] && svs.authorizeAddress.type != NA_BAD ) {\n\t\tCom_Printf( \"Resolving %s\\n\", AUTHORIZE_SERVER_NAME );\n\t\tif ( !NET_StringToAdr( AUTHORIZE_SERVER_NAME, &svs.authorizeAddress ) ) {\n\t\t\tCom_Printf( \"Couldn't resolve address\\n\" );\n\t\t\treturn;\n\t\t}\n\t\tsvs.authorizeAddress.port = BigShort( PORT_AUTHORIZE );\n\t\tCom_Printf( \"%s resolved to %i.%i.%i.%i:%i\\n\", AUTHORIZE_SERVER_NAME,\n\t\t\tsvs.authorizeAddress.ip[0], svs.authorizeAddress.ip[1],\n\t\t\tsvs.authorizeAddress.ip[2], svs.authorizeAddress.ip[3],\n\t\t\tBigShort( svs.authorizeAddress.port ) );\n\t}\n\n\t// if they have been challenging for a long time and we\n\t// haven't heard anything from the authorize server, go ahead and\n\t// let them in, assuming the id server is down\n\tif ( svs.time - challenge->firstTime > AUTHORIZE_TIMEOUT ) {\n\t\tCom_DPrintf( \"authorize server timed out\\n\" );\n\n\t\tchallenge->pingTime = svs.time;\n\t\tNET_OutOfBandPrint( NS_SERVER, challenge->adr, \n\t\t\t\"challengeResponse %i\", challenge->challenge );\n\t\treturn;\n\t}\n\n\t// otherwise send their ip to the authorize server\n\tif ( svs.authorizeAddress.type != NA_BAD ) {\n\t\tcvar_t\t*fs;\n\t\tchar\tgame[1024];\n\n\t\tCom_DPrintf( \"sending getIpAuthorize for %s\\n\", NET_AdrToString( from ));\n\t\t\n\t\tstrcpy(game, BASEGAME);\n\t\tfs = Cvar_Get (\"fs_game\", \"\", CVAR_INIT|CVAR_SYSTEMINFO );\n\t\tif (fs && fs->string[0] != 0) {\n\t\t\tstrcpy(game, fs->string);\n\t\t}\n\t\t\n\t\t// the 0 is for backwards compatibility with obsolete sv_allowanonymous flags\n\t\t// getIpAuthorize <challenge> <IP> <game> 0 <auth-flag>\n\t\tNET_OutOfBandPrint( NS_SERVER, svs.authorizeAddress,\n\t\t\t\"getIpAuthorize %i %i.%i.%i.%i %s 0 %s\",  svs.challenges[i].challenge,\n\t\t\tfrom.ip[0], from.ip[1], from.ip[2], from.ip[3], game, sv_strictAuth->string );\n\t}\n}\n\n/*\n====================\nSV_AuthorizeIpPacket\n\nA packet has been returned from the authorize server.\nIf we have a challenge adr for that ip, send the\nchallengeResponse to it\n====================\n*/\nvoid SV_AuthorizeIpPacket( netadr_t from ) {\n\tint\t\tchallenge;\n\tint\t\ti;\n\tchar\t*s;\n\tchar\t*r;\n\tchar\tret[1024];\n\n\tif ( !NET_CompareBaseAdr( from, svs.authorizeAddress ) ) {\n\t\tCom_Printf( \"SV_AuthorizeIpPacket: not from authorize server\\n\" );\n\t\treturn;\n\t}\n\n\tchallenge = atoi( Cmd_Argv( 1 ) );\n\n\tfor (i = 0 ; i < MAX_CHALLENGES ; i++) {\n\t\tif ( svs.challenges[i].challenge == challenge ) {\n\t\t\tbreak;\n\t\t}\n\t}\n\tif ( i == MAX_CHALLENGES ) {\n\t\tCom_Printf( \"SV_AuthorizeIpPacket: challenge not found\\n\" );\n\t\treturn;\n\t}\n\n\t// send a packet back to the original client\n\tsvs.challenges[i].pingTime = svs.time;\n\ts = Cmd_Argv( 2 );\n\tr = Cmd_Argv( 3 );\t\t\t// reason\n\n\tif ( !Q_stricmp( s, \"demo\" ) ) {\n\t\tif ( Cvar_VariableValue( \"fs_restrict\" ) ) {\n\t\t\t// a demo client connecting to a demo server\n\t\t\tNET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, \n\t\t\t\t\"challengeResponse %i\", svs.challenges[i].challenge );\n\t\t\treturn;\n\t\t}\n\t\t// they are a demo client trying to connect to a real server\n\t\tNET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, \"print\\nServer is not a demo server\\n\" );\n\t\t// clear the challenge record so it won't timeout and let them through\n\t\tCom_Memset( &svs.challenges[i], 0, sizeof( svs.challenges[i] ) );\n\t\treturn;\n\t}\n\tif ( !Q_stricmp( s, \"accept\" ) ) {\n\t\tNET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, \n\t\t\t\"challengeResponse %i\", svs.challenges[i].challenge );\n\t\treturn;\n\t}\n\tif ( !Q_stricmp( s, \"unknown\" ) ) {\n\t\tif (!r) {\n\t\t\tNET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, \"print\\nAwaiting CD key authorization\\n\" );\n\t\t} else {\n\t\t\tsprintf(ret, \"print\\n%s\\n\", r);\n\t\t\tNET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, ret );\n\t\t}\n\t\t// clear the challenge record so it won't timeout and let them through\n\t\tCom_Memset( &svs.challenges[i], 0, sizeof( svs.challenges[i] ) );\n\t\treturn;\n\t}\n\n\t// authorization failed\n\tif (!r) {\n\t\tNET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, \"print\\nSomeone is using this CD Key\\n\" );\n\t} else {\n\t\tsprintf(ret, \"print\\n%s\\n\", r);\n\t\tNET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, ret );\n\t}\n\n\t// clear the challenge record so it won't timeout and let them through\n\tCom_Memset( &svs.challenges[i], 0, sizeof( svs.challenges[i] ) );\n}\n\n/*\n==================\nSV_DirectConnect\n\nA \"connect\" OOB command has been received\n==================\n*/\n\n#define PB_MESSAGE \"PunkBuster Anti-Cheat software must be installed \" \\\n\t\t\t\t\"and Enabled in order to join this server. An updated game patch can be downloaded from \" \\\n\t\t\t\t\"www.idsoftware.com\"\n\nvoid SV_DirectConnect( netadr_t from ) {\n\tchar\t\tuserinfo[MAX_INFO_STRING];\n\tint\t\t\ti;\n\tclient_t\t*cl, *newcl;\n\tMAC_STATIC client_t\ttemp;\n\tsharedEntity_t *ent;\n\tint\t\t\tclientNum;\n\tint\t\t\tversion;\n\tint\t\t\tqport;\n\tint\t\t\tchallenge;\n\tchar\t\t*password;\n\tint\t\t\tstartIndex;\n\tintptr_t denied;\n\tint\t\t\tcount;\n\n\tCom_DPrintf (\"SVC_DirectConnect ()\\n\");\n\n\tQ_strncpyz( userinfo, Cmd_Argv(1), sizeof(userinfo) );\n\n\tversion = atoi( Info_ValueForKey( userinfo, \"protocol\" ) );\n\tif ( version != PROTOCOL_VERSION ) {\n\t\tNET_OutOfBandPrint( NS_SERVER, from, \"print\\nServer uses protocol version %i.\\n\", PROTOCOL_VERSION );\n\t\tCom_DPrintf (\"    rejected connect from version %i\\n\", version);\n\t\treturn;\n\t}\n\n\tchallenge = atoi( Info_ValueForKey( userinfo, \"challenge\" ) );\n\tqport = atoi( Info_ValueForKey( userinfo, \"qport\" ) );\n\n\t// quick reject\n\tfor (i=0,cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++) {\n\t\tif ( cl->state == CS_FREE ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( NET_CompareBaseAdr( from, cl->netchan.remoteAddress )\n\t\t\t&& ( cl->netchan.qport == qport \n\t\t\t|| from.port == cl->netchan.remoteAddress.port ) ) {\n\t\t\tif (( svs.time - cl->lastConnectTime) \n\t\t\t\t< (sv_reconnectlimit->integer * 1000)) {\n\t\t\t\tCom_DPrintf (\"%s:reconnect rejected : too soon\\n\", NET_AdrToString (from));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// see if the challenge is valid (LAN clients don't need to challenge)\n\tif ( !NET_IsLocalAddress (from) ) {\n\t\tint\t\tping;\n\n\t\tfor (i=0 ; i<MAX_CHALLENGES ; i++) {\n\t\t\tif (NET_CompareAdr(from, svs.challenges[i].adr)) {\n\t\t\t\tif ( challenge == svs.challenges[i].challenge ) {\n\t\t\t\t\tbreak;\t\t// good\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (i == MAX_CHALLENGES) {\n\t\t\tNET_OutOfBandPrint( NS_SERVER, from, \"print\\nNo or bad challenge for address.\\n\" );\n\t\t\treturn;\n\t\t}\n\t\t// force the IP key/value pair so the game can filter based on ip\n\t\tInfo_SetValueForKey( userinfo, \"ip\", NET_AdrToString( from ) );\n\n\t\tping = svs.time - svs.challenges[i].pingTime;\n\t\tCom_Printf( \"Client %i connecting with %i challenge ping\\n\", i, ping );\n\t\tsvs.challenges[i].connected = qtrue;\n\n\t\t// never reject a LAN client based on ping\n\t\tif ( !Sys_IsLANAddress( from ) ) {\n\t\t\tif ( sv_minPing->value && ping < sv_minPing->value ) {\n\t\t\t\t// don't let them keep trying until they get a big delay\n\t\t\t\tNET_OutOfBandPrint( NS_SERVER, from, \"print\\nServer is for high pings only\\n\" );\n\t\t\t\tCom_DPrintf (\"Client %i rejected on a too low ping\\n\", i);\n\t\t\t\t// reset the address otherwise their ping will keep increasing\n\t\t\t\t// with each connect message and they'd eventually be able to connect\n\t\t\t\tsvs.challenges[i].adr.port = 0;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif ( sv_maxPing->value && ping > sv_maxPing->value ) {\n\t\t\t\tNET_OutOfBandPrint( NS_SERVER, from, \"print\\nServer is for low pings only\\n\" );\n\t\t\t\tCom_DPrintf (\"Client %i rejected on a too high ping\\n\", i);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t} else {\n\t\t// force the \"ip\" info key to \"localhost\"\n\t\tInfo_SetValueForKey( userinfo, \"ip\", \"localhost\" );\n\t}\n\n\tnewcl = &temp;\n\tCom_Memset (newcl, 0, sizeof(client_t));\n\n\t// if there is already a slot for this ip, reuse it\n\tfor (i=0,cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++) {\n\t\tif ( cl->state == CS_FREE ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( NET_CompareBaseAdr( from, cl->netchan.remoteAddress )\n\t\t\t&& ( cl->netchan.qport == qport \n\t\t\t|| from.port == cl->netchan.remoteAddress.port ) ) {\n\t\t\tCom_Printf (\"%s:reconnect\\n\", NET_AdrToString (from));\n\t\t\tnewcl = cl;\n\n\t\t\t// this doesn't work because it nukes the players userinfo\n\n//\t\t\t// disconnect the client from the game first so any flags the\n//\t\t\t// player might have are dropped\n//\t\t\tVM_Call( gvm, GAME_CLIENT_DISCONNECT, newcl - svs.clients );\n\t\t\t//\n\t\t\tgoto gotnewcl;\n\t\t}\n\t}\n\n\t// find a client slot\n\t// if \"sv_privateClients\" is set > 0, then that number\n\t// of client slots will be reserved for connections that\n\t// have \"password\" set to the value of \"sv_privatePassword\"\n\t// Info requests will report the maxclients as if the private\n\t// slots didn't exist, to prevent people from trying to connect\n\t// to a full server.\n\t// This is to allow us to reserve a couple slots here on our\n\t// servers so we can play without having to kick people.\n\n\t// check for privateClient password\n\tpassword = Info_ValueForKey( userinfo, \"password\" );\n\tif ( !strcmp( password, sv_privatePassword->string ) ) {\n\t\tstartIndex = 0;\n\t} else {\n\t\t// skip past the reserved slots\n\t\tstartIndex = sv_privateClients->integer;\n\t}\n\n\tnewcl = NULL;\n\tfor ( i = startIndex; i < sv_maxclients->integer ; i++ ) {\n\t\tcl = &svs.clients[i];\n\t\tif (cl->state == CS_FREE) {\n\t\t\tnewcl = cl;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif ( !newcl ) {\n\t\tif ( NET_IsLocalAddress( from ) ) {\n\t\t\tcount = 0;\n\t\t\tfor ( i = startIndex; i < sv_maxclients->integer ; i++ ) {\n\t\t\t\tcl = &svs.clients[i];\n\t\t\t\tif (cl->netchan.remoteAddress.type == NA_BOT) {\n\t\t\t\t\tcount++;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// if they're all bots\n\t\t\tif (count >= sv_maxclients->integer - startIndex) {\n\t\t\t\tSV_DropClient(&svs.clients[sv_maxclients->integer - 1], \"only bots on server\");\n\t\t\t\tnewcl = &svs.clients[sv_maxclients->integer - 1];\n\t\t\t}\n\t\t\telse {\n\t\t\t\tCom_Error( ERR_FATAL, \"server is full on local connect\\n\" );\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tNET_OutOfBandPrint( NS_SERVER, from, \"print\\nServer is full.\\n\" );\n\t\t\tCom_DPrintf (\"Rejected a connection.\\n\");\n\t\t\treturn;\n\t\t}\n\t}\n\n\t// we got a newcl, so reset the reliableSequence and reliableAcknowledge\n\tcl->reliableAcknowledge = 0;\n\tcl->reliableSequence = 0;\n\ngotnewcl:\t\n\t// build a new connection\n\t// accept the new client\n\t// this is the only place a client_t is ever initialized\n\t*newcl = temp;\n\tclientNum = newcl - svs.clients;\n\tent = SV_GentityNum( clientNum );\n\tnewcl->gentity = ent;\n\n\t// save the challenge\n\tnewcl->challenge = challenge;\n\n\t// save the address\n\tNetchan_Setup (NS_SERVER, &newcl->netchan , from, qport);\n\t// init the netchan queue\n\tnewcl->netchan_end_queue = &newcl->netchan_start_queue;\n\n\t// save the userinfo\n\tQ_strncpyz( newcl->userinfo, userinfo, sizeof(newcl->userinfo) );\n\n\t// get the game a chance to reject this connection or modify the userinfo\n\tdenied = VM_Call( gvm, GAME_CLIENT_CONNECT, clientNum, qtrue, qfalse ); // firstTime = qtrue\n\tif ( denied ) {\n\t\t// we can't just use VM_ArgPtr, because that is only valid inside a VM_Call\n\t\tconst char* str = (const char*)VM_ExplicitArgPtr( gvm, denied );\n\t\tNET_OutOfBandPrint( NS_SERVER, from, \"print\\n%s\\n\", str );\n\t\tCom_DPrintf (\"Game rejected a connection: %s.\\n\", str);\n\t\treturn;\n\t}\n\n\tSV_UserinfoChanged( newcl );\n\n\t// send the connect packet to the client\n\tNET_OutOfBandPrint( NS_SERVER, from, \"connectResponse\" );\n\n\tCom_DPrintf( \"Going from CS_FREE to CS_CONNECTED for %s\\n\", newcl->name );\n\n\tnewcl->state = CS_CONNECTED;\n\tnewcl->nextSnapshotTime = svs.time;\n\tnewcl->lastPacketTime = svs.time;\n\tnewcl->lastConnectTime = svs.time;\n\t\n\t// when we receive the first packet from the client, we will\n\t// notice that it is from a different serverid and that the\n\t// gamestate message was not just sent, forcing a retransmit\n\tnewcl->gamestateMessageNum = -1;\n\n\t// if this was the first client on the server, or the last client\n\t// the server can hold, send a heartbeat to the master.\n\tcount = 0;\n\tfor (i=0,cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++) {\n\t\tif ( svs.clients[i].state >= CS_CONNECTED ) {\n\t\t\tcount++;\n\t\t}\n\t}\n\tif ( count == 1 || count == sv_maxclients->integer ) {\n\t\tSV_Heartbeat_f();\n\t}\n}\n\n\n/*\n=====================\nSV_DropClient\n\nCalled when the player is totally leaving the server, either willingly\nor unwillingly.  This is NOT called if the entire server is quiting\nor crashing -- SV_FinalMessage() will handle that\n=====================\n*/\nvoid SV_DropClient( client_t *drop, const char *reason ) {\n\tint\t\ti;\n\tchallenge_t\t*challenge;\n\n\tif ( drop->state == CS_ZOMBIE ) {\n\t\treturn;\t\t// already dropped\n\t}\n\n\tif ( !drop->gentity || !(drop->gentity->r.svFlags & SVF_BOT) ) {\n\t\t// see if we already have a challenge for this ip\n\t\tchallenge = &svs.challenges[0];\n\n\t\tfor (i = 0 ; i < MAX_CHALLENGES ; i++, challenge++) {\n\t\t\tif ( NET_CompareAdr( drop->netchan.remoteAddress, challenge->adr ) ) {\n\t\t\t\tchallenge->connected = qfalse;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Kill any download\n\tSV_CloseDownload( drop );\n\n\t// tell everyone why they got dropped\n\tSV_SendServerCommand( NULL, \"print \\\"%s\" S_COLOR_WHITE \" %s\\n\\\"\", drop->name, reason );\n\n\tCom_DPrintf( \"Going to CS_ZOMBIE for %s\\n\", drop->name );\n\tdrop->state = CS_ZOMBIE;\t\t// become free in a few seconds\n\n\tif (drop->download)\t{\n\t\tFS_FCloseFile( drop->download );\n\t\tdrop->download = 0;\n\t}\n\n\t// call the prog function for removing a client\n\t// this will remove the body, among other things\n\tVM_Call( gvm, GAME_CLIENT_DISCONNECT, drop - svs.clients );\n\n\t// add the disconnect command\n\tSV_SendServerCommand( drop, \"disconnect \\\"%s\\\"\", reason);\n\n\tif ( drop->netchan.remoteAddress.type == NA_BOT ) {\n\t\tSV_BotFreeClient( drop - svs.clients );\n\t}\n\n\t// nuke user info\n\tSV_SetUserinfo( drop - svs.clients, \"\" );\n\n\t// if this was the last client on the server, send a heartbeat\n\t// to the master so it is known the server is empty\n\t// send a heartbeat now so the master will get up to date info\n\t// if there is already a slot for this ip, reuse it\n\tfor (i=0 ; i < sv_maxclients->integer ; i++ ) {\n\t\tif ( svs.clients[i].state >= CS_CONNECTED ) {\n\t\t\tbreak;\n\t\t}\n\t}\n\tif ( i == sv_maxclients->integer ) {\n\t\tSV_Heartbeat_f();\n\t}\n}\n\n/*\n================\nSV_SendClientGameState\n\nSends the first message from the server to a connected client.\nThis will be sent on the initial connection and upon each new map load.\n\nIt will be resent if the client acknowledges a later message but has\nthe wrong gamestate.\n================\n*/\nvoid SV_SendClientGameState( client_t *client ) {\n\tint\t\t\tstart;\n\tentityState_t\t*base, nullstate;\n\tmsg_t\t\tmsg;\n\tbyte\t\tmsgBuffer[MAX_MSGLEN];\n\n \tCom_DPrintf (\"SV_SendClientGameState() for %s\\n\", client->name);\n\tCom_DPrintf( \"Going from CS_CONNECTED to CS_PRIMED for %s\\n\", client->name );\n\tclient->state = CS_PRIMED;\n\tclient->pureAuthentic = 0;\n\tclient->gotCP = qfalse;\n\n\t// when we receive the first packet from the client, we will\n\t// notice that it is from a different serverid and that the\n\t// gamestate message was not just sent, forcing a retransmit\n\tclient->gamestateMessageNum = client->netchan.outgoingSequence;\n\n\tMSG_Init( &msg, msgBuffer, sizeof( msgBuffer ) );\n\n\t// NOTE, MRE: all server->client messages now acknowledge\n\t// let the client know which reliable clientCommands we have received\n\tMSG_WriteLong( &msg, client->lastClientCommand );\n\n\t// send any server commands waiting to be sent first.\n\t// we have to do this cause we send the client->reliableSequence\n\t// with a gamestate and it sets the clc.serverCommandSequence at\n\t// the client side\n\tSV_UpdateServerCommandsToClient( client, &msg );\n\n\t// send the gamestate\n\tMSG_WriteByte( &msg, svc_gamestate );\n\tMSG_WriteLong( &msg, client->reliableSequence );\n\n\t// write the configstrings\n\tfor ( start = 0 ; start < MAX_CONFIGSTRINGS ; start++ ) {\n\t\tif (sv.configstrings[start][0]) {\n\t\t\tMSG_WriteByte( &msg, svc_configstring );\n\t\t\tMSG_WriteShort( &msg, start );\n\t\t\tMSG_WriteBigString( &msg, sv.configstrings[start] );\n\t\t}\n\t}\n\n\t// write the baselines\n\tCom_Memset( &nullstate, 0, sizeof( nullstate ) );\n\tfor ( start = 0 ; start < MAX_GENTITIES; start++ ) {\n\t\tbase = &sv.svEntities[start].baseline;\n\t\tif ( !base->number ) {\n\t\t\tcontinue;\n\t\t}\n\t\tMSG_WriteByte( &msg, svc_baseline );\n\t\tMSG_WriteDeltaEntity( &msg, &nullstate, base, qtrue );\n\t}\n\n\tMSG_WriteByte( &msg, svc_EOF );\n\n\tMSG_WriteLong( &msg, client - svs.clients);\n\n\t// write the checksum feed\n\tMSG_WriteLong( &msg, sv.checksumFeed);\n\n\t// deliver this to the client\n\tSV_SendMessageToClient( &msg, client );\n}\n\n\n/*\n==================\nSV_ClientEnterWorld\n==================\n*/\nvoid SV_ClientEnterWorld( client_t *client, usercmd_t *cmd ) {\n\tint\t\tclientNum;\n\tsharedEntity_t *ent;\n\n\tCom_DPrintf( \"Going from CS_PRIMED to CS_ACTIVE for %s\\n\", client->name );\n\tclient->state = CS_ACTIVE;\n\n\t// set up the entity for the client\n\tclientNum = client - svs.clients;\n\tent = SV_GentityNum( clientNum );\n\tent->s.number = clientNum;\n\tclient->gentity = ent;\n\n\tclient->deltaMessage = -1;\n\tclient->nextSnapshotTime = svs.time;\t// generate a snapshot immediately\n\tclient->lastUsercmd = *cmd;\n\n\t// call the game begin function\n\tVM_Call( gvm, GAME_CLIENT_BEGIN, client - svs.clients );\n}\n\n/*\n============================================================\n\nCLIENT COMMAND EXECUTION\n\n============================================================\n*/\n\n/*\n==================\nSV_CloseDownload\n\nclear/free any download vars\n==================\n*/\nstatic void SV_CloseDownload( client_t *cl ) {\n\tint i;\n\n\t// EOF\n\tif (cl->download) {\n\t\tFS_FCloseFile( cl->download );\n\t}\n\tcl->download = 0;\n\t*cl->downloadName = 0;\n\n\t// Free the temporary buffer space\n\tfor (i = 0; i < MAX_DOWNLOAD_WINDOW; i++) {\n\t\tif (cl->downloadBlocks[i]) {\n\t\t\tZ_Free( cl->downloadBlocks[i] );\n\t\t\tcl->downloadBlocks[i] = NULL;\n\t\t}\n\t}\n\n}\n\n/*\n==================\nSV_StopDownload_f\n\nAbort a download if in progress\n==================\n*/\nvoid SV_StopDownload_f( client_t *cl ) {\n\tif (*cl->downloadName)\n\t\tCom_DPrintf( \"clientDownload: %d : file \\\"%s\\\" aborted\\n\", cl - svs.clients, cl->downloadName );\n\n\tSV_CloseDownload( cl );\n}\n\n/*\n==================\nSV_DoneDownload_f\n\nDownloads are finished\n==================\n*/\nvoid SV_DoneDownload_f( client_t *cl ) {\n\tCom_DPrintf( \"clientDownload: %s Done\\n\", cl->name);\n\t// resend the game state to update any clients that entered during the download\n\tSV_SendClientGameState(cl);\n}\n\n/*\n==================\nSV_NextDownload_f\n\nThe argument will be the last acknowledged block from the client, it should be\nthe same as cl->downloadClientBlock\n==================\n*/\nvoid SV_NextDownload_f( client_t *cl )\n{\n\tint block = atoi( Cmd_Argv(1) );\n\n\tif (block == cl->downloadClientBlock) {\n\t\tCom_DPrintf( \"clientDownload: %d : client acknowledge of block %d\\n\", cl - svs.clients, block );\n\n\t\t// Find out if we are done.  A zero-length block indicates EOF\n\t\tif (cl->downloadBlockSize[cl->downloadClientBlock % MAX_DOWNLOAD_WINDOW] == 0) {\n\t\t\tCom_Printf( \"clientDownload: %d : file \\\"%s\\\" completed\\n\", cl - svs.clients, cl->downloadName );\n\t\t\tSV_CloseDownload( cl );\n\t\t\treturn;\n\t\t}\n\n\t\tcl->downloadSendTime = svs.time;\n\t\tcl->downloadClientBlock++;\n\t\treturn;\n\t}\n\t// We aren't getting an acknowledge for the correct block, drop the client\n\t// FIXME: this is bad... the client will never parse the disconnect message\n\t//\t\t\tbecause the cgame isn't loaded yet\n\tSV_DropClient( cl, \"broken download\" );\n}\n\n/*\n==================\nSV_BeginDownload_f\n==================\n*/\nvoid SV_BeginDownload_f( client_t *cl ) {\n\n\t// Kill any existing download\n\tSV_CloseDownload( cl );\n\n\t// cl->downloadName is non-zero now, SV_WriteDownloadToClient will see this and open\n\t// the file itself\n\tQ_strncpyz( cl->downloadName, Cmd_Argv(1), sizeof(cl->downloadName) );\n}\n\n/*\n==================\nSV_WriteDownloadToClient\n\nCheck to see if the client wants a file, open it if needed and start pumping the client\nFill up msg with data \n==================\n*/\nvoid SV_WriteDownloadToClient( client_t *cl , msg_t *msg )\n{\n\tint curindex;\n\tint rate;\n\tint blockspersnap;\n\tint idPack, missionPack;\n\tchar errorMessage[1024];\n\n\tif (!*cl->downloadName)\n\t\treturn;\t// Nothing being downloaded\n\n\tif (!cl->download) {\n\t\t// We open the file here\n\n\t\tCom_Printf( \"clientDownload: %d : begining \\\"%s\\\"\\n\", cl - svs.clients, cl->downloadName );\n\n\t\tmissionPack = FS_idPak(cl->downloadName, \"missionpack\");\n\t\tidPack = missionPack || FS_idPak(cl->downloadName, \"baseq3\");\n\n\t\tif ( !sv_allowDownload->integer || idPack ||\n\t\t\t( cl->downloadSize = FS_SV_FOpenFileRead( cl->downloadName, &cl->download ) ) <= 0 ) {\n\t\t\t// cannot auto-download file\n\t\t\tif (idPack) {\n\t\t\t\tCom_Printf(\"clientDownload: %d : \\\"%s\\\" cannot download id pk3 files\\n\", cl - svs.clients, cl->downloadName);\n\t\t\t\tif (missionPack) {\n\t\t\t\t\tCom_sprintf(errorMessage, sizeof(errorMessage), \"Cannot autodownload Team Arena file \\\"%s\\\"\\n\"\n\t\t\t\t\t\t\t\t\t\"The Team Arena mission pack can be found in your local game store.\", cl->downloadName);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tCom_sprintf(errorMessage, sizeof(errorMessage), \"Cannot autodownload id pk3 file \\\"%s\\\"\", cl->downloadName);\n\t\t\t\t}\n\t\t\t} else if ( !sv_allowDownload->integer ) {\n\t\t\t\tCom_Printf(\"clientDownload: %d : \\\"%s\\\" download disabled\", cl - svs.clients, cl->downloadName);\n\t\t\t\tif (sv_pure->integer) {\n\t\t\t\t\tCom_sprintf(errorMessage, sizeof(errorMessage), \"Could not download \\\"%s\\\" because autodownloading is disabled on the server.\\n\\n\"\n\t\t\t\t\t\t\t\t\t\t\"You will need to get this file elsewhere before you \"\n\t\t\t\t\t\t\t\t\t\t\"can connect to this pure server.\\n\", cl->downloadName);\n\t\t\t\t} else {\n\t\t\t\t\tCom_sprintf(errorMessage, sizeof(errorMessage), \"Could not download \\\"%s\\\" because autodownloading is disabled on the server.\\n\\n\"\n                    \"The server you are connecting to is not a pure server, \"\n                    \"set autodownload to No in your settings and you might be \"\n                    \"able to join the game anyway.\\n\", cl->downloadName);\n\t\t\t\t}\n\t\t\t} else {\n        // NOTE TTimo this is NOT supposed to happen unless bug in our filesystem scheme?\n        //   if the pk3 is referenced, it must have been found somewhere in the filesystem\n\t\t\t\tCom_Printf(\"clientDownload: %d : \\\"%s\\\" file not found on server\\n\", cl - svs.clients, cl->downloadName);\n\t\t\t\tCom_sprintf(errorMessage, sizeof(errorMessage), \"File \\\"%s\\\" not found on server for autodownloading.\\n\", cl->downloadName);\n\t\t\t}\n\t\t\tMSG_WriteByte( msg, svc_download );\n\t\t\tMSG_WriteShort( msg, 0 ); // client is expecting block zero\n\t\t\tMSG_WriteLong( msg, -1 ); // illegal file size\n\t\t\tMSG_WriteString( msg, errorMessage );\n\n\t\t\t*cl->downloadName = 0;\n\t\t\treturn;\n\t\t}\n \n\t\t// Init\n\t\tcl->downloadCurrentBlock = cl->downloadClientBlock = cl->downloadXmitBlock = 0;\n\t\tcl->downloadCount = 0;\n\t\tcl->downloadEOF = qfalse;\n\t}\n\n\t// Perform any reads that we need to\n\twhile (cl->downloadCurrentBlock - cl->downloadClientBlock < MAX_DOWNLOAD_WINDOW &&\n\t\tcl->downloadSize != cl->downloadCount) {\n\n\t\tcurindex = (cl->downloadCurrentBlock % MAX_DOWNLOAD_WINDOW);\n\n\t\tif (!cl->downloadBlocks[curindex])\n\t\t\tcl->downloadBlocks[curindex] = (unsigned char*) Z_Malloc( MAX_DOWNLOAD_BLKSIZE );\n\n\t\tcl->downloadBlockSize[curindex] = FS_Read( cl->downloadBlocks[curindex], MAX_DOWNLOAD_BLKSIZE, cl->download );\n\n\t\tif (cl->downloadBlockSize[curindex] < 0) {\n\t\t\t// EOF right now\n\t\t\tcl->downloadCount = cl->downloadSize;\n\t\t\tbreak;\n\t\t}\n\n\t\tcl->downloadCount += cl->downloadBlockSize[curindex];\n\n\t\t// Load in next block\n\t\tcl->downloadCurrentBlock++;\n\t}\n\n\t// Check to see if we have eof condition and add the EOF block\n\tif (cl->downloadCount == cl->downloadSize &&\n\t\t!cl->downloadEOF &&\n\t\tcl->downloadCurrentBlock - cl->downloadClientBlock < MAX_DOWNLOAD_WINDOW) {\n\n\t\tcl->downloadBlockSize[cl->downloadCurrentBlock % MAX_DOWNLOAD_WINDOW] = 0;\n\t\tcl->downloadCurrentBlock++;\n\n\t\tcl->downloadEOF = qtrue;  // We have added the EOF block\n\t}\n\n\t// Loop up to window size times based on how many blocks we can fit in the\n\t// client snapMsec and rate\n\n\t// based on the rate, how many bytes can we fit in the snapMsec time of the client\n\t// normal rate / snapshotMsec calculation\n\trate = cl->rate;\n\tif ( sv_maxRate->integer ) {\n\t\tif ( sv_maxRate->integer < 1000 ) {\n\t\t\tCvar_Set( \"sv_MaxRate\", \"1000\" );\n\t\t}\n\t\tif ( sv_maxRate->integer < rate ) {\n\t\t\trate = sv_maxRate->integer;\n\t\t}\n\t}\n\n\tif (!rate) {\n\t\tblockspersnap = 1;\n\t} else {\n\t\tblockspersnap = ( (rate * cl->snapshotMsec) / 1000 + MAX_DOWNLOAD_BLKSIZE ) /\n\t\t\tMAX_DOWNLOAD_BLKSIZE;\n\t}\n\n\tif (blockspersnap < 0)\n\t\tblockspersnap = 1;\n\n\twhile (blockspersnap--) {\n\n\t\t// Write out the next section of the file, if we have already reached our window,\n\t\t// automatically start retransmitting\n\n\t\tif (cl->downloadClientBlock == cl->downloadCurrentBlock)\n\t\t\treturn; // Nothing to transmit\n\n\t\tif (cl->downloadXmitBlock == cl->downloadCurrentBlock) {\n\t\t\t// We have transmitted the complete window, should we start resending?\n\n\t\t\t//FIXME:  This uses a hardcoded one second timeout for lost blocks\n\t\t\t//the timeout should be based on client rate somehow\n\t\t\tif (svs.time - cl->downloadSendTime > 1000)\n\t\t\t\tcl->downloadXmitBlock = cl->downloadClientBlock;\n\t\t\telse\n\t\t\t\treturn;\n\t\t}\n\n\t\t// Send current block\n\t\tcurindex = (cl->downloadXmitBlock % MAX_DOWNLOAD_WINDOW);\n\n\t\tMSG_WriteByte( msg, svc_download );\n\t\tMSG_WriteShort( msg, cl->downloadXmitBlock );\n\n\t\t// block zero is special, contains file size\n\t\tif ( cl->downloadXmitBlock == 0 )\n\t\t\tMSG_WriteLong( msg, cl->downloadSize );\n \n\t\tMSG_WriteShort( msg, cl->downloadBlockSize[curindex] );\n\n\t\t// Write the block\n\t\tif ( cl->downloadBlockSize[curindex] ) {\n\t\t\tMSG_WriteData( msg, cl->downloadBlocks[curindex], cl->downloadBlockSize[curindex] );\n\t\t}\n\n\t\tCom_DPrintf( \"clientDownload: %d : writing block %d\\n\", cl - svs.clients, cl->downloadXmitBlock );\n\n\t\t// Move on to the next block\n\t\t// It will get sent with next snap shot.  The rate will keep us in line.\n\t\tcl->downloadXmitBlock++;\n\n\t\tcl->downloadSendTime = svs.time;\n\t}\n}\n\n/*\n=================\nSV_Disconnect_f\n\nThe client is going to disconnect, so remove the connection immediately  FIXME: move to game?\n=================\n*/\nstatic void SV_Disconnect_f( client_t *cl ) {\n\tSV_DropClient( cl, \"disconnected\" );\n}\n\n/*\n=================\nSV_VerifyPaks_f\n\nIf we are pure, disconnect the client if they do no meet the following conditions:\n\n1. the first two checksums match our view of cgame and ui\n2. there are no any additional checksums that we do not have\n\nThis routine would be a bit simpler with a goto but i abstained\n\n=================\n*/\nstatic void SV_VerifyPaks_f( client_t *cl ) {\n\tint nChkSum1, nChkSum2, nClientPaks, nServerPaks, i, j, nCurArg;\n\tint nClientChkSum[1024];\n\tint nServerChkSum[1024];\n\tconst char *pPaks, *pArg;\n\tqboolean bGood = qtrue;\n\n\t// if we are pure, we \"expect\" the client to load certain things from \n\t// certain pk3 files, namely we want the client to have loaded the\n\t// ui and cgame that we think should be loaded based on the pure setting\n\t//\n\tif ( sv_pure->integer != 0 ) {\n\n\t\tbGood = qtrue;\n\t\tnChkSum1 = nChkSum2 = 0;\n\t\t// we run the game, so determine which cgame and ui the client \"should\" be running\n\t\tbGood = (qboolean) (FS_FileIsInPAK(\"vm/cgame.qvm\", &nChkSum1) == 1);\n\t\tif (bGood)\n\t\t\tbGood = (qboolean) (FS_FileIsInPAK(\"vm/ui.qvm\", &nChkSum2) == 1);\n\n\t\tnClientPaks = Cmd_Argc();\n\n\t\t// start at arg 2 ( skip serverId cl_paks )\n\t\tnCurArg = 1;\n\n\t\tpArg = Cmd_Argv(nCurArg++);\n\t\tif(!pArg) {\n\t\t\tbGood = qfalse;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=475\n\t\t\t// we may get incoming cp sequences from a previous checksumFeed, which we need to ignore\n\t\t\t// since serverId is a frame count, it always goes up\n\t\t\tif (atoi(pArg) < sv.checksumFeedServerId)\n\t\t\t{\n\t\t\t\tCom_DPrintf(\"ignoring outdated cp command from client %s\\n\", cl->name);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\n\t\t// we basically use this while loop to avoid using 'goto' :)\n\t\twhile (bGood) {\n\n\t\t\t// must be at least 6: \"cl_paks cgame ui @ firstref ... numChecksums\"\n\t\t\t// numChecksums is encoded\n\t\t\tif (nClientPaks < 6) {\n\t\t\t\tbGood = qfalse;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t// verify first to be the cgame checksum\n\t\t\tpArg = Cmd_Argv(nCurArg++);\n\t\t\tif (!pArg || *pArg == '@' || atoi(pArg) != nChkSum1 ) {\n\t\t\t\tbGood = qfalse;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t// verify the second to be the ui checksum\n\t\t\tpArg = Cmd_Argv(nCurArg++);\n\t\t\tif (!pArg || *pArg == '@' || atoi(pArg) != nChkSum2 ) {\n\t\t\t\tbGood = qfalse;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t// should be sitting at the delimeter now\n\t\t\tpArg = Cmd_Argv(nCurArg++);\n\t\t\tif (*pArg != '@') {\n\t\t\t\tbGood = qfalse;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t// store checksums since tokenization is not re-entrant\n\t\t\tfor (i = 0; nCurArg < nClientPaks; i++) {\n\t\t\t\tnClientChkSum[i] = atoi(Cmd_Argv(nCurArg++));\n\t\t\t}\n\n\t\t\t// store number to compare against (minus one cause the last is the number of checksums)\n\t\t\tnClientPaks = i - 1;\n\n\t\t\t// make sure none of the client check sums are the same\n\t\t\t// so the client can't send 5 the same checksums\n\t\t\tfor (i = 0; i < nClientPaks; i++) {\n\t\t\t\tfor (j = 0; j < nClientPaks; j++) {\n\t\t\t\t\tif (i == j)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif (nClientChkSum[i] == nClientChkSum[j]) {\n\t\t\t\t\t\tbGood = qfalse;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (bGood == qfalse)\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (bGood == qfalse)\n\t\t\t\tbreak;\n\n\t\t\t// get the pure checksums of the pk3 files loaded by the server\n\t\t\tpPaks = FS_LoadedPakPureChecksums();\n\t\t\tCmd_TokenizeString( pPaks );\n\t\t\tnServerPaks = Cmd_Argc();\n\t\t\tif (nServerPaks > 1024)\n\t\t\t\tnServerPaks = 1024;\n\n\t\t\tfor (i = 0; i < nServerPaks; i++) {\n\t\t\t\tnServerChkSum[i] = atoi(Cmd_Argv(i));\n\t\t\t}\n\n\t\t\t// check if the client has provided any pure checksums of pk3 files not loaded by the server\n\t\t\tfor (i = 0; i < nClientPaks; i++) {\n\t\t\t\tfor (j = 0; j < nServerPaks; j++) {\n\t\t\t\t\tif (nClientChkSum[i] == nServerChkSum[j]) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (j >= nServerPaks) {\n\t\t\t\t\tbGood = qfalse;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif ( bGood == qfalse ) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// check if the number of checksums was correct\n\t\t\tnChkSum1 = sv.checksumFeed;\n\t\t\tfor (i = 0; i < nClientPaks; i++) {\n\t\t\t\tnChkSum1 ^= nClientChkSum[i];\n\t\t\t}\n\t\t\tnChkSum1 ^= nClientPaks;\n\t\t\tif (nChkSum1 != nClientChkSum[nClientPaks]) {\n\t\t\t\tbGood = qfalse;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// break out\n\t\t\tbreak;\n\t\t}\n\n\t\tcl->gotCP = qtrue;\n\n\t\tif (bGood) {\n\t\t\tcl->pureAuthentic = 1;\n\t\t} \n\t\telse {\n\t\t\tcl->pureAuthentic = 0;\n\t\t\tcl->nextSnapshotTime = -1;\n\t\t\tcl->state = CS_ACTIVE;\n\t\t\tSV_SendClientSnapshot( cl );\n\t\t\tSV_DropClient( cl, \"Unpure client detected. Invalid .PK3 files referenced!\" );\n\t\t}\n\t}\n}\n\n/*\n=================\nSV_ResetPureClient_f\n=================\n*/\nstatic void SV_ResetPureClient_f( client_t *cl ) {\n\tcl->pureAuthentic = 0;\n\tcl->gotCP = qfalse;\n}\n\n/*\n=================\nSV_UserinfoChanged\n\nPull specific info from a newly changed userinfo string\ninto a more C friendly form.\n=================\n*/\nvoid SV_UserinfoChanged( client_t *cl ) {\n\tchar\t*val;\n\tint\t\ti;\n\n\t// name for C code\n\tQ_strncpyz( cl->name, Info_ValueForKey (cl->userinfo, \"name\"), sizeof(cl->name) );\n\n\t// rate command\n\n\t// if the client is on the same subnet as the server and we aren't running an\n\t// internet public server, assume they don't need a rate choke\n\tif ( Sys_IsLANAddress( cl->netchan.remoteAddress ) && com_dedicated->integer != 2 && sv_lanForceRate->integer == 1) {\n\t\tcl->rate = 99999;\t// lans should not rate limit\n\t} else {\n\t\tval = Info_ValueForKey (cl->userinfo, \"rate\");\n\t\tif (strlen(val)) {\n\t\t\ti = atoi(val);\n\t\t\tcl->rate = i;\n\t\t\tif (cl->rate < 1000) {\n\t\t\t\tcl->rate = 1000;\n\t\t\t} else if (cl->rate > 90000) {\n\t\t\t\tcl->rate = 90000;\n\t\t\t}\n\t\t} else {\n\t\t\tcl->rate = 3000;\n\t\t}\n\t}\n\tval = Info_ValueForKey (cl->userinfo, \"handicap\");\n\tif (strlen(val)) {\n\t\ti = atoi(val);\n\t\tif (i<=0 || i>100 || (int)strlen(val) > 4) {\n\t\t\tInfo_SetValueForKey( cl->userinfo, \"handicap\", \"100\" );\n\t\t}\n\t}\n\n\t// snaps command\n\tval = Info_ValueForKey (cl->userinfo, \"snaps\");\n\tif (strlen(val)) {\n\t\ti = atoi(val);\n\t\tif ( i < 1 ) {\n\t\t\ti = 1;\n\t\t} else if ( i > 30 ) {\n\t\t\ti = 30;\n\t\t}\n\t\tcl->snapshotMsec = 1000/i;\n\t} else {\n\t\tcl->snapshotMsec = 50;\n\t}\n\t\n\t// TTimo\n\t// maintain the IP information\n\t// this is set in SV_DirectConnect (directly on the server, not transmitted), may be lost when client updates it's userinfo\n\t// the banning code relies on this being consistently present\n\tval = Info_ValueForKey (cl->userinfo, \"ip\");\n\tif (!val[0])\n\t{\n\t\t//Com_DPrintf(\"Maintain IP in userinfo for '%s'\\n\", cl->name);\n\t\tif ( !NET_IsLocalAddress(cl->netchan.remoteAddress) )\n\t\t\tInfo_SetValueForKey( cl->userinfo, \"ip\", NET_AdrToString( cl->netchan.remoteAddress ) );\n\t\telse\n\t\t\t// force the \"ip\" info key to \"localhost\" for local clients\n\t\t\tInfo_SetValueForKey( cl->userinfo, \"ip\", \"localhost\" );\n\t}\n}\n\n\n/*\n==================\nSV_UpdateUserinfo_f\n==================\n*/\nstatic void SV_UpdateUserinfo_f( client_t *cl ) {\n\tQ_strncpyz( cl->userinfo, Cmd_Argv(1), sizeof(cl->userinfo) );\n\n\tSV_UserinfoChanged( cl );\n\t// call prog code to allow overrides\n\tVM_Call( gvm, GAME_CLIENT_USERINFO_CHANGED, cl - svs.clients );\n}\n\ntypedef struct {\n\tchar\t*name;\n\tvoid\t(*func)( client_t *cl );\n} ucmd_t;\n\nstatic ucmd_t ucmds[] = {\n\t{\"userinfo\", SV_UpdateUserinfo_f},\n\t{\"disconnect\", SV_Disconnect_f},\n\t{\"cp\", SV_VerifyPaks_f},\n\t{\"vdr\", SV_ResetPureClient_f},\n\t{\"download\", SV_BeginDownload_f},\n\t{\"nextdl\", SV_NextDownload_f},\n\t{\"stopdl\", SV_StopDownload_f},\n\t{\"donedl\", SV_DoneDownload_f},\n\n\t{NULL, NULL}\n};\n\n/*\n==================\nSV_ExecuteClientCommand\n\nAlso called by bot code\n==================\n*/\nvoid SV_ExecuteClientCommand( client_t *cl, const char *s, qboolean clientOK ) {\n\tucmd_t\t*u;\n\tqboolean bProcessed = qfalse;\n\t\n\tCmd_TokenizeString( s );\n\n\t// see if it is a server level command\n\tfor (u=ucmds ; u->name ; u++) {\n\t\tif (!strcmp (Cmd_Argv(0), u->name) ) {\n\t\t\tu->func( cl );\n\t\t\tbProcessed = qtrue;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (clientOK) {\n\t\t// pass unknown strings to the game\n\t\tif (!u->name && sv.state == SS_GAME) {\n\t\t\tVM_Call( gvm, GAME_CLIENT_COMMAND, cl - svs.clients );\n\t\t}\n\t}\n\telse if (!bProcessed)\n\t\tCom_DPrintf( \"client text ignored for %s: %s\\n\", cl->name, Cmd_Argv(0) );\n}\n\n/*\n===============\nSV_ClientCommand\n===============\n*/\nstatic qboolean SV_ClientCommand( client_t *cl, msg_t *msg ) {\n\tint\t\tseq;\n\tconst char\t*s;\n\tqboolean clientOk = qtrue;\n\n\tseq = MSG_ReadLong( msg );\n\ts = MSG_ReadString( msg );\n\n\t// see if we have already executed it\n\tif ( cl->lastClientCommand >= seq ) {\n\t\treturn qtrue;\n\t}\n\n\tCom_DPrintf( \"clientCommand: %s : %i : %s\\n\", cl->name, seq, s );\n\n\t// drop the connection if we have somehow lost commands\n\tif ( seq > cl->lastClientCommand + 1 ) {\n\t\tCom_Printf( \"Client %s lost %i clientCommands\\n\", cl->name, \n\t\t\tseq - cl->lastClientCommand + 1 );\n\t\tSV_DropClient( cl, \"Lost reliable commands\" );\n\t\treturn qfalse;\n\t}\n\n\t// malicious users may try using too many string commands\n\t// to lag other players.  If we decide that we want to stall\n\t// the command, we will stop processing the rest of the packet,\n\t// including the usercmd.  This causes flooders to lag themselves\n\t// but not other people\n\t// We don't do this when the client hasn't been active yet since its\n\t// normal to spam a lot of commands when downloading\n\tif ( !com_cl_running->integer && \n\t\tcl->state >= CS_ACTIVE &&\n\t\tsv_floodProtect->integer && \n\t\tsvs.time < cl->nextReliableTime ) {\n\t\t// ignore any other text messages from this client but let them keep playing\n\t\t// TTimo - moved the ignored verbose to the actual processing in SV_ExecuteClientCommand, only printing if the core doesn't intercept\n\t\tclientOk = qfalse;\n\t} \n\n\t// don't allow another command for one second\n\tcl->nextReliableTime = svs.time + 1000;\n\n\tSV_ExecuteClientCommand( cl, s, clientOk );\n\n\tcl->lastClientCommand = seq;\n\tCom_sprintf(cl->lastClientCommandString, sizeof(cl->lastClientCommandString), \"%s\", s);\n\n\treturn qtrue;\t\t// continue procesing\n}\n\n\n//==================================================================================\n\n\n/*\n==================\nSV_ClientThink\n\nAlso called by bot code\n==================\n*/\nvoid SV_ClientThink (client_t *cl, usercmd_t *cmd) {\n\tcl->lastUsercmd = *cmd;\n\n\tif ( cl->state != CS_ACTIVE ) {\n\t\treturn;\t\t// may have been kicked during the last usercmd\n\t}\n\n\tVM_Call( gvm, GAME_CLIENT_THINK, cl - svs.clients );\n}\n\n/*\n==================\nSV_UserMove\n\nThe message usually contains all the movement commands \nthat were in the last three packets, so that the information\nin dropped packets can be recovered.\n\nOn very fast clients, there may be multiple usercmd packed into\neach of the backup packets.\n==================\n*/\nstatic void SV_UserMove( client_t *cl, msg_t *msg, qboolean delta ) {\n\tint\t\t\ti, key;\n\tint\t\t\tcmdCount;\n\tusercmd_t\tnullcmd;\n\tusercmd_t\tcmds[MAX_PACKET_USERCMDS];\n\tusercmd_t\t*cmd, *oldcmd;\n\n\tif ( delta ) {\n\t\tcl->deltaMessage = cl->messageAcknowledge;\n\t} else {\n\t\tcl->deltaMessage = -1;\n\t}\n\n\tcmdCount = MSG_ReadByte( msg );\n\n\tif ( cmdCount < 1 ) {\n\t\tCom_Printf( \"cmdCount < 1\\n\" );\n\t\treturn;\n\t}\n\n\tif ( cmdCount > MAX_PACKET_USERCMDS ) {\n\t\tCom_Printf( \"cmdCount > MAX_PACKET_USERCMDS\\n\" );\n\t\treturn;\n\t}\n\n\t// use the checksum feed in the key\n\tkey = sv.checksumFeed;\n\t// also use the message acknowledge\n\tkey ^= cl->messageAcknowledge;\n\t// also use the last acknowledged server command in the key\n\tkey ^= Com_HashKey(cl->reliableCommands[ cl->reliableAcknowledge & (MAX_RELIABLE_COMMANDS-1) ], 32);\n\n\tCom_Memset( &nullcmd, 0, sizeof(nullcmd) );\n\toldcmd = &nullcmd;\n\tfor ( i = 0 ; i < cmdCount ; i++ ) {\n\t\tcmd = &cmds[i];\n\t\tMSG_ReadDeltaUsercmdKey( msg, key, oldcmd, cmd );\n\t\toldcmd = cmd;\n\t}\n\n\t// save time for ping calculation\n\tcl->frames[ cl->messageAcknowledge & PACKET_MASK ].messageAcked = svs.time;\n\n\t// TTimo\n\t// catch the no-cp-yet situation before SV_ClientEnterWorld\n\t// if CS_ACTIVE, then it's time to trigger a new gamestate emission\n\t// if not, then we are getting remaining parasite usermove commands, which we should ignore\n\tif (sv_pure->integer != 0 && cl->pureAuthentic == 0 && !cl->gotCP) {\n\t\tif (cl->state == CS_ACTIVE)\n\t\t{\n\t\t\t// we didn't get a cp yet, don't assume anything and just send the gamestate all over again\n\t\t\tCom_DPrintf( \"%s: didn't get cp command, resending gamestate\\n\", cl->name, cl->state );\n\t\t\tSV_SendClientGameState( cl );\n\t\t}\n\t\treturn;\n\t}\t\t\t\n\t\n\t// if this is the first usercmd we have received\n\t// this gamestate, put the client into the world\n\tif ( cl->state == CS_PRIMED ) {\n\t\tSV_ClientEnterWorld( cl, &cmds[0] );\n\t\t// the moves can be processed normaly\n\t}\n\t\n\t// a bad cp command was sent, drop the client\n\tif (sv_pure->integer != 0 && cl->pureAuthentic == 0) {\t\t\n\t\tSV_DropClient( cl, \"Cannot validate pure client!\");\n\t\treturn;\n\t}\n\n\tif ( cl->state != CS_ACTIVE ) {\n\t\tcl->deltaMessage = -1;\n\t\treturn;\n\t}\n\n\t// usually, the first couple commands will be duplicates\n\t// of ones we have previously received, but the servertimes\n\t// in the commands will cause them to be immediately discarded\n\tfor ( i =  0 ; i < cmdCount ; i++ ) {\n\t\t// if this is a cmd from before a map_restart ignore it\n\t\tif ( cmds[i].serverTime > cmds[cmdCount-1].serverTime ) {\n\t\t\tcontinue;\n\t\t}\n\t\t// extremely lagged or cmd from before a map_restart\n\t\t//if ( cmds[i].serverTime > svs.time + 3000 ) {\n\t\t//\tcontinue;\n\t\t//}\n\t\t// don't execute if this is an old cmd which is already executed\n\t\t// these old cmds are included when cl_packetdup > 0\n\t\tif ( cmds[i].serverTime <= cl->lastUsercmd.serverTime ) {\n\t\t\tcontinue;\n\t\t}\n\t\tSV_ClientThink (cl, &cmds[ i ]);\n\t}\n}\n\n\n/*\n===========================================================================\n\nUSER CMD EXECUTION\n\n===========================================================================\n*/\n\n/*\n===================\nSV_ExecuteClientMessage\n\nParse a client packet\n===================\n*/\nvoid SV_ExecuteClientMessage( client_t *cl, msg_t *msg ) {\n\tint\t\t\tc;\n\tint\t\t\tserverId;\n\n\tMSG_Bitstream(msg);\n\n\tserverId = MSG_ReadLong( msg );\n\tcl->messageAcknowledge = MSG_ReadLong( msg );\n\n\tif (cl->messageAcknowledge < 0) {\n\t\t// usually only hackers create messages like this\n\t\t// it is more annoying for them to let them hanging\n#ifndef NDEBUG\n\t\tSV_DropClient( cl, \"DEBUG: illegible client message\" );\n#endif\n\t\treturn;\n\t}\n\n\tcl->reliableAcknowledge = MSG_ReadLong( msg );\n\n\t// NOTE: when the client message is fux0red the acknowledgement numbers\n\t// can be out of range, this could cause the server to send thousands of server\n\t// commands which the server thinks are not yet acknowledged in SV_UpdateServerCommandsToClient\n\tif (cl->reliableAcknowledge < cl->reliableSequence - MAX_RELIABLE_COMMANDS) {\n\t\t// usually only hackers create messages like this\n\t\t// it is more annoying for them to let them hanging\n#ifndef NDEBUG\n\t\tSV_DropClient( cl, \"DEBUG: illegible client message\" );\n#endif\n\t\tcl->reliableAcknowledge = cl->reliableSequence;\n\t\treturn;\n\t}\n\t// if this is a usercmd from a previous gamestate,\n\t// ignore it or retransmit the current gamestate\n\t// \n\t// if the client was downloading, let it stay at whatever serverId and\n\t// gamestate it was at.  This allows it to keep downloading even when\n\t// the gamestate changes.  After the download is finished, we'll\n\t// notice and send it a new game state\n\t//\n\t// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=536\n\t// don't drop as long as previous command was a nextdl, after a dl is done, downloadName is set back to \"\"\n\t// but we still need to read the next message to move to next download or send gamestate\n\t// I don't like this hack though, it must have been working fine at some point, suspecting the fix is somewhere else\n\tif ( serverId != sv.serverId && !*cl->downloadName && !strstr(cl->lastClientCommandString, \"nextdl\") ) {\n\t\tif ( serverId >= sv.restartedServerId && serverId < sv.serverId ) { // TTimo - use a comparison here to catch multiple map_restart\n\t\t\t// they just haven't caught the map_restart yet\n\t\t\tCom_DPrintf(\"%s : ignoring pre map_restart / outdated client message\\n\", cl->name);\n\t\t\treturn;\n\t\t}\n\t\t// if we can tell that the client has dropped the last\n\t\t// gamestate we sent them, resend it\n\t\tif ( cl->messageAcknowledge > cl->gamestateMessageNum ) {\n\t\t\tCom_DPrintf( \"%s : dropped gamestate, resending\\n\", cl->name );\n\t\t\tSV_SendClientGameState( cl );\n\t\t}\n\t\treturn;\n\t}\n\n\t// read optional clientCommand strings\n\tdo {\n\t\tc = MSG_ReadByte( msg );\n\t\tif ( c == clc_EOF ) {\n\t\t\tbreak;\n\t\t}\n\t\tif ( c != clc_clientCommand ) {\n\t\t\tbreak;\n\t\t}\n\t\tif ( !SV_ClientCommand( cl, msg ) ) {\n\t\t\treturn;\t// we couldn't execute it because of the flood protection\n\t\t}\n\t\tif (cl->state == CS_ZOMBIE) {\n\t\t\treturn;\t// disconnect command\n\t\t}\n\t} while ( 1 );\n\n\t// read the usercmd_t\n\tif ( c == clc_move ) {\n\t\tSV_UserMove( cl, msg, qtrue );\n\t} else if ( c == clc_moveNoDelta ) {\n\t\tSV_UserMove( cl, msg, qfalse );\n\t} else if ( c != clc_EOF ) {\n\t\tCom_Printf( \"WARNING: bad command byte for client %i\\n\", cl - svs.clients );\n\t}\n//\tif ( msg->readcount != msg->cursize ) {\n//\t\tCom_Printf( \"WARNING: Junk at end of packet for client %i\\n\", cl - svs.clients );\n//\t}\n}\n"
  },
  {
    "path": "src/engine/server/sv_game.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n// sv_game.c -- interface to the game dll\n\n#include \"server.h\"\n\n#include \"../../game/botlib.h\"\n\nbotlib_export_t\t*botlib_export;\n\nvoid SV_GameError( const char *string ) {\n\tCom_Error( ERR_DROP, \"%s\", string );\n}\n\nvoid SV_GamePrint( const char *string ) {\n\tCom_Printf( \"%s\", string );\n}\n\n// these functions must be used instead of pointer arithmetic, because\n// the game allocates gentities with private information after the server shared part\nint\tSV_NumForGentity( sharedEntity_t *ent ) {\n\tint\t\tnum;\n\n\tnum = ( (byte *)ent - (byte *)sv.gentities ) / sv.gentitySize;\n\n\treturn num;\n}\n\nsharedEntity_t *SV_GentityNum( int num ) {\n\tsharedEntity_t *ent;\n\n\tent = (sharedEntity_t *)((byte *)sv.gentities + sv.gentitySize*(num));\n\n\treturn ent;\n}\n\nplayerState_t *SV_GameClientNum( int num ) {\n\tplayerState_t\t*ps;\n\n\tps = (playerState_t *)((byte *)sv.gameClients + sv.gameClientSize*(num));\n\n\treturn ps;\n}\n\nsvEntity_t\t*SV_SvEntityForGentity( sharedEntity_t *gEnt ) {\n\tif ( !gEnt || gEnt->s.number < 0 || gEnt->s.number >= MAX_GENTITIES ) {\n\t\tCom_Error( ERR_DROP, \"SV_SvEntityForGentity: bad gEnt\" );\n\t}\n\treturn &sv.svEntities[ gEnt->s.number ];\n}\n\nsharedEntity_t *SV_GEntityForSvEntity( svEntity_t *svEnt ) {\n\tint\t\tnum;\n\n\tnum = svEnt - sv.svEntities;\n\treturn SV_GentityNum( num );\n}\n\n/*\n===============\nSV_GameSendServerCommand\n\nSends a command string to a client\n===============\n*/\nvoid SV_GameSendServerCommand( int clientNum, const char *text ) {\n\tif ( clientNum == -1 ) {\n\t\tSV_SendServerCommand( NULL, \"%s\", text );\n\t} else {\n\t\tif ( clientNum < 0 || clientNum >= sv_maxclients->integer ) {\n\t\t\treturn;\n\t\t}\n\t\tSV_SendServerCommand( svs.clients + clientNum, \"%s\", text );\t\n\t}\n}\n\n\n/*\n===============\nSV_GameDropClient\n\nDisconnects the client with a message\n===============\n*/\nvoid SV_GameDropClient( int clientNum, const char *reason ) {\n\tif ( clientNum < 0 || clientNum >= sv_maxclients->integer ) {\n\t\treturn;\n\t}\n\tSV_DropClient( svs.clients + clientNum, reason );\t\n}\n\n\n/*\n=================\nSV_SetBrushModel\n\nsets mins and maxs for inline bmodels\n=================\n*/\nvoid SV_SetBrushModel( sharedEntity_t *ent, const char *name ) {\n\tclipHandle_t\th;\n\tvec3_t\t\t\tmins, maxs;\n\n\tif (!name) {\n\t\tCom_Error( ERR_DROP, \"SV_SetBrushModel: NULL\" );\n\t}\n\n\tif (name[0] != '*') {\n\t\tCom_Error( ERR_DROP, \"SV_SetBrushModel: %s isn't a brush model\", name );\n\t}\n\n\n\tent->s.modelindex = atoi( name + 1 );\n\n\th = CM_InlineModel( ent->s.modelindex );\n\tCM_ModelBounds( h, mins, maxs );\n\tVectorCopy (mins, ent->r.mins);\n\tVectorCopy (maxs, ent->r.maxs);\n\tent->r.bmodel = qtrue;\n\n\tent->r.contents = -1;\t\t// we don't know exactly what is in the brushes\n\n\tSV_LinkEntity( ent );\t\t// FIXME: remove\n}\n\n\n\n/*\n=================\nSV_inPVS\n\nAlso checks portalareas so that doors block sight\n=================\n*/\nqboolean SV_inPVS (const vec3_t p1, const vec3_t p2)\n{\n\tint\t\tleafnum;\n\tint\t\tcluster;\n\tint\t\tarea1, area2;\n\tbyte\t*mask;\n\n\tleafnum = CM_PointLeafnum (p1);\n\tcluster = CM_LeafCluster (leafnum);\n\tarea1 = CM_LeafArea (leafnum);\n\tmask = CM_ClusterPVS (cluster);\n\n\tleafnum = CM_PointLeafnum (p2);\n\tcluster = CM_LeafCluster (leafnum);\n\tarea2 = CM_LeafArea (leafnum);\n\tif ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) )\n\t\treturn qfalse;\n\tif (!CM_AreasConnected (area1, area2))\n\t\treturn qfalse;\t\t// a door blocks sight\n\treturn qtrue;\n}\n\n\n/*\n=================\nSV_inPVSIgnorePortals\n\nDoes NOT check portalareas\n=================\n*/\nqboolean SV_inPVSIgnorePortals( const vec3_t p1, const vec3_t p2)\n{\n\tint\t\tleafnum;\n\tint\t\tcluster;\n\tint\t\tarea1, area2;\n\tbyte\t*mask;\n\n\tleafnum = CM_PointLeafnum (p1);\n\tcluster = CM_LeafCluster (leafnum);\n\tarea1 = CM_LeafArea (leafnum);\n\tmask = CM_ClusterPVS (cluster);\n\n\tleafnum = CM_PointLeafnum (p2);\n\tcluster = CM_LeafCluster (leafnum);\n\tarea2 = CM_LeafArea (leafnum);\n\n\tif ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) )\n\t\treturn qfalse;\n\n\treturn qtrue;\n}\n\n\n/*\n========================\nSV_AdjustAreaPortalState\n========================\n*/\nvoid SV_AdjustAreaPortalState( sharedEntity_t *ent, qboolean open ) {\n\tsvEntity_t\t*svEnt;\n\n\tsvEnt = SV_SvEntityForGentity( ent );\n\tif ( svEnt->areanum2 == -1 ) {\n\t\treturn;\n\t}\n\tCM_AdjustAreaPortalState( svEnt->areanum, svEnt->areanum2, open );\n}\n\n\n/*\n==================\nSV_GameAreaEntities\n==================\n*/\nqboolean\tSV_EntityContact( vec3_t mins, vec3_t maxs, const sharedEntity_t *gEnt, int capsule ) {\n\tconst float\t*origin, *angles;\n\tclipHandle_t\tch;\n\ttrace_t\t\t\ttrace;\n\n\t// check for exact collision\n\torigin = gEnt->r.currentOrigin;\n\tangles = gEnt->r.currentAngles;\n\n\tch = SV_ClipHandleForEntity( gEnt );\n\tCM_TransformedBoxTrace ( &trace, vec3_origin, vec3_origin, mins, maxs,\n\t\tch, -1, origin, angles, capsule );\n\n\treturn trace.startsolid;\n}\n\n\n/*\n===============\nSV_GetServerinfo\n\n===============\n*/\nvoid SV_GetServerinfo( char *buffer, int bufferSize ) {\n\tif ( bufferSize < 1 ) {\n\t\tCom_Error( ERR_DROP, \"SV_GetServerinfo: bufferSize == %i\", bufferSize );\n\t}\n\tQ_strncpyz( buffer, Cvar_InfoString( CVAR_SERVERINFO ), bufferSize );\n}\n\n/*\n===============\nSV_LocateGameData\n\n===============\n*/\nvoid SV_LocateGameData( sharedEntity_t *gEnts, int numGEntities, int sizeofGEntity_t,\n\t\t\t\t\t   playerState_t *clients, int sizeofGameClient ) {\n\tsv.gentities = gEnts;\n\tsv.gentitySize = sizeofGEntity_t;\n\tsv.num_entities = numGEntities;\n\n\tsv.gameClients = clients;\n\tsv.gameClientSize = sizeofGameClient;\n}\n\n\n/*\n===============\nSV_GetUsercmd\n\n===============\n*/\nvoid SV_GetUsercmd( int clientNum, usercmd_t *cmd ) {\n\tif ( clientNum < 0 || clientNum >= sv_maxclients->integer ) {\n\t\tCom_Error( ERR_DROP, \"SV_GetUsercmd: bad clientNum:%i\", clientNum );\n\t}\n\t*cmd = svs.clients[clientNum].lastUsercmd;\n}\n\n//==============================================\n\nstatic int\tFloatAsInt( float f ) {\n\tunion\n\t{\n\t    int i;\n\t    float f;\n\t} temp;\n\t\n\ttemp.f = f;\n\treturn temp.i;\n}\n\n/*\n====================\nSV_GameSystemCalls\n\nThe module is making a system call\n====================\n*/\n#define\tVMA(x) VM_ArgPtr(args[x])\n#define\tVMF(x) (*(float*)&args[x])\n\nintptr_t SV_GameSystemCalls( intptr_t *args ) {\n\tswitch( args[0] ) {\n\tcase G_PRINT:\n\t\tCom_Printf( \"%s\", VMA(1) );\n\t\treturn 0;\n\tcase G_ERROR:\n\t\tCom_Error( ERR_DROP, \"%s\", VMA(1) );\n\t\treturn 0;\n\tcase G_MILLISECONDS:\n\t\treturn Sys_Milliseconds();\n\tcase G_CVAR_REGISTER:\n\t\tCvar_Register( (vmCvar_t*) VMA(1), (const char*) VMA(2), (const char*) VMA(3), args[4] ); \n\t\treturn 0;\n\tcase G_CVAR_UPDATE:\n\t\tCvar_Update( (vmCvar_t*) VMA(1) );\n\t\treturn 0;\n\tcase G_CVAR_SET:\n\t\tCvar_Set( (const char *)VMA(1), (const char *)VMA(2) );\n\t\treturn 0;\n\tcase G_CVAR_VARIABLE_INTEGER_VALUE:\n\t\treturn Cvar_VariableIntegerValue( (const char *)VMA(1) );\n\tcase G_CVAR_VARIABLE_STRING_BUFFER:\n\t\tCvar_VariableStringBuffer( (const char*) VMA(1), (char*) VMA(2), args[3] );\n\t\treturn 0;\n\tcase G_ARGC:\n\t\treturn Cmd_Argc();\n\tcase G_ARGV:\n\t\tCmd_ArgvBuffer( args[1], (char*) VMA(2), args[3] );\n\t\treturn 0;\n\tcase G_SEND_CONSOLE_COMMAND:\n\t\tCbuf_ExecuteText( args[1], (const char*) VMA(2) );\n\t\treturn 0;\n\n\tcase G_FS_FOPEN_FILE:\n\t\treturn FS_FOpenFileByMode( (const char*) VMA(1), (fileHandle_t*) VMA(2), (fsMode_t) args[3] );\n\tcase G_FS_READ:\n\t\tFS_Read2( VMA(1), args[2], args[3] );\n\t\treturn 0;\n\tcase G_FS_WRITE:\n\t\tFS_Write( VMA(1), args[2], args[3] );\n\t\treturn 0;\n\tcase G_FS_FCLOSE_FILE:\n\t\tFS_FCloseFile( args[1] );\n\t\treturn 0;\n\tcase G_FS_GETFILELIST:\n\t\treturn FS_GetFileList( (const char*) VMA(1), (const char*) VMA(2), (char*) VMA(3), args[4] );\n\tcase G_FS_SEEK:\n\t\treturn FS_Seek( args[1], args[2], args[3] );\n\n\tcase G_LOCATE_GAME_DATA:\n\t\tSV_LocateGameData( (sharedEntity_t*) VMA(1), args[2], args[3], (playerState_t*) VMA(4), args[5] );\n\t\treturn 0;\n\tcase G_DROP_CLIENT:\n\t\tSV_GameDropClient( args[1], (const char*) VMA(2) );\n\t\treturn 0;\n\tcase G_SEND_SERVER_COMMAND:\n\t\tSV_GameSendServerCommand( args[1], (const char*) VMA(2) );\n\t\treturn 0;\n\tcase G_LINKENTITY:\n\t\tSV_LinkEntity( (sharedEntity_t*) VMA(1) );\n\t\treturn 0;\n\tcase G_UNLINKENTITY:\n\t\tSV_UnlinkEntity( (sharedEntity_t*) VMA(1) );\n\t\treturn 0;\n\tcase G_ENTITIES_IN_BOX:\n\t\treturn SV_AreaEntities( (const vec_t*) VMA(1), (const vec_t*) VMA(2), (int*) VMA(3), args[4] );\n\tcase G_ENTITY_CONTACT:\n\t\treturn SV_EntityContact((vec_t*) VMA(1), (vec_t*) VMA(2), (const sharedEntity_t*) VMA(3), /*int capsule*/ qfalse);\n\tcase G_ENTITY_CONTACTCAPSULE:\n\t\treturn SV_EntityContact( (vec_t*) VMA(1), (vec_t*) VMA(2), (const sharedEntity_t*) VMA(3), /*int capsule*/ qtrue );\n\tcase G_TRACE:\n\t\tSV_Trace((trace_t*)VMA(1), (const vec_t*)VMA(2), (vec_t*) VMA(3), (vec_t*)VMA(4), (const vec_t*) VMA(5), args[6], args[7], /*int capsule*/ qfalse);\n\t\treturn 0;\n\tcase G_TRACECAPSULE:\n\t\tSV_Trace((trace_t*)VMA(1), (const vec_t*)VMA(2), (vec_t*)VMA(3), (vec_t*)VMA(4), (const vec_t*)VMA(5), args[6], args[7], /*int capsule*/ qtrue);\n\t\treturn 0;\n\tcase G_POINT_CONTENTS:\n\t\treturn SV_PointContents( (const vec_t*) VMA(1), args[2] );\n\tcase G_SET_BRUSH_MODEL:\n\t\tSV_SetBrushModel( (sharedEntity_t*) VMA(1), (const char*) VMA(2) );\n\t\treturn 0;\n\tcase G_IN_PVS:\n\t\treturn SV_inPVS( (const vec_t*) VMA(1), (const vec_t*) VMA(2) );\n\tcase G_IN_PVS_IGNORE_PORTALS:\n\t\treturn SV_inPVSIgnorePortals( (const vec_t*) VMA(1), (const vec_t*) VMA(2) );\n\n\tcase G_SET_CONFIGSTRING:\n\t\tSV_SetConfigstring( args[1], (const char*) VMA(2) );\n\t\treturn 0;\n\tcase G_GET_CONFIGSTRING:\n\t\tSV_GetConfigstring( args[1], (char*) VMA(2), args[3] );\n\t\treturn 0;\n\tcase G_SET_USERINFO:\n\t\tSV_SetUserinfo( args[1], (const char*) VMA(2) );\n\t\treturn 0;\n\tcase G_GET_USERINFO:\n\t\tSV_GetUserinfo( args[1], (char*) VMA(2), args[3] );\n\t\treturn 0;\n\tcase G_GET_SERVERINFO:\n\t\tSV_GetServerinfo( (char*) VMA(1), args[2] );\n\t\treturn 0;\n\tcase G_ADJUST_AREA_PORTAL_STATE:\n\t\tSV_AdjustAreaPortalState( (sharedEntity_t*) VMA(1), (qboolean) args[2] );\n\t\treturn 0;\n\tcase G_AREAS_CONNECTED:\n\t\treturn CM_AreasConnected( args[1], args[2] );\n\n\tcase G_BOT_ALLOCATE_CLIENT:\n\t\treturn SV_BotAllocateClient();\n\tcase G_BOT_FREE_CLIENT:\n\t\tSV_BotFreeClient( args[1] );\n\t\treturn 0;\n\n\tcase G_GET_USERCMD:\n\t\tSV_GetUsercmd( args[1], (usercmd_t*) VMA(2) );\n\t\treturn 0;\n\tcase G_GET_ENTITY_TOKEN:\n\t\t{\n\t\t\tconst char\t*s;\n\n\t\t\ts = COM_Parse( &sv.entityParsePoint );\n\t\t\tQ_strncpyz( (char*) VMA(1), s, args[2] );\n\t\t\tif ( !sv.entityParsePoint && !s[0] ) {\n\t\t\t\treturn qfalse;\n\t\t\t} else {\n\t\t\t\treturn qtrue;\n\t\t\t}\n\t\t}\n\n\tcase G_DEBUG_POLYGON_CREATE:\n\t\treturn BotImport_DebugPolygonCreate( args[1], args[2], (vec3_t*) VMA(3) );\n\tcase G_DEBUG_POLYGON_DELETE:\n\t\tBotImport_DebugPolygonDelete( args[1] );\n\t\treturn 0;\n\tcase G_REAL_TIME:\n\t\treturn Com_RealTime( (qtime_t*) VMA(1) );\n\tcase G_SNAPVECTOR:\n\t\tSys_SnapVector( (float*) VMA(1) );\n\t\treturn 0;\n\n\t\t//====================================\n\n\tcase BOTLIB_SETUP:\n\t\treturn SV_BotLibSetup();\n\tcase BOTLIB_SHUTDOWN:\n\t\treturn SV_BotLibShutdown();\n\tcase BOTLIB_LIBVAR_SET:\n\t\treturn botlib_export->BotLibVarSet( (char*) VMA(1), (char*) VMA(2) );\n\tcase BOTLIB_LIBVAR_GET:\n\t\treturn botlib_export->BotLibVarGet( (char*) VMA(1), (char*) VMA(2), args[3] );\n\n\tcase BOTLIB_PC_ADD_GLOBAL_DEFINE:\n\t\treturn botlib_export->PC_AddGlobalDefine( (char*) VMA(1) );\n\tcase BOTLIB_PC_LOAD_SOURCE:\n\t\treturn botlib_export->PC_LoadSourceHandle( (const char*) VMA(1) );\n\tcase BOTLIB_PC_FREE_SOURCE:\n\t\treturn botlib_export->PC_FreeSourceHandle( args[1] );\n\tcase BOTLIB_PC_READ_TOKEN:\n\t\treturn botlib_export->PC_ReadTokenHandle( args[1], (pc_token_t*) VMA(2) );\n\tcase BOTLIB_PC_SOURCE_FILE_AND_LINE:\n\t\treturn botlib_export->PC_SourceFileAndLine( args[1], (char*) VMA(2), (int*) VMA(3) );\n\n\tcase BOTLIB_START_FRAME:\n\t\treturn botlib_export->BotLibStartFrame( VMF(1) );\n\tcase BOTLIB_LOAD_MAP:\n\t\treturn botlib_export->BotLibLoadMap( (const char*) VMA(1) );\n\tcase BOTLIB_UPDATENTITY:\n\t\treturn botlib_export->BotLibUpdateEntity( args[1], (bot_entitystate_t*) VMA(2) );\n\tcase BOTLIB_TEST:\n\t\treturn botlib_export->Test( args[1], (char*) VMA(2), (vec_t*) VMA(3), (vec_t*) VMA(4) );\n\n\tcase BOTLIB_GET_SNAPSHOT_ENTITY:\n\t\treturn SV_BotGetSnapshotEntity( args[1], args[2] );\n\tcase BOTLIB_GET_CONSOLE_MESSAGE:\n\t\treturn SV_BotGetConsoleMessage( args[1], (char*) VMA(2), args[3] );\n\tcase BOTLIB_USER_COMMAND:\n\t\tSV_ClientThink( &svs.clients[args[1]], (usercmd_t*) VMA(2) );\n\t\treturn 0;\n\n\tcase BOTLIB_AAS_BBOX_AREAS:\n\t\treturn botlib_export->aas.AAS_BBoxAreas( (vec_t*) VMA(1), (vec_t*) VMA(2), (int*) VMA(3), args[4] );\n\tcase BOTLIB_AAS_AREA_INFO:\n\t\treturn botlib_export->aas.AAS_AreaInfo( args[1], (aas_areainfo_s*) VMA(2) );\n\tcase BOTLIB_AAS_ALTERNATIVE_ROUTE_GOAL:\n\t\treturn botlib_export->aas.AAS_AlternativeRouteGoals( (vec_t*) VMA(1), args[2], (vec_t*) VMA(3), args[4], args[5], (aas_altroutegoal_s*) VMA(6), args[7], args[8] );\n\tcase BOTLIB_AAS_ENTITY_INFO:\n\t\tbotlib_export->aas.AAS_EntityInfo( args[1], (aas_entityinfo_s*) VMA(2) );\n\t\treturn 0;\n\n\tcase BOTLIB_AAS_INITIALIZED:\n\t\treturn botlib_export->aas.AAS_Initialized();\n\tcase BOTLIB_AAS_PRESENCE_TYPE_BOUNDING_BOX:\n\t\tbotlib_export->aas.AAS_PresenceTypeBoundingBox( args[1], (vec_t*) VMA(2), (vec_t*) VMA(3) );\n\t\treturn 0;\n\tcase BOTLIB_AAS_TIME:\n\t\treturn FloatAsInt( botlib_export->aas.AAS_Time() );\n\n\tcase BOTLIB_AAS_POINT_AREA_NUM:\n\t\treturn botlib_export->aas.AAS_PointAreaNum((vec_t*) VMA(1));\n\tcase BOTLIB_AAS_POINT_REACHABILITY_AREA_INDEX:\n\t\treturn botlib_export->aas.AAS_PointReachabilityAreaIndex((vec_t*) VMA(1));\n\tcase BOTLIB_AAS_TRACE_AREAS:\n\t\treturn botlib_export->aas.AAS_TraceAreas((vec_t*)VMA(1), (vec_t*) VMA(2), (int*) VMA(3), (vec3_t*) VMA(4), args[5]);\n\n\tcase BOTLIB_AAS_POINT_CONTENTS:\n\t\treturn botlib_export->aas.AAS_PointContents((vec_t*) VMA(1));\n\tcase BOTLIB_AAS_NEXT_BSP_ENTITY:\n\t\treturn botlib_export->aas.AAS_NextBSPEntity( args[1] );\n\tcase BOTLIB_AAS_VALUE_FOR_BSP_EPAIR_KEY:\n\t\treturn botlib_export->aas.AAS_ValueForBSPEpairKey( args[1], (char*) VMA(2), (char*) VMA(3), args[4] );\n\tcase BOTLIB_AAS_VECTOR_FOR_BSP_EPAIR_KEY:\n\t\treturn botlib_export->aas.AAS_VectorForBSPEpairKey(args[1], (char*)VMA(2), (vec_t*) VMA(3));\n\tcase BOTLIB_AAS_FLOAT_FOR_BSP_EPAIR_KEY:\n\t\treturn botlib_export->aas.AAS_FloatForBSPEpairKey( args[1], (char*) VMA(2), (float*) VMA(3) );\n\tcase BOTLIB_AAS_INT_FOR_BSP_EPAIR_KEY:\n\t\treturn botlib_export->aas.AAS_IntForBSPEpairKey( args[1], (char*) VMA(2), (int*) VMA(3) );\n\n\tcase BOTLIB_AAS_AREA_REACHABILITY:\n\t\treturn botlib_export->aas.AAS_AreaReachability( args[1] );\n\n\tcase BOTLIB_AAS_AREA_TRAVEL_TIME_TO_GOAL_AREA:\n\t\treturn botlib_export->aas.AAS_AreaTravelTimeToGoalArea(args[1], (vec_t*) VMA(2), args[3], args[4]);\n\tcase BOTLIB_AAS_ENABLE_ROUTING_AREA:\n\t\treturn botlib_export->aas.AAS_EnableRoutingArea( args[1], args[2] );\n\tcase BOTLIB_AAS_PREDICT_ROUTE:\n\t\treturn botlib_export->aas.AAS_PredictRoute((aas_predictroute_s*)VMA(1), args[2], (vec_t*) VMA(3), args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11]);\n\n\tcase BOTLIB_AAS_SWIMMING:\n\t\treturn botlib_export->aas.AAS_Swimming((vec_t*) VMA(1));\n\tcase BOTLIB_AAS_PREDICT_CLIENT_MOVEMENT:\n\t\treturn botlib_export->aas.AAS_PredictClientMovement((aas_clientmove_s*)VMA(1), args[2], (vec_t*) VMA(3), args[4], args[5],\n\t\t\t(vec_t*)VMA(6), (vec_t*) VMA(7), args[8], args[9], VMF(10), args[11], args[12], args[13]);\n\n\tcase BOTLIB_EA_SAY:\n\t\tbotlib_export->ea.EA_Say( args[1], (char*) VMA(2) );\n\t\treturn 0;\n\tcase BOTLIB_EA_SAY_TEAM:\n\t\tbotlib_export->ea.EA_SayTeam( args[1], (char*) VMA(2) );\n\t\treturn 0;\n\tcase BOTLIB_EA_COMMAND:\n\t\tbotlib_export->ea.EA_Command( args[1], (char*) VMA(2) );\n\t\treturn 0;\n\n\tcase BOTLIB_EA_ACTION:\n\t\tbotlib_export->ea.EA_Action( args[1], args[2] );\n\t\tbreak;\n\tcase BOTLIB_EA_GESTURE:\n\t\tbotlib_export->ea.EA_Gesture( args[1] );\n\t\treturn 0;\n\tcase BOTLIB_EA_TALK:\n\t\tbotlib_export->ea.EA_Talk( args[1] );\n\t\treturn 0;\n\tcase BOTLIB_EA_ATTACK:\n\t\tbotlib_export->ea.EA_Attack( args[1] );\n\t\treturn 0;\n\tcase BOTLIB_EA_USE:\n\t\tbotlib_export->ea.EA_Use( args[1] );\n\t\treturn 0;\n\tcase BOTLIB_EA_RESPAWN:\n\t\tbotlib_export->ea.EA_Respawn( args[1] );\n\t\treturn 0;\n\tcase BOTLIB_EA_CROUCH:\n\t\tbotlib_export->ea.EA_Crouch( args[1] );\n\t\treturn 0;\n\tcase BOTLIB_EA_MOVE_UP:\n\t\tbotlib_export->ea.EA_MoveUp( args[1] );\n\t\treturn 0;\n\tcase BOTLIB_EA_MOVE_DOWN:\n\t\tbotlib_export->ea.EA_MoveDown( args[1] );\n\t\treturn 0;\n\tcase BOTLIB_EA_MOVE_FORWARD:\n\t\tbotlib_export->ea.EA_MoveForward( args[1] );\n\t\treturn 0;\n\tcase BOTLIB_EA_MOVE_BACK:\n\t\tbotlib_export->ea.EA_MoveBack( args[1] );\n\t\treturn 0;\n\tcase BOTLIB_EA_MOVE_LEFT:\n\t\tbotlib_export->ea.EA_MoveLeft( args[1] );\n\t\treturn 0;\n\tcase BOTLIB_EA_MOVE_RIGHT:\n\t\tbotlib_export->ea.EA_MoveRight( args[1] );\n\t\treturn 0;\n\n\tcase BOTLIB_EA_SELECT_WEAPON:\n\t\tbotlib_export->ea.EA_SelectWeapon( args[1], args[2] );\n\t\treturn 0;\n\tcase BOTLIB_EA_JUMP:\n\t\tbotlib_export->ea.EA_Jump( args[1] );\n\t\treturn 0;\n\tcase BOTLIB_EA_DELAYED_JUMP:\n\t\tbotlib_export->ea.EA_DelayedJump( args[1] );\n\t\treturn 0;\n\tcase BOTLIB_EA_MOVE:\n\t\tbotlib_export->ea.EA_Move(args[1], (vec_t*) VMA(2), VMF(3));\n\t\treturn 0;\n\tcase BOTLIB_EA_VIEW:\n\t\tbotlib_export->ea.EA_View(args[1], (vec_t*) VMA(2));\n\t\treturn 0;\n\n\tcase BOTLIB_EA_END_REGULAR:\n\t\tbotlib_export->ea.EA_EndRegular( args[1], VMF(2) );\n\t\treturn 0;\n\tcase BOTLIB_EA_GET_INPUT:\n\t\tbotlib_export->ea.EA_GetInput( args[1], VMF(2), (bot_input_t*) VMA(3) );\n\t\treturn 0;\n\tcase BOTLIB_EA_RESET_INPUT:\n\t\tbotlib_export->ea.EA_ResetInput( args[1] );\n\t\treturn 0;\n\n\tcase BOTLIB_AI_LOAD_CHARACTER:\n\t\treturn botlib_export->ai.BotLoadCharacter( (char*) VMA(1), VMF(2) );\n\tcase BOTLIB_AI_FREE_CHARACTER:\n\t\tbotlib_export->ai.BotFreeCharacter( args[1] );\n\t\treturn 0;\n\tcase BOTLIB_AI_CHARACTERISTIC_FLOAT:\n\t\treturn FloatAsInt( botlib_export->ai.Characteristic_Float( args[1], args[2] ) );\n\tcase BOTLIB_AI_CHARACTERISTIC_BFLOAT:\n\t\treturn FloatAsInt( botlib_export->ai.Characteristic_BFloat( args[1], args[2], VMF(3), VMF(4) ) );\n\tcase BOTLIB_AI_CHARACTERISTIC_INTEGER:\n\t\treturn botlib_export->ai.Characteristic_Integer( args[1], args[2] );\n\tcase BOTLIB_AI_CHARACTERISTIC_BINTEGER:\n\t\treturn botlib_export->ai.Characteristic_BInteger( args[1], args[2], args[3], args[4] );\n\tcase BOTLIB_AI_CHARACTERISTIC_STRING:\n\t\tbotlib_export->ai.Characteristic_String( args[1], args[2], (char*) VMA(3), args[4] );\n\t\treturn 0;\n\n\tcase BOTLIB_AI_ALLOC_CHAT_STATE:\n\t\treturn botlib_export->ai.BotAllocChatState();\n\tcase BOTLIB_AI_FREE_CHAT_STATE:\n\t\tbotlib_export->ai.BotFreeChatState( args[1] );\n\t\treturn 0;\n\tcase BOTLIB_AI_QUEUE_CONSOLE_MESSAGE:\n\t\tbotlib_export->ai.BotQueueConsoleMessage( args[1], args[2], (char*) VMA(3) );\n\t\treturn 0;\n\tcase BOTLIB_AI_REMOVE_CONSOLE_MESSAGE:\n\t\tbotlib_export->ai.BotRemoveConsoleMessage( args[1], args[2] );\n\t\treturn 0;\n\tcase BOTLIB_AI_NEXT_CONSOLE_MESSAGE:\n\t\treturn botlib_export->ai.BotNextConsoleMessage( args[1], (bot_consolemessage_s*) VMA(2) );\n\tcase BOTLIB_AI_NUM_CONSOLE_MESSAGE:\n\t\treturn botlib_export->ai.BotNumConsoleMessages( args[1] );\n\tcase BOTLIB_AI_INITIAL_CHAT:\n\t\tbotlib_export->ai.BotInitialChat( args[1], (char*) VMA(2), args[3], (char*) VMA(4), (char*) VMA(5), (char*) VMA(6), (char*) VMA(7), (char*) VMA(8), (char*) VMA(9), (char*) VMA(10), (char*) VMA(11) );\n\t\treturn 0;\n\tcase BOTLIB_AI_NUM_INITIAL_CHATS:\n\t\treturn botlib_export->ai.BotNumInitialChats( args[1], (char*) VMA(2) );\n\tcase BOTLIB_AI_REPLY_CHAT:\n\t\treturn botlib_export->ai.BotReplyChat( args[1], (char*) VMA(2), args[3], args[4], (char*) VMA(5), (char*) VMA(6), (char*) VMA(7), (char*) VMA(8), (char*) VMA(9), (char*) VMA(10), (char*) VMA(11), (char*) VMA(12) );\n\tcase BOTLIB_AI_CHAT_LENGTH:\n\t\treturn botlib_export->ai.BotChatLength( args[1] );\n\tcase BOTLIB_AI_ENTER_CHAT:\n\t\tbotlib_export->ai.BotEnterChat( args[1], args[2], args[3] );\n\t\treturn 0;\n\tcase BOTLIB_AI_GET_CHAT_MESSAGE:\n\t\tbotlib_export->ai.BotGetChatMessage( args[1], (char*) VMA(2), args[3] );\n\t\treturn 0;\n\tcase BOTLIB_AI_STRING_CONTAINS:\n\t\treturn botlib_export->ai.StringContains((char*)VMA(1), (char*) VMA(2), args[3]);\n\tcase BOTLIB_AI_FIND_MATCH:\n\t\treturn botlib_export->ai.BotFindMatch((char*) VMA(1), (bot_match_s*) VMA(2), args[3]);\n\tcase BOTLIB_AI_MATCH_VARIABLE:\n\t\tbotlib_export->ai.BotMatchVariable( (bot_match_s*) VMA(1), args[2], (char*) VMA(3), args[4] );\n\t\treturn 0;\n\tcase BOTLIB_AI_UNIFY_WHITE_SPACES:\n\t\tbotlib_export->ai.UnifyWhiteSpaces((char*) VMA(1));\n\t\treturn 0;\n\tcase BOTLIB_AI_REPLACE_SYNONYMS:\n\t\tbotlib_export->ai.BotReplaceSynonyms((char*) VMA(1), args[2]);\n\t\treturn 0;\n\tcase BOTLIB_AI_LOAD_CHAT_FILE:\n\t\treturn botlib_export->ai.BotLoadChatFile(args[1], (char*)VMA(2), (char*) VMA(3));\n\tcase BOTLIB_AI_SET_CHAT_GENDER:\n\t\tbotlib_export->ai.BotSetChatGender( args[1], args[2] );\n\t\treturn 0;\n\tcase BOTLIB_AI_SET_CHAT_NAME:\n\t\tbotlib_export->ai.BotSetChatName(args[1], (char*) VMA(2), args[3]);\n\t\treturn 0;\n\n\tcase BOTLIB_AI_RESET_GOAL_STATE:\n\t\tbotlib_export->ai.BotResetGoalState( args[1] );\n\t\treturn 0;\n\tcase BOTLIB_AI_RESET_AVOID_GOALS:\n\t\tbotlib_export->ai.BotResetAvoidGoals( args[1] );\n\t\treturn 0;\n\tcase BOTLIB_AI_REMOVE_FROM_AVOID_GOALS:\n\t\tbotlib_export->ai.BotRemoveFromAvoidGoals( args[1], args[2] );\n\t\treturn 0;\n\tcase BOTLIB_AI_PUSH_GOAL:\n\t\tbotlib_export->ai.BotPushGoal(args[1], (bot_goal_s*) VMA(2));\n\t\treturn 0;\n\tcase BOTLIB_AI_POP_GOAL:\n\t\tbotlib_export->ai.BotPopGoal( args[1] );\n\t\treturn 0;\n\tcase BOTLIB_AI_EMPTY_GOAL_STACK:\n\t\tbotlib_export->ai.BotEmptyGoalStack( args[1] );\n\t\treturn 0;\n\tcase BOTLIB_AI_DUMP_AVOID_GOALS:\n\t\tbotlib_export->ai.BotDumpAvoidGoals( args[1] );\n\t\treturn 0;\n\tcase BOTLIB_AI_DUMP_GOAL_STACK:\n\t\tbotlib_export->ai.BotDumpGoalStack( args[1] );\n\t\treturn 0;\n\tcase BOTLIB_AI_GOAL_NAME:\n\t\tbotlib_export->ai.BotGoalName( args[1], (char*) VMA(2), args[3] );\n\t\treturn 0;\n\tcase BOTLIB_AI_GET_TOP_GOAL:\n\t\treturn botlib_export->ai.BotGetTopGoal( args[1], (bot_goal_s*) VMA(2) );\n\tcase BOTLIB_AI_GET_SECOND_GOAL:\n\t\treturn botlib_export->ai.BotGetSecondGoal(args[1], (bot_goal_s*) VMA(2));\n\tcase BOTLIB_AI_CHOOSE_LTG_ITEM:\n\t\treturn botlib_export->ai.BotChooseLTGItem( args[1], (vec_t*) VMA(2), (int*) VMA(3), args[4] );\n\tcase BOTLIB_AI_CHOOSE_NBG_ITEM:\n\t\treturn botlib_export->ai.BotChooseNBGItem( args[1], (vec_t*) VMA(2), (int*) VMA(3), args[4], (bot_goal_s*) VMA(5), VMF(6) );\n\tcase BOTLIB_AI_TOUCHING_GOAL:\n\t\treturn botlib_export->ai.BotTouchingGoal((vec_t*)VMA(1), (bot_goal_s*) VMA(2));\n\tcase BOTLIB_AI_ITEM_GOAL_IN_VIS_BUT_NOT_VISIBLE:\n\t\treturn botlib_export->ai.BotItemGoalInVisButNotVisible(args[1], (vec_t*)VMA(2), (vec_t*)VMA(3), (bot_goal_s*) VMA(4));\n\tcase BOTLIB_AI_GET_LEVEL_ITEM_GOAL:\n\t\treturn botlib_export->ai.BotGetLevelItemGoal(args[1], (char*)VMA(2), (bot_goal_s*) VMA(3));\n\tcase BOTLIB_AI_GET_NEXT_CAMP_SPOT_GOAL:\n\t\treturn botlib_export->ai.BotGetNextCampSpotGoal(args[1], (bot_goal_s*) VMA(2));\n\tcase BOTLIB_AI_GET_MAP_LOCATION_GOAL:\n\t\treturn botlib_export->ai.BotGetMapLocationGoal((char*)VMA(1), (bot_goal_s*) VMA(2));\n\tcase BOTLIB_AI_AVOID_GOAL_TIME:\n\t\treturn FloatAsInt( botlib_export->ai.BotAvoidGoalTime( args[1], args[2] ) );\n\tcase BOTLIB_AI_SET_AVOID_GOAL_TIME:\n\t\tbotlib_export->ai.BotSetAvoidGoalTime( args[1], args[2], VMF(3));\n\t\treturn 0;\n\tcase BOTLIB_AI_INIT_LEVEL_ITEMS:\n\t\tbotlib_export->ai.BotInitLevelItems();\n\t\treturn 0;\n\tcase BOTLIB_AI_UPDATE_ENTITY_ITEMS:\n\t\tbotlib_export->ai.BotUpdateEntityItems();\n\t\treturn 0;\n\tcase BOTLIB_AI_LOAD_ITEM_WEIGHTS:\n\t\treturn botlib_export->ai.BotLoadItemWeights( args[1], (char*) VMA(2) );\n\tcase BOTLIB_AI_FREE_ITEM_WEIGHTS:\n\t\tbotlib_export->ai.BotFreeItemWeights( args[1] );\n\t\treturn 0;\n\tcase BOTLIB_AI_INTERBREED_GOAL_FUZZY_LOGIC:\n\t\tbotlib_export->ai.BotInterbreedGoalFuzzyLogic( args[1], args[2], args[3] );\n\t\treturn 0;\n\tcase BOTLIB_AI_SAVE_GOAL_FUZZY_LOGIC:\n\t\tbotlib_export->ai.BotSaveGoalFuzzyLogic( args[1], (char*) VMA(2) );\n\t\treturn 0;\n\tcase BOTLIB_AI_MUTATE_GOAL_FUZZY_LOGIC:\n\t\tbotlib_export->ai.BotMutateGoalFuzzyLogic( args[1], VMF(2) );\n\t\treturn 0;\n\tcase BOTLIB_AI_ALLOC_GOAL_STATE:\n\t\treturn botlib_export->ai.BotAllocGoalState( args[1] );\n\tcase BOTLIB_AI_FREE_GOAL_STATE:\n\t\tbotlib_export->ai.BotFreeGoalState( args[1] );\n\t\treturn 0;\n\n\tcase BOTLIB_AI_RESET_MOVE_STATE:\n\t\tbotlib_export->ai.BotResetMoveState( args[1] );\n\t\treturn 0;\n\tcase BOTLIB_AI_ADD_AVOID_SPOT:\n\t\tbotlib_export->ai.BotAddAvoidSpot( args[1], (vec_t*) VMA(2), VMF(3), args[4] );\n\t\treturn 0;\n\tcase BOTLIB_AI_MOVE_TO_GOAL:\n\t\tbotlib_export->ai.BotMoveToGoal((bot_moveresult_s*)VMA(1), args[2], (bot_goal_s*) VMA(3), args[4]);\n\t\treturn 0;\n\tcase BOTLIB_AI_MOVE_IN_DIRECTION:\n\t\treturn botlib_export->ai.BotMoveInDirection( args[1], (vec_t*) VMA(2), VMF(3), args[4] );\n\tcase BOTLIB_AI_RESET_AVOID_REACH:\n\t\tbotlib_export->ai.BotResetAvoidReach( args[1] );\n\t\treturn 0;\n\tcase BOTLIB_AI_RESET_LAST_AVOID_REACH:\n\t\tbotlib_export->ai.BotResetLastAvoidReach( args[1] );\n\t\treturn 0;\n\tcase BOTLIB_AI_REACHABILITY_AREA:\n\t\treturn botlib_export->ai.BotReachabilityArea( (vec_t*) VMA(1), args[2] );\n\tcase BOTLIB_AI_MOVEMENT_VIEW_TARGET:\n\t\treturn botlib_export->ai.BotMovementViewTarget(args[1], (bot_goal_s*) VMA(2), args[3], VMF(4), (vec_t*) VMA(5));\n\tcase BOTLIB_AI_PREDICT_VISIBLE_POSITION:\n\t\treturn botlib_export->ai.BotPredictVisiblePosition((vec_t*)VMA(1), args[2], (bot_goal_s*) VMA(3), args[4], (vec_t*) VMA(5));\n\tcase BOTLIB_AI_ALLOC_MOVE_STATE:\n\t\treturn botlib_export->ai.BotAllocMoveState();\n\tcase BOTLIB_AI_FREE_MOVE_STATE:\n\t\tbotlib_export->ai.BotFreeMoveState( args[1] );\n\t\treturn 0;\n\tcase BOTLIB_AI_INIT_MOVE_STATE:\n\t\tbotlib_export->ai.BotInitMoveState( args[1], (bot_initmove_s*) VMA(2) );\n\t\treturn 0;\n\n\tcase BOTLIB_AI_CHOOSE_BEST_FIGHT_WEAPON:\n\t\treturn botlib_export->ai.BotChooseBestFightWeapon( args[1], (int*) VMA(2) );\n\tcase BOTLIB_AI_GET_WEAPON_INFO:\n\t\tbotlib_export->ai.BotGetWeaponInfo( args[1], args[2], (weaponinfo_s*) VMA(3) );\n\t\treturn 0;\n\tcase BOTLIB_AI_LOAD_WEAPON_WEIGHTS:\n\t\treturn botlib_export->ai.BotLoadWeaponWeights( args[1], (char*) VMA(2) );\n\tcase BOTLIB_AI_ALLOC_WEAPON_STATE:\n\t\treturn botlib_export->ai.BotAllocWeaponState();\n\tcase BOTLIB_AI_FREE_WEAPON_STATE:\n\t\tbotlib_export->ai.BotFreeWeaponState( args[1] );\n\t\treturn 0;\n\tcase BOTLIB_AI_RESET_WEAPON_STATE:\n\t\tbotlib_export->ai.BotResetWeaponState( args[1] );\n\t\treturn 0;\n\n\tcase BOTLIB_AI_GENETIC_PARENTS_AND_CHILD_SELECTION:\n\t\treturn botlib_export->ai.GeneticParentsAndChildSelection(args[1], (float*) VMA(2), (int*) VMA(3), (int*) VMA(4), (int*) VMA(5));\n\n\tcase TRAP_MEMSET:\n\t\tCom_Memset( VMA(1), args[2], args[3] );\n\t\treturn 0;\n\n\tcase TRAP_MEMCPY:\n\t\tCom_Memcpy( VMA(1), VMA(2), args[3] );\n\t\treturn 0;\n\n\tcase TRAP_STRNCPY:\n        strncpy( (char*)VMA(1), (const char*)VMA(2), args[3] );\n        return args[1];\n\tcase TRAP_SIN:\n\t\treturn FloatAsInt( sin( VMF(1) ) );\n\n\tcase TRAP_COS:\n\t\treturn FloatAsInt( cos( VMF(1) ) );\n\n\tcase TRAP_ATAN2:\n\t\treturn FloatAsInt( atan2( VMF(1), VMF(2) ) );\n\n\tcase TRAP_SQRT:\n\t\treturn FloatAsInt( sqrt( VMF(1) ) );\n\n\tcase TRAP_MATRIXMULTIPLY:\n\t\tMatrixMultiply((float(*)[3]) VMA(1), (float(*)[3]) VMA(2), (float(*)[3]) VMA(3));\n\t\treturn 0;\n\n\tcase TRAP_ANGLEVECTORS:\n\t\tAngleVectors( (const vec_t*) VMA(1), (vec_t*) VMA(2), (vec_t*) VMA(3), (vec_t*) VMA(4) );\n\t\treturn 0;\n\n\tcase TRAP_PERPENDICULARVECTOR:\n\t\tPerpendicularVector( (vec_t*) VMA(1), (vec_t*) VMA(2) );\n\t\treturn 0;\n\n\tcase TRAP_FLOOR:\n\t\treturn FloatAsInt( floor( VMF(1) ) );\n\n\tcase TRAP_CEIL:\n\t\treturn FloatAsInt( ceil( VMF(1) ) );\n\n\n\tdefault:\n\t\tCom_Error( ERR_DROP, \"Bad game system trap: %i\", args[0] );\n\t}\n\treturn -1;\n}\n\n/*\n===============\nSV_ShutdownGameProgs\n\nCalled every time a map changes\n===============\n*/\nvoid SV_ShutdownGameProgs( void ) {\n\tif ( !gvm ) {\n\t\treturn;\n\t}\n\tVM_Call( gvm, GAME_SHUTDOWN, qfalse );\n\tVM_Free( gvm );\n\tgvm = NULL;\n}\n\n/*\n==================\nSV_InitGameVM\n\nCalled for both a full init and a restart\n==================\n*/\nstatic void SV_InitGameVM( qboolean restart ) {\n\tint\t\ti;\n\n\t// start the entity parsing at the beginning\n\tsv.entityParsePoint = CM_EntityString();\n\n\t// clear all gentity pointers that might still be set from\n\t// a previous level\n\t// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=522\n\t//   now done before GAME_INIT call\n\tfor ( i = 0 ; i < sv_maxclients->integer ; i++ ) {\n\t\tsvs.clients[i].gentity = NULL;\n\t}\n\t\n\t// use the current msec count for a random seed\n\t// init for this gamestate\n\tVM_Call( gvm, GAME_INIT, svs.time, Com_Milliseconds(), restart );\n}\n\n\n\n/*\n===================\nSV_RestartGameProgs\n\nCalled on a map_restart, but not on a normal map change\n===================\n*/\nvoid SV_RestartGameProgs( void ) {\n\tif ( !gvm ) {\n\t\treturn;\n\t}\n\tVM_Call( gvm, GAME_SHUTDOWN, qtrue );\n\n\t// do a restart instead of a free\n\tgvm = VM_Restart( gvm );\n\tif ( !gvm ) { // bk001212 - as done below\n\t\tCom_Error( ERR_FATAL, \"VM_Restart on game failed\" );\n\t}\n\n\tSV_InitGameVM( qtrue );\n}\n\n\n/*\n===============\nSV_InitGameProgs\n\nCalled on a normal map change, not on a map_restart\n===============\n*/\nvoid SV_InitGameProgs( void ) {\n\tcvar_t\t*var;\n\t//FIXME these are temp while I make bots run in vm\n\textern int\tbot_enable;\n\n\tvar = Cvar_Get( \"bot_enable\", \"1\", CVAR_LATCH );\n\tif ( var ) {\n\t\tbot_enable = var->integer;\n\t}\n\telse {\n\t\tbot_enable = 0;\n\t}\n\n\t// load the dll or bytecode\n\tgvm = VM_Create( \"qagame\", SV_GameSystemCalls, (vmInterpret_t) (int) Cvar_VariableValue( \"vm_game\" ) );\n\tif ( !gvm ) {\n\t\tCom_Error( ERR_FATAL, \"VM_Create on game failed\" );\n\t}\n\n\tSV_InitGameVM( qfalse );\n}\n\n\n/*\n====================\nSV_GameCommand\n\nSee if the current console command is claimed by the game\n====================\n*/\nqboolean SV_GameCommand( void ) {\n\tif ( sv.state != SS_GAME ) {\n\t\treturn qfalse;\n\t}\n\n\treturn (qboolean) VM_Call( gvm, GAME_CONSOLE_COMMAND );\n}\n\n"
  },
  {
    "path": "src/engine/server/sv_init.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n#include \"server.h\"\n\n/*\n===============\nSV_SetConfigstring\n\n===============\n*/\nvoid SV_SetConfigstring (int index, const char *val) {\n\tint\t\tlen, i;\n\tint\t\tmaxChunkSize = MAX_STRING_CHARS - 24;\n\tclient_t\t*client;\n\n\tif ( index < 0 || index >= MAX_CONFIGSTRINGS ) {\n\t\tCom_Error (ERR_DROP, \"SV_SetConfigstring: bad index %i\\n\", index);\n\t}\n\n\tif ( !val ) {\n\t\tval = \"\";\n\t}\n\n\t// don't bother broadcasting an update if no change\n\tif ( !strcmp( val, sv.configstrings[ index ] ) ) {\n\t\treturn;\n\t}\n\n\t// change the string in sv\n\tZ_Free( sv.configstrings[index] );\n\tsv.configstrings[index] = CopyString( val );\n\n\t// send it to all the clients if we aren't\n\t// spawning a new server\n\tif ( sv.state == SS_GAME || sv.restarting ) {\n\n\t\t// send the data to all relevent clients\n\t\tfor (i = 0, client = svs.clients; i < sv_maxclients->integer ; i++, client++) {\n\t\t\tif ( client->state < CS_PRIMED ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// do not always send server info to all clients\n\t\t\tif ( index == CS_SERVERINFO && client->gentity && (client->gentity->r.svFlags & SVF_NOSERVERINFO) ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tlen = (int)strlen( val );\n\t\t\tif( len >= maxChunkSize ) {\n\t\t\t\tint\t\tsent = 0;\n\t\t\t\tint\t\tremaining = len;\n\t\t\t\tchar\t*cmd;\n\t\t\t\tchar\tbuf[MAX_STRING_CHARS];\n\n\t\t\t\twhile (remaining > 0 ) {\n\t\t\t\t\tif ( sent == 0 ) {\n\t\t\t\t\t\tcmd = \"bcs0\";\n\t\t\t\t\t}\n\t\t\t\t\telse if( remaining < maxChunkSize ) {\n\t\t\t\t\t\tcmd = \"bcs2\";\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tcmd = \"bcs1\";\n\t\t\t\t\t}\n\t\t\t\t\tQ_strncpyz( buf, &val[sent], maxChunkSize );\n\n\t\t\t\t\tSV_SendServerCommand( client, \"%s %i \\\"%s\\\"\\n\", cmd, index, buf );\n\n\t\t\t\t\tsent += (maxChunkSize - 1);\n\t\t\t\t\tremaining -= (maxChunkSize - 1);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// standard cs, just send it\n\t\t\t\tSV_SendServerCommand( client, \"cs %i \\\"%s\\\"\\n\", index, val );\n\t\t\t}\n\t\t}\n\t}\n}\n\n\n\n/*\n===============\nSV_GetConfigstring\n\n===============\n*/\nvoid SV_GetConfigstring( int index, char *buffer, int bufferSize ) {\n\tif ( bufferSize < 1 ) {\n\t\tCom_Error( ERR_DROP, \"SV_GetConfigstring: bufferSize == %i\", bufferSize );\n\t}\n\tif ( index < 0 || index >= MAX_CONFIGSTRINGS ) {\n\t\tCom_Error (ERR_DROP, \"SV_GetConfigstring: bad index %i\\n\", index);\n\t}\n\tif ( !sv.configstrings[index] ) {\n\t\tbuffer[0] = 0;\n\t\treturn;\n\t}\n\n\tQ_strncpyz( buffer, sv.configstrings[index], bufferSize );\n}\n\n\n/*\n===============\nSV_SetUserinfo\n\n===============\n*/\nvoid SV_SetUserinfo( int index, const char *val ) {\n\tif ( index < 0 || index >= sv_maxclients->integer ) {\n\t\tCom_Error (ERR_DROP, \"SV_SetUserinfo: bad index %i\\n\", index);\n\t}\n\n\tif ( !val ) {\n\t\tval = \"\";\n\t}\n\n\tQ_strncpyz( svs.clients[index].userinfo, val, sizeof( svs.clients[ index ].userinfo ) );\n\tQ_strncpyz( svs.clients[index].name, Info_ValueForKey( val, \"name\" ), sizeof(svs.clients[index].name) );\n}\n\n\n\n/*\n===============\nSV_GetUserinfo\n\n===============\n*/\nvoid SV_GetUserinfo( int index, char *buffer, int bufferSize ) {\n\tif ( bufferSize < 1 ) {\n\t\tCom_Error( ERR_DROP, \"SV_GetUserinfo: bufferSize == %i\", bufferSize );\n\t}\n\tif ( index < 0 || index >= sv_maxclients->integer ) {\n\t\tCom_Error (ERR_DROP, \"SV_GetUserinfo: bad index %i\\n\", index);\n\t}\n\tQ_strncpyz( buffer, svs.clients[ index ].userinfo, bufferSize );\n}\n\n\n/*\n================\nSV_CreateBaseline\n\nEntity baselines are used to compress non-delta messages\nto the clients -- only the fields that differ from the\nbaseline will be transmitted\n================\n*/\nvoid SV_CreateBaseline( void ) {\n\tsharedEntity_t *svent;\n\tint\t\t\t\tentnum;\t\n\n\tfor ( entnum = 1; entnum < sv.num_entities ; entnum++ ) {\n\t\tsvent = SV_GentityNum(entnum);\n\t\tif (!svent->r.linked) {\n\t\t\tcontinue;\n\t\t}\n\t\tsvent->s.number = entnum;\n\n\t\t//\n\t\t// take current state as baseline\n\t\t//\n\t\tsv.svEntities[entnum].baseline = svent->s;\n\t}\n}\n\n\n/*\n===============\nSV_BoundMaxClients\n\n===============\n*/\nvoid SV_BoundMaxClients( int minimum ) {\n\t// get the current maxclients value\n\tCvar_Get( \"sv_maxclients\", \"8\", 0 );\n\n\tsv_maxclients->modified = qfalse;\n\n\tif ( sv_maxclients->integer < minimum ) {\n\t\tCvar_Set( \"sv_maxclients\", va(\"%i\", minimum) );\n\t} else if ( sv_maxclients->integer > MAX_CLIENTS ) {\n\t\tCvar_Set( \"sv_maxclients\", va(\"%i\", MAX_CLIENTS) );\n\t}\n}\n\n\n/*\n===============\nSV_Startup\n\nCalled when a host starts a map when it wasn't running\none before.  Successive map or map_restart commands will\nNOT cause this to be called, unless the game is exited to\nthe menu system first.\n===============\n*/\nvoid SV_Startup( void ) {\n\tif ( svs.initialized ) {\n\t\tCom_Error( ERR_FATAL, \"SV_Startup: svs.initialized\" );\n\t}\n\tSV_BoundMaxClients( 1 );\n\n\tsvs.clients = (client_t*) Z_Malloc (sizeof(client_t) * sv_maxclients->integer );\n\tif ( com_dedicated->integer ) {\n\t\tsvs.numSnapshotEntities = sv_maxclients->integer * PACKET_BACKUP * 64;\n\t} else {\n\t\t// we don't need nearly as many when playing locally\n\t\tsvs.numSnapshotEntities = sv_maxclients->integer * 4 * 64;\n\t}\n\tsvs.initialized = qtrue;\n\n\tCvar_Set( \"sv_running\", \"1\" );\n}\n\n\n/*\n==================\nSV_ChangeMaxClients\n==================\n*/\nvoid SV_ChangeMaxClients( void ) {\n\tint\t\toldMaxClients;\n\tint\t\ti;\n\tclient_t\t*oldClients;\n\tint\t\tcount;\n\n\t// get the highest client number in use\n\tcount = 0;\n\tfor ( i = 0 ; i < sv_maxclients->integer ; i++ ) {\n\t\tif ( svs.clients[i].state >= CS_CONNECTED ) {\n\t\t\tif (i > count)\n\t\t\t\tcount = i;\n\t\t}\n\t}\n\tcount++;\n\n\toldMaxClients = sv_maxclients->integer;\n\t// never go below the highest client number in use\n\tSV_BoundMaxClients( count );\n\t// if still the same\n\tif ( sv_maxclients->integer == oldMaxClients ) {\n\t\treturn;\n\t}\n\n\toldClients = (client_t*) Hunk_AllocateTempMemory( count * sizeof(client_t) );\n\t// copy the clients to hunk memory\n\tfor ( i = 0 ; i < count ; i++ ) {\n\t\tif ( svs.clients[i].state >= CS_CONNECTED ) {\n\t\t\toldClients[i] = svs.clients[i];\n\t\t}\n\t\telse {\n\t\t\tCom_Memset(&oldClients[i], 0, sizeof(client_t));\n\t\t}\n\t}\n\n\t// free old clients arrays\n\tZ_Free( svs.clients );\n\n\t// allocate new clients\n\tsvs.clients = (client_t*) Z_Malloc ( sv_maxclients->integer * sizeof(client_t) );\n\tCom_Memset( svs.clients, 0, sv_maxclients->integer * sizeof(client_t) );\n\n\t// copy the clients over\n\tfor ( i = 0 ; i < count ; i++ ) {\n\t\tif ( oldClients[i].state >= CS_CONNECTED ) {\n\t\t\tsvs.clients[i] = oldClients[i];\n\t\t}\n\t}\n\n\t// free the old clients on the hunk\n\tHunk_FreeTempMemory( oldClients );\n\t\n\t// allocate new snapshot entities\n\tif ( com_dedicated->integer ) {\n\t\tsvs.numSnapshotEntities = sv_maxclients->integer * PACKET_BACKUP * 64;\n\t} else {\n\t\t// we don't need nearly as many when playing locally\n\t\tsvs.numSnapshotEntities = sv_maxclients->integer * 4 * 64;\n\t}\n}\n\n/*\n================\nSV_ClearServer\n================\n*/\nvoid SV_ClearServer(void) {\n\tint i;\n\n\tfor ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) {\n\t\tif ( sv.configstrings[i] ) {\n\t\t\tZ_Free( sv.configstrings[i] );\n\t\t}\n\t}\n\tCom_Memset (&sv, 0, sizeof(sv));\n}\n\n/*\n================\nSV_TouchCGame\n\n  touch the cgame.vm so that a pure client can load it if it's in a seperate pk3\n================\n*/\nvoid SV_TouchCGame(void) {\n\tfileHandle_t\tf;\n\tchar filename[MAX_QPATH];\n\n\tCom_sprintf( filename, sizeof(filename), \"vm/%s.qvm\", \"cgame\" );\n\tFS_FOpenFileRead( filename, &f, qfalse );\n\tif ( f ) {\n\t\tFS_FCloseFile( f );\n\t}\n}\n\n/*\n================\nSV_SpawnServer\n\nChange the server to a new map, taking all connected\nclients along with it.\nThis is NOT called for map_restart\n================\n*/\nvoid SV_SpawnServer( char *server, qboolean killBots ) {\n\tint\t\t\ti;\n\tint\t\t\tchecksum;\n\tqboolean\tisBot;\n\tchar\t\tsystemInfo[16384];\n\tconst char\t*p;\n\n\t// shut down the existing game if it is running\n\tSV_ShutdownGameProgs();\n\n\tCom_Printf (\"------ Server Initialization ------\\n\");\n\tCom_Printf (\"Server: %s\\n\",server);\n\n\t// if not running a dedicated server CL_MapLoading will connect the client to the server\n\t// also print some status stuff\n\tCL_MapLoading();\n\n\t// make sure all the client stuff is unloaded\n\tCL_ShutdownAll();\n\n\t// clear the whole hunk because we're (re)loading the server\n\tHunk_Clear();\n\n\t// clear collision map data\n\tCM_ClearMap();\n\n\t// init client structures and svs.numSnapshotEntities \n\tif ( !Cvar_VariableValue(\"sv_running\") ) {\n\t\tSV_Startup();\n\t} else {\n\t\t// check for maxclients change\n\t\tif ( sv_maxclients->modified ) {\n\t\t\tSV_ChangeMaxClients();\n\t\t}\n\t}\n\n\t// clear pak references\n\tFS_ClearPakReferences(0);\n\n\t// allocate the snapshot entities on the hunk\n\tsvs.snapshotEntities = (entityState_t*) Hunk_Alloc( sizeof(entityState_t)*svs.numSnapshotEntities, h_high );\n\tsvs.nextSnapshotEntities = 0;\n\n\t// toggle the server bit so clients can detect that a\n\t// server has changed\n\tsvs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT;\n\n\t// set nextmap to the same map, but it may be overriden\n\t// by the game startup or another console command\n\tCvar_Set( \"nextmap\", \"map_restart 0\");\n//\tCvar_Set( \"nextmap\", va(\"map %s\", server) );\n\n\t// wipe the entire per-level structure\n\tSV_ClearServer();\n\tfor ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) {\n\t\tsv.configstrings[i] = CopyString(\"\");\n\t}\n\n\t// make sure we are not paused\n\tCvar_Set(\"cl_paused\", \"0\");\n\n\t// get a new checksum feed and restart the file system\n\tsrand(Com_Milliseconds());\n\tsv.checksumFeed = ( ((int) rand() << 16) ^ rand() ) ^ Com_Milliseconds();\n\tFS_Restart( sv.checksumFeed );\n\n\tCM_LoadMap( va(\"maps/%s.bsp\", server), qfalse, &checksum );\n\n\t// set serverinfo visible name\n\tCvar_Set( \"mapname\", server );\n\n\tCvar_Set( \"sv_mapChecksum\", va(\"%i\",checksum) );\n\n\t// serverid should be different each time\n\tsv.serverId = com_frameTime;\n\tsv.restartedServerId = sv.serverId; // I suppose the init here is just to be safe\n\tsv.checksumFeedServerId = sv.serverId;\n\tCvar_Set( \"sv_serverid\", va(\"%i\", sv.serverId ) );\n\n\t// clear physics interaction links\n\tSV_ClearWorld ();\n\t\n\t// media configstring setting should be done during\n\t// the loading stage, so connected clients don't have\n\t// to load during actual gameplay\n\tsv.state = SS_LOADING;\n\n\t// load and spawn all other entities\n\tSV_InitGameProgs();\n\n\t// don't allow a map_restart if game is modified\n\tsv_gametype->modified = qfalse;\n\n\t// run a few frames to allow everything to settle\n\tfor ( i = 0 ;i < 3 ; i++ ) {\n\t\tVM_Call( gvm, GAME_RUN_FRAME, svs.time );\n\t\tSV_BotFrame( svs.time );\n\t\tsvs.time += 100;\n\t}\n\n\t// create a baseline for more efficient communications\n\tSV_CreateBaseline ();\n\n\tfor (i=0 ; i<sv_maxclients->integer ; i++) {\n\t\t// send the new gamestate to all connected clients\n\t\tif (svs.clients[i].state >= CS_CONNECTED) {\n\t\t\tchar\t*denied;\n\n\t\t\tif ( svs.clients[i].netchan.remoteAddress.type == NA_BOT ) {\n\t\t\t\tif ( killBots ) {\n\t\t\t\t\tSV_DropClient( &svs.clients[i], \"\" );\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tisBot = qtrue;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tisBot = qfalse;\n\t\t\t}\n\n\t\t\t// connect the client again\n\t\t\tdenied = (char*) VM_ExplicitArgPtr( gvm, VM_Call( gvm, GAME_CLIENT_CONNECT, i, qfalse, isBot ) );\t// firstTime = qfalse\n\t\t\tif ( denied ) {\n\t\t\t\t// this generally shouldn't happen, because the client\n\t\t\t\t// was connected before the level change\n\t\t\t\tSV_DropClient( &svs.clients[i], denied );\n\t\t\t} else {\n\t\t\t\tif( !isBot ) {\n\t\t\t\t\t// when we get the next packet from a connected client,\n\t\t\t\t\t// the new gamestate will be sent\n\t\t\t\t\tsvs.clients[i].state = CS_CONNECTED;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tclient_t\t\t*client;\n\t\t\t\t\tsharedEntity_t\t*ent;\n\n\t\t\t\t\tclient = &svs.clients[i];\n\t\t\t\t\tclient->state = CS_ACTIVE;\n\t\t\t\t\tent = SV_GentityNum( i );\n\t\t\t\t\tent->s.number = i;\n\t\t\t\t\tclient->gentity = ent;\n\n\t\t\t\t\tclient->deltaMessage = -1;\n\t\t\t\t\tclient->nextSnapshotTime = svs.time;\t// generate a snapshot immediately\n\n\t\t\t\t\tVM_Call( gvm, GAME_CLIENT_BEGIN, i );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\t\n\n\t// run another frame to allow things to look at all the players\n\tVM_Call( gvm, GAME_RUN_FRAME, svs.time );\n\tSV_BotFrame( svs.time );\n\tsvs.time += 100;\n\n\tif ( sv_pure->integer ) {\n\t\t// the server sends these to the clients so they will only\n\t\t// load pk3s also loaded at the server\n\t\tp = FS_LoadedPakChecksums();\n\t\tCvar_Set( \"sv_paks\", p );\n\t\tif (strlen(p) == 0) {\n\t\t\tCom_Printf( \"WARNING: sv_pure set but no PK3 files loaded\\n\" );\n\t\t}\n\t\tp = FS_LoadedPakNames();\n\t\tCvar_Set( \"sv_pakNames\", p );\n\n\t\t// if a dedicated pure server we need to touch the cgame because it could be in a\n\t\t// seperate pk3 file and the client will need to load the latest cgame.qvm\n\t\tif ( com_dedicated->integer ) {\n\t\t\tSV_TouchCGame();\n\t\t}\n\t}\n\telse {\n\t\tCvar_Set( \"sv_paks\", \"\" );\n\t\tCvar_Set( \"sv_pakNames\", \"\" );\n\t}\n\t// the server sends these to the clients so they can figure\n\t// out which pk3s should be auto-downloaded\n\tp = FS_ReferencedPakChecksums();\n\tCvar_Set( \"sv_referencedPaks\", p );\n\tp = FS_ReferencedPakNames();\n\tCvar_Set( \"sv_referencedPakNames\", p );\n\n\t// save systeminfo and serverinfo strings\n\tQ_strncpyz( systemInfo, Cvar_InfoString_Big( CVAR_SYSTEMINFO ), sizeof( systemInfo ) );\n\tcvar_modifiedFlags &= ~CVAR_SYSTEMINFO;\n\tSV_SetConfigstring( CS_SYSTEMINFO, systemInfo );\n\n\tSV_SetConfigstring( CS_SERVERINFO, Cvar_InfoString( CVAR_SERVERINFO ) );\n\tcvar_modifiedFlags &= ~CVAR_SERVERINFO;\n\n\t// any media configstring setting now should issue a warning\n\t// and any configstring changes should be reliably transmitted\n\t// to all clients\n\tsv.state = SS_GAME;\n\n\t// send a heartbeat now so the master will get up to date info\n\tSV_Heartbeat_f();\n\n\tHunk_SetMark();\n\n\tCom_Printf (\"-----------------------------------\\n\");\n}\n\n/*\n===============\nSV_Init\n\nOnly called at main exe startup, not for each game\n===============\n*/\nvoid SV_BotInitBotLib(void);\n\nvoid SV_Init (void) {\n\tSV_AddOperatorCommands ();\n\n\t// serverinfo vars\n\tCvar_Get (\"dmflags\", \"0\", CVAR_SERVERINFO);\n\tCvar_Get (\"fraglimit\", \"20\", CVAR_SERVERINFO);\n\tCvar_Get (\"timelimit\", \"0\", CVAR_SERVERINFO);\n\tsv_gametype = Cvar_Get (\"g_gametype\", \"0\", CVAR_SERVERINFO | CVAR_LATCH );\n\tCvar_Get (\"sv_keywords\", \"\", CVAR_SERVERINFO);\n\tCvar_Get (\"protocol\", va(\"%i\", PROTOCOL_VERSION), CVAR_SERVERINFO | CVAR_ROM);\n\tsv_mapname = Cvar_Get (\"mapname\", \"nomap\", CVAR_SERVERINFO | CVAR_ROM);\n\tsv_privateClients = Cvar_Get (\"sv_privateClients\", \"0\", CVAR_SERVERINFO);\n\tsv_hostname = Cvar_Get (\"sv_hostname\", \"noname\", CVAR_SERVERINFO | CVAR_ARCHIVE );\n\tsv_maxclients = Cvar_Get (\"sv_maxclients\", \"8\", CVAR_SERVERINFO | CVAR_LATCH);\n\n\tsv_maxRate = Cvar_Get (\"sv_maxRate\", \"0\", CVAR_ARCHIVE | CVAR_SERVERINFO );\n\tsv_minPing = Cvar_Get (\"sv_minPing\", \"0\", CVAR_ARCHIVE | CVAR_SERVERINFO );\n\tsv_maxPing = Cvar_Get (\"sv_maxPing\", \"0\", CVAR_ARCHIVE | CVAR_SERVERINFO );\n\tsv_floodProtect = Cvar_Get (\"sv_floodProtect\", \"1\", CVAR_ARCHIVE | CVAR_SERVERINFO );\n\n\t// systeminfo\n\tCvar_Get (\"sv_cheats\", \"1\", CVAR_SYSTEMINFO | CVAR_ROM );\n\tsv_serverid = Cvar_Get (\"sv_serverid\", \"0\", CVAR_SYSTEMINFO | CVAR_ROM );\n#ifndef DLL_ONLY // bk010216 - for DLL-only servers\n\tsv_pure = Cvar_Get (\"sv_pure\", \"1\", CVAR_SYSTEMINFO );\n#else\n\tsv_pure = Cvar_Get (\"sv_pure\", \"0\", CVAR_SYSTEMINFO | CVAR_INIT | CVAR_ROM );\n#endif\n\tCvar_Get (\"sv_paks\", \"\", CVAR_SYSTEMINFO | CVAR_ROM );\n\tCvar_Get (\"sv_pakNames\", \"\", CVAR_SYSTEMINFO | CVAR_ROM );\n\tCvar_Get (\"sv_referencedPaks\", \"\", CVAR_SYSTEMINFO | CVAR_ROM );\n\tCvar_Get (\"sv_referencedPakNames\", \"\", CVAR_SYSTEMINFO | CVAR_ROM );\n\n\t// server vars\n\tsv_rconPassword = Cvar_Get (\"rconPassword\", \"\", CVAR_TEMP );\n\tsv_privatePassword = Cvar_Get (\"sv_privatePassword\", \"\", CVAR_TEMP );\n\tsv_fps = Cvar_Get (\"sv_fps\", \"20\", CVAR_TEMP );\n\tsv_timeout = Cvar_Get (\"sv_timeout\", \"200\", CVAR_TEMP );\n\tsv_zombietime = Cvar_Get (\"sv_zombietime\", \"2\", CVAR_TEMP );\n\tCvar_Get (\"nextmap\", \"\", CVAR_TEMP );\n\n\tsv_allowDownload = Cvar_Get (\"sv_allowDownload\", \"0\", CVAR_SERVERINFO);\n\tsv_master[0] = Cvar_Get (\"sv_master1\", MASTER_SERVER_NAME, 0 );\n\tsv_master[1] = Cvar_Get (\"sv_master2\", \"\", CVAR_ARCHIVE );\n\tsv_master[2] = Cvar_Get (\"sv_master3\", \"\", CVAR_ARCHIVE );\n\tsv_master[3] = Cvar_Get (\"sv_master4\", \"\", CVAR_ARCHIVE );\n\tsv_master[4] = Cvar_Get (\"sv_master5\", \"\", CVAR_ARCHIVE );\n\tsv_reconnectlimit = Cvar_Get (\"sv_reconnectlimit\", \"3\", 0);\n\tsv_showloss = Cvar_Get (\"sv_showloss\", \"0\", 0);\n\tsv_padPackets = Cvar_Get (\"sv_padPackets\", \"0\", 0);\n\tsv_killserver = Cvar_Get (\"sv_killserver\", \"0\", 0);\n\tsv_mapChecksum = Cvar_Get (\"sv_mapChecksum\", \"\", CVAR_ROM);\n\tsv_lanForceRate = Cvar_Get (\"sv_lanForceRate\", \"1\", CVAR_ARCHIVE );\n\tsv_strictAuth = Cvar_Get (\"sv_strictAuth\", \"1\", CVAR_ARCHIVE );\n\n\t// initialize bot cvars so they are listed and can be set before loading the botlib\n\tSV_BotInitCvars();\n\n\t// init the botlib here because we need the pre-compiler in the UI\n\tSV_BotInitBotLib();\n}\n\n\n/*\n==================\nSV_FinalMessage\n\nUsed by SV_Shutdown to send a final message to all\nconnected clients before the server goes down.  The messages are sent immediately,\nnot just stuck on the outgoing message list, because the server is going\nto totally exit after returning from this function.\n==================\n*/\nvoid SV_FinalMessage( char *message ) {\n\tint\t\t\ti, j;\n\tclient_t\t*cl;\n\t\n\t// send it twice, ignoring rate\n\tfor ( j = 0 ; j < 2 ; j++ ) {\n\t\tfor (i=0, cl = svs.clients ; i < sv_maxclients->integer ; i++, cl++) {\n\t\t\tif (cl->state >= CS_CONNECTED) {\n\t\t\t\t// don't send a disconnect to a local client\n\t\t\t\tif ( cl->netchan.remoteAddress.type != NA_LOOPBACK ) {\n\t\t\t\t\tSV_SendServerCommand( cl, \"print \\\"%s\\\"\", message );\n\t\t\t\t\tSV_SendServerCommand( cl, \"disconnect\" );\n\t\t\t\t}\n\t\t\t\t// force a snapshot to be sent\n\t\t\t\tcl->nextSnapshotTime = -1;\n\t\t\t\tSV_SendClientSnapshot( cl );\n\t\t\t}\n\t\t}\n\t}\n}\n\n\n/*\n================\nSV_Shutdown\n\nCalled when each game quits,\nbefore Sys_Quit or Sys_Error\n================\n*/\nvoid SV_Shutdown( char *finalmsg ) {\n\tif ( !com_sv_running || !com_sv_running->integer ) {\n\t\treturn;\n\t}\n\n\tCom_Printf( \"----- Server Shutdown -----\\n\" );\n\n\tif ( svs.clients && !com_errorEntered ) {\n\t\tSV_FinalMessage( finalmsg );\n\t}\n\n\tSV_RemoveOperatorCommands();\n\tSV_MasterShutdown();\n\tSV_ShutdownGameProgs();\n\n\t// free current level\n\tSV_ClearServer();\n\n\t// free server static data\n\tif ( svs.clients ) {\n\t\tZ_Free( svs.clients );\n\t}\n\tCom_Memset( &svs, 0, sizeof( svs ) );\n\n\tCvar_Set( \"sv_running\", \"0\" );\n\tCvar_Set(\"ui_singlePlayerActive\", \"0\");\n\n\tCom_Printf( \"---------------------------\\n\" );\n\n\t// disconnect any local clients\n\tCL_Disconnect( qfalse );\n}\n\n"
  },
  {
    "path": "src/engine/server/sv_main.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n#include \"server.h\"\n\nserverStatic_t\tsvs;\t\t\t\t// persistant server info\nserver_t\t\tsv;\t\t\t\t\t// local server\nvm_t\t\t\t*gvm = NULL;\t\t\t\t// game virtual machine // bk001212 init\n\ncvar_t\t*sv_fps;\t\t\t\t// time rate for running non-clients\ncvar_t\t*sv_timeout;\t\t\t// seconds without any message\ncvar_t\t*sv_zombietime;\t\t\t// seconds to sink messages after disconnect\ncvar_t\t*sv_rconPassword;\t\t// password for remote server commands\ncvar_t\t*sv_privatePassword;\t// password for the privateClient slots\ncvar_t\t*sv_allowDownload;\ncvar_t\t*sv_maxclients;\n\ncvar_t\t*sv_privateClients;\t\t// number of clients reserved for password\ncvar_t\t*sv_hostname;\ncvar_t\t*sv_master[MAX_MASTER_SERVERS];\t\t// master server ip address\ncvar_t\t*sv_reconnectlimit;\t\t// minimum seconds between connect messages\ncvar_t\t*sv_showloss;\t\t\t// report when usercmds are lost\ncvar_t\t*sv_padPackets;\t\t\t// add nop bytes to messages\ncvar_t\t*sv_killserver;\t\t\t// menu system can set to 1 to shut server down\ncvar_t\t*sv_mapname;\ncvar_t\t*sv_mapChecksum;\ncvar_t\t*sv_serverid;\ncvar_t\t*sv_maxRate;\ncvar_t\t*sv_minPing;\ncvar_t\t*sv_maxPing;\ncvar_t\t*sv_gametype;\ncvar_t\t*sv_pure;\ncvar_t\t*sv_floodProtect;\ncvar_t\t*sv_lanForceRate; // dedicated 1 (LAN) server forces local client rates to 99999 (bug #491)\ncvar_t\t*sv_strictAuth;\n\n/*\n=============================================================================\n\nEVENT MESSAGES\n\n=============================================================================\n*/\n\n/*\n===============\nSV_ExpandNewlines\n\nConverts newlines to \"\\n\" so a line prints nicer\n===============\n*/\nchar\t*SV_ExpandNewlines( char *in ) {\n\tstatic\tchar\tstring[1024];\n\tint\t\tl;\n\n\tl = 0;\n\twhile ( *in && l < sizeof(string) - 3 ) {\n\t\tif ( *in == '\\n' ) {\n\t\t\tstring[l++] = '\\\\';\n\t\t\tstring[l++] = 'n';\n\t\t} else {\n\t\t\tstring[l++] = *in;\n\t\t}\n\t\tin++;\n\t}\n\tstring[l] = 0;\n\n\treturn string;\n}\n\n/*\n======================\nSV_ReplacePendingServerCommands\n\n  This is ugly\n======================\n*/\nint SV_ReplacePendingServerCommands( client_t *client, const char *cmd ) {\n\tint i, index, csnum1, csnum2;\n\n\tfor ( i = client->reliableSent+1; i <= client->reliableSequence; i++ ) {\n\t\tindex = i & ( MAX_RELIABLE_COMMANDS - 1 );\n\t\t//\n\t\tif ( !Q_strncmp(cmd, client->reliableCommands[ index ], (int)strlen(\"cs\")) ) {\n\t\t\tsscanf(cmd, \"cs %i\", &csnum1);\n\t\t\tsscanf(client->reliableCommands[ index ], \"cs %i\", &csnum2);\n\t\t\tif ( csnum1 == csnum2 ) {\n\t\t\t\tQ_strncpyz( client->reliableCommands[ index ], cmd, sizeof( client->reliableCommands[ index ] ) );\n\t\t\t\t/*\n\t\t\t\tif ( client->netchan.remoteAddress.type != NA_BOT ) {\n\t\t\t\t\tCom_Printf( \"WARNING: client %i removed double pending config string %i: %s\\n\", client-svs.clients, csnum1, cmd );\n\t\t\t\t}\n\t\t\t\t*/\n\t\t\t\treturn qtrue;\n\t\t\t}\n\t\t}\n\t}\n\treturn qfalse;\n}\n\n/*\n======================\nSV_AddServerCommand\n\nThe given command will be transmitted to the client, and is guaranteed to\nnot have future snapshot_t executed before it is executed\n======================\n*/\nvoid SV_AddServerCommand( client_t *client, const char *cmd ) {\n\tint\t\tindex, i;\n\n\t// this is very ugly but it's also a waste to for instance send multiple config string updates\n\t// for the same config string index in one snapshot\n//\tif ( SV_ReplacePendingServerCommands( client, cmd ) ) {\n//\t\treturn;\n//\t}\n\n\tclient->reliableSequence++;\n\t// if we would be losing an old command that hasn't been acknowledged,\n\t// we must drop the connection\n\t// we check == instead of >= so a broadcast print added by SV_DropClient()\n\t// doesn't cause a recursive drop client\n\tif ( client->reliableSequence - client->reliableAcknowledge == MAX_RELIABLE_COMMANDS + 1 ) {\n\t\tCom_Printf( \"===== pending server commands =====\\n\" );\n\t\tfor ( i = client->reliableAcknowledge + 1 ; i <= client->reliableSequence ; i++ ) {\n\t\t\tCom_Printf( \"cmd %5d: %s\\n\", i, client->reliableCommands[ i & (MAX_RELIABLE_COMMANDS-1) ] );\n\t\t}\n\t\tCom_Printf( \"cmd %5d: %s\\n\", i, cmd );\n\t\tSV_DropClient( client, \"Server command overflow\" );\n\t\treturn;\n\t}\n\tindex = client->reliableSequence & ( MAX_RELIABLE_COMMANDS - 1 );\n\tQ_strncpyz( client->reliableCommands[ index ], cmd, sizeof( client->reliableCommands[ index ] ) );\n}\n\n\n/*\n=================\nSV_SendServerCommand\n\nSends a reliable command string to be interpreted by \nthe client game module: \"cp\", \"print\", \"chat\", etc\nA NULL client will broadcast to all clients\n=================\n*/\nvoid QDECL SV_SendServerCommand(client_t *cl, const char *fmt, ...) {\n\tva_list\t\targptr;\n\tbyte\t\tmessage[MAX_MSGLEN];\n\tclient_t\t*client;\n\tint\t\t\tj;\n\t\n\tva_start (argptr,fmt);\n\tQ_vsnprintf ((char *)message, sizeof(message), fmt,argptr);\n\tva_end (argptr);\n\n\tif ( cl != NULL ) {\n\t\tSV_AddServerCommand( cl, (char *)message );\n\t\treturn;\n\t}\n\n\t// hack to echo broadcast prints to console\n\tif ( com_dedicated->integer && !strncmp( (char *)message, \"print\", 5) ) {\n\t\tCom_Printf (\"broadcast: %s\\n\", SV_ExpandNewlines((char *)message) );\n\t}\n\n\t// send the data to all relevent clients\n\tfor (j = 0, client = svs.clients; j < sv_maxclients->integer ; j++, client++) {\n\t\tif ( client->state < CS_PRIMED ) {\n\t\t\tcontinue;\n\t\t}\n\t\tSV_AddServerCommand( client, (char *)message );\n\t}\n}\n\n\n/*\n==============================================================================\n\nMASTER SERVER FUNCTIONS\n\n==============================================================================\n*/\n\n/*\n================\nSV_MasterHeartbeat\n\nSend a message to the masters every few minutes to\nlet it know we are alive, and log information.\nWe will also have a heartbeat sent when a server\nchanges from empty to non-empty, and full to non-full,\nbut not on every player enter or exit.\n================\n*/\n#define\tHEARTBEAT_MSEC\t300*1000\n#define\tHEARTBEAT_GAME\t\"QuakeArena-1\"\nvoid SV_MasterHeartbeat( void ) {\n\tstatic netadr_t\tadr[MAX_MASTER_SERVERS];\n\tint\t\t\ti;\n\n\t// \"dedicated 1\" is for lan play, \"dedicated 2\" is for inet public play\n\tif ( !com_dedicated || com_dedicated->integer != 2 ) {\n\t\treturn;\t\t// only dedicated servers send heartbeats\n\t}\n\n\t// if not time yet, don't send anything\n\tif ( svs.time < svs.nextHeartbeatTime ) {\n\t\treturn;\n\t}\n\tsvs.nextHeartbeatTime = svs.time + HEARTBEAT_MSEC;\n\n\n\t// send to group masters\n\tfor ( i = 0 ; i < MAX_MASTER_SERVERS ; i++ ) {\n\t\tif ( !sv_master[i]->string[0] ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// see if we haven't already resolved the name\n\t\t// resolving usually causes hitches on win95, so only\n\t\t// do it when needed\n\t\tif ( sv_master[i]->modified ) {\n\t\t\tsv_master[i]->modified = qfalse;\n\t\n\t\t\tCom_Printf( \"Resolving %s\\n\", sv_master[i]->string );\n\t\t\tif ( !NET_StringToAdr( sv_master[i]->string, &adr[i] ) ) {\n\t\t\t\t// if the address failed to resolve, clear it\n\t\t\t\t// so we don't take repeated dns hits\n\t\t\t\tCom_Printf( \"Couldn't resolve address: %s\\n\", sv_master[i]->string );\n\t\t\t\tCvar_Set( sv_master[i]->name, \"\" );\n\t\t\t\tsv_master[i]->modified = qfalse;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif ( !strstr( \":\", sv_master[i]->string ) ) {\n\t\t\t\tadr[i].port = BigShort( PORT_MASTER );\n\t\t\t}\n\t\t\tCom_Printf( \"%s resolved to %i.%i.%i.%i:%i\\n\", sv_master[i]->string,\n\t\t\t\tadr[i].ip[0], adr[i].ip[1], adr[i].ip[2], adr[i].ip[3],\n\t\t\t\tBigShort( adr[i].port ) );\n\t\t}\n\n\n\t\tCom_Printf (\"Sending heartbeat to %s\\n\", sv_master[i]->string );\n\t\t// this command should be changed if the server info / status format\n\t\t// ever incompatably changes\n\t\tNET_OutOfBandPrint( NS_SERVER, adr[i], \"heartbeat %s\\n\", HEARTBEAT_GAME );\n\t}\n}\n\n/*\n=================\nSV_MasterShutdown\n\nInforms all masters that this server is going down\n=================\n*/\nvoid SV_MasterShutdown( void ) {\n\t// send a hearbeat right now\n\tsvs.nextHeartbeatTime = -9999;\n\tSV_MasterHeartbeat();\n\n\t// send it again to minimize chance of drops\n\tsvs.nextHeartbeatTime = -9999;\n\tSV_MasterHeartbeat();\n\n\t// when the master tries to poll the server, it won't respond, so\n\t// it will be removed from the list\n}\n\n\n/*\n==============================================================================\n\nCONNECTIONLESS COMMANDS\n\n==============================================================================\n*/\n\n/*\n================\nSVC_Status\n\nResponds with all the info that qplug or qspy can see about the server\nand all connected players.  Used for getting detailed information after\nthe simple info query.\n================\n*/\nvoid SVC_Status( netadr_t from ) {\n\tchar\tplayer[1024];\n\tchar\tstatus[MAX_MSGLEN];\n\tint\t\ti;\n\tclient_t\t*cl;\n\tplayerState_t\t*ps;\n\tint\t\tstatusLength;\n\tint\t\tplayerLength;\n\tchar\tinfostring[MAX_INFO_STRING];\n\n\t// ignore if we are in single player\n\tif ( Cvar_VariableValue( \"g_gametype\" ) == GT_SINGLE_PLAYER ) {\n\t\treturn;\n\t}\n\n\tstrcpy( infostring, Cvar_InfoString( CVAR_SERVERINFO ) );\n\n\t// echo back the parameter to status. so master servers can use it as a challenge\n\t// to prevent timed spoofed reply packets that add ghost servers\n\tInfo_SetValueForKey( infostring, \"challenge\", Cmd_Argv(1) );\n\n\t// add \"demo\" to the sv_keywords if restricted\n\tif ( Cvar_VariableValue( \"fs_restrict\" ) ) {\n\t\tchar\tkeywords[MAX_INFO_STRING];\n\n\t\tCom_sprintf( keywords, sizeof( keywords ), \"demo %s\",\n\t\t\tInfo_ValueForKey( infostring, \"sv_keywords\" ) );\n\t\tInfo_SetValueForKey( infostring, \"sv_keywords\", keywords );\n\t}\n\n\tstatus[0] = 0;\n\tstatusLength = 0;\n\n\tfor (i=0 ; i < sv_maxclients->integer ; i++) {\n\t\tcl = &svs.clients[i];\n\t\tif ( cl->state >= CS_CONNECTED ) {\n\t\t\tps = SV_GameClientNum( i );\n\t\t\tCom_sprintf (player, sizeof(player), \"%i %i \\\"%s\\\"\\n\", \n\t\t\t\tps->persistant[PERS_SCORE], cl->ping, cl->name);\n\t\t\tplayerLength = (int)strlen(player);\n\t\t\tif (statusLength + playerLength >= sizeof(status) ) {\n\t\t\t\tbreak;\t\t// can't hold any more\n\t\t\t}\n\t\t\tstrcpy (status + statusLength, player);\n\t\t\tstatusLength += playerLength;\n\t\t}\n\t}\n\n\tNET_OutOfBandPrint( NS_SERVER, from, \"statusResponse\\n%s\\n%s\", infostring, status );\n}\n\n/*\n================\nSVC_Info\n\nResponds with a short info message that should be enough to determine\nif a user is interested in a server to do a full status\n================\n*/\nvoid SVC_Info( netadr_t from ) {\n\tint\t\ti, count;\n\tchar\t*gamedir;\n\tchar\tinfostring[MAX_INFO_STRING];\n\n\t// ignore if we are in single player\n\tif ( Cvar_VariableValue( \"g_gametype\" ) == GT_SINGLE_PLAYER || Cvar_VariableValue(\"ui_singlePlayerActive\")) {\n\t\treturn;\n\t}\n\n\t// don't count privateclients\n\tcount = 0;\n\tfor ( i = sv_privateClients->integer ; i < sv_maxclients->integer ; i++ ) {\n\t\tif ( svs.clients[i].state >= CS_CONNECTED ) {\n\t\t\tcount++;\n\t\t}\n\t}\n\n\tinfostring[0] = 0;\n\n\t// echo back the parameter to status. so servers can use it as a challenge\n\t// to prevent timed spoofed reply packets that add ghost servers\n\tInfo_SetValueForKey( infostring, \"challenge\", Cmd_Argv(1) );\n\n\tInfo_SetValueForKey( infostring, \"protocol\", va(\"%i\", PROTOCOL_VERSION) );\n\tInfo_SetValueForKey( infostring, \"hostname\", sv_hostname->string );\n\tInfo_SetValueForKey( infostring, \"mapname\", sv_mapname->string );\n\tInfo_SetValueForKey( infostring, \"clients\", va(\"%i\", count) );\n\tInfo_SetValueForKey( infostring, \"sv_maxclients\", \n\t\tva(\"%i\", sv_maxclients->integer - sv_privateClients->integer ) );\n\tInfo_SetValueForKey( infostring, \"gametype\", va(\"%i\", sv_gametype->integer ) );\n\tInfo_SetValueForKey( infostring, \"pure\", va(\"%i\", sv_pure->integer ) );\n\n\tif( sv_minPing->integer ) {\n\t\tInfo_SetValueForKey( infostring, \"minPing\", va(\"%i\", sv_minPing->integer) );\n\t}\n\tif( sv_maxPing->integer ) {\n\t\tInfo_SetValueForKey( infostring, \"maxPing\", va(\"%i\", sv_maxPing->integer) );\n\t}\n\tgamedir = Cvar_VariableString( \"fs_game\" );\n\tif( *gamedir ) {\n\t\tInfo_SetValueForKey( infostring, \"game\", gamedir );\n\t}\n\n\tNET_OutOfBandPrint( NS_SERVER, from, \"infoResponse\\n%s\", infostring );\n}\n\n/*\n================\nSVC_FlushRedirect\n\n================\n*/\nvoid SV_FlushRedirect( char *outputbuf ) {\n\tNET_OutOfBandPrint( NS_SERVER, svs.redirectAddress, \"print\\n%s\", outputbuf );\n}\n\n/*\n===============\nSVC_RemoteCommand\n\nAn rcon packet arrived from the network.\nShift down the remaining args\nRedirect all printfs\n===============\n*/\nvoid SVC_RemoteCommand( netadr_t from, msg_t *msg ) {\n\tqboolean\tvalid;\n\tunsigned int time;\n\tchar\t\tremaining[1024];\n\t// TTimo - scaled down to accumulate, but not overflow anything network wise, print wise etc.\n\t// (OOB messages are the bottleneck here)\n#define SV_OUTPUTBUF_LENGTH (1024 - 16)\n\tchar\t\tsv_outputbuf[SV_OUTPUTBUF_LENGTH];\n\tstatic unsigned int lasttime = 0;\n\tchar *cmd_aux;\n\n\t// TTimo - https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=534\n\ttime = Com_Milliseconds();\n\tif (time<(lasttime+500)) {\n\t\treturn;\n\t}\n\tlasttime = time;\n\n\tif ( !strlen( sv_rconPassword->string ) ||\n\t\tstrcmp (Cmd_Argv(1), sv_rconPassword->string) ) {\n\t\tvalid = qfalse;\n\t\tCom_Printf (\"Bad rcon from %s:\\n%s\\n\", NET_AdrToString (from), Cmd_Argv(2) );\n\t} else {\n\t\tvalid = qtrue;\n\t\tCom_Printf (\"Rcon from %s:\\n%s\\n\", NET_AdrToString (from), Cmd_Argv(2) );\n\t}\n\n\t// start redirecting all print outputs to the packet\n\tsvs.redirectAddress = from;\n\tCom_BeginRedirect (sv_outputbuf, SV_OUTPUTBUF_LENGTH, SV_FlushRedirect);\n\n\tif ( !strlen( sv_rconPassword->string ) ) {\n\t\tCom_Printf (\"No rconpassword set on the server.\\n\");\n\t} else if ( !valid ) {\n\t\tCom_Printf (\"Bad rconpassword.\\n\");\n\t} else {\n\t\tremaining[0] = 0;\n\t\t\n\t\t// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=543\n\t\t// get the command directly, \"rcon <pass> <command>\" to avoid quoting issues\n\t\t// extract the command by walking\n\t\t// since the cmd formatting can fuckup (amount of spaces), using a dumb step by step parsing\n\t\tcmd_aux = Cmd_Cmd();\n\t\tcmd_aux+=4;\n\t\twhile(cmd_aux[0]==' ')\n\t\t\tcmd_aux++;\n\t\twhile(cmd_aux[0] && cmd_aux[0]!=' ') // password\n\t\t\tcmd_aux++;\n\t\twhile(cmd_aux[0]==' ')\n\t\t\tcmd_aux++;\n\t\t\n\t\tQ_strcat( remaining, sizeof(remaining), cmd_aux);\n\t\t\n\t\tCmd_ExecuteString (remaining);\n\n\t}\n\n\tCom_EndRedirect ();\n}\n\n/*\n=================\nSV_ConnectionlessPacket\n\nA connectionless packet has four leading 0xff\ncharacters to distinguish it from a game channel.\nClients that are in the game can still send\nconnectionless packets.\n=================\n*/\nvoid SV_ConnectionlessPacket( netadr_t from, msg_t *msg ) {\n\tchar\t*s;\n\tchar\t*c;\n\n\tMSG_BeginReadingOOB( msg );\n\tMSG_ReadLong( msg );\t\t// skip the -1 marker\n\n\tif (!Q_strncmp(\"connect\", (const char*) &msg->data[4], 7)) {\n\t\tHuff_Decompress(msg, 12);\n\t}\n\n\ts = MSG_ReadStringLine( msg );\n\tCmd_TokenizeString( s );\n\n\tc = Cmd_Argv(0);\n\tCom_DPrintf (\"SV packet %s : %s\\n\", NET_AdrToString(from), c);\n\n\tif (!Q_stricmp(c, \"getstatus\")) {\n\t\tSVC_Status( from  );\n  } else if (!Q_stricmp(c, \"getinfo\")) {\n\t\tSVC_Info( from );\n\t} else if (!Q_stricmp(c, \"getchallenge\")) {\n\t\tSV_GetChallenge( from );\n\t} else if (!Q_stricmp(c, \"connect\")) {\n\t\tSV_DirectConnect( from );\n\t} else if (!Q_stricmp(c, \"ipAuthorize\")) {\n\t\tSV_AuthorizeIpPacket( from );\n\t} else if (!Q_stricmp(c, \"rcon\")) {\n\t\tSVC_RemoteCommand( from, msg );\n\t} else if (!Q_stricmp(c, \"disconnect\")) {\n\t\t// if a client starts up a local server, we may see some spurious\n\t\t// server disconnect messages when their new server sees our final\n\t\t// sequenced messages to the old client\n\t} else {\n\t\tCom_DPrintf (\"bad connectionless packet from %s:\\n%s\\n\"\n\t\t, NET_AdrToString (from), s);\n\t}\n}\n\n//============================================================================\n\n/*\n=================\nSV_ReadPackets\n=================\n*/\nvoid SV_PacketEvent( netadr_t from, msg_t *msg ) {\n\tint\t\t\ti;\n\tclient_t\t*cl;\n\tint\t\t\tqport;\n\n\t// check for connectionless packet (0xffffffff) first\n\tif ( msg->cursize >= 4 && *(int *)msg->data == -1) {\n\t\tSV_ConnectionlessPacket( from, msg );\n\t\treturn;\n\t}\n\n\t// read the qport out of the message so we can fix up\n\t// stupid address translating routers\n\tMSG_BeginReadingOOB( msg );\n\tMSG_ReadLong( msg );\t\t\t\t// sequence number\n\tqport = MSG_ReadShort( msg ) & 0xffff;\n\n\t// find which client the message is from\n\tfor (i=0, cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++) {\n\t\tif (cl->state == CS_FREE) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( !NET_CompareBaseAdr( from, cl->netchan.remoteAddress ) ) {\n\t\t\tcontinue;\n\t\t}\n\t\t// it is possible to have multiple clients from a single IP\n\t\t// address, so they are differentiated by the qport variable\n\t\tif (cl->netchan.qport != qport) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// the IP port can't be used to differentiate them, because\n\t\t// some address translating routers periodically change UDP\n\t\t// port assignments\n\t\tif (cl->netchan.remoteAddress.port != from.port) {\n\t\t\tCom_Printf( \"SV_PacketEvent: fixing up a translated port\\n\" );\n\t\t\tcl->netchan.remoteAddress.port = from.port;\n\t\t}\n\n\t\t// make sure it is a valid, in sequence packet\n\t\tif (SV_Netchan_Process(cl, msg)) {\n\t\t\t// zombie clients still need to do the Netchan_Process\n\t\t\t// to make sure they don't need to retransmit the final\n\t\t\t// reliable message, but they don't do any other processing\n\t\t\tif (cl->state != CS_ZOMBIE) {\n\t\t\t\tcl->lastPacketTime = svs.time;\t// don't timeout\n\t\t\t\tSV_ExecuteClientMessage( cl, msg );\n\t\t\t}\n\t\t}\n\t\treturn;\n\t}\n\t\n\t// if we received a sequenced packet from an address we don't recognize,\n\t// send an out of band disconnect packet to it\n\tNET_OutOfBandPrint( NS_SERVER, from, \"disconnect\" );\n}\n\n\n/*\n===================\nSV_CalcPings\n\nUpdates the cl->ping variables\n===================\n*/\nvoid SV_CalcPings( void ) {\n\tint\t\t\ti, j;\n\tclient_t\t*cl;\n\tint\t\t\ttotal, count;\n\tint\t\t\tdelta;\n\tplayerState_t\t*ps;\n\n\tfor (i=0 ; i < sv_maxclients->integer ; i++) {\n\t\tcl = &svs.clients[i];\n\t\tif ( cl->state != CS_ACTIVE ) {\n\t\t\tcl->ping = 999;\n\t\t\tcontinue;\n\t\t}\n\t\tif ( !cl->gentity ) {\n\t\t\tcl->ping = 999;\n\t\t\tcontinue;\n\t\t}\n\t\tif ( cl->gentity->r.svFlags & SVF_BOT ) {\n\t\t\tcl->ping = 0;\n\t\t\tcontinue;\n\t\t}\n\n\t\ttotal = 0;\n\t\tcount = 0;\n\t\tfor ( j = 0 ; j < PACKET_BACKUP ; j++ ) {\n\t\t\tif ( cl->frames[j].messageAcked <= 0 ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tdelta = cl->frames[j].messageAcked - cl->frames[j].messageSent;\n\t\t\tcount++;\n\t\t\ttotal += delta;\n\t\t}\n\t\tif (!count) {\n\t\t\tcl->ping = 999;\n\t\t} else {\n\t\t\tcl->ping = total/count;\n\t\t\tif ( cl->ping > 999 ) {\n\t\t\t\tcl->ping = 999;\n\t\t\t}\n\t\t}\n\n\t\t// let the game dll know about the ping\n\t\tps = SV_GameClientNum( i );\n\t\tps->ping = cl->ping;\n\t}\n}\n\n/*\n==================\nSV_CheckTimeouts\n\nIf a packet has not been received from a client for timeout->integer \nseconds, drop the conneciton.  Server time is used instead of\nrealtime to avoid dropping the local client while debugging.\n\nWhen a client is normally dropped, the client_t goes into a zombie state\nfor a few seconds to make sure any final reliable message gets resent\nif necessary\n==================\n*/\nvoid SV_CheckTimeouts( void ) {\n\tint\t\ti;\n\tclient_t\t*cl;\n\tint\t\t\tdroppoint;\n\tint\t\t\tzombiepoint;\n\n\tdroppoint = svs.time - 1000 * sv_timeout->integer;\n\tzombiepoint = svs.time - 1000 * sv_zombietime->integer;\n\n\tfor (i=0,cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++) {\n\t\t// message times may be wrong across a changelevel\n\t\tif (cl->lastPacketTime > svs.time) {\n\t\t\tcl->lastPacketTime = svs.time;\n\t\t}\n\n\t\tif (cl->state == CS_ZOMBIE\n\t\t&& cl->lastPacketTime < zombiepoint) {\n\t\t\t// using the client id cause the cl->name is empty at this point\n\t\t\tCom_DPrintf( \"Going from CS_ZOMBIE to CS_FREE for client %d\\n\", i );\n\t\t\tcl->state = CS_FREE;\t// can now be reused\n\t\t\tcontinue;\n\t\t}\n\t\tif ( cl->state >= CS_CONNECTED && cl->lastPacketTime < droppoint) {\n\t\t\t// wait several frames so a debugger session doesn't\n\t\t\t// cause a timeout\n\t\t\tif ( ++cl->timeoutCount > 5 ) {\n\t\t\t\tSV_DropClient (cl, \"timed out\"); \n\t\t\t\tcl->state = CS_FREE;\t// don't bother with zombie state\n\t\t\t}\n\t\t} else {\n\t\t\tcl->timeoutCount = 0;\n\t\t}\n\t}\n}\n\n\n/*\n==================\nSV_CheckPaused\n==================\n*/\nqboolean SV_CheckPaused( void ) {\n\tint\t\tcount;\n\tclient_t\t*cl;\n\tint\t\ti;\n\n\tif ( !cl_paused->integer ) {\n\t\treturn qfalse;\n\t}\n\n\t// only pause if there is just a single client connected\n\tcount = 0;\n\tfor (i=0,cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++) {\n\t\tif ( cl->state >= CS_CONNECTED && cl->netchan.remoteAddress.type != NA_BOT ) {\n\t\t\tcount++;\n\t\t}\n\t}\n\n\tif ( count > 1 ) {\n\t\t// don't pause\n\t\tif (sv_paused->integer)\n\t\t\tCvar_Set(\"sv_paused\", \"0\");\n\t\treturn qfalse;\n\t}\n\n\tif (!sv_paused->integer)\n\t\tCvar_Set(\"sv_paused\", \"1\");\n\treturn qtrue;\n}\n\n/*\n==================\nSV_Frame\n\nPlayer movement occurs as a result of packet events, which\nhappen before SV_Frame is called\n==================\n*/\nvoid SV_Frame( int msec ) {\n\tint\t\tframeMsec;\n\tint\t\tstartTime;\n\n\t// the menu kills the server with this cvar\n\tif ( sv_killserver->integer ) {\n\t\tSV_Shutdown (\"Server was killed.\\n\");\n\t\tCvar_Set( \"sv_killserver\", \"0\" );\n\t\treturn;\n\t}\n\n\tif ( !com_sv_running->integer ) {\n\t\treturn;\n\t}\n\n\t// allow pause if only the local client is connected\n\tif ( SV_CheckPaused() ) {\n\t\treturn;\n\t}\n\n\t// if it isn't time for the next frame, do nothing\n\tif ( sv_fps->integer < 1 ) {\n\t\tCvar_Set( \"sv_fps\", \"10\" );\n\t}\n\tframeMsec = 1000 / sv_fps->integer ;\n\n\tsv.timeResidual += msec;\n\n\tif (!com_dedicated->integer) SV_BotFrame( svs.time + sv.timeResidual );\n\n\tif ( com_dedicated->integer && sv.timeResidual < frameMsec ) {\n\t\t// NET_Sleep will give the OS time slices until either get a packet\n\t\t// or time enough for a server frame has gone by\n\t\tNET_Sleep(frameMsec - sv.timeResidual);\n\t\treturn;\n\t}\n\n\t// if time is about to hit the 32nd bit, kick all clients\n\t// and clear sv.time, rather\n\t// than checking for negative time wraparound everywhere.\n\t// 2giga-milliseconds = 23 days, so it won't be too often\n\tif ( svs.time > 0x70000000 ) {\n\t\tSV_Shutdown( \"Restarting server due to time wrapping\" );\n\t\tCbuf_AddText( \"vstr nextmap\\n\" );\n\t\treturn;\n\t}\n\t// this can happen considerably earlier when lots of clients play and the map doesn't change\n\tif ( svs.nextSnapshotEntities >= 0x7FFFFFFE - svs.numSnapshotEntities ) {\n\t\tSV_Shutdown( \"Restarting server due to numSnapshotEntities wrapping\" );\n\t\tCbuf_AddText( \"vstr nextmap\\n\" );\n\t\treturn;\n\t}\n\n\tif( sv.restartTime && svs.time >= sv.restartTime ) {\n\t\tsv.restartTime = 0;\n\t\tCbuf_AddText( \"map_restart 0\\n\" );\n\t\treturn;\n\t}\n\n\t// update infostrings if anything has been changed\n\tif ( cvar_modifiedFlags & CVAR_SERVERINFO ) {\n\t\tSV_SetConfigstring( CS_SERVERINFO, Cvar_InfoString( CVAR_SERVERINFO ) );\n\t\tcvar_modifiedFlags &= ~CVAR_SERVERINFO;\n\t}\n\tif ( cvar_modifiedFlags & CVAR_SYSTEMINFO ) {\n\t\tSV_SetConfigstring( CS_SYSTEMINFO, Cvar_InfoString_Big( CVAR_SYSTEMINFO ) );\n\t\tcvar_modifiedFlags &= ~CVAR_SYSTEMINFO;\n\t}\n\n\tif ( com_speeds->integer ) {\n\t\tstartTime = Sys_Milliseconds ();\n\t} else {\n\t\tstartTime = 0;\t// quite a compiler warning\n\t}\n\n\t// update ping based on the all received frames\n\tSV_CalcPings();\n\n\tif (com_dedicated->integer) SV_BotFrame( svs.time );\n\n\t// run the game simulation in chunks\n\twhile ( sv.timeResidual >= frameMsec ) {\n\t\tsv.timeResidual -= frameMsec;\n\t\tsvs.time += frameMsec;\n\n\t\t// let everything in the world think and move\n\t\tVM_Call( gvm, GAME_RUN_FRAME, svs.time );\n\t}\n\n\tif ( com_speeds->integer ) {\n\t\ttime_game = Sys_Milliseconds () - startTime;\n\t}\n\n\t// check timeouts\n\tSV_CheckTimeouts();\n\n\t// send messages back to the clients\n\tSV_SendClientMessages();\n\n\t// send a heartbeat to the master if needed\n\tSV_MasterHeartbeat();\n}\n\n//============================================================================\n\n"
  },
  {
    "path": "src/engine/server/sv_net_chan.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n#include \"../../game/q_shared.h\"\n#include \"../qcommon/qcommon.h\"\n#include \"server.h\"\n\n/*\n==============\nSV_Netchan_Encode\n\n\t// first four bytes of the data are always:\n\tlong reliableAcknowledge;\n\n==============\n*/\nstatic void SV_Netchan_Encode( client_t *client, msg_t *msg ) {\n\tlong reliableAcknowledge, i, index;\n\tbyte key, *string;\n        int\tsrdc, sbit, soob;\n        \n\tif ( msg->cursize < SV_ENCODE_START ) {\n\t\treturn;\n\t}\n\n        srdc = msg->readcount;\n        sbit = msg->bit;\n        soob = msg->oob;\n        \n        msg->bit = 0;\n        msg->readcount = 0;\n        msg->oob = (qboolean) 0;\n        \n\treliableAcknowledge = MSG_ReadLong(msg);\n\n\t\tmsg->oob = (qboolean) soob;\n        msg->bit = sbit;\n        msg->readcount = srdc;\n        \n\tstring = (byte *)client->lastClientCommandString;\n\tindex = 0;\n\t// xor the client challenge with the netchan sequence number\n\tkey = client->challenge ^ client->netchan.outgoingSequence;\n\tfor (i = SV_ENCODE_START; i < msg->cursize; i++) {\n\t\t// modify the key with the last received and with this message acknowledged client command\n\t\tif (!string[index])\n\t\t\tindex = 0;\n\t\tif (string[index] > 127 || string[index] == '%') {\n\t\t\tkey ^= '.' << (i & 1);\n\t\t}\n\t\telse {\n\t\t\tkey ^= string[index] << (i & 1);\n\t\t}\n\t\tindex++;\n\t\t// encode the data with this key\n\t\t*(msg->data + i) = *(msg->data + i) ^ key;\n\t}\n}\n\n/*\n==============\nSV_Netchan_Decode\n\n\t// first 12 bytes of the data are always:\n\tlong serverId;\n\tlong messageAcknowledge;\n\tlong reliableAcknowledge;\n\n==============\n*/\nstatic void SV_Netchan_Decode( client_t *client, msg_t *msg ) {\n\tint serverId, messageAcknowledge, reliableAcknowledge;\n\tint i, index, srdc, sbit, soob;\n\tbyte key, *string;\n\n        srdc = msg->readcount;\n        sbit = msg->bit;\n        soob = msg->oob;\n        \n\t\tmsg->oob = (qboolean) 0;\n        \n        serverId = MSG_ReadLong(msg);\n\tmessageAcknowledge = MSG_ReadLong(msg);\n\treliableAcknowledge = MSG_ReadLong(msg);\n\n    msg->oob = (qboolean) soob;\n        msg->bit = sbit;\n        msg->readcount = srdc;\n        \n\tstring = (byte *)client->reliableCommands[ reliableAcknowledge & (MAX_RELIABLE_COMMANDS-1) ];\n\tindex = 0;\n\t//\n\tkey = client->challenge ^ serverId ^ messageAcknowledge;\n\tfor (i = msg->readcount + SV_DECODE_START; i < msg->cursize; i++) {\n\t\t// modify the key with the last sent and acknowledged server command\n\t\tif (!string[index])\n\t\t\tindex = 0;\n\t\tif (string[index] > 127 || string[index] == '%') {\n\t\t\tkey ^= '.' << (i & 1);\n\t\t}\n\t\telse {\n\t\t\tkey ^= string[index] << (i & 1);\n\t\t}\n\t\tindex++;\n\t\t// decode the data with this key\n\t\t*(msg->data + i) = *(msg->data + i) ^ key;\n\t}\n}\n\n/*\n=================\nSV_Netchan_TransmitNextFragment\n=================\n*/\nvoid SV_Netchan_TransmitNextFragment( client_t *client ) {\n\tNetchan_TransmitNextFragment( &client->netchan );\n\tif (!client->netchan.unsentFragments)\n\t{\n\t\t// make sure the netchan queue has been properly initialized (you never know)\n\t\tif (!client->netchan_end_queue) {\n\t\t\tCom_Error(ERR_DROP, \"netchan queue is not properly initialized in SV_Netchan_TransmitNextFragment\\n\");\n\t\t}\n\t\t// the last fragment was transmitted, check wether we have queued messages\n\t\tif (client->netchan_start_queue) {\n\t\t\tnetchan_buffer_t *netbuf;\n\t\t\tCom_DPrintf(\"#462 Netchan_TransmitNextFragment: popping a queued message for transmit\\n\");\n\t\t\tnetbuf = client->netchan_start_queue;\n\t\t\tSV_Netchan_Encode( client, &netbuf->msg );\n\t\t\tNetchan_Transmit( &client->netchan, netbuf->msg.cursize, netbuf->msg.data );\n\t\t\t// pop from queue\n\t\t\tclient->netchan_start_queue = netbuf->next;\n\t\t\tif (!client->netchan_start_queue) {\n\t\t\t\tCom_DPrintf(\"#462 Netchan_TransmitNextFragment: emptied queue\\n\");\n\t\t\t\tclient->netchan_end_queue = &client->netchan_start_queue;\n\t\t\t}\n\t\t\telse\n\t\t\t\tCom_DPrintf(\"#462 Netchan_TransmitNextFragment: remaining queued message\\n\");\n\t\t\tZ_Free(netbuf);\n\t\t} \n\t}\t\n}\n\n\n/*\n===============\nSV_Netchan_Transmit\nTTimo\nhttps://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=462\nif there are some unsent fragments (which may happen if the snapshots\nand the gamestate are fragmenting, and collide on send for instance)\nthen buffer them and make sure they get sent in correct order\n================\n*/\n\nvoid SV_Netchan_Transmit( client_t *client, msg_t *msg) {\t//int length, const byte *data ) {\n\tMSG_WriteByte( msg, svc_EOF );\n\tif (client->netchan.unsentFragments) {\n\t\tnetchan_buffer_t *netbuf;\n\t\tCom_DPrintf(\"#462 SV_Netchan_Transmit: unsent fragments, stacked\\n\");\n\t\tnetbuf = (netchan_buffer_t *)Z_Malloc(sizeof(netchan_buffer_t));\n\t\t// store the msg, we can't store it encoded, as the encoding depends on stuff we still have to finish sending\n\t\tMSG_Copy(&netbuf->msg, netbuf->msgBuffer, sizeof( netbuf->msgBuffer ), msg);\n\t\tnetbuf->next = NULL;\n\t\t// insert it in the queue, the message will be encoded and sent later\n\t\t*client->netchan_end_queue = netbuf;\n\t\tclient->netchan_end_queue = &(*client->netchan_end_queue)->next;\n\t\t// emit the next fragment of the current message for now\n\t\tNetchan_TransmitNextFragment(&client->netchan);\n\t} else {\n\t\tSV_Netchan_Encode( client, msg );\n\t\tNetchan_Transmit( &client->netchan, msg->cursize, msg->data );\n\t}\n}\n\n/*\n=================\nNetchan_SV_Process\n=================\n*/\nqboolean SV_Netchan_Process( client_t *client, msg_t *msg ) {\n\tint ret;\n\tret = Netchan_Process( &client->netchan, msg );\n\tif (!ret)\n\t\treturn qfalse;\n\tSV_Netchan_Decode( client, msg );\n\treturn qtrue;\n}\n\n"
  },
  {
    "path": "src/engine/server/sv_snapshot.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n#include \"server.h\"\n\n\n/*\n=============================================================================\n\nDelta encode a client frame onto the network channel\n\nA normal server packet will look like:\n\n4\tsequence number (high bit set if an oversize fragment)\n<optional reliable commands>\n1\tsvc_snapshot\n4\tlast client reliable command\n4\tserverTime\n1\tlastframe for delta compression\n1\tsnapFlags\n1\tareaBytes\n<areabytes>\n<playerstate>\n<packetentities>\n\n=============================================================================\n*/\n\n/*\n=============\nSV_EmitPacketEntities\n\nWrites a delta update of an entityState_t list to the message.\n=============\n*/\nstatic void SV_EmitPacketEntities( clientSnapshot_t *from, clientSnapshot_t *to, msg_t *msg ) {\n\tentityState_t\t*oldent, *newent;\n\tint\t\toldindex, newindex;\n\tint\t\toldnum, newnum;\n\tint\t\tfrom_num_entities;\n\n\t// generate the delta update\n\tif ( !from ) {\n\t\tfrom_num_entities = 0;\n\t} else {\n\t\tfrom_num_entities = from->num_entities;\n\t}\n\n\tnewent = NULL;\n\toldent = NULL;\n\tnewindex = 0;\n\toldindex = 0;\n\twhile ( newindex < to->num_entities || oldindex < from_num_entities ) {\n\t\tif ( newindex >= to->num_entities ) {\n\t\t\tnewnum = 9999;\n\t\t} else {\n\t\t\tnewent = &svs.snapshotEntities[(to->first_entity+newindex) % svs.numSnapshotEntities];\n\t\t\tnewnum = newent->number;\n\t\t}\n\n\t\tif ( oldindex >= from_num_entities ) {\n\t\t\toldnum = 9999;\n\t\t} else {\n\t\t\toldent = &svs.snapshotEntities[(from->first_entity+oldindex) % svs.numSnapshotEntities];\n\t\t\toldnum = oldent->number;\n\t\t}\n\n\t\tif ( newnum == oldnum ) {\n\t\t\t// delta update from old position\n\t\t\t// because the force parm is qfalse, this will not result\n\t\t\t// in any bytes being emited if the entity has not changed at all\n\t\t\tMSG_WriteDeltaEntity (msg, oldent, newent, qfalse );\n\t\t\toldindex++;\n\t\t\tnewindex++;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif ( newnum < oldnum ) {\n\t\t\t// this is a new entity, send it from the baseline\n\t\t\tMSG_WriteDeltaEntity (msg, &sv.svEntities[newnum].baseline, newent, qtrue );\n\t\t\tnewindex++;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif ( newnum > oldnum ) {\n\t\t\t// the old entity isn't present in the new message\n\t\t\tMSG_WriteDeltaEntity (msg, oldent, NULL, qtrue );\n\t\t\toldindex++;\n\t\t\tcontinue;\n\t\t}\n\t}\n\n\tMSG_WriteBits( msg, (MAX_GENTITIES-1), GENTITYNUM_BITS );\t// end of packetentities\n}\n\n\n\n/*\n==================\nSV_WriteSnapshotToClient\n==================\n*/\nstatic void SV_WriteSnapshotToClient( client_t *client, msg_t *msg ) {\n\tclientSnapshot_t\t*frame, *oldframe;\n\tint\t\t\t\t\tlastframe;\n\tint\t\t\t\t\ti;\n\tint\t\t\t\t\tsnapFlags;\n\n\t// this is the snapshot we are creating\n\tframe = &client->frames[ client->netchan.outgoingSequence & PACKET_MASK ];\n\n\t// try to use a previous frame as the source for delta compressing the snapshot\n\tif ( client->deltaMessage <= 0 || client->state != CS_ACTIVE ) {\n\t\t// client is asking for a retransmit\n\t\toldframe = NULL;\n\t\tlastframe = 0;\n\t} else if ( client->netchan.outgoingSequence - client->deltaMessage \n\t\t>= (PACKET_BACKUP - 3) ) {\n\t\t// client hasn't gotten a good message through in a long time\n\t\tCom_DPrintf (\"%s: Delta request from out of date packet.\\n\", client->name);\n\t\toldframe = NULL;\n\t\tlastframe = 0;\n\t} else {\n\t\t// we have a valid snapshot to delta from\n\t\toldframe = &client->frames[ client->deltaMessage & PACKET_MASK ];\n\t\tlastframe = client->netchan.outgoingSequence - client->deltaMessage;\n\n\t\t// the snapshot's entities may still have rolled off the buffer, though\n\t\tif ( oldframe->first_entity <= svs.nextSnapshotEntities - svs.numSnapshotEntities ) {\n\t\t\tCom_DPrintf (\"%s: Delta request from out of date entities.\\n\", client->name);\n\t\t\toldframe = NULL;\n\t\t\tlastframe = 0;\n\t\t}\n\t}\n\n\tMSG_WriteByte (msg, svc_snapshot);\n\n\t// NOTE, MRE: now sent at the start of every message from server to client\n\t// let the client know which reliable clientCommands we have received\n\t//MSG_WriteLong( msg, client->lastClientCommand );\n\n\t// send over the current server time so the client can drift\n\t// its view of time to try to match\n\tMSG_WriteLong (msg, svs.time);\n\n\t// what we are delta'ing from\n\tMSG_WriteByte (msg, lastframe);\n\n\tsnapFlags = svs.snapFlagServerBit;\n\tif ( client->rateDelayed ) {\n\t\tsnapFlags |= SNAPFLAG_RATE_DELAYED;\n\t}\n\tif ( client->state != CS_ACTIVE ) {\n\t\tsnapFlags |= SNAPFLAG_NOT_ACTIVE;\n\t}\n\n\tMSG_WriteByte (msg, snapFlags);\n\n\t// send over the areabits\n\tMSG_WriteByte (msg, frame->areabytes);\n\tMSG_WriteData (msg, frame->areabits, frame->areabytes);\n\n\t// delta encode the playerstate\n\tif ( oldframe ) {\n\t\tMSG_WriteDeltaPlayerstate( msg, &oldframe->ps, &frame->ps );\n\t} else {\n\t\tMSG_WriteDeltaPlayerstate( msg, NULL, &frame->ps );\n\t}\n\n\t// delta encode the entities\n\tSV_EmitPacketEntities (oldframe, frame, msg);\n\n\t// padding for rate debugging\n\tif ( sv_padPackets->integer ) {\n\t\tfor ( i = 0 ; i < sv_padPackets->integer ; i++ ) {\n\t\t\tMSG_WriteByte (msg, svc_nop);\n\t\t}\n\t}\n}\n\n\n/*\n==================\nSV_UpdateServerCommandsToClient\n\n(re)send all server commands the client hasn't acknowledged yet\n==================\n*/\nvoid SV_UpdateServerCommandsToClient( client_t *client, msg_t *msg ) {\n\tint\t\ti;\n\n\t// write any unacknowledged serverCommands\n\tfor ( i = client->reliableAcknowledge + 1 ; i <= client->reliableSequence ; i++ ) {\n\t\tMSG_WriteByte( msg, svc_serverCommand );\n\t\tMSG_WriteLong( msg, i );\n\t\tMSG_WriteString( msg, client->reliableCommands[ i & (MAX_RELIABLE_COMMANDS-1) ] );\n\t}\n\tclient->reliableSent = client->reliableSequence;\n}\n\n/*\n=============================================================================\n\nBuild a client snapshot structure\n\n=============================================================================\n*/\n\n#define\tMAX_SNAPSHOT_ENTITIES\t1024\ntypedef struct {\n\tint\t\tnumSnapshotEntities;\n\tint\t\tsnapshotEntities[MAX_SNAPSHOT_ENTITIES];\t\n} snapshotEntityNumbers_t;\n\n/*\n=======================\nSV_QsortEntityNumbers\n=======================\n*/\nstatic int QDECL SV_QsortEntityNumbers( const void *a, const void *b ) {\n\tint\t*ea, *eb;\n\n\tea = (int *)a;\n\teb = (int *)b;\n\n\tif ( *ea == *eb ) {\n\t\tCom_Error( ERR_DROP, \"SV_QsortEntityStates: duplicated entity\" );\n\t}\n\n\tif ( *ea < *eb ) {\n\t\treturn -1;\n\t}\n\n\treturn 1;\n}\n\n\n/*\n===============\nSV_AddEntToSnapshot\n===============\n*/\nstatic void SV_AddEntToSnapshot( svEntity_t *svEnt, sharedEntity_t *gEnt, snapshotEntityNumbers_t *eNums ) {\n\t// if we have already added this entity to this snapshot, don't add again\n\tif ( svEnt->snapshotCounter == sv.snapshotCounter ) {\n\t\treturn;\n\t}\n\tsvEnt->snapshotCounter = sv.snapshotCounter;\n\n\t// if we are full, silently discard entities\n\tif ( eNums->numSnapshotEntities == MAX_SNAPSHOT_ENTITIES ) {\n\t\treturn;\n\t}\n\n\teNums->snapshotEntities[ eNums->numSnapshotEntities ] = gEnt->s.number;\n\teNums->numSnapshotEntities++;\n}\n\n/*\n===============\nSV_AddEntitiesVisibleFromPoint\n===============\n*/\nstatic void SV_AddEntitiesVisibleFromPoint( vec3_t origin, clientSnapshot_t *frame, \n\t\t\t\t\t\t\t\t\tsnapshotEntityNumbers_t *eNums, qboolean portal ) {\n\tint\t\te, i;\n\tsharedEntity_t *ent;\n\tsvEntity_t\t*svEnt;\n\tint\t\tl;\n\tint\t\tclientarea, clientcluster;\n\tint\t\tleafnum;\n\tint\t\tc_fullsend;\n\tbyte\t*clientpvs;\n\tbyte\t*bitvector;\n\n\t// during an error shutdown message we may need to transmit\n\t// the shutdown message after the server has shutdown, so\n\t// specfically check for it\n\tif ( !sv.state ) {\n\t\treturn;\n\t}\n\n\tleafnum = CM_PointLeafnum (origin);\n\tclientarea = CM_LeafArea (leafnum);\n\tclientcluster = CM_LeafCluster (leafnum);\n\n\t// calculate the visible areas\n\tframe->areabytes = CM_WriteAreaBits( frame->areabits, clientarea );\n\n\tclientpvs = CM_ClusterPVS (clientcluster);\n\n\tc_fullsend = 0;\n\n\tfor ( e = 0 ; e < sv.num_entities ; e++ ) {\n\t\tent = SV_GentityNum(e);\n\n\t\t// never send entities that aren't linked in\n\t\tif ( !ent->r.linked ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (ent->s.number != e) {\n\t\t\tCom_DPrintf (\"FIXING ENT->S.NUMBER!!!\\n\");\n\t\t\tent->s.number = e;\n\t\t}\n\n\t\t// entities can be flagged to explicitly not be sent to the client\n\t\tif ( ent->r.svFlags & SVF_NOCLIENT ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// entities can be flagged to be sent to only one client\n\t\tif ( ent->r.svFlags & SVF_SINGLECLIENT ) {\n\t\t\tif ( ent->r.singleClient != frame->ps.clientNum ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\t// entities can be flagged to be sent to everyone but one client\n\t\tif ( ent->r.svFlags & SVF_NOTSINGLECLIENT ) {\n\t\t\tif ( ent->r.singleClient == frame->ps.clientNum ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\t// entities can be flagged to be sent to a given mask of clients\n\t\tif ( ent->r.svFlags & SVF_CLIENTMASK ) {\n\t\t\tif (frame->ps.clientNum >= 32)\n\t\t\t\tCom_Error( ERR_DROP, \"SVF_CLIENTMASK: cientNum > 32\\n\" );\n\t\t\tif (~ent->r.singleClient & (1 << frame->ps.clientNum))\n\t\t\t\tcontinue;\n\t\t}\n\n\t\tsvEnt = SV_SvEntityForGentity( ent );\n\n\t\t// don't double add an entity through portals\n\t\tif ( svEnt->snapshotCounter == sv.snapshotCounter ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// broadcast entities are always sent\n\t\tif ( ent->r.svFlags & SVF_BROADCAST ) {\n\t\t\tSV_AddEntToSnapshot( svEnt, ent, eNums );\n\t\t\tcontinue;\n\t\t}\n\n\t\t// ignore if not touching a PV leaf\n\t\t// check area\n\t\tif ( !CM_AreasConnected( clientarea, svEnt->areanum ) ) {\n\t\t\t// doors can legally straddle two areas, so\n\t\t\t// we may need to check another one\n\t\t\tif ( !CM_AreasConnected( clientarea, svEnt->areanum2 ) ) {\n\t\t\t\tcontinue;\t\t// blocked by a door\n\t\t\t}\n\t\t}\n\n\t\tbitvector = clientpvs;\n\n\t\t// check individual leafs\n\t\tif ( !svEnt->numClusters ) {\n\t\t\tcontinue;\n\t\t}\n\t\tl = 0;\n\t\tfor ( i=0 ; i < svEnt->numClusters ; i++ ) {\n\t\t\tl = svEnt->clusternums[i];\n\t\t\tif ( bitvector[l >> 3] & (1 << (l&7) ) ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// if we haven't found it to be visible,\n\t\t// check overflow clusters that coudln't be stored\n\t\tif ( i == svEnt->numClusters ) {\n\t\t\tif ( svEnt->lastCluster ) {\n\t\t\t\tfor ( ; l <= svEnt->lastCluster ; l++ ) {\n\t\t\t\t\tif ( bitvector[l >> 3] & (1 << (l&7) ) ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif ( l == svEnt->lastCluster ) {\n\t\t\t\t\tcontinue;\t// not visible\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\t// add it\n\t\tSV_AddEntToSnapshot( svEnt, ent, eNums );\n\n\t\t// if its a portal entity, add everything visible from its camera position\n\t\tif ( ent->r.svFlags & SVF_PORTAL ) {\n\t\t\tif ( ent->s.generic1 ) {\n\t\t\t\tvec3_t dir;\n\t\t\t\tVectorSubtract(ent->s.origin, origin, dir);\n\t\t\t\tif ( VectorLengthSquared(dir) > (float) ent->s.generic1 * ent->s.generic1 ) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\tSV_AddEntitiesVisibleFromPoint( ent->s.origin2, frame, eNums, qtrue );\n\t\t}\n\n\t}\n}\n\n/*\n=============\nSV_BuildClientSnapshot\n\nDecides which entities are going to be visible to the client, and\ncopies off the playerstate and areabits.\n\nThis properly handles multiple recursive portals, but the render\ncurrently doesn't.\n\nFor viewing through other player's eyes, clent can be something other than client->gentity\n=============\n*/\nstatic void SV_BuildClientSnapshot( client_t *client ) {\n\tvec3_t\t\t\t\t\t\torg;\n\tclientSnapshot_t\t\t\t*frame;\n\tsnapshotEntityNumbers_t\t\tentityNumbers;\n\tint\t\t\t\t\t\t\ti;\n\tsharedEntity_t\t\t\t\t*ent;\n\tentityState_t\t\t\t\t*state;\n\tsvEntity_t\t\t\t\t\t*svEnt;\n\tsharedEntity_t\t\t\t\t*clent;\n\tint\t\t\t\t\t\t\tclientNum;\n\tplayerState_t\t\t\t\t*ps;\n\n\t// bump the counter used to prevent double adding\n\tsv.snapshotCounter++;\n\n\t// this is the frame we are creating\n\tframe = &client->frames[ client->netchan.outgoingSequence & PACKET_MASK ];\n\n\t// clear everything in this snapshot\n\tentityNumbers.numSnapshotEntities = 0;\n\tCom_Memset( frame->areabits, 0, sizeof( frame->areabits ) );\n\n  // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=62\n\tframe->num_entities = 0;\n\t\n\tclent = client->gentity;\n\tif ( !clent || client->state == CS_ZOMBIE ) {\n\t\treturn;\n\t}\n\n\t// grab the current playerState_t\n\tps = SV_GameClientNum( client - svs.clients );\n\tframe->ps = *ps;\n\n\t// never send client's own entity, because it can\n\t// be regenerated from the playerstate\n\tclientNum = frame->ps.clientNum;\n\tif ( clientNum < 0 || clientNum >= MAX_GENTITIES ) {\n\t\tCom_Error( ERR_DROP, \"SV_SvEntityForGentity: bad gEnt\" );\n\t}\n\tsvEnt = &sv.svEntities[ clientNum ];\n\n\tsvEnt->snapshotCounter = sv.snapshotCounter;\n\n\t// find the client's viewpoint\n\tVectorCopy( ps->origin, org );\n\torg[2] += ps->viewheight;\n\n\t// add all the entities directly visible to the eye, which\n\t// may include portal entities that merge other viewpoints\n\tSV_AddEntitiesVisibleFromPoint( org, frame, &entityNumbers, qfalse );\n\n\t// if there were portals visible, there may be out of order entities\n\t// in the list which will need to be resorted for the delta compression\n\t// to work correctly.  This also catches the error condition\n\t// of an entity being included twice.\n\tqsort( entityNumbers.snapshotEntities, entityNumbers.numSnapshotEntities, \n\t\tsizeof( entityNumbers.snapshotEntities[0] ), SV_QsortEntityNumbers );\n\n\t// now that all viewpoint's areabits have been OR'd together, invert\n\t// all of them to make it a mask vector, which is what the renderer wants\n\tfor ( i = 0 ; i < MAX_MAP_AREA_BYTES/4 ; i++ ) {\n\t\t((int *)frame->areabits)[i] = ((int *)frame->areabits)[i] ^ -1;\n\t}\n\n\t// copy the entity states out\n\tframe->num_entities = 0;\n\tframe->first_entity = svs.nextSnapshotEntities;\n\tfor ( i = 0 ; i < entityNumbers.numSnapshotEntities ; i++ ) {\n\t\tent = SV_GentityNum(entityNumbers.snapshotEntities[i]);\n\t\tstate = &svs.snapshotEntities[svs.nextSnapshotEntities % svs.numSnapshotEntities];\n\t\t*state = ent->s;\n\t\tsvs.nextSnapshotEntities++;\n\t\t// this should never hit, map should always be restarted first in SV_Frame\n\t\tif ( svs.nextSnapshotEntities >= 0x7FFFFFFE ) {\n\t\t\tCom_Error(ERR_FATAL, \"svs.nextSnapshotEntities wrapped\");\n\t\t}\n\t\tframe->num_entities++;\n\t}\n}\n\n\n/*\n====================\nSV_RateMsec\n\nReturn the number of msec a given size message is supposed\nto take to clear, based on the current rate\n====================\n*/\n#define\tHEADER_RATE_BYTES\t48\t\t// include our header, IP header, and some overhead\nstatic int SV_RateMsec( client_t *client, int messageSize ) {\n\tint\t\trate;\n\tint\t\trateMsec;\n\n\t// individual messages will never be larger than fragment size\n\tif ( messageSize > 1500 ) {\n\t\tmessageSize = 1500;\n\t}\n\trate = client->rate;\n\tif ( sv_maxRate->integer ) {\n\t\tif ( sv_maxRate->integer < 1000 ) {\n\t\t\tCvar_Set( \"sv_MaxRate\", \"1000\" );\n\t\t}\n\t\tif ( sv_maxRate->integer < rate ) {\n\t\t\trate = sv_maxRate->integer;\n\t\t}\n\t}\n\trateMsec = ( messageSize + HEADER_RATE_BYTES ) * 1000 / rate;\n\n\treturn rateMsec;\n}\n\n/*\n=======================\nSV_SendMessageToClient\n\nCalled by SV_SendClientSnapshot and SV_SendClientGameState\n=======================\n*/\nvoid SV_SendMessageToClient( msg_t *msg, client_t *client ) {\n\tint\t\t\trateMsec;\n\n\t// record information about the message\n\tclient->frames[client->netchan.outgoingSequence & PACKET_MASK].messageSize = msg->cursize;\n\tclient->frames[client->netchan.outgoingSequence & PACKET_MASK].messageSent = svs.time;\n\tclient->frames[client->netchan.outgoingSequence & PACKET_MASK].messageAcked = -1;\n\n\t// send the datagram\n\tSV_Netchan_Transmit( client, msg );\t//msg->cursize, msg->data );\n\n\t// set nextSnapshotTime based on rate and requested number of updates\n\n\t// local clients get snapshots every frame\n\t// TTimo - https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=491\n\t// added sv_lanForceRate check\n\tif ( client->netchan.remoteAddress.type == NA_LOOPBACK || (sv_lanForceRate->integer && Sys_IsLANAddress (client->netchan.remoteAddress)) ) {\n\t\tclient->nextSnapshotTime = svs.time - 1;\n\t\treturn;\n\t}\n\t\n\t// normal rate / snapshotMsec calculation\n\trateMsec = SV_RateMsec( client, msg->cursize );\n\n\tif ( rateMsec < client->snapshotMsec ) {\n\t\t// never send more packets than this, no matter what the rate is at\n\t\trateMsec = client->snapshotMsec;\n\t\tclient->rateDelayed = qfalse;\n\t} else {\n\t\tclient->rateDelayed = qtrue;\n\t}\n\n\tclient->nextSnapshotTime = svs.time + rateMsec;\n\n\t// don't pile up empty snapshots while connecting\n\tif ( client->state != CS_ACTIVE ) {\n\t\t// a gigantic connection message may have already put the nextSnapshotTime\n\t\t// more than a second away, so don't shorten it\n\t\t// do shorten if client is downloading\n\t\tif ( !*client->downloadName && client->nextSnapshotTime < svs.time + 1000 ) {\n\t\t\tclient->nextSnapshotTime = svs.time + 1000;\n\t\t}\n\t}\n}\n\n\n/*\n=======================\nSV_SendClientSnapshot\n\nAlso called by SV_FinalMessage\n\n=======================\n*/\nvoid SV_SendClientSnapshot( client_t *client ) {\n\tbyte\t\tmsg_buf[MAX_MSGLEN];\n\tmsg_t\t\tmsg;\n\n\t// build the snapshot\n\tSV_BuildClientSnapshot( client );\n\n\t// bots need to have their snapshots build, but\n\t// the query them directly without needing to be sent\n\tif ( client->gentity && client->gentity->r.svFlags & SVF_BOT ) {\n\t\treturn;\n\t}\n\n\tMSG_Init (&msg, msg_buf, sizeof(msg_buf));\n\tmsg.allowoverflow = qtrue;\n\n\t// NOTE, MRE: all server->client messages now acknowledge\n\t// let the client know which reliable clientCommands we have received\n\tMSG_WriteLong( &msg, client->lastClientCommand );\n\n\t// (re)send any reliable server commands\n\tSV_UpdateServerCommandsToClient( client, &msg );\n\n\t// send over all the relevant entityState_t\n\t// and the playerState_t\n\tSV_WriteSnapshotToClient( client, &msg );\n\n\t// Add any download data if the client is downloading\n\tSV_WriteDownloadToClient( client, &msg );\n\n\t// check for overflow\n\tif ( msg.overflowed ) {\n\t\tCom_Printf (\"WARNING: msg overflowed for %s\\n\", client->name);\n\t\tMSG_Clear (&msg);\n\t}\n\n\tSV_SendMessageToClient( &msg, client );\n}\n\n\n/*\n=======================\nSV_SendClientMessages\n=======================\n*/\nvoid SV_SendClientMessages( void ) {\n\tint\t\t\ti;\n\tclient_t\t*c;\n\n\t// send a message to each connected client\n\tfor (i=0, c = svs.clients ; i < sv_maxclients->integer ; i++, c++) {\n\t\tif (!c->state) {\n\t\t\tcontinue;\t\t// not connected\n\t\t}\n\n\t\tif ( svs.time < c->nextSnapshotTime ) {\n\t\t\tcontinue;\t\t// not time yet\n\t\t}\n\n\t\t// send additional message fragments if the last message\n\t\t// was too large to send at once\n\t\tif ( c->netchan.unsentFragments ) {\n\t\t\tc->nextSnapshotTime = svs.time + \n\t\t\t\tSV_RateMsec( c, c->netchan.unsentLength - c->netchan.unsentFragmentStart );\n\t\t\tSV_Netchan_TransmitNextFragment( c );\n\t\t\tcontinue;\n\t\t}\n\n\t\t// generate and send a new message\n\t\tSV_SendClientSnapshot( c );\n\t}\n}\n\n"
  },
  {
    "path": "src/engine/server/sv_world.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n// world.c -- world query functions\n\n#include \"server.h\"\n\n/*\n================\nSV_ClipHandleForEntity\n\nReturns a headnode that can be used for testing or clipping to a\ngiven entity.  If the entity is a bsp model, the headnode will\nbe returned, otherwise a custom box tree will be constructed.\n================\n*/\nclipHandle_t SV_ClipHandleForEntity( const sharedEntity_t *ent ) {\n\tif ( ent->r.bmodel ) {\n\t\t// explicit hulls in the BSP model\n\t\treturn CM_InlineModel( ent->s.modelindex );\n\t}\n\tif ( ent->r.svFlags & SVF_CAPSULE ) {\n\t\t// create a temp capsule from bounding box sizes\n\t\treturn CM_TempBoxModel( ent->r.mins, ent->r.maxs, qtrue );\n\t}\n\n\t// create a temp tree from bounding box sizes\n\treturn CM_TempBoxModel( ent->r.mins, ent->r.maxs, qfalse );\n}\n\n\n\n/*\n===============================================================================\n\nENTITY CHECKING\n\nTo avoid linearly searching through lists of entities during environment testing,\nthe world is carved up with an evenly spaced, axially aligned bsp tree.  Entities\nare kept in chains either at the final leafs, or at the first node that splits\nthem, which prevents having to deal with multiple fragments of a single entity.\n\n===============================================================================\n*/\n\ntypedef struct worldSector_s {\n\tint\t\taxis;\t\t// -1 = leaf node\n\tfloat\tdist;\n\tstruct worldSector_s\t*children[2];\n\tsvEntity_t\t*entities;\n} worldSector_t;\n\n#define\tAREA_DEPTH\t4\n#define\tAREA_NODES\t64\n\nworldSector_t\tsv_worldSectors[AREA_NODES];\nint\t\t\tsv_numworldSectors;\n\n\n/*\n===============\nSV_SectorList_f\n===============\n*/\nvoid SV_SectorList_f( void ) {\n\tint\t\t\t\ti, c;\n\tworldSector_t\t*sec;\n\tsvEntity_t\t\t*ent;\n\n\tfor ( i = 0 ; i < AREA_NODES ; i++ ) {\n\t\tsec = &sv_worldSectors[i];\n\n\t\tc = 0;\n\t\tfor ( ent = sec->entities ; ent ; ent = ent->nextEntityInWorldSector ) {\n\t\t\tc++;\n\t\t}\n\t\tCom_Printf( \"sector %i: %i entities\\n\", i, c );\n\t}\n}\n\n/*\n===============\nSV_CreateworldSector\n\nBuilds a uniformly subdivided tree for the given world size\n===============\n*/\nworldSector_t *SV_CreateworldSector( int depth, vec3_t mins, vec3_t maxs ) {\n\tworldSector_t\t*anode;\n\tvec3_t\t\tsize;\n\tvec3_t\t\tmins1, maxs1, mins2, maxs2;\n\n\tanode = &sv_worldSectors[sv_numworldSectors];\n\tsv_numworldSectors++;\n\n\tif (depth == AREA_DEPTH) {\n\t\tanode->axis = -1;\n\t\tanode->children[0] = anode->children[1] = NULL;\n\t\treturn anode;\n\t}\n\t\n\tVectorSubtract (maxs, mins, size);\n\tif (size[0] > size[1]) {\n\t\tanode->axis = 0;\n\t} else {\n\t\tanode->axis = 1;\n\t}\n\n\tanode->dist = 0.5 * (maxs[anode->axis] + mins[anode->axis]);\n\tVectorCopy (mins, mins1);\t\n\tVectorCopy (mins, mins2);\t\n\tVectorCopy (maxs, maxs1);\t\n\tVectorCopy (maxs, maxs2);\t\n\t\n\tmaxs1[anode->axis] = mins2[anode->axis] = anode->dist;\n\t\n\tanode->children[0] = SV_CreateworldSector (depth+1, mins2, maxs2);\n\tanode->children[1] = SV_CreateworldSector (depth+1, mins1, maxs1);\n\n\treturn anode;\n}\n\n/*\n===============\nSV_ClearWorld\n\n===============\n*/\nvoid SV_ClearWorld( void ) {\n\tclipHandle_t\th;\n\tvec3_t\t\t\tmins, maxs;\n\n\tCom_Memset( sv_worldSectors, 0, sizeof(sv_worldSectors) );\n\tsv_numworldSectors = 0;\n\n\t// get world map bounds\n\th = CM_InlineModel( 0 );\n\tCM_ModelBounds( h, mins, maxs );\n\tSV_CreateworldSector( 0, mins, maxs );\n}\n\n\n/*\n===============\nSV_UnlinkEntity\n\n===============\n*/\nvoid SV_UnlinkEntity( sharedEntity_t *gEnt ) {\n\tsvEntity_t\t\t*ent;\n\tsvEntity_t\t\t*scan;\n\tworldSector_t\t*ws;\n\n\tent = SV_SvEntityForGentity( gEnt );\n\n\tgEnt->r.linked = qfalse;\n\n\tws = ent->worldSector;\n\tif ( !ws ) {\n\t\treturn;\t\t// not linked in anywhere\n\t}\n\tent->worldSector = NULL;\n\n\tif ( ws->entities == ent ) {\n\t\tws->entities = ent->nextEntityInWorldSector;\n\t\treturn;\n\t}\n\n\tfor ( scan = ws->entities ; scan ; scan = scan->nextEntityInWorldSector ) {\n\t\tif ( scan->nextEntityInWorldSector == ent ) {\n\t\t\tscan->nextEntityInWorldSector = ent->nextEntityInWorldSector;\n\t\t\treturn;\n\t\t}\n\t}\n\n\tCom_Printf( \"WARNING: SV_UnlinkEntity: not found in worldSector\\n\" );\n}\n\n\n/*\n===============\nSV_LinkEntity\n\n===============\n*/\n#define MAX_TOTAL_ENT_LEAFS\t\t128\nvoid SV_LinkEntity( sharedEntity_t *gEnt ) {\n\tworldSector_t\t*node;\n\tint\t\t\tleafs[MAX_TOTAL_ENT_LEAFS];\n\tint\t\t\tcluster;\n\tint\t\t\tnum_leafs;\n\tint\t\t\ti, j, k;\n\tint\t\t\tarea;\n\tint\t\t\tlastLeaf;\n\tfloat\t\t*origin, *angles;\n\tsvEntity_t\t*ent;\n\n\tent = SV_SvEntityForGentity( gEnt );\n\n\tif ( ent->worldSector ) {\n\t\tSV_UnlinkEntity( gEnt );\t// unlink from old position\n\t}\n\n\t// encode the size into the entityState_t for client prediction\n\tif ( gEnt->r.bmodel ) {\n\t\tgEnt->s.solid = SOLID_BMODEL;\t\t// a solid_box will never create this value\n\t} else if ( gEnt->r.contents & ( CONTENTS_SOLID | CONTENTS_BODY ) ) {\n\t\t// assume that x/y are equal and symetric\n\t\ti = gEnt->r.maxs[0];\n\t\tif (i<1)\n\t\t\ti = 1;\n\t\tif (i>255)\n\t\t\ti = 255;\n\n\t\t// z is not symetric\n\t\tj = (-gEnt->r.mins[2]);\n\t\tif (j<1)\n\t\t\tj = 1;\n\t\tif (j>255)\n\t\t\tj = 255;\n\n\t\t// and z maxs can be negative...\n\t\tk = (gEnt->r.maxs[2]+32);\n\t\tif (k<1)\n\t\t\tk = 1;\n\t\tif (k>255)\n\t\t\tk = 255;\n\n\t\tgEnt->s.solid = (k<<16) | (j<<8) | i;\n\t} else {\n\t\tgEnt->s.solid = 0;\n\t}\n\n\t// get the position\n\torigin = gEnt->r.currentOrigin;\n\tangles = gEnt->r.currentAngles;\n\n\t// set the abs box\n\tif ( gEnt->r.bmodel && (angles[0] || angles[1] || angles[2]) ) {\n\t\t// expand for rotation\n\t\tfloat\t\tmax;\n\t\tint\t\t\ti;\n\n\t\tmax = RadiusFromBounds( gEnt->r.mins, gEnt->r.maxs );\n\t\tfor (i=0 ; i<3 ; i++) {\n\t\t\tgEnt->r.absmin[i] = origin[i] - max;\n\t\t\tgEnt->r.absmax[i] = origin[i] + max;\n\t\t}\n\t} else {\n\t\t// normal\n\t\tVectorAdd (origin, gEnt->r.mins, gEnt->r.absmin);\t\n\t\tVectorAdd (origin, gEnt->r.maxs, gEnt->r.absmax);\n\t}\n\n\t// because movement is clipped an epsilon away from an actual edge,\n\t// we must fully check even when bounding boxes don't quite touch\n\tgEnt->r.absmin[0] -= 1;\n\tgEnt->r.absmin[1] -= 1;\n\tgEnt->r.absmin[2] -= 1;\n\tgEnt->r.absmax[0] += 1;\n\tgEnt->r.absmax[1] += 1;\n\tgEnt->r.absmax[2] += 1;\n\n\t// link to PVS leafs\n\tent->numClusters = 0;\n\tent->lastCluster = 0;\n\tent->areanum = -1;\n\tent->areanum2 = -1;\n\n\t//get all leafs, including solids\n\tnum_leafs = CM_BoxLeafnums( gEnt->r.absmin, gEnt->r.absmax,\n\t\tleafs, MAX_TOTAL_ENT_LEAFS, &lastLeaf );\n\n\t// if none of the leafs were inside the map, the\n\t// entity is outside the world and can be considered unlinked\n\tif ( !num_leafs ) {\n\t\treturn;\n\t}\n\n\t// set areas, even from clusters that don't fit in the entity array\n\tfor (i=0 ; i<num_leafs ; i++) {\n\t\tarea = CM_LeafArea (leafs[i]);\n\t\tif (area != -1) {\n\t\t\t// doors may legally straggle two areas,\n\t\t\t// but nothing should evern need more than that\n\t\t\tif (ent->areanum != -1 && ent->areanum != area) {\n\t\t\t\tif (ent->areanum2 != -1 && ent->areanum2 != area && sv.state == SS_LOADING) {\n\t\t\t\t\tCom_DPrintf (\"Object %i touching 3 areas at %f %f %f\\n\",\n\t\t\t\t\tgEnt->s.number,\n\t\t\t\t\tgEnt->r.absmin[0], gEnt->r.absmin[1], gEnt->r.absmin[2]);\n\t\t\t\t}\n\t\t\t\tent->areanum2 = area;\n\t\t\t} else {\n\t\t\t\tent->areanum = area;\n\t\t\t}\n\t\t}\n\t}\n\n\t// store as many explicit clusters as we can\n\tent->numClusters = 0;\n\tfor (i=0 ; i < num_leafs ; i++) {\n\t\tcluster = CM_LeafCluster( leafs[i] );\n\t\tif ( cluster != -1 ) {\n\t\t\tent->clusternums[ent->numClusters++] = cluster;\n\t\t\tif ( ent->numClusters == MAX_ENT_CLUSTERS ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t// store off a last cluster if we need to\n\tif ( i != num_leafs ) {\n\t\tent->lastCluster = CM_LeafCluster( lastLeaf );\n\t}\n\n\tgEnt->r.linkcount++;\n\n\t// find the first world sector node that the ent's box crosses\n\tnode = sv_worldSectors;\n\twhile (1)\n\t{\n\t\tif (node->axis == -1)\n\t\t\tbreak;\n\t\tif ( gEnt->r.absmin[node->axis] > node->dist)\n\t\t\tnode = node->children[0];\n\t\telse if ( gEnt->r.absmax[node->axis] < node->dist)\n\t\t\tnode = node->children[1];\n\t\telse\n\t\t\tbreak;\t\t// crosses the node\n\t}\n\t\n\t// link it in\n\tent->worldSector = node;\n\tent->nextEntityInWorldSector = node->entities;\n\tnode->entities = ent;\n\n\tgEnt->r.linked = qtrue;\n}\n\n/*\n============================================================================\n\nAREA QUERY\n\nFills in a list of all entities who's absmin / absmax intersects the given\nbounds.  This does NOT mean that they actually touch in the case of bmodels.\n============================================================================\n*/\n\ntypedef struct {\n\tconst float\t*mins;\n\tconst float\t*maxs;\n\tint\t\t\t*list;\n\tint\t\t\tcount, maxcount;\n} areaParms_t;\n\n\n/*\n====================\nSV_AreaEntities_r\n\n====================\n*/\nvoid SV_AreaEntities_r( worldSector_t *node, areaParms_t *ap ) {\n\tsvEntity_t\t*check, *next;\n\tsharedEntity_t *gcheck;\n\tint\t\t\tcount;\n\n\tcount = 0;\n\n\tfor ( check = node->entities  ; check ; check = next ) {\n\t\tnext = check->nextEntityInWorldSector;\n\n\t\tgcheck = SV_GEntityForSvEntity( check );\n\n\t\tif ( gcheck->r.absmin[0] > ap->maxs[0]\n\t\t|| gcheck->r.absmin[1] > ap->maxs[1]\n\t\t|| gcheck->r.absmin[2] > ap->maxs[2]\n\t\t|| gcheck->r.absmax[0] < ap->mins[0]\n\t\t|| gcheck->r.absmax[1] < ap->mins[1]\n\t\t|| gcheck->r.absmax[2] < ap->mins[2]) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif ( ap->count == ap->maxcount ) {\n\t\t\tCom_Printf (\"SV_AreaEntities: MAXCOUNT\\n\");\n\t\t\treturn;\n\t\t}\n\n\t\tap->list[ap->count] = check - sv.svEntities;\n\t\tap->count++;\n\t}\n\t\n\tif (node->axis == -1) {\n\t\treturn;\t\t// terminal node\n\t}\n\n\t// recurse down both sides\n\tif ( ap->maxs[node->axis] > node->dist ) {\n\t\tSV_AreaEntities_r ( node->children[0], ap );\n\t}\n\tif ( ap->mins[node->axis] < node->dist ) {\n\t\tSV_AreaEntities_r ( node->children[1], ap );\n\t}\n}\n\n/*\n================\nSV_AreaEntities\n================\n*/\nint SV_AreaEntities( const vec3_t mins, const vec3_t maxs, int *entityList, int maxcount ) {\n\tareaParms_t\t\tap;\n\n\tap.mins = mins;\n\tap.maxs = maxs;\n\tap.list = entityList;\n\tap.count = 0;\n\tap.maxcount = maxcount;\n\n\tSV_AreaEntities_r( sv_worldSectors, &ap );\n\n\treturn ap.count;\n}\n\n\n\n//===========================================================================\n\n\ntypedef struct {\n\tvec3_t\t\tboxmins, boxmaxs;// enclose the test object along entire move\n\tconst float\t*mins;\n\tconst float *maxs;\t// size of the moving object\n\tconst float\t*start;\n\tvec3_t\t\tend;\n\ttrace_t\t\ttrace;\n\tint\t\t\tpassEntityNum;\n\tint\t\t\tcontentmask;\n\tint\t\t\tcapsule;\n} moveclip_t;\n\n\n/*\n====================\nSV_ClipToEntity\n\n====================\n*/\nvoid SV_ClipToEntity( trace_t *trace, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int entityNum, int contentmask, int capsule ) {\n\tsharedEntity_t\t*touch;\n\tclipHandle_t\tclipHandle;\n\tfloat\t\t\t*origin, *angles;\n\n\ttouch = SV_GentityNum( entityNum );\n\n\tCom_Memset(trace, 0, sizeof(trace_t));\n\n\t// if it doesn't have any brushes of a type we\n\t// are looking for, ignore it\n\tif ( ! ( contentmask & touch->r.contents ) ) {\n\t\ttrace->fraction = 1.0;\n\t\treturn;\n\t}\n\n\t// might intersect, so do an exact clip\n\tclipHandle = SV_ClipHandleForEntity (touch);\n\n\torigin = touch->r.currentOrigin;\n\tangles = touch->r.currentAngles;\n\n\tif ( !touch->r.bmodel ) {\n\t\tangles = vec3_origin;\t// boxes don't rotate\n\t}\n\n\tCM_TransformedBoxTrace ( trace, (float *)start, (float *)end,\n\t\t(float *)mins, (float *)maxs, clipHandle,  contentmask,\n\t\torigin, angles, capsule);\n\n\tif ( trace->fraction < 1 ) {\n\t\ttrace->entityNum = touch->s.number;\n\t}\n}\n\n\n/*\n====================\nSV_ClipMoveToEntities\n\n====================\n*/\nvoid SV_ClipMoveToEntities( moveclip_t *clip ) {\n\tint\t\t\ti, num;\n\tint\t\t\ttouchlist[MAX_GENTITIES];\n\tsharedEntity_t *touch;\n\tint\t\t\tpassOwnerNum;\n\ttrace_t\t\ttrace;\n\tclipHandle_t\tclipHandle;\n\tfloat\t\t*origin, *angles;\n\n\tnum = SV_AreaEntities( clip->boxmins, clip->boxmaxs, touchlist, MAX_GENTITIES);\n\n\tif ( clip->passEntityNum != ENTITYNUM_NONE ) {\n\t\tpassOwnerNum = ( SV_GentityNum( clip->passEntityNum ) )->r.ownerNum;\n\t\tif ( passOwnerNum == ENTITYNUM_NONE ) {\n\t\t\tpassOwnerNum = -1;\n\t\t}\n\t} else {\n\t\tpassOwnerNum = -1;\n\t}\n\n\tfor ( i=0 ; i<num ; i++ ) {\n\t\tif ( clip->trace.allsolid ) {\n\t\t\treturn;\n\t\t}\n\t\ttouch = SV_GentityNum( touchlist[i] );\n\n\t\t// see if we should ignore this entity\n\t\tif ( clip->passEntityNum != ENTITYNUM_NONE ) {\n\t\t\tif ( touchlist[i] == clip->passEntityNum ) {\n\t\t\t\tcontinue;\t// don't clip against the pass entity\n\t\t\t}\n\t\t\tif ( touch->r.ownerNum == clip->passEntityNum ) {\n\t\t\t\tcontinue;\t// don't clip against own missiles\n\t\t\t}\n\t\t\tif ( touch->r.ownerNum == passOwnerNum ) {\n\t\t\t\tcontinue;\t// don't clip against other missiles from our owner\n\t\t\t}\n\t\t}\n\n\t\t// if it doesn't have any brushes of a type we\n\t\t// are looking for, ignore it\n\t\tif ( ! ( clip->contentmask & touch->r.contents ) ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// might intersect, so do an exact clip\n\t\tclipHandle = SV_ClipHandleForEntity (touch);\n\n\t\torigin = touch->r.currentOrigin;\n\t\tangles = touch->r.currentAngles;\n\n\n\t\tif ( !touch->r.bmodel ) {\n\t\t\tangles = vec3_origin;\t// boxes don't rotate\n\t\t}\n\n\t\tCM_TransformedBoxTrace ( &trace, (float *)clip->start, (float *)clip->end,\n\t\t\t(float *)clip->mins, (float *)clip->maxs, clipHandle,  clip->contentmask,\n\t\t\torigin, angles, clip->capsule);\n\n\t\tif ( trace.allsolid ) {\n\t\t\tclip->trace.allsolid = qtrue;\n\t\t\ttrace.entityNum = touch->s.number;\n\t\t} else if ( trace.startsolid ) {\n\t\t\tclip->trace.startsolid = qtrue;\n\t\t\ttrace.entityNum = touch->s.number;\n\t\t}\n\n\t\tif ( trace.fraction < clip->trace.fraction ) {\n\t\t\tqboolean\toldStart;\n\n\t\t\t// make sure we keep a startsolid from a previous trace\n\t\t\toldStart = clip->trace.startsolid;\n\n\t\t\ttrace.entityNum = touch->s.number;\n\t\t\tclip->trace = trace;\n\n\t\t\t//clip->trace.startsolid |= oldStart;\n\t\t\tif (oldStart == qtrue) {\n\t\t\t\tclip->trace.startsolid = qtrue;\n\t\t\t}\n\t\t\t\n\t\t}\n\t}\n}\n\n\n/*\n==================\nSV_Trace\n\nMoves the given mins/maxs volume through the world from start to end.\npassEntityNum and entities owned by passEntityNum are explicitly not checked.\n==================\n*/\nvoid SV_Trace( trace_t *results, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, int passEntityNum, int contentmask, int capsule ) {\n\tmoveclip_t\tclip;\n\tint\t\t\ti;\n\n\tif ( !mins ) {\n\t\tmins = vec3_origin;\n\t}\n\tif ( !maxs ) {\n\t\tmaxs = vec3_origin;\n\t}\n\n\tCom_Memset ( &clip, 0, sizeof ( moveclip_t ) );\n\n\t// clip to world\n\tCM_BoxTrace( &clip.trace, start, end, mins, maxs, 0, contentmask, capsule );\n\tclip.trace.entityNum = clip.trace.fraction != 1.0 ? ENTITYNUM_WORLD : ENTITYNUM_NONE;\n\tif ( clip.trace.fraction == 0 ) {\n\t\t*results = clip.trace;\n\t\treturn;\t\t// blocked immediately by the world\n\t}\n\n\tclip.contentmask = contentmask;\n\tclip.start = start;\n//\tVectorCopy( clip.trace.endpos, clip.end );\n\tVectorCopy( end, clip.end );\n\tclip.mins = mins;\n\tclip.maxs = maxs;\n\tclip.passEntityNum = passEntityNum;\n\tclip.capsule = capsule;\n\n\t// create the bounding box of the entire move\n\t// we can limit it to the part of the move not\n\t// already clipped off by the world, which can be\n\t// a significant savings for line of sight and shot traces\n\tfor ( i=0 ; i<3 ; i++ ) {\n\t\tif ( end[i] > start[i] ) {\n\t\t\tclip.boxmins[i] = clip.start[i] + clip.mins[i] - 1;\n\t\t\tclip.boxmaxs[i] = clip.end[i] + clip.maxs[i] + 1;\n\t\t} else {\n\t\t\tclip.boxmins[i] = clip.end[i] + clip.mins[i] - 1;\n\t\t\tclip.boxmaxs[i] = clip.start[i] + clip.maxs[i] + 1;\n\t\t}\n\t}\n\n\t// clip to other solid entities\n\tSV_ClipMoveToEntities ( &clip );\n\n\t*results = clip.trace;\n}\n\n\n\n/*\n=============\nSV_PointContents\n=============\n*/\nint SV_PointContents( const vec3_t p, int passEntityNum ) {\n\tint\t\t\ttouch[MAX_GENTITIES];\n\tsharedEntity_t *hit;\n\tint\t\t\ti, num;\n\tint\t\t\tcontents, c2;\n\tclipHandle_t\tclipHandle;\n\tfloat\t\t*angles;\n\n\t// get base contents from world\n\tcontents = CM_PointContents( p, 0 );\n\n\t// or in contents from all the other entities\n\tnum = SV_AreaEntities( p, p, touch, MAX_GENTITIES );\n\n\tfor ( i=0 ; i<num ; i++ ) {\n\t\tif ( touch[i] == passEntityNum ) {\n\t\t\tcontinue;\n\t\t}\n\t\thit = SV_GentityNum( touch[i] );\n\t\t// might intersect, so do an exact clip\n\t\tclipHandle = SV_ClipHandleForEntity( hit );\n\t\tangles = hit->s.angles;\n\t\tif ( !hit->r.bmodel ) {\n\t\t\tangles = vec3_origin;\t// boxes don't rotate\n\t\t}\n\n\t\tc2 = CM_TransformedPointContents (p, clipHandle, hit->s.origin, hit->s.angles);\n\n\t\tcontents |= c2;\n\t}\n\n\treturn contents;\n}\n\n\n"
  },
  {
    "path": "src/game/ai_chat.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n\n/*****************************************************************************\n * name:\t\tai_chat.c\n *\n * desc:\t\tQuake3 bot AI\n *\n * $Archive: /MissionPack/code/game/ai_chat.c $\n *\n *****************************************************************************/\n\n#include \"g_local.h\"\n#include \"botlib.h\"\n#include \"be_aas.h\"\n#include \"be_ea.h\"\n#include \"be_ai_char.h\"\n#include \"be_ai_chat.h\"\n#include \"be_ai_gen.h\"\n#include \"be_ai_goal.h\"\n#include \"be_ai_move.h\"\n#include \"be_ai_weap.h\"\n//\n#include \"ai_main.h\"\n#include \"ai_dmq3.h\"\n#include \"ai_chat.h\"\n#include \"ai_cmd.h\"\n#include \"ai_dmnet.h\"\n//\n#include \"chars.h\"\t\t\t\t//characteristics\n#include \"inv.h\"\t\t\t\t//indexes into the inventory\n#include \"syn.h\"\t\t\t\t//synonyms\n#include \"match.h\"\t\t\t\t//string matching types and vars\n\n#define TIME_BETWEENCHATTING\t25\n\n\n/*\n==================\nBotNumActivePlayers\n==================\n*/\nint BotNumActivePlayers(void) {\n\tint i, num;\n\tchar buf[MAX_INFO_STRING];\n\tstatic int maxclients;\n\n\tif (!maxclients)\n\t\tmaxclients = trap_Cvar_VariableIntegerValue(\"sv_maxclients\");\n\n\tnum = 0;\n\tfor (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {\n\t\ttrap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));\n\t\t//if no config string or no name\n\t\tif (!strlen(buf) || !strlen(Info_ValueForKey(buf, \"n\"))) continue;\n\t\t//skip spectators\n\t\tif (atoi(Info_ValueForKey(buf, \"t\")) == TEAM_SPECTATOR) continue;\n\t\t//\n\t\tnum++;\n\t}\n\treturn num;\n}\n\n/*\n==================\nBotIsFirstInRankings\n==================\n*/\nint BotIsFirstInRankings(bot_state_t *bs) {\n\tint i, score;\n\tchar buf[MAX_INFO_STRING];\n\tstatic int maxclients;\n\tplayerState_t ps;\n\n\tif (!maxclients)\n\t\tmaxclients = trap_Cvar_VariableIntegerValue(\"sv_maxclients\");\n\n\tscore = bs->cur_ps.persistant[PERS_SCORE];\n\tfor (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {\n\t\ttrap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));\n\t\t//if no config string or no name\n\t\tif (!strlen(buf) || !strlen(Info_ValueForKey(buf, \"n\"))) continue;\n\t\t//skip spectators\n\t\tif (atoi(Info_ValueForKey(buf, \"t\")) == TEAM_SPECTATOR) continue;\n\t\t//\n\t\tBotAI_GetClientState(i, &ps);\n\t\tif (score < ps.persistant[PERS_SCORE]) return qfalse;\n\t}\n\treturn qtrue;\n}\n\n/*\n==================\nBotIsLastInRankings\n==================\n*/\nint BotIsLastInRankings(bot_state_t *bs) {\n\tint i, score;\n\tchar buf[MAX_INFO_STRING];\n\tstatic int maxclients;\n\tplayerState_t ps;\n\n\tif (!maxclients)\n\t\tmaxclients = trap_Cvar_VariableIntegerValue(\"sv_maxclients\");\n\n\tscore = bs->cur_ps.persistant[PERS_SCORE];\n\tfor (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {\n\t\ttrap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));\n\t\t//if no config string or no name\n\t\tif (!strlen(buf) || !strlen(Info_ValueForKey(buf, \"n\"))) continue;\n\t\t//skip spectators\n\t\tif (atoi(Info_ValueForKey(buf, \"t\")) == TEAM_SPECTATOR) continue;\n\t\t//\n\t\tBotAI_GetClientState(i, &ps);\n\t\tif (score > ps.persistant[PERS_SCORE]) return qfalse;\n\t}\n\treturn qtrue;\n}\n\n/*\n==================\nBotFirstClientInRankings\n==================\n*/\nchar *BotFirstClientInRankings(void) {\n\tint i, bestscore, bestclient;\n\tchar buf[MAX_INFO_STRING];\n\tstatic char name[32];\n\tstatic int maxclients;\n\tplayerState_t ps;\n\n\tif (!maxclients)\n\t\tmaxclients = trap_Cvar_VariableIntegerValue(\"sv_maxclients\");\n\n\tbestscore = -999999;\n\tbestclient = 0;\n\tfor (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {\n\t\ttrap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));\n\t\t//if no config string or no name\n\t\tif (!strlen(buf) || !strlen(Info_ValueForKey(buf, \"n\"))) continue;\n\t\t//skip spectators\n\t\tif (atoi(Info_ValueForKey(buf, \"t\")) == TEAM_SPECTATOR) continue;\n\t\t//\n\t\tBotAI_GetClientState(i, &ps);\n\t\tif (ps.persistant[PERS_SCORE] > bestscore) {\n\t\t\tbestscore = ps.persistant[PERS_SCORE];\n\t\t\tbestclient = i;\n\t\t}\n\t}\n\tEasyClientName(bestclient, name, 32);\n\treturn name;\n}\n\n/*\n==================\nBotLastClientInRankings\n==================\n*/\nchar *BotLastClientInRankings(void) {\n\tint i, worstscore, bestclient;\n\tchar buf[MAX_INFO_STRING];\n\tstatic char name[32];\n\tstatic int maxclients;\n\tplayerState_t ps;\n\n\tif (!maxclients)\n\t\tmaxclients = trap_Cvar_VariableIntegerValue(\"sv_maxclients\");\n\n\tworstscore = 999999;\n\tbestclient = 0;\n\tfor (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {\n\t\ttrap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));\n\t\t//if no config string or no name\n\t\tif (!strlen(buf) || !strlen(Info_ValueForKey(buf, \"n\"))) continue;\n\t\t//skip spectators\n\t\tif (atoi(Info_ValueForKey(buf, \"t\")) == TEAM_SPECTATOR) continue;\n\t\t//\n\t\tBotAI_GetClientState(i, &ps);\n\t\tif (ps.persistant[PERS_SCORE] < worstscore) {\n\t\t\tworstscore = ps.persistant[PERS_SCORE];\n\t\t\tbestclient = i;\n\t\t}\n\t}\n\tEasyClientName(bestclient, name, 32);\n\treturn name;\n}\n\n/*\n==================\nBotRandomOpponentName\n==================\n*/\nchar *BotRandomOpponentName(bot_state_t *bs) {\n\tint i, count;\n\tchar buf[MAX_INFO_STRING];\n\tint opponents[MAX_CLIENTS], numopponents;\n\tstatic int maxclients;\n\tstatic char name[32];\n\n\tif (!maxclients)\n\t\tmaxclients = trap_Cvar_VariableIntegerValue(\"sv_maxclients\");\n\n\tnumopponents = 0;\n\topponents[0] = 0;\n\tfor (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {\n\t\tif (i == bs->client) continue;\n\t\t//\n\t\ttrap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));\n\t\t//if no config string or no name\n\t\tif (!strlen(buf) || !strlen(Info_ValueForKey(buf, \"n\"))) continue;\n\t\t//skip spectators\n\t\tif (atoi(Info_ValueForKey(buf, \"t\")) == TEAM_SPECTATOR) continue;\n\t\t//skip team mates\n\t\tif (BotSameTeam(bs, i)) continue;\n\t\t//\n\t\topponents[numopponents] = i;\n\t\tnumopponents++;\n\t}\n\tcount = random() * numopponents;\n\tfor (i = 0; i < numopponents; i++) {\n\t\tcount--;\n\t\tif (count <= 0) {\n\t\t\tEasyClientName(opponents[i], name, sizeof(name));\n\t\t\treturn name;\n\t\t}\n\t}\n\tEasyClientName(opponents[0], name, sizeof(name));\n\treturn name;\n}\n\n/*\n==================\nBotMapTitle\n==================\n*/\n\nchar *BotMapTitle(void) {\n\tchar info[1024];\n\tstatic char mapname[128];\n\n\ttrap_GetServerinfo(info, sizeof(info));\n\n\tstrncpy(mapname, Info_ValueForKey( info, \"mapname\" ), sizeof(mapname)-1);\n\tmapname[sizeof(mapname)-1] = '\\0';\n\n\treturn mapname;\n}\n\n\n/*\n==================\nBotWeaponNameForMeansOfDeath\n==================\n*/\n\nchar *BotWeaponNameForMeansOfDeath(int mod) {\n\tswitch(mod) {\n\t\tcase MOD_SHOTGUN: return \"Shotgun\";\n\t\tcase MOD_GAUNTLET: return \"Gauntlet\";\n\t\tcase MOD_MACHINEGUN: return \"Machinegun\";\n\t\tcase MOD_GRENADE:\n\t\tcase MOD_GRENADE_SPLASH: return \"Grenade Launcher\";\n\t\tcase MOD_ROCKET:\n\t\tcase MOD_ROCKET_SPLASH: return \"Rocket Launcher\";\n\t\tcase MOD_PLASMA:\n\t\tcase MOD_PLASMA_SPLASH: return \"Plasmagun\";\n\t\tcase MOD_RAILGUN: return \"Railgun\";\n\t\tcase MOD_LIGHTNING: return \"Lightning Gun\";\n\t\tcase MOD_BFG:\n\t\tcase MOD_BFG_SPLASH: return \"BFG10K\";\n\t\tcase MOD_GRAPPLE: return \"Grapple\";\n\t\tdefault: return \"[unknown weapon]\";\n\t}\n}\n\n/*\n==================\nBotRandomWeaponName\n==================\n*/\nchar *BotRandomWeaponName(void) {\n\tint rnd = random() * 8.9;\n\n\tswitch(rnd) {\n\t\tcase 0: return \"Gauntlet\";\n\t\tcase 1: return \"Shotgun\";\n\t\tcase 2: return \"Machinegun\";\n\t\tcase 3: return \"Grenade Launcher\";\n\t\tcase 4: return \"Rocket Launcher\";\n\t\tcase 5: return \"Plasmagun\";\n\t\tcase 6: return \"Railgun\";\n\t\tcase 7: return \"Lightning Gun\";\n\t\tdefault: return \"BFG10K\";\n\t}\n}\n\n/*\n==================\nBotVisibleEnemies\n==================\n*/\nint BotVisibleEnemies(bot_state_t *bs) {\n\tfloat vis;\n\tint i;\n\taas_entityinfo_t entinfo;\n\n\tfor (i = 0; i < MAX_CLIENTS; i++) {\n\n\t\tif (i == bs->client) continue;\n\t\t//\n\t\tBotEntityInfo(i, &entinfo);\n\t\t//\n\t\tif (!entinfo.valid) continue;\n\t\t//if the enemy isn't dead and the enemy isn't the bot self\n\t\tif (EntityIsDead(&entinfo) || entinfo.number == bs->entitynum) continue;\n\t\t//if the enemy is invisible and not shooting\n\t\tif (EntityIsInvisible(&entinfo) && !EntityIsShooting(&entinfo)) {\n\t\t\tcontinue;\n\t\t}\n\t\t//if on the same team\n\t\tif (BotSameTeam(bs, i)) continue;\n\t\t//check if the enemy is visible\n\t\tvis = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, i);\n\t\tif (vis > 0) return qtrue;\n\t}\n\treturn qfalse;\n}\n\n/*\n==================\nBotValidChatPosition\n==================\n*/\nint BotValidChatPosition(bot_state_t *bs) {\n\tvec3_t point, start, end, mins, maxs;\n\tbsp_trace_t trace;\n\n\t//if the bot is dead all positions are valid\n\tif (BotIsDead(bs)) return qtrue;\n\t//never start chatting with a powerup\n\tif (bs->inventory[INVENTORY_QUAD] ||\n\t\tbs->inventory[INVENTORY_HASTE] ||\n\t\tbs->inventory[INVENTORY_INVISIBILITY] ||\n\t\tbs->inventory[INVENTORY_REGEN] ||\n\t\tbs->inventory[INVENTORY_FLIGHT]) return qfalse;\n\t//must be on the ground\n\t//if (bs->cur_ps.groundEntityNum != ENTITYNUM_NONE) return qfalse;\n\t//do not chat if in lava or slime\n\tVectorCopy(bs->origin, point);\n\tpoint[2] -= 24;\n\tif (trap_PointContents(point,bs->entitynum) & (CONTENTS_LAVA|CONTENTS_SLIME)) return qfalse;\n\t//do not chat if under water\n\tVectorCopy(bs->origin, point);\n\tpoint[2] += 32;\n\tif (trap_PointContents(point,bs->entitynum) & MASK_WATER) return qfalse;\n\t//must be standing on the world entity\n\tVectorCopy(bs->origin, start);\n\tVectorCopy(bs->origin, end);\n\tstart[2] += 1;\n\tend[2] -= 10;\n\ttrap_AAS_PresenceTypeBoundingBox(PRESENCE_CROUCH, mins, maxs);\n\tBotAI_Trace(&trace, start, mins, maxs, end, bs->client, MASK_SOLID);\n\tif (trace.ent != ENTITYNUM_WORLD) return qfalse;\n\t//the bot is in a position where it can chat\n\treturn qtrue;\n}\n\n/*\n==================\nBotChat_EnterGame\n==================\n*/\nint BotChat_EnterGame(bot_state_t *bs) {\n\tchar name[32];\n\tfloat rnd;\n\n\tif (bot_nochat.integer) return qfalse;\n\tif (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;\n\t//don't chat in teamplay\n\tif (TeamPlayIsOn()) return qfalse;\n\t// don't chat in tournament mode\n\tif (gametype == GT_TOURNAMENT) return qfalse;\n\trnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_ENTEREXITGAME, 0, 1);\n\tif (!bot_fastchat.integer) {\n\t\tif (random() > rnd) return qfalse;\n\t}\n\tif (BotNumActivePlayers() <= 1) return qfalse;\n\tif (!BotValidChatPosition(bs)) return qfalse;\n\tBotAI_BotInitialChat(bs, \"game_enter\",\n\t\t\t\tEasyClientName(bs->client, name, 32),\t// 0\n\t\t\t\tBotRandomOpponentName(bs),\t\t\t\t// 1\n\t\t\t\t\"[invalid var]\",\t\t\t\t\t\t// 2\n\t\t\t\t\"[invalid var]\",\t\t\t\t\t\t// 3\n\t\t\t\tBotMapTitle(),\t\t\t\t\t\t\t// 4\n\t\t\t\tNULL);\n\tbs->lastchat_time = FloatTime();\n\tbs->chatto = CHAT_ALL;\n\treturn qtrue;\n}\n\n/*\n==================\nBotChat_ExitGame\n==================\n*/\nint BotChat_ExitGame(bot_state_t *bs) {\n\tchar name[32];\n\tfloat rnd;\n\n\tif (bot_nochat.integer) return qfalse;\n\tif (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;\n\t//don't chat in teamplay\n\tif (TeamPlayIsOn()) return qfalse;\n\t// don't chat in tournament mode\n\tif (gametype == GT_TOURNAMENT) return qfalse;\n\trnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_ENTEREXITGAME, 0, 1);\n\tif (!bot_fastchat.integer) {\n\t\tif (random() > rnd) return qfalse;\n\t}\n\tif (BotNumActivePlayers() <= 1) return qfalse;\n\t//\n\tBotAI_BotInitialChat(bs, \"game_exit\",\n\t\t\t\tEasyClientName(bs->client, name, 32),\t// 0\n\t\t\t\tBotRandomOpponentName(bs),\t\t\t\t// 1\n\t\t\t\t\"[invalid var]\",\t\t\t\t\t\t// 2\n\t\t\t\t\"[invalid var]\",\t\t\t\t\t\t// 3\n\t\t\t\tBotMapTitle(),\t\t\t\t\t\t\t// 4\n\t\t\t\tNULL);\n\tbs->lastchat_time = FloatTime();\n\tbs->chatto = CHAT_ALL;\n\treturn qtrue;\n}\n\n/*\n==================\nBotChat_StartLevel\n==================\n*/\nint BotChat_StartLevel(bot_state_t *bs) {\n\tchar name[32];\n\tfloat rnd;\n\n\tif (bot_nochat.integer) return qfalse;\n\tif (BotIsObserver(bs)) return qfalse;\n\tif (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;\n\t//don't chat in teamplay\n\tif (TeamPlayIsOn()) {\n\t    trap_EA_Command(bs->client, \"vtaunt\");\n\t    return qfalse;\n\t}\n\t// don't chat in tournament mode\n\tif (gametype == GT_TOURNAMENT) return qfalse;\n\trnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_STARTENDLEVEL, 0, 1);\n\tif (!bot_fastchat.integer) {\n\t\tif (random() > rnd) return qfalse;\n\t}\n\tif (BotNumActivePlayers() <= 1) return qfalse;\n\tBotAI_BotInitialChat(bs, \"level_start\",\n\t\t\t\tEasyClientName(bs->client, name, 32),\t// 0\n\t\t\t\tNULL);\n\tbs->lastchat_time = FloatTime();\n\tbs->chatto = CHAT_ALL;\n\treturn qtrue;\n}\n\n/*\n==================\nBotChat_EndLevel\n==================\n*/\nint BotChat_EndLevel(bot_state_t *bs) {\n\tchar name[32];\n\tfloat rnd;\n\n\tif (bot_nochat.integer) return qfalse;\n\tif (BotIsObserver(bs)) return qfalse;\n\tif (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;\n\t// teamplay\n\tif (TeamPlayIsOn()) \n\t{\n\t\tif (BotIsFirstInRankings(bs)) {\n\t\t\ttrap_EA_Command(bs->client, \"vtaunt\");\n\t\t}\n\t\treturn qtrue;\n\t}\n\t// don't chat in tournament mode\n\tif (gametype == GT_TOURNAMENT) return qfalse;\n\trnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_STARTENDLEVEL, 0, 1);\n\tif (!bot_fastchat.integer) {\n\t\tif (random() > rnd) return qfalse;\n\t}\n\tif (BotNumActivePlayers() <= 1) return qfalse;\n\t//\n\tif (BotIsFirstInRankings(bs)) {\n\t\tBotAI_BotInitialChat(bs, \"level_end_victory\",\n\t\t\t\tEasyClientName(bs->client, name, 32),\t// 0\n\t\t\t\tBotRandomOpponentName(bs),\t\t\t\t// 1\n\t\t\t\t\"[invalid var]\",\t\t\t\t\t\t// 2\n\t\t\t\tBotLastClientInRankings(),\t\t\t\t// 3\n\t\t\t\tBotMapTitle(),\t\t\t\t\t\t\t// 4\n\t\t\t\tNULL);\n\t}\n\telse if (BotIsLastInRankings(bs)) {\n\t\tBotAI_BotInitialChat(bs, \"level_end_lose\",\n\t\t\t\tEasyClientName(bs->client, name, 32),\t// 0\n\t\t\t\tBotRandomOpponentName(bs),\t\t\t\t// 1\n\t\t\t\tBotFirstClientInRankings(),\t\t\t\t// 2\n\t\t\t\t\"[invalid var]\",\t\t\t\t\t\t// 3\n\t\t\t\tBotMapTitle(),\t\t\t\t\t\t\t// 4\n\t\t\t\tNULL);\n\t}\n\telse {\n\t\tBotAI_BotInitialChat(bs, \"level_end\",\n\t\t\t\tEasyClientName(bs->client, name, 32),\t// 0\n\t\t\t\tBotRandomOpponentName(bs),\t\t\t\t// 1\n\t\t\t\tBotFirstClientInRankings(),\t\t\t\t// 2\n\t\t\t\tBotLastClientInRankings(),\t\t\t\t// 3\n\t\t\t\tBotMapTitle(),\t\t\t\t\t\t\t// 4\n\t\t\t\tNULL);\n\t}\n\tbs->lastchat_time = FloatTime();\n\tbs->chatto = CHAT_ALL;\n\treturn qtrue;\n}\n\n/*\n==================\nBotChat_Death\n==================\n*/\nint BotChat_Death(bot_state_t *bs) {\n\tchar name[32];\n\tfloat rnd;\n\n\tif (bot_nochat.integer) return qfalse;\n\tif (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;\n\trnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_DEATH, 0, 1);\n\t// don't chat in tournament mode\n\tif (gametype == GT_TOURNAMENT) return qfalse;\n\t//if fast chatting is off\n\tif (!bot_fastchat.integer) {\n\t\tif (random() > rnd) return qfalse;\n\t}\n\tif (BotNumActivePlayers() <= 1) return qfalse;\n\t//\n\tif (bs->lastkilledby >= 0 && bs->lastkilledby < MAX_CLIENTS)\n\t\tEasyClientName(bs->lastkilledby, name, 32);\n\telse\n\t\tstrcpy(name, \"[world]\");\n\t//\n\tif (TeamPlayIsOn() && BotSameTeam(bs, bs->lastkilledby)) {\n\t\tif (bs->lastkilledby == bs->client) return qfalse;\n\t\tBotAI_BotInitialChat(bs, \"death_teammate\", name, NULL);\n\t\tbs->chatto = CHAT_TEAM;\n\t}\n\telse\n\t{\n\t\t//teamplay\n\t\tif (TeamPlayIsOn()) {\n\t\t\ttrap_EA_Command(bs->client, \"vtaunt\");\n\t\t\treturn qtrue;\n\t\t}\n\t\t//\n\t\tif (bs->botdeathtype == MOD_WATER)\n\t\t\tBotAI_BotInitialChat(bs, \"death_drown\", BotRandomOpponentName(bs), NULL);\n\t\telse if (bs->botdeathtype == MOD_SLIME)\n\t\t\tBotAI_BotInitialChat(bs, \"death_slime\", BotRandomOpponentName(bs), NULL);\n\t\telse if (bs->botdeathtype == MOD_LAVA)\n\t\t\tBotAI_BotInitialChat(bs, \"death_lava\", BotRandomOpponentName(bs), NULL);\n\t\telse if (bs->botdeathtype == MOD_FALLING)\n\t\t\tBotAI_BotInitialChat(bs, \"death_cratered\", BotRandomOpponentName(bs), NULL);\n\t\telse if (bs->botsuicide || //all other suicides by own weapon\n\t\t\t\tbs->botdeathtype == MOD_CRUSH ||\n\t\t\t\tbs->botdeathtype == MOD_SUICIDE ||\n\t\t\t\tbs->botdeathtype == MOD_TARGET_LASER ||\n\t\t\t\tbs->botdeathtype == MOD_TRIGGER_HURT ||\n\t\t\t\tbs->botdeathtype == MOD_UNKNOWN)\n\t\t\tBotAI_BotInitialChat(bs, \"death_suicide\", BotRandomOpponentName(bs), NULL);\n\t\telse if (bs->botdeathtype == MOD_TELEFRAG)\n\t\t\tBotAI_BotInitialChat(bs, \"death_telefrag\", name, NULL);\n\t\telse {\n\t\t\tif ((bs->botdeathtype == MOD_GAUNTLET ||\n\t\t\t\tbs->botdeathtype == MOD_RAILGUN ||\n\t\t\t\tbs->botdeathtype == MOD_BFG ||\n\t\t\t\tbs->botdeathtype == MOD_BFG_SPLASH) && random() < 0.5) {\n\n\t\t\t\tif (bs->botdeathtype == MOD_GAUNTLET)\n\t\t\t\t\tBotAI_BotInitialChat(bs, \"death_gauntlet\",\n\t\t\t\t\t\t\tname,\t\t\t\t\t\t\t\t\t\t\t\t// 0\n\t\t\t\t\t\t\tBotWeaponNameForMeansOfDeath(bs->botdeathtype),\t\t// 1\n\t\t\t\t\t\t\tNULL);\n\t\t\t\telse if (bs->botdeathtype == MOD_RAILGUN)\n\t\t\t\t\tBotAI_BotInitialChat(bs, \"death_rail\",\n\t\t\t\t\t\t\tname,\t\t\t\t\t\t\t\t\t\t\t\t// 0\n\t\t\t\t\t\t\tBotWeaponNameForMeansOfDeath(bs->botdeathtype),\t\t// 1\n\t\t\t\t\t\t\tNULL);\n\t\t\t\telse\n\t\t\t\t\tBotAI_BotInitialChat(bs, \"death_bfg\",\n\t\t\t\t\t\t\tname,\t\t\t\t\t\t\t\t\t\t\t\t// 0\n\t\t\t\t\t\t\tBotWeaponNameForMeansOfDeath(bs->botdeathtype),\t\t// 1\n\t\t\t\t\t\t\tNULL);\n\t\t\t}\n\t\t\t//choose between insult and praise\n\t\t\telse if (random() < trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_INSULT, 0, 1)) {\n\t\t\t\tBotAI_BotInitialChat(bs, \"death_insult\",\n\t\t\t\t\t\t\tname,\t\t\t\t\t\t\t\t\t\t\t\t// 0\n\t\t\t\t\t\t\tBotWeaponNameForMeansOfDeath(bs->botdeathtype),\t\t// 1\n\t\t\t\t\t\t\tNULL);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tBotAI_BotInitialChat(bs, \"death_praise\",\n\t\t\t\t\t\t\tname,\t\t\t\t\t\t\t\t\t\t\t\t// 0\n\t\t\t\t\t\t\tBotWeaponNameForMeansOfDeath(bs->botdeathtype),\t\t// 1\n\t\t\t\t\t\t\tNULL);\n\t\t\t}\n\t\t}\n\t\tbs->chatto = CHAT_ALL;\n\t}\n\tbs->lastchat_time = FloatTime();\n\treturn qtrue;\n}\n\n/*\n==================\nBotChat_Kill\n==================\n*/\nint BotChat_Kill(bot_state_t *bs) {\n\tchar name[32];\n\tfloat rnd;\n\n\tif (bot_nochat.integer) return qfalse;\n\tif (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;\n\trnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_KILL, 0, 1);\n\t// don't chat in tournament mode\n\tif (gametype == GT_TOURNAMENT) return qfalse;\n\t//if fast chat is off\n\tif (!bot_fastchat.integer) {\n\t\tif (random() > rnd) return qfalse;\n\t}\n\tif (bs->lastkilledplayer == bs->client) return qfalse;\n\tif (BotNumActivePlayers() <= 1) return qfalse;\n\tif (!BotValidChatPosition(bs)) return qfalse;\n\t//\n\tif (BotVisibleEnemies(bs)) return qfalse;\n\t//\n\tEasyClientName(bs->lastkilledplayer, name, 32);\n\t//\n\tbs->chatto = CHAT_ALL;\n\tif (TeamPlayIsOn() && BotSameTeam(bs, bs->lastkilledplayer)) {\n\t\tBotAI_BotInitialChat(bs, \"kill_teammate\", name, NULL);\n\t\tbs->chatto = CHAT_TEAM;\n\t}\n\telse\n\t{\n\t\t//don't chat in teamplay\n\t\tif (TeamPlayIsOn()) {\n\t\t\ttrap_EA_Command(bs->client, \"vtaunt\");\n\t\t\treturn qfalse;\t\t\t// don't wait\n\t\t}\n\t\t//\n\t\tif (bs->enemydeathtype == MOD_GAUNTLET) {\n\t\t\tBotAI_BotInitialChat(bs, \"kill_gauntlet\", name, NULL);\n\t\t}\n\t\telse if (bs->enemydeathtype == MOD_RAILGUN) {\n\t\t\tBotAI_BotInitialChat(bs, \"kill_rail\", name, NULL);\n\t\t}\n\t\telse if (bs->enemydeathtype == MOD_TELEFRAG) {\n\t\t\tBotAI_BotInitialChat(bs, \"kill_telefrag\", name, NULL);\n\t\t}\n\t\t//choose between insult and praise\n\t\telse if (random() < trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_INSULT, 0, 1)) {\n\t\t\tBotAI_BotInitialChat(bs, \"kill_insult\", name, NULL);\n\t\t}\n\t\telse {\n\t\t\tBotAI_BotInitialChat(bs, \"kill_praise\", name, NULL);\n\t\t}\n\t}\n\tbs->lastchat_time = FloatTime();\n\treturn qtrue;\n}\n\n/*\n==================\nBotChat_EnemySuicide\n==================\n*/\nint BotChat_EnemySuicide(bot_state_t *bs) {\n\tchar name[32];\n\tfloat rnd;\n\n\tif (bot_nochat.integer) return qfalse;\n\tif (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;\n\tif (BotNumActivePlayers() <= 1) return qfalse;\n\t//\n\trnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_KILL, 0, 1);\n\t//don't chat in teamplay\n\tif (TeamPlayIsOn()) return qfalse;\n\t// don't chat in tournament mode\n\tif (gametype == GT_TOURNAMENT) return qfalse;\n\t//if fast chat is off\n\tif (!bot_fastchat.integer) {\n\t\tif (random() > rnd) return qfalse;\n\t}\n\tif (!BotValidChatPosition(bs)) return qfalse;\n\t//\n\tif (BotVisibleEnemies(bs)) return qfalse;\n\t//\n\tif (bs->enemy >= 0) EasyClientName(bs->enemy, name, 32);\n\telse strcpy(name, \"\");\n\tBotAI_BotInitialChat(bs, \"enemy_suicide\", name, NULL);\n\tbs->lastchat_time = FloatTime();\n\tbs->chatto = CHAT_ALL;\n\treturn qtrue;\n}\n\n/*\n==================\nBotChat_HitTalking\n==================\n*/\nint BotChat_HitTalking(bot_state_t *bs) {\n\tchar name[32], *weap;\n\tint lasthurt_client;\n\tfloat rnd;\n\n\tif (bot_nochat.integer) return qfalse;\n\tif (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;\n\tif (BotNumActivePlayers() <= 1) return qfalse;\n\tlasthurt_client = g_entities[bs->client].client->lasthurt_client;\n\tif (!lasthurt_client) return qfalse;\n\tif (lasthurt_client == bs->client) return qfalse;\n\t//\n\tif (lasthurt_client < 0 || lasthurt_client >= MAX_CLIENTS) return qfalse;\n\t//\n\trnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_HITTALKING, 0, 1);\n\t//don't chat in teamplay\n\tif (TeamPlayIsOn()) return qfalse;\n\t// don't chat in tournament mode\n\tif (gametype == GT_TOURNAMENT) return qfalse;\n\t//if fast chat is off\n\tif (!bot_fastchat.integer) {\n\t\tif (random() > rnd * 0.5) return qfalse;\n\t}\n\tif (!BotValidChatPosition(bs)) return qfalse;\n\t//\n\tClientName(g_entities[bs->client].client->lasthurt_client, name, sizeof(name));\n\tweap = BotWeaponNameForMeansOfDeath(g_entities[bs->client].client->lasthurt_client);\n\t//\n\tBotAI_BotInitialChat(bs, \"hit_talking\", name, weap, NULL);\n\tbs->lastchat_time = FloatTime();\n\tbs->chatto = CHAT_ALL;\n\treturn qtrue;\n}\n\n/*\n==================\nBotChat_HitNoDeath\n==================\n*/\nint BotChat_HitNoDeath(bot_state_t *bs) {\n\tchar name[32], *weap;\n\tfloat rnd;\n\tint lasthurt_client;\n\taas_entityinfo_t entinfo;\n\n\tlasthurt_client = g_entities[bs->client].client->lasthurt_client;\n\tif (!lasthurt_client) return qfalse;\n\tif (lasthurt_client == bs->client) return qfalse;\n\t//\n\tif (lasthurt_client < 0 || lasthurt_client >= MAX_CLIENTS) return qfalse;\n\t//\n\tif (bot_nochat.integer) return qfalse;\n\tif (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;\n\tif (BotNumActivePlayers() <= 1) return qfalse;\n\trnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_HITNODEATH, 0, 1);\n\t//don't chat in teamplay\n\tif (TeamPlayIsOn()) return qfalse;\n\t// don't chat in tournament mode\n\tif (gametype == GT_TOURNAMENT) return qfalse;\n\t//if fast chat is off\n\tif (!bot_fastchat.integer) {\n\t\tif (random() > rnd * 0.5) return qfalse;\n\t}\n\tif (!BotValidChatPosition(bs)) return qfalse;\n\t//\n\tif (BotVisibleEnemies(bs)) return qfalse;\n\t//\n\tBotEntityInfo(bs->enemy, &entinfo);\n\tif (EntityIsShooting(&entinfo)) return qfalse;\n\t//\n\tClientName(lasthurt_client, name, sizeof(name));\n\tweap = BotWeaponNameForMeansOfDeath(g_entities[bs->client].client->lasthurt_mod);\n\t//\n\tBotAI_BotInitialChat(bs, \"hit_nodeath\", name, weap, NULL);\n\tbs->lastchat_time = FloatTime();\n\tbs->chatto = CHAT_ALL;\n\treturn qtrue;\n}\n\n/*\n==================\nBotChat_HitNoKill\n==================\n*/\nint BotChat_HitNoKill(bot_state_t *bs) {\n\tchar name[32], *weap;\n\tfloat rnd;\n\taas_entityinfo_t entinfo;\n\n\tif (bot_nochat.integer) return qfalse;\n\tif (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;\n\tif (BotNumActivePlayers() <= 1) return qfalse;\n\trnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_HITNOKILL, 0, 1);\n\t//don't chat in teamplay\n\tif (TeamPlayIsOn()) return qfalse;\n\t// don't chat in tournament mode\n\tif (gametype == GT_TOURNAMENT) return qfalse;\n\t//if fast chat is off\n\tif (!bot_fastchat.integer) {\n\t\tif (random() > rnd * 0.5) return qfalse;\n\t}\n\tif (!BotValidChatPosition(bs)) return qfalse;\n\t//\n\tif (BotVisibleEnemies(bs)) return qfalse;\n\t//\n\tBotEntityInfo(bs->enemy, &entinfo);\n\tif (EntityIsShooting(&entinfo)) return qfalse;\n\t//\n\tClientName(bs->enemy, name, sizeof(name));\n\tweap = BotWeaponNameForMeansOfDeath(g_entities[bs->enemy].client->lasthurt_mod);\n\t//\n\tBotAI_BotInitialChat(bs, \"hit_nokill\", name, weap, NULL);\n\tbs->lastchat_time = FloatTime();\n\tbs->chatto = CHAT_ALL;\n\treturn qtrue;\n}\n\n/*\n==================\nBotChat_Random\n==================\n*/\nint BotChat_Random(bot_state_t *bs) {\n\tfloat rnd;\n\tchar name[32];\n\n\tif (bot_nochat.integer) return qfalse;\n\tif (BotIsObserver(bs)) return qfalse;\n\tif (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;\n\t// don't chat in tournament mode\n\tif (gametype == GT_TOURNAMENT) return qfalse;\n\t//don't chat when doing something important :)\n\tif (bs->ltgtype == LTG_TEAMHELP ||\n\t\tbs->ltgtype == LTG_TEAMACCOMPANY ||\n\t\tbs->ltgtype == LTG_RUSHBASE) return qfalse;\n\t//\n\trnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_RANDOM, 0, 1);\n\tif (random() > bs->thinktime * 0.1) return qfalse;\n\tif (!bot_fastchat.integer) {\n\t\tif (random() > rnd) return qfalse;\n\t\tif (random() > 0.25) return qfalse;\n\t}\n\tif (BotNumActivePlayers() <= 1) return qfalse;\n\t//\n\tif (!BotValidChatPosition(bs)) return qfalse;\n\t//\n\tif (BotVisibleEnemies(bs)) return qfalse;\n\t//\n\tif (bs->lastkilledplayer == bs->client) {\n\t\tstrcpy(name, BotRandomOpponentName(bs));\n\t}\n\telse {\n\t\tEasyClientName(bs->lastkilledplayer, name, sizeof(name));\n\t}\n\tif (TeamPlayIsOn()) {\n\t\ttrap_EA_Command(bs->client, \"vtaunt\");\n\t\treturn qfalse;\t\t\t// don't wait\n\t}\n\t//\n\tif (random() < trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_MISC, 0, 1)) {\n\t\tBotAI_BotInitialChat(bs, \"random_misc\",\n\t\t\t\t\tBotRandomOpponentName(bs),\t// 0\n\t\t\t\t\tname,\t\t\t\t\t\t// 1\n\t\t\t\t\t\"[invalid var]\",\t\t\t// 2\n\t\t\t\t\t\"[invalid var]\",\t\t\t// 3\n\t\t\t\t\tBotMapTitle(),\t\t\t\t// 4\n\t\t\t\t\tBotRandomWeaponName(),\t\t// 5\n\t\t\t\t\tNULL);\n\t}\n\telse {\n\t\tBotAI_BotInitialChat(bs, \"random_insult\",\n\t\t\t\t\tBotRandomOpponentName(bs),\t// 0\n\t\t\t\t\tname,\t\t\t\t\t\t// 1\n\t\t\t\t\t\"[invalid var]\",\t\t\t// 2\n\t\t\t\t\t\"[invalid var]\",\t\t\t// 3\n\t\t\t\t\tBotMapTitle(),\t\t\t\t// 4\n\t\t\t\t\tBotRandomWeaponName(),\t\t// 5\n\t\t\t\t\tNULL);\n\t}\n\tbs->lastchat_time = FloatTime();\n\tbs->chatto = CHAT_ALL;\n\treturn qtrue;\n}\n\n/*\n==================\nBotChatTime\n==================\n*/\nfloat BotChatTime(bot_state_t *bs) {\n\tint cpm;\n\n\tcpm = trap_Characteristic_BInteger(bs->character, CHARACTERISTIC_CHAT_CPM, 1, 4000);\n\n\treturn 2.0;\t//(float) trap_BotChatLength(bs->cs) * 30 / cpm;\n}\n\n/*\n==================\nBotChatTest\n==================\n*/\nvoid BotChatTest(bot_state_t *bs) {\n\n\tchar name[32];\n\tchar *weap;\n\tint num, i;\n\n\tnum = trap_BotNumInitialChats(bs->cs, \"game_enter\");\n\tfor (i = 0; i < num; i++)\n\t{\n\t\tBotAI_BotInitialChat(bs, \"game_enter\",\n\t\t\t\t\tEasyClientName(bs->client, name, 32),\t// 0\n\t\t\t\t\tBotRandomOpponentName(bs),\t\t\t\t// 1\n\t\t\t\t\t\"[invalid var]\",\t\t\t\t\t\t// 2\n\t\t\t\t\t\"[invalid var]\",\t\t\t\t\t\t// 3\n\t\t\t\t\tBotMapTitle(),\t\t\t\t\t\t\t// 4\n\t\t\t\t\tNULL);\n\t\ttrap_BotEnterChat(bs->cs, 0, CHAT_ALL);\n\t}\n\tnum = trap_BotNumInitialChats(bs->cs, \"game_exit\");\n\tfor (i = 0; i < num; i++)\n\t{\n\t\tBotAI_BotInitialChat(bs, \"game_exit\",\n\t\t\t\t\tEasyClientName(bs->client, name, 32),\t// 0\n\t\t\t\t\tBotRandomOpponentName(bs),\t\t\t\t// 1\n\t\t\t\t\t\"[invalid var]\",\t\t\t\t\t\t// 2\n\t\t\t\t\t\"[invalid var]\",\t\t\t\t\t\t// 3\n\t\t\t\t\tBotMapTitle(),\t\t\t\t\t\t\t// 4\n\t\t\t\t\tNULL);\n\t\ttrap_BotEnterChat(bs->cs, 0, CHAT_ALL);\n\t}\n\tnum = trap_BotNumInitialChats(bs->cs, \"level_start\");\n\tfor (i = 0; i < num; i++)\n\t{\n\t\tBotAI_BotInitialChat(bs, \"level_start\",\n\t\t\t\t\tEasyClientName(bs->client, name, 32),\t// 0\n\t\t\t\t\tNULL);\n\t\ttrap_BotEnterChat(bs->cs, 0, CHAT_ALL);\n\t}\n\tnum = trap_BotNumInitialChats(bs->cs, \"level_end_victory\");\n\tfor (i = 0; i < num; i++)\n\t{\n\t\tBotAI_BotInitialChat(bs, \"level_end_victory\",\n\t\t\t\tEasyClientName(bs->client, name, 32),\t// 0\n\t\t\t\tBotRandomOpponentName(bs),\t\t\t\t// 1\n\t\t\t\tBotFirstClientInRankings(),\t\t\t\t// 2\n\t\t\t\tBotLastClientInRankings(),\t\t\t\t// 3\n\t\t\t\tBotMapTitle(),\t\t\t\t\t\t\t// 4\n\t\t\t\tNULL);\n\t\ttrap_BotEnterChat(bs->cs, 0, CHAT_ALL);\n\t}\n\tnum = trap_BotNumInitialChats(bs->cs, \"level_end_lose\");\n\tfor (i = 0; i < num; i++)\n\t{\n\t\tBotAI_BotInitialChat(bs, \"level_end_lose\",\n\t\t\t\tEasyClientName(bs->client, name, 32),\t// 0\n\t\t\t\tBotRandomOpponentName(bs),\t\t\t\t// 1\n\t\t\t\tBotFirstClientInRankings(),\t\t\t\t// 2\n\t\t\t\tBotLastClientInRankings(),\t\t\t\t// 3\n\t\t\t\tBotMapTitle(),\t\t\t\t\t\t\t// 4\n\t\t\t\tNULL);\n\t\ttrap_BotEnterChat(bs->cs, 0, CHAT_ALL);\n\t}\n\tnum = trap_BotNumInitialChats(bs->cs, \"level_end\");\n\tfor (i = 0; i < num; i++)\n\t{\n\t\tBotAI_BotInitialChat(bs, \"level_end\",\n\t\t\t\tEasyClientName(bs->client, name, 32),\t// 0\n\t\t\t\tBotRandomOpponentName(bs),\t\t\t\t// 1\n\t\t\t\tBotFirstClientInRankings(),\t\t\t\t// 2\n\t\t\t\tBotLastClientInRankings(),\t\t\t\t// 3\n\t\t\t\tBotMapTitle(),\t\t\t\t\t\t\t// 4\n\t\t\t\tNULL);\n\t\ttrap_BotEnterChat(bs->cs, 0, CHAT_ALL);\n\t}\n\tEasyClientName(bs->lastkilledby, name, sizeof(name));\n\tnum = trap_BotNumInitialChats(bs->cs, \"death_drown\");\n\tfor (i = 0; i < num; i++)\n\t{\n\t\t//\n\t\tBotAI_BotInitialChat(bs, \"death_drown\", name, NULL);\n\t\ttrap_BotEnterChat(bs->cs, 0, CHAT_ALL);\n\t}\n\tnum = trap_BotNumInitialChats(bs->cs, \"death_slime\");\n\tfor (i = 0; i < num; i++)\n\t{\n\t\tBotAI_BotInitialChat(bs, \"death_slime\", name, NULL);\n\t\ttrap_BotEnterChat(bs->cs, 0, CHAT_ALL);\n\t}\n\tnum = trap_BotNumInitialChats(bs->cs, \"death_lava\");\n\tfor (i = 0; i < num; i++)\n\t{\n\t\tBotAI_BotInitialChat(bs, \"death_lava\", name, NULL);\n\t\ttrap_BotEnterChat(bs->cs, 0, CHAT_ALL);\n\t}\n\tnum = trap_BotNumInitialChats(bs->cs, \"death_cratered\");\n\tfor (i = 0; i < num; i++)\n\t{\n\t\tBotAI_BotInitialChat(bs, \"death_cratered\", name, NULL);\n\t\ttrap_BotEnterChat(bs->cs, 0, CHAT_ALL);\n\t}\n\tnum = trap_BotNumInitialChats(bs->cs, \"death_suicide\");\n\tfor (i = 0; i < num; i++)\n\t{\n\t\tBotAI_BotInitialChat(bs, \"death_suicide\", name, NULL);\n\t\ttrap_BotEnterChat(bs->cs, 0, CHAT_ALL);\n\t}\n\tnum = trap_BotNumInitialChats(bs->cs, \"death_telefrag\");\n\tfor (i = 0; i < num; i++)\n\t{\n\t\tBotAI_BotInitialChat(bs, \"death_telefrag\", name, NULL);\n\t\ttrap_BotEnterChat(bs->cs, 0, CHAT_ALL);\n\t}\n\tnum = trap_BotNumInitialChats(bs->cs, \"death_gauntlet\");\n\tfor (i = 0; i < num; i++)\n\t{\n\t\tBotAI_BotInitialChat(bs, \"death_gauntlet\",\n\t\t\t\tname,\t\t\t\t\t\t\t\t\t\t\t\t// 0\n\t\t\t\tBotWeaponNameForMeansOfDeath(bs->botdeathtype),\t\t// 1\n\t\t\t\tNULL);\n\t\ttrap_BotEnterChat(bs->cs, 0, CHAT_ALL);\n\t}\n\tnum = trap_BotNumInitialChats(bs->cs, \"death_rail\");\n\tfor (i = 0; i < num; i++)\n\t{\n\t\tBotAI_BotInitialChat(bs, \"death_rail\",\n\t\t\t\tname,\t\t\t\t\t\t\t\t\t\t\t\t// 0\n\t\t\t\tBotWeaponNameForMeansOfDeath(bs->botdeathtype),\t\t// 1\n\t\t\t\tNULL);\n\t\ttrap_BotEnterChat(bs->cs, 0, CHAT_ALL);\n\t}\n\tnum = trap_BotNumInitialChats(bs->cs, \"death_bfg\");\n\tfor (i = 0; i < num; i++)\n\t{\n\t\tBotAI_BotInitialChat(bs, \"death_bfg\",\n\t\t\t\tname,\t\t\t\t\t\t\t\t\t\t\t\t// 0\n\t\t\t\tBotWeaponNameForMeansOfDeath(bs->botdeathtype),\t\t// 1\n\t\t\t\tNULL);\n\t\ttrap_BotEnterChat(bs->cs, 0, CHAT_ALL);\n\t}\n\tnum = trap_BotNumInitialChats(bs->cs, \"death_insult\");\n\tfor (i = 0; i < num; i++)\n\t{\n\t\tBotAI_BotInitialChat(bs, \"death_insult\",\n\t\t\t\t\tname,\t\t\t\t\t\t\t\t\t\t\t\t// 0\n\t\t\t\t\tBotWeaponNameForMeansOfDeath(bs->botdeathtype),\t\t// 1\n\t\t\t\t\tNULL);\n\t\ttrap_BotEnterChat(bs->cs, 0, CHAT_ALL);\n\t}\n\tnum = trap_BotNumInitialChats(bs->cs, \"death_praise\");\n\tfor (i = 0; i < num; i++)\n\t{\n\t\tBotAI_BotInitialChat(bs, \"death_praise\",\n\t\t\t\t\tname,\t\t\t\t\t\t\t\t\t\t\t\t// 0\n\t\t\t\t\tBotWeaponNameForMeansOfDeath(bs->botdeathtype),\t\t// 1\n\t\t\t\t\tNULL);\n\t\ttrap_BotEnterChat(bs->cs, 0, CHAT_ALL);\n\t}\n\t//\n\tEasyClientName(bs->lastkilledplayer, name, 32);\n\t//\n\tnum = trap_BotNumInitialChats(bs->cs, \"kill_gauntlet\");\n\tfor (i = 0; i < num; i++)\n\t{\n\t\t//\n\t\tBotAI_BotInitialChat(bs, \"kill_gauntlet\", name, NULL);\n\t\ttrap_BotEnterChat(bs->cs, 0, CHAT_ALL);\n\t}\n\tnum = trap_BotNumInitialChats(bs->cs, \"kill_rail\");\n\tfor (i = 0; i < num; i++)\n\t{\n\t\tBotAI_BotInitialChat(bs, \"kill_rail\", name, NULL);\n\t\ttrap_BotEnterChat(bs->cs, 0, CHAT_ALL);\n\t}\n\tnum = trap_BotNumInitialChats(bs->cs, \"kill_telefrag\");\n\tfor (i = 0; i < num; i++)\n\t{\n\t\tBotAI_BotInitialChat(bs, \"kill_telefrag\", name, NULL);\n\t\ttrap_BotEnterChat(bs->cs, 0, CHAT_ALL);\n\t}\n\tnum = trap_BotNumInitialChats(bs->cs, \"kill_insult\");\n\tfor (i = 0; i < num; i++)\n\t{\n\t\tBotAI_BotInitialChat(bs, \"kill_insult\", name, NULL);\n\t\ttrap_BotEnterChat(bs->cs, 0, CHAT_ALL);\n\t}\n\tnum = trap_BotNumInitialChats(bs->cs, \"kill_praise\");\n\tfor (i = 0; i < num; i++)\n\t{\n\t\tBotAI_BotInitialChat(bs, \"kill_praise\", name, NULL);\n\t\ttrap_BotEnterChat(bs->cs, 0, CHAT_ALL);\n\t}\n\tnum = trap_BotNumInitialChats(bs->cs, \"enemy_suicide\");\n\tfor (i = 0; i < num; i++)\n\t{\n\t\tBotAI_BotInitialChat(bs, \"enemy_suicide\", name, NULL);\n\t\ttrap_BotEnterChat(bs->cs, 0, CHAT_ALL);\n\t}\n\tClientName(g_entities[bs->client].client->lasthurt_client, name, sizeof(name));\n\tweap = BotWeaponNameForMeansOfDeath(g_entities[bs->client].client->lasthurt_client);\n\tnum = trap_BotNumInitialChats(bs->cs, \"hit_talking\");\n\tfor (i = 0; i < num; i++)\n\t{\n\t\tBotAI_BotInitialChat(bs, \"hit_talking\", name, weap, NULL);\n\t\ttrap_BotEnterChat(bs->cs, 0, CHAT_ALL);\n\t}\n\tnum = trap_BotNumInitialChats(bs->cs, \"hit_nodeath\");\n\tfor (i = 0; i < num; i++)\n\t{\n\t\tBotAI_BotInitialChat(bs, \"hit_nodeath\", name, weap, NULL);\n\t\ttrap_BotEnterChat(bs->cs, 0, CHAT_ALL);\n\t}\n\tnum = trap_BotNumInitialChats(bs->cs, \"hit_nokill\");\n\tfor (i = 0; i < num; i++)\n\t{\n\t\tBotAI_BotInitialChat(bs, \"hit_nokill\", name, weap, NULL);\n\t\ttrap_BotEnterChat(bs->cs, 0, CHAT_ALL);\n\t}\n\t//\n\tif (bs->lastkilledplayer == bs->client) {\n\t\tstrcpy(name, BotRandomOpponentName(bs));\n\t}\n\telse {\n\t\tEasyClientName(bs->lastkilledplayer, name, sizeof(name));\n\t}\n\t//\n\tnum = trap_BotNumInitialChats(bs->cs, \"random_misc\");\n\tfor (i = 0; i < num; i++)\n\t{\n\t\t//\n\t\tBotAI_BotInitialChat(bs, \"random_misc\",\n\t\t\t\t\tBotRandomOpponentName(bs),\t// 0\n\t\t\t\t\tname,\t\t\t\t\t\t// 1\n\t\t\t\t\t\"[invalid var]\",\t\t\t// 2\n\t\t\t\t\t\"[invalid var]\",\t\t\t// 3\n\t\t\t\t\tBotMapTitle(),\t\t\t\t// 4\n\t\t\t\t\tBotRandomWeaponName(),\t\t// 5\n\t\t\t\t\tNULL);\n\t\ttrap_BotEnterChat(bs->cs, 0, CHAT_ALL);\n\t}\n\tnum = trap_BotNumInitialChats(bs->cs, \"random_insult\");\n\tfor (i = 0; i < num; i++)\n\t{\n\t\tBotAI_BotInitialChat(bs, \"random_insult\",\n\t\t\t\t\tBotRandomOpponentName(bs),\t// 0\n\t\t\t\t\tname,\t\t\t\t\t\t// 1\n\t\t\t\t\t\"[invalid var]\",\t\t\t// 2\n\t\t\t\t\t\"[invalid var]\",\t\t\t// 3\n\t\t\t\t\tBotMapTitle(),\t\t\t\t// 4\n\t\t\t\t\tBotRandomWeaponName(),\t\t// 5\n\t\t\t\t\tNULL);\n\t\ttrap_BotEnterChat(bs->cs, 0, CHAT_ALL);\n\t}\n}\n"
  },
  {
    "path": "src/game/ai_chat.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n\n/*****************************************************************************\n * name:\t\tai_chat.h\n *\n * desc:\t\tQuake3 bot AI\n *\n * $Archive: /source/code/botai/ai_chat.c $\n *\n *****************************************************************************/\n\n//\nint BotChat_EnterGame(bot_state_t *bs);\n//\nint BotChat_ExitGame(bot_state_t *bs);\n//\nint BotChat_StartLevel(bot_state_t *bs);\n//\nint BotChat_EndLevel(bot_state_t *bs);\n//\nint BotChat_HitTalking(bot_state_t *bs);\n//\nint BotChat_HitNoDeath(bot_state_t *bs);\n//\nint BotChat_HitNoKill(bot_state_t *bs);\n//\nint BotChat_Death(bot_state_t *bs);\n//\nint BotChat_Kill(bot_state_t *bs);\n//\nint BotChat_EnemySuicide(bot_state_t *bs);\n//\nint BotChat_Random(bot_state_t *bs);\n// time the selected chat takes to type in\nfloat BotChatTime(bot_state_t *bs);\n// returns true if the bot can chat at the current position\nint BotValidChatPosition(bot_state_t *bs);\n// test the initial bot chats\nvoid BotChatTest(bot_state_t *bs);\n\n"
  },
  {
    "path": "src/game/ai_cmd.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n\n/*****************************************************************************\n * name:\t\tai_cmd.c\n *\n * desc:\t\tQuake3 bot AI\n *\n * $Archive: /MissionPack/code/game/ai_cmd.c $\n *\n *****************************************************************************/\n\n#include \"g_local.h\"\n#include \"botlib.h\"\n#include \"be_aas.h\"\n#include \"be_ea.h\"\n#include \"be_ai_char.h\"\n#include \"be_ai_chat.h\"\n#include \"be_ai_gen.h\"\n#include \"be_ai_goal.h\"\n#include \"be_ai_move.h\"\n#include \"be_ai_weap.h\"\n//\n#include \"ai_main.h\"\n#include \"ai_dmq3.h\"\n#include \"ai_chat.h\"\n#include \"ai_cmd.h\"\n#include \"ai_dmnet.h\"\n#include \"ai_team.h\"\n//\n#include \"chars.h\"\t\t\t\t//characteristics\n#include \"inv.h\"\t\t\t\t//indexes into the inventory\n#include \"syn.h\"\t\t\t\t//synonyms\n#include \"match.h\"\t\t\t\t//string matching types and vars\n\n// for the voice chats\n#include \"menudef.h\"\n\nint notleader[MAX_CLIENTS];\n\n#ifdef DEBUG\n/*\n==================\nBotPrintTeamGoal\n==================\n*/\nvoid BotPrintTeamGoal(bot_state_t *bs) {\n\tchar netname[MAX_NETNAME];\n\tfloat t;\n\n\tClientName(bs->client, netname, sizeof(netname));\n\tt = bs->teamgoal_time - FloatTime();\n\tswitch(bs->ltgtype) {\n\t\tcase LTG_TEAMHELP:\n\t\t{\n\t\t\tBotAI_Print(PRT_MESSAGE, \"%s: I'm gonna help a team mate for %1.0f secs\\n\", netname, t);\n\t\t\tbreak;\n\t\t}\n\t\tcase LTG_TEAMACCOMPANY:\n\t\t{\n\t\t\tBotAI_Print(PRT_MESSAGE, \"%s: I'm gonna accompany a team mate for %1.0f secs\\n\", netname, t);\n\t\t\tbreak;\n\t\t}\n\t\tcase LTG_GETFLAG:\n\t\t{\n\t\t\tBotAI_Print(PRT_MESSAGE, \"%s: I'm gonna get the flag for %1.0f secs\\n\", netname, t);\n\t\t\tbreak;\n\t\t}\n\t\tcase LTG_RUSHBASE:\n\t\t{\n\t\t\tBotAI_Print(PRT_MESSAGE, \"%s: I'm gonna rush to the base for %1.0f secs\\n\", netname, t);\n\t\t\tbreak;\n\t\t}\n\t\tcase LTG_RETURNFLAG:\n\t\t{\n\t\t\tBotAI_Print(PRT_MESSAGE, \"%s: I'm gonna try to return the flag for %1.0f secs\\n\", netname, t);\n\t\t\tbreak;\n\t\t}\n\t\tcase LTG_DEFENDKEYAREA:\n\t\t{\n\t\t\tBotAI_Print(PRT_MESSAGE, \"%s: I'm gonna defend a key area for %1.0f secs\\n\", netname, t);\n\t\t\tbreak;\n\t\t}\n\t\tcase LTG_GETITEM:\n\t\t{\n\t\t\tBotAI_Print(PRT_MESSAGE, \"%s: I'm gonna get an item for %1.0f secs\\n\", netname, t);\n\t\t\tbreak;\n\t\t}\n\t\tcase LTG_KILL:\n\t\t{\n\t\t\tBotAI_Print(PRT_MESSAGE, \"%s: I'm gonna kill someone for %1.0f secs\\n\", netname, t);\n\t\t\tbreak;\n\t\t}\n\t\tcase LTG_CAMP:\n\t\tcase LTG_CAMPORDER:\n\t\t{\n\t\t\tBotAI_Print(PRT_MESSAGE, \"%s: I'm gonna camp for %1.0f secs\\n\", netname, t);\n\t\t\tbreak;\n\t\t}\n\t\tcase LTG_PATROL:\n\t\t{\n\t\t\tBotAI_Print(PRT_MESSAGE, \"%s: I'm gonna patrol for %1.0f secs\\n\", netname, t);\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t{\n\t\t\tif (bs->ctfroam_time > FloatTime()) {\n\t\t\t\tt = bs->ctfroam_time - FloatTime();\n\t\t\t\tBotAI_Print(PRT_MESSAGE, \"%s: I'm gonna roam for %1.0f secs\\n\", netname, t);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tBotAI_Print(PRT_MESSAGE, \"%s: I've got a regular goal\\n\", netname);\n\t\t\t}\n\t\t}\n\t}\n}\n#endif //DEBUG\n\n/*\n==================\nBotGetItemTeamGoal\n\nFIXME: add stuff like \"upper rocket launcher\"\n\"the rl near the railgun\", \"lower grenade launcher\" etc.\n==================\n*/\nint BotGetItemTeamGoal(char *goalname, bot_goal_t *goal) {\n\tint i;\n\n\tif (!strlen(goalname)) return qfalse;\n\ti = -1;\n\tdo {\n\t\ti = trap_BotGetLevelItemGoal(i, goalname, goal);\n\t\tif (i > 0) {\n\t\t\t//do NOT defend dropped items\n\t\t\tif (goal->flags & GFL_DROPPED)\n\t\t\t\tcontinue;\n\t\t\treturn qtrue;\n\t\t}\n\t} while(i > 0);\n\treturn qfalse;\n}\n\n/*\n==================\nBotGetMessageTeamGoal\n==================\n*/\nint BotGetMessageTeamGoal(bot_state_t *bs, char *goalname, bot_goal_t *goal) {\n\tbot_waypoint_t *cp;\n\n\tif (BotGetItemTeamGoal(goalname, goal)) return qtrue;\n\n\tcp = BotFindWayPoint(bs->checkpoints, goalname);\n\tif (cp) {\n\t\tmemcpy(goal, &cp->goal, sizeof(bot_goal_t));\n\t\treturn qtrue;\n\t}\n\treturn qfalse;\n}\n\n/*\n==================\nBotGetTime\n==================\n*/\nfloat BotGetTime(bot_match_t *match) {\n\tbot_match_t timematch;\n\tchar timestring[MAX_MESSAGE_SIZE];\n\tfloat t;\n\n\t//if the matched string has a time\n\tif (match->subtype & ST_TIME) {\n\t\t//get the time string\n\t\ttrap_BotMatchVariable(match, TIME, timestring, MAX_MESSAGE_SIZE);\n\t\t//match it to find out if the time is in seconds or minutes\n\t\tif (trap_BotFindMatch(timestring, &timematch, MTCONTEXT_TIME)) {\n\t\t\tif (timematch.type == MSG_FOREVER) {\n\t\t\t\tt = 99999999.0f;\n\t\t\t}\n\t\t\telse if (timematch.type == MSG_FORAWHILE) {\n\t\t\t\tt = 10 * 60; // 10 minutes\n\t\t\t}\n\t\t\telse if (timematch.type == MSG_FORALONGTIME) {\n\t\t\t\tt = 30 * 60; // 30 minutes\n\t\t\t}\n\t\t\telse {\n\t\t\t\ttrap_BotMatchVariable(&timematch, TIME, timestring, MAX_MESSAGE_SIZE);\n\t\t\t\tif (timematch.type == MSG_MINUTES) t = atof(timestring) * 60;\n\t\t\t\telse if (timematch.type == MSG_SECONDS) t = atof(timestring);\n\t\t\t\telse t = 0;\n\t\t\t}\n\t\t\t//if there's a valid time\n\t\t\tif (t > 0) return FloatTime() + t;\n\t\t}\n\t}\n\treturn 0;\n}\n\n/*\n==================\nFindClientByName\n==================\n*/\nint FindClientByName(char *name) {\n\tint i;\n\tchar buf[MAX_INFO_STRING];\n\tstatic int maxclients;\n\n\tif (!maxclients)\n\t\tmaxclients = trap_Cvar_VariableIntegerValue(\"sv_maxclients\");\n\tfor (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {\n\t\tClientName(i, buf, sizeof(buf));\n\t\tif (!Q_stricmp(buf, name)) return i;\n\t}\n\tfor (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {\n\t\tClientName(i, buf, sizeof(buf));\n\t\tif (stristr(buf, name)) return i;\n\t}\n\treturn -1;\n}\n\n/*\n==================\nFindEnemyByName\n==================\n*/\nint FindEnemyByName(bot_state_t *bs, char *name) {\n\tint i;\n\tchar buf[MAX_INFO_STRING];\n\tstatic int maxclients;\n\n\tif (!maxclients)\n\t\tmaxclients = trap_Cvar_VariableIntegerValue(\"sv_maxclients\");\n\tfor (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {\n\t\tif (BotSameTeam(bs, i)) continue;\n\t\tClientName(i, buf, sizeof(buf));\n\t\tif (!Q_stricmp(buf, name)) return i;\n\t}\n\tfor (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {\n\t\tif (BotSameTeam(bs, i)) continue;\n\t\tClientName(i, buf, sizeof(buf));\n\t\tif (stristr(buf, name)) return i;\n\t}\n\treturn -1;\n}\n\n/*\n==================\nNumPlayersOnSameTeam\n==================\n*/\nint NumPlayersOnSameTeam(bot_state_t *bs) {\n\tint i, num;\n\tchar buf[MAX_INFO_STRING];\n\tstatic int maxclients;\n\n\tif (!maxclients)\n\t\tmaxclients = trap_Cvar_VariableIntegerValue(\"sv_maxclients\");\n\n\tnum = 0;\n\tfor (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {\n\t\ttrap_GetConfigstring(CS_PLAYERS+i, buf, MAX_INFO_STRING);\n\t\tif (strlen(buf)) {\n\t\t\tif (BotSameTeam(bs, i+1)) num++;\n\t\t}\n\t}\n\treturn num;\n}\n\n/*\n==================\nTeamPlayIsOn\n==================\n*/\nint BotGetPatrolWaypoints(bot_state_t *bs, bot_match_t *match) {\n\tchar keyarea[MAX_MESSAGE_SIZE];\n\tint patrolflags;\n\tbot_waypoint_t *wp, *newwp, *newpatrolpoints;\n\tbot_match_t keyareamatch;\n\tbot_goal_t goal;\n\n\tnewpatrolpoints = NULL;\n\tpatrolflags = 0;\n\t//\n\ttrap_BotMatchVariable(match, KEYAREA, keyarea, MAX_MESSAGE_SIZE);\n\t//\n\twhile(1) {\n\t\tif (!trap_BotFindMatch(keyarea, &keyareamatch, MTCONTEXT_PATROLKEYAREA)) {\n\t\t\ttrap_EA_SayTeam(bs->client, \"what do you say?\");\n\t\t\tBotFreeWaypoints(newpatrolpoints);\n\t\t\tbs->patrolpoints = NULL;\n\t\t\treturn qfalse;\n\t\t}\n\t\ttrap_BotMatchVariable(&keyareamatch, KEYAREA, keyarea, MAX_MESSAGE_SIZE);\n\t\tif (!BotGetMessageTeamGoal(bs, keyarea, &goal)) {\n\t\t\t//BotAI_BotInitialChat(bs, \"cannotfind\", keyarea, NULL);\n\t\t\t//trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);\n\t\t\tBotFreeWaypoints(newpatrolpoints);\n\t\t\tbs->patrolpoints = NULL;\n\t\t\treturn qfalse;\n\t\t}\n\t\t//create a new waypoint\n\t\tnewwp = BotCreateWayPoint(keyarea, goal.origin, goal.areanum);\n\t\tif (!newwp)\n\t\t\tbreak;\n\t\t//add the waypoint to the patrol points\n\t\tnewwp->next = NULL;\n\t\tfor (wp = newpatrolpoints; wp && wp->next; wp = wp->next);\n\t\tif (!wp) {\n\t\t\tnewpatrolpoints = newwp;\n\t\t\tnewwp->prev = NULL;\n\t\t}\n\t\telse {\n\t\t\twp->next = newwp;\n\t\t\tnewwp->prev = wp;\n\t\t}\n\t\t//\n\t\tif (keyareamatch.subtype & ST_BACK) {\n\t\t\tpatrolflags = PATROL_LOOP;\n\t\t\tbreak;\n\t\t}\n\t\telse if (keyareamatch.subtype & ST_REVERSE) {\n\t\t\tpatrolflags = PATROL_REVERSE;\n\t\t\tbreak;\n\t\t}\n\t\telse if (keyareamatch.subtype & ST_MORE) {\n\t\t\ttrap_BotMatchVariable(&keyareamatch, MORE, keyarea, MAX_MESSAGE_SIZE);\n\t\t}\n\t\telse {\n\t\t\tbreak;\n\t\t}\n\t}\n\t//\n\tif (!newpatrolpoints || !newpatrolpoints->next) {\n\t\ttrap_EA_SayTeam(bs->client, \"I need more key points to patrol\\n\");\n\t\tBotFreeWaypoints(newpatrolpoints);\n\t\tnewpatrolpoints = NULL;\n\t\treturn qfalse;\n\t}\n\t//\n\tBotFreeWaypoints(bs->patrolpoints);\n\tbs->patrolpoints = newpatrolpoints;\n\t//\n\tbs->curpatrolpoint = bs->patrolpoints;\n\tbs->patrolflags = patrolflags;\n\t//\n\treturn qtrue;\n}\n\n/*\n==================\nBotAddressedToBot\n==================\n*/\nint BotAddressedToBot(bot_state_t *bs, bot_match_t *match) {\n\tchar addressedto[MAX_MESSAGE_SIZE];\n\tchar netname[MAX_MESSAGE_SIZE];\n\tchar name[MAX_MESSAGE_SIZE];\n\tchar botname[128];\n\tint client;\n\tbot_match_t addresseematch;\n\n\ttrap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));\n\tclient = ClientOnSameTeamFromName(bs, netname);\n\tif (client < 0) return qfalse;\n\t//if the message is addressed to someone\n\tif (match->subtype & ST_ADDRESSED) {\n\t\ttrap_BotMatchVariable(match, ADDRESSEE, addressedto, sizeof(addressedto));\n\t\t//the name of this bot\n\t\tClientName(bs->client, botname, 128);\n\t\t//\n\t\twhile(trap_BotFindMatch(addressedto, &addresseematch, MTCONTEXT_ADDRESSEE)) {\n\t\t\tif (addresseematch.type == MSG_EVERYONE) {\n\t\t\t\treturn qtrue;\n\t\t\t}\n\t\t\telse if (addresseematch.type == MSG_MULTIPLENAMES) {\n\t\t\t\ttrap_BotMatchVariable(&addresseematch, TEAMMATE, name, sizeof(name));\n\t\t\t\tif (strlen(name)) {\n\t\t\t\t\tif (stristr(botname, name)) return qtrue;\n\t\t\t\t\tif (stristr(bs->subteam, name)) return qtrue;\n\t\t\t\t}\n\t\t\t\ttrap_BotMatchVariable(&addresseematch, MORE, addressedto, MAX_MESSAGE_SIZE);\n\t\t\t}\n\t\t\telse {\n\t\t\t\ttrap_BotMatchVariable(&addresseematch, TEAMMATE, name, MAX_MESSAGE_SIZE);\n\t\t\t\tif (strlen(name)) {\n\t\t\t\t\tif (stristr(botname, name)) return qtrue;\n\t\t\t\t\tif (stristr(bs->subteam, name)) return qtrue;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\t//Com_sprintf(buf, sizeof(buf), \"not addressed to me but %s\", addressedto);\n\t\t//trap_EA_Say(bs->client, buf);\n\t\treturn qfalse;\n\t}\n\telse {\n\t\tbot_match_t tellmatch;\n\n\t\ttellmatch.type = 0;\n\t\t//if this message wasn't directed solely to this bot\n\t\tif (!trap_BotFindMatch(match->string, &tellmatch, MTCONTEXT_REPLYCHAT) ||\n\t\t\t\ttellmatch.type != MSG_CHATTELL) {\n\t\t\t//make sure not everyone reacts to this message\n\t\t\tif (random() > (float ) 1.0 / (NumPlayersOnSameTeam(bs)-1)) return qfalse;\n\t\t}\n\t}\n\treturn qtrue;\n}\n\n/*\n==================\nBotGPSToPosition\n==================\n*/\nint BotGPSToPosition(char *buf, vec3_t position) {\n\tint i, j = 0;\n\tint num, sign;\n\n\tfor (i = 0; i < 3; i++) {\n\t\tnum = 0;\n\t\twhile(buf[j] == ' ') j++;\n\t\tif (buf[j] == '-') {\n\t\t\tj++;\n\t\t\tsign = -1;\n\t\t}\n\t\telse {\n\t\t\tsign = 1;\n\t\t}\n\t\twhile (buf[j]) {\n\t\t\tif (buf[j] >= '0' && buf[j] <= '9') {\n\t\t\t\tnum = num * 10 + buf[j] - '0';\n\t\t\t\tj++;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tj++;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tBotAI_Print(PRT_MESSAGE, \"%d\\n\", sign * num);\n\t\tposition[i] = (float) sign * num;\n\t}\n\treturn qtrue;\n}\n\n/*\n==================\nBotMatch_HelpAccompany\n==================\n*/\nvoid BotMatch_HelpAccompany(bot_state_t *bs, bot_match_t *match) {\n\tint client, other, areanum;\n\tchar teammate[MAX_MESSAGE_SIZE];\n\tchar netname[MAX_MESSAGE_SIZE];\n\tchar itemname[MAX_MESSAGE_SIZE];\n\tbot_match_t teammatematch;\n\taas_entityinfo_t entinfo;\n\n\tif (!TeamPlayIsOn()) return;\n\t//if not addressed to this bot\n\tif (!BotAddressedToBot(bs, match)) return;\n\t//get the team mate name\n\ttrap_BotMatchVariable(match, TEAMMATE, teammate, sizeof(teammate));\n\t//get the client to help\n\tif (trap_BotFindMatch(teammate, &teammatematch, MTCONTEXT_TEAMMATE) &&\n\t\t\t//if someone asks for him or herself\n\t\t\tteammatematch.type == MSG_ME) {\n\t\t//get the netname\n\t\ttrap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));\n\t\tclient = ClientFromName(netname);\n\t\tother = qfalse;\n\t}\n\telse {\n\t\t//asked for someone else\n\t\tclient = FindClientByName(teammate);\n\t\t//if this is the bot self\n\t\tif (client == bs->client) {\n\t\t\tother = qfalse;\n\t\t}\n\t\telse if (!BotSameTeam(bs, client)) {\n\t\t\t//FIXME: say \"I don't help the enemy\"\n\t\t\treturn;\n\t\t}\n\t\telse {\n\t\t\tother = qtrue;\n\t\t}\n\t}\n\t//if the bot doesn't know who to help (FindClientByName returned -1)\n\tif (client < 0) {\n\t\tif (other) BotAI_BotInitialChat(bs, \"whois\", teammate, NULL);\n\t\telse BotAI_BotInitialChat(bs, \"whois\", netname, NULL);\n\t\tclient = ClientFromName(netname);\n\t\ttrap_BotEnterChat(bs->cs, client, CHAT_TELL);\n\t\treturn;\n\t}\n\t//don't help or accompany yourself\n\tif (client == bs->client) {\n\t\treturn;\n\t}\n\t//\n\tbs->teamgoal.entitynum = -1;\n\tBotEntityInfo(client, &entinfo);\n\t//if info is valid (in PVS)\n\tif (entinfo.valid) {\n\t\tareanum = BotPointAreaNum(entinfo.origin);\n\t\tif (areanum) {// && trap_AAS_AreaReachability(areanum)) {\n\t\t\tbs->teamgoal.entitynum = client;\n\t\t\tbs->teamgoal.areanum = areanum;\n\t\t\tVectorCopy(entinfo.origin, bs->teamgoal.origin);\n\t\t\tVectorSet(bs->teamgoal.mins, -8, -8, -8);\n\t\t\tVectorSet(bs->teamgoal.maxs, 8, 8, 8);\n\t\t}\n\t}\n\t//if no teamgoal yet\n\tif (bs->teamgoal.entitynum < 0) {\n\t\t//if near an item\n\t\tif (match->subtype & ST_NEARITEM) {\n\t\t\t//get the match variable\n\t\t\ttrap_BotMatchVariable(match, ITEM, itemname, sizeof(itemname));\n\t\t\t//\n\t\t\tif (!BotGetMessageTeamGoal(bs, itemname, &bs->teamgoal)) {\n\t\t\t\t//BotAI_BotInitialChat(bs, \"cannotfind\", itemname, NULL);\n\t\t\t\t//trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\t//\n\tif (bs->teamgoal.entitynum < 0) {\n\t\tif (other) BotAI_BotInitialChat(bs, \"whereis\", teammate, NULL);\n\t\telse BotAI_BotInitialChat(bs, \"whereareyou\", netname, NULL);\n\t\tclient = ClientFromName(netname);\n\t\ttrap_BotEnterChat(bs->cs, client, CHAT_TEAM);\n\t\treturn;\n\t}\n\t//the team mate\n\tbs->teammate = client;\n\t//\n\ttrap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));\n\t//\n\tclient = ClientFromName(netname);\n\t//the team mate who ordered\n\tbs->decisionmaker = client;\n\tbs->ordered = qtrue;\n\tbs->order_time = FloatTime();\n\t//last time the team mate was assumed visible\n\tbs->teammatevisible_time = FloatTime();\n\t//set the time to send a message to the team mates\n\tbs->teammessage_time = FloatTime() + 2 * random();\n\t//get the team goal time\n\tbs->teamgoal_time = BotGetTime(match);\n\t//set the ltg type\n\tif (match->type == MSG_HELP) {\n\t\tbs->ltgtype = LTG_TEAMHELP;\n\t\tif (!bs->teamgoal_time) bs->teamgoal_time = FloatTime() + TEAM_HELP_TIME;\n\t}\n\telse {\n\t\tbs->ltgtype = LTG_TEAMACCOMPANY;\n\t\tif (!bs->teamgoal_time) bs->teamgoal_time = FloatTime() + TEAM_ACCOMPANY_TIME;\n\t\tbs->formation_dist = 3.5 * 32;\t\t//3.5 meter\n\t\tbs->arrive_time = 0;\n\t\t//\n\t\tBotSetTeamStatus(bs);\n\t\t// remember last ordered task\n\t\tBotRememberLastOrderedTask(bs);\n\t}\n#ifdef DEBUG\n\tBotPrintTeamGoal(bs);\n#endif //DEBUG\n}\n\n/*\n==================\nBotMatch_DefendKeyArea\n==================\n*/\nvoid BotMatch_DefendKeyArea(bot_state_t *bs, bot_match_t *match) {\n\tchar itemname[MAX_MESSAGE_SIZE];\n\tchar netname[MAX_MESSAGE_SIZE];\n\tint client;\n\n\tif (!TeamPlayIsOn()) return;\n\t//if not addressed to this bot\n\tif (!BotAddressedToBot(bs, match)) return;\n\t//get the match variable\n\ttrap_BotMatchVariable(match, KEYAREA, itemname, sizeof(itemname));\n\t//\n\tif (!BotGetMessageTeamGoal(bs, itemname, &bs->teamgoal)) {\n\t\t//BotAI_BotInitialChat(bs, \"cannotfind\", itemname, NULL);\n\t\t//trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM);\n\t\treturn;\n\t}\n\t//\n\ttrap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));\n\t//\n\tclient = ClientFromName(netname);\n\t//the team mate who ordered\n\tbs->decisionmaker = client;\n\tbs->ordered = qtrue;\n\tbs->order_time = FloatTime();\n\t//set the time to send a message to the team mates\n\tbs->teammessage_time = FloatTime() + 2 * random();\n\t//set the ltg type\n\tbs->ltgtype = LTG_DEFENDKEYAREA;\n\t//get the team goal time\n\tbs->teamgoal_time = BotGetTime(match);\n\t//set the team goal time\n\tif (!bs->teamgoal_time) bs->teamgoal_time = FloatTime() + TEAM_DEFENDKEYAREA_TIME;\n\t//away from defending\n\tbs->defendaway_time = 0;\n\t//\n\tBotSetTeamStatus(bs);\n\t// remember last ordered task\n\tBotRememberLastOrderedTask(bs);\n#ifdef DEBUG\n\tBotPrintTeamGoal(bs);\n#endif //DEBUG\n}\n\n/*\n==================\nBotMatch_GetItem\n==================\n*/\nvoid BotMatch_GetItem(bot_state_t *bs, bot_match_t *match) {\n\tchar itemname[MAX_MESSAGE_SIZE];\n\tchar netname[MAX_MESSAGE_SIZE];\n\tint client;\n\n\tif (!TeamPlayIsOn()) return;\n\t//if not addressed to this bot\n\tif (!BotAddressedToBot(bs, match)) return;\n\t//get the match variable\n\ttrap_BotMatchVariable(match, ITEM, itemname, sizeof(itemname));\n\t//\n\tif (!BotGetMessageTeamGoal(bs, itemname, &bs->teamgoal)) {\n\t\t//BotAI_BotInitialChat(bs, \"cannotfind\", itemname, NULL);\n\t\t//trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM);\n\t\treturn;\n\t}\n\ttrap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));\n\tclient = ClientOnSameTeamFromName(bs, netname);\n\t//\n\tbs->decisionmaker = client;\n\tbs->ordered = qtrue;\n\tbs->order_time = FloatTime();\n\t//set the time to send a message to the team mates\n\tbs->teammessage_time = FloatTime() + 2 * random();\n\t//set the ltg type\n\tbs->ltgtype = LTG_GETITEM;\n\t//set the team goal time\n\tbs->teamgoal_time = FloatTime() + TEAM_GETITEM_TIME;\n\t//\n\tBotSetTeamStatus(bs);\n#ifdef DEBUG\n\tBotPrintTeamGoal(bs);\n#endif //DEBUG\n}\n\n/*\n==================\nBotMatch_Camp\n==================\n*/\nvoid BotMatch_Camp(bot_state_t *bs, bot_match_t *match) {\n\tint client, areanum;\n\tchar netname[MAX_MESSAGE_SIZE];\n\tchar itemname[MAX_MESSAGE_SIZE];\n\taas_entityinfo_t entinfo;\n\n\tif (!TeamPlayIsOn()) return;\n\t//if not addressed to this bot\n\tif (!BotAddressedToBot(bs, match)) return;\n\t//\n\ttrap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));\n\t//asked for someone else\n\tclient = FindClientByName(netname);\n\t//if there's no valid client with this name\n\tif (client < 0) {\n\t\tBotAI_BotInitialChat(bs, \"whois\", netname, NULL);\n\t\ttrap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM);\n\t\treturn;\n\t}\n\t//get the match variable\n\ttrap_BotMatchVariable(match, KEYAREA, itemname, sizeof(itemname));\n\t//in CTF it could be the base\n\tif (match->subtype & ST_THERE) {\n\t\t//camp at the spot the bot is currently standing\n\t\tbs->teamgoal.entitynum = bs->entitynum;\n\t\tbs->teamgoal.areanum = bs->areanum;\n\t\tVectorCopy(bs->origin, bs->teamgoal.origin);\n\t\tVectorSet(bs->teamgoal.mins, -8, -8, -8);\n\t\tVectorSet(bs->teamgoal.maxs, 8, 8, 8);\n\t}\n\telse if (match->subtype & ST_HERE) {\n\t\t//if this is the bot self\n\t\tif (client == bs->client) return;\n\t\t//\n\t\tbs->teamgoal.entitynum = -1;\n\t\tBotEntityInfo(client, &entinfo);\n\t\t//if info is valid (in PVS)\n\t\tif (entinfo.valid) {\n\t\t\tareanum = BotPointAreaNum(entinfo.origin);\n\t\t\tif (areanum) {// && trap_AAS_AreaReachability(areanum)) {\n\t\t\t\t//NOTE: just assume the bot knows where the person is\n\t\t\t\t//if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, client)) {\n\t\t\t\t\tbs->teamgoal.entitynum = client;\n\t\t\t\t\tbs->teamgoal.areanum = areanum;\n\t\t\t\t\tVectorCopy(entinfo.origin, bs->teamgoal.origin);\n\t\t\t\t\tVectorSet(bs->teamgoal.mins, -8, -8, -8);\n\t\t\t\t\tVectorSet(bs->teamgoal.maxs, 8, 8, 8);\n\t\t\t\t//}\n\t\t\t}\n\t\t}\n\t\t//if the other is not visible\n\t\tif (bs->teamgoal.entitynum < 0) {\n\t\t\tBotAI_BotInitialChat(bs, \"whereareyou\", netname, NULL);\n\t\t\tclient = ClientFromName(netname);\n\t\t\ttrap_BotEnterChat(bs->cs, client, CHAT_TELL);\n\t\t\treturn;\n\t\t}\n\t}\n\telse if (!BotGetMessageTeamGoal(bs, itemname, &bs->teamgoal)) {\n\t\t//BotAI_BotInitialChat(bs, \"cannotfind\", itemname, NULL);\n\t\t//client = ClientFromName(netname);\n\t\t//trap_BotEnterChat(bs->cs, client, CHAT_TELL);\n\t\treturn;\n\t}\n\t//\n\tbs->decisionmaker = client;\n\tbs->ordered = qtrue;\n\tbs->order_time = FloatTime();\n\t//set the time to send a message to the team mates\n\tbs->teammessage_time = FloatTime() + 2 * random();\n\t//set the ltg type\n\tbs->ltgtype = LTG_CAMPORDER;\n\t//get the team goal time\n\tbs->teamgoal_time = BotGetTime(match);\n\t//set the team goal time\n\tif (!bs->teamgoal_time) bs->teamgoal_time = FloatTime() + TEAM_CAMP_TIME;\n\t//not arrived yet\n\tbs->arrive_time = 0;\n\t//\n\tBotSetTeamStatus(bs);\n\t// remember last ordered task\n\tBotRememberLastOrderedTask(bs);\n#ifdef DEBUG\n\tBotPrintTeamGoal(bs);\n#endif //DEBUG\n}\n\n/*\n==================\nBotMatch_Patrol\n==================\n*/\nvoid BotMatch_Patrol(bot_state_t *bs, bot_match_t *match) {\n\tchar netname[MAX_MESSAGE_SIZE];\n\tint client;\n\n\tif (!TeamPlayIsOn()) return;\n\t//if not addressed to this bot\n\tif (!BotAddressedToBot(bs, match)) return;\n\t//get the patrol waypoints\n\tif (!BotGetPatrolWaypoints(bs, match)) return;\n\t//\n\ttrap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));\n\t//\n\tclient = FindClientByName(netname);\n\t//\n\tbs->decisionmaker = client;\n\tbs->ordered = qtrue;\n\tbs->order_time = FloatTime();\n\t//set the time to send a message to the team mates\n\tbs->teammessage_time = FloatTime() + 2 * random();\n\t//set the ltg type\n\tbs->ltgtype = LTG_PATROL;\n\t//get the team goal time\n\tbs->teamgoal_time = BotGetTime(match);\n\t//set the team goal time if not set already\n\tif (!bs->teamgoal_time) bs->teamgoal_time = FloatTime() + TEAM_PATROL_TIME;\n\t//\n\tBotSetTeamStatus(bs);\n\t// remember last ordered task\n\tBotRememberLastOrderedTask(bs);\n#ifdef DEBUG\n\tBotPrintTeamGoal(bs);\n#endif //DEBUG\n}\n\n/*\n==================\nBotMatch_GetFlag\n==================\n*/\nvoid BotMatch_GetFlag(bot_state_t *bs, bot_match_t *match) {\n\tchar netname[MAX_MESSAGE_SIZE];\n\tint client;\n\n\tif (gametype == GT_CTF) {\n\t\tif (!ctf_redflag.areanum || !ctf_blueflag.areanum)\n\t\t\treturn;\n\t}\n\telse {\n\t\treturn;\n\t}\n\t//if not addressed to this bot\n\tif (!BotAddressedToBot(bs, match)) return;\n\t//\n\ttrap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));\n\t//\n\tclient = FindClientByName(netname);\n\t//\n\tbs->decisionmaker = client;\n\tbs->ordered = qtrue;\n\tbs->order_time = FloatTime();\n\t//set the time to send a message to the team mates\n\tbs->teammessage_time = FloatTime() + 2 * random();\n\t//set the ltg type\n\tbs->ltgtype = LTG_GETFLAG;\n\t//set the team goal time\n\tbs->teamgoal_time = FloatTime() + CTF_GETFLAG_TIME;\n\t// get an alternate route in ctf\n\tif (gametype == GT_CTF) {\n\t\t//get an alternative route goal towards the enemy base\n\t\tBotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));\n\t}\n\t//\n\tBotSetTeamStatus(bs);\n\t// remember last ordered task\n\tBotRememberLastOrderedTask(bs);\n#ifdef DEBUG\n\tBotPrintTeamGoal(bs);\n#endif //DEBUG\n}\n\n/*\n==================\nBotMatch_AttackEnemyBase\n==================\n*/\nvoid BotMatch_AttackEnemyBase(bot_state_t *bs, bot_match_t *match) {\n\tchar netname[MAX_MESSAGE_SIZE];\n\tint client;\n\n\tif (gametype == GT_CTF) {\n\t\tBotMatch_GetFlag(bs, match);\n\t}\n\telse {\n\t\treturn;\n\t}\n\t//if not addressed to this bot\n\tif (!BotAddressedToBot(bs, match)) return;\n\t//\n\ttrap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));\n\t//\n\tclient = FindClientByName(netname);\n\t//\n\tbs->decisionmaker = client;\n\tbs->ordered = qtrue;\n\tbs->order_time = FloatTime();\n\t//set the time to send a message to the team mates\n\tbs->teammessage_time = FloatTime() + 2 * random();\n\t//set the ltg type\n\tbs->ltgtype = LTG_ATTACKENEMYBASE;\n\t//set the team goal time\n\tbs->teamgoal_time = FloatTime() + TEAM_ATTACKENEMYBASE_TIME;\n\tbs->attackaway_time = 0;\n\t//\n\tBotSetTeamStatus(bs);\n\t// remember last ordered task\n\tBotRememberLastOrderedTask(bs);\n#ifdef DEBUG\n\tBotPrintTeamGoal(bs);\n#endif //DEBUG\n}\n\n/*\n==================\nBotMatch_RushBase\n==================\n*/\nvoid BotMatch_RushBase(bot_state_t *bs, bot_match_t *match) {\n\tchar netname[MAX_MESSAGE_SIZE];\n\tint client;\n\n\tif (gametype == GT_CTF) {\n\t\tif (!ctf_redflag.areanum || !ctf_blueflag.areanum)\n\t\t\treturn;\n\t}\n\telse {\n\t\treturn;\n\t}\n\t//if not addressed to this bot\n\tif (!BotAddressedToBot(bs, match)) return;\n\t//\n\ttrap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));\n\t//\n\tclient = FindClientByName(netname);\n\t//\n\tbs->decisionmaker = client;\n\tbs->ordered = qtrue;\n\tbs->order_time = FloatTime();\n\t//set the time to send a message to the team mates\n\tbs->teammessage_time = FloatTime() + 2 * random();\n\t//set the ltg type\n\tbs->ltgtype = LTG_RUSHBASE;\n\t//set the team goal time\n\tbs->teamgoal_time = FloatTime() + CTF_RUSHBASE_TIME;\n\tbs->rushbaseaway_time = 0;\n\t//\n\tBotSetTeamStatus(bs);\n#ifdef DEBUG\n\tBotPrintTeamGoal(bs);\n#endif //DEBUG\n}\n\n/*\n==================\nBotMatch_TaskPreference\n==================\n*/\nvoid BotMatch_TaskPreference(bot_state_t *bs, bot_match_t *match) {\n\tchar netname[MAX_NETNAME];\n\tchar teammatename[MAX_MESSAGE_SIZE];\n\tint teammate, preference;\n\n\tClientName(bs->client, netname, sizeof(netname));\n\tif (Q_stricmp(netname, bs->teamleader) != 0) return;\n\n\ttrap_BotMatchVariable(match, NETNAME, teammatename, sizeof(teammatename));\n\tteammate = ClientFromName(teammatename);\n\tif (teammate < 0) return;\n\n\tpreference = BotGetTeamMateTaskPreference(bs, teammate);\n\tswitch(match->subtype)\n\t{\n\t\tcase ST_DEFENDER:\n\t\t{\n\t\t\tpreference &= ~TEAMTP_ATTACKER;\n\t\t\tpreference |= TEAMTP_DEFENDER;\n\t\t\tbreak;\n\t\t}\n\t\tcase ST_ATTACKER:\n\t\t{\n\t\t\tpreference &= ~TEAMTP_DEFENDER;\n\t\t\tpreference |= TEAMTP_ATTACKER;\n\t\t\tbreak;\n\t\t}\n\t\tcase ST_ROAMER:\n\t\t{\n\t\t\tpreference &= ~(TEAMTP_ATTACKER|TEAMTP_DEFENDER);\n\t\t\tbreak;\n\t\t}\n\t}\n\tBotSetTeamMateTaskPreference(bs, teammate, preference);\n\t//\n\tEasyClientName(teammate, teammatename, sizeof(teammatename));\n\tBotAI_BotInitialChat(bs, \"keepinmind\", teammatename, NULL);\n\ttrap_BotEnterChat(bs->cs, teammate, CHAT_TELL);\n\tBotVoiceChatOnly(bs, teammate, VOICECHAT_YES);\n\ttrap_EA_Action(bs->client, ACTION_AFFIRMATIVE);\n}\n\n/*\n==================\nBotMatch_ReturnFlag\n==================\n*/\nvoid BotMatch_ReturnFlag(bot_state_t *bs, bot_match_t *match) {\n\tchar netname[MAX_MESSAGE_SIZE];\n\tint client;\n\n\t//if not in CTF mode\n\tif (\n\t\tgametype != GT_CTF\n\t\t)\n\t\treturn;\n\t//if not addressed to this bot\n\tif (!BotAddressedToBot(bs, match))\n\t\treturn;\n\t//\n\ttrap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));\n\t//\n\tclient = FindClientByName(netname);\n\t//\n\tbs->decisionmaker = client;\n\tbs->ordered = qtrue;\n\tbs->order_time = FloatTime();\n\t//set the time to send a message to the team mates\n\tbs->teammessage_time = FloatTime() + 2 * random();\n\t//set the ltg type\n\tbs->ltgtype = LTG_RETURNFLAG;\n\t//set the team goal time\n\tbs->teamgoal_time = FloatTime() + CTF_RETURNFLAG_TIME;\n\tbs->rushbaseaway_time = 0;\n\t//\n\tBotSetTeamStatus(bs);\n#ifdef DEBUG\n\tBotPrintTeamGoal(bs);\n#endif //DEBUG\n}\n\n/*\n==================\nBotMatch_JoinSubteam\n==================\n*/\nvoid BotMatch_JoinSubteam(bot_state_t *bs, bot_match_t *match) {\n\tchar teammate[MAX_MESSAGE_SIZE];\n\tchar netname[MAX_MESSAGE_SIZE];\n\tint client;\n\n\tif (!TeamPlayIsOn()) return;\n\t//if not addressed to this bot\n\tif (!BotAddressedToBot(bs, match)) return;\n\t//get the sub team name\n\ttrap_BotMatchVariable(match, TEAMNAME, teammate, sizeof(teammate));\n\t//set the sub team name\n\tstrncpy(bs->subteam, teammate, 32);\n\tbs->subteam[31] = '\\0';\n\t//\n\ttrap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));\n\tBotAI_BotInitialChat(bs, \"joinedteam\", teammate, NULL);\n\tclient = ClientFromName(netname);\n\ttrap_BotEnterChat(bs->cs, client, CHAT_TELL);\n}\n\n/*\n==================\nBotMatch_LeaveSubteam\n==================\n*/\nvoid BotMatch_LeaveSubteam(bot_state_t *bs, bot_match_t *match) {\n\tchar netname[MAX_MESSAGE_SIZE];\n\tint client;\n\n\tif (!TeamPlayIsOn()) return;\n\t//if not addressed to this bot\n\tif (!BotAddressedToBot(bs, match)) return;\n\t//\n\tif (strlen(bs->subteam))\n\t{\n\t\tBotAI_BotInitialChat(bs, \"leftteam\", bs->subteam, NULL);\n\t\ttrap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));\n\t\tclient = ClientFromName(netname);\n\t\ttrap_BotEnterChat(bs->cs, client, CHAT_TELL);\n\t} //end if\n\tstrcpy(bs->subteam, \"\");\n}\n\n/*\n==================\nBotMatch_LeaveSubteam\n==================\n*/\nvoid BotMatch_WhichTeam(bot_state_t *bs, bot_match_t *match) {\n\tif (!TeamPlayIsOn()) return;\n\t//if not addressed to this bot\n\tif (!BotAddressedToBot(bs, match)) return;\n\t//\n\tif (strlen(bs->subteam)) {\n\t\tBotAI_BotInitialChat(bs, \"inteam\", bs->subteam, NULL);\n\t}\n\telse {\n\t\tBotAI_BotInitialChat(bs, \"noteam\", NULL);\n\t}\n\ttrap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM);\n}\n\n/*\n==================\nBotMatch_CheckPoint\n==================\n*/\nvoid BotMatch_CheckPoint(bot_state_t *bs, bot_match_t *match) {\n\tint areanum, client;\n\tchar buf[MAX_MESSAGE_SIZE];\n\tchar netname[MAX_MESSAGE_SIZE];\n\tvec3_t position;\n\tbot_waypoint_t *cp;\n\n\tif (!TeamPlayIsOn()) return;\n\t//\n\ttrap_BotMatchVariable(match, POSITION, buf, MAX_MESSAGE_SIZE);\n\tVectorClear(position);\n\t//\n\ttrap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));\n\tclient = ClientFromName(netname);\n\t//BotGPSToPosition(buf, position);\n\tsscanf(buf, \"%f %f %f\", &position[0], &position[1], &position[2]);\n\tposition[2] += 0.5;\n\tareanum = BotPointAreaNum(position);\n\tif (!areanum) {\n\t\tif (BotAddressedToBot(bs, match)) {\n\t\t\tBotAI_BotInitialChat(bs, \"checkpoint_invalid\", NULL);\n\t\t\ttrap_BotEnterChat(bs->cs, client, CHAT_TELL);\n\t\t}\n\t\treturn;\n\t}\n\t//\n\ttrap_BotMatchVariable(match, NAME, buf, MAX_MESSAGE_SIZE);\n\t//check if there already exists a checkpoint with this name\n\tcp = BotFindWayPoint(bs->checkpoints, buf);\n\tif (cp) {\n\t\tif (cp->next) cp->next->prev = cp->prev;\n\t\tif (cp->prev) cp->prev->next = cp->next;\n\t\telse bs->checkpoints = cp->next;\n\t\tcp->inuse = qfalse;\n\t}\n\t//create a new check point\n\tcp = BotCreateWayPoint(buf, position, areanum);\n\t//add the check point to the bot's known chech points\n\tcp->next = bs->checkpoints;\n\tif (bs->checkpoints) bs->checkpoints->prev = cp;\n\tbs->checkpoints = cp;\n\t//\n\tif (BotAddressedToBot(bs, match)) {\n\t\tCom_sprintf(buf, sizeof(buf), \"%1.0f %1.0f %1.0f\", cp->goal.origin[0],\n\t\t\t\t\t\t\t\t\t\t\t\t\tcp->goal.origin[1],\n\t\t\t\t\t\t\t\t\t\t\t\t\tcp->goal.origin[2]);\n\n\t\tBotAI_BotInitialChat(bs, \"checkpoint_confirm\", cp->name, buf, NULL);\n\t\ttrap_BotEnterChat(bs->cs, client, CHAT_TELL);\n\t}\n}\n\n/*\n==================\nBotMatch_FormationSpace\n==================\n*/\nvoid BotMatch_FormationSpace(bot_state_t *bs, bot_match_t *match) {\n\tchar buf[MAX_MESSAGE_SIZE];\n\tfloat space;\n\n\tif (!TeamPlayIsOn()) return;\n\t//if not addressed to this bot\n\tif (!BotAddressedToBot(bs, match)) return;\n\t//\n\ttrap_BotMatchVariable(match, NUMBER, buf, MAX_MESSAGE_SIZE);\n\t//if it's the distance in feet\n\tif (match->subtype & ST_FEET) space = 0.3048 * 32 * atof(buf);\n\t//else it's in meters\n\telse space = 32 * atof(buf);\n\t//check if the formation intervening space is valid\n\tif (space < 48 || space > 500) space = 100;\n\tbs->formation_dist = space;\n}\n\n/*\n==================\nBotMatch_Dismiss\n==================\n*/\nvoid BotMatch_Dismiss(bot_state_t *bs, bot_match_t *match) {\n\tchar netname[MAX_MESSAGE_SIZE];\n\tint client;\n\n\tif (!TeamPlayIsOn()) return;\n\t//if not addressed to this bot\n\tif (!BotAddressedToBot(bs, match)) return;\n\ttrap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));\n\tclient = ClientFromName(netname);\n\t//\n\tbs->decisionmaker = client;\n\t//\n\tbs->ltgtype = 0;\n\tbs->lead_time = 0;\n\tbs->lastgoal_ltgtype = 0;\n\t//\n\tBotAI_BotInitialChat(bs, \"dismissed\", NULL);\n\ttrap_BotEnterChat(bs->cs, client, CHAT_TELL);\n}\n\n/*\n==================\nBotMatch_Suicide\n==================\n*/\nvoid BotMatch_Suicide(bot_state_t *bs, bot_match_t *match) {\n\tchar netname[MAX_MESSAGE_SIZE];\n\tint client;\n\n\tif (!TeamPlayIsOn()) return;\n\t//if not addressed to this bot\n\tif (!BotAddressedToBot(bs, match)) return;\n\t//\n\ttrap_EA_Command(bs->client, \"kill\");\n\t//\n\ttrap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));\n\tclient = ClientFromName(netname);\n\t//\n\tBotVoiceChat(bs, client, VOICECHAT_TAUNT);\n\ttrap_EA_Action(bs->client, ACTION_AFFIRMATIVE);\n}\n\n/*\n==================\nBotMatch_StartTeamLeaderShip\n==================\n*/\nvoid BotMatch_StartTeamLeaderShip(bot_state_t *bs, bot_match_t *match) {\n\tint client;\n\tchar teammate[MAX_MESSAGE_SIZE];\n\n\tif (!TeamPlayIsOn()) return;\n\t//if chats for him or herself\n\tif (match->subtype & ST_I) {\n\t\t//get the team mate that will be the team leader\n\t\ttrap_BotMatchVariable(match, NETNAME, teammate, sizeof(teammate));\n\t\tstrncpy(bs->teamleader, teammate, sizeof(bs->teamleader));\n\t\tbs->teamleader[sizeof(bs->teamleader)] = '\\0';\n\t}\n\t//chats for someone else\n\telse {\n\t\t//get the team mate that will be the team leader\n\t\ttrap_BotMatchVariable(match, TEAMMATE, teammate, sizeof(teammate));\n\t\tclient = FindClientByName(teammate);\n\t\tif (client >= 0) ClientName(client, bs->teamleader, sizeof(bs->teamleader));\n\t}\n}\n\n/*\n==================\nBotMatch_StopTeamLeaderShip\n==================\n*/\nvoid BotMatch_StopTeamLeaderShip(bot_state_t *bs, bot_match_t *match) {\n\tint client;\n\tchar teammate[MAX_MESSAGE_SIZE];\n\tchar netname[MAX_MESSAGE_SIZE];\n\n\tif (!TeamPlayIsOn()) return;\n\t//get the team mate that stops being the team leader\n\ttrap_BotMatchVariable(match, TEAMMATE, teammate, sizeof(teammate));\n\t//if chats for him or herself\n\tif (match->subtype & ST_I) {\n\t\ttrap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));\n\t\tclient = FindClientByName(netname);\n\t}\n\t//chats for someone else\n\telse {\n\t\tclient = FindClientByName(teammate);\n\t} //end else\n\tif (client >= 0) {\n\t\tif (!Q_stricmp(bs->teamleader, ClientName(client, netname, sizeof(netname)))) {\n\t\t\tbs->teamleader[0] = '\\0';\n\t\t\tnotleader[client] = qtrue;\n\t\t}\n\t}\n}\n\n/*\n==================\nBotMatch_WhoIsTeamLeader\n==================\n*/\nvoid BotMatch_WhoIsTeamLeader(bot_state_t *bs, bot_match_t *match) {\n\tchar netname[MAX_MESSAGE_SIZE];\n\n\tif (!TeamPlayIsOn()) return;\n\n\tClientName(bs->client, netname, sizeof(netname));\n\t//if this bot IS the team leader\n\tif (!Q_stricmp(netname, bs->teamleader)) {\n\t\ttrap_EA_SayTeam(bs->client, \"I'm the team leader\\n\");\n\t}\n}\n\n/*\n==================\nBotMatch_WhatAreYouDoing\n==================\n*/\nvoid BotMatch_WhatAreYouDoing(bot_state_t *bs, bot_match_t *match) {\n\tchar netname[MAX_MESSAGE_SIZE];\n\tchar goalname[MAX_MESSAGE_SIZE];\n\tint client;\n\n\t//if not addressed to this bot\n\tif (!BotAddressedToBot(bs, match)) return;\n\t//\n\tswitch(bs->ltgtype) {\n\t\tcase LTG_TEAMHELP:\n\t\t{\n\t\t\tEasyClientName(bs->teammate, netname, sizeof(netname));\n\t\t\tBotAI_BotInitialChat(bs, \"helping\", netname, NULL);\n\t\t\tbreak;\n\t\t}\n\t\tcase LTG_TEAMACCOMPANY:\n\t\t{\n\t\t\tEasyClientName(bs->teammate, netname, sizeof(netname));\n\t\t\tBotAI_BotInitialChat(bs, \"accompanying\", netname, NULL);\n\t\t\tbreak;\n\t\t}\n\t\tcase LTG_DEFENDKEYAREA:\n\t\t{\n\t\t\ttrap_BotGoalName(bs->teamgoal.number, goalname, sizeof(goalname));\n\t\t\tBotAI_BotInitialChat(bs, \"defending\", goalname, NULL);\n\t\t\tbreak;\n\t\t}\n\t\tcase LTG_GETITEM:\n\t\t{\n\t\t\ttrap_BotGoalName(bs->teamgoal.number, goalname, sizeof(goalname));\n\t\t\tBotAI_BotInitialChat(bs, \"gettingitem\", goalname, NULL);\n\t\t\tbreak;\n\t\t}\n\t\tcase LTG_KILL:\n\t\t{\n\t\t\tClientName(bs->teamgoal.entitynum, netname, sizeof(netname));\n\t\t\tBotAI_BotInitialChat(bs, \"killing\", netname, NULL);\n\t\t\tbreak;\n\t\t}\n\t\tcase LTG_CAMP:\n\t\tcase LTG_CAMPORDER:\n\t\t{\n\t\t\tBotAI_BotInitialChat(bs, \"camping\", NULL);\n\t\t\tbreak;\n\t\t}\n\t\tcase LTG_PATROL:\n\t\t{\n\t\t\tBotAI_BotInitialChat(bs, \"patrolling\", NULL);\n\t\t\tbreak;\n\t\t}\n\t\tcase LTG_GETFLAG:\n\t\t{\n\t\t\tBotAI_BotInitialChat(bs, \"capturingflag\", NULL);\n\t\t\tbreak;\n\t\t}\n\t\tcase LTG_RUSHBASE:\n\t\t{\n\t\t\tBotAI_BotInitialChat(bs, \"rushingbase\", NULL);\n\t\t\tbreak;\n\t\t}\n\t\tcase LTG_RETURNFLAG:\n\t\t{\n\t\t\tBotAI_BotInitialChat(bs, \"returningflag\", NULL);\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t{\n\t\t\tBotAI_BotInitialChat(bs, \"roaming\", NULL);\n\t\t\tbreak;\n\t\t}\n\t}\n\t//chat what the bot is doing\n\ttrap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));\n\tclient = ClientFromName(netname);\n\ttrap_BotEnterChat(bs->cs, client, CHAT_TELL);\n}\n\n/*\n==================\nBotMatch_WhatIsMyCommand\n==================\n*/\nvoid BotMatch_WhatIsMyCommand(bot_state_t *bs, bot_match_t *match) {\n\tchar netname[MAX_NETNAME];\n\n\tClientName(bs->client, netname, sizeof(netname));\n\tif (Q_stricmp(netname, bs->teamleader) != 0) return;\n\tbs->forceorders = qtrue;\n}\n\n/*\n==================\nBotNearestVisibleItem\n==================\n*/\nfloat BotNearestVisibleItem(bot_state_t *bs, char *itemname, bot_goal_t *goal) {\n\tint i;\n\tchar name[64];\n\tbot_goal_t tmpgoal;\n\tfloat dist, bestdist;\n\tvec3_t dir;\n\tbsp_trace_t trace;\n\n\tbestdist = 999999;\n\ti = -1;\n\tdo {\n\t\ti = trap_BotGetLevelItemGoal(i, itemname, &tmpgoal);\n\t\ttrap_BotGoalName(tmpgoal.number, name, sizeof(name));\n\t\tif (Q_stricmp(itemname, name) != 0)\n\t\t\tcontinue;\n\t\tVectorSubtract(tmpgoal.origin, bs->origin, dir);\n\t\tdist = VectorLength(dir);\n\t\tif (dist < bestdist) {\n\t\t\t//trace from start to end\n\t\t\tBotAI_Trace(&trace, bs->eye, NULL, NULL, tmpgoal.origin, bs->client, CONTENTS_SOLID|CONTENTS_PLAYERCLIP);\n\t\t\tif (trace.fraction >= 1.0) {\n\t\t\t\tbestdist = dist;\n\t\t\t\tmemcpy(goal, &tmpgoal, sizeof(bot_goal_t));\n\t\t\t}\n\t\t}\n\t} while(i > 0);\n\treturn bestdist;\n}\n\n/*\n==================\nBotMatch_WhereAreYou\n==================\n*/\nvoid BotMatch_WhereAreYou(bot_state_t *bs, bot_match_t *match) {\n\tfloat dist, bestdist;\n\tint i, bestitem, redtt, bluett, client;\n\tbot_goal_t goal;\n\tchar netname[MAX_MESSAGE_SIZE];\n\tchar *nearbyitems[] = {\n\t\t\"Shotgun\",\n\t\t\"Grenade Launcher\",\n\t\t\"Rocket Launcher\",\n\t\t\"Plasmagun\",\n\t\t\"Railgun\",\n\t\t\"Lightning Gun\",\n\t\t\"BFG10K\",\n\t\t\"Quad Damage\",\n\t\t\"Regeneration\",\n\t\t\"Battle Suit\",\n\t\t\"Speed\",\n\t\t\"Invisibility\",\n\t\t\"Flight\",\n\t\t\"Armor\",\n\t\t\"Heavy Armor\",\n\t\t\"Red Flag\",\n\t\t\"Blue Flag\",\n\t\tNULL\n\t};\n\t//\n\tif (!TeamPlayIsOn())\n\t\treturn;\n\t//if not addressed to this bot\n\tif (!BotAddressedToBot(bs, match))\n\t\treturn;\n\n\tbestitem = -1;\n\tbestdist = 999999;\n\tfor (i = 0; nearbyitems[i]; i++) {\n\t\tdist = BotNearestVisibleItem(bs, nearbyitems[i], &goal);\n\t\tif (dist < bestdist) {\n\t\t\tbestdist = dist;\n\t\t\tbestitem = i;\n\t\t}\n\t}\n\tif (bestitem != -1) {\n\t\tif (gametype == GT_CTF\n\t\t\t) {\n\t\t\tredtt = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, ctf_redflag.areanum, TFL_DEFAULT);\n\t\t\tbluett = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, ctf_blueflag.areanum, TFL_DEFAULT);\n\t\t\tif (redtt < (redtt + bluett) * 0.4) {\n\t\t\t\tBotAI_BotInitialChat(bs, \"teamlocation\", nearbyitems[bestitem], \"red\", NULL);\n\t\t\t}\n\t\t\telse if (bluett < (redtt + bluett) * 0.4) {\n\t\t\t\tBotAI_BotInitialChat(bs, \"teamlocation\", nearbyitems[bestitem], \"blue\", NULL);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tBotAI_BotInitialChat(bs, \"location\", nearbyitems[bestitem], NULL);\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tBotAI_BotInitialChat(bs, \"location\", nearbyitems[bestitem], NULL);\n\t\t}\n\t\ttrap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));\n\t\tclient = ClientFromName(netname);\n\t\ttrap_BotEnterChat(bs->cs, client, CHAT_TELL);\n\t}\n}\n\n/*\n==================\nBotMatch_LeadTheWay\n==================\n*/\nvoid BotMatch_LeadTheWay(bot_state_t *bs, bot_match_t *match) {\n\taas_entityinfo_t entinfo;\n\tchar netname[MAX_MESSAGE_SIZE], teammate[MAX_MESSAGE_SIZE];\n\tint client, areanum, other;\n\n\tif (!TeamPlayIsOn()) return;\n\t//if not addressed to this bot\n\tif (!BotAddressedToBot(bs, match)) return;\n\t//if someone asks for someone else\n\tif (match->subtype & ST_SOMEONE) {\n\t\t//get the team mate name\n\t\ttrap_BotMatchVariable(match, TEAMMATE, teammate, sizeof(teammate));\n\t\tclient = FindClientByName(teammate);\n\t\t//if this is the bot self\n\t\tif (client == bs->client) {\n\t\t\tother = qfalse;\n\t\t}\n\t\telse if (!BotSameTeam(bs, client)) {\n\t\t\t//FIXME: say \"I don't help the enemy\"\n\t\t\treturn;\n\t\t}\n\t\telse {\n\t\t\tother = qtrue;\n\t\t}\n\t}\n\telse {\n\t\t//get the netname\n\t\ttrap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));\n\t\tclient = ClientFromName(netname);\n\t\tother = qfalse;\n\t}\n\t//if the bot doesn't know who to help (FindClientByName returned -1)\n\tif (client < 0) {\n\t\tBotAI_BotInitialChat(bs, \"whois\", netname, NULL);\n\t\ttrap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM);\n\t\treturn;\n\t}\n\t//\n\tbs->lead_teamgoal.entitynum = -1;\n\tBotEntityInfo(client, &entinfo);\n\t//if info is valid (in PVS)\n\tif (entinfo.valid) {\n\t\tareanum = BotPointAreaNum(entinfo.origin);\n\t\tif (areanum) { // && trap_AAS_AreaReachability(areanum)) {\n\t\t\tbs->lead_teamgoal.entitynum = client;\n\t\t\tbs->lead_teamgoal.areanum = areanum;\n\t\t\tVectorCopy(entinfo.origin, bs->lead_teamgoal.origin);\n\t\t\tVectorSet(bs->lead_teamgoal.mins, -8, -8, -8);\n\t\t\tVectorSet(bs->lead_teamgoal.maxs, 8, 8, 8);\n\t\t}\n\t}\n\n\tif (bs->teamgoal.entitynum < 0) {\n\t\tif (other) BotAI_BotInitialChat(bs, \"whereis\", teammate, NULL);\n\t\telse BotAI_BotInitialChat(bs, \"whereareyou\", netname, NULL);\n\t\ttrap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM);\n\t\treturn;\n\t}\n\tbs->lead_teammate = client;\n\tbs->lead_time = FloatTime() + TEAM_LEAD_TIME;\n\tbs->leadvisible_time = 0;\n\tbs->leadmessage_time = -(FloatTime() + 2 * random());\n}\n\n/*\n==================\nBotMatch_Kill\n==================\n*/\nvoid BotMatch_Kill(bot_state_t *bs, bot_match_t *match) {\n\tchar enemy[MAX_MESSAGE_SIZE];\n\tchar netname[MAX_MESSAGE_SIZE];\n\tint client;\n\n\tif (!TeamPlayIsOn()) return;\n\t//if not addressed to this bot\n\tif (!BotAddressedToBot(bs, match)) return;\n\n\ttrap_BotMatchVariable(match, ENEMY, enemy, sizeof(enemy));\n\t//\n\tclient = FindEnemyByName(bs, enemy);\n\tif (client < 0) {\n\t\tBotAI_BotInitialChat(bs, \"whois\", enemy, NULL);\n\t\ttrap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));\n\t\tclient = ClientFromName(netname);\n\t\ttrap_BotEnterChat(bs->cs, client, CHAT_TELL);\n\t\treturn;\n\t}\n\tbs->teamgoal.entitynum = client;\n\t//set the time to send a message to the team mates\n\tbs->teammessage_time = FloatTime() + 2 * random();\n\t//set the ltg type\n\tbs->ltgtype = LTG_KILL;\n\t//set the team goal time\n\tbs->teamgoal_time = FloatTime() + TEAM_KILL_SOMEONE;\n\t//\n\tBotSetTeamStatus(bs);\n#ifdef DEBUG\n\tBotPrintTeamGoal(bs);\n#endif //DEBUG\n}\n\n/*\n==================\nBotMatch_CTF\n==================\n*/\nvoid BotMatch_CTF(bot_state_t *bs, bot_match_t *match) {\n\n\tchar flag[128], netname[MAX_NETNAME];\n\n\tif (gametype == GT_CTF) {\n\t\ttrap_BotMatchVariable(match, FLAG, flag, sizeof(flag));\n\t\tif (match->subtype & ST_GOTFLAG) {\n\t\t\tif (!Q_stricmp(flag, \"red\")) {\n\t\t\t\tbs->redflagstatus = 1;\n\t\t\t\tif (BotTeam(bs) == TEAM_BLUE) {\n\t\t\t\t\ttrap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));\n\t\t\t\t\tbs->flagcarrier = ClientFromName(netname);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tbs->blueflagstatus = 1;\n\t\t\t\tif (BotTeam(bs) == TEAM_RED) {\n\t\t\t\t\ttrap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));\n\t\t\t\t\tbs->flagcarrier = ClientFromName(netname);\n\t\t\t\t}\n\t\t\t}\n\t\t\tbs->flagstatuschanged = 1;\n\t\t\tbs->lastflagcapture_time = FloatTime();\n\t\t}\n\t\telse if (match->subtype & ST_CAPTUREDFLAG) {\n\t\t\tbs->redflagstatus = 0;\n\t\t\tbs->blueflagstatus = 0;\n\t\t\tbs->flagcarrier = 0;\n\t\t\tbs->flagstatuschanged = 1;\n\t\t}\n\t\telse if (match->subtype & ST_RETURNEDFLAG) {\n\t\t\tif (!Q_stricmp(flag, \"red\")) bs->redflagstatus = 0;\n\t\t\telse bs->blueflagstatus = 0;\n\t\t\tbs->flagstatuschanged = 1;\n\t\t}\n\t}\n}\n\nvoid BotMatch_EnterGame(bot_state_t *bs, bot_match_t *match) {\n\tint client;\n\tchar netname[MAX_NETNAME];\n\n\ttrap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));\n\tclient = FindClientByName(netname);\n\tif (client >= 0) {\n\t\tnotleader[client] = qfalse;\n\t}\n\t//NOTE: eliza chats will catch this\n\t//Com_sprintf(buf, sizeof(buf), \"heya %s\", netname);\n\t//EA_Say(bs->client, buf);\n}\n\nvoid BotMatch_NewLeader(bot_state_t *bs, bot_match_t *match) {\n\tint client;\n\tchar netname[MAX_NETNAME];\n\n\ttrap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));\n\tclient = FindClientByName(netname);\n\tif (!BotSameTeam(bs, client))\n\t\treturn;\n\tQ_strncpyz(bs->teamleader, netname, sizeof(bs->teamleader));\n}\n\n/*\n==================\nBotMatchMessage\n==================\n*/\nint BotMatchMessage(bot_state_t *bs, char *message) {\n\tbot_match_t match;\n\n\tmatch.type = 0;\n\t//if it is an unknown message\n\tif (!trap_BotFindMatch(message, &match, MTCONTEXT_MISC\n\t\t\t\t\t\t\t\t\t\t\t|MTCONTEXT_INITIALTEAMCHAT\n\t\t\t\t\t\t\t\t\t\t\t|MTCONTEXT_CTF)) {\n\t\treturn qfalse;\n\t}\n\t//react to the found message\n\tswitch(match.type)\n\t{\n\t\tcase MSG_HELP:\t\t\t\t\t//someone calling for help\n\t\tcase MSG_ACCOMPANY:\t\t\t\t//someone calling for company\n\t\t{\n\t\t\tBotMatch_HelpAccompany(bs, &match);\n\t\t\tbreak;\n\t\t}\n\t\tcase MSG_DEFENDKEYAREA:\t\t\t//teamplay defend a key area\n\t\t{\n\t\t\tBotMatch_DefendKeyArea(bs, &match);\n\t\t\tbreak;\n\t\t}\n\t\tcase MSG_CAMP:\t\t\t\t\t//camp somewhere\n\t\t{\n\t\t\tBotMatch_Camp(bs, &match);\n\t\t\tbreak;\n\t\t}\n\t\tcase MSG_PATROL:\t\t\t\t//patrol between several key areas\n\t\t{\n\t\t\tBotMatch_Patrol(bs, &match);\n\t\t\tbreak;\n\t\t}\n\t\t//CTF & 1FCTF\n\t\tcase MSG_GETFLAG:\t\t\t\t//ctf get the enemy flag\n\t\t{\n\t\t\tBotMatch_GetFlag(bs, &match);\n\t\t\tbreak;\n\t\t}\n\t\t//CTF & 1FCTF & Harvester\n\t\tcase MSG_RUSHBASE:\t\t\t\t//ctf rush to the base\n\t\t{\n\t\t\tBotMatch_RushBase(bs, &match);\n\t\t\tbreak;\n\t\t}\n\t\t//CTF & 1FCTF\n\t\tcase MSG_RETURNFLAG:\n\t\t{\n\t\t\tBotMatch_ReturnFlag(bs, &match);\n\t\t\tbreak;\n\t\t}\n\t\t//CTF & 1FCTF & Obelisk & Harvester\n\t\tcase MSG_TASKPREFERENCE:\n\t\t{\n\t\t\tBotMatch_TaskPreference(bs, &match);\n\t\t\tbreak;\n\t\t}\n\t\t//CTF & 1FCTF\n\t\tcase MSG_CTF:\n\t\t{\n\t\t\tBotMatch_CTF(bs, &match);\n\t\t\tbreak;\n\t\t}\n\t\tcase MSG_GETITEM:\n\t\t{\n\t\t\tBotMatch_GetItem(bs, &match);\n\t\t\tbreak;\n\t\t}\n\t\tcase MSG_JOINSUBTEAM:\t\t\t//join a sub team\n\t\t{\n\t\t\tBotMatch_JoinSubteam(bs, &match);\n\t\t\tbreak;\n\t\t}\n\t\tcase MSG_LEAVESUBTEAM:\t\t\t//leave a sub team\n\t\t{\n\t\t\tBotMatch_LeaveSubteam(bs, &match);\n\t\t\tbreak;\n\t\t}\n\t\tcase MSG_WHICHTEAM:\n\t\t{\n\t\t\tBotMatch_WhichTeam(bs, &match);\n\t\t\tbreak;\n\t\t}\n\t\tcase MSG_CHECKPOINT:\t\t\t//remember a check point\n\t\t{\n\t\t\tBotMatch_CheckPoint(bs, &match);\n\t\t\tbreak;\n\t\t}\n\t\tcase MSG_CREATENEWFORMATION:\t//start the creation of a new formation\n\t\t{\n\t\t\ttrap_EA_SayTeam(bs->client, \"the part of my brain to create formations has been damaged\");\n\t\t\tbreak;\n\t\t}\n\t\tcase MSG_FORMATIONPOSITION:\t\t//tell someone his/her position in the formation\n\t\t{\n\t\t\ttrap_EA_SayTeam(bs->client, \"the part of my brain to create formations has been damaged\");\n\t\t\tbreak;\n\t\t}\n\t\tcase MSG_FORMATIONSPACE:\t\t//set the formation space\n\t\t{\n\t\t\tBotMatch_FormationSpace(bs, &match);\n\t\t\tbreak;\n\t\t}\n\t\tcase MSG_DOFORMATION:\t\t\t//form a certain formation\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t\tcase MSG_DISMISS:\t\t\t\t//dismiss someone\n\t\t{\n\t\t\tBotMatch_Dismiss(bs, &match);\n\t\t\tbreak;\n\t\t}\n\t\tcase MSG_STARTTEAMLEADERSHIP:\t//someone will become the team leader\n\t\t{\n\t\t\tBotMatch_StartTeamLeaderShip(bs, &match);\n\t\t\tbreak;\n\t\t}\n\t\tcase MSG_STOPTEAMLEADERSHIP:\t//someone will stop being the team leader\n\t\t{\n\t\t\tBotMatch_StopTeamLeaderShip(bs, &match);\n\t\t\tbreak;\n\t\t}\n\t\tcase MSG_WHOISTEAMLAEDER:\n\t\t{\n\t\t\tBotMatch_WhoIsTeamLeader(bs, &match);\n\t\t\tbreak;\n\t\t}\n\t\tcase MSG_WHATAREYOUDOING:\t\t//ask a bot what he/she is doing\n\t\t{\n\t\t\tBotMatch_WhatAreYouDoing(bs, &match);\n\t\t\tbreak;\n\t\t}\n\t\tcase MSG_WHATISMYCOMMAND:\n\t\t{\n\t\t\tBotMatch_WhatIsMyCommand(bs, &match);\n\t\t\tbreak;\n\t\t}\n\t\tcase MSG_WHEREAREYOU:\n\t\t{\n\t\t\tBotMatch_WhereAreYou(bs, &match);\n\t\t\tbreak;\n\t\t}\n\t\tcase MSG_LEADTHEWAY:\n\t\t{\n\t\t\tBotMatch_LeadTheWay(bs, &match);\n\t\t\tbreak;\n\t\t}\n\t\tcase MSG_KILL:\n\t\t{\n\t\t\tBotMatch_Kill(bs, &match);\n\t\t\tbreak;\n\t\t}\n\t\tcase MSG_ENTERGAME:\t\t\t\t//someone entered the game\n\t\t{\n\t\t\tBotMatch_EnterGame(bs, &match);\n\t\t\tbreak;\n\t\t}\n\t\tcase MSG_NEWLEADER:\n\t\t{\n\t\t\tBotMatch_NewLeader(bs, &match);\n\t\t\tbreak;\n\t\t}\n\t\tcase MSG_WAIT:\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t\tcase MSG_SUICIDE:\n\t\t{\n\t\t\tBotMatch_Suicide(bs, &match);\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t{\n\t\t\tBotAI_Print(PRT_MESSAGE, \"unknown match type\\n\");\n\t\t\tbreak;\n\t\t}\n\t}\n\treturn qtrue;\n}\n"
  },
  {
    "path": "src/game/ai_cmd.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n\n/*****************************************************************************\n * name:\t\tai_cmd.h\n *\n * desc:\t\tQuake3 bot AI\n *\n * $Archive: /source/code/botai/ai_chat.c $\n *\n *****************************************************************************/\n\nextern int notleader[MAX_CLIENTS];\n\nint BotMatchMessage(bot_state_t *bs, char *message);\nvoid BotPrintTeamGoal(bot_state_t *bs);\n\n"
  },
  {
    "path": "src/game/ai_dmnet.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n\n/*****************************************************************************\n * name:\t\tai_dmnet.c\n *\n * desc:\t\tQuake3 bot AI\n *\n * $Archive: /MissionPack/code/game/ai_dmnet.c $\n *\n *****************************************************************************/\n\n#include \"g_local.h\"\n#include \"botlib.h\"\n#include \"be_aas.h\"\n#include \"be_ea.h\"\n#include \"be_ai_char.h\"\n#include \"be_ai_chat.h\"\n#include \"be_ai_gen.h\"\n#include \"be_ai_goal.h\"\n#include \"be_ai_move.h\"\n#include \"be_ai_weap.h\"\n//\n#include \"ai_main.h\"\n#include \"ai_dmq3.h\"\n#include \"ai_chat.h\"\n#include \"ai_cmd.h\"\n#include \"ai_dmnet.h\"\n#include \"ai_team.h\"\n//data file headers\n#include \"chars.h\"\t\t\t//characteristics\n#include \"inv.h\"\t\t\t//indexes into the inventory\n#include \"syn.h\"\t\t\t//synonyms\n#include \"match.h\"\t\t\t//string matching types and vars\n\n// for the voice chats\n#include \"menudef.h\"\n\n//goal flag, see be_ai_goal.h for the other GFL_*\n#define GFL_AIR\t\t\t128\n\nint numnodeswitches;\nchar nodeswitch[MAX_NODESWITCHES+1][144];\n\n#define LOOKAHEAD_DISTANCE\t\t\t300\n\n/*\n==================\nBotResetNodeSwitches\n==================\n*/\nvoid BotResetNodeSwitches(void) {\n\tnumnodeswitches = 0;\n}\n\n/*\n==================\nBotDumpNodeSwitches\n==================\n*/\nvoid BotDumpNodeSwitches(bot_state_t *bs) {\n\tint i;\n\tchar netname[MAX_NETNAME];\n\n\tClientName(bs->client, netname, sizeof(netname));\n\tBotAI_Print(PRT_MESSAGE, \"%s at %1.1f switched more than %d AI nodes\\n\", netname, FloatTime(), MAX_NODESWITCHES);\n\tfor (i = 0; i < numnodeswitches; i++) {\n\t\tBotAI_Print(PRT_MESSAGE, nodeswitch[i]);\n\t}\n\tBotAI_Print(PRT_FATAL, \"\");\n}\n\n/*\n==================\nBotRecordNodeSwitch\n==================\n*/\nvoid BotRecordNodeSwitch(bot_state_t *bs, char *node, char *str, char *s) {\n\tchar netname[MAX_NETNAME];\n\n\tClientName(bs->client, netname, sizeof(netname));\n\tCom_sprintf(nodeswitch[numnodeswitches], 144, \"%s at %2.1f entered %s: %s from %s\\n\", netname, FloatTime(), node, str, s);\n#ifdef DEBUG\n\tif (0) {\n\t\tBotAI_Print(PRT_MESSAGE, nodeswitch[numnodeswitches]);\n\t}\n#endif //DEBUG\n\tnumnodeswitches++;\n}\n\n/*\n==================\nBotGetAirGoal\n==================\n*/\nint BotGetAirGoal(bot_state_t *bs, bot_goal_t *goal) {\n\tbsp_trace_t bsptrace;\n\tvec3_t end, mins = {-15, -15, -2}, maxs = {15, 15, 2};\n\tint areanum;\n\n\t//trace up until we hit solid\n\tVectorCopy(bs->origin, end);\n\tend[2] += 1000;\n\tBotAI_Trace(&bsptrace, bs->origin, mins, maxs, end, bs->entitynum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP);\n\t//trace down until we hit water\n\tVectorCopy(bsptrace.endpos, end);\n\tBotAI_Trace(&bsptrace, end, mins, maxs, bs->origin, bs->entitynum, CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA);\n\t//if we found the water surface\n\tif (bsptrace.fraction > 0) {\n\t\tareanum = BotPointAreaNum(bsptrace.endpos);\n\t\tif (areanum) {\n\t\t\tVectorCopy(bsptrace.endpos, goal->origin);\n\t\t\tgoal->origin[2] -= 2;\n\t\t\tgoal->areanum = areanum;\n\t\t\tgoal->mins[0] = -15;\n\t\t\tgoal->mins[1] = -15;\n\t\t\tgoal->mins[2] = -1;\n\t\t\tgoal->maxs[0] = 15;\n\t\t\tgoal->maxs[1] = 15;\n\t\t\tgoal->maxs[2] = 1;\n\t\t\tgoal->flags = GFL_AIR;\n\t\t\tgoal->number = 0;\n\t\t\tgoal->iteminfo = 0;\n\t\t\tgoal->entitynum = 0;\n\t\t\treturn qtrue;\n\t\t}\n\t}\n\treturn qfalse;\n}\n\n/*\n==================\nBotGoForAir\n==================\n*/\nint BotGoForAir(bot_state_t *bs, int tfl, bot_goal_t *ltg, float range) {\n\tbot_goal_t goal;\n\n\t//if the bot needs air\n\tif (bs->lastair_time < FloatTime() - 6) {\n\t\t//\n#ifdef DEBUG\n\t\t//BotAI_Print(PRT_MESSAGE, \"going for air\\n\");\n#endif //DEBUG\n\t\t//if we can find an air goal\n\t\tif (BotGetAirGoal(bs, &goal)) {\n\t\t\ttrap_BotPushGoal(bs->gs, &goal);\n\t\t\treturn qtrue;\n\t\t}\n\t\telse {\n\t\t\t//get a nearby goal outside the water\n\t\t\twhile(trap_BotChooseNBGItem(bs->gs, bs->origin, bs->inventory, tfl, ltg, range)) {\n\t\t\t\ttrap_BotGetTopGoal(bs->gs, &goal);\n\t\t\t\t//if the goal is not in water\n\t\t\t\tif (!(trap_AAS_PointContents(goal.origin) & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA))) {\n\t\t\t\t\treturn qtrue;\n\t\t\t\t}\n\t\t\t\ttrap_BotPopGoal(bs->gs);\n\t\t\t}\n\t\t\ttrap_BotResetAvoidGoals(bs->gs);\n\t\t}\n\t}\n\treturn qfalse;\n}\n\n/*\n==================\nBotNearbyGoal\n==================\n*/\nint BotNearbyGoal(bot_state_t *bs, int tfl, bot_goal_t *ltg, float range) {\n\tint ret;\n\n\t//check if the bot should go for air\n\tif (BotGoForAir(bs, tfl, ltg, range)) return qtrue;\n\t//if the bot is carrying the enemy flag\n\tif (BotCTFCarryingFlag(bs)) {\n\t\t//if the bot is just a few secs away from the base \n\t\tif (trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin,\n\t\t\t\tbs->teamgoal.areanum, TFL_DEFAULT) < 300) {\n\t\t\t//make the range really small\n\t\t\trange = 50;\n\t\t}\n\t}\n\t//\n\tret = trap_BotChooseNBGItem(bs->gs, bs->origin, bs->inventory, tfl, ltg, range);\n\t/*\n\tif (ret)\n\t{\n\t\tchar buf[128];\n\t\t//get the goal at the top of the stack\n\t\ttrap_BotGetTopGoal(bs->gs, &goal);\n\t\ttrap_BotGoalName(goal.number, buf, sizeof(buf));\n\t\tBotAI_Print(PRT_MESSAGE, \"%1.1f: new nearby goal %s\\n\", FloatTime(), buf);\n\t}\n    */\n\treturn ret;\n}\n\n/*\n==================\nBotReachedGoal\n==================\n*/\nint BotReachedGoal(bot_state_t *bs, bot_goal_t *goal) {\n\tif (goal->flags & GFL_ITEM) {\n\t\t//if touching the goal\n\t\tif (trap_BotTouchingGoal(bs->origin, goal)) {\n\t\t\tif (!(goal->flags & GFL_DROPPED)) {\n\t\t\t\ttrap_BotSetAvoidGoalTime(bs->gs, goal->number, -1);\n\t\t\t}\n\t\t\treturn qtrue;\n\t\t}\n\t\t//if the goal isn't there\n\t\tif (trap_BotItemGoalInVisButNotVisible(bs->entitynum, bs->eye, bs->viewangles, goal)) {\n\t\t\t/*\n\t\t\tfloat avoidtime;\n\t\t\tint t;\n\n\t\t\tavoidtime = trap_BotAvoidGoalTime(bs->gs, goal->number);\n\t\t\tif (avoidtime > 0) {\n\t\t\t\tt = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, goal->areanum, bs->tfl);\n\t\t\t\tif ((float) t * 0.009 < avoidtime)\n\t\t\t\t\treturn qtrue;\n\t\t\t}\n\t\t\t*/\n\t\t\treturn qtrue;\n\t\t}\n\t\t//if in the goal area and below or above the goal and not swimming\n\t\tif (bs->areanum == goal->areanum) {\n\t\t\tif (bs->origin[0] > goal->origin[0] + goal->mins[0] && bs->origin[0] < goal->origin[0] + goal->maxs[0]) {\n\t\t\t\tif (bs->origin[1] > goal->origin[1] + goal->mins[1] && bs->origin[1] < goal->origin[1] + goal->maxs[1]) {\n\t\t\t\t\tif (!trap_AAS_Swimming(bs->origin)) {\n\t\t\t\t\t\treturn qtrue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\telse if (goal->flags & GFL_AIR) {\n\t\t//if touching the goal\n\t\tif (trap_BotTouchingGoal(bs->origin, goal)) return qtrue;\n\t\t//if the bot got air\n\t\tif (bs->lastair_time > FloatTime() - 1) return qtrue;\n\t}\n\telse {\n\t\t//if touching the goal\n\t\tif (trap_BotTouchingGoal(bs->origin, goal)) return qtrue;\n\t}\n\treturn qfalse;\n}\n\n/*\n==================\nBotGetItemLongTermGoal\n==================\n*/\nint BotGetItemLongTermGoal(bot_state_t *bs, int tfl, bot_goal_t *goal) {\n\t//if the bot has no goal\n\tif (!trap_BotGetTopGoal(bs->gs, goal)) {\n\t\t//BotAI_Print(PRT_MESSAGE, \"no ltg on stack\\n\");\n\t\tbs->ltg_time = 0;\n\t}\n\t//if the bot touches the current goal\n\telse if (BotReachedGoal(bs, goal)) {\n\t\tBotChooseWeapon(bs);\n\t\tbs->ltg_time = 0;\n\t}\n\t//if it is time to find a new long term goal\n\tif (bs->ltg_time < FloatTime()) {\n\t\t//pop the current goal from the stack\n\t\ttrap_BotPopGoal(bs->gs);\n\t\t//BotAI_Print(PRT_MESSAGE, \"%s: choosing new ltg\\n\", ClientName(bs->client, netname, sizeof(netname)));\n\t\t//choose a new goal\n\t\t//BotAI_Print(PRT_MESSAGE, \"%6.1f client %d: BotChooseLTGItem\\n\", FloatTime(), bs->client);\n\t\tif (trap_BotChooseLTGItem(bs->gs, bs->origin, bs->inventory, tfl)) {\n\t\t\t/*\n\t\t\tchar buf[128];\n\t\t\t//get the goal at the top of the stack\n\t\t\ttrap_BotGetTopGoal(bs->gs, goal);\n\t\t\ttrap_BotGoalName(goal->number, buf, sizeof(buf));\n\t\t\tBotAI_Print(PRT_MESSAGE, \"%1.1f: new long term goal %s\\n\", FloatTime(), buf);\n            */\n\t\t\tbs->ltg_time = FloatTime() + 20;\n\t\t}\n\t\telse {//the bot gets sorta stuck with all the avoid timings, shouldn't happen though\n\t\t\t//\n#ifdef DEBUG\n\t\t\tchar netname[128];\n\n\t\t\tBotAI_Print(PRT_MESSAGE, \"%s: no valid ltg (probably stuck)\\n\", ClientName(bs->client, netname, sizeof(netname)));\n#endif\n\t\t\t//trap_BotDumpAvoidGoals(bs->gs);\n\t\t\t//reset the avoid goals and the avoid reach\n\t\t\ttrap_BotResetAvoidGoals(bs->gs);\n\t\t\ttrap_BotResetAvoidReach(bs->ms);\n\t\t}\n\t\t//get the goal at the top of the stack\n\t\treturn trap_BotGetTopGoal(bs->gs, goal);\n\t}\n\treturn qtrue;\n}\n\n/*\n==================\nBotGetLongTermGoal\n\nwe could also create a seperate AI node for every long term goal type\nhowever this saves us a lot of code\n==================\n*/\nint BotGetLongTermGoal(bot_state_t *bs, int tfl, int retreat, bot_goal_t *goal) {\n\tvec3_t target, dir, dir2;\n\tchar netname[MAX_NETNAME];\n\tchar buf[MAX_MESSAGE_SIZE];\n\tint areanum;\n\tfloat croucher;\n\taas_entityinfo_t entinfo, botinfo;\n\tbot_waypoint_t *wp;\n\n\tif (bs->ltgtype == LTG_TEAMHELP && !retreat) {\n\t\t//check for bot typing status message\n\t\tif (bs->teammessage_time && bs->teammessage_time < FloatTime()) {\n\t\t\tBotAI_BotInitialChat(bs, \"help_start\", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL);\n\t\t\ttrap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);\n\t\t\tBotVoiceChatOnly(bs, bs->decisionmaker, VOICECHAT_YES);\n\t\t\ttrap_EA_Action(bs->client, ACTION_AFFIRMATIVE);\n\t\t\tbs->teammessage_time = 0;\n\t\t}\n\t\t//if trying to help the team mate for more than a minute\n\t\tif (bs->teamgoal_time < FloatTime())\n\t\t\tbs->ltgtype = 0;\n\t\t//if the team mate IS visible for quite some time\n\t\tif (bs->teammatevisible_time < FloatTime() - 10) bs->ltgtype = 0;\n\t\t//get entity information of the companion\n\t\tBotEntityInfo(bs->teammate, &entinfo);\n\t\t//if the team mate is visible\n\t\tif (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->teammate)) {\n\t\t\t//if close just stand still there\n\t\t\tVectorSubtract(entinfo.origin, bs->origin, dir);\n\t\t\tif (VectorLengthSquared(dir) < Square(100)) {\n\t\t\t\ttrap_BotResetAvoidReach(bs->ms);\n\t\t\t\treturn qfalse;\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\t//last time the bot was NOT visible\n\t\t\tbs->teammatevisible_time = FloatTime();\n\t\t}\n\t\t//if the entity information is valid (entity in PVS)\n\t\tif (entinfo.valid) {\n\t\t\tareanum = BotPointAreaNum(entinfo.origin);\n\t\t\tif (areanum && trap_AAS_AreaReachability(areanum)) {\n\t\t\t\t//update team goal\n\t\t\t\tbs->teamgoal.entitynum = bs->teammate;\n\t\t\t\tbs->teamgoal.areanum = areanum;\n\t\t\t\tVectorCopy(entinfo.origin, bs->teamgoal.origin);\n\t\t\t\tVectorSet(bs->teamgoal.mins, -8, -8, -8);\n\t\t\t\tVectorSet(bs->teamgoal.maxs, 8, 8, 8);\n\t\t\t}\n\t\t}\n\t\tmemcpy(goal, &bs->teamgoal, sizeof(bot_goal_t));\n\t\treturn qtrue;\n\t}\n\t//if the bot accompanies someone\n\tif (bs->ltgtype == LTG_TEAMACCOMPANY && !retreat) {\n\t\t//check for bot typing status message\n\t\tif (bs->teammessage_time && bs->teammessage_time < FloatTime()) {\n\t\t\tBotAI_BotInitialChat(bs, \"accompany_start\", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL);\n\t\t\ttrap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);\n\t\t\tBotVoiceChatOnly(bs, bs->decisionmaker, VOICECHAT_YES);\n\t\t\ttrap_EA_Action(bs->client, ACTION_AFFIRMATIVE);\n\t\t\tbs->teammessage_time = 0;\n\t\t}\n\t\t//if accompanying the companion for 3 minutes\n\t\tif (bs->teamgoal_time < FloatTime()) {\n\t\t\tBotAI_BotInitialChat(bs, \"accompany_stop\", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL);\n\t\t\ttrap_BotEnterChat(bs->cs, bs->teammate, CHAT_TELL);\n\t\t\tbs->ltgtype = 0;\n\t\t}\n\t\t//get entity information of the companion\n\t\tBotEntityInfo(bs->teammate, &entinfo);\n\t\t//if the companion is visible\n\t\tif (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->teammate)) {\n\t\t\t//update visible time\n\t\t\tbs->teammatevisible_time = FloatTime();\n\t\t\tVectorSubtract(entinfo.origin, bs->origin, dir);\n\t\t\tif (VectorLengthSquared(dir) < Square(bs->formation_dist)) {\n\t\t\t\t//\n\t\t\t\t// if the client being followed bumps into this bot then\n\t\t\t\t// the bot should back up\n\t\t\t\tBotEntityInfo(bs->entitynum, &botinfo);\n\t\t\t\t// if the followed client is not standing ontop of the bot\n\t\t\t\tif (botinfo.origin[2] + botinfo.maxs[2] > entinfo.origin[2] + entinfo.mins[2]) {\n\t\t\t\t\t// if the bounding boxes touch each other\n\t\t\t\t\tif (botinfo.origin[0] + botinfo.maxs[0] > entinfo.origin[0] + entinfo.mins[0] - 4&&\n\t\t\t\t\t\tbotinfo.origin[0] + botinfo.mins[0] < entinfo.origin[0] + entinfo.maxs[0] + 4) {\n\t\t\t\t\t\tif (botinfo.origin[1] + botinfo.maxs[1] > entinfo.origin[1] + entinfo.mins[1] - 4 &&\n\t\t\t\t\t\t\tbotinfo.origin[1] + botinfo.mins[1] < entinfo.origin[1] + entinfo.maxs[1] + 4) {\n\t\t\t\t\t\t\tif (botinfo.origin[2] + botinfo.maxs[2] > entinfo.origin[2] + entinfo.mins[2] - 4 &&\n\t\t\t\t\t\t\t\tbotinfo.origin[2] + botinfo.mins[2] < entinfo.origin[2] + entinfo.maxs[2] + 4) {\n\t\t\t\t\t\t\t\t// if the followed client looks in the direction of this bot\n\t\t\t\t\t\t\t\tAngleVectors(entinfo.angles, dir, NULL, NULL);\n\t\t\t\t\t\t\t\tdir[2] = 0;\n\t\t\t\t\t\t\t\tVectorNormalize(dir);\n\t\t\t\t\t\t\t\t//VectorSubtract(entinfo.origin, entinfo.lastvisorigin, dir);\n\t\t\t\t\t\t\t\tVectorSubtract(bs->origin, entinfo.origin, dir2);\n\t\t\t\t\t\t\t\tVectorNormalize(dir2);\n\t\t\t\t\t\t\t\tif (DotProduct(dir, dir2) > 0.7) {\n\t\t\t\t\t\t\t\t\t// back up\n\t\t\t\t\t\t\t\t\tBotSetupForMovement(bs);\n\t\t\t\t\t\t\t\t\ttrap_BotMoveInDirection(bs->ms, dir2, 400, MOVE_WALK);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t//check if the bot wants to crouch\n\t\t\t\t//don't crouch if crouched less than 5 seconds ago\n\t\t\t\tif (bs->attackcrouch_time < FloatTime() - 5) {\n\t\t\t\t\tcroucher = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CROUCHER, 0, 1);\n\t\t\t\t\tif (random() < bs->thinktime * croucher) {\n\t\t\t\t\t\tbs->attackcrouch_time = FloatTime() + 5 + croucher * 15;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t//don't crouch when swimming\n\t\t\t\tif (trap_AAS_Swimming(bs->origin)) bs->attackcrouch_time = FloatTime() - 1;\n\t\t\t\t//if not arrived yet or arived some time ago\n\t\t\t\tif (bs->arrive_time < FloatTime() - 2) {\n\t\t\t\t\t//if not arrived yet\n\t\t\t\t\tif (!bs->arrive_time) {\n\t\t\t\t\t\ttrap_EA_Gesture(bs->client);\n\t\t\t\t\t\tBotAI_BotInitialChat(bs, \"accompany_arrive\", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL);\n\t\t\t\t\t\ttrap_BotEnterChat(bs->cs, bs->teammate, CHAT_TELL);\n\t\t\t\t\t\tbs->arrive_time = FloatTime();\n\t\t\t\t\t}\n\t\t\t\t\t//if the bot wants to crouch\n\t\t\t\t\telse if (bs->attackcrouch_time > FloatTime()) {\n\t\t\t\t\t\ttrap_EA_Crouch(bs->client);\n\t\t\t\t\t}\n\t\t\t\t\t//else do some model taunts\n\t\t\t\t\telse if (random() < bs->thinktime * 0.05) {\n\t\t\t\t\t\t//do a gesture :)\n\t\t\t\t\t\ttrap_EA_Gesture(bs->client);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t//if just arrived look at the companion\n\t\t\t\tif (bs->arrive_time > FloatTime() - 2) {\n\t\t\t\t\tVectorSubtract(entinfo.origin, bs->origin, dir);\n\t\t\t\t\tvectoangles(dir, bs->ideal_viewangles);\n\t\t\t\t\tbs->ideal_viewangles[2] *= 0.5;\n\t\t\t\t}\n\t\t\t\t//else look strategically around for enemies\n\t\t\t\telse if (random() < bs->thinktime * 0.8) {\n\t\t\t\t\tBotRoamGoal(bs, target);\n\t\t\t\t\tVectorSubtract(target, bs->origin, dir);\n\t\t\t\t\tvectoangles(dir, bs->ideal_viewangles);\n\t\t\t\t\tbs->ideal_viewangles[2] *= 0.5;\n\t\t\t\t}\n\t\t\t\t//check if the bot wants to go for air\n\t\t\t\tif (BotGoForAir(bs, bs->tfl, &bs->teamgoal, 400)) {\n\t\t\t\t\ttrap_BotResetLastAvoidReach(bs->ms);\n\t\t\t\t\t//get the goal at the top of the stack\n\t\t\t\t\t//trap_BotGetTopGoal(bs->gs, &tmpgoal);\n\t\t\t\t\t//trap_BotGoalName(tmpgoal.number, buf, 144);\n\t\t\t\t\t//BotAI_Print(PRT_MESSAGE, \"new nearby goal %s\\n\", buf);\n\t\t\t\t\t//time the bot gets to pick up the nearby goal item\n\t\t\t\t\tbs->nbg_time = FloatTime() + 8;\n\t\t\t\t\tAIEnter_Seek_NBG(bs, \"BotLongTermGoal: go for air\");\n\t\t\t\t\treturn qfalse;\n\t\t\t\t}\n\t\t\t\t//\n\t\t\t\ttrap_BotResetAvoidReach(bs->ms);\n\t\t\t\treturn qfalse;\n\t\t\t}\n\t\t}\n\t\t//if the entity information is valid (entity in PVS)\n\t\tif (entinfo.valid) {\n\t\t\tareanum = BotPointAreaNum(entinfo.origin);\n\t\t\tif (areanum && trap_AAS_AreaReachability(areanum)) {\n\t\t\t\t//update team goal\n\t\t\t\tbs->teamgoal.entitynum = bs->teammate;\n\t\t\t\tbs->teamgoal.areanum = areanum;\n\t\t\t\tVectorCopy(entinfo.origin, bs->teamgoal.origin);\n\t\t\t\tVectorSet(bs->teamgoal.mins, -8, -8, -8);\n\t\t\t\tVectorSet(bs->teamgoal.maxs, 8, 8, 8);\n\t\t\t}\n\t\t}\n\t\t//the goal the bot should go for\n\t\tmemcpy(goal, &bs->teamgoal, sizeof(bot_goal_t));\n\t\t//if the companion is NOT visible for too long\n\t\tif (bs->teammatevisible_time < FloatTime() - 60) {\n\t\t\tBotAI_BotInitialChat(bs, \"accompany_cannotfind\", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL);\n\t\t\ttrap_BotEnterChat(bs->cs, bs->teammate, CHAT_TELL);\n\t\t\tbs->ltgtype = 0;\n\t\t\t// just to make sure the bot won't spam this message\n\t\t\tbs->teammatevisible_time = FloatTime();\n\t\t}\n\t\treturn qtrue;\n\t}\n\t//\n\tif (bs->ltgtype == LTG_DEFENDKEYAREA) {\n\t\tif (trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin,\n\t\t\t\tbs->teamgoal.areanum, TFL_DEFAULT) > bs->defendaway_range) {\n\t\t\tbs->defendaway_time = 0;\n\t\t}\n\t}\n\t//if defending a key area\n\tif (bs->ltgtype == LTG_DEFENDKEYAREA && !retreat &&\n\t\t\t\tbs->defendaway_time < FloatTime()) {\n\t\t//check for bot typing status message\n\t\tif (bs->teammessage_time && bs->teammessage_time < FloatTime()) {\n\t\t\ttrap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf));\n\t\t\tBotAI_BotInitialChat(bs, \"defend_start\", buf, NULL);\n\t\t\ttrap_BotEnterChat(bs->cs, 0, CHAT_TEAM);\n\t\t\tBotVoiceChatOnly(bs, -1, VOICECHAT_ONDEFENSE);\n\t\t\tbs->teammessage_time = 0;\n\t\t}\n\t\t//set the bot goal\n\t\tmemcpy(goal, &bs->teamgoal, sizeof(bot_goal_t));\n\t\t//stop after 2 minutes\n\t\tif (bs->teamgoal_time < FloatTime()) {\n\t\t\ttrap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf));\n\t\t\tBotAI_BotInitialChat(bs, \"defend_stop\", buf, NULL);\n\t\t\ttrap_BotEnterChat(bs->cs, 0, CHAT_TEAM);\n\t\t\tbs->ltgtype = 0;\n\t\t}\n\t\t//if very close... go away for some time\n\t\tVectorSubtract(goal->origin, bs->origin, dir);\n\t\tif (VectorLengthSquared(dir) < Square(70)) {\n\t\t\ttrap_BotResetAvoidReach(bs->ms);\n\t\t\tbs->defendaway_time = FloatTime() + 3 + 3 * random();\n\t\t\tif (BotHasPersistantPowerupAndWeapon(bs)) {\n\t\t\t\tbs->defendaway_range = 100;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tbs->defendaway_range = 350;\n\t\t\t}\n\t\t}\n\t\treturn qtrue;\n\t}\n\t//going to kill someone\n\tif (bs->ltgtype == LTG_KILL && !retreat) {\n\t\t//check for bot typing status message\n\t\tif (bs->teammessage_time && bs->teammessage_time < FloatTime()) {\n\t\t\tEasyClientName(bs->teamgoal.entitynum, buf, sizeof(buf));\n\t\t\tBotAI_BotInitialChat(bs, \"kill_start\", buf, NULL);\n\t\t\ttrap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);\n\t\t\tbs->teammessage_time = 0;\n\t\t}\n\t\t//\n\t\tif (bs->lastkilledplayer == bs->teamgoal.entitynum) {\n\t\t\tEasyClientName(bs->teamgoal.entitynum, buf, sizeof(buf));\n\t\t\tBotAI_BotInitialChat(bs, \"kill_done\", buf, NULL);\n\t\t\ttrap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);\n\t\t\tbs->lastkilledplayer = -1;\n\t\t\tbs->ltgtype = 0;\n\t\t}\n\t\t//\n\t\tif (bs->teamgoal_time < FloatTime()) {\n\t\t\tbs->ltgtype = 0;\n\t\t}\n\t\t//just roam around\n\t\treturn BotGetItemLongTermGoal(bs, tfl, goal);\n\t}\n\t//get an item\n\tif (bs->ltgtype == LTG_GETITEM && !retreat) {\n\t\t//check for bot typing status message\n\t\tif (bs->teammessage_time && bs->teammessage_time < FloatTime()) {\n\t\t\ttrap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf));\n\t\t\tBotAI_BotInitialChat(bs, \"getitem_start\", buf, NULL);\n\t\t\ttrap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);\n\t\t\tBotVoiceChatOnly(bs, bs->decisionmaker, VOICECHAT_YES);\n\t\t\ttrap_EA_Action(bs->client, ACTION_AFFIRMATIVE);\n\t\t\tbs->teammessage_time = 0;\n\t\t}\n\t\t//set the bot goal\n\t\tmemcpy(goal, &bs->teamgoal, sizeof(bot_goal_t));\n\t\t//stop after some time\n\t\tif (bs->teamgoal_time < FloatTime()) {\n\t\t\tbs->ltgtype = 0;\n\t\t}\n\t\t//\n\t\tif (trap_BotItemGoalInVisButNotVisible(bs->entitynum, bs->eye, bs->viewangles, goal)) {\n\t\t\ttrap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf));\n\t\t\tBotAI_BotInitialChat(bs, \"getitem_notthere\", buf, NULL);\n\t\t\ttrap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);\n\t\t\tbs->ltgtype = 0;\n\t\t}\n\t\telse if (BotReachedGoal(bs, goal)) {\n\t\t\ttrap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf));\n\t\t\tBotAI_BotInitialChat(bs, \"getitem_gotit\", buf, NULL);\n\t\t\ttrap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);\n\t\t\tbs->ltgtype = 0;\n\t\t}\n\t\treturn qtrue;\n\t}\n\t//if camping somewhere\n\tif ((bs->ltgtype == LTG_CAMP || bs->ltgtype == LTG_CAMPORDER) && !retreat) {\n\t\t//check for bot typing status message\n\t\tif (bs->teammessage_time && bs->teammessage_time < FloatTime()) {\n\t\t\tif (bs->ltgtype == LTG_CAMPORDER) {\n\t\t\t\tBotAI_BotInitialChat(bs, \"camp_start\", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL);\n\t\t\t\ttrap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);\n\t\t\t\tBotVoiceChatOnly(bs, bs->decisionmaker, VOICECHAT_YES);\n\t\t\t\ttrap_EA_Action(bs->client, ACTION_AFFIRMATIVE);\n\t\t\t}\n\t\t\tbs->teammessage_time = 0;\n\t\t}\n\t\t//set the bot goal\n\t\tmemcpy(goal, &bs->teamgoal, sizeof(bot_goal_t));\n\t\t//\n\t\tif (bs->teamgoal_time < FloatTime()) {\n\t\t\tif (bs->ltgtype == LTG_CAMPORDER) {\n\t\t\t\tBotAI_BotInitialChat(bs, \"camp_stop\", NULL);\n\t\t\t\ttrap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);\n\t\t\t}\n\t\t\tbs->ltgtype = 0;\n\t\t}\n\t\t//if really near the camp spot\n\t\tVectorSubtract(goal->origin, bs->origin, dir);\n\t\tif (VectorLengthSquared(dir) < Square(60))\n\t\t{\n\t\t\t//if not arrived yet\n\t\t\tif (!bs->arrive_time) {\n\t\t\t\tif (bs->ltgtype == LTG_CAMPORDER) {\n\t\t\t\t\tBotAI_BotInitialChat(bs, \"camp_arrive\", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL);\n\t\t\t\t\ttrap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);\n\t\t\t\t\tBotVoiceChatOnly(bs, bs->decisionmaker, VOICECHAT_INPOSITION);\n\t\t\t\t}\n\t\t\t\tbs->arrive_time = FloatTime();\n\t\t\t}\n\t\t\t//look strategically around for enemies\n\t\t\tif (random() < bs->thinktime * 0.8) {\n\t\t\t\tBotRoamGoal(bs, target);\n\t\t\t\tVectorSubtract(target, bs->origin, dir);\n\t\t\t\tvectoangles(dir, bs->ideal_viewangles);\n\t\t\t\tbs->ideal_viewangles[2] *= 0.5;\n\t\t\t}\n\t\t\t//check if the bot wants to crouch\n\t\t\t//don't crouch if crouched less than 5 seconds ago\n\t\t\tif (bs->attackcrouch_time < FloatTime() - 5) {\n\t\t\t\tcroucher = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CROUCHER, 0, 1);\n\t\t\t\tif (random() < bs->thinktime * croucher) {\n\t\t\t\t\tbs->attackcrouch_time = FloatTime() + 5 + croucher * 15;\n\t\t\t\t}\n\t\t\t}\n\t\t\t//if the bot wants to crouch\n\t\t\tif (bs->attackcrouch_time > FloatTime()) {\n\t\t\t\ttrap_EA_Crouch(bs->client);\n\t\t\t}\n\t\t\t//don't crouch when swimming\n\t\t\tif (trap_AAS_Swimming(bs->origin)) bs->attackcrouch_time = FloatTime() - 1;\n\t\t\t//make sure the bot is not gonna drown\n\t\t\tif (trap_PointContents(bs->eye,bs->entitynum) & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA)) {\n\t\t\t\tif (bs->ltgtype == LTG_CAMPORDER) {\n\t\t\t\t\tBotAI_BotInitialChat(bs, \"camp_stop\", NULL);\n\t\t\t\t\ttrap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);\n\t\t\t\t\t//\n\t\t\t\t\tif (bs->lastgoal_ltgtype == LTG_CAMPORDER) {\n\t\t\t\t\t\tbs->lastgoal_ltgtype = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbs->ltgtype = 0;\n\t\t\t}\n\t\t\t//\n\t\t\tif (bs->camp_range > 0) {\n\t\t\t\t//FIXME: move around a bit\n\t\t\t}\n\t\t\t//\n\t\t\ttrap_BotResetAvoidReach(bs->ms);\n\t\t\treturn qfalse;\n\t\t}\n\t\treturn qtrue;\n\t}\n\t//patrolling along several waypoints\n\tif (bs->ltgtype == LTG_PATROL && !retreat) {\n\t\t//check for bot typing status message\n\t\tif (bs->teammessage_time && bs->teammessage_time < FloatTime()) {\n\t\t\tstrcpy(buf, \"\");\n\t\t\tfor (wp = bs->patrolpoints; wp; wp = wp->next) {\n\t\t\t\tstrcat(buf, wp->name);\n\t\t\t\tif (wp->next) strcat(buf, \" to \");\n\t\t\t}\n\t\t\tBotAI_BotInitialChat(bs, \"patrol_start\", buf, NULL);\n\t\t\ttrap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);\n\t\t\tBotVoiceChatOnly(bs, bs->decisionmaker, VOICECHAT_YES);\n\t\t\ttrap_EA_Action(bs->client, ACTION_AFFIRMATIVE);\n\t\t\tbs->teammessage_time = 0;\n\t\t}\n\t\t//\n\t\tif (!bs->curpatrolpoint) {\n\t\t\tbs->ltgtype = 0;\n\t\t\treturn qfalse;\n\t\t}\n\t\t//if the bot touches the current goal\n\t\tif (trap_BotTouchingGoal(bs->origin, &bs->curpatrolpoint->goal)) {\n\t\t\tif (bs->patrolflags & PATROL_BACK) {\n\t\t\t\tif (bs->curpatrolpoint->prev) {\n\t\t\t\t\tbs->curpatrolpoint = bs->curpatrolpoint->prev;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tbs->curpatrolpoint = bs->curpatrolpoint->next;\n\t\t\t\t\tbs->patrolflags &= ~PATROL_BACK;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (bs->curpatrolpoint->next) {\n\t\t\t\t\tbs->curpatrolpoint = bs->curpatrolpoint->next;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tbs->curpatrolpoint = bs->curpatrolpoint->prev;\n\t\t\t\t\tbs->patrolflags |= PATROL_BACK;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t//stop after 5 minutes\n\t\tif (bs->teamgoal_time < FloatTime()) {\n\t\t\tBotAI_BotInitialChat(bs, \"patrol_stop\", NULL);\n\t\t\ttrap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);\n\t\t\tbs->ltgtype = 0;\n\t\t}\n\t\tif (!bs->curpatrolpoint) {\n\t\t\tbs->ltgtype = 0;\n\t\t\treturn qfalse;\n\t\t}\n\t\tmemcpy(goal, &bs->curpatrolpoint->goal, sizeof(bot_goal_t));\n\t\treturn qtrue;\n\t}\n#ifdef CTF\n\tif (gametype == GT_CTF) {\n\t\t//if going for enemy flag\n\t\tif (bs->ltgtype == LTG_GETFLAG) {\n\t\t\t//check for bot typing status message\n\t\t\tif (bs->teammessage_time && bs->teammessage_time < FloatTime()) {\n\t\t\t\tBotAI_BotInitialChat(bs, \"captureflag_start\", NULL);\n\t\t\t\ttrap_BotEnterChat(bs->cs, 0, CHAT_TEAM);\n\t\t\t\tBotVoiceChatOnly(bs, -1, VOICECHAT_ONGETFLAG);\n\t\t\t\tbs->teammessage_time = 0;\n\t\t\t}\n\t\t\t//\n\t\t\tswitch(BotTeam(bs)) {\n\t\t\t\tcase TEAM_RED: memcpy(goal, &ctf_blueflag, sizeof(bot_goal_t)); break;\n\t\t\t\tcase TEAM_BLUE: memcpy(goal, &ctf_redflag, sizeof(bot_goal_t)); break;\n\t\t\t\tdefault: bs->ltgtype = 0; return qfalse;\n\t\t\t}\n\t\t\t//if touching the flag\n\t\t\tif (trap_BotTouchingGoal(bs->origin, goal)) {\n\t\t\t\t// make sure the bot knows the flag isn't there anymore\n\t\t\t\tswitch(BotTeam(bs)) {\n\t\t\t\t\tcase TEAM_RED: bs->blueflagstatus = 1; break;\n\t\t\t\t\tcase TEAM_BLUE: bs->redflagstatus = 1; break;\n\t\t\t\t}\n\t\t\t\tbs->ltgtype = 0;\n\t\t\t}\n\t\t\t//stop after 3 minutes\n\t\t\tif (bs->teamgoal_time < FloatTime()) {\n\t\t\t\tbs->ltgtype = 0;\n\t\t\t}\n\t\t\tBotAlternateRoute(bs, goal);\n\t\t\treturn qtrue;\n\t\t}\n\t\t//if rushing to the base\n\t\tif (bs->ltgtype == LTG_RUSHBASE && bs->rushbaseaway_time < FloatTime()) {\n\t\t\tswitch(BotTeam(bs)) {\n\t\t\t\tcase TEAM_RED: memcpy(goal, &ctf_redflag, sizeof(bot_goal_t)); break;\n\t\t\t\tcase TEAM_BLUE: memcpy(goal, &ctf_blueflag, sizeof(bot_goal_t)); break;\n\t\t\t\tdefault: bs->ltgtype = 0; return qfalse;\n\t\t\t}\n\t\t\t//if not carrying the flag anymore\n\t\t\tif (!BotCTFCarryingFlag(bs)) bs->ltgtype = 0;\n\t\t\t//quit rushing after 2 minutes\n\t\t\tif (bs->teamgoal_time < FloatTime()) bs->ltgtype = 0;\n\t\t\t//if touching the base flag the bot should loose the enemy flag\n\t\t\tif (trap_BotTouchingGoal(bs->origin, goal)) {\n\t\t\t\t//if the bot is still carrying the enemy flag then the\n\t\t\t\t//base flag is gone, now just walk near the base a bit\n\t\t\t\tif (BotCTFCarryingFlag(bs)) {\n\t\t\t\t\ttrap_BotResetAvoidReach(bs->ms);\n\t\t\t\t\tbs->rushbaseaway_time = FloatTime() + 5 + 10 * random();\n\t\t\t\t\t//FIXME: add chat to tell the others to get back the flag\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tbs->ltgtype = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\tBotAlternateRoute(bs, goal);\n\t\t\treturn qtrue;\n\t\t}\n\t\t//returning flag\n\t\tif (bs->ltgtype == LTG_RETURNFLAG) {\n\t\t\t//check for bot typing status message\n\t\t\tif (bs->teammessage_time && bs->teammessage_time < FloatTime()) {\n\t\t\t\tBotAI_BotInitialChat(bs, \"returnflag_start\", NULL);\n\t\t\t\ttrap_BotEnterChat(bs->cs, 0, CHAT_TEAM);\n\t\t\t\tBotVoiceChatOnly(bs, -1, VOICECHAT_ONRETURNFLAG);\n\t\t\t\tbs->teammessage_time = 0;\n\t\t\t}\n\t\t\t//\n\t\t\tswitch(BotTeam(bs)) {\n\t\t\t\tcase TEAM_RED: memcpy(goal, &ctf_blueflag, sizeof(bot_goal_t)); break;\n\t\t\t\tcase TEAM_BLUE: memcpy(goal, &ctf_redflag, sizeof(bot_goal_t)); break;\n\t\t\t\tdefault: bs->ltgtype = 0; return qfalse;\n\t\t\t}\n\t\t\t//if touching the flag\n\t\t\tif (trap_BotTouchingGoal(bs->origin, goal)) bs->ltgtype = 0;\n\t\t\t//stop after 3 minutes\n\t\t\tif (bs->teamgoal_time < FloatTime()) {\n\t\t\t\tbs->ltgtype = 0;\n\t\t\t}\n\t\t\tBotAlternateRoute(bs, goal);\n\t\t\treturn qtrue;\n\t\t}\n\t}\n#endif //CTF\n\t//normal goal stuff\n\treturn BotGetItemLongTermGoal(bs, tfl, goal);\n}\n\n/*\n==================\nBotLongTermGoal\n==================\n*/\nint BotLongTermGoal(bot_state_t *bs, int tfl, int retreat, bot_goal_t *goal) {\n\taas_entityinfo_t entinfo;\n\tchar teammate[MAX_MESSAGE_SIZE];\n\tfloat squaredist;\n\tint areanum;\n\tvec3_t dir;\n\n\t//FIXME: also have air long term goals?\n\t//\n\t//if the bot is leading someone and not retreating\n\tif (bs->lead_time > 0 && !retreat) {\n\t\tif (bs->lead_time < FloatTime()) {\n\t\t\tBotAI_BotInitialChat(bs, \"lead_stop\", EasyClientName(bs->lead_teammate, teammate, sizeof(teammate)), NULL);\n\t\t\ttrap_BotEnterChat(bs->cs, bs->teammate, CHAT_TELL);\n\t\t\tbs->lead_time = 0;\n\t\t\treturn BotGetLongTermGoal(bs, tfl, retreat, goal);\n\t\t}\n\t\t//\n\t\tif (bs->leadmessage_time < 0 && -bs->leadmessage_time < FloatTime()) {\n\t\t\tBotAI_BotInitialChat(bs, \"followme\", EasyClientName(bs->lead_teammate, teammate, sizeof(teammate)), NULL);\n\t\t\ttrap_BotEnterChat(bs->cs, bs->teammate, CHAT_TELL);\n\t\t\tbs->leadmessage_time = FloatTime();\n\t\t}\n\t\t//get entity information of the companion\n\t\tBotEntityInfo(bs->lead_teammate, &entinfo);\n\t\t//\n\t\tif (entinfo.valid) {\n\t\t\tareanum = BotPointAreaNum(entinfo.origin);\n\t\t\tif (areanum && trap_AAS_AreaReachability(areanum)) {\n\t\t\t\t//update team goal\n\t\t\t\tbs->lead_teamgoal.entitynum = bs->lead_teammate;\n\t\t\t\tbs->lead_teamgoal.areanum = areanum;\n\t\t\t\tVectorCopy(entinfo.origin, bs->lead_teamgoal.origin);\n\t\t\t\tVectorSet(bs->lead_teamgoal.mins, -8, -8, -8);\n\t\t\t\tVectorSet(bs->lead_teamgoal.maxs, 8, 8, 8);\n\t\t\t}\n\t\t}\n\t\t//if the team mate is visible\n\t\tif (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->lead_teammate)) {\n\t\t\tbs->leadvisible_time = FloatTime();\n\t\t}\n\t\t//if the team mate is not visible for 1 seconds\n\t\tif (bs->leadvisible_time < FloatTime() - 1) {\n\t\t\tbs->leadbackup_time = FloatTime() + 2;\n\t\t}\n\t\t//distance towards the team mate\n\t\tVectorSubtract(bs->origin, bs->lead_teamgoal.origin, dir);\n\t\tsquaredist = VectorLengthSquared(dir);\n\t\t//if backing up towards the team mate\n\t\tif (bs->leadbackup_time > FloatTime()) {\n\t\t\tif (bs->leadmessage_time < FloatTime() - 20) {\n\t\t\t\tBotAI_BotInitialChat(bs, \"followme\", EasyClientName(bs->lead_teammate, teammate, sizeof(teammate)), NULL);\n\t\t\t\ttrap_BotEnterChat(bs->cs, bs->teammate, CHAT_TELL);\n\t\t\t\tbs->leadmessage_time = FloatTime();\n\t\t\t}\n\t\t\t//if very close to the team mate\n\t\t\tif (squaredist < Square(100)) {\n\t\t\t\tbs->leadbackup_time = 0;\n\t\t\t}\n\t\t\t//the bot should go back to the team mate\n\t\t\tmemcpy(goal, &bs->lead_teamgoal, sizeof(bot_goal_t));\n\t\t\treturn qtrue;\n\t\t}\n\t\telse {\n\t\t\t//if quite distant from the team mate\n\t\t\tif (squaredist > Square(500)) {\n\t\t\t\tif (bs->leadmessage_time < FloatTime() - 20) {\n\t\t\t\t\tBotAI_BotInitialChat(bs, \"followme\", EasyClientName(bs->lead_teammate, teammate, sizeof(teammate)), NULL);\n\t\t\t\t\ttrap_BotEnterChat(bs->cs, bs->teammate, CHAT_TELL);\n\t\t\t\t\tbs->leadmessage_time = FloatTime();\n\t\t\t\t}\n\t\t\t\t//look at the team mate\n\t\t\t\tVectorSubtract(entinfo.origin, bs->origin, dir);\n\t\t\t\tvectoangles(dir, bs->ideal_viewangles);\n\t\t\t\tbs->ideal_viewangles[2] *= 0.5;\n\t\t\t\t//just wait for the team mate\n\t\t\t\treturn qfalse;\n\t\t\t}\n\t\t}\n\t}\n\treturn BotGetLongTermGoal(bs, tfl, retreat, goal);\n}\n\n/*\n==================\nAIEnter_Intermission\n==================\n*/\nvoid AIEnter_Intermission(bot_state_t *bs, char *s) {\n\tBotRecordNodeSwitch(bs, \"intermission\", \"\", s);\n\t//reset the bot state\n\tBotResetState(bs);\n\t//check for end level chat\n\tif (BotChat_EndLevel(bs)) {\n\t\ttrap_BotEnterChat(bs->cs, 0, bs->chatto);\n\t}\n\tbs->ainode = AINode_Intermission;\n}\n\n/*\n==================\nAINode_Intermission\n==================\n*/\nint AINode_Intermission(bot_state_t *bs) {\n\t//if the intermission ended\n\tif (!BotIntermission(bs)) {\n\t\tif (BotChat_StartLevel(bs)) {\n\t\t\tbs->stand_time = FloatTime() + BotChatTime(bs);\n\t\t}\n\t\telse {\n\t\t\tbs->stand_time = FloatTime() + 2;\n\t\t}\n\t\tAIEnter_Stand(bs, \"intermission: chat\");\n\t}\n\treturn qtrue;\n}\n\n/*\n==================\nAIEnter_Observer\n==================\n*/\nvoid AIEnter_Observer(bot_state_t *bs, char *s) {\n\tBotRecordNodeSwitch(bs, \"observer\", \"\", s);\n\t//reset the bot state\n\tBotResetState(bs);\n\tbs->ainode = AINode_Observer;\n}\n\n/*\n==================\nAINode_Observer\n==================\n*/\nint AINode_Observer(bot_state_t *bs) {\n\t//if the bot left observer mode\n\tif (!BotIsObserver(bs)) {\n\t\tAIEnter_Stand(bs, \"observer: left observer\");\n\t}\n\treturn qtrue;\n}\n\n/*\n==================\nAIEnter_Stand\n==================\n*/\nvoid AIEnter_Stand(bot_state_t *bs, char *s) {\n\tBotRecordNodeSwitch(bs, \"stand\", \"\", s);\n\tbs->standfindenemy_time = FloatTime() + 1;\n\tbs->ainode = AINode_Stand;\n}\n\n/*\n==================\nAINode_Stand\n==================\n*/\nint AINode_Stand(bot_state_t *bs) {\n\n\t//if the bot's health decreased\n\tif (bs->lastframe_health > bs->inventory[INVENTORY_HEALTH]) {\n\t\tif (BotChat_HitTalking(bs)) {\n\t\t\tbs->standfindenemy_time = FloatTime() + BotChatTime(bs) + 0.1;\n\t\t\tbs->stand_time = FloatTime() + BotChatTime(bs) + 0.1;\n\t\t}\n\t}\n\tif (bs->standfindenemy_time < FloatTime()) {\n\t\tif (BotFindEnemy(bs, -1)) {\n\t\t\tAIEnter_Battle_Fight(bs, \"stand: found enemy\");\n\t\t\treturn qfalse;\n\t\t}\n\t\tbs->standfindenemy_time = FloatTime() + 1;\n\t}\n\t// put up chat icon\n\ttrap_EA_Talk(bs->client);\n\t// when done standing\n\tif (bs->stand_time < FloatTime()) {\n\t\ttrap_BotEnterChat(bs->cs, 0, bs->chatto);\n\t\tAIEnter_Seek_LTG(bs, \"stand: time out\");\n\t\treturn qfalse;\n\t}\n\t//\n\treturn qtrue;\n}\n\n/*\n==================\nAIEnter_Respawn\n==================\n*/\nvoid AIEnter_Respawn(bot_state_t *bs, char *s) {\n\tBotRecordNodeSwitch(bs, \"respawn\", \"\", s);\n\t//reset some states\n\ttrap_BotResetMoveState(bs->ms);\n\ttrap_BotResetGoalState(bs->gs);\n\ttrap_BotResetAvoidGoals(bs->gs);\n\ttrap_BotResetAvoidReach(bs->ms);\n\t//if the bot wants to chat\n\tif (BotChat_Death(bs)) {\n\t\tbs->respawn_time = FloatTime() + BotChatTime(bs);\n\t\tbs->respawnchat_time = FloatTime();\n\t}\n\telse {\n\t\tbs->respawn_time = FloatTime() + 1 + random();\n\t\tbs->respawnchat_time = 0;\n\t}\n\t//set respawn state\n\tbs->respawn_wait = qfalse;\n\tbs->ainode = AINode_Respawn;\n}\n\n/*\n==================\nAINode_Respawn\n==================\n*/\nint AINode_Respawn(bot_state_t *bs) {\n\t// if waiting for the actual respawn\n\tif (bs->respawn_wait) {\n\t\tif (!BotIsDead(bs)) {\n\t\t\tAIEnter_Seek_LTG(bs, \"respawn: respawned\");\n\t\t}\n\t\telse {\n\t\t\ttrap_EA_Respawn(bs->client);\n\t\t}\n\t}\n\telse if (bs->respawn_time < FloatTime()) {\n\t\t// wait until respawned\n\t\tbs->respawn_wait = qtrue;\n\t\t// elementary action respawn\n\t\ttrap_EA_Respawn(bs->client);\n\t\t//\n\t\tif (bs->respawnchat_time) {\n\t\t\ttrap_BotEnterChat(bs->cs, 0, bs->chatto);\n\t\t\tbs->enemy = -1;\n\t\t}\n\t}\n\tif (bs->respawnchat_time && bs->respawnchat_time < FloatTime() - 0.5) {\n\t\ttrap_EA_Talk(bs->client);\n\t}\n\t//\n\treturn qtrue;\n}\n\n/*\n==================\nBotSelectActivateWeapon\n==================\n*/\nint BotSelectActivateWeapon(bot_state_t *bs) {\n\t//\n\tif (bs->inventory[INVENTORY_MACHINEGUN] > 0 && bs->inventory[INVENTORY_BULLETS] > 0)\n\t\treturn WEAPONINDEX_MACHINEGUN;\n\telse if (bs->inventory[INVENTORY_SHOTGUN] > 0 && bs->inventory[INVENTORY_SHELLS] > 0)\n\t\treturn WEAPONINDEX_SHOTGUN;\n\telse if (bs->inventory[INVENTORY_PLASMAGUN] > 0 && bs->inventory[INVENTORY_CELLS] > 0)\n\t\treturn WEAPONINDEX_PLASMAGUN;\n\telse if (bs->inventory[INVENTORY_LIGHTNING] > 0 && bs->inventory[INVENTORY_LIGHTNINGAMMO] > 0)\n\t\treturn WEAPONINDEX_LIGHTNING;\n\telse if (bs->inventory[INVENTORY_RAILGUN] > 0 && bs->inventory[INVENTORY_SLUGS] > 0)\n\t\treturn WEAPONINDEX_RAILGUN;\n\telse if (bs->inventory[INVENTORY_ROCKETLAUNCHER] > 0 && bs->inventory[INVENTORY_ROCKETS] > 0)\n\t\treturn WEAPONINDEX_ROCKET_LAUNCHER;\n\telse if (bs->inventory[INVENTORY_BFG10K] > 0 && bs->inventory[INVENTORY_BFGAMMO] > 0)\n\t\treturn WEAPONINDEX_BFG;\n\telse {\n\t\treturn -1;\n\t}\n}\n\n/*\n==================\nBotClearPath\n\n try to deactivate obstacles like proximity mines on the bot's path\n==================\n*/\nvoid BotClearPath(bot_state_t *bs, bot_moveresult_t *moveresult) {\n\tint i, bestmine;\n\tfloat dist, bestdist;\n\tvec3_t target, dir;\n\tbsp_trace_t bsptrace;\n\tentityState_t state;\n\n\t// if there is a dead body wearing kamikze nearby\n\tif (bs->kamikazebody) {\n\t\t// if the bot's view angles and weapon are not used for movement\n\t\tif ( !(moveresult->flags & (MOVERESULT_MOVEMENTVIEW | MOVERESULT_MOVEMENTWEAPON)) ) {\n\t\t\t//\n\t\t\tBotAI_GetEntityState(bs->kamikazebody, &state);\n\t\t\tVectorCopy(state.pos.trBase, target);\n\t\t\ttarget[2] += 8;\n\t\t\tVectorSubtract(target, bs->eye, dir);\n\t\t\tvectoangles(dir, moveresult->ideal_viewangles);\n\t\t\t//\n\t\t\tmoveresult->weapon = BotSelectActivateWeapon(bs);\n\t\t\tif (moveresult->weapon == -1) {\n\t\t\t\t// FIXME: run away!\n\t\t\t\tmoveresult->weapon = 0;\n\t\t\t}\n\t\t\tif (moveresult->weapon) {\n\t\t\t\t//\n\t\t\t\tmoveresult->flags |= MOVERESULT_MOVEMENTWEAPON | MOVERESULT_MOVEMENTVIEW;\n\t\t\t\t// if holding the right weapon\n\t\t\t\tif (bs->cur_ps.weapon == moveresult->weapon) {\n\t\t\t\t\t// if the bot is pretty close with it's aim\n\t\t\t\t\tif (InFieldOfVision(bs->viewangles, 20, moveresult->ideal_viewangles)) {\n\t\t\t\t\t\t//\n\t\t\t\t\t\tBotAI_Trace(&bsptrace, bs->eye, NULL, NULL, target, bs->entitynum, MASK_SHOT);\n\t\t\t\t\t\t// if the mine is visible from the current position\n\t\t\t\t\t\tif (bsptrace.fraction >= 1.0 || bsptrace.ent == state.number) {\n\t\t\t\t\t\t\t// shoot at the mine\n\t\t\t\t\t\t\ttrap_EA_Attack(bs->client);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tif (moveresult->flags & MOVERESULT_BLOCKEDBYAVOIDSPOT) {\n\t\tbs->blockedbyavoidspot_time = FloatTime() + 5;\n\t}\n\t// if blocked by an avoid spot and the view angles and weapon are used for movement\n\tif (bs->blockedbyavoidspot_time > FloatTime() &&\n\t\t!(moveresult->flags & (MOVERESULT_MOVEMENTVIEW | MOVERESULT_MOVEMENTWEAPON)) ) {\n\t\tbestdist = 300;\n\t\tbestmine = -1;\n\t\tfor (i = 0; i < bs->numproxmines; i++) {\n\t\t\tBotAI_GetEntityState(bs->proxmines[i], &state);\n\t\t\tVectorSubtract(state.pos.trBase, bs->origin, dir);\n\t\t\tdist = VectorLength(dir);\n\t\t\tif (dist < bestdist) {\n\t\t\t\tbestdist = dist;\n\t\t\t\tbestmine = i;\n\t\t\t}\n\t\t}\n\t\tif (bestmine != -1) {\n\t\t\t//\n\t\t\t// state->generic1 == TEAM_RED || state->generic1 == TEAM_BLUE\n\t\t\t//\n\t\t\t// deactivate prox mines in the bot's path by shooting\n\t\t\t// rockets or plasma cells etc. at them\n\t\t\tBotAI_GetEntityState(bs->proxmines[bestmine], &state);\n\t\t\tVectorCopy(state.pos.trBase, target);\n\t\t\ttarget[2] += 2;\n\t\t\tVectorSubtract(target, bs->eye, dir);\n\t\t\tvectoangles(dir, moveresult->ideal_viewangles);\n\t\t\t// if the bot has a weapon that does splash damage\n\t\t\tif (bs->inventory[INVENTORY_PLASMAGUN] > 0 && bs->inventory[INVENTORY_CELLS] > 0)\n\t\t\t\tmoveresult->weapon = WEAPONINDEX_PLASMAGUN;\n\t\t\telse if (bs->inventory[INVENTORY_ROCKETLAUNCHER] > 0 && bs->inventory[INVENTORY_ROCKETS] > 0)\n\t\t\t\tmoveresult->weapon = WEAPONINDEX_ROCKET_LAUNCHER;\n\t\t\telse if (bs->inventory[INVENTORY_BFG10K] > 0 && bs->inventory[INVENTORY_BFGAMMO] > 0)\n\t\t\t\tmoveresult->weapon = WEAPONINDEX_BFG;\n\t\t\telse {\n\t\t\t\tmoveresult->weapon = 0;\n\t\t\t}\n\t\t\tif (moveresult->weapon) {\n\t\t\t\t//\n\t\t\t\tmoveresult->flags |= MOVERESULT_MOVEMENTWEAPON | MOVERESULT_MOVEMENTVIEW;\n\t\t\t\t// if holding the right weapon\n\t\t\t\tif (bs->cur_ps.weapon == moveresult->weapon) {\n\t\t\t\t\t// if the bot is pretty close with it's aim\n\t\t\t\t\tif (InFieldOfVision(bs->viewangles, 20, moveresult->ideal_viewangles)) {\n\t\t\t\t\t\t//\n\t\t\t\t\t\tBotAI_Trace(&bsptrace, bs->eye, NULL, NULL, target, bs->entitynum, MASK_SHOT);\n\t\t\t\t\t\t// if the mine is visible from the current position\n\t\t\t\t\t\tif (bsptrace.fraction >= 1.0 || bsptrace.ent == state.number) {\n\t\t\t\t\t\t\t// shoot at the mine\n\t\t\t\t\t\t\ttrap_EA_Attack(bs->client);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n/*\n==================\nAIEnter_Seek_ActivateEntity\n==================\n*/\nvoid AIEnter_Seek_ActivateEntity(bot_state_t *bs, char *s) {\n\tBotRecordNodeSwitch(bs, \"activate entity\", \"\", s);\n\tbs->ainode = AINode_Seek_ActivateEntity;\n}\n\n/*\n==================\nAINode_Seek_Activate_Entity\n==================\n*/\nint AINode_Seek_ActivateEntity(bot_state_t *bs) {\n\tbot_goal_t *goal;\n\tvec3_t target, dir, ideal_viewangles;\n\tbot_moveresult_t moveresult;\n\tint targetvisible;\n\tbsp_trace_t bsptrace;\n\taas_entityinfo_t entinfo;\n\n\tif (BotIsObserver(bs)) {\n\t\tBotClearActivateGoalStack(bs);\n\t\tAIEnter_Observer(bs, \"active entity: observer\");\n\t\treturn qfalse;\n\t}\n\t//if in the intermission\n\tif (BotIntermission(bs)) {\n\t\tBotClearActivateGoalStack(bs);\n\t\tAIEnter_Intermission(bs, \"activate entity: intermission\");\n\t\treturn qfalse;\n\t}\n\t//respawn if dead\n\tif (BotIsDead(bs)) {\n\t\tBotClearActivateGoalStack(bs);\n\t\tAIEnter_Respawn(bs, \"activate entity: bot dead\");\n\t\treturn qfalse;\n\t}\n\t//\n\tbs->tfl = TFL_DEFAULT;\n\tif (bot_grapple.integer) bs->tfl |= TFL_GRAPPLEHOOK;\n\t// if in lava or slime the bot should be able to get out\n\tif (BotInLavaOrSlime(bs)) bs->tfl |= TFL_LAVA|TFL_SLIME;\n\t// map specific code\n\tBotMapScripts(bs);\n\t// no enemy\n\tbs->enemy = -1;\n\t// if the bot has no activate goal\n\tif (!bs->activatestack) {\n\t\tBotClearActivateGoalStack(bs);\n\t\tAIEnter_Seek_NBG(bs, \"activate entity: no goal\");\n\t\treturn qfalse;\n\t}\n\t//\n\tgoal = &bs->activatestack->goal;\n\t// initialize target being visible to false\n\ttargetvisible = qfalse;\n\t// if the bot has to shoot at a target to activate something\n\tif (bs->activatestack->shoot) {\n\t\t//\n\t\tBotAI_Trace(&bsptrace, bs->eye, NULL, NULL, bs->activatestack->target, bs->entitynum, MASK_SHOT);\n\t\t// if the shootable entity is visible from the current position\n\t\tif (bsptrace.fraction >= 1.0 || bsptrace.ent == goal->entitynum) {\n\t\t\ttargetvisible = qtrue;\n\t\t\t// if holding the right weapon\n\t\t\tif (bs->cur_ps.weapon == bs->activatestack->weapon) {\n\t\t\t\tVectorSubtract(bs->activatestack->target, bs->eye, dir);\n\t\t\t\tvectoangles(dir, ideal_viewangles);\n\t\t\t\t// if the bot is pretty close with it's aim\n\t\t\t\tif (InFieldOfVision(bs->viewangles, 20, ideal_viewangles)) {\n\t\t\t\t\ttrap_EA_Attack(bs->client);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t// if the shoot target is visible\n\tif (targetvisible) {\n\t\t// get the entity info of the entity the bot is shooting at\n\t\tBotEntityInfo(goal->entitynum, &entinfo);\n\t\t// if the entity the bot shoots at moved\n\t\tif (!VectorCompare(bs->activatestack->origin, entinfo.origin)) {\n#ifdef DEBUG\n\t\t\tBotAI_Print(PRT_MESSAGE, \"hit shootable button or trigger\\n\");\n#endif //DEBUG\n\t\t\tbs->activatestack->time = 0;\n\t\t}\n\t\t// if the activate goal has been activated or the bot takes too long\n\t\tif (bs->activatestack->time < FloatTime()) {\n\t\t\tBotPopFromActivateGoalStack(bs);\n\t\t\t// if there are more activate goals on the stack\n\t\t\tif (bs->activatestack) {\n\t\t\t\tbs->activatestack->time = FloatTime() + 10;\n\t\t\t\treturn qfalse;\n\t\t\t}\n\t\t\tAIEnter_Seek_NBG(bs, \"activate entity: time out\");\n\t\t\treturn qfalse;\n\t\t}\n\t\tmemset(&moveresult, 0, sizeof(bot_moveresult_t));\n\t}\n\telse {\n\t\t// if the bot has no goal\n\t\tif (!goal) {\n\t\t\tbs->activatestack->time = 0;\n\t\t}\n\t\t// if the bot does not have a shoot goal\n\t\telse if (!bs->activatestack->shoot) {\n\t\t\t//if the bot touches the current goal\n\t\t\tif (trap_BotTouchingGoal(bs->origin, goal)) {\n#ifdef DEBUG\n\t\t\t\tBotAI_Print(PRT_MESSAGE, \"touched button or trigger\\n\");\n#endif //DEBUG\n\t\t\t\tbs->activatestack->time = 0;\n\t\t\t}\n\t\t}\n\t\t// if the activate goal has been activated or the bot takes too long\n\t\tif (bs->activatestack->time < FloatTime()) {\n\t\t\tBotPopFromActivateGoalStack(bs);\n\t\t\t// if there are more activate goals on the stack\n\t\t\tif (bs->activatestack) {\n\t\t\t\tbs->activatestack->time = FloatTime() + 10;\n\t\t\t\treturn qfalse;\n\t\t\t}\n\t\t\tAIEnter_Seek_NBG(bs, \"activate entity: activated\");\n\t\t\treturn qfalse;\n\t\t}\n\t\t//predict obstacles\n\t\tif (BotAIPredictObstacles(bs, goal))\n\t\t\treturn qfalse;\n\t\t//initialize the movement state\n\t\tBotSetupForMovement(bs);\n\t\t//move towards the goal\n\t\ttrap_BotMoveToGoal(&moveresult, bs->ms, goal, bs->tfl);\n\t\t//if the movement failed\n\t\tif (moveresult.failure) {\n\t\t\t//reset the avoid reach, otherwise bot is stuck in current area\n\t\t\ttrap_BotResetAvoidReach(bs->ms);\n\t\t\t//\n\t\t\tbs->activatestack->time = 0;\n\t\t}\n\t\t//check if the bot is blocked\n\t\tBotAIBlocked(bs, &moveresult, qtrue);\n\t}\n\t//\n\tBotClearPath(bs, &moveresult);\n\t// if the bot has to shoot to activate\n\tif (bs->activatestack->shoot) {\n\t\t// if the view angles aren't yet used for the movement\n\t\tif (!(moveresult.flags & MOVERESULT_MOVEMENTVIEW)) {\n\t\t\tVectorSubtract(bs->activatestack->target, bs->eye, dir);\n\t\t\tvectoangles(dir, moveresult.ideal_viewangles);\n\t\t\tmoveresult.flags |= MOVERESULT_MOVEMENTVIEW;\n\t\t}\n\t\t// if there's no weapon yet used for the movement\n\t\tif (!(moveresult.flags & MOVERESULT_MOVEMENTWEAPON)) {\n\t\t\tmoveresult.flags |= MOVERESULT_MOVEMENTWEAPON;\n\t\t\t//\n\t\t\tbs->activatestack->weapon = BotSelectActivateWeapon(bs);\n\t\t\tif (bs->activatestack->weapon == -1) {\n\t\t\t\t//FIXME: find a decent weapon first\n\t\t\t\tbs->activatestack->weapon = 0;\n\t\t\t}\n\t\t\tmoveresult.weapon = bs->activatestack->weapon;\n\t\t}\n\t}\n\t// if the ideal view angles are set for movement\n\tif (moveresult.flags & (MOVERESULT_MOVEMENTVIEWSET|MOVERESULT_MOVEMENTVIEW|MOVERESULT_SWIMVIEW)) {\n\t\tVectorCopy(moveresult.ideal_viewangles, bs->ideal_viewangles);\n\t}\n\t// if waiting for something\n\telse if (moveresult.flags & MOVERESULT_WAITING) {\n\t\tif (random() < bs->thinktime * 0.8) {\n\t\t\tBotRoamGoal(bs, target);\n\t\t\tVectorSubtract(target, bs->origin, dir);\n\t\t\tvectoangles(dir, bs->ideal_viewangles);\n\t\t\tbs->ideal_viewangles[2] *= 0.5;\n\t\t}\n\t}\n\telse if (!(bs->flags & BFL_IDEALVIEWSET)) {\n\t\tif (trap_BotMovementViewTarget(bs->ms, goal, bs->tfl, 300, target)) {\n\t\t\tVectorSubtract(target, bs->origin, dir);\n\t\t\tvectoangles(dir, bs->ideal_viewangles);\n\t\t}\n\t\telse {\n\t\t\tvectoangles(moveresult.movedir, bs->ideal_viewangles);\n\t\t}\n\t\tbs->ideal_viewangles[2] *= 0.5;\n\t}\n\t// if the weapon is used for the bot movement\n\tif (moveresult.flags & MOVERESULT_MOVEMENTWEAPON)\n\t\tbs->weaponnum = moveresult.weapon;\n\t// if there is an enemy\n\tif (BotFindEnemy(bs, -1)) {\n\t\tif (BotWantsToRetreat(bs)) {\n\t\t\t//keep the current long term goal and retreat\n\t\t\tAIEnter_Battle_NBG(bs, \"activate entity: found enemy\");\n\t\t}\n\t\telse {\n\t\t\ttrap_BotResetLastAvoidReach(bs->ms);\n\t\t\t//empty the goal stack\n\t\t\ttrap_BotEmptyGoalStack(bs->gs);\n\t\t\t//go fight\n\t\t\tAIEnter_Battle_Fight(bs, \"activate entity: found enemy\");\n\t\t}\n\t\tBotClearActivateGoalStack(bs);\n\t}\n\treturn qtrue;\n}\n\n/*\n==================\nAIEnter_Seek_NBG\n==================\n*/\nvoid AIEnter_Seek_NBG(bot_state_t *bs, char *s) {\n\tbot_goal_t goal;\n\tchar buf[144];\n\n\tif (trap_BotGetTopGoal(bs->gs, &goal)) {\n\t\ttrap_BotGoalName(goal.number, buf, 144);\n\t\tBotRecordNodeSwitch(bs, \"seek NBG\", buf, s);\n\t}\n\telse {\n\t\tBotRecordNodeSwitch(bs, \"seek NBG\", \"no goal\", s);\n\t}\n\tbs->ainode = AINode_Seek_NBG;\n}\n\n/*\n==================\nAINode_Seek_NBG\n==================\n*/\nint AINode_Seek_NBG(bot_state_t *bs) {\n\tbot_goal_t goal;\n\tvec3_t target, dir;\n\tbot_moveresult_t moveresult;\n\n\tif (BotIsObserver(bs)) {\n\t\tAIEnter_Observer(bs, \"seek nbg: observer\");\n\t\treturn qfalse;\n\t}\n\t//if in the intermission\n\tif (BotIntermission(bs)) {\n\t\tAIEnter_Intermission(bs, \"seek nbg: intermision\");\n\t\treturn qfalse;\n\t}\n\t//respawn if dead\n\tif (BotIsDead(bs)) {\n\t\tAIEnter_Respawn(bs, \"seek nbg: bot dead\");\n\t\treturn qfalse;\n\t}\n\t//\n\tbs->tfl = TFL_DEFAULT;\n\tif (bot_grapple.integer) bs->tfl |= TFL_GRAPPLEHOOK;\n\t//if in lava or slime the bot should be able to get out\n\tif (BotInLavaOrSlime(bs)) bs->tfl |= TFL_LAVA|TFL_SLIME;\n\t//\n\tif (BotCanAndWantsToRocketJump(bs)) {\n\t\tbs->tfl |= TFL_ROCKETJUMP;\n\t}\n\t//map specific code\n\tBotMapScripts(bs);\n\t//no enemy\n\tbs->enemy = -1;\n\t//if the bot has no goal\n\tif (!trap_BotGetTopGoal(bs->gs, &goal)) bs->nbg_time = 0;\n\t//if the bot touches the current goal\n\telse if (BotReachedGoal(bs, &goal)) {\n\t\tBotChooseWeapon(bs);\n\t\tbs->nbg_time = 0;\n\t}\n\t//\n\tif (bs->nbg_time < FloatTime()) {\n\t\t//pop the current goal from the stack\n\t\ttrap_BotPopGoal(bs->gs);\n\t\t//check for new nearby items right away\n\t\t//NOTE: we canNOT reset the check_time to zero because it would create an endless loop of node switches\n\t\tbs->check_time = FloatTime() + 0.05;\n\t\t//go back to seek ltg\n\t\tAIEnter_Seek_LTG(bs, \"seek nbg: time out\");\n\t\treturn qfalse;\n\t}\n\t//predict obstacles\n\tif (BotAIPredictObstacles(bs, &goal))\n\t\treturn qfalse;\n\t//initialize the movement state\n\tBotSetupForMovement(bs);\n\t//move towards the goal\n\ttrap_BotMoveToGoal(&moveresult, bs->ms, &goal, bs->tfl);\n\t//if the movement failed\n\tif (moveresult.failure) {\n\t\t//reset the avoid reach, otherwise bot is stuck in current area\n\t\ttrap_BotResetAvoidReach(bs->ms);\n\t\tbs->nbg_time = 0;\n\t}\n\t//check if the bot is blocked\n\tBotAIBlocked(bs, &moveresult, qtrue);\n\t//\n\tBotClearPath(bs, &moveresult);\n\t//if the viewangles are used for the movement\n\tif (moveresult.flags & (MOVERESULT_MOVEMENTVIEWSET|MOVERESULT_MOVEMENTVIEW|MOVERESULT_SWIMVIEW)) {\n\t\tVectorCopy(moveresult.ideal_viewangles, bs->ideal_viewangles);\n\t}\n\t//if waiting for something\n\telse if (moveresult.flags & MOVERESULT_WAITING) {\n\t\tif (random() < bs->thinktime * 0.8) {\n\t\t\tBotRoamGoal(bs, target);\n\t\t\tVectorSubtract(target, bs->origin, dir);\n\t\t\tvectoangles(dir, bs->ideal_viewangles);\n\t\t\tbs->ideal_viewangles[2] *= 0.5;\n\t\t}\n\t}\n\telse if (!(bs->flags & BFL_IDEALVIEWSET)) {\n\t\tif (!trap_BotGetSecondGoal(bs->gs, &goal)) trap_BotGetTopGoal(bs->gs, &goal);\n\t\tif (trap_BotMovementViewTarget(bs->ms, &goal, bs->tfl, 300, target)) {\n\t\t\tVectorSubtract(target, bs->origin, dir);\n\t\t\tvectoangles(dir, bs->ideal_viewangles);\n\t\t}\n\t\t//FIXME: look at cluster portals?\n\t\telse vectoangles(moveresult.movedir, bs->ideal_viewangles);\n\t\tbs->ideal_viewangles[2] *= 0.5;\n\t}\n\t//if the weapon is used for the bot movement\n\tif (moveresult.flags & MOVERESULT_MOVEMENTWEAPON) bs->weaponnum = moveresult.weapon;\n\t//if there is an enemy\n\tif (BotFindEnemy(bs, -1)) {\n\t\tif (BotWantsToRetreat(bs)) {\n\t\t\t//keep the current long term goal and retreat\n\t\t\tAIEnter_Battle_NBG(bs, \"seek nbg: found enemy\");\n\t\t}\n\t\telse {\n\t\t\ttrap_BotResetLastAvoidReach(bs->ms);\n\t\t\t//empty the goal stack\n\t\t\ttrap_BotEmptyGoalStack(bs->gs);\n\t\t\t//go fight\n\t\t\tAIEnter_Battle_Fight(bs, \"seek nbg: found enemy\");\n\t\t}\n\t}\n\treturn qtrue;\n}\n\n/*\n==================\nAIEnter_Seek_LTG\n==================\n*/\nvoid AIEnter_Seek_LTG(bot_state_t *bs, char *s) {\n\tbot_goal_t goal;\n\tchar buf[144];\n\n\tif (trap_BotGetTopGoal(bs->gs, &goal)) {\n\t\ttrap_BotGoalName(goal.number, buf, 144);\n\t\tBotRecordNodeSwitch(bs, \"seek LTG\", buf, s);\n\t}\n\telse {\n\t\tBotRecordNodeSwitch(bs, \"seek LTG\", \"no goal\", s);\n\t}\n\tbs->ainode = AINode_Seek_LTG;\n}\n\n/*\n==================\nAINode_Seek_LTG\n==================\n*/\nint AINode_Seek_LTG(bot_state_t *bs)\n{\n\tbot_goal_t goal;\n\tvec3_t target, dir;\n\tbot_moveresult_t moveresult;\n\tint range;\n\t//char buf[128];\n\t//bot_goal_t tmpgoal;\n\n\tif (BotIsObserver(bs)) {\n\t\tAIEnter_Observer(bs, \"seek ltg: observer\");\n\t\treturn qfalse;\n\t}\n\t//if in the intermission\n\tif (BotIntermission(bs)) {\n\t\tAIEnter_Intermission(bs, \"seek ltg: intermission\");\n\t\treturn qfalse;\n\t}\n\t//respawn if dead\n\tif (BotIsDead(bs)) {\n\t\tAIEnter_Respawn(bs, \"seek ltg: bot dead\");\n\t\treturn qfalse;\n\t}\n\t//\n\tif (BotChat_Random(bs)) {\n\t\tbs->stand_time = FloatTime() + BotChatTime(bs);\n\t\tAIEnter_Stand(bs, \"seek ltg: random chat\");\n\t\treturn qfalse;\n\t}\n\t//\n\tbs->tfl = TFL_DEFAULT;\n\tif (bot_grapple.integer) bs->tfl |= TFL_GRAPPLEHOOK;\n\t//if in lava or slime the bot should be able to get out\n\tif (BotInLavaOrSlime(bs)) bs->tfl |= TFL_LAVA|TFL_SLIME;\n\t//\n\tif (BotCanAndWantsToRocketJump(bs)) {\n\t\tbs->tfl |= TFL_ROCKETJUMP;\n\t}\n\t//map specific code\n\tBotMapScripts(bs);\n\t//no enemy\n\tbs->enemy = -1;\n\t//\n\tif (bs->killedenemy_time > FloatTime() - 2) {\n\t\tif (random() < bs->thinktime * 1) {\n\t\t\ttrap_EA_Gesture(bs->client);\n\t\t}\n\t}\n\t//if there is an enemy\n\tif (BotFindEnemy(bs, -1)) {\n\t\tif (BotWantsToRetreat(bs)) {\n\t\t\t//keep the current long term goal and retreat\n\t\t\tAIEnter_Battle_Retreat(bs, \"seek ltg: found enemy\");\n\t\t\treturn qfalse;\n\t\t}\n\t\telse {\n\t\t\ttrap_BotResetLastAvoidReach(bs->ms);\n\t\t\t//empty the goal stack\n\t\t\ttrap_BotEmptyGoalStack(bs->gs);\n\t\t\t//go fight\n\t\t\tAIEnter_Battle_Fight(bs, \"seek ltg: found enemy\");\n\t\t\treturn qfalse;\n\t\t}\n\t}\n\t//\n\tBotTeamGoals(bs, qfalse);\n\t//get the current long term goal\n\tif (!BotLongTermGoal(bs, bs->tfl, qfalse, &goal)) {\n\t\treturn qtrue;\n\t}\n\t//check for nearby goals periodicly\n\tif (bs->check_time < FloatTime()) {\n\t\tbs->check_time = FloatTime() + 0.5;\n\t\t//check if the bot wants to camp\n\t\tBotWantsToCamp(bs);\n\t\t//\n\t\tif (bs->ltgtype == LTG_DEFENDKEYAREA) range = 400;\n\t\telse range = 150;\n\t\t//\n#ifdef CTF\n\t\tif (gametype == GT_CTF) {\n\t\t\t//if carrying a flag the bot shouldn't be distracted too much\n\t\t\tif (BotCTFCarryingFlag(bs))\n\t\t\t\trange = 50;\n\t\t}\n#endif //CTF\n\t\t//\n\t\tif (BotNearbyGoal(bs, bs->tfl, &goal, range)) {\n\t\t\ttrap_BotResetLastAvoidReach(bs->ms);\n\t\t\t//get the goal at the top of the stack\n\t\t\t//trap_BotGetTopGoal(bs->gs, &tmpgoal);\n\t\t\t//trap_BotGoalName(tmpgoal.number, buf, 144);\n\t\t\t//BotAI_Print(PRT_MESSAGE, \"new nearby goal %s\\n\", buf);\n\t\t\t//time the bot gets to pick up the nearby goal item\n\t\t\tbs->nbg_time = FloatTime() + 4 + range * 0.01;\n\t\t\tAIEnter_Seek_NBG(bs, \"ltg seek: nbg\");\n\t\t\treturn qfalse;\n\t\t}\n\t}\n\t//predict obstacles\n\tif (BotAIPredictObstacles(bs, &goal))\n\t\treturn qfalse;\n\t//initialize the movement state\n\tBotSetupForMovement(bs);\n\t//move towards the goal\n\ttrap_BotMoveToGoal(&moveresult, bs->ms, &goal, bs->tfl);\n\t//if the movement failed\n\tif (moveresult.failure) {\n\t\t//reset the avoid reach, otherwise bot is stuck in current area\n\t\ttrap_BotResetAvoidReach(bs->ms);\n\t\t//BotAI_Print(PRT_MESSAGE, \"movement failure %d\\n\", moveresult.traveltype);\n\t\tbs->ltg_time = 0;\n\t}\n\t//\n\tBotAIBlocked(bs, &moveresult, qtrue);\n\t//\n\tBotClearPath(bs, &moveresult);\n\t//if the viewangles are used for the movement\n\tif (moveresult.flags & (MOVERESULT_MOVEMENTVIEWSET|MOVERESULT_MOVEMENTVIEW|MOVERESULT_SWIMVIEW)) {\n\t\tVectorCopy(moveresult.ideal_viewangles, bs->ideal_viewangles);\n\t}\n\t//if waiting for something\n\telse if (moveresult.flags & MOVERESULT_WAITING) {\n\t\tif (random() < bs->thinktime * 0.8) {\n\t\t\tBotRoamGoal(bs, target);\n\t\t\tVectorSubtract(target, bs->origin, dir);\n\t\t\tvectoangles(dir, bs->ideal_viewangles);\n\t\t\tbs->ideal_viewangles[2] *= 0.5;\n\t\t}\n\t}\n\telse if (!(bs->flags & BFL_IDEALVIEWSET)) {\n\t\tif (trap_BotMovementViewTarget(bs->ms, &goal, bs->tfl, 300, target)) {\n\t\t\tVectorSubtract(target, bs->origin, dir);\n\t\t\tvectoangles(dir, bs->ideal_viewangles);\n\t\t}\n\t\t//FIXME: look at cluster portals?\n\t\telse if (VectorLengthSquared(moveresult.movedir)) {\n\t\t\tvectoangles(moveresult.movedir, bs->ideal_viewangles);\n\t\t}\n\t\telse if (random() < bs->thinktime * 0.8) {\n\t\t\tBotRoamGoal(bs, target);\n\t\t\tVectorSubtract(target, bs->origin, dir);\n\t\t\tvectoangles(dir, bs->ideal_viewangles);\n\t\t\tbs->ideal_viewangles[2] *= 0.5;\n\t\t}\n\t\tbs->ideal_viewangles[2] *= 0.5;\n\t}\n\t//if the weapon is used for the bot movement\n\tif (moveresult.flags & MOVERESULT_MOVEMENTWEAPON) bs->weaponnum = moveresult.weapon;\n\t//\n\treturn qtrue;\n}\n\n/*\n==================\nAIEnter_Battle_Fight\n==================\n*/\nvoid AIEnter_Battle_Fight(bot_state_t *bs, char *s) {\n\tBotRecordNodeSwitch(bs, \"battle fight\", \"\", s);\n\ttrap_BotResetLastAvoidReach(bs->ms);\n\tbs->ainode = AINode_Battle_Fight;\n}\n\n/*\n==================\nAIEnter_Battle_Fight\n==================\n*/\nvoid AIEnter_Battle_SuicidalFight(bot_state_t *bs, char *s) {\n\tBotRecordNodeSwitch(bs, \"battle fight\", \"\", s);\n\ttrap_BotResetLastAvoidReach(bs->ms);\n\tbs->ainode = AINode_Battle_Fight;\n\tbs->flags |= BFL_FIGHTSUICIDAL;\n}\n\n/*\n==================\nAINode_Battle_Fight\n==================\n*/\nint AINode_Battle_Fight(bot_state_t *bs) {\n\tint areanum;\n\tvec3_t target;\n\taas_entityinfo_t entinfo;\n\tbot_moveresult_t moveresult;\n\n\tif (BotIsObserver(bs)) {\n\t\tAIEnter_Observer(bs, \"battle fight: observer\");\n\t\treturn qfalse;\n\t}\n\n\t//if in the intermission\n\tif (BotIntermission(bs)) {\n\t\tAIEnter_Intermission(bs, \"battle fight: intermission\");\n\t\treturn qfalse;\n\t}\n\t//respawn if dead\n\tif (BotIsDead(bs)) {\n\t\tAIEnter_Respawn(bs, \"battle fight: bot dead\");\n\t\treturn qfalse;\n\t}\n\t//if there is another better enemy\n\tif (BotFindEnemy(bs, bs->enemy)) {\n#ifdef DEBUG\n\t\tBotAI_Print(PRT_MESSAGE, \"found new better enemy\\n\");\n#endif\n\t}\n\t//if no enemy\n\tif (bs->enemy < 0) {\n\t\tAIEnter_Seek_LTG(bs, \"battle fight: no enemy\");\n\t\treturn qfalse;\n\t}\n\t//\n\tBotEntityInfo(bs->enemy, &entinfo);\n\t//if the enemy is dead\n\tif (bs->enemydeath_time) {\n\t\tif (bs->enemydeath_time < FloatTime() - 1.0) {\n\t\t\tbs->enemydeath_time = 0;\n\t\t\tif (bs->enemysuicide) {\n\t\t\t\tBotChat_EnemySuicide(bs);\n\t\t\t}\n\t\t\tif (bs->lastkilledplayer == bs->enemy && BotChat_Kill(bs)) {\n\t\t\t\tbs->stand_time = FloatTime() + BotChatTime(bs);\n\t\t\t\tAIEnter_Stand(bs, \"battle fight: enemy dead\");\n\t\t\t}\n\t\t\telse {\n\t\t\t\tbs->ltg_time = 0;\n\t\t\t\tAIEnter_Seek_LTG(bs, \"battle fight: enemy dead\");\n\t\t\t}\n\t\t\treturn qfalse;\n\t\t}\n\t}\n\telse {\n\t\tif (EntityIsDead(&entinfo)) {\n\t\t\tbs->enemydeath_time = FloatTime();\n\t\t}\n\t}\n\t//if the enemy is invisible and not shooting the bot looses track easily\n\tif (EntityIsInvisible(&entinfo) && !EntityIsShooting(&entinfo)) {\n\t\tif (random() < 0.2) {\n\t\t\tAIEnter_Seek_LTG(bs, \"battle fight: invisible\");\n\t\t\treturn qfalse;\n\t\t}\n\t}\n\t//\n\tVectorCopy(entinfo.origin, target);\n\t// if not a player enemy\n\tif (bs->enemy >= MAX_CLIENTS) {\n\t}\n\t//update the reachability area and origin if possible\n\tareanum = BotPointAreaNum(target);\n\tif (areanum && trap_AAS_AreaReachability(areanum)) {\n\t\tVectorCopy(target, bs->lastenemyorigin);\n\t\tbs->lastenemyareanum = areanum;\n\t}\n\t//update the attack inventory values\n\tBotUpdateBattleInventory(bs, bs->enemy);\n\t//if the bot's health decreased\n\tif (bs->lastframe_health > bs->inventory[INVENTORY_HEALTH]) {\n\t\tif (BotChat_HitNoDeath(bs)) {\n\t\t\tbs->stand_time = FloatTime() + BotChatTime(bs);\n\t\t\tAIEnter_Stand(bs, \"battle fight: chat health decreased\");\n\t\t\treturn qfalse;\n\t\t}\n\t}\n\t//if the bot hit someone\n\tif (bs->cur_ps.persistant[PERS_HITS] > bs->lasthitcount) {\n\t\tif (BotChat_HitNoKill(bs)) {\n\t\t\tbs->stand_time = FloatTime() + BotChatTime(bs);\n\t\t\tAIEnter_Stand(bs, \"battle fight: chat hit someone\");\n\t\t\treturn qfalse;\n\t\t}\n\t}\n\t//if the enemy is not visible\n\tif (!BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->enemy)) {\n\t\tif (BotWantsToChase(bs)) {\n\t\t\tAIEnter_Battle_Chase(bs, \"battle fight: enemy out of sight\");\n\t\t\treturn qfalse;\n\t\t}\n\t\telse {\n\t\t\tAIEnter_Seek_LTG(bs, \"battle fight: enemy out of sight\");\n\t\t\treturn qfalse;\n\t\t}\n\t}\n\t//use holdable items\n\tBotBattleUseItems(bs);\n\t//\n\tbs->tfl = TFL_DEFAULT;\n\tif (bot_grapple.integer) bs->tfl |= TFL_GRAPPLEHOOK;\n\t//if in lava or slime the bot should be able to get out\n\tif (BotInLavaOrSlime(bs)) bs->tfl |= TFL_LAVA|TFL_SLIME;\n\t//\n\tif (BotCanAndWantsToRocketJump(bs)) {\n\t\tbs->tfl |= TFL_ROCKETJUMP;\n\t}\n\t//choose the best weapon to fight with\n\tBotChooseWeapon(bs);\n\t//do attack movements\n\tmoveresult = BotAttackMove(bs, bs->tfl);\n\t//if the movement failed\n\tif (moveresult.failure) {\n\t\t//reset the avoid reach, otherwise bot is stuck in current area\n\t\ttrap_BotResetAvoidReach(bs->ms);\n\t\t//BotAI_Print(PRT_MESSAGE, \"movement failure %d\\n\", moveresult.traveltype);\n\t\tbs->ltg_time = 0;\n\t}\n\t//\n\tBotAIBlocked(bs, &moveresult, qfalse);\n\t//aim at the enemy\n\tBotAimAtEnemy(bs);\n\t//attack the enemy if possible\n\tBotCheckAttack(bs);\n\t//if the bot wants to retreat\n\tif (!(bs->flags & BFL_FIGHTSUICIDAL)) {\n\t\tif (BotWantsToRetreat(bs)) {\n\t\t\tAIEnter_Battle_Retreat(bs, \"battle fight: wants to retreat\");\n\t\t\treturn qtrue;\n\t\t}\n\t}\n\treturn qtrue;\n}\n\n/*\n==================\nAIEnter_Battle_Chase\n==================\n*/\nvoid AIEnter_Battle_Chase(bot_state_t *bs, char *s) {\n\tBotRecordNodeSwitch(bs, \"battle chase\", \"\", s);\n\tbs->chase_time = FloatTime();\n\tbs->ainode = AINode_Battle_Chase;\n}\n\n/*\n==================\nAINode_Battle_Chase\n==================\n*/\nint AINode_Battle_Chase(bot_state_t *bs)\n{\n\tbot_goal_t goal;\n\tvec3_t target, dir;\n\tbot_moveresult_t moveresult;\n\tfloat range;\n\n\tif (BotIsObserver(bs)) {\n\t\tAIEnter_Observer(bs, \"battle chase: observer\");\n\t\treturn qfalse;\n\t}\n\t//if in the intermission\n\tif (BotIntermission(bs)) {\n\t\tAIEnter_Intermission(bs, \"battle chase: intermission\");\n\t\treturn qfalse;\n\t}\n\t//respawn if dead\n\tif (BotIsDead(bs)) {\n\t\tAIEnter_Respawn(bs, \"battle chase: bot dead\");\n\t\treturn qfalse;\n\t}\n\t//if no enemy\n\tif (bs->enemy < 0) {\n\t\tAIEnter_Seek_LTG(bs, \"battle chase: no enemy\");\n\t\treturn qfalse;\n\t}\n\t//if the enemy is visible\n\tif (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->enemy)) {\n\t\tAIEnter_Battle_Fight(bs, \"battle chase\");\n\t\treturn qfalse;\n\t}\n\t//if there is another enemy\n\tif (BotFindEnemy(bs, -1)) {\n\t\tAIEnter_Battle_Fight(bs, \"battle chase: better enemy\");\n\t\treturn qfalse;\n\t}\n\t//there is no last enemy area\n\tif (!bs->lastenemyareanum) {\n\t\tAIEnter_Seek_LTG(bs, \"battle chase: no enemy area\");\n\t\treturn qfalse;\n\t}\n\t//\n\tbs->tfl = TFL_DEFAULT;\n\tif (bot_grapple.integer) bs->tfl |= TFL_GRAPPLEHOOK;\n\t//if in lava or slime the bot should be able to get out\n\tif (BotInLavaOrSlime(bs)) bs->tfl |= TFL_LAVA|TFL_SLIME;\n\t//\n\tif (BotCanAndWantsToRocketJump(bs)) {\n\t\tbs->tfl |= TFL_ROCKETJUMP;\n\t}\n\t//map specific code\n\tBotMapScripts(bs);\n\t//create the chase goal\n\tgoal.entitynum = bs->enemy;\n\tgoal.areanum = bs->lastenemyareanum;\n\tVectorCopy(bs->lastenemyorigin, goal.origin);\n\tVectorSet(goal.mins, -8, -8, -8);\n\tVectorSet(goal.maxs, 8, 8, 8);\n\t//if the last seen enemy spot is reached the enemy could not be found\n\tif (trap_BotTouchingGoal(bs->origin, &goal)) bs->chase_time = 0;\n\t//if there's no chase time left\n\tif (!bs->chase_time || bs->chase_time < FloatTime() - 10) {\n\t\tAIEnter_Seek_LTG(bs, \"battle chase: time out\");\n\t\treturn qfalse;\n\t}\n\t//check for nearby goals periodicly\n\tif (bs->check_time < FloatTime()) {\n\t\tbs->check_time = FloatTime() + 1;\n\t\trange = 150;\n\t\t//\n\t\tif (BotNearbyGoal(bs, bs->tfl, &goal, range)) {\n\t\t\t//the bot gets 5 seconds to pick up the nearby goal item\n\t\t\tbs->nbg_time = FloatTime() + 0.1 * range + 1;\n\t\t\ttrap_BotResetLastAvoidReach(bs->ms);\n\t\t\tAIEnter_Battle_NBG(bs, \"battle chase: nbg\");\n\t\t\treturn qfalse;\n\t\t}\n\t}\n\t//\n\tBotUpdateBattleInventory(bs, bs->enemy);\n\t//initialize the movement state\n\tBotSetupForMovement(bs);\n\t//move towards the goal\n\ttrap_BotMoveToGoal(&moveresult, bs->ms, &goal, bs->tfl);\n\t//if the movement failed\n\tif (moveresult.failure) {\n\t\t//reset the avoid reach, otherwise bot is stuck in current area\n\t\ttrap_BotResetAvoidReach(bs->ms);\n\t\t//BotAI_Print(PRT_MESSAGE, \"movement failure %d\\n\", moveresult.traveltype);\n\t\tbs->ltg_time = 0;\n\t}\n\t//\n\tBotAIBlocked(bs, &moveresult, qfalse);\n\t//\n\tif (moveresult.flags & (MOVERESULT_MOVEMENTVIEWSET|MOVERESULT_MOVEMENTVIEW|MOVERESULT_SWIMVIEW)) {\n\t\tVectorCopy(moveresult.ideal_viewangles, bs->ideal_viewangles);\n\t}\n\telse if (!(bs->flags & BFL_IDEALVIEWSET)) {\n\t\tif (bs->chase_time > FloatTime() - 2) {\n\t\t\tBotAimAtEnemy(bs);\n\t\t}\n\t\telse {\n\t\t\tif (trap_BotMovementViewTarget(bs->ms, &goal, bs->tfl, 300, target)) {\n\t\t\t\tVectorSubtract(target, bs->origin, dir);\n\t\t\t\tvectoangles(dir, bs->ideal_viewangles);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tvectoangles(moveresult.movedir, bs->ideal_viewangles);\n\t\t\t}\n\t\t}\n\t\tbs->ideal_viewangles[2] *= 0.5;\n\t}\n\t//if the weapon is used for the bot movement\n\tif (moveresult.flags & MOVERESULT_MOVEMENTWEAPON) bs->weaponnum = moveresult.weapon;\n\t//if the bot is in the area the enemy was last seen in\n\tif (bs->areanum == bs->lastenemyareanum) bs->chase_time = 0;\n\t//if the bot wants to retreat (the bot could have been damage during the chase)\n\tif (BotWantsToRetreat(bs)) {\n\t\tAIEnter_Battle_Retreat(bs, \"battle chase: wants to retreat\");\n\t\treturn qtrue;\n\t}\n\treturn qtrue;\n}\n\n/*\n==================\nAIEnter_Battle_Retreat\n==================\n*/\nvoid AIEnter_Battle_Retreat(bot_state_t *bs, char *s) {\n\tBotRecordNodeSwitch(bs, \"battle retreat\", \"\", s);\n\tbs->ainode = AINode_Battle_Retreat;\n}\n\n/*\n==================\nAINode_Battle_Retreat\n==================\n*/\nint AINode_Battle_Retreat(bot_state_t *bs) {\n\tbot_goal_t goal;\n\taas_entityinfo_t entinfo;\n\tbot_moveresult_t moveresult;\n\tvec3_t target, dir;\n\tfloat attack_skill, range;\n\tint areanum;\n\n\tif (BotIsObserver(bs)) {\n\t\tAIEnter_Observer(bs, \"battle retreat: observer\");\n\t\treturn qfalse;\n\t}\n\t//if in the intermission\n\tif (BotIntermission(bs)) {\n\t\tAIEnter_Intermission(bs, \"battle retreat: intermission\");\n\t\treturn qfalse;\n\t}\n\t//respawn if dead\n\tif (BotIsDead(bs)) {\n\t\tAIEnter_Respawn(bs, \"battle retreat: bot dead\");\n\t\treturn qfalse;\n\t}\n\t//if no enemy\n\tif (bs->enemy < 0) {\n\t\tAIEnter_Seek_LTG(bs, \"battle retreat: no enemy\");\n\t\treturn qfalse;\n\t}\n\t//\n\tBotEntityInfo(bs->enemy, &entinfo);\n\tif (EntityIsDead(&entinfo)) {\n\t\tAIEnter_Seek_LTG(bs, \"battle retreat: enemy dead\");\n\t\treturn qfalse;\n\t}\n\t//if there is another better enemy\n\tif (BotFindEnemy(bs, bs->enemy)) {\n#ifdef DEBUG\n\t\tBotAI_Print(PRT_MESSAGE, \"found new better enemy\\n\");\n#endif\n\t}\n\t//\n\tbs->tfl = TFL_DEFAULT;\n\tif (bot_grapple.integer) bs->tfl |= TFL_GRAPPLEHOOK;\n\t//if in lava or slime the bot should be able to get out\n\tif (BotInLavaOrSlime(bs)) bs->tfl |= TFL_LAVA|TFL_SLIME;\n\t//map specific code\n\tBotMapScripts(bs);\n\t//update the attack inventory values\n\tBotUpdateBattleInventory(bs, bs->enemy);\n\t//if the bot doesn't want to retreat anymore... probably picked up some nice items\n\tif (BotWantsToChase(bs)) {\n\t\t//empty the goal stack, when chasing, only the enemy is the goal\n\t\ttrap_BotEmptyGoalStack(bs->gs);\n\t\t//go chase the enemy\n\t\tAIEnter_Battle_Chase(bs, \"battle retreat: wants to chase\");\n\t\treturn qfalse;\n\t}\n\t//update the last time the enemy was visible\n\tif (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->enemy)) {\n\t\tbs->enemyvisible_time = FloatTime();\n\t\tVectorCopy(entinfo.origin, target);\n\t\t// if not a player enemy\n\t\tif (bs->enemy >= MAX_CLIENTS) {\n\t\t}\n\t\t//update the reachability area and origin if possible\n\t\tareanum = BotPointAreaNum(target);\n\t\tif (areanum && trap_AAS_AreaReachability(areanum)) {\n\t\t\tVectorCopy(target, bs->lastenemyorigin);\n\t\t\tbs->lastenemyareanum = areanum;\n\t\t}\n\t}\n\t//if the enemy is NOT visible for 4 seconds\n\tif (bs->enemyvisible_time < FloatTime() - 4) {\n\t\tAIEnter_Seek_LTG(bs, \"battle retreat: lost enemy\");\n\t\treturn qfalse;\n\t}\n\t//else if the enemy is NOT visible\n\telse if (bs->enemyvisible_time < FloatTime()) {\n\t\t//if there is another enemy\n\t\tif (BotFindEnemy(bs, -1)) {\n\t\t\tAIEnter_Battle_Fight(bs, \"battle retreat: another enemy\");\n\t\t\treturn qfalse;\n\t\t}\n\t}\n\t//\n\tBotTeamGoals(bs, qtrue);\n\t//use holdable items\n\tBotBattleUseItems(bs);\n\t//get the current long term goal while retreating\n\tif (!BotLongTermGoal(bs, bs->tfl, qtrue, &goal)) {\n\t\tAIEnter_Battle_SuicidalFight(bs, \"battle retreat: no way out\");\n\t\treturn qfalse;\n\t}\n\t//check for nearby goals periodicly\n\tif (bs->check_time < FloatTime()) {\n\t\tbs->check_time = FloatTime() + 1;\n\t\trange = 150;\n#ifdef CTF\n\t\tif (gametype == GT_CTF) {\n\t\t\t//if carrying a flag the bot shouldn't be distracted too much\n\t\t\tif (BotCTFCarryingFlag(bs))\n\t\t\t\trange = 50;\n\t\t}\n#endif //CTF\n\t\t//\n\t\tif (BotNearbyGoal(bs, bs->tfl, &goal, range)) {\n\t\t\ttrap_BotResetLastAvoidReach(bs->ms);\n\t\t\t//time the bot gets to pick up the nearby goal item\n\t\t\tbs->nbg_time = FloatTime() + range / 100 + 1;\n\t\t\tAIEnter_Battle_NBG(bs, \"battle retreat: nbg\");\n\t\t\treturn qfalse;\n\t\t}\n\t}\n\t//initialize the movement state\n\tBotSetupForMovement(bs);\n\t//move towards the goal\n\ttrap_BotMoveToGoal(&moveresult, bs->ms, &goal, bs->tfl);\n\t//if the movement failed\n\tif (moveresult.failure) {\n\t\t//reset the avoid reach, otherwise bot is stuck in current area\n\t\ttrap_BotResetAvoidReach(bs->ms);\n\t\t//BotAI_Print(PRT_MESSAGE, \"movement failure %d\\n\", moveresult.traveltype);\n\t\tbs->ltg_time = 0;\n\t}\n\t//\n\tBotAIBlocked(bs, &moveresult, qfalse);\n\t//choose the best weapon to fight with\n\tBotChooseWeapon(bs);\n\t//if the view is fixed for the movement\n\tif (moveresult.flags & (MOVERESULT_MOVEMENTVIEW|MOVERESULT_SWIMVIEW)) {\n\t\tVectorCopy(moveresult.ideal_viewangles, bs->ideal_viewangles);\n\t}\n\telse if (!(moveresult.flags & MOVERESULT_MOVEMENTVIEWSET)\n\t\t\t\t&& !(bs->flags & BFL_IDEALVIEWSET) ) {\n\t\tattack_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_ATTACK_SKILL, 0, 1);\n\t\t//if the bot is skilled anough\n\t\tif (attack_skill > 0.3) {\n\t\t\tBotAimAtEnemy(bs);\n\t\t}\n\t\telse {\n\t\t\tif (trap_BotMovementViewTarget(bs->ms, &goal, bs->tfl, 300, target)) {\n\t\t\t\tVectorSubtract(target, bs->origin, dir);\n\t\t\t\tvectoangles(dir, bs->ideal_viewangles);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tvectoangles(moveresult.movedir, bs->ideal_viewangles);\n\t\t\t}\n\t\t\tbs->ideal_viewangles[2] *= 0.5;\n\t\t}\n\t}\n\t//if the weapon is used for the bot movement\n\tif (moveresult.flags & MOVERESULT_MOVEMENTWEAPON) bs->weaponnum = moveresult.weapon;\n\t//attack the enemy if possible\n\tBotCheckAttack(bs);\n\t//\n\treturn qtrue;\n}\n\n/*\n==================\nAIEnter_Battle_NBG\n==================\n*/\nvoid AIEnter_Battle_NBG(bot_state_t *bs, char *s) {\n\tBotRecordNodeSwitch(bs, \"battle NBG\", \"\", s);\n\tbs->ainode = AINode_Battle_NBG;\n}\n\n/*\n==================\nAINode_Battle_NBG\n==================\n*/\nint AINode_Battle_NBG(bot_state_t *bs) {\n\tint areanum;\n\tbot_goal_t goal;\n\taas_entityinfo_t entinfo;\n\tbot_moveresult_t moveresult;\n\tfloat attack_skill;\n\tvec3_t target, dir;\n\n\tif (BotIsObserver(bs)) {\n\t\tAIEnter_Observer(bs, \"battle nbg: observer\");\n\t\treturn qfalse;\n\t}\n\t//if in the intermission\n\tif (BotIntermission(bs)) {\n\t\tAIEnter_Intermission(bs, \"battle nbg: intermission\");\n\t\treturn qfalse;\n\t}\n\t//respawn if dead\n\tif (BotIsDead(bs)) {\n\t\tAIEnter_Respawn(bs, \"battle nbg: bot dead\");\n\t\treturn qfalse;\n\t}\n\t//if no enemy\n\tif (bs->enemy < 0) {\n\t\tAIEnter_Seek_NBG(bs, \"battle nbg: no enemy\");\n\t\treturn qfalse;\n\t}\n\t//\n\tBotEntityInfo(bs->enemy, &entinfo);\n\tif (EntityIsDead(&entinfo)) {\n\t\tAIEnter_Seek_NBG(bs, \"battle nbg: enemy dead\");\n\t\treturn qfalse;\n\t}\n\t//\n\tbs->tfl = TFL_DEFAULT;\n\tif (bot_grapple.integer) bs->tfl |= TFL_GRAPPLEHOOK;\n\t//if in lava or slime the bot should be able to get out\n\tif (BotInLavaOrSlime(bs)) bs->tfl |= TFL_LAVA|TFL_SLIME;\n\t//\n\tif (BotCanAndWantsToRocketJump(bs)) {\n\t\tbs->tfl |= TFL_ROCKETJUMP;\n\t}\n\t//map specific code\n\tBotMapScripts(bs);\n\t//update the last time the enemy was visible\n\tif (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->enemy)) {\n\t\tbs->enemyvisible_time = FloatTime();\n\t\tVectorCopy(entinfo.origin, target);\n\t\t// if not a player enemy\n\t\tif (bs->enemy >= MAX_CLIENTS) {\n\t\t}\n\t\t//update the reachability area and origin if possible\n\t\tareanum = BotPointAreaNum(target);\n\t\tif (areanum && trap_AAS_AreaReachability(areanum)) {\n\t\t\tVectorCopy(target, bs->lastenemyorigin);\n\t\t\tbs->lastenemyareanum = areanum;\n\t\t}\n\t}\n\t//if the bot has no goal or touches the current goal\n\tif (!trap_BotGetTopGoal(bs->gs, &goal)) {\n\t\tbs->nbg_time = 0;\n\t}\n\telse if (BotReachedGoal(bs, &goal)) {\n\t\tbs->nbg_time = 0;\n\t}\n\t//\n\tif (bs->nbg_time < FloatTime()) {\n\t\t//pop the current goal from the stack\n\t\ttrap_BotPopGoal(bs->gs);\n\t\t//if the bot still has a goal\n\t\tif (trap_BotGetTopGoal(bs->gs, &goal))\n\t\t\tAIEnter_Battle_Retreat(bs, \"battle nbg: time out\");\n\t\telse\n\t\t\tAIEnter_Battle_Fight(bs, \"battle nbg: time out\");\n\t\t//\n\t\treturn qfalse;\n\t}\n\t//initialize the movement state\n\tBotSetupForMovement(bs);\n\t//move towards the goal\n\ttrap_BotMoveToGoal(&moveresult, bs->ms, &goal, bs->tfl);\n\t//if the movement failed\n\tif (moveresult.failure) {\n\t\t//reset the avoid reach, otherwise bot is stuck in current area\n\t\ttrap_BotResetAvoidReach(bs->ms);\n\t\t//BotAI_Print(PRT_MESSAGE, \"movement failure %d\\n\", moveresult.traveltype);\n\t\tbs->nbg_time = 0;\n\t}\n\t//\n\tBotAIBlocked(bs, &moveresult, qfalse);\n\t//update the attack inventory values\n\tBotUpdateBattleInventory(bs, bs->enemy);\n\t//choose the best weapon to fight with\n\tBotChooseWeapon(bs);\n\t//if the view is fixed for the movement\n\tif (moveresult.flags & (MOVERESULT_MOVEMENTVIEW|MOVERESULT_SWIMVIEW)) {\n\t\tVectorCopy(moveresult.ideal_viewangles, bs->ideal_viewangles);\n\t}\n\telse if (!(moveresult.flags & MOVERESULT_MOVEMENTVIEWSET)\n\t\t\t\t&& !(bs->flags & BFL_IDEALVIEWSET)) {\n\t\tattack_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_ATTACK_SKILL, 0, 1);\n\t\t//if the bot is skilled anough and the enemy is visible\n\t\tif (attack_skill > 0.3) {\n\t\t\t//&& BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->enemy)\n\t\t\tBotAimAtEnemy(bs);\n\t\t}\n\t\telse {\n\t\t\tif (trap_BotMovementViewTarget(bs->ms, &goal, bs->tfl, 300, target)) {\n\t\t\t\tVectorSubtract(target, bs->origin, dir);\n\t\t\t\tvectoangles(dir, bs->ideal_viewangles);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tvectoangles(moveresult.movedir, bs->ideal_viewangles);\n\t\t\t}\n\t\t\tbs->ideal_viewangles[2] *= 0.5;\n\t\t}\n\t}\n\t//if the weapon is used for the bot movement\n\tif (moveresult.flags & MOVERESULT_MOVEMENTWEAPON) bs->weaponnum = moveresult.weapon;\n\t//attack the enemy if possible\n\tBotCheckAttack(bs);\n\t//\n\treturn qtrue;\n}\n\n"
  },
  {
    "path": "src/game/ai_dmnet.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n\n/*****************************************************************************\n * name:\t\tai_dmnet.h\n *\n * desc:\t\tQuake3 bot AI\n *\n * $Archive: /source/code/botai/ai_chat.c $\n *\n *****************************************************************************/\n\n#define MAX_NODESWITCHES\t50\n\nvoid AIEnter_Intermission(bot_state_t *bs, char *s);\nvoid AIEnter_Observer(bot_state_t *bs, char *s);\nvoid AIEnter_Respawn(bot_state_t *bs, char *s);\nvoid AIEnter_Stand(bot_state_t *bs, char *s);\nvoid AIEnter_Seek_ActivateEntity(bot_state_t *bs, char *s);\nvoid AIEnter_Seek_NBG(bot_state_t *bs, char *s);\nvoid AIEnter_Seek_LTG(bot_state_t *bs, char *s);\nvoid AIEnter_Seek_Camp(bot_state_t *bs, char *s);\nvoid AIEnter_Battle_Fight(bot_state_t *bs, char *s);\nvoid AIEnter_Battle_Chase(bot_state_t *bs, char *s);\nvoid AIEnter_Battle_Retreat(bot_state_t *bs, char *s);\nvoid AIEnter_Battle_NBG(bot_state_t *bs, char *s);\nint AINode_Intermission(bot_state_t *bs);\nint AINode_Observer(bot_state_t *bs);\nint AINode_Respawn(bot_state_t *bs);\nint AINode_Stand(bot_state_t *bs);\nint AINode_Seek_ActivateEntity(bot_state_t *bs);\nint AINode_Seek_NBG(bot_state_t *bs);\nint AINode_Seek_LTG(bot_state_t *bs);\nint AINode_Battle_Fight(bot_state_t *bs);\nint AINode_Battle_Chase(bot_state_t *bs);\nint AINode_Battle_Retreat(bot_state_t *bs);\nint AINode_Battle_NBG(bot_state_t *bs);\n\nvoid BotResetNodeSwitches(void);\nvoid BotDumpNodeSwitches(bot_state_t *bs);\n\n"
  },
  {
    "path": "src/game/ai_dmq3.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n\n/*****************************************************************************\n * name:\t\tai_dmq3.c\n *\n * desc:\t\tQuake3 bot AI\n *\n * $Archive: /MissionPack/code/game/ai_dmq3.c $\n *\n *****************************************************************************/\n\n\n#include \"g_local.h\"\n#include \"botlib.h\"\n#include \"be_aas.h\"\n#include \"be_ea.h\"\n#include \"be_ai_char.h\"\n#include \"be_ai_chat.h\"\n#include \"be_ai_gen.h\"\n#include \"be_ai_goal.h\"\n#include \"be_ai_move.h\"\n#include \"be_ai_weap.h\"\n//\n#include \"ai_main.h\"\n#include \"ai_dmq3.h\"\n#include \"ai_chat.h\"\n#include \"ai_cmd.h\"\n#include \"ai_dmnet.h\"\n#include \"ai_team.h\"\n//\n#include \"chars.h\"\t\t\t\t//characteristics\n#include \"inv.h\"\t\t\t\t//indexes into the inventory\n#include \"syn.h\"\t\t\t\t//synonyms\n#include \"match.h\"\t\t\t\t//string matching types and vars\n\n// for the voice chats\n#include \"menudef.h\" // sos001205 - for q3_ui also\n\n// from aasfile.h\n#define AREACONTENTS_MOVER\t\t\t\t1024\n#define AREACONTENTS_MODELNUMSHIFT\t\t24\n#define AREACONTENTS_MAXMODELNUM\t\t0xFF\n#define AREACONTENTS_MODELNUM\t\t\t(AREACONTENTS_MAXMODELNUM << AREACONTENTS_MODELNUMSHIFT)\n\n#define IDEAL_ATTACKDIST\t\t\t140\n\n#define MAX_WAYPOINTS\t\t128\n//\nbot_waypoint_t botai_waypoints[MAX_WAYPOINTS];\nbot_waypoint_t *botai_freewaypoints;\n\n//NOTE: not using a cvars which can be updated because the game should be reloaded anyway\nint gametype;\t\t//game type\nint maxclients;\t\t//maximum number of clients\n\nvmCvar_t bot_grapple;\nvmCvar_t bot_rocketjump;\nvmCvar_t bot_fastchat;\nvmCvar_t bot_nochat;\nvmCvar_t bot_testrchat;\nvmCvar_t bot_challenge;\nvmCvar_t bot_predictobstacles;\nvmCvar_t g_spSkill;\n\nextern vmCvar_t bot_developer;\n\nvec3_t lastteleport_origin;\t\t//last teleport event origin\nfloat lastteleport_time;\t\t//last teleport event time\nint max_bspmodelindex;\t\t\t//maximum BSP model index\n\n//CTF flag goals\nbot_goal_t ctf_redflag;\nbot_goal_t ctf_blueflag;\n\n#define MAX_ALTROUTEGOALS\t\t32\n\nint altroutegoals_setup;\naas_altroutegoal_t red_altroutegoals[MAX_ALTROUTEGOALS];\nint red_numaltroutegoals;\naas_altroutegoal_t blue_altroutegoals[MAX_ALTROUTEGOALS];\nint blue_numaltroutegoals;\n\n\n/*\n==================\nBotSetUserInfo\n==================\n*/\nvoid BotSetUserInfo(bot_state_t *bs, char *key, char *value) {\n\tchar userinfo[MAX_INFO_STRING];\n\n\ttrap_GetUserinfo(bs->client, userinfo, sizeof(userinfo));\n\tInfo_SetValueForKey(userinfo, key, value);\n\ttrap_SetUserinfo(bs->client, userinfo);\n\tClientUserinfoChanged( bs->client );\n}\n\n/*\n==================\nBotCTFCarryingFlag\n==================\n*/\nint BotCTFCarryingFlag(bot_state_t *bs) {\n\tif (gametype != GT_CTF) return CTF_FLAG_NONE;\n\n\tif (bs->inventory[INVENTORY_REDFLAG] > 0) return CTF_FLAG_RED;\n\telse if (bs->inventory[INVENTORY_BLUEFLAG] > 0) return CTF_FLAG_BLUE;\n\treturn CTF_FLAG_NONE;\n}\n\n/*\n==================\nBotTeam\n==================\n*/\nint BotTeam(bot_state_t *bs) {\n\tchar info[1024];\n\n\tif (bs->client < 0 || bs->client >= MAX_CLIENTS) {\n\t\t//BotAI_Print(PRT_ERROR, \"BotCTFTeam: client out of range\\n\");\n\t\treturn qfalse;\n\t}\n\ttrap_GetConfigstring(CS_PLAYERS+bs->client, info, sizeof(info));\n\t//\n\tif (atoi(Info_ValueForKey(info, \"t\")) == TEAM_RED) return TEAM_RED;\n\telse if (atoi(Info_ValueForKey(info, \"t\")) == TEAM_BLUE) return TEAM_BLUE;\n\treturn TEAM_FREE;\n}\n\n/*\n==================\nBotOppositeTeam\n==================\n*/\nint BotOppositeTeam(bot_state_t *bs) {\n\tswitch(BotTeam(bs)) {\n\t\tcase TEAM_RED: return TEAM_BLUE;\n\t\tcase TEAM_BLUE: return TEAM_RED;\n\t\tdefault: return TEAM_FREE;\n\t}\n}\n\n/*\n==================\nBotEnemyFlag\n==================\n*/\nbot_goal_t *BotEnemyFlag(bot_state_t *bs) {\n\tif (BotTeam(bs) == TEAM_RED) {\n\t\treturn &ctf_blueflag;\n\t}\n\telse {\n\t\treturn &ctf_redflag;\n\t}\n}\n\n/*\n==================\nBotTeamFlag\n==================\n*/\nbot_goal_t *BotTeamFlag(bot_state_t *bs) {\n\tif (BotTeam(bs) == TEAM_RED) {\n\t\treturn &ctf_redflag;\n\t}\n\telse {\n\t\treturn &ctf_blueflag;\n\t}\n}\n\n\n/*\n==================\nEntityIsDead\n==================\n*/\nqboolean EntityIsDead(aas_entityinfo_t *entinfo) {\n\tplayerState_t ps;\n\n\tif (entinfo->number >= 0 && entinfo->number < MAX_CLIENTS) {\n\t\t//retrieve the current client state\n\t\tBotAI_GetClientState( entinfo->number, &ps );\n\t\tif (ps.pm_type != PM_NORMAL) return qtrue;\n\t}\n\treturn qfalse;\n}\n\n/*\n==================\nEntityCarriesFlag\n==================\n*/\nqboolean EntityCarriesFlag(aas_entityinfo_t *entinfo) {\n\tif ( entinfo->powerups & ( 1 << PW_REDFLAG ) )\n\t\treturn qtrue;\n\tif ( entinfo->powerups & ( 1 << PW_BLUEFLAG ) )\n\t\treturn qtrue;\n\treturn qfalse;\n}\n\n/*\n==================\nEntityIsInvisible\n==================\n*/\nqboolean EntityIsInvisible(aas_entityinfo_t *entinfo) {\n\t// the flag is always visible\n\tif (EntityCarriesFlag(entinfo)) {\n\t\treturn qfalse;\n\t}\n\tif (entinfo->powerups & (1 << PW_INVIS)) {\n\t\treturn qtrue;\n\t}\n\treturn qfalse;\n}\n\n/*\n==================\nEntityIsShooting\n==================\n*/\nqboolean EntityIsShooting(aas_entityinfo_t *entinfo) {\n\tif (entinfo->flags & EF_FIRING) {\n\t\treturn qtrue;\n\t}\n\treturn qfalse;\n}\n\n/*\n==================\nEntityIsChatting\n==================\n*/\nqboolean EntityIsChatting(aas_entityinfo_t *entinfo) {\n\tif (entinfo->flags & EF_TALK) {\n\t\treturn qtrue;\n\t}\n\treturn qfalse;\n}\n\n/*\n==================\nEntityHasQuad\n==================\n*/\nqboolean EntityHasQuad(aas_entityinfo_t *entinfo) {\n\tif (entinfo->powerups & (1 << PW_QUAD)) {\n\t\treturn qtrue;\n\t}\n\treturn qfalse;\n}\n\n/*\n==================\nBotRememberLastOrderedTask\n==================\n*/\nvoid BotRememberLastOrderedTask(bot_state_t *bs) {\n\tif (!bs->ordered) {\n\t\treturn;\n\t}\n\tbs->lastgoal_decisionmaker = bs->decisionmaker;\n\tbs->lastgoal_ltgtype = bs->ltgtype;\n\tmemcpy(&bs->lastgoal_teamgoal, &bs->teamgoal, sizeof(bot_goal_t));\n\tbs->lastgoal_teammate = bs->teammate;\n}\n\n/*\n==================\nBotSetTeamStatus\n==================\n*/\nvoid BotSetTeamStatus(bot_state_t *bs) {\n}\n\n/*\n==================\nBotSetLastOrderedTask\n==================\n*/\nint BotSetLastOrderedTask(bot_state_t *bs) {\n\n\tif (gametype == GT_CTF) {\n\t\t// don't go back to returning the flag if it's at the base\n\t\tif ( bs->lastgoal_ltgtype == LTG_RETURNFLAG ) {\n\t\t\tif ( BotTeam(bs) == TEAM_RED ) {\n\t\t\t\tif ( bs->redflagstatus == 0 ) {\n\t\t\t\t\tbs->lastgoal_ltgtype = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif ( bs->blueflagstatus == 0 ) {\n\t\t\t\t\tbs->lastgoal_ltgtype = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif ( bs->lastgoal_ltgtype ) {\n\t\tbs->decisionmaker = bs->lastgoal_decisionmaker;\n\t\tbs->ordered = qtrue;\n\t\tbs->ltgtype = bs->lastgoal_ltgtype;\n\t\tmemcpy(&bs->teamgoal, &bs->lastgoal_teamgoal, sizeof(bot_goal_t));\n\t\tbs->teammate = bs->lastgoal_teammate;\n\t\tbs->teamgoal_time = FloatTime() + 300;\n\t\tBotSetTeamStatus(bs);\n\t\t//\n\t\tif ( gametype == GT_CTF ) {\n\t\t\tif ( bs->ltgtype == LTG_GETFLAG ) {\n\t\t\t\tbot_goal_t *tb, *eb;\n\t\t\t\tint tt, et;\n\n\t\t\t\ttb = BotTeamFlag(bs);\n\t\t\t\teb = BotEnemyFlag(bs);\n\t\t\t\ttt = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, tb->areanum, TFL_DEFAULT);\n\t\t\t\tet = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, eb->areanum, TFL_DEFAULT);\n\t\t\t\t// if the travel time towards the enemy base is larger than towards our base\n\t\t\t\tif (et > tt) {\n\t\t\t\t\t//get an alternative route goal towards the enemy base\n\t\t\t\t\tBotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn qtrue;\n\t}\n\treturn qfalse;\n}\n\n/*\n==================\nBotRefuseOrder\n==================\n*/\nvoid BotRefuseOrder(bot_state_t *bs) {\n\tif (!bs->ordered)\n\t\treturn;\n\t// if the bot was ordered to do something\n\tif ( bs->order_time && bs->order_time > FloatTime() - 10 ) {\n\t\ttrap_EA_Action(bs->client, ACTION_NEGATIVE);\n\t\tBotVoiceChat(bs, bs->decisionmaker, VOICECHAT_NO);\n\t\tbs->order_time = 0;\n\t}\n}\n\n/*\n==================\nBotCTFSeekGoals\n==================\n*/\nvoid BotCTFSeekGoals(bot_state_t *bs) {\n\tfloat rnd, l1, l2;\n\tint flagstatus, c;\n\tvec3_t dir;\n\taas_entityinfo_t entinfo;\n\n\t//when carrying a flag in ctf the bot should rush to the base\n\tif (BotCTFCarryingFlag(bs)) {\n\t\t//if not already rushing to the base\n\t\tif (bs->ltgtype != LTG_RUSHBASE) {\n\t\t\tBotRefuseOrder(bs);\n\t\t\tbs->ltgtype = LTG_RUSHBASE;\n\t\t\tbs->teamgoal_time = FloatTime() + CTF_RUSHBASE_TIME;\n\t\t\tbs->rushbaseaway_time = 0;\n\t\t\tbs->decisionmaker = bs->client;\n\t\t\tbs->ordered = qfalse;\n\t\t\t//\n\t\t\tswitch(BotTeam(bs)) {\n\t\t\t\tcase TEAM_RED: VectorSubtract(bs->origin, ctf_blueflag.origin, dir); break;\n\t\t\t\tcase TEAM_BLUE: VectorSubtract(bs->origin, ctf_redflag.origin, dir); break;\n\t\t\t\tdefault: VectorSet(dir, 999, 999, 999); break;\n\t\t\t}\n\t\t\t// if the bot picked up the flag very close to the enemy base\n\t\t\tif ( VectorLength(dir) < 128 ) {\n\t\t\t\t// get an alternative route goal through the enemy base\n\t\t\t\tBotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));\n\t\t\t} else {\n\t\t\t\t// don't use any alt route goal, just get the hell out of the base\n\t\t\t\tbs->altroutegoal.areanum = 0;\n\t\t\t}\n\t\t\tBotSetUserInfo(bs, \"teamtask\", va(\"%d\", TEAMTASK_OFFENSE));\n\t\t\tBotVoiceChat(bs, -1, VOICECHAT_IHAVEFLAG);\n\t\t}\n\t\telse if (bs->rushbaseaway_time > FloatTime()) {\n\t\t\tif (BotTeam(bs) == TEAM_RED) flagstatus = bs->redflagstatus;\n\t\t\telse flagstatus = bs->blueflagstatus;\n\t\t\t//if the flag is back\n\t\t\tif (flagstatus == 0) {\n\t\t\t\tbs->rushbaseaway_time = 0;\n\t\t\t}\n\t\t}\n\t\treturn;\n\t}\n\t// if the bot decided to follow someone\n\tif ( bs->ltgtype == LTG_TEAMACCOMPANY && !bs->ordered ) {\n\t\t// if the team mate being accompanied no longer carries the flag\n\t\tBotEntityInfo(bs->teammate, &entinfo);\n\t\tif (!EntityCarriesFlag(&entinfo)) {\n\t\t\tbs->ltgtype = 0;\n\t\t}\n\t}\n\t//\n\tif (BotTeam(bs) == TEAM_RED) flagstatus = bs->redflagstatus * 2 + bs->blueflagstatus;\n\telse flagstatus = bs->blueflagstatus * 2 + bs->redflagstatus;\n\t//if our team has the enemy flag and our flag is at the base\n\tif (flagstatus == 1) {\n\t\t//\n\t\tif (bs->owndecision_time < FloatTime()) {\n\t\t\t//if Not defending the base already\n\t\t\tif (!(bs->ltgtype == LTG_DEFENDKEYAREA &&\n\t\t\t\t\t(bs->teamgoal.number == ctf_redflag.number ||\n\t\t\t\t\tbs->teamgoal.number == ctf_blueflag.number))) {\n\t\t\t\t//if there is a visible team mate flag carrier\n\t\t\t\tc = BotTeamFlagCarrierVisible(bs);\n\t\t\t\tif (c >= 0 &&\n\t\t\t\t\t\t// and not already following the team mate flag carrier\n\t\t\t\t\t\t(bs->ltgtype != LTG_TEAMACCOMPANY || bs->teammate != c)) {\n\t\t\t\t\t//\n\t\t\t\t\tBotRefuseOrder(bs);\n\t\t\t\t\t//follow the flag carrier\n\t\t\t\t\tbs->decisionmaker = bs->client;\n\t\t\t\t\tbs->ordered = qfalse;\n\t\t\t\t\t//the team mate\n\t\t\t\t\tbs->teammate = c;\n\t\t\t\t\t//last time the team mate was visible\n\t\t\t\t\tbs->teammatevisible_time = FloatTime();\n\t\t\t\t\t//no message\n\t\t\t\t\tbs->teammessage_time = 0;\n\t\t\t\t\t//no arrive message\n\t\t\t\t\tbs->arrive_time = 1;\n\t\t\t\t\t//\n\t\t\t\t\tBotVoiceChat(bs, bs->teammate, VOICECHAT_ONFOLLOW);\n\t\t\t\t\t//get the team goal time\n\t\t\t\t\tbs->teamgoal_time = FloatTime() + TEAM_ACCOMPANY_TIME;\n\t\t\t\t\tbs->ltgtype = LTG_TEAMACCOMPANY;\n\t\t\t\t\tbs->formation_dist = 3.5 * 32;\t\t//3.5 meter\n\t\t\t\t\tBotSetTeamStatus(bs);\n\t\t\t\t\tbs->owndecision_time = FloatTime() + 5;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn;\n\t}\n\t//if the enemy has our flag\n\telse if (flagstatus == 2) {\n\t\t//\n\t\tif (bs->owndecision_time < FloatTime()) {\n\t\t\t//if enemy flag carrier is visible\n\t\t\tc = BotEnemyFlagCarrierVisible(bs);\n\t\t\tif (c >= 0) {\n\t\t\t\t//FIXME: fight enemy flag carrier\n\t\t\t}\n\t\t\t//if not already doing something important\n\t\t\tif (bs->ltgtype != LTG_GETFLAG &&\n\t\t\t\tbs->ltgtype != LTG_RETURNFLAG &&\n\t\t\t\tbs->ltgtype != LTG_TEAMHELP &&\n\t\t\t\tbs->ltgtype != LTG_TEAMACCOMPANY &&\n\t\t\t\tbs->ltgtype != LTG_CAMPORDER &&\n\t\t\t\tbs->ltgtype != LTG_PATROL &&\n\t\t\t\tbs->ltgtype != LTG_GETITEM) {\n\n\t\t\t\tBotRefuseOrder(bs);\n\t\t\t\tbs->decisionmaker = bs->client;\n\t\t\t\tbs->ordered = qfalse;\n\t\t\t\t//\n\t\t\t\tif (random() < 0.5) {\n\t\t\t\t\t//go for the enemy flag\n\t\t\t\t\tbs->ltgtype = LTG_GETFLAG;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tbs->ltgtype = LTG_RETURNFLAG;\n\t\t\t\t}\n\t\t\t\t//no team message\n\t\t\t\tbs->teammessage_time = 0;\n\t\t\t\t//set the time the bot will stop getting the flag\n\t\t\t\tbs->teamgoal_time = FloatTime() + CTF_GETFLAG_TIME;\n\t\t\t\t//get an alternative route goal towards the enemy base\n\t\t\t\tBotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));\n\t\t\t\t//\n\t\t\t\tBotSetTeamStatus(bs);\n\t\t\t\tbs->owndecision_time = FloatTime() + 5;\n\t\t\t}\n\t\t}\n\t\treturn;\n\t}\n\t//if both flags Not at their bases\n\telse if (flagstatus == 3) {\n\t\t//\n\t\tif (bs->owndecision_time < FloatTime()) {\n\t\t\t// if not trying to return the flag and not following the team flag carrier\n\t\t\tif ( bs->ltgtype != LTG_RETURNFLAG && bs->ltgtype != LTG_TEAMACCOMPANY ) {\n\t\t\t\t//\n\t\t\t\tc = BotTeamFlagCarrierVisible(bs);\n\t\t\t\t// if there is a visible team mate flag carrier\n\t\t\t\tif (c >= 0) {\n\t\t\t\t\tBotRefuseOrder(bs);\n\t\t\t\t\t//follow the flag carrier\n\t\t\t\t\tbs->decisionmaker = bs->client;\n\t\t\t\t\tbs->ordered = qfalse;\n\t\t\t\t\t//the team mate\n\t\t\t\t\tbs->teammate = c;\n\t\t\t\t\t//last time the team mate was visible\n\t\t\t\t\tbs->teammatevisible_time = FloatTime();\n\t\t\t\t\t//no message\n\t\t\t\t\tbs->teammessage_time = 0;\n\t\t\t\t\t//no arrive message\n\t\t\t\t\tbs->arrive_time = 1;\n\t\t\t\t\t//\n\t\t\t\t\tBotVoiceChat(bs, bs->teammate, VOICECHAT_ONFOLLOW);\n\t\t\t\t\t//get the team goal time\n\t\t\t\t\tbs->teamgoal_time = FloatTime() + TEAM_ACCOMPANY_TIME;\n\t\t\t\t\tbs->ltgtype = LTG_TEAMACCOMPANY;\n\t\t\t\t\tbs->formation_dist = 3.5 * 32;\t\t//3.5 meter\n\t\t\t\t\t//\n\t\t\t\t\tBotSetTeamStatus(bs);\n\t\t\t\t\tbs->owndecision_time = FloatTime() + 5;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tBotRefuseOrder(bs);\n\t\t\t\t\tbs->decisionmaker = bs->client;\n\t\t\t\t\tbs->ordered = qfalse;\n\t\t\t\t\t//get the enemy flag\n\t\t\t\t\tbs->teammessage_time = FloatTime() + 2 * random();\n\t\t\t\t\t//get the flag\n\t\t\t\t\tbs->ltgtype = LTG_RETURNFLAG;\n\t\t\t\t\t//set the time the bot will stop getting the flag\n\t\t\t\t\tbs->teamgoal_time = FloatTime() + CTF_RETURNFLAG_TIME;\n\t\t\t\t\t//get an alternative route goal towards the enemy base\n\t\t\t\t\tBotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));\n\t\t\t\t\t//\n\t\t\t\t\tBotSetTeamStatus(bs);\n\t\t\t\t\tbs->owndecision_time = FloatTime() + 5;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn;\n\t}\n\t// don't just do something wait for the bot team leader to give orders\n\tif (BotTeamLeader(bs)) {\n\t\treturn;\n\t}\n\t// if the bot is ordered to do something\n\tif ( bs->lastgoal_ltgtype ) {\n\t\tbs->teamgoal_time += 60;\n\t}\n\t// if the bot decided to do something on it's own and has a last ordered goal\n\tif ( !bs->ordered && bs->lastgoal_ltgtype ) {\n\t\tbs->ltgtype = 0;\n\t}\n\t//if already a CTF or team goal\n\tif (bs->ltgtype == LTG_TEAMHELP ||\n\t\t\tbs->ltgtype == LTG_TEAMACCOMPANY ||\n\t\t\tbs->ltgtype == LTG_DEFENDKEYAREA ||\n\t\t\tbs->ltgtype == LTG_GETFLAG ||\n\t\t\tbs->ltgtype == LTG_RUSHBASE ||\n\t\t\tbs->ltgtype == LTG_RETURNFLAG ||\n\t\t\tbs->ltgtype == LTG_CAMPORDER ||\n\t\t\tbs->ltgtype == LTG_PATROL ||\n\t\t\tbs->ltgtype == LTG_GETITEM ||\n\t\t\tbs->ltgtype == LTG_MAKELOVE_UNDER ||\n\t\t\tbs->ltgtype == LTG_MAKELOVE_ONTOP) {\n\t\treturn;\n\t}\n\t//\n\tif (BotSetLastOrderedTask(bs))\n\t\treturn;\n\t//\n\tif (bs->owndecision_time > FloatTime())\n\t\treturn;;\n\t//if the bot is roaming\n\tif (bs->ctfroam_time > FloatTime())\n\t\treturn;\n\t//if the bot has anough aggression to decide what to do\n\tif (BotAggression(bs) < 50)\n\t\treturn;\n\t//set the time to send a message to the team mates\n\tbs->teammessage_time = FloatTime() + 2 * random();\n\t//\n\tif (bs->teamtaskpreference & (TEAMTP_ATTACKER|TEAMTP_DEFENDER)) {\n\t\tif (bs->teamtaskpreference & TEAMTP_ATTACKER) {\n\t\t\tl1 = 0.7f;\n\t\t}\n\t\telse {\n\t\t\tl1 = 0.2f;\n\t\t}\n\t\tl2 = 0.9f;\n\t}\n\telse {\n\t\tl1 = 0.4f;\n\t\tl2 = 0.7f;\n\t}\n\t//get the flag or defend the base\n\trnd = random();\n\tif (rnd < l1 && ctf_redflag.areanum && ctf_blueflag.areanum) {\n\t\tbs->decisionmaker = bs->client;\n\t\tbs->ordered = qfalse;\n\t\tbs->ltgtype = LTG_GETFLAG;\n\t\t//set the time the bot will stop getting the flag\n\t\tbs->teamgoal_time = FloatTime() + CTF_GETFLAG_TIME;\n\t\t//get an alternative route goal towards the enemy base\n\t\tBotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));\n\t\tBotSetTeamStatus(bs);\n\t}\n\telse if (rnd < l2 && ctf_redflag.areanum && ctf_blueflag.areanum) {\n\t\tbs->decisionmaker = bs->client;\n\t\tbs->ordered = qfalse;\n\t\t//\n\t\tif (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &ctf_redflag, sizeof(bot_goal_t));\n\t\telse memcpy(&bs->teamgoal, &ctf_blueflag, sizeof(bot_goal_t));\n\t\t//set the ltg type\n\t\tbs->ltgtype = LTG_DEFENDKEYAREA;\n\t\t//set the time the bot stops defending the base\n\t\tbs->teamgoal_time = FloatTime() + TEAM_DEFENDKEYAREA_TIME;\n\t\tbs->defendaway_time = 0;\n\t\tBotSetTeamStatus(bs);\n\t}\n\telse {\n\t\tbs->ltgtype = 0;\n\t\t//set the time the bot will stop roaming\n\t\tbs->ctfroam_time = FloatTime() + CTF_ROAM_TIME;\n\t\tBotSetTeamStatus(bs);\n\t}\n\tbs->owndecision_time = FloatTime() + 5;\n#ifdef DEBUG\n\tBotPrintTeamGoal(bs);\n#endif //DEBUG\n}\n\n/*\n==================\nBotCTFRetreatGoals\n==================\n*/\nvoid BotCTFRetreatGoals(bot_state_t *bs) {\n\t//when carrying a flag in ctf the bot should rush to the base\n\tif (BotCTFCarryingFlag(bs)) {\n\t\t//if not already rushing to the base\n\t\tif (bs->ltgtype != LTG_RUSHBASE) {\n\t\t\tBotRefuseOrder(bs);\n\t\t\tbs->ltgtype = LTG_RUSHBASE;\n\t\t\tbs->teamgoal_time = FloatTime() + CTF_RUSHBASE_TIME;\n\t\t\tbs->rushbaseaway_time = 0;\n\t\t\tbs->decisionmaker = bs->client;\n\t\t\tbs->ordered = qfalse;\n\t\t\tBotSetTeamStatus(bs);\n\t\t}\n\t}\n}\n\n/*\n==================\nBotTeamGoals\n==================\n*/\nvoid BotTeamGoals(bot_state_t *bs, int retreat) {\n\n\tif ( retreat ) {\n\t\tif (gametype == GT_CTF) {\n\t\t\tBotCTFRetreatGoals(bs);\n\t\t}\n\t}\n\telse {\n\t\tif (gametype == GT_CTF) {\n\t\t\t//decide what to do in CTF mode\n\t\t\tBotCTFSeekGoals(bs);\n\t\t}\n\t}\n\t// reset the order time which is used to see if\n\t// we decided to refuse an order\n\tbs->order_time = 0;\n}\n\n/*\n==================\nBotPointAreaNum\n==================\n*/\nint BotPointAreaNum(vec3_t origin) {\n\tint areanum, numareas, areas[10];\n\tvec3_t end;\n\n\tareanum = trap_AAS_PointAreaNum(origin);\n\tif (areanum) return areanum;\n\tVectorCopy(origin, end);\n\tend[2] += 10;\n\tnumareas = trap_AAS_TraceAreas(origin, end, areas, NULL, 10);\n\tif (numareas > 0) return areas[0];\n\treturn 0;\n}\n\n/*\n==================\nClientName\n==================\n*/\nchar *ClientName(int client, char *name, int size) {\n\tchar buf[MAX_INFO_STRING];\n\n\tif (client < 0 || client >= MAX_CLIENTS) {\n\t\tBotAI_Print(PRT_ERROR, \"ClientName: client out of range\\n\");\n\t\treturn \"[client out of range]\";\n\t}\n\ttrap_GetConfigstring(CS_PLAYERS+client, buf, sizeof(buf));\n\tstrncpy(name, Info_ValueForKey(buf, \"n\"), size-1);\n\tname[size-1] = '\\0';\n\tQ_CleanStr( name );\n\treturn name;\n}\n\n/*\n==================\nClientSkin\n==================\n*/\nchar *ClientSkin(int client, char *skin, int size) {\n\tchar buf[MAX_INFO_STRING];\n\n\tif (client < 0 || client >= MAX_CLIENTS) {\n\t\tBotAI_Print(PRT_ERROR, \"ClientSkin: client out of range\\n\");\n\t\treturn \"[client out of range]\";\n\t}\n\ttrap_GetConfigstring(CS_PLAYERS+client, buf, sizeof(buf));\n\tstrncpy(skin, Info_ValueForKey(buf, \"model\"), size-1);\n\tskin[size-1] = '\\0';\n\treturn skin;\n}\n\n/*\n==================\nClientFromName\n==================\n*/\nint ClientFromName(char *name) {\n\tint i;\n\tchar buf[MAX_INFO_STRING];\n\tstatic int maxclients;\n\n\tif (!maxclients)\n\t\tmaxclients = trap_Cvar_VariableIntegerValue(\"sv_maxclients\");\n\tfor (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {\n\t\ttrap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));\n\t\tQ_CleanStr( buf );\n\t\tif (!Q_stricmp(Info_ValueForKey(buf, \"n\"), name)) return i;\n\t}\n\treturn -1;\n}\n\n/*\n==================\nClientOnSameTeamFromName\n==================\n*/\nint ClientOnSameTeamFromName(bot_state_t *bs, char *name) {\n\tint i;\n\tchar buf[MAX_INFO_STRING];\n\tstatic int maxclients;\n\n\tif (!maxclients)\n\t\tmaxclients = trap_Cvar_VariableIntegerValue(\"sv_maxclients\");\n\tfor (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {\n\t\tif (!BotSameTeam(bs, i))\n\t\t\tcontinue;\n\t\ttrap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));\n\t\tQ_CleanStr( buf );\n\t\tif (!Q_stricmp(Info_ValueForKey(buf, \"n\"), name)) return i;\n\t}\n\treturn -1;\n}\n\n/*\n==================\nstristr\n==================\n*/\nchar *stristr(char *str, char *charset) {\n\tint i;\n\n\twhile(*str) {\n\t\tfor (i = 0; charset[i] && str[i]; i++) {\n\t\t\tif (toupper(charset[i]) != toupper(str[i])) break;\n\t\t}\n\t\tif (!charset[i]) return str;\n\t\tstr++;\n\t}\n\treturn NULL;\n}\n\n/*\n==================\nEasyClientName\n==================\n*/\nchar *EasyClientName(int client, char *buf, int size) {\n\tint i;\n\tchar *str1, *str2, *ptr, c;\n\tchar name[128];\n\n\tstrcpy(name, ClientName(client, name, sizeof(name)));\n\tfor (i = 0; name[i]; i++) name[i] &= 127;\n\t//remove all spaces\n\tfor (ptr = strstr(name, \" \"); ptr; ptr = strstr(name, \" \")) {\n\t\tmemmove(ptr, ptr+1, (int)strlen(ptr+1)+1);\n\t}\n\t//check for [x] and ]x[ clan names\n\tstr1 = strstr(name, \"[\");\n\tstr2 = strstr(name, \"]\");\n\tif (str1 && str2) {\n\t\tif (str2 > str1) memmove(str1, str2+1, (int)strlen(str2+1)+1);\n\t\telse memmove(str2, str1+1, (int)strlen(str1+1)+1);\n\t}\n\t//remove Mr prefix\n\tif ((name[0] == 'm' || name[0] == 'M') &&\n\t\t\t(name[1] == 'r' || name[1] == 'R')) {\n\t\tmemmove(name, name+2, (int)strlen(name+2)+1);\n\t}\n\t//only allow lower case alphabet characters\n\tptr = name;\n\twhile(*ptr) {\n\t\tc = *ptr;\n\t\tif ((c >= 'a' && c <= 'z') ||\n\t\t\t\t(c >= '0' && c <= '9') || c == '_') {\n\t\t\tptr++;\n\t\t}\n\t\telse if (c >= 'A' && c <= 'Z') {\n\t\t\t*ptr += 'a' - 'A';\n\t\t\tptr++;\n\t\t}\n\t\telse {\n\t\t\tmemmove(ptr, ptr+1, (int)strlen(ptr + 1)+1);\n\t\t}\n\t}\n\tstrncpy(buf, name, size-1);\n\tbuf[size-1] = '\\0';\n\treturn buf;\n}\n\n/*\n==================\nBotSynonymContext\n==================\n*/\nint BotSynonymContext(bot_state_t *bs) {\n\tint context;\n\n\tcontext = CONTEXT_NORMAL|CONTEXT_NEARBYITEM|CONTEXT_NAMES;\n\t//\n\tif (gametype == GT_CTF\n\t\t) {\n\t\tif (BotTeam(bs) == TEAM_RED) context |= CONTEXT_CTFREDTEAM;\n\t\telse context |= CONTEXT_CTFBLUETEAM;\n\t}\n\treturn context;\n}\n\n/*\n==================\nBotChooseWeapon\n==================\n*/\nvoid BotChooseWeapon(bot_state_t *bs) {\n\tint newweaponnum;\n\n\tif (bs->cur_ps.weaponstate == WEAPON_RAISING ||\n\t\t\tbs->cur_ps.weaponstate == WEAPON_DROPPING) {\n\t\ttrap_EA_SelectWeapon(bs->client, bs->weaponnum);\n\t}\n\telse {\n\t\tnewweaponnum = trap_BotChooseBestFightWeapon(bs->ws, bs->inventory);\n\t\tif (bs->weaponnum != newweaponnum) bs->weaponchange_time = FloatTime();\n\t\tbs->weaponnum = newweaponnum;\n\t\t//BotAI_Print(PRT_MESSAGE, \"bs->weaponnum = %d\\n\", bs->weaponnum);\n\t\ttrap_EA_SelectWeapon(bs->client, bs->weaponnum);\n\t}\n}\n\n/*\n==================\nBotSetupForMovement\n==================\n*/\nvoid BotSetupForMovement(bot_state_t *bs) {\n\tbot_initmove_t initmove;\n\n\tmemset(&initmove, 0, sizeof(bot_initmove_t));\n\tVectorCopy(bs->cur_ps.origin, initmove.origin);\n\tVectorCopy(bs->cur_ps.velocity, initmove.velocity);\n\tVectorClear(initmove.viewoffset);\n\tinitmove.viewoffset[2] += bs->cur_ps.viewheight;\n\tinitmove.entitynum = bs->entitynum;\n\tinitmove.client = bs->client;\n\tinitmove.thinktime = bs->thinktime;\n\t//set the onground flag\n\tif (bs->cur_ps.groundEntityNum != ENTITYNUM_NONE) initmove.or_moveflags |= MFL_ONGROUND;\n\t//set the teleported flag\n\tif ((bs->cur_ps.pm_flags & PMF_TIME_KNOCKBACK) && (bs->cur_ps.pm_time > 0)) {\n\t\tinitmove.or_moveflags |= MFL_TELEPORTED;\n\t}\n\t//set the waterjump flag\n\tif ((bs->cur_ps.pm_flags & PMF_TIME_WATERJUMP) && (bs->cur_ps.pm_time > 0)) {\n\t\tinitmove.or_moveflags |= MFL_WATERJUMP;\n\t}\n\t//set presence type\n\tif (bs->cur_ps.pm_flags & PMF_DUCKED) initmove.presencetype = PRESENCE_CROUCH;\n\telse initmove.presencetype = PRESENCE_NORMAL;\n\t//\n\tif (bs->walker > 0.5) initmove.or_moveflags |= MFL_WALK;\n\t//\n\tVectorCopy(bs->viewangles, initmove.viewangles);\n\t//\n\ttrap_BotInitMoveState(bs->ms, &initmove);\n}\n\n/*\n==================\nBotCheckItemPickup\n==================\n*/\nvoid BotCheckItemPickup(bot_state_t *bs, int *oldinventory) {\n}\n\n/*\n==================\nBotUpdateInventory\n==================\n*/\nvoid BotUpdateInventory(bot_state_t *bs) {\n\tint oldinventory[MAX_ITEMS];\n\n\tmemcpy(oldinventory, bs->inventory, sizeof(oldinventory));\n\t//armor\n\tbs->inventory[INVENTORY_ARMOR] = bs->cur_ps.stats[STAT_ARMOR];\n\t//weapons\n\tbs->inventory[INVENTORY_GAUNTLET] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_GAUNTLET)) != 0;\n\tbs->inventory[INVENTORY_SHOTGUN] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_SHOTGUN)) != 0;\n\tbs->inventory[INVENTORY_MACHINEGUN] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_MACHINEGUN)) != 0;\n\tbs->inventory[INVENTORY_GRENADELAUNCHER] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_GRENADE_LAUNCHER)) != 0;\n\tbs->inventory[INVENTORY_ROCKETLAUNCHER] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_ROCKET_LAUNCHER)) != 0;\n\tbs->inventory[INVENTORY_LIGHTNING] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_LIGHTNING)) != 0;\n\tbs->inventory[INVENTORY_RAILGUN] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_RAILGUN)) != 0;\n\tbs->inventory[INVENTORY_PLASMAGUN] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_PLASMAGUN)) != 0;\n\tbs->inventory[INVENTORY_BFG10K] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_BFG)) != 0;\n\tbs->inventory[INVENTORY_GRAPPLINGHOOK] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_GRAPPLING_HOOK)) != 0;\n\t//ammo\n\tbs->inventory[INVENTORY_SHELLS] = bs->cur_ps.ammo[WP_SHOTGUN];\n\tbs->inventory[INVENTORY_BULLETS] = bs->cur_ps.ammo[WP_MACHINEGUN];\n\tbs->inventory[INVENTORY_GRENADES] = bs->cur_ps.ammo[WP_GRENADE_LAUNCHER];\n\tbs->inventory[INVENTORY_CELLS] = bs->cur_ps.ammo[WP_PLASMAGUN];\n\tbs->inventory[INVENTORY_LIGHTNINGAMMO] = bs->cur_ps.ammo[WP_LIGHTNING];\n\tbs->inventory[INVENTORY_ROCKETS] = bs->cur_ps.ammo[WP_ROCKET_LAUNCHER];\n\tbs->inventory[INVENTORY_SLUGS] = bs->cur_ps.ammo[WP_RAILGUN];\n\tbs->inventory[INVENTORY_BFGAMMO] = bs->cur_ps.ammo[WP_BFG];\n\t//powerups\n\tbs->inventory[INVENTORY_HEALTH] = bs->cur_ps.stats[STAT_HEALTH];\n\tbs->inventory[INVENTORY_TELEPORTER] = bs->cur_ps.stats[STAT_HOLDABLE_ITEM] == MODELINDEX_TELEPORTER;\n\tbs->inventory[INVENTORY_MEDKIT] = bs->cur_ps.stats[STAT_HOLDABLE_ITEM] == MODELINDEX_MEDKIT;\n\tbs->inventory[INVENTORY_QUAD] = bs->cur_ps.powerups[PW_QUAD] != 0;\n\tbs->inventory[INVENTORY_ENVIRONMENTSUIT] = bs->cur_ps.powerups[PW_BATTLESUIT] != 0;\n\tbs->inventory[INVENTORY_HASTE] = bs->cur_ps.powerups[PW_HASTE] != 0;\n\tbs->inventory[INVENTORY_INVISIBILITY] = bs->cur_ps.powerups[PW_INVIS] != 0;\n\tbs->inventory[INVENTORY_REGEN] = bs->cur_ps.powerups[PW_REGEN] != 0;\n\tbs->inventory[INVENTORY_FLIGHT] = bs->cur_ps.powerups[PW_FLIGHT] != 0;\n\tbs->inventory[INVENTORY_REDFLAG] = bs->cur_ps.powerups[PW_REDFLAG] != 0;\n\tbs->inventory[INVENTORY_BLUEFLAG] = bs->cur_ps.powerups[PW_BLUEFLAG] != 0;\n\n\tBotCheckItemPickup(bs, oldinventory);\n}\n\n/*\n==================\nBotUpdateBattleInventory\n==================\n*/\nvoid BotUpdateBattleInventory(bot_state_t *bs, int enemy) {\n\tvec3_t dir;\n\taas_entityinfo_t entinfo;\n\n\tBotEntityInfo(enemy, &entinfo);\n\tVectorSubtract(entinfo.origin, bs->origin, dir);\n\tbs->inventory[ENEMY_HEIGHT] = (int) dir[2];\n\tdir[2] = 0;\n\tbs->inventory[ENEMY_HORIZONTAL_DIST] = (int) VectorLength(dir);\n\t//FIXME: add num visible enemies and num visible team mates to the inventory\n}\n\n/*\n==================\nBotBattleUseItems\n==================\n*/\nvoid BotBattleUseItems(bot_state_t *bs) {\n\tif (bs->inventory[INVENTORY_HEALTH] < 40) {\n\t\tif (bs->inventory[INVENTORY_TELEPORTER] > 0) {\n\t\t\tif (!BotCTFCarryingFlag(bs)\n\t\t\t\t) {\n\t\t\t\ttrap_EA_Use(bs->client);\n\t\t\t}\n\t\t}\n\t}\n\tif (bs->inventory[INVENTORY_HEALTH] < 60) {\n\t\tif (bs->inventory[INVENTORY_MEDKIT] > 0) {\n\t\t\ttrap_EA_Use(bs->client);\n\t\t}\n\t}\n}\n\n/*\n==================\nBotSetTeleportTime\n==================\n*/\nvoid BotSetTeleportTime(bot_state_t *bs) {\n\tif ((bs->cur_ps.eFlags ^ bs->last_eFlags) & EF_TELEPORT_BIT) {\n\t\tbs->teleport_time = FloatTime();\n\t}\n\tbs->last_eFlags = bs->cur_ps.eFlags;\n}\n\n/*\n==================\nBotIsDead\n==================\n*/\nqboolean BotIsDead(bot_state_t *bs) {\n\treturn (bs->cur_ps.pm_type == PM_DEAD);\n}\n\n/*\n==================\nBotIsObserver\n==================\n*/\nqboolean BotIsObserver(bot_state_t *bs) {\n\tchar buf[MAX_INFO_STRING];\n\tif (bs->cur_ps.pm_type == PM_SPECTATOR) return qtrue;\n\ttrap_GetConfigstring(CS_PLAYERS+bs->client, buf, sizeof(buf));\n\tif (atoi(Info_ValueForKey(buf, \"t\")) == TEAM_SPECTATOR) return qtrue;\n\treturn qfalse;\n}\n\n/*\n==================\nBotIntermission\n==================\n*/\nqboolean BotIntermission(bot_state_t *bs) {\n\t//NOTE: we shouldn't be looking at the game code...\n\tif (level.intermissiontime) return qtrue;\n\treturn (bs->cur_ps.pm_type == PM_FREEZE || bs->cur_ps.pm_type == PM_INTERMISSION);\n}\n\n/*\n==================\nBotInLavaOrSlime\n==================\n*/\nqboolean BotInLavaOrSlime(bot_state_t *bs) {\n\tvec3_t feet;\n\n\tVectorCopy(bs->origin, feet);\n\tfeet[2] -= 23;\n\treturn (trap_AAS_PointContents(feet) & (CONTENTS_LAVA|CONTENTS_SLIME));\n}\n\n/*\n==================\nBotCreateWayPoint\n==================\n*/\nbot_waypoint_t *BotCreateWayPoint(char *name, vec3_t origin, int areanum) {\n\tbot_waypoint_t *wp;\n\tvec3_t waypointmins = {-8, -8, -8}, waypointmaxs = {8, 8, 8};\n\n\twp = botai_freewaypoints;\n\tif ( !wp ) {\n\t\tBotAI_Print( PRT_WARNING, \"BotCreateWayPoint: Out of waypoints\\n\" );\n\t\treturn NULL;\n\t}\n\tbotai_freewaypoints = botai_freewaypoints->next;\n\n\tQ_strncpyz( wp->name, name, sizeof(wp->name) );\n\tVectorCopy(origin, wp->goal.origin);\n\tVectorCopy(waypointmins, wp->goal.mins);\n\tVectorCopy(waypointmaxs, wp->goal.maxs);\n\twp->goal.areanum = areanum;\n\twp->next = NULL;\n\twp->prev = NULL;\n\treturn wp;\n}\n\n/*\n==================\nBotFindWayPoint\n==================\n*/\nbot_waypoint_t *BotFindWayPoint(bot_waypoint_t *waypoints, char *name) {\n\tbot_waypoint_t *wp;\n\n\tfor (wp = waypoints; wp; wp = wp->next) {\n\t\tif (!Q_stricmp(wp->name, name)) return wp;\n\t}\n\treturn NULL;\n}\n\n/*\n==================\nBotFreeWaypoints\n==================\n*/\nvoid BotFreeWaypoints(bot_waypoint_t *wp) {\n\tbot_waypoint_t *nextwp;\n\n\tfor (; wp; wp = nextwp) {\n\t\tnextwp = wp->next;\n\t\twp->next = botai_freewaypoints;\n\t\tbotai_freewaypoints = wp;\n\t}\n}\n\n/*\n==================\nBotInitWaypoints\n==================\n*/\nvoid BotInitWaypoints(void) {\n\tint i;\n\n\tbotai_freewaypoints = NULL;\n\tfor (i = 0; i < MAX_WAYPOINTS; i++) {\n\t\tbotai_waypoints[i].next = botai_freewaypoints;\n\t\tbotai_freewaypoints = &botai_waypoints[i];\n\t}\n}\n\n/*\n==================\nTeamPlayIsOn\n==================\n*/\nint TeamPlayIsOn(void) {\n\treturn ( gametype >= GT_TEAM );\n}\n\n/*\n==================\nBotAggression\n==================\n*/\nfloat BotAggression(bot_state_t *bs) {\n\t//if the bot has quad\n\tif (bs->inventory[INVENTORY_QUAD]) {\n\t\t//if the bot is not holding the gauntlet or the enemy is really nearby\n\t\tif (bs->weaponnum != WP_GAUNTLET ||\n\t\t\tbs->inventory[ENEMY_HORIZONTAL_DIST] < 80) {\n\t\t\treturn 70;\n\t\t}\n\t}\n\t//if the enemy is located way higher than the bot\n\tif (bs->inventory[ENEMY_HEIGHT] > 200) return 0;\n\t//if the bot is very low on health\n\tif (bs->inventory[INVENTORY_HEALTH] < 60) return 0;\n\t//if the bot is low on health\n\tif (bs->inventory[INVENTORY_HEALTH] < 80) {\n\t\t//if the bot has insufficient armor\n\t\tif (bs->inventory[INVENTORY_ARMOR] < 40) return 0;\n\t}\n\t//if the bot can use the bfg\n\tif (bs->inventory[INVENTORY_BFG10K] > 0 &&\n\t\t\tbs->inventory[INVENTORY_BFGAMMO] > 7) return 100;\n\t//if the bot can use the railgun\n\tif (bs->inventory[INVENTORY_RAILGUN] > 0 &&\n\t\t\tbs->inventory[INVENTORY_SLUGS] > 5) return 95;\n\t//if the bot can use the lightning gun\n\tif (bs->inventory[INVENTORY_LIGHTNING] > 0 &&\n\t\t\tbs->inventory[INVENTORY_LIGHTNINGAMMO] > 50) return 90;\n\t//if the bot can use the rocketlauncher\n\tif (bs->inventory[INVENTORY_ROCKETLAUNCHER] > 0 &&\n\t\t\tbs->inventory[INVENTORY_ROCKETS] > 5) return 90;\n\t//if the bot can use the plasmagun\n\tif (bs->inventory[INVENTORY_PLASMAGUN] > 0 &&\n\t\t\tbs->inventory[INVENTORY_CELLS] > 40) return 85;\n\t//if the bot can use the grenade launcher\n\tif (bs->inventory[INVENTORY_GRENADELAUNCHER] > 0 &&\n\t\t\tbs->inventory[INVENTORY_GRENADES] > 10) return 80;\n\t//if the bot can use the shotgun\n\tif (bs->inventory[INVENTORY_SHOTGUN] > 0 &&\n\t\t\tbs->inventory[INVENTORY_SHELLS] > 10) return 50;\n\t//otherwise the bot is not feeling too good\n\treturn 0;\n}\n\n/*\n==================\nBotFeelingBad\n==================\n*/\nfloat BotFeelingBad(bot_state_t *bs) {\n\tif (bs->weaponnum == WP_GAUNTLET) {\n\t\treturn 100;\n\t}\n\tif (bs->inventory[INVENTORY_HEALTH] < 40) {\n\t\treturn 100;\n\t}\n\tif (bs->weaponnum == WP_MACHINEGUN) {\n\t\treturn 90;\n\t}\n\tif (bs->inventory[INVENTORY_HEALTH] < 60) {\n\t\treturn 80;\n\t}\n\treturn 0;\n}\n\n/*\n==================\nBotWantsToRetreat\n==================\n*/\nint BotWantsToRetreat(bot_state_t *bs) {\n\taas_entityinfo_t entinfo;\n\n\tif (gametype == GT_CTF) {\n\t\t//always retreat when carrying a CTF flag\n\t\tif (BotCTFCarryingFlag(bs))\n\t\t\treturn qtrue;\n\t}\n\t//\n\tif (bs->enemy >= 0) {\n\t\t//if the enemy is carrying a flag\n\t\tBotEntityInfo(bs->enemy, &entinfo);\n\t\tif (EntityCarriesFlag(&entinfo))\n\t\t\treturn qfalse;\n\t}\n\t//if the bot is getting the flag\n\tif (bs->ltgtype == LTG_GETFLAG)\n\t\treturn qtrue;\n\t//\n\tif (BotAggression(bs) < 50)\n\t\treturn qtrue;\n\treturn qfalse;\n}\n\n/*\n==================\nBotWantsToChase\n==================\n*/\nint BotWantsToChase(bot_state_t *bs) {\n\taas_entityinfo_t entinfo;\n\n\tif (gametype == GT_CTF) {\n\t\t//never chase when carrying a CTF flag\n\t\tif (BotCTFCarryingFlag(bs))\n\t\t\treturn qfalse;\n\t\t//always chase if the enemy is carrying a flag\n\t\tBotEntityInfo(bs->enemy, &entinfo);\n\t\tif (EntityCarriesFlag(&entinfo))\n\t\t\treturn qtrue;\n\t}\n\t//if the bot is getting the flag\n\tif (bs->ltgtype == LTG_GETFLAG)\n\t\treturn qfalse;\n\t//\n\tif (BotAggression(bs) > 50)\n\t\treturn qtrue;\n\treturn qfalse;\n}\n\n/*\n==================\nBotWantsToHelp\n==================\n*/\nint BotWantsToHelp(bot_state_t *bs) {\n\treturn qtrue;\n}\n\n/*\n==================\nBotCanAndWantsToRocketJump\n==================\n*/\nint BotCanAndWantsToRocketJump(bot_state_t *bs) {\n\tfloat rocketjumper;\n\n\t//if rocket jumping is disabled\n\tif (!bot_rocketjump.integer) return qfalse;\n\t//if no rocket launcher\n\tif (bs->inventory[INVENTORY_ROCKETLAUNCHER] <= 0) return qfalse;\n\t//if low on rockets\n\tif (bs->inventory[INVENTORY_ROCKETS] < 3) return qfalse;\n\t//never rocket jump with the Quad\n\tif (bs->inventory[INVENTORY_QUAD]) return qfalse;\n\t//if low on health\n\tif (bs->inventory[INVENTORY_HEALTH] < 60) return qfalse;\n\t//if not full health\n\tif (bs->inventory[INVENTORY_HEALTH] < 90) {\n\t\t//if the bot has insufficient armor\n\t\tif (bs->inventory[INVENTORY_ARMOR] < 40) return qfalse;\n\t}\n\trocketjumper = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_WEAPONJUMPING, 0, 1);\n\tif (rocketjumper < 0.5) return qfalse;\n\treturn qtrue;\n}\n\n/*\n==================\nBotHasPersistantPowerupAndWeapon\n==================\n*/\nint BotHasPersistantPowerupAndWeapon(bot_state_t *bs) {\n\t//if the bot is very low on health\n\tif (bs->inventory[INVENTORY_HEALTH] < 60) return qfalse;\n\t//if the bot is low on health\n\tif (bs->inventory[INVENTORY_HEALTH] < 80) {\n\t\t//if the bot has insufficient armor\n\t\tif (bs->inventory[INVENTORY_ARMOR] < 40) return qfalse;\n\t}\n\t//if the bot can use the bfg\n\tif (bs->inventory[INVENTORY_BFG10K] > 0 &&\n\t\t\tbs->inventory[INVENTORY_BFGAMMO] > 7) return qtrue;\n\t//if the bot can use the railgun\n\tif (bs->inventory[INVENTORY_RAILGUN] > 0 &&\n\t\t\tbs->inventory[INVENTORY_SLUGS] > 5) return qtrue;\n\t//if the bot can use the lightning gun\n\tif (bs->inventory[INVENTORY_LIGHTNING] > 0 &&\n\t\t\tbs->inventory[INVENTORY_LIGHTNINGAMMO] > 50) return qtrue;\n\t//if the bot can use the rocketlauncher\n\tif (bs->inventory[INVENTORY_ROCKETLAUNCHER] > 0 &&\n\t\t\tbs->inventory[INVENTORY_ROCKETS] > 5) return qtrue;\n\t//\n\tif (bs->inventory[INVENTORY_NAILGUN] > 0 &&\n\t\t\tbs->inventory[INVENTORY_NAILS] > 5) return qtrue;\n\t//\n\tif (bs->inventory[INVENTORY_PROXLAUNCHER] > 0 &&\n\t\t\tbs->inventory[INVENTORY_MINES] > 5) return qtrue;\n\t//\n\tif (bs->inventory[INVENTORY_CHAINGUN] > 0 &&\n\t\t\tbs->inventory[INVENTORY_BELT] > 40) return qtrue;\n\t//if the bot can use the plasmagun\n\tif (bs->inventory[INVENTORY_PLASMAGUN] > 0 &&\n\t\t\tbs->inventory[INVENTORY_CELLS] > 20) return qtrue;\n\treturn qfalse;\n}\n\n/*\n==================\nBotGoCamp\n==================\n*/\nvoid BotGoCamp(bot_state_t *bs, bot_goal_t *goal) {\n\tfloat camper;\n\n\tbs->decisionmaker = bs->client;\n\t//set message time to zero so bot will NOT show any message\n\tbs->teammessage_time = 0;\n\t//set the ltg type\n\tbs->ltgtype = LTG_CAMP;\n\t//set the team goal\n\tmemcpy(&bs->teamgoal, goal, sizeof(bot_goal_t));\n\t//get the team goal time\n\tcamper = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CAMPER, 0, 1);\n\tif (camper > 0.99) bs->teamgoal_time = FloatTime() + 99999;\n\telse bs->teamgoal_time = FloatTime() + 120 + 180 * camper + random() * 15;\n\t//set the last time the bot started camping\n\tbs->camp_time = FloatTime();\n\t//the teammate that requested the camping\n\tbs->teammate = 0;\n\t//do NOT type arrive message\n\tbs->arrive_time = 1;\n}\n\n/*\n==================\nBotWantsToCamp\n==================\n*/\nint BotWantsToCamp(bot_state_t *bs) {\n\tfloat camper;\n\tint cs, traveltime, besttraveltime;\n\tbot_goal_t goal, bestgoal;\n\n\tcamper = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CAMPER, 0, 1);\n\tif (camper < 0.1) return qfalse;\n\t//if the bot has a team goal\n\tif (bs->ltgtype == LTG_TEAMHELP ||\n\t\t\tbs->ltgtype == LTG_TEAMACCOMPANY ||\n\t\t\tbs->ltgtype == LTG_DEFENDKEYAREA ||\n\t\t\tbs->ltgtype == LTG_GETFLAG ||\n\t\t\tbs->ltgtype == LTG_RUSHBASE ||\n\t\t\tbs->ltgtype == LTG_CAMP ||\n\t\t\tbs->ltgtype == LTG_CAMPORDER ||\n\t\t\tbs->ltgtype == LTG_PATROL) {\n\t\treturn qfalse;\n\t}\n\t//if camped recently\n\tif (bs->camp_time > FloatTime() - 60 + 300 * (1-camper)) return qfalse;\n\t//\n\tif (random() > camper) {\n\t\tbs->camp_time = FloatTime();\n\t\treturn qfalse;\n\t}\n\t//if the bot isn't healthy anough\n\tif (BotAggression(bs) < 50) return qfalse;\n\t//the bot should have at least have the rocket launcher, the railgun or the bfg10k with some ammo\n\tif ((bs->inventory[INVENTORY_ROCKETLAUNCHER] <= 0 || bs->inventory[INVENTORY_ROCKETS < 10]) &&\n\t\t(bs->inventory[INVENTORY_RAILGUN] <= 0 || bs->inventory[INVENTORY_SLUGS] < 10) &&\n\t\t(bs->inventory[INVENTORY_BFG10K] <= 0 || bs->inventory[INVENTORY_BFGAMMO] < 10)) {\n\t\treturn qfalse;\n\t}\n\t//find the closest camp spot\n\tbesttraveltime = 99999;\n\tfor (cs = trap_BotGetNextCampSpotGoal(0, &goal); cs; cs = trap_BotGetNextCampSpotGoal(cs, &goal)) {\n\t\ttraveltime = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, goal.areanum, TFL_DEFAULT);\n\t\tif (traveltime && traveltime < besttraveltime) {\n\t\t\tbesttraveltime = traveltime;\n\t\t\tmemcpy(&bestgoal, &goal, sizeof(bot_goal_t));\n\t\t}\n\t}\n\tif (besttraveltime > 150) return qfalse;\n\t//ok found a camp spot, go camp there\n\tBotGoCamp(bs, &bestgoal);\n\tbs->ordered = qfalse;\n\t//\n\treturn qtrue;\n}\n\n/*\n==================\nBotDontAvoid\n==================\n*/\nvoid BotDontAvoid(bot_state_t *bs, char *itemname) {\n\tbot_goal_t goal;\n\tint num;\n\n\tnum = trap_BotGetLevelItemGoal(-1, itemname, &goal);\n\twhile(num >= 0) {\n\t\ttrap_BotRemoveFromAvoidGoals(bs->gs, goal.number);\n\t\tnum = trap_BotGetLevelItemGoal(num, itemname, &goal);\n\t}\n}\n\n/*\n==================\nBotGoForPowerups\n==================\n*/\nvoid BotGoForPowerups(bot_state_t *bs) {\n\n\t//don't avoid any of the powerups anymore\n\tBotDontAvoid(bs, \"Quad Damage\");\n\tBotDontAvoid(bs, \"Regeneration\");\n\tBotDontAvoid(bs, \"Battle Suit\");\n\tBotDontAvoid(bs, \"Speed\");\n\tBotDontAvoid(bs, \"Invisibility\");\n\t//BotDontAvoid(bs, \"Flight\");\n\t//reset the long term goal time so the bot will go for the powerup\n\t//NOTE: the long term goal type doesn't change\n\tbs->ltg_time = 0;\n}\n\n/*\n==================\nBotRoamGoal\n==================\n*/\nvoid BotRoamGoal(bot_state_t *bs, vec3_t goal) {\n\tint pc, i;\n\tfloat len, rnd;\n\tvec3_t dir, bestorg, belowbestorg;\n\tbsp_trace_t trace;\n\n\tfor (i = 0; i < 10; i++) {\n\t\t//start at the bot origin\n\t\tVectorCopy(bs->origin, bestorg);\n\t\trnd = random();\n\t\tif (rnd > 0.25) {\n\t\t\t//add a random value to the x-coordinate\n\t\t\tif (random() < 0.5) bestorg[0] -= 800 * random() + 100;\n\t\t\telse bestorg[0] += 800 * random() + 100;\n\t\t}\n\t\tif (rnd < 0.75) {\n\t\t\t//add a random value to the y-coordinate\n\t\t\tif (random() < 0.5) bestorg[1] -= 800 * random() + 100;\n\t\t\telse bestorg[1] += 800 * random() + 100;\n\t\t}\n\t\t//add a random value to the z-coordinate (NOTE: 48 = maxjump?)\n\t\tbestorg[2] += 2 * 48 * crandom();\n\t\t//trace a line from the origin to the roam target\n\t\tBotAI_Trace(&trace, bs->origin, NULL, NULL, bestorg, bs->entitynum, MASK_SOLID);\n\t\t//direction and length towards the roam target\n\t\tVectorSubtract(trace.endpos, bs->origin, dir);\n\t\tlen = VectorNormalize(dir);\n\t\t//if the roam target is far away anough\n\t\tif (len > 200) {\n\t\t\t//the roam target is in the given direction before walls\n\t\t\tVectorScale(dir, len * trace.fraction - 40, dir);\n\t\t\tVectorAdd(bs->origin, dir, bestorg);\n\t\t\t//get the coordinates of the floor below the roam target\n\t\t\tbelowbestorg[0] = bestorg[0];\n\t\t\tbelowbestorg[1] = bestorg[1];\n\t\t\tbelowbestorg[2] = bestorg[2] - 800;\n\t\t\tBotAI_Trace(&trace, bestorg, NULL, NULL, belowbestorg, bs->entitynum, MASK_SOLID);\n\t\t\t//\n\t\t\tif (!trace.startsolid) {\n\t\t\t\ttrace.endpos[2]++;\n\t\t\t\tpc = trap_PointContents(trace.endpos, bs->entitynum);\n\t\t\t\tif (!(pc & (CONTENTS_LAVA | CONTENTS_SLIME))) {\n\t\t\t\t\tVectorCopy(bestorg, goal);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tVectorCopy(bestorg, goal);\n}\n\n/*\n==================\nBotAttackMove\n==================\n*/\nbot_moveresult_t BotAttackMove(bot_state_t *bs, int tfl) {\n\tint movetype, i, attackentity;\n\tfloat attack_skill, jumper, croucher, dist, strafechange_time;\n\tfloat attack_dist, attack_range;\n\tvec3_t forward, backward, sideward, hordir, up = {0, 0, 1};\n\taas_entityinfo_t entinfo;\n\tbot_moveresult_t moveresult;\n\tbot_goal_t goal;\n\n\tattackentity = bs->enemy;\n\t//\n\tif (bs->attackchase_time > FloatTime()) {\n\t\t//create the chase goal\n\t\tgoal.entitynum = attackentity;\n\t\tgoal.areanum = bs->lastenemyareanum;\n\t\tVectorCopy(bs->lastenemyorigin, goal.origin);\n\t\tVectorSet(goal.mins, -8, -8, -8);\n\t\tVectorSet(goal.maxs, 8, 8, 8);\n\t\t//initialize the movement state\n\t\tBotSetupForMovement(bs);\n\t\t//move towards the goal\n\t\ttrap_BotMoveToGoal(&moveresult, bs->ms, &goal, tfl);\n\t\treturn moveresult;\n\t}\n\t//\n\tmemset(&moveresult, 0, sizeof(bot_moveresult_t));\n\t//\n\tattack_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_ATTACK_SKILL, 0, 1);\n\tjumper = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_JUMPER, 0, 1);\n\tcroucher = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CROUCHER, 0, 1);\n\t//if the bot is really stupid\n\tif (attack_skill < 0.2) return moveresult;\n\t//initialize the movement state\n\tBotSetupForMovement(bs);\n\t//get the enemy entity info\n\tBotEntityInfo(attackentity, &entinfo);\n\t//direction towards the enemy\n\tVectorSubtract(entinfo.origin, bs->origin, forward);\n\t//the distance towards the enemy\n\tdist = VectorNormalize(forward);\n\tVectorNegate(forward, backward);\n\t//walk, crouch or jump\n\tmovetype = MOVE_WALK;\n\t//\n\tif (bs->attackcrouch_time < FloatTime() - 1) {\n\t\tif (random() < jumper) {\n\t\t\tmovetype = MOVE_JUMP;\n\t\t}\n\t\t//wait at least one second before crouching again\n\t\telse if (bs->attackcrouch_time < FloatTime() - 1 && random() < croucher) {\n\t\t\tbs->attackcrouch_time = FloatTime() + croucher * 5;\n\t\t}\n\t}\n\tif (bs->attackcrouch_time > FloatTime()) movetype = MOVE_CROUCH;\n\t//if the bot should jump\n\tif (movetype == MOVE_JUMP) {\n\t\t//if jumped last frame\n\t\tif (bs->attackjump_time > FloatTime()) {\n\t\t\tmovetype = MOVE_WALK;\n\t\t}\n\t\telse {\n\t\t\tbs->attackjump_time = FloatTime() + 1;\n\t\t}\n\t}\n\tif (bs->cur_ps.weapon == WP_GAUNTLET) {\n\t\tattack_dist = 0;\n\t\tattack_range = 0;\n\t}\n\telse {\n\t\tattack_dist = IDEAL_ATTACKDIST;\n\t\tattack_range = 40;\n\t}\n\t//if the bot is stupid\n\tif (attack_skill <= 0.4) {\n\t\t//just walk to or away from the enemy\n\t\tif (dist > attack_dist + attack_range) {\n\t\t\tif (trap_BotMoveInDirection(bs->ms, forward, 400, movetype)) return moveresult;\n\t\t}\n\t\tif (dist < attack_dist - attack_range) {\n\t\t\tif (trap_BotMoveInDirection(bs->ms, backward, 400, movetype)) return moveresult;\n\t\t}\n\t\treturn moveresult;\n\t}\n\t//increase the strafe time\n\tbs->attackstrafe_time += bs->thinktime;\n\t//get the strafe change time\n\tstrafechange_time = 0.4 + (1 - attack_skill) * 0.2;\n\tif (attack_skill > 0.7) strafechange_time += crandom() * 0.2;\n\t//if the strafe direction should be changed\n\tif (bs->attackstrafe_time > strafechange_time) {\n\t\t//some magic number :)\n\t\tif (random() > 0.935) {\n\t\t\t//flip the strafe direction\n\t\t\tbs->flags ^= BFL_STRAFERIGHT;\n\t\t\tbs->attackstrafe_time = 0;\n\t\t}\n\t}\n\t//\n\tfor (i = 0; i < 2; i++) {\n\t\thordir[0] = forward[0];\n\t\thordir[1] = forward[1];\n\t\thordir[2] = 0;\n\t\tVectorNormalize(hordir);\n\t\t//get the sideward vector\n\t\tCrossProduct(hordir, up, sideward);\n\t\t//reverse the vector depending on the strafe direction\n\t\tif (bs->flags & BFL_STRAFERIGHT) VectorNegate(sideward, sideward);\n\t\t//randomly go back a little\n\t\tif (random() > 0.9) {\n\t\t\tVectorAdd(sideward, backward, sideward);\n\t\t}\n\t\telse {\n\t\t\t//walk forward or backward to get at the ideal attack distance\n\t\t\tif (dist > attack_dist + attack_range) {\n\t\t\t\tVectorAdd(sideward, forward, sideward);\n\t\t\t}\n\t\t\telse if (dist < attack_dist - attack_range) {\n\t\t\t\tVectorAdd(sideward, backward, sideward);\n\t\t\t}\n\t\t}\n\t\t//perform the movement\n\t\tif (trap_BotMoveInDirection(bs->ms, sideward, 400, movetype))\n\t\t\treturn moveresult;\n\t\t//movement failed, flip the strafe direction\n\t\tbs->flags ^= BFL_STRAFERIGHT;\n\t\tbs->attackstrafe_time = 0;\n\t}\n\t//bot couldn't do any usefull movement\n//\tbs->attackchase_time = AAS_Time() + 6;\n\treturn moveresult;\n}\n\n/*\n==================\nBotSameTeam\n==================\n*/\nint BotSameTeam(bot_state_t *bs, int entnum) {\n\tchar info1[1024], info2[1024];\n\n\tif (bs->client < 0 || bs->client >= MAX_CLIENTS) {\n\t\t//BotAI_Print(PRT_ERROR, \"BotSameTeam: client out of range\\n\");\n\t\treturn qfalse;\n\t}\n\tif (entnum < 0 || entnum >= MAX_CLIENTS) {\n\t\t//BotAI_Print(PRT_ERROR, \"BotSameTeam: client out of range\\n\");\n\t\treturn qfalse;\n\t}\n\tif ( gametype >= GT_TEAM ) {\n\t\ttrap_GetConfigstring(CS_PLAYERS+bs->client, info1, sizeof(info1));\n\t\ttrap_GetConfigstring(CS_PLAYERS+entnum, info2, sizeof(info2));\n\t\t//\n\t\tif (atoi(Info_ValueForKey(info1, \"t\")) == atoi(Info_ValueForKey(info2, \"t\"))) return qtrue;\n\t}\n\treturn qfalse;\n}\n\n/*\n==================\nInFieldOfVision\n==================\n*/\nqboolean InFieldOfVision(vec3_t viewangles, float fov, vec3_t angles)\n{\n\tint i;\n\tfloat diff, angle;\n\n\tfor (i = 0; i < 2; i++) {\n\t\tangle = AngleMod(viewangles[i]);\n\t\tangles[i] = AngleMod(angles[i]);\n\t\tdiff = angles[i] - angle;\n\t\tif (angles[i] > angle) {\n\t\t\tif (diff > 180.0) diff -= 360.0;\n\t\t}\n\t\telse {\n\t\t\tif (diff < -180.0) diff += 360.0;\n\t\t}\n\t\tif (diff > 0) {\n\t\t\tif (diff > fov * 0.5) return qfalse;\n\t\t}\n\t\telse {\n\t\t\tif (diff < -fov * 0.5) return qfalse;\n\t\t}\n\t}\n\treturn qtrue;\n}\n\n/*\n==================\nBotEntityVisible\n\nreturns visibility in the range [0, 1] taking fog and water surfaces into account\n==================\n*/\nfloat BotEntityVisible(int viewer, vec3_t eye, vec3_t viewangles, float fov, int ent) {\n\tint i, contents_mask, passent, hitent, infog, inwater, otherinfog, pc;\n\tfloat squaredfogdist, waterfactor, vis, bestvis;\n\tbsp_trace_t trace;\n\taas_entityinfo_t entinfo;\n\tvec3_t dir, entangles, start, end, middle;\n\n\t//calculate middle of bounding box\n\tBotEntityInfo(ent, &entinfo);\n\tVectorAdd(entinfo.mins, entinfo.maxs, middle);\n\tVectorScale(middle, 0.5, middle);\n\tVectorAdd(entinfo.origin, middle, middle);\n\t//check if entity is within field of vision\n\tVectorSubtract(middle, eye, dir);\n\tvectoangles(dir, entangles);\n\tif (!InFieldOfVision(viewangles, fov, entangles)) return 0;\n\t//\n\tpc = trap_AAS_PointContents(eye);\n\tinfog = (pc & CONTENTS_FOG);\n\tinwater = (pc & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER));\n\t//\n\tbestvis = 0;\n\tfor (i = 0; i < 3; i++) {\n\t\t//if the point is not in potential visible sight\n\t\t//if (!AAS_inPVS(eye, middle)) continue;\n\t\t//\n\t\tcontents_mask = CONTENTS_SOLID|CONTENTS_PLAYERCLIP;\n\t\tpassent = viewer;\n\t\thitent = ent;\n\t\tVectorCopy(eye, start);\n\t\tVectorCopy(middle, end);\n\t\t//if the entity is in water, lava or slime\n\t\tif (trap_AAS_PointContents(middle) & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER)) {\n\t\t\tcontents_mask |= (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER);\n\t\t}\n\t\t//if eye is in water, lava or slime\n\t\tif (inwater) {\n\t\t\tif (!(contents_mask & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER))) {\n\t\t\t\tpassent = ent;\n\t\t\t\thitent = viewer;\n\t\t\t\tVectorCopy(middle, start);\n\t\t\t\tVectorCopy(eye, end);\n\t\t\t}\n\t\t\tcontents_mask ^= (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER);\n\t\t}\n\t\t//trace from start to end\n\t\tBotAI_Trace(&trace, start, NULL, NULL, end, passent, contents_mask);\n\t\t//if water was hit\n\t\twaterfactor = 1.0;\n\t\tif (trace.contents & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER)) {\n\t\t\t//if the water surface is translucent\n\t\t\tif (1) {\n\t\t\t\t//trace through the water\n\t\t\t\tcontents_mask &= ~(CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER);\n\t\t\t\tBotAI_Trace(&trace, trace.endpos, NULL, NULL, end, passent, contents_mask);\n\t\t\t\twaterfactor = 0.5;\n\t\t\t}\n\t\t}\n\t\t//if a full trace or the hitent was hit\n\t\tif (trace.fraction >= 1 || trace.ent == hitent) {\n\t\t\t//check for fog, assuming there's only one fog brush where\n\t\t\t//either the viewer or the entity is in or both are in\n\t\t\totherinfog = (trap_AAS_PointContents(middle) & CONTENTS_FOG);\n\t\t\tif (infog && otherinfog) {\n\t\t\t\tVectorSubtract(trace.endpos, eye, dir);\n\t\t\t\tsquaredfogdist = VectorLengthSquared(dir);\n\t\t\t}\n\t\t\telse if (infog) {\n\t\t\t\tVectorCopy(trace.endpos, start);\n\t\t\t\tBotAI_Trace(&trace, start, NULL, NULL, eye, viewer, CONTENTS_FOG);\n\t\t\t\tVectorSubtract(eye, trace.endpos, dir);\n\t\t\t\tsquaredfogdist = VectorLengthSquared(dir);\n\t\t\t}\n\t\t\telse if (otherinfog) {\n\t\t\t\tVectorCopy(trace.endpos, end);\n\t\t\t\tBotAI_Trace(&trace, eye, NULL, NULL, end, viewer, CONTENTS_FOG);\n\t\t\t\tVectorSubtract(end, trace.endpos, dir);\n\t\t\t\tsquaredfogdist = VectorLengthSquared(dir);\n\t\t\t}\n\t\t\telse {\n\t\t\t\t//if the entity and the viewer are not in fog assume there's no fog in between\n\t\t\t\tsquaredfogdist = 0;\n\t\t\t}\n\t\t\t//decrease visibility with the view distance through fog\n\t\t\tvis = 1 / ((squaredfogdist * 0.001) < 1 ? 1 : (squaredfogdist * 0.001));\n\t\t\t//if entering water visibility is reduced\n\t\t\tvis *= waterfactor;\n\t\t\t//\n\t\t\tif (vis > bestvis) bestvis = vis;\n\t\t\t//if pretty much no fog\n\t\t\tif (bestvis >= 0.95) return bestvis;\n\t\t}\n\t\t//check bottom and top of bounding box as well\n\t\tif (i == 0) middle[2] += entinfo.mins[2];\n\t\telse if (i == 1) middle[2] += entinfo.maxs[2] - entinfo.mins[2];\n\t}\n\treturn bestvis;\n}\n\n/*\n==================\nBotFindEnemy\n==================\n*/\nint BotFindEnemy(bot_state_t *bs, int curenemy) {\n\tint i, healthdecrease;\n\tfloat f, alertness, easyfragger, vis;\n\tfloat squaredist, cursquaredist;\n\taas_entityinfo_t entinfo, curenemyinfo;\n\tvec3_t dir, angles;\n\n\talertness = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_ALERTNESS, 0, 1);\n\teasyfragger = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_EASY_FRAGGER, 0, 1);\n\t//check if the health decreased\n\thealthdecrease = bs->lasthealth > bs->inventory[INVENTORY_HEALTH];\n\t//remember the current health value\n\tbs->lasthealth = bs->inventory[INVENTORY_HEALTH];\n\t//\n\tif (curenemy >= 0) {\n\t\tBotEntityInfo(curenemy, &curenemyinfo);\n\t\tif (EntityCarriesFlag(&curenemyinfo)) return qfalse;\n\t\tVectorSubtract(curenemyinfo.origin, bs->origin, dir);\n\t\tcursquaredist = VectorLengthSquared(dir);\n\t}\n\telse {\n\t\tcursquaredist = 0;\n\t}\n\t//\n\tfor (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {\n\n\t\tif (i == bs->client) continue;\n\t\t//if it's the current enemy\n\t\tif (i == curenemy) continue;\n\t\t//\n\t\tBotEntityInfo(i, &entinfo);\n\t\t//\n\t\tif (!entinfo.valid) continue;\n\t\t//if the enemy isn't dead and the enemy isn't the bot self\n\t\tif (EntityIsDead(&entinfo) || entinfo.number == bs->entitynum) continue;\n\t\t//if the enemy is invisible and not shooting\n\t\tif (EntityIsInvisible(&entinfo) && !EntityIsShooting(&entinfo)) {\n\t\t\tcontinue;\n\t\t}\n\t\t//if not an easy fragger don't shoot at chatting players\n\t\tif (easyfragger < 0.5 && EntityIsChatting(&entinfo)) continue;\n\t\t//\n\t\tif (lastteleport_time > FloatTime() - 3) {\n\t\t\tVectorSubtract(entinfo.origin, lastteleport_origin, dir);\n\t\t\tif (VectorLengthSquared(dir) < Square(70)) continue;\n\t\t}\n\t\t//calculate the distance towards the enemy\n\t\tVectorSubtract(entinfo.origin, bs->origin, dir);\n\t\tsquaredist = VectorLengthSquared(dir);\n\t\t//if this entity is not carrying a flag\n\t\tif (!EntityCarriesFlag(&entinfo))\n\t\t{\n\t\t\t//if this enemy is further away than the current one\n\t\t\tif (curenemy >= 0 && squaredist > cursquaredist) continue;\n\t\t} //end if\n\t\t//if the bot has no\n\t\tif (squaredist > Square(900.0 + alertness * 4000.0)) continue;\n\t\t//if on the same team\n\t\tif (BotSameTeam(bs, i)) continue;\n\t\t//if the bot's health decreased or the enemy is shooting\n\t\tif (curenemy < 0 && (healthdecrease || EntityIsShooting(&entinfo)))\n\t\t\tf = 360;\n\t\telse\n\t\t\tf = 90 + 90 - (90 - (squaredist > Square(810) ? Square(810) : squaredist) / (810 * 9));\n\t\t//check if the enemy is visible\n\t\tvis = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, f, i);\n\t\tif (vis <= 0) continue;\n\t\t//if the enemy is quite far away, not shooting and the bot is not damaged\n\t\tif (curenemy < 0 && squaredist > Square(100) && !healthdecrease && !EntityIsShooting(&entinfo))\n\t\t{\n\t\t\t//check if we can avoid this enemy\n\t\t\tVectorSubtract(bs->origin, entinfo.origin, dir);\n\t\t\tvectoangles(dir, angles);\n\t\t\t//if the bot isn't in the fov of the enemy\n\t\t\tif (!InFieldOfVision(entinfo.angles, 90, angles)) {\n\t\t\t\t//update some stuff for this enemy\n\t\t\t\tBotUpdateBattleInventory(bs, i);\n\t\t\t\t//if the bot doesn't really want to fight\n\t\t\t\tif (BotWantsToRetreat(bs)) continue;\n\t\t\t}\n\t\t}\n\t\t//found an enemy\n\t\tbs->enemy = entinfo.number;\n\t\tif (curenemy >= 0) bs->enemysight_time = FloatTime() - 2;\n\t\telse bs->enemysight_time = FloatTime();\n\t\tbs->enemysuicide = qfalse;\n\t\tbs->enemydeath_time = 0;\n\t\tbs->enemyvisible_time = FloatTime();\n\t\treturn qtrue;\n\t}\n\treturn qfalse;\n}\n\n/*\n==================\nBotTeamFlagCarrierVisible\n==================\n*/\nint BotTeamFlagCarrierVisible(bot_state_t *bs) {\n\tint i;\n\tfloat vis;\n\taas_entityinfo_t entinfo;\n\n\tfor (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {\n\t\tif (i == bs->client)\n\t\t\tcontinue;\n\t\t//\n\t\tBotEntityInfo(i, &entinfo);\n\t\t//if this player is active\n\t\tif (!entinfo.valid)\n\t\t\tcontinue;\n\t\t//if this player is carrying a flag\n\t\tif (!EntityCarriesFlag(&entinfo))\n\t\t\tcontinue;\n\t\t//if the flag carrier is not on the same team\n\t\tif (!BotSameTeam(bs, i))\n\t\t\tcontinue;\n\t\t//if the flag carrier is not visible\n\t\tvis = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, i);\n\t\tif (vis <= 0)\n\t\t\tcontinue;\n\t\t//\n\t\treturn i;\n\t}\n\treturn -1;\n}\n\n/*\n==================\nBotTeamFlagCarrier\n==================\n*/\nint BotTeamFlagCarrier(bot_state_t *bs) {\n\tint i;\n\taas_entityinfo_t entinfo;\n\n\tfor (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {\n\t\tif (i == bs->client)\n\t\t\tcontinue;\n\t\t//\n\t\tBotEntityInfo(i, &entinfo);\n\t\t//if this player is active\n\t\tif (!entinfo.valid)\n\t\t\tcontinue;\n\t\t//if this player is carrying a flag\n\t\tif (!EntityCarriesFlag(&entinfo))\n\t\t\tcontinue;\n\t\t//if the flag carrier is not on the same team\n\t\tif (!BotSameTeam(bs, i))\n\t\t\tcontinue;\n\t\t//\n\t\treturn i;\n\t}\n\treturn -1;\n}\n\n/*\n==================\nBotEnemyFlagCarrierVisible\n==================\n*/\nint BotEnemyFlagCarrierVisible(bot_state_t *bs) {\n\tint i;\n\tfloat vis;\n\taas_entityinfo_t entinfo;\n\n\tfor (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {\n\t\tif (i == bs->client)\n\t\t\tcontinue;\n\t\t//\n\t\tBotEntityInfo(i, &entinfo);\n\t\t//if this player is active\n\t\tif (!entinfo.valid)\n\t\t\tcontinue;\n\t\t//if this player is carrying a flag\n\t\tif (!EntityCarriesFlag(&entinfo))\n\t\t\tcontinue;\n\t\t//if the flag carrier is on the same team\n\t\tif (BotSameTeam(bs, i))\n\t\t\tcontinue;\n\t\t//if the flag carrier is not visible\n\t\tvis = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, i);\n\t\tif (vis <= 0)\n\t\t\tcontinue;\n\t\t//\n\t\treturn i;\n\t}\n\treturn -1;\n}\n\n/*\n==================\nBotVisibleTeamMatesAndEnemies\n==================\n*/\nvoid BotVisibleTeamMatesAndEnemies(bot_state_t *bs, int *teammates, int *enemies, float range) {\n\tint i;\n\tfloat vis;\n\taas_entityinfo_t entinfo;\n\tvec3_t dir;\n\n\tif (teammates)\n\t\t*teammates = 0;\n\tif (enemies)\n\t\t*enemies = 0;\n\tfor (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {\n\t\tif (i == bs->client)\n\t\t\tcontinue;\n\t\t//\n\t\tBotEntityInfo(i, &entinfo);\n\t\t//if this player is active\n\t\tif (!entinfo.valid)\n\t\t\tcontinue;\n\t\t//if this player is carrying a flag\n\t\tif (!EntityCarriesFlag(&entinfo))\n\t\t\tcontinue;\n\t\t//if not within range\n\t\tVectorSubtract(entinfo.origin, bs->origin, dir);\n\t\tif (VectorLengthSquared(dir) > Square(range))\n\t\t\tcontinue;\n\t\t//if the flag carrier is not visible\n\t\tvis = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, i);\n\t\tif (vis <= 0)\n\t\t\tcontinue;\n\t\t//if the flag carrier is on the same team\n\t\tif (BotSameTeam(bs, i)) {\n\t\t\tif (teammates)\n\t\t\t\t(*teammates)++;\n\t\t}\n\t\telse {\n\t\t\tif (enemies)\n\t\t\t\t(*enemies)++;\n\t\t}\n\t}\n}\n\n/*\n==================\nBotAimAtEnemy\n==================\n*/\nvoid BotAimAtEnemy(bot_state_t *bs) {\n\tint i, enemyvisible;\n\tfloat dist, f, aim_skill, aim_accuracy, speed, reactiontime;\n\tvec3_t dir, bestorigin, end, start, groundtarget, cmdmove, enemyvelocity;\n\tvec3_t mins = {-4,-4,-4}, maxs = {4, 4, 4};\n\tweaponinfo_t wi;\n\taas_entityinfo_t entinfo;\n\tbot_goal_t goal;\n\tbsp_trace_t trace;\n\tvec3_t target;\n\n\t//if the bot has no enemy\n\tif (bs->enemy < 0) {\n\t\treturn;\n\t}\n\t//get the enemy entity information\n\tBotEntityInfo(bs->enemy, &entinfo);\n\t//if this is not a player (should be an obelisk)\n\tif (bs->enemy >= MAX_CLIENTS) {\n\t\t//if the obelisk is visible\n\t\tVectorCopy(entinfo.origin, target);\n\t\t//aim at the obelisk\n\t\tVectorSubtract(target, bs->eye, dir);\n\t\tvectoangles(dir, bs->ideal_viewangles);\n\t\t//set the aim target before trying to attack\n\t\tVectorCopy(target, bs->aimtarget);\n\t\treturn;\n\t}\n\t//\n\t//BotAI_Print(PRT_MESSAGE, \"client %d: aiming at client %d\\n\", bs->entitynum, bs->enemy);\n\t//\n\taim_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_SKILL, 0, 1);\n\taim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY, 0, 1);\n\t//\n\tif (aim_skill > 0.95) {\n\t\t//don't aim too early\n\t\treactiontime = 0.5 * trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_REACTIONTIME, 0, 1);\n\t\tif (bs->enemysight_time > FloatTime() - reactiontime) return;\n\t\tif (bs->teleport_time > FloatTime() - reactiontime) return;\n\t}\n\n\t//get the weapon information\n\ttrap_BotGetWeaponInfo(bs->ws, bs->weaponnum, &wi);\n\t//get the weapon specific aim accuracy and or aim skill\n\tif (wi.number == WP_MACHINEGUN) {\n\t\taim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_MACHINEGUN, 0, 1);\n\t}\n\telse if (wi.number == WP_SHOTGUN) {\n\t\taim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_SHOTGUN, 0, 1);\n\t}\n\telse if (wi.number == WP_GRENADE_LAUNCHER) {\n\t\taim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_GRENADELAUNCHER, 0, 1);\n\t\taim_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_SKILL_GRENADELAUNCHER, 0, 1);\n\t}\n\telse if (wi.number == WP_ROCKET_LAUNCHER) {\n\t\taim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_ROCKETLAUNCHER, 0, 1);\n\t\taim_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_SKILL_ROCKETLAUNCHER, 0, 1);\n\t}\n\telse if (wi.number == WP_LIGHTNING) {\n\t\taim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_LIGHTNING, 0, 1);\n\t}\n\telse if (wi.number == WP_RAILGUN) {\n\t\taim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_RAILGUN, 0, 1);\n\t}\n\telse if (wi.number == WP_PLASMAGUN) {\n\t\taim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_PLASMAGUN, 0, 1);\n\t\taim_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_SKILL_PLASMAGUN, 0, 1);\n\t}\n\telse if (wi.number == WP_BFG) {\n\t\taim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_BFG10K, 0, 1);\n\t\taim_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_SKILL_BFG10K, 0, 1);\n\t}\n\t//\n\tif (aim_accuracy <= 0) aim_accuracy = 0.0001f;\n\t//get the enemy entity information\n\tBotEntityInfo(bs->enemy, &entinfo);\n\t//if the enemy is invisible then shoot crappy most of the time\n\tif (EntityIsInvisible(&entinfo)) {\n\t\tif (random() > 0.1) aim_accuracy *= 0.4f;\n\t}\n\t//\n\tVectorSubtract(entinfo.origin, entinfo.lastvisorigin, enemyvelocity);\n\tVectorScale(enemyvelocity, 1 / entinfo.update_time, enemyvelocity);\n\t//enemy origin and velocity is remembered every 0.5 seconds\n\tif (bs->enemyposition_time < FloatTime()) {\n\t\t//\n\t\tbs->enemyposition_time = FloatTime() + 0.5;\n\t\tVectorCopy(enemyvelocity, bs->enemyvelocity);\n\t\tVectorCopy(entinfo.origin, bs->enemyorigin);\n\t}\n\t//if not extremely skilled\n\tif (aim_skill < 0.9) {\n\t\tVectorSubtract(entinfo.origin, bs->enemyorigin, dir);\n\t\t//if the enemy moved a bit\n\t\tif (VectorLengthSquared(dir) > Square(48)) {\n\t\t\t//if the enemy changed direction\n\t\t\tif (DotProduct(bs->enemyvelocity, enemyvelocity) < 0) {\n\t\t\t\t//aim accuracy should be worse now\n\t\t\t\taim_accuracy *= 0.7f;\n\t\t\t}\n\t\t}\n\t}\n\t//check visibility of enemy\n\tenemyvisible = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->enemy);\n\t//if the enemy is visible\n\tif (enemyvisible) {\n\t\t//\n\t\tVectorCopy(entinfo.origin, bestorigin);\n\t\tbestorigin[2] += 8;\n\t\t//get the start point shooting from\n\t\t//NOTE: the x and y projectile start offsets are ignored\n\t\tVectorCopy(bs->origin, start);\n\t\tstart[2] += bs->cur_ps.viewheight;\n\t\tstart[2] += wi.offset[2];\n\t\t//\n\t\tBotAI_Trace(&trace, start, mins, maxs, bestorigin, bs->entitynum, MASK_SHOT);\n\t\t//if the enemy is NOT hit\n\t\tif (trace.fraction <= 1 && trace.ent != entinfo.number) {\n\t\t\tbestorigin[2] += 16;\n\t\t}\n\t\t//if it is not an instant hit weapon the bot might want to predict the enemy\n\t\tif (wi.speed) {\n\t\t\t//\n\t\t\tVectorSubtract(bestorigin, bs->origin, dir);\n\t\t\tdist = VectorLength(dir);\n\t\t\tVectorSubtract(entinfo.origin, bs->enemyorigin, dir);\n\t\t\t//if the enemy is NOT pretty far away and strafing just small steps left and right\n\t\t\tif (!(dist > 100 && VectorLengthSquared(dir) < Square(32))) {\n\t\t\t\t//if skilled anough do exact prediction\n\t\t\t\tif (aim_skill > 0.8 &&\n\t\t\t\t\t\t//if the weapon is ready to fire\n\t\t\t\t\t\tbs->cur_ps.weaponstate == WEAPON_READY) {\n\t\t\t\t\taas_clientmove_t move;\n\t\t\t\t\tvec3_t origin;\n\n\t\t\t\t\tVectorSubtract(entinfo.origin, bs->origin, dir);\n\t\t\t\t\t//distance towards the enemy\n\t\t\t\t\tdist = VectorLength(dir);\n\t\t\t\t\t//direction the enemy is moving in\n\t\t\t\t\tVectorSubtract(entinfo.origin, entinfo.lastvisorigin, dir);\n\t\t\t\t\t//\n\t\t\t\t\tVectorScale(dir, 1 / entinfo.update_time, dir);\n\t\t\t\t\t//\n\t\t\t\t\tVectorCopy(entinfo.origin, origin);\n\t\t\t\t\torigin[2] += 1;\n\t\t\t\t\t//\n\t\t\t\t\tVectorClear(cmdmove);\n\t\t\t\t\t//AAS_ClearShownDebugLines();\n\t\t\t\t\ttrap_AAS_PredictClientMovement(&move, bs->enemy, origin,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tPRESENCE_CROUCH, qfalse,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tdir, cmdmove, 0,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tdist * 10 / wi.speed, 0.1f, 0, 0, qfalse);\n\t\t\t\t\tVectorCopy(move.endpos, bestorigin);\n\t\t\t\t\t//BotAI_Print(PRT_MESSAGE, \"%1.1f predicted speed = %f, frames = %f\\n\", FloatTime(), VectorLength(dir), dist * 10 / wi.speed);\n\t\t\t\t}\n\t\t\t\t//if not that skilled do linear prediction\n\t\t\t\telse if (aim_skill > 0.4) {\n\t\t\t\t\tVectorSubtract(entinfo.origin, bs->origin, dir);\n\t\t\t\t\t//distance towards the enemy\n\t\t\t\t\tdist = VectorLength(dir);\n\t\t\t\t\t//direction the enemy is moving in\n\t\t\t\t\tVectorSubtract(entinfo.origin, entinfo.lastvisorigin, dir);\n\t\t\t\t\tdir[2] = 0;\n\t\t\t\t\t//\n\t\t\t\t\tspeed = VectorNormalize(dir) / entinfo.update_time;\n\t\t\t\t\t//botimport.Print(PRT_MESSAGE, \"speed = %f, wi->speed = %f\\n\", speed, wi->speed);\n\t\t\t\t\t//best spot to aim at\n\t\t\t\t\tVectorMA(entinfo.origin, (dist / wi.speed) * speed, dir, bestorigin);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t//if the projectile does radial damage\n\t\tif (aim_skill > 0.6 && wi.proj.damagetype & DAMAGETYPE_RADIAL) {\n\t\t\t//if the enemy isn't standing significantly higher than the bot\n\t\t\tif (entinfo.origin[2] < bs->origin[2] + 16) {\n\t\t\t\t//try to aim at the ground in front of the enemy\n\t\t\t\tVectorCopy(entinfo.origin, end);\n\t\t\t\tend[2] -= 64;\n\t\t\t\tBotAI_Trace(&trace, entinfo.origin, NULL, NULL, end, entinfo.number, MASK_SHOT);\n\t\t\t\t//\n\t\t\t\tVectorCopy(bestorigin, groundtarget);\n\t\t\t\tif (trace.startsolid) groundtarget[2] = entinfo.origin[2] - 16;\n\t\t\t\telse groundtarget[2] = trace.endpos[2] - 8;\n\t\t\t\t//trace a line from projectile start to ground target\n\t\t\t\tBotAI_Trace(&trace, start, NULL, NULL, groundtarget, bs->entitynum, MASK_SHOT);\n\t\t\t\t//if hitpoint is not vertically too far from the ground target\n\t\t\t\tif (fabs(trace.endpos[2] - groundtarget[2]) < 50) {\n\t\t\t\t\tVectorSubtract(trace.endpos, groundtarget, dir);\n\t\t\t\t\t//if the hitpoint is near anough the ground target\n\t\t\t\t\tif (VectorLengthSquared(dir) < Square(60)) {\n\t\t\t\t\t\tVectorSubtract(trace.endpos, start, dir);\n\t\t\t\t\t\t//if the hitpoint is far anough from the bot\n\t\t\t\t\t\tif (VectorLengthSquared(dir) > Square(100)) {\n\t\t\t\t\t\t\t//check if the bot is visible from the ground target\n\t\t\t\t\t\t\ttrace.endpos[2] += 1;\n\t\t\t\t\t\t\tBotAI_Trace(&trace, trace.endpos, NULL, NULL, entinfo.origin, entinfo.number, MASK_SHOT);\n\t\t\t\t\t\t\tif (trace.fraction >= 1) {\n\t\t\t\t\t\t\t\t//botimport.Print(PRT_MESSAGE, \"%1.1f aiming at ground\\n\", AAS_Time());\n\t\t\t\t\t\t\t\tVectorCopy(groundtarget, bestorigin);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tbestorigin[0] += 20 * crandom() * (1 - aim_accuracy);\n\t\tbestorigin[1] += 20 * crandom() * (1 - aim_accuracy);\n\t\tbestorigin[2] += 10 * crandom() * (1 - aim_accuracy);\n\t}\n\telse {\n\t\t//\n\t\tVectorCopy(bs->lastenemyorigin, bestorigin);\n\t\tbestorigin[2] += 8;\n\t\t//if the bot is skilled anough\n\t\tif (aim_skill > 0.5) {\n\t\t\t//do prediction shots around corners\n\t\t\tif (wi.number == WP_BFG ||\n\t\t\t\twi.number == WP_ROCKET_LAUNCHER ||\n\t\t\t\twi.number == WP_GRENADE_LAUNCHER) {\n\t\t\t\t//create the chase goal\n\t\t\t\tgoal.entitynum = bs->client;\n\t\t\t\tgoal.areanum = bs->areanum;\n\t\t\t\tVectorCopy(bs->eye, goal.origin);\n\t\t\t\tVectorSet(goal.mins, -8, -8, -8);\n\t\t\t\tVectorSet(goal.maxs, 8, 8, 8);\n\t\t\t\t//\n\t\t\t\tif (trap_BotPredictVisiblePosition(bs->lastenemyorigin, bs->lastenemyareanum, &goal, TFL_DEFAULT, target)) {\n\t\t\t\t\tVectorSubtract(target, bs->eye, dir);\n\t\t\t\t\tif (VectorLengthSquared(dir) > Square(80)) {\n\t\t\t\t\t\tVectorCopy(target, bestorigin);\n\t\t\t\t\t\tbestorigin[2] -= 20;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\taim_accuracy = 1;\n\t\t\t}\n\t\t}\n\t}\n\t//\n\tif (enemyvisible) {\n\t\tBotAI_Trace(&trace, bs->eye, NULL, NULL, bestorigin, bs->entitynum, MASK_SHOT);\n\t\tVectorCopy(trace.endpos, bs->aimtarget);\n\t}\n\telse {\n\t\tVectorCopy(bestorigin, bs->aimtarget);\n\t}\n\t//get aim direction\n\tVectorSubtract(bestorigin, bs->eye, dir);\n\t//\n\tif (wi.number == WP_MACHINEGUN ||\n\t\twi.number == WP_SHOTGUN ||\n\t\twi.number == WP_LIGHTNING ||\n\t\twi.number == WP_RAILGUN) {\n\t\t//distance towards the enemy\n\t\tdist = VectorLength(dir);\n\t\tif (dist > 150) dist = 150;\n\t\tf = 0.6 + dist / 150 * 0.4;\n\t\taim_accuracy *= f;\n\t}\n\t//add some random stuff to the aim direction depending on the aim accuracy\n\tif (aim_accuracy < 0.8) {\n\t\tVectorNormalize(dir);\n\t\tfor (i = 0; i < 3; i++) dir[i] += 0.3 * crandom() * (1 - aim_accuracy);\n\t}\n\t//set the ideal view angles\n\tvectoangles(dir, bs->ideal_viewangles);\n\t//take the weapon spread into account for lower skilled bots\n\tbs->ideal_viewangles[PITCH] += 6 * wi.vspread * crandom() * (1 - aim_accuracy);\n\tbs->ideal_viewangles[PITCH] = AngleMod(bs->ideal_viewangles[PITCH]);\n\tbs->ideal_viewangles[YAW] += 6 * wi.hspread * crandom() * (1 - aim_accuracy);\n\tbs->ideal_viewangles[YAW] = AngleMod(bs->ideal_viewangles[YAW]);\n\t//if the bots should be really challenging\n\tif (bot_challenge.integer) {\n\t\t//if the bot is really accurate and has the enemy in view for some time\n\t\tif (aim_accuracy > 0.9 && bs->enemysight_time < FloatTime() - 1) {\n\t\t\t//set the view angles directly\n\t\t\tif (bs->ideal_viewangles[PITCH] > 180) bs->ideal_viewangles[PITCH] -= 360;\n\t\t\tVectorCopy(bs->ideal_viewangles, bs->viewangles);\n\t\t\ttrap_EA_View(bs->client, bs->viewangles);\n\t\t}\n\t}\n}\n\n/*\n==================\nBotCheckAttack\n==================\n*/\nvoid BotCheckAttack(bot_state_t *bs) {\n\tfloat points, reactiontime, fov, firethrottle;\n\tint attackentity;\n\tbsp_trace_t bsptrace;\n\t//float selfpreservation;\n\tvec3_t forward, right, start, end, dir, angles;\n\tweaponinfo_t wi;\n\tbsp_trace_t trace;\n\taas_entityinfo_t entinfo;\n\tvec3_t mins = {-8, -8, -8}, maxs = {8, 8, 8};\n\n\tattackentity = bs->enemy;\n\t//\n\tBotEntityInfo(attackentity, &entinfo);\n\t// if not attacking a player\n\tif (attackentity >= MAX_CLIENTS) {\n\t}\n\t//\n\treactiontime = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_REACTIONTIME, 0, 1);\n\tif (bs->enemysight_time > FloatTime() - reactiontime) return;\n\tif (bs->teleport_time > FloatTime() - reactiontime) return;\n\t//if changing weapons\n\tif (bs->weaponchange_time > FloatTime() - 0.1) return;\n\t//check fire throttle characteristic\n\tif (bs->firethrottlewait_time > FloatTime()) return;\n\tfirethrottle = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_FIRETHROTTLE, 0, 1);\n\tif (bs->firethrottleshoot_time < FloatTime()) {\n\t\tif (random() > firethrottle) {\n\t\t\tbs->firethrottlewait_time = FloatTime() + firethrottle;\n\t\t\tbs->firethrottleshoot_time = 0;\n\t\t}\n\t\telse {\n\t\t\tbs->firethrottleshoot_time = FloatTime() + 1 - firethrottle;\n\t\t\tbs->firethrottlewait_time = 0;\n\t\t}\n\t}\n\t//\n\t//\n\tVectorSubtract(bs->aimtarget, bs->eye, dir);\n\t//\n\tif (bs->weaponnum == WP_GAUNTLET) {\n\t\tif (VectorLengthSquared(dir) > Square(60)) {\n\t\t\treturn;\n\t\t}\n\t}\n\tif (VectorLengthSquared(dir) < Square(100))\n\t\tfov = 120;\n\telse\n\t\tfov = 50;\n\t//\n\tvectoangles(dir, angles);\n\tif (!InFieldOfVision(bs->viewangles, fov, angles))\n\t\treturn;\n\tBotAI_Trace(&bsptrace, bs->eye, NULL, NULL, bs->aimtarget, bs->client, CONTENTS_SOLID|CONTENTS_PLAYERCLIP);\n\tif (bsptrace.fraction < 1 && bsptrace.ent != attackentity)\n\t\treturn;\n\n\t//get the weapon info\n\ttrap_BotGetWeaponInfo(bs->ws, bs->weaponnum, &wi);\n\t//get the start point shooting from\n\tVectorCopy(bs->origin, start);\n\tstart[2] += bs->cur_ps.viewheight;\n\tAngleVectors(bs->viewangles, forward, right, NULL);\n\tstart[0] += forward[0] * wi.offset[0] + right[0] * wi.offset[1];\n\tstart[1] += forward[1] * wi.offset[0] + right[1] * wi.offset[1];\n\tstart[2] += forward[2] * wi.offset[0] + right[2] * wi.offset[1] + wi.offset[2];\n\t//end point aiming at\n\tVectorMA(start, 1000, forward, end);\n\t//a little back to make sure not inside a very close enemy\n\tVectorMA(start, -12, forward, start);\n\tBotAI_Trace(&trace, start, mins, maxs, end, bs->entitynum, MASK_SHOT);\n\t//if the entity is a client\n\tif (trace.ent > 0 && trace.ent <= MAX_CLIENTS) {\n\t\tif (trace.ent != attackentity) {\n\t\t\t//if a teammate is hit\n\t\t\tif (BotSameTeam(bs, trace.ent))\n\t\t\t\treturn;\n\t\t}\n\t}\n\t//if won't hit the enemy or not attacking a player (obelisk)\n\tif (trace.ent != attackentity || attackentity >= MAX_CLIENTS) {\n\t\t//if the projectile does radial damage\n\t\tif (wi.proj.damagetype & DAMAGETYPE_RADIAL) {\n\t\t\tif (trace.fraction * 1000 < wi.proj.radius) {\n\t\t\t\tpoints = (wi.proj.damage - 0.5 * trace.fraction * 1000) * 0.5;\n\t\t\t\tif (points > 0) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\t//FIXME: check if a teammate gets radial damage\n\t\t}\n\t}\n\t//if fire has to be release to activate weapon\n\tif (wi.flags & WFL_FIRERELEASED) {\n\t\tif (bs->flags & BFL_ATTACKED) {\n\t\t\ttrap_EA_Attack(bs->client);\n\t\t}\n\t}\n\telse {\n\t\ttrap_EA_Attack(bs->client);\n\t}\n\tbs->flags ^= BFL_ATTACKED;\n}\n\n/*\n==================\nBotMapScripts\n==================\n*/\nvoid BotMapScripts(bot_state_t *bs) {\n\tchar info[1024];\n\tchar mapname[128];\n\tint i, shootbutton;\n\tfloat aim_accuracy;\n\taas_entityinfo_t entinfo;\n\tvec3_t dir;\n\n\ttrap_GetServerinfo(info, sizeof(info));\n\n\tstrncpy(mapname, Info_ValueForKey( info, \"mapname\" ), sizeof(mapname)-1);\n\tmapname[sizeof(mapname)-1] = '\\0';\n\n\tif (!Q_stricmp(mapname, \"q3tourney6\")) {\n\t\tvec3_t mins = {700, 204, 672}, maxs = {964, 468, 680};\n\t\tvec3_t buttonorg = {304, 352, 920};\n\t\t//NOTE: NEVER use the func_bobbing in q3tourney6\n\t\tbs->tfl &= ~TFL_FUNCBOB;\n\t\t//if the bot is below the bounding box\n\t\tif (bs->origin[0] > mins[0] && bs->origin[0] < maxs[0]) {\n\t\t\tif (bs->origin[1] > mins[1] && bs->origin[1] < maxs[1]) {\n\t\t\t\tif (bs->origin[2] < mins[2]) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tshootbutton = qfalse;\n\t\t//if an enemy is below this bounding box then shoot the button\n\t\tfor (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {\n\n\t\t\tif (i == bs->client) continue;\n\t\t\t//\n\t\t\tBotEntityInfo(i, &entinfo);\n\t\t\t//\n\t\t\tif (!entinfo.valid) continue;\n\t\t\t//if the enemy isn't dead and the enemy isn't the bot self\n\t\t\tif (EntityIsDead(&entinfo) || entinfo.number == bs->entitynum) continue;\n\t\t\t//\n\t\t\tif (entinfo.origin[0] > mins[0] && entinfo.origin[0] < maxs[0]) {\n\t\t\t\tif (entinfo.origin[1] > mins[1] && entinfo.origin[1] < maxs[1]) {\n\t\t\t\t\tif (entinfo.origin[2] < mins[2]) {\n\t\t\t\t\t\t//if there's a team mate below the crusher\n\t\t\t\t\t\tif (BotSameTeam(bs, i)) {\n\t\t\t\t\t\t\tshootbutton = qfalse;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tshootbutton = qtrue;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (shootbutton) {\n\t\t\tbs->flags |= BFL_IDEALVIEWSET;\n\t\t\tVectorSubtract(buttonorg, bs->eye, dir);\n\t\t\tvectoangles(dir, bs->ideal_viewangles);\n\t\t\taim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY, 0, 1);\n\t\t\tbs->ideal_viewangles[PITCH] += 8 * crandom() * (1 - aim_accuracy);\n\t\t\tbs->ideal_viewangles[PITCH] = AngleMod(bs->ideal_viewangles[PITCH]);\n\t\t\tbs->ideal_viewangles[YAW] += 8 * crandom() * (1 - aim_accuracy);\n\t\t\tbs->ideal_viewangles[YAW] = AngleMod(bs->ideal_viewangles[YAW]);\n\t\t\t//\n\t\t\tif (InFieldOfVision(bs->viewangles, 20, bs->ideal_viewangles)) {\n\t\t\t\ttrap_EA_Attack(bs->client);\n\t\t\t}\n\t\t}\n\t}\n\telse if (!Q_stricmp(mapname, \"mpq3tourney6\")) {\n\t\t//NOTE: NEVER use the func_bobbing in mpq3tourney6\n\t\tbs->tfl &= ~TFL_FUNCBOB;\n\t}\n}\n\n/*\n==================\nBotSetMovedir\n==================\n*/\n// bk001205 - made these static\nstatic vec3_t VEC_UP\t\t= {0, -1,  0};\nstatic vec3_t MOVEDIR_UP\t= {0,  0,  1};\nstatic vec3_t VEC_DOWN\t\t= {0, -2,  0};\nstatic vec3_t MOVEDIR_DOWN\t= {0,  0, -1};\n\nvoid BotSetMovedir(vec3_t angles, vec3_t movedir) {\n\tif (VectorCompare(angles, VEC_UP)) {\n\t\tVectorCopy(MOVEDIR_UP, movedir);\n\t}\n\telse if (VectorCompare(angles, VEC_DOWN)) {\n\t\tVectorCopy(MOVEDIR_DOWN, movedir);\n\t}\n\telse {\n\t\tAngleVectors(angles, movedir, NULL, NULL);\n\t}\n}\n\n/*\n==================\nBotModelMinsMaxs\n\nthis is ugly\n==================\n*/\nint BotModelMinsMaxs(int modelindex, int eType, int contents, vec3_t mins, vec3_t maxs) {\n\tgentity_t *ent;\n\tint i;\n\n\tent = &g_entities[0];\n\tfor (i = 0; i < level.num_entities; i++, ent++) {\n\t\tif ( !ent->inuse ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( eType && ent->s.eType != eType) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( contents && ent->r.contents != contents) {\n\t\t\tcontinue;\n\t\t}\n\t\tif (ent->s.modelindex == modelindex) {\n\t\t\tif (mins)\n\t\t\t\tVectorAdd(ent->r.currentOrigin, ent->r.mins, mins);\n\t\t\tif (maxs)\n\t\t\t\tVectorAdd(ent->r.currentOrigin, ent->r.maxs, maxs);\n\t\t\treturn i;\n\t\t}\n\t}\n\tif (mins)\n\t\tVectorClear(mins);\n\tif (maxs)\n\t\tVectorClear(maxs);\n\treturn 0;\n}\n\n/*\n==================\nBotFuncButtonGoal\n==================\n*/\nint BotFuncButtonActivateGoal(bot_state_t *bs, int bspent, bot_activategoal_t *activategoal) {\n\tint i, areas[10], numareas, modelindex, entitynum;\n\tchar model[128];\n\tfloat lip, dist, health, angle;\n\tvec3_t size, start, end, mins, maxs, angles, points[10];\n\tvec3_t movedir, origin, goalorigin, bboxmins, bboxmaxs;\n\tvec3_t extramins = {1, 1, 1}, extramaxs = {-1, -1, -1};\n\tbsp_trace_t bsptrace;\n\n\tactivategoal->shoot = qfalse;\n\tVectorClear(activategoal->target);\n\t//create a bot goal towards the button\n\ttrap_AAS_ValueForBSPEpairKey(bspent, \"model\", model, sizeof(model));\n\tif (!*model)\n\t\treturn qfalse;\n\tmodelindex = atoi(model+1);\n\tif (!modelindex)\n\t\treturn qfalse;\n\tVectorClear(angles);\n\tentitynum = BotModelMinsMaxs(modelindex, ET_MOVER, 0, mins, maxs);\n\t//get the lip of the button\n\ttrap_AAS_FloatForBSPEpairKey(bspent, \"lip\", &lip);\n\tif (!lip) lip = 4;\n\t//get the move direction from the angle\n\ttrap_AAS_FloatForBSPEpairKey(bspent, \"angle\", &angle);\n\tVectorSet(angles, 0, angle, 0);\n\tBotSetMovedir(angles, movedir);\n\t//button size\n\tVectorSubtract(maxs, mins, size);\n\t//button origin\n\tVectorAdd(mins, maxs, origin);\n\tVectorScale(origin, 0.5, origin);\n\t//touch distance of the button\n\tdist = fabs(movedir[0]) * size[0] + fabs(movedir[1]) * size[1] + fabs(movedir[2]) * size[2];\n\tdist *= 0.5;\n\t//\n\ttrap_AAS_FloatForBSPEpairKey(bspent, \"health\", &health);\n\t//if the button is shootable\n\tif (health) {\n\t\t//calculate the shoot target\n\t\tVectorMA(origin, -dist, movedir, goalorigin);\n\t\t//\n\t\tVectorCopy(goalorigin, activategoal->target);\n\t\tactivategoal->shoot = qtrue;\n\t\t//\n\t\tBotAI_Trace(&bsptrace, bs->eye, NULL, NULL, goalorigin, bs->entitynum, MASK_SHOT);\n\t\t// if the button is visible from the current position\n\t\tif (bsptrace.fraction >= 1.0 || bsptrace.ent == entitynum) {\n\t\t\t//\n\t\t\tactivategoal->goal.entitynum = entitynum; //NOTE: this is the entity number of the shootable button\n\t\t\tactivategoal->goal.number = 0;\n\t\t\tactivategoal->goal.flags = 0;\n\t\t\tVectorCopy(bs->origin, activategoal->goal.origin);\n\t\t\tactivategoal->goal.areanum = bs->areanum;\n\t\t\tVectorSet(activategoal->goal.mins, -8, -8, -8);\n\t\t\tVectorSet(activategoal->goal.maxs, 8, 8, 8);\n\t\t\t//\n\t\t\treturn qtrue;\n\t\t}\n\t\telse {\n\t\t\t//create a goal from where the button is visible and shoot at the button from there\n\t\t\t//add bounding box size to the dist\n\t\t\ttrap_AAS_PresenceTypeBoundingBox(PRESENCE_CROUCH, bboxmins, bboxmaxs);\n\t\t\tfor (i = 0; i < 3; i++) {\n\t\t\t\tif (movedir[i] < 0) dist += fabs(movedir[i]) * fabs(bboxmaxs[i]);\n\t\t\t\telse dist += fabs(movedir[i]) * fabs(bboxmins[i]);\n\t\t\t}\n\t\t\t//calculate the goal origin\n\t\t\tVectorMA(origin, -dist, movedir, goalorigin);\n\t\t\t//\n\t\t\tVectorCopy(goalorigin, start);\n\t\t\tstart[2] += 24;\n\t\t\tVectorCopy(start, end);\n\t\t\tend[2] -= 512;\n\t\t\tnumareas = trap_AAS_TraceAreas(start, end, areas, points, 10);\n\t\t\t//\n\t\t\tfor (i = numareas-1; i >= 0; i--) {\n\t\t\t\tif (trap_AAS_AreaReachability(areas[i])) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (i < 0) {\n\t\t\t\t// FIXME: trace forward and maybe in other directions to find a valid area\n\t\t\t}\n\t\t\tif (i >= 0) {\n\t\t\t\t//\n\t\t\t\tVectorCopy(points[i], activategoal->goal.origin);\n\t\t\t\tactivategoal->goal.areanum = areas[i];\n\t\t\t\tVectorSet(activategoal->goal.mins, 8, 8, 8);\n\t\t\t\tVectorSet(activategoal->goal.maxs, -8, -8, -8);\n\t\t\t\t//\n\t\t\t\tfor (i = 0; i < 3; i++)\n\t\t\t\t{\n\t\t\t\t\tif (movedir[i] < 0) activategoal->goal.maxs[i] += fabs(movedir[i]) * fabs(extramaxs[i]);\n\t\t\t\t\telse activategoal->goal.mins[i] += fabs(movedir[i]) * fabs(extramins[i]);\n\t\t\t\t} //end for\n\t\t\t\t//\n\t\t\t\tactivategoal->goal.entitynum = entitynum;\n\t\t\t\tactivategoal->goal.number = 0;\n\t\t\t\tactivategoal->goal.flags = 0;\n\t\t\t\treturn qtrue;\n\t\t\t}\n\t\t}\n\t\treturn qfalse;\n\t}\n\telse {\n\t\t//add bounding box size to the dist\n\t\ttrap_AAS_PresenceTypeBoundingBox(PRESENCE_CROUCH, bboxmins, bboxmaxs);\n\t\tfor (i = 0; i < 3; i++) {\n\t\t\tif (movedir[i] < 0) dist += fabs(movedir[i]) * fabs(bboxmaxs[i]);\n\t\t\telse dist += fabs(movedir[i]) * fabs(bboxmins[i]);\n\t\t}\n\t\t//calculate the goal origin\n\t\tVectorMA(origin, -dist, movedir, goalorigin);\n\t\t//\n\t\tVectorCopy(goalorigin, start);\n\t\tstart[2] += 24;\n\t\tVectorCopy(start, end);\n\t\tend[2] -= 100;\n\t\tnumareas = trap_AAS_TraceAreas(start, end, areas, NULL, 10);\n\t\t//\n\t\tfor (i = 0; i < numareas; i++) {\n\t\t\tif (trap_AAS_AreaReachability(areas[i])) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (i < numareas) {\n\t\t\t//\n\t\t\tVectorCopy(origin, activategoal->goal.origin);\n\t\t\tactivategoal->goal.areanum = areas[i];\n\t\t\tVectorSubtract(mins, origin, activategoal->goal.mins);\n\t\t\tVectorSubtract(maxs, origin, activategoal->goal.maxs);\n\t\t\t//\n\t\t\tfor (i = 0; i < 3; i++)\n\t\t\t{\n\t\t\t\tif (movedir[i] < 0) activategoal->goal.maxs[i] += fabs(movedir[i]) * fabs(extramaxs[i]);\n\t\t\t\telse activategoal->goal.mins[i] += fabs(movedir[i]) * fabs(extramins[i]);\n\t\t\t} //end for\n\t\t\t//\n\t\t\tactivategoal->goal.entitynum = entitynum;\n\t\t\tactivategoal->goal.number = 0;\n\t\t\tactivategoal->goal.flags = 0;\n\t\t\treturn qtrue;\n\t\t}\n\t}\n\treturn qfalse;\n}\n\n/*\n==================\nBotFuncDoorGoal\n==================\n*/\nint BotFuncDoorActivateGoal(bot_state_t *bs, int bspent, bot_activategoal_t *activategoal) {\n\tint modelindex, entitynum;\n\tchar model[MAX_INFO_STRING];\n\tvec3_t mins, maxs, origin, angles;\n\n\t//shoot at the shootable door\n\ttrap_AAS_ValueForBSPEpairKey(bspent, \"model\", model, sizeof(model));\n\tif (!*model)\n\t\treturn qfalse;\n\tmodelindex = atoi(model+1);\n\tif (!modelindex)\n\t\treturn qfalse;\n\tVectorClear(angles);\n\tentitynum = BotModelMinsMaxs(modelindex, ET_MOVER, 0, mins, maxs);\n\t//door origin\n\tVectorAdd(mins, maxs, origin);\n\tVectorScale(origin, 0.5, origin);\n\tVectorCopy(origin, activategoal->target);\n\tactivategoal->shoot = qtrue;\n\t//\n\tactivategoal->goal.entitynum = entitynum; //NOTE: this is the entity number of the shootable door\n\tactivategoal->goal.number = 0;\n\tactivategoal->goal.flags = 0;\n\tVectorCopy(bs->origin, activategoal->goal.origin);\n\tactivategoal->goal.areanum = bs->areanum;\n\tVectorSet(activategoal->goal.mins, -8, -8, -8);\n\tVectorSet(activategoal->goal.maxs, 8, 8, 8);\n\treturn qtrue;\n}\n\n/*\n==================\nBotTriggerMultipleGoal\n==================\n*/\nint BotTriggerMultipleActivateGoal(bot_state_t *bs, int bspent, bot_activategoal_t *activategoal) {\n\tint i, areas[10], numareas, modelindex, entitynum;\n\tchar model[128];\n\tvec3_t start, end, mins, maxs, angles;\n\tvec3_t origin, goalorigin;\n\n\tactivategoal->shoot = qfalse;\n\tVectorClear(activategoal->target);\n\t//create a bot goal towards the trigger\n\ttrap_AAS_ValueForBSPEpairKey(bspent, \"model\", model, sizeof(model));\n\tif (!*model)\n\t\treturn qfalse;\n\tmodelindex = atoi(model+1);\n\tif (!modelindex)\n\t\treturn qfalse;\n\tVectorClear(angles);\n\tentitynum = BotModelMinsMaxs(modelindex, 0, CONTENTS_TRIGGER, mins, maxs);\n\t//trigger origin\n\tVectorAdd(mins, maxs, origin);\n\tVectorScale(origin, 0.5, origin);\n\tVectorCopy(origin, goalorigin);\n\t//\n\tVectorCopy(goalorigin, start);\n\tstart[2] += 24;\n\tVectorCopy(start, end);\n\tend[2] -= 100;\n\tnumareas = trap_AAS_TraceAreas(start, end, areas, NULL, 10);\n\t//\n\tfor (i = 0; i < numareas; i++) {\n\t\tif (trap_AAS_AreaReachability(areas[i])) {\n\t\t\tbreak;\n\t\t}\n\t}\n\tif (i < numareas) {\n\t\tVectorCopy(origin, activategoal->goal.origin);\n\t\tactivategoal->goal.areanum = areas[i];\n\t\tVectorSubtract(mins, origin, activategoal->goal.mins);\n\t\tVectorSubtract(maxs, origin, activategoal->goal.maxs);\n\t\t//\n\t\tactivategoal->goal.entitynum = entitynum;\n\t\tactivategoal->goal.number = 0;\n\t\tactivategoal->goal.flags = 0;\n\t\treturn qtrue;\n\t}\n\treturn qfalse;\n}\n\n/*\n==================\nBotPopFromActivateGoalStack\n==================\n*/\nint BotPopFromActivateGoalStack(bot_state_t *bs) {\n\tif (!bs->activatestack)\n\t\treturn qfalse;\n\tBotEnableActivateGoalAreas(bs->activatestack, qtrue);\n\tbs->activatestack->inuse = qfalse;\n\tbs->activatestack->justused_time = FloatTime();\n\tbs->activatestack = bs->activatestack->next;\n\treturn qtrue;\n}\n\n/*\n==================\nBotPushOntoActivateGoalStack\n==================\n*/\nint BotPushOntoActivateGoalStack(bot_state_t *bs, bot_activategoal_t *activategoal) {\n\tint i, best;\n\tfloat besttime;\n\n\tbest = -1;\n\tbesttime = FloatTime() + 9999;\n\t//\n\tfor (i = 0; i < MAX_ACTIVATESTACK; i++) {\n\t\tif (!bs->activategoalheap[i].inuse) {\n\t\t\tif (bs->activategoalheap[i].justused_time < besttime) {\n\t\t\t\tbesttime = bs->activategoalheap[i].justused_time;\n\t\t\t\tbest = i;\n\t\t\t}\n\t\t}\n\t}\n\tif (best != -1) {\n\t\tmemcpy(&bs->activategoalheap[best], activategoal, sizeof(bot_activategoal_t));\n\t\tbs->activategoalheap[best].inuse = qtrue;\n\t\tbs->activategoalheap[best].next = bs->activatestack;\n\t\tbs->activatestack = &bs->activategoalheap[best];\n\t\treturn qtrue;\n\t}\n\treturn qfalse;\n}\n\n/*\n==================\nBotClearActivateGoalStack\n==================\n*/\nvoid BotClearActivateGoalStack(bot_state_t *bs) {\n\twhile(bs->activatestack)\n\t\tBotPopFromActivateGoalStack(bs);\n}\n\n/*\n==================\nBotEnableActivateGoalAreas\n==================\n*/\nvoid BotEnableActivateGoalAreas(bot_activategoal_t *activategoal, int enable) {\n\tint i;\n\n\tif (activategoal->areasdisabled == !enable)\n\t\treturn;\n\tfor (i = 0; i < activategoal->numareas; i++)\n\t\ttrap_AAS_EnableRoutingArea( activategoal->areas[i], enable );\n\tactivategoal->areasdisabled = !enable;\n}\n\n/*\n==================\nBotIsGoingToActivateEntity\n==================\n*/\nint BotIsGoingToActivateEntity(bot_state_t *bs, int entitynum) {\n\tbot_activategoal_t *a;\n\tint i;\n\n\tfor (a = bs->activatestack; a; a = a->next) {\n\t\tif (a->time < FloatTime())\n\t\t\tcontinue;\n\t\tif (a->goal.entitynum == entitynum)\n\t\t\treturn qtrue;\n\t}\n\tfor (i = 0; i < MAX_ACTIVATESTACK; i++) {\n\t\tif (bs->activategoalheap[i].inuse)\n\t\t\tcontinue;\n\t\t//\n\t\tif (bs->activategoalheap[i].goal.entitynum == entitynum) {\n\t\t\t// if the bot went for this goal less than 2 seconds ago\n\t\t\tif (bs->activategoalheap[i].justused_time > FloatTime() - 2)\n\t\t\t\treturn qtrue;\n\t\t}\n\t}\n\treturn qfalse;\n}\n\n/*\n==================\nBotGetActivateGoal\n\n  returns the number of the bsp entity to activate\n  goal->entitynum will be set to the game entity to activate\n==================\n*/\n//#define OBSTACLEDEBUG\n\nint BotGetActivateGoal(bot_state_t *bs, int entitynum, bot_activategoal_t *activategoal) {\n\tint i, ent, cur_entities[10], spawnflags, modelindex, areas[MAX_ACTIVATEAREAS*2], numareas, t;\n\tchar model[MAX_INFO_STRING], tmpmodel[128];\n\tchar target[128], classname[128];\n\tfloat health;\n\tchar targetname[10][128];\n\taas_entityinfo_t entinfo;\n\taas_areainfo_t areainfo;\n\tvec3_t origin, angles, absmins, absmaxs;\n\n\tmemset(activategoal, 0, sizeof(bot_activategoal_t));\n\tBotEntityInfo(entitynum, &entinfo);\n\tCom_sprintf(model, sizeof( model ), \"*%d\", entinfo.modelindex);\n\tfor (ent = trap_AAS_NextBSPEntity(0); ent; ent = trap_AAS_NextBSPEntity(ent)) {\n\t\tif (!trap_AAS_ValueForBSPEpairKey(ent, \"model\", tmpmodel, sizeof(tmpmodel))) continue;\n\t\tif (!strcmp(model, tmpmodel)) break;\n\t}\n\tif (!ent) {\n\t\tBotAI_Print(PRT_ERROR, \"BotGetActivateGoal: no entity found with model %s\\n\", model);\n\t\treturn 0;\n\t}\n\ttrap_AAS_ValueForBSPEpairKey(ent, \"classname\", classname, sizeof(classname));\n\tif (!classname) {\n\t\tBotAI_Print(PRT_ERROR, \"BotGetActivateGoal: entity with model %s has no classname\\n\", model);\n\t\treturn 0;\n\t}\n\t//if it is a door\n\tif (!strcmp(classname, \"func_door\")) {\n\t\tif (trap_AAS_FloatForBSPEpairKey(ent, \"health\", &health)) {\n\t\t\t//if the door has health then the door must be shot to open\n\t\t\tif (health) {\n\t\t\t\tBotFuncDoorActivateGoal(bs, ent, activategoal);\n\t\t\t\treturn ent;\n\t\t\t}\n\t\t}\n\t\t//\n\t\ttrap_AAS_IntForBSPEpairKey(ent, \"spawnflags\", &spawnflags);\n\t\t// if the door starts open then just wait for the door to return\n\t\tif ( spawnflags & 1 )\n\t\t\treturn 0;\n\t\t//get the door origin\n\t\tif (!trap_AAS_VectorForBSPEpairKey(ent, \"origin\", origin)) {\n\t\t\tVectorClear(origin);\n\t\t}\n\t\t//if the door is open or opening already\n\t\tif (!VectorCompare(origin, entinfo.origin))\n\t\t\treturn 0;\n\t\t// store all the areas the door is in\n\t\ttrap_AAS_ValueForBSPEpairKey(ent, \"model\", model, sizeof(model));\n\t\tif (*model) {\n\t\t\tmodelindex = atoi(model+1);\n\t\t\tif (modelindex) {\n\t\t\t\tVectorClear(angles);\n\t\t\t\tBotModelMinsMaxs(modelindex, ET_MOVER, 0, absmins, absmaxs);\n\t\t\t\t//\n\t\t\t\tnumareas = trap_AAS_BBoxAreas(absmins, absmaxs, areas, MAX_ACTIVATEAREAS*2);\n\t\t\t\t// store the areas with reachabilities first\n\t\t\t\tfor (i = 0; i < numareas; i++) {\n\t\t\t\t\tif (activategoal->numareas >= MAX_ACTIVATEAREAS)\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tif ( !trap_AAS_AreaReachability(areas[i]) ) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\ttrap_AAS_AreaInfo(areas[i], &areainfo);\n\t\t\t\t\tif (areainfo.contents & AREACONTENTS_MOVER) {\n\t\t\t\t\t\tactivategoal->areas[activategoal->numareas++] = areas[i];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// store any remaining areas\n\t\t\t\tfor (i = 0; i < numareas; i++) {\n\t\t\t\t\tif (activategoal->numareas >= MAX_ACTIVATEAREAS)\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tif ( trap_AAS_AreaReachability(areas[i]) ) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\ttrap_AAS_AreaInfo(areas[i], &areainfo);\n\t\t\t\t\tif (areainfo.contents & AREACONTENTS_MOVER) {\n\t\t\t\t\t\tactivategoal->areas[activategoal->numareas++] = areas[i];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t// if the bot is blocked by or standing on top of a button\n\tif (!strcmp(classname, \"func_button\")) {\n\t\treturn 0;\n\t}\n\t// get the targetname so we can find an entity with a matching target\n\tif (!trap_AAS_ValueForBSPEpairKey(ent, \"targetname\", targetname[0], sizeof(targetname[0]))) {\n\t\tif (bot_developer.integer) {\n\t\t\tBotAI_Print(PRT_ERROR, \"BotGetActivateGoal: entity with model \\\"%s\\\" has no targetname\\n\", model);\n\t\t}\n\t\treturn 0;\n\t}\n\t// allow tree-like activation\n\tcur_entities[0] = trap_AAS_NextBSPEntity(0);\n\tfor (i = 0; i >= 0 && i < 10;) {\n\t\tfor (ent = cur_entities[i]; ent; ent = trap_AAS_NextBSPEntity(ent)) {\n\t\t\tif (!trap_AAS_ValueForBSPEpairKey(ent, \"target\", target, sizeof(target))) continue;\n\t\t\tif (!strcmp(targetname[i], target)) {\n\t\t\t\tcur_entities[i] = trap_AAS_NextBSPEntity(ent);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (!ent) {\n\t\t\tif (bot_developer.integer) {\n\t\t\t\tBotAI_Print(PRT_ERROR, \"BotGetActivateGoal: no entity with target \\\"%s\\\"\\n\", targetname[i]);\n\t\t\t}\n\t\t\ti--;\n\t\t\tcontinue;\n\t\t}\n\t\tif (!trap_AAS_ValueForBSPEpairKey(ent, \"classname\", classname, sizeof(classname))) {\n\t\t\tif (bot_developer.integer) {\n\t\t\t\tBotAI_Print(PRT_ERROR, \"BotGetActivateGoal: entity with target \\\"%s\\\" has no classname\\n\", targetname[i]);\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\t// BSP button model\n\t\tif (!strcmp(classname, \"func_button\")) {\n\t\t\t//\n\t\t\tif (!BotFuncButtonActivateGoal(bs, ent, activategoal))\n\t\t\t\tcontinue;\n\t\t\t// if the bot tries to activate this button already\n\t\t\tif ( bs->activatestack && bs->activatestack->inuse &&\n\t\t\t\t bs->activatestack->goal.entitynum == activategoal->goal.entitynum &&\n\t\t\t\t bs->activatestack->time > FloatTime() &&\n\t\t\t\t bs->activatestack->start_time < FloatTime() - 2)\n\t\t\t\tcontinue;\n\t\t\t// if the bot is in a reachability area\n\t\t\tif ( trap_AAS_AreaReachability(bs->areanum) ) {\n\t\t\t\t// disable all areas the blocking entity is in\n\t\t\t\tBotEnableActivateGoalAreas( activategoal, qfalse );\n\t\t\t\t//\n\t\t\t\tt = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, activategoal->goal.areanum, bs->tfl);\n\t\t\t\t// if the button is not reachable\n\t\t\t\tif (!t) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tactivategoal->time = FloatTime() + t * 0.01 + 5;\n\t\t\t}\n\t\t\treturn ent;\n\t\t}\n\t\t// invisible trigger multiple box\n\t\telse if (!strcmp(classname, \"trigger_multiple\")) {\n\t\t\t//\n\t\t\tif (!BotTriggerMultipleActivateGoal(bs, ent, activategoal))\n\t\t\t\tcontinue;\n\t\t\t// if the bot tries to activate this trigger already\n\t\t\tif ( bs->activatestack && bs->activatestack->inuse &&\n\t\t\t\t bs->activatestack->goal.entitynum == activategoal->goal.entitynum &&\n\t\t\t\t bs->activatestack->time > FloatTime() &&\n\t\t\t\t bs->activatestack->start_time < FloatTime() - 2)\n\t\t\t\tcontinue;\n\t\t\t// if the bot is in a reachability area\n\t\t\tif ( trap_AAS_AreaReachability(bs->areanum) ) {\n\t\t\t\t// disable all areas the blocking entity is in\n\t\t\t\tBotEnableActivateGoalAreas( activategoal, qfalse );\n\t\t\t\t//\n\t\t\t\tt = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, activategoal->goal.areanum, bs->tfl);\n\t\t\t\t// if the trigger is not reachable\n\t\t\t\tif (!t) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tactivategoal->time = FloatTime() + t * 0.01 + 5;\n\t\t\t}\n\t\t\treturn ent;\n\t\t}\n\t\telse if (!strcmp(classname, \"func_timer\")) {\n\t\t\t// just skip the func_timer\n\t\t\tcontinue;\n\t\t}\n\t\t// the actual button or trigger might be linked through a target_relay or target_delay\n\t\telse if (!strcmp(classname, \"target_relay\") || !strcmp(classname, \"target_delay\")) {\n\t\t\tif (trap_AAS_ValueForBSPEpairKey(ent, \"targetname\", targetname[i+1], sizeof(targetname[0]))) {\n\t\t\t\ti++;\n\t\t\t\tcur_entities[i] = trap_AAS_NextBSPEntity(0);\n\t\t\t}\n\t\t}\n\t}\n#ifdef OBSTACLEDEBUG\n\tBotAI_Print(PRT_ERROR, \"BotGetActivateGoal: no valid activator for entity with target \\\"%s\\\"\\n\", targetname[0]);\n#endif\n\treturn 0;\n}\n\n/*\n==================\nBotGoForActivateGoal\n==================\n*/\nint BotGoForActivateGoal(bot_state_t *bs, bot_activategoal_t *activategoal) {\n\taas_entityinfo_t activateinfo;\n\n\tactivategoal->inuse = qtrue;\n\tif (!activategoal->time)\n\t\tactivategoal->time = FloatTime() + 10;\n\tactivategoal->start_time = FloatTime();\n\tBotEntityInfo(activategoal->goal.entitynum, &activateinfo);\n\tVectorCopy(activateinfo.origin, activategoal->origin);\n\t//\n\tif (BotPushOntoActivateGoalStack(bs, activategoal)) {\n\t\t// enter the activate entity AI node\n\t\tAIEnter_Seek_ActivateEntity(bs, \"BotGoForActivateGoal\");\n\t\treturn qtrue;\n\t}\n\telse {\n\t\t// enable any routing areas that were disabled\n\t\tBotEnableActivateGoalAreas(activategoal, qtrue);\n\t\treturn qfalse;\n\t}\n}\n\n/*\n==================\nBotPrintActivateGoalInfo\n==================\n*/\nvoid BotPrintActivateGoalInfo(bot_state_t *bs, bot_activategoal_t *activategoal, int bspent) {\n\tchar netname[MAX_NETNAME];\n\tchar classname[128];\n\tchar buf[128];\n\n\tClientName(bs->client, netname, sizeof(netname));\n\ttrap_AAS_ValueForBSPEpairKey(bspent, \"classname\", classname, sizeof(classname));\n\tif (activategoal->shoot) {\n\t\tCom_sprintf(buf, sizeof(buf), \"%s: I have to shoot at a %s from %1.1f %1.1f %1.1f in area %d\\n\",\n\t\t\t\t\t\tnetname, classname,\n\t\t\t\t\t\tactivategoal->goal.origin[0],\n\t\t\t\t\t\tactivategoal->goal.origin[1],\n\t\t\t\t\t\tactivategoal->goal.origin[2],\n\t\t\t\t\t\tactivategoal->goal.areanum);\n\t}\n\telse {\n\t\tCom_sprintf(buf, sizeof(buf), \"%s: I have to activate a %s at %1.1f %1.1f %1.1f in area %d\\n\",\n\t\t\t\t\t\tnetname, classname,\n\t\t\t\t\t\tactivategoal->goal.origin[0],\n\t\t\t\t\t\tactivategoal->goal.origin[1],\n\t\t\t\t\t\tactivategoal->goal.origin[2],\n\t\t\t\t\t\tactivategoal->goal.areanum);\n\t}\n\ttrap_EA_Say(bs->client, buf);\n}\n\n/*\n==================\nBotRandomMove\n==================\n*/\nvoid BotRandomMove(bot_state_t *bs, bot_moveresult_t *moveresult) {\n\tvec3_t dir, angles;\n\n\tangles[0] = 0;\n\tangles[1] = random() * 360;\n\tangles[2] = 0;\n\tAngleVectors(angles, dir, NULL, NULL);\n\n\ttrap_BotMoveInDirection(bs->ms, dir, 400, MOVE_WALK);\n\n\tmoveresult->failure = qfalse;\n\tVectorCopy(dir, moveresult->movedir);\n}\n\n/*\n==================\nBotAIBlocked\n\nVery basic handling of bots being blocked by other entities.\nCheck what kind of entity is blocking the bot and try to activate\nit. If that's not an option then try to walk around or over the entity.\nBefore the bot ends in this part of the AI it should predict which doors to\nopen, which buttons to activate etc.\n==================\n*/\nvoid BotAIBlocked(bot_state_t *bs, bot_moveresult_t *moveresult, int activate) {\n\tint movetype, bspent;\n\tvec3_t hordir, start, end, mins, maxs, sideward, angles, up = {0, 0, 1};\n\taas_entityinfo_t entinfo;\n\tbot_activategoal_t activategoal;\n\n\t// if the bot is not blocked by anything\n\tif (!moveresult->blocked) {\n\t\tbs->notblocked_time = FloatTime();\n\t\treturn;\n\t}\n\t// if stuck in a solid area\n\tif ( moveresult->type == RESULTTYPE_INSOLIDAREA ) {\n\t\t// move in a random direction in the hope to get out\n\t\tBotRandomMove(bs, moveresult);\n\t\t//\n\t\treturn;\n\t}\n\t// get info for the entity that is blocking the bot\n\tBotEntityInfo(moveresult->blockentity, &entinfo);\n#ifdef OBSTACLEDEBUG\n\tClientName(bs->client, netname, sizeof(netname));\n\tBotAI_Print(PRT_MESSAGE, \"%s: I'm blocked by model %d\\n\", netname, entinfo.modelindex);\n#endif // OBSTACLEDEBUG\n\t// if blocked by a bsp model and the bot wants to activate it\n\tif (activate && entinfo.modelindex > 0 && entinfo.modelindex <= max_bspmodelindex) {\n\t\t// find the bsp entity which should be activated in order to get the blocking entity out of the way\n\t\tbspent = BotGetActivateGoal(bs, entinfo.number, &activategoal);\n\t\tif (bspent) {\n\t\t\t//\n\t\t\tif (bs->activatestack && !bs->activatestack->inuse)\n\t\t\t\tbs->activatestack = NULL;\n\t\t\t// if not already trying to activate this entity\n\t\t\tif (!BotIsGoingToActivateEntity(bs, activategoal.goal.entitynum)) {\n\t\t\t\t//\n\t\t\t\tBotGoForActivateGoal(bs, &activategoal);\n\t\t\t}\n\t\t\t// if ontop of an obstacle or\n\t\t\t// if the bot is not in a reachability area it'll still\n\t\t\t// need some dynamic obstacle avoidance, otherwise return\n\t\t\tif (!(moveresult->flags & MOVERESULT_ONTOPOFOBSTACLE) &&\n\t\t\t\ttrap_AAS_AreaReachability(bs->areanum))\n\t\t\t\treturn;\n\t\t}\n\t\telse {\n\t\t\t// enable any routing areas that were disabled\n\t\t\tBotEnableActivateGoalAreas(&activategoal, qtrue);\n\t\t}\n\t}\n\t// just some basic dynamic obstacle avoidance code\n\thordir[0] = moveresult->movedir[0];\n\thordir[1] = moveresult->movedir[1];\n\thordir[2] = 0;\n\t// if no direction just take a random direction\n\tif (VectorNormalize(hordir) < 0.1) {\n\t\tVectorSet(angles, 0, 360 * random(), 0);\n\t\tAngleVectors(angles, hordir, NULL, NULL);\n\t}\n\t//\n\t//if (moveresult->flags & MOVERESULT_ONTOPOFOBSTACLE) movetype = MOVE_JUMP;\n\t//else\n\tmovetype = MOVE_WALK;\n\t// if there's an obstacle at the bot's feet and head then\n\t// the bot might be able to crouch through\n\tVectorCopy(bs->origin, start);\n\tstart[2] += 18;\n\tVectorMA(start, 5, hordir, end);\n\tVectorSet(mins, -16, -16, -24);\n\tVectorSet(maxs, 16, 16, 4);\n\t//\n\t//bsptrace = AAS_Trace(start, mins, maxs, end, bs->entitynum, MASK_PLAYERSOLID);\n\t//if (bsptrace.fraction >= 1) movetype = MOVE_CROUCH;\n\t// get the sideward vector\n\tCrossProduct(hordir, up, sideward);\n\t//\n\tif (bs->flags & BFL_AVOIDRIGHT) VectorNegate(sideward, sideward);\n\t// try to crouch straight forward?\n\tif (movetype != MOVE_CROUCH || !trap_BotMoveInDirection(bs->ms, hordir, 400, movetype)) {\n\t\t// perform the movement\n\t\tif (!trap_BotMoveInDirection(bs->ms, sideward, 400, movetype)) {\n\t\t\t// flip the avoid direction flag\n\t\t\tbs->flags ^= BFL_AVOIDRIGHT;\n\t\t\t// flip the direction\n\t\t\t// VectorNegate(sideward, sideward);\n\t\t\tVectorMA(sideward, -1, hordir, sideward);\n\t\t\t// move in the other direction\n\t\t\ttrap_BotMoveInDirection(bs->ms, sideward, 400, movetype);\n\t\t}\n\t}\n\t//\n\tif (bs->notblocked_time < FloatTime() - 0.4) {\n\t\t// just reset goals and hope the bot will go into another direction?\n\t\t// is this still needed??\n\t\tif (bs->ainode == AINode_Seek_NBG) bs->nbg_time = 0;\n\t\telse if (bs->ainode == AINode_Seek_LTG) bs->ltg_time = 0;\n\t}\n}\n\n/*\n==================\nBotAIPredictObstacles\n\nPredict the route towards the goal and check if the bot\nwill be blocked by certain obstacles. When the bot has obstacles\non it's path the bot should figure out if they can be removed\nby activating certain entities.\n==================\n*/\nint BotAIPredictObstacles(bot_state_t *bs, bot_goal_t *goal) {\n\tint modelnum, entitynum, bspent;\n\tbot_activategoal_t activategoal;\n\taas_predictroute_t route;\n\n\tif (!bot_predictobstacles.integer)\n\t\treturn qfalse;\n\n\t// always predict when the goal change or at regular intervals\n\tif (bs->predictobstacles_goalareanum == goal->areanum &&\n\t\tbs->predictobstacles_time > FloatTime() - 6) {\n\t\treturn qfalse;\n\t}\n\tbs->predictobstacles_goalareanum = goal->areanum;\n\tbs->predictobstacles_time = FloatTime();\n\n\t// predict at most 100 areas or 10 seconds ahead\n\ttrap_AAS_PredictRoute(&route, bs->areanum, bs->origin,\n\t\t\t\t\t\t\tgoal->areanum, bs->tfl, 100, 1000,\n\t\t\t\t\t\t\tRSE_USETRAVELTYPE|RSE_ENTERCONTENTS,\n\t\t\t\t\t\t\tAREACONTENTS_MOVER, TFL_BRIDGE, 0);\n\t// if bot has to travel through an area with a mover\n\tif (route.stopevent & RSE_ENTERCONTENTS) {\n\t\t// if the bot will run into a mover\n\t\tif (route.endcontents & AREACONTENTS_MOVER) {\n\t\t\t//NOTE: this only works with bspc 2.1 or higher\n\t\t\tmodelnum = (route.endcontents & AREACONTENTS_MODELNUM) >> AREACONTENTS_MODELNUMSHIFT;\n\t\t\tif (modelnum) {\n\t\t\t\t//\n\t\t\t\tentitynum = BotModelMinsMaxs(modelnum, ET_MOVER, 0, NULL, NULL);\n\t\t\t\tif (entitynum) {\n\t\t\t\t\t//NOTE: BotGetActivateGoal already checks if the door is open or not\n\t\t\t\t\tbspent = BotGetActivateGoal(bs, entitynum, &activategoal);\n\t\t\t\t\tif (bspent) {\n\t\t\t\t\t\t//\n\t\t\t\t\t\tif (bs->activatestack && !bs->activatestack->inuse)\n\t\t\t\t\t\t\tbs->activatestack = NULL;\n\t\t\t\t\t\t// if not already trying to activate this entity\n\t\t\t\t\t\tif (!BotIsGoingToActivateEntity(bs, activategoal.goal.entitynum)) {\n\t\t\t\t\t\t\t//\n\t\t\t\t\t\t\t//BotAI_Print(PRT_MESSAGE, \"blocked by mover model %d, entity %d ?\\n\", modelnum, entitynum);\n\t\t\t\t\t\t\t//\n\t\t\t\t\t\t\tBotGoForActivateGoal(bs, &activategoal);\n\t\t\t\t\t\t\treturn qtrue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t// enable any routing areas that were disabled\n\t\t\t\t\t\t\tBotEnableActivateGoalAreas(&activategoal, qtrue);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\telse if (route.stopevent & RSE_USETRAVELTYPE) {\n\t\tif (route.endtravelflags & TFL_BRIDGE) {\n\t\t\t//FIXME: check if the bridge is available to travel over\n\t\t}\n\t}\n\treturn qfalse;\n}\n\n/*\n==================\nBotCheckConsoleMessages\n==================\n*/\nvoid BotCheckConsoleMessages(bot_state_t *bs) {\n\tchar botname[MAX_NETNAME], message[MAX_MESSAGE_SIZE], netname[MAX_NETNAME], *ptr;\n\tfloat chat_reply;\n\tint context, handle;\n\tbot_consolemessage_t m;\n\tbot_match_t match;\n\n\t//the name of this bot\n\tClientName(bs->client, botname, sizeof(botname));\n\t//\n\twhile((handle = trap_BotNextConsoleMessage(bs->cs, &m)) != 0) {\n\t\t//if the chat state is flooded with messages the bot will read them quickly\n\t\tif (trap_BotNumConsoleMessages(bs->cs) < 10) {\n\t\t\t//if it is a chat message the bot needs some time to read it\n\t\t\tif (m.type == CMS_CHAT && m.time > FloatTime() - (1 + random())) break;\n\t\t}\n\t\t//\n\t\tptr = m.message;\n\t\t//if it is a chat message then don't unify white spaces and don't\n\t\t//replace synonyms in the netname\n\t\tif (m.type == CMS_CHAT) {\n\t\t\t//\n\t\t\tif (trap_BotFindMatch(m.message, &match, MTCONTEXT_REPLYCHAT)) {\n\t\t\t\tptr = m.message + match.variables[MESSAGE].offset;\n\t\t\t}\n\t\t}\n\t\t//unify the white spaces in the message\n\t\ttrap_UnifyWhiteSpaces(ptr);\n\t\t//replace synonyms in the right context\n\t\tcontext = BotSynonymContext(bs);\n\t\ttrap_BotReplaceSynonyms(ptr, context);\n\t\t//if there's no match\n\t\tif (!BotMatchMessage(bs, m.message)) {\n\t\t\t//if it is a chat message\n\t\t\tif (m.type == CMS_CHAT && !bot_nochat.integer) {\n\t\t\t\t//\n\t\t\t\tif (!trap_BotFindMatch(m.message, &match, MTCONTEXT_REPLYCHAT)) {\n\t\t\t\t\ttrap_BotRemoveConsoleMessage(bs->cs, handle);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t//don't use eliza chats with team messages\n\t\t\t\tif (match.subtype & ST_TEAM) {\n\t\t\t\t\ttrap_BotRemoveConsoleMessage(bs->cs, handle);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t//\n\t\t\t\ttrap_BotMatchVariable(&match, NETNAME, netname, sizeof(netname));\n\t\t\t\ttrap_BotMatchVariable(&match, MESSAGE, message, sizeof(message));\n\t\t\t\t//if this is a message from the bot self\n\t\t\t\tif (bs->client == ClientFromName(netname)) {\n\t\t\t\t\ttrap_BotRemoveConsoleMessage(bs->cs, handle);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t//unify the message\n\t\t\t\ttrap_UnifyWhiteSpaces(message);\n\t\t\t\t//\n\t\t\t\ttrap_Cvar_Update(&bot_testrchat);\n\t\t\t\tif (bot_testrchat.integer) {\n\t\t\t\t\t//\n\t\t\t\t\ttrap_BotLibVarSet(\"bot_testrchat\", \"1\");\n\t\t\t\t\t//if bot replies with a chat message\n\t\t\t\t\tif (trap_BotReplyChat(bs->cs, message, context, CONTEXT_REPLY,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tNULL, NULL,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tNULL, NULL,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tNULL, NULL,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tbotname, netname)) {\n\t\t\t\t\t\tBotAI_Print(PRT_MESSAGE, \"------------------------\\n\");\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tBotAI_Print(PRT_MESSAGE, \"**** no valid reply ****\\n\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t//if at a valid chat position and not chatting already and not in teamplay\n\t\t\t\telse if (bs->ainode != AINode_Stand && BotValidChatPosition(bs) && !TeamPlayIsOn()) {\n\t\t\t\t\tchat_reply = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_REPLY, 0, 1);\n\t\t\t\t\tif (random() < 1.5 / (NumBots()+1) && random() < chat_reply) {\n\t\t\t\t\t\t//if bot replies with a chat message\n\t\t\t\t\t\tif (trap_BotReplyChat(bs->cs, message, context, CONTEXT_REPLY,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tNULL, NULL,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tNULL, NULL,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tNULL, NULL,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tbotname, netname)) {\n\t\t\t\t\t\t\t//remove the console message\n\t\t\t\t\t\t\ttrap_BotRemoveConsoleMessage(bs->cs, handle);\n\t\t\t\t\t\t\tbs->stand_time = FloatTime() + BotChatTime(bs);\n\t\t\t\t\t\t\tAIEnter_Stand(bs, \"BotCheckConsoleMessages: reply chat\");\n\t\t\t\t\t\t\t//EA_Say(bs->client, bs->cs.chatmessage);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t//remove the console message\n\t\ttrap_BotRemoveConsoleMessage(bs->cs, handle);\n\t}\n}\n\n/*\n==================\nBotCheckEvents\n==================\n*/\nvoid BotCheckForGrenades(bot_state_t *bs, entityState_t *state) {\n\t// if this is not a grenade\n\tif (state->eType != ET_MISSILE || state->weapon != WP_GRENADE_LAUNCHER)\n\t\treturn;\n\t// try to avoid the grenade\n\ttrap_BotAddAvoidSpot(bs->ms, state->pos.trBase, 160, AVOID_ALWAYS);\n}\n\n/*\n==================\nBotCheckEvents\n==================\n*/\nvoid BotCheckEvents(bot_state_t *bs, entityState_t *state) {\n\tint event;\n\tchar buf[128];\n\n\t//NOTE: this sucks, we're accessing the gentity_t directly\n\t//but there's no other fast way to do it right now\n\tif (bs->entityeventTime[state->number] == g_entities[state->number].eventTime) {\n\t\treturn;\n\t}\n\tbs->entityeventTime[state->number] = g_entities[state->number].eventTime;\n\t//if it's an event only entity\n\tif (state->eType > ET_EVENTS) {\n\t\tevent = (state->eType - ET_EVENTS) & ~EV_EVENT_BITS;\n\t}\n\telse {\n\t\tevent = state->event & ~EV_EVENT_BITS;\n\t}\n\t//\n\tswitch(event) {\n\t\t//client obituary event\n\t\tcase EV_OBITUARY:\n\t\t{\n\t\t\tint target, attacker, mod;\n\n\t\t\ttarget = state->otherEntityNum;\n\t\t\tattacker = state->otherEntityNum2;\n\t\t\tmod = state->eventParm;\n\t\t\t//\n\t\t\tif (target == bs->client) {\n\t\t\t\tbs->botdeathtype = mod;\n\t\t\t\tbs->lastkilledby = attacker;\n\t\t\t\t//\n\t\t\t\tif (target == attacker ||\n\t\t\t\t\ttarget == ENTITYNUM_NONE ||\n\t\t\t\t\ttarget == ENTITYNUM_WORLD) bs->botsuicide = qtrue;\n\t\t\t\telse bs->botsuicide = qfalse;\n\t\t\t\t//\n\t\t\t\tbs->num_deaths++;\n\t\t\t}\n\t\t\t//else if this client was killed by the bot\n\t\t\telse if (attacker == bs->client) {\n\t\t\t\tbs->enemydeathtype = mod;\n\t\t\t\tbs->lastkilledplayer = target;\n\t\t\t\tbs->killedenemy_time = FloatTime();\n\t\t\t\t//\n\t\t\t\tbs->num_kills++;\n\t\t\t}\n\t\t\telse if (attacker == bs->enemy && target == attacker) {\n\t\t\t\tbs->enemysuicide = qtrue;\n\t\t\t}\n\t\t\t//\n\t\t\tbreak;\n\t\t}\n\t\tcase EV_GLOBAL_SOUND:\n\t\t{\n\t\t\tif (state->eventParm < 0 || state->eventParm > MAX_SOUNDS) {\n\t\t\t\tBotAI_Print(PRT_ERROR, \"EV_GLOBAL_SOUND: eventParm (%d) out of range\\n\", state->eventParm);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\ttrap_GetConfigstring(CS_SOUNDS + state->eventParm, buf, sizeof(buf));\n\t\t\t/*\n\t\t\tif (!strcmp(buf, \"sound/teamplay/flagret_red.wav\")) {\n\t\t\t\t//red flag is returned\n\t\t\t\tbs->redflagstatus = 0;\n\t\t\t\tbs->flagstatuschanged = qtrue;\n\t\t\t}\n\t\t\telse if (!strcmp(buf, \"sound/teamplay/flagret_blu.wav\")) {\n\t\t\t\t//blue flag is returned\n\t\t\t\tbs->blueflagstatus = 0;\n\t\t\t\tbs->flagstatuschanged = qtrue;\n\t\t\t}\n\t\t\telse*/\n\t\t\t\tif (!strcmp(buf, \"sound/items/poweruprespawn.wav\")) {\n\t\t\t\t//powerup respawned... go get it\n\t\t\t\tBotGoForPowerups(bs);\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase EV_GLOBAL_TEAM_SOUND:\n\t\t{\n\t\t\tif (gametype == GT_CTF) {\n\t\t\t\tswitch(state->eventParm) {\n\t\t\t\t\tcase GTS_RED_CAPTURE:\n\t\t\t\t\t\tbs->blueflagstatus = 0;\n\t\t\t\t\t\tbs->redflagstatus = 0;\n\t\t\t\t\t\tbs->flagstatuschanged = qtrue;\n\t\t\t\t\t\tbreak; //see BotMatch_CTF\n\t\t\t\t\tcase GTS_BLUE_CAPTURE:\n\t\t\t\t\t\tbs->blueflagstatus = 0;\n\t\t\t\t\t\tbs->redflagstatus = 0;\n\t\t\t\t\t\tbs->flagstatuschanged = qtrue;\n\t\t\t\t\t\tbreak; //see BotMatch_CTF\n\t\t\t\t\tcase GTS_RED_RETURN:\n\t\t\t\t\t\t//blue flag is returned\n\t\t\t\t\t\tbs->blueflagstatus = 0;\n\t\t\t\t\t\tbs->flagstatuschanged = qtrue;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase GTS_BLUE_RETURN:\n\t\t\t\t\t\t//red flag is returned\n\t\t\t\t\t\tbs->redflagstatus = 0;\n\t\t\t\t\t\tbs->flagstatuschanged = qtrue;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase GTS_RED_TAKEN:\n\t\t\t\t\t\t//blue flag is taken\n\t\t\t\t\t\tbs->blueflagstatus = 1;\n\t\t\t\t\t\tbs->flagstatuschanged = qtrue;\n\t\t\t\t\t\tbreak; //see BotMatch_CTF\n\t\t\t\t\tcase GTS_BLUE_TAKEN:\n\t\t\t\t\t\t//red flag is taken\n\t\t\t\t\t\tbs->redflagstatus = 1;\n\t\t\t\t\t\tbs->flagstatuschanged = qtrue;\n\t\t\t\t\t\tbreak; //see BotMatch_CTF\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase EV_PLAYER_TELEPORT_IN:\n\t\t{\n\t\t\tVectorCopy(state->origin, lastteleport_origin);\n\t\t\tlastteleport_time = FloatTime();\n\t\t\tbreak;\n\t\t}\n\t\tcase EV_GENERAL_SOUND:\n\t\t{\n\t\t\t//if this sound is played on the bot\n\t\t\tif (state->number == bs->client) {\n\t\t\t\tif (state->eventParm < 0 || state->eventParm > MAX_SOUNDS) {\n\t\t\t\t\tBotAI_Print(PRT_ERROR, \"EV_GENERAL_SOUND: eventParm (%d) out of range\\n\", state->eventParm);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t//check out the sound\n\t\t\t\ttrap_GetConfigstring(CS_SOUNDS + state->eventParm, buf, sizeof(buf));\n\t\t\t\t//if falling into a death pit\n\t\t\t\tif (!strcmp(buf, \"*falling1.wav\")) {\n\t\t\t\t\t//if the bot has a personal teleporter\n\t\t\t\t\tif (bs->inventory[INVENTORY_TELEPORTER] > 0) {\n\t\t\t\t\t\t//use the holdable item\n\t\t\t\t\t\ttrap_EA_Use(bs->client);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase EV_FOOTSTEP:\n\t\tcase EV_FOOTSTEP_METAL:\n\t\tcase EV_FOOTSPLASH:\n\t\tcase EV_FOOTWADE:\n\t\tcase EV_SWIM:\n\t\tcase EV_FALL_SHORT:\n\t\tcase EV_FALL_MEDIUM:\n\t\tcase EV_FALL_FAR:\n\t\tcase EV_STEP_4:\n\t\tcase EV_STEP_8:\n\t\tcase EV_STEP_12:\n\t\tcase EV_STEP_16:\n\t\tcase EV_JUMP_PAD:\n\t\tcase EV_JUMP:\n\t\tcase EV_TAUNT:\n\t\tcase EV_WATER_TOUCH:\n\t\tcase EV_WATER_LEAVE:\n\t\tcase EV_WATER_UNDER:\n\t\tcase EV_WATER_CLEAR:\n\t\tcase EV_ITEM_PICKUP:\n\t\tcase EV_GLOBAL_ITEM_PICKUP:\n\t\tcase EV_NOAMMO:\n\t\tcase EV_CHANGE_WEAPON:\n\t\tcase EV_FIRE_WEAPON:\n\t\t\t//FIXME: either add to sound queue or mark player as someone making noise\n\t\t\tbreak;\n\t\tcase EV_USE_ITEM0:\n\t\tcase EV_USE_ITEM1:\n\t\tcase EV_USE_ITEM2:\n\t\tcase EV_USE_ITEM3:\n\t\tcase EV_USE_ITEM4:\n\t\tcase EV_USE_ITEM5:\n\t\tcase EV_USE_ITEM6:\n\t\tcase EV_USE_ITEM7:\n\t\tcase EV_USE_ITEM8:\n\t\tcase EV_USE_ITEM9:\n\t\tcase EV_USE_ITEM10:\n\t\tcase EV_USE_ITEM11:\n\t\tcase EV_USE_ITEM12:\n\t\tcase EV_USE_ITEM13:\n\t\tcase EV_USE_ITEM14:\n\t\t\tbreak;\n\t}\n}\n\n/*\n==================\nBotCheckSnapshot\n==================\n*/\nvoid BotCheckSnapshot(bot_state_t *bs) {\n\tint ent;\n\tentityState_t state;\n\n\t//remove all avoid spots\n\ttrap_BotAddAvoidSpot(bs->ms, vec3_origin, 0, AVOID_CLEAR);\n\t//reset kamikaze body\n\tbs->kamikazebody = 0;\n\t//reset number of proxmines\n\tbs->numproxmines = 0;\n\t//\n\tent = 0;\n\twhile( ( ent = BotAI_GetSnapshotEntity( bs->client, ent, &state ) ) != -1 ) {\n\t\t//check the entity state for events\n\t\tBotCheckEvents(bs, &state);\n\t\t//check for grenades the bot should avoid\n\t\tBotCheckForGrenades(bs, &state);\n\t\t//\n\t}\n\t//check the player state for events\n\tBotAI_GetEntityState(bs->client, &state);\n\t//copy the player state events to the entity state\n\tstate.event = bs->cur_ps.externalEvent;\n\tstate.eventParm = bs->cur_ps.externalEventParm;\n\t//\n\tBotCheckEvents(bs, &state);\n}\n\n/*\n==================\nBotCheckAir\n==================\n*/\nvoid BotCheckAir(bot_state_t *bs) {\n\tif (bs->inventory[INVENTORY_ENVIRONMENTSUIT] <= 0) {\n\t\tif (trap_AAS_PointContents(bs->eye) & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA)) {\n\t\t\treturn;\n\t\t}\n\t}\n\tbs->lastair_time = FloatTime();\n}\n\n/*\n==================\nBotAlternateRoute\n==================\n*/\nbot_goal_t *BotAlternateRoute(bot_state_t *bs, bot_goal_t *goal) {\n\tint t;\n\n\t// if the bot has an alternative route goal\n\tif (bs->altroutegoal.areanum) {\n\t\t//\n\t\tif (bs->reachedaltroutegoal_time)\n\t\t\treturn goal;\n\t\t// travel time towards alternative route goal\n\t\tt = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, bs->altroutegoal.areanum, bs->tfl);\n\t\tif (t && t < 20) {\n\t\t\t//BotAI_Print(PRT_MESSAGE, \"reached alternate route goal\\n\");\n\t\t\tbs->reachedaltroutegoal_time = FloatTime();\n\t\t}\n\t\tmemcpy(goal, &bs->altroutegoal, sizeof(bot_goal_t));\n\t\treturn &bs->altroutegoal;\n\t}\n\treturn goal;\n}\n\n/*\n==================\nBotGetAlternateRouteGoal\n==================\n*/\nint BotGetAlternateRouteGoal(bot_state_t *bs, int base) {\n\taas_altroutegoal_t *altroutegoals;\n\tbot_goal_t *goal;\n\tint numaltroutegoals, rnd;\n\n\tif (base == TEAM_RED) {\n\t\taltroutegoals = red_altroutegoals;\n\t\tnumaltroutegoals = red_numaltroutegoals;\n\t}\n\telse {\n\t\taltroutegoals = blue_altroutegoals;\n\t\tnumaltroutegoals = blue_numaltroutegoals;\n\t}\n\tif (!numaltroutegoals)\n\t\treturn qfalse;\n\trnd = (float) random() * numaltroutegoals;\n\tif (rnd >= numaltroutegoals)\n\t\trnd = numaltroutegoals-1;\n\tgoal = &bs->altroutegoal;\n\tgoal->areanum = altroutegoals[rnd].areanum;\n\tVectorCopy(altroutegoals[rnd].origin, goal->origin);\n\tVectorSet(goal->mins, -8, -8, -8);\n\tVectorSet(goal->maxs, 8, 8, 8);\n\tgoal->entitynum = 0;\n\tgoal->iteminfo = 0;\n\tgoal->number = 0;\n\tgoal->flags = 0;\n\t//\n\tbs->reachedaltroutegoal_time = 0;\n\treturn qtrue;\n}\n\n/*\n==================\nBotSetupAlternateRouteGoals\n==================\n*/\nvoid BotSetupAlternativeRouteGoals(void) {\n\n\tif (altroutegoals_setup)\n\t\treturn;\n\taltroutegoals_setup = qtrue;\n}\n\n/*\n==================\nBotDeathmatchAI\n==================\n*/\nvoid BotDeathmatchAI(bot_state_t *bs, float thinktime) {\n\tchar gender[144], name[144], buf[144];\n\tchar userinfo[MAX_INFO_STRING];\n\tint i;\n\n\t//if the bot has just been setup\n\tif (bs->setupcount > 0) {\n\t\tbs->setupcount--;\n\t\tif (bs->setupcount > 0) return;\n\t\t//get the gender characteristic\n\t\ttrap_Characteristic_String(bs->character, CHARACTERISTIC_GENDER, gender, sizeof(gender));\n\t\t//set the bot gender\n\t\ttrap_GetUserinfo(bs->client, userinfo, sizeof(userinfo));\n\t\tInfo_SetValueForKey(userinfo, \"sex\", gender);\n\t\ttrap_SetUserinfo(bs->client, userinfo);\n\t\t//set the team\n\t\tif ( !bs->map_restart && g_gametype.integer != GT_TOURNAMENT ) {\n\t\t\tCom_sprintf(buf, sizeof(buf), \"team %s\", bs->settings.team);\n\t\t\ttrap_EA_Command(bs->client, buf);\n\t\t}\n\t\t//set the chat gender\n\t\tif (gender[0] == 'm') trap_BotSetChatGender(bs->cs, CHAT_GENDERMALE);\n\t\telse if (gender[0] == 'f')  trap_BotSetChatGender(bs->cs, CHAT_GENDERFEMALE);\n\t\telse  trap_BotSetChatGender(bs->cs, CHAT_GENDERLESS);\n\t\t//set the chat name\n\t\tClientName(bs->client, name, sizeof(name));\n\t\ttrap_BotSetChatName(bs->cs, name, bs->client);\n\t\t//\n\t\tbs->lastframe_health = bs->inventory[INVENTORY_HEALTH];\n\t\tbs->lasthitcount = bs->cur_ps.persistant[PERS_HITS];\n\t\t//\n\t\tbs->setupcount = 0;\n\t\t//\n\t\tBotSetupAlternativeRouteGoals();\n\t}\n\t//no ideal view set\n\tbs->flags &= ~BFL_IDEALVIEWSET;\n\t//\n\tif (!BotIntermission(bs)) {\n\t\t//set the teleport time\n\t\tBotSetTeleportTime(bs);\n\t\t//update some inventory values\n\t\tBotUpdateInventory(bs);\n\t\t//check out the snapshot\n\t\tBotCheckSnapshot(bs);\n\t\t//check for air\n\t\tBotCheckAir(bs);\n\t}\n\t//check the console messages\n\tBotCheckConsoleMessages(bs);\n\t//if not in the intermission and not in observer mode\n\tif (!BotIntermission(bs) && !BotIsObserver(bs)) {\n\t\t//do team AI\n\t\tBotTeamAI(bs);\n\t}\n\t//if the bot has no ai node\n\tif (!bs->ainode) {\n\t\tAIEnter_Seek_LTG(bs, \"BotDeathmatchAI: no ai node\");\n\t}\n\t//if the bot entered the game less than 8 seconds ago\n\tif (!bs->entergamechat && bs->entergame_time > FloatTime() - 8) {\n\t\tif (BotChat_EnterGame(bs)) {\n\t\t\tbs->stand_time = FloatTime() + BotChatTime(bs);\n\t\t\tAIEnter_Stand(bs, \"BotDeathmatchAI: chat enter game\");\n\t\t}\n\t\tbs->entergamechat = qtrue;\n\t}\n\t//reset the node switches from the previous frame\n\tBotResetNodeSwitches();\n\t//execute AI nodes\n\tfor (i = 0; i < MAX_NODESWITCHES; i++) {\n\t\tif (bs->ainode(bs)) break;\n\t}\n\t//if the bot removed itself :)\n\tif (!bs->inuse) return;\n\t//if the bot executed too many AI nodes\n\tif (i >= MAX_NODESWITCHES) {\n\t\ttrap_BotDumpGoalStack(bs->gs);\n\t\ttrap_BotDumpAvoidGoals(bs->gs);\n\t\tBotDumpNodeSwitches(bs);\n\t\tClientName(bs->client, name, sizeof(name));\n\t\tBotAI_Print(PRT_ERROR, \"%s at %1.1f switched more than %d AI nodes\\n\", name, FloatTime(), MAX_NODESWITCHES);\n\t}\n\t//\n\tbs->lastframe_health = bs->inventory[INVENTORY_HEALTH];\n\tbs->lasthitcount = bs->cur_ps.persistant[PERS_HITS];\n}\n\n/*\n==================\nBotSetEntityNumForGoalWithModel\n==================\n*/\nvoid BotSetEntityNumForGoalWithModel(bot_goal_t *goal, int eType, char *modelname) {\n\tgentity_t *ent;\n\tint i, modelindex;\n\tvec3_t dir;\n\n\tmodelindex = G_ModelIndex( modelname );\n\tent = &g_entities[0];\n\tfor (i = 0; i < level.num_entities; i++, ent++) {\n\t\tif ( !ent->inuse ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( eType && ent->s.eType != eType) {\n\t\t\tcontinue;\n\t\t}\n\t\tif (ent->s.modelindex != modelindex) {\n\t\t\tcontinue;\n\t\t}\n\t\tVectorSubtract(goal->origin, ent->s.origin, dir);\n\t\tif (VectorLengthSquared(dir) < Square(10)) {\n\t\t\tgoal->entitynum = i;\n\t\t\treturn;\n\t\t}\n\t}\n}\n\n/*\n==================\nBotSetEntityNumForGoal\n==================\n*/\nvoid BotSetEntityNumForGoal(bot_goal_t *goal, char *classname) {\n\tgentity_t *ent;\n\tint i;\n\tvec3_t dir;\n\n\tent = &g_entities[0];\n\tfor (i = 0; i < level.num_entities; i++, ent++) {\n\t\tif ( !ent->inuse ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( !Q_stricmp(ent->classname, classname) ) {\n\t\t\tcontinue;\n\t\t}\n\t\tVectorSubtract(goal->origin, ent->s.origin, dir);\n\t\tif (VectorLengthSquared(dir) < Square(10)) {\n\t\t\tgoal->entitynum = i;\n\t\t\treturn;\n\t\t}\n\t}\n}\n\n/*\n==================\nBotGoalForBSPEntity\n==================\n*/\nint BotGoalForBSPEntity( char *classname, bot_goal_t *goal ) {\n\tchar value[MAX_INFO_STRING];\n\tvec3_t origin, start, end;\n\tint ent, numareas, areas[10];\n\n\tmemset(goal, 0, sizeof(bot_goal_t));\n\tfor (ent = trap_AAS_NextBSPEntity(0); ent; ent = trap_AAS_NextBSPEntity(ent)) {\n\t\tif (!trap_AAS_ValueForBSPEpairKey(ent, \"classname\", value, sizeof(value)))\n\t\t\tcontinue;\n\t\tif (!strcmp(value, classname)) {\n\t\t\tif (!trap_AAS_VectorForBSPEpairKey(ent, \"origin\", origin))\n\t\t\t\treturn qfalse;\n\t\t\tVectorCopy(origin, goal->origin);\n\t\t\tVectorCopy(origin, start);\n\t\t\tstart[2] -= 32;\n\t\t\tVectorCopy(origin, end);\n\t\t\tend[2] += 32;\n\t\t\tnumareas = trap_AAS_TraceAreas(start, end, areas, NULL, 10);\n\t\t\tif (!numareas)\n\t\t\t\treturn qfalse;\n\t\t\tgoal->areanum = areas[0];\n\t\t\treturn qtrue;\n\t\t}\n\t}\n\treturn qfalse;\n}\n\n/*\n==================\nBotSetupDeathmatchAI\n==================\n*/\nvoid BotSetupDeathmatchAI(void) {\n\tint ent, modelnum;\n\tchar model[128];\n\n\tgametype = trap_Cvar_VariableIntegerValue(\"g_gametype\");\n\tmaxclients = trap_Cvar_VariableIntegerValue(\"sv_maxclients\");\n\n\ttrap_Cvar_Register(&bot_rocketjump, \"bot_rocketjump\", \"1\", 0);\n\ttrap_Cvar_Register(&bot_grapple, \"bot_grapple\", \"0\", 0);\n\ttrap_Cvar_Register(&bot_fastchat, \"bot_fastchat\", \"0\", 0);\n\ttrap_Cvar_Register(&bot_nochat, \"bot_nochat\", \"0\", 0);\n\ttrap_Cvar_Register(&bot_testrchat, \"bot_testrchat\", \"0\", 0);\n\ttrap_Cvar_Register(&bot_challenge, \"bot_challenge\", \"0\", 0);\n\ttrap_Cvar_Register(&bot_predictobstacles, \"bot_predictobstacles\", \"1\", 0);\n\ttrap_Cvar_Register(&g_spSkill, \"g_spSkill\", \"2\", 0);\n\t//\n\tif (gametype == GT_CTF) {\n\t\tif (trap_BotGetLevelItemGoal(-1, \"Red Flag\", &ctf_redflag) < 0)\n\t\t\tBotAI_Print(PRT_WARNING, \"CTF without Red Flag\\n\");\n\t\tif (trap_BotGetLevelItemGoal(-1, \"Blue Flag\", &ctf_blueflag) < 0)\n\t\t\tBotAI_Print(PRT_WARNING, \"CTF without Blue Flag\\n\");\n\t}\n\n\tmax_bspmodelindex = 0;\n\tfor (ent = trap_AAS_NextBSPEntity(0); ent; ent = trap_AAS_NextBSPEntity(ent)) {\n\t\tif (!trap_AAS_ValueForBSPEpairKey(ent, \"model\", model, sizeof(model))) continue;\n\t\tif (model[0] == '*') {\n\t\t\tmodelnum = atoi(model+1);\n\t\t\tif (modelnum > max_bspmodelindex)\n\t\t\t\tmax_bspmodelindex = modelnum;\n\t\t}\n\t}\n\t//initialize the waypoint heap\n\tBotInitWaypoints();\n}\n\n/*\n==================\nBotShutdownDeathmatchAI\n==================\n*/\nvoid BotShutdownDeathmatchAI(void) {\n\taltroutegoals_setup = qfalse;\n}\n"
  },
  {
    "path": "src/game/ai_dmq3.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n\n/*****************************************************************************\n * name:\t\tai_dmq3.h\n *\n * desc:\t\tQuake3 bot AI\n *\n * $Archive: /source/code/botai/ai_chat.c $\n *\n *****************************************************************************/\n\n//setup the deathmatch AI\nvoid BotSetupDeathmatchAI(void);\n//shutdown the deathmatch AI\nvoid BotShutdownDeathmatchAI(void);\n//let the bot live within it's deathmatch AI net\nvoid BotDeathmatchAI(bot_state_t *bs, float thinktime);\n//free waypoints\nvoid BotFreeWaypoints(bot_waypoint_t *wp);\n//choose a weapon\nvoid BotChooseWeapon(bot_state_t *bs);\n//setup movement stuff\nvoid BotSetupForMovement(bot_state_t *bs);\n//update the inventory\nvoid BotUpdateInventory(bot_state_t *bs);\n//update the inventory during battle\nvoid BotUpdateBattleInventory(bot_state_t *bs, int enemy);\n//use holdable items during battle\nvoid BotBattleUseItems(bot_state_t *bs);\n//return true if the bot is dead\nqboolean BotIsDead(bot_state_t *bs);\n//returns true if the bot is in observer mode\nqboolean BotIsObserver(bot_state_t *bs);\n//returns true if the bot is in the intermission\nqboolean BotIntermission(bot_state_t *bs);\n//returns true if the bot is in lava or slime\nqboolean BotInLavaOrSlime(bot_state_t *bs);\n//returns true if the entity is dead\nqboolean EntityIsDead(aas_entityinfo_t *entinfo);\n//returns true if the entity is invisible\nqboolean EntityIsInvisible(aas_entityinfo_t *entinfo);\n//returns true if the entity is shooting\nqboolean EntityIsShooting(aas_entityinfo_t *entinfo);\n// set a user info key/value pair\nvoid BotSetUserInfo(bot_state_t *bs, char *key, char *value);\n// set the team status (offense, defense etc.)\nvoid BotSetTeamStatus(bot_state_t *bs);\n//returns the name of the client\nchar *ClientName(int client, char *name, int size);\n//returns an simplyfied client name\nchar *EasyClientName(int client, char *name, int size);\n//returns the skin used by the client\nchar *ClientSkin(int client, char *skin, int size);\n// returns the appropriate synonym context for the current game type and situation\nint BotSynonymContext(bot_state_t *bs);\n// set last ordered task\nint BotSetLastOrderedTask(bot_state_t *bs);\n// selection of goals for teamplay\nvoid BotTeamGoals(bot_state_t *bs, int retreat);\n//returns the aggression of the bot in the range [0, 100]\nfloat BotAggression(bot_state_t *bs);\n//returns how bad the bot feels\nfloat BotFeelingBad(bot_state_t *bs);\n//returns true if the bot wants to retreat\nint BotWantsToRetreat(bot_state_t *bs);\n//returns true if the bot wants to chase\nint BotWantsToChase(bot_state_t *bs);\n//returns true if the bot wants to help\nint BotWantsToHelp(bot_state_t *bs);\n//returns true if the bot can and wants to rocketjump\nint BotCanAndWantsToRocketJump(bot_state_t *bs);\n// returns true if the bot has a persistant powerup and a weapon\nint BotHasPersistantPowerupAndWeapon(bot_state_t *bs);\n//returns true if the bot wants to and goes camping\nint BotWantsToCamp(bot_state_t *bs);\n//the bot will perform attack movements\nbot_moveresult_t BotAttackMove(bot_state_t *bs, int tfl);\n//returns true if the bot and the entity are in the same team\nint BotSameTeam(bot_state_t *bs, int entnum);\n//returns true if teamplay is on\nint TeamPlayIsOn(void);\n// returns the client number of the team mate flag carrier (-1 if none)\nint BotTeamFlagCarrier(bot_state_t *bs);\n//returns visible team mate flag carrier if available\nint BotTeamFlagCarrierVisible(bot_state_t *bs);\n//returns visible enemy flag carrier if available\nint BotEnemyFlagCarrierVisible(bot_state_t *bs);\n//get the number of visible teammates and enemies\nvoid BotVisibleTeamMatesAndEnemies(bot_state_t *bs, int *teammates, int *enemies, float range);\n//returns true if within the field of vision for the given angles\nqboolean InFieldOfVision(vec3_t viewangles, float fov, vec3_t angles);\n//returns true and sets the .enemy field when an enemy is found\nint BotFindEnemy(bot_state_t *bs, int curenemy);\n//returns a roam goal\nvoid BotRoamGoal(bot_state_t *bs, vec3_t goal);\n//returns entity visibility in the range [0, 1]\nfloat BotEntityVisible(int viewer, vec3_t eye, vec3_t viewangles, float fov, int ent);\n//the bot will aim at the current enemy\nvoid BotAimAtEnemy(bot_state_t *bs);\n//check if the bot should attack\nvoid BotCheckAttack(bot_state_t *bs);\n//AI when the bot is blocked\nvoid BotAIBlocked(bot_state_t *bs, bot_moveresult_t *moveresult, int activate);\n//AI to predict obstacles\nint BotAIPredictObstacles(bot_state_t *bs, bot_goal_t *goal);\n//enable or disable the areas the blocking entity is in\nvoid BotEnableActivateGoalAreas(bot_activategoal_t *activategoal, int enable);\n//pop an activate goal from the stack\nint BotPopFromActivateGoalStack(bot_state_t *bs);\n//clear the activate goal stack\nvoid BotClearActivateGoalStack(bot_state_t *bs);\n//returns the team the bot is in\nint BotTeam(bot_state_t *bs);\n//retuns the opposite team of the bot\nint BotOppositeTeam(bot_state_t *bs);\n//returns the flag the bot is carrying (CTFFLAG_?)\nint BotCTFCarryingFlag(bot_state_t *bs);\n//remember the last ordered task\nvoid BotRememberLastOrderedTask(bot_state_t *bs);\n//set ctf goals (defend base, get enemy flag) during seek\nvoid BotCTFSeekGoals(bot_state_t *bs);\n//set ctf goals (defend base, get enemy flag) during retreat\nvoid BotCTFRetreatGoals(bot_state_t *bs);\n//get a random alternate route goal towards the given base\nint BotGetAlternateRouteGoal(bot_state_t *bs, int base);\n//returns either the alternate route goal or the given goal\nbot_goal_t *BotAlternateRoute(bot_state_t *bs, bot_goal_t *goal);\n//create a new waypoint\nbot_waypoint_t *BotCreateWayPoint(char *name, vec3_t origin, int areanum);\n//find a waypoint with the given name\nbot_waypoint_t *BotFindWayPoint(bot_waypoint_t *waypoints, char *name);\n//strstr but case insensitive\nchar *stristr(char *str, char *charset);\n//returns the number of the client with the given name\nint ClientFromName(char *name);\nint ClientOnSameTeamFromName(bot_state_t *bs, char *name);\n//\nint BotPointAreaNum(vec3_t origin);\n//\nvoid BotMapScripts(bot_state_t *bs);\n\n//ctf flags\n#define CTF_FLAG_NONE\t\t0\n#define CTF_FLAG_RED\t\t1\n#define CTF_FLAG_BLUE\t\t2\n//CTF skins\n#define CTF_SKIN_REDTEAM\t\"red\"\n#define CTF_SKIN_BLUETEAM\t\"blue\"\n\nextern int gametype;\t\t//game type\nextern int maxclients;\t\t//maximum number of clients\n\nextern vmCvar_t bot_grapple;\nextern vmCvar_t bot_rocketjump;\nextern vmCvar_t bot_fastchat;\nextern vmCvar_t bot_nochat;\nextern vmCvar_t bot_testrchat;\nextern vmCvar_t bot_challenge;\n\nextern bot_goal_t ctf_redflag;\nextern bot_goal_t ctf_blueflag;\n"
  },
  {
    "path": "src/game/ai_main.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n\n/*****************************************************************************\n * name:\t\tai_main.c\n *\n * desc:\t\tQuake3 bot AI\n *\n * $Archive: /MissionPack/code/game/ai_main.c $\n *\n *****************************************************************************/\n\n\n#include \"g_local.h\"\n#include \"q_shared.h\"\n#include \"botlib.h\"\t\t//bot lib interface\n#include \"be_aas.h\"\n#include \"be_ea.h\"\n#include \"be_ai_char.h\"\n#include \"be_ai_chat.h\"\n#include \"be_ai_gen.h\"\n#include \"be_ai_goal.h\"\n#include \"be_ai_move.h\"\n#include \"be_ai_weap.h\"\n//\n#include \"ai_main.h\"\n#include \"ai_dmq3.h\"\n#include \"ai_chat.h\"\n#include \"ai_cmd.h\"\n#include \"ai_dmnet.h\"\n#include \"ai_vcmd.h\"\n\n//\n#include \"chars.h\"\n#include \"inv.h\"\n#include \"syn.h\"\n\n#define MAX_PATH\t\t144\n\n\n//bot states\nbot_state_t\t*botstates[MAX_CLIENTS];\n//number of bots\nint numbots;\n//floating point time\nfloat floattime;\n//time to do a regular update\nfloat regularupdate_time;\n//\nint bot_interbreed;\nint bot_interbreedmatchcount;\n//\nvmCvar_t bot_thinktime;\nvmCvar_t bot_memorydump;\nvmCvar_t bot_saveroutingcache;\nvmCvar_t bot_pause;\nvmCvar_t bot_report;\nvmCvar_t bot_testsolid;\nvmCvar_t bot_testclusters;\nvmCvar_t bot_developer;\nvmCvar_t bot_interbreedchar;\nvmCvar_t bot_interbreedbots;\nvmCvar_t bot_interbreedcycle;\nvmCvar_t bot_interbreedwrite;\n\n\nvoid ExitLevel( void );\n\n\n/*\n==================\nBotAI_Print\n==================\n*/\nvoid QDECL BotAI_Print(int type, char *fmt, ...) {\n\tchar str[2048];\n\tva_list ap;\n\n\tva_start(ap, fmt);\n\tvsprintf(str, fmt, ap);\n\tva_end(ap);\n\n\tswitch(type) {\n\t\tcase PRT_MESSAGE: {\n\t\t\tG_Printf(\"%s\", str);\n\t\t\tbreak;\n\t\t}\n\t\tcase PRT_WARNING: {\n\t\t\tG_Printf( S_COLOR_YELLOW \"Warning: %s\", str );\n\t\t\tbreak;\n\t\t}\n\t\tcase PRT_ERROR: {\n\t\t\tG_Printf( S_COLOR_RED \"Error: %s\", str );\n\t\t\tbreak;\n\t\t}\n\t\tcase PRT_FATAL: {\n\t\t\tG_Printf( S_COLOR_RED \"Fatal: %s\", str );\n\t\t\tbreak;\n\t\t}\n\t\tcase PRT_EXIT: {\n\t\t\tG_Error( S_COLOR_RED \"Exit: %s\", str );\n\t\t\tbreak;\n\t\t}\n\t\tdefault: {\n\t\t\tG_Printf( \"unknown print type\\n\" );\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\n\n/*\n==================\nBotAI_Trace\n==================\n*/\nvoid BotAI_Trace(bsp_trace_t *bsptrace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int passent, int contentmask) {\n\ttrace_t trace;\n\n\ttrap_Trace(&trace, start, mins, maxs, end, passent, contentmask);\n\t//copy the trace information\n\tbsptrace->allsolid = trace.allsolid;\n\tbsptrace->startsolid = trace.startsolid;\n\tbsptrace->fraction = trace.fraction;\n\tVectorCopy(trace.endpos, bsptrace->endpos);\n\tbsptrace->plane.dist = trace.plane.dist;\n\tVectorCopy(trace.plane.normal, bsptrace->plane.normal);\n\tbsptrace->plane.signbits = trace.plane.signbits;\n\tbsptrace->plane.type = trace.plane.type;\n\tbsptrace->surface.value = trace.surfaceFlags;\n\tbsptrace->ent = trace.entityNum;\n\tbsptrace->exp_dist = 0;\n\tbsptrace->sidenum = 0;\n\tbsptrace->contents = 0;\n}\n\n/*\n==================\nBotAI_GetClientState\n==================\n*/\nint BotAI_GetClientState( int clientNum, playerState_t *state ) {\n\tgentity_t\t*ent;\n\n\tent = &g_entities[clientNum];\n\tif ( !ent->inuse ) {\n\t\treturn qfalse;\n\t}\n\tif ( !ent->client ) {\n\t\treturn qfalse;\n\t}\n\n\tmemcpy( state, &ent->client->ps, sizeof(playerState_t) );\n\treturn qtrue;\n}\n\n/*\n==================\nBotAI_GetEntityState\n==================\n*/\nint BotAI_GetEntityState( int entityNum, entityState_t *state ) {\n\tgentity_t\t*ent;\n\n\tent = &g_entities[entityNum];\n\tmemset( state, 0, sizeof(entityState_t) );\n\tif (!ent->inuse) return qfalse;\n\tif (!ent->r.linked) return qfalse;\n\tif (ent->r.svFlags & SVF_NOCLIENT) return qfalse;\n\tmemcpy( state, &ent->s, sizeof(entityState_t) );\n\treturn qtrue;\n}\n\n/*\n==================\nBotAI_GetSnapshotEntity\n==================\n*/\nint BotAI_GetSnapshotEntity( int clientNum, int sequence, entityState_t *state ) {\n\tint\t\tentNum;\n\n\tentNum = trap_BotGetSnapshotEntity( clientNum, sequence );\n\tif ( entNum == -1 ) {\n\t\tmemset(state, 0, sizeof(entityState_t));\n\t\treturn -1;\n\t}\n\n\tBotAI_GetEntityState( entNum, state );\n\n\treturn sequence + 1;\n}\n\n/*\n==================\nBotAI_BotInitialChat\n==================\n*/\nvoid QDECL BotAI_BotInitialChat( bot_state_t *bs, char *type, ... ) {\n\tint\t\ti, mcontext;\n\tva_list\tap;\n\tchar\t*p;\n\tchar\t*vars[MAX_MATCHVARIABLES];\n\n\tmemset(vars, 0, sizeof(vars));\n\tva_start(ap, type);\n\tp = va_arg(ap, char *);\n\tfor (i = 0; i < MAX_MATCHVARIABLES; i++) {\n\t\tif( !p ) {\n\t\t\tbreak;\n\t\t}\n\t\tvars[i] = p;\n\t\tp = va_arg(ap, char *);\n\t}\n\tva_end(ap);\n\n\tmcontext = BotSynonymContext(bs);\n\n\ttrap_BotInitialChat( bs->cs, type, mcontext, vars[0], vars[1], vars[2], vars[3], vars[4], vars[5], vars[6], vars[7] );\n}\n\n\n/*\n==================\nBotTestAAS\n==================\n*/\nvoid BotTestAAS(vec3_t origin) {\n\tint areanum;\n\taas_areainfo_t info;\n\n\ttrap_Cvar_Update(&bot_testsolid);\n\ttrap_Cvar_Update(&bot_testclusters);\n\tif (bot_testsolid.integer) {\n\t\tif (!trap_AAS_Initialized()) return;\n\t\tareanum = BotPointAreaNum(origin);\n\t\tif (areanum) BotAI_Print(PRT_MESSAGE, \"\\remtpy area\");\n\t\telse BotAI_Print(PRT_MESSAGE, \"\\r^1SOLID area\");\n\t}\n\telse if (bot_testclusters.integer) {\n\t\tif (!trap_AAS_Initialized()) return;\n\t\tareanum = BotPointAreaNum(origin);\n\t\tif (!areanum)\n\t\t\tBotAI_Print(PRT_MESSAGE, \"\\r^1Solid!                              \");\n\t\telse {\n\t\t\ttrap_AAS_AreaInfo(areanum, &info);\n\t\t\tBotAI_Print(PRT_MESSAGE, \"\\rarea %d, cluster %d       \", areanum, info.cluster);\n\t\t}\n\t}\n}\n\n/*\n==================\nBotReportStatus\n==================\n*/\nvoid BotReportStatus(bot_state_t *bs) {\n\tchar goalname[MAX_MESSAGE_SIZE];\n\tchar netname[MAX_MESSAGE_SIZE];\n\tchar *leader, flagstatus[32];\n\t//\n\tClientName(bs->client, netname, sizeof(netname));\n\tif (Q_stricmp(netname, bs->teamleader) == 0) leader = \"L\";\n\telse leader = \" \";\n\n\tstrcpy(flagstatus, \"  \");\n\tif (gametype == GT_CTF) {\n\t\tif (BotCTFCarryingFlag(bs)) {\n\t\t\tif (BotTeam(bs) == TEAM_RED) strcpy(flagstatus, S_COLOR_RED\"F \");\n\t\t\telse strcpy(flagstatus, S_COLOR_BLUE\"F \");\n\t\t}\n\t}\n\n\tswitch(bs->ltgtype) {\n\t\tcase LTG_TEAMHELP:\n\t\t{\n\t\t\tEasyClientName(bs->teammate, goalname, sizeof(goalname));\n\t\t\tBotAI_Print(PRT_MESSAGE, \"%-20s%s%s: helping %s\\n\", netname, leader, flagstatus, goalname);\n\t\t\tbreak;\n\t\t}\n\t\tcase LTG_TEAMACCOMPANY:\n\t\t{\n\t\t\tEasyClientName(bs->teammate, goalname, sizeof(goalname));\n\t\t\tBotAI_Print(PRT_MESSAGE, \"%-20s%s%s: accompanying %s\\n\", netname, leader, flagstatus, goalname);\n\t\t\tbreak;\n\t\t}\n\t\tcase LTG_DEFENDKEYAREA:\n\t\t{\n\t\t\ttrap_BotGoalName(bs->teamgoal.number, goalname, sizeof(goalname));\n\t\t\tBotAI_Print(PRT_MESSAGE, \"%-20s%s%s: defending %s\\n\", netname, leader, flagstatus, goalname);\n\t\t\tbreak;\n\t\t}\n\t\tcase LTG_GETITEM:\n\t\t{\n\t\t\ttrap_BotGoalName(bs->teamgoal.number, goalname, sizeof(goalname));\n\t\t\tBotAI_Print(PRT_MESSAGE, \"%-20s%s%s: getting item %s\\n\", netname, leader, flagstatus, goalname);\n\t\t\tbreak;\n\t\t}\n\t\tcase LTG_KILL:\n\t\t{\n\t\t\tClientName(bs->teamgoal.entitynum, goalname, sizeof(goalname));\n\t\t\tBotAI_Print(PRT_MESSAGE, \"%-20s%s%s: killing %s\\n\", netname, leader, flagstatus, goalname);\n\t\t\tbreak;\n\t\t}\n\t\tcase LTG_CAMP:\n\t\tcase LTG_CAMPORDER:\n\t\t{\n\t\t\tBotAI_Print(PRT_MESSAGE, \"%-20s%s%s: camping\\n\", netname, leader, flagstatus);\n\t\t\tbreak;\n\t\t}\n\t\tcase LTG_PATROL:\n\t\t{\n\t\t\tBotAI_Print(PRT_MESSAGE, \"%-20s%s%s: patrolling\\n\", netname, leader, flagstatus);\n\t\t\tbreak;\n\t\t}\n\t\tcase LTG_GETFLAG:\n\t\t{\n\t\t\tBotAI_Print(PRT_MESSAGE, \"%-20s%s%s: capturing flag\\n\", netname, leader, flagstatus);\n\t\t\tbreak;\n\t\t}\n\t\tcase LTG_RUSHBASE:\n\t\t{\n\t\t\tBotAI_Print(PRT_MESSAGE, \"%-20s%s%s: rushing base\\n\", netname, leader, flagstatus);\n\t\t\tbreak;\n\t\t}\n\t\tcase LTG_RETURNFLAG:\n\t\t{\n\t\t\tBotAI_Print(PRT_MESSAGE, \"%-20s%s%s: returning flag\\n\", netname, leader, flagstatus);\n\t\t\tbreak;\n\t\t}\n\t\tcase LTG_ATTACKENEMYBASE:\n\t\t{\n\t\t\tBotAI_Print(PRT_MESSAGE, \"%-20s%s%s: attacking the enemy base\\n\", netname, leader, flagstatus);\n\t\t\tbreak;\n\t\t}\n\t\tcase LTG_HARVEST:\n\t\t{\n\t\t\tBotAI_Print(PRT_MESSAGE, \"%-20s%s%s: harvesting\\n\", netname, leader, flagstatus);\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t{\n\t\t\tBotAI_Print(PRT_MESSAGE, \"%-20s%s%s: roaming\\n\", netname, leader, flagstatus);\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\n/*\n==================\nBotTeamplayReport\n==================\n*/\nvoid BotTeamplayReport(void) {\n\tint i;\n\tchar buf[MAX_INFO_STRING];\n\n\tBotAI_Print(PRT_MESSAGE, S_COLOR_RED\"RED\\n\");\n\tfor (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {\n\t\t//\n\t\tif ( !botstates[i] || !botstates[i]->inuse ) continue;\n\t\t//\n\t\ttrap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));\n\t\t//if no config string or no name\n\t\tif (!strlen(buf) || !strlen(Info_ValueForKey(buf, \"n\"))) continue;\n\t\t//skip spectators\n\t\tif (atoi(Info_ValueForKey(buf, \"t\")) == TEAM_RED) {\n\t\t\tBotReportStatus(botstates[i]);\n\t\t}\n\t}\n\tBotAI_Print(PRT_MESSAGE, S_COLOR_BLUE\"BLUE\\n\");\n\tfor (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {\n\t\t//\n\t\tif ( !botstates[i] || !botstates[i]->inuse ) continue;\n\t\t//\n\t\ttrap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));\n\t\t//if no config string or no name\n\t\tif (!strlen(buf) || !strlen(Info_ValueForKey(buf, \"n\"))) continue;\n\t\t//skip spectators\n\t\tif (atoi(Info_ValueForKey(buf, \"t\")) == TEAM_BLUE) {\n\t\t\tBotReportStatus(botstates[i]);\n\t\t}\n\t}\n}\n\n/*\n==================\nBotSetInfoConfigString\n==================\n*/\nvoid BotSetInfoConfigString(bot_state_t *bs) {\n\tchar goalname[MAX_MESSAGE_SIZE];\n\tchar netname[MAX_MESSAGE_SIZE];\n\tchar action[MAX_MESSAGE_SIZE];\n\tchar *leader, carrying[32], *cs;\n\tbot_goal_t goal;\n\t//\n\tClientName(bs->client, netname, sizeof(netname));\n\tif (Q_stricmp(netname, bs->teamleader) == 0) leader = \"L\";\n\telse leader = \" \";\n\n\tstrcpy(carrying, \"  \");\n\tif (gametype == GT_CTF) {\n\t\tif (BotCTFCarryingFlag(bs)) {\n\t\t\tstrcpy(carrying, \"F \");\n\t\t}\n\t}\n\n\tswitch(bs->ltgtype) {\n\t\tcase LTG_TEAMHELP:\n\t\t{\n\t\t\tEasyClientName(bs->teammate, goalname, sizeof(goalname));\n\t\t\tCom_sprintf(action, sizeof(action), \"helping %s\", goalname);\n\t\t\tbreak;\n\t\t}\n\t\tcase LTG_TEAMACCOMPANY:\n\t\t{\n\t\t\tEasyClientName(bs->teammate, goalname, sizeof(goalname));\n\t\t\tCom_sprintf(action, sizeof(action), \"accompanying %s\", goalname);\n\t\t\tbreak;\n\t\t}\n\t\tcase LTG_DEFENDKEYAREA:\n\t\t{\n\t\t\ttrap_BotGoalName(bs->teamgoal.number, goalname, sizeof(goalname));\n\t\t\tCom_sprintf(action, sizeof(action), \"defending %s\", goalname);\n\t\t\tbreak;\n\t\t}\n\t\tcase LTG_GETITEM:\n\t\t{\n\t\t\ttrap_BotGoalName(bs->teamgoal.number, goalname, sizeof(goalname));\n\t\t\tCom_sprintf(action, sizeof(action), \"getting item %s\", goalname);\n\t\t\tbreak;\n\t\t}\n\t\tcase LTG_KILL:\n\t\t{\n\t\t\tClientName(bs->teamgoal.entitynum, goalname, sizeof(goalname));\n\t\t\tCom_sprintf(action, sizeof(action), \"killing %s\", goalname);\n\t\t\tbreak;\n\t\t}\n\t\tcase LTG_CAMP:\n\t\tcase LTG_CAMPORDER:\n\t\t{\n\t\t\tCom_sprintf(action, sizeof(action), \"camping\");\n\t\t\tbreak;\n\t\t}\n\t\tcase LTG_PATROL:\n\t\t{\n\t\t\tCom_sprintf(action, sizeof(action), \"patrolling\");\n\t\t\tbreak;\n\t\t}\n\t\tcase LTG_GETFLAG:\n\t\t{\n\t\t\tCom_sprintf(action, sizeof(action), \"capturing flag\");\n\t\t\tbreak;\n\t\t}\n\t\tcase LTG_RUSHBASE:\n\t\t{\n\t\t\tCom_sprintf(action, sizeof(action), \"rushing base\");\n\t\t\tbreak;\n\t\t}\n\t\tcase LTG_RETURNFLAG:\n\t\t{\n\t\t\tCom_sprintf(action, sizeof(action), \"returning flag\");\n\t\t\tbreak;\n\t\t}\n\t\tcase LTG_ATTACKENEMYBASE:\n\t\t{\n\t\t\tCom_sprintf(action, sizeof(action), \"attacking the enemy base\");\n\t\t\tbreak;\n\t\t}\n\t\tcase LTG_HARVEST:\n\t\t{\n\t\t\tCom_sprintf(action, sizeof(action), \"harvesting\");\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t{\n\t\t\ttrap_BotGetTopGoal(bs->gs, &goal);\n\t\t\ttrap_BotGoalName(goal.number, goalname, sizeof(goalname));\n\t\t\tCom_sprintf(action, sizeof(action), \"roaming %s\", goalname);\n\t\t\tbreak;\n\t\t}\n\t}\n  \tcs = va(\"l\\\\%s\\\\c\\\\%s\\\\a\\\\%s\",\n\t\t\t\tleader,\n\t\t\t\tcarrying,\n\t\t\t\taction);\n  \ttrap_SetConfigstring (CS_BOTINFO + bs->client, cs);\n}\n\n/*\n==============\nBotUpdateInfoConfigStrings\n==============\n*/\nvoid BotUpdateInfoConfigStrings(void) {\n\tint i;\n\tchar buf[MAX_INFO_STRING];\n\n\tfor (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {\n\t\t//\n\t\tif ( !botstates[i] || !botstates[i]->inuse )\n\t\t\tcontinue;\n\t\t//\n\t\ttrap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));\n\t\t//if no config string or no name\n\t\tif (!strlen(buf) || !strlen(Info_ValueForKey(buf, \"n\")))\n\t\t\tcontinue;\n\t\tBotSetInfoConfigString(botstates[i]);\n\t}\n}\n\n/*\n==============\nBotInterbreedBots\n==============\n*/\nvoid BotInterbreedBots(void) {\n\tfloat ranks[MAX_CLIENTS];\n\tint parent1, parent2, child;\n\tint i;\n\n\t// get rankings for all the bots\n\tfor (i = 0; i < MAX_CLIENTS; i++) {\n\t\tif ( botstates[i] && botstates[i]->inuse ) {\n\t\t\tranks[i] = botstates[i]->num_kills * 2 - botstates[i]->num_deaths;\n\t\t}\n\t\telse {\n\t\t\tranks[i] = -1;\n\t\t}\n\t}\n\n\tif (trap_GeneticParentsAndChildSelection(MAX_CLIENTS, ranks, &parent1, &parent2, &child)) {\n\t\ttrap_BotInterbreedGoalFuzzyLogic(botstates[parent1]->gs, botstates[parent2]->gs, botstates[child]->gs);\n\t\ttrap_BotMutateGoalFuzzyLogic(botstates[child]->gs, 1);\n\t}\n\t// reset the kills and deaths\n\tfor (i = 0; i < MAX_CLIENTS; i++) {\n\t\tif (botstates[i] && botstates[i]->inuse) {\n\t\t\tbotstates[i]->num_kills = 0;\n\t\t\tbotstates[i]->num_deaths = 0;\n\t\t}\n\t}\n}\n\n/*\n==============\nBotWriteInterbreeded\n==============\n*/\nvoid BotWriteInterbreeded(char *filename) {\n\tfloat rank, bestrank;\n\tint i, bestbot;\n\n\tbestrank = 0;\n\tbestbot = -1;\n\t// get the best bot\n\tfor (i = 0; i < MAX_CLIENTS; i++) {\n\t\tif ( botstates[i] && botstates[i]->inuse ) {\n\t\t\trank = botstates[i]->num_kills * 2 - botstates[i]->num_deaths;\n\t\t}\n\t\telse {\n\t\t\trank = -1;\n\t\t}\n\t\tif (rank > bestrank) {\n\t\t\tbestrank = rank;\n\t\t\tbestbot = i;\n\t\t}\n\t}\n\tif (bestbot >= 0) {\n\t\t//write out the new goal fuzzy logic\n\t\ttrap_BotSaveGoalFuzzyLogic(botstates[bestbot]->gs, filename);\n\t}\n}\n\n/*\n==============\nBotInterbreedEndMatch\n\nadd link back into ExitLevel?\n==============\n*/\nvoid BotInterbreedEndMatch(void) {\n\n\tif (!bot_interbreed) return;\n\tbot_interbreedmatchcount++;\n\tif (bot_interbreedmatchcount >= bot_interbreedcycle.integer) {\n\t\tbot_interbreedmatchcount = 0;\n\t\t//\n\t\ttrap_Cvar_Update(&bot_interbreedwrite);\n\t\tif (strlen(bot_interbreedwrite.string)) {\n\t\t\tBotWriteInterbreeded(bot_interbreedwrite.string);\n\t\t\ttrap_Cvar_Set(\"bot_interbreedwrite\", \"\");\n\t\t}\n\t\tBotInterbreedBots();\n\t}\n}\n\n/*\n==============\nBotInterbreeding\n==============\n*/\nvoid BotInterbreeding(void) {\n\tint i;\n\n\ttrap_Cvar_Update(&bot_interbreedchar);\n\tif (!strlen(bot_interbreedchar.string)) return;\n\t//make sure we are in tournament mode\n\tif (gametype != GT_TOURNAMENT) {\n\t\ttrap_Cvar_Set(\"g_gametype\", va(\"%d\", GT_TOURNAMENT));\n\t\tExitLevel();\n\t\treturn;\n\t}\n\t//shutdown all the bots\n\tfor (i = 0; i < MAX_CLIENTS; i++) {\n\t\tif (botstates[i] && botstates[i]->inuse) {\n\t\t\tBotAIShutdownClient(botstates[i]->client, qfalse);\n\t\t}\n\t}\n\t//make sure all item weight configs are reloaded and Not shared\n\ttrap_BotLibVarSet(\"bot_reloadcharacters\", \"1\");\n\t//add a number of bots using the desired bot character\n\tfor (i = 0; i < bot_interbreedbots.integer; i++) {\n\t\ttrap_SendConsoleCommand( EXEC_INSERT, va(\"addbot %s 4 free %i %s%d\\n\",\n\t\t\t\t\t\tbot_interbreedchar.string, i * 50, bot_interbreedchar.string, i) );\n\t}\n\t//\n\ttrap_Cvar_Set(\"bot_interbreedchar\", \"\");\n\tbot_interbreed = qtrue;\n}\n\n/*\n==============\nBotEntityInfo\n==============\n*/\nvoid BotEntityInfo(int entnum, aas_entityinfo_t *info) {\n\ttrap_AAS_EntityInfo(entnum, info);\n}\n\n/*\n==============\nNumBots\n==============\n*/\nint NumBots(void) {\n\treturn numbots;\n}\n\n/*\n==============\nBotTeamLeader\n==============\n*/\nint BotTeamLeader(bot_state_t *bs) {\n\tint leader;\n\n\tleader = ClientFromName(bs->teamleader);\n\tif (leader < 0) return qfalse;\n\tif (!botstates[leader] || !botstates[leader]->inuse) return qfalse;\n\treturn qtrue;\n}\n\n/*\n==============\nAngleDifference\n==============\n*/\nfloat AngleDifference(float ang1, float ang2) {\n\tfloat diff;\n\n\tdiff = ang1 - ang2;\n\tif (ang1 > ang2) {\n\t\tif (diff > 180.0) diff -= 360.0;\n\t}\n\telse {\n\t\tif (diff < -180.0) diff += 360.0;\n\t}\n\treturn diff;\n}\n\n/*\n==============\nBotChangeViewAngle\n==============\n*/\nfloat BotChangeViewAngle(float angle, float ideal_angle, float speed) {\n\tfloat move;\n\n\tangle = AngleMod(angle);\n\tideal_angle = AngleMod(ideal_angle);\n\tif (angle == ideal_angle) return angle;\n\tmove = ideal_angle - angle;\n\tif (ideal_angle > angle) {\n\t\tif (move > 180.0) move -= 360.0;\n\t}\n\telse {\n\t\tif (move < -180.0) move += 360.0;\n\t}\n\tif (move > 0) {\n\t\tif (move > speed) move = speed;\n\t}\n\telse {\n\t\tif (move < -speed) move = -speed;\n\t}\n\treturn AngleMod(angle + move);\n}\n\n/*\n==============\nBotChangeViewAngles\n==============\n*/\nvoid BotChangeViewAngles(bot_state_t *bs, float thinktime) {\n\tfloat diff, factor, maxchange, anglespeed, disired_speed;\n\tint i;\n\n\tif (bs->ideal_viewangles[PITCH] > 180) bs->ideal_viewangles[PITCH] -= 360;\n\t//\n\tif (bs->enemy >= 0) {\n\t\tfactor = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_VIEW_FACTOR, 0.01f, 1);\n\t\tmaxchange = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_VIEW_MAXCHANGE, 1, 1800);\n\t}\n\telse {\n\t\tfactor = 0.05f;\n\t\tmaxchange = 360;\n\t}\n\tif (maxchange < 240) maxchange = 240;\n\tmaxchange *= thinktime;\n\tfor (i = 0; i < 2; i++) {\n\t\t//\n\t\tif (bot_challenge.integer) {\n\t\t\t//smooth slowdown view model\n\t\t\tdiff = abs(AngleDifference(bs->viewangles[i], bs->ideal_viewangles[i]));\n\t\t\tanglespeed = diff * factor;\n\t\t\tif (anglespeed > maxchange) anglespeed = maxchange;\n\t\t\tbs->viewangles[i] = BotChangeViewAngle(bs->viewangles[i],\n\t\t\t\t\t\t\t\t\t\t\tbs->ideal_viewangles[i], anglespeed);\n\t\t}\n\t\telse {\n\t\t\t//over reaction view model\n\t\t\tbs->viewangles[i] = AngleMod(bs->viewangles[i]);\n\t\t\tbs->ideal_viewangles[i] = AngleMod(bs->ideal_viewangles[i]);\n\t\t\tdiff = AngleDifference(bs->viewangles[i], bs->ideal_viewangles[i]);\n\t\t\tdisired_speed = diff * factor;\n\t\t\tbs->viewanglespeed[i] += (bs->viewanglespeed[i] - disired_speed);\n\t\t\tif (bs->viewanglespeed[i] > 180) bs->viewanglespeed[i] = maxchange;\n\t\t\tif (bs->viewanglespeed[i] < -180) bs->viewanglespeed[i] = -maxchange;\n\t\t\tanglespeed = bs->viewanglespeed[i];\n\t\t\tif (anglespeed > maxchange) anglespeed = maxchange;\n\t\t\tif (anglespeed < -maxchange) anglespeed = -maxchange;\n\t\t\tbs->viewangles[i] += anglespeed;\n\t\t\tbs->viewangles[i] = AngleMod(bs->viewangles[i]);\n\t\t\t//demping\n\t\t\tbs->viewanglespeed[i] *= 0.45 * (1 - factor);\n\t\t}\n\t\t//BotAI_Print(PRT_MESSAGE, \"ideal_angles %f %f\\n\", bs->ideal_viewangles[0], bs->ideal_viewangles[1], bs->ideal_viewangles[2]);`\n\t\t//bs->viewangles[i] = bs->ideal_viewangles[i];\n\t}\n\t//bs->viewangles[PITCH] = 0;\n\tif (bs->viewangles[PITCH] > 180) bs->viewangles[PITCH] -= 360;\n\t//elementary action: view\n\ttrap_EA_View(bs->client, bs->viewangles);\n}\n\n/*\n==============\nBotInputToUserCommand\n==============\n*/\nvoid BotInputToUserCommand(bot_input_t *bi, usercmd_t *ucmd, int delta_angles[3], int time) {\n\tvec3_t angles, forward, right;\n\tshort temp;\n\tint j;\n\n\t//clear the whole structure\n\tmemset(ucmd, 0, sizeof(usercmd_t));\n\t//\n\t//Com_Printf(\"dir = %f %f %f speed = %f\\n\", bi->dir[0], bi->dir[1], bi->dir[2], bi->speed);\n\t//the duration for the user command in milli seconds\n\tucmd->serverTime = time;\n\t//\n\tif (bi->actionflags & ACTION_DELAYEDJUMP) {\n\t\tbi->actionflags |= ACTION_JUMP;\n\t\tbi->actionflags &= ~ACTION_DELAYEDJUMP;\n\t}\n\t//set the buttons\n\tif (bi->actionflags & ACTION_RESPAWN) ucmd->buttons = BUTTON_ATTACK;\n\tif (bi->actionflags & ACTION_ATTACK) ucmd->buttons |= BUTTON_ATTACK;\n\tif (bi->actionflags & ACTION_TALK) ucmd->buttons |= BUTTON_TALK;\n\tif (bi->actionflags & ACTION_GESTURE) ucmd->buttons |= BUTTON_GESTURE;\n\tif (bi->actionflags & ACTION_USE) ucmd->buttons |= BUTTON_USE_HOLDABLE;\n\tif (bi->actionflags & ACTION_WALK) ucmd->buttons |= BUTTON_WALKING;\n\tif (bi->actionflags & ACTION_AFFIRMATIVE) ucmd->buttons |= BUTTON_AFFIRMATIVE;\n\tif (bi->actionflags & ACTION_NEGATIVE) ucmd->buttons |= BUTTON_NEGATIVE;\n\tif (bi->actionflags & ACTION_GETFLAG) ucmd->buttons |= BUTTON_GETFLAG;\n\tif (bi->actionflags & ACTION_GUARDBASE) ucmd->buttons |= BUTTON_GUARDBASE;\n\tif (bi->actionflags & ACTION_PATROL) ucmd->buttons |= BUTTON_PATROL;\n\tif (bi->actionflags & ACTION_FOLLOWME) ucmd->buttons |= BUTTON_FOLLOWME;\n\t//\n\tucmd->weapon = bi->weapon;\n\t//set the view angles\n\t//NOTE: the ucmd->angles are the angles WITHOUT the delta angles\n\tucmd->angles[PITCH] = ANGLE2SHORT(bi->viewangles[PITCH]);\n\tucmd->angles[YAW] = ANGLE2SHORT(bi->viewangles[YAW]);\n\tucmd->angles[ROLL] = ANGLE2SHORT(bi->viewangles[ROLL]);\n\t//subtract the delta angles\n\tfor (j = 0; j < 3; j++) {\n\t\ttemp = ucmd->angles[j] - delta_angles[j];\n\t\t/*NOTE: disabled because temp should be mod first\n\t\tif ( j == PITCH ) {\n\t\t\t// don't let the player look up or down more than 90 degrees\n\t\t\tif ( temp > 16000 ) temp = 16000;\n\t\t\telse if ( temp < -16000 ) temp = -16000;\n\t\t}\n\t\t*/\n\t\tucmd->angles[j] = temp;\n\t}\n\t//NOTE: movement is relative to the REAL view angles\n\t//get the horizontal forward and right vector\n\t//get the pitch in the range [-180, 180]\n\tif (bi->dir[2]) angles[PITCH] = bi->viewangles[PITCH];\n\telse angles[PITCH] = 0;\n\tangles[YAW] = bi->viewangles[YAW];\n\tangles[ROLL] = 0;\n\tAngleVectors(angles, forward, right, NULL);\n\t//bot input speed is in the range [0, 400]\n\tbi->speed = bi->speed * 127 / 400;\n\t//set the view independent movement\n\tucmd->forwardmove = DotProduct(forward, bi->dir) * bi->speed;\n\tucmd->rightmove = DotProduct(right, bi->dir) * bi->speed;\n\tucmd->upmove = abs(forward[2]) * bi->dir[2] * bi->speed;\n\t//normal keyboard movement\n\tif (bi->actionflags & ACTION_MOVEFORWARD) ucmd->forwardmove += 127;\n\tif (bi->actionflags & ACTION_MOVEBACK) ucmd->forwardmove -= 127;\n\tif (bi->actionflags & ACTION_MOVELEFT) ucmd->rightmove -= 127;\n\tif (bi->actionflags & ACTION_MOVERIGHT) ucmd->rightmove += 127;\n\t//jump/moveup\n\tif (bi->actionflags & ACTION_JUMP) ucmd->upmove += 127;\n\t//crouch/movedown\n\tif (bi->actionflags & ACTION_CROUCH) ucmd->upmove -= 127;\n\t//\n\t//Com_Printf(\"forward = %d right = %d up = %d\\n\", ucmd.forwardmove, ucmd.rightmove, ucmd.upmove);\n\t//Com_Printf(\"ucmd->serverTime = %d\\n\", ucmd->serverTime);\n}\n\n/*\n==============\nBotUpdateInput\n==============\n*/\nvoid BotUpdateInput(bot_state_t *bs, int time, int elapsed_time) {\n\tbot_input_t bi;\n\tint j;\n\n\t//add the delta angles to the bot's current view angles\n\tfor (j = 0; j < 3; j++) {\n\t\tbs->viewangles[j] = AngleMod(bs->viewangles[j] + SHORT2ANGLE(bs->cur_ps.delta_angles[j]));\n\t}\n\t//change the bot view angles\n\tBotChangeViewAngles(bs, (float) elapsed_time / 1000);\n\t//retrieve the bot input\n\ttrap_EA_GetInput(bs->client, (float) time / 1000, &bi);\n\t//respawn hack\n\tif (bi.actionflags & ACTION_RESPAWN) {\n\t\tif (bs->lastucmd.buttons & BUTTON_ATTACK) bi.actionflags &= ~(ACTION_RESPAWN|ACTION_ATTACK);\n\t}\n\t//convert the bot input to a usercmd\n\tBotInputToUserCommand(&bi, &bs->lastucmd, bs->cur_ps.delta_angles, time);\n\t//subtract the delta angles\n\tfor (j = 0; j < 3; j++) {\n\t\tbs->viewangles[j] = AngleMod(bs->viewangles[j] - SHORT2ANGLE(bs->cur_ps.delta_angles[j]));\n\t}\n}\n\n/*\n==============\nBotAIRegularUpdate\n==============\n*/\nvoid BotAIRegularUpdate(void) {\n\tif (regularupdate_time < FloatTime()) {\n\t\ttrap_BotUpdateEntityItems();\n\t\tregularupdate_time = FloatTime() + 0.3;\n\t}\n}\n\n/*\n==============\nRemoveColorEscapeSequences\n==============\n*/\nvoid RemoveColorEscapeSequences( char *text ) {\n\tint i, l;\n\n\tl = 0;\n\tfor ( i = 0; text[i]; i++ ) {\n\t\tif (Q_IsColorString(&text[i])) {\n\t\t\ti++;\n\t\t\tcontinue;\n\t\t}\n\t\tif (text[i] > 0x7E)\n\t\t\tcontinue;\n\t\ttext[l++] = text[i];\n\t}\n\ttext[l] = '\\0';\n}\n\n/*\n==============\nBotAI\n==============\n*/\nint BotAI(int client, float thinktime) {\n\tbot_state_t *bs;\n\tchar buf[1024], *args;\n\tint j;\n\n\ttrap_EA_ResetInput(client);\n\t//\n\tbs = botstates[client];\n\tif (!bs || !bs->inuse) {\n\t\tBotAI_Print(PRT_FATAL, \"BotAI: client %d is not setup\\n\", client);\n\t\treturn qfalse;\n\t}\n\n\t//retrieve the current client state\n\tBotAI_GetClientState( client, &bs->cur_ps );\n\n\t//retrieve any waiting server commands\n\twhile( trap_BotGetServerCommand(client, buf, sizeof(buf)) ) {\n\t\t//have buf point to the command and args to the command arguments\n\t\targs = strchr( buf, ' ');\n\t\tif (!args) continue;\n\t\t*args++ = '\\0';\n\n\t\t//remove color espace sequences from the arguments\n\t\tRemoveColorEscapeSequences( args );\n\n\t\tif (!Q_stricmp(buf, \"cp \"))\n\t\t\t{ /*CenterPrintf*/ }\n\t\telse if (!Q_stricmp(buf, \"cs\"))\n\t\t\t{ /*ConfigStringModified*/ }\n\t\telse if (!Q_stricmp(buf, \"print\")) {\n\t\t\t//remove first and last quote from the chat message\n\t\t\tmemmove(args, args+1, (int)strlen(args));\n\t\t\targs[strlen(args)-1] = '\\0';\n\t\t\ttrap_BotQueueConsoleMessage(bs->cs, CMS_NORMAL, args);\n\t\t}\n\t\telse if (!Q_stricmp(buf, \"chat\")) {\n\t\t\t//remove first and last quote from the chat message\n\t\t\tmemmove(args, args+1, (int)strlen(args));\n\t\t\targs[strlen(args)-1] = '\\0';\n\t\t\ttrap_BotQueueConsoleMessage(bs->cs, CMS_CHAT, args);\n\t\t}\n\t\telse if (!Q_stricmp(buf, \"tchat\")) {\n\t\t\t//remove first and last quote from the chat message\n\t\t\tmemmove(args, args+1, (int)strlen(args));\n\t\t\targs[strlen(args)-1] = '\\0';\n\t\t\ttrap_BotQueueConsoleMessage(bs->cs, CMS_CHAT, args);\n\t\t}\n\t\telse if (!Q_stricmp(buf, \"scores\"))\n\t\t\t{ /*FIXME: parse scores?*/ }\n\t\telse if (!Q_stricmp(buf, \"clientLevelShot\"))\n\t\t\t{ /*ignore*/ }\n\t}\n\t//add the delta angles to the bot's current view angles\n\tfor (j = 0; j < 3; j++) {\n\t\tbs->viewangles[j] = AngleMod(bs->viewangles[j] + SHORT2ANGLE(bs->cur_ps.delta_angles[j]));\n\t}\n\t//increase the local time of the bot\n\tbs->ltime += thinktime;\n\t//\n\tbs->thinktime = thinktime;\n\t//origin of the bot\n\tVectorCopy(bs->cur_ps.origin, bs->origin);\n\t//eye coordinates of the bot\n\tVectorCopy(bs->cur_ps.origin, bs->eye);\n\tbs->eye[2] += bs->cur_ps.viewheight;\n\t//get the area the bot is in\n\tbs->areanum = BotPointAreaNum(bs->origin);\n\t//the real AI\n\tBotDeathmatchAI(bs, thinktime);\n\t//set the weapon selection every AI frame\n\ttrap_EA_SelectWeapon(bs->client, bs->weaponnum);\n\t//subtract the delta angles\n\tfor (j = 0; j < 3; j++) {\n\t\tbs->viewangles[j] = AngleMod(bs->viewangles[j] - SHORT2ANGLE(bs->cur_ps.delta_angles[j]));\n\t}\n\t//everything was ok\n\treturn qtrue;\n}\n\n/*\n==================\nBotScheduleBotThink\n==================\n*/\nvoid BotScheduleBotThink(void) {\n\tint i, botnum;\n\n\tbotnum = 0;\n\n\tfor( i = 0; i < MAX_CLIENTS; i++ ) {\n\t\tif( !botstates[i] || !botstates[i]->inuse ) {\n\t\t\tcontinue;\n\t\t}\n\t\t//initialize the bot think residual time\n\t\tbotstates[i]->botthink_residual = bot_thinktime.integer * botnum / numbots;\n\t\tbotnum++;\n\t}\n}\n\n/*\n==============\nBotWriteSessionData\n==============\n*/\nvoid BotWriteSessionData(bot_state_t *bs) {\n\tconst char\t*s;\n\tconst char\t*var;\n\n\ts = va(\n\t\t\t\"%i %i %i %i %i %i %i %i\"\n\t\t\t\" %f %f %f\"\n\t\t\t\" %f %f %f\"\n\t\t\t\" %f %f %f\",\n\t\tbs->lastgoal_decisionmaker,\n\t\tbs->lastgoal_ltgtype,\n\t\tbs->lastgoal_teammate,\n\t\tbs->lastgoal_teamgoal.areanum,\n\t\tbs->lastgoal_teamgoal.entitynum,\n\t\tbs->lastgoal_teamgoal.flags,\n\t\tbs->lastgoal_teamgoal.iteminfo,\n\t\tbs->lastgoal_teamgoal.number,\n\t\tbs->lastgoal_teamgoal.origin[0],\n\t\tbs->lastgoal_teamgoal.origin[1],\n\t\tbs->lastgoal_teamgoal.origin[2],\n\t\tbs->lastgoal_teamgoal.mins[0],\n\t\tbs->lastgoal_teamgoal.mins[1],\n\t\tbs->lastgoal_teamgoal.mins[2],\n\t\tbs->lastgoal_teamgoal.maxs[0],\n\t\tbs->lastgoal_teamgoal.maxs[1],\n\t\tbs->lastgoal_teamgoal.maxs[2]\n\t\t);\n\n\tvar = va( \"botsession%i\", bs->client );\n\n\ttrap_Cvar_Set( var, s );\n}\n\n/*\n==============\nBotReadSessionData\n==============\n*/\nvoid BotReadSessionData(bot_state_t *bs) {\n\tchar\ts[MAX_STRING_CHARS];\n\tconst char\t*var;\n\n\tvar = va( \"botsession%i\", bs->client );\n\ttrap_Cvar_VariableStringBuffer( var, s, sizeof(s) );\n\n\tsscanf(s,\n\t\t\t\"%i %i %i %i %i %i %i %i\"\n\t\t\t\" %f %f %f\"\n\t\t\t\" %f %f %f\"\n\t\t\t\" %f %f %f\",\n\t\t&bs->lastgoal_decisionmaker,\n\t\t&bs->lastgoal_ltgtype,\n\t\t&bs->lastgoal_teammate,\n\t\t&bs->lastgoal_teamgoal.areanum,\n\t\t&bs->lastgoal_teamgoal.entitynum,\n\t\t&bs->lastgoal_teamgoal.flags,\n\t\t&bs->lastgoal_teamgoal.iteminfo,\n\t\t&bs->lastgoal_teamgoal.number,\n\t\t&bs->lastgoal_teamgoal.origin[0],\n\t\t&bs->lastgoal_teamgoal.origin[1],\n\t\t&bs->lastgoal_teamgoal.origin[2],\n\t\t&bs->lastgoal_teamgoal.mins[0],\n\t\t&bs->lastgoal_teamgoal.mins[1],\n\t\t&bs->lastgoal_teamgoal.mins[2],\n\t\t&bs->lastgoal_teamgoal.maxs[0],\n\t\t&bs->lastgoal_teamgoal.maxs[1],\n\t\t&bs->lastgoal_teamgoal.maxs[2]\n\t\t);\n}\n\n/*\n==============\nBotAISetupClient\n==============\n*/\nint BotAISetupClient(int client, struct bot_settings_s *settings, qboolean restart) {\n\tchar filename[MAX_PATH], name[MAX_PATH], gender[MAX_PATH];\n\tbot_state_t *bs;\n\tint errnum;\n\n\tif (!botstates[client]) botstates[client] = G_Alloc(sizeof(bot_state_t));\n\tbs = botstates[client];\n\n\tif (bs && bs->inuse) {\n\t\tBotAI_Print(PRT_FATAL, \"BotAISetupClient: client %d already setup\\n\", client);\n\t\treturn qfalse;\n\t}\n\n\tif (!trap_AAS_Initialized()) {\n\t\tBotAI_Print(PRT_FATAL, \"AAS not initialized\\n\");\n\t\treturn qfalse;\n\t}\n\n\t//load the bot character\n\tbs->character = trap_BotLoadCharacter(settings->characterfile, settings->skill);\n\tif (!bs->character) {\n\t\tBotAI_Print(PRT_FATAL, \"couldn't load skill %f from %s\\n\", settings->skill, settings->characterfile);\n\t\treturn qfalse;\n\t}\n\t//copy the settings\n\tmemcpy(&bs->settings, settings, sizeof(bot_settings_t));\n\t//allocate a goal state\n\tbs->gs = trap_BotAllocGoalState(client);\n\t//load the item weights\n\ttrap_Characteristic_String(bs->character, CHARACTERISTIC_ITEMWEIGHTS, filename, MAX_PATH);\n\terrnum = trap_BotLoadItemWeights(bs->gs, filename);\n\tif (errnum != BLERR_NOERROR) {\n\t\ttrap_BotFreeGoalState(bs->gs);\n\t\treturn qfalse;\n\t}\n\t//allocate a weapon state\n\tbs->ws = trap_BotAllocWeaponState();\n\t//load the weapon weights\n\ttrap_Characteristic_String(bs->character, CHARACTERISTIC_WEAPONWEIGHTS, filename, MAX_PATH);\n\terrnum = trap_BotLoadWeaponWeights(bs->ws, filename);\n\tif (errnum != BLERR_NOERROR) {\n\t\ttrap_BotFreeGoalState(bs->gs);\n\t\ttrap_BotFreeWeaponState(bs->ws);\n\t\treturn qfalse;\n\t}\n\t//allocate a chat state\n\tbs->cs = trap_BotAllocChatState();\n\t//load the chat file\n\ttrap_Characteristic_String(bs->character, CHARACTERISTIC_CHAT_FILE, filename, MAX_PATH);\n\ttrap_Characteristic_String(bs->character, CHARACTERISTIC_CHAT_NAME, name, MAX_PATH);\n\terrnum = trap_BotLoadChatFile(bs->cs, filename, name);\n\tif (errnum != BLERR_NOERROR) {\n\t\ttrap_BotFreeChatState(bs->cs);\n\t\ttrap_BotFreeGoalState(bs->gs);\n\t\ttrap_BotFreeWeaponState(bs->ws);\n\t\treturn qfalse;\n\t}\n\t//get the gender characteristic\n\ttrap_Characteristic_String(bs->character, CHARACTERISTIC_GENDER, gender, MAX_PATH);\n\t//set the chat gender\n\tif (*gender == 'f' || *gender == 'F') trap_BotSetChatGender(bs->cs, CHAT_GENDERFEMALE);\n\telse if (*gender == 'm' || *gender == 'M') trap_BotSetChatGender(bs->cs, CHAT_GENDERMALE);\n\telse trap_BotSetChatGender(bs->cs, CHAT_GENDERLESS);\n\n\tbs->inuse = qtrue;\n\tbs->client = client;\n\tbs->entitynum = client;\n\tbs->setupcount = 4;\n\tbs->entergame_time = FloatTime();\n\tbs->ms = trap_BotAllocMoveState();\n\tbs->walker = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_WALKER, 0, 1);\n\tnumbots++;\n\n\tif (trap_Cvar_VariableIntegerValue(\"bot_testichat\")) {\n\t\ttrap_BotLibVarSet(\"bot_testichat\", \"1\");\n\t\tBotChatTest(bs);\n\t}\n\t//NOTE: reschedule the bot thinking\n\tBotScheduleBotThink();\n\t//if interbreeding start with a mutation\n\tif (bot_interbreed) {\n\t\ttrap_BotMutateGoalFuzzyLogic(bs->gs, 1);\n\t}\n\t// if we kept the bot client\n\tif (restart) {\n\t\tBotReadSessionData(bs);\n\t}\n\t//bot has been setup succesfully\n\treturn qtrue;\n}\n\n/*\n==============\nBotAIShutdownClient\n==============\n*/\nint BotAIShutdownClient(int client, qboolean restart) {\n\tbot_state_t *bs;\n\n\tbs = botstates[client];\n\tif (!bs || !bs->inuse) {\n\t\t//BotAI_Print(PRT_ERROR, \"BotAIShutdownClient: client %d already shutdown\\n\", client);\n\t\treturn qfalse;\n\t}\n\n\tif (restart) {\n\t\tBotWriteSessionData(bs);\n\t}\n\n\tif (BotChat_ExitGame(bs)) {\n\t\ttrap_BotEnterChat(bs->cs, bs->client, CHAT_ALL);\n\t}\n\n\ttrap_BotFreeMoveState(bs->ms);\n\t//free the goal state`\t\t\t\n\ttrap_BotFreeGoalState(bs->gs);\n\t//free the chat file\n\ttrap_BotFreeChatState(bs->cs);\n\t//free the weapon weights\n\ttrap_BotFreeWeaponState(bs->ws);\n\t//free the bot character\n\ttrap_BotFreeCharacter(bs->character);\n\t//\n\tBotFreeWaypoints(bs->checkpoints);\n\tBotFreeWaypoints(bs->patrolpoints);\n\t//clear activate goal stack\n\tBotClearActivateGoalStack(bs);\n\t//clear the bot state\n\tmemset(bs, 0, sizeof(bot_state_t));\n\t//set the inuse flag to qfalse\n\tbs->inuse = qfalse;\n\t//there's one bot less\n\tnumbots--;\n\t//everything went ok\n\treturn qtrue;\n}\n\n/*\n==============\nBotResetState\n\ncalled when a bot enters the intermission or observer mode and\nwhen the level is changed\n==============\n*/\nvoid BotResetState(bot_state_t *bs) {\n\tint client, entitynum, inuse;\n\tint movestate, goalstate, chatstate, weaponstate;\n\tbot_settings_t settings;\n\tint character;\n\tplayerState_t ps;\t\t\t\t\t\t\t//current player state\n\tfloat entergame_time;\n\n\t//save some things that should not be reset here\n\tmemcpy(&settings, &bs->settings, sizeof(bot_settings_t));\n\tmemcpy(&ps, &bs->cur_ps, sizeof(playerState_t));\n\tinuse = bs->inuse;\n\tclient = bs->client;\n\tentitynum = bs->entitynum;\n\tcharacter = bs->character;\n\tmovestate = bs->ms;\n\tgoalstate = bs->gs;\n\tchatstate = bs->cs;\n\tweaponstate = bs->ws;\n\tentergame_time = bs->entergame_time;\n\t//free checkpoints and patrol points\n\tBotFreeWaypoints(bs->checkpoints);\n\tBotFreeWaypoints(bs->patrolpoints);\n\t//reset the whole state\n\tmemset(bs, 0, sizeof(bot_state_t));\n\t//copy back some state stuff that should not be reset\n\tbs->ms = movestate;\n\tbs->gs = goalstate;\n\tbs->cs = chatstate;\n\tbs->ws = weaponstate;\n\tmemcpy(&bs->cur_ps, &ps, sizeof(playerState_t));\n\tmemcpy(&bs->settings, &settings, sizeof(bot_settings_t));\n\tbs->inuse = inuse;\n\tbs->client = client;\n\tbs->entitynum = entitynum;\n\tbs->character = character;\n\tbs->entergame_time = entergame_time;\n\t//reset several states\n\tif (bs->ms) trap_BotResetMoveState(bs->ms);\n\tif (bs->gs) trap_BotResetGoalState(bs->gs);\n\tif (bs->ws) trap_BotResetWeaponState(bs->ws);\n\tif (bs->gs) trap_BotResetAvoidGoals(bs->gs);\n\tif (bs->ms) trap_BotResetAvoidReach(bs->ms);\n}\n\n/*\n==============\nBotAILoadMap\n==============\n*/\nint BotAILoadMap( int restart ) {\n\tint\t\t\ti;\n\tvmCvar_t\tmapname;\n\n\tif (!restart) {\n\t\ttrap_Cvar_Register( &mapname, \"mapname\", \"\", CVAR_SERVERINFO | CVAR_ROM );\n\t\ttrap_BotLibLoadMap( mapname.string );\n\t}\n\n\tfor (i = 0; i < MAX_CLIENTS; i++) {\n\t\tif (botstates[i] && botstates[i]->inuse) {\n\t\t\tBotResetState( botstates[i] );\n\t\t\tbotstates[i]->setupcount = 4;\n\t\t}\n\t}\n\n\tBotSetupDeathmatchAI();\n\n\treturn qtrue;\n}\n\n/*\n==================\nBotAIStartFrame\n==================\n*/\nint BotAIStartFrame(int time) {\n\tint i;\n\tgentity_t\t*ent;\n\tbot_entitystate_t state;\n\tint elapsed_time, thinktime;\n\tstatic int local_time;\n\tstatic int botlib_residual;\n\tstatic int lastbotthink_time;\n\n\tG_CheckBotSpawn();\n\n\ttrap_Cvar_Update(&bot_rocketjump);\n\ttrap_Cvar_Update(&bot_grapple);\n\ttrap_Cvar_Update(&bot_fastchat);\n\ttrap_Cvar_Update(&bot_nochat);\n\ttrap_Cvar_Update(&bot_testrchat);\n\ttrap_Cvar_Update(&bot_thinktime);\n\ttrap_Cvar_Update(&bot_memorydump);\n\ttrap_Cvar_Update(&bot_saveroutingcache);\n\ttrap_Cvar_Update(&bot_pause);\n\ttrap_Cvar_Update(&bot_report);\n\n\tif (bot_report.integer) {\n//\t\tBotTeamplayReport();\n//\t\ttrap_Cvar_Set(\"bot_report\", \"0\");\n\t\tBotUpdateInfoConfigStrings();\n\t}\n\n\tif (bot_pause.integer) {\n\t\t// execute bot user commands every frame\n\t\tfor( i = 0; i < MAX_CLIENTS; i++ ) {\n\t\t\tif( !botstates[i] || !botstates[i]->inuse ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif( g_entities[i].client->pers.connected != CON_CONNECTED ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tbotstates[i]->lastucmd.forwardmove = 0;\n\t\t\tbotstates[i]->lastucmd.rightmove = 0;\n\t\t\tbotstates[i]->lastucmd.upmove = 0;\n\t\t\tbotstates[i]->lastucmd.buttons = 0;\n\t\t\tbotstates[i]->lastucmd.serverTime = time;\n\t\t\ttrap_BotUserCommand(botstates[i]->client, &botstates[i]->lastucmd);\n\t\t}\n\t\treturn qtrue;\n\t}\n\n\tif (bot_memorydump.integer) {\n\t\ttrap_BotLibVarSet(\"memorydump\", \"1\");\n\t\ttrap_Cvar_Set(\"bot_memorydump\", \"0\");\n\t}\n\tif (bot_saveroutingcache.integer) {\n\t\ttrap_BotLibVarSet(\"saveroutingcache\", \"1\");\n\t\ttrap_Cvar_Set(\"bot_saveroutingcache\", \"0\");\n\t}\n\t//check if bot interbreeding is activated\n\tBotInterbreeding();\n\t//cap the bot think time\n\tif (bot_thinktime.integer > 200) {\n\t\ttrap_Cvar_Set(\"bot_thinktime\", \"200\");\n\t}\n\t//if the bot think time changed we should reschedule the bots\n\tif (bot_thinktime.integer != lastbotthink_time) {\n\t\tlastbotthink_time = bot_thinktime.integer;\n\t\tBotScheduleBotThink();\n\t}\n\n\telapsed_time = time - local_time;\n\tlocal_time = time;\n\n\tbotlib_residual += elapsed_time;\n\n\tif (elapsed_time > bot_thinktime.integer) thinktime = elapsed_time;\n\telse thinktime = bot_thinktime.integer;\n\n\t// update the bot library\n\tif ( botlib_residual >= thinktime ) {\n\t\tbotlib_residual -= thinktime;\n\n\t\ttrap_BotLibStartFrame((float) time / 1000);\n\n\t\tif (!trap_AAS_Initialized()) return qfalse;\n\n\t\t//update entities in the botlib\n\t\tfor (i = 0; i < MAX_GENTITIES; i++) {\n\t\t\tent = &g_entities[i];\n\t\t\tif (!ent->inuse) {\n\t\t\t\ttrap_BotLibUpdateEntity(i, NULL);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (!ent->r.linked) {\n\t\t\t\ttrap_BotLibUpdateEntity(i, NULL);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (ent->r.svFlags & SVF_NOCLIENT) {\n\t\t\t\ttrap_BotLibUpdateEntity(i, NULL);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// do not update missiles\n\t\t\tif (ent->s.eType == ET_MISSILE && ent->s.weapon != WP_GRAPPLING_HOOK) {\n\t\t\t\ttrap_BotLibUpdateEntity(i, NULL);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// do not update event only entities\n\t\t\tif (ent->s.eType > ET_EVENTS) {\n\t\t\t\ttrap_BotLibUpdateEntity(i, NULL);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t//\n\t\t\tmemset(&state, 0, sizeof(bot_entitystate_t));\n\t\t\t//\n\t\t\tVectorCopy(ent->r.currentOrigin, state.origin);\n\t\t\tif (i < MAX_CLIENTS) {\n\t\t\t\tVectorCopy(ent->s.apos.trBase, state.angles);\n\t\t\t} else {\n\t\t\t\tVectorCopy(ent->r.currentAngles, state.angles);\n\t\t\t}\n\t\t\tVectorCopy(ent->s.origin2, state.old_origin);\n\t\t\tVectorCopy(ent->r.mins, state.mins);\n\t\t\tVectorCopy(ent->r.maxs, state.maxs);\n\t\t\tstate.type = ent->s.eType;\n\t\t\tstate.flags = ent->s.eFlags;\n\t\t\tif (ent->r.bmodel) state.solid = SOLID_BSP;\n\t\t\telse state.solid = SOLID_BBOX;\n\t\t\tstate.groundent = ent->s.groundEntityNum;\n\t\t\tstate.modelindex = ent->s.modelindex;\n\t\t\tstate.modelindex2 = ent->s.modelindex2;\n\t\t\tstate.frame = ent->s.frame;\n\t\t\tstate.event = ent->s.event;\n\t\t\tstate.eventParm = ent->s.eventParm;\n\t\t\tstate.powerups = ent->s.powerups;\n\t\t\tstate.legsAnim = ent->s.legsAnim;\n\t\t\tstate.torsoAnim = ent->s.torsoAnim;\n\t\t\tstate.weapon = ent->s.weapon;\n\t\t\t//\n\t\t\ttrap_BotLibUpdateEntity(i, &state);\n\t\t}\n\n\t\tBotAIRegularUpdate();\n\t}\n\n\tfloattime = trap_AAS_Time();\n\n\t// execute scheduled bot AI\n\tfor( i = 0; i < MAX_CLIENTS; i++ ) {\n\t\tif( !botstates[i] || !botstates[i]->inuse ) {\n\t\t\tcontinue;\n\t\t}\n\t\t//\n\t\tbotstates[i]->botthink_residual += elapsed_time;\n\t\t//\n\t\tif ( botstates[i]->botthink_residual >= thinktime ) {\n\t\t\tbotstates[i]->botthink_residual -= thinktime;\n\n\t\t\tif (!trap_AAS_Initialized()) return qfalse;\n\n\t\t\tif (g_entities[i].client->pers.connected == CON_CONNECTED) {\n\t\t\t\tBotAI(i, (float) thinktime / 1000);\n\t\t\t}\n\t\t}\n\t}\n\n\n\t// execute bot user commands every frame\n\tfor( i = 0; i < MAX_CLIENTS; i++ ) {\n\t\tif( !botstates[i] || !botstates[i]->inuse ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif( g_entities[i].client->pers.connected != CON_CONNECTED ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tBotUpdateInput(botstates[i], time, elapsed_time);\n\t\ttrap_BotUserCommand(botstates[i]->client, &botstates[i]->lastucmd);\n\t}\n\n\treturn qtrue;\n}\n\n/*\n==============\nBotInitLibrary\n==============\n*/\nint BotInitLibrary(void) {\n\tchar buf[144];\n\n\t//set the maxclients and maxentities library variables before calling BotSetupLibrary\n\ttrap_Cvar_VariableStringBuffer(\"sv_maxclients\", buf, sizeof(buf));\n\tif (!strlen(buf)) strcpy(buf, \"8\");\n\ttrap_BotLibVarSet(\"maxclients\", buf);\n\tCom_sprintf(buf, sizeof(buf), \"%d\", MAX_GENTITIES);\n\ttrap_BotLibVarSet(\"maxentities\", buf);\n\t//bsp checksum\n\ttrap_Cvar_VariableStringBuffer(\"sv_mapChecksum\", buf, sizeof(buf));\n\tif (strlen(buf)) trap_BotLibVarSet(\"sv_mapChecksum\", buf);\n\t//maximum number of aas links\n\ttrap_Cvar_VariableStringBuffer(\"max_aaslinks\", buf, sizeof(buf));\n\tif (strlen(buf)) trap_BotLibVarSet(\"max_aaslinks\", buf);\n\t//maximum number of items in a level\n\ttrap_Cvar_VariableStringBuffer(\"max_levelitems\", buf, sizeof(buf));\n\tif (strlen(buf)) trap_BotLibVarSet(\"max_levelitems\", buf);\n\t//game type\n\ttrap_Cvar_VariableStringBuffer(\"g_gametype\", buf, sizeof(buf));\n\tif (!strlen(buf)) strcpy(buf, \"0\");\n\ttrap_BotLibVarSet(\"g_gametype\", buf);\n\t//bot developer mode and log file\n\ttrap_BotLibVarSet(\"bot_developer\", bot_developer.string);\n\ttrap_BotLibVarSet(\"log\", buf);\n\t//no chatting\n\ttrap_Cvar_VariableStringBuffer(\"bot_nochat\", buf, sizeof(buf));\n\tif (strlen(buf)) trap_BotLibVarSet(\"nochat\", \"0\");\n\t//visualize jump pads\n\ttrap_Cvar_VariableStringBuffer(\"bot_visualizejumppads\", buf, sizeof(buf));\n\tif (strlen(buf)) trap_BotLibVarSet(\"bot_visualizejumppads\", buf);\n\t//forced clustering calculations\n\ttrap_Cvar_VariableStringBuffer(\"bot_forceclustering\", buf, sizeof(buf));\n\tif (strlen(buf)) trap_BotLibVarSet(\"forceclustering\", buf);\n\t//forced reachability calculations\n\ttrap_Cvar_VariableStringBuffer(\"bot_forcereachability\", buf, sizeof(buf));\n\tif (strlen(buf)) trap_BotLibVarSet(\"forcereachability\", buf);\n\t//force writing of AAS to file\n\ttrap_Cvar_VariableStringBuffer(\"bot_forcewrite\", buf, sizeof(buf));\n\tif (strlen(buf)) trap_BotLibVarSet(\"forcewrite\", buf);\n\t//no AAS optimization\n\ttrap_Cvar_VariableStringBuffer(\"bot_aasoptimize\", buf, sizeof(buf));\n\tif (strlen(buf)) trap_BotLibVarSet(\"aasoptimize\", buf);\n\t//\n\ttrap_Cvar_VariableStringBuffer(\"bot_saveroutingcache\", buf, sizeof(buf));\n\tif (strlen(buf)) trap_BotLibVarSet(\"saveroutingcache\", buf);\n\t//reload instead of cache bot character files\n\ttrap_Cvar_VariableStringBuffer(\"bot_reloadcharacters\", buf, sizeof(buf));\n\tif (!strlen(buf)) strcpy(buf, \"0\");\n\ttrap_BotLibVarSet(\"bot_reloadcharacters\", buf);\n\t//base directory\n\ttrap_Cvar_VariableStringBuffer(\"fs_basepath\", buf, sizeof(buf));\n\tif (strlen(buf)) trap_BotLibVarSet(\"basedir\", buf);\n\t//game directory\n\ttrap_Cvar_VariableStringBuffer(\"fs_game\", buf, sizeof(buf));\n\tif (strlen(buf)) trap_BotLibVarSet(\"gamedir\", buf);\n\t//cd directory\n\ttrap_Cvar_VariableStringBuffer(\"fs_cdpath\", buf, sizeof(buf));\n\tif (strlen(buf)) trap_BotLibVarSet(\"cddir\", buf);\n\t//setup the bot library\n\treturn trap_BotLibSetup();\n}\n\n/*\n==============\nBotAISetup\n==============\n*/\nint BotAISetup( int restart ) {\n\tint\t\t\terrnum;\n\n\ttrap_Cvar_Register(&bot_thinktime, \"bot_thinktime\", \"100\", CVAR_CHEAT);\n\ttrap_Cvar_Register(&bot_memorydump, \"bot_memorydump\", \"0\", CVAR_CHEAT);\n\ttrap_Cvar_Register(&bot_saveroutingcache, \"bot_saveroutingcache\", \"0\", CVAR_CHEAT);\n\ttrap_Cvar_Register(&bot_pause, \"bot_pause\", \"0\", CVAR_CHEAT);\n\ttrap_Cvar_Register(&bot_report, \"bot_report\", \"0\", CVAR_CHEAT);\n\ttrap_Cvar_Register(&bot_testsolid, \"bot_testsolid\", \"0\", CVAR_CHEAT);\n\ttrap_Cvar_Register(&bot_testclusters, \"bot_testclusters\", \"0\", CVAR_CHEAT);\n\ttrap_Cvar_Register(&bot_developer, \"bot_developer\", \"0\", CVAR_CHEAT);\n\ttrap_Cvar_Register(&bot_interbreedchar, \"bot_interbreedchar\", \"\", 0);\n\ttrap_Cvar_Register(&bot_interbreedbots, \"bot_interbreedbots\", \"10\", 0);\n\ttrap_Cvar_Register(&bot_interbreedcycle, \"bot_interbreedcycle\", \"20\", 0);\n\ttrap_Cvar_Register(&bot_interbreedwrite, \"bot_interbreedwrite\", \"\", 0);\n\n\t//if the game is restarted for a tournament\n\tif (restart) {\n\t\treturn qtrue;\n\t}\n\n\t//initialize the bot states\n\tmemset( botstates, 0, sizeof(botstates) );\n\n\terrnum = BotInitLibrary();\n\tif (errnum != BLERR_NOERROR) return qfalse;\n\treturn qtrue;\n}\n\n/*\n==============\nBotAIShutdown\n==============\n*/\nint BotAIShutdown( int restart ) {\n\n\tint i;\n\n\t//if the game is restarted for a tournament\n\tif ( restart ) {\n\t\t//shutdown all the bots in the botlib\n\t\tfor (i = 0; i < MAX_CLIENTS; i++) {\n\t\t\tif (botstates[i] && botstates[i]->inuse) {\n\t\t\t\tBotAIShutdownClient(botstates[i]->client, restart);\n\t\t\t}\n\t\t}\n\t\t//don't shutdown the bot library\n\t}\n\telse {\n\t\ttrap_BotLibShutdown();\n\t}\n\treturn qtrue;\n}\n\n"
  },
  {
    "path": "src/game/ai_main.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n\n/*****************************************************************************\n * name:\t\tai_main.h\n *\n * desc:\t\tQuake3 bot AI\n *\n * $Archive: /source/code/botai/ai_chat.c $\n *\n *****************************************************************************/\n\n//#define DEBUG\n#define CTF\n\n#define MAX_ITEMS\t\t\t\t\t256\n//bot flags\n#define BFL_STRAFERIGHT\t\t\t\t1\t//strafe to the right\n#define BFL_ATTACKED\t\t\t\t2\t//bot has attacked last ai frame\n#define BFL_ATTACKJUMPED\t\t\t4\t//bot jumped during attack last frame\n#define BFL_AIMATENEMY\t\t\t\t8\t//bot aimed at the enemy this frame\n#define BFL_AVOIDRIGHT\t\t\t\t16\t//avoid obstacles by going to the right\n#define BFL_IDEALVIEWSET\t\t\t32\t//bot has ideal view angles set\n#define BFL_FIGHTSUICIDAL\t\t\t64\t//bot is in a suicidal fight\n//long term goal types\n#define LTG_TEAMHELP\t\t\t\t1\t//help a team mate\n#define LTG_TEAMACCOMPANY\t\t\t2\t//accompany a team mate\n#define LTG_DEFENDKEYAREA\t\t\t3\t//defend a key area\n#define LTG_GETFLAG\t\t\t\t\t4\t//get the enemy flag\n#define LTG_RUSHBASE\t\t\t\t5\t//rush to the base\n#define LTG_RETURNFLAG\t\t\t\t6\t//return the flag\n#define LTG_CAMP\t\t\t\t\t7\t//camp somewhere\n#define LTG_CAMPORDER\t\t\t\t8\t//ordered to camp somewhere\n#define LTG_PATROL\t\t\t\t\t9\t//patrol\n#define LTG_GETITEM\t\t\t\t\t10\t//get an item\n#define LTG_KILL\t\t\t\t\t11\t//kill someone\n#define LTG_HARVEST\t\t\t\t\t12\t//harvest skulls\n#define LTG_ATTACKENEMYBASE\t\t\t13\t//attack the enemy base\n#define LTG_MAKELOVE_UNDER\t\t\t14\n#define LTG_MAKELOVE_ONTOP\t\t\t15\n//some goal dedication times\n#define TEAM_HELP_TIME\t\t\t\t60\t//1 minute teamplay help time\n#define TEAM_ACCOMPANY_TIME\t\t\t600\t//10 minutes teamplay accompany time\n#define TEAM_DEFENDKEYAREA_TIME\t\t600\t//10 minutes ctf defend base time\n#define TEAM_CAMP_TIME\t\t\t\t600\t//10 minutes camping time\n#define TEAM_PATROL_TIME\t\t\t600\t//10 minutes patrolling time\n#define TEAM_LEAD_TIME\t\t\t\t600\t//10 minutes taking the lead\n#define TEAM_GETITEM_TIME\t\t\t60\t//1 minute\n#define\tTEAM_KILL_SOMEONE\t\t\t180\t//3 minute to kill someone\n#define TEAM_ATTACKENEMYBASE_TIME\t600\t//10 minutes\n#define TEAM_HARVEST_TIME\t\t\t120\t//2 minutes\n#define CTF_GETFLAG_TIME\t\t\t600\t//10 minutes ctf get flag time\n#define CTF_RUSHBASE_TIME\t\t\t120\t//2 minutes ctf rush base time\n#define CTF_RETURNFLAG_TIME\t\t\t180\t//3 minutes to return the flag\n#define CTF_ROAM_TIME\t\t\t\t60\t//1 minute ctf roam time\n//patrol flags\n#define PATROL_LOOP\t\t\t\t\t1\n#define PATROL_REVERSE\t\t\t\t2\n#define PATROL_BACK\t\t\t\t\t4\n//teamplay task preference\n#define TEAMTP_DEFENDER\t\t\t\t1\n#define TEAMTP_ATTACKER\t\t\t\t2\n//CTF strategy\n#define CTFS_AGRESSIVE\t\t\t\t1\n//copied from the aas file header\n#define PRESENCE_NONE\t\t\t\t1\n#define PRESENCE_NORMAL\t\t\t\t2\n#define PRESENCE_CROUCH\t\t\t\t4\n//\n#define MAX_PROXMINES\t\t\t\t64\n\n//check points\ntypedef struct bot_waypoint_s\n{\n\tint\t\t\tinuse;\n\tchar\t\tname[32];\n\tbot_goal_t\tgoal;\n\tstruct\t\tbot_waypoint_s *next, *prev;\n} bot_waypoint_t;\n\n#define MAX_ACTIVATESTACK\t\t8\n#define MAX_ACTIVATEAREAS\t\t32\n\ntypedef struct bot_activategoal_s\n{\n\tint inuse;\n\tbot_goal_t goal;\t\t\t\t\t\t//goal to activate (buttons etc.)\n\tfloat time;\t\t\t\t\t\t\t\t//time to activate something\n\tfloat start_time;\t\t\t\t\t\t//time starting to activate something\n\tfloat justused_time;\t\t\t\t\t//time the goal was used\n\tint shoot;\t\t\t\t\t\t\t\t//true if bot has to shoot to activate\n\tint weapon;\t\t\t\t\t\t\t\t//weapon to be used for activation\n\tvec3_t target;\t\t\t\t\t\t\t//target to shoot at to activate something\n\tvec3_t origin;\t\t\t\t\t\t\t//origin of the blocking entity to activate\n\tint areas[MAX_ACTIVATEAREAS];\t\t\t//routing areas disabled by blocking entity\n\tint numareas;\t\t\t\t\t\t\t//number of disabled routing areas\n\tint areasdisabled;\t\t\t\t\t\t//true if the areas are disabled for the routing\n\tstruct bot_activategoal_s *next;\t\t//next activate goal on stack\n} bot_activategoal_t;\n\n//bot state\ntypedef struct bot_state_s\n{\n\tint inuse;\t\t\t\t\t\t\t\t\t\t//true if this state is used by a bot client\n\tint botthink_residual;\t\t\t\t\t\t\t//residual for the bot thinks\n\tint client;\t\t\t\t\t\t\t\t\t\t//client number of the bot\n\tint entitynum;\t\t\t\t\t\t\t\t\t//entity number of the bot\n\tplayerState_t cur_ps;\t\t\t\t\t\t\t//current player state\n\tint last_eFlags;\t\t\t\t\t\t\t\t//last ps flags\n\tusercmd_t lastucmd;\t\t\t\t\t\t\t\t//usercmd from last frame\n\tint entityeventTime[1024];\t\t\t\t\t\t//last entity event time\n\t//\n\tbot_settings_t settings;\t\t\t\t\t\t//several bot settings\n\tint (*ainode)(struct bot_state_s *bs);\t\t\t//current AI node\n\tfloat thinktime;\t\t\t\t\t\t\t\t//time the bot thinks this frame\n\tvec3_t origin;\t\t\t\t\t\t\t\t\t//origin of the bot\n\tvec3_t velocity;\t\t\t\t\t\t\t\t//velocity of the bot\n\tint presencetype;\t\t\t\t\t\t\t\t//presence type of the bot\n\tvec3_t eye;\t\t\t\t\t\t\t\t\t\t//eye coordinates of the bot\n\tint areanum;\t\t\t\t\t\t\t\t\t//the number of the area the bot is in\n\tint inventory[MAX_ITEMS];\t\t\t\t\t\t//string with items amounts the bot has\n\tint tfl;\t\t\t\t\t\t\t\t\t\t//the travel flags the bot uses\n\tint flags;\t\t\t\t\t\t\t\t\t\t//several flags\n\tint respawn_wait;\t\t\t\t\t\t\t\t//wait until respawned\n\tint lasthealth;\t\t\t\t\t\t\t\t\t//health value previous frame\n\tint lastkilledplayer;\t\t\t\t\t\t\t//last killed player\n\tint lastkilledby;\t\t\t\t\t\t\t\t//player that last killed this bot\n\tint botdeathtype;\t\t\t\t\t\t\t\t//the death type of the bot\n\tint enemydeathtype;\t\t\t\t\t\t\t\t//the death type of the enemy\n\tint botsuicide;\t\t\t\t\t\t\t\t\t//true when the bot suicides\n\tint enemysuicide;\t\t\t\t\t\t\t\t//true when the enemy of the bot suicides\n\tint setupcount;\t\t\t\t\t\t\t\t\t//true when the bot has just been setup\n\tint map_restart;\t\t\t\t\t\t\t\t\t//true when the map is being restarted\n\tint entergamechat;\t\t\t\t\t\t\t\t//true when the bot used an enter game chat\n\tint num_deaths;\t\t\t\t\t\t\t\t\t//number of time this bot died\n\tint num_kills;\t\t\t\t\t\t\t\t\t//number of kills of this bot\n\tint revenge_enemy;\t\t\t\t\t\t\t\t//the revenge enemy\n\tint revenge_kills;\t\t\t\t\t\t\t\t//number of kills the enemy made\n\tint lastframe_health;\t\t\t\t\t\t\t//health value the last frame\n\tint lasthitcount;\t\t\t\t\t\t\t\t//number of hits last frame\n\tint chatto;\t\t\t\t\t\t\t\t\t\t//chat to all or team\n\tfloat walker;\t\t\t\t\t\t\t\t\t//walker charactertic\n\tfloat ltime;\t\t\t\t\t\t\t\t\t//local bot time\n\tfloat entergame_time;\t\t\t\t\t\t\t//time the bot entered the game\n\tfloat ltg_time;\t\t\t\t\t\t\t\t\t//long term goal time\n\tfloat nbg_time;\t\t\t\t\t\t\t\t\t//nearby goal time\n\tfloat respawn_time;\t\t\t\t\t\t\t\t//time the bot takes to respawn\n\tfloat respawnchat_time;\t\t\t\t\t\t\t//time the bot started a chat during respawn\n\tfloat chase_time;\t\t\t\t\t\t\t\t//time the bot will chase the enemy\n\tfloat enemyvisible_time;\t\t\t\t\t\t//time the enemy was last visible\n\tfloat check_time;\t\t\t\t\t\t\t\t//time to check for nearby items\n\tfloat stand_time;\t\t\t\t\t\t\t\t//time the bot is standing still\n\tfloat lastchat_time;\t\t\t\t\t\t\t//time the bot last selected a chat\n\tfloat kamikaze_time;\t\t\t\t\t\t\t//time to check for kamikaze usage\n\tfloat invulnerability_time;\t\t\t\t\t\t//time to check for invulnerability usage\n\tfloat standfindenemy_time;\t\t\t\t\t\t//time to find enemy while standing\n\tfloat attackstrafe_time;\t\t\t\t\t\t//time the bot is strafing in one dir\n\tfloat attackcrouch_time;\t\t\t\t\t\t//time the bot will stop crouching\n\tfloat attackchase_time;\t\t\t\t\t\t\t//time the bot chases during actual attack\n\tfloat attackjump_time;\t\t\t\t\t\t\t//time the bot jumped during attack\n\tfloat enemysight_time;\t\t\t\t\t\t\t//time before reacting to enemy\n\tfloat enemydeath_time;\t\t\t\t\t\t\t//time the enemy died\n\tfloat enemyposition_time;\t\t\t\t\t\t//time the position and velocity of the enemy were stored\n\tfloat defendaway_time;\t\t\t\t\t\t\t//time away while defending\n\tfloat defendaway_range;\t\t\t\t\t\t\t//max travel time away from defend area\n\tfloat rushbaseaway_time;\t\t\t\t\t\t//time away from rushing to the base\n\tfloat attackaway_time;\t\t\t\t\t\t\t//time away from attacking the enemy base\n\tfloat harvestaway_time;\t\t\t\t\t\t\t//time away from harvesting\n\tfloat ctfroam_time;\t\t\t\t\t\t\t\t//time the bot is roaming in ctf\n\tfloat killedenemy_time;\t\t\t\t\t\t\t//time the bot killed the enemy\n\tfloat arrive_time;\t\t\t\t\t\t\t\t//time arrived (at companion)\n\tfloat lastair_time;\t\t\t\t\t\t\t\t//last time the bot had air\n\tfloat teleport_time;\t\t\t\t\t\t\t//last time the bot teleported\n\tfloat camp_time;\t\t\t\t\t\t\t\t//last time camped\n\tfloat camp_range;\t\t\t\t\t\t\t\t//camp range\n\tfloat weaponchange_time;\t\t\t\t\t\t//time the bot started changing weapons\n\tfloat firethrottlewait_time;\t\t\t\t\t//amount of time to wait\n\tfloat firethrottleshoot_time;\t\t\t\t\t//amount of time to shoot\n\tfloat notblocked_time;\t\t\t\t\t\t\t//last time the bot was not blocked\n\tfloat blockedbyavoidspot_time;\t\t\t\t\t//time blocked by an avoid spot\n\tfloat predictobstacles_time;\t\t\t\t\t//last time the bot predicted obstacles\n\tint predictobstacles_goalareanum;\t\t\t\t//last goal areanum the bot predicted obstacles for\n\tvec3_t aimtarget;\n\tvec3_t enemyvelocity;\t\t\t\t\t\t\t//enemy velocity 0.5 secs ago during battle\n\tvec3_t enemyorigin;\t\t\t\t\t\t\t\t//enemy origin 0.5 secs ago during battle\n\t//\n\tint kamikazebody;\t\t\t\t\t\t\t\t//kamikaze body\n\tint proxmines[MAX_PROXMINES];\n\tint numproxmines;\n\t//\n\tint character;\t\t\t\t\t\t\t\t\t//the bot character\n\tint ms;\t\t\t\t\t\t\t\t\t\t\t//move state of the bot\n\tint gs;\t\t\t\t\t\t\t\t\t\t\t//goal state of the bot\n\tint cs;\t\t\t\t\t\t\t\t\t\t\t//chat state of the bot\n\tint ws;\t\t\t\t\t\t\t\t\t\t\t//weapon state of the bot\n\t//\n\tint enemy;\t\t\t\t\t\t\t\t\t\t//enemy entity number\n\tint lastenemyareanum;\t\t\t\t\t\t\t//last reachability area the enemy was in\n\tvec3_t lastenemyorigin;\t\t\t\t\t\t\t//last origin of the enemy in the reachability area\n\tint weaponnum;\t\t\t\t\t\t\t\t\t//current weapon number\n\tvec3_t viewangles;\t\t\t\t\t\t\t\t//current view angles\n\tvec3_t ideal_viewangles;\t\t\t\t\t\t//ideal view angles\n\tvec3_t viewanglespeed;\n\t//\n\tint ltgtype;\t\t\t\t\t\t\t\t\t//long term goal type\n\t// team goals\n\tint teammate;\t\t\t\t\t\t\t\t\t//team mate involved in this team goal\n\tint decisionmaker;\t\t\t\t\t\t\t\t//player who decided to go for this goal\n\tint ordered;\t\t\t\t\t\t\t\t\t//true if ordered to do something\n\tfloat order_time;\t\t\t\t\t\t\t\t//time ordered to do something\n\tint owndecision_time;\t\t\t\t\t\t\t//time the bot made it's own decision\n\tbot_goal_t teamgoal;\t\t\t\t\t\t\t//the team goal\n\tbot_goal_t altroutegoal;\t\t\t\t\t\t//alternative route goal\n\tfloat reachedaltroutegoal_time;\t\t\t\t\t//time the bot reached the alt route goal\n\tfloat teammessage_time;\t\t\t\t\t\t\t//time to message team mates what the bot is doing\n\tfloat teamgoal_time;\t\t\t\t\t\t\t//time to stop helping team mate\n\tfloat teammatevisible_time;\t\t\t\t\t\t//last time the team mate was NOT visible\n\tint teamtaskpreference;\t\t\t\t\t\t\t//team task preference\n\t// last ordered team goal\n\tint lastgoal_decisionmaker;\n\tint lastgoal_ltgtype;\n\tint lastgoal_teammate;\n\tbot_goal_t lastgoal_teamgoal;\n\t// for leading team mates\n\tint lead_teammate;\t\t\t\t\t\t\t\t//team mate the bot is leading\n\tbot_goal_t lead_teamgoal;\t\t\t\t\t\t//team goal while leading\n\tfloat lead_time;\t\t\t\t\t\t\t\t//time leading someone\n\tfloat leadvisible_time;\t\t\t\t\t\t\t//last time the team mate was visible\n\tfloat leadmessage_time;\t\t\t\t\t\t\t//last time a messaged was sent to the team mate\n\tfloat leadbackup_time;\t\t\t\t\t\t\t//time backing up towards team mate\n\t//\n\tchar teamleader[32];\t\t\t\t\t\t\t//netname of the team leader\n\tfloat askteamleader_time;\t\t\t\t\t\t//time asked for team leader\n\tfloat becometeamleader_time;\t\t\t\t\t//time the bot will become the team leader\n\tfloat teamgiveorders_time;\t\t\t\t\t\t//time to give team orders\n\tfloat lastflagcapture_time;\t\t\t\t\t\t//last time a flag was captured\n\tint numteammates;\t\t\t\t\t\t\t\t//number of team mates\n\tint redflagstatus;\t\t\t\t\t\t\t\t//0 = at base, 1 = not at base\n\tint blueflagstatus;\t\t\t\t\t\t\t\t//0 = at base, 1 = not at base\n\tint neutralflagstatus;\t\t\t\t\t\t\t//0 = at base, 1 = our team has flag, 2 = enemy team has flag, 3 = enemy team dropped the flag\n\tint flagstatuschanged;\t\t\t\t\t\t\t//flag status changed\n\tint forceorders;\t\t\t\t\t\t\t\t//true if forced to give orders\n\tint flagcarrier;\t\t\t\t\t\t\t\t//team mate carrying the enemy flag\n\tint ctfstrategy;\t\t\t\t\t\t\t\t//ctf strategy\n\tchar subteam[32];\t\t\t\t\t\t\t\t//sub team name\n\tfloat formation_dist;\t\t\t\t\t\t\t//formation team mate intervening space\n\tchar formation_teammate[16];\t\t\t\t\t//netname of the team mate the bot uses for relative positioning\n\tfloat formation_angle;\t\t\t\t\t\t\t//angle relative to the formation team mate\n\tvec3_t formation_dir;\t\t\t\t\t\t\t//the direction the formation is moving in\n\tvec3_t formation_origin;\t\t\t\t\t\t//origin the bot uses for relative positioning\n\tbot_goal_t formation_goal;\t\t\t\t\t\t//formation goal\n\n\tbot_activategoal_t *activatestack;\t\t\t\t//first activate goal on the stack\n\tbot_activategoal_t activategoalheap[MAX_ACTIVATESTACK];\t//activate goal heap\n\n\tbot_waypoint_t *checkpoints;\t\t\t\t\t//check points\n\tbot_waypoint_t *patrolpoints;\t\t\t\t\t//patrol points\n\tbot_waypoint_t *curpatrolpoint;\t\t\t\t\t//current patrol point the bot is going for\n\tint patrolflags;\t\t\t\t\t\t\t\t//patrol flags\n} bot_state_t;\n\n//resets the whole bot state\nvoid BotResetState(bot_state_t *bs);\n//returns the number of bots in the game\nint NumBots(void);\n//returns info about the entity\nvoid BotEntityInfo(int entnum, aas_entityinfo_t *info);\n\nextern float floattime;\n#define FloatTime() floattime\n\n// from the game source\nvoid\tQDECL BotAI_Print(int type, char *fmt, ...);\nvoid\tQDECL QDECL BotAI_BotInitialChat( bot_state_t *bs, char *type, ... );\nvoid\tBotAI_Trace(bsp_trace_t *bsptrace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int passent, int contentmask);\nint\t\tBotAI_GetClientState( int clientNum, playerState_t *state );\nint\t\tBotAI_GetEntityState( int entityNum, entityState_t *state );\nint\t\tBotAI_GetSnapshotEntity( int clientNum, int sequence, entityState_t *state );\nint\t\tBotTeamLeader(bot_state_t *bs);\n"
  },
  {
    "path": "src/game/ai_team.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n\n/*****************************************************************************\n * name:\t\tai_team.c\n *\n * desc:\t\tQuake3 bot AI\n *\n * $Archive: /MissionPack/code/game/ai_team.c $\n *\n *****************************************************************************/\n\n#include \"g_local.h\"\n#include \"botlib.h\"\n#include \"be_aas.h\"\n#include \"be_ea.h\"\n#include \"be_ai_char.h\"\n#include \"be_ai_chat.h\"\n#include \"be_ai_gen.h\"\n#include \"be_ai_goal.h\"\n#include \"be_ai_move.h\"\n#include \"be_ai_weap.h\"\n//\n#include \"ai_main.h\"\n#include \"ai_dmq3.h\"\n#include \"ai_chat.h\"\n#include \"ai_cmd.h\"\n#include \"ai_dmnet.h\"\n#include \"ai_team.h\"\n#include \"ai_vcmd.h\"\n\n#include \"match.h\"\n\n// for the voice chats\n#include \"menudef.h\"\n\n//ctf task preferences for a client\ntypedef struct bot_ctftaskpreference_s\n{\n\tchar\t\tname[36];\n\tint\t\t\tpreference;\n} bot_ctftaskpreference_t;\n\nbot_ctftaskpreference_t ctftaskpreferences[MAX_CLIENTS];\n\n\n/*\n==================\nBotValidTeamLeader\n==================\n*/\nint BotValidTeamLeader(bot_state_t *bs) {\n\tif (!strlen(bs->teamleader)) return qfalse;\n\tif (ClientFromName(bs->teamleader) == -1) return qfalse;\n\treturn qtrue;\n}\n\n/*\n==================\nBotNumTeamMates\n==================\n*/\nint BotNumTeamMates(bot_state_t *bs) {\n\tint i, numplayers;\n\tchar buf[MAX_INFO_STRING];\n\tstatic int maxclients;\n\n\tif (!maxclients)\n\t\tmaxclients = trap_Cvar_VariableIntegerValue(\"sv_maxclients\");\n\n\tnumplayers = 0;\n\tfor (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {\n\t\ttrap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));\n\t\t//if no config string or no name\n\t\tif (!strlen(buf) || !strlen(Info_ValueForKey(buf, \"n\"))) continue;\n\t\t//skip spectators\n\t\tif (atoi(Info_ValueForKey(buf, \"t\")) == TEAM_SPECTATOR) continue;\n\t\t//\n\t\tif (BotSameTeam(bs, i)) {\n\t\t\tnumplayers++;\n\t\t}\n\t}\n\treturn numplayers;\n}\n\n/*\n==================\nBotClientTravelTimeToGoal\n==================\n*/\nint BotClientTravelTimeToGoal(int client, bot_goal_t *goal) {\n\tplayerState_t ps;\n\tint areanum;\n\n\tBotAI_GetClientState(client, &ps);\n\tareanum = BotPointAreaNum(ps.origin);\n\tif (!areanum) return 1;\n\treturn trap_AAS_AreaTravelTimeToGoalArea(areanum, ps.origin, goal->areanum, TFL_DEFAULT);\n}\n\n/*\n==================\nBotSortTeamMatesByBaseTravelTime\n==================\n*/\nint BotSortTeamMatesByBaseTravelTime(bot_state_t *bs, int *teammates, int maxteammates) {\n\n\tint i, j, k, numteammates, traveltime;\n\tchar buf[MAX_INFO_STRING];\n\tstatic int maxclients;\n\tint traveltimes[MAX_CLIENTS];\n\tbot_goal_t *goal = NULL;\n\n\tif (gametype == GT_CTF || gametype == GT_1FCTF) {\n\t\tif (BotTeam(bs) == TEAM_RED)\n\t\t\tgoal = &ctf_redflag;\n\t\telse\n\t\t\tgoal = &ctf_blueflag;\n\t}\n\tif (!maxclients)\n\t\tmaxclients = trap_Cvar_VariableIntegerValue(\"sv_maxclients\");\n\n\tnumteammates = 0;\n\tfor (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {\n\t\ttrap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));\n\t\t//if no config string or no name\n\t\tif (!strlen(buf) || !strlen(Info_ValueForKey(buf, \"n\"))) continue;\n\t\t//skip spectators\n\t\tif (atoi(Info_ValueForKey(buf, \"t\")) == TEAM_SPECTATOR) continue;\n\t\t//\n\t\tif (BotSameTeam(bs, i)) {\n\t\t\t//\n\t\t\ttraveltime = BotClientTravelTimeToGoal(i, goal);\n\t\t\t//\n\t\t\tfor (j = 0; j < numteammates; j++) {\n\t\t\t\tif (traveltime < traveltimes[j]) {\n\t\t\t\t\tfor (k = numteammates; k > j; k--) {\n\t\t\t\t\t\ttraveltimes[k] = traveltimes[k-1];\n\t\t\t\t\t\tteammates[k] = teammates[k-1];\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\ttraveltimes[j] = traveltime;\n\t\t\tteammates[j] = i;\n\t\t\tnumteammates++;\n\t\t\tif (numteammates >= maxteammates) break;\n\t\t}\n\t}\n\treturn numteammates;\n}\n\n/*\n==================\nBotSetTeamMateTaskPreference\n==================\n*/\nvoid BotSetTeamMateTaskPreference(bot_state_t *bs, int teammate, int preference) {\n\tchar teammatename[MAX_NETNAME];\n\n\tctftaskpreferences[teammate].preference = preference;\n\tClientName(teammate, teammatename, sizeof(teammatename));\n\tstrcpy(ctftaskpreferences[teammate].name, teammatename);\n}\n\n/*\n==================\nBotGetTeamMateTaskPreference\n==================\n*/\nint BotGetTeamMateTaskPreference(bot_state_t *bs, int teammate) {\n\tchar teammatename[MAX_NETNAME];\n\n\tif (!ctftaskpreferences[teammate].preference) return 0;\n\tClientName(teammate, teammatename, sizeof(teammatename));\n\tif (Q_stricmp(teammatename, ctftaskpreferences[teammate].name)) return 0;\n\treturn ctftaskpreferences[teammate].preference;\n}\n\n/*\n==================\nBotSortTeamMatesByTaskPreference\n==================\n*/\nint BotSortTeamMatesByTaskPreference(bot_state_t *bs, int *teammates, int numteammates) {\n\tint defenders[MAX_CLIENTS], numdefenders;\n\tint attackers[MAX_CLIENTS], numattackers;\n\tint roamers[MAX_CLIENTS], numroamers;\n\tint i, preference;\n\n\tnumdefenders = numattackers = numroamers = 0;\n\tfor (i = 0; i < numteammates; i++) {\n\t\tpreference = BotGetTeamMateTaskPreference(bs, teammates[i]);\n\t\tif (preference & TEAMTP_DEFENDER) {\n\t\t\tdefenders[numdefenders++] = teammates[i];\n\t\t}\n\t\telse if (preference & TEAMTP_ATTACKER) {\n\t\t\tattackers[numattackers++] = teammates[i];\n\t\t}\n\t\telse {\n\t\t\troamers[numroamers++] = teammates[i];\n\t\t}\n\t}\n\tnumteammates = 0;\n\t//defenders at the front of the list\n\tmemcpy(&teammates[numteammates], defenders, numdefenders * sizeof(int));\n\tnumteammates += numdefenders;\n\t//roamers in the middle\n\tmemcpy(&teammates[numteammates], roamers, numroamers * sizeof(int));\n\tnumteammates += numroamers;\n\t//attacker in the back of the list\n\tmemcpy(&teammates[numteammates], attackers, numattackers * sizeof(int));\n\tnumteammates += numattackers;\n\n\treturn numteammates;\n}\n\n/*\n==================\nBotSayTeamOrders\n==================\n*/\nvoid BotSayTeamOrderAlways(bot_state_t *bs, int toclient) {\n\tchar teamchat[MAX_MESSAGE_SIZE];\n\tchar buf[MAX_MESSAGE_SIZE];\n\tchar name[MAX_NETNAME];\n\n\t//if the bot is talking to itself\n\tif (bs->client == toclient) {\n\t\t//don't show the message just put it in the console message queue\n\t\ttrap_BotGetChatMessage(bs->cs, buf, sizeof(buf));\n\t\tClientName(bs->client, name, sizeof(name));\n\t\tCom_sprintf(teamchat, sizeof(teamchat), EC\"(%s\"EC\")\"EC\": %s\", name, buf);\n\t\ttrap_BotQueueConsoleMessage(bs->cs, CMS_CHAT, teamchat);\n\t}\n\telse {\n\t\ttrap_BotEnterChat(bs->cs, toclient, CHAT_TELL);\n\t}\n}\n\n/*\n==================\nBotSayTeamOrders\n==================\n*/\nvoid BotSayTeamOrder(bot_state_t *bs, int toclient) {\n\tBotSayTeamOrderAlways(bs, toclient);\n}\n\n/*\n==================\nBotVoiceChat\n==================\n*/\nvoid BotVoiceChat(bot_state_t *bs, int toclient, char *voicechat) {\n}\n\n/*\n==================\nBotVoiceChatOnly\n==================\n*/\nvoid BotVoiceChatOnly(bot_state_t *bs, int toclient, char *voicechat) {\n}\n\n/*\n==================\nBotSayVoiceTeamOrder\n==================\n*/\nvoid BotSayVoiceTeamOrder(bot_state_t *bs, int toclient, char *voicechat) {\n}\n\n/*\n==================\nBotCTFOrders\n==================\n*/\nvoid BotCTFOrders_BothFlagsNotAtBase(bot_state_t *bs) {\n\tint numteammates, defenders, attackers, i, other;\n\tint teammates[MAX_CLIENTS];\n\tchar name[MAX_NETNAME], carriername[MAX_NETNAME];\n\n\tnumteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));\n\tBotSortTeamMatesByTaskPreference(bs, teammates, numteammates);\n\t//different orders based on the number of team mates\n\tswitch(bs->numteammates) {\n\t\tcase 1: break;\n\t\tcase 2:\n\t\t{\n\t\t\t//tell the one not carrying the flag to attack the enemy base\n\t\t\tif (teammates[0] != bs->flagcarrier) other = teammates[0];\n\t\t\telse other = teammates[1];\n\t\t\tClientName(other, name, sizeof(name));\n\t\t\tBotAI_BotInitialChat(bs, \"cmd_getflag\", name, NULL);\n\t\t\tBotSayTeamOrder(bs, other);\n\t\t\tBotSayVoiceTeamOrder(bs, other, VOICECHAT_GETFLAG);\n\t\t\tbreak;\n\t\t}\n\t\tcase 3:\n\t\t{\n\t\t\t//tell the one closest to the base not carrying the flag to accompany the flag carrier\n\t\t\tif (teammates[0] != bs->flagcarrier) other = teammates[0];\n\t\t\telse other = teammates[1];\n\t\t\tClientName(other, name, sizeof(name));\n\t\t\tif ( bs->flagcarrier != -1 ) {\n\t\t\t\tClientName(bs->flagcarrier, carriername, sizeof(carriername));\n\t\t\t\tif (bs->flagcarrier == bs->client) {\n\t\t\t\t\tBotAI_BotInitialChat(bs, \"cmd_accompanyme\", name, NULL);\n\t\t\t\t\tBotSayVoiceTeamOrder(bs, other, VOICECHAT_FOLLOWME);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tBotAI_BotInitialChat(bs, \"cmd_accompany\", name, carriername, NULL);\n\t\t\t\t\tBotSayVoiceTeamOrder(bs, other, VOICECHAT_FOLLOWFLAGCARRIER);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t//\n\t\t\t\tBotAI_BotInitialChat(bs, \"cmd_getflag\", name, NULL);\n\t\t\t\tBotSayVoiceTeamOrder(bs, other, VOICECHAT_GETFLAG);\n\t\t\t}\n\t\t\tBotSayTeamOrder(bs, other);\n\t\t\t//tell the one furthest from the the base not carrying the flag to get the enemy flag\n\t\t\tif (teammates[2] != bs->flagcarrier) other = teammates[2];\n\t\t\telse other = teammates[1];\n\t\t\tClientName(other, name, sizeof(name));\n\t\t\tBotAI_BotInitialChat(bs, \"cmd_getflag\", name, NULL);\n\t\t\tBotSayTeamOrder(bs, other);\n\t\t\tBotSayVoiceTeamOrder(bs, other, VOICECHAT_RETURNFLAG);\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t{\n\t\t\tdefenders = (int) (float) numteammates * 0.4 + 0.5;\n\t\t\tif (defenders > 4) defenders = 4;\n\t\t\tattackers = (int) (float) numteammates * 0.5 + 0.5;\n\t\t\tif (attackers > 5) attackers = 5;\n\t\t\tif (bs->flagcarrier != -1) {\n\t\t\t\tClientName(bs->flagcarrier, carriername, sizeof(carriername));\n\t\t\t\tfor (i = 0; i < defenders; i++) {\n\t\t\t\t\t//\n\t\t\t\t\tif (teammates[i] == bs->flagcarrier) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\t//\n\t\t\t\t\tClientName(teammates[i], name, sizeof(name));\n\t\t\t\t\tif (bs->flagcarrier == bs->client) {\n\t\t\t\t\t\tBotAI_BotInitialChat(bs, \"cmd_accompanyme\", name, NULL);\n\t\t\t\t\t\tBotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_FOLLOWME);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tBotAI_BotInitialChat(bs, \"cmd_accompany\", name, carriername, NULL);\n\t\t\t\t\t\tBotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_FOLLOWFLAGCARRIER);\n\t\t\t\t\t}\n\t\t\t\t\tBotSayTeamOrder(bs, teammates[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tfor (i = 0; i < defenders; i++) {\n\t\t\t\t\t//\n\t\t\t\t\tif (teammates[i] == bs->flagcarrier) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\t//\n\t\t\t\t\tClientName(teammates[i], name, sizeof(name));\n\t\t\t\t\tBotAI_BotInitialChat(bs, \"cmd_getflag\", name, NULL);\n\t\t\t\t\tBotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_GETFLAG);\n\t\t\t\t\tBotSayTeamOrder(bs, teammates[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (i = 0; i < attackers; i++) {\n\t\t\t\t//\n\t\t\t\tif (teammates[numteammates - i - 1] == bs->flagcarrier) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t//\n\t\t\t\tClientName(teammates[numteammates - i - 1], name, sizeof(name));\n\t\t\t\tBotAI_BotInitialChat(bs, \"cmd_getflag\", name, NULL);\n\t\t\t\tBotSayTeamOrder(bs, teammates[numteammates - i - 1]);\n\t\t\t\tBotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_RETURNFLAG);\n\t\t\t}\n\t\t\t//\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\n/*\n==================\nBotCTFOrders\n==================\n*/\nvoid BotCTFOrders_FlagNotAtBase(bot_state_t *bs) {\n\tint numteammates, defenders, attackers, i;\n\tint teammates[MAX_CLIENTS];\n\tchar name[MAX_NETNAME];\n\n\tnumteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));\n\tBotSortTeamMatesByTaskPreference(bs, teammates, numteammates);\n\t//passive strategy\n\tif (!(bs->ctfstrategy & CTFS_AGRESSIVE)) {\n\t\t//different orders based on the number of team mates\n\t\tswitch(bs->numteammates) {\n\t\t\tcase 1: break;\n\t\t\tcase 2:\n\t\t\t{\n\t\t\t\t//both will go for the enemy flag\n\t\t\t\tClientName(teammates[0], name, sizeof(name));\n\t\t\t\tBotAI_BotInitialChat(bs, \"cmd_defendbase\", name, NULL);\n\t\t\t\tBotSayTeamOrder(bs, teammates[0]);\n\t\t\t\tBotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_GETFLAG);\n\t\t\t\t//\n\t\t\t\tClientName(teammates[1], name, sizeof(name));\n\t\t\t\tBotAI_BotInitialChat(bs, \"cmd_getflag\", name, NULL);\n\t\t\t\tBotSayTeamOrder(bs, teammates[1]);\n\t\t\t\tBotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 3:\n\t\t\t{\n\t\t\t\t//keep one near the base for when the flag is returned\n\t\t\t\tClientName(teammates[0], name, sizeof(name));\n\t\t\t\tBotAI_BotInitialChat(bs, \"cmd_defendbase\", name, NULL);\n\t\t\t\tBotSayTeamOrder(bs, teammates[0]);\n\t\t\t\tBotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);\n\t\t\t\t//the other two get the flag\n\t\t\t\tClientName(teammates[1], name, sizeof(name));\n\t\t\t\tBotAI_BotInitialChat(bs, \"cmd_getflag\", name, NULL);\n\t\t\t\tBotSayTeamOrder(bs, teammates[1]);\n\t\t\t\tBotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);\n\t\t\t\t//\n\t\t\t\tClientName(teammates[2], name, sizeof(name));\n\t\t\t\tBotAI_BotInitialChat(bs, \"cmd_getflag\", name, NULL);\n\t\t\t\tBotSayTeamOrder(bs, teammates[2]);\n\t\t\t\tBotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault:\n\t\t\t{\n\t\t\t\t//keep some people near the base for when the flag is returned\n\t\t\t\tdefenders = (int) (float) numteammates * 0.3 + 0.5;\n\t\t\t\tif (defenders > 3) defenders = 3;\n\t\t\t\tattackers = (int) (float) numteammates * 0.7 + 0.5;\n\t\t\t\tif (attackers > 6) attackers = 6;\n\t\t\t\tfor (i = 0; i < defenders; i++) {\n\t\t\t\t\t//\n\t\t\t\t\tClientName(teammates[i], name, sizeof(name));\n\t\t\t\t\tBotAI_BotInitialChat(bs, \"cmd_defendbase\", name, NULL);\n\t\t\t\t\tBotSayTeamOrder(bs, teammates[i]);\n\t\t\t\t\tBotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);\n\t\t\t\t}\n\t\t\t\tfor (i = 0; i < attackers; i++) {\n\t\t\t\t\t//\n\t\t\t\t\tClientName(teammates[numteammates - i - 1], name, sizeof(name));\n\t\t\t\t\tBotAI_BotInitialChat(bs, \"cmd_getflag\", name, NULL);\n\t\t\t\t\tBotSayTeamOrder(bs, teammates[numteammates - i - 1]);\n\t\t\t\t\tBotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_GETFLAG);\n\t\t\t\t}\n\t\t\t\t//\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\telse {\n\t\t//different orders based on the number of team mates\n\t\tswitch(bs->numteammates) {\n\t\t\tcase 1: break;\n\t\t\tcase 2:\n\t\t\t{\n\t\t\t\t//both will go for the enemy flag\n\t\t\t\tClientName(teammates[0], name, sizeof(name));\n\t\t\t\tBotAI_BotInitialChat(bs, \"cmd_getflag\", name, NULL);\n\t\t\t\tBotSayTeamOrder(bs, teammates[0]);\n\t\t\t\tBotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_GETFLAG);\n\t\t\t\t//\n\t\t\t\tClientName(teammates[1], name, sizeof(name));\n\t\t\t\tBotAI_BotInitialChat(bs, \"cmd_getflag\", name, NULL);\n\t\t\t\tBotSayTeamOrder(bs, teammates[1]);\n\t\t\t\tBotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 3:\n\t\t\t{\n\t\t\t\t//everyone go for the flag\n\t\t\t\tClientName(teammates[0], name, sizeof(name));\n\t\t\t\tBotAI_BotInitialChat(bs, \"cmd_defendbase\", name, NULL);\n\t\t\t\tBotSayTeamOrder(bs, teammates[0]);\n\t\t\t\tBotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_GETFLAG);\n\t\t\t\t//\n\t\t\t\tClientName(teammates[1], name, sizeof(name));\n\t\t\t\tBotAI_BotInitialChat(bs, \"cmd_getflag\", name, NULL);\n\t\t\t\tBotSayTeamOrder(bs, teammates[1]);\n\t\t\t\tBotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);\n\t\t\t\t//\n\t\t\t\tClientName(teammates[2], name, sizeof(name));\n\t\t\t\tBotAI_BotInitialChat(bs, \"cmd_getflag\", name, NULL);\n\t\t\t\tBotSayTeamOrder(bs, teammates[2]);\n\t\t\t\tBotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault:\n\t\t\t{\n\t\t\t\t//keep some people near the base for when the flag is returned\n\t\t\t\tdefenders = (int) (float) numteammates * 0.2 + 0.5;\n\t\t\t\tif (defenders > 2) defenders = 2;\n\t\t\t\tattackers = (int) (float) numteammates * 0.7 + 0.5;\n\t\t\t\tif (attackers > 7) attackers = 7;\n\t\t\t\tfor (i = 0; i < defenders; i++) {\n\t\t\t\t\t//\n\t\t\t\t\tClientName(teammates[i], name, sizeof(name));\n\t\t\t\t\tBotAI_BotInitialChat(bs, \"cmd_defendbase\", name, NULL);\n\t\t\t\t\tBotSayTeamOrder(bs, teammates[i]);\n\t\t\t\t\tBotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);\n\t\t\t\t}\n\t\t\t\tfor (i = 0; i < attackers; i++) {\n\t\t\t\t\t//\n\t\t\t\t\tClientName(teammates[numteammates - i - 1], name, sizeof(name));\n\t\t\t\t\tBotAI_BotInitialChat(bs, \"cmd_getflag\", name, NULL);\n\t\t\t\t\tBotSayTeamOrder(bs, teammates[numteammates - i - 1]);\n\t\t\t\t\tBotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);\n\t\t\t\t}\n\t\t\t\t//\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n}\n\n/*\n==================\nBotCTFOrders\n==================\n*/\nvoid BotCTFOrders_EnemyFlagNotAtBase(bot_state_t *bs) {\n\tint numteammates, defenders, attackers, i, other;\n\tint teammates[MAX_CLIENTS];\n\tchar name[MAX_NETNAME], carriername[MAX_NETNAME];\n\n\tnumteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));\n\tBotSortTeamMatesByTaskPreference(bs, teammates, numteammates);\n\t//different orders based on the number of team mates\n\tswitch(numteammates) {\n\t\tcase 1: break;\n\t\tcase 2:\n\t\t{\n\t\t\t//tell the one not carrying the flag to defend the base\n\t\t\tif (teammates[0] == bs->flagcarrier) other = teammates[1];\n\t\t\telse other = teammates[0];\n\t\t\tClientName(other, name, sizeof(name));\n\t\t\tBotAI_BotInitialChat(bs, \"cmd_defendbase\", name, NULL);\n\t\t\tBotSayTeamOrder(bs, other);\n\t\t\tBotSayVoiceTeamOrder(bs, other, VOICECHAT_DEFEND);\n\t\t\tbreak;\n\t\t}\n\t\tcase 3:\n\t\t{\n\t\t\t//tell the one closest to the base not carrying the flag to defend the base\n\t\t\tif (teammates[0] != bs->flagcarrier) other = teammates[0];\n\t\t\telse other = teammates[1];\n\t\t\tClientName(other, name, sizeof(name));\n\t\t\tBotAI_BotInitialChat(bs, \"cmd_defendbase\", name, NULL);\n\t\t\tBotSayTeamOrder(bs, other);\n\t\t\tBotSayVoiceTeamOrder(bs, other, VOICECHAT_DEFEND);\n\t\t\t//tell the other also to defend the base\n\t\t\tif (teammates[2] != bs->flagcarrier) other = teammates[2];\n\t\t\telse other = teammates[1];\n\t\t\tClientName(other, name, sizeof(name));\n\t\t\tBotAI_BotInitialChat(bs, \"cmd_defendbase\", name, NULL);\n\t\t\tBotSayTeamOrder(bs, other);\n\t\t\tBotSayVoiceTeamOrder(bs, other, VOICECHAT_DEFEND);\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t{\n\t\t\t//60% will defend the base\n\t\t\tdefenders = (int) (float) numteammates * 0.6 + 0.5;\n\t\t\tif (defenders > 6) defenders = 6;\n\t\t\t//30% accompanies the flag carrier\n\t\t\tattackers = (int) (float) numteammates * 0.3 + 0.5;\n\t\t\tif (attackers > 3) attackers = 3;\n\t\t\tfor (i = 0; i < defenders; i++) {\n\t\t\t\t//\n\t\t\t\tif (teammates[i] == bs->flagcarrier) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tClientName(teammates[i], name, sizeof(name));\n\t\t\t\tBotAI_BotInitialChat(bs, \"cmd_defendbase\", name, NULL);\n\t\t\t\tBotSayTeamOrder(bs, teammates[i]);\n\t\t\t\tBotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);\n\t\t\t}\n\t\t\t// if we have a flag carrier\n\t\t\tif ( bs->flagcarrier != -1 ) {\n\t\t\t\tClientName(bs->flagcarrier, carriername, sizeof(carriername));\n\t\t\t\tfor (i = 0; i < attackers; i++) {\n\t\t\t\t\t//\n\t\t\t\t\tif (teammates[numteammates - i - 1] == bs->flagcarrier) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\t//\n\t\t\t\t\tClientName(teammates[numteammates - i - 1], name, sizeof(name));\n\t\t\t\t\tif (bs->flagcarrier == bs->client) {\n\t\t\t\t\t\tBotAI_BotInitialChat(bs, \"cmd_accompanyme\", name, NULL);\n\t\t\t\t\t\tBotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_FOLLOWME);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tBotAI_BotInitialChat(bs, \"cmd_accompany\", name, carriername, NULL);\n\t\t\t\t\t\tBotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_FOLLOWFLAGCARRIER);\n\t\t\t\t\t}\n\t\t\t\t\tBotSayTeamOrder(bs, teammates[numteammates - i - 1]);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tfor (i = 0; i < attackers; i++) {\n\t\t\t\t\t//\n\t\t\t\t\tif (teammates[numteammates - i - 1] == bs->flagcarrier) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\t//\n\t\t\t\t\tClientName(teammates[numteammates - i - 1], name, sizeof(name));\n\t\t\t\t\tBotAI_BotInitialChat(bs, \"cmd_getflag\", name, NULL);\n\t\t\t\t\tBotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);\n\t\t\t\t\tBotSayTeamOrder(bs, teammates[numteammates - i - 1]);\n\t\t\t\t}\n\t\t\t}\n\t\t\t//\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\n\n/*\n==================\nBotCTFOrders\n==================\n*/\nvoid BotCTFOrders_BothFlagsAtBase(bot_state_t *bs) {\n\tint numteammates, defenders, attackers, i;\n\tint teammates[MAX_CLIENTS];\n\tchar name[MAX_NETNAME];\n\n\t//sort team mates by travel time to base\n\tnumteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));\n\t//sort team mates by CTF preference\n\tBotSortTeamMatesByTaskPreference(bs, teammates, numteammates);\n\t//passive strategy\n\tif (!(bs->ctfstrategy & CTFS_AGRESSIVE)) {\n\t\t//different orders based on the number of team mates\n\t\tswitch(numteammates) {\n\t\t\tcase 1: break;\n\t\t\tcase 2:\n\t\t\t{\n\t\t\t\t//the one closest to the base will defend the base\n\t\t\t\tClientName(teammates[0], name, sizeof(name));\n\t\t\t\tBotAI_BotInitialChat(bs, \"cmd_defendbase\", name, NULL);\n\t\t\t\tBotSayTeamOrder(bs, teammates[0]);\n\t\t\t\tBotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);\n\t\t\t\t//the other will get the flag\n\t\t\t\tClientName(teammates[1], name, sizeof(name));\n\t\t\t\tBotAI_BotInitialChat(bs, \"cmd_getflag\", name, NULL);\n\t\t\t\tBotSayTeamOrder(bs, teammates[1]);\n\t\t\t\tBotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 3:\n\t\t\t{\n\t\t\t\t//the one closest to the base will defend the base\n\t\t\t\tClientName(teammates[0], name, sizeof(name));\n\t\t\t\tBotAI_BotInitialChat(bs, \"cmd_defendbase\", name, NULL);\n\t\t\t\tBotSayTeamOrder(bs, teammates[0]);\n\t\t\t\tBotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);\n\t\t\t\t//the second one closest to the base will defend the base\n\t\t\t\tClientName(teammates[1], name, sizeof(name));\n\t\t\t\tBotAI_BotInitialChat(bs, \"cmd_defendbase\", name, NULL);\n\t\t\t\tBotSayTeamOrder(bs, teammates[1]);\n\t\t\t\tBotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND);\n\t\t\t\t//the other will get the flag\n\t\t\t\tClientName(teammates[2], name, sizeof(name));\n\t\t\t\tBotAI_BotInitialChat(bs, \"cmd_getflag\", name, NULL);\n\t\t\t\tBotSayTeamOrder(bs, teammates[2]);\n\t\t\t\tBotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault:\n\t\t\t{\n\t\t\t\tdefenders = (int) (float) numteammates * 0.5 + 0.5;\n\t\t\t\tif (defenders > 5) defenders = 5;\n\t\t\t\tattackers = (int) (float) numteammates * 0.4 + 0.5;\n\t\t\t\tif (attackers > 4) attackers = 4;\n\t\t\t\tfor (i = 0; i < defenders; i++) {\n\t\t\t\t\t//\n\t\t\t\t\tClientName(teammates[i], name, sizeof(name));\n\t\t\t\t\tBotAI_BotInitialChat(bs, \"cmd_defendbase\", name, NULL);\n\t\t\t\t\tBotSayTeamOrder(bs, teammates[i]);\n\t\t\t\t\tBotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);\n\t\t\t\t}\n\t\t\t\tfor (i = 0; i < attackers; i++) {\n\t\t\t\t\t//\n\t\t\t\t\tClientName(teammates[numteammates - i - 1], name, sizeof(name));\n\t\t\t\t\tBotAI_BotInitialChat(bs, \"cmd_getflag\", name, NULL);\n\t\t\t\t\tBotSayTeamOrder(bs, teammates[numteammates - i - 1]);\n\t\t\t\t\tBotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);\n\t\t\t\t}\n\t\t\t\t//\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\telse {\n\t\t//different orders based on the number of team mates\n\t\tswitch(numteammates) {\n\t\t\tcase 1: break;\n\t\t\tcase 2:\n\t\t\t{\n\t\t\t\t//the one closest to the base will defend the base\n\t\t\t\tClientName(teammates[0], name, sizeof(name));\n\t\t\t\tBotAI_BotInitialChat(bs, \"cmd_defendbase\", name, NULL);\n\t\t\t\tBotSayTeamOrder(bs, teammates[0]);\n\t\t\t\tBotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);\n\t\t\t\t//the other will get the flag\n\t\t\t\tClientName(teammates[1], name, sizeof(name));\n\t\t\t\tBotAI_BotInitialChat(bs, \"cmd_getflag\", name, NULL);\n\t\t\t\tBotSayTeamOrder(bs, teammates[1]);\n\t\t\t\tBotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 3:\n\t\t\t{\n\t\t\t\t//the one closest to the base will defend the base\n\t\t\t\tClientName(teammates[0], name, sizeof(name));\n\t\t\t\tBotAI_BotInitialChat(bs, \"cmd_defendbase\", name, NULL);\n\t\t\t\tBotSayTeamOrder(bs, teammates[0]);\n\t\t\t\tBotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);\n\t\t\t\t//the others should go for the enemy flag\n\t\t\t\tClientName(teammates[1], name, sizeof(name));\n\t\t\t\tBotAI_BotInitialChat(bs, \"cmd_getflag\", name, NULL);\n\t\t\t\tBotSayTeamOrder(bs, teammates[1]);\n\t\t\t\tBotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);\n\t\t\t\t//\n\t\t\t\tClientName(teammates[2], name, sizeof(name));\n\t\t\t\tBotAI_BotInitialChat(bs, \"cmd_getflag\", name, NULL);\n\t\t\t\tBotSayTeamOrder(bs, teammates[2]);\n\t\t\t\tBotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault:\n\t\t\t{\n\t\t\t\tdefenders = (int) (float) numteammates * 0.4 + 0.5;\n\t\t\t\tif (defenders > 4) defenders = 4;\n\t\t\t\tattackers = (int) (float) numteammates * 0.5 + 0.5;\n\t\t\t\tif (attackers > 5) attackers = 5;\n\t\t\t\tfor (i = 0; i < defenders; i++) {\n\t\t\t\t\t//\n\t\t\t\t\tClientName(teammates[i], name, sizeof(name));\n\t\t\t\t\tBotAI_BotInitialChat(bs, \"cmd_defendbase\", name, NULL);\n\t\t\t\t\tBotSayTeamOrder(bs, teammates[i]);\n\t\t\t\t\tBotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);\n\t\t\t\t}\n\t\t\t\tfor (i = 0; i < attackers; i++) {\n\t\t\t\t\t//\n\t\t\t\t\tClientName(teammates[numteammates - i - 1], name, sizeof(name));\n\t\t\t\t\tBotAI_BotInitialChat(bs, \"cmd_getflag\", name, NULL);\n\t\t\t\t\tBotSayTeamOrder(bs, teammates[numteammates - i - 1]);\n\t\t\t\t\tBotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);\n\t\t\t\t}\n\t\t\t\t//\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n}\n\n/*\n==================\nBotCTFOrders\n==================\n*/\nvoid BotCTFOrders(bot_state_t *bs) {\n\tint flagstatus;\n\n\t//\n\tif (BotTeam(bs) == TEAM_RED) flagstatus = bs->redflagstatus * 2 + bs->blueflagstatus;\n\telse flagstatus = bs->blueflagstatus * 2 + bs->redflagstatus;\n\t//\n\tswitch(flagstatus) {\n\t\tcase 0: BotCTFOrders_BothFlagsAtBase(bs); break;\n\t\tcase 1: BotCTFOrders_EnemyFlagNotAtBase(bs); break;\n\t\tcase 2: BotCTFOrders_FlagNotAtBase(bs); break;\n\t\tcase 3: BotCTFOrders_BothFlagsNotAtBase(bs); break;\n\t}\n}\n\n\n/*\n==================\nBotCreateGroup\n==================\n*/\nvoid BotCreateGroup(bot_state_t *bs, int *teammates, int groupsize) {\n\tchar name[MAX_NETNAME], leadername[MAX_NETNAME];\n\tint i;\n\n\t// the others in the group will follow the teammates[0]\n\tClientName(teammates[0], leadername, sizeof(leadername));\n\tfor (i = 1; i < groupsize; i++)\n\t{\n\t\tClientName(teammates[i], name, sizeof(name));\n\t\tif (teammates[0] == bs->client) {\n\t\t\tBotAI_BotInitialChat(bs, \"cmd_accompanyme\", name, NULL);\n\t\t}\n\t\telse {\n\t\t\tBotAI_BotInitialChat(bs, \"cmd_accompany\", name, leadername, NULL);\n\t\t}\n\t\tBotSayTeamOrderAlways(bs, teammates[i]);\n\t}\n}\n\n/*\n==================\nBotTeamOrders\n\n  FIXME: defend key areas?\n==================\n*/\nvoid BotTeamOrders(bot_state_t *bs) {\n\tint teammates[MAX_CLIENTS];\n\tint numteammates, i;\n\tchar buf[MAX_INFO_STRING];\n\tstatic int maxclients;\n\n\tif (!maxclients)\n\t\tmaxclients = trap_Cvar_VariableIntegerValue(\"sv_maxclients\");\n\n\tnumteammates = 0;\n\tfor (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {\n\t\ttrap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));\n\t\t//if no config string or no name\n\t\tif (!strlen(buf) || !strlen(Info_ValueForKey(buf, \"n\"))) continue;\n\t\t//skip spectators\n\t\tif (atoi(Info_ValueForKey(buf, \"t\")) == TEAM_SPECTATOR) continue;\n\t\t//\n\t\tif (BotSameTeam(bs, i)) {\n\t\t\tteammates[numteammates] = i;\n\t\t\tnumteammates++;\n\t\t}\n\t}\n\t//\n\tswitch(numteammates) {\n\t\tcase 1: break;\n\t\tcase 2:\n\t\t{\n\t\t\t//nothing special\n\t\t\tbreak;\n\t\t}\n\t\tcase 3:\n\t\t{\n\t\t\t//have one follow another and one free roaming\n\t\t\tBotCreateGroup(bs, teammates, 2);\n\t\t\tbreak;\n\t\t}\n\t\tcase 4:\n\t\t{\n\t\t\tBotCreateGroup(bs, teammates, 2);\t\t//a group of 2\n\t\t\tBotCreateGroup(bs, &teammates[2], 2);\t//a group of 2\n\t\t\tbreak;\n\t\t}\n\t\tcase 5:\n\t\t{\n\t\t\tBotCreateGroup(bs, teammates, 2);\t\t//a group of 2\n\t\t\tBotCreateGroup(bs, &teammates[2], 3);\t//a group of 3\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t{\n\t\t\tif (numteammates <= 10) {\n\t\t\t\tfor (i = 0; i < numteammates / 2; i++) {\n\t\t\t\t\tBotCreateGroup(bs, &teammates[i*2], 2);\t//groups of 2\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\n/*\n==================\nFindHumanTeamLeader\n==================\n*/\nint FindHumanTeamLeader(bot_state_t *bs) {\n\tint i;\n\n\tfor (i = 0; i < MAX_CLIENTS; i++) {\n\t\tif ( g_entities[i].inuse ) {\n\t\t\t// if this player is not a bot\n\t\t\tif ( !(g_entities[i].r.svFlags & SVF_BOT) ) {\n\t\t\t\t// if this player is ok with being the leader\n\t\t\t\tif (!notleader[i]) {\n\t\t\t\t\t// if this player is on the same team\n\t\t\t\t\tif ( BotSameTeam(bs, i) ) {\n\t\t\t\t\t\tClientName(i, bs->teamleader, sizeof(bs->teamleader));\n\t\t\t\t\t\t// if not yet ordered to do anything\n\t\t\t\t\t\tif ( !BotSetLastOrderedTask(bs) ) {\n\t\t\t\t\t\t\t// go on defense by default\n\t\t\t\t\t\t\tBotVoiceChat_Defend(bs, i, SAY_TELL);\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn qtrue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn qfalse;\n}\n\n/*\n==================\nBotTeamAI\n==================\n*/\nvoid BotTeamAI(bot_state_t *bs) {\n\tint numteammates;\n\tchar netname[MAX_NETNAME];\n\n\t//\n\tif ( gametype < GT_TEAM  )\n\t\treturn;\n\t// make sure we've got a valid team leader\n\tif (!BotValidTeamLeader(bs)) {\n\t\t//\n\t\tif (!FindHumanTeamLeader(bs)) {\n\t\t\t//\n\t\t\tif (!bs->askteamleader_time && !bs->becometeamleader_time) {\n\t\t\t\tif (bs->entergame_time + 10 > FloatTime()) {\n\t\t\t\t\tbs->askteamleader_time = FloatTime() + 5 + random() * 10;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tbs->becometeamleader_time = FloatTime() + 5 + random() * 10;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (bs->askteamleader_time && bs->askteamleader_time < FloatTime()) {\n\t\t\t\t// if asked for a team leader and no response\n\t\t\t\tBotAI_BotInitialChat(bs, \"whoisteamleader\", NULL);\n\t\t\t\ttrap_BotEnterChat(bs->cs, 0, CHAT_TEAM);\n\t\t\t\tbs->askteamleader_time = 0;\n\t\t\t\tbs->becometeamleader_time = FloatTime() + 8 + random() * 10;\n\t\t\t}\n\t\t\tif (bs->becometeamleader_time && bs->becometeamleader_time < FloatTime()) {\n\t\t\t\tBotAI_BotInitialChat(bs, \"iamteamleader\", NULL);\n\t\t\t\ttrap_BotEnterChat(bs->cs, 0, CHAT_TEAM);\n\t\t\t\tBotSayVoiceTeamOrder(bs, -1, VOICECHAT_STARTLEADER);\n\t\t\t\tClientName(bs->client, netname, sizeof(netname));\n\t\t\t\tstrncpy(bs->teamleader, netname, sizeof(bs->teamleader));\n\t\t\t\tbs->teamleader[sizeof(bs->teamleader)] = '\\0';\n\t\t\t\tbs->becometeamleader_time = 0;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t}\n\tbs->askteamleader_time = 0;\n\tbs->becometeamleader_time = 0;\n\n\t//return if this bot is NOT the team leader\n\tClientName(bs->client, netname, sizeof(netname));\n\tif (Q_stricmp(netname, bs->teamleader) != 0) return;\n\t//\n\tnumteammates = BotNumTeamMates(bs);\n\t//give orders\n\tswitch(gametype) {\n\t\tcase GT_TEAM:\n\t\t{\n\t\t\tif (bs->numteammates != numteammates || bs->forceorders) {\n\t\t\t\tbs->teamgiveorders_time = FloatTime();\n\t\t\t\tbs->numteammates = numteammates;\n\t\t\t\tbs->forceorders = qfalse;\n\t\t\t}\n\t\t\t//if it's time to give orders\n\t\t\tif (bs->teamgiveorders_time && bs->teamgiveorders_time < FloatTime() - 5) {\n\t\t\t\tBotTeamOrders(bs);\n\t\t\t\t//give orders again after 120 seconds\n\t\t\t\tbs->teamgiveorders_time = FloatTime() + 120;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase GT_CTF:\n\t\t{\n\t\t\t//if the number of team mates changed or the flag status changed\n\t\t\t//or someone wants to know what to do\n\t\t\tif (bs->numteammates != numteammates || bs->flagstatuschanged || bs->forceorders) {\n\t\t\t\tbs->teamgiveorders_time = FloatTime();\n\t\t\t\tbs->numteammates = numteammates;\n\t\t\t\tbs->flagstatuschanged = qfalse;\n\t\t\t\tbs->forceorders = qfalse;\n\t\t\t}\n\t\t\t//if there were no flag captures the last 3 minutes\n\t\t\tif (bs->lastflagcapture_time < FloatTime() - 240) {\n\t\t\t\tbs->lastflagcapture_time = FloatTime();\n\t\t\t\t//randomly change the CTF strategy\n\t\t\t\tif (random() < 0.4) {\n\t\t\t\t\tbs->ctfstrategy ^= CTFS_AGRESSIVE;\n\t\t\t\t\tbs->teamgiveorders_time = FloatTime();\n\t\t\t\t}\n\t\t\t}\n\t\t\t//if it's time to give orders\n\t\t\tif (bs->teamgiveorders_time && bs->teamgiveorders_time < FloatTime() - 3) {\n\t\t\t\tBotCTFOrders(bs);\n\t\t\t\t//\n\t\t\t\tbs->teamgiveorders_time = 0;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/game/ai_team.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n\n/*****************************************************************************\n * name:\t\tai_team.h\n *\n * desc:\t\tQuake3 bot AI\n *\n * $Archive: /source/code/botai/ai_chat.c $\n *\n *****************************************************************************/\n\nvoid BotTeamAI(bot_state_t *bs);\nint BotGetTeamMateTaskPreference(bot_state_t *bs, int teammate);\nvoid BotSetTeamMateTaskPreference(bot_state_t *bs, int teammate, int preference);\nvoid BotVoiceChat(bot_state_t *bs, int toclient, char *voicechat);\nvoid BotVoiceChatOnly(bot_state_t *bs, int toclient, char *voicechat);\n\n\n"
  },
  {
    "path": "src/game/ai_vcmd.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n\n/*****************************************************************************\n * name:\t\tai_vcmd.c\n *\n * desc:\t\tQuake3 bot AI\n *\n * $Archive: /MissionPack/code/game/ai_vcmd.c $\n *\n *****************************************************************************/\n\n#include \"g_local.h\"\n#include \"botlib.h\"\n#include \"be_aas.h\"\n#include \"be_ea.h\"\n#include \"be_ai_char.h\"\n#include \"be_ai_chat.h\"\n#include \"be_ai_gen.h\"\n#include \"be_ai_goal.h\"\n#include \"be_ai_move.h\"\n#include \"be_ai_weap.h\"\n//\n#include \"ai_main.h\"\n#include \"ai_dmq3.h\"\n#include \"ai_chat.h\"\n#include \"ai_cmd.h\"\n#include \"ai_dmnet.h\"\n#include \"ai_team.h\"\n#include \"ai_vcmd.h\"\n//\n#include \"chars.h\"\t\t\t\t//characteristics\n#include \"inv.h\"\t\t\t\t//indexes into the inventory\n#include \"syn.h\"\t\t\t\t//synonyms\n#include \"match.h\"\t\t\t\t//string matching types and vars\n\n// for the voice chats\n#include \"menudef.h\"\n\n\ntypedef struct voiceCommand_s\n{\n\tchar *cmd;\n\tvoid (*func)(bot_state_t *bs, int client, int mode);\n} voiceCommand_t;\n\n/*\n==================\nBotVoiceChat_GetFlag\n==================\n*/\nvoid BotVoiceChat_GetFlag(bot_state_t *bs, int client, int mode) {\n\t//\n\tif (gametype == GT_CTF) {\n\t\tif (!ctf_redflag.areanum || !ctf_blueflag.areanum)\n\t\t\treturn;\n\t}\n\telse {\n\t\treturn;\n\t}\n\t//\n\tbs->decisionmaker = client;\n\tbs->ordered = qtrue;\n\tbs->order_time = FloatTime();\n\t//set the time to send a message to the team mates\n\tbs->teammessage_time = FloatTime() + 2 * random();\n\t//set the ltg type\n\tbs->ltgtype = LTG_GETFLAG;\n\t//set the team goal time\n\tbs->teamgoal_time = FloatTime() + CTF_GETFLAG_TIME;\n\t// get an alternate route in ctf\n\tif (gametype == GT_CTF) {\n\t\t//get an alternative route goal towards the enemy base\n\t\tBotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));\n\t}\n\t//\n\tBotSetTeamStatus(bs);\n\t// remember last ordered task\n\tBotRememberLastOrderedTask(bs);\n#ifdef DEBUG\n\tBotPrintTeamGoal(bs);\n#endif //DEBUG\n}\n\n/*\n==================\nBotVoiceChat_Offense\n==================\n*/\nvoid BotVoiceChat_Offense(bot_state_t *bs, int client, int mode) {\n\tif ( gametype == GT_CTF\n\t\t) {\n\t\tBotVoiceChat_GetFlag(bs, client, mode);\n\t\treturn;\n\t}\n\t{\n\t\t//\n\t\tbs->decisionmaker = client;\n\t\tbs->ordered = qtrue;\n\t\tbs->order_time = FloatTime();\n\t\t//set the time to send a message to the team mates\n\t\tbs->teammessage_time = FloatTime() + 2 * random();\n\t\t//set the ltg type\n\t\tbs->ltgtype = LTG_ATTACKENEMYBASE;\n\t\t//set the team goal time\n\t\tbs->teamgoal_time = FloatTime() + TEAM_ATTACKENEMYBASE_TIME;\n\t\tbs->attackaway_time = 0;\n\t\t//\n\t\tBotSetTeamStatus(bs);\n\t\t// remember last ordered task\n\t\tBotRememberLastOrderedTask(bs);\n\t}\n#ifdef DEBUG\n\tBotPrintTeamGoal(bs);\n#endif //DEBUG\n}\n\n/*\n==================\nBotVoiceChat_Defend\n==================\n*/\nvoid BotVoiceChat_Defend(bot_state_t *bs, int client, int mode) {\n\t\tif (gametype == GT_CTF\n\t\t\t) {\n\t\t//\n\t\tswitch(BotTeam(bs)) {\n\t\t\tcase TEAM_RED: memcpy(&bs->teamgoal, &ctf_redflag, sizeof(bot_goal_t)); break;\n\t\t\tcase TEAM_BLUE: memcpy(&bs->teamgoal, &ctf_blueflag, sizeof(bot_goal_t)); break;\n\t\t\tdefault: return;\n\t\t}\n\t}\n\telse {\n\t\treturn;\n\t}\n\t//\n\tbs->decisionmaker = client;\n\tbs->ordered = qtrue;\n\tbs->order_time = FloatTime();\n\t//set the time to send a message to the team mates\n\tbs->teammessage_time = FloatTime() + 2 * random();\n\t//set the ltg type\n\tbs->ltgtype = LTG_DEFENDKEYAREA;\n\t//get the team goal time\n\tbs->teamgoal_time = FloatTime() + TEAM_DEFENDKEYAREA_TIME;\n\t//away from defending\n\tbs->defendaway_time = 0;\n\t//\n\tBotSetTeamStatus(bs);\n\t// remember last ordered task\n\tBotRememberLastOrderedTask(bs);\n#ifdef DEBUG\n\tBotPrintTeamGoal(bs);\n#endif //DEBUG\n}\n\n/*\n==================\nBotVoiceChat_DefendFlag\n==================\n*/\nvoid BotVoiceChat_DefendFlag(bot_state_t *bs, int client, int mode) {\n\tBotVoiceChat_Defend(bs, client, mode);\n}\n\n/*\n==================\nBotVoiceChat_Patrol\n==================\n*/\nvoid BotVoiceChat_Patrol(bot_state_t *bs, int client, int mode) {\n\t//\n\tbs->decisionmaker = client;\n\t//\n\tbs->ltgtype = 0;\n\tbs->lead_time = 0;\n\tbs->lastgoal_ltgtype = 0;\n\t//\n\tBotAI_BotInitialChat(bs, \"dismissed\", NULL);\n\ttrap_BotEnterChat(bs->cs, client, CHAT_TELL);\n\tBotVoiceChatOnly(bs, -1, VOICECHAT_ONPATROL);\n\t//\n\tBotSetTeamStatus(bs);\n#ifdef DEBUG\n\tBotPrintTeamGoal(bs);\n#endif //DEBUG\n}\n\n/*\n==================\nBotVoiceChat_Camp\n==================\n*/\nvoid BotVoiceChat_Camp(bot_state_t *bs, int client, int mode) {\n\tint areanum;\n\taas_entityinfo_t entinfo;\n\tchar netname[MAX_NETNAME];\n\n\t//\n\tbs->teamgoal.entitynum = -1;\n\tBotEntityInfo(client, &entinfo);\n\t//if info is valid (in PVS)\n\tif (entinfo.valid) {\n\t\tareanum = BotPointAreaNum(entinfo.origin);\n\t\tif (areanum) { // && trap_AAS_AreaReachability(areanum)) {\n\t\t\t//NOTE: just assume the bot knows where the person is\n\t\t\t//if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, client)) {\n\t\t\t\tbs->teamgoal.entitynum = client;\n\t\t\t\tbs->teamgoal.areanum = areanum;\n\t\t\t\tVectorCopy(entinfo.origin, bs->teamgoal.origin);\n\t\t\t\tVectorSet(bs->teamgoal.mins, -8, -8, -8);\n\t\t\t\tVectorSet(bs->teamgoal.maxs, 8, 8, 8);\n\t\t\t//}\n\t\t}\n\t}\n\t//if the other is not visible\n\tif (bs->teamgoal.entitynum < 0) {\n\t\tBotAI_BotInitialChat(bs, \"whereareyou\", EasyClientName(client, netname, sizeof(netname)), NULL);\n\t\ttrap_BotEnterChat(bs->cs, client, CHAT_TELL);\n\t\treturn;\n\t}\n\t//\n\tbs->decisionmaker = client;\n\tbs->ordered = qtrue;\n\tbs->order_time = FloatTime();\n\t//set the time to send a message to the team mates\n\tbs->teammessage_time = FloatTime() + 2 * random();\n\t//set the ltg type\n\tbs->ltgtype = LTG_CAMPORDER;\n\t//get the team goal time\n\tbs->teamgoal_time = FloatTime() + TEAM_CAMP_TIME;\n\t//the teammate that requested the camping\n\tbs->teammate = client;\n\t//not arrived yet\n\tbs->arrive_time = 0;\n\t//\n\tBotSetTeamStatus(bs);\n\t// remember last ordered task\n\tBotRememberLastOrderedTask(bs);\n#ifdef DEBUG\n\tBotPrintTeamGoal(bs);\n#endif //DEBUG\n}\n\n/*\n==================\nBotVoiceChat_FollowMe\n==================\n*/\nvoid BotVoiceChat_FollowMe(bot_state_t *bs, int client, int mode) {\n\tint areanum;\n\taas_entityinfo_t entinfo;\n\tchar netname[MAX_NETNAME];\n\n\tbs->teamgoal.entitynum = -1;\n\tBotEntityInfo(client, &entinfo);\n\t//if info is valid (in PVS)\n\tif (entinfo.valid) {\n\t\tareanum = BotPointAreaNum(entinfo.origin);\n\t\tif (areanum) { // && trap_AAS_AreaReachability(areanum)) {\n\t\t\tbs->teamgoal.entitynum = client;\n\t\t\tbs->teamgoal.areanum = areanum;\n\t\t\tVectorCopy(entinfo.origin, bs->teamgoal.origin);\n\t\t\tVectorSet(bs->teamgoal.mins, -8, -8, -8);\n\t\t\tVectorSet(bs->teamgoal.maxs, 8, 8, 8);\n\t\t}\n\t}\n\t//if the other is not visible\n\tif (bs->teamgoal.entitynum < 0) {\n\t\tBotAI_BotInitialChat(bs, \"whereareyou\", EasyClientName(client, netname, sizeof(netname)), NULL);\n\t\ttrap_BotEnterChat(bs->cs, client, CHAT_TELL);\n\t\treturn;\n\t}\n\t//\n\tbs->decisionmaker = client;\n\tbs->ordered = qtrue;\n\tbs->order_time = FloatTime();\n\t//the team mate\n\tbs->teammate = client;\n\t//last time the team mate was assumed visible\n\tbs->teammatevisible_time = FloatTime();\n\t//set the time to send a message to the team mates\n\tbs->teammessage_time = FloatTime() + 2 * random();\n\t//get the team goal time\n\tbs->teamgoal_time = FloatTime() + TEAM_ACCOMPANY_TIME;\n\t//set the ltg type\n\tbs->ltgtype = LTG_TEAMACCOMPANY;\n\tbs->formation_dist = 3.5 * 32;\t\t//3.5 meter\n\tbs->arrive_time = 0;\n\t//\n\tBotSetTeamStatus(bs);\n\t// remember last ordered task\n\tBotRememberLastOrderedTask(bs);\n#ifdef DEBUG\n\tBotPrintTeamGoal(bs);\n#endif //DEBUG\n}\n\n/*\n==================\nBotVoiceChat_FollowFlagCarrier\n==================\n*/\nvoid BotVoiceChat_FollowFlagCarrier(bot_state_t *bs, int client, int mode) {\n\tint carrier;\n\n\tcarrier = BotTeamFlagCarrier(bs);\n\tif (carrier >= 0)\n\t\tBotVoiceChat_FollowMe(bs, carrier, mode);\n#ifdef DEBUG\n\tBotPrintTeamGoal(bs);\n#endif //DEBUG\n}\n\n/*\n==================\nBotVoiceChat_ReturnFlag\n==================\n*/\nvoid BotVoiceChat_ReturnFlag(bot_state_t *bs, int client, int mode) {\n\t//if not in CTF mode\n\tif (\n\t\tgametype != GT_CTF\n\t\t) {\n\t\treturn;\n\t}\n\t//\n\tbs->decisionmaker = client;\n\tbs->ordered = qtrue;\n\tbs->order_time = FloatTime();\n\t//set the time to send a message to the team mates\n\tbs->teammessage_time = FloatTime() + 2 * random();\n\t//set the ltg type\n\tbs->ltgtype = LTG_RETURNFLAG;\n\t//set the team goal time\n\tbs->teamgoal_time = FloatTime() + CTF_RETURNFLAG_TIME;\n\tbs->rushbaseaway_time = 0;\n\tBotSetTeamStatus(bs);\n#ifdef DEBUG\n\tBotPrintTeamGoal(bs);\n#endif //DEBUG\n}\n\n/*\n==================\nBotVoiceChat_StartLeader\n==================\n*/\nvoid BotVoiceChat_StartLeader(bot_state_t *bs, int client, int mode) {\n\tClientName(client, bs->teamleader, sizeof(bs->teamleader));\n}\n\n/*\n==================\nBotVoiceChat_StopLeader\n==================\n*/\nvoid BotVoiceChat_StopLeader(bot_state_t *bs, int client, int mode) {\n\tchar netname[MAX_MESSAGE_SIZE];\n\n\tif (!Q_stricmp(bs->teamleader, ClientName(client, netname, sizeof(netname)))) {\n\t\tbs->teamleader[0] = '\\0';\n\t\tnotleader[client] = qtrue;\n\t}\n}\n\n/*\n==================\nBotVoiceChat_WhoIsLeader\n==================\n*/\nvoid BotVoiceChat_WhoIsLeader(bot_state_t *bs, int client, int mode) {\n\tchar netname[MAX_MESSAGE_SIZE];\n\n\tif (!TeamPlayIsOn()) return;\n\n\tClientName(bs->client, netname, sizeof(netname));\n\t//if this bot IS the team leader\n\tif (!Q_stricmp(netname, bs->teamleader)) {\n\t\tBotAI_BotInitialChat(bs, \"iamteamleader\", NULL);\n\t\ttrap_BotEnterChat(bs->cs, 0, CHAT_TEAM);\n\t\tBotVoiceChatOnly(bs, -1, VOICECHAT_STARTLEADER);\n\t}\n}\n\n/*\n==================\nBotVoiceChat_WantOnDefense\n==================\n*/\nvoid BotVoiceChat_WantOnDefense(bot_state_t *bs, int client, int mode) {\n\tchar netname[MAX_NETNAME];\n\tint preference;\n\n\tpreference = BotGetTeamMateTaskPreference(bs, client);\n\tpreference &= ~TEAMTP_ATTACKER;\n\tpreference |= TEAMTP_DEFENDER;\n\tBotSetTeamMateTaskPreference(bs, client, preference);\n\t//\n\tEasyClientName(client, netname, sizeof(netname));\n\tBotAI_BotInitialChat(bs, \"keepinmind\", netname, NULL);\n\ttrap_BotEnterChat(bs->cs, client, CHAT_TELL);\n\tBotVoiceChatOnly(bs, client, VOICECHAT_YES);\n\ttrap_EA_Action(bs->client, ACTION_AFFIRMATIVE);\n}\n\n/*\n==================\nBotVoiceChat_WantOnOffense\n==================\n*/\nvoid BotVoiceChat_WantOnOffense(bot_state_t *bs, int client, int mode) {\n\tchar netname[MAX_NETNAME];\n\tint preference;\n\n\tpreference = BotGetTeamMateTaskPreference(bs, client);\n\tpreference &= ~TEAMTP_DEFENDER;\n\tpreference |= TEAMTP_ATTACKER;\n\tBotSetTeamMateTaskPreference(bs, client, preference);\n\t//\n\tEasyClientName(client, netname, sizeof(netname));\n\tBotAI_BotInitialChat(bs, \"keepinmind\", netname, NULL);\n\ttrap_BotEnterChat(bs->cs, client, CHAT_TELL);\n\tBotVoiceChatOnly(bs, client, VOICECHAT_YES);\n\ttrap_EA_Action(bs->client, ACTION_AFFIRMATIVE);\n}\n\nvoid BotVoiceChat_Dummy(bot_state_t *bs, int client, int mode) {\n}\n\nvoiceCommand_t voiceCommands[] = {\n\t{VOICECHAT_GETFLAG, BotVoiceChat_GetFlag},\n\t{VOICECHAT_OFFENSE, BotVoiceChat_Offense },\n\t{VOICECHAT_DEFEND, BotVoiceChat_Defend },\n\t{VOICECHAT_DEFENDFLAG, BotVoiceChat_DefendFlag },\n\t{VOICECHAT_PATROL, BotVoiceChat_Patrol },\n\t{VOICECHAT_CAMP, BotVoiceChat_Camp },\n\t{VOICECHAT_FOLLOWME, BotVoiceChat_FollowMe },\n\t{VOICECHAT_FOLLOWFLAGCARRIER, BotVoiceChat_FollowFlagCarrier },\n\t{VOICECHAT_RETURNFLAG, BotVoiceChat_ReturnFlag },\n\t{VOICECHAT_STARTLEADER, BotVoiceChat_StartLeader },\n\t{VOICECHAT_STOPLEADER, BotVoiceChat_StopLeader },\n\t{VOICECHAT_WHOISLEADER, BotVoiceChat_WhoIsLeader },\n\t{VOICECHAT_WANTONDEFENSE, BotVoiceChat_WantOnDefense },\n\t{VOICECHAT_WANTONOFFENSE, BotVoiceChat_WantOnOffense },\n\t{NULL, BotVoiceChat_Dummy}\n};\n\nint BotVoiceChatCommand(bot_state_t *bs, int mode, char *voiceChat) {\n\tint i, voiceOnly, clientNum, color;\n\tchar *ptr, buf[MAX_MESSAGE_SIZE], *cmd;\n\n\tif (!TeamPlayIsOn()) {\n\t\treturn qfalse;\n\t}\n\n\tif ( mode == SAY_ALL ) {\n\t\treturn qfalse;\t// don't do anything with voice chats to everyone\n\t}\n\n\tQ_strncpyz(buf, voiceChat, sizeof(buf));\n\tcmd = buf;\n\tfor (ptr = cmd; *cmd && *cmd > ' '; cmd++);\n\twhile (*cmd && *cmd <= ' ') *cmd++ = '\\0';\n\tvoiceOnly = atoi(ptr);\n\tfor (ptr = cmd; *cmd && *cmd > ' '; cmd++);\n\twhile (*cmd && *cmd <= ' ') *cmd++ = '\\0';\n\tclientNum = atoi(ptr);\n\tfor (ptr = cmd; *cmd && *cmd > ' '; cmd++);\n\twhile (*cmd && *cmd <= ' ') *cmd++ = '\\0';\n\tcolor = atoi(ptr);\n\n\tif (!BotSameTeam(bs, clientNum)) {\n\t\treturn qfalse;\n\t}\n\n\tfor (i = 0; voiceCommands[i].cmd; i++) {\n\t\tif (!Q_stricmp(cmd, voiceCommands[i].cmd)) {\n\t\t\tvoiceCommands[i].func(bs, clientNum, mode);\n\t\t\treturn qtrue;\n\t\t}\n\t}\n\treturn qfalse;\n}\n"
  },
  {
    "path": "src/game/ai_vcmd.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n\n/*****************************************************************************\n * name:\t\tai_vcmd.h\n *\n * desc:\t\tQuake3 bot AI\n *\n * $Archive: /source/code/botai/ai_vcmd.c $\n *\n *****************************************************************************/\n\nint BotVoiceChatCommand(bot_state_t *bs, int mode, char *voicechat);\nvoid BotVoiceChat_Defend(bot_state_t *bs, int client, int mode);\n\n\n"
  },
  {
    "path": "src/game/be_aas.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n\n/*****************************************************************************\n * name:\t\tbe_aas.h\n *\n * desc:\t\tArea Awareness System, stuff exported to the AI\n *\n * $Archive: /source/code/botlib/be_aas.h $\n *\n *****************************************************************************/\n\n#ifndef MAX_STRINGFIELD\n#define MAX_STRINGFIELD\t\t\t\t80\n#endif\n\n//travel flags\n#define TFL_INVALID\t\t\t\t0x00000001\t//traveling temporary not possible\n#define TFL_WALK\t\t\t\t0x00000002\t//walking\n#define TFL_CROUCH\t\t\t\t0x00000004\t//crouching\n#define TFL_BARRIERJUMP\t\t\t0x00000008\t//jumping onto a barrier\n#define TFL_JUMP\t\t\t\t0x00000010\t//jumping\n#define TFL_LADDER\t\t\t\t0x00000020\t//climbing a ladder\n#define TFL_WALKOFFLEDGE\t\t0x00000080\t//walking of a ledge\n#define TFL_SWIM\t\t\t\t0x00000100\t//swimming\n#define TFL_WATERJUMP\t\t\t0x00000200\t//jumping out of the water\n#define TFL_TELEPORT\t\t\t0x00000400\t//teleporting\n#define TFL_ELEVATOR\t\t\t0x00000800\t//elevator\n#define TFL_ROCKETJUMP\t\t\t0x00001000\t//rocket jumping\n#define TFL_BFGJUMP\t\t\t\t0x00002000\t//bfg jumping\n#define TFL_GRAPPLEHOOK\t\t\t0x00004000\t//grappling hook\n#define TFL_DOUBLEJUMP\t\t\t0x00008000\t//double jump\n#define TFL_RAMPJUMP\t\t\t0x00010000\t//ramp jump\n#define TFL_STRAFEJUMP\t\t\t0x00020000\t//strafe jump\n#define TFL_JUMPPAD\t\t\t\t0x00040000\t//jump pad\n#define TFL_AIR\t\t\t\t\t0x00080000\t//travel through air\n#define TFL_WATER\t\t\t\t0x00100000\t//travel through water\n#define TFL_SLIME\t\t\t\t0x00200000\t//travel through slime\n#define TFL_LAVA\t\t\t\t0x00400000\t//travel through lava\n#define TFL_DONOTENTER\t\t\t0x00800000\t//travel through donotenter area\n#define TFL_FUNCBOB\t\t\t\t0x01000000\t//func bobbing\n#define TFL_FLIGHT\t\t\t\t0x02000000\t//flight\n#define TFL_BRIDGE\t\t\t\t0x04000000\t//move over a bridge\n//\n#define TFL_NOTTEAM1\t\t\t0x08000000\t//not team 1\n#define TFL_NOTTEAM2\t\t\t0x10000000\t//not team 2\n\n//default travel flags\n#define TFL_DEFAULT\tTFL_WALK|TFL_CROUCH|TFL_BARRIERJUMP|\\\n\tTFL_JUMP|TFL_LADDER|\\\n\tTFL_WALKOFFLEDGE|TFL_SWIM|TFL_WATERJUMP|\\\n\tTFL_TELEPORT|TFL_ELEVATOR|\\\n\tTFL_AIR|TFL_WATER|TFL_JUMPPAD|TFL_FUNCBOB\n\ntypedef enum\n{\n\tSOLID_NOT,\t\t\t// no interaction with other objects\n\tSOLID_TRIGGER,\t\t// only touch when inside, after moving\n\tSOLID_BBOX,\t\t\t// touch on edge\n\tSOLID_BSP\t\t\t// bsp clip, touch on edge\n} solid_t;\n\n//a trace is returned when a box is swept through the AAS world\ntypedef struct aas_trace_s\n{\n\tqboolean\tstartsolid;\t// if true, the initial point was in a solid area\n\tfloat\t\tfraction;\t// time completed, 1.0 = didn't hit anything\n\tvec3_t\t\tendpos;\t\t// final position\n\tint\t\t\tent;\t\t// entity blocking the trace\n\tint\t\t\tlastarea;\t// last area the trace was in (zero if none)\n\tint\t\t\tarea;\t\t// area blocking the trace (zero if none)\n\tint\t\t\tplanenum;\t// number of the plane that was hit\n} aas_trace_t;\n\n/* Defined in botlib.h\n\n//bsp_trace_t hit surface\ntypedef struct bsp_surface_s\n{\n\tchar name[16];\n\tint flags;\n\tint value;\n} bsp_surface_t;\n\n//a trace is returned when a box is swept through the BSP world\ntypedef struct bsp_trace_s\n{\n\tqboolean\t\tallsolid;\t// if true, plane is not valid\n\tqboolean\t\tstartsolid;\t// if true, the initial point was in a solid area\n\tfloat\t\t\tfraction;\t// time completed, 1.0 = didn't hit anything\n\tvec3_t\t\t\tendpos;\t\t// final position\n\tcplane_t\t\tplane;\t\t// surface normal at impact\n\tfloat\t\t\texp_dist;\t// expanded plane distance\n\tint\t\t\t\tsidenum;\t// number of the brush side hit\n\tbsp_surface_t\tsurface;\t// hit surface\n\tint\t\t\t\tcontents;\t// contents on other side of surface hit\n\tint\t\t\t\tent;\t\t// number of entity hit\n} bsp_trace_t;\n//\n*/\n\n//entity info\ntypedef struct aas_entityinfo_s\n{\n\tint\t\tvalid;\t\t\t// true if updated this frame\n\tint\t\ttype;\t\t\t// entity type\n\tint\t\tflags;\t\t\t// entity flags\n\tfloat\tltime;\t\t\t// local time\n\tfloat\tupdate_time;\t// time between last and current update\n\tint\t\tnumber;\t\t\t// number of the entity\n\tvec3_t\torigin;\t\t\t// origin of the entity\n\tvec3_t\tangles;\t\t\t// angles of the model\n\tvec3_t\told_origin;\t\t// for lerping\n\tvec3_t\tlastvisorigin;\t// last visible origin\n\tvec3_t\tmins;\t\t\t// bounding box minimums\n\tvec3_t\tmaxs;\t\t\t// bounding box maximums\n\tint\t\tgroundent;\t\t// ground entity\n\tint\t\tsolid;\t\t\t// solid type\n\tint\t\tmodelindex;\t\t// model used\n\tint\t\tmodelindex2;\t// weapons, CTF flags, etc\n\tint\t\tframe;\t\t\t// model frame number\n\tint\t\tevent;\t\t\t// impulse events -- muzzle flashes, footsteps, etc\n\tint\t\teventParm;\t\t// even parameter\n\tint\t\tpowerups;\t\t// bit flags\n\tint\t\tweapon;\t\t\t// determines weapon and flash model, etc\n\tint\t\tlegsAnim;\t\t// mask off ANIM_TOGGLEBIT\n\tint\t\ttorsoAnim;\t\t// mask off ANIM_TOGGLEBIT\n} aas_entityinfo_t;\n\n// area info\ntypedef struct aas_areainfo_s\n{\n\tint contents;\n\tint flags;\n\tint presencetype;\n\tint cluster;\n\tvec3_t mins;\n\tvec3_t maxs;\n\tvec3_t center;\n} aas_areainfo_t;\n\n// client movement prediction stop events, stop as soon as:\n#define SE_NONE\t\t\t\t\t0\n#define SE_HITGROUND\t\t\t1\t\t// the ground is hit\n#define SE_LEAVEGROUND\t\t\t2\t\t// there's no ground\n#define SE_ENTERWATER\t\t\t4\t\t// water is entered\n#define SE_ENTERSLIME\t\t\t8\t\t// slime is entered\n#define SE_ENTERLAVA\t\t\t16\t\t// lava is entered\n#define SE_HITGROUNDDAMAGE\t\t32\t\t// the ground is hit with damage\n#define SE_GAP\t\t\t\t\t64\t\t// there's a gap\n#define SE_TOUCHJUMPPAD\t\t\t128\t\t// touching a jump pad area\n#define SE_TOUCHTELEPORTER\t\t256\t\t// touching teleporter\n#define SE_ENTERAREA\t\t\t512\t\t// the given stoparea is entered\n#define SE_HITGROUNDAREA\t\t1024\t// a ground face in the area is hit\n#define SE_HITBOUNDINGBOX\t\t2048\t// hit the specified bounding box\n#define SE_TOUCHCLUSTERPORTAL\t4096\t// touching a cluster portal\n\ntypedef struct aas_clientmove_s\n{\n\tvec3_t endpos;\t\t\t//position at the end of movement prediction\n\tint endarea;\t\t\t//area at end of movement prediction\n\tvec3_t velocity;\t\t//velocity at the end of movement prediction\n\taas_trace_t trace;\t\t//last trace\n\tint presencetype;\t\t//presence type at end of movement prediction\n\tint stopevent;\t\t\t//event that made the prediction stop\n\tint endcontents;\t\t//contents at the end of movement prediction\n\tfloat time;\t\t\t\t//time predicted ahead\n\tint frames;\t\t\t\t//number of frames predicted ahead\n} aas_clientmove_t;\n\n// alternate route goals\n#define ALTROUTEGOAL_ALL\t\t\t\t1\n#define ALTROUTEGOAL_CLUSTERPORTALS\t\t2\n#define ALTROUTEGOAL_VIEWPORTALS\t\t4\n\ntypedef struct aas_altroutegoal_s\n{\n\tvec3_t origin;\n\tint areanum;\n\tunsigned short starttraveltime;\n\tunsigned short goaltraveltime;\n\tunsigned short extratraveltime;\n} aas_altroutegoal_t;\n\n// route prediction stop events\n#define RSE_NONE\t\t\t\t0\n#define RSE_NOROUTE\t\t\t\t1\t//no route to goal\n#define RSE_USETRAVELTYPE\t\t2\t//stop as soon as on of the given travel types is used\n#define RSE_ENTERCONTENTS\t\t4\t//stop when entering the given contents\n#define RSE_ENTERAREA\t\t\t8\t//stop when entering the given area\n\ntypedef struct aas_predictroute_s\n{\n\tvec3_t endpos;\t\t\t//position at the end of movement prediction\n\tint endarea;\t\t\t//area at end of movement prediction\n\tint stopevent;\t\t\t//event that made the prediction stop\n\tint endcontents;\t\t//contents at the end of movement prediction\n\tint endtravelflags;\t\t//end travel flags\n\tint numareas;\t\t\t//number of areas predicted ahead\n\tint time;\t\t\t\t//time predicted ahead (in hundreth of a sec)\n} aas_predictroute_t;\n"
  },
  {
    "path": "src/game/be_ai_char.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n\n/*****************************************************************************\n * name:\t\tbe_ai_char.h\n *\n * desc:\t\tbot characters\n *\n * $Archive: /source/code/botlib/be_ai_char.h $\n *\n *****************************************************************************/\n\n//loads a bot character from a file\nint BotLoadCharacter(char *charfile, float skill);\n//frees a bot character\nvoid BotFreeCharacter(int character);\n//returns a float characteristic\nfloat Characteristic_Float(int character, int index);\n//returns a bounded float characteristic\nfloat Characteristic_BFloat(int character, int index, float min, float max);\n//returns an integer characteristic\nint Characteristic_Integer(int character, int index);\n//returns a bounded integer characteristic\nint Characteristic_BInteger(int character, int index, int min, int max);\n//returns a string characteristic\nvoid Characteristic_String(int character, int index, char *buf, int size);\n//free cached bot characters\nvoid BotShutdownCharacters(void);\n"
  },
  {
    "path": "src/game/be_ai_chat.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n/*****************************************************************************\n * name:\t\tbe_ai_chat.h\n *\n * desc:\t\tchar AI\n *\n * $Archive: /source/code/botlib/be_ai_chat.h $\n *\n *****************************************************************************/\n\n#define MAX_MESSAGE_SIZE\t\t256\n#define MAX_CHATTYPE_NAME\t\t32\n#define MAX_MATCHVARIABLES\t\t8\n\n#define CHAT_GENDERLESS\t\t\t0\n#define CHAT_GENDERFEMALE\t\t1\n#define CHAT_GENDERMALE\t\t\t2\n\n#define CHAT_ALL\t\t\t\t\t0\n#define CHAT_TEAM\t\t\t\t\t1\n#define CHAT_TELL\t\t\t\t\t2\n\n//a console message\ntypedef struct bot_consolemessage_s\n{\n\tint handle;\n\tfloat time;\t\t\t\t\t\t\t\t\t//message time\n\tint type;\t\t\t\t\t\t\t\t\t//message type\n\tchar message[MAX_MESSAGE_SIZE];\t\t\t\t//message\n\tstruct bot_consolemessage_s *prev, *next;\t//prev and next in list\n} bot_consolemessage_t;\n\n//match variable\ntypedef struct bot_matchvariable_s\n{\n\tchar offset;\n\tint length;\n} bot_matchvariable_t;\n//returned to AI when a match is found\ntypedef struct bot_match_s\n{\n\tchar string[MAX_MESSAGE_SIZE];\n\tint type;\n\tint subtype;\n\tbot_matchvariable_t variables[MAX_MATCHVARIABLES];\n} bot_match_t;\n\n//setup the chat AI\nint BotSetupChatAI(void);\n//shutdown the chat AI\nvoid BotShutdownChatAI(void);\n//returns the handle to a newly allocated chat state\nint BotAllocChatState(void);\n//frees the chatstate\nvoid BotFreeChatState(int handle);\n//adds a console message to the chat state\nvoid BotQueueConsoleMessage(int chatstate, int type, char *message);\n//removes the console message from the chat state\nvoid BotRemoveConsoleMessage(int chatstate, int handle);\n//returns the next console message from the state\nint BotNextConsoleMessage(int chatstate, bot_consolemessage_t *cm);\n//returns the number of console messages currently stored in the state\nint BotNumConsoleMessages(int chatstate);\n//selects a chat message of the given type\nvoid BotInitialChat(int chatstate, char *type, int mcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7);\n//returns the number of initial chat messages of the given type\nint BotNumInitialChats(int chatstate, char *type);\n//find and select a reply for the given message\nint BotReplyChat(int chatstate, char *message, int mcontext, int vcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7);\n//returns the length of the currently selected chat message\nint BotChatLength(int chatstate);\n//enters the selected chat message\nvoid BotEnterChat(int chatstate, int clientto, int sendto);\n//get the chat message ready to be output\nvoid BotGetChatMessage(int chatstate, char *buf, int size);\n//checks if the first string contains the second one, returns index into first string or -1 if not found\nint StringContains(char *str1, char *str2, int casesensitive);\n//finds a match for the given string using the match templates\nint BotFindMatch(char *str, bot_match_t *match, unsigned long int context);\n//returns a variable from a match\nvoid BotMatchVariable(bot_match_t *match, int variable, char *buf, int size);\n//unify all the white spaces in the string\nvoid UnifyWhiteSpaces(char *string);\n//replace all the context related synonyms in the string\nvoid BotReplaceSynonyms(char *string, unsigned long int context);\n//loads a chat file for the chat state\nint BotLoadChatFile(int chatstate, char *chatfile, char *chatname);\n//store the gender of the bot in the chat state\nvoid BotSetChatGender(int chatstate, int gender);\n//store the bot name in the chat state\nvoid BotSetChatName(int chatstate, char *name, int client);\n\n"
  },
  {
    "path": "src/game/be_ai_gen.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n\n/*****************************************************************************\n * name:\t\tbe_ai_gen.h\n *\n * desc:\t\tgenetic selection\n *\n * $Archive: /source/code/botlib/be_ai_gen.h $\n *\n *****************************************************************************/\n\nint GeneticParentsAndChildSelection(int numranks, float *ranks, int *parent1, int *parent2, int *child);\n"
  },
  {
    "path": "src/game/be_ai_goal.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n/*****************************************************************************\n * name:\t\tbe_ai_goal.h\n *\n * desc:\t\tgoal AI\n *\n * $Archive: /source/code/botlib/be_ai_goal.h $\n *\n *****************************************************************************/\n\n#define MAX_AVOIDGOALS\t\t\t256\n#define MAX_GOALSTACK\t\t\t8\n\n#define GFL_NONE\t\t\t\t0\n#define GFL_ITEM\t\t\t\t1\n#define GFL_ROAM\t\t\t\t2\n#define GFL_DROPPED\t\t\t\t4\n\n//a bot goal\ntypedef struct bot_goal_s\n{\n\tvec3_t origin;\t\t\t\t//origin of the goal\n\tint areanum;\t\t\t\t//area number of the goal\n\tvec3_t mins, maxs;\t\t\t//mins and maxs of the goal\n\tint entitynum;\t\t\t\t//number of the goal entity\n\tint number;\t\t\t\t\t//goal number\n\tint flags;\t\t\t\t\t//goal flags\n\tint iteminfo;\t\t\t\t//item information\n} bot_goal_t;\n\n//reset the whole goal state, but keep the item weights\nvoid BotResetGoalState(int goalstate);\n//reset avoid goals\nvoid BotResetAvoidGoals(int goalstate);\n//remove the goal with the given number from the avoid goals\nvoid BotRemoveFromAvoidGoals(int goalstate, int number);\n//push a goal onto the goal stack\nvoid BotPushGoal(int goalstate, bot_goal_t *goal);\n//pop a goal from the goal stack\nvoid BotPopGoal(int goalstate);\n//empty the bot's goal stack\nvoid BotEmptyGoalStack(int goalstate);\n//dump the avoid goals\nvoid BotDumpAvoidGoals(int goalstate);\n//dump the goal stack\nvoid BotDumpGoalStack(int goalstate);\n//get the name name of the goal with the given number\nvoid BotGoalName(int number, char *name, int size);\n//get the top goal from the stack\nint BotGetTopGoal(int goalstate, bot_goal_t *goal);\n//get the second goal on the stack\nint BotGetSecondGoal(int goalstate, bot_goal_t *goal);\n//choose the best long term goal item for the bot\nint BotChooseLTGItem(int goalstate, vec3_t origin, int *inventory, int travelflags);\n//choose the best nearby goal item for the bot\n//the item may not be further away from the current bot position than maxtime\n//also the travel time from the nearby goal towards the long term goal may not\n//be larger than the travel time towards the long term goal from the current bot position\nint BotChooseNBGItem(int goalstate, vec3_t origin, int *inventory, int travelflags,\n\t\t\t\t\t\t\tbot_goal_t *ltg, float maxtime);\n//returns true if the bot touches the goal\nint BotTouchingGoal(vec3_t origin, bot_goal_t *goal);\n//returns true if the goal should be visible but isn't\nint BotItemGoalInVisButNotVisible(int viewer, vec3_t eye, vec3_t viewangles, bot_goal_t *goal);\n//search for a goal for the given classname, the index can be used\n//as a start point for the search when multiple goals are available with that same classname\nint BotGetLevelItemGoal(int index, char *classname, bot_goal_t *goal);\n//get the next camp spot in the map\nint BotGetNextCampSpotGoal(int num, bot_goal_t *goal);\n//get the map location with the given name\nint BotGetMapLocationGoal(char *name, bot_goal_t *goal);\n//returns the avoid goal time\nfloat BotAvoidGoalTime(int goalstate, int number);\n//set the avoid goal time\nvoid BotSetAvoidGoalTime(int goalstate, int number, float avoidtime);\n//initializes the items in the level\nvoid BotInitLevelItems(void);\n//regularly update dynamic entity items (dropped weapons, flags etc.)\nvoid BotUpdateEntityItems(void);\n//interbreed the goal fuzzy logic\nvoid BotInterbreedGoalFuzzyLogic(int parent1, int parent2, int child);\n//save the goal fuzzy logic to disk\nvoid BotSaveGoalFuzzyLogic(int goalstate, char *filename);\n//mutate the goal fuzzy logic\nvoid BotMutateGoalFuzzyLogic(int goalstate, float range);\n//loads item weights for the bot\nint BotLoadItemWeights(int goalstate, char *filename);\n//frees the item weights of the bot\nvoid BotFreeItemWeights(int goalstate);\n//returns the handle of a newly allocated goal state\nint BotAllocGoalState(int client);\n//free the given goal state\nvoid BotFreeGoalState(int handle);\n//setup the goal AI\nint BotSetupGoalAI(void);\n//shut down the goal AI\nvoid BotShutdownGoalAI(void);\n"
  },
  {
    "path": "src/game/be_ai_move.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n\n/*****************************************************************************\n * name:\t\tbe_ai_move.h\n *\n * desc:\t\tmovement AI\n *\n * $Archive: /source/code/botlib/be_ai_move.h $\n *\n *****************************************************************************/\n\n//movement types\n#define MOVE_WALK\t\t\t\t\t\t1\n#define MOVE_CROUCH\t\t\t\t\t\t2\n#define MOVE_JUMP\t\t\t\t\t\t4\n#define MOVE_GRAPPLE\t\t\t\t\t8\n#define MOVE_ROCKETJUMP\t\t\t\t\t16\n#define MOVE_BFGJUMP\t\t\t\t\t32\n//move flags\n#define MFL_BARRIERJUMP\t\t\t\t\t1\t\t//bot is performing a barrier jump\n#define MFL_ONGROUND\t\t\t\t\t2\t\t//bot is in the ground\n#define MFL_SWIMMING\t\t\t\t\t4\t\t//bot is swimming\n#define MFL_AGAINSTLADDER\t\t\t\t8\t\t//bot is against a ladder\n#define MFL_WATERJUMP\t\t\t\t\t16\t\t//bot is waterjumping\n#define MFL_TELEPORTED\t\t\t\t\t32\t\t//bot is being teleported\n#define MFL_GRAPPLEPULL\t\t\t\t\t64\t\t//bot is being pulled by the grapple\n#define MFL_ACTIVEGRAPPLE\t\t\t\t128\t\t//bot is using the grapple hook\n#define MFL_GRAPPLERESET\t\t\t\t256\t\t//bot has reset the grapple\n#define MFL_WALK\t\t\t\t\t\t512\t\t//bot should walk slowly\n// move result flags\n#define MOVERESULT_MOVEMENTVIEW\t\t\t1\t\t//bot uses view for movement\n#define MOVERESULT_SWIMVIEW\t\t\t\t2\t\t//bot uses view for swimming\n#define MOVERESULT_WAITING\t\t\t\t4\t\t//bot is waiting for something\n#define MOVERESULT_MOVEMENTVIEWSET\t\t8\t\t//bot has set the view in movement code\n#define MOVERESULT_MOVEMENTWEAPON\t\t16\t\t//bot uses weapon for movement\n#define MOVERESULT_ONTOPOFOBSTACLE\t\t32\t\t//bot is ontop of obstacle\n#define MOVERESULT_ONTOPOF_FUNCBOB\t\t64\t\t//bot is ontop of a func_bobbing\n#define MOVERESULT_ONTOPOF_ELEVATOR\t\t128\t\t//bot is ontop of an elevator (func_plat)\n#define MOVERESULT_BLOCKEDBYAVOIDSPOT\t256\t\t//bot is blocked by an avoid spot\n//\n#define MAX_AVOIDREACH\t\t\t\t\t1\n#define MAX_AVOIDSPOTS\t\t\t\t\t32\n// avoid spot types\n#define AVOID_CLEAR\t\t\t\t\t\t0\t\t//clear all avoid spots\n#define AVOID_ALWAYS\t\t\t\t\t1\t\t//avoid always\n#define AVOID_DONTBLOCK\t\t\t\t\t2\t\t//never totally block\n// restult types\n#define RESULTTYPE_ELEVATORUP\t\t\t1\t\t//elevator is up\n#define RESULTTYPE_WAITFORFUNCBOBBING\t2\t\t//waiting for func bobbing to arrive\n#define RESULTTYPE_BADGRAPPLEPATH\t\t4\t\t//grapple path is obstructed\n#define RESULTTYPE_INSOLIDAREA\t\t\t8\t\t//stuck in solid area, this is bad\n\n//structure used to initialize the movement state\n//the or_moveflags MFL_ONGROUND, MFL_TELEPORTED and MFL_WATERJUMP come from the playerstate\ntypedef struct bot_initmove_s\n{\n\tvec3_t origin;\t\t\t\t//origin of the bot\n\tvec3_t velocity;\t\t\t//velocity of the bot\n\tvec3_t viewoffset;\t\t\t//view offset\n\tint entitynum;\t\t\t\t//entity number of the bot\n\tint client;\t\t\t\t\t//client number of the bot\n\tfloat thinktime;\t\t\t//time the bot thinks\n\tint presencetype;\t\t\t//presencetype of the bot\n\tvec3_t viewangles;\t\t\t//view angles of the bot\n\tint or_moveflags;\t\t\t//values ored to the movement flags\n} bot_initmove_t;\n\n//NOTE: the ideal_viewangles are only valid if MFL_MOVEMENTVIEW is set\ntypedef struct bot_moveresult_s\n{\n\tint failure;\t\t\t\t//true if movement failed all together\n\tint type;\t\t\t\t\t//failure or blocked type\n\tint blocked;\t\t\t\t//true if blocked by an entity\n\tint blockentity;\t\t\t//entity blocking the bot\n\tint traveltype;\t\t\t\t//last executed travel type\n\tint flags;\t\t\t\t\t//result flags\n\tint weapon;\t\t\t\t\t//weapon used for movement\n\tvec3_t movedir;\t\t\t\t//movement direction\n\tvec3_t ideal_viewangles;\t//ideal viewangles for the movement\n} bot_moveresult_t;\n\n// bk001204: from code/botlib/be_ai_move.c\n// TTimo 04/12/2001 was moved here to avoid dup defines\ntypedef struct bot_avoidspot_s\n{\n\tvec3_t origin;\n\tfloat radius;\n\tint type;\n} bot_avoidspot_t;\n\n//resets the whole move state\nvoid BotResetMoveState(int movestate);\n//moves the bot to the given goal\nvoid BotMoveToGoal(bot_moveresult_t *result, int movestate, bot_goal_t *goal, int travelflags);\n//moves the bot in the specified direction using the specified type of movement\nint BotMoveInDirection(int movestate, vec3_t dir, float speed, int type);\n//reset avoid reachability\nvoid BotResetAvoidReach(int movestate);\n//resets the last avoid reachability\nvoid BotResetLastAvoidReach(int movestate);\n//returns a reachability area if the origin is in one\nint BotReachabilityArea(vec3_t origin, int client);\n//view target based on movement\nint BotMovementViewTarget(int movestate, bot_goal_t *goal, int travelflags, float lookahead, vec3_t target);\n//predict the position of a player based on movement towards a goal\nint BotPredictVisiblePosition(vec3_t origin, int areanum, bot_goal_t *goal, int travelflags, vec3_t target);\n//returns the handle of a newly allocated movestate\nint BotAllocMoveState(void);\n//frees the movestate with the given handle\nvoid BotFreeMoveState(int handle);\n//initialize movement state before performing any movement\nvoid BotInitMoveState(int handle, bot_initmove_t *initmove);\n//add a spot to avoid (if type == AVOID_CLEAR all spots are removed)\nvoid BotAddAvoidSpot(int movestate, vec3_t origin, float radius, int type);\n//must be called every map change\nvoid BotSetBrushModelTypes(void);\n//setup movement AI\nint BotSetupMoveAI(void);\n//shutdown movement AI\nvoid BotShutdownMoveAI(void);\n\n"
  },
  {
    "path": "src/game/be_ai_weap.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n\n/*****************************************************************************\n * name:\t\tbe_ai_weap.h\n *\n * desc:\t\tweapon AI\n *\n * $Archive: /source/code/botlib/be_ai_weap.h $\n *\n *****************************************************************************/\n\n//projectile flags\n#define PFL_WINDOWDAMAGE\t\t\t1\t\t//projectile damages through window\n#define PFL_RETURN\t\t\t\t\t2\t\t//set when projectile returns to owner\n//weapon flags\n#define WFL_FIRERELEASED\t\t\t1\t\t//set when projectile is fired with key-up event\n//damage types\n#define DAMAGETYPE_IMPACT\t\t\t1\t\t//damage on impact\n#define DAMAGETYPE_RADIAL\t\t\t2\t\t//radial damage\n#define DAMAGETYPE_VISIBLE\t\t\t4\t\t//damage to all entities visible to the projectile\n\ntypedef struct projectileinfo_s\n{\n\tchar name[MAX_STRINGFIELD];\n\tchar model[MAX_STRINGFIELD];\n\tint flags;\n\tfloat gravity;\n\tint damage;\n\tfloat radius;\n\tint visdamage;\n\tint damagetype;\n\tint healthinc;\n\tfloat push;\n\tfloat detonation;\n\tfloat bounce;\n\tfloat bouncefric;\n\tfloat bouncestop;\n} projectileinfo_t;\n\ntypedef struct weaponinfo_s\n{\n\tint valid;\t\t\t\t\t//true if the weapon info is valid\n\tint number;\t\t\t\t\t\t\t\t\t//number of the weapon\n\tchar name[MAX_STRINGFIELD];\n\tchar model[MAX_STRINGFIELD];\n\tint level;\n\tint weaponindex;\n\tint flags;\n\tchar projectile[MAX_STRINGFIELD];\n\tint numprojectiles;\n\tfloat hspread;\n\tfloat vspread;\n\tfloat speed;\n\tfloat acceleration;\n\tvec3_t recoil;\n\tvec3_t offset;\n\tvec3_t angleoffset;\n\tfloat extrazvelocity;\n\tint ammoamount;\n\tint ammoindex;\n\tfloat activate;\n\tfloat reload;\n\tfloat spinup;\n\tfloat spindown;\n\tprojectileinfo_t proj;\t\t\t\t\t\t//pointer to the used projectile\n} weaponinfo_t;\n\n//setup the weapon AI\nint BotSetupWeaponAI(void);\n//shut down the weapon AI\nvoid BotShutdownWeaponAI(void);\n//returns the best weapon to fight with\nint BotChooseBestFightWeapon(int weaponstate, int *inventory);\n//returns the information of the current weapon\nvoid BotGetWeaponInfo(int weaponstate, int weapon, weaponinfo_t *weaponinfo);\n//loads the weapon weights\nint BotLoadWeaponWeights(int weaponstate, char *filename);\n//returns a handle to a newly allocated weapon state\nint BotAllocWeaponState(void);\n//frees the weapon state\nvoid BotFreeWeaponState(int weaponstate);\n//resets the whole weapon state\nvoid BotResetWeaponState(int weaponstate);\n"
  },
  {
    "path": "src/game/be_ea.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n\n/*****************************************************************************\n * name:\t\tbe_ea.h\n *\n * desc:\t\telementary actions\n *\n * $Archive: /source/code/botlib/be_ea.h $\n *\n *****************************************************************************/\n\n//ClientCommand elementary actions\nvoid EA_Say(int client, char *str);\nvoid EA_SayTeam(int client, char *str);\nvoid EA_Command(int client, char *command );\n\nvoid EA_Action(int client, int action);\nvoid EA_Crouch(int client);\nvoid EA_Walk(int client);\nvoid EA_MoveUp(int client);\nvoid EA_MoveDown(int client);\nvoid EA_MoveForward(int client);\nvoid EA_MoveBack(int client);\nvoid EA_MoveLeft(int client);\nvoid EA_MoveRight(int client);\nvoid EA_Attack(int client);\nvoid EA_Respawn(int client);\nvoid EA_Talk(int client);\nvoid EA_Gesture(int client);\nvoid EA_Use(int client);\n\n//regular elementary actions\nvoid EA_SelectWeapon(int client, int weapon);\nvoid EA_Jump(int client);\nvoid EA_DelayedJump(int client);\nvoid EA_Move(int client, vec3_t dir, float speed);\nvoid EA_View(int client, vec3_t viewangles);\n\n//send regular input to the server\nvoid EA_EndRegular(int client, float thinktime);\nvoid EA_GetInput(int client, float thinktime, bot_input_t *input);\nvoid EA_ResetInput(int client);\n//setup and shutdown routines\nint EA_Setup(void);\nvoid EA_Shutdown(void);\n"
  },
  {
    "path": "src/game/bg_lib.c",
    "content": "//\n//\n// bg_lib,c -- standard C library replacement routines used by code\n// compiled for the virtual machine\n\n#include \"q_shared.h\"\n\n/*-\n * Copyright (c) 1992, 1993\n *\tThe Regents of the University of California.  All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 3. All advertising materials mentioning features or use of this software\n *    must display the following acknowledgement:\n *\tThis product includes software developed by the University of\n *\tCalifornia, Berkeley and its contributors.\n * 4. Neither the name of the University nor the names of its contributors\n *    may be used to endorse or promote products derived from this software\n *    without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#if defined(LIBC_SCCS) && !defined(lint)\n#if 0\nstatic char sccsid[] = \"@(#)qsort.c\t8.1 (Berkeley) 6/4/93\";\n#endif\nstatic const char rcsid[] =\n#endif /* LIBC_SCCS and not lint */\n\n// bk001127 - needed for DLL's\n#if !defined( Q3_VM )\ntypedef int\t\t cmp_t(const void *, const void *);\n#endif\n\nstatic char* med3(char *, char *, char *, cmp_t *);\nstatic void\t swapfunc(char *, char *, int, int);\n\n#ifndef min\n#define min(a, b)\t(a) < (b) ? a : b\n#endif\n\n/*\n * Qsort routine from Bentley & McIlroy's \"Engineering a Sort Function\".\n */\n#define swapcode(TYPE, parmi, parmj, n) { \t\t\\\n\tlong i = (n) / sizeof (TYPE); \t\t\t\\\n\tregister TYPE *pi = (TYPE *) (parmi); \t\t\\\n\tregister TYPE *pj = (TYPE *) (parmj); \t\t\\\n\tdo { \t\t\t\t\t\t\\\n\t\tregister TYPE\tt = *pi;\t\t\\\n\t\t*pi++ = *pj;\t\t\t\t\\\n\t\t*pj++ = t;\t\t\t\t\\\n        } while (--i > 0);\t\t\t\t\\\n}\n\n#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \\\n\tes % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;\n\nstatic void\nswapfunc(a, b, n, swaptype)\n\tchar *a, *b;\n\tint n, swaptype;\n{\n\tif(swaptype <= 1)\n\t\tswapcode(long, a, b, n)\n\telse\n\t\tswapcode(char, a, b, n)\n}\n\n#define swap(a, b)\t\t\t\t\t\\\n\tif (swaptype == 0) {\t\t\t\t\\\n\t\tlong t = *(long *)(a);\t\t\t\\\n\t\t*(long *)(a) = *(long *)(b);\t\t\\\n\t\t*(long *)(b) = t;\t\t\t\\\n\t} else\t\t\t\t\t\t\\\n\t\tswapfunc(a, b, es, swaptype)\n\n#define vecswap(a, b, n) \tif ((n) > 0) swapfunc(a, b, n, swaptype)\n\nstatic char *\nmed3(a, b, c, cmp)\n\tchar *a, *b, *c;\n\tcmp_t *cmp;\n{\n\treturn cmp(a, b) < 0 ?\n\t       (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a ))\n              :(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c ));\n}\n\nvoid\nqsort(a, n, es, cmp)\n\tvoid *a;\n\tsize_t n, es;\n\tcmp_t *cmp;\n{\n\tchar *pa, *pb, *pc, *pd, *pl, *pm, *pn;\n\tint d, r, swaptype, swap_cnt;\n\nloop:\tSWAPINIT(a, es);\n\tswap_cnt = 0;\n\tif (n < 7) {\n\t\tfor (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)\n\t\t\tfor (pl = pm; pl > (char *)a && cmp(pl - es, pl) > 0;\n\t\t\t     pl -= es)\n\t\t\t\tswap(pl, pl - es);\n\t\treturn;\n\t}\n\tpm = (char *)a + (n / 2) * es;\n\tif (n > 7) {\n\t\tpl = a;\n\t\tpn = (char *)a + (n - 1) * es;\n\t\tif (n > 40) {\n\t\t\td = (n / 8) * es;\n\t\t\tpl = med3(pl, pl + d, pl + 2 * d, cmp);\n\t\t\tpm = med3(pm - d, pm, pm + d, cmp);\n\t\t\tpn = med3(pn - 2 * d, pn - d, pn, cmp);\n\t\t}\n\t\tpm = med3(pl, pm, pn, cmp);\n\t}\n\tswap(a, pm);\n\tpa = pb = (char *)a + es;\n\n\tpc = pd = (char *)a + (n - 1) * es;\n\tfor (;;) {\n\t\twhile (pb <= pc && (r = cmp(pb, a)) <= 0) {\n\t\t\tif (r == 0) {\n\t\t\t\tswap_cnt = 1;\n\t\t\t\tswap(pa, pb);\n\t\t\t\tpa += es;\n\t\t\t}\n\t\t\tpb += es;\n\t\t}\n\t\twhile (pb <= pc && (r = cmp(pc, a)) >= 0) {\n\t\t\tif (r == 0) {\n\t\t\t\tswap_cnt = 1;\n\t\t\t\tswap(pc, pd);\n\t\t\t\tpd -= es;\n\t\t\t}\n\t\t\tpc -= es;\n\t\t}\n\t\tif (pb > pc)\n\t\t\tbreak;\n\t\tswap(pb, pc);\n\t\tswap_cnt = 1;\n\t\tpb += es;\n\t\tpc -= es;\n\t}\n\tif (swap_cnt == 0) {  /* Switch to insertion sort */\n\t\tfor (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)\n\t\t\tfor (pl = pm; pl > (char *)a && cmp(pl - es, pl) > 0;\n\t\t\t     pl -= es)\n\t\t\t\tswap(pl, pl - es);\n\t\treturn;\n\t}\n\n\tpn = (char *)a + n * es;\n\tr = min(pa - (char *)a, pb - pa);\n\tvecswap(a, pb - r, r);\n\tr = min(pd - pc, pn - pd - es);\n\tvecswap(pb, pn - r, r);\n\tif ((r = pb - pa) > es)\n\t\tqsort(a, r / es, es, cmp);\n\tif ((r = pd - pc) > es) {\n\t\t/* Iterate rather than recurse to save stack space */\n\t\ta = pn - r;\n\t\tn = r / es;\n\t\tgoto loop;\n\t}\n/*\t\tqsort(pn - r, r / es, es, cmp);*/\n}\n\n//==================================================================================\n\n\n// this file is excluded from release builds because of intrinsics\n\n// bk001211 - gcc errors on compiling strcpy:  parse error before `__extension__'\n#if defined ( Q3_VM )\n\nint strlen( const char *string ) {\n\tconst char\t*s;\n\n\ts = string;\n\twhile ( *s ) {\n\t\ts++;\n\t}\n\treturn s - string;\n}\n\n\nchar *strcat( char *strDestination, const char *strSource ) {\n\tchar\t*s;\n\n\ts = strDestination;\n\twhile ( *s ) {\n\t\ts++;\n\t}\n\twhile ( *strSource ) {\n\t\t*s++ = *strSource++;\n\t}\n\t*s = 0;\n\treturn strDestination;\n}\n\nchar *strcpy( char *strDestination, const char *strSource ) {\n\tchar *s;\n\n\ts = strDestination;\n\twhile ( *strSource ) {\n\t\t*s++ = *strSource++;\n\t}\n\t*s = 0;\n\treturn strDestination;\n}\n\n\nint strcmp( const char *string1, const char *string2 ) {\n\twhile ( *string1 == *string2 && *string1 && *string2 ) {\n\t\tstring1++;\n\t\tstring2++;\n\t}\n\treturn *string1 - *string2;\n}\n\n\nchar *strchr( const char *string, int c ) {\n\twhile ( *string ) {\n\t\tif ( *string == c ) {\n\t\t\treturn ( char * )string;\n\t\t}\n\t\tstring++;\n\t}\n\treturn (char *)0;\n}\n\nchar *strstr( const char *string, const char *strCharSet ) {\n\twhile ( *string ) {\n\t\tint\t\ti;\n\n\t\tfor ( i = 0 ; strCharSet[i] ; i++ ) {\n\t\t\tif ( string[i] != strCharSet[i] ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif ( !strCharSet[i] ) {\n\t\t\treturn (char *)string;\n\t\t}\n\t\tstring++;\n\t}\n\treturn (char *)0;\n}\n#endif // bk001211\n\n// bk001120 - presumably needed for Mac\n//#if !defined(_MSC_VER) && !defined(__linux__)\n// bk001127 - undid undo\n#if defined ( Q3_VM )\nint tolower( int c ) {\n\tif ( c >= 'A' && c <= 'Z' ) {\n\t\tc += 'a' - 'A';\n\t}\n\treturn c;\n}\n\n\nint toupper( int c ) {\n\tif ( c >= 'a' && c <= 'z' ) {\n\t\tc += 'A' - 'a';\n\t}\n\treturn c;\n}\n\n#endif\n//#ifndef _MSC_VER\n\nvoid *memmove( void *dest, const void *src, size_t count ) {\n\tint\t\ti;\n\n\tif ( dest > src ) {\n\t\tfor ( i = count-1 ; i >= 0 ; i-- ) {\n\t\t\t((char *)dest)[i] = ((char *)src)[i];\n\t\t}\n\t} else {\n\t\tfor ( i = 0 ; i < count ; i++ ) {\n\t\t\t((char *)dest)[i] = ((char *)src)[i];\n\t\t}\n\t}\n\treturn dest;\n}\n\n\n#if 0\n\ndouble floor( double x ) {\n\treturn (int)(x + 0x40000000) - 0x40000000;\n}\n\nvoid *memset( void *dest, int c, size_t count ) {\n\twhile ( count-- ) {\n\t\t((char *)dest)[count] = c;\n\t}\n\treturn dest;\n}\n\nvoid *memcpy( void *dest, const void *src, size_t count ) {\n\twhile ( count-- ) {\n\t\t((char *)dest)[count] = ((char *)src)[count];\n\t}\n\treturn dest;\n}\n\nchar *strncpy( char *strDest, const char *strSource, size_t count ) {\n\tchar\t*s;\n\n\ts = strDest;\n\twhile ( *strSource && count ) {\n\t\t*s++ = *strSource++;\n\t\tcount--;\n\t}\n\twhile ( count-- ) {\n\t\t*s++ = 0;\n\t}\n\treturn strDest;\n}\n\ndouble sqrt( double x ) {\n\tfloat\ty;\n\tfloat\tdelta;\n\tfloat\tmaxError;\n\n\tif ( x <= 0 ) {\n\t\treturn 0;\n\t}\n\n\t// initial guess\n\ty = x / 2;\n\n\t// refine\n\tmaxError = x * 0.001;\n\n\tdo {\n\t\tdelta = ( y * y ) - x;\n\t\ty -= delta / ( 2 * y );\n\t} while ( delta > maxError || delta < -maxError );\n\n\treturn y;\n}\n\n\nfloat sintable[1024] = {\n0.000000,0.001534,0.003068,0.004602,0.006136,0.007670,0.009204,0.010738,\n0.012272,0.013805,0.015339,0.016873,0.018407,0.019940,0.021474,0.023008,\n0.024541,0.026075,0.027608,0.029142,0.030675,0.032208,0.033741,0.035274,\n0.036807,0.038340,0.039873,0.041406,0.042938,0.044471,0.046003,0.047535,\n0.049068,0.050600,0.052132,0.053664,0.055195,0.056727,0.058258,0.059790,\n0.061321,0.062852,0.064383,0.065913,0.067444,0.068974,0.070505,0.072035,\n0.073565,0.075094,0.076624,0.078153,0.079682,0.081211,0.082740,0.084269,\n0.085797,0.087326,0.088854,0.090381,0.091909,0.093436,0.094963,0.096490,\n0.098017,0.099544,0.101070,0.102596,0.104122,0.105647,0.107172,0.108697,\n0.110222,0.111747,0.113271,0.114795,0.116319,0.117842,0.119365,0.120888,\n0.122411,0.123933,0.125455,0.126977,0.128498,0.130019,0.131540,0.133061,\n0.134581,0.136101,0.137620,0.139139,0.140658,0.142177,0.143695,0.145213,\n0.146730,0.148248,0.149765,0.151281,0.152797,0.154313,0.155828,0.157343,\n0.158858,0.160372,0.161886,0.163400,0.164913,0.166426,0.167938,0.169450,\n0.170962,0.172473,0.173984,0.175494,0.177004,0.178514,0.180023,0.181532,\n0.183040,0.184548,0.186055,0.187562,0.189069,0.190575,0.192080,0.193586,\n0.195090,0.196595,0.198098,0.199602,0.201105,0.202607,0.204109,0.205610,\n0.207111,0.208612,0.210112,0.211611,0.213110,0.214609,0.216107,0.217604,\n0.219101,0.220598,0.222094,0.223589,0.225084,0.226578,0.228072,0.229565,\n0.231058,0.232550,0.234042,0.235533,0.237024,0.238514,0.240003,0.241492,\n0.242980,0.244468,0.245955,0.247442,0.248928,0.250413,0.251898,0.253382,\n0.254866,0.256349,0.257831,0.259313,0.260794,0.262275,0.263755,0.265234,\n0.266713,0.268191,0.269668,0.271145,0.272621,0.274097,0.275572,0.277046,\n0.278520,0.279993,0.281465,0.282937,0.284408,0.285878,0.287347,0.288816,\n0.290285,0.291752,0.293219,0.294685,0.296151,0.297616,0.299080,0.300543,\n0.302006,0.303468,0.304929,0.306390,0.307850,0.309309,0.310767,0.312225,\n0.313682,0.315138,0.316593,0.318048,0.319502,0.320955,0.322408,0.323859,\n0.325310,0.326760,0.328210,0.329658,0.331106,0.332553,0.334000,0.335445,\n0.336890,0.338334,0.339777,0.341219,0.342661,0.344101,0.345541,0.346980,\n0.348419,0.349856,0.351293,0.352729,0.354164,0.355598,0.357031,0.358463,\n0.359895,0.361326,0.362756,0.364185,0.365613,0.367040,0.368467,0.369892,\n0.371317,0.372741,0.374164,0.375586,0.377007,0.378428,0.379847,0.381266,\n0.382683,0.384100,0.385516,0.386931,0.388345,0.389758,0.391170,0.392582,\n0.393992,0.395401,0.396810,0.398218,0.399624,0.401030,0.402435,0.403838,\n0.405241,0.406643,0.408044,0.409444,0.410843,0.412241,0.413638,0.415034,\n0.416430,0.417824,0.419217,0.420609,0.422000,0.423390,0.424780,0.426168,\n0.427555,0.428941,0.430326,0.431711,0.433094,0.434476,0.435857,0.437237,\n0.438616,0.439994,0.441371,0.442747,0.444122,0.445496,0.446869,0.448241,\n0.449611,0.450981,0.452350,0.453717,0.455084,0.456449,0.457813,0.459177,\n0.460539,0.461900,0.463260,0.464619,0.465976,0.467333,0.468689,0.470043,\n0.471397,0.472749,0.474100,0.475450,0.476799,0.478147,0.479494,0.480839,\n0.482184,0.483527,0.484869,0.486210,0.487550,0.488889,0.490226,0.491563,\n0.492898,0.494232,0.495565,0.496897,0.498228,0.499557,0.500885,0.502212,\n0.503538,0.504863,0.506187,0.507509,0.508830,0.510150,0.511469,0.512786,\n0.514103,0.515418,0.516732,0.518045,0.519356,0.520666,0.521975,0.523283,\n0.524590,0.525895,0.527199,0.528502,0.529804,0.531104,0.532403,0.533701,\n0.534998,0.536293,0.537587,0.538880,0.540171,0.541462,0.542751,0.544039,\n0.545325,0.546610,0.547894,0.549177,0.550458,0.551738,0.553017,0.554294,\n0.555570,0.556845,0.558119,0.559391,0.560662,0.561931,0.563199,0.564466,\n0.565732,0.566996,0.568259,0.569521,0.570781,0.572040,0.573297,0.574553,\n0.575808,0.577062,0.578314,0.579565,0.580814,0.582062,0.583309,0.584554,\n0.585798,0.587040,0.588282,0.589521,0.590760,0.591997,0.593232,0.594466,\n0.595699,0.596931,0.598161,0.599389,0.600616,0.601842,0.603067,0.604290,\n0.605511,0.606731,0.607950,0.609167,0.610383,0.611597,0.612810,0.614022,\n0.615232,0.616440,0.617647,0.618853,0.620057,0.621260,0.622461,0.623661,\n0.624859,0.626056,0.627252,0.628446,0.629638,0.630829,0.632019,0.633207,\n0.634393,0.635578,0.636762,0.637944,0.639124,0.640303,0.641481,0.642657,\n0.643832,0.645005,0.646176,0.647346,0.648514,0.649681,0.650847,0.652011,\n0.653173,0.654334,0.655493,0.656651,0.657807,0.658961,0.660114,0.661266,\n0.662416,0.663564,0.664711,0.665856,0.667000,0.668142,0.669283,0.670422,\n0.671559,0.672695,0.673829,0.674962,0.676093,0.677222,0.678350,0.679476,\n0.680601,0.681724,0.682846,0.683965,0.685084,0.686200,0.687315,0.688429,\n0.689541,0.690651,0.691759,0.692866,0.693971,0.695075,0.696177,0.697278,\n0.698376,0.699473,0.700569,0.701663,0.702755,0.703845,0.704934,0.706021,\n0.707107,0.708191,0.709273,0.710353,0.711432,0.712509,0.713585,0.714659,\n0.715731,0.716801,0.717870,0.718937,0.720003,0.721066,0.722128,0.723188,\n0.724247,0.725304,0.726359,0.727413,0.728464,0.729514,0.730563,0.731609,\n0.732654,0.733697,0.734739,0.735779,0.736817,0.737853,0.738887,0.739920,\n0.740951,0.741980,0.743008,0.744034,0.745058,0.746080,0.747101,0.748119,\n0.749136,0.750152,0.751165,0.752177,0.753187,0.754195,0.755201,0.756206,\n0.757209,0.758210,0.759209,0.760207,0.761202,0.762196,0.763188,0.764179,\n0.765167,0.766154,0.767139,0.768122,0.769103,0.770083,0.771061,0.772036,\n0.773010,0.773983,0.774953,0.775922,0.776888,0.777853,0.778817,0.779778,\n0.780737,0.781695,0.782651,0.783605,0.784557,0.785507,0.786455,0.787402,\n0.788346,0.789289,0.790230,0.791169,0.792107,0.793042,0.793975,0.794907,\n0.795837,0.796765,0.797691,0.798615,0.799537,0.800458,0.801376,0.802293,\n0.803208,0.804120,0.805031,0.805940,0.806848,0.807753,0.808656,0.809558,\n0.810457,0.811355,0.812251,0.813144,0.814036,0.814926,0.815814,0.816701,\n0.817585,0.818467,0.819348,0.820226,0.821103,0.821977,0.822850,0.823721,\n0.824589,0.825456,0.826321,0.827184,0.828045,0.828904,0.829761,0.830616,\n0.831470,0.832321,0.833170,0.834018,0.834863,0.835706,0.836548,0.837387,\n0.838225,0.839060,0.839894,0.840725,0.841555,0.842383,0.843208,0.844032,\n0.844854,0.845673,0.846491,0.847307,0.848120,0.848932,0.849742,0.850549,\n0.851355,0.852159,0.852961,0.853760,0.854558,0.855354,0.856147,0.856939,\n0.857729,0.858516,0.859302,0.860085,0.860867,0.861646,0.862424,0.863199,\n0.863973,0.864744,0.865514,0.866281,0.867046,0.867809,0.868571,0.869330,\n0.870087,0.870842,0.871595,0.872346,0.873095,0.873842,0.874587,0.875329,\n0.876070,0.876809,0.877545,0.878280,0.879012,0.879743,0.880471,0.881197,\n0.881921,0.882643,0.883363,0.884081,0.884797,0.885511,0.886223,0.886932,\n0.887640,0.888345,0.889048,0.889750,0.890449,0.891146,0.891841,0.892534,\n0.893224,0.893913,0.894599,0.895284,0.895966,0.896646,0.897325,0.898001,\n0.898674,0.899346,0.900016,0.900683,0.901349,0.902012,0.902673,0.903332,\n0.903989,0.904644,0.905297,0.905947,0.906596,0.907242,0.907886,0.908528,\n0.909168,0.909806,0.910441,0.911075,0.911706,0.912335,0.912962,0.913587,\n0.914210,0.914830,0.915449,0.916065,0.916679,0.917291,0.917901,0.918508,\n0.919114,0.919717,0.920318,0.920917,0.921514,0.922109,0.922701,0.923291,\n0.923880,0.924465,0.925049,0.925631,0.926210,0.926787,0.927363,0.927935,\n0.928506,0.929075,0.929641,0.930205,0.930767,0.931327,0.931884,0.932440,\n0.932993,0.933544,0.934093,0.934639,0.935184,0.935726,0.936266,0.936803,\n0.937339,0.937872,0.938404,0.938932,0.939459,0.939984,0.940506,0.941026,\n0.941544,0.942060,0.942573,0.943084,0.943593,0.944100,0.944605,0.945107,\n0.945607,0.946105,0.946601,0.947094,0.947586,0.948075,0.948561,0.949046,\n0.949528,0.950008,0.950486,0.950962,0.951435,0.951906,0.952375,0.952842,\n0.953306,0.953768,0.954228,0.954686,0.955141,0.955594,0.956045,0.956494,\n0.956940,0.957385,0.957826,0.958266,0.958703,0.959139,0.959572,0.960002,\n0.960431,0.960857,0.961280,0.961702,0.962121,0.962538,0.962953,0.963366,\n0.963776,0.964184,0.964590,0.964993,0.965394,0.965793,0.966190,0.966584,\n0.966976,0.967366,0.967754,0.968139,0.968522,0.968903,0.969281,0.969657,\n0.970031,0.970403,0.970772,0.971139,0.971504,0.971866,0.972226,0.972584,\n0.972940,0.973293,0.973644,0.973993,0.974339,0.974684,0.975025,0.975365,\n0.975702,0.976037,0.976370,0.976700,0.977028,0.977354,0.977677,0.977999,\n0.978317,0.978634,0.978948,0.979260,0.979570,0.979877,0.980182,0.980485,\n0.980785,0.981083,0.981379,0.981673,0.981964,0.982253,0.982539,0.982824,\n0.983105,0.983385,0.983662,0.983937,0.984210,0.984480,0.984749,0.985014,\n0.985278,0.985539,0.985798,0.986054,0.986308,0.986560,0.986809,0.987057,\n0.987301,0.987544,0.987784,0.988022,0.988258,0.988491,0.988722,0.988950,\n0.989177,0.989400,0.989622,0.989841,0.990058,0.990273,0.990485,0.990695,\n0.990903,0.991108,0.991311,0.991511,0.991710,0.991906,0.992099,0.992291,\n0.992480,0.992666,0.992850,0.993032,0.993212,0.993389,0.993564,0.993737,\n0.993907,0.994075,0.994240,0.994404,0.994565,0.994723,0.994879,0.995033,\n0.995185,0.995334,0.995481,0.995625,0.995767,0.995907,0.996045,0.996180,\n0.996313,0.996443,0.996571,0.996697,0.996820,0.996941,0.997060,0.997176,\n0.997290,0.997402,0.997511,0.997618,0.997723,0.997825,0.997925,0.998023,\n0.998118,0.998211,0.998302,0.998390,0.998476,0.998559,0.998640,0.998719,\n0.998795,0.998870,0.998941,0.999011,0.999078,0.999142,0.999205,0.999265,\n0.999322,0.999378,0.999431,0.999481,0.999529,0.999575,0.999619,0.999660,\n0.999699,0.999735,0.999769,0.999801,0.999831,0.999858,0.999882,0.999905,\n0.999925,0.999942,0.999958,0.999971,0.999981,0.999989,0.999995,0.999999\n};\n\ndouble sin( double x ) {\n\tint\tindex;\n\tint\tquad;\n\n\tindex = 1024 * x / (M_PI * 0.5);\n\tquad = ( index >> 10 ) & 3;\n\tindex &= 1023;\n\tswitch ( quad ) {\n\tcase 0:\n\t\treturn sintable[index];\n\tcase 1:\n\t\treturn sintable[1023-index];\n\tcase 2:\n\t\treturn -sintable[index];\n\tcase 3:\n\t\treturn -sintable[1023-index];\n\t}\n\treturn 0;\n}\n\n\ndouble cos( double x ) {\n\tint\tindex;\n\tint\tquad;\n\n\tindex = 1024 * x / (M_PI * 0.5);\n\tquad = ( index >> 10 ) & 3;\n\tindex &= 1023;\n\tswitch ( quad ) {\n\tcase 3:\n\t\treturn sintable[index];\n\tcase 0:\n\t\treturn sintable[1023-index];\n\tcase 1:\n\t\treturn -sintable[index];\n\tcase 2:\n\t\treturn -sintable[1023-index];\n\t}\n\treturn 0;\n}\n\n\n/*\nvoid create_acostable( void ) {\n\tint i;\n\tFILE *fp;\n\tfloat a;\n\n\tfp = fopen(\"c:\\\\acostable.txt\", \"w\");\n\tfprintf(fp, \"float acostable[] = {\");\n\tfor (i = 0; i < 1024; i++) {\n\t\tif (!(i & 7))\n\t\t\tfprintf(fp, \"\\n\");\n\t\ta = acos( (float) -1 + i / 512 );\n\t\tfprintf(fp, \"%1.8f,\", a);\n\t}\n\tfprintf(fp, \"\\n}\\n\");\n\tfclose(fp);\n}\n*/\n\nfloat acostable[] = {\n3.14159265,3.07908248,3.05317551,3.03328655,3.01651113,3.00172442,2.98834964,2.97604422,\n2.96458497,2.95381690,2.94362719,2.93393068,2.92466119,2.91576615,2.90720289,2.89893629,\n2.89093699,2.88318015,2.87564455,2.86831188,2.86116621,2.85419358,2.84738169,2.84071962,\n2.83419760,2.82780691,2.82153967,2.81538876,2.80934770,2.80341062,2.79757211,2.79182724,\n2.78617145,2.78060056,2.77511069,2.76969824,2.76435988,2.75909250,2.75389319,2.74875926,\n2.74368816,2.73867752,2.73372510,2.72882880,2.72398665,2.71919677,2.71445741,2.70976688,\n2.70512362,2.70052613,2.69597298,2.69146283,2.68699438,2.68256642,2.67817778,2.67382735,\n2.66951407,2.66523692,2.66099493,2.65678719,2.65261279,2.64847088,2.64436066,2.64028133,\n2.63623214,2.63221238,2.62822133,2.62425835,2.62032277,2.61641398,2.61253138,2.60867440,\n2.60484248,2.60103507,2.59725167,2.59349176,2.58975488,2.58604053,2.58234828,2.57867769,\n2.57502832,2.57139977,2.56779164,2.56420354,2.56063509,2.55708594,2.55355572,2.55004409,\n2.54655073,2.54307530,2.53961750,2.53617701,2.53275354,2.52934680,2.52595650,2.52258238,\n2.51922417,2.51588159,2.51255441,2.50924238,2.50594525,2.50266278,2.49939476,2.49614096,\n2.49290115,2.48967513,2.48646269,2.48326362,2.48007773,2.47690482,2.47374472,2.47059722,\n2.46746215,2.46433933,2.46122860,2.45812977,2.45504269,2.45196720,2.44890314,2.44585034,\n2.44280867,2.43977797,2.43675809,2.43374890,2.43075025,2.42776201,2.42478404,2.42181622,\n2.41885841,2.41591048,2.41297232,2.41004380,2.40712480,2.40421521,2.40131491,2.39842379,\n2.39554173,2.39266863,2.38980439,2.38694889,2.38410204,2.38126374,2.37843388,2.37561237,\n2.37279910,2.36999400,2.36719697,2.36440790,2.36162673,2.35885335,2.35608768,2.35332964,\n2.35057914,2.34783610,2.34510044,2.34237208,2.33965094,2.33693695,2.33423003,2.33153010,\n2.32883709,2.32615093,2.32347155,2.32079888,2.31813284,2.31547337,2.31282041,2.31017388,\n2.30753373,2.30489988,2.30227228,2.29965086,2.29703556,2.29442632,2.29182309,2.28922580,\n2.28663439,2.28404881,2.28146900,2.27889490,2.27632647,2.27376364,2.27120637,2.26865460,\n2.26610827,2.26356735,2.26103177,2.25850149,2.25597646,2.25345663,2.25094195,2.24843238,\n2.24592786,2.24342836,2.24093382,2.23844420,2.23595946,2.23347956,2.23100444,2.22853408,\n2.22606842,2.22360742,2.22115104,2.21869925,2.21625199,2.21380924,2.21137096,2.20893709,\n2.20650761,2.20408248,2.20166166,2.19924511,2.19683280,2.19442469,2.19202074,2.18962092,\n2.18722520,2.18483354,2.18244590,2.18006225,2.17768257,2.17530680,2.17293493,2.17056692,\n2.16820274,2.16584236,2.16348574,2.16113285,2.15878367,2.15643816,2.15409630,2.15175805,\n2.14942338,2.14709226,2.14476468,2.14244059,2.14011997,2.13780279,2.13548903,2.13317865,\n2.13087163,2.12856795,2.12626757,2.12397047,2.12167662,2.11938600,2.11709859,2.11481435,\n2.11253326,2.11025530,2.10798044,2.10570867,2.10343994,2.10117424,2.09891156,2.09665185,\n2.09439510,2.09214129,2.08989040,2.08764239,2.08539725,2.08315496,2.08091550,2.07867884,\n2.07644495,2.07421383,2.07198545,2.06975978,2.06753681,2.06531651,2.06309887,2.06088387,\n2.05867147,2.05646168,2.05425445,2.05204979,2.04984765,2.04764804,2.04545092,2.04325628,\n2.04106409,2.03887435,2.03668703,2.03450211,2.03231957,2.03013941,2.02796159,2.02578610,\n2.02361292,2.02144204,2.01927344,2.01710710,2.01494300,2.01278113,2.01062146,2.00846399,\n2.00630870,2.00415556,2.00200457,1.99985570,1.99770895,1.99556429,1.99342171,1.99128119,\n1.98914271,1.98700627,1.98487185,1.98273942,1.98060898,1.97848051,1.97635399,1.97422942,\n1.97210676,1.96998602,1.96786718,1.96575021,1.96363511,1.96152187,1.95941046,1.95730088,\n1.95519310,1.95308712,1.95098292,1.94888050,1.94677982,1.94468089,1.94258368,1.94048818,\n1.93839439,1.93630228,1.93421185,1.93212308,1.93003595,1.92795046,1.92586659,1.92378433,\n1.92170367,1.91962459,1.91754708,1.91547113,1.91339673,1.91132385,1.90925250,1.90718266,\n1.90511432,1.90304746,1.90098208,1.89891815,1.89685568,1.89479464,1.89273503,1.89067683,\n1.88862003,1.88656463,1.88451060,1.88245794,1.88040664,1.87835668,1.87630806,1.87426076,\n1.87221477,1.87017008,1.86812668,1.86608457,1.86404371,1.86200412,1.85996577,1.85792866,\n1.85589277,1.85385809,1.85182462,1.84979234,1.84776125,1.84573132,1.84370256,1.84167495,\n1.83964848,1.83762314,1.83559892,1.83357582,1.83155381,1.82953289,1.82751305,1.82549429,\n1.82347658,1.82145993,1.81944431,1.81742973,1.81541617,1.81340362,1.81139207,1.80938151,\n1.80737194,1.80536334,1.80335570,1.80134902,1.79934328,1.79733848,1.79533460,1.79333164,\n1.79132959,1.78932843,1.78732817,1.78532878,1.78333027,1.78133261,1.77933581,1.77733985,\n1.77534473,1.77335043,1.77135695,1.76936428,1.76737240,1.76538132,1.76339101,1.76140148,\n1.75941271,1.75742470,1.75543743,1.75345090,1.75146510,1.74948002,1.74749565,1.74551198,\n1.74352900,1.74154672,1.73956511,1.73758417,1.73560389,1.73362426,1.73164527,1.72966692,\n1.72768920,1.72571209,1.72373560,1.72175971,1.71978441,1.71780969,1.71583556,1.71386199,\n1.71188899,1.70991653,1.70794462,1.70597325,1.70400241,1.70203209,1.70006228,1.69809297,\n1.69612416,1.69415584,1.69218799,1.69022062,1.68825372,1.68628727,1.68432127,1.68235571,\n1.68039058,1.67842588,1.67646160,1.67449772,1.67253424,1.67057116,1.66860847,1.66664615,\n1.66468420,1.66272262,1.66076139,1.65880050,1.65683996,1.65487975,1.65291986,1.65096028,\n1.64900102,1.64704205,1.64508338,1.64312500,1.64116689,1.63920905,1.63725148,1.63529416,\n1.63333709,1.63138026,1.62942366,1.62746728,1.62551112,1.62355517,1.62159943,1.61964388,\n1.61768851,1.61573332,1.61377831,1.61182346,1.60986877,1.60791422,1.60595982,1.60400556,\n1.60205142,1.60009739,1.59814349,1.59618968,1.59423597,1.59228235,1.59032882,1.58837536,\n1.58642196,1.58446863,1.58251535,1.58056211,1.57860891,1.57665574,1.57470259,1.57274945,\n1.57079633,1.56884320,1.56689007,1.56493692,1.56298375,1.56103055,1.55907731,1.55712403,\n1.55517069,1.55321730,1.55126383,1.54931030,1.54735668,1.54540297,1.54344917,1.54149526,\n1.53954124,1.53758710,1.53563283,1.53367843,1.53172389,1.52976919,1.52781434,1.52585933,\n1.52390414,1.52194878,1.51999323,1.51803748,1.51608153,1.51412537,1.51216900,1.51021240,\n1.50825556,1.50629849,1.50434117,1.50238360,1.50042576,1.49846765,1.49650927,1.49455060,\n1.49259163,1.49063237,1.48867280,1.48671291,1.48475270,1.48279215,1.48083127,1.47887004,\n1.47690845,1.47494650,1.47298419,1.47102149,1.46905841,1.46709493,1.46513106,1.46316677,\n1.46120207,1.45923694,1.45727138,1.45530538,1.45333893,1.45137203,1.44940466,1.44743682,\n1.44546850,1.44349969,1.44153038,1.43956057,1.43759024,1.43561940,1.43364803,1.43167612,\n1.42970367,1.42773066,1.42575709,1.42378296,1.42180825,1.41983295,1.41785705,1.41588056,\n1.41390346,1.41192573,1.40994738,1.40796840,1.40598877,1.40400849,1.40202755,1.40004594,\n1.39806365,1.39608068,1.39409701,1.39211264,1.39012756,1.38814175,1.38615522,1.38416795,\n1.38217994,1.38019117,1.37820164,1.37621134,1.37422025,1.37222837,1.37023570,1.36824222,\n1.36624792,1.36425280,1.36225684,1.36026004,1.35826239,1.35626387,1.35426449,1.35226422,\n1.35026307,1.34826101,1.34625805,1.34425418,1.34224937,1.34024364,1.33823695,1.33622932,\n1.33422072,1.33221114,1.33020059,1.32818904,1.32617649,1.32416292,1.32214834,1.32013273,\n1.31811607,1.31609837,1.31407960,1.31205976,1.31003885,1.30801684,1.30599373,1.30396951,\n1.30194417,1.29991770,1.29789009,1.29586133,1.29383141,1.29180031,1.28976803,1.28773456,\n1.28569989,1.28366400,1.28162688,1.27958854,1.27754894,1.27550809,1.27346597,1.27142257,\n1.26937788,1.26733189,1.26528459,1.26323597,1.26118602,1.25913471,1.25708205,1.25502803,\n1.25297262,1.25091583,1.24885763,1.24679802,1.24473698,1.24267450,1.24061058,1.23854519,\n1.23647833,1.23440999,1.23234015,1.23026880,1.22819593,1.22612152,1.22404557,1.22196806,\n1.21988898,1.21780832,1.21572606,1.21364219,1.21155670,1.20946958,1.20738080,1.20529037,\n1.20319826,1.20110447,1.19900898,1.19691177,1.19481283,1.19271216,1.19060973,1.18850553,\n1.18639955,1.18429178,1.18218219,1.18007079,1.17795754,1.17584244,1.17372548,1.17160663,\n1.16948589,1.16736324,1.16523866,1.16311215,1.16098368,1.15885323,1.15672081,1.15458638,\n1.15244994,1.15031147,1.14817095,1.14602836,1.14388370,1.14173695,1.13958808,1.13743709,\n1.13528396,1.13312866,1.13097119,1.12881153,1.12664966,1.12448556,1.12231921,1.12015061,\n1.11797973,1.11580656,1.11363107,1.11145325,1.10927308,1.10709055,1.10490563,1.10271831,\n1.10052856,1.09833638,1.09614174,1.09394462,1.09174500,1.08954287,1.08733820,1.08513098,\n1.08292118,1.08070879,1.07849378,1.07627614,1.07405585,1.07183287,1.06960721,1.06737882,\n1.06514770,1.06291382,1.06067715,1.05843769,1.05619540,1.05395026,1.05170226,1.04945136,\n1.04719755,1.04494080,1.04268110,1.04041841,1.03815271,1.03588399,1.03361221,1.03133735,\n1.02905939,1.02677830,1.02449407,1.02220665,1.01991603,1.01762219,1.01532509,1.01302471,\n1.01072102,1.00841400,1.00610363,1.00378986,1.00147268,0.99915206,0.99682798,0.99450039,\n0.99216928,0.98983461,0.98749636,0.98515449,0.98280898,0.98045980,0.97810691,0.97575030,\n0.97338991,0.97102573,0.96865772,0.96628585,0.96391009,0.96153040,0.95914675,0.95675912,\n0.95436745,0.95197173,0.94957191,0.94716796,0.94475985,0.94234754,0.93993099,0.93751017,\n0.93508504,0.93265556,0.93022170,0.92778341,0.92534066,0.92289341,0.92044161,0.91798524,\n0.91552424,0.91305858,0.91058821,0.90811309,0.90563319,0.90314845,0.90065884,0.89816430,\n0.89566479,0.89316028,0.89065070,0.88813602,0.88561619,0.88309116,0.88056088,0.87802531,\n0.87548438,0.87293806,0.87038629,0.86782901,0.86526619,0.86269775,0.86012366,0.85754385,\n0.85495827,0.85236686,0.84976956,0.84716633,0.84455709,0.84194179,0.83932037,0.83669277,\n0.83405893,0.83141877,0.82877225,0.82611928,0.82345981,0.82079378,0.81812110,0.81544172,\n0.81275556,0.81006255,0.80736262,0.80465570,0.80194171,0.79922057,0.79649221,0.79375655,\n0.79101352,0.78826302,0.78550497,0.78273931,0.77996593,0.77718475,0.77439569,0.77159865,\n0.76879355,0.76598029,0.76315878,0.76032891,0.75749061,0.75464376,0.75178826,0.74892402,\n0.74605092,0.74316887,0.74027775,0.73737744,0.73446785,0.73154885,0.72862033,0.72568217,\n0.72273425,0.71977644,0.71680861,0.71383064,0.71084240,0.70784376,0.70483456,0.70181469,\n0.69878398,0.69574231,0.69268952,0.68962545,0.68654996,0.68346288,0.68036406,0.67725332,\n0.67413051,0.67099544,0.66784794,0.66468783,0.66151492,0.65832903,0.65512997,0.65191753,\n0.64869151,0.64545170,0.64219789,0.63892987,0.63564741,0.63235028,0.62903824,0.62571106,\n0.62236849,0.61901027,0.61563615,0.61224585,0.60883911,0.60541564,0.60197515,0.59851735,\n0.59504192,0.59154856,0.58803694,0.58450672,0.58095756,0.57738911,0.57380101,0.57019288,\n0.56656433,0.56291496,0.55924437,0.55555212,0.55183778,0.54810089,0.54434099,0.54055758,\n0.53675018,0.53291825,0.52906127,0.52517867,0.52126988,0.51733431,0.51337132,0.50938028,\n0.50536051,0.50131132,0.49723200,0.49312177,0.48897987,0.48480547,0.48059772,0.47635573,\n0.47207859,0.46776530,0.46341487,0.45902623,0.45459827,0.45012983,0.44561967,0.44106652,\n0.43646903,0.43182577,0.42713525,0.42239588,0.41760600,0.41276385,0.40786755,0.40291513,\n0.39790449,0.39283339,0.38769946,0.38250016,0.37723277,0.37189441,0.36648196,0.36099209,\n0.35542120,0.34976542,0.34402054,0.33818204,0.33224495,0.32620390,0.32005298,0.31378574,\n0.30739505,0.30087304,0.29421096,0.28739907,0.28042645,0.27328078,0.26594810,0.25841250,\n0.25065566,0.24265636,0.23438976,0.22582651,0.21693146,0.20766198,0.19796546,0.18777575,\n0.17700769,0.16554844,0.15324301,0.13986823,0.12508152,0.10830610,0.08841715,0.06251018,\n}\n\ndouble acos( double x ) {\n\tint index;\n\n\tif (x < -1)\n\t\tx = -1;\n\tif (x > 1)\n\t\tx = 1;\n\tindex = (float) (1.0 + x) * 511.9;\n\treturn acostable[index];\n}\n\ndouble atan2( double y, double x ) {\n\tfloat\tbase;\n\tfloat\ttemp;\n\tfloat\tdir;\n\tfloat\ttest;\n\tint\t\ti;\n\n\tif ( x < 0 ) {\n\t\tif ( y >= 0 ) {\n\t\t\t// quad 1\n\t\t\tbase = M_PI / 2;\n\t\t\ttemp = x;\n\t\t\tx = y;\n\t\t\ty = -temp;\n\t\t} else {\n\t\t\t// quad 2\n\t\t\tbase = M_PI;\n\t\t\tx = -x;\n\t\t\ty = -y;\n\t\t}\n\t} else {\n\t\tif ( y < 0 ) {\n\t\t\t// quad 3\n\t\t\tbase = 3 * M_PI / 2;\n\t\t\ttemp = x;\n\t\t\tx = -y;\n\t\t\ty = temp;\n\t\t}\n\t}\n\n\tif ( y > x ) {\n\t\tbase += M_PI/2;\n\t\ttemp = x;\n\t\tx = y;\n\t\ty = temp;\n\t\tdir = -1;\n\t} else {\n\t\tdir = 1;\n\t}\n\n\t// calcualte angle in octant 0\n\tif ( x == 0 ) {\n\t\treturn base;\n\t}\n\ty /= x;\n\n\tfor ( i = 0 ; i < 512 ; i++ ) {\n\t\ttest = sintable[i] / sintable[1023-i];\n\t\tif ( test > y ) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn base + dir * i * ( M_PI/2048); \n}\n\n\n#endif\n\n#ifdef Q3_VM\n// bk001127 - guarded this tan replacement \n// ld: undefined versioned symbol name tan@@GLIBC_2.0\ndouble tan( double x ) {\n\treturn sin(x) / cos(x);\n}\n#endif\n\n\nstatic int randSeed = 0;\n\nvoid\tsrand( unsigned seed ) {\n\trandSeed = seed;\n}\n\nint\t\trand( void ) {\n\trandSeed = (69069 * randSeed + 1);\n\treturn randSeed & 0x7fff;\n}\n\ndouble atof( const char *string ) {\n\tfloat sign;\n\tfloat value;\n\tint\t\tc;\n\n\n\t// skip whitespace\n\twhile ( *string <= ' ' ) {\n\t\tif ( !*string ) {\n\t\t\treturn 0;\n\t\t}\n\t\tstring++;\n\t}\n\n\t// check sign\n\tswitch ( *string ) {\n\tcase '+':\n\t\tstring++;\n\t\tsign = 1;\n\t\tbreak;\n\tcase '-':\n\t\tstring++;\n\t\tsign = -1;\n\t\tbreak;\n\tdefault:\n\t\tsign = 1;\n\t\tbreak;\n\t}\n\n\t// read digits\n\tvalue = 0;\n\tc = string[0];\n\tif ( c != '.' ) {\n\t\tdo {\n\t\t\tc = *string++;\n\t\t\tif ( c < '0' || c > '9' ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tc -= '0';\n\t\t\tvalue = value * 10 + c;\n\t\t} while ( 1 );\n\t} else {\n\t\tstring++;\n\t}\n\n\t// check for decimal point\n\tif ( c == '.' ) {\n\t\tdouble fraction;\n\n\t\tfraction = 0.1;\n\t\tdo {\n\t\t\tc = *string++;\n\t\t\tif ( c < '0' || c > '9' ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tc -= '0';\n\t\t\tvalue += c * fraction;\n\t\t\tfraction *= 0.1;\n\t\t} while ( 1 );\n\n\t}\n\n\t// not handling 10e10 notation...\n\n\treturn value * sign;\n}\n\ndouble _atof( const char **stringPtr ) {\n\tconst char\t*string;\n\tfloat sign;\n\tfloat value;\n\tint\t\tc = '0'; // bk001211 - uninitialized use possible\n\n\tstring = *stringPtr;\n\n\t// skip whitespace\n\twhile ( *string <= ' ' ) {\n\t\tif ( !*string ) {\n\t\t\t*stringPtr = string;\n\t\t\treturn 0;\n\t\t}\n\t\tstring++;\n\t}\n\n\t// check sign\n\tswitch ( *string ) {\n\tcase '+':\n\t\tstring++;\n\t\tsign = 1;\n\t\tbreak;\n\tcase '-':\n\t\tstring++;\n\t\tsign = -1;\n\t\tbreak;\n\tdefault:\n\t\tsign = 1;\n\t\tbreak;\n\t}\n\n\t// read digits\n\tvalue = 0;\n\tif ( string[0] != '.' ) {\n\t\tdo {\n\t\t\tc = *string++;\n\t\t\tif ( c < '0' || c > '9' ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tc -= '0';\n\t\t\tvalue = value * 10 + c;\n\t\t} while ( 1 );\n\t}\n\n\t// check for decimal point\n\tif ( c == '.' ) {\n\t\tdouble fraction;\n\n\t\tfraction = 0.1;\n\t\tdo {\n\t\t\tc = *string++;\n\t\t\tif ( c < '0' || c > '9' ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tc -= '0';\n\t\t\tvalue += c * fraction;\n\t\t\tfraction *= 0.1;\n\t\t} while ( 1 );\n\n\t}\n\n\t// not handling 10e10 notation...\n\t*stringPtr = string;\n\n\treturn value * sign;\n}\n\n\n// bk001120 - presumably needed for Mac\n//#if !defined ( _MSC_VER ) && ! defined ( __linux__ )\n\n// bk001127 - undid undo\n#if defined ( Q3_VM )\nint atoi( const char *string ) {\n\tint\t\tsign;\n\tint\t\tvalue;\n\tint\t\tc;\n\n\n\t// skip whitespace\n\twhile ( *string <= ' ' ) {\n\t\tif ( !*string ) {\n\t\t\treturn 0;\n\t\t}\n\t\tstring++;\n\t}\n\n\t// check sign\n\tswitch ( *string ) {\n\tcase '+':\n\t\tstring++;\n\t\tsign = 1;\n\t\tbreak;\n\tcase '-':\n\t\tstring++;\n\t\tsign = -1;\n\t\tbreak;\n\tdefault:\n\t\tsign = 1;\n\t\tbreak;\n\t}\n\n\t// read digits\n\tvalue = 0;\n\tdo {\n\t\tc = *string++;\n\t\tif ( c < '0' || c > '9' ) {\n\t\t\tbreak;\n\t\t}\n\t\tc -= '0';\n\t\tvalue = value * 10 + c;\n\t} while ( 1 );\n\n\t// not handling 10e10 notation...\n\n\treturn value * sign;\n}\n\n\nint _atoi( const char **stringPtr ) {\n\tint\t\tsign;\n\tint\t\tvalue;\n\tint\t\tc;\n\tconst char\t*string;\n\n\tstring = *stringPtr;\n\n\t// skip whitespace\n\twhile ( *string <= ' ' ) {\n\t\tif ( !*string ) {\n\t\t\treturn 0;\n\t\t}\n\t\tstring++;\n\t}\n\n\t// check sign\n\tswitch ( *string ) {\n\tcase '+':\n\t\tstring++;\n\t\tsign = 1;\n\t\tbreak;\n\tcase '-':\n\t\tstring++;\n\t\tsign = -1;\n\t\tbreak;\n\tdefault:\n\t\tsign = 1;\n\t\tbreak;\n\t}\n\n\t// read digits\n\tvalue = 0;\n\tdo {\n\t\tc = *string++;\n\t\tif ( c < '0' || c > '9' ) {\n\t\t\tbreak;\n\t\t}\n\t\tc -= '0';\n\t\tvalue = value * 10 + c;\n\t} while ( 1 );\n\n\t// not handling 10e10 notation...\n\n\t*stringPtr = string;\n\n\treturn value * sign;\n}\n\nint abs( int n ) {\n\treturn n < 0 ? -n : n;\n}\n\ndouble fabs( double x ) {\n\treturn x < 0 ? -x : x;\n}\n\n\n\n//=========================================================\n\n\n#define ALT\t\t\t0x00000001\t\t/* alternate form */\n#define HEXPREFIX\t0x00000002\t\t/* add 0x or 0X prefix */\n#define LADJUST\t\t0x00000004\t\t/* left adjustment */\n#define LONGDBL\t\t0x00000008\t\t/* long double */\n#define LONGINT\t\t0x00000010\t\t/* long integer */\n#define QUADINT\t\t0x00000020\t\t/* quad integer */\n#define SHORTINT\t0x00000040\t\t/* short integer */\n#define ZEROPAD\t\t0x00000080\t\t/* zero (as opposed to blank) pad */\n#define FPT\t\t\t0x00000100\t\t/* floating point number */\n\n#define to_digit(c)\t\t((c) - '0')\n#define is_digit(c)\t\t((unsigned)to_digit(c) <= 9)\n#define to_char(n)\t\t((n) + '0')\n\nvoid AddInt( char **buf_p, int val, int width, int flags ) {\n\tchar\ttext[32];\n\tint\t\tdigits;\n\tint\t\tsignedVal;\n\tchar\t*buf;\n\n\tdigits = 0;\n\tsignedVal = val;\n\tif ( val < 0 ) {\n\t\tval = -val;\n\t}\n\tdo {\n\t\ttext[digits++] = '0' + val % 10;\n\t\tval /= 10;\n\t} while ( val );\n\n\tif ( signedVal < 0 ) {\n\t\ttext[digits++] = '-';\n\t}\n\n\tbuf = *buf_p;\n\n\tif( !( flags & LADJUST ) ) {\n\t\twhile ( digits < width ) {\n\t\t\t*buf++ = ( flags & ZEROPAD ) ? '0' : ' ';\n\t\t\twidth--;\n\t\t}\n\t}\n\n\twhile ( digits-- ) {\n\t\t*buf++ = text[digits];\n\t\twidth--;\n\t}\n\n\tif( flags & LADJUST ) {\n\t\twhile ( width-- ) {\n\t\t\t*buf++ = ( flags & ZEROPAD ) ? '0' : ' ';\n\t\t}\n\t}\n\n\t*buf_p = buf;\n}\n\nvoid AddFloat( char **buf_p, float fval, int width, int prec ) {\n\tchar\ttext[32];\n\tint\t\tdigits;\n\tfloat\tsignedVal;\n\tchar\t*buf;\n\tint\t\tval;\n\n\t// get the sign\n\tsignedVal = fval;\n\tif ( fval < 0 ) {\n\t\tfval = -fval;\n\t}\n\n\t// write the float number\n\tdigits = 0;\n\tval = (int)fval;\n\tdo {\n\t\ttext[digits++] = '0' + val % 10;\n\t\tval /= 10;\n\t} while ( val );\n\n\tif ( signedVal < 0 ) {\n\t\ttext[digits++] = '-';\n\t}\n\n\tbuf = *buf_p;\n\n\twhile ( digits < width ) {\n\t\t*buf++ = ' ';\n\t\twidth--;\n\t}\n\n\twhile ( digits-- ) {\n\t\t*buf++ = text[digits];\n\t}\n\n\t*buf_p = buf;\n\n\tif (prec < 0)\n\t\tprec = 6;\n\t// write the fraction\n\tdigits = 0;\n\twhile (digits < prec) {\n\t\tfval -= (int) fval;\n\t\tfval *= 10.0;\n\t\tval = (int) fval;\n\t\ttext[digits++] = '0' + val % 10;\n\t}\n\n\tif (digits > 0) {\n\t\tbuf = *buf_p;\n\t\t*buf++ = '.';\n\t\tfor (prec = 0; prec < digits; prec++) {\n\t\t\t*buf++ = text[prec];\n\t\t}\n\t\t*buf_p = buf;\n\t}\n}\n\n\nvoid AddString( char **buf_p, char *string, int width, int prec ) {\n\tint\t\tsize;\n\tchar\t*buf;\n\n\tbuf = *buf_p;\n\n\tif ( string == NULL ) {\n\t\tstring = \"(null)\";\n\t\tprec = -1;\n\t}\n\n\tif ( prec >= 0 ) {\n\t\tfor( size = 0; size < prec; size++ ) {\n\t\t\tif( string[size] == '\\0' ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\telse {\n\t\tsize = strlen( string );\n\t}\n\n\twidth -= size;\n\n\twhile( size-- ) {\n\t\t*buf++ = *string++;\n\t}\n\n\twhile( width-- > 0 ) {\n\t\t*buf++ = ' ';\n\t}\n\n\t*buf_p = buf;\n}\n\n/*\nvsprintf\n\nI'm not going to support a bunch of the more arcane stuff in here\njust to keep it simpler.  For example, the '*' and '$' are not\ncurrently supported.  I've tried to make it so that it will just\nparse and ignore formats we don't support.\n*/\nint vsprintf( char *buffer, const char *fmt, va_list argptr ) {\n\tint\t\t*arg;\n\tchar\t*buf_p;\n\tchar\tch;\n\tint\t\tflags;\n\tint\t\twidth;\n\tint\t\tprec;\n\tint\t\tn;\n\tchar\tsign;\n\n\tbuf_p = buffer;\n\targ = (int *)argptr;\n\n\twhile( qtrue ) {\n\t\t// run through the format string until we hit a '%' or '\\0'\n\t\tfor ( ch = *fmt; (ch = *fmt) != '\\0' && ch != '%'; fmt++ ) {\n\t\t\t*buf_p++ = ch;\n\t\t}\n\t\tif ( ch == '\\0' ) {\n\t\t\tgoto done;\n\t\t}\n\n\t\t// skip over the '%'\n\t\tfmt++;\n\n\t\t// reset formatting state\n\t\tflags = 0;\n\t\twidth = 0;\n\t\tprec = -1;\n\t\tsign = '\\0';\n\nrflag:\n\t\tch = *fmt++;\nreswitch:\n\t\tswitch( ch ) {\n\t\tcase '-':\n\t\t\tflags |= LADJUST;\n\t\t\tgoto rflag;\n\t\tcase '.':\n\t\t\tn = 0;\n\t\t\twhile( is_digit( ( ch = *fmt++ ) ) ) {\n\t\t\t\tn = 10 * n + ( ch - '0' );\n\t\t\t}\n\t\t\tprec = n < 0 ? -1 : n;\n\t\t\tgoto reswitch;\n\t\tcase '0':\n\t\t\tflags |= ZEROPAD;\n\t\t\tgoto rflag;\n\t\tcase '1':\n\t\tcase '2':\n\t\tcase '3':\n\t\tcase '4':\n\t\tcase '5':\n\t\tcase '6':\n\t\tcase '7':\n\t\tcase '8':\n\t\tcase '9':\n\t\t\tn = 0;\n\t\t\tdo {\n\t\t\t\tn = 10 * n + ( ch - '0' );\n\t\t\t\tch = *fmt++;\n\t\t\t} while( is_digit( ch ) );\n\t\t\twidth = n;\n\t\t\tgoto reswitch;\n\t\tcase 'c':\n\t\t\t*buf_p++ = (char)*arg;\n\t\t\targ++;\n\t\t\tbreak;\n\t\tcase 'd':\n\t\tcase 'i':\n\t\t\tAddInt( &buf_p, *arg, width, flags );\n\t\t\targ++;\n\t\t\tbreak;\n\t\tcase 'f':\n\t\t\tAddFloat( &buf_p, *(double *)arg, width, prec );\n#ifdef __LCC__\n\t\t\targ += 1;\t// everything is 32 bit in my compiler\n#else\n\t\t\targ += 2;\n#endif\n\t\t\tbreak;\n\t\tcase 's':\n\t\t\tAddString( &buf_p, (char *)*arg, width, prec );\n\t\t\targ++;\n\t\t\tbreak;\n\t\tcase '%':\n\t\t\t*buf_p++ = ch;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\t*buf_p++ = (char)*arg;\n\t\t\targ++;\n\t\t\tbreak;\n\t\t}\n\t}\n\ndone:\n\t*buf_p = 0;\n\treturn buf_p - buffer;\n}\n\n/* this is really crappy */\nint sscanf( const char *buffer, const char *fmt, ... ) {\n\tint\t\tcmd;\n\tint\t\t**arg;\n\tint\t\tcount;\n\n\targ = (int **)&fmt + 1;\n\tcount = 0;\n\n\twhile ( *fmt ) {\n\t\tif ( fmt[0] != '%' ) {\n\t\t\tfmt++;\n\t\t\tcontinue;\n\t\t}\n\n\t\tcmd = fmt[1];\n\t\tfmt += 2;\n\n\t\tswitch ( cmd ) {\n\t\tcase 'i':\n\t\tcase 'd':\n\t\tcase 'u':\n\t\t\t**arg = _atoi( &buffer );\n\t\t\tbreak;\n\t\tcase 'f':\n\t\t\t*(float *)*arg = _atof( &buffer );\n\t\t\tbreak;\n\t\t}\n\t\targ++;\n\t}\n\n\treturn count;\n}\n\n#endif\n"
  },
  {
    "path": "src/game/bg_lib.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n// bg_lib.h -- standard C library replacement routines used by code\n// compiled for the virtual machine\n\n// This file is NOT included on native builds\n\ntypedef int size_t;\n\ntypedef char *  va_list;\n#define _INTSIZEOF(n)   ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )\n#define va_start(ap,v)  ( ap = (va_list)&v + _INTSIZEOF(v) )\n#define va_arg(ap,t)    ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )\n#define va_end(ap)      ( ap = (va_list)0 )\n\n#define CHAR_BIT      8         /* number of bits in a char */\n#define SCHAR_MIN   (-128)      /* minimum signed char value */\n#define SCHAR_MAX     127       /* maximum signed char value */\n#define UCHAR_MAX     0xff      /* maximum unsigned char value */\n\n#define SHRT_MIN    (-32768)        /* minimum (signed) short value */\n#define SHRT_MAX      32767         /* maximum (signed) short value */\n#define USHRT_MAX     0xffff        /* maximum unsigned short value */\n#define INT_MIN     (-2147483647 - 1) /* minimum (signed) int value */\n#define INT_MAX       2147483647    /* maximum (signed) int value */\n#define UINT_MAX      0xffffffff    /* maximum unsigned int value */\n#define LONG_MIN    (-2147483647L - 1) /* minimum (signed) long value */\n#define LONG_MAX      2147483647L   /* maximum (signed) long value */\n#define ULONG_MAX     0xffffffffUL  /* maximum unsigned long value */\n\n// Misc functions\ntypedef int cmp_t(const void *, const void *);\nvoid qsort(void *a, size_t n, size_t es, cmp_t *cmp);\nvoid\tsrand( unsigned seed );\nint\t\trand( void );\n\n// String functions\nint strlen( const char *string );\nchar *strcat( char *strDestination, const char *strSource );\nchar *strcpy( char *strDestination, const char *strSource );\nint strcmp( const char *string1, const char *string2 );\nchar *strchr( const char *string, int c );\nchar *strstr( const char *string, const char *strCharSet );\nchar *strncpy( char *strDest, const char *strSource, size_t count );\nint tolower( int c );\nint toupper( int c );\n\ndouble atof( const char *string );\ndouble _atof( const char **stringPtr );\nint atoi( const char *string );\nint _atoi( const char **stringPtr );\n\nint vsprintf( char *buffer, const char *fmt, va_list argptr );\nint sscanf( const char *buffer, const char *fmt, ... );\n\n// Memory functions\nvoid *memmove( void *dest, const void *src, size_t count );\nvoid *memset( void *dest, int c, size_t count );\nvoid *memcpy( void *dest, const void *src, size_t count );\n\n// Math functions\ndouble ceil( double x );\ndouble floor( double x );\ndouble sqrt( double x );\ndouble sin( double x );\ndouble cos( double x );\ndouble atan2( double y, double x );\ndouble tan( double x );\nint abs( int n );\ndouble fabs( double x );\ndouble acos( double x );\n\n"
  },
  {
    "path": "src/game/bg_local.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n// bg_local.h -- local definitions for the bg (both games) files\n\n#define\tMIN_WALK_NORMAL\t0.7f\t\t// can't walk on very steep slopes\n\n#define\tSTEPSIZE\t\t18\n\n#define\tJUMP_VELOCITY\t270\n\n#define\tTIMER_LAND\t\t130\n#define\tTIMER_GESTURE\t(34*66+50)\n\n#define\tOVERCLIP\t\t1.001f\n\n// all of the locals will be zeroed before each\n// pmove, just to make damn sure we don't have\n// any differences when running on client or server\ntypedef struct {\n\tvec3_t\t\tforward, right, up;\n\tfloat\t\tframetime;\n\n\tint\t\t\tmsec;\n\n\tqboolean\twalking;\n\tqboolean\tgroundPlane;\n\ttrace_t\t\tgroundTrace;\n\n\tfloat\t\timpactSpeed;\n\n\tvec3_t\t\tprevious_origin;\n\tvec3_t\t\tprevious_velocity;\n\tint\t\t\tprevious_waterlevel;\n} pml_t;\n\nextern\tpmove_t\t\t*pm;\nextern\tpml_t\t\tpml;\n\n// movement parameters\nextern\tfloat\tpm_stopspeed;\nextern\tfloat\tpm_duckScale;\nextern\tfloat\tpm_swimScale;\nextern\tfloat\tpm_wadeScale;\n\nextern\tfloat\tpm_accelerate;\nextern\tfloat\tpm_airaccelerate;\nextern\tfloat\tpm_wateraccelerate;\nextern\tfloat\tpm_flyaccelerate;\n\nextern\tfloat\tpm_friction;\nextern\tfloat\tpm_waterfriction;\nextern\tfloat\tpm_flightfriction;\n\nextern\tint\t\tc_pmove;\n\nvoid PM_ClipVelocity( vec3_t in, vec3_t normal, vec3_t out, float overbounce );\nvoid PM_AddTouchEnt( int entityNum );\nvoid PM_AddEvent( int newEvent );\n\nqboolean\tPM_SlideMove( qboolean gravity );\nvoid\t\tPM_StepSlideMove( qboolean gravity );\n\n\n"
  },
  {
    "path": "src/game/bg_misc.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n// bg_misc.c -- both games misc functions, all completely stateless\n\n#include \"q_shared.h\"\n#include \"bg_public.h\"\n\n/*QUAKED item_***** ( 0 0 0 ) (-16 -16 -16) (16 16 16) suspended\nDO NOT USE THIS CLASS, IT JUST HOLDS GENERAL INFORMATION.\nThe suspended flag will allow items to hang in the air, otherwise they are dropped to the next surface.\n\nIf an item is the target of another entity, it will not spawn in until fired.\n\nAn item fires all of its targets when it is picked up.  If the toucher can't carry it, the targets won't be fired.\n\n\"notfree\" if set to 1, don't spawn in free for all games\n\"notteam\" if set to 1, don't spawn in team games\n\"notsingle\" if set to 1, don't spawn in single player games\n\"wait\"\toverride the default wait before respawning.  -1 = never respawn automatically, which can be used with targeted spawning.\n\"random\" random number of plus or minus seconds varied from the respawn time\n\"count\" override quantity or duration on most items.\n*/\n\ngitem_t\tbg_itemlist[] = \n{\n\t{\n\t\tNULL,\n\t\tNULL,\n\t\t{ NULL,\n\t\tNULL,\n\t\t0, 0} ,\n/* icon */\t\tNULL,\n/* pickup */\tNULL,\n\t\t0,\n\t\t0,\n\t\t0,\n/* precache */ \"\",\n/* sounds */ \"\"\n\t},\t// leave index 0 alone\n\n\t//\n\t// ARMOR\n\t//\n\n/*QUAKED item_armor_shard (.3 .3 1) (-16 -16 -16) (16 16 16) suspended\n*/\n\t{\n\t\t\"item_armor_shard\", \n\t\t\"sound/misc/ar1_pkup.wav\",\n\t\t{ \"models/powerups/armor/shard.md3\", \n\t\t\"models/powerups/armor/shard_sphere.md3\",\n\t\t0, 0} ,\n/* icon */\t\t\"icons/iconr_shard\",\n/* pickup */\t\"Armor Shard\",\n\t\t5,\n\t\tIT_ARMOR,\n\t\t0,\n/* precache */ \"\",\n/* sounds */ \"\"\n\t},\n\n/*QUAKED item_armor_combat (.3 .3 1) (-16 -16 -16) (16 16 16) suspended\n*/\n\t{\n\t\t\"item_armor_combat\", \n\t\t\"sound/misc/ar2_pkup.wav\",\n        { \"models/powerups/armor/armor_yel.md3\",\n\t\t0, 0, 0},\n/* icon */\t\t\"icons/iconr_yellow\",\n/* pickup */\t\"Armor\",\n\t\t50,\n\t\tIT_ARMOR,\n\t\t0,\n/* precache */ \"\",\n/* sounds */ \"\"\n\t},\n\n/*QUAKED item_armor_body (.3 .3 1) (-16 -16 -16) (16 16 16) suspended\n*/\n\t{\n\t\t\"item_armor_body\", \n\t\t\"sound/misc/ar2_pkup.wav\",\n        { \"models/powerups/armor/armor_red.md3\",\n\t\t0, 0, 0},\n/* icon */\t\t\"icons/iconr_red\",\n/* pickup */\t\"Heavy Armor\",\n\t\t100,\n\t\tIT_ARMOR,\n\t\t0,\n/* precache */ \"\",\n/* sounds */ \"\"\n\t},\n\n\t//\n\t// health\n\t//\n/*QUAKED item_health_small (.3 .3 1) (-16 -16 -16) (16 16 16) suspended\n*/\n\t{\n\t\t\"item_health_small\",\n\t\t\"sound/items/s_health.wav\",\n        { \"models/powerups/health/small_cross.md3\", \n\t\t\"models/powerups/health/small_sphere.md3\", \n\t\t0, 0 },\n/* icon */\t\t\"icons/iconh_green\",\n/* pickup */\t\"5 Health\",\n\t\t5,\n\t\tIT_HEALTH,\n\t\t0,\n/* precache */ \"\",\n/* sounds */ \"\"\n\t},\n\n/*QUAKED item_health (.3 .3 1) (-16 -16 -16) (16 16 16) suspended\n*/\n\t{\n\t\t\"item_health\",\n\t\t\"sound/items/n_health.wav\",\n        { \"models/powerups/health/medium_cross.md3\", \n\t\t\"models/powerups/health/medium_sphere.md3\", \n\t\t0, 0 },\n/* icon */\t\t\"icons/iconh_yellow\",\n/* pickup */\t\"25 Health\",\n\t\t25,\n\t\tIT_HEALTH,\n\t\t0,\n/* precache */ \"\",\n/* sounds */ \"\"\n\t},\n\n/*QUAKED item_health_large (.3 .3 1) (-16 -16 -16) (16 16 16) suspended\n*/\n\t{\n\t\t\"item_health_large\",\n\t\t\"sound/items/l_health.wav\",\n        { \"models/powerups/health/large_cross.md3\", \n\t\t\"models/powerups/health/large_sphere.md3\", \n\t\t0, 0 },\n/* icon */\t\t\"icons/iconh_red\",\n/* pickup */\t\"50 Health\",\n\t\t50,\n\t\tIT_HEALTH,\n\t\t0,\n/* precache */ \"\",\n/* sounds */ \"\"\n\t},\n\n/*QUAKED item_health_mega (.3 .3 1) (-16 -16 -16) (16 16 16) suspended\n*/\n\t{\n\t\t\"item_health_mega\",\n\t\t\"sound/items/m_health.wav\",\n        { \"models/powerups/health/mega_cross.md3\", \n\t\t\"models/powerups/health/mega_sphere.md3\", \n\t\t0, 0 },\n/* icon */\t\t\"icons/iconh_mega\",\n/* pickup */\t\"Mega Health\",\n\t\t100,\n\t\tIT_HEALTH,\n\t\t0,\n/* precache */ \"\",\n/* sounds */ \"\"\n\t},\n\n\n\t//\n\t// WEAPONS \n\t//\n\n/*QUAKED weapon_gauntlet (.3 .3 1) (-16 -16 -16) (16 16 16) suspended\n*/\n\t{\n\t\t\"weapon_gauntlet\", \n\t\t\"sound/misc/w_pkup.wav\",\n        { \"models/weapons2/gauntlet/gauntlet.md3\",\n\t\t0, 0, 0},\n/* icon */\t\t\"icons/iconw_gauntlet\",\n/* pickup */\t\"Gauntlet\",\n\t\t0,\n\t\tIT_WEAPON,\n\t\tWP_GAUNTLET,\n/* precache */ \"\",\n/* sounds */ \"\"\n\t},\n\n/*QUAKED weapon_shotgun (.3 .3 1) (-16 -16 -16) (16 16 16) suspended\n*/\n\t{\n\t\t\"weapon_shotgun\", \n\t\t\"sound/misc/w_pkup.wav\",\n        { \"models/weapons2/shotgun/shotgun.md3\", \n\t\t0, 0, 0},\n/* icon */\t\t\"icons/iconw_shotgun\",\n/* pickup */\t\"Shotgun\",\n\t\t10,\n\t\tIT_WEAPON,\n\t\tWP_SHOTGUN,\n/* precache */ \"\",\n/* sounds */ \"\"\n\t},\n\n/*QUAKED weapon_machinegun (.3 .3 1) (-16 -16 -16) (16 16 16) suspended\n*/\n\t{\n\t\t\"weapon_machinegun\", \n\t\t\"sound/misc/w_pkup.wav\",\n        { \"models/weapons2/machinegun/machinegun.md3\", \n\t\t0, 0, 0},\n/* icon */\t\t\"icons/iconw_machinegun\",\n/* pickup */\t\"Machinegun\",\n\t\t40,\n\t\tIT_WEAPON,\n\t\tWP_MACHINEGUN,\n/* precache */ \"\",\n/* sounds */ \"\"\n\t},\n\n/*QUAKED weapon_grenadelauncher (.3 .3 1) (-16 -16 -16) (16 16 16) suspended\n*/\n\t{\n\t\t\"weapon_grenadelauncher\",\n\t\t\"sound/misc/w_pkup.wav\",\n        { \"models/weapons2/grenadel/grenadel.md3\", \n\t\t0, 0, 0},\n/* icon */\t\t\"icons/iconw_grenade\",\n/* pickup */\t\"Grenade Launcher\",\n\t\t10,\n\t\tIT_WEAPON,\n\t\tWP_GRENADE_LAUNCHER,\n/* precache */ \"\",\n/* sounds */ \"sound/weapons/grenade/hgrenb1a.wav sound/weapons/grenade/hgrenb2a.wav\"\n\t},\n\n/*QUAKED weapon_rocketlauncher (.3 .3 1) (-16 -16 -16) (16 16 16) suspended\n*/\n\t{\n\t\t\"weapon_rocketlauncher\",\n\t\t\"sound/misc/w_pkup.wav\",\n        { \"models/weapons2/rocketl/rocketl.md3\", \n\t\t0, 0, 0},\n/* icon */\t\t\"icons/iconw_rocket\",\n/* pickup */\t\"Rocket Launcher\",\n\t\t10,\n\t\tIT_WEAPON,\n\t\tWP_ROCKET_LAUNCHER,\n/* precache */ \"\",\n/* sounds */ \"\"\n\t},\n\n/*QUAKED weapon_lightning (.3 .3 1) (-16 -16 -16) (16 16 16) suspended\n*/\n\t{\n\t\t\"weapon_lightning\", \n\t\t\"sound/misc/w_pkup.wav\",\n        { \"models/weapons2/lightning/lightning.md3\", \n\t\t0, 0, 0},\n/* icon */\t\t\"icons/iconw_lightning\",\n/* pickup */\t\"Lightning Gun\",\n\t\t100,\n\t\tIT_WEAPON,\n\t\tWP_LIGHTNING,\n/* precache */ \"\",\n/* sounds */ \"\"\n\t},\n\n/*QUAKED weapon_railgun (.3 .3 1) (-16 -16 -16) (16 16 16) suspended\n*/\n\t{\n\t\t\"weapon_railgun\", \n\t\t\"sound/misc/w_pkup.wav\",\n        { \"models/weapons2/railgun/railgun.md3\", \n\t\t0, 0, 0},\n/* icon */\t\t\"icons/iconw_railgun\",\n/* pickup */\t\"Railgun\",\n\t\t10,\n\t\tIT_WEAPON,\n\t\tWP_RAILGUN,\n/* precache */ \"\",\n/* sounds */ \"\"\n\t},\n\n/*QUAKED weapon_plasmagun (.3 .3 1) (-16 -16 -16) (16 16 16) suspended\n*/\n\t{\n\t\t\"weapon_plasmagun\", \n\t\t\"sound/misc/w_pkup.wav\",\n        { \"models/weapons2/plasma/plasma.md3\", \n\t\t0, 0, 0},\n/* icon */\t\t\"icons/iconw_plasma\",\n/* pickup */\t\"Plasma Gun\",\n\t\t50,\n\t\tIT_WEAPON,\n\t\tWP_PLASMAGUN,\n/* precache */ \"\",\n/* sounds */ \"\"\n\t},\n\n/*QUAKED weapon_bfg (.3 .3 1) (-16 -16 -16) (16 16 16) suspended\n*/\n\t{\n\t\t\"weapon_bfg\",\n\t\t\"sound/misc/w_pkup.wav\",\n        { \"models/weapons2/bfg/bfg.md3\", \n\t\t0, 0, 0},\n/* icon */\t\t\"icons/iconw_bfg\",\n/* pickup */\t\"BFG10K\",\n\t\t20,\n\t\tIT_WEAPON,\n\t\tWP_BFG,\n/* precache */ \"\",\n/* sounds */ \"\"\n\t},\n\n/*QUAKED weapon_grapplinghook (.3 .3 1) (-16 -16 -16) (16 16 16) suspended\n*/\n\t{\n\t\t\"weapon_grapplinghook\",\n\t\t\"sound/misc/w_pkup.wav\",\n        { \"models/weapons2/grapple/grapple.md3\", \n\t\t0, 0, 0},\n/* icon */\t\t\"icons/iconw_grapple\",\n/* pickup */\t\"Grappling Hook\",\n\t\t0,\n\t\tIT_WEAPON,\n\t\tWP_GRAPPLING_HOOK,\n/* precache */ \"\",\n/* sounds */ \"\"\n\t},\n\n\t//\n\t// AMMO ITEMS\n\t//\n\n/*QUAKED ammo_shells (.3 .3 1) (-16 -16 -16) (16 16 16) suspended\n*/\n\t{\n\t\t\"ammo_shells\",\n\t\t\"sound/misc/am_pkup.wav\",\n        { \"models/powerups/ammo/shotgunam.md3\", \n\t\t0, 0, 0},\n/* icon */\t\t\"icons/icona_shotgun\",\n/* pickup */\t\"Shells\",\n\t\t10,\n\t\tIT_AMMO,\n\t\tWP_SHOTGUN,\n/* precache */ \"\",\n/* sounds */ \"\"\n\t},\n\n/*QUAKED ammo_bullets (.3 .3 1) (-16 -16 -16) (16 16 16) suspended\n*/\n\t{\n\t\t\"ammo_bullets\",\n\t\t\"sound/misc/am_pkup.wav\",\n        { \"models/powerups/ammo/machinegunam.md3\", \n\t\t0, 0, 0},\n/* icon */\t\t\"icons/icona_machinegun\",\n/* pickup */\t\"Bullets\",\n\t\t50,\n\t\tIT_AMMO,\n\t\tWP_MACHINEGUN,\n/* precache */ \"\",\n/* sounds */ \"\"\n\t},\n\n/*QUAKED ammo_grenades (.3 .3 1) (-16 -16 -16) (16 16 16) suspended\n*/\n\t{\n\t\t\"ammo_grenades\",\n\t\t\"sound/misc/am_pkup.wav\",\n        { \"models/powerups/ammo/grenadeam.md3\", \n\t\t0, 0, 0},\n/* icon */\t\t\"icons/icona_grenade\",\n/* pickup */\t\"Grenades\",\n\t\t5,\n\t\tIT_AMMO,\n\t\tWP_GRENADE_LAUNCHER,\n/* precache */ \"\",\n/* sounds */ \"\"\n\t},\n\n/*QUAKED ammo_cells (.3 .3 1) (-16 -16 -16) (16 16 16) suspended\n*/\n\t{\n\t\t\"ammo_cells\",\n\t\t\"sound/misc/am_pkup.wav\",\n        { \"models/powerups/ammo/plasmaam.md3\", \n\t\t0, 0, 0},\n/* icon */\t\t\"icons/icona_plasma\",\n/* pickup */\t\"Cells\",\n\t\t30,\n\t\tIT_AMMO,\n\t\tWP_PLASMAGUN,\n/* precache */ \"\",\n/* sounds */ \"\"\n\t},\n\n/*QUAKED ammo_lightning (.3 .3 1) (-16 -16 -16) (16 16 16) suspended\n*/\n\t{\n\t\t\"ammo_lightning\",\n\t\t\"sound/misc/am_pkup.wav\",\n        { \"models/powerups/ammo/lightningam.md3\", \n\t\t0, 0, 0},\n/* icon */\t\t\"icons/icona_lightning\",\n/* pickup */\t\"Lightning\",\n\t\t60,\n\t\tIT_AMMO,\n\t\tWP_LIGHTNING,\n/* precache */ \"\",\n/* sounds */ \"\"\n\t},\n\n/*QUAKED ammo_rockets (.3 .3 1) (-16 -16 -16) (16 16 16) suspended\n*/\n\t{\n\t\t\"ammo_rockets\",\n\t\t\"sound/misc/am_pkup.wav\",\n        { \"models/powerups/ammo/rocketam.md3\", \n\t\t0, 0, 0},\n/* icon */\t\t\"icons/icona_rocket\",\n/* pickup */\t\"Rockets\",\n\t\t5,\n\t\tIT_AMMO,\n\t\tWP_ROCKET_LAUNCHER,\n/* precache */ \"\",\n/* sounds */ \"\"\n\t},\n\n/*QUAKED ammo_slugs (.3 .3 1) (-16 -16 -16) (16 16 16) suspended\n*/\n\t{\n\t\t\"ammo_slugs\",\n\t\t\"sound/misc/am_pkup.wav\",\n        { \"models/powerups/ammo/railgunam.md3\", \n\t\t0, 0, 0},\n/* icon */\t\t\"icons/icona_railgun\",\n/* pickup */\t\"Slugs\",\n\t\t10,\n\t\tIT_AMMO,\n\t\tWP_RAILGUN,\n/* precache */ \"\",\n/* sounds */ \"\"\n\t},\n\n/*QUAKED ammo_bfg (.3 .3 1) (-16 -16 -16) (16 16 16) suspended\n*/\n\t{\n\t\t\"ammo_bfg\",\n\t\t\"sound/misc/am_pkup.wav\",\n        { \"models/powerups/ammo/bfgam.md3\", \n\t\t0, 0, 0},\n/* icon */\t\t\"icons/icona_bfg\",\n/* pickup */\t\"Bfg Ammo\",\n\t\t15,\n\t\tIT_AMMO,\n\t\tWP_BFG,\n/* precache */ \"\",\n/* sounds */ \"\"\n\t},\n\n\t//\n\t// HOLDABLE ITEMS\n\t//\n/*QUAKED holdable_teleporter (.3 .3 1) (-16 -16 -16) (16 16 16) suspended\n*/\n\t{\n\t\t\"holdable_teleporter\", \n\t\t\"sound/items/holdable.wav\",\n        { \"models/powerups/holdable/teleporter.md3\", \n\t\t0, 0, 0},\n/* icon */\t\t\"icons/teleporter\",\n/* pickup */\t\"Personal Teleporter\",\n\t\t60,\n\t\tIT_HOLDABLE,\n\t\tHI_TELEPORTER,\n/* precache */ \"\",\n/* sounds */ \"\"\n\t},\n/*QUAKED holdable_medkit (.3 .3 1) (-16 -16 -16) (16 16 16) suspended\n*/\n\t{\n\t\t\"holdable_medkit\", \n\t\t\"sound/items/holdable.wav\",\n        { \n\t\t\"models/powerups/holdable/medkit.md3\", \n\t\t\"models/powerups/holdable/medkit_sphere.md3\",\n\t\t0, 0},\n/* icon */\t\t\"icons/medkit\",\n/* pickup */\t\"Medkit\",\n\t\t60,\n\t\tIT_HOLDABLE,\n\t\tHI_MEDKIT,\n/* precache */ \"\",\n/* sounds */ \"sound/items/use_medkit.wav\"\n\t},\n\n\t//\n\t// POWERUP ITEMS\n\t//\n/*QUAKED item_quad (.3 .3 1) (-16 -16 -16) (16 16 16) suspended\n*/\n\t{\n\t\t\"item_quad\", \n\t\t\"sound/items/quaddamage.wav\",\n        { \"models/powerups/instant/quad.md3\", \n        \"models/powerups/instant/quad_ring.md3\",\n\t\t0, 0 },\n/* icon */\t\t\"icons/quad\",\n/* pickup */\t\"Quad Damage\",\n\t\t30,\n\t\tIT_POWERUP,\n\t\tPW_QUAD,\n/* precache */ \"\",\n/* sounds */ \"sound/items/damage2.wav sound/items/damage3.wav\"\n\t},\n\n/*QUAKED item_enviro (.3 .3 1) (-16 -16 -16) (16 16 16) suspended\n*/\n\t{\n\t\t\"item_enviro\",\n\t\t\"sound/items/protect.wav\",\n        { \"models/powerups/instant/enviro.md3\", \n\t\t\"models/powerups/instant/enviro_ring.md3\", \n\t\t0, 0 },\n/* icon */\t\t\"icons/envirosuit\",\n/* pickup */\t\"Battle Suit\",\n\t\t30,\n\t\tIT_POWERUP,\n\t\tPW_BATTLESUIT,\n/* precache */ \"\",\n/* sounds */ \"sound/items/airout.wav sound/items/protect3.wav\"\n\t},\n\n/*QUAKED item_haste (.3 .3 1) (-16 -16 -16) (16 16 16) suspended\n*/\n\t{\n\t\t\"item_haste\",\n\t\t\"sound/items/haste.wav\",\n        { \"models/powerups/instant/haste.md3\", \n\t\t\"models/powerups/instant/haste_ring.md3\", \n\t\t0, 0 },\n/* icon */\t\t\"icons/haste\",\n/* pickup */\t\"Speed\",\n\t\t30,\n\t\tIT_POWERUP,\n\t\tPW_HASTE,\n/* precache */ \"\",\n/* sounds */ \"\"\n\t},\n\n/*QUAKED item_invis (.3 .3 1) (-16 -16 -16) (16 16 16) suspended\n*/\n\t{\n\t\t\"item_invis\",\n\t\t\"sound/items/invisibility.wav\",\n        { \"models/powerups/instant/invis.md3\", \n\t\t\"models/powerups/instant/invis_ring.md3\", \n\t\t0, 0 },\n/* icon */\t\t\"icons/invis\",\n/* pickup */\t\"Invisibility\",\n\t\t30,\n\t\tIT_POWERUP,\n\t\tPW_INVIS,\n/* precache */ \"\",\n/* sounds */ \"\"\n\t},\n\n/*QUAKED item_regen (.3 .3 1) (-16 -16 -16) (16 16 16) suspended\n*/\n\t{\n\t\t\"item_regen\",\n\t\t\"sound/items/regeneration.wav\",\n        { \"models/powerups/instant/regen.md3\", \n\t\t\"models/powerups/instant/regen_ring.md3\", \n\t\t0, 0 },\n/* icon */\t\t\"icons/regen\",\n/* pickup */\t\"Regeneration\",\n\t\t30,\n\t\tIT_POWERUP,\n\t\tPW_REGEN,\n/* precache */ \"\",\n/* sounds */ \"sound/items/regen.wav\"\n\t},\n\n/*QUAKED item_flight (.3 .3 1) (-16 -16 -16) (16 16 16) suspended\n*/\n\t{\n\t\t\"item_flight\",\n\t\t\"sound/items/flight.wav\",\n        { \"models/powerups/instant/flight.md3\", \n\t\t\"models/powerups/instant/flight_ring.md3\", \n\t\t0, 0 },\n/* icon */\t\t\"icons/flight\",\n/* pickup */\t\"Flight\",\n\t\t60,\n\t\tIT_POWERUP,\n\t\tPW_FLIGHT,\n/* precache */ \"\",\n/* sounds */ \"sound/items/flight.wav\"\n\t},\n\n/*QUAKED team_CTF_redflag (1 0 0) (-16 -16 -16) (16 16 16)\nOnly in CTF games\n*/\n\t{\n\t\t\"team_CTF_redflag\",\n\t\tNULL,\n        { \"models/flags/r_flag.md3\",\n\t\t0, 0, 0 },\n/* icon */\t\t\"icons/iconf_red1\",\n/* pickup */\t\"Red Flag\",\n\t\t0,\n\t\tIT_TEAM,\n\t\tPW_REDFLAG,\n/* precache */ \"\",\n/* sounds */ \"\"\n\t},\n\n/*QUAKED team_CTF_blueflag (0 0 1) (-16 -16 -16) (16 16 16)\nOnly in CTF games\n*/\n\t{\n\t\t\"team_CTF_blueflag\",\n\t\tNULL,\n        { \"models/flags/b_flag.md3\",\n\t\t0, 0, 0 },\n/* icon */\t\t\"icons/iconf_blu1\",\n/* pickup */\t\"Blue Flag\",\n\t\t0,\n\t\tIT_TEAM,\n\t\tPW_BLUEFLAG,\n/* precache */ \"\",\n/* sounds */ \"\"\n\t},\n\n\t// end of list marker\n\t{NULL}\n};\n\nint\t\tbg_numItems = sizeof(bg_itemlist) / sizeof(bg_itemlist[0]) - 1;\n\n\n/*\n==============\nBG_FindItemForPowerup\n==============\n*/\ngitem_t\t*BG_FindItemForPowerup( powerup_t pw ) {\n\tint\t\ti;\n\n\tfor ( i = 0 ; i < bg_numItems ; i++ ) {\n\t\tif ( (bg_itemlist[i].giType == IT_POWERUP || \n\t\t\t\t\tbg_itemlist[i].giType == IT_TEAM ||\n\t\t\t\t\tbg_itemlist[i].giType == IT_PERSISTANT_POWERUP) && \n\t\t\tbg_itemlist[i].giTag == pw ) {\n\t\t\treturn &bg_itemlist[i];\n\t\t}\n\t}\n\n\treturn NULL;\n}\n\n\n/*\n==============\nBG_FindItemForHoldable\n==============\n*/\ngitem_t\t*BG_FindItemForHoldable( holdable_t pw ) {\n\tint\t\ti;\n\n\tfor ( i = 0 ; i < bg_numItems ; i++ ) {\n\t\tif ( bg_itemlist[i].giType == IT_HOLDABLE && bg_itemlist[i].giTag == pw ) {\n\t\t\treturn &bg_itemlist[i];\n\t\t}\n\t}\n\n\tCom_Error( ERR_DROP, \"HoldableItem not found\" );\n\n\treturn NULL;\n}\n\n\n/*\n===============\nBG_FindItemForWeapon\n\n===============\n*/\ngitem_t\t*BG_FindItemForWeapon( weapon_t weapon ) {\n\tgitem_t\t*it;\n\t\n\tfor ( it = bg_itemlist + 1 ; it->classname ; it++) {\n\t\tif ( it->giType == IT_WEAPON && it->giTag == weapon ) {\n\t\t\treturn it;\n\t\t}\n\t}\n\n\tCom_Error( ERR_DROP, \"Couldn't find item for weapon %i\", weapon);\n\treturn NULL;\n}\n\n/*\n===============\nBG_FindItem\n\n===============\n*/\ngitem_t\t*BG_FindItem( const char *pickupName ) {\n\tgitem_t\t*it;\n\t\n\tfor ( it = bg_itemlist + 1 ; it->classname ; it++ ) {\n\t\tif ( !Q_stricmp( it->pickup_name, pickupName ) )\n\t\t\treturn it;\n\t}\n\n\treturn NULL;\n}\n\n/*\n============\nBG_PlayerTouchesItem\n\nItems can be picked up without actually touching their physical bounds to make\ngrabbing them easier\n============\n*/\nqboolean\tBG_PlayerTouchesItem( playerState_t *ps, entityState_t *item, int atTime ) {\n\tvec3_t\t\torigin;\n\n\tBG_EvaluateTrajectory( &item->pos, atTime, origin );\n\n\t// we are ignoring ducked differences here\n\tif ( ps->origin[0] - origin[0] > 44\n\t\t|| ps->origin[0] - origin[0] < -50\n\t\t|| ps->origin[1] - origin[1] > 36\n\t\t|| ps->origin[1] - origin[1] < -36\n\t\t|| ps->origin[2] - origin[2] > 36\n\t\t|| ps->origin[2] - origin[2] < -36 ) {\n\t\treturn qfalse;\n\t}\n\n\treturn qtrue;\n}\n\n\n\n/*\n================\nBG_CanItemBeGrabbed\n\nReturns false if the item should not be picked up.\nThis needs to be the same for client side prediction and server use.\n================\n*/\nqboolean BG_CanItemBeGrabbed( int gametype, const entityState_t *ent, const playerState_t *ps ) {\n\tgitem_t\t*item;\n\n\tif ( ent->modelindex < 1 || ent->modelindex >= bg_numItems ) {\n\t\tCom_Error( ERR_DROP, \"BG_CanItemBeGrabbed: index out of range\" );\n\t}\n\n\titem = &bg_itemlist[ent->modelindex];\n\n\tswitch( item->giType ) {\n\tcase IT_WEAPON:\n\t\treturn qtrue;\t// weapons are always picked up\n\n\tcase IT_AMMO:\n\t\tif ( ps->ammo[ item->giTag ] >= 200 ) {\n\t\t\treturn qfalse;\t\t// can't hold any more\n\t\t}\n\t\treturn qtrue;\n\n\tcase IT_ARMOR:\n\t\tif ( ps->stats[STAT_ARMOR] >= ps->stats[STAT_MAX_HEALTH] * 2 ) {\n\t\t\treturn qfalse;\n\t\t}\n\t\treturn qtrue;\n\n\tcase IT_HEALTH:\n\t\t// small and mega healths will go over the max, otherwise\n\t\t// don't pick up if already at max\n\t\tif ( item->quantity == 5 || item->quantity == 100 ) {\n\t\t\tif ( ps->stats[STAT_HEALTH] >= ps->stats[STAT_MAX_HEALTH] * 2 ) {\n\t\t\t\treturn qfalse;\n\t\t\t}\n\t\t\treturn qtrue;\n\t\t}\n\n\t\tif ( ps->stats[STAT_HEALTH] >= ps->stats[STAT_MAX_HEALTH] ) {\n\t\t\treturn qfalse;\n\t\t}\n\t\treturn qtrue;\n\n\tcase IT_POWERUP:\n\t\treturn qtrue;\t// powerups are always picked up\n\n\tcase IT_TEAM: // team items, such as flags\n\t\tif( gametype == GT_CTF ) {\n\t\t\t// ent->modelindex2 is non-zero on items if they are dropped\n\t\t\t// we need to know this because we can pick up our dropped flag (and return it)\n\t\t\t// but we can't pick up our flag at base\n\t\t\tif (ps->persistant[PERS_TEAM] == TEAM_RED) {\n\t\t\t\tif (item->giTag == PW_BLUEFLAG ||\n\t\t\t\t\t(item->giTag == PW_REDFLAG && ent->modelindex2) ||\n\t\t\t\t\t(item->giTag == PW_REDFLAG && ps->powerups[PW_BLUEFLAG]) )\n\t\t\t\t\treturn qtrue;\n\t\t\t} else if (ps->persistant[PERS_TEAM] == TEAM_BLUE) {\n\t\t\t\tif (item->giTag == PW_REDFLAG ||\n\t\t\t\t\t(item->giTag == PW_BLUEFLAG && ent->modelindex2) ||\n\t\t\t\t\t(item->giTag == PW_BLUEFLAG && ps->powerups[PW_REDFLAG]) )\n\t\t\t\t\treturn qtrue;\n\t\t\t}\n\t\t}\n\n\t\treturn qfalse;\n\n\tcase IT_HOLDABLE:\n\t\t// can only hold one item at a time\n\t\tif ( ps->stats[STAT_HOLDABLE_ITEM] ) {\n\t\t\treturn qfalse;\n\t\t}\n\t\treturn qtrue;\n\n        case IT_BAD:\n            Com_Error( ERR_DROP, \"BG_CanItemBeGrabbed: IT_BAD\" );\n        default:\n#ifndef Q3_VM\n#ifndef NDEBUG // bk0001204\n          Com_Printf(\"BG_CanItemBeGrabbed: unknown enum %d\\n\", item->giType );\n#endif\n#endif\n         break;\n\t}\n\n\treturn qfalse;\n}\n\n//======================================================================\n\n/*\n================\nBG_EvaluateTrajectory\n\n================\n*/\nvoid BG_EvaluateTrajectory( const trajectory_t *tr, int atTime, vec3_t result ) {\n\tfloat\t\tdeltaTime;\n\tfloat\t\tphase;\n\n\tswitch( tr->trType ) {\n\tcase TR_STATIONARY:\n\tcase TR_INTERPOLATE:\n\t\tVectorCopy( tr->trBase, result );\n\t\tbreak;\n\tcase TR_LINEAR:\n\t\tdeltaTime = ( atTime - tr->trTime ) * 0.001;\t// milliseconds to seconds\n\t\tVectorMA( tr->trBase, deltaTime, tr->trDelta, result );\n\t\tbreak;\n\tcase TR_SINE:\n\t\tdeltaTime = ( atTime - tr->trTime ) / (float) tr->trDuration;\n\t\tphase = sin( deltaTime * M_PI * 2 );\n\t\tVectorMA( tr->trBase, phase, tr->trDelta, result );\n\t\tbreak;\n\tcase TR_LINEAR_STOP:\n\t\tif ( atTime > tr->trTime + tr->trDuration ) {\n\t\t\tatTime = tr->trTime + tr->trDuration;\n\t\t}\n\t\tdeltaTime = ( atTime - tr->trTime ) * 0.001;\t// milliseconds to seconds\n\t\tif ( deltaTime < 0 ) {\n\t\t\tdeltaTime = 0;\n\t\t}\n\t\tVectorMA( tr->trBase, deltaTime, tr->trDelta, result );\n\t\tbreak;\n\tcase TR_GRAVITY:\n\t\tdeltaTime = ( atTime - tr->trTime ) * 0.001;\t// milliseconds to seconds\n\t\tVectorMA( tr->trBase, deltaTime, tr->trDelta, result );\n\t\tresult[2] -= 0.5 * DEFAULT_GRAVITY * deltaTime * deltaTime;\t\t// FIXME: local gravity...\n\t\tbreak;\n\tdefault:\n\t\tCom_Error( ERR_DROP, \"BG_EvaluateTrajectory: unknown trType: %i\", tr->trTime );\n\t\tbreak;\n\t}\n}\n\n/*\n================\nBG_EvaluateTrajectoryDelta\n\nFor determining velocity at a given time\n================\n*/\nvoid BG_EvaluateTrajectoryDelta( const trajectory_t *tr, int atTime, vec3_t result ) {\n\tfloat\tdeltaTime;\n\tfloat\tphase;\n\n\tswitch( tr->trType ) {\n\tcase TR_STATIONARY:\n\tcase TR_INTERPOLATE:\n\t\tVectorClear( result );\n\t\tbreak;\n\tcase TR_LINEAR:\n\t\tVectorCopy( tr->trDelta, result );\n\t\tbreak;\n\tcase TR_SINE:\n\t\tdeltaTime = ( atTime - tr->trTime ) / (float) tr->trDuration;\n\t\tphase = cos( deltaTime * M_PI * 2 );\t// derivative of sin = cos\n\t\tphase *= 0.5;\n\t\tVectorScale( tr->trDelta, phase, result );\n\t\tbreak;\n\tcase TR_LINEAR_STOP:\n\t\tif ( atTime > tr->trTime + tr->trDuration ) {\n\t\t\tVectorClear( result );\n\t\t\treturn;\n\t\t}\n\t\tVectorCopy( tr->trDelta, result );\n\t\tbreak;\n\tcase TR_GRAVITY:\n\t\tdeltaTime = ( atTime - tr->trTime ) * 0.001;\t// milliseconds to seconds\n\t\tVectorCopy( tr->trDelta, result );\n\t\tresult[2] -= DEFAULT_GRAVITY * deltaTime;\t\t// FIXME: local gravity...\n\t\tbreak;\n\tdefault:\n\t\tCom_Error( ERR_DROP, \"BG_EvaluateTrajectoryDelta: unknown trType: %i\", tr->trTime );\n\t\tbreak;\n\t}\n}\n\nchar *eventnames[] = {\n\t\"EV_NONE\",\n\n\t\"EV_FOOTSTEP\",\n\t\"EV_FOOTSTEP_METAL\",\n\t\"EV_FOOTSPLASH\",\n\t\"EV_FOOTWADE\",\n\t\"EV_SWIM\",\n\n\t\"EV_STEP_4\",\n\t\"EV_STEP_8\",\n\t\"EV_STEP_12\",\n\t\"EV_STEP_16\",\n\n\t\"EV_FALL_SHORT\",\n\t\"EV_FALL_MEDIUM\",\n\t\"EV_FALL_FAR\",\n\n\t\"EV_JUMP_PAD\",\t\t\t// boing sound at origin\", jump sound on player\n\n\t\"EV_JUMP\",\n\t\"EV_WATER_TOUCH\",\t// foot touches\n\t\"EV_WATER_LEAVE\",\t// foot leaves\n\t\"EV_WATER_UNDER\",\t// head touches\n\t\"EV_WATER_CLEAR\",\t// head leaves\n\n\t\"EV_ITEM_PICKUP\",\t\t\t// normal item pickups are predictable\n\t\"EV_GLOBAL_ITEM_PICKUP\",\t// powerup / team sounds are broadcast to everyone\n\n\t\"EV_NOAMMO\",\n\t\"EV_CHANGE_WEAPON\",\n\t\"EV_FIRE_WEAPON\",\n\n\t\"EV_USE_ITEM0\",\n\t\"EV_USE_ITEM1\",\n\t\"EV_USE_ITEM2\",\n\t\"EV_USE_ITEM3\",\n\t\"EV_USE_ITEM4\",\n\t\"EV_USE_ITEM5\",\n\t\"EV_USE_ITEM6\",\n\t\"EV_USE_ITEM7\",\n\t\"EV_USE_ITEM8\",\n\t\"EV_USE_ITEM9\",\n\t\"EV_USE_ITEM10\",\n\t\"EV_USE_ITEM11\",\n\t\"EV_USE_ITEM12\",\n\t\"EV_USE_ITEM13\",\n\t\"EV_USE_ITEM14\",\n\t\"EV_USE_ITEM15\",\n\n\t\"EV_ITEM_RESPAWN\",\n\t\"EV_ITEM_POP\",\n\t\"EV_PLAYER_TELEPORT_IN\",\n\t\"EV_PLAYER_TELEPORT_OUT\",\n\n\t\"EV_GRENADE_BOUNCE\",\t\t// eventParm will be the soundindex\n\n\t\"EV_GENERAL_SOUND\",\n\t\"EV_GLOBAL_SOUND\",\t\t// no attenuation\n\t\"EV_GLOBAL_TEAM_SOUND\",\n\n\t\"EV_BULLET_HIT_FLESH\",\n\t\"EV_BULLET_HIT_WALL\",\n\n\t\"EV_MISSILE_HIT\",\n\t\"EV_MISSILE_MISS\",\n\t\"EV_MISSILE_MISS_METAL\",\n\t\"EV_RAILTRAIL\",\n\t\"EV_SHOTGUN\",\n\t\"EV_BULLET\",\t\t\t\t// otherEntity is the shooter\n\n\t\"EV_PAIN\",\n\t\"EV_DEATH1\",\n\t\"EV_DEATH2\",\n\t\"EV_DEATH3\",\n\t\"EV_OBITUARY\",\n\n\t\"EV_POWERUP_QUAD\",\n\t\"EV_POWERUP_BATTLESUIT\",\n\t\"EV_POWERUP_REGEN\",\n\n\t\"EV_GIB_PLAYER\",\t\t\t// gib a previously living player\n\t\"EV_SCOREPLUM\",\t\t\t// score plum\n\n\t\"EV_DEBUG_LINE\",\n\t\"EV_STOPLOOPINGSOUND\",\n\t\"EV_TAUNT\"\n\n};\n\n/*\n===============\nBG_AddPredictableEventToPlayerstate\n\nHandles the sequence numbers\n===============\n*/\n\nvoid\ttrap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize );\n\nvoid BG_AddPredictableEventToPlayerstate( int newEvent, int eventParm, playerState_t *ps ) {\n\n#ifdef _DEBUG\n\t{\n\t\tchar buf[256];\n\t\ttrap_Cvar_VariableStringBuffer(\"showevents\", buf, sizeof(buf));\n\t\tif ( atof(buf) != 0 ) {\n#ifdef QAGAME\n\t\t\tCom_Printf(\" game event svt %5d -> %5d: num = %20s parm %d\\n\", ps->pmove_framecount/*ps->commandTime*/, ps->eventSequence, eventnames[newEvent], eventParm);\n#else\n\t\t\tCom_Printf(\"Cgame event svt %5d -> %5d: num = %20s parm %d\\n\", ps->pmove_framecount/*ps->commandTime*/, ps->eventSequence, eventnames[newEvent], eventParm);\n#endif\n\t\t}\n\t}\n#endif\n\tps->events[ps->eventSequence & (MAX_PS_EVENTS-1)] = newEvent;\n\tps->eventParms[ps->eventSequence & (MAX_PS_EVENTS-1)] = eventParm;\n\tps->eventSequence++;\n}\n\n/*\n========================\nBG_TouchJumpPad\n========================\n*/\nvoid BG_TouchJumpPad( playerState_t *ps, entityState_t *jumppad ) {\n\tvec3_t\tangles;\n\tfloat p;\n\tint effectNum;\n\n\t// spectators don't use jump pads\n\tif ( ps->pm_type != PM_NORMAL ) {\n\t\treturn;\n\t}\n\n\t// flying characters don't hit bounce pads\n\tif ( ps->powerups[PW_FLIGHT] ) {\n\t\treturn;\n\t}\n\n\t// if we didn't hit this same jumppad the previous frame\n\t// then don't play the event sound again if we are in a fat trigger\n\tif ( ps->jumppad_ent != jumppad->number ) {\n\n\t\tvectoangles( jumppad->origin2, angles);\n\t\tp = fabs( AngleNormalize180( angles[PITCH] ) );\n\t\tif( p < 45 ) {\n\t\t\teffectNum = 0;\n\t\t} else {\n\t\t\teffectNum = 1;\n\t\t}\n\t\tBG_AddPredictableEventToPlayerstate( EV_JUMP_PAD, effectNum, ps );\n\t}\n\t// remember hitting this jumppad this frame\n\tps->jumppad_ent = jumppad->number;\n\tps->jumppad_frame = ps->pmove_framecount;\n\t// give the player the velocity from the jumppad\n\tVectorCopy( jumppad->origin2, ps->velocity );\n}\n\n/*\n========================\nBG_PlayerStateToEntityState\n\nThis is done after each set of usercmd_t on the server,\nand after local prediction on the client\n========================\n*/\nvoid BG_PlayerStateToEntityState( playerState_t *ps, entityState_t *s, qboolean snap ) {\n\tint\t\ti;\n\n\tif ( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_SPECTATOR ) {\n\t\ts->eType = ET_INVISIBLE;\n\t} else if ( ps->stats[STAT_HEALTH] <= GIB_HEALTH ) {\n\t\ts->eType = ET_INVISIBLE;\n\t} else {\n\t\ts->eType = ET_PLAYER;\n\t}\n\n\ts->number = ps->clientNum;\n\n\ts->pos.trType = TR_INTERPOLATE;\n\tVectorCopy( ps->origin, s->pos.trBase );\n\tif ( snap ) {\n\t\tSnapVector( s->pos.trBase );\n\t}\n\t// set the trDelta for flag direction\n\tVectorCopy( ps->velocity, s->pos.trDelta );\n\n\ts->apos.trType = TR_INTERPOLATE;\n\tVectorCopy( ps->viewangles, s->apos.trBase );\n\tif ( snap ) {\n\t\tSnapVector( s->apos.trBase );\n\t}\n\n\ts->angles2[YAW] = ps->movementDir;\n\ts->legsAnim = ps->legsAnim;\n\ts->torsoAnim = ps->torsoAnim;\n\ts->clientNum = ps->clientNum;\t\t// ET_PLAYER looks here instead of at number\n\t\t\t\t\t\t\t\t\t\t// so corpses can also reference the proper config\n\ts->eFlags = ps->eFlags;\n\tif ( ps->stats[STAT_HEALTH] <= 0 ) {\n\t\ts->eFlags |= EF_DEAD;\n\t} else {\n\t\ts->eFlags &= ~EF_DEAD;\n\t}\n\n\tif ( ps->externalEvent ) {\n\t\ts->event = ps->externalEvent;\n\t\ts->eventParm = ps->externalEventParm;\n\t} else if ( ps->entityEventSequence < ps->eventSequence ) {\n\t\tint\t\tseq;\n\n\t\tif ( ps->entityEventSequence < ps->eventSequence - MAX_PS_EVENTS) {\n\t\t\tps->entityEventSequence = ps->eventSequence - MAX_PS_EVENTS;\n\t\t}\n\t\tseq = ps->entityEventSequence & (MAX_PS_EVENTS-1);\n\t\ts->event = ps->events[ seq ] | ( ( ps->entityEventSequence & 3 ) << 8 );\n\t\ts->eventParm = ps->eventParms[ seq ];\n\t\tps->entityEventSequence++;\n\t}\n\n\ts->weapon = ps->weapon;\n\ts->groundEntityNum = ps->groundEntityNum;\n\n\ts->powerups = 0;\n\tfor ( i = 0 ; i < MAX_POWERUPS ; i++ ) {\n\t\tif ( ps->powerups[ i ] ) {\n\t\t\ts->powerups |= 1 << i;\n\t\t}\n\t}\n\n\ts->loopSound = ps->loopSound;\n\ts->generic1 = ps->generic1;\n}\n\n/*\n========================\nBG_PlayerStateToEntityStateExtraPolate\n\nThis is done after each set of usercmd_t on the server,\nand after local prediction on the client\n========================\n*/\nvoid BG_PlayerStateToEntityStateExtraPolate( playerState_t *ps, entityState_t *s, int time, qboolean snap ) {\n\tint\t\ti;\n\n\tif ( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_SPECTATOR ) {\n\t\ts->eType = ET_INVISIBLE;\n\t} else if ( ps->stats[STAT_HEALTH] <= GIB_HEALTH ) {\n\t\ts->eType = ET_INVISIBLE;\n\t} else {\n\t\ts->eType = ET_PLAYER;\n\t}\n\n\ts->number = ps->clientNum;\n\n\ts->pos.trType = TR_LINEAR_STOP;\n\tVectorCopy( ps->origin, s->pos.trBase );\n\tif ( snap ) {\n\t\tSnapVector( s->pos.trBase );\n\t}\n\t// set the trDelta for flag direction and linear prediction\n\tVectorCopy( ps->velocity, s->pos.trDelta );\n\t// set the time for linear prediction\n\ts->pos.trTime = time;\n\t// set maximum extra polation time\n\ts->pos.trDuration = 50; // 1000 / sv_fps (default = 20)\n\n\ts->apos.trType = TR_INTERPOLATE;\n\tVectorCopy( ps->viewangles, s->apos.trBase );\n\tif ( snap ) {\n\t\tSnapVector( s->apos.trBase );\n\t}\n\n\ts->angles2[YAW] = ps->movementDir;\n\ts->legsAnim = ps->legsAnim;\n\ts->torsoAnim = ps->torsoAnim;\n\ts->clientNum = ps->clientNum;\t\t// ET_PLAYER looks here instead of at number\n\t\t\t\t\t\t\t\t\t\t// so corpses can also reference the proper config\n\ts->eFlags = ps->eFlags;\n\tif ( ps->stats[STAT_HEALTH] <= 0 ) {\n\t\ts->eFlags |= EF_DEAD;\n\t} else {\n\t\ts->eFlags &= ~EF_DEAD;\n\t}\n\n\tif ( ps->externalEvent ) {\n\t\ts->event = ps->externalEvent;\n\t\ts->eventParm = ps->externalEventParm;\n\t} else if ( ps->entityEventSequence < ps->eventSequence ) {\n\t\tint\t\tseq;\n\n\t\tif ( ps->entityEventSequence < ps->eventSequence - MAX_PS_EVENTS) {\n\t\t\tps->entityEventSequence = ps->eventSequence - MAX_PS_EVENTS;\n\t\t}\n\t\tseq = ps->entityEventSequence & (MAX_PS_EVENTS-1);\n\t\ts->event = ps->events[ seq ] | ( ( ps->entityEventSequence & 3 ) << 8 );\n\t\ts->eventParm = ps->eventParms[ seq ];\n\t\tps->entityEventSequence++;\n\t}\n\n\ts->weapon = ps->weapon;\n\ts->groundEntityNum = ps->groundEntityNum;\n\n\ts->powerups = 0;\n\tfor ( i = 0 ; i < MAX_POWERUPS ; i++ ) {\n\t\tif ( ps->powerups[ i ] ) {\n\t\t\ts->powerups |= 1 << i;\n\t\t}\n\t}\n\n\ts->loopSound = ps->loopSound;\n\ts->generic1 = ps->generic1;\n}\n"
  },
  {
    "path": "src/game/bg_pmove.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n// bg_pmove.c -- both games player movement code\n// takes a playerstate and a usercmd as input and returns a modifed playerstate\n\n#include \"q_shared.h\"\n#include \"bg_public.h\"\n#include \"bg_local.h\"\n\npmove_t\t\t*pm;\npml_t\t\tpml;\n\n// movement parameters\nfloat\tpm_stopspeed = 100.0f;\nfloat\tpm_duckScale = 0.25f;\nfloat\tpm_swimScale = 0.50f;\nfloat\tpm_wadeScale = 0.70f;\n\nfloat\tpm_accelerate = 10.0f;\nfloat\tpm_airaccelerate = 1.0f;\nfloat\tpm_wateraccelerate = 4.0f;\nfloat\tpm_flyaccelerate = 8.0f;\n\nfloat\tpm_friction = 6.0f;\nfloat\tpm_waterfriction = 1.0f;\nfloat\tpm_flightfriction = 3.0f;\nfloat\tpm_spectatorfriction = 5.0f;\n\nint\t\tc_pmove = 0;\n\n\n/*\n===============\nPM_AddEvent\n\n===============\n*/\nvoid PM_AddEvent( int newEvent ) {\n\tBG_AddPredictableEventToPlayerstate( newEvent, 0, pm->ps );\n}\n\n/*\n===============\nPM_AddTouchEnt\n===============\n*/\nvoid PM_AddTouchEnt( int entityNum ) {\n\tint\t\ti;\n\n\tif ( entityNum == ENTITYNUM_WORLD ) {\n\t\treturn;\n\t}\n\tif ( pm->numtouch == MAXTOUCH ) {\n\t\treturn;\n\t}\n\n\t// see if it is already added\n\tfor ( i = 0 ; i < pm->numtouch ; i++ ) {\n\t\tif ( pm->touchents[ i ] == entityNum ) {\n\t\t\treturn;\n\t\t}\n\t}\n\n\t// add it\n\tpm->touchents[pm->numtouch] = entityNum;\n\tpm->numtouch++;\n}\n\n/*\n===================\nPM_StartTorsoAnim\n===================\n*/\nstatic void PM_StartTorsoAnim( int anim ) {\n\tif ( pm->ps->pm_type >= PM_DEAD ) {\n\t\treturn;\n\t}\n\tpm->ps->torsoAnim = ( ( pm->ps->torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT )\n\t\t| anim;\n}\nstatic void PM_StartLegsAnim( int anim ) {\n\tif ( pm->ps->pm_type >= PM_DEAD ) {\n\t\treturn;\n\t}\n\tif ( pm->ps->legsTimer > 0 ) {\n\t\treturn;\t\t// a high priority animation is running\n\t}\n\tpm->ps->legsAnim = ( ( pm->ps->legsAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT )\n\t\t| anim;\n}\n\nstatic void PM_ContinueLegsAnim( int anim ) {\n\tif ( ( pm->ps->legsAnim & ~ANIM_TOGGLEBIT ) == anim ) {\n\t\treturn;\n\t}\n\tif ( pm->ps->legsTimer > 0 ) {\n\t\treturn;\t\t// a high priority animation is running\n\t}\n\tPM_StartLegsAnim( anim );\n}\n\nstatic void PM_ContinueTorsoAnim( int anim ) {\n\tif ( ( pm->ps->torsoAnim & ~ANIM_TOGGLEBIT ) == anim ) {\n\t\treturn;\n\t}\n\tif ( pm->ps->torsoTimer > 0 ) {\n\t\treturn;\t\t// a high priority animation is running\n\t}\n\tPM_StartTorsoAnim( anim );\n}\n\nstatic void PM_ForceLegsAnim( int anim ) {\n\tpm->ps->legsTimer = 0;\n\tPM_StartLegsAnim( anim );\n}\n\n\n/*\n==================\nPM_ClipVelocity\n\nSlide off of the impacting surface\n==================\n*/\nvoid PM_ClipVelocity( vec3_t in, vec3_t normal, vec3_t out, float overbounce ) {\n\tfloat\tbackoff;\n\tfloat\tchange;\n\tint\t\ti;\n\t\n\tbackoff = DotProduct (in, normal);\n\t\n\tif ( backoff < 0 ) {\n\t\tbackoff *= overbounce;\n\t} else {\n\t\tbackoff /= overbounce;\n\t}\n\n\tfor ( i=0 ; i<3 ; i++ ) {\n\t\tchange = normal[i]*backoff;\n\t\tout[i] = in[i] - change;\n\t}\n}\n\n\n/*\n==================\nPM_Friction\n\nHandles both ground friction and water friction\n==================\n*/\nstatic void PM_Friction( void ) {\n\tvec3_t\tvec;\n\tfloat\t*vel;\n\tfloat\tspeed, newspeed, control;\n\tfloat\tdrop;\n\t\n\tvel = pm->ps->velocity;\n\t\n\tVectorCopy( vel, vec );\n\tif ( pml.walking ) {\n\t\tvec[2] = 0;\t// ignore slope movement\n\t}\n\n\tspeed = VectorLength(vec);\n\tif (speed < 1) {\n\t\tvel[0] = 0;\n\t\tvel[1] = 0;\t\t// allow sinking underwater\n\t\t// FIXME: still have z friction underwater?\n\t\treturn;\n\t}\n\n\tdrop = 0;\n\n\t// apply ground friction\n\tif ( pm->waterlevel <= 1 ) {\n\t\tif ( pml.walking && !(pml.groundTrace.surfaceFlags & SURF_SLICK) ) {\n\t\t\t// if getting knocked back, no friction\n\t\t\tif ( ! (pm->ps->pm_flags & PMF_TIME_KNOCKBACK) ) {\n\t\t\t\tcontrol = speed < pm_stopspeed ? pm_stopspeed : speed;\n\t\t\t\tdrop += control*pm_friction*pml.frametime;\n\t\t\t}\n\t\t}\n\t}\n\n\t// apply water friction even if just wading\n\tif ( pm->waterlevel ) {\n\t\tdrop += speed*pm_waterfriction*pm->waterlevel*pml.frametime;\n\t}\n\n\t// apply flying friction\n\tif ( pm->ps->powerups[PW_FLIGHT]) {\n\t\tdrop += speed*pm_flightfriction*pml.frametime;\n\t}\n\n\tif ( pm->ps->pm_type == PM_SPECTATOR) {\n\t\tdrop += speed*pm_spectatorfriction*pml.frametime;\n\t}\n\n\t// scale the velocity\n\tnewspeed = speed - drop;\n\tif (newspeed < 0) {\n\t\tnewspeed = 0;\n\t}\n\tnewspeed /= speed;\n\n\tvel[0] = vel[0] * newspeed;\n\tvel[1] = vel[1] * newspeed;\n\tvel[2] = vel[2] * newspeed;\n}\n\n\n/*\n==============\nPM_Accelerate\n\nHandles user intended acceleration\n==============\n*/\nstatic void PM_Accelerate( vec3_t wishdir, float wishspeed, float accel ) {\n#if 1\n\t// q2 style\n\tint\t\t\ti;\n\tfloat\t\taddspeed, accelspeed, currentspeed;\n\n\tcurrentspeed = DotProduct (pm->ps->velocity, wishdir);\n\taddspeed = wishspeed - currentspeed;\n\tif (addspeed <= 0) {\n\t\treturn;\n\t}\n\taccelspeed = accel*pml.frametime*wishspeed;\n\tif (accelspeed > addspeed) {\n\t\taccelspeed = addspeed;\n\t}\n\t\n\tfor (i=0 ; i<3 ; i++) {\n\t\tpm->ps->velocity[i] += accelspeed*wishdir[i];\t\n\t}\n#else\n\t// proper way (avoids strafe jump maxspeed bug), but feels bad\n\tvec3_t\t\twishVelocity;\n\tvec3_t\t\tpushDir;\n\tfloat\t\tpushLen;\n\tfloat\t\tcanPush;\n\n\tVectorScale( wishdir, wishspeed, wishVelocity );\n\tVectorSubtract( wishVelocity, pm->ps->velocity, pushDir );\n\tpushLen = VectorNormalize( pushDir );\n\n\tcanPush = accel*pml.frametime*wishspeed;\n\tif (canPush > pushLen) {\n\t\tcanPush = pushLen;\n\t}\n\n\tVectorMA( pm->ps->velocity, canPush, pushDir, pm->ps->velocity );\n#endif\n}\n\n\n\n/*\n============\nPM_CmdScale\n\nReturns the scale factor to apply to cmd movements\nThis allows the clients to use axial -127 to 127 values for all directions\nwithout getting a sqrt(2) distortion in speed.\n============\n*/\nstatic float PM_CmdScale( usercmd_t *cmd ) {\n\tint\t\tmax;\n\tfloat\ttotal;\n\tfloat\tscale;\n\n\tmax = abs( cmd->forwardmove );\n\tif ( abs( cmd->rightmove ) > max ) {\n\t\tmax = abs( cmd->rightmove );\n\t}\n\tif ( abs( cmd->upmove ) > max ) {\n\t\tmax = abs( cmd->upmove );\n\t}\n\tif ( !max ) {\n\t\treturn 0;\n\t}\n\n\ttotal = sqrt( cmd->forwardmove * cmd->forwardmove\n\t\t+ cmd->rightmove * cmd->rightmove + cmd->upmove * cmd->upmove );\n\tscale = (float)pm->ps->speed * max / ( 127.0 * total );\n\n\treturn scale;\n}\n\n\n/*\n================\nPM_SetMovementDir\n\nDetermine the rotation of the legs reletive\nto the facing dir\n================\n*/\nstatic void PM_SetMovementDir( void ) {\n\tif ( pm->cmd.forwardmove || pm->cmd.rightmove ) {\n\t\tif ( pm->cmd.rightmove == 0 && pm->cmd.forwardmove > 0 ) {\n\t\t\tpm->ps->movementDir = 0;\n\t\t} else if ( pm->cmd.rightmove < 0 && pm->cmd.forwardmove > 0 ) {\n\t\t\tpm->ps->movementDir = 1;\n\t\t} else if ( pm->cmd.rightmove < 0 && pm->cmd.forwardmove == 0 ) {\n\t\t\tpm->ps->movementDir = 2;\n\t\t} else if ( pm->cmd.rightmove < 0 && pm->cmd.forwardmove < 0 ) {\n\t\t\tpm->ps->movementDir = 3;\n\t\t} else if ( pm->cmd.rightmove == 0 && pm->cmd.forwardmove < 0 ) {\n\t\t\tpm->ps->movementDir = 4;\n\t\t} else if ( pm->cmd.rightmove > 0 && pm->cmd.forwardmove < 0 ) {\n\t\t\tpm->ps->movementDir = 5;\n\t\t} else if ( pm->cmd.rightmove > 0 && pm->cmd.forwardmove == 0 ) {\n\t\t\tpm->ps->movementDir = 6;\n\t\t} else if ( pm->cmd.rightmove > 0 && pm->cmd.forwardmove > 0 ) {\n\t\t\tpm->ps->movementDir = 7;\n\t\t}\n\t} else {\n\t\t// if they aren't actively going directly sideways,\n\t\t// change the animation to the diagonal so they\n\t\t// don't stop too crooked\n\t\tif ( pm->ps->movementDir == 2 ) {\n\t\t\tpm->ps->movementDir = 1;\n\t\t} else if ( pm->ps->movementDir == 6 ) {\n\t\t\tpm->ps->movementDir = 7;\n\t\t} \n\t}\n}\n\n\n/*\n=============\nPM_CheckJump\n=============\n*/\nstatic qboolean PM_CheckJump( void ) {\n\tif ( pm->ps->pm_flags & PMF_RESPAWNED ) {\n\t\treturn qfalse;\t\t// don't allow jump until all buttons are up\n\t}\n\n\tif ( pm->cmd.upmove < 10 ) {\n\t\t// not holding jump\n\t\treturn qfalse;\n\t}\n\n\t// must wait for jump to be released\n\tif ( pm->ps->pm_flags & PMF_JUMP_HELD ) {\n\t\t// clear upmove so cmdscale doesn't lower running speed\n\t\tpm->cmd.upmove = 0;\n\t\treturn qfalse;\n\t}\n\n\tpml.groundPlane = qfalse;\t\t// jumping away\n\tpml.walking = qfalse;\n\tpm->ps->pm_flags |= PMF_JUMP_HELD;\n\n\tpm->ps->groundEntityNum = ENTITYNUM_NONE;\n\tpm->ps->velocity[2] = JUMP_VELOCITY;\n\tPM_AddEvent( EV_JUMP );\n\n\tif ( pm->cmd.forwardmove >= 0 ) {\n\t\tPM_ForceLegsAnim( LEGS_JUMP );\n\t\tpm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP;\n\t} else {\n\t\tPM_ForceLegsAnim( LEGS_JUMPB );\n\t\tpm->ps->pm_flags |= PMF_BACKWARDS_JUMP;\n\t}\n\n\treturn qtrue;\n}\n\n/*\n=============\nPM_CheckWaterJump\n=============\n*/\nstatic qboolean\tPM_CheckWaterJump( void ) {\n\tvec3_t\tspot;\n\tint\t\tcont;\n\tvec3_t\tflatforward;\n\n\tif (pm->ps->pm_time) {\n\t\treturn qfalse;\n\t}\n\n\t// check for water jump\n\tif ( pm->waterlevel != 2 ) {\n\t\treturn qfalse;\n\t}\n\n\tflatforward[0] = pml.forward[0];\n\tflatforward[1] = pml.forward[1];\n\tflatforward[2] = 0;\n\tVectorNormalize (flatforward);\n\n\tVectorMA (pm->ps->origin, 30, flatforward, spot);\n\tspot[2] += 4;\n\tcont = pm->pointcontents (spot, pm->ps->clientNum );\n\tif ( !(cont & CONTENTS_SOLID) ) {\n\t\treturn qfalse;\n\t}\n\n\tspot[2] += 16;\n\tcont = pm->pointcontents (spot, pm->ps->clientNum );\n\tif ( cont ) {\n\t\treturn qfalse;\n\t}\n\n\t// jump out of water\n\tVectorScale (pml.forward, 200, pm->ps->velocity);\n\tpm->ps->velocity[2] = 350;\n\n\tpm->ps->pm_flags |= PMF_TIME_WATERJUMP;\n\tpm->ps->pm_time = 2000;\n\n\treturn qtrue;\n}\n\n//============================================================================\n\n\n/*\n===================\nPM_WaterJumpMove\n\nFlying out of the water\n===================\n*/\nstatic void PM_WaterJumpMove( void ) {\n\t// waterjump has no control, but falls\n\n\tPM_StepSlideMove( qtrue );\n\n\tpm->ps->velocity[2] -= pm->ps->gravity * pml.frametime;\n\tif (pm->ps->velocity[2] < 0) {\n\t\t// cancel as soon as we are falling down again\n\t\tpm->ps->pm_flags &= ~PMF_ALL_TIMES;\n\t\tpm->ps->pm_time = 0;\n\t}\n}\n\n/*\n===================\nPM_WaterMove\n\n===================\n*/\nstatic void PM_WaterMove( void ) {\n\tint\t\ti;\n\tvec3_t\twishvel;\n\tfloat\twishspeed;\n\tvec3_t\twishdir;\n\tfloat\tscale;\n\tfloat\tvel;\n\n\tif ( PM_CheckWaterJump() ) {\n\t\tPM_WaterJumpMove();\n\t\treturn;\n\t}\n#if 0\n\t// jump = head for surface\n\tif ( pm->cmd.upmove >= 10 ) {\n\t\tif (pm->ps->velocity[2] > -300) {\n\t\t\tif ( pm->watertype == CONTENTS_WATER ) {\n\t\t\t\tpm->ps->velocity[2] = 100;\n\t\t\t} else if (pm->watertype == CONTENTS_SLIME) {\n\t\t\t\tpm->ps->velocity[2] = 80;\n\t\t\t} else {\n\t\t\t\tpm->ps->velocity[2] = 50;\n\t\t\t}\n\t\t}\n\t}\n#endif\n\tPM_Friction ();\n\n\tscale = PM_CmdScale( &pm->cmd );\n\t//\n\t// user intentions\n\t//\n\tif ( !scale ) {\n\t\twishvel[0] = 0;\n\t\twishvel[1] = 0;\n\t\twishvel[2] = -60;\t\t// sink towards bottom\n\t} else {\n\t\tfor (i=0 ; i<3 ; i++)\n\t\t\twishvel[i] = scale * pml.forward[i]*pm->cmd.forwardmove + scale * pml.right[i]*pm->cmd.rightmove;\n\n\t\twishvel[2] += scale * pm->cmd.upmove;\n\t}\n\n\tVectorCopy (wishvel, wishdir);\n\twishspeed = VectorNormalize(wishdir);\n\n\tif ( wishspeed > pm->ps->speed * pm_swimScale ) {\n\t\twishspeed = pm->ps->speed * pm_swimScale;\n\t}\n\n\tPM_Accelerate (wishdir, wishspeed, pm_wateraccelerate);\n\n\t// make sure we can go up slopes easily under water\n\tif ( pml.groundPlane && DotProduct( pm->ps->velocity, pml.groundTrace.plane.normal ) < 0 ) {\n\t\tvel = VectorLength(pm->ps->velocity);\n\t\t// slide along the ground plane\n\t\tPM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, \n\t\t\tpm->ps->velocity, OVERCLIP );\n\n\t\tVectorNormalize(pm->ps->velocity);\n\t\tVectorScale(pm->ps->velocity, vel, pm->ps->velocity);\n\t}\n\n\tPM_SlideMove( qfalse );\n}\n\n/*\n===================\nPM_FlyMove\n\nOnly with the flight powerup\n===================\n*/\nstatic void PM_FlyMove( void ) {\n\tint\t\ti;\n\tvec3_t\twishvel;\n\tfloat\twishspeed;\n\tvec3_t\twishdir;\n\tfloat\tscale;\n\n\t// normal slowdown\n\tPM_Friction ();\n\n\tscale = PM_CmdScale( &pm->cmd );\n\t//\n\t// user intentions\n\t//\n\tif ( !scale ) {\n\t\twishvel[0] = 0;\n\t\twishvel[1] = 0;\n\t\twishvel[2] = 0;\n\t} else {\n\t\tfor (i=0 ; i<3 ; i++) {\n\t\t\twishvel[i] = scale * pml.forward[i]*pm->cmd.forwardmove + scale * pml.right[i]*pm->cmd.rightmove;\n\t\t}\n\n\t\twishvel[2] += scale * pm->cmd.upmove;\n\t}\n\n\tVectorCopy (wishvel, wishdir);\n\twishspeed = VectorNormalize(wishdir);\n\n\tPM_Accelerate (wishdir, wishspeed, pm_flyaccelerate);\n\n\tPM_StepSlideMove( qfalse );\n}\n\n\n/*\n===================\nPM_AirMove\n\n===================\n*/\nstatic void PM_AirMove( void ) {\n\tint\t\t\ti;\n\tvec3_t\t\twishvel;\n\tfloat\t\tfmove, smove;\n\tvec3_t\t\twishdir;\n\tfloat\t\twishspeed;\n\tfloat\t\tscale;\n\tusercmd_t\tcmd;\n\n\tPM_Friction();\n\n\tfmove = pm->cmd.forwardmove;\n\tsmove = pm->cmd.rightmove;\n\n\tcmd = pm->cmd;\n\tscale = PM_CmdScale( &cmd );\n\n\t// set the movementDir so clients can rotate the legs for strafing\n\tPM_SetMovementDir();\n\n\t// project moves down to flat plane\n\tpml.forward[2] = 0;\n\tpml.right[2] = 0;\n\tVectorNormalize (pml.forward);\n\tVectorNormalize (pml.right);\n\n\tfor ( i = 0 ; i < 2 ; i++ ) {\n\t\twishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove;\n\t}\n\twishvel[2] = 0;\n\n\tVectorCopy (wishvel, wishdir);\n\twishspeed = VectorNormalize(wishdir);\n\twishspeed *= scale;\n\n\t// not on ground, so little effect on velocity\n\tPM_Accelerate (wishdir, wishspeed, pm_airaccelerate);\n\n\t// we may have a ground plane that is very steep, even\n\t// though we don't have a groundentity\n\t// slide along the steep plane\n\tif ( pml.groundPlane ) {\n\t\tPM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, \n\t\t\tpm->ps->velocity, OVERCLIP );\n\t}\n\n#if 0\n\t//ZOID:  If we are on the grapple, try stair-stepping\n\t//this allows a player to use the grapple to pull himself\n\t//over a ledge\n\tif (pm->ps->pm_flags & PMF_GRAPPLE_PULL)\n\t\tPM_StepSlideMove ( qtrue );\n\telse\n\t\tPM_SlideMove ( qtrue );\n#endif\n\n\tPM_StepSlideMove ( qtrue );\n}\n\n/*\n===================\nPM_GrappleMove\n\n===================\n*/\nstatic void PM_GrappleMove( void ) {\n\tvec3_t vel, v;\n\tfloat vlen;\n\n\tVectorScale(pml.forward, -16, v);\n\tVectorAdd(pm->ps->grapplePoint, v, v);\n\tVectorSubtract(v, pm->ps->origin, vel);\n\tvlen = VectorLength(vel);\n\tVectorNormalize( vel );\n\n\tif (vlen <= 100)\n\t\tVectorScale(vel, 10 * vlen, vel);\n\telse\n\t\tVectorScale(vel, 800, vel);\n\n\tVectorCopy(vel, pm->ps->velocity);\n\n\tpml.groundPlane = qfalse;\n}\n\n/*\n===================\nPM_WalkMove\n\n===================\n*/\nstatic void PM_WalkMove( void ) {\n\tint\t\t\ti;\n\tvec3_t\t\twishvel;\n\tfloat\t\tfmove, smove;\n\tvec3_t\t\twishdir;\n\tfloat\t\twishspeed;\n\tfloat\t\tscale;\n\tusercmd_t\tcmd;\n\tfloat\t\taccelerate;\n\tfloat\t\tvel;\n\n\tif ( pm->waterlevel > 2 && DotProduct( pml.forward, pml.groundTrace.plane.normal ) > 0 ) {\n\t\t// begin swimming\n\t\tPM_WaterMove();\n\t\treturn;\n\t}\n\n\n\tif ( PM_CheckJump () ) {\n\t\t// jumped away\n\t\tif ( pm->waterlevel > 1 ) {\n\t\t\tPM_WaterMove();\n\t\t} else {\n\t\t\tPM_AirMove();\n\t\t}\n\t\treturn;\n\t}\n\n\tPM_Friction ();\n\n\tfmove = pm->cmd.forwardmove;\n\tsmove = pm->cmd.rightmove;\n\n\tcmd = pm->cmd;\n\tscale = PM_CmdScale( &cmd );\n\n\t// set the movementDir so clients can rotate the legs for strafing\n\tPM_SetMovementDir();\n\n\t// project moves down to flat plane\n\tpml.forward[2] = 0;\n\tpml.right[2] = 0;\n\n\t// project the forward and right directions onto the ground plane\n\tPM_ClipVelocity (pml.forward, pml.groundTrace.plane.normal, pml.forward, OVERCLIP );\n\tPM_ClipVelocity (pml.right, pml.groundTrace.plane.normal, pml.right, OVERCLIP );\n\t//\n\tVectorNormalize (pml.forward);\n\tVectorNormalize (pml.right);\n\n\tfor ( i = 0 ; i < 3 ; i++ ) {\n\t\twishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove;\n\t}\n\t// when going up or down slopes the wish velocity should Not be zero\n//\twishvel[2] = 0;\n\n\tVectorCopy (wishvel, wishdir);\n\twishspeed = VectorNormalize(wishdir);\n\twishspeed *= scale;\n\n\t// clamp the speed lower if ducking\n\tif ( pm->ps->pm_flags & PMF_DUCKED ) {\n\t\tif ( wishspeed > pm->ps->speed * pm_duckScale ) {\n\t\t\twishspeed = pm->ps->speed * pm_duckScale;\n\t\t}\n\t}\n\n\t// clamp the speed lower if wading or walking on the bottom\n\tif ( pm->waterlevel ) {\n\t\tfloat\twaterScale;\n\n\t\twaterScale = pm->waterlevel / 3.0;\n\t\twaterScale = 1.0 - ( 1.0 - pm_swimScale ) * waterScale;\n\t\tif ( wishspeed > pm->ps->speed * waterScale ) {\n\t\t\twishspeed = pm->ps->speed * waterScale;\n\t\t}\n\t}\n\n\t// when a player gets hit, they temporarily lose\n\t// full control, which allows them to be moved a bit\n\tif ( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) {\n\t\taccelerate = pm_airaccelerate;\n\t} else {\n\t\taccelerate = pm_accelerate;\n\t}\n\n\tPM_Accelerate (wishdir, wishspeed, accelerate);\n\n\t//Com_Printf(\"velocity = %1.1f %1.1f %1.1f\\n\", pm->ps->velocity[0], pm->ps->velocity[1], pm->ps->velocity[2]);\n\t//Com_Printf(\"velocity1 = %1.1f\\n\", VectorLength(pm->ps->velocity));\n\n\tif ( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) {\n\t\tpm->ps->velocity[2] -= pm->ps->gravity * pml.frametime;\n\t} else {\n\t\t// don't reset the z velocity for slopes\n//\t\tpm->ps->velocity[2] = 0;\n\t}\n\n\tvel = VectorLength(pm->ps->velocity);\n\n\t// slide along the ground plane\n\tPM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, \n\t\tpm->ps->velocity, OVERCLIP );\n\n\t// don't decrease velocity when going up or down a slope\n\tVectorNormalize(pm->ps->velocity);\n\tVectorScale(pm->ps->velocity, vel, pm->ps->velocity);\n\n\t// don't do anything if standing still\n\tif (!pm->ps->velocity[0] && !pm->ps->velocity[1]) {\n\t\treturn;\n\t}\n\n\tPM_StepSlideMove( qfalse );\n\n\t//Com_Printf(\"velocity2 = %1.1f\\n\", VectorLength(pm->ps->velocity));\n\n}\n\n\n/*\n==============\nPM_DeadMove\n==============\n*/\nstatic void PM_DeadMove( void ) {\n\tfloat\tforward;\n\n\tif ( !pml.walking ) {\n\t\treturn;\n\t}\n\n\t// extra friction\n\n\tforward = VectorLength (pm->ps->velocity);\n\tforward -= 20;\n\tif ( forward <= 0 ) {\n\t\tVectorClear (pm->ps->velocity);\n\t} else {\n\t\tVectorNormalize (pm->ps->velocity);\n\t\tVectorScale (pm->ps->velocity, forward, pm->ps->velocity);\n\t}\n}\n\n\n/*\n===============\nPM_NoclipMove\n===============\n*/\nstatic void PM_NoclipMove( void ) {\n\tfloat\tspeed, drop, friction, control, newspeed;\n\tint\t\t\ti;\n\tvec3_t\t\twishvel;\n\tfloat\t\tfmove, smove;\n\tvec3_t\t\twishdir;\n\tfloat\t\twishspeed;\n\tfloat\t\tscale;\n\n\tpm->ps->viewheight = DEFAULT_VIEWHEIGHT;\n\n\t// friction\n\n\tspeed = VectorLength (pm->ps->velocity);\n\tif (speed < 1)\n\t{\n\t\tVectorCopy (vec3_origin, pm->ps->velocity);\n\t}\n\telse\n\t{\n\t\tdrop = 0;\n\n\t\tfriction = pm_friction*1.5;\t// extra friction\n\t\tcontrol = speed < pm_stopspeed ? pm_stopspeed : speed;\n\t\tdrop += control*friction*pml.frametime;\n\n\t\t// scale the velocity\n\t\tnewspeed = speed - drop;\n\t\tif (newspeed < 0)\n\t\t\tnewspeed = 0;\n\t\tnewspeed /= speed;\n\n\t\tVectorScale (pm->ps->velocity, newspeed, pm->ps->velocity);\n\t}\n\n\t// accelerate\n\tscale = PM_CmdScale( &pm->cmd );\n\n\tfmove = pm->cmd.forwardmove;\n\tsmove = pm->cmd.rightmove;\n\t\n\tfor (i=0 ; i<3 ; i++)\n\t\twishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove;\n\twishvel[2] += pm->cmd.upmove;\n\n\tVectorCopy (wishvel, wishdir);\n\twishspeed = VectorNormalize(wishdir);\n\twishspeed *= scale;\n\n\tPM_Accelerate( wishdir, wishspeed, pm_accelerate );\n\n\t// move\n\tVectorMA (pm->ps->origin, pml.frametime, pm->ps->velocity, pm->ps->origin);\n}\n\n//============================================================================\n\n/*\n================\nPM_FootstepForSurface\n\nReturns an event number apropriate for the groundsurface\n================\n*/\nstatic int PM_FootstepForSurface( void ) {\n\tif ( pml.groundTrace.surfaceFlags & SURF_NOSTEPS ) {\n\t\treturn 0;\n\t}\n\tif ( pml.groundTrace.surfaceFlags & SURF_METALSTEPS ) {\n\t\treturn EV_FOOTSTEP_METAL;\n\t}\n\treturn EV_FOOTSTEP;\n}\n\n\n/*\n=================\nPM_CrashLand\n\nCheck for hard landings that generate sound events\n=================\n*/\nstatic void PM_CrashLand( void ) {\n\tfloat\t\tdelta;\n\tfloat\t\tdist;\n\tfloat\t\tvel, acc;\n\tfloat\t\tt;\n\tfloat\t\ta, b, c, den;\n\n\t// decide which landing animation to use\n\tif ( pm->ps->pm_flags & PMF_BACKWARDS_JUMP ) {\n\t\tPM_ForceLegsAnim( LEGS_LANDB );\n\t} else {\n\t\tPM_ForceLegsAnim( LEGS_LAND );\n\t}\n\n\tpm->ps->legsTimer = TIMER_LAND;\n\n\t// calculate the exact velocity on landing\n\tdist = pm->ps->origin[2] - pml.previous_origin[2];\n\tvel = pml.previous_velocity[2];\n\tacc = -pm->ps->gravity;\n\n\ta = acc / 2;\n\tb = vel;\n\tc = -dist;\n\n\tden =  b * b - 4 * a * c;\n\tif ( den < 0 ) {\n\t\treturn;\n\t}\n\tt = (-b - sqrt( den ) ) / ( 2 * a );\n\n\tdelta = vel + t * acc;\n\tdelta = delta*delta * 0.0001;\n\n\t// ducking while falling doubles damage\n\tif ( pm->ps->pm_flags & PMF_DUCKED ) {\n\t\tdelta *= 2;\n\t}\n\n\t// never take falling damage if completely underwater\n\tif ( pm->waterlevel == 3 ) {\n\t\treturn;\n\t}\n\n\t// reduce falling damage if there is standing water\n\tif ( pm->waterlevel == 2 ) {\n\t\tdelta *= 0.25;\n\t}\n\tif ( pm->waterlevel == 1 ) {\n\t\tdelta *= 0.5;\n\t}\n\n\tif ( delta < 1 ) {\n\t\treturn;\n\t}\n\n\t// create a local entity event to play the sound\n\n\t// SURF_NODAMAGE is used for bounce pads where you don't ever\n\t// want to take damage or play a crunch sound\n\tif ( !(pml.groundTrace.surfaceFlags & SURF_NODAMAGE) )  {\n\t\tif ( delta > 60 ) {\n\t\t\tPM_AddEvent( EV_FALL_FAR );\n\t\t} else if ( delta > 40 ) {\n\t\t\t// this is a pain grunt, so don't play it if dead\n\t\t\tif ( pm->ps->stats[STAT_HEALTH] > 0 ) {\n\t\t\t\tPM_AddEvent( EV_FALL_MEDIUM );\n\t\t\t}\n\t\t} else if ( delta > 7 ) {\n\t\t\tPM_AddEvent( EV_FALL_SHORT );\n\t\t} else {\n\t\t\tPM_AddEvent( PM_FootstepForSurface() );\n\t\t}\n\t}\n\n\t// start footstep cycle over\n\tpm->ps->bobCycle = 0;\n}\n\n/*\n=============\nPM_CheckStuck\n=============\n*/\n/*\nvoid PM_CheckStuck(void) {\n\ttrace_t trace;\n\n\tpm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, pm->ps->origin, pm->ps->clientNum, pm->tracemask);\n\tif (trace.allsolid) {\n\t\t//int shit = qtrue;\n\t}\n}\n*/\n\n/*\n=============\nPM_CorrectAllSolid\n=============\n*/\nstatic int PM_CorrectAllSolid( trace_t *trace ) {\n\tint\t\t\ti, j, k;\n\tvec3_t\t\tpoint;\n\n\tif ( pm->debugLevel ) {\n\t\tCom_Printf(\"%i:allsolid\\n\", c_pmove);\n\t}\n\n\t// jitter around\n\tfor (i = -1; i <= 1; i++) {\n\t\tfor (j = -1; j <= 1; j++) {\n\t\t\tfor (k = -1; k <= 1; k++) {\n\t\t\t\tVectorCopy(pm->ps->origin, point);\n\t\t\t\tpoint[0] += (float) i;\n\t\t\t\tpoint[1] += (float) j;\n\t\t\t\tpoint[2] += (float) k;\n\t\t\t\tpm->trace (trace, point, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask);\n\t\t\t\tif ( !trace->allsolid ) {\n\t\t\t\t\tpoint[0] = pm->ps->origin[0];\n\t\t\t\t\tpoint[1] = pm->ps->origin[1];\n\t\t\t\t\tpoint[2] = pm->ps->origin[2] - 0.25;\n\n\t\t\t\t\tpm->trace (trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask);\n\t\t\t\t\tpml.groundTrace = *trace;\n\t\t\t\t\treturn qtrue;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tpm->ps->groundEntityNum = ENTITYNUM_NONE;\n\tpml.groundPlane = qfalse;\n\tpml.walking = qfalse;\n\n\treturn qfalse;\n}\n\n\n/*\n=============\nPM_GroundTraceMissed\n\nThe ground trace didn't hit a surface, so we are in freefall\n=============\n*/\nstatic void PM_GroundTraceMissed( void ) {\n\ttrace_t\t\ttrace;\n\tvec3_t\t\tpoint;\n\n\tif ( pm->ps->groundEntityNum != ENTITYNUM_NONE ) {\n\t\t// we just transitioned into freefall\n\t\tif ( pm->debugLevel ) {\n\t\t\tCom_Printf(\"%i:lift\\n\", c_pmove);\n\t\t}\n\n\t\t// if they aren't in a jumping animation and the ground is a ways away, force into it\n\t\t// if we didn't do the trace, the player would be backflipping down staircases\n\t\tVectorCopy( pm->ps->origin, point );\n\t\tpoint[2] -= 64;\n\n\t\tpm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask);\n\t\tif ( trace.fraction == 1.0 ) {\n\t\t\tif ( pm->cmd.forwardmove >= 0 ) {\n\t\t\t\tPM_ForceLegsAnim( LEGS_JUMP );\n\t\t\t\tpm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP;\n\t\t\t} else {\n\t\t\t\tPM_ForceLegsAnim( LEGS_JUMPB );\n\t\t\t\tpm->ps->pm_flags |= PMF_BACKWARDS_JUMP;\n\t\t\t}\n\t\t}\n\t}\n\n\tpm->ps->groundEntityNum = ENTITYNUM_NONE;\n\tpml.groundPlane = qfalse;\n\tpml.walking = qfalse;\n}\n\n\n/*\n=============\nPM_GroundTrace\n=============\n*/\nstatic void PM_GroundTrace( void ) {\n\tvec3_t\t\tpoint;\n\ttrace_t\t\ttrace;\n\n\tpoint[0] = pm->ps->origin[0];\n\tpoint[1] = pm->ps->origin[1];\n\tpoint[2] = pm->ps->origin[2] - 0.25;\n\n\tpm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask);\n\tpml.groundTrace = trace;\n\n\t// do something corrective if the trace starts in a solid...\n\tif ( trace.allsolid ) {\n\t\tif ( !PM_CorrectAllSolid(&trace) )\n\t\t\treturn;\n\t}\n\n\t// if the trace didn't hit anything, we are in free fall\n\tif ( trace.fraction == 1.0 ) {\n\t\tPM_GroundTraceMissed();\n\t\tpml.groundPlane = qfalse;\n\t\tpml.walking = qfalse;\n\t\treturn;\n\t}\n\n\t// check if getting thrown off the ground\n\tif ( pm->ps->velocity[2] > 0 && DotProduct( pm->ps->velocity, trace.plane.normal ) > 10 ) {\n\t\tif ( pm->debugLevel ) {\n\t\t\tCom_Printf(\"%i:kickoff\\n\", c_pmove);\n\t\t}\n\t\t// go into jump animation\n\t\tif ( pm->cmd.forwardmove >= 0 ) {\n\t\t\tPM_ForceLegsAnim( LEGS_JUMP );\n\t\t\tpm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP;\n\t\t} else {\n\t\t\tPM_ForceLegsAnim( LEGS_JUMPB );\n\t\t\tpm->ps->pm_flags |= PMF_BACKWARDS_JUMP;\n\t\t}\n\n\t\tpm->ps->groundEntityNum = ENTITYNUM_NONE;\n\t\tpml.groundPlane = qfalse;\n\t\tpml.walking = qfalse;\n\t\treturn;\n\t}\n\t\n\t// slopes that are too steep will not be considered onground\n\tif ( trace.plane.normal[2] < MIN_WALK_NORMAL ) {\n\t\tif ( pm->debugLevel ) {\n\t\t\tCom_Printf(\"%i:steep\\n\", c_pmove);\n\t\t}\n\t\t// FIXME: if they can't slide down the slope, let them\n\t\t// walk (sharp crevices)\n\t\tpm->ps->groundEntityNum = ENTITYNUM_NONE;\n\t\tpml.groundPlane = qtrue;\n\t\tpml.walking = qfalse;\n\t\treturn;\n\t}\n\n\tpml.groundPlane = qtrue;\n\tpml.walking = qtrue;\n\n\t// hitting solid ground will end a waterjump\n\tif (pm->ps->pm_flags & PMF_TIME_WATERJUMP)\n\t{\n\t\tpm->ps->pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND);\n\t\tpm->ps->pm_time = 0;\n\t}\n\n\tif ( pm->ps->groundEntityNum == ENTITYNUM_NONE ) {\n\t\t// just hit the ground\n\t\tif ( pm->debugLevel ) {\n\t\t\tCom_Printf(\"%i:Land\\n\", c_pmove);\n\t\t}\n\t\t\n\t\tPM_CrashLand();\n\n\t\t// don't do landing time if we were just going down a slope\n\t\tif ( pml.previous_velocity[2] < -200 ) {\n\t\t\t// don't allow another jump for a little while\n\t\t\tpm->ps->pm_flags |= PMF_TIME_LAND;\n\t\t\tpm->ps->pm_time = 250;\n\t\t}\n\t}\n\n\tpm->ps->groundEntityNum = trace.entityNum;\n\n\t// don't reset the z velocity for slopes\n//\tpm->ps->velocity[2] = 0;\n\n\tPM_AddTouchEnt( trace.entityNum );\n}\n\n\n/*\n=============\nPM_SetWaterLevel\tFIXME: avoid this twice?  certainly if not moving\n=============\n*/\nstatic void PM_SetWaterLevel( void ) {\n\tvec3_t\t\tpoint;\n\tint\t\t\tcont;\n\tint\t\t\tsample1;\n\tint\t\t\tsample2;\n\n\t//\n\t// get waterlevel, accounting for ducking\n\t//\n\tpm->waterlevel = 0;\n\tpm->watertype = 0;\n\n\tpoint[0] = pm->ps->origin[0];\n\tpoint[1] = pm->ps->origin[1];\n\tpoint[2] = pm->ps->origin[2] + MINS_Z + 1;\t\n\tcont = pm->pointcontents( point, pm->ps->clientNum );\n\n\tif ( cont & MASK_WATER ) {\n\t\tsample2 = pm->ps->viewheight - MINS_Z;\n\t\tsample1 = sample2 / 2;\n\n\t\tpm->watertype = cont;\n\t\tpm->waterlevel = 1;\n\t\tpoint[2] = pm->ps->origin[2] + MINS_Z + sample1;\n\t\tcont = pm->pointcontents (point, pm->ps->clientNum );\n\t\tif ( cont & MASK_WATER ) {\n\t\t\tpm->waterlevel = 2;\n\t\t\tpoint[2] = pm->ps->origin[2] + MINS_Z + sample2;\n\t\t\tcont = pm->pointcontents (point, pm->ps->clientNum );\n\t\t\tif ( cont & MASK_WATER ){\n\t\t\t\tpm->waterlevel = 3;\n\t\t\t}\n\t\t}\n\t}\n\n}\n\n/*\n==============\nPM_CheckDuck\n\nSets mins, maxs, and pm->ps->viewheight\n==============\n*/\nstatic void PM_CheckDuck (void)\n{\n\ttrace_t\ttrace;\n\n\tif ( pm->ps->powerups[PW_INVULNERABILITY] ) {\n\t\tif ( pm->ps->pm_flags & PMF_INVULEXPAND ) {\n\t\t\t// invulnerability sphere has a 42 units radius\n\t\t\tVectorSet( pm->mins, -42, -42, -42 );\n\t\t\tVectorSet( pm->maxs, 42, 42, 42 );\n\t\t}\n\t\telse {\n\t\t\tVectorSet( pm->mins, -15, -15, MINS_Z );\n\t\t\tVectorSet( pm->maxs, 15, 15, 16 );\n\t\t}\n\t\tpm->ps->pm_flags |= PMF_DUCKED;\n\t\tpm->ps->viewheight = CROUCH_VIEWHEIGHT;\n\t\treturn;\n\t}\n\tpm->ps->pm_flags &= ~PMF_INVULEXPAND;\n\n\tpm->mins[0] = -15;\n\tpm->mins[1] = -15;\n\n\tpm->maxs[0] = 15;\n\tpm->maxs[1] = 15;\n\n\tpm->mins[2] = MINS_Z;\n\n\tif (pm->ps->pm_type == PM_DEAD)\n\t{\n\t\tpm->maxs[2] = -8;\n\t\tpm->ps->viewheight = DEAD_VIEWHEIGHT;\n\t\treturn;\n\t}\n\n\tif (pm->cmd.upmove < 0)\n\t{\t// duck\n\t\tpm->ps->pm_flags |= PMF_DUCKED;\n\t}\n\telse\n\t{\t// stand up if possible\n\t\tif (pm->ps->pm_flags & PMF_DUCKED)\n\t\t{\n\t\t\t// try to stand up\n\t\t\tpm->maxs[2] = 32;\n\t\t\tpm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, pm->ps->origin, pm->ps->clientNum, pm->tracemask );\n\t\t\tif (!trace.allsolid)\n\t\t\t\tpm->ps->pm_flags &= ~PMF_DUCKED;\n\t\t}\n\t}\n\n\tif (pm->ps->pm_flags & PMF_DUCKED)\n\t{\n\t\tpm->maxs[2] = 16;\n\t\tpm->ps->viewheight = CROUCH_VIEWHEIGHT;\n\t}\n\telse\n\t{\n\t\tpm->maxs[2] = 32;\n\t\tpm->ps->viewheight = DEFAULT_VIEWHEIGHT;\n\t}\n}\n\n\n\n//===================================================================\n\n\n/*\n===============\nPM_Footsteps\n===============\n*/\nstatic void PM_Footsteps( void ) {\n\tfloat\t\tbobmove;\n\tint\t\t\told;\n\tqboolean\tfootstep;\n\n\t//\n\t// calculate speed and cycle to be used for\n\t// all cyclic walking effects\n\t//\n\tpm->xyspeed = sqrt( pm->ps->velocity[0] * pm->ps->velocity[0]\n\t\t+  pm->ps->velocity[1] * pm->ps->velocity[1] );\n\n\tif ( pm->ps->groundEntityNum == ENTITYNUM_NONE ) {\n\n\t\tif ( pm->ps->powerups[PW_INVULNERABILITY] ) {\n\t\t\tPM_ContinueLegsAnim( LEGS_IDLECR );\n\t\t}\n\t\t// airborne leaves position in cycle intact, but doesn't advance\n\t\tif ( pm->waterlevel > 1 ) {\n\t\t\tPM_ContinueLegsAnim( LEGS_SWIM );\n\t\t}\n\t\treturn;\n\t}\n\n\t// if not trying to move\n\tif ( !pm->cmd.forwardmove && !pm->cmd.rightmove ) {\n\t\tif (  pm->xyspeed < 5 ) {\n\t\t\tpm->ps->bobCycle = 0;\t// start at beginning of cycle again\n\t\t\tif ( pm->ps->pm_flags & PMF_DUCKED ) {\n\t\t\t\tPM_ContinueLegsAnim( LEGS_IDLECR );\n\t\t\t} else {\n\t\t\t\tPM_ContinueLegsAnim( LEGS_IDLE );\n\t\t\t}\n\t\t}\n\t\treturn;\n\t}\n\t\n\n\tfootstep = qfalse;\n\n\tif ( pm->ps->pm_flags & PMF_DUCKED ) {\n\t\tbobmove = 0.5;\t// ducked characters bob much faster\n\t\tif ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) {\n\t\t\tPM_ContinueLegsAnim( LEGS_BACKCR );\n\t\t}\n\t\telse {\n\t\t\tPM_ContinueLegsAnim( LEGS_WALKCR );\n\t\t}\n\t\t// ducked characters never play footsteps\n\t/*\n\t} else \tif ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) {\n\t\tif ( !( pm->cmd.buttons & BUTTON_WALKING ) ) {\n\t\t\tbobmove = 0.4;\t// faster speeds bob faster\n\t\t\tfootstep = qtrue;\n\t\t} else {\n\t\t\tbobmove = 0.3;\n\t\t}\n\t\tPM_ContinueLegsAnim( LEGS_BACK );\n\t*/\n\t} else {\n\t\tif ( !( pm->cmd.buttons & BUTTON_WALKING ) ) {\n\t\t\tbobmove = 0.4f;\t// faster speeds bob faster\n\t\t\tif ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) {\n\t\t\t\tPM_ContinueLegsAnim( LEGS_BACK );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tPM_ContinueLegsAnim( LEGS_RUN );\n\t\t\t}\n\t\t\tfootstep = qtrue;\n\t\t} else {\n\t\t\tbobmove = 0.3f;\t// walking bobs slow\n\t\t\tif ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) {\n\t\t\t\tPM_ContinueLegsAnim( LEGS_BACKWALK );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tPM_ContinueLegsAnim( LEGS_WALK );\n\t\t\t}\n\t\t}\n\t}\n\n\t// check for footstep / splash sounds\n\told = pm->ps->bobCycle;\n\tpm->ps->bobCycle = (int)( old + bobmove * pml.msec ) & 255;\n\n\t// if we just crossed a cycle boundary, play an apropriate footstep event\n\tif ( ( ( old + 64 ) ^ ( pm->ps->bobCycle + 64 ) ) & 128 ) {\n\t\tif ( pm->waterlevel == 0 ) {\n\t\t\t// on ground will only play sounds if running\n\t\t\tif ( footstep && !pm->noFootsteps ) {\n\t\t\t\tPM_AddEvent( PM_FootstepForSurface() );\n\t\t\t}\n\t\t} else if ( pm->waterlevel == 1 ) {\n\t\t\t// splashing\n\t\t\tPM_AddEvent( EV_FOOTSPLASH );\n\t\t} else if ( pm->waterlevel == 2 ) {\n\t\t\t// wading / swimming at surface\n\t\t\tPM_AddEvent( EV_SWIM );\n\t\t} else if ( pm->waterlevel == 3 ) {\n\t\t\t// no sound when completely underwater\n\n\t\t}\n\t}\n}\n\n/*\n==============\nPM_WaterEvents\n\nGenerate sound events for entering and leaving water\n==============\n*/\nstatic void PM_WaterEvents( void ) {\t\t// FIXME?\n\t//\n\t// if just entered a water volume, play a sound\n\t//\n\tif (!pml.previous_waterlevel && pm->waterlevel) {\n\t\tPM_AddEvent( EV_WATER_TOUCH );\n\t}\n\n\t//\n\t// if just completely exited a water volume, play a sound\n\t//\n\tif (pml.previous_waterlevel && !pm->waterlevel) {\n\t\tPM_AddEvent( EV_WATER_LEAVE );\n\t}\n\n\t//\n\t// check for head just going under water\n\t//\n\tif (pml.previous_waterlevel != 3 && pm->waterlevel == 3) {\n\t\tPM_AddEvent( EV_WATER_UNDER );\n\t}\n\n\t//\n\t// check for head just coming out of water\n\t//\n\tif (pml.previous_waterlevel == 3 && pm->waterlevel != 3) {\n\t\tPM_AddEvent( EV_WATER_CLEAR );\n\t}\n}\n\n\n/*\n===============\nPM_BeginWeaponChange\n===============\n*/\nstatic void PM_BeginWeaponChange( int weapon ) {\n\tif ( weapon <= WP_NONE || weapon >= WP_NUM_WEAPONS ) {\n\t\treturn;\n\t}\n\n\tif ( !( pm->ps->stats[STAT_WEAPONS] & ( 1 << weapon ) ) ) {\n\t\treturn;\n\t}\n\t\n\tif ( pm->ps->weaponstate == WEAPON_DROPPING ) {\n\t\treturn;\n\t}\n\n\tPM_AddEvent( EV_CHANGE_WEAPON );\n\tpm->ps->weaponstate = WEAPON_DROPPING;\n\tpm->ps->weaponTime += 200;\n\tPM_StartTorsoAnim( TORSO_DROP );\n}\n\n\n/*\n===============\nPM_FinishWeaponChange\n===============\n*/\nstatic void PM_FinishWeaponChange( void ) {\n\tint\t\tweapon;\n\n\tweapon = pm->cmd.weapon;\n\tif ( weapon < WP_NONE || weapon >= WP_NUM_WEAPONS ) {\n\t\tweapon = WP_NONE;\n\t}\n\n\tif ( !( pm->ps->stats[STAT_WEAPONS] & ( 1 << weapon ) ) ) {\n\t\tweapon = WP_NONE;\n\t}\n\n\tpm->ps->weapon = weapon;\n\tpm->ps->weaponstate = WEAPON_RAISING;\n\tpm->ps->weaponTime += 250;\n\tPM_StartTorsoAnim( TORSO_RAISE );\n}\n\n\n/*\n==============\nPM_TorsoAnimation\n\n==============\n*/\nstatic void PM_TorsoAnimation( void ) {\n\tif ( pm->ps->weaponstate == WEAPON_READY ) {\n\t\tif ( pm->ps->weapon == WP_GAUNTLET ) {\n\t\t\tPM_ContinueTorsoAnim( TORSO_STAND2 );\n\t\t} else {\n\t\t\tPM_ContinueTorsoAnim( TORSO_STAND );\n\t\t}\n\t\treturn;\n\t}\n}\n\n\n/*\n==============\nPM_Weapon\n\nGenerates weapon events and modifes the weapon counter\n==============\n*/\nstatic void PM_Weapon( void ) {\n\tint\t\taddTime;\n\n\t// don't allow attack until all buttons are up\n\tif ( pm->ps->pm_flags & PMF_RESPAWNED ) {\n\t\treturn;\n\t}\n\n\t// ignore if spectator\n\tif ( pm->ps->persistant[PERS_TEAM] == TEAM_SPECTATOR ) {\n\t\treturn;\n\t}\n\n\t// check for dead player\n\tif ( pm->ps->stats[STAT_HEALTH] <= 0 ) {\n\t\tpm->ps->weapon = WP_NONE;\n\t\treturn;\n\t}\n\n\t// check for item using\n\tif ( pm->cmd.buttons & BUTTON_USE_HOLDABLE ) {\n\t\tif ( ! ( pm->ps->pm_flags & PMF_USE_ITEM_HELD ) ) {\n\t\t\tif ( bg_itemlist[pm->ps->stats[STAT_HOLDABLE_ITEM]].giTag == HI_MEDKIT\n\t\t\t\t&& pm->ps->stats[STAT_HEALTH] >= (pm->ps->stats[STAT_MAX_HEALTH] + 25) ) {\n\t\t\t\t// don't use medkit if at max health\n\t\t\t} else {\n\t\t\t\tpm->ps->pm_flags |= PMF_USE_ITEM_HELD;\n\t\t\t\tPM_AddEvent( EV_USE_ITEM0 + bg_itemlist[pm->ps->stats[STAT_HOLDABLE_ITEM]].giTag );\n\t\t\t\tpm->ps->stats[STAT_HOLDABLE_ITEM] = 0;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t} else {\n\t\tpm->ps->pm_flags &= ~PMF_USE_ITEM_HELD;\n\t}\n\n\n\t// make weapon function\n\tif ( pm->ps->weaponTime > 0 ) {\n\t\tpm->ps->weaponTime -= pml.msec;\n\t}\n\n\t// check for weapon change\n\t// can't change if weapon is firing, but can change\n\t// again if lowering or raising\n\tif ( pm->ps->weaponTime <= 0 || pm->ps->weaponstate != WEAPON_FIRING ) {\n\t\tif ( pm->ps->weapon != pm->cmd.weapon ) {\n\t\t\tPM_BeginWeaponChange( pm->cmd.weapon );\n\t\t}\n\t}\n\n\tif ( pm->ps->weaponTime > 0 ) {\n\t\treturn;\n\t}\n\n\t// change weapon if time\n\tif ( pm->ps->weaponstate == WEAPON_DROPPING ) {\n\t\tPM_FinishWeaponChange();\n\t\treturn;\n\t}\n\n\tif ( pm->ps->weaponstate == WEAPON_RAISING ) {\n\t\tpm->ps->weaponstate = WEAPON_READY;\n\t\tif ( pm->ps->weapon == WP_GAUNTLET ) {\n\t\t\tPM_StartTorsoAnim( TORSO_STAND2 );\n\t\t} else {\n\t\t\tPM_StartTorsoAnim( TORSO_STAND );\n\t\t}\n\t\treturn;\n\t}\n\n\t// check for fire\n\tif ( ! (pm->cmd.buttons & BUTTON_ATTACK) ) {\n\t\tpm->ps->weaponTime = 0;\n\t\tpm->ps->weaponstate = WEAPON_READY;\n\t\treturn;\n\t}\n\n\t// start the animation even if out of ammo\n\tif ( pm->ps->weapon == WP_GAUNTLET ) {\n\t\t// the guantlet only \"fires\" when it actually hits something\n\t\tif ( !pm->gauntletHit ) {\n\t\t\tpm->ps->weaponTime = 0;\n\t\t\tpm->ps->weaponstate = WEAPON_READY;\n\t\t\treturn;\n\t\t}\n\t\tPM_StartTorsoAnim( TORSO_ATTACK2 );\n\t} else {\n\t\tPM_StartTorsoAnim( TORSO_ATTACK );\n\t}\n\n\tpm->ps->weaponstate = WEAPON_FIRING;\n\n\t// check for out of ammo\n\tif ( ! pm->ps->ammo[ pm->ps->weapon ] ) {\n\t\tPM_AddEvent( EV_NOAMMO );\n\t\tpm->ps->weaponTime += 500;\n\t\treturn;\n\t}\n\n\t// take an ammo away if not infinite\n\tif ( pm->ps->ammo[ pm->ps->weapon ] != -1 ) {\n\t\tpm->ps->ammo[ pm->ps->weapon ]--;\n\t}\n\n\t// fire weapon\n\tPM_AddEvent( EV_FIRE_WEAPON );\n\n\tswitch( pm->ps->weapon ) {\n\tdefault:\n\tcase WP_GAUNTLET:\n\t\taddTime = 400;\n\t\tbreak;\n\tcase WP_LIGHTNING:\n\t\taddTime = 50;\n\t\tbreak;\n\tcase WP_SHOTGUN:\n\t\taddTime = 1000;\n\t\tbreak;\n\tcase WP_MACHINEGUN:\n\t\taddTime = 100;\n\t\tbreak;\n\tcase WP_GRENADE_LAUNCHER:\n\t\taddTime = 800;\n\t\tbreak;\n\tcase WP_ROCKET_LAUNCHER:\n\t\taddTime = 800;\n\t\tbreak;\n\tcase WP_PLASMAGUN:\n\t\taddTime = 100;\n\t\tbreak;\n\tcase WP_RAILGUN:\n\t\taddTime = 1500;\n\t\tbreak;\n\tcase WP_BFG:\n\t\taddTime = 200;\n\t\tbreak;\n\tcase WP_GRAPPLING_HOOK:\n\t\taddTime = 400;\n\t\tbreak;\n\t}\n\n\tif ( pm->ps->powerups[PW_HASTE] ) {\n\t\taddTime /= 1.3;\n\t}\n\n\tpm->ps->weaponTime += addTime;\n}\n\n/*\n================\nPM_Animate\n================\n*/\n\nstatic void PM_Animate( void ) {\n\tif ( pm->cmd.buttons & BUTTON_GESTURE ) {\n\t\tif ( pm->ps->torsoTimer == 0 ) {\n\t\t\tPM_StartTorsoAnim( TORSO_GESTURE );\n\t\t\tpm->ps->torsoTimer = TIMER_GESTURE;\n\t\t\tPM_AddEvent( EV_TAUNT );\n\t\t}\n\t}\n}\n\n\n/*\n================\nPM_DropTimers\n================\n*/\nstatic void PM_DropTimers( void ) {\n\t// drop misc timing counter\n\tif ( pm->ps->pm_time ) {\n\t\tif ( pml.msec >= pm->ps->pm_time ) {\n\t\t\tpm->ps->pm_flags &= ~PMF_ALL_TIMES;\n\t\t\tpm->ps->pm_time = 0;\n\t\t} else {\n\t\t\tpm->ps->pm_time -= pml.msec;\n\t\t}\n\t}\n\n\t// drop animation counter\n\tif ( pm->ps->legsTimer > 0 ) {\n\t\tpm->ps->legsTimer -= pml.msec;\n\t\tif ( pm->ps->legsTimer < 0 ) {\n\t\t\tpm->ps->legsTimer = 0;\n\t\t}\n\t}\n\n\tif ( pm->ps->torsoTimer > 0 ) {\n\t\tpm->ps->torsoTimer -= pml.msec;\n\t\tif ( pm->ps->torsoTimer < 0 ) {\n\t\t\tpm->ps->torsoTimer = 0;\n\t\t}\n\t}\n}\n\n/*\n================\nPM_UpdateViewAngles\n\nThis can be used as another entry point when only the viewangles\nare being updated isntead of a full move\n================\n*/\nvoid PM_UpdateViewAngles( playerState_t *ps, const usercmd_t *cmd ) {\n\tshort\t\ttemp;\n\tint\t\ti;\n\n\tif ( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_SPINTERMISSION) {\n\t\treturn;\t\t// no view changes at all\n\t}\n\n\tif ( ps->pm_type != PM_SPECTATOR && ps->stats[STAT_HEALTH] <= 0 ) {\n\t\treturn;\t\t// no view changes at all\n\t}\n\n\t// circularly clamp the angles with deltas\n\tfor (i=0 ; i<3 ; i++) {\n\t\ttemp = cmd->angles[i] + ps->delta_angles[i];\n\t\tif ( i == PITCH ) {\n\t\t\t// don't let the player look up or down more than 90 degrees\n\t\t\tif ( temp > 16000 ) {\n\t\t\t\tps->delta_angles[i] = 16000 - cmd->angles[i];\n\t\t\t\ttemp = 16000;\n\t\t\t} else if ( temp < -16000 ) {\n\t\t\t\tps->delta_angles[i] = -16000 - cmd->angles[i];\n\t\t\t\ttemp = -16000;\n\t\t\t}\n\t\t}\n\t\tps->viewangles[i] = SHORT2ANGLE(temp);\n\t}\n\n}\n\n\n/*\n================\nPmoveSingle\n\n================\n*/\nvoid trap_SnapVector( float *v );\n\nvoid PmoveSingle (pmove_t *pmove) {\n\tpm = pmove;\n\n\t// this counter lets us debug movement problems with a journal\n\t// by setting a conditional breakpoint fot the previous frame\n\tc_pmove++;\n\n\t// clear results\n\tpm->numtouch = 0;\n\tpm->watertype = 0;\n\tpm->waterlevel = 0;\n\n\tif ( pm->ps->stats[STAT_HEALTH] <= 0 ) {\n\t\tpm->tracemask &= ~CONTENTS_BODY;\t// corpses can fly through bodies\n\t}\n\n\t// make sure walking button is clear if they are running, to avoid\n\t// proxy no-footsteps cheats\n\tif ( abs( pm->cmd.forwardmove ) > 64 || abs( pm->cmd.rightmove ) > 64 ) {\n\t\tpm->cmd.buttons &= ~BUTTON_WALKING;\n\t}\n\n\t// set the talk balloon flag\n\tif ( pm->cmd.buttons & BUTTON_TALK ) {\n\t\tpm->ps->eFlags |= EF_TALK;\n\t} else {\n\t\tpm->ps->eFlags &= ~EF_TALK;\n\t}\n\n\t// set the firing flag for continuous beam weapons\n\tif ( !(pm->ps->pm_flags & PMF_RESPAWNED) && pm->ps->pm_type != PM_INTERMISSION\n\t\t&& ( pm->cmd.buttons & BUTTON_ATTACK ) && pm->ps->ammo[ pm->ps->weapon ] ) {\n\t\tpm->ps->eFlags |= EF_FIRING;\n\t} else {\n\t\tpm->ps->eFlags &= ~EF_FIRING;\n\t}\n\n\t// clear the respawned flag if attack and use are cleared\n\tif ( pm->ps->stats[STAT_HEALTH] > 0 && \n\t\t!( pm->cmd.buttons & (BUTTON_ATTACK | BUTTON_USE_HOLDABLE) ) ) {\n\t\tpm->ps->pm_flags &= ~PMF_RESPAWNED;\n\t}\n\n\t// if talk button is down, dissallow all other input\n\t// this is to prevent any possible intercept proxy from\n\t// adding fake talk balloons\n\tif ( pmove->cmd.buttons & BUTTON_TALK ) {\n\t\t// keep the talk button set tho for when the cmd.serverTime > 66 msec\n\t\t// and the same cmd is used multiple times in Pmove\n\t\tpmove->cmd.buttons = BUTTON_TALK;\n\t\tpmove->cmd.forwardmove = 0;\n\t\tpmove->cmd.rightmove = 0;\n\t\tpmove->cmd.upmove = 0;\n\t}\n\n\t// clear all pmove local vars\n\tmemset (&pml, 0, sizeof(pml));\n\n\t// determine the time\n\tpml.msec = pmove->cmd.serverTime - pm->ps->commandTime;\n\tif ( pml.msec < 1 ) {\n\t\tpml.msec = 1;\n\t} else if ( pml.msec > 200 ) {\n\t\tpml.msec = 200;\n\t}\n\tpm->ps->commandTime = pmove->cmd.serverTime;\n\n\t// save old org in case we get stuck\n\tVectorCopy (pm->ps->origin, pml.previous_origin);\n\n\t// save old velocity for crashlanding\n\tVectorCopy (pm->ps->velocity, pml.previous_velocity);\n\n\tpml.frametime = pml.msec * 0.001;\n\n\t// update the viewangles\n\tPM_UpdateViewAngles( pm->ps, &pm->cmd );\n\n\tAngleVectors (pm->ps->viewangles, pml.forward, pml.right, pml.up);\n\n\tif ( pm->cmd.upmove < 10 ) {\n\t\t// not holding jump\n\t\tpm->ps->pm_flags &= ~PMF_JUMP_HELD;\n\t}\n\n\t// decide if backpedaling animations should be used\n\tif ( pm->cmd.forwardmove < 0 ) {\n\t\tpm->ps->pm_flags |= PMF_BACKWARDS_RUN;\n\t} else if ( pm->cmd.forwardmove > 0 || ( pm->cmd.forwardmove == 0 && pm->cmd.rightmove ) ) {\n\t\tpm->ps->pm_flags &= ~PMF_BACKWARDS_RUN;\n\t}\n\n\tif ( pm->ps->pm_type >= PM_DEAD ) {\n\t\tpm->cmd.forwardmove = 0;\n\t\tpm->cmd.rightmove = 0;\n\t\tpm->cmd.upmove = 0;\n\t}\n\n\tif ( pm->ps->pm_type == PM_SPECTATOR ) {\n\t\tPM_CheckDuck ();\n\t\tPM_FlyMove ();\n\t\tPM_DropTimers ();\n\t\treturn;\n\t}\n\n\tif ( pm->ps->pm_type == PM_NOCLIP ) {\n\t\tPM_NoclipMove ();\n\t\tPM_DropTimers ();\n\t\treturn;\n\t}\n\n\tif (pm->ps->pm_type == PM_FREEZE) {\n\t\treturn;\t\t// no movement at all\n\t}\n\n\tif ( pm->ps->pm_type == PM_INTERMISSION || pm->ps->pm_type == PM_SPINTERMISSION) {\n\t\treturn;\t\t// no movement at all\n\t}\n\n\t// set watertype, and waterlevel\n\tPM_SetWaterLevel();\n\tpml.previous_waterlevel = pmove->waterlevel;\n\n\t// set mins, maxs, and viewheight\n\tPM_CheckDuck ();\n\n\t// set groundentity\n\tPM_GroundTrace();\n\n\tif ( pm->ps->pm_type == PM_DEAD ) {\n\t\tPM_DeadMove ();\n\t}\n\n\tPM_DropTimers();\n\n\tif ( pm->ps->powerups[PW_FLIGHT] ) {\n\t\t// flight powerup doesn't allow jump and has different friction\n\t\tPM_FlyMove();\n\t} else if (pm->ps->pm_flags & PMF_GRAPPLE_PULL) {\n\t\tPM_GrappleMove();\n\t\t// We can wiggle a bit\n\t\tPM_AirMove();\n\t} else if (pm->ps->pm_flags & PMF_TIME_WATERJUMP) {\n\t\tPM_WaterJumpMove();\n\t} else if ( pm->waterlevel > 1 ) {\n\t\t// swimming\n\t\tPM_WaterMove();\n\t} else if ( pml.walking ) {\n\t\t// walking on ground\n\t\tPM_WalkMove();\n\t} else {\n\t\t// airborne\n\t\tPM_AirMove();\n\t}\n\n\tPM_Animate();\n\n\t// set groundentity, watertype, and waterlevel\n\tPM_GroundTrace();\n\tPM_SetWaterLevel();\n\n\t// weapons\n\tPM_Weapon();\n\n\t// torso animation\n\tPM_TorsoAnimation();\n\n\t// footstep events / legs animations\n\tPM_Footsteps();\n\n\t// entering / leaving water splashes\n\tPM_WaterEvents();\n\n\t// snap some parts of playerstate to save network bandwidth\n\ttrap_SnapVector( pm->ps->velocity );\n}\n\n\n/*\n================\nPmove\n\nCan be called by either the server or the client\n================\n*/\nvoid Pmove (pmove_t *pmove) {\n\tint\t\t\tfinalTime;\n\n\tfinalTime = pmove->cmd.serverTime;\n\n\tif ( finalTime < pmove->ps->commandTime ) {\n\t\treturn;\t// should not happen\n\t}\n\n\tif ( finalTime > pmove->ps->commandTime + 1000 ) {\n\t\tpmove->ps->commandTime = finalTime - 1000;\n\t}\n\n\tpmove->ps->pmove_framecount = (pmove->ps->pmove_framecount+1) & ((1<<PS_PMOVEFRAMECOUNTBITS)-1);\n\n\t// chop the move up if it is too long, to prevent framerate\n\t// dependent behavior\n\twhile ( pmove->ps->commandTime != finalTime ) {\n\t\tint\t\tmsec;\n\n\t\tmsec = finalTime - pmove->ps->commandTime;\n\n\t\tif ( pmove->pmove_fixed ) {\n\t\t\tif ( msec > pmove->pmove_msec ) {\n\t\t\t\tmsec = pmove->pmove_msec;\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tif ( msec > 66 ) {\n\t\t\t\tmsec = 66;\n\t\t\t}\n\t\t}\n\t\tpmove->cmd.serverTime = pmove->ps->commandTime + msec;\n\t\tPmoveSingle( pmove );\n\n\t\tif ( pmove->ps->pm_flags & PMF_JUMP_HELD ) {\n\t\t\tpmove->cmd.upmove = 20;\n\t\t}\n\t}\n\n\t//PM_CheckStuck();\n\n}\n\n"
  },
  {
    "path": "src/game/bg_public.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n// bg_public.h -- definitions shared by both the server game and client game modules\n\n// because games can change separately from the main system version, we need a\n// second version that must match between game and cgame\n\n#define\tGAME_VERSION\t\t\"baseq3-1\"\n\n#define\tDEFAULT_GRAVITY\t\t800\n#define\tGIB_HEALTH\t\t\t-40\n#define\tARMOR_PROTECTION\t0.66\n\n#define\tMAX_ITEMS\t\t\t256\n\n#define\tRANK_TIED_FLAG\t\t0x4000\n\n#define DEFAULT_SHOTGUN_SPREAD\t700\n#define DEFAULT_SHOTGUN_COUNT\t11\n\n#define\tITEM_RADIUS\t\t\t15\t\t// item sizes are needed for client side pickup detection\n\n#define\tLIGHTNING_RANGE\t\t768\n\n#define\tSCORE_NOT_PRESENT\t-9999\t// for the CS_SCORES[12] when only one player is present\n\n#define\tVOTE_TIME\t\t\t30000\t// 30 seconds before vote times out\n\n#define\tMINS_Z\t\t\t\t-24\n#define\tDEFAULT_VIEWHEIGHT\t26\n#define CROUCH_VIEWHEIGHT\t12\n#define\tDEAD_VIEWHEIGHT\t\t-16\n\n//\n// config strings are a general means of communicating variable length strings\n// from the server to all connected clients.\n//\n\n// CS_SERVERINFO and CS_SYSTEMINFO are defined in q_shared.h\n#define\tCS_MUSIC\t\t\t\t2\n#define\tCS_MESSAGE\t\t\t\t3\t\t// from the map worldspawn's message field\n#define\tCS_MOTD\t\t\t\t\t4\t\t// g_motd string for server message of the day\n#define\tCS_WARMUP\t\t\t\t5\t\t// server time when the match will be restarted\n#define\tCS_SCORES1\t\t\t\t6\n#define\tCS_SCORES2\t\t\t\t7\n#define CS_VOTE_TIME\t\t\t8\n#define CS_VOTE_STRING\t\t\t9\n#define\tCS_VOTE_YES\t\t\t\t10\n#define\tCS_VOTE_NO\t\t\t\t11\n\n#define CS_TEAMVOTE_TIME\t\t12\n#define CS_TEAMVOTE_STRING\t\t14\n#define\tCS_TEAMVOTE_YES\t\t\t16\n#define\tCS_TEAMVOTE_NO\t\t\t18\n\n#define\tCS_GAME_VERSION\t\t\t20\n#define\tCS_LEVEL_START_TIME\t\t21\t\t// so the timer only shows the current level\n#define\tCS_INTERMISSION\t\t\t22\t\t// when 1, fraglimit/timelimit has been hit and intermission will start in a second or two\n#define CS_FLAGSTATUS\t\t\t23\t\t// string indicating flag status in CTF\n#define CS_SHADERSTATE\t\t\t24\n#define CS_BOTINFO\t\t\t\t25\n\n#define\tCS_ITEMS\t\t\t\t27\t\t// string of 0's and 1's that tell which items are present\n\n#define\tCS_MODELS\t\t\t\t32\n#define\tCS_SOUNDS\t\t\t\t(CS_MODELS+MAX_MODELS)\n#define\tCS_PLAYERS\t\t\t\t(CS_SOUNDS+MAX_SOUNDS)\n#define CS_LOCATIONS\t\t\t(CS_PLAYERS+MAX_CLIENTS)\n#define CS_PARTICLES\t\t\t(CS_LOCATIONS+MAX_LOCATIONS) \n\n#define CS_MAX\t\t\t\t\t(CS_PARTICLES+MAX_LOCATIONS)\n\n#if (CS_MAX) > MAX_CONFIGSTRINGS\n#error overflow: (CS_MAX) > MAX_CONFIGSTRINGS\n#endif\n\ntypedef enum {\n\tGT_FFA,\t\t\t\t// free for all\n\tGT_TOURNAMENT,\t\t// one on one tournament\n\tGT_SINGLE_PLAYER,\t// single player ffa\n\n\t//-- team games go after this --\n\n\tGT_TEAM,\t\t\t// team deathmatch\n\tGT_CTF,\t\t\t\t// capture the flag\n\tGT_1FCTF,\n\tGT_OBELISK,\n\tGT_HARVESTER,\n\tGT_MAX_GAME_TYPE\n} gametype_t;\n\ntypedef enum { GENDER_MALE, GENDER_FEMALE, GENDER_NEUTER } gender_t;\n\n/*\n===================================================================================\n\nPMOVE MODULE\n\nThe pmove code takes a player_state_t and a usercmd_t and generates a new player_state_t\nand some other output data.  Used for local prediction on the client game and true\nmovement on the server game.\n===================================================================================\n*/\n\ntypedef enum {\n\tPM_NORMAL,\t\t// can accelerate and turn\n\tPM_NOCLIP,\t\t// noclip movement\n\tPM_SPECTATOR,\t// still run into walls\n\tPM_DEAD,\t\t// no acceleration or turning, but free falling\n\tPM_FREEZE,\t\t// stuck in place with no control\n\tPM_INTERMISSION,\t// no movement or status bar\n\tPM_SPINTERMISSION\t// no movement or status bar\n} pmtype_t;\n\ntypedef enum {\n\tWEAPON_READY, \n\tWEAPON_RAISING,\n\tWEAPON_DROPPING,\n\tWEAPON_FIRING\n} weaponstate_t;\n\n// pmove->pm_flags\n#define\tPMF_DUCKED\t\t\t1\n#define\tPMF_JUMP_HELD\t\t2\n#define\tPMF_BACKWARDS_JUMP\t8\t\t// go into backwards land\n#define\tPMF_BACKWARDS_RUN\t16\t\t// coast down to backwards run\n#define\tPMF_TIME_LAND\t\t32\t\t// pm_time is time before rejump\n#define\tPMF_TIME_KNOCKBACK\t64\t\t// pm_time is an air-accelerate only time\n#define\tPMF_TIME_WATERJUMP\t256\t\t// pm_time is waterjump\n#define\tPMF_RESPAWNED\t\t512\t\t// clear after attack and jump buttons come up\n#define\tPMF_USE_ITEM_HELD\t1024\n#define PMF_GRAPPLE_PULL\t2048\t// pull towards grapple location\n#define PMF_FOLLOW\t\t\t4096\t// spectate following another player\n#define PMF_SCOREBOARD\t\t8192\t// spectate as a scoreboard\n#define PMF_INVULEXPAND\t\t16384\t// invulnerability sphere set to full size\n\n#define\tPMF_ALL_TIMES\t(PMF_TIME_WATERJUMP|PMF_TIME_LAND|PMF_TIME_KNOCKBACK)\n\n#define\tMAXTOUCH\t32\ntypedef struct {\n\t// state (in / out)\n\tplayerState_t\t*ps;\n\n\t// command (in)\n\tusercmd_t\tcmd;\n\tint\t\t\ttracemask;\t\t\t// collide against these types of surfaces\n\tint\t\t\tdebugLevel;\t\t\t// if set, diagnostic output will be printed\n\tqboolean\tnoFootsteps;\t\t// if the game is setup for no footsteps by the server\n\tqboolean\tgauntletHit;\t\t// true if a gauntlet attack would actually hit something\n\n\tint\t\t\tframecount;\n\n\t// results (out)\n\tint\t\t\tnumtouch;\n\tint\t\t\ttouchents[MAXTOUCH];\n\n\tvec3_t\t\tmins, maxs;\t\t\t// bounding box size\n\n\tint\t\t\twatertype;\n\tint\t\t\twaterlevel;\n\n\tfloat\t\txyspeed;\n\n\t// for fixed msec Pmove\n\tint\t\t\tpmove_fixed;\n\tint\t\t\tpmove_msec;\n\n\t// callbacks to test the world\n\t// these will be different functions during game and cgame\n\tvoid\t\t(*trace)( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentMask );\n\tint\t\t\t(*pointcontents)( const vec3_t point, int passEntityNum );\n} pmove_t;\n\n// if a full pmove isn't done on the client, you can just update the angles\nvoid PM_UpdateViewAngles( playerState_t *ps, const usercmd_t *cmd );\nvoid Pmove (pmove_t *pmove);\n\n//===================================================================================\n\n\n// player_state->stats[] indexes\n// NOTE: may not have more than 16\ntypedef enum {\n\tSTAT_HEALTH,\n\tSTAT_HOLDABLE_ITEM,\n\tSTAT_WEAPONS,\t\t\t\t\t// 16 bit fields\n\tSTAT_ARMOR,\t\t\t\t\n\tSTAT_DEAD_YAW,\t\t\t\t\t// look this direction when dead (FIXME: get rid of?)\n\tSTAT_CLIENTS_READY,\t\t\t\t// bit mask of clients wishing to exit the intermission (FIXME: configstring?)\n\tSTAT_MAX_HEALTH\t\t\t\t\t// health / armor limit, changable by handicap\n} statIndex_t;\n\n\n// player_state->persistant[] indexes\n// these fields are the only part of player_state that isn't\n// cleared on respawn\n// NOTE: may not have more than 16\ntypedef enum {\n\tPERS_SCORE,\t\t\t\t\t\t// !!! MUST NOT CHANGE, SERVER AND GAME BOTH REFERENCE !!!\n\tPERS_HITS,\t\t\t\t\t\t// total points damage inflicted so damage beeps can sound on change\n\tPERS_RANK,\t\t\t\t\t\t// player rank or team rank\n\tPERS_TEAM,\t\t\t\t\t\t// player team\n\tPERS_SPAWN_COUNT,\t\t\t\t// incremented every respawn\n\tPERS_PLAYEREVENTS,\t\t\t\t// 16 bits that can be flipped for events\n\tPERS_ATTACKER,\t\t\t\t\t// clientnum of last damage inflicter\n\tPERS_ATTACKEE_ARMOR,\t\t\t// health/armor of last person we attacked\n\tPERS_KILLED,\t\t\t\t\t// count of the number of times you died\n\t// player awards tracking\n\tPERS_IMPRESSIVE_COUNT,\t\t\t// two railgun hits in a row\n\tPERS_EXCELLENT_COUNT,\t\t\t// two successive kills in a short amount of time\n\tPERS_DEFEND_COUNT,\t\t\t\t// defend awards\n\tPERS_ASSIST_COUNT,\t\t\t\t// assist awards\n\tPERS_GAUNTLET_FRAG_COUNT,\t\t// kills with the guantlet\n\tPERS_CAPTURES\t\t\t\t\t// captures\n} persEnum_t;\n\n\n// entityState_t->eFlags\n#define\tEF_DEAD\t\t\t\t0x00000001\t\t// don't draw a foe marker over players with EF_DEAD\n#define\tEF_TELEPORT_BIT\t\t0x00000004\t\t// toggled every time the origin abruptly changes\n#define\tEF_AWARD_EXCELLENT\t0x00000008\t\t// draw an excellent sprite\n#define EF_PLAYER_EVENT\t\t0x00000010\n#define\tEF_BOUNCE\t\t\t0x00000010\t\t// for missiles\n#define\tEF_BOUNCE_HALF\t\t0x00000020\t\t// for missiles\n#define\tEF_AWARD_GAUNTLET\t0x00000040\t\t// draw a gauntlet sprite\n#define\tEF_NODRAW\t\t\t0x00000080\t\t// may have an event, but no model (unspawned items)\n#define\tEF_FIRING\t\t\t0x00000100\t\t// for lightning gun\n#define\tEF_KAMIKAZE\t\t\t0x00000200\n#define\tEF_MOVER_STOP\t\t0x00000400\t\t// will push otherwise\n#define EF_AWARD_CAP\t\t0x00000800\t\t// draw the capture sprite\n#define\tEF_TALK\t\t\t\t0x00001000\t\t// draw a talk balloon\n#define\tEF_CONNECTION\t\t0x00002000\t\t// draw a connection trouble sprite\n#define\tEF_VOTED\t\t\t0x00004000\t\t// already cast a vote\n#define\tEF_AWARD_IMPRESSIVE\t0x00008000\t\t// draw an impressive sprite\n#define\tEF_AWARD_DEFEND\t\t0x00010000\t\t// draw a defend sprite\n#define\tEF_AWARD_ASSIST\t\t0x00020000\t\t// draw a assist sprite\n#define EF_AWARD_DENIED\t\t0x00040000\t\t// denied\n#define EF_TEAMVOTED\t\t0x00080000\t\t// already cast a team vote\n\n// NOTE: may not have more than 16\ntypedef enum {\n\tPW_NONE,\n\n\tPW_QUAD,\n\tPW_BATTLESUIT,\n\tPW_HASTE,\n\tPW_INVIS,\n\tPW_REGEN,\n\tPW_FLIGHT,\n\n\tPW_REDFLAG,\n\tPW_BLUEFLAG,\n\tPW_NEUTRALFLAG,\n\n\tPW_SCOUT,\n\tPW_GUARD,\n\tPW_DOUBLER,\n\tPW_AMMOREGEN,\n\tPW_INVULNERABILITY,\n\n\tPW_NUM_POWERUPS\n\n} powerup_t;\n\ntypedef enum {\n\tHI_NONE,\n\n\tHI_TELEPORTER,\n\tHI_MEDKIT,\n\tHI_KAMIKAZE,\n\tHI_PORTAL,\n\tHI_INVULNERABILITY,\n\n\tHI_NUM_HOLDABLE\n} holdable_t;\n\n\ntypedef enum {\n\tWP_NONE,\n\n\tWP_GAUNTLET,\n\tWP_MACHINEGUN,\n\tWP_SHOTGUN,\n\tWP_GRENADE_LAUNCHER,\n\tWP_ROCKET_LAUNCHER,\n\tWP_LIGHTNING,\n\tWP_RAILGUN,\n\tWP_PLASMAGUN,\n\tWP_BFG,\n\tWP_GRAPPLING_HOOK,\n\n\tWP_NUM_WEAPONS\n} weapon_t;\n\n\n// reward sounds (stored in ps->persistant[PERS_PLAYEREVENTS])\n#define\tPLAYEREVENT_DENIEDREWARD\t\t0x0001\n#define\tPLAYEREVENT_GAUNTLETREWARD\t\t0x0002\n#define PLAYEREVENT_HOLYSHIT\t\t\t0x0004\n\n// entityState_t->event values\n// entity events are for effects that take place reletive\n// to an existing entities origin.  Very network efficient.\n\n// two bits at the top of the entityState->event field\n// will be incremented with each change in the event so\n// that an identical event started twice in a row can\n// be distinguished.  And off the value with ~EV_EVENT_BITS\n// to retrieve the actual event number\n#define\tEV_EVENT_BIT1\t\t0x00000100\n#define\tEV_EVENT_BIT2\t\t0x00000200\n#define\tEV_EVENT_BITS\t\t(EV_EVENT_BIT1|EV_EVENT_BIT2)\n\n#define\tEVENT_VALID_MSEC\t300\n\ntypedef enum {\n\tEV_NONE,\n\n\tEV_FOOTSTEP,\n\tEV_FOOTSTEP_METAL,\n\tEV_FOOTSPLASH,\n\tEV_FOOTWADE,\n\tEV_SWIM,\n\n\tEV_STEP_4,\n\tEV_STEP_8,\n\tEV_STEP_12,\n\tEV_STEP_16,\n\n\tEV_FALL_SHORT,\n\tEV_FALL_MEDIUM,\n\tEV_FALL_FAR,\n\n\tEV_JUMP_PAD,\t\t\t// boing sound at origin, jump sound on player\n\n\tEV_JUMP,\n\tEV_WATER_TOUCH,\t// foot touches\n\tEV_WATER_LEAVE,\t// foot leaves\n\tEV_WATER_UNDER,\t// head touches\n\tEV_WATER_CLEAR,\t// head leaves\n\n\tEV_ITEM_PICKUP,\t\t\t// normal item pickups are predictable\n\tEV_GLOBAL_ITEM_PICKUP,\t// powerup / team sounds are broadcast to everyone\n\n\tEV_NOAMMO,\n\tEV_CHANGE_WEAPON,\n\tEV_FIRE_WEAPON,\n\n\tEV_USE_ITEM0,\n\tEV_USE_ITEM1,\n\tEV_USE_ITEM2,\n\tEV_USE_ITEM3,\n\tEV_USE_ITEM4,\n\tEV_USE_ITEM5,\n\tEV_USE_ITEM6,\n\tEV_USE_ITEM7,\n\tEV_USE_ITEM8,\n\tEV_USE_ITEM9,\n\tEV_USE_ITEM10,\n\tEV_USE_ITEM11,\n\tEV_USE_ITEM12,\n\tEV_USE_ITEM13,\n\tEV_USE_ITEM14,\n\tEV_USE_ITEM15,\n\n\tEV_ITEM_RESPAWN,\n\tEV_ITEM_POP,\n\tEV_PLAYER_TELEPORT_IN,\n\tEV_PLAYER_TELEPORT_OUT,\n\n\tEV_GRENADE_BOUNCE,\t\t// eventParm will be the soundindex\n\n\tEV_GENERAL_SOUND,\n\tEV_GLOBAL_SOUND,\t\t// no attenuation\n\tEV_GLOBAL_TEAM_SOUND,\n\n\tEV_BULLET_HIT_FLESH,\n\tEV_BULLET_HIT_WALL,\n\n\tEV_MISSILE_HIT,\n\tEV_MISSILE_MISS,\n\tEV_MISSILE_MISS_METAL,\n\tEV_RAILTRAIL,\n\tEV_SHOTGUN,\n\tEV_BULLET,\t\t\t\t// otherEntity is the shooter\n\n\tEV_PAIN,\n\tEV_DEATH1,\n\tEV_DEATH2,\n\tEV_DEATH3,\n\tEV_OBITUARY,\n\n\tEV_POWERUP_QUAD,\n\tEV_POWERUP_BATTLESUIT,\n\tEV_POWERUP_REGEN,\n\n\tEV_GIB_PLAYER,\t\t\t// gib a previously living player\n\tEV_SCOREPLUM,\t\t\t// score plum\n\n\tEV_DEBUG_LINE,\n\tEV_STOPLOOPINGSOUND,\n\tEV_TAUNT,\n\tEV_TAUNT_YES,\n\tEV_TAUNT_NO,\n\tEV_TAUNT_FOLLOWME,\n\tEV_TAUNT_GETFLAG,\n\tEV_TAUNT_GUARDBASE,\n\tEV_TAUNT_PATROL\n\n} entity_event_t;\n\n\ntypedef enum {\n\tGTS_RED_CAPTURE,\n\tGTS_BLUE_CAPTURE,\n\tGTS_RED_RETURN,\n\tGTS_BLUE_RETURN,\n\tGTS_RED_TAKEN,\n\tGTS_BLUE_TAKEN,\n\tGTS_REDOBELISK_ATTACKED,\n\tGTS_BLUEOBELISK_ATTACKED,\n\tGTS_REDTEAM_SCORED,\n\tGTS_BLUETEAM_SCORED,\n\tGTS_REDTEAM_TOOK_LEAD,\n\tGTS_BLUETEAM_TOOK_LEAD,\n\tGTS_TEAMS_ARE_TIED,\n\tGTS_KAMIKAZE\n} global_team_sound_t;\n\n// animations\ntypedef enum {\n\tBOTH_DEATH1,\n\tBOTH_DEAD1,\n\tBOTH_DEATH2,\n\tBOTH_DEAD2,\n\tBOTH_DEATH3,\n\tBOTH_DEAD3,\n\n\tTORSO_GESTURE,\n\n\tTORSO_ATTACK,\n\tTORSO_ATTACK2,\n\n\tTORSO_DROP,\n\tTORSO_RAISE,\n\n\tTORSO_STAND,\n\tTORSO_STAND2,\n\n\tLEGS_WALKCR,\n\tLEGS_WALK,\n\tLEGS_RUN,\n\tLEGS_BACK,\n\tLEGS_SWIM,\n\n\tLEGS_JUMP,\n\tLEGS_LAND,\n\n\tLEGS_JUMPB,\n\tLEGS_LANDB,\n\n\tLEGS_IDLE,\n\tLEGS_IDLECR,\n\n\tLEGS_TURN,\n\n\tTORSO_GETFLAG,\n\tTORSO_GUARDBASE,\n\tTORSO_PATROL,\n\tTORSO_FOLLOWME,\n\tTORSO_AFFIRMATIVE,\n\tTORSO_NEGATIVE,\n\n\tMAX_ANIMATIONS,\n\n\tLEGS_BACKCR,\n\tLEGS_BACKWALK,\n\tFLAG_RUN,\n\tFLAG_STAND,\n\tFLAG_STAND2RUN,\n\n\tMAX_TOTALANIMATIONS\n} animNumber_t;\n\n\ntypedef struct animation_s {\n\tint\t\tfirstFrame;\n\tint\t\tnumFrames;\n\tint\t\tloopFrames;\t\t\t// 0 to numFrames\n\tint\t\tframeLerp;\t\t\t// msec between frames\n\tint\t\tinitialLerp;\t\t// msec to get to first frame\n\tint\t\treversed;\t\t\t// true if animation is reversed\n\tint\t\tflipflop;\t\t\t// true if animation should flipflop back to base\n} animation_t;\n\n\n// flip the togglebit every time an animation\n// changes so a restart of the same anim can be detected\n#define\tANIM_TOGGLEBIT\t\t128\n\n\ntypedef enum {\n\tTEAM_FREE,\n\tTEAM_RED,\n\tTEAM_BLUE,\n\tTEAM_SPECTATOR,\n\n\tTEAM_NUM_TEAMS\n} team_t;\n\n// Time between location updates\n#define TEAM_LOCATION_UPDATE_TIME\t\t1000\n\n// How many players on the overlay\n#define TEAM_MAXOVERLAY\t\t32\n\n//team task\ntypedef enum {\n\tTEAMTASK_NONE,\n\tTEAMTASK_OFFENSE, \n\tTEAMTASK_DEFENSE,\n\tTEAMTASK_PATROL,\n\tTEAMTASK_FOLLOW,\n\tTEAMTASK_RETRIEVE,\n\tTEAMTASK_ESCORT,\n\tTEAMTASK_CAMP\n} teamtask_t;\n\n// means of death\ntypedef enum {\n\tMOD_UNKNOWN,\n\tMOD_SHOTGUN,\n\tMOD_GAUNTLET,\n\tMOD_MACHINEGUN,\n\tMOD_GRENADE,\n\tMOD_GRENADE_SPLASH,\n\tMOD_ROCKET,\n\tMOD_ROCKET_SPLASH,\n\tMOD_PLASMA,\n\tMOD_PLASMA_SPLASH,\n\tMOD_RAILGUN,\n\tMOD_LIGHTNING,\n\tMOD_BFG,\n\tMOD_BFG_SPLASH,\n\tMOD_WATER,\n\tMOD_SLIME,\n\tMOD_LAVA,\n\tMOD_CRUSH,\n\tMOD_TELEFRAG,\n\tMOD_FALLING,\n\tMOD_SUICIDE,\n\tMOD_TARGET_LASER,\n\tMOD_TRIGGER_HURT,\n\tMOD_GRAPPLE\n} meansOfDeath_t;\n\n\n//---------------------------------------------------------\n\n// gitem_t->type\ntypedef enum {\n\tIT_BAD,\n\tIT_WEAPON,\t\t\t\t// EFX: rotate + upscale + minlight\n\tIT_AMMO,\t\t\t\t// EFX: rotate\n\tIT_ARMOR,\t\t\t\t// EFX: rotate + minlight\n\tIT_HEALTH,\t\t\t\t// EFX: static external sphere + rotating internal\n\tIT_POWERUP,\t\t\t\t// instant on, timer based\n\t\t\t\t\t\t\t// EFX: rotate + external ring that rotates\n\tIT_HOLDABLE,\t\t\t// single use, holdable item\n\t\t\t\t\t\t\t// EFX: rotate + bob\n\tIT_PERSISTANT_POWERUP,\n\tIT_TEAM\n} itemType_t;\n\n#define MAX_ITEM_MODELS 4\n\ntypedef struct gitem_s {\n\tchar\t\t*classname;\t// spawning name\n\tchar\t\t*pickup_sound;\n\tchar\t\t*world_model[MAX_ITEM_MODELS];\n\n\tchar\t\t*icon;\n\tchar\t\t*pickup_name;\t// for printing on pickup\n\n\tint\t\t\tquantity;\t\t// for ammo how much, or duration of powerup\n\titemType_t  giType;\t\t\t// IT_* flags\n\n\tint\t\t\tgiTag;\n\n\tchar\t\t*precaches;\t\t// string of all models and images this item will use\n\tchar\t\t*sounds;\t\t// string of all sounds this item will use\n} gitem_t;\n\n// included in both the game dll and the client\nextern\tgitem_t\tbg_itemlist[];\nextern\tint\t\tbg_numItems;\n\ngitem_t\t*BG_FindItem( const char *pickupName );\ngitem_t\t*BG_FindItemForWeapon( weapon_t weapon );\ngitem_t\t*BG_FindItemForPowerup( powerup_t pw );\ngitem_t\t*BG_FindItemForHoldable( holdable_t pw );\n#define\tITEM_INDEX(x) ((x)-bg_itemlist)\n\nqboolean\tBG_CanItemBeGrabbed( int gametype, const entityState_t *ent, const playerState_t *ps );\n\n\n// g_dmflags->integer flags\n#define\tDF_NO_FALLING\t\t\t8\n#define DF_FIXED_FOV\t\t\t16\n#define\tDF_NO_FOOTSTEPS\t\t\t32\n\n// content masks\n#define\tMASK_ALL\t\t\t\t(-1)\n#define\tMASK_SOLID\t\t\t\t(CONTENTS_SOLID)\n#define\tMASK_PLAYERSOLID\t\t(CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_BODY)\n#define\tMASK_DEADSOLID\t\t\t(CONTENTS_SOLID|CONTENTS_PLAYERCLIP)\n#define\tMASK_WATER\t\t\t\t(CONTENTS_WATER|CONTENTS_LAVA|CONTENTS_SLIME)\n#define\tMASK_OPAQUE\t\t\t\t(CONTENTS_SOLID|CONTENTS_SLIME|CONTENTS_LAVA)\n#define\tMASK_SHOT\t\t\t\t(CONTENTS_SOLID|CONTENTS_BODY|CONTENTS_CORPSE)\n\n\n//\n// entityState_t->eType\n//\ntypedef enum {\n\tET_GENERAL,\n\tET_PLAYER,\n\tET_ITEM,\n\tET_MISSILE,\n\tET_MOVER,\n\tET_BEAM,\n\tET_PORTAL,\n\tET_SPEAKER,\n\tET_PUSH_TRIGGER,\n\tET_TELEPORT_TRIGGER,\n\tET_INVISIBLE,\n\tET_GRAPPLE,\t\t\t\t// grapple hooked on wall\n\tET_TEAM,\n\n\tET_EVENTS\t\t\t\t// any of the EV_* events can be added freestanding\n\t\t\t\t\t\t\t// by setting eType to ET_EVENTS + eventNum\n\t\t\t\t\t\t\t// this avoids having to set eFlags and eventNum\n} entityType_t;\n\n\n\nvoid\tBG_EvaluateTrajectory( const trajectory_t *tr, int atTime, vec3_t result );\nvoid\tBG_EvaluateTrajectoryDelta( const trajectory_t *tr, int atTime, vec3_t result );\n\nvoid\tBG_AddPredictableEventToPlayerstate( int newEvent, int eventParm, playerState_t *ps );\n\nvoid\tBG_TouchJumpPad( playerState_t *ps, entityState_t *jumppad );\n\nvoid\tBG_PlayerStateToEntityState( playerState_t *ps, entityState_t *s, qboolean snap );\nvoid\tBG_PlayerStateToEntityStateExtraPolate( playerState_t *ps, entityState_t *s, int time, qboolean snap );\n\nqboolean\tBG_PlayerTouchesItem( playerState_t *ps, entityState_t *item, int atTime );\n\n\n#define ARENAS_PER_TIER\t\t4\n#define MAX_ARENAS\t\t\t1024\n#define\tMAX_ARENAS_TEXT\t\t8192\n\n#define MAX_BOTS\t\t\t1024\n#define MAX_BOTS_TEXT\t\t8192\n\n\n// Kamikaze\n\n// 1st shockwave times\n#define KAMI_SHOCKWAVE_STARTTIME\t\t0\n#define KAMI_SHOCKWAVEFADE_STARTTIME\t1500\n#define KAMI_SHOCKWAVE_ENDTIME\t\t\t2000\n// explosion/implosion times\n#define KAMI_EXPLODE_STARTTIME\t\t\t250\n#define KAMI_IMPLODE_STARTTIME\t\t\t2000\n#define KAMI_IMPLODE_ENDTIME\t\t\t2250\n// 2nd shockwave times\n#define KAMI_SHOCKWAVE2_STARTTIME\t\t2000\n#define KAMI_SHOCKWAVE2FADE_STARTTIME\t2500\n#define KAMI_SHOCKWAVE2_ENDTIME\t\t\t3000\n// radius of the models without scaling\n#define KAMI_SHOCKWAVEMODEL_RADIUS\t\t88\n#define KAMI_BOOMSPHEREMODEL_RADIUS\t\t72\n// maximum radius of the models during the effect\n#define KAMI_SHOCKWAVE_MAXRADIUS\t\t1320\n#define KAMI_BOOMSPHERE_MAXRADIUS\t\t720\n#define KAMI_SHOCKWAVE2_MAXRADIUS\t\t704\n\n"
  },
  {
    "path": "src/game/bg_slidemove.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n// bg_slidemove.c -- part of bg_pmove functionality\n\n#include \"q_shared.h\"\n#include \"bg_public.h\"\n#include \"bg_local.h\"\n\n/*\n\ninput: origin, velocity, bounds, groundPlane, trace function\n\noutput: origin, velocity, impacts, stairup boolean\n\n*/\n\n/*\n==================\nPM_SlideMove\n\nReturns qtrue if the velocity was clipped in some way\n==================\n*/\n#define\tMAX_CLIP_PLANES\t5\nqboolean\tPM_SlideMove( qboolean gravity ) {\n\tint\t\t\tbumpcount, numbumps;\n\tvec3_t\t\tdir;\n\tfloat\t\td;\n\tint\t\t\tnumplanes;\n\tvec3_t\t\tplanes[MAX_CLIP_PLANES];\n\tvec3_t\t\tprimal_velocity;\n\tvec3_t\t\tclipVelocity;\n\tint\t\t\ti, j, k;\n\ttrace_t\ttrace;\n\tvec3_t\t\tend;\n\tfloat\t\ttime_left;\n\tfloat\t\tinto;\n\tvec3_t\t\tendVelocity;\n\tvec3_t\t\tendClipVelocity;\n\t\n\tnumbumps = 4;\n\n\tVectorCopy (pm->ps->velocity, primal_velocity);\n\n\tif ( gravity ) {\n\t\tVectorCopy( pm->ps->velocity, endVelocity );\n\t\tendVelocity[2] -= pm->ps->gravity * pml.frametime;\n\t\tpm->ps->velocity[2] = ( pm->ps->velocity[2] + endVelocity[2] ) * 0.5;\n\t\tprimal_velocity[2] = endVelocity[2];\n\t\tif ( pml.groundPlane ) {\n\t\t\t// slide along the ground plane\n\t\t\tPM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, \n\t\t\t\tpm->ps->velocity, OVERCLIP );\n\t\t}\n\t}\n\n\ttime_left = pml.frametime;\n\n\t// never turn against the ground plane\n\tif ( pml.groundPlane ) {\n\t\tnumplanes = 1;\n\t\tVectorCopy( pml.groundTrace.plane.normal, planes[0] );\n\t} else {\n\t\tnumplanes = 0;\n\t}\n\n\t// never turn against original velocity\n\tVectorNormalize2( pm->ps->velocity, planes[numplanes] );\n\tnumplanes++;\n\n\tfor ( bumpcount=0 ; bumpcount < numbumps ; bumpcount++ ) {\n\n\t\t// calculate position we are trying to move to\n\t\tVectorMA( pm->ps->origin, time_left, pm->ps->velocity, end );\n\n\t\t// see if we can make it there\n\t\tpm->trace ( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, pm->tracemask);\n\n\t\tif (trace.allsolid) {\n\t\t\t// entity is completely trapped in another solid\n\t\t\tpm->ps->velocity[2] = 0;\t// don't build up falling damage, but allow sideways acceleration\n\t\t\treturn qtrue;\n\t\t}\n\n\t\tif (trace.fraction > 0) {\n\t\t\t// actually covered some distance\n\t\t\tVectorCopy (trace.endpos, pm->ps->origin);\n\t\t}\n\n\t\tif (trace.fraction == 1) {\n\t\t\t break;\t\t// moved the entire distance\n\t\t}\n\n\t\t// save entity for contact\n\t\tPM_AddTouchEnt( trace.entityNum );\n\n\t\ttime_left -= time_left * trace.fraction;\n\n\t\tif (numplanes >= MAX_CLIP_PLANES) {\n\t\t\t// this shouldn't really happen\n\t\t\tVectorClear( pm->ps->velocity );\n\t\t\treturn qtrue;\n\t\t}\n\n\t\t//\n\t\t// if this is the same plane we hit before, nudge velocity\n\t\t// out along it, which fixes some epsilon issues with\n\t\t// non-axial planes\n\t\t//\n\t\tfor ( i = 0 ; i < numplanes ; i++ ) {\n\t\t\tif ( DotProduct( trace.plane.normal, planes[i] ) > 0.99 ) {\n\t\t\t\tVectorAdd( trace.plane.normal, pm->ps->velocity, pm->ps->velocity );\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif ( i < numplanes ) {\n\t\t\tcontinue;\n\t\t}\n\t\tVectorCopy (trace.plane.normal, planes[numplanes]);\n\t\tnumplanes++;\n\n\t\t//\n\t\t// modify velocity so it parallels all of the clip planes\n\t\t//\n\n\t\t// find a plane that it enters\n\t\tfor ( i = 0 ; i < numplanes ; i++ ) {\n\t\t\tinto = DotProduct( pm->ps->velocity, planes[i] );\n\t\t\tif ( into >= 0.1 ) {\n\t\t\t\tcontinue;\t\t// move doesn't interact with the plane\n\t\t\t}\n\n\t\t\t// see how hard we are hitting things\n\t\t\tif ( -into > pml.impactSpeed ) {\n\t\t\t\tpml.impactSpeed = -into;\n\t\t\t}\n\n\t\t\t// slide along the plane\n\t\t\tPM_ClipVelocity (pm->ps->velocity, planes[i], clipVelocity, OVERCLIP );\n\n\t\t\t// slide along the plane\n\t\t\tPM_ClipVelocity (endVelocity, planes[i], endClipVelocity, OVERCLIP );\n\n\t\t\t// see if there is a second plane that the new move enters\n\t\t\tfor ( j = 0 ; j < numplanes ; j++ ) {\n\t\t\t\tif ( j == i ) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif ( DotProduct( clipVelocity, planes[j] ) >= 0.1 ) {\n\t\t\t\t\tcontinue;\t\t// move doesn't interact with the plane\n\t\t\t\t}\n\n\t\t\t\t// try clipping the move to the plane\n\t\t\t\tPM_ClipVelocity( clipVelocity, planes[j], clipVelocity, OVERCLIP );\n\t\t\t\tPM_ClipVelocity( endClipVelocity, planes[j], endClipVelocity, OVERCLIP );\n\n\t\t\t\t// see if it goes back into the first clip plane\n\t\t\t\tif ( DotProduct( clipVelocity, planes[i] ) >= 0 ) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// slide the original velocity along the crease\n\t\t\t\tCrossProduct (planes[i], planes[j], dir);\n\t\t\t\tVectorNormalize( dir );\n\t\t\t\td = DotProduct( dir, pm->ps->velocity );\n\t\t\t\tVectorScale( dir, d, clipVelocity );\n\n\t\t\t\tCrossProduct (planes[i], planes[j], dir);\n\t\t\t\tVectorNormalize( dir );\n\t\t\t\td = DotProduct( dir, endVelocity );\n\t\t\t\tVectorScale( dir, d, endClipVelocity );\n\n\t\t\t\t// see if there is a third plane the the new move enters\n\t\t\t\tfor ( k = 0 ; k < numplanes ; k++ ) {\n\t\t\t\t\tif ( k == i || k == j ) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tif ( DotProduct( clipVelocity, planes[k] ) >= 0.1 ) {\n\t\t\t\t\t\tcontinue;\t\t// move doesn't interact with the plane\n\t\t\t\t\t}\n\n\t\t\t\t\t// stop dead at a tripple plane interaction\n\t\t\t\t\tVectorClear( pm->ps->velocity );\n\t\t\t\t\treturn qtrue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// if we have fixed all interactions, try another move\n\t\t\tVectorCopy( clipVelocity, pm->ps->velocity );\n\t\t\tVectorCopy( endClipVelocity, endVelocity );\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif ( gravity ) {\n\t\tVectorCopy( endVelocity, pm->ps->velocity );\n\t}\n\n\t// don't change velocity if in a timer (FIXME: is this correct?)\n\tif ( pm->ps->pm_time ) {\n\t\tVectorCopy( primal_velocity, pm->ps->velocity );\n\t}\n\n\treturn ( bumpcount != 0 );\n}\n\n/*\n==================\nPM_StepSlideMove\n\n==================\n*/\nvoid PM_StepSlideMove( qboolean gravity ) {\n\tvec3_t\t\tstart_o, start_v;\n\tvec3_t\t\tdown_o, down_v;\n\ttrace_t\t\ttrace;\n//\tfloat\t\tdown_dist, up_dist;\n//\tvec3_t\t\tdelta, delta2;\n\tvec3_t\t\tup, down;\n\tfloat\t\tstepSize;\n\n\tVectorCopy (pm->ps->origin, start_o);\n\tVectorCopy (pm->ps->velocity, start_v);\n\n\tif ( PM_SlideMove( gravity ) == 0 ) {\n\t\treturn;\t\t// we got exactly where we wanted to go first try\t\n\t}\n\n\tVectorCopy(start_o, down);\n\tdown[2] -= STEPSIZE;\n\tpm->trace (&trace, start_o, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask);\n\tVectorSet(up, 0, 0, 1);\n\t// never step up when you still have up velocity\n\tif ( pm->ps->velocity[2] > 0 && (trace.fraction == 1.0 ||\n\t\t\t\t\t\t\t\t\t\tDotProduct(trace.plane.normal, up) < 0.7)) {\n\t\treturn;\n\t}\n\n\tVectorCopy (pm->ps->origin, down_o);\n\tVectorCopy (pm->ps->velocity, down_v);\n\n\tVectorCopy (start_o, up);\n\tup[2] += STEPSIZE;\n\n\t// test the player position if they were a stepheight higher\n\tpm->trace (&trace, start_o, pm->mins, pm->maxs, up, pm->ps->clientNum, pm->tracemask);\n\tif ( trace.allsolid ) {\n\t\tif ( pm->debugLevel ) {\n\t\t\tCom_Printf(\"%i:bend can't step\\n\", c_pmove);\n\t\t}\n\t\treturn;\t\t// can't step up\n\t}\n\n\tstepSize = trace.endpos[2] - start_o[2];\n\t// try slidemove from this position\n\tVectorCopy (trace.endpos, pm->ps->origin);\n\tVectorCopy (start_v, pm->ps->velocity);\n\n\tPM_SlideMove( gravity );\n\n\t// push down the final amount\n\tVectorCopy (pm->ps->origin, down);\n\tdown[2] -= stepSize;\n\tpm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask);\n\tif ( !trace.allsolid ) {\n\t\tVectorCopy (trace.endpos, pm->ps->origin);\n\t}\n\tif ( trace.fraction < 1.0 ) {\n\t\tPM_ClipVelocity( pm->ps->velocity, trace.plane.normal, pm->ps->velocity, OVERCLIP );\n\t}\n\n#if 0\n\t// if the down trace can trace back to the original position directly, don't step\n\tpm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, start_o, pm->ps->clientNum, pm->tracemask);\n\tif ( trace.fraction == 1.0 ) {\n\t\t// use the original move\n\t\tVectorCopy (down_o, pm->ps->origin);\n\t\tVectorCopy (down_v, pm->ps->velocity);\n\t\tif ( pm->debugLevel ) {\n\t\t\tCom_Printf(\"%i:bend\\n\", c_pmove);\n\t\t}\n\t} else \n#endif\n\t{\n\t\t// use the step move\n\t\tfloat\tdelta;\n\n\t\tdelta = pm->ps->origin[2] - start_o[2];\n\t\tif ( delta > 2 ) {\n\t\t\tif ( delta < 7 ) {\n\t\t\t\tPM_AddEvent( EV_STEP_4 );\n\t\t\t} else if ( delta < 11 ) {\n\t\t\t\tPM_AddEvent( EV_STEP_8 );\n\t\t\t} else if ( delta < 15 ) {\n\t\t\t\tPM_AddEvent( EV_STEP_12 );\n\t\t\t} else {\n\t\t\t\tPM_AddEvent( EV_STEP_16 );\n\t\t\t}\n\t\t}\n\t\tif ( pm->debugLevel ) {\n\t\t\tCom_Printf(\"%i:stepped\\n\", c_pmove);\n\t\t}\n\t}\n}\n\n"
  },
  {
    "path": "src/game/botlib.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n/*****************************************************************************\n * name:\t\tbotlib.h\n *\n * desc:\t\tbot AI library\n *\n * $Archive: /source/code/game/botai.h $\n *\n *****************************************************************************/\n\n#define\tBOTLIB_API_VERSION\t\t2\n\nstruct aas_clientmove_s;\nstruct aas_entityinfo_s;\nstruct aas_areainfo_s;\nstruct aas_altroutegoal_s;\nstruct aas_predictroute_s;\nstruct bot_consolemessage_s;\nstruct bot_match_s;\nstruct bot_goal_s;\nstruct bot_moveresult_s;\nstruct bot_initmove_s;\nstruct weaponinfo_s;\n\n#define BOTFILESBASEFOLDER\t\t\"botfiles\"\n//debug line colors\n#define LINECOLOR_NONE\t\t\t-1\n#define LINECOLOR_RED\t\t\t1//0xf2f2f0f0L\n#define LINECOLOR_GREEN\t\t\t2//0xd0d1d2d3L\n#define LINECOLOR_BLUE\t\t\t3//0xf3f3f1f1L\n#define LINECOLOR_YELLOW\t\t4//0xdcdddedfL\n#define LINECOLOR_ORANGE\t\t5//0xe0e1e2e3L\n\n//Print types\n#define PRT_MESSAGE\t\t\t\t1\n#define PRT_WARNING\t\t\t\t2\n#define PRT_ERROR\t\t\t\t3\n#define PRT_FATAL\t\t\t\t4\n#define PRT_EXIT\t\t\t\t5\n\n//console message types\n#define CMS_NORMAL\t\t\t\t0\n#define CMS_CHAT\t\t\t\t1\n\n//botlib error codes\n#define BLERR_NOERROR\t\t\t\t\t0\t//no error\n#define BLERR_LIBRARYNOTSETUP\t\t\t1\t//library not setup\n#define BLERR_INVALIDENTITYNUMBER\t\t2\t//invalid entity number\n#define BLERR_NOAASFILE\t\t\t\t\t3\t//no AAS file available\n#define BLERR_CANNOTOPENAASFILE\t\t\t4\t//cannot open AAS file\n#define BLERR_WRONGAASFILEID\t\t\t5\t//incorrect AAS file id\n#define BLERR_WRONGAASFILEVERSION\t\t6\t//incorrect AAS file version\n#define BLERR_CANNOTREADAASLUMP\t\t\t7\t//cannot read AAS file lump\n#define BLERR_CANNOTLOADICHAT\t\t\t8\t//cannot load initial chats\n#define BLERR_CANNOTLOADITEMWEIGHTS\t\t9\t//cannot load item weights\n#define BLERR_CANNOTLOADITEMCONFIG\t\t10\t//cannot load item config\n#define BLERR_CANNOTLOADWEAPONWEIGHTS\t11\t//cannot load weapon weights\n#define BLERR_CANNOTLOADWEAPONCONFIG\t12\t//cannot load weapon config\n\n//action flags\n#define ACTION_ATTACK\t\t\t0x0000001\n#define ACTION_USE\t\t\t\t0x0000002\n#define ACTION_RESPAWN\t\t\t0x0000008\n#define ACTION_JUMP\t\t\t\t0x0000010\n#define ACTION_MOVEUP\t\t\t0x0000020\n#define ACTION_CROUCH\t\t\t0x0000080\n#define ACTION_MOVEDOWN\t\t\t0x0000100\n#define ACTION_MOVEFORWARD\t\t0x0000200\n#define ACTION_MOVEBACK\t\t\t0x0000800\n#define ACTION_MOVELEFT\t\t\t0x0001000\n#define ACTION_MOVERIGHT\t\t0x0002000\n#define ACTION_DELAYEDJUMP\t\t0x0008000\n#define ACTION_TALK\t\t\t\t0x0010000\n#define ACTION_GESTURE\t\t\t0x0020000\n#define ACTION_WALK\t\t\t\t0x0080000\n#define ACTION_AFFIRMATIVE\t\t0x0100000\n#define ACTION_NEGATIVE\t\t\t0x0200000\n#define ACTION_GETFLAG\t\t\t0x0800000\n#define ACTION_GUARDBASE\t\t0x1000000\n#define ACTION_PATROL\t\t\t0x2000000\n#define ACTION_FOLLOWME\t\t\t0x8000000\n\n//the bot input, will be converted to an usercmd_t\ntypedef struct bot_input_s\n{\n\tfloat thinktime;\t\t//time since last output (in seconds)\n\tvec3_t dir;\t\t\t\t//movement direction\n\tfloat speed;\t\t\t//speed in the range [0, 400]\n\tvec3_t viewangles;\t\t//the view angles\n\tint actionflags;\t\t//one of the ACTION_? flags\n\tint weapon;\t\t\t\t//weapon to use\n} bot_input_t;\n\n#ifndef BSPTRACE\n\n#define BSPTRACE\n\n//bsp_trace_t hit surface\ntypedef struct bsp_surface_s\n{\n\tchar name[16];\n\tint flags;\n\tint value;\n} bsp_surface_t;\n\n//remove the bsp_trace_s structure definition l8r on\n//a trace is returned when a box is swept through the world\ntypedef struct bsp_trace_s\n{\n\tqboolean\t\tallsolid;\t// if true, plane is not valid\n\tqboolean\t\tstartsolid;\t// if true, the initial point was in a solid area\n\tfloat\t\t\tfraction;\t// time completed, 1.0 = didn't hit anything\n\tvec3_t\t\t\tendpos;\t\t// final position\n\tcplane_t\t\tplane;\t\t// surface normal at impact\n\tfloat\t\t\texp_dist;\t// expanded plane distance\n\tint\t\t\t\tsidenum;\t// number of the brush side hit\n\tbsp_surface_t\tsurface;\t// the hit point surface\n\tint\t\t\t\tcontents;\t// contents on other side of surface hit\n\tint\t\t\t\tent;\t\t// number of entity hit\n} bsp_trace_t;\n\n#endif\t// BSPTRACE\n\n//entity state\ntypedef struct bot_entitystate_s\n{\n\tint\t\ttype;\t\t\t// entity type\n\tint\t\tflags;\t\t\t// entity flags\n\tvec3_t\torigin;\t\t\t// origin of the entity\n\tvec3_t\tangles;\t\t\t// angles of the model\n\tvec3_t\told_origin;\t\t// for lerping\n\tvec3_t\tmins;\t\t\t// bounding box minimums\n\tvec3_t\tmaxs;\t\t\t// bounding box maximums\n\tint\t\tgroundent;\t\t// ground entity\n\tint\t\tsolid;\t\t\t// solid type\n\tint\t\tmodelindex;\t\t// model used\n\tint\t\tmodelindex2;\t// weapons, CTF flags, etc\n\tint\t\tframe;\t\t\t// model frame number\n\tint\t\tevent;\t\t\t// impulse events -- muzzle flashes, footsteps, etc\n\tint\t\teventParm;\t\t// even parameter\n\tint\t\tpowerups;\t\t// bit flags\n\tint\t\tweapon;\t\t\t// determines weapon and flash model, etc\n\tint\t\tlegsAnim;\t\t// mask off ANIM_TOGGLEBIT\n\tint\t\ttorsoAnim;\t\t// mask off ANIM_TOGGLEBIT\n} bot_entitystate_t;\n\n//bot AI library exported functions\ntypedef struct botlib_import_s\n{\n\t//print messages from the bot library\n\tvoid\t\t(QDECL *Print)(int type, char *fmt, ...);\n\t//trace a bbox through the world\n\tvoid\t\t(*Trace)(bsp_trace_t *trace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int passent, int contentmask);\n\t//trace a bbox against a specific entity\n\tvoid\t\t(*EntityTrace)(bsp_trace_t *trace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int entnum, int contentmask);\n\t//retrieve the contents at the given point\n\tint\t\t\t(*PointContents)(vec3_t point);\n\t//check if the point is in potential visible sight\n\tint\t\t\t(*inPVS)(vec3_t p1, vec3_t p2);\n\t//retrieve the BSP entity data lump\n\tchar\t\t*(*BSPEntityData)(void);\n\t//\n\tvoid\t\t(*BSPModelMinsMaxsOrigin)(int modelnum, vec3_t angles, vec3_t mins, vec3_t maxs, vec3_t origin);\n\t//send a bot client command\n\tvoid\t\t(*BotClientCommand)(int client, char *command);\n\t//memory allocation\n\tvoid\t\t*(*GetMemory)(int size);\t\t// allocate from Zone\n\tvoid\t\t(*FreeMemory)(void *ptr);\t\t// free memory from Zone\n\tint\t\t\t(*AvailableMemory)(void);\t\t// available Zone memory\n\tvoid\t\t*(*HunkAlloc)(int size);\t\t// allocate from hunk\n\t//file system access\n\tint\t\t\t(*FS_FOpenFile)( const char *qpath, fileHandle_t *file, fsMode_t mode );\n\tint\t\t\t(*FS_Read)( void *buffer, int len, fileHandle_t f );\n\tint\t\t\t(*FS_Write)( const void *buffer, int len, fileHandle_t f );\n\tvoid\t\t(*FS_FCloseFile)( fileHandle_t f );\n\tint\t\t\t(*FS_Seek)( fileHandle_t f, long offset, int origin );\n\t//debug visualisation stuff\n\tint\t\t\t(*DebugLineCreate)(void);\n\tvoid\t\t(*DebugLineDelete)(int line);\n\tvoid\t\t(*DebugLineShow)(int line, vec3_t start, vec3_t end, int color);\n\t//\n\tint\t\t\t(*DebugPolygonCreate)(int color, int numPoints, vec3_t *points);\n\tvoid\t\t(*DebugPolygonDelete)(int id);\n} botlib_import_t;\n\ntypedef struct aas_export_s\n{\n\t//-----------------------------------\n\t// be_aas_entity.h\n\t//-----------------------------------\n\tvoid\t\t(*AAS_EntityInfo)(int entnum, struct aas_entityinfo_s *info);\n\t//-----------------------------------\n\t// be_aas_main.h\n\t//-----------------------------------\n\tint\t\t\t(*AAS_Initialized)(void);\n\tvoid\t\t(*AAS_PresenceTypeBoundingBox)(int presencetype, vec3_t mins, vec3_t maxs);\n\tfloat\t\t(*AAS_Time)(void);\n\t//--------------------------------------------\n\t// be_aas_sample.c\n\t//--------------------------------------------\n\tint\t\t\t(*AAS_PointAreaNum)(vec3_t point);\n\tint\t\t\t(*AAS_PointReachabilityAreaIndex)( vec3_t point );\n\tint\t\t\t(*AAS_TraceAreas)(vec3_t start, vec3_t end, int *areas, vec3_t *points, int maxareas);\n\tint\t\t\t(*AAS_BBoxAreas)(vec3_t absmins, vec3_t absmaxs, int *areas, int maxareas);\n\tint\t\t\t(*AAS_AreaInfo)( int areanum, struct aas_areainfo_s *info );\n\t//--------------------------------------------\n\t// be_aas_bspq3.c\n\t//--------------------------------------------\n\tint\t\t\t(*AAS_PointContents)(vec3_t point);\n\tint\t\t\t(*AAS_NextBSPEntity)(int ent);\n\tint\t\t\t(*AAS_ValueForBSPEpairKey)(int ent, char *key, char *value, int size);\n\tint\t\t\t(*AAS_VectorForBSPEpairKey)(int ent, char *key, vec3_t v);\n\tint\t\t\t(*AAS_FloatForBSPEpairKey)(int ent, char *key, float *value);\n\tint\t\t\t(*AAS_IntForBSPEpairKey)(int ent, char *key, int *value);\n\t//--------------------------------------------\n\t// be_aas_reach.c\n\t//--------------------------------------------\n\tint\t\t\t(*AAS_AreaReachability)(int areanum);\n\t//--------------------------------------------\n\t// be_aas_route.c\n\t//--------------------------------------------\n\tint\t\t\t(*AAS_AreaTravelTimeToGoalArea)(int areanum, vec3_t origin, int goalareanum, int travelflags);\n\tint\t\t\t(*AAS_EnableRoutingArea)(int areanum, int enable);\n\tint\t\t\t(*AAS_PredictRoute)(struct aas_predictroute_s *route, int areanum, vec3_t origin,\n\t\t\t\t\t\t\tint goalareanum, int travelflags, int maxareas, int maxtime,\n\t\t\t\t\t\t\tint stopevent, int stopcontents, int stoptfl, int stopareanum);\n\t//--------------------------------------------\n\t// be_aas_altroute.c\n\t//--------------------------------------------\n\tint\t\t\t(*AAS_AlternativeRouteGoals)(vec3_t start, int startareanum, vec3_t goal, int goalareanum, int travelflags,\n\t\t\t\t\t\t\t\t\t\tstruct aas_altroutegoal_s *altroutegoals, int maxaltroutegoals,\n\t\t\t\t\t\t\t\t\t\tint type);\n\t//--------------------------------------------\n\t// be_aas_move.c\n\t//--------------------------------------------\n\tint\t\t\t(*AAS_Swimming)(vec3_t origin);\n\tint\t\t\t(*AAS_PredictClientMovement)(struct aas_clientmove_s *move,\n\t\t\t\t\t\t\t\t\t\t\tint entnum, vec3_t origin,\n\t\t\t\t\t\t\t\t\t\t\tint presencetype, int onground,\n\t\t\t\t\t\t\t\t\t\t\tvec3_t velocity, vec3_t cmdmove,\n\t\t\t\t\t\t\t\t\t\t\tint cmdframes,\n\t\t\t\t\t\t\t\t\t\t\tint maxframes, float frametime,\n\t\t\t\t\t\t\t\t\t\t\tint stopevent, int stopareanum, int visualize);\n} aas_export_t;\n\ntypedef struct ea_export_s\n{\n\t//ClientCommand elementary actions\n\tvoid\t(*EA_Command)(int client, char *command );\n\tvoid\t(*EA_Say)(int client, char *str);\n\tvoid\t(*EA_SayTeam)(int client, char *str);\n\t//\n\tvoid\t(*EA_Action)(int client, int action);\n\tvoid\t(*EA_Gesture)(int client);\n\tvoid\t(*EA_Talk)(int client);\n\tvoid\t(*EA_Attack)(int client);\n\tvoid\t(*EA_Use)(int client);\n\tvoid\t(*EA_Respawn)(int client);\n\tvoid\t(*EA_MoveUp)(int client);\n\tvoid\t(*EA_MoveDown)(int client);\n\tvoid\t(*EA_MoveForward)(int client);\n\tvoid\t(*EA_MoveBack)(int client);\n\tvoid\t(*EA_MoveLeft)(int client);\n\tvoid\t(*EA_MoveRight)(int client);\n\tvoid\t(*EA_Crouch)(int client);\n\n\tvoid\t(*EA_SelectWeapon)(int client, int weapon);\n\tvoid\t(*EA_Jump)(int client);\n\tvoid\t(*EA_DelayedJump)(int client);\n\tvoid\t(*EA_Move)(int client, vec3_t dir, float speed);\n\tvoid\t(*EA_View)(int client, vec3_t viewangles);\n\t//send regular input to the server\n\tvoid\t(*EA_EndRegular)(int client, float thinktime);\n\tvoid\t(*EA_GetInput)(int client, float thinktime, bot_input_t *input);\n\tvoid\t(*EA_ResetInput)(int client);\n} ea_export_t;\n\ntypedef struct ai_export_s\n{\n\t//-----------------------------------\n\t// be_ai_char.h\n\t//-----------------------------------\n\tint\t\t(*BotLoadCharacter)(char *charfile, float skill);\n\tvoid\t(*BotFreeCharacter)(int character);\n\tfloat\t(*Characteristic_Float)(int character, int index);\n\tfloat\t(*Characteristic_BFloat)(int character, int index, float min, float max);\n\tint\t\t(*Characteristic_Integer)(int character, int index);\n\tint\t\t(*Characteristic_BInteger)(int character, int index, int min, int max);\n\tvoid\t(*Characteristic_String)(int character, int index, char *buf, int size);\n\t//-----------------------------------\n\t// be_ai_chat.h\n\t//-----------------------------------\n\tint\t\t(*BotAllocChatState)(void);\n\tvoid\t(*BotFreeChatState)(int handle);\n\tvoid\t(*BotQueueConsoleMessage)(int chatstate, int type, char *message);\n\tvoid\t(*BotRemoveConsoleMessage)(int chatstate, int handle);\n\tint\t\t(*BotNextConsoleMessage)(int chatstate, struct bot_consolemessage_s *cm);\n\tint\t\t(*BotNumConsoleMessages)(int chatstate);\n\tvoid\t(*BotInitialChat)(int chatstate, char *type, int mcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7);\n\tint\t\t(*BotNumInitialChats)(int chatstate, char *type);\n\tint\t\t(*BotReplyChat)(int chatstate, char *message, int mcontext, int vcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7);\n\tint\t\t(*BotChatLength)(int chatstate);\n\tvoid\t(*BotEnterChat)(int chatstate, int client, int sendto);\n\tvoid\t(*BotGetChatMessage)(int chatstate, char *buf, int size);\n\tint\t\t(*StringContains)(char *str1, char *str2, int casesensitive);\n\tint\t\t(*BotFindMatch)(char *str, struct bot_match_s *match, unsigned long int context);\n\tvoid\t(*BotMatchVariable)(struct bot_match_s *match, int variable, char *buf, int size);\n\tvoid\t(*UnifyWhiteSpaces)(char *string);\n\tvoid\t(*BotReplaceSynonyms)(char *string, unsigned long int context);\n\tint\t\t(*BotLoadChatFile)(int chatstate, char *chatfile, char *chatname);\n\tvoid\t(*BotSetChatGender)(int chatstate, int gender);\n\tvoid\t(*BotSetChatName)(int chatstate, char *name, int client);\n\t//-----------------------------------\n\t// be_ai_goal.h\n\t//-----------------------------------\n\tvoid\t(*BotResetGoalState)(int goalstate);\n\tvoid\t(*BotResetAvoidGoals)(int goalstate);\n\tvoid\t(*BotRemoveFromAvoidGoals)(int goalstate, int number);\n\tvoid\t(*BotPushGoal)(int goalstate, struct bot_goal_s *goal);\n\tvoid\t(*BotPopGoal)(int goalstate);\n\tvoid\t(*BotEmptyGoalStack)(int goalstate);\n\tvoid\t(*BotDumpAvoidGoals)(int goalstate);\n\tvoid\t(*BotDumpGoalStack)(int goalstate);\n\tvoid\t(*BotGoalName)(int number, char *name, int size);\n\tint\t\t(*BotGetTopGoal)(int goalstate, struct bot_goal_s *goal);\n\tint\t\t(*BotGetSecondGoal)(int goalstate, struct bot_goal_s *goal);\n\tint\t\t(*BotChooseLTGItem)(int goalstate, vec3_t origin, int *inventory, int travelflags);\n\tint\t\t(*BotChooseNBGItem)(int goalstate, vec3_t origin, int *inventory, int travelflags,\n\t\t\t\t\t\t\t\tstruct bot_goal_s *ltg, float maxtime);\n\tint\t\t(*BotTouchingGoal)(vec3_t origin, struct bot_goal_s *goal);\n\tint\t\t(*BotItemGoalInVisButNotVisible)(int viewer, vec3_t eye, vec3_t viewangles, struct bot_goal_s *goal);\n\tint\t\t(*BotGetLevelItemGoal)(int index, char *classname, struct bot_goal_s *goal);\n\tint\t\t(*BotGetNextCampSpotGoal)(int num, struct bot_goal_s *goal);\n\tint\t\t(*BotGetMapLocationGoal)(char *name, struct bot_goal_s *goal);\n\tfloat\t(*BotAvoidGoalTime)(int goalstate, int number);\n\tvoid\t(*BotSetAvoidGoalTime)(int goalstate, int number, float avoidtime);\n\tvoid\t(*BotInitLevelItems)(void);\n\tvoid\t(*BotUpdateEntityItems)(void);\n\tint\t\t(*BotLoadItemWeights)(int goalstate, char *filename);\n\tvoid\t(*BotFreeItemWeights)(int goalstate);\n\tvoid\t(*BotInterbreedGoalFuzzyLogic)(int parent1, int parent2, int child);\n\tvoid\t(*BotSaveGoalFuzzyLogic)(int goalstate, char *filename);\n\tvoid\t(*BotMutateGoalFuzzyLogic)(int goalstate, float range);\n\tint\t\t(*BotAllocGoalState)(int client);\n\tvoid\t(*BotFreeGoalState)(int handle);\n\t//-----------------------------------\n\t// be_ai_move.h\n\t//-----------------------------------\n\tvoid\t(*BotResetMoveState)(int movestate);\n\tvoid\t(*BotMoveToGoal)(struct bot_moveresult_s *result, int movestate, struct bot_goal_s *goal, int travelflags);\n\tint\t\t(*BotMoveInDirection)(int movestate, vec3_t dir, float speed, int type);\n\tvoid\t(*BotResetAvoidReach)(int movestate);\n\tvoid\t(*BotResetLastAvoidReach)(int movestate);\n\tint\t\t(*BotReachabilityArea)(vec3_t origin, int testground);\n\tint\t\t(*BotMovementViewTarget)(int movestate, struct bot_goal_s *goal, int travelflags, float lookahead, vec3_t target);\n\tint\t\t(*BotPredictVisiblePosition)(vec3_t origin, int areanum, struct bot_goal_s *goal, int travelflags, vec3_t target);\n\tint\t\t(*BotAllocMoveState)(void);\n\tvoid\t(*BotFreeMoveState)(int handle);\n\tvoid\t(*BotInitMoveState)(int handle, struct bot_initmove_s *initmove);\n\tvoid\t(*BotAddAvoidSpot)(int movestate, vec3_t origin, float radius, int type);\n\t//-----------------------------------\n\t// be_ai_weap.h\n\t//-----------------------------------\n\tint\t\t(*BotChooseBestFightWeapon)(int weaponstate, int *inventory);\n\tvoid\t(*BotGetWeaponInfo)(int weaponstate, int weapon, struct weaponinfo_s *weaponinfo);\n\tint\t\t(*BotLoadWeaponWeights)(int weaponstate, char *filename);\n\tint\t\t(*BotAllocWeaponState)(void);\n\tvoid\t(*BotFreeWeaponState)(int weaponstate);\n\tvoid\t(*BotResetWeaponState)(int weaponstate);\n\t//-----------------------------------\n\t// be_ai_gen.h\n\t//-----------------------------------\n\tint\t\t(*GeneticParentsAndChildSelection)(int numranks, float *ranks, int *parent1, int *parent2, int *child);\n} ai_export_t;\n\n//bot AI library imported functions\ntypedef struct botlib_export_s\n{\n\t//Area Awareness System functions\n\taas_export_t aas;\n\t//Elementary Action functions\n\tea_export_t ea;\n\t//AI functions\n\tai_export_t ai;\n\t//setup the bot library, returns BLERR_\n\tint (*BotLibSetup)(void);\n\t//shutdown the bot library, returns BLERR_\n\tint (*BotLibShutdown)(void);\n\t//sets a library variable returns BLERR_\n\tint (*BotLibVarSet)(char *var_name, char *value);\n\t//gets a library variable returns BLERR_\n\tint (*BotLibVarGet)(char *var_name, char *value, int size);\n\n\t//sets a C-like define returns BLERR_\n\tint (*PC_AddGlobalDefine)(char *string);\n\tint (*PC_LoadSourceHandle)(const char *filename);\n\tint (*PC_FreeSourceHandle)(int handle);\n\tint (*PC_ReadTokenHandle)(int handle, pc_token_t *pc_token);\n\tint (*PC_SourceFileAndLine)(int handle, char *filename, int *line);\n\n\t//start a frame in the bot library\n\tint (*BotLibStartFrame)(float time);\n\t//load a new map in the bot library\n\tint (*BotLibLoadMap)(const char *mapname);\n\t//entity updates\n\tint (*BotLibUpdateEntity)(int ent, bot_entitystate_t *state);\n\t//just for testing\n\tint (*Test)(int parm0, char *parm1, vec3_t parm2, vec3_t parm3);\n} botlib_export_t;\n\n//linking of bot library\nbotlib_export_t *GetBotLibAPI( int apiVersion, botlib_import_t *import );\n\n/* Library variables:\n\nname:\t\t\t\t\t\tdefault:\t\t\tmodule(s):\t\t\tdescription:\n\n\"basedir\"\t\t\t\t\t\"\"\t\t\t\t\tl_utils.c\t\t\tbase directory\n\"gamedir\"\t\t\t\t\t\"\"\t\t\t\t\tl_utils.c\t\t\tgame directory\n\"cddir\"\t\t\t\t\t\t\"\"\t\t\t\t\tl_utils.c\t\t\tCD directory\n\n\"log\"\t\t\t\t\t\t\"0\"\t\t\t\t\tl_log.c\t\t\t\tenable/disable creating a log file\n\"maxclients\"\t\t\t\t\"4\"\t\t\t\t\tbe_interface.c\t\tmaximum number of clients\n\"maxentities\"\t\t\t\t\"1024\"\t\t\t\tbe_interface.c\t\tmaximum number of entities\n\"bot_developer\"\t\t\t\t\"0\"\t\t\t\t\tbe_interface.c\t\tbot developer mode\n\n\"phys_friction\"\t\t\t\t\"6\"\t\t\t\t\tbe_aas_move.c\t\tground friction\n\"phys_stopspeed\"\t\t\t\"100\"\t\t\t\tbe_aas_move.c\t\tstop speed\n\"phys_gravity\"\t\t\t\t\"800\"\t\t\t\tbe_aas_move.c\t\tgravity value\n\"phys_waterfriction\"\t\t\"1\"\t\t\t\t\tbe_aas_move.c\t\twater friction\n\"phys_watergravity\"\t\t\t\"400\"\t\t\t\tbe_aas_move.c\t\tgravity in water\n\"phys_maxvelocity\"\t\t\t\"320\"\t\t\t\tbe_aas_move.c\t\tmaximum velocity\n\"phys_maxwalkvelocity\"\t\t\"320\"\t\t\t\tbe_aas_move.c\t\tmaximum walk velocity\n\"phys_maxcrouchvelocity\"\t\"100\"\t\t\t\tbe_aas_move.c\t\tmaximum crouch velocity\n\"phys_maxswimvelocity\"\t\t\"150\"\t\t\t\tbe_aas_move.c\t\tmaximum swim velocity\n\"phys_walkaccelerate\"\t\t\"10\"\t\t\t\tbe_aas_move.c\t\twalk acceleration\n\"phys_airaccelerate\"\t\t\"1\"\t\t\t\t\tbe_aas_move.c\t\tair acceleration\n\"phys_swimaccelerate\"\t\t\"4\"\t\t\t\t\tbe_aas_move.c\t\tswim acceleration\n\"phys_maxstep\"\t\t\t\t\"18\"\t\t\t\tbe_aas_move.c\t\tmaximum step height\n\"phys_maxsteepness\"\t\t\t\"0.7\"\t\t\t\tbe_aas_move.c\t\tmaximum floor steepness\n\"phys_maxbarrier\"\t\t\t\"32\"\t\t\t\tbe_aas_move.c\t\tmaximum barrier height\n\"phys_maxwaterjump\"\t\t\t\"19\"\t\t\t\tbe_aas_move.c\t\tmaximum waterjump height\n\"phys_jumpvel\"\t\t\t\t\"270\"\t\t\t\tbe_aas_move.c\t\tjump z velocity\n\"phys_falldelta5\"\t\t\t\"40\"\t\t\t\tbe_aas_move.c\n\"phys_falldelta10\"\t\t\t\"60\"\t\t\t\tbe_aas_move.c\n\"rs_waterjump\"\t\t\t\t\"400\"\t\t\t\tbe_aas_move.c\n\"rs_teleport\"\t\t\t\t\"50\"\t\t\t\tbe_aas_move.c\n\"rs_barrierjump\"\t\t\t\"100\"\t\t\t\tbe_aas_move.c\n\"rs_startcrouch\"\t\t\t\"300\"\t\t\t\tbe_aas_move.c\n\"rs_startgrapple\"\t\t\t\"500\"\t\t\t\tbe_aas_move.c\n\"rs_startwalkoffledge\"\t\t\"70\"\t\t\t\tbe_aas_move.c\n\"rs_startjump\"\t\t\t\t\"300\"\t\t\t\tbe_aas_move.c\n\"rs_rocketjump\"\t\t\t\t\"500\"\t\t\t\tbe_aas_move.c\n\"rs_bfgjump\"\t\t\t\t\"500\"\t\t\t\tbe_aas_move.c\n\"rs_jumppad\"\t\t\t\t\"250\"\t\t\t\tbe_aas_move.c\n\"rs_aircontrolledjumppad\"\t\"300\"\t\t\t\tbe_aas_move.c\n\"rs_funcbob\"\t\t\t\t\"300\"\t\t\t\tbe_aas_move.c\n\"rs_startelevator\"\t\t\t\"50\"\t\t\t\tbe_aas_move.c\n\"rs_falldamage5\"\t\t\t\"300\"\t\t\t\tbe_aas_move.c\n\"rs_falldamage10\"\t\t\t\"500\"\t\t\t\tbe_aas_move.c\n\"rs_maxjumpfallheight\"\t\t\"450\"\t\t\t\tbe_aas_move.c\n\n\"max_aaslinks\"\t\t\t\t\"4096\"\t\t\t\tbe_aas_sample.c\t\tmaximum links in the AAS\n\"max_routingcache\"\t\t\t\"4096\"\t\t\t\tbe_aas_route.c\t\tmaximum routing cache size in KB\n\"forceclustering\"\t\t\t\"0\"\t\t\t\t\tbe_aas_main.c\t\tforce recalculation of clusters\n\"forcereachability\"\t\t\t\"0\"\t\t\t\t\tbe_aas_main.c\t\tforce recalculation of reachabilities\n\"forcewrite\"\t\t\t\t\"0\"\t\t\t\t\tbe_aas_main.c\t\tforce writing of aas file\n\"aasoptimize\"\t\t\t\t\"0\"\t\t\t\t\tbe_aas_main.c\t\tenable aas optimization\n\"sv_mapChecksum\"\t\t\t\"0\"\t\t\t\t\tbe_aas_main.c\t\tBSP file checksum\n\"bot_visualizejumppads\"\t\t\"0\"\t\t\t\t\tbe_aas_reach.c\t\tvisualize jump pads\n\n\"bot_reloadcharacters\"\t\t\"0\"\t\t\t\t\t-\t\t\t\t\treload bot character files\n\"ai_gametype\"\t\t\t\t\"0\"\t\t\t\t\tbe_ai_goal.c\t\tgame type\n\"droppedweight\"\t\t\t\t\"1000\"\t\t\t\tbe_ai_goal.c\t\tadditional dropped item weight\n\"weapindex_rocketlauncher\"\t\"5\"\t\t\t\t\tbe_ai_move.c\t\trl weapon index for rocket jumping\n\"weapindex_bfg10k\"\t\t\t\"9\"\t\t\t\t\tbe_ai_move.c\t\tbfg weapon index for bfg jumping\n\"weapindex_grapple\"\t\t\t\"10\"\t\t\t\tbe_ai_move.c\t\tgrapple weapon index for grappling\n\"entitytypemissile\"\t\t\t\"3\"\t\t\t\t\tbe_ai_move.c\t\tET_MISSILE\n\"offhandgrapple\"\t\t\t\"0\"\t\t\t\t\tbe_ai_move.c\t\tenable off hand grapple hook\n\"cmd_grappleon\"\t\t\t\t\"grappleon\"\t\t\tbe_ai_move.c\t\tcommand to activate off hand grapple\n\"cmd_grappleoff\"\t\t\t\"grappleoff\"\t\tbe_ai_move.c\t\tcommand to deactivate off hand grapple\n\"itemconfig\"\t\t\t\t\"items.c\"\t\t\tbe_ai_goal.c\t\titem configuration file\n\"weaponconfig\"\t\t\t\t\"weapons.c\"\t\t\tbe_ai_weap.c\t\tweapon configuration file\n\"synfile\"\t\t\t\t\t\"syn.c\"\t\t\t\tbe_ai_chat.c\t\tfile with synonyms\n\"rndfile\"\t\t\t\t\t\"rnd.c\"\t\t\t\tbe_ai_chat.c\t\tfile with random strings\n\"matchfile\"\t\t\t\t\t\"match.c\"\t\t\tbe_ai_chat.c\t\tfile with match strings\n\"nochat\"\t\t\t\t\t\"0\"\t\t\t\t\tbe_ai_chat.c\t\tdisable chats\n\"max_messages\"\t\t\t\t\"1024\"\t\t\t\tbe_ai_chat.c\t\tconsole message heap size\n\"max_weaponinfo\"\t\t\t\"32\"\t\t\t\tbe_ai_weap.c\t\tmaximum number of weapon info\n\"max_projectileinfo\"\t\t\"32\"\t\t\t\tbe_ai_weap.c\t\tmaximum number of projectile info\n\"max_iteminfo\"\t\t\t\t\"256\"\t\t\t\tbe_ai_goal.c\t\tmaximum number of item info\n\"max_levelitems\"\t\t\t\"256\"\t\t\t\tbe_ai_goal.c\t\tmaximum number of level items\n\n*/\n\n"
  },
  {
    "path": "src/game/chars.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n//========================================================\n//========================================================\n//name\n#define CHARACTERISTIC_NAME\t\t\t\t\t\t\t0\t//string\n//gender of the bot\n#define CHARACTERISTIC_GENDER\t\t\t\t\t\t1\t//string (\"male\", \"female\", \"it\")\n//attack skill\n// >  0.0 && <  0.2 = don't move\n// >  0.3 && <  1.0 = aim at enemy during retreat\n// >  0.0 && <  0.4 = only move forward/backward\n// >= 0.4 && <  1.0 = circle strafing\n// >  0.7 && <  1.0 = random strafe direction change\n#define CHARACTERISTIC_ATTACK_SKILL\t\t\t\t\t2\t//float [0, 1]\n//weapon weight file\n#define CHARACTERISTIC_WEAPONWEIGHTS\t\t\t\t3\t//string\n//view angle difference to angle change factor\n#define CHARACTERISTIC_VIEW_FACTOR\t\t\t\t\t4\t//float <0, 1]\n//maximum view angle change\n#define CHARACTERISTIC_VIEW_MAXCHANGE\t\t\t\t5\t//float [1, 360]\n//reaction time in seconds\n#define CHARACTERISTIC_REACTIONTIME\t\t\t\t\t6\t//float [0, 5]\n//accuracy when aiming\n#define CHARACTERISTIC_AIM_ACCURACY\t\t\t\t\t7\t//float [0, 1]\n//weapon specific aim accuracy\n#define CHARACTERISTIC_AIM_ACCURACY_MACHINEGUN\t\t8\t//float [0, 1]\n#define CHARACTERISTIC_AIM_ACCURACY_SHOTGUN\t\t\t9\t//float [0, 1]\n#define CHARACTERISTIC_AIM_ACCURACY_ROCKETLAUNCHER\t10\t//float [0, 1]\n#define CHARACTERISTIC_AIM_ACCURACY_GRENADELAUNCHER\t11\t//float [0, 1]\n#define CHARACTERISTIC_AIM_ACCURACY_LIGHTNING\t\t12\n#define CHARACTERISTIC_AIM_ACCURACY_PLASMAGUN\t\t13\t//float [0, 1]\n#define CHARACTERISTIC_AIM_ACCURACY_RAILGUN\t\t\t14\n#define CHARACTERISTIC_AIM_ACCURACY_BFG10K\t\t\t15\t//float [0, 1]\n//skill when aiming\n// >  0.0 && <  0.9 = aim is affected by enemy movement\n// >  0.4 && <= 0.8 = enemy linear leading\n// >  0.8 && <= 1.0 = enemy exact movement leading\n// >  0.5 && <= 1.0 = prediction shots when enemy is not visible\n// >  0.6 && <= 1.0 = splash damage by shooting nearby geometry\n#define CHARACTERISTIC_AIM_SKILL\t\t\t\t\t16\t//float [0, 1]\n//weapon specific aim skill\n#define CHARACTERISTIC_AIM_SKILL_ROCKETLAUNCHER\t\t17\t//float [0, 1]\n#define CHARACTERISTIC_AIM_SKILL_GRENADELAUNCHER\t18\t//float [0, 1]\n#define CHARACTERISTIC_AIM_SKILL_PLASMAGUN\t\t\t19\t//float [0, 1]\n#define CHARACTERISTIC_AIM_SKILL_BFG10K\t\t\t\t20\t//float [0, 1]\n//========================================================\n//chat\n//========================================================\n//file with chats\n#define CHARACTERISTIC_CHAT_FILE\t\t\t\t\t21\t//string\n//name of the chat character\n#define CHARACTERISTIC_CHAT_NAME\t\t\t\t\t22\t//string\n//characters per minute type speed\n#define CHARACTERISTIC_CHAT_CPM\t\t\t\t\t\t23\t//integer [1, 4000]\n//tendency to insult/praise\n#define CHARACTERISTIC_CHAT_INSULT\t\t\t\t\t24\t//float [0, 1]\n//tendency to chat misc\n#define CHARACTERISTIC_CHAT_MISC\t\t\t\t\t25\t//float [0, 1]\n//tendency to chat at start or end of level\n#define CHARACTERISTIC_CHAT_STARTENDLEVEL\t\t\t26\t//float [0, 1]\n//tendency to chat entering or exiting the game\n#define CHARACTERISTIC_CHAT_ENTEREXITGAME\t\t\t27\t//float [0, 1]\n//tendency to chat when killed someone\n#define CHARACTERISTIC_CHAT_KILL\t\t\t\t\t28\t//float [0, 1]\n//tendency to chat when died\n#define CHARACTERISTIC_CHAT_DEATH\t\t\t\t\t29\t//float [0, 1]\n//tendency to chat when enemy suicides\n#define CHARACTERISTIC_CHAT_ENEMYSUICIDE\t\t\t30\t//float [0, 1]\n//tendency to chat when hit while talking\n#define CHARACTERISTIC_CHAT_HITTALKING\t\t\t\t31\t//float [0, 1]\n//tendency to chat when bot was hit but didn't dye\n#define CHARACTERISTIC_CHAT_HITNODEATH\t\t\t\t32\t//float [0, 1]\n//tendency to chat when bot hit the enemy but enemy didn't dye\n#define CHARACTERISTIC_CHAT_HITNOKILL\t\t\t\t33\t//float [0, 1]\n//tendency to randomly chat\n#define CHARACTERISTIC_CHAT_RANDOM\t\t\t\t\t34\t//float [0, 1]\n//tendency to reply\n#define CHARACTERISTIC_CHAT_REPLY\t\t\t\t\t35\t//float [0, 1]\n//========================================================\n//movement\n//========================================================\n//tendency to crouch\n#define CHARACTERISTIC_CROUCHER\t\t\t\t\t\t36\t//float [0, 1]\n//tendency to jump\n#define CHARACTERISTIC_JUMPER\t\t\t\t\t\t37\t//float [0, 1]\n//tendency to walk\n#define CHARACTERISTIC_WALKER\t\t\t\t\t\t48\t//float [0, 1]\n//tendency to jump using a weapon\n#define CHARACTERISTIC_WEAPONJUMPING\t\t\t\t38\t//float [0, 1]\n//tendency to use the grapple hook when available\n#define CHARACTERISTIC_GRAPPLE_USER\t\t\t\t\t39\t//float [0, 1]\t//use this!!\n//========================================================\n//goal\n//========================================================\n//item weight file\n#define CHARACTERISTIC_ITEMWEIGHTS\t\t\t\t\t40\t//string\n//the aggression of the bot\n#define CHARACTERISTIC_AGGRESSION\t\t\t\t\t41\t//float [0, 1]\n//the self preservation of the bot (rockets near walls etc.)\n#define CHARACTERISTIC_SELFPRESERVATION\t\t\t\t42\t//float [0, 1]\n//how likely the bot is to take revenge\n#define CHARACTERISTIC_VENGEFULNESS\t\t\t\t\t43\t//float [0, 1]\t//use this!!\n//tendency to camp\n#define CHARACTERISTIC_CAMPER\t\t\t\t\t\t44\t//float [0, 1]\n//========================================================\n//========================================================\n//tendency to get easy frags\n#define CHARACTERISTIC_EASY_FRAGGER\t\t\t\t\t45\t//float [0, 1]\n//how alert the bot is (view distance)\n#define CHARACTERISTIC_ALERTNESS\t\t\t\t\t46\t//float [0, 1]\n//how much the bot fires it's weapon\n#define CHARACTERISTIC_FIRETHROTTLE\t\t\t\t\t47\t//float [0, 1]\n\n"
  },
  {
    "path": "src/game/g_active.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n\n#include \"g_local.h\"\n\n\n/*\n===============\nG_DamageFeedback\n\nCalled just before a snapshot is sent to the given player.\nTotals up all damage and generates both the player_state_t\ndamage values to that client for pain blends and kicks, and\nglobal pain sound events for all clients.\n===============\n*/\nvoid P_DamageFeedback( gentity_t *player ) {\n\tgclient_t\t*client;\n\tfloat\tcount;\n\tvec3_t\tangles;\n\n\tclient = player->client;\n\tif ( client->ps.pm_type == PM_DEAD ) {\n\t\treturn;\n\t}\n\n\t// total points of damage shot at the player this frame\n\tcount = client->damage_blood + client->damage_armor;\n\tif ( count == 0 ) {\n\t\treturn;\t\t// didn't take any damage\n\t}\n\n\tif ( count > 255 ) {\n\t\tcount = 255;\n\t}\n\n\t// send the information to the client\n\n\t// world damage (falling, slime, etc) uses a special code\n\t// to make the blend blob centered instead of positional\n\tif ( client->damage_fromWorld ) {\n\t\tclient->ps.damagePitch = 255;\n\t\tclient->ps.damageYaw = 255;\n\n\t\tclient->damage_fromWorld = qfalse;\n\t} else {\n\t\tvectoangles( client->damage_from, angles );\n\t\tclient->ps.damagePitch = angles[PITCH]/360.0 * 256;\n\t\tclient->ps.damageYaw = angles[YAW]/360.0 * 256;\n\t}\n\n\t// play an apropriate pain sound\n\tif ( (level.time > player->pain_debounce_time) && !(player->flags & FL_GODMODE) ) {\n\t\tplayer->pain_debounce_time = level.time + 700;\n\t\tG_AddEvent( player, EV_PAIN, player->health );\n\t\tclient->ps.damageEvent++;\n\t}\n\n\n\tclient->ps.damageCount = count;\n\n\t//\n\t// clear totals\n\t//\n\tclient->damage_blood = 0;\n\tclient->damage_armor = 0;\n\tclient->damage_knockback = 0;\n}\n\n\n\n/*\n=============\nP_WorldEffects\n\nCheck for lava / slime contents and drowning\n=============\n*/\nvoid P_WorldEffects( gentity_t *ent ) {\n\tqboolean\tenvirosuit;\n\tint\t\t\twaterlevel;\n\n\tif ( ent->client->noclip ) {\n\t\tent->client->airOutTime = level.time + 12000;\t// don't need air\n\t\treturn;\n\t}\n\n\twaterlevel = ent->waterlevel;\n\n\tenvirosuit = ent->client->ps.powerups[PW_BATTLESUIT] > level.time;\n\n\t//\n\t// check for drowning\n\t//\n\tif ( waterlevel == 3 ) {\n\t\t// envirosuit give air\n\t\tif ( envirosuit ) {\n\t\t\tent->client->airOutTime = level.time + 10000;\n\t\t}\n\n\t\t// if out of air, start drowning\n\t\tif ( ent->client->airOutTime < level.time) {\n\t\t\t// drown!\n\t\t\tent->client->airOutTime += 1000;\n\t\t\tif ( ent->health > 0 ) {\n\t\t\t\t// take more damage the longer underwater\n\t\t\t\tent->damage += 2;\n\t\t\t\tif (ent->damage > 15)\n\t\t\t\t\tent->damage = 15;\n\n\t\t\t\t// play a gurp sound instead of a normal pain sound\n\t\t\t\tif (ent->health <= ent->damage) {\n\t\t\t\t\tG_Sound(ent, CHAN_VOICE, G_SoundIndex(\"*drown.wav\"));\n\t\t\t\t} else if (rand()&1) {\n\t\t\t\t\tG_Sound(ent, CHAN_VOICE, G_SoundIndex(\"sound/player/gurp1.wav\"));\n\t\t\t\t} else {\n\t\t\t\t\tG_Sound(ent, CHAN_VOICE, G_SoundIndex(\"sound/player/gurp2.wav\"));\n\t\t\t\t}\n\n\t\t\t\t// don't play a normal pain sound\n\t\t\t\tent->pain_debounce_time = level.time + 200;\n\n\t\t\t\tG_Damage (ent, NULL, NULL, NULL, NULL, \n\t\t\t\t\tent->damage, DAMAGE_NO_ARMOR, MOD_WATER);\n\t\t\t}\n\t\t}\n\t} else {\n\t\tent->client->airOutTime = level.time + 12000;\n\t\tent->damage = 2;\n\t}\n\n\t//\n\t// check for sizzle damage (move to pmove?)\n\t//\n\tif (waterlevel && \n\t\t(ent->watertype&(CONTENTS_LAVA|CONTENTS_SLIME)) ) {\n\t\tif (ent->health > 0\n\t\t\t&& ent->pain_debounce_time <= level.time\t) {\n\n\t\t\tif ( envirosuit ) {\n\t\t\t\tG_AddEvent( ent, EV_POWERUP_BATTLESUIT, 0 );\n\t\t\t} else {\n\t\t\t\tif (ent->watertype & CONTENTS_LAVA) {\n\t\t\t\t\tG_Damage (ent, NULL, NULL, NULL, NULL, \n\t\t\t\t\t\t30*waterlevel, 0, MOD_LAVA);\n\t\t\t\t}\n\n\t\t\t\tif (ent->watertype & CONTENTS_SLIME) {\n\t\t\t\t\tG_Damage (ent, NULL, NULL, NULL, NULL, \n\t\t\t\t\t\t10*waterlevel, 0, MOD_SLIME);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n\n\n/*\n===============\nG_SetClientSound\n===============\n*/\nvoid G_SetClientSound( gentity_t *ent ) {\n\tif (ent->waterlevel && (ent->watertype&(CONTENTS_LAVA|CONTENTS_SLIME)) ) {\n\t\tent->client->ps.loopSound = level.snd_fry;\n\t} else {\n\t\tent->client->ps.loopSound = 0;\n\t}\n}\n\n\n\n//==============================================================\n\n/*\n==============\nClientImpacts\n==============\n*/\nvoid ClientImpacts( gentity_t *ent, pmove_t *pm ) {\n\tint\t\ti, j;\n\ttrace_t\ttrace;\n\tgentity_t\t*other;\n\n\tmemset( &trace, 0, sizeof( trace ) );\n\tfor (i=0 ; i<pm->numtouch ; i++) {\n\t\tfor (j=0 ; j<i ; j++) {\n\t\t\tif (pm->touchents[j] == pm->touchents[i] ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (j != i) {\n\t\t\tcontinue;\t// duplicated\n\t\t}\n\t\tother = &g_entities[ pm->touchents[i] ];\n\n\t\tif ( ( ent->r.svFlags & SVF_BOT ) && ( ent->touch ) ) {\n\t\t\tent->touch( ent, other, &trace );\n\t\t}\n\n\t\tif ( !other->touch ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tother->touch( other, ent, &trace );\n\t}\n\n}\n\n/*\n============\nG_TouchTriggers\n\nFind all trigger entities that ent's current position touches.\nSpectators will only interact with teleporters.\n============\n*/\nvoid\tG_TouchTriggers( gentity_t *ent ) {\n\tint\t\t\ti, num;\n\tint\t\t\ttouch[MAX_GENTITIES];\n\tgentity_t\t*hit;\n\ttrace_t\t\ttrace;\n\tvec3_t\t\tmins, maxs;\n\tstatic vec3_t\trange = { 40, 40, 52 };\n\n\tif ( !ent->client ) {\n\t\treturn;\n\t}\n\n\t// dead clients don't activate triggers!\n\tif ( ent->client->ps.stats[STAT_HEALTH] <= 0 ) {\n\t\treturn;\n\t}\n\n\tVectorSubtract( ent->client->ps.origin, range, mins );\n\tVectorAdd( ent->client->ps.origin, range, maxs );\n\n\tnum = trap_EntitiesInBox( mins, maxs, touch, MAX_GENTITIES );\n\n\t// can't use ent->absmin, because that has a one unit pad\n\tVectorAdd( ent->client->ps.origin, ent->r.mins, mins );\n\tVectorAdd( ent->client->ps.origin, ent->r.maxs, maxs );\n\n\tfor ( i=0 ; i<num ; i++ ) {\n\t\thit = &g_entities[touch[i]];\n\n\t\tif ( !hit->touch && !ent->touch ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( !( hit->r.contents & CONTENTS_TRIGGER ) ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// ignore most entities if a spectator\n\t\tif ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) {\n\t\t\tif ( hit->s.eType != ET_TELEPORT_TRIGGER &&\n\t\t\t\t// this is ugly but adding a new ET_? type will\n\t\t\t\t// most likely cause network incompatibilities\n\t\t\t\thit->touch != Touch_DoorTrigger) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\t// use seperate code for determining if an item is picked up\n\t\t// so you don't have to actually contact its bounding box\n\t\tif ( hit->s.eType == ET_ITEM ) {\n\t\t\tif ( !BG_PlayerTouchesItem( &ent->client->ps, &hit->s, level.time ) ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t} else {\n\t\t\tif ( !trap_EntityContact( mins, maxs, hit ) ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\tmemset( &trace, 0, sizeof(trace) );\n\n\t\tif ( hit->touch ) {\n\t\t\thit->touch (hit, ent, &trace);\n\t\t}\n\n\t\tif ( ( ent->r.svFlags & SVF_BOT ) && ( ent->touch ) ) {\n\t\t\tent->touch( ent, hit, &trace );\n\t\t}\n\t}\n\n\t// if we didn't touch a jump pad this pmove frame\n\tif ( ent->client->ps.jumppad_frame != ent->client->ps.pmove_framecount ) {\n\t\tent->client->ps.jumppad_frame = 0;\n\t\tent->client->ps.jumppad_ent = 0;\n\t}\n}\n\n/*\n=================\nSpectatorThink\n=================\n*/\nvoid SpectatorThink( gentity_t *ent, usercmd_t *ucmd ) {\n\tpmove_t\tpm;\n\tgclient_t\t*client;\n\n\tclient = ent->client;\n\n\tif ( client->sess.spectatorState != SPECTATOR_FOLLOW ) {\n\t\tclient->ps.pm_type = PM_SPECTATOR;\n\t\tclient->ps.speed = 400;\t// faster than normal\n\n\t\t// set up for pmove\n\t\tmemset (&pm, 0, sizeof(pm));\n\t\tpm.ps = &client->ps;\n\t\tpm.cmd = *ucmd;\n\t\tpm.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY;\t// spectators can fly through bodies\n\t\tpm.trace = trap_Trace;\n\t\tpm.pointcontents = trap_PointContents;\n\n\t\t// perform a pmove\n\t\tPmove (&pm);\n\t\t// save results of pmove\n\t\tVectorCopy( client->ps.origin, ent->s.origin );\n\n\t\tG_TouchTriggers( ent );\n\t\ttrap_UnlinkEntity( ent );\n\t}\n\n\tclient->oldbuttons = client->buttons;\n\tclient->buttons = ucmd->buttons;\n\n\t// attack button cycles through spectators\n\tif ( ( client->buttons & BUTTON_ATTACK ) && ! ( client->oldbuttons & BUTTON_ATTACK ) ) {\n\t\tCmd_FollowCycle_f( ent, 1 );\n\t}\n}\n\n\n\n/*\n=================\nClientInactivityTimer\n\nReturns qfalse if the client is dropped\n=================\n*/\nqboolean ClientInactivityTimer( gclient_t *client ) {\n\tif ( ! g_inactivity.integer ) {\n\t\t// give everyone some time, so if the operator sets g_inactivity during\n\t\t// gameplay, everyone isn't kicked\n\t\tclient->inactivityTime = level.time + 60 * 1000;\n\t\tclient->inactivityWarning = qfalse;\n\t} else if ( client->pers.cmd.forwardmove || \n\t\tclient->pers.cmd.rightmove || \n\t\tclient->pers.cmd.upmove ||\n\t\t(client->pers.cmd.buttons & BUTTON_ATTACK) ) {\n\t\tclient->inactivityTime = level.time + g_inactivity.integer * 1000;\n\t\tclient->inactivityWarning = qfalse;\n\t} else if ( !client->pers.localClient ) {\n\t\tif ( level.time > client->inactivityTime ) {\n\t\t\ttrap_DropClient( client - level.clients, \"Dropped due to inactivity\" );\n\t\t\treturn qfalse;\n\t\t}\n\t\tif ( level.time > client->inactivityTime - 10000 && !client->inactivityWarning ) {\n\t\t\tclient->inactivityWarning = qtrue;\n\t\t\ttrap_SendServerCommand( client - level.clients, \"cp \\\"Ten seconds until inactivity drop!\\n\\\"\" );\n\t\t}\n\t}\n\treturn qtrue;\n}\n\n/*\n==================\nClientTimerActions\n\nActions that happen once a second\n==================\n*/\nvoid ClientTimerActions( gentity_t *ent, int msec ) {\n\tgclient_t\t*client;\n\n\tclient = ent->client;\n\tclient->timeResidual += msec;\n\n\twhile ( client->timeResidual >= 1000 ) {\n\t\tclient->timeResidual -= 1000;\n\n\t\t// regenerate\n\t\tif ( client->ps.powerups[PW_REGEN] ) {\n\t\t\tif ( ent->health < client->ps.stats[STAT_MAX_HEALTH]) {\n\t\t\t\tent->health += 15;\n\t\t\t\tif ( ent->health > client->ps.stats[STAT_MAX_HEALTH] * 1.1 ) {\n\t\t\t\t\tent->health = client->ps.stats[STAT_MAX_HEALTH] * 1.1;\n\t\t\t\t}\n\t\t\t\tG_AddEvent( ent, EV_POWERUP_REGEN, 0 );\n\t\t\t} else if ( ent->health < client->ps.stats[STAT_MAX_HEALTH] * 2) {\n\t\t\t\tent->health += 5;\n\t\t\t\tif ( ent->health > client->ps.stats[STAT_MAX_HEALTH] * 2 ) {\n\t\t\t\t\tent->health = client->ps.stats[STAT_MAX_HEALTH] * 2;\n\t\t\t\t}\n\t\t\t\tG_AddEvent( ent, EV_POWERUP_REGEN, 0 );\n\t\t\t}\n\t\t} else {\n\t\t\t// count down health when over max\n\t\t\tif ( ent->health > client->ps.stats[STAT_MAX_HEALTH] ) {\n\t\t\t\tent->health--;\n\t\t\t}\n\t\t}\n\n\t\t// count down armor when over max\n\t\tif ( client->ps.stats[STAT_ARMOR] > client->ps.stats[STAT_MAX_HEALTH] ) {\n\t\t\tclient->ps.stats[STAT_ARMOR]--;\n\t\t}\n\t}\n}\n\n/*\n====================\nClientIntermissionThink\n====================\n*/\nvoid ClientIntermissionThink( gclient_t *client ) {\n\tclient->ps.eFlags &= ~EF_TALK;\n\tclient->ps.eFlags &= ~EF_FIRING;\n\n\t// the level will exit when everyone wants to or after timeouts\n\n\t// swap and latch button actions\n\tclient->oldbuttons = client->buttons;\n\tclient->buttons = client->pers.cmd.buttons;\n\tif ( client->buttons & ( BUTTON_ATTACK | BUTTON_USE_HOLDABLE ) & ( client->oldbuttons ^ client->buttons ) ) {\n\t\t// this used to be an ^1 but once a player says ready, it should stick\n\t\tclient->readyToExit = 1;\n\t}\n}\n\n\n/*\n================\nClientEvents\n\nEvents will be passed on to the clients for presentation,\nbut any server game effects are handled here\n================\n*/\nvoid ClientEvents( gentity_t *ent, int oldEventSequence ) {\n\tint\t\ti, j;\n\tint\t\tevent;\n\tgclient_t *client;\n\tint\t\tdamage;\n\tvec3_t\tdir;\n\tvec3_t\torigin, angles;\n//\tqboolean\tfired;\n\tgitem_t *item;\n\tgentity_t *drop;\n\n\tclient = ent->client;\n\n\tif ( oldEventSequence < client->ps.eventSequence - MAX_PS_EVENTS ) {\n\t\toldEventSequence = client->ps.eventSequence - MAX_PS_EVENTS;\n\t}\n\tfor ( i = oldEventSequence ; i < client->ps.eventSequence ; i++ ) {\n\t\tevent = client->ps.events[ i & (MAX_PS_EVENTS-1) ];\n\n\t\tswitch ( event ) {\n\t\tcase EV_FALL_MEDIUM:\n\t\tcase EV_FALL_FAR:\n\t\t\tif ( ent->s.eType != ET_PLAYER ) {\n\t\t\t\tbreak;\t\t// not in the player model\n\t\t\t}\n\t\t\tif ( g_dmflags.integer & DF_NO_FALLING ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( event == EV_FALL_FAR ) {\n\t\t\t\tdamage = 10;\n\t\t\t} else {\n\t\t\t\tdamage = 5;\n\t\t\t}\n\t\t\tVectorSet (dir, 0, 0, 1);\n\t\t\tent->pain_debounce_time = level.time + 200;\t// no normal pain sound\n\t\t\tG_Damage (ent, NULL, NULL, NULL, NULL, damage, 0, MOD_FALLING);\n\t\t\tbreak;\n\n\t\tcase EV_FIRE_WEAPON:\n\t\t\tFireWeapon( ent );\n\t\t\tbreak;\n\n\t\tcase EV_USE_ITEM1:\t\t// teleporter\n\t\t\t// drop flags in CTF\n\t\t\titem = NULL;\n\t\t\tj = 0;\n\n\t\t\tif ( ent->client->ps.powerups[ PW_REDFLAG ] ) {\n\t\t\t\titem = BG_FindItemForPowerup( PW_REDFLAG );\n\t\t\t\tj = PW_REDFLAG;\n\t\t\t} else if ( ent->client->ps.powerups[ PW_BLUEFLAG ] ) {\n\t\t\t\titem = BG_FindItemForPowerup( PW_BLUEFLAG );\n\t\t\t\tj = PW_BLUEFLAG;\n\t\t\t} else if ( ent->client->ps.powerups[ PW_NEUTRALFLAG ] ) {\n\t\t\t\titem = BG_FindItemForPowerup( PW_NEUTRALFLAG );\n\t\t\t\tj = PW_NEUTRALFLAG;\n\t\t\t}\n\n\t\t\tif ( item ) {\n\t\t\t\tdrop = Drop_Item( ent, item, 0 );\n\t\t\t\t// decide how many seconds it has left\n\t\t\t\tdrop->count = ( ent->client->ps.powerups[ j ] - level.time ) / 1000;\n\t\t\t\tif ( drop->count < 1 ) {\n\t\t\t\t\tdrop->count = 1;\n\t\t\t\t}\n\n\t\t\t\tent->client->ps.powerups[ j ] = 0;\n\t\t\t}\n\n\t\t\tSelectSpawnPoint( ent->client->ps.origin, origin, angles );\n\t\t\tTeleportPlayer( ent, origin, angles );\n\t\t\tbreak;\n\n\t\tcase EV_USE_ITEM2:\t\t// medkit\n\t\t\tent->health = ent->client->ps.stats[STAT_MAX_HEALTH] + 25;\n\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\t}\n\n}\n\nvoid BotTestSolid(vec3_t origin);\n\n/*\n==============\nSendPendingPredictableEvents\n==============\n*/\nvoid SendPendingPredictableEvents( playerState_t *ps ) {\n\tgentity_t *t;\n\tint event, seq;\n\tint extEvent, number;\n\n\t// if there are still events pending\n\tif ( ps->entityEventSequence < ps->eventSequence ) {\n\t\t// create a temporary entity for this event which is sent to everyone\n\t\t// except the client who generated the event\n\t\tseq = ps->entityEventSequence & (MAX_PS_EVENTS-1);\n\t\tevent = ps->events[ seq ] | ( ( ps->entityEventSequence & 3 ) << 8 );\n\t\t// set external event to zero before calling BG_PlayerStateToEntityState\n\t\textEvent = ps->externalEvent;\n\t\tps->externalEvent = 0;\n\t\t// create temporary entity for event\n\t\tt = G_TempEntity( ps->origin, event );\n\t\tnumber = t->s.number;\n\t\tBG_PlayerStateToEntityState( ps, &t->s, qtrue );\n\t\tt->s.number = number;\n\t\tt->s.eType = ET_EVENTS + event;\n\t\tt->s.eFlags |= EF_PLAYER_EVENT;\n\t\tt->s.otherEntityNum = ps->clientNum;\n\t\t// send to everyone except the client who generated the event\n\t\tt->r.svFlags |= SVF_NOTSINGLECLIENT;\n\t\tt->r.singleClient = ps->clientNum;\n\t\t// set back external event\n\t\tps->externalEvent = extEvent;\n\t}\n}\n\n/*\n==============\nClientThink\n\nThis will be called once for each client frame, which will\nusually be a couple times for each server frame on fast clients.\n\nIf \"g_synchronousClients 1\" is set, this will be called exactly\nonce for each server frame, which makes for smooth demo recording.\n==============\n*/\nvoid ClientThink_real( gentity_t *ent ) {\n\tgclient_t\t*client;\n\tpmove_t\t\tpm;\n\tint\t\t\toldEventSequence;\n\tint\t\t\tmsec;\n\tusercmd_t\t*ucmd;\n\n\tclient = ent->client;\n\n\t// don't think if the client is not yet connected (and thus not yet spawned in)\n\tif (client->pers.connected != CON_CONNECTED) {\n\t\treturn;\n\t}\n\t// mark the time, so the connection sprite can be removed\n\tucmd = &ent->client->pers.cmd;\n\n\t// sanity check the command time to prevent speedup cheating\n\tif ( ucmd->serverTime > level.time + 200 ) {\n\t\tucmd->serverTime = level.time + 200;\n//\t\tG_Printf(\"serverTime <<<<<\\n\" );\n\t}\n\tif ( ucmd->serverTime < level.time - 1000 ) {\n\t\tucmd->serverTime = level.time - 1000;\n//\t\tG_Printf(\"serverTime >>>>>\\n\" );\n\t} \n\n\tmsec = ucmd->serverTime - client->ps.commandTime;\n\t// following others may result in bad times, but we still want\n\t// to check for follow toggles\n\tif ( msec < 1 && client->sess.spectatorState != SPECTATOR_FOLLOW ) {\n\t\treturn;\n\t}\n\tif ( msec > 200 ) {\n\t\tmsec = 200;\n\t}\n\n\tif ( pmove_msec.integer < 8 ) {\n\t\ttrap_Cvar_Set(\"pmove_msec\", \"8\");\n\t}\n\telse if (pmove_msec.integer > 33) {\n\t\ttrap_Cvar_Set(\"pmove_msec\", \"33\");\n\t}\n\n\tif ( pmove_fixed.integer || client->pers.pmoveFixed ) {\n\t\tucmd->serverTime = ((ucmd->serverTime + pmove_msec.integer-1) / pmove_msec.integer) * pmove_msec.integer;\n\t\t//if (ucmd->serverTime - client->ps.commandTime <= 0)\n\t\t//\treturn;\n\t}\n\n\t//\n\t// check for exiting intermission\n\t//\n\tif ( level.intermissiontime ) {\n\t\tClientIntermissionThink( client );\n\t\treturn;\n\t}\n\n\t// spectators don't do much\n\tif ( client->sess.sessionTeam == TEAM_SPECTATOR ) {\n\t\tif ( client->sess.spectatorState == SPECTATOR_SCOREBOARD ) {\n\t\t\treturn;\n\t\t}\n\t\tSpectatorThink( ent, ucmd );\n\t\treturn;\n\t}\n\n\t// check for inactivity timer, but never drop the local client of a non-dedicated server\n\tif ( !ClientInactivityTimer( client ) ) {\n\t\treturn;\n\t}\n\n\t// clear the rewards if time\n\tif ( level.time > client->rewardTime ) {\n\t\tclient->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );\n\t}\n\n\tif ( client->noclip ) {\n\t\tclient->ps.pm_type = PM_NOCLIP;\n\t} else if ( client->ps.stats[STAT_HEALTH] <= 0 ) {\n\t\tclient->ps.pm_type = PM_DEAD;\n\t} else {\n\t\tclient->ps.pm_type = PM_NORMAL;\n\t}\n\n\tclient->ps.gravity = g_gravity.value;\n\n\t// set speed\n\tclient->ps.speed = g_speed.value;\n\n\tif ( client->ps.powerups[PW_HASTE] ) {\n\t\tclient->ps.speed *= 1.3;\n\t}\n\n\t// Let go of the hook if we aren't firing\n\tif ( client->ps.weapon == WP_GRAPPLING_HOOK &&\n\t\tclient->hook && !( ucmd->buttons & BUTTON_ATTACK ) ) {\n\t\tWeapon_HookFree(client->hook);\n\t}\n\n\t// set up for pmove\n\toldEventSequence = client->ps.eventSequence;\n\n\tmemset (&pm, 0, sizeof(pm));\n\n\t// check for the hit-scan gauntlet, don't let the action\n\t// go through as an attack unless it actually hits something\n\tif ( client->ps.weapon == WP_GAUNTLET && !( ucmd->buttons & BUTTON_TALK ) &&\n\t\t( ucmd->buttons & BUTTON_ATTACK ) && client->ps.weaponTime <= 0 ) {\n\t\tpm.gauntletHit = CheckGauntletAttack( ent );\n\t}\n\n\tif ( ent->flags & FL_FORCE_GESTURE ) {\n\t\tent->flags &= ~FL_FORCE_GESTURE;\n\t\tent->client->pers.cmd.buttons |= BUTTON_GESTURE;\n\t}\n\n\tpm.ps = &client->ps;\n\tpm.cmd = *ucmd;\n\tif ( pm.ps->pm_type == PM_DEAD ) {\n\t\tpm.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY;\n\t}\n\telse if ( ent->r.svFlags & SVF_BOT ) {\n\t\tpm.tracemask = MASK_PLAYERSOLID | CONTENTS_BOTCLIP;\n\t}\n\telse {\n\t\tpm.tracemask = MASK_PLAYERSOLID;\n\t}\n\tpm.trace = trap_Trace;\n\tpm.pointcontents = trap_PointContents;\n\tpm.debugLevel = g_debugMove.integer;\n\tpm.noFootsteps = ( g_dmflags.integer & DF_NO_FOOTSTEPS ) > 0;\n\n\tpm.pmove_fixed = pmove_fixed.integer | client->pers.pmoveFixed;\n\tpm.pmove_msec = pmove_msec.integer;\n\n\tVectorCopy( client->ps.origin, client->oldOrigin );\n\n\tPmove (&pm);\n\n\t// save results of pmove\n\tif ( ent->client->ps.eventSequence != oldEventSequence ) {\n\t\tent->eventTime = level.time;\n\t}\n\tif (g_smoothClients.integer) {\n\t\tBG_PlayerStateToEntityStateExtraPolate( &ent->client->ps, &ent->s, ent->client->ps.commandTime, qtrue );\n\t}\n\telse {\n\t\tBG_PlayerStateToEntityState( &ent->client->ps, &ent->s, qtrue );\n\t}\n\tSendPendingPredictableEvents( &ent->client->ps );\n\n\tif ( !( ent->client->ps.eFlags & EF_FIRING ) ) {\n\t\tclient->fireHeld = qfalse;\t\t// for grapple\n\t}\n\n\t// use the snapped origin for linking so it matches client predicted versions\n\tVectorCopy( ent->s.pos.trBase, ent->r.currentOrigin );\n\n\tVectorCopy (pm.mins, ent->r.mins);\n\tVectorCopy (pm.maxs, ent->r.maxs);\n\n\tent->waterlevel = pm.waterlevel;\n\tent->watertype = pm.watertype;\n\n\t// execute client events\n\tClientEvents( ent, oldEventSequence );\n\n\t// link entity now, after any personal teleporters have been used\n\ttrap_LinkEntity (ent);\n\tif ( !ent->client->noclip ) {\n\t\tG_TouchTriggers( ent );\n\t}\n\n\t// NOTE: now copy the exact origin over otherwise clients can be snapped into solid\n\tVectorCopy( ent->client->ps.origin, ent->r.currentOrigin );\n\n\t//test for solid areas in the AAS file\n\tBotTestAAS(ent->r.currentOrigin);\n\n\t// touch other objects\n\tClientImpacts( ent, &pm );\n\n\t// save results of triggers and client events\n\tif (ent->client->ps.eventSequence != oldEventSequence) {\n\t\tent->eventTime = level.time;\n\t}\n\n\t// swap and latch button actions\n\tclient->oldbuttons = client->buttons;\n\tclient->buttons = ucmd->buttons;\n\tclient->latched_buttons |= client->buttons & ~client->oldbuttons;\n\n\t// check for respawning\n\tif ( client->ps.stats[STAT_HEALTH] <= 0 ) {\n\t\t// wait for the attack button to be pressed\n\t\tif ( level.time > client->respawnTime ) {\n\t\t\t// forcerespawn is to prevent users from waiting out powerups\n\t\t\tif ( g_forcerespawn.integer > 0 && \n\t\t\t\t( level.time - client->respawnTime ) > g_forcerespawn.integer * 1000 ) {\n\t\t\t\trespawn( ent );\n\t\t\t\treturn;\n\t\t\t}\n\t\t\n\t\t\t// pressing attack or use is the normal respawn method\n\t\t\tif ( ucmd->buttons & ( BUTTON_ATTACK | BUTTON_USE_HOLDABLE ) ) {\n\t\t\t\trespawn( ent );\n\t\t\t}\n\t\t}\n\t\treturn;\n\t}\n\n\t// perform once-a-second actions\n\tClientTimerActions( ent, msec );\n}\n\n/*\n==================\nClientThink\n\nA new command has arrived from the client\n==================\n*/\nvoid ClientThink( int clientNum ) {\n\tgentity_t *ent;\n\n\tent = g_entities + clientNum;\n\ttrap_GetUsercmd( clientNum, &ent->client->pers.cmd );\n\n\t// mark the time we got info, so we can display the\n\t// phone jack if they don't get any for a while\n\tent->client->lastCmdTime = level.time;\n\n\tif ( !(ent->r.svFlags & SVF_BOT) && !g_synchronousClients.integer ) {\n\t\tClientThink_real( ent );\n\t}\n}\n\n\nvoid G_RunClient( gentity_t *ent ) {\n\tif ( !(ent->r.svFlags & SVF_BOT) && !g_synchronousClients.integer ) {\n\t\treturn;\n\t}\n\tent->client->pers.cmd.serverTime = level.time;\n\tClientThink_real( ent );\n}\n\n\n/*\n==================\nSpectatorClientEndFrame\n\n==================\n*/\nvoid SpectatorClientEndFrame( gentity_t *ent ) {\n\tgclient_t\t*cl;\n\n\t// if we are doing a chase cam or a remote view, grab the latest info\n\tif ( ent->client->sess.spectatorState == SPECTATOR_FOLLOW ) {\n\t\tint\t\tclientNum, flags;\n\n\t\tclientNum = ent->client->sess.spectatorClient;\n\n\t\t// team follow1 and team follow2 go to whatever clients are playing\n\t\tif ( clientNum == -1 ) {\n\t\t\tclientNum = level.follow1;\n\t\t} else if ( clientNum == -2 ) {\n\t\t\tclientNum = level.follow2;\n\t\t}\n\t\tif ( clientNum >= 0 ) {\n\t\t\tcl = &level.clients[ clientNum ];\n\t\t\tif ( cl->pers.connected == CON_CONNECTED && cl->sess.sessionTeam != TEAM_SPECTATOR ) {\n\t\t\t\tflags = (cl->ps.eFlags & ~(EF_VOTED | EF_TEAMVOTED)) | (ent->client->ps.eFlags & (EF_VOTED | EF_TEAMVOTED));\n\t\t\t\tent->client->ps = cl->ps;\n\t\t\t\tent->client->ps.pm_flags |= PMF_FOLLOW;\n\t\t\t\tent->client->ps.eFlags = flags;\n\t\t\t\treturn;\n\t\t\t} else {\n\t\t\t\t// drop them to free spectators unless they are dedicated camera followers\n\t\t\t\tif ( ent->client->sess.spectatorClient >= 0 ) {\n\t\t\t\t\tent->client->sess.spectatorState = SPECTATOR_FREE;\n\t\t\t\t\tClientBegin( ent->client - level.clients );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif ( ent->client->sess.spectatorState == SPECTATOR_SCOREBOARD ) {\n\t\tent->client->ps.pm_flags |= PMF_SCOREBOARD;\n\t} else {\n\t\tent->client->ps.pm_flags &= ~PMF_SCOREBOARD;\n\t}\n}\n\n/*\n==============\nClientEndFrame\n\nCalled at the end of each server frame for each connected client\nA fast client will have multiple ClientThink for each ClientEdFrame,\nwhile a slow client may have multiple ClientEndFrame between ClientThink.\n==============\n*/\nvoid ClientEndFrame( gentity_t *ent ) {\n\tint\t\t\ti;\n\tclientPersistant_t\t*pers;\n\n\tif ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) {\n\t\tSpectatorClientEndFrame( ent );\n\t\treturn;\n\t}\n\n\tpers = &ent->client->pers;\n\n\t// turn off any expired powerups\n\tfor ( i = 0 ; i < MAX_POWERUPS ; i++ ) {\n\t\tif ( ent->client->ps.powerups[ i ] < level.time ) {\n\t\t\tent->client->ps.powerups[ i ] = 0;\n\t\t}\n\t}\n\n\t// save network bandwidth\n#if 0\n\tif ( !g_synchronousClients->integer && ent->client->ps.pm_type == PM_NORMAL ) {\n\t\t// FIXME: this must change eventually for non-sync demo recording\n\t\tVectorClear( ent->client->ps.viewangles );\n\t}\n#endif\n\n\t//\n\t// If the end of unit layout is displayed, don't give\n\t// the player any normal movement attributes\n\t//\n\tif ( level.intermissiontime ) {\n\t\treturn;\n\t}\n\n\t// burn from lava, etc\n\tP_WorldEffects (ent);\n\n\t// apply all the damage taken this frame\n\tP_DamageFeedback (ent);\n\n\t// add the EF_CONNECTION flag if we haven't gotten commands recently\n\tif ( level.time - ent->client->lastCmdTime > 1000 ) {\n\t\tent->s.eFlags |= EF_CONNECTION;\n\t} else {\n\t\tent->s.eFlags &= ~EF_CONNECTION;\n\t}\n\n\tent->client->ps.stats[STAT_HEALTH] = ent->health;\t// FIXME: get rid of ent->health...\n\n\tG_SetClientSound (ent);\n\n\t// set the latest infor\n\tif (g_smoothClients.integer) {\n\t\tBG_PlayerStateToEntityStateExtraPolate( &ent->client->ps, &ent->s, ent->client->ps.commandTime, qtrue );\n\t}\n\telse {\n\t\tBG_PlayerStateToEntityState( &ent->client->ps, &ent->s, qtrue );\n\t}\n\tSendPendingPredictableEvents( &ent->client->ps );\n\n\t// set the bit for the reachability area the client is currently in\n//\ti = trap_AAS_PointReachabilityAreaIndex( ent->client->ps.origin );\n//\tent->client->areabits[i >> 3] |= 1 << (i & 7);\n}\n\n\n"
  },
  {
    "path": "src/game/g_arenas.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n//\n// g_arenas.c\n//\n\n#include \"g_local.h\"\n\n\ngentity_t\t*podium1;\ngentity_t\t*podium2;\ngentity_t\t*podium3;\n\n\n/*\n==================\nUpdateTournamentInfo\n==================\n*/\nvoid UpdateTournamentInfo( void ) {\n\tint\t\t\ti;\n\tgentity_t\t*player;\n\tint\t\t\tplayerClientNum;\n\tint\t\t\tn, accuracy, perfect,\tmsglen;\n\tint\t\t\tbuflen;\n\tchar\t\tbuf[32];\n\tchar\t\tmsg[MAX_STRING_CHARS];\n\n\t// find the real player\n\tplayer = NULL;\n\tfor (i = 0; i < level.maxclients; i++ ) {\n\t\tplayer = &g_entities[i];\n\t\tif ( !player->inuse ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( !( player->r.svFlags & SVF_BOT ) ) {\n\t\t\tbreak;\n\t\t}\n\t}\n\t// this should never happen!\n\tif ( !player || i == level.maxclients ) {\n\t\treturn;\n\t}\n\tplayerClientNum = i;\n\n\tCalculateRanks();\n\n\tif ( level.clients[playerClientNum].sess.sessionTeam == TEAM_SPECTATOR ) {\n\t\tCom_sprintf( msg, sizeof(msg), \"postgame %i %i 0 0 0 0 0 0\", level.numNonSpectatorClients, playerClientNum );\n\t}\n\telse {\n\t\tif( player->client->accuracy_shots ) {\n\t\t\taccuracy = player->client->accuracy_hits * 100 / player->client->accuracy_shots;\n\t\t}\n\t\telse {\n\t\t\taccuracy = 0;\n\t\t}\n\n\t\tperfect = ( level.clients[playerClientNum].ps.persistant[PERS_RANK] == 0 && player->client->ps.persistant[PERS_KILLED] == 0 ) ? 1 : 0;\n\t\tCom_sprintf( msg, sizeof(msg), \"postgame %i %i %i %i %i %i %i %i\", level.numNonSpectatorClients, playerClientNum, accuracy,\n\t\t\tplayer->client->ps.persistant[PERS_IMPRESSIVE_COUNT], player->client->ps.persistant[PERS_EXCELLENT_COUNT],\n\t\t\tplayer->client->ps.persistant[PERS_GAUNTLET_FRAG_COUNT], player->client->ps.persistant[PERS_SCORE],\n\t\t\tperfect );\n\t}\n\n\tmsglen = (int)strlen( msg );\n\tfor( i = 0; i < level.numNonSpectatorClients; i++ ) {\n\t\tn = level.sortedClients[i];\n\t\tCom_sprintf( buf, sizeof(buf), \" %i %i %i\", n, level.clients[n].ps.persistant[PERS_RANK], level.clients[n].ps.persistant[PERS_SCORE] );\n\t\tbuflen = (int)strlen( buf );\n\t\tif( msglen + buflen + 1 >= sizeof(msg) ) {\n\t\t\tbreak;\n\t\t}\n\t\tstrcat( msg, buf );\n\t}\n\ttrap_SendConsoleCommand( EXEC_APPEND, msg );\n}\n\n\nstatic gentity_t *SpawnModelOnVictoryPad( gentity_t *pad, vec3_t offset, gentity_t *ent, int place ) {\n\tgentity_t\t*body;\n\tvec3_t\t\tvec;\n\tvec3_t\t\tf, r, u;\n\n\tbody = G_Spawn();\n\tif ( !body ) {\n\t\tG_Printf( S_COLOR_RED \"ERROR: out of gentities\\n\" );\n\t\treturn NULL;\n\t}\n\n\tbody->classname = ent->client->pers.netname;\n\tbody->client = ent->client;\n\tbody->s = ent->s;\n\tbody->s.eType = ET_PLAYER;\t\t// could be ET_INVISIBLE\n\tbody->s.eFlags = 0;\t\t\t\t// clear EF_TALK, etc\n\tbody->s.powerups = 0;\t\t\t// clear powerups\n\tbody->s.loopSound = 0;\t\t\t// clear lava burning\n\tbody->s.number = body - g_entities;\n\tbody->timestamp = level.time;\n\tbody->physicsObject = qtrue;\n\tbody->physicsBounce = 0;\t\t// don't bounce\n\tbody->s.event = 0;\n\tbody->s.pos.trType = TR_STATIONARY;\n\tbody->s.groundEntityNum = ENTITYNUM_WORLD;\n\tbody->s.legsAnim = LEGS_IDLE;\n\tbody->s.torsoAnim = TORSO_STAND;\n\tif( body->s.weapon == WP_NONE ) {\n\t\tbody->s.weapon = WP_MACHINEGUN;\n\t}\n\tif( body->s.weapon == WP_GAUNTLET) {\n\t\tbody->s.torsoAnim = TORSO_STAND2;\n\t}\n\tbody->s.event = 0;\n\tbody->r.svFlags = ent->r.svFlags;\n\tVectorCopy (ent->r.mins, body->r.mins);\n\tVectorCopy (ent->r.maxs, body->r.maxs);\n\tVectorCopy (ent->r.absmin, body->r.absmin);\n\tVectorCopy (ent->r.absmax, body->r.absmax);\n\tbody->clipmask = CONTENTS_SOLID | CONTENTS_PLAYERCLIP;\n\tbody->r.contents = CONTENTS_BODY;\n\tbody->r.ownerNum = ent->r.ownerNum;\n\tbody->takedamage = qfalse;\n\n\tVectorSubtract( level.intermission_origin, pad->r.currentOrigin, vec );\n\tvectoangles( vec, body->s.apos.trBase );\n\tbody->s.apos.trBase[PITCH] = 0;\n\tbody->s.apos.trBase[ROLL] = 0;\n\n\tAngleVectors( body->s.apos.trBase, f, r, u );\n\tVectorMA( pad->r.currentOrigin, offset[0], f, vec );\n\tVectorMA( vec, offset[1], r, vec );\n\tVectorMA( vec, offset[2], u, vec );\n\n\tG_SetOrigin( body, vec );\n\n\ttrap_LinkEntity (body);\n\n\tbody->count = place;\n\n\treturn body;\n}\n\n\nstatic void CelebrateStop( gentity_t *player ) {\n\tint\t\tanim;\n\n\tif( player->s.weapon == WP_GAUNTLET) {\n\t\tanim = TORSO_STAND2;\n\t}\n\telse {\n\t\tanim = TORSO_STAND;\n\t}\n\tplayer->s.torsoAnim = ( ( player->s.torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;\n}\n\n\n#define\tTIMER_GESTURE\t(34*66+50)\nstatic void CelebrateStart( gentity_t *player ) {\n\tplayer->s.torsoAnim = ( ( player->s.torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | TORSO_GESTURE;\n\tplayer->nextthink = level.time + TIMER_GESTURE;\n\tplayer->think = CelebrateStop;\n\n\t/*\n\tplayer->client->ps.events[player->client->ps.eventSequence & (MAX_PS_EVENTS-1)] = EV_TAUNT;\n\tplayer->client->ps.eventParms[player->client->ps.eventSequence & (MAX_PS_EVENTS-1)] = 0;\n\tplayer->client->ps.eventSequence++;\n\t*/\n\tG_AddEvent(player, EV_TAUNT, 0);\n}\n\n\nstatic vec3_t\toffsetFirst  = {0, 0, 74};\nstatic vec3_t\toffsetSecond = {-10, 60, 54};\nstatic vec3_t\toffsetThird  = {-19, -60, 45};\n\nstatic void PodiumPlacementThink( gentity_t *podium ) {\n\tvec3_t\t\tvec;\n\tvec3_t\t\torigin;\n\tvec3_t\t\tf, r, u;\n\n\tpodium->nextthink = level.time + 100;\n\n\tAngleVectors( level.intermission_angle, vec, NULL, NULL );\n\tVectorMA( level.intermission_origin, trap_Cvar_VariableIntegerValue( \"g_podiumDist\" ), vec, origin );\n\torigin[2] -= trap_Cvar_VariableIntegerValue( \"g_podiumDrop\" );\n\tG_SetOrigin( podium, origin );\n\n\tif( podium1 ) {\n\t\tVectorSubtract( level.intermission_origin, podium->r.currentOrigin, vec );\n\t\tvectoangles( vec, podium1->s.apos.trBase );\n\t\tpodium1->s.apos.trBase[PITCH] = 0;\n\t\tpodium1->s.apos.trBase[ROLL] = 0;\n\n\t\tAngleVectors( podium1->s.apos.trBase, f, r, u );\n\t\tVectorMA( podium->r.currentOrigin, offsetFirst[0], f, vec );\n\t\tVectorMA( vec, offsetFirst[1], r, vec );\n\t\tVectorMA( vec, offsetFirst[2], u, vec );\n\n\t\tG_SetOrigin( podium1, vec );\n\t}\n\n\tif( podium2 ) {\n\t\tVectorSubtract( level.intermission_origin, podium->r.currentOrigin, vec );\n\t\tvectoangles( vec, podium2->s.apos.trBase );\n\t\tpodium2->s.apos.trBase[PITCH] = 0;\n\t\tpodium2->s.apos.trBase[ROLL] = 0;\n\n\t\tAngleVectors( podium2->s.apos.trBase, f, r, u );\n\t\tVectorMA( podium->r.currentOrigin, offsetSecond[0], f, vec );\n\t\tVectorMA( vec, offsetSecond[1], r, vec );\n\t\tVectorMA( vec, offsetSecond[2], u, vec );\n\n\t\tG_SetOrigin( podium2, vec );\n\t}\n\n\tif( podium3 ) {\n\t\tVectorSubtract( level.intermission_origin, podium->r.currentOrigin, vec );\n\t\tvectoangles( vec, podium3->s.apos.trBase );\n\t\tpodium3->s.apos.trBase[PITCH] = 0;\n\t\tpodium3->s.apos.trBase[ROLL] = 0;\n\n\t\tAngleVectors( podium3->s.apos.trBase, f, r, u );\n\t\tVectorMA( podium->r.currentOrigin, offsetThird[0], f, vec );\n\t\tVectorMA( vec, offsetThird[1], r, vec );\n\t\tVectorMA( vec, offsetThird[2], u, vec );\n\n\t\tG_SetOrigin( podium3, vec );\n\t}\n}\n\n\nstatic gentity_t *SpawnPodium( void ) {\n\tgentity_t\t*podium;\n\tvec3_t\t\tvec;\n\tvec3_t\t\torigin;\n\n\tpodium = G_Spawn();\n\tif ( !podium ) {\n\t\treturn NULL;\n\t}\n\n\tpodium->classname = \"podium\";\n\tpodium->s.eType = ET_GENERAL;\n\tpodium->s.number = podium - g_entities;\n\tpodium->clipmask = CONTENTS_SOLID;\n\tpodium->r.contents = CONTENTS_SOLID;\n\tpodium->s.modelindex = G_ModelIndex( SP_PODIUM_MODEL );\n\n\tAngleVectors( level.intermission_angle, vec, NULL, NULL );\n\tVectorMA( level.intermission_origin, trap_Cvar_VariableIntegerValue( \"g_podiumDist\" ), vec, origin );\n\torigin[2] -= trap_Cvar_VariableIntegerValue( \"g_podiumDrop\" );\n\tG_SetOrigin( podium, origin );\n\n\tVectorSubtract( level.intermission_origin, podium->r.currentOrigin, vec );\n\tpodium->s.apos.trBase[YAW] = vectoyaw( vec );\n\ttrap_LinkEntity (podium);\n\n\tpodium->think = PodiumPlacementThink;\n\tpodium->nextthink = level.time + 100;\n\treturn podium;\n}\n\n\n/*\n==================\nSpawnModelsOnVictoryPads\n==================\n*/\nvoid SpawnModelsOnVictoryPads( void ) {\n\tgentity_t\t*player;\n\tgentity_t\t*podium;\n\n\tpodium1 = NULL;\n\tpodium2 = NULL;\n\tpodium3 = NULL;\n\n\tpodium = SpawnPodium();\n\n\tplayer = SpawnModelOnVictoryPad( podium, offsetFirst, &g_entities[level.sortedClients[0]],\n\t\t\t\tlevel.clients[ level.sortedClients[0] ].ps.persistant[PERS_RANK] &~ RANK_TIED_FLAG );\n\tif ( player ) {\n\t\tplayer->nextthink = level.time + 2000;\n\t\tplayer->think = CelebrateStart;\n\t\tpodium1 = player;\n\t}\n\n\tplayer = SpawnModelOnVictoryPad( podium, offsetSecond, &g_entities[level.sortedClients[1]],\n\t\t\t\tlevel.clients[ level.sortedClients[1] ].ps.persistant[PERS_RANK] &~ RANK_TIED_FLAG );\n\tif ( player ) {\n\t\tpodium2 = player;\n\t}\n\n\tif ( level.numNonSpectatorClients > 2 ) {\n\t\tplayer = SpawnModelOnVictoryPad( podium, offsetThird, &g_entities[level.sortedClients[2]],\n\t\t\t\tlevel.clients[ level.sortedClients[2] ].ps.persistant[PERS_RANK] &~ RANK_TIED_FLAG );\n\t\tif ( player ) {\n\t\t\tpodium3 = player;\n\t\t}\n\t}\n}\n\n\n/*\n===============\nSvcmd_AbortPodium_f\n===============\n*/\nvoid Svcmd_AbortPodium_f( void ) {\n\tif( g_gametype.integer != GT_SINGLE_PLAYER ) {\n\t\treturn;\n\t}\n\n\tif( podium1 ) {\n\t\tpodium1->nextthink = level.time;\n\t\tpodium1->think = CelebrateStop;\n\t}\n}\n"
  },
  {
    "path": "src/game/g_bot.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n// g_bot.c\n\n#include \"g_local.h\"\n\n\nstatic int\t\tg_numBots;\nstatic char\t\t*g_botInfos[MAX_BOTS];\n\n\nint\t\t\t\tg_numArenas;\nstatic char\t\t*g_arenaInfos[MAX_ARENAS];\n\n\n#define BOT_BEGIN_DELAY_BASE\t\t2000\n#define BOT_BEGIN_DELAY_INCREMENT\t1500\n\n#define BOT_SPAWN_QUEUE_DEPTH\t16\n\ntypedef struct {\n\tint\t\tclientNum;\n\tint\t\tspawnTime;\n} botSpawnQueue_t;\n\n//static int\t\t\tbotBeginDelay = 0;  // bk001206 - unused, init\nstatic botSpawnQueue_t\tbotSpawnQueue[BOT_SPAWN_QUEUE_DEPTH];\n\nvmCvar_t bot_minplayers;\n\nextern gentity_t\t*podium1;\nextern gentity_t\t*podium2;\nextern gentity_t\t*podium3;\n\nfloat trap_Cvar_VariableValue( const char *var_name ) {\n\tchar buf[128];\n\n\ttrap_Cvar_VariableStringBuffer(var_name, buf, sizeof(buf));\n\treturn atof(buf);\n}\n\n\n\n/*\n===============\nG_ParseInfos\n===============\n*/\nint G_ParseInfos( char *buf, int max, char *infos[] ) {\n\tchar\t*token;\n\tint\t\tcount;\n\tchar\tkey[MAX_TOKEN_CHARS];\n\tchar\tinfo[MAX_INFO_STRING];\n\n\tcount = 0;\n\n\twhile ( 1 ) {\n\t\ttoken = COM_Parse( &buf );\n\t\tif ( !token[0] ) {\n\t\t\tbreak;\n\t\t}\n\t\tif ( strcmp( token, \"{\" ) ) {\n\t\t\tCom_Printf( \"Missing { in info file\\n\" );\n\t\t\tbreak;\n\t\t}\n\n\t\tif ( count == max ) {\n\t\t\tCom_Printf( \"Max infos exceeded\\n\" );\n\t\t\tbreak;\n\t\t}\n\n\t\tinfo[0] = '\\0';\n\t\twhile ( 1 ) {\n\t\t\ttoken = COM_ParseExt( &buf, qtrue );\n\t\t\tif ( !token[0] ) {\n\t\t\t\tCom_Printf( \"Unexpected end of info file\\n\" );\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( !strcmp( token, \"}\" ) ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tQ_strncpyz( key, token, sizeof( key ) );\n\n\t\t\ttoken = COM_ParseExt( &buf, qfalse );\n\t\t\tif ( !token[0] ) {\n\t\t\t\tstrcpy( token, \"<NULL>\" );\n\t\t\t}\n\t\t\tInfo_SetValueForKey( info, key, token );\n\t\t}\n\t\t//NOTE: extra space for arena number\n\t\tinfos[count] = G_Alloc((int)strlen(info) + (int)strlen(\"\\\\num\\\\\") + (int)strlen(va(\"%d\", MAX_ARENAS)) + 1);\n\t\tif (infos[count]) {\n\t\t\tstrcpy(infos[count], info);\n\t\t\tcount++;\n\t\t}\n\t}\n\treturn count;\n}\n\n/*\n===============\nG_LoadArenasFromFile\n===============\n*/\nstatic void G_LoadArenasFromFile( char *filename ) {\n\tint\t\t\t\tlen;\n\tfileHandle_t\tf;\n\tchar\t\t\tbuf[MAX_ARENAS_TEXT];\n\n\tlen = trap_FS_FOpenFile( filename, &f, FS_READ );\n\tif ( !f ) {\n\t\ttrap_Printf( va( S_COLOR_RED \"file not found: %s\\n\", filename ) );\n\t\treturn;\n\t}\n\tif ( len >= MAX_ARENAS_TEXT ) {\n\t\ttrap_Printf( va( S_COLOR_RED \"file too large: %s is %i, max allowed is %i\", filename, len, MAX_ARENAS_TEXT ) );\n\t\ttrap_FS_FCloseFile( f );\n\t\treturn;\n\t}\n\n\ttrap_FS_Read( buf, len, f );\n\tbuf[len] = 0;\n\ttrap_FS_FCloseFile( f );\n\n\tg_numArenas += G_ParseInfos( buf, MAX_ARENAS - g_numArenas, &g_arenaInfos[g_numArenas] );\n}\n\n/*\n===============\nG_LoadArenas\n===============\n*/\nstatic void G_LoadArenas( void ) {\n\tint\t\t\tnumdirs;\n\tvmCvar_t\tarenasFile;\n\tchar\t\tfilename[128];\n\tchar\t\tdirlist[1024];\n\tchar*\t\tdirptr;\n\tint\t\t\ti, n;\n\tint\t\t\tdirlen;\n\n\tg_numArenas = 0;\n\n\ttrap_Cvar_Register( &arenasFile, \"g_arenasFile\", \"\", CVAR_INIT|CVAR_ROM );\n\tif( *arenasFile.string ) {\n\t\tG_LoadArenasFromFile(arenasFile.string);\n\t}\n\telse {\n\t\tG_LoadArenasFromFile(\"scripts/arenas.txt\");\n\t}\n\n\t// get all arenas from .arena files\n\tnumdirs = trap_FS_GetFileList(\"scripts\", \".arena\", dirlist, 1024 );\n\tdirptr  = dirlist;\n\tfor (i = 0; i < numdirs; i++, dirptr += dirlen+1) {\n\t\tdirlen = (int)strlen(dirptr);\n\t\tstrcpy(filename, \"scripts/\");\n\t\tstrcat(filename, dirptr);\n\t\tG_LoadArenasFromFile(filename);\n\t}\n\ttrap_Printf( va( \"%i arenas parsed\\n\", g_numArenas ) );\n\t\n\tfor( n = 0; n < g_numArenas; n++ ) {\n\t\tInfo_SetValueForKey( g_arenaInfos[n], \"num\", va( \"%i\", n ) );\n\t}\n}\n\n\n/*\n===============\nG_GetArenaInfoByNumber\n===============\n*/\nconst char *G_GetArenaInfoByMap( const char *map ) {\n\tint\t\t\tn;\n\n\tfor( n = 0; n < g_numArenas; n++ ) {\n\t\tif( Q_stricmp( Info_ValueForKey( g_arenaInfos[n], \"map\" ), map ) == 0 ) {\n\t\t\treturn g_arenaInfos[n];\n\t\t}\n\t}\n\n\treturn NULL;\n}\n\n\n/*\n=================\nPlayerIntroSound\n=================\n*/\nstatic void PlayerIntroSound( const char *modelAndSkin ) {\n\tchar\tmodel[MAX_QPATH];\n\tchar\t*skin;\n\n\tQ_strncpyz( model, modelAndSkin, sizeof(model) );\n\tskin = Q_strrchr( model, '/' );\n\tif ( skin ) {\n\t\t*skin++ = '\\0';\n\t}\n\telse {\n\t\tskin = model;\n\t}\n\n\tif( Q_stricmp( skin, \"default\" ) == 0 ) {\n\t\tskin = model;\n\t}\n\n\ttrap_SendConsoleCommand( EXEC_APPEND, va( \"play sound/player/announce/%s.wav\\n\", skin ) );\n}\n\n/*\n===============\nG_AddRandomBot\n===============\n*/\nvoid G_AddRandomBot( int team ) {\n\tint\t\ti, n, num;\n\tfloat\tskill;\n\tchar\t*value, netname[36], *teamstr;\n\tgclient_t\t*cl;\n\n\tnum = 0;\n\tfor ( n = 0; n < g_numBots ; n++ ) {\n\t\tvalue = Info_ValueForKey( g_botInfos[n], \"name\" );\n\t\t//\n\t\tfor ( i=0 ; i< g_maxclients.integer ; i++ ) {\n\t\t\tcl = level.clients + i;\n\t\t\tif ( cl->pers.connected != CON_CONNECTED ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif ( !(g_entities[cl->ps.clientNum].r.svFlags & SVF_BOT) ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif ( team >= 0 && cl->sess.sessionTeam != team ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif ( !Q_stricmp( value, cl->pers.netname ) ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (i >= g_maxclients.integer) {\n\t\t\tnum++;\n\t\t}\n\t}\n\tnum = random() * num;\n\tfor ( n = 0; n < g_numBots ; n++ ) {\n\t\tvalue = Info_ValueForKey( g_botInfos[n], \"name\" );\n\t\t//\n\t\tfor ( i=0 ; i< g_maxclients.integer ; i++ ) {\n\t\t\tcl = level.clients + i;\n\t\t\tif ( cl->pers.connected != CON_CONNECTED ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif ( !(g_entities[cl->ps.clientNum].r.svFlags & SVF_BOT) ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif ( team >= 0 && cl->sess.sessionTeam != team ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif ( !Q_stricmp( value, cl->pers.netname ) ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (i >= g_maxclients.integer) {\n\t\t\tnum--;\n\t\t\tif (num <= 0) {\n\t\t\t\tskill = trap_Cvar_VariableValue( \"g_spSkill\" );\n\t\t\t\tif (team == TEAM_RED) teamstr = \"red\";\n\t\t\t\telse if (team == TEAM_BLUE) teamstr = \"blue\";\n\t\t\t\telse teamstr = \"\";\n\t\t\t\tstrncpy(netname, value, sizeof(netname)-1);\n\t\t\t\tnetname[sizeof(netname)-1] = '\\0';\n\t\t\t\tQ_CleanStr(netname);\n\t\t\t\ttrap_SendConsoleCommand( EXEC_INSERT, va(\"addbot %s %f %s %i\\n\", netname, skill, teamstr, 0) );\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n}\n\n/*\n===============\nG_RemoveRandomBot\n===============\n*/\nint G_RemoveRandomBot( int team ) {\n\tint i;\n\tchar netname[36];\n\tgclient_t\t*cl;\n\n\tfor ( i=0 ; i< g_maxclients.integer ; i++ ) {\n\t\tcl = level.clients + i;\n\t\tif ( cl->pers.connected != CON_CONNECTED ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( !(g_entities[cl->ps.clientNum].r.svFlags & SVF_BOT) ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( team >= 0 && cl->sess.sessionTeam != team ) {\n\t\t\tcontinue;\n\t\t}\n\t\tstrcpy(netname, cl->pers.netname);\n\t\tQ_CleanStr(netname);\n\t\ttrap_SendConsoleCommand( EXEC_INSERT, va(\"kick %s\\n\", netname) );\n\t\treturn qtrue;\n\t}\n\treturn qfalse;\n}\n\n/*\n===============\nG_CountHumanPlayers\n===============\n*/\nint G_CountHumanPlayers( int team ) {\n\tint i, num;\n\tgclient_t\t*cl;\n\n\tnum = 0;\n\tfor ( i=0 ; i< g_maxclients.integer ; i++ ) {\n\t\tcl = level.clients + i;\n\t\tif ( cl->pers.connected != CON_CONNECTED ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( g_entities[cl->ps.clientNum].r.svFlags & SVF_BOT ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( team >= 0 && cl->sess.sessionTeam != team ) {\n\t\t\tcontinue;\n\t\t}\n\t\tnum++;\n\t}\n\treturn num;\n}\n\n/*\n===============\nG_CountBotPlayers\n===============\n*/\nint G_CountBotPlayers( int team ) {\n\tint i, n, num;\n\tgclient_t\t*cl;\n\n\tnum = 0;\n\tfor ( i=0 ; i< g_maxclients.integer ; i++ ) {\n\t\tcl = level.clients + i;\n\t\tif ( cl->pers.connected != CON_CONNECTED ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( !(g_entities[cl->ps.clientNum].r.svFlags & SVF_BOT) ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( team >= 0 && cl->sess.sessionTeam != team ) {\n\t\t\tcontinue;\n\t\t}\n\t\tnum++;\n\t}\n\tfor( n = 0; n < BOT_SPAWN_QUEUE_DEPTH; n++ ) {\n\t\tif( !botSpawnQueue[n].spawnTime ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( botSpawnQueue[n].spawnTime > level.time ) {\n\t\t\tcontinue;\n\t\t}\n\t\tnum++;\n\t}\n\treturn num;\n}\n\n/*\n===============\nG_CheckMinimumPlayers\n===============\n*/\nvoid G_CheckMinimumPlayers( void ) {\n\tint minplayers;\n\tint humanplayers, botplayers;\n\tstatic int checkminimumplayers_time;\n\n\tif (level.intermissiontime) return;\n\t//only check once each 10 seconds\n\tif (checkminimumplayers_time > level.time - 10000) {\n\t\treturn;\n\t}\n\tcheckminimumplayers_time = level.time;\n\ttrap_Cvar_Update(&bot_minplayers);\n\tminplayers = bot_minplayers.integer;\n\tif (minplayers <= 0) return;\n\n\tif (g_gametype.integer >= GT_TEAM) {\n\t\tif (minplayers >= g_maxclients.integer / 2) {\n\t\t\tminplayers = (g_maxclients.integer / 2) -1;\n\t\t}\n\n\t\thumanplayers = G_CountHumanPlayers( TEAM_RED );\n\t\tbotplayers = G_CountBotPlayers(\tTEAM_RED );\n\t\t//\n\t\tif (humanplayers + botplayers < minplayers) {\n\t\t\tG_AddRandomBot( TEAM_RED );\n\t\t} else if (humanplayers + botplayers > minplayers && botplayers) {\n\t\t\tG_RemoveRandomBot( TEAM_RED );\n\t\t}\n\t\t//\n\t\thumanplayers = G_CountHumanPlayers( TEAM_BLUE );\n\t\tbotplayers = G_CountBotPlayers( TEAM_BLUE );\n\t\t//\n\t\tif (humanplayers + botplayers < minplayers) {\n\t\t\tG_AddRandomBot( TEAM_BLUE );\n\t\t} else if (humanplayers + botplayers > minplayers && botplayers) {\n\t\t\tG_RemoveRandomBot( TEAM_BLUE );\n\t\t}\n\t}\n\telse if (g_gametype.integer == GT_TOURNAMENT ) {\n\t\tif (minplayers >= g_maxclients.integer) {\n\t\t\tminplayers = g_maxclients.integer-1;\n\t\t}\n\t\thumanplayers = G_CountHumanPlayers( -1 );\n\t\tbotplayers = G_CountBotPlayers( -1 );\n\t\t//\n\t\tif (humanplayers + botplayers < minplayers) {\n\t\t\tG_AddRandomBot( TEAM_FREE );\n\t\t} else if (humanplayers + botplayers > minplayers && botplayers) {\n\t\t\t// try to remove spectators first\n\t\t\tif (!G_RemoveRandomBot( TEAM_SPECTATOR )) {\n\t\t\t\t// just remove the bot that is playing\n\t\t\t\tG_RemoveRandomBot( -1 );\n\t\t\t}\n\t\t}\n\t}\n\telse if (g_gametype.integer == GT_FFA) {\n\t\tif (minplayers >= g_maxclients.integer) {\n\t\t\tminplayers = g_maxclients.integer-1;\n\t\t}\n\t\thumanplayers = G_CountHumanPlayers( TEAM_FREE );\n\t\tbotplayers = G_CountBotPlayers( TEAM_FREE );\n\t\t//\n\t\tif (humanplayers + botplayers < minplayers) {\n\t\t\tG_AddRandomBot( TEAM_FREE );\n\t\t} else if (humanplayers + botplayers > minplayers && botplayers) {\n\t\t\tG_RemoveRandomBot( TEAM_FREE );\n\t\t}\n\t}\n}\n\n/*\n===============\nG_CheckBotSpawn\n===============\n*/\nvoid G_CheckBotSpawn( void ) {\n\tint\t\tn;\n\tchar\tuserinfo[MAX_INFO_VALUE];\n\n\tG_CheckMinimumPlayers();\n\n\tfor( n = 0; n < BOT_SPAWN_QUEUE_DEPTH; n++ ) {\n\t\tif( !botSpawnQueue[n].spawnTime ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( botSpawnQueue[n].spawnTime > level.time ) {\n\t\t\tcontinue;\n\t\t}\n\t\tClientBegin( botSpawnQueue[n].clientNum );\n\t\tbotSpawnQueue[n].spawnTime = 0;\n\n\t\tif( g_gametype.integer == GT_SINGLE_PLAYER ) {\n\t\t\ttrap_GetUserinfo( botSpawnQueue[n].clientNum, userinfo, sizeof(userinfo) );\n\t\t\tPlayerIntroSound( Info_ValueForKey (userinfo, \"model\") );\n\t\t}\n\t}\n}\n\n\n/*\n===============\nAddBotToSpawnQueue\n===============\n*/\nstatic void AddBotToSpawnQueue( int clientNum, int delay ) {\n\tint\t\tn;\n\n\tfor( n = 0; n < BOT_SPAWN_QUEUE_DEPTH; n++ ) {\n\t\tif( !botSpawnQueue[n].spawnTime ) {\n\t\t\tbotSpawnQueue[n].spawnTime = level.time + delay;\n\t\t\tbotSpawnQueue[n].clientNum = clientNum;\n\t\t\treturn;\n\t\t}\n\t}\n\n\tG_Printf( S_COLOR_YELLOW \"Unable to delay spawn\\n\" );\n\tClientBegin( clientNum );\n}\n\n\n/*\n===============\nG_RemoveQueuedBotBegin\n\nCalled on client disconnect to make sure the delayed spawn\ndoesn't happen on a freed index\n===============\n*/\nvoid G_RemoveQueuedBotBegin( int clientNum ) {\n\tint\t\tn;\n\n\tfor( n = 0; n < BOT_SPAWN_QUEUE_DEPTH; n++ ) {\n\t\tif( botSpawnQueue[n].clientNum == clientNum ) {\n\t\t\tbotSpawnQueue[n].spawnTime = 0;\n\t\t\treturn;\n\t\t}\n\t}\n}\n\n\n/*\n===============\nG_BotConnect\n===============\n*/\nqboolean G_BotConnect( int clientNum, qboolean restart ) {\n\tbot_settings_t\tsettings;\n\tchar\t\t\tuserinfo[MAX_INFO_STRING];\n\n\ttrap_GetUserinfo( clientNum, userinfo, sizeof(userinfo) );\n\n\tQ_strncpyz( settings.characterfile, Info_ValueForKey( userinfo, \"characterfile\" ), sizeof(settings.characterfile) );\n\tsettings.skill = atof( Info_ValueForKey( userinfo, \"skill\" ) );\n\tQ_strncpyz( settings.team, Info_ValueForKey( userinfo, \"team\" ), sizeof(settings.team) );\n\n\tif (!BotAISetupClient( clientNum, &settings, restart )) {\n\t\ttrap_DropClient( clientNum, \"BotAISetupClient failed\" );\n\t\treturn qfalse;\n\t}\n\n\treturn qtrue;\n}\n\n\n/*\n===============\nG_AddBot\n===============\n*/\nstatic void G_AddBot( const char *name, float skill, const char *team, int delay, char *altname) {\n\tint\t\t\t\tclientNum;\n\tchar\t\t\t*botinfo;\n\tgentity_t\t\t*bot;\n\tchar\t\t\t*key;\n\tchar\t\t\t*s;\n\tchar\t\t\t*botname;\n\tchar\t\t\t*model;\n\tchar\t\t\t*headmodel;\n\tchar\t\t\tuserinfo[MAX_INFO_STRING];\n\n\t// get the botinfo from bots.txt\n\tbotinfo = G_GetBotInfoByName( name );\n\tif ( !botinfo ) {\n\t\tG_Printf( S_COLOR_RED \"Error: Bot '%s' not defined\\n\", name );\n\t\treturn;\n\t}\n\n\t// create the bot's userinfo\n\tuserinfo[0] = '\\0';\n\n\tbotname = Info_ValueForKey( botinfo, \"funname\" );\n\tif( !botname[0] ) {\n\t\tbotname = Info_ValueForKey( botinfo, \"name\" );\n\t}\n\t// check for an alternative name\n\tif (altname && altname[0]) {\n\t\tbotname = altname;\n\t}\n\tInfo_SetValueForKey( userinfo, \"name\", botname );\n\tInfo_SetValueForKey( userinfo, \"rate\", \"25000\" );\n\tInfo_SetValueForKey( userinfo, \"snaps\", \"20\" );\n\tInfo_SetValueForKey( userinfo, \"skill\", va(\"%1.2f\", skill) );\n\n\tif ( skill >= 1 && skill < 2 ) {\n\t\tInfo_SetValueForKey( userinfo, \"handicap\", \"50\" );\n\t}\n\telse if ( skill >= 2 && skill < 3 ) {\n\t\tInfo_SetValueForKey( userinfo, \"handicap\", \"70\" );\n\t}\n\telse if ( skill >= 3 && skill < 4 ) {\n\t\tInfo_SetValueForKey( userinfo, \"handicap\", \"90\" );\n\t}\n\n\tkey = \"model\";\n\tmodel = Info_ValueForKey( botinfo, key );\n\tif ( !*model ) {\n\t\tmodel = \"visor/default\";\n\t}\n\tInfo_SetValueForKey( userinfo, key, model );\n\tkey = \"team_model\";\n\tInfo_SetValueForKey( userinfo, key, model );\n\n\tkey = \"headmodel\";\n\theadmodel = Info_ValueForKey( botinfo, key );\n\tif ( !*headmodel ) {\n\t\theadmodel = model;\n\t}\n\tInfo_SetValueForKey( userinfo, key, headmodel );\n\tkey = \"team_headmodel\";\n\tInfo_SetValueForKey( userinfo, key, headmodel );\n\n\tkey = \"gender\";\n\ts = Info_ValueForKey( botinfo, key );\n\tif ( !*s ) {\n\t\ts = \"male\";\n\t}\n\tInfo_SetValueForKey( userinfo, \"sex\", s );\n\n\tkey = \"color1\";\n\ts = Info_ValueForKey( botinfo, key );\n\tif ( !*s ) {\n\t\ts = \"4\";\n\t}\n\tInfo_SetValueForKey( userinfo, key, s );\n\n\tkey = \"color2\";\n\ts = Info_ValueForKey( botinfo, key );\n\tif ( !*s ) {\n\t\ts = \"5\";\n\t}\n\tInfo_SetValueForKey( userinfo, key, s );\n\n\ts = Info_ValueForKey(botinfo, \"aifile\");\n\tif (!*s ) {\n\t\ttrap_Printf( S_COLOR_RED \"Error: bot has no aifile specified\\n\" );\n\t\treturn;\n\t}\n\n\t// have the server allocate a client slot\n\tclientNum = trap_BotAllocateClient();\n\tif ( clientNum == -1 ) {\n\t\tG_Printf( S_COLOR_RED \"Unable to add bot.  All player slots are in use.\\n\" );\n\t\tG_Printf( S_COLOR_RED \"Start server with more 'open' slots (or check setting of sv_maxclients cvar).\\n\" );\n\t\treturn;\n\t}\n\n\t// initialize the bot settings\n\tif( !team || !*team ) {\n\t\tif( g_gametype.integer >= GT_TEAM ) {\n\t\t\tif( PickTeam(clientNum) == TEAM_RED) {\n\t\t\t\tteam = \"red\";\n\t\t\t}\n\t\t\telse {\n\t\t\t\tteam = \"blue\";\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tteam = \"red\";\n\t\t}\n\t}\n\tInfo_SetValueForKey( userinfo, \"characterfile\", Info_ValueForKey( botinfo, \"aifile\" ) );\n\tInfo_SetValueForKey( userinfo, \"skill\", va( \"%5.2f\", skill ) );\n\tInfo_SetValueForKey( userinfo, \"team\", team );\n\n\tbot = &g_entities[ clientNum ];\n\tbot->r.svFlags |= SVF_BOT;\n\tbot->inuse = qtrue;\n\n\t// register the userinfo\n\ttrap_SetUserinfo( clientNum, userinfo );\n\n\t// have it connect to the game as a normal client\n\tif ( ClientConnect( clientNum, qtrue, qtrue ) ) {\n\t\treturn;\n\t}\n\n\tif( delay == 0 ) {\n\t\tClientBegin( clientNum );\n\t\treturn;\n\t}\n\n\tAddBotToSpawnQueue( clientNum, delay );\n}\n\n\n/*\n===============\nSvcmd_AddBot_f\n===============\n*/\nvoid Svcmd_AddBot_f( void ) {\n\tfloat\t\t\tskill;\n\tint\t\t\t\tdelay;\n\tchar\t\t\tname[MAX_TOKEN_CHARS];\n\tchar\t\t\taltname[MAX_TOKEN_CHARS];\n\tchar\t\t\tstring[MAX_TOKEN_CHARS];\n\tchar\t\t\tteam[MAX_TOKEN_CHARS];\n\n\t// are bots enabled?\n\tif ( !trap_Cvar_VariableIntegerValue( \"bot_enable\" ) ) {\n\t\treturn;\n\t}\n\n\t// name\n\ttrap_Argv( 1, name, sizeof( name ) );\n\tif ( !name[0] ) {\n\t\ttrap_Printf( \"Usage: Addbot <botname> [skill 1-5] [team] [msec delay] [altname]\\n\" );\n\t\treturn;\n\t}\n\n\t// skill\n\ttrap_Argv( 2, string, sizeof( string ) );\n\tif ( !string[0] ) {\n\t\tskill = 4;\n\t}\n\telse {\n\t\tskill = atof( string );\n\t}\n\n\t// team\n\ttrap_Argv( 3, team, sizeof( team ) );\n\n\t// delay\n\ttrap_Argv( 4, string, sizeof( string ) );\n\tif ( !string[0] ) {\n\t\tdelay = 0;\n\t}\n\telse {\n\t\tdelay = atoi( string );\n\t}\n\n\t// alternative name\n\ttrap_Argv( 5, altname, sizeof( altname ) );\n\n\tG_AddBot( name, skill, team, delay, altname );\n\n\t// if this was issued during gameplay and we are playing locally,\n\t// go ahead and load the bot's media immediately\n\tif ( level.time - level.startTime > 1000 &&\n\t\ttrap_Cvar_VariableIntegerValue( \"cl_running\" ) ) {\n\t\ttrap_SendServerCommand( -1, \"loaddefered\\n\" );\t// FIXME: spelled wrong, but not changing for demo\n\t}\n}\n\n/*\n===============\nSvcmd_BotList_f\n===============\n*/\nvoid Svcmd_BotList_f( void ) {\n\tint i;\n\tchar name[MAX_TOKEN_CHARS];\n\tchar funname[MAX_TOKEN_CHARS];\n\tchar model[MAX_TOKEN_CHARS];\n\tchar aifile[MAX_TOKEN_CHARS];\n\n\ttrap_Printf(\"^1name             model            aifile              funname\\n\");\n\tfor (i = 0; i < g_numBots; i++) {\n\t\tstrcpy(name, Info_ValueForKey( g_botInfos[i], \"name\" ));\n\t\tif ( !*name ) {\n\t\t\tstrcpy(name, \"UnnamedPlayer\");\n\t\t}\n\t\tstrcpy(funname, Info_ValueForKey( g_botInfos[i], \"funname\" ));\n\t\tif ( !*funname ) {\n\t\t\tstrcpy(funname, \"\");\n\t\t}\n\t\tstrcpy(model, Info_ValueForKey( g_botInfos[i], \"model\" ));\n\t\tif ( !*model ) {\n\t\t\tstrcpy(model, \"visor/default\");\n\t\t}\n\t\tstrcpy(aifile, Info_ValueForKey( g_botInfos[i], \"aifile\"));\n\t\tif (!*aifile ) {\n\t\t\tstrcpy(aifile, \"bots/default_c.c\");\n\t\t}\n\t\ttrap_Printf(va(\"%-16s %-16s %-20s %-20s\\n\", name, model, aifile, funname));\n\t}\n}\n\n\n/*\n===============\nG_SpawnBots\n===============\n*/\nstatic void G_SpawnBots( char *botList, int baseDelay ) {\n\tchar\t\t*bot;\n\tchar\t\t*p;\n\tfloat\t\tskill;\n\tint\t\t\tdelay;\n\tchar\t\tbots[MAX_INFO_VALUE];\n\n\tpodium1 = NULL;\n\tpodium2 = NULL;\n\tpodium3 = NULL;\n\n\tskill = trap_Cvar_VariableValue( \"g_spSkill\" );\n\tif( skill < 1 ) {\n\t\ttrap_Cvar_Set( \"g_spSkill\", \"1\" );\n\t\tskill = 1;\n\t}\n\telse if ( skill > 5 ) {\n\t\ttrap_Cvar_Set( \"g_spSkill\", \"5\" );\n\t\tskill = 5;\n\t}\n\n\tQ_strncpyz( bots, botList, sizeof(bots) );\n\tp = &bots[0];\n\tdelay = baseDelay;\n\twhile( *p ) {\n\t\t//skip spaces\n\t\twhile( *p && *p == ' ' ) {\n\t\t\tp++;\n\t\t}\n\t\tif( !p ) {\n\t\t\tbreak;\n\t\t}\n\n\t\t// mark start of bot name\n\t\tbot = p;\n\n\t\t// skip until space of null\n\t\twhile( *p && *p != ' ' ) {\n\t\t\tp++;\n\t\t}\n\t\tif( *p ) {\n\t\t\t*p++ = 0;\n\t\t}\n\n\t\t// we must add the bot this way, calling G_AddBot directly at this stage\n\t\t// does \"Bad Things\"\n\t\ttrap_SendConsoleCommand( EXEC_INSERT, va(\"addbot %s %f free %i\\n\", bot, skill, delay) );\n\n\t\tdelay += BOT_BEGIN_DELAY_INCREMENT;\n\t}\n}\n\n\n/*\n===============\nG_LoadBotsFromFile\n===============\n*/\nstatic void G_LoadBotsFromFile( char *filename ) {\n\tint\t\t\t\tlen;\n\tfileHandle_t\tf;\n\tchar\t\t\tbuf[MAX_BOTS_TEXT];\n\n\tlen = trap_FS_FOpenFile( filename, &f, FS_READ );\n\tif ( !f ) {\n\t\ttrap_Printf( va( S_COLOR_RED \"file not found: %s\\n\", filename ) );\n\t\treturn;\n\t}\n\tif ( len >= MAX_BOTS_TEXT ) {\n\t\ttrap_Printf( va( S_COLOR_RED \"file too large: %s is %i, max allowed is %i\", filename, len, MAX_BOTS_TEXT ) );\n\t\ttrap_FS_FCloseFile( f );\n\t\treturn;\n\t}\n\n\ttrap_FS_Read( buf, len, f );\n\tbuf[len] = 0;\n\ttrap_FS_FCloseFile( f );\n\n\tg_numBots += G_ParseInfos( buf, MAX_BOTS - g_numBots, &g_botInfos[g_numBots] );\n}\n\n/*\n===============\nG_LoadBots\n===============\n*/\nstatic void G_LoadBots( void ) {\n\tvmCvar_t\tbotsFile;\n\tint\t\t\tnumdirs;\n\tchar\t\tfilename[128];\n\tchar\t\tdirlist[1024];\n\tchar*\t\tdirptr;\n\tint\t\t\ti;\n\tint\t\t\tdirlen;\n\n\tif ( !trap_Cvar_VariableIntegerValue( \"bot_enable\" ) ) {\n\t\treturn;\n\t}\n\n\tg_numBots = 0;\n\n\ttrap_Cvar_Register( &botsFile, \"g_botsFile\", \"\", CVAR_INIT|CVAR_ROM );\n\tif( *botsFile.string ) {\n\t\tG_LoadBotsFromFile(botsFile.string);\n\t}\n\telse {\n\t\tG_LoadBotsFromFile(\"scripts/bots.txt\");\n\t}\n\n\t// get all bots from .bot files\n\tnumdirs = trap_FS_GetFileList(\"scripts\", \".bot\", dirlist, 1024 );\n\tdirptr  = dirlist;\n\tfor (i = 0; i < numdirs; i++, dirptr += dirlen+1) {\n\t\tdirlen = (int)strlen(dirptr);\n\t\tstrcpy(filename, \"scripts/\");\n\t\tstrcat(filename, dirptr);\n\t\tG_LoadBotsFromFile(filename);\n\t}\n\ttrap_Printf( va( \"%i bots parsed\\n\", g_numBots ) );\n}\n\n\n\n/*\n===============\nG_GetBotInfoByNumber\n===============\n*/\nchar *G_GetBotInfoByNumber( int num ) {\n\tif( num < 0 || num >= g_numBots ) {\n\t\ttrap_Printf( va( S_COLOR_RED \"Invalid bot number: %i\\n\", num ) );\n\t\treturn NULL;\n\t}\n\treturn g_botInfos[num];\n}\n\n\n/*\n===============\nG_GetBotInfoByName\n===============\n*/\nchar *G_GetBotInfoByName( const char *name ) {\n\tint\t\tn;\n\tchar\t*value;\n\n\tfor ( n = 0; n < g_numBots ; n++ ) {\n\t\tvalue = Info_ValueForKey( g_botInfos[n], \"name\" );\n\t\tif ( !Q_stricmp( value, name ) ) {\n\t\t\treturn g_botInfos[n];\n\t\t}\n\t}\n\n\treturn NULL;\n}\n\n/*\n===============\nG_InitBots\n===============\n*/\nvoid G_InitBots( qboolean restart ) {\n\tint\t\t\tfragLimit;\n\tint\t\t\ttimeLimit;\n\tconst char\t*arenainfo;\n\tchar\t\t*strValue;\n\tint\t\t\tbasedelay;\n\tchar\t\tmap[MAX_QPATH];\n\tchar\t\tserverinfo[MAX_INFO_STRING];\n\n\tG_LoadBots();\n\tG_LoadArenas();\n\n\ttrap_Cvar_Register( &bot_minplayers, \"bot_minplayers\", \"0\", CVAR_SERVERINFO );\n\n\tif( g_gametype.integer == GT_SINGLE_PLAYER ) {\n\t\ttrap_GetServerinfo( serverinfo, sizeof(serverinfo) );\n\t\tQ_strncpyz( map, Info_ValueForKey( serverinfo, \"mapname\" ), sizeof(map) );\n\t\tarenainfo = G_GetArenaInfoByMap( map );\n\t\tif ( !arenainfo ) {\n\t\t\treturn;\n\t\t}\n\n\t\tstrValue = Info_ValueForKey( arenainfo, \"fraglimit\" );\n\t\tfragLimit = atoi( strValue );\n\t\tif ( fragLimit ) {\n\t\t\ttrap_Cvar_Set( \"fraglimit\", strValue );\n\t\t}\n\t\telse {\n\t\t\ttrap_Cvar_Set( \"fraglimit\", \"0\" );\n\t\t}\n\n\t\tstrValue = Info_ValueForKey( arenainfo, \"timelimit\" );\n\t\ttimeLimit = atoi( strValue );\n\t\tif ( timeLimit ) {\n\t\t\ttrap_Cvar_Set( \"timelimit\", strValue );\n\t\t}\n\t\telse {\n\t\t\ttrap_Cvar_Set( \"timelimit\", \"0\" );\n\t\t}\n\n\t\tif ( !fragLimit && !timeLimit ) {\n\t\t\ttrap_Cvar_Set( \"fraglimit\", \"10\" );\n\t\t\ttrap_Cvar_Set( \"timelimit\", \"0\" );\n\t\t}\n\n\t\tbasedelay = BOT_BEGIN_DELAY_BASE;\n\t\tstrValue = Info_ValueForKey( arenainfo, \"special\" );\n\t\tif( Q_stricmp( strValue, \"training\" ) == 0 ) {\n\t\t\tbasedelay += 10000;\n\t\t}\n\n\t\tif( !restart ) {\n\t\t\tG_SpawnBots( Info_ValueForKey( arenainfo, \"bots\" ), basedelay );\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/game/g_client.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n#include \"g_local.h\"\n\n// g_client.c -- client functions that don't happen every frame\n\nstatic vec3_t\tplayerMins = {-15, -15, -24};\nstatic vec3_t\tplayerMaxs = {15, 15, 32};\n\n/*QUAKED info_player_deathmatch (1 0 1) (-16 -16 -24) (16 16 32) initial\npotential spawning position for deathmatch games.\nThe first time a player enters the game, they will be at an 'initial' spot.\nTargets will be fired when someone spawns in on them.\n\"nobots\" will prevent bots from using this spot.\n\"nohumans\" will prevent non-bots from using this spot.\n*/\nvoid SP_info_player_deathmatch( gentity_t *ent ) {\n\tint\t\ti;\n\n\tG_SpawnInt( \"nobots\", \"0\", &i);\n\tif ( i ) {\n\t\tent->flags |= FL_NO_BOTS;\n\t}\n\tG_SpawnInt( \"nohumans\", \"0\", &i );\n\tif ( i ) {\n\t\tent->flags |= FL_NO_HUMANS;\n\t}\n}\n\n/*QUAKED info_player_start (1 0 0) (-16 -16 -24) (16 16 32)\nequivelant to info_player_deathmatch\n*/\nvoid SP_info_player_start(gentity_t *ent) {\n\tent->classname = \"info_player_deathmatch\";\n\tSP_info_player_deathmatch( ent );\n}\n\n/*QUAKED info_player_intermission (1 0 1) (-16 -16 -24) (16 16 32)\nThe intermission will be viewed from this point.  Target an info_notnull for the view direction.\n*/\nvoid SP_info_player_intermission( gentity_t *ent ) {\n\n}\n\n\n\n/*\n=======================================================================\n\n  SelectSpawnPoint\n\n=======================================================================\n*/\n\n/*\n================\nSpotWouldTelefrag\n\n================\n*/\nqboolean SpotWouldTelefrag( gentity_t *spot ) {\n\tint\t\t\ti, num;\n\tint\t\t\ttouch[MAX_GENTITIES];\n\tgentity_t\t*hit;\n\tvec3_t\t\tmins, maxs;\n\n\tVectorAdd( spot->s.origin, playerMins, mins );\n\tVectorAdd( spot->s.origin, playerMaxs, maxs );\n\tnum = trap_EntitiesInBox( mins, maxs, touch, MAX_GENTITIES );\n\n\tfor (i=0 ; i<num ; i++) {\n\t\thit = &g_entities[touch[i]];\n\t\t//if ( hit->client && hit->client->ps.stats[STAT_HEALTH] > 0 ) {\n\t\tif ( hit->client) {\n\t\t\treturn qtrue;\n\t\t}\n\n\t}\n\n\treturn qfalse;\n}\n\n/*\n================\nSelectNearestDeathmatchSpawnPoint\n\nFind the spot that we DON'T want to use\n================\n*/\n#define\tMAX_SPAWN_POINTS\t128\ngentity_t *SelectNearestDeathmatchSpawnPoint( vec3_t from ) {\n\tgentity_t\t*spot;\n\tvec3_t\t\tdelta;\n\tfloat\t\tdist, nearestDist;\n\tgentity_t\t*nearestSpot;\n\n\tnearestDist = 999999;\n\tnearestSpot = NULL;\n\tspot = NULL;\n\n\twhile ((spot = G_Find (spot, FOFS(classname), \"info_player_deathmatch\")) != NULL) {\n\n\t\tVectorSubtract( spot->s.origin, from, delta );\n\t\tdist = VectorLength( delta );\n\t\tif ( dist < nearestDist ) {\n\t\t\tnearestDist = dist;\n\t\t\tnearestSpot = spot;\n\t\t}\n\t}\n\n\treturn nearestSpot;\n}\n\n\n/*\n================\nSelectRandomDeathmatchSpawnPoint\n\ngo to a random point that doesn't telefrag\n================\n*/\n#define\tMAX_SPAWN_POINTS\t128\ngentity_t *SelectRandomDeathmatchSpawnPoint( void ) {\n\tgentity_t\t*spot;\n\tint\t\t\tcount;\n\tint\t\t\tselection;\n\tgentity_t\t*spots[MAX_SPAWN_POINTS];\n\n\tcount = 0;\n\tspot = NULL;\n\n\twhile ((spot = G_Find (spot, FOFS(classname), \"info_player_deathmatch\")) != NULL) {\n\t\tif ( SpotWouldTelefrag( spot ) ) {\n\t\t\tcontinue;\n\t\t}\n\t\tspots[ count ] = spot;\n\t\tcount++;\n\t}\n\n\tif ( !count ) {\t// no spots that won't telefrag\n\t\treturn G_Find( NULL, FOFS(classname), \"info_player_deathmatch\");\n\t}\n\n\tselection = rand() % count;\n\treturn spots[ selection ];\n}\n\n/*\n===========\nSelectRandomFurthestSpawnPoint\n\nChooses a player start, deathmatch start, etc\n============\n*/\ngentity_t *SelectRandomFurthestSpawnPoint ( vec3_t avoidPoint, vec3_t origin, vec3_t angles ) {\n\tgentity_t\t*spot;\n\tvec3_t\t\tdelta;\n\tfloat\t\tdist;\n\tfloat\t\tlist_dist[64];\n\tgentity_t\t*list_spot[64];\n\tint\t\t\tnumSpots, rnd, i, j;\n\n\tnumSpots = 0;\n\tspot = NULL;\n\n\twhile ((spot = G_Find (spot, FOFS(classname), \"info_player_deathmatch\")) != NULL) {\n\t\tif ( SpotWouldTelefrag( spot ) ) {\n\t\t\tcontinue;\n\t\t}\n\t\tVectorSubtract( spot->s.origin, avoidPoint, delta );\n\t\tdist = VectorLength( delta );\n\t\tfor (i = 0; i < numSpots; i++) {\n\t\t\tif ( dist > list_dist[i] ) {\n\t\t\t\tif ( numSpots >= 64 )\n\t\t\t\t\tnumSpots = 64-1;\n\t\t\t\tfor (j = numSpots; j > i; j--) {\n\t\t\t\t\tlist_dist[j] = list_dist[j-1];\n\t\t\t\t\tlist_spot[j] = list_spot[j-1];\n\t\t\t\t}\n\t\t\t\tlist_dist[i] = dist;\n\t\t\t\tlist_spot[i] = spot;\n\t\t\t\tnumSpots++;\n\t\t\t\tif (numSpots > 64)\n\t\t\t\t\tnumSpots = 64;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (i >= numSpots && numSpots < 64) {\n\t\t\tlist_dist[numSpots] = dist;\n\t\t\tlist_spot[numSpots] = spot;\n\t\t\tnumSpots++;\n\t\t}\n\t}\n\tif (!numSpots) {\n\t\tspot = G_Find( NULL, FOFS(classname), \"info_player_deathmatch\");\n\t\tif (!spot)\n\t\t\tG_Error( \"Couldn't find a spawn point\" );\n\t\tVectorCopy (spot->s.origin, origin);\n\t\torigin[2] += 9;\n\t\tVectorCopy (spot->s.angles, angles);\n\t\treturn spot;\n\t}\n\n\t// select a random spot from the spawn points furthest away\n\trnd = random() * (numSpots / 2);\n\n\tVectorCopy (list_spot[rnd]->s.origin, origin);\n\torigin[2] += 9;\n\tVectorCopy (list_spot[rnd]->s.angles, angles);\n\n\treturn list_spot[rnd];\n}\n\n/*\n===========\nSelectSpawnPoint\n\nChooses a player start, deathmatch start, etc\n============\n*/\ngentity_t *SelectSpawnPoint ( vec3_t avoidPoint, vec3_t origin, vec3_t angles ) {\n\treturn SelectRandomFurthestSpawnPoint( avoidPoint, origin, angles );\n\n\t/*\n\tgentity_t\t*spot;\n\tgentity_t\t*nearestSpot;\n\n\tnearestSpot = SelectNearestDeathmatchSpawnPoint( avoidPoint );\n\n\tspot = SelectRandomDeathmatchSpawnPoint ( );\n\tif ( spot == nearestSpot ) {\n\t\t// roll again if it would be real close to point of death\n\t\tspot = SelectRandomDeathmatchSpawnPoint ( );\n\t\tif ( spot == nearestSpot ) {\n\t\t\t// last try\n\t\t\tspot = SelectRandomDeathmatchSpawnPoint ( );\n\t\t}\t\t\n\t}\n\n\t// find a single player start spot\n\tif (!spot) {\n\t\tG_Error( \"Couldn't find a spawn point\" );\n\t}\n\n\tVectorCopy (spot->s.origin, origin);\n\torigin[2] += 9;\n\tVectorCopy (spot->s.angles, angles);\n\n\treturn spot;\n\t*/\n}\n\n/*\n===========\nSelectInitialSpawnPoint\n\nTry to find a spawn point marked 'initial', otherwise\nuse normal spawn selection.\n============\n*/\ngentity_t *SelectInitialSpawnPoint( vec3_t origin, vec3_t angles ) {\n\tgentity_t\t*spot;\n\n\tspot = NULL;\n\twhile ((spot = G_Find (spot, FOFS(classname), \"info_player_deathmatch\")) != NULL) {\n\t\tif ( spot->spawnflags & 1 ) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif ( !spot || SpotWouldTelefrag( spot ) ) {\n\t\treturn SelectSpawnPoint( vec3_origin, origin, angles );\n\t}\n\n\tVectorCopy (spot->s.origin, origin);\n\torigin[2] += 9;\n\tVectorCopy (spot->s.angles, angles);\n\n\treturn spot;\n}\n\n/*\n===========\nSelectSpectatorSpawnPoint\n\n============\n*/\ngentity_t *SelectSpectatorSpawnPoint( vec3_t origin, vec3_t angles ) {\n\tFindIntermissionPoint();\n\n\tVectorCopy( level.intermission_origin, origin );\n\tVectorCopy( level.intermission_angle, angles );\n\n\treturn NULL;\n}\n\n/*\n=======================================================================\n\nBODYQUE\n\n=======================================================================\n*/\n\n/*\n===============\nInitBodyQue\n===============\n*/\nvoid InitBodyQue (void) {\n\tint\t\ti;\n\tgentity_t\t*ent;\n\n\tlevel.bodyQueIndex = 0;\n\tfor (i=0; i<BODY_QUEUE_SIZE ; i++) {\n\t\tent = G_Spawn();\n\t\tent->classname = \"bodyque\";\n\t\tent->neverFree = qtrue;\n\t\tlevel.bodyQue[i] = ent;\n\t}\n}\n\n/*\n=============\nBodySink\n\nAfter sitting around for five seconds, fall into the ground and dissapear\n=============\n*/\nvoid BodySink( gentity_t *ent ) {\n\tif ( level.time - ent->timestamp > 6500 ) {\n\t\t// the body ques are never actually freed, they are just unlinked\n\t\ttrap_UnlinkEntity( ent );\n\t\tent->physicsObject = qfalse;\n\t\treturn;\t\n\t}\n\tent->nextthink = level.time + 100;\n\tent->s.pos.trBase[2] -= 1;\n}\n\n/*\n=============\nCopyToBodyQue\n\nA player is respawning, so make an entity that looks\njust like the existing corpse to leave behind.\n=============\n*/\nvoid CopyToBodyQue( gentity_t *ent ) {\n\tgentity_t\t\t*body;\n\tint\t\t\tcontents;\n\n\ttrap_UnlinkEntity (ent);\n\n\t// if client is in a nodrop area, don't leave the body\n\tcontents = trap_PointContents( ent->s.origin, -1 );\n\tif ( contents & CONTENTS_NODROP ) {\n\t\treturn;\n\t}\n\n\t// grab a body que and cycle to the next one\n\tbody = level.bodyQue[ level.bodyQueIndex ];\n\tlevel.bodyQueIndex = (level.bodyQueIndex + 1) % BODY_QUEUE_SIZE;\n\n\ttrap_UnlinkEntity (body);\n\n\tbody->s = ent->s;\n\tbody->s.eFlags = EF_DEAD;\t\t// clear EF_TALK, etc\n\tbody->s.powerups = 0;\t// clear powerups\n\tbody->s.loopSound = 0;\t// clear lava burning\n\tbody->s.number = body - g_entities;\n\tbody->timestamp = level.time;\n\tbody->physicsObject = qtrue;\n\tbody->physicsBounce = 0;\t\t// don't bounce\n\tif ( body->s.groundEntityNum == ENTITYNUM_NONE ) {\n\t\tbody->s.pos.trType = TR_GRAVITY;\n\t\tbody->s.pos.trTime = level.time;\n\t\tVectorCopy( ent->client->ps.velocity, body->s.pos.trDelta );\n\t} else {\n\t\tbody->s.pos.trType = TR_STATIONARY;\n\t}\n\tbody->s.event = 0;\n\n\t// change the animation to the last-frame only, so the sequence\n\t// doesn't repeat anew for the body\n\tswitch ( body->s.legsAnim & ~ANIM_TOGGLEBIT ) {\n\tcase BOTH_DEATH1:\n\tcase BOTH_DEAD1:\n\t\tbody->s.torsoAnim = body->s.legsAnim = BOTH_DEAD1;\n\t\tbreak;\n\tcase BOTH_DEATH2:\n\tcase BOTH_DEAD2:\n\t\tbody->s.torsoAnim = body->s.legsAnim = BOTH_DEAD2;\n\t\tbreak;\n\tcase BOTH_DEATH3:\n\tcase BOTH_DEAD3:\n\tdefault:\n\t\tbody->s.torsoAnim = body->s.legsAnim = BOTH_DEAD3;\n\t\tbreak;\n\t}\n\n\tbody->r.svFlags = ent->r.svFlags;\n\tVectorCopy (ent->r.mins, body->r.mins);\n\tVectorCopy (ent->r.maxs, body->r.maxs);\n\tVectorCopy (ent->r.absmin, body->r.absmin);\n\tVectorCopy (ent->r.absmax, body->r.absmax);\n\n\tbody->clipmask = CONTENTS_SOLID | CONTENTS_PLAYERCLIP;\n\tbody->r.contents = CONTENTS_CORPSE;\n\tbody->r.ownerNum = ent->s.number;\n\n\tbody->nextthink = level.time + 5000;\n\tbody->think = BodySink;\n\n\tbody->die = body_die;\n\n\t// don't take more damage if already gibbed\n\tif ( ent->health <= GIB_HEALTH ) {\n\t\tbody->takedamage = qfalse;\n\t} else {\n\t\tbody->takedamage = qtrue;\n\t}\n\n\n\tVectorCopy ( body->s.pos.trBase, body->r.currentOrigin );\n\ttrap_LinkEntity (body);\n}\n\n//======================================================================\n\n\n/*\n==================\nSetClientViewAngle\n\n==================\n*/\nvoid SetClientViewAngle( gentity_t *ent, vec3_t angle ) {\n\tint\t\t\ti;\n\n\t// set the delta angle\n\tfor (i=0 ; i<3 ; i++) {\n\t\tint\t\tcmdAngle;\n\n\t\tcmdAngle = ANGLE2SHORT(angle[i]);\n\t\tent->client->ps.delta_angles[i] = cmdAngle - ent->client->pers.cmd.angles[i];\n\t}\n\tVectorCopy( angle, ent->s.angles );\n\tVectorCopy (ent->s.angles, ent->client->ps.viewangles);\n}\n\n/*\n================\nrespawn\n================\n*/\nvoid respawn( gentity_t *ent ) {\n\tgentity_t\t*tent;\n\n\tCopyToBodyQue (ent);\n\tClientSpawn(ent);\n\n\t// add a teleportation effect\n\ttent = G_TempEntity( ent->client->ps.origin, EV_PLAYER_TELEPORT_IN );\n\ttent->s.clientNum = ent->s.clientNum;\n}\n\n/*\n================\nTeamCount\n\nReturns number of players on a team\n================\n*/\nteam_t TeamCount( int ignoreClientNum, int team ) {\n\tint\t\ti;\n\tint\t\tcount = 0;\n\n\tfor ( i = 0 ; i < level.maxclients ; i++ ) {\n\t\tif ( i == ignoreClientNum ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( level.clients[i].pers.connected == CON_DISCONNECTED ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( level.clients[i].sess.sessionTeam == team ) {\n\t\t\tcount++;\n\t\t}\n\t}\n\n\treturn count;\n}\n\n/*\n================\nTeamLeader\n\nReturns the client number of the team leader\n================\n*/\nint TeamLeader( int team ) {\n\tint\t\ti;\n\n\tfor ( i = 0 ; i < level.maxclients ; i++ ) {\n\t\tif ( level.clients[i].pers.connected == CON_DISCONNECTED ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( level.clients[i].sess.sessionTeam == team ) {\n\t\t\tif ( level.clients[i].sess.teamLeader )\n\t\t\t\treturn i;\n\t\t}\n\t}\n\n\treturn -1;\n}\n\n\n/*\n================\nPickTeam\n\n================\n*/\nteam_t PickTeam( int ignoreClientNum ) {\n\tint\t\tcounts[TEAM_NUM_TEAMS];\n\n\tcounts[TEAM_BLUE] = TeamCount( ignoreClientNum, TEAM_BLUE );\n\tcounts[TEAM_RED] = TeamCount( ignoreClientNum, TEAM_RED );\n\n\tif ( counts[TEAM_BLUE] > counts[TEAM_RED] ) {\n\t\treturn TEAM_RED;\n\t}\n\tif ( counts[TEAM_RED] > counts[TEAM_BLUE] ) {\n\t\treturn TEAM_BLUE;\n\t}\n\t// equal team count, so join the team with the lowest score\n\tif ( level.teamScores[TEAM_BLUE] > level.teamScores[TEAM_RED] ) {\n\t\treturn TEAM_RED;\n\t}\n\treturn TEAM_BLUE;\n}\n\n/*\n===========\nForceClientSkin\n\nForces a client's skin (for teamplay)\n===========\n*/\n/*\nstatic void ForceClientSkin( gclient_t *client, char *model, const char *skin ) {\n\tchar *p;\n\n\tif ((p = Q_strrchr(model, '/')) != 0) {\n\t\t*p = 0;\n\t}\n\n\tQ_strcat(model, MAX_QPATH, \"/\");\n\tQ_strcat(model, MAX_QPATH, skin);\n}\n*/\n\n/*\n===========\nClientCheckName\n============\n*/\nstatic void ClientCleanName( const char *in, char *out, int outSize ) {\n\tint\t\tlen, colorlessLen;\n\tchar\tch;\n\tchar\t*p;\n\tint\t\tspaces;\n\n\t//save room for trailing null byte\n\toutSize--;\n\n\tlen = 0;\n\tcolorlessLen = 0;\n\tp = out;\n\t*p = 0;\n\tspaces = 0;\n\n\twhile( 1 ) {\n\t\tch = *in++;\n\t\tif( !ch ) {\n\t\t\tbreak;\n\t\t}\n\n\t\t// don't allow leading spaces\n\t\tif( !*p && ch == ' ' ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// check colors\n\t\tif( ch == Q_COLOR_ESCAPE ) {\n\t\t\t// solo trailing carat is not a color prefix\n\t\t\tif( !*in ) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// don't allow black in a name, period\n\t\t\tif( ColorIndex(*in) == 0 ) {\n\t\t\t\tin++;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// make sure room in dest for both chars\n\t\t\tif( len > outSize - 2 ) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t*out++ = ch;\n\t\t\t*out++ = *in++;\n\t\t\tlen += 2;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// don't allow too many consecutive spaces\n\t\tif( ch == ' ' ) {\n\t\t\tspaces++;\n\t\t\tif( spaces > 3 ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tspaces = 0;\n\t\t}\n\n\t\tif( len > outSize - 1 ) {\n\t\t\tbreak;\n\t\t}\n\n\t\t*out++ = ch;\n\t\tcolorlessLen++;\n\t\tlen++;\n\t}\n\t*out = 0;\n\n\t// don't allow empty names\n\tif( *p == 0 || colorlessLen == 0 ) {\n\t\tQ_strncpyz( p, \"UnnamedPlayer\", outSize );\n\t}\n}\n\n\n/*\n===========\nClientUserInfoChanged\n\nCalled from ClientConnect when the player first connects and\ndirectly by the server system when the player updates a userinfo variable.\n\nThe game can override any of the settings and call trap_SetUserinfo\nif desired.\n============\n*/\nvoid ClientUserinfoChanged( int clientNum ) {\n\tgentity_t *ent;\n\tint\t\tteamTask, teamLeader, team, health;\n\tchar\t*s;\n\tchar\tmodel[MAX_QPATH];\n\tchar\theadModel[MAX_QPATH];\n\tchar\toldname[MAX_STRING_CHARS];\n\tgclient_t\t*client;\n\tchar\tc1[MAX_INFO_STRING];\n\tchar\tc2[MAX_INFO_STRING];\n\tchar\tredTeam[MAX_INFO_STRING];\n\tchar\tblueTeam[MAX_INFO_STRING];\n\tchar\tuserinfo[MAX_INFO_STRING];\n\n\tent = g_entities + clientNum;\n\tclient = ent->client;\n\n\ttrap_GetUserinfo( clientNum, userinfo, sizeof( userinfo ) );\n\n\t// check for malformed or illegal info strings\n\tif ( !Info_Validate(userinfo) ) {\n\t\tstrcpy (userinfo, \"\\\\name\\\\badinfo\");\n\t}\n\n\t// check for local client\n\ts = Info_ValueForKey( userinfo, \"ip\" );\n\tif ( !strcmp( s, \"localhost\" ) ) {\n\t\tclient->pers.localClient = qtrue;\n\t}\n\n\t// check the item prediction\n\ts = Info_ValueForKey( userinfo, \"cg_predictItems\" );\n\tif ( !atoi( s ) ) {\n\t\tclient->pers.predictItemPickup = qfalse;\n\t} else {\n\t\tclient->pers.predictItemPickup = qtrue;\n\t}\n\n\t// set name\n\tQ_strncpyz ( oldname, client->pers.netname, sizeof( oldname ) );\n\ts = Info_ValueForKey (userinfo, \"name\");\n\tClientCleanName( s, client->pers.netname, sizeof(client->pers.netname) );\n\n\tif ( client->sess.sessionTeam == TEAM_SPECTATOR ) {\n\t\tif ( client->sess.spectatorState == SPECTATOR_SCOREBOARD ) {\n\t\t\tQ_strncpyz( client->pers.netname, \"scoreboard\", sizeof(client->pers.netname) );\n\t\t}\n\t}\n\n\tif ( client->pers.connected == CON_CONNECTED ) {\n\t\tif ( strcmp( oldname, client->pers.netname ) ) {\n\t\t\ttrap_SendServerCommand( -1, va(\"print \\\"%s\" S_COLOR_WHITE \" renamed to %s\\n\\\"\", oldname, \n\t\t\t\tclient->pers.netname) );\n\t\t}\n\t}\n\n\t// set max health\n\thealth = atoi( Info_ValueForKey( userinfo, \"handicap\" ) );\n\tclient->pers.maxHealth = health;\n\tif ( client->pers.maxHealth < 1 || client->pers.maxHealth > 100 ) {\n\t\tclient->pers.maxHealth = 100;\n\t}\n\tclient->ps.stats[STAT_MAX_HEALTH] = client->pers.maxHealth;\n\n\t// set model\n\tif( g_gametype.integer >= GT_TEAM ) {\n\t\tQ_strncpyz( model, Info_ValueForKey (userinfo, \"team_model\"), sizeof( model ) );\n\t\tQ_strncpyz( headModel, Info_ValueForKey (userinfo, \"team_headmodel\"), sizeof( headModel ) );\n\t} else {\n\t\tQ_strncpyz( model, Info_ValueForKey (userinfo, \"model\"), sizeof( model ) );\n\t\tQ_strncpyz( headModel, Info_ValueForKey (userinfo, \"headmodel\"), sizeof( headModel ) );\n\t}\n\n\t// bots set their team a few frames later\n\tif (g_gametype.integer >= GT_TEAM && g_entities[clientNum].r.svFlags & SVF_BOT) {\n\t\ts = Info_ValueForKey( userinfo, \"team\" );\n\t\tif ( !Q_stricmp( s, \"red\" ) || !Q_stricmp( s, \"r\" ) ) {\n\t\t\tteam = TEAM_RED;\n\t\t} else if ( !Q_stricmp( s, \"blue\" ) || !Q_stricmp( s, \"b\" ) ) {\n\t\t\tteam = TEAM_BLUE;\n\t\t} else {\n\t\t\t// pick the team with the least number of players\n\t\t\tteam = PickTeam( clientNum );\n\t\t}\n\t}\n\telse {\n\t\tteam = client->sess.sessionTeam;\n\t}\n\n/*\tNOTE: all client side now\n\n\t// team\n\tswitch( team ) {\n\tcase TEAM_RED:\n\t\tForceClientSkin(client, model, \"red\");\n//\t\tForceClientSkin(client, headModel, \"red\");\n\t\tbreak;\n\tcase TEAM_BLUE:\n\t\tForceClientSkin(client, model, \"blue\");\n//\t\tForceClientSkin(client, headModel, \"blue\");\n\t\tbreak;\n\t}\n\t// don't ever use a default skin in teamplay, it would just waste memory\n\t// however bots will always join a team but they spawn in as spectator\n\tif ( g_gametype.integer >= GT_TEAM && team == TEAM_SPECTATOR) {\n\t\tForceClientSkin(client, model, \"red\");\n//\t\tForceClientSkin(client, headModel, \"red\");\n\t}\n*/\n\n\t// teamInfo\n\ts = Info_ValueForKey( userinfo, \"teamoverlay\" );\n\tif ( ! *s || atoi( s ) != 0 ) {\n\t\tclient->pers.teamInfo = qtrue;\n\t} else {\n\t\tclient->pers.teamInfo = qfalse;\n\t}\n\t/*\n\ts = Info_ValueForKey( userinfo, \"cg_pmove_fixed\" );\n\tif ( !*s || atoi( s ) == 0 ) {\n\t\tclient->pers.pmoveFixed = qfalse;\n\t}\n\telse {\n\t\tclient->pers.pmoveFixed = qtrue;\n\t}\n\t*/\n\n\t// team task (0 = none, 1 = offence, 2 = defence)\n\tteamTask = atoi(Info_ValueForKey(userinfo, \"teamtask\"));\n\t// team Leader (1 = leader, 0 is normal player)\n\tteamLeader = client->sess.teamLeader;\n\n\t// colors\n\tstrcpy(c1, Info_ValueForKey( userinfo, \"color1\" ));\n\tstrcpy(c2, Info_ValueForKey( userinfo, \"color2\" ));\n\n\tstrcpy(redTeam, Info_ValueForKey( userinfo, \"g_redteam\" ));\n\tstrcpy(blueTeam, Info_ValueForKey( userinfo, \"g_blueteam\" ));\n\n\t// send over a subset of the userinfo keys so other clients can\n\t// print scoreboards, display models, and play custom sounds\n\tif ( ent->r.svFlags & SVF_BOT ) {\n\t\ts = va(\"n\\\\%s\\\\t\\\\%i\\\\model\\\\%s\\\\hmodel\\\\%s\\\\c1\\\\%s\\\\c2\\\\%s\\\\hc\\\\%i\\\\w\\\\%i\\\\l\\\\%i\\\\skill\\\\%s\\\\tt\\\\%d\\\\tl\\\\%d\",\n\t\t\tclient->pers.netname, team, model, headModel, c1, c2, \n\t\t\tclient->pers.maxHealth, client->sess.wins, client->sess.losses,\n\t\t\tInfo_ValueForKey( userinfo, \"skill\" ), teamTask, teamLeader );\n\t} else {\n\t\ts = va(\"n\\\\%s\\\\t\\\\%i\\\\model\\\\%s\\\\hmodel\\\\%s\\\\g_redteam\\\\%s\\\\g_blueteam\\\\%s\\\\c1\\\\%s\\\\c2\\\\%s\\\\hc\\\\%i\\\\w\\\\%i\\\\l\\\\%i\\\\tt\\\\%d\\\\tl\\\\%d\",\n\t\t\tclient->pers.netname, client->sess.sessionTeam, model, headModel, redTeam, blueTeam, c1, c2, \n\t\t\tclient->pers.maxHealth, client->sess.wins, client->sess.losses, teamTask, teamLeader);\n\t}\n\n\ttrap_SetConfigstring( CS_PLAYERS+clientNum, s );\n\n\t// this is not the userinfo, more like the configstring actually\n\tG_LogPrintf( \"ClientUserinfoChanged: %i %s\\n\", clientNum, s );\n}\n\n\n/*\n===========\nClientConnect\n\nCalled when a player begins connecting to the server.\nCalled again for every map change or tournement restart.\n\nThe session information will be valid after exit.\n\nReturn NULL if the client should be allowed, otherwise return\na string with the reason for denial.\n\nOtherwise, the client will be sent the current gamestate\nand will eventually get to ClientBegin.\n\nfirstTime will be qtrue the very first time a client connects\nto the server machine, but qfalse on map changes and tournement\nrestarts.\n============\n*/\nchar *ClientConnect( int clientNum, qboolean firstTime, qboolean isBot ) {\n\tchar\t\t*value;\n//\tchar\t\t*areabits;\n\tgclient_t\t*client;\n\tchar\t\tuserinfo[MAX_INFO_STRING];\n\tgentity_t\t*ent;\n\n\tent = &g_entities[ clientNum ];\n\n\ttrap_GetUserinfo( clientNum, userinfo, sizeof( userinfo ) );\n\n \t// IP filtering\n \t// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=500\n \t// recommanding PB based IP / GUID banning, the builtin system is pretty limited\n \t// check to see if they are on the banned IP list\n\tvalue = Info_ValueForKey (userinfo, \"ip\");\n\tif ( G_FilterPacket( value ) ) {\n\t\treturn \"You are banned from this server.\";\n\t}\n\n  // we don't check password for bots and local client\n  // NOTE: local client <-> \"ip\" \"localhost\"\n  //   this means this client is not running in our current process\n\tif ( !( ent->r.svFlags & SVF_BOT ) && (strcmp(value, \"localhost\") != 0)) {\n\t\t// check for a password\n\t\tvalue = Info_ValueForKey (userinfo, \"password\");\n\t\tif ( g_password.string[0] && Q_stricmp( g_password.string, \"none\" ) &&\n\t\t\tstrcmp( g_password.string, value) != 0) {\n\t\t\treturn \"Invalid password\";\n\t\t}\n\t}\n\n\t// they can connect\n\tent->client = level.clients + clientNum;\n\tclient = ent->client;\n\n//\tareabits = client->areabits;\n\n\tmemset( client, 0, sizeof(*client) );\n\n\tclient->pers.connected = CON_CONNECTING;\n\n\t// read or initialize the session data\n\tif ( firstTime || level.newSession ) {\n\t\tG_InitSessionData( client, userinfo );\n\t}\n\tG_ReadSessionData( client );\n\n\tif( isBot ) {\n\t\tent->r.svFlags |= SVF_BOT;\n\t\tent->inuse = qtrue;\n\t\tif( !G_BotConnect( clientNum, !firstTime ) ) {\n\t\t\treturn \"BotConnectfailed\";\n\t\t}\n\t}\n\n\t// get and distribute relevent paramters\n\tG_LogPrintf( \"ClientConnect: %i\\n\", clientNum );\n\tClientUserinfoChanged( clientNum );\n\n\t// don't do the \"xxx connected\" messages if they were caried over from previous level\n\tif ( firstTime ) {\n\t\ttrap_SendServerCommand( -1, va(\"print \\\"%s\" S_COLOR_WHITE \" connected\\n\\\"\", client->pers.netname) );\n\t}\n\n\tif ( g_gametype.integer >= GT_TEAM &&\n\t\tclient->sess.sessionTeam != TEAM_SPECTATOR ) {\n\t\tBroadcastTeamChange( client, -1 );\n\t}\n\n\t// count current clients and rank for scoreboard\n\tCalculateRanks();\n\n\t// for statistics\n//\tclient->areabits = areabits;\n//\tif ( !client->areabits )\n//\t\tclient->areabits = G_Alloc( (trap_AAS_PointReachabilityAreaIndex( NULL ) + 7) / 8 );\n\n\treturn NULL;\n}\n\n/*\n===========\nClientBegin\n\ncalled when a client has finished connecting, and is ready\nto be placed into the level.  This will happen every level load,\nand on transition between teams, but doesn't happen on respawns\n============\n*/\nvoid ClientBegin( int clientNum ) {\n\tgentity_t\t*ent;\n\tgclient_t\t*client;\n\tgentity_t\t*tent;\n\tint\t\t\tflags;\n\n\tent = g_entities + clientNum;\n\n\tclient = level.clients + clientNum;\n\n\tif ( ent->r.linked ) {\n\t\ttrap_UnlinkEntity( ent );\n\t}\n\tG_InitGentity( ent );\n\tent->touch = 0;\n\tent->pain = 0;\n\tent->client = client;\n\n\tclient->pers.connected = CON_CONNECTED;\n\tclient->pers.enterTime = level.time;\n\tclient->pers.teamState.state = TEAM_BEGIN;\n\n\t// save eflags around this, because changing teams will\n\t// cause this to happen with a valid entity, and we\n\t// want to make sure the teleport bit is set right\n\t// so the viewpoint doesn't interpolate through the\n\t// world to the new position\n\tflags = client->ps.eFlags;\n\tmemset( &client->ps, 0, sizeof( client->ps ) );\n\tclient->ps.eFlags = flags;\n\n\t// locate ent at a spawn point\n\tClientSpawn( ent );\n\n\tif ( client->sess.sessionTeam != TEAM_SPECTATOR ) {\n\t\t// send event\n\t\ttent = G_TempEntity( ent->client->ps.origin, EV_PLAYER_TELEPORT_IN );\n\t\ttent->s.clientNum = ent->s.clientNum;\n\n\t\tif ( g_gametype.integer != GT_TOURNAMENT  ) {\n\t\t\ttrap_SendServerCommand( -1, va(\"print \\\"%s\" S_COLOR_WHITE \" entered the game\\n\\\"\", client->pers.netname) );\n\t\t}\n\t}\n\tG_LogPrintf( \"ClientBegin: %i\\n\", clientNum );\n\n\t// count current clients and rank for scoreboard\n\tCalculateRanks();\n}\n\n/*\n===========\nClientSpawn\n\nCalled every time a client is placed fresh in the world:\nafter the first ClientBegin, and after each respawn\nInitializes all non-persistant parts of playerState\n============\n*/\nvoid ClientSpawn(gentity_t *ent) {\n\tint\t\tindex;\n\tvec3_t\tspawn_origin, spawn_angles;\n\tgclient_t\t*client;\n\tint\t\ti;\n\tclientPersistant_t\tsaved;\n\tclientSession_t\t\tsavedSess;\n\tint\t\tpersistant[MAX_PERSISTANT];\n\tgentity_t\t*spawnPoint;\n\tint\t\tflags;\n\tint\t\tsavedPing;\n//\tchar\t*savedAreaBits;\n\tint\t\taccuracy_hits, accuracy_shots;\n\tint\t\teventSequence;\n\tchar\tuserinfo[MAX_INFO_STRING];\n\n\tindex = ent - g_entities;\n\tclient = ent->client;\n\n\t// find a spawn point\n\t// do it before setting health back up, so farthest\n\t// ranging doesn't count this client\n\tif ( client->sess.sessionTeam == TEAM_SPECTATOR ) {\n\t\tspawnPoint = SelectSpectatorSpawnPoint ( \n\t\t\t\t\t\tspawn_origin, spawn_angles);\n\t} else if (g_gametype.integer >= GT_CTF ) {\n\t\t// all base oriented team games use the CTF spawn points\n\t\tspawnPoint = SelectCTFSpawnPoint ( \n\t\t\t\t\t\tclient->sess.sessionTeam, \n\t\t\t\t\t\tclient->pers.teamState.state, \n\t\t\t\t\t\tspawn_origin, spawn_angles);\n\t} else {\n\t\tdo {\n\t\t\t// the first spawn should be at a good looking spot\n\t\t\tif ( !client->pers.initialSpawn && client->pers.localClient ) {\n\t\t\t\tclient->pers.initialSpawn = qtrue;\n\t\t\t\tspawnPoint = SelectInitialSpawnPoint( spawn_origin, spawn_angles );\n\t\t\t} else {\n\t\t\t\t// don't spawn near existing origin if possible\n\t\t\t\tspawnPoint = SelectSpawnPoint ( \n\t\t\t\t\tclient->ps.origin, \n\t\t\t\t\tspawn_origin, spawn_angles);\n\t\t\t}\n\n\t\t\t// Tim needs to prevent bots from spawning at the initial point\n\t\t\t// on q3dm0...\n\t\t\tif ( ( spawnPoint->flags & FL_NO_BOTS ) && ( ent->r.svFlags & SVF_BOT ) ) {\n\t\t\t\tcontinue;\t// try again\n\t\t\t}\n\t\t\t// just to be symetric, we have a nohumans option...\n\t\t\tif ( ( spawnPoint->flags & FL_NO_HUMANS ) && !( ent->r.svFlags & SVF_BOT ) ) {\n\t\t\t\tcontinue;\t// try again\n\t\t\t}\n\n\t\t\tbreak;\n\n\t\t} while ( 1 );\n\t}\n\tclient->pers.teamState.state = TEAM_ACTIVE;\n\n\t// always clear the kamikaze flag\n\tent->s.eFlags &= ~EF_KAMIKAZE;\n\n\t// toggle the teleport bit so the client knows to not lerp\n\t// and never clear the voted flag\n\tflags = ent->client->ps.eFlags & (EF_TELEPORT_BIT | EF_VOTED | EF_TEAMVOTED);\n\tflags ^= EF_TELEPORT_BIT;\n\n\t// clear everything but the persistant data\n\n\tsaved = client->pers;\n\tsavedSess = client->sess;\n\tsavedPing = client->ps.ping;\n//\tsavedAreaBits = client->areabits;\n\taccuracy_hits = client->accuracy_hits;\n\taccuracy_shots = client->accuracy_shots;\n\tfor ( i = 0 ; i < MAX_PERSISTANT ; i++ ) {\n\t\tpersistant[i] = client->ps.persistant[i];\n\t}\n\teventSequence = client->ps.eventSequence;\n\n\tmemset (client, 0, sizeof(*client)); // bk FIXME: Com_Memset?\n\n\tclient->pers = saved;\n\tclient->sess = savedSess;\n\tclient->ps.ping = savedPing;\n//\tclient->areabits = savedAreaBits;\n\tclient->accuracy_hits = accuracy_hits;\n\tclient->accuracy_shots = accuracy_shots;\n\tclient->lastkilled_client = -1;\n\n\tfor ( i = 0 ; i < MAX_PERSISTANT ; i++ ) {\n\t\tclient->ps.persistant[i] = persistant[i];\n\t}\n\tclient->ps.eventSequence = eventSequence;\n\t// increment the spawncount so the client will detect the respawn\n\tclient->ps.persistant[PERS_SPAWN_COUNT]++;\n\tclient->ps.persistant[PERS_TEAM] = client->sess.sessionTeam;\n\n\tclient->airOutTime = level.time + 12000;\n\n\ttrap_GetUserinfo( index, userinfo, sizeof(userinfo) );\n\t// set max health\n\tclient->pers.maxHealth = atoi( Info_ValueForKey( userinfo, \"handicap\" ) );\n\tif ( client->pers.maxHealth < 1 || client->pers.maxHealth > 100 ) {\n\t\tclient->pers.maxHealth = 100;\n\t}\n\t// clear entity values\n\tclient->ps.stats[STAT_MAX_HEALTH] = client->pers.maxHealth;\n\tclient->ps.eFlags = flags;\n\n\tent->s.groundEntityNum = ENTITYNUM_NONE;\n\tent->client = &level.clients[index];\n\tent->takedamage = qtrue;\n\tent->inuse = qtrue;\n\tent->classname = \"player\";\n\tent->r.contents = CONTENTS_BODY;\n\tent->clipmask = MASK_PLAYERSOLID;\n\tent->die = player_die;\n\tent->waterlevel = 0;\n\tent->watertype = 0;\n\tent->flags = 0;\n\t\n\tVectorCopy (playerMins, ent->r.mins);\n\tVectorCopy (playerMaxs, ent->r.maxs);\n\n\tclient->ps.clientNum = index;\n\n\tclient->ps.stats[STAT_WEAPONS] = ( 1 << WP_MACHINEGUN );\n\tif ( g_gametype.integer == GT_TEAM ) {\n\t\tclient->ps.ammo[WP_MACHINEGUN] = 50;\n\t} else {\n\t\tclient->ps.ammo[WP_MACHINEGUN] = 100;\n\t}\n\n\tclient->ps.stats[STAT_WEAPONS] |= ( 1 << WP_GAUNTLET );\n\tclient->ps.ammo[WP_GAUNTLET] = -1;\n\tclient->ps.ammo[WP_GRAPPLING_HOOK] = -1;\n\n\t// health will count down towards max_health\n\tent->health = client->ps.stats[STAT_HEALTH] = client->ps.stats[STAT_MAX_HEALTH] + 25;\n\n\tG_SetOrigin( ent, spawn_origin );\n\tVectorCopy( spawn_origin, client->ps.origin );\n\n\t// the respawned flag will be cleared after the attack and jump keys come up\n\tclient->ps.pm_flags |= PMF_RESPAWNED;\n\n\ttrap_GetUsercmd( client - level.clients, &ent->client->pers.cmd );\n\tSetClientViewAngle( ent, spawn_angles );\n\n\tif ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) {\n\n\t} else {\n\t\tG_KillBox( ent );\n\t\ttrap_LinkEntity (ent);\n\n\t\t// force the base weapon up\n\t\tclient->ps.weapon = WP_MACHINEGUN;\n\t\tclient->ps.weaponstate = WEAPON_READY;\n\n\t}\n\n\t// don't allow full run speed for a bit\n\tclient->ps.pm_flags |= PMF_TIME_KNOCKBACK;\n\tclient->ps.pm_time = 100;\n\n\tclient->respawnTime = level.time;\n\tclient->inactivityTime = level.time + g_inactivity.integer * 1000;\n\tclient->latched_buttons = 0;\n\n\t// set default animations\n\tclient->ps.torsoAnim = TORSO_STAND;\n\tclient->ps.legsAnim = LEGS_IDLE;\n\n\tif ( level.intermissiontime ) {\n\t\tMoveClientToIntermission( ent );\n\t} else {\n\t\t// fire the targets of the spawn point\n\t\tG_UseTargets( spawnPoint, ent );\n\n\t\t// select the highest weapon number available, after any\n\t\t// spawn given items have fired\n\t\tclient->ps.weapon = 1;\n\t\tfor ( i = WP_NUM_WEAPONS - 1 ; i > 0 ; i-- ) {\n\t\t\tif ( client->ps.stats[STAT_WEAPONS] & ( 1 << i ) ) {\n\t\t\t\tclient->ps.weapon = i;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t// run a client frame to drop exactly to the floor,\n\t// initialize animations and other things\n\tclient->ps.commandTime = level.time - 100;\n\tent->client->pers.cmd.serverTime = level.time;\n\tClientThink( ent-g_entities );\n\n\t// positively link the client, even if the command times are weird\n\tif ( ent->client->sess.sessionTeam != TEAM_SPECTATOR ) {\n\t\tBG_PlayerStateToEntityState( &client->ps, &ent->s, qtrue );\n\t\tVectorCopy( ent->client->ps.origin, ent->r.currentOrigin );\n\t\ttrap_LinkEntity( ent );\n\t}\n\n\t// run the presend to set anything else\n\tClientEndFrame( ent );\n\n\t// clear entity state values\n\tBG_PlayerStateToEntityState( &client->ps, &ent->s, qtrue );\n}\n\n\n/*\n===========\nClientDisconnect\n\nCalled when a player drops from the server.\nWill not be called between levels.\n\nThis should NOT be called directly by any game logic,\ncall trap_DropClient(), which will call this and do\nserver system housekeeping.\n============\n*/\nvoid ClientDisconnect( int clientNum ) {\n\tgentity_t\t*ent;\n\tgentity_t\t*tent;\n\tint\t\t\ti;\n\n\t// cleanup if we are kicking a bot that\n\t// hasn't spawned yet\n\tG_RemoveQueuedBotBegin( clientNum );\n\n\tent = g_entities + clientNum;\n\tif ( !ent->client ) {\n\t\treturn;\n\t}\n\n\t// stop any following clients\n\tfor ( i = 0 ; i < level.maxclients ; i++ ) {\n\t\tif ( level.clients[i].sess.sessionTeam == TEAM_SPECTATOR\n\t\t\t&& level.clients[i].sess.spectatorState == SPECTATOR_FOLLOW\n\t\t\t&& level.clients[i].sess.spectatorClient == clientNum ) {\n\t\t\tStopFollowing( &g_entities[i] );\n\t\t}\n\t}\n\n\t// send effect if they were completely connected\n\tif ( ent->client->pers.connected == CON_CONNECTED \n\t\t&& ent->client->sess.sessionTeam != TEAM_SPECTATOR ) {\n\t\ttent = G_TempEntity( ent->client->ps.origin, EV_PLAYER_TELEPORT_OUT );\n\t\ttent->s.clientNum = ent->s.clientNum;\n\n\t\t// They don't get to take powerups with them!\n\t\t// Especially important for stuff like CTF flags\n\t\tTossClientItems( ent );\n\t}\n\n\tG_LogPrintf( \"ClientDisconnect: %i\\n\", clientNum );\n\n\t// if we are playing in tourney mode and losing, give a win to the other player\n\tif ( (g_gametype.integer == GT_TOURNAMENT )\n\t\t&& !level.intermissiontime\n\t\t&& !level.warmupTime && level.sortedClients[1] == clientNum ) {\n\t\tlevel.clients[ level.sortedClients[0] ].sess.wins++;\n\t\tClientUserinfoChanged( level.sortedClients[0] );\n\t}\n\n\ttrap_UnlinkEntity (ent);\n\tent->s.modelindex = 0;\n\tent->inuse = qfalse;\n\tent->classname = \"disconnected\";\n\tent->client->pers.connected = CON_DISCONNECTED;\n\tent->client->ps.persistant[PERS_TEAM] = TEAM_FREE;\n\tent->client->sess.sessionTeam = TEAM_FREE;\n\n\ttrap_SetConfigstring( CS_PLAYERS + clientNum, \"\");\n\n\tCalculateRanks();\n\n\tif ( ent->r.svFlags & SVF_BOT ) {\n\t\tBotAIShutdownClient( clientNum, qfalse );\n\t}\n}\n\n\n"
  },
  {
    "path": "src/game/g_cmds.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n#include \"g_local.h\"\n\n#include \"menudef.h\"\t\t\t// for the voice chats\n\n/*\n==================\nDeathmatchScoreboardMessage\n\n==================\n*/\nvoid DeathmatchScoreboardMessage( gentity_t *ent ) {\n\tchar\t\tentry[1024];\n\tchar\t\tstring[1400];\n\tint\t\t\tstringlength;\n\tint\t\t\ti, j;\n\tgclient_t\t*cl;\n\tint\t\t\tnumSorted, scoreFlags, accuracy, perfect;\n\n\t// send the latest information on all clients\n\tstring[0] = 0;\n\tstringlength = 0;\n\tscoreFlags = 0;\n\n\tnumSorted = level.numConnectedClients;\n\t\n\tfor (i=0 ; i < numSorted ; i++) {\n\t\tint\t\tping;\n\n\t\tcl = &level.clients[level.sortedClients[i]];\n\n\t\tif ( cl->pers.connected == CON_CONNECTING ) {\n\t\t\tping = -1;\n\t\t} else {\n\t\t\tping = cl->ps.ping < 999 ? cl->ps.ping : 999;\n\t\t}\n\n\t\tif( cl->accuracy_shots ) {\n\t\t\taccuracy = cl->accuracy_hits * 100 / cl->accuracy_shots;\n\t\t}\n\t\telse {\n\t\t\taccuracy = 0;\n\t\t}\n\t\tperfect = ( cl->ps.persistant[PERS_RANK] == 0 && cl->ps.persistant[PERS_KILLED] == 0 ) ? 1 : 0;\n\n\t\tCom_sprintf (entry, sizeof(entry),\n\t\t\t\" %i %i %i %i %i %i %i %i %i %i %i %i %i %i\", level.sortedClients[i],\n\t\t\tcl->ps.persistant[PERS_SCORE], ping, (level.time - cl->pers.enterTime)/60000,\n\t\t\tscoreFlags, g_entities[level.sortedClients[i]].s.powerups, accuracy, \n\t\t\tcl->ps.persistant[PERS_IMPRESSIVE_COUNT],\n\t\t\tcl->ps.persistant[PERS_EXCELLENT_COUNT],\n\t\t\tcl->ps.persistant[PERS_GAUNTLET_FRAG_COUNT], \n\t\t\tcl->ps.persistant[PERS_DEFEND_COUNT], \n\t\t\tcl->ps.persistant[PERS_ASSIST_COUNT], \n\t\t\tperfect,\n\t\t\tcl->ps.persistant[PERS_CAPTURES]);\n\t\tj = (int)strlen(entry);\n\t\tif (stringlength + j > 1024)\n\t\t\tbreak;\n\t\tstrcpy (string + stringlength, entry);\n\t\tstringlength += j;\n\t}\n\n\ttrap_SendServerCommand( ent-g_entities, va(\"scores %i %i %i%s\", i, \n\t\tlevel.teamScores[TEAM_RED], level.teamScores[TEAM_BLUE],\n\t\tstring ) );\n}\n\n\n/*\n==================\nCmd_Score_f\n\nRequest current scoreboard information\n==================\n*/\nvoid Cmd_Score_f( gentity_t *ent ) {\n\tDeathmatchScoreboardMessage( ent );\n}\n\n\n\n/*\n==================\nCheatsOk\n==================\n*/\nqboolean\tCheatsOk( gentity_t *ent ) {\n\tif ( !g_cheats.integer ) {\n\t\ttrap_SendServerCommand( ent-g_entities, va(\"print \\\"Cheats are not enabled on this server.\\n\\\"\"));\n\t\treturn qfalse;\n\t}\n\tif ( ent->health <= 0 ) {\n\t\ttrap_SendServerCommand( ent-g_entities, va(\"print \\\"You must be alive to use this command.\\n\\\"\"));\n\t\treturn qfalse;\n\t}\n\treturn qtrue;\n}\n\n\n/*\n==================\nConcatArgs\n==================\n*/\nchar\t*ConcatArgs( int start ) {\n\tint\t\ti, c, tlen;\n\tstatic char\tline[MAX_STRING_CHARS];\n\tint\t\tlen;\n\tchar\targ[MAX_STRING_CHARS];\n\n\tlen = 0;\n\tc = trap_Argc();\n\tfor ( i = start ; i < c ; i++ ) {\n\t\ttrap_Argv( i, arg, sizeof( arg ) );\n\t\ttlen = (int)strlen( arg );\n\t\tif ( len + tlen >= MAX_STRING_CHARS - 1 ) {\n\t\t\tbreak;\n\t\t}\n\t\tmemcpy( line + len, arg, tlen );\n\t\tlen += tlen;\n\t\tif ( i != c - 1 ) {\n\t\t\tline[len] = ' ';\n\t\t\tlen++;\n\t\t}\n\t}\n\n\tline[len] = 0;\n\n\treturn line;\n}\n\n/*\n==================\nSanitizeString\n\nRemove case and control characters\n==================\n*/\nvoid SanitizeString( char *in, char *out ) {\n\twhile ( *in ) {\n\t\tif ( *in == 27 ) {\n\t\t\tin += 2;\t\t// skip color code\n\t\t\tcontinue;\n\t\t}\n\t\tif ( *in < 32 ) {\n\t\t\tin++;\n\t\t\tcontinue;\n\t\t}\n\t\t*out++ = tolower( *in++ );\n\t}\n\n\t*out = 0;\n}\n\n/*\n==================\nClientNumberFromString\n\nReturns a player number for either a number or name string\nReturns -1 if invalid\n==================\n*/\nint ClientNumberFromString( gentity_t *to, char *s ) {\n\tgclient_t\t*cl;\n\tint\t\t\tidnum;\n\tchar\t\ts2[MAX_STRING_CHARS];\n\tchar\t\tn2[MAX_STRING_CHARS];\n\n\t// numeric values are just slot numbers\n\tif (s[0] >= '0' && s[0] <= '9') {\n\t\tidnum = atoi( s );\n\t\tif ( idnum < 0 || idnum >= level.maxclients ) {\n\t\t\ttrap_SendServerCommand( to-g_entities, va(\"print \\\"Bad client slot: %i\\n\\\"\", idnum));\n\t\t\treturn -1;\n\t\t}\n\n\t\tcl = &level.clients[idnum];\n\t\tif ( cl->pers.connected != CON_CONNECTED ) {\n\t\t\ttrap_SendServerCommand( to-g_entities, va(\"print \\\"Client %i is not active\\n\\\"\", idnum));\n\t\t\treturn -1;\n\t\t}\n\t\treturn idnum;\n\t}\n\n\t// check for a name match\n\tSanitizeString( s, s2 );\n\tfor ( idnum=0,cl=level.clients ; idnum < level.maxclients ; idnum++,cl++ ) {\n\t\tif ( cl->pers.connected != CON_CONNECTED ) {\n\t\t\tcontinue;\n\t\t}\n\t\tSanitizeString( cl->pers.netname, n2 );\n\t\tif ( !strcmp( n2, s2 ) ) {\n\t\t\treturn idnum;\n\t\t}\n\t}\n\n\ttrap_SendServerCommand( to-g_entities, va(\"print \\\"User %s is not on the server\\n\\\"\", s));\n\treturn -1;\n}\n\n/*\n==================\nCmd_Give_f\n\nGive items to a client\n==================\n*/\nvoid Cmd_Give_f (gentity_t *ent)\n{\n\tchar\t\t*name;\n\tgitem_t\t\t*it;\n\tint\t\t\ti;\n\tqboolean\tgive_all;\n\tgentity_t\t\t*it_ent;\n\ttrace_t\t\ttrace;\n\n\tif ( !CheatsOk( ent ) ) {\n\t\treturn;\n\t}\n\n\tname = ConcatArgs( 1 );\n\n\tif (Q_stricmp(name, \"all\") == 0)\n\t\tgive_all = qtrue;\n\telse\n\t\tgive_all = qfalse;\n\n\tif (give_all || Q_stricmp( name, \"health\") == 0)\n\t{\n\t\tent->health = ent->client->ps.stats[STAT_MAX_HEALTH];\n\t\tif (!give_all)\n\t\t\treturn;\n\t}\n\n\tif (give_all || Q_stricmp(name, \"weapons\") == 0)\n\t{\n\t\tent->client->ps.stats[STAT_WEAPONS] = (1 << WP_NUM_WEAPONS) - 1 - \n\t\t\t( 1 << WP_GRAPPLING_HOOK ) - ( 1 << WP_NONE );\n\t\tif (!give_all)\n\t\t\treturn;\n\t}\n\n\tif (give_all || Q_stricmp(name, \"ammo\") == 0)\n\t{\n\t\tfor ( i = 0 ; i < MAX_WEAPONS ; i++ ) {\n\t\t\tent->client->ps.ammo[i] = 999;\n\t\t}\n\t\tif (!give_all)\n\t\t\treturn;\n\t}\n\n\tif (give_all || Q_stricmp(name, \"armor\") == 0)\n\t{\n\t\tent->client->ps.stats[STAT_ARMOR] = 200;\n\n\t\tif (!give_all)\n\t\t\treturn;\n\t}\n\n\tif (Q_stricmp(name, \"excellent\") == 0) {\n\t\tent->client->ps.persistant[PERS_EXCELLENT_COUNT]++;\n\t\treturn;\n\t}\n\tif (Q_stricmp(name, \"impressive\") == 0) {\n\t\tent->client->ps.persistant[PERS_IMPRESSIVE_COUNT]++;\n\t\treturn;\n\t}\n\tif (Q_stricmp(name, \"gauntletaward\") == 0) {\n\t\tent->client->ps.persistant[PERS_GAUNTLET_FRAG_COUNT]++;\n\t\treturn;\n\t}\n\tif (Q_stricmp(name, \"defend\") == 0) {\n\t\tent->client->ps.persistant[PERS_DEFEND_COUNT]++;\n\t\treturn;\n\t}\n\tif (Q_stricmp(name, \"assist\") == 0) {\n\t\tent->client->ps.persistant[PERS_ASSIST_COUNT]++;\n\t\treturn;\n\t}\n\n\t// spawn a specific item right on the player\n\tif ( !give_all ) {\n\t\tit = BG_FindItem (name);\n\t\tif (!it) {\n\t\t\treturn;\n\t\t}\n\n\t\tit_ent = G_Spawn();\n\t\tVectorCopy( ent->r.currentOrigin, it_ent->s.origin );\n\t\tit_ent->classname = it->classname;\n\t\tG_SpawnItem (it_ent, it);\n\t\tFinishSpawningItem(it_ent );\n\t\tmemset( &trace, 0, sizeof( trace ) );\n\t\tTouch_Item (it_ent, ent, &trace);\n\t\tif (it_ent->inuse) {\n\t\t\tG_FreeEntity( it_ent );\n\t\t}\n\t}\n}\n\n\n/*\n==================\nCmd_God_f\n\nSets client to godmode\n\nargv(0) god\n==================\n*/\nvoid Cmd_God_f (gentity_t *ent)\n{\n\tchar\t*msg;\n\n\tif ( !CheatsOk( ent ) ) {\n\t\treturn;\n\t}\n\n\tent->flags ^= FL_GODMODE;\n\tif (!(ent->flags & FL_GODMODE) )\n\t\tmsg = \"godmode OFF\\n\";\n\telse\n\t\tmsg = \"godmode ON\\n\";\n\n\ttrap_SendServerCommand( ent-g_entities, va(\"print \\\"%s\\\"\", msg));\n}\n\n\n/*\n==================\nCmd_Notarget_f\n\nSets client to notarget\n\nargv(0) notarget\n==================\n*/\nvoid Cmd_Notarget_f( gentity_t *ent ) {\n\tchar\t*msg;\n\n\tif ( !CheatsOk( ent ) ) {\n\t\treturn;\n\t}\n\n\tent->flags ^= FL_NOTARGET;\n\tif (!(ent->flags & FL_NOTARGET) )\n\t\tmsg = \"notarget OFF\\n\";\n\telse\n\t\tmsg = \"notarget ON\\n\";\n\n\ttrap_SendServerCommand( ent-g_entities, va(\"print \\\"%s\\\"\", msg));\n}\n\n\n/*\n==================\nCmd_Noclip_f\n\nargv(0) noclip\n==================\n*/\nvoid Cmd_Noclip_f( gentity_t *ent ) {\n\tchar\t*msg;\n\n\tif ( !CheatsOk( ent ) ) {\n\t\treturn;\n\t}\n\n\tif ( ent->client->noclip ) {\n\t\tmsg = \"noclip OFF\\n\";\n\t} else {\n\t\tmsg = \"noclip ON\\n\";\n\t}\n\tent->client->noclip = !ent->client->noclip;\n\n\ttrap_SendServerCommand( ent-g_entities, va(\"print \\\"%s\\\"\", msg));\n}\n\n\n/*\n==================\nCmd_LevelShot_f\n\nThis is just to help generate the level pictures\nfor the menus.  It goes to the intermission immediately\nand sends over a command to the client to resize the view,\nhide the scoreboard, and take a special screenshot\n==================\n*/\nvoid Cmd_LevelShot_f( gentity_t *ent ) {\n\tif ( !CheatsOk( ent ) ) {\n\t\treturn;\n\t}\n\n\t// doesn't work in single player\n\tif ( g_gametype.integer != 0 ) {\n\t\ttrap_SendServerCommand( ent-g_entities, \n\t\t\t\"print \\\"Must be in g_gametype 0 for levelshot\\n\\\"\" );\n\t\treturn;\n\t}\n\n\tBeginIntermission();\n\ttrap_SendServerCommand( ent-g_entities, \"clientLevelShot\" );\n}\n\n\n/*\n==================\nCmd_LevelShot_f\n\nThis is just to help generate the level pictures\nfor the menus.  It goes to the intermission immediately\nand sends over a command to the client to resize the view,\nhide the scoreboard, and take a special screenshot\n==================\n*/\nvoid Cmd_TeamTask_f( gentity_t *ent ) {\n\tchar userinfo[MAX_INFO_STRING];\n\tchar\t\targ[MAX_TOKEN_CHARS];\n\tint task;\n\tint client = ent->client - level.clients;\n\n\tif ( trap_Argc() != 2 ) {\n\t\treturn;\n\t}\n\ttrap_Argv( 1, arg, sizeof( arg ) );\n\ttask = atoi( arg );\n\n\ttrap_GetUserinfo(client, userinfo, sizeof(userinfo));\n\tInfo_SetValueForKey(userinfo, \"teamtask\", va(\"%d\", task));\n\ttrap_SetUserinfo(client, userinfo);\n\tClientUserinfoChanged(client);\n}\n\n\n\n/*\n=================\nCmd_Kill_f\n=================\n*/\nvoid Cmd_Kill_f( gentity_t *ent ) {\n\tif ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) {\n\t\treturn;\n\t}\n\tif (ent->health <= 0) {\n\t\treturn;\n\t}\n\tent->flags &= ~FL_GODMODE;\n\tent->client->ps.stats[STAT_HEALTH] = ent->health = -999;\n\tplayer_die (ent, ent, ent, 100000, MOD_SUICIDE);\n}\n\n/*\n=================\nBroadCastTeamChange\n\nLet everyone know about a team change\n=================\n*/\nvoid BroadcastTeamChange( gclient_t *client, int oldTeam )\n{\n\tif ( client->sess.sessionTeam == TEAM_RED ) {\n\t\ttrap_SendServerCommand( -1, va(\"cp \\\"%s\" S_COLOR_WHITE \" joined the red team.\\n\\\"\",\n\t\t\tclient->pers.netname) );\n\t} else if ( client->sess.sessionTeam == TEAM_BLUE ) {\n\t\ttrap_SendServerCommand( -1, va(\"cp \\\"%s\" S_COLOR_WHITE \" joined the blue team.\\n\\\"\",\n\t\tclient->pers.netname));\n\t} else if ( client->sess.sessionTeam == TEAM_SPECTATOR && oldTeam != TEAM_SPECTATOR ) {\n\t\ttrap_SendServerCommand( -1, va(\"cp \\\"%s\" S_COLOR_WHITE \" joined the spectators.\\n\\\"\",\n\t\tclient->pers.netname));\n\t} else if ( client->sess.sessionTeam == TEAM_FREE ) {\n\t\ttrap_SendServerCommand( -1, va(\"cp \\\"%s\" S_COLOR_WHITE \" joined the battle.\\n\\\"\",\n\t\tclient->pers.netname));\n\t}\n}\n\n/*\n=================\nSetTeam\n=================\n*/\nvoid SetTeam( gentity_t *ent, char *s ) {\n\tint\t\t\t\t\tteam, oldTeam;\n\tgclient_t\t\t\t*client;\n\tint\t\t\t\t\tclientNum;\n\tspectatorState_t\tspecState;\n\tint\t\t\t\t\tspecClient;\n\tint\t\t\t\t\tteamLeader;\n\n\t//\n\t// see what change is requested\n\t//\n\tclient = ent->client;\n\n\tclientNum = client - level.clients;\n\tspecClient = 0;\n\tspecState = SPECTATOR_NOT;\n\tif ( !Q_stricmp( s, \"scoreboard\" ) || !Q_stricmp( s, \"score\" )  ) {\n\t\tteam = TEAM_SPECTATOR;\n\t\tspecState = SPECTATOR_SCOREBOARD;\n\t} else if ( !Q_stricmp( s, \"follow1\" ) ) {\n\t\tteam = TEAM_SPECTATOR;\n\t\tspecState = SPECTATOR_FOLLOW;\n\t\tspecClient = -1;\n\t} else if ( !Q_stricmp( s, \"follow2\" ) ) {\n\t\tteam = TEAM_SPECTATOR;\n\t\tspecState = SPECTATOR_FOLLOW;\n\t\tspecClient = -2;\n\t} else if ( !Q_stricmp( s, \"spectator\" ) || !Q_stricmp( s, \"s\" ) ) {\n\t\tteam = TEAM_SPECTATOR;\n\t\tspecState = SPECTATOR_FREE;\n\t} else if ( g_gametype.integer >= GT_TEAM ) {\n\t\t// if running a team game, assign player to one of the teams\n\t\tspecState = SPECTATOR_NOT;\n\t\tif ( !Q_stricmp( s, \"red\" ) || !Q_stricmp( s, \"r\" ) ) {\n\t\t\tteam = TEAM_RED;\n\t\t} else if ( !Q_stricmp( s, \"blue\" ) || !Q_stricmp( s, \"b\" ) ) {\n\t\t\tteam = TEAM_BLUE;\n\t\t} else {\n\t\t\t// pick the team with the least number of players\n\t\t\tteam = PickTeam( clientNum );\n\t\t}\n\n\t\tif ( g_teamForceBalance.integer  ) {\n\t\t\tint\t\tcounts[TEAM_NUM_TEAMS];\n\n\t\t\tcounts[TEAM_BLUE] = TeamCount( ent->client->ps.clientNum, TEAM_BLUE );\n\t\t\tcounts[TEAM_RED] = TeamCount( ent->client->ps.clientNum, TEAM_RED );\n\n\t\t\t// We allow a spread of two\n\t\t\tif ( team == TEAM_RED && counts[TEAM_RED] - counts[TEAM_BLUE] > 1 ) {\n\t\t\t\ttrap_SendServerCommand( ent->client->ps.clientNum, \n\t\t\t\t\t\"cp \\\"Red team has too many players.\\n\\\"\" );\n\t\t\t\treturn; // ignore the request\n\t\t\t}\n\t\t\tif ( team == TEAM_BLUE && counts[TEAM_BLUE] - counts[TEAM_RED] > 1 ) {\n\t\t\t\ttrap_SendServerCommand( ent->client->ps.clientNum, \n\t\t\t\t\t\"cp \\\"Blue team has too many players.\\n\\\"\" );\n\t\t\t\treturn; // ignore the request\n\t\t\t}\n\n\t\t\t// It's ok, the team we are switching to has less or same number of players\n\t\t}\n\n\t} else {\n\t\t// force them to spectators if there aren't any spots free\n\t\tteam = TEAM_FREE;\n\t}\n\n\t// override decision if limiting the players\n\tif ( (g_gametype.integer == GT_TOURNAMENT)\n\t\t&& level.numNonSpectatorClients >= 2 ) {\n\t\tteam = TEAM_SPECTATOR;\n\t} else if ( g_maxGameClients.integer > 0 && \n\t\tlevel.numNonSpectatorClients >= g_maxGameClients.integer ) {\n\t\tteam = TEAM_SPECTATOR;\n\t}\n\n\t//\n\t// decide if we will allow the change\n\t//\n\toldTeam = client->sess.sessionTeam;\n\tif ( team == oldTeam && team != TEAM_SPECTATOR ) {\n\t\treturn;\n\t}\n\n\t//\n\t// execute the team change\n\t//\n\n\t// if the player was dead leave the body\n\tif ( client->ps.stats[STAT_HEALTH] <= 0 ) {\n\t\tCopyToBodyQue(ent);\n\t}\n\n\t// he starts at 'base'\n\tclient->pers.teamState.state = TEAM_BEGIN;\n\tif ( oldTeam != TEAM_SPECTATOR ) {\n\t\t// Kill him (makes sure he loses flags, etc)\n\t\tent->flags &= ~FL_GODMODE;\n\t\tent->client->ps.stats[STAT_HEALTH] = ent->health = 0;\n\t\tplayer_die (ent, ent, ent, 100000, MOD_SUICIDE);\n\n\t}\n\t// they go to the end of the line for tournements\n\tif ( team == TEAM_SPECTATOR ) {\n\t\tclient->sess.spectatorTime = level.time;\n\t}\n\n\tclient->sess.sessionTeam = team;\n\tclient->sess.spectatorState = specState;\n\tclient->sess.spectatorClient = specClient;\n\n\tclient->sess.teamLeader = qfalse;\n\tif ( team == TEAM_RED || team == TEAM_BLUE ) {\n\t\tteamLeader = TeamLeader( team );\n\t\t// if there is no team leader or the team leader is a bot and this client is not a bot\n\t\tif ( teamLeader == -1 || ( !(g_entities[clientNum].r.svFlags & SVF_BOT) && (g_entities[teamLeader].r.svFlags & SVF_BOT) ) ) {\n\t\t\tSetLeader( team, clientNum );\n\t\t}\n\t}\n\t// make sure there is a team leader on the team the player came from\n\tif ( oldTeam == TEAM_RED || oldTeam == TEAM_BLUE ) {\n\t\tCheckTeamLeader( oldTeam );\n\t}\n\n\tBroadcastTeamChange( client, oldTeam );\n\n\t// get and distribute relevent paramters\n\tClientUserinfoChanged( clientNum );\n\n\tClientBegin( clientNum );\n}\n\n/*\n=================\nStopFollowing\n\nIf the client being followed leaves the game, or you just want to drop\nto free floating spectator mode\n=================\n*/\nvoid StopFollowing( gentity_t *ent ) {\n\tent->client->ps.persistant[ PERS_TEAM ] = TEAM_SPECTATOR;\t\n\tent->client->sess.sessionTeam = TEAM_SPECTATOR;\t\n\tent->client->sess.spectatorState = SPECTATOR_FREE;\n\tent->client->ps.pm_flags &= ~PMF_FOLLOW;\n\tent->r.svFlags &= ~SVF_BOT;\n\tent->client->ps.clientNum = ent - g_entities;\n}\n\n/*\n=================\nCmd_Team_f\n=================\n*/\nvoid Cmd_Team_f( gentity_t *ent ) {\n\tint\t\t\toldTeam;\n\tchar\t\ts[MAX_TOKEN_CHARS];\n\n\tif ( trap_Argc() != 2 ) {\n\t\toldTeam = ent->client->sess.sessionTeam;\n\t\tswitch ( oldTeam ) {\n\t\tcase TEAM_BLUE:\n\t\t\ttrap_SendServerCommand( ent-g_entities, \"print \\\"Blue team\\n\\\"\" );\n\t\t\tbreak;\n\t\tcase TEAM_RED:\n\t\t\ttrap_SendServerCommand( ent-g_entities, \"print \\\"Red team\\n\\\"\" );\n\t\t\tbreak;\n\t\tcase TEAM_FREE:\n\t\t\ttrap_SendServerCommand( ent-g_entities, \"print \\\"Free team\\n\\\"\" );\n\t\t\tbreak;\n\t\tcase TEAM_SPECTATOR:\n\t\t\ttrap_SendServerCommand( ent-g_entities, \"print \\\"Spectator team\\n\\\"\" );\n\t\t\tbreak;\n\t\t}\n\t\treturn;\n\t}\n\n\tif ( ent->client->switchTeamTime > level.time ) {\n\t\ttrap_SendServerCommand( ent-g_entities, \"print \\\"May not switch teams more than once per 5 seconds.\\n\\\"\" );\n\t\treturn;\n\t}\n\n\t// if they are playing a tournement game, count as a loss\n\tif ( (g_gametype.integer == GT_TOURNAMENT )\n\t\t&& ent->client->sess.sessionTeam == TEAM_FREE ) {\n\t\tent->client->sess.losses++;\n\t}\n\n\ttrap_Argv( 1, s, sizeof( s ) );\n\n\tSetTeam( ent, s );\n\n\tent->client->switchTeamTime = level.time + 5000;\n}\n\n\n/*\n=================\nCmd_Follow_f\n=================\n*/\nvoid Cmd_Follow_f( gentity_t *ent ) {\n\tint\t\ti;\n\tchar\targ[MAX_TOKEN_CHARS];\n\n\tif ( trap_Argc() != 2 ) {\n\t\tif ( ent->client->sess.spectatorState == SPECTATOR_FOLLOW ) {\n\t\t\tStopFollowing( ent );\n\t\t}\n\t\treturn;\n\t}\n\n\ttrap_Argv( 1, arg, sizeof( arg ) );\n\ti = ClientNumberFromString( ent, arg );\n\tif ( i == -1 ) {\n\t\treturn;\n\t}\n\n\t// can't follow self\n\tif ( &level.clients[ i ] == ent->client ) {\n\t\treturn;\n\t}\n\n\t// can't follow another spectator\n\tif ( level.clients[ i ].sess.sessionTeam == TEAM_SPECTATOR ) {\n\t\treturn;\n\t}\n\n\t// if they are playing a tournement game, count as a loss\n\tif ( (g_gametype.integer == GT_TOURNAMENT )\n\t\t&& ent->client->sess.sessionTeam == TEAM_FREE ) {\n\t\tent->client->sess.losses++;\n\t}\n\n\t// first set them to spectator\n\tif ( ent->client->sess.sessionTeam != TEAM_SPECTATOR ) {\n\t\tSetTeam( ent, \"spectator\" );\n\t}\n\n\tent->client->sess.spectatorState = SPECTATOR_FOLLOW;\n\tent->client->sess.spectatorClient = i;\n}\n\n/*\n=================\nCmd_FollowCycle_f\n=================\n*/\nvoid Cmd_FollowCycle_f( gentity_t *ent, int dir ) {\n\tint\t\tclientnum;\n\tint\t\toriginal;\n\n\t// if they are playing a tournement game, count as a loss\n\tif ( (g_gametype.integer == GT_TOURNAMENT )\n\t\t&& ent->client->sess.sessionTeam == TEAM_FREE ) {\n\t\tent->client->sess.losses++;\n\t}\n\t// first set them to spectator\n\tif ( ent->client->sess.spectatorState == SPECTATOR_NOT ) {\n\t\tSetTeam( ent, \"spectator\" );\n\t}\n\n\tif ( dir != 1 && dir != -1 ) {\n\t\tG_Error( \"Cmd_FollowCycle_f: bad dir %i\", dir );\n\t}\n\n\tclientnum = ent->client->sess.spectatorClient;\n\toriginal = clientnum;\n\tdo {\n\t\tclientnum += dir;\n\t\tif ( clientnum >= level.maxclients ) {\n\t\t\tclientnum = 0;\n\t\t}\n\t\tif ( clientnum < 0 ) {\n\t\t\tclientnum = level.maxclients - 1;\n\t\t}\n\n\t\t// can only follow connected clients\n\t\tif ( level.clients[ clientnum ].pers.connected != CON_CONNECTED ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// can't follow another spectator\n\t\tif ( level.clients[ clientnum ].sess.sessionTeam == TEAM_SPECTATOR ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// this is good, we can use it\n\t\tent->client->sess.spectatorClient = clientnum;\n\t\tent->client->sess.spectatorState = SPECTATOR_FOLLOW;\n\t\treturn;\n\t} while ( clientnum != original );\n\n\t// leave it where it was\n}\n\n\n/*\n==================\nG_Say\n==================\n*/\n\nstatic void G_SayTo( gentity_t *ent, gentity_t *other, int mode, int color, const char *name, const char *message ) {\n\tif (!other) {\n\t\treturn;\n\t}\n\tif (!other->inuse) {\n\t\treturn;\n\t}\n\tif (!other->client) {\n\t\treturn;\n\t}\n\tif ( other->client->pers.connected != CON_CONNECTED ) {\n\t\treturn;\n\t}\n\tif ( mode == SAY_TEAM  && !OnSameTeam(ent, other) ) {\n\t\treturn;\n\t}\n\t// no chatting to players in tournements\n\tif ( (g_gametype.integer == GT_TOURNAMENT )\n\t\t&& other->client->sess.sessionTeam == TEAM_FREE\n\t\t&& ent->client->sess.sessionTeam != TEAM_FREE ) {\n\t\treturn;\n\t}\n\n\ttrap_SendServerCommand( other-g_entities, va(\"%s \\\"%s%c%c%s\\\"\", \n\t\tmode == SAY_TEAM ? \"tchat\" : \"chat\",\n\t\tname, Q_COLOR_ESCAPE, color, message));\n}\n\n#define EC\t\t\"\\x19\"\n\nvoid G_Say( gentity_t *ent, gentity_t *target, int mode, const char *chatText ) {\n\tint\t\t\tj;\n\tgentity_t\t*other;\n\tint\t\t\tcolor;\n\tchar\t\tname[64];\n\t// don't let text be too long for malicious reasons\n\tchar\t\ttext[MAX_SAY_TEXT];\n\tchar\t\tlocation[64];\n\n\tif ( g_gametype.integer < GT_TEAM && mode == SAY_TEAM ) {\n\t\tmode = SAY_ALL;\n\t}\n\n\tswitch ( mode ) {\n\tdefault:\n\tcase SAY_ALL:\n\t\tG_LogPrintf( \"say: %s: %s\\n\", ent->client->pers.netname, chatText );\n\t\tCom_sprintf (name, sizeof(name), \"%s%c%c\"EC\": \", ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE );\n\t\tcolor = COLOR_GREEN;\n\t\tbreak;\n\tcase SAY_TEAM:\n\t\tG_LogPrintf( \"sayteam: %s: %s\\n\", ent->client->pers.netname, chatText );\n\t\tif (Team_GetLocationMsg(ent, location, sizeof(location)))\n\t\t\tCom_sprintf (name, sizeof(name), EC\"(%s%c%c\"EC\") (%s)\"EC\": \", \n\t\t\t\tent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE, location);\n\t\telse\n\t\t\tCom_sprintf (name, sizeof(name), EC\"(%s%c%c\"EC\")\"EC\": \", \n\t\t\t\tent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE );\n\t\tcolor = COLOR_CYAN;\n\t\tbreak;\n\tcase SAY_TELL:\n\t\tif (target && g_gametype.integer >= GT_TEAM &&\n\t\t\ttarget->client->sess.sessionTeam == ent->client->sess.sessionTeam &&\n\t\t\tTeam_GetLocationMsg(ent, location, sizeof(location)))\n\t\t\tCom_sprintf (name, sizeof(name), EC\"[%s%c%c\"EC\"] (%s)\"EC\": \", ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE, location );\n\t\telse\n\t\t\tCom_sprintf (name, sizeof(name), EC\"[%s%c%c\"EC\"]\"EC\": \", ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE );\n\t\tcolor = COLOR_MAGENTA;\n\t\tbreak;\n\t}\n\n\tQ_strncpyz( text, chatText, sizeof(text) );\n\n\tif ( target ) {\n\t\tG_SayTo( ent, target, mode, color, name, text );\n\t\treturn;\n\t}\n\n\t// echo the text to the console\n\tif ( g_dedicated.integer ) {\n\t\tG_Printf( \"%s%s\\n\", name, text);\n\t}\n\n\t// send it to all the apropriate clients\n\tfor (j = 0; j < level.maxclients; j++) {\n\t\tother = &g_entities[j];\n\t\tG_SayTo( ent, other, mode, color, name, text );\n\t}\n}\n\n\n/*\n==================\nCmd_Say_f\n==================\n*/\nstatic void Cmd_Say_f( gentity_t *ent, int mode, qboolean arg0 ) {\n\tchar\t\t*p;\n\n\tif ( trap_Argc () < 2 && !arg0 ) {\n\t\treturn;\n\t}\n\n\tif (arg0)\n\t{\n\t\tp = ConcatArgs( 0 );\n\t}\n\telse\n\t{\n\t\tp = ConcatArgs( 1 );\n\t}\n\n\tG_Say( ent, NULL, mode, p );\n}\n\n/*\n==================\nCmd_Tell_f\n==================\n*/\nstatic void Cmd_Tell_f( gentity_t *ent ) {\n\tint\t\t\ttargetNum;\n\tgentity_t\t*target;\n\tchar\t\t*p;\n\tchar\t\targ[MAX_TOKEN_CHARS];\n\n\tif ( trap_Argc () < 2 ) {\n\t\treturn;\n\t}\n\n\ttrap_Argv( 1, arg, sizeof( arg ) );\n\ttargetNum = atoi( arg );\n\tif ( targetNum < 0 || targetNum >= level.maxclients ) {\n\t\treturn;\n\t}\n\n\ttarget = &g_entities[targetNum];\n\tif ( !target || !target->inuse || !target->client ) {\n\t\treturn;\n\t}\n\n\tp = ConcatArgs( 2 );\n\n\tG_LogPrintf( \"tell: %s to %s: %s\\n\", ent->client->pers.netname, target->client->pers.netname, p );\n\tG_Say( ent, target, SAY_TELL, p );\n\t// don't tell to the player self if it was already directed to this player\n\t// also don't send the chat back to a bot\n\tif ( ent != target && !(ent->r.svFlags & SVF_BOT)) {\n\t\tG_Say( ent, ent, SAY_TELL, p );\n\t}\n}\n\n\nstatic void G_VoiceTo( gentity_t *ent, gentity_t *other, int mode, const char *id, qboolean voiceonly ) {\n\tint color;\n\tchar *cmd;\n\n\tif (!other) {\n\t\treturn;\n\t}\n\tif (!other->inuse) {\n\t\treturn;\n\t}\n\tif (!other->client) {\n\t\treturn;\n\t}\n\tif ( mode == SAY_TEAM && !OnSameTeam(ent, other) ) {\n\t\treturn;\n\t}\n\t// no chatting to players in tournements\n\tif ( (g_gametype.integer == GT_TOURNAMENT )) {\n\t\treturn;\n\t}\n\n\tif (mode == SAY_TEAM) {\n\t\tcolor = COLOR_CYAN;\n\t\tcmd = \"vtchat\";\n\t}\n\telse if (mode == SAY_TELL) {\n\t\tcolor = COLOR_MAGENTA;\n\t\tcmd = \"vtell\";\n\t}\n\telse {\n\t\tcolor = COLOR_GREEN;\n\t\tcmd = \"vchat\";\n\t}\n\n\ttrap_SendServerCommand( other-g_entities, va(\"%s %d %d %d %s\", cmd, voiceonly, ent->s.number, color, id));\n}\n\nvoid G_Voice( gentity_t *ent, gentity_t *target, int mode, const char *id, qboolean voiceonly ) {\n\tint\t\t\tj;\n\tgentity_t\t*other;\n\n\tif ( g_gametype.integer < GT_TEAM && mode == SAY_TEAM ) {\n\t\tmode = SAY_ALL;\n\t}\n\n\tif ( target ) {\n\t\tG_VoiceTo( ent, target, mode, id, voiceonly );\n\t\treturn;\n\t}\n\n\t// echo the text to the console\n\tif ( g_dedicated.integer ) {\n\t\tG_Printf( \"voice: %s %s\\n\", ent->client->pers.netname, id);\n\t}\n\n\t// send it to all the apropriate clients\n\tfor (j = 0; j < level.maxclients; j++) {\n\t\tother = &g_entities[j];\n\t\tG_VoiceTo( ent, other, mode, id, voiceonly );\n\t}\n}\n\n/*\n==================\nCmd_Voice_f\n==================\n*/\nstatic void Cmd_Voice_f( gentity_t *ent, int mode, qboolean arg0, qboolean voiceonly ) {\n\tchar\t\t*p;\n\n\tif ( trap_Argc () < 2 && !arg0 ) {\n\t\treturn;\n\t}\n\n\tif (arg0)\n\t{\n\t\tp = ConcatArgs( 0 );\n\t}\n\telse\n\t{\n\t\tp = ConcatArgs( 1 );\n\t}\n\n\tG_Voice( ent, NULL, mode, p, voiceonly );\n}\n\n/*\n==================\nCmd_VoiceTell_f\n==================\n*/\nstatic void Cmd_VoiceTell_f( gentity_t *ent, qboolean voiceonly ) {\n\tint\t\t\ttargetNum;\n\tgentity_t\t*target;\n\tchar\t\t*id;\n\tchar\t\targ[MAX_TOKEN_CHARS];\n\n\tif ( trap_Argc () < 2 ) {\n\t\treturn;\n\t}\n\n\ttrap_Argv( 1, arg, sizeof( arg ) );\n\ttargetNum = atoi( arg );\n\tif ( targetNum < 0 || targetNum >= level.maxclients ) {\n\t\treturn;\n\t}\n\n\ttarget = &g_entities[targetNum];\n\tif ( !target || !target->inuse || !target->client ) {\n\t\treturn;\n\t}\n\n\tid = ConcatArgs( 2 );\n\n\tG_LogPrintf( \"vtell: %s to %s: %s\\n\", ent->client->pers.netname, target->client->pers.netname, id );\n\tG_Voice( ent, target, SAY_TELL, id, voiceonly );\n\t// don't tell to the player self if it was already directed to this player\n\t// also don't send the chat back to a bot\n\tif ( ent != target && !(ent->r.svFlags & SVF_BOT)) {\n\t\tG_Voice( ent, ent, SAY_TELL, id, voiceonly );\n\t}\n}\n\n\n/*\n==================\nCmd_VoiceTaunt_f\n==================\n*/\nstatic void Cmd_VoiceTaunt_f( gentity_t *ent ) {\n\tgentity_t *who;\n\tint i;\n\n\tif (!ent->client) {\n\t\treturn;\n\t}\n\n\t// insult someone who just killed you\n\tif (ent->enemy && ent->enemy->client && ent->enemy->client->lastkilled_client == ent->s.number) {\n\t\t// i am a dead corpse\n\t\tif (!(ent->enemy->r.svFlags & SVF_BOT)) {\n\t\t\tG_Voice( ent, ent->enemy, SAY_TELL, VOICECHAT_DEATHINSULT, qfalse );\n\t\t}\n\t\tif (!(ent->r.svFlags & SVF_BOT)) {\n\t\t\tG_Voice( ent, ent,        SAY_TELL, VOICECHAT_DEATHINSULT, qfalse );\n\t\t}\n\t\tent->enemy = NULL;\n\t\treturn;\n\t}\n\t// insult someone you just killed\n\tif (ent->client->lastkilled_client >= 0 && ent->client->lastkilled_client != ent->s.number) {\n\t\twho = g_entities + ent->client->lastkilled_client;\n\t\tif (who->client) {\n\t\t\t// who is the person I just killed\n\t\t\tif (who->client->lasthurt_mod == MOD_GAUNTLET) {\n\t\t\t\tif (!(who->r.svFlags & SVF_BOT)) {\n\t\t\t\t\tG_Voice( ent, who, SAY_TELL, VOICECHAT_KILLGAUNTLET, qfalse );\t// and I killed them with a gauntlet\n\t\t\t\t}\n\t\t\t\tif (!(ent->r.svFlags & SVF_BOT)) {\n\t\t\t\t\tG_Voice( ent, ent, SAY_TELL, VOICECHAT_KILLGAUNTLET, qfalse );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (!(who->r.svFlags & SVF_BOT)) {\n\t\t\t\t\tG_Voice( ent, who, SAY_TELL, VOICECHAT_KILLINSULT, qfalse );\t// and I killed them with something else\n\t\t\t\t}\n\t\t\t\tif (!(ent->r.svFlags & SVF_BOT)) {\n\t\t\t\t\tG_Voice( ent, ent, SAY_TELL, VOICECHAT_KILLINSULT, qfalse );\n\t\t\t\t}\n\t\t\t}\n\t\t\tent->client->lastkilled_client = -1;\n\t\t\treturn;\n\t\t}\n\t}\n\n\tif (g_gametype.integer >= GT_TEAM) {\n\t\t// praise a team mate who just got a reward\n\t\tfor(i = 0; i < MAX_CLIENTS; i++) {\n\t\t\twho = g_entities + i;\n\t\t\tif (who->client && who != ent && who->client->sess.sessionTeam == ent->client->sess.sessionTeam) {\n\t\t\t\tif (who->client->rewardTime > level.time) {\n\t\t\t\t\tif (!(who->r.svFlags & SVF_BOT)) {\n\t\t\t\t\t\tG_Voice( ent, who, SAY_TELL, VOICECHAT_PRAISE, qfalse );\n\t\t\t\t\t}\n\t\t\t\t\tif (!(ent->r.svFlags & SVF_BOT)) {\n\t\t\t\t\t\tG_Voice( ent, ent, SAY_TELL, VOICECHAT_PRAISE, qfalse );\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// just say something\n\tG_Voice( ent, NULL, SAY_ALL, VOICECHAT_TAUNT, qfalse );\n}\n\n\n\nstatic char\t*gc_orders[] = {\n\t\"hold your position\",\n\t\"hold this position\",\n\t\"come here\",\n\t\"cover me\",\n\t\"guard location\",\n\t\"search and destroy\",\n\t\"report\"\n};\n\nvoid Cmd_GameCommand_f( gentity_t *ent ) {\n\tint\t\tplayer;\n\tint\t\torder;\n\tchar\tstr[MAX_TOKEN_CHARS];\n\n\ttrap_Argv( 1, str, sizeof( str ) );\n\tplayer = atoi( str );\n\ttrap_Argv( 2, str, sizeof( str ) );\n\torder = atoi( str );\n\n\tif ( player < 0 || player >= MAX_CLIENTS ) {\n\t\treturn;\n\t}\n\tif ( order < 0 || order > sizeof(gc_orders)/sizeof(char *) ) {\n\t\treturn;\n\t}\n\tG_Say( ent, &g_entities[player], SAY_TELL, gc_orders[order] );\n\tG_Say( ent, ent, SAY_TELL, gc_orders[order] );\n}\n\n/*\n==================\nCmd_Where_f\n==================\n*/\nvoid Cmd_Where_f( gentity_t *ent ) {\n\ttrap_SendServerCommand( ent-g_entities, va(\"print \\\"%s\\n\\\"\", vtos( ent->s.origin ) ) );\n}\n\nstatic const char *gameNames[] = {\n\t\"Free For All\",\n\t\"Tournament\",\n\t\"Single Player\",\n\t\"Team Deathmatch\",\n\t\"Capture the Flag\",\n\t\"One Flag CTF\",\n\t\"Overload\",\n\t\"Harvester\"\n};\n\n/*\n==================\nCmd_CallVote_f\n==================\n*/\nvoid Cmd_CallVote_f( gentity_t *ent ) {\n\tint\t\ti;\n\tchar\targ1[MAX_STRING_TOKENS];\n\tchar\targ2[MAX_STRING_TOKENS];\n\n\tif ( !g_allowVote.integer ) {\n\t\ttrap_SendServerCommand( ent-g_entities, \"print \\\"Voting not allowed here.\\n\\\"\" );\n\t\treturn;\n\t}\n\n\tif ( level.voteTime ) {\n\t\ttrap_SendServerCommand( ent-g_entities, \"print \\\"A vote is already in progress.\\n\\\"\" );\n\t\treturn;\n\t}\n\tif ( ent->client->pers.voteCount >= MAX_VOTE_COUNT ) {\n\t\ttrap_SendServerCommand( ent-g_entities, \"print \\\"You have called the maximum number of votes.\\n\\\"\" );\n\t\treturn;\n\t}\n\tif ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) {\n\t\ttrap_SendServerCommand( ent-g_entities, \"print \\\"Not allowed to call a vote as spectator.\\n\\\"\" );\n\t\treturn;\n\t}\n\n\t// make sure it is a valid command to vote on\n\ttrap_Argv( 1, arg1, sizeof( arg1 ) );\n\ttrap_Argv( 2, arg2, sizeof( arg2 ) );\n\n\tif( strchr( arg1, ';' ) || strchr( arg2, ';' ) ) {\n\t\ttrap_SendServerCommand( ent-g_entities, \"print \\\"Invalid vote string.\\n\\\"\" );\n\t\treturn;\n\t}\n\n\tif ( !Q_stricmp( arg1, \"map_restart\" ) ) {\n\t} else if ( !Q_stricmp( arg1, \"nextmap\" ) ) {\n\t} else if ( !Q_stricmp( arg1, \"map\" ) ) {\n\t} else if ( !Q_stricmp( arg1, \"g_gametype\" ) ) {\n\t} else if ( !Q_stricmp( arg1, \"kick\" ) ) {\n\t} else if ( !Q_stricmp( arg1, \"clientkick\" ) ) {\n\t} else if ( !Q_stricmp( arg1, \"g_doWarmup\" ) ) {\n\t} else if ( !Q_stricmp( arg1, \"timelimit\" ) ) {\n\t} else if ( !Q_stricmp( arg1, \"fraglimit\" ) ) {\n\t} else {\n\t\ttrap_SendServerCommand( ent-g_entities, \"print \\\"Invalid vote string.\\n\\\"\" );\n\t\ttrap_SendServerCommand( ent-g_entities, \"print \\\"Vote commands are: map_restart, nextmap, map <mapname>, g_gametype <n>, kick <player>, clientkick <clientnum>, g_doWarmup, timelimit <time>, fraglimit <frags>.\\n\\\"\" );\n\t\treturn;\n\t}\n\n\t// if there is still a vote to be executed\n\tif ( level.voteExecuteTime ) {\n\t\tlevel.voteExecuteTime = 0;\n\t\ttrap_SendConsoleCommand( EXEC_APPEND, va(\"%s\\n\", level.voteString ) );\n\t}\n\n\t// special case for g_gametype, check for bad values\n\tif ( !Q_stricmp( arg1, \"g_gametype\" ) ) {\n\t\ti = atoi( arg2 );\n\t\tif( i == GT_SINGLE_PLAYER || i < GT_FFA || i >= GT_MAX_GAME_TYPE) {\n\t\t\ttrap_SendServerCommand( ent-g_entities, \"print \\\"Invalid gametype.\\n\\\"\" );\n\t\t\treturn;\n\t\t}\n\n\t\tCom_sprintf( level.voteString, sizeof( level.voteString ), \"%s %d\", arg1, i );\n\t\tCom_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), \"%s %s\", arg1, gameNames[i] );\n\t} else if ( !Q_stricmp( arg1, \"map\" ) ) {\n\t\t// special case for map changes, we want to reset the nextmap setting\n\t\t// this allows a player to change maps, but not upset the map rotation\n\t\tchar\ts[MAX_STRING_CHARS];\n\n\t\ttrap_Cvar_VariableStringBuffer( \"nextmap\", s, sizeof(s) );\n\t\tif (*s) {\n\t\t\tCom_sprintf( level.voteString, sizeof( level.voteString ), \"%s %s; set nextmap \\\"%s\\\"\", arg1, arg2, s );\n\t\t} else {\n\t\t\tCom_sprintf( level.voteString, sizeof( level.voteString ), \"%s %s\", arg1, arg2 );\n\t\t}\n\t\tCom_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), \"%s\", level.voteString );\n\t} else if ( !Q_stricmp( arg1, \"nextmap\" ) ) {\n\t\tchar\ts[MAX_STRING_CHARS];\n\n\t\ttrap_Cvar_VariableStringBuffer( \"nextmap\", s, sizeof(s) );\n\t\tif (!*s) {\n\t\t\ttrap_SendServerCommand( ent-g_entities, \"print \\\"nextmap not set.\\n\\\"\" );\n\t\t\treturn;\n\t\t}\n\t\tCom_sprintf( level.voteString, sizeof( level.voteString ), \"vstr nextmap\");\n\t\tCom_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), \"%s\", level.voteString );\n\t} else {\n\t\tCom_sprintf( level.voteString, sizeof( level.voteString ), \"%s \\\"%s\\\"\", arg1, arg2 );\n\t\tCom_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), \"%s\", level.voteString );\n\t}\n\n\ttrap_SendServerCommand( -1, va(\"print \\\"%s called a vote.\\n\\\"\", ent->client->pers.netname ) );\n\n\t// start the voting, the caller autoamtically votes yes\n\tlevel.voteTime = level.time;\n\tlevel.voteYes = 1;\n\tlevel.voteNo = 0;\n\n\tfor ( i = 0 ; i < level.maxclients ; i++ ) {\n\t\tlevel.clients[i].ps.eFlags &= ~EF_VOTED;\n\t}\n\tent->client->ps.eFlags |= EF_VOTED;\n\n\ttrap_SetConfigstring( CS_VOTE_TIME, va(\"%i\", level.voteTime ) );\n\ttrap_SetConfigstring( CS_VOTE_STRING, level.voteDisplayString );\t\n\ttrap_SetConfigstring( CS_VOTE_YES, va(\"%i\", level.voteYes ) );\n\ttrap_SetConfigstring( CS_VOTE_NO, va(\"%i\", level.voteNo ) );\t\n}\n\n/*\n==================\nCmd_Vote_f\n==================\n*/\nvoid Cmd_Vote_f( gentity_t *ent ) {\n\tchar\t\tmsg[64];\n\n\tif ( !level.voteTime ) {\n\t\ttrap_SendServerCommand( ent-g_entities, \"print \\\"No vote in progress.\\n\\\"\" );\n\t\treturn;\n\t}\n\tif ( ent->client->ps.eFlags & EF_VOTED ) {\n\t\ttrap_SendServerCommand( ent-g_entities, \"print \\\"Vote already cast.\\n\\\"\" );\n\t\treturn;\n\t}\n\tif ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) {\n\t\ttrap_SendServerCommand( ent-g_entities, \"print \\\"Not allowed to vote as spectator.\\n\\\"\" );\n\t\treturn;\n\t}\n\n\ttrap_SendServerCommand( ent-g_entities, \"print \\\"Vote cast.\\n\\\"\" );\n\n\tent->client->ps.eFlags |= EF_VOTED;\n\n\ttrap_Argv( 1, msg, sizeof( msg ) );\n\n\tif ( msg[0] == 'y' || msg[1] == 'Y' || msg[1] == '1' ) {\n\t\tlevel.voteYes++;\n\t\ttrap_SetConfigstring( CS_VOTE_YES, va(\"%i\", level.voteYes ) );\n\t} else {\n\t\tlevel.voteNo++;\n\t\ttrap_SetConfigstring( CS_VOTE_NO, va(\"%i\", level.voteNo ) );\t\n\t}\n\n\t// a majority will be determined in CheckVote, which will also account\n\t// for players entering or leaving\n}\n\n/*\n==================\nCmd_CallTeamVote_f\n==================\n*/\nvoid Cmd_CallTeamVote_f( gentity_t *ent ) {\n\tint\t\ti, team, cs_offset;\n\tchar\targ1[MAX_STRING_TOKENS];\n\tchar\targ2[MAX_STRING_TOKENS];\n\n\tteam = ent->client->sess.sessionTeam;\n\tif ( team == TEAM_RED )\n\t\tcs_offset = 0;\n\telse if ( team == TEAM_BLUE )\n\t\tcs_offset = 1;\n\telse\n\t\treturn;\n\n\tif ( !g_allowVote.integer ) {\n\t\ttrap_SendServerCommand( ent-g_entities, \"print \\\"Voting not allowed here.\\n\\\"\" );\n\t\treturn;\n\t}\n\n\tif ( level.teamVoteTime[cs_offset] ) {\n\t\ttrap_SendServerCommand( ent-g_entities, \"print \\\"A team vote is already in progress.\\n\\\"\" );\n\t\treturn;\n\t}\n\tif ( ent->client->pers.teamVoteCount >= MAX_VOTE_COUNT ) {\n\t\ttrap_SendServerCommand( ent-g_entities, \"print \\\"You have called the maximum number of team votes.\\n\\\"\" );\n\t\treturn;\n\t}\n\tif ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) {\n\t\ttrap_SendServerCommand( ent-g_entities, \"print \\\"Not allowed to call a vote as spectator.\\n\\\"\" );\n\t\treturn;\n\t}\n\n\t// make sure it is a valid command to vote on\n\ttrap_Argv( 1, arg1, sizeof( arg1 ) );\n\targ2[0] = '\\0';\n\tfor ( i = 2; i < trap_Argc(); i++ ) {\n\t\tif (i > 2)\n\t\t\tstrcat(arg2, \" \");\n\t\ttrap_Argv( i, &arg2[strlen(arg2)], sizeof( arg2 ) - (int)strlen(arg2) );\n\t}\n\n\tif( strchr( arg1, ';' ) || strchr( arg2, ';' ) ) {\n\t\ttrap_SendServerCommand( ent-g_entities, \"print \\\"Invalid vote string.\\n\\\"\" );\n\t\treturn;\n\t}\n\n\tif ( !Q_stricmp( arg1, \"leader\" ) ) {\n\t\tchar netname[MAX_NETNAME], leader[MAX_NETNAME];\n\n\t\tif ( !arg2[0] ) {\n\t\t\ti = ent->client->ps.clientNum;\n\t\t}\n\t\telse {\n\t\t\t// numeric values are just slot numbers\n\t\t\tfor (i = 0; i < 3; i++) {\n\t\t\t\tif ( !arg2[i] || arg2[i] < '0' || arg2[i] > '9' )\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( i >= 3 || !arg2[i]) {\n\t\t\t\ti = atoi( arg2 );\n\t\t\t\tif ( i < 0 || i >= level.maxclients ) {\n\t\t\t\t\ttrap_SendServerCommand( ent-g_entities, va(\"print \\\"Bad client slot: %i\\n\\\"\", i) );\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif ( !g_entities[i].inuse ) {\n\t\t\t\t\ttrap_SendServerCommand( ent-g_entities, va(\"print \\\"Client %i is not active\\n\\\"\", i) );\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tQ_strncpyz(leader, arg2, sizeof(leader));\n\t\t\t\tQ_CleanStr(leader);\n\t\t\t\tfor ( i = 0 ; i < level.maxclients ; i++ ) {\n\t\t\t\t\tif ( level.clients[i].pers.connected == CON_DISCONNECTED )\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif (level.clients[i].sess.sessionTeam != team)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tQ_strncpyz(netname, level.clients[i].pers.netname, sizeof(netname));\n\t\t\t\t\tQ_CleanStr(netname);\n\t\t\t\t\tif ( !Q_stricmp(netname, leader) ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif ( i >= level.maxclients ) {\n\t\t\t\t\ttrap_SendServerCommand( ent-g_entities, va(\"print \\\"%s is not a valid player on your team.\\n\\\"\", arg2) );\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tCom_sprintf(arg2, sizeof(arg2), \"%d\", i);\n\t} else {\n\t\ttrap_SendServerCommand( ent-g_entities, \"print \\\"Invalid vote string.\\n\\\"\" );\n\t\ttrap_SendServerCommand( ent-g_entities, \"print \\\"Team vote commands are: leader <player>.\\n\\\"\" );\n\t\treturn;\n\t}\n\n\tCom_sprintf( level.teamVoteString[cs_offset], sizeof( level.teamVoteString[cs_offset] ), \"%s %s\", arg1, arg2 );\n\n\tfor ( i = 0 ; i < level.maxclients ; i++ ) {\n\t\tif ( level.clients[i].pers.connected == CON_DISCONNECTED )\n\t\t\tcontinue;\n\t\tif (level.clients[i].sess.sessionTeam == team)\n\t\t\ttrap_SendServerCommand( i, va(\"print \\\"%s called a team vote.\\n\\\"\", ent->client->pers.netname ) );\n\t}\n\n\t// start the voting, the caller autoamtically votes yes\n\tlevel.teamVoteTime[cs_offset] = level.time;\n\tlevel.teamVoteYes[cs_offset] = 1;\n\tlevel.teamVoteNo[cs_offset] = 0;\n\n\tfor ( i = 0 ; i < level.maxclients ; i++ ) {\n\t\tif (level.clients[i].sess.sessionTeam == team)\n\t\t\tlevel.clients[i].ps.eFlags &= ~EF_TEAMVOTED;\n\t}\n\tent->client->ps.eFlags |= EF_TEAMVOTED;\n\n\ttrap_SetConfigstring( CS_TEAMVOTE_TIME + cs_offset, va(\"%i\", level.teamVoteTime[cs_offset] ) );\n\ttrap_SetConfigstring( CS_TEAMVOTE_STRING + cs_offset, level.teamVoteString[cs_offset] );\n\ttrap_SetConfigstring( CS_TEAMVOTE_YES + cs_offset, va(\"%i\", level.teamVoteYes[cs_offset] ) );\n\ttrap_SetConfigstring( CS_TEAMVOTE_NO + cs_offset, va(\"%i\", level.teamVoteNo[cs_offset] ) );\n}\n\n/*\n==================\nCmd_TeamVote_f\n==================\n*/\nvoid Cmd_TeamVote_f( gentity_t *ent ) {\n\tint\t\t\tteam, cs_offset;\n\tchar\t\tmsg[64];\n\n\tteam = ent->client->sess.sessionTeam;\n\tif ( team == TEAM_RED )\n\t\tcs_offset = 0;\n\telse if ( team == TEAM_BLUE )\n\t\tcs_offset = 1;\n\telse\n\t\treturn;\n\n\tif ( !level.teamVoteTime[cs_offset] ) {\n\t\ttrap_SendServerCommand( ent-g_entities, \"print \\\"No team vote in progress.\\n\\\"\" );\n\t\treturn;\n\t}\n\tif ( ent->client->ps.eFlags & EF_TEAMVOTED ) {\n\t\ttrap_SendServerCommand( ent-g_entities, \"print \\\"Team vote already cast.\\n\\\"\" );\n\t\treturn;\n\t}\n\tif ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) {\n\t\ttrap_SendServerCommand( ent-g_entities, \"print \\\"Not allowed to vote as spectator.\\n\\\"\" );\n\t\treturn;\n\t}\n\n\ttrap_SendServerCommand( ent-g_entities, \"print \\\"Team vote cast.\\n\\\"\" );\n\n\tent->client->ps.eFlags |= EF_TEAMVOTED;\n\n\ttrap_Argv( 1, msg, sizeof( msg ) );\n\n\tif ( msg[0] == 'y' || msg[1] == 'Y' || msg[1] == '1' ) {\n\t\tlevel.teamVoteYes[cs_offset]++;\n\t\ttrap_SetConfigstring( CS_TEAMVOTE_YES + cs_offset, va(\"%i\", level.teamVoteYes[cs_offset] ) );\n\t} else {\n\t\tlevel.teamVoteNo[cs_offset]++;\n\t\ttrap_SetConfigstring( CS_TEAMVOTE_NO + cs_offset, va(\"%i\", level.teamVoteNo[cs_offset] ) );\t\n\t}\n\n\t// a majority will be determined in TeamCheckVote, which will also account\n\t// for players entering or leaving\n}\n\n\n/*\n=================\nCmd_SetViewpos_f\n=================\n*/\nvoid Cmd_SetViewpos_f( gentity_t *ent ) {\n\tvec3_t\t\torigin, angles;\n\tchar\t\tbuffer[MAX_TOKEN_CHARS];\n\tint\t\t\ti;\n\n\tif ( !g_cheats.integer ) {\n\t\ttrap_SendServerCommand( ent-g_entities, va(\"print \\\"Cheats are not enabled on this server.\\n\\\"\"));\n\t\treturn;\n\t}\n\tif ( trap_Argc() != 5 ) {\n\t\ttrap_SendServerCommand( ent-g_entities, va(\"print \\\"usage: setviewpos x y z yaw\\n\\\"\"));\n\t\treturn;\n\t}\n\n\tVectorClear( angles );\n\tfor ( i = 0 ; i < 3 ; i++ ) {\n\t\ttrap_Argv( i + 1, buffer, sizeof( buffer ) );\n\t\torigin[i] = atof( buffer );\n\t}\n\n\ttrap_Argv( 4, buffer, sizeof( buffer ) );\n\tangles[YAW] = atof( buffer );\n\n\tTeleportPlayer( ent, origin, angles );\n}\n\n\n\n/*\n=================\nCmd_Stats_f\n=================\n*/\nvoid Cmd_Stats_f( gentity_t *ent ) {\n/*\n\tint max, n, i;\n\n\tmax = trap_AAS_PointReachabilityAreaIndex( NULL );\n\n\tn = 0;\n\tfor ( i = 0; i < max; i++ ) {\n\t\tif ( ent->client->areabits[i >> 3] & (1 << (i & 7)) )\n\t\t\tn++;\n\t}\n\n\t//trap_SendServerCommand( ent-g_entities, va(\"print \\\"visited %d of %d areas\\n\\\"\", n, max));\n\ttrap_SendServerCommand( ent-g_entities, va(\"print \\\"%d%% level coverage\\n\\\"\", n * 100 / max));\n*/\n}\n\n/*\n=================\nClientCommand\n=================\n*/\nvoid ClientCommand( int clientNum ) {\n\tgentity_t *ent;\n\tchar\tcmd[MAX_TOKEN_CHARS];\n\n\tent = g_entities + clientNum;\n\tif ( !ent->client ) {\n\t\treturn;\t\t// not fully in game yet\n\t}\n\n\n\ttrap_Argv( 0, cmd, sizeof( cmd ) );\n\n\tif (Q_stricmp (cmd, \"say\") == 0) {\n\t\tCmd_Say_f (ent, SAY_ALL, qfalse);\n\t\treturn;\n\t}\n\tif (Q_stricmp (cmd, \"say_team\") == 0) {\n\t\tCmd_Say_f (ent, SAY_TEAM, qfalse);\n\t\treturn;\n\t}\n\tif (Q_stricmp (cmd, \"tell\") == 0) {\n\t\tCmd_Tell_f ( ent );\n\t\treturn;\n\t}\n\tif (Q_stricmp (cmd, \"vsay\") == 0) {\n\t\tCmd_Voice_f (ent, SAY_ALL, qfalse, qfalse);\n\t\treturn;\n\t}\n\tif (Q_stricmp (cmd, \"vsay_team\") == 0) {\n\t\tCmd_Voice_f (ent, SAY_TEAM, qfalse, qfalse);\n\t\treturn;\n\t}\n\tif (Q_stricmp (cmd, \"vtell\") == 0) {\n\t\tCmd_VoiceTell_f ( ent, qfalse );\n\t\treturn;\n\t}\n\tif (Q_stricmp (cmd, \"vosay\") == 0) {\n\t\tCmd_Voice_f (ent, SAY_ALL, qfalse, qtrue);\n\t\treturn;\n\t}\n\tif (Q_stricmp (cmd, \"vosay_team\") == 0) {\n\t\tCmd_Voice_f (ent, SAY_TEAM, qfalse, qtrue);\n\t\treturn;\n\t}\n\tif (Q_stricmp (cmd, \"votell\") == 0) {\n\t\tCmd_VoiceTell_f ( ent, qtrue );\n\t\treturn;\n\t}\n\tif (Q_stricmp (cmd, \"vtaunt\") == 0) {\n\t\tCmd_VoiceTaunt_f ( ent );\n\t\treturn;\n\t}\n\tif (Q_stricmp (cmd, \"score\") == 0) {\n\t\tCmd_Score_f (ent);\n\t\treturn;\n\t}\n\n\t// ignore all other commands when at intermission\n\tif (level.intermissiontime) {\n\t\tCmd_Say_f (ent, qfalse, qtrue);\n\t\treturn;\n\t}\n\n\tif (Q_stricmp (cmd, \"give\") == 0)\n\t\tCmd_Give_f (ent);\n\telse if (Q_stricmp (cmd, \"god\") == 0)\n\t\tCmd_God_f (ent);\n\telse if (Q_stricmp (cmd, \"notarget\") == 0)\n\t\tCmd_Notarget_f (ent);\n\telse if (Q_stricmp (cmd, \"noclip\") == 0)\n\t\tCmd_Noclip_f (ent);\n\telse if (Q_stricmp (cmd, \"kill\") == 0)\n\t\tCmd_Kill_f (ent);\n\telse if (Q_stricmp (cmd, \"teamtask\") == 0)\n\t\tCmd_TeamTask_f (ent);\n\telse if (Q_stricmp (cmd, \"levelshot\") == 0)\n\t\tCmd_LevelShot_f (ent);\n\telse if (Q_stricmp (cmd, \"follow\") == 0)\n\t\tCmd_Follow_f (ent);\n\telse if (Q_stricmp (cmd, \"follownext\") == 0)\n\t\tCmd_FollowCycle_f (ent, 1);\n\telse if (Q_stricmp (cmd, \"followprev\") == 0)\n\t\tCmd_FollowCycle_f (ent, -1);\n\telse if (Q_stricmp (cmd, \"team\") == 0)\n\t\tCmd_Team_f (ent);\n\telse if (Q_stricmp (cmd, \"where\") == 0)\n\t\tCmd_Where_f (ent);\n\telse if (Q_stricmp (cmd, \"callvote\") == 0)\n\t\tCmd_CallVote_f (ent);\n\telse if (Q_stricmp (cmd, \"vote\") == 0)\n\t\tCmd_Vote_f (ent);\n\telse if (Q_stricmp (cmd, \"callteamvote\") == 0)\n\t\tCmd_CallTeamVote_f (ent);\n\telse if (Q_stricmp (cmd, \"teamvote\") == 0)\n\t\tCmd_TeamVote_f (ent);\n\telse if (Q_stricmp (cmd, \"gc\") == 0)\n\t\tCmd_GameCommand_f( ent );\n\telse if (Q_stricmp (cmd, \"setviewpos\") == 0)\n\t\tCmd_SetViewpos_f( ent );\n\telse if (Q_stricmp (cmd, \"stats\") == 0)\n\t\tCmd_Stats_f( ent );\n\telse\n\t\ttrap_SendServerCommand( clientNum, va(\"print \\\"unknown cmd %s\\n\\\"\", cmd ) );\n}\n"
  },
  {
    "path": "src/game/g_combat.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n// g_combat.c\n\n#include \"g_local.h\"\n\n\n/*\n============\nScorePlum\n============\n*/\nvoid ScorePlum( gentity_t *ent, vec3_t origin, int score ) {\n\tgentity_t *plum;\n\n\tplum = G_TempEntity( origin, EV_SCOREPLUM );\n\t// only send this temp entity to a single client\n\tplum->r.svFlags |= SVF_SINGLECLIENT;\n\tplum->r.singleClient = ent->s.number;\n\t//\n\tplum->s.otherEntityNum = ent->s.number;\n\tplum->s.time = score;\n}\n\n/*\n============\nAddScore\n\nAdds score to both the client and his team\n============\n*/\nvoid AddScore( gentity_t *ent, vec3_t origin, int score ) {\n\tif ( !ent->client ) {\n\t\treturn;\n\t}\n\t// no scoring during pre-match warmup\n\tif ( level.warmupTime ) {\n\t\treturn;\n\t}\n\t// show score plum\n\tScorePlum(ent, origin, score);\n\t//\n\tent->client->ps.persistant[PERS_SCORE] += score;\n\tif ( g_gametype.integer == GT_TEAM )\n\t\tlevel.teamScores[ ent->client->ps.persistant[PERS_TEAM] ] += score;\n\tCalculateRanks();\n}\n\n/*\n=================\nTossClientItems\n\nToss the weapon and powerups for the killed player\n=================\n*/\nvoid TossClientItems( gentity_t *self ) {\n\tgitem_t\t\t*item;\n\tint\t\t\tweapon;\n\tfloat\t\tangle;\n\tint\t\t\ti;\n\tgentity_t\t*drop;\n\n\t// drop the weapon if not a gauntlet or machinegun\n\tweapon = self->s.weapon;\n\n\t// make a special check to see if they are changing to a new\n\t// weapon that isn't the mg or gauntlet.  Without this, a client\n\t// can pick up a weapon, be killed, and not drop the weapon because\n\t// their weapon change hasn't completed yet and they are still holding the MG.\n\tif ( weapon == WP_MACHINEGUN || weapon == WP_GRAPPLING_HOOK ) {\n\t\tif ( self->client->ps.weaponstate == WEAPON_DROPPING ) {\n\t\t\tweapon = self->client->pers.cmd.weapon;\n\t\t}\n\t\tif ( !( self->client->ps.stats[STAT_WEAPONS] & ( 1 << weapon ) ) ) {\n\t\t\tweapon = WP_NONE;\n\t\t}\n\t}\n\n\tif ( weapon > WP_MACHINEGUN && weapon != WP_GRAPPLING_HOOK && \n\t\tself->client->ps.ammo[ weapon ] ) {\n\t\t// find the item type for this weapon\n\t\titem = BG_FindItemForWeapon( weapon );\n\n\t\t// spawn the item\n\t\tDrop_Item( self, item, 0 );\n\t}\n\n\t// drop all the powerups if not in teamplay\n\tif ( g_gametype.integer != GT_TEAM ) {\n\t\tangle = 45;\n\t\tfor ( i = 1 ; i < PW_NUM_POWERUPS ; i++ ) {\n\t\t\tif ( self->client->ps.powerups[ i ] > level.time ) {\n\t\t\t\titem = BG_FindItemForPowerup( i );\n\t\t\t\tif ( !item ) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tdrop = Drop_Item( self, item, angle );\n\t\t\t\t// decide how many seconds it has left\n\t\t\t\tdrop->count = ( self->client->ps.powerups[ i ] - level.time ) / 1000;\n\t\t\t\tif ( drop->count < 1 ) {\n\t\t\t\t\tdrop->count = 1;\n\t\t\t\t}\n\t\t\t\tangle += 45;\n\t\t\t}\n\t\t}\n\t}\n}\n\n/*\n==================\nLookAtKiller\n==================\n*/\nvoid LookAtKiller( gentity_t *self, gentity_t *inflictor, gentity_t *attacker ) {\n\tvec3_t\t\tdir;\n\tvec3_t\t\tangles;\n\n\tif ( attacker && attacker != self ) {\n\t\tVectorSubtract (attacker->s.pos.trBase, self->s.pos.trBase, dir);\n\t} else if ( inflictor && inflictor != self ) {\n\t\tVectorSubtract (inflictor->s.pos.trBase, self->s.pos.trBase, dir);\n\t} else {\n\t\tself->client->ps.stats[STAT_DEAD_YAW] = self->s.angles[YAW];\n\t\treturn;\n\t}\n\n\tself->client->ps.stats[STAT_DEAD_YAW] = vectoyaw ( dir );\n\n\tangles[YAW] = vectoyaw ( dir );\n\tangles[PITCH] = 0; \n\tangles[ROLL] = 0;\n}\n\n/*\n==================\nGibEntity\n==================\n*/\nvoid GibEntity( gentity_t *self, int killer ) {\n\tgentity_t *ent;\n\tint i;\n\n\t//if this entity still has kamikaze\n\tif (self->s.eFlags & EF_KAMIKAZE) {\n\t\t// check if there is a kamikaze timer around for this owner\n\t\tfor (i = 0; i < MAX_GENTITIES; i++) {\n\t\t\tent = &g_entities[i];\n\t\t\tif (!ent->inuse)\n\t\t\t\tcontinue;\n\t\t\tif (ent->activator != self)\n\t\t\t\tcontinue;\n\t\t\tif (strcmp(ent->classname, \"kamikaze timer\"))\n\t\t\t\tcontinue;\n\t\t\tG_FreeEntity(ent);\n\t\t\tbreak;\n\t\t}\n\t}\n\tG_AddEvent( self, EV_GIB_PLAYER, killer );\n\tself->takedamage = qfalse;\n\tself->s.eType = ET_INVISIBLE;\n\tself->r.contents = 0;\n}\n\n/*\n==================\nbody_die\n==================\n*/\nvoid body_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath ) {\n\tif ( self->health > GIB_HEALTH ) {\n\t\treturn;\n\t}\n\tif ( !g_blood.integer ) {\n\t\tself->health = GIB_HEALTH+1;\n\t\treturn;\n\t}\n\n\tGibEntity( self, 0 );\n}\n\n\n// these are just for logging, the client prints its own messages\nchar\t*modNames[] = {\n\t\"MOD_UNKNOWN\",\n\t\"MOD_SHOTGUN\",\n\t\"MOD_GAUNTLET\",\n\t\"MOD_MACHINEGUN\",\n\t\"MOD_GRENADE\",\n\t\"MOD_GRENADE_SPLASH\",\n\t\"MOD_ROCKET\",\n\t\"MOD_ROCKET_SPLASH\",\n\t\"MOD_PLASMA\",\n\t\"MOD_PLASMA_SPLASH\",\n\t\"MOD_RAILGUN\",\n\t\"MOD_LIGHTNING\",\n\t\"MOD_BFG\",\n\t\"MOD_BFG_SPLASH\",\n\t\"MOD_WATER\",\n\t\"MOD_SLIME\",\n\t\"MOD_LAVA\",\n\t\"MOD_CRUSH\",\n\t\"MOD_TELEFRAG\",\n\t\"MOD_FALLING\",\n\t\"MOD_SUICIDE\",\n\t\"MOD_TARGET_LASER\",\n\t\"MOD_TRIGGER_HURT\",\n\t\"MOD_GRAPPLE\"\n};\n\n/*\n==================\nCheckAlmostCapture\n==================\n*/\nvoid CheckAlmostCapture( gentity_t *self, gentity_t *attacker ) {\n\tgentity_t\t*ent;\n\tvec3_t\t\tdir;\n\tchar\t\t*classname;\n\n\t// if this player was carrying a flag\n\tif ( self->client->ps.powerups[PW_REDFLAG] ||\n\t\tself->client->ps.powerups[PW_BLUEFLAG] ||\n\t\tself->client->ps.powerups[PW_NEUTRALFLAG] ) {\n\t\t// get the goal flag this player should have been going for\n\t\tif ( g_gametype.integer == GT_CTF ) {\n\t\t\tif ( self->client->sess.sessionTeam == TEAM_BLUE ) {\n\t\t\t\tclassname = \"team_CTF_blueflag\";\n\t\t\t}\n\t\t\telse {\n\t\t\t\tclassname = \"team_CTF_redflag\";\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tif ( self->client->sess.sessionTeam == TEAM_BLUE ) {\n\t\t\t\tclassname = \"team_CTF_redflag\";\n\t\t\t}\n\t\t\telse {\n\t\t\t\tclassname = \"team_CTF_blueflag\";\n\t\t\t}\n\t\t}\n\t\tent = NULL;\n\t\tdo\n\t\t{\n\t\t\tent = G_Find(ent, FOFS(classname), classname);\n\t\t} while (ent && (ent->flags & FL_DROPPED_ITEM));\n\t\t// if we found the destination flag and it's not picked up\n\t\tif (ent && !(ent->r.svFlags & SVF_NOCLIENT) ) {\n\t\t\t// if the player was *very* close\n\t\t\tVectorSubtract( self->client->ps.origin, ent->s.origin, dir );\n\t\t\tif ( VectorLength(dir) < 200 ) {\n\t\t\t\tself->client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_HOLYSHIT;\n\t\t\t\tif ( attacker->client ) {\n\t\t\t\t\tattacker->client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_HOLYSHIT;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n/*\n==================\nCheckAlmostScored\n==================\n*/\nvoid CheckAlmostScored( gentity_t *self, gentity_t *attacker ) {\n\tgentity_t\t*ent;\n\tvec3_t\t\tdir;\n\tchar\t\t*classname;\n\n\t// if the player was carrying cubes\n\tif ( self->client->ps.generic1 ) {\n\t\tif ( self->client->sess.sessionTeam == TEAM_BLUE ) {\n\t\t\tclassname = \"team_redobelisk\";\n\t\t}\n\t\telse {\n\t\t\tclassname = \"team_blueobelisk\";\n\t\t}\n\t\tent = G_Find(NULL, FOFS(classname), classname);\n\t\t// if we found the destination obelisk\n\t\tif ( ent ) {\n\t\t\t// if the player was *very* close\n\t\t\tVectorSubtract( self->client->ps.origin, ent->s.origin, dir );\n\t\t\tif ( VectorLength(dir) < 200 ) {\n\t\t\t\tself->client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_HOLYSHIT;\n\t\t\t\tif ( attacker->client ) {\n\t\t\t\t\tattacker->client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_HOLYSHIT;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n/*\n==================\nplayer_die\n==================\n*/\nvoid player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath ) {\n\tgentity_t\t*ent;\n\tint\t\t\tanim;\n\tint\t\t\tcontents;\n\tint\t\t\tkiller;\n\tint\t\t\ti;\n\tchar\t\t*killerName, *obit;\n\n\tif ( self->client->ps.pm_type == PM_DEAD ) {\n\t\treturn;\n\t}\n\n\tif ( level.intermissiontime ) {\n\t\treturn;\n\t}\n\n\t// check for an almost capture\n\tCheckAlmostCapture( self, attacker );\n\t// check for a player that almost brought in cubes\n\tCheckAlmostScored( self, attacker );\n\n\tif (self->client && self->client->hook) {\n\t\tWeapon_HookFree(self->client->hook);\n\t}\n\tself->client->ps.pm_type = PM_DEAD;\n\n\tif ( attacker ) {\n\t\tkiller = attacker->s.number;\n\t\tif ( attacker->client ) {\n\t\t\tkillerName = attacker->client->pers.netname;\n\t\t} else {\n\t\t\tkillerName = \"<non-client>\";\n\t\t}\n\t} else {\n\t\tkiller = ENTITYNUM_WORLD;\n\t\tkillerName = \"<world>\";\n\t}\n\n\tif ( killer < 0 || killer >= MAX_CLIENTS ) {\n\t\tkiller = ENTITYNUM_WORLD;\n\t\tkillerName = \"<world>\";\n\t}\n\n\tif ( meansOfDeath < 0 || meansOfDeath >= sizeof( modNames ) / sizeof( modNames[0] ) ) {\n\t\tobit = \"<bad obituary>\";\n\t} else {\n\t\tobit = modNames[ meansOfDeath ];\n\t}\n\n\tG_LogPrintf(\"Kill: %i %i %i: %s killed %s by %s\\n\", \n\t\tkiller, self->s.number, meansOfDeath, killerName, \n\t\tself->client->pers.netname, obit );\n\n\t// broadcast the death event to everyone\n\tent = G_TempEntity( self->r.currentOrigin, EV_OBITUARY );\n\tent->s.eventParm = meansOfDeath;\n\tent->s.otherEntityNum = self->s.number;\n\tent->s.otherEntityNum2 = killer;\n\tent->r.svFlags = SVF_BROADCAST;\t// send to everyone\n\n\tself->enemy = attacker;\n\n\tself->client->ps.persistant[PERS_KILLED]++;\n\n\tif (attacker && attacker->client) {\n\t\tattacker->client->lastkilled_client = self->s.number;\n\n\t\tif ( attacker == self || OnSameTeam (self, attacker ) ) {\n\t\t\tAddScore( attacker, self->r.currentOrigin, -1 );\n\t\t} else {\n\t\t\tAddScore( attacker, self->r.currentOrigin, 1 );\n\n\t\t\tif( meansOfDeath == MOD_GAUNTLET ) {\n\t\t\t\t\n\t\t\t\t// play humiliation on player\n\t\t\t\tattacker->client->ps.persistant[PERS_GAUNTLET_FRAG_COUNT]++;\n\n\t\t\t\t// add the sprite over the player's head\n\t\t\t\tattacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );\n\t\t\t\tattacker->client->ps.eFlags |= EF_AWARD_GAUNTLET;\n\t\t\t\tattacker->client->rewardTime = level.time + REWARD_SPRITE_TIME;\n\n\t\t\t\t// also play humiliation on target\n\t\t\t\tself->client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_GAUNTLETREWARD;\n\t\t\t}\n\n\t\t\t// check for two kills in a short amount of time\n\t\t\t// if this is close enough to the last kill, give a reward sound\n\t\t\tif ( level.time - attacker->client->lastKillTime < CARNAGE_REWARD_TIME ) {\n\t\t\t\t// play excellent on player\n\t\t\t\tattacker->client->ps.persistant[PERS_EXCELLENT_COUNT]++;\n\n\t\t\t\t// add the sprite over the player's head\n\t\t\t\tattacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );\n\t\t\t\tattacker->client->ps.eFlags |= EF_AWARD_EXCELLENT;\n\t\t\t\tattacker->client->rewardTime = level.time + REWARD_SPRITE_TIME;\n\t\t\t}\n\t\t\tattacker->client->lastKillTime = level.time;\n\n\t\t}\n\t} else {\n\t\tAddScore( self, self->r.currentOrigin, -1 );\n\t}\n\n\t// Add team bonuses\n\tTeam_FragBonuses(self, inflictor, attacker);\n\n\t// if I committed suicide, the flag does not fall, it returns.\n\tif (meansOfDeath == MOD_SUICIDE) {\n\t\tif ( self->client->ps.powerups[PW_NEUTRALFLAG] ) {\t\t// only happens in One Flag CTF\n\t\t\tTeam_ReturnFlag( TEAM_FREE );\n\t\t\tself->client->ps.powerups[PW_NEUTRALFLAG] = 0;\n\t\t}\n\t\telse if ( self->client->ps.powerups[PW_REDFLAG] ) {\t\t// only happens in standard CTF\n\t\t\tTeam_ReturnFlag( TEAM_RED );\n\t\t\tself->client->ps.powerups[PW_REDFLAG] = 0;\n\t\t}\n\t\telse if ( self->client->ps.powerups[PW_BLUEFLAG] ) {\t// only happens in standard CTF\n\t\t\tTeam_ReturnFlag( TEAM_BLUE );\n\t\t\tself->client->ps.powerups[PW_BLUEFLAG] = 0;\n\t\t}\n\t}\n\n\t// if client is in a nodrop area, don't drop anything (but return CTF flags!)\n\tcontents = trap_PointContents( self->r.currentOrigin, -1 );\n\tif ( !( contents & CONTENTS_NODROP )) {\n\t\tTossClientItems( self );\n\t}\n\telse {\n\t\tif ( self->client->ps.powerups[PW_NEUTRALFLAG] ) {\t\t// only happens in One Flag CTF\n\t\t\tTeam_ReturnFlag( TEAM_FREE );\n\t\t}\n\t\telse if ( self->client->ps.powerups[PW_REDFLAG] ) {\t\t// only happens in standard CTF\n\t\t\tTeam_ReturnFlag( TEAM_RED );\n\t\t}\n\t\telse if ( self->client->ps.powerups[PW_BLUEFLAG] ) {\t// only happens in standard CTF\n\t\t\tTeam_ReturnFlag( TEAM_BLUE );\n\t\t}\n\t}\n\n\tCmd_Score_f( self );\t\t// show scores\n\t// send updated scores to any clients that are following this one,\n\t// or they would get stale scoreboards\n\tfor ( i = 0 ; i < level.maxclients ; i++ ) {\n\t\tgclient_t\t*client;\n\n\t\tclient = &level.clients[i];\n\t\tif ( client->pers.connected != CON_CONNECTED ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( client->sess.sessionTeam != TEAM_SPECTATOR ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( client->sess.spectatorClient == self->s.number ) {\n\t\t\tCmd_Score_f( g_entities + i );\n\t\t}\n\t}\n\n\tself->takedamage = qtrue;\t// can still be gibbed\n\n\tself->s.weapon = WP_NONE;\n\tself->s.powerups = 0;\n\tself->r.contents = CONTENTS_CORPSE;\n\n\tself->s.angles[0] = 0;\n\tself->s.angles[2] = 0;\n\tLookAtKiller (self, inflictor, attacker);\n\n\tVectorCopy( self->s.angles, self->client->ps.viewangles );\n\n\tself->s.loopSound = 0;\n\n\tself->r.maxs[2] = -8;\n\n\t// don't allow respawn until the death anim is done\n\t// g_forcerespawn may force spawning at some later time\n\tself->client->respawnTime = level.time + 1700;\n\n\t// remove powerups\n\tmemset( self->client->ps.powerups, 0, sizeof(self->client->ps.powerups) );\n\n\t// never gib in a nodrop\n\tif ( (self->health <= GIB_HEALTH && !(contents & CONTENTS_NODROP) && g_blood.integer) || meansOfDeath == MOD_SUICIDE) {\n\t\t// gib death\n\t\tGibEntity( self, killer );\n\t} else {\n\t\t// normal death\n\t\tstatic int i;\n\n\t\tswitch ( i ) {\n\t\tcase 0:\n\t\t\tanim = BOTH_DEATH1;\n\t\t\tbreak;\n\t\tcase 1:\n\t\t\tanim = BOTH_DEATH2;\n\t\t\tbreak;\n\t\tcase 2:\n\t\tdefault:\n\t\t\tanim = BOTH_DEATH3;\n\t\t\tbreak;\n\t\t}\n\n\t\t// for the no-blood option, we need to prevent the health\n\t\t// from going to gib level\n\t\tif ( self->health <= GIB_HEALTH ) {\n\t\t\tself->health = GIB_HEALTH+1;\n\t\t}\n\n\t\tself->client->ps.legsAnim = \n\t\t\t( ( self->client->ps.legsAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;\n\t\tself->client->ps.torsoAnim = \n\t\t\t( ( self->client->ps.torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;\n\n\t\tG_AddEvent( self, EV_DEATH1 + i, killer );\n\n\t\t// the body can still be gibbed\n\t\tself->die = body_die;\n\n\t\t// globally cycle through the different death animations\n\t\ti = ( i + 1 ) % 3;\n\n\t}\n\n\ttrap_LinkEntity (self);\n\n}\n\n\n/*\n================\nCheckArmor\n================\n*/\nint CheckArmor (gentity_t *ent, int damage, int dflags)\n{\n\tgclient_t\t*client;\n\tint\t\t\tsave;\n\tint\t\t\tcount;\n\n\tif (!damage)\n\t\treturn 0;\n\n\tclient = ent->client;\n\n\tif (!client)\n\t\treturn 0;\n\n\tif (dflags & DAMAGE_NO_ARMOR)\n\t\treturn 0;\n\n\t// armor\n\tcount = client->ps.stats[STAT_ARMOR];\n\tsave = ceil( damage * ARMOR_PROTECTION );\n\tif (save >= count)\n\t\tsave = count;\n\n\tif (!save)\n\t\treturn 0;\n\n\tclient->ps.stats[STAT_ARMOR] -= save;\n\n\treturn save;\n}\n\n/*\n================\nRaySphereIntersections\n================\n*/\nint RaySphereIntersections( vec3_t origin, float radius, vec3_t point, vec3_t dir, vec3_t intersections[2] ) {\n\tfloat b, c, d, t;\n\n\t//\t| origin - (point + t * dir) | = radius\n\t//\ta = dir[0]^2 + dir[1]^2 + dir[2]^2;\n\t//\tb = 2 * (dir[0] * (point[0] - origin[0]) + dir[1] * (point[1] - origin[1]) + dir[2] * (point[2] - origin[2]));\n\t//\tc = (point[0] - origin[0])^2 + (point[1] - origin[1])^2 + (point[2] - origin[2])^2 - radius^2;\n\n\t// normalize dir so a = 1\n\tVectorNormalize(dir);\n\tb = 2 * (dir[0] * (point[0] - origin[0]) + dir[1] * (point[1] - origin[1]) + dir[2] * (point[2] - origin[2]));\n\tc = (point[0] - origin[0]) * (point[0] - origin[0]) +\n\t\t(point[1] - origin[1]) * (point[1] - origin[1]) +\n\t\t(point[2] - origin[2]) * (point[2] - origin[2]) -\n\t\tradius * radius;\n\n\td = b * b - 4 * c;\n\tif (d > 0) {\n\t\tt = (- b + sqrt(d)) / 2;\n\t\tVectorMA(point, t, dir, intersections[0]);\n\t\tt = (- b - sqrt(d)) / 2;\n\t\tVectorMA(point, t, dir, intersections[1]);\n\t\treturn 2;\n\t}\n\telse if (d == 0) {\n\t\tt = (- b ) / 2;\n\t\tVectorMA(point, t, dir, intersections[0]);\n\t\treturn 1;\n\t}\n\treturn 0;\n}\n\n/*\n============\nT_Damage\n\ntarg\t\tentity that is being damaged\ninflictor\tentity that is causing the damage\nattacker\tentity that caused the inflictor to damage targ\n\texample: targ=monster, inflictor=rocket, attacker=player\n\ndir\t\t\tdirection of the attack for knockback\npoint\t\tpoint at which the damage is being inflicted, used for headshots\ndamage\t\tamount of damage being inflicted\nknockback\tforce to be applied against targ as a result of the damage\n\ninflictor, attacker, dir, and point can be NULL for environmental effects\n\ndflags\t\tthese flags are used to control how T_Damage works\n\tDAMAGE_RADIUS\t\t\tdamage was indirect (from a nearby explosion)\n\tDAMAGE_NO_ARMOR\t\t\tarmor does not protect from this damage\n\tDAMAGE_NO_KNOCKBACK\t\tdo not affect velocity, just view angles\n\tDAMAGE_NO_PROTECTION\tkills godmode, armor, everything\n============\n*/\n\nvoid G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker,\n\t\t\t   vec3_t dir, vec3_t point, int damage, int dflags, int mod ) {\n\tgclient_t\t*client;\n\tint\t\t\ttake;\n\tint\t\t\tsave;\n\tint\t\t\tasave;\n\tint\t\t\tknockback;\n\tint\t\t\tmax;\n\n\tif (!targ->takedamage) {\n\t\treturn;\n\t}\n\n\t// the intermission has allready been qualified for, so don't\n\t// allow any extra scoring\n\tif ( level.intermissionQueued ) {\n\t\treturn;\n\t}\n\tif ( !inflictor ) {\n\t\tinflictor = &g_entities[ENTITYNUM_WORLD];\n\t}\n\tif ( !attacker ) {\n\t\tattacker = &g_entities[ENTITYNUM_WORLD];\n\t}\n\n\t// shootable doors / buttons don't actually have any health\n\tif ( targ->s.eType == ET_MOVER ) {\n\t\tif ( targ->use && targ->moverState == MOVER_POS1 ) {\n\t\t\ttarg->use( targ, inflictor, attacker );\n\t\t}\n\t\treturn;\n\t}\n\t// reduce damage by the attacker's handicap value\n\t// unless they are rocket jumping\n\tif ( attacker->client && attacker != targ ) {\n\t\tmax = attacker->client->ps.stats[STAT_MAX_HEALTH];\n\t\tdamage = damage * max / 100;\n\t}\n\n\tclient = targ->client;\n\n\tif ( client ) {\n\t\tif ( client->noclip ) {\n\t\t\treturn;\n\t\t}\n\t}\n\n\tif ( !dir ) {\n\t\tdflags |= DAMAGE_NO_KNOCKBACK;\n\t} else {\n\t\tVectorNormalize(dir);\n\t}\n\n\tknockback = damage;\n\tif ( knockback > 200 ) {\n\t\tknockback = 200;\n\t}\n\tif ( targ->flags & FL_NO_KNOCKBACK ) {\n\t\tknockback = 0;\n\t}\n\tif ( dflags & DAMAGE_NO_KNOCKBACK ) {\n\t\tknockback = 0;\n\t}\n\n\t// figure momentum add, even if the damage won't be taken\n\tif ( knockback && targ->client ) {\n\t\tvec3_t\tkvel;\n\t\tfloat\tmass;\n\n\t\tmass = 200;\n\n\t\tVectorScale (dir, g_knockback.value * (float)knockback / mass, kvel);\n\t\tVectorAdd (targ->client->ps.velocity, kvel, targ->client->ps.velocity);\n\n\t\t// set the timer so that the other client can't cancel\n\t\t// out the movement immediately\n\t\tif ( !targ->client->ps.pm_time ) {\n\t\t\tint\t\tt;\n\n\t\t\tt = knockback * 2;\n\t\t\tif ( t < 50 ) {\n\t\t\t\tt = 50;\n\t\t\t}\n\t\t\tif ( t > 200 ) {\n\t\t\t\tt = 200;\n\t\t\t}\n\t\t\ttarg->client->ps.pm_time = t;\n\t\t\ttarg->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;\n\t\t}\n\t}\n\n\t// check for completely getting out of the damage\n\tif ( !(dflags & DAMAGE_NO_PROTECTION) ) {\n\n\t\t// if TF_NO_FRIENDLY_FIRE is set, don't do damage to the target\n\t\t// if the attacker was on the same team\n\t\tif ( targ != attacker && OnSameTeam (targ, attacker)  ) {\n\t\t\tif ( !g_friendlyFire.integer ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\t// check for godmode\n\t\tif ( targ->flags & FL_GODMODE ) {\n\t\t\treturn;\n\t\t}\n\t}\n\n\t// battlesuit protects from all radius damage (but takes knockback)\n\t// and protects 50% against all damage\n\tif ( client && client->ps.powerups[PW_BATTLESUIT] ) {\n\t\tG_AddEvent( targ, EV_POWERUP_BATTLESUIT, 0 );\n\t\tif ( ( dflags & DAMAGE_RADIUS ) || ( mod == MOD_FALLING ) ) {\n\t\t\treturn;\n\t\t}\n\t\tdamage *= 0.5;\n\t}\n\n\t// add to the attacker's hit counter (if the target isn't a general entity like a prox mine)\n\tif ( attacker->client && targ != attacker && targ->health > 0\n\t\t\t&& targ->s.eType != ET_MISSILE\n\t\t\t&& targ->s.eType != ET_GENERAL) {\n\t\tif ( OnSameTeam( targ, attacker ) ) {\n\t\t\tattacker->client->ps.persistant[PERS_HITS]--;\n\t\t} else {\n\t\t\tattacker->client->ps.persistant[PERS_HITS]++;\n\t\t}\n\t\tattacker->client->ps.persistant[PERS_ATTACKEE_ARMOR] = (targ->health<<8)|(client->ps.stats[STAT_ARMOR]);\n\t}\n\n\t// always give half damage if hurting self\n\t// calculated after knockback, so rocket jumping works\n\tif ( targ == attacker) {\n\t\tdamage *= 0.5;\n\t}\n\n\tif ( damage < 1 ) {\n\t\tdamage = 1;\n\t}\n\ttake = damage;\n\tsave = 0;\n\n\t// save some from armor\n\tasave = CheckArmor (targ, take, dflags);\n\ttake -= asave;\n\n\tif ( g_debugDamage.integer ) {\n\t\tG_Printf( \"%i: client:%i health:%i damage:%i armor:%i\\n\", level.time, targ->s.number,\n\t\t\ttarg->health, take, asave );\n\t}\n\n\t// add to the damage inflicted on a player this frame\n\t// the total will be turned into screen blends and view angle kicks\n\t// at the end of the frame\n\tif ( client ) {\n\t\tif ( attacker ) {\n\t\t\tclient->ps.persistant[PERS_ATTACKER] = attacker->s.number;\n\t\t} else {\n\t\t\tclient->ps.persistant[PERS_ATTACKER] = ENTITYNUM_WORLD;\n\t\t}\n\t\tclient->damage_armor += asave;\n\t\tclient->damage_blood += take;\n\t\tclient->damage_knockback += knockback;\n\t\tif ( dir ) {\n\t\t\tVectorCopy ( dir, client->damage_from );\n\t\t\tclient->damage_fromWorld = qfalse;\n\t\t} else {\n\t\t\tVectorCopy ( targ->r.currentOrigin, client->damage_from );\n\t\t\tclient->damage_fromWorld = qtrue;\n\t\t}\n\t}\n\n\t// See if it's the player hurting the emeny flag carrier\n\tif( g_gametype.integer == GT_CTF) {\n\t\tTeam_CheckHurtCarrier(targ, attacker);\n\t}\n\n\tif (targ->client) {\n\t\t// set the last client who damaged the target\n\t\ttarg->client->lasthurt_client = attacker->s.number;\n\t\ttarg->client->lasthurt_mod = mod;\n\t}\n\n\t// do the damage\n\tif (take) {\n\t\ttarg->health = targ->health - take;\n\t\tif ( targ->client ) {\n\t\t\ttarg->client->ps.stats[STAT_HEALTH] = targ->health;\n\t\t}\n\t\t\t\n\t\tif ( targ->health <= 0 ) {\n\t\t\tif ( client )\n\t\t\t\ttarg->flags |= FL_NO_KNOCKBACK;\n\n\t\t\tif (targ->health < -999)\n\t\t\t\ttarg->health = -999;\n\n\t\t\ttarg->enemy = attacker;\n\t\t\ttarg->die (targ, inflictor, attacker, take, mod);\n\t\t\treturn;\n\t\t} else if ( targ->pain ) {\n\t\t\ttarg->pain (targ, attacker, take);\n\t\t}\n\t}\n\n}\n\n\n/*\n============\nCanDamage\n\nReturns qtrue if the inflictor can directly damage the target.  Used for\nexplosions and melee attacks.\n============\n*/\nqboolean CanDamage (gentity_t *targ, vec3_t origin) {\n\tvec3_t\tdest;\n\ttrace_t\ttr;\n\tvec3_t\tmidpoint;\n\n\t// use the midpoint of the bounds instead of the origin, because\n\t// bmodels may have their origin is 0,0,0\n\tVectorAdd (targ->r.absmin, targ->r.absmax, midpoint);\n\tVectorScale (midpoint, 0.5, midpoint);\n\n\tVectorCopy (midpoint, dest);\n\ttrap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);\n\tif (tr.fraction == 1.0 || tr.entityNum == targ->s.number)\n\t\treturn qtrue;\n\n\t// this should probably check in the plane of projection, \n\t// rather than in world coordinate, and also include Z\n\tVectorCopy (midpoint, dest);\n\tdest[0] += 15.0;\n\tdest[1] += 15.0;\n\ttrap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);\n\tif (tr.fraction == 1.0)\n\t\treturn qtrue;\n\n\tVectorCopy (midpoint, dest);\n\tdest[0] += 15.0;\n\tdest[1] -= 15.0;\n\ttrap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);\n\tif (tr.fraction == 1.0)\n\t\treturn qtrue;\n\n\tVectorCopy (midpoint, dest);\n\tdest[0] -= 15.0;\n\tdest[1] += 15.0;\n\ttrap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);\n\tif (tr.fraction == 1.0)\n\t\treturn qtrue;\n\n\tVectorCopy (midpoint, dest);\n\tdest[0] -= 15.0;\n\tdest[1] -= 15.0;\n\ttrap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);\n\tif (tr.fraction == 1.0)\n\t\treturn qtrue;\n\n\n\treturn qfalse;\n}\n\n\n/*\n============\nG_RadiusDamage\n============\n*/\nqboolean G_RadiusDamage ( vec3_t origin, gentity_t *attacker, float damage, float radius,\n\t\t\t\t\t gentity_t *ignore, int mod) {\n\tfloat\t\tpoints, dist;\n\tgentity_t\t*ent;\n\tint\t\t\tentityList[MAX_GENTITIES];\n\tint\t\t\tnumListedEntities;\n\tvec3_t\t\tmins, maxs;\n\tvec3_t\t\tv;\n\tvec3_t\t\tdir;\n\tint\t\t\ti, e;\n\tqboolean\thitClient = qfalse;\n\n\tif ( radius < 1 ) {\n\t\tradius = 1;\n\t}\n\n\tfor ( i = 0 ; i < 3 ; i++ ) {\n\t\tmins[i] = origin[i] - radius;\n\t\tmaxs[i] = origin[i] + radius;\n\t}\n\n\tnumListedEntities = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );\n\n\tfor ( e = 0 ; e < numListedEntities ; e++ ) {\n\t\tent = &g_entities[entityList[ e ]];\n\n\t\tif (ent == ignore)\n\t\t\tcontinue;\n\t\tif (!ent->takedamage)\n\t\t\tcontinue;\n\n\t\t// find the distance from the edge of the bounding box\n\t\tfor ( i = 0 ; i < 3 ; i++ ) {\n\t\t\tif ( origin[i] < ent->r.absmin[i] ) {\n\t\t\t\tv[i] = ent->r.absmin[i] - origin[i];\n\t\t\t} else if ( origin[i] > ent->r.absmax[i] ) {\n\t\t\t\tv[i] = origin[i] - ent->r.absmax[i];\n\t\t\t} else {\n\t\t\t\tv[i] = 0;\n\t\t\t}\n\t\t}\n\n\t\tdist = VectorLength( v );\n\t\tif ( dist >= radius ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tpoints = damage * ( 1.0 - dist / radius );\n\n\t\tif( CanDamage (ent, origin) ) {\n\t\t\tif( LogAccuracyHit( ent, attacker ) ) {\n\t\t\t\thitClient = qtrue;\n\t\t\t}\n\t\t\tVectorSubtract (ent->r.currentOrigin, origin, dir);\n\t\t\t// push the center of mass higher than the origin so players\n\t\t\t// get knocked into the air more\n\t\t\tdir[2] += 24;\n\t\t\tG_Damage (ent, NULL, attacker, dir, origin, (int)points, DAMAGE_RADIUS, mod);\n\t\t}\n\t}\n\n\treturn hitClient;\n}\n"
  },
  {
    "path": "src/game/g_items.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n#include \"g_local.h\"\n\n/*\n\n  Items are any object that a player can touch to gain some effect.\n\n  Pickup will return the number of seconds until they should respawn.\n\n  all items should pop when dropped in lava or slime\n\n  Respawnable items don't actually go away when picked up, they are\n  just made invisible and untouchable.  This allows them to ride\n  movers and respawn apropriately.\n*/\n\n\n#define\tRESPAWN_ARMOR\t\t25\n#define\tRESPAWN_HEALTH\t\t35\n#define\tRESPAWN_AMMO\t\t40\n#define\tRESPAWN_HOLDABLE\t60\n#define\tRESPAWN_MEGAHEALTH\t35//120\n#define\tRESPAWN_POWERUP\t\t120\n\n\n//======================================================================\n\nint Pickup_Powerup( gentity_t *ent, gentity_t *other ) {\n\tint\t\t\tquantity;\n\tint\t\t\ti;\n\tgclient_t\t*client;\n\n\tif ( !other->client->ps.powerups[ent->item->giTag] ) {\n\t\t// round timing to seconds to make multiple powerup timers\n\t\t// count in sync\n\t\tother->client->ps.powerups[ent->item->giTag] = \n\t\t\tlevel.time - ( level.time % 1000 );\n\t}\n\n\tif ( ent->count ) {\n\t\tquantity = ent->count;\n\t} else {\n\t\tquantity = ent->item->quantity;\n\t}\n\n\tother->client->ps.powerups[ent->item->giTag] += quantity * 1000;\n\n\t// give any nearby players a \"denied\" anti-reward\n\tfor ( i = 0 ; i < level.maxclients ; i++ ) {\n\t\tvec3_t\t\tdelta;\n\t\tfloat\t\tlen;\n\t\tvec3_t\t\tforward;\n\t\ttrace_t\t\ttr;\n\n\t\tclient = &level.clients[i];\n\t\tif ( client == other->client ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( client->pers.connected == CON_DISCONNECTED ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( client->ps.stats[STAT_HEALTH] <= 0 ) {\n\t\t\tcontinue;\n\t\t}\n\n    // if same team in team game, no sound\n    // cannot use OnSameTeam as it expects to g_entities, not clients\n  \tif ( g_gametype.integer >= GT_TEAM && other->client->sess.sessionTeam == client->sess.sessionTeam  ) {\n      continue;\n    }\n\n\t\t// if too far away, no sound\n\t\tVectorSubtract( ent->s.pos.trBase, client->ps.origin, delta );\n\t\tlen = VectorNormalize( delta );\n\t\tif ( len > 192 ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// if not facing, no sound\n\t\tAngleVectors( client->ps.viewangles, forward, NULL, NULL );\n\t\tif ( DotProduct( delta, forward ) < 0.4 ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// if not line of sight, no sound\n\t\ttrap_Trace( &tr, client->ps.origin, NULL, NULL, ent->s.pos.trBase, ENTITYNUM_NONE, CONTENTS_SOLID );\n\t\tif ( tr.fraction != 1.0 ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// anti-reward\n\t\tclient->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_DENIEDREWARD;\n\t}\n\treturn RESPAWN_POWERUP;\n}\n\n//======================================================================\nint Pickup_Holdable( gentity_t *ent, gentity_t *other ) {\n\n\tother->client->ps.stats[STAT_HOLDABLE_ITEM] = ent->item - bg_itemlist;\n\n\tif( ent->item->giTag == HI_KAMIKAZE ) {\n\t\tother->client->ps.eFlags |= EF_KAMIKAZE;\n\t}\n\n\treturn RESPAWN_HOLDABLE;\n}\n\n\n//======================================================================\n\nvoid Add_Ammo (gentity_t *ent, int weapon, int count)\n{\n\tent->client->ps.ammo[weapon] += count;\n\tif ( ent->client->ps.ammo[weapon] > 200 ) {\n\t\tent->client->ps.ammo[weapon] = 200;\n\t}\n}\n\nint Pickup_Ammo (gentity_t *ent, gentity_t *other)\n{\n\tint\t\tquantity;\n\n\tif ( ent->count ) {\n\t\tquantity = ent->count;\n\t} else {\n\t\tquantity = ent->item->quantity;\n\t}\n\n\tAdd_Ammo (other, ent->item->giTag, quantity);\n\n\treturn RESPAWN_AMMO;\n}\n\n//======================================================================\n\n\nint Pickup_Weapon (gentity_t *ent, gentity_t *other) {\n\tint\t\tquantity;\n\n\tif ( ent->count < 0 ) {\n\t\tquantity = 0; // None for you, sir!\n\t} else {\n\t\tif ( ent->count ) {\n\t\t\tquantity = ent->count;\n\t\t} else {\n\t\t\tquantity = ent->item->quantity;\n\t\t}\n\n\t\t// dropped items and teamplay weapons always have full ammo\n\t\tif ( ! (ent->flags & FL_DROPPED_ITEM) && g_gametype.integer != GT_TEAM ) {\n\t\t\t// respawning rules\n\t\t\t// drop the quantity if the already have over the minimum\n\t\t\tif ( other->client->ps.ammo[ ent->item->giTag ] < quantity ) {\n\t\t\t\tquantity = quantity - other->client->ps.ammo[ ent->item->giTag ];\n\t\t\t} else {\n\t\t\t\tquantity = 1;\t\t// only add a single shot\n\t\t\t}\n\t\t}\n\t}\n\n\t// add the weapon\n\tother->client->ps.stats[STAT_WEAPONS] |= ( 1 << ent->item->giTag );\n\n\tAdd_Ammo( other, ent->item->giTag, quantity );\n\n\tif (ent->item->giTag == WP_GRAPPLING_HOOK)\n\t\tother->client->ps.ammo[ent->item->giTag] = -1; // unlimited ammo\n\n\t// team deathmatch has slow weapon respawns\n\tif ( g_gametype.integer == GT_TEAM ) {\n\t\treturn g_weaponTeamRespawn.integer;\n\t}\n\n\treturn g_weaponRespawn.integer;\n}\n\n\n//======================================================================\n\nint Pickup_Health (gentity_t *ent, gentity_t *other) {\n\tint\t\t\tmax;\n\tint\t\t\tquantity;\n\n\t// small and mega healths will go over the max\n\tif ( ent->item->quantity != 5 && ent->item->quantity != 100 ) {\n\t\tmax = other->client->ps.stats[STAT_MAX_HEALTH];\n\t} else {\n\t\tmax = other->client->ps.stats[STAT_MAX_HEALTH] * 2;\n\t}\n\n\tif ( ent->count ) {\n\t\tquantity = ent->count;\n\t} else {\n\t\tquantity = ent->item->quantity;\n\t}\n\n\tother->health += quantity;\n\n\tif (other->health > max ) {\n\t\tother->health = max;\n\t}\n\tother->client->ps.stats[STAT_HEALTH] = other->health;\n\n\tif ( ent->item->quantity == 100 ) {\t\t// mega health respawns slow\n\t\treturn RESPAWN_MEGAHEALTH;\n\t}\n\n\treturn RESPAWN_HEALTH;\n}\n\n//======================================================================\n\nint Pickup_Armor( gentity_t *ent, gentity_t *other ) {\n\tother->client->ps.stats[STAT_ARMOR] += ent->item->quantity;\n\tif ( other->client->ps.stats[STAT_ARMOR] > other->client->ps.stats[STAT_MAX_HEALTH] * 2 ) {\n\t\tother->client->ps.stats[STAT_ARMOR] = other->client->ps.stats[STAT_MAX_HEALTH] * 2;\n\t}\n\treturn RESPAWN_ARMOR;\n}\n\n//======================================================================\n\n/*\n===============\nRespawnItem\n===============\n*/\nvoid RespawnItem( gentity_t *ent ) {\n\t// randomly select from teamed entities\n\tif (ent->team) {\n\t\tgentity_t\t*master;\n\t\tint\tcount;\n\t\tint choice;\n\n\t\tif ( !ent->teammaster ) {\n\t\t\tG_Error( \"RespawnItem: bad teammaster\");\n\t\t}\n\t\tmaster = ent->teammaster;\n\n\t\tfor (count = 0, ent = master; ent; ent = ent->teamchain, count++)\n\t\t\t;\n\n\t\tchoice = rand() % count;\n\n\t\tfor (count = 0, ent = master; count < choice; ent = ent->teamchain, count++)\n\t\t\t;\n\t}\n\n\tent->r.contents = CONTENTS_TRIGGER;\n\tent->s.eFlags &= ~EF_NODRAW;\n\tent->r.svFlags &= ~SVF_NOCLIENT;\n\ttrap_LinkEntity (ent);\n\n\tif ( ent->item->giType == IT_POWERUP ) {\n\t\t// play powerup spawn sound to all clients\n\t\tgentity_t\t*te;\n\n\t\t// if the powerup respawn sound should Not be global\n\t\tif (ent->speed) {\n\t\t\tte = G_TempEntity( ent->s.pos.trBase, EV_GENERAL_SOUND );\n\t\t}\n\t\telse {\n\t\t\tte = G_TempEntity( ent->s.pos.trBase, EV_GLOBAL_SOUND );\n\t\t}\n\t\tte->s.eventParm = G_SoundIndex( \"sound/items/poweruprespawn.wav\" );\n\t\tte->r.svFlags |= SVF_BROADCAST;\n\t}\n\n\tif ( ent->item->giType == IT_HOLDABLE && ent->item->giTag == HI_KAMIKAZE ) {\n\t\t// play powerup spawn sound to all clients\n\t\tgentity_t\t*te;\n\n\t\t// if the powerup respawn sound should Not be global\n\t\tif (ent->speed) {\n\t\t\tte = G_TempEntity( ent->s.pos.trBase, EV_GENERAL_SOUND );\n\t\t}\n\t\telse {\n\t\t\tte = G_TempEntity( ent->s.pos.trBase, EV_GLOBAL_SOUND );\n\t\t}\n\t\tte->s.eventParm = G_SoundIndex( \"sound/items/kamikazerespawn.wav\" );\n\t\tte->r.svFlags |= SVF_BROADCAST;\n\t}\n\n\t// play the normal respawn sound only to nearby clients\n\tG_AddEvent( ent, EV_ITEM_RESPAWN, 0 );\n\n\tent->nextthink = 0;\n}\n\n\n/*\n===============\nTouch_Item\n===============\n*/\nvoid Touch_Item (gentity_t *ent, gentity_t *other, trace_t *trace) {\n\tint\t\t\trespawn;\n\tqboolean\tpredict;\n\n\tif (!other->client)\n\t\treturn;\n\tif (other->health < 1)\n\t\treturn;\t\t// dead people can't pickup\n\n\t// the same pickup rules are used for client side and server side\n\tif ( !BG_CanItemBeGrabbed( g_gametype.integer, &ent->s, &other->client->ps ) ) {\n\t\treturn;\n\t}\n\n\tG_LogPrintf( \"Item: %i %s\\n\", other->s.number, ent->item->classname );\n\n\tpredict = other->client->pers.predictItemPickup;\n\n\t// call the item-specific pickup function\n\tswitch( ent->item->giType ) {\n\tcase IT_WEAPON:\n\t\trespawn = Pickup_Weapon(ent, other);\n//\t\tpredict = qfalse;\n\t\tbreak;\n\tcase IT_AMMO:\n\t\trespawn = Pickup_Ammo(ent, other);\n//\t\tpredict = qfalse;\n\t\tbreak;\n\tcase IT_ARMOR:\n\t\trespawn = Pickup_Armor(ent, other);\n\t\tbreak;\n\tcase IT_HEALTH:\n\t\trespawn = Pickup_Health(ent, other);\n\t\tbreak;\n\tcase IT_POWERUP:\n\t\trespawn = Pickup_Powerup(ent, other);\n\t\tpredict = qfalse;\n\t\tbreak;\n\tcase IT_TEAM:\n\t\trespawn = Pickup_Team(ent, other);\n\t\tbreak;\n\tcase IT_HOLDABLE:\n\t\trespawn = Pickup_Holdable(ent, other);\n\t\tbreak;\n\tdefault:\n\t\treturn;\n\t}\n\n\tif ( !respawn ) {\n\t\treturn;\n\t}\n\n\t// play the normal pickup sound\n\tif (predict) {\n\t\tG_AddPredictableEvent( other, EV_ITEM_PICKUP, ent->s.modelindex );\n\t} else {\n\t\tG_AddEvent( other, EV_ITEM_PICKUP, ent->s.modelindex );\n\t}\n\n\t// powerup pickups are global broadcasts\n\tif ( ent->item->giType == IT_POWERUP || ent->item->giType == IT_TEAM) {\n\t\t// if we want the global sound to play\n\t\tif (!ent->speed) {\n\t\t\tgentity_t\t*te;\n\n\t\t\tte = G_TempEntity( ent->s.pos.trBase, EV_GLOBAL_ITEM_PICKUP );\n\t\t\tte->s.eventParm = ent->s.modelindex;\n\t\t\tte->r.svFlags |= SVF_BROADCAST;\n\t\t} else {\n\t\t\tgentity_t\t*te;\n\n\t\t\tte = G_TempEntity( ent->s.pos.trBase, EV_GLOBAL_ITEM_PICKUP );\n\t\t\tte->s.eventParm = ent->s.modelindex;\n\t\t\t// only send this temp entity to a single client\n\t\t\tte->r.svFlags |= SVF_SINGLECLIENT;\n\t\t\tte->r.singleClient = other->s.number;\n\t\t}\n\t}\n\n\t// fire item targets\n\tG_UseTargets (ent, other);\n\n\t// wait of -1 will not respawn\n\tif ( ent->wait == -1 ) {\n\t\tent->r.svFlags |= SVF_NOCLIENT;\n\t\tent->s.eFlags |= EF_NODRAW;\n\t\tent->r.contents = 0;\n\t\tent->unlinkAfterEvent = qtrue;\n\t\treturn;\n\t}\n\n\t// non zero wait overrides respawn time\n\tif ( ent->wait ) {\n\t\trespawn = ent->wait;\n\t}\n\n\t// random can be used to vary the respawn time\n\tif ( ent->random ) {\n\t\trespawn += crandom() * ent->random;\n\t\tif ( respawn < 1 ) {\n\t\t\trespawn = 1;\n\t\t}\n\t}\n\n\t// dropped items will not respawn\n\tif ( ent->flags & FL_DROPPED_ITEM ) {\n\t\tent->freeAfterEvent = qtrue;\n\t}\n\n\t// picked up items still stay around, they just don't\n\t// draw anything.  This allows respawnable items\n\t// to be placed on movers.\n\tent->r.svFlags |= SVF_NOCLIENT;\n\tent->s.eFlags |= EF_NODRAW;\n\tent->r.contents = 0;\n\n\t// ZOID\n\t// A negative respawn times means to never respawn this item (but don't \n\t// delete it).  This is used by items that are respawned by third party \n\t// events such as ctf flags\n\tif ( respawn <= 0 ) {\n\t\tent->nextthink = 0;\n\t\tent->think = 0;\n\t} else {\n\t\tent->nextthink = level.time + respawn * 1000;\n\t\tent->think = RespawnItem;\n\t}\n\ttrap_LinkEntity( ent );\n}\n\n\n//======================================================================\n\n/*\n================\nLaunchItem\n\nSpawns an item and tosses it forward\n================\n*/\ngentity_t *LaunchItem( gitem_t *item, vec3_t origin, vec3_t velocity ) {\n\tgentity_t\t*dropped;\n\n\tdropped = G_Spawn();\n\n\tdropped->s.eType = ET_ITEM;\n\tdropped->s.modelindex = item - bg_itemlist;\t// store item number in modelindex\n\tdropped->s.modelindex2 = 1; // This is non-zero is it's a dropped item\n\n\tdropped->classname = item->classname;\n\tdropped->item = item;\n\tVectorSet (dropped->r.mins, -ITEM_RADIUS, -ITEM_RADIUS, -ITEM_RADIUS);\n\tVectorSet (dropped->r.maxs, ITEM_RADIUS, ITEM_RADIUS, ITEM_RADIUS);\n\tdropped->r.contents = CONTENTS_TRIGGER;\n\n\tdropped->touch = Touch_Item;\n\n\tG_SetOrigin( dropped, origin );\n\tdropped->s.pos.trType = TR_GRAVITY;\n\tdropped->s.pos.trTime = level.time;\n\tVectorCopy( velocity, dropped->s.pos.trDelta );\n\n\tdropped->s.eFlags |= EF_BOUNCE_HALF;\n\tif (g_gametype.integer == GT_CTF && item->giType == IT_TEAM) { // Special case for CTF flags\n\t\tdropped->think = Team_DroppedFlagThink;\n\t\tdropped->nextthink = level.time + 30000;\n\t\tTeam_CheckDroppedItem( dropped );\n\t} else { // auto-remove after 30 seconds\n\t\tdropped->think = G_FreeEntity;\n\t\tdropped->nextthink = level.time + 30000;\n\t}\n\n\tdropped->flags = FL_DROPPED_ITEM;\n\n\ttrap_LinkEntity (dropped);\n\n\treturn dropped;\n}\n\n/*\n================\nDrop_Item\n\nSpawns an item and tosses it forward\n================\n*/\ngentity_t *Drop_Item( gentity_t *ent, gitem_t *item, float angle ) {\n\tvec3_t\tvelocity;\n\tvec3_t\tangles;\n\n\tVectorCopy( ent->s.apos.trBase, angles );\n\tangles[YAW] += angle;\n\tangles[PITCH] = 0;\t// always forward\n\n\tAngleVectors( angles, velocity, NULL, NULL );\n\tVectorScale( velocity, 150, velocity );\n\tvelocity[2] += 200 + crandom() * 50;\n\t\n\treturn LaunchItem( item, ent->s.pos.trBase, velocity );\n}\n\n\n/*\n================\nUse_Item\n\nRespawn the item\n================\n*/\nvoid Use_Item( gentity_t *ent, gentity_t *other, gentity_t *activator ) {\n\tRespawnItem( ent );\n}\n\n//======================================================================\n\n/*\n================\nFinishSpawningItem\n\nTraces down to find where an item should rest, instead of letting them\nfree fall from their spawn points\n================\n*/\nvoid FinishSpawningItem( gentity_t *ent ) {\n\ttrace_t\t\ttr;\n\tvec3_t\t\tdest;\n\n\tVectorSet( ent->r.mins, -ITEM_RADIUS, -ITEM_RADIUS, -ITEM_RADIUS );\n\tVectorSet( ent->r.maxs, ITEM_RADIUS, ITEM_RADIUS, ITEM_RADIUS );\n\n\tent->s.eType = ET_ITEM;\n\tent->s.modelindex = ent->item - bg_itemlist;\t\t// store item number in modelindex\n\tent->s.modelindex2 = 0; // zero indicates this isn't a dropped item\n\n\tent->r.contents = CONTENTS_TRIGGER;\n\tent->touch = Touch_Item;\n\t// useing an item causes it to respawn\n\tent->use = Use_Item;\n\n\tif ( ent->spawnflags & 1 ) {\n\t\t// suspended\n\t\tG_SetOrigin( ent, ent->s.origin );\n\t} else {\n\t\t// drop to floor\n\t\tVectorSet( dest, ent->s.origin[0], ent->s.origin[1], ent->s.origin[2] - 4096 );\n\t\ttrap_Trace( &tr, ent->s.origin, ent->r.mins, ent->r.maxs, dest, ent->s.number, MASK_SOLID );\n\t\tif ( tr.startsolid ) {\n\t\t\tG_Printf (\"FinishSpawningItem: %s startsolid at %s\\n\", ent->classname, vtos(ent->s.origin));\n\t\t\tG_FreeEntity( ent );\n\t\t\treturn;\n\t\t}\n\n\t\t// allow to ride movers\n\t\tent->s.groundEntityNum = tr.entityNum;\n\n\t\tG_SetOrigin( ent, tr.endpos );\n\t}\n\n\t// team slaves and targeted items aren't present at start\n\tif ( ( ent->flags & FL_TEAMSLAVE ) || ent->targetname ) {\n\t\tent->s.eFlags |= EF_NODRAW;\n\t\tent->r.contents = 0;\n\t\treturn;\n\t}\n\n\t// powerups don't spawn in for a while\n\tif ( ent->item->giType == IT_POWERUP ) {\n\t\tfloat\trespawn;\n\n\t\trespawn = 45 + crandom() * 15;\n\t\tent->s.eFlags |= EF_NODRAW;\n\t\tent->r.contents = 0;\n\t\tent->nextthink = level.time + respawn * 1000;\n\t\tent->think = RespawnItem;\n\t\treturn;\n\t}\n\n\n\ttrap_LinkEntity (ent);\n}\n\n\nqboolean\titemRegistered[MAX_ITEMS];\n\n/*\n==================\nG_CheckTeamItems\n==================\n*/\nvoid G_CheckTeamItems( void ) {\n\n\t// Set up team stuff\n\tTeam_InitGame();\n\n\tif( g_gametype.integer == GT_CTF ) {\n\t\tgitem_t\t*item;\n\n\t\t// check for the two flags\n\t\titem = BG_FindItem( \"Red Flag\" );\n\t\tif ( !item || !itemRegistered[ item - bg_itemlist ] ) {\n\t\t\tG_Printf( S_COLOR_YELLOW \"WARNING: No team_CTF_redflag in map\" );\n\t\t}\n\t\titem = BG_FindItem( \"Blue Flag\" );\n\t\tif ( !item || !itemRegistered[ item - bg_itemlist ] ) {\n\t\t\tG_Printf( S_COLOR_YELLOW \"WARNING: No team_CTF_blueflag in map\" );\n\t\t}\n\t}\n}\n\n/*\n==============\nClearRegisteredItems\n==============\n*/\nvoid ClearRegisteredItems( void ) {\n\tmemset( itemRegistered, 0, sizeof( itemRegistered ) );\n\n\t// players always start with the base weapon\n\tRegisterItem( BG_FindItemForWeapon( WP_MACHINEGUN ) );\n\tRegisterItem( BG_FindItemForWeapon( WP_GAUNTLET ) );\n}\n\n/*\n===============\nRegisterItem\n\nThe item will be added to the precache list\n===============\n*/\nvoid RegisterItem( gitem_t *item ) {\n\tif ( !item ) {\n\t\tG_Error( \"RegisterItem: NULL\" );\n\t}\n\titemRegistered[ item - bg_itemlist ] = qtrue;\n}\n\n\n/*\n===============\nSaveRegisteredItems\n\nWrite the needed items to a config string\nso the client will know which ones to precache\n===============\n*/\nvoid SaveRegisteredItems( void ) {\n\tchar\tstring[MAX_ITEMS+1];\n\tint\t\ti;\n\tint\t\tcount;\n\n\tcount = 0;\n\tfor ( i = 0 ; i < bg_numItems ; i++ ) {\n\t\tif ( itemRegistered[i] ) {\n\t\t\tcount++;\n\t\t\tstring[i] = '1';\n\t\t} else {\n\t\t\tstring[i] = '0';\n\t\t}\n\t}\n\tstring[ bg_numItems ] = 0;\n\n\tG_Printf( \"%i items registered\\n\", count );\n\ttrap_SetConfigstring(CS_ITEMS, string);\n}\n\n/*\n============\nG_ItemDisabled\n============\n*/\nint G_ItemDisabled( gitem_t *item ) {\n\n\tchar name[128];\n\n\tCom_sprintf(name, sizeof(name), \"disable_%s\", item->classname);\n\treturn trap_Cvar_VariableIntegerValue( name );\n}\n\n/*\n============\nG_SpawnItem\n\nSets the clipping size and plants the object on the floor.\n\nItems can't be immediately dropped to floor, because they might\nbe on an entity that hasn't spawned yet.\n============\n*/\nvoid G_SpawnItem (gentity_t *ent, gitem_t *item) {\n\tG_SpawnFloat( \"random\", \"0\", &ent->random );\n\tG_SpawnFloat( \"wait\", \"0\", &ent->wait );\n\n\tRegisterItem( item );\n\tif ( G_ItemDisabled(item) )\n\t\treturn;\n\n\tent->item = item;\n\t// some movers spawn on the second frame, so delay item\n\t// spawns until the third frame so they can ride trains\n\tent->nextthink = level.time + FRAMETIME * 2;\n\tent->think = FinishSpawningItem;\n\n\tent->physicsBounce = 0.50;\t\t// items are bouncy\n\n\tif ( item->giType == IT_POWERUP ) {\n\t\tG_SoundIndex( \"sound/items/poweruprespawn.wav\" );\n\t\tG_SpawnFloat( \"noglobalsound\", \"0\", &ent->speed);\n\t}\n}\n\n\n/*\n================\nG_BounceItem\n\n================\n*/\nvoid G_BounceItem( gentity_t *ent, trace_t *trace ) {\n\tvec3_t\tvelocity;\n\tfloat\tdot;\n\tint\t\thitTime;\n\n\t// reflect the velocity on the trace plane\n\thitTime = level.previousTime + ( level.time - level.previousTime ) * trace->fraction;\n\tBG_EvaluateTrajectoryDelta( &ent->s.pos, hitTime, velocity );\n\tdot = DotProduct( velocity, trace->plane.normal );\n\tVectorMA( velocity, -2*dot, trace->plane.normal, ent->s.pos.trDelta );\n\n\t// cut the velocity to keep from bouncing forever\n\tVectorScale( ent->s.pos.trDelta, ent->physicsBounce, ent->s.pos.trDelta );\n\n\t// check for stop\n\tif ( trace->plane.normal[2] > 0 && ent->s.pos.trDelta[2] < 40 ) {\n\t\ttrace->endpos[2] += 1.0;\t// make sure it is off ground\n\t\tSnapVector( trace->endpos );\n\t\tG_SetOrigin( ent, trace->endpos );\n\t\tent->s.groundEntityNum = trace->entityNum;\n\t\treturn;\n\t}\n\n\tVectorAdd( ent->r.currentOrigin, trace->plane.normal, ent->r.currentOrigin);\n\tVectorCopy( ent->r.currentOrigin, ent->s.pos.trBase );\n\tent->s.pos.trTime = level.time;\n}\n\n\n/*\n================\nG_RunItem\n\n================\n*/\nvoid G_RunItem( gentity_t *ent ) {\n\tvec3_t\t\torigin;\n\ttrace_t\t\ttr;\n\tint\t\t\tcontents;\n\tint\t\t\tmask;\n\n\t// if groundentity has been set to -1, it may have been pushed off an edge\n\tif ( ent->s.groundEntityNum == -1 ) {\n\t\tif ( ent->s.pos.trType != TR_GRAVITY ) {\n\t\t\tent->s.pos.trType = TR_GRAVITY;\n\t\t\tent->s.pos.trTime = level.time;\n\t\t}\n\t}\n\n\tif ( ent->s.pos.trType == TR_STATIONARY ) {\n\t\t// check think function\n\t\tG_RunThink( ent );\n\t\treturn;\n\t}\n\n\t// get current position\n\tBG_EvaluateTrajectory( &ent->s.pos, level.time, origin );\n\n\t// trace a line from the previous position to the current position\n\tif ( ent->clipmask ) {\n\t\tmask = ent->clipmask;\n\t} else {\n\t\tmask = MASK_PLAYERSOLID & ~CONTENTS_BODY;//MASK_SOLID;\n\t}\n\ttrap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, \n\t\tent->r.ownerNum, mask );\n\n\tVectorCopy( tr.endpos, ent->r.currentOrigin );\n\n\tif ( tr.startsolid ) {\n\t\ttr.fraction = 0;\n\t}\n\n\ttrap_LinkEntity( ent );\t// FIXME: avoid this for stationary?\n\n\t// check think function\n\tG_RunThink( ent );\n\n\tif ( tr.fraction == 1 ) {\n\t\treturn;\n\t}\n\n\t// if it is in a nodrop volume, remove it\n\tcontents = trap_PointContents( ent->r.currentOrigin, -1 );\n\tif ( contents & CONTENTS_NODROP ) {\n\t\tif (ent->item && ent->item->giType == IT_TEAM) {\n\t\t\tTeam_FreeEntity(ent);\n\t\t} else {\n\t\t\tG_FreeEntity( ent );\n\t\t}\n\t\treturn;\n\t}\n\n\tG_BounceItem( ent, &tr );\n}\n\n"
  },
  {
    "path": "src/game/g_local.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n// g_local.h -- local definitions for game module\n\n#include \"q_shared.h\"\n#include \"bg_public.h\"\n#include \"g_public.h\"\n\n//==================================================================\n\n// the \"gameversion\" client command will print this plus compile date\n#define\tGAMEVERSION\t\"baseq3\"\n\n#define BODY_QUEUE_SIZE\t\t8\n\n#define INFINITE\t\t\t1000000\n\n#define\tFRAMETIME\t\t\t100\t\t\t\t\t// msec\n#define\tCARNAGE_REWARD_TIME\t3000\n#define REWARD_SPRITE_TIME\t2000\n\n#define\tINTERMISSION_DELAY_TIME\t1000\n#define\tSP_INTERMISSION_DELAY_TIME\t5000\n\n// gentity->flags\n#define\tFL_GODMODE\t\t\t\t0x00000010\n#define\tFL_NOTARGET\t\t\t\t0x00000020\n#define\tFL_TEAMSLAVE\t\t\t0x00000400\t// not the first on the team\n#define FL_NO_KNOCKBACK\t\t\t0x00000800\n#define FL_DROPPED_ITEM\t\t\t0x00001000\n#define FL_NO_BOTS\t\t\t\t0x00002000\t// spawn point not for bot use\n#define FL_NO_HUMANS\t\t\t0x00004000\t// spawn point just for bots\n#define FL_FORCE_GESTURE\t\t0x00008000\t// force gesture on client\n\n// movers are things like doors, plats, buttons, etc\ntypedef enum {\n\tMOVER_POS1,\n\tMOVER_POS2,\n\tMOVER_1TO2,\n\tMOVER_2TO1\n} moverState_t;\n\n#define SP_PODIUM_MODEL\t\t\"models/mapobjects/podium/podium4.md3\"\n\n//============================================================================\n\ntypedef struct gentity_s gentity_t;\ntypedef struct gclient_s gclient_t;\n\nstruct gentity_s {\n\tentityState_t\ts;\t\t\t\t// communicated by server to clients\n\tentityShared_t\tr;\t\t\t\t// shared by both the server system and game\n\n\t// DO NOT MODIFY ANYTHING ABOVE THIS, THE SERVER\n\t// EXPECTS THE FIELDS IN THAT ORDER!\n\t//================================\n\n\tstruct gclient_s\t*client;\t\t\t// NULL if not a client\n\n\tqboolean\tinuse;\n\n\tchar\t\t*classname;\t\t\t// set in QuakeEd\n\tint\t\t\tspawnflags;\t\t\t// set in QuakeEd\n\n\tqboolean\tneverFree;\t\t\t// if true, FreeEntity will only unlink\n\t\t\t\t\t\t\t\t\t// bodyque uses this\n\n\tint\t\t\tflags;\t\t\t\t// FL_* variables\n\n\tchar\t\t*model;\n\tchar\t\t*model2;\n\tint\t\t\tfreetime;\t\t\t// level.time when the object was freed\n\t\n\tint\t\t\teventTime;\t\t\t// events will be cleared EVENT_VALID_MSEC after set\n\tqboolean\tfreeAfterEvent;\n\tqboolean\tunlinkAfterEvent;\n\n\tqboolean\tphysicsObject;\t\t// if true, it can be pushed by movers and fall off edges\n\t\t\t\t\t\t\t\t\t// all game items are physicsObjects, \n\tfloat\t\tphysicsBounce;\t\t// 1.0 = continuous bounce, 0.0 = no bounce\n\tint\t\t\tclipmask;\t\t\t// brushes with this content value will be collided against\n\t\t\t\t\t\t\t\t\t// when moving.  items and corpses do not collide against\n\t\t\t\t\t\t\t\t\t// players, for instance\n\n\t// movers\n\tmoverState_t moverState;\n\tint\t\t\tsoundPos1;\n\tint\t\t\tsound1to2;\n\tint\t\t\tsound2to1;\n\tint\t\t\tsoundPos2;\n\tint\t\t\tsoundLoop;\n\tgentity_t\t*parent;\n\tgentity_t\t*nextTrain;\n\tgentity_t\t*prevTrain;\n\tvec3_t\t\tpos1, pos2;\n\n\tchar\t\t*message;\n\n\tint\t\t\ttimestamp;\t\t// body queue sinking, etc\n\n\tfloat\t\tangle;\t\t\t// set in editor, -1 = up, -2 = down\n\tchar\t\t*target;\n\tchar\t\t*targetname;\n\tchar\t\t*team;\n\tchar\t\t*targetShaderName;\n\tchar\t\t*targetShaderNewName;\n\tgentity_t\t*target_ent;\n\n\tfloat\t\tspeed;\n\tvec3_t\t\tmovedir;\n\n\tint\t\t\tnextthink;\n\tvoid\t\t(*think)(gentity_t *self);\n\tvoid\t\t(*reached)(gentity_t *self);\t// movers call this when hitting endpoint\n\tvoid\t\t(*blocked)(gentity_t *self, gentity_t *other);\n\tvoid\t\t(*touch)(gentity_t *self, gentity_t *other, trace_t *trace);\n\tvoid\t\t(*use)(gentity_t *self, gentity_t *other, gentity_t *activator);\n\tvoid\t\t(*pain)(gentity_t *self, gentity_t *attacker, int damage);\n\tvoid\t\t(*die)(gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod);\n\n\tint\t\t\tpain_debounce_time;\n\tint\t\t\tfly_sound_debounce_time;\t// wind tunnel\n\tint\t\t\tlast_move_time;\n\n\tint\t\t\thealth;\n\n\tqboolean\ttakedamage;\n\n\tint\t\t\tdamage;\n\tint\t\t\tsplashDamage;\t// quad will increase this without increasing radius\n\tint\t\t\tsplashRadius;\n\tint\t\t\tmethodOfDeath;\n\tint\t\t\tsplashMethodOfDeath;\n\n\tint\t\t\tcount;\n\n\tgentity_t\t*chain;\n\tgentity_t\t*enemy;\n\tgentity_t\t*activator;\n\tgentity_t\t*teamchain;\t\t// next entity in team\n\tgentity_t\t*teammaster;\t// master of the team\n\n\tint\t\t\twatertype;\n\tint\t\t\twaterlevel;\n\n\tint\t\t\tnoise_index;\n\n\t// timing variables\n\tfloat\t\twait;\n\tfloat\t\trandom;\n\n\tgitem_t\t\t*item;\t\t\t// for bonus items\n};\n\n\ntypedef enum {\n\tCON_DISCONNECTED,\n\tCON_CONNECTING,\n\tCON_CONNECTED\n} clientConnected_t;\n\ntypedef enum {\n\tSPECTATOR_NOT,\n\tSPECTATOR_FREE,\n\tSPECTATOR_FOLLOW,\n\tSPECTATOR_SCOREBOARD\n} spectatorState_t;\n\ntypedef enum {\n\tTEAM_BEGIN,\t\t// Beginning a team game, spawn at base\n\tTEAM_ACTIVE\t\t// Now actively playing\n} playerTeamStateState_t;\n\ntypedef struct {\n\tplayerTeamStateState_t\tstate;\n\n\tint\t\t\tlocation;\n\n\tint\t\t\tcaptures;\n\tint\t\t\tbasedefense;\n\tint\t\t\tcarrierdefense;\n\tint\t\t\tflagrecovery;\n\tint\t\t\tfragcarrier;\n\tint\t\t\tassists;\n\n\tfloat\t\tlasthurtcarrier;\n\tfloat\t\tlastreturnedflag;\n\tfloat\t\tflagsince;\n\tfloat\t\tlastfraggedcarrier;\n} playerTeamState_t;\n\n// the auto following clients don't follow a specific client\n// number, but instead follow the first two active players\n#define\tFOLLOW_ACTIVE1\t-1\n#define\tFOLLOW_ACTIVE2\t-2\n\n// client data that stays across multiple levels or tournament restarts\n// this is achieved by writing all the data to cvar strings at game shutdown\n// time and reading them back at connection time.  Anything added here\n// MUST be dealt with in G_InitSessionData() / G_ReadSessionData() / G_WriteSessionData()\ntypedef struct {\n\tteam_t\t\tsessionTeam;\n\tint\t\t\tspectatorTime;\t\t// for determining next-in-line to play\n\tspectatorState_t\tspectatorState;\n\tint\t\t\tspectatorClient;\t// for chasecam and follow mode\n\tint\t\t\twins, losses;\t\t// tournament stats\n\tqboolean\tteamLeader;\t\t\t// true when this client is a team leader\n} clientSession_t;\n\n//\n#define MAX_NETNAME\t\t\t36\n#define\tMAX_VOTE_COUNT\t\t3\n\n// client data that stays across multiple respawns, but is cleared\n// on each level change or team change at ClientBegin()\ntypedef struct {\n\tclientConnected_t\tconnected;\t\n\tusercmd_t\tcmd;\t\t\t\t// we would lose angles if not persistant\n\tqboolean\tlocalClient;\t\t// true if \"ip\" info key is \"localhost\"\n\tqboolean\tinitialSpawn;\t\t// the first spawn should be at a cool location\n\tqboolean\tpredictItemPickup;\t// based on cg_predictItems userinfo\n\tqboolean\tpmoveFixed;\t\t\t//\n\tchar\t\tnetname[MAX_NETNAME];\n\tint\t\t\tmaxHealth;\t\t\t// for handicapping\n\tint\t\t\tenterTime;\t\t\t// level.time the client entered the game\n\tplayerTeamState_t teamState;\t// status in teamplay games\n\tint\t\t\tvoteCount;\t\t\t// to prevent people from constantly calling votes\n\tint\t\t\tteamVoteCount;\t\t// to prevent people from constantly calling votes\n\tqboolean\tteamInfo;\t\t\t// send team overlay updates?\n} clientPersistant_t;\n\n\n// this structure is cleared on each ClientSpawn(),\n// except for 'client->pers' and 'client->sess'\nstruct gclient_s {\n\t// ps MUST be the first element, because the server expects it\n\tplayerState_t\tps;\t\t\t\t// communicated by server to clients\n\n\t// the rest of the structure is private to game\n\tclientPersistant_t\tpers;\n\tclientSession_t\t\tsess;\n\n\tqboolean\treadyToExit;\t\t// wishes to leave the intermission\n\n\tqboolean\tnoclip;\n\n\tint\t\t\tlastCmdTime;\t\t// level.time of last usercmd_t, for EF_CONNECTION\n\t\t\t\t\t\t\t\t\t// we can't just use pers.lastCommand.time, because\n\t\t\t\t\t\t\t\t\t// of the g_sycronousclients case\n\tint\t\t\tbuttons;\n\tint\t\t\toldbuttons;\n\tint\t\t\tlatched_buttons;\n\n\tvec3_t\t\toldOrigin;\n\n\t// sum up damage over an entire frame, so\n\t// shotgun blasts give a single big kick\n\tint\t\t\tdamage_armor;\t\t// damage absorbed by armor\n\tint\t\t\tdamage_blood;\t\t// damage taken out of health\n\tint\t\t\tdamage_knockback;\t// impact damage\n\tvec3_t\t\tdamage_from;\t\t// origin for vector calculation\n\tqboolean\tdamage_fromWorld;\t// if true, don't use the damage_from vector\n\n\tint\t\t\taccurateCount;\t\t// for \"impressive\" reward sound\n\n\tint\t\t\taccuracy_shots;\t\t// total number of shots\n\tint\t\t\taccuracy_hits;\t\t// total number of hits\n\n\t//\n\tint\t\t\tlastkilled_client;\t// last client that this client killed\n\tint\t\t\tlasthurt_client;\t// last client that damaged this client\n\tint\t\t\tlasthurt_mod;\t\t// type of damage the client did\n\n\t// timers\n\tint\t\t\trespawnTime;\t\t// can respawn when time > this, force after g_forcerespwan\n\tint\t\t\tinactivityTime;\t\t// kick players when time > this\n\tqboolean\tinactivityWarning;\t// qtrue if the five seoond warning has been given\n\tint\t\t\trewardTime;\t\t\t// clear the EF_AWARD_IMPRESSIVE, etc when time > this\n\n\tint\t\t\tairOutTime;\n\n\tint\t\t\tlastKillTime;\t\t// for multiple kill rewards\n\n\tqboolean\tfireHeld;\t\t\t// used for hook\n\tgentity_t\t*hook;\t\t\t\t// grapple hook if out\n\n\tint\t\t\tswitchTeamTime;\t\t// time the player switched teams\n\n\t// timeResidual is used to handle events that happen every second\n\t// like health / armor countdowns and regeneration\n\tint\t\t\ttimeResidual;\n\n\tchar\t\t*areabits;\n};\n\n\n//\n// this structure is cleared as each map is entered\n//\n#define\tMAX_SPAWN_VARS\t\t\t64\n#define\tMAX_SPAWN_VARS_CHARS\t4096\n\ntypedef struct {\n\tstruct gclient_s\t*clients;\t\t// [maxclients]\n\n\tstruct gentity_s\t*gentities;\n\tint\t\t\tgentitySize;\n\tint\t\t\tnum_entities;\t\t// current number, <= MAX_GENTITIES\n\n\tint\t\t\twarmupTime;\t\t\t// restart match at this time\n\n\tfileHandle_t\tlogFile;\n\n\t// store latched cvars here that we want to get at often\n\tint\t\t\tmaxclients;\n\n\tint\t\t\tframenum;\n\tint\t\t\ttime;\t\t\t\t\t// in msec\n\tint\t\t\tpreviousTime;\t\t\t// so movers can back up when blocked\n\n\tint\t\t\tstartTime;\t\t\t\t// level.time the map was started\n\n\tint\t\t\tteamScores[TEAM_NUM_TEAMS];\n\tint\t\t\tlastTeamLocationTime;\t\t// last time of client team location update\n\n\tqboolean\tnewSession;\t\t\t\t// don't use any old session data, because\n\t\t\t\t\t\t\t\t\t\t// we changed gametype\n\n\tqboolean\trestarted;\t\t\t\t// waiting for a map_restart to fire\n\n\tint\t\t\tnumConnectedClients;\n\tint\t\t\tnumNonSpectatorClients;\t// includes connecting clients\n\tint\t\t\tnumPlayingClients;\t\t// connected, non-spectators\n\tint\t\t\tsortedClients[MAX_CLIENTS];\t\t// sorted by score\n\tint\t\t\tfollow1, follow2;\t\t// clientNums for auto-follow spectators\n\n\tint\t\t\tsnd_fry;\t\t\t\t// sound index for standing in lava\n\n\tint\t\t\twarmupModificationCount;\t// for detecting if g_warmup is changed\n\n\t// voting state\n\tchar\t\tvoteString[MAX_STRING_CHARS];\n\tchar\t\tvoteDisplayString[MAX_STRING_CHARS];\n\tint\t\t\tvoteTime;\t\t\t\t// level.time vote was called\n\tint\t\t\tvoteExecuteTime;\t\t// time the vote is executed\n\tint\t\t\tvoteYes;\n\tint\t\t\tvoteNo;\n\tint\t\t\tnumVotingClients;\t\t// set by CalculateRanks\n\n\t// team voting state\n\tchar\t\tteamVoteString[2][MAX_STRING_CHARS];\n\tint\t\t\tteamVoteTime[2];\t\t// level.time vote was called\n\tint\t\t\tteamVoteYes[2];\n\tint\t\t\tteamVoteNo[2];\n\tint\t\t\tnumteamVotingClients[2];// set by CalculateRanks\n\n\t// spawn variables\n\tqboolean\tspawning;\t\t\t\t// the G_Spawn*() functions are valid\n\tint\t\t\tnumSpawnVars;\n\tchar\t\t*spawnVars[MAX_SPAWN_VARS][2];\t// key / value pairs\n\tint\t\t\tnumSpawnVarChars;\n\tchar\t\tspawnVarChars[MAX_SPAWN_VARS_CHARS];\n\n\t// intermission state\n\tint\t\t\tintermissionQueued;\t\t// intermission was qualified, but\n\t\t\t\t\t\t\t\t\t\t// wait INTERMISSION_DELAY_TIME before\n\t\t\t\t\t\t\t\t\t\t// actually going there so the last\n\t\t\t\t\t\t\t\t\t\t// frag can be watched.  Disable future\n\t\t\t\t\t\t\t\t\t\t// kills during this delay\n\tint\t\t\tintermissiontime;\t\t// time the intermission was started\n\tchar\t\t*changemap;\n\tqboolean\treadyToExit;\t\t\t// at least one client wants to exit\n\tint\t\t\texitTime;\n\tvec3_t\t\tintermission_origin;\t// also used for spectator spawns\n\tvec3_t\t\tintermission_angle;\n\n\tqboolean\tlocationLinked;\t\t\t// target_locations get linked\n\tgentity_t\t*locationHead;\t\t\t// head of the location list\n\tint\t\t\tbodyQueIndex;\t\t\t// dead bodies\n\tgentity_t\t*bodyQue[BODY_QUEUE_SIZE];\n} level_locals_t;\n\n\n//\n// g_spawn.c\n//\nqboolean\tG_SpawnString( const char *key, const char *defaultString, char **out );\n// spawn string returns a temporary reference, you must CopyString() if you want to keep it\nqboolean\tG_SpawnFloat( const char *key, const char *defaultString, float *out );\nqboolean\tG_SpawnInt( const char *key, const char *defaultString, int *out );\nqboolean\tG_SpawnVector( const char *key, const char *defaultString, float *out );\nvoid\t\tG_SpawnEntitiesFromString( void );\nchar *G_NewString( const char *string );\n\n//\n// g_cmds.c\n//\nvoid Cmd_Score_f (gentity_t *ent);\nvoid StopFollowing( gentity_t *ent );\nvoid BroadcastTeamChange( gclient_t *client, int oldTeam );\nvoid SetTeam( gentity_t *ent, char *s );\nvoid Cmd_FollowCycle_f( gentity_t *ent, int dir );\n\n//\n// g_items.c\n//\nvoid G_CheckTeamItems( void );\nvoid G_RunItem( gentity_t *ent );\nvoid RespawnItem( gentity_t *ent );\n\nvoid UseHoldableItem( gentity_t *ent );\nvoid PrecacheItem (gitem_t *it);\ngentity_t *Drop_Item( gentity_t *ent, gitem_t *item, float angle );\ngentity_t *LaunchItem( gitem_t *item, vec3_t origin, vec3_t velocity );\nvoid SetRespawn (gentity_t *ent, float delay);\nvoid G_SpawnItem (gentity_t *ent, gitem_t *item);\nvoid FinishSpawningItem( gentity_t *ent );\nvoid Think_Weapon (gentity_t *ent);\nint ArmorIndex (gentity_t *ent);\nvoid\tAdd_Ammo (gentity_t *ent, int weapon, int count);\nvoid Touch_Item (gentity_t *ent, gentity_t *other, trace_t *trace);\n\nvoid ClearRegisteredItems( void );\nvoid RegisterItem( gitem_t *item );\nvoid SaveRegisteredItems( void );\n\n//\n// g_utils.c\n//\nint G_ModelIndex( char *name );\nint\t\tG_SoundIndex( char *name );\nvoid\tG_TeamCommand( team_t team, char *cmd );\nvoid\tG_KillBox (gentity_t *ent);\ngentity_t *G_Find (gentity_t *from, int fieldofs, const char *match);\ngentity_t *G_PickTarget (char *targetname);\nvoid\tG_UseTargets (gentity_t *ent, gentity_t *activator);\nvoid\tG_SetMovedir ( vec3_t angles, vec3_t movedir);\n\nvoid\tG_InitGentity( gentity_t *e );\ngentity_t\t*G_Spawn (void);\ngentity_t *G_TempEntity( vec3_t origin, int event );\nvoid\tG_Sound( gentity_t *ent, int channel, int soundIndex );\nvoid\tG_FreeEntity( gentity_t *e );\nqboolean\tG_EntitiesFree( void );\n\nvoid\tG_TouchTriggers (gentity_t *ent);\nvoid\tG_TouchSolids (gentity_t *ent);\n\nfloat\t*tv (float x, float y, float z);\nchar\t*vtos( const vec3_t v );\n\nfloat vectoyaw( const vec3_t vec );\n\nvoid G_AddPredictableEvent( gentity_t *ent, int event, int eventParm );\nvoid G_AddEvent( gentity_t *ent, int event, int eventParm );\nvoid G_SetOrigin( gentity_t *ent, vec3_t origin );\nvoid AddRemap(const char *oldShader, const char *newShader, float timeOffset);\nconst char *BuildShaderStateConfig();\n\n//\n// g_combat.c\n//\nqboolean CanDamage (gentity_t *targ, vec3_t origin);\nvoid G_Damage (gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, vec3_t dir, vec3_t point, int damage, int dflags, int mod);\nqboolean G_RadiusDamage (vec3_t origin, gentity_t *attacker, float damage, float radius, gentity_t *ignore, int mod);\nint G_InvulnerabilityEffect( gentity_t *targ, vec3_t dir, vec3_t point, vec3_t impactpoint, vec3_t bouncedir );\nvoid body_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath );\nvoid TossClientItems( gentity_t *self );\nvoid TossClientCubes( gentity_t *self );\n\n// damage flags\n#define DAMAGE_RADIUS\t\t\t\t0x00000001\t// damage was indirect\n#define DAMAGE_NO_ARMOR\t\t\t\t0x00000002\t// armour does not protect from this damage\n#define DAMAGE_NO_KNOCKBACK\t\t\t0x00000004\t// do not affect velocity, just view angles\n#define DAMAGE_NO_PROTECTION\t\t0x00000008  // armor, shields, invulnerability, and godmode have no effect\n\n//\n// g_missile.c\n//\nvoid G_RunMissile( gentity_t *ent );\n\ngentity_t *fire_blaster (gentity_t *self, vec3_t start, vec3_t aimdir);\ngentity_t *fire_plasma (gentity_t *self, vec3_t start, vec3_t aimdir);\ngentity_t *fire_grenade (gentity_t *self, vec3_t start, vec3_t aimdir);\ngentity_t *fire_rocket (gentity_t *self, vec3_t start, vec3_t dir);\ngentity_t *fire_bfg (gentity_t *self, vec3_t start, vec3_t dir);\ngentity_t *fire_grapple (gentity_t *self, vec3_t start, vec3_t dir);\n\n\n//\n// g_mover.c\n//\nvoid G_RunMover( gentity_t *ent );\nvoid Touch_DoorTrigger( gentity_t *ent, gentity_t *other, trace_t *trace );\n\n//\n// g_trigger.c\n//\nvoid trigger_teleporter_touch (gentity_t *self, gentity_t *other, trace_t *trace );\n\n\n//\n// g_misc.c\n//\nvoid TeleportPlayer( gentity_t *player, vec3_t origin, vec3_t angles );\n\n\n//\n// g_weapon.c\n//\nqboolean LogAccuracyHit( gentity_t *target, gentity_t *attacker );\nvoid CalcMuzzlePoint ( gentity_t *ent, vec3_t forward, vec3_t right, vec3_t up, vec3_t muzzlePoint );\nvoid SnapVectorTowards( vec3_t v, vec3_t to );\nqboolean CheckGauntletAttack( gentity_t *ent );\nvoid Weapon_HookFree (gentity_t *ent);\nvoid Weapon_HookThink (gentity_t *ent);\n\n\n//\n// g_client.c\n//\nteam_t TeamCount( int ignoreClientNum, int team );\nint TeamLeader( int team );\nteam_t PickTeam( int ignoreClientNum );\nvoid SetClientViewAngle( gentity_t *ent, vec3_t angle );\ngentity_t *SelectSpawnPoint ( vec3_t avoidPoint, vec3_t origin, vec3_t angles );\nvoid CopyToBodyQue( gentity_t *ent );\nvoid respawn (gentity_t *ent);\nvoid BeginIntermission (void);\nvoid InitClientPersistant (gclient_t *client);\nvoid InitClientResp (gclient_t *client);\nvoid InitBodyQue (void);\nvoid ClientSpawn( gentity_t *ent );\nvoid player_die (gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod);\nvoid AddScore( gentity_t *ent, vec3_t origin, int score );\nvoid CalculateRanks( void );\nqboolean SpotWouldTelefrag( gentity_t *spot );\n\n//\n// g_svcmds.c\n//\nqboolean\tConsoleCommand( void );\nvoid G_ProcessIPBans(void);\nqboolean G_FilterPacket (char *from);\n\n//\n// g_weapon.c\n//\nvoid FireWeapon( gentity_t *ent );\n\n//\n// p_hud.c\n//\nvoid MoveClientToIntermission (gentity_t *client);\nvoid G_SetStats (gentity_t *ent);\nvoid DeathmatchScoreboardMessage (gentity_t *client);\n\n//\n// g_cmds.c\n//\n\n//\n// g_pweapon.c\n//\n\n\n//\n// g_main.c\n//\nvoid FindIntermissionPoint( void );\nvoid SetLeader(int team, int client);\nvoid CheckTeamLeader( int team );\nvoid G_RunThink (gentity_t *ent);\nvoid QDECL G_LogPrintf( const char *fmt, ... );\nvoid SendScoreboardMessageToAllClients( void );\nvoid QDECL G_Printf( const char *fmt, ... );\nvoid QDECL G_Error( const char *fmt, ... );\n\n//\n// g_client.c\n//\nchar *ClientConnect( int clientNum, qboolean firstTime, qboolean isBot );\nvoid ClientUserinfoChanged( int clientNum );\nvoid ClientDisconnect( int clientNum );\nvoid ClientBegin( int clientNum );\nvoid ClientCommand( int clientNum );\n\n//\n// g_active.c\n//\nvoid ClientThink( int clientNum );\nvoid ClientEndFrame( gentity_t *ent );\nvoid G_RunClient( gentity_t *ent );\n\n//\n// g_team.c\n//\nqboolean OnSameTeam( gentity_t *ent1, gentity_t *ent2 );\nvoid Team_CheckDroppedItem( gentity_t *dropped );\nqboolean CheckObeliskAttack( gentity_t *obelisk, gentity_t *attacker );\n\n//\n// g_mem.c\n//\nvoid *G_Alloc( int size );\nvoid G_InitMemory( void );\nvoid Svcmd_GameMem_f( void );\n\n//\n// g_session.c\n//\nvoid G_ReadSessionData( gclient_t *client );\nvoid G_InitSessionData( gclient_t *client, char *userinfo );\n\nvoid G_InitWorldSession( void );\nvoid G_WriteSessionData( void );\n\n//\n// g_arenas.c\n//\nvoid UpdateTournamentInfo( void );\nvoid SpawnModelsOnVictoryPads( void );\nvoid Svcmd_AbortPodium_f( void );\n\n//\n// g_bot.c\n//\nvoid G_InitBots( qboolean restart );\nchar *G_GetBotInfoByNumber( int num );\nchar *G_GetBotInfoByName( const char *name );\nvoid G_CheckBotSpawn( void );\nvoid G_RemoveQueuedBotBegin( int clientNum );\nqboolean G_BotConnect( int clientNum, qboolean restart );\nvoid Svcmd_AddBot_f( void );\nvoid Svcmd_BotList_f( void );\nvoid BotInterbreedEndMatch( void );\n\n// ai_main.c\n#define MAX_FILEPATH\t\t\t144\n\n//bot settings\ntypedef struct bot_settings_s\n{\n\tchar characterfile[MAX_FILEPATH];\n\tfloat skill;\n\tchar team[MAX_FILEPATH];\n} bot_settings_t;\n\nint BotAISetup( int restart );\nint BotAIShutdown( int restart );\nint BotAILoadMap( int restart );\nint BotAISetupClient(int client, struct bot_settings_s *settings, qboolean restart);\nint BotAIShutdownClient( int client, qboolean restart );\nint BotAIStartFrame( int time );\nvoid BotTestAAS(vec3_t origin);\n\n#include \"g_team.h\" // teamplay specific stuff\n\n\nextern\tlevel_locals_t\tlevel;\nextern\tgentity_t\t\tg_entities[MAX_GENTITIES];\n\n#define\tFOFS(x) ((int)(intptr_t)&(((gentity_t *)0)->x))\n\nextern\tvmCvar_t\tg_gametype;\nextern\tvmCvar_t\tg_dedicated;\nextern\tvmCvar_t\tg_cheats;\nextern\tvmCvar_t\tg_maxclients;\t\t\t// allow this many total, including spectators\nextern\tvmCvar_t\tg_maxGameClients;\t\t// allow this many active\nextern\tvmCvar_t\tg_restarted;\n\nextern\tvmCvar_t\tg_dmflags;\nextern\tvmCvar_t\tg_fraglimit;\nextern\tvmCvar_t\tg_timelimit;\nextern\tvmCvar_t\tg_capturelimit;\nextern\tvmCvar_t\tg_friendlyFire;\nextern\tvmCvar_t\tg_password;\nextern\tvmCvar_t\tg_needpass;\nextern\tvmCvar_t\tg_gravity;\nextern\tvmCvar_t\tg_speed;\nextern\tvmCvar_t\tg_knockback;\nextern\tvmCvar_t\tg_quadfactor;\nextern\tvmCvar_t\tg_forcerespawn;\nextern\tvmCvar_t\tg_inactivity;\nextern\tvmCvar_t\tg_debugMove;\nextern\tvmCvar_t\tg_debugAlloc;\nextern\tvmCvar_t\tg_debugDamage;\nextern\tvmCvar_t\tg_weaponRespawn;\nextern\tvmCvar_t\tg_weaponTeamRespawn;\nextern\tvmCvar_t\tg_synchronousClients;\nextern\tvmCvar_t\tg_motd;\nextern\tvmCvar_t\tg_warmup;\nextern\tvmCvar_t\tg_doWarmup;\nextern\tvmCvar_t\tg_blood;\nextern\tvmCvar_t\tg_allowVote;\nextern\tvmCvar_t\tg_teamAutoJoin;\nextern\tvmCvar_t\tg_teamForceBalance;\nextern\tvmCvar_t\tg_banIPs;\nextern\tvmCvar_t\tg_filterBan;\nextern\tvmCvar_t\tg_obeliskHealth;\nextern\tvmCvar_t\tg_obeliskRegenPeriod;\nextern\tvmCvar_t\tg_obeliskRegenAmount;\nextern\tvmCvar_t\tg_obeliskRespawnDelay;\nextern\tvmCvar_t\tg_cubeTimeout;\nextern\tvmCvar_t\tg_redteam;\nextern\tvmCvar_t\tg_blueteam;\nextern\tvmCvar_t\tg_smoothClients;\nextern\tvmCvar_t\tpmove_fixed;\nextern\tvmCvar_t\tpmove_msec;\nextern\tvmCvar_t\tg_rankings;\nextern\tvmCvar_t\tg_enableDust;\nextern\tvmCvar_t\tg_enableBreath;\nextern\tvmCvar_t\tg_singlePlayer;\nextern\tvmCvar_t\tg_proxMineTimeout;\n\nvoid\ttrap_Printf( const char *fmt );\nvoid\ttrap_Error( const char *fmt );\nint\t\ttrap_Milliseconds( void );\nint\t\ttrap_Argc( void );\nvoid\ttrap_Argv( int n, char *buffer, int bufferLength );\nvoid\ttrap_Args( char *buffer, int bufferLength );\nint\t\ttrap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode );\nvoid\ttrap_FS_Read( void *buffer, int len, fileHandle_t f );\nvoid\ttrap_FS_Write( const void *buffer, int len, fileHandle_t f );\nvoid\ttrap_FS_FCloseFile( fileHandle_t f );\nint\t\ttrap_FS_GetFileList( const char *path, const char *extension, char *listbuf, int bufsize );\nint\t\ttrap_FS_Seek( fileHandle_t f, long offset, int origin ); // fsOrigin_t\nvoid\ttrap_SendConsoleCommand( int exec_when, const char *text );\nvoid\ttrap_Cvar_Register( vmCvar_t *cvar, const char *var_name, const char *value, int flags );\nvoid\ttrap_Cvar_Update( vmCvar_t *cvar );\nvoid\ttrap_Cvar_Set( const char *var_name, const char *value );\nint\t\ttrap_Cvar_VariableIntegerValue( const char *var_name );\nfloat\ttrap_Cvar_VariableValue( const char *var_name );\nvoid\ttrap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize );\nvoid\ttrap_LocateGameData( gentity_t *gEnts, int numGEntities, int sizeofGEntity_t, playerState_t *gameClients, int sizeofGameClient );\nvoid\ttrap_DropClient( int clientNum, const char *reason );\nvoid\ttrap_SendServerCommand( int clientNum, const char *text );\nvoid\ttrap_SetConfigstring( int num, const char *string );\nvoid\ttrap_GetConfigstring( int num, char *buffer, int bufferSize );\nvoid\ttrap_GetUserinfo( int num, char *buffer, int bufferSize );\nvoid\ttrap_SetUserinfo( int num, const char *buffer );\nvoid\ttrap_GetServerinfo( char *buffer, int bufferSize );\nvoid\ttrap_SetBrushModel( gentity_t *ent, const char *name );\nvoid\ttrap_Trace( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentmask );\nint\t\ttrap_PointContents( const vec3_t point, int passEntityNum );\nqboolean trap_InPVS( const vec3_t p1, const vec3_t p2 );\nqboolean trap_InPVSIgnorePortals( const vec3_t p1, const vec3_t p2 );\nvoid\ttrap_AdjustAreaPortalState( gentity_t *ent, qboolean open );\nqboolean trap_AreasConnected( int area1, int area2 );\nvoid\ttrap_LinkEntity( gentity_t *ent );\nvoid\ttrap_UnlinkEntity( gentity_t *ent );\nint\t\ttrap_EntitiesInBox( const vec3_t mins, const vec3_t maxs, int *entityList, int maxcount );\nqboolean trap_EntityContact( const vec3_t mins, const vec3_t maxs, const gentity_t *ent );\nint\t\ttrap_BotAllocateClient( void );\nvoid\ttrap_BotFreeClient( int clientNum );\nvoid\ttrap_GetUsercmd( int clientNum, usercmd_t *cmd );\nqboolean\ttrap_GetEntityToken( char *buffer, int bufferSize );\n\nint\t\ttrap_DebugPolygonCreate(int color, int numPoints, vec3_t *points);\nvoid\ttrap_DebugPolygonDelete(int id);\n\nint\t\ttrap_BotLibSetup( void );\nint\t\ttrap_BotLibShutdown( void );\nint\t\ttrap_BotLibVarSet(char *var_name, char *value);\nint\t\ttrap_BotLibVarGet(char *var_name, char *value, int size);\nint\t\ttrap_BotLibDefine(char *string);\nint\t\ttrap_BotLibStartFrame(float time);\nint\t\ttrap_BotLibLoadMap(const char *mapname);\nint\t\ttrap_BotLibUpdateEntity(int ent, void /* struct bot_updateentity_s */ *bue);\nint\t\ttrap_BotLibTest(int parm0, char *parm1, vec3_t parm2, vec3_t parm3);\n\nint\t\ttrap_BotGetSnapshotEntity( int clientNum, int sequence );\nint\t\ttrap_BotGetServerCommand(int clientNum, char *message, int size);\nvoid\ttrap_BotUserCommand(int client, usercmd_t *ucmd);\n\nint\t\ttrap_AAS_BBoxAreas(vec3_t absmins, vec3_t absmaxs, int *areas, int maxareas);\nint\t\ttrap_AAS_AreaInfo( int areanum, void /* struct aas_areainfo_s */ *info );\nvoid\ttrap_AAS_EntityInfo(int entnum, void /* struct aas_entityinfo_s */ *info);\n\nint\t\ttrap_AAS_Initialized(void);\nvoid\ttrap_AAS_PresenceTypeBoundingBox(int presencetype, vec3_t mins, vec3_t maxs);\nfloat\ttrap_AAS_Time(void);\n\nint\t\ttrap_AAS_PointAreaNum(vec3_t point);\nint\t\ttrap_AAS_PointReachabilityAreaIndex(vec3_t point);\nint\t\ttrap_AAS_TraceAreas(vec3_t start, vec3_t end, int *areas, vec3_t *points, int maxareas);\n\nint\t\ttrap_AAS_PointContents(vec3_t point);\nint\t\ttrap_AAS_NextBSPEntity(int ent);\nint\t\ttrap_AAS_ValueForBSPEpairKey(int ent, char *key, char *value, int size);\nint\t\ttrap_AAS_VectorForBSPEpairKey(int ent, char *key, vec3_t v);\nint\t\ttrap_AAS_FloatForBSPEpairKey(int ent, char *key, float *value);\nint\t\ttrap_AAS_IntForBSPEpairKey(int ent, char *key, int *value);\n\nint\t\ttrap_AAS_AreaReachability(int areanum);\n\nint\t\ttrap_AAS_AreaTravelTimeToGoalArea(int areanum, vec3_t origin, int goalareanum, int travelflags);\nint\t\ttrap_AAS_EnableRoutingArea( int areanum, int enable );\nint\t\ttrap_AAS_PredictRoute(void /*struct aas_predictroute_s*/ *route, int areanum, vec3_t origin,\n\t\t\t\t\t\t\tint goalareanum, int travelflags, int maxareas, int maxtime,\n\t\t\t\t\t\t\tint stopevent, int stopcontents, int stoptfl, int stopareanum);\n\nint\t\ttrap_AAS_AlternativeRouteGoals(vec3_t start, int startareanum, vec3_t goal, int goalareanum, int travelflags,\n\t\t\t\t\t\t\t\t\t\tvoid /*struct aas_altroutegoal_s*/ *altroutegoals, int maxaltroutegoals,\n\t\t\t\t\t\t\t\t\t\tint type);\nint\t\ttrap_AAS_Swimming(vec3_t origin);\nint\t\ttrap_AAS_PredictClientMovement(void /* aas_clientmove_s */ *move, int entnum, vec3_t origin, int presencetype, int onground, vec3_t velocity, vec3_t cmdmove, int cmdframes, int maxframes, float frametime, int stopevent, int stopareanum, int visualize);\n\n\nvoid\ttrap_EA_Say(int client, char *str);\nvoid\ttrap_EA_SayTeam(int client, char *str);\nvoid\ttrap_EA_Command(int client, char *command);\n\nvoid\ttrap_EA_Action(int client, int action);\nvoid\ttrap_EA_Gesture(int client);\nvoid\ttrap_EA_Talk(int client);\nvoid\ttrap_EA_Attack(int client);\nvoid\ttrap_EA_Use(int client);\nvoid\ttrap_EA_Respawn(int client);\nvoid\ttrap_EA_Crouch(int client);\nvoid\ttrap_EA_MoveUp(int client);\nvoid\ttrap_EA_MoveDown(int client);\nvoid\ttrap_EA_MoveForward(int client);\nvoid\ttrap_EA_MoveBack(int client);\nvoid\ttrap_EA_MoveLeft(int client);\nvoid\ttrap_EA_MoveRight(int client);\nvoid\ttrap_EA_SelectWeapon(int client, int weapon);\nvoid\ttrap_EA_Jump(int client);\nvoid\ttrap_EA_DelayedJump(int client);\nvoid\ttrap_EA_Move(int client, vec3_t dir, float speed);\nvoid\ttrap_EA_View(int client, vec3_t viewangles);\n\nvoid\ttrap_EA_EndRegular(int client, float thinktime);\nvoid\ttrap_EA_GetInput(int client, float thinktime, void /* struct bot_input_s */ *input);\nvoid\ttrap_EA_ResetInput(int client);\n\n\nint\t\ttrap_BotLoadCharacter(char *charfile, float skill);\nvoid\ttrap_BotFreeCharacter(int character);\nfloat\ttrap_Characteristic_Float(int character, int index);\nfloat\ttrap_Characteristic_BFloat(int character, int index, float min, float max);\nint\t\ttrap_Characteristic_Integer(int character, int index);\nint\t\ttrap_Characteristic_BInteger(int character, int index, int min, int max);\nvoid\ttrap_Characteristic_String(int character, int index, char *buf, int size);\n\nint\t\ttrap_BotAllocChatState(void);\nvoid\ttrap_BotFreeChatState(int handle);\nvoid\ttrap_BotQueueConsoleMessage(int chatstate, int type, char *message);\nvoid\ttrap_BotRemoveConsoleMessage(int chatstate, int handle);\nint\t\ttrap_BotNextConsoleMessage(int chatstate, void /* struct bot_consolemessage_s */ *cm);\nint\t\ttrap_BotNumConsoleMessages(int chatstate);\nvoid\ttrap_BotInitialChat(int chatstate, char *type, int mcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7 );\nint\t\ttrap_BotNumInitialChats(int chatstate, char *type);\nint\t\ttrap_BotReplyChat(int chatstate, char *message, int mcontext, int vcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7 );\nint\t\ttrap_BotChatLength(int chatstate);\nvoid\ttrap_BotEnterChat(int chatstate, int client, int sendto);\nvoid\ttrap_BotGetChatMessage(int chatstate, char *buf, int size);\nint\t\ttrap_StringContains(char *str1, char *str2, int casesensitive);\nint\t\ttrap_BotFindMatch(char *str, void /* struct bot_match_s */ *match, unsigned long int context);\nvoid\ttrap_BotMatchVariable(void /* struct bot_match_s */ *match, int variable, char *buf, int size);\nvoid\ttrap_UnifyWhiteSpaces(char *string);\nvoid\ttrap_BotReplaceSynonyms(char *string, unsigned long int context);\nint\t\ttrap_BotLoadChatFile(int chatstate, char *chatfile, char *chatname);\nvoid\ttrap_BotSetChatGender(int chatstate, int gender);\nvoid\ttrap_BotSetChatName(int chatstate, char *name, int client);\nvoid\ttrap_BotResetGoalState(int goalstate);\nvoid\ttrap_BotRemoveFromAvoidGoals(int goalstate, int number);\nvoid\ttrap_BotResetAvoidGoals(int goalstate);\nvoid\ttrap_BotPushGoal(int goalstate, void /* struct bot_goal_s */ *goal);\nvoid\ttrap_BotPopGoal(int goalstate);\nvoid\ttrap_BotEmptyGoalStack(int goalstate);\nvoid\ttrap_BotDumpAvoidGoals(int goalstate);\nvoid\ttrap_BotDumpGoalStack(int goalstate);\nvoid\ttrap_BotGoalName(int number, char *name, int size);\nint\t\ttrap_BotGetTopGoal(int goalstate, void /* struct bot_goal_s */ *goal);\nint\t\ttrap_BotGetSecondGoal(int goalstate, void /* struct bot_goal_s */ *goal);\nint\t\ttrap_BotChooseLTGItem(int goalstate, vec3_t origin, int *inventory, int travelflags);\nint\t\ttrap_BotChooseNBGItem(int goalstate, vec3_t origin, int *inventory, int travelflags, void /* struct bot_goal_s */ *ltg, float maxtime);\nint\t\ttrap_BotTouchingGoal(vec3_t origin, void /* struct bot_goal_s */ *goal);\nint\t\ttrap_BotItemGoalInVisButNotVisible(int viewer, vec3_t eye, vec3_t viewangles, void /* struct bot_goal_s */ *goal);\nint\t\ttrap_BotGetNextCampSpotGoal(int num, void /* struct bot_goal_s */ *goal);\nint\t\ttrap_BotGetMapLocationGoal(char *name, void /* struct bot_goal_s */ *goal);\nint\t\ttrap_BotGetLevelItemGoal(int index, char *classname, void /* struct bot_goal_s */ *goal);\nfloat\ttrap_BotAvoidGoalTime(int goalstate, int number);\nvoid\ttrap_BotSetAvoidGoalTime(int goalstate, int number, float avoidtime);\nvoid\ttrap_BotInitLevelItems(void);\nvoid\ttrap_BotUpdateEntityItems(void);\nint\t\ttrap_BotLoadItemWeights(int goalstate, char *filename);\nvoid\ttrap_BotFreeItemWeights(int goalstate);\nvoid\ttrap_BotInterbreedGoalFuzzyLogic(int parent1, int parent2, int child);\nvoid\ttrap_BotSaveGoalFuzzyLogic(int goalstate, char *filename);\nvoid\ttrap_BotMutateGoalFuzzyLogic(int goalstate, float range);\nint\t\ttrap_BotAllocGoalState(int state);\nvoid\ttrap_BotFreeGoalState(int handle);\n\nvoid\ttrap_BotResetMoveState(int movestate);\nvoid\ttrap_BotMoveToGoal(void /* struct bot_moveresult_s */ *result, int movestate, void /* struct bot_goal_s */ *goal, int travelflags);\nint\t\ttrap_BotMoveInDirection(int movestate, vec3_t dir, float speed, int type);\nvoid\ttrap_BotResetAvoidReach(int movestate);\nvoid\ttrap_BotResetLastAvoidReach(int movestate);\nint\t\ttrap_BotReachabilityArea(vec3_t origin, int testground);\nint\t\ttrap_BotMovementViewTarget(int movestate, void /* struct bot_goal_s */ *goal, int travelflags, float lookahead, vec3_t target);\nint\t\ttrap_BotPredictVisiblePosition(vec3_t origin, int areanum, void /* struct bot_goal_s */ *goal, int travelflags, vec3_t target);\nint\t\ttrap_BotAllocMoveState(void);\nvoid\ttrap_BotFreeMoveState(int handle);\nvoid\ttrap_BotInitMoveState(int handle, void /* struct bot_initmove_s */ *initmove);\nvoid\ttrap_BotAddAvoidSpot(int movestate, vec3_t origin, float radius, int type);\n\nint\t\ttrap_BotChooseBestFightWeapon(int weaponstate, int *inventory);\nvoid\ttrap_BotGetWeaponInfo(int weaponstate, int weapon, void /* struct weaponinfo_s */ *weaponinfo);\nint\t\ttrap_BotLoadWeaponWeights(int weaponstate, char *filename);\nint\t\ttrap_BotAllocWeaponState(void);\nvoid\ttrap_BotFreeWeaponState(int weaponstate);\nvoid\ttrap_BotResetWeaponState(int weaponstate);\n\nint\t\ttrap_GeneticParentsAndChildSelection(int numranks, float *ranks, int *parent1, int *parent2, int *child);\n\nvoid\ttrap_SnapVector( float *v );\n\n"
  },
  {
    "path": "src/game/g_main.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n\n#include \"g_local.h\"\n\nlevel_locals_t\tlevel;\n\ntypedef struct {\n\tvmCvar_t\t*vmCvar;\n\tchar\t\t*cvarName;\n\tchar\t\t*defaultString;\n\tint\t\t\tcvarFlags;\n\tint\t\t\tmodificationCount;  // for tracking changes\n\tqboolean\ttrackChange;\t    // track this variable, and announce if changed\n  qboolean teamShader;        // track and if changed, update shader state\n} cvarTable_t;\n\ngentity_t\t\tg_entities[MAX_GENTITIES];\ngclient_t\t\tg_clients[MAX_CLIENTS];\n\nvmCvar_t\tg_gametype;\nvmCvar_t\tg_dmflags;\nvmCvar_t\tg_fraglimit;\nvmCvar_t\tg_timelimit;\nvmCvar_t\tg_capturelimit;\nvmCvar_t\tg_friendlyFire;\nvmCvar_t\tg_password;\nvmCvar_t\tg_needpass;\nvmCvar_t\tg_maxclients;\nvmCvar_t\tg_maxGameClients;\nvmCvar_t\tg_dedicated;\nvmCvar_t\tg_speed;\nvmCvar_t\tg_gravity;\nvmCvar_t\tg_cheats;\nvmCvar_t\tg_knockback;\nvmCvar_t\tg_quadfactor;\nvmCvar_t\tg_forcerespawn;\nvmCvar_t\tg_inactivity;\nvmCvar_t\tg_debugMove;\nvmCvar_t\tg_debugDamage;\nvmCvar_t\tg_debugAlloc;\nvmCvar_t\tg_weaponRespawn;\nvmCvar_t\tg_weaponTeamRespawn;\nvmCvar_t\tg_motd;\nvmCvar_t\tg_synchronousClients;\nvmCvar_t\tg_warmup;\nvmCvar_t\tg_doWarmup;\nvmCvar_t\tg_restarted;\nvmCvar_t\tg_log;\nvmCvar_t\tg_logSync;\nvmCvar_t\tg_blood;\nvmCvar_t\tg_podiumDist;\nvmCvar_t\tg_podiumDrop;\nvmCvar_t\tg_allowVote;\nvmCvar_t\tg_teamAutoJoin;\nvmCvar_t\tg_teamForceBalance;\nvmCvar_t\tg_banIPs;\nvmCvar_t\tg_filterBan;\nvmCvar_t\tg_smoothClients;\nvmCvar_t\tpmove_fixed;\nvmCvar_t\tpmove_msec;\nvmCvar_t\tg_rankings;\nvmCvar_t\tg_listEntity;\n\n// bk001129 - made static to avoid aliasing\nstatic cvarTable_t\t\tgameCvarTable[] = {\n\t// don't override the cheat state set by the system\n\t{ &g_cheats, \"sv_cheats\", \"\", 0, 0, qfalse },\n\n\t// noset vars\n\t{ NULL, \"gamename\", GAMEVERSION , CVAR_SERVERINFO | CVAR_ROM, 0, qfalse  },\n\t{ NULL, \"gamedate\", __DATE__ , CVAR_ROM, 0, qfalse  },\n\t{ &g_restarted, \"g_restarted\", \"0\", CVAR_ROM, 0, qfalse  },\n\t{ NULL, \"sv_mapname\", \"\", CVAR_SERVERINFO | CVAR_ROM, 0, qfalse  },\n\n\t// latched vars\n\t{ &g_gametype, \"g_gametype\", \"0\", CVAR_SERVERINFO | CVAR_USERINFO | CVAR_LATCH, 0, qfalse  },\n\n\t{ &g_maxclients, \"sv_maxclients\", \"8\", CVAR_SERVERINFO | CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse  },\n\t{ &g_maxGameClients, \"g_maxGameClients\", \"0\", CVAR_SERVERINFO | CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse  },\n\n\t// change anytime vars\n\t{ &g_dmflags, \"dmflags\", \"0\", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qtrue  },\n\t{ &g_fraglimit, \"fraglimit\", \"20\", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue },\n\t{ &g_timelimit, \"timelimit\", \"0\", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue },\n\t{ &g_capturelimit, \"capturelimit\", \"8\", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue },\n\n\t{ &g_synchronousClients, \"g_synchronousClients\", \"0\", CVAR_SYSTEMINFO, 0, qfalse  },\n\n\t{ &g_friendlyFire, \"g_friendlyFire\", \"0\", CVAR_ARCHIVE, 0, qtrue  },\n\n\t{ &g_teamAutoJoin, \"g_teamAutoJoin\", \"0\", CVAR_ARCHIVE  },\n\t{ &g_teamForceBalance, \"g_teamForceBalance\", \"0\", CVAR_ARCHIVE  },\n\n\t{ &g_warmup, \"g_warmup\", \"20\", CVAR_ARCHIVE, 0, qtrue  },\n\t{ &g_doWarmup, \"g_doWarmup\", \"0\", 0, 0, qtrue  },\n\t{ &g_log, \"g_log\", \"games.log\", CVAR_ARCHIVE, 0, qfalse  },\n\t{ &g_logSync, \"g_logSync\", \"0\", CVAR_ARCHIVE, 0, qfalse  },\n\n\t{ &g_password, \"g_password\", \"\", CVAR_USERINFO, 0, qfalse  },\n\n\t{ &g_banIPs, \"g_banIPs\", \"\", CVAR_ARCHIVE, 0, qfalse  },\n\t{ &g_filterBan, \"g_filterBan\", \"1\", CVAR_ARCHIVE, 0, qfalse  },\n\n\t{ &g_needpass, \"g_needpass\", \"0\", CVAR_SERVERINFO | CVAR_ROM, 0, qfalse },\n\n\t{ &g_dedicated, \"dedicated\", \"0\", 0, 0, qfalse  },\n\n\t{ &g_speed, \"g_speed\", \"320\", 0, 0, qtrue  },\n\t{ &g_gravity, \"g_gravity\", \"800\", 0, 0, qtrue  },\n\t{ &g_knockback, \"g_knockback\", \"1000\", 0, 0, qtrue  },\n\t{ &g_quadfactor, \"g_quadfactor\", \"3\", 0, 0, qtrue  },\n\t{ &g_weaponRespawn, \"g_weaponrespawn\", \"5\", 0, 0, qtrue  },\n\t{ &g_weaponTeamRespawn, \"g_weaponTeamRespawn\", \"30\", 0, 0, qtrue },\n\t{ &g_forcerespawn, \"g_forcerespawn\", \"20\", 0, 0, qtrue },\n\t{ &g_inactivity, \"g_inactivity\", \"0\", 0, 0, qtrue },\n\t{ &g_debugMove, \"g_debugMove\", \"0\", 0, 0, qfalse },\n\t{ &g_debugDamage, \"g_debugDamage\", \"0\", 0, 0, qfalse },\n\t{ &g_debugAlloc, \"g_debugAlloc\", \"0\", 0, 0, qfalse },\n\t{ &g_motd, \"g_motd\", \"\", 0, 0, qfalse },\n\t{ &g_blood, \"com_blood\", \"1\", 0, 0, qfalse },\n\n\t{ &g_podiumDist, \"g_podiumDist\", \"80\", 0, 0, qfalse },\n\t{ &g_podiumDrop, \"g_podiumDrop\", \"70\", 0, 0, qfalse },\n\n\t{ &g_allowVote, \"g_allowVote\", \"1\", CVAR_ARCHIVE, 0, qfalse },\n\t{ &g_listEntity, \"g_listEntity\", \"0\", 0, 0, qfalse },\n\n\t{ &g_smoothClients, \"g_smoothClients\", \"1\", 0, 0, qfalse},\n\t{ &pmove_fixed, \"pmove_fixed\", \"0\", CVAR_SYSTEMINFO, 0, qfalse},\n\t{ &pmove_msec, \"pmove_msec\", \"8\", CVAR_SYSTEMINFO, 0, qfalse},\n\n\t{ &g_rankings, \"g_rankings\", \"0\", 0, 0, qfalse}\n\n};\n\n// bk001129 - made static to avoid aliasing\nstatic int gameCvarTableSize = sizeof( gameCvarTable ) / sizeof( gameCvarTable[0] );\n\n\nvoid G_InitGame( int levelTime, int randomSeed, int restart );\nvoid G_RunFrame( int levelTime );\nvoid G_ShutdownGame( int restart );\nvoid CheckExitRules( void );\n\n\n/*\n================\nvmMain\n\nThis is the only way control passes into the module.\nThis must be the very first function compiled into the .q3vm file\n================\n*/\nintptr_t vmMain( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10, int arg11  ) {\n\tswitch ( command ) {\n\tcase GAME_INIT:\n\t\tG_InitGame( arg0, arg1, arg2 );\n\t\treturn 0;\n\tcase GAME_SHUTDOWN:\n\t\tG_ShutdownGame( arg0 );\n\t\treturn 0;\n\tcase GAME_CLIENT_CONNECT:\n\t\treturn (intptr_t)ClientConnect( arg0, arg1, arg2 );\n\tcase GAME_CLIENT_THINK:\n\t\tClientThink( arg0 );\n\t\treturn 0;\n\tcase GAME_CLIENT_USERINFO_CHANGED:\n\t\tClientUserinfoChanged( arg0 );\n\t\treturn 0;\n\tcase GAME_CLIENT_DISCONNECT:\n\t\tClientDisconnect( arg0 );\n\t\treturn 0;\n\tcase GAME_CLIENT_BEGIN:\n\t\tClientBegin( arg0 );\n\t\treturn 0;\n\tcase GAME_CLIENT_COMMAND:\n\t\tClientCommand( arg0 );\n\t\treturn 0;\n\tcase GAME_RUN_FRAME:\n\t\tG_RunFrame( arg0 );\n\t\treturn 0;\n\tcase GAME_CONSOLE_COMMAND:\n\t\treturn ConsoleCommand();\n\tcase BOTAI_START_FRAME:\n\t\treturn BotAIStartFrame( arg0 );\n\t}\n\n\treturn -1;\n}\n\n\nvoid QDECL G_Printf( const char *fmt, ... ) {\n\tva_list\t\targptr;\n\tchar\t\ttext[1024];\n\n\tva_start (argptr, fmt);\n\tvsprintf (text, fmt, argptr);\n\tva_end (argptr);\n\n\ttrap_Printf( text );\n}\n\nvoid QDECL G_Error( const char *fmt, ... ) {\n\tva_list\t\targptr;\n\tchar\t\ttext[1024];\n\n\tva_start (argptr, fmt);\n\tvsprintf (text, fmt, argptr);\n\tva_end (argptr);\n\n\ttrap_Error( text );\n}\n\n/*\n================\nG_FindTeams\n\nChain together all entities with a matching team field.\nEntity teams are used for item groups and multi-entity mover groups.\n\nAll but the first will have the FL_TEAMSLAVE flag set and teammaster field set\nAll but the last will have the teamchain field set to the next one\n================\n*/\nvoid G_FindTeams( void ) {\n\tgentity_t\t*e, *e2;\n\tint\t\ti, j;\n\tint\t\tc, c2;\n\n\tc = 0;\n\tc2 = 0;\n\tfor ( i=1, e=g_entities+i ; i < level.num_entities ; i++,e++ ){\n\t\tif (!e->inuse)\n\t\t\tcontinue;\n\t\tif (!e->team)\n\t\t\tcontinue;\n\t\tif (e->flags & FL_TEAMSLAVE)\n\t\t\tcontinue;\n\t\te->teammaster = e;\n\t\tc++;\n\t\tc2++;\n\t\tfor (j=i+1, e2=e+1 ; j < level.num_entities ; j++,e2++)\n\t\t{\n\t\t\tif (!e2->inuse)\n\t\t\t\tcontinue;\n\t\t\tif (!e2->team)\n\t\t\t\tcontinue;\n\t\t\tif (e2->flags & FL_TEAMSLAVE)\n\t\t\t\tcontinue;\n\t\t\tif (!strcmp(e->team, e2->team))\n\t\t\t{\n\t\t\t\tc2++;\n\t\t\t\te2->teamchain = e->teamchain;\n\t\t\t\te->teamchain = e2;\n\t\t\t\te2->teammaster = e;\n\t\t\t\te2->flags |= FL_TEAMSLAVE;\n\n\t\t\t\t// make sure that targets only point at the master\n\t\t\t\tif ( e2->targetname ) {\n\t\t\t\t\te->targetname = e2->targetname;\n\t\t\t\t\te2->targetname = NULL;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tG_Printf (\"%i teams with %i entities\\n\", c, c2);\n}\n\nvoid G_RemapTeamShaders() {\n}\n\n\n/*\n=================\nG_RegisterCvars\n=================\n*/\nvoid G_RegisterCvars( void ) {\n\tint\t\t\ti;\n\tcvarTable_t\t*cv;\n\tqboolean remapped = qfalse;\n\n\tfor ( i = 0, cv = gameCvarTable ; i < gameCvarTableSize ; i++, cv++ ) {\n\t\ttrap_Cvar_Register( cv->vmCvar, cv->cvarName,\n\t\t\tcv->defaultString, cv->cvarFlags );\n\t\tif ( cv->vmCvar )\n\t\t\tcv->modificationCount = cv->vmCvar->modificationCount;\n\n\t\tif (cv->teamShader) {\n\t\t\tremapped = qtrue;\n\t\t}\n\t}\n\n\tif (remapped) {\n\t\tG_RemapTeamShaders();\n\t}\n\n\t// check some things\n\tif ( g_gametype.integer < 0 || g_gametype.integer >= GT_MAX_GAME_TYPE ) {\n\t\tG_Printf( \"g_gametype %i is out of range, defaulting to 0\\n\", g_gametype.integer );\n\t\ttrap_Cvar_Set( \"g_gametype\", \"0\" );\n\t}\n\n\tlevel.warmupModificationCount = g_warmup.modificationCount;\n}\n\n/*\n=================\nG_UpdateCvars\n=================\n*/\nvoid G_UpdateCvars( void ) {\n\tint\t\t\ti;\n\tcvarTable_t\t*cv;\n\tqboolean remapped = qfalse;\n\n\tfor ( i = 0, cv = gameCvarTable ; i < gameCvarTableSize ; i++, cv++ ) {\n\t\tif ( cv->vmCvar ) {\n\t\t\ttrap_Cvar_Update( cv->vmCvar );\n\n\t\t\tif ( cv->modificationCount != cv->vmCvar->modificationCount ) {\n\t\t\t\tcv->modificationCount = cv->vmCvar->modificationCount;\n\n\t\t\t\tif ( cv->trackChange ) {\n\t\t\t\t\ttrap_SendServerCommand( -1, va(\"print \\\"Server: %s changed to %s\\n\\\"\", \n\t\t\t\t\t\tcv->cvarName, cv->vmCvar->string ) );\n\t\t\t\t}\n\n\t\t\t\tif (cv->teamShader) {\n\t\t\t\t\tremapped = qtrue;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif (remapped) {\n\t\tG_RemapTeamShaders();\n\t}\n}\n\n/*\n============\nG_InitGame\n\n============\n*/\nvoid G_InitGame( int levelTime, int randomSeed, int restart ) {\n\tint\t\t\t\t\ti;\n\n\tG_Printf (\"------- Game Initialization -------\\n\");\n\tG_Printf (\"gamename: %s\\n\", GAMEVERSION);\n\tG_Printf (\"gamedate: %s\\n\", __DATE__);\n\n\tsrand( randomSeed );\n\n\tG_RegisterCvars();\n\n\tG_ProcessIPBans();\n\n\tG_InitMemory();\n\n\t// set some level globals\n\tmemset( &level, 0, sizeof( level ) );\n\tlevel.time = levelTime;\n\tlevel.startTime = levelTime;\n\n\tlevel.snd_fry = G_SoundIndex(\"sound/player/fry.wav\");\t// FIXME standing in lava / slime\n\n\tif ( g_gametype.integer != GT_SINGLE_PLAYER && g_log.string[0] ) {\n\t\tif ( g_logSync.integer ) {\n\t\t\ttrap_FS_FOpenFile( g_log.string, &level.logFile, FS_APPEND_SYNC );\n\t\t} else {\n\t\t\ttrap_FS_FOpenFile( g_log.string, &level.logFile, FS_APPEND );\n\t\t}\n\t\tif ( !level.logFile ) {\n\t\t\tG_Printf( \"WARNING: Couldn't open logfile: %s\\n\", g_log.string );\n\t\t} else {\n\t\t\tchar\tserverinfo[MAX_INFO_STRING];\n\n\t\t\ttrap_GetServerinfo( serverinfo, sizeof( serverinfo ) );\n\n\t\t\tG_LogPrintf(\"------------------------------------------------------------\\n\" );\n\t\t\tG_LogPrintf(\"InitGame: %s\\n\", serverinfo );\n\t\t}\n\t} else {\n\t\tG_Printf( \"Not logging to disk.\\n\" );\n\t}\n\n\tG_InitWorldSession();\n\n\t// initialize all entities for this game\n\tmemset( g_entities, 0, MAX_GENTITIES * sizeof(g_entities[0]) );\n\tlevel.gentities = g_entities;\n\n\t// initialize all clients for this game\n\tlevel.maxclients = g_maxclients.integer;\n\tmemset( g_clients, 0, MAX_CLIENTS * sizeof(g_clients[0]) );\n\tlevel.clients = g_clients;\n\n\t// set client fields on player ents\n\tfor ( i=0 ; i<level.maxclients ; i++ ) {\n\t\tg_entities[i].client = level.clients + i;\n\t}\n\n\t// always leave room for the max number of clients,\n\t// even if they aren't all used, so numbers inside that\n\t// range are NEVER anything but clients\n\tlevel.num_entities = MAX_CLIENTS;\n\n\t// let the server system know where the entites are\n\ttrap_LocateGameData( level.gentities, level.num_entities, sizeof( gentity_t ), \n\t\t&level.clients[0].ps, sizeof( level.clients[0] ) );\n\n\t// reserve some spots for dead player bodies\n\tInitBodyQue();\n\n\tClearRegisteredItems();\n\n\t// parse the key/value pairs and spawn gentities\n\tG_SpawnEntitiesFromString();\n\n\t// general initialization\n\tG_FindTeams();\n\n\t// make sure we have flags for CTF, etc\n\tif( g_gametype.integer >= GT_TEAM ) {\n\t\tG_CheckTeamItems();\n\t}\n\n\tSaveRegisteredItems();\n\n\tG_Printf (\"-----------------------------------\\n\");\n\n\tif( g_gametype.integer == GT_SINGLE_PLAYER || trap_Cvar_VariableIntegerValue( \"com_buildScript\" ) ) {\n\t\tG_ModelIndex( SP_PODIUM_MODEL );\n\t\tG_SoundIndex( \"sound/player/gurp1.wav\" );\n\t\tG_SoundIndex( \"sound/player/gurp2.wav\" );\n\t}\n\n\tif ( trap_Cvar_VariableIntegerValue( \"bot_enable\" ) ) {\n\t\tBotAISetup( restart );\n\t\tBotAILoadMap( restart );\n\t\tG_InitBots( restart );\n\t}\n\n\tG_RemapTeamShaders();\n\n}\n\n\n\n/*\n=================\nG_ShutdownGame\n=================\n*/\nvoid G_ShutdownGame( int restart ) {\n\tG_Printf (\"==== ShutdownGame ====\\n\");\n\n\tif ( level.logFile ) {\n\t\tG_LogPrintf(\"ShutdownGame:\\n\" );\n\t\tG_LogPrintf(\"------------------------------------------------------------\\n\" );\n\t\ttrap_FS_FCloseFile( level.logFile );\n\t}\n\n\t// write all the client session data so we can get it back\n\tG_WriteSessionData();\n\n\tif ( trap_Cvar_VariableIntegerValue( \"bot_enable\" ) ) {\n\t\tBotAIShutdown( restart );\n\t}\n}\n\n\n\n//===================================================================\n\n#ifndef GAME_HARD_LINKED\n// this is only here so the functions in q_shared.c and bg_*.c can link\n\nvoid QDECL Com_Error ( int level, const char *error, ... ) {\n\tva_list\t\targptr;\n\tchar\t\ttext[1024];\n\n\tva_start (argptr, error);\n\tvsprintf (text, error, argptr);\n\tva_end (argptr);\n\n\tG_Error( \"%s\", text);\n}\n\nvoid QDECL Com_Printf( const char *msg, ... ) {\n\tva_list\t\targptr;\n\tchar\t\ttext[1024];\n\n\tva_start (argptr, msg);\n\tvsprintf (text, msg, argptr);\n\tva_end (argptr);\n\n\tG_Printf (\"%s\", text);\n}\n\n#endif\n\n/*\n========================================================================\n\nPLAYER COUNTING / SCORE SORTING\n\n========================================================================\n*/\n\n/*\n=============\nAddTournamentPlayer\n\nIf there are less than two tournament players, put a\nspectator in the game and restart\n=============\n*/\nvoid AddTournamentPlayer( void ) {\n\tint\t\t\ti;\n\tgclient_t\t*client;\n\tgclient_t\t*nextInLine;\n\n\tif ( level.numPlayingClients >= 2 ) {\n\t\treturn;\n\t}\n\n\t// never change during intermission\n\tif ( level.intermissiontime ) {\n\t\treturn;\n\t}\n\n\tnextInLine = NULL;\n\n\tfor ( i = 0 ; i < level.maxclients ; i++ ) {\n\t\tclient = &level.clients[i];\n\t\tif ( client->pers.connected != CON_CONNECTED ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( client->sess.sessionTeam != TEAM_SPECTATOR ) {\n\t\t\tcontinue;\n\t\t}\n\t\t// never select the dedicated follow or scoreboard clients\n\t\tif ( client->sess.spectatorState == SPECTATOR_SCOREBOARD || \n\t\t\tclient->sess.spectatorClient < 0  ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif ( !nextInLine || client->sess.spectatorTime < nextInLine->sess.spectatorTime ) {\n\t\t\tnextInLine = client;\n\t\t}\n\t}\n\n\tif ( !nextInLine ) {\n\t\treturn;\n\t}\n\n\tlevel.warmupTime = -1;\n\n\t// set them to free-for-all team\n\tSetTeam( &g_entities[ nextInLine - level.clients ], \"f\" );\n}\n\n/*\n=======================\nRemoveTournamentLoser\n\nMake the loser a spectator at the back of the line\n=======================\n*/\nvoid RemoveTournamentLoser( void ) {\n\tint\t\t\tclientNum;\n\n\tif ( level.numPlayingClients != 2 ) {\n\t\treturn;\n\t}\n\n\tclientNum = level.sortedClients[1];\n\n\tif ( level.clients[ clientNum ].pers.connected != CON_CONNECTED ) {\n\t\treturn;\n\t}\n\n\t// make them a spectator\n\tSetTeam( &g_entities[ clientNum ], \"s\" );\n}\n\n/*\n=======================\nRemoveTournamentWinner\n=======================\n*/\nvoid RemoveTournamentWinner( void ) {\n\tint\t\t\tclientNum;\n\n\tif ( level.numPlayingClients != 2 ) {\n\t\treturn;\n\t}\n\n\tclientNum = level.sortedClients[0];\n\n\tif ( level.clients[ clientNum ].pers.connected != CON_CONNECTED ) {\n\t\treturn;\n\t}\n\n\t// make them a spectator\n\tSetTeam( &g_entities[ clientNum ], \"s\" );\n}\n\n/*\n=======================\nAdjustTournamentScores\n=======================\n*/\nvoid AdjustTournamentScores( void ) {\n\tint\t\t\tclientNum;\n\n\tclientNum = level.sortedClients[0];\n\tif ( level.clients[ clientNum ].pers.connected == CON_CONNECTED ) {\n\t\tlevel.clients[ clientNum ].sess.wins++;\n\t\tClientUserinfoChanged( clientNum );\n\t}\n\n\tclientNum = level.sortedClients[1];\n\tif ( level.clients[ clientNum ].pers.connected == CON_CONNECTED ) {\n\t\tlevel.clients[ clientNum ].sess.losses++;\n\t\tClientUserinfoChanged( clientNum );\n\t}\n\n}\n\n/*\n=============\nSortRanks\n\n=============\n*/\nint QDECL SortRanks( const void *a, const void *b ) {\n\tgclient_t\t*ca, *cb;\n\n\tca = &level.clients[*(int *)a];\n\tcb = &level.clients[*(int *)b];\n\n\t// sort special clients last\n\tif ( ca->sess.spectatorState == SPECTATOR_SCOREBOARD || ca->sess.spectatorClient < 0 ) {\n\t\treturn 1;\n\t}\n\tif ( cb->sess.spectatorState == SPECTATOR_SCOREBOARD || cb->sess.spectatorClient < 0  ) {\n\t\treturn -1;\n\t}\n\n\t// then connecting clients\n\tif ( ca->pers.connected == CON_CONNECTING ) {\n\t\treturn 1;\n\t}\n\tif ( cb->pers.connected == CON_CONNECTING ) {\n\t\treturn -1;\n\t}\n\n\n\t// then spectators\n\tif ( ca->sess.sessionTeam == TEAM_SPECTATOR && cb->sess.sessionTeam == TEAM_SPECTATOR ) {\n\t\tif ( ca->sess.spectatorTime < cb->sess.spectatorTime ) {\n\t\t\treturn -1;\n\t\t}\n\t\tif ( ca->sess.spectatorTime > cb->sess.spectatorTime ) {\n\t\t\treturn 1;\n\t\t}\n\t\treturn 0;\n\t}\n\tif ( ca->sess.sessionTeam == TEAM_SPECTATOR ) {\n\t\treturn 1;\n\t}\n\tif ( cb->sess.sessionTeam == TEAM_SPECTATOR ) {\n\t\treturn -1;\n\t}\n\n\t// then sort by score\n\tif ( ca->ps.persistant[PERS_SCORE]\n\t\t> cb->ps.persistant[PERS_SCORE] ) {\n\t\treturn -1;\n\t}\n\tif ( ca->ps.persistant[PERS_SCORE]\n\t\t< cb->ps.persistant[PERS_SCORE] ) {\n\t\treturn 1;\n\t}\n\treturn 0;\n}\n\n/*\n============\nCalculateRanks\n\nRecalculates the score ranks of all players\nThis will be called on every client connect, begin, disconnect, death,\nand team change.\n============\n*/\nvoid CalculateRanks( void ) {\n\tint\t\ti;\n\tint\t\trank;\n\tint\t\tscore;\n\tint\t\tnewScore;\n\tgclient_t\t*cl;\n\n\tlevel.follow1 = -1;\n\tlevel.follow2 = -1;\n\tlevel.numConnectedClients = 0;\n\tlevel.numNonSpectatorClients = 0;\n\tlevel.numPlayingClients = 0;\n\tlevel.numVotingClients = 0;\t\t// don't count bots\n\tfor ( i = 0; i < TEAM_NUM_TEAMS; i++ ) {\n\t\tlevel.numteamVotingClients[i] = 0;\n\t}\n\tfor ( i = 0 ; i < level.maxclients ; i++ ) {\n\t\tif ( level.clients[i].pers.connected != CON_DISCONNECTED ) {\n\t\t\tlevel.sortedClients[level.numConnectedClients] = i;\n\t\t\tlevel.numConnectedClients++;\n\n\t\t\tif ( level.clients[i].sess.sessionTeam != TEAM_SPECTATOR ) {\n\t\t\t\tlevel.numNonSpectatorClients++;\n\t\t\t\n\t\t\t\t// decide if this should be auto-followed\n\t\t\t\tif ( level.clients[i].pers.connected == CON_CONNECTED ) {\n\t\t\t\t\tlevel.numPlayingClients++;\n\t\t\t\t\tif ( !(g_entities[i].r.svFlags & SVF_BOT) ) {\n\t\t\t\t\t\tlevel.numVotingClients++;\n\t\t\t\t\t\tif ( level.clients[i].sess.sessionTeam == TEAM_RED )\n\t\t\t\t\t\t\tlevel.numteamVotingClients[0]++;\n\t\t\t\t\t\telse if ( level.clients[i].sess.sessionTeam == TEAM_BLUE )\n\t\t\t\t\t\t\tlevel.numteamVotingClients[1]++;\n\t\t\t\t\t}\n\t\t\t\t\tif ( level.follow1 == -1 ) {\n\t\t\t\t\t\tlevel.follow1 = i;\n\t\t\t\t\t} else if ( level.follow2 == -1 ) {\n\t\t\t\t\t\tlevel.follow2 = i;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tqsort( level.sortedClients, level.numConnectedClients, \n\t\tsizeof(level.sortedClients[0]), SortRanks );\n\n\t// set the rank value for all clients that are connected and not spectators\n\tif ( g_gametype.integer >= GT_TEAM ) {\n\t\t// in team games, rank is just the order of the teams, 0=red, 1=blue, 2=tied\n\t\tfor ( i = 0;  i < level.numConnectedClients; i++ ) {\n\t\t\tcl = &level.clients[ level.sortedClients[i] ];\n\t\t\tif ( level.teamScores[TEAM_RED] == level.teamScores[TEAM_BLUE] ) {\n\t\t\t\tcl->ps.persistant[PERS_RANK] = 2;\n\t\t\t} else if ( level.teamScores[TEAM_RED] > level.teamScores[TEAM_BLUE] ) {\n\t\t\t\tcl->ps.persistant[PERS_RANK] = 0;\n\t\t\t} else {\n\t\t\t\tcl->ps.persistant[PERS_RANK] = 1;\n\t\t\t}\n\t\t}\n\t} else {\t\n\t\trank = -1;\n\t\tscore = 0;\n\t\tfor ( i = 0;  i < level.numPlayingClients; i++ ) {\n\t\t\tcl = &level.clients[ level.sortedClients[i] ];\n\t\t\tnewScore = cl->ps.persistant[PERS_SCORE];\n\t\t\tif ( i == 0 || newScore != score ) {\n\t\t\t\trank = i;\n\t\t\t\t// assume we aren't tied until the next client is checked\n\t\t\t\tlevel.clients[ level.sortedClients[i] ].ps.persistant[PERS_RANK] = rank;\n\t\t\t} else {\n\t\t\t\t// we are tied with the previous client\n\t\t\t\tlevel.clients[ level.sortedClients[i-1] ].ps.persistant[PERS_RANK] = rank | RANK_TIED_FLAG;\n\t\t\t\tlevel.clients[ level.sortedClients[i] ].ps.persistant[PERS_RANK] = rank | RANK_TIED_FLAG;\n\t\t\t}\n\t\t\tscore = newScore;\n\t\t\tif ( g_gametype.integer == GT_SINGLE_PLAYER && level.numPlayingClients == 1 ) {\n\t\t\t\tlevel.clients[ level.sortedClients[i] ].ps.persistant[PERS_RANK] = rank | RANK_TIED_FLAG;\n\t\t\t}\n\t\t}\n\t}\n\n\t// set the CS_SCORES1/2 configstrings, which will be visible to everyone\n\tif ( g_gametype.integer >= GT_TEAM ) {\n\t\ttrap_SetConfigstring( CS_SCORES1, va(\"%i\", level.teamScores[TEAM_RED] ) );\n\t\ttrap_SetConfigstring( CS_SCORES2, va(\"%i\", level.teamScores[TEAM_BLUE] ) );\n\t} else {\n\t\tif ( level.numConnectedClients == 0 ) {\n\t\t\ttrap_SetConfigstring( CS_SCORES1, va(\"%i\", SCORE_NOT_PRESENT) );\n\t\t\ttrap_SetConfigstring( CS_SCORES2, va(\"%i\", SCORE_NOT_PRESENT) );\n\t\t} else if ( level.numConnectedClients == 1 ) {\n\t\t\ttrap_SetConfigstring( CS_SCORES1, va(\"%i\", level.clients[ level.sortedClients[0] ].ps.persistant[PERS_SCORE] ) );\n\t\t\ttrap_SetConfigstring( CS_SCORES2, va(\"%i\", SCORE_NOT_PRESENT) );\n\t\t} else {\n\t\t\ttrap_SetConfigstring( CS_SCORES1, va(\"%i\", level.clients[ level.sortedClients[0] ].ps.persistant[PERS_SCORE] ) );\n\t\t\ttrap_SetConfigstring( CS_SCORES2, va(\"%i\", level.clients[ level.sortedClients[1] ].ps.persistant[PERS_SCORE] ) );\n\t\t}\n\t}\n\n\t// see if it is time to end the level\n\tCheckExitRules();\n\n\t// if we are at the intermission, send the new info to everyone\n\tif ( level.intermissiontime ) {\n\t\tSendScoreboardMessageToAllClients();\n\t}\n}\n\n\n/*\n========================================================================\n\nMAP CHANGING\n\n========================================================================\n*/\n\n/*\n========================\nSendScoreboardMessageToAllClients\n\nDo this at BeginIntermission time and whenever ranks are recalculated\ndue to enters/exits/forced team changes\n========================\n*/\nvoid SendScoreboardMessageToAllClients( void ) {\n\tint\t\ti;\n\n\tfor ( i = 0 ; i < level.maxclients ; i++ ) {\n\t\tif ( level.clients[ i ].pers.connected == CON_CONNECTED ) {\n\t\t\tDeathmatchScoreboardMessage( g_entities + i );\n\t\t}\n\t}\n}\n\n/*\n========================\nMoveClientToIntermission\n\nWhen the intermission starts, this will be called for all players.\nIf a new client connects, this will be called after the spawn function.\n========================\n*/\nvoid MoveClientToIntermission( gentity_t *ent ) {\n\t// take out of follow mode if needed\n\tif ( ent->client->sess.spectatorState == SPECTATOR_FOLLOW ) {\n\t\tStopFollowing( ent );\n\t}\n\n\n\t// move to the spot\n\tVectorCopy( level.intermission_origin, ent->s.origin );\n\tVectorCopy( level.intermission_origin, ent->client->ps.origin );\n\tVectorCopy (level.intermission_angle, ent->client->ps.viewangles);\n\tent->client->ps.pm_type = PM_INTERMISSION;\n\n\t// clean up powerup info\n\tmemset( ent->client->ps.powerups, 0, sizeof(ent->client->ps.powerups) );\n\n\tent->client->ps.eFlags = 0;\n\tent->s.eFlags = 0;\n\tent->s.eType = ET_GENERAL;\n\tent->s.modelindex = 0;\n\tent->s.loopSound = 0;\n\tent->s.event = 0;\n\tent->r.contents = 0;\n}\n\n/*\n==================\nFindIntermissionPoint\n\nThis is also used for spectator spawns\n==================\n*/\nvoid FindIntermissionPoint( void ) {\n\tgentity_t\t*ent, *target;\n\tvec3_t\t\tdir;\n\n\t// find the intermission spot\n\tent = G_Find (NULL, FOFS(classname), \"info_player_intermission\");\n\tif ( !ent ) {\t// the map creator forgot to put in an intermission point...\n\t\tSelectSpawnPoint ( vec3_origin, level.intermission_origin, level.intermission_angle );\n\t} else {\n\t\tVectorCopy (ent->s.origin, level.intermission_origin);\n\t\tVectorCopy (ent->s.angles, level.intermission_angle);\n\t\t// if it has a target, look towards it\n\t\tif ( ent->target ) {\n\t\t\ttarget = G_PickTarget( ent->target );\n\t\t\tif ( target ) {\n\t\t\t\tVectorSubtract( target->s.origin, level.intermission_origin, dir );\n\t\t\t\tvectoangles( dir, level.intermission_angle );\n\t\t\t}\n\t\t}\n\t}\n\n}\n\n/*\n==================\nBeginIntermission\n==================\n*/\nvoid BeginIntermission( void ) {\n\tint\t\t\ti;\n\tgentity_t\t*client;\n\n\tif ( level.intermissiontime ) {\n\t\treturn;\t\t// already active\n\t}\n\n\t// if in tournement mode, change the wins / losses\n\tif ( g_gametype.integer == GT_TOURNAMENT ) {\n\t\tAdjustTournamentScores();\n\t}\n\n\tlevel.intermissiontime = level.time;\n\tFindIntermissionPoint();\n\n\t// if single player game\n\tif ( g_gametype.integer == GT_SINGLE_PLAYER ) {\n\t\tUpdateTournamentInfo();\n\t\tSpawnModelsOnVictoryPads();\n\t}\n\n\t// move all clients to the intermission point\n\tfor (i=0 ; i< level.maxclients ; i++) {\n\t\tclient = g_entities + i;\n\t\tif (!client->inuse)\n\t\t\tcontinue;\n\t\t// respawn if dead\n\t\tif (client->health <= 0) {\n\t\t\trespawn(client);\n\t\t}\n\t\tMoveClientToIntermission( client );\n\t}\n\n\t// send the current scoring to all clients\n\tSendScoreboardMessageToAllClients();\n\n}\n\n\n/*\n=============\nExitLevel\n\nWhen the intermission has been exited, the server is either killed\nor moved to a new level based on the \"nextmap\" cvar \n\n=============\n*/\nvoid ExitLevel (void) {\n\tint\t\ti;\n\tgclient_t *cl;\n\n\t//bot interbreeding\n\tBotInterbreedEndMatch();\n\n\t// if we are running a tournement map, kick the loser to spectator status,\n\t// which will automatically grab the next spectator and restart\n\tif ( g_gametype.integer == GT_TOURNAMENT  ) {\n\t\tif ( !level.restarted ) {\n\t\t\tRemoveTournamentLoser();\n\t\t\ttrap_SendConsoleCommand( EXEC_APPEND, \"map_restart 0\\n\" );\n\t\t\tlevel.restarted = qtrue;\n\t\t\tlevel.changemap = NULL;\n\t\t\tlevel.intermissiontime = 0;\n\t\t}\n\t\treturn;\t\n\t}\n\n\n\ttrap_SendConsoleCommand( EXEC_APPEND, \"vstr nextmap\\n\" );\n\tlevel.changemap = NULL;\n\tlevel.intermissiontime = 0;\n\n\t// reset all the scores so we don't enter the intermission again\n\tlevel.teamScores[TEAM_RED] = 0;\n\tlevel.teamScores[TEAM_BLUE] = 0;\n\tfor ( i=0 ; i< g_maxclients.integer ; i++ ) {\n\t\tcl = level.clients + i;\n\t\tif ( cl->pers.connected != CON_CONNECTED ) {\n\t\t\tcontinue;\n\t\t}\n\t\tcl->ps.persistant[PERS_SCORE] = 0;\n\t}\n\n\t// we need to do this here before chaning to CON_CONNECTING\n\tG_WriteSessionData();\n\n\t// change all client states to connecting, so the early players into the\n\t// next level will know the others aren't done reconnecting\n\tfor (i=0 ; i< g_maxclients.integer ; i++) {\n\t\tif ( level.clients[i].pers.connected == CON_CONNECTED ) {\n\t\t\tlevel.clients[i].pers.connected = CON_CONNECTING;\n\t\t}\n\t}\n\n}\n\n/*\n=================\nG_LogPrintf\n\nPrint to the logfile with a time stamp if it is open\n=================\n*/\nvoid QDECL G_LogPrintf( const char *fmt, ... ) {\n\tva_list\t\targptr;\n\tchar\t\tstring[1024];\n\tint\t\t\tmin, tens, sec;\n\n\tsec = level.time / 1000;\n\n\tmin = sec / 60;\n\tsec -= min * 60;\n\ttens = sec / 10;\n\tsec -= tens * 10;\n\n\tCom_sprintf( string, sizeof(string), \"%3i:%i%i \", min, tens, sec );\n\n\tva_start( argptr, fmt );\n\tvsprintf( string +7 , fmt,argptr );\n\tva_end( argptr );\n\n\tif ( g_dedicated.integer ) {\n\t\tG_Printf( \"%s\", string + 7 );\n\t}\n\n\tif ( !level.logFile ) {\n\t\treturn;\n\t}\n\n\ttrap_FS_Write( string, (int)strlen( string ), level.logFile );\n}\n\n/*\n================\nLogExit\n\nAppend information about this game to the log file\n================\n*/\nvoid LogExit( const char *string ) {\n\tint\t\t\t\ti, numSorted;\n\tgclient_t\t\t*cl;\n\n\tG_LogPrintf( \"Exit: %s\\n\", string );\n\n\tlevel.intermissionQueued = level.time;\n\n\t// this will keep the clients from playing any voice sounds\n\t// that will get cut off when the queued intermission starts\n\ttrap_SetConfigstring( CS_INTERMISSION, \"1\" );\n\n\t// don't send more than 32 scores (FIXME?)\n\tnumSorted = level.numConnectedClients;\n\tif ( numSorted > 32 ) {\n\t\tnumSorted = 32;\n\t}\n\n\tif ( g_gametype.integer >= GT_TEAM ) {\n\t\tG_LogPrintf( \"red:%i  blue:%i\\n\",\n\t\t\tlevel.teamScores[TEAM_RED], level.teamScores[TEAM_BLUE] );\n\t}\n\n\tfor (i=0 ; i < numSorted ; i++) {\n\t\tint\t\tping;\n\n\t\tcl = &level.clients[level.sortedClients[i]];\n\n\t\tif ( cl->sess.sessionTeam == TEAM_SPECTATOR ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( cl->pers.connected == CON_CONNECTING ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tping = cl->ps.ping < 999 ? cl->ps.ping : 999;\n\n\t\tG_LogPrintf( \"score: %i  ping: %i  client: %i %s\\n\", cl->ps.persistant[PERS_SCORE], ping, level.sortedClients[i],\tcl->pers.netname );\n\t}\n}\n\n\n/*\n=================\nCheckIntermissionExit\n\nThe level will stay at the intermission for a minimum of 5 seconds\nIf all players wish to continue, the level will then exit.\nIf one or more players have not acknowledged the continue, the game will\nwait 10 seconds before going on.\n=================\n*/\nvoid CheckIntermissionExit( void ) {\n\tint\t\t\tready, notReady;\n\tint\t\t\ti;\n\tgclient_t\t*cl;\n\tint\t\t\treadyMask;\n\n\tif ( g_gametype.integer == GT_SINGLE_PLAYER ) {\n\t\treturn;\n\t}\n\n\t// see which players are ready\n\tready = 0;\n\tnotReady = 0;\n\treadyMask = 0;\n\tfor (i=0 ; i< g_maxclients.integer ; i++) {\n\t\tcl = level.clients + i;\n\t\tif ( cl->pers.connected != CON_CONNECTED ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( g_entities[cl->ps.clientNum].r.svFlags & SVF_BOT ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif ( cl->readyToExit ) {\n\t\t\tready++;\n\t\t\tif ( i < 16 ) {\n\t\t\t\treadyMask |= 1 << i;\n\t\t\t}\n\t\t} else {\n\t\t\tnotReady++;\n\t\t}\n\t}\n\n\t// copy the readyMask to each player's stats so\n\t// it can be displayed on the scoreboard\n\tfor (i=0 ; i< g_maxclients.integer ; i++) {\n\t\tcl = level.clients + i;\n\t\tif ( cl->pers.connected != CON_CONNECTED ) {\n\t\t\tcontinue;\n\t\t}\n\t\tcl->ps.stats[STAT_CLIENTS_READY] = readyMask;\n\t}\n\n\t// never exit in less than five seconds\n\tif ( level.time < level.intermissiontime + 5000 ) {\n\t\treturn;\n\t}\n\n\t// if nobody wants to go, clear timer\n\tif ( !ready ) {\n\t\tlevel.readyToExit = qfalse;\n\t\treturn;\n\t}\n\n\t// if everyone wants to go, go now\n\tif ( !notReady ) {\n\t\tExitLevel();\n\t\treturn;\n\t}\n\n\t// the first person to ready starts the ten second timeout\n\tif ( !level.readyToExit ) {\n\t\tlevel.readyToExit = qtrue;\n\t\tlevel.exitTime = level.time;\n\t}\n\n\t// if we have waited ten seconds since at least one player\n\t// wanted to exit, go ahead\n\tif ( level.time < level.exitTime + 10000 ) {\n\t\treturn;\n\t}\n\n\tExitLevel();\n}\n\n/*\n=============\nScoreIsTied\n=============\n*/\nqboolean ScoreIsTied( void ) {\n\tint\t\ta, b;\n\n\tif ( level.numPlayingClients < 2 ) {\n\t\treturn qfalse;\n\t}\n\t\n\tif ( g_gametype.integer >= GT_TEAM ) {\n\t\treturn level.teamScores[TEAM_RED] == level.teamScores[TEAM_BLUE];\n\t}\n\n\ta = level.clients[level.sortedClients[0]].ps.persistant[PERS_SCORE];\n\tb = level.clients[level.sortedClients[1]].ps.persistant[PERS_SCORE];\n\n\treturn a == b;\n}\n\n/*\n=================\nCheckExitRules\n\nThere will be a delay between the time the exit is qualified for\nand the time everyone is moved to the intermission spot, so you\ncan see the last frag.\n=================\n*/\nvoid CheckExitRules( void ) {\n \tint\t\t\ti;\n\tgclient_t\t*cl;\n\t// if at the intermission, wait for all non-bots to\n\t// signal ready, then go to next level\n\tif ( level.intermissiontime ) {\n\t\tCheckIntermissionExit ();\n\t\treturn;\n\t}\n\n\tif ( level.intermissionQueued ) {\n\t\tif ( level.time - level.intermissionQueued >= INTERMISSION_DELAY_TIME ) {\n\t\t\tlevel.intermissionQueued = 0;\n\t\t\tBeginIntermission();\n\t\t}\n\t\treturn;\n\t}\n\n\t// check for sudden death\n\tif ( ScoreIsTied() ) {\n\t\t// always wait for sudden death\n\t\treturn;\n\t}\n\n\tif ( g_timelimit.integer && !level.warmupTime ) {\n\t\tif ( level.time - level.startTime >= g_timelimit.integer*60000 ) {\n\t\t\ttrap_SendServerCommand( -1, \"print \\\"Timelimit hit.\\n\\\"\");\n\t\t\tLogExit( \"Timelimit hit.\" );\n\t\t\treturn;\n\t\t}\n\t}\n\n\tif ( level.numPlayingClients < 2 ) {\n\t\treturn;\n\t}\n\n\tif ( g_gametype.integer < GT_CTF && g_fraglimit.integer ) {\n\t\tif ( level.teamScores[TEAM_RED] >= g_fraglimit.integer ) {\n\t\t\ttrap_SendServerCommand( -1, \"print \\\"Red hit the fraglimit.\\n\\\"\" );\n\t\t\tLogExit( \"Fraglimit hit.\" );\n\t\t\treturn;\n\t\t}\n\n\t\tif ( level.teamScores[TEAM_BLUE] >= g_fraglimit.integer ) {\n\t\t\ttrap_SendServerCommand( -1, \"print \\\"Blue hit the fraglimit.\\n\\\"\" );\n\t\t\tLogExit( \"Fraglimit hit.\" );\n\t\t\treturn;\n\t\t}\n\n\t\tfor ( i=0 ; i< g_maxclients.integer ; i++ ) {\n\t\t\tcl = level.clients + i;\n\t\t\tif ( cl->pers.connected != CON_CONNECTED ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif ( cl->sess.sessionTeam != TEAM_FREE ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif ( cl->ps.persistant[PERS_SCORE] >= g_fraglimit.integer ) {\n\t\t\t\tLogExit( \"Fraglimit hit.\" );\n\t\t\t\ttrap_SendServerCommand( -1, va(\"print \\\"%s\" S_COLOR_WHITE \" hit the fraglimit.\\n\\\"\",\n\t\t\t\t\tcl->pers.netname ) );\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\tif ( g_gametype.integer >= GT_CTF && g_capturelimit.integer ) {\n\n\t\tif ( level.teamScores[TEAM_RED] >= g_capturelimit.integer ) {\n\t\t\ttrap_SendServerCommand( -1, \"print \\\"Red hit the capturelimit.\\n\\\"\" );\n\t\t\tLogExit( \"Capturelimit hit.\" );\n\t\t\treturn;\n\t\t}\n\n\t\tif ( level.teamScores[TEAM_BLUE] >= g_capturelimit.integer ) {\n\t\t\ttrap_SendServerCommand( -1, \"print \\\"Blue hit the capturelimit.\\n\\\"\" );\n\t\t\tLogExit( \"Capturelimit hit.\" );\n\t\t\treturn;\n\t\t}\n\t}\n}\n\n\n\n/*\n========================================================================\n\nFUNCTIONS CALLED EVERY FRAME\n\n========================================================================\n*/\n\n\n/*\n=============\nCheckTournament\n\nOnce a frame, check for changes in tournement player state\n=============\n*/\nvoid CheckTournament( void ) {\n\t// check because we run 3 game frames before calling Connect and/or ClientBegin\n\t// for clients on a map_restart\n\tif ( level.numPlayingClients == 0 ) {\n\t\treturn;\n\t}\n\n\tif ( g_gametype.integer == GT_TOURNAMENT ) {\n\n\t\t// pull in a spectator if needed\n\t\tif ( level.numPlayingClients < 2 ) {\n\t\t\tAddTournamentPlayer();\n\t\t}\n\n\t\t// if we don't have two players, go back to \"waiting for players\"\n\t\tif ( level.numPlayingClients != 2 ) {\n\t\t\tif ( level.warmupTime != -1 ) {\n\t\t\t\tlevel.warmupTime = -1;\n\t\t\t\ttrap_SetConfigstring( CS_WARMUP, va(\"%i\", level.warmupTime) );\n\t\t\t\tG_LogPrintf( \"Warmup:\\n\" );\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif ( level.warmupTime == 0 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// if the warmup is changed at the console, restart it\n\t\tif ( g_warmup.modificationCount != level.warmupModificationCount ) {\n\t\t\tlevel.warmupModificationCount = g_warmup.modificationCount;\n\t\t\tlevel.warmupTime = -1;\n\t\t}\n\n\t\t// if all players have arrived, start the countdown\n\t\tif ( level.warmupTime < 0 ) {\n\t\t\tif ( level.numPlayingClients == 2 ) {\n\t\t\t\t// fudge by -1 to account for extra delays\n\t\t\t\tlevel.warmupTime = level.time + ( g_warmup.integer - 1 ) * 1000;\n\t\t\t\ttrap_SetConfigstring( CS_WARMUP, va(\"%i\", level.warmupTime) );\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// if the warmup time has counted down, restart\n\t\tif ( level.time > level.warmupTime ) {\n\t\t\tlevel.warmupTime += 10000;\n\t\t\ttrap_Cvar_Set( \"g_restarted\", \"1\" );\n\t\t\ttrap_SendConsoleCommand( EXEC_APPEND, \"map_restart 0\\n\" );\n\t\t\tlevel.restarted = qtrue;\n\t\t\treturn;\n\t\t}\n\t} else if ( g_gametype.integer != GT_SINGLE_PLAYER && level.warmupTime != 0 ) {\n\t\tint\t\tcounts[TEAM_NUM_TEAMS];\n\t\tqboolean\tnotEnough = qfalse;\n\n\t\tif ( g_gametype.integer > GT_TEAM ) {\n\t\t\tcounts[TEAM_BLUE] = TeamCount( -1, TEAM_BLUE );\n\t\t\tcounts[TEAM_RED] = TeamCount( -1, TEAM_RED );\n\n\t\t\tif (counts[TEAM_RED] < 1 || counts[TEAM_BLUE] < 1) {\n\t\t\t\tnotEnough = qtrue;\n\t\t\t}\n\t\t} else if ( level.numPlayingClients < 2 ) {\n\t\t\tnotEnough = qtrue;\n\t\t}\n\n\t\tif ( notEnough ) {\n\t\t\tif ( level.warmupTime != -1 ) {\n\t\t\t\tlevel.warmupTime = -1;\n\t\t\t\ttrap_SetConfigstring( CS_WARMUP, va(\"%i\", level.warmupTime) );\n\t\t\t\tG_LogPrintf( \"Warmup:\\n\" );\n\t\t\t}\n\t\t\treturn; // still waiting for team members\n\t\t}\n\n\t\tif ( level.warmupTime == 0 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// if the warmup is changed at the console, restart it\n\t\tif ( g_warmup.modificationCount != level.warmupModificationCount ) {\n\t\t\tlevel.warmupModificationCount = g_warmup.modificationCount;\n\t\t\tlevel.warmupTime = -1;\n\t\t}\n\n\t\t// if all players have arrived, start the countdown\n\t\tif ( level.warmupTime < 0 ) {\n\t\t\t// fudge by -1 to account for extra delays\n\t\t\tlevel.warmupTime = level.time + ( g_warmup.integer - 1 ) * 1000;\n\t\t\ttrap_SetConfigstring( CS_WARMUP, va(\"%i\", level.warmupTime) );\n\t\t\treturn;\n\t\t}\n\n\t\t// if the warmup time has counted down, restart\n\t\tif ( level.time > level.warmupTime ) {\n\t\t\tlevel.warmupTime += 10000;\n\t\t\ttrap_Cvar_Set( \"g_restarted\", \"1\" );\n\t\t\ttrap_SendConsoleCommand( EXEC_APPEND, \"map_restart 0\\n\" );\n\t\t\tlevel.restarted = qtrue;\n\t\t\treturn;\n\t\t}\n\t}\n}\n\n\n/*\n==================\nCheckVote\n==================\n*/\nvoid CheckVote( void ) {\n\tif ( level.voteExecuteTime && level.voteExecuteTime < level.time ) {\n\t\tlevel.voteExecuteTime = 0;\n\t\ttrap_SendConsoleCommand( EXEC_APPEND, va(\"%s\\n\", level.voteString ) );\n\t}\n\tif ( !level.voteTime ) {\n\t\treturn;\n\t}\n\tif ( level.time - level.voteTime >= VOTE_TIME ) {\n\t\ttrap_SendServerCommand( -1, \"print \\\"Vote failed.\\n\\\"\" );\n\t} else {\n\t\t// ATVI Q3 1.32 Patch #9, WNF\n\t\tif ( level.voteYes > level.numVotingClients/2 ) {\n\t\t\t// execute the command, then remove the vote\n\t\t\ttrap_SendServerCommand( -1, \"print \\\"Vote passed.\\n\\\"\" );\n\t\t\tlevel.voteExecuteTime = level.time + 3000;\n\t\t} else if ( level.voteNo >= level.numVotingClients/2 ) {\n\t\t\t// same behavior as a timeout\n\t\t\ttrap_SendServerCommand( -1, \"print \\\"Vote failed.\\n\\\"\" );\n\t\t} else {\n\t\t\t// still waiting for a majority\n\t\t\treturn;\n\t\t}\n\t}\n\tlevel.voteTime = 0;\n\ttrap_SetConfigstring( CS_VOTE_TIME, \"\" );\n\n}\n\n/*\n==================\nPrintTeam\n==================\n*/\nvoid PrintTeam(int team, char *message) {\n\tint i;\n\n\tfor ( i = 0 ; i < level.maxclients ; i++ ) {\n\t\tif (level.clients[i].sess.sessionTeam != team)\n\t\t\tcontinue;\n\t\ttrap_SendServerCommand( i, message );\n\t}\n}\n\n/*\n==================\nSetLeader\n==================\n*/\nvoid SetLeader(int team, int client) {\n\tint i;\n\n\tif ( level.clients[client].pers.connected == CON_DISCONNECTED ) {\n\t\tPrintTeam(team, va(\"print \\\"%s is not connected\\n\\\"\", level.clients[client].pers.netname) );\n\t\treturn;\n\t}\n\tif (level.clients[client].sess.sessionTeam != team) {\n\t\tPrintTeam(team, va(\"print \\\"%s is not on the team anymore\\n\\\"\", level.clients[client].pers.netname) );\n\t\treturn;\n\t}\n\tfor ( i = 0 ; i < level.maxclients ; i++ ) {\n\t\tif (level.clients[i].sess.sessionTeam != team)\n\t\t\tcontinue;\n\t\tif (level.clients[i].sess.teamLeader) {\n\t\t\tlevel.clients[i].sess.teamLeader = qfalse;\n\t\t\tClientUserinfoChanged(i);\n\t\t}\n\t}\n\tlevel.clients[client].sess.teamLeader = qtrue;\n\tClientUserinfoChanged( client );\n\tPrintTeam(team, va(\"print \\\"%s is the new team leader\\n\\\"\", level.clients[client].pers.netname) );\n}\n\n/*\n==================\nCheckTeamLeader\n==================\n*/\nvoid CheckTeamLeader( int team ) {\n\tint i;\n\n\tfor ( i = 0 ; i < level.maxclients ; i++ ) {\n\t\tif (level.clients[i].sess.sessionTeam != team)\n\t\t\tcontinue;\n\t\tif (level.clients[i].sess.teamLeader)\n\t\t\tbreak;\n\t}\n\tif (i >= level.maxclients) {\n\t\tfor ( i = 0 ; i < level.maxclients ; i++ ) {\n\t\t\tif (level.clients[i].sess.sessionTeam != team)\n\t\t\t\tcontinue;\n\t\t\tif (!(g_entities[i].r.svFlags & SVF_BOT)) {\n\t\t\t\tlevel.clients[i].sess.teamLeader = qtrue;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tfor ( i = 0 ; i < level.maxclients ; i++ ) {\n\t\t\tif (level.clients[i].sess.sessionTeam != team)\n\t\t\t\tcontinue;\n\t\t\tlevel.clients[i].sess.teamLeader = qtrue;\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\n/*\n==================\nCheckTeamVote\n==================\n*/\nvoid CheckTeamVote( int team ) {\n\tint cs_offset;\n\n\tif ( team == TEAM_RED )\n\t\tcs_offset = 0;\n\telse if ( team == TEAM_BLUE )\n\t\tcs_offset = 1;\n\telse\n\t\treturn;\n\n\tif ( !level.teamVoteTime[cs_offset] ) {\n\t\treturn;\n\t}\n\tif ( level.time - level.teamVoteTime[cs_offset] >= VOTE_TIME ) {\n\t\ttrap_SendServerCommand( -1, \"print \\\"Team vote failed.\\n\\\"\" );\n\t} else {\n\t\tif ( level.teamVoteYes[cs_offset] > level.numteamVotingClients[cs_offset]/2 ) {\n\t\t\t// execute the command, then remove the vote\n\t\t\ttrap_SendServerCommand( -1, \"print \\\"Team vote passed.\\n\\\"\" );\n\t\t\t//\n\t\t\tif ( !Q_strncmp( \"leader\", level.teamVoteString[cs_offset], 6) ) {\n\t\t\t\t//set the team leader\n\t\t\t\tSetLeader(team, atoi(level.teamVoteString[cs_offset] + 7));\n\t\t\t}\n\t\t\telse {\n\t\t\t\ttrap_SendConsoleCommand( EXEC_APPEND, va(\"%s\\n\", level.teamVoteString[cs_offset] ) );\n\t\t\t}\n\t\t} else if ( level.teamVoteNo[cs_offset] >= level.numteamVotingClients[cs_offset]/2 ) {\n\t\t\t// same behavior as a timeout\n\t\t\ttrap_SendServerCommand( -1, \"print \\\"Team vote failed.\\n\\\"\" );\n\t\t} else {\n\t\t\t// still waiting for a majority\n\t\t\treturn;\n\t\t}\n\t}\n\tlevel.teamVoteTime[cs_offset] = 0;\n\ttrap_SetConfigstring( CS_TEAMVOTE_TIME + cs_offset, \"\" );\n\n}\n\n\n/*\n==================\nCheckCvars\n==================\n*/\nvoid CheckCvars( void ) {\n\tstatic int lastMod = -1;\n\n\tif ( g_password.modificationCount != lastMod ) {\n\t\tlastMod = g_password.modificationCount;\n\t\tif ( *g_password.string && Q_stricmp( g_password.string, \"none\" ) ) {\n\t\t\ttrap_Cvar_Set( \"g_needpass\", \"1\" );\n\t\t} else {\n\t\t\ttrap_Cvar_Set( \"g_needpass\", \"0\" );\n\t\t}\n\t}\n}\n\n/*\n=============\nG_RunThink\n\nRuns thinking code for this frame if necessary\n=============\n*/\nvoid G_RunThink (gentity_t *ent) {\n\tfloat\tthinktime;\n\n\tthinktime = ent->nextthink;\n\tif (thinktime <= 0) {\n\t\treturn;\n\t}\n\tif (thinktime > level.time) {\n\t\treturn;\n\t}\n\t\n\tent->nextthink = 0;\n\tif (!ent->think) {\n\t\tG_Error ( \"NULL ent->think\");\n\t}\n\tent->think (ent);\n}\n\n/*\n================\nG_RunFrame\n\nAdvances the non-player objects in the world\n================\n*/\nvoid G_RunFrame( int levelTime ) {\n\tint\t\t\ti;\n\tgentity_t\t*ent;\n\tint\t\t\tmsec;\nint start, end;\n\n\t// if we are waiting for the level to restart, do nothing\n\tif ( level.restarted ) {\n\t\treturn;\n\t}\n\n\tlevel.framenum++;\n\tlevel.previousTime = level.time;\n\tlevel.time = levelTime;\n\tmsec = level.time - level.previousTime;\n\n\t// get any cvar changes\n\tG_UpdateCvars();\n\n\t//\n\t// go through all allocated objects\n\t//\n\tstart = trap_Milliseconds();\n\tent = &g_entities[0];\n\tfor (i=0 ; i<level.num_entities ; i++, ent++) {\n\t\tif ( !ent->inuse ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// clear events that are too old\n\t\tif ( level.time - ent->eventTime > EVENT_VALID_MSEC ) {\n\t\t\tif ( ent->s.event ) {\n\t\t\t\tent->s.event = 0;\t// &= EV_EVENT_BITS;\n\t\t\t\tif ( ent->client ) {\n\t\t\t\t\tent->client->ps.externalEvent = 0;\n\t\t\t\t\t// predicted events should never be set to zero\n\t\t\t\t\t//ent->client->ps.events[0] = 0;\n\t\t\t\t\t//ent->client->ps.events[1] = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif ( ent->freeAfterEvent ) {\n\t\t\t\t// tempEntities or dropped items completely go away after their event\n\t\t\t\tG_FreeEntity( ent );\n\t\t\t\tcontinue;\n\t\t\t} else if ( ent->unlinkAfterEvent ) {\n\t\t\t\t// items that will respawn will hide themselves after their pickup event\n\t\t\t\tent->unlinkAfterEvent = qfalse;\n\t\t\t\ttrap_UnlinkEntity( ent );\n\t\t\t}\n\t\t}\n\n\t\t// temporary entities don't think\n\t\tif ( ent->freeAfterEvent ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif ( !ent->r.linked && ent->neverFree ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif ( ent->s.eType == ET_MISSILE ) {\n\t\t\tG_RunMissile( ent );\n\t\t\tcontinue;\n\t\t}\n\n\t\tif ( ent->s.eType == ET_ITEM || ent->physicsObject ) {\n\t\t\tG_RunItem( ent );\n\t\t\tcontinue;\n\t\t}\n\n\t\tif ( ent->s.eType == ET_MOVER ) {\n\t\t\tG_RunMover( ent );\n\t\t\tcontinue;\n\t\t}\n\n\t\tif ( i < MAX_CLIENTS ) {\n\t\t\tG_RunClient( ent );\n\t\t\tcontinue;\n\t\t}\n\n\t\tG_RunThink( ent );\n\t}\nend = trap_Milliseconds();\n\nstart = trap_Milliseconds();\n\t// perform final fixups on the players\n\tent = &g_entities[0];\n\tfor (i=0 ; i < level.maxclients ; i++, ent++ ) {\n\t\tif ( ent->inuse ) {\n\t\t\tClientEndFrame( ent );\n\t\t}\n\t}\nend = trap_Milliseconds();\n\n\t// see if it is time to do a tournement restart\n\tCheckTournament();\n\n\t// see if it is time to end the level\n\tCheckExitRules();\n\n\t// update to team status?\n\tCheckTeamStatus();\n\n\t// cancel vote if timed out\n\tCheckVote();\n\n\t// check team votes\n\tCheckTeamVote( TEAM_RED );\n\tCheckTeamVote( TEAM_BLUE );\n\n\t// for tracking changes\n\tCheckCvars();\n\n\tif (g_listEntity.integer) {\n\t\tfor (i = 0; i < MAX_GENTITIES; i++) {\n\t\t\tG_Printf(\"%4i: %s\\n\", i, g_entities[i].classname);\n\t\t}\n\t\ttrap_Cvar_Set(\"g_listEntity\", \"0\");\n\t}\n}\n"
  },
  {
    "path": "src/game/g_mem.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n//\n// g_mem.c\n//\n\n\n#include \"g_local.h\"\n\n\n#define POOLSIZE\t(256 * 1024)\n\nstatic char\t\tmemoryPool[POOLSIZE];\nstatic int\t\tallocPoint;\n\nvoid *G_Alloc( int size ) {\n\tchar\t*p;\n\n\tif ( g_debugAlloc.integer ) {\n\t\tG_Printf( \"G_Alloc of %i bytes (%i left)\\n\", size, POOLSIZE - allocPoint - ( ( size + 31 ) & ~31 ) );\n\t}\n\n\tif ( allocPoint + size > POOLSIZE ) {\n\t  G_Error( \"G_Alloc: failed on allocation of %i bytes\\n\", size ); // bk010103 - was %u, but is signed\n\t\treturn NULL;\n\t}\n\n\tp = &memoryPool[allocPoint];\n\n\tallocPoint += ( size + 31 ) & ~31;\n\n\treturn p;\n}\n\nvoid G_InitMemory( void ) {\n\tallocPoint = 0;\n}\n\nvoid Svcmd_GameMem_f( void ) {\n\tG_Printf( \"Game memory status: %i out of %i bytes allocated\\n\", allocPoint, POOLSIZE );\n}\n"
  },
  {
    "path": "src/game/g_misc.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n// g_misc.c\n\n#include \"g_local.h\"\n\n\n/*QUAKED func_group (0 0 0) ?\nUsed to group brushes together just for editor convenience.  They are turned into normal brushes by the utilities.\n*/\n\n\n/*QUAKED info_camp (0 0.5 0) (-4 -4 -4) (4 4 4)\nUsed as a positional target for calculations in the utilities (spotlights, etc), but removed during gameplay.\n*/\nvoid SP_info_camp( gentity_t *self ) {\n\tG_SetOrigin( self, self->s.origin );\n}\n\n\n/*QUAKED info_null (0 0.5 0) (-4 -4 -4) (4 4 4)\nUsed as a positional target for calculations in the utilities (spotlights, etc), but removed during gameplay.\n*/\nvoid SP_info_null( gentity_t *self ) {\n\tG_FreeEntity( self );\n}\n\n\n/*QUAKED info_notnull (0 0.5 0) (-4 -4 -4) (4 4 4)\nUsed as a positional target for in-game calculation, like jumppad targets.\ntarget_position does the same thing\n*/\nvoid SP_info_notnull( gentity_t *self ){\n\tG_SetOrigin( self, self->s.origin );\n}\n\n\n/*QUAKED light (0 1 0) (-8 -8 -8) (8 8 8) linear\nNon-displayed light.\n\"light\" overrides the default 300 intensity.\nLinear checbox gives linear falloff instead of inverse square\nLights pointed at a target will be spotlights.\n\"radius\" overrides the default 64 unit radius of a spotlight at the target point.\n*/\nvoid SP_light( gentity_t *self ) {\n\tG_FreeEntity( self );\n}\n\n\n\n/*\n=================================================================================\n\nTELEPORTERS\n\n=================================================================================\n*/\n\nvoid TeleportPlayer( gentity_t *player, vec3_t origin, vec3_t angles ) {\n\tgentity_t\t*tent;\n\n\t// use temp events at source and destination to prevent the effect\n\t// from getting dropped by a second player event\n\tif ( player->client->sess.sessionTeam != TEAM_SPECTATOR ) {\n\t\ttent = G_TempEntity( player->client->ps.origin, EV_PLAYER_TELEPORT_OUT );\n\t\ttent->s.clientNum = player->s.clientNum;\n\n\t\ttent = G_TempEntity( origin, EV_PLAYER_TELEPORT_IN );\n\t\ttent->s.clientNum = player->s.clientNum;\n\t}\n\n\t// unlink to make sure it can't possibly interfere with G_KillBox\n\ttrap_UnlinkEntity (player);\n\n\tVectorCopy ( origin, player->client->ps.origin );\n\tplayer->client->ps.origin[2] += 1;\n\n\t// spit the player out\n\tAngleVectors( angles, player->client->ps.velocity, NULL, NULL );\n\tVectorScale( player->client->ps.velocity, 400, player->client->ps.velocity );\n\tplayer->client->ps.pm_time = 160;\t\t// hold time\n\tplayer->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;\n\n\t// toggle the teleport bit so the client knows to not lerp\n\tplayer->client->ps.eFlags ^= EF_TELEPORT_BIT;\n\n\t// set angles\n\tSetClientViewAngle( player, angles );\n\n\t// kill anything at the destination\n\tif ( player->client->sess.sessionTeam != TEAM_SPECTATOR ) {\n\t\tG_KillBox (player);\n\t}\n\n\t// save results of pmove\n\tBG_PlayerStateToEntityState( &player->client->ps, &player->s, qtrue );\n\n\t// use the precise origin for linking\n\tVectorCopy( player->client->ps.origin, player->r.currentOrigin );\n\n\tif ( player->client->sess.sessionTeam != TEAM_SPECTATOR ) {\n\t\ttrap_LinkEntity (player);\n\t}\n}\n\n\n/*QUAKED misc_teleporter_dest (1 0 0) (-32 -32 -24) (32 32 -16)\nPoint teleporters at these.\nNow that we don't have teleport destination pads, this is just\nan info_notnull\n*/\nvoid SP_misc_teleporter_dest( gentity_t *ent ) {\n}\n\n\n//===========================================================\n\n/*QUAKED misc_model (1 0 0) (-16 -16 -16) (16 16 16)\n\"model\"\t\tarbitrary .md3 file to display\n*/\nvoid SP_misc_model( gentity_t *ent ) {\n\n#if 0\n\tent->s.modelindex = G_ModelIndex( ent->model );\n\tVectorSet (ent->mins, -16, -16, -16);\n\tVectorSet (ent->maxs, 16, 16, 16);\n\ttrap_LinkEntity (ent);\n\n\tG_SetOrigin( ent, ent->s.origin );\n\tVectorCopy( ent->s.angles, ent->s.apos.trBase );\n#else\n\tG_FreeEntity( ent );\n#endif\n}\n\n//===========================================================\n\nvoid locateCamera( gentity_t *ent ) {\n\tvec3_t\t\tdir;\n\tgentity_t\t*target;\n\tgentity_t\t*owner;\n\n\towner = G_PickTarget( ent->target );\n\tif ( !owner ) {\n\t\tG_Printf( \"Couldn't find target for misc_partal_surface\\n\" );\n\t\tG_FreeEntity( ent );\n\t\treturn;\n\t}\n\tent->r.ownerNum = owner->s.number;\n\n\t// frame holds the rotate speed\n\tif ( owner->spawnflags & 1 ) {\n\t\tent->s.frame = 25;\n\t} else if ( owner->spawnflags & 2 ) {\n\t\tent->s.frame = 75;\n\t}\n\n\t// swing camera ?\n\tif ( owner->spawnflags & 4 ) {\n\t\t// set to 0 for no rotation at all\n\t\tent->s.powerups = 0;\n\t}\n\telse {\n\t\tent->s.powerups = 1;\n\t}\n\n\t// clientNum holds the rotate offset\n\tent->s.clientNum = owner->s.clientNum;\n\n\tVectorCopy( owner->s.origin, ent->s.origin2 );\n\n\t// see if the portal_camera has a target\n\ttarget = G_PickTarget( owner->target );\n\tif ( target ) {\n\t\tVectorSubtract( target->s.origin, owner->s.origin, dir );\n\t\tVectorNormalize( dir );\n\t} else {\n\t\tG_SetMovedir( owner->s.angles, dir );\n\t}\n\n\tent->s.eventParm = DirToByte( dir );\n}\n\n/*QUAKED misc_portal_surface (0 0 1) (-8 -8 -8) (8 8 8)\nThe portal surface nearest this entity will show a view from the targeted misc_portal_camera, or a mirror view if untargeted.\nThis must be within 64 world units of the surface!\n*/\nvoid SP_misc_portal_surface(gentity_t *ent) {\n\tVectorClear( ent->r.mins );\n\tVectorClear( ent->r.maxs );\n\ttrap_LinkEntity (ent);\n\n\tent->r.svFlags = SVF_PORTAL;\n\tent->s.eType = ET_PORTAL;\n\n\tif ( !ent->target ) {\n\t\tVectorCopy( ent->s.origin, ent->s.origin2 );\n\t} else {\n\t\tent->think = locateCamera;\n\t\tent->nextthink = level.time + 100;\n\t}\n}\n\n/*QUAKED misc_portal_camera (0 0 1) (-8 -8 -8) (8 8 8) slowrotate fastrotate noswing\nThe target for a misc_portal_director.  You can set either angles or target another entity to determine the direction of view.\n\"roll\" an angle modifier to orient the camera around the target vector;\n*/\nvoid SP_misc_portal_camera(gentity_t *ent) {\n\tfloat\troll;\n\n\tVectorClear( ent->r.mins );\n\tVectorClear( ent->r.maxs );\n\ttrap_LinkEntity (ent);\n\n\tG_SpawnFloat( \"roll\", \"0\", &roll );\n\n\tent->s.clientNum = roll/360.0 * 256;\n}\n\n/*\n======================================================================\n\n  SHOOTERS\n\n======================================================================\n*/\n\nvoid Use_Shooter( gentity_t *ent, gentity_t *other, gentity_t *activator ) {\n\tvec3_t\t\tdir;\n\tfloat\t\tdeg;\n\tvec3_t\t\tup, right;\n\n\t// see if we have a target\n\tif ( ent->enemy ) {\n\t\tVectorSubtract( ent->enemy->r.currentOrigin, ent->s.origin, dir );\n\t\tVectorNormalize( dir );\n\t} else {\n\t\tVectorCopy( ent->movedir, dir );\n\t}\n\n\t// randomize a bit\n\tPerpendicularVector( up, dir );\n\tCrossProduct( up, dir, right );\n\n\tdeg = crandom() * ent->random;\n\tVectorMA( dir, deg, up, dir );\n\n\tdeg = crandom() * ent->random;\n\tVectorMA( dir, deg, right, dir );\n\n\tVectorNormalize( dir );\n\n\tswitch ( ent->s.weapon ) {\n\tcase WP_GRENADE_LAUNCHER:\n\t\tfire_grenade( ent, ent->s.origin, dir );\n\t\tbreak;\n\tcase WP_ROCKET_LAUNCHER:\n\t\tfire_rocket( ent, ent->s.origin, dir );\n\t\tbreak;\n\tcase WP_PLASMAGUN:\n\t\tfire_plasma( ent, ent->s.origin, dir );\n\t\tbreak;\n\t}\n\n\tG_AddEvent( ent, EV_FIRE_WEAPON, 0 );\n}\n\n\nstatic void InitShooter_Finish( gentity_t *ent ) {\n\tent->enemy = G_PickTarget( ent->target );\n\tent->think = 0;\n\tent->nextthink = 0;\n}\n\nvoid InitShooter( gentity_t *ent, int weapon ) {\n\tent->use = Use_Shooter;\n\tent->s.weapon = weapon;\n\n\tRegisterItem( BG_FindItemForWeapon( weapon ) );\n\n\tG_SetMovedir( ent->s.angles, ent->movedir );\n\n\tif ( !ent->random ) {\n\t\tent->random = 1.0;\n\t}\n\tent->random = sin( M_PI * ent->random / 180 );\n\t// target might be a moving object, so we can't set movedir for it\n\tif ( ent->target ) {\n\t\tent->think = InitShooter_Finish;\n\t\tent->nextthink = level.time + 500;\n\t}\n\ttrap_LinkEntity( ent );\n}\n\n/*QUAKED shooter_rocket (1 0 0) (-16 -16 -16) (16 16 16)\nFires at either the target or the current direction.\n\"random\" the number of degrees of deviance from the taget. (1.0 default)\n*/\nvoid SP_shooter_rocket( gentity_t *ent ) {\n\tInitShooter( ent, WP_ROCKET_LAUNCHER );\n}\n\n/*QUAKED shooter_plasma (1 0 0) (-16 -16 -16) (16 16 16)\nFires at either the target or the current direction.\n\"random\" is the number of degrees of deviance from the taget. (1.0 default)\n*/\nvoid SP_shooter_plasma( gentity_t *ent ) {\n\tInitShooter( ent, WP_PLASMAGUN);\n}\n\n/*QUAKED shooter_grenade (1 0 0) (-16 -16 -16) (16 16 16)\nFires at either the target or the current direction.\n\"random\" is the number of degrees of deviance from the taget. (1.0 default)\n*/\nvoid SP_shooter_grenade( gentity_t *ent ) {\n\tInitShooter( ent, WP_GRENADE_LAUNCHER);\n}\n"
  },
  {
    "path": "src/game/g_missile.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n#include \"g_local.h\"\n\n#define\tMISSILE_PRESTEP_TIME\t50\n\n/*\n================\nG_BounceMissile\n\n================\n*/\nvoid G_BounceMissile( gentity_t *ent, trace_t *trace ) {\n\tvec3_t\tvelocity;\n\tfloat\tdot;\n\tint\t\thitTime;\n\n\t// reflect the velocity on the trace plane\n\thitTime = level.previousTime + ( level.time - level.previousTime ) * trace->fraction;\n\tBG_EvaluateTrajectoryDelta( &ent->s.pos, hitTime, velocity );\n\tdot = DotProduct( velocity, trace->plane.normal );\n\tVectorMA( velocity, -2*dot, trace->plane.normal, ent->s.pos.trDelta );\n\n\tif ( ent->s.eFlags & EF_BOUNCE_HALF ) {\n\t\tVectorScale( ent->s.pos.trDelta, 0.65, ent->s.pos.trDelta );\n\t\t// check for stop\n\t\tif ( trace->plane.normal[2] > 0.2 && VectorLength( ent->s.pos.trDelta ) < 40 ) {\n\t\t\tG_SetOrigin( ent, trace->endpos );\n\t\t\treturn;\n\t\t}\n\t}\n\n\tVectorAdd( ent->r.currentOrigin, trace->plane.normal, ent->r.currentOrigin);\n\tVectorCopy( ent->r.currentOrigin, ent->s.pos.trBase );\n\tent->s.pos.trTime = level.time;\n}\n\n\n/*\n================\nG_ExplodeMissile\n\nExplode a missile without an impact\n================\n*/\nvoid G_ExplodeMissile( gentity_t *ent ) {\n\tvec3_t\t\tdir;\n\tvec3_t\t\torigin;\n\n\tBG_EvaluateTrajectory( &ent->s.pos, level.time, origin );\n\tSnapVector( origin );\n\tG_SetOrigin( ent, origin );\n\n\t// we don't have a valid direction, so just point straight up\n\tdir[0] = dir[1] = 0;\n\tdir[2] = 1;\n\n\tent->s.eType = ET_GENERAL;\n\tG_AddEvent( ent, EV_MISSILE_MISS, DirToByte( dir ) );\n\n\tent->freeAfterEvent = qtrue;\n\n\t// splash damage\n\tif ( ent->splashDamage ) {\n\t\tif( G_RadiusDamage( ent->r.currentOrigin, ent->parent, ent->splashDamage, ent->splashRadius, ent\n\t\t\t, ent->splashMethodOfDeath ) ) {\n\t\t\tg_entities[ent->r.ownerNum].client->accuracy_hits++;\n\t\t}\n\t}\n\n\ttrap_LinkEntity( ent );\n}\n\n/*\n================\nG_MissileImpact\n================\n*/\nvoid G_MissileImpact( gentity_t *ent, trace_t *trace ) {\n\tgentity_t\t\t*other;\n\tqboolean\t\thitClient = qfalse;\n\n\tother = &g_entities[trace->entityNum];\n\n\t// check for bounce\n\tif ( !other->takedamage &&\n\t\t( ent->s.eFlags & ( EF_BOUNCE | EF_BOUNCE_HALF ) ) ) {\n\t\tG_BounceMissile( ent, trace );\n\t\tG_AddEvent( ent, EV_GRENADE_BOUNCE, 0 );\n\t\treturn;\n\t}\n\n\t// impact damage\n\tif (other->takedamage) {\n\t\t// FIXME: wrong damage direction?\n\t\tif ( ent->damage ) {\n\t\t\tvec3_t\tvelocity;\n\n\t\t\tif( LogAccuracyHit( other, &g_entities[ent->r.ownerNum] ) ) {\n\t\t\t\tg_entities[ent->r.ownerNum].client->accuracy_hits++;\n\t\t\t\thitClient = qtrue;\n\t\t\t}\n\t\t\tBG_EvaluateTrajectoryDelta( &ent->s.pos, level.time, velocity );\n\t\t\tif ( VectorLength( velocity ) == 0 ) {\n\t\t\t\tvelocity[2] = 1;\t// stepped on a grenade\n\t\t\t}\n\t\t\tG_Damage (other, ent, &g_entities[ent->r.ownerNum], velocity,\n\t\t\t\tent->s.origin, ent->damage, \n\t\t\t\t0, ent->methodOfDeath);\n\t\t}\n\t}\n\n\tif (!strcmp(ent->classname, \"hook\")) {\n\t\tgentity_t *nent;\n\t\tvec3_t v;\n\n\t\tnent = G_Spawn();\n\t\tif ( other->takedamage && other->client ) {\n\n\t\t\tG_AddEvent( nent, EV_MISSILE_HIT, DirToByte( trace->plane.normal ) );\n\t\t\tnent->s.otherEntityNum = other->s.number;\n\n\t\t\tent->enemy = other;\n\n\t\t\tv[0] = other->r.currentOrigin[0] + (other->r.mins[0] + other->r.maxs[0]) * 0.5;\n\t\t\tv[1] = other->r.currentOrigin[1] + (other->r.mins[1] + other->r.maxs[1]) * 0.5;\n\t\t\tv[2] = other->r.currentOrigin[2] + (other->r.mins[2] + other->r.maxs[2]) * 0.5;\n\n\t\t\tSnapVectorTowards( v, ent->s.pos.trBase );\t// save net bandwidth\n\t\t} else {\n\t\t\tVectorCopy(trace->endpos, v);\n\t\t\tG_AddEvent( nent, EV_MISSILE_MISS, DirToByte( trace->plane.normal ) );\n\t\t\tent->enemy = NULL;\n\t\t}\n\n\t\tSnapVectorTowards( v, ent->s.pos.trBase );\t// save net bandwidth\n\n\t\tnent->freeAfterEvent = qtrue;\n\t\t// change over to a normal entity right at the point of impact\n\t\tnent->s.eType = ET_GENERAL;\n\t\tent->s.eType = ET_GRAPPLE;\n\n\t\tG_SetOrigin( ent, v );\n\t\tG_SetOrigin( nent, v );\n\n\t\tent->think = Weapon_HookThink;\n\t\tent->nextthink = level.time + FRAMETIME;\n\n\t\tent->parent->client->ps.pm_flags |= PMF_GRAPPLE_PULL;\n\t\tVectorCopy( ent->r.currentOrigin, ent->parent->client->ps.grapplePoint);\n\n\t\ttrap_LinkEntity( ent );\n\t\ttrap_LinkEntity( nent );\n\n\t\treturn;\n\t}\n\n\t// is it cheaper in bandwidth to just remove this ent and create a new\n\t// one, rather than changing the missile into the explosion?\n\n\tif ( other->takedamage && other->client ) {\n\t\tG_AddEvent( ent, EV_MISSILE_HIT, DirToByte( trace->plane.normal ) );\n\t\tent->s.otherEntityNum = other->s.number;\n\t} else if( trace->surfaceFlags & SURF_METALSTEPS ) {\n\t\tG_AddEvent( ent, EV_MISSILE_MISS_METAL, DirToByte( trace->plane.normal ) );\n\t} else {\n\t\tG_AddEvent( ent, EV_MISSILE_MISS, DirToByte( trace->plane.normal ) );\n\t}\n\n\tent->freeAfterEvent = qtrue;\n\n\t// change over to a normal entity right at the point of impact\n\tent->s.eType = ET_GENERAL;\n\n\tSnapVectorTowards( trace->endpos, ent->s.pos.trBase );\t// save net bandwidth\n\n\tG_SetOrigin( ent, trace->endpos );\n\n\t// splash damage (doesn't apply to person directly hit)\n\tif ( ent->splashDamage ) {\n\t\tif( G_RadiusDamage( trace->endpos, ent->parent, ent->splashDamage, ent->splashRadius, \n\t\t\tother, ent->splashMethodOfDeath ) ) {\n\t\t\tif( !hitClient ) {\n\t\t\t\tg_entities[ent->r.ownerNum].client->accuracy_hits++;\n\t\t\t}\n\t\t}\n\t}\n\n\ttrap_LinkEntity( ent );\n}\n\n/*\n================\nG_RunMissile\n================\n*/\nvoid G_RunMissile( gentity_t *ent ) {\n\tvec3_t\t\torigin;\n\ttrace_t\t\ttr;\n\tint\t\t\tpassent;\n\n\t// get current position\n\tBG_EvaluateTrajectory( &ent->s.pos, level.time, origin );\n\n\t// if this missile bounced off an invulnerability sphere\n\tif ( ent->target_ent ) {\n\t\tpassent = ent->target_ent->s.number;\n\t}\n\telse {\n\t\t// ignore interactions with the missile owner\n\t\tpassent = ent->r.ownerNum;\n\t}\n\t// trace a line from the previous position to the current position\n\ttrap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, passent, ent->clipmask );\n\n\tif ( tr.startsolid || tr.allsolid ) {\n\t\t// make sure the tr.entityNum is set to the entity we're stuck in\n\t\ttrap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, ent->r.currentOrigin, passent, ent->clipmask );\n\t\ttr.fraction = 0;\n\t}\n\telse {\n\t\tVectorCopy( tr.endpos, ent->r.currentOrigin );\n\t}\n\n\ttrap_LinkEntity( ent );\n\n\tif ( tr.fraction != 1 ) {\n\t\t// never explode or bounce on sky\n\t\tif ( tr.surfaceFlags & SURF_NOIMPACT ) {\n\t\t\t// If grapple, reset owner\n\t\t\tif (ent->parent && ent->parent->client && ent->parent->client->hook == ent) {\n\t\t\t\tent->parent->client->hook = NULL;\n\t\t\t}\n\t\t\tG_FreeEntity( ent );\n\t\t\treturn;\n\t\t}\n\t\tG_MissileImpact( ent, &tr );\n\t\tif ( ent->s.eType != ET_MISSILE ) {\n\t\t\treturn;\t\t// exploded\n\t\t}\n\t}\n\t// check think function after bouncing\n\tG_RunThink( ent );\n}\n\n\n//=============================================================================\n\n/*\n=================\nfire_plasma\n\n=================\n*/\ngentity_t *fire_plasma (gentity_t *self, vec3_t start, vec3_t dir) {\n\tgentity_t\t*bolt;\n\n\tVectorNormalize (dir);\n\n\tbolt = G_Spawn();\n\tbolt->classname = \"plasma\";\n\tbolt->nextthink = level.time + 10000;\n\tbolt->think = G_ExplodeMissile;\n\tbolt->s.eType = ET_MISSILE;\n\tbolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;\n\tbolt->s.weapon = WP_PLASMAGUN;\n\tbolt->r.ownerNum = self->s.number;\n\tbolt->parent = self;\n\tbolt->damage = 20;\n\tbolt->splashDamage = 15;\n\tbolt->splashRadius = 20;\n\tbolt->methodOfDeath = MOD_PLASMA;\n\tbolt->splashMethodOfDeath = MOD_PLASMA_SPLASH;\n\tbolt->clipmask = MASK_SHOT;\n\tbolt->target_ent = NULL;\n\n\tbolt->s.pos.trType = TR_LINEAR;\n\tbolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME;\t\t// move a bit on the very first frame\n\tVectorCopy( start, bolt->s.pos.trBase );\n\tVectorScale( dir, 2000, bolt->s.pos.trDelta );\n\tSnapVector( bolt->s.pos.trDelta );\t\t\t// save net bandwidth\n\n\tVectorCopy (start, bolt->r.currentOrigin);\n\n\treturn bolt;\n}\t\n\n//=============================================================================\n\n\n/*\n=================\nfire_grenade\n=================\n*/\ngentity_t *fire_grenade (gentity_t *self, vec3_t start, vec3_t dir) {\n\tgentity_t\t*bolt;\n\n\tVectorNormalize (dir);\n\n\tbolt = G_Spawn();\n\tbolt->classname = \"grenade\";\n\tbolt->nextthink = level.time + 2500;\n\tbolt->think = G_ExplodeMissile;\n\tbolt->s.eType = ET_MISSILE;\n\tbolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;\n\tbolt->s.weapon = WP_GRENADE_LAUNCHER;\n\tbolt->s.eFlags = EF_BOUNCE_HALF;\n\tbolt->r.ownerNum = self->s.number;\n\tbolt->parent = self;\n\tbolt->damage = 100;\n\tbolt->splashDamage = 100;\n\tbolt->splashRadius = 150;\n\tbolt->methodOfDeath = MOD_GRENADE;\n\tbolt->splashMethodOfDeath = MOD_GRENADE_SPLASH;\n\tbolt->clipmask = MASK_SHOT;\n\tbolt->target_ent = NULL;\n\n\tbolt->s.pos.trType = TR_GRAVITY;\n\tbolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME;\t\t// move a bit on the very first frame\n\tVectorCopy( start, bolt->s.pos.trBase );\n\tVectorScale( dir, 700, bolt->s.pos.trDelta );\n\tSnapVector( bolt->s.pos.trDelta );\t\t\t// save net bandwidth\n\n\tVectorCopy (start, bolt->r.currentOrigin);\n\n\treturn bolt;\n}\n\n//=============================================================================\n\n\n/*\n=================\nfire_bfg\n=================\n*/\ngentity_t *fire_bfg (gentity_t *self, vec3_t start, vec3_t dir) {\n\tgentity_t\t*bolt;\n\n\tVectorNormalize (dir);\n\n\tbolt = G_Spawn();\n\tbolt->classname = \"bfg\";\n\tbolt->nextthink = level.time + 10000;\n\tbolt->think = G_ExplodeMissile;\n\tbolt->s.eType = ET_MISSILE;\n\tbolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;\n\tbolt->s.weapon = WP_BFG;\n\tbolt->r.ownerNum = self->s.number;\n\tbolt->parent = self;\n\tbolt->damage = 100;\n\tbolt->splashDamage = 100;\n\tbolt->splashRadius = 120;\n\tbolt->methodOfDeath = MOD_BFG;\n\tbolt->splashMethodOfDeath = MOD_BFG_SPLASH;\n\tbolt->clipmask = MASK_SHOT;\n\tbolt->target_ent = NULL;\n\n\tbolt->s.pos.trType = TR_LINEAR;\n\tbolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME;\t\t// move a bit on the very first frame\n\tVectorCopy( start, bolt->s.pos.trBase );\n\tVectorScale( dir, 2000, bolt->s.pos.trDelta );\n\tSnapVector( bolt->s.pos.trDelta );\t\t\t// save net bandwidth\n\tVectorCopy (start, bolt->r.currentOrigin);\n\n\treturn bolt;\n}\n\n//=============================================================================\n\n\n/*\n=================\nfire_rocket\n=================\n*/\ngentity_t *fire_rocket (gentity_t *self, vec3_t start, vec3_t dir) {\n\tgentity_t\t*bolt;\n\n\tVectorNormalize (dir);\n\n\tbolt = G_Spawn();\n\tbolt->classname = \"rocket\";\n\tbolt->nextthink = level.time + 15000;\n\tbolt->think = G_ExplodeMissile;\n\tbolt->s.eType = ET_MISSILE;\n\tbolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;\n\tbolt->s.weapon = WP_ROCKET_LAUNCHER;\n\tbolt->r.ownerNum = self->s.number;\n\tbolt->parent = self;\n\tbolt->damage = 100;\n\tbolt->splashDamage = 100;\n\tbolt->splashRadius = 120;\n\tbolt->methodOfDeath = MOD_ROCKET;\n\tbolt->splashMethodOfDeath = MOD_ROCKET_SPLASH;\n\tbolt->clipmask = MASK_SHOT;\n\tbolt->target_ent = NULL;\n\n\tbolt->s.pos.trType = TR_LINEAR;\n\tbolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME;\t\t// move a bit on the very first frame\n\tVectorCopy( start, bolt->s.pos.trBase );\n\tVectorScale( dir, 900, bolt->s.pos.trDelta );\n\tSnapVector( bolt->s.pos.trDelta );\t\t\t// save net bandwidth\n\tVectorCopy (start, bolt->r.currentOrigin);\n\n\treturn bolt;\n}\n\n/*\n=================\nfire_grapple\n=================\n*/\ngentity_t *fire_grapple (gentity_t *self, vec3_t start, vec3_t dir) {\n\tgentity_t\t*hook;\n\n\tVectorNormalize (dir);\n\n\thook = G_Spawn();\n\thook->classname = \"hook\";\n\thook->nextthink = level.time + 10000;\n\thook->think = Weapon_HookFree;\n\thook->s.eType = ET_MISSILE;\n\thook->r.svFlags = SVF_USE_CURRENT_ORIGIN;\n\thook->s.weapon = WP_GRAPPLING_HOOK;\n\thook->r.ownerNum = self->s.number;\n\thook->methodOfDeath = MOD_GRAPPLE;\n\thook->clipmask = MASK_SHOT;\n\thook->parent = self;\n\thook->target_ent = NULL;\n\n\thook->s.pos.trType = TR_LINEAR;\n\thook->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME;\t\t// move a bit on the very first frame\n\thook->s.otherEntityNum = self->s.number; // use to match beam in client\n\tVectorCopy( start, hook->s.pos.trBase );\n\tVectorScale( dir, 800, hook->s.pos.trDelta );\n\tSnapVector( hook->s.pos.trDelta );\t\t\t// save net bandwidth\n\tVectorCopy (start, hook->r.currentOrigin);\n\n\tself->client->hook = hook;\n\n\treturn hook;\n}\n"
  },
  {
    "path": "src/game/g_mover.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n\n#include \"g_local.h\"\n\n\n\n/*\n===============================================================================\n\nPUSHMOVE\n\n===============================================================================\n*/\n\nvoid MatchTeam( gentity_t *teamLeader, int moverState, int time );\n\ntypedef struct {\n\tgentity_t\t*ent;\n\tvec3_t\torigin;\n\tvec3_t\tangles;\n\tfloat\tdeltayaw;\n} pushed_t;\npushed_t\tpushed[MAX_GENTITIES], *pushed_p;\n\n\n/*\n============\nG_TestEntityPosition\n\n============\n*/\ngentity_t\t*G_TestEntityPosition( gentity_t *ent ) {\n\ttrace_t\ttr;\n\tint\t\tmask;\n\n\tif ( ent->clipmask ) {\n\t\tmask = ent->clipmask;\n\t} else {\n\t\tmask = MASK_SOLID;\n\t}\n\tif ( ent->client ) {\n\t\ttrap_Trace( &tr, ent->client->ps.origin, ent->r.mins, ent->r.maxs, ent->client->ps.origin, ent->s.number, mask );\n\t} else {\n\t\ttrap_Trace( &tr, ent->s.pos.trBase, ent->r.mins, ent->r.maxs, ent->s.pos.trBase, ent->s.number, mask );\n\t}\n\t\n\tif (tr.startsolid)\n\t\treturn &g_entities[ tr.entityNum ];\n\t\t\n\treturn NULL;\n}\n\n/*\n================\nG_CreateRotationMatrix\n================\n*/\nvoid G_CreateRotationMatrix(vec3_t angles, vec3_t matrix[3]) {\n\tAngleVectors(angles, matrix[0], matrix[1], matrix[2]);\n\tVectorInverse(matrix[1]);\n}\n\n/*\n================\nG_TransposeMatrix\n================\n*/\nvoid G_TransposeMatrix(vec3_t matrix[3], vec3_t transpose[3]) {\n\tint i, j;\n\tfor (i = 0; i < 3; i++) {\n\t\tfor (j = 0; j < 3; j++) {\n\t\t\ttranspose[i][j] = matrix[j][i];\n\t\t}\n\t}\n}\n\n/*\n================\nG_RotatePoint\n================\n*/\nvoid G_RotatePoint(vec3_t point, vec3_t matrix[3]) {\n\tvec3_t tvec;\n\n\tVectorCopy(point, tvec);\n\tpoint[0] = DotProduct(matrix[0], tvec);\n\tpoint[1] = DotProduct(matrix[1], tvec);\n\tpoint[2] = DotProduct(matrix[2], tvec);\n}\n\n/*\n==================\nG_TryPushingEntity\n\nReturns qfalse if the move is blocked\n==================\n*/\nqboolean\tG_TryPushingEntity( gentity_t *check, gentity_t *pusher, vec3_t move, vec3_t amove ) {\n\tvec3_t\t\tmatrix[3], transpose[3];\n\tvec3_t\t\torg, org2, move2;\n\tgentity_t\t*block;\n\n\t// EF_MOVER_STOP will just stop when contacting another entity\n\t// instead of pushing it, but entities can still ride on top of it\n\tif ( ( pusher->s.eFlags & EF_MOVER_STOP ) && \n\t\tcheck->s.groundEntityNum != pusher->s.number ) {\n\t\treturn qfalse;\n\t}\n\n\t// save off the old position\n\tif (pushed_p > &pushed[MAX_GENTITIES]) {\n\t\tG_Error( \"pushed_p > &pushed[MAX_GENTITIES]\" );\n\t}\n\tpushed_p->ent = check;\n\tVectorCopy (check->s.pos.trBase, pushed_p->origin);\n\tVectorCopy (check->s.apos.trBase, pushed_p->angles);\n\tif ( check->client ) {\n\t\tpushed_p->deltayaw = check->client->ps.delta_angles[YAW];\n\t\tVectorCopy (check->client->ps.origin, pushed_p->origin);\n\t}\n\tpushed_p++;\n\n\t// try moving the contacted entity \n\t// figure movement due to the pusher's amove\n\tG_CreateRotationMatrix( amove, transpose );\n\tG_TransposeMatrix( transpose, matrix );\n\tif ( check->client ) {\n\t\tVectorSubtract (check->client->ps.origin, pusher->r.currentOrigin, org);\n\t}\n\telse {\n\t\tVectorSubtract (check->s.pos.trBase, pusher->r.currentOrigin, org);\n\t}\n\tVectorCopy( org, org2 );\n\tG_RotatePoint( org2, matrix );\n\tVectorSubtract (org2, org, move2);\n\t// add movement\n\tVectorAdd (check->s.pos.trBase, move, check->s.pos.trBase);\n\tVectorAdd (check->s.pos.trBase, move2, check->s.pos.trBase);\n\tif ( check->client ) {\n\t\tVectorAdd (check->client->ps.origin, move, check->client->ps.origin);\n\t\tVectorAdd (check->client->ps.origin, move2, check->client->ps.origin);\n\t\t// make sure the client's view rotates when on a rotating mover\n\t\tcheck->client->ps.delta_angles[YAW] += ANGLE2SHORT(amove[YAW]);\n\t}\n\n\t// may have pushed them off an edge\n\tif ( check->s.groundEntityNum != pusher->s.number ) {\n\t\tcheck->s.groundEntityNum = -1;\n\t}\n\n\tblock = G_TestEntityPosition( check );\n\tif (!block) {\n\t\t// pushed ok\n\t\tif ( check->client ) {\n\t\t\tVectorCopy( check->client->ps.origin, check->r.currentOrigin );\n\t\t} else {\n\t\t\tVectorCopy( check->s.pos.trBase, check->r.currentOrigin );\n\t\t}\n\t\ttrap_LinkEntity (check);\n\t\treturn qtrue;\n\t}\n\n\t// if it is ok to leave in the old position, do it\n\t// this is only relevent for riding entities, not pushed\n\t// Sliding trapdoors can cause this.\n\tVectorCopy( (pushed_p-1)->origin, check->s.pos.trBase);\n\tif ( check->client ) {\n\t\tVectorCopy( (pushed_p-1)->origin, check->client->ps.origin);\n\t}\n\tVectorCopy( (pushed_p-1)->angles, check->s.apos.trBase );\n\tblock = G_TestEntityPosition (check);\n\tif ( !block ) {\n\t\tcheck->s.groundEntityNum = -1;\n\t\tpushed_p--;\n\t\treturn qtrue;\n\t}\n\n\t// blocked\n\treturn qfalse;\n}\n\n/*\n==================\nG_CheckProxMinePosition\n==================\n*/\nqboolean G_CheckProxMinePosition( gentity_t *check ) {\n\tvec3_t\t\tstart, end;\n\ttrace_t\ttr;\n\n\tVectorMA(check->s.pos.trBase, 0.125, check->movedir, start);\n\tVectorMA(check->s.pos.trBase, 2, check->movedir, end);\n\ttrap_Trace( &tr, start, NULL, NULL, end, check->s.number, MASK_SOLID );\n\t\n\tif (tr.startsolid || tr.fraction < 1)\n\t\treturn qfalse;\n\n\treturn qtrue;\n}\n\n/*\n==================\nG_TryPushingProxMine\n==================\n*/\nqboolean G_TryPushingProxMine( gentity_t *check, gentity_t *pusher, vec3_t move, vec3_t amove ) {\n\tvec3_t\t\tforward, right, up;\n\tvec3_t\t\torg, org2, move2;\n\tint ret;\n\n\t// we need this for pushing things later\n\tVectorSubtract (vec3_origin, amove, org);\n\tAngleVectors (org, forward, right, up);\n\n\t// try moving the contacted entity \n\tVectorAdd (check->s.pos.trBase, move, check->s.pos.trBase);\n\n\t// figure movement due to the pusher's amove\n\tVectorSubtract (check->s.pos.trBase, pusher->r.currentOrigin, org);\n\torg2[0] = DotProduct (org, forward);\n\torg2[1] = -DotProduct (org, right);\n\torg2[2] = DotProduct (org, up);\n\tVectorSubtract (org2, org, move2);\n\tVectorAdd (check->s.pos.trBase, move2, check->s.pos.trBase);\n\n\tret = G_CheckProxMinePosition( check );\n\tif (ret) {\n\t\tVectorCopy( check->s.pos.trBase, check->r.currentOrigin );\n\t\ttrap_LinkEntity (check);\n\t}\n\treturn ret;\n}\n\nvoid G_ExplodeMissile( gentity_t *ent );\n\n/*\n============\nG_MoverPush\n\nObjects need to be moved back on a failed push,\notherwise riders would continue to slide.\nIf qfalse is returned, *obstacle will be the blocking entity\n============\n*/\nqboolean G_MoverPush( gentity_t *pusher, vec3_t move, vec3_t amove, gentity_t **obstacle ) {\n\tint\t\t\ti, e;\n\tgentity_t\t*check;\n\tvec3_t\t\tmins, maxs;\n\tpushed_t\t*p;\n\tint\t\t\tentityList[MAX_GENTITIES];\n\tint\t\t\tlistedEntities;\n\tvec3_t\t\ttotalMins, totalMaxs;\n\n\t*obstacle = NULL;\n\n\n\t// mins/maxs are the bounds at the destination\n\t// totalMins / totalMaxs are the bounds for the entire move\n\tif ( pusher->r.currentAngles[0] || pusher->r.currentAngles[1] || pusher->r.currentAngles[2]\n\t\t|| amove[0] || amove[1] || amove[2] ) {\n\t\tfloat\t\tradius;\n\n\t\tradius = RadiusFromBounds( pusher->r.mins, pusher->r.maxs );\n\t\tfor ( i = 0 ; i < 3 ; i++ ) {\n\t\t\tmins[i] = pusher->r.currentOrigin[i] + move[i] - radius;\n\t\t\tmaxs[i] = pusher->r.currentOrigin[i] + move[i] + radius;\n\t\t\ttotalMins[i] = mins[i] - move[i];\n\t\t\ttotalMaxs[i] = maxs[i] - move[i];\n\t\t}\n\t} else {\n\t\tfor (i=0 ; i<3 ; i++) {\n\t\t\tmins[i] = pusher->r.absmin[i] + move[i];\n\t\t\tmaxs[i] = pusher->r.absmax[i] + move[i];\n\t\t}\n\n\t\tVectorCopy( pusher->r.absmin, totalMins );\n\t\tVectorCopy( pusher->r.absmax, totalMaxs );\n\t\tfor (i=0 ; i<3 ; i++) {\n\t\t\tif ( move[i] > 0 ) {\n\t\t\t\ttotalMaxs[i] += move[i];\n\t\t\t} else {\n\t\t\t\ttotalMins[i] += move[i];\n\t\t\t}\n\t\t}\n\t}\n\n\t// unlink the pusher so we don't get it in the entityList\n\ttrap_UnlinkEntity( pusher );\n\n\tlistedEntities = trap_EntitiesInBox( totalMins, totalMaxs, entityList, MAX_GENTITIES );\n\n\t// move the pusher to it's final position\n\tVectorAdd( pusher->r.currentOrigin, move, pusher->r.currentOrigin );\n\tVectorAdd( pusher->r.currentAngles, amove, pusher->r.currentAngles );\n\ttrap_LinkEntity( pusher );\n\n\t// see if any solid entities are inside the final position\n\tfor ( e = 0 ; e < listedEntities ; e++ ) {\n\t\tcheck = &g_entities[ entityList[ e ] ];\n\n\t\t// only push items and players\n\t\tif ( check->s.eType != ET_ITEM && check->s.eType != ET_PLAYER && !check->physicsObject ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// if the entity is standing on the pusher, it will definitely be moved\n\t\tif ( check->s.groundEntityNum != pusher->s.number ) {\n\t\t\t// see if the ent needs to be tested\n\t\t\tif ( check->r.absmin[0] >= maxs[0]\n\t\t\t|| check->r.absmin[1] >= maxs[1]\n\t\t\t|| check->r.absmin[2] >= maxs[2]\n\t\t\t|| check->r.absmax[0] <= mins[0]\n\t\t\t|| check->r.absmax[1] <= mins[1]\n\t\t\t|| check->r.absmax[2] <= mins[2] ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// see if the ent's bbox is inside the pusher's final position\n\t\t\t// this does allow a fast moving object to pass through a thin entity...\n\t\t\tif (!G_TestEntityPosition (check)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\t// the entity needs to be pushed\n\t\tif ( G_TryPushingEntity( check, pusher, move, amove ) ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// the move was blocked an entity\n\n\t\t// bobbing entities are instant-kill and never get blocked\n\t\tif ( pusher->s.pos.trType == TR_SINE || pusher->s.apos.trType == TR_SINE ) {\n\t\t\tG_Damage( check, pusher, pusher, NULL, NULL, 99999, 0, MOD_CRUSH );\n\t\t\tcontinue;\n\t\t}\n\n\t\t\n\t\t// save off the obstacle so we can call the block function (crush, etc)\n\t\t*obstacle = check;\n\n\t\t// move back any entities we already moved\n\t\t// go backwards, so if the same entity was pushed\n\t\t// twice, it goes back to the original position\n\t\tfor ( p=pushed_p-1 ; p>=pushed ; p-- ) {\n\t\t\tVectorCopy (p->origin, p->ent->s.pos.trBase);\n\t\t\tVectorCopy (p->angles, p->ent->s.apos.trBase);\n\t\t\tif ( p->ent->client ) {\n\t\t\t\tp->ent->client->ps.delta_angles[YAW] = p->deltayaw;\n\t\t\t\tVectorCopy (p->origin, p->ent->client->ps.origin);\n\t\t\t}\n\t\t\ttrap_LinkEntity (p->ent);\n\t\t}\n\t\treturn qfalse;\n\t}\n\n\treturn qtrue;\n}\n\n\n/*\n=================\nG_MoverTeam\n=================\n*/\nvoid G_MoverTeam( gentity_t *ent ) {\n\tvec3_t\t\tmove, amove;\n\tgentity_t\t*part, *obstacle;\n\tvec3_t\t\torigin, angles;\n\n\tobstacle = NULL;\n\n\t// make sure all team slaves can move before commiting\n\t// any moves or calling any think functions\n\t// if the move is blocked, all moved objects will be backed out\n\tpushed_p = pushed;\n\tfor (part = ent ; part ; part=part->teamchain) {\n\t\t// get current position\n\t\tBG_EvaluateTrajectory( &part->s.pos, level.time, origin );\n\t\tBG_EvaluateTrajectory( &part->s.apos, level.time, angles );\n\t\tVectorSubtract( origin, part->r.currentOrigin, move );\n\t\tVectorSubtract( angles, part->r.currentAngles, amove );\n\t\tif ( !G_MoverPush( part, move, amove, &obstacle ) ) {\n\t\t\tbreak;\t// move was blocked\n\t\t}\n\t}\n\n\tif (part) {\n\t\t// go back to the previous position\n\t\tfor ( part = ent ; part ; part = part->teamchain ) {\n\t\t\tpart->s.pos.trTime += level.time - level.previousTime;\n\t\t\tpart->s.apos.trTime += level.time - level.previousTime;\n\t\t\tBG_EvaluateTrajectory( &part->s.pos, level.time, part->r.currentOrigin );\n\t\t\tBG_EvaluateTrajectory( &part->s.apos, level.time, part->r.currentAngles );\n\t\t\ttrap_LinkEntity( part );\n\t\t}\n\n\t\t// if the pusher has a \"blocked\" function, call it\n\t\tif (ent->blocked) {\n\t\t\tent->blocked( ent, obstacle );\n\t\t}\n\t\treturn;\n\t}\n\n\t// the move succeeded\n\tfor ( part = ent ; part ; part = part->teamchain ) {\n\t\t// call the reached function if time is at or past end point\n\t\tif ( part->s.pos.trType == TR_LINEAR_STOP ) {\n\t\t\tif ( level.time >= part->s.pos.trTime + part->s.pos.trDuration ) {\n\t\t\t\tif ( part->reached ) {\n\t\t\t\t\tpart->reached( part );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n/*\n================\nG_RunMover\n\n================\n*/\nvoid G_RunMover( gentity_t *ent ) {\n\t// if not a team captain, don't do anything, because\n\t// the captain will handle everything\n\tif ( ent->flags & FL_TEAMSLAVE ) {\n\t\treturn;\n\t}\n\n\t// if stationary at one of the positions, don't move anything\n\tif ( ent->s.pos.trType != TR_STATIONARY || ent->s.apos.trType != TR_STATIONARY ) {\n\t\tG_MoverTeam( ent );\n\t}\n\n\t// check think function\n\tG_RunThink( ent );\n}\n\n/*\n============================================================================\n\nGENERAL MOVERS\n\nDoors, plats, and buttons are all binary (two position) movers\nPos1 is \"at rest\", pos2 is \"activated\"\n============================================================================\n*/\n\n/*\n===============\nSetMoverState\n===============\n*/\nvoid SetMoverState( gentity_t *ent, moverState_t moverState, int time ) {\n\tvec3_t\t\t\tdelta;\n\tfloat\t\t\tf;\n\n\tent->moverState = moverState;\n\n\tent->s.pos.trTime = time;\n\tswitch( moverState ) {\n\tcase MOVER_POS1:\n\t\tVectorCopy( ent->pos1, ent->s.pos.trBase );\n\t\tent->s.pos.trType = TR_STATIONARY;\n\t\tbreak;\n\tcase MOVER_POS2:\n\t\tVectorCopy( ent->pos2, ent->s.pos.trBase );\n\t\tent->s.pos.trType = TR_STATIONARY;\n\t\tbreak;\n\tcase MOVER_1TO2:\n\t\tVectorCopy( ent->pos1, ent->s.pos.trBase );\n\t\tVectorSubtract( ent->pos2, ent->pos1, delta );\n\t\tf = 1000.0 / ent->s.pos.trDuration;\n\t\tVectorScale( delta, f, ent->s.pos.trDelta );\n\t\tent->s.pos.trType = TR_LINEAR_STOP;\n\t\tbreak;\n\tcase MOVER_2TO1:\n\t\tVectorCopy( ent->pos2, ent->s.pos.trBase );\n\t\tVectorSubtract( ent->pos1, ent->pos2, delta );\n\t\tf = 1000.0 / ent->s.pos.trDuration;\n\t\tVectorScale( delta, f, ent->s.pos.trDelta );\n\t\tent->s.pos.trType = TR_LINEAR_STOP;\n\t\tbreak;\n\t}\n\tBG_EvaluateTrajectory( &ent->s.pos, level.time, ent->r.currentOrigin );\t\n\ttrap_LinkEntity( ent );\n}\n\n/*\n================\nMatchTeam\n\nAll entities in a mover team will move from pos1 to pos2\nin the same amount of time\n================\n*/\nvoid MatchTeam( gentity_t *teamLeader, int moverState, int time ) {\n\tgentity_t\t\t*slave;\n\n\tfor ( slave = teamLeader ; slave ; slave = slave->teamchain ) {\n\t\tSetMoverState( slave, moverState, time );\n\t}\n}\n\n\n\n/*\n================\nReturnToPos1\n================\n*/\nvoid ReturnToPos1( gentity_t *ent ) {\n\tMatchTeam( ent, MOVER_2TO1, level.time );\n\n\t// looping sound\n\tent->s.loopSound = ent->soundLoop;\n\n\t// starting sound\n\tif ( ent->sound2to1 ) {\n\t\tG_AddEvent( ent, EV_GENERAL_SOUND, ent->sound2to1 );\n\t}\n}\n\n\n/*\n================\nReached_BinaryMover\n================\n*/\nvoid Reached_BinaryMover( gentity_t *ent ) {\n\n\t// stop the looping sound\n\tent->s.loopSound = ent->soundLoop;\n\n\tif ( ent->moverState == MOVER_1TO2 ) {\n\t\t// reached pos2\n\t\tSetMoverState( ent, MOVER_POS2, level.time );\n\n\t\t// play sound\n\t\tif ( ent->soundPos2 ) {\n\t\t\tG_AddEvent( ent, EV_GENERAL_SOUND, ent->soundPos2 );\n\t\t}\n\n\t\t// return to pos1 after a delay\n\t\tent->think = ReturnToPos1;\n\t\tent->nextthink = level.time + ent->wait;\n\n\t\t// fire targets\n\t\tif ( !ent->activator ) {\n\t\t\tent->activator = ent;\n\t\t}\n\t\tG_UseTargets( ent, ent->activator );\n\t} else if ( ent->moverState == MOVER_2TO1 ) {\n\t\t// reached pos1\n\t\tSetMoverState( ent, MOVER_POS1, level.time );\n\n\t\t// play sound\n\t\tif ( ent->soundPos1 ) {\n\t\t\tG_AddEvent( ent, EV_GENERAL_SOUND, ent->soundPos1 );\n\t\t}\n\n\t\t// close areaportals\n\t\tif ( ent->teammaster == ent || !ent->teammaster ) {\n\t\t\ttrap_AdjustAreaPortalState( ent, qfalse );\n\t\t}\n\t} else {\n\t\tG_Error( \"Reached_BinaryMover: bad moverState\" );\n\t}\n}\n\n\n/*\n================\nUse_BinaryMover\n================\n*/\nvoid Use_BinaryMover( gentity_t *ent, gentity_t *other, gentity_t *activator ) {\n\tint\t\ttotal;\n\tint\t\tpartial;\n\n\t// only the master should be used\n\tif ( ent->flags & FL_TEAMSLAVE ) {\n\t\tUse_BinaryMover( ent->teammaster, other, activator );\n\t\treturn;\n\t}\n\n\tent->activator = activator;\n\n\tif ( ent->moverState == MOVER_POS1 ) {\n\t\t// start moving 50 msec later, becase if this was player\n\t\t// triggered, level.time hasn't been advanced yet\n\t\tMatchTeam( ent, MOVER_1TO2, level.time + 50 );\n\n\t\t// starting sound\n\t\tif ( ent->sound1to2 ) {\n\t\t\tG_AddEvent( ent, EV_GENERAL_SOUND, ent->sound1to2 );\n\t\t}\n\n\t\t// looping sound\n\t\tent->s.loopSound = ent->soundLoop;\n\n\t\t// open areaportal\n\t\tif ( ent->teammaster == ent || !ent->teammaster ) {\n\t\t\ttrap_AdjustAreaPortalState( ent, qtrue );\n\t\t}\n\t\treturn;\n\t}\n\n\t// if all the way up, just delay before coming down\n\tif ( ent->moverState == MOVER_POS2 ) {\n\t\tent->nextthink = level.time + ent->wait;\n\t\treturn;\n\t}\n\n\t// only partway down before reversing\n\tif ( ent->moverState == MOVER_2TO1 ) {\n\t\ttotal = ent->s.pos.trDuration;\n\t\tpartial = level.time - ent->s.pos.trTime;\n\t\tif ( partial > total ) {\n\t\t\tpartial = total;\n\t\t}\n\n\t\tMatchTeam( ent, MOVER_1TO2, level.time - ( total - partial ) );\n\n\t\tif ( ent->sound1to2 ) {\n\t\t\tG_AddEvent( ent, EV_GENERAL_SOUND, ent->sound1to2 );\n\t\t}\n\t\treturn;\n\t}\n\n\t// only partway up before reversing\n\tif ( ent->moverState == MOVER_1TO2 ) {\n\t\ttotal = ent->s.pos.trDuration;\n\t\tpartial = level.time - ent->s.pos.trTime;\n\t\tif ( partial > total ) {\n\t\t\tpartial = total;\n\t\t}\n\n\t\tMatchTeam( ent, MOVER_2TO1, level.time - ( total - partial ) );\n\n\t\tif ( ent->sound2to1 ) {\n\t\t\tG_AddEvent( ent, EV_GENERAL_SOUND, ent->sound2to1 );\n\t\t}\n\t\treturn;\n\t}\n}\n\n\n\n/*\n================\nInitMover\n\n\"pos1\", \"pos2\", and \"speed\" should be set before calling,\nso the movement delta can be calculated\n================\n*/\nvoid InitMover( gentity_t *ent ) {\n\tvec3_t\t\tmove;\n\tfloat\t\tdistance;\n\tfloat\t\tlight;\n\tvec3_t\t\tcolor;\n\tqboolean\tlightSet, colorSet;\n\tchar\t\t*sound;\n\n\t// if the \"model2\" key is set, use a seperate model\n\t// for drawing, but clip against the brushes\n\tif ( ent->model2 ) {\n\t\tent->s.modelindex2 = G_ModelIndex( ent->model2 );\n\t}\n\n\t// if the \"loopsound\" key is set, use a constant looping sound when moving\n\tif ( G_SpawnString( \"noise\", \"100\", &sound ) ) {\n\t\tent->s.loopSound = G_SoundIndex( sound );\n\t}\n\n\t// if the \"color\" or \"light\" keys are set, setup constantLight\n\tlightSet = G_SpawnFloat( \"light\", \"100\", &light );\n\tcolorSet = G_SpawnVector( \"color\", \"1 1 1\", color );\n\tif ( lightSet || colorSet ) {\n\t\tint\t\tr, g, b, i;\n\n\t\tr = color[0] * 255;\n\t\tif ( r > 255 ) {\n\t\t\tr = 255;\n\t\t}\n\t\tg = color[1] * 255;\n\t\tif ( g > 255 ) {\n\t\t\tg = 255;\n\t\t}\n\t\tb = color[2] * 255;\n\t\tif ( b > 255 ) {\n\t\t\tb = 255;\n\t\t}\n\t\ti = light / 4;\n\t\tif ( i > 255 ) {\n\t\t\ti = 255;\n\t\t}\n\t\tent->s.constantLight = r | ( g << 8 ) | ( b << 16 ) | ( i << 24 );\n\t}\n\n\n\tent->use = Use_BinaryMover;\n\tent->reached = Reached_BinaryMover;\n\n\tent->moverState = MOVER_POS1;\n\tent->r.svFlags = SVF_USE_CURRENT_ORIGIN;\n\tent->s.eType = ET_MOVER;\n\tVectorCopy (ent->pos1, ent->r.currentOrigin);\n\ttrap_LinkEntity (ent);\n\n\tent->s.pos.trType = TR_STATIONARY;\n\tVectorCopy( ent->pos1, ent->s.pos.trBase );\n\n\t// calculate time to reach second position from speed\n\tVectorSubtract( ent->pos2, ent->pos1, move );\n\tdistance = VectorLength( move );\n\tif ( ! ent->speed ) {\n\t\tent->speed = 100;\n\t}\n\tVectorScale( move, ent->speed, ent->s.pos.trDelta );\n\tent->s.pos.trDuration = distance * 1000 / ent->speed;\n\tif ( ent->s.pos.trDuration <= 0 ) {\n\t\tent->s.pos.trDuration = 1;\n\t}\n}\n\n\n/*\n===============================================================================\n\nDOOR\n\nA use can be triggered either by a touch function, by being shot, or by being\ntargeted by another entity.\n\n===============================================================================\n*/\n\n/*\n================\nBlocked_Door\n================\n*/\nvoid Blocked_Door( gentity_t *ent, gentity_t *other ) {\n\t// remove anything other than a client\n\tif ( !other->client ) {\n\t\t// except CTF flags!!!!\n\t\tif( other->s.eType == ET_ITEM && other->item->giType == IT_TEAM ) {\n\t\t\tTeam_DroppedFlagThink( other );\n\t\t\treturn;\n\t\t}\n\t\tG_TempEntity( other->s.origin, EV_ITEM_POP );\n\t\tG_FreeEntity( other );\n\t\treturn;\n\t}\n\n\tif ( ent->damage ) {\n\t\tG_Damage( other, ent, ent, NULL, NULL, ent->damage, 0, MOD_CRUSH );\n\t}\n\tif ( ent->spawnflags & 4 ) {\n\t\treturn;\t\t// crushers don't reverse\n\t}\n\n\t// reverse direction\n\tUse_BinaryMover( ent, ent, other );\n}\n\n/*\n================\nTouch_DoorTriggerSpectator\n================\n*/\nstatic void Touch_DoorTriggerSpectator( gentity_t *ent, gentity_t *other, trace_t *trace ) {\n\tint i, axis;\n\tvec3_t origin, dir, angles;\n\n\taxis = ent->count;\n\tVectorClear(dir);\n\tif (fabs(other->s.origin[axis] - ent->r.absmax[axis]) <\n\t\tfabs(other->s.origin[axis] - ent->r.absmin[axis])) {\n\t\torigin[axis] = ent->r.absmin[axis] - 10;\n\t\tdir[axis] = -1;\n\t}\n\telse {\n\t\torigin[axis] = ent->r.absmax[axis] + 10;\n\t\tdir[axis] = 1;\n\t}\n\tfor (i = 0; i < 3; i++) {\n\t\tif (i == axis) continue;\n\t\torigin[i] = (ent->r.absmin[i] + ent->r.absmax[i]) * 0.5;\n\t}\n\tvectoangles(dir, angles);\n\tTeleportPlayer(other, origin, angles );\n}\n\n/*\n================\nTouch_DoorTrigger\n================\n*/\nvoid Touch_DoorTrigger( gentity_t *ent, gentity_t *other, trace_t *trace ) {\n\tif ( other->client && other->client->sess.sessionTeam == TEAM_SPECTATOR ) {\n\t\t// if the door is not open and not opening\n\t\tif ( ent->parent->moverState != MOVER_1TO2 &&\n\t\t\tent->parent->moverState != MOVER_POS2) {\n\t\t\tTouch_DoorTriggerSpectator( ent, other, trace );\n\t\t}\n\t}\n\telse if ( ent->parent->moverState != MOVER_1TO2 ) {\n\t\tUse_BinaryMover( ent->parent, ent, other );\n\t}\n}\n\n\n/*\n======================\nThink_SpawnNewDoorTrigger\n\nAll of the parts of a door have been spawned, so create\na trigger that encloses all of them\n======================\n*/\nvoid Think_SpawnNewDoorTrigger( gentity_t *ent ) {\n\tgentity_t\t\t*other;\n\tvec3_t\t\tmins, maxs;\n\tint\t\t\ti, best;\n\n\t// set all of the slaves as shootable\n\tfor ( other = ent ; other ; other = other->teamchain ) {\n\t\tother->takedamage = qtrue;\n\t}\n\n\t// find the bounds of everything on the team\n\tVectorCopy (ent->r.absmin, mins);\n\tVectorCopy (ent->r.absmax, maxs);\n\n\tfor (other = ent->teamchain ; other ; other=other->teamchain) {\n\t\tAddPointToBounds (other->r.absmin, mins, maxs);\n\t\tAddPointToBounds (other->r.absmax, mins, maxs);\n\t}\n\n\t// find the thinnest axis, which will be the one we expand\n\tbest = 0;\n\tfor ( i = 1 ; i < 3 ; i++ ) {\n\t\tif ( maxs[i] - mins[i] < maxs[best] - mins[best] ) {\n\t\t\tbest = i;\n\t\t}\n\t}\n\tmaxs[best] += 120;\n\tmins[best] -= 120;\n\n\t// create a trigger with this size\n\tother = G_Spawn ();\n\tother->classname = \"door_trigger\";\n\tVectorCopy (mins, other->r.mins);\n\tVectorCopy (maxs, other->r.maxs);\n\tother->parent = ent;\n\tother->r.contents = CONTENTS_TRIGGER;\n\tother->touch = Touch_DoorTrigger;\n\t// remember the thinnest axis\n\tother->count = best;\n\ttrap_LinkEntity (other);\n\n\tMatchTeam( ent, ent->moverState, level.time );\n}\n\nvoid Think_MatchTeam( gentity_t *ent ) {\n\tMatchTeam( ent, ent->moverState, level.time );\n}\n\n\n/*QUAKED func_door (0 .5 .8) ? START_OPEN x CRUSHER\nTOGGLE\t\twait in both the start and end states for a trigger event.\nSTART_OPEN\tthe door to moves to its destination when spawned, and operate in reverse.  It is used to temporarily or permanently close off an area when triggered (not useful for touch or takedamage doors).\nNOMONSTER\tmonsters will not trigger this door\n\n\"model2\"\t.md3 model to also draw\n\"angle\"\t\tdetermines the opening direction\n\"targetname\" if set, no touch field will be spawned and a remote button or trigger field activates the door.\n\"speed\"\t\tmovement speed (100 default)\n\"wait\"\t\twait before returning (3 default, -1 = never return)\n\"lip\"\t\tlip remaining at end of move (8 default)\n\"dmg\"\t\tdamage to inflict when blocked (2 default)\n\"color\"\t\tconstantLight color\n\"light\"\t\tconstantLight radius\n\"health\"\tif set, the door must be shot open\n*/\nvoid SP_func_door (gentity_t *ent) {\n\tvec3_t\tabs_movedir;\n\tfloat\tdistance;\n\tvec3_t\tsize;\n\tfloat\tlip;\n\n\tent->sound1to2 = ent->sound2to1 = G_SoundIndex(\"sound/movers/doors/dr1_strt.wav\");\n\tent->soundPos1 = ent->soundPos2 = G_SoundIndex(\"sound/movers/doors/dr1_end.wav\");\n\n\tent->blocked = Blocked_Door;\n\n\t// default speed of 400\n\tif (!ent->speed)\n\t\tent->speed = 400;\n\n\t// default wait of 2 seconds\n\tif (!ent->wait)\n\t\tent->wait = 2;\n\tent->wait *= 1000;\n\n\t// default lip of 8 units\n\tG_SpawnFloat( \"lip\", \"8\", &lip );\n\n\t// default damage of 2 points\n\tG_SpawnInt( \"dmg\", \"2\", &ent->damage );\n\n\t// first position at start\n\tVectorCopy( ent->s.origin, ent->pos1 );\n\n\t// calculate second position\n\ttrap_SetBrushModel( ent, ent->model );\n\tG_SetMovedir (ent->s.angles, ent->movedir);\n\tabs_movedir[0] = fabs(ent->movedir[0]);\n\tabs_movedir[1] = fabs(ent->movedir[1]);\n\tabs_movedir[2] = fabs(ent->movedir[2]);\n\tVectorSubtract( ent->r.maxs, ent->r.mins, size );\n\tdistance = DotProduct( abs_movedir, size ) - lip;\n\tVectorMA( ent->pos1, distance, ent->movedir, ent->pos2 );\n\n\t// if \"start_open\", reverse position 1 and 2\n\tif ( ent->spawnflags & 1 ) {\n\t\tvec3_t\ttemp;\n\n\t\tVectorCopy( ent->pos2, temp );\n\t\tVectorCopy( ent->s.origin, ent->pos2 );\n\t\tVectorCopy( temp, ent->pos1 );\n\t}\n\n\tInitMover( ent );\n\n\tent->nextthink = level.time + FRAMETIME;\n\n\tif ( ! (ent->flags & FL_TEAMSLAVE ) ) {\n\t\tint health;\n\n\t\tG_SpawnInt( \"health\", \"0\", &health );\n\t\tif ( health ) {\n\t\t\tent->takedamage = qtrue;\n\t\t}\n\t\tif ( ent->targetname || health ) {\n\t\t\t// non touch/shoot doors\n\t\t\tent->think = Think_MatchTeam;\n\t\t} else {\n\t\t\tent->think = Think_SpawnNewDoorTrigger;\n\t\t}\n\t}\n\n\n}\n\n/*\n===============================================================================\n\nPLAT\n\n===============================================================================\n*/\n\n/*\n==============\nTouch_Plat\n\nDon't allow decent if a living player is on it\n===============\n*/\nvoid Touch_Plat( gentity_t *ent, gentity_t *other, trace_t *trace ) {\n\tif ( !other->client || other->client->ps.stats[STAT_HEALTH] <= 0 ) {\n\t\treturn;\n\t}\n\n\t// delay return-to-pos1 by one second\n\tif ( ent->moverState == MOVER_POS2 ) {\n\t\tent->nextthink = level.time + 1000;\n\t}\n}\n\n/*\n==============\nTouch_PlatCenterTrigger\n\nIf the plat is at the bottom position, start it going up\n===============\n*/\nvoid Touch_PlatCenterTrigger(gentity_t *ent, gentity_t *other, trace_t *trace ) {\n\tif ( !other->client ) {\n\t\treturn;\n\t}\n\n\tif ( ent->parent->moverState == MOVER_POS1 ) {\n\t\tUse_BinaryMover( ent->parent, ent, other );\n\t}\n}\n\n\n/*\n================\nSpawnPlatTrigger\n\nSpawn a trigger in the middle of the plat's low position\nElevator cars require that the trigger extend through the entire low position,\nnot just sit on top of it.\n================\n*/\nvoid SpawnPlatTrigger( gentity_t *ent ) {\n\tgentity_t\t*trigger;\n\tvec3_t\ttmin, tmax;\n\n\t// the middle trigger will be a thin trigger just\n\t// above the starting position\n\ttrigger = G_Spawn();\n\ttrigger->classname = \"plat_trigger\";\n\ttrigger->touch = Touch_PlatCenterTrigger;\n\ttrigger->r.contents = CONTENTS_TRIGGER;\n\ttrigger->parent = ent;\n\t\n\ttmin[0] = ent->pos1[0] + ent->r.mins[0] + 33;\n\ttmin[1] = ent->pos1[1] + ent->r.mins[1] + 33;\n\ttmin[2] = ent->pos1[2] + ent->r.mins[2];\n\n\ttmax[0] = ent->pos1[0] + ent->r.maxs[0] - 33;\n\ttmax[1] = ent->pos1[1] + ent->r.maxs[1] - 33;\n\ttmax[2] = ent->pos1[2] + ent->r.maxs[2] + 8;\n\n\tif ( tmax[0] <= tmin[0] ) {\n\t\ttmin[0] = ent->pos1[0] + (ent->r.mins[0] + ent->r.maxs[0]) *0.5;\n\t\ttmax[0] = tmin[0] + 1;\n\t}\n\tif ( tmax[1] <= tmin[1] ) {\n\t\ttmin[1] = ent->pos1[1] + (ent->r.mins[1] + ent->r.maxs[1]) *0.5;\n\t\ttmax[1] = tmin[1] + 1;\n\t}\n\t\n\tVectorCopy (tmin, trigger->r.mins);\n\tVectorCopy (tmax, trigger->r.maxs);\n\n\ttrap_LinkEntity (trigger);\n}\n\n\n/*QUAKED func_plat (0 .5 .8) ?\nPlats are always drawn in the extended position so they will light correctly.\n\n\"lip\"\t\tdefault 8, protrusion above rest position\n\"height\"\ttotal height of movement, defaults to model height\n\"speed\"\t\toverrides default 200.\n\"dmg\"\t\toverrides default 2\n\"model2\"\t.md3 model to also draw\n\"color\"\t\tconstantLight color\n\"light\"\t\tconstantLight radius\n*/\nvoid SP_func_plat (gentity_t *ent) {\n\tfloat\t\tlip, height;\n\n\tent->sound1to2 = ent->sound2to1 = G_SoundIndex(\"sound/movers/plats/pt1_strt.wav\");\n\tent->soundPos1 = ent->soundPos2 = G_SoundIndex(\"sound/movers/plats/pt1_end.wav\");\n\n\tVectorClear (ent->s.angles);\n\n\tG_SpawnFloat( \"speed\", \"200\", &ent->speed );\n\tG_SpawnInt( \"dmg\", \"2\", &ent->damage );\n\tG_SpawnFloat( \"wait\", \"1\", &ent->wait );\n\tG_SpawnFloat( \"lip\", \"8\", &lip );\n\n\tent->wait = 1000;\n\n\t// create second position\n\ttrap_SetBrushModel( ent, ent->model );\n\n\tif ( !G_SpawnFloat( \"height\", \"0\", &height ) ) {\n\t\theight = (ent->r.maxs[2] - ent->r.mins[2]) - lip;\n\t}\n\n\t// pos1 is the rest (bottom) position, pos2 is the top\n\tVectorCopy( ent->s.origin, ent->pos2 );\n\tVectorCopy( ent->pos2, ent->pos1 );\n\tent->pos1[2] -= height;\n\n\tInitMover( ent );\n\n\t// touch function keeps the plat from returning while\n\t// a live player is standing on it\n\tent->touch = Touch_Plat;\n\n\tent->blocked = Blocked_Door;\n\n\tent->parent = ent;\t// so it can be treated as a door\n\n\t// spawn the trigger if one hasn't been custom made\n\tif ( !ent->targetname ) {\n\t\tSpawnPlatTrigger(ent);\n\t}\n}\n\n\n/*\n===============================================================================\n\nBUTTON\n\n===============================================================================\n*/\n\n/*\n==============\nTouch_Button\n\n===============\n*/\nvoid Touch_Button(gentity_t *ent, gentity_t *other, trace_t *trace ) {\n\tif ( !other->client ) {\n\t\treturn;\n\t}\n\n\tif ( ent->moverState == MOVER_POS1 ) {\n\t\tUse_BinaryMover( ent, other, other );\n\t}\n}\n\n\n/*QUAKED func_button (0 .5 .8) ?\nWhen a button is touched, it moves some distance in the direction of it's angle, triggers all of it's targets, waits some time, then returns to it's original position where it can be triggered again.\n\n\"model2\"\t.md3 model to also draw\n\"angle\"\t\tdetermines the opening direction\n\"target\"\tall entities with a matching targetname will be used\n\"speed\"\t\toverride the default 40 speed\n\"wait\"\t\toverride the default 1 second wait (-1 = never return)\n\"lip\"\t\toverride the default 4 pixel lip remaining at end of move\n\"health\"\tif set, the button must be killed instead of touched\n\"color\"\t\tconstantLight color\n\"light\"\t\tconstantLight radius\n*/\nvoid SP_func_button( gentity_t *ent ) {\n\tvec3_t\t\tabs_movedir;\n\tfloat\t\tdistance;\n\tvec3_t\t\tsize;\n\tfloat\t\tlip;\n\n\tent->sound1to2 = G_SoundIndex(\"sound/movers/switches/butn2.wav\");\n\t\n\tif ( !ent->speed ) {\n\t\tent->speed = 40;\n\t}\n\n\tif ( !ent->wait ) {\n\t\tent->wait = 1;\n\t}\n\tent->wait *= 1000;\n\n\t// first position\n\tVectorCopy( ent->s.origin, ent->pos1 );\n\n\t// calculate second position\n\ttrap_SetBrushModel( ent, ent->model );\n\n\tG_SpawnFloat( \"lip\", \"4\", &lip );\n\n\tG_SetMovedir( ent->s.angles, ent->movedir );\n\tabs_movedir[0] = fabs(ent->movedir[0]);\n\tabs_movedir[1] = fabs(ent->movedir[1]);\n\tabs_movedir[2] = fabs(ent->movedir[2]);\n\tVectorSubtract( ent->r.maxs, ent->r.mins, size );\n\tdistance = abs_movedir[0] * size[0] + abs_movedir[1] * size[1] + abs_movedir[2] * size[2] - lip;\n\tVectorMA (ent->pos1, distance, ent->movedir, ent->pos2);\n\n\tif (ent->health) {\n\t\t// shootable button\n\t\tent->takedamage = qtrue;\n\t} else {\n\t\t// touchable button\n\t\tent->touch = Touch_Button;\n\t}\n\n\tInitMover( ent );\n}\n\n\n\n/*\n===============================================================================\n\nTRAIN\n\n===============================================================================\n*/\n\n\n#define TRAIN_START_ON\t\t1\n#define TRAIN_TOGGLE\t\t2\n#define TRAIN_BLOCK_STOPS\t4\n\n/*\n===============\nThink_BeginMoving\n\nThe wait time at a corner has completed, so start moving again\n===============\n*/\nvoid Think_BeginMoving( gentity_t *ent ) {\n\tent->s.pos.trTime = level.time;\n\tent->s.pos.trType = TR_LINEAR_STOP;\n}\n\n/*\n===============\nReached_Train\n===============\n*/\nvoid Reached_Train( gentity_t *ent ) {\n\tgentity_t\t\t*next;\n\tfloat\t\t\tspeed;\n\tvec3_t\t\t\tmove;\n\tfloat\t\t\tlength;\n\n\t// copy the apropriate values\n\tnext = ent->nextTrain;\n\tif ( !next || !next->nextTrain ) {\n\t\treturn;\t\t// just stop\n\t}\n\n\t// fire all other targets\n\tG_UseTargets( next, NULL );\n\n\t// set the new trajectory\n\tent->nextTrain = next->nextTrain;\n\tVectorCopy( next->s.origin, ent->pos1 );\n\tVectorCopy( next->nextTrain->s.origin, ent->pos2 );\n\n\t// if the path_corner has a speed, use that\n\tif ( next->speed ) {\n\t\tspeed = next->speed;\n\t} else {\n\t\t// otherwise use the train's speed\n\t\tspeed = ent->speed;\n\t}\n\tif ( speed < 1 ) {\n\t\tspeed = 1;\n\t}\n\n\t// calculate duration\n\tVectorSubtract( ent->pos2, ent->pos1, move );\n\tlength = VectorLength( move );\n\n\tent->s.pos.trDuration = length * 1000 / speed;\n\n\t// looping sound\n\tent->s.loopSound = next->soundLoop;\n\n\t// start it going\n\tSetMoverState( ent, MOVER_1TO2, level.time );\n\n\t// if there is a \"wait\" value on the target, don't start moving yet\n\tif ( next->wait ) {\n\t\tent->nextthink = level.time + next->wait * 1000;\n\t\tent->think = Think_BeginMoving;\n\t\tent->s.pos.trType = TR_STATIONARY;\n\t}\n}\n\n\n/*\n===============\nThink_SetupTrainTargets\n\nLink all the corners together\n===============\n*/\nvoid Think_SetupTrainTargets( gentity_t *ent ) {\n\tgentity_t\t\t*path, *next, *start;\n\n\tent->nextTrain = G_Find( NULL, FOFS(targetname), ent->target );\n\tif ( !ent->nextTrain ) {\n\t\tG_Printf( \"func_train at %s with an unfound target\\n\",\n\t\t\tvtos(ent->r.absmin) );\n\t\treturn;\n\t}\n\n\tstart = NULL;\n\tfor ( path = ent->nextTrain ; path != start ; path = next ) {\n\t\tif ( !start ) {\n\t\t\tstart = path;\n\t\t}\n\n\t\tif ( !path->target ) {\n\t\t\tG_Printf( \"Train corner at %s without a target\\n\",\n\t\t\t\tvtos(path->s.origin) );\n\t\t\treturn;\n\t\t}\n\n\t\t// find a path_corner among the targets\n\t\t// there may also be other targets that get fired when the corner\n\t\t// is reached\n\t\tnext = NULL;\n\t\tdo {\n\t\t\tnext = G_Find( next, FOFS(targetname), path->target );\n\t\t\tif ( !next ) {\n\t\t\t\tG_Printf( \"Train corner at %s without a target path_corner\\n\",\n\t\t\t\t\tvtos(path->s.origin) );\n\t\t\t\treturn;\n\t\t\t}\n\t\t} while ( strcmp( next->classname, \"path_corner\" ) );\n\n\t\tpath->nextTrain = next;\n\t}\n\n\t// start the train moving from the first corner\n\tReached_Train( ent );\n}\n\n\n\n/*QUAKED path_corner (.5 .3 0) (-8 -8 -8) (8 8 8)\nTrain path corners.\nTarget: next path corner and other targets to fire\n\"speed\" speed to move to the next corner\n\"wait\" seconds to wait before behining move to next corner\n*/\nvoid SP_path_corner( gentity_t *self ) {\n\tif ( !self->targetname ) {\n\t\tG_Printf (\"path_corner with no targetname at %s\\n\", vtos(self->s.origin));\n\t\tG_FreeEntity( self );\n\t\treturn;\n\t}\n\t// path corners don't need to be linked in\n}\n\n\n\n/*QUAKED func_train (0 .5 .8) ? START_ON TOGGLE BLOCK_STOPS\nA train is a mover that moves between path_corner target points.\nTrains MUST HAVE AN ORIGIN BRUSH.\nThe train spawns at the first target it is pointing at.\n\"model2\"\t.md3 model to also draw\n\"speed\"\t\tdefault 100\n\"dmg\"\t\tdefault\t2\n\"noise\"\t\tlooping sound to play when the train is in motion\n\"target\"\tnext path corner\n\"color\"\t\tconstantLight color\n\"light\"\t\tconstantLight radius\n*/\nvoid SP_func_train (gentity_t *self) {\n\tVectorClear (self->s.angles);\n\n\tif (self->spawnflags & TRAIN_BLOCK_STOPS) {\n\t\tself->damage = 0;\n\t} else {\n\t\tif (!self->damage) {\n\t\t\tself->damage = 2;\n\t\t}\n\t}\n\n\tif ( !self->speed ) {\n\t\tself->speed = 100;\n\t}\n\n\tif ( !self->target ) {\n\t\tG_Printf (\"func_train without a target at %s\\n\", vtos(self->r.absmin));\n\t\tG_FreeEntity( self );\n\t\treturn;\n\t}\n\n\ttrap_SetBrushModel( self, self->model );\n\tInitMover( self );\n\n\tself->reached = Reached_Train;\n\n\t// start trains on the second frame, to make sure their targets have had\n\t// a chance to spawn\n\tself->nextthink = level.time + FRAMETIME;\n\tself->think = Think_SetupTrainTargets;\n}\n\n/*\n===============================================================================\n\nSTATIC\n\n===============================================================================\n*/\n\n\n/*QUAKED func_static (0 .5 .8) ?\nA bmodel that just sits there, doing nothing.  Can be used for conditional walls and models.\n\"model2\"\t.md3 model to also draw\n\"color\"\t\tconstantLight color\n\"light\"\t\tconstantLight radius\n*/\nvoid SP_func_static( gentity_t *ent ) {\n\ttrap_SetBrushModel( ent, ent->model );\n\tInitMover( ent );\n\tVectorCopy( ent->s.origin, ent->s.pos.trBase );\n\tVectorCopy( ent->s.origin, ent->r.currentOrigin );\n}\n\n\n/*\n===============================================================================\n\nROTATING\n\n===============================================================================\n*/\n\n\n/*QUAKED func_rotating (0 .5 .8) ? START_ON - X_AXIS Y_AXIS\nYou need to have an origin brush as part of this entity.  The center of that brush will be\nthe point around which it is rotated. It will rotate around the Z axis by default.  You can\ncheck either the X_AXIS or Y_AXIS box to change that.\n\n\"model2\"\t.md3 model to also draw\n\"speed\"\t\tdetermines how fast it moves; default value is 100.\n\"dmg\"\t\tdamage to inflict when blocked (2 default)\n\"color\"\t\tconstantLight color\n\"light\"\t\tconstantLight radius\n*/\nvoid SP_func_rotating (gentity_t *ent) {\n\tif ( !ent->speed ) {\n\t\tent->speed = 100;\n\t}\n\n\t// set the axis of rotation\n\tent->s.apos.trType = TR_LINEAR;\n\tif ( ent->spawnflags & 4 ) {\n\t\tent->s.apos.trDelta[2] = ent->speed;\n\t} else if ( ent->spawnflags & 8 ) {\n\t\tent->s.apos.trDelta[0] = ent->speed;\n\t} else {\n\t\tent->s.apos.trDelta[1] = ent->speed;\n\t}\n\n\tif (!ent->damage) {\n\t\tent->damage = 2;\n\t}\n\n\ttrap_SetBrushModel( ent, ent->model );\n\tInitMover( ent );\n\n\tVectorCopy( ent->s.origin, ent->s.pos.trBase );\n\tVectorCopy( ent->s.pos.trBase, ent->r.currentOrigin );\n\tVectorCopy( ent->s.apos.trBase, ent->r.currentAngles );\n\n\ttrap_LinkEntity( ent );\n}\n\n\n/*\n===============================================================================\n\nBOBBING\n\n===============================================================================\n*/\n\n\n/*QUAKED func_bobbing (0 .5 .8) ? X_AXIS Y_AXIS\nNormally bobs on the Z axis\n\"model2\"\t.md3 model to also draw\n\"height\"\tamplitude of bob (32 default)\n\"speed\"\t\tseconds to complete a bob cycle (4 default)\n\"phase\"\t\tthe 0.0 to 1.0 offset in the cycle to start at\n\"dmg\"\t\tdamage to inflict when blocked (2 default)\n\"color\"\t\tconstantLight color\n\"light\"\t\tconstantLight radius\n*/\nvoid SP_func_bobbing (gentity_t *ent) {\n\tfloat\t\theight;\n\tfloat\t\tphase;\n\n\tG_SpawnFloat( \"speed\", \"4\", &ent->speed );\n\tG_SpawnFloat( \"height\", \"32\", &height );\n\tG_SpawnInt( \"dmg\", \"2\", &ent->damage );\n\tG_SpawnFloat( \"phase\", \"0\", &phase );\n\n\ttrap_SetBrushModel( ent, ent->model );\n\tInitMover( ent );\n\n\tVectorCopy( ent->s.origin, ent->s.pos.trBase );\n\tVectorCopy( ent->s.origin, ent->r.currentOrigin );\n\n\tent->s.pos.trDuration = ent->speed * 1000;\n\tent->s.pos.trTime = ent->s.pos.trDuration * phase;\n\tent->s.pos.trType = TR_SINE;\n\n\t// set the axis of bobbing\n\tif ( ent->spawnflags & 1 ) {\n\t\tent->s.pos.trDelta[0] = height;\n\t} else if ( ent->spawnflags & 2 ) {\n\t\tent->s.pos.trDelta[1] = height;\n\t} else {\n\t\tent->s.pos.trDelta[2] = height;\n\t}\n}\n\n/*\n===============================================================================\n\nPENDULUM\n\n===============================================================================\n*/\n\n\n/*QUAKED func_pendulum (0 .5 .8) ?\nYou need to have an origin brush as part of this entity.\nPendulums always swing north / south on unrotated models.  Add an angles field to the model to allow rotation in other directions.\nPendulum frequency is a physical constant based on the length of the beam and gravity.\n\"model2\"\t.md3 model to also draw\n\"speed\"\t\tthe number of degrees each way the pendulum swings, (30 default)\n\"phase\"\t\tthe 0.0 to 1.0 offset in the cycle to start at\n\"dmg\"\t\tdamage to inflict when blocked (2 default)\n\"color\"\t\tconstantLight color\n\"light\"\t\tconstantLight radius\n*/\nvoid SP_func_pendulum(gentity_t *ent) {\n\tfloat\t\tfreq;\n\tfloat\t\tlength;\n\tfloat\t\tphase;\n\tfloat\t\tspeed;\n\n\tG_SpawnFloat( \"speed\", \"30\", &speed );\n\tG_SpawnInt( \"dmg\", \"2\", &ent->damage );\n\tG_SpawnFloat( \"phase\", \"0\", &phase );\n\n\ttrap_SetBrushModel( ent, ent->model );\n\n\t// find pendulum length\n\tlength = fabs( ent->r.mins[2] );\n\tif ( length < 8 ) {\n\t\tlength = 8;\n\t}\n\n\tfreq = 1 / ( M_PI * 2 ) * sqrt( g_gravity.value / ( 3 * length ) );\n\n\tent->s.pos.trDuration = ( 1000 / freq );\n\n\tInitMover( ent );\n\n\tVectorCopy( ent->s.origin, ent->s.pos.trBase );\n\tVectorCopy( ent->s.origin, ent->r.currentOrigin );\n\n\tVectorCopy( ent->s.angles, ent->s.apos.trBase );\n\n\tent->s.apos.trDuration = 1000 / freq;\n\tent->s.apos.trTime = ent->s.apos.trDuration * phase;\n\tent->s.apos.trType = TR_SINE;\n\tent->s.apos.trDelta[2] = speed;\n}\n"
  },
  {
    "path": "src/game/g_public.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n\n// g_public.h -- game module information visible to server\n\n#define\tGAME_API_VERSION\t8\n\n// entity->svFlags\n// the server does not know how to interpret most of the values\n// in entityStates (level eType), so the game must explicitly flag\n// special server behaviors\n#define\tSVF_NOCLIENT\t\t\t0x00000001\t// don't send entity to clients, even if it has effects\n\n// TTimo\n// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=551\n#define SVF_CLIENTMASK 0x00000002\n\n#define SVF_BOT\t\t\t\t\t0x00000008\t// set if the entity is a bot\n#define\tSVF_BROADCAST\t\t\t0x00000020\t// send to all connected clients\n#define\tSVF_PORTAL\t\t\t\t0x00000040\t// merge a second pvs at origin2 into snapshots\n#define\tSVF_USE_CURRENT_ORIGIN\t0x00000080\t// entity->r.currentOrigin instead of entity->s.origin\n\t\t\t\t\t\t\t\t\t\t\t// for link position (missiles and movers)\n#define SVF_SINGLECLIENT\t\t0x00000100\t// only send to a single client (entityShared_t->singleClient)\n#define SVF_NOSERVERINFO\t\t0x00000200\t// don't send CS_SERVERINFO updates to this client\n\t\t\t\t\t\t\t\t\t\t\t// so that it can be updated for ping tools without\n\t\t\t\t\t\t\t\t\t\t\t// lagging clients\n#define SVF_CAPSULE\t\t\t\t0x00000400\t// use capsule for collision detection instead of bbox\n#define SVF_NOTSINGLECLIENT\t\t0x00000800\t// send entity to everyone but one client\n\t\t\t\t\t\t\t\t\t\t\t// (entityShared_t->singleClient)\n\n\n\n//===============================================================\n\n\ntypedef struct {\n\tentityState_t\ts;\t\t\t\t// communicated by server to clients\n\n\tqboolean\tlinked;\t\t\t\t// qfalse if not in any good cluster\n\tint\t\t\tlinkcount;\n\n\tint\t\t\tsvFlags;\t\t\t// SVF_NOCLIENT, SVF_BROADCAST, etc\n\n\t// only send to this client when SVF_SINGLECLIENT is set\t\n\t// if SVF_CLIENTMASK is set, use bitmask for clients to send to (maxclients must be <= 32, up to the mod to enforce this)\n\tint\t\t\tsingleClient;\t\t\n\n\tqboolean\tbmodel;\t\t\t\t// if false, assume an explicit mins / maxs bounding box\n\t\t\t\t\t\t\t\t\t// only set by trap_SetBrushModel\n\tvec3_t\t\tmins, maxs;\n\tint\t\t\tcontents;\t\t\t// CONTENTS_TRIGGER, CONTENTS_SOLID, CONTENTS_BODY, etc\n\t\t\t\t\t\t\t\t\t// a non-solid entity should set to 0\n\n\tvec3_t\t\tabsmin, absmax;\t\t// derived from mins/maxs and origin + rotation\n\n\t// currentOrigin will be used for all collision detection and world linking.\n\t// it will not necessarily be the same as the trajectory evaluation for the current\n\t// time, because each entity must be moved one at a time after time is advanced\n\t// to avoid simultanious collision issues\n\tvec3_t\t\tcurrentOrigin;\n\tvec3_t\t\tcurrentAngles;\n\n\t// when a trace call is made and passEntityNum != ENTITYNUM_NONE,\n\t// an ent will be excluded from testing if:\n\t// ent->s.number == passEntityNum\t(don't interact with self)\n\t// ent->s.ownerNum = passEntityNum\t(don't interact with your own missiles)\n\t// entity[ent->s.ownerNum].ownerNum = passEntityNum\t(don't interact with other missiles from owner)\n\tint\t\t\townerNum;\n} entityShared_t;\n\n\n\n// the server looks at a sharedEntity, which is the start of the game's gentity_t structure\ntypedef struct {\n\tentityState_t\ts;\t\t\t\t// communicated by server to clients\n\tentityShared_t\tr;\t\t\t\t// shared by both the server system and game\n} sharedEntity_t;\n\n\n\n//===============================================================\n\n//\n// system traps provided by the main engine\n//\ntypedef enum {\n\t//============== general Quake services ==================\n\n\tG_PRINT,\t\t// ( const char *string );\n\t// print message on the local console\n\n\tG_ERROR,\t\t// ( const char *string );\n\t// abort the game\n\n\tG_MILLISECONDS,\t// ( void );\n\t// get current time for profiling reasons\n\t// this should NOT be used for any game related tasks,\n\t// because it is not journaled\n\n\t// console variable interaction\n\tG_CVAR_REGISTER,\t// ( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags );\n\tG_CVAR_UPDATE,\t// ( vmCvar_t *vmCvar );\n\tG_CVAR_SET,\t\t// ( const char *var_name, const char *value );\n\tG_CVAR_VARIABLE_INTEGER_VALUE,\t// ( const char *var_name );\n\n\tG_CVAR_VARIABLE_STRING_BUFFER,\t// ( const char *var_name, char *buffer, int bufsize );\n\n\tG_ARGC,\t\t\t// ( void );\n\t// ClientCommand and ServerCommand parameter access\n\n\tG_ARGV,\t\t\t// ( int n, char *buffer, int bufferLength );\n\n\tG_FS_FOPEN_FILE,\t// ( const char *qpath, fileHandle_t *file, fsMode_t mode );\n\tG_FS_READ,\t\t// ( void *buffer, int len, fileHandle_t f );\n\tG_FS_WRITE,\t\t// ( const void *buffer, int len, fileHandle_t f );\n\tG_FS_FCLOSE_FILE,\t\t// ( fileHandle_t f );\n\n\tG_SEND_CONSOLE_COMMAND,\t// ( const char *text );\n\t// add commands to the console as if they were typed in\n\t// for map changing, etc\n\n\n\t//=========== server specific functionality =============\n\n\tG_LOCATE_GAME_DATA,\t\t// ( gentity_t *gEnts, int numGEntities, int sizeofGEntity_t,\n\t//\t\t\t\t\t\t\tplayerState_t *clients, int sizeofGameClient );\n\t// the game needs to let the server system know where and how big the gentities\n\t// are, so it can look at them directly without going through an interface\n\n\tG_DROP_CLIENT,\t\t// ( int clientNum, const char *reason );\n\t// kick a client off the server with a message\n\n\tG_SEND_SERVER_COMMAND,\t// ( int clientNum, const char *fmt, ... );\n\t// reliably sends a command string to be interpreted by the given\n\t// client.  If clientNum is -1, it will be sent to all clients\n\n\tG_SET_CONFIGSTRING,\t// ( int num, const char *string );\n\t// config strings hold all the index strings, and various other information\n\t// that is reliably communicated to all clients\n\t// All of the current configstrings are sent to clients when\n\t// they connect, and changes are sent to all connected clients.\n\t// All confgstrings are cleared at each level start.\n\n\tG_GET_CONFIGSTRING,\t// ( int num, char *buffer, int bufferSize );\n\n\tG_GET_USERINFO,\t\t// ( int num, char *buffer, int bufferSize );\n\t// userinfo strings are maintained by the server system, so they\n\t// are persistant across level loads, while all other game visible\n\t// data is completely reset\n\n\tG_SET_USERINFO,\t\t// ( int num, const char *buffer );\n\n\tG_GET_SERVERINFO,\t// ( char *buffer, int bufferSize );\n\t// the serverinfo info string has all the cvars visible to server browsers\n\n\tG_SET_BRUSH_MODEL,\t// ( gentity_t *ent, const char *name );\n\t// sets mins and maxs based on the brushmodel name\n\n\tG_TRACE,\t// ( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentmask );\n\t// collision detection against all linked entities\n\n\tG_POINT_CONTENTS,\t// ( const vec3_t point, int passEntityNum );\n\t// point contents against all linked entities\n\n\tG_IN_PVS,\t\t\t// ( const vec3_t p1, const vec3_t p2 );\n\n\tG_IN_PVS_IGNORE_PORTALS,\t// ( const vec3_t p1, const vec3_t p2 );\n\n\tG_ADJUST_AREA_PORTAL_STATE,\t// ( gentity_t *ent, qboolean open );\n\n\tG_AREAS_CONNECTED,\t// ( int area1, int area2 );\n\n\tG_LINKENTITY,\t\t// ( gentity_t *ent );\n\t// an entity will never be sent to a client or used for collision\n\t// if it is not passed to linkentity.  If the size, position, or\n\t// solidity changes, it must be relinked.\n\n\tG_UNLINKENTITY,\t\t// ( gentity_t *ent );\t\t\n\t// call before removing an interactive entity\n\n\tG_ENTITIES_IN_BOX,\t// ( const vec3_t mins, const vec3_t maxs, gentity_t **list, int maxcount );\n\t// EntitiesInBox will return brush models based on their bounding box,\n\t// so exact determination must still be done with EntityContact\n\n\tG_ENTITY_CONTACT,\t// ( const vec3_t mins, const vec3_t maxs, const gentity_t *ent );\n\t// perform an exact check against inline brush models of non-square shape\n\n\t// access for bots to get and free a server client (FIXME?)\n\tG_BOT_ALLOCATE_CLIENT,\t// ( void );\n\n\tG_BOT_FREE_CLIENT,\t// ( int clientNum );\n\n\tG_GET_USERCMD,\t// ( int clientNum, usercmd_t *cmd )\n\n\tG_GET_ENTITY_TOKEN,\t// qboolean ( char *buffer, int bufferSize )\n\t// Retrieves the next string token from the entity spawn text, returning\n\t// false when all tokens have been parsed.\n\t// This should only be done at GAME_INIT time.\n\n\tG_FS_GETFILELIST,\n\tG_DEBUG_POLYGON_CREATE,\n\tG_DEBUG_POLYGON_DELETE,\n\tG_REAL_TIME,\n\tG_SNAPVECTOR,\n\n\tG_TRACECAPSULE,\t// ( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentmask );\n\tG_ENTITY_CONTACTCAPSULE,\t// ( const vec3_t mins, const vec3_t maxs, const gentity_t *ent );\n\t\n\t// 1.32\n\tG_FS_SEEK,\n\n\tBOTLIB_SETUP = 200,\t\t\t\t// ( void );\n\tBOTLIB_SHUTDOWN,\t\t\t\t// ( void );\n\tBOTLIB_LIBVAR_SET,\n\tBOTLIB_LIBVAR_GET,\n\tBOTLIB_PC_ADD_GLOBAL_DEFINE,\n\tBOTLIB_START_FRAME,\n\tBOTLIB_LOAD_MAP,\n\tBOTLIB_UPDATENTITY,\n\tBOTLIB_TEST,\n\n\tBOTLIB_GET_SNAPSHOT_ENTITY,\t\t// ( int client, int ent );\n\tBOTLIB_GET_CONSOLE_MESSAGE,\t\t// ( int client, char *message, int size );\n\tBOTLIB_USER_COMMAND,\t\t\t// ( int client, usercmd_t *ucmd );\n\n\tBOTLIB_AAS_ENABLE_ROUTING_AREA = 300,\n\tBOTLIB_AAS_BBOX_AREAS,\n\tBOTLIB_AAS_AREA_INFO,\n\tBOTLIB_AAS_ENTITY_INFO,\n\n\tBOTLIB_AAS_INITIALIZED,\n\tBOTLIB_AAS_PRESENCE_TYPE_BOUNDING_BOX,\n\tBOTLIB_AAS_TIME,\n\n\tBOTLIB_AAS_POINT_AREA_NUM,\n\tBOTLIB_AAS_TRACE_AREAS,\n\n\tBOTLIB_AAS_POINT_CONTENTS,\n\tBOTLIB_AAS_NEXT_BSP_ENTITY,\n\tBOTLIB_AAS_VALUE_FOR_BSP_EPAIR_KEY,\n\tBOTLIB_AAS_VECTOR_FOR_BSP_EPAIR_KEY,\n\tBOTLIB_AAS_FLOAT_FOR_BSP_EPAIR_KEY,\n\tBOTLIB_AAS_INT_FOR_BSP_EPAIR_KEY,\n\n\tBOTLIB_AAS_AREA_REACHABILITY,\n\n\tBOTLIB_AAS_AREA_TRAVEL_TIME_TO_GOAL_AREA,\n\n\tBOTLIB_AAS_SWIMMING,\n\tBOTLIB_AAS_PREDICT_CLIENT_MOVEMENT,\n\n\tBOTLIB_EA_SAY = 400,\n\tBOTLIB_EA_SAY_TEAM,\n\tBOTLIB_EA_COMMAND,\n\n\tBOTLIB_EA_ACTION,\n\tBOTLIB_EA_GESTURE,\n\tBOTLIB_EA_TALK,\n\tBOTLIB_EA_ATTACK,\n\tBOTLIB_EA_USE,\n\tBOTLIB_EA_RESPAWN,\n\tBOTLIB_EA_CROUCH,\n\tBOTLIB_EA_MOVE_UP,\n\tBOTLIB_EA_MOVE_DOWN,\n\tBOTLIB_EA_MOVE_FORWARD,\n\tBOTLIB_EA_MOVE_BACK,\n\tBOTLIB_EA_MOVE_LEFT,\n\tBOTLIB_EA_MOVE_RIGHT,\n\n\tBOTLIB_EA_SELECT_WEAPON,\n\tBOTLIB_EA_JUMP,\n\tBOTLIB_EA_DELAYED_JUMP,\n\tBOTLIB_EA_MOVE,\n\tBOTLIB_EA_VIEW,\n\n\tBOTLIB_EA_END_REGULAR,\n\tBOTLIB_EA_GET_INPUT,\n\tBOTLIB_EA_RESET_INPUT,\n\n\n\tBOTLIB_AI_LOAD_CHARACTER = 500,\n\tBOTLIB_AI_FREE_CHARACTER,\n\tBOTLIB_AI_CHARACTERISTIC_FLOAT,\n\tBOTLIB_AI_CHARACTERISTIC_BFLOAT,\n\tBOTLIB_AI_CHARACTERISTIC_INTEGER,\n\tBOTLIB_AI_CHARACTERISTIC_BINTEGER,\n\tBOTLIB_AI_CHARACTERISTIC_STRING,\n\n\tBOTLIB_AI_ALLOC_CHAT_STATE,\n\tBOTLIB_AI_FREE_CHAT_STATE,\n\tBOTLIB_AI_QUEUE_CONSOLE_MESSAGE,\n\tBOTLIB_AI_REMOVE_CONSOLE_MESSAGE,\n\tBOTLIB_AI_NEXT_CONSOLE_MESSAGE,\n\tBOTLIB_AI_NUM_CONSOLE_MESSAGE,\n\tBOTLIB_AI_INITIAL_CHAT,\n\tBOTLIB_AI_REPLY_CHAT,\n\tBOTLIB_AI_CHAT_LENGTH,\n\tBOTLIB_AI_ENTER_CHAT,\n\tBOTLIB_AI_STRING_CONTAINS,\n\tBOTLIB_AI_FIND_MATCH,\n\tBOTLIB_AI_MATCH_VARIABLE,\n\tBOTLIB_AI_UNIFY_WHITE_SPACES,\n\tBOTLIB_AI_REPLACE_SYNONYMS,\n\tBOTLIB_AI_LOAD_CHAT_FILE,\n\tBOTLIB_AI_SET_CHAT_GENDER,\n\tBOTLIB_AI_SET_CHAT_NAME,\n\n\tBOTLIB_AI_RESET_GOAL_STATE,\n\tBOTLIB_AI_RESET_AVOID_GOALS,\n\tBOTLIB_AI_PUSH_GOAL,\n\tBOTLIB_AI_POP_GOAL,\n\tBOTLIB_AI_EMPTY_GOAL_STACK,\n\tBOTLIB_AI_DUMP_AVOID_GOALS,\n\tBOTLIB_AI_DUMP_GOAL_STACK,\n\tBOTLIB_AI_GOAL_NAME,\n\tBOTLIB_AI_GET_TOP_GOAL,\n\tBOTLIB_AI_GET_SECOND_GOAL,\n\tBOTLIB_AI_CHOOSE_LTG_ITEM,\n\tBOTLIB_AI_CHOOSE_NBG_ITEM,\n\tBOTLIB_AI_TOUCHING_GOAL,\n\tBOTLIB_AI_ITEM_GOAL_IN_VIS_BUT_NOT_VISIBLE,\n\tBOTLIB_AI_GET_LEVEL_ITEM_GOAL,\n\tBOTLIB_AI_AVOID_GOAL_TIME,\n\tBOTLIB_AI_INIT_LEVEL_ITEMS,\n\tBOTLIB_AI_UPDATE_ENTITY_ITEMS,\n\tBOTLIB_AI_LOAD_ITEM_WEIGHTS,\n\tBOTLIB_AI_FREE_ITEM_WEIGHTS,\n\tBOTLIB_AI_SAVE_GOAL_FUZZY_LOGIC,\n\tBOTLIB_AI_ALLOC_GOAL_STATE,\n\tBOTLIB_AI_FREE_GOAL_STATE,\n\n\tBOTLIB_AI_RESET_MOVE_STATE,\n\tBOTLIB_AI_MOVE_TO_GOAL,\n\tBOTLIB_AI_MOVE_IN_DIRECTION,\n\tBOTLIB_AI_RESET_AVOID_REACH,\n\tBOTLIB_AI_RESET_LAST_AVOID_REACH,\n\tBOTLIB_AI_REACHABILITY_AREA,\n\tBOTLIB_AI_MOVEMENT_VIEW_TARGET,\n\tBOTLIB_AI_ALLOC_MOVE_STATE,\n\tBOTLIB_AI_FREE_MOVE_STATE,\n\tBOTLIB_AI_INIT_MOVE_STATE,\n\n\tBOTLIB_AI_CHOOSE_BEST_FIGHT_WEAPON,\n\tBOTLIB_AI_GET_WEAPON_INFO,\n\tBOTLIB_AI_LOAD_WEAPON_WEIGHTS,\n\tBOTLIB_AI_ALLOC_WEAPON_STATE,\n\tBOTLIB_AI_FREE_WEAPON_STATE,\n\tBOTLIB_AI_RESET_WEAPON_STATE,\n\n\tBOTLIB_AI_GENETIC_PARENTS_AND_CHILD_SELECTION,\n\tBOTLIB_AI_INTERBREED_GOAL_FUZZY_LOGIC,\n\tBOTLIB_AI_MUTATE_GOAL_FUZZY_LOGIC,\n\tBOTLIB_AI_GET_NEXT_CAMP_SPOT_GOAL,\n\tBOTLIB_AI_GET_MAP_LOCATION_GOAL,\n\tBOTLIB_AI_NUM_INITIAL_CHATS,\n\tBOTLIB_AI_GET_CHAT_MESSAGE,\n\tBOTLIB_AI_REMOVE_FROM_AVOID_GOALS,\n\tBOTLIB_AI_PREDICT_VISIBLE_POSITION,\n\n\tBOTLIB_AI_SET_AVOID_GOAL_TIME,\n\tBOTLIB_AI_ADD_AVOID_SPOT,\n\tBOTLIB_AAS_ALTERNATIVE_ROUTE_GOAL,\n\tBOTLIB_AAS_PREDICT_ROUTE,\n\tBOTLIB_AAS_POINT_REACHABILITY_AREA_INDEX,\n\n\tBOTLIB_PC_LOAD_SOURCE,\n\tBOTLIB_PC_FREE_SOURCE,\n\tBOTLIB_PC_READ_TOKEN,\n\tBOTLIB_PC_SOURCE_FILE_AND_LINE\n\n} gameImport_t;\n\n\n//\n// functions exported by the game subsystem\n//\ntypedef enum {\n\tGAME_INIT,\t// ( int levelTime, int randomSeed, int restart );\n\t// init and shutdown will be called every single level\n\t// The game should call G_GET_ENTITY_TOKEN to parse through all the\n\t// entity configuration text and spawn gentities.\n\n\tGAME_SHUTDOWN,\t// (void);\n\n\tGAME_CLIENT_CONNECT,\t// ( int clientNum, qboolean firstTime, qboolean isBot );\n\t// return NULL if the client is allowed to connect, otherwise return\n\t// a text string with the reason for denial\n\n\tGAME_CLIENT_BEGIN,\t\t\t\t// ( int clientNum );\n\n\tGAME_CLIENT_USERINFO_CHANGED,\t// ( int clientNum );\n\n\tGAME_CLIENT_DISCONNECT,\t\t\t// ( int clientNum );\n\n\tGAME_CLIENT_COMMAND,\t\t\t// ( int clientNum );\n\n\tGAME_CLIENT_THINK,\t\t\t\t// ( int clientNum );\n\n\tGAME_RUN_FRAME,\t\t\t\t\t// ( int levelTime );\n\n\tGAME_CONSOLE_COMMAND,\t\t\t// ( void );\n\t// ConsoleCommand will be called when a command has been issued\n\t// that is not recognized as a builtin function.\n\t// The game can issue trap_argc() / trap_argv() commands to get the command\n\t// and parameters.  Return qfalse if the game doesn't recognize it as a command.\n\n\tBOTAI_START_FRAME\t\t\t\t// ( int time );\n} gameExport_t;\n\n"
  },
  {
    "path": "src/game/g_rankings.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n// g_rankings.c -- reports for global rankings system\n\n#include \"g_local.h\"\n#include \"g_rankings.h\"\n\n/*\n================\nG_RankRunFrame\n================\n*/\nvoid G_RankRunFrame()\n{\n\tgentity_t*\t\tent;\n\tgentity_t*\t\tent2;\n\tgrank_status_t\told_status;\n\tgrank_status_t\tstatus;\n\tint\t\t\t\ttime;\n\tint\t\t\t\ti;\n\tint\t\t\t\tj;\n\n\tif( !trap_RankCheckInit() ) \n\t{\n\t\ttrap_RankBegin( GR_GAMEKEY );\n\t}\n\n\ttrap_RankPoll();\n\t\n\tif( trap_RankActive() )\n\t{\n\t\tfor( i = 0; i < level.maxclients; i++ )\n\t\t{\n\t\t\tent = &(g_entities[i]);\n\t\t\tif ( !ent->inuse )\n\t\t\t\tcontinue;\n\t\t\tif ( ent->client == NULL )\n\t\t\t\tcontinue;\n\t\t\tif ( ent->r.svFlags & SVF_BOT)\n\t\t\t{\n\t\t\t\t// no bots in ranked games\n\t\t\t\ttrap_SendConsoleCommand( EXEC_INSERT, va(\"kick %s\\n\", \n\t\t\t\t\tent->client->pers.netname) );\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\told_status = ent->client->client_status;\n\t\t\tstatus = trap_RankUserStatus( i );\n\t\t\t\n\t\t\tif( ent->client->client_status != status )\n\t\t\t{\n\t\t\t\t// inform client of current status\n\t\t\t\t// not needed for client side log in\n\t\t\t\ttrap_SendServerCommand( i, va(\"rank_status %i\\n\",status) );\n\t\t\t\tif ( i == 0 )\n\t\t\t\t{\n\t\t\t\t\tint j = 0;\n\t\t\t\t}\n\t\t\t\tent->client->client_status = status;\n\t\t\t}\n\t\t\t\n\t\t\tswitch( status )\n\t\t\t{\n\t\t\tcase QGR_STATUS_NEW:\n\t\t\tcase QGR_STATUS_SPECTATOR:\n\t\t\t\tif( ent->client->sess.sessionTeam != TEAM_SPECTATOR )\n\t\t\t\t{\n\t\t\t\t\tent->client->sess.sessionTeam = TEAM_SPECTATOR;\n\t\t\t\t\tent->client->sess.spectatorState = SPECTATOR_FREE;\n\t\t\t\t\tClientSpawn( ent );\n\t\t\t\t\t// make sure by now CS_GRAND rankingsGameID is ready\n\t\t\t\t\ttrap_SendServerCommand( i, va(\"rank_status %i\\n\",status) );\n\t\t\t\t\ttrap_SendServerCommand( i, \"rank_menu\\n\" );\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase QGR_STATUS_NO_USER:\n\t\t\tcase QGR_STATUS_BAD_PASSWORD:\n\t\t\tcase QGR_STATUS_TIMEOUT:\n\t\t\tcase QGR_STATUS_NO_MEMBERSHIP:\n\t\t\tcase QGR_STATUS_INVALIDUSER:\n\t\t\tcase QGR_STATUS_ERROR:\n\t\t\t\tif( (ent->r.svFlags & SVF_BOT) == 0 )\n\t\t\t\t{\n\t\t\t\t\ttrap_RankUserReset( ent->s.clientNum );\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase QGR_STATUS_ACTIVE:\n\t\t\t\tif( (ent->client->sess.sessionTeam == TEAM_SPECTATOR) &&\n\t\t\t\t\t(g_gametype.integer < GT_TEAM) )\n\t\t\t\t{\n\t\t\t\t\tSetTeam( ent, \"free\" );\n\t\t\t\t}\n\n\t\t\t\tif( old_status != QGR_STATUS_ACTIVE )\n\t\t\t\t{\n\t\t\t\t\t// player has just become active\n\t\t\t\t\tfor( j = 0; j < level.maxclients; j++ )\n\t\t\t\t\t{\n\t\t\t\t\t\tent2 = &(g_entities[j]);\n\t\t\t\t\t\tif ( !ent2->inuse )\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\tif ( ent2->client == NULL )\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\tif ( ent2->r.svFlags & SVF_BOT)\n\t\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t\tif( (i != j) && (trap_RankUserStatus( j ) == QGR_STATUS_ACTIVE) )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttrap_RankReportInt( i, j, QGR_KEY_PLAYED_WITH, 1, 0 );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// send current scores so the player's rank will show \n\t\t\t\t\t\t// up under the crosshair immediately\n\t\t\t\t\t\tDeathmatchScoreboardMessage( ent2 );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// don't let ranked games last forever\n\t\tif( ((g_fraglimit.integer == 0) || (g_fraglimit.integer > 100)) && \n\t\t\t((g_timelimit.integer == 0) || (g_timelimit.integer > 1000)) )\n\t\t{\n\t\t\ttrap_Cvar_Set( \"timelimit\", \"1000\" );\n\t\t}\n\t}\n\n\t// tell time to clients so they can show current match rating\n\tif( level.intermissiontime == 0 )\n\t{\n\t\tfor( i = 0; i < level.maxclients; i++ )\n\t\t{\n\t\t\tent = &(g_entities[i]);\n\t\t\tif( ent->client == NULL )\n\t\t\t{\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\ttime = (level.time - ent->client->pers.enterTime) / 1000;\n\t\t\tent->client->ps.persistant[PERS_MATCH_TIME] = time;\n\t\t}\n\t}\n}\n\n/*\n================\nG_RankFireWeapon\n================\n*/\nvoid G_RankFireWeapon( int self, int weapon )\n{\n\tif( level.warmupTime != 0 )\n\t{\n\t\t// no reports during warmup period\n\t\treturn;\n\t}\n\t\n\tif( weapon == WP_GAUNTLET )\n\t{\n\t\t// the gauntlet only \"fires\" when it actually hits something\n\t\treturn;\n\t}\n\t\n\ttrap_RankReportInt( self, -1, QGR_KEY_SHOT_FIRED, 1, 1 );\n\t\n\tswitch( weapon )\n\t{\n\tcase WP_MACHINEGUN:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_SHOT_FIRED_MACHINEGUN, 1, 1 );\n\t\tbreak;\n\tcase WP_SHOTGUN:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_SHOT_FIRED_SHOTGUN, 1, 1 );\n\t\tbreak;\n\tcase WP_GRENADE_LAUNCHER:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_SHOT_FIRED_GRENADE, 1, 1 );\n\t\tbreak;\n\tcase WP_ROCKET_LAUNCHER:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_SHOT_FIRED_ROCKET, 1, 1 );\n\t\tbreak;\n\tcase WP_LIGHTNING:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_SHOT_FIRED_LIGHTNING, 1, 1 );\n\t\tbreak;\n\tcase WP_RAILGUN:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_SHOT_FIRED_RAILGUN, 1, 1 );\n\t\tbreak;\n\tcase WP_PLASMAGUN:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_SHOT_FIRED_PLASMA, 1, 1 );\n\t\tbreak;\n\tcase WP_BFG:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_SHOT_FIRED_BFG, 1, 1 );\n\t\tbreak;\n\tcase WP_GRAPPLING_HOOK:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_SHOT_FIRED_GRAPPLE, 1, 1 );\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n}\n\n/*\n================\nG_RankDamage\n================\n*/\nvoid G_RankDamage( int self, int attacker, int damage, int means_of_death )\n{\n\t// state information to avoid counting each shotgun pellet as a hit\n\tstatic int\tlast_framenum = -1;\n\tstatic int\tlast_self = -1;\n\tstatic int\tlast_attacker = -1;\n\tstatic int\tlast_means_of_death = MOD_UNKNOWN;\n\n\tqboolean\tnew_hit;\n\tint\t\t\tsplash;\n\tint\t\t\tkey_hit;\n\tint\t\t\tkey_damage;\n\tint\t\t\tkey_splash;\n\n\tif( level.warmupTime != 0 )\n\t{\n\t\t// no reports during warmup period\n\t\treturn;\n\t}\n\t\n\tnew_hit = (level.framenum != last_framenum) || \n\t\t(self != last_self) || \n\t\t(attacker != last_attacker) || \n\t\t(means_of_death != last_means_of_death);\n\n\t// update state information\n\tlast_framenum = level.framenum;\n\tlast_self = self;\n\tlast_attacker = attacker;\n\tlast_means_of_death = means_of_death;\n\n\t// the gauntlet only \"fires\" when it actually hits something\n\tif( (attacker != ENTITYNUM_WORLD) && (attacker != self) && \n\t\t(means_of_death == MOD_GAUNTLET)  && \n\t\t(g_entities[attacker].client) )\n\t{\n\t\ttrap_RankReportInt( attacker, -1, QGR_KEY_SHOT_FIRED_GAUNTLET, 1, 1 );\n\t}\n\n\t// don't track hazard damage, just deaths\n\tswitch( means_of_death )\n\t{\n\tcase MOD_WATER:\n\tcase MOD_SLIME:\n\tcase MOD_LAVA:\n\tcase MOD_CRUSH:\n\tcase MOD_TELEFRAG:\n\tcase MOD_FALLING:\n\tcase MOD_SUICIDE:\n\tcase MOD_TRIGGER_HURT:\n\t\treturn;\n\tdefault:\n\t\tbreak;\n\t}\n\n\t// get splash damage\n\tswitch( means_of_death )\n\t{\n\tcase MOD_GRENADE_SPLASH:\n\tcase MOD_ROCKET_SPLASH:\n\tcase MOD_PLASMA_SPLASH:\n\tcase MOD_BFG_SPLASH:\n\t\tsplash = damage;\n\t\tbreak;\n\tdefault:\n\t\tsplash = 0;\n\t\tkey_splash = -1;\n\t\tbreak;\n\t}\n\t\n\t// hit, damage, and splash taken\n\tswitch( means_of_death )\n\t{\n\tcase MOD_GAUNTLET:\n\t\tkey_hit = QGR_KEY_HIT_TAKEN_GAUNTLET;\n\t\tkey_damage = QGR_KEY_DAMAGE_TAKEN_GAUNTLET;\n\t\tbreak;\n\tcase MOD_MACHINEGUN:\n\t\tkey_hit = QGR_KEY_HIT_TAKEN_MACHINEGUN;\n\t\tkey_damage = QGR_KEY_DAMAGE_TAKEN_MACHINEGUN;\n\t\tbreak;\n\tcase MOD_SHOTGUN:\n\t\tkey_hit = QGR_KEY_HIT_TAKEN_SHOTGUN;\n\t\tkey_damage = QGR_KEY_DAMAGE_TAKEN_SHOTGUN;\n\t\tbreak;\n\tcase MOD_GRENADE:\n\tcase MOD_GRENADE_SPLASH:\n\t\tkey_hit = QGR_KEY_HIT_TAKEN_GRENADE;\n\t\tkey_damage = QGR_KEY_DAMAGE_TAKEN_GRENADE;\n\t\tkey_splash = QGR_KEY_SPLASH_TAKEN_GRENADE;\n\t\tbreak;\n\tcase MOD_ROCKET:\n\tcase MOD_ROCKET_SPLASH:\n\t\tkey_hit = QGR_KEY_HIT_TAKEN_ROCKET;\n\t\tkey_damage = QGR_KEY_DAMAGE_TAKEN_ROCKET;\n\t\tkey_splash = QGR_KEY_SPLASH_TAKEN_ROCKET;\n\t\tbreak;\n\tcase MOD_PLASMA:\n\tcase MOD_PLASMA_SPLASH:\n\t\tkey_hit = QGR_KEY_HIT_TAKEN_PLASMA;\n\t\tkey_damage = QGR_KEY_DAMAGE_TAKEN_PLASMA;\n\t\tkey_splash = QGR_KEY_SPLASH_TAKEN_PLASMA;\n\t\tbreak;\n\tcase MOD_RAILGUN:\n\t\tkey_hit = QGR_KEY_HIT_TAKEN_RAILGUN;\n\t\tkey_damage = QGR_KEY_DAMAGE_TAKEN_RAILGUN;\n\t\tbreak;\n\tcase MOD_LIGHTNING:\n\t\tkey_hit = QGR_KEY_HIT_TAKEN_LIGHTNING;\n\t\tkey_damage = QGR_KEY_DAMAGE_TAKEN_LIGHTNING;\n\t\tbreak;\n\tcase MOD_BFG:\n\tcase MOD_BFG_SPLASH:\n\t\tkey_hit = QGR_KEY_HIT_TAKEN_BFG;\n\t\tkey_damage = QGR_KEY_DAMAGE_TAKEN_BFG;\n\t\tkey_splash = QGR_KEY_SPLASH_TAKEN_BFG;\n\t\tbreak;\n\tcase MOD_GRAPPLE:\n\t\tkey_hit = QGR_KEY_HIT_TAKEN_GRAPPLE;\n\t\tkey_damage = QGR_KEY_DAMAGE_TAKEN_GRAPPLE;\n\t\tbreak;\n\tdefault:\n\t\tkey_hit = QGR_KEY_HIT_TAKEN_UNKNOWN;\n\t\tkey_damage = QGR_KEY_DAMAGE_TAKEN_UNKNOWN;\n\t\tbreak;\n\t}\n\n\t// report general and specific hit taken\n\tif( new_hit )\n\t{\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_HIT_TAKEN, 1, 1 );\n\t\ttrap_RankReportInt( self, -1, key_hit, 1, 1 );\n\t}\n\t\n\t// report general and specific damage taken\n\ttrap_RankReportInt( self, -1, QGR_KEY_DAMAGE_TAKEN, damage, 1 );\n\ttrap_RankReportInt( self, -1, key_damage, damage, 1 );\n\n\t// report general and specific splash taken\n\tif( splash != 0 )\n\t{\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_SPLASH_TAKEN, splash, 1 );\n\t\ttrap_RankReportInt( self, -1, key_splash, splash, 1 );\n\t}\n\n\t// hit, damage, and splash given\n\tif( (attacker != ENTITYNUM_WORLD) && (attacker != self) )\n\t{\n\t\tswitch( means_of_death )\n\t\t{\n\t\tcase MOD_GAUNTLET:\n\t\t\tkey_hit = QGR_KEY_HIT_GIVEN_GAUNTLET;\n\t\t\tkey_damage = QGR_KEY_DAMAGE_GIVEN_GAUNTLET;\n\t\t\tbreak;\n\t\tcase MOD_MACHINEGUN:\n\t\t\tkey_hit = QGR_KEY_HIT_GIVEN_MACHINEGUN;\n\t\t\tkey_damage = QGR_KEY_DAMAGE_GIVEN_MACHINEGUN;\n\t\t\tbreak;\n\t\tcase MOD_SHOTGUN:\n\t\t\tkey_hit = QGR_KEY_HIT_GIVEN_SHOTGUN;\n\t\t\tkey_damage = QGR_KEY_DAMAGE_GIVEN_SHOTGUN;\n\t\t\tbreak;\n\t\tcase MOD_GRENADE:\n\t\tcase MOD_GRENADE_SPLASH:\n\t\t\tkey_hit = QGR_KEY_HIT_GIVEN_GRENADE;\n\t\t\tkey_damage = QGR_KEY_DAMAGE_GIVEN_GRENADE;\n\t\t\tkey_splash = QGR_KEY_SPLASH_GIVEN_GRENADE;\n\t\t\tbreak;\n\t\tcase MOD_ROCKET:\n\t\tcase MOD_ROCKET_SPLASH:\n\t\t\tkey_hit = QGR_KEY_HIT_GIVEN_ROCKET;\n\t\t\tkey_damage = QGR_KEY_DAMAGE_GIVEN_ROCKET;\n\t\t\tkey_splash = QGR_KEY_SPLASH_GIVEN_ROCKET;\n\t\t\tbreak;\n\t\tcase MOD_PLASMA:\n\t\tcase MOD_PLASMA_SPLASH:\n\t\t\tkey_hit = QGR_KEY_HIT_GIVEN_PLASMA;\n\t\t\tkey_damage = QGR_KEY_DAMAGE_GIVEN_PLASMA;\n\t\t\tkey_splash = QGR_KEY_SPLASH_GIVEN_PLASMA;\n\t\t\tbreak;\n\t\tcase MOD_RAILGUN:\n\t\t\tkey_hit = QGR_KEY_HIT_GIVEN_RAILGUN;\n\t\t\tkey_damage = QGR_KEY_DAMAGE_GIVEN_RAILGUN;\n\t\t\tbreak;\n\t\tcase MOD_LIGHTNING:\n\t\t\tkey_hit = QGR_KEY_HIT_GIVEN_LIGHTNING;\n\t\t\tkey_damage = QGR_KEY_DAMAGE_GIVEN_LIGHTNING;\n\t\t\tbreak;\n\t\tcase MOD_BFG:\n\t\tcase MOD_BFG_SPLASH:\n\t\t\tkey_hit = QGR_KEY_HIT_GIVEN_BFG;\n\t\t\tkey_damage = QGR_KEY_DAMAGE_GIVEN_BFG;\n\t\t\tkey_splash = QGR_KEY_SPLASH_GIVEN_BFG;\n\t\t\tbreak;\n\t\tcase MOD_GRAPPLE:\n\t\t\tkey_hit = QGR_KEY_HIT_GIVEN_GRAPPLE;\n\t\t\tkey_damage = QGR_KEY_DAMAGE_GIVEN_GRAPPLE;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tkey_hit = QGR_KEY_HIT_GIVEN_UNKNOWN;\n\t\t\tkey_damage = QGR_KEY_DAMAGE_GIVEN_UNKNOWN;\n\t\t\tbreak;\n\t\t}\n\t\t\n\t\t// report general and specific hit given\n\t\t// jwu 8/26/00\n\t\t// had a case where attacker is 245 which is grnadeshooter attacker is \n\t\t// g_entities index not necessarilly clientnum\n\t\tif (g_entities[attacker].client) {\n\t\t\tif( new_hit )\n\t\t\t{\n\t\t\t\ttrap_RankReportInt( attacker, -1, QGR_KEY_HIT_GIVEN, 1, 1 );\n\t\t\t\ttrap_RankReportInt( attacker, -1, key_hit, 1, 1 );\n\t\t\t}\n\t\t\t\n\t\t\t// report general and specific damage given\n\t\t\ttrap_RankReportInt( attacker, -1, QGR_KEY_DAMAGE_GIVEN, damage, 1 );\n\t\t\ttrap_RankReportInt( attacker, -1, key_damage, damage, 1 );\n\n\t\t\t// report general and specific splash given\n\t\t\tif( splash != 0 )\n\t\t\t{\n\t\t\t\ttrap_RankReportInt( attacker, -1, QGR_KEY_SPLASH_GIVEN, splash, 1 );\n\t\t\t\ttrap_RankReportInt( attacker, -1, key_splash, splash, 1 );\n\t\t\t}\n\t\t}\n\t}\n\n\t// friendly fire\n\tif( (attacker != self) && \n\t\tOnSameTeam( &(g_entities[self]), &(g_entities[attacker])) &&\n\t\t(g_entities[attacker].client) )\n\t{\n\t\t// report teammate hit\n\t\tif( new_hit )\n\t\t{\n\t\t\ttrap_RankReportInt( self, -1, QGR_KEY_TEAMMATE_HIT_TAKEN, 1, 1 );\n\t\t\ttrap_RankReportInt( attacker, -1, QGR_KEY_TEAMMATE_HIT_GIVEN, 1, \n\t\t\t\t1 );\n\t\t}\n\n\t\t// report teammate damage\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_TEAMMATE_DAMAGE_TAKEN, damage, \n\t\t\t1 );\n\t\ttrap_RankReportInt( attacker, -1, QGR_KEY_TEAMMATE_DAMAGE_GIVEN, \n\t\t\tdamage, 1 );\n\t\t\t\n\t\t// report teammate splash\n\t\tif( splash != 0 )\n\t\t{\n\t\t\ttrap_RankReportInt( self, -1, QGR_KEY_TEAMMATE_SPLASH_TAKEN, \n\t\t\t\tsplash, 1 );\n\t\t\ttrap_RankReportInt( attacker, -1, QGR_KEY_TEAMMATE_SPLASH_GIVEN, \n\t\t\t\tsplash, 1 );\n\t\t}\n\t}\n}\n\n/*\n================\nG_RankPlayerDie\n================\n*/\nvoid G_RankPlayerDie( int self, int attacker, int means_of_death )\n{\n\tint\tp1;\n\tint\tp2;\n\n\tif( level.warmupTime != 0 )\n\t{\n\t\t// no reports during warmup period\n\t\treturn;\n\t}\n\t\n\tif( attacker == ENTITYNUM_WORLD )\n\t{\n\t\tp1 = self;\n\t\tp2 = -1;\n\t\t\n\t\ttrap_RankReportInt( p1, p2, QGR_KEY_HAZARD_DEATH, 1, 1 );\n\n\t\tswitch( means_of_death )\n\t\t{\n\t\tcase MOD_WATER:\n\t\t\ttrap_RankReportInt( p1, p2, QGR_KEY_WATER, 1, 1 );\n\t\t\tbreak;\n\t\tcase MOD_SLIME:\n\t\t\ttrap_RankReportInt( p1, p2, QGR_KEY_SLIME, 1, 1 );\n\t\t\tbreak;\n\t\tcase MOD_LAVA:\n\t\t\ttrap_RankReportInt( p1, p2, QGR_KEY_LAVA, 1, 1 );\n\t\t\tbreak;\n\t\tcase MOD_CRUSH:\n\t\t\ttrap_RankReportInt( p1, p2, QGR_KEY_CRUSH, 1, 1 );\n\t\t\tbreak;\n\t\tcase MOD_TELEFRAG:\n\t\t\ttrap_RankReportInt( p1, p2, QGR_KEY_TELEFRAG, 1, 1 );\n\t\t\tbreak;\n\t\tcase MOD_FALLING:\n\t\t\ttrap_RankReportInt( p1, p2, QGR_KEY_FALLING, 1, 1 );\n\t\t\tbreak;\n\t\tcase MOD_SUICIDE:\n\t\t\ttrap_RankReportInt( p1, p2, QGR_KEY_SUICIDE_CMD, 1, 1 );\n\t\t\tbreak;\n\t\tcase MOD_TRIGGER_HURT:\n\t\t\ttrap_RankReportInt( p1, p2, QGR_KEY_TRIGGER_HURT, 1, 1 );\n\t\t\tbreak;\n\t\tdefault:\n\t\t\ttrap_RankReportInt( p1, p2, QGR_KEY_HAZARD_MISC, 1, 1 );\n\t\t\tbreak;\n\t\t}\n\t}\n\telse if( attacker == self )\n\t{\n\t\tp1 = self;\n\t\tp2 = -1;\n\t\t\n\t\ttrap_RankReportInt( p1, p2, QGR_KEY_SUICIDE, 1, 1 );\n\t\t\n\t\tswitch( means_of_death )\n\t\t{\n\t\tcase MOD_GAUNTLET:\n\t\t\ttrap_RankReportInt( p1, p2, QGR_KEY_SUICIDE_GAUNTLET, 1, 1 );\n\t\t\tbreak;\n\t\tcase MOD_MACHINEGUN:\n\t\t\ttrap_RankReportInt( p1, p2, QGR_KEY_SUICIDE_MACHINEGUN, 1, 1 );\n\t\t\tbreak;\n\t\tcase MOD_SHOTGUN:\n\t\t\ttrap_RankReportInt( p1, p2, QGR_KEY_SUICIDE_SHOTGUN, 1, 1 );\n\t\t\tbreak;\n\t\tcase MOD_GRENADE:\n\t\tcase MOD_GRENADE_SPLASH:\n\t\t\ttrap_RankReportInt( p1, p2, QGR_KEY_SUICIDE_GRENADE, 1, 1 );\n\t\t\tbreak;\n\t\tcase MOD_ROCKET:\n\t\tcase MOD_ROCKET_SPLASH:\n\t\t\ttrap_RankReportInt( p1, p2, QGR_KEY_SUICIDE_ROCKET, 1, 1 );\n\t\t\tbreak;\n\t\tcase MOD_PLASMA:\n\t\tcase MOD_PLASMA_SPLASH:\n\t\t\ttrap_RankReportInt( p1, p2, QGR_KEY_SUICIDE_PLASMA, 1, 1 );\n\t\t\tbreak;\n\t\tcase MOD_RAILGUN:\n\t\t\ttrap_RankReportInt( p1, p2, QGR_KEY_SUICIDE_RAILGUN, 1, 1 );\n\t\t\tbreak;\n\t\tcase MOD_LIGHTNING:\n\t\t\ttrap_RankReportInt( p1, p2, QGR_KEY_SUICIDE_LIGHTNING, 1, 1 );\n\t\t\tbreak;\n\t\tcase MOD_BFG:\n\t\tcase MOD_BFG_SPLASH:\n\t\t\ttrap_RankReportInt( p1, p2, QGR_KEY_SUICIDE_BFG, 1, 1 );\n\t\t\tbreak;\n\t\tcase MOD_GRAPPLE:\n\t\t\ttrap_RankReportInt( p1, p2, QGR_KEY_SUICIDE_GRAPPLE, 1, 1 );\n\t\t\tbreak;\n\t\tdefault:\n\t\t\ttrap_RankReportInt( p1, p2, QGR_KEY_SUICIDE_UNKNOWN, 1, 1 );\n\t\t\tbreak;\n\t\t}\n\t}\n\telse\n\t{\n\t\tp1 = attacker;\n\t\tp2 = self;\n\n\t\ttrap_RankReportInt( p1, p2, QGR_KEY_FRAG, 1, 1 );\n\t\t\n\t\tswitch( means_of_death )\n\t\t{\n\t\tcase MOD_GAUNTLET:\n\t\t\ttrap_RankReportInt( p1, p2, QGR_KEY_FRAG_GAUNTLET, 1, 1 );\n\t\t\tbreak;\n\t\tcase MOD_MACHINEGUN:\n\t\t\ttrap_RankReportInt( p1, p2, QGR_KEY_FRAG_MACHINEGUN, 1, 1 );\n\t\t\tbreak;\n\t\tcase MOD_SHOTGUN:\n\t\t\ttrap_RankReportInt( p1, p2, QGR_KEY_FRAG_SHOTGUN, 1, 1 );\n\t\t\tbreak;\n\t\tcase MOD_GRENADE:\n\t\tcase MOD_GRENADE_SPLASH:\n\t\t\ttrap_RankReportInt( p1, p2, QGR_KEY_FRAG_GRENADE, 1, 1 );\n\t\t\tbreak;\n\t\tcase MOD_ROCKET:\n\t\tcase MOD_ROCKET_SPLASH:\n\t\t\ttrap_RankReportInt( p1, p2, QGR_KEY_FRAG_ROCKET, 1, 1 );\n\t\t\tbreak;\n\t\tcase MOD_PLASMA:\n\t\tcase MOD_PLASMA_SPLASH:\n\t\t\ttrap_RankReportInt( p1, p2, QGR_KEY_FRAG_PLASMA, 1, 1 );\n\t\t\tbreak;\n\t\tcase MOD_RAILGUN:\n\t\t\ttrap_RankReportInt( p1, p2, QGR_KEY_FRAG_RAILGUN, 1, 1 );\n\t\t\tbreak;\n\t\tcase MOD_LIGHTNING:\n\t\t\ttrap_RankReportInt( p1, p2, QGR_KEY_FRAG_LIGHTNING, 1, 1 );\n\t\t\tbreak;\n\t\tcase MOD_BFG:\n\t\tcase MOD_BFG_SPLASH:\n\t\t\ttrap_RankReportInt( p1, p2, QGR_KEY_FRAG_BFG, 1, 1 );\n\t\t\tbreak;\n\t\tcase MOD_GRAPPLE:\n\t\t\ttrap_RankReportInt( p1, p2, QGR_KEY_FRAG_GRAPPLE, 1, 1 );\n\t\t\tbreak;\n\t\tdefault:\n\t\t\ttrap_RankReportInt( p1, p2, QGR_KEY_FRAG_UNKNOWN, 1, 1 );\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\n/*\n================\nG_RankWeaponTime\n================\n*/\nvoid G_RankWeaponTime( int self, int weapon )\n{\n\tgclient_t*\tclient;\n\tint\t\t\ttime;\n\n\tif( level.warmupTime != 0 )\n\t{\n\t\t// no reports during warmup period\n\t\treturn;\n\t}\n\t\n\tclient = g_entities[self].client;\n\ttime = (level.time - client->weapon_change_time) / 1000;\n\tclient->weapon_change_time = level.time;\n\n\tif( time <= 0 )\n\t{\n\t\treturn;\n\t}\n\t\n\ttrap_RankReportInt( self, -1, QGR_KEY_TIME, time, 1 );\n\n\tswitch( weapon )\n\t{\n\tcase WP_GAUNTLET:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_TIME_GAUNTLET, time, 1 );\n\t\tbreak;\n\tcase WP_MACHINEGUN:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_TIME_MACHINEGUN, time, 1 );\n\t\tbreak;\n\tcase WP_SHOTGUN:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_TIME_SHOTGUN, time, 1 );\n\t\tbreak;\n\tcase WP_GRENADE_LAUNCHER:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_TIME_GRENADE, time, 1 );\n\t\tbreak;\n\tcase WP_ROCKET_LAUNCHER:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_TIME_ROCKET, time, 1 );\n\t\tbreak;\n\tcase WP_LIGHTNING:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_TIME_LIGHTNING, time, 1 );\n\t\tbreak;\n\tcase WP_RAILGUN:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_TIME_RAILGUN, time, 1 );\n\t\tbreak;\n\tcase WP_PLASMAGUN:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_TIME_PLASMA, time, 1 );\n\t\tbreak;\n\tcase WP_BFG:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_TIME_BFG, time, 1 );\n\t\tbreak;\n\tcase WP_GRAPPLING_HOOK:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_TIME_GRAPPLE, time, 1 );\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n}\n\n/*\n================\nG_RankPickupWeapon\n================\n*/\nvoid G_RankPickupWeapon( int self, int weapon )\n{\n\tif( level.warmupTime != 0 )\n\t{\n\t\t// no reports during warmup period\n\t\treturn;\n\t}\n\t\n\ttrap_RankReportInt( self, -1, QGR_KEY_PICKUP_WEAPON, 1, 1 );\n\tswitch( weapon )\n\t{\n\tcase WP_GAUNTLET:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_PICKUP_GAUNTLET, 1, 1 );\n\t\tbreak;\n\tcase WP_MACHINEGUN:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_PICKUP_MACHINEGUN, 1, 1 );\n\t\tbreak;\n\tcase WP_SHOTGUN:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_PICKUP_SHOTGUN, 1, 1 );\n\t\tbreak;\n\tcase WP_GRENADE_LAUNCHER:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_PICKUP_GRENADE, 1, 1 );\n\t\tbreak;\n\tcase WP_ROCKET_LAUNCHER:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_PICKUP_ROCKET, 1, 1 );\n\t\tbreak;\n\tcase WP_LIGHTNING:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_PICKUP_LIGHTNING, 1, 1 );\n\t\tbreak;\n\tcase WP_RAILGUN:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_PICKUP_RAILGUN, 1, 1 );\n\t\tbreak;\n\tcase WP_PLASMAGUN:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_PICKUP_PLASMA, 1, 1 );\n\t\tbreak;\n\tcase WP_BFG:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_PICKUP_BFG, 1, 1 );\n\t\tbreak;\n\tcase WP_GRAPPLING_HOOK:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_PICKUP_GRAPPLE, 1, 1 );\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n}\n\n/*\n================\nG_RankPickupAmmo\n================\n*/\nvoid G_RankPickupAmmo( int self, int weapon, int quantity )\n{\n\tif( level.warmupTime != 0 )\n\t{\n\t\t// no reports during warmup period\n\t\treturn;\n\t}\n\t\n\ttrap_RankReportInt( self, -1, QGR_KEY_BOXES, 1, 1 );\n\ttrap_RankReportInt( self, -1, QGR_KEY_ROUNDS, quantity, 1 );\n\t\n\tswitch( weapon )\n\t{\n\tcase WP_MACHINEGUN:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_BOXES_BULLETS, 1, 1 );\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_ROUNDS_BULLETS, quantity, 1 );\n\t\tbreak;\n\tcase WP_SHOTGUN:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_BOXES_SHELLS, 1, 1 );\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_ROUNDS_SHELLS, quantity, 1 );\n\t\tbreak;\n\tcase WP_GRENADE_LAUNCHER:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_BOXES_GRENADES, 1, 1 );\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_ROUNDS_GRENADES, quantity, 1 );\n\t\tbreak;\n\tcase WP_ROCKET_LAUNCHER:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_BOXES_ROCKETS, 1, 1 );\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_ROUNDS_ROCKETS, quantity, 1 );\n\t\tbreak;\n\tcase WP_LIGHTNING:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_BOXES_LG_AMMO, 1, 1 );\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_ROUNDS_LG_AMMO, quantity, 1 );\n\t\tbreak;\n\tcase WP_RAILGUN:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_BOXES_SLUGS, 1, 1 );\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_ROUNDS_SLUGS, quantity, 1 );\n\t\tbreak;\n\tcase WP_PLASMAGUN:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_BOXES_CELLS, 1, 1 );\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_ROUNDS_CELLS, quantity, 1 );\n\t\tbreak;\n\tcase WP_BFG:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_BOXES_BFG_AMMO, 1, 1 );\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_ROUNDS_BFG_AMMO, quantity, 1 );\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n}\n\n/*\n================\nG_RankPickupHealth\n================\n*/\nvoid G_RankPickupHealth( int self, int quantity )\n{\n\tif( level.warmupTime != 0 )\n\t{\n\t\t// no reports during warmup period\n\t\treturn;\n\t}\n\t\n\ttrap_RankReportInt( self, -1, QGR_KEY_HEALTH, 1, 1 );\n\ttrap_RankReportInt( self, -1, QGR_KEY_HEALTH_TOTAL, quantity, 1 );\n\n\tswitch( quantity )\n\t{\n\tcase 5:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_HEALTH_5, 1, 1 );\n\t\tbreak;\n\tcase 25:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_HEALTH_25, 1, 1 );\n\t\tbreak;\n\tcase 50:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_HEALTH_50, 1, 1 );\n\t\tbreak;\n\tcase 100:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_HEALTH_MEGA, 1, 1 );\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n}\n\n/*\n================\nG_RankPickupArmor\n================\n*/\nvoid G_RankPickupArmor( int self, int quantity )\n{\n\tif( level.warmupTime != 0 )\n\t{\n\t\t// no reports during warmup period\n\t\treturn;\n\t}\n\t\n\ttrap_RankReportInt( self, -1, QGR_KEY_ARMOR, 1, 1 );\n\ttrap_RankReportInt( self, -1, QGR_KEY_ARMOR_TOTAL, quantity, 1 );\n\n\tswitch( quantity )\n\t{\n\tcase 5:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_ARMOR_SHARD, 1, 1 );\n\t\tbreak;\n\tcase 50:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_ARMOR_YELLOW, 1, 1 );\n\t\tbreak;\n\tcase 100:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_ARMOR_RED, 1, 1 );\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n}\n\n/*\n================\nG_RankPickupPowerup\n================\n*/\nvoid G_RankPickupPowerup( int self, int powerup )\n{\n\tif( level.warmupTime != 0 )\n\t{\n\t\t// no reports during warmup period\n\t\treturn;\n\t}\n\t\n\t// ctf flags are treated as powerups\n\tif( (powerup == PW_REDFLAG) || (powerup == PW_BLUEFLAG) )\n\t{\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_FLAG_PICKUP, 1, 1 );\n\t\treturn;\n\t}\n\n\ttrap_RankReportInt( self, -1, QGR_KEY_POWERUP, 1, 1 );\n\t\n\tswitch( powerup )\n\t{\n\tcase PW_QUAD:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_QUAD, 1, 1 );\n\t\tbreak;\n\tcase PW_BATTLESUIT:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_SUIT, 1, 1 );\n\t\tbreak;\n\tcase PW_HASTE:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_HASTE, 1, 1 );\n\t\tbreak;\n\tcase PW_INVIS:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_INVIS, 1, 1 );\n\t\tbreak;\n\tcase PW_REGEN:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_REGEN, 1, 1 );\n\t\tbreak;\n\tcase PW_FLIGHT:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_FLIGHT, 1, 1 );\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n}\n\n/*\n================\nG_RankPickupHoldable\n================\n*/\nvoid G_RankPickupHoldable( int self, int holdable )\n{\n\tif( level.warmupTime != 0 )\n\t{\n\t\t// no reports during warmup period\n\t\treturn;\n\t}\n\t\n\tswitch( holdable )\n\t{\n\tcase HI_MEDKIT:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_MEDKIT, 1, 1 );\n\t\tbreak;\n\tcase HI_TELEPORTER:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_TELEPORTER, 1, 1 );\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n}\n\n/*\n================\nG_RankUseHoldable\n================\n*/\nvoid G_RankUseHoldable( int self, int holdable )\n{\n\tif( level.warmupTime != 0 )\n\t{\n\t\t// no reports during warmup period\n\t\treturn;\n\t}\n\t\n\tswitch( holdable )\n\t{\n\tcase HI_MEDKIT:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_MEDKIT_USE, 1, 1 );\n\t\tbreak;\n\tcase HI_TELEPORTER:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_TELEPORTER_USE, 1, 1 );\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n}\n\n/*\n================\nG_RankReward\n================\n*/\nvoid G_RankReward( int self, int award )\n{\n\tif( level.warmupTime != 0 )\n\t{\n\t\t// no reports during warmup period\n\t\treturn;\n\t}\n\t\n\tswitch( award )\n\t{\n\tcase EF_AWARD_IMPRESSIVE:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_IMPRESSIVE, 1, 1 );\n\t\tbreak;\n\tcase EF_AWARD_EXCELLENT:\n\t\ttrap_RankReportInt( self, -1, QGR_KEY_EXCELLENT, 1, 1 );\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n}\n\n/*\n================\nG_RankCapture\n================\n*/\nvoid G_RankCapture( int self )\n{\n\tif( level.warmupTime != 0 )\n\t{\n\t\t// no reports during warmup period\n\t\treturn;\n\t}\n\t\n\ttrap_RankReportInt( self, -1, QGR_KEY_FLAG_CAPTURE, 1, 1 );\n}\n\n/*\n================\nG_RankUserTeamName\n================\n*/\nvoid G_RankUserTeamName( int self, char* team_name )\n{\n\tif( level.warmupTime != 0 )\n\t{\n\t\t// no reports during warmup period\n\t\treturn;\n\t}\n\t\n\ttrap_RankReportStr( self, -1, QGR_KEY_TEAM_NAME, team_name );\n}\n\n/*\n================\nG_RankClientDisconnect\n================\n*/\nvoid G_RankClientDisconnect( int self )\n{\n\tgclient_t*\tclient;\n\tint\t\t\ttime;\n\tint\t\t\tmatch_rating;\n\t\n\tif( level.warmupTime != 0 )\n\t{\n\t\t// no reports during warmup period\n\t\treturn;\n\t}\n\t\n\t// match rating\n\tclient = g_entities[self].client;\n\ttime = (level.time - client->pers.enterTime) / 1000;\n\tif( time < 60 )\n\t{\n\t\tmatch_rating = 0;\n\t}\n\telse\n\t{\n\t\tmatch_rating = client->ps.persistant[PERS_MATCH_RATING] / time;\n\t}\n\ttrap_RankReportInt( self, -1, QGR_KEY_MATCH_RATING, match_rating, 0 );\n}\n\n/*\n================\nG_RankGameOver\n================\n*/\nvoid G_RankGameOver( void )\n{\n\tint\t\ti;\n\tchar\tstr[MAX_INFO_VALUE];\n\tint\t\tnum;\n\t\n\tif( level.warmupTime != 0 )\n\t{\n\t\t// no reports during warmup period\n\t\treturn;\n\t}\n\t\n\tfor( i = 0; i < level.maxclients; i++ )\n\t{\n\t\tif( trap_RankUserStatus( i ) == QGR_STATUS_ACTIVE )\n\t\t{\n\t\t\tG_RankClientDisconnect( i );\n\t\t}\n\t}\n\t\n\t// hostname\n\ttrap_Cvar_VariableStringBuffer( \"sv_hostname\", str, sizeof(str) );\n\ttrap_RankReportStr( -1, -1, QGR_KEY_HOSTNAME, str );\n\n\t// map\n\ttrap_Cvar_VariableStringBuffer( \"mapname\", str, sizeof(str) );\n\ttrap_RankReportStr( -1, -1, QGR_KEY_MAP, str );\n\n\t// mod\n\ttrap_Cvar_VariableStringBuffer( \"fs_game\", str, sizeof(str) );\n\ttrap_RankReportStr( -1, -1, QGR_KEY_MOD, str );\n\n\t// gametype\n\tnum = trap_Cvar_VariableIntegerValue(\"g_gametype\");\n\ttrap_RankReportInt( -1, -1, QGR_KEY_GAMETYPE, num, 0 );\n\t\n\t// fraglimit\n\tnum = trap_Cvar_VariableIntegerValue(\"fraglimit\");\n\ttrap_RankReportInt( -1, -1, QGR_KEY_FRAGLIMIT, num, 0 );\n\t\n\t// timelimit\n\tnum = trap_Cvar_VariableIntegerValue(\"timelimit\");\n\ttrap_RankReportInt( -1, -1, QGR_KEY_TIMELIMIT, num, 0 );\n\n\t// maxclients\n\tnum = trap_Cvar_VariableIntegerValue(\"sv_maxclients\");\n\ttrap_RankReportInt( -1, -1, QGR_KEY_MAXCLIENTS, num, 0 );\n\n\t// maxrate\n\tnum = trap_Cvar_VariableIntegerValue(\"sv_maxRate\");\n\ttrap_RankReportInt( -1, -1, QGR_KEY_MAXRATE, num, 0 );\n\n\t// minping\n\tnum = trap_Cvar_VariableIntegerValue(\"sv_minPing\");\n\ttrap_RankReportInt( -1, -1, QGR_KEY_MINPING, num, 0 );\n\n\t// maxping\n\tnum = trap_Cvar_VariableIntegerValue(\"sv_maxPing\");\n\ttrap_RankReportInt( -1, -1, QGR_KEY_MAXPING, num, 0 );\n\n\t// dedicated\n\tnum = trap_Cvar_VariableIntegerValue(\"dedicated\");\n\ttrap_RankReportInt( -1, -1, QGR_KEY_DEDICATED, num, 0 );\n\n\t// version\n\ttrap_Cvar_VariableStringBuffer( \"version\", str, sizeof(str) );\n\ttrap_RankReportStr( -1, -1, QGR_KEY_VERSION, str );\n}\n\n"
  },
  {
    "path": "src/game/g_rankings.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n// g_rankings.h -- score keys for global rankings\n\n#ifndef _G_RANKINGS_H_\n#define _G_RANKINGS_H_\n\n/*\n==============================================================================\n\nKey digits:\n\t10^9: report type\n\t\t\t1 = normal\n\t\t\t2 = developer-only\n\t10^8: stat type\n\t\t\t0 = match stat\n\t\t\t1 = single player stat\n\t\t\t2 = duel stat\n\t10^7: data type\n\t\t\t0 = string\n\t\t\t1 = uint32\n\t10^6: calculation\n\t\t\t0 = use raw value\n\t\t\t1 = add to total\n\t\t\t2 = average\n\t\t\t3 = max\n\t\t\t4 = min\n\t10^5\n\t10^4: category\n\t\t\t00 = general\n\t\t\t01 = session\n\t\t\t02 = weapon\n\t\t\t03 = ammo\n\t\t\t04 = health\n\t\t\t05 = armor\n\t\t\t06 = powerup\n\t\t\t07 = holdable\n\t\t\t08 = hazard\n\t\t\t09 = reward\n\t\t\t10 = teammate\n\t\t\t11 = ctf\n\t10^3:\n\t10^2: sub-category\n\t10^1:\n\t10^0: ordinal\n \n==============================================================================\n*/\n\n// general keys\n#define QGR_KEY_MATCH_RATING\t\t\t1112000001\n#define QGR_KEY_PLAYED_WITH\t\t\t\t1210000002\n\n// session keys\n#define QGR_KEY_HOSTNAME\t\t\t\t1000010000\n#define QGR_KEY_MAP\t\t\t\t\t\t1000010001\n#define QGR_KEY_MOD\t\t\t\t\t\t1000010002\n#define QGR_KEY_GAMETYPE\t\t\t\t1010010003\n#define QGR_KEY_FRAGLIMIT\t\t\t\t1010010004\n#define QGR_KEY_TIMELIMIT\t\t\t\t1010010005\n#define QGR_KEY_MAXCLIENTS\t\t\t\t1010010006\n#define QGR_KEY_MAXRATE\t\t\t\t\t1010010007\n#define QGR_KEY_MINPING\t\t\t\t\t1010010008\n#define QGR_KEY_MAXPING\t\t\t\t\t1010010009\n#define QGR_KEY_DEDICATED\t\t\t\t1010010010\n#define QGR_KEY_VERSION\t\t\t\t\t1000010011\n\n// weapon keys\n#define QGR_KEY_FRAG\t\t\t\t\t1211020000\n#define QGR_KEY_SUICIDE\t\t\t\t\t1111020001\n#define QGR_KEY_SHOT_FIRED\t\t\t\t1111020002\n#define QGR_KEY_HIT_GIVEN\t\t\t\t1111020003\n#define QGR_KEY_HIT_TAKEN\t\t\t\t1111020004\n#define QGR_KEY_DAMAGE_GIVEN\t\t\t1111020005\n#define QGR_KEY_DAMAGE_TAKEN\t\t\t1111020006\n#define QGR_KEY_SPLASH_GIVEN\t\t\t1111020007\n#define QGR_KEY_SPLASH_TAKEN\t\t\t1111020008\n#define QGR_KEY_PICKUP_WEAPON\t\t\t1111020009\n#define QGR_KEY_TIME\t\t\t\t\t1111020010\n\n#define QGR_KEY_FRAG_GAUNTLET\t\t\t1211020100\n#define QGR_KEY_SUICIDE_GAUNTLET\t\t1111020101\n#define QGR_KEY_SHOT_FIRED_GAUNTLET\t\t1111020102\n#define QGR_KEY_HIT_GIVEN_GAUNTLET\t\t1111020103\n#define QGR_KEY_HIT_TAKEN_GAUNTLET\t\t1111020104\n#define QGR_KEY_DAMAGE_GIVEN_GAUNTLET\t1111020105\n#define QGR_KEY_DAMAGE_TAKEN_GAUNTLET\t1111020106\n#define QGR_KEY_SPLASH_GIVEN_GAUNTLET\t1111020107\n#define QGR_KEY_SPLASH_TAKEN_GAUNTLET\t1111020108\n#define QGR_KEY_PICKUP_GAUNTLET\t\t\t1111020109\n#define QGR_KEY_TIME_GAUNTLET\t\t\t1111020110\n\n#define QGR_KEY_FRAG_MACHINEGUN\t\t\t1211020200\n#define QGR_KEY_SUICIDE_MACHINEGUN\t\t1111020201\n#define QGR_KEY_SHOT_FIRED_MACHINEGUN\t1111020202\n#define QGR_KEY_HIT_GIVEN_MACHINEGUN\t1111020203\n#define QGR_KEY_HIT_TAKEN_MACHINEGUN\t1111020204\n#define QGR_KEY_DAMAGE_GIVEN_MACHINEGUN\t1111020205\n#define QGR_KEY_DAMAGE_TAKEN_MACHINEGUN\t1111020206\n#define QGR_KEY_SPLASH_GIVEN_MACHINEGUN\t1111020207\n#define QGR_KEY_SPLASH_TAKEN_MACHINEGUN\t1111020208\n#define QGR_KEY_PICKUP_MACHINEGUN\t\t1111020209\n#define QGR_KEY_TIME_MACHINEGUN\t\t\t1111020210\n\n#define QGR_KEY_FRAG_SHOTGUN\t\t\t1211020300\n#define QGR_KEY_SUICIDE_SHOTGUN\t\t\t1111020301\n#define QGR_KEY_SHOT_FIRED_SHOTGUN\t\t1111020302\n#define QGR_KEY_HIT_GIVEN_SHOTGUN\t\t1111020303\n#define QGR_KEY_HIT_TAKEN_SHOTGUN\t\t1111020304\n#define QGR_KEY_DAMAGE_GIVEN_SHOTGUN\t1111020305\n#define QGR_KEY_DAMAGE_TAKEN_SHOTGUN\t1111020306\n#define QGR_KEY_SPLASH_GIVEN_SHOTGUN\t1111020307\n#define QGR_KEY_SPLASH_TAKEN_SHOTGUN\t1111020308\n#define QGR_KEY_PICKUP_SHOTGUN\t\t\t1111020309\n#define QGR_KEY_TIME_SHOTGUN\t\t\t1111020310\n\n#define QGR_KEY_FRAG_GRENADE\t\t\t1211020400\n#define QGR_KEY_SUICIDE_GRENADE\t\t\t1111020401\n#define QGR_KEY_SHOT_FIRED_GRENADE\t\t1111020402\n#define QGR_KEY_HIT_GIVEN_GRENADE\t\t1111020403\n#define QGR_KEY_HIT_TAKEN_GRENADE\t\t1111020404\n#define QGR_KEY_DAMAGE_GIVEN_GRENADE\t1111020405\n#define QGR_KEY_DAMAGE_TAKEN_GRENADE\t1111020406\n#define QGR_KEY_SPLASH_GIVEN_GRENADE\t1111020407\n#define QGR_KEY_SPLASH_TAKEN_GRENADE\t1111020408\n#define QGR_KEY_PICKUP_GRENADE\t\t\t1111020409\n#define QGR_KEY_TIME_GRENADE\t\t\t1111020410\n\n#define QGR_KEY_FRAG_ROCKET\t\t\t\t1211020500\n#define QGR_KEY_SUICIDE_ROCKET\t\t\t1111020501\n#define QGR_KEY_SHOT_FIRED_ROCKET\t\t1111020502\n#define QGR_KEY_HIT_GIVEN_ROCKET\t\t1111020503\n#define QGR_KEY_HIT_TAKEN_ROCKET\t\t1111020504\n#define QGR_KEY_DAMAGE_GIVEN_ROCKET\t\t1111020505\n#define QGR_KEY_DAMAGE_TAKEN_ROCKET\t\t1111020506\n#define QGR_KEY_SPLASH_GIVEN_ROCKET\t\t1111020507\n#define QGR_KEY_SPLASH_TAKEN_ROCKET\t\t1111020508\n#define QGR_KEY_PICKUP_ROCKET\t\t\t1111020509\n#define QGR_KEY_TIME_ROCKET\t\t\t\t1111020510\n\n#define QGR_KEY_FRAG_PLASMA\t\t\t\t1211020600\n#define QGR_KEY_SUICIDE_PLASMA\t\t\t1111020601\n#define QGR_KEY_SHOT_FIRED_PLASMA\t\t1111020602\n#define QGR_KEY_HIT_GIVEN_PLASMA\t\t1111020603\n#define QGR_KEY_HIT_TAKEN_PLASMA\t\t1111020604\n#define QGR_KEY_DAMAGE_GIVEN_PLASMA\t\t1111020605\n#define QGR_KEY_DAMAGE_TAKEN_PLASMA\t\t1111020606\n#define QGR_KEY_SPLASH_GIVEN_PLASMA\t\t1111020607\n#define QGR_KEY_SPLASH_TAKEN_PLASMA\t\t1111020608\n#define QGR_KEY_PICKUP_PLASMA\t\t\t1111020609\n#define QGR_KEY_TIME_PLASMA\t\t\t\t1111020610\n\n#define QGR_KEY_FRAG_RAILGUN\t\t\t1211020700\n#define QGR_KEY_SUICIDE_RAILGUN\t\t\t1111020701\n#define QGR_KEY_SHOT_FIRED_RAILGUN\t\t1111020702\n#define QGR_KEY_HIT_GIVEN_RAILGUN\t\t1111020703\n#define QGR_KEY_HIT_TAKEN_RAILGUN\t\t1111020704\n#define QGR_KEY_DAMAGE_GIVEN_RAILGUN\t1111020705\n#define QGR_KEY_DAMAGE_TAKEN_RAILGUN\t1111020706\n#define QGR_KEY_SPLASH_GIVEN_RAILGUN\t1111020707\n#define QGR_KEY_SPLASH_TAKEN_RAILGUN\t1111020708\n#define QGR_KEY_PICKUP_RAILGUN\t\t\t1111020709\n#define QGR_KEY_TIME_RAILGUN\t\t\t1111020710\n\n#define QGR_KEY_FRAG_LIGHTNING\t\t\t1211020800\n#define QGR_KEY_SUICIDE_LIGHTNING\t\t1111020801\n#define QGR_KEY_SHOT_FIRED_LIGHTNING\t1111020802\n#define QGR_KEY_HIT_GIVEN_LIGHTNING\t\t1111020803\n#define QGR_KEY_HIT_TAKEN_LIGHTNING\t\t1111020804\n#define QGR_KEY_DAMAGE_GIVEN_LIGHTNING\t1111020805\n#define QGR_KEY_DAMAGE_TAKEN_LIGHTNING\t1111020806\n#define QGR_KEY_SPLASH_GIVEN_LIGHTNING\t1111020807\n#define QGR_KEY_SPLASH_TAKEN_LIGHTNING\t1111020808\n#define QGR_KEY_PICKUP_LIGHTNING\t\t1111020809\n#define QGR_KEY_TIME_LIGHTNING\t\t\t1111020810\n\n#define QGR_KEY_FRAG_BFG\t\t\t\t1211020900\n#define QGR_KEY_SUICIDE_BFG\t\t\t\t1111020901\n#define QGR_KEY_SHOT_FIRED_BFG\t\t\t1111020902\n#define QGR_KEY_HIT_GIVEN_BFG\t\t\t1111020903\n#define QGR_KEY_HIT_TAKEN_BFG\t\t\t1111020904\n#define QGR_KEY_DAMAGE_GIVEN_BFG\t\t1111020905\n#define QGR_KEY_DAMAGE_TAKEN_BFG\t\t1111020906\n#define QGR_KEY_SPLASH_GIVEN_BFG\t\t1111020907\n#define QGR_KEY_SPLASH_TAKEN_BFG\t\t1111020908\n#define QGR_KEY_PICKUP_BFG\t\t\t\t1111020909\n#define QGR_KEY_TIME_BFG\t\t\t\t1111020910\n\n#define QGR_KEY_FRAG_GRAPPLE\t\t\t1211021000\n#define QGR_KEY_SUICIDE_GRAPPLE\t\t\t1111021001\n#define QGR_KEY_SHOT_FIRED_GRAPPLE\t\t1111021002\n#define QGR_KEY_HIT_GIVEN_GRAPPLE\t\t1111021003\n#define QGR_KEY_HIT_TAKEN_GRAPPLE\t\t1111021004\n#define QGR_KEY_DAMAGE_GIVEN_GRAPPLE\t1111021005\n#define QGR_KEY_DAMAGE_TAKEN_GRAPPLE\t1111021006\n#define QGR_KEY_SPLASH_GIVEN_GRAPPLE\t1111021007\n#define QGR_KEY_SPLASH_TAKEN_GRAPPLE\t1111021008\n#define QGR_KEY_PICKUP_GRAPPLE\t\t\t1111021009\n#define QGR_KEY_TIME_GRAPPLE\t\t\t1111021010\n\n#define QGR_KEY_FRAG_UNKNOWN\t\t\t1211021100\n#define QGR_KEY_SUICIDE_UNKNOWN\t\t\t1111021101\n#define QGR_KEY_SHOT_FIRED_UNKNOWN\t\t1111021102\n#define QGR_KEY_HIT_GIVEN_UNKNOWN\t\t1111021103\n#define QGR_KEY_HIT_TAKEN_UNKNOWN\t\t1111021104\n#define QGR_KEY_DAMAGE_GIVEN_UNKNOWN\t1111021105\n#define QGR_KEY_DAMAGE_TAKEN_UNKNOWN\t1111021106\n#define QGR_KEY_SPLASH_GIVEN_UNKNOWN\t1111021107\n#define QGR_KEY_SPLASH_TAKEN_UNKNOWN\t1111021108\n#define QGR_KEY_PICKUP_UNKNOWN\t\t\t1111021109\n#define QGR_KEY_TIME_UNKNOWN\t\t\t1111021110\n\n#ifdef MISSIONPACK\n// new to team arena\n#define QGR_KEY_FRAG_NAILGIN\t\t\t1211021200\n#define QGR_KEY_SUICIDE_NAILGIN\t\t\t1111021201\n#define QGR_KEY_SHOT_FIRED_NAILGIN\t\t1111021202\n#define QGR_KEY_HIT_GIVEN_NAILGIN\t\t1111021203\n#define QGR_KEY_HIT_TAKEN_NAILGIN\t\t1111021204\n#define QGR_KEY_DAMAGE_GIVEN_NAILGIN\t1111021205\n#define QGR_KEY_DAMAGE_TAKEN_NAILGIN\t1111021206\n#define QGR_KEY_SPLASH_GIVEN_NAILGIN\t1111021207\n#define QGR_KEY_SPLASH_TAKEN_NAILGIN\t1111021208\n#define QGR_KEY_PICKUP_NAILGIN\t\t\t1111021209\n#define QGR_KEY_TIME_NAILGIN\t\t\t1111021210\n// new to team arena\n#define QGR_KEY_FRAG_PROX_LAUNCHER\t\t\t1211021300\n#define QGR_KEY_SUICIDE_PROX_LAUNCHER\t\t1111021301\n#define QGR_KEY_SHOT_FIRED_PROX_LAUNCHER \t1111021302\n#define QGR_KEY_HIT_GIVEN_PROX_LAUNCHER\t\t1111021303\n#define QGR_KEY_HIT_TAKEN_PROX_LAUNCHER\t\t1111021304\n#define QGR_KEY_DAMAGE_GIVEN_PROX_LAUNCHER\t1111021305\n#define QGR_KEY_DAMAGE_TAKEN_PROX_LAUNCHER\t1111021306\n#define QGR_KEY_SPLASH_GIVEN_PROX_LAUNCHER\t1111021307\n#define QGR_KEY_SPLASH_TAKEN_PROX_LAUNCHER\t1111021308\n#define QGR_KEY_PICKUP_PROX_LAUNCHER\t\t1111021309\n#define QGR_KEY_TIME_PROX_LAUNCHER\t\t\t1111021310\n// new to team arena\n#define QGR_KEY_FRAG_CHAINGUN\t\t\t1211021400\n#define QGR_KEY_SUICIDE_CHAINGUN\t\t1111021401\n#define QGR_KEY_SHOT_FIRED_CHAINGUN \t1111021402\n#define QGR_KEY_HIT_GIVEN_CHAINGUN\t\t1111021403\n#define QGR_KEY_HIT_TAKEN_CHAINGUN\t\t1111021404\n#define QGR_KEY_DAMAGE_GIVEN_CHAINGUN\t1111021405\n#define QGR_KEY_DAMAGE_TAKEN_CHAINGUN\t1111021406\n#define QGR_KEY_SPLASH_GIVEN_CHAINGUN\t1111021407\n#define QGR_KEY_SPLASH_TAKEN_CHAINGUN\t1111021408\n#define QGR_KEY_PICKUP_CHAINGUN\t\t\t1111021409\n#define QGR_KEY_TIME_CHAINGUN\t\t\t1111021410\n#endif /* MISSIONPACK */\n\n// ammo keys\n#define QGR_KEY_BOXES\t\t\t\t\t1111030000\n#define QGR_KEY_ROUNDS\t\t\t\t\t1111030001\n\n#define QGR_KEY_BOXES_BULLETS\t\t\t1111030100\n#define QGR_KEY_ROUNDS_BULLETS\t\t\t1111030101\n\n#define QGR_KEY_BOXES_SHELLS\t\t\t1111030200\n#define QGR_KEY_ROUNDS_SHELLS\t\t\t1111030201\n\n#define QGR_KEY_BOXES_GRENADES\t\t\t1111030300\n#define QGR_KEY_ROUNDS_GRENADES\t\t\t1111030301\n\n#define QGR_KEY_BOXES_ROCKETS\t\t\t1111030400\n#define QGR_KEY_ROUNDS_ROCKETS\t\t\t1111030401\n\n#define QGR_KEY_BOXES_CELLS\t\t\t\t1111030500\n#define QGR_KEY_ROUNDS_CELLS\t\t\t1111030501\n\n#define QGR_KEY_BOXES_SLUGS\t\t\t\t1111030600\n#define QGR_KEY_ROUNDS_SLUGS\t\t\t1111030601\n\n#define QGR_KEY_BOXES_LG_AMMO\t\t\t1111030700\n#define QGR_KEY_ROUNDS_LG_AMMO\t\t\t1111030701\n\n#define QGR_KEY_BOXES_BFG_AMMO\t\t\t1111030800\n#define QGR_KEY_ROUNDS_BFG_AMMO\t\t\t1111030801\n\n#ifdef MISSIONPACK\n// new to team arena\n#define QGR_KEY_BOXES_NAILGUN_AMMO\t\t1111030900\n#define QGR_KEY_ROUNDS_NAILGUN_AMMO\t \t1111030901\n// new to team arena\n#define QGR_KEY_BOXES_PROX_LAUNCHER_AMMO \t1111031000\n#define QGR_KEY_ROUNDS_PROX_LAUNCHER_AMMO \t1111031001\n// new to team arena\n#define QGR_KEY_BOXES_CHAINGUN_AMMO \t1111031100\n#define QGR_KEY_ROUNDS_CHAINGUN_AMMO \t1111031101\n#endif /* MISSIONPACK */\n\n// health keys\n#define QGR_KEY_HEALTH\t\t\t\t\t1111040000\n#define QGR_KEY_HEALTH_TOTAL\t\t\t1111040001\n\n#define QGR_KEY_HEALTH_5\t\t\t\t1111040100\n#define QGR_KEY_HEALTH_25\t\t\t\t1111040200\n#define QGR_KEY_HEALTH_50\t\t\t\t1111040300\n#define QGR_KEY_HEALTH_MEGA\t\t\t\t1111040400\n\n// armor keys\n#define QGR_KEY_ARMOR\t\t\t\t\t1111050000\n#define QGR_KEY_ARMOR_TOTAL\t\t\t\t1111050001\n\n#define QGR_KEY_ARMOR_SHARD\t\t\t\t1111050100\n#define QGR_KEY_ARMOR_YELLOW\t\t\t1111050200\n#define QGR_KEY_ARMOR_RED\t\t\t\t1111050300\n\n// powerup keys\n#define QGR_KEY_POWERUP\t\t\t\t\t1111060000\n#define QGR_KEY_QUAD\t\t\t\t\t1111060100\n#define QGR_KEY_SUIT\t\t\t\t\t1111060200\n#define QGR_KEY_HASTE\t\t\t\t\t1111060300\n#define QGR_KEY_INVIS\t\t\t\t\t1111060400\n#define QGR_KEY_REGEN\t\t\t\t\t1111060500\n#define QGR_KEY_FLIGHT\t\t\t\t\t1111060600\n\n#ifdef MISSIONPACK\n// persistant powerup keys\n// new to team arena\n#define QGR_KEY_SCOUT\t\t\t\t\t1111160800\n#define QGR_KEY_GUARD\t\t\t\t\t1111160801\n#define QGR_KEY_DOUBLER\t\t\t\t\t1111160802\n#define QGR_KEY_AMMOREGEN\t\t\t\t1111160803\n\n#endif //MISSIONPACK\n\n// holdable item keys\n#define QGR_KEY_MEDKIT\t\t\t\t\t1111070000\n#define QGR_KEY_MEDKIT_USE\t\t\t\t1111070001\n\n#define QGR_KEY_TELEPORTER\t\t\t\t1111070100\n#define QGR_KEY_TELEPORTER_USE\t\t\t1111070101\n\n#ifdef MISSIONPACK\n// new to team arena\n#define QGR_KEY_KAMIKAZE\t\t\t\t1111070200\n#define QGR_KEY_KAMIKAZE_USE\t\t\t1111070201\n// new to team arena\n#define QGR_KEY_PORTAL\t\t\t\t\t1111070300\n#define QGR_KEY_PORTAL_USE\t\t\t\t1111070301\n// new to team arena\n#define QGR_KEY_INVULNERABILITY\t\t\t1111070400\n#define QGR_KEY_INVULNERABILITY_USE\t\t1111070401\n#endif /* MISSIONPACK */\n\n// hazard keys\n#define QGR_KEY_HAZARD_DEATH\t\t\t1111080000\n#define QGR_KEY_WATER\t\t\t\t\t1111080100\n#define QGR_KEY_SLIME\t\t\t\t\t1111080200\n#define QGR_KEY_LAVA\t\t\t\t\t1111080300\n#define QGR_KEY_CRUSH\t\t\t\t\t1111080400\n#define QGR_KEY_TELEFRAG\t\t\t\t1111080500\n#define QGR_KEY_FALLING\t\t\t\t\t1111080600\n#define QGR_KEY_SUICIDE_CMD\t\t\t\t1111080700\n#define QGR_KEY_TRIGGER_HURT\t\t\t1111080800\n#define QGR_KEY_HAZARD_MISC\t\t\t\t1111080900\n\n// reward keys\n#define QGR_KEY_IMPRESSIVE\t\t\t\t1111090000\n#define QGR_KEY_EXCELLENT\t\t\t\t1111090100\n\n// teammate keys\n#define QGR_KEY_TEAMMATE_FRAG\t\t\t1211100000\n#define QGR_KEY_TEAMMATE_HIT_GIVEN\t\t1111100001\n#define QGR_KEY_TEAMMATE_HIT_TAKEN\t\t1111100002\n#define QGR_KEY_TEAMMATE_DAMAGE_GIVEN\t1111100003\n#define QGR_KEY_TEAMMATE_DAMAGE_TAKEN\t1111100004\n#define QGR_KEY_TEAMMATE_SPLASH_GIVEN\t1111100005\n#define QGR_KEY_TEAMMATE_SPLASH_TAKEN\t1111100006\n#define QGR_KEY_TEAM_NAME\t\t\t\t1100100007\n\n// ctf keys\n#define QGR_KEY_FLAG_PICKUP\t\t\t\t1111110000\n#define QGR_KEY_FLAG_CAPTURE\t\t\t1111110001\n\n#endif // _G_RANKINGS_H_\n"
  },
  {
    "path": "src/game/g_session.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n#include \"g_local.h\"\n\n\n/*\n=======================================================================\n\n  SESSION DATA\n\nSession data is the only data that stays persistant across level loads\nand tournament restarts.\n=======================================================================\n*/\n\n/*\n================\nG_WriteClientSessionData\n\nCalled on game shutdown\n================\n*/\nvoid G_WriteClientSessionData( gclient_t *client ) {\n\tconst char\t*s;\n\tconst char\t*var;\n\n\ts = va(\"%i %i %i %i %i %i %i\", \n\t\tclient->sess.sessionTeam,\n\t\tclient->sess.spectatorTime,\n\t\tclient->sess.spectatorState,\n\t\tclient->sess.spectatorClient,\n\t\tclient->sess.wins,\n\t\tclient->sess.losses,\n\t\tclient->sess.teamLeader\n\t\t);\n\n\tvar = va( \"session%i\", client - level.clients );\n\n\ttrap_Cvar_Set( var, s );\n}\n\n/*\n================\nG_ReadSessionData\n\nCalled on a reconnect\n================\n*/\nvoid G_ReadSessionData( gclient_t *client ) {\n\tchar\ts[MAX_STRING_CHARS];\n\tconst char\t*var;\n\n\t// bk001205 - format\n\tint teamLeader;\n\tint spectatorState;\n\tint sessionTeam;\n\n\tvar = va( \"session%i\", client - level.clients );\n\ttrap_Cvar_VariableStringBuffer( var, s, sizeof(s) );\n\n\tsscanf( s, \"%i %i %i %i %i %i %i\",\n\t\t&sessionTeam,                 // bk010221 - format\n\t\t&client->sess.spectatorTime,\n\t\t&spectatorState,              // bk010221 - format\n\t\t&client->sess.spectatorClient,\n\t\t&client->sess.wins,\n\t\t&client->sess.losses,\n\t\t&teamLeader                   // bk010221 - format\n\t\t);\n\n\t// bk001205 - format issues\n\tclient->sess.sessionTeam = (team_t)sessionTeam;\n\tclient->sess.spectatorState = (spectatorState_t)spectatorState;\n\tclient->sess.teamLeader = (qboolean)teamLeader;\n}\n\n\n/*\n================\nG_InitSessionData\n\nCalled on a first-time connect\n================\n*/\nvoid G_InitSessionData( gclient_t *client, char *userinfo ) {\n\tclientSession_t\t*sess;\n\tconst char\t\t*value;\n\n\tsess = &client->sess;\n\n\t// initial team determination\n\tif ( g_gametype.integer >= GT_TEAM ) {\n\t\tif ( g_teamAutoJoin.integer ) {\n\t\t\tsess->sessionTeam = PickTeam( -1 );\n\t\t\tBroadcastTeamChange( client, -1 );\n\t\t} else {\n\t\t\t// always spawn as spectator in team games\n\t\t\tsess->sessionTeam = TEAM_SPECTATOR;\t\n\t\t}\n\t} else {\n\t\tvalue = Info_ValueForKey( userinfo, \"team\" );\n\t\tif ( value[0] == 's' ) {\n\t\t\t// a willing spectator, not a waiting-in-line\n\t\t\tsess->sessionTeam = TEAM_SPECTATOR;\n\t\t} else {\n\t\t\tswitch ( g_gametype.integer ) {\n\t\t\tdefault:\n\t\t\tcase GT_FFA:\n\t\t\tcase GT_SINGLE_PLAYER:\n\t\t\t\tif ( g_maxGameClients.integer > 0 && \n\t\t\t\t\tlevel.numNonSpectatorClients >= g_maxGameClients.integer ) {\n\t\t\t\t\tsess->sessionTeam = TEAM_SPECTATOR;\n\t\t\t\t} else {\n\t\t\t\t\tsess->sessionTeam = TEAM_FREE;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase GT_TOURNAMENT:\n\t\t\t\t// if the game is full, go into a waiting mode\n\t\t\t\tif ( level.numNonSpectatorClients >= 2 ) {\n\t\t\t\t\tsess->sessionTeam = TEAM_SPECTATOR;\n\t\t\t\t} else {\n\t\t\t\t\tsess->sessionTeam = TEAM_FREE;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tsess->spectatorState = SPECTATOR_FREE;\n\tsess->spectatorTime = level.time;\n\n\tG_WriteClientSessionData( client );\n}\n\n\n/*\n==================\nG_InitWorldSession\n\n==================\n*/\nvoid G_InitWorldSession( void ) {\n\tchar\ts[MAX_STRING_CHARS];\n\tint\t\t\tgt;\n\n\ttrap_Cvar_VariableStringBuffer( \"session\", s, sizeof(s) );\n\tgt = atoi( s );\n\t\n\t// if the gametype changed since the last session, don't use any\n\t// client sessions\n\tif ( g_gametype.integer != gt ) {\n\t\tlevel.newSession = qtrue;\n\t\tG_Printf( \"Gametype changed, clearing session data.\\n\" );\n\t}\n}\n\n/*\n==================\nG_WriteSessionData\n\n==================\n*/\nvoid G_WriteSessionData( void ) {\n\tint\t\ti;\n\n\ttrap_Cvar_Set( \"session\", va(\"%i\", g_gametype.integer) );\n\n\tfor ( i = 0 ; i < level.maxclients ; i++ ) {\n\t\tif ( level.clients[i].pers.connected == CON_CONNECTED ) {\n\t\t\tG_WriteClientSessionData( &level.clients[i] );\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/game/g_spawn.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n\n#include \"g_local.h\"\n\nqboolean\tG_SpawnString( const char *key, const char *defaultString, char **out ) {\n\tint\t\ti;\n\n\tif ( !level.spawning ) {\n\t\t*out = (char *)defaultString;\n//\t\tG_Error( \"G_SpawnString() called while not spawning\" );\n\t}\n\n\tfor ( i = 0 ; i < level.numSpawnVars ; i++ ) {\n\t\tif ( !Q_stricmp( key, level.spawnVars[i][0] ) ) {\n\t\t\t*out = level.spawnVars[i][1];\n\t\t\treturn qtrue;\n\t\t}\n\t}\n\n\t*out = (char *)defaultString;\n\treturn qfalse;\n}\n\nqboolean\tG_SpawnFloat( const char *key, const char *defaultString, float *out ) {\n\tchar\t\t*s;\n\tqboolean\tpresent;\n\n\tpresent = G_SpawnString( key, defaultString, &s );\n\t*out = atof( s );\n\treturn present;\n}\n\nqboolean\tG_SpawnInt( const char *key, const char *defaultString, int *out ) {\n\tchar\t\t*s;\n\tqboolean\tpresent;\n\n\tpresent = G_SpawnString( key, defaultString, &s );\n\t*out = atoi( s );\n\treturn present;\n}\n\nqboolean\tG_SpawnVector( const char *key, const char *defaultString, float *out ) {\n\tchar\t\t*s;\n\tqboolean\tpresent;\n\n\tpresent = G_SpawnString( key, defaultString, &s );\n\tsscanf( s, \"%f %f %f\", &out[0], &out[1], &out[2] );\n\treturn present;\n}\n\n\n\n//\n// fields are needed for spawning from the entity string\n//\ntypedef enum {\n\tF_INT, \n\tF_FLOAT,\n\tF_LSTRING,\t\t\t// string on disk, pointer in memory, TAG_LEVEL\n\tF_GSTRING,\t\t\t// string on disk, pointer in memory, TAG_GAME\n\tF_VECTOR,\n\tF_ANGLEHACK,\n\tF_ENTITY,\t\t\t// index on disk, pointer in memory\n\tF_ITEM,\t\t\t\t// index on disk, pointer in memory\n\tF_CLIENT,\t\t\t// index on disk, pointer in memory\n\tF_IGNORE\n} fieldtype_t;\n\ntypedef struct\n{\n\tchar\t*name;\n\tint\t\tofs;\n\tfieldtype_t\ttype;\n\tint\t\tflags;\n} field_t;\n\nfield_t fields[] = {\n\t{\"classname\", FOFS(classname), F_LSTRING},\n\t{\"origin\", FOFS(s.origin), F_VECTOR},\n\t{\"model\", FOFS(model), F_LSTRING},\n\t{\"model2\", FOFS(model2), F_LSTRING},\n\t{\"spawnflags\", FOFS(spawnflags), F_INT},\n\t{\"speed\", FOFS(speed), F_FLOAT},\n\t{\"target\", FOFS(target), F_LSTRING},\n\t{\"targetname\", FOFS(targetname), F_LSTRING},\n\t{\"message\", FOFS(message), F_LSTRING},\n\t{\"team\", FOFS(team), F_LSTRING},\n\t{\"wait\", FOFS(wait), F_FLOAT},\n\t{\"random\", FOFS(random), F_FLOAT},\n\t{\"count\", FOFS(count), F_INT},\n\t{\"health\", FOFS(health), F_INT},\n\t{\"light\", 0, F_IGNORE},\n\t{\"dmg\", FOFS(damage), F_INT},\n\t{\"angles\", FOFS(s.angles), F_VECTOR},\n\t{\"angle\", FOFS(s.angles), F_ANGLEHACK},\n\t{\"targetShaderName\", FOFS(targetShaderName), F_LSTRING},\n\t{\"targetShaderNewName\", FOFS(targetShaderNewName), F_LSTRING},\n\n\t{NULL}\n};\n\n\ntypedef struct {\n\tchar\t*name;\n\tvoid\t(*spawn)(gentity_t *ent);\n} spawn_t;\n\nvoid SP_info_player_start (gentity_t *ent);\nvoid SP_info_player_deathmatch (gentity_t *ent);\nvoid SP_info_player_intermission (gentity_t *ent);\nvoid SP_info_firstplace(gentity_t *ent);\nvoid SP_info_secondplace(gentity_t *ent);\nvoid SP_info_thirdplace(gentity_t *ent);\nvoid SP_info_podium(gentity_t *ent);\n\nvoid SP_func_plat (gentity_t *ent);\nvoid SP_func_static (gentity_t *ent);\nvoid SP_func_rotating (gentity_t *ent);\nvoid SP_func_bobbing (gentity_t *ent);\nvoid SP_func_pendulum( gentity_t *ent );\nvoid SP_func_button (gentity_t *ent);\nvoid SP_func_door (gentity_t *ent);\nvoid SP_func_train (gentity_t *ent);\nvoid SP_func_timer (gentity_t *self);\n\nvoid SP_trigger_always (gentity_t *ent);\nvoid SP_trigger_multiple (gentity_t *ent);\nvoid SP_trigger_push (gentity_t *ent);\nvoid SP_trigger_teleport (gentity_t *ent);\nvoid SP_trigger_hurt (gentity_t *ent);\n\nvoid SP_target_remove_powerups( gentity_t *ent );\nvoid SP_target_give (gentity_t *ent);\nvoid SP_target_delay (gentity_t *ent);\nvoid SP_target_speaker (gentity_t *ent);\nvoid SP_target_print (gentity_t *ent);\nvoid SP_target_laser (gentity_t *self);\nvoid SP_target_character (gentity_t *ent);\nvoid SP_target_score( gentity_t *ent );\nvoid SP_target_teleporter( gentity_t *ent );\nvoid SP_target_relay (gentity_t *ent);\nvoid SP_target_kill (gentity_t *ent);\nvoid SP_target_position (gentity_t *ent);\nvoid SP_target_location (gentity_t *ent);\nvoid SP_target_push (gentity_t *ent);\n\nvoid SP_light (gentity_t *self);\nvoid SP_info_null (gentity_t *self);\nvoid SP_info_notnull (gentity_t *self);\nvoid SP_info_camp (gentity_t *self);\nvoid SP_path_corner (gentity_t *self);\n\nvoid SP_misc_teleporter_dest (gentity_t *self);\nvoid SP_misc_model(gentity_t *ent);\nvoid SP_misc_portal_camera(gentity_t *ent);\nvoid SP_misc_portal_surface(gentity_t *ent);\n\nvoid SP_shooter_rocket( gentity_t *ent );\nvoid SP_shooter_plasma( gentity_t *ent );\nvoid SP_shooter_grenade( gentity_t *ent );\n\nvoid SP_team_CTF_redplayer( gentity_t *ent );\nvoid SP_team_CTF_blueplayer( gentity_t *ent );\n\nvoid SP_team_CTF_redspawn( gentity_t *ent );\nvoid SP_team_CTF_bluespawn( gentity_t *ent );\n\nvoid SP_item_botroam( gentity_t *ent ) {};\n\nspawn_t\tspawns[] = {\n\t// info entities don't do anything at all, but provide positional\n\t// information for things controlled by other processes\n\t{\"info_player_start\", SP_info_player_start},\n\t{\"info_player_deathmatch\", SP_info_player_deathmatch},\n\t{\"info_player_intermission\", SP_info_player_intermission},\n\t{\"info_null\", SP_info_null},\n\t{\"info_notnull\", SP_info_notnull},\t\t// use target_position instead\n\t{\"info_camp\", SP_info_camp},\n\n\t{\"func_plat\", SP_func_plat},\n\t{\"func_button\", SP_func_button},\n\t{\"func_door\", SP_func_door},\n\t{\"func_static\", SP_func_static},\n\t{\"func_rotating\", SP_func_rotating},\n\t{\"func_bobbing\", SP_func_bobbing},\n\t{\"func_pendulum\", SP_func_pendulum},\n\t{\"func_train\", SP_func_train},\n\t{\"func_group\", SP_info_null},\n\t{\"func_timer\", SP_func_timer},\t\t\t// rename trigger_timer?\n\n\t// Triggers are brush objects that cause an effect when contacted\n\t// by a living player, usually involving firing targets.\n\t// While almost everything could be done with\n\t// a single trigger class and different targets, triggered effects\n\t// could not be client side predicted (push and teleport).\n\t{\"trigger_always\", SP_trigger_always},\n\t{\"trigger_multiple\", SP_trigger_multiple},\n\t{\"trigger_push\", SP_trigger_push},\n\t{\"trigger_teleport\", SP_trigger_teleport},\n\t{\"trigger_hurt\", SP_trigger_hurt},\n\n\t// targets perform no action by themselves, but must be triggered\n\t// by another entity\n\t{\"target_give\", SP_target_give},\n\t{\"target_remove_powerups\", SP_target_remove_powerups},\n\t{\"target_delay\", SP_target_delay},\n\t{\"target_speaker\", SP_target_speaker},\n\t{\"target_print\", SP_target_print},\n\t{\"target_laser\", SP_target_laser},\n\t{\"target_score\", SP_target_score},\n\t{\"target_teleporter\", SP_target_teleporter},\n\t{\"target_relay\", SP_target_relay},\n\t{\"target_kill\", SP_target_kill},\n\t{\"target_position\", SP_target_position},\n\t{\"target_location\", SP_target_location},\n\t{\"target_push\", SP_target_push},\n\n\t{\"light\", SP_light},\n\t{\"path_corner\", SP_path_corner},\n\n\t{\"misc_teleporter_dest\", SP_misc_teleporter_dest},\n\t{\"misc_model\", SP_misc_model},\n\t{\"misc_portal_surface\", SP_misc_portal_surface},\n\t{\"misc_portal_camera\", SP_misc_portal_camera},\n\n\t{\"shooter_rocket\", SP_shooter_rocket},\n\t{\"shooter_grenade\", SP_shooter_grenade},\n\t{\"shooter_plasma\", SP_shooter_plasma},\n\n\t{\"team_CTF_redplayer\", SP_team_CTF_redplayer},\n\t{\"team_CTF_blueplayer\", SP_team_CTF_blueplayer},\n\n\t{\"team_CTF_redspawn\", SP_team_CTF_redspawn},\n\t{\"team_CTF_bluespawn\", SP_team_CTF_bluespawn},\n\n\t{\"item_botroam\", SP_item_botroam},\n\n\t{0, 0}\n};\n\n/*\n===============\nG_CallSpawn\n\nFinds the spawn function for the entity and calls it,\nreturning qfalse if not found\n===============\n*/\nqboolean G_CallSpawn( gentity_t *ent ) {\n\tspawn_t\t*s;\n\tgitem_t\t*item;\n\n\tif ( !ent->classname ) {\n\t\tG_Printf (\"G_CallSpawn: NULL classname\\n\");\n\t\treturn qfalse;\n\t}\n\n\t// check item spawn functions\n\tfor ( item=bg_itemlist+1 ; item->classname ; item++ ) {\n\t\tif ( !strcmp(item->classname, ent->classname) ) {\n\t\t\tG_SpawnItem( ent, item );\n\t\t\treturn qtrue;\n\t\t}\n\t}\n\n\t// check normal spawn functions\n\tfor ( s=spawns ; s->name ; s++ ) {\n\t\tif ( !strcmp(s->name, ent->classname) ) {\n\t\t\t// found it\n\t\t\ts->spawn(ent);\n\t\t\treturn qtrue;\n\t\t}\n\t}\n\tG_Printf (\"%s doesn't have a spawn function\\n\", ent->classname);\n\treturn qfalse;\n}\n\n/*\n=============\nG_NewString\n\nBuilds a copy of the string, translating \\n to real linefeeds\nso message texts can be multi-line\n=============\n*/\nchar *G_NewString( const char *string ) {\n\tchar\t*newb, *new_p;\n\tint\t\ti,l;\n\t\n\tl = (int)strlen(string) + 1;\n\n\tnewb = G_Alloc( l );\n\n\tnew_p = newb;\n\n\t// turn \\n into a real linefeed\n\tfor ( i=0 ; i< l ; i++ ) {\n\t\tif (string[i] == '\\\\' && i < l-1) {\n\t\t\ti++;\n\t\t\tif (string[i] == 'n') {\n\t\t\t\t*new_p++ = '\\n';\n\t\t\t} else {\n\t\t\t\t*new_p++ = '\\\\';\n\t\t\t}\n\t\t} else {\n\t\t\t*new_p++ = string[i];\n\t\t}\n\t}\n\t\n\treturn newb;\n}\n\n\n\n\n/*\n===============\nG_ParseField\n\nTakes a key/value pair and sets the binary values\nin a gentity\n===============\n*/\nvoid G_ParseField( const char *key, const char *value, gentity_t *ent ) {\n\tfield_t\t*f;\n\tbyte\t*b;\n\tfloat\tv;\n\tvec3_t\tvec;\n\n\tfor ( f=fields ; f->name ; f++ ) {\n\t\tif ( !Q_stricmp(f->name, key) ) {\n\t\t\t// found it\n\t\t\tb = (byte *)ent;\n\n\t\t\tswitch( f->type ) {\n\t\t\tcase F_LSTRING:\n\t\t\t\t*(char **)(b+f->ofs) = G_NewString (value);\n\t\t\t\tbreak;\n\t\t\tcase F_VECTOR:\n\t\t\t\tsscanf (value, \"%f %f %f\", &vec[0], &vec[1], &vec[2]);\n\t\t\t\t((float *)(b+f->ofs))[0] = vec[0];\n\t\t\t\t((float *)(b+f->ofs))[1] = vec[1];\n\t\t\t\t((float *)(b+f->ofs))[2] = vec[2];\n\t\t\t\tbreak;\n\t\t\tcase F_INT:\n\t\t\t\t*(int *)(b+f->ofs) = atoi(value);\n\t\t\t\tbreak;\n\t\t\tcase F_FLOAT:\n\t\t\t\t*(float *)(b+f->ofs) = atof(value);\n\t\t\t\tbreak;\n\t\t\tcase F_ANGLEHACK:\n\t\t\t\tv = atof(value);\n\t\t\t\t((float *)(b+f->ofs))[0] = 0;\n\t\t\t\t((float *)(b+f->ofs))[1] = v;\n\t\t\t\t((float *)(b+f->ofs))[2] = 0;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\tcase F_IGNORE:\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t}\n}\n\n\n\n\n/*\n===================\nG_SpawnGEntityFromSpawnVars\n\nSpawn an entity and fill in all of the level fields from\nlevel.spawnVars[], then call the class specfic spawn function\n===================\n*/\nvoid G_SpawnGEntityFromSpawnVars( void ) {\n\tint\t\t\ti;\n\tgentity_t\t*ent;\n\tchar\t\t*s, *value, *gametypeName;\n\tstatic char *gametypeNames[] = {\"ffa\", \"tournament\", \"single\", \"team\", \"ctf\", \"oneflag\", \"obelisk\", \"harvester\", \"teamtournament\"};\n\n\t// get the next free entity\n\tent = G_Spawn();\n\n\tfor ( i = 0 ; i < level.numSpawnVars ; i++ ) {\n\t\tG_ParseField( level.spawnVars[i][0], level.spawnVars[i][1], ent );\n\t}\n\n\t// check for \"notsingle\" flag\n\tif ( g_gametype.integer == GT_SINGLE_PLAYER ) {\n\t\tG_SpawnInt( \"notsingle\", \"0\", &i );\n\t\tif ( i ) {\n\t\t\tG_FreeEntity( ent );\n\t\t\treturn;\n\t\t}\n\t}\n\t// check for \"notteam\" flag (GT_FFA, GT_TOURNAMENT, GT_SINGLE_PLAYER)\n\tif ( g_gametype.integer >= GT_TEAM ) {\n\t\tG_SpawnInt( \"notteam\", \"0\", &i );\n\t\tif ( i ) {\n\t\t\tG_FreeEntity( ent );\n\t\t\treturn;\n\t\t}\n\t} else {\n\t\tG_SpawnInt( \"notfree\", \"0\", &i );\n\t\tif ( i ) {\n\t\t\tG_FreeEntity( ent );\n\t\t\treturn;\n\t\t}\n\t}\n\n\tG_SpawnInt( \"notq3a\", \"0\", &i );\n\tif ( i ) {\n\t\tG_FreeEntity( ent );\n\t\treturn;\n\t}\n\n\tif( G_SpawnString( \"gametype\", NULL, &value ) ) {\n\t\tif( g_gametype.integer >= GT_FFA && g_gametype.integer < GT_MAX_GAME_TYPE ) {\n\t\t\tgametypeName = gametypeNames[g_gametype.integer];\n\n\t\t\ts = strstr( value, gametypeName );\n\t\t\tif( !s ) {\n\t\t\t\tG_FreeEntity( ent );\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\t// move editor origin to pos\n\tVectorCopy( ent->s.origin, ent->s.pos.trBase );\n\tVectorCopy( ent->s.origin, ent->r.currentOrigin );\n\n\t// if we didn't get a classname, don't bother spawning anything\n\tif ( !G_CallSpawn( ent ) ) {\n\t\tG_FreeEntity( ent );\n\t}\n}\n\n\n\n/*\n====================\nG_AddSpawnVarToken\n====================\n*/\nchar *G_AddSpawnVarToken( const char *string ) {\n\tint\t\tl;\n\tchar\t*dest;\n\n\tl = (int)strlen( string );\n\tif ( level.numSpawnVarChars + l + 1 > MAX_SPAWN_VARS_CHARS ) {\n\t\tG_Error( \"G_AddSpawnVarToken: MAX_SPAWN_CHARS\" );\n\t}\n\n\tdest = level.spawnVarChars + level.numSpawnVarChars;\n\tmemcpy( dest, string, l+1 );\n\n\tlevel.numSpawnVarChars += l + 1;\n\n\treturn dest;\n}\n\n/*\n====================\nG_ParseSpawnVars\n\nParses a brace bounded set of key / value pairs out of the\nlevel's entity strings into level.spawnVars[]\n\nThis does not actually spawn an entity.\n====================\n*/\nqboolean G_ParseSpawnVars( void ) {\n\tchar\t\tkeyname[MAX_TOKEN_CHARS];\n\tchar\t\tcom_token[MAX_TOKEN_CHARS];\n\n\tlevel.numSpawnVars = 0;\n\tlevel.numSpawnVarChars = 0;\n\n\t// parse the opening brace\n\tif ( !trap_GetEntityToken( com_token, sizeof( com_token ) ) ) {\n\t\t// end of spawn string\n\t\treturn qfalse;\n\t}\n\tif ( com_token[0] != '{' ) {\n\t\tG_Error( \"G_ParseSpawnVars: found %s when expecting {\",com_token );\n\t}\n\n\t// go through all the key / value pairs\n\twhile ( 1 ) {\t\n\t\t// parse key\n\t\tif ( !trap_GetEntityToken( keyname, sizeof( keyname ) ) ) {\n\t\t\tG_Error( \"G_ParseSpawnVars: EOF without closing brace\" );\n\t\t}\n\n\t\tif ( keyname[0] == '}' ) {\n\t\t\tbreak;\n\t\t}\n\t\t\n\t\t// parse value\t\n\t\tif ( !trap_GetEntityToken( com_token, sizeof( com_token ) ) ) {\n\t\t\tG_Error( \"G_ParseSpawnVars: EOF without closing brace\" );\n\t\t}\n\n\t\tif ( com_token[0] == '}' ) {\n\t\t\tG_Error( \"G_ParseSpawnVars: closing brace without data\" );\n\t\t}\n\t\tif ( level.numSpawnVars == MAX_SPAWN_VARS ) {\n\t\t\tG_Error( \"G_ParseSpawnVars: MAX_SPAWN_VARS\" );\n\t\t}\n\t\tlevel.spawnVars[ level.numSpawnVars ][0] = G_AddSpawnVarToken( keyname );\n\t\tlevel.spawnVars[ level.numSpawnVars ][1] = G_AddSpawnVarToken( com_token );\n\t\tlevel.numSpawnVars++;\n\t}\n\n\treturn qtrue;\n}\n\n\n\n/*QUAKED worldspawn (0 0 0) ?\n\nEvery map should have exactly one worldspawn.\n\"music\"\t\tmusic wav file\n\"gravity\"\t800 is default gravity\n\"message\"\tText to print during connection process\n*/\nvoid SP_worldspawn( void ) {\n\tchar\t*s;\n\n\tG_SpawnString( \"classname\", \"\", &s );\n\tif ( Q_stricmp( s, \"worldspawn\" ) ) {\n\t\tG_Error( \"SP_worldspawn: The first entity isn't 'worldspawn'\" );\n\t}\n\n\t// make some data visible to connecting client\n\ttrap_SetConfigstring( CS_GAME_VERSION, GAME_VERSION );\n\n\ttrap_SetConfigstring( CS_LEVEL_START_TIME, va(\"%i\", level.startTime ) );\n\n\tG_SpawnString( \"music\", \"\", &s );\n\ttrap_SetConfigstring( CS_MUSIC, s );\n\n\tG_SpawnString( \"message\", \"\", &s );\n\ttrap_SetConfigstring( CS_MESSAGE, s );\t\t\t\t// map specific message\n\n\ttrap_SetConfigstring( CS_MOTD, g_motd.string );\t\t// message of the day\n\n\tG_SpawnString( \"gravity\", \"800\", &s );\n\ttrap_Cvar_Set( \"g_gravity\", s );\n\n\tG_SpawnString( \"enableDust\", \"0\", &s );\n\ttrap_Cvar_Set( \"g_enableDust\", s );\n\n\tG_SpawnString( \"enableBreath\", \"0\", &s );\n\ttrap_Cvar_Set( \"g_enableBreath\", s );\n\n\tg_entities[ENTITYNUM_WORLD].s.number = ENTITYNUM_WORLD;\n\tg_entities[ENTITYNUM_WORLD].classname = \"worldspawn\";\n\n\t// see if we want a warmup time\n\ttrap_SetConfigstring( CS_WARMUP, \"\" );\n\tif ( g_restarted.integer ) {\n\t\ttrap_Cvar_Set( \"g_restarted\", \"0\" );\n\t\tlevel.warmupTime = 0;\n\t} else if ( g_doWarmup.integer ) { // Turn it on\n\t\tlevel.warmupTime = -1;\n\t\ttrap_SetConfigstring( CS_WARMUP, va(\"%i\", level.warmupTime) );\n\t\tG_LogPrintf( \"Warmup:\\n\" );\n\t}\n\n}\n\n\n/*\n==============\nG_SpawnEntitiesFromString\n\nParses textual entity definitions out of an entstring and spawns gentities.\n==============\n*/\nvoid G_SpawnEntitiesFromString( void ) {\n\t// allow calls to G_Spawn*()\n\tlevel.spawning = qtrue;\n\tlevel.numSpawnVars = 0;\n\n\t// the worldspawn is not an actual entity, but it still\n\t// has a \"spawn\" function to perform any global setup\n\t// needed by a level (setting configstrings or cvars, etc)\n\tif ( !G_ParseSpawnVars() ) {\n\t\tG_Error( \"SpawnEntities: no entities\" );\n\t}\n\tSP_worldspawn();\n\n\t// parse ents\n\twhile( G_ParseSpawnVars() ) {\n\t\tG_SpawnGEntityFromSpawnVars();\n\t}\t\n\n\tlevel.spawning = qfalse;\t\t\t// any future calls to G_Spawn*() will be errors\n}\n\n"
  },
  {
    "path": "src/game/g_svcmds.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n\n// this file holds commands that can be executed by the server console, but not remote clients\n\n#include \"g_local.h\"\n\n\n/*\n==============================================================================\n\nPACKET FILTERING\n \n\nYou can add or remove addresses from the filter list with:\n\naddip <ip>\nremoveip <ip>\n\nThe ip address is specified in dot format, and you can use '*' to match any value\nso you can specify an entire class C network with \"addip 192.246.40.*\"\n\nRemoveip will only remove an address specified exactly the same way.  You cannot addip a subnet, then removeip a single host.\n\nlistip\nPrints the current list of filters.\n\ng_filterban <0 or 1>\n\nIf 1 (the default), then ip addresses matching the current list will be prohibited from entering the game.  This is the default setting.\n\nIf 0, then only addresses matching the list will be allowed.  This lets you easily set up a private game, or a game that only allows players from your local network.\n\nTTimo NOTE: for persistence, bans are stored in g_banIPs cvar MAX_CVAR_VALUE_STRING\nThe size of the cvar string buffer is limiting the banning to around 20 masks\nthis could be improved by putting some g_banIPs2 g_banIps3 etc. maybe\nstill, you should rely on PB for banning instead\n\n==============================================================================\n*/\n\ntypedef struct ipFilter_s\n{\n\tunsigned\tmask;\n\tunsigned\tcompare;\n} ipFilter_t;\n\n#define\tMAX_IPFILTERS\t1024\n\nstatic ipFilter_t\tipFilters[MAX_IPFILTERS];\nstatic int\t\t\tnumIPFilters;\n\n/*\n=================\nStringToFilter\n=================\n*/\nstatic qboolean StringToFilter (char *s, ipFilter_t *f)\n{\n\tchar\tnum[128];\n\tint\t\ti, j;\n\tbyte\tb[4];\n\tbyte\tm[4];\n\t\n\tfor (i=0 ; i<4 ; i++)\n\t{\n\t\tb[i] = 0;\n\t\tm[i] = 0;\n\t}\n\t\n\tfor (i=0 ; i<4 ; i++)\n\t{\n\t\tif (*s < '0' || *s > '9')\n\t\t{\n\t\t\tif (*s == '*') // 'match any'\n\t\t\t{\n\t\t\t\t// b[i] and m[i] to 0\n\t\t\t\ts++;\n\t\t\t\tif (!*s)\n\t\t\t\t\tbreak;\n\t\t\t\ts++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tG_Printf( \"Bad filter address: %s\\n\", s );\n\t\t\treturn qfalse;\n\t\t}\n\t\t\n\t\tj = 0;\n\t\twhile (*s >= '0' && *s <= '9')\n\t\t{\n\t\t\tnum[j++] = *s++;\n\t\t}\n\t\tnum[j] = 0;\n\t\tb[i] = atoi(num);\n\t\tm[i] = 255;\n\n\t\tif (!*s)\n\t\t\tbreak;\n\t\ts++;\n\t}\n\t\n\tf->mask = *(unsigned *)m;\n\tf->compare = *(unsigned *)b;\n\t\n\treturn qtrue;\n}\n\n/*\n=================\nUpdateIPBans\n=================\n*/\nstatic void UpdateIPBans (void)\n{\n\tbyte\tb[4];\n\tbyte\tm[4];\n\tint\t\ti,j;\n\tchar\tiplist_final[MAX_CVAR_VALUE_STRING];\n\tchar\tip[64];\n\n\t*iplist_final = 0;\n\tfor (i = 0 ; i < numIPFilters ; i++)\n\t{\n\t\tif (ipFilters[i].compare == 0xffffffff)\n\t\t\tcontinue;\n\n\t\t*(unsigned *)b = ipFilters[i].compare;\n\t\t*(unsigned *)m = ipFilters[i].mask;\n\t\t*ip = 0;\n\t\tfor (j = 0 ; j < 4 ; j++)\n\t\t{\n\t\t\tif (m[j]!=255)\n\t\t\t\tQ_strcat(ip, sizeof(ip), \"*\");\n\t\t\telse\n\t\t\t\tQ_strcat(ip, sizeof(ip), va(\"%i\", b[j]));\n\t\t\tQ_strcat(ip, sizeof(ip), (j<3) ? \".\" : \" \");\n\t\t}\t\t\n\t\tif (strlen(iplist_final)+strlen(ip) < MAX_CVAR_VALUE_STRING)\n\t\t{\n\t\t\tQ_strcat( iplist_final, sizeof(iplist_final), ip);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tCom_Printf(\"g_banIPs overflowed at MAX_CVAR_VALUE_STRING\\n\");\n\t\t\tbreak;\n\t\t}\n\t}\n\n\ttrap_Cvar_Set( \"g_banIPs\", iplist_final );\n}\n\n/*\n=================\nG_FilterPacket\n=================\n*/\nqboolean G_FilterPacket (char *from)\n{\n\tint\t\ti;\n\tunsigned\tin;\n\tbyte m[4];\n\tchar *p;\n\n\ti = 0;\n\tp = from;\n\twhile (*p && i < 4) {\n\t\tm[i] = 0;\n\t\twhile (*p >= '0' && *p <= '9') {\n\t\t\tm[i] = m[i]*10 + (*p - '0');\n\t\t\tp++;\n\t\t}\n\t\tif (!*p || *p == ':')\n\t\t\tbreak;\n\t\ti++, p++;\n\t}\n\t\n\tin = *(unsigned *)m;\n\n\tfor (i=0 ; i<numIPFilters ; i++)\n\t\tif ( (in & ipFilters[i].mask) == ipFilters[i].compare)\n\t\t\treturn g_filterBan.integer != 0;\n\n\treturn g_filterBan.integer == 0;\n}\n\n/*\n=================\nAddIP\n=================\n*/\nstatic void AddIP( char *str )\n{\n\tint\t\ti;\n\n\tfor (i = 0 ; i < numIPFilters ; i++)\n\t\tif (ipFilters[i].compare == 0xffffffff)\n\t\t\tbreak;\t\t// free spot\n\tif (i == numIPFilters)\n\t{\n\t\tif (numIPFilters == MAX_IPFILTERS)\n\t\t{\n\t\t\tG_Printf (\"IP filter list is full\\n\");\n\t\t\treturn;\n\t\t}\n\t\tnumIPFilters++;\n\t}\n\t\n\tif (!StringToFilter (str, &ipFilters[i]))\n\t\tipFilters[i].compare = 0xffffffffu;\n\n\tUpdateIPBans();\n}\n\n/*\n=================\nG_ProcessIPBans\n=================\n*/\nvoid G_ProcessIPBans(void) \n{\n\tchar *s, *t;\n\tchar\t\tstr[MAX_CVAR_VALUE_STRING];\n\n\tQ_strncpyz( str, g_banIPs.string, sizeof(str) );\n\n\tfor (t = s = g_banIPs.string; *t; /* */ ) {\n\t\ts = strchr(s, ' ');\n\t\tif (!s)\n\t\t\tbreak;\n\t\twhile (*s == ' ')\n\t\t\t*s++ = 0;\n\t\tif (*t)\n\t\t\tAddIP( t );\n\t\tt = s;\n\t}\n}\n\n\n/*\n=================\nSvcmd_AddIP_f\n=================\n*/\nvoid Svcmd_AddIP_f (void)\n{\n\tchar\t\tstr[MAX_TOKEN_CHARS];\n\n\tif ( trap_Argc() < 2 ) {\n\t\tG_Printf(\"Usage:  addip <ip-mask>\\n\");\n\t\treturn;\n\t}\n\n\ttrap_Argv( 1, str, sizeof( str ) );\n\n\tAddIP( str );\n\n}\n\n/*\n=================\nSvcmd_RemoveIP_f\n=================\n*/\nvoid Svcmd_RemoveIP_f (void)\n{\n\tipFilter_t\tf;\n\tint\t\t\ti;\n\tchar\t\tstr[MAX_TOKEN_CHARS];\n\n\tif ( trap_Argc() < 2 ) {\n\t\tG_Printf(\"Usage:  sv removeip <ip-mask>\\n\");\n\t\treturn;\n\t}\n\n\ttrap_Argv( 1, str, sizeof( str ) );\n\n\tif (!StringToFilter (str, &f))\n\t\treturn;\n\n\tfor (i=0 ; i<numIPFilters ; i++) {\n\t\tif (ipFilters[i].mask == f.mask\t&&\n\t\t\tipFilters[i].compare == f.compare) {\n\t\t\tipFilters[i].compare = 0xffffffffu;\n\t\t\tG_Printf (\"Removed.\\n\");\n\n\t\t\tUpdateIPBans();\n\t\t\treturn;\n\t\t}\n\t}\n\n\tG_Printf ( \"Didn't find %s.\\n\", str );\n}\n\n/*\n===================\nSvcmd_EntityList_f\n===================\n*/\nvoid\tSvcmd_EntityList_f (void) {\n\tint\t\t\te;\n\tgentity_t\t\t*check;\n\n\tcheck = g_entities+1;\n\tfor (e = 1; e < level.num_entities ; e++, check++) {\n\t\tif ( !check->inuse ) {\n\t\t\tcontinue;\n\t\t}\n\t\tG_Printf(\"%3i:\", e);\n\t\tswitch ( check->s.eType ) {\n\t\tcase ET_GENERAL:\n\t\t\tG_Printf(\"ET_GENERAL          \");\n\t\t\tbreak;\n\t\tcase ET_PLAYER:\n\t\t\tG_Printf(\"ET_PLAYER           \");\n\t\t\tbreak;\n\t\tcase ET_ITEM:\n\t\t\tG_Printf(\"ET_ITEM             \");\n\t\t\tbreak;\n\t\tcase ET_MISSILE:\n\t\t\tG_Printf(\"ET_MISSILE          \");\n\t\t\tbreak;\n\t\tcase ET_MOVER:\n\t\t\tG_Printf(\"ET_MOVER            \");\n\t\t\tbreak;\n\t\tcase ET_BEAM:\n\t\t\tG_Printf(\"ET_BEAM             \");\n\t\t\tbreak;\n\t\tcase ET_PORTAL:\n\t\t\tG_Printf(\"ET_PORTAL           \");\n\t\t\tbreak;\n\t\tcase ET_SPEAKER:\n\t\t\tG_Printf(\"ET_SPEAKER          \");\n\t\t\tbreak;\n\t\tcase ET_PUSH_TRIGGER:\n\t\t\tG_Printf(\"ET_PUSH_TRIGGER     \");\n\t\t\tbreak;\n\t\tcase ET_TELEPORT_TRIGGER:\n\t\t\tG_Printf(\"ET_TELEPORT_TRIGGER \");\n\t\t\tbreak;\n\t\tcase ET_INVISIBLE:\n\t\t\tG_Printf(\"ET_INVISIBLE        \");\n\t\t\tbreak;\n\t\tcase ET_GRAPPLE:\n\t\t\tG_Printf(\"ET_GRAPPLE          \");\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tG_Printf(\"%3i                 \", check->s.eType);\n\t\t\tbreak;\n\t\t}\n\n\t\tif ( check->classname ) {\n\t\t\tG_Printf(\"%s\", check->classname);\n\t\t}\n\t\tG_Printf(\"\\n\");\n\t}\n}\n\ngclient_t\t*ClientForString( const char *s ) {\n\tgclient_t\t*cl;\n\tint\t\t\ti;\n\tint\t\t\tidnum;\n\n\t// numeric values are just slot numbers\n\tif ( s[0] >= '0' && s[0] <= '9' ) {\n\t\tidnum = atoi( s );\n\t\tif ( idnum < 0 || idnum >= level.maxclients ) {\n\t\t\tCom_Printf( \"Bad client slot: %i\\n\", idnum );\n\t\t\treturn NULL;\n\t\t}\n\n\t\tcl = &level.clients[idnum];\n\t\tif ( cl->pers.connected == CON_DISCONNECTED ) {\n\t\t\tG_Printf( \"Client %i is not connected\\n\", idnum );\n\t\t\treturn NULL;\n\t\t}\n\t\treturn cl;\n\t}\n\n\t// check for a name match\n\tfor ( i=0 ; i < level.maxclients ; i++ ) {\n\t\tcl = &level.clients[i];\n\t\tif ( cl->pers.connected == CON_DISCONNECTED ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( !Q_stricmp( cl->pers.netname, s ) ) {\n\t\t\treturn cl;\n\t\t}\n\t}\n\n\tG_Printf( \"User %s is not on the server\\n\", s );\n\n\treturn NULL;\n}\n\n/*\n===================\nSvcmd_ForceTeam_f\n\nforceteam <player> <team>\n===================\n*/\nvoid\tSvcmd_ForceTeam_f( void ) {\n\tgclient_t\t*cl;\n\tchar\t\tstr[MAX_TOKEN_CHARS];\n\n\t// find the player\n\ttrap_Argv( 1, str, sizeof( str ) );\n\tcl = ClientForString( str );\n\tif ( !cl ) {\n\t\treturn;\n\t}\n\n\t// set the team\n\ttrap_Argv( 2, str, sizeof( str ) );\n\tSetTeam( &g_entities[cl - level.clients], str );\n}\n\nchar\t*ConcatArgs( int start );\n\n/*\n=================\nConsoleCommand\n\n=================\n*/\nqboolean\tConsoleCommand( void ) {\n\tchar\tcmd[MAX_TOKEN_CHARS];\n\n\ttrap_Argv( 0, cmd, sizeof( cmd ) );\n\n\tif ( Q_stricmp (cmd, \"entitylist\") == 0 ) {\n\t\tSvcmd_EntityList_f();\n\t\treturn qtrue;\n\t}\n\n\tif ( Q_stricmp (cmd, \"forceteam\") == 0 ) {\n\t\tSvcmd_ForceTeam_f();\n\t\treturn qtrue;\n\t}\n\n\tif (Q_stricmp (cmd, \"game_memory\") == 0) {\n\t\tSvcmd_GameMem_f();\n\t\treturn qtrue;\n\t}\n\n\tif (Q_stricmp (cmd, \"addbot\") == 0) {\n\t\tSvcmd_AddBot_f();\n\t\treturn qtrue;\n\t}\n\n\tif (Q_stricmp (cmd, \"botlist\") == 0) {\n\t\tSvcmd_BotList_f();\n\t\treturn qtrue;\n\t}\n\n\tif (Q_stricmp (cmd, \"abort_podium\") == 0) {\n\t\tSvcmd_AbortPodium_f();\n\t\treturn qtrue;\n\t}\n\n\tif (Q_stricmp (cmd, \"addip\") == 0) {\n\t\tSvcmd_AddIP_f();\n\t\treturn qtrue;\n\t}\n\n\tif (Q_stricmp (cmd, \"removeip\") == 0) {\n\t\tSvcmd_RemoveIP_f();\n\t\treturn qtrue;\n\t}\n\n\tif (Q_stricmp (cmd, \"listip\") == 0) {\n\t\ttrap_SendConsoleCommand( EXEC_NOW, \"g_banIPs\\n\" );\n\t\treturn qtrue;\n\t}\n\n\tif (g_dedicated.integer) {\n\t\tif (Q_stricmp (cmd, \"say\") == 0) {\n\t\t\ttrap_SendServerCommand( -1, va(\"print \\\"server: %s\\\"\", ConcatArgs(1) ) );\n\t\t\treturn qtrue;\n\t\t}\n\t\t// everything else will also be printed as a say command\n\t\ttrap_SendServerCommand( -1, va(\"print \\\"server: %s\\\"\", ConcatArgs(0) ) );\n\t\treturn qtrue;\n\t}\n\n\treturn qfalse;\n}\n\n"
  },
  {
    "path": "src/game/g_syscalls.asm",
    "content": "code\n\nequ\ttrap_Printf\t\t\t\t-1\nequ\ttrap_Error\t\t\t\t-2\nequ\ttrap_Milliseconds\t\t-3\nequ\ttrap_Cvar_Register\t\t-4\nequ\ttrap_Cvar_Update\t\t-5\nequ\ttrap_Cvar_Set\t\t\t-6\nequ\ttrap_Cvar_VariableIntegerValue\t-7\nequ\ttrap_Cvar_VariableStringBuffer\t-8\nequ\ttrap_Argc\t\t\t\t-9\nequ\ttrap_Argv\t\t\t\t-10\nequ\ttrap_FS_FOpenFile\t\t-11\nequ\ttrap_FS_Read\t\t\t-12\nequ\ttrap_FS_Write\t\t\t-13\nequ\ttrap_FS_FCloseFile\t\t-14\nequ\ttrap_SendConsoleCommand\t-15\nequ\ttrap_LocateGameData\t\t-16\nequ\ttrap_DropClient\t\t\t-17\nequ\ttrap_SendServerCommand\t-18\nequ\ttrap_SetConfigstring\t-19\nequ\ttrap_GetConfigstring\t-20\nequ\ttrap_GetUserinfo\t\t-21\nequ\ttrap_SetUserinfo\t\t-22\nequ\ttrap_GetServerinfo\t\t-23\nequ\ttrap_SetBrushModel\t\t-24\nequ\ttrap_Trace\t\t\t\t-25\nequ\ttrap_PointContents\t\t-26\nequ trap_InPVS\t\t\t\t-27\nequ\ttrap_InPVSIgnorePortals\t-28\nequ\ttrap_AdjustAreaPortalState\t-29\nequ\ttrap_AreasConnected\t\t-30\nequ\ttrap_LinkEntity\t\t\t-31\nequ\ttrap_UnlinkEntity\t\t-32\nequ\ttrap_EntitiesInBox\t\t-33\nequ\ttrap_EntityContact\t\t-34\nequ\ttrap_BotAllocateClient\t-35\nequ\ttrap_BotFreeClient\t\t-36\nequ\ttrap_GetUsercmd\t\t\t-37\nequ\ttrap_GetEntityToken\t\t-38\nequ\ttrap_FS_GetFileList\t\t-39\nequ trap_DebugPolygonCreate\t-40\nequ trap_DebugPolygonDelete\t-41\nequ trap_RealTime\t\t\t-42\nequ trap_SnapVector\t\t\t-43\nequ trap_TraceCapsule\t\t-44\nequ trap_EntityContactCapsule\t-45\nequ trap_FS_Seek -46\n\nequ\tmemset\t\t\t\t\t-101\nequ\tmemcpy\t\t\t\t\t-102\nequ\tstrncpy\t\t\t\t\t-103\nequ\tsin\t\t\t\t\t\t-104\nequ\tcos\t\t\t\t\t\t-105\nequ\tatan2\t\t\t\t\t-106\nequ\tsqrt\t\t\t\t\t-107\nequ floor\t\t\t\t\t-111\nequ\tceil\t\t\t\t\t-112\nequ\ttestPrintInt\t\t\t-113\nequ\ttestPrintFloat\t\t\t-114\n\n\n\nequ trap_BotLibSetup\t\t\t\t\t-201\nequ trap_BotLibShutdown\t\t\t\t\t-202\nequ trap_BotLibVarSet\t\t\t\t\t-203\nequ trap_BotLibVarGet\t\t\t\t\t-204\nequ trap_BotLibDefine\t\t\t\t\t-205\nequ trap_BotLibStartFrame\t\t\t\t-206\nequ trap_BotLibLoadMap\t\t\t\t\t-207\nequ trap_BotLibUpdateEntity\t\t\t\t-208\nequ trap_BotLibTest\t\t\t\t\t\t-209\n\nequ trap_BotGetSnapshotEntity\t\t\t-210\nequ trap_BotGetServerCommand\t\t-211\nequ trap_BotUserCommand\t\t\t\t\t-212\n\n\n\nequ trap_AAS_EnableRoutingArea\t\t-301\nequ trap_AAS_BBoxAreas\t\t\t\t-302\nequ trap_AAS_AreaInfo\t\t\t\t-303\nequ trap_AAS_EntityInfo\t\t\t\t\t-304\n\nequ trap_AAS_Initialized\t\t\t\t-305\nequ trap_AAS_PresenceTypeBoundingBox\t-306\nequ trap_AAS_Time\t\t\t\t\t\t-307\n\nequ trap_AAS_PointAreaNum\t\t\t\t-308\nequ trap_AAS_TraceAreas\t\t\t\t\t-309\n\nequ trap_AAS_PointContents\t\t\t\t-310\nequ trap_AAS_NextBSPEntity\t\t\t\t-311\nequ trap_AAS_ValueForBSPEpairKey\t\t-312\nequ trap_AAS_VectorForBSPEpairKey\t\t-313\nequ trap_AAS_FloatForBSPEpairKey\t\t-314\nequ trap_AAS_IntForBSPEpairKey\t\t\t-315\n\nequ trap_AAS_AreaReachability\t\t\t-316\n\nequ trap_AAS_AreaTravelTimeToGoalArea\t-317\n\nequ trap_AAS_Swimming\t\t\t\t\t-318\nequ trap_AAS_PredictClientMovement\t\t-319\n\n\n\nequ trap_EA_Say\t\t\t\t\t\t\t-401\nequ trap_EA_SayTeam\t\t\t\t\t\t-402\nequ trap_EA_Command\t\t\t\t\t\t-403\n\nequ trap_EA_Action\t\t\t\t\t\t-404\nequ trap_EA_Gesture\t\t\t\t\t\t-405\nequ trap_EA_Talk\t\t\t\t\t\t-406\nequ trap_EA_Attack\t\t\t\t\t\t-407\nequ trap_EA_Use\t\t\t\t\t\t\t-408\nequ trap_EA_Respawn\t\t\t\t\t\t-409\nequ trap_EA_Crouch\t\t\t\t\t\t-410\nequ trap_EA_MoveUp\t\t\t\t\t\t-411\nequ trap_EA_MoveDown\t\t\t\t\t-412\nequ trap_EA_MoveForward\t\t\t\t\t-413\nequ trap_EA_MoveBack\t\t\t\t\t-414\nequ trap_EA_MoveLeft\t\t\t\t\t-415\nequ trap_EA_MoveRight\t\t\t\t\t-416\n\nequ trap_EA_SelectWeapon\t\t\t\t-417\nequ trap_EA_Jump\t\t\t\t\t\t-418\nequ trap_EA_DelayedJump\t\t\t\t\t-419\nequ trap_EA_Move\t\t\t\t\t\t-420\nequ trap_EA_View\t\t\t\t\t\t-421\n\nequ trap_EA_EndRegular\t\t\t\t\t-422\nequ trap_EA_GetInput\t\t\t\t\t-423\nequ trap_EA_ResetInput\t\t\t\t\t-424\n\n\n\nequ trap_BotLoadCharacter\t\t\t\t-501\nequ trap_BotFreeCharacter\t\t\t\t-502\nequ trap_Characteristic_Float\t\t\t-503\nequ trap_Characteristic_BFloat\t\t\t-504\nequ trap_Characteristic_Integer\t\t\t-505\nequ trap_Characteristic_BInteger\t\t-506\nequ trap_Characteristic_String\t\t\t-507\n\nequ trap_BotAllocChatState\t\t\t\t-508\nequ trap_BotFreeChatState\t\t\t\t-509\nequ trap_BotQueueConsoleMessage\t\t\t-510\nequ trap_BotRemoveConsoleMessage\t\t-511\nequ trap_BotNextConsoleMessage\t\t\t-512\nequ trap_BotNumConsoleMessages\t\t\t-513\nequ trap_BotInitialChat\t\t\t\t\t-514\nequ trap_BotReplyChat\t\t\t\t\t-515\nequ trap_BotChatLength\t\t\t\t\t-516\nequ trap_BotEnterChat\t\t\t\t\t-517\nequ trap_StringContains\t\t\t\t\t-518\nequ trap_BotFindMatch\t\t\t\t\t-519\nequ trap_BotMatchVariable\t\t\t\t-520\nequ trap_UnifyWhiteSpaces\t\t\t\t-521\nequ trap_BotReplaceSynonyms\t\t\t\t-522\nequ trap_BotLoadChatFile\t\t\t\t-523\nequ trap_BotSetChatGender\t\t\t\t-524\nequ trap_BotSetChatName\t\t\t\t\t-525\n\nequ trap_BotResetGoalState\t\t\t\t-526\nequ trap_BotResetAvoidGoals\t\t\t\t-527\nequ trap_BotPushGoal\t\t\t\t\t-528\nequ trap_BotPopGoal\t\t\t\t\t\t-529\nequ trap_BotEmptyGoalStack\t\t\t\t-530\nequ trap_BotDumpAvoidGoals\t\t\t\t-531\nequ trap_BotDumpGoalStack\t\t\t\t-532\nequ trap_BotGoalName\t\t\t\t\t-533\nequ trap_BotGetTopGoal\t\t\t\t\t-534\nequ trap_BotGetSecondGoal\t\t\t\t-535\nequ trap_BotChooseLTGItem\t\t\t\t-536\nequ trap_BotChooseNBGItem\t\t\t\t-537\nequ trap_BotTouchingGoal\t\t\t\t-538\nequ trap_BotItemGoalInVisButNotVisible\t-539\nequ trap_BotGetLevelItemGoal\t\t\t-540\nequ trap_BotAvoidGoalTime\t\t\t\t-541\nequ trap_BotInitLevelItems\t\t\t\t-542\nequ trap_BotUpdateEntityItems\t\t\t-543\nequ trap_BotLoadItemWeights\t\t\t\t-544\nequ trap_BotFreeItemWeights\t\t\t\t-546\nequ trap_BotSaveGoalFuzzyLogic\t\t\t-546\nequ trap_BotAllocGoalState\t\t\t\t-547\nequ trap_BotFreeGoalState\t\t\t\t-548\n\nequ trap_BotResetMoveState\t\t\t\t-549\nequ trap_BotMoveToGoal\t\t\t\t\t-550\nequ trap_BotMoveInDirection\t\t\t\t-551\nequ trap_BotResetAvoidReach\t\t\t\t-552\nequ trap_BotResetLastAvoidReach\t\t\t-553\nequ trap_BotReachabilityArea\t\t\t-554\nequ trap_BotMovementViewTarget\t\t\t-555\nequ trap_BotAllocMoveState\t\t\t\t-556\nequ trap_BotFreeMoveState\t\t\t\t-557\nequ trap_BotInitMoveState\t\t\t\t-558\n\nequ trap_BotChooseBestFightWeapon\t\t-559\nequ trap_BotGetWeaponInfo\t\t\t\t-560\nequ trap_BotLoadWeaponWeights\t\t\t-561\nequ trap_BotAllocWeaponState\t\t\t-562\nequ trap_BotFreeWeaponState\t\t\t\t-563\nequ trap_BotResetWeaponState\t\t\t-564\nequ trap_GeneticParentsAndChildSelection -565\nequ trap_BotInterbreedGoalFuzzyLogic\t-566\nequ trap_BotMutateGoalFuzzyLogic\t\t-567\nequ trap_BotGetNextCampSpotGoal\t\t\t-568\nequ trap_BotGetMapLocationGoal\t\t\t-569\nequ trap_BotNumInitialChats\t\t\t\t-570\nequ trap_BotGetChatMessage\t\t\t\t-571\nequ trap_BotRemoveFromAvoidGoals\t\t-572\nequ trap_BotPredictVisiblePosition\t\t-573\nequ trap_BotSetAvoidGoalTime\t\t\t-574\nequ trap_BotAddAvoidSpot\t\t\t\t-575\nequ trap_AAS_AlternativeRouteGoals\t\t-576\nequ trap_AAS_PredictRoute\t\t\t\t-577\nequ trap_AAS_PointReachabilityAreaIndex\t-578\n\nequ trap_BotLibLoadSource\t\t\t\t-579\nequ trap_BotLibFreeSource\t\t\t\t-580\nequ trap_BotLibReadToken\t\t\t\t-581\nequ trap_BotLibSourceFileAndLine\t\t-582\n \n"
  },
  {
    "path": "src/game/g_syscalls.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n#include \"g_local.h\"\n\n// this file is only included when building a dll\n// g_syscalls.asm is included instead when building a qvm\n#ifdef Q3_VM\n#error \"Do not use in VM build\"\n#endif\n\nstatic intptr_t (QDECL *syscall)( intptr_t arg, ... ) = (intptr_t (QDECL *)( intptr_t, ...))-1;\n\n\nvoid dllEntry( intptr_t (QDECL *syscallptr)( intptr_t arg,... ) ) {\n\tsyscall = syscallptr;\n}\n\nint PASSFLOAT( float x ) {\n\tfloat\tfloatTemp;\n\tfloatTemp = x;\n\treturn *(int *)&floatTemp;\n}\n\nvoid\ttrap_Printf( const char *fmt ) {\n\tsyscall( G_PRINT, fmt );\n}\n\nvoid\ttrap_Error( const char *fmt ) {\n\tsyscall( G_ERROR, fmt );\n}\n\nint\t\ttrap_Milliseconds( void ) {\n\treturn syscall( G_MILLISECONDS ); \n}\nint\t\ttrap_Argc( void ) {\n\treturn syscall( G_ARGC );\n}\n\nvoid\ttrap_Argv( int n, char *buffer, int bufferLength ) {\n\tsyscall( G_ARGV, n, buffer, bufferLength );\n}\n\nint\t\ttrap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode ) {\n\treturn syscall( G_FS_FOPEN_FILE, qpath, f, mode );\n}\n\nvoid\ttrap_FS_Read( void *buffer, int len, fileHandle_t f ) {\n\tsyscall( G_FS_READ, buffer, len, f );\n}\n\nvoid\ttrap_FS_Write( const void *buffer, int len, fileHandle_t f ) {\n\tsyscall( G_FS_WRITE, buffer, len, f );\n}\n\nvoid\ttrap_FS_FCloseFile( fileHandle_t f ) {\n\tsyscall( G_FS_FCLOSE_FILE, f );\n}\n\nint trap_FS_GetFileList(  const char *path, const char *extension, char *listbuf, int bufsize ) {\n\treturn syscall( G_FS_GETFILELIST, path, extension, listbuf, bufsize );\n}\n\nint trap_FS_Seek( fileHandle_t f, long offset, int origin ) {\n\treturn syscall( G_FS_SEEK, f, offset, origin );\n}\n\nvoid\ttrap_SendConsoleCommand( int exec_when, const char *text ) {\n\tsyscall( G_SEND_CONSOLE_COMMAND, exec_when, text );\n}\n\nvoid\ttrap_Cvar_Register( vmCvar_t *cvar, const char *var_name, const char *value, int flags ) {\n\tsyscall( G_CVAR_REGISTER, cvar, var_name, value, flags );\n}\n\nvoid\ttrap_Cvar_Update( vmCvar_t *cvar ) {\n\tsyscall( G_CVAR_UPDATE, cvar );\n}\n\nvoid trap_Cvar_Set( const char *var_name, const char *value ) {\n\tsyscall( G_CVAR_SET, var_name, value );\n}\n\nint trap_Cvar_VariableIntegerValue( const char *var_name ) {\n\treturn syscall( G_CVAR_VARIABLE_INTEGER_VALUE, var_name );\n}\n\nvoid trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize ) {\n\tsyscall( G_CVAR_VARIABLE_STRING_BUFFER, var_name, buffer, bufsize );\n}\n\n\nvoid trap_LocateGameData( gentity_t *gEnts, int numGEntities, int sizeofGEntity_t,\n\t\t\t\t\t\t playerState_t *clients, int sizeofGClient ) {\n\tsyscall( G_LOCATE_GAME_DATA, gEnts, numGEntities, sizeofGEntity_t, clients, sizeofGClient );\n}\n\nvoid trap_DropClient( int clientNum, const char *reason ) {\n\tsyscall( G_DROP_CLIENT, clientNum, reason );\n}\n\nvoid trap_SendServerCommand( int clientNum, const char *text ) {\n\tsyscall( G_SEND_SERVER_COMMAND, clientNum, text );\n}\n\nvoid trap_SetConfigstring( int num, const char *string ) {\n\tsyscall( G_SET_CONFIGSTRING, num, string );\n}\n\nvoid trap_GetConfigstring( int num, char *buffer, int bufferSize ) {\n\tsyscall( G_GET_CONFIGSTRING, num, buffer, bufferSize );\n}\n\nvoid trap_GetUserinfo( int num, char *buffer, int bufferSize ) {\n\tsyscall( G_GET_USERINFO, num, buffer, bufferSize );\n}\n\nvoid trap_SetUserinfo( int num, const char *buffer ) {\n\tsyscall( G_SET_USERINFO, num, buffer );\n}\n\nvoid trap_GetServerinfo( char *buffer, int bufferSize ) {\n\tsyscall( G_GET_SERVERINFO, buffer, bufferSize );\n}\n\nvoid trap_SetBrushModel( gentity_t *ent, const char *name ) {\n\tsyscall( G_SET_BRUSH_MODEL, ent, name );\n}\n\nvoid trap_Trace( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentmask ) {\n\tsyscall( G_TRACE, results, start, mins, maxs, end, passEntityNum, contentmask );\n}\n\nvoid trap_TraceCapsule( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentmask ) {\n\tsyscall( G_TRACECAPSULE, results, start, mins, maxs, end, passEntityNum, contentmask );\n}\n\nint trap_PointContents( const vec3_t point, int passEntityNum ) {\n\treturn syscall( G_POINT_CONTENTS, point, passEntityNum );\n}\n\n\nqboolean trap_InPVS( const vec3_t p1, const vec3_t p2 ) {\n\treturn syscall( G_IN_PVS, p1, p2 );\n}\n\nqboolean trap_InPVSIgnorePortals( const vec3_t p1, const vec3_t p2 ) {\n\treturn syscall( G_IN_PVS_IGNORE_PORTALS, p1, p2 );\n}\n\nvoid trap_AdjustAreaPortalState( gentity_t *ent, qboolean open ) {\n\tsyscall( G_ADJUST_AREA_PORTAL_STATE, ent, open );\n}\n\nqboolean trap_AreasConnected( int area1, int area2 ) {\n\treturn syscall( G_AREAS_CONNECTED, area1, area2 );\n}\n\nvoid trap_LinkEntity( gentity_t *ent ) {\n\tsyscall( G_LINKENTITY, ent );\n}\n\nvoid trap_UnlinkEntity( gentity_t *ent ) {\n\tsyscall( G_UNLINKENTITY, ent );\n}\n\nint trap_EntitiesInBox( const vec3_t mins, const vec3_t maxs, int *list, int maxcount ) {\n\treturn syscall( G_ENTITIES_IN_BOX, mins, maxs, list, maxcount );\n}\n\nqboolean trap_EntityContact( const vec3_t mins, const vec3_t maxs, const gentity_t *ent ) {\n\treturn syscall( G_ENTITY_CONTACT, mins, maxs, ent );\n}\n\nqboolean trap_EntityContactCapsule( const vec3_t mins, const vec3_t maxs, const gentity_t *ent ) {\n\treturn syscall( G_ENTITY_CONTACTCAPSULE, mins, maxs, ent );\n}\n\nint trap_BotAllocateClient( void ) {\n\treturn syscall( G_BOT_ALLOCATE_CLIENT );\n}\n\nvoid trap_BotFreeClient( int clientNum ) {\n\tsyscall( G_BOT_FREE_CLIENT, clientNum );\n}\n\nvoid trap_GetUsercmd( int clientNum, usercmd_t *cmd ) {\n\tsyscall( G_GET_USERCMD, clientNum, cmd );\n}\n\nqboolean trap_GetEntityToken( char *buffer, int bufferSize ) {\n\treturn syscall( G_GET_ENTITY_TOKEN, buffer, bufferSize );\n}\n\nint trap_DebugPolygonCreate(int color, int numPoints, vec3_t *points) {\n\treturn syscall( G_DEBUG_POLYGON_CREATE, color, numPoints, points );\n}\n\nvoid trap_DebugPolygonDelete(int id) {\n\tsyscall( G_DEBUG_POLYGON_DELETE, id );\n}\n\nint trap_RealTime( qtime_t *qtime ) {\n\treturn syscall( G_REAL_TIME, qtime );\n}\n\nvoid trap_SnapVector( float *v ) {\n\tsyscall( G_SNAPVECTOR, v );\n\treturn;\n}\n\n// BotLib traps start here\nint trap_BotLibSetup( void ) {\n\treturn syscall( BOTLIB_SETUP );\n}\n\nint trap_BotLibShutdown( void ) {\n\treturn syscall( BOTLIB_SHUTDOWN );\n}\n\nint trap_BotLibVarSet(char *var_name, char *value) {\n\treturn syscall( BOTLIB_LIBVAR_SET, var_name, value );\n}\n\nint trap_BotLibVarGet(char *var_name, char *value, int size) {\n\treturn syscall( BOTLIB_LIBVAR_GET, var_name, value, size );\n}\n\nint trap_BotLibDefine(char *string) {\n\treturn syscall( BOTLIB_PC_ADD_GLOBAL_DEFINE, string );\n}\n\nint trap_BotLibStartFrame(float time) {\n\treturn syscall( BOTLIB_START_FRAME, PASSFLOAT( time ) );\n}\n\nint trap_BotLibLoadMap(const char *mapname) {\n\treturn syscall( BOTLIB_LOAD_MAP, mapname );\n}\n\nint trap_BotLibUpdateEntity(int ent, void /* struct bot_updateentity_s */ *bue) {\n\treturn syscall( BOTLIB_UPDATENTITY, ent, bue );\n}\n\nint trap_BotLibTest(int parm0, char *parm1, vec3_t parm2, vec3_t parm3) {\n\treturn syscall( BOTLIB_TEST, parm0, parm1, parm2, parm3 );\n}\n\nint trap_BotGetSnapshotEntity( int clientNum, int sequence ) {\n\treturn syscall( BOTLIB_GET_SNAPSHOT_ENTITY, clientNum, sequence );\n}\n\nint trap_BotGetServerCommand(int clientNum, char *message, int size) {\n\treturn syscall( BOTLIB_GET_CONSOLE_MESSAGE, clientNum, message, size );\n}\n\nvoid trap_BotUserCommand(int clientNum, usercmd_t *ucmd) {\n\tsyscall( BOTLIB_USER_COMMAND, clientNum, ucmd );\n}\n\nvoid trap_AAS_EntityInfo(int entnum, void /* struct aas_entityinfo_s */ *info) {\n\tsyscall( BOTLIB_AAS_ENTITY_INFO, entnum, info );\n}\n\nint trap_AAS_Initialized(void) {\n\treturn syscall( BOTLIB_AAS_INITIALIZED );\n}\n\nvoid trap_AAS_PresenceTypeBoundingBox(int presencetype, vec3_t mins, vec3_t maxs) {\n\tsyscall( BOTLIB_AAS_PRESENCE_TYPE_BOUNDING_BOX, presencetype, mins, maxs );\n}\n\nfloat trap_AAS_Time(void) {\n\tint temp;\n\ttemp = syscall( BOTLIB_AAS_TIME );\n\treturn (*(float*)&temp);\n}\n\nint trap_AAS_PointAreaNum(vec3_t point) {\n\treturn syscall( BOTLIB_AAS_POINT_AREA_NUM, point );\n}\n\nint trap_AAS_PointReachabilityAreaIndex(vec3_t point) {\n\treturn syscall( BOTLIB_AAS_POINT_REACHABILITY_AREA_INDEX, point );\n}\n\nint trap_AAS_TraceAreas(vec3_t start, vec3_t end, int *areas, vec3_t *points, int maxareas) {\n\treturn syscall( BOTLIB_AAS_TRACE_AREAS, start, end, areas, points, maxareas );\n}\n\nint trap_AAS_BBoxAreas(vec3_t absmins, vec3_t absmaxs, int *areas, int maxareas) {\n\treturn syscall( BOTLIB_AAS_BBOX_AREAS, absmins, absmaxs, areas, maxareas );\n}\n\nint trap_AAS_AreaInfo( int areanum, void /* struct aas_areainfo_s */ *info ) {\n\treturn syscall( BOTLIB_AAS_AREA_INFO, areanum, info );\n}\n\nint trap_AAS_PointContents(vec3_t point) {\n\treturn syscall( BOTLIB_AAS_POINT_CONTENTS, point );\n}\n\nint trap_AAS_NextBSPEntity(int ent) {\n\treturn syscall( BOTLIB_AAS_NEXT_BSP_ENTITY, ent );\n}\n\nint trap_AAS_ValueForBSPEpairKey(int ent, char *key, char *value, int size) {\n\treturn syscall( BOTLIB_AAS_VALUE_FOR_BSP_EPAIR_KEY, ent, key, value, size );\n}\n\nint trap_AAS_VectorForBSPEpairKey(int ent, char *key, vec3_t v) {\n\treturn syscall( BOTLIB_AAS_VECTOR_FOR_BSP_EPAIR_KEY, ent, key, v );\n}\n\nint trap_AAS_FloatForBSPEpairKey(int ent, char *key, float *value) {\n\treturn syscall( BOTLIB_AAS_FLOAT_FOR_BSP_EPAIR_KEY, ent, key, value );\n}\n\nint trap_AAS_IntForBSPEpairKey(int ent, char *key, int *value) {\n\treturn syscall( BOTLIB_AAS_INT_FOR_BSP_EPAIR_KEY, ent, key, value );\n}\n\nint trap_AAS_AreaReachability(int areanum) {\n\treturn syscall( BOTLIB_AAS_AREA_REACHABILITY, areanum );\n}\n\nint trap_AAS_AreaTravelTimeToGoalArea(int areanum, vec3_t origin, int goalareanum, int travelflags) {\n\treturn syscall( BOTLIB_AAS_AREA_TRAVEL_TIME_TO_GOAL_AREA, areanum, origin, goalareanum, travelflags );\n}\n\nint trap_AAS_EnableRoutingArea( int areanum, int enable ) {\n\treturn syscall( BOTLIB_AAS_ENABLE_ROUTING_AREA, areanum, enable );\n}\n\nint trap_AAS_PredictRoute(void /*struct aas_predictroute_s*/ *route, int areanum, vec3_t origin,\n\t\t\t\t\t\t\tint goalareanum, int travelflags, int maxareas, int maxtime,\n\t\t\t\t\t\t\tint stopevent, int stopcontents, int stoptfl, int stopareanum) {\n\treturn syscall( BOTLIB_AAS_PREDICT_ROUTE, route, areanum, origin, goalareanum, travelflags, maxareas, maxtime, stopevent, stopcontents, stoptfl, stopareanum );\n}\n\nint trap_AAS_AlternativeRouteGoals(vec3_t start, int startareanum, vec3_t goal, int goalareanum, int travelflags,\n\t\t\t\t\t\t\t\t\t\tvoid /*struct aas_altroutegoal_s*/ *altroutegoals, int maxaltroutegoals,\n\t\t\t\t\t\t\t\t\t\tint type) {\n\treturn syscall( BOTLIB_AAS_ALTERNATIVE_ROUTE_GOAL, start, startareanum, goal, goalareanum, travelflags, altroutegoals, maxaltroutegoals, type );\n}\n\nint trap_AAS_Swimming(vec3_t origin) {\n\treturn syscall( BOTLIB_AAS_SWIMMING, origin );\n}\n\nint trap_AAS_PredictClientMovement(void /* struct aas_clientmove_s */ *move, int entnum, vec3_t origin, int presencetype, int onground, vec3_t velocity, vec3_t cmdmove, int cmdframes, int maxframes, float frametime, int stopevent, int stopareanum, int visualize) {\n\treturn syscall( BOTLIB_AAS_PREDICT_CLIENT_MOVEMENT, move, entnum, origin, presencetype, onground, velocity, cmdmove, cmdframes, maxframes, PASSFLOAT(frametime), stopevent, stopareanum, visualize );\n}\n\nvoid trap_EA_Say(int client, char *str) {\n\tsyscall( BOTLIB_EA_SAY, client, str );\n}\n\nvoid trap_EA_SayTeam(int client, char *str) {\n\tsyscall( BOTLIB_EA_SAY_TEAM, client, str );\n}\n\nvoid trap_EA_Command(int client, char *command) {\n\tsyscall( BOTLIB_EA_COMMAND, client, command );\n}\n\nvoid trap_EA_Action(int client, int action) {\n\tsyscall( BOTLIB_EA_ACTION, client, action );\n}\n\nvoid trap_EA_Gesture(int client) {\n\tsyscall( BOTLIB_EA_GESTURE, client );\n}\n\nvoid trap_EA_Talk(int client) {\n\tsyscall( BOTLIB_EA_TALK, client );\n}\n\nvoid trap_EA_Attack(int client) {\n\tsyscall( BOTLIB_EA_ATTACK, client );\n}\n\nvoid trap_EA_Use(int client) {\n\tsyscall( BOTLIB_EA_USE, client );\n}\n\nvoid trap_EA_Respawn(int client) {\n\tsyscall( BOTLIB_EA_RESPAWN, client );\n}\n\nvoid trap_EA_Crouch(int client) {\n\tsyscall( BOTLIB_EA_CROUCH, client );\n}\n\nvoid trap_EA_MoveUp(int client) {\n\tsyscall( BOTLIB_EA_MOVE_UP, client );\n}\n\nvoid trap_EA_MoveDown(int client) {\n\tsyscall( BOTLIB_EA_MOVE_DOWN, client );\n}\n\nvoid trap_EA_MoveForward(int client) {\n\tsyscall( BOTLIB_EA_MOVE_FORWARD, client );\n}\n\nvoid trap_EA_MoveBack(int client) {\n\tsyscall( BOTLIB_EA_MOVE_BACK, client );\n}\n\nvoid trap_EA_MoveLeft(int client) {\n\tsyscall( BOTLIB_EA_MOVE_LEFT, client );\n}\n\nvoid trap_EA_MoveRight(int client) {\n\tsyscall( BOTLIB_EA_MOVE_RIGHT, client );\n}\n\nvoid trap_EA_SelectWeapon(int client, int weapon) {\n\tsyscall( BOTLIB_EA_SELECT_WEAPON, client, weapon );\n}\n\nvoid trap_EA_Jump(int client) {\n\tsyscall( BOTLIB_EA_JUMP, client );\n}\n\nvoid trap_EA_DelayedJump(int client) {\n\tsyscall( BOTLIB_EA_DELAYED_JUMP, client );\n}\n\nvoid trap_EA_Move(int client, vec3_t dir, float speed) {\n\tsyscall( BOTLIB_EA_MOVE, client, dir, PASSFLOAT(speed) );\n}\n\nvoid trap_EA_View(int client, vec3_t viewangles) {\n\tsyscall( BOTLIB_EA_VIEW, client, viewangles );\n}\n\nvoid trap_EA_EndRegular(int client, float thinktime) {\n\tsyscall( BOTLIB_EA_END_REGULAR, client, PASSFLOAT(thinktime) );\n}\n\nvoid trap_EA_GetInput(int client, float thinktime, void /* struct bot_input_s */ *input) {\n\tsyscall( BOTLIB_EA_GET_INPUT, client, PASSFLOAT(thinktime), input );\n}\n\nvoid trap_EA_ResetInput(int client) {\n\tsyscall( BOTLIB_EA_RESET_INPUT, client );\n}\n\nint trap_BotLoadCharacter(char *charfile, float skill) {\n\treturn syscall( BOTLIB_AI_LOAD_CHARACTER, charfile, PASSFLOAT(skill));\n}\n\nvoid trap_BotFreeCharacter(int character) {\n\tsyscall( BOTLIB_AI_FREE_CHARACTER, character );\n}\n\nfloat trap_Characteristic_Float(int character, int index) {\n\tint temp;\n\ttemp = syscall( BOTLIB_AI_CHARACTERISTIC_FLOAT, character, index );\n\treturn (*(float*)&temp);\n}\n\nfloat trap_Characteristic_BFloat(int character, int index, float min, float max) {\n\tint temp;\n\ttemp = syscall( BOTLIB_AI_CHARACTERISTIC_BFLOAT, character, index, PASSFLOAT(min), PASSFLOAT(max) );\n\treturn (*(float*)&temp);\n}\n\nint trap_Characteristic_Integer(int character, int index) {\n\treturn syscall( BOTLIB_AI_CHARACTERISTIC_INTEGER, character, index );\n}\n\nint trap_Characteristic_BInteger(int character, int index, int min, int max) {\n\treturn syscall( BOTLIB_AI_CHARACTERISTIC_BINTEGER, character, index, min, max );\n}\n\nvoid trap_Characteristic_String(int character, int index, char *buf, int size) {\n\tsyscall( BOTLIB_AI_CHARACTERISTIC_STRING, character, index, buf, size );\n}\n\nint trap_BotAllocChatState(void) {\n\treturn syscall( BOTLIB_AI_ALLOC_CHAT_STATE );\n}\n\nvoid trap_BotFreeChatState(int handle) {\n\tsyscall( BOTLIB_AI_FREE_CHAT_STATE, handle );\n}\n\nvoid trap_BotQueueConsoleMessage(int chatstate, int type, char *message) {\n\tsyscall( BOTLIB_AI_QUEUE_CONSOLE_MESSAGE, chatstate, type, message );\n}\n\nvoid trap_BotRemoveConsoleMessage(int chatstate, int handle) {\n\tsyscall( BOTLIB_AI_REMOVE_CONSOLE_MESSAGE, chatstate, handle );\n}\n\nint trap_BotNextConsoleMessage(int chatstate, void /* struct bot_consolemessage_s */ *cm) {\n\treturn syscall( BOTLIB_AI_NEXT_CONSOLE_MESSAGE, chatstate, cm );\n}\n\nint trap_BotNumConsoleMessages(int chatstate) {\n\treturn syscall( BOTLIB_AI_NUM_CONSOLE_MESSAGE, chatstate );\n}\n\nvoid trap_BotInitialChat(int chatstate, char *type, int mcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7 ) {\n\tsyscall( BOTLIB_AI_INITIAL_CHAT, chatstate, type, mcontext, var0, var1, var2, var3, var4, var5, var6, var7 );\n}\n\nint\ttrap_BotNumInitialChats(int chatstate, char *type) {\n\treturn syscall( BOTLIB_AI_NUM_INITIAL_CHATS, chatstate, type );\n}\n\nint trap_BotReplyChat(int chatstate, char *message, int mcontext, int vcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7 ) {\n\treturn syscall( BOTLIB_AI_REPLY_CHAT, chatstate, message, mcontext, vcontext, var0, var1, var2, var3, var4, var5, var6, var7 );\n}\n\nint trap_BotChatLength(int chatstate) {\n\treturn syscall( BOTLIB_AI_CHAT_LENGTH, chatstate );\n}\n\nvoid trap_BotEnterChat(int chatstate, int client, int sendto) {\n\tsyscall( BOTLIB_AI_ENTER_CHAT, chatstate, client, sendto );\n}\n\nvoid trap_BotGetChatMessage(int chatstate, char *buf, int size) {\n\tsyscall( BOTLIB_AI_GET_CHAT_MESSAGE, chatstate, buf, size);\n}\n\nint trap_StringContains(char *str1, char *str2, int casesensitive) {\n\treturn syscall( BOTLIB_AI_STRING_CONTAINS, str1, str2, casesensitive );\n}\n\nint trap_BotFindMatch(char *str, void /* struct bot_match_s */ *match, unsigned long int context) {\n\treturn syscall( BOTLIB_AI_FIND_MATCH, str, match, context );\n}\n\nvoid trap_BotMatchVariable(void /* struct bot_match_s */ *match, int variable, char *buf, int size) {\n\tsyscall( BOTLIB_AI_MATCH_VARIABLE, match, variable, buf, size );\n}\n\nvoid trap_UnifyWhiteSpaces(char *string) {\n\tsyscall( BOTLIB_AI_UNIFY_WHITE_SPACES, string );\n}\n\nvoid trap_BotReplaceSynonyms(char *string, unsigned long int context) {\n\tsyscall( BOTLIB_AI_REPLACE_SYNONYMS, string, context );\n}\n\nint trap_BotLoadChatFile(int chatstate, char *chatfile, char *chatname) {\n\treturn syscall( BOTLIB_AI_LOAD_CHAT_FILE, chatstate, chatfile, chatname );\n}\n\nvoid trap_BotSetChatGender(int chatstate, int gender) {\n\tsyscall( BOTLIB_AI_SET_CHAT_GENDER, chatstate, gender );\n}\n\nvoid trap_BotSetChatName(int chatstate, char *name, int client) {\n\tsyscall( BOTLIB_AI_SET_CHAT_NAME, chatstate, name, client );\n}\n\nvoid trap_BotResetGoalState(int goalstate) {\n\tsyscall( BOTLIB_AI_RESET_GOAL_STATE, goalstate );\n}\n\nvoid trap_BotResetAvoidGoals(int goalstate) {\n\tsyscall( BOTLIB_AI_RESET_AVOID_GOALS, goalstate );\n}\n\nvoid trap_BotRemoveFromAvoidGoals(int goalstate, int number) {\n\tsyscall( BOTLIB_AI_REMOVE_FROM_AVOID_GOALS, goalstate, number);\n}\n\nvoid trap_BotPushGoal(int goalstate, void /* struct bot_goal_s */ *goal) {\n\tsyscall( BOTLIB_AI_PUSH_GOAL, goalstate, goal );\n}\n\nvoid trap_BotPopGoal(int goalstate) {\n\tsyscall( BOTLIB_AI_POP_GOAL, goalstate );\n}\n\nvoid trap_BotEmptyGoalStack(int goalstate) {\n\tsyscall( BOTLIB_AI_EMPTY_GOAL_STACK, goalstate );\n}\n\nvoid trap_BotDumpAvoidGoals(int goalstate) {\n\tsyscall( BOTLIB_AI_DUMP_AVOID_GOALS, goalstate );\n}\n\nvoid trap_BotDumpGoalStack(int goalstate) {\n\tsyscall( BOTLIB_AI_DUMP_GOAL_STACK, goalstate );\n}\n\nvoid trap_BotGoalName(int number, char *name, int size) {\n\tsyscall( BOTLIB_AI_GOAL_NAME, number, name, size );\n}\n\nint trap_BotGetTopGoal(int goalstate, void /* struct bot_goal_s */ *goal) {\n\treturn syscall( BOTLIB_AI_GET_TOP_GOAL, goalstate, goal );\n}\n\nint trap_BotGetSecondGoal(int goalstate, void /* struct bot_goal_s */ *goal) {\n\treturn syscall( BOTLIB_AI_GET_SECOND_GOAL, goalstate, goal );\n}\n\nint trap_BotChooseLTGItem(int goalstate, vec3_t origin, int *inventory, int travelflags) {\n\treturn syscall( BOTLIB_AI_CHOOSE_LTG_ITEM, goalstate, origin, inventory, travelflags );\n}\n\nint trap_BotChooseNBGItem(int goalstate, vec3_t origin, int *inventory, int travelflags, void /* struct bot_goal_s */ *ltg, float maxtime) {\n\treturn syscall( BOTLIB_AI_CHOOSE_NBG_ITEM, goalstate, origin, inventory, travelflags, ltg, PASSFLOAT(maxtime) );\n}\n\nint trap_BotTouchingGoal(vec3_t origin, void /* struct bot_goal_s */ *goal) {\n\treturn syscall( BOTLIB_AI_TOUCHING_GOAL, origin, goal );\n}\n\nint trap_BotItemGoalInVisButNotVisible(int viewer, vec3_t eye, vec3_t viewangles, void /* struct bot_goal_s */ *goal) {\n\treturn syscall( BOTLIB_AI_ITEM_GOAL_IN_VIS_BUT_NOT_VISIBLE, viewer, eye, viewangles, goal );\n}\n\nint trap_BotGetLevelItemGoal(int index, char *classname, void /* struct bot_goal_s */ *goal) {\n\treturn syscall( BOTLIB_AI_GET_LEVEL_ITEM_GOAL, index, classname, goal );\n}\n\nint trap_BotGetNextCampSpotGoal(int num, void /* struct bot_goal_s */ *goal) {\n\treturn syscall( BOTLIB_AI_GET_NEXT_CAMP_SPOT_GOAL, num, goal );\n}\n\nint trap_BotGetMapLocationGoal(char *name, void /* struct bot_goal_s */ *goal) {\n\treturn syscall( BOTLIB_AI_GET_MAP_LOCATION_GOAL, name, goal );\n}\n\nfloat trap_BotAvoidGoalTime(int goalstate, int number) {\n\tint temp;\n\ttemp = syscall( BOTLIB_AI_AVOID_GOAL_TIME, goalstate, number );\n\treturn (*(float*)&temp);\n}\n\nvoid trap_BotSetAvoidGoalTime(int goalstate, int number, float avoidtime) {\n\tsyscall( BOTLIB_AI_SET_AVOID_GOAL_TIME, goalstate, number, PASSFLOAT(avoidtime));\n}\n\nvoid trap_BotInitLevelItems(void) {\n\tsyscall( BOTLIB_AI_INIT_LEVEL_ITEMS );\n}\n\nvoid trap_BotUpdateEntityItems(void) {\n\tsyscall( BOTLIB_AI_UPDATE_ENTITY_ITEMS );\n}\n\nint trap_BotLoadItemWeights(int goalstate, char *filename) {\n\treturn syscall( BOTLIB_AI_LOAD_ITEM_WEIGHTS, goalstate, filename );\n}\n\nvoid trap_BotFreeItemWeights(int goalstate) {\n\tsyscall( BOTLIB_AI_FREE_ITEM_WEIGHTS, goalstate );\n}\n\nvoid trap_BotInterbreedGoalFuzzyLogic(int parent1, int parent2, int child) {\n\tsyscall( BOTLIB_AI_INTERBREED_GOAL_FUZZY_LOGIC, parent1, parent2, child );\n}\n\nvoid trap_BotSaveGoalFuzzyLogic(int goalstate, char *filename) {\n\tsyscall( BOTLIB_AI_SAVE_GOAL_FUZZY_LOGIC, goalstate, filename );\n}\n\nvoid trap_BotMutateGoalFuzzyLogic(int goalstate, float range) {\n\tsyscall( BOTLIB_AI_MUTATE_GOAL_FUZZY_LOGIC, goalstate, range );\n}\n\nint trap_BotAllocGoalState(int state) {\n\treturn syscall( BOTLIB_AI_ALLOC_GOAL_STATE, state );\n}\n\nvoid trap_BotFreeGoalState(int handle) {\n\tsyscall( BOTLIB_AI_FREE_GOAL_STATE, handle );\n}\n\nvoid trap_BotResetMoveState(int movestate) {\n\tsyscall( BOTLIB_AI_RESET_MOVE_STATE, movestate );\n}\n\nvoid trap_BotAddAvoidSpot(int movestate, vec3_t origin, float radius, int type) {\n\tsyscall( BOTLIB_AI_ADD_AVOID_SPOT, movestate, origin, PASSFLOAT(radius), type);\n}\n\nvoid trap_BotMoveToGoal(void /* struct bot_moveresult_s */ *result, int movestate, void /* struct bot_goal_s */ *goal, int travelflags) {\n\tsyscall( BOTLIB_AI_MOVE_TO_GOAL, result, movestate, goal, travelflags );\n}\n\nint trap_BotMoveInDirection(int movestate, vec3_t dir, float speed, int type) {\n\treturn syscall( BOTLIB_AI_MOVE_IN_DIRECTION, movestate, dir, PASSFLOAT(speed), type );\n}\n\nvoid trap_BotResetAvoidReach(int movestate) {\n\tsyscall( BOTLIB_AI_RESET_AVOID_REACH, movestate );\n}\n\nvoid trap_BotResetLastAvoidReach(int movestate) {\n\tsyscall( BOTLIB_AI_RESET_LAST_AVOID_REACH,movestate  );\n}\n\nint trap_BotReachabilityArea(vec3_t origin, int testground) {\n\treturn syscall( BOTLIB_AI_REACHABILITY_AREA, origin, testground );\n}\n\nint trap_BotMovementViewTarget(int movestate, void /* struct bot_goal_s */ *goal, int travelflags, float lookahead, vec3_t target) {\n\treturn syscall( BOTLIB_AI_MOVEMENT_VIEW_TARGET, movestate, goal, travelflags, PASSFLOAT(lookahead), target );\n}\n\nint trap_BotPredictVisiblePosition(vec3_t origin, int areanum, void /* struct bot_goal_s */ *goal, int travelflags, vec3_t target) {\n\treturn syscall( BOTLIB_AI_PREDICT_VISIBLE_POSITION, origin, areanum, goal, travelflags, target );\n}\n\nint trap_BotAllocMoveState(void) {\n\treturn syscall( BOTLIB_AI_ALLOC_MOVE_STATE );\n}\n\nvoid trap_BotFreeMoveState(int handle) {\n\tsyscall( BOTLIB_AI_FREE_MOVE_STATE, handle );\n}\n\nvoid trap_BotInitMoveState(int handle, void /* struct bot_initmove_s */ *initmove) {\n\tsyscall( BOTLIB_AI_INIT_MOVE_STATE, handle, initmove );\n}\n\nint trap_BotChooseBestFightWeapon(int weaponstate, int *inventory) {\n\treturn syscall( BOTLIB_AI_CHOOSE_BEST_FIGHT_WEAPON, weaponstate, inventory );\n}\n\nvoid trap_BotGetWeaponInfo(int weaponstate, int weapon, void /* struct weaponinfo_s */ *weaponinfo) {\n\tsyscall( BOTLIB_AI_GET_WEAPON_INFO, weaponstate, weapon, weaponinfo );\n}\n\nint trap_BotLoadWeaponWeights(int weaponstate, char *filename) {\n\treturn syscall( BOTLIB_AI_LOAD_WEAPON_WEIGHTS, weaponstate, filename );\n}\n\nint trap_BotAllocWeaponState(void) {\n\treturn syscall( BOTLIB_AI_ALLOC_WEAPON_STATE );\n}\n\nvoid trap_BotFreeWeaponState(int weaponstate) {\n\tsyscall( BOTLIB_AI_FREE_WEAPON_STATE, weaponstate );\n}\n\nvoid trap_BotResetWeaponState(int weaponstate) {\n\tsyscall( BOTLIB_AI_RESET_WEAPON_STATE, weaponstate );\n}\n\nint trap_GeneticParentsAndChildSelection(int numranks, float *ranks, int *parent1, int *parent2, int *child) {\n\treturn syscall( BOTLIB_AI_GENETIC_PARENTS_AND_CHILD_SELECTION, numranks, ranks, parent1, parent2, child );\n}\n\nint trap_PC_LoadSource( const char *filename ) {\n\treturn syscall( BOTLIB_PC_LOAD_SOURCE, filename );\n}\n\nint trap_PC_FreeSource( int handle ) {\n\treturn syscall( BOTLIB_PC_FREE_SOURCE, handle );\n}\n\nint trap_PC_ReadToken( int handle, pc_token_t *pc_token ) {\n\treturn syscall( BOTLIB_PC_READ_TOKEN, handle, pc_token );\n}\n\nint trap_PC_SourceFileAndLine( int handle, char *filename, int *line ) {\n\treturn syscall( BOTLIB_PC_SOURCE_FILE_AND_LINE, handle, filename, line );\n}\n"
  },
  {
    "path": "src/game/g_target.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n#include \"g_local.h\"\n\n//==========================================================\n\n/*QUAKED target_give (1 0 0) (-8 -8 -8) (8 8 8)\nGives the activator all the items pointed to.\n*/\nvoid Use_Target_Give( gentity_t *ent, gentity_t *other, gentity_t *activator ) {\n\tgentity_t\t*t;\n\ttrace_t\t\ttrace;\n\n\tif ( !activator->client ) {\n\t\treturn;\n\t}\n\n\tif ( !ent->target ) {\n\t\treturn;\n\t}\n\n\tmemset( &trace, 0, sizeof( trace ) );\n\tt = NULL;\n\twhile ( (t = G_Find (t, FOFS(targetname), ent->target)) != NULL ) {\n\t\tif ( !t->item ) {\n\t\t\tcontinue;\n\t\t}\n\t\tTouch_Item( t, activator, &trace );\n\n\t\t// make sure it isn't going to respawn or show any events\n\t\tt->nextthink = 0;\n\t\ttrap_UnlinkEntity( t );\n\t}\n}\n\nvoid SP_target_give( gentity_t *ent ) {\n\tent->use = Use_Target_Give;\n}\n\n\n//==========================================================\n\n/*QUAKED target_remove_powerups (1 0 0) (-8 -8 -8) (8 8 8)\ntakes away all the activators powerups.\nUsed to drop flight powerups into death puts.\n*/\nvoid Use_target_remove_powerups( gentity_t *ent, gentity_t *other, gentity_t *activator ) {\n\tif( !activator->client ) {\n\t\treturn;\n\t}\n\n\tif( activator->client->ps.powerups[PW_REDFLAG] ) {\n\t\tTeam_ReturnFlag( TEAM_RED );\n\t} else if( activator->client->ps.powerups[PW_BLUEFLAG] ) {\n\t\tTeam_ReturnFlag( TEAM_BLUE );\n\t} else if( activator->client->ps.powerups[PW_NEUTRALFLAG] ) {\n\t\tTeam_ReturnFlag( TEAM_FREE );\n\t}\n\n\tmemset( activator->client->ps.powerups, 0, sizeof( activator->client->ps.powerups ) );\n}\n\nvoid SP_target_remove_powerups( gentity_t *ent ) {\n\tent->use = Use_target_remove_powerups;\n}\n\n\n//==========================================================\n\n/*QUAKED target_delay (1 0 0) (-8 -8 -8) (8 8 8)\n\"wait\" seconds to pause before firing targets.\n\"random\" delay variance, total delay = delay +/- random seconds\n*/\nvoid Think_Target_Delay( gentity_t *ent ) {\n\tG_UseTargets( ent, ent->activator );\n}\n\nvoid Use_Target_Delay( gentity_t *ent, gentity_t *other, gentity_t *activator ) {\n\tent->nextthink = level.time + ( ent->wait + ent->random * crandom() ) * 1000;\n\tent->think = Think_Target_Delay;\n\tent->activator = activator;\n}\n\nvoid SP_target_delay( gentity_t *ent ) {\n\t// check delay for backwards compatability\n\tif ( !G_SpawnFloat( \"delay\", \"0\", &ent->wait ) ) {\n\t\tG_SpawnFloat( \"wait\", \"1\", &ent->wait );\n\t}\n\n\tif ( !ent->wait ) {\n\t\tent->wait = 1;\n\t}\n\tent->use = Use_Target_Delay;\n}\n\n\n//==========================================================\n\n/*QUAKED target_score (1 0 0) (-8 -8 -8) (8 8 8)\n\"count\" number of points to add, default 1\n\nThe activator is given this many points.\n*/\nvoid Use_Target_Score (gentity_t *ent, gentity_t *other, gentity_t *activator) {\n\tAddScore( activator, ent->r.currentOrigin, ent->count );\n}\n\nvoid SP_target_score( gentity_t *ent ) {\n\tif ( !ent->count ) {\n\t\tent->count = 1;\n\t}\n\tent->use = Use_Target_Score;\n}\n\n\n//==========================================================\n\n/*QUAKED target_print (1 0 0) (-8 -8 -8) (8 8 8) redteam blueteam private\n\"message\"\ttext to print\nIf \"private\", only the activator gets the message.  If no checks, all clients get the message.\n*/\nvoid Use_Target_Print (gentity_t *ent, gentity_t *other, gentity_t *activator) {\n\tif ( activator->client && ( ent->spawnflags & 4 ) ) {\n\t\ttrap_SendServerCommand( activator-g_entities, va(\"cp \\\"%s\\\"\", ent->message ));\n\t\treturn;\n\t}\n\n\tif ( ent->spawnflags & 3 ) {\n\t\tif ( ent->spawnflags & 1 ) {\n\t\t\tG_TeamCommand( TEAM_RED, va(\"cp \\\"%s\\\"\", ent->message) );\n\t\t}\n\t\tif ( ent->spawnflags & 2 ) {\n\t\t\tG_TeamCommand( TEAM_BLUE, va(\"cp \\\"%s\\\"\", ent->message) );\n\t\t}\n\t\treturn;\n\t}\n\n\ttrap_SendServerCommand( -1, va(\"cp \\\"%s\\\"\", ent->message ));\n}\n\nvoid SP_target_print( gentity_t *ent ) {\n\tent->use = Use_Target_Print;\n}\n\n\n//==========================================================\n\n\n/*QUAKED target_speaker (1 0 0) (-8 -8 -8) (8 8 8) looped-on looped-off global activator\n\"noise\"\t\twav file to play\n\nA global sound will play full volume throughout the level.\nActivator sounds will play on the player that activated the target.\nGlobal and activator sounds can't be combined with looping.\nNormal sounds play each time the target is used.\nLooped sounds will be toggled by use functions.\nMultiple identical looping sounds will just increase volume without any speed cost.\n\"wait\" : Seconds between auto triggerings, 0 = don't auto trigger\n\"random\"\twait variance, default is 0\n*/\nvoid Use_Target_Speaker (gentity_t *ent, gentity_t *other, gentity_t *activator) {\n\tif (ent->spawnflags & 3) {\t// looping sound toggles\n\t\tif (ent->s.loopSound)\n\t\t\tent->s.loopSound = 0;\t// turn it off\n\t\telse\n\t\t\tent->s.loopSound = ent->noise_index;\t// start it\n\t}else {\t// normal sound\n\t\tif ( ent->spawnflags & 8 ) {\n\t\t\tG_AddEvent( activator, EV_GENERAL_SOUND, ent->noise_index );\n\t\t} else if (ent->spawnflags & 4) {\n\t\t\tG_AddEvent( ent, EV_GLOBAL_SOUND, ent->noise_index );\n\t\t} else {\n\t\t\tG_AddEvent( ent, EV_GENERAL_SOUND, ent->noise_index );\n\t\t}\n\t}\n}\n\nvoid SP_target_speaker( gentity_t *ent ) {\n\tchar\tbuffer[MAX_QPATH];\n\tchar\t*s;\n\n\tG_SpawnFloat( \"wait\", \"0\", &ent->wait );\n\tG_SpawnFloat( \"random\", \"0\", &ent->random );\n\n\tif ( !G_SpawnString( \"noise\", \"NOSOUND\", &s ) ) {\n\t\tG_Error( \"target_speaker without a noise key at %s\", vtos( ent->s.origin ) );\n\t}\n\n\t// force all client reletive sounds to be \"activator\" speakers that\n\t// play on the entity that activates it\n\tif ( s[0] == '*' ) {\n\t\tent->spawnflags |= 8;\n\t}\n\n\tif (!strstr( s, \".wav\" )) {\n\t\tCom_sprintf (buffer, sizeof(buffer), \"%s.wav\", s );\n\t} else {\n\t\tQ_strncpyz( buffer, s, sizeof(buffer) );\n\t}\n\tent->noise_index = G_SoundIndex(buffer);\n\n\t// a repeating speaker can be done completely client side\n\tent->s.eType = ET_SPEAKER;\n\tent->s.eventParm = ent->noise_index;\n\tent->s.frame = ent->wait * 10;\n\tent->s.clientNum = ent->random * 10;\n\n\n\t// check for prestarted looping sound\n\tif ( ent->spawnflags & 1 ) {\n\t\tent->s.loopSound = ent->noise_index;\n\t}\n\n\tent->use = Use_Target_Speaker;\n\n\tif (ent->spawnflags & 4) {\n\t\tent->r.svFlags |= SVF_BROADCAST;\n\t}\n\n\tVectorCopy( ent->s.origin, ent->s.pos.trBase );\n\n\t// must link the entity so we get areas and clusters so\n\t// the server can determine who to send updates to\n\ttrap_LinkEntity( ent );\n}\n\n\n\n//==========================================================\n\n/*QUAKED target_laser (0 .5 .8) (-8 -8 -8) (8 8 8) START_ON\nWhen triggered, fires a laser.  You can either set a target or a direction.\n*/\nvoid target_laser_think (gentity_t *self) {\n\tvec3_t\tend;\n\ttrace_t\ttr;\n\tvec3_t\tpoint;\n\n\t// if pointed at another entity, set movedir to point at it\n\tif ( self->enemy ) {\n\t\tVectorMA (self->enemy->s.origin, 0.5, self->enemy->r.mins, point);\n\t\tVectorMA (point, 0.5, self->enemy->r.maxs, point);\n\t\tVectorSubtract (point, self->s.origin, self->movedir);\n\t\tVectorNormalize (self->movedir);\n\t}\n\n\t// fire forward and see what we hit\n\tVectorMA (self->s.origin, 2048, self->movedir, end);\n\n\ttrap_Trace( &tr, self->s.origin, NULL, NULL, end, self->s.number, CONTENTS_SOLID|CONTENTS_BODY|CONTENTS_CORPSE);\n\n\tif ( tr.entityNum ) {\n\t\t// hurt it if we can\n\t\tG_Damage ( &g_entities[tr.entityNum], self, self->activator, self->movedir, \n\t\t\ttr.endpos, self->damage, DAMAGE_NO_KNOCKBACK, MOD_TARGET_LASER);\n\t}\n\n\tVectorCopy (tr.endpos, self->s.origin2);\n\n\ttrap_LinkEntity( self );\n\tself->nextthink = level.time + FRAMETIME;\n}\n\nvoid target_laser_on (gentity_t *self)\n{\n\tif (!self->activator)\n\t\tself->activator = self;\n\ttarget_laser_think (self);\n}\n\nvoid target_laser_off (gentity_t *self)\n{\n\ttrap_UnlinkEntity( self );\n\tself->nextthink = 0;\n}\n\nvoid target_laser_use (gentity_t *self, gentity_t *other, gentity_t *activator)\n{\n\tself->activator = activator;\n\tif ( self->nextthink > 0 )\n\t\ttarget_laser_off (self);\n\telse\n\t\ttarget_laser_on (self);\n}\n\nvoid target_laser_start (gentity_t *self)\n{\n\tgentity_t *ent;\n\n\tself->s.eType = ET_BEAM;\n\n\tif (self->target) {\n\t\tent = G_Find (NULL, FOFS(targetname), self->target);\n\t\tif (!ent) {\n\t\t\tG_Printf (\"%s at %s: %s is a bad target\\n\", self->classname, vtos(self->s.origin), self->target);\n\t\t}\n\t\tself->enemy = ent;\n\t} else {\n\t\tG_SetMovedir (self->s.angles, self->movedir);\n\t}\n\n\tself->use = target_laser_use;\n\tself->think = target_laser_think;\n\n\tif ( !self->damage ) {\n\t\tself->damage = 1;\n\t}\n\n\tif (self->spawnflags & 1)\n\t\ttarget_laser_on (self);\n\telse\n\t\ttarget_laser_off (self);\n}\n\nvoid SP_target_laser (gentity_t *self)\n{\n\t// let everything else get spawned before we start firing\n\tself->think = target_laser_start;\n\tself->nextthink = level.time + FRAMETIME;\n}\n\n\n//==========================================================\n\nvoid target_teleporter_use( gentity_t *self, gentity_t *other, gentity_t *activator ) {\n\tgentity_t\t*dest;\n\n\tif (!activator->client)\n\t\treturn;\n\tdest = \tG_PickTarget( self->target );\n\tif (!dest) {\n\t\tG_Printf (\"Couldn't find teleporter destination\\n\");\n\t\treturn;\n\t}\n\n\tTeleportPlayer( activator, dest->s.origin, dest->s.angles );\n}\n\n/*QUAKED target_teleporter (1 0 0) (-8 -8 -8) (8 8 8)\nThe activator will be teleported away.\n*/\nvoid SP_target_teleporter( gentity_t *self ) {\n\tif (!self->targetname)\n\t\tG_Printf(\"untargeted %s at %s\\n\", self->classname, vtos(self->s.origin));\n\n\tself->use = target_teleporter_use;\n}\n\n//==========================================================\n\n\n/*QUAKED target_relay (.5 .5 .5) (-8 -8 -8) (8 8 8) RED_ONLY BLUE_ONLY RANDOM\nThis doesn't perform any actions except fire its targets.\nThe activator can be forced to be from a certain team.\nif RANDOM is checked, only one of the targets will be fired, not all of them\n*/\nvoid target_relay_use (gentity_t *self, gentity_t *other, gentity_t *activator) {\n\tif ( ( self->spawnflags & 1 ) && activator->client \n\t\t&& activator->client->sess.sessionTeam != TEAM_RED ) {\n\t\treturn;\n\t}\n\tif ( ( self->spawnflags & 2 ) && activator->client \n\t\t&& activator->client->sess.sessionTeam != TEAM_BLUE ) {\n\t\treturn;\n\t}\n\tif ( self->spawnflags & 4 ) {\n\t\tgentity_t\t*ent;\n\n\t\tent = G_PickTarget( self->target );\n\t\tif ( ent && ent->use ) {\n\t\t\tent->use( ent, self, activator );\n\t\t}\n\t\treturn;\n\t}\n\tG_UseTargets (self, activator);\n}\n\nvoid SP_target_relay (gentity_t *self) {\n\tself->use = target_relay_use;\n}\n\n\n//==========================================================\n\n/*QUAKED target_kill (.5 .5 .5) (-8 -8 -8) (8 8 8)\nKills the activator.\n*/\nvoid target_kill_use( gentity_t *self, gentity_t *other, gentity_t *activator ) {\n\tG_Damage ( activator, NULL, NULL, NULL, NULL, 100000, DAMAGE_NO_PROTECTION, MOD_TELEFRAG);\n}\n\nvoid SP_target_kill( gentity_t *self ) {\n\tself->use = target_kill_use;\n}\n\n/*QUAKED target_position (0 0.5 0) (-4 -4 -4) (4 4 4)\nUsed as a positional target for in-game calculation, like jumppad targets.\n*/\nvoid SP_target_position( gentity_t *self ){\n\tG_SetOrigin( self, self->s.origin );\n}\n\nstatic void target_location_linkup(gentity_t *ent)\n{\n\tint i;\n\tint n;\n\n\tif (level.locationLinked) \n\t\treturn;\n\n\tlevel.locationLinked = qtrue;\n\n\tlevel.locationHead = NULL;\n\n\ttrap_SetConfigstring( CS_LOCATIONS, \"unknown\" );\n\n\tfor (i = 0, ent = g_entities, n = 1;\n\t\t\ti < level.num_entities;\n\t\t\ti++, ent++) {\n\t\tif (ent->classname && !Q_stricmp(ent->classname, \"target_location\")) {\n\t\t\t// lets overload some variables!\n\t\t\tent->health = n; // use for location marking\n\t\t\ttrap_SetConfigstring( CS_LOCATIONS + n, ent->message );\n\t\t\tn++;\n\t\t\tent->nextTrain = level.locationHead;\n\t\t\tlevel.locationHead = ent;\n\t\t}\n\t}\n\n\t// All linked together now\n}\n\n/*QUAKED target_location (0 0.5 0) (-8 -8 -8) (8 8 8)\nSet \"message\" to the name of this location.\nSet \"count\" to 0-7 for color.\n0:white 1:red 2:green 3:yellow 4:blue 5:cyan 6:magenta 7:white\n\nClosest target_location in sight used for the location, if none\nin site, closest in distance\n*/\nvoid SP_target_location( gentity_t *self ){\n\tself->think = target_location_linkup;\n\tself->nextthink = level.time + 200;  // Let them all spawn first\n\n\tG_SetOrigin( self, self->s.origin );\n}\n\n"
  },
  {
    "path": "src/game/g_team.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n\n#include \"g_local.h\"\n\n\ntypedef struct teamgame_s {\n\tfloat\t\t\tlast_flag_capture;\n\tint\t\t\t\tlast_capture_team;\n\tflagStatus_t\tredStatus;\t// CTF\n\tflagStatus_t\tblueStatus;\t// CTF\n\tflagStatus_t\tflagStatus;\t// One Flag CTF\n\tint\t\t\t\tredTakenTime;\n\tint\t\t\t\tblueTakenTime;\n\tint\t\t\t\tredObeliskAttackedTime;\n\tint\t\t\t\tblueObeliskAttackedTime;\n} teamgame_t;\n\nteamgame_t teamgame;\n\ngentity_t\t*neutralObelisk;\n\nvoid Team_SetFlagStatus( int team, flagStatus_t status );\n\nvoid Team_InitGame( void ) {\n\tmemset(&teamgame, 0, sizeof teamgame);\n\n\tswitch( g_gametype.integer ) {\n\tcase GT_CTF:\n\t\tteamgame.redStatus = teamgame.blueStatus = -1; // Invalid to force update\n\t\tTeam_SetFlagStatus( TEAM_RED, FLAG_ATBASE );\n\t\tTeam_SetFlagStatus( TEAM_BLUE, FLAG_ATBASE );\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n}\n\nint OtherTeam(int team) {\n\tif (team==TEAM_RED)\n\t\treturn TEAM_BLUE;\n\telse if (team==TEAM_BLUE)\n\t\treturn TEAM_RED;\n\treturn team;\n}\n\nconst char *TeamName(int team)  {\n\tif (team==TEAM_RED)\n\t\treturn \"RED\";\n\telse if (team==TEAM_BLUE)\n\t\treturn \"BLUE\";\n\telse if (team==TEAM_SPECTATOR)\n\t\treturn \"SPECTATOR\";\n\treturn \"FREE\";\n}\n\nconst char *OtherTeamName(int team) {\n\tif (team==TEAM_RED)\n\t\treturn \"BLUE\";\n\telse if (team==TEAM_BLUE)\n\t\treturn \"RED\";\n\telse if (team==TEAM_SPECTATOR)\n\t\treturn \"SPECTATOR\";\n\treturn \"FREE\";\n}\n\nconst char *TeamColorString(int team) {\n\tif (team==TEAM_RED)\n\t\treturn S_COLOR_RED;\n\telse if (team==TEAM_BLUE)\n\t\treturn S_COLOR_BLUE;\n\telse if (team==TEAM_SPECTATOR)\n\t\treturn S_COLOR_YELLOW;\n\treturn S_COLOR_WHITE;\n}\n\n// NULL for everyone\nvoid QDECL PrintMsg( gentity_t *ent, const char *fmt, ... ) {\n\tchar\t\tmsg[1024];\n\tva_list\t\targptr;\n\tchar\t\t*p;\n\t\n\tva_start (argptr,fmt);\n\tif (vsprintf (msg, fmt, argptr) > sizeof(msg)) {\n\t\tG_Error ( \"PrintMsg overrun\" );\n\t}\n\tva_end (argptr);\n\n\t// double quotes are bad\n\twhile ((p = strchr(msg, '\"')) != NULL)\n\t\t*p = '\\'';\n\n\ttrap_SendServerCommand ( ( (ent == NULL) ? -1 : ent-g_entities ), va(\"print \\\"%s\\\"\", msg ));\n}\n\n/*\n==============\nAddTeamScore\n\n used for gametype > GT_TEAM\n for gametype GT_TEAM the level.teamScores is updated in AddScore in g_combat.c\n==============\n*/\nvoid AddTeamScore(vec3_t origin, int team, int score) {\n\tgentity_t\t*te;\n\n\tte = G_TempEntity(origin, EV_GLOBAL_TEAM_SOUND );\n\tte->r.svFlags |= SVF_BROADCAST;\n\n\tif ( team == TEAM_RED ) {\n\t\tif ( level.teamScores[ TEAM_RED ] + score == level.teamScores[ TEAM_BLUE ] ) {\n\t\t\t//teams are tied sound\n\t\t\tte->s.eventParm = GTS_TEAMS_ARE_TIED;\n\t\t}\n\t\telse if ( level.teamScores[ TEAM_RED ] <= level.teamScores[ TEAM_BLUE ] &&\n\t\t\t\t\tlevel.teamScores[ TEAM_RED ] + score > level.teamScores[ TEAM_BLUE ]) {\n\t\t\t// red took the lead sound\n\t\t\tte->s.eventParm = GTS_REDTEAM_TOOK_LEAD;\n\t\t}\n\t\telse {\n\t\t\t// red scored sound\n\t\t\tte->s.eventParm = GTS_REDTEAM_SCORED;\n\t\t}\n\t}\n\telse {\n\t\tif ( level.teamScores[ TEAM_BLUE ] + score == level.teamScores[ TEAM_RED ] ) {\n\t\t\t//teams are tied sound\n\t\t\tte->s.eventParm = GTS_TEAMS_ARE_TIED;\n\t\t}\n\t\telse if ( level.teamScores[ TEAM_BLUE ] <= level.teamScores[ TEAM_RED ] &&\n\t\t\t\t\tlevel.teamScores[ TEAM_BLUE ] + score > level.teamScores[ TEAM_RED ]) {\n\t\t\t// blue took the lead sound\n\t\t\tte->s.eventParm = GTS_BLUETEAM_TOOK_LEAD;\n\t\t}\n\t\telse {\n\t\t\t// blue scored sound\n\t\t\tte->s.eventParm = GTS_BLUETEAM_SCORED;\n\t\t}\n\t}\n\tlevel.teamScores[ team ] += score;\n}\n\n/*\n==============\nOnSameTeam\n==============\n*/\nqboolean OnSameTeam( gentity_t *ent1, gentity_t *ent2 ) {\n\tif ( !ent1->client || !ent2->client ) {\n\t\treturn qfalse;\n\t}\n\n\tif ( g_gametype.integer < GT_TEAM ) {\n\t\treturn qfalse;\n\t}\n\n\tif ( ent1->client->sess.sessionTeam == ent2->client->sess.sessionTeam ) {\n\t\treturn qtrue;\n\t}\n\n\treturn qfalse;\n}\n\n\nstatic char ctfFlagStatusRemap[] = { '0', '1', '*', '*', '2' };\nstatic char oneFlagStatusRemap[] = { '0', '1', '2', '3', '4' };\n\nvoid Team_SetFlagStatus( int team, flagStatus_t status ) {\n\tqboolean modified = qfalse;\n\n\tswitch( team ) {\n\tcase TEAM_RED:\t// CTF\n\t\tif( teamgame.redStatus != status ) {\n\t\t\tteamgame.redStatus = status;\n\t\t\tmodified = qtrue;\n\t\t}\n\t\tbreak;\n\n\tcase TEAM_BLUE:\t// CTF\n\t\tif( teamgame.blueStatus != status ) {\n\t\t\tteamgame.blueStatus = status;\n\t\t\tmodified = qtrue;\n\t\t}\n\t\tbreak;\n\n\tcase TEAM_FREE:\t// One Flag CTF\n\t\tif( teamgame.flagStatus != status ) {\n\t\t\tteamgame.flagStatus = status;\n\t\t\tmodified = qtrue;\n\t\t}\n\t\tbreak;\n\t}\n\n\tif( modified ) {\n\t\tchar st[4];\n\n\t\tif( g_gametype.integer == GT_CTF ) {\n\t\t\tst[0] = ctfFlagStatusRemap[teamgame.redStatus];\n\t\t\tst[1] = ctfFlagStatusRemap[teamgame.blueStatus];\n\t\t\tst[2] = 0;\n\t\t}\n\t\telse {\t\t// GT_1FCTF\n\t\t\tst[0] = oneFlagStatusRemap[teamgame.flagStatus];\n\t\t\tst[1] = 0;\n\t\t}\n\n\t\ttrap_SetConfigstring( CS_FLAGSTATUS, st );\n\t}\n}\n\nvoid Team_CheckDroppedItem( gentity_t *dropped ) {\n\tif( dropped->item->giTag == PW_REDFLAG ) {\n\t\tTeam_SetFlagStatus( TEAM_RED, FLAG_DROPPED );\n\t}\n\telse if( dropped->item->giTag == PW_BLUEFLAG ) {\n\t\tTeam_SetFlagStatus( TEAM_BLUE, FLAG_DROPPED );\n\t}\n\telse if( dropped->item->giTag == PW_NEUTRALFLAG ) {\n\t\tTeam_SetFlagStatus( TEAM_FREE, FLAG_DROPPED );\n\t}\n}\n\n/*\n================\nTeam_ForceGesture\n================\n*/\nvoid Team_ForceGesture(int team) {\n\tint i;\n\tgentity_t *ent;\n\n\tfor (i = 0; i < MAX_CLIENTS; i++) {\n\t\tent = &g_entities[i];\n\t\tif (!ent->inuse)\n\t\t\tcontinue;\n\t\tif (!ent->client)\n\t\t\tcontinue;\n\t\tif (ent->client->sess.sessionTeam != team)\n\t\t\tcontinue;\n\t\t//\n\t\tent->flags |= FL_FORCE_GESTURE;\n\t}\n}\n\n/*\n================\nTeam_FragBonuses\n\nCalculate the bonuses for flag defense, flag carrier defense, etc.\nNote that bonuses are not cumulative.  You get one, they are in importance\norder.\n================\n*/\nvoid Team_FragBonuses(gentity_t *targ, gentity_t *inflictor, gentity_t *attacker)\n{\n\tint i;\n\tgentity_t *ent;\n\tint flag_pw, enemy_flag_pw;\n\tint otherteam;\n\tint tokens;\n\tgentity_t *flag, *carrier = NULL;\n\tchar *c;\n\tvec3_t v1, v2;\n\tint team;\n\n\t// no bonus for fragging yourself or team mates\n\tif (!targ->client || !attacker->client || targ == attacker || OnSameTeam(targ, attacker))\n\t\treturn;\n\n\tteam = targ->client->sess.sessionTeam;\n\totherteam = OtherTeam(targ->client->sess.sessionTeam);\n\tif (otherteam < 0)\n\t\treturn; // whoever died isn't on a team\n\n\t// same team, if the flag at base, check to he has the enemy flag\n\tif (team == TEAM_RED) {\n\t\tflag_pw = PW_REDFLAG;\n\t\tenemy_flag_pw = PW_BLUEFLAG;\n\t} else {\n\t\tflag_pw = PW_BLUEFLAG;\n\t\tenemy_flag_pw = PW_REDFLAG;\n\t}\n\n\tif (g_gametype.integer == GT_1FCTF) {\n\t\tenemy_flag_pw = PW_NEUTRALFLAG;\n\t} \n\n\t// did the attacker frag the flag carrier?\n\ttokens = 0;\n\tif (targ->client->ps.powerups[enemy_flag_pw]) {\n\t\tattacker->client->pers.teamState.lastfraggedcarrier = level.time;\n\t\tAddScore(attacker, targ->r.currentOrigin, CTF_FRAG_CARRIER_BONUS);\n\t\tattacker->client->pers.teamState.fragcarrier++;\n\t\tPrintMsg(NULL, \"%s\" S_COLOR_WHITE \" fragged %s's flag carrier!\\n\",\n\t\t\tattacker->client->pers.netname, TeamName(team));\n\n\t\t// the target had the flag, clear the hurt carrier\n\t\t// field on the other team\n\t\tfor (i = 0; i < g_maxclients.integer; i++) {\n\t\t\tent = g_entities + i;\n\t\t\tif (ent->inuse && ent->client->sess.sessionTeam == otherteam)\n\t\t\t\tent->client->pers.teamState.lasthurtcarrier = 0;\n\t\t}\n\t\treturn;\n\t}\n\n\t// did the attacker frag a head carrier? other->client->ps.generic1\n\tif (tokens) {\n\t\tattacker->client->pers.teamState.lastfraggedcarrier = level.time;\n\t\tAddScore(attacker, targ->r.currentOrigin, CTF_FRAG_CARRIER_BONUS * tokens * tokens);\n\t\tattacker->client->pers.teamState.fragcarrier++;\n\t\tPrintMsg(NULL, \"%s\" S_COLOR_WHITE \" fragged %s's skull carrier!\\n\",\n\t\t\tattacker->client->pers.netname, TeamName(team));\n\n\t\t// the target had the flag, clear the hurt carrier\n\t\t// field on the other team\n\t\tfor (i = 0; i < g_maxclients.integer; i++) {\n\t\t\tent = g_entities + i;\n\t\t\tif (ent->inuse && ent->client->sess.sessionTeam == otherteam)\n\t\t\t\tent->client->pers.teamState.lasthurtcarrier = 0;\n\t\t}\n\t\treturn;\n\t}\n\n\tif (targ->client->pers.teamState.lasthurtcarrier &&\n\t\tlevel.time - targ->client->pers.teamState.lasthurtcarrier < CTF_CARRIER_DANGER_PROTECT_TIMEOUT &&\n\t\t!attacker->client->ps.powerups[flag_pw]) {\n\t\t// attacker is on the same team as the flag carrier and\n\t\t// fragged a guy who hurt our flag carrier\n\t\tAddScore(attacker, targ->r.currentOrigin, CTF_CARRIER_DANGER_PROTECT_BONUS);\n\n\t\tattacker->client->pers.teamState.carrierdefense++;\n\t\ttarg->client->pers.teamState.lasthurtcarrier = 0;\n\n\t\tattacker->client->ps.persistant[PERS_DEFEND_COUNT]++;\n\t\tteam = attacker->client->sess.sessionTeam;\n\t\t// add the sprite over the player's head\n\t\tattacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );\n\t\tattacker->client->ps.eFlags |= EF_AWARD_DEFEND;\n\t\tattacker->client->rewardTime = level.time + REWARD_SPRITE_TIME;\n\n\t\treturn;\n\t}\n\n\tif (targ->client->pers.teamState.lasthurtcarrier &&\n\t\tlevel.time - targ->client->pers.teamState.lasthurtcarrier < CTF_CARRIER_DANGER_PROTECT_TIMEOUT) {\n\t\t// attacker is on the same team as the skull carrier and\n\t\tAddScore(attacker, targ->r.currentOrigin, CTF_CARRIER_DANGER_PROTECT_BONUS);\n\n\t\tattacker->client->pers.teamState.carrierdefense++;\n\t\ttarg->client->pers.teamState.lasthurtcarrier = 0;\n\n\t\tattacker->client->ps.persistant[PERS_DEFEND_COUNT]++;\n\t\tteam = attacker->client->sess.sessionTeam;\n\t\t// add the sprite over the player's head\n\t\tattacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );\n\t\tattacker->client->ps.eFlags |= EF_AWARD_DEFEND;\n\t\tattacker->client->rewardTime = level.time + REWARD_SPRITE_TIME;\n\n\t\treturn;\n\t}\n\n\t// flag and flag carrier area defense bonuses\n\n\t// we have to find the flag and carrier entities\n\n\t// find the flag\n\tswitch (attacker->client->sess.sessionTeam) {\n\tcase TEAM_RED:\n\t\tc = \"team_CTF_redflag\";\n\t\tbreak;\n\tcase TEAM_BLUE:\n\t\tc = \"team_CTF_blueflag\";\n\t\tbreak;\t\t\n\tdefault:\n\t\treturn;\n\t}\n\t// find attacker's team's flag carrier\n\tfor (i = 0; i < g_maxclients.integer; i++) {\n\t\tcarrier = g_entities + i;\n\t\tif (carrier->inuse && carrier->client->ps.powerups[flag_pw])\n\t\t\tbreak;\n\t\tcarrier = NULL;\n\t}\n\tflag = NULL;\n\twhile ((flag = G_Find (flag, FOFS(classname), c)) != NULL) {\n\t\tif (!(flag->flags & FL_DROPPED_ITEM))\n\t\t\tbreak;\n\t}\n\n\tif (!flag)\n\t\treturn; // can't find attacker's flag\n\n\t// ok we have the attackers flag and a pointer to the carrier\n\n\t// check to see if we are defending the base's flag\n\tVectorSubtract(targ->r.currentOrigin, flag->r.currentOrigin, v1);\n\tVectorSubtract(attacker->r.currentOrigin, flag->r.currentOrigin, v2);\n\n\tif ( ( ( VectorLength(v1) < CTF_TARGET_PROTECT_RADIUS &&\n\t\ttrap_InPVS(flag->r.currentOrigin, targ->r.currentOrigin ) ) ||\n\t\t( VectorLength(v2) < CTF_TARGET_PROTECT_RADIUS &&\n\t\ttrap_InPVS(flag->r.currentOrigin, attacker->r.currentOrigin ) ) ) &&\n\t\tattacker->client->sess.sessionTeam != targ->client->sess.sessionTeam) {\n\n\t\t// we defended the base flag\n\t\tAddScore(attacker, targ->r.currentOrigin, CTF_FLAG_DEFENSE_BONUS);\n\t\tattacker->client->pers.teamState.basedefense++;\n\n\t\tattacker->client->ps.persistant[PERS_DEFEND_COUNT]++;\n\t\t// add the sprite over the player's head\n\t\tattacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );\n\t\tattacker->client->ps.eFlags |= EF_AWARD_DEFEND;\n\t\tattacker->client->rewardTime = level.time + REWARD_SPRITE_TIME;\n\n\t\treturn;\n\t}\n\n\tif (carrier && carrier != attacker) {\n\t\tVectorSubtract(targ->r.currentOrigin, carrier->r.currentOrigin, v1);\n\t\tVectorSubtract(attacker->r.currentOrigin, carrier->r.currentOrigin, v1);\n\n\t\tif ( ( ( VectorLength(v1) < CTF_ATTACKER_PROTECT_RADIUS &&\n\t\t\ttrap_InPVS(carrier->r.currentOrigin, targ->r.currentOrigin ) ) ||\n\t\t\t( VectorLength(v2) < CTF_ATTACKER_PROTECT_RADIUS &&\n\t\t\t\ttrap_InPVS(carrier->r.currentOrigin, attacker->r.currentOrigin ) ) ) &&\n\t\t\tattacker->client->sess.sessionTeam != targ->client->sess.sessionTeam) {\n\t\t\tAddScore(attacker, targ->r.currentOrigin, CTF_CARRIER_PROTECT_BONUS);\n\t\t\tattacker->client->pers.teamState.carrierdefense++;\n\n\t\t\tattacker->client->ps.persistant[PERS_DEFEND_COUNT]++;\n\t\t\t// add the sprite over the player's head\n\t\t\tattacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );\n\t\t\tattacker->client->ps.eFlags |= EF_AWARD_DEFEND;\n\t\t\tattacker->client->rewardTime = level.time + REWARD_SPRITE_TIME;\n\n\t\t\treturn;\n\t\t}\n\t}\n}\n\n/*\n================\nTeam_CheckHurtCarrier\n\nCheck to see if attacker hurt the flag carrier.  Needed when handing out bonuses for assistance to flag\ncarrier defense.\n================\n*/\nvoid Team_CheckHurtCarrier(gentity_t *targ, gentity_t *attacker)\n{\n\tint flag_pw;\n\n\tif (!targ->client || !attacker->client)\n\t\treturn;\n\n\tif (targ->client->sess.sessionTeam == TEAM_RED)\n\t\tflag_pw = PW_BLUEFLAG;\n\telse\n\t\tflag_pw = PW_REDFLAG;\n\n\t// flags\n\tif (targ->client->ps.powerups[flag_pw] &&\n\t\ttarg->client->sess.sessionTeam != attacker->client->sess.sessionTeam)\n\t\tattacker->client->pers.teamState.lasthurtcarrier = level.time;\n\n\t// skulls\n\tif (targ->client->ps.generic1 &&\n\t\ttarg->client->sess.sessionTeam != attacker->client->sess.sessionTeam)\n\t\tattacker->client->pers.teamState.lasthurtcarrier = level.time;\n}\n\n\ngentity_t *Team_ResetFlag( int team ) {\n\tchar *c;\n\tgentity_t *ent, *rent = NULL;\n\n\tswitch (team) {\n\tcase TEAM_RED:\n\t\tc = \"team_CTF_redflag\";\n\t\tbreak;\n\tcase TEAM_BLUE:\n\t\tc = \"team_CTF_blueflag\";\n\t\tbreak;\n\tcase TEAM_FREE:\n\t\tc = \"team_CTF_neutralflag\";\n\t\tbreak;\n\tdefault:\n\t\treturn NULL;\n\t}\n\n\tent = NULL;\n\twhile ((ent = G_Find (ent, FOFS(classname), c)) != NULL) {\n\t\tif (ent->flags & FL_DROPPED_ITEM)\n\t\t\tG_FreeEntity(ent);\n\t\telse {\n\t\t\trent = ent;\n\t\t\tRespawnItem(ent);\n\t\t}\n\t}\n\n\tTeam_SetFlagStatus( team, FLAG_ATBASE );\n\n\treturn rent;\n}\n\nvoid Team_ResetFlags( void ) {\n\tif( g_gametype.integer == GT_CTF ) {\n\t\tTeam_ResetFlag( TEAM_RED );\n\t\tTeam_ResetFlag( TEAM_BLUE );\n\t}\n}\n\nvoid Team_ReturnFlagSound( gentity_t *ent, int team ) {\n\tgentity_t\t*te;\n\n\tif (ent == NULL) {\n\t\tG_Printf (\"Warning:  NULL passed to Team_ReturnFlagSound\\n\");\n\t\treturn;\n\t}\n\n\tte = G_TempEntity( ent->s.pos.trBase, EV_GLOBAL_TEAM_SOUND );\n\tif( team == TEAM_BLUE ) {\n\t\tte->s.eventParm = GTS_RED_RETURN;\n\t}\n\telse {\n\t\tte->s.eventParm = GTS_BLUE_RETURN;\n\t}\n\tte->r.svFlags |= SVF_BROADCAST;\n}\n\nvoid Team_TakeFlagSound( gentity_t *ent, int team ) {\n\tgentity_t\t*te;\n\n\tif (ent == NULL) {\n\t\tG_Printf (\"Warning:  NULL passed to Team_TakeFlagSound\\n\");\n\t\treturn;\n\t}\n\n\t// only play sound when the flag was at the base\n\t// or not picked up the last 10 seconds\n\tswitch(team) {\n\t\tcase TEAM_RED:\n\t\t\tif( teamgame.blueStatus != FLAG_ATBASE ) {\n\t\t\t\tif (teamgame.blueTakenTime > level.time - 10000)\n\t\t\t\t\treturn;\n\t\t\t}\n\t\t\tteamgame.blueTakenTime = level.time;\n\t\t\tbreak;\n\n\t\tcase TEAM_BLUE:\t// CTF\n\t\t\tif( teamgame.redStatus != FLAG_ATBASE ) {\n\t\t\t\tif (teamgame.redTakenTime > level.time - 10000)\n\t\t\t\t\treturn;\n\t\t\t}\n\t\t\tteamgame.redTakenTime = level.time;\n\t\t\tbreak;\n\t}\n\n\tte = G_TempEntity( ent->s.pos.trBase, EV_GLOBAL_TEAM_SOUND );\n\tif( team == TEAM_BLUE ) {\n\t\tte->s.eventParm = GTS_RED_TAKEN;\n\t}\n\telse {\n\t\tte->s.eventParm = GTS_BLUE_TAKEN;\n\t}\n\tte->r.svFlags |= SVF_BROADCAST;\n}\n\nvoid Team_CaptureFlagSound( gentity_t *ent, int team ) {\n\tgentity_t\t*te;\n\n\tif (ent == NULL) {\n\t\tG_Printf (\"Warning:  NULL passed to Team_CaptureFlagSound\\n\");\n\t\treturn;\n\t}\n\n\tte = G_TempEntity( ent->s.pos.trBase, EV_GLOBAL_TEAM_SOUND );\n\tif( team == TEAM_BLUE ) {\n\t\tte->s.eventParm = GTS_BLUE_CAPTURE;\n\t}\n\telse {\n\t\tte->s.eventParm = GTS_RED_CAPTURE;\n\t}\n\tte->r.svFlags |= SVF_BROADCAST;\n}\n\nvoid Team_ReturnFlag( int team ) {\n\tTeam_ReturnFlagSound(Team_ResetFlag(team), team);\n\tif( team == TEAM_FREE ) {\n\t\tPrintMsg(NULL, \"The flag has returned!\\n\" );\n\t}\n\telse {\n\t\tPrintMsg(NULL, \"The %s flag has returned!\\n\", TeamName(team));\n\t}\n}\n\nvoid Team_FreeEntity( gentity_t *ent ) {\n\tif( ent->item->giTag == PW_REDFLAG ) {\n\t\tTeam_ReturnFlag( TEAM_RED );\n\t}\n\telse if( ent->item->giTag == PW_BLUEFLAG ) {\n\t\tTeam_ReturnFlag( TEAM_BLUE );\n\t}\n\telse if( ent->item->giTag == PW_NEUTRALFLAG ) {\n\t\tTeam_ReturnFlag( TEAM_FREE );\n\t}\n}\n\n/*\n==============\nTeam_DroppedFlagThink\n\nAutomatically set in Launch_Item if the item is one of the flags\n\nFlags are unique in that if they are dropped, the base flag must be respawned when they time out\n==============\n*/\nvoid Team_DroppedFlagThink(gentity_t *ent) {\n\tint\t\tteam = TEAM_FREE;\n\n\tif( ent->item->giTag == PW_REDFLAG ) {\n\t\tteam = TEAM_RED;\n\t}\n\telse if( ent->item->giTag == PW_BLUEFLAG ) {\n\t\tteam = TEAM_BLUE;\n\t}\n\telse if( ent->item->giTag == PW_NEUTRALFLAG ) {\n\t\tteam = TEAM_FREE;\n\t}\n\n\tTeam_ReturnFlagSound( Team_ResetFlag( team ), team );\n\t// Reset Flag will delete this entity\n}\n\n\n/*\n==============\nTeam_DroppedFlagThink\n==============\n*/\nint Team_TouchOurFlag( gentity_t *ent, gentity_t *other, int team ) {\n\tint\t\t\ti;\n\tgentity_t\t*player;\n\tgclient_t\t*cl = other->client;\n\tint\t\t\tenemy_flag;\n\n\tif (cl->sess.sessionTeam == TEAM_RED) {\n\t\tenemy_flag = PW_BLUEFLAG;\n\t} else {\n\t\tenemy_flag = PW_REDFLAG;\n\t}\n\n\tif ( ent->flags & FL_DROPPED_ITEM ) {\n\t\t// hey, its not home.  return it by teleporting it back\n\t\tPrintMsg( NULL, \"%s\" S_COLOR_WHITE \" returned the %s flag!\\n\", \n\t\t\tcl->pers.netname, TeamName(team));\n\t\tAddScore(other, ent->r.currentOrigin, CTF_RECOVERY_BONUS);\n\t\tother->client->pers.teamState.flagrecovery++;\n\t\tother->client->pers.teamState.lastreturnedflag = level.time;\n\t\t//ResetFlag will remove this entity!  We must return zero\n\t\tTeam_ReturnFlagSound(Team_ResetFlag(team), team);\n\t\treturn 0;\n\t}\n\n\t// the flag is at home base.  if the player has the enemy\n\t// flag, he's just won!\n\tif (!cl->ps.powerups[enemy_flag])\n\t\treturn 0; // We don't have the flag\n\tPrintMsg( NULL, \"%s\" S_COLOR_WHITE \" captured the %s flag!\\n\", cl->pers.netname, TeamName(OtherTeam(team)));\n\n\tcl->ps.powerups[enemy_flag] = 0;\n\n\tteamgame.last_flag_capture = level.time;\n\tteamgame.last_capture_team = team;\n\n\t// Increase the team's score\n\tAddTeamScore(ent->s.pos.trBase, other->client->sess.sessionTeam, 1);\n\tTeam_ForceGesture(other->client->sess.sessionTeam);\n\n\tother->client->pers.teamState.captures++;\n\t// add the sprite over the player's head\n\tother->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );\n\tother->client->ps.eFlags |= EF_AWARD_CAP;\n\tother->client->rewardTime = level.time + REWARD_SPRITE_TIME;\n\tother->client->ps.persistant[PERS_CAPTURES]++;\n\n\t// other gets another 10 frag bonus\n\tAddScore(other, ent->r.currentOrigin, CTF_CAPTURE_BONUS);\n\n\tTeam_CaptureFlagSound( ent, team );\n\n\t// Ok, let's do the player loop, hand out the bonuses\n\tfor (i = 0; i < g_maxclients.integer; i++) {\n\t\tplayer = &g_entities[i];\n\t\tif (!player->inuse)\n\t\t\tcontinue;\n\n\t\tif (player->client->sess.sessionTeam !=\n\t\t\tcl->sess.sessionTeam) {\n\t\t\tplayer->client->pers.teamState.lasthurtcarrier = -5;\n\t\t} else if (player->client->sess.sessionTeam ==\n\t\t\tcl->sess.sessionTeam) {\n\t\t\tif (player != other)\n\t\t\t\tAddScore(player, ent->r.currentOrigin, CTF_TEAM_BONUS);\n\t\t\t// award extra points for capture assists\n\t\t\tif (player->client->pers.teamState.lastreturnedflag + \n\t\t\t\tCTF_RETURN_FLAG_ASSIST_TIMEOUT > level.time) {\n\t\t\t\tAddScore (player, ent->r.currentOrigin, CTF_RETURN_FLAG_ASSIST_BONUS);\n\t\t\t\tother->client->pers.teamState.assists++;\n\n\t\t\t\tplayer->client->ps.persistant[PERS_ASSIST_COUNT]++;\n\t\t\t\t// add the sprite over the player's head\n\t\t\t\tplayer->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );\n\t\t\t\tplayer->client->ps.eFlags |= EF_AWARD_ASSIST;\n\t\t\t\tplayer->client->rewardTime = level.time + REWARD_SPRITE_TIME;\n\n\t\t\t} else if (player->client->pers.teamState.lastfraggedcarrier + \n\t\t\t\tCTF_FRAG_CARRIER_ASSIST_TIMEOUT > level.time) {\n\t\t\t\tAddScore(player, ent->r.currentOrigin, CTF_FRAG_CARRIER_ASSIST_BONUS);\n\t\t\t\tother->client->pers.teamState.assists++;\n\t\t\t\tplayer->client->ps.persistant[PERS_ASSIST_COUNT]++;\n\t\t\t\t// add the sprite over the player's head\n\t\t\t\tplayer->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );\n\t\t\t\tplayer->client->ps.eFlags |= EF_AWARD_ASSIST;\n\t\t\t\tplayer->client->rewardTime = level.time + REWARD_SPRITE_TIME;\n\t\t\t}\n\t\t}\n\t}\n\tTeam_ResetFlags();\n\n\tCalculateRanks();\n\n\treturn 0; // Do not respawn this automatically\n}\n\nint Team_TouchEnemyFlag( gentity_t *ent, gentity_t *other, int team ) {\n\tgclient_t *cl = other->client;\n\n\t\tPrintMsg (NULL, \"%s\" S_COLOR_WHITE \" got the %s flag!\\n\",\n\t\t\tother->client->pers.netname, TeamName(team));\n\n\t\tif (team == TEAM_RED)\n\t\t\tcl->ps.powerups[PW_REDFLAG] = INT_MAX; // flags never expire\n\t\telse\n\t\t\tcl->ps.powerups[PW_BLUEFLAG] = INT_MAX; // flags never expire\n\n\t\tTeam_SetFlagStatus( team, FLAG_TAKEN );\n\n\tAddScore(other, ent->r.currentOrigin, CTF_FLAG_BONUS);\n\tcl->pers.teamState.flagsince = level.time;\n\tTeam_TakeFlagSound( ent, team );\n\n\treturn -1; // Do not respawn this automatically, but do delete it if it was FL_DROPPED\n}\n\nint Pickup_Team( gentity_t *ent, gentity_t *other ) {\n\tint team;\n\tgclient_t *cl = other->client;\n\n\t// figure out what team this flag is\n\tif( strcmp(ent->classname, \"team_CTF_redflag\") == 0 ) {\n\t\tteam = TEAM_RED;\n\t}\n\telse if( strcmp(ent->classname, \"team_CTF_blueflag\") == 0 ) {\n\t\tteam = TEAM_BLUE;\n\t}\n\telse {\n\t\tPrintMsg ( other, \"Don't know what team the flag is on.\\n\");\n\t\treturn 0;\n\t}\n\t// GT_CTF\n\tif( team == cl->sess.sessionTeam) {\n\t\treturn Team_TouchOurFlag( ent, other, team );\n\t}\n\treturn Team_TouchEnemyFlag( ent, other, team );\n}\n\n/*\n===========\nTeam_GetLocation\n\nReport a location for the player. Uses placed nearby target_location entities\n============\n*/\ngentity_t *Team_GetLocation(gentity_t *ent)\n{\n\tgentity_t\t\t*eloc, *best;\n\tfloat\t\t\tbestlen, len;\n\tvec3_t\t\t\torigin;\n\n\tbest = NULL;\n\tbestlen = 3*8192.0*8192.0;\n\n\tVectorCopy( ent->r.currentOrigin, origin );\n\n\tfor (eloc = level.locationHead; eloc; eloc = eloc->nextTrain) {\n\t\tlen = ( origin[0] - eloc->r.currentOrigin[0] ) * ( origin[0] - eloc->r.currentOrigin[0] )\n\t\t\t+ ( origin[1] - eloc->r.currentOrigin[1] ) * ( origin[1] - eloc->r.currentOrigin[1] )\n\t\t\t+ ( origin[2] - eloc->r.currentOrigin[2] ) * ( origin[2] - eloc->r.currentOrigin[2] );\n\n\t\tif ( len > bestlen ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif ( !trap_InPVS( origin, eloc->r.currentOrigin ) ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tbestlen = len;\n\t\tbest = eloc;\n\t}\n\n\treturn best;\n}\n\n\n/*\n===========\nTeam_GetLocation\n\nReport a location for the player. Uses placed nearby target_location entities\n============\n*/\nqboolean Team_GetLocationMsg(gentity_t *ent, char *loc, int loclen)\n{\n\tgentity_t *best;\n\n\tbest = Team_GetLocation( ent );\n\t\n\tif (!best)\n\t\treturn qfalse;\n\n\tif (best->count) {\n\t\tif (best->count < 0)\n\t\t\tbest->count = 0;\n\t\tif (best->count > 7)\n\t\t\tbest->count = 7;\n\t\tCom_sprintf(loc, loclen, \"%c%c%s\" S_COLOR_WHITE, Q_COLOR_ESCAPE, best->count + '0', best->message );\n\t} else\n\t\tCom_sprintf(loc, loclen, \"%s\", best->message);\n\n\treturn qtrue;\n}\n\n\n/*---------------------------------------------------------------------------*/\n\n/*\n================\nSelectRandomDeathmatchSpawnPoint\n\ngo to a random point that doesn't telefrag\n================\n*/\n#define\tMAX_TEAM_SPAWN_POINTS\t32\ngentity_t *SelectRandomTeamSpawnPoint( int teamstate, team_t team ) {\n\tgentity_t\t*spot;\n\tint\t\t\tcount;\n\tint\t\t\tselection;\n\tgentity_t\t*spots[MAX_TEAM_SPAWN_POINTS];\n\tchar\t\t*classname;\n\n\tif (teamstate == TEAM_BEGIN) {\n\t\tif (team == TEAM_RED)\n\t\t\tclassname = \"team_CTF_redplayer\";\n\t\telse if (team == TEAM_BLUE)\n\t\t\tclassname = \"team_CTF_blueplayer\";\n\t\telse\n\t\t\treturn NULL;\n\t} else {\n\t\tif (team == TEAM_RED)\n\t\t\tclassname = \"team_CTF_redspawn\";\n\t\telse if (team == TEAM_BLUE)\n\t\t\tclassname = \"team_CTF_bluespawn\";\n\t\telse\n\t\t\treturn NULL;\n\t}\n\tcount = 0;\n\n\tspot = NULL;\n\n\twhile ((spot = G_Find (spot, FOFS(classname), classname)) != NULL) {\n\t\tif ( SpotWouldTelefrag( spot ) ) {\n\t\t\tcontinue;\n\t\t}\n\t\tspots[ count ] = spot;\n\t\tif (++count == MAX_TEAM_SPAWN_POINTS)\n\t\t\tbreak;\n\t}\n\n\tif ( !count ) {\t// no spots that won't telefrag\n\t\treturn G_Find( NULL, FOFS(classname), classname);\n\t}\n\n\tselection = rand() % count;\n\treturn spots[ selection ];\n}\n\n\n/*\n===========\nSelectCTFSpawnPoint\n\n============\n*/\ngentity_t *SelectCTFSpawnPoint ( team_t team, int teamstate, vec3_t origin, vec3_t angles ) {\n\tgentity_t\t*spot;\n\n\tspot = SelectRandomTeamSpawnPoint ( teamstate, team );\n\n\tif (!spot) {\n\t\treturn SelectSpawnPoint( vec3_origin, origin, angles );\n\t}\n\n\tVectorCopy (spot->s.origin, origin);\n\torigin[2] += 9;\n\tVectorCopy (spot->s.angles, angles);\n\n\treturn spot;\n}\n\n/*---------------------------------------------------------------------------*/\n\nstatic int QDECL SortClients( const void *a, const void *b ) {\n\treturn *(int *)a - *(int *)b;\n}\n\n\n/*\n==================\nTeamplayLocationsMessage\n\nFormat:\n\tclientNum location health armor weapon powerups\n\n==================\n*/\nvoid TeamplayInfoMessage( gentity_t *ent ) {\n\tchar\t\tentry[1024];\n\tchar\t\tstring[8192];\n\tint\t\t\tstringlength;\n\tint\t\t\ti, j;\n\tgentity_t\t*player;\n\tint\t\t\tcnt;\n\tint\t\t\th, a;\n\tint\t\t\tclients[TEAM_MAXOVERLAY];\n\n\tif ( ! ent->client->pers.teamInfo )\n\t\treturn;\n\n\t// figure out what client should be on the display\n\t// we are limited to 8, but we want to use the top eight players\n\t// but in client order (so they don't keep changing position on the overlay)\n\tfor (i = 0, cnt = 0; i < g_maxclients.integer && cnt < TEAM_MAXOVERLAY; i++) {\n\t\tplayer = g_entities + level.sortedClients[i];\n\t\tif (player->inuse && player->client->sess.sessionTeam == \n\t\t\tent->client->sess.sessionTeam ) {\n\t\t\tclients[cnt++] = level.sortedClients[i];\n\t\t}\n\t}\n\n\t// We have the top eight players, sort them by clientNum\n\tqsort( clients, cnt, sizeof( clients[0] ), SortClients );\n\n\t// send the latest information on all clients\n\tstring[0] = 0;\n\tstringlength = 0;\n\n\tfor (i = 0, cnt = 0; i < g_maxclients.integer && cnt < TEAM_MAXOVERLAY; i++) {\n\t\tplayer = g_entities + i;\n\t\tif (player->inuse && player->client->sess.sessionTeam == \n\t\t\tent->client->sess.sessionTeam ) {\n\n\t\t\th = player->client->ps.stats[STAT_HEALTH];\n\t\t\ta = player->client->ps.stats[STAT_ARMOR];\n\t\t\tif (h < 0) h = 0;\n\t\t\tif (a < 0) a = 0;\n\n\t\t\tCom_sprintf (entry, sizeof(entry),\n\t\t\t\t\" %i %i %i %i %i %i\", \n//\t\t\t\tlevel.sortedClients[i], player->client->pers.teamState.location, h, a, \n\t\t\t\ti, player->client->pers.teamState.location, h, a, \n\t\t\t\tplayer->client->ps.weapon, player->s.powerups);\n\t\t\tj = (int)strlen(entry);\n\t\t\tif (stringlength + j > sizeof(string))\n\t\t\t\tbreak;\n\t\t\tstrcpy (string + stringlength, entry);\n\t\t\tstringlength += j;\n\t\t\tcnt++;\n\t\t}\n\t}\n\n\ttrap_SendServerCommand( ent-g_entities, va(\"tinfo %i %s\", cnt, string) );\n}\n\nvoid CheckTeamStatus(void) {\n\tint i;\n\tgentity_t *loc, *ent;\n\n\tif (level.time - level.lastTeamLocationTime > TEAM_LOCATION_UPDATE_TIME) {\n\n\t\tlevel.lastTeamLocationTime = level.time;\n\n\t\tfor (i = 0; i < g_maxclients.integer; i++) {\n\t\t\tent = g_entities + i;\n\n\t\t\tif ( ent->client->pers.connected != CON_CONNECTED ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (ent->inuse && (ent->client->sess.sessionTeam == TEAM_RED ||\tent->client->sess.sessionTeam == TEAM_BLUE)) {\n\t\t\t\tloc = Team_GetLocation( ent );\n\t\t\t\tif (loc)\n\t\t\t\t\tent->client->pers.teamState.location = loc->health;\n\t\t\t\telse\n\t\t\t\t\tent->client->pers.teamState.location = 0;\n\t\t\t}\n\t\t}\n\n\t\tfor (i = 0; i < g_maxclients.integer; i++) {\n\t\t\tent = g_entities + i;\n\n\t\t\tif ( ent->client->pers.connected != CON_CONNECTED ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (ent->inuse && (ent->client->sess.sessionTeam == TEAM_RED ||\tent->client->sess.sessionTeam == TEAM_BLUE)) {\n\t\t\t\tTeamplayInfoMessage( ent );\n\t\t\t}\n\t\t}\n\t}\n}\n\n/*-----------------------------------------------------------------*/\n\n/*QUAKED team_CTF_redplayer (1 0 0) (-16 -16 -16) (16 16 32)\nOnly in CTF games.  Red players spawn here at game start.\n*/\nvoid SP_team_CTF_redplayer( gentity_t *ent ) {\n}\n\n\n/*QUAKED team_CTF_blueplayer (0 0 1) (-16 -16 -16) (16 16 32)\nOnly in CTF games.  Blue players spawn here at game start.\n*/\nvoid SP_team_CTF_blueplayer( gentity_t *ent ) {\n}\n\n\n/*QUAKED team_CTF_redspawn (1 0 0) (-16 -16 -24) (16 16 32)\npotential spawning position for red team in CTF games.\nTargets will be fired when someone spawns in on them.\n*/\nvoid SP_team_CTF_redspawn(gentity_t *ent) {\n}\n\n/*QUAKED team_CTF_bluespawn (0 0 1) (-16 -16 -24) (16 16 32)\npotential spawning position for blue team in CTF games.\nTargets will be fired when someone spawns in on them.\n*/\nvoid SP_team_CTF_bluespawn(gentity_t *ent) {\n}\n"
  },
  {
    "path": "src/game/g_team.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n\n#define CTF_CAPTURE_BONUS\t\t5\t\t// what you get for capture\n#define CTF_TEAM_BONUS\t\t\t0\t\t// what your team gets for capture\n#define CTF_RECOVERY_BONUS\t\t1\t\t// what you get for recovery\n#define CTF_FLAG_BONUS\t\t\t0\t\t// what you get for picking up enemy flag\n#define CTF_FRAG_CARRIER_BONUS\t2\t\t// what you get for fragging enemy flag carrier\n#define CTF_FLAG_RETURN_TIME\t40000\t// seconds until auto return\n\n#define CTF_CARRIER_DANGER_PROTECT_BONUS\t2\t// bonus for fraggin someone who has recently hurt your flag carrier\n#define CTF_CARRIER_PROTECT_BONUS\t\t\t1\t// bonus for fraggin someone while either you or your target are near your flag carrier\n#define CTF_FLAG_DEFENSE_BONUS\t\t\t\t1\t// bonus for fraggin someone while either you or your target are near your flag\n#define CTF_RETURN_FLAG_ASSIST_BONUS\t\t1\t// awarded for returning a flag that causes a capture to happen almost immediately\n#define CTF_FRAG_CARRIER_ASSIST_BONUS\t\t2\t// award for fragging a flag carrier if a capture happens almost immediately\n\n#define CTF_TARGET_PROTECT_RADIUS\t\t\t1000\t// the radius around an object being defended where a target will be worth extra frags\n#define CTF_ATTACKER_PROTECT_RADIUS\t\t\t1000\t// the radius around an object being defended where an attacker will get extra frags when making kills\n\n#define CTF_CARRIER_DANGER_PROTECT_TIMEOUT\t8000\n#define CTF_FRAG_CARRIER_ASSIST_TIMEOUT\t\t10000\n#define CTF_RETURN_FLAG_ASSIST_TIMEOUT\t\t10000\n\n#define CTF_GRAPPLE_SPEED\t\t\t\t\t750 // speed of grapple in flight\n#define CTF_GRAPPLE_PULL_SPEED\t\t\t\t750\t// speed player is pulled at\n\n#define OVERLOAD_ATTACK_BASE_SOUND_TIME\t\t20000\n\n// Prototypes\n\nint OtherTeam(int team);\nconst char *TeamName(int team);\nconst char *OtherTeamName(int team);\nconst char *TeamColorString(int team);\nvoid AddTeamScore(vec3_t origin, int team, int score);\n\nvoid Team_DroppedFlagThink(gentity_t *ent);\nvoid Team_FragBonuses(gentity_t *targ, gentity_t *inflictor, gentity_t *attacker);\nvoid Team_CheckHurtCarrier(gentity_t *targ, gentity_t *attacker);\nvoid Team_InitGame(void);\nvoid Team_ReturnFlag(int team);\nvoid Team_FreeEntity(gentity_t *ent);\ngentity_t *SelectCTFSpawnPoint ( team_t team, int teamstate, vec3_t origin, vec3_t angles );\ngentity_t *Team_GetLocation(gentity_t *ent);\nqboolean Team_GetLocationMsg(gentity_t *ent, char *loc, int loclen);\nvoid TeamplayInfoMessage( gentity_t *ent );\nvoid CheckTeamStatus(void);\n\nint Pickup_Team( gentity_t *ent, gentity_t *other );\n"
  },
  {
    "path": "src/game/g_trigger.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n#include \"g_local.h\"\n\n\nvoid InitTrigger( gentity_t *self ) {\n\tif (!VectorCompare (self->s.angles, vec3_origin))\n\t\tG_SetMovedir (self->s.angles, self->movedir);\n\n\ttrap_SetBrushModel( self, self->model );\n\tself->r.contents = CONTENTS_TRIGGER;\t\t// replaces the -1 from trap_SetBrushModel\n\tself->r.svFlags = SVF_NOCLIENT;\n}\n\n\n// the wait time has passed, so set back up for another activation\nvoid multi_wait( gentity_t *ent ) {\n\tent->nextthink = 0;\n}\n\n\n// the trigger was just activated\n// ent->activator should be set to the activator so it can be held through a delay\n// so wait for the delay time before firing\nvoid multi_trigger( gentity_t *ent, gentity_t *activator ) {\n\tent->activator = activator;\n\tif ( ent->nextthink ) {\n\t\treturn;\t\t// can't retrigger until the wait is over\n\t}\n\n\tif ( activator->client ) {\n\t\tif ( ( ent->spawnflags & 1 ) &&\n\t\t\tactivator->client->sess.sessionTeam != TEAM_RED ) {\n\t\t\treturn;\n\t\t}\n\t\tif ( ( ent->spawnflags & 2 ) &&\n\t\t\tactivator->client->sess.sessionTeam != TEAM_BLUE ) {\n\t\t\treturn;\n\t\t}\n\t}\n\n\tG_UseTargets (ent, ent->activator);\n\n\tif ( ent->wait > 0 ) {\n\t\tent->think = multi_wait;\n\t\tent->nextthink = level.time + ( ent->wait + ent->random * crandom() ) * 1000;\n\t} else {\n\t\t// we can't just remove (self) here, because this is a touch function\n\t\t// called while looping through area links...\n\t\tent->touch = 0;\n\t\tent->nextthink = level.time + FRAMETIME;\n\t\tent->think = G_FreeEntity;\n\t}\n}\n\nvoid Use_Multi( gentity_t *ent, gentity_t *other, gentity_t *activator ) {\n\tmulti_trigger( ent, activator );\n}\n\nvoid Touch_Multi( gentity_t *self, gentity_t *other, trace_t *trace ) {\n\tif( !other->client ) {\n\t\treturn;\n\t}\n\tmulti_trigger( self, other );\n}\n\n/*QUAKED trigger_multiple (.5 .5 .5) ?\n\"wait\" : Seconds between triggerings, 0.5 default, -1 = one time only.\n\"random\"\twait variance, default is 0\nVariable sized repeatable trigger.  Must be targeted at one or more entities.\nso, the basic time between firing is a random time between\n(wait - random) and (wait + random)\n*/\nvoid SP_trigger_multiple( gentity_t *ent ) {\n\tG_SpawnFloat( \"wait\", \"0.5\", &ent->wait );\n\tG_SpawnFloat( \"random\", \"0\", &ent->random );\n\n\tif ( ent->random >= ent->wait && ent->wait >= 0 ) {\n\t\tent->random = ent->wait - FRAMETIME;\n\t\tG_Printf( \"trigger_multiple has random >= wait\\n\" );\n\t}\n\n\tent->touch = Touch_Multi;\n\tent->use = Use_Multi;\n\n\tInitTrigger( ent );\n\ttrap_LinkEntity (ent);\n}\n\n\n\n/*\n==============================================================================\n\ntrigger_always\n\n==============================================================================\n*/\n\nvoid trigger_always_think( gentity_t *ent ) {\n\tG_UseTargets(ent, ent);\n\tG_FreeEntity( ent );\n}\n\n/*QUAKED trigger_always (.5 .5 .5) (-8 -8 -8) (8 8 8)\nThis trigger will always fire.  It is activated by the world.\n*/\nvoid SP_trigger_always (gentity_t *ent) {\n\t// we must have some delay to make sure our use targets are present\n\tent->nextthink = level.time + 300;\n\tent->think = trigger_always_think;\n}\n\n\n/*\n==============================================================================\n\ntrigger_push\n\n==============================================================================\n*/\n\nvoid trigger_push_touch (gentity_t *self, gentity_t *other, trace_t *trace ) {\n\n\tif ( !other->client ) {\n\t\treturn;\n\t}\n\n\tBG_TouchJumpPad( &other->client->ps, &self->s );\n}\n\n\n/*\n=================\nAimAtTarget\n\nCalculate origin2 so the target apogee will be hit\n=================\n*/\nvoid AimAtTarget( gentity_t *self ) {\n\tgentity_t\t*ent;\n\tvec3_t\t\torigin;\n\tfloat\t\theight, gravity, time, forward;\n\tfloat\t\tdist;\n\n\tVectorAdd( self->r.absmin, self->r.absmax, origin );\n\tVectorScale ( origin, 0.5, origin );\n\n\tent = G_PickTarget( self->target );\n\tif ( !ent ) {\n\t\tG_FreeEntity( self );\n\t\treturn;\n\t}\n\n\theight = ent->s.origin[2] - origin[2];\n\tgravity = g_gravity.value;\n\ttime = sqrt( height / ( .5 * gravity ) );\n\tif ( !time ) {\n\t\tG_FreeEntity( self );\n\t\treturn;\n\t}\n\n\t// set s.origin2 to the push velocity\n\tVectorSubtract ( ent->s.origin, origin, self->s.origin2 );\n\tself->s.origin2[2] = 0;\n\tdist = VectorNormalize( self->s.origin2);\n\n\tforward = dist / time;\n\tVectorScale( self->s.origin2, forward, self->s.origin2 );\n\n\tself->s.origin2[2] = time * gravity;\n}\n\n\n/*QUAKED trigger_push (.5 .5 .5) ?\nMust point at a target_position, which will be the apex of the leap.\nThis will be client side predicted, unlike target_push\n*/\nvoid SP_trigger_push( gentity_t *self ) {\n\tInitTrigger (self);\n\n\t// unlike other triggers, we need to send this one to the client\n\tself->r.svFlags &= ~SVF_NOCLIENT;\n\n\t// make sure the client precaches this sound\n\tG_SoundIndex(\"sound/world/jumppad.wav\");\n\n\tself->s.eType = ET_PUSH_TRIGGER;\n\tself->touch = trigger_push_touch;\n\tself->think = AimAtTarget;\n\tself->nextthink = level.time + FRAMETIME;\n\ttrap_LinkEntity (self);\n}\n\n\nvoid Use_target_push( gentity_t *self, gentity_t *other, gentity_t *activator ) {\n\tif ( !activator->client ) {\n\t\treturn;\n\t}\n\n\tif ( activator->client->ps.pm_type != PM_NORMAL ) {\n\t\treturn;\n\t}\n\tif ( activator->client->ps.powerups[PW_FLIGHT] ) {\n\t\treturn;\n\t}\n\n\tVectorCopy (self->s.origin2, activator->client->ps.velocity);\n\n\t// play fly sound every 1.5 seconds\n\tif ( activator->fly_sound_debounce_time < level.time ) {\n\t\tactivator->fly_sound_debounce_time = level.time + 1500;\n\t\tG_Sound( activator, CHAN_AUTO, self->noise_index );\n\t}\n}\n\n/*QUAKED target_push (.5 .5 .5) (-8 -8 -8) (8 8 8) bouncepad\nPushes the activator in the direction.of angle, or towards a target apex.\n\"speed\"\t\tdefaults to 1000\nif \"bouncepad\", play bounce noise instead of windfly\n*/\nvoid SP_target_push( gentity_t *self ) {\n\tif (!self->speed) {\n\t\tself->speed = 1000;\n\t}\n\tG_SetMovedir (self->s.angles, self->s.origin2);\n\tVectorScale (self->s.origin2, self->speed, self->s.origin2);\n\n\tif ( self->spawnflags & 1 ) {\n\t\tself->noise_index = G_SoundIndex(\"sound/world/jumppad.wav\");\n\t} else {\n\t\tself->noise_index = G_SoundIndex(\"sound/misc/windfly.wav\");\n\t}\n\tif ( self->target ) {\n\t\tVectorCopy( self->s.origin, self->r.absmin );\n\t\tVectorCopy( self->s.origin, self->r.absmax );\n\t\tself->think = AimAtTarget;\n\t\tself->nextthink = level.time + FRAMETIME;\n\t}\n\tself->use = Use_target_push;\n}\n\n/*\n==============================================================================\n\ntrigger_teleport\n\n==============================================================================\n*/\n\nvoid trigger_teleporter_touch (gentity_t *self, gentity_t *other, trace_t *trace ) {\n\tgentity_t\t*dest;\n\n\tif ( !other->client ) {\n\t\treturn;\n\t}\n\tif ( other->client->ps.pm_type == PM_DEAD ) {\n\t\treturn;\n\t}\n\t// Spectators only?\n\tif ( ( self->spawnflags & 1 ) && \n\t\tother->client->sess.sessionTeam != TEAM_SPECTATOR ) {\n\t\treturn;\n\t}\n\n\n\tdest = \tG_PickTarget( self->target );\n\tif (!dest) {\n\t\tG_Printf (\"Couldn't find teleporter destination\\n\");\n\t\treturn;\n\t}\n\n\tTeleportPlayer( other, dest->s.origin, dest->s.angles );\n}\n\n\n/*QUAKED trigger_teleport (.5 .5 .5) ? SPECTATOR\nAllows client side prediction of teleportation events.\nMust point at a target_position, which will be the teleport destination.\n\nIf spectator is set, only spectators can use this teleport\nSpectator teleporters are not normally placed in the editor, but are created\nautomatically near doors to allow spectators to move through them\n*/\nvoid SP_trigger_teleport( gentity_t *self ) {\n\tInitTrigger (self);\n\n\t// unlike other triggers, we need to send this one to the client\n\t// unless is a spectator trigger\n\tif ( self->spawnflags & 1 ) {\n\t\tself->r.svFlags |= SVF_NOCLIENT;\n\t} else {\n\t\tself->r.svFlags &= ~SVF_NOCLIENT;\n\t}\n\n\t// make sure the client precaches this sound\n\tG_SoundIndex(\"sound/world/jumppad.wav\");\n\n\tself->s.eType = ET_TELEPORT_TRIGGER;\n\tself->touch = trigger_teleporter_touch;\n\n\ttrap_LinkEntity (self);\n}\n\n\n/*\n==============================================================================\n\ntrigger_hurt\n\n==============================================================================\n*/\n\n/*QUAKED trigger_hurt (.5 .5 .5) ? START_OFF - SILENT NO_PROTECTION SLOW\nAny entity that touches this will be hurt.\nIt does dmg points of damage each server frame\nTargeting the trigger will toggle its on / off state.\n\nSILENT\t\t\tsupresses playing the sound\nSLOW\t\t\tchanges the damage rate to once per second\nNO_PROTECTION\t*nothing* stops the damage\n\n\"dmg\"\t\t\tdefault 5 (whole numbers only)\n\n*/\nvoid hurt_use( gentity_t *self, gentity_t *other, gentity_t *activator ) {\n\tif ( self->r.linked ) {\n\t\ttrap_UnlinkEntity( self );\n\t} else {\n\t\ttrap_LinkEntity( self );\n\t}\n}\n\nvoid hurt_touch( gentity_t *self, gentity_t *other, trace_t *trace ) {\n\tint\t\tdflags;\n\n\tif ( !other->takedamage ) {\n\t\treturn;\n\t}\n\n\tif ( self->timestamp > level.time ) {\n\t\treturn;\n\t}\n\n\tif ( self->spawnflags & 16 ) {\n\t\tself->timestamp = level.time + 1000;\n\t} else {\n\t\tself->timestamp = level.time + FRAMETIME;\n\t}\n\n\t// play sound\n\tif ( !(self->spawnflags & 4) ) {\n\t\tG_Sound( other, CHAN_AUTO, self->noise_index );\n\t}\n\n\tif (self->spawnflags & 8)\n\t\tdflags = DAMAGE_NO_PROTECTION;\n\telse\n\t\tdflags = 0;\n\tG_Damage (other, self, self, NULL, NULL, self->damage, dflags, MOD_TRIGGER_HURT);\n}\n\nvoid SP_trigger_hurt( gentity_t *self ) {\n\tInitTrigger (self);\n\n\tself->noise_index = G_SoundIndex( \"sound/world/electro.wav\" );\n\tself->touch = hurt_touch;\n\n\tif ( !self->damage ) {\n\t\tself->damage = 5;\n\t}\n\n\tself->r.contents = CONTENTS_TRIGGER;\n\n\tif ( self->spawnflags & 2 ) {\n\t\tself->use = hurt_use;\n\t}\n\n\t// link in to the world if starting active\n\tif ( ! (self->spawnflags & 1) ) {\n\t\ttrap_LinkEntity (self);\n\t}\n}\n\n\n/*\n==============================================================================\n\ntimer\n\n==============================================================================\n*/\n\n\n/*QUAKED func_timer (0.3 0.1 0.6) (-8 -8 -8) (8 8 8) START_ON\nThis should be renamed trigger_timer...\nRepeatedly fires its targets.\nCan be turned on or off by using.\n\n\"wait\"\t\t\tbase time between triggering all targets, default is 1\n\"random\"\t\twait variance, default is 0\nso, the basic time between firing is a random time between\n(wait - random) and (wait + random)\n\n*/\nvoid func_timer_think( gentity_t *self ) {\n\tG_UseTargets (self, self->activator);\n\t// set time before next firing\n\tself->nextthink = level.time + 1000 * ( self->wait + crandom() * self->random );\n}\n\nvoid func_timer_use( gentity_t *self, gentity_t *other, gentity_t *activator ) {\n\tself->activator = activator;\n\n\t// if on, turn it off\n\tif ( self->nextthink ) {\n\t\tself->nextthink = 0;\n\t\treturn;\n\t}\n\n\t// turn it on\n\tfunc_timer_think (self);\n}\n\nvoid SP_func_timer( gentity_t *self ) {\n\tG_SpawnFloat( \"random\", \"1\", &self->random);\n\tG_SpawnFloat( \"wait\", \"1\", &self->wait );\n\n\tself->use = func_timer_use;\n\tself->think = func_timer_think;\n\n\tif ( self->random >= self->wait ) {\n\t\tself->random = self->wait - FRAMETIME;\n\t\tG_Printf( \"func_timer at %s has random >= wait\\n\", vtos( self->s.origin ) );\n\t}\n\n\tif ( self->spawnflags & 1 ) {\n\t\tself->nextthink = level.time + FRAMETIME;\n\t\tself->activator = self;\n\t}\n\n\tself->r.svFlags = SVF_NOCLIENT;\n}\n\n\n"
  },
  {
    "path": "src/game/g_utils.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n// g_utils.c -- misc utility functions for game module\n\n#include \"g_local.h\"\n\ntypedef struct {\n  char oldShader[MAX_QPATH];\n  char newShader[MAX_QPATH];\n  float timeOffset;\n} shaderRemap_t;\n\n#define MAX_SHADER_REMAPS 128\n\nint remapCount = 0;\nshaderRemap_t remappedShaders[MAX_SHADER_REMAPS];\n\nvoid AddRemap(const char *oldShader, const char *newShader, float timeOffset) {\n\tint i;\n\n\tfor (i = 0; i < remapCount; i++) {\n\t\tif (Q_stricmp(oldShader, remappedShaders[i].oldShader) == 0) {\n\t\t\t// found it, just update this one\n\t\t\tstrcpy(remappedShaders[i].newShader,newShader);\n\t\t\tremappedShaders[i].timeOffset = timeOffset;\n\t\t\treturn;\n\t\t}\n\t}\n\tif (remapCount < MAX_SHADER_REMAPS) {\n\t\tstrcpy(remappedShaders[remapCount].newShader,newShader);\n\t\tstrcpy(remappedShaders[remapCount].oldShader,oldShader);\n\t\tremappedShaders[remapCount].timeOffset = timeOffset;\n\t\tremapCount++;\n\t}\n}\n\nconst char *BuildShaderStateConfig() {\n\tstatic char\tbuff[MAX_STRING_CHARS*4];\n\tchar out[(MAX_QPATH * 2) + 5];\n\tint i;\n  \n\tmemset(buff, 0, MAX_STRING_CHARS);\n\tfor (i = 0; i < remapCount; i++) {\n\t\tCom_sprintf(out, (MAX_QPATH * 2) + 5, \"%s=%s:%5.2f@\", remappedShaders[i].oldShader, remappedShaders[i].newShader, remappedShaders[i].timeOffset);\n\t\tQ_strcat( buff, sizeof( buff ), out);\n\t}\n\treturn buff;\n}\n\n/*\n=========================================================================\n\nmodel / sound configstring indexes\n\n=========================================================================\n*/\n\n/*\n================\nG_FindConfigstringIndex\n\n================\n*/\nint G_FindConfigstringIndex( char *name, int start, int max, qboolean create ) {\n\tint\t\ti;\n\tchar\ts[MAX_STRING_CHARS];\n\n\tif ( !name || !name[0] ) {\n\t\treturn 0;\n\t}\n\n\tfor ( i=1 ; i<max ; i++ ) {\n\t\ttrap_GetConfigstring( start + i, s, sizeof( s ) );\n\t\tif ( !s[0] ) {\n\t\t\tbreak;\n\t\t}\n\t\tif ( !strcmp( s, name ) ) {\n\t\t\treturn i;\n\t\t}\n\t}\n\n\tif ( !create ) {\n\t\treturn 0;\n\t}\n\n\tif ( i == max ) {\n\t\tG_Error( \"G_FindConfigstringIndex: overflow\" );\n\t}\n\n\ttrap_SetConfigstring( start + i, name );\n\n\treturn i;\n}\n\n\nint G_ModelIndex( char *name ) {\n\treturn G_FindConfigstringIndex (name, CS_MODELS, MAX_MODELS, qtrue);\n}\n\nint G_SoundIndex( char *name ) {\n\treturn G_FindConfigstringIndex (name, CS_SOUNDS, MAX_SOUNDS, qtrue);\n}\n\n//=====================================================================\n\n\n/*\n================\nG_TeamCommand\n\nBroadcasts a command to only a specific team\n================\n*/\nvoid G_TeamCommand( team_t team, char *cmd ) {\n\tint\t\ti;\n\n\tfor ( i = 0 ; i < level.maxclients ; i++ ) {\n\t\tif ( level.clients[i].pers.connected == CON_CONNECTED ) {\n\t\t\tif ( level.clients[i].sess.sessionTeam == team ) {\n\t\t\t\ttrap_SendServerCommand( i, va(\"%s\", cmd ));\n\t\t\t}\n\t\t}\n\t}\n}\n\n\n/*\n=============\nG_Find\n\nSearches all active entities for the next one that holds\nthe matching string at fieldofs (use the FOFS() macro) in the structure.\n\nSearches beginning at the entity after from, or the beginning if NULL\nNULL will be returned if the end of the list is reached.\n\n=============\n*/\ngentity_t *G_Find (gentity_t *from, int fieldofs, const char *match)\n{\n\tchar\t*s;\n\n\tif (!from)\n\t\tfrom = g_entities;\n\telse\n\t\tfrom++;\n\n\tfor ( ; from < &g_entities[level.num_entities] ; from++)\n\t{\n\t\tif (!from->inuse)\n\t\t\tcontinue;\n\t\ts = *(char **) ((byte *)from + fieldofs);\n\t\tif (!s)\n\t\t\tcontinue;\n\t\tif (!Q_stricmp (s, match))\n\t\t\treturn from;\n\t}\n\n\treturn NULL;\n}\n\n\n/*\n=============\nG_PickTarget\n\nSelects a random entity from among the targets\n=============\n*/\n#define MAXCHOICES\t32\n\ngentity_t *G_PickTarget (char *targetname)\n{\n\tgentity_t\t*ent = NULL;\n\tint\t\tnum_choices = 0;\n\tgentity_t\t*choice[MAXCHOICES];\n\n\tif (!targetname)\n\t{\n\t\tG_Printf(\"G_PickTarget called with NULL targetname\\n\");\n\t\treturn NULL;\n\t}\n\n\twhile(1)\n\t{\n\t\tent = G_Find (ent, FOFS(targetname), targetname);\n\t\tif (!ent)\n\t\t\tbreak;\n\t\tchoice[num_choices++] = ent;\n\t\tif (num_choices == MAXCHOICES)\n\t\t\tbreak;\n\t}\n\n\tif (!num_choices)\n\t{\n\t\tG_Printf(\"G_PickTarget: target %s not found\\n\", targetname);\n\t\treturn NULL;\n\t}\n\n\treturn choice[rand() % num_choices];\n}\n\n\n/*\n==============================\nG_UseTargets\n\n\"activator\" should be set to the entity that initiated the firing.\n\nSearch for (string)targetname in all entities that\nmatch (string)self.target and call their .use function\n\n==============================\n*/\nvoid G_UseTargets( gentity_t *ent, gentity_t *activator ) {\n\tgentity_t\t\t*t;\n\t\n\tif ( !ent ) {\n\t\treturn;\n\t}\n\n\tif (ent->targetShaderName && ent->targetShaderNewName) {\n\t\tfloat f = level.time * 0.001;\n\t\tAddRemap(ent->targetShaderName, ent->targetShaderNewName, f);\n\t\ttrap_SetConfigstring(CS_SHADERSTATE, BuildShaderStateConfig());\n\t}\n\n\tif ( !ent->target ) {\n\t\treturn;\n\t}\n\n\tt = NULL;\n\twhile ( (t = G_Find (t, FOFS(targetname), ent->target)) != NULL ) {\n\t\tif ( t == ent ) {\n\t\t\tG_Printf (\"WARNING: Entity used itself.\\n\");\n\t\t} else {\n\t\t\tif ( t->use ) {\n\t\t\t\tt->use (t, ent, activator);\n\t\t\t}\n\t\t}\n\t\tif ( !ent->inuse ) {\n\t\t\tG_Printf(\"entity was removed while using targets\\n\");\n\t\t\treturn;\n\t\t}\n\t}\n}\n\n\n/*\n=============\nTempVector\n\nThis is just a convenience function\nfor making temporary vectors for function calls\n=============\n*/\nfloat\t*tv( float x, float y, float z ) {\n\tstatic\tint\t\tindex;\n\tstatic\tvec3_t\tvecs[8];\n\tfloat\t*v;\n\n\t// use an array so that multiple tempvectors won't collide\n\t// for a while\n\tv = vecs[index];\n\tindex = (index + 1)&7;\n\n\tv[0] = x;\n\tv[1] = y;\n\tv[2] = z;\n\n\treturn v;\n}\n\n\n/*\n=============\nVectorToString\n\nThis is just a convenience function\nfor printing vectors\n=============\n*/\nchar\t*vtos( const vec3_t v ) {\n\tstatic\tint\t\tindex;\n\tstatic\tchar\tstr[8][32];\n\tchar\t*s;\n\n\t// use an array so that multiple vtos won't collide\n\ts = str[index];\n\tindex = (index + 1)&7;\n\n\tCom_sprintf (s, 32, \"(%i %i %i)\", (int)v[0], (int)v[1], (int)v[2]);\n\n\treturn s;\n}\n\n\n/*\n===============\nG_SetMovedir\n\nThe editor only specifies a single value for angles (yaw),\nbut we have special constants to generate an up or down direction.\nAngles will be cleared, because it is being used to represent a direction\ninstead of an orientation.\n===============\n*/\nvoid G_SetMovedir( vec3_t angles, vec3_t movedir ) {\n\tstatic vec3_t VEC_UP\t\t= {0, -1, 0};\n\tstatic vec3_t MOVEDIR_UP\t= {0, 0, 1};\n\tstatic vec3_t VEC_DOWN\t\t= {0, -2, 0};\n\tstatic vec3_t MOVEDIR_DOWN\t= {0, 0, -1};\n\n\tif ( VectorCompare (angles, VEC_UP) ) {\n\t\tVectorCopy (MOVEDIR_UP, movedir);\n\t} else if ( VectorCompare (angles, VEC_DOWN) ) {\n\t\tVectorCopy (MOVEDIR_DOWN, movedir);\n\t} else {\n\t\tAngleVectors (angles, movedir, NULL, NULL);\n\t}\n\tVectorClear( angles );\n}\n\n\nfloat vectoyaw( const vec3_t vec ) {\n\tfloat\tyaw;\n\t\n\tif (vec[YAW] == 0 && vec[PITCH] == 0) {\n\t\tyaw = 0;\n\t} else {\n\t\tif (vec[PITCH]) {\n\t\t\tyaw = ( atan2( vec[YAW], vec[PITCH]) * 180 / M_PI );\n\t\t} else if (vec[YAW] > 0) {\n\t\t\tyaw = 90;\n\t\t} else {\n\t\t\tyaw = 270;\n\t\t}\n\t\tif (yaw < 0) {\n\t\t\tyaw += 360;\n\t\t}\n\t}\n\n\treturn yaw;\n}\n\n\nvoid G_InitGentity( gentity_t *e ) {\n\te->inuse = qtrue;\n\te->classname = \"noclass\";\n\te->s.number = e - g_entities;\n\te->r.ownerNum = ENTITYNUM_NONE;\n}\n\n/*\n=================\nG_Spawn\n\nEither finds a free entity, or allocates a new one.\n\n  The slots from 0 to MAX_CLIENTS-1 are always reserved for clients, and will\nnever be used by anything else.\n\nTry to avoid reusing an entity that was recently freed, because it\ncan cause the client to think the entity morphed into something else\ninstead of being removed and recreated, which can cause interpolated\nangles and bad trails.\n=================\n*/\ngentity_t *G_Spawn( void ) {\n\tint\t\t\ti, force;\n\tgentity_t\t*e;\n\n\te = NULL;\t// shut up warning\n\ti = 0;\t\t// shut up warning\n\tfor ( force = 0 ; force < 2 ; force++ ) {\n\t\t// if we go through all entities and can't find one to free,\n\t\t// override the normal minimum times before use\n\t\te = &g_entities[MAX_CLIENTS];\n\t\tfor ( i = MAX_CLIENTS ; i<level.num_entities ; i++, e++) {\n\t\t\tif ( e->inuse ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// the first couple seconds of server time can involve a lot of\n\t\t\t// freeing and allocating, so relax the replacement policy\n\t\t\tif ( !force && e->freetime > level.startTime + 2000 && level.time - e->freetime < 1000 ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// reuse this slot\n\t\t\tG_InitGentity( e );\n\t\t\treturn e;\n\t\t}\n\t\tif ( i != MAX_GENTITIES ) {\n\t\t\tbreak;\n\t\t}\n\t}\n\tif ( i == ENTITYNUM_MAX_NORMAL ) {\n\t\tfor (i = 0; i < MAX_GENTITIES; i++) {\n\t\t\tG_Printf(\"%4i: %s\\n\", i, g_entities[i].classname);\n\t\t}\n\t\tG_Error( \"G_Spawn: no free entities\" );\n\t}\n\t\n\t// open up a new slot\n\tlevel.num_entities++;\n\n\t// let the server system know that there are more entities\n\ttrap_LocateGameData( level.gentities, level.num_entities, sizeof( gentity_t ), \n\t\t&level.clients[0].ps, sizeof( level.clients[0] ) );\n\n\tG_InitGentity( e );\n\treturn e;\n}\n\n/*\n=================\nG_EntitiesFree\n=================\n*/\nqboolean G_EntitiesFree( void ) {\n\tint\t\t\ti;\n\tgentity_t\t*e;\n\n\te = &g_entities[MAX_CLIENTS];\n\tfor ( i = MAX_CLIENTS; i < level.num_entities; i++, e++) {\n\t\tif ( e->inuse ) {\n\t\t\tcontinue;\n\t\t}\n\t\t// slot available\n\t\treturn qtrue;\n\t}\n\treturn qfalse;\n}\n\n\n/*\n=================\nG_FreeEntity\n\nMarks the entity as free\n=================\n*/\nvoid G_FreeEntity( gentity_t *ed ) {\n\ttrap_UnlinkEntity (ed);\t\t// unlink from world\n\n\tif ( ed->neverFree ) {\n\t\treturn;\n\t}\n\n\tmemset (ed, 0, sizeof(*ed));\n\ted->classname = \"freed\";\n\ted->freetime = level.time;\n\ted->inuse = qfalse;\n}\n\n/*\n=================\nG_TempEntity\n\nSpawns an event entity that will be auto-removed\nThe origin will be snapped to save net bandwidth, so care\nmust be taken if the origin is right on a surface (snap towards start vector first)\n=================\n*/\ngentity_t *G_TempEntity( vec3_t origin, int event ) {\n\tgentity_t\t\t*e;\n\tvec3_t\t\tsnapped;\n\n\te = G_Spawn();\n\te->s.eType = ET_EVENTS + event;\n\n\te->classname = \"tempEntity\";\n\te->eventTime = level.time;\n\te->freeAfterEvent = qtrue;\n\n\tVectorCopy( origin, snapped );\n\tSnapVector( snapped );\t\t// save network bandwidth\n\tG_SetOrigin( e, snapped );\n\n\t// find cluster for PVS\n\ttrap_LinkEntity( e );\n\n\treturn e;\n}\n\n\n\n/*\n==============================================================================\n\nKill box\n\n==============================================================================\n*/\n\n/*\n=================\nG_KillBox\n\nKills all entities that would touch the proposed new positioning\nof ent.  Ent should be unlinked before calling this!\n=================\n*/\nvoid G_KillBox (gentity_t *ent) {\n\tint\t\t\ti, num;\n\tint\t\t\ttouch[MAX_GENTITIES];\n\tgentity_t\t*hit;\n\tvec3_t\t\tmins, maxs;\n\n\tVectorAdd( ent->client->ps.origin, ent->r.mins, mins );\n\tVectorAdd( ent->client->ps.origin, ent->r.maxs, maxs );\n\tnum = trap_EntitiesInBox( mins, maxs, touch, MAX_GENTITIES );\n\n\tfor (i=0 ; i<num ; i++) {\n\t\thit = &g_entities[touch[i]];\n\t\tif ( !hit->client ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// nail it\n\t\tG_Damage ( hit, ent, ent, NULL, NULL,\n\t\t\t100000, DAMAGE_NO_PROTECTION, MOD_TELEFRAG);\n\t}\n\n}\n\n//==============================================================================\n\n/*\n===============\nG_AddPredictableEvent\n\nUse for non-pmove events that would also be predicted on the\nclient side: jumppads and item pickups\nAdds an event+parm and twiddles the event counter\n===============\n*/\nvoid G_AddPredictableEvent( gentity_t *ent, int event, int eventParm ) {\n\tif ( !ent->client ) {\n\t\treturn;\n\t}\n\tBG_AddPredictableEventToPlayerstate( event, eventParm, &ent->client->ps );\n}\n\n\n/*\n===============\nG_AddEvent\n\nAdds an event+parm and twiddles the event counter\n===============\n*/\nvoid G_AddEvent( gentity_t *ent, int event, int eventParm ) {\n\tint\t\tbits;\n\n\tif ( !event ) {\n\t\tG_Printf( \"G_AddEvent: zero event added for entity %i\\n\", ent->s.number );\n\t\treturn;\n\t}\n\n\t// clients need to add the event in playerState_t instead of entityState_t\n\tif ( ent->client ) {\n\t\tbits = ent->client->ps.externalEvent & EV_EVENT_BITS;\n\t\tbits = ( bits + EV_EVENT_BIT1 ) & EV_EVENT_BITS;\n\t\tent->client->ps.externalEvent = event | bits;\n\t\tent->client->ps.externalEventParm = eventParm;\n\t\tent->client->ps.externalEventTime = level.time;\n\t} else {\n\t\tbits = ent->s.event & EV_EVENT_BITS;\n\t\tbits = ( bits + EV_EVENT_BIT1 ) & EV_EVENT_BITS;\n\t\tent->s.event = event | bits;\n\t\tent->s.eventParm = eventParm;\n\t}\n\tent->eventTime = level.time;\n}\n\n\n/*\n=============\nG_Sound\n=============\n*/\nvoid G_Sound( gentity_t *ent, int channel, int soundIndex ) {\n\tgentity_t\t*te;\n\n\tte = G_TempEntity( ent->r.currentOrigin, EV_GENERAL_SOUND );\n\tte->s.eventParm = soundIndex;\n}\n\n\n//==============================================================================\n\n\n/*\n================\nG_SetOrigin\n\nSets the pos trajectory for a fixed position\n================\n*/\nvoid G_SetOrigin( gentity_t *ent, vec3_t origin ) {\n\tVectorCopy( origin, ent->s.pos.trBase );\n\tent->s.pos.trType = TR_STATIONARY;\n\tent->s.pos.trTime = 0;\n\tent->s.pos.trDuration = 0;\n\tVectorClear( ent->s.pos.trDelta );\n\n\tVectorCopy( origin, ent->r.currentOrigin );\n}\n\n/*\n================\nDebugLine\n\n  debug polygons only work when running a local game\n  with r_debugSurface set to 2\n================\n*/\nint DebugLine(vec3_t start, vec3_t end, int color) {\n\tvec3_t points[4], dir, cross, up = {0, 0, 1};\n\tfloat dot;\n\n\tVectorCopy(start, points[0]);\n\tVectorCopy(start, points[1]);\n\t//points[1][2] -= 2;\n\tVectorCopy(end, points[2]);\n\t//points[2][2] -= 2;\n\tVectorCopy(end, points[3]);\n\n\n\tVectorSubtract(end, start, dir);\n\tVectorNormalize(dir);\n\tdot = DotProduct(dir, up);\n\tif (dot > 0.99 || dot < -0.99) VectorSet(cross, 1, 0, 0);\n\telse CrossProduct(dir, up, cross);\n\n\tVectorNormalize(cross);\n\n\tVectorMA(points[0], 2, cross, points[0]);\n\tVectorMA(points[1], -2, cross, points[1]);\n\tVectorMA(points[2], -2, cross, points[2]);\n\tVectorMA(points[3], 2, cross, points[3]);\n\n\treturn trap_DebugPolygonCreate(color, 4, points);\n}\n"
  },
  {
    "path": "src/game/g_weapon.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n// g_weapon.c \n// perform the server side effects of a weapon firing\n\n#include \"g_local.h\"\n\nstatic\tfloat\ts_quadFactor;\nstatic\tvec3_t\tforward, right, up;\nstatic\tvec3_t\tmuzzle;\n\n#define NUM_NAILSHOTS 15\n\n/*\n================\nG_BounceProjectile\n================\n*/\nvoid G_BounceProjectile( vec3_t start, vec3_t impact, vec3_t dir, vec3_t endout ) {\n\tvec3_t v, newv;\n\tfloat dot;\n\n\tVectorSubtract( impact, start, v );\n\tdot = DotProduct( v, dir );\n\tVectorMA( v, -2*dot, dir, newv );\n\n\tVectorNormalize(newv);\n\tVectorMA(impact, 8192, newv, endout);\n}\n\n\n/*\n======================================================================\n\nGAUNTLET\n\n======================================================================\n*/\n\nvoid Weapon_Gauntlet( gentity_t *ent ) {\n\n}\n\n/*\n===============\nCheckGauntletAttack\n===============\n*/\nqboolean CheckGauntletAttack( gentity_t *ent ) {\n\ttrace_t\t\ttr;\n\tvec3_t\t\tend;\n\tgentity_t\t*tent;\n\tgentity_t\t*traceEnt;\n\tint\t\t\tdamage;\n\n\t// set aiming directions\n\tAngleVectors (ent->client->ps.viewangles, forward, right, up);\n\n\tCalcMuzzlePoint ( ent, forward, right, up, muzzle );\n\n\tVectorMA (muzzle, 32, forward, end);\n\n\ttrap_Trace (&tr, muzzle, NULL, NULL, end, ent->s.number, MASK_SHOT);\n\tif ( tr.surfaceFlags & SURF_NOIMPACT ) {\n\t\treturn qfalse;\n\t}\n\n\ttraceEnt = &g_entities[ tr.entityNum ];\n\n\t// send blood impact\n\tif ( traceEnt->takedamage && traceEnt->client ) {\n\t\ttent = G_TempEntity( tr.endpos, EV_MISSILE_HIT );\n\t\ttent->s.otherEntityNum = traceEnt->s.number;\n\t\ttent->s.eventParm = DirToByte( tr.plane.normal );\n\t\ttent->s.weapon = ent->s.weapon;\n\t}\n\n\tif ( !traceEnt->takedamage) {\n\t\treturn qfalse;\n\t}\n\n\tif (ent->client->ps.powerups[PW_QUAD] ) {\n\t\tG_AddEvent( ent, EV_POWERUP_QUAD, 0 );\n\t\ts_quadFactor = g_quadfactor.value;\n\t} else {\n\t\ts_quadFactor = 1;\n\t}\n\n\tdamage = 50 * s_quadFactor;\n\tG_Damage( traceEnt, ent, ent, forward, tr.endpos,\n\t\tdamage, 0, MOD_GAUNTLET );\n\n\treturn qtrue;\n}\n\n\n/*\n======================================================================\n\nMACHINEGUN\n\n======================================================================\n*/\n\n/*\n======================\nSnapVectorTowards\n\nRound a vector to integers for more efficient network\ntransmission, but make sure that it rounds towards a given point\nrather than blindly truncating.  This prevents it from truncating \ninto a wall.\n======================\n*/\nvoid SnapVectorTowards( vec3_t v, vec3_t to ) {\n\tint\t\ti;\n\n\tfor ( i = 0 ; i < 3 ; i++ ) {\n\t\tif ( to[i] <= v[i] ) {\n\t\t\tv[i] = (int)v[i];\n\t\t} else {\n\t\t\tv[i] = (int)v[i] + 1;\n\t\t}\n\t}\n}\n\n#define MACHINEGUN_SPREAD\t200\n#define\tMACHINEGUN_DAMAGE\t7\n#define\tMACHINEGUN_TEAM_DAMAGE\t5\t\t// wimpier MG in teamplay\n\nvoid Bullet_Fire (gentity_t *ent, float spread, int damage ) {\n\ttrace_t\t\ttr;\n\tvec3_t\t\tend;\n\tfloat\t\tr;\n\tfloat\t\tu;\n\tgentity_t\t*tent;\n\tgentity_t\t*traceEnt;\n\tint\t\t\ti, passent;\n\n\tdamage *= s_quadFactor;\n\n\tr = random() * M_PI * 2.0f;\n\tu = sin(r) * crandom() * spread * 16;\n\tr = cos(r) * crandom() * spread * 16;\n\tVectorMA (muzzle, 8192*16, forward, end);\n\tVectorMA (end, r, right, end);\n\tVectorMA (end, u, up, end);\n\n\tpassent = ent->s.number;\n\tfor (i = 0; i < 10; i++) {\n\n\t\ttrap_Trace (&tr, muzzle, NULL, NULL, end, passent, MASK_SHOT);\n\t\tif ( tr.surfaceFlags & SURF_NOIMPACT ) {\n\t\t\treturn;\n\t\t}\n\n\t\ttraceEnt = &g_entities[ tr.entityNum ];\n\n\t\t// snap the endpos to integers, but nudged towards the line\n\t\tSnapVectorTowards( tr.endpos, muzzle );\n\n\t\t// send bullet impact\n\t\tif ( traceEnt->takedamage && traceEnt->client ) {\n\t\t\ttent = G_TempEntity( tr.endpos, EV_BULLET_HIT_FLESH );\n\t\t\ttent->s.eventParm = traceEnt->s.number;\n\t\t\tif( LogAccuracyHit( traceEnt, ent ) ) {\n\t\t\t\tent->client->accuracy_hits++;\n\t\t\t}\n\t\t} else {\n\t\t\ttent = G_TempEntity( tr.endpos, EV_BULLET_HIT_WALL );\n\t\t\ttent->s.eventParm = DirToByte( tr.plane.normal );\n\t\t}\n\t\ttent->s.otherEntityNum = ent->s.number;\n\n\t\tif ( traceEnt->takedamage) {\n\t\t\t\tG_Damage( traceEnt, ent, ent, forward, tr.endpos,\n\t\t\t\t\tdamage, 0, MOD_MACHINEGUN);\n\t\t}\n\t\tbreak;\n\t}\n}\n\n\n/*\n======================================================================\n\nBFG\n\n======================================================================\n*/\n\nvoid BFG_Fire ( gentity_t *ent ) {\n\tgentity_t\t*m;\n\n\tm = fire_bfg (ent, muzzle, forward);\n\tm->damage *= s_quadFactor;\n\tm->splashDamage *= s_quadFactor;\n\n//\tVectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta );\t// \"real\" physics\n}\n\n\n/*\n======================================================================\n\nSHOTGUN\n\n======================================================================\n*/\n\n// DEFAULT_SHOTGUN_SPREAD and DEFAULT_SHOTGUN_COUNT\tare in bg_public.h, because\n// client predicts same spreads\n#define\tDEFAULT_SHOTGUN_DAMAGE\t10\n\nqboolean ShotgunPellet( vec3_t start, vec3_t end, gentity_t *ent ) {\n\ttrace_t\t\ttr;\n\tint\t\t\tdamage, i, passent;\n\tgentity_t\t*traceEnt;\n\tvec3_t\t\ttr_start, tr_end;\n\n\tpassent = ent->s.number;\n\tVectorCopy( start, tr_start );\n\tVectorCopy( end, tr_end );\n\tfor (i = 0; i < 10; i++) {\n\t\ttrap_Trace (&tr, tr_start, NULL, NULL, tr_end, passent, MASK_SHOT);\n\t\ttraceEnt = &g_entities[ tr.entityNum ];\n\n\t\t// send bullet impact\n\t\tif (  tr.surfaceFlags & SURF_NOIMPACT ) {\n\t\t\treturn qfalse;\n\t\t}\n\n\t\tif ( traceEnt->takedamage) {\n\t\t\tdamage = DEFAULT_SHOTGUN_DAMAGE * s_quadFactor;\n\t\t\tG_Damage( traceEnt, ent, ent, forward, tr.endpos,\tdamage, 0, MOD_SHOTGUN);\n\t\t\t\tif( LogAccuracyHit( traceEnt, ent ) ) {\n\t\t\t\t\treturn qtrue;\n\t\t\t\t}\n\t\t}\n\t\treturn qfalse;\n\t}\n\treturn qfalse;\n}\n\n// this should match CG_ShotgunPattern\nvoid ShotgunPattern( vec3_t origin, vec3_t origin2, int seed, gentity_t *ent ) {\n\tint\t\t\ti;\n\tfloat\t\tr, u;\n\tvec3_t\t\tend;\n\tvec3_t\t\tforward, right, up;\n\tint\t\t\toldScore;\n\tqboolean\thitClient = qfalse;\n\n\t// derive the right and up vectors from the forward vector, because\n\t// the client won't have any other information\n\tVectorNormalize2( origin2, forward );\n\tPerpendicularVector( right, forward );\n\tCrossProduct( forward, right, up );\n\n\toldScore = ent->client->ps.persistant[PERS_SCORE];\n\n\t// generate the \"random\" spread pattern\n\tfor ( i = 0 ; i < DEFAULT_SHOTGUN_COUNT ; i++ ) {\n\t\tr = Q_crandom( &seed ) * DEFAULT_SHOTGUN_SPREAD * 16;\n\t\tu = Q_crandom( &seed ) * DEFAULT_SHOTGUN_SPREAD * 16;\n\t\tVectorMA( origin, 8192 * 16, forward, end);\n\t\tVectorMA (end, r, right, end);\n\t\tVectorMA (end, u, up, end);\n\t\tif( ShotgunPellet( origin, end, ent ) && !hitClient ) {\n\t\t\thitClient = qtrue;\n\t\t\tent->client->accuracy_hits++;\n\t\t}\n\t}\n}\n\n\nvoid weapon_supershotgun_fire (gentity_t *ent) {\n\tgentity_t\t\t*tent;\n\n\t// send shotgun blast\n\ttent = G_TempEntity( muzzle, EV_SHOTGUN );\n\tVectorScale( forward, 4096, tent->s.origin2 );\n\tSnapVector( tent->s.origin2 );\n\ttent->s.eventParm = rand() & 255;\t\t// seed for spread pattern\n\ttent->s.otherEntityNum = ent->s.number;\n\n\tShotgunPattern( tent->s.pos.trBase, tent->s.origin2, tent->s.eventParm, ent );\n}\n\n\n/*\n======================================================================\n\nGRENADE LAUNCHER\n\n======================================================================\n*/\n\nvoid weapon_grenadelauncher_fire (gentity_t *ent) {\n\tgentity_t\t*m;\n\n\t// extra vertical velocity\n\tforward[2] += 0.2f;\n\tVectorNormalize( forward );\n\n\tm = fire_grenade (ent, muzzle, forward);\n\tm->damage *= s_quadFactor;\n\tm->splashDamage *= s_quadFactor;\n\n//\tVectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta );\t// \"real\" physics\n}\n\n/*\n======================================================================\n\nROCKET\n\n======================================================================\n*/\n\nvoid Weapon_RocketLauncher_Fire (gentity_t *ent) {\n\tgentity_t\t*m;\n\n\tm = fire_rocket (ent, muzzle, forward);\n\tm->damage *= s_quadFactor;\n\tm->splashDamage *= s_quadFactor;\n\n//\tVectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta );\t// \"real\" physics\n}\n\n\n/*\n======================================================================\n\nPLASMA GUN\n\n======================================================================\n*/\n\nvoid Weapon_Plasmagun_Fire (gentity_t *ent) {\n\tgentity_t\t*m;\n\n\tm = fire_plasma (ent, muzzle, forward);\n\tm->damage *= s_quadFactor;\n\tm->splashDamage *= s_quadFactor;\n\n//\tVectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta );\t// \"real\" physics\n}\n\n/*\n======================================================================\n\nRAILGUN\n\n======================================================================\n*/\n\n\n/*\n=================\nweapon_railgun_fire\n=================\n*/\n#define\tMAX_RAIL_HITS\t4\nvoid weapon_railgun_fire (gentity_t *ent) {\n\tvec3_t\t\tend;\n\ttrace_t\t\ttrace;\n\tgentity_t\t*tent;\n\tgentity_t\t*traceEnt;\n\tint\t\t\tdamage;\n\tint\t\t\ti;\n\tint\t\t\thits;\n\tint\t\t\tunlinked;\n\tint\t\t\tpassent;\n\tgentity_t\t*unlinkedEntities[MAX_RAIL_HITS];\n\n\tdamage = 100 * s_quadFactor;\n\n\tVectorMA (muzzle, 8192, forward, end);\n\n\t// trace only against the solids, so the railgun will go through people\n\tunlinked = 0;\n\thits = 0;\n\tpassent = ent->s.number;\n\tdo {\n\t\ttrap_Trace (&trace, muzzle, NULL, NULL, end, passent, MASK_SHOT );\n\t\tif ( trace.entityNum >= ENTITYNUM_MAX_NORMAL ) {\n\t\t\tbreak;\n\t\t}\n\t\ttraceEnt = &g_entities[ trace.entityNum ];\n\t\tif ( traceEnt->takedamage ) {\n\t\t\t\tif( LogAccuracyHit( traceEnt, ent ) ) {\n\t\t\t\t\thits++;\n\t\t\t\t}\n\t\t\t\tG_Damage (traceEnt, ent, ent, forward, trace.endpos, damage, 0, MOD_RAILGUN);\n\t\t}\n\t\tif ( trace.contents & CONTENTS_SOLID ) {\n\t\t\tbreak;\t\t// we hit something solid enough to stop the beam\n\t\t}\n\t\t// unlink this entity, so the next trace will go past it\n\t\ttrap_UnlinkEntity( traceEnt );\n\t\tunlinkedEntities[unlinked] = traceEnt;\n\t\tunlinked++;\n\t} while ( unlinked < MAX_RAIL_HITS );\n\n\t// link back in any entities we unlinked\n\tfor ( i = 0 ; i < unlinked ; i++ ) {\n\t\ttrap_LinkEntity( unlinkedEntities[i] );\n\t}\n\n\t// the final trace endpos will be the terminal point of the rail trail\n\n\t// snap the endpos to integers to save net bandwidth, but nudged towards the line\n\tSnapVectorTowards( trace.endpos, muzzle );\n\n\t// send railgun beam effect\n\ttent = G_TempEntity( trace.endpos, EV_RAILTRAIL );\n\n\t// set player number for custom colors on the railtrail\n\ttent->s.clientNum = ent->s.clientNum;\n\n\tVectorCopy( muzzle, tent->s.origin2 );\n\t// move origin a bit to come closer to the drawn gun muzzle\n\tVectorMA( tent->s.origin2, 4, right, tent->s.origin2 );\n\tVectorMA( tent->s.origin2, -1, up, tent->s.origin2 );\n\n\t// no explosion at end if SURF_NOIMPACT, but still make the trail\n\tif ( trace.surfaceFlags & SURF_NOIMPACT ) {\n\t\ttent->s.eventParm = 255;\t// don't make the explosion at the end\n\t} else {\n\t\ttent->s.eventParm = DirToByte( trace.plane.normal );\n\t}\n\ttent->s.clientNum = ent->s.clientNum;\n\n\t// give the shooter a reward sound if they have made two railgun hits in a row\n\tif ( hits == 0 ) {\n\t\t// complete miss\n\t\tent->client->accurateCount = 0;\n\t} else {\n\t\t// check for \"impressive\" reward sound\n\t\tent->client->accurateCount += hits;\n\t\tif ( ent->client->accurateCount >= 2 ) {\n\t\t\tent->client->accurateCount -= 2;\n\t\t\tent->client->ps.persistant[PERS_IMPRESSIVE_COUNT]++;\n\t\t\t// add the sprite over the player's head\n\t\t\tent->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );\n\t\t\tent->client->ps.eFlags |= EF_AWARD_IMPRESSIVE;\n\t\t\tent->client->rewardTime = level.time + REWARD_SPRITE_TIME;\n\t\t}\n\t\tent->client->accuracy_hits++;\n\t}\n\n}\n\n\n/*\n======================================================================\n\nGRAPPLING HOOK\n\n======================================================================\n*/\n\nvoid Weapon_GrapplingHook_Fire (gentity_t *ent)\n{\n\tif (!ent->client->fireHeld && !ent->client->hook)\n\t\tfire_grapple (ent, muzzle, forward);\n\n\tent->client->fireHeld = qtrue;\n}\n\nvoid Weapon_HookFree (gentity_t *ent)\n{\n\tent->parent->client->hook = NULL;\n\tent->parent->client->ps.pm_flags &= ~PMF_GRAPPLE_PULL;\n\tG_FreeEntity( ent );\n}\n\nvoid Weapon_HookThink (gentity_t *ent)\n{\n\tif (ent->enemy) {\n\t\tvec3_t v, oldorigin;\n\n\t\tVectorCopy(ent->r.currentOrigin, oldorigin);\n\t\tv[0] = ent->enemy->r.currentOrigin[0] + (ent->enemy->r.mins[0] + ent->enemy->r.maxs[0]) * 0.5;\n\t\tv[1] = ent->enemy->r.currentOrigin[1] + (ent->enemy->r.mins[1] + ent->enemy->r.maxs[1]) * 0.5;\n\t\tv[2] = ent->enemy->r.currentOrigin[2] + (ent->enemy->r.mins[2] + ent->enemy->r.maxs[2]) * 0.5;\n\t\tSnapVectorTowards( v, oldorigin );\t// save net bandwidth\n\n\t\tG_SetOrigin( ent, v );\n\t}\n\n\tVectorCopy( ent->r.currentOrigin, ent->parent->client->ps.grapplePoint);\n}\n\n/*\n======================================================================\n\nLIGHTNING GUN\n\n======================================================================\n*/\n\nvoid Weapon_LightningFire( gentity_t *ent ) {\n\ttrace_t\t\ttr;\n\tvec3_t\t\tend;\n\tgentity_t\t*traceEnt, *tent;\n\tint\t\t\tdamage, i, passent;\n\n\tdamage = 8 * s_quadFactor;\n\n\tpassent = ent->s.number;\n\tfor (i = 0; i < 10; i++) {\n\t\tVectorMA( muzzle, LIGHTNING_RANGE, forward, end );\n\n\t\ttrap_Trace( &tr, muzzle, NULL, NULL, end, passent, MASK_SHOT );\n\n\t\tif ( tr.entityNum == ENTITYNUM_NONE ) {\n\t\t\treturn;\n\t\t}\n\n\t\ttraceEnt = &g_entities[ tr.entityNum ];\n\n\t\tif ( traceEnt->takedamage) {\n\t\t\t\tG_Damage( traceEnt, ent, ent, forward, tr.endpos,\n\t\t\t\t\tdamage, 0, MOD_LIGHTNING);\n\t\t}\n\n\t\tif ( traceEnt->takedamage && traceEnt->client ) {\n\t\t\ttent = G_TempEntity( tr.endpos, EV_MISSILE_HIT );\n\t\t\ttent->s.otherEntityNum = traceEnt->s.number;\n\t\t\ttent->s.eventParm = DirToByte( tr.plane.normal );\n\t\t\ttent->s.weapon = ent->s.weapon;\n\t\t\tif( LogAccuracyHit( traceEnt, ent ) ) {\n\t\t\t\tent->client->accuracy_hits++;\n\t\t\t}\n\t\t} else if ( !( tr.surfaceFlags & SURF_NOIMPACT ) ) {\n\t\t\ttent = G_TempEntity( tr.endpos, EV_MISSILE_MISS );\n\t\t\ttent->s.eventParm = DirToByte( tr.plane.normal );\n\t\t}\n\n\t\tbreak;\n\t}\n}\n\n//======================================================================\n\n\n/*\n===============\nLogAccuracyHit\n===============\n*/\nqboolean LogAccuracyHit( gentity_t *target, gentity_t *attacker ) {\n\tif( !target->takedamage ) {\n\t\treturn qfalse;\n\t}\n\n\tif ( target == attacker ) {\n\t\treturn qfalse;\n\t}\n\n\tif( !target->client ) {\n\t\treturn qfalse;\n\t}\n\n\tif( !attacker->client ) {\n\t\treturn qfalse;\n\t}\n\n\tif( target->client->ps.stats[STAT_HEALTH] <= 0 ) {\n\t\treturn qfalse;\n\t}\n\n\tif ( OnSameTeam( target, attacker ) ) {\n\t\treturn qfalse;\n\t}\n\n\treturn qtrue;\n}\n\n\n/*\n===============\nCalcMuzzlePoint\n\nset muzzle location relative to pivoting eye\n===============\n*/\nvoid CalcMuzzlePoint ( gentity_t *ent, vec3_t forward, vec3_t right, vec3_t up, vec3_t muzzlePoint ) {\n\tVectorCopy( ent->s.pos.trBase, muzzlePoint );\n\tmuzzlePoint[2] += ent->client->ps.viewheight;\n\tVectorMA( muzzlePoint, 14, forward, muzzlePoint );\n\t// snap to integer coordinates for more efficient network bandwidth usage\n\tSnapVector( muzzlePoint );\n}\n\n/*\n===============\nCalcMuzzlePointOrigin\n\nset muzzle location relative to pivoting eye\n===============\n*/\nvoid CalcMuzzlePointOrigin ( gentity_t *ent, vec3_t origin, vec3_t forward, vec3_t right, vec3_t up, vec3_t muzzlePoint ) {\n\tVectorCopy( ent->s.pos.trBase, muzzlePoint );\n\tmuzzlePoint[2] += ent->client->ps.viewheight;\n\tVectorMA( muzzlePoint, 14, forward, muzzlePoint );\n\t// snap to integer coordinates for more efficient network bandwidth usage\n\tSnapVector( muzzlePoint );\n}\n\n\n\n/*\n===============\nFireWeapon\n===============\n*/\nvoid FireWeapon( gentity_t *ent ) {\n\tif (ent->client->ps.powerups[PW_QUAD] ) {\n\t\ts_quadFactor = g_quadfactor.value;\n\t} else {\n\t\ts_quadFactor = 1;\n\t}\n\n\t// track shots taken for accuracy tracking.  Grapple is not a weapon and gauntet is just not tracked\n\tif( ent->s.weapon != WP_GRAPPLING_HOOK && ent->s.weapon != WP_GAUNTLET ) {\n\t\tent->client->accuracy_shots++;\n\t}\n\n\t// set aiming directions\n\tAngleVectors (ent->client->ps.viewangles, forward, right, up);\n\n\tCalcMuzzlePointOrigin ( ent, ent->client->oldOrigin, forward, right, up, muzzle );\n\n\t// fire the specific weapon\n\tswitch( ent->s.weapon ) {\n\tcase WP_GAUNTLET:\n\t\tWeapon_Gauntlet( ent );\n\t\tbreak;\n\tcase WP_LIGHTNING:\n\t\tWeapon_LightningFire( ent );\n\t\tbreak;\n\tcase WP_SHOTGUN:\n\t\tweapon_supershotgun_fire( ent );\n\t\tbreak;\n\tcase WP_MACHINEGUN:\n\t\tif ( g_gametype.integer != GT_TEAM ) {\n\t\t\tBullet_Fire( ent, MACHINEGUN_SPREAD, MACHINEGUN_DAMAGE );\n\t\t} else {\n\t\t\tBullet_Fire( ent, MACHINEGUN_SPREAD, MACHINEGUN_TEAM_DAMAGE );\n\t\t}\n\t\tbreak;\n\tcase WP_GRENADE_LAUNCHER:\n\t\tweapon_grenadelauncher_fire( ent );\n\t\tbreak;\n\tcase WP_ROCKET_LAUNCHER:\n\t\tWeapon_RocketLauncher_Fire( ent );\n\t\tbreak;\n\tcase WP_PLASMAGUN:\n\t\tWeapon_Plasmagun_Fire( ent );\n\t\tbreak;\n\tcase WP_RAILGUN:\n\t\tweapon_railgun_fire( ent );\n\t\tbreak;\n\tcase WP_BFG:\n\t\tBFG_Fire( ent );\n\t\tbreak;\n\tcase WP_GRAPPLING_HOOK:\n\t\tWeapon_GrapplingHook_Fire( ent );\n\t\tbreak;\n\tdefault:\n// FIXME\t\tG_Error( \"Bad ent->s.weapon\" );\n\t\tbreak;\n\t}\n}\n"
  },
  {
    "path": "src/game/game.bat",
    "content": "rem make sure we have a safe environement\nset LIBRARY=\nset INCLUDE=\n\nmkdir ..\\..\\intermediate\\vm\\game\ncd ..\\..\\intermediate\\vm\\game\n\nset PATH=..\\..\\..\\tools\\bin;%PATH%\n\nset src=..\\..\\..\\source\nset cc=lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I%src%\\cgame -I%src%\\game -I%src%\\ui %1\n\n%cc%  %src%/game/g_main.c\n@if errorlevel 1 goto quit\n\n%cc%  %src%/game/g_syscalls.c\n@if errorlevel 1 goto quit\n\n%cc%  %src%/game/bg_misc.c\n@if errorlevel 1 goto quit\n%cc%  %src%/game/bg_lib.c\n@if errorlevel 1 goto quit\n%cc%  %src%/game/bg_pmove.c\n@if errorlevel 1 goto quit\n%cc%  %src%/game/bg_slidemove.c\n@if errorlevel 1 goto quit\n%cc%  %src%/game/q_math.c\n@if errorlevel 1 goto quit\n%cc%  %src%/game/q_shared.c\n@if errorlevel 1 goto quit\n\n%cc%  %src%/game/ai_dmnet.c\n@if errorlevel 1 goto quit\n%cc%  %src%/game/ai_dmq3.c\n@if errorlevel 1 goto quit\n%cc%  %src%/game/ai_main.c\n@if errorlevel 1 goto quit\n%cc%  %src%/game/ai_chat.c\n@if errorlevel 1 goto quit\n%cc%  %src%/game/ai_cmd.c\n@if errorlevel 1 goto quit\n%cc%  %src%/game/ai_team.c\n@if errorlevel 1 goto quit\n\n%cc%  %src%/game/g_active.c\n@if errorlevel 1 goto quit\n%cc%  %src%/game/g_arenas.c\n@if errorlevel 1 goto quit\n%cc%  %src%/game/g_bot.c\n@if errorlevel 1 goto quit\n%cc%  %src%/game/g_client.c\n@if errorlevel 1 goto quit\n%cc%  %src%/game/g_cmds.c\n@if errorlevel 1 goto quit\n%cc%  %src%/game/g_combat.c\n@if errorlevel 1 goto quit\n%cc%  %src%/game/g_items.c\n@if errorlevel 1 goto quit\n%cc%  %src%/game/g_mem.c\n@if errorlevel 1 goto quit\n%cc%  %src%/game/g_misc.c\n@if errorlevel 1 goto quit\n%cc%  %src%/game/g_missile.c\n@if errorlevel 1 goto quit\n%cc%  %src%/game/g_mover.c\n@if errorlevel 1 goto quit\n%cc%  %src%/game/g_session.c\n@if errorlevel 1 goto quit\n%cc%  %src%/game/g_spawn.c\n@if errorlevel 1 goto quit\n%cc%  %src%/game/g_svcmds.c\n@if errorlevel 1 goto quit\n%cc%  %src%/game/g_target.c\n@if errorlevel 1 goto quit\n%cc%  %src%/game/g_team.c\n@if errorlevel 1 goto quit\n%cc%  %src%/game/g_trigger.c\n@if errorlevel 1 goto quit\n%cc%  %src%/game/g_utils.c\n@if errorlevel 1 goto quit\n%cc%  %src%/game/g_weapon.c\n@if errorlevel 1 goto quit\n%cc%  %src%/game/ai_vcmd.c\n@if errorlevel 1 goto quit\n\nq3asm -f %src%/game/game\n:quit\ncd %src%/game\n"
  },
  {
    "path": "src/game/game.q3asm",
    "content": "-o \"..\\..\\..\\binaries\\vm\\qagame.qvm\"\ng_main\n..\\..\\..\\source\\game\\g_syscalls\nbg_misc\nbg_lib\nbg_pmove\nbg_slidemove\nq_math\nq_shared\nai_dmnet\nai_dmq3\nai_team\nai_main\nai_chat\nai_cmd\nai_vcmd\ng_active\ng_arenas\ng_bot\ng_client\ng_cmds\ng_combat\ng_items\ng_mem\ng_misc\ng_missile\ng_mover\ng_session\ng_spawn\ng_svcmds\ng_target\ng_team\ng_trigger\ng_utils\ng_weapon\n"
  },
  {
    "path": "src/game/inv.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n#define INVENTORY_NONE\t\t\t\t0\n//armor\n#define INVENTORY_ARMOR\t\t\t\t1\n//weapons\n#define INVENTORY_GAUNTLET\t\t\t4\n#define INVENTORY_SHOTGUN\t\t\t5\n#define INVENTORY_MACHINEGUN\t\t6\n#define INVENTORY_GRENADELAUNCHER\t7\n#define INVENTORY_ROCKETLAUNCHER\t8\n#define INVENTORY_LIGHTNING\t\t\t9\n#define INVENTORY_RAILGUN\t\t\t10\n#define INVENTORY_PLASMAGUN\t\t\t11\n#define INVENTORY_BFG10K\t\t\t13\n#define INVENTORY_GRAPPLINGHOOK\t\t14\n#define INVENTORY_NAILGUN\t\t\t15\n#define INVENTORY_PROXLAUNCHER\t\t16\n#define INVENTORY_CHAINGUN\t\t\t17\n//ammo\n#define INVENTORY_SHELLS\t\t\t18\n#define INVENTORY_BULLETS\t\t\t19\n#define INVENTORY_GRENADES\t\t\t20\n#define INVENTORY_CELLS\t\t\t\t21\n#define INVENTORY_LIGHTNINGAMMO\t\t22\n#define INVENTORY_ROCKETS\t\t\t23\n#define INVENTORY_SLUGS\t\t\t\t24\n#define INVENTORY_BFGAMMO\t\t\t25\n#define INVENTORY_NAILS\t\t\t\t26\n#define INVENTORY_MINES\t\t\t\t27\n#define INVENTORY_BELT\t\t\t\t28\n//powerups\n#define INVENTORY_HEALTH\t\t\t29\n#define INVENTORY_TELEPORTER\t\t30\n#define INVENTORY_MEDKIT\t\t\t31\n#define INVENTORY_KAMIKAZE\t\t\t32\n#define INVENTORY_PORTAL\t\t\t33\n#define INVENTORY_INVULNERABILITY\t34\n#define INVENTORY_QUAD\t\t\t\t35\n#define INVENTORY_ENVIRONMENTSUIT\t36\n#define INVENTORY_HASTE\t\t\t\t37\n#define INVENTORY_INVISIBILITY\t\t38\n#define INVENTORY_REGEN\t\t\t\t39\n#define INVENTORY_FLIGHT\t\t\t40\n#define INVENTORY_SCOUT\t\t\t\t41\n#define INVENTORY_GUARD\t\t\t\t42\n#define INVENTORY_DOUBLER\t\t\t43\n#define INVENTORY_AMMOREGEN\t\t\t44\n\n#define INVENTORY_REDFLAG\t\t\t45\n#define INVENTORY_BLUEFLAG\t\t\t46\n#define INVENTORY_NEUTRALFLAG\t\t47\n#define INVENTORY_REDCUBE\t\t\t48\n#define INVENTORY_BLUECUBE\t\t\t49\n//enemy stuff\n#define ENEMY_HORIZONTAL_DIST\t\t200\n#define ENEMY_HEIGHT\t\t\t\t201\n#define NUM_VISIBLE_ENEMIES\t\t\t202\n#define NUM_VISIBLE_TEAMMATES\t\t203\n\n//item numbers (make sure they are in sync with bg_itemlist in bg_misc.c)\n#define MODELINDEX_ARMORSHARD\t\t1\n#define MODELINDEX_ARMORCOMBAT\t\t2\n#define MODELINDEX_ARMORBODY\t\t3\n#define MODELINDEX_HEALTHSMALL\t\t4\n#define MODELINDEX_HEALTH\t\t\t5\n#define MODELINDEX_HEALTHLARGE\t\t6\n#define MODELINDEX_HEALTHMEGA\t\t7\n\n#define MODELINDEX_GAUNTLET\t\t\t8\n#define MODELINDEX_SHOTGUN\t\t\t9\n#define MODELINDEX_MACHINEGUN\t\t10\n#define MODELINDEX_GRENADELAUNCHER\t11\n#define MODELINDEX_ROCKETLAUNCHER\t12\n#define MODELINDEX_LIGHTNING\t\t13\n#define MODELINDEX_RAILGUN\t\t\t14\n#define MODELINDEX_PLASMAGUN\t\t15\n#define MODELINDEX_BFG10K\t\t\t16\n#define MODELINDEX_GRAPPLINGHOOK\t17\n\n#define MODELINDEX_SHELLS\t\t\t18\n#define MODELINDEX_BULLETS\t\t\t19\n#define MODELINDEX_GRENADES\t\t\t20\n#define MODELINDEX_CELLS\t\t\t21\n#define MODELINDEX_LIGHTNINGAMMO\t22\n#define MODELINDEX_ROCKETS\t\t\t23\n#define MODELINDEX_SLUGS\t\t\t24\n#define MODELINDEX_BFGAMMO\t\t\t25\n\n#define MODELINDEX_TELEPORTER\t\t26\n#define MODELINDEX_MEDKIT\t\t\t27\n#define MODELINDEX_QUAD\t\t\t\t28\n#define MODELINDEX_ENVIRONMENTSUIT\t29\n#define MODELINDEX_HASTE\t\t\t30\n#define MODELINDEX_INVISIBILITY\t\t31\n#define MODELINDEX_REGEN\t\t\t32\n#define MODELINDEX_FLIGHT\t\t\t33\n\n#define MODELINDEX_REDFLAG\t\t\t34\n#define MODELINDEX_BLUEFLAG\t\t\t35\n\n// mission pack only defines\n\n#define MODELINDEX_KAMIKAZE\t\t\t36\n#define MODELINDEX_PORTAL\t\t\t37\n#define MODELINDEX_INVULNERABILITY\t38\n\n#define MODELINDEX_NAILS\t\t\t39\n#define MODELINDEX_MINES\t\t\t40\n#define MODELINDEX_BELT\t\t\t\t41\n\n#define MODELINDEX_SCOUT\t\t\t42\n#define MODELINDEX_GUARD\t\t\t43\n#define MODELINDEX_DOUBLER\t\t\t44\n#define MODELINDEX_AMMOREGEN\t\t45\n\n#define MODELINDEX_NEUTRALFLAG\t\t46\n#define MODELINDEX_REDCUBE\t\t\t47\n#define MODELINDEX_BLUECUBE\t\t\t48\n\n#define MODELINDEX_NAILGUN\t\t\t49\n#define MODELINDEX_PROXLAUNCHER\t\t50\n#define MODELINDEX_CHAINGUN\t\t\t51\n\n\n//\n#define WEAPONINDEX_GAUNTLET\t\t\t1\n#define WEAPONINDEX_MACHINEGUN\t\t\t2\n#define WEAPONINDEX_SHOTGUN\t\t\t\t3\n#define WEAPONINDEX_GRENADE_LAUNCHER\t4\n#define WEAPONINDEX_ROCKET_LAUNCHER\t\t5\n#define WEAPONINDEX_LIGHTNING\t\t\t6\n#define WEAPONINDEX_RAILGUN\t\t\t\t7\n#define WEAPONINDEX_PLASMAGUN\t\t\t8\n#define WEAPONINDEX_BFG\t\t\t\t\t9\n#define WEAPONINDEX_GRAPPLING_HOOK\t\t10\n#define WEAPONINDEX_NAILGUN\t\t\t\t11\n#define WEAPONINDEX_PROXLAUNCHER\t\t12\n#define WEAPONINDEX_CHAINGUN\t\t\t13\n"
  },
  {
    "path": "src/game/match.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n// make sure this is the same character as we use in chats in g_cmd.c\n#define EC\t\"\\x19\"\n\n//match template contexts\n#define MTCONTEXT_MISC\t\t\t\t\t2\n#define MTCONTEXT_INITIALTEAMCHAT\t\t4\n#define MTCONTEXT_TIME\t\t\t\t\t8\n#define MTCONTEXT_TEAMMATE\t\t\t\t16\n#define MTCONTEXT_ADDRESSEE\t\t\t\t32\n#define MTCONTEXT_PATROLKEYAREA\t\t\t64\n#define MTCONTEXT_REPLYCHAT\t\t\t\t128\n#define MTCONTEXT_CTF\t\t\t\t\t256\n\n//message types\n#define MSG_NEWLEADER\t\t\t\t\t1\t\t//new leader\n#define MSG_ENTERGAME\t\t\t\t\t2\t\t//enter game message\n#define MSG_HELP\t\t\t\t\t\t3\t\t//help someone\n#define MSG_ACCOMPANY\t\t\t\t\t4\t\t//accompany someone\n#define MSG_DEFENDKEYAREA\t\t\t\t5\t\t//defend a key area\n#define MSG_RUSHBASE\t\t\t\t\t6\t\t//everyone rush to base\n#define MSG_GETFLAG\t\t\t\t\t\t7\t\t//get the enemy flag\n#define MSG_STARTTEAMLEADERSHIP\t\t\t8\t\t//someone wants to become the team leader\n#define MSG_STOPTEAMLEADERSHIP\t\t\t9\t\t//someone wants to stop being the team leader\n#define MSG_WHOISTEAMLAEDER\t\t\t\t10\t\t//who is the team leader\n#define MSG_WAIT\t\t\t\t\t\t11\t\t//wait for someone\n#define MSG_WHATAREYOUDOING\t\t\t\t12\t\t//what are you doing?\n#define MSG_JOINSUBTEAM\t\t\t\t\t13\t\t//join a sub-team\n#define MSG_LEAVESUBTEAM\t\t\t\t14\t\t//leave a sub-team\n#define MSG_CREATENEWFORMATION\t\t\t15\t\t//create a new formation\n#define MSG_FORMATIONPOSITION\t\t\t16\t\t//tell someone his/her position in a formation\n#define MSG_FORMATIONSPACE\t\t\t\t17\t\t//set the formation intervening space\n#define MSG_DOFORMATION\t\t\t\t\t18\t\t//form a known formation\n#define MSG_DISMISS\t\t\t\t\t\t19\t\t//dismiss commanded team mates\n#define MSG_CAMP\t\t\t\t\t\t20\t\t//camp somewhere\n#define MSG_CHECKPOINT\t\t\t\t\t21\t\t//remember a check point\n#define MSG_PATROL\t\t\t\t\t\t22\t\t//patrol between certain keypoints\n#define MSG_LEADTHEWAY\t\t\t\t\t23\t\t//lead the way\n#define MSG_GETITEM\t\t\t\t\t\t24\t\t//get an item\n#define MSG_KILL\t\t\t\t\t\t25\t\t//kill someone\n#define MSG_WHEREAREYOU\t\t\t\t\t26\t\t//where is someone\n#define MSG_RETURNFLAG\t\t\t\t\t27\t\t//return the flag\n#define MSG_WHATISMYCOMMAND\t\t\t\t28\t\t//ask the team leader what to do\n#define MSG_WHICHTEAM\t\t\t\t\t29\t\t//ask which team a bot is in\n#define MSG_TASKPREFERENCE\t\t\t\t30\t\t//tell your teamplay task preference\n#define MSG_ATTACKENEMYBASE\t\t\t\t31\t\t//attack the enemy base\n#define MSG_HARVEST\t\t\t\t\t\t32\t\t//go harvest\n#define MSG_SUICIDE\t\t\t\t\t\t33\t\t//order to suicide\n//\n#define MSG_ME\t\t\t\t\t\t\t100\n#define MSG_EVERYONE\t\t\t\t\t101\n#define MSG_MULTIPLENAMES\t\t\t\t102\n#define MSG_NAME\t\t\t\t\t\t103\n#define MSG_PATROLKEYAREA\t\t\t\t104\n#define MSG_MINUTES\t\t\t\t\t\t105\n#define MSG_SECONDS\t\t\t\t\t\t106\n#define MSG_FOREVER\t\t\t\t\t\t107\n#define MSG_FORALONGTIME\t\t\t\t108\n#define MSG_FORAWHILE\t\t\t\t\t109\n//\n#define MSG_CHATALL\t\t\t\t\t\t200\n#define MSG_CHATTEAM\t\t\t\t\t201\n#define MSG_CHATTELL\t\t\t\t\t202\n//\n#define MSG_CTF\t\t\t\t\t\t\t300\t\t//ctf message\n\n//command sub types\n#define ST_SOMEWHERE\t\t\t\t\t0\n#define ST_NEARITEM\t\t\t\t\t\t1\n#define ST_ADDRESSED\t\t\t\t\t2\n#define ST_METER\t\t\t\t\t\t4\n#define ST_FEET\t\t\t\t\t\t\t8\n#define ST_TIME\t\t\t\t\t\t\t16\n#define ST_HERE\t\t\t\t\t\t\t32\n#define ST_THERE\t\t\t\t\t\t64\n#define ST_I\t\t\t\t\t\t\t128\n#define ST_MORE\t\t\t\t\t\t\t256\n#define ST_BACK\t\t\t\t\t\t\t512\n#define ST_REVERSE\t\t\t\t\t\t1024\n#define ST_SOMEONE\t\t\t\t\t\t2048\n#define ST_GOTFLAG\t\t\t\t\t\t4096\n#define ST_CAPTUREDFLAG\t\t\t\t\t8192\n#define ST_RETURNEDFLAG\t\t\t\t\t16384\n#define ST_TEAM\t\t\t\t\t\t\t32768\n#define ST_1FCTFGOTFLAG\t\t\t\t\t65535\n//ctf task preferences\n#define ST_DEFENDER\t\t\t\t\t\t1\n#define ST_ATTACKER\t\t\t\t\t\t2\n#define ST_ROAMER\t\t\t\t\t\t4\n\n\n//word replacement variables\n#define THE_ENEMY\t\t\t\t\t\t7\n#define THE_TEAM\t\t\t\t\t\t7\n//team message variables\n#define NETNAME\t\t\t\t\t\t\t0\n#define PLACE\t\t\t\t\t\t\t1\n#define FLAG\t\t\t\t\t\t\t1\n#define MESSAGE\t\t\t\t\t\t\t2\n#define ADDRESSEE\t\t\t\t\t\t2\n#define ITEM\t\t\t\t\t\t\t3\n#define TEAMMATE\t\t\t\t\t\t4\n#define TEAMNAME\t\t\t\t\t\t4\n#define ENEMY\t\t\t\t\t\t\t4\n#define KEYAREA\t\t\t\t\t\t\t5\n#define FORMATION\t\t\t\t\t\t5\n#define POSITION\t\t\t\t\t\t5\n#define NUMBER\t\t\t\t\t\t\t5\n#define TIME\t\t\t\t\t\t\t6\n#define NAME\t\t\t\t\t\t\t6\n#define MORE\t\t\t\t\t\t\t6\n\n\n"
  },
  {
    "path": "src/game/menudef.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n#define ITEM_TYPE_TEXT 0                  // simple text\n#define ITEM_TYPE_BUTTON 1                // button, basically text with a border \n#define ITEM_TYPE_RADIOBUTTON 2           // toggle button, may be grouped \n#define ITEM_TYPE_CHECKBOX 3              // check box\n#define ITEM_TYPE_EDITFIELD 4             // editable text, associated with a cvar\n#define ITEM_TYPE_COMBO 5                 // drop down list\n#define ITEM_TYPE_LISTBOX 6               // scrollable list  \n#define ITEM_TYPE_MODEL 7                 // model\n#define ITEM_TYPE_OWNERDRAW 8             // owner draw, name specs what it is\n#define ITEM_TYPE_NUMERICFIELD 9          // editable text, associated with a cvar\n#define ITEM_TYPE_SLIDER 10               // mouse speed, volume, etc.\n#define ITEM_TYPE_YESNO 11                // yes no cvar setting\n#define ITEM_TYPE_MULTI 12                // multiple list setting, enumerated\n#define ITEM_TYPE_BIND 13\t\t              // multiple list setting, enumerated\n    \n#define ITEM_ALIGN_LEFT 0                 // left alignment\n#define ITEM_ALIGN_CENTER 1               // center alignment\n#define ITEM_ALIGN_RIGHT 2                // right alignment\n\n#define ITEM_TEXTSTYLE_NORMAL 0           // normal text\n#define ITEM_TEXTSTYLE_BLINK 1            // fast blinking\n#define ITEM_TEXTSTYLE_PULSE 2            // slow pulsing\n#define ITEM_TEXTSTYLE_SHADOWED 3         // drop shadow ( need a color for this )\n#define ITEM_TEXTSTYLE_OUTLINED 4         // drop shadow ( need a color for this )\n#define ITEM_TEXTSTYLE_OUTLINESHADOWED 5  // drop shadow ( need a color for this )\n#define ITEM_TEXTSTYLE_SHADOWEDMORE 6         // drop shadow ( need a color for this )\n                          \n#define WINDOW_BORDER_NONE 0              // no border\n#define WINDOW_BORDER_FULL 1              // full border based on border color ( single pixel )\n#define WINDOW_BORDER_HORZ 2              // horizontal borders only\n#define WINDOW_BORDER_VERT 3              // vertical borders only \n#define WINDOW_BORDER_KCGRADIENT 4        // horizontal border using the gradient bars\n  \n#define WINDOW_STYLE_EMPTY 0              // no background\n#define WINDOW_STYLE_FILLED 1             // filled with background color\n#define WINDOW_STYLE_GRADIENT 2           // gradient bar based on background color \n#define WINDOW_STYLE_SHADER   3           // gradient bar based on background color \n#define WINDOW_STYLE_TEAMCOLOR 4          // team color\n#define WINDOW_STYLE_CINEMATIC 5          // cinematic\n\n#define MENU_TRUE 1                       // uh.. true\n#define MENU_FALSE 0                      // and false\n\n#define HUD_VERTICAL\t\t\t\t0x00\n#define HUD_HORIZONTAL\t\t\t\t0x01\n\n// list box element types\n#define LISTBOX_TEXT  0x00\n#define LISTBOX_IMAGE 0x01\n\n// list feeders\n#define FEEDER_HEADS\t\t\t\t\t\t0x00\t\t\t// model heads\n#define FEEDER_MAPS\t\t\t\t\t\t\t0x01\t\t\t// text maps based on game type\n#define FEEDER_SERVERS\t\t\t\t\t\t0x02\t\t\t// servers\n#define FEEDER_CLANS\t\t\t\t\t\t0x03\t\t\t// clan names\n#define FEEDER_ALLMAPS\t\t\t\t\t\t0x04\t\t\t// all maps available, in graphic format\n#define FEEDER_REDTEAM_LIST\t\t\t\t\t0x05\t\t\t// red team members\n#define FEEDER_BLUETEAM_LIST\t\t\t\t0x06\t\t\t// blue team members\n#define FEEDER_PLAYER_LIST\t\t\t\t\t0x07\t\t\t// players\n#define FEEDER_TEAM_LIST\t\t\t\t\t0x08\t\t\t// team members for team voting\n#define FEEDER_MODS\t\t\t\t\t\t\t0x09\t\t\t// team members for team voting\n#define FEEDER_DEMOS \t\t\t\t\t\t0x0a\t\t\t// team members for team voting\n#define FEEDER_SCOREBOARD\t\t\t\t\t0x0b\t\t\t// team members for team voting\n#define FEEDER_Q3HEADS\t\t \t\t\t\t0x0c\t\t\t// model heads\n#define FEEDER_SERVERSTATUS\t\t\t\t\t0x0d\t\t\t// server status\n#define FEEDER_FINDPLAYER\t\t\t\t\t0x0e\t\t\t// find player\n#define FEEDER_CINEMATICS\t\t\t\t\t0x0f\t\t\t// cinematics\n\n// display flags\n#define CG_SHOW_BLUE_TEAM_HAS_REDFLAG     0x00000001\n#define CG_SHOW_RED_TEAM_HAS_BLUEFLAG     0x00000002\n#define CG_SHOW_ANYTEAMGAME               0x00000004\n#define CG_SHOW_HARVESTER                 0x00000008\n#define CG_SHOW_ONEFLAG                   0x00000010\n#define CG_SHOW_CTF                       0x00000020\n#define CG_SHOW_OBELISK                   0x00000040\n#define CG_SHOW_HEALTHCRITICAL            0x00000080\n#define CG_SHOW_SINGLEPLAYER              0x00000100\n#define CG_SHOW_TOURNAMENT                0x00000200\n#define CG_SHOW_DURINGINCOMINGVOICE       0x00000400\n#define CG_SHOW_IF_PLAYER_HAS_FLAG\t\t\t\t0x00000800\n#define CG_SHOW_LANPLAYONLY\t\t\t\t\t\t\t\t0x00001000\n#define CG_SHOW_MINED\t\t\t\t\t\t\t\t\t\t\t0x00002000\n#define CG_SHOW_HEALTHOK\t\t\t            0x00004000\n#define CG_SHOW_TEAMINFO\t\t\t            0x00008000\n#define CG_SHOW_NOTEAMINFO\t\t            0x00010000\n#define CG_SHOW_OTHERTEAMHASFLAG          0x00020000\n#define CG_SHOW_YOURTEAMHASENEMYFLAG      0x00040000\n#define CG_SHOW_ANYNONTEAMGAME            0x00080000\n#define CG_SHOW_2DONLY\t\t\t\t\t\t\t\t\t\t0x10000000\n\n\n#define UI_SHOW_LEADER\t\t\t\t            0x00000001\n#define UI_SHOW_NOTLEADER\t\t\t            0x00000002\n#define UI_SHOW_FAVORITESERVERS\t\t\t\t\t\t0x00000004\n#define UI_SHOW_ANYNONTEAMGAME\t\t\t\t\t\t0x00000008\n#define UI_SHOW_ANYTEAMGAME\t\t\t\t\t\t\t\t0x00000010\n#define UI_SHOW_NEWHIGHSCORE\t\t\t\t\t\t\t0x00000020\n#define UI_SHOW_DEMOAVAILABLE\t\t\t\t\t\t\t0x00000040\n#define UI_SHOW_NEWBESTTIME\t\t\t\t\t\t\t\t0x00000080\n#define UI_SHOW_FFA\t\t\t\t\t\t\t\t\t\t\t\t0x00000100\n#define UI_SHOW_NOTFFA\t\t\t\t\t\t\t\t\t\t0x00000200\n#define UI_SHOW_NETANYNONTEAMGAME\t \t\t\t\t0x00000400\n#define UI_SHOW_NETANYTEAMGAME\t\t \t\t\t\t0x00000800\n#define UI_SHOW_NOTFAVORITESERVERS\t\t\t\t0x00001000\n\n\n\n\n// owner draw types\n// ideally these should be done outside of this file but\n// this makes it much easier for the macro expansion to \n// convert them for the designers ( from the .menu files )\n#define CG_OWNERDRAW_BASE 1\n#define CG_PLAYER_ARMOR_ICON 1              \n#define CG_PLAYER_ARMOR_VALUE 2\n#define CG_PLAYER_HEAD 3\n#define CG_PLAYER_HEALTH 4\n#define CG_PLAYER_AMMO_ICON 5\n#define CG_PLAYER_AMMO_VALUE 6\n#define CG_SELECTEDPLAYER_HEAD 7\n#define CG_SELECTEDPLAYER_NAME 8\n#define CG_SELECTEDPLAYER_LOCATION 9\n#define CG_SELECTEDPLAYER_STATUS 10\n#define CG_SELECTEDPLAYER_WEAPON 11\n#define CG_SELECTEDPLAYER_POWERUP 12\n\n#define CG_FLAGCARRIER_HEAD 13\n#define CG_FLAGCARRIER_NAME 14\n#define CG_FLAGCARRIER_LOCATION 15\n#define CG_FLAGCARRIER_STATUS 16\n#define CG_FLAGCARRIER_WEAPON 17\n#define CG_FLAGCARRIER_POWERUP 18\n\n#define CG_PLAYER_ITEM 19\n#define CG_PLAYER_SCORE 20\n\n#define CG_BLUE_FLAGHEAD 21\n#define CG_BLUE_FLAGSTATUS 22\n#define CG_BLUE_FLAGNAME 23\n#define CG_RED_FLAGHEAD 24\n#define CG_RED_FLAGSTATUS 25\n#define CG_RED_FLAGNAME 26\n\n#define CG_BLUE_SCORE 27\n#define CG_RED_SCORE 28\n#define CG_RED_NAME 29\n#define CG_BLUE_NAME 30\n#define CG_HARVESTER_SKULLS 31\t\t\t\t\t// only shows in harvester\n#define CG_ONEFLAG_STATUS 32\t\t\t\t\t\t// only shows in one flag\n#define CG_PLAYER_LOCATION 33\n#define CG_TEAM_COLOR 34\n#define CG_CTF_POWERUP 35\n                                        \n#define CG_AREA_POWERUP\t36\n#define CG_AREA_LAGOMETER\t37            // painted with old system\n#define CG_PLAYER_HASFLAG 38            \n#define CG_GAME_TYPE 39                 // not done\n\n#define CG_SELECTEDPLAYER_ARMOR 40      \n#define CG_SELECTEDPLAYER_HEALTH 41\n#define CG_PLAYER_STATUS 42\n#define CG_FRAGGED_MSG 43               // painted with old system\n#define CG_PROXMINED_MSG 44             // painted with old system\n#define CG_AREA_FPSINFO 45              // painted with old system\n#define CG_AREA_SYSTEMCHAT 46           // painted with old system\n#define CG_AREA_TEAMCHAT 47             // painted with old system\n#define CG_AREA_CHAT 48                 // painted with old system\n#define CG_GAME_STATUS 49\n#define CG_KILLER 50\n#define CG_PLAYER_ARMOR_ICON2D 51              \n#define CG_PLAYER_AMMO_ICON2D 52\n#define CG_ACCURACY 53\n#define CG_ASSISTS 54\n#define CG_DEFEND 55\n#define CG_EXCELLENT 56\n#define CG_IMPRESSIVE 57\n#define CG_PERFECT 58\n#define CG_GAUNTLET 59\n#define CG_SPECTATORS 60\n#define CG_TEAMINFO 61\n#define CG_VOICE_HEAD 62\n#define CG_VOICE_NAME 63\n#define CG_PLAYER_HASFLAG2D 64            \n#define CG_HARVESTER_SKULLS2D 65\t\t\t\t\t// only shows in harvester\n#define CG_CAPFRAGLIMIT 66\t \n#define CG_1STPLACE 67\n#define CG_2NDPLACE 68\n#define CG_CAPTURES 69\n\n\n\n\n#define UI_OWNERDRAW_BASE 200\n#define UI_HANDICAP 200\n#define UI_EFFECTS 201\n#define UI_PLAYERMODEL 202\n#define UI_CLANNAME 203\n#define UI_CLANLOGO 204\n#define UI_GAMETYPE 205\n#define UI_MAPPREVIEW 206\n#define UI_SKILL 207\n#define UI_BLUETEAMNAME 208\n#define UI_REDTEAMNAME 209\n#define UI_BLUETEAM1 210\n#define UI_BLUETEAM2 211\n#define UI_BLUETEAM3 212\n#define UI_BLUETEAM4 213\n#define UI_BLUETEAM5 214\n#define UI_REDTEAM1 215\n#define UI_REDTEAM2 216\n#define UI_REDTEAM3 217\n#define UI_REDTEAM4 218\n#define UI_REDTEAM5 219\n#define UI_NETSOURCE 220\n#define UI_NETMAPPREVIEW 221\n#define UI_NETFILTER 222\n#define UI_TIER 223\n#define UI_OPPONENTMODEL 224\n#define UI_TIERMAP1 225\n#define UI_TIERMAP2 226\n#define UI_TIERMAP3 227\n#define UI_PLAYERLOGO 228\n#define UI_OPPONENTLOGO 229\n#define UI_PLAYERLOGO_METAL 230\n#define UI_OPPONENTLOGO_METAL 231\n#define UI_PLAYERLOGO_NAME 232\n#define UI_OPPONENTLOGO_NAME 233\n#define UI_TIER_MAPNAME 234\n#define UI_TIER_GAMETYPE 235\n#define UI_ALLMAPS_SELECTION 236\n#define UI_OPPONENT_NAME 237\n#define UI_VOTE_KICK 238\n#define UI_BOTNAME 239\n#define UI_BOTSKILL 240\n#define UI_REDBLUE 241\n#define UI_CROSSHAIR 242\n#define UI_SELECTEDPLAYER 243\n#define UI_MAPCINEMATIC 244\n#define UI_NETGAMETYPE 245\n#define UI_NETMAPCINEMATIC 246\n#define UI_SERVERREFRESHDATE 247\n#define UI_SERVERMOTD 248\n#define UI_GLINFO  249\n#define UI_KEYBINDSTATUS 250\n#define UI_CLANCINEMATIC 251\n#define UI_MAP_TIMETOBEAT 252\n#define UI_JOINGAMETYPE 253\n#define UI_PREVIEWCINEMATIC 254\n#define UI_STARTMAPCINEMATIC 255\n#define UI_MAPS_SELECTION 256\n\n#define VOICECHAT_GETFLAG\t\t\t\"getflag\"\t\t\t\t// command someone to get the flag\n#define VOICECHAT_OFFENSE\t\t\t\"offense\"\t\t\t\t// command someone to go on offense\n#define VOICECHAT_DEFEND\t\t\t\"defend\"\t\t\t\t// command someone to go on defense\n#define VOICECHAT_DEFENDFLAG\t\t\"defendflag\"\t\t\t// command someone to defend the flag\n#define VOICECHAT_PATROL\t\t\t\"patrol\"\t\t\t\t// command someone to go on patrol (roam)\n#define VOICECHAT_CAMP\t\t\t\t\"camp\"\t\t\t\t\t// command someone to camp (we don't have sounds for this one)\n#define VOICECHAT_FOLLOWME\t\t\t\"followme\"\t\t\t\t// command someone to follow you\n#define VOICECHAT_RETURNFLAG\t\t\"returnflag\"\t\t\t// command someone to return our flag\n#define VOICECHAT_FOLLOWFLAGCARRIER\t\"followflagcarrier\"\t\t// command someone to follow the flag carrier\n#define VOICECHAT_YES\t\t\t\t\"yes\"\t\t\t\t\t// yes, affirmative, etc.\n#define VOICECHAT_NO\t\t\t\t\"no\"\t\t\t\t\t// no, negative, etc.\n#define VOICECHAT_ONGETFLAG\t\t\t\"ongetflag\"\t\t\t\t// I'm getting the flag\n#define VOICECHAT_ONOFFENSE\t\t\t\"onoffense\"\t\t\t\t// I'm on offense\n#define VOICECHAT_ONDEFENSE\t\t\t\"ondefense\"\t\t\t\t// I'm on defense\n#define VOICECHAT_ONPATROL\t\t\t\"onpatrol\"\t\t\t\t// I'm on patrol (roaming)\n#define VOICECHAT_ONCAMPING\t\t\t\"oncamp\"\t\t\t\t// I'm camping somewhere\n#define VOICECHAT_ONFOLLOW\t\t\t\"onfollow\"\t\t\t\t// I'm following\n#define VOICECHAT_ONFOLLOWCARRIER\t\"onfollowcarrier\"\t\t// I'm following the flag carrier\n#define VOICECHAT_ONRETURNFLAG\t\t\"onreturnflag\"\t\t\t// I'm returning our flag\n#define VOICECHAT_INPOSITION\t\t\"inposition\"\t\t\t// I'm in position\n#define VOICECHAT_IHAVEFLAG\t\t\t\"ihaveflag\"\t\t\t\t// I have the flag\n#define VOICECHAT_BASEATTACK\t\t\"baseattack\"\t\t\t// the base is under attack\n#define VOICECHAT_ENEMYHASFLAG\t\t\"enemyhasflag\"\t\t\t// the enemy has our flag (CTF)\n#define VOICECHAT_STARTLEADER\t\t\"startleader\"\t\t\t// I'm the leader\n#define VOICECHAT_STOPLEADER\t\t\"stopleader\"\t\t\t// I resign leadership\n#define VOICECHAT_TRASH\t\t\t\t\"trash\"\t\t\t\t\t// lots of trash talk\n#define VOICECHAT_WHOISLEADER\t\t\"whoisleader\"\t\t\t// who is the team leader\n#define VOICECHAT_WANTONDEFENSE\t\t\"wantondefense\"\t\t\t// I want to be on defense\n#define VOICECHAT_WANTONOFFENSE\t\t\"wantonoffense\"\t\t\t// I want to be on offense\n#define VOICECHAT_KILLINSULT\t\t\"kill_insult\"\t\t\t// I just killed you\n#define VOICECHAT_TAUNT\t\t\t\t\"taunt\"\t\t\t\t\t// I want to taunt you\n#define VOICECHAT_DEATHINSULT\t\t\"death_insult\"\t\t\t// you just killed me\n#define VOICECHAT_KILLGAUNTLET\t\t\"kill_gauntlet\"\t\t\t// I just killed you with the gauntlet\n#define VOICECHAT_PRAISE\t\t\t\"praise\"\t\t\t\t// you did something good\n"
  },
  {
    "path": "src/game/q_math.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n// q_math.c -- stateless support routines that are included in each code module\n#include \"q_shared.h\"\n\n\nvec3_t\tvec3_origin = {0,0,0};\nvec3_t\taxisDefault[3] = { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } };\n\n\nvec4_t\t\tcolorBlack\t= {0, 0, 0, 1};\nvec4_t\t\tcolorRed\t= {1, 0, 0, 1};\nvec4_t\t\tcolorGreen\t= {0, 1, 0, 1};\nvec4_t\t\tcolorBlue\t= {0, 0, 1, 1};\nvec4_t\t\tcolorYellow\t= {1, 1, 0, 1};\nvec4_t\t\tcolorMagenta= {1, 0, 1, 1};\nvec4_t\t\tcolorCyan\t= {0, 1, 1, 1};\nvec4_t\t\tcolorWhite\t= {1, 1, 1, 1};\nvec4_t\t\tcolorLtGrey\t= {0.75, 0.75, 0.75, 1};\nvec4_t\t\tcolorMdGrey\t= {0.5, 0.5, 0.5, 1};\nvec4_t\t\tcolorDkGrey\t= {0.25, 0.25, 0.25, 1};\n\nvec4_t\tg_color_table[8] =\n\t{\n\t{0.0, 0.0, 0.0, 1.0},\n\t{1.0, 0.0, 0.0, 1.0},\n\t{0.0, 1.0, 0.0, 1.0},\n\t{1.0, 1.0, 0.0, 1.0},\n\t{0.0, 0.0, 1.0, 1.0},\n\t{0.0, 1.0, 1.0, 1.0},\n\t{1.0, 0.0, 1.0, 1.0},\n\t{1.0, 1.0, 1.0, 1.0},\n\t};\n\n\nvec3_t\tbytedirs[NUMVERTEXNORMALS] =\n{\n{-0.525731f, 0.000000f, 0.850651f}, {-0.442863f, 0.238856f, 0.864188f}, \n{-0.295242f, 0.000000f, 0.955423f}, {-0.309017f, 0.500000f, 0.809017f}, \n{-0.162460f, 0.262866f, 0.951056f}, {0.000000f, 0.000000f, 1.000000f}, \n{0.000000f, 0.850651f, 0.525731f}, {-0.147621f, 0.716567f, 0.681718f}, \n{0.147621f, 0.716567f, 0.681718f}, {0.000000f, 0.525731f, 0.850651f}, \n{0.309017f, 0.500000f, 0.809017f}, {0.525731f, 0.000000f, 0.850651f}, \n{0.295242f, 0.000000f, 0.955423f}, {0.442863f, 0.238856f, 0.864188f}, \n{0.162460f, 0.262866f, 0.951056f}, {-0.681718f, 0.147621f, 0.716567f}, \n{-0.809017f, 0.309017f, 0.500000f},{-0.587785f, 0.425325f, 0.688191f}, \n{-0.850651f, 0.525731f, 0.000000f},{-0.864188f, 0.442863f, 0.238856f}, \n{-0.716567f, 0.681718f, 0.147621f},{-0.688191f, 0.587785f, 0.425325f}, \n{-0.500000f, 0.809017f, 0.309017f}, {-0.238856f, 0.864188f, 0.442863f}, \n{-0.425325f, 0.688191f, 0.587785f}, {-0.716567f, 0.681718f, -0.147621f}, \n{-0.500000f, 0.809017f, -0.309017f}, {-0.525731f, 0.850651f, 0.000000f}, \n{0.000000f, 0.850651f, -0.525731f}, {-0.238856f, 0.864188f, -0.442863f}, \n{0.000000f, 0.955423f, -0.295242f}, {-0.262866f, 0.951056f, -0.162460f}, \n{0.000000f, 1.000000f, 0.000000f}, {0.000000f, 0.955423f, 0.295242f}, \n{-0.262866f, 0.951056f, 0.162460f}, {0.238856f, 0.864188f, 0.442863f}, \n{0.262866f, 0.951056f, 0.162460f}, {0.500000f, 0.809017f, 0.309017f}, \n{0.238856f, 0.864188f, -0.442863f},{0.262866f, 0.951056f, -0.162460f}, \n{0.500000f, 0.809017f, -0.309017f},{0.850651f, 0.525731f, 0.000000f}, \n{0.716567f, 0.681718f, 0.147621f}, {0.716567f, 0.681718f, -0.147621f}, \n{0.525731f, 0.850651f, 0.000000f}, {0.425325f, 0.688191f, 0.587785f}, \n{0.864188f, 0.442863f, 0.238856f}, {0.688191f, 0.587785f, 0.425325f}, \n{0.809017f, 0.309017f, 0.500000f}, {0.681718f, 0.147621f, 0.716567f}, \n{0.587785f, 0.425325f, 0.688191f}, {0.955423f, 0.295242f, 0.000000f}, \n{1.000000f, 0.000000f, 0.000000f}, {0.951056f, 0.162460f, 0.262866f}, \n{0.850651f, -0.525731f, 0.000000f},{0.955423f, -0.295242f, 0.000000f}, \n{0.864188f, -0.442863f, 0.238856f}, {0.951056f, -0.162460f, 0.262866f}, \n{0.809017f, -0.309017f, 0.500000f}, {0.681718f, -0.147621f, 0.716567f}, \n{0.850651f, 0.000000f, 0.525731f}, {0.864188f, 0.442863f, -0.238856f}, \n{0.809017f, 0.309017f, -0.500000f}, {0.951056f, 0.162460f, -0.262866f}, \n{0.525731f, 0.000000f, -0.850651f}, {0.681718f, 0.147621f, -0.716567f}, \n{0.681718f, -0.147621f, -0.716567f},{0.850651f, 0.000000f, -0.525731f}, \n{0.809017f, -0.309017f, -0.500000f}, {0.864188f, -0.442863f, -0.238856f}, \n{0.951056f, -0.162460f, -0.262866f}, {0.147621f, 0.716567f, -0.681718f}, \n{0.309017f, 0.500000f, -0.809017f}, {0.425325f, 0.688191f, -0.587785f}, \n{0.442863f, 0.238856f, -0.864188f}, {0.587785f, 0.425325f, -0.688191f}, \n{0.688191f, 0.587785f, -0.425325f}, {-0.147621f, 0.716567f, -0.681718f}, \n{-0.309017f, 0.500000f, -0.809017f}, {0.000000f, 0.525731f, -0.850651f}, \n{-0.525731f, 0.000000f, -0.850651f}, {-0.442863f, 0.238856f, -0.864188f}, \n{-0.295242f, 0.000000f, -0.955423f}, {-0.162460f, 0.262866f, -0.951056f}, \n{0.000000f, 0.000000f, -1.000000f}, {0.295242f, 0.000000f, -0.955423f}, \n{0.162460f, 0.262866f, -0.951056f}, {-0.442863f, -0.238856f, -0.864188f}, \n{-0.309017f, -0.500000f, -0.809017f}, {-0.162460f, -0.262866f, -0.951056f}, \n{0.000000f, -0.850651f, -0.525731f}, {-0.147621f, -0.716567f, -0.681718f}, \n{0.147621f, -0.716567f, -0.681718f}, {0.000000f, -0.525731f, -0.850651f}, \n{0.309017f, -0.500000f, -0.809017f}, {0.442863f, -0.238856f, -0.864188f}, \n{0.162460f, -0.262866f, -0.951056f}, {0.238856f, -0.864188f, -0.442863f}, \n{0.500000f, -0.809017f, -0.309017f}, {0.425325f, -0.688191f, -0.587785f}, \n{0.716567f, -0.681718f, -0.147621f}, {0.688191f, -0.587785f, -0.425325f}, \n{0.587785f, -0.425325f, -0.688191f}, {0.000000f, -0.955423f, -0.295242f}, \n{0.000000f, -1.000000f, 0.000000f}, {0.262866f, -0.951056f, -0.162460f}, \n{0.000000f, -0.850651f, 0.525731f}, {0.000000f, -0.955423f, 0.295242f}, \n{0.238856f, -0.864188f, 0.442863f}, {0.262866f, -0.951056f, 0.162460f}, \n{0.500000f, -0.809017f, 0.309017f}, {0.716567f, -0.681718f, 0.147621f}, \n{0.525731f, -0.850651f, 0.000000f}, {-0.238856f, -0.864188f, -0.442863f}, \n{-0.500000f, -0.809017f, -0.309017f}, {-0.262866f, -0.951056f, -0.162460f}, \n{-0.850651f, -0.525731f, 0.000000f}, {-0.716567f, -0.681718f, -0.147621f}, \n{-0.716567f, -0.681718f, 0.147621f}, {-0.525731f, -0.850651f, 0.000000f}, \n{-0.500000f, -0.809017f, 0.309017f}, {-0.238856f, -0.864188f, 0.442863f}, \n{-0.262866f, -0.951056f, 0.162460f}, {-0.864188f, -0.442863f, 0.238856f}, \n{-0.809017f, -0.309017f, 0.500000f}, {-0.688191f, -0.587785f, 0.425325f}, \n{-0.681718f, -0.147621f, 0.716567f}, {-0.442863f, -0.238856f, 0.864188f}, \n{-0.587785f, -0.425325f, 0.688191f}, {-0.309017f, -0.500000f, 0.809017f}, \n{-0.147621f, -0.716567f, 0.681718f}, {-0.425325f, -0.688191f, 0.587785f}, \n{-0.162460f, -0.262866f, 0.951056f}, {0.442863f, -0.238856f, 0.864188f}, \n{0.162460f, -0.262866f, 0.951056f}, {0.309017f, -0.500000f, 0.809017f}, \n{0.147621f, -0.716567f, 0.681718f}, {0.000000f, -0.525731f, 0.850651f}, \n{0.425325f, -0.688191f, 0.587785f}, {0.587785f, -0.425325f, 0.688191f}, \n{0.688191f, -0.587785f, 0.425325f}, {-0.955423f, 0.295242f, 0.000000f}, \n{-0.951056f, 0.162460f, 0.262866f}, {-1.000000f, 0.000000f, 0.000000f}, \n{-0.850651f, 0.000000f, 0.525731f}, {-0.955423f, -0.295242f, 0.000000f}, \n{-0.951056f, -0.162460f, 0.262866f}, {-0.864188f, 0.442863f, -0.238856f}, \n{-0.951056f, 0.162460f, -0.262866f}, {-0.809017f, 0.309017f, -0.500000f}, \n{-0.864188f, -0.442863f, -0.238856f}, {-0.951056f, -0.162460f, -0.262866f}, \n{-0.809017f, -0.309017f, -0.500000f}, {-0.681718f, 0.147621f, -0.716567f}, \n{-0.681718f, -0.147621f, -0.716567f}, {-0.850651f, 0.000000f, -0.525731f}, \n{-0.688191f, 0.587785f, -0.425325f}, {-0.587785f, 0.425325f, -0.688191f}, \n{-0.425325f, 0.688191f, -0.587785f}, {-0.425325f, -0.688191f, -0.587785f}, \n{-0.587785f, -0.425325f, -0.688191f}, {-0.688191f, -0.587785f, -0.425325f}\n};\n\n//==============================================================\n\nint\t\tQ_rand( int *seed ) {\n\t*seed = (69069 * *seed + 1);\n\treturn *seed;\n}\n\nfloat\tQ_random( int *seed ) {\n\treturn ( Q_rand( seed ) & 0xffff ) / (float)0x10000;\n}\n\nfloat\tQ_crandom( int *seed ) {\n\treturn 2.0 * ( Q_random( seed ) - 0.5 );\n}\n\n#ifdef __LCC__\n\nint VectorCompare( const vec3_t v1, const vec3_t v2 ) {\n\tif (v1[0] != v2[0] || v1[1] != v2[1] || v1[2] != v2[2]) {\n\t\treturn 0;\n\t}\t\t\t\n\treturn 1;\n}\n\nvec_t VectorLength( const vec3_t v ) {\n\treturn (vec_t)sqrt (v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);\n}\n\nvec_t VectorLengthSquared( const vec3_t v ) {\n\treturn (v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);\n}\n\nvec_t Distance( const vec3_t p1, const vec3_t p2 ) {\n\tvec3_t\tv;\n\n\tVectorSubtract (p2, p1, v);\n\treturn VectorLength( v );\n}\n\nvec_t DistanceSquared( const vec3_t p1, const vec3_t p2 ) {\n\tvec3_t\tv;\n\n\tVectorSubtract (p2, p1, v);\n\treturn v[0]*v[0] + v[1]*v[1] + v[2]*v[2];\n}\n\n// fast vector normalize routine that does not check to make sure\n// that length != 0, nor does it return length, uses rsqrt approximation\nvoid VectorNormalizeFast( vec3_t v )\n{\n\tfloat ilength;\n\n\tilength = Q_rsqrt( DotProduct( v, v ) );\n\n\tv[0] *= ilength;\n\tv[1] *= ilength;\n\tv[2] *= ilength;\n}\n\nvoid VectorInverse( vec3_t v ){\n\tv[0] = -v[0];\n\tv[1] = -v[1];\n\tv[2] = -v[2];\n}\n\nvoid CrossProduct( const vec3_t v1, const vec3_t v2, vec3_t cross ) {\n\tcross[0] = v1[1]*v2[2] - v1[2]*v2[1];\n\tcross[1] = v1[2]*v2[0] - v1[0]*v2[2];\n\tcross[2] = v1[0]*v2[1] - v1[1]*v2[0];\n}\n#endif\n\n//=======================================================\n\nsigned char ClampChar( int i ) {\n\tif ( i < -128 ) {\n\t\treturn -128;\n\t}\n\tif ( i > 127 ) {\n\t\treturn 127;\n\t}\n\treturn i;\n}\n\nsigned short ClampShort( int i ) {\n\tif ( i < -32768 ) {\n\t\treturn -32768;\n\t}\n\tif ( i > 0x7fff ) {\n\t\treturn 0x7fff;\n\t}\n\treturn i;\n}\n\n\n// this isn't a real cheap function to call!\nint DirToByte( vec3_t dir ) {\n\tint\t\ti, best;\n\tfloat\td, bestd;\n\n\tif ( !dir ) {\n\t\treturn 0;\n\t}\n\n\tbestd = 0;\n\tbest = 0;\n\tfor (i=0 ; i<NUMVERTEXNORMALS ; i++)\n\t{\n\t\td = DotProduct (dir, bytedirs[i]);\n\t\tif (d > bestd)\n\t\t{\n\t\t\tbestd = d;\n\t\t\tbest = i;\n\t\t}\n\t}\n\n\treturn best;\n}\n\nvoid ByteToDir( int b, vec3_t dir ) {\n\tif ( b < 0 || b >= NUMVERTEXNORMALS ) {\n\t\tVectorCopy( vec3_origin, dir );\n\t\treturn;\n\t}\n\tVectorCopy (bytedirs[b], dir);\n}\n\n\nunsigned ColorBytes3 (float r, float g, float b) {\n\tunsigned\ti;\n\n\t( (byte *)&i )[0] = r * 255;\n\t( (byte *)&i )[1] = g * 255;\n\t( (byte *)&i )[2] = b * 255;\n\n\treturn i;\n}\n\nunsigned ColorBytes4 (float r, float g, float b, float a) {\n\tunsigned\ti;\n\n\t( (byte *)&i )[0] = r * 255;\n\t( (byte *)&i )[1] = g * 255;\n\t( (byte *)&i )[2] = b * 255;\n\t( (byte *)&i )[3] = a * 255;\n\n\treturn i;\n}\n\nfloat NormalizeColor( const vec3_t in, vec3_t out ) {\n\tfloat\tmax;\n\t\n\tmax = in[0];\n\tif ( in[1] > max ) {\n\t\tmax = in[1];\n\t}\n\tif ( in[2] > max ) {\n\t\tmax = in[2];\n\t}\n\n\tif ( !max ) {\n\t\tVectorClear( out );\n\t} else {\n\t\tout[0] = in[0] / max;\n\t\tout[1] = in[1] / max;\n\t\tout[2] = in[2] / max;\n\t}\n\treturn max;\n}\n\n\n/*\n=====================\nPlaneFromPoints\n\nReturns false if the triangle is degenrate.\nThe normal will point out of the clock for clockwise ordered points\n=====================\n*/\nqboolean PlaneFromPoints( vec4_t plane, const vec3_t a, const vec3_t b, const vec3_t c ) {\n\tvec3_t\td1, d2;\n\n\tVectorSubtract( b, a, d1 );\n\tVectorSubtract( c, a, d2 );\n\tCrossProduct( d2, d1, plane );\n\tif ( VectorNormalize( plane ) == 0 ) {\n\t\treturn qfalse;\n\t}\n\n\tplane[3] = DotProduct( a, plane );\n\treturn qtrue;\n}\n\n/*\n===============\nRotatePointAroundVector\n\nThis is not implemented very well...\n===============\n*/\nvoid RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point,\n\t\t\t\t\t\t\t float degrees ) {\n\tfloat\tm[3][3];\n\tfloat\tim[3][3];\n\tfloat\tzrot[3][3];\n\tfloat\ttmpmat[3][3];\n\tfloat\trot[3][3];\n\tint\ti;\n\tvec3_t vr, vup, vf;\n\tfloat\trad;\n\n\tvf[0] = dir[0];\n\tvf[1] = dir[1];\n\tvf[2] = dir[2];\n\n\tPerpendicularVector( vr, dir );\n\tCrossProduct( vr, vf, vup );\n\n\tm[0][0] = vr[0];\n\tm[1][0] = vr[1];\n\tm[2][0] = vr[2];\n\n\tm[0][1] = vup[0];\n\tm[1][1] = vup[1];\n\tm[2][1] = vup[2];\n\n\tm[0][2] = vf[0];\n\tm[1][2] = vf[1];\n\tm[2][2] = vf[2];\n\n\tmemcpy( im, m, sizeof( im ) );\n\n\tim[0][1] = m[1][0];\n\tim[0][2] = m[2][0];\n\tim[1][0] = m[0][1];\n\tim[1][2] = m[2][1];\n\tim[2][0] = m[0][2];\n\tim[2][1] = m[1][2];\n\n\tmemset( zrot, 0, sizeof( zrot ) );\n\tzrot[0][0] = zrot[1][1] = zrot[2][2] = 1.0F;\n\n\trad = DEG2RAD( degrees );\n\tzrot[0][0] = cos( rad );\n\tzrot[0][1] = sin( rad );\n\tzrot[1][0] = -sin( rad );\n\tzrot[1][1] = cos( rad );\n\n\tMatrixMultiply( m, zrot, tmpmat );\n\tMatrixMultiply( tmpmat, im, rot );\n\n\tfor ( i = 0; i < 3; i++ ) {\n\t\tdst[i] = rot[i][0] * point[0] + rot[i][1] * point[1] + rot[i][2] * point[2];\n\t}\n}\n\n/*\n===============\nRotateAroundDirection\n===============\n*/\nvoid RotateAroundDirection( vec3_t axis[3], float yaw ) {\n\n\t// create an arbitrary axis[1] \n\tPerpendicularVector( axis[1], axis[0] );\n\n\t// rotate it around axis[0] by yaw\n\tif ( yaw ) {\n\t\tvec3_t\ttemp;\n\n\t\tVectorCopy( axis[1], temp );\n\t\tRotatePointAroundVector( axis[1], axis[0], temp, yaw );\n\t}\n\n\t// cross to get axis[2]\n\tCrossProduct( axis[0], axis[1], axis[2] );\n}\n\n\n\nvoid vectoangles( const vec3_t value1, vec3_t angles ) {\n\tfloat\tforward;\n\tfloat\tyaw, pitch;\n\t\n\tif ( value1[1] == 0 && value1[0] == 0 ) {\n\t\tyaw = 0;\n\t\tif ( value1[2] > 0 ) {\n\t\t\tpitch = 90;\n\t\t}\n\t\telse {\n\t\t\tpitch = 270;\n\t\t}\n\t}\n\telse {\n\t\tif ( value1[0] ) {\n\t\t\tyaw = ( atan2 ( value1[1], value1[0] ) * 180 / M_PI );\n\t\t}\n\t\telse if ( value1[1] > 0 ) {\n\t\t\tyaw = 90;\n\t\t}\n\t\telse {\n\t\t\tyaw = 270;\n\t\t}\n\t\tif ( yaw < 0 ) {\n\t\t\tyaw += 360;\n\t\t}\n\n\t\tforward = sqrt ( value1[0]*value1[0] + value1[1]*value1[1] );\n\t\tpitch = ( atan2(value1[2], forward) * 180 / M_PI );\n\t\tif ( pitch < 0 ) {\n\t\t\tpitch += 360;\n\t\t}\n\t}\n\n\tangles[PITCH] = -pitch;\n\tangles[YAW] = yaw;\n\tangles[ROLL] = 0;\n}\n\n\n/*\n=================\nAnglesToAxis\n=================\n*/\nvoid AnglesToAxis( const vec3_t angles, vec3_t axis[3] ) {\n\tvec3_t\tright;\n\n\t// angle vectors returns \"right\" instead of \"y axis\"\n\tAngleVectors( angles, axis[0], right, axis[2] );\n\tVectorSubtract( vec3_origin, right, axis[1] );\n}\n\nvoid AxisClear( vec3_t axis[3] ) {\n\taxis[0][0] = 1;\n\taxis[0][1] = 0;\n\taxis[0][2] = 0;\n\taxis[1][0] = 0;\n\taxis[1][1] = 1;\n\taxis[1][2] = 0;\n\taxis[2][0] = 0;\n\taxis[2][1] = 0;\n\taxis[2][2] = 1;\n}\n\nvoid AxisCopy( vec3_t in[3], vec3_t out[3] ) {\n\tVectorCopy( in[0], out[0] );\n\tVectorCopy( in[1], out[1] );\n\tVectorCopy( in[2], out[2] );\n}\n\nvoid ProjectPointOnPlane( vec3_t dst, const vec3_t p, const vec3_t normal )\n{\n\tfloat d;\n\tvec3_t n;\n\tfloat inv_denom;\n\n\tinv_denom =  DotProduct( normal, normal );\n#ifndef Q3_VM\n\tassert( Q_fabs(inv_denom) != 0.0f ); // bk010122 - zero vectors get here\n#endif\n\tinv_denom = 1.0f / inv_denom;\n\n\td = DotProduct( normal, p ) * inv_denom;\n\n\tn[0] = normal[0] * inv_denom;\n\tn[1] = normal[1] * inv_denom;\n\tn[2] = normal[2] * inv_denom;\n\n\tdst[0] = p[0] - d * n[0];\n\tdst[1] = p[1] - d * n[1];\n\tdst[2] = p[2] - d * n[2];\n}\n\n/*\n================\nMakeNormalVectors\n\nGiven a normalized forward vector, create two\nother perpendicular vectors\n================\n*/\nvoid MakeNormalVectors( const vec3_t forward, vec3_t right, vec3_t up) {\n\tfloat\t\td;\n\n\t// this rotate and negate guarantees a vector\n\t// not colinear with the original\n\tright[1] = -forward[0];\n\tright[2] = forward[1];\n\tright[0] = forward[2];\n\n\td = DotProduct (right, forward);\n\tVectorMA (right, -d, forward, right);\n\tVectorNormalize (right);\n\tCrossProduct (right, forward, up);\n}\n\n\nvoid VectorRotate( vec3_t in, vec3_t matrix[3], vec3_t out )\n{\n\tout[0] = DotProduct( in, matrix[0] );\n\tout[1] = DotProduct( in, matrix[1] );\n\tout[2] = DotProduct( in, matrix[2] );\n}\n\n//============================================================================\n\n#if !idppc\n/*\n** float q_rsqrt( float number )\n*/\nfloat Q_rsqrt( float number )\n{\n\tlong i;\n\tfloat x2, y;\n\tconst float threehalfs = 1.5F;\n\n\tx2 = number * 0.5F;\n\ty  = number;\n\ti  = * ( long * ) &y;\t\t\t\t\t\t// evil floating point bit level hacking\n\ti  = 0x5f3759df - ( i >> 1 );               // what the fuck?\n\ty  = * ( float * ) &i;\n\ty  = y * ( threehalfs - ( x2 * y * y ) );   // 1st iteration\n//\ty  = y * ( threehalfs - ( x2 * y * y ) );   // 2nd iteration, this can be removed\n\n#ifndef Q3_VM\n#ifdef __linux__\n\tassert( !isnan(y) ); // bk010122 - FPE?\n#endif\n#endif\n\treturn y;\n}\n\nfloat Q_fabs( float f ) {\n\tint tmp = * ( int * ) &f;\n\ttmp &= 0x7FFFFFFF;\n\treturn * ( float * ) &tmp;\n}\n#endif\n\n//============================================================\n\n/*\n===============\nLerpAngle\n\n===============\n*/\nfloat LerpAngle (float from, float to, float frac) {\n\tfloat\ta;\n\n\tif ( to - from > 180 ) {\n\t\tto -= 360;\n\t}\n\tif ( to - from < -180 ) {\n\t\tto += 360;\n\t}\n\ta = from + frac * (to - from);\n\n\treturn a;\n}\n\n\n/*\n=================\nAngleSubtract\n\nAlways returns a value from -180 to 180\n=================\n*/\nfloat\tAngleSubtract( float a1, float a2 ) {\n\tfloat\ta;\n\n\ta = a1 - a2;\n\twhile ( a > 180 ) {\n\t\ta -= 360;\n\t}\n\twhile ( a < -180 ) {\n\t\ta += 360;\n\t}\n\treturn a;\n}\n\n\nvoid AnglesSubtract( vec3_t v1, vec3_t v2, vec3_t v3 ) {\n\tv3[0] = AngleSubtract( v1[0], v2[0] );\n\tv3[1] = AngleSubtract( v1[1], v2[1] );\n\tv3[2] = AngleSubtract( v1[2], v2[2] );\n}\n\n\nfloat\tAngleMod(float a) {\n\ta = (360.0/65536) * ((int)(a*(65536/360.0)) & 65535);\n\treturn a;\n}\n\n\n/*\n=================\nAngleNormalize360\n\nreturns angle normalized to the range [0 <= angle < 360]\n=================\n*/\nfloat AngleNormalize360 ( float angle ) {\n\treturn (360.0 / 65536) * ((int)(angle * (65536 / 360.0)) & 65535);\n}\n\n\n/*\n=================\nAngleNormalize180\n\nreturns angle normalized to the range [-180 < angle <= 180]\n=================\n*/\nfloat AngleNormalize180 ( float angle ) {\n\tangle = AngleNormalize360( angle );\n\tif ( angle > 180.0 ) {\n\t\tangle -= 360.0;\n\t}\n\treturn angle;\n}\n\n\n/*\n=================\nAngleDelta\n\nreturns the normalized delta from angle1 to angle2\n=================\n*/\nfloat AngleDelta ( float angle1, float angle2 ) {\n\treturn AngleNormalize180( angle1 - angle2 );\n}\n\n\n//============================================================\n\n\n/*\n=================\nSetPlaneSignbits\n=================\n*/\nvoid SetPlaneSignbits (cplane_t *out) {\n\tint\tbits, j;\n\n\t// for fast box on planeside test\n\tbits = 0;\n\tfor (j=0 ; j<3 ; j++) {\n\t\tif (out->normal[j] < 0) {\n\t\t\tbits |= 1<<j;\n\t\t}\n\t}\n\tout->signbits = bits;\n}\n\n\n/*\n==================\nBoxOnPlaneSide\n\nReturns 1, 2, or 1 + 2\n\n// this is the slow, general version\nint BoxOnPlaneSide2 (vec3_t emins, vec3_t emaxs, struct cplane_s *p)\n{\n\tint\t\ti;\n\tfloat\tdist1, dist2;\n\tint\t\tsides;\n\tvec3_t\tcorners[2];\n\n\tfor (i=0 ; i<3 ; i++)\n\t{\n\t\tif (p->normal[i] < 0)\n\t\t{\n\t\t\tcorners[0][i] = emins[i];\n\t\t\tcorners[1][i] = emaxs[i];\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcorners[1][i] = emins[i];\n\t\t\tcorners[0][i] = emaxs[i];\n\t\t}\n\t}\n\tdist1 = DotProduct (p->normal, corners[0]) - p->dist;\n\tdist2 = DotProduct (p->normal, corners[1]) - p->dist;\n\tsides = 0;\n\tif (dist1 >= 0)\n\t\tsides = 1;\n\tif (dist2 < 0)\n\t\tsides |= 2;\n\n\treturn sides;\n}\n\n==================\n*/\n\n#if !( (defined __linux__ || __FreeBSD__) && (defined __i386__) && (!defined C_ONLY)) // rb010123\n\n#if defined __LCC__ || defined C_ONLY || !id386 || defined __VECTORC\n\nint BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct cplane_s *p)\n{\n\tfloat\tdist1, dist2;\n\tint\t\tsides;\n\n// fast axial cases\n\tif (p->type < 3)\n\t{\n\t\tif (p->dist <= emins[p->type])\n\t\t\treturn 1;\n\t\tif (p->dist >= emaxs[p->type])\n\t\t\treturn 2;\n\t\treturn 3;\n\t}\n\n// general case\n\tswitch (p->signbits)\n\t{\n\tcase 0:\n\t\tdist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];\n\t\tdist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];\n\t\tbreak;\n\tcase 1:\n\t\tdist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];\n\t\tdist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];\n\t\tbreak;\n\tcase 2:\n\t\tdist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];\n\t\tdist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];\n\t\tbreak;\n\tcase 3:\n\t\tdist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];\n\t\tdist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];\n\t\tbreak;\n\tcase 4:\n\t\tdist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];\n\t\tdist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];\n\t\tbreak;\n\tcase 5:\n\t\tdist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];\n\t\tdist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];\n\t\tbreak;\n\tcase 6:\n\t\tdist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];\n\t\tdist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];\n\t\tbreak;\n\tcase 7:\n\t\tdist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];\n\t\tdist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];\n\t\tbreak;\n\tdefault:\n\t\tdist1 = dist2 = 0;\t\t// shut up compiler\n\t\tbreak;\n\t}\n\n\tsides = 0;\n\tif (dist1 >= p->dist)\n\t\tsides = 1;\n\tif (dist2 < p->dist)\n\t\tsides |= 2;\n\n\treturn sides;\n}\n#else\n#pragma warning( disable: 4035 )\n\n__declspec( naked ) int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct cplane_s *p)\n{\n\tstatic int bops_initialized;\n\tstatic int Ljmptab[8];\n\n\t__asm {\n\n\t\tpush ebx\n\t\t\t\n\t\tcmp bops_initialized, 1\n\t\tje  initialized\n\t\tmov bops_initialized, 1\n\t\t\n\t\tmov Ljmptab[0*4], offset Lcase0\n\t\tmov Ljmptab[1*4], offset Lcase1\n\t\tmov Ljmptab[2*4], offset Lcase2\n\t\tmov Ljmptab[3*4], offset Lcase3\n\t\tmov Ljmptab[4*4], offset Lcase4\n\t\tmov Ljmptab[5*4], offset Lcase5\n\t\tmov Ljmptab[6*4], offset Lcase6\n\t\tmov Ljmptab[7*4], offset Lcase7\n\t\t\t\ninitialized:\n\n\t\tmov edx,dword ptr[4+12+esp]\n\t\tmov ecx,dword ptr[4+4+esp]\n\t\txor eax,eax\n\t\tmov ebx,dword ptr[4+8+esp]\n\t\tmov al,byte ptr[17+edx]\n\t\tcmp al,8\n\t\tjge Lerror\n\t\tfld dword ptr[0+edx]\n\t\tfld st(0)\n\t\tjmp dword ptr[Ljmptab+eax*4]\nLcase0:\n\t\tfmul dword ptr[ebx]\n\t\tfld dword ptr[0+4+edx]\n\t\tfxch st(2)\n\t\tfmul dword ptr[ecx]\n\t\tfxch st(2)\n\t\tfld st(0)\n\t\tfmul dword ptr[4+ebx]\n\t\tfld dword ptr[0+8+edx]\n\t\tfxch st(2)\n\t\tfmul dword ptr[4+ecx]\n\t\tfxch st(2)\n\t\tfld st(0)\n\t\tfmul dword ptr[8+ebx]\n\t\tfxch st(5)\n\t\tfaddp st(3),st(0)\n\t\tfmul dword ptr[8+ecx]\n\t\tfxch st(1)\n\t\tfaddp st(3),st(0)\n\t\tfxch st(3)\n\t\tfaddp st(2),st(0)\n\t\tjmp LSetSides\nLcase1:\n\t\tfmul dword ptr[ecx]\n\t\tfld dword ptr[0+4+edx]\n\t\tfxch st(2)\n\t\tfmul dword ptr[ebx]\n\t\tfxch st(2)\n\t\tfld st(0)\n\t\tfmul dword ptr[4+ebx]\n\t\tfld dword ptr[0+8+edx]\n\t\tfxch st(2)\n\t\tfmul dword ptr[4+ecx]\n\t\tfxch st(2)\n\t\tfld st(0)\n\t\tfmul dword ptr[8+ebx]\n\t\tfxch st(5)\n\t\tfaddp st(3),st(0)\n\t\tfmul dword ptr[8+ecx]\n\t\tfxch st(1)\n\t\tfaddp st(3),st(0)\n\t\tfxch st(3)\n\t\tfaddp st(2),st(0)\n\t\tjmp LSetSides\nLcase2:\n\t\tfmul dword ptr[ebx]\n\t\tfld dword ptr[0+4+edx]\n\t\tfxch st(2)\n\t\tfmul dword ptr[ecx]\n\t\tfxch st(2)\n\t\tfld st(0)\n\t\tfmul dword ptr[4+ecx]\n\t\tfld dword ptr[0+8+edx]\n\t\tfxch st(2)\n\t\tfmul dword ptr[4+ebx]\n\t\tfxch st(2)\n\t\tfld st(0)\n\t\tfmul dword ptr[8+ebx]\n\t\tfxch st(5)\n\t\tfaddp st(3),st(0)\n\t\tfmul dword ptr[8+ecx]\n\t\tfxch st(1)\n\t\tfaddp st(3),st(0)\n\t\tfxch st(3)\n\t\tfaddp st(2),st(0)\n\t\tjmp LSetSides\nLcase3:\n\t\tfmul dword ptr[ecx]\n\t\tfld dword ptr[0+4+edx]\n\t\tfxch st(2)\n\t\tfmul dword ptr[ebx]\n\t\tfxch st(2)\n\t\tfld st(0)\n\t\tfmul dword ptr[4+ecx]\n\t\tfld dword ptr[0+8+edx]\n\t\tfxch st(2)\n\t\tfmul dword ptr[4+ebx]\n\t\tfxch st(2)\n\t\tfld st(0)\n\t\tfmul dword ptr[8+ebx]\n\t\tfxch st(5)\n\t\tfaddp st(3),st(0)\n\t\tfmul dword ptr[8+ecx]\n\t\tfxch st(1)\n\t\tfaddp st(3),st(0)\n\t\tfxch st(3)\n\t\tfaddp st(2),st(0)\n\t\tjmp LSetSides\nLcase4:\n\t\tfmul dword ptr[ebx]\n\t\tfld dword ptr[0+4+edx]\n\t\tfxch st(2)\n\t\tfmul dword ptr[ecx]\n\t\tfxch st(2)\n\t\tfld st(0)\n\t\tfmul dword ptr[4+ebx]\n\t\tfld dword ptr[0+8+edx]\n\t\tfxch st(2)\n\t\tfmul dword ptr[4+ecx]\n\t\tfxch st(2)\n\t\tfld st(0)\n\t\tfmul dword ptr[8+ecx]\n\t\tfxch st(5)\n\t\tfaddp st(3),st(0)\n\t\tfmul dword ptr[8+ebx]\n\t\tfxch st(1)\n\t\tfaddp st(3),st(0)\n\t\tfxch st(3)\n\t\tfaddp st(2),st(0)\n\t\tjmp LSetSides\nLcase5:\n\t\tfmul dword ptr[ecx]\n\t\tfld dword ptr[0+4+edx]\n\t\tfxch st(2)\n\t\tfmul dword ptr[ebx]\n\t\tfxch st(2)\n\t\tfld st(0)\n\t\tfmul dword ptr[4+ebx]\n\t\tfld dword ptr[0+8+edx]\n\t\tfxch st(2)\n\t\tfmul dword ptr[4+ecx]\n\t\tfxch st(2)\n\t\tfld st(0)\n\t\tfmul dword ptr[8+ecx]\n\t\tfxch st(5)\n\t\tfaddp st(3),st(0)\n\t\tfmul dword ptr[8+ebx]\n\t\tfxch st(1)\n\t\tfaddp st(3),st(0)\n\t\tfxch st(3)\n\t\tfaddp st(2),st(0)\n\t\tjmp LSetSides\nLcase6:\n\t\tfmul dword ptr[ebx]\n\t\tfld dword ptr[0+4+edx]\n\t\tfxch st(2)\n\t\tfmul dword ptr[ecx]\n\t\tfxch st(2)\n\t\tfld st(0)\n\t\tfmul dword ptr[4+ecx]\n\t\tfld dword ptr[0+8+edx]\n\t\tfxch st(2)\n\t\tfmul dword ptr[4+ebx]\n\t\tfxch st(2)\n\t\tfld st(0)\n\t\tfmul dword ptr[8+ecx]\n\t\tfxch st(5)\n\t\tfaddp st(3),st(0)\n\t\tfmul dword ptr[8+ebx]\n\t\tfxch st(1)\n\t\tfaddp st(3),st(0)\n\t\tfxch st(3)\n\t\tfaddp st(2),st(0)\n\t\tjmp LSetSides\nLcase7:\n\t\tfmul dword ptr[ecx]\n\t\tfld dword ptr[0+4+edx]\n\t\tfxch st(2)\n\t\tfmul dword ptr[ebx]\n\t\tfxch st(2)\n\t\tfld st(0)\n\t\tfmul dword ptr[4+ecx]\n\t\tfld dword ptr[0+8+edx]\n\t\tfxch st(2)\n\t\tfmul dword ptr[4+ebx]\n\t\tfxch st(2)\n\t\tfld st(0)\n\t\tfmul dword ptr[8+ecx]\n\t\tfxch st(5)\n\t\tfaddp st(3),st(0)\n\t\tfmul dword ptr[8+ebx]\n\t\tfxch st(1)\n\t\tfaddp st(3),st(0)\n\t\tfxch st(3)\n\t\tfaddp st(2),st(0)\nLSetSides:\n\t\tfaddp st(2),st(0)\n\t\tfcomp dword ptr[12+edx]\n\t\txor ecx,ecx\n\t\tfnstsw ax\n\t\tfcomp dword ptr[12+edx]\n\t\tand ah,1\n\t\txor ah,1\n\t\tadd cl,ah\n\t\tfnstsw ax\n\t\tand ah,1\n\t\tadd ah,ah\n\t\tadd cl,ah\n\t\tpop ebx\n\t\tmov eax,ecx\n\t\tret\nLerror:\n\t\tint 3\n\t}\n}\n#pragma warning( default: 4035 )\n\n#endif\n#endif\n\n/*\n=================\nRadiusFromBounds\n=================\n*/\nfloat RadiusFromBounds( const vec3_t mins, const vec3_t maxs ) {\n\tint\t\ti;\n\tvec3_t\tcorner;\n\tfloat\ta, b;\n\n\tfor (i=0 ; i<3 ; i++) {\n\t\ta = fabs( mins[i] );\n\t\tb = fabs( maxs[i] );\n\t\tcorner[i] = a > b ? a : b;\n\t}\n\n\treturn VectorLength (corner);\n}\n\n\nvoid ClearBounds( vec3_t mins, vec3_t maxs ) {\n\tmins[0] = mins[1] = mins[2] = 99999;\n\tmaxs[0] = maxs[1] = maxs[2] = -99999;\n}\n\nvoid AddPointToBounds( const vec3_t v, vec3_t mins, vec3_t maxs ) {\n\tif ( v[0] < mins[0] ) {\n\t\tmins[0] = v[0];\n\t}\n\tif ( v[0] > maxs[0]) {\n\t\tmaxs[0] = v[0];\n\t}\n\n\tif ( v[1] < mins[1] ) {\n\t\tmins[1] = v[1];\n\t}\n\tif ( v[1] > maxs[1]) {\n\t\tmaxs[1] = v[1];\n\t}\n\n\tif ( v[2] < mins[2] ) {\n\t\tmins[2] = v[2];\n\t}\n\tif ( v[2] > maxs[2]) {\n\t\tmaxs[2] = v[2];\n\t}\n}\n\n\nvec_t VectorNormalize( vec3_t v ) {\n\t// NOTE: TTimo - Apple G4 altivec source uses double?\n\tfloat\tlength, ilength;\n\n\tlength = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];\n\tlength = sqrt (length);\n\n\tif ( length ) {\n\t\tilength = 1/length;\n\t\tv[0] *= ilength;\n\t\tv[1] *= ilength;\n\t\tv[2] *= ilength;\n\t}\n\t\t\n\treturn length;\n}\n\nvec_t VectorNormalize2( const vec3_t v, vec3_t out) {\n\tfloat\tlength, ilength;\n\n\tlength = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];\n\tlength = sqrt (length);\n\n\tif (length)\n\t{\n#ifndef Q3_VM // bk0101022 - FPE related\n//\t  assert( ((Q_fabs(v[0])!=0.0f) || (Q_fabs(v[1])!=0.0f) || (Q_fabs(v[2])!=0.0f)) );\n#endif\n\t\tilength = 1/length;\n\t\tout[0] = v[0]*ilength;\n\t\tout[1] = v[1]*ilength;\n\t\tout[2] = v[2]*ilength;\n\t} else {\n#ifndef Q3_VM // bk0101022 - FPE related\n//\t  assert( ((Q_fabs(v[0])==0.0f) && (Q_fabs(v[1])==0.0f) && (Q_fabs(v[2])==0.0f)) );\n#endif\n\t\tVectorClear( out );\n\t}\n\t\t\n\treturn length;\n\n}\n\nvoid _VectorMA( const vec3_t veca, float scale, const vec3_t vecb, vec3_t vecc) {\n\tvecc[0] = veca[0] + scale*vecb[0];\n\tvecc[1] = veca[1] + scale*vecb[1];\n\tvecc[2] = veca[2] + scale*vecb[2];\n}\n\n\nvec_t _DotProduct( const vec3_t v1, const vec3_t v2 ) {\n\treturn v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];\n}\n\nvoid _VectorSubtract( const vec3_t veca, const vec3_t vecb, vec3_t out ) {\n\tout[0] = veca[0]-vecb[0];\n\tout[1] = veca[1]-vecb[1];\n\tout[2] = veca[2]-vecb[2];\n}\n\nvoid _VectorAdd( const vec3_t veca, const vec3_t vecb, vec3_t out ) {\n\tout[0] = veca[0]+vecb[0];\n\tout[1] = veca[1]+vecb[1];\n\tout[2] = veca[2]+vecb[2];\n}\n\nvoid _VectorCopy( const vec3_t in, vec3_t out ) {\n\tout[0] = in[0];\n\tout[1] = in[1];\n\tout[2] = in[2];\n}\n\nvoid _VectorScale( const vec3_t in, vec_t scale, vec3_t out ) {\n\tout[0] = in[0]*scale;\n\tout[1] = in[1]*scale;\n\tout[2] = in[2]*scale;\n}\n\nvoid Vector4Scale( const vec4_t in, vec_t scale, vec4_t out ) {\n\tout[0] = in[0]*scale;\n\tout[1] = in[1]*scale;\n\tout[2] = in[2]*scale;\n\tout[3] = in[3]*scale;\n}\n\n\nint Q_log2( int val ) {\n\tint answer;\n\n\tanswer = 0;\n\twhile ( ( val>>=1 ) != 0 ) {\n\t\tanswer++;\n\t}\n\treturn answer;\n}\n\n\n\n/*\n=================\nPlaneTypeForNormal\n=================\n*/\n/*\nint\tPlaneTypeForNormal (vec3_t normal) {\n\tif ( normal[0] == 1.0 )\n\t\treturn PLANE_X;\n\tif ( normal[1] == 1.0 )\n\t\treturn PLANE_Y;\n\tif ( normal[2] == 1.0 )\n\t\treturn PLANE_Z;\n\t\n\treturn PLANE_NON_AXIAL;\n}\n*/\n\n\n/*\n================\nMatrixMultiply\n================\n*/\nvoid MatrixMultiply(float in1[3][3], float in2[3][3], float out[3][3]) {\n\tout[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] +\n\t\t\t\tin1[0][2] * in2[2][0];\n\tout[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] +\n\t\t\t\tin1[0][2] * in2[2][1];\n\tout[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] +\n\t\t\t\tin1[0][2] * in2[2][2];\n\tout[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] +\n\t\t\t\tin1[1][2] * in2[2][0];\n\tout[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] +\n\t\t\t\tin1[1][2] * in2[2][1];\n\tout[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] +\n\t\t\t\tin1[1][2] * in2[2][2];\n\tout[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] +\n\t\t\t\tin1[2][2] * in2[2][0];\n\tout[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] +\n\t\t\t\tin1[2][2] * in2[2][1];\n\tout[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] +\n\t\t\t\tin1[2][2] * in2[2][2];\n}\n\n\nvoid AngleVectors( const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up) {\n\tfloat\t\tangle;\n\tstatic float\t\tsr, sp, sy, cr, cp, cy;\n\t// static to help MS compiler fp bugs\n\n\tangle = angles[YAW] * (M_PI*2 / 360);\n\tsy = sin(angle);\n\tcy = cos(angle);\n\tangle = angles[PITCH] * (M_PI*2 / 360);\n\tsp = sin(angle);\n\tcp = cos(angle);\n\tangle = angles[ROLL] * (M_PI*2 / 360);\n\tsr = sin(angle);\n\tcr = cos(angle);\n\n\tif (forward)\n\t{\n\t\tforward[0] = cp*cy;\n\t\tforward[1] = cp*sy;\n\t\tforward[2] = -sp;\n\t}\n\tif (right)\n\t{\n\t\tright[0] = (-1*sr*sp*cy+-1*cr*-sy);\n\t\tright[1] = (-1*sr*sp*sy+-1*cr*cy);\n\t\tright[2] = -1*sr*cp;\n\t}\n\tif (up)\n\t{\n\t\tup[0] = (cr*sp*cy+-sr*-sy);\n\t\tup[1] = (cr*sp*sy+-sr*cy);\n\t\tup[2] = cr*cp;\n\t}\n}\n\n/*\n** assumes \"src\" is normalized\n*/\nvoid PerpendicularVector( vec3_t dst, const vec3_t src )\n{\n\tint\tpos;\n\tint i;\n\tfloat minelem = 1.0F;\n\tvec3_t tempvec;\n\n\t/*\n\t** find the smallest magnitude axially aligned vector\n\t*/\n\tfor ( pos = 0, i = 0; i < 3; i++ )\n\t{\n\t\tif ( fabs( src[i] ) < minelem )\n\t\t{\n\t\t\tpos = i;\n\t\t\tminelem = fabs( src[i] );\n\t\t}\n\t}\n\ttempvec[0] = tempvec[1] = tempvec[2] = 0.0F;\n\ttempvec[pos] = 1.0F;\n\n\t/*\n\t** project the point onto the plane defined by src\n\t*/\n\tProjectPointOnPlane( dst, tempvec, src );\n\n\t/*\n\t** normalize the result\n\t*/\n\tVectorNormalize( dst );\n}\n\n\n"
  },
  {
    "path": "src/game/q_shared.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n// q_shared.c -- stateless support routines that are included in each code dll\n#include \"q_shared.h\"\n\nfloat Com_Clamp( float min, float max, float value ) {\n\tif ( value < min ) {\n\t\treturn min;\n\t}\n\tif ( value > max ) {\n\t\treturn max;\n\t}\n\treturn value;\n}\n\n\n/*\n============\nCOM_SkipPath\n============\n*/\nchar *COM_SkipPath (char *pathname)\n{\n\tchar\t*last;\n\t\n\tlast = pathname;\n\twhile (*pathname)\n\t{\n\t\tif (*pathname=='/')\n\t\t\tlast = pathname+1;\n\t\tpathname++;\n\t}\n\treturn last;\n}\n\n/*\n============\nCOM_StripExtension\n============\n*/\nvoid COM_StripExtension( const char *in, char *out ) {\n\twhile ( *in && *in != '.' ) {\n\t\t*out++ = *in++;\n\t}\n\t*out = 0;\n}\n\n\n/*\n==================\nCOM_DefaultExtension\n==================\n*/\nvoid COM_DefaultExtension (char *path, int maxSize, const char *extension ) {\n\tchar\toldPath[MAX_QPATH];\n\tchar    *src;\n\n//\n// if path doesn't have a .EXT, append extension\n// (extension should include the .)\n//\n\tsrc = path + (int)strlen(path) - 1;\n\n\twhile (*src != '/' && src != path) {\n\t\tif ( *src == '.' ) {\n\t\t\treturn;                 // it has an extension\n\t\t}\n\t\tsrc--;\n\t}\n\n\tQ_strncpyz( oldPath, path, sizeof( oldPath ) );\n\tCom_sprintf( path, maxSize, \"%s%s\", oldPath, extension );\n}\n\n/*\n============================================================================\n\n\t\t\t\t\tBYTE ORDER FUNCTIONS\n\n============================================================================\n*/\n/*\n// can't just use function pointers, or dll linkage can\n// mess up when qcommon is included in multiple places\nstatic short\t(*_BigShort) (short l);\nstatic short\t(*_LittleShort) (short l);\nstatic int\t\t(*_BigLong) (int l);\nstatic int\t\t(*_LittleLong) (int l);\nstatic qint64\t(*_BigLong64) (qint64 l);\nstatic qint64\t(*_LittleLong64) (qint64 l);\nstatic float\t(*_BigFloat) (const float *l);\nstatic float\t(*_LittleFloat) (const float *l);\n\nshort\tBigShort(short l){return _BigShort(l);}\nshort\tLittleShort(short l) {return _LittleShort(l);}\nint\t\tBigLong (int l) {return _BigLong(l);}\nint\t\tLittleLong (int l) {return _LittleLong(l);}\nqint64 \tBigLong64 (qint64 l) {return _BigLong64(l);}\nqint64 \tLittleLong64 (qint64 l) {return _LittleLong64(l);}\nfloat\tBigFloat (const float *l) {return _BigFloat(l);}\nfloat\tLittleFloat (const float *l) {return _LittleFloat(l);}\n*/\n\nshort   ShortSwap (short l)\n{\n\tbyte    b1,b2;\n\n\tb1 = l&255;\n\tb2 = (l>>8)&255;\n\n\treturn (b1<<8) + b2;\n}\n\nshort\tShortNoSwap (short l)\n{\n\treturn l;\n}\n\nint    LongSwap (int l)\n{\n\tbyte    b1,b2,b3,b4;\n\n\tb1 = l&255;\n\tb2 = (l>>8)&255;\n\tb3 = (l>>16)&255;\n\tb4 = (l>>24)&255;\n\n\treturn ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;\n}\n\nint\tLongNoSwap (int l)\n{\n\treturn l;\n}\n\nqint64 Long64Swap (qint64 ll)\n{\n\tqint64\tresult;\n\n\tresult.b0 = ll.b7;\n\tresult.b1 = ll.b6;\n\tresult.b2 = ll.b5;\n\tresult.b3 = ll.b4;\n\tresult.b4 = ll.b3;\n\tresult.b5 = ll.b2;\n\tresult.b6 = ll.b1;\n\tresult.b7 = ll.b0;\n\n\treturn result;\n}\n\nqint64 Long64NoSwap (qint64 ll)\n{\n\treturn ll;\n}\n\ntypedef union {\n    float\tf;\n    unsigned int i;\n} _FloatByteUnion;\n\nfloat FloatSwap (const float *f) {\n\tconst _FloatByteUnion *in;\n\t_FloatByteUnion out;\n\n\tin = (_FloatByteUnion *)f;\n\tout.i = LongSwap(in->i);\n\n\treturn out.f;\n}\n\nfloat FloatNoSwap (const float *f)\n{\n\treturn *f;\n}\n\n/*\n================\nSwap_Init\n================\n*/\n/*\nvoid Swap_Init (void)\n{\n\tbyte\tswaptest[2] = {1,0};\n\n// set the byte swapping variables in a portable manner\t\n\tif ( *(short *)swaptest == 1)\n\t{\n\t\t_BigShort = ShortSwap;\n\t\t_LittleShort = ShortNoSwap;\n\t\t_BigLong = LongSwap;\n\t\t_LittleLong = LongNoSwap;\n\t\t_BigLong64 = Long64Swap;\n\t\t_LittleLong64 = Long64NoSwap;\n\t\t_BigFloat = FloatSwap;\n\t\t_LittleFloat = FloatNoSwap;\n\t}\n\telse\n\t{\n\t\t_BigShort = ShortNoSwap;\n\t\t_LittleShort = ShortSwap;\n\t\t_BigLong = LongNoSwap;\n\t\t_LittleLong = LongSwap;\n\t\t_BigLong64 = Long64NoSwap;\n\t\t_LittleLong64 = Long64Swap;\n\t\t_BigFloat = FloatNoSwap;\n\t\t_LittleFloat = FloatSwap;\n\t}\n\n}\n*/\n\n/*\n============================================================================\n\nPARSING\n\n============================================================================\n*/\n\nstatic\tchar\tcom_token[MAX_TOKEN_CHARS];\nstatic\tchar\tcom_parsename[MAX_TOKEN_CHARS];\nstatic\tint\t\tcom_lines;\n\nvoid COM_BeginParseSession( const char *name )\n{\n\tcom_lines = 0;\n\tCom_sprintf(com_parsename, sizeof(com_parsename), \"%s\", name);\n}\n\nint COM_GetCurrentParseLine( void )\n{\n\treturn com_lines;\n}\n\nchar *COM_Parse( char **data_p )\n{\n\treturn COM_ParseExt( data_p, qtrue );\n}\n\nvoid COM_ParseError( char *format, ... )\n{\n\tva_list argptr;\n\tstatic char string[4096];\n\n\tva_start (argptr, format);\n\tvsprintf (string, format, argptr);\n\tva_end (argptr);\n\n\tCom_Printf(\"ERROR: %s, line %d: %s\\n\", com_parsename, com_lines, string);\n}\n\nvoid COM_ParseWarning( char *format, ... )\n{\n\tva_list argptr;\n\tstatic char string[4096];\n\n\tva_start (argptr, format);\n\tvsprintf (string, format, argptr);\n\tva_end (argptr);\n\n\tCom_Printf(\"WARNING: %s, line %d: %s\\n\", com_parsename, com_lines, string);\n}\n\n/*\n==============\nCOM_Parse\n\nParse a token out of a string\nWill never return NULL, just empty strings\n\nIf \"allowLineBreaks\" is qtrue then an empty\nstring will be returned if the next token is\na newline.\n==============\n*/\nstatic char *SkipWhitespace( char *data, qboolean *hasNewLines ) {\n\tint c;\n\n\twhile( (c = *data) <= ' ') {\n\t\tif( !c ) {\n\t\t\treturn NULL;\n\t\t}\n\t\tif( c == '\\n' ) {\n\t\t\tcom_lines++;\n\t\t\t*hasNewLines = qtrue;\n\t\t}\n\t\tdata++;\n\t}\n\n\treturn data;\n}\n\nint COM_Compress( char *data_p ) {\n\tchar *in, *out;\n\tint c;\n\tqboolean newline = qfalse, whitespace = qfalse;\n\n\tin = out = data_p;\n\tif (in) {\n\t\twhile ((c = *in) != 0) {\n\t\t\t// skip double slash comments\n\t\t\tif ( c == '/' && in[1] == '/' ) {\n\t\t\t\twhile (*in && *in != '\\n') {\n\t\t\t\t\tin++;\n\t\t\t\t}\n\t\t\t// skip /* */ comments\n\t\t\t} else if ( c == '/' && in[1] == '*' ) {\n\t\t\t\twhile ( *in && ( *in != '*' || in[1] != '/' ) ) \n\t\t\t\t\tin++;\n\t\t\t\tif ( *in ) \n\t\t\t\t\tin += 2;\n                        // record when we hit a newline\n                        } else if ( c == '\\n' || c == '\\r' ) {\n                            newline = qtrue;\n                            in++;\n                        // record when we hit whitespace\n                        } else if ( c == ' ' || c == '\\t') {\n                            whitespace = qtrue;\n                            in++;\n                        // an actual token\n\t\t\t} else {\n                            // if we have a pending newline, emit it (and it counts as whitespace)\n                            if (newline) {\n                                *out++ = '\\n';\n                                newline = qfalse;\n                                whitespace = qfalse;\n                            } if (whitespace) {\n                                *out++ = ' ';\n                                whitespace = qfalse;\n                            }\n                            \n                            // copy quoted strings unmolested\n                            if (c == '\"') {\n                                    *out++ = c;\n                                    in++;\n                                    while (1) {\n                                        c = *in;\n                                        if (c && c != '\"') {\n                                            *out++ = c;\n                                            in++;\n                                        } else {\n                                            break;\n                                        }\n                                    }\n                                    if (c == '\"') {\n                                        *out++ = c;\n                                        in++;\n                                    }\n                            } else {\n                                *out = c;\n                                out++;\n                                in++;\n                            }\n\t\t\t}\n\t\t}\n\t}\n\t*out = 0;\n\treturn out - data_p;\n}\n\nchar *COM_ParseExt( char **data_p, qboolean allowLineBreaks )\n{\n\tint c = 0, len;\n\tqboolean hasNewLines = qfalse;\n\tchar *data;\n\n\tdata = *data_p;\n\tlen = 0;\n\tcom_token[0] = 0;\n\n\t// make sure incoming data is valid\n\tif ( !data )\n\t{\n\t\t*data_p = NULL;\n\t\treturn com_token;\n\t}\n\n\twhile ( 1 )\n\t{\n\t\t// skip whitespace\n\t\tdata = SkipWhitespace( data, &hasNewLines );\n\t\tif ( !data )\n\t\t{\n\t\t\t*data_p = NULL;\n\t\t\treturn com_token;\n\t\t}\n\t\tif ( hasNewLines && !allowLineBreaks )\n\t\t{\n\t\t\t*data_p = data;\n\t\t\treturn com_token;\n\t\t}\n\n\t\tc = *data;\n\n\t\t// skip double slash comments\n\t\tif ( c == '/' && data[1] == '/' )\n\t\t{\n\t\t\tdata += 2;\n\t\t\twhile (*data && *data != '\\n') {\n\t\t\t\tdata++;\n\t\t\t}\n\t\t}\n\t\t// skip /* */ comments\n\t\telse if ( c=='/' && data[1] == '*' ) \n\t\t{\n\t\t\tdata += 2;\n\t\t\twhile ( *data && ( *data != '*' || data[1] != '/' ) ) \n\t\t\t{\n\t\t\t\tdata++;\n\t\t\t}\n\t\t\tif ( *data ) \n\t\t\t{\n\t\t\t\tdata += 2;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// handle quoted strings\n\tif (c == '\\\"')\n\t{\n\t\tdata++;\n\t\twhile (1)\n\t\t{\n\t\t\tc = *data++;\n\t\t\tif (c=='\\\"' || !c)\n\t\t\t{\n\t\t\t\tcom_token[len] = 0;\n\t\t\t\t*data_p = ( char * ) data;\n\t\t\t\treturn com_token;\n\t\t\t}\n\t\t\tif (len < MAX_TOKEN_CHARS)\n\t\t\t{\n\t\t\t\tcom_token[len] = c;\n\t\t\t\tlen++;\n\t\t\t}\n\t\t}\n\t}\n\n\t// parse a regular word\n\tdo\n\t{\n\t\tif (len < MAX_TOKEN_CHARS)\n\t\t{\n\t\t\tcom_token[len] = c;\n\t\t\tlen++;\n\t\t}\n\t\tdata++;\n\t\tc = *data;\n\t\tif ( c == '\\n' )\n\t\t\tcom_lines++;\n\t} while (c>32);\n\n\tif (len == MAX_TOKEN_CHARS)\n\t{\n//\t\tCom_Printf (\"Token exceeded %i chars, discarded.\\n\", MAX_TOKEN_CHARS);\n\t\tlen = 0;\n\t}\n\tcom_token[len] = 0;\n\n\t*data_p = ( char * ) data;\n\treturn com_token;\n}\n\n\n#if 0\n// no longer used\n/*\n===============\nCOM_ParseInfos\n===============\n*/\nint COM_ParseInfos( char *buf, int max, char infos[][MAX_INFO_STRING] ) {\n\tchar\t*token;\n\tint\t\tcount;\n\tchar\tkey[MAX_TOKEN_CHARS];\n\n\tcount = 0;\n\n\twhile ( 1 ) {\n\t\ttoken = COM_Parse( &buf );\n\t\tif ( !token[0] ) {\n\t\t\tbreak;\n\t\t}\n\t\tif ( strcmp( token, \"{\" ) ) {\n\t\t\tCom_Printf( \"Missing { in info file\\n\" );\n\t\t\tbreak;\n\t\t}\n\n\t\tif ( count == max ) {\n\t\t\tCom_Printf( \"Max infos exceeded\\n\" );\n\t\t\tbreak;\n\t\t}\n\n\t\tinfos[count][0] = 0;\n\t\twhile ( 1 ) {\n\t\t\ttoken = COM_ParseExt( &buf, qtrue );\n\t\t\tif ( !token[0] ) {\n\t\t\t\tCom_Printf( \"Unexpected end of info file\\n\" );\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( !strcmp( token, \"}\" ) ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tQ_strncpyz( key, token, sizeof( key ) );\n\n\t\t\ttoken = COM_ParseExt( &buf, qfalse );\n\t\t\tif ( !token[0] ) {\n\t\t\t\tstrcpy( token, \"<NULL>\" );\n\t\t\t}\n\t\t\tInfo_SetValueForKey( infos[count], key, token );\n\t\t}\n\t\tcount++;\n\t}\n\n\treturn count;\n}\n#endif\n\n\n/*\n==================\nCOM_MatchToken\n==================\n*/\nvoid COM_MatchToken( char **buf_p, char *match ) {\n\tchar\t*token;\n\n\ttoken = COM_Parse( buf_p );\n\tif ( strcmp( token, match ) ) {\n\t\tCom_Error( ERR_DROP, \"MatchToken: %s != %s\", token, match );\n\t}\n}\n\n\n/*\n=================\nSkipBracedSection\n\nThe next token should be an open brace.\nSkips until a matching close brace is found.\nInternal brace depths are properly skipped.\n=================\n*/\nvoid SkipBracedSection (char **program) {\n\tchar\t\t\t*token;\n\tint\t\t\t\tdepth;\n\n\tdepth = 0;\n\tdo {\n\t\ttoken = COM_ParseExt( program, qtrue );\n\t\tif( token[1] == 0 ) {\n\t\t\tif( token[0] == '{' ) {\n\t\t\t\tdepth++;\n\t\t\t}\n\t\t\telse if( token[0] == '}' ) {\n\t\t\t\tdepth--;\n\t\t\t}\n\t\t}\n\t} while( depth && *program );\n}\n\n/*\n=================\nSkipRestOfLine\n=================\n*/\nvoid SkipRestOfLine ( char **data ) {\n\tchar\t*p;\n\tint\t\tc;\n\n\tp = *data;\n\twhile ( (c = *p++) != 0 ) {\n\t\tif ( c == '\\n' ) {\n\t\t\tcom_lines++;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t*data = p;\n}\n\n\nvoid Parse1DMatrix (char **buf_p, int x, float *m) {\n\tchar\t*token;\n\tint\t\ti;\n\n\tCOM_MatchToken( buf_p, \"(\" );\n\n\tfor (i = 0 ; i < x ; i++) {\n\t\ttoken = COM_Parse(buf_p);\n\t\tm[i] = atof(token);\n\t}\n\n\tCOM_MatchToken( buf_p, \")\" );\n}\n\nvoid Parse2DMatrix (char **buf_p, int y, int x, float *m) {\n\tint\t\ti;\n\n\tCOM_MatchToken( buf_p, \"(\" );\n\n\tfor (i = 0 ; i < y ; i++) {\n\t\tParse1DMatrix (buf_p, x, m + i * x);\n\t}\n\n\tCOM_MatchToken( buf_p, \")\" );\n}\n\nvoid Parse3DMatrix (char **buf_p, int z, int y, int x, float *m) {\n\tint\t\ti;\n\n\tCOM_MatchToken( buf_p, \"(\" );\n\n\tfor (i = 0 ; i < z ; i++) {\n\t\tParse2DMatrix (buf_p, y, x, m + i * x*y);\n\t}\n\n\tCOM_MatchToken( buf_p, \")\" );\n}\n\n\n/*\n============================================================================\n\n\t\t\t\t\tLIBRARY REPLACEMENT FUNCTIONS\n\n============================================================================\n*/\n\nint Q_isprint( int c )\n{\n\tif ( c >= 0x20 && c <= 0x7E )\n\t\treturn ( 1 );\n\treturn ( 0 );\n}\n\nint Q_islower( int c )\n{\n\tif (c >= 'a' && c <= 'z')\n\t\treturn ( 1 );\n\treturn ( 0 );\n}\n\nint Q_isupper( int c )\n{\n\tif (c >= 'A' && c <= 'Z')\n\t\treturn ( 1 );\n\treturn ( 0 );\n}\n\nint Q_isalpha( int c )\n{\n\tif ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))\n\t\treturn ( 1 );\n\treturn ( 0 );\n}\n\nchar* Q_strrchr( const char* string, int c )\n{\n\tchar cc = c;\n\tchar *s;\n\tchar *sp=(char *)0;\n\n\ts = (char*)string;\n\n\twhile (*s)\n\t{\n\t\tif (*s == cc)\n\t\t\tsp = s;\n\t\ts++;\n\t}\n\tif (cc == 0)\n\t\tsp = s;\n\n\treturn sp;\n}\n\n/*\n=============\nQ_strncpyz\n \nSafe strncpy that ensures a trailing zero\n=============\n*/\nvoid Q_strncpyz( char *dest, const char *src, int destsize ) {\n  // bk001129 - also NULL dest\n  if ( !dest ) {\n    Com_Error( ERR_FATAL, \"Q_strncpyz: NULL dest\" );\n  }\n\tif ( !src ) {\n\t\tCom_Error( ERR_FATAL, \"Q_strncpyz: NULL src\" );\n\t}\n\tif ( destsize < 1 ) {\n\t\tCom_Error(ERR_FATAL,\"Q_strncpyz: destsize < 1\" ); \n\t}\n\n\tstrncpy( dest, src, destsize-1 );\n  dest[destsize-1] = 0;\n}\n                 \nint Q_stricmpn (const char *s1, const char *s2, int n) {\n\tint\t\tc1, c2;\n\n\t// bk001129 - moved in 1.17 fix not in id codebase\n        if ( s1 == NULL ) {\n           if ( s2 == NULL )\n             return 0;\n           else\n             return -1;\n        }\n        else if ( s2==NULL )\n          return 1;\n\n\n\t\n\tdo {\n\t\tc1 = *s1++;\n\t\tc2 = *s2++;\n\n\t\tif (!n--) {\n\t\t\treturn 0;\t\t// strings are equal until end point\n\t\t}\n\t\t\n\t\tif (c1 != c2) {\n\t\t\tif (c1 >= 'a' && c1 <= 'z') {\n\t\t\t\tc1 -= ('a' - 'A');\n\t\t\t}\n\t\t\tif (c2 >= 'a' && c2 <= 'z') {\n\t\t\t\tc2 -= ('a' - 'A');\n\t\t\t}\n\t\t\tif (c1 != c2) {\n\t\t\t\treturn c1 < c2 ? -1 : 1;\n\t\t\t}\n\t\t}\n\t} while (c1);\n\t\n\treturn 0;\t\t// strings are equal\n}\n\nint Q_strncmp (const char *s1, const char *s2, int n) {\n\tint\t\tc1, c2;\n\t\n\tdo {\n\t\tc1 = *s1++;\n\t\tc2 = *s2++;\n\n\t\tif (!n--) {\n\t\t\treturn 0;\t\t// strings are equal until end point\n\t\t}\n\t\t\n\t\tif (c1 != c2) {\n\t\t\treturn c1 < c2 ? -1 : 1;\n\t\t}\n\t} while (c1);\n\t\n\treturn 0;\t\t// strings are equal\n}\n\nint Q_stricmp (const char *s1, const char *s2) {\n\treturn (s1 && s2) ? Q_stricmpn (s1, s2, 99999) : -1;\n}\n\n\nchar *Q_strlwr( char *s1 ) {\n    char\t*s;\n\n    s = s1;\n\twhile ( *s ) {\n\t\t*s = tolower(*s);\n\t\ts++;\n\t}\n    return s1;\n}\n\nchar *Q_strupr( char *s1 ) {\n    char\t*s;\n\n    s = s1;\n\twhile ( *s ) {\n\t\t*s = toupper(*s);\n\t\ts++;\n\t}\n    return s1;\n}\n\n\n// never goes past bounds or leaves without a terminating 0\nvoid Q_strcat( char *dest, int size, const char *src ) {\n\tint\t\tl1;\n\n\tl1 = (int)strlen( dest );\n\tif ( l1 >= size ) {\n\t\tCom_Error( ERR_FATAL, \"Q_strcat: already overflowed\" );\n\t}\n\tQ_strncpyz( dest + l1, src, size - l1 );\n}\n\n\nint Q_PrintStrlen( const char *string ) {\n\tint\t\t\tlen;\n\tconst char\t*p;\n\n\tif( !string ) {\n\t\treturn 0;\n\t}\n\n\tlen = 0;\n\tp = string;\n\twhile( *p ) {\n\t\tif( Q_IsColorString( p ) ) {\n\t\t\tp += 2;\n\t\t\tcontinue;\n\t\t}\n\t\tp++;\n\t\tlen++;\n\t}\n\n\treturn len;\n}\n\n\nchar *Q_CleanStr( char *string ) {\n\tchar*\td;\n\tchar*\ts;\n\tint\t\tc;\n\n\ts = string;\n\td = string;\n\twhile ((c = *s) != 0 ) {\n\t\tif ( Q_IsColorString( s ) ) {\n\t\t\ts++;\n\t\t}\t\t\n\t\telse if ( c >= 0x20 && c <= 0x7E ) {\n\t\t\t*d++ = c;\n\t\t}\n\t\ts++;\n\t}\n\t*d = '\\0';\n\n\treturn string;\n}\n\n\nvoid QDECL Com_sprintf( char *dest, int size, const char *fmt, ...) {\n\tint\t\tlen;\n\tva_list\t\targptr;\n\tchar\tbigbuffer[32000];\t// big, but small enough to fit in PPC stack\n\n\tva_start (argptr,fmt);\n\tlen = vsprintf (bigbuffer,fmt,argptr);\n\tva_end (argptr);\n\tif ( len >= sizeof( bigbuffer ) ) {\n\t\tCom_Error( ERR_FATAL, \"Com_sprintf: overflowed bigbuffer\" );\n\t}\n\tif (len >= size) {\n\t\tCom_Printf (\"Com_sprintf: overflow of %i in %i\\n\", len, size);\n#ifdef\t_DEBUG\n\t\t__debugbreak();\n#endif\n\t}\n\tQ_strncpyz (dest, bigbuffer, size );\n}\n\n\n/*\n============\nva\n\ndoes a varargs printf into a temp buffer, so I don't need to have\nvarargs versions of all text functions.\nFIXME: make this buffer size safe someday\n============\n*/\nchar\t* QDECL va( char *format, ... ) {\n\tva_list\t\targptr;\n\tstatic char\t\tstring[2][32000];\t// in case va is called by nested functions\n\tstatic int\t\tindex = 0;\n\tchar\t*buf;\n\n\tbuf = string[index & 1];\n\tindex++;\n\n\tva_start (argptr, format);\n\tvsprintf (buf, format,argptr);\n\tva_end (argptr);\n\n\treturn buf;\n}\n\n\n/*\n=====================================================================\n\n  INFO STRINGS\n\n=====================================================================\n*/\n\n/*\n===============\nInfo_ValueForKey\n\nSearches the string for the given\nkey and returns the associated value, or an empty string.\nFIXME: overflow check?\n===============\n*/\nchar *Info_ValueForKey( const char *s, const char *key ) {\n\tchar\tpkey[BIG_INFO_KEY];\n\tstatic\tchar value[2][BIG_INFO_VALUE];\t// use two buffers so compares\n\t\t\t\t\t\t\t\t\t\t\t// work without stomping on each other\n\tstatic\tint\tvalueindex = 0;\n\tchar\t*o;\n\t\n\tif ( !s || !key ) {\n\t\treturn \"\";\n\t}\n\n\tif ( (int)strlen( s ) >= BIG_INFO_STRING ) {\n\t\tCom_Error( ERR_DROP, \"Info_ValueForKey: oversize infostring\" );\n\t}\n\n\tvalueindex ^= 1;\n\tif (*s == '\\\\')\n\t\ts++;\n\twhile (1)\n\t{\n\t\to = pkey;\n\t\twhile (*s != '\\\\')\n\t\t{\n\t\t\tif (!*s)\n\t\t\t\treturn \"\";\n\t\t\t*o++ = *s++;\n\t\t}\n\t\t*o = 0;\n\t\ts++;\n\n\t\to = value[valueindex];\n\n\t\twhile (*s != '\\\\' && *s)\n\t\t{\n\t\t\t*o++ = *s++;\n\t\t}\n\t\t*o = 0;\n\n\t\tif (!Q_stricmp (key, pkey) )\n\t\t\treturn value[valueindex];\n\n\t\tif (!*s)\n\t\t\tbreak;\n\t\ts++;\n\t}\n\n\treturn \"\";\n}\n\n\n/*\n===================\nInfo_NextPair\n\nUsed to itterate through all the key/value pairs in an info string\n===================\n*/\nvoid Info_NextPair( const char **head, char *key, char *value ) {\n\tchar\t*o;\n\tconst char\t*s;\n\n\ts = *head;\n\n\tif ( *s == '\\\\' ) {\n\t\ts++;\n\t}\n\tkey[0] = 0;\n\tvalue[0] = 0;\n\n\to = key;\n\twhile ( *s != '\\\\' ) {\n\t\tif ( !*s ) {\n\t\t\t*o = 0;\n\t\t\t*head = s;\n\t\t\treturn;\n\t\t}\n\t\t*o++ = *s++;\n\t}\n\t*o = 0;\n\ts++;\n\n\to = value;\n\twhile ( *s != '\\\\' && *s ) {\n\t\t*o++ = *s++;\n\t}\n\t*o = 0;\n\n\t*head = s;\n}\n\n\n/*\n===================\nInfo_RemoveKey\n===================\n*/\nvoid Info_RemoveKey( char *s, const char *key ) {\n\tchar\t*start;\n\tchar\tpkey[MAX_INFO_KEY];\n\tchar\tvalue[MAX_INFO_VALUE];\n\tchar\t*o;\n\n\tif ( (int)strlen( s ) >= MAX_INFO_STRING ) {\n\t\tCom_Error( ERR_DROP, \"Info_RemoveKey: oversize infostring\" );\n\t}\n\n\tif (strchr (key, '\\\\')) {\n\t\treturn;\n\t}\n\n\twhile (1)\n\t{\n\t\tstart = s;\n\t\tif (*s == '\\\\')\n\t\t\ts++;\n\t\to = pkey;\n\t\twhile (*s != '\\\\')\n\t\t{\n\t\t\tif (!*s)\n\t\t\t\treturn;\n\t\t\t*o++ = *s++;\n\t\t}\n\t\t*o = 0;\n\t\ts++;\n\n\t\to = value;\n\t\twhile (*s != '\\\\' && *s)\n\t\t{\n\t\t\tif (!*s)\n\t\t\t\treturn;\n\t\t\t*o++ = *s++;\n\t\t}\n\t\t*o = 0;\n\n\t\tif (!strcmp (key, pkey) )\n\t\t{\n\t\t\tstrcpy (start, s);\t// remove this part\n\t\t\treturn;\n\t\t}\n\n\t\tif (!*s)\n\t\t\treturn;\n\t}\n\n}\n\n/*\n===================\nInfo_RemoveKey_Big\n===================\n*/\nvoid Info_RemoveKey_Big( char *s, const char *key ) {\n\tchar\t*start;\n\tchar\tpkey[BIG_INFO_KEY];\n\tchar\tvalue[BIG_INFO_VALUE];\n\tchar\t*o;\n\n\tif ( (int)strlen( s ) >= BIG_INFO_STRING ) {\n\t\tCom_Error( ERR_DROP, \"Info_RemoveKey_Big: oversize infostring\" );\n\t}\n\n\tif (strchr (key, '\\\\')) {\n\t\treturn;\n\t}\n\n\twhile (1)\n\t{\n\t\tstart = s;\n\t\tif (*s == '\\\\')\n\t\t\ts++;\n\t\to = pkey;\n\t\twhile (*s != '\\\\')\n\t\t{\n\t\t\tif (!*s)\n\t\t\t\treturn;\n\t\t\t*o++ = *s++;\n\t\t}\n\t\t*o = 0;\n\t\ts++;\n\n\t\to = value;\n\t\twhile (*s != '\\\\' && *s)\n\t\t{\n\t\t\tif (!*s)\n\t\t\t\treturn;\n\t\t\t*o++ = *s++;\n\t\t}\n\t\t*o = 0;\n\n\t\tif (!strcmp (key, pkey) )\n\t\t{\n\t\t\tstrcpy (start, s);\t// remove this part\n\t\t\treturn;\n\t\t}\n\n\t\tif (!*s)\n\t\t\treturn;\n\t}\n\n}\n\n\n\n\n/*\n==================\nInfo_Validate\n\nSome characters are illegal in info strings because they\ncan mess up the server's parsing\n==================\n*/\nqboolean Info_Validate( const char *s ) {\n\tif ( strchr( s, '\\\"' ) ) {\n\t\treturn qfalse;\n\t}\n\tif ( strchr( s, ';' ) ) {\n\t\treturn qfalse;\n\t}\n\treturn qtrue;\n}\n\n/*\n==================\nInfo_SetValueForKey\n\nChanges or adds a key/value pair\n==================\n*/\nvoid Info_SetValueForKey( char *s, const char *key, const char *value ) {\n\tchar\tnewi[MAX_INFO_STRING];\n\n\tif ( (int)strlen( s ) >= MAX_INFO_STRING ) {\n\t\tCom_Error( ERR_DROP, \"Info_SetValueForKey: oversize infostring\" );\n\t}\n\n\tif (strchr (key, '\\\\') || strchr (value, '\\\\'))\n\t{\n\t\tCom_Printf (\"Can't use keys or values with a \\\\\\n\");\n\t\treturn;\n\t}\n\n\tif (strchr (key, ';') || strchr (value, ';'))\n\t{\n\t\tCom_Printf (\"Can't use keys or values with a semicolon\\n\");\n\t\treturn;\n\t}\n\n\tif (strchr (key, '\\\"') || strchr (value, '\\\"'))\n\t{\n\t\tCom_Printf (\"Can't use keys or values with a \\\"\\n\");\n\t\treturn;\n\t}\n\n\tInfo_RemoveKey (s, key);\n\tif (!value || !strlen(value))\n\t\treturn;\n\n\tCom_sprintf (newi, sizeof(newi), \"\\\\%s\\\\%s\", key, value);\n\n\tif (strlen(newi) + (int)strlen(s) > MAX_INFO_STRING)\n\t{\n\t\tCom_Printf (\"Info string length exceeded\\n\");\n\t\treturn;\n\t}\n\n\tstrcat (newi, s);\n\tstrcpy (s, newi);\n}\n\n/*\n==================\nInfo_SetValueForKey_Big\n\nChanges or adds a key/value pair\n==================\n*/\nvoid Info_SetValueForKey_Big( char *s, const char *key, const char *value ) {\n\tchar\tnewi[BIG_INFO_STRING];\n\n\tif ( (int)strlen( s ) >= BIG_INFO_STRING ) {\n\t\tCom_Error( ERR_DROP, \"Info_SetValueForKey: oversize infostring\" );\n\t}\n\n\tif (strchr (key, '\\\\') || strchr (value, '\\\\'))\n\t{\n\t\tCom_Printf (\"Can't use keys or values with a \\\\\\n\");\n\t\treturn;\n\t}\n\n\tif (strchr (key, ';') || strchr (value, ';'))\n\t{\n\t\tCom_Printf (\"Can't use keys or values with a semicolon\\n\");\n\t\treturn;\n\t}\n\n\tif (strchr (key, '\\\"') || strchr (value, '\\\"'))\n\t{\n\t\tCom_Printf (\"Can't use keys or values with a \\\"\\n\");\n\t\treturn;\n\t}\n\n\tInfo_RemoveKey_Big (s, key);\n\tif (!value || !strlen(value))\n\t\treturn;\n\n\tCom_sprintf (newi, sizeof(newi), \"\\\\%s\\\\%s\", key, value);\n\n\tif (strlen(newi) + (int)strlen(s) > BIG_INFO_STRING)\n\t{\n\t\tCom_Printf (\"BIG Info string length exceeded\\n\");\n\t\treturn;\n\t}\n\n\tstrcat (s, newi);\n}\n\n\n\n\n//====================================================================\n\n\n"
  },
  {
    "path": "src/game/q_shared.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n#ifndef __Q_SHARED_H\n#define __Q_SHARED_H\n\n// q_shared.h -- included first by ALL program modules.\n// A user mod should never modify this file\n\n#define\tQ3_VERSION\t\t\"Q3 1.32b Kenny edition\"\n// 1.32 released 7-10-2002\n\n#define MAX_TEAMNAME 32\n\n#ifdef _WIN32\n\n#pragma warning(disable : 4018)     // signed/unsigned mismatch\n#pragma warning(disable : 4032)\n#pragma warning(disable : 4051)\n#pragma warning(disable : 4057)\t\t// slightly different base types\n#pragma warning(disable : 4100)\t\t// unreferenced formal parameter\n#pragma warning(disable : 4115)\n#pragma warning(disable : 4125)\t\t// decimal digit terminates octal escape sequence\n#pragma warning(disable : 4127)\t\t// conditional expression is constant\n#pragma warning(disable : 4136)\n#pragma warning(disable : 4152)\t\t// nonstandard extension, function/data pointer conversion in expression\n//#pragma warning(disable : 4201)\n//#pragma warning(disable : 4214)\n#pragma warning(disable : 4244)\n#pragma warning(disable : 4142)\t\t// benign redefinition\n//#pragma warning(disable : 4305)\t\t// truncation from const double to float\n//#pragma warning(disable : 4310)\t\t// cast truncates constant value\n//#pragma warning(disable:  4505) \t// unreferenced local function has been removed\n#pragma warning(disable : 4514)\n#pragma warning(disable : 4702)\t\t// unreachable code\n#pragma warning(disable : 4711)\t\t// selected for automatic inline expansion\n#pragma warning(disable : 4220)\t\t// varargs matches remaining parameters\n\n// <artem>\n#pragma warning(disable : 4996) // the function or variable may be unsafe\n// </artem>\n\n#endif\n\n/**********************************************************************\n  VM Considerations\n\n  The VM can not use the standard system headers because we aren't really\n  using the compiler they were meant for.  We use bg_lib.h which contains\n  prototypes for the functions we define for our own use in bg_lib.c.\n\n  When writing mods, please add needed headers HERE, do not start including\n  stuff like <stdio.h> in the various .c files that make up each of the VMs\n  since you will be including system headers files can will have issues.\n\n  Remember, if you use a C library function that is not defined in bg_lib.c,\n  you will have to add your own version for support in the VM.\n\n **********************************************************************/\n\n#ifdef Q3_VM\n\n#include \"bg_lib.h\"\n\ntypedef int intptr_t;\n\n#else\n\n#include <assert.h>\n#include <math.h>\n#include <stdio.h>\n#include <stdarg.h>\n#include <string.h>\n#include <stdlib.h>\n#include <time.h>\n#include <ctype.h>\n#include <limits.h>\n\n#endif\n\n#ifdef _WIN32\n\n//#pragma intrinsic( memset, memcpy )\n\n#endif\n\n\n// this is the define for determining if we have an asm version of a C function\n#if (defined _M_IX86 || defined __i386__) && !defined __sun__  && !defined __LCC__\n#define id386\t1\n#else\n#define id386\t0\n#endif\n\n#if (defined(powerc) || defined(powerpc) || defined(ppc) || defined(__ppc) || defined(__ppc__)) && !defined(C_ONLY)\n#define idppc\t1\n#if defined(__VEC__)\n#define idppc_altivec 1\n#else\n#define idppc_altivec 0\n#endif\n#else\n#define idppc\t0\n#define idppc_altivec 0\n#endif\n\n// for windows fastcall option\n\n#define\tQDECL\n\nshort   ShortSwap (short l);\nint\t\tLongSwap (int l);\nfloat\tFloatSwap (const float *f);\n\n//======================= WIN32 DEFINES =================================\n\n#ifdef WIN32\n\n#define\tMAC_STATIC\n\n#undef QDECL\n#define\tQDECL\t__cdecl\n\n#define CPUSTRING \"generic\"\n\n#define ID_INLINE __inline \n\nstatic ID_INLINE short BigShort( short l) { return ShortSwap(l); }\n#define LittleShort\nstatic ID_INLINE int BigLong(int l) { LongSwap(l); }\n#define LittleLong\nstatic ID_INLINE float BigFloat(const float *l) { FloatSwap(l); }\n#define LittleFloat\n\n#define\tPATH_SEP '\\\\'\n\n#endif\n\n//======================= MAC OS X DEFINES =====================\n\n#if defined(MACOS_X)\n\n#define MAC_STATIC\n#define __cdecl\n#define __declspec(x)\n#define stricmp strcasecmp\n#define ID_INLINE inline \n\n#ifdef __ppc__\n#define CPUSTRING\t\"MacOSX-ppc\"\n#elif defined __i386__\n#define CPUSTRING\t\"MacOSX-i386\"\n#else\n#define CPUSTRING\t\"MacOSX-other\"\n#endif\n\n#define\tPATH_SEP\t'/'\n\n#define __rlwimi(out, in, shift, maskBegin, maskEnd) asm(\"rlwimi %0,%1,%2,%3,%4\" : \"=r\" (out) : \"r\" (in), \"i\" (shift), \"i\" (maskBegin), \"i\" (maskEnd))\n#define __dcbt(addr, offset) asm(\"dcbt %0,%1\" : : \"b\" (addr), \"r\" (offset))\n\nstatic inline unsigned int __lwbrx(register void *addr, register int offset) {\n    register unsigned int word;\n    \n    asm(\"lwbrx %0,%2,%1\" : \"=r\" (word) : \"r\" (addr), \"b\" (offset));\n    return word;\n}\n\nstatic inline unsigned short __lhbrx(register void *addr, register int offset) {\n    register unsigned short halfword;\n    \n    asm(\"lhbrx %0,%2,%1\" : \"=r\" (halfword) : \"r\" (addr), \"b\" (offset));\n    return halfword;\n}\n\nstatic inline float __fctiw(register float f) {\n    register float fi;\n    \n    asm(\"fctiw %0,%1\" : \"=f\" (fi) : \"f\" (f));\n\n    return fi;\n}\n\n#define BigShort\nstatic inline short LittleShort(short l) { return ShortSwap(l); }\n#define BigLong\nstatic inline int LittleLong (int l) { return LongSwap(l); }\n#define BigFloat\nstatic inline float LittleFloat (const float l) { return FloatSwap(&l); }\n\n#endif\n\n//======================= MAC DEFINES =================================\n\n#ifdef __MACOS__\n\n#include <MacTypes.h>\n#define\tMAC_STATIC\n#define ID_INLINE inline \n\n#define\tCPUSTRING\t\"MacOS-PPC\"\n\n#define\tPATH_SEP ':'\n\nvoid Sys_PumpEvents( void );\n\n#define BigShort\nstatic inline short LittleShort(short l) { return ShortSwap(l); }\n#define BigLong\nstatic inline int LittleLong (int l) { return LongSwap(l); }\n#define BigFloat\nstatic inline float LittleFloat (const float l) { return FloatSwap(&l); }\n\n#endif\n\n//======================= LINUX DEFINES =================================\n\n// the mac compiler can't handle >32k of locals, so we\n// just waste space and make big arrays static...\n#ifdef __linux__\n\n// bk001205 - from Makefile\n#define stricmp strcasecmp\n\n#define\tMAC_STATIC // bk: FIXME\n#define ID_INLINE inline \n\n#ifdef __i386__\n#define\tCPUSTRING\t\"linux-i386\"\n#elif defined __axp__\n#define\tCPUSTRING\t\"linux-alpha\"\n#else\n#define\tCPUSTRING\t\"linux-other\"\n#endif\n\n#define\tPATH_SEP '/'\n\n// bk001205 - try\n#ifdef Q3_STATIC\n#define\tGAME_HARD_LINKED\n#define\tCGAME_HARD_LINKED\n#define\tUI_HARD_LINKED\n#define\tBOTLIB_HARD_LINKED\n#endif\n\n#if !idppc\ninline static short BigShort( short l) { return ShortSwap(l); }\n#define LittleShort\ninline static int BigLong(int l) { return LongSwap(l); }\n#define LittleLong\ninline static float BigFloat(const float *l) { return FloatSwap(l); }\n#define LittleFloat\n#else\n#define BigShort\ninline static short LittleShort(short l) { return ShortSwap(l); }\n#define BigLong\ninline static int LittleLong (int l) { return LongSwap(l); }\n#define BigFloat\ninline static float LittleFloat (const float *l) { return FloatSwap(l); }\n#endif\n\n#endif\n\n//======================= FreeBSD DEFINES =====================\n#ifdef __FreeBSD__ // rb010123\n\n#define stricmp strcasecmp\n\n#define MAC_STATIC\n#define ID_INLINE inline \n\n#ifdef __i386__\n#define CPUSTRING       \"freebsd-i386\"\n#elif defined __axp__\n#define CPUSTRING       \"freebsd-alpha\"\n#else\n#define CPUSTRING       \"freebsd-other\"\n#endif\n\n#define\tPATH_SEP '/'\n\n// bk010116 - omitted Q3STATIC (see Linux above), broken target\n\n#if !idppc\nstatic short BigShort( short l) { return ShortSwap(l); }\n#define LittleShort\nstatic int BigLong(int l) { LongSwap(l); }\n#define LittleLong\nstatic float BigFloat(const float *l) { FloatSwap(l); }\n#define LittleFloat\n#else\n#define BigShort\nstatic short LittleShort(short l) { return ShortSwap(l); }\n#define BigLong\nstatic int LittleLong (int l) { return LongSwap(l); }\n#define BigFloat\nstatic float LittleFloat (const float *l) { return FloatSwap(l); }\n#endif\n\n#endif\n\n//=============================================================\n\ntypedef unsigned char \t\tbyte;\n\ntypedef enum {qfalse, qtrue}\tqboolean;\n\ntypedef int\t\tqhandle_t;\ntypedef int\t\tsfxHandle_t;\ntypedef int\t\tfileHandle_t;\ntypedef int\t\tclipHandle_t;\n\n\n#ifndef NULL\n#define NULL ((void *)0)\n#endif\n\n#define\tMAX_QINT\t\t\t0x7fffffff\n#define\tMIN_QINT\t\t\t(-MAX_QINT-1)\n\n#define ARRAY_LEN(x)        (sizeof(x) / sizeof(*(x)))\n\n// angle indexes\n#define\tPITCH\t\t\t\t0\t\t// up / down\n#define\tYAW\t\t\t\t\t1\t\t// left / right\n#define\tROLL\t\t\t\t2\t\t// fall over\n\n// the game guarantees that no string from the network will ever\n// exceed MAX_STRING_CHARS\n#define\tMAX_STRING_CHARS\t1024\t// max length of a string passed to Cmd_TokenizeString\n#define\tMAX_STRING_TOKENS\t1024\t// max tokens resulting from Cmd_TokenizeString\n#define\tMAX_TOKEN_CHARS\t\t1024\t// max length of an individual token\n\n#define\tMAX_INFO_STRING\t\t1024\n#define\tMAX_INFO_KEY\t\t  1024\n#define\tMAX_INFO_VALUE\t\t1024\n\n#define\tBIG_INFO_STRING\t\t8192  // used for system info key only\n#define\tBIG_INFO_KEY\t\t  8192\n#define\tBIG_INFO_VALUE\t\t8192\n\n\n#define\tMAX_QPATH\t\t\t64\t\t// max length of a quake game pathname\n#ifdef PATH_MAX\n#define MAX_OSPATH\t\t\tPATH_MAX\n#else\n#define\tMAX_OSPATH\t\t\t256\t\t// max length of a filesystem pathname\n#endif\n\n#define\tMAX_NAME_LENGTH\t\t32\t\t// max length of a client name\n\n#define\tMAX_SAY_TEXT\t150\n\n// paramters for command buffer stuffing\ntypedef enum {\n\tEXEC_NOW,\t\t\t// don't return until completed, a VM should NEVER use this,\n\t\t\t\t\t\t// because some commands might cause the VM to be unloaded...\n\tEXEC_INSERT,\t\t// insert at current position, but don't run yet\n\tEXEC_APPEND\t\t\t// add to end of the command buffer (normal case)\n} cbufExec_t;\n\n\n//\n// these aren't needed by any of the VMs.  put in another header?\n//\n#define\tMAX_MAP_AREA_BYTES\t\t32\t\t// bit vector of area visibility\n\n\n// print levels from renderer (FIXME: set up for game / cgame?)\ntypedef enum {\n\tPRINT_ALL,\n\tPRINT_DEVELOPER,\t\t// only print when \"developer 1\"\n\tPRINT_WARNING,\n\tPRINT_ERROR\n} printParm_t;\n\n\n#ifdef ERR_FATAL\n#undef ERR_FATAL\t\t\t// this is be defined in malloc.h\n#endif\n\n// parameters to the main Error routine\ntypedef enum {\n\tERR_FATAL,\t\t\t\t\t// exit the entire game with a popup window\n\tERR_DROP,\t\t\t\t\t// print to console and disconnect from game\n\tERR_SERVERDISCONNECT,\t\t// don't kill server\n\tERR_DISCONNECT,\t\t\t\t// client disconnected from the server\n\tERR_NEED_CD\t\t\t\t\t// pop up the need-cd dialog\n} errorParm_t;\n\n\n// font rendering values used by ui and cgame\n\n#define PROP_GAP_WIDTH\t\t\t3\n#define PROP_SPACE_WIDTH\t\t8\n#define PROP_HEIGHT\t\t\t\t27\n#define PROP_SMALL_SIZE_SCALE\t0.75\n\n#define BLINK_DIVISOR\t\t\t200\n#define PULSE_DIVISOR\t\t\t75\n\n#define UI_LEFT\t\t\t0x00000000\t// default\n#define UI_CENTER\t\t0x00000001\n#define UI_RIGHT\t\t0x00000002\n#define UI_FORMATMASK\t0x00000007\n#define UI_SMALLFONT\t0x00000010\n#define UI_BIGFONT\t\t0x00000020\t// default\n#define UI_GIANTFONT\t0x00000040\n#define UI_DROPSHADOW\t0x00000800\n#define UI_BLINK\t\t0x00001000\n#define UI_INVERSE\t\t0x00002000\n#define UI_PULSE\t\t0x00004000\n\n#if defined(_DEBUG) && !defined(BSPC)\n\t#define HUNK_DEBUG\n#endif\n\ntypedef enum {\n\th_high,\n\th_low,\n\th_dontcare\n} ha_pref;\n\n#ifdef HUNK_DEBUG\n#define Hunk_Alloc( size, preference )\t\t\t\tHunk_AllocDebug(size, preference, #size, __FILE__, __LINE__)\nvoid *Hunk_AllocDebug( int size, ha_pref preference, char *label, char *file, int line );\n#else\nvoid *Hunk_Alloc( int size, ha_pref preference );\n#endif\n\n#ifdef __linux__\n// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=371\n// custom Snd_Memset implementation for glibc memset bug workaround\nvoid Snd_Memset (void* dest, const int val, const size_t count);\n#else\n#define Snd_Memset Com_Memset\n#endif\n\n#if !( defined __VECTORC )\nvoid Com_Memset (void* dest, const int val, const size_t count);\nvoid Com_Memcpy (void* dest, const void* src, const size_t count);\n#else\n#define Com_Memset memset\n#define Com_Memcpy memcpy\n#endif\n\n#define CIN_system\t1\n#define CIN_loop\t2\n#define\tCIN_hold\t4\n#define CIN_silent\t8\n#define CIN_shader\t16\n\n/*\n==============================================================\n\nMATHLIB\n\n==============================================================\n*/\n\n\ntypedef float vec_t;\ntypedef vec_t vec2_t[2];\ntypedef vec_t vec3_t[3];\ntypedef vec_t vec4_t[4];\ntypedef vec_t vec5_t[5];\n\ntypedef\tint\tfixed4_t;\ntypedef\tint\tfixed8_t;\ntypedef\tint\tfixed16_t;\n\n#ifndef M_PI\n#define M_PI\t\t3.14159265358979323846f\t// matches value in gcc v2 math.h\n#endif\n\n#define NUMVERTEXNORMALS\t162\nextern\tvec3_t\tbytedirs[NUMVERTEXNORMALS];\n\n// all drawing is done to a 640*480 virtual screen size\n// and will be automatically scaled to the real resolution\n#define\tSCREEN_WIDTH\t\t640\n#define\tSCREEN_HEIGHT\t\t480\n\n#define TINYCHAR_WIDTH\t\t(SMALLCHAR_WIDTH)\n#define TINYCHAR_HEIGHT\t\t(SMALLCHAR_HEIGHT/2)\n\n#define SMALLCHAR_WIDTH\t\t8\n#define SMALLCHAR_HEIGHT\t16\n\n#define BIGCHAR_WIDTH\t\t16\n#define BIGCHAR_HEIGHT\t\t16\n\n#define\tGIANTCHAR_WIDTH\t\t32\n#define\tGIANTCHAR_HEIGHT\t48\n\nextern\tvec4_t\t\tcolorBlack;\nextern\tvec4_t\t\tcolorRed;\nextern\tvec4_t\t\tcolorGreen;\nextern\tvec4_t\t\tcolorBlue;\nextern\tvec4_t\t\tcolorYellow;\nextern\tvec4_t\t\tcolorMagenta;\nextern\tvec4_t\t\tcolorCyan;\nextern\tvec4_t\t\tcolorWhite;\nextern\tvec4_t\t\tcolorLtGrey;\nextern\tvec4_t\t\tcolorMdGrey;\nextern\tvec4_t\t\tcolorDkGrey;\n\n#define Q_COLOR_ESCAPE\t'^'\n#define Q_IsColorString(p)\t( p && *(p) == Q_COLOR_ESCAPE && *((p)+1) && *((p)+1) != Q_COLOR_ESCAPE )\n\n#define COLOR_BLACK\t\t'0'\n#define COLOR_RED\t\t'1'\n#define COLOR_GREEN\t\t'2'\n#define COLOR_YELLOW\t'3'\n#define COLOR_BLUE\t\t'4'\n#define COLOR_CYAN\t\t'5'\n#define COLOR_MAGENTA\t'6'\n#define COLOR_WHITE\t\t'7'\n#define ColorIndex(c)\t( ( (c) - '0' ) & 7 )\n\n#define S_COLOR_BLACK\t\"^0\"\n#define S_COLOR_RED\t\t\"^1\"\n#define S_COLOR_GREEN\t\"^2\"\n#define S_COLOR_YELLOW\t\"^3\"\n#define S_COLOR_BLUE\t\"^4\"\n#define S_COLOR_CYAN\t\"^5\"\n#define S_COLOR_MAGENTA\t\"^6\"\n#define S_COLOR_WHITE\t\"^7\"\n\nextern vec4_t\tg_color_table[8];\n\n#define\tMAKERGB( v, r, g, b ) v[0]=r;v[1]=g;v[2]=b\n#define\tMAKERGBA( v, r, g, b, a ) v[0]=r;v[1]=g;v[2]=b;v[3]=a\n\n#define DEG2RAD( a ) ( ( (a) * M_PI ) / 180.0F )\n#define RAD2DEG( a ) ( ( (a) * 180.0f ) / M_PI )\n\nstruct cplane_s;\n\nextern\tvec3_t\tvec3_origin;\nextern\tvec3_t\taxisDefault[3];\n\n#define\tnanmask (255<<23)\n\n#define\tIS_NAN(x) (((*(int *)&x)&nanmask)==nanmask)\n\n#if idppc\n\nstatic inline float Q_rsqrt( float number ) {\n\t\tfloat x = 0.5f * number;\n                float y;\n#ifdef __GNUC__            \n                asm(\"frsqrte %0,%1\" : \"=f\" (y) : \"f\" (number));\n#else\n\t\ty = __frsqrte( number );\n#endif\n\t\treturn y * (1.5f - (x * y * y));\n\t}\n\n#ifdef __GNUC__            \nstatic inline float Q_fabs(float x) {\n    float abs_x;\n    \n    asm(\"fabs %0,%1\" : \"=f\" (abs_x) : \"f\" (x));\n    return abs_x;\n}\n#else\n#define Q_fabs __fabsf\n#endif\n\n#else\nfloat Q_fabs( float f );\nfloat Q_rsqrt( float f );\t\t// reciprocal square root\n#endif\n\n#define SQRTFAST( x ) ( (x) * Q_rsqrt( x ) )\n\nsigned char ClampChar( int i );\nsigned short ClampShort( int i );\n\n// this isn't a real cheap function to call!\nint DirToByte( vec3_t dir );\nvoid ByteToDir( int b, vec3_t dir );\n\n#if\t1\n\n#define DotProduct(x,y)\t\t\t((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2])\n#define VectorSubtract(a,b,c)\t((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1],(c)[2]=(a)[2]-(b)[2])\n#define VectorAdd(a,b,c)\t\t((c)[0]=(a)[0]+(b)[0],(c)[1]=(a)[1]+(b)[1],(c)[2]=(a)[2]+(b)[2])\n#define VectorCopy(a,b)\t\t\t((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2])\n#define\tVectorScale(v, s, o)\t((o)[0]=(v)[0]*(s),(o)[1]=(v)[1]*(s),(o)[2]=(v)[2]*(s))\n#define\tVectorMA(v, s, b, o)\t((o)[0]=(v)[0]+(b)[0]*(s),(o)[1]=(v)[1]+(b)[1]*(s),(o)[2]=(v)[2]+(b)[2]*(s))\n\n#else\n\n#define DotProduct(x,y)\t\t\t_DotProduct(x,y)\n#define VectorSubtract(a,b,c)\t_VectorSubtract(a,b,c)\n#define VectorAdd(a,b,c)\t\t_VectorAdd(a,b,c)\n#define VectorCopy(a,b)\t\t\t_VectorCopy(a,b)\n#define\tVectorScale(v, s, o)\t_VectorScale(v,s,o)\n#define\tVectorMA(v, s, b, o)\t_VectorMA(v,s,b,o)\n\n#endif\n\n#ifdef __LCC__\n#ifdef VectorCopy\n#undef VectorCopy\n// this is a little hack to get more efficient copies in our interpreter\ntypedef struct {\n\tfloat\tv[3];\n} vec3struct_t;\n#define VectorCopy(a,b)\t(*(vec3struct_t *)b=*(vec3struct_t *)a)\n#define ID_INLINE static\n#endif\n#endif\n\n#define VectorClear(a)\t\t\t((a)[0]=(a)[1]=(a)[2]=0)\n#define VectorNegate(a,b)\t\t((b)[0]=-(a)[0],(b)[1]=-(a)[1],(b)[2]=-(a)[2])\n#define VectorSet(v, x, y, z)\t((v)[0]=(x), (v)[1]=(y), (v)[2]=(z))\n#define Vector4Copy(a,b)\t\t((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3])\n\n#define\tSnapVector(v) {v[0]=((int)(v[0]));v[1]=((int)(v[1]));v[2]=((int)(v[2]));}\n// just in case you do't want to use the macros\nvec_t _DotProduct( const vec3_t v1, const vec3_t v2 );\nvoid _VectorSubtract( const vec3_t veca, const vec3_t vecb, vec3_t out );\nvoid _VectorAdd( const vec3_t veca, const vec3_t vecb, vec3_t out );\nvoid _VectorCopy( const vec3_t in, vec3_t out );\nvoid _VectorScale( const vec3_t in, float scale, vec3_t out );\nvoid _VectorMA( const vec3_t veca, float scale, const vec3_t vecb, vec3_t vecc );\n\nunsigned ColorBytes3 (float r, float g, float b);\nunsigned ColorBytes4 (float r, float g, float b, float a);\n\nfloat NormalizeColor( const vec3_t in, vec3_t out );\n\nfloat RadiusFromBounds( const vec3_t mins, const vec3_t maxs );\nvoid ClearBounds( vec3_t mins, vec3_t maxs );\nvoid AddPointToBounds( const vec3_t v, vec3_t mins, vec3_t maxs );\n\n#ifndef __LCC__\nstatic ID_INLINE int VectorCompare( const vec3_t v1, const vec3_t v2 ) {\n\tif (v1[0] != v2[0] || v1[1] != v2[1] || v1[2] != v2[2]) {\n\t\treturn 0;\n\t}\t\t\t\n\treturn 1;\n}\n\nstatic ID_INLINE vec_t VectorLength( const vec3_t v ) {\n\treturn (vec_t)sqrt (v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);\n}\n\nstatic ID_INLINE vec_t VectorLengthSquared( const vec3_t v ) {\n\treturn (v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);\n}\n\nstatic ID_INLINE vec_t Distance( const vec3_t p1, const vec3_t p2 ) {\n\tvec3_t\tv;\n\n\tVectorSubtract (p2, p1, v);\n\treturn VectorLength( v );\n}\n\nstatic ID_INLINE vec_t DistanceSquared( const vec3_t p1, const vec3_t p2 ) {\n\tvec3_t\tv;\n\n\tVectorSubtract (p2, p1, v);\n\treturn v[0]*v[0] + v[1]*v[1] + v[2]*v[2];\n}\n\n// fast vector normalize routine that does not check to make sure\n// that length != 0, nor does it return length, uses rsqrt approximation\nstatic ID_INLINE void VectorNormalizeFast( vec3_t v )\n{\n\tfloat ilength;\n\n\tilength = Q_rsqrt( DotProduct( v, v ) );\n\n\tv[0] *= ilength;\n\tv[1] *= ilength;\n\tv[2] *= ilength;\n}\n\nstatic ID_INLINE void VectorInverse( vec3_t v ){\n\tv[0] = -v[0];\n\tv[1] = -v[1];\n\tv[2] = -v[2];\n}\n\nstatic ID_INLINE void CrossProduct( const vec3_t v1, const vec3_t v2, vec3_t cross ) {\n\tcross[0] = v1[1]*v2[2] - v1[2]*v2[1];\n\tcross[1] = v1[2]*v2[0] - v1[0]*v2[2];\n\tcross[2] = v1[0]*v2[1] - v1[1]*v2[0];\n}\n\n#else\nint VectorCompare( const vec3_t v1, const vec3_t v2 );\n\nvec_t VectorLength( const vec3_t v );\n\nvec_t VectorLengthSquared( const vec3_t v );\n\nvec_t Distance( const vec3_t p1, const vec3_t p2 );\n\nvec_t DistanceSquared( const vec3_t p1, const vec3_t p2 );\n \nvoid VectorNormalizeFast( vec3_t v );\n\nvoid VectorInverse( vec3_t v );\n\nvoid CrossProduct( const vec3_t v1, const vec3_t v2, vec3_t cross );\n\n#endif\n\nvec_t VectorNormalize (vec3_t v);\t\t// returns vector length\nvec_t VectorNormalize2( const vec3_t v, vec3_t out );\nvoid Vector4Scale( const vec4_t in, vec_t scale, vec4_t out );\nvoid VectorRotate( vec3_t in, vec3_t matrix[3], vec3_t out );\nint Q_log2(int val);\n\nfloat Q_acos(float c);\n\nint\t\tQ_rand( int *seed );\nfloat\tQ_random( int *seed );\nfloat\tQ_crandom( int *seed );\n\n#define random()\t((rand () & 0x7fff) / ((float)0x7fff))\n#define crandom()\t(2.0 * (random() - 0.5))\n\nvoid vectoangles( const vec3_t value1, vec3_t angles);\nvoid AnglesToAxis( const vec3_t angles, vec3_t axis[3] );\n\nvoid AxisClear( vec3_t axis[3] );\nvoid AxisCopy( vec3_t in[3], vec3_t out[3] );\n\nvoid SetPlaneSignbits( struct cplane_s *out );\nint BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct cplane_s *plane);\n\nfloat\tAngleMod(float a);\nfloat\tLerpAngle (float from, float to, float frac);\nfloat\tAngleSubtract( float a1, float a2 );\nvoid\tAnglesSubtract( vec3_t v1, vec3_t v2, vec3_t v3 );\n\nfloat AngleNormalize360 ( float angle );\nfloat AngleNormalize180 ( float angle );\nfloat AngleDelta ( float angle1, float angle2 );\n\nqboolean PlaneFromPoints( vec4_t plane, const vec3_t a, const vec3_t b, const vec3_t c );\nvoid ProjectPointOnPlane( vec3_t dst, const vec3_t p, const vec3_t normal );\nvoid RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees );\nvoid RotateAroundDirection( vec3_t axis[3], float yaw );\nvoid MakeNormalVectors( const vec3_t forward, vec3_t right, vec3_t up );\n// perpendicular vector could be replaced by this\n\n//int\tPlaneTypeForNormal (vec3_t normal);\n\nvoid MatrixMultiply(float in1[3][3], float in2[3][3], float out[3][3]);\nvoid AngleVectors( const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up);\nvoid PerpendicularVector( vec3_t dst, const vec3_t src );\n\n\n//=============================================\n\nfloat Com_Clamp( float min, float max, float value );\n\nchar\t*COM_SkipPath( char *pathname );\nvoid\tCOM_StripExtension( const char *in, char *out );\nvoid\tCOM_DefaultExtension( char *path, int maxSize, const char *extension );\n\nvoid\tCOM_BeginParseSession( const char *name );\nint\t\tCOM_GetCurrentParseLine( void );\nchar\t*COM_Parse( char **data_p );\nchar\t*COM_ParseExt( char **data_p, qboolean allowLineBreak );\nint\t\tCOM_Compress( char *data_p );\nvoid\tCOM_ParseError( char *format, ... );\nvoid\tCOM_ParseWarning( char *format, ... );\n//int\t\tCOM_ParseInfos( char *buf, int max, char infos[][MAX_INFO_STRING] );\n\n#define MAX_TOKENLENGTH\t\t1024\n\n#ifndef TT_STRING\n//token types\n#define TT_STRING\t\t\t\t\t1\t\t\t// string\n#define TT_LITERAL\t\t\t\t\t2\t\t\t// literal\n#define TT_NUMBER\t\t\t\t\t3\t\t\t// number\n#define TT_NAME\t\t\t\t\t\t4\t\t\t// name\n#define TT_PUNCTUATION\t\t\t\t5\t\t\t// punctuation\n#endif\n\ntypedef struct pc_token_s\n{\n\tint type;\n\tint subtype;\n\tint intvalue;\n\tfloat floatvalue;\n\tchar string[MAX_TOKENLENGTH];\n} pc_token_t;\n\n// data is an in/out parm, returns a parsed out token\n\nvoid\tCOM_MatchToken( char**buf_p, char *match );\n\nvoid SkipBracedSection (char **program);\nvoid SkipRestOfLine ( char **data );\n\nvoid Parse1DMatrix (char **buf_p, int x, float *m);\nvoid Parse2DMatrix (char **buf_p, int y, int x, float *m);\nvoid Parse3DMatrix (char **buf_p, int z, int y, int x, float *m);\n\nvoid\tQDECL Com_sprintf (char *dest, int size, const char *fmt, ...);\n\n\n// mode parm for FS_FOpenFile\ntypedef enum {\n\tFS_READ,\n\tFS_WRITE,\n\tFS_APPEND,\n\tFS_APPEND_SYNC\n} fsMode_t;\n\ntypedef enum {\n\tFS_SEEK_CUR,\n\tFS_SEEK_END,\n\tFS_SEEK_SET\n} fsOrigin_t;\n\n//=============================================\n\nint Q_isprint( int c );\nint Q_islower( int c );\nint Q_isupper( int c );\nint Q_isalpha( int c );\n\n// portable case insensitive compare\nint\t\tQ_stricmp (const char *s1, const char *s2);\nint\t\tQ_strncmp (const char *s1, const char *s2, int n);\nint\t\tQ_stricmpn (const char *s1, const char *s2, int n);\nchar\t*Q_strlwr( char *s1 );\nchar\t*Q_strupr( char *s1 );\nchar\t*Q_strrchr( const char* string, int c );\n\n// buffer size safe library replacements\nvoid\tQ_strncpyz( char *dest, const char *src, int destsize );\nvoid\tQ_strcat( char *dest, int size, const char *src );\n\n// strlen that discounts Quake color sequences\nint Q_PrintStrlen( const char *string );\n// removes color sequences from string\nchar *Q_CleanStr( char *string );\n\n//=============================================\n\n// 64-bit integers for global rankings interface\n// implemented as a struct for qvm compatibility\ntypedef struct\n{\n\tbyte\tb0;\n\tbyte\tb1;\n\tbyte\tb2;\n\tbyte\tb3;\n\tbyte\tb4;\n\tbyte\tb5;\n\tbyte\tb6;\n\tbyte\tb7;\n} qint64;\n\n//=============================================\n/*\nshort\tBigShort(short l);\nshort\tLittleShort(short l);\nint\t\tBigLong (int l);\nint\t\tLittleLong (int l);\nqint64  BigLong64 (qint64 l);\nqint64  LittleLong64 (qint64 l);\nfloat\tBigFloat (const float *l);\nfloat\tLittleFloat (const float *l);\n\nvoid\tSwap_Init (void);\n*/\nchar\t* QDECL va(char *format, ...);\n\n//=============================================\n\n//\n// key / value info strings\n//\nchar *Info_ValueForKey( const char *s, const char *key );\nvoid Info_RemoveKey( char *s, const char *key );\nvoid Info_RemoveKey_big( char *s, const char *key );\nvoid Info_SetValueForKey( char *s, const char *key, const char *value );\nvoid Info_SetValueForKey_Big( char *s, const char *key, const char *value );\nqboolean Info_Validate( const char *s );\nvoid Info_NextPair( const char **s, char *key, char *value );\n\n// this is only here so the functions in q_shared.c and bg_*.c can link\nvoid\tQDECL Com_Error( int level, const char *error, ... );\nvoid\tQDECL Com_Printf( const char *msg, ... );\n\n\n/*\n==========================================================\n\nCVARS (console variables)\n\nMany variables can be used for cheating purposes, so when\ncheats is zero, force all unspecified variables to their\ndefault values.\n==========================================================\n*/\n\n#define\tCVAR_ARCHIVE\t\t1\t// set to cause it to be saved to vars.rc\n\t\t\t\t\t\t\t\t// used for system variables, not for player\n\t\t\t\t\t\t\t\t// specific configurations\n#define\tCVAR_USERINFO\t\t2\t// sent to server on connect or change\n#define\tCVAR_SERVERINFO\t\t4\t// sent in response to front end requests\n#define\tCVAR_SYSTEMINFO\t\t8\t// these cvars will be duplicated on all clients\n#define\tCVAR_INIT\t\t\t16\t// don't allow change from console at all,\n\t\t\t\t\t\t\t\t// but can be set from the command line\n#define\tCVAR_LATCH\t\t\t32\t// will only change when C code next does\n\t\t\t\t\t\t\t\t// a Cvar_Get(), so it can't be changed\n\t\t\t\t\t\t\t\t// without proper initialization.  modified\n\t\t\t\t\t\t\t\t// will be set, even though the value hasn't\n\t\t\t\t\t\t\t\t// changed yet\n#define\tCVAR_ROM\t\t\t64\t// display only, cannot be set by user at all\n#define\tCVAR_USER_CREATED\t128\t// created by a set command\n#define\tCVAR_TEMP\t\t\t256\t// can be set even when cheats are disabled, but is not archived\n#define CVAR_CHEAT\t\t\t512\t// can not be changed if cheats are disabled\n#define CVAR_NORESTART\t\t1024\t// do not clear when a cvar_restart is issued\n\n// nothing outside the Cvar_*() functions should modify these fields!\ntypedef struct cvar_s {\n\tchar\t\t*name;\n\tchar\t\t*string;\n\tchar\t\t*resetString;\t\t// cvar_restart will reset to this value\n\tchar\t\t*latchedString;\t\t// for CVAR_LATCH vars\n\tint\t\t\tflags;\n\tqboolean\tmodified;\t\t\t// set each time the cvar is changed\n\tint\t\t\tmodificationCount;\t// incremented each time the cvar is changed\n\tfloat\t\tvalue;\t\t\t\t// atof( string )\n\tint\t\t\tinteger;\t\t\t// atoi( string )\n\tstruct cvar_s *next;\n\tstruct cvar_s *hashNext;\n} cvar_t;\n\n#define\tMAX_CVAR_VALUE_STRING\t256\n\ntypedef int\tcvarHandle_t;\n\n// the modules that run in the virtual machine can't access the cvar_t directly,\n// so they must ask for structured updates\ntypedef struct {\n\tcvarHandle_t\thandle;\n\tint\t\t\tmodificationCount;\n\tfloat\t\tvalue;\n\tint\t\t\tinteger;\n\tchar\t\tstring[MAX_CVAR_VALUE_STRING];\n} vmCvar_t;\n\n/*\n==============================================================\n\nCOLLISION DETECTION\n\n==============================================================\n*/\n\n#include \"surfaceflags.h\"\t\t\t// shared with the q3map utility\n\n// plane types are used to speed some tests\n// 0-2 are axial planes\n#define\tPLANE_X\t\t\t0\n#define\tPLANE_Y\t\t\t1\n#define\tPLANE_Z\t\t\t2\n#define\tPLANE_NON_AXIAL\t3\n\n\n/*\n=================\nPlaneTypeForNormal\n=================\n*/\n\n#define PlaneTypeForNormal(x) (x[0] == 1.0 ? PLANE_X : (x[1] == 1.0 ? PLANE_Y : (x[2] == 1.0 ? PLANE_Z : PLANE_NON_AXIAL) ) )\n\n// plane_t structure\n// !!! if this is changed, it must be changed in asm code too !!!\ntypedef struct cplane_s {\n\tvec3_t\tnormal;\n\tfloat\tdist;\n\tbyte\ttype;\t\t\t// for fast side tests: 0,1,2 = axial, 3 = nonaxial\n\tbyte\tsignbits;\t\t// signx + (signy<<1) + (signz<<2), used as lookup during collision\n\tbyte\tpad[2];\n} cplane_t;\n\n\n// a trace is returned when a box is swept through the world\ntypedef struct {\n\tqboolean\tallsolid;\t// if true, plane is not valid\n\tqboolean\tstartsolid;\t// if true, the initial point was in a solid area\n\tfloat\t\tfraction;\t// time completed, 1.0 = didn't hit anything\n\tvec3_t\t\tendpos;\t\t// final position\n\tcplane_t\tplane;\t\t// surface normal at impact, transformed to world space\n\tint\t\t\tsurfaceFlags;\t// surface hit\n\tint\t\t\tcontents;\t// contents on other side of surface hit\n\tint\t\t\tentityNum;\t// entity the contacted sirface is a part of\n} trace_t;\n\n// trace->entityNum can also be 0 to (MAX_GENTITIES-1)\n// or ENTITYNUM_NONE, ENTITYNUM_WORLD\n\n\n// markfragments are returned by CM_MarkFragments()\ntypedef struct {\n\tint\t\tfirstPoint;\n\tint\t\tnumPoints;\n} markFragment_t;\n\n\n\ntypedef struct {\n\tvec3_t\t\torigin;\n\tvec3_t\t\taxis[3];\n} orientation_t;\n\n//=====================================================================\n\n\n// in order from highest priority to lowest\n// if none of the catchers are active, bound key strings will be executed\n#define KEYCATCH_CONSOLE\t\t0x0001\n#define\tKEYCATCH_UI\t\t\t\t\t0x0002\n#define\tKEYCATCH_MESSAGE\t\t0x0004\n#define\tKEYCATCH_CGAME\t\t\t0x0008\n\n\n// sound channels\n// channel 0 never willingly overrides\n// other channels will allways override a playing sound on that channel\ntypedef enum {\n\tCHAN_AUTO,\n\tCHAN_LOCAL,\t\t// menu sounds, etc\n\tCHAN_WEAPON,\n\tCHAN_VOICE,\n\tCHAN_ITEM,\n\tCHAN_BODY,\n\tCHAN_LOCAL_SOUND,\t// chat messages, etc\n\tCHAN_ANNOUNCER\t\t// announcer voices, etc\n} soundChannel_t;\n\n\n/*\n========================================================================\n\n  ELEMENTS COMMUNICATED ACROSS THE NET\n\n========================================================================\n*/\n\n#define\tANGLE2SHORT(x)\t((int)((x)*65536/360) & 65535)\n#define\tSHORT2ANGLE(x)\t((x)*(360.0/65536))\n\n#define\tSNAPFLAG_RATE_DELAYED\t1\n#define\tSNAPFLAG_NOT_ACTIVE\t\t2\t// snapshot used during connection and for zombies\n#define SNAPFLAG_SERVERCOUNT\t4\t// toggled every map_restart so transitions can be detected\n\n//\n// per-level limits\n//\n#define\tMAX_CLIENTS\t\t\t64\t\t// absolute limit\n#define MAX_LOCATIONS\t\t64\n\n#define\tGENTITYNUM_BITS\t\t10\t\t// don't need to send any more\n#define\tMAX_GENTITIES\t\t(1<<GENTITYNUM_BITS)\n\n// entitynums are communicated with GENTITY_BITS, so any reserved\n// values that are going to be communcated over the net need to\n// also be in this range\n#define\tENTITYNUM_NONE\t\t(MAX_GENTITIES-1)\n#define\tENTITYNUM_WORLD\t\t(MAX_GENTITIES-2)\n#define\tENTITYNUM_MAX_NORMAL\t(MAX_GENTITIES-2)\n\n\n#define\tMAX_MODELS\t\t\t256\t\t// these are sent over the net as 8 bits\n#define\tMAX_SOUNDS\t\t\t256\t\t// so they cannot be blindly increased\n\n\n#define\tMAX_CONFIGSTRINGS\t1024\n\n// these are the only configstrings that the system reserves, all the\n// other ones are strictly for servergame to clientgame communication\n#define\tCS_SERVERINFO\t\t0\t\t// an info string with all the serverinfo cvars\n#define\tCS_SYSTEMINFO\t\t1\t\t// an info string for server system to client system configuration (timescale, etc)\n\n#define\tRESERVED_CONFIGSTRINGS\t2\t// game can't modify below this, only the system can\n\n#define\tMAX_GAMESTATE_CHARS\t16000\ntypedef struct {\n\tint\t\t\tstringOffsets[MAX_CONFIGSTRINGS];\n\tchar\t\tstringData[MAX_GAMESTATE_CHARS];\n\tint\t\t\tdataCount;\n} gameState_t;\n\n//=========================================================\n\n// bit field limits\n#define\tMAX_STATS\t\t\t\t16\n#define\tMAX_PERSISTANT\t\t\t16\n#define\tMAX_POWERUPS\t\t\t16\n#define\tMAX_WEAPONS\t\t\t\t16\t\t\n\n#define\tMAX_PS_EVENTS\t\t\t2\n\n#define PS_PMOVEFRAMECOUNTBITS\t6\n\n// playerState_t is the information needed by both the client and server\n// to predict player motion and actions\n// nothing outside of pmove should modify these, or some degree of prediction error\n// will occur\n\n// you can't add anything to this without modifying the code in msg.c\n\n// playerState_t is a full superset of entityState_t as it is used by players,\n// so if a playerState_t is transmitted, the entityState_t can be fully derived\n// from it.\ntypedef struct playerState_s {\n\tint\t\t\tcommandTime;\t// cmd->serverTime of last executed command\n\tint\t\t\tpm_type;\n\tint\t\t\tbobCycle;\t\t// for view bobbing and footstep generation\n\tint\t\t\tpm_flags;\t\t// ducked, jump_held, etc\n\tint\t\t\tpm_time;\n\n\tvec3_t\t\torigin;\n\tvec3_t\t\tvelocity;\n\tint\t\t\tweaponTime;\n\tint\t\t\tgravity;\n\tint\t\t\tspeed;\n\tint\t\t\tdelta_angles[3];\t// add to command angles to get view direction\n\t\t\t\t\t\t\t\t\t// changed by spawns, rotating objects, and teleporters\n\n\tint\t\t\tgroundEntityNum;// ENTITYNUM_NONE = in air\n\n\tint\t\t\tlegsTimer;\t\t// don't change low priority animations until this runs out\n\tint\t\t\tlegsAnim;\t\t// mask off ANIM_TOGGLEBIT\n\n\tint\t\t\ttorsoTimer;\t\t// don't change low priority animations until this runs out\n\tint\t\t\ttorsoAnim;\t\t// mask off ANIM_TOGGLEBIT\n\n\tint\t\t\tmovementDir;\t// a number 0 to 7 that represents the reletive angle\n\t\t\t\t\t\t\t\t// of movement to the view angle (axial and diagonals)\n\t\t\t\t\t\t\t\t// when at rest, the value will remain unchanged\n\t\t\t\t\t\t\t\t// used to twist the legs during strafing\n\n\tvec3_t\t\tgrapplePoint;\t// location of grapple to pull towards if PMF_GRAPPLE_PULL\n\n\tint\t\t\teFlags;\t\t\t// copied to entityState_t->eFlags\n\n\tint\t\t\teventSequence;\t// pmove generated events\n\tint\t\t\tevents[MAX_PS_EVENTS];\n\tint\t\t\teventParms[MAX_PS_EVENTS];\n\n\tint\t\t\texternalEvent;\t// events set on player from another source\n\tint\t\t\texternalEventParm;\n\tint\t\t\texternalEventTime;\n\n\tint\t\t\tclientNum;\t\t// ranges from 0 to MAX_CLIENTS-1\n\tint\t\t\tweapon;\t\t\t// copied to entityState_t->weapon\n\tint\t\t\tweaponstate;\n\n\tvec3_t\t\tviewangles;\t\t// for fixed views\n\tint\t\t\tviewheight;\n\n\t// damage feedback\n\tint\t\t\tdamageEvent;\t// when it changes, latch the other parms\n\tint\t\t\tdamageYaw;\n\tint\t\t\tdamagePitch;\n\tint\t\t\tdamageCount;\n\n\tint\t\t\tstats[MAX_STATS];\n\tint\t\t\tpersistant[MAX_PERSISTANT];\t// stats that aren't cleared on death\n\tint\t\t\tpowerups[MAX_POWERUPS];\t// level.time that the powerup runs out\n\tint\t\t\tammo[MAX_WEAPONS];\n\n\tint\t\t\tgeneric1;\n\tint\t\t\tloopSound;\n\tint\t\t\tjumppad_ent;\t// jumppad entity hit this frame\n\n\t// not communicated over the net at all\n\tint\t\t\tping;\t\t\t// server to game info for scoreboard\n\tint\t\t\tpmove_framecount;\t// FIXME: don't transmit over the network\n\tint\t\t\tjumppad_frame;\n\tint\t\t\tentityEventSequence;\n} playerState_t;\n\n\n//====================================================================\n\n\n//\n// usercmd_t->button bits, many of which are generated by the client system,\n// so they aren't game/cgame only definitions\n//\n#define\tBUTTON_ATTACK\t\t1\n#define\tBUTTON_TALK\t\t\t2\t\t\t// displays talk balloon and disables actions\n#define\tBUTTON_USE_HOLDABLE\t4\n#define\tBUTTON_GESTURE\t\t8\n#define\tBUTTON_WALKING\t\t16\t\t\t// walking can't just be infered from MOVE_RUN\n\t\t\t\t\t\t\t\t\t\t// because a key pressed late in the frame will\n\t\t\t\t\t\t\t\t\t\t// only generate a small move value for that frame\n\t\t\t\t\t\t\t\t\t\t// walking will use different animations and\n\t\t\t\t\t\t\t\t\t\t// won't generate footsteps\n#define BUTTON_AFFIRMATIVE\t32\n#define\tBUTTON_NEGATIVE\t\t64\n\n#define BUTTON_GETFLAG\t\t128\n#define BUTTON_GUARDBASE\t256\n#define BUTTON_PATROL\t\t512\n#define BUTTON_FOLLOWME\t\t1024\n\n#define\tBUTTON_ANY\t\t\t2048\t\t\t// any key whatsoever\n\n#define\tMOVE_RUN\t\t\t120\t\t\t// if forwardmove or rightmove are >= MOVE_RUN,\n\t\t\t\t\t\t\t\t\t\t// then BUTTON_WALKING should be set\n\n// usercmd_t is sent to the server each client frame\ntypedef struct usercmd_s {\n\tint\t\t\t\tserverTime;\n\tint\t\t\t\tangles[3];\n\tint \t\t\tbuttons;\n\tbyte\t\t\tweapon;           // weapon \n\tsigned char\tforwardmove, rightmove, upmove;\n} usercmd_t;\n\n//===================================================================\n\n// if entityState->solid == SOLID_BMODEL, modelindex is an inline model number\n#define\tSOLID_BMODEL\t0xffffff\n\ntypedef enum {\n\tTR_STATIONARY,\n\tTR_INTERPOLATE,\t\t\t\t// non-parametric, but interpolate between snapshots\n\tTR_LINEAR,\n\tTR_LINEAR_STOP,\n\tTR_SINE,\t\t\t\t\t// value = base + sin( time / duration ) * delta\n\tTR_GRAVITY\n} trType_t;\n\ntypedef struct {\n\ttrType_t\ttrType;\n\tint\t\ttrTime;\n\tint\t\ttrDuration;\t\t\t// if non 0, trTime + trDuration = stop time\n\tvec3_t\ttrBase;\n\tvec3_t\ttrDelta;\t\t\t// velocity, etc\n} trajectory_t;\n\n// entityState_t is the information conveyed from the server\n// in an update message about entities that the client will\n// need to render in some way\n// Different eTypes may use the information in different ways\n// The messages are delta compressed, so it doesn't really matter if\n// the structure size is fairly large\n\ntypedef struct entityState_s {\n\tint\t\tnumber;\t\t\t// entity index\n\tint\t\teType;\t\t\t// entityType_t\n\tint\t\teFlags;\n\n\ttrajectory_t\tpos;\t// for calculating position\n\ttrajectory_t\tapos;\t// for calculating angles\n\n\tint\t\ttime;\n\tint\t\ttime2;\n\n\tvec3_t\torigin;\n\tvec3_t\torigin2;\n\n\tvec3_t\tangles;\n\tvec3_t\tangles2;\n\n\tint\t\totherEntityNum;\t// shotgun sources, etc\n\tint\t\totherEntityNum2;\n\n\tint\t\tgroundEntityNum;\t// -1 = in air\n\n\tint\t\tconstantLight;\t// r + (g<<8) + (b<<16) + (intensity<<24)\n\tint\t\tloopSound;\t\t// constantly loop this sound\n\n\tint\t\tmodelindex;\n\tint\t\tmodelindex2;\n\tint\t\tclientNum;\t\t// 0 to (MAX_CLIENTS - 1), for players and corpses\n\tint\t\tframe;\n\n\tint\t\tsolid;\t\t\t// for client side prediction, trap_linkentity sets this properly\n\n\tint\t\tevent;\t\t\t// impulse events -- muzzle flashes, footsteps, etc\n\tint\t\teventParm;\n\n\t// for players\n\tint\t\tpowerups;\t\t// bit flags\n\tint\t\tweapon;\t\t\t// determines weapon and flash model, etc\n\tint\t\tlegsAnim;\t\t// mask off ANIM_TOGGLEBIT\n\tint\t\ttorsoAnim;\t\t// mask off ANIM_TOGGLEBIT\n\n\tint\t\tgeneric1;\n} entityState_t;\n\ntypedef enum {\n\tCA_UNINITIALIZED,\n\tCA_DISCONNECTED, \t// not talking to a server\n\tCA_AUTHORIZING,\t\t// not used any more, was checking cd key \n\tCA_CONNECTING,\t\t// sending request packets to the server\n\tCA_CHALLENGING,\t\t// sending challenge packets to the server\n\tCA_CONNECTED,\t\t// netchan_t established, getting gamestate\n\tCA_LOADING,\t\t\t// only during cgame initialization, never during main loop\n\tCA_PRIMED,\t\t\t// got gamestate, waiting for first frame\n\tCA_ACTIVE,\t\t\t// game views should be displayed\n\tCA_CINEMATIC\t\t// playing a cinematic or a static pic, not connected to a server\n} connstate_t;\n\n// font support \n\n#define GLYPH_START 0\n#define GLYPH_END 255\n#define GLYPH_CHARSTART 32\n#define GLYPH_CHAREND 127\n#define GLYPHS_PER_FONT GLYPH_END - GLYPH_START + 1\ntypedef struct {\n  int height;       // number of scan lines\n  int top;          // top of glyph in buffer\n  int bottom;       // bottom of glyph in buffer\n  int pitch;        // width for copying\n  int xSkip;        // x adjustment\n  int imageWidth;   // width of actual image\n  int imageHeight;  // height of actual image\n  float s;          // x offset in image where glyph starts\n  float t;          // y offset in image where glyph starts\n  float s2;\n  float t2;\n  qhandle_t glyph;  // handle to the shader with the glyph\n  char shaderName[32];\n} glyphInfo_t;\n\ntypedef struct {\n  glyphInfo_t glyphs [GLYPHS_PER_FONT];\n  float glyphScale;\n  char name[MAX_QPATH];\n} fontInfo_t;\n\n#define Square(x) ((x)*(x))\n\n// real time\n//=============================================\n\n\ntypedef struct qtime_s {\n\tint tm_sec;     /* seconds after the minute - [0,59] */\n\tint tm_min;     /* minutes after the hour - [0,59] */\n\tint tm_hour;    /* hours since midnight - [0,23] */\n\tint tm_mday;    /* day of the month - [1,31] */\n\tint tm_mon;     /* months since January - [0,11] */\n\tint tm_year;    /* years since 1900 */\n\tint tm_wday;    /* days since Sunday - [0,6] */\n\tint tm_yday;    /* days since January 1 - [0,365] */\n\tint tm_isdst;   /* daylight savings time flag */\n} qtime_t;\n\n\n// server browser sources\n// TTimo: AS_MPLAYER is no longer used\n#define AS_LOCAL\t\t\t0\n#define AS_MPLAYER\t\t1\n#define AS_GLOBAL\t\t\t2\n#define AS_FAVORITES\t3\n\n\n// cinematic states\ntypedef enum {\n\tFMV_IDLE,\n\tFMV_PLAY,\t\t// play\n\tFMV_EOF,\t\t// all other conditions, i.e. stop/EOF/abort\n\tFMV_ID_BLT,\n\tFMV_ID_IDLE,\n\tFMV_LOOPED,\n\tFMV_ID_WAIT\n} e_status;\n\ntypedef enum _flag_status {\n\tFLAG_ATBASE = 0,\n\tFLAG_TAKEN,\t\t\t// CTF\n\tFLAG_TAKEN_RED,\t\t// One Flag CTF\n\tFLAG_TAKEN_BLUE,\t// One Flag CTF\n\tFLAG_DROPPED\n} flagStatus_t;\n\n\n\n#define\tMAX_GLOBAL_SERVERS\t\t\t\t4096\n#define\tMAX_OTHER_SERVERS\t\t\t\t\t128\n#define MAX_PINGREQUESTS\t\t\t\t\t32\n#define MAX_SERVERSTATUSREQUESTS\t16\n\n#define SAY_ALL\t\t0\n#define SAY_TEAM\t1\n#define SAY_TELL\t2\n\n#define CDKEY_LEN 16\n#define CDCHKSUM_LEN 2\n\n\n#endif\t// __Q_SHARED_H\n"
  },
  {
    "path": "src/game/surfaceflags.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n// This file must be identical in the quake and utils directories\n\n// contents flags are seperate bits\n// a given brush can contribute multiple content bits\n\n// these definitions also need to be in q_shared.h!\n\n#define\tCONTENTS_SOLID\t\t\t1\t\t// an eye is never valid in a solid\n#define\tCONTENTS_LAVA\t\t\t8\n#define\tCONTENTS_SLIME\t\t\t16\n#define\tCONTENTS_WATER\t\t\t32\n#define\tCONTENTS_FOG\t\t\t64\n\n#define CONTENTS_NOTTEAM1\t\t0x0080\n#define CONTENTS_NOTTEAM2\t\t0x0100\n#define CONTENTS_NOBOTCLIP\t\t0x0200\n\n#define\tCONTENTS_AREAPORTAL\t\t0x8000\n\n#define\tCONTENTS_PLAYERCLIP\t\t0x10000\n#define\tCONTENTS_MONSTERCLIP\t0x20000\n//bot specific contents types\n#define\tCONTENTS_TELEPORTER\t\t0x40000\n#define\tCONTENTS_JUMPPAD\t\t0x80000\n#define CONTENTS_CLUSTERPORTAL\t0x100000\n#define CONTENTS_DONOTENTER\t\t0x200000\n#define CONTENTS_BOTCLIP\t\t0x400000\n#define CONTENTS_MOVER\t\t\t0x800000\n\n#define\tCONTENTS_ORIGIN\t\t\t0x1000000\t// removed before bsping an entity\n\n#define\tCONTENTS_BODY\t\t\t0x2000000\t// should never be on a brush, only in game\n#define\tCONTENTS_CORPSE\t\t\t0x4000000\n#define\tCONTENTS_DETAIL\t\t\t0x8000000\t// brushes not used for the bsp\n#define\tCONTENTS_STRUCTURAL\t\t0x10000000\t// brushes used for the bsp\n#define\tCONTENTS_TRANSLUCENT\t0x20000000\t// don't consume surface fragments inside\n#define\tCONTENTS_TRIGGER\t\t0x40000000\n#define\tCONTENTS_NODROP\t\t\t0x80000000\t// don't leave bodies or items (death fog, lava)\n\n#define\tSURF_NODAMAGE\t\t\t0x1\t\t// never give falling damage\n#define\tSURF_SLICK\t\t\t\t0x2\t\t// effects game physics\n#define\tSURF_SKY\t\t\t\t0x4\t\t// lighting from environment map\n#define\tSURF_LADDER\t\t\t\t0x8\n#define\tSURF_NOIMPACT\t\t\t0x10\t// don't make missile explosions\n#define\tSURF_NOMARKS\t\t\t0x20\t// don't leave missile marks\n#define\tSURF_FLESH\t\t\t\t0x40\t// make flesh sounds and effects\n#define\tSURF_NODRAW\t\t\t\t0x80\t// don't generate a drawsurface at all\n#define\tSURF_HINT\t\t\t\t0x100\t// make a primary bsp splitter\n#define\tSURF_SKIP\t\t\t\t0x200\t// completely ignore, allowing non-closed brushes\n#define\tSURF_NOLIGHTMAP\t\t\t0x400\t// surface doesn't need a lightmap\n#define\tSURF_POINTLIGHT\t\t\t0x800\t// generate lighting info at vertexes\n#define\tSURF_METALSTEPS\t\t\t0x1000\t// clanking footsteps\n#define\tSURF_NOSTEPS\t\t\t0x2000\t// no footstep sounds\n#define\tSURF_NONSOLID\t\t\t0x4000\t// don't collide against curves with this set\n#define\tSURF_LIGHTFILTER\t\t0x8000\t// act as a light filter during q3map -light\n#define\tSURF_ALPHASHADOW\t\t0x10000\t// do per-pixel light shadow casting in q3map\n#define\tSURF_NODLIGHT\t\t\t0x20000\t// don't dlight even if solid (solid lava, skies)\n#define SURF_DUST\t\t\t\t0x40000 // leave a dust trail when walking on this surface\n"
  },
  {
    "path": "src/game/syn.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n\n#define CONTEXT_ALL\t\t\t\t\t\t0xFFFFFFFF\n#define CONTEXT_NORMAL\t\t\t\t\t1\n#define CONTEXT_NEARBYITEM\t\t\t\t2\n#define CONTEXT_CTFREDTEAM\t\t\t\t4\n#define CONTEXT_CTFBLUETEAM\t\t\t\t8\n#define CONTEXT_REPLY\t\t\t\t\t16\n#define CONTEXT_OBELISKREDTEAM\t\t\t32\n#define CONTEXT_OBELISKBLUETEAM\t\t\t64\n#define CONTEXT_HARVESTERREDTEAM\t\t128\n#define CONTEXT_HARVESTERBLUETEAM\t\t256\n\n#define CONTEXT_NAMES 1024\n"
  },
  {
    "path": "src/q3_ui/keycodes.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n#ifndef __KEYCODES_H__\n#define __KEYCODES_H__\n\n//\n// these are the key numbers that should be passed to KeyEvent\n//\n\n// normal keys should be passed as lowercased ascii\n\ntypedef enum {\n\tK_TAB = 9,\n\tK_ENTER = 13,\n\tK_ESCAPE = 27,\n\tK_SPACE = 32,\n\n\tK_BACKSPACE = 127,\n\n\tK_COMMAND = 128,\n\tK_CAPSLOCK,\n\tK_POWER,\n\tK_PAUSE,\n\n\tK_UPARROW,\n\tK_DOWNARROW,\n\tK_LEFTARROW,\n\tK_RIGHTARROW,\n\n\tK_ALT,\n\tK_CTRL,\n\tK_SHIFT,\n\tK_INS,\n\tK_DEL,\n\tK_PGDN,\n\tK_PGUP,\n\tK_HOME,\n\tK_END,\n\n\tK_F1,\n\tK_F2,\n\tK_F3,\n\tK_F4,\n\tK_F5,\n\tK_F6,\n\tK_F7,\n\tK_F8,\n\tK_F9,\n\tK_F10,\n\tK_F11,\n\tK_F12,\n\tK_F13,\n\tK_F14,\n\tK_F15,\n\n\tK_KP_HOME,\n\tK_KP_UPARROW,\n\tK_KP_PGUP,\n\tK_KP_LEFTARROW,\n\tK_KP_5,\n\tK_KP_RIGHTARROW,\n\tK_KP_END,\n\tK_KP_DOWNARROW,\n\tK_KP_PGDN,\n\tK_KP_ENTER,\n\tK_KP_INS,\n\tK_KP_DEL,\n\tK_KP_SLASH,\n\tK_KP_MINUS,\n\tK_KP_PLUS,\n\tK_KP_NUMLOCK,\n\tK_KP_STAR,\n\tK_KP_EQUALS,\n\n\tK_MOUSE1,\n\tK_MOUSE2,\n\tK_MOUSE3,\n\tK_MOUSE4,\n\tK_MOUSE5,\n\n\tK_MWHEELDOWN,\n\tK_MWHEELUP,\n\n\tK_JOY1,\n\tK_JOY2,\n\tK_JOY3,\n\tK_JOY4,\n\tK_JOY5,\n\tK_JOY6,\n\tK_JOY7,\n\tK_JOY8,\n\tK_JOY9,\n\tK_JOY10,\n\tK_JOY11,\n\tK_JOY12,\n\tK_JOY13,\n\tK_JOY14,\n\tK_JOY15,\n\tK_JOY16,\n\tK_JOY17,\n\tK_JOY18,\n\tK_JOY19,\n\tK_JOY20,\n\tK_JOY21,\n\tK_JOY22,\n\tK_JOY23,\n\tK_JOY24,\n\tK_JOY25,\n\tK_JOY26,\n\tK_JOY27,\n\tK_JOY28,\n\tK_JOY29,\n\tK_JOY30,\n\tK_JOY31,\n\tK_JOY32,\n\n\tK_AUX1,\n\tK_AUX2,\n\tK_AUX3,\n\tK_AUX4,\n\tK_AUX5,\n\tK_AUX6,\n\tK_AUX7,\n\tK_AUX8,\n\tK_AUX9,\n\tK_AUX10,\n\tK_AUX11,\n\tK_AUX12,\n\tK_AUX13,\n\tK_AUX14,\n\tK_AUX15,\n\tK_AUX16,\n\n\tK_LAST_KEY\t\t// this had better be <256!\n} keyNum_t;\n\n\n// The menu code needs to get both key and char events, but\n// to avoid duplicating the paths, the char events are just\n// distinguished by or'ing in K_CHAR_FLAG (ugly)\n#define\tK_CHAR_FLAG\t\t1024\n\n#endif\n"
  },
  {
    "path": "src/q3_ui/q3_ui.bat",
    "content": "rem make sure we have a safe environement\nset LIBRARY=\nset INCLUDE=\n\nmkdir ..\\..\\intermediate\\vm\\ui\ncd ..\\..\\intermediate\\vm\\ui\n\nset PATH=..\\..\\..\\tools\\bin;%PATH%\n\nset src=..\\..\\..\\source\nset cc=lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I%src%\\cgame -I%src%\\game -I%src%\\ui %1\n\n%cc% %src%/q3_ui/ui_main.c\n@if errorlevel 1 goto quit\n%cc% %src%/q3_ui/ui_cdkey.c\n@if errorlevel 1 goto quit\n%cc% %src%/q3_ui/ui_ingame.c\n@if errorlevel 1 goto quit\n%cc% %src%/q3_ui/ui_serverinfo.c\n@if errorlevel 1 goto quit\n%cc% %src%/q3_ui/ui_confirm.c\n@if errorlevel 1 goto quit\n%cc% %src%/q3_ui/ui_setup.c\n@if errorlevel 1 goto quit\n%cc% %src%/game/bg_misc.c\n@if errorlevel 1 goto quit\n%cc% %src%/game/bg_lib.c\n@if errorlevel 1 goto quit\n%cc% %src%/game/q_math.c\n@if errorlevel 1 goto quit\n%cc% %src%/game/q_shared.c\n@if errorlevel 1 goto quit\n%cc% %src%/q3_ui/ui_gameinfo.c\n@if errorlevel 1 goto quit\n%cc% %src%/q3_ui/ui_atoms.c\n@if errorlevel 1 goto quit\n%cc% %src%/q3_ui/ui_connect.c\n@if errorlevel 1 goto quit\n%cc% %src%/q3_ui/ui_controls2.c\n@if errorlevel 1 goto quit\n%cc% %src%/q3_ui/ui_demo2.c\n@if errorlevel 1 goto quit\n%cc% %src%/q3_ui/ui_mfield.c\n@if errorlevel 1 goto quit\n%cc% %src%/q3_ui/ui_credits.c\n@if errorlevel 1 goto quit\n%cc% %src%/q3_ui/ui_menu.c\n@if errorlevel 1 goto quit\n%cc% %src%/q3_ui/ui_options.c\n@if errorlevel 1 goto quit\n%cc% %src%/q3_ui/ui_display.c\n@if errorlevel 1 goto quit\n%cc% %src%/q3_ui/ui_sound.c\n@if errorlevel 1 goto quit\n%cc% %src%/q3_ui/ui_network.c\n@if errorlevel 1 goto quit\n%cc% %src%/q3_ui/ui_playermodel.c\n@if errorlevel 1 goto quit\n%cc% %src%/q3_ui/ui_players.c\n@if errorlevel 1 goto quit\n%cc% %src%/q3_ui/ui_playersettings.c\n@if errorlevel 1 goto quit\n%cc% %src%/q3_ui/ui_preferences.c\n@if errorlevel 1 goto quit\n%cc% %src%/q3_ui/ui_qmenu.c\n@if errorlevel 1 goto quit\n%cc% %src%/q3_ui/ui_servers2.c\n@if errorlevel 1 goto quit\n%cc% %src%/q3_ui/ui_sparena.c\n@if errorlevel 1 goto quit\n%cc% %src%/q3_ui/ui_specifyserver.c\n@if errorlevel 1 goto quit\n%cc% %src%/q3_ui/ui_splevel.c\n@if errorlevel 1 goto quit\n%cc% %src%/q3_ui/ui_sppostgame.c\n@if errorlevel 1 goto quit\n%cc% %src%/q3_ui/ui_startserver.c\n@if errorlevel 1 goto quit\n%cc% %src%/q3_ui/ui_team.c\n@if errorlevel 1 goto quit\n%cc% %src%/q3_ui/ui_video.c\n@if errorlevel 1 goto quit\n%cc% %src%/q3_ui/ui_cinematics.c\n@if errorlevel 1 goto quit\n%cc% %src%/q3_ui/ui_spskill.c\n@if errorlevel 1 goto quit\n%cc% %src%/q3_ui/ui_addbots.c\n@if errorlevel 1 goto quit\n%cc% %src%/q3_ui/ui_removebots.c\n@if errorlevel 1 goto quit\n%cc% %src%/q3_ui/ui_teamorders.c\n@if errorlevel 1 goto quit\n%cc% %src%/q3_ui/ui_mods.c\n@if errorlevel 1 goto quit\n\nq3asm -f %src%/q3_ui/q3_ui\n:quit\ncd %src%/q3_ui\n"
  },
  {
    "path": "src/q3_ui/q3_ui.q3asm",
    "content": "-o \"..\\..\\..\\binaries\\vm\\ui.qvm\"\nui_main\n..\\..\\..\\source\\q3_ui\\ui_syscalls\nui_gameinfo\nui_atoms\nui_cinematics\nui_connect\nui_controls2\nui_demo2\nui_mfield\nui_credits\nui_menu\nui_ingame\nui_confirm\nui_setup\nui_options\nui_display\nui_sound\nui_network\nui_playermodel\nui_players\nui_playersettings\nui_preferences\nui_qmenu\nui_serverinfo\nui_servers2\nui_sparena\nui_specifyserver\nui_sppostgame\nui_splevel\nui_spskill\nui_startserver\nui_team\nui_video\nui_addbots\nui_removebots\nui_teamorders\nui_cdkey\nui_mods\nbg_misc\nbg_lib\nq_math\nq_shared\n"
  },
  {
    "path": "src/q3_ui/ui_addbots.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n/*\n=======================================================================\n\nADD BOTS MENU\n\n=======================================================================\n*/\n\n\n#include \"ui_local.h\"\n\n\n#define ART_BACK0\t\t\t\"menu/art/back_0\"\n#define ART_BACK1\t\t\t\"menu/art/back_1\"\t\n#define ART_FIGHT0\t\t\t\"menu/art/accept_0\"\n#define ART_FIGHT1\t\t\t\"menu/art/accept_1\"\n#define ART_BACKGROUND\t\t\"menu/art/addbotframe\"\n#define ART_ARROWS\t\t\t\"menu/art/arrows_vert_0\"\n#define ART_ARROWUP\t\t\t\"menu/art/arrows_vert_top\"\n#define ART_ARROWDOWN\t\t\"menu/art/arrows_vert_bot\"\n\n#define ID_BACK\t\t\t\t10\n#define ID_GO\t\t\t\t11\n#define ID_LIST\t\t\t\t12\n#define ID_UP\t\t\t\t13\n#define ID_DOWN\t\t\t\t14\n#define ID_SKILL\t\t\t15\n#define ID_TEAM\t\t\t\t16\n#define ID_BOTNAME0\t\t\t20\n#define ID_BOTNAME1\t\t\t21\n#define ID_BOTNAME2\t\t\t22\n#define ID_BOTNAME3\t\t\t23\n#define ID_BOTNAME4\t\t\t24\n#define ID_BOTNAME5\t\t\t25\n#define ID_BOTNAME6\t\t\t26\n\n\ntypedef struct {\n\tmenuframework_s\tmenu;\n\tmenubitmap_s\tarrows;\n\tmenubitmap_s\tup;\n\tmenubitmap_s\tdown;\n\tmenutext_s\t\tbots[7];\n\tmenulist_s\t\tskill;\n\tmenulist_s\t\tteam;\n\tmenubitmap_s\tgo;\n\tmenubitmap_s\tback;\n\n\tint\t\t\t\tnumBots;\n\tint\t\t\t\tdelay;\n\tint\t\t\t\tbaseBotNum;\n\tint\t\t\t\tselectedBotNum;\n\tint\t\t\t\tsortedBotNums[MAX_BOTS];\n\tchar\t\t\tbotnames[7][32];\n} addBotsMenuInfo_t;\n\nstatic addBotsMenuInfo_t\taddBotsMenuInfo;\n\n\n/*\n=================\nUI_AddBotsMenu_FightEvent\n=================\n*/\nstatic void UI_AddBotsMenu_FightEvent( void* ptr, int event ) {\n\tconst char\t*team;\n\tint\t\t\tskill;\n\n\tif (event != QM_ACTIVATED) {\n\t\treturn;\n\t}\n\n\tteam = addBotsMenuInfo.team.itemnames[addBotsMenuInfo.team.curvalue];\n\tskill = addBotsMenuInfo.skill.curvalue + 1;\n\n\ttrap_Cmd_ExecuteText( EXEC_APPEND, va(\"addbot %s %i %s %i\\n\",\n\t\taddBotsMenuInfo.botnames[addBotsMenuInfo.selectedBotNum], skill, team, addBotsMenuInfo.delay) );\n\n\taddBotsMenuInfo.delay += 1500;\n}\n\n\n/*\n=================\nUI_AddBotsMenu_BotEvent\n=================\n*/\nstatic void UI_AddBotsMenu_BotEvent( void* ptr, int event ) {\n\tif (event != QM_ACTIVATED) {\n\t\treturn;\n\t}\n\n\taddBotsMenuInfo.bots[addBotsMenuInfo.selectedBotNum].color = color_orange;\n\taddBotsMenuInfo.selectedBotNum = ((menucommon_s*)ptr)->id - ID_BOTNAME0;\n\taddBotsMenuInfo.bots[addBotsMenuInfo.selectedBotNum].color = color_white;\n}\n\n\n/*\n=================\nUI_AddBotsMenu_BackEvent\n=================\n*/\nstatic void UI_AddBotsMenu_BackEvent( void* ptr, int event ) {\n\tif (event != QM_ACTIVATED) {\n\t\treturn;\n\t}\n\tUI_PopMenu();\n}\n\n\n/*\n=================\nUI_AddBotsMenu_SetBotNames\n=================\n*/\nstatic void UI_AddBotsMenu_SetBotNames( void ) {\n\tint\t\t\tn;\n\tconst char\t*info;\n\n\tfor ( n = 0; n < 7; n++ ) {\n\t\tinfo = UI_GetBotInfoByNumber( addBotsMenuInfo.sortedBotNums[addBotsMenuInfo.baseBotNum + n] );\n\t\tQ_strncpyz( addBotsMenuInfo.botnames[n], Info_ValueForKey( info, \"name\" ), sizeof(addBotsMenuInfo.botnames[n]) );\n\t}\n\n}\n\n\n/*\n=================\nUI_AddBotsMenu_UpEvent\n=================\n*/\nstatic void UI_AddBotsMenu_UpEvent( void* ptr, int event ) {\n\tif (event != QM_ACTIVATED) {\n\t\treturn;\n\t}\n\n\tif( addBotsMenuInfo.baseBotNum > 0 ) {\n\t\taddBotsMenuInfo.baseBotNum--;\n\t\tUI_AddBotsMenu_SetBotNames();\n\t}\n}\n\n\n/*\n=================\nUI_AddBotsMenu_DownEvent\n=================\n*/\nstatic void UI_AddBotsMenu_DownEvent( void* ptr, int event ) {\n\tif (event != QM_ACTIVATED) {\n\t\treturn;\n\t}\n\n\tif( addBotsMenuInfo.baseBotNum + 7 < addBotsMenuInfo.numBots ) {\n\t\taddBotsMenuInfo.baseBotNum++;\n\t\tUI_AddBotsMenu_SetBotNames();\n\t}\n}\n\n\n/*\n=================\nUI_AddBotsMenu_GetSortedBotNums\n=================\n*/\nstatic int QDECL UI_AddBotsMenu_SortCompare( const void *arg1, const void *arg2 ) {\n\tint\t\t\tnum1, num2;\n\tconst char\t*info1, *info2;\n\tconst char\t*name1, *name2;\n\n\tnum1 = *(int *)arg1;\n\tnum2 = *(int *)arg2;\n\n\tinfo1 = UI_GetBotInfoByNumber( num1 );\n\tinfo2 = UI_GetBotInfoByNumber( num2 );\n\n\tname1 = Info_ValueForKey( info1, \"name\" );\n\tname2 = Info_ValueForKey( info2, \"name\" );\n\n\treturn Q_stricmp( name1, name2 );\n}\n\nstatic void UI_AddBotsMenu_GetSortedBotNums( void ) {\n\tint\t\tn;\n\n\t// initialize the array\n\tfor( n = 0; n < addBotsMenuInfo.numBots; n++ ) {\n\t\taddBotsMenuInfo.sortedBotNums[n] = n;\n\t}\n\n\tqsort( addBotsMenuInfo.sortedBotNums, addBotsMenuInfo.numBots, sizeof(addBotsMenuInfo.sortedBotNums[0]), UI_AddBotsMenu_SortCompare );\n}\n\n\n/*\n=================\nUI_AddBotsMenu_Draw\n=================\n*/\nstatic void UI_AddBotsMenu_Draw( void ) {\n\tUI_DrawBannerString( 320, 16, \"ADD BOTS\", UI_CENTER, color_white );\n\tUI_DrawNamedPic( 320-233, 240-166, 466, 332, ART_BACKGROUND );\n\n\t// standard menu drawing\n\tMenu_Draw( &addBotsMenuInfo.menu );\n}\n\n\t\n/*\n=================\nUI_AddBotsMenu_Init\n=================\n*/\nstatic const char *skillNames[] = {\n\t\"I Can Win\",\n\t\"Bring It On\",\n\t\"Hurt Me Plenty\",\n\t\"Hardcore\",\n\t\"Nightmare!\",\n\t0\n};\n\nstatic const char *teamNames1[] = {\n\t\"Free\",\n\t0\n};\n\nstatic const char *teamNames2[] = {\n\t\"Red\",\n\t\"Blue\",\n\t0\n};\n\nstatic void UI_AddBotsMenu_Init( void ) {\n\tint\t\tn;\n\tint\t\ty;\n\tint\t\tgametype;\n\tint\t\tcount;\n\tchar\tinfo[MAX_INFO_STRING];\n\n\ttrap_GetConfigString(CS_SERVERINFO, info, MAX_INFO_STRING);   \n\tgametype = atoi( Info_ValueForKey( info,\"g_gametype\" ) );\n\n\tmemset( &addBotsMenuInfo, 0 ,sizeof(addBotsMenuInfo) );\n\taddBotsMenuInfo.menu.draw = UI_AddBotsMenu_Draw;\n\taddBotsMenuInfo.menu.fullscreen = qfalse;\n\taddBotsMenuInfo.menu.wrapAround = qtrue;\n\taddBotsMenuInfo.delay = 1000;\n\n\tUI_AddBots_Cache();\n\n\taddBotsMenuInfo.numBots = UI_GetNumBots();\n\tcount = addBotsMenuInfo.numBots < 7 ? addBotsMenuInfo.numBots : 7;\n\n\taddBotsMenuInfo.arrows.generic.type  = MTYPE_BITMAP;\n\taddBotsMenuInfo.arrows.generic.name  = ART_ARROWS;\n\taddBotsMenuInfo.arrows.generic.flags = QMF_INACTIVE;\n\taddBotsMenuInfo.arrows.generic.x\t = 200;\n\taddBotsMenuInfo.arrows.generic.y\t = 128;\n\taddBotsMenuInfo.arrows.width  \t     = 64;\n\taddBotsMenuInfo.arrows.height  \t     = 128;\n\n\taddBotsMenuInfo.up.generic.type\t    = MTYPE_BITMAP;\n\taddBotsMenuInfo.up.generic.flags    = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\taddBotsMenuInfo.up.generic.x\t\t= 200;\n\taddBotsMenuInfo.up.generic.y\t\t= 128;\n\taddBotsMenuInfo.up.generic.id\t    = ID_UP;\n\taddBotsMenuInfo.up.generic.callback = UI_AddBotsMenu_UpEvent;\n\taddBotsMenuInfo.up.width  \t\t    = 64;\n\taddBotsMenuInfo.up.height  \t\t    = 64;\n\taddBotsMenuInfo.up.focuspic         = ART_ARROWUP;\n\n\taddBotsMenuInfo.down.generic.type\t  = MTYPE_BITMAP;\n\taddBotsMenuInfo.down.generic.flags    = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\taddBotsMenuInfo.down.generic.x\t\t  = 200;\n\taddBotsMenuInfo.down.generic.y\t\t  = 128+64;\n\taddBotsMenuInfo.down.generic.id\t      = ID_DOWN;\n\taddBotsMenuInfo.down.generic.callback = UI_AddBotsMenu_DownEvent;\n\taddBotsMenuInfo.down.width  \t\t  = 64;\n\taddBotsMenuInfo.down.height  \t\t  = 64;\n\taddBotsMenuInfo.down.focuspic         = ART_ARROWDOWN;\n\n\tfor( n = 0, y = 120; n < count; n++, y += 20 ) {\n\t\taddBotsMenuInfo.bots[n].generic.type\t\t= MTYPE_PTEXT;\n\t\taddBotsMenuInfo.bots[n].generic.flags\t\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\t\taddBotsMenuInfo.bots[n].generic.id\t\t\t= ID_BOTNAME0 + n;\n\t\taddBotsMenuInfo.bots[n].generic.x\t\t\t= 320 - 56;\n\t\taddBotsMenuInfo.bots[n].generic.y\t\t\t= y;\n\t\taddBotsMenuInfo.bots[n].generic.callback\t= UI_AddBotsMenu_BotEvent;\n\t\taddBotsMenuInfo.bots[n].string\t\t\t\t= addBotsMenuInfo.botnames[n];\n\t\taddBotsMenuInfo.bots[n].color\t\t\t\t= color_orange;\n\t\taddBotsMenuInfo.bots[n].style\t\t\t\t= UI_LEFT|UI_SMALLFONT;\n\t}\n\n\ty += 12;\n\taddBotsMenuInfo.skill.generic.type\t\t= MTYPE_SPINCONTROL;\n\taddBotsMenuInfo.skill.generic.flags\t\t= QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\taddBotsMenuInfo.skill.generic.x\t\t\t= 320;\n\taddBotsMenuInfo.skill.generic.y\t\t\t= y;\n\taddBotsMenuInfo.skill.generic.name\t\t= \"Skill:\";\n\taddBotsMenuInfo.skill.generic.id\t\t= ID_SKILL;\n\taddBotsMenuInfo.skill.itemnames\t\t\t= skillNames;\n\taddBotsMenuInfo.skill.curvalue\t\t\t= Com_Clamp( 0, 4, (int)trap_Cvar_VariableValue( \"g_spSkill\" ) - 1 );\n\n\ty += SMALLCHAR_HEIGHT;\n\taddBotsMenuInfo.team.generic.type\t\t= MTYPE_SPINCONTROL;\n\taddBotsMenuInfo.team.generic.flags\t\t= QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\taddBotsMenuInfo.team.generic.x\t\t\t= 320;\n\taddBotsMenuInfo.team.generic.y\t\t\t= y;\n\taddBotsMenuInfo.team.generic.name\t\t= \"Team: \";\n\taddBotsMenuInfo.team.generic.id\t\t\t= ID_TEAM;\n\tif( gametype >= GT_TEAM ) {\n\t\taddBotsMenuInfo.team.itemnames\t\t= teamNames2;\n\t}\n\telse {\n\t\taddBotsMenuInfo.team.itemnames\t\t= teamNames1;\n\t\taddBotsMenuInfo.team.generic.flags\t= QMF_GRAYED;\n\t}\n\n\taddBotsMenuInfo.go.generic.type\t\t\t= MTYPE_BITMAP;\n\taddBotsMenuInfo.go.generic.name\t\t\t= ART_FIGHT0;\n\taddBotsMenuInfo.go.generic.flags\t\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\taddBotsMenuInfo.go.generic.id\t\t\t= ID_GO;\n\taddBotsMenuInfo.go.generic.callback\t\t= UI_AddBotsMenu_FightEvent;\n\taddBotsMenuInfo.go.generic.x\t\t\t= 320+128-128;\n\taddBotsMenuInfo.go.generic.y\t\t\t= 256+128-64;\n\taddBotsMenuInfo.go.width  \t\t\t\t= 128;\n\taddBotsMenuInfo.go.height  \t\t\t\t= 64;\n\taddBotsMenuInfo.go.focuspic\t\t\t\t= ART_FIGHT1;\n\n\taddBotsMenuInfo.back.generic.type\t\t= MTYPE_BITMAP;\n\taddBotsMenuInfo.back.generic.name\t\t= ART_BACK0;\n\taddBotsMenuInfo.back.generic.flags\t\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\taddBotsMenuInfo.back.generic.id\t\t\t= ID_BACK;\n\taddBotsMenuInfo.back.generic.callback\t= UI_AddBotsMenu_BackEvent;\n\taddBotsMenuInfo.back.generic.x\t\t\t= 320-128;\n\taddBotsMenuInfo.back.generic.y\t\t\t= 256+128-64;\n\taddBotsMenuInfo.back.width\t\t\t\t= 128;\n\taddBotsMenuInfo.back.height\t\t\t\t= 64;\n\taddBotsMenuInfo.back.focuspic\t\t\t= ART_BACK1;\n\n\taddBotsMenuInfo.baseBotNum = 0;\n\taddBotsMenuInfo.selectedBotNum = 0;\n\taddBotsMenuInfo.bots[0].color = color_white;\n\n\tUI_AddBotsMenu_GetSortedBotNums();\n\tUI_AddBotsMenu_SetBotNames();\n\n\tMenu_AddItem( &addBotsMenuInfo.menu, &addBotsMenuInfo.arrows );\n\n\tMenu_AddItem( &addBotsMenuInfo.menu, &addBotsMenuInfo.up );\n\tMenu_AddItem( &addBotsMenuInfo.menu, &addBotsMenuInfo.down );\n\tfor( n = 0; n < count; n++ ) {\n\t\tMenu_AddItem( &addBotsMenuInfo.menu, &addBotsMenuInfo.bots[n] );\n\t}\n\tMenu_AddItem( &addBotsMenuInfo.menu, &addBotsMenuInfo.skill );\n\tMenu_AddItem( &addBotsMenuInfo.menu, &addBotsMenuInfo.team );\n\tMenu_AddItem( &addBotsMenuInfo.menu, &addBotsMenuInfo.go );\n\tMenu_AddItem( &addBotsMenuInfo.menu, &addBotsMenuInfo.back );\n}\n\n\n/*\n=================\nUI_AddBots_Cache\n=================\n*/\nvoid UI_AddBots_Cache( void ) {\n\ttrap_R_RegisterShaderNoMip( ART_BACK0 );\n\ttrap_R_RegisterShaderNoMip( ART_BACK1 );\n\ttrap_R_RegisterShaderNoMip( ART_FIGHT0 );\n\ttrap_R_RegisterShaderNoMip( ART_FIGHT1 );\n\ttrap_R_RegisterShaderNoMip( ART_BACKGROUND );\n\ttrap_R_RegisterShaderNoMip( ART_ARROWS );\n\ttrap_R_RegisterShaderNoMip( ART_ARROWUP );\n\ttrap_R_RegisterShaderNoMip( ART_ARROWDOWN );\n}\n\n\n/*\n=================\nUI_AddBotsMenu\n=================\n*/\nvoid UI_AddBotsMenu( void ) {\n\tUI_AddBotsMenu_Init();\n\tUI_PushMenu( &addBotsMenuInfo.menu );\n}\n"
  },
  {
    "path": "src/q3_ui/ui_atoms.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n/**********************************************************************\n\tUI_ATOMS.C\n\n\tUser interface building blocks and support functions.\n**********************************************************************/\n#include \"ui_local.h\"\n\nuiStatic_t\t\tuis;\nqboolean\t\tm_entersound;\t\t// after a frame, so caching won't disrupt the sound\n\n// these are here so the functions in q_shared.c can link\n#ifndef UI_HARD_LINKED\n\nvoid QDECL Com_Error( int level, const char *error, ... ) {\n\tva_list\t\targptr;\n\tchar\t\ttext[1024];\n\n\tva_start (argptr, error);\n\tvsprintf (text, error, argptr);\n\tva_end (argptr);\n\n\ttrap_Error( va(\"%s\", text) );\n}\n\nvoid QDECL Com_Printf( const char *msg, ... ) {\n\tva_list\t\targptr;\n\tchar\t\ttext[1024];\n\n\tva_start (argptr, msg);\n\tvsprintf (text, msg, argptr);\n\tva_end (argptr);\n\n\ttrap_Print( va(\"%s\", text) );\n}\n\n#endif\n\n/*\n=================\nUI_ClampCvar\n=================\n*/\nfloat UI_ClampCvar( float min, float max, float value )\n{\n\tif ( value < min ) return min;\n\tif ( value > max ) return max;\n\treturn value;\n}\n\n/*\n=================\nUI_StartDemoLoop\n=================\n*/\nvoid UI_StartDemoLoop( void ) {\n\ttrap_Cmd_ExecuteText( EXEC_APPEND, \"d1\\n\" );\n}\n\n/*\n=================\nUI_PushMenu\n=================\n*/\nvoid UI_PushMenu( menuframework_s *menu )\n{\n\tint\t\t\t\ti;\n\tmenucommon_s*\titem;\n\n\t// avoid stacking menus invoked by hotkeys\n\tfor (i=0 ; i<uis.menusp ; i++)\n\t{\n\t\tif (uis.stack[i] == menu)\n\t\t{\n\t\t\tuis.menusp = i;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (i == uis.menusp)\n\t{\n\t\tif (uis.menusp >= MAX_MENUDEPTH)\n\t\t\ttrap_Error(\"UI_PushMenu: menu stack overflow\");\n\n\t\tuis.stack[uis.menusp++] = menu;\n\t}\n\n\tuis.activemenu = menu;\n\n\t// default cursor position\n\tmenu->cursor      = 0;\n\tmenu->cursor_prev = 0;\n\n\tm_entersound = qtrue;\n\n\ttrap_Key_SetCatcher( KEYCATCH_UI );\n\n\t// force first available item to have focus\n\tfor (i=0; i<menu->nitems; i++)\n\t{\n\t\titem = (menucommon_s *)menu->items[i];\n\t\tif (!(item->flags & (QMF_GRAYED|QMF_MOUSEONLY|QMF_INACTIVE)))\n\t\t{\n\t\t\tmenu->cursor_prev = -1;\n\t\t\tMenu_SetCursor( menu, i );\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tuis.firstdraw = qtrue;\n}\n\n/*\n=================\nUI_PopMenu\n=================\n*/\nvoid UI_PopMenu (void)\n{\n\ttrap_S_StartLocalSound( menu_out_sound, CHAN_LOCAL_SOUND );\n\n\tuis.menusp--;\n\n\tif (uis.menusp < 0)\n\t\ttrap_Error (\"UI_PopMenu: menu stack underflow\");\n\n\tif (uis.menusp) {\n\t\tuis.activemenu = uis.stack[uis.menusp-1];\n\t\tuis.firstdraw = qtrue;\n\t}\n\telse {\n\t\tUI_ForceMenuOff ();\n\t}\n}\n\nvoid UI_ForceMenuOff (void)\n{\n\tuis.menusp     = 0;\n\tuis.activemenu = NULL;\n\n\ttrap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );\n\ttrap_Key_ClearStates();\n\ttrap_Cvar_Set( \"cl_paused\", \"0\" );\n}\n\n/*\n=================\nUI_LerpColor\n=================\n*/\nvoid UI_LerpColor(vec4_t a, vec4_t b, vec4_t c, float t)\n{\n\tint i;\n\n\t// lerp and clamp each component\n\tfor (i=0; i<4; i++)\n\t{\n\t\tc[i] = a[i] + t*(b[i]-a[i]);\n\t\tif (c[i] < 0)\n\t\t\tc[i] = 0;\n\t\telse if (c[i] > 1.0)\n\t\t\tc[i] = 1.0;\n\t}\n}\n\n/*\n=================\nUI_DrawProportionalString2\n=================\n*/\nstatic int\tpropMap[128][3] = {\n{0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},\n{0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},\n\n{0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},\n{0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},\n\n{0, 0, PROP_SPACE_WIDTH},\t\t// SPACE\n{11, 122, 7},\t// !\n{154, 181, 14},\t// \"\n{55, 122, 17},\t// #\n{79, 122, 18},\t// $\n{101, 122, 23},\t// %\n{153, 122, 18},\t// &\n{9, 93, 7},\t\t// '\n{207, 122, 8},\t// (\n{230, 122, 9},\t// )\n{177, 122, 18},\t// *\n{30, 152, 18},\t// +\n{85, 181, 7},\t// ,\n{34, 93, 11},\t// -\n{110, 181, 6},\t// .\n{130, 152, 14},\t// /\n\n{22, 64, 17},\t// 0\n{41, 64, 12},\t// 1\n{58, 64, 17},\t// 2\n{78, 64, 18},\t// 3\n{98, 64, 19},\t// 4\n{120, 64, 18},\t// 5\n{141, 64, 18},\t// 6\n{204, 64, 16},\t// 7\n{162, 64, 17},\t// 8\n{182, 64, 18},\t// 9\n{59, 181, 7},\t// :\n{35,181, 7},\t// ;\n{203, 152, 14},\t// <\n{56, 93, 14},\t// =\n{228, 152, 14},\t// >\n{177, 181, 18},\t// ?\n\n{28, 122, 22},\t// @\n{5, 4, 18},\t\t// A\n{27, 4, 18},\t// B\n{48, 4, 18},\t// C\n{69, 4, 17},\t// D\n{90, 4, 13},\t// E\n{106, 4, 13},\t// F\n{121, 4, 18},\t// G\n{143, 4, 17},\t// H\n{164, 4, 8},\t// I\n{175, 4, 16},\t// J\n{195, 4, 18},\t// K\n{216, 4, 12},\t// L\n{230, 4, 23},\t// M\n{6, 34, 18},\t// N\n{27, 34, 18},\t// O\n\n{48, 34, 18},\t// P\n{68, 34, 18},\t// Q\n{90, 34, 17},\t// R\n{110, 34, 18},\t// S\n{130, 34, 14},\t// T\n{146, 34, 18},\t// U\n{166, 34, 19},\t// V\n{185, 34, 29},\t// W\n{215, 34, 18},\t// X\n{234, 34, 18},\t// Y\n{5, 64, 14},\t// Z\n{60, 152, 7},\t// [\n{106, 151, 13},\t// '\\'\n{83, 152, 7},\t// ]\n{128, 122, 17},\t// ^\n{4, 152, 21},\t// _\n\n{134, 181, 5},\t// '\n{5, 4, 18},\t\t// A\n{27, 4, 18},\t// B\n{48, 4, 18},\t// C\n{69, 4, 17},\t// D\n{90, 4, 13},\t// E\n{106, 4, 13},\t// F\n{121, 4, 18},\t// G\n{143, 4, 17},\t// H\n{164, 4, 8},\t// I\n{175, 4, 16},\t// J\n{195, 4, 18},\t// K\n{216, 4, 12},\t// L\n{230, 4, 23},\t// M\n{6, 34, 18},\t// N\n{27, 34, 18},\t// O\n\n{48, 34, 18},\t// P\n{68, 34, 18},\t// Q\n{90, 34, 17},\t// R\n{110, 34, 18},\t// S\n{130, 34, 14},\t// T\n{146, 34, 18},\t// U\n{166, 34, 19},\t// V\n{185, 34, 29},\t// W\n{215, 34, 18},\t// X\n{234, 34, 18},\t// Y\n{5, 64, 14},\t// Z\n{153, 152, 13},\t// {\n{11, 181, 5},\t// |\n{180, 152, 13},\t// }\n{79, 93, 17},\t// ~\n{0, 0, -1}\t\t// DEL\n};\n\nstatic int propMapB[26][3] = {\n{11, 12, 33},\n{49, 12, 31},\n{85, 12, 31},\n{120, 12, 30},\n{156, 12, 21},\n{183, 12, 21},\n{207, 12, 32},\n\n{13, 55, 30},\n{49, 55, 13},\n{66, 55, 29},\n{101, 55, 31},\n{135, 55, 21},\n{158, 55, 40},\n{204, 55, 32},\n\n{12, 97, 31},\n{48, 97, 31},\n{82, 97, 30},\n{118, 97, 30},\n{153, 97, 30},\n{185, 97, 25},\n{213, 97, 30},\n\n{11, 139, 32},\n{42, 139, 51},\n{93, 139, 32},\n{126, 139, 31},\n{158, 139, 25},\n};\n\n#define PROPB_GAP_WIDTH\t\t4\n#define PROPB_SPACE_WIDTH\t12\n#define PROPB_HEIGHT\t\t36\n\n// bk001205 - code below duplicated in cgame/cg_drawtools.c\n// bk001205 - FIXME: does this belong in ui_shared.c?\n/*\n=================\nUI_DrawBannerString\n=================\n*/\nstatic void UI_DrawBannerString2( int x, int y, const char* str, vec4_t color )\n{\n\tconst char* s;\n\tunsigned char\tch; // bk001204 - unsigned\n\tfloat\tax;\n\tfloat\tay;\n\tfloat\taw;\n\tfloat\tah;\n\tfloat\tfrow;\n\tfloat\tfcol;\n\tfloat\tfwidth;\n\tfloat\tfheight;\n\n\t// draw the colored text\n\ttrap_R_SetColor( color );\n\t\n\tax = x * uis.scale + uis.bias;\n\tay = y * uis.scale;\n\n\ts = str;\n\twhile ( *s )\n\t{\n\t\tch = *s & 127;\n\t\tif ( ch == ' ' ) {\n\t\t\tax += ((float)PROPB_SPACE_WIDTH + (float)PROPB_GAP_WIDTH)* uis.scale;\n\t\t}\n\t\telse if ( ch >= 'A' && ch <= 'Z' ) {\n\t\t\tch -= 'A';\n\t\t\tfcol = (float)propMapB[ch][0] / 256.0f;\n\t\t\tfrow = (float)propMapB[ch][1] / 256.0f;\n\t\t\tfwidth = (float)propMapB[ch][2] / 256.0f;\n\t\t\tfheight = (float)PROPB_HEIGHT / 256.0f;\n\t\t\taw = (float)propMapB[ch][2] * uis.scale;\n\t\t\tah = (float)PROPB_HEIGHT * uis.scale;\n\t\t\ttrap_R_DrawStretchPic( ax, ay, aw, ah, fcol, frow, fcol+fwidth, frow+fheight, uis.charsetPropB );\n\t\t\tax += (aw + (float)PROPB_GAP_WIDTH * uis.scale);\n\t\t}\n\t\ts++;\n\t}\n\n\ttrap_R_SetColor( NULL );\n}\n\nvoid UI_DrawBannerString( int x, int y, const char* str, int style, vec4_t color ) {\n\tconst char *\ts;\n\tint\t\t\t\tch;\n\tint\t\t\t\twidth;\n\tvec4_t\t\t\tdrawcolor;\n\n\t// find the width of the drawn text\n\ts = str;\n\twidth = 0;\n\twhile ( *s ) {\n\t\tch = *s;\n\t\tif ( ch == ' ' ) {\n\t\t\twidth += PROPB_SPACE_WIDTH;\n\t\t}\n\t\telse if ( ch >= 'A' && ch <= 'Z' ) {\n\t\t\twidth += propMapB[ch - 'A'][2] + PROPB_GAP_WIDTH;\n\t\t}\n\t\ts++;\n\t}\n\twidth -= PROPB_GAP_WIDTH;\n\n\tswitch( style & UI_FORMATMASK ) {\n\t\tcase UI_CENTER:\n\t\t\tx -= width / 2;\n\t\t\tbreak;\n\n\t\tcase UI_RIGHT:\n\t\t\tx -= width;\n\t\t\tbreak;\n\n\t\tcase UI_LEFT:\n\t\tdefault:\n\t\t\tbreak;\n\t}\n\n\tif ( style & UI_DROPSHADOW ) {\n\t\tdrawcolor[0] = drawcolor[1] = drawcolor[2] = 0;\n\t\tdrawcolor[3] = color[3];\n\t\tUI_DrawBannerString2( x+2, y+2, str, drawcolor );\n\t}\n\n\tUI_DrawBannerString2( x, y, str, color );\n}\n\n\nint UI_ProportionalStringWidth( const char* str ) {\n\tconst char *\ts;\n\tint\t\t\t\tch;\n\tint\t\t\t\tcharWidth;\n\tint\t\t\t\twidth;\n\n\ts = str;\n\twidth = 0;\n\twhile ( *s ) {\n\t\tch = *s & 127;\n\t\tcharWidth = propMap[ch][2];\n\t\tif ( charWidth != -1 ) {\n\t\t\twidth += charWidth;\n\t\t\twidth += PROP_GAP_WIDTH;\n\t\t}\n\t\ts++;\n\t}\n\n\twidth -= PROP_GAP_WIDTH;\n\treturn width;\n}\n\nstatic void UI_DrawProportionalString2( int x, int y, const char* str, vec4_t color, float sizeScale, qhandle_t charset )\n{\n\tconst char* s;\n\tunsigned char\tch; // bk001204 - unsigned\n\tfloat\tax;\n\tfloat\tay;\n\tfloat\taw = 0; // bk001204 - init\n\tfloat\tah;\n\tfloat\tfrow;\n\tfloat\tfcol;\n\tfloat\tfwidth;\n\tfloat\tfheight;\n\n\t// draw the colored text\n\ttrap_R_SetColor( color );\n\t\n\tax = x * uis.scale + uis.bias;\n\tay = y * uis.scale;\n\n\ts = str;\n\twhile ( *s )\n\t{\n\t\tch = *s & 127;\n\t\tif ( ch == ' ' ) {\n\t\t\taw = (float)PROP_SPACE_WIDTH * uis.scale * sizeScale;\n\t\t}\n\t\telse if ( propMap[ch][2] != -1 ) {\n\t\t\tfcol = (float)propMap[ch][0] / 256.0f;\n\t\t\tfrow = (float)propMap[ch][1] / 256.0f;\n\t\t\tfwidth = (float)propMap[ch][2] / 256.0f;\n\t\t\tfheight = (float)PROP_HEIGHT / 256.0f;\n\t\t\taw = (float)propMap[ch][2] * uis.scale * sizeScale;\n\t\t\tah = (float)PROP_HEIGHT * uis.scale * sizeScale;\n\t\t\ttrap_R_DrawStretchPic( ax, ay, aw, ah, fcol, frow, fcol+fwidth, frow+fheight, charset );\n\t\t}\n\n\t\tax += (aw + (float)PROP_GAP_WIDTH * uis.scale * sizeScale);\n\t\ts++;\n\t}\n\n\ttrap_R_SetColor( NULL );\n}\n\n/*\n=================\nUI_ProportionalSizeScale\n=================\n*/\nfloat UI_ProportionalSizeScale( int style ) {\n\tif(  style & UI_SMALLFONT ) {\n\t\treturn PROP_SMALL_SIZE_SCALE;\n\t}\n\n\treturn 1.00;\n}\n\n\n/*\n=================\nUI_DrawProportionalString\n=================\n*/\nvoid UI_DrawProportionalString( int x, int y, const char* str, int style, vec4_t color ) {\n\tvec4_t\tdrawcolor;\n\tint\t\twidth;\n\tfloat\tsizeScale;\n\n\tsizeScale = UI_ProportionalSizeScale( style );\n\n\tswitch( style & UI_FORMATMASK ) {\n\t\tcase UI_CENTER:\n\t\t\twidth = UI_ProportionalStringWidth( str ) * sizeScale;\n\t\t\tx -= width / 2;\n\t\t\tbreak;\n\n\t\tcase UI_RIGHT:\n\t\t\twidth = UI_ProportionalStringWidth( str ) * sizeScale;\n\t\t\tx -= width;\n\t\t\tbreak;\n\n\t\tcase UI_LEFT:\n\t\tdefault:\n\t\t\tbreak;\n\t}\n\n\tif ( style & UI_DROPSHADOW ) {\n\t\tdrawcolor[0] = drawcolor[1] = drawcolor[2] = 0;\n\t\tdrawcolor[3] = color[3];\n\t\tUI_DrawProportionalString2( x+2, y+2, str, drawcolor, sizeScale, uis.charsetProp );\n\t}\n\n\tif ( style & UI_INVERSE ) {\n\t\tdrawcolor[0] = color[0] * 0.7;\n\t\tdrawcolor[1] = color[1] * 0.7;\n\t\tdrawcolor[2] = color[2] * 0.7;\n\t\tdrawcolor[3] = color[3];\n\t\tUI_DrawProportionalString2( x, y, str, drawcolor, sizeScale, uis.charsetProp );\n\t\treturn;\n\t}\n\n\tif ( style & UI_PULSE ) {\n\t\tdrawcolor[0] = color[0] * 0.7;\n\t\tdrawcolor[1] = color[1] * 0.7;\n\t\tdrawcolor[2] = color[2] * 0.7;\n\t\tdrawcolor[3] = color[3];\n\t\tUI_DrawProportionalString2( x, y, str, color, sizeScale, uis.charsetProp );\n\n\t\tdrawcolor[0] = color[0];\n\t\tdrawcolor[1] = color[1];\n\t\tdrawcolor[2] = color[2];\n\t\tdrawcolor[3] = 0.5 + 0.5 * sin( uis.realtime / PULSE_DIVISOR );\n\t\tUI_DrawProportionalString2( x, y, str, drawcolor, sizeScale, uis.charsetPropGlow );\n\t\treturn;\n\t}\n\n\tUI_DrawProportionalString2( x, y, str, color, sizeScale, uis.charsetProp );\n}\n\n/*\n=================\nUI_DrawProportionalString_Wrapped\n=================\n*/\nvoid UI_DrawProportionalString_AutoWrapped( int x, int y, int xmax, int ystep, const char* str, int style, vec4_t color ) {\n\tint width;\n\tchar *s1,*s2,*s3;\n\tchar c_bcp;\n\tchar buf[1024];\n\tfloat   sizeScale;\n\n\tif (!str || str[0]=='\\0')\n\t\treturn;\n\t\n\tsizeScale = UI_ProportionalSizeScale( style );\n\t\n\tQ_strncpyz(buf, str, sizeof(buf));\n\ts1 = s2 = s3 = buf;\n\n\twhile (1) {\n\t\tdo {\n\t\t\ts3++;\n\t\t} while (*s3!=' ' && *s3!='\\0');\n\t\tc_bcp = *s3;\n\t\t*s3 = '\\0';\n\t\twidth = UI_ProportionalStringWidth(s1) * sizeScale;\n\t\t*s3 = c_bcp;\n\t\tif (width > xmax) {\n\t\t\tif (s1==s2)\n\t\t\t{\n\t\t\t\t// fuck, don't have a clean cut, we'll overflow\n\t\t\t\ts2 = s3;\n\t\t\t}\n\t\t\t*s2 = '\\0';\n\t\t\tUI_DrawProportionalString(x, y, s1, style, color);\n\t\t\ty += ystep;\n\t\t\tif (c_bcp == '\\0')\n      {\n        // that was the last word\n        // we could start a new loop, but that wouldn't be much use\n        // even if the word is too long, we would overflow it (see above)\n        // so just print it now if needed\n        s2++;\n        if (*s2 != '\\0') // if we are printing an overflowing line we have s2 == s3\n          UI_DrawProportionalString(x, y, s2, style, color);\n\t\t\t\tbreak; \n      }\n\t\t\ts2++;\n\t\t\ts1 = s2;\n\t\t\ts3 = s2;\n\t\t}\n\t\telse\n\t\t{\n\t\t\ts2 = s3;\n\t\t\tif (c_bcp == '\\0') // we reached the end\n\t\t\t{\n\t\t\t\tUI_DrawProportionalString(x, y, s1, style, color);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n}\n\n/*\n=================\nUI_DrawString2\n=================\n*/\nstatic void UI_DrawString2( int x, int y, const char* str, vec4_t color, int charw, int charh )\n{\n\tconst char* s;\n\tchar\tch;\n\tint forceColor = qfalse; //APSFIXME;\n\tvec4_t\ttempcolor;\n\tfloat\tax;\n\tfloat\tay;\n\tfloat\taw;\n\tfloat\tah;\n\tfloat\tfrow;\n\tfloat\tfcol;\n\n\tif (y < -charh)\n\t\t// offscreen\n\t\treturn;\n\n\t// draw the colored text\n\ttrap_R_SetColor( color );\n\t\n\tax = x * uis.scale + uis.bias;\n\tay = y * uis.scale;\n\taw = charw * uis.scale;\n\tah = charh * uis.scale;\n\n\ts = str;\n\twhile ( *s )\n\t{\n\t\tif ( Q_IsColorString( s ) )\n\t\t{\n\t\t\tif ( !forceColor )\n\t\t\t{\n\t\t\t\tmemcpy( tempcolor, g_color_table[ColorIndex(s[1])], sizeof( tempcolor ) );\n\t\t\t\ttempcolor[3] = color[3];\n\t\t\t\ttrap_R_SetColor( tempcolor );\n\t\t\t}\n\t\t\ts += 2;\n\t\t\tcontinue;\n\t\t}\n\n\t\tch = *s & 255;\n\t\tif (ch != ' ')\n\t\t{\n\t\t\tfrow = (ch>>4)*0.0625;\n\t\t\tfcol = (ch&15)*0.0625;\n\t\t\ttrap_R_DrawStretchPic( ax, ay, aw, ah, fcol, frow, fcol + 0.0625, frow + 0.0625, uis.charset );\n\t\t}\n\n\t\tax += aw;\n\t\ts++;\n\t}\n\n\ttrap_R_SetColor( NULL );\n}\n\n/*\n=================\nUI_DrawString\n=================\n*/\nvoid UI_DrawString( int x, int y, const char* str, int style, vec4_t color )\n{\n\tint\t\tlen;\n\tint\t\tcharw;\n\tint\t\tcharh;\n\tvec4_t\tnewcolor;\n\tvec4_t\tlowlight;\n\tfloat\t*drawcolor;\n\tvec4_t\tdropcolor;\n\n\tif( !str ) {\n\t\treturn;\n\t}\n\n\tif ((style & UI_BLINK) && ((uis.realtime/BLINK_DIVISOR) & 1))\n\t\treturn;\n\n\tif (style & UI_SMALLFONT)\n\t{\n\t\tcharw =\tSMALLCHAR_WIDTH;\n\t\tcharh =\tSMALLCHAR_HEIGHT;\n\t}\n\telse if (style & UI_GIANTFONT)\n\t{\n\t\tcharw =\tGIANTCHAR_WIDTH;\n\t\tcharh =\tGIANTCHAR_HEIGHT;\n\t}\n\telse\n\t{\n\t\tcharw =\tBIGCHAR_WIDTH;\n\t\tcharh =\tBIGCHAR_HEIGHT;\n\t}\n\n\tif (style & UI_PULSE)\n\t{\n\t\tlowlight[0] = 0.8*color[0]; \n\t\tlowlight[1] = 0.8*color[1];\n\t\tlowlight[2] = 0.8*color[2];\n\t\tlowlight[3] = 0.8*color[3];\n\t\tUI_LerpColor(color,lowlight,newcolor,0.5+0.5*sin(uis.realtime/PULSE_DIVISOR));\n\t\tdrawcolor = newcolor;\n\t}\t\n\telse\n\t\tdrawcolor = color;\n\n\tswitch (style & UI_FORMATMASK)\n\t{\n\t\tcase UI_CENTER:\n\t\t\t// center justify at x\n\t\t\tlen = (int)strlen(str);\n\t\t\tx   = x - len*charw/2;\n\t\t\tbreak;\n\n\t\tcase UI_RIGHT:\n\t\t\t// right justify at x\n\t\t\tlen = (int)strlen(str);\n\t\t\tx   = x - len*charw;\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\t// left justify at x\n\t\t\tbreak;\n\t}\n\n\tif ( style & UI_DROPSHADOW )\n\t{\n\t\tdropcolor[0] = dropcolor[1] = dropcolor[2] = 0;\n\t\tdropcolor[3] = drawcolor[3];\n\t\tUI_DrawString2(x+2,y+2,str,dropcolor,charw,charh);\n\t}\n\n\tUI_DrawString2(x,y,str,drawcolor,charw,charh);\n}\n\n/*\n=================\nUI_DrawChar\n=================\n*/\nvoid UI_DrawChar( int x, int y, int ch, int style, vec4_t color )\n{\n\tchar\tbuff[2];\n\n\tbuff[0] = ch;\n\tbuff[1] = '\\0';\n\n\tUI_DrawString( x, y, buff, style, color );\n}\n\nqboolean UI_IsFullscreen( void ) {\n\tif ( uis.activemenu && ( trap_Key_GetCatcher() & KEYCATCH_UI ) ) {\n\t\treturn uis.activemenu->fullscreen;\n\t}\n\n\treturn qfalse;\n}\n\nstatic void NeedCDAction( qboolean result ) {\n\tif ( !result ) {\n\t\ttrap_Cmd_ExecuteText( EXEC_APPEND, \"quit\\n\" );\n\t}\n}\n\nstatic void NeedCDKeyAction( qboolean result ) {\n\tif ( !result ) {\n\t\ttrap_Cmd_ExecuteText( EXEC_APPEND, \"quit\\n\" );\n\t}\n}\n\nvoid UI_SetActiveMenu( uiMenuCommand_t menu ) {\n\t// this should be the ONLY way the menu system is brought up\n\t// enusure minumum menu data is cached\n\tMenu_Cache();\n\n\tswitch ( menu ) {\n\tcase UIMENU_NONE:\n\t\tUI_ForceMenuOff();\n\t\treturn;\n\tcase UIMENU_MAIN:\n\t\tUI_MainMenu();\n\t\treturn;\n\tcase UIMENU_NEED_CD:\n\t\tUI_ConfirmMenu( \"Insert the CD\", (voidfunc_f)NULL, NeedCDAction );\n\t\treturn;\n\tcase UIMENU_BAD_CD_KEY:\n\t\tUI_ConfirmMenu( \"Bad CD Key\", (voidfunc_f)NULL, NeedCDKeyAction );\n\t\treturn;\n\tcase UIMENU_INGAME:\n\t\t/*\n\t\t//GRank\n\t\tUI_RankingsMenu();\n\t\treturn;\n\t\t*/\n\t\ttrap_Cvar_Set( \"cl_paused\", \"1\" );\n\t\tUI_InGameMenu();\n\t\treturn;\n\t\t\n\t// bk001204\n\tcase UIMENU_TEAM:\n\tcase UIMENU_POSTGAME:\n\tdefault:\n#ifndef NDEBUG\n\t  Com_Printf(\"UI_SetActiveMenu: bad enum %d\\n\", menu );\n#endif\n\t  break;\n\t}\n}\n\n/*\n=================\nUI_KeyEvent\n=================\n*/\nvoid UI_KeyEvent( int key, int down ) {\n\tsfxHandle_t\t\ts;\n\n\tif (!uis.activemenu) {\n\t\treturn;\n\t}\n\n\tif (!down) {\n\t\treturn;\n\t}\n\n\tif (uis.activemenu->key)\n\t\ts = uis.activemenu->key( key );\n\telse\n\t\ts = Menu_DefaultKey( uis.activemenu, key );\n\n\tif ((s > 0) && (s != menu_null_sound))\n\t\ttrap_S_StartLocalSound( s, CHAN_LOCAL_SOUND );\n}\n\n/*\n=================\nUI_MouseEvent\n=================\n*/\nvoid UI_MouseEvent( int dx, int dy )\n{\n\tint\t\t\t\ti;\n\tmenucommon_s*\tm;\n\n\tif (!uis.activemenu)\n\t\treturn;\n\n\t// update mouse screen position\n\tuis.cursorx += dx;\n\tif (uis.cursorx < 0)\n\t\tuis.cursorx = 0;\n\telse if (uis.cursorx > SCREEN_WIDTH)\n\t\tuis.cursorx = SCREEN_WIDTH;\n\n\tuis.cursory += dy;\n\tif (uis.cursory < 0)\n\t\tuis.cursory = 0;\n\telse if (uis.cursory > SCREEN_HEIGHT)\n\t\tuis.cursory = SCREEN_HEIGHT;\n\n\t// region test the active menu items\n\tfor (i=0; i<uis.activemenu->nitems; i++)\n\t{\n\t\tm = (menucommon_s*)uis.activemenu->items[i];\n\n\t\tif (m->flags & (QMF_GRAYED|QMF_INACTIVE))\n\t\t\tcontinue;\n\n\t\tif ((uis.cursorx < m->left) ||\n\t\t\t(uis.cursorx > m->right) ||\n\t\t\t(uis.cursory < m->top) ||\n\t\t\t(uis.cursory > m->bottom))\n\t\t{\n\t\t\t// cursor out of item bounds\n\t\t\tcontinue;\n\t\t}\n\n\t\t// set focus to item at cursor\n\t\tif (uis.activemenu->cursor != i)\n\t\t{\n\t\t\tMenu_SetCursor( uis.activemenu, i );\n\t\t\t((menucommon_s*)(uis.activemenu->items[uis.activemenu->cursor_prev]))->flags &= ~QMF_HASMOUSEFOCUS;\n\n\t\t\tif ( !(((menucommon_s*)(uis.activemenu->items[uis.activemenu->cursor]))->flags & QMF_SILENT ) ) {\n\t\t\t\ttrap_S_StartLocalSound( menu_move_sound, CHAN_LOCAL_SOUND );\n\t\t\t}\n\t\t}\n\n\t\t((menucommon_s*)(uis.activemenu->items[uis.activemenu->cursor]))->flags |= QMF_HASMOUSEFOCUS;\n\t\treturn;\n\t}  \n\n\tif (uis.activemenu->nitems > 0) {\n\t\t// out of any region\n\t\t((menucommon_s*)(uis.activemenu->items[uis.activemenu->cursor]))->flags &= ~QMF_HASMOUSEFOCUS;\n\t}\n}\n\nchar *UI_Argv( int arg ) {\n\tstatic char\tbuffer[MAX_STRING_CHARS];\n\n\ttrap_Argv( arg, buffer, sizeof( buffer ) );\n\n\treturn buffer;\n}\n\n\nchar *UI_Cvar_VariableString( const char *var_name ) {\n\tstatic char\tbuffer[MAX_STRING_CHARS];\n\n\ttrap_Cvar_VariableStringBuffer( var_name, buffer, sizeof( buffer ) );\n\n\treturn buffer;\n}\n\n\n/*\n=================\nUI_Cache\n=================\n*/\nvoid UI_Cache_f( void ) {\n\tMainMenu_Cache();\n\tInGame_Cache();\n\tConfirmMenu_Cache();\n\tPlayerModel_Cache();\n\tPlayerSettings_Cache();\n\tControls_Cache();\n\tDemos_Cache();\n\tUI_CinematicsMenu_Cache();\n\tPreferences_Cache();\n\tServerInfo_Cache();\n\tSpecifyServer_Cache();\n\tArenaServers_Cache();\n\tStartServer_Cache();\n\tServerOptions_Cache();\n\tDriverInfo_Cache();\n\tGraphicsOptions_Cache();\n\tUI_DisplayOptionsMenu_Cache();\n\tUI_SoundOptionsMenu_Cache();\n\tUI_NetworkOptionsMenu_Cache();\n\tUI_SPLevelMenu_Cache();\n\tUI_SPSkillMenu_Cache();\n\tUI_SPPostgameMenu_Cache();\n\tTeamMain_Cache();\n\tUI_AddBots_Cache();\n\tUI_RemoveBots_Cache();\n\tUI_SetupMenu_Cache();\n//\tUI_LoadConfig_Cache();\n//\tUI_SaveConfigMenu_Cache();\n\tUI_BotSelectMenu_Cache();\n\tUI_CDKeyMenu_Cache();\n\tUI_ModsMenu_Cache();\n\n}\n\n\n/*\n=================\nUI_ConsoleCommand\n=================\n*/\nqboolean UI_ConsoleCommand( int realTime ) {\n\tchar\t*cmd;\n\n\tcmd = UI_Argv( 0 );\n\n\t// ensure minimum menu data is available\n\tMenu_Cache();\n\n\tif ( Q_stricmp (cmd, \"levelselect\") == 0 ) {\n\t\tUI_SPLevelMenu_f();\n\t\treturn qtrue;\n\t}\n\n\tif ( Q_stricmp (cmd, \"postgame\") == 0 ) {\n\t\tUI_SPPostgameMenu_f();\n\t\treturn qtrue;\n\t}\n\n\tif ( Q_stricmp (cmd, \"ui_cache\") == 0 ) {\n\t\tUI_Cache_f();\n\t\treturn qtrue;\n\t}\n\n\tif ( Q_stricmp (cmd, \"ui_cinematics\") == 0 ) {\n\t\tUI_CinematicsMenu_f();\n\t\treturn qtrue;\n\t}\n\n\tif ( Q_stricmp (cmd, \"ui_teamOrders\") == 0 ) {\n\t\tUI_TeamOrdersMenu_f();\n\t\treturn qtrue;\n\t}\n\n\tif ( Q_stricmp (cmd, \"iamacheater\") == 0 ) {\n\t\tUI_SPUnlock_f();\n\t\treturn qtrue;\n\t}\n\n\tif ( Q_stricmp (cmd, \"iamamonkey\") == 0 ) {\n\t\tUI_SPUnlockMedals_f();\n\t\treturn qtrue;\n\t}\n\n\tif ( Q_stricmp (cmd, \"ui_cdkey\") == 0 ) {\n\t\tUI_CDKeyMenu_f();\n\t\treturn qtrue;\n\t}\n\n\treturn qfalse;\n}\n\n/*\n=================\nUI_Shutdown\n=================\n*/\nvoid UI_Shutdown( void ) {\n}\n\n/*\n=================\nUI_Init\n=================\n*/\nvoid UI_Init( void ) {\n\tUI_RegisterCvars();\n\n\tUI_InitGameinfo();\n\n\t// cache redundant calulations\n\ttrap_GetGlconfig( &uis.glconfig );\n\n\t// for 640x480 virtualized screen\n\tuis.scale = uis.glconfig.vidHeight * (1.0/480.0);\n\tif ( uis.glconfig.vidWidth * 480 > uis.glconfig.vidHeight * 640 ) {\n\t\t// wide screen\n\t\tuis.bias = 0.5 * ( uis.glconfig.vidWidth - ( uis.glconfig.vidHeight * (640.0/480.0) ) );\n\t}\n\telse {\n\t\t// no wide screen\n\t\tuis.bias = 0;\n\t}\n\n\t// initialize the menu system\n\tMenu_Cache();\n\n\tuis.activemenu = NULL;\n\tuis.menusp     = 0;\n}\n\n/*\n================\nUI_AdjustFrom640\n\nAdjusted for resolution and screen aspect ratio\n================\n*/\nvoid UI_AdjustFrom640( float *x, float *y, float *w, float *h ) {\n\t// expect valid pointers\n\t*x = *x * uis.scale + uis.bias;\n\t*y *= uis.scale;\n\t*w *= uis.scale;\n\t*h *= uis.scale;\n}\n\nvoid UI_DrawNamedPic( float x, float y, float width, float height, const char *picname ) {\n\tqhandle_t\thShader;\n\n\thShader = trap_R_RegisterShaderNoMip( picname );\n\tUI_AdjustFrom640( &x, &y, &width, &height );\n\ttrap_R_DrawStretchPic( x, y, width, height, 0, 0, 1, 1, hShader );\n}\n\nvoid UI_DrawHandlePic( float x, float y, float w, float h, qhandle_t hShader ) {\n\tfloat\ts0;\n\tfloat\ts1;\n\tfloat\tt0;\n\tfloat\tt1;\n\n\tif( w < 0 ) {\t// flip about vertical\n\t\tw  = -w;\n\t\ts0 = 1;\n\t\ts1 = 0;\n\t}\n\telse {\n\t\ts0 = 0;\n\t\ts1 = 1;\n\t}\n\n\tif( h < 0 ) {\t// flip about horizontal\n\t\th  = -h;\n\t\tt0 = 1;\n\t\tt1 = 0;\n\t}\n\telse {\n\t\tt0 = 0;\n\t\tt1 = 1;\n\t}\n\t\n\tUI_AdjustFrom640( &x, &y, &w, &h );\n\ttrap_R_DrawStretchPic( x, y, w, h, s0, t0, s1, t1, hShader );\n}\n\n/*\n================\nUI_FillRect\n\nCoordinates are 640*480 virtual values\n=================\n*/\nvoid UI_FillRect( float x, float y, float width, float height, const float *color ) {\n\ttrap_R_SetColor( color );\n\n\tUI_AdjustFrom640( &x, &y, &width, &height );\n\ttrap_R_DrawStretchPic( x, y, width, height, 0, 0, 0, 0, uis.whiteShader );\n\n\ttrap_R_SetColor( NULL );\n}\n\n/*\n================\nUI_DrawRect\n\nCoordinates are 640*480 virtual values\n=================\n*/\nvoid UI_DrawRect( float x, float y, float width, float height, const float *color ) {\n\ttrap_R_SetColor( color );\n\n\tUI_AdjustFrom640( &x, &y, &width, &height );\n\n\ttrap_R_DrawStretchPic( x, y, width, 1, 0, 0, 0, 0, uis.whiteShader );\n\ttrap_R_DrawStretchPic( x, y, 1, height, 0, 0, 0, 0, uis.whiteShader );\n\ttrap_R_DrawStretchPic( x, y + height - 1, width, 1, 0, 0, 0, 0, uis.whiteShader );\n\ttrap_R_DrawStretchPic( x + width - 1, y, 1, height, 0, 0, 0, 0, uis.whiteShader );\n\n\ttrap_R_SetColor( NULL );\n}\n\nvoid UI_SetColor( const float *rgba ) {\n\ttrap_R_SetColor( rgba );\n}\n\nvoid UI_UpdateScreen( void ) {\n\ttrap_UpdateScreen();\n}\n\n/*\n=================\nUI_Refresh\n=================\n*/\nvoid UI_Refresh( int realtime )\n{\n\tuis.frametime = realtime - uis.realtime;\n\tuis.realtime  = realtime;\n\n\tif ( !( trap_Key_GetCatcher() & KEYCATCH_UI ) ) {\n\t\treturn;\n\t}\n\n\tUI_UpdateCvars();\n\n\tif ( uis.activemenu )\n\t{\n\t\tif (uis.activemenu->fullscreen)\n\t\t{\n\t\t\t// draw the background\n\t\t\tif( uis.activemenu->showlogo ) {\n\t\t\t\tUI_DrawHandlePic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, uis.menuBackShader );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tUI_DrawHandlePic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, uis.menuBackNoLogoShader );\n\t\t\t}\n\t\t}\n\n\t\tif (uis.activemenu->draw)\n\t\t\tuis.activemenu->draw();\n\t\telse\n\t\t\tMenu_Draw( uis.activemenu );\n\n\t\tif( uis.firstdraw ) {\n\t\t\tUI_MouseEvent( 0, 0 );\n\t\t\tuis.firstdraw = qfalse;\n\t\t}\n\t}\n\n\t// draw cursor\n\tUI_SetColor( NULL );\n\tUI_DrawHandlePic( uis.cursorx-16, uis.cursory-16, 32, 32, uis.cursor);\n\n#ifndef NDEBUG\n\tif (uis.debug)\n\t{\n\t\t// cursor coordinates\n\t\tUI_DrawString( 0, 0, va(\"(%d,%d)\",uis.cursorx,uis.cursory), UI_LEFT|UI_SMALLFONT, colorRed );\n\t}\n#endif\n\n\t// delay playing the enter sound until after the\n\t// menu has been drawn, to avoid delay while\n\t// caching images\n\tif (m_entersound)\n\t{\n\t\ttrap_S_StartLocalSound( menu_in_sound, CHAN_LOCAL_SOUND );\n\t\tm_entersound = qfalse;\n\t}\n}\n\nvoid UI_DrawTextBox (int x, int y, int width, int lines)\n{\n\tUI_FillRect( x + BIGCHAR_WIDTH/2, y + BIGCHAR_HEIGHT/2, ( width + 1 ) * BIGCHAR_WIDTH, ( lines + 1 ) * BIGCHAR_HEIGHT, colorBlack );\n\tUI_DrawRect( x + BIGCHAR_WIDTH/2, y + BIGCHAR_HEIGHT/2, ( width + 1 ) * BIGCHAR_WIDTH, ( lines + 1 ) * BIGCHAR_HEIGHT, colorWhite );\n}\n\nqboolean UI_CursorInRect (int x, int y, int width, int height)\n{\n\tif (uis.cursorx < x ||\n\t\tuis.cursory < y ||\n\t\tuis.cursorx > x+width ||\n\t\tuis.cursory > y+height)\n\t\treturn qfalse;\n\n\treturn qtrue;\n}\n"
  },
  {
    "path": "src/q3_ui/ui_cdkey.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n/*\n=======================================================================\n\nCD KEY MENU\n\n=======================================================================\n*/\n\n\n#include \"ui_local.h\"\n\n\n#define ART_FRAME\t\t\"menu/art/cut_frame\"\n#define ART_ACCEPT0\t\t\"menu/art/accept_0\"\n#define ART_ACCEPT1\t\t\"menu/art/accept_1\"\t\n#define ART_BACK0\t\t\"menu/art/back_0\"\n#define ART_BACK1\t\t\"menu/art/back_1\"\t\n\n#define ID_CDKEY\t\t10\n#define ID_ACCEPT\t\t11\n#define ID_BACK\t\t\t12\n\n\ntypedef struct {\n\tmenuframework_s\tmenu;\n\n\tmenutext_s\t\tbanner;\n\tmenubitmap_s\tframe;\n\n\tmenufield_s\t\tcdkey;\n\n\tmenubitmap_s\taccept;\n\tmenubitmap_s\tback;\n} cdkeyMenuInfo_t;\n\nstatic cdkeyMenuInfo_t\tcdkeyMenuInfo;\n\n\n/*\n===============\nUI_CDKeyMenu_Event\n===============\n*/\nstatic void UI_CDKeyMenu_Event( void *ptr, int event ) {\n\tif( event != QM_ACTIVATED ) {\n\t\treturn;\n\t}\n\n\tswitch( ((menucommon_s*)ptr)->id ) {\n\tcase ID_ACCEPT:\n\t\tif( cdkeyMenuInfo.cdkey.field.buffer[0] ) {\n\t\t\ttrap_SetCDKey( cdkeyMenuInfo.cdkey.field.buffer );\n\t\t}\n\t\tUI_PopMenu();\n\t\tbreak;\n\n\tcase ID_BACK:\n\t\tUI_PopMenu();\n\t\tbreak;\n\t}\n}\n\n\n/*\n=================\nUI_CDKeyMenu_PreValidateKey\n=================\n*/\nstatic int UI_CDKeyMenu_PreValidateKey( const char *key ) {\n\tchar\tch;\n\n\tif( (int)strlen( key ) != 16 ) {\n\t\treturn 1;\n\t}\n\n\twhile( ( ch = *key++ ) ) {\n\t\tswitch( ch ) {\n\t\tcase '2':\n\t\tcase '3':\n\t\tcase '7':\n\t\tcase 'a':\n\t\tcase 'b':\n\t\tcase 'c':\n\t\tcase 'd':\n\t\tcase 'g':\n\t\tcase 'h':\n\t\tcase 'j':\n\t\tcase 'l':\n\t\tcase 'p':\n\t\tcase 'r':\n\t\tcase 's':\n\t\tcase 't':\n\t\tcase 'w':\n\t\t\tcontinue;\n\t\tdefault:\n\t\t\treturn -1;\n\t\t}\n\t}\n\n\treturn 0;\n}\n\n\n/*\n=================\nUI_CDKeyMenu_DrawKey\n=================\n*/\nstatic void UI_CDKeyMenu_DrawKey( void *self ) {\n\tmenufield_s\t\t*f;\n\tqboolean\t\tfocus;\n\tint\t\t\t\tstyle;\n\tchar\t\t\tc;\n\tfloat\t\t\t*color;\n\tint\t\t\t\tx, y;\n\tint\t\t\t\tval;\n\n\tf = (menufield_s *)self;\n\n\tfocus = (f->generic.parent->cursor == f->generic.menuPosition);\n\n\tstyle = UI_LEFT;\n\tif( focus ) {\n\t\tcolor = color_yellow;\n\t}\n\telse {\n\t\tcolor = color_orange;\n\t}\n\n\tx = 320 - 8 * BIGCHAR_WIDTH;\n\ty = 240 - BIGCHAR_HEIGHT / 2;\n\tUI_FillRect( x, y, 16 * BIGCHAR_WIDTH, BIGCHAR_HEIGHT, listbar_color );\n\tUI_DrawString( x, y, f->field.buffer, style, color );\n\n\t// draw cursor if we have focus\n\tif( focus ) {\n\t\tif ( trap_Key_GetOverstrikeMode() ) {\n\t\t\tc = 11;\n\t\t} else {\n\t\t\tc = 10;\n\t\t}\n\n\t\tstyle &= ~UI_PULSE;\n\t\tstyle |= UI_BLINK;\n\n\t\tUI_DrawChar( x + f->field.cursor * BIGCHAR_WIDTH, y, c, style, color_white );\n\t}\n\n\tval = UI_CDKeyMenu_PreValidateKey( f->field.buffer );\n\tif( val == 1 ) {\n\t\tUI_DrawProportionalString( 320, 376, \"Please enter your CD Key\", UI_CENTER|UI_SMALLFONT, color_yellow );\n\t}\n\telse if ( val == 0 ) {\n\t\tUI_DrawProportionalString( 320, 376, \"The CD Key appears to be valid, thank you\", UI_CENTER|UI_SMALLFONT, color_white );\n\t}\n\telse {\n\t\tUI_DrawProportionalString( 320, 376, \"The CD Key is not valid\", UI_CENTER|UI_SMALLFONT, color_red );\n\t}\n}\n\n\n/*\n===============\nUI_CDKeyMenu_Init\n===============\n*/\nstatic void UI_CDKeyMenu_Init( void ) {\n\ttrap_Cvar_Set( \"ui_cdkeychecked\", \"1\" );\n\n\tUI_CDKeyMenu_Cache();\n\n\tmemset( &cdkeyMenuInfo, 0, sizeof(cdkeyMenuInfo) );\n\tcdkeyMenuInfo.menu.wrapAround = qtrue;\n\tcdkeyMenuInfo.menu.fullscreen = qtrue;\n\n\tcdkeyMenuInfo.banner.generic.type\t\t\t\t= MTYPE_BTEXT;\n\tcdkeyMenuInfo.banner.generic.x\t\t\t\t\t= 320;\n\tcdkeyMenuInfo.banner.generic.y\t\t\t\t\t= 16;\n\tcdkeyMenuInfo.banner.string\t\t\t\t\t\t= \"CD KEY\";\n\tcdkeyMenuInfo.banner.color\t\t\t\t\t\t= color_white;\n\tcdkeyMenuInfo.banner.style\t\t\t\t\t\t= UI_CENTER;\n\n\tcdkeyMenuInfo.frame.generic.type\t\t\t\t= MTYPE_BITMAP;\n\tcdkeyMenuInfo.frame.generic.name\t\t\t\t= ART_FRAME;\n\tcdkeyMenuInfo.frame.generic.flags\t\t\t\t= QMF_INACTIVE;\n\tcdkeyMenuInfo.frame.generic.x\t\t\t\t\t= 142;\n\tcdkeyMenuInfo.frame.generic.y\t\t\t\t\t= 118;\n\tcdkeyMenuInfo.frame.width  \t\t\t\t\t\t= 359;\n\tcdkeyMenuInfo.frame.height  \t\t\t\t\t= 256;\n\n\tcdkeyMenuInfo.cdkey.generic.type\t\t\t\t= MTYPE_FIELD;\n\tcdkeyMenuInfo.cdkey.generic.name\t\t\t\t= \"CD Key:\";\n\tcdkeyMenuInfo.cdkey.generic.flags\t\t\t\t= QMF_LOWERCASE;\n\tcdkeyMenuInfo.cdkey.generic.x\t\t\t\t\t= 320 - BIGCHAR_WIDTH * 2.5;\n\tcdkeyMenuInfo.cdkey.generic.y\t\t\t\t\t= 240 - BIGCHAR_HEIGHT / 2;\n\tcdkeyMenuInfo.cdkey.field.widthInChars\t\t\t= 16;\n\tcdkeyMenuInfo.cdkey.field.maxchars\t\t\t\t= 16;\n\tcdkeyMenuInfo.cdkey.generic.ownerdraw\t\t\t= UI_CDKeyMenu_DrawKey;\n\n\tcdkeyMenuInfo.accept.generic.type\t\t\t\t= MTYPE_BITMAP;\n\tcdkeyMenuInfo.accept.generic.name\t\t\t\t= ART_ACCEPT0;\n\tcdkeyMenuInfo.accept.generic.flags\t\t\t\t= QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;\n\tcdkeyMenuInfo.accept.generic.id\t\t\t\t\t= ID_ACCEPT;\n\tcdkeyMenuInfo.accept.generic.callback\t\t\t= UI_CDKeyMenu_Event;\n\tcdkeyMenuInfo.accept.generic.x\t\t\t\t\t= 640;\n\tcdkeyMenuInfo.accept.generic.y\t\t\t\t\t= 480-64;\n\tcdkeyMenuInfo.accept.width\t\t\t\t\t\t= 128;\n\tcdkeyMenuInfo.accept.height\t\t\t\t\t\t= 64;\n\tcdkeyMenuInfo.accept.focuspic\t\t\t\t\t= ART_ACCEPT1;\n\n\tcdkeyMenuInfo.back.generic.type\t\t\t\t\t= MTYPE_BITMAP;\n\tcdkeyMenuInfo.back.generic.name\t\t\t\t\t= ART_BACK0;\n\tcdkeyMenuInfo.back.generic.flags\t\t\t\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\tcdkeyMenuInfo.back.generic.id\t\t\t\t\t= ID_BACK;\n\tcdkeyMenuInfo.back.generic.callback\t\t\t\t= UI_CDKeyMenu_Event;\n\tcdkeyMenuInfo.back.generic.x\t\t\t\t\t= 0;\n\tcdkeyMenuInfo.back.generic.y\t\t\t\t\t= 480-64;\n\tcdkeyMenuInfo.back.width\t\t\t\t\t\t= 128;\n\tcdkeyMenuInfo.back.height\t\t\t\t\t\t= 64;\n\tcdkeyMenuInfo.back.focuspic\t\t\t\t\t\t= ART_BACK1;\n\n\tMenu_AddItem( &cdkeyMenuInfo.menu, &cdkeyMenuInfo.banner );\n\tMenu_AddItem( &cdkeyMenuInfo.menu, &cdkeyMenuInfo.frame );\n\tMenu_AddItem( &cdkeyMenuInfo.menu, &cdkeyMenuInfo.cdkey );\n\tMenu_AddItem( &cdkeyMenuInfo.menu, &cdkeyMenuInfo.accept );\n\tif( uis.menusp ) {\n\t\tMenu_AddItem( &cdkeyMenuInfo.menu, &cdkeyMenuInfo.back );\n\t}\n\n\ttrap_GetCDKey( cdkeyMenuInfo.cdkey.field.buffer, cdkeyMenuInfo.cdkey.field.maxchars + 1 );\n\tif( trap_VerifyCDKey( cdkeyMenuInfo.cdkey.field.buffer, NULL ) == qfalse ) {\n\t\tcdkeyMenuInfo.cdkey.field.buffer[0] = 0;\n\t}\n}\n\n\n/*\n=================\nUI_CDKeyMenu_Cache\n=================\n*/\nvoid UI_CDKeyMenu_Cache( void ) {\n\ttrap_R_RegisterShaderNoMip( ART_ACCEPT0 );\n\ttrap_R_RegisterShaderNoMip( ART_ACCEPT1 );\n\ttrap_R_RegisterShaderNoMip( ART_BACK0 );\n\ttrap_R_RegisterShaderNoMip( ART_BACK1 );\n\ttrap_R_RegisterShaderNoMip( ART_FRAME );\n}\n\n\n/*\n===============\nUI_CDKeyMenu\n===============\n*/\nvoid UI_CDKeyMenu( void ) {\n\tUI_CDKeyMenu_Init();\n\tUI_PushMenu( &cdkeyMenuInfo.menu );\n}\n\n\n/*\n===============\nUI_CDKeyMenu_f\n===============\n*/\nvoid UI_CDKeyMenu_f( void ) {\n\tUI_CDKeyMenu();\n}\n"
  },
  {
    "path": "src/q3_ui/ui_cinematics.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n#include \"ui_local.h\"\n\n\n#define ART_BACK0\t\t\"menu/art/back_0\"\n#define ART_BACK1\t\t\"menu/art/back_1\"\t\n#define ART_FRAMEL\t\t\"menu/art/frame2_l\"\n#define ART_FRAMER\t\t\"menu/art/frame1_r\"\n\n#define VERTICAL_SPACING\t30\n\n#define ID_BACK\t\t\t10\n#define ID_CIN_IDLOGO\t11\n#define ID_CIN_INTRO\t12\n#define ID_CIN_TIER1\t13\n#define ID_CIN_TIER2\t14\n#define ID_CIN_TIER3\t15\n#define ID_CIN_TIER4\t16\n#define ID_CIN_TIER5\t17\n#define ID_CIN_TIER6\t18\n#define ID_CIN_TIER7\t19\n#define ID_CIN_END\t\t20\n\n\ntypedef struct {\n\tmenuframework_s\tmenu;\n\tmenutext_s\t\tbanner;\n\tmenubitmap_s\tframel;\n\tmenubitmap_s\tframer;\n\tmenutext_s\t\tcin_idlogo;\n\tmenutext_s\t\tcin_intro;\n\tmenutext_s\t\tcin_tier1;\n\tmenutext_s\t\tcin_tier2;\n\tmenutext_s\t\tcin_tier3;\n\tmenutext_s\t\tcin_tier4;\n\tmenutext_s\t\tcin_tier5;\n\tmenutext_s\t\tcin_tier6;\n\tmenutext_s\t\tcin_tier7;\n\tmenutext_s\t\tcin_end;\n\tmenubitmap_s\tback;\n} cinematicsMenuInfo_t;\n\nstatic cinematicsMenuInfo_t\tcinematicsMenuInfo;\n\nstatic char *cinematics[] = {\n\t\"idlogo\",\n\t\"intro\",\n\t\"tier1\",\n\t\"tier2\",\n\t\"tier3\",\n\t\"tier4\",\n\t\"tier5\",\n\t\"tier6\",\n\t\"tier7\",\n\t\"end\"\n};\n\n/*\n===============\nUI_CinematicsMenu_BackEvent\n===============\n*/\nstatic void UI_CinematicsMenu_BackEvent( void *ptr, int event ) {\n\tif( event != QM_ACTIVATED ) {\n\t\treturn;\n\t}\n\tUI_PopMenu();\n}\n\n\n/*\n===============\nUI_CinematicsMenu_Event\n===============\n*/\nstatic void UI_CinematicsMenu_Event( void *ptr, int event ) {\n\tint\t\tn;\n\n\tif (event != QM_ACTIVATED)\n\t\treturn;\n\n\tn = ((menucommon_s*)ptr)->id - ID_CIN_IDLOGO;\n\ttrap_Cvar_Set( \"nextmap\", va( \"ui_cinematics %i\", n ) );\n\tif( uis.demoversion && ((menucommon_s*)ptr)->id == ID_CIN_END ) {\n\t\ttrap_Cmd_ExecuteText( EXEC_APPEND, \"disconnect; cinematic demoEnd.RoQ 1\\n\" );\n\t}\n\telse {\n\t\ttrap_Cmd_ExecuteText( EXEC_APPEND, va( \"disconnect; cinematic %s.RoQ\\n\", cinematics[n] ) );\n\t}\n}\n\n\n/*\n===============\nUI_CinematicsMenu_Init\n===============\n*/\nstatic void UI_CinematicsMenu_Init( void ) {\n\tint\t\ty;\n\n\tUI_CinematicsMenu_Cache();\n\n\tmemset( &cinematicsMenuInfo, 0, sizeof(cinematicsMenuInfo) );\n\tcinematicsMenuInfo.menu.fullscreen = qtrue;\n\n\tcinematicsMenuInfo.banner.generic.type\t\t= MTYPE_BTEXT;\n\tcinematicsMenuInfo.banner.generic.x\t\t\t= 320;\n\tcinematicsMenuInfo.banner.generic.y\t\t\t= 16;\n\tcinematicsMenuInfo.banner.string\t\t\t= \"CINEMATICS\";\n\tcinematicsMenuInfo.banner.color\t\t\t\t= color_white;\n\tcinematicsMenuInfo.banner.style\t\t\t\t= UI_CENTER;\n\n\tcinematicsMenuInfo.framel.generic.type\t\t= MTYPE_BITMAP;\n\tcinematicsMenuInfo.framel.generic.name\t\t= ART_FRAMEL;\n\tcinematicsMenuInfo.framel.generic.flags\t\t= QMF_INACTIVE;\n\tcinematicsMenuInfo.framel.generic.x\t\t\t= 0;  \n\tcinematicsMenuInfo.framel.generic.y\t\t\t= 78;\n\tcinematicsMenuInfo.framel.width  \t\t\t= 256;\n\tcinematicsMenuInfo.framel.height  \t\t\t= 329;\n\n\tcinematicsMenuInfo.framer.generic.type\t\t= MTYPE_BITMAP;\n\tcinematicsMenuInfo.framer.generic.name\t\t= ART_FRAMER;\n\tcinematicsMenuInfo.framer.generic.flags\t\t= QMF_INACTIVE;\n\tcinematicsMenuInfo.framer.generic.x\t\t\t= 376;\n\tcinematicsMenuInfo.framer.generic.y\t\t\t= 76;\n\tcinematicsMenuInfo.framer.width  \t\t\t= 256;\n\tcinematicsMenuInfo.framer.height  \t\t\t= 334;\n\n\ty = 100;\n\tcinematicsMenuInfo.cin_idlogo.generic.type\t\t= MTYPE_PTEXT;\n\tcinematicsMenuInfo.cin_idlogo.generic.flags\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\tcinematicsMenuInfo.cin_idlogo.generic.x\t\t\t= 320;\n\tcinematicsMenuInfo.cin_idlogo.generic.y\t\t\t= y;\n\tcinematicsMenuInfo.cin_idlogo.generic.id\t\t= ID_CIN_IDLOGO;\n\tcinematicsMenuInfo.cin_idlogo.generic.callback\t= UI_CinematicsMenu_Event; \n\tcinematicsMenuInfo.cin_idlogo.string\t\t\t= \"ID LOGO\";\n\tcinematicsMenuInfo.cin_idlogo.color\t\t\t\t= color_red;\n\tcinematicsMenuInfo.cin_idlogo.style\t\t\t\t= UI_CENTER;\n\n\ty += VERTICAL_SPACING;\n\tcinematicsMenuInfo.cin_intro.generic.type\t\t= MTYPE_PTEXT;\n\tcinematicsMenuInfo.cin_intro.generic.flags\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\tcinematicsMenuInfo.cin_intro.generic.x\t\t\t= 320;\n\tcinematicsMenuInfo.cin_intro.generic.y\t\t\t= y;\n\tcinematicsMenuInfo.cin_intro.generic.id\t\t\t= ID_CIN_INTRO;\n\tcinematicsMenuInfo.cin_intro.generic.callback\t= UI_CinematicsMenu_Event; \n\tcinematicsMenuInfo.cin_intro.string\t\t\t\t= \"INTRO\";\n\tcinematicsMenuInfo.cin_intro.color\t\t\t\t= color_red;\n\tcinematicsMenuInfo.cin_intro.style\t\t\t\t= UI_CENTER;\n\tif( uis.demoversion ) {\n\t\tcinematicsMenuInfo.cin_intro.generic.flags |= QMF_GRAYED;\n\t}\n\n\ty += VERTICAL_SPACING;\n\tcinematicsMenuInfo.cin_tier1.generic.type\t\t= MTYPE_PTEXT;\n\tcinematicsMenuInfo.cin_tier1.generic.flags\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\tcinematicsMenuInfo.cin_tier1.generic.x\t\t\t= 320;\n\tcinematicsMenuInfo.cin_tier1.generic.y\t\t\t= y;\n\tcinematicsMenuInfo.cin_tier1.generic.id\t\t\t= ID_CIN_TIER1;\n\tcinematicsMenuInfo.cin_tier1.generic.callback\t= UI_CinematicsMenu_Event; \n\tcinematicsMenuInfo.cin_tier1.string\t\t\t\t= \"Tier 1\";\n\tcinematicsMenuInfo.cin_tier1.color\t\t\t\t= color_red;\n\tcinematicsMenuInfo.cin_tier1.style\t\t\t\t= UI_CENTER;\n\tif( !UI_CanShowTierVideo( 1 ) ) {\n\t\tcinematicsMenuInfo.cin_tier1.generic.flags |= QMF_GRAYED;\n\t}\n\n\ty += VERTICAL_SPACING;\n\tcinematicsMenuInfo.cin_tier2.generic.type\t\t= MTYPE_PTEXT;\n\tcinematicsMenuInfo.cin_tier2.generic.flags\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\tcinematicsMenuInfo.cin_tier2.generic.x\t\t\t= 320;\n\tcinematicsMenuInfo.cin_tier2.generic.y\t\t\t= y;\n\tcinematicsMenuInfo.cin_tier2.generic.id\t\t\t= ID_CIN_TIER2;\n\tcinematicsMenuInfo.cin_tier2.generic.callback\t= UI_CinematicsMenu_Event; \n\tcinematicsMenuInfo.cin_tier2.string\t\t\t\t= \"Tier 2\";\n\tcinematicsMenuInfo.cin_tier2.color\t\t\t\t= color_red;\n\tcinematicsMenuInfo.cin_tier2.style\t\t\t\t= UI_CENTER;\n\tif( !UI_CanShowTierVideo( 2 ) ) {\n\t\tcinematicsMenuInfo.cin_tier2.generic.flags |= QMF_GRAYED;\n\t}\n\n\ty += VERTICAL_SPACING;\n\tcinematicsMenuInfo.cin_tier3.generic.type\t\t= MTYPE_PTEXT;\n\tcinematicsMenuInfo.cin_tier3.generic.flags\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\tcinematicsMenuInfo.cin_tier3.generic.x\t\t\t= 320;\n\tcinematicsMenuInfo.cin_tier3.generic.y\t\t\t= y;\n\tcinematicsMenuInfo.cin_tier3.generic.id\t\t\t= ID_CIN_TIER3;\n\tcinematicsMenuInfo.cin_tier3.generic.callback\t= UI_CinematicsMenu_Event; \n\tcinematicsMenuInfo.cin_tier3.string\t\t\t\t= \"Tier 3\";\n\tcinematicsMenuInfo.cin_tier3.color\t\t\t\t= color_red;\n\tcinematicsMenuInfo.cin_tier3.style\t\t\t\t= UI_CENTER;\n\tif( !UI_CanShowTierVideo( 3 ) ) {\n\t\tcinematicsMenuInfo.cin_tier3.generic.flags |= QMF_GRAYED;\n\t}\n\n\ty += VERTICAL_SPACING;\n\tcinematicsMenuInfo.cin_tier4.generic.type\t\t= MTYPE_PTEXT;\n\tcinematicsMenuInfo.cin_tier4.generic.flags\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\tcinematicsMenuInfo.cin_tier4.generic.x\t\t\t= 320;\n\tcinematicsMenuInfo.cin_tier4.generic.y\t\t\t= y;\n\tcinematicsMenuInfo.cin_tier4.generic.id\t\t\t= ID_CIN_TIER4;\n\tcinematicsMenuInfo.cin_tier4.generic.callback\t= UI_CinematicsMenu_Event; \n\tcinematicsMenuInfo.cin_tier4.string\t\t\t\t= \"Tier 4\";\n\tcinematicsMenuInfo.cin_tier4.color\t\t\t\t= color_red;\n\tcinematicsMenuInfo.cin_tier4.style\t\t\t\t= UI_CENTER;\n\tif( !UI_CanShowTierVideo( 4 ) ) {\n\t\tcinematicsMenuInfo.cin_tier4.generic.flags |= QMF_GRAYED;\n\t}\n\n\ty += VERTICAL_SPACING;\n\tcinematicsMenuInfo.cin_tier5.generic.type\t\t= MTYPE_PTEXT;\n\tcinematicsMenuInfo.cin_tier5.generic.flags\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\tcinematicsMenuInfo.cin_tier5.generic.x\t\t\t= 320;\n\tcinematicsMenuInfo.cin_tier5.generic.y\t\t\t= y;\n\tcinematicsMenuInfo.cin_tier5.generic.id\t\t\t= ID_CIN_TIER5;\n\tcinematicsMenuInfo.cin_tier5.generic.callback\t= UI_CinematicsMenu_Event; \n\tcinematicsMenuInfo.cin_tier5.string\t\t\t\t= \"Tier 5\";\n\tcinematicsMenuInfo.cin_tier5.color\t\t\t\t= color_red;\n\tcinematicsMenuInfo.cin_tier5.style\t\t\t\t= UI_CENTER;\n\tif( !UI_CanShowTierVideo( 5 ) ) {\n\t\tcinematicsMenuInfo.cin_tier5.generic.flags |= QMF_GRAYED;\n\t}\n\n\ty += VERTICAL_SPACING;\n\tcinematicsMenuInfo.cin_tier6.generic.type\t\t= MTYPE_PTEXT;\n\tcinematicsMenuInfo.cin_tier6.generic.flags\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\tcinematicsMenuInfo.cin_tier6.generic.x\t\t\t= 320;\n\tcinematicsMenuInfo.cin_tier6.generic.y\t\t\t= y;\n\tcinematicsMenuInfo.cin_tier6.generic.id\t\t\t= ID_CIN_TIER6;\n\tcinematicsMenuInfo.cin_tier6.generic.callback\t= UI_CinematicsMenu_Event; \n\tcinematicsMenuInfo.cin_tier6.string\t\t\t\t= \"Tier 6\";\n\tcinematicsMenuInfo.cin_tier6.color\t\t\t\t= color_red;\n\tcinematicsMenuInfo.cin_tier6.style\t\t\t\t= UI_CENTER;\n\tif( !UI_CanShowTierVideo( 6 ) ) {\n\t\tcinematicsMenuInfo.cin_tier6.generic.flags |= QMF_GRAYED;\n\t}\n\n\ty += VERTICAL_SPACING;\n\tcinematicsMenuInfo.cin_tier7.generic.type\t\t= MTYPE_PTEXT;\n\tcinematicsMenuInfo.cin_tier7.generic.flags\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\tcinematicsMenuInfo.cin_tier7.generic.x\t\t\t= 320;\n\tcinematicsMenuInfo.cin_tier7.generic.y\t\t\t= y;\n\tcinematicsMenuInfo.cin_tier7.generic.id\t\t\t= ID_CIN_TIER7;\n\tcinematicsMenuInfo.cin_tier7.generic.callback\t= UI_CinematicsMenu_Event; \n\tcinematicsMenuInfo.cin_tier7.string\t\t\t\t= \"Tier 7\";\n\tcinematicsMenuInfo.cin_tier7.color\t\t\t\t= color_red;\n\tcinematicsMenuInfo.cin_tier7.style\t\t\t\t= UI_CENTER;\n\tif( !UI_CanShowTierVideo( 7 ) ) {\n\t\tcinematicsMenuInfo.cin_tier7.generic.flags |= QMF_GRAYED;\n\t}\n\n\ty += VERTICAL_SPACING;\n\tcinematicsMenuInfo.cin_end.generic.type\t\t\t= MTYPE_PTEXT;\n\tcinematicsMenuInfo.cin_end.generic.flags\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\tcinematicsMenuInfo.cin_end.generic.x\t\t\t= 320;\n\tcinematicsMenuInfo.cin_end.generic.y\t\t\t= y;\n\tcinematicsMenuInfo.cin_end.generic.id\t\t\t= ID_CIN_END;\n\tcinematicsMenuInfo.cin_end.generic.callback\t\t= UI_CinematicsMenu_Event; \n\tcinematicsMenuInfo.cin_end.string\t\t\t\t= \"END\";\n\tcinematicsMenuInfo.cin_end.color\t\t\t\t= color_red;\n\tcinematicsMenuInfo.cin_end.style\t\t\t\t= UI_CENTER;\n\tif( !UI_CanShowTierVideo( 8 ) ) {\n\t\tcinematicsMenuInfo.cin_end.generic.flags |= QMF_GRAYED;\n\t}\n\n\tcinematicsMenuInfo.back.generic.type\t\t= MTYPE_BITMAP;\n\tcinematicsMenuInfo.back.generic.name\t\t= ART_BACK0;\n\tcinematicsMenuInfo.back.generic.flags\t\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\tcinematicsMenuInfo.back.generic.id\t\t\t= ID_BACK;\n\tcinematicsMenuInfo.back.generic.callback\t= UI_CinematicsMenu_BackEvent;\n\tcinematicsMenuInfo.back.generic.x\t\t\t= 0;\n\tcinematicsMenuInfo.back.generic.y\t\t\t= 480-64;\n\tcinematicsMenuInfo.back.width\t\t\t\t= 128;\n\tcinematicsMenuInfo.back.height\t\t\t\t= 64;\n\tcinematicsMenuInfo.back.focuspic\t\t\t= ART_BACK1;\n\n\tMenu_AddItem( &cinematicsMenuInfo.menu, &cinematicsMenuInfo.banner );\n\tMenu_AddItem( &cinematicsMenuInfo.menu, &cinematicsMenuInfo.framel );\n\tMenu_AddItem( &cinematicsMenuInfo.menu, &cinematicsMenuInfo.framer );\n\tMenu_AddItem( &cinematicsMenuInfo.menu, &cinematicsMenuInfo.cin_idlogo );\n\tMenu_AddItem( &cinematicsMenuInfo.menu, &cinematicsMenuInfo.cin_intro );\n\tMenu_AddItem( &cinematicsMenuInfo.menu, &cinematicsMenuInfo.cin_tier1 );\n\tMenu_AddItem( &cinematicsMenuInfo.menu, &cinematicsMenuInfo.cin_tier2 );\n\tMenu_AddItem( &cinematicsMenuInfo.menu, &cinematicsMenuInfo.cin_tier3 );\n\tMenu_AddItem( &cinematicsMenuInfo.menu, &cinematicsMenuInfo.cin_tier4 );\n\tMenu_AddItem( &cinematicsMenuInfo.menu, &cinematicsMenuInfo.cin_tier5 );\n\tMenu_AddItem( &cinematicsMenuInfo.menu, &cinematicsMenuInfo.cin_tier6 );\n\tMenu_AddItem( &cinematicsMenuInfo.menu, &cinematicsMenuInfo.cin_tier7 );\n\tMenu_AddItem( &cinematicsMenuInfo.menu, &cinematicsMenuInfo.cin_end );\n\tMenu_AddItem( &cinematicsMenuInfo.menu, &cinematicsMenuInfo.back );\n}\n\n\n/*\n=================\nUI_CinematicsMenu_Cache\n=================\n*/\nvoid UI_CinematicsMenu_Cache( void ) {\n\ttrap_R_RegisterShaderNoMip( ART_BACK0 );\n\ttrap_R_RegisterShaderNoMip( ART_BACK1 );\n\ttrap_R_RegisterShaderNoMip( ART_FRAMEL );\n\ttrap_R_RegisterShaderNoMip( ART_FRAMER );\n}\n\n\n/*\n===============\nUI_CinematicsMenu\n===============\n*/\nvoid UI_CinematicsMenu( void ) {\n\tUI_CinematicsMenu_Init();\n\tUI_PushMenu( &cinematicsMenuInfo.menu );\n}\n\n\n/*\n===============\nUI_CinematicsMenu_f\n===============\n*/\nvoid UI_CinematicsMenu_f( void ) {\n\tint\t\tn;\n\n\tn = atoi( UI_Argv( 1 ) );\n\tUI_CinematicsMenu();\n\tMenu_SetCursorToItem( &cinematicsMenuInfo.menu, cinematicsMenuInfo.menu.items[n + 3] );\n}\n"
  },
  {
    "path": "src/q3_ui/ui_confirm.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n/*\n=======================================================================\n\nCONFIRMATION MENU\n\n=======================================================================\n*/\n\n\n#include \"ui_local.h\"\n\n\n#define ART_CONFIRM_FRAME\t\"menu/art/cut_frame\"\n\n#define ID_CONFIRM_NO\t\t10\n#define ID_CONFIRM_YES\t\t11\n\n\ntypedef struct {\n\tmenuframework_s menu;\n\n\tmenutext_s\t\tno;\n\tmenutext_s\t\tyes;\n\n\tint\t\t\t\tslashX;\n\tconst char *\tquestion;\n\tvoid\t\t\t(*draw)( void );\n\tvoid\t\t\t(*action)( qboolean result );\n\t\n\tint style;\n\tconst char **lines;\n} confirmMenu_t;\n\n\nstatic confirmMenu_t\ts_confirm;\n\n\n/*\n=================\nConfirmMenu_Event\n=================\n*/\nstatic void ConfirmMenu_Event( void* ptr, int event ) {\n\tqboolean\tresult;\n\n\tif( event != QM_ACTIVATED ) {\n\t\treturn;\n\t}\n\n\tUI_PopMenu();\n\n\tif( ((menucommon_s*)ptr)->id == ID_CONFIRM_NO ) {\n\t\tresult = qfalse;\n\t}\n\telse {\n\t\tresult = qtrue;\n\t}\n\n\tif( s_confirm.action ) {\n\t\ts_confirm.action( result );\n\t}\n}\n\n\n/*\n=================\nConfirmMenu_Key\n=================\n*/\nstatic sfxHandle_t ConfirmMenu_Key( int key ) {\n\tswitch ( key ) {\n\tcase K_KP_LEFTARROW:\n\tcase K_LEFTARROW:\n\tcase K_KP_RIGHTARROW:\n\tcase K_RIGHTARROW:\n\t\tkey = K_TAB;\n\t\tbreak;\n\n\tcase 'n':\n\tcase 'N':\n\t\tConfirmMenu_Event( &s_confirm.no, QM_ACTIVATED );\n\t\tbreak;\n\n\tcase 'y':\n\tcase 'Y':\n\t\tConfirmMenu_Event( &s_confirm.yes, QM_ACTIVATED );\n\t\tbreak;\n\t}\n\n\treturn Menu_DefaultKey( &s_confirm.menu, key );\n}\n\n\n/*\n=================\nMessaheMenu_Draw\n=================\n*/\nstatic void MessageMenu_Draw( void ) {\n\tint i,y;\n\t\n\tUI_DrawNamedPic( 142, 118, 359, 256, ART_CONFIRM_FRAME );\n\t\n\ty = 188;\n\tfor(i=0; s_confirm.lines[i]; i++)\n\t{\n\t\tUI_DrawProportionalString( 320, y, s_confirm.lines[i], s_confirm.style, color_red );\n\t\ty += 18;\n\t}\n\n\tMenu_Draw( &s_confirm.menu );\n\n\tif( s_confirm.draw ) {\n\t\ts_confirm.draw();\n\t}\n}\n\n/*\n=================\nConfirmMenu_Draw\n=================\n*/\nstatic void ConfirmMenu_Draw( void ) {\n\tUI_DrawNamedPic( 142, 118, 359, 256, ART_CONFIRM_FRAME );\n\tUI_DrawProportionalString( 320, 204, s_confirm.question, s_confirm.style, color_red );\n\tUI_DrawProportionalString( s_confirm.slashX, 265, \"/\", UI_LEFT|UI_INVERSE, color_red );\n\n\tMenu_Draw( &s_confirm.menu );\n\n\tif( s_confirm.draw ) {\n\t\ts_confirm.draw();\n\t}\n}\n\n\n/*\n=================\nConfirmMenu_Cache\n=================\n*/\nvoid ConfirmMenu_Cache( void ) {\n\ttrap_R_RegisterShaderNoMip( ART_CONFIRM_FRAME );\n}\n\n\n/*\n=================\nUI_ConfirmMenu_Stlye\n=================\n*/\nvoid UI_ConfirmMenu_Style( const char *question, int style, void (*draw)( void ), void (*action)( qboolean result ) ) {\n\tuiClientState_t\tcstate;\n\tint\tn1, n2, n3;\n\tint\tl1, l2, l3;\n\n\t// zero set all our globals\n\tmemset( &s_confirm, 0, sizeof(s_confirm) );\n\n\tConfirmMenu_Cache();\n\n\tn1 = UI_ProportionalStringWidth( \"YES/NO\" );\n\tn2 = UI_ProportionalStringWidth( \"YES\" ) + PROP_GAP_WIDTH;\n\tn3 = UI_ProportionalStringWidth( \"/\" )  + PROP_GAP_WIDTH;\n\tl1 = 320 - ( n1 / 2 );\n\tl2 = l1 + n2;\n\tl3 = l2 + n3;\n\ts_confirm.slashX = l2;\n\n\ts_confirm.question = question;\n\ts_confirm.draw = draw;\n\ts_confirm.action = action;\n\ts_confirm.style = style;\n\n\ts_confirm.menu.draw       = ConfirmMenu_Draw;\n\ts_confirm.menu.key        = ConfirmMenu_Key;\n\ts_confirm.menu.wrapAround = qtrue;\n\n\ttrap_GetClientState( &cstate );\n\tif ( cstate.connState >= CA_CONNECTED ) {\n\t\ts_confirm.menu.fullscreen = qfalse;\n\t}\n\telse {\n\t\ts_confirm.menu.fullscreen = qtrue;\n\t}\n\n\ts_confirm.yes.generic.type\t\t= MTYPE_PTEXT;      \n\ts_confirm.yes.generic.flags\t\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; \n\ts_confirm.yes.generic.callback\t= ConfirmMenu_Event;\n\ts_confirm.yes.generic.id\t\t= ID_CONFIRM_YES;\n\ts_confirm.yes.generic.x\t\t\t= l1;\n\ts_confirm.yes.generic.y\t\t\t= 264;\n\ts_confirm.yes.string\t\t\t= \"YES\";\n\ts_confirm.yes.color\t\t\t\t= color_red;\n\ts_confirm.yes.style\t\t\t\t= UI_LEFT;\n\n\ts_confirm.no.generic.type\t\t= MTYPE_PTEXT;      \n\ts_confirm.no.generic.flags\t\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; \n\ts_confirm.no.generic.callback\t= ConfirmMenu_Event;\n\ts_confirm.no.generic.id\t\t\t= ID_CONFIRM_NO;\n\ts_confirm.no.generic.x\t\t    = l3;\n\ts_confirm.no.generic.y\t\t    = 264;\n\ts_confirm.no.string\t\t\t\t= \"NO\";\n\ts_confirm.no.color\t\t\t    = color_red;\n\ts_confirm.no.style\t\t\t    = UI_LEFT;\n\n\tMenu_AddItem( &s_confirm.menu,\t&s_confirm.yes );             \n\tMenu_AddItem( &s_confirm.menu,\t&s_confirm.no );\n\n\tUI_PushMenu( &s_confirm.menu );\n\n\tMenu_SetCursorToItem( &s_confirm.menu, &s_confirm.no );\n}\n\n/*\n=================\nUI_ConfirmMenu\n=================\n*/\nvoid UI_ConfirmMenu( const char *question, void (*draw)( void ), void (*action)( qboolean result ) ) {\n\tUI_ConfirmMenu_Style(question, UI_CENTER|UI_INVERSE, draw, action);\n}\n\n/*\n=================\nUI_Message\nhacked over from Confirm stuff\n=================\n*/\nvoid UI_Message( const char **lines ) {\n\tuiClientState_t\tcstate;\n\tint n1, l1;\n\t\n\t// zero set all our globals\n\tmemset( &s_confirm, 0, sizeof(s_confirm) );\n\n\tConfirmMenu_Cache();\n\n\tn1 = UI_ProportionalStringWidth( \"OK\" );\n\tl1 = 320 - ( n1 / 2 );\n\t\n\ts_confirm.lines = lines;\n\ts_confirm.style = UI_CENTER|UI_INVERSE|UI_SMALLFONT;\n\n\ts_confirm.menu.draw       = MessageMenu_Draw;\n\ts_confirm.menu.key        = ConfirmMenu_Key;\n\ts_confirm.menu.wrapAround = qtrue;\n\t\n\ttrap_GetClientState( &cstate );\n\tif ( cstate.connState >= CA_CONNECTED ) {\n\t\ts_confirm.menu.fullscreen = qfalse;\n\t}\n\telse {\n\t\ts_confirm.menu.fullscreen = qtrue;\n\t}\n\n\ts_confirm.yes.generic.type\t\t= MTYPE_PTEXT;      \n\ts_confirm.yes.generic.flags\t\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; \n\ts_confirm.yes.generic.callback\t= ConfirmMenu_Event;\n\ts_confirm.yes.generic.id\t\t= ID_CONFIRM_YES;\n\ts_confirm.yes.generic.x\t\t\t= l1;\n\ts_confirm.yes.generic.y\t\t\t= 280;\n\ts_confirm.yes.string\t\t\t= \"OK\";\n\ts_confirm.yes.color\t\t\t\t= color_red;\n\ts_confirm.yes.style\t\t\t\t= UI_LEFT;\n\n\tMenu_AddItem( &s_confirm.menu,\t&s_confirm.yes );\n\t\n\tUI_PushMenu( &s_confirm.menu );\n\n\tMenu_SetCursorToItem( &s_confirm.menu, &s_confirm.yes );\n}\n"
  },
  {
    "path": "src/q3_ui/ui_connect.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n#include \"ui_local.h\"\n\n/*\n===============================================================================\n\nCONNECTION SCREEN\n\n===============================================================================\n*/\n\nqboolean\tpasswordNeeded = qtrue;\nmenufield_s passwordField;\n\nstatic connstate_t\tlastConnState;\nstatic char\t\t\tlastLoadingText[MAX_INFO_VALUE];\n\nstatic void UI_ReadableSize ( char *buf, int bufsize, int value )\n{\n\tif (value > 1024*1024*1024 ) { // gigs\n\t\tCom_sprintf( buf, bufsize, \"%d\", value / (1024*1024*1024) );\n\t\tCom_sprintf( buf+(int)strlen(buf), bufsize-(int)strlen(buf), \".%02d GB\", \n\t\t\t(value % (1024*1024*1024))*100 / (1024*1024*1024) );\n\t} else if (value > 1024*1024 ) { // megs\n\t\tCom_sprintf( buf, bufsize, \"%d\", value / (1024*1024) );\n\t\tCom_sprintf( buf+(int)strlen(buf), bufsize-(int)strlen(buf), \".%02d MB\", \n\t\t\t(value % (1024*1024))*100 / (1024*1024) );\n\t} else if (value > 1024 ) { // kilos\n\t\tCom_sprintf( buf, bufsize, \"%d KB\", value / 1024 );\n\t} else { // bytes\n\t\tCom_sprintf( buf, bufsize, \"%d bytes\", value );\n\t}\n}\n\n// Assumes time is in msec\nstatic void UI_PrintTime ( char *buf, int bufsize, int time ) {\n\ttime /= 1000;  // change to seconds\n\n\tif (time > 3600) { // in the hours range\n\t\tCom_sprintf( buf, bufsize, \"%d hr %d min\", time / 3600, (time % 3600) / 60 );\n\t} else if (time > 60) { // mins\n\t\tCom_sprintf( buf, bufsize, \"%d min %d sec\", time / 60, time % 60 );\n\t} else  { // secs\n\t\tCom_sprintf( buf, bufsize, \"%d sec\", time );\n\t}\n}\n\nstatic void UI_DisplayDownloadInfo( const char *downloadName ) {\n\tstatic char dlText[]\t= \"Downloading:\";\n\tstatic char etaText[]\t= \"Estimated time left:\";\n\tstatic char xferText[]\t= \"Transfer rate:\";\n\n\tint downloadSize, downloadCount, downloadTime;\n\tchar dlSizeBuf[64], totalSizeBuf[64], xferRateBuf[64], dlTimeBuf[64];\n\tint xferRate;\n\tint width, leftWidth;\n\tint style = UI_LEFT|UI_SMALLFONT|UI_DROPSHADOW;\n\tconst char *s;\n\n\tdownloadSize = trap_Cvar_VariableValue( \"cl_downloadSize\" );\n\tdownloadCount = trap_Cvar_VariableValue( \"cl_downloadCount\" );\n\tdownloadTime = trap_Cvar_VariableValue( \"cl_downloadTime\" );\n\n#if 0 // bk010104\n\tfprintf( stderr, \"\\n\\n-----------------------------------------------\\n\");\n\tfprintf( stderr, \"DB: downloadSize:  %16d\\n\", downloadSize );\n\tfprintf( stderr, \"DB: downloadCount: %16d\\n\", downloadCount );\n\tfprintf( stderr, \"DB: downloadTime:  %16d\\n\", downloadTime );  \n  \tfprintf( stderr, \"DB: UI realtime:   %16d\\n\", uis.realtime );\t// bk\n\tfprintf( stderr, \"DB: UI frametime:  %16d\\n\", uis.frametime );\t// bk\n#endif\n\n\tleftWidth = width = UI_ProportionalStringWidth( dlText ) * UI_ProportionalSizeScale( style );\n\twidth = UI_ProportionalStringWidth( etaText ) * UI_ProportionalSizeScale( style );\n\tif (width > leftWidth) leftWidth = width;\n\twidth = UI_ProportionalStringWidth( xferText ) * UI_ProportionalSizeScale( style );\n\tif (width > leftWidth) leftWidth = width;\n\tleftWidth += 16;\n\n\tUI_DrawProportionalString( 8, 128, dlText, style, color_white );\n\tUI_DrawProportionalString( 8, 160, etaText, style, color_white );\n\tUI_DrawProportionalString( 8, 224, xferText, style, color_white );\n\n\tif (downloadSize > 0) {\n\t\ts = va( \"%s (%d%%)\", downloadName, downloadCount * 100 / downloadSize );\n\t} else {\n\t\ts = downloadName;\n\t}\n\n\tUI_DrawProportionalString( leftWidth, 128, s, style, color_white );\n\n\tUI_ReadableSize( dlSizeBuf,\t\tsizeof dlSizeBuf,\t\tdownloadCount );\n\tUI_ReadableSize( totalSizeBuf,\tsizeof totalSizeBuf,\tdownloadSize );\n\n\tif (downloadCount < 4096 || !downloadTime) {\n\t\tUI_DrawProportionalString( leftWidth, 160, \"estimating\", style, color_white );\n\t\tUI_DrawProportionalString( leftWidth, 192, \n\t\t\tva(\"(%s of %s copied)\", dlSizeBuf, totalSizeBuf), style, color_white );\n\t} else {\n\t  // bk010108\n\t  //float elapsedTime = (float)(uis.realtime - downloadTime); // current - start (msecs)\n\t  //elapsedTime = elapsedTime * 0.001f; // in seconds\n\t  //if ( elapsedTime <= 0.0f ) elapsedTime == 0.0f;\n\t  if ( (uis.realtime - downloadTime) / 1000) {\n\t\t\txferRate = downloadCount / ((uis.realtime - downloadTime) / 1000);\n\t\t  //xferRate = (int)( ((float)downloadCount) / elapsedTime);\n\t\t} else {\n\t\t\txferRate = 0;\n\t\t}\n\n\t  //fprintf( stderr, \"DB: elapsedTime:  %16.8f\\n\", elapsedTime );\t// bk\n\t  //fprintf( stderr, \"DB: xferRate:   %16d\\n\", xferRate );\t// bk\n\n\t\tUI_ReadableSize( xferRateBuf, sizeof xferRateBuf, xferRate );\n\n\t\t// Extrapolate estimated completion time\n\t\tif (downloadSize && xferRate) {\n\t\t\tint n = downloadSize / xferRate; // estimated time for entire d/l in secs\n\n\t\t\t// We do it in K (/1024) because we'd overflow around 4MB\n\t\t\tn = (n - (((downloadCount/1024) * n) / (downloadSize/1024))) * 1000;\n\t\t\t\n\t\t\tUI_PrintTime ( dlTimeBuf, sizeof dlTimeBuf, n ); // bk010104\n\t\t\t\t//(n - (((downloadCount/1024) * n) / (downloadSize/1024))) * 1000);\n\n\t\t\tUI_DrawProportionalString( leftWidth, 160, \n\t\t\t\tdlTimeBuf, style, color_white );\n\t\t\tUI_DrawProportionalString( leftWidth, 192, \n\t\t\t\tva(\"(%s of %s copied)\", dlSizeBuf, totalSizeBuf), style, color_white );\n\t\t} else {\n\t\t\tUI_DrawProportionalString( leftWidth, 160, \n\t\t\t\t\"estimating\", style, color_white );\n\t\t\tif (downloadSize) {\n\t\t\t\tUI_DrawProportionalString( leftWidth, 192, \n\t\t\t\t\tva(\"(%s of %s copied)\", dlSizeBuf, totalSizeBuf), style, color_white );\n\t\t\t} else {\n\t\t\t\tUI_DrawProportionalString( leftWidth, 192, \n\t\t\t\t\tva(\"(%s copied)\", dlSizeBuf), style, color_white );\n\t\t\t}\n\t\t}\n\n\t\tif (xferRate) {\n\t\t\tUI_DrawProportionalString( leftWidth, 224, \n\t\t\t\tva(\"%s/Sec\", xferRateBuf), style, color_white );\n\t\t}\n\t}\n}\n\n/*\n========================\nUI_DrawConnectScreen\n\nThis will also be overlaid on the cgame info screen during loading\nto prevent it from blinking away too rapidly on local or lan games.\n========================\n*/\nvoid UI_DrawConnectScreen( qboolean overlay ) {\n\tchar\t\t\t*s;\n\tuiClientState_t\tcstate;\n\tchar\t\t\tinfo[MAX_INFO_VALUE];\n\n\tMenu_Cache();\n\n\tif ( !overlay ) {\n\t\t// draw the dialog background\n\t\tUI_SetColor( color_white );\n\t\tUI_DrawHandlePic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, uis.menuBackShader );\n\t}\n\n\t// see what information we should display\n\ttrap_GetClientState( &cstate );\n\n\tinfo[0] = '\\0';\n\tif( trap_GetConfigString( CS_SERVERINFO, info, sizeof(info) ) ) {\n\t\tUI_DrawProportionalString( 320, 16, va( \"Loading %s\", Info_ValueForKey( info, \"mapname\" ) ), UI_BIGFONT|UI_CENTER|UI_DROPSHADOW, color_white );\n\t}\n\n\tUI_DrawProportionalString( 320, 64, va(\"Connecting to %s\", cstate.servername), UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, menu_text_color );\n\t//UI_DrawProportionalString( 320, 96, \"Press Esc to abort\", UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, menu_text_color );\n\n\t// display global MOTD at bottom\n\tUI_DrawProportionalString( SCREEN_WIDTH/2, SCREEN_HEIGHT-32, \n\t\tInfo_ValueForKey( cstate.updateInfoString, \"motd\" ), UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, menu_text_color );\n\t\n\t// print any server info (server full, bad version, etc)\n\tif ( cstate.connState < CA_CONNECTED ) {\n\t\tUI_DrawProportionalString_AutoWrapped( 320, 192, 630, 20, cstate.messageString, UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, menu_text_color );\n\t}\n\n#if 0\n\t// display password field\n\tif ( passwordNeeded ) {\n\t\ts_ingame_menu.x = SCREEN_WIDTH * 0.50 - 128;\n\t\ts_ingame_menu.nitems = 0;\n\t\ts_ingame_menu.wrapAround = qtrue;\n\n\t\tpasswordField.generic.type = MTYPE_FIELD;\n\t\tpasswordField.generic.name = \"Password:\";\n\t\tpasswordField.generic.callback = 0;\n\t\tpasswordField.generic.x\t\t= 10;\n\t\tpasswordField.generic.y\t\t= 180;\n\t\tField_Clear( &passwordField.field );\n\t\tpasswordField.width = 256;\n\t\tpasswordField.field.widthInChars = 16;\n\t\tQ_strncpyz( passwordField.field.buffer, Cvar_VariableString(\"password\"), \n\t\t\tsizeof(passwordField.field.buffer) );\n\n\t\tMenu_AddItem( &s_ingame_menu, ( void * ) &s_customize_player_action );\n\n\t\tMField_Draw( &passwordField );\n\t}\n#endif\n\n\tif ( lastConnState > cstate.connState ) {\n\t\tlastLoadingText[0] = '\\0';\n\t}\n\tlastConnState = cstate.connState;\n\n\tswitch ( cstate.connState ) {\n\tcase CA_CONNECTING:\n\t\ts = va(\"Awaiting challenge...%i\", cstate.connectPacketCount);\n\t\tbreak;\n\tcase CA_CHALLENGING:\n\t\ts = va(\"Awaiting connection...%i\", cstate.connectPacketCount);\n\t\tbreak;\n\tcase CA_CONNECTED: {\n\t\tchar downloadName[MAX_INFO_VALUE];\n\n\t\t\ttrap_Cvar_VariableStringBuffer( \"cl_downloadName\", downloadName, sizeof(downloadName) );\n\t\t\tif (*downloadName) {\n\t\t\t\tUI_DisplayDownloadInfo( downloadName );\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\ts = \"Awaiting gamestate...\";\n\t\tbreak;\n\tcase CA_LOADING:\n\t\treturn;\n\tcase CA_PRIMED:\n\t\treturn;\n\tdefault:\n\t\treturn;\n\t}\n\n\tUI_DrawProportionalString( 320, 128, s, UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, color_white );\n\n\t// password required / connection rejected information goes here\n}\n\n\n/*\n===================\nUI_KeyConnect\n===================\n*/\nvoid UI_KeyConnect( int key ) {\n\tif ( key == K_ESCAPE ) {\n\t\ttrap_Cmd_ExecuteText( EXEC_APPEND, \"disconnect\\n\" );\n\t\treturn;\n\t}\n}\n"
  },
  {
    "path": "src/q3_ui/ui_controls2.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n/*\n=======================================================================\n\nCONTROLS MENU\n\n=======================================================================\n*/\n\n\n#include \"ui_local.h\"\n\n#define ART_BACK0\t\t\t\"menu/art/back_0\"\n#define ART_BACK1\t\t\t\"menu/art/back_1\"\n#define ART_FRAMEL\t\t\t\"menu/art/frame2_l\"\n#define ART_FRAMER\t\t\t\"menu/art/frame1_r\"\n\n\ntypedef struct {\n\tchar\t*command;\n\tchar\t*label;\n\tint\t\tid;\n\tint\t\tanim;\n\tint\t\tdefaultbind1;\n\tint\t\tdefaultbind2;\n\tint\t\tbind1;\n\tint\t\tbind2;\n} bind_t;\n\ntypedef struct\n{\n\tchar*\tname;\n\tfloat\tdefaultvalue;\n\tfloat\tvalue;\t\n} configcvar_t;\n\n#define SAVE_NOOP\t\t0\n#define SAVE_YES\t\t1\n#define SAVE_NO\t\t\t2\n#define SAVE_CANCEL\t\t3\n\n// control sections\n#define C_MOVEMENT\t\t0\n#define C_LOOKING\t\t1\n#define C_WEAPONS\t\t2\n#define C_MISC\t\t\t3\n#define C_MAX\t\t\t4\n\n#define ID_MOVEMENT\t\t100\n#define ID_LOOKING\t\t101\n#define ID_WEAPONS\t\t102\n#define ID_MISC\t\t\t103\n#define ID_DEFAULTS\t\t104\n#define ID_BACK\t\t\t105\n#define ID_SAVEANDEXIT\t106\n#define ID_EXIT\t\t\t107\n\n// bindable actions\n#define ID_SHOWSCORES\t0\n#define ID_USEITEM\t\t1\t\n#define ID_SPEED\t\t2\t\n#define ID_FORWARD\t\t3\t\n#define ID_BACKPEDAL\t4\n#define ID_MOVELEFT\t\t5\n#define ID_MOVERIGHT\t6\n#define ID_MOVEUP\t\t7\t\n#define ID_MOVEDOWN\t\t8\n#define ID_LEFT\t\t\t9\t\n#define ID_RIGHT\t\t10\t\n#define ID_STRAFE\t\t11\t\n#define ID_LOOKUP\t\t12\t\n#define ID_LOOKDOWN\t\t13\n#define ID_MOUSELOOK\t14\n#define ID_CENTERVIEW\t15\n#define ID_ZOOMVIEW\t\t16\n#define ID_WEAPON1\t\t17\t\n#define ID_WEAPON2\t\t18\t\n#define ID_WEAPON3\t\t19\t\n#define ID_WEAPON4\t\t20\t\n#define ID_WEAPON5\t\t21\t\n#define ID_WEAPON6\t\t22\t\n#define ID_WEAPON7\t\t23\t\n#define ID_WEAPON8\t\t24\t\n#define ID_WEAPON9\t\t25\t\n#define ID_ATTACK\t\t26\n#define ID_WEAPPREV\t\t27\n#define ID_WEAPNEXT\t\t28\n#define ID_GESTURE\t\t29\n#define ID_CHAT\t\t\t30\n#define ID_CHAT2\t\t31\n#define ID_CHAT3\t\t32\n#define ID_CHAT4\t\t33\n\n// all others\n#define ID_FREELOOK\t\t34\n#define ID_INVERTMOUSE\t35\n#define ID_ALWAYSRUN\t36\n#define ID_AUTOSWITCH\t37\n#define ID_MOUSESPEED\t38\n#define ID_SMOOTHMOUSE\t41\n\n#define ANIM_IDLE\t\t0\n#define ANIM_RUN\t\t1\n#define ANIM_WALK\t\t2\n#define ANIM_BACK\t\t3\n#define ANIM_JUMP\t\t4\n#define ANIM_CROUCH\t\t5\n#define ANIM_STEPLEFT\t6\n#define ANIM_STEPRIGHT\t7\n#define ANIM_TURNLEFT\t8\n#define ANIM_TURNRIGHT\t9\n#define ANIM_LOOKUP\t\t10\n#define ANIM_LOOKDOWN\t11\n#define ANIM_WEAPON1\t12\n#define ANIM_WEAPON2\t13\n#define ANIM_WEAPON3\t14\n#define ANIM_WEAPON4\t15\n#define ANIM_WEAPON5\t16\n#define ANIM_WEAPON6\t17\n#define ANIM_WEAPON7\t18\n#define ANIM_WEAPON8\t19\n#define ANIM_WEAPON9\t20\n#define ANIM_WEAPON10\t21\n#define ANIM_ATTACK\t\t22\n#define ANIM_GESTURE\t23\n#define ANIM_DIE\t\t24\n#define ANIM_CHAT\t\t25\n\ntypedef struct\n{\n\tmenuframework_s\t\tmenu;\n\n\tmenutext_s\t\t\tbanner;\n\tmenubitmap_s\t\tframel;\n\tmenubitmap_s\t\tframer;\n\tmenubitmap_s\t\tplayer;\n\n\tmenutext_s\t\t\tmovement;\n\tmenutext_s\t\t\tlooking;\n\tmenutext_s\t\t\tweapons;\n\tmenutext_s\t\t\tmisc;\n\n\tmenuaction_s\t\twalkforward;\n\tmenuaction_s\t\tbackpedal;\n\tmenuaction_s\t\tstepleft;\n\tmenuaction_s\t\tstepright;\n\tmenuaction_s\t\tmoveup;\n\tmenuaction_s\t\tmovedown;\n\tmenuaction_s\t\tturnleft;\n\tmenuaction_s\t\tturnright;\n\tmenuaction_s\t\tsidestep;\n\tmenuaction_s\t\trun;\n\tmenuaction_s\t\tmachinegun;\n\tmenuaction_s\t\tchainsaw;\n\tmenuaction_s\t\tshotgun;\n\tmenuaction_s\t\tgrenadelauncher;\n\tmenuaction_s\t\trocketlauncher;\n\tmenuaction_s\t\tlightning;\n\tmenuaction_s\t\trailgun;\n\tmenuaction_s\t\tplasma;\n\tmenuaction_s\t\tbfg;\n\tmenuaction_s\t\tattack;\n\tmenuaction_s\t\tprevweapon;\n\tmenuaction_s\t\tnextweapon;\n\tmenuaction_s\t\tlookup;\n\tmenuaction_s\t\tlookdown;\n\tmenuaction_s\t\tmouselook;\n\tmenuradiobutton_s\tfreelook;\n\tmenuaction_s\t\tcenterview;\n\tmenuaction_s\t\tzoomview;\n\tmenuaction_s\t\tgesture;\n\tmenuradiobutton_s\tinvertmouse;\n\tmenuslider_s\t\tsensitivity;\n\tmenuradiobutton_s\tsmoothmouse;\n\tmenuradiobutton_s\talwaysrun;\n\tmenuaction_s\t\tshowscores;\n\tmenuradiobutton_s\tautoswitch;\n\tmenuaction_s\t\tuseitem;\n\tplayerInfo_t\t\tplayerinfo;\n\tqboolean\t\t\tchangesmade;\n\tmenuaction_s\t\tchat;\n\tmenuaction_s\t\tchat2;\n\tmenuaction_s\t\tchat3;\n\tmenuaction_s\t\tchat4;\n\tint\t\t\t\t\tsection;\n\tqboolean\t\t\twaitingforkey;\n\tchar\t\t\t\tplayerModel[64];\n\tvec3_t\t\t\t\tplayerViewangles;\n\tvec3_t\t\t\t\tplayerMoveangles;\n\tint\t\t\t\t\tplayerLegs;\n\tint\t\t\t\t\tplayerTorso;\n\tint\t\t\t\t\tplayerWeapon;\n\tqboolean\t\t\tplayerChat;\n\n\tmenubitmap_s\t\tback;\n\tmenutext_s\t\t\tname;\n} controls_t; \t\n\nstatic controls_t s_controls;\n\nstatic vec4_t controls_binding_color  = {1.00f, 0.43f, 0.00f, 1.00f}; // bk: Win32 C4305\n\nstatic bind_t g_bindings[] = \n{\n\t{\"+scores\",\t\t\t\"show scores\",\t\tID_SHOWSCORES,\tANIM_IDLE,\t\tK_TAB,\t\t\t-1,\t\t-1, -1},\n\t{\"+button2\",\t\t\"use item\",\t\t\tID_USEITEM,\t\tANIM_IDLE,\t\tK_ENTER,\t\t-1,\t\t-1, -1},\n\t{\"+speed\", \t\t\t\"run / walk\",\t\tID_SPEED,\t\tANIM_RUN,\t\tK_SHIFT,\t\t-1,\t\t-1,\t-1},\n\t{\"+forward\", \t\t\"walk forward\",\t\tID_FORWARD,\t\tANIM_WALK,\t\tK_UPARROW,\t\t-1,\t\t-1, -1},\n\t{\"+back\", \t\t\t\"backpedal\",\t\tID_BACKPEDAL,\tANIM_BACK,\t\tK_DOWNARROW,\t-1,\t\t-1, -1},\n\t{\"+moveleft\", \t\t\"step left\",\t\tID_MOVELEFT,\tANIM_STEPLEFT,\t',',\t\t\t-1,\t\t-1, -1},\n\t{\"+moveright\", \t\t\"step right\",\t\tID_MOVERIGHT,\tANIM_STEPRIGHT,\t'.',\t\t\t-1,\t\t-1, -1},\n\t{\"+moveup\",\t\t\t\"up / jump\",\t\tID_MOVEUP,\t\tANIM_JUMP,\t\tK_SPACE,\t\t-1,\t\t-1, -1},\n\t{\"+movedown\",\t\t\"down / crouch\",\tID_MOVEDOWN,\tANIM_CROUCH,\t'c',\t\t\t-1,\t\t-1, -1},\n\t{\"+left\", \t\t\t\"turn left\",\t\tID_LEFT,\t\tANIM_TURNLEFT,\tK_LEFTARROW,\t-1,\t\t-1, -1},\n\t{\"+right\", \t\t\t\"turn right\",\t\tID_RIGHT,\t\tANIM_TURNRIGHT,\tK_RIGHTARROW,\t-1,\t\t-1, -1},\n\t{\"+strafe\", \t\t\"sidestep / turn\",\tID_STRAFE,\t\tANIM_IDLE,\t\tK_ALT,\t\t\t-1,\t\t-1, -1},\n\t{\"+lookup\", \t\t\"look up\",\t\t\tID_LOOKUP,\t\tANIM_LOOKUP,\tK_PGDN,\t\t\t-1,\t\t-1, -1},\n\t{\"+lookdown\", \t\t\"look down\",\t\tID_LOOKDOWN,\tANIM_LOOKDOWN,\tK_DEL,\t\t\t-1,\t\t-1, -1},\n\t{\"+mlook\", \t\t\t\"mouse look\",\t\tID_MOUSELOOK,\tANIM_IDLE,\t\t'/',\t\t\t-1,\t\t-1, -1},\n\t{\"centerview\", \t\t\"center view\",\t\tID_CENTERVIEW,\tANIM_IDLE,\t\tK_END,\t\t\t-1,\t\t-1, -1},\n\t{\"+zoom\", \t\t\t\"zoom view\",\t\tID_ZOOMVIEW,\tANIM_IDLE,\t\t-1,\t\t\t\t-1,\t\t-1, -1},\n\t{\"weapon 1\",\t\t\"gauntlet\",\t\t\tID_WEAPON1,\t\tANIM_WEAPON1,\t'1',\t\t\t-1,\t\t-1, -1},\n\t{\"weapon 2\",\t\t\"machinegun\",\t\tID_WEAPON2,\t\tANIM_WEAPON2,\t'2',\t\t\t-1,\t\t-1, -1},\n\t{\"weapon 3\",\t\t\"shotgun\",\t\t\tID_WEAPON3,\t\tANIM_WEAPON3,\t'3',\t\t\t-1,\t\t-1, -1},\n\t{\"weapon 4\",\t\t\"grenade launcher\",\tID_WEAPON4,\t\tANIM_WEAPON4,\t'4',\t\t\t-1,\t\t-1, -1},\n\t{\"weapon 5\",\t\t\"rocket launcher\",\tID_WEAPON5,\t\tANIM_WEAPON5,\t'5',\t\t\t-1,\t\t-1, -1},\n\t{\"weapon 6\",\t\t\"lightning\",\t\tID_WEAPON6,\t\tANIM_WEAPON6,\t'6',\t\t\t-1,\t\t-1, -1},\n\t{\"weapon 7\",\t\t\"railgun\",\t\t\tID_WEAPON7,\t\tANIM_WEAPON7,\t'7',\t\t\t-1,\t\t-1, -1},\n\t{\"weapon 8\",\t\t\"plasma gun\",\t\tID_WEAPON8,\t\tANIM_WEAPON8,\t'8',\t\t\t-1,\t\t-1, -1},\n\t{\"weapon 9\",\t\t\"BFG\",\t\t\t\tID_WEAPON9,\t\tANIM_WEAPON9,\t'9',\t\t\t-1,\t\t-1, -1},\n\t{\"+attack\", \t\t\"attack\",\t\t\tID_ATTACK,\t\tANIM_ATTACK,\tK_CTRL,\t\t\t-1,\t\t-1, -1},\n\t{\"weapprev\",\t\t\"prev weapon\",\t\tID_WEAPPREV,\tANIM_IDLE,\t\t'[',\t\t\t-1,\t\t-1, -1},\n\t{\"weapnext\", \t\t\"next weapon\",\t\tID_WEAPNEXT,\tANIM_IDLE,\t\t']',\t\t\t-1,\t\t-1, -1},\n\t{\"+button3\", \t\t\"gesture\",\t\t\tID_GESTURE,\t\tANIM_GESTURE,\tK_MOUSE3,\t\t-1,\t\t-1, -1},\n\t{\"messagemode\", \t\"chat\",\t\t\t\tID_CHAT,\t\tANIM_CHAT,\t\t't',\t\t\t-1,\t\t-1, -1},\n\t{\"messagemode2\", \t\"chat - team\",\t\tID_CHAT2,\t\tANIM_CHAT,\t\t-1,\t\t\t\t-1,\t\t-1, -1},\n\t{\"messagemode3\", \t\"chat - target\",\tID_CHAT3,\t\tANIM_CHAT,\t\t-1,\t\t\t\t-1,\t\t-1, -1},\n\t{\"messagemode4\", \t\"chat - attacker\",\tID_CHAT4,\t\tANIM_CHAT,\t\t-1,\t\t\t\t-1,\t\t-1, -1},\n\t{(char*)NULL,\t\t(char*)NULL,\t\t0,\t\t\t\t0,\t\t\t\t-1,\t\t\t\t-1,\t\t-1,\t-1},\n};\n\nstatic configcvar_t g_configcvars[] =\n{\n\t{\"cl_run\",\t\t\t0,\t\t\t\t\t0},\n\t{\"m_pitch\",\t\t\t0,\t\t\t\t\t0},\n\t{\"cg_autoswitch\",\t0,\t\t\t\t\t0},\n\t{\"sensitivity\",\t\t0,\t\t\t\t\t0},\n\t{\"m_filter\",\t\t0,\t\t\t\t\t0},\n\t{\"cl_freelook\",\t\t0,\t\t\t\t\t0},\n\t{NULL,\t\t\t\t0,\t\t\t\t\t0}\n};\n\nstatic menucommon_s *g_movement_controls[] =\n{\n\t(menucommon_s *)&s_controls.alwaysrun,     \n\t(menucommon_s *)&s_controls.run,            \n\t(menucommon_s *)&s_controls.walkforward,\n\t(menucommon_s *)&s_controls.backpedal,\n\t(menucommon_s *)&s_controls.stepleft,      \n\t(menucommon_s *)&s_controls.stepright,     \n\t(menucommon_s *)&s_controls.moveup,        \n\t(menucommon_s *)&s_controls.movedown,      \n\t(menucommon_s *)&s_controls.turnleft,      \n\t(menucommon_s *)&s_controls.turnright,     \n\t(menucommon_s *)&s_controls.sidestep,\n\tNULL\n};\n\nstatic menucommon_s *g_weapons_controls[] = {\n\t(menucommon_s *)&s_controls.attack,           \n\t(menucommon_s *)&s_controls.nextweapon,\n\t(menucommon_s *)&s_controls.prevweapon,\n\t(menucommon_s *)&s_controls.autoswitch,    \n\t(menucommon_s *)&s_controls.chainsaw,         \n\t(menucommon_s *)&s_controls.machinegun,\n\t(menucommon_s *)&s_controls.shotgun,          \n\t(menucommon_s *)&s_controls.grenadelauncher,\n\t(menucommon_s *)&s_controls.rocketlauncher,   \n\t(menucommon_s *)&s_controls.lightning,   \n\t(menucommon_s *)&s_controls.railgun,          \n\t(menucommon_s *)&s_controls.plasma,           \n\t(menucommon_s *)&s_controls.bfg,              \n\tNULL,\n};\n\nstatic menucommon_s *g_looking_controls[] = {\n\t(menucommon_s *)&s_controls.sensitivity,\n\t(menucommon_s *)&s_controls.smoothmouse,\n\t(menucommon_s *)&s_controls.invertmouse,\n\t(menucommon_s *)&s_controls.lookup,\n\t(menucommon_s *)&s_controls.lookdown,\n\t(menucommon_s *)&s_controls.mouselook,\n\t(menucommon_s *)&s_controls.freelook,\n\t(menucommon_s *)&s_controls.centerview,\n\t(menucommon_s *)&s_controls.zoomview,\n\tNULL,\n};\n\nstatic menucommon_s *g_misc_controls[] = {\n\t(menucommon_s *)&s_controls.showscores, \n\t(menucommon_s *)&s_controls.useitem,\n\t(menucommon_s *)&s_controls.gesture,\n\t(menucommon_s *)&s_controls.chat,\n\t(menucommon_s *)&s_controls.chat2,\n\t(menucommon_s *)&s_controls.chat3,\n\t(menucommon_s *)&s_controls.chat4,\n\tNULL,\n};\n\nstatic menucommon_s **g_controls[] = {\n\tg_movement_controls,\n\tg_looking_controls,\n\tg_weapons_controls,\n\tg_misc_controls,\n};\n\n/*\n=================\nControls_InitCvars\n=================\n*/\nstatic void Controls_InitCvars( void )\n{\n\tint\t\t\t\ti;\n\tconfigcvar_t*\tcvarptr;\n\n\tcvarptr = g_configcvars;\n\tfor (i=0; ;i++,cvarptr++)\n\t{\n\t\tif (!cvarptr->name)\n\t\t\tbreak;\n\n\t\t// get current value\n\t\tcvarptr->value = trap_Cvar_VariableValue( cvarptr->name );\n\n\t\t// get default value\n\t\ttrap_Cvar_Reset( cvarptr->name );\n\t\tcvarptr->defaultvalue = trap_Cvar_VariableValue( cvarptr->name );\n\n\t\t// restore current value\n\t\ttrap_Cvar_SetValue( cvarptr->name, cvarptr->value );\n\t}\n}\n\n/*\n=================\nControls_GetCvarDefault\n=================\n*/\nstatic float Controls_GetCvarDefault( char* name )\n{\n\tconfigcvar_t*\tcvarptr;\n\tint\t\t\t\ti;\n\n\tcvarptr = g_configcvars;\n\tfor (i=0; ;i++,cvarptr++)\n\t{\n\t\tif (!cvarptr->name)\n\t\t\treturn (0);\n\n\t\tif (!strcmp(cvarptr->name,name))\n\t\t\tbreak;\n\t}\n\n\treturn (cvarptr->defaultvalue);\n}\n\n/*\n=================\nControls_GetCvarValue\n=================\n*/\nstatic float Controls_GetCvarValue( char* name )\n{\n\tconfigcvar_t*\tcvarptr;\n\tint\t\t\t\ti;\n\n\tcvarptr = g_configcvars;\n\tfor (i=0; ;i++,cvarptr++)\n\t{\n\t\tif (!cvarptr->name)\n\t\t\treturn (0);\n\n\t\tif (!strcmp(cvarptr->name,name))\n\t\t\tbreak;\n\t}\n\n\treturn (cvarptr->value);\n}\n\n\n/*\n=================\nControls_UpdateModel\n=================\n*/\nstatic void Controls_UpdateModel( int anim ) {\n\tVectorClear( s_controls.playerViewangles );\n\tVectorClear( s_controls.playerMoveangles );\n\ts_controls.playerViewangles[YAW] = 180 - 30;\n\ts_controls.playerMoveangles[YAW] = s_controls.playerViewangles[YAW];\n\ts_controls.playerLegs\t\t     = LEGS_IDLE;\n\ts_controls.playerTorso\t\t\t = TORSO_STAND;\n\ts_controls.playerWeapon\t\t\t = -1;\n\ts_controls.playerChat\t\t\t = qfalse;\n\n\tswitch( anim ) {\n\tcase ANIM_RUN:\t\n\t\ts_controls.playerLegs = LEGS_RUN;\n\t\tbreak;\n\n\tcase ANIM_WALK:\t\n\t\ts_controls.playerLegs = LEGS_WALK;\n\t\tbreak;\n\n\tcase ANIM_BACK:\t\n\t\ts_controls.playerLegs = LEGS_BACK;\n\t\tbreak;\n\n\tcase ANIM_JUMP:\t\n\t\ts_controls.playerLegs = LEGS_JUMP;\n\t\tbreak;\n\n\tcase ANIM_CROUCH:\t\n\t\ts_controls.playerLegs = LEGS_IDLECR;\n\t\tbreak;\n\n\tcase ANIM_TURNLEFT:\n\t\ts_controls.playerViewangles[YAW] += 90;\n\t\tbreak;\n\n\tcase ANIM_TURNRIGHT:\n\t\ts_controls.playerViewangles[YAW] -= 90;\n\t\tbreak;\n\n\tcase ANIM_STEPLEFT:\n\t\ts_controls.playerLegs = LEGS_WALK;\n\t\ts_controls.playerMoveangles[YAW] = s_controls.playerViewangles[YAW] + 90;\n\t\tbreak;\n\n\tcase ANIM_STEPRIGHT:\n\t\ts_controls.playerLegs = LEGS_WALK;\n\t\ts_controls.playerMoveangles[YAW] = s_controls.playerViewangles[YAW] - 90;\n\t\tbreak;\n\n\tcase ANIM_LOOKUP:\n\t\ts_controls.playerViewangles[PITCH] = -45;\n\t\tbreak;\n\n\tcase ANIM_LOOKDOWN:\n\t\ts_controls.playerViewangles[PITCH] = 45;\n\t\tbreak;\n\n\tcase ANIM_WEAPON1:\n\t\ts_controls.playerWeapon = WP_GAUNTLET;\n\t\tbreak;\n\n\tcase ANIM_WEAPON2:\n\t\ts_controls.playerWeapon = WP_MACHINEGUN;\n\t\tbreak;\n\n\tcase ANIM_WEAPON3:\n\t\ts_controls.playerWeapon = WP_SHOTGUN;\n\t\tbreak;\n\n\tcase ANIM_WEAPON4:\n\t\ts_controls.playerWeapon = WP_GRENADE_LAUNCHER;\n\t\tbreak;\n\n\tcase ANIM_WEAPON5:\n\t\ts_controls.playerWeapon = WP_ROCKET_LAUNCHER;\n\t\tbreak;\n\n\tcase ANIM_WEAPON6:\n\t\ts_controls.playerWeapon = WP_LIGHTNING;\n\t\tbreak;\n\n\tcase ANIM_WEAPON7:\n\t\ts_controls.playerWeapon = WP_RAILGUN;\n\t\tbreak;\n\n\tcase ANIM_WEAPON8:\n\t\ts_controls.playerWeapon = WP_PLASMAGUN;\n\t\tbreak;\n\n\tcase ANIM_WEAPON9:\n\t\ts_controls.playerWeapon = WP_BFG;\n\t\tbreak;\n\n\tcase ANIM_WEAPON10:\n\t\ts_controls.playerWeapon = WP_GRAPPLING_HOOK;\n\t\tbreak;\n\n\tcase ANIM_ATTACK:\n\t\ts_controls.playerTorso = TORSO_ATTACK;\n\t\tbreak;\n\n\tcase ANIM_GESTURE:\n\t\ts_controls.playerTorso = TORSO_GESTURE;\n\t\tbreak;\n\n\tcase ANIM_DIE:\n\t\ts_controls.playerLegs = BOTH_DEATH1;\n\t\ts_controls.playerTorso = BOTH_DEATH1;\n\t\ts_controls.playerWeapon = WP_NONE;\n\t\tbreak;\n\n\tcase ANIM_CHAT:\n\t\ts_controls.playerChat = qtrue;\n\t\tbreak;\n\n\tdefault:\n\t\tbreak;\n\t}\n\n\tUI_PlayerInfo_SetInfo( &s_controls.playerinfo, s_controls.playerLegs, s_controls.playerTorso, s_controls.playerViewangles, s_controls.playerMoveangles, s_controls.playerWeapon, s_controls.playerChat );\n}\n\n\n/*\n=================\nControls_Update\n=================\n*/\nstatic void Controls_Update( void ) {\n\tint\t\ti;\n\tint\t\tj;\n\tint\t\ty;\n\tmenucommon_s\t**controls;\n\tmenucommon_s\t*control;\n\n\t// disable all controls in all groups\n\tfor( i = 0; i < C_MAX; i++ ) {\n\t\tcontrols = g_controls[i];\n\t\t// bk001204 - parentheses\n\t\tfor( j = 0;  (control = controls[j]) ; j++ ) {\n\t\t\tcontrol->flags |= (QMF_HIDDEN|QMF_INACTIVE);\n\t\t}\n\t}\n\n\tcontrols = g_controls[s_controls.section];\n\n\t// enable controls in active group (and count number of items for vertical centering)\n\t// bk001204 - parentheses\n\tfor( j = 0;  (control = controls[j]) ; j++ ) {\n\t\tcontrol->flags &= ~(QMF_GRAYED|QMF_HIDDEN|QMF_INACTIVE);\n\t}\n\n\t// position controls\n\ty = ( SCREEN_HEIGHT - j * SMALLCHAR_HEIGHT ) / 2;\n\t// bk001204 - parentheses\n\tfor( j = 0;\t(control = controls[j]) ; j++, y += SMALLCHAR_HEIGHT ) {\n\t\tcontrol->x      = 320;\n\t\tcontrol->y      = y;\n\t\tcontrol->left   = 320 - 19*SMALLCHAR_WIDTH;\n\t\tcontrol->right  = 320 + 21*SMALLCHAR_WIDTH;\n\t\tcontrol->top    = y;\n\t\tcontrol->bottom = y + SMALLCHAR_HEIGHT;\n\t}\n\n\tif( s_controls.waitingforkey ) {\n\t\t// disable everybody\n\t\tfor( i = 0; i < s_controls.menu.nitems; i++ ) {\n\t\t\t((menucommon_s*)(s_controls.menu.items[i]))->flags |= QMF_GRAYED;\n\t\t}\n\n\t\t// enable action item\n\t\t((menucommon_s*)(s_controls.menu.items[s_controls.menu.cursor]))->flags &= ~QMF_GRAYED;\n\n\t\t// don't gray out player's name\n\t\ts_controls.name.generic.flags &= ~QMF_GRAYED;\n\n\t\treturn;\n\t}\n\n\t// enable everybody\n\tfor( i = 0; i < s_controls.menu.nitems; i++ ) {\n\t\t((menucommon_s*)(s_controls.menu.items[i]))->flags &= ~QMF_GRAYED;\n\t}\n\n\t// makes sure flags are right on the group selection controls\n\ts_controls.looking.generic.flags  &= ~(QMF_GRAYED|QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS);\n\ts_controls.movement.generic.flags &= ~(QMF_GRAYED|QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS);\n\ts_controls.weapons.generic.flags  &= ~(QMF_GRAYED|QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS);\n\ts_controls.misc.generic.flags     &= ~(QMF_GRAYED|QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS);\n\n\ts_controls.looking.generic.flags  |= QMF_PULSEIFFOCUS;\n\ts_controls.movement.generic.flags |= QMF_PULSEIFFOCUS;\n\ts_controls.weapons.generic.flags  |= QMF_PULSEIFFOCUS;\n\ts_controls.misc.generic.flags     |= QMF_PULSEIFFOCUS;\n\n\t// set buttons\n\tswitch( s_controls.section ) {\n\tcase C_MOVEMENT:\n\t\ts_controls.movement.generic.flags &= ~QMF_PULSEIFFOCUS;\n\t\ts_controls.movement.generic.flags |= (QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS);\n\t\tbreak;\n\t\n\tcase C_LOOKING:\n\t\ts_controls.looking.generic.flags &= ~QMF_PULSEIFFOCUS;\n\t\ts_controls.looking.generic.flags |= (QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS);\n\t\tbreak;\n\t\n\tcase C_WEAPONS:\n\t\ts_controls.weapons.generic.flags &= ~QMF_PULSEIFFOCUS;\n\t\ts_controls.weapons.generic.flags |= (QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS);\n\t\tbreak;\t\t\n\n\tcase C_MISC:\n\t\ts_controls.misc.generic.flags &= ~QMF_PULSEIFFOCUS;\n\t\ts_controls.misc.generic.flags |= (QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS);\n\t\tbreak;\n\t}\n}\n\n\n/*\n=================\nControls_DrawKeyBinding\n=================\n*/\nstatic void Controls_DrawKeyBinding( void *self )\n{\n\tmenuaction_s*\ta;\n\tint\t\t\t\tx;\n\tint\t\t\t\ty;\n\tint\t\t\t\tb1;\n\tint\t\t\t\tb2;\n\tqboolean\t\tc;\n\tchar\t\t\tname[32];\n\tchar\t\t\tname2[32];\n\n\ta = (menuaction_s*) self;\n\n\tx =\ta->generic.x;\n\ty = a->generic.y;\n\n\tc = (Menu_ItemAtCursor( a->generic.parent ) == a);\n\n\tb1 = g_bindings[a->generic.id].bind1;\n\tif (b1 == -1)\n\t\tstrcpy(name,\"???\");\n\telse\n\t{\n\t\ttrap_Key_KeynumToStringBuf( b1, name, 32 );\n\t\tQ_strupr(name);\n\n\t\tb2 = g_bindings[a->generic.id].bind2;\n\t\tif (b2 != -1)\n\t\t{\n\t\t\ttrap_Key_KeynumToStringBuf( b2, name2, 32 );\n\t\t\tQ_strupr(name2);\n\n\t\t\tstrcat( name, \" or \" );\n\t\t\tstrcat( name, name2 );\n\t\t}\n\t}\n\n\tif (c)\n\t{\n\t\tUI_FillRect( a->generic.left, a->generic.top, a->generic.right-a->generic.left+1, a->generic.bottom-a->generic.top+1, listbar_color ); \n\n\t\tUI_DrawString( x - SMALLCHAR_WIDTH, y, g_bindings[a->generic.id].label, UI_RIGHT|UI_SMALLFONT, text_color_highlight );\n\t\tUI_DrawString( x + SMALLCHAR_WIDTH, y, name, UI_LEFT|UI_SMALLFONT|UI_PULSE, text_color_highlight );\n\n\t\tif (s_controls.waitingforkey)\n\t\t{\n\t\t\tUI_DrawChar( x, y, '=', UI_CENTER|UI_BLINK|UI_SMALLFONT, text_color_highlight);\n\t\t\tUI_DrawString(SCREEN_WIDTH * 0.50, SCREEN_HEIGHT * 0.80, \"Waiting for new key ... ESCAPE to cancel\", UI_SMALLFONT|UI_CENTER|UI_PULSE, colorWhite );\n\t\t}\n\t\telse\n\t\t{\n\t\t\tUI_DrawChar( x, y, 13, UI_CENTER|UI_BLINK|UI_SMALLFONT, text_color_highlight);\n\t\t\tUI_DrawString(SCREEN_WIDTH * 0.50, SCREEN_HEIGHT * 0.78, \"Press ENTER or CLICK to change\", UI_SMALLFONT|UI_CENTER, colorWhite );\n\t\t\tUI_DrawString(SCREEN_WIDTH * 0.50, SCREEN_HEIGHT * 0.82, \"Press BACKSPACE to clear\", UI_SMALLFONT|UI_CENTER, colorWhite );\n\t\t}\n\t}\n\telse\n\t{\n\t\tif (a->generic.flags & QMF_GRAYED)\n\t\t{\n\t\t\tUI_DrawString( x - SMALLCHAR_WIDTH, y, g_bindings[a->generic.id].label, UI_RIGHT|UI_SMALLFONT, text_color_disabled );\n\t\t\tUI_DrawString( x + SMALLCHAR_WIDTH, y, name, UI_LEFT|UI_SMALLFONT, text_color_disabled );\n\t\t}\n\t\telse\n\t\t{\n\t\t\tUI_DrawString( x - SMALLCHAR_WIDTH, y, g_bindings[a->generic.id].label, UI_RIGHT|UI_SMALLFONT, controls_binding_color );\n\t\t\tUI_DrawString( x + SMALLCHAR_WIDTH, y, name, UI_LEFT|UI_SMALLFONT, controls_binding_color );\n\t\t}\n\t}\n}\n\n/*\n=================\nControls_StatusBar\n=================\n*/\nstatic void Controls_StatusBar( void *self )\n{\n\tUI_DrawString(SCREEN_WIDTH * 0.50, SCREEN_HEIGHT * 0.80, \"Use Arrow Keys or CLICK to change\", UI_SMALLFONT|UI_CENTER, colorWhite );\n}\n\n\n/*\n=================\nControls_DrawPlayer\n=================\n*/\nstatic void Controls_DrawPlayer( void *self ) {\n\tmenubitmap_s\t*b;\n\tchar\t\t\tbuf[MAX_QPATH];\n\n\ttrap_Cvar_VariableStringBuffer( \"model\", buf, sizeof( buf ) );\n\tif ( strcmp( buf, s_controls.playerModel ) != 0 ) {\n\t\tUI_PlayerInfo_SetModel( &s_controls.playerinfo, buf );\n\t\tstrcpy( s_controls.playerModel, buf );\n\t\tControls_UpdateModel( ANIM_IDLE );\n\t}\n\n\tb = (menubitmap_s*) self;\n\tUI_DrawPlayer( b->generic.x, b->generic.y, b->width, b->height, &s_controls.playerinfo, uis.realtime/2 );\n}\n\n\n/*\n=================\nControls_GetKeyAssignment\n=================\n*/\nstatic void Controls_GetKeyAssignment (char *command, int *twokeys)\n{\n\tint\t\tcount;\n\tint\t\tj;\n\tchar\tb[256];\n\n\ttwokeys[0] = twokeys[1] = -1;\n\tcount = 0;\n\n\tfor ( j = 0; j < 256; j++ )\n\t{\n\t\ttrap_Key_GetBindingBuf( j, b, 256 );\n\t\tif ( *b == 0 ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( !Q_stricmp( b, command ) ) {\n\t\t\ttwokeys[count] = j;\n\t\t\tcount++;\n\t\t\tif (count == 2)\n\t\t\t\tbreak;\n\t\t}\n\t}\n}\n\n/*\n=================\nControls_GetConfig\n=================\n*/\nstatic void Controls_GetConfig( void )\n{\n\tint\t\ti;\n\tint\t\ttwokeys[2];\n\tbind_t*\tbindptr;\n\n\t// put the bindings into a local store\n\tbindptr = g_bindings;\n\n\t// iterate each command, get its numeric binding\n\tfor (i=0; ;i++,bindptr++)\n\t{\n\t\tif (!bindptr->label)\n\t\t\tbreak;\n\n\t\tControls_GetKeyAssignment(bindptr->command, twokeys);\n\n\t\tbindptr->bind1 = twokeys[0];\n\t\tbindptr->bind2 = twokeys[1];\n\t}\n\n\ts_controls.invertmouse.curvalue  = Controls_GetCvarValue( \"m_pitch\" ) < 0;\n\ts_controls.smoothmouse.curvalue  = UI_ClampCvar( 0, 1, Controls_GetCvarValue( \"m_filter\" ) );\n\ts_controls.alwaysrun.curvalue    = UI_ClampCvar( 0, 1, Controls_GetCvarValue( \"cl_run\" ) );\n\ts_controls.autoswitch.curvalue   = UI_ClampCvar( 0, 1, Controls_GetCvarValue( \"cg_autoswitch\" ) );\n\ts_controls.sensitivity.curvalue  = UI_ClampCvar( 2, 30, Controls_GetCvarValue( \"sensitivity\" ) );\n\ts_controls.freelook.curvalue     = UI_ClampCvar( 0, 1, Controls_GetCvarValue( \"cl_freelook\" ) );\n}\n\n/*\n=================\nControls_SetConfig\n=================\n*/\nstatic void Controls_SetConfig( void )\n{\n\tint\t\ti;\n\tbind_t*\tbindptr;\n\n\t// set the bindings from the local store\n\tbindptr = g_bindings;\n\n\t// iterate each command, get its numeric binding\n\tfor (i=0; ;i++,bindptr++)\n\t{\n\t\tif (!bindptr->label)\n\t\t\tbreak;\n\n\t\tif (bindptr->bind1 != -1)\n\t\t{\t\n\t\t\ttrap_Key_SetBinding( bindptr->bind1, bindptr->command );\n\n\t\t\tif (bindptr->bind2 != -1)\n\t\t\t\ttrap_Key_SetBinding( bindptr->bind2, bindptr->command );\n\t\t}\n\t}\n\n\tif ( s_controls.invertmouse.curvalue )\n\t\ttrap_Cvar_SetValue( \"m_pitch\", -fabs( trap_Cvar_VariableValue( \"m_pitch\" ) ) );\n\telse\n\t\ttrap_Cvar_SetValue( \"m_pitch\", fabs( trap_Cvar_VariableValue( \"m_pitch\" ) ) );\n\n\ttrap_Cvar_SetValue( \"m_filter\", s_controls.smoothmouse.curvalue );\n\ttrap_Cvar_SetValue( \"cl_run\", s_controls.alwaysrun.curvalue );\n\ttrap_Cvar_SetValue( \"cg_autoswitch\", s_controls.autoswitch.curvalue );\n\ttrap_Cvar_SetValue( \"sensitivity\", s_controls.sensitivity.curvalue );\n\ttrap_Cvar_SetValue( \"cl_freelook\", s_controls.freelook.curvalue );\n\ttrap_Cmd_ExecuteText( EXEC_APPEND, \"in_restart\\n\" );\n}\n\n/*\n=================\nControls_SetDefaults\n=================\n*/\nstatic void Controls_SetDefaults( void )\n{\n\tint\ti;\n\tbind_t*\tbindptr;\n\n\t// set the bindings from the local store\n\tbindptr = g_bindings;\n\n\t// iterate each command, set its default binding\n\tfor (i=0; ;i++,bindptr++)\n\t{\n\t\tif (!bindptr->label)\n\t\t\tbreak;\n\n\t\tbindptr->bind1 = bindptr->defaultbind1;\n\t\tbindptr->bind2 = bindptr->defaultbind2;\n\t}\n\n\ts_controls.invertmouse.curvalue  = Controls_GetCvarDefault( \"m_pitch\" ) < 0;\n\ts_controls.smoothmouse.curvalue  = Controls_GetCvarDefault( \"m_filter\" );\n\ts_controls.alwaysrun.curvalue    = Controls_GetCvarDefault( \"cl_run\" );\n\ts_controls.autoswitch.curvalue   = Controls_GetCvarDefault( \"cg_autoswitch\" );\n\ts_controls.sensitivity.curvalue  = Controls_GetCvarDefault( \"sensitivity\" );\n\ts_controls.freelook.curvalue     = Controls_GetCvarDefault( \"cl_freelook\" );\n}\n\n/*\n=================\nControls_MenuKey\n=================\n*/\nstatic sfxHandle_t Controls_MenuKey( int key )\n{\n\tint\t\t\tid;\n\tint\t\t\ti;\n\tqboolean\tfound;\n\tbind_t*\t\tbindptr;\n\tfound = qfalse;\n\n\tif (!s_controls.waitingforkey)\n\t{\n\t\tswitch (key)\n\t\t{\n\t\t\tcase K_BACKSPACE:\n\t\t\tcase K_DEL:\n\t\t\tcase K_KP_DEL:\n\t\t\t\tkey = -1;\n\t\t\t\tbreak;\n\t\t\n\t\t\tcase K_MOUSE2:\n\t\t\tcase K_ESCAPE:\n\t\t\t\tif (s_controls.changesmade)\n\t\t\t\t\tControls_SetConfig();\n\t\t\t\tgoto ignorekey;\t\n\n\t\t\tdefault:\n\t\t\t\tgoto ignorekey;\n\t\t}\n\t}\n\telse\n\t{\n\t\tif (key & K_CHAR_FLAG)\n\t\t\tgoto ignorekey;\n\n\t\tswitch (key)\n\t\t{\n\t\t\tcase K_ESCAPE:\n\t\t\t\ts_controls.waitingforkey = qfalse;\n\t\t\t\tControls_Update();\n\t\t\t\treturn (menu_out_sound);\n\t\n\t\t\tcase '`':\n\t\t\t\tgoto ignorekey;\n\t\t}\n\t}\n\n\ts_controls.changesmade = qtrue;\n\t\n\tif (key != -1)\n\t{\n\t\t// remove from any other bind\n\t\tbindptr = g_bindings;\n\t\tfor (i=0; ;i++,bindptr++)\n\t\t{\n\t\t\tif (!bindptr->label)\t\n\t\t\t\tbreak;\n\n\t\t\tif (bindptr->bind2 == key)\n\t\t\t\tbindptr->bind2 = -1;\n\n\t\t\tif (bindptr->bind1 == key)\n\t\t\t{\n\t\t\t\tbindptr->bind1 = bindptr->bind2;\t\n\t\t\t\tbindptr->bind2 = -1;\n\t\t\t}\n\t\t}\n\t}\n\n\t// assign key to local store\n\tid      = ((menucommon_s*)(s_controls.menu.items[s_controls.menu.cursor]))->id;\n\tbindptr = g_bindings;\n\tfor (i=0; ;i++,bindptr++)\n\t{\n\t\tif (!bindptr->label)\t\n\t\t\tbreak;\n\t\t\n\t\tif (bindptr->id == id)\n\t\t{\n\t\t\tfound = qtrue;\n\t\t\tif (key == -1)\n\t\t\t{\n\t\t\t\tif( bindptr->bind1 != -1 ) {\n\t\t\t\t\ttrap_Key_SetBinding( bindptr->bind1, \"\" );\n\t\t\t\t\tbindptr->bind1 = -1;\n\t\t\t\t}\n\t\t\t\tif( bindptr->bind2 != -1 ) {\n\t\t\t\t\ttrap_Key_SetBinding( bindptr->bind2, \"\" );\n\t\t\t\t\tbindptr->bind2 = -1;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (bindptr->bind1 == -1) {\n\t\t\t\tbindptr->bind1 = key;\n\t\t\t}\n\t\t\telse if (bindptr->bind1 != key && bindptr->bind2 == -1) {\n\t\t\t\tbindptr->bind2 = key;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttrap_Key_SetBinding( bindptr->bind1, \"\" );\n\t\t\t\ttrap_Key_SetBinding( bindptr->bind2, \"\" );\n\t\t\t\tbindptr->bind1 = key;\n\t\t\t\tbindptr->bind2 = -1;\n\t\t\t}\t\t\t\t\t\t\n\t\t\tbreak;\n\t\t}\n\t}\t\t\t\t\n\t\t\n\ts_controls.waitingforkey = qfalse;\n\n\tif (found)\n\t{\t\n\t\tControls_Update();\n\t\treturn (menu_out_sound);\n\t}\n\nignorekey:\n\treturn Menu_DefaultKey( &s_controls.menu, key );\n}\n\n/*\n=================\nControls_ResetDefaults_Action\n=================\n*/\nstatic void Controls_ResetDefaults_Action( qboolean result ) {\n\tif( !result ) {\n\t\treturn;\n\t}\n\n\ts_controls.changesmade = qtrue;\n\tControls_SetDefaults();\n\tControls_Update();\n}\n\n/*\n=================\nControls_ResetDefaults_Draw\n=================\n*/\nstatic void Controls_ResetDefaults_Draw( void ) {\n\tUI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 0, \"WARNING: This will reset all\", UI_CENTER|UI_SMALLFONT, color_yellow );\n\tUI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 1, \"controls to their default values.\", UI_CENTER|UI_SMALLFONT, color_yellow );\n}\n\n/*\n=================\nControls_MenuEvent\n=================\n*/\nstatic void Controls_MenuEvent( void* ptr, int event )\n{\n\tswitch (((menucommon_s*)ptr)->id)\n\t{\n\t\tcase ID_MOVEMENT:\n\t\t\tif (event == QM_ACTIVATED)\n\t\t\t{\n\t\t\t\ts_controls.section = C_MOVEMENT; \n\t\t\t\tControls_Update();\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase ID_LOOKING:\n\t\t\tif (event == QM_ACTIVATED)\n\t\t\t{\n\t\t\t\ts_controls.section = C_LOOKING; \n\t\t\t\tControls_Update();\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase ID_WEAPONS:\n\t\t\tif (event == QM_ACTIVATED)\n\t\t\t{\n\t\t\t\ts_controls.section = C_WEAPONS; \n\t\t\t\tControls_Update();\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase ID_MISC:\n\t\t\tif (event == QM_ACTIVATED)\n\t\t\t{\n\t\t\t\ts_controls.section = C_MISC; \n\t\t\t\tControls_Update();\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase ID_DEFAULTS:\n\t\t\tif (event == QM_ACTIVATED)\n\t\t\t{\n\t\t\t\tUI_ConfirmMenu( \"SET TO DEFAULTS?\", Controls_ResetDefaults_Draw, Controls_ResetDefaults_Action );\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase ID_BACK:\n\t\t\tif (event == QM_ACTIVATED)\n\t\t\t{\n\t\t\t\tif (s_controls.changesmade)\n\t\t\t\t\tControls_SetConfig();\n\t\t\t\tUI_PopMenu();\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase ID_SAVEANDEXIT:\n\t\t\tif (event == QM_ACTIVATED)\n\t\t\t{\n\t\t\t\tControls_SetConfig();\n\t\t\t\tUI_PopMenu();\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase ID_EXIT:\n\t\t\tif (event == QM_ACTIVATED)\n\t\t\t{\n\t\t\t\tUI_PopMenu();\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase ID_FREELOOK:\n\t\tcase ID_MOUSESPEED:\n\t\tcase ID_INVERTMOUSE:\n\t\tcase ID_SMOOTHMOUSE:\n\t\tcase ID_ALWAYSRUN:\n\t\tcase ID_AUTOSWITCH:\n\t\t\tif (event == QM_ACTIVATED)\n\t\t\t{\n\t\t\t\ts_controls.changesmade = qtrue;\n\t\t\t}\n\t\t\tbreak;\t\t\n\t}\n}\n\n/*\n=================\nControls_ActionEvent\n=================\n*/\nstatic void Controls_ActionEvent( void* ptr, int event )\n{\n\tif (event == QM_LOSTFOCUS)\n\t{\n\t\tControls_UpdateModel( ANIM_IDLE );\n\t}\n\telse if (event == QM_GOTFOCUS)\n\t{\n\t\tControls_UpdateModel( g_bindings[((menucommon_s*)ptr)->id].anim );\n\t}\n\telse if ((event == QM_ACTIVATED) && !s_controls.waitingforkey)\n\t{\n\t\ts_controls.waitingforkey = 1;\n\t\tControls_Update();\n\t}\n}\n\n/*\n=================\nControls_InitModel\n=================\n*/\nstatic void Controls_InitModel( void )\n{\n\tmemset( &s_controls.playerinfo, 0, sizeof(playerInfo_t) );\n\n\tUI_PlayerInfo_SetModel( &s_controls.playerinfo, UI_Cvar_VariableString( \"model\" ) );\n\n\tControls_UpdateModel( ANIM_IDLE );\n}\n\n/*\n=================\nControls_InitWeapons\n=================\n*/\nstatic void Controls_InitWeapons( void ) {\n\tgitem_t *\titem;\n\n\tfor ( item = bg_itemlist + 1 ; item->classname ; item++ ) {\n\t\tif ( item->giType != IT_WEAPON ) {\n\t\t\tcontinue;\n\t\t}\n\t\ttrap_R_RegisterModel( item->world_model[0] );\n\t}\n}\n\n/*\n=================\nControls_MenuInit\n=================\n*/\nstatic void Controls_MenuInit( void )\n{\n\tstatic char playername[32];\n\n\t// zero set all our globals\n\tmemset( &s_controls, 0 ,sizeof(controls_t) );\n\n\tControls_Cache();\n\n\ts_controls.menu.key        = Controls_MenuKey;\n\ts_controls.menu.wrapAround = qtrue;\n\ts_controls.menu.fullscreen = qtrue;\n\n\ts_controls.banner.generic.type\t= MTYPE_BTEXT;\n\ts_controls.banner.generic.flags\t= QMF_CENTER_JUSTIFY;\n\ts_controls.banner.generic.x\t\t= 320;\n\ts_controls.banner.generic.y\t\t= 16;\n\ts_controls.banner.string\t\t= \"CONTROLS\";\n\ts_controls.banner.color\t\t\t= color_white;\n\ts_controls.banner.style\t\t\t= UI_CENTER;\n\n\ts_controls.framel.generic.type  = MTYPE_BITMAP;\n\ts_controls.framel.generic.name  = ART_FRAMEL;\n\ts_controls.framel.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;\n\ts_controls.framel.generic.x     = 0;\n\ts_controls.framel.generic.y     = 78;\n\ts_controls.framel.width  \t    = 256;\n\ts_controls.framel.height  \t    = 329;\n\n\ts_controls.framer.generic.type  = MTYPE_BITMAP;\n\ts_controls.framer.generic.name  = ART_FRAMER;\n\ts_controls.framer.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;\n\ts_controls.framer.generic.x     = 376;\n\ts_controls.framer.generic.y     = 76;\n\ts_controls.framer.width  \t    = 256;\n\ts_controls.framer.height  \t    = 334;\n\n\ts_controls.looking.generic.type     = MTYPE_PTEXT;\n\ts_controls.looking.generic.flags    = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_controls.looking.generic.id\t    = ID_LOOKING;\n\ts_controls.looking.generic.callback\t= Controls_MenuEvent;\n\ts_controls.looking.generic.x\t    = 152;\n\ts_controls.looking.generic.y\t    = 240 - 2 * PROP_HEIGHT;\n\ts_controls.looking.string\t\t\t= \"LOOK\";\n\ts_controls.looking.style\t\t\t= UI_RIGHT;\n\ts_controls.looking.color\t\t\t= color_red;\n\n\ts_controls.movement.generic.type     = MTYPE_PTEXT;\n\ts_controls.movement.generic.flags    = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_controls.movement.generic.id\t     = ID_MOVEMENT;\n\ts_controls.movement.generic.callback = Controls_MenuEvent;\n\ts_controls.movement.generic.x\t     = 152;\n\ts_controls.movement.generic.y\t     = 240 - PROP_HEIGHT;\n\ts_controls.movement.string\t\t\t= \"MOVE\";\n\ts_controls.movement.style\t\t\t= UI_RIGHT;\n\ts_controls.movement.color\t\t\t= color_red;\n\n\ts_controls.weapons.generic.type\t    = MTYPE_PTEXT;\n\ts_controls.weapons.generic.flags    = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_controls.weapons.generic.id\t    = ID_WEAPONS;\n\ts_controls.weapons.generic.callback\t= Controls_MenuEvent;\n\ts_controls.weapons.generic.x\t    = 152;\n\ts_controls.weapons.generic.y\t    = 240;\n\ts_controls.weapons.string\t\t\t= \"SHOOT\";\n\ts_controls.weapons.style\t\t\t= UI_RIGHT;\n\ts_controls.weapons.color\t\t\t= color_red;\n\n\ts_controls.misc.generic.type\t = MTYPE_PTEXT;\n\ts_controls.misc.generic.flags    = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_controls.misc.generic.id\t     = ID_MISC;\n\ts_controls.misc.generic.callback = Controls_MenuEvent;\n\ts_controls.misc.generic.x\t\t = 152;\n\ts_controls.misc.generic.y\t\t = 240 + PROP_HEIGHT;\n\ts_controls.misc.string\t\t\t= \"MISC\";\n\ts_controls.misc.style\t\t\t= UI_RIGHT;\n\ts_controls.misc.color\t\t\t= color_red;\n\n\ts_controls.back.generic.type\t = MTYPE_BITMAP;\n\ts_controls.back.generic.name     = ART_BACK0;\n\ts_controls.back.generic.flags    = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_controls.back.generic.x\t\t = 0;\n\ts_controls.back.generic.y\t\t = 480-64;\n\ts_controls.back.generic.id\t     = ID_BACK;\n\ts_controls.back.generic.callback = Controls_MenuEvent;\n\ts_controls.back.width  \t\t     = 128;\n\ts_controls.back.height  \t\t = 64;\n\ts_controls.back.focuspic         = ART_BACK1;\n\n\ts_controls.player.generic.type      = MTYPE_BITMAP;\n\ts_controls.player.generic.flags     = QMF_INACTIVE;\n\ts_controls.player.generic.ownerdraw = Controls_DrawPlayer;\n\ts_controls.player.generic.x\t        = 400;\n\ts_controls.player.generic.y\t        = -40;\n\ts_controls.player.width\t            = 32*10;\n\ts_controls.player.height            = 56*10;\n\n\ts_controls.walkforward.generic.type\t     = MTYPE_ACTION;\n\ts_controls.walkforward.generic.flags     = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;\n\ts_controls.walkforward.generic.callback  = Controls_ActionEvent;\n\ts_controls.walkforward.generic.ownerdraw = Controls_DrawKeyBinding;\n\ts_controls.walkforward.generic.id \t     = ID_FORWARD;\n\n\ts_controls.backpedal.generic.type\t   = MTYPE_ACTION;\n\ts_controls.backpedal.generic.flags     = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;\n\ts_controls.backpedal.generic.callback  = Controls_ActionEvent;\n\ts_controls.backpedal.generic.ownerdraw = Controls_DrawKeyBinding;\n\ts_controls.backpedal.generic.id \t   = ID_BACKPEDAL;\n\n\ts_controls.stepleft.generic.type\t  = MTYPE_ACTION;\n\ts_controls.stepleft.generic.flags     = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;\n\ts_controls.stepleft.generic.callback  = Controls_ActionEvent;\n\ts_controls.stepleft.generic.ownerdraw = Controls_DrawKeyBinding;\n\ts_controls.stepleft.generic.id \t\t  = ID_MOVELEFT;\n\n\ts_controls.stepright.generic.type\t   = MTYPE_ACTION;\n\ts_controls.stepright.generic.flags     = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;\n\ts_controls.stepright.generic.callback  = Controls_ActionEvent;\n\ts_controls.stepright.generic.ownerdraw = Controls_DrawKeyBinding;\n\ts_controls.stepright.generic.id        = ID_MOVERIGHT;\n\n\ts_controls.moveup.generic.type\t    = MTYPE_ACTION;\n\ts_controls.moveup.generic.flags     = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;\n\ts_controls.moveup.generic.callback  = Controls_ActionEvent;\n\ts_controls.moveup.generic.ownerdraw = Controls_DrawKeyBinding;\n\ts_controls.moveup.generic.id        = ID_MOVEUP;\n\n\ts_controls.movedown.generic.type\t  = MTYPE_ACTION;\n\ts_controls.movedown.generic.flags     = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;\n\ts_controls.movedown.generic.callback  = Controls_ActionEvent;\n\ts_controls.movedown.generic.ownerdraw = Controls_DrawKeyBinding;\n\ts_controls.movedown.generic.id        = ID_MOVEDOWN;\n\n\ts_controls.turnleft.generic.type\t  = MTYPE_ACTION;\n\ts_controls.turnleft.generic.flags     = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;\n\ts_controls.turnleft.generic.callback  = Controls_ActionEvent;\n\ts_controls.turnleft.generic.ownerdraw = Controls_DrawKeyBinding;\n\ts_controls.turnleft.generic.id        = ID_LEFT;\n\n\ts_controls.turnright.generic.type\t   = MTYPE_ACTION;\n\ts_controls.turnright.generic.flags     = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;\n\ts_controls.turnright.generic.callback  = Controls_ActionEvent;\n\ts_controls.turnright.generic.ownerdraw = Controls_DrawKeyBinding;\n\ts_controls.turnright.generic.id        = ID_RIGHT;\n\n\ts_controls.sidestep.generic.type\t  = MTYPE_ACTION;\n\ts_controls.sidestep.generic.flags     = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;\n\ts_controls.sidestep.generic.callback  = Controls_ActionEvent;\n\ts_controls.sidestep.generic.ownerdraw = Controls_DrawKeyBinding;\n\ts_controls.sidestep.generic.id        = ID_STRAFE;\n\n\ts_controls.run.generic.type\t     = MTYPE_ACTION;\n\ts_controls.run.generic.flags     = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;\n\ts_controls.run.generic.callback  = Controls_ActionEvent;\n\ts_controls.run.generic.ownerdraw = Controls_DrawKeyBinding;\n\ts_controls.run.generic.id        = ID_SPEED;\n\n\ts_controls.chainsaw.generic.type\t  = MTYPE_ACTION;\n\ts_controls.chainsaw.generic.flags     = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;\n\ts_controls.chainsaw.generic.callback  = Controls_ActionEvent;\n\ts_controls.chainsaw.generic.ownerdraw = Controls_DrawKeyBinding;\n\ts_controls.chainsaw.generic.id        = ID_WEAPON1;\n\n\ts_controls.machinegun.generic.type\t    = MTYPE_ACTION;\n\ts_controls.machinegun.generic.flags     = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;\n\ts_controls.machinegun.generic.callback  = Controls_ActionEvent;\n\ts_controls.machinegun.generic.ownerdraw = Controls_DrawKeyBinding;\n\ts_controls.machinegun.generic.id        = ID_WEAPON2;\n\n\ts_controls.shotgun.generic.type\t     = MTYPE_ACTION;\n\ts_controls.shotgun.generic.flags     = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;\n\ts_controls.shotgun.generic.callback  = Controls_ActionEvent;\n\ts_controls.shotgun.generic.ownerdraw = Controls_DrawKeyBinding;\n\ts_controls.shotgun.generic.id        = ID_WEAPON3;\n\n\ts_controls.grenadelauncher.generic.type\t     = MTYPE_ACTION;\n\ts_controls.grenadelauncher.generic.flags     = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;\n\ts_controls.grenadelauncher.generic.callback  = Controls_ActionEvent;\n\ts_controls.grenadelauncher.generic.ownerdraw = Controls_DrawKeyBinding;\n\ts_controls.grenadelauncher.generic.id        = ID_WEAPON4;\n\n\ts_controls.rocketlauncher.generic.type\t    = MTYPE_ACTION;\n\ts_controls.rocketlauncher.generic.flags     = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;\n\ts_controls.rocketlauncher.generic.callback  = Controls_ActionEvent;\n\ts_controls.rocketlauncher.generic.ownerdraw = Controls_DrawKeyBinding;\n\ts_controls.rocketlauncher.generic.id        = ID_WEAPON5;\n\n\ts_controls.lightning.generic.type\t   = MTYPE_ACTION;\n\ts_controls.lightning.generic.flags     = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;\n\ts_controls.lightning.generic.callback  = Controls_ActionEvent;\n\ts_controls.lightning.generic.ownerdraw = Controls_DrawKeyBinding;\n\ts_controls.lightning.generic.id        = ID_WEAPON6;\n\n\ts_controls.railgun.generic.type\t     = MTYPE_ACTION;\n\ts_controls.railgun.generic.flags     = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;\n\ts_controls.railgun.generic.callback  = Controls_ActionEvent;\n\ts_controls.railgun.generic.ownerdraw = Controls_DrawKeyBinding;\n\ts_controls.railgun.generic.id        = ID_WEAPON7;\n\n\ts_controls.plasma.generic.type\t    = MTYPE_ACTION;\n\ts_controls.plasma.generic.flags     = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;\n\ts_controls.plasma.generic.callback  = Controls_ActionEvent;\n\ts_controls.plasma.generic.ownerdraw = Controls_DrawKeyBinding;\n\ts_controls.plasma.generic.id        = ID_WEAPON8;\n\n\ts_controls.bfg.generic.type\t     = MTYPE_ACTION;\n\ts_controls.bfg.generic.flags     = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;\n\ts_controls.bfg.generic.callback  = Controls_ActionEvent;\n\ts_controls.bfg.generic.ownerdraw = Controls_DrawKeyBinding;\n\ts_controls.bfg.generic.id        = ID_WEAPON9;\n\n\ts_controls.attack.generic.type\t    = MTYPE_ACTION;\n\ts_controls.attack.generic.flags     = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;\n\ts_controls.attack.generic.callback  = Controls_ActionEvent;\n\ts_controls.attack.generic.ownerdraw = Controls_DrawKeyBinding;\n\ts_controls.attack.generic.id        = ID_ATTACK;\n\n\ts_controls.prevweapon.generic.type\t    = MTYPE_ACTION;\n\ts_controls.prevweapon.generic.flags     = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;\n\ts_controls.prevweapon.generic.callback  = Controls_ActionEvent;\n\ts_controls.prevweapon.generic.ownerdraw = Controls_DrawKeyBinding;\n\ts_controls.prevweapon.generic.id        = ID_WEAPPREV;\n\n\ts_controls.nextweapon.generic.type\t    = MTYPE_ACTION;\n\ts_controls.nextweapon.generic.flags     = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;\n\ts_controls.nextweapon.generic.callback  = Controls_ActionEvent;\n\ts_controls.nextweapon.generic.ownerdraw = Controls_DrawKeyBinding;\n\ts_controls.nextweapon.generic.id        = ID_WEAPNEXT;\n\n\ts_controls.lookup.generic.type\t    = MTYPE_ACTION;\n\ts_controls.lookup.generic.flags     = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;\n\ts_controls.lookup.generic.callback  = Controls_ActionEvent;\n\ts_controls.lookup.generic.ownerdraw = Controls_DrawKeyBinding;\n\ts_controls.lookup.generic.id        = ID_LOOKUP;\n\n\ts_controls.lookdown.generic.type\t  = MTYPE_ACTION;\n\ts_controls.lookdown.generic.flags     = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;\n\ts_controls.lookdown.generic.callback  = Controls_ActionEvent;\n\ts_controls.lookdown.generic.ownerdraw = Controls_DrawKeyBinding;\n\ts_controls.lookdown.generic.id        = ID_LOOKDOWN;\n\n\ts_controls.mouselook.generic.type\t   = MTYPE_ACTION;\n\ts_controls.mouselook.generic.flags     = QMF_LEFT_JUSTIFY|QMF_HIGHLIGHT_IF_FOCUS|QMF_GRAYED|QMF_HIDDEN;\n\ts_controls.mouselook.generic.callback  = Controls_ActionEvent;\n\ts_controls.mouselook.generic.ownerdraw = Controls_DrawKeyBinding;\n\ts_controls.mouselook.generic.id        = ID_MOUSELOOK;\n\n\ts_controls.freelook.generic.type\t\t= MTYPE_RADIOBUTTON;\n\ts_controls.freelook.generic.flags\t\t= QMF_SMALLFONT;\n\ts_controls.freelook.generic.x\t\t\t= SCREEN_WIDTH/2;\n\ts_controls.freelook.generic.name\t\t= \"free look\";\n\ts_controls.freelook.generic.id\t\t\t= ID_FREELOOK;\n\ts_controls.freelook.generic.callback\t= Controls_MenuEvent;\n\ts_controls.freelook.generic.statusbar\t= Controls_StatusBar;\n\n\ts_controls.centerview.generic.type\t    = MTYPE_ACTION;\n\ts_controls.centerview.generic.flags     = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;\n\ts_controls.centerview.generic.callback  = Controls_ActionEvent;\n\ts_controls.centerview.generic.ownerdraw = Controls_DrawKeyBinding;\n\ts_controls.centerview.generic.id        = ID_CENTERVIEW;\n\n\ts_controls.zoomview.generic.type\t  = MTYPE_ACTION;\n\ts_controls.zoomview.generic.flags     = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;\n\ts_controls.zoomview.generic.callback  = Controls_ActionEvent;\n\ts_controls.zoomview.generic.ownerdraw = Controls_DrawKeyBinding;\n\ts_controls.zoomview.generic.id        = ID_ZOOMVIEW;\n\n\ts_controls.useitem.generic.type\t     = MTYPE_ACTION;\n\ts_controls.useitem.generic.flags     = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;\n\ts_controls.useitem.generic.callback  = Controls_ActionEvent;\n\ts_controls.useitem.generic.ownerdraw = Controls_DrawKeyBinding;\n\ts_controls.useitem.generic.id        = ID_USEITEM;\n\n\ts_controls.showscores.generic.type\t    = MTYPE_ACTION;\n\ts_controls.showscores.generic.flags     = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;\n\ts_controls.showscores.generic.callback  = Controls_ActionEvent;\n\ts_controls.showscores.generic.ownerdraw = Controls_DrawKeyBinding;\n\ts_controls.showscores.generic.id        = ID_SHOWSCORES;\n\n\ts_controls.invertmouse.generic.type      = MTYPE_RADIOBUTTON;\n\ts_controls.invertmouse.generic.flags\t = QMF_SMALLFONT;\n\ts_controls.invertmouse.generic.x\t     = SCREEN_WIDTH/2;\n\ts_controls.invertmouse.generic.name\t     = \"invert mouse\";\n\ts_controls.invertmouse.generic.id        = ID_INVERTMOUSE;\n\ts_controls.invertmouse.generic.callback  = Controls_MenuEvent;\n\ts_controls.invertmouse.generic.statusbar = Controls_StatusBar;\n\n\ts_controls.smoothmouse.generic.type      = MTYPE_RADIOBUTTON;\n\ts_controls.smoothmouse.generic.flags\t = QMF_SMALLFONT;\n\ts_controls.smoothmouse.generic.x\t     = SCREEN_WIDTH/2;\n\ts_controls.smoothmouse.generic.name\t     = \"smooth mouse\";\n\ts_controls.smoothmouse.generic.id        = ID_SMOOTHMOUSE;\n\ts_controls.smoothmouse.generic.callback  = Controls_MenuEvent;\n\ts_controls.smoothmouse.generic.statusbar = Controls_StatusBar;\n\n\ts_controls.alwaysrun.generic.type      = MTYPE_RADIOBUTTON;\n\ts_controls.alwaysrun.generic.flags\t   = QMF_SMALLFONT;\n\ts_controls.alwaysrun.generic.x\t       = SCREEN_WIDTH/2;\n\ts_controls.alwaysrun.generic.name\t   = \"always run\";\n\ts_controls.alwaysrun.generic.id        = ID_ALWAYSRUN;\n\ts_controls.alwaysrun.generic.callback  = Controls_MenuEvent;\n\ts_controls.alwaysrun.generic.statusbar = Controls_StatusBar;\n\n\ts_controls.autoswitch.generic.type      = MTYPE_RADIOBUTTON;\n\ts_controls.autoswitch.generic.flags\t    = QMF_SMALLFONT;\n\ts_controls.autoswitch.generic.x\t        = SCREEN_WIDTH/2;\n\ts_controls.autoswitch.generic.name\t    = \"autoswitch weapons\";\n\ts_controls.autoswitch.generic.id        = ID_AUTOSWITCH;\n\ts_controls.autoswitch.generic.callback  = Controls_MenuEvent;\n\ts_controls.autoswitch.generic.statusbar = Controls_StatusBar;\n\n\ts_controls.sensitivity.generic.type\t     = MTYPE_SLIDER;\n\ts_controls.sensitivity.generic.x\t\t = SCREEN_WIDTH/2;\n\ts_controls.sensitivity.generic.flags\t = QMF_SMALLFONT;\n\ts_controls.sensitivity.generic.name\t     = \"mouse speed\";\n\ts_controls.sensitivity.generic.id \t     = ID_MOUSESPEED;\n\ts_controls.sensitivity.generic.callback  = Controls_MenuEvent;\n\ts_controls.sensitivity.minvalue\t\t     = 2;\n\ts_controls.sensitivity.maxvalue\t\t     = 30;\n\ts_controls.sensitivity.generic.statusbar = Controls_StatusBar;\n\n\ts_controls.gesture.generic.type\t     = MTYPE_ACTION;\n\ts_controls.gesture.generic.flags     = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;\n\ts_controls.gesture.generic.callback  = Controls_ActionEvent;\n\ts_controls.gesture.generic.ownerdraw = Controls_DrawKeyBinding;\n\ts_controls.gesture.generic.id        = ID_GESTURE;\n\n\ts_controls.chat.generic.type\t  = MTYPE_ACTION;\n\ts_controls.chat.generic.flags     = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;\n\ts_controls.chat.generic.callback  = Controls_ActionEvent;\n\ts_controls.chat.generic.ownerdraw = Controls_DrawKeyBinding;\n\ts_controls.chat.generic.id        = ID_CHAT;\n\n\ts_controls.chat2.generic.type\t   = MTYPE_ACTION;\n\ts_controls.chat2.generic.flags     = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;\n\ts_controls.chat2.generic.callback  = Controls_ActionEvent;\n\ts_controls.chat2.generic.ownerdraw = Controls_DrawKeyBinding;\n\ts_controls.chat2.generic.id        = ID_CHAT2;\n\n\ts_controls.chat3.generic.type\t   = MTYPE_ACTION;\n\ts_controls.chat3.generic.flags     = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;\n\ts_controls.chat3.generic.callback  = Controls_ActionEvent;\n\ts_controls.chat3.generic.ownerdraw = Controls_DrawKeyBinding;\n\ts_controls.chat3.generic.id        = ID_CHAT3;\n\n\ts_controls.chat4.generic.type\t   = MTYPE_ACTION;\n\ts_controls.chat4.generic.flags     = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;\n\ts_controls.chat4.generic.callback  = Controls_ActionEvent;\n\ts_controls.chat4.generic.ownerdraw = Controls_DrawKeyBinding;\n\ts_controls.chat4.generic.id        = ID_CHAT4;\n\n\ts_controls.name.generic.type\t= MTYPE_PTEXT;\n\ts_controls.name.generic.flags\t= QMF_CENTER_JUSTIFY|QMF_INACTIVE;\n\ts_controls.name.generic.x\t\t= 320;\n\ts_controls.name.generic.y\t\t= 440;\n\ts_controls.name.string\t\t\t= playername;\n\ts_controls.name.style\t\t\t= UI_CENTER;\n\ts_controls.name.color\t\t\t= text_color_normal;\n\n\tMenu_AddItem( &s_controls.menu, &s_controls.banner );\n\tMenu_AddItem( &s_controls.menu, &s_controls.framel );\n\tMenu_AddItem( &s_controls.menu, &s_controls.framer );\n\tMenu_AddItem( &s_controls.menu, &s_controls.player );\n\tMenu_AddItem( &s_controls.menu, &s_controls.name );\n\n\tMenu_AddItem( &s_controls.menu, &s_controls.looking );\n\tMenu_AddItem( &s_controls.menu, &s_controls.movement );\n\tMenu_AddItem( &s_controls.menu, &s_controls.weapons );\n\tMenu_AddItem( &s_controls.menu, &s_controls.misc );\n\n\tMenu_AddItem( &s_controls.menu, &s_controls.sensitivity );\n\tMenu_AddItem( &s_controls.menu, &s_controls.smoothmouse );\n\tMenu_AddItem( &s_controls.menu, &s_controls.invertmouse );\n\tMenu_AddItem( &s_controls.menu, &s_controls.lookup );\n\tMenu_AddItem( &s_controls.menu, &s_controls.lookdown );\n\tMenu_AddItem( &s_controls.menu, &s_controls.mouselook );\n\tMenu_AddItem( &s_controls.menu, &s_controls.freelook );\n\tMenu_AddItem( &s_controls.menu, &s_controls.centerview );\n\tMenu_AddItem( &s_controls.menu, &s_controls.zoomview );\n\n\tMenu_AddItem( &s_controls.menu, &s_controls.alwaysrun );\n\tMenu_AddItem( &s_controls.menu, &s_controls.run );\n\tMenu_AddItem( &s_controls.menu, &s_controls.walkforward );\n\tMenu_AddItem( &s_controls.menu, &s_controls.backpedal );\n\tMenu_AddItem( &s_controls.menu, &s_controls.stepleft );\n\tMenu_AddItem( &s_controls.menu, &s_controls.stepright );\n\tMenu_AddItem( &s_controls.menu, &s_controls.moveup );\n\tMenu_AddItem( &s_controls.menu, &s_controls.movedown );\n\tMenu_AddItem( &s_controls.menu, &s_controls.turnleft );\n\tMenu_AddItem( &s_controls.menu, &s_controls.turnright );\n\tMenu_AddItem( &s_controls.menu, &s_controls.sidestep );\n\n\tMenu_AddItem( &s_controls.menu, &s_controls.attack );\n\tMenu_AddItem( &s_controls.menu, &s_controls.nextweapon );\n\tMenu_AddItem( &s_controls.menu, &s_controls.prevweapon );\n\tMenu_AddItem( &s_controls.menu, &s_controls.autoswitch );\n\tMenu_AddItem( &s_controls.menu, &s_controls.chainsaw );\n\tMenu_AddItem( &s_controls.menu, &s_controls.machinegun );\n\tMenu_AddItem( &s_controls.menu, &s_controls.shotgun );\n\tMenu_AddItem( &s_controls.menu, &s_controls.grenadelauncher );\n\tMenu_AddItem( &s_controls.menu, &s_controls.rocketlauncher );\n\tMenu_AddItem( &s_controls.menu, &s_controls.lightning );\n\tMenu_AddItem( &s_controls.menu, &s_controls.railgun );\n\tMenu_AddItem( &s_controls.menu, &s_controls.plasma );\n\tMenu_AddItem( &s_controls.menu, &s_controls.bfg );\n\n\tMenu_AddItem( &s_controls.menu, &s_controls.showscores );\n\tMenu_AddItem( &s_controls.menu, &s_controls.useitem );\n\tMenu_AddItem( &s_controls.menu, &s_controls.gesture );\n\tMenu_AddItem( &s_controls.menu, &s_controls.chat );\n\tMenu_AddItem( &s_controls.menu, &s_controls.chat2 );\n\tMenu_AddItem( &s_controls.menu, &s_controls.chat3 );\n\tMenu_AddItem( &s_controls.menu, &s_controls.chat4 );\n\n\tMenu_AddItem( &s_controls.menu, &s_controls.back );\n\n\ttrap_Cvar_VariableStringBuffer( \"name\", s_controls.name.string, 16 );\n\tQ_CleanStr( s_controls.name.string );\n\n\t// initialize the configurable cvars\n\tControls_InitCvars();\n\n\t// initialize the current config\n\tControls_GetConfig();\n\n\t// intialize the model\n\tControls_InitModel();\n\n\t// intialize the weapons\n\tControls_InitWeapons ();\n\n\t// initial default section\n\ts_controls.section = C_LOOKING;\n\n\t// update the ui\n\tControls_Update();\n}\n\n\n/*\n=================\nControls_Cache\n=================\n*/\nvoid Controls_Cache( void ) {\n\ttrap_R_RegisterShaderNoMip( ART_BACK0 );\n\ttrap_R_RegisterShaderNoMip( ART_BACK1 );\n\ttrap_R_RegisterShaderNoMip( ART_FRAMEL );\n\ttrap_R_RegisterShaderNoMip( ART_FRAMER );\n}\n\n\n/*\n=================\nUI_ControlsMenu\n=================\n*/\nvoid UI_ControlsMenu( void ) {\n\tControls_MenuInit();\n\tUI_PushMenu( &s_controls.menu );\n}\n"
  },
  {
    "path": "src/q3_ui/ui_credits.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n/*\n=======================================================================\n\nCREDITS\n\n=======================================================================\n*/\n\n\n#include \"ui_local.h\"\n\n\ntypedef struct {\n\tmenuframework_s\tmenu;\n} creditsmenu_t;\n\nstatic creditsmenu_t\ts_credits;\n\n\n/*\n=================\nUI_CreditMenu_Key\n=================\n*/\nstatic sfxHandle_t UI_CreditMenu_Key( int key ) {\n\tif( key & K_CHAR_FLAG ) {\n\t\treturn 0;\n\t}\n\n\ttrap_Cmd_ExecuteText( EXEC_APPEND, \"quit\\n\" );\n\treturn 0;\n}\n\n\n/*\n===============\nUI_CreditMenu_Draw\n===============\n*/\nstatic void UI_CreditMenu_Draw( void ) {\n\tint\t\ty;\n\n\ty = 12;\n\tUI_DrawProportionalString( 320, y, \"id Software is:\", UI_CENTER|UI_SMALLFONT, color_white );\n\n\ty += 1.42 * PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;\n\tUI_DrawProportionalString( 320, y, \"Programming\", UI_CENTER|UI_SMALLFONT, color_white );\n\ty += PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;\n\tUI_DrawProportionalString( 320, y, \"John Carmack, Robert A. Duffy, Jim Dose'\", UI_CENTER|UI_SMALLFONT, color_white );\n\n\ty += 1.42 * PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;\n\tUI_DrawProportionalString( 320, y, \"Art\", UI_CENTER|UI_SMALLFONT, color_white );\n\ty += PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;\n\tUI_DrawProportionalString( 320, y, \"Adrian Carmack, Kevin Cloud,\", UI_CENTER|UI_SMALLFONT, color_white );\n\ty += PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;\n\tUI_DrawProportionalString( 320, y, \"Kenneth Scott, Seneca Menard, Fred Nilsson\", UI_CENTER|UI_SMALLFONT, color_white );\n\n\ty += 1.42 * PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;\n\tUI_DrawProportionalString( 320, y, \"Game Designer\", UI_CENTER|UI_SMALLFONT, color_white );\n\ty += PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;\n\tUI_DrawProportionalString( 320, y, \"Graeme Devine\", UI_CENTER|UI_SMALLFONT, color_white );\n\n\ty += 1.42 * PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;\n\tUI_DrawProportionalString( 320, y, \"Level Design\", UI_CENTER|UI_SMALLFONT, color_white );\n\ty += PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;\n\tUI_DrawProportionalString( 320, y, \"Tim Willits, Christian Antkow, Paul Jaquays\", UI_CENTER|UI_SMALLFONT, color_white );\n\n\ty += 1.42 * PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;\n\tUI_DrawProportionalString( 320, y, \"CEO\", UI_CENTER|UI_SMALLFONT, color_white );\n\ty += PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;\n\tUI_DrawProportionalString( 320, y, \"Todd Hollenshead\", UI_CENTER|UI_SMALLFONT, color_white );\n\n\ty += 1.42 * PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;\n\tUI_DrawProportionalString( 320, y, \"Director of Business Development\", UI_CENTER|UI_SMALLFONT, color_white );\n\ty += PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;\n\tUI_DrawProportionalString( 320, y, \"Marty Stratton\", UI_CENTER|UI_SMALLFONT, color_white );\n\n\ty += 1.42 * PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;\n\tUI_DrawProportionalString( 320, y, \"Biz Assist and id Mom\", UI_CENTER|UI_SMALLFONT, color_white );\n\ty += PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;\n\tUI_DrawProportionalString( 320, y, \"Donna Jackson\", UI_CENTER|UI_SMALLFONT, color_white );\n\n\ty += 1.42 * PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;\n\tUI_DrawProportionalString( 320, y, \"Development Assistance\", UI_CENTER|UI_SMALLFONT, color_white );\n\ty += PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;\n\tUI_DrawProportionalString( 320, y, \"Eric Webb\", UI_CENTER|UI_SMALLFONT, color_white );\n\n\ty += 1.35 * PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;\n\tUI_DrawString( 320, y, \"To order: 1-800-idgames     www.quake3arena.com     www.idsoftware.com\", UI_CENTER|UI_SMALLFONT, color_red );\n\ty += SMALLCHAR_HEIGHT;\n\tUI_DrawString( 320, y, \"Quake III Arena(c) 1999-2000, Id Software, Inc.  All Rights Reserved\", UI_CENTER|UI_SMALLFONT, color_red );\n}\n\n\n/*\n===============\nUI_CreditMenu\n===============\n*/\nvoid UI_CreditMenu( void ) {\n\tmemset( &s_credits, 0 ,sizeof(s_credits) );\n\n\ts_credits.menu.draw = UI_CreditMenu_Draw;\n\ts_credits.menu.key = UI_CreditMenu_Key;\n\ts_credits.menu.fullscreen = qtrue;\n\tUI_PushMenu ( &s_credits.menu );\n}\n"
  },
  {
    "path": "src/q3_ui/ui_demo2.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n/*\n=======================================================================\n\nDEMOS MENU\n\n=======================================================================\n*/\n\n\n#include \"ui_local.h\"\n\n\n#define ART_BACK0\t\t\t\"menu/art/back_0\"\n#define ART_BACK1\t\t\t\"menu/art/back_1\"\t\n#define ART_GO0\t\t\t\t\"menu/art/play_0\"\n#define ART_GO1\t\t\t\t\"menu/art/play_1\"\n#define ART_FRAMEL\t\t\t\"menu/art/frame2_l\"\n#define ART_FRAMER\t\t\t\"menu/art/frame1_r\"\n#define ART_ARROWS\t\t\t\"menu/art/arrows_horz_0\"\n#define ART_ARROWLEFT\t\t\"menu/art/arrows_horz_left\"\n#define ART_ARROWRIGHT\t\t\"menu/art/arrows_horz_right\"\n\n#define MAX_DEMOS\t\t\t128\n#define NAMEBUFSIZE\t\t\t( MAX_DEMOS * 16 )\n\n#define ID_BACK\t\t\t\t10\n#define ID_GO\t\t\t\t11\n#define ID_LIST\t\t\t\t12\n#define ID_RIGHT\t\t\t13\n#define ID_LEFT\t\t\t\t14\n\n#define ARROWS_WIDTH\t\t128\n#define ARROWS_HEIGHT\t\t48\n\n\ntypedef struct {\n\tmenuframework_s\tmenu;\n\n\tmenutext_s\t\tbanner;\n\tmenubitmap_s\tframel;\n\tmenubitmap_s\tframer;\n\n\tmenulist_s\t\tlist;\n\n\tmenubitmap_s\tarrows;\n\tmenubitmap_s\tleft;\n\tmenubitmap_s\tright;\n\tmenubitmap_s\tback;\n\tmenubitmap_s\tgo;\n\n\tint\t\t\t\tnumDemos;\n\tchar\t\t\tnames[NAMEBUFSIZE];\n\tchar\t\t\t*demolist[MAX_DEMOS];\n} demos_t;\n\nstatic demos_t\ts_demos;\n\n\n/*\n===============\nDemos_MenuEvent\n===============\n*/\nstatic void Demos_MenuEvent( void *ptr, int event ) {\n\tif( event != QM_ACTIVATED ) {\n\t\treturn;\n\t}\n\n\tswitch( ((menucommon_s*)ptr)->id ) {\n\tcase ID_GO:\n\t\tUI_ForceMenuOff ();\n\t\ttrap_Cmd_ExecuteText( EXEC_APPEND, va( \"demo %s\\n\",\n\t\t\t\t\t\t\t\ts_demos.list.itemnames[s_demos.list.curvalue]) );\n\t\tbreak;\n\n\tcase ID_BACK:\n\t\tUI_PopMenu();\n\t\tbreak;\n\n\tcase ID_LEFT:\n\t\tScrollList_Key( &s_demos.list, K_LEFTARROW );\n\t\tbreak;\n\n\tcase ID_RIGHT:\n\t\tScrollList_Key( &s_demos.list, K_RIGHTARROW );\n\t\tbreak;\n\t}\n}\n\n\n/*\n=================\nUI_DemosMenu_Key\n=================\n*/\nstatic sfxHandle_t UI_DemosMenu_Key( int key ) {\n\tmenucommon_s\t*item;\n\n\titem = Menu_ItemAtCursor( &s_demos.menu );\n\n\treturn Menu_DefaultKey( &s_demos.menu, key );\n}\n\n\n/*\n===============\nDemos_MenuInit\n===============\n*/\nstatic void Demos_MenuInit( void ) {\n\tint\t\ti;\n\tint\t\tlen;\n\tchar\t*demoname, extension[32];\n\n\tmemset( &s_demos, 0 ,sizeof(demos_t) );\n\ts_demos.menu.key = UI_DemosMenu_Key;\n\n\tDemos_Cache();\n\n\ts_demos.menu.fullscreen = qtrue;\n\ts_demos.menu.wrapAround = qtrue;\n\n\ts_demos.banner.generic.type\t\t= MTYPE_BTEXT;\n\ts_demos.banner.generic.x\t\t= 320;\n\ts_demos.banner.generic.y\t\t= 16;\n\ts_demos.banner.string\t\t\t= \"DEMOS\";\n\ts_demos.banner.color\t\t\t= color_white;\n\ts_demos.banner.style\t\t\t= UI_CENTER;\n\n\ts_demos.framel.generic.type\t\t= MTYPE_BITMAP;\n\ts_demos.framel.generic.name\t\t= ART_FRAMEL;\n\ts_demos.framel.generic.flags\t= QMF_INACTIVE;\n\ts_demos.framel.generic.x\t\t= 0;  \n\ts_demos.framel.generic.y\t\t= 78;\n\ts_demos.framel.width\t\t\t= 256;\n\ts_demos.framel.height\t\t\t= 329;\n\n\ts_demos.framer.generic.type\t\t= MTYPE_BITMAP;\n\ts_demos.framer.generic.name\t\t= ART_FRAMER;\n\ts_demos.framer.generic.flags\t= QMF_INACTIVE;\n\ts_demos.framer.generic.x\t\t= 376;\n\ts_demos.framer.generic.y\t\t= 76;\n\ts_demos.framer.width\t\t\t= 256;\n\ts_demos.framer.height\t\t\t= 334;\n\n\ts_demos.arrows.generic.type\t\t= MTYPE_BITMAP;\n\ts_demos.arrows.generic.name\t\t= ART_ARROWS;\n\ts_demos.arrows.generic.flags\t= QMF_INACTIVE;\n\ts_demos.arrows.generic.x\t\t= 320-ARROWS_WIDTH/2;\n\ts_demos.arrows.generic.y\t\t= 400;\n\ts_demos.arrows.width\t\t\t= ARROWS_WIDTH;\n\ts_demos.arrows.height\t\t\t= ARROWS_HEIGHT;\n\n\ts_demos.left.generic.type\t\t= MTYPE_BITMAP;\n\ts_demos.left.generic.flags\t\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_MOUSEONLY;\n\ts_demos.left.generic.x\t\t\t= 320-ARROWS_WIDTH/2;\n\ts_demos.left.generic.y\t\t\t= 400;\n\ts_demos.left.generic.id\t\t\t= ID_LEFT;\n\ts_demos.left.generic.callback\t= Demos_MenuEvent;\n\ts_demos.left.width\t\t\t\t= ARROWS_WIDTH/2;\n\ts_demos.left.height\t\t\t\t= ARROWS_HEIGHT;\n\ts_demos.left.focuspic\t\t\t= ART_ARROWLEFT;\n\n\ts_demos.right.generic.type\t\t= MTYPE_BITMAP;\n\ts_demos.right.generic.flags\t\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_MOUSEONLY;\n\ts_demos.right.generic.x\t\t\t= 320;\n\ts_demos.right.generic.y\t\t\t= 400;\n\ts_demos.right.generic.id\t\t= ID_RIGHT;\n\ts_demos.right.generic.callback\t= Demos_MenuEvent;\n\ts_demos.right.width\t\t\t\t= ARROWS_WIDTH/2;\n\ts_demos.right.height\t\t\t= ARROWS_HEIGHT;\n\ts_demos.right.focuspic\t\t\t= ART_ARROWRIGHT;\n\n\ts_demos.back.generic.type\t\t= MTYPE_BITMAP;\n\ts_demos.back.generic.name\t\t= ART_BACK0;\n\ts_demos.back.generic.flags\t\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_demos.back.generic.id\t\t\t= ID_BACK;\n\ts_demos.back.generic.callback\t= Demos_MenuEvent;\n\ts_demos.back.generic.x\t\t\t= 0;\n\ts_demos.back.generic.y\t\t\t= 480-64;\n\ts_demos.back.width\t\t\t\t= 128;\n\ts_demos.back.height\t\t\t\t= 64;\n\ts_demos.back.focuspic\t\t\t= ART_BACK1;\n\n\ts_demos.go.generic.type\t\t\t= MTYPE_BITMAP;\n\ts_demos.go.generic.name\t\t\t= ART_GO0;\n\ts_demos.go.generic.flags\t\t= QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_demos.go.generic.id\t\t\t= ID_GO;\n\ts_demos.go.generic.callback\t\t= Demos_MenuEvent;\n\ts_demos.go.generic.x\t\t\t= 640;\n\ts_demos.go.generic.y\t\t\t= 480-64;\n\ts_demos.go.width\t\t\t\t= 128;\n\ts_demos.go.height\t\t\t\t= 64;\n\ts_demos.go.focuspic\t\t\t\t= ART_GO1;\n\n\ts_demos.list.generic.type\t\t= MTYPE_SCROLLLIST;\n\ts_demos.list.generic.flags\t\t= QMF_PULSEIFFOCUS;\n\ts_demos.list.generic.callback\t= Demos_MenuEvent;\n\ts_demos.list.generic.id\t\t\t= ID_LIST;\n\ts_demos.list.generic.x\t\t\t= 118;\n\ts_demos.list.generic.y\t\t\t= 130;\n\ts_demos.list.width\t\t\t\t= 16;\n\ts_demos.list.height\t\t\t\t= 14;\n\tCom_sprintf(extension, sizeof(extension), \"dm_%d\", (int)trap_Cvar_VariableValue( \"protocol\" ) );\n\ts_demos.list.numitems\t\t\t= trap_FS_GetFileList( \"demos\", extension, s_demos.names, NAMEBUFSIZE );\n\ts_demos.list.itemnames\t\t\t= (const char **)s_demos.demolist;\n\ts_demos.list.columns\t\t\t= 3;\n\n\tif (!s_demos.list.numitems) {\n\t\tstrcpy( s_demos.names, \"No Demos Found.\" );\n\t\ts_demos.list.numitems = 1;\n\n\t\t//degenerate case, not selectable\n\t\ts_demos.go.generic.flags |= (QMF_INACTIVE|QMF_HIDDEN);\n\t}\n\telse if (s_demos.list.numitems > MAX_DEMOS)\n\t\ts_demos.list.numitems = MAX_DEMOS;\n\n\tdemoname = s_demos.names;\n\tfor ( i = 0; i < s_demos.list.numitems; i++ ) {\n\t\ts_demos.list.itemnames[i] = demoname;\n\t\t\n\t\t// strip extension\n\t\tlen = (int)strlen( demoname );\n\t\tif (!Q_stricmp(demoname +  len - 4,\".dm3\"))\n\t\t\tdemoname[len-4] = '\\0';\n\n\t\tQ_strupr(demoname);\n\n\t\tdemoname += len + 1;\n\t}\n\n\tMenu_AddItem( &s_demos.menu, &s_demos.banner );\n\tMenu_AddItem( &s_demos.menu, &s_demos.framel );\n\tMenu_AddItem( &s_demos.menu, &s_demos.framer );\n\tMenu_AddItem( &s_demos.menu, &s_demos.list );\n\tMenu_AddItem( &s_demos.menu, &s_demos.arrows );\n\tMenu_AddItem( &s_demos.menu, &s_demos.left );\n\tMenu_AddItem( &s_demos.menu, &s_demos.right );\n\tMenu_AddItem( &s_demos.menu, &s_demos.back );\n\tMenu_AddItem( &s_demos.menu, &s_demos.go );\n}\n\n/*\n=================\nDemos_Cache\n=================\n*/\nvoid Demos_Cache( void ) {\n\ttrap_R_RegisterShaderNoMip( ART_BACK0 );\n\ttrap_R_RegisterShaderNoMip( ART_BACK1 );\n\ttrap_R_RegisterShaderNoMip( ART_GO0 );\n\ttrap_R_RegisterShaderNoMip( ART_GO1 );\n\ttrap_R_RegisterShaderNoMip( ART_FRAMEL );\n\ttrap_R_RegisterShaderNoMip( ART_FRAMER );\n\ttrap_R_RegisterShaderNoMip( ART_ARROWS );\n\ttrap_R_RegisterShaderNoMip( ART_ARROWLEFT );\n\ttrap_R_RegisterShaderNoMip( ART_ARROWRIGHT );\n}\n\n/*\n===============\nUI_DemosMenu\n===============\n*/\nvoid UI_DemosMenu( void ) {\n\tDemos_MenuInit();\n\tUI_PushMenu( &s_demos.menu );\n}\n"
  },
  {
    "path": "src/q3_ui/ui_display.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n/*\n=======================================================================\n\nDISPLAY OPTIONS MENU\n\n=======================================================================\n*/\n\n#include \"ui_local.h\"\n\n\n#define ART_FRAMEL\t\t\t\"menu/art/frame2_l\"\n#define ART_FRAMER\t\t\t\"menu/art/frame1_r\"\n#define ART_BACK0\t\t\t\"menu/art/back_0\"\n#define ART_BACK1\t\t\t\"menu/art/back_1\"\n\n#define ID_GRAPHICS\t\t\t10\n#define ID_DISPLAY\t\t\t11\n#define ID_SOUND\t\t\t12\n#define ID_NETWORK\t\t\t13\n#define ID_BRIGHTNESS\t\t14\n#define ID_SCREENSIZE\t\t15\n#define ID_BACK\t\t\t\t16\n\n\ntypedef struct {\n\tmenuframework_s\tmenu;\n\n\tmenutext_s\t\tbanner;\n\tmenubitmap_s\tframel;\n\tmenubitmap_s\tframer;\n\n\tmenutext_s\t\tgraphics;\n\tmenutext_s\t\tdisplay;\n\tmenutext_s\t\tsound;\n\tmenutext_s\t\tnetwork;\n\n\tmenuslider_s\tbrightness;\n\tmenuslider_s\tscreensize;\n\n\tmenubitmap_s\tback;\n} displayOptionsInfo_t;\n\nstatic displayOptionsInfo_t\tdisplayOptionsInfo;\n\n\n/*\n=================\nUI_DisplayOptionsMenu_Event\n=================\n*/\nstatic void UI_DisplayOptionsMenu_Event( void* ptr, int event ) {\n\tif( event != QM_ACTIVATED ) {\n\t\treturn;\n\t}\n\n\tswitch( ((menucommon_s*)ptr)->id ) {\n\tcase ID_GRAPHICS:\n\t\tUI_PopMenu();\n\t\tUI_GraphicsOptionsMenu();\n\t\tbreak;\n\n\tcase ID_DISPLAY:\n\t\tbreak;\n\n\tcase ID_SOUND:\n\t\tUI_PopMenu();\n\t\tUI_SoundOptionsMenu();\n\t\tbreak;\n\n\tcase ID_NETWORK:\n\t\tUI_PopMenu();\n\t\tUI_NetworkOptionsMenu();\n\t\tbreak;\n\n\tcase ID_BRIGHTNESS:\n\t\ttrap_Cvar_SetValue( \"r_gamma\", displayOptionsInfo.brightness.curvalue / 10.0f );\n\t\tbreak;\n\t\n\tcase ID_SCREENSIZE:\n\t\ttrap_Cvar_SetValue( \"cg_viewsize\", displayOptionsInfo.screensize.curvalue * 10 );\n\t\tbreak;\n\n\tcase ID_BACK:\n\t\tUI_PopMenu();\n\t\tbreak;\n\t}\n}\n\n\n/*\n===============\nUI_DisplayOptionsMenu_Init\n===============\n*/\nstatic void UI_DisplayOptionsMenu_Init( void ) {\n\tint\t\ty;\n\n\tmemset( &displayOptionsInfo, 0, sizeof(displayOptionsInfo) );\n\n\tUI_DisplayOptionsMenu_Cache();\n\tdisplayOptionsInfo.menu.wrapAround = qtrue;\n\tdisplayOptionsInfo.menu.fullscreen = qtrue;\n\n\tdisplayOptionsInfo.banner.generic.type\t\t= MTYPE_BTEXT;\n\tdisplayOptionsInfo.banner.generic.flags\t\t= QMF_CENTER_JUSTIFY;\n\tdisplayOptionsInfo.banner.generic.x\t\t\t= 320;\n\tdisplayOptionsInfo.banner.generic.y\t\t\t= 16;\n\tdisplayOptionsInfo.banner.string\t\t\t= \"SYSTEM SETUP\";\n\tdisplayOptionsInfo.banner.color\t\t\t\t= color_white;\n\tdisplayOptionsInfo.banner.style\t\t\t\t= UI_CENTER;\n\n\tdisplayOptionsInfo.framel.generic.type\t\t= MTYPE_BITMAP;\n\tdisplayOptionsInfo.framel.generic.name\t\t= ART_FRAMEL;\n\tdisplayOptionsInfo.framel.generic.flags\t\t= QMF_INACTIVE;\n\tdisplayOptionsInfo.framel.generic.x\t\t\t= 0;  \n\tdisplayOptionsInfo.framel.generic.y\t\t\t= 78;\n\tdisplayOptionsInfo.framel.width\t\t\t\t= 256;\n\tdisplayOptionsInfo.framel.height\t\t\t= 329;\n\n\tdisplayOptionsInfo.framer.generic.type\t\t= MTYPE_BITMAP;\n\tdisplayOptionsInfo.framer.generic.name\t\t= ART_FRAMER;\n\tdisplayOptionsInfo.framer.generic.flags\t\t= QMF_INACTIVE;\n\tdisplayOptionsInfo.framer.generic.x\t\t\t= 376;\n\tdisplayOptionsInfo.framer.generic.y\t\t\t= 76;\n\tdisplayOptionsInfo.framer.width\t\t\t\t= 256;\n\tdisplayOptionsInfo.framer.height\t\t\t= 334;\n\n\tdisplayOptionsInfo.graphics.generic.type\t\t= MTYPE_PTEXT;\n\tdisplayOptionsInfo.graphics.generic.flags\t\t= QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;\n\tdisplayOptionsInfo.graphics.generic.id\t\t\t= ID_GRAPHICS;\n\tdisplayOptionsInfo.graphics.generic.callback\t= UI_DisplayOptionsMenu_Event;\n\tdisplayOptionsInfo.graphics.generic.x\t\t\t= 216;\n\tdisplayOptionsInfo.graphics.generic.y\t\t\t= 240 - 2 * PROP_HEIGHT;\n\tdisplayOptionsInfo.graphics.string\t\t\t\t= \"GRAPHICS\";\n\tdisplayOptionsInfo.graphics.style\t\t\t\t= UI_RIGHT;\n\tdisplayOptionsInfo.graphics.color\t\t\t\t= color_red;\n\n\tdisplayOptionsInfo.display.generic.type\t\t\t= MTYPE_PTEXT;\n\tdisplayOptionsInfo.display.generic.flags\t\t= QMF_RIGHT_JUSTIFY;\n\tdisplayOptionsInfo.display.generic.id\t\t\t= ID_DISPLAY;\n\tdisplayOptionsInfo.display.generic.callback\t\t= UI_DisplayOptionsMenu_Event;\n\tdisplayOptionsInfo.display.generic.x\t\t\t= 216;\n\tdisplayOptionsInfo.display.generic.y\t\t\t= 240 - PROP_HEIGHT;\n\tdisplayOptionsInfo.display.string\t\t\t\t= \"DISPLAY\";\n\tdisplayOptionsInfo.display.style\t\t\t\t= UI_RIGHT;\n\tdisplayOptionsInfo.display.color\t\t\t\t= color_red;\n\n\tdisplayOptionsInfo.sound.generic.type\t\t\t= MTYPE_PTEXT;\n\tdisplayOptionsInfo.sound.generic.flags\t\t\t= QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;\n\tdisplayOptionsInfo.sound.generic.id\t\t\t\t= ID_SOUND;\n\tdisplayOptionsInfo.sound.generic.callback\t\t= UI_DisplayOptionsMenu_Event;\n\tdisplayOptionsInfo.sound.generic.x\t\t\t\t= 216;\n\tdisplayOptionsInfo.sound.generic.y\t\t\t\t= 240;\n\tdisplayOptionsInfo.sound.string\t\t\t\t\t= \"SOUND\";\n\tdisplayOptionsInfo.sound.style\t\t\t\t\t= UI_RIGHT;\n\tdisplayOptionsInfo.sound.color\t\t\t\t\t= color_red;\n\n\tdisplayOptionsInfo.network.generic.type\t\t\t= MTYPE_PTEXT;\n\tdisplayOptionsInfo.network.generic.flags\t\t= QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;\n\tdisplayOptionsInfo.network.generic.id\t\t\t= ID_NETWORK;\n\tdisplayOptionsInfo.network.generic.callback\t\t= UI_DisplayOptionsMenu_Event;\n\tdisplayOptionsInfo.network.generic.x\t\t\t= 216;\n\tdisplayOptionsInfo.network.generic.y\t\t\t= 240 + PROP_HEIGHT;\n\tdisplayOptionsInfo.network.string\t\t\t\t= \"NETWORK\";\n\tdisplayOptionsInfo.network.style\t\t\t\t= UI_RIGHT;\n\tdisplayOptionsInfo.network.color\t\t\t\t= color_red;\n\n\ty = 240 - 1 * (BIGCHAR_HEIGHT+2);\n\tdisplayOptionsInfo.brightness.generic.type\t\t= MTYPE_SLIDER;\n\tdisplayOptionsInfo.brightness.generic.name\t\t= \"Brightness:\";\n\tdisplayOptionsInfo.brightness.generic.flags\t\t= QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\tdisplayOptionsInfo.brightness.generic.callback\t= UI_DisplayOptionsMenu_Event;\n\tdisplayOptionsInfo.brightness.generic.id\t\t= ID_BRIGHTNESS;\n\tdisplayOptionsInfo.brightness.generic.x\t\t\t= 400;\n\tdisplayOptionsInfo.brightness.generic.y\t\t\t= y;\n\tdisplayOptionsInfo.brightness.minvalue\t\t\t= 5;\n\tdisplayOptionsInfo.brightness.maxvalue\t\t\t= 20;\n\tif( !uis.glconfig.deviceSupportsGamma ) {\n\t\tdisplayOptionsInfo.brightness.generic.flags |= QMF_GRAYED;\n\t}\n\n\ty += BIGCHAR_HEIGHT+2;\n\tdisplayOptionsInfo.screensize.generic.type\t\t= MTYPE_SLIDER;\n\tdisplayOptionsInfo.screensize.generic.name\t\t= \"Screen Size:\";\n\tdisplayOptionsInfo.screensize.generic.flags\t\t= QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\tdisplayOptionsInfo.screensize.generic.callback\t= UI_DisplayOptionsMenu_Event;\n\tdisplayOptionsInfo.screensize.generic.id\t\t= ID_SCREENSIZE;\n\tdisplayOptionsInfo.screensize.generic.x\t\t\t= 400;\n\tdisplayOptionsInfo.screensize.generic.y\t\t\t= y;\n\tdisplayOptionsInfo.screensize.minvalue\t\t\t= 3;\n    displayOptionsInfo.screensize.maxvalue\t\t\t= 10;\n\n\tdisplayOptionsInfo.back.generic.type\t\t= MTYPE_BITMAP;\n\tdisplayOptionsInfo.back.generic.name\t\t= ART_BACK0;\n\tdisplayOptionsInfo.back.generic.flags\t\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\tdisplayOptionsInfo.back.generic.callback\t= UI_DisplayOptionsMenu_Event;\n\tdisplayOptionsInfo.back.generic.id\t\t\t= ID_BACK;\n\tdisplayOptionsInfo.back.generic.x\t\t\t= 0;\n\tdisplayOptionsInfo.back.generic.y\t\t\t= 480-64;\n\tdisplayOptionsInfo.back.width\t\t\t\t= 128;\n\tdisplayOptionsInfo.back.height\t\t\t\t= 64;\n\tdisplayOptionsInfo.back.focuspic\t\t\t= ART_BACK1;\n\n\tMenu_AddItem( &displayOptionsInfo.menu, ( void * ) &displayOptionsInfo.banner );\n\tMenu_AddItem( &displayOptionsInfo.menu, ( void * ) &displayOptionsInfo.framel );\n\tMenu_AddItem( &displayOptionsInfo.menu, ( void * ) &displayOptionsInfo.framer );\n\tMenu_AddItem( &displayOptionsInfo.menu, ( void * ) &displayOptionsInfo.graphics );\n\tMenu_AddItem( &displayOptionsInfo.menu, ( void * ) &displayOptionsInfo.display );\n\tMenu_AddItem( &displayOptionsInfo.menu, ( void * ) &displayOptionsInfo.sound );\n\tMenu_AddItem( &displayOptionsInfo.menu, ( void * ) &displayOptionsInfo.network );\n\tMenu_AddItem( &displayOptionsInfo.menu, ( void * ) &displayOptionsInfo.brightness );\n\tMenu_AddItem( &displayOptionsInfo.menu, ( void * ) &displayOptionsInfo.screensize );\n\tMenu_AddItem( &displayOptionsInfo.menu, ( void * ) &displayOptionsInfo.back );\n\n\tdisplayOptionsInfo.brightness.curvalue  = trap_Cvar_VariableValue(\"r_gamma\") * 10;\n\tdisplayOptionsInfo.screensize.curvalue  = trap_Cvar_VariableValue( \"cg_viewsize\")/10;\n}\n\n\n/*\n===============\nUI_DisplayOptionsMenu_Cache\n===============\n*/\nvoid UI_DisplayOptionsMenu_Cache( void ) {\n\ttrap_R_RegisterShaderNoMip( ART_FRAMEL );\n\ttrap_R_RegisterShaderNoMip( ART_FRAMER );\n\ttrap_R_RegisterShaderNoMip( ART_BACK0 );\n\ttrap_R_RegisterShaderNoMip( ART_BACK1 );\n}\n\n\n/*\n===============\nUI_DisplayOptionsMenu\n===============\n*/\nvoid UI_DisplayOptionsMenu( void ) {\n\tUI_DisplayOptionsMenu_Init();\n\tUI_PushMenu( &displayOptionsInfo.menu );\n\tMenu_SetCursorToItem( &displayOptionsInfo.menu, &displayOptionsInfo.display );\n}\n"
  },
  {
    "path": "src/q3_ui/ui_gameinfo.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n//\n// gameinfo.c\n//\n\n#include \"ui_local.h\"\n\n\n//\n// arena and bot info\n//\n\n#define POOLSIZE\t128 * 1024\n\nint\t\t\t\tui_numBots;\nstatic char\t\t*ui_botInfos[MAX_BOTS];\n\nstatic int\t\tui_numArenas;\nstatic char\t\t*ui_arenaInfos[MAX_ARENAS];\n\nstatic int\t\tui_numSinglePlayerArenas;\nstatic int\t\tui_numSpecialSinglePlayerArenas;\n\nstatic char\t\tmemoryPool[POOLSIZE];\nstatic int\t\tallocPoint, outOfMemory;\n\n\n/*\n===============\nUI_Alloc\n===============\n*/\nvoid *UI_Alloc( int size ) {\n\tchar\t*p;\n\n\tif ( allocPoint + size > POOLSIZE ) {\n\t\toutOfMemory = qtrue;\n\t\treturn NULL;\n\t}\n\n\tp = &memoryPool[allocPoint];\n\n\tallocPoint += ( size + 31 ) & ~31;\n\n\treturn p;\n}\n\n/*\n===============\nUI_InitMemory\n===============\n*/\nvoid UI_InitMemory( void ) {\n\tallocPoint = 0;\n\toutOfMemory = qfalse;\n}\n\n/*\n===============\nUI_ParseInfos\n===============\n*/\nint UI_ParseInfos( char *buf, int max, char *infos[] ) {\n\tchar\t*token;\n\tint\t\tcount;\n\tchar\tkey[MAX_TOKEN_CHARS];\n\tchar\tinfo[MAX_INFO_STRING];\n\n\tcount = 0;\n\n\twhile ( 1 ) {\n\t\ttoken = COM_Parse( &buf );\n\t\tif ( !token[0] ) {\n\t\t\tbreak;\n\t\t}\n\t\tif ( strcmp( token, \"{\" ) ) {\n\t\t\tCom_Printf( \"Missing { in info file\\n\" );\n\t\t\tbreak;\n\t\t}\n\n\t\tif ( count == max ) {\n\t\t\tCom_Printf( \"Max infos exceeded\\n\" );\n\t\t\tbreak;\n\t\t}\n\n\t\tinfo[0] = '\\0';\n\t\twhile ( 1 ) {\n\t\t\ttoken = COM_ParseExt( &buf, qtrue );\n\t\t\tif ( !token[0] ) {\n\t\t\t\tCom_Printf( \"Unexpected end of info file\\n\" );\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( !strcmp( token, \"}\" ) ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tQ_strncpyz( key, token, sizeof( key ) );\n\n\t\t\ttoken = COM_ParseExt( &buf, qfalse );\n\t\t\tif ( !token[0] ) {\n\t\t\t\tstrcpy( token, \"<NULL>\" );\n\t\t\t}\n\t\t\tInfo_SetValueForKey( info, key, token );\n\t\t}\n\t\t//NOTE: extra space for arena number\n\t\tinfos[count] = UI_Alloc((int)strlen(info) + (int)strlen(\"\\\\num\\\\\") + (int)strlen(va(\"%d\", MAX_ARENAS)) + 1);\n\t\tif (infos[count]) {\n\t\t\tstrcpy(infos[count], info);\n\t\t\tcount++;\n\t\t}\n\t}\n\treturn count;\n}\n\n/*\n===============\nUI_LoadArenasFromFile\n===============\n*/\nstatic void UI_LoadArenasFromFile( char *filename ) {\n\tint\t\t\t\tlen;\n\tfileHandle_t\tf;\n\tchar\t\t\tbuf[MAX_ARENAS_TEXT];\n\n\tlen = trap_FS_FOpenFile( filename, &f, FS_READ );\n\tif ( !f ) {\n\t\ttrap_Print( va( S_COLOR_RED \"file not found: %s\\n\", filename ) );\n\t\treturn;\n\t}\n\tif ( len >= MAX_ARENAS_TEXT ) {\n\t\ttrap_Print( va( S_COLOR_RED \"file too large: %s is %i, max allowed is %i\", filename, len, MAX_ARENAS_TEXT ) );\n\t\ttrap_FS_FCloseFile( f );\n\t\treturn;\n\t}\n\n\ttrap_FS_Read( buf, len, f );\n\tbuf[len] = 0;\n\ttrap_FS_FCloseFile( f );\n\n\tui_numArenas += UI_ParseInfos( buf, MAX_ARENAS - ui_numArenas, &ui_arenaInfos[ui_numArenas] );\n}\n\n/*\n===============\nUI_LoadArenas\n===============\n*/\nstatic void UI_LoadArenas( void ) {\n\tint\t\t\tnumdirs;\n\tvmCvar_t\tarenasFile;\n\tchar\t\tfilename[128];\n\tchar\t\tdirlist[1024];\n\tchar*\t\tdirptr;\n\tint\t\t\ti, n;\n\tint\t\t\tdirlen;\n\tchar\t\t*type;\n\tchar\t\t*tag;\n\tint\t\t\tsinglePlayerNum, specialNum, otherNum;\n\n\tui_numArenas = 0;\n\n\ttrap_Cvar_Register( &arenasFile, \"g_arenasFile\", \"\", CVAR_INIT|CVAR_ROM );\n\tif( *arenasFile.string ) {\n\t\tUI_LoadArenasFromFile(arenasFile.string);\n\t}\n\telse {\n\t\tUI_LoadArenasFromFile(\"scripts/arenas.txt\");\n\t}\n\n\t// get all arenas from .arena files\n\tnumdirs = trap_FS_GetFileList(\"scripts\", \".arena\", dirlist, 1024 );\n\tdirptr  = dirlist;\n\tfor (i = 0; i < numdirs; i++, dirptr += dirlen+1) {\n\t\tdirlen = (int)strlen(dirptr);\n\t\tstrcpy(filename, \"scripts/\");\n\t\tstrcat(filename, dirptr);\n\t\tUI_LoadArenasFromFile(filename);\n\t}\n\ttrap_Print( va( \"%i arenas parsed\\n\", ui_numArenas ) );\n\tif (outOfMemory) trap_Print(S_COLOR_YELLOW\"WARNING: not anough memory in pool to load all arenas\\n\");\n\n\t// set initial numbers\n\tfor( n = 0; n < ui_numArenas; n++ ) {\n\t\tInfo_SetValueForKey( ui_arenaInfos[n], \"num\", va( \"%i\", n ) );\n\t}\n\n\t// go through and count single players levels\n\tui_numSinglePlayerArenas = 0;\n\tui_numSpecialSinglePlayerArenas = 0;\n\tfor( n = 0; n < ui_numArenas; n++ ) {\n\t\t// determine type\n\t\ttype = Info_ValueForKey( ui_arenaInfos[n], \"type\" );\n\n\t\t// if no type specified, it will be treated as \"ffa\"\n\t\tif( !*type ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif( strstr( type, \"single\" ) ) {\n\t\t\t// check for special single player arenas (training, final)\n\t\t\ttag = Info_ValueForKey( ui_arenaInfos[n], \"special\" );\n\t\t\tif( *tag ) {\n\t\t\t\tui_numSpecialSinglePlayerArenas++;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tui_numSinglePlayerArenas++;\n\t\t}\n\t}\n\n\tn = ui_numSinglePlayerArenas % ARENAS_PER_TIER;\n\tif( n != 0 ) {\n\t\tui_numSinglePlayerArenas -= n;\n\t\ttrap_Print( va( \"%i arenas ignored to make count divisible by %i\\n\", n, ARENAS_PER_TIER ) );\n\t}\n\n\t// go through once more and assign number to the levels\n\tsinglePlayerNum = 0;\n\tspecialNum = singlePlayerNum + ui_numSinglePlayerArenas;\n\totherNum = specialNum + ui_numSpecialSinglePlayerArenas;\n\tfor( n = 0; n < ui_numArenas; n++ ) {\n\t\t// determine type\n\t\ttype = Info_ValueForKey( ui_arenaInfos[n], \"type\" );\n\n\t\t// if no type specified, it will be treated as \"ffa\"\n\t\tif( *type ) {\n\t\t\tif( strstr( type, \"single\" ) ) {\n\t\t\t\t// check for special single player arenas (training, final)\n\t\t\t\ttag = Info_ValueForKey( ui_arenaInfos[n], \"special\" );\n\t\t\t\tif( *tag ) {\n\t\t\t\t\tInfo_SetValueForKey( ui_arenaInfos[n], \"num\", va( \"%i\", specialNum++ ) );\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tInfo_SetValueForKey( ui_arenaInfos[n], \"num\", va( \"%i\", singlePlayerNum++ ) );\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\tInfo_SetValueForKey( ui_arenaInfos[n], \"num\", va( \"%i\", otherNum++ ) );\n\t}\n}\n\n/*\n===============\nUI_GetArenaInfoByNumber\n===============\n*/\nconst char *UI_GetArenaInfoByNumber( int num ) {\n\tint\t\tn;\n\tchar\t*value;\n\n\tif( num < 0 || num >= ui_numArenas ) {\n\t\ttrap_Print( va( S_COLOR_RED \"Invalid arena number: %i\\n\", num ) );\n\t\treturn NULL;\n\t}\n\n\tfor( n = 0; n < ui_numArenas; n++ ) {\n\t\tvalue = Info_ValueForKey( ui_arenaInfos[n], \"num\" );\n\t\tif( *value && atoi(value) == num ) {\n\t\t\treturn ui_arenaInfos[n];\n\t\t}\n\t}\n\n\treturn NULL;\n}\n\n\n/*\n===============\nUI_GetArenaInfoByNumber\n===============\n*/\nconst char *UI_GetArenaInfoByMap( const char *map ) {\n\tint\t\t\tn;\n\n\tfor( n = 0; n < ui_numArenas; n++ ) {\n\t\tif( Q_stricmp( Info_ValueForKey( ui_arenaInfos[n], \"map\" ), map ) == 0 ) {\n\t\t\treturn ui_arenaInfos[n];\n\t\t}\n\t}\n\n\treturn NULL;\n}\n\n\n/*\n===============\nUI_GetSpecialArenaInfo\n===============\n*/\nconst char *UI_GetSpecialArenaInfo( const char *tag ) {\n\tint\t\t\tn;\n\n\tfor( n = 0; n < ui_numArenas; n++ ) {\n\t\tif( Q_stricmp( Info_ValueForKey( ui_arenaInfos[n], \"special\" ), tag ) == 0 ) {\n\t\t\treturn ui_arenaInfos[n];\n\t\t}\n\t}\n\n\treturn NULL;\n}\n\n/*\n===============\nUI_LoadBotsFromFile\n===============\n*/\nstatic void UI_LoadBotsFromFile( char *filename ) {\n\tint\t\t\t\tlen;\n\tfileHandle_t\tf;\n\tchar\t\t\tbuf[MAX_BOTS_TEXT];\n\n\tlen = trap_FS_FOpenFile( filename, &f, FS_READ );\n\tif ( !f ) {\n\t\ttrap_Print( va( S_COLOR_RED \"file not found: %s\\n\", filename ) );\n\t\treturn;\n\t}\n\tif ( len >= MAX_BOTS_TEXT ) {\n\t\ttrap_Print( va( S_COLOR_RED \"file too large: %s is %i, max allowed is %i\", filename, len, MAX_BOTS_TEXT ) );\n\t\ttrap_FS_FCloseFile( f );\n\t\treturn;\n\t}\n\n\ttrap_FS_Read( buf, len, f );\n\tbuf[len] = 0;\n\ttrap_FS_FCloseFile( f );\n\n\tui_numBots += UI_ParseInfos( buf, MAX_BOTS - ui_numBots, &ui_botInfos[ui_numBots] );\n\tif (outOfMemory) trap_Print(S_COLOR_YELLOW\"WARNING: not anough memory in pool to load all bots\\n\");\n}\n\n/*\n===============\nUI_LoadBots\n===============\n*/\nstatic void UI_LoadBots( void ) {\n\tvmCvar_t\tbotsFile;\n\tint\t\t\tnumdirs;\n\tchar\t\tfilename[128];\n\tchar\t\tdirlist[1024];\n\tchar*\t\tdirptr;\n\tint\t\t\ti;\n\tint\t\t\tdirlen;\n\n\tui_numBots = 0;\n\n\ttrap_Cvar_Register( &botsFile, \"g_botsFile\", \"\", CVAR_INIT|CVAR_ROM );\n\tif( *botsFile.string ) {\n\t\tUI_LoadBotsFromFile(botsFile.string);\n\t}\n\telse {\n\t\tUI_LoadBotsFromFile(\"scripts/bots.txt\");\n\t}\n\n\t// get all bots from .bot files\n\tnumdirs = trap_FS_GetFileList(\"scripts\", \".bot\", dirlist, 1024 );\n\tdirptr  = dirlist;\n\tfor (i = 0; i < numdirs; i++, dirptr += dirlen+1) {\n\t\tdirlen = (int)strlen(dirptr);\n\t\tstrcpy(filename, \"scripts/\");\n\t\tstrcat(filename, dirptr);\n\t\tUI_LoadBotsFromFile(filename);\n\t}\n\ttrap_Print( va( \"%i bots parsed\\n\", ui_numBots ) );\n}\n\n\n/*\n===============\nUI_GetBotInfoByNumber\n===============\n*/\nchar *UI_GetBotInfoByNumber( int num ) {\n\tif( num < 0 || num >= ui_numBots ) {\n\t\ttrap_Print( va( S_COLOR_RED \"Invalid bot number: %i\\n\", num ) );\n\t\treturn NULL;\n\t}\n\treturn ui_botInfos[num];\n}\n\n\n/*\n===============\nUI_GetBotInfoByName\n===============\n*/\nchar *UI_GetBotInfoByName( const char *name ) {\n\tint\t\tn;\n\tchar\t*value;\n\n\tfor ( n = 0; n < ui_numBots ; n++ ) {\n\t\tvalue = Info_ValueForKey( ui_botInfos[n], \"name\" );\n\t\tif ( !Q_stricmp( value, name ) ) {\n\t\t\treturn ui_botInfos[n];\n\t\t}\n\t}\n\n\treturn NULL;\n}\n\n\n//\n// single player game info\n//\n\n/*\n===============\nUI_GetBestScore\n\nReturns the player's best finish on a given level, 0 if the have not played the level\n===============\n*/\nvoid UI_GetBestScore( int level, int *score, int *skill ) {\n\tint\t\tn;\n\tint\t\tskillScore;\n\tint\t\tbestScore;\n\tint\t\tbestScoreSkill;\n\tchar\tarenaKey[16];\n\tchar\tscores[MAX_INFO_VALUE];\n\n\tif( !score || !skill ) {\n\t\treturn;\n\t}\n\n\tif( level < 0 || level > ui_numArenas ) {\n\t\treturn;\n\t}\n\n\tbestScore = 0;\n\tbestScoreSkill = 0;\n\n\tfor( n = 1; n <= 5; n++ ) {\n\t\ttrap_Cvar_VariableStringBuffer( va( \"g_spScores%i\", n ), scores, MAX_INFO_VALUE );\n\n\t\tCom_sprintf( arenaKey, sizeof( arenaKey ), \"l%i\", level );\n\t\tskillScore = atoi( Info_ValueForKey( scores, arenaKey ) );\n\n\t\tif( skillScore < 1 || skillScore > 8 ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif( !bestScore || skillScore <= bestScore ) {\n\t\t\tbestScore = skillScore;\n\t\t\tbestScoreSkill = n;\n\t\t}\n\t}\n\n\t*score = bestScore;\n\t*skill = bestScoreSkill;\n}\n\n\n/*\n===============\nUI_SetBestScore\n\nSet the player's best finish for a level\n===============\n*/\nvoid UI_SetBestScore( int level, int score ) {\n\tint\t\tskill;\n\tint\t\toldScore;\n\tchar\tarenaKey[16];\n\tchar\tscores[MAX_INFO_VALUE];\n\n\t// validate score\n\tif( score < 1 || score > 8 ) {\n\t\treturn;\n\t}\n\n\t// validate skill\n\tskill = (int)trap_Cvar_VariableValue( \"g_spSkill\" );\n\tif( skill < 1 || skill > 5 ) {\n\t\treturn;\n\t}\n\n\t// get scores\n\ttrap_Cvar_VariableStringBuffer( va( \"g_spScores%i\", skill ), scores, MAX_INFO_VALUE );\n\n\t// see if this is better\n\tCom_sprintf( arenaKey, sizeof( arenaKey ), \"l%i\", level );\n\toldScore = atoi( Info_ValueForKey( scores, arenaKey ) );\n\tif( oldScore && oldScore <= score ) {\n\t\treturn;\n\t}\n\n\t// update scores\n\tInfo_SetValueForKey( scores, arenaKey, va( \"%i\", score ) );\n\ttrap_Cvar_Set( va( \"g_spScores%i\", skill ), scores );\n}\n\n\n/*\n===============\nUI_LogAwardData\n===============\n*/\nvoid UI_LogAwardData( int award, int data ) {\n\tchar\tkey[16];\n\tchar\tawardData[MAX_INFO_VALUE];\n\tint\t\toldValue;\n\n\tif( data == 0 ) {\n\t\treturn;\n\t}\n\n\tif( award > AWARD_PERFECT ) {\n\t\ttrap_Print( va( S_COLOR_RED \"Bad award %i in UI_LogAwardData\\n\", award ) );\n\t\treturn;\n\t}\n\n\ttrap_Cvar_VariableStringBuffer( \"g_spAwards\", awardData, sizeof(awardData) );\n\n\tCom_sprintf( key, sizeof(key), \"a%i\", award );\n\toldValue = atoi( Info_ValueForKey( awardData, key ) );\n\n\tInfo_SetValueForKey( awardData, key, va( \"%i\", oldValue + data ) );\n\ttrap_Cvar_Set( \"g_spAwards\", awardData );\n}\n\n\n/*\n===============\nUI_GetAwardLevel\n===============\n*/\nint UI_GetAwardLevel( int award ) {\n\tchar\tkey[16];\n\tchar\tawardData[MAX_INFO_VALUE];\n\n\ttrap_Cvar_VariableStringBuffer( \"g_spAwards\", awardData, sizeof(awardData) );\n\n\tCom_sprintf( key, sizeof(key), \"a%i\", award );\n\treturn atoi( Info_ValueForKey( awardData, key ) );\n}\n\n\n/*\n===============\nUI_TierCompleted\n===============\n*/\nint UI_TierCompleted( int levelWon ) {\n\tint\t\t\tlevel;\n\tint\t\t\tn;\n\tint\t\t\ttier;\n\tint\t\t\tscore;\n\tint\t\t\tskill;\n\tconst char\t*info;\n\n\ttier = levelWon / ARENAS_PER_TIER;\n\tlevel = tier * ARENAS_PER_TIER;\n\n\tif( tier == UI_GetNumSPTiers() ) {\n\t\tinfo = UI_GetSpecialArenaInfo( \"training\" );\n\t\tif( levelWon == atoi( Info_ValueForKey( info, \"num\" ) ) ) {\n\t\t\treturn 0;\n\t\t}\n\t\tinfo = UI_GetSpecialArenaInfo( \"final\" );\n\t\tif( !info || levelWon == atoi( Info_ValueForKey( info, \"num\" ) ) ) {\n\t\t\treturn tier + 1;\n\t\t}\n\t\treturn -1;\n\t}\n\n\tfor( n = 0; n < ARENAS_PER_TIER; n++, level++ ) {\n\t\tUI_GetBestScore( level, &score, &skill );\n\t\tif ( score != 1 ) {\n\t\t\treturn -1;\n\t\t}\n\t}\n\treturn tier + 1;\n}\n\n\n/*\n===============\nUI_ShowTierVideo\n===============\n*/\nqboolean UI_ShowTierVideo( int tier ) {\n\tchar\tkey[16];\n\tchar\tvideos[MAX_INFO_VALUE];\n\n\tif( tier <= 0 ) {\n\t\treturn qfalse;\n\t}\n\n\ttrap_Cvar_VariableStringBuffer( \"g_spVideos\", videos, sizeof(videos) );\n\n\tCom_sprintf( key, sizeof(key), \"tier%i\", tier );\n\tif( atoi( Info_ValueForKey( videos, key ) ) ) {\n\t\treturn qfalse;\n\t}\n\n\tInfo_SetValueForKey( videos, key, va( \"%i\", 1 ) );\n\ttrap_Cvar_Set( \"g_spVideos\", videos );\n\n\treturn qtrue;\n}\n\n\n/*\n===============\nUI_CanShowTierVideo\n===============\n*/\nqboolean UI_CanShowTierVideo( int tier ) {\n\tchar\tkey[16];\n\tchar\tvideos[MAX_INFO_VALUE];\n\n\tif( !tier ) {\n\t\treturn qfalse;\n\t}\n\n\tif( uis.demoversion && tier != 8 ) {\n\t\treturn qfalse;\n\t}\n\n\ttrap_Cvar_VariableStringBuffer( \"g_spVideos\", videos, sizeof(videos) );\n\n\tCom_sprintf( key, sizeof(key), \"tier%i\", tier );\n\tif( atoi( Info_ValueForKey( videos, key ) ) ) {\n\t\treturn qtrue;\n\t}\n\n\treturn qfalse;\n}\n\n\n/*\n===============\nUI_GetCurrentGame\n\nReturns the next level the player has not won\n===============\n*/\nint UI_GetCurrentGame( void ) {\n\tint\t\tlevel;\n\tint\t\trank;\n\tint\t\tskill;\n\tconst char *info;\n\n\tinfo = UI_GetSpecialArenaInfo( \"training\" );\n\tif( info ) {\n\t\tlevel = atoi( Info_ValueForKey( info, \"num\" ) );\n\t\tUI_GetBestScore( level, &rank, &skill );\n\t\tif ( !rank || rank > 1 ) {\n\t\t\treturn level;\n\t\t}\n\t}\n\n\tfor( level = 0; level < ui_numSinglePlayerArenas; level++ ) {\n\t\tUI_GetBestScore( level, &rank, &skill );\n\t\tif ( !rank || rank > 1 ) {\n\t\t\treturn level;\n\t\t}\n\t}\n\n\tinfo = UI_GetSpecialArenaInfo( \"final\" );\n\tif( !info ) {\n\t\treturn -1;\n\t}\n\treturn atoi( Info_ValueForKey( info, \"num\" ) );\n}\n\n\n/*\n===============\nUI_NewGame\n\nClears the scores and sets the difficutly level\n===============\n*/\nvoid UI_NewGame( void ) {\n\ttrap_Cvar_Set( \"g_spScores1\", \"\" );\n\ttrap_Cvar_Set( \"g_spScores2\", \"\" );\n\ttrap_Cvar_Set( \"g_spScores3\", \"\" );\n\ttrap_Cvar_Set( \"g_spScores4\", \"\" );\n\ttrap_Cvar_Set( \"g_spScores5\", \"\" );\n\ttrap_Cvar_Set( \"g_spAwards\", \"\" );\n\ttrap_Cvar_Set( \"g_spVideos\", \"\" );\n}\n\n\n/*\n===============\nUI_GetNumArenas\n===============\n*/\nint UI_GetNumArenas( void ) {\n\treturn ui_numArenas;\n}\n\n\n/*\n===============\nUI_GetNumSPArenas\n===============\n*/\nint UI_GetNumSPArenas( void ) {\n\treturn ui_numSinglePlayerArenas;\n}\n\n\n/*\n===============\nUI_GetNumSPTiers\n===============\n*/\nint UI_GetNumSPTiers( void ) {\n\treturn ui_numSinglePlayerArenas / ARENAS_PER_TIER;\n}\n\n\n/*\n===============\nUI_GetNumBots\n===============\n*/\nint UI_GetNumBots( void ) {\n\treturn ui_numBots;\n}\n\n\n/*\n===============\nUI_SPUnlock_f\n===============\n*/\nvoid UI_SPUnlock_f( void ) {\n\tchar\tarenaKey[16];\n\tchar\tscores[MAX_INFO_VALUE];\n\tint\t\tlevel;\n\tint\t\ttier;\n\n\t// get scores for skill 1\n\ttrap_Cvar_VariableStringBuffer( \"g_spScores1\", scores, MAX_INFO_VALUE );\n\n\t// update scores\n\tfor( level = 0; level < ui_numSinglePlayerArenas + ui_numSpecialSinglePlayerArenas; level++ ) {\n\t\tCom_sprintf( arenaKey, sizeof( arenaKey ), \"l%i\", level );\n\t\tInfo_SetValueForKey( scores, arenaKey, \"1\" );\n\t}\n\ttrap_Cvar_Set( \"g_spScores1\", scores );\n\n\t// unlock cinematics\n\tfor( tier = 1; tier <= 8; tier++ ) {\n\t\tUI_ShowTierVideo( tier );\n\t}\n\n\ttrap_Print( \"All levels unlocked at skill level 1\\n\" );\n\n\tUI_SPLevelMenu_ReInit();\n}\n\n\n/*\n===============\nUI_SPUnlockMedals_f\n===============\n*/\nvoid UI_SPUnlockMedals_f( void ) {\n\tint\t\tn;\n\tchar\tkey[16];\n\tchar\tawardData[MAX_INFO_VALUE];\n\n\ttrap_Cvar_VariableStringBuffer( \"g_spAwards\", awardData, MAX_INFO_VALUE );\n\n\tfor( n = 0; n < 6; n++ ) {\n\t\tCom_sprintf( key, sizeof(key), \"a%i\", n );\n\t\tInfo_SetValueForKey( awardData, key, \"100\" );\n\t}\n\n\ttrap_Cvar_Set( \"g_spAwards\", awardData );\n\n\ttrap_Print( \"All levels unlocked at 100\\n\" );\n}\n\n\n/*\n===============\nUI_InitGameinfo\n===============\n*/\nvoid UI_InitGameinfo( void ) {\n\n\tUI_InitMemory();\n\tUI_LoadArenas();\n\tUI_LoadBots();\n\n\tif( (trap_Cvar_VariableValue( \"fs_restrict\" )) || (ui_numSpecialSinglePlayerArenas == 0 && ui_numSinglePlayerArenas == 4) ) {\n\t\tuis.demoversion = qtrue;\n\t}\n\telse {\n\t\tuis.demoversion = qfalse;\n\t}\n}\n"
  },
  {
    "path": "src/q3_ui/ui_ingame.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n/*\n=======================================================================\n\nINGAME MENU\n\n=======================================================================\n*/\n\n\n#include \"ui_local.h\"\n\n\n#define INGAME_FRAME\t\t\t\t\t\"menu/art/addbotframe\"\n//#define INGAME_FRAME\t\t\t\t\t\"menu/art/cut_frame\"\n#define INGAME_MENU_VERTICAL_SPACING\t28\n\n#define ID_TEAM\t\t\t\t\t10\n#define ID_ADDBOTS\t\t\t\t11\n#define ID_REMOVEBOTS\t\t\t12\n#define ID_SETUP\t\t\t\t13\n#define ID_SERVERINFO\t\t\t14\n#define ID_LEAVEARENA\t\t\t15\n#define ID_RESTART\t\t\t\t16\n#define ID_QUIT\t\t\t\t\t17\n#define ID_RESUME\t\t\t\t18\n#define ID_TEAMORDERS\t\t\t19\n\n\ntypedef struct {\n\tmenuframework_s\tmenu;\n\n\tmenubitmap_s\tframe;\n\tmenutext_s\t\tteam;\n\tmenutext_s\t\tsetup;\n\tmenutext_s\t\tserver;\n\tmenutext_s\t\tleave;\n\tmenutext_s\t\trestart;\n\tmenutext_s\t\taddbots;\n\tmenutext_s\t\tremovebots;\n\tmenutext_s\t\tteamorders;\n\tmenutext_s\t\tquit;\n\tmenutext_s\t\tresume;\n} ingamemenu_t;\n\nstatic ingamemenu_t\ts_ingame;\n\n\n/*\n=================\nInGame_RestartAction\n=================\n*/\nstatic void InGame_RestartAction( qboolean result ) {\n\tif( !result ) {\n\t\treturn;\n\t}\n\n\tUI_PopMenu();\n\ttrap_Cmd_ExecuteText( EXEC_APPEND, \"map_restart 0\\n\" );\n}\n\n\n/*\n=================\nInGame_QuitAction\n=================\n*/\nstatic void InGame_QuitAction( qboolean result ) {\n\tif( !result ) {\n\t\treturn;\n\t}\n\tUI_PopMenu();\n\tUI_CreditMenu();\n}\n\n\n/*\n=================\nInGame_Event\n=================\n*/\nvoid InGame_Event( void *ptr, int notification ) {\n\tif( notification != QM_ACTIVATED ) {\n\t\treturn;\n\t}\n\n\tswitch( ((menucommon_s*)ptr)->id ) {\n\tcase ID_TEAM:\n\t\tUI_TeamMainMenu();\n\t\tbreak;\n\n\tcase ID_SETUP:\n\t\tUI_SetupMenu();\n\t\tbreak;\n\n\tcase ID_LEAVEARENA:\n\t\ttrap_Cmd_ExecuteText( EXEC_APPEND, \"disconnect\\n\" );\n\t\tbreak;\n\n\tcase ID_RESTART:\n\t\tUI_ConfirmMenu( \"RESTART ARENA?\", (voidfunc_f)NULL, InGame_RestartAction );\n\t\tbreak;\n\n\tcase ID_QUIT:\n\t\tUI_ConfirmMenu( \"EXIT GAME?\",  (voidfunc_f)NULL, InGame_QuitAction );\n\t\tbreak;\n\n\tcase ID_SERVERINFO:\n\t\tUI_ServerInfoMenu();\n\t\tbreak;\n\n\tcase ID_ADDBOTS:\n\t\tUI_AddBotsMenu();\n\t\tbreak;\n\n\tcase ID_REMOVEBOTS:\n\t\tUI_RemoveBotsMenu();\n\t\tbreak;\n\n\tcase ID_TEAMORDERS:\n\t\tUI_TeamOrdersMenu();\n\t\tbreak;\n\n\tcase ID_RESUME:\n\t\tUI_PopMenu();\n\t\tbreak;\n\t}\n}\n\n\n/*\n=================\nInGame_MenuInit\n=================\n*/\nvoid InGame_MenuInit( void ) {\n\tint\t\ty;\n\tuiClientState_t\tcs;\n\tchar\tinfo[MAX_INFO_STRING];\n\tint\t\tteam;\n\n\tmemset( &s_ingame, 0 ,sizeof(ingamemenu_t) );\n\n\tInGame_Cache();\n\n\ts_ingame.menu.wrapAround = qtrue;\n\ts_ingame.menu.fullscreen = qfalse;\n\n\ts_ingame.frame.generic.type\t\t\t= MTYPE_BITMAP;\n\ts_ingame.frame.generic.flags\t\t= QMF_INACTIVE;\n\ts_ingame.frame.generic.name\t\t\t= INGAME_FRAME;\n\ts_ingame.frame.generic.x\t\t\t= 320-233;//142;\n\ts_ingame.frame.generic.y\t\t\t= 240-166;//118;\n\ts_ingame.frame.width\t\t\t\t= 466;//359;\n\ts_ingame.frame.height\t\t\t\t= 332;//256;\n\n\t//y = 96;\n\ty = 88;\n\ts_ingame.team.generic.type\t\t\t= MTYPE_PTEXT;\n\ts_ingame.team.generic.flags\t\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_ingame.team.generic.x\t\t\t\t= 320;\n\ts_ingame.team.generic.y\t\t\t\t= y;\n\ts_ingame.team.generic.id\t\t\t= ID_TEAM;\n\ts_ingame.team.generic.callback\t\t= InGame_Event; \n\ts_ingame.team.string\t\t\t\t= \"START\";\n\ts_ingame.team.color\t\t\t\t\t= color_red;\n\ts_ingame.team.style\t\t\t\t\t= UI_CENTER|UI_SMALLFONT;\n\n\ty += INGAME_MENU_VERTICAL_SPACING;\n\ts_ingame.addbots.generic.type\t\t= MTYPE_PTEXT;\n\ts_ingame.addbots.generic.flags\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_ingame.addbots.generic.x\t\t\t= 320;\n\ts_ingame.addbots.generic.y\t\t\t= y;\n\ts_ingame.addbots.generic.id\t\t\t= ID_ADDBOTS;\n\ts_ingame.addbots.generic.callback\t= InGame_Event; \n\ts_ingame.addbots.string\t\t\t\t= \"ADD BOTS\";\n\ts_ingame.addbots.color\t\t\t\t= color_red;\n\ts_ingame.addbots.style\t\t\t\t= UI_CENTER|UI_SMALLFONT;\n\tif( !trap_Cvar_VariableValue( \"sv_running\" ) || !trap_Cvar_VariableValue( \"bot_enable\" ) || (trap_Cvar_VariableValue( \"g_gametype\" ) == GT_SINGLE_PLAYER)) {\n\t\ts_ingame.addbots.generic.flags |= QMF_GRAYED;\n\t}\n\n\ty += INGAME_MENU_VERTICAL_SPACING;\n\ts_ingame.removebots.generic.type\t\t= MTYPE_PTEXT;\n\ts_ingame.removebots.generic.flags\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_ingame.removebots.generic.x\t\t\t= 320;\n\ts_ingame.removebots.generic.y\t\t\t= y;\n\ts_ingame.removebots.generic.id\t\t\t= ID_REMOVEBOTS;\n\ts_ingame.removebots.generic.callback\t= InGame_Event; \n\ts_ingame.removebots.string\t\t\t\t= \"REMOVE BOTS\";\n\ts_ingame.removebots.color\t\t\t\t= color_red;\n\ts_ingame.removebots.style\t\t\t\t= UI_CENTER|UI_SMALLFONT;\n\tif( !trap_Cvar_VariableValue( \"sv_running\" ) || !trap_Cvar_VariableValue( \"bot_enable\" ) || (trap_Cvar_VariableValue( \"g_gametype\" ) == GT_SINGLE_PLAYER)) {\n\t\ts_ingame.removebots.generic.flags |= QMF_GRAYED;\n\t}\n\n\ty += INGAME_MENU_VERTICAL_SPACING;\n\ts_ingame.teamorders.generic.type\t\t= MTYPE_PTEXT;\n\ts_ingame.teamorders.generic.flags\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_ingame.teamorders.generic.x\t\t\t= 320;\n\ts_ingame.teamorders.generic.y\t\t\t= y;\n\ts_ingame.teamorders.generic.id\t\t\t= ID_TEAMORDERS;\n\ts_ingame.teamorders.generic.callback\t= InGame_Event; \n\ts_ingame.teamorders.string\t\t\t\t= \"TEAM ORDERS\";\n\ts_ingame.teamorders.color\t\t\t\t= color_red;\n\ts_ingame.teamorders.style\t\t\t\t= UI_CENTER|UI_SMALLFONT;\n\tif( !(trap_Cvar_VariableValue( \"g_gametype\" ) >= GT_TEAM) ) {\n\t\ts_ingame.teamorders.generic.flags |= QMF_GRAYED;\n\t}\n\telse {\n\t\ttrap_GetClientState( &cs );\n\t\ttrap_GetConfigString( CS_PLAYERS + cs.clientNum, info, MAX_INFO_STRING );\n\t\tteam = atoi( Info_ValueForKey( info, \"t\" ) );\n\t\tif( team == TEAM_SPECTATOR ) {\n\t\t\ts_ingame.teamorders.generic.flags |= QMF_GRAYED;\n\t\t}\n\t}\n\n\ty += INGAME_MENU_VERTICAL_SPACING;\n\ts_ingame.setup.generic.type\t\t\t= MTYPE_PTEXT;\n\ts_ingame.setup.generic.flags\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_ingame.setup.generic.x\t\t\t= 320;\n\ts_ingame.setup.generic.y\t\t\t= y;\n\ts_ingame.setup.generic.id\t\t\t= ID_SETUP;\n\ts_ingame.setup.generic.callback\t\t= InGame_Event; \n\ts_ingame.setup.string\t\t\t\t= \"SETUP\";\n\ts_ingame.setup.color\t\t\t\t= color_red;\n\ts_ingame.setup.style\t\t\t\t= UI_CENTER|UI_SMALLFONT;\n\n\ty += INGAME_MENU_VERTICAL_SPACING;\n\ts_ingame.server.generic.type\t\t= MTYPE_PTEXT;\n\ts_ingame.server.generic.flags\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_ingame.server.generic.x\t\t\t= 320;\n\ts_ingame.server.generic.y\t\t\t= y;\n\ts_ingame.server.generic.id\t\t\t= ID_SERVERINFO;\n\ts_ingame.server.generic.callback\t= InGame_Event; \n\ts_ingame.server.string\t\t\t\t= \"SERVER INFO\";\n\ts_ingame.server.color\t\t\t\t= color_red;\n\ts_ingame.server.style\t\t\t\t= UI_CENTER|UI_SMALLFONT;\n\n\ty += INGAME_MENU_VERTICAL_SPACING;\n\ts_ingame.restart.generic.type\t\t= MTYPE_PTEXT;\n\ts_ingame.restart.generic.flags\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_ingame.restart.generic.x\t\t\t= 320;\n\ts_ingame.restart.generic.y\t\t\t= y;\n\ts_ingame.restart.generic.id\t\t\t= ID_RESTART;\n\ts_ingame.restart.generic.callback\t= InGame_Event; \n\ts_ingame.restart.string\t\t\t\t= \"RESTART ARENA\";\n\ts_ingame.restart.color\t\t\t\t= color_red;\n\ts_ingame.restart.style\t\t\t\t= UI_CENTER|UI_SMALLFONT;\n\tif( !trap_Cvar_VariableValue( \"sv_running\" ) ) {\n\t\ts_ingame.restart.generic.flags |= QMF_GRAYED;\n\t}\n\n\ty += INGAME_MENU_VERTICAL_SPACING;\n\ts_ingame.resume.generic.type\t\t\t= MTYPE_PTEXT;\n\ts_ingame.resume.generic.flags\t\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_ingame.resume.generic.x\t\t\t\t= 320;\n\ts_ingame.resume.generic.y\t\t\t\t= y;\n\ts_ingame.resume.generic.id\t\t\t\t= ID_RESUME;\n\ts_ingame.resume.generic.callback\t\t= InGame_Event; \n\ts_ingame.resume.string\t\t\t\t\t= \"RESUME GAME\";\n\ts_ingame.resume.color\t\t\t\t\t= color_red;\n\ts_ingame.resume.style\t\t\t\t\t= UI_CENTER|UI_SMALLFONT;\n\n\ty += INGAME_MENU_VERTICAL_SPACING;\n\ts_ingame.leave.generic.type\t\t\t= MTYPE_PTEXT;\n\ts_ingame.leave.generic.flags\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_ingame.leave.generic.x\t\t\t= 320;\n\ts_ingame.leave.generic.y\t\t\t= y;\n\ts_ingame.leave.generic.id\t\t\t= ID_LEAVEARENA;\n\ts_ingame.leave.generic.callback\t\t= InGame_Event; \n\ts_ingame.leave.string\t\t\t\t= \"LEAVE ARENA\";\n\ts_ingame.leave.color\t\t\t\t= color_red;\n\ts_ingame.leave.style\t\t\t\t= UI_CENTER|UI_SMALLFONT;\n\n\ty += INGAME_MENU_VERTICAL_SPACING;\n\ts_ingame.quit.generic.type\t\t\t= MTYPE_PTEXT;\n\ts_ingame.quit.generic.flags\t\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_ingame.quit.generic.x\t\t\t\t= 320;\n\ts_ingame.quit.generic.y\t\t\t\t= y;\n\ts_ingame.quit.generic.id\t\t\t= ID_QUIT;\n\ts_ingame.quit.generic.callback\t\t= InGame_Event; \n\ts_ingame.quit.string\t\t\t\t= \"EXIT GAME\";\n\ts_ingame.quit.color\t\t\t\t\t= color_red;\n\ts_ingame.quit.style\t\t\t\t\t= UI_CENTER|UI_SMALLFONT;\n\n\tMenu_AddItem( &s_ingame.menu, &s_ingame.frame );\n\tMenu_AddItem( &s_ingame.menu, &s_ingame.team );\n\tMenu_AddItem( &s_ingame.menu, &s_ingame.addbots );\n\tMenu_AddItem( &s_ingame.menu, &s_ingame.removebots );\n\tMenu_AddItem( &s_ingame.menu, &s_ingame.teamorders );\n\tMenu_AddItem( &s_ingame.menu, &s_ingame.setup );\n\tMenu_AddItem( &s_ingame.menu, &s_ingame.server );\n\tMenu_AddItem( &s_ingame.menu, &s_ingame.restart );\n\tMenu_AddItem( &s_ingame.menu, &s_ingame.resume );\n\tMenu_AddItem( &s_ingame.menu, &s_ingame.leave );\n\tMenu_AddItem( &s_ingame.menu, &s_ingame.quit );\n}\n\n\n/*\n=================\nInGame_Cache\n=================\n*/\nvoid InGame_Cache( void ) {\n\ttrap_R_RegisterShaderNoMip( INGAME_FRAME );\n}\n\n\n/*\n=================\nUI_InGameMenu\n=================\n*/\nvoid UI_InGameMenu( void ) {\n\t// force as top level menu\n\tuis.menusp = 0;  \n\n\t// set menu cursor to a nice location\n\tuis.cursorx = 319;\n\tuis.cursory = 80;\n\n\tInGame_MenuInit();\n\tUI_PushMenu( &s_ingame.menu );\n}\n"
  },
  {
    "path": "src/q3_ui/ui_local.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n#ifndef __UI_LOCAL_H__\n#define __UI_LOCAL_H__\n\n#include \"../game/q_shared.h\"\n#include \"../cgame/tr_types.h\"\n//NOTE: include the ui_public.h from the new UI\n#include \"ui_public.h\" // bk001205 - yes, do have to use this\n//redefine to old API version\n#undef UI_API_VERSION\n#define UI_API_VERSION\t4\n#include \"keycodes.h\"\n#include \"../game/bg_public.h\"\n\ntypedef void (*voidfunc_f)(void);\n\nextern vmCvar_t\tui_ffa_fraglimit;\nextern vmCvar_t\tui_ffa_timelimit;\n\nextern vmCvar_t\tui_tourney_fraglimit;\nextern vmCvar_t\tui_tourney_timelimit;\n\nextern vmCvar_t\tui_team_fraglimit;\nextern vmCvar_t\tui_team_timelimit;\nextern vmCvar_t\tui_team_friendly;\n\nextern vmCvar_t\tui_ctf_capturelimit;\nextern vmCvar_t\tui_ctf_timelimit;\nextern vmCvar_t\tui_ctf_friendly;\n\nextern vmCvar_t\tui_arenasFile;\nextern vmCvar_t\tui_botsFile;\nextern vmCvar_t\tui_spScores1;\nextern vmCvar_t\tui_spScores2;\nextern vmCvar_t\tui_spScores3;\nextern vmCvar_t\tui_spScores4;\nextern vmCvar_t\tui_spScores5;\nextern vmCvar_t\tui_spAwards;\nextern vmCvar_t\tui_spVideos;\nextern vmCvar_t\tui_spSkill;\n\nextern vmCvar_t\tui_spSelection;\n\nextern vmCvar_t\tui_browserMaster;\nextern vmCvar_t\tui_browserGameType;\nextern vmCvar_t\tui_browserSortKey;\nextern vmCvar_t\tui_browserShowFull;\nextern vmCvar_t\tui_browserShowEmpty;\n\nextern vmCvar_t\tui_brassTime;\nextern vmCvar_t\tui_drawCrosshair;\nextern vmCvar_t\tui_drawCrosshairNames;\nextern vmCvar_t\tui_marks;\n\nextern vmCvar_t\tui_server1;\nextern vmCvar_t\tui_server2;\nextern vmCvar_t\tui_server3;\nextern vmCvar_t\tui_server4;\nextern vmCvar_t\tui_server5;\nextern vmCvar_t\tui_server6;\nextern vmCvar_t\tui_server7;\nextern vmCvar_t\tui_server8;\nextern vmCvar_t\tui_server9;\nextern vmCvar_t\tui_server10;\nextern vmCvar_t\tui_server11;\nextern vmCvar_t\tui_server12;\nextern vmCvar_t\tui_server13;\nextern vmCvar_t\tui_server14;\nextern vmCvar_t\tui_server15;\nextern vmCvar_t\tui_server16;\n\nextern vmCvar_t\tui_cdkey;\nextern vmCvar_t\tui_cdkeychecked;\n\n\n//\n// ui_qmenu.c\n//\n\n#define RCOLUMN_OFFSET\t\t\t( BIGCHAR_WIDTH )\n#define LCOLUMN_OFFSET\t\t\t(-BIGCHAR_WIDTH )\n\n#define SLIDER_RANGE\t\t\t10\n#define\tMAX_EDIT_LINE\t\t\t256\n\n#define MAX_MENUDEPTH\t\t\t8\n#define MAX_MENUITEMS\t\t\t64\n\n#define MTYPE_NULL\t\t\t\t0\n#define MTYPE_SLIDER\t\t\t1\t\n#define MTYPE_ACTION\t\t\t2\n#define MTYPE_SPINCONTROL\t\t3\n#define MTYPE_FIELD\t\t\t\t4\n#define MTYPE_RADIOBUTTON\t\t5\n#define MTYPE_BITMAP\t\t\t6\t\n#define MTYPE_TEXT\t\t\t\t7\n#define MTYPE_SCROLLLIST\t\t8\n#define MTYPE_PTEXT\t\t\t\t9\n#define MTYPE_BTEXT\t\t\t\t10\n\n#define QMF_BLINK\t\t\t\t0x00000001\n#define QMF_SMALLFONT\t\t\t0x00000002\n#define QMF_LEFT_JUSTIFY\t\t0x00000004\n#define QMF_CENTER_JUSTIFY\t\t0x00000008\n#define QMF_RIGHT_JUSTIFY\t\t0x00000010\n#define QMF_NUMBERSONLY\t\t\t0x00000020\t// edit field is only numbers\n#define QMF_HIGHLIGHT\t\t\t0x00000040\n#define QMF_HIGHLIGHT_IF_FOCUS\t0x00000080\t// steady focus\n#define QMF_PULSEIFFOCUS\t\t0x00000100\t// pulse if focus\n#define QMF_HASMOUSEFOCUS\t\t0x00000200\n#define QMF_NOONOFFTEXT\t\t\t0x00000400\n#define QMF_MOUSEONLY\t\t\t0x00000800\t// only mouse input allowed\n#define QMF_HIDDEN\t\t\t\t0x00001000\t// skips drawing\n#define QMF_GRAYED\t\t\t\t0x00002000\t// grays and disables\n#define QMF_INACTIVE\t\t\t0x00004000\t// disables any input\n#define QMF_NODEFAULTINIT\t\t0x00008000\t// skip default initialization\n#define QMF_OWNERDRAW\t\t\t0x00010000\n#define QMF_PULSE\t\t\t\t0x00020000\n#define QMF_LOWERCASE\t\t\t0x00040000\t// edit field is all lower case\n#define QMF_UPPERCASE\t\t\t0x00080000\t// edit field is all upper case\n#define QMF_SILENT\t\t\t\t0x00100000\n\n// callback notifications\n#define QM_GOTFOCUS\t\t\t\t1\n#define QM_LOSTFOCUS\t\t\t2\n#define QM_ACTIVATED\t\t\t3\n\ntypedef struct _tag_menuframework\n{\n\tint\tcursor;\n\tint cursor_prev;\n\n\tint\tnitems;\n\tvoid *items[MAX_MENUITEMS];\n\n\tvoid (*draw) (void);\n\tsfxHandle_t (*key) (int key);\n\n\tqboolean\twrapAround;\n\tqboolean\tfullscreen;\n\tqboolean\tshowlogo;\n} menuframework_s;\n\ntypedef struct\n{\n\tint type;\n\tconst char *name;\n\tint\tid;\n\tint x, y;\n\tint left;\n\tint\ttop;\n\tint\tright;\n\tint\tbottom;\n\tmenuframework_s *parent;\n\tint menuPosition;\n\tunsigned flags;\n\n\tvoid (*callback)( void *self, int event );\n\tvoid (*statusbar)( void *self );\n\tvoid (*ownerdraw)( void *self );\n} menucommon_s;\n\ntypedef struct {\n\tint\t\tcursor;\n\tint\t\tscroll;\n\tint\t\twidthInChars;\n\tchar\tbuffer[MAX_EDIT_LINE];\n\tint\t\tmaxchars;\n} mfield_t;\n\ntypedef struct\n{\n\tmenucommon_s\tgeneric;\n\tmfield_t\t\tfield;\n} menufield_s;\n\ntypedef struct \n{\n\tmenucommon_s generic;\n\n\tfloat minvalue;\n\tfloat maxvalue;\n\tfloat curvalue;\n\n\tfloat range;\n} menuslider_s;\n\ntypedef struct\n{\n\tmenucommon_s generic;\n\n\tint\toldvalue;\n\tint curvalue;\n\tint\tnumitems;\n\tint\ttop;\n\t\t\n\tconst char **itemnames;\n\n\tint width;\n\tint height;\n\tint\tcolumns;\n\tint\tseperation;\n} menulist_s;\n\ntypedef struct\n{\n\tmenucommon_s generic;\n} menuaction_s;\n\ntypedef struct\n{\n\tmenucommon_s generic;\n\tint curvalue;\n} menuradiobutton_s;\n\ntypedef struct\n{\n\tmenucommon_s\tgeneric;\n\tchar*\t\t\tfocuspic;\t\n\tchar*\t\t\terrorpic;\n\tqhandle_t\t\tshader;\n\tqhandle_t\t\tfocusshader;\n\tint\t\t\t\twidth;\n\tint\t\t\t\theight;\n\tfloat*\t\t\tfocuscolor;\n} menubitmap_s;\n\ntypedef struct\n{\n\tmenucommon_s\tgeneric;\n\tchar*\t\t\tstring;\n\tint\t\t\t\tstyle;\n\tfloat*\t\t\tcolor;\n} menutext_s;\n\nextern void\t\t\tMenu_Cache( void );\nextern void\t\t\tMenu_Focus( menucommon_s *m );\nextern void\t\t\tMenu_AddItem( menuframework_s *menu, void *item );\nextern void\t\t\tMenu_AdjustCursor( menuframework_s *menu, int dir );\nextern void\t\t\tMenu_Draw( menuframework_s *menu );\nextern void\t\t\t*Menu_ItemAtCursor( menuframework_s *m );\nextern sfxHandle_t\tMenu_ActivateItem( menuframework_s *s, menucommon_s* item );\nextern void\t\t\tMenu_SetCursor( menuframework_s *s, int cursor );\nextern void\t\t\tMenu_SetCursorToItem( menuframework_s *m, void* ptr );\nextern sfxHandle_t\tMenu_DefaultKey( menuframework_s *s, int key );\nextern void\t\t\tBitmap_Init( menubitmap_s *b );\nextern void\t\t\tBitmap_Draw( menubitmap_s *b );\nextern void\t\t\tScrollList_Draw( menulist_s *l );\nextern sfxHandle_t\tScrollList_Key( menulist_s *l, int key );\nextern sfxHandle_t\tmenu_in_sound;\nextern sfxHandle_t\tmenu_move_sound;\nextern sfxHandle_t\tmenu_out_sound;\nextern sfxHandle_t\tmenu_buzz_sound;\nextern sfxHandle_t\tmenu_null_sound;\nextern sfxHandle_t\tweaponChangeSound;\nextern vec4_t\t\tmenu_text_color;\nextern vec4_t\t\tmenu_grayed_color;\nextern vec4_t\t\tmenu_dark_color;\nextern vec4_t\t\tmenu_highlight_color;\nextern vec4_t\t\tmenu_red_color;\nextern vec4_t\t\tmenu_black_color;\nextern vec4_t\t\tmenu_dim_color;\nextern vec4_t\t\tcolor_black;\nextern vec4_t\t\tcolor_white;\nextern vec4_t\t\tcolor_yellow;\nextern vec4_t\t\tcolor_blue;\nextern vec4_t\t\tcolor_orange;\nextern vec4_t\t\tcolor_red;\nextern vec4_t\t\tcolor_dim;\nextern vec4_t\t\tname_color;\nextern vec4_t\t\tlist_color;\nextern vec4_t\t\tlistbar_color;\nextern vec4_t\t\ttext_color_disabled; \nextern vec4_t\t\ttext_color_normal;\nextern vec4_t\t\ttext_color_highlight;\n\nextern char\t*ui_medalNames[];\nextern char\t*ui_medalPicNames[];\nextern char\t*ui_medalSounds[];\n\n//\n// ui_mfield.c\n//\nextern void\t\t\tMField_Clear( mfield_t *edit );\nextern void\t\t\tMField_KeyDownEvent( mfield_t *edit, int key );\nextern void\t\t\tMField_CharEvent( mfield_t *edit, int ch );\nextern void\t\t\tMField_Draw( mfield_t *edit, int x, int y, int style, vec4_t color );\nextern void\t\t\tMenuField_Init( menufield_s* m );\nextern void\t\t\tMenuField_Draw( menufield_s *f );\nextern sfxHandle_t\tMenuField_Key( menufield_s* m, int* key );\n\n//\n// ui_menu.c\n//\nextern void MainMenu_Cache( void );\nextern void UI_MainMenu(void);\nextern void UI_RegisterCvars( void );\nextern void UI_UpdateCvars( void );\n\n//\n// ui_credits.c\n//\nextern void UI_CreditMenu( void );\n\n//\n// ui_ingame.c\n//\nextern void InGame_Cache( void );\nextern void UI_InGameMenu(void);\n\n//\n// ui_confirm.c\n//\nextern void ConfirmMenu_Cache( void );\nextern void UI_ConfirmMenu( const char *question, void (*draw)( void ), void (*action)( qboolean result ) );\nextern void UI_ConfirmMenu_Style( const char *question, int style, void (*draw)( void ), void (*action)( qboolean result ) );\nextern void UI_Message( const char **lines );\n\n//\n// ui_setup.c\n//\nextern void UI_SetupMenu_Cache( void );\nextern void UI_SetupMenu(void);\n\n//\n// ui_team.c\n//\nextern void UI_TeamMainMenu( void );\nextern void TeamMain_Cache( void );\n\n//\n// ui_connect.c\n//\nextern void UI_DrawConnectScreen( qboolean overlay );\n\n//\n// ui_controls2.c\n//\nextern void UI_ControlsMenu( void );\nextern void Controls_Cache( void );\n\n//\n// ui_demo2.c\n//\nextern void UI_DemosMenu( void );\nextern void Demos_Cache( void );\n\n//\n// ui_cinematics.c\n//\nextern void UI_CinematicsMenu( void );\nextern void UI_CinematicsMenu_f( void );\nextern void UI_CinematicsMenu_Cache( void );\n\n//\n// ui_mods.c\n//\nextern void UI_ModsMenu( void );\nextern void UI_ModsMenu_Cache( void );\n\n//\n// ui_cdkey.c\n//\nextern void UI_CDKeyMenu( void );\nextern void UI_CDKeyMenu_Cache( void );\nextern void UI_CDKeyMenu_f( void );\n\n//\n// ui_playermodel.c\n//\nextern void UI_PlayerModelMenu( void );\nextern void PlayerModel_Cache( void );\n\n//\n// ui_playersettings.c\n//\nextern void UI_PlayerSettingsMenu( void );\nextern void PlayerSettings_Cache( void );\n\n//\n// ui_preferences.c\n//\nextern void UI_PreferencesMenu( void );\nextern void Preferences_Cache( void );\n\n//\n// ui_specifyleague.c\n//\nextern void UI_SpecifyLeagueMenu( void );\nextern void SpecifyLeague_Cache( void );\n\n//\n// ui_specifyserver.c\n//\nextern void UI_SpecifyServerMenu( void );\nextern void SpecifyServer_Cache( void );\n\n//\n// ui_servers2.c\n//\n#define MAX_FAVORITESERVERS 16\n\nextern void UI_ArenaServersMenu( void );\nextern void ArenaServers_Cache( void );\n\n//\n// ui_startserver.c\n//\nextern void UI_StartServerMenu( qboolean multiplayer );\nextern void StartServer_Cache( void );\nextern void ServerOptions_Cache( void );\nextern void UI_BotSelectMenu( char *bot );\nextern void UI_BotSelectMenu_Cache( void );\n\n//\n// ui_serverinfo.c\n//\nextern void UI_ServerInfoMenu( void );\nextern void ServerInfo_Cache( void );\n\n//\n// ui_video.c\n//\nextern void UI_GraphicsOptionsMenu( void );\nextern void GraphicsOptions_Cache( void );\nextern void DriverInfo_Cache( void );\n\n//\n// ui_players.c\n//\n\n//FIXME ripped from cg_local.h\ntypedef struct {\n\tint\t\t\toldFrame;\n\tint\t\t\toldFrameTime;\t\t// time when ->oldFrame was exactly on\n\n\tint\t\t\tframe;\n\tint\t\t\tframeTime;\t\t\t// time when ->frame will be exactly on\n\n\tfloat\t\tbacklerp;\n\n\tfloat\t\tyawAngle;\n\tqboolean\tyawing;\n\tfloat\t\tpitchAngle;\n\tqboolean\tpitching;\n\n\tint\t\t\tanimationNumber;\t// may include ANIM_TOGGLEBIT\n\tanimation_t\t*animation;\n\tint\t\t\tanimationTime;\t\t// time when the first frame of the animation will be exact\n} lerpFrame_t;\n\ntypedef struct {\n\t// model info\n\tqhandle_t\t\tlegsModel;\n\tqhandle_t\t\tlegsSkin;\n\tlerpFrame_t\t\tlegs;\n\n\tqhandle_t\t\ttorsoModel;\n\tqhandle_t\t\ttorsoSkin;\n\tlerpFrame_t\t\ttorso;\n\n\tqhandle_t\t\theadModel;\n\tqhandle_t\t\theadSkin;\n\n\tanimation_t\t\tanimations[MAX_ANIMATIONS];\n\n\tqhandle_t\t\tweaponModel;\n\tqhandle_t\t\tbarrelModel;\n\tqhandle_t\t\tflashModel;\n\tvec3_t\t\t\tflashDlightColor;\n\tint\t\t\t\tmuzzleFlashTime;\n\n\t// currently in use drawing parms\n\tvec3_t\t\t\tviewAngles;\n\tvec3_t\t\t\tmoveAngles;\n\tweapon_t\t\tcurrentWeapon;\n\tint\t\t\t\tlegsAnim;\n\tint\t\t\t\ttorsoAnim;\n\n\t// animation vars\n\tweapon_t\t\tweapon;\n\tweapon_t\t\tlastWeapon;\n\tweapon_t\t\tpendingWeapon;\n\tint\t\t\t\tweaponTimer;\n\tint\t\t\t\tpendingLegsAnim;\n\tint\t\t\t\ttorsoAnimationTimer;\n\n\tint\t\t\t\tpendingTorsoAnim;\n\tint\t\t\t\tlegsAnimationTimer;\n\n\tqboolean\t\tchat;\n\tqboolean\t\tnewModel;\n\n\tqboolean\t\tbarrelSpinning;\n\tfloat\t\t\tbarrelAngle;\n\tint\t\t\t\tbarrelTime;\n\n\tint\t\t\t\trealWeapon;\n} playerInfo_t;\n\nvoid UI_DrawPlayer( float x, float y, float w, float h, playerInfo_t *pi, int time );\nvoid UI_PlayerInfo_SetModel( playerInfo_t *pi, const char *model );\nvoid UI_PlayerInfo_SetInfo( playerInfo_t *pi, int legsAnim, int torsoAnim, vec3_t viewAngles, vec3_t moveAngles, weapon_t weaponNum, qboolean chat );\nqboolean UI_RegisterClientModelname( playerInfo_t *pi, const char *modelSkinName );\n\n//\n// ui_atoms.c\n//\ntypedef struct {\n\tint\t\t\t\t\tframetime;\n\tint\t\t\t\t\trealtime;\n\tint\t\t\t\t\tcursorx;\n\tint\t\t\t\t\tcursory;\n\tint\t\t\t\t\tmenusp;\n\tmenuframework_s*\tactivemenu;\n\tmenuframework_s*\tstack[MAX_MENUDEPTH];\n\tglconfig_t\t\t\tglconfig;\n\tqboolean\t\t\tdebug;\n\tqhandle_t\t\t\twhiteShader;\n\tqhandle_t\t\t\tmenuBackShader;\n\tqhandle_t\t\t\tmenuBackNoLogoShader;\n\tqhandle_t\t\t\tcharset;\n\tqhandle_t\t\t\tcharsetProp;\n\tqhandle_t\t\t\tcharsetPropGlow;\n\tqhandle_t\t\t\tcharsetPropB;\n\tqhandle_t\t\t\tcursor;\n\tqhandle_t\t\t\trb_on;\n\tqhandle_t\t\t\trb_off;\n\tfloat\t\t\t\tscale;\n\tfloat\t\t\t\tbias;\n\tqboolean\t\t\tdemoversion;\n\tqboolean\t\t\tfirstdraw;\n} uiStatic_t;\n\nextern void\t\t\tUI_Init( void );\nextern void\t\t\tUI_Shutdown( void );\nextern void\t\t\tUI_KeyEvent( int key, int down );\nextern void\t\t\tUI_MouseEvent( int dx, int dy );\nextern void\t\t\tUI_Refresh( int realtime );\nextern qboolean\t\tUI_ConsoleCommand( int realTime );\nextern float\t\tUI_ClampCvar( float min, float max, float value );\nextern void\t\t\tUI_DrawNamedPic( float x, float y, float width, float height, const char *picname );\nextern void\t\t\tUI_DrawHandlePic( float x, float y, float w, float h, qhandle_t hShader ); \nextern void\t\t\tUI_FillRect( float x, float y, float width, float height, const float *color );\nextern void\t\t\tUI_DrawRect( float x, float y, float width, float height, const float *color );\nextern void\t\t\tUI_UpdateScreen( void );\nextern void\t\t\tUI_SetColor( const float *rgba );\nextern void\t\t\tUI_LerpColor(vec4_t a, vec4_t b, vec4_t c, float t);\nextern void\t\t\tUI_DrawBannerString( int x, int y, const char* str, int style, vec4_t color );\nextern float\t\tUI_ProportionalSizeScale( int style );\nextern void\t\t\tUI_DrawProportionalString( int x, int y, const char* str, int style, vec4_t color );\nextern void\t\t\tUI_DrawProportionalString_AutoWrapped( int x, int ystart, int xmax, int ystep, const char* str, int style, vec4_t color );\nextern int\t\t\tUI_ProportionalStringWidth( const char* str );\nextern void\t\t\tUI_DrawString( int x, int y, const char* str, int style, vec4_t color );\nextern void\t\t\tUI_DrawChar( int x, int y, int ch, int style, vec4_t color );\nextern qboolean \tUI_CursorInRect (int x, int y, int width, int height);\nextern void\t\t\tUI_AdjustFrom640( float *x, float *y, float *w, float *h );\nextern void\t\t\tUI_DrawTextBox (int x, int y, int width, int lines);\nextern qboolean\t\tUI_IsFullscreen( void );\nextern void\t\t\tUI_SetActiveMenu( uiMenuCommand_t menu );\nextern void\t\t\tUI_PushMenu ( menuframework_s *menu );\nextern void\t\t\tUI_PopMenu (void);\nextern void\t\t\tUI_ForceMenuOff (void);\nextern char\t\t\t*UI_Argv( int arg );\nextern char\t\t\t*UI_Cvar_VariableString( const char *var_name );\nextern void\t\t\tUI_Refresh( int time );\nextern void\t\t\tUI_StartDemoLoop( void );\nextern qboolean\t\tm_entersound;\nextern uiStatic_t\tuis;\n\n//\n// ui_spLevel.c\n//\nvoid UI_SPLevelMenu_Cache( void );\nvoid UI_SPLevelMenu( void );\nvoid UI_SPLevelMenu_f( void );\nvoid UI_SPLevelMenu_ReInit( void );\n\n//\n// ui_spArena.c\n//\nvoid UI_SPArena_Start( const char *arenaInfo );\n\n//\n// ui_spPostgame.c\n//\nvoid UI_SPPostgameMenu_Cache( void );\nvoid UI_SPPostgameMenu_f( void );\n\n//\n// ui_spSkill.c\n//\nvoid UI_SPSkillMenu( const char *arenaInfo );\nvoid UI_SPSkillMenu_Cache( void );\n\n//\n// ui_syscalls.c\n//\nvoid\t\t\ttrap_Print( const char *string );\nvoid\t\t\ttrap_Error( const char *string );\nint\t\t\t\ttrap_Milliseconds( void );\nvoid\t\t\ttrap_Cvar_Register( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags );\nvoid\t\t\ttrap_Cvar_Update( vmCvar_t *vmCvar );\nvoid\t\t\ttrap_Cvar_Set( const char *var_name, const char *value );\nfloat\t\t\ttrap_Cvar_VariableValue( const char *var_name );\nvoid\t\t\ttrap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize );\nvoid\t\t\ttrap_Cvar_SetValue( const char *var_name, float value );\nvoid\t\t\ttrap_Cvar_Reset( const char *name );\nvoid\t\t\ttrap_Cvar_Create( const char *var_name, const char *var_value, int flags );\nvoid\t\t\ttrap_Cvar_InfoStringBuffer( int bit, char *buffer, int bufsize );\nint\t\t\t\ttrap_Argc( void );\nvoid\t\t\ttrap_Argv( int n, char *buffer, int bufferLength );\nvoid\t\t\ttrap_Cmd_ExecuteText( int exec_when, const char *text );\t// don't use EXEC_NOW!\nint\t\t\t\ttrap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode );\nvoid\t\t\ttrap_FS_Read( void *buffer, int len, fileHandle_t f );\nvoid\t\t\ttrap_FS_Write( const void *buffer, int len, fileHandle_t f );\nvoid\t\t\ttrap_FS_FCloseFile( fileHandle_t f );\nint\t\t\t\ttrap_FS_GetFileList(  const char *path, const char *extension, char *listbuf, int bufsize );\nint\t\t\t\ttrap_FS_Seek( fileHandle_t f, long offset, int origin ); // fsOrigin_t\nqhandle_t\t\ttrap_R_RegisterModel( const char *name );\nqhandle_t\t\ttrap_R_RegisterSkin( const char *name );\nqhandle_t\t\ttrap_R_RegisterShaderNoMip( const char *name );\nvoid\t\t\ttrap_R_ClearScene( void );\nvoid\t\t\ttrap_R_AddRefEntityToScene( const refEntity_t *re );\nvoid\t\t\ttrap_R_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts );\nvoid\t\t\ttrap_R_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b );\nvoid\t\t\ttrap_R_RenderScene( const refdef_t *fd );\nvoid\t\t\ttrap_R_SetColor( const float *rgba );\nvoid\t\t\ttrap_R_DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, qhandle_t hShader );\nvoid\t\t\ttrap_UpdateScreen( void );\nint\t\t\t\ttrap_CM_LerpTag( orientation_t *tag, clipHandle_t mod, int startFrame, int endFrame, float frac, const char *tagName );\nvoid\t\t\ttrap_S_StartLocalSound( sfxHandle_t sfx, int channelNum );\nsfxHandle_t\ttrap_S_RegisterSound( const char *sample, qboolean compressed );\nvoid\t\t\ttrap_Key_KeynumToStringBuf( int keynum, char *buf, int buflen );\nvoid\t\t\ttrap_Key_GetBindingBuf( int keynum, char *buf, int buflen );\nvoid\t\t\ttrap_Key_SetBinding( int keynum, const char *binding );\nqboolean\t\ttrap_Key_IsDown( int keynum );\nqboolean\t\ttrap_Key_GetOverstrikeMode( void );\nvoid\t\t\ttrap_Key_SetOverstrikeMode( qboolean state );\nvoid\t\t\ttrap_Key_ClearStates( void );\nint\t\t\t\ttrap_Key_GetCatcher( void );\nvoid\t\t\ttrap_Key_SetCatcher( int catcher );\nvoid\t\t\ttrap_GetClipboardData( char *buf, int bufsize );\nvoid\t\t\ttrap_GetClientState( uiClientState_t *state );\nvoid\t\t\ttrap_GetGlconfig( glconfig_t *glconfig );\nint\t\t\t\ttrap_GetConfigString( int index, char* buff, int buffsize );\nint\t\t\t\ttrap_LAN_GetServerCount( int source );\nvoid\t\t\ttrap_LAN_GetServerAddressString( int source, int n, char *buf, int buflen );\nvoid\t\t\ttrap_LAN_GetServerInfo( int source, int n, char *buf, int buflen );\nint\t\t\t\ttrap_LAN_GetPingQueueCount( void );\nint\t\t\t\ttrap_LAN_ServerStatus( const char *serverAddress, char *serverStatus, int maxLen );\nvoid\t\t\ttrap_LAN_ClearPing( int n );\nvoid\t\t\ttrap_LAN_GetPing( int n, char *buf, int buflen, int *pingtime );\nvoid\t\t\ttrap_LAN_GetPingInfo( int n, char *buf, int buflen );\nint\t\t\t\ttrap_MemoryRemaining( void );\nvoid\t\t\ttrap_GetCDKey( char *buf, int buflen );\nvoid\t\t\ttrap_SetCDKey( char *buf );\n\nqboolean               trap_VerifyCDKey( const char *key, const char *chksum); // bk001208 - RC4\n\nvoid\t\t\ttrap_SetPbClStatus( int status );\n\n//\n// ui_addbots.c\n//\nvoid UI_AddBots_Cache( void );\nvoid UI_AddBotsMenu( void );\n\n//\n// ui_removebots.c\n//\nvoid UI_RemoveBots_Cache( void );\nvoid UI_RemoveBotsMenu( void );\n\n//\n// ui_teamorders.c\n//\nextern void UI_TeamOrdersMenu( void );\nextern void UI_TeamOrdersMenu_f( void );\nextern void UI_TeamOrdersMenu_Cache( void );\n\n//\n// ui_loadconfig.c\n//\nvoid UI_LoadConfig_Cache( void );\nvoid UI_LoadConfigMenu( void );\n\n//\n// ui_saveconfig.c\n//\nvoid UI_SaveConfigMenu_Cache( void );\nvoid UI_SaveConfigMenu( void );\n\n//\n// ui_display.c\n//\nvoid UI_DisplayOptionsMenu_Cache( void );\nvoid UI_DisplayOptionsMenu( void );\n\n//\n// ui_sound.c\n//\nvoid UI_SoundOptionsMenu_Cache( void );\nvoid UI_SoundOptionsMenu( void );\n\n//\n// ui_network.c\n//\nvoid UI_NetworkOptionsMenu_Cache( void );\nvoid UI_NetworkOptionsMenu( void );\n\n//\n// ui_gameinfo.c\n//\ntypedef enum {\n\tAWARD_ACCURACY,\n\tAWARD_IMPRESSIVE,\n\tAWARD_EXCELLENT,\n\tAWARD_GAUNTLET,\n\tAWARD_FRAGS,\n\tAWARD_PERFECT\n} awardType_t;\n\nconst char *UI_GetArenaInfoByNumber( int num );\nconst char *UI_GetArenaInfoByMap( const char *map );\nconst char *UI_GetSpecialArenaInfo( const char *tag );\nint UI_GetNumArenas( void );\nint UI_GetNumSPArenas( void );\nint UI_GetNumSPTiers( void );\n\nchar *UI_GetBotInfoByNumber( int num );\nchar *UI_GetBotInfoByName( const char *name );\nint UI_GetNumBots( void );\n\nvoid UI_GetBestScore( int level, int *score, int *skill );\nvoid UI_SetBestScore( int level, int score );\nint UI_TierCompleted( int levelWon );\nqboolean UI_ShowTierVideo( int tier );\nqboolean UI_CanShowTierVideo( int tier );\nint  UI_GetCurrentGame( void );\nvoid UI_NewGame( void );\nvoid UI_LogAwardData( int award, int data );\nint UI_GetAwardLevel( int award );\n\nvoid UI_SPUnlock_f( void );\nvoid UI_SPUnlockMedals_f( void );\n\nvoid UI_InitGameinfo( void );\n\n//GRank\n\n//\n// ui_rankings.c\n//\nvoid Rankings_DrawText( void* self );\nvoid Rankings_DrawName( void* self );\nvoid Rankings_DrawPassword( void* self );\nvoid Rankings_Cache( void );\nvoid UI_RankingsMenu( void );\n\n//\n// ui_login.c\n//\nvoid Login_Cache( void );\nvoid UI_LoginMenu( void );\n\n//\n// ui_signup.c\n//\nvoid Signup_Cache( void );\nvoid UI_SignupMenu( void );\n\n//\n// ui_rankstatus.c\n//\nvoid RankStatus_Cache( void );\nvoid UI_RankStatusMenu( void );\n\n#endif\n"
  },
  {
    "path": "src/q3_ui/ui_login.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n//\n// ui_login.c\n//\n\n#include \"ui_local.h\"\n\n\n#define LOGIN_FRAME\t\t\"menu/art/cut_frame\"\n\n#define ID_NAME\t\t\t100\n#define ID_NAME_BOX\t\t101\n#define ID_PASSWORD\t\t102\n#define ID_PASSWORD_BOX\t103\n#define ID_LOGIN\t\t104\n#define ID_CANCEL\t\t105\n\n\ntypedef struct\n{\n\tmenuframework_s\tmenu;\n\tmenubitmap_s\tframe;\n\tmenutext_s\t\tname;\n\tmenufield_s\t\tname_box;\n\tmenutext_s\t\tpassword;\n\tmenufield_s\t\tpassword_box;\n\tmenutext_s\t\tlogin;\n\tmenutext_s\t\tcancel;\n} login_t;\n\nstatic login_t\ts_login;\n\nstatic menuframework_s\ts_login_menu;\nstatic menuaction_s\t\ts_login_login;\nstatic menuaction_s\t\ts_login_cancel;\n\nstatic vec4_t s_login_color_prompt  = {1.00, 0.43, 0.00, 1.00};\n\n/*\n===============\nLogin_MenuEvent\n===============\n*/\nstatic void Login_MenuEvent( void* ptr, int event ) {\n\tif( event != QM_ACTIVATED ) {\n\t\treturn;\n\t}\n\n\tswitch( ((menucommon_s*)ptr)->id ) {\n\tcase ID_LOGIN:\n\t\t// set name\t\t\t\t\t\t\t\t``\n\t\t//trap_Cvar_Set( \"name\", s_login.name_box.field.buffer );\n\t\t/*\n\t\ttrap_Cvar_Set( \"rank_name\", s_login.name_box.field.buffer );\n\t\ttrap_Cvar_Set( \"rank_pwd\", s_login.password_box.field.buffer );\n\t\t*/\n\n\t\t// login\n\t\ttrap_CL_UI_RankUserLogin(\n\t\t\ts_login.name_box.field.buffer, \n\t\t\ts_login.password_box.field.buffer );\n\n\t\tUI_ForceMenuOff();\n\t\tbreak;\n\t\t\n\tcase ID_CANCEL:\n\t\tUI_PopMenu();\n\t\tbreak;\n\t}\n}\n\n\n/*\n===============\nLogin_MenuInit\n===============\n*/\nvoid Login_MenuInit( void ) {\n\tint\t\t\t\ty;\n\n\tmemset( &s_login, 0, sizeof(s_login) );\n\n\tLogin_Cache();\n\n\ts_login.menu.wrapAround = qtrue;\n\ts_login.menu.fullscreen = qfalse;\n\n\ts_login.frame.generic.type\t\t\t= MTYPE_BITMAP;\n\ts_login.frame.generic.flags\t\t\t= QMF_INACTIVE;\n\ts_login.frame.generic.name\t\t\t= LOGIN_FRAME;\n\ts_login.frame.generic.x\t\t\t\t= 142; //320-233;\n\ts_login.frame.generic.y\t\t\t\t= 118; //240-166;\n\ts_login.frame.width\t\t\t\t\t= 359; //466;\n\ts_login.frame.height\t\t\t\t= 256; //332;\n\n\ty = 214;\n\n\ts_login.name.generic.type\t\t\t= MTYPE_PTEXT;\n\ts_login.name.generic.flags\t\t\t= QMF_RIGHT_JUSTIFY|QMF_INACTIVE;\n\ts_login.name.generic.id\t\t\t\t= ID_NAME;\n\ts_login.name.generic.x\t\t\t\t= 310;\n\ts_login.name.generic.y\t\t\t\t= y;\n\ts_login.name.string\t\t\t\t\t= \"NAME\";\n\ts_login.name.style\t\t\t\t\t= UI_RIGHT|UI_SMALLFONT;\n\ts_login.name.color\t\t\t\t\t= s_login_color_prompt;\n\n\ts_login.name_box.generic.type\t\t= MTYPE_FIELD;\n\ts_login.name_box.generic.ownerdraw\t= Rankings_DrawName;\n\ts_login.name_box.generic.name\t\t= \"\";\n\ts_login.name_box.generic.flags\t\t= 0;\n\ts_login.name_box.generic.x\t\t\t= 330;\n\ts_login.name_box.generic.y\t\t\t= y;\n\ts_login.name_box.field.widthInChars\t= 16;\n\ts_login.name_box.field.maxchars\t\t= 16;\n\ty += 20;\n\t\n\ts_login.password.generic.type\t\t= MTYPE_PTEXT;\n\ts_login.password.generic.flags\t\t= QMF_RIGHT_JUSTIFY|QMF_INACTIVE;\n\ts_login.password.generic.id\t\t\t= ID_PASSWORD;\n\ts_login.password.generic.x\t\t\t= 310;\n\ts_login.password.generic.y\t\t\t= y;\n\ts_login.password.string\t\t\t\t= \"PASSWORD\";\n\ts_login.password.style\t\t\t\t= UI_RIGHT|UI_SMALLFONT;\n\ts_login.password.color\t\t\t\t= s_login_color_prompt;\n\n\ts_login.password_box.generic.type\t\t= MTYPE_FIELD;\n\ts_login.password_box.generic.ownerdraw\t= Rankings_DrawPassword;\n\ts_login.password_box.generic.name\t\t= \"\";\n\ts_login.password_box.generic.flags\t\t= 0;\n\ts_login.password_box.generic.x\t\t\t= 330;\n\ts_login.password_box.generic.y\t\t\t= y;\n\ts_login.password_box.field.widthInChars\t= 16;\n\ts_login.password_box.field.maxchars\t\t= 16;\n\ty += 40;\n\n\ts_login.login.generic.type\t\t\t\t= MTYPE_PTEXT;\n\ts_login.login.generic.flags\t\t\t\t= QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_login.login.generic.id\t\t\t\t= ID_LOGIN;\n\ts_login.login.generic.callback\t\t\t= Login_MenuEvent;\n\ts_login.login.generic.x\t\t\t\t\t= 310;\n\ts_login.login.generic.y\t\t\t\t\t= y;\n\ts_login.login.string\t\t\t\t\t= \"LOGIN\";\n\ts_login.login.style\t\t\t\t\t\t= UI_RIGHT|UI_SMALLFONT;\n\ts_login.login.color\t\t\t\t\t\t= colorRed;\n\n\ts_login.cancel.generic.type\t\t\t\t= MTYPE_PTEXT;\n\ts_login.cancel.generic.flags\t\t\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_login.cancel.generic.id\t\t\t\t= ID_CANCEL;\n\ts_login.cancel.generic.callback\t\t\t= Login_MenuEvent;\n\ts_login.cancel.generic.x\t\t\t\t= 330;\n\ts_login.cancel.generic.y\t\t\t\t= y;\n\ts_login.cancel.string\t\t\t\t\t= \"CANCEL\";\n\ts_login.cancel.style\t\t\t\t\t= UI_LEFT|UI_SMALLFONT;\n\ts_login.cancel.color\t\t\t\t\t= colorRed;\n\ty += 20;\n\n\tMenu_AddItem( &s_login.menu, (void*) &s_login.frame );\n\tMenu_AddItem( &s_login.menu, (void*) &s_login.name );\n\tMenu_AddItem( &s_login.menu, (void*) &s_login.name_box );\n\tMenu_AddItem( &s_login.menu, (void*) &s_login.password );\n\tMenu_AddItem( &s_login.menu, (void*) &s_login.password_box );\n\tMenu_AddItem( &s_login.menu, (void*) &s_login.login );\n\tMenu_AddItem( &s_login.menu, (void*) &s_login.cancel );\n}\n\n\n/*\n===============\nLogin_Cache\n===============\n*/\nvoid Login_Cache( void ) {\n\ttrap_R_RegisterShaderNoMip( LOGIN_FRAME );\n}\n\n\n/*\n===============\nUI_LoginMenu\n===============\n*/\nvoid UI_LoginMenu( void ) {\n\tLogin_MenuInit();\n\tUI_PushMenu ( &s_login.menu );\n}\n\n\n"
  },
  {
    "path": "src/q3_ui/ui_main.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n/*\n=======================================================================\n\nUSER INTERFACE MAIN\n\n=======================================================================\n*/\n\n\n#include \"ui_local.h\"\n\n\n/*\n================\nvmMain\n\nThis is the only way control passes into the module.\nThis must be the very first function compiled into the .qvm file\n================\n*/\nintptr_t vmMain( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10, int arg11  ) {\n\tswitch ( command ) {\n\tcase UI_GETAPIVERSION:\n\t\treturn UI_API_VERSION;\n\n\tcase UI_INIT:\n\t\tUI_Init();\n\t\treturn 0;\n\n\tcase UI_SHUTDOWN:\n\t\tUI_Shutdown();\n\t\treturn 0;\n\n\tcase UI_KEY_EVENT:\n\t\tUI_KeyEvent( arg0, arg1 );\n\t\treturn 0;\n\n\tcase UI_MOUSE_EVENT:\n\t\tUI_MouseEvent( arg0, arg1 );\n\t\treturn 0;\n\n\tcase UI_REFRESH:\n\t\tUI_Refresh( arg0 );\n\t\treturn 0;\n\n\tcase UI_IS_FULLSCREEN:\n\t\treturn UI_IsFullscreen();\n\n\tcase UI_SET_ACTIVE_MENU:\n\t\tUI_SetActiveMenu( arg0 );\n\t\treturn 0;\n\n\tcase UI_CONSOLE_COMMAND:\n\t\treturn UI_ConsoleCommand(arg0);\n\n\tcase UI_DRAW_CONNECT_SCREEN:\n\t\tUI_DrawConnectScreen( arg0 );\n\t\treturn 0;\n\tcase UI_HASUNIQUECDKEY:\t\t\t\t// mod authors need to observe this\n\t\treturn qtrue;  // bk010117 - change this to qfalse for mods!\n\t}\n\n\treturn -1;\n}\n\n\n/*\n================\ncvars\n================\n*/\n\ntypedef struct {\n\tvmCvar_t\t*vmCvar;\n\tchar\t\t*cvarName;\n\tchar\t\t*defaultString;\n\tint\t\t\tcvarFlags;\n} cvarTable_t;\n\nvmCvar_t\tui_ffa_fraglimit;\nvmCvar_t\tui_ffa_timelimit;\n\nvmCvar_t\tui_tourney_fraglimit;\nvmCvar_t\tui_tourney_timelimit;\n\nvmCvar_t\tui_team_fraglimit;\nvmCvar_t\tui_team_timelimit;\nvmCvar_t\tui_team_friendly;\n\nvmCvar_t\tui_ctf_capturelimit;\nvmCvar_t\tui_ctf_timelimit;\nvmCvar_t\tui_ctf_friendly;\n\nvmCvar_t\tui_arenasFile;\nvmCvar_t\tui_botsFile;\nvmCvar_t\tui_spScores1;\nvmCvar_t\tui_spScores2;\nvmCvar_t\tui_spScores3;\nvmCvar_t\tui_spScores4;\nvmCvar_t\tui_spScores5;\nvmCvar_t\tui_spAwards;\nvmCvar_t\tui_spVideos;\nvmCvar_t\tui_spSkill;\n\nvmCvar_t\tui_spSelection;\n\nvmCvar_t\tui_browserMaster;\nvmCvar_t\tui_browserGameType;\nvmCvar_t\tui_browserSortKey;\nvmCvar_t\tui_browserShowFull;\nvmCvar_t\tui_browserShowEmpty;\n\nvmCvar_t\tui_brassTime;\nvmCvar_t\tui_drawCrosshair;\nvmCvar_t\tui_drawCrosshairNames;\nvmCvar_t\tui_marks;\n\nvmCvar_t\tui_server1;\nvmCvar_t\tui_server2;\nvmCvar_t\tui_server3;\nvmCvar_t\tui_server4;\nvmCvar_t\tui_server5;\nvmCvar_t\tui_server6;\nvmCvar_t\tui_server7;\nvmCvar_t\tui_server8;\nvmCvar_t\tui_server9;\nvmCvar_t\tui_server10;\nvmCvar_t\tui_server11;\nvmCvar_t\tui_server12;\nvmCvar_t\tui_server13;\nvmCvar_t\tui_server14;\nvmCvar_t\tui_server15;\nvmCvar_t\tui_server16;\n\nvmCvar_t\tui_cdkeychecked;\n\n// bk001129 - made static to avoid aliasing.\nstatic cvarTable_t\t\tcvarTable[] = {\n\t{ &ui_ffa_fraglimit, \"ui_ffa_fraglimit\", \"20\", CVAR_ARCHIVE },\n\t{ &ui_ffa_timelimit, \"ui_ffa_timelimit\", \"0\", CVAR_ARCHIVE },\n\n\t{ &ui_tourney_fraglimit, \"ui_tourney_fraglimit\", \"0\", CVAR_ARCHIVE },\n\t{ &ui_tourney_timelimit, \"ui_tourney_timelimit\", \"15\", CVAR_ARCHIVE },\n\n\t{ &ui_team_fraglimit, \"ui_team_fraglimit\", \"0\", CVAR_ARCHIVE },\n\t{ &ui_team_timelimit, \"ui_team_timelimit\", \"20\", CVAR_ARCHIVE },\n\t{ &ui_team_friendly, \"ui_team_friendly\",  \"1\", CVAR_ARCHIVE },\n\n\t{ &ui_ctf_capturelimit, \"ui_ctf_capturelimit\", \"8\", CVAR_ARCHIVE },\n\t{ &ui_ctf_timelimit, \"ui_ctf_timelimit\", \"30\", CVAR_ARCHIVE },\n\t{ &ui_ctf_friendly, \"ui_ctf_friendly\",  \"0\", CVAR_ARCHIVE },\n\n\t{ &ui_arenasFile, \"g_arenasFile\", \"\", CVAR_INIT|CVAR_ROM },\n\t{ &ui_botsFile, \"g_botsFile\", \"\", CVAR_INIT|CVAR_ROM },\n\t{ &ui_spScores1, \"g_spScores1\", \"\", CVAR_ARCHIVE | CVAR_ROM },\n\t{ &ui_spScores2, \"g_spScores2\", \"\", CVAR_ARCHIVE | CVAR_ROM },\n\t{ &ui_spScores3, \"g_spScores3\", \"\", CVAR_ARCHIVE | CVAR_ROM },\n\t{ &ui_spScores4, \"g_spScores4\", \"\", CVAR_ARCHIVE | CVAR_ROM },\n\t{ &ui_spScores5, \"g_spScores5\", \"\", CVAR_ARCHIVE | CVAR_ROM },\n\t{ &ui_spAwards, \"g_spAwards\", \"\", CVAR_ARCHIVE | CVAR_ROM },\n\t{ &ui_spVideos, \"g_spVideos\", \"\", CVAR_ARCHIVE | CVAR_ROM },\n\t{ &ui_spSkill, \"g_spSkill\", \"2\", CVAR_ARCHIVE | CVAR_LATCH },\n\n\t{ &ui_spSelection, \"ui_spSelection\", \"\", CVAR_ROM },\n\n\t{ &ui_browserMaster, \"ui_browserMaster\", \"0\", CVAR_ARCHIVE },\n\t{ &ui_browserGameType, \"ui_browserGameType\", \"0\", CVAR_ARCHIVE },\n\t{ &ui_browserSortKey, \"ui_browserSortKey\", \"4\", CVAR_ARCHIVE },\n\t{ &ui_browserShowFull, \"ui_browserShowFull\", \"1\", CVAR_ARCHIVE },\n\t{ &ui_browserShowEmpty, \"ui_browserShowEmpty\", \"1\", CVAR_ARCHIVE },\n\n\t{ &ui_brassTime, \"cg_brassTime\", \"2500\", CVAR_ARCHIVE },\n\t{ &ui_drawCrosshair, \"cg_drawCrosshair\", \"4\", CVAR_ARCHIVE },\n\t{ &ui_drawCrosshairNames, \"cg_drawCrosshairNames\", \"1\", CVAR_ARCHIVE },\n\t{ &ui_marks, \"cg_marks\", \"1\", CVAR_ARCHIVE },\n\n\t{ &ui_server1, \"server1\", \"\", CVAR_ARCHIVE },\n\t{ &ui_server2, \"server2\", \"\", CVAR_ARCHIVE },\n\t{ &ui_server3, \"server3\", \"\", CVAR_ARCHIVE },\n\t{ &ui_server4, \"server4\", \"\", CVAR_ARCHIVE },\n\t{ &ui_server5, \"server5\", \"\", CVAR_ARCHIVE },\n\t{ &ui_server6, \"server6\", \"\", CVAR_ARCHIVE },\n\t{ &ui_server7, \"server7\", \"\", CVAR_ARCHIVE },\n\t{ &ui_server8, \"server8\", \"\", CVAR_ARCHIVE },\n\t{ &ui_server9, \"server9\", \"\", CVAR_ARCHIVE },\n\t{ &ui_server10, \"server10\", \"\", CVAR_ARCHIVE },\n\t{ &ui_server11, \"server11\", \"\", CVAR_ARCHIVE },\n\t{ &ui_server12, \"server12\", \"\", CVAR_ARCHIVE },\n\t{ &ui_server13, \"server13\", \"\", CVAR_ARCHIVE },\n\t{ &ui_server14, \"server14\", \"\", CVAR_ARCHIVE },\n\t{ &ui_server15, \"server15\", \"\", CVAR_ARCHIVE },\n\t{ &ui_server16, \"server16\", \"\", CVAR_ARCHIVE },\n\n\t{ &ui_cdkeychecked, \"ui_cdkeychecked\", \"0\", CVAR_ROM }\n};\n\n// bk001129 - made static to avoid aliasing\nstatic int cvarTableSize = sizeof(cvarTable) / sizeof(cvarTable[0]);\n\n\n/*\n=================\nUI_RegisterCvars\n=================\n*/\nvoid UI_RegisterCvars( void ) {\n\tint\t\t\ti;\n\tcvarTable_t\t*cv;\n\n\tfor ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ ) {\n\t\ttrap_Cvar_Register( cv->vmCvar, cv->cvarName, cv->defaultString, cv->cvarFlags );\n\t}\n}\n\n/*\n=================\nUI_UpdateCvars\n=================\n*/\nvoid UI_UpdateCvars( void ) {\n\tint\t\t\ti;\n\tcvarTable_t\t*cv;\n\n\tfor ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ ) {\n\t\ttrap_Cvar_Update( cv->vmCvar );\n\t}\n}\n"
  },
  {
    "path": "src/q3_ui/ui_menu.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n/*\n=======================================================================\n\nMAIN MENU\n\n=======================================================================\n*/\n\n\n#include \"ui_local.h\"\n\n\n#define ID_SINGLEPLAYER\t\t\t10\n#define ID_MULTIPLAYER\t\t\t11\n#define ID_SETUP\t\t\t\t12\n#define ID_DEMOS\t\t\t\t13\n#define ID_CINEMATICS\t\t\t14\n#define ID_TEAMARENA\t\t15\n#define ID_MODS\t\t\t\t\t16\n#define ID_EXIT\t\t\t\t\t17\n\n#define MAIN_BANNER_MODEL\t\t\t\t\"models/mapobjects/banner/banner5.md3\"\n#define MAIN_MENU_VERTICAL_SPACING\t\t34\n\n\ntypedef struct {\n\tmenuframework_s\tmenu;\n\n\tmenutext_s\t\tsingleplayer;\n\tmenutext_s\t\tmultiplayer;\n\tmenutext_s\t\tsetup;\n\tmenutext_s\t\tdemos;\n\tmenutext_s\t\tcinematics;\n\tmenutext_s\t\tteamArena;\n\tmenutext_s\t\tmods;\n\tmenutext_s\t\texit;\n\n\tqhandle_t\t\tbannerModel;\n} mainmenu_t;\n\n\nstatic mainmenu_t s_main;\n\ntypedef struct {\n\tmenuframework_s menu;\t\n\tchar errorMessage[4096];\n} errorMessage_t;\n\nstatic errorMessage_t s_errorMessage;\n\n/*\n=================\nMainMenu_ExitAction\n=================\n*/\nstatic void MainMenu_ExitAction( qboolean result ) {\n\tif( !result ) {\n\t\treturn;\n\t}\n\tUI_PopMenu();\n\tUI_CreditMenu();\n}\n\n\n\n/*\n=================\nMain_MenuEvent\n=================\n*/\nvoid Main_MenuEvent (void* ptr, int event) {\n\tif( event != QM_ACTIVATED ) {\n\t\treturn;\n\t}\n\n\tswitch( ((menucommon_s*)ptr)->id ) {\n\tcase ID_SINGLEPLAYER:\n\t\tUI_SPLevelMenu();\n\t\tbreak;\n\n\tcase ID_MULTIPLAYER:\n\t\tUI_ArenaServersMenu();\n\t\tbreak;\n\n\tcase ID_SETUP:\n\t\tUI_SetupMenu();\n\t\tbreak;\n\n\tcase ID_DEMOS:\n\t\tUI_DemosMenu();\n\t\tbreak;\n\n\tcase ID_CINEMATICS:\n\t\tUI_CinematicsMenu();\n\t\tbreak;\n\n\tcase ID_MODS:\n\t\tUI_ModsMenu();\n\t\tbreak;\n\n\tcase ID_TEAMARENA:\n\t\ttrap_Cvar_Set( \"fs_game\", \"missionpack\");\n\t\ttrap_Cmd_ExecuteText( EXEC_APPEND, \"vid_restart;\" );\n\t\tbreak;\n\n\tcase ID_EXIT:\n\t\tUI_ConfirmMenu( \"EXIT GAME?\", NULL, MainMenu_ExitAction );\n\t\tbreak;\n\t}\n}\n\n\n/*\n===============\nMainMenu_Cache\n===============\n*/\nvoid MainMenu_Cache( void ) {\n\ts_main.bannerModel = trap_R_RegisterModel( MAIN_BANNER_MODEL );\n}\n\nsfxHandle_t ErrorMessage_Key(int key)\n{\n\ttrap_Cvar_Set( \"com_errorMessage\", \"\" );\n\tUI_MainMenu();\n\treturn (menu_null_sound);\n}\n\n/*\n===============\nMain_MenuDraw\nTTimo: this function is common to the main menu and errorMessage menu\n===============\n*/\n\nstatic void Main_MenuDraw( void ) {\n\trefdef_t\t\trefdef;\n\trefEntity_t\t\tent;\n\tvec3_t\t\t\torigin;\n\tvec3_t\t\t\tangles;\n\tfloat\t\t\tadjust;\n\tfloat\t\t\tx, y, w, h;\n\tvec4_t\t\t\tcolor = {0.5, 0, 0, 1};\n\n\t// setup the refdef\n\n\tmemset( &refdef, 0, sizeof( refdef ) );\n\n\trefdef.rdflags = RDF_NOWORLDMODEL;\n\n\tAxisClear( refdef.viewaxis );\n\n\tx = 0;\n\ty = 0;\n\tw = 640;\n\th = 120;\n\tUI_AdjustFrom640( &x, &y, &w, &h );\n\trefdef.x = x;\n\trefdef.y = y;\n\trefdef.width = w;\n\trefdef.height = h;\n\n\tadjust = 0; // JDC: Kenneth asked me to stop this 1.0 * sin( (float)uis.realtime / 1000 );\n\trefdef.fov_x = 60 + adjust;\n\trefdef.fov_y = 19.6875 + adjust;\n\n\trefdef.time = uis.realtime;\n\n\torigin[0] = 300;\n\torigin[1] = 0;\n\torigin[2] = -32;\n\n\ttrap_R_ClearScene();\n\n\t// add the model\n\n\tmemset( &ent, 0, sizeof(ent) );\n\n\tadjust = 5.0 * sin( (float)uis.realtime / 5000 );\n\tVectorSet( angles, 0, 180 + adjust, 0 );\n\tAnglesToAxis( angles, ent.axis );\n\tent.hModel = s_main.bannerModel;\n\tVectorCopy( origin, ent.origin );\n\tVectorCopy( origin, ent.lightingOrigin );\n\tent.renderfx = RF_LIGHTING_ORIGIN | RF_NOSHADOW;\n\tVectorCopy( ent.origin, ent.oldorigin );\n\n\ttrap_R_AddRefEntityToScene( &ent );\n\n\ttrap_R_RenderScene( &refdef );\n\t\n\tif (strlen(s_errorMessage.errorMessage))\n\t{\n\t\tUI_DrawProportionalString_AutoWrapped( 320, 192, 600, 20, s_errorMessage.errorMessage, UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, menu_text_color );\n\t}\n\telse\n\t{\n\t\t// standard menu drawing\n\t\tMenu_Draw( &s_main.menu );\t\t\n\t}\n\n\tif (uis.demoversion) {\n\t\tUI_DrawProportionalString( 320, 372, \"DEMO      FOR MATURE AUDIENCES      DEMO\", UI_CENTER|UI_SMALLFONT, color );\n\t\tUI_DrawString( 320, 400, \"Quake III Arena(c) 1999-2000, Id Software, Inc.  All Rights Reserved\", UI_CENTER|UI_SMALLFONT, color );\n\t} else {\n\t\tUI_DrawString( 320, 450, \"Quake III Arena(c) 1999-2000, Id Software, Inc.  All Rights Reserved\", UI_CENTER|UI_SMALLFONT, color );\n\t}\n}\n\n\n/*\n===============\nUI_TeamArenaExists\n===============\n*/\nstatic qboolean UI_TeamArenaExists( void ) {\n\tint\t\tnumdirs;\n\tchar\tdirlist[2048];\n\tchar\t*dirptr;\n  char  *descptr;\n\tint\t\ti;\n\tint\t\tdirlen;\n\n\tnumdirs = trap_FS_GetFileList( \"$modlist\", \"\", dirlist, sizeof(dirlist) );\n\tdirptr  = dirlist;\n\tfor( i = 0; i < numdirs; i++ ) {\n\t\tdirlen = (int)strlen( dirptr ) + 1;\n    descptr = dirptr + dirlen;\n\t\tif (Q_stricmp(dirptr, \"missionpack\") == 0) {\n\t\t\treturn qtrue;\n\t\t}\n    dirptr += dirlen + (int)strlen(descptr) + 1;\n\t}\n\treturn qfalse;\n}\n\n\n/*\n===============\nUI_MainMenu\n\nThe main menu only comes up when not in a game,\nso make sure that the attract loop server is down\nand that local cinematics are killed\n===============\n*/\nvoid UI_MainMenu( void ) {\n\tint\t\ty;\n\tqboolean teamArena = qfalse;\n\tint\t\tstyle = UI_CENTER | UI_DROPSHADOW;\n\n\ttrap_Cvar_Set( \"sv_killserver\", \"1\" );\n\n\tif( !uis.demoversion && !ui_cdkeychecked.integer ) {\n\t\tchar\tkey[17];\n\n\t\ttrap_GetCDKey( key, sizeof(key) );\n\t\tif( trap_VerifyCDKey( key, NULL ) == qfalse ) {\n\t\t\tUI_CDKeyMenu();\n\t\t\treturn;\n\t\t}\n\t}\n\t\n\tmemset( &s_main, 0 ,sizeof(mainmenu_t) );\n\tmemset( &s_errorMessage, 0 ,sizeof(errorMessage_t) );\n\n\t// com_errorMessage would need that too\n\tMainMenu_Cache();\n\t\n\ttrap_Cvar_VariableStringBuffer( \"com_errorMessage\", s_errorMessage.errorMessage, sizeof(s_errorMessage.errorMessage) );\n\tif (strlen(s_errorMessage.errorMessage))\n\t{\t\n\t\ts_errorMessage.menu.draw = Main_MenuDraw;\n\t\ts_errorMessage.menu.key = ErrorMessage_Key;\n\t\ts_errorMessage.menu.fullscreen = qtrue;\n\t\ts_errorMessage.menu.wrapAround = qtrue;\n\t\ts_errorMessage.menu.showlogo = qtrue;\t\t\n\n\t\ttrap_Key_SetCatcher( KEYCATCH_UI );\n\t\tuis.menusp = 0;\n\t\tUI_PushMenu ( &s_errorMessage.menu );\n\t\t\n\t\treturn;\n\t}\n\n\ts_main.menu.draw = Main_MenuDraw;\n\ts_main.menu.fullscreen = qtrue;\n\ts_main.menu.wrapAround = qtrue;\n\ts_main.menu.showlogo = qtrue;\n\n\ty = 134;\n\ts_main.singleplayer.generic.type\t\t= MTYPE_PTEXT;\n\ts_main.singleplayer.generic.flags\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_main.singleplayer.generic.x\t\t\t= 320;\n\ts_main.singleplayer.generic.y\t\t\t= y;\n\ts_main.singleplayer.generic.id\t\t\t= ID_SINGLEPLAYER;\n\ts_main.singleplayer.generic.callback\t= Main_MenuEvent; \n\ts_main.singleplayer.string\t\t\t\t= \"SINGLE PLAYER\";\n\ts_main.singleplayer.color\t\t\t\t= color_red;\n\ts_main.singleplayer.style\t\t\t\t= style;\n\n\ty += MAIN_MENU_VERTICAL_SPACING;\n\ts_main.multiplayer.generic.type\t\t\t= MTYPE_PTEXT;\n\ts_main.multiplayer.generic.flags\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_main.multiplayer.generic.x\t\t\t= 320;\n\ts_main.multiplayer.generic.y\t\t\t= y;\n\ts_main.multiplayer.generic.id\t\t\t= ID_MULTIPLAYER;\n\ts_main.multiplayer.generic.callback\t\t= Main_MenuEvent; \n\ts_main.multiplayer.string\t\t\t\t= \"MULTIPLAYER\";\n\ts_main.multiplayer.color\t\t\t\t= color_red;\n\ts_main.multiplayer.style\t\t\t\t= style;\n\n\ty += MAIN_MENU_VERTICAL_SPACING;\n\ts_main.setup.generic.type\t\t\t\t= MTYPE_PTEXT;\n\ts_main.setup.generic.flags\t\t\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_main.setup.generic.x\t\t\t\t\t= 320;\n\ts_main.setup.generic.y\t\t\t\t\t= y;\n\ts_main.setup.generic.id\t\t\t\t\t= ID_SETUP;\n\ts_main.setup.generic.callback\t\t\t= Main_MenuEvent; \n\ts_main.setup.string\t\t\t\t\t\t= \"SETUP\";\n\ts_main.setup.color\t\t\t\t\t\t= color_red;\n\ts_main.setup.style\t\t\t\t\t\t= style;\n\n\ty += MAIN_MENU_VERTICAL_SPACING;\n\ts_main.demos.generic.type\t\t\t\t= MTYPE_PTEXT;\n\ts_main.demos.generic.flags\t\t\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_main.demos.generic.x\t\t\t\t\t= 320;\n\ts_main.demos.generic.y\t\t\t\t\t= y;\n\ts_main.demos.generic.id\t\t\t\t\t= ID_DEMOS;\n\ts_main.demos.generic.callback\t\t\t= Main_MenuEvent; \n\ts_main.demos.string\t\t\t\t\t\t= \"DEMOS\";\n\ts_main.demos.color\t\t\t\t\t\t= color_red;\n\ts_main.demos.style\t\t\t\t\t\t= style;\n\n\ty += MAIN_MENU_VERTICAL_SPACING;\n\ts_main.cinematics.generic.type\t\t\t= MTYPE_PTEXT;\n\ts_main.cinematics.generic.flags\t\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_main.cinematics.generic.x\t\t\t\t= 320;\n\ts_main.cinematics.generic.y\t\t\t\t= y;\n\ts_main.cinematics.generic.id\t\t\t= ID_CINEMATICS;\n\ts_main.cinematics.generic.callback\t\t= Main_MenuEvent; \n\ts_main.cinematics.string\t\t\t\t= \"CINEMATICS\";\n\ts_main.cinematics.color\t\t\t\t\t= color_red;\n\ts_main.cinematics.style\t\t\t\t\t= style;\n\n\tif (UI_TeamArenaExists()) {\n\t\tteamArena = qtrue;\n\t\ty += MAIN_MENU_VERTICAL_SPACING;\n\t\ts_main.teamArena.generic.type\t\t\t= MTYPE_PTEXT;\n\t\ts_main.teamArena.generic.flags\t\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\t\ts_main.teamArena.generic.x\t\t\t\t= 320;\n\t\ts_main.teamArena.generic.y\t\t\t\t= y;\n\t\ts_main.teamArena.generic.id\t\t\t\t= ID_TEAMARENA;\n\t\ts_main.teamArena.generic.callback\t\t= Main_MenuEvent; \n\t\ts_main.teamArena.string\t\t\t\t\t= \"TEAM ARENA\";\n\t\ts_main.teamArena.color\t\t\t\t\t= color_red;\n\t\ts_main.teamArena.style\t\t\t\t\t= style;\n\t}\n\n\ty += MAIN_MENU_VERTICAL_SPACING;\n\ts_main.mods.generic.type\t\t\t= MTYPE_PTEXT;\n\ts_main.mods.generic.flags\t\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_main.mods.generic.x\t\t\t\t= 320;\n\ts_main.mods.generic.y\t\t\t\t= y;\n\ts_main.mods.generic.id\t\t\t\t= ID_MODS;\n\ts_main.mods.generic.callback\t\t= Main_MenuEvent; \n\ts_main.mods.string\t\t\t\t\t= \"MODS\";\n\ts_main.mods.color\t\t\t\t\t= color_red;\n\ts_main.mods.style\t\t\t\t\t= style;\n\n\ty += MAIN_MENU_VERTICAL_SPACING;\n\ts_main.exit.generic.type\t\t\t\t= MTYPE_PTEXT;\n\ts_main.exit.generic.flags\t\t\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_main.exit.generic.x\t\t\t\t\t= 320;\n\ts_main.exit.generic.y\t\t\t\t\t= y;\n\ts_main.exit.generic.id\t\t\t\t\t= ID_EXIT;\n\ts_main.exit.generic.callback\t\t\t= Main_MenuEvent; \n\ts_main.exit.string\t\t\t\t\t\t= \"EXIT\";\n\ts_main.exit.color\t\t\t\t\t\t= color_red;\n\ts_main.exit.style\t\t\t\t\t\t= style;\n\n\tMenu_AddItem( &s_main.menu,\t&s_main.singleplayer );\n\tMenu_AddItem( &s_main.menu,\t&s_main.multiplayer );\n\tMenu_AddItem( &s_main.menu,\t&s_main.setup );\n\tMenu_AddItem( &s_main.menu,\t&s_main.demos );\n\tMenu_AddItem( &s_main.menu,\t&s_main.cinematics );\n\tif (teamArena) {\n\t\tMenu_AddItem( &s_main.menu,\t&s_main.teamArena );\n\t}\n\tMenu_AddItem( &s_main.menu,\t&s_main.mods );\n\tMenu_AddItem( &s_main.menu,\t&s_main.exit );             \n\n\ttrap_Key_SetCatcher( KEYCATCH_UI );\n\tuis.menusp = 0;\n\tUI_PushMenu ( &s_main.menu );\n\t\t\n}\n"
  },
  {
    "path": "src/q3_ui/ui_mfield.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n#include \"ui_local.h\"\n\n/*\n===================\nMField_Draw\n\nHandles horizontal scrolling and cursor blinking\nx, y, are in pixels\n===================\n*/\nvoid MField_Draw( mfield_t *edit, int x, int y, int style, vec4_t color ) {\n\tint\t\tlen;\n\tint\t\tcharw;\n\tint\t\tdrawLen;\n\tint\t\tprestep;\n\tint\t\tcursorChar;\n\tchar\tstr[MAX_STRING_CHARS];\n\n\tdrawLen = edit->widthInChars;\n\tlen     = (int)strlen( edit->buffer ) + 1;\n\n\t// guarantee that cursor will be visible\n\tif ( len <= drawLen ) {\n\t\tprestep = 0;\n\t} else {\n\t\tif ( edit->scroll + drawLen > len ) {\n\t\t\tedit->scroll = len - drawLen;\n\t\t\tif ( edit->scroll < 0 ) {\n\t\t\t\tedit->scroll = 0;\n\t\t\t}\n\t\t}\n\t\tprestep = edit->scroll;\n\t}\n\n\tif ( prestep + drawLen > len ) {\n\t\tdrawLen = len - prestep;\n\t}\n\n\t// extract <drawLen> characters from the field at <prestep>\n\tif ( drawLen >= MAX_STRING_CHARS ) {\n\t\ttrap_Error( \"drawLen >= MAX_STRING_CHARS\" );\n\t}\n\tmemcpy( str, edit->buffer + prestep, drawLen );\n\tstr[ drawLen ] = 0;\n\n\tUI_DrawString( x, y, str, style, color );\n\n\t// draw the cursor\n\tif (!(style & UI_PULSE)) {\n\t\treturn;\n\t}\n\n\tif ( trap_Key_GetOverstrikeMode() ) {\n\t\tcursorChar = 11;\n\t} else {\n\t\tcursorChar = 10;\n\t}\n\n\tstyle &= ~UI_PULSE;\n\tstyle |= UI_BLINK;\n\n\tif (style & UI_SMALLFONT)\n\t{\n\t\tcharw =\tSMALLCHAR_WIDTH;\n\t}\n\telse if (style & UI_GIANTFONT)\n\t{\n\t\tcharw =\tGIANTCHAR_WIDTH;\n\t}\n\telse\n\t{\n\t\tcharw =\tBIGCHAR_WIDTH;\n\t}\n\n\tif (style & UI_CENTER)\n\t{\n\t\tlen = (int)strlen(str);\n\t\tx = x - len*charw/2;\n\t}\n\telse if (style & UI_RIGHT)\n\t{\n\t\tlen = (int)strlen(str);\n\t\tx = x - len*charw;\n\t}\n\t\n\tUI_DrawChar( x + ( edit->cursor - prestep ) * charw, y, cursorChar, style & ~(UI_CENTER|UI_RIGHT), color );\n}\n\n/*\n================\nMField_Paste\n================\n*/\nvoid MField_Paste( mfield_t *edit ) {\n\tchar\tpasteBuffer[64];\n\tint\t\tpasteLen, i;\n\n\ttrap_GetClipboardData( pasteBuffer, 64 );\n\n\t// send as if typed, so insert / overstrike works properly\n\tpasteLen = (int)strlen( pasteBuffer );\n\tfor ( i = 0 ; i < pasteLen ; i++ ) {\n\t\tMField_CharEvent( edit, pasteBuffer[i] );\n\t}\n}\n\n/*\n=================\nMField_KeyDownEvent\n\nPerforms the basic line editing functions for the console,\nin-game talk, and menu fields\n\nKey events are used for non-printable characters, others are gotten from char events.\n=================\n*/\nvoid MField_KeyDownEvent( mfield_t *edit, int key ) {\n\tint\t\tlen;\n\n\t// shift-insert is paste\n\tif ( ( ( key == K_INS ) || ( key == K_KP_INS ) ) && trap_Key_IsDown( K_SHIFT ) ) {\n\t\tMField_Paste( edit );\n\t\treturn;\n\t}\n\n\tlen = (int)strlen( edit->buffer );\n\n\tif ( key == K_DEL || key == K_KP_DEL ) {\n\t\tif ( edit->cursor < len ) {\n\t\t\tmemmove( edit->buffer + edit->cursor, \n\t\t\t\tedit->buffer + edit->cursor + 1, len - edit->cursor );\n\t\t}\n\t\treturn;\n\t}\n\n\tif ( key == K_RIGHTARROW || key == K_KP_RIGHTARROW ) \n\t{\n\t\tif ( edit->cursor < len ) {\n\t\t\tedit->cursor++;\n\t\t}\n\t\tif ( edit->cursor >= edit->scroll + edit->widthInChars && edit->cursor <= len )\n\t\t{\n\t\t\tedit->scroll++;\n\t\t}\n\t\treturn;\n\t}\n\n\tif ( key == K_LEFTARROW || key == K_KP_LEFTARROW ) \n\t{\n\t\tif ( edit->cursor > 0 ) {\n\t\t\tedit->cursor--;\n\t\t}\n\t\tif ( edit->cursor < edit->scroll )\n\t\t{\n\t\t\tedit->scroll--;\n\t\t}\n\t\treturn;\n\t}\n\n\tif ( key == K_HOME || key == K_KP_HOME || ( tolower(key) == 'a' && trap_Key_IsDown( K_CTRL ) ) ) {\n\t\tedit->cursor = 0;\n\t\tedit->scroll = 0;\n\t\treturn;\n\t}\n\n\tif ( key == K_END || key == K_KP_END || ( tolower(key) == 'e' && trap_Key_IsDown( K_CTRL ) ) ) {\n\t\tedit->cursor = len;\n\t\tedit->scroll = len - edit->widthInChars + 1;\n\t\tif (edit->scroll < 0)\n\t\t\tedit->scroll = 0;\n\t\treturn;\n\t}\n\n\tif ( key == K_INS || key == K_KP_INS ) {\n\t\ttrap_Key_SetOverstrikeMode( !trap_Key_GetOverstrikeMode() );\n\t\treturn;\n\t}\n}\n\n/*\n==================\nMField_CharEvent\n==================\n*/\nvoid MField_CharEvent( mfield_t *edit, int ch ) {\n\tint\t\tlen;\n\n\tif ( ch == 'v' - 'a' + 1 ) {\t// ctrl-v is paste\n\t\tMField_Paste( edit );\n\t\treturn;\n\t}\n\n\tif ( ch == 'c' - 'a' + 1 ) {\t// ctrl-c clears the field\n\t\tMField_Clear( edit );\n\t\treturn;\n\t}\n\n\tlen = (int)strlen( edit->buffer );\n\n\tif ( ch == 'h' - 'a' + 1 )\t{\t// ctrl-h is backspace\n\t\tif ( edit->cursor > 0 ) {\n\t\t\tmemmove( edit->buffer + edit->cursor - 1, \n\t\t\t\tedit->buffer + edit->cursor, len + 1 - edit->cursor );\n\t\t\tedit->cursor--;\n\t\t\tif ( edit->cursor < edit->scroll )\n\t\t\t{\n\t\t\t\tedit->scroll--;\n\t\t\t}\n\t\t}\n\t\treturn;\n\t}\n\n\tif ( ch == 'a' - 'a' + 1 ) {\t// ctrl-a is home\n\t\tedit->cursor = 0;\n\t\tedit->scroll = 0;\n\t\treturn;\n\t}\n\n\tif ( ch == 'e' - 'a' + 1 ) {\t// ctrl-e is end\n\t\tedit->cursor = len;\n\t\tedit->scroll = edit->cursor - edit->widthInChars + 1;\n\t\tif (edit->scroll < 0)\n\t\t\tedit->scroll = 0;\n\t\treturn;\n\t}\n\n\t//\n\t// ignore any other non printable chars\n\t//\n\tif ( ch < 32 ) {\n\t\treturn;\n\t}\n\n\tif ( !trap_Key_GetOverstrikeMode() ) {\t\n\t\tif ((edit->cursor == MAX_EDIT_LINE - 1) || (edit->maxchars && edit->cursor >= edit->maxchars))\n\t\t\treturn;\n\t} else {\n\t\t// insert mode\n\t\tif (( len == MAX_EDIT_LINE - 1 ) || (edit->maxchars && len >= edit->maxchars))\n\t\t\treturn;\n\t\tmemmove( edit->buffer + edit->cursor + 1, edit->buffer + edit->cursor, len + 1 - edit->cursor );\n\t}\n\n\tedit->buffer[edit->cursor] = ch;\n\tif (!edit->maxchars || edit->cursor < edit->maxchars-1)\n\t\tedit->cursor++;\n\n\tif ( edit->cursor >= edit->widthInChars )\n\t{\n\t\tedit->scroll++;\n\t}\n\n\tif ( edit->cursor == len + 1) {\n\t\tedit->buffer[edit->cursor] = 0;\n\t}\n}\n\n/*\n==================\nMField_Clear\n==================\n*/\nvoid MField_Clear( mfield_t *edit ) {\n\tedit->buffer[0] = 0;\n\tedit->cursor = 0;\n\tedit->scroll = 0;\n}\n\n/*\n==================\nMenuField_Init\n==================\n*/\nvoid MenuField_Init( menufield_s* m ) {\n\tint\tl;\n\tint\tw;\n\tint\th;\n\n\tMField_Clear( &m->field );\n\n\tif (m->generic.flags & QMF_SMALLFONT)\n\t{\n\t\tw = SMALLCHAR_WIDTH;\n\t\th = SMALLCHAR_HEIGHT;\n\t}\n\telse\n\t{\n\t\tw = BIGCHAR_WIDTH;\n\t\th = BIGCHAR_HEIGHT;\n\t}\t\n\n\tif (m->generic.name) {\n\t\tl = ((int)strlen( m->generic.name )+1) * w;\t\t\n\t}\n\telse {\n\t\tl = 0;\n\t}\n\n\tm->generic.left   = m->generic.x - l;\n\tm->generic.top    = m->generic.y;\n\tm->generic.right  = m->generic.x + w + m->field.widthInChars*w;\n\tm->generic.bottom = m->generic.y + h;\n}\n\n/*\n==================\nMenuField_Draw\n==================\n*/\nvoid MenuField_Draw( menufield_s *f )\n{\n\tint\t\tx;\n\tint\t\ty;\n\tint\t\tw;\n\tint\t\th;\n\tint\t\tstyle;\n\tqboolean focus;\n\tfloat\t*color;\n\n\tx =\tf->generic.x;\n\ty =\tf->generic.y;\n\n\tif (f->generic.flags & QMF_SMALLFONT)\n\t{\n\t\tw = SMALLCHAR_WIDTH;\n\t\th = SMALLCHAR_HEIGHT;\n\t\tstyle = UI_SMALLFONT;\n\t}\n\telse\n\t{\n\t\tw = BIGCHAR_WIDTH;\n\t\th = BIGCHAR_HEIGHT;\n\t\tstyle = UI_BIGFONT;\n\t}\t\n\n\tif (Menu_ItemAtCursor( f->generic.parent ) == f) {\n\t\tfocus = qtrue;\n\t\tstyle |= UI_PULSE;\n\t}\n\telse {\n\t\tfocus = qfalse;\n\t}\n\n\tif (f->generic.flags & QMF_GRAYED)\n\t\tcolor = text_color_disabled;\n\telse if (focus)\n\t\tcolor = text_color_highlight;\n\telse\n\t\tcolor = text_color_normal;\n\n\tif ( focus )\n\t{\n\t\t// draw cursor\n\t\tUI_FillRect( f->generic.left, f->generic.top, f->generic.right-f->generic.left+1, f->generic.bottom-f->generic.top+1, listbar_color ); \n\t\tUI_DrawChar( x, y, 13, UI_CENTER|UI_BLINK|style, color);\n\t}\n\n\tif ( f->generic.name ) {\n\t\tUI_DrawString( x - w, y, f->generic.name, style|UI_RIGHT, color );\n\t}\n\n\tMField_Draw( &f->field, x + w, y, style, color );\n}\n\n/*\n==================\nMenuField_Key\n==================\n*/\nsfxHandle_t MenuField_Key( menufield_s* m, int* key )\n{\n\tint keycode;\n\n\tkeycode = *key;\n\n\tswitch ( keycode )\n\t{\n\t\tcase K_KP_ENTER:\n\t\tcase K_ENTER:\n\t\tcase K_JOY1:\n\t\tcase K_JOY2:\n\t\tcase K_JOY3:\n\t\tcase K_JOY4:\n\t\t\t// have enter go to next cursor point\n\t\t\t*key = K_TAB;\n\t\t\tbreak;\n\n\t\tcase K_TAB:\n\t\tcase K_KP_DOWNARROW:\n\t\tcase K_DOWNARROW:\n\t\tcase K_KP_UPARROW:\n\t\tcase K_UPARROW:\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tif ( keycode & K_CHAR_FLAG )\n\t\t\t{\n\t\t\t\tkeycode &= ~K_CHAR_FLAG;\n\n\t\t\t\tif ((m->generic.flags & QMF_UPPERCASE) && Q_islower( keycode ))\n\t\t\t\t\tkeycode -= 'a' - 'A';\n\t\t\t\telse if ((m->generic.flags & QMF_LOWERCASE) && Q_isupper( keycode ))\n\t\t\t\t\tkeycode -= 'A' - 'a';\n\t\t\t\telse if ((m->generic.flags & QMF_NUMBERSONLY) && Q_isalpha( keycode ))\n\t\t\t\t\treturn (menu_buzz_sound);\n\n\t\t\t\tMField_CharEvent( &m->field, keycode);\n\t\t\t}\n\t\t\telse\n\t\t\t\tMField_KeyDownEvent( &m->field, keycode );\n\t\t\tbreak;\n\t}\n\n\treturn (0);\n}\n\n\n"
  },
  {
    "path": "src/q3_ui/ui_mods.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n#include \"ui_local.h\"\n\n#define ART_BACK0\t\t\t\"menu/art/back_0\"\n#define ART_BACK1\t\t\t\"menu/art/back_1\"\t\n#define ART_FIGHT0\t\t\t\"menu/art/load_0\"\n#define ART_FIGHT1\t\t\t\"menu/art/load_1\"\n#define ART_FRAMEL\t\t\t\"menu/art/frame2_l\"\n#define ART_FRAMER\t\t\t\"menu/art/frame1_r\"\n\n#define MAX_MODS\t\t\t64\n#define NAMEBUFSIZE\t\t\t( MAX_MODS * 48 )\n#define GAMEBUFSIZE\t\t\t( MAX_MODS * 16 )\n\n#define ID_BACK\t\t\t\t10\n#define ID_GO\t\t\t\t11\n#define ID_LIST\t\t\t\t12\n\n\ntypedef struct {\n\tmenuframework_s\tmenu;\n\n\tmenutext_s\t\tbanner;\n\tmenubitmap_s\tframel;\n\tmenubitmap_s\tframer;\n\n\tmenulist_s\t\tlist;\n\n\tmenubitmap_s\tback;\n\tmenubitmap_s\tgo;\n\n\tchar\t\t\tdescription[NAMEBUFSIZE];\n\tchar\t\t\tfs_game[GAMEBUFSIZE];\n\n\tchar\t\t\t*descriptionPtr;\n\tchar\t\t\t*fs_gamePtr;\n\n\tchar\t\t\t*descriptionList[MAX_MODS];\n\tchar\t\t\t*fs_gameList[MAX_MODS];\n} mods_t;\n\nstatic mods_t\ts_mods;\n\n\n/*\n===============\nUI_Mods_MenuEvent\n===============\n*/\nstatic void UI_Mods_MenuEvent( void *ptr, int event ) {\n\tif( event != QM_ACTIVATED ) {\n\t\treturn;\n\t}\n\n\tswitch ( ((menucommon_s*)ptr)->id ) {\n\tcase ID_GO:\n\t\ttrap_Cvar_Set( \"fs_game\", s_mods.fs_gameList[s_mods.list.curvalue] );\n\t\ttrap_Cmd_ExecuteText( EXEC_APPEND, \"vid_restart;\" );\n\t\tUI_PopMenu();\n\t\tbreak;\n\n\tcase ID_BACK:\n\t\tUI_PopMenu();\n\t\tbreak;\n\t}\n}\n\n\n/*\n===============\nUI_Mods_ParseInfos\n===============\n*/\nstatic void UI_Mods_ParseInfos( char *modDir, char *modDesc ) {\n\ts_mods.fs_gameList[s_mods.list.numitems] = s_mods.fs_gamePtr;\n\tQ_strncpyz( s_mods.fs_gamePtr, modDir, 16 );\n\n\ts_mods.descriptionList[s_mods.list.numitems] = s_mods.descriptionPtr;\n\tQ_strncpyz( s_mods.descriptionPtr, modDesc, 48 );\n\n\ts_mods.list.itemnames[s_mods.list.numitems] = s_mods.descriptionPtr;\n\ts_mods.descriptionPtr += (int)strlen( s_mods.descriptionPtr ) + 1;\n\ts_mods.fs_gamePtr += (int)strlen( s_mods.fs_gamePtr ) + 1;\n\ts_mods.list.numitems++;\n}\n\n\n#if 0 // bk001204 - unused\n/*\n===============\nUI_Mods_LoadModsFromFile\n===============\n*/\nstatic void UI_Mods_LoadModsFromFile( char *filename ) {\n\tint\t\t\t\tlen;\n\tfileHandle_t\tf;\n\tchar\t\t\tbuf[1024];\n\n\tlen = trap_FS_FOpenFile( filename, &f, FS_READ );\n\tif ( !f ) {\n\t\ttrap_Print( va( S_COLOR_RED \"file not found: %s\\n\", filename ) );\n\t\treturn;\n\t}\n\tif ( len >= sizeof(buf) ) {\n\t\ttrap_Print( va( S_COLOR_RED \"file too large: %s is %i, max allowed is %i\", filename, len, sizeof(buf) ) );\n\t\ttrap_FS_FCloseFile( f );\n\t\treturn;\n\t}\n\n\ttrap_FS_Read( buf, len, f );\n\tbuf[len] = 0;\n\ttrap_FS_FCloseFile( f );\n\n\tlen = (int)strlen( filename );\n\tif( !Q_stricmp(filename +  len - 4,\".mod\") ) {\n\t\tfilename[len-4] = '\\0';\n\t}\n\n\tUI_Mods_ParseInfos( filename, buf );\n}\n#endif\n\n\n/*\n===============\nUI_Mods_LoadMods\n===============\n*/\nstatic void UI_Mods_LoadMods( void ) {\n\tint\t\tnumdirs;\n\tchar\tdirlist[2048];\n\tchar\t*dirptr;\n  char  *descptr;\n\tint\t\ti;\n\tint\t\tdirlen;\n\n\ts_mods.list.itemnames = (const char **)s_mods.descriptionList;\n\ts_mods.descriptionPtr = s_mods.description;\n\ts_mods.fs_gamePtr = s_mods.fs_game;\n\n\t// always start off with baseq3\n\ts_mods.list.numitems = 1;\n\ts_mods.list.itemnames[0] = s_mods.descriptionList[0] = \"Quake III Arena\";\n\ts_mods.fs_gameList[0] = \"\";\n\n\tnumdirs = trap_FS_GetFileList( \"$modlist\", \"\", dirlist, sizeof(dirlist) );\n\tdirptr  = dirlist;\n\tfor( i = 0; i < numdirs; i++ ) {\n\t\tdirlen = (int)strlen( dirptr ) + 1;\n    descptr = dirptr + dirlen;\n  \tUI_Mods_ParseInfos( dirptr, descptr);\n    dirptr += dirlen + (int)strlen(descptr) + 1;\n\t}\n\n\ttrap_Print( va( \"%i mods parsed\\n\", s_mods.list.numitems ) );\n\tif (s_mods.list.numitems > MAX_MODS) {\n\t\ts_mods.list.numitems = MAX_MODS;\n\t}\n}\n\n\n/*\n===============\nUI_Mods_MenuInit\n===============\n*/\nstatic void UI_Mods_MenuInit( void ) {\n\tUI_ModsMenu_Cache();\n\n\tmemset( &s_mods, 0 ,sizeof(mods_t) );\n\ts_mods.menu.wrapAround = qtrue;\n\ts_mods.menu.fullscreen = qtrue;\n\n\ts_mods.banner.generic.type\t\t= MTYPE_BTEXT;\n\ts_mods.banner.generic.x\t\t\t= 320;\n\ts_mods.banner.generic.y\t\t\t= 16;\n\ts_mods.banner.string\t\t\t= \"MODS\";\n\ts_mods.banner.color\t\t\t\t= color_white;\n\ts_mods.banner.style\t\t\t\t= UI_CENTER;\n\n\ts_mods.framel.generic.type\t\t= MTYPE_BITMAP;\n\ts_mods.framel.generic.name\t\t= ART_FRAMEL;\n\ts_mods.framel.generic.flags\t\t= QMF_INACTIVE;\n\ts_mods.framel.generic.x\t\t\t= 0;  \n\ts_mods.framel.generic.y\t\t\t= 78;\n\ts_mods.framel.width\t\t\t\t= 256;\n\ts_mods.framel.height\t\t\t= 329;\n\n\ts_mods.framer.generic.type\t\t= MTYPE_BITMAP;\n\ts_mods.framer.generic.name\t\t= ART_FRAMER;\n\ts_mods.framer.generic.flags\t\t= QMF_INACTIVE;\n\ts_mods.framer.generic.x\t\t\t= 376;\n\ts_mods.framer.generic.y\t\t\t= 76;\n\ts_mods.framer.width\t\t\t\t= 256;\n\ts_mods.framer.height\t\t\t= 334;\n\n\ts_mods.back.generic.type\t\t= MTYPE_BITMAP;\n\ts_mods.back.generic.name\t\t= ART_BACK0;\n\ts_mods.back.generic.flags\t\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_mods.back.generic.id\t\t\t= ID_BACK;\n\ts_mods.back.generic.callback\t= UI_Mods_MenuEvent;\n\ts_mods.back.generic.x\t\t\t= 0;\n\ts_mods.back.generic.y\t\t\t= 480-64;\n\ts_mods.back.width\t\t\t\t= 128;\n\ts_mods.back.height\t\t\t\t= 64;\n\ts_mods.back.focuspic\t\t\t= ART_BACK1;\n\n\ts_mods.go.generic.type\t\t\t= MTYPE_BITMAP;\n\ts_mods.go.generic.name\t\t\t= ART_FIGHT0;\n\ts_mods.go.generic.flags\t\t\t= QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_mods.go.generic.id\t\t\t= ID_GO;\n\ts_mods.go.generic.callback\t\t= UI_Mods_MenuEvent;\n\ts_mods.go.generic.x\t\t\t\t= 640;\n\ts_mods.go.generic.y\t\t\t\t= 480-64;\n\ts_mods.go.width\t\t\t\t\t= 128;\n\ts_mods.go.height\t\t\t\t= 64;\n\ts_mods.go.focuspic\t\t\t\t= ART_FIGHT1;\n\n\t// scan for mods\n\ts_mods.list.generic.type\t\t= MTYPE_SCROLLLIST;\n\ts_mods.list.generic.flags\t\t= QMF_PULSEIFFOCUS|QMF_CENTER_JUSTIFY;\n\ts_mods.list.generic.callback\t= UI_Mods_MenuEvent;\n\ts_mods.list.generic.id\t\t\t= ID_LIST;\n\ts_mods.list.generic.x\t\t\t= 320;\n\ts_mods.list.generic.y\t\t\t= 130;\n\ts_mods.list.width\t\t\t\t= 48;\n\ts_mods.list.height\t\t\t\t= 14;\n\n\tUI_Mods_LoadMods();\n\n\tMenu_AddItem( &s_mods.menu, &s_mods.banner );\n\tMenu_AddItem( &s_mods.menu, &s_mods.framel );\n\tMenu_AddItem( &s_mods.menu, &s_mods.framer );\n\tMenu_AddItem( &s_mods.menu, &s_mods.list );\n\tMenu_AddItem( &s_mods.menu, &s_mods.back );\n\tMenu_AddItem( &s_mods.menu, &s_mods.go );\n}\n\n/*\n=================\nUI_Mods_Cache\n=================\n*/\nvoid UI_ModsMenu_Cache( void ) {\n\ttrap_R_RegisterShaderNoMip( ART_BACK0 );\n\ttrap_R_RegisterShaderNoMip( ART_BACK1 );\n\ttrap_R_RegisterShaderNoMip( ART_FIGHT0 );\n\ttrap_R_RegisterShaderNoMip( ART_FIGHT1 );\n\ttrap_R_RegisterShaderNoMip( ART_FRAMEL );\n\ttrap_R_RegisterShaderNoMip( ART_FRAMER );\n}\n\n\n/*\n===============\nUI_ModsMenu\n===============\n*/\nvoid UI_ModsMenu( void ) {\n\tUI_Mods_MenuInit();\n\tUI_PushMenu( &s_mods.menu );\n}\n"
  },
  {
    "path": "src/q3_ui/ui_network.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n/*\n=======================================================================\n\nNETWORK OPTIONS MENU\n\n=======================================================================\n*/\n\n#include \"ui_local.h\"\n\n\n#define ART_FRAMEL\t\t\t\"menu/art/frame2_l\"\n#define ART_FRAMER\t\t\t\"menu/art/frame1_r\"\n#define ART_BACK0\t\t\t\"menu/art/back_0\"\n#define ART_BACK1\t\t\t\"menu/art/back_1\"\n\n#define ID_GRAPHICS\t\t\t10\n#define ID_DISPLAY\t\t\t11\n#define ID_SOUND\t\t\t12\n#define ID_NETWORK\t\t\t13\n#define ID_RATE\t\t\t\t14\n#define ID_BACK\t\t\t\t15\n\n\nstatic const char *rate_items[] = {\n\t\"<= 28.8K\",\n\t\"33.6K\",\n\t\"56K\",\n\t\"ISDN\",\n\t\"LAN/Cable/xDSL\",\n\t0\n};\n\ntypedef struct {\n\tmenuframework_s\tmenu;\n\n\tmenutext_s\t\tbanner;\n\tmenubitmap_s\tframel;\n\tmenubitmap_s\tframer;\n\n\tmenutext_s\t\tgraphics;\n\tmenutext_s\t\tdisplay;\n\tmenutext_s\t\tsound;\n\tmenutext_s\t\tnetwork;\n\n\tmenulist_s\t\trate;\n\n\tmenubitmap_s\tback;\n} networkOptionsInfo_t;\n\nstatic networkOptionsInfo_t\tnetworkOptionsInfo;\n\n\n/*\n=================\nUI_NetworkOptionsMenu_Event\n=================\n*/\nstatic void UI_NetworkOptionsMenu_Event( void* ptr, int event ) {\n\tif( event != QM_ACTIVATED ) {\n\t\treturn;\n\t}\n\n\tswitch( ((menucommon_s*)ptr)->id ) {\n\tcase ID_GRAPHICS:\n\t\tUI_PopMenu();\n\t\tUI_GraphicsOptionsMenu();\n\t\tbreak;\n\n\tcase ID_DISPLAY:\n\t\tUI_PopMenu();\n\t\tUI_DisplayOptionsMenu();\n\t\tbreak;\n\n\tcase ID_SOUND:\n\t\tUI_PopMenu();\n\t\tUI_SoundOptionsMenu();\n\t\tbreak;\n\n\tcase ID_NETWORK:\n\t\tbreak;\n\n\tcase ID_RATE:\n\t\tif( networkOptionsInfo.rate.curvalue == 0 ) {\n\t\t\ttrap_Cvar_SetValue( \"rate\", 2500 );\n\t\t}\n\t\telse if( networkOptionsInfo.rate.curvalue == 1 ) {\n\t\t\ttrap_Cvar_SetValue( \"rate\", 3000 );\n\t\t}\n\t\telse if( networkOptionsInfo.rate.curvalue == 2 ) {\n\t\t\ttrap_Cvar_SetValue( \"rate\", 4000 );\n\t\t}\n\t\telse if( networkOptionsInfo.rate.curvalue == 3 ) {\n\t\t\ttrap_Cvar_SetValue( \"rate\", 5000 );\n\t\t}\n\t\telse if( networkOptionsInfo.rate.curvalue == 4 ) {\n\t\t\ttrap_Cvar_SetValue( \"rate\", 25000 );\n\t\t}\n\t\tbreak;\n\n\tcase ID_BACK:\n\t\tUI_PopMenu();\n\t\tbreak;\n\t}\n}\n\n\n/*\n===============\nUI_NetworkOptionsMenu_Init\n===============\n*/\nstatic void UI_NetworkOptionsMenu_Init( void ) {\n\tint\t\ty;\n\tint\t\trate;\n\n\tmemset( &networkOptionsInfo, 0, sizeof(networkOptionsInfo) );\n\n\tUI_NetworkOptionsMenu_Cache();\n\tnetworkOptionsInfo.menu.wrapAround = qtrue;\n\tnetworkOptionsInfo.menu.fullscreen = qtrue;\n\n\tnetworkOptionsInfo.banner.generic.type\t\t= MTYPE_BTEXT;\n\tnetworkOptionsInfo.banner.generic.flags\t\t= QMF_CENTER_JUSTIFY;\n\tnetworkOptionsInfo.banner.generic.x\t\t\t= 320;\n\tnetworkOptionsInfo.banner.generic.y\t\t\t= 16;\n\tnetworkOptionsInfo.banner.string\t\t\t= \"SYSTEM SETUP\";\n\tnetworkOptionsInfo.banner.color\t\t\t\t= color_white;\n\tnetworkOptionsInfo.banner.style\t\t\t\t= UI_CENTER;\n\n\tnetworkOptionsInfo.framel.generic.type\t\t= MTYPE_BITMAP;\n\tnetworkOptionsInfo.framel.generic.name\t\t= ART_FRAMEL;\n\tnetworkOptionsInfo.framel.generic.flags\t\t= QMF_INACTIVE;\n\tnetworkOptionsInfo.framel.generic.x\t\t\t= 0;  \n\tnetworkOptionsInfo.framel.generic.y\t\t\t= 78;\n\tnetworkOptionsInfo.framel.width\t\t\t\t= 256;\n\tnetworkOptionsInfo.framel.height\t\t\t= 329;\n\n\tnetworkOptionsInfo.framer.generic.type\t\t= MTYPE_BITMAP;\n\tnetworkOptionsInfo.framer.generic.name\t\t= ART_FRAMER;\n\tnetworkOptionsInfo.framer.generic.flags\t\t= QMF_INACTIVE;\n\tnetworkOptionsInfo.framer.generic.x\t\t\t= 376;\n\tnetworkOptionsInfo.framer.generic.y\t\t\t= 76;\n\tnetworkOptionsInfo.framer.width\t\t\t\t= 256;\n\tnetworkOptionsInfo.framer.height\t\t\t= 334;\n\n\tnetworkOptionsInfo.graphics.generic.type\t\t= MTYPE_PTEXT;\n\tnetworkOptionsInfo.graphics.generic.flags\t\t= QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;\n\tnetworkOptionsInfo.graphics.generic.id\t\t\t= ID_GRAPHICS;\n\tnetworkOptionsInfo.graphics.generic.callback\t= UI_NetworkOptionsMenu_Event;\n\tnetworkOptionsInfo.graphics.generic.x\t\t\t= 216;\n\tnetworkOptionsInfo.graphics.generic.y\t\t\t= 240 - 2 * PROP_HEIGHT;\n\tnetworkOptionsInfo.graphics.string\t\t\t\t= \"GRAPHICS\";\n\tnetworkOptionsInfo.graphics.style\t\t\t\t= UI_RIGHT;\n\tnetworkOptionsInfo.graphics.color\t\t\t\t= color_red;\n\n\tnetworkOptionsInfo.display.generic.type\t\t\t= MTYPE_PTEXT;\n\tnetworkOptionsInfo.display.generic.flags\t\t= QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;\n\tnetworkOptionsInfo.display.generic.id\t\t\t= ID_DISPLAY;\n\tnetworkOptionsInfo.display.generic.callback\t\t= UI_NetworkOptionsMenu_Event;\n\tnetworkOptionsInfo.display.generic.x\t\t\t= 216;\n\tnetworkOptionsInfo.display.generic.y\t\t\t= 240 - PROP_HEIGHT;\n\tnetworkOptionsInfo.display.string\t\t\t\t= \"DISPLAY\";\n\tnetworkOptionsInfo.display.style\t\t\t\t= UI_RIGHT;\n\tnetworkOptionsInfo.display.color\t\t\t\t= color_red;\n\n\tnetworkOptionsInfo.sound.generic.type\t\t\t= MTYPE_PTEXT;\n\tnetworkOptionsInfo.sound.generic.flags\t\t\t= QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;\n\tnetworkOptionsInfo.sound.generic.id\t\t\t\t= ID_SOUND;\n\tnetworkOptionsInfo.sound.generic.callback\t\t= UI_NetworkOptionsMenu_Event;\n\tnetworkOptionsInfo.sound.generic.x\t\t\t\t= 216;\n\tnetworkOptionsInfo.sound.generic.y\t\t\t\t= 240;\n\tnetworkOptionsInfo.sound.string\t\t\t\t\t= \"SOUND\";\n\tnetworkOptionsInfo.sound.style\t\t\t\t\t= UI_RIGHT;\n\tnetworkOptionsInfo.sound.color\t\t\t\t\t= color_red;\n\n\tnetworkOptionsInfo.network.generic.type\t\t\t= MTYPE_PTEXT;\n\tnetworkOptionsInfo.network.generic.flags\t\t= QMF_RIGHT_JUSTIFY;\n\tnetworkOptionsInfo.network.generic.id\t\t\t= ID_NETWORK;\n\tnetworkOptionsInfo.network.generic.callback\t\t= UI_NetworkOptionsMenu_Event;\n\tnetworkOptionsInfo.network.generic.x\t\t\t= 216;\n\tnetworkOptionsInfo.network.generic.y\t\t\t= 240 + PROP_HEIGHT;\n\tnetworkOptionsInfo.network.string\t\t\t\t= \"NETWORK\";\n\tnetworkOptionsInfo.network.style\t\t\t\t= UI_RIGHT;\n\tnetworkOptionsInfo.network.color\t\t\t\t= color_red;\n\n\ty = 240 - 1 * (BIGCHAR_HEIGHT+2);\n\tnetworkOptionsInfo.rate.generic.type\t\t= MTYPE_SPINCONTROL;\n\tnetworkOptionsInfo.rate.generic.name\t\t= \"Data Rate:\";\n\tnetworkOptionsInfo.rate.generic.flags\t\t= QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\tnetworkOptionsInfo.rate.generic.callback\t= UI_NetworkOptionsMenu_Event;\n\tnetworkOptionsInfo.rate.generic.id\t\t\t= ID_RATE;\n\tnetworkOptionsInfo.rate.generic.x\t\t\t= 400;\n\tnetworkOptionsInfo.rate.generic.y\t\t\t= y;\n\tnetworkOptionsInfo.rate.itemnames\t\t\t= rate_items;\n\n\tnetworkOptionsInfo.back.generic.type\t\t= MTYPE_BITMAP;\n\tnetworkOptionsInfo.back.generic.name\t\t= ART_BACK0;\n\tnetworkOptionsInfo.back.generic.flags\t\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\tnetworkOptionsInfo.back.generic.callback\t= UI_NetworkOptionsMenu_Event;\n\tnetworkOptionsInfo.back.generic.id\t\t\t= ID_BACK;\n\tnetworkOptionsInfo.back.generic.x\t\t\t= 0;\n\tnetworkOptionsInfo.back.generic.y\t\t\t= 480-64;\n\tnetworkOptionsInfo.back.width\t\t\t\t= 128;\n\tnetworkOptionsInfo.back.height\t\t\t\t= 64;\n\tnetworkOptionsInfo.back.focuspic\t\t\t= ART_BACK1;\n\n\tMenu_AddItem( &networkOptionsInfo.menu, ( void * ) &networkOptionsInfo.banner );\n\tMenu_AddItem( &networkOptionsInfo.menu, ( void * ) &networkOptionsInfo.framel );\n\tMenu_AddItem( &networkOptionsInfo.menu, ( void * ) &networkOptionsInfo.framer );\n\tMenu_AddItem( &networkOptionsInfo.menu, ( void * ) &networkOptionsInfo.graphics );\n\tMenu_AddItem( &networkOptionsInfo.menu, ( void * ) &networkOptionsInfo.display );\n\tMenu_AddItem( &networkOptionsInfo.menu, ( void * ) &networkOptionsInfo.sound );\n\tMenu_AddItem( &networkOptionsInfo.menu, ( void * ) &networkOptionsInfo.network );\n\tMenu_AddItem( &networkOptionsInfo.menu, ( void * ) &networkOptionsInfo.rate );\n\tMenu_AddItem( &networkOptionsInfo.menu, ( void * ) &networkOptionsInfo.back );\n\n\trate = trap_Cvar_VariableValue( \"rate\" );\n\tif( rate <= 2500 ) {\n\t\tnetworkOptionsInfo.rate.curvalue = 0;\n\t}\n\telse if( rate <= 3000 ) {\n\t\tnetworkOptionsInfo.rate.curvalue = 1;\n\t}\n\telse if( rate <= 4000 ) {\n\t\tnetworkOptionsInfo.rate.curvalue = 2;\n\t}\n\telse if( rate <= 5000 ) {\n\t\tnetworkOptionsInfo.rate.curvalue = 3;\n\t}\n\telse {\n\t\tnetworkOptionsInfo.rate.curvalue = 4;\n\t}\n}\n\n\n/*\n===============\nUI_NetworkOptionsMenu_Cache\n===============\n*/\nvoid UI_NetworkOptionsMenu_Cache( void ) {\n\ttrap_R_RegisterShaderNoMip( ART_FRAMEL );\n\ttrap_R_RegisterShaderNoMip( ART_FRAMER );\n\ttrap_R_RegisterShaderNoMip( ART_BACK0 );\n\ttrap_R_RegisterShaderNoMip( ART_BACK1 );\n}\n\n\n/*\n===============\nUI_NetworkOptionsMenu\n===============\n*/\nvoid UI_NetworkOptionsMenu( void ) {\n\tUI_NetworkOptionsMenu_Init();\n\tUI_PushMenu( &networkOptionsInfo.menu );\n\tMenu_SetCursorToItem( &networkOptionsInfo.menu, &networkOptionsInfo.network );\n}\n"
  },
  {
    "path": "src/q3_ui/ui_options.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n/*\n=======================================================================\n\nSYSTEM CONFIGURATION MENU\n\n=======================================================================\n*/\n\n#include \"ui_local.h\"\n\n\n#define ART_FRAMEL\t\t\t\"menu/art/frame2_l\"\n#define ART_FRAMER\t\t\t\"menu/art/frame1_r\"\n#define ART_BACK0\t\t\t\"menu/art/back_0\"\n#define ART_BACK1\t\t\t\"menu/art/back_1\"\n\n#define ID_GRAPHICS\t\t\t10\n#define ID_DISPLAY\t\t\t11\n#define ID_SOUND\t\t\t12\n#define ID_NETWORK\t\t\t13\n#define ID_BACK\t\t\t\t14\n\n#define VERTICAL_SPACING\t34\n\ntypedef struct {\n\tmenuframework_s\tmenu;\n\n\tmenutext_s\t\tbanner;\n\tmenubitmap_s\tframel;\n\tmenubitmap_s\tframer;\n\n\tmenutext_s\t\tgraphics;\n\tmenutext_s\t\tdisplay;\n\tmenutext_s\t\tsound;\n\tmenutext_s\t\tnetwork;\n\tmenubitmap_s\tback;\n} optionsmenu_t;\n\nstatic optionsmenu_t\ts_options;\n\n\n/*\n=================\nOptions_Event\n=================\n*/\nstatic void Options_Event( void* ptr, int event ) {\n\tif( event != QM_ACTIVATED ) {\n\t\treturn;\n\t}\n\n\tswitch( ((menucommon_s*)ptr)->id ) {\n\tcase ID_GRAPHICS:\n\t\tUI_GraphicsOptionsMenu();\n\t\tbreak;\n\n\tcase ID_DISPLAY:\n\t\tUI_DisplayOptionsMenu();\n\t\tbreak;\n\n\tcase ID_SOUND:\n\t\tUI_SoundOptionsMenu();\n\t\tbreak;\n\n\tcase ID_NETWORK:\n\t\tUI_NetworkOptionsMenu();\n\t\tbreak;\n\n\tcase ID_BACK:\n\t\tUI_PopMenu();\n\t\tbreak;\n\t}\n}\n\n\n/*\n===============\nSystemConfig_Cache\n===============\n*/\nvoid SystemConfig_Cache( void ) {\n\ttrap_R_RegisterShaderNoMip( ART_FRAMEL );\n\ttrap_R_RegisterShaderNoMip( ART_FRAMER );\n\ttrap_R_RegisterShaderNoMip( ART_BACK0 );\n\ttrap_R_RegisterShaderNoMip( ART_BACK1 );\n}\n\n/*\n===============\nOptions_MenuInit\n===============\n*/\nvoid Options_MenuInit( void ) {\n\tint\t\t\t\ty;\n\tuiClientState_t\tcstate;\n\n\tmemset( &s_options, 0, sizeof(optionsmenu_t) );\n\n\tSystemConfig_Cache();\n\ts_options.menu.wrapAround = qtrue;\n\n\ttrap_GetClientState( &cstate );\n\tif ( cstate.connState >= CA_CONNECTED ) {\n\t\ts_options.menu.fullscreen = qfalse;\n\t}\n\telse {\n\t\ts_options.menu.fullscreen = qtrue;\n\t}\n\n\ts_options.banner.generic.type\t= MTYPE_BTEXT;\n\ts_options.banner.generic.flags\t= QMF_CENTER_JUSTIFY;\n\ts_options.banner.generic.x\t\t= 320;\n\ts_options.banner.generic.y\t\t= 16;\n\ts_options.banner.string\t\t    = \"SYSTEM SETUP\";\n\ts_options.banner.color\t\t\t= color_white;\n\ts_options.banner.style\t\t\t= UI_CENTER;\n\n\ts_options.framel.generic.type  = MTYPE_BITMAP;\n\ts_options.framel.generic.name  = ART_FRAMEL;\n\ts_options.framel.generic.flags = QMF_INACTIVE;\n\ts_options.framel.generic.x\t   = 8;  \n\ts_options.framel.generic.y\t   = 76;\n\ts_options.framel.width  \t   = 256;\n\ts_options.framel.height  \t   = 334;\n\n\ts_options.framer.generic.type  = MTYPE_BITMAP;\n\ts_options.framer.generic.name  = ART_FRAMER;\n\ts_options.framer.generic.flags = QMF_INACTIVE;\n\ts_options.framer.generic.x\t   = 376;\n\ts_options.framer.generic.y\t   = 76;\n\ts_options.framer.width  \t   = 256;\n\ts_options.framer.height  \t   = 334;\n\n\ty = 168;\n\ts_options.graphics.generic.type\t\t= MTYPE_PTEXT;\n\ts_options.graphics.generic.flags\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_options.graphics.generic.callback\t= Options_Event;\n\ts_options.graphics.generic.id\t\t= ID_GRAPHICS;\n\ts_options.graphics.generic.x\t\t= 320;\n\ts_options.graphics.generic.y\t\t= y;\n\ts_options.graphics.string\t\t\t= \"GRAPHICS\";\n\ts_options.graphics.color\t\t\t= color_red;\n\ts_options.graphics.style\t\t\t= UI_CENTER;\n\n\ty += VERTICAL_SPACING;\n\ts_options.display.generic.type\t\t= MTYPE_PTEXT;\n\ts_options.display.generic.flags\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_options.display.generic.callback\t= Options_Event;\n\ts_options.display.generic.id\t\t= ID_DISPLAY;\n\ts_options.display.generic.x\t\t\t= 320;\n\ts_options.display.generic.y\t\t\t= y;\n\ts_options.display.string\t\t\t= \"DISPLAY\";\n\ts_options.display.color\t\t\t\t= color_red;\n\ts_options.display.style\t\t\t\t= UI_CENTER;\n\n\ty += VERTICAL_SPACING;\n\ts_options.sound.generic.type\t\t= MTYPE_PTEXT;\n\ts_options.sound.generic.flags\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_options.sound.generic.callback\t= Options_Event;\n\ts_options.sound.generic.id\t\t\t= ID_SOUND;\n\ts_options.sound.generic.x\t\t\t= 320;\n\ts_options.sound.generic.y\t\t\t= y;\n\ts_options.sound.string\t\t\t\t= \"SOUND\";\n\ts_options.sound.color\t\t\t\t= color_red;\n\ts_options.sound.style\t\t\t\t= UI_CENTER;\n\n\ty += VERTICAL_SPACING;\n\ts_options.network.generic.type\t\t= MTYPE_PTEXT;\n\ts_options.network.generic.flags\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_options.network.generic.callback\t= Options_Event;\n\ts_options.network.generic.id\t\t= ID_NETWORK;\n\ts_options.network.generic.x\t\t\t= 320;\n\ts_options.network.generic.y\t\t\t= y;\n\ts_options.network.string\t\t\t= \"NETWORK\";\n\ts_options.network.color\t\t\t\t= color_red;\n\ts_options.network.style\t\t\t\t= UI_CENTER;\n\n\ts_options.back.generic.type\t    = MTYPE_BITMAP;\n\ts_options.back.generic.name     = ART_BACK0;\n\ts_options.back.generic.flags    = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_options.back.generic.callback = Options_Event;\n\ts_options.back.generic.id\t    = ID_BACK;\n\ts_options.back.generic.x\t\t= 0;\n\ts_options.back.generic.y\t\t= 480-64;\n\ts_options.back.width  \t\t    = 128;\n\ts_options.back.height  \t\t    = 64;\n\ts_options.back.focuspic         = ART_BACK1;\n\n\tMenu_AddItem( &s_options.menu, ( void * ) &s_options.banner );\n\tMenu_AddItem( &s_options.menu, ( void * ) &s_options.framel );\n\tMenu_AddItem( &s_options.menu, ( void * ) &s_options.framer );\n\tMenu_AddItem( &s_options.menu, ( void * ) &s_options.graphics );\n\tMenu_AddItem( &s_options.menu, ( void * ) &s_options.display );\n\tMenu_AddItem( &s_options.menu, ( void * ) &s_options.sound );\n\tMenu_AddItem( &s_options.menu, ( void * ) &s_options.network );\n\tMenu_AddItem( &s_options.menu, ( void * ) &s_options.back );\n}\n\n\n/*\n===============\nUI_SystemConfigMenu\n===============\n*/\nvoid UI_SystemConfigMenu( void ) {\n\tOptions_MenuInit();\n\tUI_PushMenu ( &s_options.menu );\n}\n"
  },
  {
    "path": "src/q3_ui/ui_playermodel.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n#include \"ui_local.h\"\n\n#define MODEL_BACK0\t\t\t\"menu/art/back_0\"\n#define MODEL_BACK1\t\t\t\"menu/art/back_1\"\n#define MODEL_SELECT\t\t\"menu/art/opponents_select\"\n#define MODEL_SELECTED\t\t\"menu/art/opponents_selected\"\n#define MODEL_FRAMEL\t\t\"menu/art/frame1_l\"\n#define MODEL_FRAMER\t\t\"menu/art/frame1_r\"\n#define MODEL_PORTS\t\t\t\"menu/art/player_models_ports\"\n#define MODEL_ARROWS\t\t\"menu/art/gs_arrows_0\"\n#define MODEL_ARROWSL\t\t\"menu/art/gs_arrows_l\"\n#define MODEL_ARROWSR\t\t\"menu/art/gs_arrows_r\"\n\n#define LOW_MEMORY\t\t\t(5 * 1024 * 1024)\n\nstatic char* playermodel_artlist[] =\n{\n\tMODEL_BACK0,\t\n\tMODEL_BACK1,\t\n\tMODEL_SELECT,\n\tMODEL_SELECTED,\n\tMODEL_FRAMEL,\n\tMODEL_FRAMER,\n\tMODEL_PORTS,\t\n\tMODEL_ARROWS,\n\tMODEL_ARROWSL,\n\tMODEL_ARROWSR,\n\tNULL\n};\n\n#define PLAYERGRID_COLS\t\t4\n#define PLAYERGRID_ROWS\t\t4\n#define MAX_MODELSPERPAGE\t(PLAYERGRID_ROWS*PLAYERGRID_COLS)\n\n#define MAX_PLAYERMODELS\t256\n\n#define ID_PLAYERPIC0\t\t0\n#define ID_PLAYERPIC1\t\t1\n#define ID_PLAYERPIC2\t\t2\n#define ID_PLAYERPIC3\t\t3\n#define ID_PLAYERPIC4\t\t4\n#define ID_PLAYERPIC5\t\t5\n#define ID_PLAYERPIC6\t\t6\n#define ID_PLAYERPIC7\t\t7\n#define ID_PLAYERPIC8\t\t8\n#define ID_PLAYERPIC9\t\t9\n#define ID_PLAYERPIC10\t\t10\n#define ID_PLAYERPIC11\t\t11\n#define ID_PLAYERPIC12\t\t12\n#define ID_PLAYERPIC13\t\t13\n#define ID_PLAYERPIC14\t\t14\n#define ID_PLAYERPIC15\t\t15\n#define ID_PREVPAGE\t\t\t100\n#define ID_NEXTPAGE\t\t\t101\n#define ID_BACK\t\t\t\t102\n\ntypedef struct\n{\n\tmenuframework_s\tmenu;\n\tmenubitmap_s\tpics[MAX_MODELSPERPAGE];\n\tmenubitmap_s\tpicbuttons[MAX_MODELSPERPAGE];\n\tmenubitmap_s\tframel;\n\tmenubitmap_s\tframer;\n\tmenubitmap_s\tports;\n\tmenutext_s\t\tbanner;\n\tmenubitmap_s\tback;\n\tmenubitmap_s\tplayer;\n\tmenubitmap_s\tarrows;\n\tmenubitmap_s\tleft;\n\tmenubitmap_s\tright;\n\tmenutext_s\t\tmodelname;\n\tmenutext_s\t\tskinname;\n\tmenutext_s\t\tplayername;\n\tplayerInfo_t\tplayerinfo;\n\tint\t\t\t\tnummodels;\n\tchar\t\t\tmodelnames[MAX_PLAYERMODELS][128];\n\tint\t\t\t\tmodelpage;\n\tint\t\t\t\tnumpages;\n\tchar\t\t\tmodelskin[64];\n\tint\t\t\t\tselectedmodel;\n} playermodel_t;\n\nstatic playermodel_t s_playermodel;\n\n/*\n=================\nPlayerModel_UpdateGrid\n=================\n*/\nstatic void PlayerModel_UpdateGrid( void )\n{\n\tint\ti;\n    int\tj;\n\n\tj = s_playermodel.modelpage * MAX_MODELSPERPAGE;\n\tfor (i=0; i<PLAYERGRID_ROWS*PLAYERGRID_COLS; i++,j++)\n\t{\n\t\tif (j < s_playermodel.nummodels)\n\t\t{ \n\t\t\t// model/skin portrait\n \t\t\ts_playermodel.pics[i].generic.name         = s_playermodel.modelnames[j];\n\t\t\ts_playermodel.picbuttons[i].generic.flags &= ~QMF_INACTIVE;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// dead slot\n \t\t\ts_playermodel.pics[i].generic.name         = NULL;\n\t\t\ts_playermodel.picbuttons[i].generic.flags |= QMF_INACTIVE;\n\t\t}\n\n \t\ts_playermodel.pics[i].generic.flags       &= ~QMF_HIGHLIGHT;\n \t\ts_playermodel.pics[i].shader               = 0;\n \t\ts_playermodel.picbuttons[i].generic.flags |= QMF_PULSEIFFOCUS;\n\t}\n\n\tif (s_playermodel.selectedmodel/MAX_MODELSPERPAGE == s_playermodel.modelpage)\n\t{\n\t\t// set selected model\n\t\ti = s_playermodel.selectedmodel % MAX_MODELSPERPAGE;\n\n\t\ts_playermodel.pics[i].generic.flags       |= QMF_HIGHLIGHT;\n\t\ts_playermodel.picbuttons[i].generic.flags &= ~QMF_PULSEIFFOCUS;\n\t}\n\n\tif (s_playermodel.numpages > 1)\n\t{\n\t\tif (s_playermodel.modelpage > 0)\n\t\t\ts_playermodel.left.generic.flags &= ~QMF_INACTIVE;\n\t\telse\n\t\t\ts_playermodel.left.generic.flags |= QMF_INACTIVE;\n\n\t\tif (s_playermodel.modelpage < s_playermodel.numpages-1)\n\t\t\ts_playermodel.right.generic.flags &= ~QMF_INACTIVE;\n\t\telse\n\t\t\ts_playermodel.right.generic.flags |= QMF_INACTIVE;\n\t}\n\telse\n\t{\n\t\t// hide left/right markers\n\t\ts_playermodel.left.generic.flags |= QMF_INACTIVE;\n\t\ts_playermodel.right.generic.flags |= QMF_INACTIVE;\n\t}\n}\n\n/*\n=================\nPlayerModel_UpdateModel\n=================\n*/\nstatic void PlayerModel_UpdateModel( void )\n{\n\tvec3_t\tviewangles;\n\tvec3_t\tmoveangles;\n\n\tmemset( &s_playermodel.playerinfo, 0, sizeof(playerInfo_t) );\n\t\n\tviewangles[YAW]   = 180 - 30;\n\tviewangles[PITCH] = 0;\n\tviewangles[ROLL]  = 0;\n\tVectorClear( moveangles );\n\n\tUI_PlayerInfo_SetModel( &s_playermodel.playerinfo, s_playermodel.modelskin );\n\tUI_PlayerInfo_SetInfo( &s_playermodel.playerinfo, LEGS_IDLE, TORSO_STAND, viewangles, moveangles, WP_MACHINEGUN, qfalse );\n}\n\n/*\n=================\nPlayerModel_SaveChanges\n=================\n*/\nstatic void PlayerModel_SaveChanges( void )\n{\n\ttrap_Cvar_Set( \"model\", s_playermodel.modelskin );\n\ttrap_Cvar_Set( \"headmodel\", s_playermodel.modelskin );\n\ttrap_Cvar_Set( \"team_model\", s_playermodel.modelskin );\n\ttrap_Cvar_Set( \"team_headmodel\", s_playermodel.modelskin );\n}\n\n/*\n=================\nPlayerModel_MenuEvent\n=================\n*/\nstatic void PlayerModel_MenuEvent( void* ptr, int event )\n{\n\tif (event != QM_ACTIVATED)\n\t\treturn;\n\n\tswitch (((menucommon_s*)ptr)->id)\n\t{\n\t\tcase ID_PREVPAGE:\n\t\t\tif (s_playermodel.modelpage > 0)\n\t\t\t{\n\t\t\t\ts_playermodel.modelpage--;\n\t\t\t\tPlayerModel_UpdateGrid();\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase ID_NEXTPAGE:\n\t\t\tif (s_playermodel.modelpage < s_playermodel.numpages-1)\n\t\t\t{\n\t\t\t\ts_playermodel.modelpage++;\n\t\t\t\tPlayerModel_UpdateGrid();\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase ID_BACK:\n\t\t\tPlayerModel_SaveChanges();\n\t\t\tUI_PopMenu();\n\t\t\tbreak;\n\t}\n}\n\n/*\n=================\nPlayerModel_MenuKey\n=================\n*/\nstatic sfxHandle_t PlayerModel_MenuKey( int key )\n{\n\tmenucommon_s*\tm;\n\tint\t\t\t\tpicnum;\n\n\tswitch (key)\n\t{\n\t\tcase K_KP_LEFTARROW:\n\t\tcase K_LEFTARROW:\n\t\t\tm = Menu_ItemAtCursor(&s_playermodel.menu);\n\t\t\tpicnum = m->id - ID_PLAYERPIC0;\n\t\t\tif (picnum >= 0 && picnum <= 15)\n\t\t\t{\n\t\t\t\tif (picnum > 0)\n\t\t\t\t{\n\t\t\t\t\tMenu_SetCursor(&s_playermodel.menu,s_playermodel.menu.cursor-1);\n\t\t\t\t\treturn (menu_move_sound);\n\t\t\t\t\t\n\t\t\t\t}\n\t\t\t\telse if (s_playermodel.modelpage > 0)\n\t\t\t\t{\n\t\t\t\t\ts_playermodel.modelpage--;\n\t\t\t\t\tMenu_SetCursor(&s_playermodel.menu,s_playermodel.menu.cursor+15);\n\t\t\t\t\tPlayerModel_UpdateGrid();\n\t\t\t\t\treturn (menu_move_sound);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\treturn (menu_buzz_sound);\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase K_KP_RIGHTARROW:\n\t\tcase K_RIGHTARROW:\n\t\t\tm = Menu_ItemAtCursor(&s_playermodel.menu);\n\t\t\tpicnum = m->id - ID_PLAYERPIC0;\n\t\t\tif (picnum >= 0 && picnum <= 15)\n\t\t\t{\n\t\t\t\tif ((picnum < 15) && (s_playermodel.modelpage*MAX_MODELSPERPAGE + picnum+1 < s_playermodel.nummodels))\n\t\t\t\t{\n\t\t\t\t\tMenu_SetCursor(&s_playermodel.menu,s_playermodel.menu.cursor+1);\n\t\t\t\t\treturn (menu_move_sound);\n\t\t\t\t}\t\t\t\t\t\n\t\t\t\telse if ((picnum == 15) && (s_playermodel.modelpage < s_playermodel.numpages-1))\n\t\t\t\t{\n\t\t\t\t\ts_playermodel.modelpage++;\n\t\t\t\t\tMenu_SetCursor(&s_playermodel.menu,s_playermodel.menu.cursor-15);\n\t\t\t\t\tPlayerModel_UpdateGrid();\n\t\t\t\t\treturn (menu_move_sound);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\treturn (menu_buzz_sound);\n\t\t\t}\n\t\t\tbreak;\n\t\t\t\n\t\tcase K_MOUSE2:\n\t\tcase K_ESCAPE:\n\t\t\tPlayerModel_SaveChanges();\n\t\t\tbreak;\n\t}\n\n\treturn ( Menu_DefaultKey( &s_playermodel.menu, key ) );\n}\n\n/*\n=================\nPlayerModel_PicEvent\n=================\n*/\nstatic void PlayerModel_PicEvent( void* ptr, int event )\n{\n\tint\t\t\t\tmodelnum;\n\tint\t\t\t\tmaxlen;\n\tchar*\t\t\tbuffptr;\n\tchar*\t\t\tpdest;\n\tint\t\t\t\ti;\n\n\tif (event != QM_ACTIVATED)\n\t\treturn;\n\n\tfor (i=0; i<PLAYERGRID_ROWS*PLAYERGRID_COLS; i++)\n\t{\n\t\t// reset\n \t\ts_playermodel.pics[i].generic.flags       &= ~QMF_HIGHLIGHT;\n \t\ts_playermodel.picbuttons[i].generic.flags |= QMF_PULSEIFFOCUS;\n\t}\n\n\t// set selected\n\ti = ((menucommon_s*)ptr)->id - ID_PLAYERPIC0;\n\ts_playermodel.pics[i].generic.flags       |= QMF_HIGHLIGHT;\n\ts_playermodel.picbuttons[i].generic.flags &= ~QMF_PULSEIFFOCUS;\n\n\t// get model and strip icon_\n\tmodelnum = s_playermodel.modelpage*MAX_MODELSPERPAGE + i;\n\tbuffptr  = s_playermodel.modelnames[modelnum] + (int)strlen(\"models/players/\");\n\tpdest    = strstr(buffptr,\"icon_\");\n\tif (pdest)\n\t{\n\t\t// track the whole model/skin name\n\t\tQ_strncpyz(s_playermodel.modelskin,buffptr,pdest-buffptr+1);\n\t\tstrcat(s_playermodel.modelskin,pdest + 5);\n\n\t\t// seperate the model name\n\t\tmaxlen = pdest-buffptr;\n\t\tif (maxlen > 16)\n\t\t\tmaxlen = 16;\n\t\tQ_strncpyz( s_playermodel.modelname.string, buffptr, maxlen );\n\t\tQ_strupr( s_playermodel.modelname.string );\n\n\t\t// seperate the skin name\n\t\tmaxlen = (int)strlen(pdest+5)+1;\n\t\tif (maxlen > 16)\n\t\t\tmaxlen = 16;\n\t\tQ_strncpyz( s_playermodel.skinname.string, pdest+5, maxlen );\n\t\tQ_strupr( s_playermodel.skinname.string );\n\n\t\ts_playermodel.selectedmodel = modelnum;\n\n\t\tif( trap_MemoryRemaining() > LOW_MEMORY ) {\n\t\t\tPlayerModel_UpdateModel();\n\t\t}\n\t}\n}\n\n/*\n=================\nPlayerModel_DrawPlayer\n=================\n*/\nstatic void PlayerModel_DrawPlayer( void *self )\n{\n\tmenubitmap_s*\tb;\n\n\tb = (menubitmap_s*) self;\n\n\tif( trap_MemoryRemaining() <= LOW_MEMORY ) {\n\t\tUI_DrawProportionalString( b->generic.x, b->generic.y + b->height / 2, \"LOW MEMORY\", UI_LEFT, color_red );\n\t\treturn;\n\t}\n\n\tUI_DrawPlayer( b->generic.x, b->generic.y, b->width, b->height, &s_playermodel.playerinfo, uis.realtime/2 );\n}\n\n/*\n=================\nPlayerModel_BuildList\n=================\n*/\nstatic void PlayerModel_BuildList( void )\n{\n\tint\t\tnumdirs;\n\tint\t\tnumfiles;\n\tchar\tdirlist[2048];\n\tchar\tfilelist[2048];\n\tchar\tskinname[64];\n\tchar*\tdirptr;\n\tchar*\tfileptr;\n\tint\t\ti;\n\tint\t\tj;\n\tint\t\tdirlen;\n\tint\t\tfilelen;\n\tqboolean precache;\n\n\tprecache = trap_Cvar_VariableValue(\"com_buildscript\");\n\n\ts_playermodel.modelpage = 0;\n\ts_playermodel.nummodels = 0;\n\n\t// iterate directory of all player models\n\tnumdirs = trap_FS_GetFileList(\"models/players\", \"/\", dirlist, 2048 );\n\tdirptr  = dirlist;\n\tfor (i=0; i<numdirs && s_playermodel.nummodels < MAX_PLAYERMODELS; i++,dirptr+=dirlen+1)\n\t{\n\t\tdirlen = (int)strlen(dirptr);\n\t\t\n\t\tif (dirlen && dirptr[dirlen-1]=='/') dirptr[dirlen-1]='\\0';\n\n\t\tif (!strcmp(dirptr,\".\") || !strcmp(dirptr,\"..\"))\n\t\t\tcontinue;\n\t\t\t\n\t\t// iterate all skin files in directory\n\t\tnumfiles = trap_FS_GetFileList( va(\"models/players/%s\",dirptr), \"tga\", filelist, 2048 );\n\t\tfileptr  = filelist;\n\t\tfor (j=0; j<numfiles && s_playermodel.nummodels < MAX_PLAYERMODELS;j++,fileptr+=filelen+1)\n\t\t{\n\t\t\tfilelen = (int)strlen(fileptr);\n\n\t\t\tCOM_StripExtension(fileptr,skinname);\n\n\t\t\t// look for icon_????\n\t\t\tif (!Q_stricmpn(skinname,\"icon_\",5))\n\t\t\t{\n\t\t\t\tCom_sprintf( s_playermodel.modelnames[s_playermodel.nummodels++],\n\t\t\t\t\tsizeof( s_playermodel.modelnames[s_playermodel.nummodels] ),\n\t\t\t\t\t\"models/players/%s/%s\", dirptr, skinname );\n\t\t\t\t//if (s_playermodel.nummodels >= MAX_PLAYERMODELS)\n\t\t\t\t//\treturn;\n\t\t\t}\n\n\t\t\tif( precache ) {\n\t\t\t\ttrap_S_RegisterSound( va( \"sound/player/announce/%s_wins.wav\", skinname), qfalse );\n\t\t\t}\n\t\t}\n\t}\t\n\n\t//APSFIXME - Degenerate no models case\n\n\ts_playermodel.numpages = s_playermodel.nummodels/MAX_MODELSPERPAGE;\n\tif (s_playermodel.nummodels % MAX_MODELSPERPAGE)\n\t\ts_playermodel.numpages++;\n}\n\n/*\n=================\nPlayerModel_SetMenuItems\n=================\n*/\nstatic void PlayerModel_SetMenuItems( void )\n{\n\tint\t\t\t\ti;\n\tint\t\t\t\tmaxlen;\n\tchar\t\t\tmodelskin[64];\n\tchar*\t\t\tbuffptr;\n\tchar*\t\t\tpdest;\n\n\t// name\n\ttrap_Cvar_VariableStringBuffer( \"name\", s_playermodel.playername.string, 16 );\n\tQ_CleanStr( s_playermodel.playername.string );\n\n\t// model\n\ttrap_Cvar_VariableStringBuffer( \"model\", s_playermodel.modelskin, 64 );\n\t\n\t// find model in our list\n\tfor (i=0; i<s_playermodel.nummodels; i++)\n\t{\n\t\t// strip icon_\n\t\tbuffptr  = s_playermodel.modelnames[i] + (int)strlen(\"models/players/\");\n\t\tpdest    = strstr(buffptr,\"icon_\");\n\t\tif (pdest)\n\t\t{\n\t\t\tQ_strncpyz(modelskin,buffptr,pdest-buffptr+1);\n\t\t\tstrcat(modelskin,pdest + 5);\n\t\t}\n\t\telse\n\t\t\tcontinue;\n\n\t\tif (!Q_stricmp( s_playermodel.modelskin, modelskin ))\n\t\t{\n\t\t\t// found pic, set selection here\t\t\n\t\t\ts_playermodel.selectedmodel = i;\n\t\t\ts_playermodel.modelpage     = i/MAX_MODELSPERPAGE;\n\n\t\t\t// seperate the model name\n\t\t\tmaxlen = pdest-buffptr;\n\t\t\tif (maxlen > 16)\n\t\t\t\tmaxlen = 16;\n\t\t\tQ_strncpyz( s_playermodel.modelname.string, buffptr, maxlen );\n\t\t\tQ_strupr( s_playermodel.modelname.string );\n\n\t\t\t// seperate the skin name\n\t\t\tmaxlen = (int)strlen(pdest+5)+1;\n\t\t\tif (maxlen > 16)\n\t\t\t\tmaxlen = 16;\n\t\t\tQ_strncpyz( s_playermodel.skinname.string, pdest+5, maxlen );\n\t\t\tQ_strupr( s_playermodel.skinname.string );\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\n/*\n=================\nPlayerModel_MenuInit\n=================\n*/\nstatic void PlayerModel_MenuInit( void )\n{\n\tint\t\t\ti;\n\tint\t\t\tj;\n\tint\t\t\tk;\n\tint\t\t\tx;\n\tint\t\t\ty;\n\tstatic char\tplayername[32];\n\tstatic char\tmodelname[32];\n\tstatic char\tskinname[32];\n\n\t// zero set all our globals\n\tmemset( &s_playermodel, 0 ,sizeof(playermodel_t) );\n\n\tPlayerModel_Cache();\n\n\ts_playermodel.menu.key        = PlayerModel_MenuKey;\n\ts_playermodel.menu.wrapAround = qtrue;\n\ts_playermodel.menu.fullscreen = qtrue;\n\n\ts_playermodel.banner.generic.type  = MTYPE_BTEXT;\n\ts_playermodel.banner.generic.x     = 320;\n\ts_playermodel.banner.generic.y     = 16;\n\ts_playermodel.banner.string        = \"PLAYER MODEL\";\n\ts_playermodel.banner.color         = color_white;\n\ts_playermodel.banner.style         = UI_CENTER;\n\n\ts_playermodel.framel.generic.type  = MTYPE_BITMAP;\n\ts_playermodel.framel.generic.name  = MODEL_FRAMEL;\n\ts_playermodel.framel.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;\n\ts_playermodel.framel.generic.x     = 0;\n\ts_playermodel.framel.generic.y     = 78;\n\ts_playermodel.framel.width         = 256;\n\ts_playermodel.framel.height        = 329;\n\n\ts_playermodel.framer.generic.type  = MTYPE_BITMAP;\n\ts_playermodel.framer.generic.name  = MODEL_FRAMER;\n\ts_playermodel.framer.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;\n\ts_playermodel.framer.generic.x     = 376;\n\ts_playermodel.framer.generic.y     = 76;\n\ts_playermodel.framer.width         = 256;\n\ts_playermodel.framer.height        = 334;\n\n\ts_playermodel.ports.generic.type  = MTYPE_BITMAP;\n\ts_playermodel.ports.generic.name  = MODEL_PORTS;\n\ts_playermodel.ports.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;\n\ts_playermodel.ports.generic.x     = 50;\n\ts_playermodel.ports.generic.y     = 59;\n\ts_playermodel.ports.width         = 274;\n\ts_playermodel.ports.height        = 274;\n\n\ty =\t59;\n\tfor (i=0,k=0; i<PLAYERGRID_ROWS; i++)\n\t{\n\t\tx =\t50;\n\t\tfor (j=0; j<PLAYERGRID_COLS; j++,k++)\n\t\t{\n\t\t\ts_playermodel.pics[k].generic.type\t   = MTYPE_BITMAP;\n\t\t\ts_playermodel.pics[k].generic.flags    = QMF_LEFT_JUSTIFY|QMF_INACTIVE;\n\t\t\ts_playermodel.pics[k].generic.x\t\t   = x;\n\t\t\ts_playermodel.pics[k].generic.y\t\t   = y;\n\t\t\ts_playermodel.pics[k].width  \t\t   = 64;\n\t\t\ts_playermodel.pics[k].height  \t\t   = 64;\n\t\t\ts_playermodel.pics[k].focuspic         = MODEL_SELECTED;\n\t\t\ts_playermodel.pics[k].focuscolor       = colorRed;\n\n\t\t\ts_playermodel.picbuttons[k].generic.type\t = MTYPE_BITMAP;\n\t\t\ts_playermodel.picbuttons[k].generic.flags    = QMF_LEFT_JUSTIFY|QMF_NODEFAULTINIT|QMF_PULSEIFFOCUS;\n\t\t\ts_playermodel.picbuttons[k].generic.id\t     = ID_PLAYERPIC0+k;\n\t\t\ts_playermodel.picbuttons[k].generic.callback = PlayerModel_PicEvent;\n\t\t\ts_playermodel.picbuttons[k].generic.x    \t = x - 16;\n\t\t\ts_playermodel.picbuttons[k].generic.y\t\t = y - 16;\n\t\t\ts_playermodel.picbuttons[k].generic.left\t = x;\n\t\t\ts_playermodel.picbuttons[k].generic.top\t\t = y;\n\t\t\ts_playermodel.picbuttons[k].generic.right\t = x + 64;\n\t\t\ts_playermodel.picbuttons[k].generic.bottom   = y + 64;\n\t\t\ts_playermodel.picbuttons[k].width  \t\t     = 128;\n\t\t\ts_playermodel.picbuttons[k].height  \t\t = 128;\n\t\t\ts_playermodel.picbuttons[k].focuspic  \t\t = MODEL_SELECT;\n\t\t\ts_playermodel.picbuttons[k].focuscolor  \t = colorRed;\n\n\t\t\tx += 64+6;\n\t\t}\n\t\ty += 64+6;\n\t}\n\n\ts_playermodel.playername.generic.type  = MTYPE_PTEXT;\n\ts_playermodel.playername.generic.flags = QMF_CENTER_JUSTIFY|QMF_INACTIVE;\n\ts_playermodel.playername.generic.x\t   = 320;\n\ts_playermodel.playername.generic.y\t   = 440;\n\ts_playermodel.playername.string\t       = playername;\n\ts_playermodel.playername.style\t\t   = UI_CENTER;\n\ts_playermodel.playername.color         = text_color_normal;\n\n\ts_playermodel.modelname.generic.type  = MTYPE_PTEXT;\n\ts_playermodel.modelname.generic.flags = QMF_CENTER_JUSTIFY|QMF_INACTIVE;\n\ts_playermodel.modelname.generic.x\t  = 497;\n\ts_playermodel.modelname.generic.y\t  = 54;\n\ts_playermodel.modelname.string\t      = modelname;\n\ts_playermodel.modelname.style\t\t  = UI_CENTER;\n\ts_playermodel.modelname.color         = text_color_normal;\n\n\ts_playermodel.skinname.generic.type   = MTYPE_PTEXT;\n\ts_playermodel.skinname.generic.flags  = QMF_CENTER_JUSTIFY|QMF_INACTIVE;\n\ts_playermodel.skinname.generic.x\t  = 497;\n\ts_playermodel.skinname.generic.y\t  = 394;\n\ts_playermodel.skinname.string\t      = skinname;\n\ts_playermodel.skinname.style\t\t  = UI_CENTER;\n\ts_playermodel.skinname.color          = text_color_normal;\n\n\ts_playermodel.player.generic.type      = MTYPE_BITMAP;\n\ts_playermodel.player.generic.flags     = QMF_INACTIVE;\n\ts_playermodel.player.generic.ownerdraw = PlayerModel_DrawPlayer;\n\ts_playermodel.player.generic.x\t       = 400;\n\ts_playermodel.player.generic.y\t       = -40;\n\ts_playermodel.player.width\t           = 32*10;\n\ts_playermodel.player.height            = 56*10;\n\n\ts_playermodel.arrows.generic.type\t\t= MTYPE_BITMAP;\n\ts_playermodel.arrows.generic.name\t\t= MODEL_ARROWS;\n\ts_playermodel.arrows.generic.flags\t\t= QMF_INACTIVE;\n\ts_playermodel.arrows.generic.x\t\t\t= 125;\n\ts_playermodel.arrows.generic.y\t\t\t= 340;\n\ts_playermodel.arrows.width\t\t\t\t= 128;\n\ts_playermodel.arrows.height\t\t\t\t= 32;\n\n\ts_playermodel.left.generic.type\t\t\t= MTYPE_BITMAP;\n\ts_playermodel.left.generic.flags\t\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_playermodel.left.generic.callback\t\t= PlayerModel_MenuEvent;\n\ts_playermodel.left.generic.id\t\t\t= ID_PREVPAGE;\n\ts_playermodel.left.generic.x\t\t\t= 125;\n\ts_playermodel.left.generic.y\t\t\t= 340;\n\ts_playermodel.left.width  \t\t\t\t= 64;\n\ts_playermodel.left.height  \t\t\t\t= 32;\n\ts_playermodel.left.focuspic\t\t\t\t= MODEL_ARROWSL;\n\n\ts_playermodel.right.generic.type\t    = MTYPE_BITMAP;\n\ts_playermodel.right.generic.flags\t\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_playermodel.right.generic.callback\t= PlayerModel_MenuEvent;\n\ts_playermodel.right.generic.id\t\t\t= ID_NEXTPAGE;\n\ts_playermodel.right.generic.x\t\t\t= 125+61;\n\ts_playermodel.right.generic.y\t\t\t= 340;\n\ts_playermodel.right.width  \t\t\t\t= 64;\n\ts_playermodel.right.height  \t\t    = 32;\n\ts_playermodel.right.focuspic\t\t\t= MODEL_ARROWSR;\n\n\ts_playermodel.back.generic.type\t    = MTYPE_BITMAP;\n\ts_playermodel.back.generic.name     = MODEL_BACK0;\n\ts_playermodel.back.generic.flags    = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_playermodel.back.generic.callback = PlayerModel_MenuEvent;\n\ts_playermodel.back.generic.id\t    = ID_BACK;\n\ts_playermodel.back.generic.x\t\t= 0;\n\ts_playermodel.back.generic.y\t\t= 480-64;\n\ts_playermodel.back.width  \t\t    = 128;\n\ts_playermodel.back.height  \t\t    = 64;\n\ts_playermodel.back.focuspic         = MODEL_BACK1;\n\n\tMenu_AddItem( &s_playermodel.menu,\t&s_playermodel.banner );\n\tMenu_AddItem( &s_playermodel.menu,\t&s_playermodel.framel );\n\tMenu_AddItem( &s_playermodel.menu,\t&s_playermodel.framer );\n\tMenu_AddItem( &s_playermodel.menu,\t&s_playermodel.ports );\n\tMenu_AddItem( &s_playermodel.menu,\t&s_playermodel.playername );\n\tMenu_AddItem( &s_playermodel.menu,\t&s_playermodel.modelname );\n\tMenu_AddItem( &s_playermodel.menu,\t&s_playermodel.skinname );\n\n\tfor (i=0; i<MAX_MODELSPERPAGE; i++)\n\t{\n\t\tMenu_AddItem( &s_playermodel.menu,\t&s_playermodel.pics[i] );\n\t\tMenu_AddItem( &s_playermodel.menu,\t&s_playermodel.picbuttons[i] );\n\t}\n\n\tMenu_AddItem( &s_playermodel.menu,\t&s_playermodel.player );\n\tMenu_AddItem( &s_playermodel.menu,\t&s_playermodel.arrows );\n\tMenu_AddItem( &s_playermodel.menu,\t&s_playermodel.left );\n\tMenu_AddItem( &s_playermodel.menu,\t&s_playermodel.right );\n\tMenu_AddItem( &s_playermodel.menu,\t&s_playermodel.back );\n\n\t// find all available models\n//\tPlayerModel_BuildList();\n\n\t// set initial states\n\tPlayerModel_SetMenuItems();\n\n\t// update user interface\n\tPlayerModel_UpdateGrid();\n\tPlayerModel_UpdateModel();\n}\n\n/*\n=================\nPlayerModel_Cache\n=================\n*/\nvoid PlayerModel_Cache( void )\n{\n\tint\ti;\n\n\tfor( i = 0; playermodel_artlist[i]; i++ ) {\n\t\ttrap_R_RegisterShaderNoMip( playermodel_artlist[i] );\n\t}\n\n\tPlayerModel_BuildList();\n\tfor( i = 0; i < s_playermodel.nummodels; i++ ) {\n\t\ttrap_R_RegisterShaderNoMip( s_playermodel.modelnames[i] );\n\t}\n}\n\nvoid UI_PlayerModelMenu(void)\n{\n\tPlayerModel_MenuInit();\n\n\tUI_PushMenu( &s_playermodel.menu );\n\n\tMenu_SetCursorToItem( &s_playermodel.menu, &s_playermodel.pics[s_playermodel.selectedmodel % MAX_MODELSPERPAGE] );\n}\n\n\n"
  },
  {
    "path": "src/q3_ui/ui_players.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n// ui_players.c\n\n#include \"ui_local.h\"\n\n\n#define UI_TIMER_GESTURE\t\t2300\n#define UI_TIMER_JUMP\t\t\t1000\n#define UI_TIMER_LAND\t\t\t130\n#define UI_TIMER_WEAPON_SWITCH\t300\n#define UI_TIMER_ATTACK\t\t\t500\n#define\tUI_TIMER_MUZZLE_FLASH\t20\n#define\tUI_TIMER_WEAPON_DELAY\t250\n\n#define JUMP_HEIGHT\t\t\t\t56\n\n#define SWINGSPEED\t\t\t\t0.3f\n\n#define SPIN_SPEED\t\t\t\t0.9f\n#define COAST_TIME\t\t\t\t1000\n\n\nstatic int\t\t\tdp_realtime;\nstatic float\t\tjumpHeight;\n\n\n/*\n===============\nUI_PlayerInfo_SetWeapon\n===============\n*/\nstatic void UI_PlayerInfo_SetWeapon( playerInfo_t *pi, weapon_t weaponNum ) {\n\tgitem_t *\titem;\n\tchar\t\tpath[MAX_QPATH];\n\n\tpi->currentWeapon = weaponNum;\ntryagain:\n\tpi->realWeapon = weaponNum;\n\tpi->weaponModel = 0;\n\tpi->barrelModel = 0;\n\tpi->flashModel = 0;\n\n\tif ( weaponNum == WP_NONE ) {\n\t\treturn;\n\t}\n\n\tfor ( item = bg_itemlist + 1; item->classname ; item++ ) {\n\t\tif ( item->giType != IT_WEAPON ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( item->giTag == weaponNum ) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif ( item->classname ) {\n\t\tpi->weaponModel = trap_R_RegisterModel( item->world_model[0] );\n\t}\n\n\tif( pi->weaponModel == 0 ) {\n\t\tif( weaponNum == WP_MACHINEGUN ) {\n\t\t\tweaponNum = WP_NONE;\n\t\t\tgoto tryagain;\n\t\t}\n\t\tweaponNum = WP_MACHINEGUN;\n\t\tgoto tryagain;\n\t}\n\n\tif ( weaponNum == WP_MACHINEGUN || weaponNum == WP_GAUNTLET || weaponNum == WP_BFG ) {\n\t\tstrcpy( path, item->world_model[0] );\n\t\tCOM_StripExtension( path, path );\n\t\tstrcat( path, \"_barrel.md3\" );\n\t\tpi->barrelModel = trap_R_RegisterModel( path );\n\t}\n\n\tstrcpy( path, item->world_model[0] );\n\tCOM_StripExtension( path, path );\n\tstrcat( path, \"_flash.md3\" );\n\tpi->flashModel = trap_R_RegisterModel( path );\n\n\tswitch( weaponNum ) {\n\tcase WP_GAUNTLET:\n\t\tMAKERGB( pi->flashDlightColor, 0.6f, 0.6f, 1 );\n\t\tbreak;\n\n\tcase WP_MACHINEGUN:\n\t\tMAKERGB( pi->flashDlightColor, 1, 1, 0 );\n\t\tbreak;\n\n\tcase WP_SHOTGUN:\n\t\tMAKERGB( pi->flashDlightColor, 1, 1, 0 );\n\t\tbreak;\n\n\tcase WP_GRENADE_LAUNCHER:\n\t\tMAKERGB( pi->flashDlightColor, 1, 0.7f, 0.5f );\n\t\tbreak;\n\n\tcase WP_ROCKET_LAUNCHER:\n\t\tMAKERGB( pi->flashDlightColor, 1, 0.75f, 0 );\n\t\tbreak;\n\n\tcase WP_LIGHTNING:\n\t\tMAKERGB( pi->flashDlightColor, 0.6f, 0.6f, 1 );\n\t\tbreak;\n\n\tcase WP_RAILGUN:\n\t\tMAKERGB( pi->flashDlightColor, 1, 0.5f, 0 );\n\t\tbreak;\n\n\tcase WP_PLASMAGUN:\n\t\tMAKERGB( pi->flashDlightColor, 0.6f, 0.6f, 1 );\n\t\tbreak;\n\n\tcase WP_BFG:\n\t\tMAKERGB( pi->flashDlightColor, 1, 0.7f, 1 );\n\t\tbreak;\n\n\tcase WP_GRAPPLING_HOOK:\n\t\tMAKERGB( pi->flashDlightColor, 0.6f, 0.6f, 1 );\n\t\tbreak;\n\n\tdefault:\n\t\tMAKERGB( pi->flashDlightColor, 1, 1, 1 );\n\t\tbreak;\n\t}\n}\n\n\n/*\n===============\nUI_ForceLegsAnim\n===============\n*/\nstatic void UI_ForceLegsAnim( playerInfo_t *pi, int anim ) {\n\tpi->legsAnim = ( ( pi->legsAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;\n\n\tif ( anim == LEGS_JUMP ) {\n\t\tpi->legsAnimationTimer = UI_TIMER_JUMP;\n\t}\n}\n\n\n/*\n===============\nUI_SetLegsAnim\n===============\n*/\nstatic void UI_SetLegsAnim( playerInfo_t *pi, int anim ) {\n\tif ( pi->pendingLegsAnim ) {\n\t\tanim = pi->pendingLegsAnim;\n\t\tpi->pendingLegsAnim = 0;\n\t}\n\tUI_ForceLegsAnim( pi, anim );\n}\n\n\n/*\n===============\nUI_ForceTorsoAnim\n===============\n*/\nstatic void UI_ForceTorsoAnim( playerInfo_t *pi, int anim ) {\n\tpi->torsoAnim = ( ( pi->torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;\n\n\tif ( anim == TORSO_GESTURE ) {\n\t\tpi->torsoAnimationTimer = UI_TIMER_GESTURE;\n\t}\n\n\tif ( anim == TORSO_ATTACK || anim == TORSO_ATTACK2 ) {\n\t\tpi->torsoAnimationTimer = UI_TIMER_ATTACK;\n\t}\n}\n\n\n/*\n===============\nUI_SetTorsoAnim\n===============\n*/\nstatic void UI_SetTorsoAnim( playerInfo_t *pi, int anim ) {\n\tif ( pi->pendingTorsoAnim ) {\n\t\tanim = pi->pendingTorsoAnim;\n\t\tpi->pendingTorsoAnim = 0;\n\t}\n\n\tUI_ForceTorsoAnim( pi, anim );\n}\n\n\n/*\n===============\nUI_TorsoSequencing\n===============\n*/\nstatic void UI_TorsoSequencing( playerInfo_t *pi ) {\n\tint\t\tcurrentAnim;\n\n\tcurrentAnim = pi->torsoAnim & ~ANIM_TOGGLEBIT;\n\n\tif ( pi->weapon != pi->currentWeapon ) {\n\t\tif ( currentAnim != TORSO_DROP ) {\n\t\t\tpi->torsoAnimationTimer = UI_TIMER_WEAPON_SWITCH;\n\t\t\tUI_ForceTorsoAnim( pi, TORSO_DROP );\n\t\t}\n\t}\n\n\tif ( pi->torsoAnimationTimer > 0 ) {\n\t\treturn;\n\t}\n\n\tif( currentAnim == TORSO_GESTURE ) {\n\t\tUI_SetTorsoAnim( pi, TORSO_STAND );\n\t\treturn;\n\t}\n\n\tif( currentAnim == TORSO_ATTACK || currentAnim == TORSO_ATTACK2 ) {\n\t\tUI_SetTorsoAnim( pi, TORSO_STAND );\n\t\treturn;\n\t}\n\n\tif ( currentAnim == TORSO_DROP ) {\n\t\tUI_PlayerInfo_SetWeapon( pi, pi->weapon );\n\t\tpi->torsoAnimationTimer = UI_TIMER_WEAPON_SWITCH;\n\t\tUI_ForceTorsoAnim( pi, TORSO_RAISE );\n\t\treturn;\n\t}\n\n\tif ( currentAnim == TORSO_RAISE ) {\n\t\tUI_SetTorsoAnim( pi, TORSO_STAND );\n\t\treturn;\n\t}\n}\n\n\n/*\n===============\nUI_LegsSequencing\n===============\n*/\nstatic void UI_LegsSequencing( playerInfo_t *pi ) {\n\tint\t\tcurrentAnim;\n\n\tcurrentAnim = pi->legsAnim & ~ANIM_TOGGLEBIT;\n\n\tif ( pi->legsAnimationTimer > 0 ) {\n\t\tif ( currentAnim == LEGS_JUMP ) {\n\t\t\tjumpHeight = JUMP_HEIGHT * sin( M_PI * ( UI_TIMER_JUMP - pi->legsAnimationTimer ) / UI_TIMER_JUMP );\n\t\t}\n\t\treturn;\n\t}\n\n\tif ( currentAnim == LEGS_JUMP ) {\n\t\tUI_ForceLegsAnim( pi, LEGS_LAND );\n\t\tpi->legsAnimationTimer = UI_TIMER_LAND;\n\t\tjumpHeight = 0;\n\t\treturn;\n\t}\n\n\tif ( currentAnim == LEGS_LAND ) {\n\t\tUI_SetLegsAnim( pi, LEGS_IDLE );\n\t\treturn;\n\t}\n}\n\n\n/*\n======================\nUI_PositionEntityOnTag\n======================\n*/\nstatic void UI_PositionEntityOnTag( refEntity_t *entity, const refEntity_t *parent, \n\t\t\t\t\t\t\tclipHandle_t parentModel, char *tagName ) {\n\tint\t\t\t\ti;\n\torientation_t\tlerped;\n\t\n\t// lerp the tag\n\ttrap_CM_LerpTag( &lerped, parentModel, parent->oldframe, parent->frame,\n\t\t1.0 - parent->backlerp, tagName );\n\n\t// FIXME: allow origin offsets along tag?\n\tVectorCopy( parent->origin, entity->origin );\n\tfor ( i = 0 ; i < 3 ; i++ ) {\n\t\tVectorMA( entity->origin, lerped.origin[i], parent->axis[i], entity->origin );\n\t}\n\n\t// cast away const because of compiler problems\n\tMatrixMultiply( lerped.axis, ((refEntity_t*)parent)->axis, entity->axis );\n\tentity->backlerp = parent->backlerp;\n}\n\n\n/*\n======================\nUI_PositionRotatedEntityOnTag\n======================\n*/\nstatic void UI_PositionRotatedEntityOnTag( refEntity_t *entity, const refEntity_t *parent, \n\t\t\t\t\t\t\tclipHandle_t parentModel, char *tagName ) {\n\tint\t\t\t\ti;\n\torientation_t\tlerped;\n\tvec3_t\t\t\ttempAxis[3];\n\n\t// lerp the tag\n\ttrap_CM_LerpTag( &lerped, parentModel, parent->oldframe, parent->frame,\n\t\t1.0 - parent->backlerp, tagName );\n\n\t// FIXME: allow origin offsets along tag?\n\tVectorCopy( parent->origin, entity->origin );\n\tfor ( i = 0 ; i < 3 ; i++ ) {\n\t\tVectorMA( entity->origin, lerped.origin[i], parent->axis[i], entity->origin );\n\t}\n\n\t// cast away const because of compiler problems\n\tMatrixMultiply( entity->axis, ((refEntity_t *)parent)->axis, tempAxis );\n\tMatrixMultiply( lerped.axis, tempAxis, entity->axis );\n}\n\n\n/*\n===============\nUI_SetLerpFrameAnimation\n===============\n*/\nstatic void UI_SetLerpFrameAnimation( playerInfo_t *ci, lerpFrame_t *lf, int newAnimation ) {\n\tanimation_t\t*anim;\n\n\tlf->animationNumber = newAnimation;\n\tnewAnimation &= ~ANIM_TOGGLEBIT;\n\n\tif ( newAnimation < 0 || newAnimation >= MAX_ANIMATIONS ) {\n\t\ttrap_Error( va(\"Bad animation number: %i\", newAnimation) );\n\t}\n\n\tanim = &ci->animations[ newAnimation ];\n\n\tlf->animation = anim;\n\tlf->animationTime = lf->frameTime + anim->initialLerp;\n}\n\n\n/*\n===============\nUI_RunLerpFrame\n===============\n*/\nstatic void UI_RunLerpFrame( playerInfo_t *ci, lerpFrame_t *lf, int newAnimation ) {\n\tint\t\t\tf;\n\tanimation_t\t*anim;\n\n\t// see if the animation sequence is switching\n\tif ( newAnimation != lf->animationNumber || !lf->animation ) {\n\t\tUI_SetLerpFrameAnimation( ci, lf, newAnimation );\n\t}\n\n\t// if we have passed the current frame, move it to\n\t// oldFrame and calculate a new frame\n\tif ( dp_realtime >= lf->frameTime ) {\n\t\tlf->oldFrame = lf->frame;\n\t\tlf->oldFrameTime = lf->frameTime;\n\n\t\t// get the next frame based on the animation\n\t\tanim = lf->animation;\n\t\tif ( dp_realtime < lf->animationTime ) {\n\t\t\tlf->frameTime = lf->animationTime;\t\t// initial lerp\n\t\t} else {\n\t\t\tlf->frameTime = lf->oldFrameTime + anim->frameLerp;\n\t\t}\n\t\tf = ( lf->frameTime - lf->animationTime ) / anim->frameLerp;\n\t\tif ( f >= anim->numFrames ) {\n\t\t\tf -= anim->numFrames;\n\t\t\tif ( anim->loopFrames ) {\n\t\t\t\tf %= anim->loopFrames;\n\t\t\t\tf += anim->numFrames - anim->loopFrames;\n\t\t\t} else {\n\t\t\t\tf = anim->numFrames - 1;\n\t\t\t\t// the animation is stuck at the end, so it\n\t\t\t\t// can immediately transition to another sequence\n\t\t\t\tlf->frameTime = dp_realtime;\n\t\t\t}\n\t\t}\n\t\tlf->frame = anim->firstFrame + f;\n\t\tif ( dp_realtime > lf->frameTime ) {\n\t\t\tlf->frameTime = dp_realtime;\n\t\t}\n\t}\n\n\tif ( lf->frameTime > dp_realtime + 200 ) {\n\t\tlf->frameTime = dp_realtime;\n\t}\n\n\tif ( lf->oldFrameTime > dp_realtime ) {\n\t\tlf->oldFrameTime = dp_realtime;\n\t}\n\t// calculate current lerp value\n\tif ( lf->frameTime == lf->oldFrameTime ) {\n\t\tlf->backlerp = 0;\n\t} else {\n\t\tlf->backlerp = 1.0 - (float)( dp_realtime - lf->oldFrameTime ) / ( lf->frameTime - lf->oldFrameTime );\n\t}\n}\n\n\n/*\n===============\nUI_PlayerAnimation\n===============\n*/\nstatic void UI_PlayerAnimation( playerInfo_t *pi, int *legsOld, int *legs, float *legsBackLerp,\n\t\t\t\t\t\tint *torsoOld, int *torso, float *torsoBackLerp ) {\n\n\t// legs animation\n\tpi->legsAnimationTimer -= uis.frametime;\n\tif ( pi->legsAnimationTimer < 0 ) {\n\t\tpi->legsAnimationTimer = 0;\n\t}\n\n\tUI_LegsSequencing( pi );\n\n\tif ( pi->legs.yawing && ( pi->legsAnim & ~ANIM_TOGGLEBIT ) == LEGS_IDLE ) {\n\t\tUI_RunLerpFrame( pi, &pi->legs, LEGS_TURN );\n\t} else {\n\t\tUI_RunLerpFrame( pi, &pi->legs, pi->legsAnim );\n\t}\n\t*legsOld = pi->legs.oldFrame;\n\t*legs = pi->legs.frame;\n\t*legsBackLerp = pi->legs.backlerp;\n\n\t// torso animation\n\tpi->torsoAnimationTimer -= uis.frametime;\n\tif ( pi->torsoAnimationTimer < 0 ) {\n\t\tpi->torsoAnimationTimer = 0;\n\t}\n\n\tUI_TorsoSequencing( pi );\n\n\tUI_RunLerpFrame( pi, &pi->torso, pi->torsoAnim );\n\t*torsoOld = pi->torso.oldFrame;\n\t*torso = pi->torso.frame;\n\t*torsoBackLerp = pi->torso.backlerp;\n}\n\n\n/*\n==================\nUI_SwingAngles\n==================\n*/\nstatic void UI_SwingAngles( float destination, float swingTolerance, float clampTolerance,\n\t\t\t\t\tfloat speed, float *angle, qboolean *swinging ) {\n\tfloat\tswing;\n\tfloat\tmove;\n\tfloat\tscale;\n\n\tif ( !*swinging ) {\n\t\t// see if a swing should be started\n\t\tswing = AngleSubtract( *angle, destination );\n\t\tif ( swing > swingTolerance || swing < -swingTolerance ) {\n\t\t\t*swinging = qtrue;\n\t\t}\n\t}\n\n\tif ( !*swinging ) {\n\t\treturn;\n\t}\n\t\n\t// modify the speed depending on the delta\n\t// so it doesn't seem so linear\n\tswing = AngleSubtract( destination, *angle );\n\tscale = fabs( swing );\n\tif ( scale < swingTolerance * 0.5 ) {\n\t\tscale = 0.5;\n\t} else if ( scale < swingTolerance ) {\n\t\tscale = 1.0;\n\t} else {\n\t\tscale = 2.0;\n\t}\n\n\t// swing towards the destination angle\n\tif ( swing >= 0 ) {\n\t\tmove = uis.frametime * scale * speed;\n\t\tif ( move >= swing ) {\n\t\t\tmove = swing;\n\t\t\t*swinging = qfalse;\n\t\t}\n\t\t*angle = AngleMod( *angle + move );\n\t} else if ( swing < 0 ) {\n\t\tmove = uis.frametime * scale * -speed;\n\t\tif ( move <= swing ) {\n\t\t\tmove = swing;\n\t\t\t*swinging = qfalse;\n\t\t}\n\t\t*angle = AngleMod( *angle + move );\n\t}\n\n\t// clamp to no more than tolerance\n\tswing = AngleSubtract( destination, *angle );\n\tif ( swing > clampTolerance ) {\n\t\t*angle = AngleMod( destination - (clampTolerance - 1) );\n\t} else if ( swing < -clampTolerance ) {\n\t\t*angle = AngleMod( destination + (clampTolerance - 1) );\n\t}\n}\n\n\n/*\n======================\nUI_MovedirAdjustment\n======================\n*/\nstatic float UI_MovedirAdjustment( playerInfo_t *pi ) {\n\tvec3_t\t\trelativeAngles;\n\tvec3_t\t\tmoveVector;\n\n\tVectorSubtract( pi->viewAngles, pi->moveAngles, relativeAngles );\n\tAngleVectors( relativeAngles, moveVector, NULL, NULL );\n\tif ( Q_fabs( moveVector[0] ) < 0.01 ) {\n\t\tmoveVector[0] = 0.0;\n\t}\n\tif ( Q_fabs( moveVector[1] ) < 0.01 ) {\n\t\tmoveVector[1] = 0.0;\n\t}\n\n\tif ( moveVector[1] == 0 && moveVector[0] > 0 ) {\n\t\treturn 0;\n\t}\n\tif ( moveVector[1] < 0 && moveVector[0] > 0 ) {\n\t\treturn 22;\n\t}\n\tif ( moveVector[1] < 0 && moveVector[0] == 0 ) {\n\t\treturn 45;\n\t}\n\tif ( moveVector[1] < 0 && moveVector[0] < 0 ) {\n\t\treturn -22;\n\t}\n\tif ( moveVector[1] == 0 && moveVector[0] < 0 ) {\n\t\treturn 0;\n\t}\n\tif ( moveVector[1] > 0 && moveVector[0] < 0 ) {\n\t\treturn 22;\n\t}\n\tif ( moveVector[1] > 0 && moveVector[0] == 0 ) {\n\t\treturn  -45;\n\t}\n\n\treturn -22;\n}\n\n\n/*\n===============\nUI_PlayerAngles\n===============\n*/\nstatic void UI_PlayerAngles( playerInfo_t *pi, vec3_t legs[3], vec3_t torso[3], vec3_t head[3] ) {\n\tvec3_t\t\tlegsAngles, torsoAngles, headAngles;\n\tfloat\t\tdest;\n\tfloat\t\tadjust;\n\n\tVectorCopy( pi->viewAngles, headAngles );\n\theadAngles[YAW] = AngleMod( headAngles[YAW] );\n\tVectorClear( legsAngles );\n\tVectorClear( torsoAngles );\n\n\t// --------- yaw -------------\n\n\t// allow yaw to drift a bit\n\tif ( ( pi->legsAnim & ~ANIM_TOGGLEBIT ) != LEGS_IDLE \n\t\t|| ( pi->torsoAnim & ~ANIM_TOGGLEBIT ) != TORSO_STAND  ) {\n\t\t// if not standing still, always point all in the same direction\n\t\tpi->torso.yawing = qtrue;\t// always center\n\t\tpi->torso.pitching = qtrue;\t// always center\n\t\tpi->legs.yawing = qtrue;\t// always center\n\t}\n\n\t// adjust legs for movement dir\n\tadjust = UI_MovedirAdjustment( pi );\n\tlegsAngles[YAW] = headAngles[YAW] + adjust;\n\ttorsoAngles[YAW] = headAngles[YAW] + 0.25 * adjust;\n\n\n\t// torso\n\tUI_SwingAngles( torsoAngles[YAW], 25, 90, SWINGSPEED, &pi->torso.yawAngle, &pi->torso.yawing );\n\tUI_SwingAngles( legsAngles[YAW], 40, 90, SWINGSPEED, &pi->legs.yawAngle, &pi->legs.yawing );\n\n\ttorsoAngles[YAW] = pi->torso.yawAngle;\n\tlegsAngles[YAW] = pi->legs.yawAngle;\n\n\t// --------- pitch -------------\n\n\t// only show a fraction of the pitch angle in the torso\n\tif ( headAngles[PITCH] > 180 ) {\n\t\tdest = (-360 + headAngles[PITCH]) * 0.75;\n\t} else {\n\t\tdest = headAngles[PITCH] * 0.75;\n\t}\n\tUI_SwingAngles( dest, 15, 30, 0.1f, &pi->torso.pitchAngle, &pi->torso.pitching );\n\ttorsoAngles[PITCH] = pi->torso.pitchAngle;\n\n\t// pull the angles back out of the hierarchial chain\n\tAnglesSubtract( headAngles, torsoAngles, headAngles );\n\tAnglesSubtract( torsoAngles, legsAngles, torsoAngles );\n\tAnglesToAxis( legsAngles, legs );\n\tAnglesToAxis( torsoAngles, torso );\n\tAnglesToAxis( headAngles, head );\n}\n\n\n/*\n===============\nUI_PlayerFloatSprite\n===============\n*/\nstatic void UI_PlayerFloatSprite( playerInfo_t *pi, vec3_t origin, qhandle_t shader ) {\n\trefEntity_t\t\tent;\n\n\tmemset( &ent, 0, sizeof( ent ) );\n\tVectorCopy( origin, ent.origin );\n\tent.origin[2] += 48;\n\tent.reType = RT_SPRITE;\n\tent.customShader = shader;\n\tent.radius = 10;\n\tent.renderfx = 0;\n\ttrap_R_AddRefEntityToScene( &ent );\n}\n\n\n/*\n======================\nUI_MachinegunSpinAngle\n======================\n*/\nfloat\tUI_MachinegunSpinAngle( playerInfo_t *pi ) {\n\tint\t\tdelta;\n\tfloat\tangle;\n\tfloat\tspeed;\n\tint\t\ttorsoAnim;\n\n\tdelta = dp_realtime - pi->barrelTime;\n\tif ( pi->barrelSpinning ) {\n\t\tangle = pi->barrelAngle + delta * SPIN_SPEED;\n\t} else {\n\t\tif ( delta > COAST_TIME ) {\n\t\t\tdelta = COAST_TIME;\n\t\t}\n\n\t\tspeed = 0.5 * ( SPIN_SPEED + (float)( COAST_TIME - delta ) / COAST_TIME );\n\t\tangle = pi->barrelAngle + delta * speed;\n\t}\n\n\ttorsoAnim = pi->torsoAnim  & ~ANIM_TOGGLEBIT;\n\tif( torsoAnim == TORSO_ATTACK2 ) {\n\t\ttorsoAnim = TORSO_ATTACK;\n\t}\n\tif ( pi->barrelSpinning == !(torsoAnim == TORSO_ATTACK) ) {\n\t\tpi->barrelTime = dp_realtime;\n\t\tpi->barrelAngle = AngleMod( angle );\n\t\tpi->barrelSpinning = !!(torsoAnim == TORSO_ATTACK);\n\t}\n\n\treturn angle;\n}\n\n\n/*\n===============\nUI_DrawPlayer\n===============\n*/\nvoid UI_DrawPlayer( float x, float y, float w, float h, playerInfo_t *pi, int time ) {\n\trefdef_t\t\trefdef;\n\trefEntity_t\t\tlegs;\n\trefEntity_t\t\ttorso;\n\trefEntity_t\t\thead;\n\trefEntity_t\t\tgun;\n\trefEntity_t\t\tbarrel;\n\trefEntity_t\t\tflash;\n\tvec3_t\t\t\torigin;\n\tint\t\t\t\trenderfx;\n\tvec3_t\t\t\tmins = {-16, -16, -24};\n\tvec3_t\t\t\tmaxs = {16, 16, 32};\n\tfloat\t\t\tlen;\n\tfloat\t\t\txx;\n\n\tif ( !pi->legsModel || !pi->torsoModel || !pi->headModel || !pi->animations[0].numFrames ) {\n\t\treturn;\n\t}\n\n\tdp_realtime = time;\n\n\tif ( pi->pendingWeapon != -1 && dp_realtime > pi->weaponTimer ) {\n\t\tpi->weapon = pi->pendingWeapon;\n\t\tpi->lastWeapon = pi->pendingWeapon;\n\t\tpi->pendingWeapon = -1;\n\t\tpi->weaponTimer = 0;\n\t\tif( pi->currentWeapon != pi->weapon ) {\n\t\t\ttrap_S_StartLocalSound( weaponChangeSound, CHAN_LOCAL );\n\t\t}\n\t}\n\n\tUI_AdjustFrom640( &x, &y, &w, &h );\n\n\ty -= jumpHeight;\n\n\tmemset( &refdef, 0, sizeof( refdef ) );\n\tmemset( &legs, 0, sizeof(legs) );\n\tmemset( &torso, 0, sizeof(torso) );\n\tmemset( &head, 0, sizeof(head) );\n\n\trefdef.rdflags = RDF_NOWORLDMODEL;\n\n\tAxisClear( refdef.viewaxis );\n\n\trefdef.x = x;\n\trefdef.y = y;\n\trefdef.width = w;\n\trefdef.height = h;\n\n\trefdef.fov_x = (int)((float)refdef.width / 640.0f * 90.0f);\n\txx = refdef.width / tan( refdef.fov_x / 360 * M_PI );\n\trefdef.fov_y = atan2( refdef.height, xx );\n\trefdef.fov_y *= ( 360 / M_PI );\n\n\t// calculate distance so the player nearly fills the box\n\tlen = 0.7 * ( maxs[2] - mins[2] );\t\t\n\torigin[0] = len / tan( DEG2RAD(refdef.fov_x) * 0.5 );\n\torigin[1] = 0.5 * ( mins[1] + maxs[1] );\n\torigin[2] = -0.5 * ( mins[2] + maxs[2] );\n\n\trefdef.time = dp_realtime;\n\n\ttrap_R_ClearScene();\n\n\t// get the rotation information\n\tUI_PlayerAngles( pi, legs.axis, torso.axis, head.axis );\n\t\n\t// get the animation state (after rotation, to allow feet shuffle)\n\tUI_PlayerAnimation( pi, &legs.oldframe, &legs.frame, &legs.backlerp,\n\t\t &torso.oldframe, &torso.frame, &torso.backlerp );\n\n\trenderfx = RF_LIGHTING_ORIGIN | RF_NOSHADOW;\n\n\t//\n\t// add the legs\n\t//\n\tlegs.hModel = pi->legsModel;\n\tlegs.customSkin = pi->legsSkin;\n\n\tVectorCopy( origin, legs.origin );\n\n\tVectorCopy( origin, legs.lightingOrigin );\n\tlegs.renderfx = renderfx;\n\tVectorCopy (legs.origin, legs.oldorigin);\n\n\ttrap_R_AddRefEntityToScene( &legs );\n\n\tif (!legs.hModel) {\n\t\treturn;\n\t}\n\n\t//\n\t// add the torso\n\t//\n\ttorso.hModel = pi->torsoModel;\n\tif (!torso.hModel) {\n\t\treturn;\n\t}\n\n\ttorso.customSkin = pi->torsoSkin;\n\n\tVectorCopy( origin, torso.lightingOrigin );\n\n\tUI_PositionRotatedEntityOnTag( &torso, &legs, pi->legsModel, \"tag_torso\");\n\n\ttorso.renderfx = renderfx;\n\n\ttrap_R_AddRefEntityToScene( &torso );\n\n\t//\n\t// add the head\n\t//\n\thead.hModel = pi->headModel;\n\tif (!head.hModel) {\n\t\treturn;\n\t}\n\thead.customSkin = pi->headSkin;\n\n\tVectorCopy( origin, head.lightingOrigin );\n\n\tUI_PositionRotatedEntityOnTag( &head, &torso, pi->torsoModel, \"tag_head\");\n\n\thead.renderfx = renderfx;\n\n\ttrap_R_AddRefEntityToScene( &head );\n\n\t//\n\t// add the gun\n\t//\n\tif ( pi->currentWeapon != WP_NONE ) {\n\t\tmemset( &gun, 0, sizeof(gun) );\n\t\tgun.hModel = pi->weaponModel;\n\t\tVectorCopy( origin, gun.lightingOrigin );\n\t\tUI_PositionEntityOnTag( &gun, &torso, pi->torsoModel, \"tag_weapon\");\n\t\tgun.renderfx = renderfx;\n\t\ttrap_R_AddRefEntityToScene( &gun );\n\t}\n\n\t//\n\t// add the spinning barrel\n\t//\n\tif ( pi->realWeapon == WP_MACHINEGUN || pi->realWeapon == WP_GAUNTLET || pi->realWeapon == WP_BFG ) {\n\t\tvec3_t\tangles;\n\n\t\tmemset( &barrel, 0, sizeof(barrel) );\n\t\tVectorCopy( origin, barrel.lightingOrigin );\n\t\tbarrel.renderfx = renderfx;\n\n\t\tbarrel.hModel = pi->barrelModel;\n\t\tangles[YAW] = 0;\n\t\tangles[PITCH] = 0;\n\t\tangles[ROLL] = UI_MachinegunSpinAngle( pi );\n\t\tif( pi->realWeapon == WP_GAUNTLET || pi->realWeapon == WP_BFG ) {\n\t\t\tangles[PITCH] = angles[ROLL];\n\t\t\tangles[ROLL] = 0;\n\t\t}\n\t\tAnglesToAxis( angles, barrel.axis );\n\n\t\tUI_PositionRotatedEntityOnTag( &barrel, &gun, pi->weaponModel, \"tag_barrel\");\n\n\t\ttrap_R_AddRefEntityToScene( &barrel );\n\t}\n\n\t//\n\t// add muzzle flash\n\t//\n\tif ( dp_realtime <= pi->muzzleFlashTime ) {\n\t\tif ( pi->flashModel ) {\n\t\t\tmemset( &flash, 0, sizeof(flash) );\n\t\t\tflash.hModel = pi->flashModel;\n\t\t\tVectorCopy( origin, flash.lightingOrigin );\n\t\t\tUI_PositionEntityOnTag( &flash, &gun, pi->weaponModel, \"tag_flash\");\n\t\t\tflash.renderfx = renderfx;\n\t\t\ttrap_R_AddRefEntityToScene( &flash );\n\t\t}\n\n\t\t// make a dlight for the flash\n\t\tif ( pi->flashDlightColor[0] || pi->flashDlightColor[1] || pi->flashDlightColor[2] ) {\n\t\t\ttrap_R_AddLightToScene( flash.origin, 200 + (rand()&31), pi->flashDlightColor[0],\n\t\t\t\tpi->flashDlightColor[1], pi->flashDlightColor[2] );\n\t\t}\n\t}\n\n\t//\n\t// add the chat icon\n\t//\n\tif ( pi->chat ) {\n\t\tUI_PlayerFloatSprite( pi, origin, trap_R_RegisterShaderNoMip( \"sprites/balloon3\" ) );\n\t}\n\n\t//\n\t// add an accent light\n\t//\n\torigin[0] -= 100;\t// + = behind, - = in front\n\torigin[1] += 100;\t// + = left, - = right\n\torigin[2] += 100;\t// + = above, - = below\n\ttrap_R_AddLightToScene( origin, 500, 1.0, 1.0, 1.0 );\n\n\torigin[0] -= 100;\n\torigin[1] -= 100;\n\torigin[2] -= 100;\n\ttrap_R_AddLightToScene( origin, 500, 1.0, 0.0, 0.0 );\n\n\ttrap_R_RenderScene( &refdef );\n}\n\n\n/*\n==========================\nUI_RegisterClientSkin\n==========================\n*/\nstatic qboolean UI_RegisterClientSkin( playerInfo_t *pi, const char *modelName, const char *skinName ) {\n\tchar\t\tfilename[MAX_QPATH];\n\n\tCom_sprintf( filename, sizeof( filename ), \"models/players/%s/lower_%s.skin\", modelName, skinName );\n\tpi->legsSkin = trap_R_RegisterSkin( filename );\n\n\tCom_sprintf( filename, sizeof( filename ), \"models/players/%s/upper_%s.skin\", modelName, skinName );\n\tpi->torsoSkin = trap_R_RegisterSkin( filename );\n\n\tCom_sprintf( filename, sizeof( filename ), \"models/players/%s/head_%s.skin\", modelName, skinName );\n\tpi->headSkin = trap_R_RegisterSkin( filename );\n\n\tif ( !pi->legsSkin || !pi->torsoSkin || !pi->headSkin ) {\n\t\treturn qfalse;\n\t}\n\n\treturn qtrue;\n}\n\n\n/*\n======================\nUI_ParseAnimationFile\n======================\n*/\nstatic qboolean UI_ParseAnimationFile( const char *filename, animation_t *animations ) {\n\tchar\t\t*text_p, *prev;\n\tint\t\t\tlen;\n\tint\t\t\ti;\n\tchar\t\t*token;\n\tfloat\t\tfps;\n\tint\t\t\tskip;\n\tchar\t\ttext[20000];\n\tfileHandle_t\tf;\n\n\tmemset( animations, 0, sizeof( animation_t ) * MAX_ANIMATIONS );\n\n\t// load the file\n\tlen = trap_FS_FOpenFile( filename, &f, FS_READ );\n\tif ( len <= 0 ) {\n\t\treturn qfalse;\n\t}\n\tif ( len >= ( sizeof( text ) - 1 ) ) {\n\t\tCom_Printf( \"File %s too long\\n\", filename );\n\t\treturn qfalse;\n\t}\n\ttrap_FS_Read( text, len, f );\n\ttext[len] = 0;\n\ttrap_FS_FCloseFile( f );\n\n\t// parse the text\n\ttext_p = text;\n\tskip = 0;\t// quite the compiler warning\n\n\t// read optional parameters\n\twhile ( 1 ) {\n\t\tprev = text_p;\t// so we can unget\n\t\ttoken = COM_Parse( &text_p );\n\t\tif ( !token ) {\n\t\t\tbreak;\n\t\t}\n\t\tif ( !Q_stricmp( token, \"footsteps\" ) ) {\n\t\t\ttoken = COM_Parse( &text_p );\n\t\t\tif ( !token ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcontinue;\n\t\t} else if ( !Q_stricmp( token, \"headoffset\" ) ) {\n\t\t\tfor ( i = 0 ; i < 3 ; i++ ) {\n\t\t\t\ttoken = COM_Parse( &text_p );\n\t\t\t\tif ( !token ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcontinue;\n\t\t} else if ( !Q_stricmp( token, \"sex\" ) ) {\n\t\t\ttoken = COM_Parse( &text_p );\n\t\t\tif ( !token ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\t// if it is a number, start parsing animations\n\t\tif ( token[0] >= '0' && token[0] <= '9' ) {\n\t\t\ttext_p = prev;\t// unget the token\n\t\t\tbreak;\n\t\t}\n\n\t\tCom_Printf( \"unknown token '%s' is %s\\n\", token, filename );\n\t}\n\n\t// read information for each frame\n\tfor ( i = 0 ; i < MAX_ANIMATIONS ; i++ ) {\n\n\t\ttoken = COM_Parse( &text_p );\n\t\tif ( !token ) {\n\t\t\tbreak;\n\t\t}\n\t\tanimations[i].firstFrame = atoi( token );\n\t\t// leg only frames are adjusted to not count the upper body only frames\n\t\tif ( i == LEGS_WALKCR ) {\n\t\t\tskip = animations[LEGS_WALKCR].firstFrame - animations[TORSO_GESTURE].firstFrame;\n\t\t}\n\t\tif ( i >= LEGS_WALKCR ) {\n\t\t\tanimations[i].firstFrame -= skip;\n\t\t}\n\n\t\ttoken = COM_Parse( &text_p );\n\t\tif ( !token ) {\n\t\t\tbreak;\n\t\t}\n\t\tanimations[i].numFrames = atoi( token );\n\n\t\ttoken = COM_Parse( &text_p );\n\t\tif ( !token ) {\n\t\t\tbreak;\n\t\t}\n\t\tanimations[i].loopFrames = atoi( token );\n\n\t\ttoken = COM_Parse( &text_p );\n\t\tif ( !token ) {\n\t\t\tbreak;\n\t\t}\n\t\tfps = atof( token );\n\t\tif ( fps == 0 ) {\n\t\t\tfps = 1;\n\t\t}\n\t\tanimations[i].frameLerp = 1000 / fps;\n\t\tanimations[i].initialLerp = 1000 / fps;\n\t}\n\n\tif ( i != MAX_ANIMATIONS ) {\n\t\tCom_Printf( \"Error parsing animation file: %s\", filename );\n\t\treturn qfalse;\n\t}\n\n\treturn qtrue;\n}\n\n\n/*\n==========================\nUI_RegisterClientModelname\n==========================\n*/\nqboolean UI_RegisterClientModelname( playerInfo_t *pi, const char *modelSkinName ) {\n\tchar\t\tmodelName[MAX_QPATH];\n\tchar\t\tskinName[MAX_QPATH];\n\tchar\t\tfilename[MAX_QPATH];\n\tchar\t\t*slash;\n\n\tpi->torsoModel = 0;\n\tpi->headModel = 0;\n\n\tif ( !modelSkinName[0] ) {\n\t\treturn qfalse;\n\t}\n\n\tQ_strncpyz( modelName, modelSkinName, sizeof( modelName ) );\n\n\tslash = strchr( modelName, '/' );\n\tif ( !slash ) {\n\t\t// modelName did not include a skin name\n\t\tQ_strncpyz( skinName, \"default\", sizeof( skinName ) );\n\t} else {\n\t\tQ_strncpyz( skinName, slash + 1, sizeof( skinName ) );\n\t\t// truncate modelName\n\t\t*slash = 0;\n\t}\n\n\t// load cmodels before models so filecache works\n\n\tCom_sprintf( filename, sizeof( filename ), \"models/players/%s/lower.md3\", modelName );\n\tpi->legsModel = trap_R_RegisterModel( filename );\n\tif ( !pi->legsModel ) {\n\t\tCom_Printf( \"Failed to load model file %s\\n\", filename );\n\t\treturn qfalse;\n\t}\n\n\tCom_sprintf( filename, sizeof( filename ), \"models/players/%s/upper.md3\", modelName );\n\tpi->torsoModel = trap_R_RegisterModel( filename );\n\tif ( !pi->torsoModel ) {\n\t\tCom_Printf( \"Failed to load model file %s\\n\", filename );\n\t\treturn qfalse;\n\t}\n\n\tCom_sprintf( filename, sizeof( filename ), \"models/players/%s/head.md3\", modelName );\n\tpi->headModel = trap_R_RegisterModel( filename );\n\tif ( !pi->headModel ) {\n\t\tCom_Printf( \"Failed to load model file %s\\n\", filename );\n\t\treturn qfalse;\n\t}\n\n\t// if any skins failed to load, fall back to default\n\tif ( !UI_RegisterClientSkin( pi, modelName, skinName ) ) {\n\t\tif ( !UI_RegisterClientSkin( pi, modelName, \"default\" ) ) {\n\t\t\tCom_Printf( \"Failed to load skin file: %s : %s\\n\", modelName, skinName );\n\t\t\treturn qfalse;\n\t\t}\n\t}\n\n\t// load the animations\n\tCom_sprintf( filename, sizeof( filename ), \"models/players/%s/animation.cfg\", modelName );\n\tif ( !UI_ParseAnimationFile( filename, pi->animations ) ) {\n\t\tCom_Printf( \"Failed to load animation file %s\\n\", filename );\n\t\treturn qfalse;\n\t}\n\n\treturn qtrue;\n}\n\n\n/*\n===============\nUI_PlayerInfo_SetModel\n===============\n*/\nvoid UI_PlayerInfo_SetModel( playerInfo_t *pi, const char *model ) {\n\tmemset( pi, 0, sizeof(*pi) );\n\tUI_RegisterClientModelname( pi, model );\n\tpi->weapon = WP_MACHINEGUN;\n\tpi->currentWeapon = pi->weapon;\n\tpi->lastWeapon = pi->weapon;\n\tpi->pendingWeapon = -1;\n\tpi->weaponTimer = 0;\n\tpi->chat = qfalse;\n\tpi->newModel = qtrue;\n\tUI_PlayerInfo_SetWeapon( pi, pi->weapon );\n}\n\n\n/*\n===============\nUI_PlayerInfo_SetInfo\n===============\n*/\nvoid UI_PlayerInfo_SetInfo( playerInfo_t *pi, int legsAnim, int torsoAnim, vec3_t viewAngles, vec3_t moveAngles, weapon_t weaponNumber, qboolean chat ) {\n\tint\t\t\tcurrentAnim;\n\tweapon_t\tweaponNum;\n\n\tpi->chat = chat;\n\n\t// view angles\n\tVectorCopy( viewAngles, pi->viewAngles );\n\n\t// move angles\n\tVectorCopy( moveAngles, pi->moveAngles );\n\n\tif ( pi->newModel ) {\n\t\tpi->newModel = qfalse;\n\n\t\tjumpHeight = 0;\n\t\tpi->pendingLegsAnim = 0;\n\t\tUI_ForceLegsAnim( pi, legsAnim );\n\t\tpi->legs.yawAngle = viewAngles[YAW];\n\t\tpi->legs.yawing = qfalse;\n\n\t\tpi->pendingTorsoAnim = 0;\n\t\tUI_ForceTorsoAnim( pi, torsoAnim );\n\t\tpi->torso.yawAngle = viewAngles[YAW];\n\t\tpi->torso.yawing = qfalse;\n\n\t\tif ( weaponNumber != -1 ) {\n\t\t\tpi->weapon = weaponNumber;\n\t\t\tpi->currentWeapon = weaponNumber;\n\t\t\tpi->lastWeapon = weaponNumber;\n\t\t\tpi->pendingWeapon = -1;\n\t\t\tpi->weaponTimer = 0;\n\t\t\tUI_PlayerInfo_SetWeapon( pi, pi->weapon );\n\t\t}\n\n\t\treturn;\n\t}\n\n\t// weapon\n\tif ( weaponNumber == -1 ) {\n\t\tpi->pendingWeapon = -1;\n\t\tpi->weaponTimer = 0;\n\t}\n\telse if ( weaponNumber != WP_NONE ) {\n\t\tpi->pendingWeapon = weaponNumber;\n\t\tpi->weaponTimer = dp_realtime + UI_TIMER_WEAPON_DELAY;\n\t}\n\tweaponNum = pi->lastWeapon;\n\tpi->weapon = weaponNum;\n\n\tif ( torsoAnim == BOTH_DEATH1 || legsAnim == BOTH_DEATH1 ) {\n\t\ttorsoAnim = legsAnim = BOTH_DEATH1;\n\t\tpi->weapon = pi->currentWeapon = WP_NONE;\n\t\tUI_PlayerInfo_SetWeapon( pi, pi->weapon );\n\n\t\tjumpHeight = 0;\n\t\tpi->pendingLegsAnim = 0;\n\t\tUI_ForceLegsAnim( pi, legsAnim );\n\n\t\tpi->pendingTorsoAnim = 0;\n\t\tUI_ForceTorsoAnim( pi, torsoAnim );\n\n\t\treturn;\n\t}\n\n\t// leg animation\n\tcurrentAnim = pi->legsAnim & ~ANIM_TOGGLEBIT;\n\tif ( legsAnim != LEGS_JUMP && ( currentAnim == LEGS_JUMP || currentAnim == LEGS_LAND ) ) {\n\t\tpi->pendingLegsAnim = legsAnim;\n\t}\n\telse if ( legsAnim != currentAnim ) {\n\t\tjumpHeight = 0;\n\t\tpi->pendingLegsAnim = 0;\n\t\tUI_ForceLegsAnim( pi, legsAnim );\n\t}\n\n\t// torso animation\n\tif ( torsoAnim == TORSO_STAND || torsoAnim == TORSO_STAND2 ) {\n\t\tif ( weaponNum == WP_NONE || weaponNum == WP_GAUNTLET ) {\n\t\t\ttorsoAnim = TORSO_STAND2;\n\t\t}\n\t\telse {\n\t\t\ttorsoAnim = TORSO_STAND;\n\t\t}\n\t}\n\n\tif ( torsoAnim == TORSO_ATTACK || torsoAnim == TORSO_ATTACK2 ) {\n\t\tif ( weaponNum == WP_NONE || weaponNum == WP_GAUNTLET ) {\n\t\t\ttorsoAnim = TORSO_ATTACK2;\n\t\t}\n\t\telse {\n\t\t\ttorsoAnim = TORSO_ATTACK;\n\t\t}\n\t\tpi->muzzleFlashTime = dp_realtime + UI_TIMER_MUZZLE_FLASH;\n\t\t//FIXME play firing sound here\n\t}\n\n\tcurrentAnim = pi->torsoAnim & ~ANIM_TOGGLEBIT;\n\n\tif ( weaponNum != pi->currentWeapon || currentAnim == TORSO_RAISE || currentAnim == TORSO_DROP ) {\n\t\tpi->pendingTorsoAnim = torsoAnim;\n\t}\n\telse if ( ( currentAnim == TORSO_GESTURE || currentAnim == TORSO_ATTACK ) && ( torsoAnim != currentAnim ) ) {\n\t\tpi->pendingTorsoAnim = torsoAnim;\n\t}\n\telse if ( torsoAnim != currentAnim ) {\n\t\tpi->pendingTorsoAnim = 0;\n\t\tUI_ForceTorsoAnim( pi, torsoAnim );\n\t}\n}\n"
  },
  {
    "path": "src/q3_ui/ui_playersettings.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n#include \"ui_local.h\"\n\n#define ART_FRAMEL\t\t\t\"menu/art/frame2_l\"\n#define ART_FRAMER\t\t\t\"menu/art/frame1_r\"\n#define ART_MODEL0\t\t\t\"menu/art/model_0\"\n#define ART_MODEL1\t\t\t\"menu/art/model_1\"\n#define ART_BACK0\t\t\t\"menu/art/back_0\"\n#define ART_BACK1\t\t\t\"menu/art/back_1\"\n#define ART_FX_BASE\t\t\t\"menu/art/fx_base\"\n#define ART_FX_BLUE\t\t\t\"menu/art/fx_blue\"\n#define ART_FX_CYAN\t\t\t\"menu/art/fx_cyan\"\n#define ART_FX_GREEN\t\t\"menu/art/fx_grn\"\n#define ART_FX_RED\t\t\t\"menu/art/fx_red\"\n#define ART_FX_TEAL\t\t\t\"menu/art/fx_teal\"\n#define ART_FX_WHITE\t\t\"menu/art/fx_white\"\n#define ART_FX_YELLOW\t\t\"menu/art/fx_yel\"\n\n#define ID_NAME\t\t\t10\n#define ID_HANDICAP\t\t11\n#define ID_EFFECTS\t\t12\n#define ID_BACK\t\t\t13\n#define ID_MODEL\t\t14\n\n#define MAX_NAMELENGTH\t20\n\n\ntypedef struct {\n\tmenuframework_s\t\tmenu;\n\n\tmenutext_s\t\t\tbanner;\n\tmenubitmap_s\t\tframel;\n\tmenubitmap_s\t\tframer;\n\tmenubitmap_s\t\tplayer;\n\n\tmenufield_s\t\t\tname;\n\tmenulist_s\t\t\thandicap;\n\tmenulist_s\t\t\teffects;\n\n\tmenubitmap_s\t\tback;\n\tmenubitmap_s\t\tmodel;\n\tmenubitmap_s\t\titem_null;\n\n\tqhandle_t\t\t\tfxBasePic;\n\tqhandle_t\t\t\tfxPic[7];\n\tplayerInfo_t\t\tplayerinfo;\n\tint\t\t\t\t\tcurrent_fx;\n\tchar\t\t\t\tplayerModel[MAX_QPATH];\n} playersettings_t;\n\nstatic playersettings_t\ts_playersettings;\n\nstatic int gamecodetoui[] = {4,2,3,0,5,1,6};\nstatic int uitogamecode[] = {4,6,2,3,1,5,7};\n\nstatic const char *handicap_items[] = {\n\t\"None\",\n\t\"95\",\n\t\"90\",\n\t\"85\",\n\t\"80\",\n\t\"75\",\n\t\"70\",\n\t\"65\",\n\t\"60\",\n\t\"55\",\n\t\"50\",\n\t\"45\",\n\t\"40\",\n\t\"35\",\n\t\"30\",\n\t\"25\",\n\t\"20\",\n\t\"15\",\n\t\"10\",\n\t\"5\",\n\t0\n};\n\n\n/*\n=================\nPlayerSettings_DrawName\n=================\n*/\nstatic void PlayerSettings_DrawName( void *self ) {\n\tmenufield_s\t\t*f;\n\tqboolean\t\tfocus;\n\tint\t\t\t\tstyle;\n\tchar\t\t\t*txt;\n\tchar\t\t\tc;\n\tfloat\t\t\t*color;\n\tint\t\t\t\tn;\n\tint\t\t\t\tbasex, x, y;\n\tchar\t\t\tname[32];\n\n\tf = (menufield_s*)self;\n\tbasex = f->generic.x;\n\ty = f->generic.y;\n\tfocus = (f->generic.parent->cursor == f->generic.menuPosition);\n\n\tstyle = UI_LEFT|UI_SMALLFONT;\n\tcolor = text_color_normal;\n\tif( focus ) {\n\t\tstyle |= UI_PULSE;\n\t\tcolor = text_color_highlight;\n\t}\n\n\tUI_DrawProportionalString( basex, y, \"Name\", style, color );\n\n\t// draw the actual name\n\tbasex += 64;\n\ty += PROP_HEIGHT;\n\ttxt = f->field.buffer;\n\tcolor = g_color_table[ColorIndex(COLOR_WHITE)];\n\tx = basex;\n\twhile ( (c = *txt) != 0 ) {\n\t\tif ( !focus && Q_IsColorString( txt ) ) {\n\t\t\tn = ColorIndex( *(txt+1) );\n\t\t\tif( n == 0 ) {\n\t\t\t\tn = 7;\n\t\t\t}\n\t\t\tcolor = g_color_table[n];\n\t\t\ttxt += 2;\n\t\t\tcontinue;\n\t\t}\n\t\tUI_DrawChar( x, y, c, style, color );\n\t\ttxt++;\n\t\tx += SMALLCHAR_WIDTH;\n\t}\n\n\t// draw cursor if we have focus\n\tif( focus ) {\n\t\tif ( trap_Key_GetOverstrikeMode() ) {\n\t\t\tc = 11;\n\t\t} else {\n\t\t\tc = 10;\n\t\t}\n\n\t\tstyle &= ~UI_PULSE;\n\t\tstyle |= UI_BLINK;\n\n\t\tUI_DrawChar( basex + f->field.cursor * SMALLCHAR_WIDTH, y, c, style, color_white );\n\t}\n\n\t// draw at bottom also using proportional font\n\tQ_strncpyz( name, f->field.buffer, sizeof(name) );\n\tQ_CleanStr( name );\n\tUI_DrawProportionalString( 320, 440, name, UI_CENTER|UI_BIGFONT, text_color_normal );\n}\n\n\n/*\n=================\nPlayerSettings_DrawHandicap\n=================\n*/\nstatic void PlayerSettings_DrawHandicap( void *self ) {\n\tmenulist_s\t\t*item;\n\tqboolean\t\tfocus;\n\tint\t\t\t\tstyle;\n\tfloat\t\t\t*color;\n\n\titem = (menulist_s *)self;\n\tfocus = (item->generic.parent->cursor == item->generic.menuPosition);\n\n\tstyle = UI_LEFT|UI_SMALLFONT;\n\tcolor = text_color_normal;\n\tif( focus ) {\n\t\tstyle |= UI_PULSE;\n\t\tcolor = text_color_highlight;\n\t}\n\n\tUI_DrawProportionalString( item->generic.x, item->generic.y, \"Handicap\", style, color );\n\tUI_DrawProportionalString( item->generic.x + 64, item->generic.y + PROP_HEIGHT, handicap_items[item->curvalue], style, color );\n}\n\n\n/*\n=================\nPlayerSettings_DrawEffects\n=================\n*/\nstatic void PlayerSettings_DrawEffects( void *self ) {\n\tmenulist_s\t\t*item;\n\tqboolean\t\tfocus;\n\tint\t\t\t\tstyle;\n\tfloat\t\t\t*color;\n\n\titem = (menulist_s *)self;\n\tfocus = (item->generic.parent->cursor == item->generic.menuPosition);\n\n\tstyle = UI_LEFT|UI_SMALLFONT;\n\tcolor = text_color_normal;\n\tif( focus ) {\n\t\tstyle |= UI_PULSE;\n\t\tcolor = text_color_highlight;\n\t}\n\n\tUI_DrawProportionalString( item->generic.x, item->generic.y, \"Effects\", style, color );\n\n\tUI_DrawHandlePic( item->generic.x + 64, item->generic.y + PROP_HEIGHT + 8, 128, 8, s_playersettings.fxBasePic );\n\tUI_DrawHandlePic( item->generic.x + 64 + item->curvalue * 16 + 8, item->generic.y + PROP_HEIGHT + 6, 16, 12, s_playersettings.fxPic[item->curvalue] );\n}\n\n\n/*\n=================\nPlayerSettings_DrawPlayer\n=================\n*/\nstatic void PlayerSettings_DrawPlayer( void *self ) {\n\tmenubitmap_s\t*b;\n\tvec3_t\t\t\tviewangles;\n\tchar\t\t\tbuf[MAX_QPATH];\n\n\ttrap_Cvar_VariableStringBuffer( \"model\", buf, sizeof( buf ) );\n\tif ( strcmp( buf, s_playersettings.playerModel ) != 0 ) {\n\t\tUI_PlayerInfo_SetModel( &s_playersettings.playerinfo, buf );\n\t\tstrcpy( s_playersettings.playerModel, buf );\n\n\t\tviewangles[YAW]   = 180 - 30;\n\t\tviewangles[PITCH] = 0;\n\t\tviewangles[ROLL]  = 0;\n\t\tUI_PlayerInfo_SetInfo( &s_playersettings.playerinfo, LEGS_IDLE, TORSO_STAND, viewangles, vec3_origin, WP_MACHINEGUN, qfalse );\n\t}\n\n\tb = (menubitmap_s*) self;\n\tUI_DrawPlayer( b->generic.x, b->generic.y, b->width, b->height, &s_playersettings.playerinfo, uis.realtime/2 );\n}\n\n\n/*\n=================\nPlayerSettings_SaveChanges\n=================\n*/\nstatic void PlayerSettings_SaveChanges( void ) {\n\t// name\n\ttrap_Cvar_Set( \"name\", s_playersettings.name.field.buffer );\n\n\t// handicap\n\ttrap_Cvar_SetValue( \"handicap\", 100 - s_playersettings.handicap.curvalue * 5 );\n\n\t// effects color\n\ttrap_Cvar_SetValue( \"color1\", uitogamecode[s_playersettings.effects.curvalue] );\n}\n\n\n/*\n=================\nPlayerSettings_MenuKey\n=================\n*/\nstatic sfxHandle_t PlayerSettings_MenuKey( int key ) {\n\tif( key == K_MOUSE2 || key == K_ESCAPE ) {\n\t\tPlayerSettings_SaveChanges();\n\t}\n\treturn Menu_DefaultKey( &s_playersettings.menu, key );\n}\n\n\n/*\n=================\nPlayerSettings_SetMenuItems\n=================\n*/\nstatic void PlayerSettings_SetMenuItems( void ) {\n\tvec3_t\tviewangles;\n\tint\t\tc;\n\tint\t\th;\n\n\t// name\n\tQ_strncpyz( s_playersettings.name.field.buffer, UI_Cvar_VariableString(\"name\"), sizeof(s_playersettings.name.field.buffer) );\n\n\t// effects color\n\tc = trap_Cvar_VariableValue( \"color1\" ) - 1;\n\tif( c < 0 || c > 6 ) {\n\t\tc = 6;\n\t}\n\ts_playersettings.effects.curvalue = gamecodetoui[c];\n\n\t// model/skin\n\tmemset( &s_playersettings.playerinfo, 0, sizeof(playerInfo_t) );\n\t\n\tviewangles[YAW]   = 180 - 30;\n\tviewangles[PITCH] = 0;\n\tviewangles[ROLL]  = 0;\n\n\tUI_PlayerInfo_SetModel( &s_playersettings.playerinfo, UI_Cvar_VariableString( \"model\" ) );\n\tUI_PlayerInfo_SetInfo( &s_playersettings.playerinfo, LEGS_IDLE, TORSO_STAND, viewangles, vec3_origin, WP_MACHINEGUN, qfalse );\n\n\t// handicap\n\th = Com_Clamp( 5, 100, trap_Cvar_VariableValue(\"handicap\") );\n\ts_playersettings.handicap.curvalue = 20 - h / 5;\n}\n\n\n/*\n=================\nPlayerSettings_MenuEvent\n=================\n*/\nstatic void PlayerSettings_MenuEvent( void* ptr, int event ) {\n\tif( event != QM_ACTIVATED ) {\n\t\treturn;\n\t}\n\n\tswitch( ((menucommon_s*)ptr)->id ) {\n\tcase ID_HANDICAP:\n\t\ttrap_Cvar_Set( \"handicap\", va( \"%i\", 100 - 25 * s_playersettings.handicap.curvalue ) );\n\t\tbreak;\n\n\tcase ID_MODEL:\n\t\tPlayerSettings_SaveChanges();\n\t\tUI_PlayerModelMenu();\n\t\tbreak;\n\n\tcase ID_BACK:\n\t\tPlayerSettings_SaveChanges();\n\t\tUI_PopMenu();\n\t\tbreak;\n\t}\n}\n\n\n/*\n=================\nPlayerSettings_MenuInit\n=================\n*/\nstatic void PlayerSettings_MenuInit( void ) {\n\tint\t\ty;\n\n\tmemset(&s_playersettings,0,sizeof(playersettings_t));\n\n\tPlayerSettings_Cache();\n\n\ts_playersettings.menu.key        = PlayerSettings_MenuKey;\n\ts_playersettings.menu.wrapAround = qtrue;\n\ts_playersettings.menu.fullscreen = qtrue;\n\n\ts_playersettings.banner.generic.type  = MTYPE_BTEXT;\n\ts_playersettings.banner.generic.x     = 320;\n\ts_playersettings.banner.generic.y     = 16;\n\ts_playersettings.banner.string        = \"PLAYER SETTINGS\";\n\ts_playersettings.banner.color         = color_white;\n\ts_playersettings.banner.style         = UI_CENTER;\n\n\ts_playersettings.framel.generic.type  = MTYPE_BITMAP;\n\ts_playersettings.framel.generic.name  = ART_FRAMEL;\n\ts_playersettings.framel.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;\n\ts_playersettings.framel.generic.x     = 0;\n\ts_playersettings.framel.generic.y     = 78;\n\ts_playersettings.framel.width         = 256;\n\ts_playersettings.framel.height        = 329;\n\n\ts_playersettings.framer.generic.type  = MTYPE_BITMAP;\n\ts_playersettings.framer.generic.name  = ART_FRAMER;\n\ts_playersettings.framer.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;\n\ts_playersettings.framer.generic.x     = 376;\n\ts_playersettings.framer.generic.y     = 76;\n\ts_playersettings.framer.width         = 256;\n\ts_playersettings.framer.height        = 334;\n\n\ty = 144;\n\ts_playersettings.name.generic.type\t\t\t= MTYPE_FIELD;\n\ts_playersettings.name.generic.flags\t\t\t= QMF_NODEFAULTINIT;\n\ts_playersettings.name.generic.ownerdraw\t\t= PlayerSettings_DrawName;\n\ts_playersettings.name.field.widthInChars\t= MAX_NAMELENGTH;\n\ts_playersettings.name.field.maxchars\t\t= MAX_NAMELENGTH;\n\ts_playersettings.name.generic.x\t\t\t\t= 192;\n\ts_playersettings.name.generic.y\t\t\t\t= y;\n\ts_playersettings.name.generic.left\t\t\t= 192 - 8;\n\ts_playersettings.name.generic.top\t\t\t= y - 8;\n\ts_playersettings.name.generic.right\t\t\t= 192 + 200;\n\ts_playersettings.name.generic.bottom\t\t= y + 2 * PROP_HEIGHT;\n\n\ty += 3 * PROP_HEIGHT;\n\ts_playersettings.handicap.generic.type\t\t= MTYPE_SPINCONTROL;\n\ts_playersettings.handicap.generic.flags\t\t= QMF_NODEFAULTINIT;\n\ts_playersettings.handicap.generic.id\t\t= ID_HANDICAP;\n\ts_playersettings.handicap.generic.ownerdraw\t= PlayerSettings_DrawHandicap;\n\ts_playersettings.handicap.generic.x\t\t\t= 192;\n\ts_playersettings.handicap.generic.y\t\t\t= y;\n\ts_playersettings.handicap.generic.left\t\t= 192 - 8;\n\ts_playersettings.handicap.generic.top\t\t= y - 8;\n\ts_playersettings.handicap.generic.right\t\t= 192 + 200;\n\ts_playersettings.handicap.generic.bottom\t= y + 2 * PROP_HEIGHT;\n\ts_playersettings.handicap.numitems\t\t\t= 20;\n\n\ty += 3 * PROP_HEIGHT;\n\ts_playersettings.effects.generic.type\t\t= MTYPE_SPINCONTROL;\n\ts_playersettings.effects.generic.flags\t\t= QMF_NODEFAULTINIT;\n\ts_playersettings.effects.generic.id\t\t\t= ID_EFFECTS;\n\ts_playersettings.effects.generic.ownerdraw\t= PlayerSettings_DrawEffects;\n\ts_playersettings.effects.generic.x\t\t\t= 192;\n\ts_playersettings.effects.generic.y\t\t\t= y;\n\ts_playersettings.effects.generic.left\t\t= 192 - 8;\n\ts_playersettings.effects.generic.top\t\t= y - 8;\n\ts_playersettings.effects.generic.right\t\t= 192 + 200;\n\ts_playersettings.effects.generic.bottom\t\t= y + 2* PROP_HEIGHT;\n\ts_playersettings.effects.numitems\t\t\t= 7;\n\n\ts_playersettings.model.generic.type\t\t\t= MTYPE_BITMAP;\n\ts_playersettings.model.generic.name\t\t\t= ART_MODEL0;\n\ts_playersettings.model.generic.flags\t\t= QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_playersettings.model.generic.id\t\t\t= ID_MODEL;\n\ts_playersettings.model.generic.callback\t\t= PlayerSettings_MenuEvent;\n\ts_playersettings.model.generic.x\t\t\t= 640;\n\ts_playersettings.model.generic.y\t\t\t= 480-64;\n\ts_playersettings.model.width\t\t\t\t= 128;\n\ts_playersettings.model.height\t\t\t\t= 64;\n\ts_playersettings.model.focuspic\t\t\t\t= ART_MODEL1;\n\n\ts_playersettings.player.generic.type\t\t= MTYPE_BITMAP;\n\ts_playersettings.player.generic.flags\t\t= QMF_INACTIVE;\n\ts_playersettings.player.generic.ownerdraw\t= PlayerSettings_DrawPlayer;\n\ts_playersettings.player.generic.x\t\t\t= 400;\n\ts_playersettings.player.generic.y\t\t\t= -40;\n\ts_playersettings.player.width\t\t\t\t= 32*10;\n\ts_playersettings.player.height\t\t\t\t= 56*10;\n\n\ts_playersettings.back.generic.type\t\t\t= MTYPE_BITMAP;\n\ts_playersettings.back.generic.name\t\t\t= ART_BACK0;\n\ts_playersettings.back.generic.flags\t\t\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_playersettings.back.generic.id\t\t\t= ID_BACK;\n\ts_playersettings.back.generic.callback\t\t= PlayerSettings_MenuEvent;\n\ts_playersettings.back.generic.x\t\t\t\t= 0;\n\ts_playersettings.back.generic.y\t\t\t\t= 480-64;\n\ts_playersettings.back.width\t\t\t\t\t= 128;\n\ts_playersettings.back.height\t\t\t\t= 64;\n\ts_playersettings.back.focuspic\t\t\t\t= ART_BACK1;\n\n\ts_playersettings.item_null.generic.type\t\t= MTYPE_BITMAP;\n\ts_playersettings.item_null.generic.flags\t= QMF_LEFT_JUSTIFY|QMF_MOUSEONLY|QMF_SILENT;\n\ts_playersettings.item_null.generic.x\t\t= 0;\n\ts_playersettings.item_null.generic.y\t\t= 0;\n\ts_playersettings.item_null.width\t\t\t= 640;\n\ts_playersettings.item_null.height\t\t\t= 480;\n\n\tMenu_AddItem( &s_playersettings.menu, &s_playersettings.banner );\n\tMenu_AddItem( &s_playersettings.menu, &s_playersettings.framel );\n\tMenu_AddItem( &s_playersettings.menu, &s_playersettings.framer );\n\n\tMenu_AddItem( &s_playersettings.menu, &s_playersettings.name );\n\tMenu_AddItem( &s_playersettings.menu, &s_playersettings.handicap );\n\tMenu_AddItem( &s_playersettings.menu, &s_playersettings.effects );\n\tMenu_AddItem( &s_playersettings.menu, &s_playersettings.model );\n\tMenu_AddItem( &s_playersettings.menu, &s_playersettings.back );\n\n\tMenu_AddItem( &s_playersettings.menu, &s_playersettings.player );\n\n\tMenu_AddItem( &s_playersettings.menu, &s_playersettings.item_null );\n\n\tPlayerSettings_SetMenuItems();\n}\n\n\n/*\n=================\nPlayerSettings_Cache\n=================\n*/\nvoid PlayerSettings_Cache( void ) {\n\ttrap_R_RegisterShaderNoMip( ART_FRAMEL );\n\ttrap_R_RegisterShaderNoMip( ART_FRAMER );\n\ttrap_R_RegisterShaderNoMip( ART_MODEL0 );\n\ttrap_R_RegisterShaderNoMip( ART_MODEL1 );\n\ttrap_R_RegisterShaderNoMip( ART_BACK0 );\n\ttrap_R_RegisterShaderNoMip( ART_BACK1 );\n\n\ts_playersettings.fxBasePic = trap_R_RegisterShaderNoMip( ART_FX_BASE );\n\ts_playersettings.fxPic[0] = trap_R_RegisterShaderNoMip( ART_FX_RED );\n\ts_playersettings.fxPic[1] = trap_R_RegisterShaderNoMip( ART_FX_YELLOW );\n\ts_playersettings.fxPic[2] = trap_R_RegisterShaderNoMip( ART_FX_GREEN );\n\ts_playersettings.fxPic[3] = trap_R_RegisterShaderNoMip( ART_FX_TEAL );\n\ts_playersettings.fxPic[4] = trap_R_RegisterShaderNoMip( ART_FX_BLUE );\n\ts_playersettings.fxPic[5] = trap_R_RegisterShaderNoMip( ART_FX_CYAN );\n\ts_playersettings.fxPic[6] = trap_R_RegisterShaderNoMip( ART_FX_WHITE );\n}\n\n\n/*\n=================\nUI_PlayerSettingsMenu\n=================\n*/\nvoid UI_PlayerSettingsMenu( void ) {\n\tPlayerSettings_MenuInit();\n\tUI_PushMenu( &s_playersettings.menu );\n}\n"
  },
  {
    "path": "src/q3_ui/ui_preferences.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n/*\n=======================================================================\n\nGAME OPTIONS MENU\n\n=======================================================================\n*/\n\n\n#include \"ui_local.h\"\n\n\n#define ART_FRAMEL\t\t\t\t\"menu/art/frame2_l\"\n#define ART_FRAMER\t\t\t\t\"menu/art/frame1_r\"\n#define ART_BACK0\t\t\t\t\"menu/art/back_0\"\n#define ART_BACK1\t\t\t\t\"menu/art/back_1\"\n\n#define PREFERENCES_X_POS\t\t360\n\n#define ID_CROSSHAIR\t\t\t127\n#define ID_SIMPLEITEMS\t\t\t128\n#define ID_HIGHQUALITYSKY\t\t129\n#define ID_EJECTINGBRASS\t\t130\n#define ID_WALLMARKS\t\t\t131\n#define ID_DYNAMICLIGHTS\t\t132\n#define ID_IDENTIFYTARGET\t\t133\n#define ID_SYNCEVERYFRAME\t\t134\n#define ID_FORCEMODEL\t\t\t135\n#define ID_DRAWTEAMOVERLAY\t\t136\n#define ID_ALLOWDOWNLOAD\t\t\t137\n#define ID_BACK\t\t\t\t\t138\n\n#define\tNUM_CROSSHAIRS\t\t\t10\n\n\ntypedef struct {\n\tmenuframework_s\t\tmenu;\n\n\tmenutext_s\t\t\tbanner;\n\tmenubitmap_s\t\tframel;\n\tmenubitmap_s\t\tframer;\n\n\tmenulist_s\t\t\tcrosshair;\n\tmenuradiobutton_s\tsimpleitems;\n\tmenuradiobutton_s\tbrass;\n\tmenuradiobutton_s\twallmarks;\n\tmenuradiobutton_s\tdynamiclights;\n\tmenuradiobutton_s\tidentifytarget;\n\tmenuradiobutton_s\thighqualitysky;\n\tmenuradiobutton_s\tsynceveryframe;\n\tmenuradiobutton_s\tforcemodel;\n\tmenulist_s\t\t\tdrawteamoverlay;\n\tmenuradiobutton_s\tallowdownload;\n\tmenubitmap_s\t\tback;\n\n\tqhandle_t\t\t\tcrosshairShader[NUM_CROSSHAIRS];\n} preferences_t;\n\nstatic preferences_t s_preferences;\n\nstatic const char *teamoverlay_names[] =\n{\n\t\"off\",\n\t\"upper right\",\n\t\"lower right\",\n\t\"lower left\",\n\t0\n};\n\nstatic void Preferences_SetMenuItems( void ) {\n\ts_preferences.crosshair.curvalue\t\t= (int)trap_Cvar_VariableValue( \"cg_drawCrosshair\" ) % NUM_CROSSHAIRS;\n\ts_preferences.simpleitems.curvalue\t\t= trap_Cvar_VariableValue( \"cg_simpleItems\" ) != 0;\n\ts_preferences.brass.curvalue\t\t\t= trap_Cvar_VariableValue( \"cg_brassTime\" ) != 0;\n\ts_preferences.wallmarks.curvalue\t\t= trap_Cvar_VariableValue( \"cg_marks\" ) != 0;\n\ts_preferences.identifytarget.curvalue\t= trap_Cvar_VariableValue( \"cg_drawCrosshairNames\" ) != 0;\n\ts_preferences.dynamiclights.curvalue\t= trap_Cvar_VariableValue( \"r_dynamiclight\" ) != 0;\n\ts_preferences.highqualitysky.curvalue\t= trap_Cvar_VariableValue ( \"r_fastsky\" ) == 0;\n\ts_preferences.synceveryframe.curvalue\t= trap_Cvar_VariableValue( \"r_finish\" ) != 0;\n\ts_preferences.forcemodel.curvalue\t\t= trap_Cvar_VariableValue( \"cg_forcemodel\" ) != 0;\n\ts_preferences.drawteamoverlay.curvalue\t= Com_Clamp( 0, 3, trap_Cvar_VariableValue( \"cg_drawTeamOverlay\" ) );\n\ts_preferences.allowdownload.curvalue\t= trap_Cvar_VariableValue( \"cl_allowDownload\" ) != 0;\n}\n\n\nstatic void Preferences_Event( void* ptr, int notification ) {\n\tif( notification != QM_ACTIVATED ) {\n\t\treturn;\n\t}\n\n\tswitch( ((menucommon_s*)ptr)->id ) {\n\tcase ID_CROSSHAIR:\n\t\ts_preferences.crosshair.curvalue++;\n\t\tif( s_preferences.crosshair.curvalue == NUM_CROSSHAIRS ) {\n\t\t\ts_preferences.crosshair.curvalue = 0;\n\t\t}\n\t\ttrap_Cvar_SetValue( \"cg_drawCrosshair\", s_preferences.crosshair.curvalue );\n\t\tbreak;\n\n\tcase ID_SIMPLEITEMS:\n\t\ttrap_Cvar_SetValue( \"cg_simpleItems\", s_preferences.simpleitems.curvalue );\n\t\tbreak;\n\n\tcase ID_HIGHQUALITYSKY:\n\t\ttrap_Cvar_SetValue( \"r_fastsky\", !s_preferences.highqualitysky.curvalue );\n\t\tbreak;\n\n\tcase ID_EJECTINGBRASS:\n\t\tif ( s_preferences.brass.curvalue )\n\t\t\ttrap_Cvar_Reset( \"cg_brassTime\" );\n\t\telse\n\t\t\ttrap_Cvar_SetValue( \"cg_brassTime\", 0 );\n\t\tbreak;\n\n\tcase ID_WALLMARKS:\n\t\ttrap_Cvar_SetValue( \"cg_marks\", s_preferences.wallmarks.curvalue );\n\t\tbreak;\n\n\tcase ID_DYNAMICLIGHTS:\n\t\ttrap_Cvar_SetValue( \"r_dynamiclight\", s_preferences.dynamiclights.curvalue );\n\t\tbreak;\t\t\n\n\tcase ID_IDENTIFYTARGET:\n\t\ttrap_Cvar_SetValue( \"cg_drawCrosshairNames\", s_preferences.identifytarget.curvalue );\n\t\tbreak;\n\n\tcase ID_SYNCEVERYFRAME:\n\t\ttrap_Cvar_SetValue( \"r_finish\", s_preferences.synceveryframe.curvalue );\n\t\tbreak;\n\n\tcase ID_FORCEMODEL:\n\t\ttrap_Cvar_SetValue( \"cg_forcemodel\", s_preferences.forcemodel.curvalue );\n\t\tbreak;\n\n\tcase ID_DRAWTEAMOVERLAY:\n\t\ttrap_Cvar_SetValue( \"cg_drawTeamOverlay\", s_preferences.drawteamoverlay.curvalue );\n\t\tbreak;\n\n\tcase ID_ALLOWDOWNLOAD:\n\t\ttrap_Cvar_SetValue( \"cl_allowDownload\", s_preferences.allowdownload.curvalue );\n\t\ttrap_Cvar_SetValue( \"sv_allowDownload\", s_preferences.allowdownload.curvalue );\n\t\tbreak;\n\n\tcase ID_BACK:\n\t\tUI_PopMenu();\n\t\tbreak;\n\t}\n}\n\n\n/*\n=================\nCrosshair_Draw\n=================\n*/\nstatic void Crosshair_Draw( void *self ) {\n\tmenulist_s\t*s;\n\tfloat\t\t*color;\n\tint\t\t\tx, y;\n\tint\t\t\tstyle;\n\tqboolean\tfocus;\n\n\ts = (menulist_s *)self;\n\tx = s->generic.x;\n\ty =\ts->generic.y;\n\n\tstyle = UI_SMALLFONT;\n\tfocus = (s->generic.parent->cursor == s->generic.menuPosition);\n\n\tif ( s->generic.flags & QMF_GRAYED )\n\t\tcolor = text_color_disabled;\n\telse if ( focus )\n\t{\n\t\tcolor = text_color_highlight;\n\t\tstyle |= UI_PULSE;\n\t}\n\telse if ( s->generic.flags & QMF_BLINK )\n\t{\n\t\tcolor = text_color_highlight;\n\t\tstyle |= UI_BLINK;\n\t}\n\telse\n\t\tcolor = text_color_normal;\n\n\tif ( focus )\n\t{\n\t\t// draw cursor\n\t\tUI_FillRect( s->generic.left, s->generic.top, s->generic.right-s->generic.left+1, s->generic.bottom-s->generic.top+1, listbar_color ); \n\t\tUI_DrawChar( x, y, 13, UI_CENTER|UI_BLINK|UI_SMALLFONT, color);\n\t}\n\n\tUI_DrawString( x - SMALLCHAR_WIDTH, y, s->generic.name, style|UI_RIGHT, color );\n\tif( !s->curvalue ) {\n\t\treturn;\n\t}\n\tUI_DrawHandlePic( x + SMALLCHAR_WIDTH, y - 4, 24, 24, s_preferences.crosshairShader[s->curvalue] );\n}\n\n\nstatic void Preferences_MenuInit( void ) {\n\tint\t\t\t\ty;\n\n\tmemset( &s_preferences, 0 ,sizeof(preferences_t) );\n\n\tPreferences_Cache();\n\n\ts_preferences.menu.wrapAround = qtrue;\n\ts_preferences.menu.fullscreen = qtrue;\n\n\ts_preferences.banner.generic.type  = MTYPE_BTEXT;\n\ts_preferences.banner.generic.x\t   = 320;\n\ts_preferences.banner.generic.y\t   = 16;\n\ts_preferences.banner.string\t\t   = \"GAME OPTIONS\";\n\ts_preferences.banner.color         = color_white;\n\ts_preferences.banner.style         = UI_CENTER;\n\n\ts_preferences.framel.generic.type  = MTYPE_BITMAP;\n\ts_preferences.framel.generic.name  = ART_FRAMEL;\n\ts_preferences.framel.generic.flags = QMF_INACTIVE;\n\ts_preferences.framel.generic.x\t   = 0;\n\ts_preferences.framel.generic.y\t   = 78;\n\ts_preferences.framel.width  \t   = 256;\n\ts_preferences.framel.height  \t   = 329;\n\n\ts_preferences.framer.generic.type  = MTYPE_BITMAP;\n\ts_preferences.framer.generic.name  = ART_FRAMER;\n\ts_preferences.framer.generic.flags = QMF_INACTIVE;\n\ts_preferences.framer.generic.x\t   = 376;\n\ts_preferences.framer.generic.y\t   = 76;\n\ts_preferences.framer.width  \t   = 256;\n\ts_preferences.framer.height  \t   = 334;\n\n\ty = 144;\n\ts_preferences.crosshair.generic.type\t\t= MTYPE_TEXT;\n\ts_preferences.crosshair.generic.flags\t\t= QMF_PULSEIFFOCUS|QMF_SMALLFONT|QMF_NODEFAULTINIT|QMF_OWNERDRAW;\n\ts_preferences.crosshair.generic.x\t\t\t= PREFERENCES_X_POS;\n\ts_preferences.crosshair.generic.y\t\t\t= y;\n\ts_preferences.crosshair.generic.name\t\t= \"Crosshair:\";\n\ts_preferences.crosshair.generic.callback\t= Preferences_Event;\n\ts_preferences.crosshair.generic.ownerdraw\t= Crosshair_Draw;\n\ts_preferences.crosshair.generic.id\t\t\t= ID_CROSSHAIR;\n\ts_preferences.crosshair.generic.top\t\t\t= y - 4;\n\ts_preferences.crosshair.generic.bottom\t\t= y + 20;\n\ts_preferences.crosshair.generic.left\t\t= PREFERENCES_X_POS - ( ( (int)strlen(s_preferences.crosshair.generic.name) + 1 ) * SMALLCHAR_WIDTH );\n\ts_preferences.crosshair.generic.right\t\t= PREFERENCES_X_POS + 48;\n\n\ty += BIGCHAR_HEIGHT+2+4;\n\ts_preferences.simpleitems.generic.type        = MTYPE_RADIOBUTTON;\n\ts_preferences.simpleitems.generic.name\t      = \"Simple Items:\";\n\ts_preferences.simpleitems.generic.flags\t      = QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\ts_preferences.simpleitems.generic.callback    = Preferences_Event;\n\ts_preferences.simpleitems.generic.id          = ID_SIMPLEITEMS;\n\ts_preferences.simpleitems.generic.x\t          = PREFERENCES_X_POS;\n\ts_preferences.simpleitems.generic.y\t          = y;\n\n\ty += BIGCHAR_HEIGHT;\n\ts_preferences.wallmarks.generic.type          = MTYPE_RADIOBUTTON;\n\ts_preferences.wallmarks.generic.name\t      = \"Marks on Walls:\";\n\ts_preferences.wallmarks.generic.flags\t      = QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\ts_preferences.wallmarks.generic.callback      = Preferences_Event;\n\ts_preferences.wallmarks.generic.id            = ID_WALLMARKS;\n\ts_preferences.wallmarks.generic.x\t          = PREFERENCES_X_POS;\n\ts_preferences.wallmarks.generic.y\t          = y;\n\n\ty += BIGCHAR_HEIGHT+2;\n\ts_preferences.brass.generic.type              = MTYPE_RADIOBUTTON;\n\ts_preferences.brass.generic.name\t          = \"Ejecting Brass:\";\n\ts_preferences.brass.generic.flags\t          = QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\ts_preferences.brass.generic.callback          = Preferences_Event;\n\ts_preferences.brass.generic.id                = ID_EJECTINGBRASS;\n\ts_preferences.brass.generic.x\t              = PREFERENCES_X_POS;\n\ts_preferences.brass.generic.y\t              = y;\n\n\ty += BIGCHAR_HEIGHT+2;\n\ts_preferences.dynamiclights.generic.type      = MTYPE_RADIOBUTTON;\n\ts_preferences.dynamiclights.generic.name\t  = \"Dynamic Lights:\";\n\ts_preferences.dynamiclights.generic.flags     = QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\ts_preferences.dynamiclights.generic.callback  = Preferences_Event;\n\ts_preferences.dynamiclights.generic.id        = ID_DYNAMICLIGHTS;\n\ts_preferences.dynamiclights.generic.x\t      = PREFERENCES_X_POS;\n\ts_preferences.dynamiclights.generic.y\t      = y;\n\n\ty += BIGCHAR_HEIGHT+2;\n\ts_preferences.identifytarget.generic.type     = MTYPE_RADIOBUTTON;\n\ts_preferences.identifytarget.generic.name\t  = \"Identify Target:\";\n\ts_preferences.identifytarget.generic.flags    = QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\ts_preferences.identifytarget.generic.callback = Preferences_Event;\n\ts_preferences.identifytarget.generic.id       = ID_IDENTIFYTARGET;\n\ts_preferences.identifytarget.generic.x\t      = PREFERENCES_X_POS;\n\ts_preferences.identifytarget.generic.y\t      = y;\n\n\ty += BIGCHAR_HEIGHT+2;\n\ts_preferences.highqualitysky.generic.type     = MTYPE_RADIOBUTTON;\n\ts_preferences.highqualitysky.generic.name\t  = \"High Quality Sky:\";\n\ts_preferences.highqualitysky.generic.flags\t  = QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\ts_preferences.highqualitysky.generic.callback = Preferences_Event;\n\ts_preferences.highqualitysky.generic.id       = ID_HIGHQUALITYSKY;\n\ts_preferences.highqualitysky.generic.x\t      = PREFERENCES_X_POS;\n\ts_preferences.highqualitysky.generic.y\t      = y;\n\n\ty += BIGCHAR_HEIGHT+2;\n\ts_preferences.synceveryframe.generic.type     = MTYPE_RADIOBUTTON;\n\ts_preferences.synceveryframe.generic.name\t  = \"Sync Every Frame:\";\n\ts_preferences.synceveryframe.generic.flags\t  = QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\ts_preferences.synceveryframe.generic.callback = Preferences_Event;\n\ts_preferences.synceveryframe.generic.id       = ID_SYNCEVERYFRAME;\n\ts_preferences.synceveryframe.generic.x\t      = PREFERENCES_X_POS;\n\ts_preferences.synceveryframe.generic.y\t      = y;\n\n\ty += BIGCHAR_HEIGHT+2;\n\ts_preferences.forcemodel.generic.type     = MTYPE_RADIOBUTTON;\n\ts_preferences.forcemodel.generic.name\t  = \"Force Player Models:\";\n\ts_preferences.forcemodel.generic.flags\t  = QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\ts_preferences.forcemodel.generic.callback = Preferences_Event;\n\ts_preferences.forcemodel.generic.id       = ID_FORCEMODEL;\n\ts_preferences.forcemodel.generic.x\t      = PREFERENCES_X_POS;\n\ts_preferences.forcemodel.generic.y\t      = y;\n\n\ty += BIGCHAR_HEIGHT+2;\n\ts_preferences.drawteamoverlay.generic.type     = MTYPE_SPINCONTROL;\n\ts_preferences.drawteamoverlay.generic.name\t   = \"Draw Team Overlay:\";\n\ts_preferences.drawteamoverlay.generic.flags\t   = QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\ts_preferences.drawteamoverlay.generic.callback = Preferences_Event;\n\ts_preferences.drawteamoverlay.generic.id       = ID_DRAWTEAMOVERLAY;\n\ts_preferences.drawteamoverlay.generic.x\t       = PREFERENCES_X_POS;\n\ts_preferences.drawteamoverlay.generic.y\t       = y;\n\ts_preferences.drawteamoverlay.itemnames\t\t\t= teamoverlay_names;\n\n\ty += BIGCHAR_HEIGHT+2;\n\ts_preferences.allowdownload.generic.type     = MTYPE_RADIOBUTTON;\n\ts_preferences.allowdownload.generic.name\t   = \"Automatic Downloading:\";\n\ts_preferences.allowdownload.generic.flags\t   = QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\ts_preferences.allowdownload.generic.callback = Preferences_Event;\n\ts_preferences.allowdownload.generic.id       = ID_ALLOWDOWNLOAD;\n\ts_preferences.allowdownload.generic.x\t       = PREFERENCES_X_POS;\n\ts_preferences.allowdownload.generic.y\t       = y;\n\n\ty += BIGCHAR_HEIGHT+2;\n\ts_preferences.back.generic.type\t    = MTYPE_BITMAP;\n\ts_preferences.back.generic.name     = ART_BACK0;\n\ts_preferences.back.generic.flags    = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_preferences.back.generic.callback = Preferences_Event;\n\ts_preferences.back.generic.id\t    = ID_BACK;\n\ts_preferences.back.generic.x\t\t= 0;\n\ts_preferences.back.generic.y\t\t= 480-64;\n\ts_preferences.back.width  \t\t    = 128;\n\ts_preferences.back.height  \t\t    = 64;\n\ts_preferences.back.focuspic         = ART_BACK1;\n\n\tMenu_AddItem( &s_preferences.menu, &s_preferences.banner );\n\tMenu_AddItem( &s_preferences.menu, &s_preferences.framel );\n\tMenu_AddItem( &s_preferences.menu, &s_preferences.framer );\n\n\tMenu_AddItem( &s_preferences.menu, &s_preferences.crosshair );\n\tMenu_AddItem( &s_preferences.menu, &s_preferences.simpleitems );\n\tMenu_AddItem( &s_preferences.menu, &s_preferences.wallmarks );\n\tMenu_AddItem( &s_preferences.menu, &s_preferences.brass );\n\tMenu_AddItem( &s_preferences.menu, &s_preferences.dynamiclights );\n\tMenu_AddItem( &s_preferences.menu, &s_preferences.identifytarget );\n\tMenu_AddItem( &s_preferences.menu, &s_preferences.highqualitysky );\n\tMenu_AddItem( &s_preferences.menu, &s_preferences.synceveryframe );\n\tMenu_AddItem( &s_preferences.menu, &s_preferences.forcemodel );\n\tMenu_AddItem( &s_preferences.menu, &s_preferences.drawteamoverlay );\n\tMenu_AddItem( &s_preferences.menu, &s_preferences.allowdownload );\n\n\tMenu_AddItem( &s_preferences.menu, &s_preferences.back );\n\n\tPreferences_SetMenuItems();\n}\n\n\n/*\n===============\nPreferences_Cache\n===============\n*/\nvoid Preferences_Cache( void ) {\n\tint\t\tn;\n\n\ttrap_R_RegisterShaderNoMip( ART_FRAMEL );\n\ttrap_R_RegisterShaderNoMip( ART_FRAMER );\n\ttrap_R_RegisterShaderNoMip( ART_BACK0 );\n\ttrap_R_RegisterShaderNoMip( ART_BACK1 );\n\tfor( n = 0; n < NUM_CROSSHAIRS; n++ ) {\n\t\ts_preferences.crosshairShader[n] = trap_R_RegisterShaderNoMip( va(\"gfx/2d/crosshair%c\", 'a' + n ) );\n\t}\n}\n\n\n/*\n===============\nUI_PreferencesMenu\n===============\n*/\nvoid UI_PreferencesMenu( void ) {\n\tPreferences_MenuInit();\n\tUI_PushMenu( &s_preferences.menu );\n}\n"
  },
  {
    "path": "src/q3_ui/ui_public.h",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n#ifndef __UI_PUBLIC_H__\n#define __UI_PUBLIC_H__\n\n#define UI_API_VERSION\t6\n\ntypedef struct {\n\tconnstate_t\t\tconnState;\n\tint\t\t\t\tconnectPacketCount;\n\tint\t\t\t\tclientNum;\n\tchar\t\t\tservername[MAX_STRING_CHARS];\n\tchar\t\t\tupdateInfoString[MAX_STRING_CHARS];\n\tchar\t\t\tmessageString[MAX_STRING_CHARS];\n} uiClientState_t;\n\ntypedef enum {\n\tUI_ERROR,\n\tUI_PRINT,\n\tUI_MILLISECONDS,\n\tUI_CVAR_SET,\n\tUI_CVAR_VARIABLEVALUE,\n\tUI_CVAR_VARIABLESTRINGBUFFER,\n\tUI_CVAR_SETVALUE,\n\tUI_CVAR_RESET,\n\tUI_CVAR_CREATE,\n\tUI_CVAR_INFOSTRINGBUFFER,\n\tUI_ARGC,\n\tUI_ARGV,\n\tUI_CMD_EXECUTETEXT,\n\tUI_FS_FOPENFILE,\n\tUI_FS_READ,\n\tUI_FS_WRITE,\n\tUI_FS_FCLOSEFILE,\n\tUI_FS_GETFILELIST,\n\tUI_R_REGISTERMODEL,\n\tUI_R_REGISTERSKIN,\n\tUI_R_REGISTERSHADERNOMIP,\n\tUI_R_CLEARSCENE,\n\tUI_R_ADDREFENTITYTOSCENE,\n\tUI_R_ADDPOLYTOSCENE,\n\tUI_R_ADDLIGHTTOSCENE,\n\tUI_R_RENDERSCENE,\n\tUI_R_SETCOLOR,\n\tUI_R_DRAWSTRETCHPIC,\n\tUI_UPDATESCREEN,\n\tUI_CM_LERPTAG,\n\tUI_CM_LOADMODEL,\n\tUI_S_REGISTERSOUND,\n\tUI_S_STARTLOCALSOUND,\n\tUI_KEY_KEYNUMTOSTRINGBUF,\n\tUI_KEY_GETBINDINGBUF,\n\tUI_KEY_SETBINDING,\n\tUI_KEY_ISDOWN,\n\tUI_KEY_GETOVERSTRIKEMODE,\n\tUI_KEY_SETOVERSTRIKEMODE,\n\tUI_KEY_CLEARSTATES,\n\tUI_KEY_GETCATCHER,\n\tUI_KEY_SETCATCHER,\n\tUI_GETCLIPBOARDDATA,\n\tUI_GETGLCONFIG,\n\tUI_GETCLIENTSTATE,\n\tUI_GETCONFIGSTRING,\n\tUI_LAN_GETPINGQUEUECOUNT,\n\tUI_LAN_CLEARPING,\n\tUI_LAN_GETPING,\n\tUI_LAN_GETPINGINFO,\n\tUI_CVAR_REGISTER,\n\tUI_CVAR_UPDATE,\n\tUI_MEMORY_REMAINING,\n\tUI_GET_CDKEY,\n\tUI_SET_CDKEY,\n\tUI_R_REGISTERFONT,\n\tUI_R_MODELBOUNDS,\n\tUI_PC_ADD_GLOBAL_DEFINE,\n\tUI_PC_LOAD_SOURCE,\n\tUI_PC_FREE_SOURCE,\n\tUI_PC_READ_TOKEN,\n\tUI_PC_SOURCE_FILE_AND_LINE,\n\tUI_S_STOPBACKGROUNDTRACK,\n\tUI_S_STARTBACKGROUNDTRACK,\n\tUI_REAL_TIME,\n\tUI_LAN_GETSERVERCOUNT,\n\tUI_LAN_GETSERVERADDRESSSTRING,\n\tUI_LAN_GETSERVERINFO,\n\tUI_LAN_MARKSERVERVISIBLE,\n\tUI_LAN_UPDATEVISIBLEPINGS,\n\tUI_LAN_RESETPINGS,\n\tUI_LAN_LOADCACHEDSERVERS,\n\tUI_LAN_SAVECACHEDSERVERS,\n\tUI_LAN_ADDSERVER,\n\tUI_LAN_REMOVESERVER,\n\tUI_CIN_PLAYCINEMATIC,\n\tUI_CIN_STOPCINEMATIC,\n\tUI_CIN_RUNCINEMATIC,\n\tUI_CIN_DRAWCINEMATIC,\n\tUI_CIN_SETEXTENTS,\n\tUI_R_REMAP_SHADER,\n\tUI_VERIFY_CDKEY,\n\tUI_LAN_SERVERSTATUS,\n\tUI_LAN_GETSERVERPING,\n\tUI_LAN_SERVERISVISIBLE,\n\tUI_LAN_COMPARESERVERS,\n\t// 1.32\n\tUI_FS_SEEK,\n\tUI_SET_PBCLSTATUS,\n\n\tUI_MEMSET = 100,\n\tUI_MEMCPY,\n\tUI_STRNCPY,\n\tUI_SIN,\n\tUI_COS,\n\tUI_ATAN2,\n\tUI_SQRT,\n\tUI_FLOOR,\n\tUI_CEIL\n} uiImport_t;\n\ntypedef enum {\n\tUIMENU_NONE,\n\tUIMENU_MAIN,\n\tUIMENU_INGAME,\n\tUIMENU_NEED_CD,\n\tUIMENU_BAD_CD_KEY,\n\tUIMENU_TEAM,\n\tUIMENU_POSTGAME\n} uiMenuCommand_t;\n\n#define SORT_HOST\t\t\t0\n#define SORT_MAP\t\t\t1\n#define SORT_CLIENTS\t\t2\n#define SORT_GAME\t\t\t3\n#define SORT_PING\t\t\t4\n#define SORT_PUNKBUSTER\t\t5\n\ntypedef enum {\n\tUI_GETAPIVERSION = 0,\t// system reserved\n\n\tUI_INIT,\n//\tvoid\tUI_Init( void );\n\n\tUI_SHUTDOWN,\n//\tvoid\tUI_Shutdown( void );\n\n\tUI_KEY_EVENT,\n//\tvoid\tUI_KeyEvent( int key );\n\n\tUI_MOUSE_EVENT,\n//\tvoid\tUI_MouseEvent( int dx, int dy );\n\n\tUI_REFRESH,\n//\tvoid\tUI_Refresh( int time );\n\n\tUI_IS_FULLSCREEN,\n//\tqboolean UI_IsFullscreen( void );\n\n\tUI_SET_ACTIVE_MENU,\n//\tvoid\tUI_SetActiveMenu( uiMenuCommand_t menu );\n\n\tUI_CONSOLE_COMMAND,\n//\tqboolean UI_ConsoleCommand( int realTime );\n\n\tUI_DRAW_CONNECT_SCREEN,\n//\tvoid\tUI_DrawConnectScreen( qboolean overlay );\n\tUI_HASUNIQUECDKEY\n// if !overlay, the background will be drawn, otherwise it will be\n// overlayed over whatever the cgame has drawn.\n// a GetClientState syscall will be made to get the current strings\n} uiExport_t;\n\n#endif\n"
  },
  {
    "path": "src/q3_ui/ui_qmenu.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n/**********************************************************************\n\tUI_QMENU.C\n\n\tQuake's menu framework system.\n**********************************************************************/\n#include \"ui_local.h\"\n\nsfxHandle_t menu_in_sound;\nsfxHandle_t menu_move_sound;\nsfxHandle_t menu_out_sound;\nsfxHandle_t menu_buzz_sound;\nsfxHandle_t menu_null_sound;\nsfxHandle_t weaponChangeSound;\n\nstatic qhandle_t\tsliderBar;\nstatic qhandle_t\tsliderButton_0;\nstatic qhandle_t\tsliderButton_1;\n\nvec4_t menu_text_color\t    = {1.0f, 1.0f, 1.0f, 1.0f};\nvec4_t menu_dim_color       = {0.0f, 0.0f, 0.0f, 0.75f};\nvec4_t color_black\t    = {0.00f, 0.00f, 0.00f, 1.00f};\nvec4_t color_white\t    = {1.00f, 1.00f, 1.00f, 1.00f};\nvec4_t color_yellow\t    = {1.00f, 1.00f, 0.00f, 1.00f};\nvec4_t color_blue\t    = {0.00f, 0.00f, 1.00f, 1.00f};\nvec4_t color_lightOrange    = {1.00f, 0.68f, 0.00f, 1.00f };\nvec4_t color_orange\t    = {1.00f, 0.43f, 0.00f, 1.00f};\nvec4_t color_red\t    = {1.00f, 0.00f, 0.00f, 1.00f};\nvec4_t color_dim\t    = {0.00f, 0.00f, 0.00f, 0.25f};\n\n// current color scheme\nvec4_t pulse_color          = {1.00f, 1.00f, 1.00f, 1.00f};\nvec4_t text_color_disabled  = {0.50f, 0.50f, 0.50f, 1.00f};\t// light gray\nvec4_t text_color_normal    = {1.00f, 0.43f, 0.00f, 1.00f};\t// light orange\nvec4_t text_color_highlight = {1.00f, 1.00f, 0.00f, 1.00f};\t// bright yellow\nvec4_t listbar_color        = {1.00f, 0.43f, 0.00f, 0.30f};\t// transluscent orange\nvec4_t text_color_status    = {1.00f, 1.00f, 1.00f, 1.00f};\t// bright white\t\n\n// action widget\nstatic void\tAction_Init( menuaction_s *a );\nstatic void\tAction_Draw( menuaction_s *a );\n\n// radio button widget\nstatic void\tRadioButton_Init( menuradiobutton_s *rb );\nstatic void\tRadioButton_Draw( menuradiobutton_s *rb );\nstatic sfxHandle_t RadioButton_Key( menuradiobutton_s *rb, int key );\n\n// slider widget\nstatic void Slider_Init( menuslider_s *s );\nstatic sfxHandle_t Slider_Key( menuslider_s *s, int key );\nstatic void\tSlider_Draw( menuslider_s *s );\n\n// spin control widget\nstatic void\tSpinControl_Init( menulist_s *s );\nstatic void\tSpinControl_Draw( menulist_s *s );\nstatic sfxHandle_t SpinControl_Key( menulist_s *l, int key );\n\n// text widget\nstatic void Text_Init( menutext_s *b );\nstatic void Text_Draw( menutext_s *b );\n\n// scrolllist widget\nstatic void\tScrollList_Init( menulist_s *l );\nsfxHandle_t ScrollList_Key( menulist_s *l, int key );\n\n// proportional text widget\nstatic void PText_Init( menutext_s *b );\nstatic void PText_Draw( menutext_s *b );\n\n// proportional banner text widget\nstatic void BText_Init( menutext_s *b );\nstatic void BText_Draw( menutext_s *b );\n\n/*\n=================\nText_Init\n=================\n*/\nstatic void Text_Init( menutext_s *t )\n{\n\tt->generic.flags |= QMF_INACTIVE;\n}\n\n/*\n=================\nText_Draw\n=================\n*/\nstatic void Text_Draw( menutext_s *t )\n{\n\tint\t\tx;\n\tint\t\ty;\n\tchar\tbuff[512];\t\n\tfloat*\tcolor;\n\n\tx = t->generic.x;\n\ty = t->generic.y;\n\n\tbuff[0] = '\\0';\n\n\t// possible label\n\tif (t->generic.name)\n\t\tstrcpy(buff,t->generic.name);\n\n\t// possible value\n\tif (t->string)\n\t\tstrcat(buff,t->string);\n\t\t\n\tif (t->generic.flags & QMF_GRAYED)\n\t\tcolor = text_color_disabled;\n\telse\n\t\tcolor = t->color;\n\n\tUI_DrawString( x, y, buff, t->style, color );\n}\n\n/*\n=================\nBText_Init\n=================\n*/\nstatic void BText_Init( menutext_s *t )\n{\n\tt->generic.flags |= QMF_INACTIVE;\n}\n\n/*\n=================\nBText_Draw\n=================\n*/\nstatic void BText_Draw( menutext_s *t )\n{\n\tint\t\tx;\n\tint\t\ty;\n\tfloat*\tcolor;\n\n\tx = t->generic.x;\n\ty = t->generic.y;\n\n\tif (t->generic.flags & QMF_GRAYED)\n\t\tcolor = text_color_disabled;\n\telse\n\t\tcolor = t->color;\n\n\tUI_DrawBannerString( x, y, t->string, t->style, color );\n}\n\n/*\n=================\nPText_Init\n=================\n*/\nstatic void PText_Init( menutext_s *t )\n{\n\tint\tx;\n\tint\ty;\n\tint\tw;\n\tint\th;\n\tfloat\tsizeScale;\n\n\tsizeScale = UI_ProportionalSizeScale( t->style );\n\n\tx = t->generic.x;\n\ty = t->generic.y;\n\tw = UI_ProportionalStringWidth( t->string ) * sizeScale;\n\th =\tPROP_HEIGHT * sizeScale;\n\n\tif( t->generic.flags & QMF_RIGHT_JUSTIFY ) {\n\t\tx -= w;\n\t}\n\telse if( t->generic.flags & QMF_CENTER_JUSTIFY ) {\n\t\tx -= w / 2;\n\t}\n\n\tt->generic.left   = x - PROP_GAP_WIDTH * sizeScale;\n\tt->generic.right  = x + w + PROP_GAP_WIDTH * sizeScale;\n\tt->generic.top    = y;\n\tt->generic.bottom = y + h;\n}\n\n/*\n=================\nPText_Draw\n=================\n*/\nstatic void PText_Draw( menutext_s *t )\n{\n\tint\t\tx;\n\tint\t\ty;\n\tfloat *\tcolor;\n\tint\t\tstyle;\n\n\tx = t->generic.x;\n\ty = t->generic.y;\n\n\tif (t->generic.flags & QMF_GRAYED)\n\t\tcolor = text_color_disabled;\n\telse\n\t\tcolor = t->color;\n\n\tstyle = t->style;\n\tif( t->generic.flags & QMF_PULSEIFFOCUS ) {\n\t\tif( Menu_ItemAtCursor( t->generic.parent ) == t ) {\n\t\t\tstyle |= UI_PULSE;\n\t\t}\n\t\telse {\n\t\t\tstyle |= UI_INVERSE;\n\t\t}\n\t}\n\n\tUI_DrawProportionalString( x, y, t->string, style, color );\n}\n\n/*\n=================\nBitmap_Init\n=================\n*/\nvoid Bitmap_Init( menubitmap_s *b )\n{\n\tint\tx;\n\tint\ty;\n\tint\tw;\n\tint\th;\n\n\tx = b->generic.x;\n\ty = b->generic.y;\n\tw = b->width;\n\th =\tb->height;\n\tif( w < 0 ) {\n\t\tw = -w;\n\t}\n\tif( h < 0 ) {\n\t\th = -h;\n\t}\n\n\tif (b->generic.flags & QMF_RIGHT_JUSTIFY)\n\t{\n\t\tx = x - w;\n\t}\n\telse if (b->generic.flags & QMF_CENTER_JUSTIFY)\n\t{\n\t\tx = x - w/2;\n\t}\n\n\tb->generic.left   = x;\n\tb->generic.right  = x + w;\n\tb->generic.top    = y;\n\tb->generic.bottom = y + h;\n\n\tb->shader      = 0;\n\tb->focusshader = 0;\n}\n\n/*\n=================\nBitmap_Draw\n=================\n*/\nvoid Bitmap_Draw( menubitmap_s *b )\n{\n\tfloat\tx;\n\tfloat\ty;\n\tfloat\tw;\n\tfloat\th;\n\tvec4_t\ttempcolor;\n\tfloat*\tcolor;\n\n\tx = b->generic.x;\n\ty = b->generic.y;\n\tw = b->width;\n\th =\tb->height;\n\n\tif (b->generic.flags & QMF_RIGHT_JUSTIFY)\n\t{\n\t\tx = x - w;\n\t}\n\telse if (b->generic.flags & QMF_CENTER_JUSTIFY)\n\t{\n\t\tx = x - w/2;\n\t}\n\n\t// used to refresh shader\n\tif (b->generic.name && !b->shader)\n\t{\n\t\tb->shader = trap_R_RegisterShaderNoMip( b->generic.name );\n\t\tif (!b->shader && b->errorpic)\n\t\t\tb->shader = trap_R_RegisterShaderNoMip( b->errorpic );\n\t}\n\n\tif (b->focuspic && !b->focusshader)\n\t\tb->focusshader = trap_R_RegisterShaderNoMip( b->focuspic );\n\n\tif (b->generic.flags & QMF_GRAYED)\n\t{\n\t\tif (b->shader)\n\t\t{\n\t\t\ttrap_R_SetColor( colorMdGrey );\n\t\t\tUI_DrawHandlePic( x, y, w, h, b->shader );\n\t\t\ttrap_R_SetColor( NULL );\n\t\t}\n\t}\n\telse\n\t{\n\t\tif (b->shader)\n\t\t\tUI_DrawHandlePic( x, y, w, h, b->shader );\n\n\t\t// bk001204 - parentheses\n\t\tif (  ( (b->generic.flags & QMF_PULSE) \n\t\t\t|| (b->generic.flags & QMF_PULSEIFFOCUS) )\n\t\t      && (Menu_ItemAtCursor( b->generic.parent ) == b))\n\t\t{\t\n\t\t\tif (b->focuscolor)\t\t\t\n\t\t\t{\n\t\t\t\ttempcolor[0] = b->focuscolor[0];\n\t\t\t\ttempcolor[1] = b->focuscolor[1];\n\t\t\t\ttempcolor[2] = b->focuscolor[2];\n\t\t\t\tcolor        = tempcolor;\t\n\t\t\t}\n\t\t\telse\n\t\t\t\tcolor = pulse_color;\n\t\t\tcolor[3] = 0.5+0.5*sin(uis.realtime/PULSE_DIVISOR);\n\n\t\t\ttrap_R_SetColor( color );\n\t\t\tUI_DrawHandlePic( x, y, w, h, b->focusshader );\n\t\t\ttrap_R_SetColor( NULL );\n\t\t}\n\t\telse if ((b->generic.flags & QMF_HIGHLIGHT) || ((b->generic.flags & QMF_HIGHLIGHT_IF_FOCUS) && (Menu_ItemAtCursor( b->generic.parent ) == b)))\n\t\t{\t\n\t\t\tif (b->focuscolor)\n\t\t\t{\n\t\t\t\ttrap_R_SetColor( b->focuscolor );\n\t\t\t\tUI_DrawHandlePic( x, y, w, h, b->focusshader );\n\t\t\t\ttrap_R_SetColor( NULL );\n\t\t\t}\n\t\t\telse\n\t\t\t\tUI_DrawHandlePic( x, y, w, h, b->focusshader );\n\t\t}\n\t}\n}\n\n/*\n=================\nAction_Init\n=================\n*/\nstatic void Action_Init( menuaction_s *a )\n{\n\tint\tlen;\n\n\t// calculate bounds\n\tif (a->generic.name)\n\t\tlen = (int)strlen(a->generic.name);\n\telse\n\t\tlen = 0;\n\n\t// left justify text\n\ta->generic.left   = a->generic.x; \n\ta->generic.right  = a->generic.x + len*BIGCHAR_WIDTH;\n\ta->generic.top    = a->generic.y;\n\ta->generic.bottom = a->generic.y + BIGCHAR_HEIGHT;\n}\n\n/*\n=================\nAction_Draw\n=================\n*/\nstatic void Action_Draw( menuaction_s *a )\n{\n\tint\t\tx, y;\n\tint\t\tstyle;\n\tfloat*\tcolor;\n\n\tstyle = 0;\n\tcolor = menu_text_color;\n\tif ( a->generic.flags & QMF_GRAYED )\n\t{\n\t\tcolor = text_color_disabled;\n\t}\n\telse if (( a->generic.flags & QMF_PULSEIFFOCUS ) && ( a->generic.parent->cursor == a->generic.menuPosition ))\n\t{\n\t\tcolor = text_color_highlight;\n\t\tstyle = UI_PULSE;\n\t}\n\telse if (( a->generic.flags & QMF_HIGHLIGHT_IF_FOCUS ) && ( a->generic.parent->cursor == a->generic.menuPosition ))\n\t{\n\t\tcolor = text_color_highlight;\n\t}\n\telse if ( a->generic.flags & QMF_BLINK )\n\t{\n\t\tstyle = UI_BLINK;\n\t\tcolor = text_color_highlight;\n\t}\n\n\tx = a->generic.x;\n\ty = a->generic.y;\n\n\tUI_DrawString( x, y, a->generic.name, UI_LEFT|style, color );\n\n\tif ( a->generic.parent->cursor == a->generic.menuPosition )\n\t{\n\t\t// draw cursor\n\t\tUI_DrawChar( x - BIGCHAR_WIDTH, y, 13, UI_LEFT|UI_BLINK, color);\n\t}\n}\n\n/*\n=================\nRadioButton_Init\n=================\n*/\nstatic void RadioButton_Init( menuradiobutton_s *rb )\n{\n\tint\tlen;\n\n\t// calculate bounds\n\tif (rb->generic.name)\n\t\tlen = (int)strlen(rb->generic.name);\n\telse\n\t\tlen = 0;\n\n\trb->generic.left   = rb->generic.x - (len+1)*SMALLCHAR_WIDTH;\n\trb->generic.right  = rb->generic.x + 6*SMALLCHAR_WIDTH;\n\trb->generic.top    = rb->generic.y;\n\trb->generic.bottom = rb->generic.y + SMALLCHAR_HEIGHT;\n}\n\n/*\n=================\nRadioButton_Key\n=================\n*/\nstatic sfxHandle_t RadioButton_Key( menuradiobutton_s *rb, int key )\n{\n\tswitch (key)\n\t{\n\t\tcase K_MOUSE1:\n\t\t\tif (!(rb->generic.flags & QMF_HASMOUSEFOCUS))\n\t\t\t\tbreak;\n\n\t\tcase K_JOY1:\n\t\tcase K_JOY2:\n\t\tcase K_JOY3:\n\t\tcase K_JOY4:\n\t\tcase K_ENTER:\n\t\tcase K_KP_ENTER:\n\t\tcase K_KP_LEFTARROW:\n\t\tcase K_LEFTARROW:\n\t\tcase K_KP_RIGHTARROW:\n\t\tcase K_RIGHTARROW:\n\t\t\trb->curvalue = !rb->curvalue;\n\t\t\tif ( rb->generic.callback )\n\t\t\t\trb->generic.callback( rb, QM_ACTIVATED );\n\n\t\t\treturn (menu_move_sound);\n\t}\n\n\t// key not handled\n\treturn 0;\n}\n\n/*\n=================\nRadioButton_Draw\n=================\n*/\nstatic void RadioButton_Draw( menuradiobutton_s *rb )\n{\n\tint\tx;\n\tint y;\n\tfloat *color;\n\tint\tstyle;\n\tqboolean focus;\n\n\tx = rb->generic.x;\n\ty = rb->generic.y;\n\n\tfocus = (rb->generic.parent->cursor == rb->generic.menuPosition);\n\n\tif ( rb->generic.flags & QMF_GRAYED )\n\t{\n\t\tcolor = text_color_disabled;\n\t\tstyle = UI_LEFT|UI_SMALLFONT;\n\t}\n\telse if ( focus )\n\t{\n\t\tcolor = text_color_highlight;\n\t\tstyle = UI_LEFT|UI_PULSE|UI_SMALLFONT;\n\t}\n\telse\n\t{\n\t\tcolor = text_color_normal;\n\t\tstyle = UI_LEFT|UI_SMALLFONT;\n\t}\n\n\tif ( focus )\n\t{\n\t\t// draw cursor\n\t\tUI_FillRect( rb->generic.left, rb->generic.top, rb->generic.right-rb->generic.left+1, rb->generic.bottom-rb->generic.top+1, listbar_color ); \n\t\tUI_DrawChar( x, y, 13, UI_CENTER|UI_BLINK|UI_SMALLFONT, color);\n\t}\n\n\tif ( rb->generic.name )\n\t\tUI_DrawString( x - SMALLCHAR_WIDTH, y, rb->generic.name, UI_RIGHT|UI_SMALLFONT, color );\n\n\tif ( !rb->curvalue )\n\t{\n\t\tUI_DrawHandlePic( x + SMALLCHAR_WIDTH, y + 2, 16, 16, uis.rb_off);\n\t\tUI_DrawString( x + SMALLCHAR_WIDTH + 16, y, \"off\", style, color );\n\t}\n\telse\n\t{\n\t\tUI_DrawHandlePic( x + SMALLCHAR_WIDTH, y + 2, 16, 16, uis.rb_on );\n\t\tUI_DrawString( x + SMALLCHAR_WIDTH + 16, y, \"on\", style, color );\n\t}\n}\n\n/*\n=================\nSlider_Init\n=================\n*/\nstatic void Slider_Init( menuslider_s *s )\n{\n\tint len;\n\n\t// calculate bounds\n\tif (s->generic.name)\n\t\tlen = (int)strlen(s->generic.name);\n\telse\n\t\tlen = 0;\n\n\ts->generic.left   = s->generic.x - (len+1)*SMALLCHAR_WIDTH; \n\ts->generic.right  = s->generic.x + (SLIDER_RANGE+2+1)*SMALLCHAR_WIDTH;\n\ts->generic.top    = s->generic.y;\n\ts->generic.bottom = s->generic.y + SMALLCHAR_HEIGHT;\n}\n\n/*\n=================\nSlider_Key\n=================\n*/\nstatic sfxHandle_t Slider_Key( menuslider_s *s, int key )\n{\n\tsfxHandle_t\tsound;\n\tint\t\t\tx;\n\tint\t\t\toldvalue;\n\n\tswitch (key)\n\t{\n\t\tcase K_MOUSE1:\n\t\t\tx           = uis.cursorx - s->generic.x - 2*SMALLCHAR_WIDTH;\n\t\t\toldvalue    = s->curvalue;\n\t\t\ts->curvalue = (x/(float)(SLIDER_RANGE*SMALLCHAR_WIDTH)) * (s->maxvalue-s->minvalue) + s->minvalue;\n\n\t\t\tif (s->curvalue < s->minvalue)\n\t\t\t\ts->curvalue = s->minvalue;\n\t\t\telse if (s->curvalue > s->maxvalue)\n\t\t\t\ts->curvalue = s->maxvalue;\n\t\t\tif (s->curvalue != oldvalue)\n\t\t\t\tsound = menu_move_sound;\n\t\t\telse\n\t\t\t\tsound = 0;\n\t\t\tbreak;\n\n\t\tcase K_KP_LEFTARROW:\n\t\tcase K_LEFTARROW:\n\t\t\tif (s->curvalue > s->minvalue)\n\t\t\t{\n\t\t\t\ts->curvalue--;\n\t\t\t\tsound = menu_move_sound;\n\t\t\t}\n\t\t\telse\n\t\t\t\tsound = menu_buzz_sound;\n\t\t\tbreak;\t\t\t\n\n\t\tcase K_KP_RIGHTARROW:\n\t\tcase K_RIGHTARROW:\n\t\t\tif (s->curvalue < s->maxvalue)\n\t\t\t{\n\t\t\t\ts->curvalue++;\n\t\t\t\tsound = menu_move_sound;\n\t\t\t}\n\t\t\telse\n\t\t\t\tsound = menu_buzz_sound;\n\t\t\tbreak;\t\t\t\n\n\t\tdefault:\n\t\t\t// key not handled\n\t\t\tsound = 0;\n\t\t\tbreak;\n\t}\n\n\tif ( sound && s->generic.callback )\n\t\ts->generic.callback( s, QM_ACTIVATED );\n\n\treturn (sound);\n}\n\n#if 1\n/*\n=================\nSlider_Draw\n=================\n*/\nstatic void Slider_Draw( menuslider_s *s ) {\n\tint\t\t\tx;\n\tint\t\t\ty;\n\tint\t\t\tstyle;\n\tfloat\t\t*color;\n\tint\t\t\tbutton;\n\tqboolean\tfocus;\n\t\n\tx =\ts->generic.x;\n\ty = s->generic.y;\n\tfocus = (s->generic.parent->cursor == s->generic.menuPosition);\n\n\tif( s->generic.flags & QMF_GRAYED ) {\n\t\tcolor = text_color_disabled;\n\t\tstyle = UI_SMALLFONT;\n\t}\n\telse if( focus ) {\n\t\tcolor  = text_color_highlight;\n\t\tstyle = UI_SMALLFONT | UI_PULSE;\n\t}\n\telse {\n\t\tcolor = text_color_normal;\n\t\tstyle = UI_SMALLFONT;\n\t}\n\n\t// draw label\n\tUI_DrawString( x - SMALLCHAR_WIDTH, y, s->generic.name, UI_RIGHT|style, color );\n\n\t// draw slider\n\tUI_SetColor( color );\n\tUI_DrawHandlePic( x + SMALLCHAR_WIDTH, y, 96, 16, sliderBar );\n\tUI_SetColor( NULL );\n\n\t// clamp thumb\n\tif( s->maxvalue > s->minvalue )\t{\n\t\ts->range = ( s->curvalue - s->minvalue ) / ( float ) ( s->maxvalue - s->minvalue );\n\t\tif( s->range < 0 ) {\n\t\t\ts->range = 0;\n\t\t}\n\t\telse if( s->range > 1) {\n\t\t\ts->range = 1;\n\t\t}\n\t}\n\telse {\n\t\ts->range = 0;\n\t}\n\n\t// draw thumb\n\tif( style & UI_PULSE) {\n\t\tbutton = sliderButton_1;\n\t}\n\telse {\n\t\tbutton = sliderButton_0;\n\t}\n\n\tUI_DrawHandlePic( (int)( x + 2*SMALLCHAR_WIDTH + (SLIDER_RANGE-1)*SMALLCHAR_WIDTH* s->range ) - 2, y - 2, 12, 20, button );\n}\n#else\n/*\n=================\nSlider_Draw\n=================\n*/\nstatic void Slider_Draw( menuslider_s *s )\n{\n\tfloat *color;\n\tint\tstyle;\n\tint\ti;\n\tint x;\n\tint y;\n\tqboolean focus;\n\t\n\tx =\ts->generic.x;\n\ty = s->generic.y;\n\tfocus = (s->generic.parent->cursor == s->generic.menuPosition);\n\n\tstyle = UI_SMALLFONT;\n\tif ( s->generic.flags & QMF_GRAYED )\n\t{\n\t\tcolor = text_color_disabled;\n\t}\n\telse if (focus)\n\t{\n\t\tcolor  = text_color_highlight;\n\t\tstyle |= UI_PULSE;\n\t}\n\telse\n\t{\n\t\tcolor = text_color_normal;\n\t}\n\n\tif ( focus )\n\t{\n\t\t// draw cursor\n\t\tUI_FillRect( s->generic.left, s->generic.top, s->generic.right-s->generic.left+1, s->generic.bottom-s->generic.top+1, listbar_color ); \n\t\tUI_DrawChar( x, y, 13, UI_CENTER|UI_BLINK|UI_SMALLFONT, color);\n\t}\n\n\t// draw label\n\tUI_DrawString( x - SMALLCHAR_WIDTH, y, s->generic.name, UI_RIGHT|style, color );\n\n\t// draw slider\n\tUI_DrawChar( x + SMALLCHAR_WIDTH, y, 128, UI_LEFT|style, color);\n\tfor ( i = 0; i < SLIDER_RANGE; i++ )\n\t\tUI_DrawChar( x + (i+2)*SMALLCHAR_WIDTH, y, 129, UI_LEFT|style, color);\n\tUI_DrawChar( x + (i+2)*SMALLCHAR_WIDTH, y, 130, UI_LEFT|style, color);\n\n\t// clamp thumb\n\tif (s->maxvalue > s->minvalue)\n\t{\n\t\ts->range = ( s->curvalue - s->minvalue ) / ( float ) ( s->maxvalue - s->minvalue );\n\t\tif ( s->range < 0)\n\t\t\ts->range = 0;\n\t\telse if ( s->range > 1)\n\t\t\ts->range = 1;\n\t}\n\telse\n\t\ts->range = 0;\n\n\t// draw thumb\n\tif (style & UI_PULSE) {\n\t\tstyle &= ~UI_PULSE;\n\t\tstyle |= UI_BLINK;\n\t}\n\tUI_DrawChar( (int)( x + 2*SMALLCHAR_WIDTH + (SLIDER_RANGE-1)*SMALLCHAR_WIDTH* s->range ), y, 131, UI_LEFT|style, color);\n}\n#endif\n\n/*\n=================\nSpinControl_Init\n=================\n*/\nstatic void SpinControl_Init( menulist_s *s ) {\n\tint\tlen;\n\tint\tl;\n\tconst char* str;\n\n\tif (s->generic.name)\n\t\tlen = (int)strlen(s->generic.name) * SMALLCHAR_WIDTH;\n\telse\n\t\tlen = 0;\n\n\ts->generic.left\t= s->generic.x - SMALLCHAR_WIDTH - len;\n\n\tlen = s->numitems = 0;\n\twhile ( (str = s->itemnames[s->numitems]) != 0 )\n\t{\n\t\tl = (int)strlen(str);\n\t\tif (l > len)\n\t\t\tlen = l;\n\n\t\ts->numitems++;\n\t}\t\t\n\n\ts->generic.top\t  =\ts->generic.y;\n\ts->generic.right  =\ts->generic.x + (len+1)*SMALLCHAR_WIDTH;\n\ts->generic.bottom =\ts->generic.y + SMALLCHAR_HEIGHT;\n}\n\n/*\n=================\nSpinControl_Key\n=================\n*/\nstatic sfxHandle_t SpinControl_Key( menulist_s *s, int key )\n{\n\tsfxHandle_t\tsound;\n\n\tsound = 0;\n\tswitch (key)\n\t{\n\t\tcase K_MOUSE1:\n\t\t\ts->curvalue++;\n\t\t\tif (s->curvalue >= s->numitems)\n\t\t\t\ts->curvalue = 0;\n\t\t\tsound = menu_move_sound;\n\t\t\tbreak;\n\t\t\n\t\tcase K_KP_LEFTARROW:\n\t\tcase K_LEFTARROW:\n\t\t\tif (s->curvalue > 0)\n\t\t\t{\n\t\t\t\ts->curvalue--;\n\t\t\t\tsound = menu_move_sound;\n\t\t\t}\n\t\t\telse\n\t\t\t\tsound = menu_buzz_sound;\n\t\t\tbreak;\n\n\t\tcase K_KP_RIGHTARROW:\n\t\tcase K_RIGHTARROW:\n\t\t\tif (s->curvalue < s->numitems-1)\n\t\t\t{\n\t\t\t\ts->curvalue++;\n\t\t\t\tsound = menu_move_sound;\n\t\t\t}\n\t\t\telse\n\t\t\t\tsound = menu_buzz_sound;\n\t\t\tbreak;\n\t}\n\n\tif ( sound && s->generic.callback )\n\t\ts->generic.callback( s, QM_ACTIVATED );\n\n\treturn (sound);\n}\n\n/*\n=================\nSpinControl_Draw\n=================\n*/\nstatic void SpinControl_Draw( menulist_s *s )\n{\n\tfloat *color;\n\tint\tx,y;\n\tint\tstyle;\n\tqboolean focus;\n\n\tx = s->generic.x;\n\ty =\ts->generic.y;\n\n\tstyle = UI_SMALLFONT;\n\tfocus = (s->generic.parent->cursor == s->generic.menuPosition);\n\n\tif ( s->generic.flags & QMF_GRAYED )\n\t\tcolor = text_color_disabled;\n\telse if ( focus )\n\t{\n\t\tcolor = text_color_highlight;\n\t\tstyle |= UI_PULSE;\n\t}\n\telse if ( s->generic.flags & QMF_BLINK )\n\t{\n\t\tcolor = text_color_highlight;\n\t\tstyle |= UI_BLINK;\n\t}\n\telse\n\t\tcolor = text_color_normal;\n\n\tif ( focus )\n\t{\n\t\t// draw cursor\n\t\tUI_FillRect( s->generic.left, s->generic.top, s->generic.right-s->generic.left+1, s->generic.bottom-s->generic.top+1, listbar_color ); \n\t\tUI_DrawChar( x, y, 13, UI_CENTER|UI_BLINK|UI_SMALLFONT, color);\n\t}\n\n\tUI_DrawString( x - SMALLCHAR_WIDTH, y, s->generic.name, style|UI_RIGHT, color );\n\tUI_DrawString( x + SMALLCHAR_WIDTH, y, s->itemnames[s->curvalue], style|UI_LEFT, color );\n}\n\n/*\n=================\nScrollList_Init\n=================\n*/\nstatic void ScrollList_Init( menulist_s *l )\n{\n\tint\t\tw;\n\n\tl->oldvalue = 0;\n\tl->curvalue = 0;\n\tl->top      = 0;\n\n\tif( !l->columns ) {\n\t\tl->columns = 1;\n\t\tl->seperation = 0;\n\t}\n\telse if( !l->seperation ) {\n\t\tl->seperation = 3;\n\t}\n\n\tw = ( (l->width + l->seperation) * l->columns - l->seperation) * SMALLCHAR_WIDTH;\n\n\tl->generic.left   =\tl->generic.x;\n\tl->generic.top    = l->generic.y;\t\n\tl->generic.right  =\tl->generic.x + w;\n\tl->generic.bottom =\tl->generic.y + l->height * SMALLCHAR_HEIGHT;\n\n\tif( l->generic.flags & QMF_CENTER_JUSTIFY ) {\n\t\tl->generic.left -= w / 2;\n\t\tl->generic.right -= w / 2;\n\t}\n}\n\n/*\n=================\nScrollList_Key\n=================\n*/\nsfxHandle_t ScrollList_Key( menulist_s *l, int key )\n{\n\tint\tx;\n\tint\ty;\n\tint\tw;\n\tint\ti;\n\tint\tj;\t\n\tint\tc;\n\tint\tcursorx;\n\tint\tcursory;\n\tint\tcolumn;\n\tint\tindex;\n\n\tswitch (key)\n\t{\n\t\tcase K_MOUSE1:\n\t\t\tif (l->generic.flags & QMF_HASMOUSEFOCUS)\n\t\t\t{\n\t\t\t\t// check scroll region\n\t\t\t\tx = l->generic.x;\n\t\t\t\ty = l->generic.y;\n\t\t\t\tw = ( (l->width + l->seperation) * l->columns - l->seperation) * SMALLCHAR_WIDTH;\n\t\t\t\tif( l->generic.flags & QMF_CENTER_JUSTIFY ) {\n\t\t\t\t\tx -= w / 2;\n\t\t\t\t}\n\t\t\t\tif (UI_CursorInRect( x, y, w, l->height*SMALLCHAR_HEIGHT ))\n\t\t\t\t{\n\t\t\t\t\tcursorx = (uis.cursorx - x)/SMALLCHAR_WIDTH;\n\t\t\t\t\tcolumn = cursorx / (l->width + l->seperation);\n\t\t\t\t\tcursory = (uis.cursory - y)/SMALLCHAR_HEIGHT;\n\t\t\t\t\tindex = column * l->height + cursory;\n\t\t\t\t\tif (l->top + index < l->numitems)\n\t\t\t\t\t{\n\t\t\t\t\t\tl->oldvalue = l->curvalue;\n\t\t\t\t\t\tl->curvalue = l->top + index;\n\n\t\t\t\t\t\tif (l->oldvalue != l->curvalue && l->generic.callback)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tl->generic.callback( l, QM_GOTFOCUS );\n\t\t\t\t\t\t\treturn (menu_move_sound);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\n\t\t\t\t// absorbed, silent sound effect\n\t\t\t\treturn (menu_null_sound);\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase K_KP_HOME:\n\t\tcase K_HOME:\n\t\t\tl->oldvalue = l->curvalue;\n\t\t\tl->curvalue = 0;\n\t\t\tl->top      = 0;\n\n\t\t\tif (l->oldvalue != l->curvalue && l->generic.callback)\n\t\t\t{\n\t\t\t\tl->generic.callback( l, QM_GOTFOCUS );\n\t\t\t\treturn (menu_move_sound);\n\t\t\t}\n\t\t\treturn (menu_buzz_sound);\n\n\t\tcase K_KP_END:\n\t\tcase K_END:\n\t\t\tl->oldvalue = l->curvalue;\n\t\t\tl->curvalue = l->numitems-1;\n\t\t\tif( l->columns > 1 ) {\n\t\t\t\tc = (l->curvalue / l->height + 1) * l->height;\n\t\t\t\tl->top = c - (l->columns * l->height);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tl->top = l->curvalue - (l->height - 1);\n\t\t\t}\n\t\t\tif (l->top < 0)\n\t\t\t\tl->top = 0;\t\t\t\n\n\t\t\tif (l->oldvalue != l->curvalue && l->generic.callback)\n\t\t\t{\n\t\t\t\tl->generic.callback( l, QM_GOTFOCUS );\n\t\t\t\treturn (menu_move_sound);\n\t\t\t}\n\t\t\treturn (menu_buzz_sound);\n\n\t\tcase K_PGUP:\n\t\tcase K_KP_PGUP:\n\t\t\tif( l->columns > 1 ) {\n\t\t\t\treturn menu_null_sound;\n\t\t\t}\n\n\t\t\tif (l->curvalue > 0)\n\t\t\t{\n\t\t\t\tl->oldvalue = l->curvalue;\n\t\t\t\tl->curvalue -= l->height-1;\n\t\t\t\tif (l->curvalue < 0)\n\t\t\t\t\tl->curvalue = 0;\n\t\t\t\tl->top = l->curvalue;\n\t\t\t\tif (l->top < 0)\n\t\t\t\t\tl->top = 0;\n\n\t\t\t\tif (l->generic.callback)\n\t\t\t\t\tl->generic.callback( l, QM_GOTFOCUS );\n\n\t\t\t\treturn (menu_move_sound);\n\t\t\t}\n\t\t\treturn (menu_buzz_sound);\n\n\t\tcase K_PGDN:\n\t\tcase K_KP_PGDN:\n\t\t\tif( l->columns > 1 ) {\n\t\t\t\treturn menu_null_sound;\n\t\t\t}\n\n\t\t\tif (l->curvalue < l->numitems-1)\n\t\t\t{\n\t\t\t\tl->oldvalue = l->curvalue;\n\t\t\t\tl->curvalue += l->height-1;\n\t\t\t\tif (l->curvalue > l->numitems-1)\n\t\t\t\t\tl->curvalue = l->numitems-1;\n\t\t\t\tl->top = l->curvalue - (l->height-1);\n\t\t\t\tif (l->top < 0)\n\t\t\t\t\tl->top = 0;\n\n\t\t\t\tif (l->generic.callback)\n\t\t\t\t\tl->generic.callback( l, QM_GOTFOCUS );\n\n\t\t\t\treturn (menu_move_sound);\n\t\t\t}\n\t\t\treturn (menu_buzz_sound);\n\n\t\tcase K_KP_UPARROW:\n\t\tcase K_UPARROW:\n\t\t\tif( l->curvalue == 0 ) {\n\t\t\t\treturn menu_buzz_sound;\n\t\t\t}\n\n\t\t\tl->oldvalue = l->curvalue;\n\t\t\tl->curvalue--;\n\n\t\t\tif( l->curvalue < l->top ) {\n\t\t\t\tif( l->columns == 1 ) {\n\t\t\t\t\tl->top--;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tl->top -= l->height;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif( l->generic.callback ) {\n\t\t\t\tl->generic.callback( l, QM_GOTFOCUS );\n\t\t\t}\n\n\t\t\treturn (menu_move_sound);\n\n\t\tcase K_KP_DOWNARROW:\n\t\tcase K_DOWNARROW:\n\t\t\tif( l->curvalue == l->numitems - 1 ) {\n\t\t\t\treturn menu_buzz_sound;\n\t\t\t}\n\n\t\t\tl->oldvalue = l->curvalue;\n\t\t\tl->curvalue++;\n\n\t\t\tif( l->curvalue >= l->top + l->columns * l->height ) {\n\t\t\t\tif( l->columns == 1 ) {\n\t\t\t\t\tl->top++;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tl->top += l->height;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif( l->generic.callback ) {\n\t\t\t\tl->generic.callback( l, QM_GOTFOCUS );\n\t\t\t}\n\n\t\t\treturn menu_move_sound;\n\n\t\tcase K_KP_LEFTARROW:\n\t\tcase K_LEFTARROW:\n\t\t\tif( l->columns == 1 ) {\n\t\t\t\treturn menu_null_sound;\n\t\t\t}\n\n\t\t\tif( l->curvalue < l->height ) {\n\t\t\t\treturn menu_buzz_sound;\n\t\t\t}\n\n\t\t\tl->oldvalue = l->curvalue;\n\t\t\tl->curvalue -= l->height;\n\n\t\t\tif( l->curvalue < l->top ) {\n\t\t\t\tl->top -= l->height;\n\t\t\t}\n\n\t\t\tif( l->generic.callback ) {\n\t\t\t\tl->generic.callback( l, QM_GOTFOCUS );\n\t\t\t}\n\n\t\t\treturn menu_move_sound;\n\n\t\tcase K_KP_RIGHTARROW:\n\t\tcase K_RIGHTARROW:\n\t\t\tif( l->columns == 1 ) {\n\t\t\t\treturn menu_null_sound;\n\t\t\t}\n\n\t\t\tc = l->curvalue + l->height;\n\n\t\t\tif( c >= l->numitems ) {\n\t\t\t\treturn menu_buzz_sound;\n\t\t\t}\n\n\t\t\tl->oldvalue = l->curvalue;\n\t\t\tl->curvalue = c;\n\n\t\t\tif( l->curvalue > l->top + l->columns * l->height - 1 ) {\n\t\t\t\tl->top += l->height;\n\t\t\t}\n\n\t\t\tif( l->generic.callback ) {\n\t\t\t\tl->generic.callback( l, QM_GOTFOCUS );\n\t\t\t}\n\n\t\t\treturn menu_move_sound;\n\t}\n\n\t// cycle look for ascii key inside list items\n\tif ( !Q_isprint( key ) )\n\t\treturn (0);\n\n\t// force to lower for case insensitive compare\n\tif ( Q_isupper( key ) )\n\t{\n\t\tkey -= 'A' - 'a';\n\t}\n\n\t// iterate list items\n\tfor (i=1; i<=l->numitems; i++)\n\t{\n\t\tj = (l->curvalue + i) % l->numitems;\n\t\tc = l->itemnames[j][0];\n\t\tif ( Q_isupper( c ) )\n\t\t{\n\t\t\tc -= 'A' - 'a';\n\t\t}\n\n\t\tif (c == key)\n\t\t{\n\t\t\t// set current item, mimic windows listbox scroll behavior\n\t\t\tif (j < l->top)\n\t\t\t{\n\t\t\t\t// behind top most item, set this as new top\n\t\t\t\tl->top = j;\n\t\t\t}\n\t\t\telse if (j > l->top+l->height-1)\n\t\t\t{\n\t\t\t\t// past end of list box, do page down\n\t\t\t\tl->top = (j+1) - l->height;\n\t\t\t}\n\t\t\t\n\t\t\tif (l->curvalue != j)\n\t\t\t{\n\t\t\t\tl->oldvalue = l->curvalue;\n\t\t\t\tl->curvalue = j;\n\t\t\t\tif (l->generic.callback)\n\t\t\t\t\tl->generic.callback( l, QM_GOTFOCUS );\n\t\t\t\treturn ( menu_move_sound );\t\t\t\n\t\t\t}\n\n\t\t\treturn (menu_buzz_sound);\n\t\t}\n\t}\n\n\treturn (menu_buzz_sound);\n}\n\n/*\n=================\nScrollList_Draw\n=================\n*/\nvoid ScrollList_Draw( menulist_s *l )\n{\n\tint\t\t\tx;\n\tint\t\t\tu;\n\tint\t\t\ty;\n\tint\t\t\ti;\n\tint\t\t\tbase;\n\tint\t\t\tcolumn;\n\tfloat*\t\tcolor;\n\tqboolean\thasfocus;\n\tint\t\t\tstyle;\n\n\thasfocus = (l->generic.parent->cursor == l->generic.menuPosition);\n\n\tx =\tl->generic.x;\n\tfor( column = 0; column < l->columns; column++ ) {\n\t\ty =\tl->generic.y;\n\t\tbase = l->top + column * l->height;\n\t\tfor( i = base; i < base + l->height; i++) {\n\t\t\tif (i >= l->numitems)\n\t\t\t\tbreak;\n\n\t\t\tif (i == l->curvalue)\n\t\t\t{\n\t\t\t\tu = x - 2;\n\t\t\t\tif( l->generic.flags & QMF_CENTER_JUSTIFY ) {\n\t\t\t\t\tu -= (l->width * SMALLCHAR_WIDTH) / 2 + 1;\n\t\t\t\t}\n\n\t\t\t\tUI_FillRect(u,y,l->width*SMALLCHAR_WIDTH,SMALLCHAR_HEIGHT+2,listbar_color);\n\t\t\t\tcolor = text_color_highlight;\n\n\t\t\t\tif (hasfocus)\n\t\t\t\t\tstyle = UI_PULSE|UI_LEFT|UI_SMALLFONT;\n\t\t\t\telse\n\t\t\t\t\tstyle = UI_LEFT|UI_SMALLFONT;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcolor = text_color_normal;\n\t\t\t\tstyle = UI_LEFT|UI_SMALLFONT;\n\t\t\t}\n\t\t\tif( l->generic.flags & QMF_CENTER_JUSTIFY ) {\n\t\t\t\tstyle |= UI_CENTER;\n\t\t\t}\n\n\t\t\tUI_DrawString(\n\t\t\t\tx,\n\t\t\t\ty,\n\t\t\t\tl->itemnames[i],\n\t\t\t\tstyle,\n\t\t\t\tcolor);\n\n\t\t\ty += SMALLCHAR_HEIGHT;\n\t\t}\n\t\tx += (l->width + l->seperation) * SMALLCHAR_WIDTH;\n\t}\n}\n\n/*\n=================\nMenu_AddItem\n=================\n*/\nvoid Menu_AddItem( menuframework_s *menu, void *item )\n{\n\tmenucommon_s\t*itemptr;\n\n\tif (menu->nitems >= MAX_MENUITEMS)\n\t\ttrap_Error (\"Menu_AddItem: excessive items\");\n\n\tmenu->items[menu->nitems] = item;\n\t((menucommon_s*)menu->items[menu->nitems])->parent        = menu;\n\t((menucommon_s*)menu->items[menu->nitems])->menuPosition  = menu->nitems;\n\t((menucommon_s*)menu->items[menu->nitems])->flags        &= ~QMF_HASMOUSEFOCUS;\n\n\t// perform any item specific initializations\n\titemptr = (menucommon_s*)item;\n\tif (!(itemptr->flags & QMF_NODEFAULTINIT))\n\t{\n\t\tswitch (itemptr->type)\n\t\t{\n\t\t\tcase MTYPE_ACTION:\n\t\t\t\tAction_Init((menuaction_s*)item);\n\t\t\t\tbreak;\n\n\t\t\tcase MTYPE_FIELD:\n\t\t\t\tMenuField_Init((menufield_s*)item);\n\t\t\t\tbreak;\n\n\t\t\tcase MTYPE_SPINCONTROL:\n\t\t\t\tSpinControl_Init((menulist_s*)item);\n\t\t\t\tbreak;\n\n\t\t\tcase MTYPE_RADIOBUTTON:\n\t\t\t\tRadioButton_Init((menuradiobutton_s*)item);\n\t\t\t\tbreak;\n\n\t\t\tcase MTYPE_SLIDER:\n\t\t\t\tSlider_Init((menuslider_s*)item);\n\t\t\t\tbreak;\n\n\t\t\tcase MTYPE_BITMAP:\n\t\t\t\tBitmap_Init((menubitmap_s*)item);\n\t\t\t\tbreak;\n\n\t\t\tcase MTYPE_TEXT:\n\t\t\t\tText_Init((menutext_s*)item);\n\t\t\t\tbreak;\n\n\t\t\tcase MTYPE_SCROLLLIST:\n\t\t\t\tScrollList_Init((menulist_s*)item);\n\t\t\t\tbreak;\n\n\t\t\tcase MTYPE_PTEXT:\n\t\t\t\tPText_Init((menutext_s*)item);\n\t\t\t\tbreak;\n\n\t\t\tcase MTYPE_BTEXT:\n\t\t\t\tBText_Init((menutext_s*)item);\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\ttrap_Error( va(\"Menu_Init: unknown type %d\", itemptr->type) );\n\t\t}\n\t}\n\n\tmenu->nitems++;\n}\n\n/*\n=================\nMenu_CursorMoved\n=================\n*/\nvoid Menu_CursorMoved( menuframework_s *m )\n{\n\tvoid (*callback)( void *self, int notification );\n\t\n\tif (m->cursor_prev == m->cursor)\n\t\treturn;\n\n\tif (m->cursor_prev >= 0 && m->cursor_prev < m->nitems)\n\t{\n\t\tcallback = ((menucommon_s*)(m->items[m->cursor_prev]))->callback;\n\t\tif (callback)\n\t\t\tcallback(m->items[m->cursor_prev],QM_LOSTFOCUS);\n\t}\n\t\n\tif (m->cursor >= 0 && m->cursor < m->nitems)\n\t{\n\t\tcallback = ((menucommon_s*)(m->items[m->cursor]))->callback;\n\t\tif (callback)\n\t\t\tcallback(m->items[m->cursor],QM_GOTFOCUS);\n\t}\n}\n\n/*\n=================\nMenu_SetCursor\n=================\n*/\nvoid Menu_SetCursor( menuframework_s *m, int cursor )\n{\n\tif (((menucommon_s*)(m->items[cursor]))->flags & (QMF_GRAYED|QMF_INACTIVE))\n\t{\n\t\t// cursor can't go there\n\t\treturn;\n\t}\n\n\tm->cursor_prev = m->cursor;\n\tm->cursor      = cursor;\n\n\tMenu_CursorMoved( m );\n}\n\n/*\n=================\nMenu_SetCursorToItem\n=================\n*/\nvoid Menu_SetCursorToItem( menuframework_s *m, void* ptr )\n{\n\tint\ti;\n\n\tfor (i=0; i<m->nitems; i++)\n\t{\n\t\tif (m->items[i] == ptr)\n\t\t{\n\t\t\tMenu_SetCursor( m, i );\n\t\t\treturn;\n\t\t}\n\t}\n}\n\n/*\n** Menu_AdjustCursor\n**\n** This function takes the given menu, the direction, and attempts\n** to adjust the menu's cursor so that it's at the next available\n** slot.\n*/\nvoid Menu_AdjustCursor( menuframework_s *m, int dir ) {\n\tmenucommon_s\t*item = NULL;\n\tqboolean\t\twrapped = qfalse;\n\nwrap:\n\twhile ( m->cursor >= 0 && m->cursor < m->nitems ) {\n\t\titem = ( menucommon_s * ) m->items[m->cursor];\n\t\tif (( item->flags & (QMF_GRAYED|QMF_MOUSEONLY|QMF_INACTIVE) ) ) {\n\t\t\tm->cursor += dir;\n\t\t}\n\t\telse {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif ( dir == 1 ) {\n\t\tif ( m->cursor >= m->nitems ) {\n\t\t\tif ( m->wrapAround ) {\n\t\t\t\tif ( wrapped ) {\n\t\t\t\t\tm->cursor = m->cursor_prev;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tm->cursor = 0;\n\t\t\t\twrapped = qtrue;\n\t\t\t\tgoto wrap;\n\t\t\t}\n\t\t\tm->cursor = m->cursor_prev;\n\t\t}\n\t}\n\telse {\n\t\tif ( m->cursor < 0 ) {\n\t\t\tif ( m->wrapAround ) {\n\t\t\t\tif ( wrapped ) {\n\t\t\t\t\tm->cursor = m->cursor_prev;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tm->cursor = m->nitems - 1;\n\t\t\t\twrapped = qtrue;\n\t\t\t\tgoto wrap;\n\t\t\t}\n\t\t\tm->cursor = m->cursor_prev;\n\t\t}\n\t}\n}\n\n/*\n=================\nMenu_Draw\n=================\n*/\nvoid Menu_Draw( menuframework_s *menu )\n{\n\tint\t\t\t\ti;\n\tmenucommon_s\t*itemptr;\n\n\t// draw menu\n\tfor (i=0; i<menu->nitems; i++)\n\t{\n\t\titemptr = (menucommon_s*)menu->items[i];\n\n\t\tif (itemptr->flags & QMF_HIDDEN)\n\t\t\tcontinue;\n\n\t\tif (itemptr->ownerdraw)\n\t\t{\n\t\t\t// total subclassing, owner draws everything\n\t\t\titemptr->ownerdraw( itemptr );\n\t\t}\t\n\t\telse \n\t\t{\n\t\t\tswitch (itemptr->type)\n\t\t\t{\t\n\t\t\t\tcase MTYPE_RADIOBUTTON:\n\t\t\t\t\tRadioButton_Draw( (menuradiobutton_s*)itemptr );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase MTYPE_FIELD:\n\t\t\t\t\tMenuField_Draw( (menufield_s*)itemptr );\n\t\t\t\t\tbreak;\n\t\t\n\t\t\t\tcase MTYPE_SLIDER:\n\t\t\t\t\tSlider_Draw( (menuslider_s*)itemptr );\n\t\t\t\t\tbreak;\n \n\t\t\t\tcase MTYPE_SPINCONTROL:\n\t\t\t\t\tSpinControl_Draw( (menulist_s*)itemptr );\n\t\t\t\t\tbreak;\n\t\t\n\t\t\t\tcase MTYPE_ACTION:\n\t\t\t\t\tAction_Draw( (menuaction_s*)itemptr );\n\t\t\t\t\tbreak;\n\t\t\n\t\t\t\tcase MTYPE_BITMAP:\n\t\t\t\t\tBitmap_Draw( (menubitmap_s*)itemptr );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase MTYPE_TEXT:\n\t\t\t\t\tText_Draw( (menutext_s*)itemptr );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase MTYPE_SCROLLLIST:\n\t\t\t\t\tScrollList_Draw( (menulist_s*)itemptr );\n\t\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\tcase MTYPE_PTEXT:\n\t\t\t\t\tPText_Draw( (menutext_s*)itemptr );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase MTYPE_BTEXT:\n\t\t\t\t\tBText_Draw( (menutext_s*)itemptr );\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\ttrap_Error( va(\"Menu_Draw: unknown type %d\", itemptr->type) );\n\t\t\t}\n\t\t}\n#ifndef NDEBUG\n\t\tif( uis.debug ) {\n\t\t\tint\tx;\n\t\t\tint\ty;\n\t\t\tint\tw;\n\t\t\tint\th;\n\n\t\t\tif( !( itemptr->flags & QMF_INACTIVE ) ) {\n\t\t\t\tx = itemptr->left;\n\t\t\t\ty = itemptr->top;\n\t\t\t\tw = itemptr->right - itemptr->left + 1;\n\t\t\t\th =\titemptr->bottom - itemptr->top + 1;\n\n\t\t\t\tif (itemptr->flags & QMF_HASMOUSEFOCUS) {\n\t\t\t\t\tUI_DrawRect(x, y, w, h, colorYellow );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tUI_DrawRect(x, y, w, h, colorWhite );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n#endif\n\t}\n\n\titemptr = Menu_ItemAtCursor( menu );\n\tif ( itemptr && itemptr->statusbar)\n\t\titemptr->statusbar( ( void * ) itemptr );\n}\n\n/*\n=================\nMenu_ItemAtCursor\n=================\n*/\nvoid *Menu_ItemAtCursor( menuframework_s *m )\n{\n\tif ( m->cursor < 0 || m->cursor >= m->nitems )\n\t\treturn 0;\n\n\treturn m->items[m->cursor];\n}\n\n/*\n=================\nMenu_ActivateItem\n=================\n*/\nsfxHandle_t Menu_ActivateItem( menuframework_s *s, menucommon_s* item ) {\n\tif ( item->callback ) {\n\t\titem->callback( item, QM_ACTIVATED );\n\t\tif( !( item->flags & QMF_SILENT ) ) {\n\t\t\treturn menu_move_sound;\n\t\t}\n\t}\n\n\treturn 0;\n}\n\n/*\n=================\nMenu_DefaultKey\n=================\n*/\nsfxHandle_t Menu_DefaultKey( menuframework_s *m, int key )\n{\n\tsfxHandle_t\t\tsound = 0;\n\tmenucommon_s\t*item;\n\tint\t\t\t\tcursor_prev;\n\n\t// menu system keys\n\tswitch ( key )\n\t{\n\t\tcase K_MOUSE2:\n\t\tcase K_ESCAPE:\n\t\t\tUI_PopMenu();\n\t\t\treturn menu_out_sound;\n\t}\n\n\tif (!m || !m->nitems)\n\t\treturn 0;\n\n\t// route key stimulus to widget\n\titem = Menu_ItemAtCursor( m );\n\tif (item && !(item->flags & (QMF_GRAYED|QMF_INACTIVE)))\n\t{\n\t\tswitch (item->type)\n\t\t{\n\t\t\tcase MTYPE_SPINCONTROL:\n\t\t\t\tsound = SpinControl_Key( (menulist_s*)item, key );\n\t\t\t\tbreak;\n\n\t\t\tcase MTYPE_RADIOBUTTON:\n\t\t\t\tsound = RadioButton_Key( (menuradiobutton_s*)item, key );\n\t\t\t\tbreak;\n\n\t\t\tcase MTYPE_SLIDER:\n\t\t\t\tsound = Slider_Key( (menuslider_s*)item, key );\n\t\t\t\tbreak;\n\n\t\t\tcase MTYPE_SCROLLLIST:\n\t\t\t\tsound = ScrollList_Key( (menulist_s*)item, key );\n\t\t\t\tbreak;\n\n\t\t\tcase MTYPE_FIELD:\n\t\t\t\tsound = MenuField_Key( (menufield_s*)item, &key );\n\t\t\t\tbreak;\n\t\t}\n\n\t\tif (sound) {\n\t\t\t// key was handled\n\t\t\treturn sound;\t\t\n\t\t}\n\t}\n\n\t// default handling\n\tswitch ( key )\n\t{\n#ifndef NDEBUG\n\t\tcase K_F11:\n\t\t\tuis.debug ^= 1;\n\t\t\tbreak;\n\n\t\tcase K_F12:\n\t\t\ttrap_Cmd_ExecuteText(EXEC_APPEND, \"screenshot\\n\");\n\t\t\tbreak;\n#endif\n\t\tcase K_KP_UPARROW:\n\t\tcase K_UPARROW:\n\t\t\tcursor_prev    = m->cursor;\n\t\t\tm->cursor_prev = m->cursor;\n\t\t\tm->cursor--;\n\t\t\tMenu_AdjustCursor( m, -1 );\n\t\t\tif ( cursor_prev != m->cursor ) {\n\t\t\t\tMenu_CursorMoved( m );\n\t\t\t\tsound = menu_move_sound;\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase K_TAB:\n\t\tcase K_KP_DOWNARROW:\n\t\tcase K_DOWNARROW:\n\t\t\tcursor_prev    = m->cursor;\n\t\t\tm->cursor_prev = m->cursor;\n\t\t\tm->cursor++;\n\t\t\tMenu_AdjustCursor( m, 1 );\n\t\t\tif ( cursor_prev != m->cursor ) {\n\t\t\t\tMenu_CursorMoved( m );\n\t\t\t\tsound = menu_move_sound;\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase K_MOUSE1:\n\t\tcase K_MOUSE3:\n\t\t\tif (item)\n\t\t\t\tif ((item->flags & QMF_HASMOUSEFOCUS) && !(item->flags & (QMF_GRAYED|QMF_INACTIVE)))\n\t\t\t\t\treturn (Menu_ActivateItem( m, item ));\n\t\t\tbreak;\n\n\t\tcase K_JOY1:\n\t\tcase K_JOY2:\n\t\tcase K_JOY3:\n\t\tcase K_JOY4:\n\t\tcase K_AUX1:\n\t\tcase K_AUX2:\n\t\tcase K_AUX3:\n\t\tcase K_AUX4:\n\t\tcase K_AUX5:\n\t\tcase K_AUX6:\n\t\tcase K_AUX7:\n\t\tcase K_AUX8:\n\t\tcase K_AUX9:\n\t\tcase K_AUX10:\n\t\tcase K_AUX11:\n\t\tcase K_AUX12:\n\t\tcase K_AUX13:\n\t\tcase K_AUX14:\n\t\tcase K_AUX15:\n\t\tcase K_AUX16:\n\t\tcase K_KP_ENTER:\n\t\tcase K_ENTER:\n\t\t\tif (item)\n\t\t\t\tif (!(item->flags & (QMF_MOUSEONLY|QMF_GRAYED|QMF_INACTIVE)))\n\t\t\t\t\treturn (Menu_ActivateItem( m, item ));\n\t\t\tbreak;\n\t}\n\n\treturn sound;\n}\n\n/*\n=================\nMenu_Cache\n=================\n*/\nvoid Menu_Cache( void )\n{\n\tuis.charset\t\t\t= trap_R_RegisterShaderNoMip( \"gfx/2d/bigchars\" );\n\tuis.charsetProp\t\t= trap_R_RegisterShaderNoMip( \"menu/art/font1_prop.tga\" );\n\tuis.charsetPropGlow\t= trap_R_RegisterShaderNoMip( \"menu/art/font1_prop_glo.tga\" );\n\tuis.charsetPropB\t= trap_R_RegisterShaderNoMip( \"menu/art/font2_prop.tga\" );\n\tuis.cursor          = trap_R_RegisterShaderNoMip( \"menu/art/3_cursor2\" );\n\tuis.rb_on           = trap_R_RegisterShaderNoMip( \"menu/art/switch_on\" );\n\tuis.rb_off          = trap_R_RegisterShaderNoMip( \"menu/art/switch_off\" );\n\n\tuis.whiteShader = trap_R_RegisterShaderNoMip( \"white\" );\n\tuis.menuBackShader\t= trap_R_RegisterShaderNoMip( \"menuback\" );\n\tuis.menuBackNoLogoShader = trap_R_RegisterShaderNoMip( \"menubacknologo\" );\n\n\tmenu_in_sound\t= trap_S_RegisterSound( \"sound/misc/menu1.wav\", qfalse );\n\tmenu_move_sound\t= trap_S_RegisterSound( \"sound/misc/menu2.wav\", qfalse );\n\tmenu_out_sound\t= trap_S_RegisterSound( \"sound/misc/menu3.wav\", qfalse );\n\tmenu_buzz_sound\t= trap_S_RegisterSound( \"sound/misc/menu4.wav\", qfalse );\n\tweaponChangeSound\t= trap_S_RegisterSound( \"sound/weapons/change.wav\", qfalse );\n\n\t// need a nonzero sound, make an empty sound for this\n\tmenu_null_sound = -1;\n\n\tsliderBar = trap_R_RegisterShaderNoMip( \"menu/art/slider2\" );\n\tsliderButton_0 = trap_R_RegisterShaderNoMip( \"menu/art/sliderbutt_0\" );\n\tsliderButton_1 = trap_R_RegisterShaderNoMip( \"menu/art/sliderbutt_1\" );\n}\n\t\n"
  },
  {
    "path": "src/q3_ui/ui_rankings.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n//\n// ui_rankings.c\n//\n\n#include \"ui_local.h\"\n\n\n#define RANKINGS_FRAME\t\"menu/art/cut_frame\"\n\n#define ID_LOGIN\t\t100\n#define ID_LOGOUT\t\t101\n#define ID_CREATE\t\t102\n#define ID_SPECTATE\t\t103\n#define ID_SETUP\t\t104\n#define ID_LEAVE\t\t105\n\n\ntypedef struct\n{\n\tmenuframework_s\tmenu;\n\tmenubitmap_s\tframe;\n\tmenutext_s\t\tlogin;\n\tmenutext_s\t\tlogout;\n\tmenutext_s\t\tcreate;\n\tmenutext_s\t\tspectate;\n\tmenutext_s\t\tsetup;\n\tmenutext_s\t\tleave;\n} rankings_t;\n\nstatic rankings_t\ts_rankings;\n\nstatic menuframework_s\ts_rankings_menu;\nstatic menuaction_s\t\ts_rankings_login;\nstatic menuaction_s\t\ts_rankings_logout;\nstatic menuaction_s\t\ts_rankings_create;\nstatic menuaction_s\t\ts_rankings_spectate;\nstatic menuaction_s\t\ts_rankings_setup;\nstatic menuaction_s\t\ts_rankings_leave;\n\n\n/*\n===============\nRankings_DrawText\n===============\n*/\nvoid Rankings_DrawText( void* self )\n{\n\tmenufield_s\t\t*f;\n\tqboolean\t\tfocus;\n\tint\t\t\t\tstyle;\n\tchar\t\t\t*txt;\n\tchar\t\t\tc;\n\tfloat\t\t\t*color;\n\tint\t\t\t\tbasex, x, y;\n\n\tf = (menufield_s*)self;\n\tbasex = f->generic.x;\n\ty = f->generic.y + 4;\n\tfocus = (f->generic.parent->cursor == f->generic.menuPosition);\n\n\tstyle = UI_LEFT|UI_SMALLFONT;\n\tcolor = text_color_normal;\n\tif( focus ) {\n\t\tstyle |= UI_PULSE;\n\t\tcolor = text_color_highlight;\n\t}\n\n\t// draw the actual text\n\ttxt = f->field.buffer;\n\tcolor = g_color_table[ColorIndex(COLOR_WHITE)];\n\tx = basex;\n\twhile ( (c = *txt) != 0 ) {\n\t\tUI_DrawChar( x, y, c, style, color );\n\t\ttxt++;\n\t\tx += SMALLCHAR_WIDTH;\n\t}\n\n\t// draw cursor if we have focus\n\tif( focus ) {\n\t\tif ( trap_Key_GetOverstrikeMode() ) {\n\t\t\tc = 11;\n\t\t} else {\n\t\t\tc = 10;\n\t\t}\n\n\t\tstyle &= ~UI_PULSE;\n\t\tstyle |= UI_BLINK;\n\n\t\tUI_DrawChar( basex + f->field.cursor * SMALLCHAR_WIDTH, y, c, style, color_white );\n\t}\n}\n\n/*\n===============\nRankings_DrawName\n===============\n*/\nvoid Rankings_DrawName( void* self )\n{\n\tmenufield_s\t\t*f;\n\tint\t\t\t\tlength;\n\tchar*\t\t\tp;\n\t\n\tf = (menufield_s*)self;\n\n\t// GRANK_FIXME - enforce valid characters\n\tfor( p = f->field.buffer; *p != '\\0'; p++ )\n\t{\n\t\t//if( ispunct(*p) || isspace(*p) )\n\t\tif( !( ( (*p) >= '0' && (*p) <= '9') || Q_isalpha(*p)) )\n\t\t{\n\t\t\t*p = '\\0';\n\t\t}\n\t}\n\t\n\t// strip color codes\n\tQ_CleanStr( f->field.buffer );\n\tlength = strlen( f->field.buffer );\n\tif( f->field.cursor > length )\n\t{\n\t\tf->field.cursor = length;\n\t}\t\n\n\tRankings_DrawText( f );\n}\n\n#if 0 // old version\n/*\n===============\nRankings_DrawName\n===============\n*/\nvoid Rankings_DrawName( void* self )\n{\n\tmenufield_s*\tf;\n\tint\t\t\t\tlength;\n\t\n\tf = (menufield_s*)self;\n\n\t// strip color codes\n\tQ_CleanStr( f->field.buffer );\n\tlength = strlen( f->field.buffer );\n\tif( f->field.cursor > length )\n\t{\n\t\tf->field.cursor = length;\n\t}\n\t\n\t// show beginning of long names\n\t/*\n\tif( Menu_ItemAtCursor( f->generic.parent ) != f )\n\t{\n\t\tif( f->field.scroll > 0 )\n\t\t{\n\t\t\tf->field.cursor = 0;\n\t\t\tf->field.scroll = 0;\n\t\t}\n\t}\n\t*/\n\t\n\tMenuField_Draw( f );\n}\n#endif\n\n/*\n===============\nRankings_DrawPassword\n===============\n*/\nvoid Rankings_DrawPassword( void* self )\n{\n\tmenufield_s*\tf;\n\tchar\t\t\tpassword[MAX_EDIT_LINE];\n\tint\t\t\t\tlength;\n\tint\t\t\t\ti;\n\tchar*\t\t\tp;\n\n\tf = (menufield_s*)self;\n\t\n\t// GRANK_FIXME - enforce valid characters\n\tfor( p = f->field.buffer; *p != '\\0'; p++ )\n\t{\n\t\t//if( ispunct(*p) || isspace(*p) )\n\t\tif( !( ( (*p) >= '0' && (*p) <= '9') || Q_isalpha(*p)) )\n\t\t{\n\t\t\t*p = '\\0';\n\t\t}\n\t}\n\t\n\tlength = strlen( f->field.buffer );\n\tif( f->field.cursor > length )\n\t{\n\t\tf->field.cursor = length;\n\t}\n\t\n\t// save password\n\tQ_strncpyz( password, f->field.buffer, sizeof(password) );\n\n\t// mask password with *\n\tfor( i = 0; i < length; i++ )\n\t{\n\t\tf->field.buffer[i] = '*';\n\t}\n\n\t// draw masked password\n\tRankings_DrawText( f );\n\t//MenuField_Draw( f );\n\n\t// restore password\n\tQ_strncpyz( f->field.buffer, password, sizeof(f->field.buffer) );\n}\n\n/*\n===============\nRankings_MenuEvent\n===============\n*/\nstatic void Rankings_MenuEvent( void* ptr, int event ) {\n\tif( event != QM_ACTIVATED ) {\n\t\treturn;\n\t}\n\n\tswitch( ((menucommon_s*)ptr)->id ) {\n\tcase ID_LOGIN:\n\t\tUI_LoginMenu();\n\t\tbreak;\n\n\tcase ID_LOGOUT:\n\t\t// server side masqueraded player logout first\n\t\ttrap_CL_UI_RankUserRequestLogout();\n\t\tUI_ForceMenuOff();\n\t\tbreak;\n\t\t\n\tcase ID_CREATE:\n\t\tUI_SignupMenu();\n\t\tbreak;\n\n\tcase ID_SPECTATE:\n\t\ttrap_Cmd_ExecuteText( EXEC_APPEND, \"cmd rank_spectate\\n\" );\n\t\tUI_ForceMenuOff();\n\t\tbreak;\n\n\tcase ID_SETUP:\n\t\tUI_SetupMenu();\n\t\tbreak;\n\t\t\n\tcase ID_LEAVE:\n\t\ttrap_Cmd_ExecuteText( EXEC_APPEND, \"disconnect\\n\" );\n\t\tUI_ForceMenuOff();\n\t\tbreak;\n\n\t}\n}\n\n\n/*\n===============\nRankings_MenuInit\n===============\n*/\nvoid Rankings_MenuInit( void ) {\n\tgrank_status_t\tstatus;\n\tint\t\t\t\ty;\n\n\tmemset( &s_rankings, 0, sizeof(s_rankings) );\n\n\tRankings_Cache();\n\n\ts_rankings.menu.wrapAround = qtrue;\n\ts_rankings.menu.fullscreen = qfalse;\n\n\ts_rankings.frame.generic.type\t\t= MTYPE_BITMAP;\n\ts_rankings.frame.generic.flags\t\t= QMF_INACTIVE;\n\ts_rankings.frame.generic.name\t\t= RANKINGS_FRAME;\n\ts_rankings.frame.generic.x\t\t\t= 142;\n\ts_rankings.frame.generic.y\t\t\t= 118;\n\ts_rankings.frame.width\t\t\t\t= 359;\n\ts_rankings.frame.height\t\t\t\t= 256;\n\n\ty = 194;\n\n\ts_rankings.login.generic.type\t\t= MTYPE_PTEXT;\n\ts_rankings.login.generic.flags\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_rankings.login.generic.id\t\t\t= ID_LOGIN;\n\ts_rankings.login.generic.callback\t= Rankings_MenuEvent;\n\ts_rankings.login.generic.x\t\t\t= 320;\n\ts_rankings.login.generic.y\t\t\t= y;\n\ts_rankings.login.string\t\t\t\t= \"LOGIN\";\n\ts_rankings.login.style\t\t\t\t= UI_CENTER|UI_SMALLFONT;\n\ts_rankings.login.color\t\t\t\t= colorRed;\n\ty += 20;\n\n\ts_rankings.logout.generic.type\t\t= MTYPE_PTEXT;\n\ts_rankings.logout.generic.flags\t\t= QMF_HIDDEN|QMF_INACTIVE|QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_rankings.logout.generic.id\t\t= ID_LOGOUT;\n\ts_rankings.logout.generic.callback\t= Rankings_MenuEvent;\n\ts_rankings.logout.generic.x\t\t\t= 320;\n\ts_rankings.logout.generic.y\t\t\t= y;\n\ts_rankings.logout.string\t\t\t\t= \"LOGOUT\";\n\ts_rankings.logout.style\t\t\t\t= UI_CENTER|UI_SMALLFONT;\n\ts_rankings.logout.color\t\t\t\t= colorRed;\n\n\ts_rankings.create.generic.type\t\t= MTYPE_PTEXT;\n\ts_rankings.create.generic.flags\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_rankings.create.generic.id\t\t= ID_CREATE;\n\ts_rankings.create.generic.callback\t= Rankings_MenuEvent;\n\ts_rankings.create.generic.x\t\t\t= 320;\n\ts_rankings.create.generic.y\t\t\t= y;\n\ts_rankings.create.string\t\t\t= \"SIGN UP\";\n\ts_rankings.create.style\t\t\t\t= UI_CENTER|UI_SMALLFONT;\n\ts_rankings.create.color\t\t\t\t= colorRed;\n\ty += 20;\n\n\ts_rankings.spectate.generic.type\t\t= MTYPE_PTEXT;\n\ts_rankings.spectate.generic.flags\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_rankings.spectate.generic.id\t\t\t= ID_SPECTATE;\n\ts_rankings.spectate.generic.callback\t= Rankings_MenuEvent;\n\ts_rankings.spectate.generic.x\t\t\t= 320;\n\ts_rankings.spectate.generic.y\t\t\t= y;\n\ts_rankings.spectate.string\t\t\t\t= \"SPECTATE\";\n\ts_rankings.spectate.style\t\t\t\t= UI_CENTER|UI_SMALLFONT;\n\ts_rankings.spectate.color\t\t\t\t= colorRed;\n\ty += 20;\n\n\ts_rankings.setup.generic.type\t\t= MTYPE_PTEXT;\n\ts_rankings.setup.generic.flags\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_rankings.setup.generic.id\t\t\t= ID_SETUP;\n\ts_rankings.setup.generic.callback\t= Rankings_MenuEvent;\n\ts_rankings.setup.generic.x\t\t\t= 320;\n\ts_rankings.setup.generic.y\t\t\t= y;\n\ts_rankings.setup.string\t\t\t\t= \"SETUP\";\n\ts_rankings.setup.style\t\t\t\t= UI_CENTER|UI_SMALLFONT;\n\ts_rankings.setup.color\t\t\t\t= colorRed;\n\ty += 20;\n\n\ts_rankings.leave.generic.type\t\t= MTYPE_PTEXT;\n\ts_rankings.leave.generic.flags\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_rankings.leave.generic.id\t\t\t= ID_LEAVE;\n\ts_rankings.leave.generic.callback\t= Rankings_MenuEvent;\n\ts_rankings.leave.generic.x\t\t\t= 320;\n\ts_rankings.leave.generic.y\t\t\t= y;\n\ts_rankings.leave.string\t\t\t\t= \"LEAVE ARENA\";\n\ts_rankings.leave.style\t\t\t\t= UI_CENTER|UI_SMALLFONT;\n\ts_rankings.leave.color\t\t\t\t= colorRed;\n\ty += 20;\n\n\tstatus = (grank_status_t)trap_Cvar_VariableValue(\"client_status\");\n\tif( (status != QGR_STATUS_NEW) && (status != QGR_STATUS_SPECTATOR) )\n\t{\n\t\ts_rankings.login.generic.flags |= QMF_HIDDEN | QMF_INACTIVE;\t\n\t\ts_rankings.create.generic.flags |= QMF_HIDDEN | QMF_INACTIVE;\n\t\ts_rankings.spectate.generic.flags |= QMF_HIDDEN | QMF_INACTIVE;\n\n\t\ts_rankings.logout.generic.flags &= ~(QMF_HIDDEN | QMF_INACTIVE);\n\t}\n\t\n\tif ( (status == QGR_STATUS_VALIDATING) ||\n\t\t (status == QGR_STATUS_PENDING) ||\n\t\t (status == QGR_STATUS_LEAVING) )\n\t{\n\t\ts_rankings.login.generic.flags  |= QMF_GRAYED;\n\t\ts_rankings.create.generic.flags |= QMF_GRAYED;\n\t\ts_rankings.logout.generic.flags |= QMF_GRAYED;\n\t}\n\t\n\t//GRank FIXME -- don't need setup option any more\n\ts_rankings.setup.generic.flags |= QMF_HIDDEN | QMF_INACTIVE;\n\n\tMenu_AddItem( &s_rankings.menu, (void*) &s_rankings.frame );\n\tMenu_AddItem( &s_rankings.menu, (void*) &s_rankings.login );\n\tMenu_AddItem( &s_rankings.menu, (void*) &s_rankings.logout );\n\tMenu_AddItem( &s_rankings.menu, (void*) &s_rankings.create );\n\tMenu_AddItem( &s_rankings.menu, (void*) &s_rankings.spectate );\n\tMenu_AddItem( &s_rankings.menu, (void*) &s_rankings.setup );\n\tMenu_AddItem( &s_rankings.menu, (void*) &s_rankings.leave );\n}\n\n\n/*\n===============\nRankings_Cache\n===============\n*/\nvoid Rankings_Cache( void ) {\n\ttrap_R_RegisterShaderNoMip( RANKINGS_FRAME );\n}\n\n\n/*\n===============\nUI_RankingsMenu\n===============\n*/\nvoid UI_RankingsMenu( void ) {\n\tRankings_MenuInit();\n\tUI_PushMenu ( &s_rankings.menu );\n}\n\n\n"
  },
  {
    "path": "src/q3_ui/ui_rankstatus.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n//\n// ui_rankstatus.c\n//\n\n#include \"ui_local.h\"\n\n\n#define RANKSTATUS_FRAME\t\t\"menu/art/cut_frame\"\n\n#define ID_MESSAGE\t\t100\n#define ID_OK\t\t\t101\n\n\ntypedef struct\n{\n\tmenuframework_s\tmenu;\n\tmenubitmap_s\tframe;\n\tmenutext_s\t\tmessage;\n\tmenutext_s\t\tok;\n} rankstatus_t;\n\nstatic rankstatus_t\ts_rankstatus;\n\nstatic menuframework_s\ts_rankstatus_menu;\nstatic menuaction_s\t\ts_rankstatus_ok;\n\nstatic grank_status_t\ts_status = 0;\nstatic char*\t\t\ts_rankstatus_message = NULL;\n\nstatic vec4_t s_rankingstatus_color_prompt  = {1.00, 0.43, 0.00, 1.00};\n\n/*\n===============\nRankStatus_MenuEvent\n===============\n*/\nstatic void RankStatus_MenuEvent( void* ptr, int event ) {\n\tif( event != QM_ACTIVATED ) {\n\t\treturn;\n\t}\n\n\tswitch( ((menucommon_s*)ptr)->id ) {\n\tcase ID_OK:\n\t\tUI_PopMenu();\n\t\t\n\t\tswitch( s_status )\n\t\t{\n\t\tcase QGR_STATUS_NO_USER:\n\t\t\tUI_RankingsMenu();\n\t\t\tbreak;\n\t\tcase QGR_STATUS_BAD_PASSWORD:\n\t\t\tUI_RankingsMenu();\n\t\t\tUI_LoginMenu();\n\t\t\tbreak;\n\t\tcase QGR_STATUS_USER_EXISTS:\n\t\t\tUI_RankingsMenu();\n\t\t\tUI_SignupMenu();\n\t\t\tbreak;\n\t\tcase QGR_STATUS_NO_MEMBERSHIP:\n\t\t\tUI_RankingsMenu();\n\t\t\tbreak;\n\t\tcase QGR_STATUS_TIMEOUT:\n\t\t\tUI_RankingsMenu();\n\t\t\tbreak;\n\t\tcase QGR_STATUS_INVALIDUSER:\n\t\t\tUI_RankingsMenu();\n\t\t\tbreak;\n\t\tcase QGR_STATUS_ERROR:\n\t\t\tUI_RankingsMenu();\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\n\t\tbreak;\n\t}\n}\n\n\n/*\n===============\nRankStatus_MenuInit\n===============\n*/\nvoid RankStatus_MenuInit( void ) {\n\tint\t\ty;\n\n\tmemset( &s_rankstatus, 0, sizeof(s_rankstatus) );\n\n\tRankStatus_Cache();\n\n\ts_rankstatus.menu.wrapAround = qtrue;\n\ts_rankstatus.menu.fullscreen = qfalse;\n\n\ts_rankstatus.frame.generic.type\t\t\t= MTYPE_BITMAP;\n\ts_rankstatus.frame.generic.flags\t\t= QMF_INACTIVE;\n\ts_rankstatus.frame.generic.name\t\t\t= RANKSTATUS_FRAME;\n\ts_rankstatus.frame.generic.x\t\t\t= 142; //320-233;\n\ts_rankstatus.frame.generic.y\t\t\t= 118; //240-166;\n\ts_rankstatus.frame.width\t\t\t\t= 359; //466;\n\ts_rankstatus.frame.height\t\t\t\t= 256; //332;\n\n\ty = 214;\n\n\ts_rankstatus.message.generic.type\t\t\t= MTYPE_PTEXT;\n\ts_rankstatus.message.generic.flags\t\t\t= QMF_CENTER_JUSTIFY|QMF_INACTIVE;\n\ts_rankstatus.message.generic.id\t\t\t\t= ID_MESSAGE;\n\ts_rankstatus.message.generic.x\t\t\t\t= 320;\n\ts_rankstatus.message.generic.y\t\t\t\t= y;\n\ts_rankstatus.message.string\t\t\t\t\t= s_rankstatus_message;\n\ts_rankstatus.message.style\t\t\t\t\t= UI_CENTER|UI_SMALLFONT;\n\ts_rankstatus.message.color\t\t\t\t\t= s_rankingstatus_color_prompt;\n\ty += 40;\n\n\ts_rankstatus.ok.generic.type\t\t\t\t= MTYPE_PTEXT;\n\ts_rankstatus.ok.generic.flags\t\t\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_rankstatus.ok.generic.id\t\t\t\t\t= ID_OK;\n\ts_rankstatus.ok.generic.callback\t\t\t= RankStatus_MenuEvent;\n\ts_rankstatus.ok.generic.x\t\t\t\t\t= 320;\n\ts_rankstatus.ok.generic.y\t\t\t\t\t= y;\n\ts_rankstatus.ok.string\t\t\t\t\t\t= \"OK\";\n\ts_rankstatus.ok.style\t\t\t\t\t\t= UI_CENTER|UI_SMALLFONT;\n\ts_rankstatus.ok.color\t\t\t\t\t\t= colorRed;\n\n\tMenu_AddItem( &s_rankstatus.menu, (void*) &s_rankstatus.frame );\n\tMenu_AddItem( &s_rankstatus.menu, (void*) &s_rankstatus.message );\n\tMenu_AddItem( &s_rankstatus.menu, (void*) &s_rankstatus.ok );\n}\n\n\n/*\n===============\nRankStatus_Cache\n===============\n*/\nvoid RankStatus_Cache( void ) {\n\ttrap_R_RegisterShaderNoMip( RANKSTATUS_FRAME );\n}\n\n\n/*\n===============\nUI_RankStatusMenu\n===============\n*/\nvoid UI_RankStatusMenu( void ) {\n\n\ts_status = (grank_status_t)trap_Cvar_VariableValue(\"client_status\");\n\n\tswitch( s_status )\n\t{\n\tcase QGR_STATUS_NEW:\n\t\treturn;\n\tcase QGR_STATUS_PENDING:\n\t\t// GRANK_FIXME\n\t\treturn;\n\tcase QGR_STATUS_NO_USER:\n\t\t// GRANK_FIXME - get this when user exists\n\t\ts_rankstatus_message = \"Username unavailable\";\n\t\tbreak;\n\tcase QGR_STATUS_BAD_PASSWORD:\n\t\ts_rankstatus_message = \"Invalid password\";\n\t\tbreak;\n\tcase QGR_STATUS_TIMEOUT:\n\t\ts_rankstatus_message = \"Timed out\";\n\t\tbreak;\n\tcase QGR_STATUS_NO_MEMBERSHIP:\n\t\ts_rankstatus_message = \"No membership\";\n\t\tbreak;\n\tcase QGR_STATUS_INVALIDUSER:\n\t\ts_rankstatus_message = \"Validation failed\";\n\t\tbreak;\n\tcase QGR_STATUS_ERROR:\n\t\ts_rankstatus_message = \"Error\";\n\t\tbreak;\n\tcase QGR_STATUS_SPECTATOR:\n\tcase QGR_STATUS_ACTIVE:\n\t\tUI_ForceMenuOff();\n\t\treturn;\n\tdefault:\n\t\treturn;\n\t}\n\tRankStatus_MenuInit();\n\ttrap_CL_UI_RankUserReset();\n\tUI_PushMenu ( &s_rankstatus.menu );\n}\n\n"
  },
  {
    "path": "src/q3_ui/ui_removebots.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n/*\n=======================================================================\n\nREMOVE BOTS MENU\n\n=======================================================================\n*/\n\n\n#include \"ui_local.h\"\n\n\n#define ART_BACKGROUND\t\t\"menu/art/addbotframe\"\n#define ART_BACK0\t\t\t\"menu/art/back_0\"\n#define ART_BACK1\t\t\t\"menu/art/back_1\"\t\n#define ART_DELETE0\t\t\t\"menu/art/delete_0\"\n#define ART_DELETE1\t\t\t\"menu/art/delete_1\"\n#define ART_ARROWS\t\t\t\"menu/art/arrows_vert_0\"\n#define ART_ARROWUP\t\t\t\"menu/art/arrows_vert_top\"\n#define ART_ARROWDOWN\t\t\"menu/art/arrows_vert_bot\"\n\n#define ID_UP\t\t\t\t10\n#define ID_DOWN\t\t\t\t11\n#define ID_DELETE\t\t\t12\n#define ID_BACK\t\t\t\t13\n#define ID_BOTNAME0\t\t\t20\n#define ID_BOTNAME1\t\t\t21\n#define ID_BOTNAME2\t\t\t22\n#define ID_BOTNAME3\t\t\t23\n#define ID_BOTNAME4\t\t\t24\n#define ID_BOTNAME5\t\t\t25\n#define ID_BOTNAME6\t\t\t26\n\n\ntypedef struct {\n\tmenuframework_s\tmenu;\n\n\tmenutext_s\t\tbanner;\n\tmenubitmap_s\tbackground;\n\n\tmenubitmap_s\tarrows;\n\tmenubitmap_s\tup;\n\tmenubitmap_s\tdown;\n\n\tmenutext_s\t\tbots[7];\n\n\tmenubitmap_s\tdelete;\n\tmenubitmap_s\tback;\n\n\tint\t\t\t\tnumBots;\n\tint\t\t\t\tbaseBotNum;\n\tint\t\t\t\tselectedBotNum;\n\tchar\t\t\tbotnames[7][32];\n\tint\t\t\t\tbotClientNums[MAX_BOTS];\n} removeBotsMenuInfo_t;\n\nstatic removeBotsMenuInfo_t\tremoveBotsMenuInfo;\n\n\n/*\n=================\nUI_RemoveBotsMenu_SetBotNames\n=================\n*/\nstatic void UI_RemoveBotsMenu_SetBotNames( void ) {\n\tint\t\tn;\n\tchar\tinfo[MAX_INFO_STRING];\n\n\tfor ( n = 0; (n < 7) && (removeBotsMenuInfo.baseBotNum + n < removeBotsMenuInfo.numBots); n++ ) {\n\t\ttrap_GetConfigString( CS_PLAYERS + removeBotsMenuInfo.botClientNums[removeBotsMenuInfo.baseBotNum + n], info, MAX_INFO_STRING );\n\t\tQ_strncpyz( removeBotsMenuInfo.botnames[n], Info_ValueForKey( info, \"n\" ), sizeof(removeBotsMenuInfo.botnames[n]) );\n\t\tQ_CleanStr( removeBotsMenuInfo.botnames[n] );\n\t}\n\n}\n\n\n/*\n=================\nUI_RemoveBotsMenu_DeleteEvent\n=================\n*/\nstatic void UI_RemoveBotsMenu_DeleteEvent( void* ptr, int event ) {\n\tif (event != QM_ACTIVATED) {\n\t\treturn;\n\t}\n\n\ttrap_Cmd_ExecuteText( EXEC_APPEND, va(\"clientkick %i\\n\", removeBotsMenuInfo.botClientNums[removeBotsMenuInfo.baseBotNum + removeBotsMenuInfo.selectedBotNum]) );\n}\n\n\n/*\n=================\nUI_RemoveBotsMenu_BotEvent\n=================\n*/\nstatic void UI_RemoveBotsMenu_BotEvent( void* ptr, int event ) {\n\tif (event != QM_ACTIVATED) {\n\t\treturn;\n\t}\n\n\tremoveBotsMenuInfo.bots[removeBotsMenuInfo.selectedBotNum].color = color_orange;\n\tremoveBotsMenuInfo.selectedBotNum = ((menucommon_s*)ptr)->id - ID_BOTNAME0;\n\tremoveBotsMenuInfo.bots[removeBotsMenuInfo.selectedBotNum].color = color_white;\n}\n\n\n/*\n=================\nUI_RemoveAddBotsMenu_BackEvent\n=================\n*/\nstatic void UI_RemoveBotsMenu_BackEvent( void* ptr, int event ) {\n\tif (event != QM_ACTIVATED) {\n\t\treturn;\n\t}\n\tUI_PopMenu();\n}\n\n\n/*\n=================\nUI_RemoveBotsMenu_UpEvent\n=================\n*/\nstatic void UI_RemoveBotsMenu_UpEvent( void* ptr, int event ) {\n\tif (event != QM_ACTIVATED) {\n\t\treturn;\n\t}\n\n\tif( removeBotsMenuInfo.baseBotNum > 0 ) {\n\t\tremoveBotsMenuInfo.baseBotNum--;\n\t\tUI_RemoveBotsMenu_SetBotNames();\n\t}\n}\n\n\n/*\n=================\nUI_RemoveBotsMenu_DownEvent\n=================\n*/\nstatic void UI_RemoveBotsMenu_DownEvent( void* ptr, int event ) {\n\tif (event != QM_ACTIVATED) {\n\t\treturn;\n\t}\n\n\tif( removeBotsMenuInfo.baseBotNum + 7 < removeBotsMenuInfo.numBots ) {\n\t\tremoveBotsMenuInfo.baseBotNum++;\n\t\tUI_RemoveBotsMenu_SetBotNames();\n\t}\n}\n\n\n/*\n=================\nUI_RemoveBotsMenu_GetBots\n=================\n*/\nstatic void UI_RemoveBotsMenu_GetBots( void ) {\n\tint\t\tnumPlayers;\n\tint\t\tisBot;\n\tint\t\tn;\n\tchar\tinfo[MAX_INFO_STRING];\n\n\ttrap_GetConfigString( CS_SERVERINFO, info, sizeof(info) );\n\tnumPlayers = atoi( Info_ValueForKey( info, \"sv_maxclients\" ) );\n\tremoveBotsMenuInfo.numBots = 0;\n\n\tfor( n = 0; n < numPlayers; n++ ) {\n\t\ttrap_GetConfigString( CS_PLAYERS + n, info, MAX_INFO_STRING );\n\n\t\tisBot = atoi( Info_ValueForKey( info, \"skill\" ) );\n\t\tif( !isBot ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tremoveBotsMenuInfo.botClientNums[removeBotsMenuInfo.numBots] = n;\n\t\tremoveBotsMenuInfo.numBots++;\n\t}\n}\n\n\n/*\n=================\nUI_RemoveBots_Cache\n=================\n*/\nvoid UI_RemoveBots_Cache( void ) {\n\ttrap_R_RegisterShaderNoMip( ART_BACKGROUND );\n\ttrap_R_RegisterShaderNoMip( ART_BACK0 );\n\ttrap_R_RegisterShaderNoMip( ART_BACK1 );\n\ttrap_R_RegisterShaderNoMip( ART_DELETE0 );\n\ttrap_R_RegisterShaderNoMip( ART_DELETE1 );\n}\n\n\n/*\n=================\nUI_RemoveBotsMenu_Init\n=================\n*/\nstatic void UI_RemoveBotsMenu_Init( void ) {\n\tint\t\tn;\n\tint\t\tcount;\n\tint\t\ty;\n\n\tmemset( &removeBotsMenuInfo, 0 ,sizeof(removeBotsMenuInfo) );\n\tremoveBotsMenuInfo.menu.fullscreen = qfalse;\n\tremoveBotsMenuInfo.menu.wrapAround = qtrue;\n\n\tUI_RemoveBots_Cache();\n\n\tUI_RemoveBotsMenu_GetBots();\n\tUI_RemoveBotsMenu_SetBotNames();\n\tcount = removeBotsMenuInfo.numBots < 7 ? removeBotsMenuInfo.numBots : 7;\n\n\tremoveBotsMenuInfo.banner.generic.type\t\t= MTYPE_BTEXT;\n\tremoveBotsMenuInfo.banner.generic.x\t\t\t= 320;\n\tremoveBotsMenuInfo.banner.generic.y\t\t\t= 16;\n\tremoveBotsMenuInfo.banner.string\t\t\t= \"REMOVE BOTS\";\n\tremoveBotsMenuInfo.banner.color\t\t\t\t= color_white;\n\tremoveBotsMenuInfo.banner.style\t\t\t\t= UI_CENTER;\n\n\tremoveBotsMenuInfo.background.generic.type\t= MTYPE_BITMAP;\n\tremoveBotsMenuInfo.background.generic.name\t= ART_BACKGROUND;\n\tremoveBotsMenuInfo.background.generic.flags\t= QMF_INACTIVE;\n\tremoveBotsMenuInfo.background.generic.x\t\t= 320-233;\n\tremoveBotsMenuInfo.background.generic.y\t\t= 240-166;\n\tremoveBotsMenuInfo.background.width\t\t\t= 466;\n\tremoveBotsMenuInfo.background.height\t\t= 332;\n\n\tremoveBotsMenuInfo.arrows.generic.type\t\t= MTYPE_BITMAP;\n\tremoveBotsMenuInfo.arrows.generic.name\t\t= ART_ARROWS;\n\tremoveBotsMenuInfo.arrows.generic.flags\t\t= QMF_INACTIVE;\n\tremoveBotsMenuInfo.arrows.generic.x\t\t\t= 200;\n\tremoveBotsMenuInfo.arrows.generic.y\t\t\t= 128;\n\tremoveBotsMenuInfo.arrows.width\t\t\t\t= 64;\n\tremoveBotsMenuInfo.arrows.height\t\t\t= 128;\n\n\tremoveBotsMenuInfo.up.generic.type\t\t\t= MTYPE_BITMAP;\n\tremoveBotsMenuInfo.up.generic.flags\t\t\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\tremoveBotsMenuInfo.up.generic.x\t\t\t\t= 200;\n\tremoveBotsMenuInfo.up.generic.y\t\t\t\t= 128;\n\tremoveBotsMenuInfo.up.generic.id\t\t\t= ID_UP;\n\tremoveBotsMenuInfo.up.generic.callback\t\t= UI_RemoveBotsMenu_UpEvent;\n\tremoveBotsMenuInfo.up.width\t\t\t\t\t= 64;\n\tremoveBotsMenuInfo.up.height\t\t\t\t= 64;\n\tremoveBotsMenuInfo.up.focuspic\t\t\t\t= ART_ARROWUP;\n\n\tremoveBotsMenuInfo.down.generic.type\t\t= MTYPE_BITMAP;\n\tremoveBotsMenuInfo.down.generic.flags\t\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\tremoveBotsMenuInfo.down.generic.x\t\t\t= 200;\n\tremoveBotsMenuInfo.down.generic.y\t\t\t= 128+64;\n\tremoveBotsMenuInfo.down.generic.id\t\t\t= ID_DOWN;\n\tremoveBotsMenuInfo.down.generic.callback\t= UI_RemoveBotsMenu_DownEvent;\n\tremoveBotsMenuInfo.down.width\t\t\t\t= 64;\n\tremoveBotsMenuInfo.down.height\t\t\t\t= 64;\n\tremoveBotsMenuInfo.down.focuspic\t\t\t= ART_ARROWDOWN;\n\n\tfor( n = 0, y = 120; n < count; n++, y += 20 ) {\n\t\tremoveBotsMenuInfo.bots[n].generic.type\t\t= MTYPE_PTEXT;\n\t\tremoveBotsMenuInfo.bots[n].generic.flags\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\t\tremoveBotsMenuInfo.bots[n].generic.id\t\t= ID_BOTNAME0 + n;\n\t\tremoveBotsMenuInfo.bots[n].generic.x\t\t= 320 - 56;\n\t\tremoveBotsMenuInfo.bots[n].generic.y\t\t= y;\n\t\tremoveBotsMenuInfo.bots[n].generic.callback\t= UI_RemoveBotsMenu_BotEvent;\n\t\tremoveBotsMenuInfo.bots[n].string\t\t\t= removeBotsMenuInfo.botnames[n];\n\t\tremoveBotsMenuInfo.bots[n].color\t\t\t= color_orange;\n\t\tremoveBotsMenuInfo.bots[n].style\t\t\t= UI_LEFT|UI_SMALLFONT;\n\t}\n\n\tremoveBotsMenuInfo.delete.generic.type\t\t= MTYPE_BITMAP;\n\tremoveBotsMenuInfo.delete.generic.name\t\t= ART_DELETE0;\n\tremoveBotsMenuInfo.delete.generic.flags\t\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\tremoveBotsMenuInfo.delete.generic.id\t\t= ID_DELETE;\n\tremoveBotsMenuInfo.delete.generic.callback\t= UI_RemoveBotsMenu_DeleteEvent;\n\tremoveBotsMenuInfo.delete.generic.x\t\t\t= 320+128-128;\n\tremoveBotsMenuInfo.delete.generic.y\t\t\t= 256+128-64;\n\tremoveBotsMenuInfo.delete.width  \t\t\t= 128;\n\tremoveBotsMenuInfo.delete.height  \t\t\t= 64;\n\tremoveBotsMenuInfo.delete.focuspic\t\t\t= ART_DELETE1;\n\n\tremoveBotsMenuInfo.back.generic.type\t\t= MTYPE_BITMAP;\n\tremoveBotsMenuInfo.back.generic.name\t\t= ART_BACK0;\n\tremoveBotsMenuInfo.back.generic.flags\t\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\tremoveBotsMenuInfo.back.generic.id\t\t\t= ID_BACK;\n\tremoveBotsMenuInfo.back.generic.callback\t= UI_RemoveBotsMenu_BackEvent;\n\tremoveBotsMenuInfo.back.generic.x\t\t\t= 320-128;\n\tremoveBotsMenuInfo.back.generic.y\t\t\t= 256+128-64;\n\tremoveBotsMenuInfo.back.width\t\t\t\t= 128;\n\tremoveBotsMenuInfo.back.height\t\t\t\t= 64;\n\tremoveBotsMenuInfo.back.focuspic\t\t\t= ART_BACK1;\n\n\tMenu_AddItem( &removeBotsMenuInfo.menu, &removeBotsMenuInfo.background );\n\tMenu_AddItem( &removeBotsMenuInfo.menu, &removeBotsMenuInfo.banner );\n\tMenu_AddItem( &removeBotsMenuInfo.menu, &removeBotsMenuInfo.arrows );\n\tMenu_AddItem( &removeBotsMenuInfo.menu, &removeBotsMenuInfo.up );\n\tMenu_AddItem( &removeBotsMenuInfo.menu, &removeBotsMenuInfo.down );\n\tfor( n = 0; n < count; n++ ) {\n\t\tMenu_AddItem( &removeBotsMenuInfo.menu, &removeBotsMenuInfo.bots[n] );\n\t}\n\tMenu_AddItem( &removeBotsMenuInfo.menu, &removeBotsMenuInfo.delete );\n\tMenu_AddItem( &removeBotsMenuInfo.menu, &removeBotsMenuInfo.back );\n\n\tremoveBotsMenuInfo.baseBotNum = 0;\n\tremoveBotsMenuInfo.selectedBotNum = 0;\n\tremoveBotsMenuInfo.bots[0].color = color_white;\n}\n\n\n/*\n=================\nUI_RemoveBotsMenu\n=================\n*/\nvoid UI_RemoveBotsMenu( void ) {\n\tUI_RemoveBotsMenu_Init();\n\tUI_PushMenu( &removeBotsMenuInfo.menu );\n}\n"
  },
  {
    "path": "src/q3_ui/ui_serverinfo.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n#include \"ui_local.h\"\n\n#define SERVERINFO_FRAMEL\t\"menu/art/frame2_l\"\n#define SERVERINFO_FRAMER\t\"menu/art/frame1_r\"\n#define SERVERINFO_BACK0\t\"menu/art/back_0\"\n#define SERVERINFO_BACK1\t\"menu/art/back_1\"\n\nstatic char* serverinfo_artlist[] =\n{\n\tSERVERINFO_FRAMEL,\t\n\tSERVERINFO_FRAMER,\n\tSERVERINFO_BACK0,\n\tSERVERINFO_BACK1,\n\tNULL\n};\n\n#define ID_ADD\t 100\n#define ID_BACK\t 101\n\ntypedef struct\n{\n\tmenuframework_s\tmenu;\n\tmenutext_s\t\tbanner;\n\tmenubitmap_s\tframel;\n\tmenubitmap_s\tframer;\n\tmenubitmap_s\tback;\n\tmenutext_s\t\tadd;\n\tchar\t\t\tinfo[MAX_INFO_STRING];\n\tint\t\t\t\tnumlines;\n} serverinfo_t;\n\nstatic serverinfo_t\ts_serverinfo;\n\n\n/*\n=================\nFavorites_Add\n\nAdd current server to favorites\n=================\n*/\nvoid Favorites_Add( void )\n{\n\tchar\tadrstr[128];\n\tchar\tserverbuff[128];\n\tint\t\ti;\n\tint\t\tbest;\n\n\ttrap_Cvar_VariableStringBuffer( \"cl_currentServerAddress\", serverbuff, sizeof(serverbuff) );\n\tif (!serverbuff[0])\n\t\treturn;\n\n\tbest = 0;\n\tfor (i=0; i<MAX_FAVORITESERVERS; i++)\n\t{\n\t\ttrap_Cvar_VariableStringBuffer( va(\"server%d\",i+1), adrstr, sizeof(adrstr) );\n\t\tif (!Q_stricmp(serverbuff,adrstr))\n\t\t{\n\t\t\t// already in list\n\t\t\treturn;\n\t\t}\n\t\t\n\t\t// use first empty or non-numeric available slot\n\t\tif ((adrstr[0]  < '0' || adrstr[0] > '9' ) && !best)\n\t\t\tbest = i+1;\n\t}\n\n\tif (best)\n\t\ttrap_Cvar_Set( va(\"server%d\",best), serverbuff);\n}\n\n\n/*\n=================\nServerInfo_Event\n=================\n*/\nstatic void ServerInfo_Event( void* ptr, int event )\n{\n\tswitch (((menucommon_s*)ptr)->id)\n\t{\n\t\tcase ID_ADD:\n\t\t\tif (event != QM_ACTIVATED)\n\t\t\t\tbreak;\n\t\t\n\t\t\tFavorites_Add();\n\t\t\tUI_PopMenu();\n\t\t\tbreak;\n\n\t\tcase ID_BACK:\n\t\t\tif (event != QM_ACTIVATED)\n\t\t\t\tbreak;\n\n\t\t\tUI_PopMenu();\n\t\t\tbreak;\n\t}\n}\n\n/*\n=================\nServerInfo_MenuDraw\n=================\n*/\nstatic void ServerInfo_MenuDraw( void )\n{\n\tconst char\t\t*s;\n\tchar\t\t\tkey[MAX_INFO_KEY];\n\tchar\t\t\tvalue[MAX_INFO_VALUE];\n\tint\t\t\t\ty;\n\n\ty = SCREEN_HEIGHT/2 - s_serverinfo.numlines*(SMALLCHAR_HEIGHT)/2 - 20;\n\ts = s_serverinfo.info;\n\twhile ( s ) {\n\t\tInfo_NextPair( &s, key, value );\n\t\tif ( !key[0] ) {\n\t\t\tbreak;\n\t\t}\n\n\t\tQ_strcat( key, MAX_INFO_KEY, \":\" ); \n\n\t\tUI_DrawString(SCREEN_WIDTH*0.50 - 8,y,key,UI_RIGHT|UI_SMALLFONT,color_red);\n\t\tUI_DrawString(SCREEN_WIDTH*0.50 + 8,y,value,UI_LEFT|UI_SMALLFONT,text_color_normal);\n\n\t\ty += SMALLCHAR_HEIGHT;\n\t}\n\n\tMenu_Draw( &s_serverinfo.menu );\n}\n\n/*\n=================\nServerInfo_MenuKey\n=================\n*/\nstatic sfxHandle_t ServerInfo_MenuKey( int key )\n{\n\treturn ( Menu_DefaultKey( &s_serverinfo.menu, key ) );\n}\n\n/*\n=================\nServerInfo_Cache\n=================\n*/\nvoid ServerInfo_Cache( void )\n{\n\tint\ti;\n\n\t// touch all our pics\n\tfor (i=0; ;i++)\n\t{\n\t\tif (!serverinfo_artlist[i])\n\t\t\tbreak;\n\t\ttrap_R_RegisterShaderNoMip(serverinfo_artlist[i]);\n\t}\n}\n\n/*\n=================\nUI_ServerInfoMenu\n=================\n*/\nvoid UI_ServerInfoMenu( void )\n{\n\tconst char\t\t*s;\n\tchar\t\t\tkey[MAX_INFO_KEY];\n\tchar\t\t\tvalue[MAX_INFO_VALUE];\n\n\t// zero set all our globals\n\tmemset( &s_serverinfo, 0 ,sizeof(serverinfo_t) );\n\n\tServerInfo_Cache();\n\n\ts_serverinfo.menu.draw       = ServerInfo_MenuDraw;\n\ts_serverinfo.menu.key        = ServerInfo_MenuKey;\n\ts_serverinfo.menu.wrapAround = qtrue;\n\ts_serverinfo.menu.fullscreen = qtrue;\n\n\ts_serverinfo.banner.generic.type  = MTYPE_BTEXT;\n\ts_serverinfo.banner.generic.x\t  = 320;\n\ts_serverinfo.banner.generic.y\t  = 16;\n\ts_serverinfo.banner.string\t\t  = \"SERVER INFO\";\n\ts_serverinfo.banner.color\t      = color_white;\n\ts_serverinfo.banner.style\t      = UI_CENTER;\n\n\ts_serverinfo.framel.generic.type  = MTYPE_BITMAP;\n\ts_serverinfo.framel.generic.name  = SERVERINFO_FRAMEL;\n\ts_serverinfo.framel.generic.flags = QMF_INACTIVE;\n\ts_serverinfo.framel.generic.x\t  = 0;  \n\ts_serverinfo.framel.generic.y\t  = 78;\n\ts_serverinfo.framel.width  \t      = 256;\n\ts_serverinfo.framel.height  \t  = 329;\n\n\ts_serverinfo.framer.generic.type  = MTYPE_BITMAP;\n\ts_serverinfo.framer.generic.name  = SERVERINFO_FRAMER;\n\ts_serverinfo.framer.generic.flags = QMF_INACTIVE;\n\ts_serverinfo.framer.generic.x\t  = 376;\n\ts_serverinfo.framer.generic.y\t  = 76;\n\ts_serverinfo.framer.width  \t      = 256;\n\ts_serverinfo.framer.height  \t  = 334;\n\n\ts_serverinfo.add.generic.type\t  = MTYPE_PTEXT;\n\ts_serverinfo.add.generic.flags    = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_serverinfo.add.generic.callback = ServerInfo_Event;\n\ts_serverinfo.add.generic.id\t      = ID_ADD;\n\ts_serverinfo.add.generic.x\t\t  = 320;\n\ts_serverinfo.add.generic.y\t\t  = 371;\n\ts_serverinfo.add.string  \t\t  = \"ADD TO FAVORITES\";\n\ts_serverinfo.add.style  \t\t  = UI_CENTER|UI_SMALLFONT;\n\ts_serverinfo.add.color\t\t\t  =\tcolor_red;\n\tif( trap_Cvar_VariableValue( \"sv_running\" ) ) {\n\t\ts_serverinfo.add.generic.flags |= QMF_GRAYED;\n\t}\n\n\ts_serverinfo.back.generic.type\t   = MTYPE_BITMAP;\n\ts_serverinfo.back.generic.name     = SERVERINFO_BACK0;\n\ts_serverinfo.back.generic.flags    = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_serverinfo.back.generic.callback = ServerInfo_Event;\n\ts_serverinfo.back.generic.id\t   = ID_BACK;\n\ts_serverinfo.back.generic.x\t\t   = 0;\n\ts_serverinfo.back.generic.y\t\t   = 480-64;\n\ts_serverinfo.back.width  \t\t   = 128;\n\ts_serverinfo.back.height  \t\t   = 64;\n\ts_serverinfo.back.focuspic         = SERVERINFO_BACK1;\n\n\ttrap_GetConfigString( CS_SERVERINFO, s_serverinfo.info, MAX_INFO_STRING );\n\n\ts_serverinfo.numlines = 0;\n\ts = s_serverinfo.info;\n\twhile ( s ) {\n\t\tInfo_NextPair( &s, key, value );\n\t\tif ( !key[0] ) {\n\t\t\tbreak;\n\t\t}\n\t\ts_serverinfo.numlines++;\n\t}\n\n\tif (s_serverinfo.numlines > 16)\n\t\ts_serverinfo.numlines = 16;\n\n\tMenu_AddItem( &s_serverinfo.menu, (void*) &s_serverinfo.banner );\n\tMenu_AddItem( &s_serverinfo.menu, (void*) &s_serverinfo.framel );\n\tMenu_AddItem( &s_serverinfo.menu, (void*) &s_serverinfo.framer );\n\tMenu_AddItem( &s_serverinfo.menu, (void*) &s_serverinfo.add );\n\tMenu_AddItem( &s_serverinfo.menu, (void*) &s_serverinfo.back );\n\n\tUI_PushMenu( &s_serverinfo.menu );\n}\n\n\n"
  },
  {
    "path": "src/q3_ui/ui_servers2.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n/*\n=======================================================================\n\nMULTIPLAYER MENU (SERVER BROWSER)\n\n=======================================================================\n*/\n\n\n#include \"ui_local.h\"\n\n\n#define MAX_GLOBALSERVERS\t\t128\n#define MAX_PINGREQUESTS\t\t32\n#define MAX_ADDRESSLENGTH\t\t64\n#define MAX_HOSTNAMELENGTH\t\t22\n#define MAX_MAPNAMELENGTH\t\t16\n#define MAX_LISTBOXITEMS\t\t128\n#define MAX_LOCALSERVERS\t\t128\n#define MAX_STATUSLENGTH\t\t64\n#define MAX_LEAGUELENGTH\t\t28\n#define MAX_LISTBOXWIDTH\t\t68\n\n#define ART_BACK0\t\t\t\t\"menu/art/back_0\"\n#define ART_BACK1\t\t\t\t\"menu/art/back_1\"\n#define ART_CREATE0\t\t\t\t\"menu/art/create_0\"\n#define ART_CREATE1\t\t\t\t\"menu/art/create_1\"\n#define ART_SPECIFY0\t\t\t\"menu/art/specify_0\"\n#define ART_SPECIFY1\t\t\t\"menu/art/specify_1\"\n#define ART_REFRESH0\t\t\t\"menu/art/refresh_0\"\n#define ART_REFRESH1\t\t\t\"menu/art/refresh_1\"\n#define ART_CONNECT0\t\t\t\"menu/art/fight_0\"\n#define ART_CONNECT1\t\t\t\"menu/art/fight_1\"\n#define ART_ARROWS0\t\t\t\t\"menu/art/arrows_vert_0\"\n#define ART_ARROWS_UP\t\t\t\"menu/art/arrows_vert_top\"\n#define ART_ARROWS_DOWN\t\t\t\"menu/art/arrows_vert_bot\"\n#define ART_UNKNOWNMAP\t\t\t\"menu/art/unknownmap\"\n#define ART_REMOVE0\t\t\t\t\"menu/art/delete_0\"\n#define ART_REMOVE1\t\t\t\t\"menu/art/delete_1\"\n#define ART_PUNKBUSTER\t\t\"menu/art/pblogo\"\n\n#define ID_MASTER\t\t\t10\n#define ID_GAMETYPE\t\t\t11\n#define ID_SORTKEY\t\t\t12\n#define ID_SHOW_FULL\t\t13\n#define ID_SHOW_EMPTY\t\t14\n#define ID_LIST\t\t\t\t15\n#define ID_SCROLL_UP\t\t16\n#define ID_SCROLL_DOWN\t\t17\n#define ID_BACK\t\t\t\t18\n#define ID_REFRESH\t\t\t19\n#define ID_SPECIFY\t\t\t20\n#define ID_CREATE\t\t\t21\n#define ID_CONNECT\t\t\t22\n#define ID_REMOVE\t\t\t23\n#define ID_PUNKBUSTER 24\n\n#define GR_LOGO\t\t\t\t30\n#define GR_LETTERS\t\t\t31\n\n#define AS_LOCAL\t\t\t0\n#define AS_MPLAYER\t\t\t1\n#define AS_GLOBAL\t\t\t2\n#define AS_FAVORITES\t\t3\n\n#define SORT_HOST\t\t\t0\n#define SORT_MAP\t\t\t1\n#define SORT_CLIENTS\t\t2\n#define SORT_GAME\t\t\t3\n#define SORT_PING\t\t\t4\n\n#define GAMES_ALL\t\t\t0\n#define GAMES_FFA\t\t\t1\n#define GAMES_TEAMPLAY\t\t2\n#define GAMES_TOURNEY\t\t3\n#define GAMES_CTF\t\t\t4\n\nstatic const char *master_items[] = {\n\t\"Local\",\n\t\"Internet\",\n\t\"Favorites\",\n\t0\n};\n\nstatic const char *servertype_items[] = {\n\t\"All\",\n\t\"Free For All\",\n\t\"Team Deathmatch\",\n\t\"Tournament\",\n\t\"Capture the Flag\",\n\t0\n};\n\nstatic const char *sortkey_items[] = {\n\t\"Server Name\",\n\t\"Map Name\",\n\t\"Open Player Spots\",\n\t\"Game Type\",\n\t\"Ping Time\",\n\t0\n};\n\nstatic char* gamenames[] = {\n\t\"DM \",\t// deathmatch\n\t\"1v1\",\t// tournament\n\t\"SP \",\t// single player\n\t\"Team DM\",\t// team deathmatch\n\t\"CTF\",\t// capture the flag\n\t\"One Flag CTF\",\t\t// one flag ctf\n\t\"OverLoad\",\t\t\t\t// Overload\n\t\"Harvester\",\t\t\t// Harvester\n\t\"Rocket Arena 3\",\t// Rocket Arena 3\n\t\"Q3F\",\t\t\t\t\t\t// Q3F\n\t\"Urban Terror\",\t\t// Urban Terror\n\t\"OSP\",\t\t\t\t\t\t// Orange Smoothie Productions\n\t\"???\",\t\t\t// unknown\n\t0\n};\n\nstatic char* netnames[] = {\n\t\"???\",\n\t\"UDP\",\n\t\"IPX\",\n\tNULL\n};\n\nstatic char quake3worldMessage[] = \"Visit www.quake3world.com - News, Community, Events, Files\";\n\nconst char* punkbuster_items[] = {\n\t\"Disabled\",\n\t\"Enabled\",\n\tNULL\n};\n\nconst char* punkbuster_msg[] = {\n\t\"PunkBuster will be\",\n\t\"disabled the next time\",\n\t\"Quake III Arena\",\n\t\"is started.\",\n\tNULL\n};\n\ntypedef struct {\n\tchar\tadrstr[MAX_ADDRESSLENGTH];\n\tint\t\tstart;\n} pinglist_t;\n\ntypedef struct servernode_s {\n\tchar\tadrstr[MAX_ADDRESSLENGTH];\n\tchar\thostname[MAX_HOSTNAMELENGTH+3];\n\tchar\tmapname[MAX_MAPNAMELENGTH];\n\tint\t\tnumclients;\n\tint\t\tmaxclients;\n\tint\t\tpingtime;\n\tint\t\tgametype;\n\tchar\tgamename[12];\n\tint\t\tnettype;\n\tint\t\tminPing;\n\tint\t\tmaxPing;\n\tqboolean bPB;\n\n} servernode_t; \n\ntypedef struct {\n\tchar\t\t\tbuff[MAX_LISTBOXWIDTH];\n\tservernode_t*\tservernode;\n} table_t;\n\ntypedef struct {\n\tmenuframework_s\t\tmenu;\n\n\tmenutext_s\t\t\tbanner;\n\n\tmenulist_s\t\t\tmaster;\n\tmenulist_s\t\t\tgametype;\n\tmenulist_s\t\t\tsortkey;\n\tmenuradiobutton_s\tshowfull;\n\tmenuradiobutton_s\tshowempty;\n\n\tmenulist_s\t\t\tlist;\n\tmenubitmap_s\t\tmappic;\n\tmenubitmap_s\t\tarrows;\n\tmenubitmap_s\t\tup;\n\tmenubitmap_s\t\tdown;\n\tmenutext_s\t\t\tstatus;\n\tmenutext_s\t\t\tstatusbar;\n\n\tmenubitmap_s\t\tremove;\n\tmenubitmap_s\t\tback;\n\tmenubitmap_s\t\trefresh;\n\tmenubitmap_s\t\tspecify;\n\tmenubitmap_s\t\tcreate;\n\tmenubitmap_s\t\tgo;\n\n\tpinglist_t\t\t\tpinglist[MAX_PINGREQUESTS];\n\ttable_t\t\t\t\ttable[MAX_LISTBOXITEMS];\n\tchar*\t\t\t\titems[MAX_LISTBOXITEMS];\n\tint\t\t\t\t\tnumqueriedservers;\n\tint\t\t\t\t\t*numservers;\n\tservernode_t\t\t*serverlist;\t\n\tint\t\t\t\t\tcurrentping;\n\tqboolean\t\t\trefreshservers;\n\tint\t\t\t\t\tnextpingtime;\n\tint\t\t\t\t\tmaxservers;\n\tint\t\t\t\t\trefreshtime;\n\tchar\t\t\t\tfavoriteaddresses[MAX_FAVORITESERVERS][MAX_ADDRESSLENGTH];\n\tint\t\t\t\t\tnumfavoriteaddresses;\n\n\tmenulist_s\t\tpunkbuster;\n\tmenubitmap_s\tpblogo;\n} arenaservers_t;\n\nstatic arenaservers_t\tg_arenaservers;\n\n\nstatic servernode_t\t\tg_globalserverlist[MAX_GLOBALSERVERS];\nstatic int\t\t\t\tg_numglobalservers;\nstatic servernode_t\t\tg_localserverlist[MAX_LOCALSERVERS];\nstatic int\t\t\t\tg_numlocalservers;\nstatic servernode_t\t\tg_favoriteserverlist[MAX_FAVORITESERVERS];\nstatic int\t\t\t\tg_numfavoriteservers;\nstatic servernode_t\t\tg_mplayerserverlist[MAX_GLOBALSERVERS];\nstatic int\t\t\t\tg_nummplayerservers;\nstatic int\t\t\t\tg_servertype;\nstatic int\t\t\t\tg_gametype;\nstatic int\t\t\t\tg_sortkey;\nstatic int\t\t\t\tg_emptyservers;\nstatic int\t\t\t\tg_fullservers;\n\n\n/*\n=================\nArenaServers_MaxPing\n=================\n*/\nstatic int ArenaServers_MaxPing( void ) {\n\tint\t\tmaxPing;\n\n\tmaxPing = (int)trap_Cvar_VariableValue( \"cl_maxPing\" );\n\tif( maxPing < 100 ) {\n\t\tmaxPing = 100;\n\t}\n\treturn maxPing;\n}\n\n\n/*\n=================\nArenaServers_Compare\n=================\n*/\nstatic int QDECL ArenaServers_Compare( const void *arg1, const void *arg2 ) {\n\tfloat\t\t\tf1;\n\tfloat\t\t\tf2;\n\tservernode_t*\tt1;\n\tservernode_t*\tt2;\n\n\tt1 = (servernode_t *)arg1;\n\tt2 = (servernode_t *)arg2;\n\n\tswitch( g_sortkey ) {\n\tcase SORT_HOST:\n\t\treturn Q_stricmp( t1->hostname, t2->hostname );\n\n\tcase SORT_MAP:\n\t\treturn Q_stricmp( t1->mapname, t2->mapname );\n\n\tcase SORT_CLIENTS:\n\t\tf1 = t1->maxclients - t1->numclients;\n\t\tif( f1 < 0 ) {\n\t\t\tf1 = 0;\n\t\t}\n\n\t\tf2 = t2->maxclients - t2->numclients;\n\t\tif( f2 < 0 ) {\n\t\t\tf2 = 0;\n\t\t}\n\n\t\tif( f1 < f2 ) {\n\t\t\treturn 1;\n\t\t}\n\t\tif( f1 == f2 ) {\n\t\t\treturn 0;\n\t\t}\n\t\treturn -1;\n\n\tcase SORT_GAME:\n\t\tif( t1->gametype < t2->gametype ) {\n\t\t\treturn -1;\n\t\t}\n\t\tif( t1->gametype == t2->gametype ) {\n\t\t\treturn 0;\n\t\t}\n\t\treturn 1;\n\n\tcase SORT_PING:\n\t\tif( t1->pingtime < t2->pingtime ) {\n\t\t\treturn -1;\n\t\t}\n\t\tif( t1->pingtime > t2->pingtime ) {\n\t\t\treturn 1;\n\t\t}\n\t\treturn Q_stricmp( t1->hostname, t2->hostname );\n\t}\n\n\treturn 0;\n}\n\n\n/*\n=================\nArenaServers_Go\n=================\n*/\nstatic void ArenaServers_Go( void ) {\n\tservernode_t*\tservernode;\n\n\tservernode = g_arenaservers.table[g_arenaservers.list.curvalue].servernode;\n\tif( servernode ) {\n\t\ttrap_Cmd_ExecuteText( EXEC_APPEND, va( \"connect %s\\n\", servernode->adrstr ) );\n\t}\n}\n\n\n/*\n=================\nArenaServers_UpdatePicture\n=================\n*/\nstatic void ArenaServers_UpdatePicture( void ) {\n\tstatic char\t\tpicname[64];\n\tservernode_t*\tservernodeptr;\n\n\tif( !g_arenaservers.list.numitems ) {\n\t\tg_arenaservers.mappic.generic.name = NULL;\n\t}\n\telse {\n\t\tservernodeptr = g_arenaservers.table[g_arenaservers.list.curvalue].servernode;\n\t\tCom_sprintf( picname, sizeof(picname), \"levelshots/%s.tga\", servernodeptr->mapname );\n\t\tg_arenaservers.mappic.generic.name = picname;\n\t\n\t}\n\n\t// force shader update during draw\n\tg_arenaservers.mappic.shader = 0;\n}\n\n\n/*\n=================\nArenaServers_UpdateMenu\n=================\n*/\nstatic void ArenaServers_UpdateMenu( void ) {\n\tint\t\t\t\ti;\n\tint\t\t\t\tj;\n\tint\t\t\t\tcount;\n\tchar*\t\t\tbuff;\n\tservernode_t*\tservernodeptr;\n\ttable_t*\t\ttableptr;\n\tchar\t\t\t*pingColor;\n\n\tif( g_arenaservers.numqueriedservers > 0 ) {\n\t\t// servers found\n\t\tif( g_arenaservers.refreshservers && ( g_arenaservers.currentping <= g_arenaservers.numqueriedservers ) ) {\n\t\t\t// show progress\n\t\t\tCom_sprintf( g_arenaservers.status.string, MAX_STATUSLENGTH, \"%d of %d Arena Servers.\", g_arenaservers.currentping, g_arenaservers.numqueriedservers);\n\t\t\tg_arenaservers.statusbar.string  = \"Press SPACE to stop\";\n\t\t\tqsort( g_arenaservers.serverlist, *g_arenaservers.numservers, sizeof( servernode_t ), ArenaServers_Compare);\n\t\t}\n\t\telse {\n\t\t\t// all servers pinged - enable controls\n\t\t\tg_arenaservers.master.generic.flags\t\t&= ~QMF_GRAYED;\n\t\t\tg_arenaservers.gametype.generic.flags\t&= ~QMF_GRAYED;\n\t\t\tg_arenaservers.sortkey.generic.flags\t&= ~QMF_GRAYED;\n\t\t\tg_arenaservers.showempty.generic.flags\t&= ~QMF_GRAYED;\n\t\t\tg_arenaservers.showfull.generic.flags\t&= ~QMF_GRAYED;\n\t\t\tg_arenaservers.list.generic.flags\t\t&= ~QMF_GRAYED;\n\t\t\tg_arenaservers.refresh.generic.flags\t&= ~QMF_GRAYED;\n\t\t\tg_arenaservers.go.generic.flags\t\t\t&= ~QMF_GRAYED;\n\t\t\tg_arenaservers.punkbuster.generic.flags &= ~QMF_GRAYED;\n\n\t\t\t// update status bar\n\t\t\tif( g_servertype == AS_GLOBAL || g_servertype == AS_MPLAYER ) {\n\t\t\t\tg_arenaservers.statusbar.string = quake3worldMessage;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tg_arenaservers.statusbar.string = \"\";\n\t\t\t}\n\n\t\t}\n\t}\n\telse {\n\t\t// no servers found\n\t\tif( g_arenaservers.refreshservers ) {\n\t\t\tstrcpy( g_arenaservers.status.string,\"Scanning For Servers.\" );\n\t\t\tg_arenaservers.statusbar.string = \"Press SPACE to stop\";\n\n\t\t\t// disable controls during refresh\n\t\t\tg_arenaservers.master.generic.flags\t\t|= QMF_GRAYED;\n\t\t\tg_arenaservers.gametype.generic.flags\t|= QMF_GRAYED;\n\t\t\tg_arenaservers.sortkey.generic.flags\t|= QMF_GRAYED;\n\t\t\tg_arenaservers.showempty.generic.flags\t|= QMF_GRAYED;\n\t\t\tg_arenaservers.showfull.generic.flags\t|= QMF_GRAYED;\n\t\t\tg_arenaservers.list.generic.flags\t\t|= QMF_GRAYED;\n\t\t\tg_arenaservers.refresh.generic.flags\t|= QMF_GRAYED;\n\t\t\tg_arenaservers.go.generic.flags\t\t\t|= QMF_GRAYED;\n\t\t\tg_arenaservers.punkbuster.generic.flags |= QMF_GRAYED;\n\t\t}\n\t\telse {\n\t\t\tif( g_arenaservers.numqueriedservers < 0 ) {\n\t\t\t\tstrcpy(g_arenaservers.status.string,\"No Response From Master Server.\" );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tstrcpy(g_arenaservers.status.string,\"No Servers Found.\" );\n\t\t\t}\n\n\t\t\t// update status bar\n\t\t\tif( g_servertype == AS_GLOBAL || g_servertype == AS_MPLAYER ) {\n\t\t\t\tg_arenaservers.statusbar.string = quake3worldMessage;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tg_arenaservers.statusbar.string = \"\";\n\t\t\t}\n\n\t\t\t// end of refresh - set control state\n\t\t\tg_arenaservers.master.generic.flags\t\t&= ~QMF_GRAYED;\n\t\t\tg_arenaservers.gametype.generic.flags\t&= ~QMF_GRAYED;\n\t\t\tg_arenaservers.sortkey.generic.flags\t&= ~QMF_GRAYED;\n\t\t\tg_arenaservers.showempty.generic.flags\t&= ~QMF_GRAYED;\n\t\t\tg_arenaservers.showfull.generic.flags\t&= ~QMF_GRAYED;\n\t\t\tg_arenaservers.list.generic.flags\t\t|= QMF_GRAYED;\n\t\t\tg_arenaservers.refresh.generic.flags\t&= ~QMF_GRAYED;\n\t\t\tg_arenaservers.go.generic.flags\t\t\t|= QMF_GRAYED;\n\t\t\tg_arenaservers.punkbuster.generic.flags &= ~QMF_GRAYED;\n\t\t}\n\n\t\t// zero out list box\n\t\tg_arenaservers.list.numitems = 0;\n\t\tg_arenaservers.list.curvalue = 0;\n\t\tg_arenaservers.list.top      = 0;\n\n\t\t// update picture\n\t\tArenaServers_UpdatePicture();\n\t\treturn;\n\t}\n\n\t// build list box strings - apply culling filters\n\tservernodeptr = g_arenaservers.serverlist;\n\tcount         = *g_arenaservers.numservers;\n\tfor( i = 0, j = 0; i < count; i++, servernodeptr++ ) {\n\t\ttableptr = &g_arenaservers.table[j];\n\t\ttableptr->servernode = servernodeptr;\n\t\tbuff = tableptr->buff;\n\n\t\t// can only cull valid results\n\t\tif( !g_emptyservers && !servernodeptr->numclients ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif( !g_fullservers && ( servernodeptr->numclients == servernodeptr->maxclients ) ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tswitch( g_gametype ) {\n\t\tcase GAMES_ALL:\n\t\t\tbreak;\n\n\t\tcase GAMES_FFA:\n\t\t\tif( servernodeptr->gametype != GT_FFA ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase GAMES_TEAMPLAY:\n\t\t\tif( servernodeptr->gametype != GT_TEAM ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase GAMES_TOURNEY:\n\t\t\tif( servernodeptr->gametype != GT_TOURNAMENT ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase GAMES_CTF:\n\t\t\tif( servernodeptr->gametype != GT_CTF ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\tif( servernodeptr->pingtime < servernodeptr->minPing ) {\n\t\t\tpingColor = S_COLOR_BLUE;\n\t\t}\n\t\telse if( servernodeptr->maxPing && servernodeptr->pingtime > servernodeptr->maxPing ) {\n\t\t\tpingColor = S_COLOR_BLUE;\n\t\t}\n\t\telse if( servernodeptr->pingtime < 200 ) {\n\t\t\tpingColor = S_COLOR_GREEN;\n\t\t}\n\t\telse if( servernodeptr->pingtime < 400 ) {\n\t\t\tpingColor = S_COLOR_YELLOW;\n\t\t}\n\t\telse {\n\t\t\tpingColor = S_COLOR_RED;\n\t\t}\n\n\t\tCom_sprintf( buff, MAX_LISTBOXWIDTH, \"%-20.20s %-12.12s %2d/%2d %-8.8s %3s %s%3d \" S_COLOR_YELLOW \"%s\", \n\t\t\tservernodeptr->hostname, servernodeptr->mapname, servernodeptr->numclients,\n \t\t\tservernodeptr->maxclients, servernodeptr->gamename,\n\t\t\tnetnames[servernodeptr->nettype], pingColor, servernodeptr->pingtime, servernodeptr->bPB ? \"Yes\" : \"No\" );\n\t\tj++;\n\t}\n\n\tg_arenaservers.list.numitems = j;\n\tg_arenaservers.list.curvalue = 0;\n\tg_arenaservers.list.top      = 0;\n\n\t// update picture\n\tArenaServers_UpdatePicture();\n}\n\n\n/*\n=================\nArenaServers_Remove\n=================\n*/\nstatic void ArenaServers_Remove( void )\n{\n\tint\t\t\t\ti;\n\tservernode_t*\tservernodeptr;\n\ttable_t*\t\ttableptr;\n\n\tif (!g_arenaservers.list.numitems)\n\t\treturn;\n\n\t// remove selected item from display list\n\t// items are in scattered order due to sort and cull\n\t// perform delete on list box contents, resync all lists\n\n\ttableptr      = &g_arenaservers.table[g_arenaservers.list.curvalue];\n\tservernodeptr = tableptr->servernode;\n\n\t// find address in master list\n\tfor (i=0; i<g_arenaservers.numfavoriteaddresses; i++)\n\t\tif (!Q_stricmp(g_arenaservers.favoriteaddresses[i],servernodeptr->adrstr))\n\t\t\t\tbreak;\n\n\t// delete address from master list\n\tif (i <= g_arenaservers.numfavoriteaddresses-1)\n\t{\n\t\tif (i < g_arenaservers.numfavoriteaddresses-1)\n\t\t{\n\t\t\t// shift items up\n\t\t\tmemcpy( &g_arenaservers.favoriteaddresses[i], &g_arenaservers.favoriteaddresses[i+1], (g_arenaservers.numfavoriteaddresses - i - 1)*sizeof(MAX_ADDRESSLENGTH));\n\t\t}\n\t\tg_arenaservers.numfavoriteaddresses--;\n\t}\t\n\n\t// find address in server list\n\tfor (i=0; i<g_numfavoriteservers; i++)\n\t\tif (&g_favoriteserverlist[i] == servernodeptr)\n\t\t\t\tbreak;\n\n\t// delete address from server list\n\tif (i <= g_numfavoriteservers-1)\n\t{\n\t\tif (i < g_numfavoriteservers-1)\n\t\t{\n\t\t\t// shift items up\n\t\t\tmemcpy( &g_favoriteserverlist[i], &g_favoriteserverlist[i+1], (g_numfavoriteservers - i - 1)*sizeof(servernode_t));\n\t\t}\n\t\tg_numfavoriteservers--;\n\t}\t\n\n\tg_arenaservers.numqueriedservers = g_arenaservers.numfavoriteaddresses;\n\tg_arenaservers.currentping       = g_arenaservers.numfavoriteaddresses;\n}\n\n\n/*\n=================\nArenaServers_Insert\n=================\n*/\nstatic void ArenaServers_Insert( char* adrstr, char* info, int pingtime )\n{\n\tservernode_t*\tservernodeptr;\n\tchar*\t\t\ts;\n\tint\t\t\t\ti;\n\n\n\tif ((pingtime >= ArenaServers_MaxPing()) && (g_servertype != AS_FAVORITES))\n\t{\n\t\t// slow global or local servers do not get entered\n\t\treturn;\n\t}\n\n\tif (*g_arenaservers.numservers >= g_arenaservers.maxservers) {\n\t\t// list full;\n\t\tservernodeptr = g_arenaservers.serverlist+(*g_arenaservers.numservers)-1;\n\t} else {\n\t\t// next slot\n\t\tservernodeptr = g_arenaservers.serverlist+(*g_arenaservers.numservers);\n\t\t(*g_arenaservers.numservers)++;\n\t}\n\n\tQ_strncpyz( servernodeptr->adrstr, adrstr, MAX_ADDRESSLENGTH );\n\n\tQ_strncpyz( servernodeptr->hostname, Info_ValueForKey( info, \"hostname\"), MAX_HOSTNAMELENGTH );\n\tQ_CleanStr( servernodeptr->hostname );\n\tQ_strupr( servernodeptr->hostname );\n\n\tQ_strncpyz( servernodeptr->mapname, Info_ValueForKey( info, \"mapname\"), MAX_MAPNAMELENGTH );\n\tQ_CleanStr( servernodeptr->mapname );\n\tQ_strupr( servernodeptr->mapname );\n\n\tservernodeptr->numclients = atoi( Info_ValueForKey( info, \"clients\") );\n\tservernodeptr->maxclients = atoi( Info_ValueForKey( info, \"sv_maxclients\") );\n\tservernodeptr->pingtime   = pingtime;\n\tservernodeptr->minPing    = atoi( Info_ValueForKey( info, \"minPing\") );\n\tservernodeptr->maxPing    = atoi( Info_ValueForKey( info, \"maxPing\") );\n\tservernodeptr->bPB = atoi( Info_ValueForKey( info, \"punkbuster\") );\n\n\t/*\n\ts = Info_ValueForKey( info, \"nettype\" );\n\tfor (i=0; ;i++)\n\t{\n\t\tif (!netnames[i])\n\t\t{\n\t\t\tservernodeptr->nettype = 0;\n\t\t\tbreak;\n\t\t}\n\t\telse if (!Q_stricmp( netnames[i], s ))\n\t\t{\n\t\t\tservernodeptr->nettype = i;\n\t\t\tbreak;\n\t\t}\n\t}\n\t*/\n\tservernodeptr->nettype = atoi(Info_ValueForKey(info, \"nettype\"));\n\n\ts = Info_ValueForKey( info, \"game\");\n\ti = atoi( Info_ValueForKey( info, \"gametype\") );\n\tif( i < 0 ) {\n\t\ti = 0;\n\t}\n\telse if( i > 11 ) {\n\t\ti = 12;\n\t}\n\tif( *s ) {\n\t\tservernodeptr->gametype = i;//-1;\n\t\tQ_strncpyz( servernodeptr->gamename, s, sizeof(servernodeptr->gamename) );\n\t}\n\telse {\n\t\tservernodeptr->gametype = i;\n\t\tQ_strncpyz( servernodeptr->gamename, gamenames[i], sizeof(servernodeptr->gamename) );\n\t}\n}\n\n\n/*\n=================\nArenaServers_InsertFavorites\n\nInsert nonresponsive address book entries into display lists.\n=================\n*/\nvoid ArenaServers_InsertFavorites( void )\n{\n\tint\t\ti;\n\tint\t\tj;\n\tchar\tinfo[MAX_INFO_STRING];\n\n\t// resync existing results with new or deleted cvars\n\tinfo[0] = '\\0';\n\tInfo_SetValueForKey( info, \"hostname\", \"No Response\" );\n\tfor (i=0; i<g_arenaservers.numfavoriteaddresses; i++)\n\t{\n\t\t// find favorite address in refresh list\n\t\tfor (j=0; j<g_numfavoriteservers; j++)\n\t\t\tif (!Q_stricmp(g_arenaservers.favoriteaddresses[i],g_favoriteserverlist[j].adrstr))\n\t\t\t\tbreak;\n\n\t\tif ( j >= g_numfavoriteservers)\n\t\t{\n\t\t\t// not in list, add it\n\t\t\tArenaServers_Insert( g_arenaservers.favoriteaddresses[i], info, ArenaServers_MaxPing() );\n\t\t}\n\t}\n}\n\n\n/*\n=================\nArenaServers_LoadFavorites\n\nLoad cvar address book entries into local lists.\n=================\n*/\nvoid ArenaServers_LoadFavorites( void )\n{\n\tint\t\t\t\ti;\n\tint\t\t\t\tj;\n\tint\t\t\t\tnumtempitems;\n\tchar\t\t\temptyinfo[MAX_INFO_STRING];\n\tchar\t\t\tadrstr[MAX_ADDRESSLENGTH];\n\tservernode_t\ttemplist[MAX_FAVORITESERVERS];\n\tqboolean\t\tfound;\n\n\tfound        = qfalse;\n\temptyinfo[0] = '\\0';\n\n\t// copy the old\n\tmemcpy( templist, g_favoriteserverlist, sizeof(servernode_t)*MAX_FAVORITESERVERS );\n\tnumtempitems = g_numfavoriteservers;\n\n\t// clear the current for sync\n\tmemset( g_favoriteserverlist, 0, sizeof(servernode_t)*MAX_FAVORITESERVERS );\n\tg_numfavoriteservers = 0;\n\n\t// resync existing results with new or deleted cvars\n\tfor (i=0; i<MAX_FAVORITESERVERS; i++)\n\t{\n\t\ttrap_Cvar_VariableStringBuffer( va(\"server%d\",i+1), adrstr, MAX_ADDRESSLENGTH );\n\t\tif (!adrstr[0])\n\t\t\tcontinue;\n\n\t\t// quick sanity check to avoid slow domain name resolving\n\t\t// first character must be numeric\n\t\tif (adrstr[0] < '0' || adrstr[0] > '9')\n\t\t\tcontinue;\n\n\t\t// favorite server addresses must be maintained outside refresh list\n\t\t// this mimics local and global netadr's stored in client\n\t\t// these can be fetched to fill ping list\n\t\tstrcpy( g_arenaservers.favoriteaddresses[g_numfavoriteservers], adrstr );\n\n\t\t// find this server in the old list\n\t\tfor (j=0; j<numtempitems; j++)\n\t\t\tif (!Q_stricmp( templist[j].adrstr, adrstr ))\n\t\t\t\tbreak;\n\n\t\tif (j < numtempitems)\n\t\t{\n\t\t\t// found server - add exisiting results\n\t\t\tmemcpy( &g_favoriteserverlist[g_numfavoriteservers], &templist[j], sizeof(servernode_t) );\n\t\t\tfound = qtrue;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// add new server\n\t\t\tQ_strncpyz( g_favoriteserverlist[g_numfavoriteservers].adrstr, adrstr, MAX_ADDRESSLENGTH );\n\t\t\tg_favoriteserverlist[g_numfavoriteservers].pingtime = ArenaServers_MaxPing();\n\t\t}\n\n\t\tg_numfavoriteservers++;\n\t}\n\n\tg_arenaservers.numfavoriteaddresses = g_numfavoriteservers;\n\n\tif (!found)\n\t{\n\t\t// no results were found, reset server list\n\t\t// list will be automatically refreshed when selected\n\t\tg_numfavoriteservers = 0;\n\t}\n}\n\n\n/*\n=================\nArenaServers_StopRefresh\n=================\n*/\nstatic void ArenaServers_StopRefresh( void )\n{\n\tif (!g_arenaservers.refreshservers)\n\t\t// not currently refreshing\n\t\treturn;\n\n\tg_arenaservers.refreshservers = qfalse;\n\n\tif (g_servertype == AS_FAVORITES)\n\t{\n\t\t// nonresponsive favorites must be shown\n\t\tArenaServers_InsertFavorites();\n\t}\n\n\t// final tally\n\tif (g_arenaservers.numqueriedservers >= 0)\n\t{\n\t\tg_arenaservers.currentping       = *g_arenaservers.numservers;\n\t\tg_arenaservers.numqueriedservers = *g_arenaservers.numservers; \n\t}\n\t\n\t// sort\n\tqsort( g_arenaservers.serverlist, *g_arenaservers.numservers, sizeof( servernode_t ), ArenaServers_Compare);\n\n\tArenaServers_UpdateMenu();\n}\n\n\n/*\n=================\nArenaServers_DoRefresh\n=================\n*/\nstatic void ArenaServers_DoRefresh( void )\n{\n\tint\t\ti;\n\tint\t\tj;\n\tint\t\ttime;\n\tint\t\tmaxPing;\n\tchar\tadrstr[MAX_ADDRESSLENGTH];\n\tchar\tinfo[MAX_INFO_STRING];\n\n\tif (uis.realtime < g_arenaservers.refreshtime)\n\t{\n\t  if (g_servertype != AS_FAVORITES) {\n\t\t\tif (g_servertype == AS_LOCAL) {\n\t\t\t\tif (!trap_LAN_GetServerCount(g_servertype)) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (trap_LAN_GetServerCount(g_servertype) < 0) {\n\t\t\t  // still waiting for response\n\t\t\t  return;\n\t\t\t}\n\t  }\n\t}\n\n\tif (uis.realtime < g_arenaservers.nextpingtime)\n\t{\n\t\t// wait for time trigger\n\t\treturn;\n\t}\n\n\t// trigger at 10Hz intervals\n\tg_arenaservers.nextpingtime = uis.realtime + 10;\n\n\t// process ping results\n\tmaxPing = ArenaServers_MaxPing();\n\tfor (i=0; i<MAX_PINGREQUESTS; i++)\n\t{\n\t\ttrap_LAN_GetPing( i, adrstr, MAX_ADDRESSLENGTH, &time );\n\t\tif (!adrstr[0])\n\t\t{\n\t\t\t// ignore empty or pending pings\n\t\t\tcontinue;\n\t\t}\n\n\t\t// find ping result in our local list\n\t\tfor (j=0; j<MAX_PINGREQUESTS; j++)\n\t\t\tif (!Q_stricmp( adrstr, g_arenaservers.pinglist[j].adrstr ))\n\t\t\t\tbreak;\n\n\t\tif (j < MAX_PINGREQUESTS)\n\t\t{\n\t\t\t// found it\n\t\t\tif (!time)\n\t\t\t{\n\t\t\t\ttime = uis.realtime - g_arenaservers.pinglist[j].start;\n\t\t\t\tif (time < maxPing)\n\t\t\t\t{\n\t\t\t\t\t// still waiting\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (time > maxPing)\n\t\t\t{\n\t\t\t\t// stale it out\n\t\t\t\tinfo[0] = '\\0';\n\t\t\t\ttime    = maxPing;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttrap_LAN_GetPingInfo( i, info, MAX_INFO_STRING );\n\t\t\t}\n\n\t\t\t// insert ping results\n\t\t\tArenaServers_Insert( adrstr, info, time );\n\n\t\t\t// clear this query from internal list\n\t\t\tg_arenaservers.pinglist[j].adrstr[0] = '\\0';\n   \t\t}\n\n\t\t// clear this query from external list\n\t\ttrap_LAN_ClearPing( i );\n\t}\n\n\t// get results of servers query\n\t// counts can increase as servers respond\n\tif (g_servertype == AS_FAVORITES) {\n\t  g_arenaservers.numqueriedservers = g_arenaservers.numfavoriteaddresses;\n\t} else {\n\t  g_arenaservers.numqueriedservers = trap_LAN_GetServerCount(g_servertype);\n\t}\n\n//\tif (g_arenaservers.numqueriedservers > g_arenaservers.maxservers)\n//\t\tg_arenaservers.numqueriedservers = g_arenaservers.maxservers;\n\n\t// send ping requests in reasonable bursts\n\t// iterate ping through all found servers\n\tfor (i=0; i<MAX_PINGREQUESTS && g_arenaservers.currentping < g_arenaservers.numqueriedservers; i++)\n\t{\n\t\tif (trap_LAN_GetPingQueueCount() >= MAX_PINGREQUESTS)\n\t\t{\n\t\t\t// ping queue is full\n\t\t\tbreak;\n\t\t}\n\n\t\t// find empty slot\n\t\tfor (j=0; j<MAX_PINGREQUESTS; j++)\n\t\t\tif (!g_arenaservers.pinglist[j].adrstr[0])\n\t\t\t\tbreak;\n\n\t\tif (j >= MAX_PINGREQUESTS)\n\t\t\t// no empty slots available yet - wait for timeout\n\t\t\tbreak;\n\n\t\t// get an address to ping\n\n\t\tif (g_servertype == AS_FAVORITES) {\n\t\t  strcpy( adrstr, g_arenaservers.favoriteaddresses[g_arenaservers.currentping] ); \t\t\n\t\t} else {\n\t\t  trap_LAN_GetServerAddressString(g_servertype, g_arenaservers.currentping, adrstr, MAX_ADDRESSLENGTH );\n\t\t}\n\n\t\tstrcpy( g_arenaservers.pinglist[j].adrstr, adrstr );\n\t\tg_arenaservers.pinglist[j].start = uis.realtime;\n\n\t\ttrap_Cmd_ExecuteText( EXEC_NOW, va( \"ping %s\\n\", adrstr )  );\n\t\t\n\t\t// advance to next server\n\t\tg_arenaservers.currentping++;\n\t}\n\n\tif (!trap_LAN_GetPingQueueCount())\n\t{\n\t\t// all pings completed\n\t\tArenaServers_StopRefresh();\n\t\treturn;\n\t}\n\n\t// update the user interface with ping status\n\tArenaServers_UpdateMenu();\n}\n\n\n/*\n=================\nArenaServers_StartRefresh\n=================\n*/\nstatic void ArenaServers_StartRefresh( void )\n{\n\tint\t\ti;\n\tchar\tmyargs[32], protocol[32];\n\n\tmemset( g_arenaservers.serverlist, 0, g_arenaservers.maxservers*sizeof(table_t) );\n\n\tfor (i=0; i<MAX_PINGREQUESTS; i++)\n\t{\n\t\tg_arenaservers.pinglist[i].adrstr[0] = '\\0';\n\t\ttrap_LAN_ClearPing( i );\n\t}\n\n\tg_arenaservers.refreshservers    = qtrue;\n\tg_arenaservers.currentping       = 0;\n\tg_arenaservers.nextpingtime      = 0;\n\t*g_arenaservers.numservers       = 0;\n\tg_arenaservers.numqueriedservers = 0;\n\n\t// allow max 5 seconds for responses\n\tg_arenaservers.refreshtime = uis.realtime + 5000;\n\n\t// place menu in zeroed state\n\tArenaServers_UpdateMenu();\n\n\tif( g_servertype == AS_LOCAL ) {\n\t\ttrap_Cmd_ExecuteText( EXEC_APPEND, \"localservers\\n\" );\n\t\treturn;\n\t}\n\n\tif( g_servertype == AS_GLOBAL || g_servertype == AS_MPLAYER ) {\n\t\tif( g_servertype == AS_GLOBAL ) {\n\t\t\ti = 0;\n\t\t}\n\t\telse {\n\t\t\ti = 1;\n\t\t}\n\n\t\tswitch( g_arenaservers.gametype.curvalue ) {\n\t\tdefault:\n\t\tcase GAMES_ALL:\n\t\t\tmyargs[0] = 0;\n\t\t\tbreak;\n\n\t\tcase GAMES_FFA:\n\t\t\tstrcpy( myargs, \" ffa\" );\n\t\t\tbreak;\n\n\t\tcase GAMES_TEAMPLAY:\n\t\t\tstrcpy( myargs, \" team\" );\n\t\t\tbreak;\n\n\t\tcase GAMES_TOURNEY:\n\t\t\tstrcpy( myargs, \" tourney\" );\n\t\t\tbreak;\n\n\t\tcase GAMES_CTF:\n\t\t\tstrcpy( myargs, \" ctf\" );\n\t\t\tbreak;\n\t\t}\n\n\n\t\tif (g_emptyservers) {\n\t\t\tstrcat(myargs, \" empty\");\n\t\t}\n\n\t\tif (g_fullservers) {\n\t\t\tstrcat(myargs, \" full\");\n\t\t}\n\n\t\tprotocol[0] = '\\0';\n\t\ttrap_Cvar_VariableStringBuffer( \"debug_protocol\", protocol, sizeof(protocol) );\n\t\tif (strlen(protocol)) {\n\t\t\ttrap_Cmd_ExecuteText( EXEC_APPEND, va( \"globalservers %d %s%s\\n\", i, protocol, myargs ));\n\t\t}\n\t\telse {\n\t\t\ttrap_Cmd_ExecuteText( EXEC_APPEND, va( \"globalservers %d %d%s\\n\", i, (int)trap_Cvar_VariableValue( \"protocol\" ), myargs ) );\n\t\t}\n\t}\n}\n\n\n/*\n=================\nArenaServers_SaveChanges\n=================\n*/\nvoid ArenaServers_SaveChanges( void )\n{\n\tint\ti;\n\n\tfor (i=0; i<g_arenaservers.numfavoriteaddresses; i++)\n\t\ttrap_Cvar_Set( va(\"server%d\",i+1), g_arenaservers.favoriteaddresses[i] );\n\n\tfor (; i<MAX_FAVORITESERVERS; i++)\n\t\ttrap_Cvar_Set( va(\"server%d\",i+1), \"\" );\n}\n\n\n/*\n=================\nArenaServers_Sort\n=================\n*/\nvoid ArenaServers_Sort( int type ) {\n\tif( g_sortkey == type ) {\n\t\treturn;\n\t}\n\n\tg_sortkey = type;\n\tqsort( g_arenaservers.serverlist, *g_arenaservers.numservers, sizeof( servernode_t ), ArenaServers_Compare);\n}\n\n\n/*\n=================\nArenaServers_SetType\n=================\n*/\nvoid ArenaServers_SetType( int type )\n{\n\tif (g_servertype == type)\n\t\treturn;\n\n\tg_servertype = type;\n\n\tswitch( type ) {\n\tdefault:\n\tcase AS_LOCAL:\n\t\tg_arenaservers.remove.generic.flags |= (QMF_INACTIVE|QMF_HIDDEN);\n\t\tg_arenaservers.serverlist = g_localserverlist;\n\t\tg_arenaservers.numservers = &g_numlocalservers;\n\t\tg_arenaservers.maxservers = MAX_LOCALSERVERS;\n\t\tbreak;\n\n\tcase AS_GLOBAL:\n\t\tg_arenaservers.remove.generic.flags |= (QMF_INACTIVE|QMF_HIDDEN);\n\t\tg_arenaservers.serverlist = g_globalserverlist;\n\t\tg_arenaservers.numservers = &g_numglobalservers;\n\t\tg_arenaservers.maxservers = MAX_GLOBALSERVERS;\n\t\tbreak;\n\n\tcase AS_FAVORITES:\n\t\tg_arenaservers.remove.generic.flags &= ~(QMF_INACTIVE|QMF_HIDDEN);\n\t\tg_arenaservers.serverlist = g_favoriteserverlist;\n\t\tg_arenaservers.numservers = &g_numfavoriteservers;\n\t\tg_arenaservers.maxservers = MAX_FAVORITESERVERS;\n\t\tbreak;\n\n\tcase AS_MPLAYER:\n\t\tg_arenaservers.remove.generic.flags |= (QMF_INACTIVE|QMF_HIDDEN);\n\t\tg_arenaservers.serverlist = g_mplayerserverlist;\n\t\tg_arenaservers.numservers = &g_nummplayerservers;\n\t\tg_arenaservers.maxservers = MAX_GLOBALSERVERS;\n\t\tbreak;\n\t\t\n\t}\n\n\tif( !*g_arenaservers.numservers ) {\n\t\tArenaServers_StartRefresh();\n\t}\n\telse {\n\t\t// avoid slow operation, use existing results\n\t\tg_arenaservers.currentping       = *g_arenaservers.numservers;\n\t\tg_arenaservers.numqueriedservers = *g_arenaservers.numservers; \n\t\tArenaServers_UpdateMenu();\n\t}\n\tstrcpy(g_arenaservers.status.string,\"hit refresh to update\");\n}\n\n/*\n=================\nPunkBuster_Confirm\n=================\n*/\nstatic void Punkbuster_ConfirmEnable( qboolean result ) {\n\tif (result)\n\t{\t\t\n\t\ttrap_SetPbClStatus(1);\n\t}\n\tg_arenaservers.punkbuster.curvalue = Com_Clamp( 0, 1, trap_Cvar_VariableValue( \"cl_punkbuster\" ) );\n}\n\nstatic void Punkbuster_ConfirmDisable( qboolean result ) {\n\tif (result)\n\t{\n\t\ttrap_SetPbClStatus(0);\n\t\tUI_Message( punkbuster_msg );\n\t}\n\tg_arenaservers.punkbuster.curvalue = Com_Clamp( 0, 1, trap_Cvar_VariableValue( \"cl_punkbuster\" ) );\n}\n\n/*\n=================\nArenaServers_Event\n=================\n*/\nstatic void ArenaServers_Event( void* ptr, int event ) {\n\tint\t\tid;\n\tint value;\n\n\tid = ((menucommon_s*)ptr)->id;\n\n\tif( event != QM_ACTIVATED && id != ID_LIST ) {\n\t\treturn;\n\t}\n\n\tswitch( id ) {\n\tcase ID_MASTER:\n\t\tvalue = g_arenaservers.master.curvalue;\n\t\tif (value >= 1)\n\t\t{\n\t\t\tvalue++;\n\t\t}\n\t\ttrap_Cvar_SetValue( \"ui_browserMaster\", value );\n\t\tArenaServers_SetType( value );\n\t\tbreak;\n\n\tcase ID_GAMETYPE:\n\t\ttrap_Cvar_SetValue( \"ui_browserGameType\", g_arenaservers.gametype.curvalue );\n\t\tg_gametype = g_arenaservers.gametype.curvalue;\n\t\tArenaServers_UpdateMenu();\n\t\tbreak;\n\n\tcase ID_SORTKEY:\n\t\ttrap_Cvar_SetValue( \"ui_browserSortKey\", g_arenaservers.sortkey.curvalue );\n\t\tArenaServers_Sort( g_arenaservers.sortkey.curvalue );\n\t\tArenaServers_UpdateMenu();\n\t\tbreak;\n\n\tcase ID_SHOW_FULL:\n\t\ttrap_Cvar_SetValue( \"ui_browserShowFull\", g_arenaservers.showfull.curvalue );\n\t\tg_fullservers = g_arenaservers.showfull.curvalue;\n\t\tArenaServers_UpdateMenu();\n\t\tbreak;\n\n\tcase ID_SHOW_EMPTY:\n\t\ttrap_Cvar_SetValue( \"ui_browserShowEmpty\", g_arenaservers.showempty.curvalue );\n\t\tg_emptyservers = g_arenaservers.showempty.curvalue;\n\t\tArenaServers_UpdateMenu();\n\t\tbreak;\n\n\tcase ID_LIST:\n\t\tif( event == QM_GOTFOCUS ) {\n\t\t\tArenaServers_UpdatePicture();\n\t\t}\n\t\tbreak;\n\n\tcase ID_SCROLL_UP:\n\t\tScrollList_Key( &g_arenaservers.list, K_UPARROW );\n\t\tbreak;\n\n\tcase ID_SCROLL_DOWN:\n\t\tScrollList_Key( &g_arenaservers.list, K_DOWNARROW );\n\t\tbreak;\n\n\tcase ID_BACK:\n\t\tArenaServers_StopRefresh();\n\t\tArenaServers_SaveChanges();\n\t\tUI_PopMenu();\n\t\tbreak;\n\n\tcase ID_REFRESH:\n\t\tArenaServers_StartRefresh();\n\t\tbreak;\n\n\tcase ID_SPECIFY:\n\t\tUI_SpecifyServerMenu();\n\t\tbreak;\n\n\tcase ID_CREATE:\n\t\tUI_StartServerMenu( qtrue );\n\t\tbreak;\n\n\tcase ID_CONNECT:\n\t\tArenaServers_Go();\n\t\tbreak;\n\n\tcase ID_REMOVE:\n\t\tArenaServers_Remove();\n\t\tArenaServers_UpdateMenu();\n\t\tbreak;\n\t\n\tcase ID_PUNKBUSTER:\n\t\tif (g_arenaservers.punkbuster.curvalue)\t\t\t\n\t\t{\n\t\t\tUI_ConfirmMenu_Style( \"Enable Punkbuster?\",  UI_CENTER|UI_INVERSE|UI_SMALLFONT, (voidfunc_f)NULL, Punkbuster_ConfirmEnable );\n\t\t}\n\t\telse\n\t\t{\n\t\t\tUI_ConfirmMenu_Style( \"Disable Punkbuster?\", UI_CENTER|UI_INVERSE|UI_SMALLFONT, (voidfunc_f)NULL, Punkbuster_ConfirmDisable );\n\t\t}\n\t\tbreak;\n\t}\n}\n\n\n/*\n=================\nArenaServers_MenuDraw\n=================\n*/\nstatic void ArenaServers_MenuDraw( void )\n{\n\tif (g_arenaservers.refreshservers)\n\t\tArenaServers_DoRefresh();\n\n\tMenu_Draw( &g_arenaservers.menu );\n}\n\n\n/*\n=================\nArenaServers_MenuKey\n=================\n*/\nstatic sfxHandle_t ArenaServers_MenuKey( int key ) {\n\tif( key == K_SPACE  && g_arenaservers.refreshservers ) {\n\t\tArenaServers_StopRefresh();\t\n\t\treturn menu_move_sound;\n\t}\n\n\tif( ( key == K_DEL || key == K_KP_DEL ) && ( g_servertype == AS_FAVORITES ) &&\n\t\t( Menu_ItemAtCursor( &g_arenaservers.menu) == &g_arenaservers.list ) ) {\n\t\tArenaServers_Remove();\n\t\tArenaServers_UpdateMenu();\n\t\treturn menu_move_sound;\n\t}\n\n\tif( key == K_MOUSE2 || key == K_ESCAPE ) {\n\t\tArenaServers_StopRefresh();\n\t\tArenaServers_SaveChanges();\n\t}\n\n\n\treturn Menu_DefaultKey( &g_arenaservers.menu, key );\n}\n\n\n/*\n=================\nArenaServers_MenuInit\n=================\n*/\nstatic void ArenaServers_MenuInit( void ) {\n\tint\t\t\ti;\n\tint\t\t\ttype;\n\tint\t\t\ty;\n\tint\t\t\tvalue;\n\tstatic char\tstatusbuffer[MAX_STATUSLENGTH];\n\n\t// zero set all our globals\n\tmemset( &g_arenaservers, 0 ,sizeof(arenaservers_t) );\n\n\tArenaServers_Cache();\n\n\tg_arenaservers.menu.fullscreen = qtrue;\n\tg_arenaservers.menu.wrapAround = qtrue;\n\tg_arenaservers.menu.draw       = ArenaServers_MenuDraw;\n\tg_arenaservers.menu.key        = ArenaServers_MenuKey;\n\n\tg_arenaservers.banner.generic.type  = MTYPE_BTEXT;\n\tg_arenaservers.banner.generic.flags = QMF_CENTER_JUSTIFY;\n\tg_arenaservers.banner.generic.x\t    = 320;\n\tg_arenaservers.banner.generic.y\t    = 16;\n\tg_arenaservers.banner.string  \t\t= \"ARENA SERVERS\";\n\tg_arenaservers.banner.style  \t    = UI_CENTER;\n\tg_arenaservers.banner.color  \t    = color_white;\n\n\ty = 80;\n\tg_arenaservers.master.generic.type\t\t\t= MTYPE_SPINCONTROL;\n\tg_arenaservers.master.generic.name\t\t\t= \"Servers:\";\n\tg_arenaservers.master.generic.flags\t\t\t= QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\tg_arenaservers.master.generic.callback\t\t= ArenaServers_Event;\n\tg_arenaservers.master.generic.id\t\t\t= ID_MASTER;\n\tg_arenaservers.master.generic.x\t\t\t\t= 320;\n\tg_arenaservers.master.generic.y\t\t\t\t= y;\n\tg_arenaservers.master.itemnames\t\t\t\t= master_items;\n\n\ty += SMALLCHAR_HEIGHT;\n\tg_arenaservers.gametype.generic.type\t\t= MTYPE_SPINCONTROL;\n\tg_arenaservers.gametype.generic.name\t\t= \"Game Type:\";\n\tg_arenaservers.gametype.generic.flags\t\t= QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\tg_arenaservers.gametype.generic.callback\t= ArenaServers_Event;\n\tg_arenaservers.gametype.generic.id\t\t\t= ID_GAMETYPE;\n\tg_arenaservers.gametype.generic.x\t\t\t= 320;\n\tg_arenaservers.gametype.generic.y\t\t\t= y;\n\tg_arenaservers.gametype.itemnames\t\t\t= servertype_items;\n\n\ty += SMALLCHAR_HEIGHT;\n\tg_arenaservers.sortkey.generic.type\t\t\t= MTYPE_SPINCONTROL;\n\tg_arenaservers.sortkey.generic.name\t\t\t= \"Sort By:\";\n\tg_arenaservers.sortkey.generic.flags\t\t= QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\tg_arenaservers.sortkey.generic.callback\t\t= ArenaServers_Event;\n\tg_arenaservers.sortkey.generic.id\t\t\t= ID_SORTKEY;\n\tg_arenaservers.sortkey.generic.x\t\t\t= 320;\n\tg_arenaservers.sortkey.generic.y\t\t\t= y;\n\tg_arenaservers.sortkey.itemnames\t\t\t= sortkey_items;\n\n\ty += SMALLCHAR_HEIGHT;\n\tg_arenaservers.showfull.generic.type\t\t= MTYPE_RADIOBUTTON;\n\tg_arenaservers.showfull.generic.name\t\t= \"Show Full:\";\n\tg_arenaservers.showfull.generic.flags\t\t= QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\tg_arenaservers.showfull.generic.callback\t= ArenaServers_Event;\n\tg_arenaservers.showfull.generic.id\t\t\t= ID_SHOW_FULL;\n\tg_arenaservers.showfull.generic.x\t\t\t= 320;\n\tg_arenaservers.showfull.generic.y\t\t\t= y;\n\n\ty += SMALLCHAR_HEIGHT;\n\tg_arenaservers.showempty.generic.type\t\t= MTYPE_RADIOBUTTON;\n\tg_arenaservers.showempty.generic.name\t\t= \"Show Empty:\";\n\tg_arenaservers.showempty.generic.flags\t\t= QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\tg_arenaservers.showempty.generic.callback\t= ArenaServers_Event;\n\tg_arenaservers.showempty.generic.id\t\t\t= ID_SHOW_EMPTY;\n\tg_arenaservers.showempty.generic.x\t\t\t= 320;\n\tg_arenaservers.showempty.generic.y\t\t\t= y;\n\n\ty += 3 * SMALLCHAR_HEIGHT;\n\tg_arenaservers.list.generic.type\t\t\t= MTYPE_SCROLLLIST;\n\tg_arenaservers.list.generic.flags\t\t\t= QMF_HIGHLIGHT_IF_FOCUS;\n\tg_arenaservers.list.generic.id\t\t\t\t= ID_LIST;\n\tg_arenaservers.list.generic.callback\t\t= ArenaServers_Event;\n\tg_arenaservers.list.generic.x\t\t\t\t= 72;\n\tg_arenaservers.list.generic.y\t\t\t\t= y;\n\tg_arenaservers.list.width\t\t\t\t\t= MAX_LISTBOXWIDTH;\n\tg_arenaservers.list.height\t\t\t\t\t= 11;\n\tg_arenaservers.list.itemnames\t\t\t\t= (const char **)g_arenaservers.items;\n\tfor( i = 0; i < MAX_LISTBOXITEMS; i++ ) {\n\t\tg_arenaservers.items[i] = g_arenaservers.table[i].buff;\n\t}\n\n\tg_arenaservers.mappic.generic.type\t\t\t= MTYPE_BITMAP;\n\tg_arenaservers.mappic.generic.flags\t\t\t= QMF_LEFT_JUSTIFY|QMF_INACTIVE;\n\tg_arenaservers.mappic.generic.x\t\t\t\t= 72;\n\tg_arenaservers.mappic.generic.y\t\t\t\t= 80;\n\tg_arenaservers.mappic.width\t\t\t\t\t= 128;\n\tg_arenaservers.mappic.height\t\t\t\t= 96;\n\tg_arenaservers.mappic.errorpic\t\t\t\t= ART_UNKNOWNMAP;\n\n\tg_arenaservers.arrows.generic.type\t\t\t= MTYPE_BITMAP;\n\tg_arenaservers.arrows.generic.name\t\t\t= ART_ARROWS0;\n\tg_arenaservers.arrows.generic.flags\t\t\t= QMF_LEFT_JUSTIFY|QMF_INACTIVE;\n\tg_arenaservers.arrows.generic.callback\t\t= ArenaServers_Event;\n\tg_arenaservers.arrows.generic.x\t\t\t\t= 512+48;\n\tg_arenaservers.arrows.generic.y\t\t\t\t= 240-64+16;\n\tg_arenaservers.arrows.width\t\t\t\t\t= 64;\n\tg_arenaservers.arrows.height\t\t\t\t= 128;\n\n\tg_arenaservers.up.generic.type\t\t\t\t= MTYPE_BITMAP;\n\tg_arenaservers.up.generic.flags\t\t\t\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_MOUSEONLY;\n\tg_arenaservers.up.generic.callback\t\t\t= ArenaServers_Event;\n\tg_arenaservers.up.generic.id\t\t\t\t= ID_SCROLL_UP;\n\tg_arenaservers.up.generic.x\t\t\t\t\t= 512+48;\n\tg_arenaservers.up.generic.y\t\t\t\t\t= 240-64+16;\n\tg_arenaservers.up.width\t\t\t\t\t\t= 64;\n\tg_arenaservers.up.height\t\t\t\t\t= 64;\n\tg_arenaservers.up.focuspic\t\t\t\t\t= ART_ARROWS_UP;\n\n\tg_arenaservers.down.generic.type\t\t\t= MTYPE_BITMAP;\n\tg_arenaservers.down.generic.flags\t\t\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_MOUSEONLY;\n\tg_arenaservers.down.generic.callback\t\t= ArenaServers_Event;\n\tg_arenaservers.down.generic.id\t\t\t\t= ID_SCROLL_DOWN;\n\tg_arenaservers.down.generic.x\t\t\t\t= 512+48;\n\tg_arenaservers.down.generic.y\t\t\t\t= 240+16;\n\tg_arenaservers.down.width\t\t\t\t\t= 64;\n\tg_arenaservers.down.height\t\t\t\t\t= 64;\n\tg_arenaservers.down.focuspic\t\t\t\t= ART_ARROWS_DOWN;\n\n\ty = 376;\n\tg_arenaservers.status.generic.type\t\t= MTYPE_TEXT;\n\tg_arenaservers.status.generic.x\t\t\t= 320;\n\tg_arenaservers.status.generic.y\t\t\t= y;\n\tg_arenaservers.status.string\t\t\t= statusbuffer;\n\tg_arenaservers.status.style\t\t\t\t= UI_CENTER|UI_SMALLFONT;\n\tg_arenaservers.status.color\t\t\t\t= menu_text_color;\n\n\ty += SMALLCHAR_HEIGHT;\n\tg_arenaservers.statusbar.generic.type   = MTYPE_TEXT;\n\tg_arenaservers.statusbar.generic.x\t    = 320;\n\tg_arenaservers.statusbar.generic.y\t    = y;\n\tg_arenaservers.statusbar.string\t        = \"\";\n\tg_arenaservers.statusbar.style\t        = UI_CENTER|UI_SMALLFONT;\n\tg_arenaservers.statusbar.color\t        = text_color_normal;\n\n\tg_arenaservers.remove.generic.type\t\t= MTYPE_BITMAP;\n\tg_arenaservers.remove.generic.name\t\t= ART_REMOVE0;\n\tg_arenaservers.remove.generic.flags\t\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\tg_arenaservers.remove.generic.callback\t= ArenaServers_Event;\n\tg_arenaservers.remove.generic.id\t\t= ID_REMOVE;\n\tg_arenaservers.remove.generic.x\t\t\t= 450;\n\tg_arenaservers.remove.generic.y\t\t\t= 86;\n\tg_arenaservers.remove.width\t\t\t\t= 96;\n\tg_arenaservers.remove.height\t\t\t= 48;\n\tg_arenaservers.remove.focuspic\t\t\t= ART_REMOVE1;\n\n\tg_arenaservers.back.generic.type\t\t= MTYPE_BITMAP;\n\tg_arenaservers.back.generic.name\t\t= ART_BACK0;\n\tg_arenaservers.back.generic.flags\t\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\tg_arenaservers.back.generic.callback\t= ArenaServers_Event;\n\tg_arenaservers.back.generic.id\t\t\t= ID_BACK;\n\tg_arenaservers.back.generic.x\t\t\t= 0;\n\tg_arenaservers.back.generic.y\t\t\t= 480-64;\n\tg_arenaservers.back.width\t\t\t\t= 128;\n\tg_arenaservers.back.height\t\t\t\t= 64;\n\tg_arenaservers.back.focuspic\t\t\t= ART_BACK1;\n\n\tg_arenaservers.specify.generic.type\t    = MTYPE_BITMAP;\n\tg_arenaservers.specify.generic.name\t\t= ART_SPECIFY0;\n\tg_arenaservers.specify.generic.flags    = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\tg_arenaservers.specify.generic.callback = ArenaServers_Event;\n\tg_arenaservers.specify.generic.id\t    = ID_SPECIFY;\n\tg_arenaservers.specify.generic.x\t\t= 128;\n\tg_arenaservers.specify.generic.y\t\t= 480-64;\n\tg_arenaservers.specify.width  \t\t    = 128;\n\tg_arenaservers.specify.height  \t\t    = 64;\n\tg_arenaservers.specify.focuspic         = ART_SPECIFY1;\n\n\tg_arenaservers.refresh.generic.type\t\t= MTYPE_BITMAP;\n\tg_arenaservers.refresh.generic.name\t\t= ART_REFRESH0;\n\tg_arenaservers.refresh.generic.flags\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\tg_arenaservers.refresh.generic.callback\t= ArenaServers_Event;\n\tg_arenaservers.refresh.generic.id\t\t= ID_REFRESH;\n\tg_arenaservers.refresh.generic.x\t\t= 256;\n\tg_arenaservers.refresh.generic.y\t\t= 480-64;\n\tg_arenaservers.refresh.width\t\t\t= 128;\n\tg_arenaservers.refresh.height\t\t\t= 64;\n\tg_arenaservers.refresh.focuspic\t\t\t= ART_REFRESH1;\n\n\tg_arenaservers.create.generic.type\t\t= MTYPE_BITMAP;\n\tg_arenaservers.create.generic.name\t\t= ART_CREATE0;\n\tg_arenaservers.create.generic.flags\t\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\tg_arenaservers.create.generic.callback\t= ArenaServers_Event;\n\tg_arenaservers.create.generic.id\t\t= ID_CREATE;\n\tg_arenaservers.create.generic.x\t\t\t= 384;\n\tg_arenaservers.create.generic.y\t\t\t= 480-64;\n\tg_arenaservers.create.width\t\t\t\t= 128;\n\tg_arenaservers.create.height\t\t\t= 64;\n\tg_arenaservers.create.focuspic\t\t\t= ART_CREATE1;\n\n\tg_arenaservers.go.generic.type\t\t\t= MTYPE_BITMAP;\n\tg_arenaservers.go.generic.name\t\t\t= ART_CONNECT0;\n\tg_arenaservers.go.generic.flags\t\t\t= QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;\n\tg_arenaservers.go.generic.callback\t\t= ArenaServers_Event;\n\tg_arenaservers.go.generic.id\t\t\t= ID_CONNECT;\n\tg_arenaservers.go.generic.x\t\t\t\t= 640;\n\tg_arenaservers.go.generic.y\t\t\t\t= 480-64;\n\tg_arenaservers.go.width\t\t\t\t\t= 128;\n\tg_arenaservers.go.height\t\t\t\t= 64;\n\tg_arenaservers.go.focuspic\t\t\t\t= ART_CONNECT1;\n\n\tg_arenaservers.punkbuster.generic.type\t\t\t= MTYPE_SPINCONTROL;\n\tg_arenaservers.punkbuster.generic.name\t\t\t= \"Punkbuster:\";\n\tg_arenaservers.punkbuster.generic.flags\t\t\t= QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\tg_arenaservers.punkbuster.generic.callback\t\t= ArenaServers_Event;\n\tg_arenaservers.punkbuster.generic.id\t\t\t= ID_PUNKBUSTER;\n\tg_arenaservers.punkbuster.generic.x\t\t\t\t= 480+32;\n\tg_arenaservers.punkbuster.generic.y\t\t\t\t= 144;\n\tg_arenaservers.punkbuster.itemnames\t\t\t\t= punkbuster_items;\n\t\n\tg_arenaservers.pblogo.generic.type\t\t\t= MTYPE_BITMAP;\n\tg_arenaservers.pblogo.generic.name\t\t\t= ART_PUNKBUSTER;\n\tg_arenaservers.pblogo.generic.flags\t\t\t= QMF_LEFT_JUSTIFY|QMF_INACTIVE;\n\tg_arenaservers.pblogo.generic.x\t\t\t\t= 526;\n\tg_arenaservers.pblogo.generic.y\t\t\t\t= 176;\n\tg_arenaservers.pblogo.width\t\t\t\t\t= 32;\n\tg_arenaservers.pblogo.height\t\t\t\t= 16;\n\tg_arenaservers.pblogo.errorpic\t\t\t\t= ART_UNKNOWNMAP;\n\t\n\tMenu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.banner );\n\n\tMenu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.master );\n\tMenu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.gametype );\n\tMenu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.sortkey );\n\tMenu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.showfull);\n\tMenu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.showempty );\n\n\tMenu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.mappic );\n\tMenu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.list );\n\tMenu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.status );\n\tMenu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.statusbar );\n\tMenu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.arrows );\n\tMenu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.up );\n\tMenu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.down );\n\n\tMenu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.remove );\n\tMenu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.back );\n\tMenu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.specify );\n\tMenu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.refresh );\n\tMenu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.create );\n\tMenu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.go );\n\n\tMenu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.punkbuster );\n\tMenu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.pblogo );\n\t\n\tArenaServers_LoadFavorites();\n\n\tg_servertype = Com_Clamp( 0, 3, ui_browserMaster.integer );\n\t// hack to get rid of MPlayer stuff\n\tvalue = g_servertype;\n\tif (value >= 1)\n\t\tvalue--;\n\tg_arenaservers.master.curvalue = value;\n\n\tg_gametype = Com_Clamp( 0, 4, ui_browserGameType.integer );\n\tg_arenaservers.gametype.curvalue = g_gametype;\n\n\tg_sortkey = Com_Clamp( 0, 4, ui_browserSortKey.integer );\n\tg_arenaservers.sortkey.curvalue = g_sortkey;\n\n\tg_fullservers = Com_Clamp( 0, 1, ui_browserShowFull.integer );\n\tg_arenaservers.showfull.curvalue = g_fullservers;\n\n\tg_emptyservers = Com_Clamp( 0, 1, ui_browserShowEmpty.integer );\n\tg_arenaservers.showempty.curvalue = g_emptyservers;\n\t\n\tg_arenaservers.punkbuster.curvalue = Com_Clamp( 0, 1, trap_Cvar_VariableValue( \"cl_punkbuster\" ) );\n\n\t// force to initial state and refresh\n\ttype = g_servertype;\n\tg_servertype = -1;\n\tArenaServers_SetType( type );\n\n\ttrap_Cvar_Register(NULL, \"debug_protocol\", \"\", 0 );\n}\n\n\n/*\n=================\nArenaServers_Cache\n=================\n*/\nvoid ArenaServers_Cache( void ) {\n\ttrap_R_RegisterShaderNoMip( ART_BACK0 );\n\ttrap_R_RegisterShaderNoMip( ART_BACK1 );\n\ttrap_R_RegisterShaderNoMip( ART_CREATE0 );\n\ttrap_R_RegisterShaderNoMip( ART_CREATE1 );\n\ttrap_R_RegisterShaderNoMip( ART_SPECIFY0 );\n\ttrap_R_RegisterShaderNoMip( ART_SPECIFY1 );\n\ttrap_R_RegisterShaderNoMip( ART_REFRESH0 );\n\ttrap_R_RegisterShaderNoMip( ART_REFRESH1 );\n\ttrap_R_RegisterShaderNoMip( ART_CONNECT0 );\n\ttrap_R_RegisterShaderNoMip( ART_CONNECT1 );\n\ttrap_R_RegisterShaderNoMip( ART_ARROWS0  );\n\ttrap_R_RegisterShaderNoMip( ART_ARROWS_UP );\n\ttrap_R_RegisterShaderNoMip( ART_ARROWS_DOWN );\n\ttrap_R_RegisterShaderNoMip( ART_UNKNOWNMAP );\n\ttrap_R_RegisterShaderNoMip( ART_PUNKBUSTER );\n}\n\n\n/*\n=================\nUI_ArenaServersMenu\n=================\n*/\nvoid UI_ArenaServersMenu( void ) {\n\tArenaServers_MenuInit();\n\tUI_PushMenu( &g_arenaservers.menu );\n}\t\t\t\t\t\t  \n"
  },
  {
    "path": "src/q3_ui/ui_setup.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n/*\n=======================================================================\n\nSETUP MENU\n\n=======================================================================\n*/\n\n\n#include \"ui_local.h\"\n\n\n#define SETUP_MENU_VERTICAL_SPACING\t\t34\n\n#define ART_BACK0\t\t\"menu/art/back_0\"\n#define ART_BACK1\t\t\"menu/art/back_1\"\t\n#define ART_FRAMEL\t\t\"menu/art/frame2_l\"\n#define ART_FRAMER\t\t\"menu/art/frame1_r\"\n\n#define ID_CUSTOMIZEPLAYER\t\t10\n#define ID_CUSTOMIZECONTROLS\t11\n#define ID_SYSTEMCONFIG\t\t\t12\n#define ID_GAME\t\t\t\t\t13\n#define ID_CDKEY\t\t\t\t14\n#define ID_LOAD\t\t\t\t\t15\n#define ID_SAVE\t\t\t\t\t16\n#define ID_DEFAULTS\t\t\t\t17\n#define ID_BACK\t\t\t\t\t18\n\n\ntypedef struct {\n\tmenuframework_s\tmenu;\n\n\tmenutext_s\t\tbanner;\n\tmenubitmap_s\tframel;\n\tmenubitmap_s\tframer;\n\tmenutext_s\t\tsetupplayer;\n\tmenutext_s\t\tsetupcontrols;\n\tmenutext_s\t\tsetupsystem;\n\tmenutext_s\t\tgame;\n\tmenutext_s\t\tcdkey;\n//\tmenutext_s\t\tload;\n//\tmenutext_s\t\tsave;\n\tmenutext_s\t\tdefaults;\n\tmenubitmap_s\tback;\n} setupMenuInfo_t;\n\nstatic setupMenuInfo_t\tsetupMenuInfo;\n\n\n/*\n=================\nSetup_ResetDefaults_Action\n=================\n*/\nstatic void Setup_ResetDefaults_Action( qboolean result ) {\n\tif( !result ) {\n\t\treturn;\n\t}\n\ttrap_Cmd_ExecuteText( EXEC_APPEND, \"exec default.cfg\\n\");\n\ttrap_Cmd_ExecuteText( EXEC_APPEND, \"cvar_restart\\n\");\n\ttrap_Cmd_ExecuteText( EXEC_APPEND, \"vid_restart\\n\" );\n}\n\n\n/*\n=================\nSetup_ResetDefaults_Draw\n=================\n*/\nstatic void Setup_ResetDefaults_Draw( void ) {\n\tUI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 0, \"WARNING: This will reset *ALL*\", UI_CENTER|UI_SMALLFONT, color_yellow );\n\tUI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 1, \"options to their default values.\", UI_CENTER|UI_SMALLFONT, color_yellow );\n}\n\n\n/*\n===============\nUI_SetupMenu_Event\n===============\n*/\nstatic void UI_SetupMenu_Event( void *ptr, int event ) {\n\tif( event != QM_ACTIVATED ) {\n\t\treturn;\n\t}\n\n\tswitch( ((menucommon_s*)ptr)->id ) {\n\tcase ID_CUSTOMIZEPLAYER:\n\t\tUI_PlayerSettingsMenu();\n\t\tbreak;\n\n\tcase ID_CUSTOMIZECONTROLS:\n\t\tUI_ControlsMenu();\n\t\tbreak;\n\n\tcase ID_SYSTEMCONFIG:\n\t\tUI_GraphicsOptionsMenu();\n\t\tbreak;\n\n\tcase ID_GAME:\n\t\tUI_PreferencesMenu();\n\t\tbreak;\n\n\tcase ID_CDKEY:\n\t\tUI_CDKeyMenu();\n\t\tbreak;\n\n//\tcase ID_LOAD:\n//\t\tUI_LoadConfigMenu();\n//\t\tbreak;\n\n//\tcase ID_SAVE:\n//\t\tUI_SaveConfigMenu();\n//\t\tbreak;\n\n\tcase ID_DEFAULTS:\n\t\tUI_ConfirmMenu( \"SET TO DEFAULTS?\", Setup_ResetDefaults_Draw, Setup_ResetDefaults_Action );\n\t\tbreak;\n\n\tcase ID_BACK:\n\t\tUI_PopMenu();\n\t\tbreak;\n\t}\n}\n\n\n/*\n===============\nUI_SetupMenu_Init\n===============\n*/\nstatic void UI_SetupMenu_Init( void ) {\n\tint\t\t\t\ty;\n\n\tUI_SetupMenu_Cache();\n\n\tmemset( &setupMenuInfo, 0, sizeof(setupMenuInfo) );\n\tsetupMenuInfo.menu.wrapAround = qtrue;\n\tsetupMenuInfo.menu.fullscreen = qtrue;\n\n\tsetupMenuInfo.banner.generic.type\t\t\t\t= MTYPE_BTEXT;\n\tsetupMenuInfo.banner.generic.x\t\t\t\t\t= 320;\n\tsetupMenuInfo.banner.generic.y\t\t\t\t\t= 16;\n\tsetupMenuInfo.banner.string\t\t\t\t\t\t= \"SETUP\";\n\tsetupMenuInfo.banner.color\t\t\t\t\t\t= color_white;\n\tsetupMenuInfo.banner.style\t\t\t\t\t\t= UI_CENTER;\n\n\tsetupMenuInfo.framel.generic.type\t\t\t\t= MTYPE_BITMAP;\n\tsetupMenuInfo.framel.generic.name\t\t\t\t= ART_FRAMEL;\n\tsetupMenuInfo.framel.generic.flags\t\t\t\t= QMF_INACTIVE;\n\tsetupMenuInfo.framel.generic.x\t\t\t\t\t= 0;  \n\tsetupMenuInfo.framel.generic.y\t\t\t\t\t= 78;\n\tsetupMenuInfo.framel.width  \t\t\t\t\t= 256;\n\tsetupMenuInfo.framel.height  \t\t\t\t\t= 329;\n\n\tsetupMenuInfo.framer.generic.type\t\t\t\t= MTYPE_BITMAP;\n\tsetupMenuInfo.framer.generic.name\t\t\t\t= ART_FRAMER;\n\tsetupMenuInfo.framer.generic.flags\t\t\t\t= QMF_INACTIVE;\n\tsetupMenuInfo.framer.generic.x\t\t\t\t\t= 376;\n\tsetupMenuInfo.framer.generic.y\t\t\t\t\t= 76;\n\tsetupMenuInfo.framer.width  \t\t\t\t\t= 256;\n\tsetupMenuInfo.framer.height  \t\t\t\t\t= 334;\n\n\ty = 134;\n\tsetupMenuInfo.setupplayer.generic.type\t\t\t= MTYPE_PTEXT;\n\tsetupMenuInfo.setupplayer.generic.flags\t\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\tsetupMenuInfo.setupplayer.generic.x\t\t\t\t= 320;\n\tsetupMenuInfo.setupplayer.generic.y\t\t\t\t= y;\n\tsetupMenuInfo.setupplayer.generic.id\t\t\t= ID_CUSTOMIZEPLAYER;\n\tsetupMenuInfo.setupplayer.generic.callback\t\t= UI_SetupMenu_Event; \n\tsetupMenuInfo.setupplayer.string\t\t\t\t= \"PLAYER\";\n\tsetupMenuInfo.setupplayer.color\t\t\t\t\t= color_red;\n\tsetupMenuInfo.setupplayer.style\t\t\t\t\t= UI_CENTER;\n\n\ty += SETUP_MENU_VERTICAL_SPACING;\n\tsetupMenuInfo.setupcontrols.generic.type\t\t= MTYPE_PTEXT;\n\tsetupMenuInfo.setupcontrols.generic.flags\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\tsetupMenuInfo.setupcontrols.generic.x\t\t\t= 320;\n\tsetupMenuInfo.setupcontrols.generic.y\t\t\t= y;\n\tsetupMenuInfo.setupcontrols.generic.id\t\t\t= ID_CUSTOMIZECONTROLS;\n\tsetupMenuInfo.setupcontrols.generic.callback\t= UI_SetupMenu_Event; \n\tsetupMenuInfo.setupcontrols.string\t\t\t\t= \"CONTROLS\";\n\tsetupMenuInfo.setupcontrols.color\t\t\t\t= color_red;\n\tsetupMenuInfo.setupcontrols.style\t\t\t\t= UI_CENTER;\n\n\ty += SETUP_MENU_VERTICAL_SPACING;\n\tsetupMenuInfo.setupsystem.generic.type\t\t\t= MTYPE_PTEXT;\n\tsetupMenuInfo.setupsystem.generic.flags\t\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\tsetupMenuInfo.setupsystem.generic.x\t\t\t\t= 320;\n\tsetupMenuInfo.setupsystem.generic.y\t\t\t\t= y;\n\tsetupMenuInfo.setupsystem.generic.id\t\t\t= ID_SYSTEMCONFIG;\n\tsetupMenuInfo.setupsystem.generic.callback\t\t= UI_SetupMenu_Event; \n\tsetupMenuInfo.setupsystem.string\t\t\t\t= \"SYSTEM\";\n\tsetupMenuInfo.setupsystem.color\t\t\t\t\t= color_red;\n\tsetupMenuInfo.setupsystem.style\t\t\t\t\t= UI_CENTER;\n\n\ty += SETUP_MENU_VERTICAL_SPACING;\n\tsetupMenuInfo.game.generic.type\t\t\t\t\t= MTYPE_PTEXT;\n\tsetupMenuInfo.game.generic.flags\t\t\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\tsetupMenuInfo.game.generic.x\t\t\t\t\t= 320;\n\tsetupMenuInfo.game.generic.y\t\t\t\t\t= y;\n\tsetupMenuInfo.game.generic.id\t\t\t\t\t= ID_GAME;\n\tsetupMenuInfo.game.generic.callback\t\t\t\t= UI_SetupMenu_Event; \n\tsetupMenuInfo.game.string\t\t\t\t\t\t= \"GAME OPTIONS\";\n\tsetupMenuInfo.game.color\t\t\t\t\t\t= color_red;\n\tsetupMenuInfo.game.style\t\t\t\t\t\t= UI_CENTER;\n\n\ty += SETUP_MENU_VERTICAL_SPACING;\n\tsetupMenuInfo.cdkey.generic.type\t\t\t\t= MTYPE_PTEXT;\n\tsetupMenuInfo.cdkey.generic.flags\t\t\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\tsetupMenuInfo.cdkey.generic.x\t\t\t\t\t= 320;\n\tsetupMenuInfo.cdkey.generic.y\t\t\t\t\t= y;\n\tsetupMenuInfo.cdkey.generic.id\t\t\t\t\t= ID_CDKEY;\n\tsetupMenuInfo.cdkey.generic.callback\t\t\t= UI_SetupMenu_Event; \n\tsetupMenuInfo.cdkey.string\t\t\t\t\t\t= \"CD Key\";\n\tsetupMenuInfo.cdkey.color\t\t\t\t\t\t= color_red;\n\tsetupMenuInfo.cdkey.style\t\t\t\t\t\t= UI_CENTER;\n\n\tif( !trap_Cvar_VariableValue( \"cl_paused\" ) ) {\n#if 0\n\t\ty += SETUP_MENU_VERTICAL_SPACING;\n\t\tsetupMenuInfo.load.generic.type\t\t\t\t\t= MTYPE_PTEXT;\n\t\tsetupMenuInfo.load.generic.flags\t\t\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\t\tsetupMenuInfo.load.generic.x\t\t\t\t\t= 320;\n\t\tsetupMenuInfo.load.generic.y\t\t\t\t\t= y;\n\t\tsetupMenuInfo.load.generic.id\t\t\t\t\t= ID_LOAD;\n\t\tsetupMenuInfo.load.generic.callback\t\t\t\t= UI_SetupMenu_Event; \n\t\tsetupMenuInfo.load.string\t\t\t\t\t\t= \"LOAD\";\n\t\tsetupMenuInfo.load.color\t\t\t\t\t\t= color_red;\n\t\tsetupMenuInfo.load.style\t\t\t\t\t\t= UI_CENTER;\n\n\t\ty += SETUP_MENU_VERTICAL_SPACING;\n\t\tsetupMenuInfo.save.generic.type\t\t\t\t\t= MTYPE_PTEXT;\n\t\tsetupMenuInfo.save.generic.flags\t\t\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\t\tsetupMenuInfo.save.generic.x\t\t\t\t\t= 320;\n\t\tsetupMenuInfo.save.generic.y\t\t\t\t\t= y;\n\t\tsetupMenuInfo.save.generic.id\t\t\t\t\t= ID_SAVE;\n\t\tsetupMenuInfo.save.generic.callback\t\t\t\t= UI_SetupMenu_Event; \n\t\tsetupMenuInfo.save.string\t\t\t\t\t\t= \"SAVE\";\n\t\tsetupMenuInfo.save.color\t\t\t\t\t\t= color_red;\n\t\tsetupMenuInfo.save.style\t\t\t\t\t\t= UI_CENTER;\n#endif\n\n\t\ty += SETUP_MENU_VERTICAL_SPACING;\n\t\tsetupMenuInfo.defaults.generic.type\t\t\t\t= MTYPE_PTEXT;\n\t\tsetupMenuInfo.defaults.generic.flags\t\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\t\tsetupMenuInfo.defaults.generic.x\t\t\t\t= 320;\n\t\tsetupMenuInfo.defaults.generic.y\t\t\t\t= y;\n\t\tsetupMenuInfo.defaults.generic.id\t\t\t\t= ID_DEFAULTS;\n\t\tsetupMenuInfo.defaults.generic.callback\t\t\t= UI_SetupMenu_Event; \n\t\tsetupMenuInfo.defaults.string\t\t\t\t\t= \"DEFAULTS\";\n\t\tsetupMenuInfo.defaults.color\t\t\t\t\t= color_red;\n\t\tsetupMenuInfo.defaults.style\t\t\t\t\t= UI_CENTER;\n\t}\n\n\tsetupMenuInfo.back.generic.type\t\t\t\t\t= MTYPE_BITMAP;\n\tsetupMenuInfo.back.generic.name\t\t\t\t\t= ART_BACK0;\n\tsetupMenuInfo.back.generic.flags\t\t\t\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\tsetupMenuInfo.back.generic.id\t\t\t\t\t= ID_BACK;\n\tsetupMenuInfo.back.generic.callback\t\t\t\t= UI_SetupMenu_Event;\n\tsetupMenuInfo.back.generic.x\t\t\t\t\t= 0;\n\tsetupMenuInfo.back.generic.y\t\t\t\t\t= 480-64;\n\tsetupMenuInfo.back.width\t\t\t\t\t\t= 128;\n\tsetupMenuInfo.back.height\t\t\t\t\t\t= 64;\n\tsetupMenuInfo.back.focuspic\t\t\t\t\t\t= ART_BACK1;\n\n\tMenu_AddItem( &setupMenuInfo.menu, &setupMenuInfo.banner );\n\tMenu_AddItem( &setupMenuInfo.menu, &setupMenuInfo.framel );\n\tMenu_AddItem( &setupMenuInfo.menu, &setupMenuInfo.framer );\n\tMenu_AddItem( &setupMenuInfo.menu, &setupMenuInfo.setupplayer );\n\tMenu_AddItem( &setupMenuInfo.menu, &setupMenuInfo.setupcontrols );\n\tMenu_AddItem( &setupMenuInfo.menu, &setupMenuInfo.setupsystem );\n\tMenu_AddItem( &setupMenuInfo.menu, &setupMenuInfo.game );\n\tMenu_AddItem( &setupMenuInfo.menu, &setupMenuInfo.cdkey );\n//\tMenu_AddItem( &setupMenuInfo.menu, &setupMenuInfo.load );\n//\tMenu_AddItem( &setupMenuInfo.menu, &setupMenuInfo.save );\n\tif( !trap_Cvar_VariableValue( \"cl_paused\" ) ) {\n\t\tMenu_AddItem( &setupMenuInfo.menu, &setupMenuInfo.defaults );\n\t}\n\tMenu_AddItem( &setupMenuInfo.menu, &setupMenuInfo.back );\n}\n\n\n/*\n=================\nUI_SetupMenu_Cache\n=================\n*/\nvoid UI_SetupMenu_Cache( void ) {\n\ttrap_R_RegisterShaderNoMip( ART_BACK0 );\n\ttrap_R_RegisterShaderNoMip( ART_BACK1 );\n\ttrap_R_RegisterShaderNoMip( ART_FRAMEL );\n\ttrap_R_RegisterShaderNoMip( ART_FRAMER );\n}\n\n\n/*\n===============\nUI_SetupMenu\n===============\n*/\nvoid UI_SetupMenu( void ) {\n\tUI_SetupMenu_Init();\n\tUI_PushMenu( &setupMenuInfo.menu );\n}\n"
  },
  {
    "path": "src/q3_ui/ui_signup.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n//\n// ui_signup.c\n//\n\n#include \"ui_local.h\"\n\n\n#define SIGNUP_FRAME\t\t\"menu/art/cut_frame\"\n\n#define ID_NAME\t\t\t100\n#define ID_NAME_BOX\t\t101\n#define ID_PASSWORD\t\t102\n#define ID_PASSWORD_BOX\t103\n#define ID_AGAIN\t\t104\n#define ID_AGAIN_BOX\t105\n#define ID_EMAIL\t\t106\n#define ID_EMAIL_BOX\t107\n#define ID_SIGNUP\t\t108\n#define ID_CANCEL\t\t109\n\n\ntypedef struct\n{\n\tmenuframework_s\tmenu;\n\tmenubitmap_s\tframe;\n\tmenutext_s\t\tname;\n\tmenufield_s\t\tname_box;\n\tmenutext_s\t\tpassword;\n\tmenufield_s\t\tpassword_box;\n\tmenutext_s\t\tagain;\n\tmenufield_s\t\tagain_box;\n\tmenutext_s\t\temail;\n\tmenufield_s\t\temail_box;\n\tmenutext_s\t\tsignup;\n\tmenutext_s\t\tcancel;\n} signup_t;\n\nstatic signup_t\ts_signup;\n\nstatic menuframework_s\ts_signup_menu;\nstatic menuaction_s\t\ts_signup_signup;\nstatic menuaction_s\t\ts_signup_cancel;\n\nstatic vec4_t s_signup_color_prompt  = {1.00, 0.43, 0.00, 1.00};\n\n/*\n===============\nSignup_MenuEvent\n===============\n*/\nstatic void Signup_MenuEvent( void* ptr, int event ) {\n\t//char\tcmd[1024];\n\t\n\tif( event != QM_ACTIVATED ) {\n\t\treturn;\n\t}\n\n\tswitch( ((menucommon_s*)ptr)->id ) {\n\tcase ID_SIGNUP:\n\t\tif( strcmp(s_signup.password_box.field.buffer, \n\t\t\ts_signup.again_box.field.buffer) != 0 )\n\t\t{\n\t\t\t// GRANK_FIXME - password mismatch\n\t\t\tbreak;\n\t\t}\n\t\t// set name\n\t\t//trap_Cvar_Set( \"name\", s_signup.name_box.field.buffer );\n\t\t/*\n\t\ttrap_Cvar_Set( \"rank_name\", s_signup.name_box.field.buffer );\n\t\ttrap_Cvar_Set( \"rank_pwd\", s_signup.password_box.field.buffer );\n\t\t*/\n\n\t\t// create account\n\t\t/*\n\t\tsprintf( cmd, \"cmd rank_create \\\"%s\\\" \\\"%s\\\" \\\"%s\\\"\\n\", \n\t\t\ts_signup.name_box.field.buffer, \n\t\t\ts_signup.password_box.field.buffer, \n\t\t\ts_signup.email_box.field.buffer );\n\t\ttrap_Cmd_ExecuteText( EXEC_APPEND, cmd );\n\t\t*/\n\t\ttrap_CL_UI_RankUserCreate(\n\t\t\ts_signup.name_box.field.buffer, \n\t\t\ts_signup.password_box.field.buffer, \n\t\t\ts_signup.email_box.field.buffer );\n\n\t\tUI_ForceMenuOff();\n\t\tbreak;\n\t\t\n\tcase ID_CANCEL:\n\t\tUI_PopMenu();\n\t\tbreak;\n\t}\n}\n\n/*\n===============\nSignup_MenuInit\n===============\n*/\nvoid Signup_MenuInit( void ) {\n\tgrank_status_t\tstatus;\n\tint\t\t\t\ty;\n\n\tmemset( &s_signup, 0, sizeof(s_signup) );\n\n\tSignup_Cache();\n\n\ts_signup.menu.wrapAround = qtrue;\n\ts_signup.menu.fullscreen = qfalse;\n\n\ts_signup.frame.generic.type\t\t\t\t= MTYPE_BITMAP;\n\ts_signup.frame.generic.flags\t\t\t= QMF_INACTIVE;\n\ts_signup.frame.generic.name\t\t\t\t= SIGNUP_FRAME;\n\ts_signup.frame.generic.x\t\t\t\t= 142; //320-233;\n\ts_signup.frame.generic.y\t\t\t\t= 118; //240-166;\n\ts_signup.frame.width\t\t\t\t\t= 359; //466;\n\ts_signup.frame.height\t\t\t\t\t= 256; //332;\n\n\ty = 194;\n\n\ts_signup.name.generic.type\t\t\t\t= MTYPE_PTEXT;\n\ts_signup.name.generic.flags\t\t\t\t= QMF_RIGHT_JUSTIFY|QMF_INACTIVE;\n\ts_signup.name.generic.id\t\t\t\t= ID_NAME;\n\ts_signup.name.generic.x\t\t\t\t\t= 310;\n\ts_signup.name.generic.y\t\t\t\t\t= y;\n\ts_signup.name.string\t\t\t\t\t= \"NAME\";\n\ts_signup.name.style\t\t\t\t\t\t= UI_RIGHT|UI_SMALLFONT;\n\ts_signup.name.color\t\t\t\t\t\t= s_signup_color_prompt;\n\n\ts_signup.name_box.generic.type\t\t\t= MTYPE_FIELD;\n\ts_signup.name_box.generic.ownerdraw\t\t= Rankings_DrawName;\n\ts_signup.name_box.generic.name\t\t\t= \"\";\n\ts_signup.name_box.generic.flags\t\t\t= 0;\n\ts_signup.name_box.generic.x\t\t\t\t= 330;\n\ts_signup.name_box.generic.y\t\t\t\t= y;\n\ts_signup.name_box.field.widthInChars\t= 16;\n\ts_signup.name_box.field.maxchars\t\t= 16;\n\ty += 20;\n\t\n\ts_signup.password.generic.type\t\t\t= MTYPE_PTEXT;\n\ts_signup.password.generic.flags\t\t\t= QMF_RIGHT_JUSTIFY|QMF_INACTIVE;\n\ts_signup.password.generic.id\t\t\t= ID_PASSWORD;\n\ts_signup.password.generic.x\t\t\t\t= 310;\n\ts_signup.password.generic.y\t\t\t\t= y;\n\ts_signup.password.string\t\t\t\t= \"PASSWORD\";\n\ts_signup.password.style\t\t\t\t\t= UI_RIGHT|UI_SMALLFONT;\n\ts_signup.password.color\t\t\t\t\t= s_signup_color_prompt;\n\n\ts_signup.password_box.generic.type\t\t\t= MTYPE_FIELD;\n\ts_signup.password_box.generic.ownerdraw\t\t= Rankings_DrawPassword;\n\ts_signup.password_box.generic.name\t\t\t= \"\";\n\ts_signup.password_box.generic.flags\t\t\t= 0;\n\ts_signup.password_box.generic.x\t\t\t\t= 330;\n\ts_signup.password_box.generic.y\t\t\t\t= y;\n\ts_signup.password_box.field.widthInChars\t= 16;\n\ts_signup.password_box.field.maxchars\t\t= 16;\n\ty += 20;\n\n\ts_signup.again.generic.type\t\t\t\t= MTYPE_PTEXT;\n\ts_signup.again.generic.flags\t\t\t= QMF_RIGHT_JUSTIFY|QMF_INACTIVE;\n\ts_signup.again.generic.id\t\t\t\t= ID_AGAIN;\n\ts_signup.again.generic.x\t\t\t\t= 310;\n\ts_signup.again.generic.y\t\t\t\t= y;\n\ts_signup.again.string\t\t\t\t\t= \"(AGAIN)\";\n\ts_signup.again.style\t\t\t\t\t= UI_RIGHT|UI_SMALLFONT;\n\ts_signup.again.color\t\t\t\t\t= s_signup_color_prompt;\n\n\ts_signup.again_box.generic.type\t\t\t= MTYPE_FIELD;\n\ts_signup.again_box.generic.ownerdraw\t= Rankings_DrawPassword;\n\ts_signup.again_box.generic.name\t\t\t= \"\";\n\ts_signup.again_box.generic.flags\t\t= 0;\n\ts_signup.again_box.generic.x\t\t\t= 330;\n\ts_signup.again_box.generic.y\t\t\t= y;\n\ts_signup.again_box.field.widthInChars\t= 16;\n\ts_signup.again_box.field.maxchars\t\t= 16;\n\ty += 20;\n\n\ts_signup.email.generic.type\t\t\t\t= MTYPE_PTEXT;\n\ts_signup.email.generic.flags\t\t\t= QMF_RIGHT_JUSTIFY|QMF_INACTIVE;\n\ts_signup.email.generic.id\t\t\t\t= ID_EMAIL;\n\ts_signup.email.generic.x\t\t\t\t= 310;\n\ts_signup.email.generic.y\t\t\t\t= y;\n\ts_signup.email.string\t\t\t\t\t= \"EMAIL\";\n\ts_signup.email.style\t\t\t\t\t= UI_RIGHT|UI_SMALLFONT;\n\ts_signup.email.color\t\t\t\t\t= s_signup_color_prompt;\n\n\ts_signup.email_box.generic.type\t\t\t= MTYPE_FIELD;\n\ts_signup.email_box.generic.ownerdraw\t= Rankings_DrawText;\n\ts_signup.email_box.generic.name\t\t\t= \"\";\n\ts_signup.email_box.generic.flags\t\t= 0;\n\ts_signup.email_box.generic.x\t\t\t= 330;\n\ts_signup.email_box.generic.y\t\t\t= y;\n\ts_signup.email_box.field.widthInChars\t= 16;\n\ts_signup.email_box.field.maxchars\t\t= MAX_EDIT_LINE;\n\ty += 40;\n\n\ts_signup.signup.generic.type\t\t\t= MTYPE_PTEXT;\n\ts_signup.signup.generic.flags\t\t\t= QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_signup.signup.generic.id\t\t\t\t= ID_SIGNUP;\n\ts_signup.signup.generic.callback\t\t= Signup_MenuEvent;\n\ts_signup.signup.generic.x\t\t\t\t= 310;\n\ts_signup.signup.generic.y\t\t\t\t= y;\n\ts_signup.signup.string\t\t\t\t\t= \"SIGN UP\";\n\ts_signup.signup.style\t\t\t\t\t= UI_RIGHT|UI_SMALLFONT;\n\ts_signup.signup.color\t\t\t\t\t= colorRed;\n\n\ts_signup.cancel.generic.type\t\t\t= MTYPE_PTEXT;\n\ts_signup.cancel.generic.flags\t\t\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_signup.cancel.generic.id\t\t\t\t= ID_CANCEL;\n\ts_signup.cancel.generic.callback\t\t= Signup_MenuEvent;\n\ts_signup.cancel.generic.x\t\t\t\t= 330;\n\ts_signup.cancel.generic.y\t\t\t\t= y;\n\ts_signup.cancel.string\t\t\t\t\t= \"CANCEL\";\n\ts_signup.cancel.style\t\t\t\t\t= UI_LEFT|UI_SMALLFONT;\n\ts_signup.cancel.color\t\t\t\t\t= colorRed;\n\ty += 20;\n\n\tstatus = (grank_status_t)trap_Cvar_VariableValue(\"client_status\");\n\tif( (status != QGR_STATUS_NEW) && (status != QGR_STATUS_SPECTATOR) )\n\t{\n\t\ts_signup.name_box.generic.flags |= QMF_INACTIVE;\t\n\t\ts_signup.password_box.generic.flags |= QMF_INACTIVE;\t\n\t\ts_signup.again_box.generic.flags |= QMF_INACTIVE;\t\n\t\ts_signup.email_box.generic.flags |= QMF_INACTIVE;\t\n\t\ts_signup.signup.generic.flags |= QMF_INACTIVE;\n\t\t\n\t\ts_signup.signup.color = colorMdGrey;\n\t}\n\t\n\tMenu_AddItem( &s_signup.menu, (void*) &s_signup.frame );\n\tMenu_AddItem( &s_signup.menu, (void*) &s_signup.name );\n\tMenu_AddItem( &s_signup.menu, (void*) &s_signup.name_box );\n\tMenu_AddItem( &s_signup.menu, (void*) &s_signup.password );\n\tMenu_AddItem( &s_signup.menu, (void*) &s_signup.password_box );\n\tMenu_AddItem( &s_signup.menu, (void*) &s_signup.again );\n\tMenu_AddItem( &s_signup.menu, (void*) &s_signup.again_box );\n\tMenu_AddItem( &s_signup.menu, (void*) &s_signup.email );\n\tMenu_AddItem( &s_signup.menu, (void*) &s_signup.email_box );\n\tMenu_AddItem( &s_signup.menu, (void*) &s_signup.signup );\n\tMenu_AddItem( &s_signup.menu, (void*) &s_signup.cancel );\n}\n\n\n/*\n===============\nSignup_Cache\n===============\n*/\nvoid Signup_Cache( void ) {\n\ttrap_R_RegisterShaderNoMip( SIGNUP_FRAME );\n}\n\n\n/*\n===============\nUI_SignupMenu\n===============\n*/\nvoid UI_SignupMenu( void ) {\n\tSignup_MenuInit();\n\tUI_PushMenu ( &s_signup.menu );\n}\n\n\n"
  },
  {
    "path": "src/q3_ui/ui_sound.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n/*\n=======================================================================\n\nSOUND OPTIONS MENU\n\n=======================================================================\n*/\n\n#include \"ui_local.h\"\n\n\n#define ART_FRAMEL\t\t\t\"menu/art/frame2_l\"\n#define ART_FRAMER\t\t\t\"menu/art/frame1_r\"\n#define ART_BACK0\t\t\t\"menu/art/back_0\"\n#define ART_BACK1\t\t\t\"menu/art/back_1\"\n\n#define ID_GRAPHICS\t\t\t10\n#define ID_DISPLAY\t\t\t11\n#define ID_SOUND\t\t\t12\n#define ID_NETWORK\t\t\t13\n#define ID_EFFECTSVOLUME\t14\n#define ID_MUSICVOLUME\t\t15\n#define ID_QUALITY\t\t\t16\n//#define ID_A3D\t\t\t\t17\n#define ID_BACK\t\t\t\t18\n\n\nstatic const char *quality_items[] = {\n\t\"Low\", \"High\", 0\n};\n\ntypedef struct {\n\tmenuframework_s\t\tmenu;\n\n\tmenutext_s\t\t\tbanner;\n\tmenubitmap_s\t\tframel;\n\tmenubitmap_s\t\tframer;\n\n\tmenutext_s\t\t\tgraphics;\n\tmenutext_s\t\t\tdisplay;\n\tmenutext_s\t\t\tsound;\n\tmenutext_s\t\t\tnetwork;\n\n\tmenuslider_s\t\tsfxvolume;\n\tmenuslider_s\t\tmusicvolume;\n\tmenulist_s\t\t\tquality;\n//\tmenuradiobutton_s\ta3d;\n\n\tmenubitmap_s\t\tback;\n} soundOptionsInfo_t;\n\nstatic soundOptionsInfo_t\tsoundOptionsInfo;\n\n\n/*\n=================\nUI_SoundOptionsMenu_Event\n=================\n*/\nstatic void UI_SoundOptionsMenu_Event( void* ptr, int event ) {\n\tif( event != QM_ACTIVATED ) {\n\t\treturn;\n\t}\n\n\tswitch( ((menucommon_s*)ptr)->id ) {\n\tcase ID_GRAPHICS:\n\t\tUI_PopMenu();\n\t\tUI_GraphicsOptionsMenu();\n\t\tbreak;\n\n\tcase ID_DISPLAY:\n\t\tUI_PopMenu();\n\t\tUI_DisplayOptionsMenu();\n\t\tbreak;\n\n\tcase ID_SOUND:\n\t\tbreak;\n\n\tcase ID_NETWORK:\n\t\tUI_PopMenu();\n\t\tUI_NetworkOptionsMenu();\n\t\tbreak;\n\n\tcase ID_EFFECTSVOLUME:\n\t\ttrap_Cvar_SetValue( \"s_volume\", soundOptionsInfo.sfxvolume.curvalue / 10 );\n\t\tbreak;\n\n\tcase ID_MUSICVOLUME:\n\t\ttrap_Cvar_SetValue( \"s_musicvolume\", soundOptionsInfo.musicvolume.curvalue / 10 );\n\t\tbreak;\n\n\tcase ID_QUALITY:\n\t\tif( soundOptionsInfo.quality.curvalue ) {\n\t\t\ttrap_Cvar_SetValue( \"s_khz\", 22 );\n\t\t\ttrap_Cvar_SetValue( \"s_compression\", 0 );\n\t\t}\n\t\telse {\n\t\t\ttrap_Cvar_SetValue( \"s_khz\", 11 );\n\t\t\ttrap_Cvar_SetValue( \"s_compression\", 1 );\n\t\t}\n\t\tUI_ForceMenuOff();\n\t\ttrap_Cmd_ExecuteText( EXEC_APPEND, \"snd_restart\\n\" );\n\t\tbreak;\n/*\n\tcase ID_A3D:\n\t\tif( soundOptionsInfo.a3d.curvalue ) {\n\t\t\ttrap_Cmd_ExecuteText( EXEC_NOW, \"s_enable_a3d\\n\" );\n\t\t}\n\t\telse {\n\t\t\ttrap_Cmd_ExecuteText( EXEC_NOW, \"s_disable_a3d\\n\" );\n\t\t}\n\t\tsoundOptionsInfo.a3d.curvalue = (int)trap_Cvar_VariableValue( \"s_usingA3D\" );\n\t\tbreak;\n*/\n\tcase ID_BACK:\n\t\tUI_PopMenu();\n\t\tbreak;\n\t}\n}\n\n\n/*\n===============\nUI_SoundOptionsMenu_Init\n===============\n*/\nstatic void UI_SoundOptionsMenu_Init( void ) {\n\tint\t\t\t\ty;\n\n\tmemset( &soundOptionsInfo, 0, sizeof(soundOptionsInfo) );\n\n\tUI_SoundOptionsMenu_Cache();\n\tsoundOptionsInfo.menu.wrapAround = qtrue;\n\tsoundOptionsInfo.menu.fullscreen = qtrue;\n\n\tsoundOptionsInfo.banner.generic.type\t\t= MTYPE_BTEXT;\n\tsoundOptionsInfo.banner.generic.flags\t\t= QMF_CENTER_JUSTIFY;\n\tsoundOptionsInfo.banner.generic.x\t\t\t= 320;\n\tsoundOptionsInfo.banner.generic.y\t\t\t= 16;\n\tsoundOptionsInfo.banner.string\t\t\t\t= \"SYSTEM SETUP\";\n\tsoundOptionsInfo.banner.color\t\t\t\t= color_white;\n\tsoundOptionsInfo.banner.style\t\t\t\t= UI_CENTER;\n\n\tsoundOptionsInfo.framel.generic.type\t\t= MTYPE_BITMAP;\n\tsoundOptionsInfo.framel.generic.name\t\t= ART_FRAMEL;\n\tsoundOptionsInfo.framel.generic.flags\t\t= QMF_INACTIVE;\n\tsoundOptionsInfo.framel.generic.x\t\t\t= 0;  \n\tsoundOptionsInfo.framel.generic.y\t\t\t= 78;\n\tsoundOptionsInfo.framel.width\t\t\t\t= 256;\n\tsoundOptionsInfo.framel.height\t\t\t\t= 329;\n\n\tsoundOptionsInfo.framer.generic.type\t\t= MTYPE_BITMAP;\n\tsoundOptionsInfo.framer.generic.name\t\t= ART_FRAMER;\n\tsoundOptionsInfo.framer.generic.flags\t\t= QMF_INACTIVE;\n\tsoundOptionsInfo.framer.generic.x\t\t\t= 376;\n\tsoundOptionsInfo.framer.generic.y\t\t\t= 76;\n\tsoundOptionsInfo.framer.width\t\t\t\t= 256;\n\tsoundOptionsInfo.framer.height\t\t\t\t= 334;\n\n\tsoundOptionsInfo.graphics.generic.type\t\t= MTYPE_PTEXT;\n\tsoundOptionsInfo.graphics.generic.flags\t\t= QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;\n\tsoundOptionsInfo.graphics.generic.id\t\t= ID_GRAPHICS;\n\tsoundOptionsInfo.graphics.generic.callback\t= UI_SoundOptionsMenu_Event;\n\tsoundOptionsInfo.graphics.generic.x\t\t\t= 216;\n\tsoundOptionsInfo.graphics.generic.y\t\t\t= 240 - 2 * PROP_HEIGHT;\n\tsoundOptionsInfo.graphics.string\t\t\t= \"GRAPHICS\";\n\tsoundOptionsInfo.graphics.style\t\t\t\t= UI_RIGHT;\n\tsoundOptionsInfo.graphics.color\t\t\t\t= color_red;\n\n\tsoundOptionsInfo.display.generic.type\t\t= MTYPE_PTEXT;\n\tsoundOptionsInfo.display.generic.flags\t\t= QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;\n\tsoundOptionsInfo.display.generic.id\t\t\t= ID_DISPLAY;\n\tsoundOptionsInfo.display.generic.callback\t= UI_SoundOptionsMenu_Event;\n\tsoundOptionsInfo.display.generic.x\t\t\t= 216;\n\tsoundOptionsInfo.display.generic.y\t\t\t= 240 - PROP_HEIGHT;\n\tsoundOptionsInfo.display.string\t\t\t\t= \"DISPLAY\";\n\tsoundOptionsInfo.display.style\t\t\t\t= UI_RIGHT;\n\tsoundOptionsInfo.display.color\t\t\t\t= color_red;\n\n\tsoundOptionsInfo.sound.generic.type\t\t\t= MTYPE_PTEXT;\n\tsoundOptionsInfo.sound.generic.flags\t\t= QMF_RIGHT_JUSTIFY;\n\tsoundOptionsInfo.sound.generic.id\t\t\t= ID_SOUND;\n\tsoundOptionsInfo.sound.generic.callback\t\t= UI_SoundOptionsMenu_Event;\n\tsoundOptionsInfo.sound.generic.x\t\t\t= 216;\n\tsoundOptionsInfo.sound.generic.y\t\t\t= 240;\n\tsoundOptionsInfo.sound.string\t\t\t\t= \"SOUND\";\n\tsoundOptionsInfo.sound.style\t\t\t\t= UI_RIGHT;\n\tsoundOptionsInfo.sound.color\t\t\t\t= color_red;\n\n\tsoundOptionsInfo.network.generic.type\t\t= MTYPE_PTEXT;\n\tsoundOptionsInfo.network.generic.flags\t\t= QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;\n\tsoundOptionsInfo.network.generic.id\t\t\t= ID_NETWORK;\n\tsoundOptionsInfo.network.generic.callback\t= UI_SoundOptionsMenu_Event;\n\tsoundOptionsInfo.network.generic.x\t\t\t= 216;\n\tsoundOptionsInfo.network.generic.y\t\t\t= 240 + PROP_HEIGHT;\n\tsoundOptionsInfo.network.string\t\t\t\t= \"NETWORK\";\n\tsoundOptionsInfo.network.style\t\t\t\t= UI_RIGHT;\n\tsoundOptionsInfo.network.color\t\t\t\t= color_red;\n\n\ty = 240 - 1.5 * (BIGCHAR_HEIGHT + 2);\n\tsoundOptionsInfo.sfxvolume.generic.type\t\t= MTYPE_SLIDER;\n\tsoundOptionsInfo.sfxvolume.generic.name\t\t= \"Effects Volume:\";\n\tsoundOptionsInfo.sfxvolume.generic.flags\t= QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\tsoundOptionsInfo.sfxvolume.generic.callback\t= UI_SoundOptionsMenu_Event;\n\tsoundOptionsInfo.sfxvolume.generic.id\t\t= ID_EFFECTSVOLUME;\n\tsoundOptionsInfo.sfxvolume.generic.x\t\t= 400;\n\tsoundOptionsInfo.sfxvolume.generic.y\t\t= y;\n\tsoundOptionsInfo.sfxvolume.minvalue\t\t\t= 0;\n\tsoundOptionsInfo.sfxvolume.maxvalue\t\t\t= 10;\n\n\ty += BIGCHAR_HEIGHT+2;\n\tsoundOptionsInfo.musicvolume.generic.type\t\t= MTYPE_SLIDER;\n\tsoundOptionsInfo.musicvolume.generic.name\t\t= \"Music Volume:\";\n\tsoundOptionsInfo.musicvolume.generic.flags\t\t= QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\tsoundOptionsInfo.musicvolume.generic.callback\t= UI_SoundOptionsMenu_Event;\n\tsoundOptionsInfo.musicvolume.generic.id\t\t\t= ID_MUSICVOLUME;\n\tsoundOptionsInfo.musicvolume.generic.x\t\t\t= 400;\n\tsoundOptionsInfo.musicvolume.generic.y\t\t\t= y;\n\tsoundOptionsInfo.musicvolume.minvalue\t\t\t= 0;\n\tsoundOptionsInfo.musicvolume.maxvalue\t\t\t= 10;\n\n\ty += BIGCHAR_HEIGHT+2;\n\tsoundOptionsInfo.quality.generic.type\t\t= MTYPE_SPINCONTROL;\n\tsoundOptionsInfo.quality.generic.name\t\t= \"Sound Quality:\";\n\tsoundOptionsInfo.quality.generic.flags\t\t= QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\tsoundOptionsInfo.quality.generic.callback\t= UI_SoundOptionsMenu_Event;\n\tsoundOptionsInfo.quality.generic.id\t\t\t= ID_QUALITY;\n\tsoundOptionsInfo.quality.generic.x\t\t\t= 400;\n\tsoundOptionsInfo.quality.generic.y\t\t\t= y;\n\tsoundOptionsInfo.quality.itemnames\t\t\t= quality_items;\n/*\n\ty += BIGCHAR_HEIGHT+2;\n\tsoundOptionsInfo.a3d.generic.type\t\t\t= MTYPE_RADIOBUTTON;\n\tsoundOptionsInfo.a3d.generic.name\t\t\t= \"A3D:\";\n\tsoundOptionsInfo.a3d.generic.flags\t\t\t= QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\tsoundOptionsInfo.a3d.generic.callback\t\t= UI_SoundOptionsMenu_Event;\n\tsoundOptionsInfo.a3d.generic.id\t\t\t\t= ID_A3D;\n\tsoundOptionsInfo.a3d.generic.x\t\t\t\t= 400;\n\tsoundOptionsInfo.a3d.generic.y\t\t\t\t= y;\n*/\n\tsoundOptionsInfo.back.generic.type\t\t\t= MTYPE_BITMAP;\n\tsoundOptionsInfo.back.generic.name\t\t\t= ART_BACK0;\n\tsoundOptionsInfo.back.generic.flags\t\t\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\tsoundOptionsInfo.back.generic.callback\t\t= UI_SoundOptionsMenu_Event;\n\tsoundOptionsInfo.back.generic.id\t\t\t= ID_BACK;\n\tsoundOptionsInfo.back.generic.x\t\t\t\t= 0;\n\tsoundOptionsInfo.back.generic.y\t\t\t\t= 480-64;\n\tsoundOptionsInfo.back.width\t\t\t\t\t= 128;\n\tsoundOptionsInfo.back.height\t\t\t\t= 64;\n\tsoundOptionsInfo.back.focuspic\t\t\t\t= ART_BACK1;\n\n\tMenu_AddItem( &soundOptionsInfo.menu, ( void * ) &soundOptionsInfo.banner );\n\tMenu_AddItem( &soundOptionsInfo.menu, ( void * ) &soundOptionsInfo.framel );\n\tMenu_AddItem( &soundOptionsInfo.menu, ( void * ) &soundOptionsInfo.framer );\n\tMenu_AddItem( &soundOptionsInfo.menu, ( void * ) &soundOptionsInfo.graphics );\n\tMenu_AddItem( &soundOptionsInfo.menu, ( void * ) &soundOptionsInfo.display );\n\tMenu_AddItem( &soundOptionsInfo.menu, ( void * ) &soundOptionsInfo.sound );\n\tMenu_AddItem( &soundOptionsInfo.menu, ( void * ) &soundOptionsInfo.network );\n\tMenu_AddItem( &soundOptionsInfo.menu, ( void * ) &soundOptionsInfo.sfxvolume );\n\tMenu_AddItem( &soundOptionsInfo.menu, ( void * ) &soundOptionsInfo.musicvolume );\n\tMenu_AddItem( &soundOptionsInfo.menu, ( void * ) &soundOptionsInfo.quality );\n//\tMenu_AddItem( &soundOptionsInfo.menu, ( void * ) &soundOptionsInfo.a3d );\n\tMenu_AddItem( &soundOptionsInfo.menu, ( void * ) &soundOptionsInfo.back );\n\n\tsoundOptionsInfo.sfxvolume.curvalue = trap_Cvar_VariableValue( \"s_volume\" ) * 10;\n\tsoundOptionsInfo.musicvolume.curvalue = trap_Cvar_VariableValue( \"s_musicvolume\" ) * 10;\n\tsoundOptionsInfo.quality.curvalue = !trap_Cvar_VariableValue( \"s_compression\" );\n//\tsoundOptionsInfo.a3d.curvalue = (int)trap_Cvar_VariableValue( \"s_usingA3D\" );\n}\n\n\n/*\n===============\nUI_SoundOptionsMenu_Cache\n===============\n*/\nvoid UI_SoundOptionsMenu_Cache( void ) {\n\ttrap_R_RegisterShaderNoMip( ART_FRAMEL );\n\ttrap_R_RegisterShaderNoMip( ART_FRAMER );\n\ttrap_R_RegisterShaderNoMip( ART_BACK0 );\n\ttrap_R_RegisterShaderNoMip( ART_BACK1 );\n}\n\n\n/*\n===============\nUI_SoundOptionsMenu\n===============\n*/\nvoid UI_SoundOptionsMenu( void ) {\n\tUI_SoundOptionsMenu_Init();\n\tUI_PushMenu( &soundOptionsInfo.menu );\n\tMenu_SetCursorToItem( &soundOptionsInfo.menu, &soundOptionsInfo.sound );\n}\n"
  },
  {
    "path": "src/q3_ui/ui_sparena.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n#include \"ui_local.h\"\n\nvoid UI_SPArena_Start( const char *arenaInfo ) {\n\tchar\t*map;\n\tint\t\tlevel;\n\tint\t\tn;\n\tchar\t*txt;\n\n\tn = (int)trap_Cvar_VariableValue( \"sv_maxclients\" );\n\tif ( n < 8 ) {\n\t\ttrap_Cvar_SetValue( \"sv_maxclients\", 8 );\n\t}\n\n\tlevel = atoi( Info_ValueForKey( arenaInfo, \"num\" ) );\n\ttxt = Info_ValueForKey( arenaInfo, \"special\" );\n\tif( txt[0] ) {\n\t\tif( Q_stricmp( txt, \"training\" ) == 0 ) {\n\t\t\tlevel = -4;\n\t\t}\n\t\telse if( Q_stricmp( txt, \"final\" ) == 0 ) {\n\t\t\tlevel = UI_GetNumSPTiers() * ARENAS_PER_TIER;\n\t\t}\n\t}\n\ttrap_Cvar_SetValue( \"ui_spSelection\", level );\n\n\tmap = Info_ValueForKey( arenaInfo, \"map\" );\n\ttrap_Cmd_ExecuteText( EXEC_APPEND, va( \"spmap %s\\n\", map ) );\n}\n"
  },
  {
    "path": "src/q3_ui/ui_specifyleague.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n#include \"ui_local.h\"\n\n/*********************************************************************************\n\tSPECIFY SERVER\n*********************************************************************************/\n\n#define MAX_LISTBOXITEMS\t\t128\n#define MAX_LISTBOXWIDTH\t\t40\n#define MAX_LEAGUENAME\t\t\t80\n\n#define SPECIFYLEAGUE_FRAMEL\t\"menu/art/frame2_l\"\n#define SPECIFYLEAGUE_FRAMER\t\"menu/art/frame1_r\"\n#define SPECIFYLEAGUE_BACK0\t\t\"menu/art/back_0\"\n#define SPECIFYLEAGUE_BACK1\t\t\"menu/art/back_1\"\n#define SPECIFYLEAGUE_ARROWS0\t\"menu/art/arrows_vert_0\"\n#define SPECIFYLEAGUE_UP\t\t\"menu/art/arrows_vert_top\"\n#define SPECIFYLEAGUE_DOWN\t\t\"menu/art/arrows_vert_bot\"\n#define GLOBALRANKINGS_LOGO\t\t\"menu/art/gr/grlogo\"\n#define GLOBALRANKINGS_LETTERS\t\"menu/art/gr/grletters\"\n\n#define ID_SPECIFYLEAGUENAME\t100\n#define ID_SPECIFYLEAGUELIST\t101\n#define ID_SPECIFYLEAGUEUP\t\t102\n#define ID_SPECIFYLEAGUEDOWN\t103\n#define ID_SPECIFYLEAGUEBACK\t104\n\nstatic char* specifyleague_artlist[] =\n{\n\tSPECIFYLEAGUE_FRAMEL,\n\tSPECIFYLEAGUE_FRAMER,\n\tSPECIFYLEAGUE_ARROWS0,\t\n\tSPECIFYLEAGUE_UP,\t\n\tSPECIFYLEAGUE_DOWN,\t\n\tSPECIFYLEAGUE_BACK0,\t\n\tSPECIFYLEAGUE_BACK1,\n\tGLOBALRANKINGS_LOGO,\n\tGLOBALRANKINGS_LETTERS,\n\tNULL\n};\n\nstatic char playername[80];\n\ntypedef struct\n{\n\tmenuframework_s\tmenu;\n\tmenutext_s\t\tbanner;\n\tmenubitmap_s\tframel;\n\tmenubitmap_s\tframer;\n\tmenufield_s\t\trankname;\n\tmenulist_s\t\tlist;\n\tmenubitmap_s\tarrows;\n\tmenubitmap_s\tup;\n\tmenubitmap_s\tdown;\n\tmenubitmap_s\tback;\n\tmenubitmap_s\tgrlogo;\n\tmenubitmap_s\tgrletters;\n} specifyleague_t;\n\nstatic specifyleague_t\ts_specifyleague;\n\n\ntypedef struct {\n\tchar\t\t\tbuff[MAX_LISTBOXWIDTH];\n\tchar\t\t\tleaguename[MAX_LEAGUENAME];\n} table_t;\n\ntable_t league_table[MAX_LISTBOXITEMS];\nchar *leaguename_items[MAX_LISTBOXITEMS];\n\n\nstatic void SpecifyLeague_GetList()\n{\n\tint count = 0;\n\tint i;\n\t/* The Player Name has changed. We need to perform another search */\n\tQ_strncpyz( playername,\n\t\ts_specifyleague.rankname.field.buffer, \n\t\tsizeof(playername) );\n\n\tcount = trap_CL_UI_RankGetLeauges( playername );\n\n\tfor(i = 0; i < count; i++)\n\t{\n\t\tchar\ts[MAX_LEAGUENAME];\n\t\tconst char\t*var;\n\t\tvar = va( \"leaguename%i\", i+1 );\n\t\ttrap_Cvar_VariableStringBuffer( var, s, sizeof(s) );\n\t\tQ_strncpyz(league_table[i].leaguename, s, sizeof(league_table[i].leaguename) );\n\t\tQ_strncpyz(league_table[i].buff, league_table[i].leaguename, sizeof(league_table[i].buff) );\n\t}\n\n\ts_specifyleague.list.numitems = count;\n}\n\n/*\n=================\nSpecifyLeague_Event\n=================\n*/\nstatic void SpecifyLeague_Event( void* ptr, int event )\n{\n\tint\t\tid;\n\tid = ((menucommon_s*)ptr)->id;\n\t//if( event != QM_ACTIVATED && id != ID_SPECIFYLEAGUELIST ) {\n\t//\treturn;\n\t//}\n\n\tswitch (id)\n\t{\n\t\tcase ID_SPECIFYLEAGUELIST:\n\t\t\tif( event == QM_GOTFOCUS ) {\n\t\t\t\t//ArenaServers_UpdatePicture();\n\t\t\t}\n\t\tbreak;\n\n\t\tcase ID_SPECIFYLEAGUEUP:\n\t\t\tif( event == QM_ACTIVATED )\n\t\t\t\tScrollList_Key( &s_specifyleague.list, K_UPARROW );\n\t\tbreak;\t\t\n\t\n\t\tcase ID_SPECIFYLEAGUEDOWN:\n\t\t\tif( event == QM_ACTIVATED )\n\t\t\t\tScrollList_Key( &s_specifyleague.list, K_DOWNARROW );\n\t\tbreak;\n\t\t\t\n\t\tcase ID_SPECIFYLEAGUENAME:\n\t\t\tif( (event == QM_LOSTFOCUS) && \n\t\t\t\t(Q_strncmp(playername, \n\t\t\t\t\ts_specifyleague.rankname.field.buffer, \n\t\t\t\t\tstrlen(s_specifyleague.rankname.field.buffer)) != 0))\n\t\t\t{\n\t\t\t\tSpecifyLeague_GetList();\n\t\t\t}\n\t\tbreak;\n\n\t\tcase ID_SPECIFYLEAGUEBACK:\n\t\t\tif( event == QM_ACTIVATED )\n\t\t\t{\n\t\t\t\ttrap_Cvar_Set( \"sv_leagueName\", league_table[s_specifyleague.list.curvalue].leaguename);\n\t\t\t\tUI_PopMenu();\n\t\t\t}\n\t\tbreak;\n\t}\n}\n\n/*\n=================\nSpecifyLeague_MenuInit\n=================\n*/\nvoid SpecifyLeague_MenuInit( void )\n{\n\tint i;\n\t// zero set all our globals\n\tmemset( &s_specifyleague, 0 ,sizeof(specifyleague_t) );\n\n\tSpecifyLeague_Cache();\n\n\ts_specifyleague.menu.wrapAround = qtrue;\n\ts_specifyleague.menu.fullscreen = qtrue;\n\n\ts_specifyleague.banner.generic.type\t = MTYPE_BTEXT;\n\ts_specifyleague.banner.generic.x     = 320;\n\ts_specifyleague.banner.generic.y     = 16;\n\ts_specifyleague.banner.string\t\t = \"CHOOSE LEAGUE\";\n\ts_specifyleague.banner.color  \t\t = color_white;\n\ts_specifyleague.banner.style  \t\t = UI_CENTER;\n\n\ts_specifyleague.framel.generic.type  = MTYPE_BITMAP;\n\ts_specifyleague.framel.generic.name  = SPECIFYLEAGUE_FRAMEL;\n\ts_specifyleague.framel.generic.flags = QMF_INACTIVE;\n\ts_specifyleague.framel.generic.x\t = 0;  \n\ts_specifyleague.framel.generic.y\t = 78;\n\ts_specifyleague.framel.width  \t     = 256;\n\ts_specifyleague.framel.height  \t     = 334;\n\n\ts_specifyleague.framer.generic.type  = MTYPE_BITMAP;\n\ts_specifyleague.framer.generic.name  = SPECIFYLEAGUE_FRAMER;\n\ts_specifyleague.framer.generic.flags = QMF_INACTIVE;\n\ts_specifyleague.framer.generic.x\t = 376;\n\ts_specifyleague.framer.generic.y\t = 76;\n\ts_specifyleague.framer.width  \t     = 256;\n\ts_specifyleague.framer.height  \t     = 334;\n\n\ts_specifyleague.grlogo.generic.type  = MTYPE_BITMAP;\n\ts_specifyleague.grlogo.generic.name  = GLOBALRANKINGS_LOGO;\n\ts_specifyleague.grlogo.generic.flags = QMF_INACTIVE;\n\ts_specifyleague.grlogo.generic.x\t = 0;\n\ts_specifyleague.grlogo.generic.y\t = 0;\n\ts_specifyleague.grlogo.width\t\t = 64;\n\ts_specifyleague.grlogo.height\t\t = 128;\n\n\ts_specifyleague.rankname.generic.type       = MTYPE_FIELD;\n\ts_specifyleague.rankname.generic.name       = \"Player Name:\";\n\ts_specifyleague.rankname.generic.flags      = QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\ts_specifyleague.rankname.generic.callback   = SpecifyLeague_Event;\n\ts_specifyleague.rankname.generic.id\t        = ID_SPECIFYLEAGUENAME;\n\ts_specifyleague.rankname.generic.x\t        = 226;\n\ts_specifyleague.rankname.generic.y\t        = 128;\n\ts_specifyleague.rankname.field.widthInChars = 32;\n\ts_specifyleague.rankname.field.maxchars     = 80;\n\n\ts_specifyleague.list.generic.type\t\t\t= MTYPE_SCROLLLIST;\n\ts_specifyleague.list.generic.flags\t\t\t= QMF_HIGHLIGHT_IF_FOCUS;\n\ts_specifyleague.list.generic.id\t\t\t\t= ID_SPECIFYLEAGUELIST;\n\ts_specifyleague.list.generic.callback\t\t= SpecifyLeague_Event;\n\ts_specifyleague.list.generic.x\t\t\t\t= 160;\n\ts_specifyleague.list.generic.y\t\t\t\t= 200;\n\ts_specifyleague.list.width\t\t\t\t\t= MAX_LISTBOXWIDTH;\n\ts_specifyleague.list.height\t\t\t\t\t= 8;\n\ts_specifyleague.list.itemnames\t\t\t\t= (const char **)leaguename_items;\n\ts_specifyleague.list.numitems               = 0;\n\tfor( i = 0; i < MAX_LISTBOXITEMS; i++ ) {\n\t\tleague_table[i].buff[0] = 0;\n\t\tleague_table[i].leaguename[0] = 0;\n\t\tleaguename_items[i] = league_table[i].buff;\n\t}\n\t\n\ts_specifyleague.arrows.generic.type\t\t\t= MTYPE_BITMAP;\n\ts_specifyleague.arrows.generic.name\t\t\t= SPECIFYLEAGUE_ARROWS0;\n\ts_specifyleague.arrows.generic.flags\t\t= QMF_LEFT_JUSTIFY|QMF_INACTIVE;\n\ts_specifyleague.arrows.generic.callback\t\t= SpecifyLeague_Event;\n\ts_specifyleague.arrows.generic.x\t\t\t= 512;\n\ts_specifyleague.arrows.generic.y\t\t\t= 240-64+16;\n\ts_specifyleague.arrows.width\t\t\t\t= 64;\n\ts_specifyleague.arrows.height\t\t\t\t= 128;\n\n\ts_specifyleague.up.generic.type\t\t\t\t= MTYPE_BITMAP;\n\ts_specifyleague.up.generic.flags\t\t\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_MOUSEONLY;\n\ts_specifyleague.up.generic.callback\t\t\t= SpecifyLeague_Event;\n\ts_specifyleague.up.generic.id\t\t\t\t= ID_SPECIFYLEAGUEUP;\n\ts_specifyleague.up.generic.x\t\t\t\t= 512;\n\ts_specifyleague.up.generic.y\t\t\t\t= 240-64+16;\n\ts_specifyleague.up.width\t\t\t\t\t= 64;\n\ts_specifyleague.up.height\t\t\t\t\t= 64;\n\ts_specifyleague.up.focuspic\t\t\t\t\t= SPECIFYLEAGUE_UP;\n\n\ts_specifyleague.down.generic.type\t\t\t= MTYPE_BITMAP;\n\ts_specifyleague.down.generic.flags\t\t\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_MOUSEONLY;\n\ts_specifyleague.down.generic.callback\t\t= SpecifyLeague_Event;\n\ts_specifyleague.down.generic.id\t\t\t\t= ID_SPECIFYLEAGUEDOWN;\n\ts_specifyleague.down.generic.x\t\t\t\t= 512;\n\ts_specifyleague.down.generic.y\t\t\t\t= 240+16;\n\ts_specifyleague.down.width\t\t\t\t\t= 64;\n\ts_specifyleague.down.height\t\t\t\t\t= 64;\n\ts_specifyleague.down.focuspic\t\t\t\t= SPECIFYLEAGUE_DOWN;\n\n\ts_specifyleague.back.generic.type\t  = MTYPE_BITMAP;\n\ts_specifyleague.back.generic.name     = SPECIFYLEAGUE_BACK0;\n\ts_specifyleague.back.generic.flags    = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_specifyleague.back.generic.callback = SpecifyLeague_Event;\n\ts_specifyleague.back.generic.id\t      = ID_SPECIFYLEAGUEBACK;\n\ts_specifyleague.back.generic.x\t\t  = 0;\n\ts_specifyleague.back.generic.y\t\t  = 480-64;\n\ts_specifyleague.back.width  \t\t  = 128;\n\ts_specifyleague.back.height  \t\t  = 64;\n\ts_specifyleague.back.focuspic         = SPECIFYLEAGUE_BACK1;\n\n\tMenu_AddItem( &s_specifyleague.menu, &s_specifyleague.banner );\n\tMenu_AddItem( &s_specifyleague.menu, &s_specifyleague.framel );\n\tMenu_AddItem( &s_specifyleague.menu, &s_specifyleague.framer );\n\tMenu_AddItem( &s_specifyleague.menu, &s_specifyleague.grlogo );\n\tMenu_AddItem( &s_specifyleague.menu, &s_specifyleague.rankname );\n\tMenu_AddItem( &s_specifyleague.menu, &s_specifyleague.list );\n\tMenu_AddItem( &s_specifyleague.menu, &s_specifyleague.arrows );\n\tMenu_AddItem( &s_specifyleague.menu, &s_specifyleague.up );\n\tMenu_AddItem( &s_specifyleague.menu, &s_specifyleague.down );\n\tMenu_AddItem( &s_specifyleague.menu, &s_specifyleague.back );\n\n\n\t// initialize any menu variables\n\tQ_strncpyz( s_specifyleague.rankname.field.buffer, \n\t\tUI_Cvar_VariableString(\"name\"), \n\t\tsizeof(s_specifyleague.rankname.field.buffer) );\n\n\tQ_strncpyz( playername,\n\t\tUI_Cvar_VariableString(\"name\"), \n\t\tsizeof(playername) );\n\n\tSpecifyLeague_GetList();\n}\n\n/*\n=================\nSpecifyLeague_Cache\n=================\n*/\nvoid SpecifyLeague_Cache( void )\n{\n\tint\ti;\n\n\t// touch all our pics\n\tfor (i=0; ;i++)\n\t{\n\t\tif (!specifyleague_artlist[i])\n\t\t\tbreak;\n\t\ttrap_R_RegisterShaderNoMip(specifyleague_artlist[i]);\n\t}\n}\n\n/*\n=================\nUI_SpecifyLeagueMenu\n=================\n*/\nvoid UI_SpecifyLeagueMenu( void )\n{\n\tSpecifyLeague_MenuInit();\n\tUI_PushMenu( &s_specifyleague.menu );\n}\n\n"
  },
  {
    "path": "src/q3_ui/ui_specifyserver.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n#include \"ui_local.h\"\n\n/*********************************************************************************\n\tSPECIFY SERVER\n*********************************************************************************/\n\n#define SPECIFYSERVER_FRAMEL\t\"menu/art/frame2_l\"\n#define SPECIFYSERVER_FRAMER\t\"menu/art/frame1_r\"\n#define SPECIFYSERVER_BACK0\t\t\"menu/art/back_0\"\n#define SPECIFYSERVER_BACK1\t\t\"menu/art/back_1\"\n#define SPECIFYSERVER_FIGHT0\t\"menu/art/fight_0\"\n#define SPECIFYSERVER_FIGHT1\t\"menu/art/fight_1\"\n\n#define ID_SPECIFYSERVERBACK\t102\n#define ID_SPECIFYSERVERGO\t\t103\n\nstatic char* specifyserver_artlist[] =\n{\n\tSPECIFYSERVER_FRAMEL,\n\tSPECIFYSERVER_FRAMER,\n\tSPECIFYSERVER_BACK0,\t\n\tSPECIFYSERVER_BACK1,\t\n\tSPECIFYSERVER_FIGHT0,\n\tSPECIFYSERVER_FIGHT1,\n\tNULL\n};\n\ntypedef struct\n{\n\tmenuframework_s\tmenu;\n\tmenutext_s\t\tbanner;\n\tmenubitmap_s\tframel;\n\tmenubitmap_s\tframer;\n\tmenufield_s\t\tdomain;\n\tmenufield_s\t\tport;\n\tmenubitmap_s\tgo;\n\tmenubitmap_s\tback;\n} specifyserver_t;\n\nstatic specifyserver_t\ts_specifyserver;\n\n/*\n=================\nSpecifyServer_Event\n=================\n*/\nstatic void SpecifyServer_Event( void* ptr, int event )\n{\n\tchar\tbuff[256];\n\n\tswitch (((menucommon_s*)ptr)->id)\n\t{\n\t\tcase ID_SPECIFYSERVERGO:\n\t\t\tif (event != QM_ACTIVATED)\n\t\t\t\tbreak;\n\n\t\t\tif (s_specifyserver.domain.field.buffer[0])\n\t\t\t{\n\t\t\t\tstrcpy(buff,s_specifyserver.domain.field.buffer);\n\t\t\t\tif (s_specifyserver.port.field.buffer[0])\n\t\t\t\t\tCom_sprintf( buff+strlen(buff), 128, \":%s\", s_specifyserver.port.field.buffer );\n\n\t\t\t\ttrap_Cmd_ExecuteText( EXEC_APPEND, va( \"connect %s\\n\", buff ) );\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase ID_SPECIFYSERVERBACK:\n\t\t\tif (event != QM_ACTIVATED)\n\t\t\t\tbreak;\n\n\t\t\tUI_PopMenu();\n\t\t\tbreak;\n\t}\n}\n\n/*\n=================\nSpecifyServer_MenuInit\n=================\n*/\nvoid SpecifyServer_MenuInit( void )\n{\n\t// zero set all our globals\n\tmemset( &s_specifyserver, 0 ,sizeof(specifyserver_t) );\n\n\tSpecifyServer_Cache();\n\n\ts_specifyserver.menu.wrapAround = qtrue;\n\ts_specifyserver.menu.fullscreen = qtrue;\n\n\ts_specifyserver.banner.generic.type\t = MTYPE_BTEXT;\n\ts_specifyserver.banner.generic.x     = 320;\n\ts_specifyserver.banner.generic.y     = 16;\n\ts_specifyserver.banner.string\t\t = \"SPECIFY SERVER\";\n\ts_specifyserver.banner.color  \t\t = color_white;\n\ts_specifyserver.banner.style  \t\t = UI_CENTER;\n\n\ts_specifyserver.framel.generic.type  = MTYPE_BITMAP;\n\ts_specifyserver.framel.generic.name  = SPECIFYSERVER_FRAMEL;\n\ts_specifyserver.framel.generic.flags = QMF_INACTIVE;\n\ts_specifyserver.framel.generic.x\t = 0;  \n\ts_specifyserver.framel.generic.y\t = 78;\n\ts_specifyserver.framel.width  \t     = 256;\n\ts_specifyserver.framel.height  \t     = 329;\n\n\ts_specifyserver.framer.generic.type  = MTYPE_BITMAP;\n\ts_specifyserver.framer.generic.name  = SPECIFYSERVER_FRAMER;\n\ts_specifyserver.framer.generic.flags = QMF_INACTIVE;\n\ts_specifyserver.framer.generic.x\t = 376;\n\ts_specifyserver.framer.generic.y\t = 76;\n\ts_specifyserver.framer.width  \t     = 256;\n\ts_specifyserver.framer.height  \t     = 334;\n\n\ts_specifyserver.domain.generic.type       = MTYPE_FIELD;\n\ts_specifyserver.domain.generic.name       = \"Address:\";\n\ts_specifyserver.domain.generic.flags      = QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\ts_specifyserver.domain.generic.x\t      = 206;\n\ts_specifyserver.domain.generic.y\t      = 220;\n\ts_specifyserver.domain.field.widthInChars = 38;\n\ts_specifyserver.domain.field.maxchars     = 80;\n\n\ts_specifyserver.port.generic.type       = MTYPE_FIELD;\n\ts_specifyserver.port.generic.name\t    = \"Port:\";\n\ts_specifyserver.port.generic.flags\t    = QMF_PULSEIFFOCUS|QMF_SMALLFONT|QMF_NUMBERSONLY;\n\ts_specifyserver.port.generic.x\t        = 206;\n\ts_specifyserver.port.generic.y\t        = 250;\n\ts_specifyserver.port.field.widthInChars = 6;\n\ts_specifyserver.port.field.maxchars     = 5;\n\n\ts_specifyserver.go.generic.type\t    = MTYPE_BITMAP;\n\ts_specifyserver.go.generic.name     = SPECIFYSERVER_FIGHT0;\n\ts_specifyserver.go.generic.flags    = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_specifyserver.go.generic.callback = SpecifyServer_Event;\n\ts_specifyserver.go.generic.id\t    = ID_SPECIFYSERVERGO;\n\ts_specifyserver.go.generic.x\t\t= 640;\n\ts_specifyserver.go.generic.y\t\t= 480-64;\n\ts_specifyserver.go.width  \t\t    = 128;\n\ts_specifyserver.go.height  \t\t    = 64;\n\ts_specifyserver.go.focuspic         = SPECIFYSERVER_FIGHT1;\n\n\ts_specifyserver.back.generic.type\t  = MTYPE_BITMAP;\n\ts_specifyserver.back.generic.name     = SPECIFYSERVER_BACK0;\n\ts_specifyserver.back.generic.flags    = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_specifyserver.back.generic.callback = SpecifyServer_Event;\n\ts_specifyserver.back.generic.id\t      = ID_SPECIFYSERVERBACK;\n\ts_specifyserver.back.generic.x\t\t  = 0;\n\ts_specifyserver.back.generic.y\t\t  = 480-64;\n\ts_specifyserver.back.width  \t\t  = 128;\n\ts_specifyserver.back.height  \t\t  = 64;\n\ts_specifyserver.back.focuspic         = SPECIFYSERVER_BACK1;\n\n\tMenu_AddItem( &s_specifyserver.menu, &s_specifyserver.banner );\n\tMenu_AddItem( &s_specifyserver.menu, &s_specifyserver.framel );\n\tMenu_AddItem( &s_specifyserver.menu, &s_specifyserver.framer );\n\tMenu_AddItem( &s_specifyserver.menu, &s_specifyserver.domain );\n\tMenu_AddItem( &s_specifyserver.menu, &s_specifyserver.port );\n\tMenu_AddItem( &s_specifyserver.menu, &s_specifyserver.go );\n\tMenu_AddItem( &s_specifyserver.menu, &s_specifyserver.back );\n\n\tCom_sprintf( s_specifyserver.port.field.buffer, 6, \"%i\", 27960 );\n}\n\n/*\n=================\nSpecifyServer_Cache\n=================\n*/\nvoid SpecifyServer_Cache( void )\n{\n\tint\ti;\n\n\t// touch all our pics\n\tfor (i=0; ;i++)\n\t{\n\t\tif (!specifyserver_artlist[i])\n\t\t\tbreak;\n\t\ttrap_R_RegisterShaderNoMip(specifyserver_artlist[i]);\n\t}\n}\n\n/*\n=================\nUI_SpecifyServerMenu\n=================\n*/\nvoid UI_SpecifyServerMenu( void )\n{\n\tSpecifyServer_MenuInit();\n\tUI_PushMenu( &s_specifyserver.menu );\n}\n\n"
  },
  {
    "path": "src/q3_ui/ui_splevel.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n/*\n=============================================================================\n\nSINGLE PLAYER LEVEL SELECT MENU\n\n=============================================================================\n*/\n\n#include \"ui_local.h\"\n\n\n#define ART_LEVELFRAME_FOCUS\t\t\"menu/art/maps_select\"\n#define ART_LEVELFRAME_SELECTED\t\t\"menu/art/maps_selected\"\n#define ART_ARROW\t\t\t\t\t\"menu/art/narrow_0\"\n#define ART_ARROW_FOCUS\t\t\t\t\"menu/art/narrow_1\"\n#define ART_MAP_UNKNOWN\t\t\t\t\"menu/art/unknownmap\"\n#define ART_MAP_COMPLETE1\t\t\t\"menu/art/level_complete1\"\n#define ART_MAP_COMPLETE2\t\t\t\"menu/art/level_complete2\"\n#define ART_MAP_COMPLETE3\t\t\t\"menu/art/level_complete3\"\n#define ART_MAP_COMPLETE4\t\t\t\"menu/art/level_complete4\"\n#define ART_MAP_COMPLETE5\t\t\t\"menu/art/level_complete5\"\n#define ART_BACK0\t\t\t\t\t\"menu/art/back_0\"\n#define ART_BACK1\t\t\t\t\t\"menu/art/back_1\"\t\n#define ART_FIGHT0\t\t\t\t\t\"menu/art/fight_0\"\n#define ART_FIGHT1\t\t\t\t\t\"menu/art/fight_1\"\n#define ART_RESET0\t\t\t\t\t\"menu/art/reset_0\"\n#define ART_RESET1\t\t\t\t\t\"menu/art/reset_1\"\t\n#define ART_CUSTOM0\t\t\t\t\t\"menu/art/skirmish_0\"\n#define ART_CUSTOM1\t\t\t\t\t\"menu/art/skirmish_1\"\n\n#define ID_LEFTARROW\t\t10\n#define ID_PICTURE0\t\t\t11\n#define ID_PICTURE1\t\t\t12\n#define ID_PICTURE2\t\t\t13\n#define ID_PICTURE3\t\t\t14\n#define ID_RIGHTARROW\t\t15\n#define ID_PLAYERPIC\t\t16\n#define ID_AWARD1\t\t\t17\n#define ID_AWARD2\t\t\t18\n#define ID_AWARD3\t\t\t19\n#define ID_AWARD4\t\t\t20\n#define ID_AWARD5\t\t\t21\n#define ID_AWARD6\t\t\t22\n#define ID_BACK\t\t\t\t23\n#define ID_RESET\t\t\t24\n#define ID_CUSTOM\t\t\t25\n#define ID_NEXT\t\t\t\t26\n\n#define PLAYER_Y\t\t\t314\n#define AWARDS_Y\t\t\t(PLAYER_Y + 26)\n\n\ntypedef struct {\n\tmenuframework_s\tmenu;\n\tmenutext_s\t\titem_banner;\n\tmenubitmap_s\titem_leftarrow;\n\tmenubitmap_s\titem_maps[4];\n\tmenubitmap_s\titem_rightarrow;\n\tmenubitmap_s\titem_player;\n\tmenubitmap_s\titem_awards[6];\n\tmenubitmap_s\titem_back;\n\tmenubitmap_s\titem_reset;\n\tmenubitmap_s\titem_custom;\n\tmenubitmap_s\titem_next;\n\tmenubitmap_s\titem_null;\n\n\tqboolean\t\treinit;\n\n\tconst char *\tselectedArenaInfo;\n\tint\t\t\t\tnumMaps;\n\tchar\t\t\tlevelPicNames[4][MAX_QPATH];\n\tchar\t\t\tlevelNames[4][16];\n\tint\t\t\t\tlevelScores[4];\n\tint\t\t\t\tlevelScoresSkill[4];\n\tqhandle_t\t\tlevelSelectedPic;\n\tqhandle_t\t\tlevelFocusPic;\n\tqhandle_t\t\tlevelCompletePic[5];\n\n\tchar\t\t\tplayerModel[MAX_QPATH];\n\tchar\t\t\tplayerPicName[MAX_QPATH];\n\tint\t\t\t\tawardLevels[6];\n\tsfxHandle_t\t\tawardSounds[6];\n\n\tint\t\t\t\tnumBots;\n\tqhandle_t\t\tbotPics[7];\n\tchar\t\t\tbotNames[7][10];\n} levelMenuInfo_t;\n\nstatic levelMenuInfo_t\tlevelMenuInfo;\n\nstatic int\tselectedArenaSet;\nstatic int\tselectedArena;\nstatic int\tcurrentSet;\nstatic int\tcurrentGame;\nstatic int\ttrainingTier;\nstatic int\tfinalTier;\nstatic int\tminTier;\nstatic int\tmaxTier;\n\n\n/*\n=================\nPlayerIcon\n=================\n*/\nstatic void PlayerIcon( const char *modelAndSkin, char *iconName, int iconNameMaxSize ) {\n\tchar\t*skin;\n\tchar\tmodel[MAX_QPATH];\n\n\tQ_strncpyz( model, modelAndSkin, sizeof(model));\n\tskin = Q_strrchr( model, '/' );\n\tif ( skin ) {\n\t\t*skin++ = '\\0';\n\t}\n\telse {\n\t\tskin = \"default\";\n\t}\n\n\tCom_sprintf(iconName, iconNameMaxSize, \"models/players/%s/icon_%s.tga\", model, skin );\n\n\tif( !trap_R_RegisterShaderNoMip( iconName ) && Q_stricmp( skin, \"default\" ) != 0 ) {\n\t\tCom_sprintf(iconName, iconNameMaxSize, \"models/players/%s/icon_default.tga\", model );\n\t}\n}\n\n\n/*\n=================\nPlayerIconhandle\n=================\n*/\nstatic qhandle_t PlayerIconHandle( const char *modelAndSkin ) {\n\tchar\ticonName[MAX_QPATH];\n\n\tPlayerIcon( modelAndSkin, iconName, sizeof(iconName) );\n\treturn trap_R_RegisterShaderNoMip( iconName );\n}\n\n\n/*\n=================\nUI_SPLevelMenu_SetBots\n=================\n*/\nstatic void UI_SPLevelMenu_SetBots( void ) {\n\tchar\t*p;\n\tchar\t*bot;\n\tchar\t*botInfo;\n\tchar\tbots[MAX_INFO_STRING];\n\n\tlevelMenuInfo.numBots = 0;\n\tif ( selectedArenaSet > currentSet ) {\n\t\treturn;\n\t}\n\n\tQ_strncpyz( bots, Info_ValueForKey( levelMenuInfo.selectedArenaInfo, \"bots\" ), sizeof(bots) );\n\n\tp = &bots[0];\n\twhile( *p && levelMenuInfo.numBots < 7 ) {\n\t\t//skip spaces\n\t\twhile( *p && *p == ' ' ) {\n\t\t\tp++;\n\t\t}\n\t\tif( !p ) {\n\t\t\tbreak;\n\t\t}\n\n\t\t// mark start of bot name\n\t\tbot = p;\n\n\t\t// skip until space of null\n\t\twhile( *p && *p != ' ' ) {\n\t\t\tp++;\n\t\t}\n\t\tif( *p ) {\n\t\t\t*p++ = 0;\n\t\t}\n\n\t\tbotInfo = UI_GetBotInfoByName( bot );\n\t\tif( botInfo ) {\n\t\t\tlevelMenuInfo.botPics[levelMenuInfo.numBots] = PlayerIconHandle( Info_ValueForKey( botInfo, \"model\" ) );\n\t\t\tQ_strncpyz( levelMenuInfo.botNames[levelMenuInfo.numBots], Info_ValueForKey( botInfo, \"name\" ), 10 );\n\t\t}\n\t\telse {\n\t\t\tlevelMenuInfo.botPics[levelMenuInfo.numBots] = 0;\n\t\t\tQ_strncpyz( levelMenuInfo.botNames[levelMenuInfo.numBots], bot, 10 );\n\t\t}\n\t\tQ_CleanStr( levelMenuInfo.botNames[levelMenuInfo.numBots] );\n\t\tlevelMenuInfo.numBots++;\n\t}\n}\n\n\n/*\n=================\nUI_SPLevelMenu_SetMenuItems\n=================\n*/\nstatic void UI_SPLevelMenu_SetMenuArena( int n, int level, const char *arenaInfo ) {\n\tchar\t\tmap[MAX_QPATH];\n\n\tQ_strncpyz( map, Info_ValueForKey( arenaInfo, \"map\" ), sizeof(map) );\n\n\tQ_strncpyz( levelMenuInfo.levelNames[n], map, sizeof(levelMenuInfo.levelNames[n]) );\n\tQ_strupr( levelMenuInfo.levelNames[n] );\n\n\tUI_GetBestScore( level, &levelMenuInfo.levelScores[n], &levelMenuInfo.levelScoresSkill[n] );\n\tif( levelMenuInfo.levelScores[n] > 8 ) {\n\t\tlevelMenuInfo.levelScores[n] = 8;\n\t}\n\n\tstrcpy( levelMenuInfo.levelPicNames[n], va( \"levelshots/%s.tga\", map ) );\n\tif( !trap_R_RegisterShaderNoMip( levelMenuInfo.levelPicNames[n] ) ) {\n\t\tstrcpy( levelMenuInfo.levelPicNames[n], ART_MAP_UNKNOWN );\n\t}\n\tlevelMenuInfo.item_maps[n].shader = 0;\n\tif ( selectedArenaSet > currentSet ) {\n\t\tlevelMenuInfo.item_maps[n].generic.flags |= QMF_GRAYED;\n\t}\n\telse {\n\t\tlevelMenuInfo.item_maps[n].generic.flags &= ~QMF_GRAYED;\n\t}\n\n\tlevelMenuInfo.item_maps[n].generic.flags &= ~QMF_INACTIVE;\n}\n\nstatic void UI_SPLevelMenu_SetMenuItems( void ) {\n\tint\t\t\tn;\n\tint\t\t\tlevel;\n\tconst char\t*arenaInfo;\n\n\tif ( selectedArenaSet > currentSet ) {\n\t\tselectedArena = -1;\n\t}\n\telse if ( selectedArena == -1 ) {\n\t\tselectedArena = 0;\n\t}\n\n\tif( selectedArenaSet == trainingTier || selectedArenaSet == finalTier ) {\n\t\tselectedArena = 0;\n\t}\n\n\tif( selectedArena != -1 ) {\n\t\ttrap_Cvar_SetValue( \"ui_spSelection\", selectedArenaSet * ARENAS_PER_TIER + selectedArena );\n\t}\n\n\tif( selectedArenaSet == trainingTier ) {\n\t\tarenaInfo = UI_GetSpecialArenaInfo( \"training\" );\n\t\tlevel = atoi( Info_ValueForKey( arenaInfo, \"num\" ) );\n\t\tUI_SPLevelMenu_SetMenuArena( 0, level, arenaInfo );\n\t\tlevelMenuInfo.selectedArenaInfo = arenaInfo;\n\n\t\tlevelMenuInfo.item_maps[0].generic.x = 256;\n\t\tBitmap_Init( &levelMenuInfo.item_maps[0] );\n\t\tlevelMenuInfo.item_maps[0].generic.bottom += 32;\n\t\tlevelMenuInfo.numMaps = 1;\n\n\t\tlevelMenuInfo.item_maps[1].generic.flags |= QMF_INACTIVE;\n\t\tlevelMenuInfo.item_maps[2].generic.flags |= QMF_INACTIVE;\n\t\tlevelMenuInfo.item_maps[3].generic.flags |= QMF_INACTIVE;\n\t\tlevelMenuInfo.levelPicNames[1][0] = 0;\n\t\tlevelMenuInfo.levelPicNames[2][0] = 0;\n\t\tlevelMenuInfo.levelPicNames[3][0] = 0;\n\t\tlevelMenuInfo.item_maps[1].shader = 0;\n\t\tlevelMenuInfo.item_maps[2].shader = 0;\n\t\tlevelMenuInfo.item_maps[3].shader = 0;\n\t}\n\telse if( selectedArenaSet == finalTier ) {\n\t\tarenaInfo = UI_GetSpecialArenaInfo( \"final\" );\n\t\tlevel = atoi( Info_ValueForKey( arenaInfo, \"num\" ) );\n\t\tUI_SPLevelMenu_SetMenuArena( 0, level, arenaInfo );\n\t\tlevelMenuInfo.selectedArenaInfo = arenaInfo;\n\n\t\tlevelMenuInfo.item_maps[0].generic.x = 256;\n\t\tBitmap_Init( &levelMenuInfo.item_maps[0] );\n\t\tlevelMenuInfo.item_maps[0].generic.bottom += 32;\n\t\tlevelMenuInfo.numMaps = 1;\n\n\t\tlevelMenuInfo.item_maps[1].generic.flags |= QMF_INACTIVE;\n\t\tlevelMenuInfo.item_maps[2].generic.flags |= QMF_INACTIVE;\n\t\tlevelMenuInfo.item_maps[3].generic.flags |= QMF_INACTIVE;\n\t\tlevelMenuInfo.levelPicNames[1][0] = 0;\n\t\tlevelMenuInfo.levelPicNames[2][0] = 0;\n\t\tlevelMenuInfo.levelPicNames[3][0] = 0;\n\t\tlevelMenuInfo.item_maps[1].shader = 0;\n\t\tlevelMenuInfo.item_maps[2].shader = 0;\n\t\tlevelMenuInfo.item_maps[3].shader = 0;\n\t}\n\telse {\n\t\tlevelMenuInfo.item_maps[0].generic.x = 46;\n\t\tBitmap_Init( &levelMenuInfo.item_maps[0] );\n\t\tlevelMenuInfo.item_maps[0].generic.bottom += 18;\n\t\tlevelMenuInfo.numMaps = 4;\n\n\t\tfor ( n = 0; n < 4; n++ ) {\n\t\t\tlevel = selectedArenaSet * ARENAS_PER_TIER + n;\n\t\t\tarenaInfo = UI_GetArenaInfoByNumber( level );\n\t\t\tUI_SPLevelMenu_SetMenuArena( n, level, arenaInfo );\n\t\t}\n\n\t\tif( selectedArena != -1 ) {\n\t\t\tlevelMenuInfo.selectedArenaInfo = UI_GetArenaInfoByNumber( selectedArenaSet * ARENAS_PER_TIER + selectedArena );\n\t\t}\n\t}\n\n\t// enable/disable arrows when they are valid/invalid\n\tif ( selectedArenaSet == minTier ) {\n\t\tlevelMenuInfo.item_leftarrow.generic.flags |= ( QMF_INACTIVE | QMF_HIDDEN );\n\t}\n\telse {\n\t\tlevelMenuInfo.item_leftarrow.generic.flags &= ~( QMF_INACTIVE | QMF_HIDDEN );\n\t}\n\n\tif ( selectedArenaSet == maxTier ) {\n\t\tlevelMenuInfo.item_rightarrow.generic.flags |= ( QMF_INACTIVE | QMF_HIDDEN );\n\t}\n\telse {\n\t\tlevelMenuInfo.item_rightarrow.generic.flags &= ~( QMF_INACTIVE | QMF_HIDDEN );\n\t}\n\n\tUI_SPLevelMenu_SetBots();\n}\n\n\n/*\n=================\nUI_SPLevelMenu_ResetEvent\n=================\n*/\nstatic void UI_SPLevelMenu_ResetDraw( void ) {\n\tUI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 0, \"WARNING: This resets all of the\", UI_CENTER|UI_SMALLFONT, color_yellow );\n\tUI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 1, \"single player game variables.\", UI_CENTER|UI_SMALLFONT, color_yellow );\n\tUI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 2, \"Do this only if you want to\", UI_CENTER|UI_SMALLFONT, color_yellow );\n\tUI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 3, \"start over from the beginning.\", UI_CENTER|UI_SMALLFONT, color_yellow );\n}\n\nstatic void UI_SPLevelMenu_ResetAction( qboolean result ) {\n\tif( !result ) {\n\t\treturn;\n\t}\n\n\t// clear game variables\n\tUI_NewGame();\n\ttrap_Cvar_SetValue( \"ui_spSelection\", -4 );\n\n\t// make the level select menu re-initialize\n\tUI_PopMenu();\n\tUI_SPLevelMenu();\n}\n\nstatic void UI_SPLevelMenu_ResetEvent( void* ptr, int event )\n{\n\tif (event != QM_ACTIVATED) {\n\t\treturn;\n\t}\n\n\tUI_ConfirmMenu( \"RESET GAME?\", UI_SPLevelMenu_ResetDraw, UI_SPLevelMenu_ResetAction );\n}\n\n\n/*\n=================\nUI_SPLevelMenu_LevelEvent\n=================\n*/\nstatic void UI_SPLevelMenu_LevelEvent( void* ptr, int notification ) {\n\tif (notification != QM_ACTIVATED) {\n\t\treturn;\n\t}\n\n\tif ( selectedArenaSet == trainingTier || selectedArenaSet == finalTier ) {\n\t\treturn;\n\t}\n\n\tselectedArena = ((menucommon_s*)ptr)->id - ID_PICTURE0;\n\tlevelMenuInfo.selectedArenaInfo = UI_GetArenaInfoByNumber( selectedArenaSet * ARENAS_PER_TIER + selectedArena );\n\tUI_SPLevelMenu_SetBots();\n\n\ttrap_Cvar_SetValue( \"ui_spSelection\", selectedArenaSet * ARENAS_PER_TIER + selectedArena );\n}\n\n\n/*\n=================\nUI_SPLevelMenu_LeftArrowEvent\n=================\n*/\nstatic void UI_SPLevelMenu_LeftArrowEvent( void* ptr, int notification ) {\n\tif (notification != QM_ACTIVATED) {\n\t\treturn;\n\t}\n\n\tif ( selectedArenaSet == minTier ) {\n\t\treturn;\n\t}\n\n\tselectedArenaSet--;\n\tUI_SPLevelMenu_SetMenuItems();\n}\n\n\n/*\n=================\nUI_SPLevelMenu_RightArrowEvent\n=================\n*/\nstatic void UI_SPLevelMenu_RightArrowEvent( void* ptr, int notification ) {\n\tif (notification != QM_ACTIVATED) {\n\t\treturn;\n\t}\n\n\tif ( selectedArenaSet == maxTier ) {\n\t\treturn;\n\t}\n\n\tselectedArenaSet++;\n\tUI_SPLevelMenu_SetMenuItems();\n}\n\n\n/*\n=================\nUI_SPLevelMenu_PlayerEvent\n=================\n*/\nstatic void UI_SPLevelMenu_PlayerEvent( void* ptr, int notification ) {\n\tif (notification != QM_ACTIVATED) {\n\t\treturn;\n\t}\n\n\tUI_PlayerSettingsMenu();\n}\n\n\n/*\n=================\nUI_SPLevelMenu_AwardEvent\n=================\n*/\nstatic void UI_SPLevelMenu_AwardEvent( void* ptr, int notification ) {\n\tint\t\tn;\n\n\tif (notification != QM_ACTIVATED) {\n\t\treturn;\n\t}\n\n\tn = ((menucommon_s*)ptr)->id - ID_AWARD1;\n\ttrap_S_StartLocalSound( levelMenuInfo.awardSounds[n], CHAN_ANNOUNCER );\n}\n\n\n/*\n=================\nUI_SPLevelMenu_NextEvent\n=================\n*/\nstatic void UI_SPLevelMenu_NextEvent( void* ptr, int notification ) {\n\tif (notification != QM_ACTIVATED) {\n\t\treturn;\n\t}\n\n\tif ( selectedArenaSet > currentSet ) {\n\t\treturn;\n\t}\n\n\tif ( selectedArena == -1 ) {\n\t\tselectedArena = 0;\n\t}\n\n\tUI_SPSkillMenu( levelMenuInfo.selectedArenaInfo );\n}\n\n\n/*\n=================\nUI_SPLevelMenu_BackEvent\n=================\n*/\nstatic void UI_SPLevelMenu_BackEvent( void* ptr, int notification ) {\n\tif (notification != QM_ACTIVATED) {\n\t\treturn;\n\t}\n\n\tif ( selectedArena == -1 ) {\n\t\tselectedArena = 0;\n\t}\n\n\tUI_PopMenu();\n}\n\n\n/*\n=================\nUI_SPLevelMenu_CustomEvent\n=================\n*/\nstatic void UI_SPLevelMenu_CustomEvent( void* ptr, int notification ) {\n\tif (notification != QM_ACTIVATED) {\n\t\treturn;\n\t}\n\n\tUI_StartServerMenu( qfalse );\n}\n\n\n/*\n=================\nUI_SPLevelMenu_MenuDraw\n=================\n*/\n#define LEVEL_DESC_LEFT_MARGIN\t\t332\n\nstatic void UI_SPLevelMenu_MenuDraw( void ) {\n\tint\t\t\t\tn, i;\n\tint\t\t\t\tx, y;\n\tvec4_t\t\t\tcolor;\n\tint\t\t\t\tlevel;\n//\tint\t\t\t\tfraglimit;\n\tint\t\t\t\tpad;\n\tchar\t\t\tbuf[MAX_INFO_VALUE];\n\tchar\t\t\tstring[64];\n\n\tif(\tlevelMenuInfo.reinit ) {\n\t\tUI_PopMenu();\n\t\tUI_SPLevelMenu();\n\t\treturn;\n\t}\n\n\t// draw player name\n\ttrap_Cvar_VariableStringBuffer( \"name\", string, 32 );\n\tQ_CleanStr( string );\n\tUI_DrawProportionalString( 320, PLAYER_Y, string, UI_CENTER|UI_SMALLFONT, color_orange );\n\n\t// check for model changes\n\ttrap_Cvar_VariableStringBuffer( \"model\", buf, sizeof(buf) );\n\tif( Q_stricmp( buf, levelMenuInfo.playerModel ) != 0 ) {\n\t\tQ_strncpyz( levelMenuInfo.playerModel, buf, sizeof(levelMenuInfo.playerModel) );\n\t\tPlayerIcon( levelMenuInfo.playerModel, levelMenuInfo.playerPicName, sizeof(levelMenuInfo.playerPicName) );\n\t\tlevelMenuInfo.item_player.shader = 0;\n\t}\n\n\t// standard menu drawing\n\tMenu_Draw( &levelMenuInfo.menu );\n\n\t// draw player award levels\n\ty = AWARDS_Y;\n\ti = 0;\n\tfor( n = 0; n < 6; n++ ) {\n\t\tlevel = levelMenuInfo.awardLevels[n];\n\t\tif( level > 0 ) {\n\t\t\tif( i & 1 ) {\n\t\t\t\tx = 224 - (i - 1 ) / 2 * (48 + 16);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tx = 368 + i / 2 * (48 + 16);\n\t\t\t}\n\t\t\ti++;\n\n\t\t\tif( level == 1 ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif( level >= 1000000 ) {\n\t\t\t\tCom_sprintf( string, sizeof(string), \"%im\", level / 1000000 );\n\t\t\t}\n\t\t\telse if( level >= 1000 ) {\n\t\t\t\tCom_sprintf( string, sizeof(string), \"%ik\", level / 1000 );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tCom_sprintf( string, sizeof(string), \"%i\", level );\n\t\t\t}\n\n\t\t\tUI_DrawString( x + 24, y + 48, string, UI_CENTER, color_yellow );\n\t\t}\n\t}\n\n\tUI_DrawProportionalString( 18, 38, va( \"Tier %i\", selectedArenaSet + 1 ), UI_LEFT|UI_SMALLFONT, color_orange );\n\n\tfor ( n = 0; n < levelMenuInfo.numMaps; n++ ) {\n\t\tx = levelMenuInfo.item_maps[n].generic.x;\n\t\ty = levelMenuInfo.item_maps[n].generic.y;\n\t\tUI_FillRect( x, y + 96, 128, 18, color_black );\n\t}\n\n\tif ( selectedArenaSet > currentSet ) {\n\t\tUI_DrawProportionalString( 320, 216, \"ACCESS DENIED\", UI_CENTER|UI_BIGFONT, color_red );\n\t\treturn;\n\t}\n\n\t// show levelshots for levels of current tier\n\tVector4Copy( color_white, color );\n\tcolor[3] = 0.5+0.5*sin(uis.realtime/PULSE_DIVISOR);\n\tfor ( n = 0; n < levelMenuInfo.numMaps; n++ ) {\n\t\tx = levelMenuInfo.item_maps[n].generic.x;\n\t\ty = levelMenuInfo.item_maps[n].generic.y;\n\n\t\tUI_DrawString( x + 64, y + 96, levelMenuInfo.levelNames[n], UI_CENTER|UI_SMALLFONT, color_orange );\n\n\t\tif( levelMenuInfo.levelScores[n] == 1 ) {\n\t\t\tUI_DrawHandlePic( x, y, 128, 96, levelMenuInfo.levelCompletePic[levelMenuInfo.levelScoresSkill[n] - 1] ); \n\t\t}\n\n\t\tif ( n == selectedArena ) {\n\t\t\tif( Menu_ItemAtCursor( &levelMenuInfo.menu ) == &levelMenuInfo.item_maps[n] ) {\n\t\t\t\ttrap_R_SetColor( color );\n\t\t\t}\n\t\t\tUI_DrawHandlePic( x-1, y-1, 130, 130 - 14, levelMenuInfo.levelSelectedPic ); \n\t\t\ttrap_R_SetColor( NULL );\n\t\t}\n\t\telse if( Menu_ItemAtCursor( &levelMenuInfo.menu ) == &levelMenuInfo.item_maps[n] ) {\n\t\t\ttrap_R_SetColor( color );\n\t\t\tUI_DrawHandlePic( x-31, y-30, 256, 256-27, levelMenuInfo.levelFocusPic); \n\t\t\ttrap_R_SetColor( NULL );\n\t\t}\n\t}\n\n\t// show map name and long name of selected level\n\ty = 192;\n\tQ_strncpyz( buf, Info_ValueForKey( levelMenuInfo.selectedArenaInfo, \"map\" ), 20 );\n\tQ_strupr( buf );\n\tCom_sprintf( string, sizeof(string), \"%s: %s\", buf, Info_ValueForKey( levelMenuInfo.selectedArenaInfo, \"longname\" ) );\n\tUI_DrawProportionalString( 320, y, string, UI_CENTER|UI_SMALLFONT, color_orange );\n\n//\tfraglimit = atoi( Info_ValueForKey( levelMenuInfo.selectedArenaInfo, \"fraglimit\" ) );\n//\tUI_DrawString( 18, 212, va(\"Frags %i\", fraglimit) , UI_LEFT|UI_SMALLFONT, color_orange );\n\n\t// draw bot opponents\n\ty += 24;\n\tpad = (7 - levelMenuInfo.numBots) * (64 + 26) / 2;\n\tfor( n = 0; n < levelMenuInfo.numBots; n++ ) {\n\t\tx = 18 + pad + (64 + 26) * n;\n\t\tif( levelMenuInfo.botPics[n] ) {\n\t\t\tUI_DrawHandlePic( x, y, 64, 64, levelMenuInfo.botPics[n]);\n\t\t}\n\t\telse {\n\t\t\tUI_FillRect( x, y, 64, 64, color_black );\n\t\t\tUI_DrawProportionalString( x+22, y+18, \"?\", UI_BIGFONT, color_orange );\n\t\t}\n\t\tUI_DrawString( x, y + 64, levelMenuInfo.botNames[n], UI_SMALLFONT|UI_LEFT, color_orange );\n\t}\n}\n\n\n/*\n=================\nUI_SPLevelMenu_Cache\n=================\n*/\nvoid UI_SPLevelMenu_Cache( void ) {\n\tint\t\t\t\tn;\n\n\ttrap_R_RegisterShaderNoMip( ART_LEVELFRAME_FOCUS );\n\ttrap_R_RegisterShaderNoMip( ART_LEVELFRAME_SELECTED );\n\ttrap_R_RegisterShaderNoMip( ART_ARROW );\n\ttrap_R_RegisterShaderNoMip( ART_ARROW_FOCUS );\n\ttrap_R_RegisterShaderNoMip( ART_MAP_UNKNOWN );\n\ttrap_R_RegisterShaderNoMip( ART_MAP_COMPLETE1 );\n\ttrap_R_RegisterShaderNoMip( ART_MAP_COMPLETE2 );\n\ttrap_R_RegisterShaderNoMip( ART_MAP_COMPLETE3 );\n\ttrap_R_RegisterShaderNoMip( ART_MAP_COMPLETE4 );\n\ttrap_R_RegisterShaderNoMip( ART_MAP_COMPLETE5 );\n\ttrap_R_RegisterShaderNoMip( ART_BACK0 );\n\ttrap_R_RegisterShaderNoMip( ART_BACK1 );\n\ttrap_R_RegisterShaderNoMip( ART_FIGHT0 );\n\ttrap_R_RegisterShaderNoMip( ART_FIGHT1 );\n\ttrap_R_RegisterShaderNoMip( ART_RESET0 );\n\ttrap_R_RegisterShaderNoMip( ART_RESET1 );\n\ttrap_R_RegisterShaderNoMip( ART_CUSTOM0 );\n\ttrap_R_RegisterShaderNoMip( ART_CUSTOM1 );\n\n\tfor( n = 0; n < 6; n++ ) {\n\t\ttrap_R_RegisterShaderNoMip( ui_medalPicNames[n] );\n\t\tlevelMenuInfo.awardSounds[n] = trap_S_RegisterSound( ui_medalSounds[n], qfalse );\n\t}\n\n\tlevelMenuInfo.levelSelectedPic = trap_R_RegisterShaderNoMip( ART_LEVELFRAME_SELECTED );\n\tlevelMenuInfo.levelFocusPic = trap_R_RegisterShaderNoMip( ART_LEVELFRAME_FOCUS );\n\tlevelMenuInfo.levelCompletePic[0] = trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE1 );\n\tlevelMenuInfo.levelCompletePic[1] = trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE2 );\n\tlevelMenuInfo.levelCompletePic[2] = trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE3 );\n\tlevelMenuInfo.levelCompletePic[3] = trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE4 );\n\tlevelMenuInfo.levelCompletePic[4] = trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE5 );\n}\n\n\n/*\n=================\nUI_SPLevelMenu_Init\n=================\n*/\nstatic void UI_SPLevelMenu_Init( void ) {\n\tint\t\tskill;\n\tint\t\tn;\n\tint\t\tx, y;\n\tint\t\tcount;\n\tchar\tbuf[MAX_QPATH];\n\n\tskill = (int)trap_Cvar_VariableValue( \"g_spSkill\" );\n\tif( skill < 1 || skill > 5 ) {\n\t\ttrap_Cvar_Set( \"g_spSkill\", \"2\" );\n\t\tskill = 2;\n\t}\n\n\tmemset( &levelMenuInfo, 0, sizeof(levelMenuInfo) );\n\tlevelMenuInfo.menu.fullscreen = qtrue;\n\tlevelMenuInfo.menu.wrapAround = qtrue;\n\tlevelMenuInfo.menu.draw = UI_SPLevelMenu_MenuDraw;\n\n\tUI_SPLevelMenu_Cache();\n\n\tlevelMenuInfo.item_banner.generic.type\t\t\t= MTYPE_BTEXT;\n\tlevelMenuInfo.item_banner.generic.x\t\t\t\t= 320;\n\tlevelMenuInfo.item_banner.generic.y\t\t\t\t= 16;\n\tlevelMenuInfo.item_banner.string\t\t\t\t= \"CHOOSE LEVEL\";\n\tlevelMenuInfo.item_banner.color\t\t\t\t\t= color_red;\n\tlevelMenuInfo.item_banner.style\t\t\t\t\t= UI_CENTER;\n\n\tlevelMenuInfo.item_leftarrow.generic.type\t\t= MTYPE_BITMAP;\n\tlevelMenuInfo.item_leftarrow.generic.name\t\t= ART_ARROW;\n\tlevelMenuInfo.item_leftarrow.generic.flags\t\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\tlevelMenuInfo.item_leftarrow.generic.x\t\t\t= 18;\n\tlevelMenuInfo.item_leftarrow.generic.y\t\t\t= 64;\n\tlevelMenuInfo.item_leftarrow.generic.callback\t= UI_SPLevelMenu_LeftArrowEvent;\n\tlevelMenuInfo.item_leftarrow.generic.id\t\t\t= ID_LEFTARROW;\n\tlevelMenuInfo.item_leftarrow.width\t\t\t\t= 16;\n\tlevelMenuInfo.item_leftarrow.height\t\t\t\t= 114;\n\tlevelMenuInfo.item_leftarrow.focuspic\t\t\t= ART_ARROW_FOCUS;\n\n\tlevelMenuInfo.item_maps[0].generic.type\t\t\t= MTYPE_BITMAP;\n\tlevelMenuInfo.item_maps[0].generic.name\t\t\t= levelMenuInfo.levelPicNames[0];\n\tlevelMenuInfo.item_maps[0].generic.flags\t\t= QMF_LEFT_JUSTIFY;\n\tlevelMenuInfo.item_maps[0].generic.x\t\t\t= 46;\n\tlevelMenuInfo.item_maps[0].generic.y\t\t\t= 64;\n\tlevelMenuInfo.item_maps[0].generic.id\t\t\t= ID_PICTURE0;\n\tlevelMenuInfo.item_maps[0].generic.callback\t\t= UI_SPLevelMenu_LevelEvent;\n\tlevelMenuInfo.item_maps[0].width\t\t\t\t= 128;\n\tlevelMenuInfo.item_maps[0].height\t\t\t\t= 96;\n\n\tlevelMenuInfo.item_maps[1].generic.type\t\t\t= MTYPE_BITMAP;\n\tlevelMenuInfo.item_maps[1].generic.name\t\t\t= levelMenuInfo.levelPicNames[1];\n\tlevelMenuInfo.item_maps[1].generic.flags\t\t= QMF_LEFT_JUSTIFY;\n\tlevelMenuInfo.item_maps[1].generic.x\t\t\t= 186;\n\tlevelMenuInfo.item_maps[1].generic.y\t\t\t= 64;\n\tlevelMenuInfo.item_maps[1].generic.id\t\t\t= ID_PICTURE1;\n\tlevelMenuInfo.item_maps[1].generic.callback\t\t= UI_SPLevelMenu_LevelEvent;\n\tlevelMenuInfo.item_maps[1].width\t\t\t\t= 128;\n\tlevelMenuInfo.item_maps[1].height\t\t\t\t= 96;\n\n\tlevelMenuInfo.item_maps[2].generic.type\t\t\t= MTYPE_BITMAP;\n\tlevelMenuInfo.item_maps[2].generic.name\t\t\t= levelMenuInfo.levelPicNames[2];\n\tlevelMenuInfo.item_maps[2].generic.flags\t\t= QMF_LEFT_JUSTIFY;\n\tlevelMenuInfo.item_maps[2].generic.x\t\t\t= 326;\n\tlevelMenuInfo.item_maps[2].generic.y\t\t\t= 64;\n\tlevelMenuInfo.item_maps[2].generic.id\t\t\t= ID_PICTURE2;\n\tlevelMenuInfo.item_maps[2].generic.callback\t\t= UI_SPLevelMenu_LevelEvent;\n\tlevelMenuInfo.item_maps[2].width\t\t\t\t= 128;\n\tlevelMenuInfo.item_maps[2].height\t\t\t\t= 96;\n\n\tlevelMenuInfo.item_maps[3].generic.type\t\t\t= MTYPE_BITMAP;\n\tlevelMenuInfo.item_maps[3].generic.name\t\t\t= levelMenuInfo.levelPicNames[3];\n\tlevelMenuInfo.item_maps[3].generic.flags\t\t= QMF_LEFT_JUSTIFY;\n\tlevelMenuInfo.item_maps[3].generic.x\t\t\t= 466;\n\tlevelMenuInfo.item_maps[3].generic.y\t\t\t= 64;\n\tlevelMenuInfo.item_maps[3].generic.id\t\t\t= ID_PICTURE3;\n\tlevelMenuInfo.item_maps[3].generic.callback\t\t= UI_SPLevelMenu_LevelEvent;\n\tlevelMenuInfo.item_maps[3].width\t\t\t\t= 128;\n\tlevelMenuInfo.item_maps[3].height\t\t\t\t= 96;\n\n\tlevelMenuInfo.item_rightarrow.generic.type\t\t= MTYPE_BITMAP;\n\tlevelMenuInfo.item_rightarrow.generic.name\t\t= ART_ARROW;\n\tlevelMenuInfo.item_rightarrow.generic.flags\t\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\tlevelMenuInfo.item_rightarrow.generic.x\t\t\t= 606;\n\tlevelMenuInfo.item_rightarrow.generic.y\t\t\t= 64;\n\tlevelMenuInfo.item_rightarrow.generic.callback\t= UI_SPLevelMenu_RightArrowEvent;\n\tlevelMenuInfo.item_rightarrow.generic.id\t\t= ID_RIGHTARROW;\n\tlevelMenuInfo.item_rightarrow.width\t\t\t\t= -16;\n\tlevelMenuInfo.item_rightarrow.height\t\t\t= 114;\n\tlevelMenuInfo.item_rightarrow.focuspic\t\t\t= ART_ARROW_FOCUS;\n\n\ttrap_Cvar_VariableStringBuffer( \"model\", levelMenuInfo.playerModel, sizeof(levelMenuInfo.playerModel) );\n\tPlayerIcon( levelMenuInfo.playerModel, levelMenuInfo.playerPicName, sizeof(levelMenuInfo.playerPicName) );\n\tlevelMenuInfo.item_player.generic.type\t\t\t= MTYPE_BITMAP;\n\tlevelMenuInfo.item_player.generic.name\t\t\t= levelMenuInfo.playerPicName;\n\tlevelMenuInfo.item_player.generic.flags\t\t\t= QMF_LEFT_JUSTIFY|QMF_MOUSEONLY;\n\tlevelMenuInfo.item_player.generic.x\t\t\t\t= 288;\n\tlevelMenuInfo.item_player.generic.y\t\t\t\t= AWARDS_Y;\n\tlevelMenuInfo.item_player.generic.id\t\t\t= ID_PLAYERPIC;\n\tlevelMenuInfo.item_player.generic.callback\t\t= UI_SPLevelMenu_PlayerEvent;\n\tlevelMenuInfo.item_player.width\t\t\t\t\t= 64;\n\tlevelMenuInfo.item_player.height\t\t\t\t= 64;\n\n\tfor( n = 0; n < 6; n++ ) {\n\t\tlevelMenuInfo.awardLevels[n] = UI_GetAwardLevel( n );\n\t}\n\tlevelMenuInfo.awardLevels[AWARD_FRAGS] = 100 * (levelMenuInfo.awardLevels[AWARD_FRAGS] / 100);\n\n\ty = AWARDS_Y;\n\tcount = 0;\n\tfor( n = 0; n < 6; n++ ) {\n\t\tif( levelMenuInfo.awardLevels[n] ) {\n\t\t\tif( count & 1 ) {\n\t\t\t\tx = 224 - (count - 1 ) / 2 * (48 + 16);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tx = 368 + count / 2 * (48 + 16);\n\t\t\t}\n\n\t\t\tlevelMenuInfo.item_awards[count].generic.type\t\t= MTYPE_BITMAP;\n\t\t\tlevelMenuInfo.item_awards[count].generic.name\t\t= ui_medalPicNames[n];\n\t\t\tlevelMenuInfo.item_awards[count].generic.flags\t\t= QMF_LEFT_JUSTIFY|QMF_SILENT|QMF_MOUSEONLY;\n\t\t\tlevelMenuInfo.item_awards[count].generic.x\t\t\t= x;\n\t\t\tlevelMenuInfo.item_awards[count].generic.y\t\t\t= y;\n\t\t\tlevelMenuInfo.item_awards[count].generic.id\t\t\t= ID_AWARD1 + n;\n\t\t\tlevelMenuInfo.item_awards[count].generic.callback\t= UI_SPLevelMenu_AwardEvent;\n\t\t\tlevelMenuInfo.item_awards[count].width\t\t\t\t= 48;\n\t\t\tlevelMenuInfo.item_awards[count].height\t\t\t\t= 48;\n\t\t\tcount++;\n\t\t}\n\t}\n\n\tlevelMenuInfo.item_back.generic.type\t\t\t= MTYPE_BITMAP;\n\tlevelMenuInfo.item_back.generic.name\t\t\t= ART_BACK0;\n\tlevelMenuInfo.item_back.generic.flags\t\t\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\tlevelMenuInfo.item_back.generic.x\t\t\t\t= 0;\n\tlevelMenuInfo.item_back.generic.y\t\t\t\t= 480-64;\n\tlevelMenuInfo.item_back.generic.callback\t\t= UI_SPLevelMenu_BackEvent;\n\tlevelMenuInfo.item_back.generic.id\t\t\t\t= ID_BACK;\n\tlevelMenuInfo.item_back.width\t\t\t\t\t= 128;\n\tlevelMenuInfo.item_back.height\t\t\t\t\t= 64;\n\tlevelMenuInfo.item_back.focuspic\t\t\t\t= ART_BACK1;\n\n\tlevelMenuInfo.item_reset.generic.type\t\t\t= MTYPE_BITMAP;\n\tlevelMenuInfo.item_reset.generic.name\t\t\t= ART_RESET0;\n\tlevelMenuInfo.item_reset.generic.flags\t\t\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\tlevelMenuInfo.item_reset.generic.x\t\t\t\t= 170;\n\tlevelMenuInfo.item_reset.generic.y\t\t\t\t= 480-64;\n\tlevelMenuInfo.item_reset.generic.callback\t\t= UI_SPLevelMenu_ResetEvent;\n\tlevelMenuInfo.item_reset.generic.id\t\t\t\t= ID_RESET;\n\tlevelMenuInfo.item_reset.width\t\t\t\t\t= 128;\n\tlevelMenuInfo.item_reset.height\t\t\t\t\t= 64;\n\tlevelMenuInfo.item_reset.focuspic\t\t\t\t= ART_RESET1;\n\n\tlevelMenuInfo.item_custom.generic.type\t\t\t= MTYPE_BITMAP;\n\tlevelMenuInfo.item_custom.generic.name\t\t\t= ART_CUSTOM0;\n\tlevelMenuInfo.item_custom.generic.flags\t\t\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\tlevelMenuInfo.item_custom.generic.x\t\t\t\t= 342;\n\tlevelMenuInfo.item_custom.generic.y\t\t\t\t= 480-64;\n\tlevelMenuInfo.item_custom.generic.callback\t\t= UI_SPLevelMenu_CustomEvent;\n\tlevelMenuInfo.item_custom.generic.id\t\t\t= ID_CUSTOM;\n\tlevelMenuInfo.item_custom.width\t\t\t\t\t= 128;\n\tlevelMenuInfo.item_custom.height\t\t\t\t= 64;\n\tlevelMenuInfo.item_custom.focuspic\t\t\t\t= ART_CUSTOM1;\n\n\tlevelMenuInfo.item_next.generic.type\t\t\t= MTYPE_BITMAP;\n\tlevelMenuInfo.item_next.generic.name\t\t\t= ART_FIGHT0;\n\tlevelMenuInfo.item_next.generic.flags\t\t\t= QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;\n\tlevelMenuInfo.item_next.generic.x\t\t\t\t= 640;\n\tlevelMenuInfo.item_next.generic.y\t\t\t\t= 480-64;\n\tlevelMenuInfo.item_next.generic.callback\t\t= UI_SPLevelMenu_NextEvent;\n\tlevelMenuInfo.item_next.generic.id\t\t\t\t= ID_NEXT;\n\tlevelMenuInfo.item_next.width\t\t\t\t\t= 128;\n\tlevelMenuInfo.item_next.height\t\t\t\t\t= 64;\n\tlevelMenuInfo.item_next.focuspic\t\t\t\t= ART_FIGHT1;\n\n\tlevelMenuInfo.item_null.generic.type\t\t\t= MTYPE_BITMAP;\n\tlevelMenuInfo.item_null.generic.flags\t\t\t= QMF_LEFT_JUSTIFY|QMF_MOUSEONLY|QMF_SILENT;\n\tlevelMenuInfo.item_null.generic.x\t\t\t\t= 0;\n\tlevelMenuInfo.item_null.generic.y\t\t\t\t= 0;\n\tlevelMenuInfo.item_null.width\t\t\t\t\t= 640;\n\tlevelMenuInfo.item_null.height\t\t\t\t\t= 480;\n\n\tMenu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_banner );\n\n\tMenu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_leftarrow );\n\tMenu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_maps[0] );\n\tMenu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_maps[1] );\n\tMenu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_maps[2] );\n\tMenu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_maps[3] );\n\tlevelMenuInfo.item_maps[0].generic.bottom += 18;\n\tlevelMenuInfo.item_maps[1].generic.bottom += 18;\n\tlevelMenuInfo.item_maps[2].generic.bottom += 18;\n\tlevelMenuInfo.item_maps[3].generic.bottom += 18;\n\tMenu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_rightarrow );\n\n\tMenu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_player );\n\n\tfor( n = 0; n < count; n++ ) {\n\t\tMenu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_awards[n] );\n\t}\n\tMenu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_back );\n\tMenu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_reset );\n\tMenu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_custom );\n\tMenu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_next );\n\tMenu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_null );\n\n\ttrap_Cvar_VariableStringBuffer( \"ui_spSelection\", buf, sizeof(buf) );\n\tif( *buf ) {\n\t\tn = atoi( buf );\n\t\tselectedArenaSet = n / ARENAS_PER_TIER;\n\t\tselectedArena = n % ARENAS_PER_TIER;\n\t}\n\telse {\n\t\tselectedArenaSet = currentSet;\n\t\tselectedArena = currentGame;\n\t}\n\n\tUI_SPLevelMenu_SetMenuItems();\n}\n\n\n/*\n=================\nUI_SPLevelMenu\n=================\n*/\nvoid UI_SPLevelMenu( void ) {\n\tint\t\t\tlevel;\n\tint\t\t\ttrainingLevel;\n\tconst char\t*arenaInfo;\n\n\ttrainingTier = -1;\n\tarenaInfo = UI_GetSpecialArenaInfo( \"training\" );\n\tif( arenaInfo ) {\n\t\tminTier = trainingTier;\n\t\ttrainingLevel = atoi( Info_ValueForKey( arenaInfo, \"num\" ) );\n\t}\n\telse {\n\t\tminTier = 0;\n\t\ttrainingLevel = -2;\n\t}\n\n\tfinalTier = UI_GetNumSPTiers();\n\tarenaInfo = UI_GetSpecialArenaInfo( \"final\" );\n\tif( arenaInfo ) {\n\t\tmaxTier = finalTier;\n\t}\n\telse {\n\t\tmaxTier = finalTier - 1;\n\t\tif( maxTier < minTier ) {\n\t\t\tmaxTier = minTier;\n\t\t}\n\t}\n\n\tlevel = UI_GetCurrentGame();\n\tif ( level == -1 ) {\n\t\tlevel = UI_GetNumSPArenas() - 1;\n\t\tif( maxTier == finalTier ) {\n\t\t\tlevel++;\n\t\t}\n\t}\n\n\tif( level == trainingLevel ) {\n\t\tcurrentSet = -1;\n\t\tcurrentGame = 0;\n\t}\n\telse {\n\t\tcurrentSet = level / ARENAS_PER_TIER;\n\t\tcurrentGame = level % ARENAS_PER_TIER;\n\t}\n\n\tUI_SPLevelMenu_Init();\n\tUI_PushMenu( &levelMenuInfo.menu );\n\tMenu_SetCursorToItem( &levelMenuInfo.menu, &levelMenuInfo.item_next );\n}\n\n\n/*\n=================\nUI_SPLevelMenu_f\n=================\n*/\nvoid UI_SPLevelMenu_f( void ) {\n\ttrap_Key_SetCatcher( KEYCATCH_UI );\n\tuis.menusp = 0;\n\tUI_SPLevelMenu();\n}\n\n\n/*\n=================\nUI_SPLevelMenu_ReInit\n=================\n*/\nvoid UI_SPLevelMenu_ReInit( void ) {\n\tlevelMenuInfo.reinit = qtrue;\n}\n"
  },
  {
    "path": "src/q3_ui/ui_sppostgame.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n/*\n=============================================================================\n\nSINGLE PLAYER POSTGAME MENU\n\n=============================================================================\n*/\n\n#include \"ui_local.h\"\n\n#define MAX_SCOREBOARD_CLIENTS\t\t8\n\n#define AWARD_PRESENTATION_TIME\t\t2000\n\n#define ART_MENU0\t\t\"menu/art/menu_0\"\n#define ART_MENU1\t\t\"menu/art/menu_1\"\n#define ART_REPLAY0\t\t\"menu/art/replay_0\"\n#define ART_REPLAY1\t\t\"menu/art/replay_1\"\n#define ART_NEXT0\t\t\"menu/art/next_0\"\n#define ART_NEXT1\t\t\"menu/art/next_1\"\n\n#define ID_AGAIN\t\t10\n#define ID_NEXT\t\t\t11\n#define ID_MENU\t\t\t12\n\ntypedef struct {\n\tmenuframework_s\tmenu;\n\tmenubitmap_s\titem_again;\n\tmenubitmap_s\titem_next;\n\tmenubitmap_s\titem_menu;\n\n\tint\t\t\t\tphase;\n\tint\t\t\t\tignoreKeysTime;\n\tint\t\t\t\tstarttime;\n\tint\t\t\t\tscoreboardtime;\n\tint\t\t\t\tserverId;\n\n\tint\t\t\t\tclientNums[MAX_SCOREBOARD_CLIENTS];\n\tint\t\t\t\tranks[MAX_SCOREBOARD_CLIENTS];\n\tint\t\t\t\tscores[MAX_SCOREBOARD_CLIENTS];\n\n\tchar\t\t\tplaceNames[3][64];\n\n\tint\t\t\t\tlevel;\n\tint\t\t\t\tnumClients;\n\tint\t\t\t\twon;\n\tint\t\t\t\tnumAwards;\n\tint\t\t\t\tawardsEarned[6];\n\tint\t\t\t\tawardsLevels[6];\n\tqboolean\t\tplayedSound[6];\n\tint\t\t\t\tlastTier;\n\tsfxHandle_t\t\twinnerSound;\n} postgameMenuInfo_t;\n\nstatic postgameMenuInfo_t\tpostgameMenuInfo;\nstatic char\t\t\t\t\tarenainfo[MAX_INFO_VALUE];\n\nchar\t*ui_medalNames[] = {\"Accuracy\", \"Impressive\", \"Excellent\", \"Gauntlet\", \"Frags\", \"Perfect\"};\nchar\t*ui_medalPicNames[] = {\n\t\"menu/medals/medal_accuracy\",\n\t\"menu/medals/medal_impressive\",\n\t\"menu/medals/medal_excellent\",\n\t\"menu/medals/medal_gauntlet\",\n\t\"menu/medals/medal_frags\",\n\t\"menu/medals/medal_victory\"\n};\nchar\t*ui_medalSounds[] = {\n\t\"sound/feedback/accuracy.wav\",\n\t\"sound/feedback/impressive_a.wav\",\n\t\"sound/feedback/excellent_a.wav\",\n\t\"sound/feedback/gauntlet.wav\",\n\t\"sound/feedback/frags.wav\",\n\t\"sound/feedback/perfect.wav\"\n};\n\n\n/*\n=================\nUI_SPPostgameMenu_AgainEvent\n=================\n*/\nstatic void UI_SPPostgameMenu_AgainEvent( void* ptr, int event )\n{\n\tif (event != QM_ACTIVATED) {\n\t\treturn;\n\t}\n\tUI_PopMenu();\n\ttrap_Cmd_ExecuteText( EXEC_APPEND, \"map_restart 0\\n\" );\n}\n\n\n/*\n=================\nUI_SPPostgameMenu_NextEvent\n=================\n*/\nstatic void UI_SPPostgameMenu_NextEvent( void* ptr, int event ) {\n\tint\t\t\tcurrentSet;\n\tint\t\t\tlevelSet;\n\tint\t\t\tlevel;\n\tint\t\t\tcurrentLevel;\n\tconst char\t*arenaInfo;\n\n\tif (event != QM_ACTIVATED) {\n\t\treturn;\n\t}\n\tUI_PopMenu();\n\n\t// handle specially if we just won the training map\n\tif( postgameMenuInfo.won == 0 ) {\n\t\tlevel = 0;\n\t}\n\telse {\n\t\tlevel = postgameMenuInfo.level + 1;\n\t}\n\tlevelSet = level / ARENAS_PER_TIER;\n\n\tcurrentLevel = UI_GetCurrentGame();\n\tif( currentLevel == -1 ) {\n\t\tcurrentLevel = postgameMenuInfo.level;\n\t}\n\tcurrentSet = currentLevel / ARENAS_PER_TIER;\n\n\tif( levelSet > currentSet || levelSet == UI_GetNumSPTiers() ) {\n\t\tlevel = currentLevel;\n\t}\n\n\tarenaInfo = UI_GetArenaInfoByNumber( level );\n\tif ( !arenaInfo ) {\n\t\treturn;\n\t}\n\n\tUI_SPArena_Start( arenaInfo );\n}\n\n\n/*\n=================\nUI_SPPostgameMenu_MenuEvent\n=================\n*/\nstatic void UI_SPPostgameMenu_MenuEvent( void* ptr, int event )\n{\n\tif (event != QM_ACTIVATED) {\n\t\treturn;\n\t}\n\tUI_PopMenu();\n\ttrap_Cmd_ExecuteText( EXEC_APPEND, \"disconnect; levelselect\\n\" );\n}\n\n\n/*\n=================\nUI_SPPostgameMenu_MenuKey\n=================\n*/\nstatic sfxHandle_t UI_SPPostgameMenu_MenuKey( int key ) {\n\tif ( uis.realtime < postgameMenuInfo.ignoreKeysTime ) {\n\t\treturn 0;\n\t}\n\n\tif( postgameMenuInfo.phase == 1 ) {\n\t\ttrap_Cmd_ExecuteText( EXEC_APPEND, \"abort_podium\\n\" );\n\t\tpostgameMenuInfo.phase = 2;\n\t\tpostgameMenuInfo.starttime = uis.realtime;\n\t\tpostgameMenuInfo.ignoreKeysTime\t= uis.realtime + 250;\n\t\treturn 0;\n\t}\n\n\tif( postgameMenuInfo.phase == 2 ) {\n\t\tpostgameMenuInfo.phase = 3;\n\t\tpostgameMenuInfo.starttime = uis.realtime;\n\t\tpostgameMenuInfo.ignoreKeysTime\t= uis.realtime + 250;\n\t\treturn 0;\n\t}\n\n\tif( key == K_ESCAPE || key == K_MOUSE2 ) {\n\t\treturn 0;\n\t}\n\n\treturn Menu_DefaultKey( &postgameMenuInfo.menu, key );\n}\n\n\nstatic int medalLocations[6] = {144, 448, 88, 504, 32, 560};\n\nstatic void UI_SPPostgameMenu_DrawAwardsMedals( int max ) {\n\tint\t\tn;\n\tint\t\tmedal;\n\tint\t\tamount;\n\tint\t\tx, y;\n\tchar\tbuf[16];\n\n\tfor( n = 0; n < max; n++ ) {\n\t\tx = medalLocations[n];\n\t\ty = 64;\n\t\tmedal = postgameMenuInfo.awardsEarned[n];\n\t\tamount = postgameMenuInfo.awardsLevels[n];\n\n\t\tUI_DrawNamedPic( x, y, 48, 48, ui_medalPicNames[medal] );\n\n\t\tif( medal == AWARD_ACCURACY ) {\n\t\t\tCom_sprintf( buf, sizeof(buf), \"%i%%\", amount );\n\t\t}\n\t\telse {\n\t\t\tif( amount == 1 ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tCom_sprintf( buf, sizeof(buf), \"%i\", amount );\n\t\t}\n\n\t\tUI_DrawString( x + 24, y + 52, buf, UI_CENTER, color_yellow );\n\t}\n}\n\n\nstatic void UI_SPPostgameMenu_DrawAwardsPresentation( int timer ) {\n\tint\t\tawardNum;\n\tint\t\tatimer;\n\tvec4_t\tcolor;\n\n\tawardNum = timer / AWARD_PRESENTATION_TIME;\n\tatimer = timer % AWARD_PRESENTATION_TIME;\n\n\tcolor[0] = color[1] = color[2] = 1.0f;\n\tcolor[3] = (float)( AWARD_PRESENTATION_TIME - atimer ) / (float)AWARD_PRESENTATION_TIME;\n\tUI_DrawProportionalString( 320, 64, ui_medalNames[postgameMenuInfo.awardsEarned[awardNum]], UI_CENTER, color );\n\n\tUI_SPPostgameMenu_DrawAwardsMedals( awardNum + 1 );\n\n\tif( !postgameMenuInfo.playedSound[awardNum] ) {\n\t\tpostgameMenuInfo.playedSound[awardNum] = qtrue;\n\t\ttrap_S_StartLocalSound( trap_S_RegisterSound( ui_medalSounds[postgameMenuInfo.awardsEarned[awardNum]], qfalse ), CHAN_ANNOUNCER );\n\t}\n}\n\n\n/*\n=================\nUI_SPPostgameMenu_MenuDrawScoreLine\n=================\n*/\nstatic void UI_SPPostgameMenu_MenuDrawScoreLine( int n, int y ) {\n\tint\t\trank;\n\tchar\tname[64];\n\tchar\tinfo[MAX_INFO_STRING];\n\n\tif( n > (postgameMenuInfo.numClients + 1) ) {\n\t\tn -= (postgameMenuInfo.numClients + 2);\n\t}\n\n\tif( n >= postgameMenuInfo.numClients ) {\n\t\treturn;\n\t}\n\n\trank = postgameMenuInfo.ranks[n];\n\tif( rank & RANK_TIED_FLAG ) {\n\t\tUI_DrawString( 640 - 31 * SMALLCHAR_WIDTH, y, \"(tie)\", UI_LEFT|UI_SMALLFONT, color_white );\n\t\trank &= ~RANK_TIED_FLAG;\n\t}\n\ttrap_GetConfigString( CS_PLAYERS + postgameMenuInfo.clientNums[n], info, MAX_INFO_STRING );\n\tQ_strncpyz( name, Info_ValueForKey( info, \"n\" ), sizeof(name) );\n\tQ_CleanStr( name );\n\n\tUI_DrawString( 640 - 25 * SMALLCHAR_WIDTH, y, va( \"#%i: %-16s %2i\", rank + 1, name, postgameMenuInfo.scores[n] ), UI_LEFT|UI_SMALLFONT, color_white );\n}\n\n\n/*\n=================\nUI_SPPostgameMenu_MenuDraw\n=================\n*/\nstatic void UI_SPPostgameMenu_MenuDraw( void ) {\n\tint\t\ttimer;\n\tint\t\tserverId;\n\tint\t\tn;\n\tchar\tinfo[MAX_INFO_STRING];\n\n\ttrap_GetConfigString( CS_SYSTEMINFO, info, sizeof(info) );\n\tserverId = atoi( Info_ValueForKey( info, \"sv_serverid\" ) );\n\tif( serverId != postgameMenuInfo.serverId ) {\n\t\tUI_PopMenu();\n\t\treturn;\n\t}\n\n\t// phase 1\n\tif ( postgameMenuInfo.numClients > 2 ) {\n\t\tUI_DrawProportionalString( 510, 480 - 64 - PROP_HEIGHT, postgameMenuInfo.placeNames[2], UI_CENTER, color_white );\n\t}\n\tUI_DrawProportionalString( 130, 480 - 64 - PROP_HEIGHT, postgameMenuInfo.placeNames[1], UI_CENTER, color_white );\n\tUI_DrawProportionalString( 320, 480 - 64 - 2 * PROP_HEIGHT, postgameMenuInfo.placeNames[0], UI_CENTER, color_white );\n\n\tif( postgameMenuInfo.phase == 1 ) {\n\t\ttimer = uis.realtime - postgameMenuInfo.starttime;\n\n\t\tif( timer >= 1000 && postgameMenuInfo.winnerSound ) {\n\t\t\ttrap_S_StartLocalSound( postgameMenuInfo.winnerSound, CHAN_ANNOUNCER );\n\t\t\tpostgameMenuInfo.winnerSound = 0;\n\t\t}\n\n\t\tif( timer < 5000 ) {\n\t\t\treturn;\n\t\t}\n\t\tpostgameMenuInfo.phase = 2;\n\t\tpostgameMenuInfo.starttime = uis.realtime;\n\t}\n\n\t// phase 2\n\tif( postgameMenuInfo.phase == 2 ) {\n\t\ttimer = uis.realtime - postgameMenuInfo.starttime;\n\t\tif( timer >= ( postgameMenuInfo.numAwards * AWARD_PRESENTATION_TIME ) ) {\n\n\t\t\tif( timer < 5000 ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tpostgameMenuInfo.phase = 3;\n\t\t\tpostgameMenuInfo.starttime = uis.realtime;\n\t\t}\n\t\telse {\n\t\t\tUI_SPPostgameMenu_DrawAwardsPresentation( timer );\n\t\t}\n\t}\n\n\t// phase 3\n\tif( postgameMenuInfo.phase == 3 ) {\n\t\tif( uis.demoversion ) {\n\t\t\tif( postgameMenuInfo.won == 1 && UI_ShowTierVideo( 8 )) {\n\t\t\t\ttrap_Cvar_Set( \"nextmap\", \"\" );\n\t\t\t\ttrap_Cmd_ExecuteText( EXEC_APPEND, \"disconnect; cinematic demoEnd.RoQ\\n\" );\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\telse if( postgameMenuInfo.won > -1 && UI_ShowTierVideo( postgameMenuInfo.won + 1 )) {\n\t\t\tif( postgameMenuInfo.won == postgameMenuInfo.lastTier ) {\n\t\t\t\ttrap_Cvar_Set( \"nextmap\", \"\" );\n\t\t\t\ttrap_Cmd_ExecuteText( EXEC_APPEND, \"disconnect; cinematic end.RoQ\\n\" );\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\ttrap_Cvar_SetValue( \"ui_spSelection\", postgameMenuInfo.won * ARENAS_PER_TIER );\n\t\t\ttrap_Cvar_Set( \"nextmap\", \"levelselect\" );\n\t\t\ttrap_Cmd_ExecuteText( EXEC_APPEND, va( \"disconnect; cinematic tier%i.RoQ\\n\", postgameMenuInfo.won + 1 ) );\n\t\t\treturn;\n\t\t}\n\n\t\tpostgameMenuInfo.item_again.generic.flags &= ~QMF_INACTIVE;\n\t\tpostgameMenuInfo.item_next.generic.flags &= ~QMF_INACTIVE;\n\t\tpostgameMenuInfo.item_menu.generic.flags &= ~QMF_INACTIVE;\n\n\t\tUI_SPPostgameMenu_DrawAwardsMedals( postgameMenuInfo.numAwards );\n\n\t\tMenu_Draw( &postgameMenuInfo.menu );\n\t}\n\n\t// draw the scoreboard\n\tif( !trap_Cvar_VariableValue( \"ui_spScoreboard\" ) ) {\n\t\treturn;\n\t}\n\n\ttimer = uis.realtime - postgameMenuInfo.scoreboardtime;\n\tif( postgameMenuInfo.numClients <= 3 ) {\n\t\tn = 0;\n\t}\n\telse {\n\t\tn = timer / 1500 % (postgameMenuInfo.numClients + 2);\n\t}\n\tUI_SPPostgameMenu_MenuDrawScoreLine( n, 0 );\n\tUI_SPPostgameMenu_MenuDrawScoreLine( n + 1, 0 + SMALLCHAR_HEIGHT );\n\tUI_SPPostgameMenu_MenuDrawScoreLine( n + 2, 0 + 2 * SMALLCHAR_HEIGHT );\n}\n\n\n/*\n=================\nUI_SPPostgameMenu_Cache\n=================\n*/\nvoid UI_SPPostgameMenu_Cache( void ) {\n\tint\t\t\tn;\n\tqboolean\tbuildscript;\n\n\tbuildscript = trap_Cvar_VariableValue(\"com_buildscript\");\n\n\ttrap_R_RegisterShaderNoMip( ART_MENU0 );\n\ttrap_R_RegisterShaderNoMip( ART_MENU1 );\n\ttrap_R_RegisterShaderNoMip( ART_REPLAY0 );\n\ttrap_R_RegisterShaderNoMip( ART_REPLAY1 );\n\ttrap_R_RegisterShaderNoMip( ART_NEXT0 );\n\ttrap_R_RegisterShaderNoMip( ART_NEXT1 );\n\tfor( n = 0; n < 6; n++ ) {\n\t\ttrap_R_RegisterShaderNoMip( ui_medalPicNames[n] );\n\t\ttrap_S_RegisterSound( ui_medalSounds[n], qfalse );\n\t}\n\n\tif( buildscript ) {\n\t\ttrap_S_RegisterSound( \"music/loss.wav\", qfalse );\n\t\ttrap_S_RegisterSound( \"music/win.wav\", qfalse );\n\t\ttrap_S_RegisterSound( \"sound/player/announce/youwin.wav\", qfalse );\n\t}\n}\n\n\n/*\n=================\nUI_SPPostgameMenu_Init\n=================\n*/\nstatic void UI_SPPostgameMenu_Init( void ) {\n\tpostgameMenuInfo.menu.wrapAround\t= qtrue;\n\tpostgameMenuInfo.menu.key\t\t\t= UI_SPPostgameMenu_MenuKey;\n\tpostgameMenuInfo.menu.draw\t\t\t= UI_SPPostgameMenu_MenuDraw;\n\tpostgameMenuInfo.ignoreKeysTime\t\t= uis.realtime + 1500;\n\n\tUI_SPPostgameMenu_Cache();\n\n\tpostgameMenuInfo.item_menu.generic.type\t\t\t= MTYPE_BITMAP;\n\tpostgameMenuInfo.item_menu.generic.name\t\t\t= ART_MENU0;\n\tpostgameMenuInfo.item_menu.generic.flags\t\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_INACTIVE;\n\tpostgameMenuInfo.item_menu.generic.x\t\t\t= 0;\n\tpostgameMenuInfo.item_menu.generic.y\t\t\t= 480-64;\n\tpostgameMenuInfo.item_menu.generic.callback\t\t= UI_SPPostgameMenu_MenuEvent;\n\tpostgameMenuInfo.item_menu.generic.id\t\t\t= ID_MENU;\n\tpostgameMenuInfo.item_menu.width\t\t\t\t= 128;\n\tpostgameMenuInfo.item_menu.height\t\t\t\t= 64;\n\tpostgameMenuInfo.item_menu.focuspic\t\t\t\t= ART_MENU1;\n\n\tpostgameMenuInfo.item_again.generic.type\t\t= MTYPE_BITMAP;\n\tpostgameMenuInfo.item_again.generic.name\t\t= ART_REPLAY0;\n\tpostgameMenuInfo.item_again.generic.flags\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS|QMF_INACTIVE;\n\tpostgameMenuInfo.item_again.generic.x\t\t\t= 320;\n\tpostgameMenuInfo.item_again.generic.y\t\t\t= 480-64;\n\tpostgameMenuInfo.item_again.generic.callback\t= UI_SPPostgameMenu_AgainEvent;\n\tpostgameMenuInfo.item_again.generic.id\t\t\t= ID_AGAIN;\n\tpostgameMenuInfo.item_again.width\t\t\t\t= 128;\n\tpostgameMenuInfo.item_again.height\t\t\t\t= 64;\n\tpostgameMenuInfo.item_again.focuspic\t\t\t= ART_REPLAY1;\n\n\tpostgameMenuInfo.item_next.generic.type\t\t\t= MTYPE_BITMAP;\n\tpostgameMenuInfo.item_next.generic.name\t\t\t= ART_NEXT0;\n\tpostgameMenuInfo.item_next.generic.flags\t\t= QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_INACTIVE;\n\tpostgameMenuInfo.item_next.generic.x\t\t\t= 640;\n\tpostgameMenuInfo.item_next.generic.y\t\t\t= 480-64;\n\tpostgameMenuInfo.item_next.generic.callback\t\t= UI_SPPostgameMenu_NextEvent;\n\tpostgameMenuInfo.item_next.generic.id\t\t\t= ID_NEXT;\n\tpostgameMenuInfo.item_next.width\t\t\t\t= 128;\n\tpostgameMenuInfo.item_next.height\t\t\t\t= 64;\n\tpostgameMenuInfo.item_next.focuspic\t\t\t\t= ART_NEXT1;\n\n\tMenu_AddItem( &postgameMenuInfo.menu, ( void * )&postgameMenuInfo.item_menu );\n\tMenu_AddItem( &postgameMenuInfo.menu, ( void * )&postgameMenuInfo.item_again );\n\tMenu_AddItem( &postgameMenuInfo.menu, ( void * )&postgameMenuInfo.item_next );\n}\n\n\nstatic void Prepname( int index ) {\n\tint\t\tlen;\n\tchar\tname[64];\n\tchar\tinfo[MAX_INFO_STRING];\n\n\ttrap_GetConfigString( CS_PLAYERS + postgameMenuInfo.clientNums[index], info, MAX_INFO_STRING );\n\tQ_strncpyz( name, Info_ValueForKey( info, \"n\" ), sizeof(name) );\n\tQ_CleanStr( name );\n\tlen = (int)strlen( name );\n\n\twhile( len && UI_ProportionalStringWidth( name ) > 256 ) {\n\t\tlen--;\n\t\tname[len] = 0;\n\t}\n\n\tQ_strncpyz( postgameMenuInfo.placeNames[index], name, sizeof(postgameMenuInfo.placeNames[index]) );\n}\n\n\n/*\n=================\nUI_SPPostgameMenu_f\n=================\n*/\nvoid UI_SPPostgameMenu_f( void ) {\n\tint\t\t\tplayerGameRank;\n\tint\t\t\tplayerClientNum;\n\tint\t\t\tn;\n\tint\t\t\toldFrags, newFrags;\n\tconst char\t*arena;\n\tint\t\t\tawardValues[6];\n\tchar\t\tmap[MAX_QPATH];\n\tchar\t\tinfo[MAX_INFO_STRING];\n\n\tmemset( &postgameMenuInfo, 0, sizeof(postgameMenuInfo) );\n\n\ttrap_GetConfigString( CS_SYSTEMINFO, info, sizeof(info) );\n\tpostgameMenuInfo.serverId = atoi( Info_ValueForKey( info, \"sv_serverid\" ) );\n\n\ttrap_GetConfigString( CS_SERVERINFO, info, sizeof(info) );\n\tQ_strncpyz( map, Info_ValueForKey( info, \"mapname\" ), sizeof(map) );\n\tarena = UI_GetArenaInfoByMap( map );\n\tif ( !arena ) {\n\t\treturn;\n\t}\n\tQ_strncpyz( arenainfo, arena, sizeof(arenainfo) );\n\n\tpostgameMenuInfo.level = atoi( Info_ValueForKey( arenainfo, \"num\" ) );\n\n\tpostgameMenuInfo.numClients = atoi( UI_Argv( 1 ) );\n\tplayerClientNum = atoi( UI_Argv( 2 ) );\n\tplayerGameRank = 8;\t\t// in case they ended game as a spectator\n\n\tif( postgameMenuInfo.numClients > MAX_SCOREBOARD_CLIENTS ) {\n\t\tpostgameMenuInfo.numClients = MAX_SCOREBOARD_CLIENTS;\n\t}\n\n\tfor( n = 0; n < postgameMenuInfo.numClients; n++ ) {\n\t\tpostgameMenuInfo.clientNums[n] = atoi( UI_Argv( 8 + n * 3 + 1 ) );\n\t\tpostgameMenuInfo.ranks[n] = atoi( UI_Argv( 8 + n * 3 + 2 ) );\n\t\tpostgameMenuInfo.scores[n] = atoi( UI_Argv( 8 + n * 3 + 3 ) );\n\n\t\tif( postgameMenuInfo.clientNums[n] == playerClientNum ) {\n\t\t\tplayerGameRank = (postgameMenuInfo.ranks[n] & ~RANK_TIED_FLAG) + 1;\n\t\t}\n\t}\n\n\tUI_SetBestScore( postgameMenuInfo.level, playerGameRank );\n\n\t// process award stats and prepare presentation data\n\tawardValues[AWARD_ACCURACY] = atoi( UI_Argv( 3 ) );\n\tawardValues[AWARD_IMPRESSIVE] = atoi( UI_Argv( 4 ) );\n\tawardValues[AWARD_EXCELLENT] = atoi( UI_Argv( 5 ) );\n\tawardValues[AWARD_GAUNTLET] = atoi( UI_Argv( 6 ) );\n\tawardValues[AWARD_FRAGS] = atoi( UI_Argv( 7 ) );\n\tawardValues[AWARD_PERFECT] = atoi( UI_Argv( 8 ) );\n\n\tpostgameMenuInfo.numAwards = 0;\n\n\tif( awardValues[AWARD_ACCURACY] >= 50 ) {\n\t\tUI_LogAwardData( AWARD_ACCURACY, 1 );\n\t\tpostgameMenuInfo.awardsEarned[postgameMenuInfo.numAwards] = AWARD_ACCURACY;\n\t\tpostgameMenuInfo.awardsLevels[postgameMenuInfo.numAwards] = awardValues[AWARD_ACCURACY];\n\t\tpostgameMenuInfo.numAwards++;\n\t}\n\n\tif( awardValues[AWARD_IMPRESSIVE] ) {\n\t\tUI_LogAwardData( AWARD_IMPRESSIVE, awardValues[AWARD_IMPRESSIVE] );\n\t\tpostgameMenuInfo.awardsEarned[postgameMenuInfo.numAwards] = AWARD_IMPRESSIVE;\n\t\tpostgameMenuInfo.awardsLevels[postgameMenuInfo.numAwards] = awardValues[AWARD_IMPRESSIVE];\n\t\tpostgameMenuInfo.numAwards++;\n\t}\n\n\tif( awardValues[AWARD_EXCELLENT] ) {\n\t\tUI_LogAwardData( AWARD_EXCELLENT, awardValues[AWARD_EXCELLENT] );\n\t\tpostgameMenuInfo.awardsEarned[postgameMenuInfo.numAwards] = AWARD_EXCELLENT;\n\t\tpostgameMenuInfo.awardsLevels[postgameMenuInfo.numAwards] = awardValues[AWARD_EXCELLENT];\n\t\tpostgameMenuInfo.numAwards++;\n\t}\n\n\tif( awardValues[AWARD_GAUNTLET] ) {\n\t\tUI_LogAwardData( AWARD_GAUNTLET, awardValues[AWARD_GAUNTLET] );\n\t\tpostgameMenuInfo.awardsEarned[postgameMenuInfo.numAwards] = AWARD_GAUNTLET;\n\t\tpostgameMenuInfo.awardsLevels[postgameMenuInfo.numAwards] = awardValues[AWARD_GAUNTLET];\n\t\tpostgameMenuInfo.numAwards++;\n\t}\n\n\toldFrags = UI_GetAwardLevel( AWARD_FRAGS ) / 100;\n\tUI_LogAwardData( AWARD_FRAGS, awardValues[AWARD_FRAGS] );\n\tnewFrags = UI_GetAwardLevel( AWARD_FRAGS ) / 100;\n\tif( newFrags > oldFrags ) {\n\t\tpostgameMenuInfo.awardsEarned[postgameMenuInfo.numAwards] = AWARD_FRAGS;\n\t\tpostgameMenuInfo.awardsLevels[postgameMenuInfo.numAwards] = newFrags * 100;\n\t\tpostgameMenuInfo.numAwards++;\n\t}\n\n\tif( awardValues[AWARD_PERFECT] ) {\n\t\tUI_LogAwardData( AWARD_PERFECT, 1 );\n\t\tpostgameMenuInfo.awardsEarned[postgameMenuInfo.numAwards] = AWARD_PERFECT;\n\t\tpostgameMenuInfo.awardsLevels[postgameMenuInfo.numAwards] = 1;\n\t\tpostgameMenuInfo.numAwards++;\n\t}\n\n\tif ( playerGameRank == 1 ) {\n\t\tpostgameMenuInfo.won = UI_TierCompleted( postgameMenuInfo.level );\n\t}\n\telse {\n\t\tpostgameMenuInfo.won = -1;\n\t}\n\n\tpostgameMenuInfo.starttime = uis.realtime;\n\tpostgameMenuInfo.scoreboardtime = uis.realtime;\n\n\ttrap_Key_SetCatcher( KEYCATCH_UI );\n\tuis.menusp = 0;\n\n\tUI_SPPostgameMenu_Init();\n\tUI_PushMenu( &postgameMenuInfo.menu );\n\n\tif ( playerGameRank == 1 ) {\n\t\tMenu_SetCursorToItem( &postgameMenuInfo.menu, &postgameMenuInfo.item_next );\n\t}\n\telse {\n\t\tMenu_SetCursorToItem( &postgameMenuInfo.menu, &postgameMenuInfo.item_again );\n\t}\n\n\tPrepname( 0 );\n\tPrepname( 1 );\n\tPrepname( 2 );\n\n\tif ( playerGameRank != 1 ) {\n\t\tpostgameMenuInfo.winnerSound = trap_S_RegisterSound( va( \"sound/player/announce/%s_wins.wav\", postgameMenuInfo.placeNames[0] ), qfalse );\n\t\ttrap_Cmd_ExecuteText( EXEC_APPEND, \"music music/loss\\n\" );\n\t}\n\telse {\n\t\tpostgameMenuInfo.winnerSound = trap_S_RegisterSound( \"sound/player/announce/youwin.wav\", qfalse );\n\t\ttrap_Cmd_ExecuteText( EXEC_APPEND, \"music music/win\\n\" );\n\t}\n\n\tpostgameMenuInfo.phase = 1;\n\n\tpostgameMenuInfo.lastTier = UI_GetNumSPTiers();\n\tif ( UI_GetSpecialArenaInfo( \"final\" ) ) {\n\t\tpostgameMenuInfo.lastTier++;\n\t}\n}\n"
  },
  {
    "path": "src/q3_ui/ui_spreset.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n/*\n=======================================================================\n\nRESET MENU\n\n=======================================================================\n*/\n\n#include \"ui_local.h\"\n\n\n#define ART_FRAME\t\t\t\t\t\"menu/art/cut_frame\"\n\n#define ID_NO\t\t100\n#define ID_YES\t\t101\n\ntypedef struct\n{\n\tmenuframework_s menu;\n\tmenutext_s\t\tno;\n\tmenutext_s\t\tyes;\n\tint\t\t\t\tslashX;\n} resetMenu_t;\n\nstatic resetMenu_t\ts_reset;\n\n\n/*\n=================\nReset_MenuEvent\n=================\n*/\nvoid Reset_MenuEvent(void* ptr, int event) {\n\tif( event != QM_ACTIVATED ) {\n\t\treturn;\n\t}\n\n\tUI_PopMenu();\n\n\tif( ((menucommon_s*)ptr)->id == ID_NO ) {\n\t\treturn;\n\t}\n\n\t// reset the game, pop the level menu and restart it so it updates\n\tUI_NewGame();\n\ttrap_Cvar_SetValue( \"ui_spSelection\", 0 );\n\tUI_PopMenu();\n\tUI_SPLevelMenu();\n}\n\n\n/*\n=================\nReset_MenuKey\n=================\n*/\nstatic sfxHandle_t Reset_MenuKey( int key ) {\n\tswitch ( key ) {\n\tcase K_KP_LEFTARROW:\n\tcase K_LEFTARROW:\n\tcase K_KP_RIGHTARROW:\n\tcase K_RIGHTARROW:\n\t\tkey = K_TAB;\n\t\tbreak;\n\n\tcase 'n':\n\tcase 'N':\n\t\tReset_MenuEvent( &s_reset.no, QM_ACTIVATED );\n\t\tbreak;\n\n\tcase 'y':\n\tcase 'Y':\n\t\tReset_MenuEvent( &s_reset.yes, QM_ACTIVATED );\n\t\tbreak;\n\t}\n\n\treturn Menu_DefaultKey( &s_reset.menu, key );\n}\n\n\n/*\n=================\nReset_MenuDraw\n=================\n*/\nstatic void Reset_MenuDraw( void ) {\n\tUI_DrawNamedPic( 142, 118, 359, 256, ART_FRAME );\n\tUI_DrawProportionalString( 320, 194 + 10, \"RESET GAME?\", UI_CENTER|UI_INVERSE, color_red );\n\tUI_DrawProportionalString( s_reset.slashX, 265, \"/\", UI_LEFT|UI_INVERSE, color_red );\n\tMenu_Draw( &s_reset.menu );\n\n\tUI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 0, \"WARNING: This resets all of the\", UI_CENTER|UI_SMALLFONT, color_yellow );\n\tUI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 1, \"single player game variables.\", UI_CENTER|UI_SMALLFONT, color_yellow );\n\tUI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 2, \"Do this only if you want to\", UI_CENTER|UI_SMALLFONT, color_yellow );\n\tUI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 3, \"start over from the beginning.\", UI_CENTER|UI_SMALLFONT, color_yellow );\n}\n\n\n/*\n=================\nReset_Cache\n=================\n*/\nvoid Reset_Cache( void ) {\n\ttrap_R_RegisterShaderNoMip( ART_FRAME );\n}\n\n\n/*\n=================\nUI_ResetMenu\n=================\n*/\nvoid UI_ResetMenu(void) {\n\tuiClientState_t\tcstate;\n\tint\tn1, n2, n3;\n\tint\tl1, l2, l3;\n\n\t// zero set all our globals\n\tmemset( &s_reset, 0, sizeof(s_reset) );\n\n\tReset_Cache();\n\n\tn1 = UI_ProportionalStringWidth( \"YES/NO\" );\n\tn2 = UI_ProportionalStringWidth( \"YES\" ) + PROP_GAP_WIDTH;\n\tn3 = UI_ProportionalStringWidth( \"/\" )  + PROP_GAP_WIDTH;\n\tl1 = 320 - ( n1 / 2 );\n\tl2 = l1 + n2;\n\tl3 = l2 + n3;\n\ts_reset.slashX = l2;\n\n\ts_reset.menu.draw       = Reset_MenuDraw;\n\ts_reset.menu.key        = Reset_MenuKey;\n\ts_reset.menu.wrapAround = qtrue;\n\n\ttrap_GetClientState( &cstate );\n\n\tif ( cstate.connState >= CA_CONNECTED ) {\n\t\t// float on top of running game\n\t\ts_reset.menu.fullscreen = qfalse;\n\t}\n\telse {\n\t\t// game not running\n\t\ts_reset.menu.fullscreen = qtrue;\n\t}\n\n\ts_reset.yes.generic.type\t\t= MTYPE_PTEXT;      \n\ts_reset.yes.generic.flags\t\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; \n\ts_reset.yes.generic.callback\t= Reset_MenuEvent;\n\ts_reset.yes.generic.id\t\t\t= ID_YES;\n\ts_reset.yes.generic.x\t\t\t= l1;\n\ts_reset.yes.generic.y\t\t\t= 264;\n\ts_reset.yes.string\t\t\t\t= \"YES\";\n\ts_reset.yes.color\t\t\t\t= color_red;\n\ts_reset.yes.style\t\t\t\t= UI_LEFT;\n\n\ts_reset.no.generic.type\t\t\t= MTYPE_PTEXT;      \n\ts_reset.no.generic.flags\t\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; \n\ts_reset.no.generic.callback\t\t= Reset_MenuEvent;\n\ts_reset.no.generic.id\t\t\t= ID_NO;\n\ts_reset.no.generic.x\t\t    = l3;\n\ts_reset.no.generic.y\t\t    = 264;\n\ts_reset.no.string\t\t\t\t= \"NO\";\n\ts_reset.no.color\t\t\t    = color_red;\n\ts_reset.no.style\t\t\t    = UI_LEFT;\n\n\tMenu_AddItem( &s_reset.menu,\t&s_reset.yes );             \n\tMenu_AddItem( &s_reset.menu,\t&s_reset.no );\n\n\tUI_PushMenu( &s_reset.menu );\n\n\tMenu_SetCursorToItem( &s_reset.menu, &s_reset.no );\n}\n"
  },
  {
    "path": "src/q3_ui/ui_spskill.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n/*\n=============================================================================\n\nSINGLE PLAYER SKILL MENU\n\n=============================================================================\n*/\n\n#include \"ui_local.h\"\n\n\n#define ART_FRAME\t\t\t\t\t\"menu/art/cut_frame\"\n#define ART_BACK\t\t\t\t\t\"menu/art/back_0.tga\"\n#define ART_BACK_FOCUS\t\t\t\t\"menu/art/back_1.tga\"\n#define ART_FIGHT\t\t\t\t\t\"menu/art/fight_0\"\n#define ART_FIGHT_FOCUS\t\t\t\t\"menu/art/fight_1\"\n#define ART_MAP_COMPLETE1\t\t\t\"menu/art/level_complete1\"\n#define ART_MAP_COMPLETE2\t\t\t\"menu/art/level_complete2\"\n#define ART_MAP_COMPLETE3\t\t\t\"menu/art/level_complete3\"\n#define ART_MAP_COMPLETE4\t\t\t\"menu/art/level_complete4\"\n#define ART_MAP_COMPLETE5\t\t\t\"menu/art/level_complete5\"\n\n#define ID_BABY\t\t\t\t\t\t10\n#define ID_EASY\t\t\t\t\t\t11\n#define ID_MEDIUM\t\t\t\t\t12\n#define ID_HARD\t\t\t\t\t\t13\n#define ID_NIGHTMARE\t\t\t\t14\n#define ID_BACK\t\t\t\t\t\t15\n#define ID_FIGHT\t\t\t\t\t16\n\n\ntypedef struct {\n\tmenuframework_s\tmenu;\n\n\tmenubitmap_s\tart_frame;\n\tmenutext_s\t\tart_banner;\n\n\tmenutext_s\t\titem_baby;\n\tmenutext_s\t\titem_easy;\n\tmenutext_s\t\titem_medium;\n\tmenutext_s\t\titem_hard;\n\tmenutext_s\t\titem_nightmare;\n\n\tmenubitmap_s\tart_skillPic;\n\tmenubitmap_s\titem_back;\n\tmenubitmap_s\titem_fight;\n\n\tconst char\t\t*arenaInfo;\n\tqhandle_t\t\tskillpics[5];\n\tsfxHandle_t\t\tnightmareSound;\n\tsfxHandle_t\t\tsilenceSound;\n} skillMenuInfo_t;\n\nstatic skillMenuInfo_t\tskillMenuInfo;\n\n\nstatic void SetSkillColor( int skill, vec4_t color ) {\n\tswitch( skill ) {\n\tcase 1:\n\t\tskillMenuInfo.item_baby.color = color;\n\t\tbreak;\n\tcase 2:\n\t\tskillMenuInfo.item_easy.color = color;\n\t\tbreak;\n\tcase 3:\n\t\tskillMenuInfo.item_medium.color = color;\n\t\tbreak;\n\tcase 4:\n\t\tskillMenuInfo.item_hard.color = color;\n\t\tbreak;\n\tcase 5:\n\t\tskillMenuInfo.item_nightmare.color = color;\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n}\n\n\n/*\n=================\nUI_SPSkillMenu_SkillEvent\n=================\n*/\nstatic void UI_SPSkillMenu_SkillEvent( void *ptr, int notification ) {\n\tint\t\tid;\n\tint\t\tskill;\n\n\tif (notification != QM_ACTIVATED)\n\t\treturn;\n\n\tSetSkillColor( (int)trap_Cvar_VariableValue( \"g_spSkill\" ), color_red );\n\n\tid = ((menucommon_s*)ptr)->id;\n\tskill = id - ID_BABY + 1;\n\ttrap_Cvar_SetValue( \"g_spSkill\", skill );\n\n\tSetSkillColor( skill, color_white );\n\tskillMenuInfo.art_skillPic.shader = skillMenuInfo.skillpics[skill - 1];\n\n\tif( id == ID_NIGHTMARE ) {\n\t\ttrap_S_StartLocalSound( skillMenuInfo.nightmareSound, CHAN_ANNOUNCER );\n\t}\n\telse {\n\t\ttrap_S_StartLocalSound( skillMenuInfo.silenceSound, CHAN_ANNOUNCER );\n\t}\n}\n\n\n/*\n=================\nUI_SPSkillMenu_FightEvent\n=================\n*/\nstatic void UI_SPSkillMenu_FightEvent( void *ptr, int notification ) {\n\tif (notification != QM_ACTIVATED)\n\t\treturn;\n\n\tUI_SPArena_Start( skillMenuInfo.arenaInfo );\n}\n\n\n/*\n=================\nUI_SPSkillMenu_BackEvent\n=================\n*/\nstatic void UI_SPSkillMenu_BackEvent( void* ptr, int notification ) {\n\tif (notification != QM_ACTIVATED) {\n\t\treturn;\n\t}\n\n\ttrap_S_StartLocalSound( skillMenuInfo.silenceSound, CHAN_ANNOUNCER );\n\tUI_PopMenu();\n}\n\n\n/*\n=================\nUI_SPSkillMenu_Key\n=================\n*/\nstatic sfxHandle_t UI_SPSkillMenu_Key( int key ) {\n\tif( key == K_MOUSE2 || key == K_ESCAPE ) {\n\t\ttrap_S_StartLocalSound( skillMenuInfo.silenceSound, CHAN_ANNOUNCER );\n\t}\n\treturn Menu_DefaultKey( &skillMenuInfo.menu, key );\n}\n\n\n/*\n=================\nUI_SPSkillMenu_Cache\n=================\n*/\nvoid UI_SPSkillMenu_Cache( void ) {\n\ttrap_R_RegisterShaderNoMip( ART_FRAME );\n\ttrap_R_RegisterShaderNoMip( ART_BACK );\n\ttrap_R_RegisterShaderNoMip( ART_BACK_FOCUS );\n\ttrap_R_RegisterShaderNoMip( ART_FIGHT );\n\ttrap_R_RegisterShaderNoMip( ART_FIGHT_FOCUS );\n\tskillMenuInfo.skillpics[0] = trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE1 );\n\tskillMenuInfo.skillpics[1] = trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE2 );\n\tskillMenuInfo.skillpics[2] = trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE3 );\n\tskillMenuInfo.skillpics[3] = trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE4 );\n\tskillMenuInfo.skillpics[4] = trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE5 );\n\n\tskillMenuInfo.nightmareSound = trap_S_RegisterSound( \"sound/misc/nightmare.wav\", qfalse );\n\tskillMenuInfo.silenceSound = trap_S_RegisterSound( \"sound/misc/silence.wav\", qfalse );\n}\n\n\n/*\n=================\nUI_SPSkillMenu_Init\n=================\n*/\nstatic void UI_SPSkillMenu_Init( void ) {\n\tint\t\tskill;\n\n\tmemset( &skillMenuInfo, 0, sizeof(skillMenuInfo) );\n\tskillMenuInfo.menu.fullscreen = qtrue;\n\tskillMenuInfo.menu.key = UI_SPSkillMenu_Key;\n\n\tUI_SPSkillMenu_Cache();\n\n\tskillMenuInfo.art_frame.generic.type\t\t= MTYPE_BITMAP;\n\tskillMenuInfo.art_frame.generic.name\t\t= ART_FRAME;\n\tskillMenuInfo.art_frame.generic.flags\t\t= QMF_LEFT_JUSTIFY|QMF_INACTIVE;\n\tskillMenuInfo.art_frame.generic.x\t\t\t= 142;\n\tskillMenuInfo.art_frame.generic.y\t\t\t= 118;\n\tskillMenuInfo.art_frame.width\t\t\t\t= 359;\n\tskillMenuInfo.art_frame.height\t\t\t\t= 256;\n\n\tskillMenuInfo.art_banner.generic.type\t\t= MTYPE_BTEXT;\n\tskillMenuInfo.art_banner.generic.flags\t\t= QMF_CENTER_JUSTIFY;\n\tskillMenuInfo.art_banner.generic.x\t\t\t= 320;\n\tskillMenuInfo.art_banner.generic.y\t\t\t= 16;\n\tskillMenuInfo.art_banner.string\t\t\t\t= \"DIFFICULTY\";\n\tskillMenuInfo.art_banner.color\t\t\t\t= color_white;\n\tskillMenuInfo.art_banner.style\t\t\t\t= UI_CENTER;\n\n\tskillMenuInfo.item_baby.generic.type\t\t= MTYPE_PTEXT;\n\tskillMenuInfo.item_baby.generic.flags\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\tskillMenuInfo.item_baby.generic.x\t\t\t= 320;\n\tskillMenuInfo.item_baby.generic.y\t\t\t= 170;\n\tskillMenuInfo.item_baby.generic.callback\t= UI_SPSkillMenu_SkillEvent;\n\tskillMenuInfo.item_baby.generic.id\t\t\t= ID_BABY;\n\tskillMenuInfo.item_baby.string\t\t\t\t= \"I Can Win\";\n\tskillMenuInfo.item_baby.color\t\t\t\t= color_red;\n\tskillMenuInfo.item_baby.style\t\t\t\t= UI_CENTER;\n\n\tskillMenuInfo.item_easy.generic.type\t\t= MTYPE_PTEXT;\n\tskillMenuInfo.item_easy.generic.flags\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\tskillMenuInfo.item_easy.generic.x\t\t\t= 320;\n\tskillMenuInfo.item_easy.generic.y\t\t\t= 198;\n\tskillMenuInfo.item_easy.generic.callback\t= UI_SPSkillMenu_SkillEvent;\n\tskillMenuInfo.item_easy.generic.id\t\t\t= ID_EASY;\n\tskillMenuInfo.item_easy.string\t\t\t\t= \"Bring It On\";\n\tskillMenuInfo.item_easy.color\t\t\t\t= color_red;\n\tskillMenuInfo.item_easy.style\t\t\t\t= UI_CENTER;\n\n\tskillMenuInfo.item_medium.generic.type\t\t= MTYPE_PTEXT;\n\tskillMenuInfo.item_medium.generic.flags\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\tskillMenuInfo.item_medium.generic.x\t\t\t= 320;\n\tskillMenuInfo.item_medium.generic.y\t\t\t= 227;\n\tskillMenuInfo.item_medium.generic.callback\t= UI_SPSkillMenu_SkillEvent;\n\tskillMenuInfo.item_medium.generic.id\t\t= ID_MEDIUM;\n\tskillMenuInfo.item_medium.string\t\t\t= \"Hurt Me Plenty\";\n\tskillMenuInfo.item_medium.color\t\t\t\t= color_red;\n\tskillMenuInfo.item_medium.style\t\t\t\t= UI_CENTER;\n\n\tskillMenuInfo.item_hard.generic.type\t\t= MTYPE_PTEXT;\n\tskillMenuInfo.item_hard.generic.flags\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\tskillMenuInfo.item_hard.generic.x\t\t\t= 320;\n\tskillMenuInfo.item_hard.generic.y\t\t\t= 255;\n\tskillMenuInfo.item_hard.generic.callback\t= UI_SPSkillMenu_SkillEvent;\n\tskillMenuInfo.item_hard.generic.id\t\t\t= ID_HARD;\n\tskillMenuInfo.item_hard.string\t\t\t\t= \"Hardcore\";\n\tskillMenuInfo.item_hard.color\t\t\t\t= color_red;\n\tskillMenuInfo.item_hard.style\t\t\t\t= UI_CENTER;\n\n\tskillMenuInfo.item_nightmare.generic.type\t\t= MTYPE_PTEXT;\n\tskillMenuInfo.item_nightmare.generic.flags\t\t= QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\tskillMenuInfo.item_nightmare.generic.x\t\t\t= 320;\n\tskillMenuInfo.item_nightmare.generic.y\t\t\t= 283;\n\tskillMenuInfo.item_nightmare.generic.callback\t= UI_SPSkillMenu_SkillEvent;\n\tskillMenuInfo.item_nightmare.generic.id\t\t\t= ID_NIGHTMARE;\n\tskillMenuInfo.item_nightmare.string\t\t\t\t= \"NIGHTMARE!\";\n\tskillMenuInfo.item_nightmare.color\t\t\t\t= color_red;\n\tskillMenuInfo.item_nightmare.style\t\t\t\t= UI_CENTER;\n\n\tskillMenuInfo.item_back.generic.type\t\t= MTYPE_BITMAP;\n\tskillMenuInfo.item_back.generic.name\t\t= ART_BACK;\n\tskillMenuInfo.item_back.generic.flags\t\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\tskillMenuInfo.item_back.generic.x\t\t\t= 0;\n\tskillMenuInfo.item_back.generic.y\t\t\t= 480-64;\n\tskillMenuInfo.item_back.generic.callback\t= UI_SPSkillMenu_BackEvent;\n\tskillMenuInfo.item_back.generic.id\t\t\t= ID_BACK;\n\tskillMenuInfo.item_back.width\t\t\t\t= 128;\n\tskillMenuInfo.item_back.height\t\t\t\t= 64;\n\tskillMenuInfo.item_back.focuspic\t\t\t= ART_BACK_FOCUS;\n\n\tskillMenuInfo.art_skillPic.generic.type\t\t= MTYPE_BITMAP;\n\tskillMenuInfo.art_skillPic.generic.flags\t= QMF_LEFT_JUSTIFY|QMF_INACTIVE;\n\tskillMenuInfo.art_skillPic.generic.x\t\t= 320-64;\n\tskillMenuInfo.art_skillPic.generic.y\t\t= 368;\n\tskillMenuInfo.art_skillPic.width\t\t\t= 128;\n\tskillMenuInfo.art_skillPic.height\t\t\t= 96;\n\n\tskillMenuInfo.item_fight.generic.type\t\t= MTYPE_BITMAP;\n\tskillMenuInfo.item_fight.generic.name\t\t= ART_FIGHT;\n\tskillMenuInfo.item_fight.generic.flags\t\t= QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;\n\tskillMenuInfo.item_fight.generic.callback\t= UI_SPSkillMenu_FightEvent;\n\tskillMenuInfo.item_fight.generic.id\t\t\t= ID_FIGHT;\n\tskillMenuInfo.item_fight.generic.x\t\t\t= 640;\n\tskillMenuInfo.item_fight.generic.y\t\t\t= 480-64;\n\tskillMenuInfo.item_fight.width\t\t\t\t= 128;\n\tskillMenuInfo.item_fight.height\t\t\t\t= 64;\n\tskillMenuInfo.item_fight.focuspic\t\t\t= ART_FIGHT_FOCUS;\n\n\tMenu_AddItem( &skillMenuInfo.menu, ( void * )&skillMenuInfo.art_frame );\n\tMenu_AddItem( &skillMenuInfo.menu, ( void * )&skillMenuInfo.art_banner );\n\tMenu_AddItem( &skillMenuInfo.menu, ( void * )&skillMenuInfo.item_baby );\n\tMenu_AddItem( &skillMenuInfo.menu, ( void * )&skillMenuInfo.item_easy );\n\tMenu_AddItem( &skillMenuInfo.menu, ( void * )&skillMenuInfo.item_medium );\n\tMenu_AddItem( &skillMenuInfo.menu, ( void * )&skillMenuInfo.item_hard );\n\tMenu_AddItem( &skillMenuInfo.menu, ( void * )&skillMenuInfo.item_nightmare );\n\tMenu_AddItem( &skillMenuInfo.menu, ( void * )&skillMenuInfo.art_skillPic );\n\tMenu_AddItem( &skillMenuInfo.menu, ( void * )&skillMenuInfo.item_back );\n\tMenu_AddItem( &skillMenuInfo.menu, ( void * )&skillMenuInfo.item_fight );\n\n\tskill = (int)Com_Clamp( 1, 5, trap_Cvar_VariableValue( \"g_spSkill\" ) );\n\tSetSkillColor( skill, color_white );\n\tskillMenuInfo.art_skillPic.shader = skillMenuInfo.skillpics[skill - 1];\n\tif( skill == 5 ) {\n\t\ttrap_S_StartLocalSound( skillMenuInfo.nightmareSound, CHAN_ANNOUNCER );\n\t}\n}\n\n\nvoid UI_SPSkillMenu( const char *arenaInfo ) {\n\tUI_SPSkillMenu_Init();\n\tskillMenuInfo.arenaInfo = arenaInfo;\n\tUI_PushMenu( &skillMenuInfo.menu );\n\tMenu_SetCursorToItem( &skillMenuInfo.menu, &skillMenuInfo.item_fight );\n}\n"
  },
  {
    "path": "src/q3_ui/ui_startserver.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n/*\n=============================================================================\n\nSTART SERVER MENU *****\n\n=============================================================================\n*/\n\n\n#include \"ui_local.h\"\n\n\n#define GAMESERVER_BACK0\t\t\"menu/art/back_0\"\n#define GAMESERVER_BACK1\t\t\"menu/art/back_1\"\n#define GAMESERVER_NEXT0\t\t\"menu/art/next_0\"\n#define GAMESERVER_NEXT1\t\t\"menu/art/next_1\"\n#define GAMESERVER_FRAMEL\t\t\"menu/art/frame2_l\"\n#define GAMESERVER_FRAMER\t\t\"menu/art/frame1_r\"\n#define GAMESERVER_SELECT\t\t\"menu/art/maps_select\"\n#define GAMESERVER_SELECTED\t\t\"menu/art/maps_selected\"\n#define GAMESERVER_FIGHT0\t\t\"menu/art/fight_0\"\n#define GAMESERVER_FIGHT1\t\t\"menu/art/fight_1\"\n#define GAMESERVER_UNKNOWNMAP\t\"menu/art/unknownmap\"\n#define GAMESERVER_ARROWS\t\t\"menu/art/gs_arrows_0\"\n#define GAMESERVER_ARROWSL\t\t\"menu/art/gs_arrows_l\"\n#define GAMESERVER_ARROWSR\t\t\"menu/art/gs_arrows_r\"\n\n#define MAX_MAPROWS\t\t2\n#define MAX_MAPCOLS\t\t2\n#define MAX_MAPSPERPAGE\t4\n\n#define\tMAX_SERVERSTEXT\t8192\n\n#define MAX_SERVERMAPS\t64\n#define MAX_NAMELENGTH\t16\n\n#define ID_GAMETYPE\t\t\t\t10\n#define ID_PICTURES\t\t\t\t11\t// 12, 13, 14\n#define ID_PREVPAGE\t\t\t\t15\n#define ID_NEXTPAGE\t\t\t\t16\n#define ID_STARTSERVERBACK\t\t17\n#define ID_STARTSERVERNEXT\t\t18\n\ntypedef struct {\n\tmenuframework_s\tmenu;\n\n\tmenutext_s\t\tbanner;\n\tmenubitmap_s\tframel;\n\tmenubitmap_s\tframer;\n\n\tmenulist_s\t\tgametype;\n\tmenubitmap_s\tmappics[MAX_MAPSPERPAGE];\n\tmenubitmap_s\tmapbuttons[MAX_MAPSPERPAGE];\n\tmenubitmap_s\tarrows;\n\tmenubitmap_s\tprevpage;\n\tmenubitmap_s\tnextpage;\n\tmenubitmap_s\tback;\n\tmenubitmap_s\tnext;\n\n\tmenutext_s\t\tmapname;\n\tmenubitmap_s\titem_null;\n\n\tqboolean\t\tmultiplayer;\n\tint\t\t\t\tcurrentmap;\n\tint\t\t\t\tnummaps;\n\tint\t\t\t\tpage;\n\tint\t\t\t\tmaxpages;\n\tchar\t\t\tmaplist[MAX_SERVERMAPS][MAX_NAMELENGTH];\n\tint\t\t\t\tmapGamebits[MAX_SERVERMAPS];\n} startserver_t;\n\nstatic startserver_t s_startserver;\n\nstatic const char *gametype_items[] = {\n\t\"Free For All\",\n\t\"Team Deathmatch\",\n\t\"Tournament\",\n\t\"Capture the Flag\",\n\t0\n};\n\nstatic int gametype_remap[] = {GT_FFA, GT_TEAM, GT_TOURNAMENT, GT_CTF};\nstatic int gametype_remap2[] = {0, 2, 0, 1, 3};\n\n// use ui_servers2.c definition\nextern const char* punkbuster_items[];\n\nstatic void UI_ServerOptionsMenu( qboolean multiplayer );\n\n\n/*\n=================\nGametypeBits\n=================\n*/\nstatic int GametypeBits( char *string ) {\n\tint\t\tbits;\n\tchar\t*p;\n\tchar\t*token;\n\n\tbits = 0;\n\tp = string;\n\twhile( 1 ) {\n\t\ttoken = COM_ParseExt( &p, qfalse );\n\t\tif( token[0] == 0 ) {\n\t\t\tbreak;\n\t\t}\n\n\t\tif( Q_stricmp( token, \"ffa\" ) == 0 ) {\n\t\t\tbits |= 1 << GT_FFA;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif( Q_stricmp( token, \"tourney\" ) == 0 ) {\n\t\t\tbits |= 1 << GT_TOURNAMENT;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif( Q_stricmp( token, \"single\" ) == 0 ) {\n\t\t\tbits |= 1 << GT_SINGLE_PLAYER;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif( Q_stricmp( token, \"team\" ) == 0 ) {\n\t\t\tbits |= 1 << GT_TEAM;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif( Q_stricmp( token, \"ctf\" ) == 0 ) {\n\t\t\tbits |= 1 << GT_CTF;\n\t\t\tcontinue;\n\t\t}\n\t}\n\n\treturn bits;\n}\n\n\n/*\n=================\nStartServer_Update\n=================\n*/\nstatic void StartServer_Update( void ) {\n\tint\t\t\t\ti;\n\tint\t\t\t\ttop;\n\tstatic\tchar\tpicname[MAX_MAPSPERPAGE][64];\n\n\ttop = s_startserver.page*MAX_MAPSPERPAGE;\n\n\tfor (i=0; i<MAX_MAPSPERPAGE; i++)\n\t{\n\t\tif (top+i >= s_startserver.nummaps)\n\t\t\tbreak;\n\n\t\tCom_sprintf( picname[i], sizeof(picname[i]), \"levelshots/%s\", s_startserver.maplist[top+i] );\n\n\t\ts_startserver.mappics[i].generic.flags &= ~QMF_HIGHLIGHT;\n\t\ts_startserver.mappics[i].generic.name   = picname[i];\n\t\ts_startserver.mappics[i].shader         = 0;\n\n\t\t// reset\n\t\ts_startserver.mapbuttons[i].generic.flags |= QMF_PULSEIFFOCUS;\n\t\ts_startserver.mapbuttons[i].generic.flags &= ~QMF_INACTIVE;\n\t}\n\n\tfor (; i<MAX_MAPSPERPAGE; i++)\n\t{\n\t\ts_startserver.mappics[i].generic.flags &= ~QMF_HIGHLIGHT;\n\t\ts_startserver.mappics[i].generic.name   = NULL;\n\t\ts_startserver.mappics[i].shader         = 0;\n\n\t\t// disable\n\t\ts_startserver.mapbuttons[i].generic.flags &= ~QMF_PULSEIFFOCUS;\n\t\ts_startserver.mapbuttons[i].generic.flags |= QMF_INACTIVE;\n\t}\n\n\n\t// no servers to start\n\tif( !s_startserver.nummaps ) {\n\t\ts_startserver.next.generic.flags |= QMF_INACTIVE;\n\n\t\t// set the map name\n\t\tstrcpy( s_startserver.mapname.string, \"NO MAPS FOUND\" );\n\t}\n\telse {\n\t\t// set the highlight\n\t\ts_startserver.next.generic.flags &= ~QMF_INACTIVE;\n\t\ti = s_startserver.currentmap - top;\n\t\tif ( i >=0 && i < MAX_MAPSPERPAGE ) \n\t\t{\n\t\t\ts_startserver.mappics[i].generic.flags    |= QMF_HIGHLIGHT;\n\t\t\ts_startserver.mapbuttons[i].generic.flags &= ~QMF_PULSEIFFOCUS;\n\t\t}\n\n\t\t// set the map name\n\t\tstrcpy( s_startserver.mapname.string, s_startserver.maplist[s_startserver.currentmap] );\n\t}\n\t\n\tQ_strupr( s_startserver.mapname.string );\n}\n\n\n/*\n=================\nStartServer_MapEvent\n=================\n*/\nstatic void StartServer_MapEvent( void* ptr, int event ) {\n\tif( event != QM_ACTIVATED) {\n\t\treturn;\n\t}\n\n\ts_startserver.currentmap = (s_startserver.page*MAX_MAPSPERPAGE) + (((menucommon_s*)ptr)->id - ID_PICTURES);\n\tStartServer_Update();\n}\n\n\n/*\n=================\nStartServer_GametypeEvent\n=================\n*/\nstatic void StartServer_GametypeEvent( void* ptr, int event ) {\n\tint\t\t\ti;\n\tint\t\t\tcount;\n\tint\t\t\tgamebits;\n\tint\t\t\tmatchbits;\n\tconst char\t*info;\n\n\tif( event != QM_ACTIVATED) {\n\t\treturn;\n\t}\n\n\tcount = UI_GetNumArenas();\n\ts_startserver.nummaps = 0;\n\tmatchbits = 1 << gametype_remap[s_startserver.gametype.curvalue];\n\tif( gametype_remap[s_startserver.gametype.curvalue] == GT_FFA ) {\n\t\tmatchbits |= ( 1 << GT_SINGLE_PLAYER );\n\t}\n\tfor( i = 0; i < count; i++ ) {\n\t\tinfo = UI_GetArenaInfoByNumber( i );\n\n\t\tgamebits = GametypeBits( Info_ValueForKey( info, \"type\") );\n\t\tif( !( gamebits & matchbits ) ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tQ_strncpyz( s_startserver.maplist[s_startserver.nummaps], Info_ValueForKey( info, \"map\"), MAX_NAMELENGTH );\n\t\tQ_strupr( s_startserver.maplist[s_startserver.nummaps] );\n\t\ts_startserver.mapGamebits[s_startserver.nummaps] = gamebits;\n\t\ts_startserver.nummaps++;\n\t}\n\ts_startserver.maxpages = (s_startserver.nummaps + MAX_MAPSPERPAGE-1)/MAX_MAPSPERPAGE;\n\ts_startserver.page = 0;\n\ts_startserver.currentmap = 0;\n\n\tStartServer_Update();\n}\n\n\n/*\n=================\nStartServer_MenuEvent\n=================\n*/\nstatic void StartServer_MenuEvent( void* ptr, int event ) {\n\tif( event != QM_ACTIVATED ) {\n\t\treturn;\n\t}\n\n\tswitch( ((menucommon_s*)ptr)->id ) {\n\tcase ID_PREVPAGE:\n\t\tif( s_startserver.page > 0 ) {\n\t\t\ts_startserver.page--;\n\t\t\tStartServer_Update();\n\t\t}\n\t\tbreak;\n\n\tcase ID_NEXTPAGE:\n\t\tif( s_startserver.page < s_startserver.maxpages - 1 ) {\n\t\t\ts_startserver.page++;\n\t\t\tStartServer_Update();\n\t\t}\n\t\tbreak;\n\n\tcase ID_STARTSERVERNEXT:\n\t\ttrap_Cvar_SetValue( \"g_gameType\", gametype_remap[s_startserver.gametype.curvalue] );\n\t\tUI_ServerOptionsMenu( s_startserver.multiplayer );\n\t\tbreak;\n\n\tcase ID_STARTSERVERBACK:\n\t\tUI_PopMenu();\n\t\tbreak;\n\t}\n}\n\n\n/*\n===============\nStartServer_LevelshotDraw\n===============\n*/\nstatic void StartServer_LevelshotDraw( void *self ) {\n\tmenubitmap_s\t*b;\n\tint\t\t\t\tx;\n\tint\t\t\t\ty;\n\tint\t\t\t\tw;\n\tint\t\t\t\th;\n\tint\t\t\t\tn;\n\n\tb = (menubitmap_s *)self;\n\n\tif( !b->generic.name ) {\n\t\treturn;\n\t}\n\n\tif( b->generic.name && !b->shader ) {\n\t\tb->shader = trap_R_RegisterShaderNoMip( b->generic.name );\n\t\tif( !b->shader && b->errorpic ) {\n\t\t\tb->shader = trap_R_RegisterShaderNoMip( b->errorpic );\n\t\t}\n\t}\n\n\tif( b->focuspic && !b->focusshader ) {\n\t\tb->focusshader = trap_R_RegisterShaderNoMip( b->focuspic );\n\t}\n\n\tx = b->generic.x;\n\ty = b->generic.y;\n\tw = b->width;\n\th =\tb->height;\n\tif( b->shader ) {\n\t\tUI_DrawHandlePic( x, y, w, h, b->shader );\n\t}\n\n\tx = b->generic.x;\n\ty = b->generic.y + b->height;\n\tUI_FillRect( x, y, b->width, 28, colorBlack );\n\n\tx += b->width / 2;\n\ty += 4;\n\tn = s_startserver.page * MAX_MAPSPERPAGE + b->generic.id - ID_PICTURES;\n\tUI_DrawString( x, y, s_startserver.maplist[n], UI_CENTER|UI_SMALLFONT, color_orange );\n\n\tx = b->generic.x;\n\ty = b->generic.y;\n\tw = b->width;\n\th =\tb->height + 28;\n\tif( b->generic.flags & QMF_HIGHLIGHT ) {\t\n\t\tUI_DrawHandlePic( x, y, w, h, b->focusshader );\n\t}\n}\n\n\n/*\n=================\nStartServer_MenuInit\n=================\n*/\nstatic void StartServer_MenuInit( void ) {\n\tint\ti;\n\tint\tx;\n\tint\ty;\n\tstatic char mapnamebuffer[64];\n\n\t// zero set all our globals\n\tmemset( &s_startserver, 0 ,sizeof(startserver_t) );\n\n\tStartServer_Cache();\n\n\ts_startserver.menu.wrapAround = qtrue;\n\ts_startserver.menu.fullscreen = qtrue;\n\n\ts_startserver.banner.generic.type  = MTYPE_BTEXT;\n\ts_startserver.banner.generic.x\t   = 320;\n\ts_startserver.banner.generic.y\t   = 16;\n\ts_startserver.banner.string        = \"GAME SERVER\";\n\ts_startserver.banner.color         = color_white;\n\ts_startserver.banner.style         = UI_CENTER;\n\n\ts_startserver.framel.generic.type  = MTYPE_BITMAP;\n\ts_startserver.framel.generic.name  = GAMESERVER_FRAMEL;\n\ts_startserver.framel.generic.flags = QMF_INACTIVE;\n\ts_startserver.framel.generic.x\t   = 0;  \n\ts_startserver.framel.generic.y\t   = 78;\n\ts_startserver.framel.width  \t   = 256;\n\ts_startserver.framel.height  \t   = 329;\n\n\ts_startserver.framer.generic.type  = MTYPE_BITMAP;\n\ts_startserver.framer.generic.name  = GAMESERVER_FRAMER;\n\ts_startserver.framer.generic.flags = QMF_INACTIVE;\n\ts_startserver.framer.generic.x\t   = 376;\n\ts_startserver.framer.generic.y\t   = 76;\n\ts_startserver.framer.width  \t   = 256;\n\ts_startserver.framer.height  \t   = 334;\n\n\ts_startserver.gametype.generic.type\t\t= MTYPE_SPINCONTROL;\n\ts_startserver.gametype.generic.name\t\t= \"Game Type:\";\n\ts_startserver.gametype.generic.flags\t= QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\ts_startserver.gametype.generic.callback\t= StartServer_GametypeEvent;\n\ts_startserver.gametype.generic.id\t\t= ID_GAMETYPE;\n\ts_startserver.gametype.generic.x\t\t= 320 - 24;\n\ts_startserver.gametype.generic.y\t\t= 368;\n\ts_startserver.gametype.itemnames\t\t= gametype_items;\n\n\tfor (i=0; i<MAX_MAPSPERPAGE; i++)\n\t{\n\t\tx =\t(i % MAX_MAPCOLS) * (128+8) + 188;\n\t\ty = (i / MAX_MAPROWS) * (128+8) + 96;\n\n\t\ts_startserver.mappics[i].generic.type   = MTYPE_BITMAP;\n\t\ts_startserver.mappics[i].generic.flags  = QMF_LEFT_JUSTIFY|QMF_INACTIVE;\n\t\ts_startserver.mappics[i].generic.x\t    = x;\n\t\ts_startserver.mappics[i].generic.y\t    = y;\n\t\ts_startserver.mappics[i].generic.id\t\t= ID_PICTURES+i;\n\t\ts_startserver.mappics[i].width  \t\t= 128;\n\t\ts_startserver.mappics[i].height  \t    = 96;\n\t\ts_startserver.mappics[i].focuspic       = GAMESERVER_SELECTED;\n\t\ts_startserver.mappics[i].errorpic       = GAMESERVER_UNKNOWNMAP;\n\t\ts_startserver.mappics[i].generic.ownerdraw = StartServer_LevelshotDraw;\n\n\t\ts_startserver.mapbuttons[i].generic.type     = MTYPE_BITMAP;\n\t\ts_startserver.mapbuttons[i].generic.flags    = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_NODEFAULTINIT;\n\t\ts_startserver.mapbuttons[i].generic.id       = ID_PICTURES+i;\n\t\ts_startserver.mapbuttons[i].generic.callback = StartServer_MapEvent;\n\t\ts_startserver.mapbuttons[i].generic.x\t     = x - 30;\n\t\ts_startserver.mapbuttons[i].generic.y\t     = y - 32;\n\t\ts_startserver.mapbuttons[i].width  \t\t     = 256;\n\t\ts_startserver.mapbuttons[i].height  \t     = 248;\n\t\ts_startserver.mapbuttons[i].generic.left     = x;\n\t\ts_startserver.mapbuttons[i].generic.top  \t = y;\n\t\ts_startserver.mapbuttons[i].generic.right    = x + 128;\n\t\ts_startserver.mapbuttons[i].generic.bottom   = y + 128;\n\t\ts_startserver.mapbuttons[i].focuspic         = GAMESERVER_SELECT;\n\t}\n\n\ts_startserver.arrows.generic.type  = MTYPE_BITMAP;\n\ts_startserver.arrows.generic.name  = GAMESERVER_ARROWS;\n\ts_startserver.arrows.generic.flags = QMF_INACTIVE;\n\ts_startserver.arrows.generic.x\t   = 260;\n\ts_startserver.arrows.generic.y\t   = 400;\n\ts_startserver.arrows.width  \t   = 128;\n\ts_startserver.arrows.height  \t   = 32;\n\n\ts_startserver.prevpage.generic.type\t    = MTYPE_BITMAP;\n\ts_startserver.prevpage.generic.flags    = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_startserver.prevpage.generic.callback = StartServer_MenuEvent;\n\ts_startserver.prevpage.generic.id\t    = ID_PREVPAGE;\n\ts_startserver.prevpage.generic.x\t\t= 260;\n\ts_startserver.prevpage.generic.y\t\t= 400;\n\ts_startserver.prevpage.width  \t\t    = 64;\n\ts_startserver.prevpage.height  \t\t    = 32;\n\ts_startserver.prevpage.focuspic         = GAMESERVER_ARROWSL;\n\n\ts_startserver.nextpage.generic.type\t    = MTYPE_BITMAP;\n\ts_startserver.nextpage.generic.flags    = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_startserver.nextpage.generic.callback = StartServer_MenuEvent;\n\ts_startserver.nextpage.generic.id\t    = ID_NEXTPAGE;\n\ts_startserver.nextpage.generic.x\t\t= 321;\n\ts_startserver.nextpage.generic.y\t\t= 400;\n\ts_startserver.nextpage.width  \t\t    = 64;\n\ts_startserver.nextpage.height  \t\t    = 32;\n\ts_startserver.nextpage.focuspic         = GAMESERVER_ARROWSR;\n\n\ts_startserver.mapname.generic.type  = MTYPE_PTEXT;\n\ts_startserver.mapname.generic.flags = QMF_CENTER_JUSTIFY|QMF_INACTIVE;\n\ts_startserver.mapname.generic.x\t    = 320;\n\ts_startserver.mapname.generic.y\t    = 440;\n\ts_startserver.mapname.string        = mapnamebuffer;\n\ts_startserver.mapname.style         = UI_CENTER|UI_BIGFONT;\n\ts_startserver.mapname.color         = text_color_normal;\n\n\ts_startserver.back.generic.type\t    = MTYPE_BITMAP;\n\ts_startserver.back.generic.name     = GAMESERVER_BACK0;\n\ts_startserver.back.generic.flags    = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_startserver.back.generic.callback = StartServer_MenuEvent;\n\ts_startserver.back.generic.id\t    = ID_STARTSERVERBACK;\n\ts_startserver.back.generic.x\t\t= 0;\n\ts_startserver.back.generic.y\t\t= 480-64;\n\ts_startserver.back.width  \t\t    = 128;\n\ts_startserver.back.height  \t\t    = 64;\n\ts_startserver.back.focuspic         = GAMESERVER_BACK1;\n\n\ts_startserver.next.generic.type\t    = MTYPE_BITMAP;\n\ts_startserver.next.generic.name     = GAMESERVER_NEXT0;\n\ts_startserver.next.generic.flags    = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_startserver.next.generic.callback = StartServer_MenuEvent;\n\ts_startserver.next.generic.id\t    = ID_STARTSERVERNEXT;\n\ts_startserver.next.generic.x\t\t= 640;\n\ts_startserver.next.generic.y\t\t= 480-64;\n\ts_startserver.next.width  \t\t    = 128;\n\ts_startserver.next.height  \t\t    = 64;\n\ts_startserver.next.focuspic         = GAMESERVER_NEXT1;\n\n\ts_startserver.item_null.generic.type\t= MTYPE_BITMAP;\n\ts_startserver.item_null.generic.flags\t= QMF_LEFT_JUSTIFY|QMF_MOUSEONLY|QMF_SILENT;\n\ts_startserver.item_null.generic.x\t\t= 0;\n\ts_startserver.item_null.generic.y\t\t= 0;\n\ts_startserver.item_null.width\t\t\t= 640;\n\ts_startserver.item_null.height\t\t\t= 480;\n\n\tMenu_AddItem( &s_startserver.menu, &s_startserver.banner );\n\tMenu_AddItem( &s_startserver.menu, &s_startserver.framel );\n\tMenu_AddItem( &s_startserver.menu, &s_startserver.framer );\n\n\tMenu_AddItem( &s_startserver.menu, &s_startserver.gametype );\n\tfor (i=0; i<MAX_MAPSPERPAGE; i++)\n\t{\n\t\tMenu_AddItem( &s_startserver.menu, &s_startserver.mappics[i] );\n\t\tMenu_AddItem( &s_startserver.menu, &s_startserver.mapbuttons[i] );\n\t}\n\n\tMenu_AddItem( &s_startserver.menu, &s_startserver.arrows );\n\tMenu_AddItem( &s_startserver.menu, &s_startserver.prevpage );\n\tMenu_AddItem( &s_startserver.menu, &s_startserver.nextpage );\n\tMenu_AddItem( &s_startserver.menu, &s_startserver.back );\n\tMenu_AddItem( &s_startserver.menu, &s_startserver.next );\n\tMenu_AddItem( &s_startserver.menu, &s_startserver.mapname );\n\tMenu_AddItem( &s_startserver.menu, &s_startserver.item_null );\n\n\tStartServer_GametypeEvent( NULL, QM_ACTIVATED );\n}\n\n\n/*\n=================\nStartServer_Cache\n=================\n*/\nvoid StartServer_Cache( void )\n{\n\tint\t\t\t\ti;\n\tconst char\t\t*info;\n\tqboolean\t\tprecache;\n\tchar\t\t\tpicname[64];\n\n\ttrap_R_RegisterShaderNoMip( GAMESERVER_BACK0 );\t\n\ttrap_R_RegisterShaderNoMip( GAMESERVER_BACK1 );\t\n\ttrap_R_RegisterShaderNoMip( GAMESERVER_NEXT0 );\t\n\ttrap_R_RegisterShaderNoMip( GAMESERVER_NEXT1 );\t\n\ttrap_R_RegisterShaderNoMip( GAMESERVER_FRAMEL );\t\n\ttrap_R_RegisterShaderNoMip( GAMESERVER_FRAMER );\t\n\ttrap_R_RegisterShaderNoMip( GAMESERVER_SELECT );\t\n\ttrap_R_RegisterShaderNoMip( GAMESERVER_SELECTED );\t\n\ttrap_R_RegisterShaderNoMip( GAMESERVER_UNKNOWNMAP );\n\ttrap_R_RegisterShaderNoMip( GAMESERVER_ARROWS );\n\ttrap_R_RegisterShaderNoMip( GAMESERVER_ARROWSL );\n\ttrap_R_RegisterShaderNoMip( GAMESERVER_ARROWSR );\n\n\tprecache = trap_Cvar_VariableValue(\"com_buildscript\");\n\n\ts_startserver.nummaps = UI_GetNumArenas();\n\n\tfor( i = 0; i < s_startserver.nummaps; i++ ) {\n\t\tinfo = UI_GetArenaInfoByNumber( i );\n\n\t\tQ_strncpyz( s_startserver.maplist[i], Info_ValueForKey( info, \"map\"), MAX_NAMELENGTH );\n\t\tQ_strupr( s_startserver.maplist[i] );\n\t\ts_startserver.mapGamebits[i] = GametypeBits( Info_ValueForKey( info, \"type\") );\n\n\t\tif( precache ) {\n\t\t\tCom_sprintf( picname, sizeof(picname), \"levelshots/%s\", s_startserver.maplist[i] );\n\t\t\ttrap_R_RegisterShaderNoMip(picname);\n\t\t}\n\t}\n\n\ts_startserver.maxpages = (s_startserver.nummaps + MAX_MAPSPERPAGE-1)/MAX_MAPSPERPAGE;\n}\n\n\n/*\n=================\nUI_StartServerMenu\n=================\n*/\nvoid UI_StartServerMenu( qboolean multiplayer ) {\n\tStartServer_MenuInit();\n\ts_startserver.multiplayer = multiplayer;\n\tUI_PushMenu( &s_startserver.menu );\n}\n\n\n\n/*\n=============================================================================\n\nSERVER OPTIONS MENU *****\n\n=============================================================================\n*/\n\n#define ID_PLAYER_TYPE\t\t\t20\n#define ID_MAXCLIENTS\t\t\t21\n#define ID_DEDICATED\t\t\t22\n#define ID_GO\t\t\t\t\t23\n#define ID_BACK\t\t\t\t\t24\n\n#define PLAYER_SLOTS\t\t\t12\n\n\ntypedef struct {\n\tmenuframework_s\t\tmenu;\n\n\tmenutext_s\t\t\tbanner;\n\n\tmenubitmap_s\t\tmappic;\n\tmenubitmap_s\t\tpicframe;\n\n\tmenulist_s\t\t\tdedicated;\n\tmenufield_s\t\t\ttimelimit;\n\tmenufield_s\t\t\tfraglimit;\n\tmenufield_s\t\t\tflaglimit;\n\tmenuradiobutton_s\tfriendlyfire;\n\tmenufield_s\t\t\thostname;\n\tmenuradiobutton_s\tpure;\n\tmenulist_s\t\t\tbotSkill;\n\n\tmenutext_s\t\t\tplayer0;\n\tmenulist_s\t\t\tplayerType[PLAYER_SLOTS];\n\tmenutext_s\t\t\tplayerName[PLAYER_SLOTS];\n\tmenulist_s\t\t\tplayerTeam[PLAYER_SLOTS];\n\n\tmenubitmap_s\t\tgo;\n\tmenubitmap_s\t\tnext;\n\tmenubitmap_s\t\tback;\n\n\tqboolean\t\t\tmultiplayer;\n\tint\t\t\t\t\tgametype;\n\tchar\t\t\t\tmapnamebuffer[32];\n\tchar\t\t\t\tplayerNameBuffers[PLAYER_SLOTS][16];\n\n\tqboolean\t\t\tnewBot;\n\tint\t\t\t\t\tnewBotIndex;\n\tchar\t\t\t\tnewBotName[16];\n\t\n\tmenulist_s\t\tpunkbuster;\n} serveroptions_t;\n\nstatic serveroptions_t s_serveroptions;\n\nstatic const char *dedicated_list[] = {\n\t\"No\",\n\t\"LAN\",\n\t\"Internet\",\n\t0\n};\n\nstatic const char *playerType_list[] = {\n\t\"Open\",\n\t\"Bot\",\n\t\"----\",\n\t0\n};\n\nstatic const char *playerTeam_list[] = {\n\t\"Blue\",\n\t\"Red\",\n\t0\n};\n\nstatic const char *botSkill_list[] = {\n\t\"I Can Win\",\n\t\"Bring It On\",\n\t\"Hurt Me Plenty\",\n\t\"Hardcore\",\n\t\"Nightmare!\",\n\t0\n};\n\n\n/*\n=================\nBotAlreadySelected\n=================\n*/\nstatic qboolean BotAlreadySelected( const char *checkName ) {\n\tint\t\tn;\n\n\tfor( n = 1; n < PLAYER_SLOTS; n++ ) {\n\t\tif( s_serveroptions.playerType[n].curvalue != 1 ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif( (s_serveroptions.gametype >= GT_TEAM) &&\n\t\t\t(s_serveroptions.playerTeam[n].curvalue != s_serveroptions.playerTeam[s_serveroptions.newBotIndex].curvalue ) ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif( Q_stricmp( checkName, s_serveroptions.playerNameBuffers[n] ) == 0 ) {\n\t\t\treturn qtrue;\n\t\t}\n\t}\n\n\treturn qfalse;\n}\n\n\n/*\n=================\nServerOptions_Start\n=================\n*/\nstatic void ServerOptions_Start( void ) {\n\tint\t\ttimelimit;\n\tint\t\tfraglimit;\n\tint\t\tmaxclients;\n\tint\t\tdedicated;\n\tint\t\tfriendlyfire;\n\tint\t\tflaglimit;\n\tint\t\tpure;\n\tint\t\tskill;\n\tint\t\tn;\n\tchar\tbuf[64];\n\n\n\ttimelimit\t = atoi( s_serveroptions.timelimit.field.buffer );\n\tfraglimit\t = atoi( s_serveroptions.fraglimit.field.buffer );\n\tflaglimit\t = atoi( s_serveroptions.flaglimit.field.buffer );\n\tdedicated\t = s_serveroptions.dedicated.curvalue;\n\tfriendlyfire = s_serveroptions.friendlyfire.curvalue;\n\tpure\t\t = s_serveroptions.pure.curvalue;\n\tskill\t\t = s_serveroptions.botSkill.curvalue + 1;\n\n\t//set maxclients\n\tfor( n = 0, maxclients = 0; n < PLAYER_SLOTS; n++ ) {\n\t\tif( s_serveroptions.playerType[n].curvalue == 2 ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif( (s_serveroptions.playerType[n].curvalue == 1) && (s_serveroptions.playerNameBuffers[n][0] == 0) ) {\n\t\t\tcontinue;\n\t\t}\n\t\tmaxclients++;\n\t}\n\n\tswitch( s_serveroptions.gametype ) {\n\tcase GT_FFA:\n\tdefault:\n\t\ttrap_Cvar_SetValue( \"ui_ffa_fraglimit\", fraglimit );\n\t\ttrap_Cvar_SetValue( \"ui_ffa_timelimit\", timelimit );\n\t\tbreak;\n\n\tcase GT_TOURNAMENT:\n\t\ttrap_Cvar_SetValue( \"ui_tourney_fraglimit\", fraglimit );\n\t\ttrap_Cvar_SetValue( \"ui_tourney_timelimit\", timelimit );\n\t\tbreak;\n\n\tcase GT_TEAM:\n\t\ttrap_Cvar_SetValue( \"ui_team_fraglimit\", fraglimit );\n\t\ttrap_Cvar_SetValue( \"ui_team_timelimit\", timelimit );\n\t\ttrap_Cvar_SetValue( \"ui_team_friendlt\", friendlyfire );\n\t\tbreak;\n\n\tcase GT_CTF:\n\t\ttrap_Cvar_SetValue( \"ui_ctf_fraglimit\", fraglimit );\n\t\ttrap_Cvar_SetValue( \"ui_ctf_timelimit\", timelimit );\n\t\ttrap_Cvar_SetValue( \"ui_ctf_friendlt\", friendlyfire );\n\t\tbreak;\n\t}\n\n\ttrap_Cvar_SetValue( \"sv_maxclients\", Com_Clamp( 0, 12, maxclients ) );\n\ttrap_Cvar_SetValue( \"dedicated\", Com_Clamp( 0, 2, dedicated ) );\n\ttrap_Cvar_SetValue (\"timelimit\", Com_Clamp( 0, timelimit, timelimit ) );\n\ttrap_Cvar_SetValue (\"fraglimit\", Com_Clamp( 0, fraglimit, fraglimit ) );\n\ttrap_Cvar_SetValue (\"capturelimit\", Com_Clamp( 0, flaglimit, flaglimit ) );\n\ttrap_Cvar_SetValue( \"g_friendlyfire\", friendlyfire );\n\ttrap_Cvar_SetValue( \"sv_pure\", pure );\n\ttrap_Cvar_Set(\"sv_hostname\", s_serveroptions.hostname.field.buffer );\n\t\n\ttrap_Cvar_SetValue( \"sv_punkbuster\", s_serveroptions.punkbuster.curvalue );\n\n\t// the wait commands will allow the dedicated to take effect\n\ttrap_Cmd_ExecuteText( EXEC_APPEND, va( \"wait ; wait ; map %s\\n\", s_startserver.maplist[s_startserver.currentmap] ) );\n\n\t// add bots\n\ttrap_Cmd_ExecuteText( EXEC_APPEND, \"wait 3\\n\" );\n\tfor( n = 1; n < PLAYER_SLOTS; n++ ) {\n\t\tif( s_serveroptions.playerType[n].curvalue != 1 ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif( s_serveroptions.playerNameBuffers[n][0] == 0 ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif( s_serveroptions.playerNameBuffers[n][0] == '-' ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif( s_serveroptions.gametype >= GT_TEAM ) {\n\t\t\tCom_sprintf( buf, sizeof(buf), \"addbot %s %i %s\\n\", s_serveroptions.playerNameBuffers[n], skill,\n\t\t\t\tplayerTeam_list[s_serveroptions.playerTeam[n].curvalue] );\n\t\t}\n\t\telse {\n\t\t\tCom_sprintf( buf, sizeof(buf), \"addbot %s %i\\n\", s_serveroptions.playerNameBuffers[n], skill );\n\t\t}\n\t\ttrap_Cmd_ExecuteText( EXEC_APPEND, buf );\n\t}\n\n\t// set player's team\n\tif( dedicated == 0 && s_serveroptions.gametype >= GT_TEAM ) {\n\t\ttrap_Cmd_ExecuteText( EXEC_APPEND, va( \"wait 5; team %s\\n\", playerTeam_list[s_serveroptions.playerTeam[0].curvalue] ) );\n\t}\n}\n\n\n/*\n=================\nServerOptions_InitPlayerItems\n=================\n*/\nstatic void ServerOptions_InitPlayerItems( void ) {\n\tint\t\tn;\n\tint\t\tv;\n\n\t// init types\n\tif( s_serveroptions.multiplayer ) {\n\t\tv = 0;\t// open\n\t}\n\telse {\n\t\tv = 1;\t// bot\n\t}\n\t\n\tfor( n = 0; n < PLAYER_SLOTS; n++ ) {\n\t\ts_serveroptions.playerType[n].curvalue = v;\n\t}\n\n\tif( s_serveroptions.multiplayer && (s_serveroptions.gametype < GT_TEAM) ) {\n\t\tfor( n = 8; n < PLAYER_SLOTS; n++ ) {\n\t\t\ts_serveroptions.playerType[n].curvalue = 2;\n\t\t}\n\t}\n\n\t// if not a dedicated server, first slot is reserved for the human on the server\n\tif( s_serveroptions.dedicated.curvalue == 0 ) {\n\t\t// human\n\t\ts_serveroptions.playerType[0].generic.flags |= QMF_INACTIVE;\n\t\ts_serveroptions.playerType[0].curvalue = 0;\n\t\ttrap_Cvar_VariableStringBuffer( \"name\", s_serveroptions.playerNameBuffers[0], sizeof(s_serveroptions.playerNameBuffers[0]) );\n\t\tQ_CleanStr( s_serveroptions.playerNameBuffers[0] );\n\t}\n\n\t// init teams\n\tif( s_serveroptions.gametype >= GT_TEAM ) {\n\t\tfor( n = 0; n < (PLAYER_SLOTS / 2); n++ ) {\n\t\t\ts_serveroptions.playerTeam[n].curvalue = 0;\n\t\t}\n\t\tfor( ; n < PLAYER_SLOTS; n++ ) {\n\t\t\ts_serveroptions.playerTeam[n].curvalue = 1;\n\t\t}\n\t}\n\telse {\n\t\tfor( n = 0; n < PLAYER_SLOTS; n++ ) {\n\t\t\ts_serveroptions.playerTeam[n].generic.flags |= (QMF_INACTIVE|QMF_HIDDEN);\n\t\t}\n\t}\n}\n\n\n/*\n=================\nServerOptions_SetPlayerItems\n=================\n*/\nstatic void ServerOptions_SetPlayerItems( void ) {\n\tint\t\tstart;\n\tint\t\tn;\n\n\t// types\n//\tfor( n = 0; n < PLAYER_SLOTS; n++ ) {\n//\t\tif( (!s_serveroptions.multiplayer) && (n > 0) && (s_serveroptions.playerType[n].curvalue == 0) ) {\n//\t\t\ts_serveroptions.playerType[n].curvalue = 1;\n//\t\t}\n//\t}\n\n\t// names\n\tif( s_serveroptions.dedicated.curvalue == 0 ) {\n\t\ts_serveroptions.player0.string = \"Human\";\n\t\ts_serveroptions.playerName[0].generic.flags &= ~QMF_HIDDEN;\n\n\t\tstart = 1;\n\t}\n\telse {\n\t\ts_serveroptions.player0.string = \"Open\";\n\t\tstart = 0;\n\t}\n\tfor( n = start; n < PLAYER_SLOTS; n++ ) {\n\t\tif( s_serveroptions.playerType[n].curvalue == 1 ) {\n\t\t\ts_serveroptions.playerName[n].generic.flags &= ~(QMF_INACTIVE|QMF_HIDDEN);\n\t\t}\n\t\telse {\n\t\t\ts_serveroptions.playerName[n].generic.flags |= (QMF_INACTIVE|QMF_HIDDEN);\n\t\t}\n\t}\n\n\t// teams\n\tif( s_serveroptions.gametype < GT_TEAM ) {\n\t\treturn;\n\t}\n\tfor( n = start; n < PLAYER_SLOTS; n++ ) {\n\t\tif( s_serveroptions.playerType[n].curvalue == 2 ) {\n\t\t\ts_serveroptions.playerTeam[n].generic.flags |= (QMF_INACTIVE|QMF_HIDDEN);\n\t\t}\n\t\telse {\n\t\t\ts_serveroptions.playerTeam[n].generic.flags &= ~(QMF_INACTIVE|QMF_HIDDEN);\n\t\t}\n\t}\n}\n\n\n/*\n=================\nServerOptions_Event\n=================\n*/\nstatic void ServerOptions_Event( void* ptr, int event ) {\n\tswitch( ((menucommon_s*)ptr)->id ) {\n\t\n\t//if( event != QM_ACTIVATED && event != QM_LOSTFOCUS) {\n\t//\treturn;\n\t//}\n\tcase ID_PLAYER_TYPE:\n\t\tif( event != QM_ACTIVATED ) {\n\t\t\tbreak;\n\t\t}\n\t\tServerOptions_SetPlayerItems();\n\t\tbreak;\n\n\tcase ID_MAXCLIENTS:\n\tcase ID_DEDICATED:\n\t\tServerOptions_SetPlayerItems();\n\t\tbreak;\n\tcase ID_GO:\n\t\tif( event != QM_ACTIVATED ) {\n\t\t\tbreak;\n\t\t}\n\t\tServerOptions_Start();\n\t\tbreak;\n\n\tcase ID_STARTSERVERNEXT:\n\t\tif( event != QM_ACTIVATED ) {\n\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\tcase ID_BACK:\n\t\tif( event != QM_ACTIVATED ) {\n\t\t\tbreak;\n\t\t}\n\t\tUI_PopMenu();\n\t\tbreak;\n\t}\n}\n\n\nstatic void ServerOptions_PlayerNameEvent( void* ptr, int event ) {\n\tint\t\tn;\n\n\tif( event != QM_ACTIVATED ) {\n\t\treturn;\n\t}\n\tn = ((menutext_s*)ptr)->generic.id;\n\ts_serveroptions.newBotIndex = n;\n\tUI_BotSelectMenu( s_serveroptions.playerNameBuffers[n] );\n}\n\n\n/*\n=================\nServerOptions_StatusBar\n=================\n*/\nstatic void ServerOptions_StatusBar( void* ptr ) {\n\tswitch( ((menucommon_s*)ptr)->id ) {\n\tdefault:\n\t\tUI_DrawString( 320, 440, \"0 = NO LIMIT\", UI_CENTER|UI_SMALLFONT, colorWhite );\n\t\tbreak;\n\t}\n}\n\n\n/*\n===============\nServerOptions_LevelshotDraw\n===============\n*/\nstatic void ServerOptions_LevelshotDraw( void *self ) {\n\tmenubitmap_s\t*b;\n\tint\t\t\t\tx;\n\tint\t\t\t\ty;\n\n\t// strange place for this, but it works\n\tif( s_serveroptions.newBot ) {\n\t\tQ_strncpyz( s_serveroptions.playerNameBuffers[s_serveroptions.newBotIndex], s_serveroptions.newBotName, 16 );\n\t\ts_serveroptions.newBot = qfalse;\n\t}\n\n\tb = (menubitmap_s *)self;\n\n\tBitmap_Draw( b );\n\n\tx = b->generic.x;\n\ty = b->generic.y + b->height;\n\tUI_FillRect( x, y, b->width, 40, colorBlack );\n\n\tx += b->width / 2;\n\ty += 4;\n\tUI_DrawString( x, y, s_serveroptions.mapnamebuffer, UI_CENTER|UI_SMALLFONT, color_orange );\n\n\ty += SMALLCHAR_HEIGHT;\n\tUI_DrawString( x, y, gametype_items[gametype_remap2[s_serveroptions.gametype]], UI_CENTER|UI_SMALLFONT, color_orange );\n}\n\n\nstatic void ServerOptions_InitBotNames( void ) {\n\tint\t\t\tcount;\n\tint\t\t\tn;\n\tconst char\t*arenaInfo;\n\tconst char\t*botInfo;\n\tchar\t\t*p;\n\tchar\t\t*bot;\n\tchar\t\tbots[MAX_INFO_STRING];\n\n\tif( s_serveroptions.gametype >= GT_TEAM ) {\n\t\tQ_strncpyz( s_serveroptions.playerNameBuffers[1], \"grunt\", 16 );\n\t\tQ_strncpyz( s_serveroptions.playerNameBuffers[2], \"major\", 16 );\n\t\tif( s_serveroptions.gametype == GT_TEAM ) {\n\t\t\tQ_strncpyz( s_serveroptions.playerNameBuffers[3], \"visor\", 16 );\n\t\t}\n\t\telse {\n\t\t\ts_serveroptions.playerType[3].curvalue = 2;\n\t\t}\n\t\ts_serveroptions.playerType[4].curvalue = 2;\n\t\ts_serveroptions.playerType[5].curvalue = 2;\n\n\t\tQ_strncpyz( s_serveroptions.playerNameBuffers[6], \"sarge\", 16 );\n\t\tQ_strncpyz( s_serveroptions.playerNameBuffers[7], \"grunt\", 16 );\n\t\tQ_strncpyz( s_serveroptions.playerNameBuffers[8], \"major\", 16 );\n\t\tif( s_serveroptions.gametype == GT_TEAM ) {\n\t\t\tQ_strncpyz( s_serveroptions.playerNameBuffers[9], \"visor\", 16 );\n\t\t}\n\t\telse {\n\t\t\ts_serveroptions.playerType[9].curvalue = 2;\n\t\t}\n\t\ts_serveroptions.playerType[10].curvalue = 2;\n\t\ts_serveroptions.playerType[11].curvalue = 2;\n\n\t\treturn;\n\t}\n\n\tcount = 1;\t// skip the first slot, reserved for a human\n\n\t// get info for this map\n\tarenaInfo = UI_GetArenaInfoByMap( s_serveroptions.mapnamebuffer );\n\n\t// get the bot info - we'll seed with them if any are listed\n\tQ_strncpyz( bots, Info_ValueForKey( arenaInfo, \"bots\" ), sizeof(bots) );\n\tp = &bots[0];\n\twhile( *p && count < PLAYER_SLOTS ) {\n\t\t//skip spaces\n\t\twhile( *p && *p == ' ' ) {\n\t\t\tp++;\n\t\t}\n\t\tif( !p ) {\n\t\t\tbreak;\n\t\t}\n\n\t\t// mark start of bot name\n\t\tbot = p;\n\n\t\t// skip until space of null\n\t\twhile( *p && *p != ' ' ) {\n\t\t\tp++;\n\t\t}\n\t\tif( *p ) {\n\t\t\t*p++ = 0;\n\t\t}\n\n\t\tbotInfo = UI_GetBotInfoByName( bot );\n\t\tbot = Info_ValueForKey( botInfo, \"name\" );\n\n\t\tQ_strncpyz( s_serveroptions.playerNameBuffers[count], bot, sizeof(s_serveroptions.playerNameBuffers[count]) );\n\t\tcount++;\n\t}\n\n\t// set the rest of the bot slots to \"---\"\n\tfor( n = count; n < PLAYER_SLOTS; n++ ) {\n\t\tstrcpy( s_serveroptions.playerNameBuffers[n], \"--------\" );\n\t}\n\n\t// pad up to #8 as open slots\n\tfor( ;count < 8; count++ ) {\n\t\ts_serveroptions.playerType[count].curvalue = 0;\n\t}\n\n\t// close off the rest by default\n\tfor( ;count < PLAYER_SLOTS; count++ ) {\n\t\tif( s_serveroptions.playerType[count].curvalue == 1 ) {\n\t\t\ts_serveroptions.playerType[count].curvalue = 2;\n\t\t}\n\t}\n}\n\n\n/*\n=================\nServerOptions_SetMenuItems\n=================\n*/\nstatic void ServerOptions_SetMenuItems( void ) {\n\tstatic char picname[64];\n\n\tswitch( s_serveroptions.gametype ) {\n\tcase GT_FFA:\n\tdefault:\n\t\tCom_sprintf( s_serveroptions.fraglimit.field.buffer, 4, \"%i\", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( \"ui_ffa_fraglimit\" ) ) );\n\t\tCom_sprintf( s_serveroptions.timelimit.field.buffer, 4, \"%i\", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( \"ui_ffa_timelimit\" ) ) );\n\t\tbreak;\n\n\tcase GT_TOURNAMENT:\n\t\tCom_sprintf( s_serveroptions.fraglimit.field.buffer, 4, \"%i\", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( \"ui_tourney_fraglimit\" ) ) );\n\t\tCom_sprintf( s_serveroptions.timelimit.field.buffer, 4, \"%i\", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( \"ui_tourney_timelimit\" ) ) );\n\t\tbreak;\n\n\tcase GT_TEAM:\n\t\tCom_sprintf( s_serveroptions.fraglimit.field.buffer, 4, \"%i\", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( \"ui_team_fraglimit\" ) ) );\n\t\tCom_sprintf( s_serveroptions.timelimit.field.buffer, 4, \"%i\", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( \"ui_team_timelimit\" ) ) );\n\t\ts_serveroptions.friendlyfire.curvalue = (int)Com_Clamp( 0, 1, trap_Cvar_VariableValue( \"ui_team_friendly\" ) );\n\t\tbreak;\n\n\tcase GT_CTF:\n\t\tCom_sprintf( s_serveroptions.flaglimit.field.buffer, 4, \"%i\", (int)Com_Clamp( 0, 100, trap_Cvar_VariableValue( \"ui_ctf_capturelimit\" ) ) );\n\t\tCom_sprintf( s_serveroptions.timelimit.field.buffer, 4, \"%i\", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( \"ui_ctf_timelimit\" ) ) );\n\t\ts_serveroptions.friendlyfire.curvalue = (int)Com_Clamp( 0, 1, trap_Cvar_VariableValue( \"ui_ctf_friendly\" ) );\n\t\tbreak;\n\t}\n\n\tQ_strncpyz( s_serveroptions.hostname.field.buffer, UI_Cvar_VariableString( \"sv_hostname\" ), sizeof( s_serveroptions.hostname.field.buffer ) );\n\ts_serveroptions.pure.curvalue = Com_Clamp( 0, 1, trap_Cvar_VariableValue( \"sv_pure\" ) );\n\n\t// set the map pic\n\tCom_sprintf( picname, 64, \"levelshots/%s\", s_startserver.maplist[s_startserver.currentmap] );\n\ts_serveroptions.mappic.generic.name = picname;\n\n\t// set the map name\n\tstrcpy( s_serveroptions.mapnamebuffer, s_startserver.mapname.string );\n\tQ_strupr( s_serveroptions.mapnamebuffer );\n\n\t// get the player selections initialized\n\tServerOptions_InitPlayerItems();\n\tServerOptions_SetPlayerItems();\n\n\t// seed bot names\n\tServerOptions_InitBotNames();\n\tServerOptions_SetPlayerItems();\n}\n\n/*\n=================\nPlayerName_Draw\n=================\n*/\nstatic void PlayerName_Draw( void *item ) {\n\tmenutext_s\t*s;\n\tfloat\t\t*color;\n\tint\t\t\tx, y;\n\tint\t\t\tstyle;\n\tqboolean\tfocus;\n\n\ts = (menutext_s *)item;\n\n\tx = s->generic.x;\n\ty =\ts->generic.y;\n\n\tstyle = UI_SMALLFONT;\n\tfocus = (s->generic.parent->cursor == s->generic.menuPosition);\n\n\tif ( s->generic.flags & QMF_GRAYED )\n\t\tcolor = text_color_disabled;\n\telse if ( focus )\n\t{\n\t\tcolor = text_color_highlight;\n\t\tstyle |= UI_PULSE;\n\t}\n\telse if ( s->generic.flags & QMF_BLINK )\n\t{\n\t\tcolor = text_color_highlight;\n\t\tstyle |= UI_BLINK;\n\t}\n\telse\n\t\tcolor = text_color_normal;\n\n\tif ( focus )\n\t{\n\t\t// draw cursor\n\t\tUI_FillRect( s->generic.left, s->generic.top, s->generic.right-s->generic.left+1, s->generic.bottom-s->generic.top+1, listbar_color ); \n\t\tUI_DrawChar( x, y, 13, UI_CENTER|UI_BLINK|UI_SMALLFONT, color);\n\t}\n\n\tUI_DrawString( x - SMALLCHAR_WIDTH, y, s->generic.name, style|UI_RIGHT, color );\n\tUI_DrawString( x + SMALLCHAR_WIDTH, y, s->string, style|UI_LEFT, color );\n}\n\n\n/*\n=================\nServerOptions_MenuInit\n=================\n*/\n#define OPTIONS_X\t456\n\nstatic void ServerOptions_MenuInit( qboolean multiplayer ) {\n\tint\t\ty;\n\tint\t\tn;\n\n\tmemset( &s_serveroptions, 0 ,sizeof(serveroptions_t) );\n\ts_serveroptions.multiplayer = multiplayer;\n\ts_serveroptions.gametype = (int)Com_Clamp( 0, 5, trap_Cvar_VariableValue( \"g_gameType\" ) );\n\ts_serveroptions.punkbuster.curvalue = Com_Clamp( 0, 1, trap_Cvar_VariableValue( \"sv_punkbuster\" ) );\n\n\tServerOptions_Cache();\n\n\ts_serveroptions.menu.wrapAround = qtrue;\n\ts_serveroptions.menu.fullscreen = qtrue;\n\n\ts_serveroptions.banner.generic.type\t\t\t= MTYPE_BTEXT;\n\ts_serveroptions.banner.generic.x\t\t\t= 320;\n\ts_serveroptions.banner.generic.y\t\t\t= 16;\n\ts_serveroptions.banner.string  \t\t\t\t= \"GAME SERVER\";\n\ts_serveroptions.banner.color  \t\t\t\t= color_white;\n\ts_serveroptions.banner.style  \t\t\t\t= UI_CENTER;\n\n\ts_serveroptions.mappic.generic.type\t\t\t= MTYPE_BITMAP;\n\ts_serveroptions.mappic.generic.flags\t\t= QMF_LEFT_JUSTIFY|QMF_INACTIVE;\n\ts_serveroptions.mappic.generic.x\t\t\t= 352;\n\ts_serveroptions.mappic.generic.y\t\t\t= 80;\n\ts_serveroptions.mappic.width\t\t\t\t= 160;\n\ts_serveroptions.mappic.height\t\t\t\t= 120;\n\ts_serveroptions.mappic.errorpic\t\t\t\t= GAMESERVER_UNKNOWNMAP;\n\ts_serveroptions.mappic.generic.ownerdraw\t= ServerOptions_LevelshotDraw;\n\n\ts_serveroptions.picframe.generic.type\t\t= MTYPE_BITMAP;\n\ts_serveroptions.picframe.generic.flags\t\t= QMF_LEFT_JUSTIFY|QMF_INACTIVE|QMF_HIGHLIGHT;\n\ts_serveroptions.picframe.generic.x\t\t\t= 352 - 38;\n\ts_serveroptions.picframe.generic.y\t\t\t= 80 - 40;\n\ts_serveroptions.picframe.width  \t\t\t= 320;\n\ts_serveroptions.picframe.height  \t\t\t= 320;\n\ts_serveroptions.picframe.focuspic\t\t\t= GAMESERVER_SELECT;\n\n\ty = 272;\n\tif( s_serveroptions.gametype != GT_CTF ) {\n\t\ts_serveroptions.fraglimit.generic.type       = MTYPE_FIELD;\n\t\ts_serveroptions.fraglimit.generic.name       = \"Frag Limit:\";\n\t\ts_serveroptions.fraglimit.generic.flags      = QMF_NUMBERSONLY|QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\t\ts_serveroptions.fraglimit.generic.x\t         = OPTIONS_X;\n\t\ts_serveroptions.fraglimit.generic.y\t         = y;\n\t\ts_serveroptions.fraglimit.generic.statusbar  = ServerOptions_StatusBar;\n\t\ts_serveroptions.fraglimit.field.widthInChars = 3;\n\t\ts_serveroptions.fraglimit.field.maxchars     = 3;\n\t}\n\telse {\n\t\ts_serveroptions.flaglimit.generic.type       = MTYPE_FIELD;\n\t\ts_serveroptions.flaglimit.generic.name       = \"Capture Limit:\";\n\t\ts_serveroptions.flaglimit.generic.flags      = QMF_NUMBERSONLY|QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\t\ts_serveroptions.flaglimit.generic.x\t         = OPTIONS_X;\n\t\ts_serveroptions.flaglimit.generic.y\t         = y;\n\t\ts_serveroptions.flaglimit.generic.statusbar  = ServerOptions_StatusBar;\n\t\ts_serveroptions.flaglimit.field.widthInChars = 3;\n\t\ts_serveroptions.flaglimit.field.maxchars     = 3;\n\t}\n\n\ty += BIGCHAR_HEIGHT+2;\n\ts_serveroptions.timelimit.generic.type       = MTYPE_FIELD;\n\ts_serveroptions.timelimit.generic.name       = \"Time Limit:\";\n\ts_serveroptions.timelimit.generic.flags      = QMF_NUMBERSONLY|QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\ts_serveroptions.timelimit.generic.x\t         = OPTIONS_X;\n\ts_serveroptions.timelimit.generic.y\t         = y;\n\ts_serveroptions.timelimit.generic.statusbar  = ServerOptions_StatusBar;\n\ts_serveroptions.timelimit.field.widthInChars = 3;\n\ts_serveroptions.timelimit.field.maxchars     = 3;\n\n\tif( s_serveroptions.gametype >= GT_TEAM ) {\n\t\ty += BIGCHAR_HEIGHT+2;\n\t\ts_serveroptions.friendlyfire.generic.type     = MTYPE_RADIOBUTTON;\n\t\ts_serveroptions.friendlyfire.generic.flags    = QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\t\ts_serveroptions.friendlyfire.generic.x\t      = OPTIONS_X;\n\t\ts_serveroptions.friendlyfire.generic.y\t      = y;\n\t\ts_serveroptions.friendlyfire.generic.name\t  = \"Friendly Fire:\";\n\t}\n\n\ty += BIGCHAR_HEIGHT+2;\n\ts_serveroptions.pure.generic.type\t\t\t= MTYPE_RADIOBUTTON;\n\ts_serveroptions.pure.generic.flags\t\t\t= QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\ts_serveroptions.pure.generic.x\t\t\t\t= OPTIONS_X;\n\ts_serveroptions.pure.generic.y\t\t\t\t= y;\n\ts_serveroptions.pure.generic.name\t\t\t= \"Pure Server:\";\n\n\tif( s_serveroptions.multiplayer ) {\n\t\ty += BIGCHAR_HEIGHT+2;\n\t\ts_serveroptions.dedicated.generic.type\t\t= MTYPE_SPINCONTROL;\n\t\ts_serveroptions.dedicated.generic.id\t\t= ID_DEDICATED;\n\t\ts_serveroptions.dedicated.generic.flags\t\t= QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\t\ts_serveroptions.dedicated.generic.callback\t= ServerOptions_Event;\n\t\ts_serveroptions.dedicated.generic.x\t\t\t= OPTIONS_X;\n\t\ts_serveroptions.dedicated.generic.y\t\t\t= y;\n\t\ts_serveroptions.dedicated.generic.name\t\t= \"Dedicated:\";\n\t\ts_serveroptions.dedicated.itemnames\t\t\t= dedicated_list;\n\t}\n\n\tif( s_serveroptions.multiplayer ) {\n\t\ty += BIGCHAR_HEIGHT+2;\n\t\ts_serveroptions.hostname.generic.type       = MTYPE_FIELD;\n\t\ts_serveroptions.hostname.generic.name       = \"Hostname:\";\n\t\ts_serveroptions.hostname.generic.flags      = QMF_SMALLFONT;\n\t\ts_serveroptions.hostname.generic.x          = OPTIONS_X;\n\t\ts_serveroptions.hostname.generic.y\t        = y;\n\t\ts_serveroptions.hostname.field.widthInChars = 18;\n\t\ts_serveroptions.hostname.field.maxchars     = 64;\n\t}\n\n\ty += BIGCHAR_HEIGHT+2;\n\ts_serveroptions.punkbuster.generic.type\t\t\t= MTYPE_SPINCONTROL;\n\ts_serveroptions.punkbuster.generic.name\t\t\t= \"Punkbuster:\";\n\ts_serveroptions.punkbuster.generic.flags\t\t\t= QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\ts_serveroptions.punkbuster.generic.id\t\t\t= 0;\n\ts_serveroptions.punkbuster.generic.x\t\t\t\t= OPTIONS_X;\n\ts_serveroptions.punkbuster.generic.y\t\t\t\t= y;\n\ts_serveroptions.punkbuster.itemnames\t\t\t\t= punkbuster_items;\n\t\n\ty = 80;\n\ts_serveroptions.botSkill.generic.type\t\t\t= MTYPE_SPINCONTROL;\n\ts_serveroptions.botSkill.generic.flags\t\t\t= QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\ts_serveroptions.botSkill.generic.name\t\t\t= \"Bot Skill:  \";\n\ts_serveroptions.botSkill.generic.x\t\t\t\t= 32 + ((int)strlen(s_serveroptions.botSkill.generic.name) + 2 ) * SMALLCHAR_WIDTH;\n\ts_serveroptions.botSkill.generic.y\t\t\t\t= y;\n\ts_serveroptions.botSkill.itemnames\t\t\t\t= botSkill_list;\n\ts_serveroptions.botSkill.curvalue\t\t\t\t= 1;\n\n\ty += ( 2 * SMALLCHAR_HEIGHT );\n\ts_serveroptions.player0.generic.type\t\t\t= MTYPE_TEXT;\n\ts_serveroptions.player0.generic.flags\t\t\t= QMF_SMALLFONT;\n\ts_serveroptions.player0.generic.x\t\t\t\t= 32 + SMALLCHAR_WIDTH;\n\ts_serveroptions.player0.generic.y\t\t\t\t= y;\n\ts_serveroptions.player0.color\t\t\t\t\t= color_orange;\n\ts_serveroptions.player0.style\t\t\t\t\t= UI_LEFT|UI_SMALLFONT;\n\n\tfor( n = 0; n < PLAYER_SLOTS; n++ ) {\n\t\ts_serveroptions.playerType[n].generic.type\t\t= MTYPE_SPINCONTROL;\n\t\ts_serveroptions.playerType[n].generic.flags\t\t= QMF_SMALLFONT;\n\t\ts_serveroptions.playerType[n].generic.id\t\t= ID_PLAYER_TYPE;\n\t\ts_serveroptions.playerType[n].generic.callback\t= ServerOptions_Event;\n\t\ts_serveroptions.playerType[n].generic.x\t\t\t= 32;\n\t\ts_serveroptions.playerType[n].generic.y\t\t\t= y;\n\t\ts_serveroptions.playerType[n].itemnames\t\t\t= playerType_list;\n\n\t\ts_serveroptions.playerName[n].generic.type\t\t= MTYPE_TEXT;\n\t\ts_serveroptions.playerName[n].generic.flags\t\t= QMF_SMALLFONT;\n\t\ts_serveroptions.playerName[n].generic.x\t\t\t= 96;\n\t\ts_serveroptions.playerName[n].generic.y\t\t\t= y;\n\t\ts_serveroptions.playerName[n].generic.callback\t= ServerOptions_PlayerNameEvent;\n\t\ts_serveroptions.playerName[n].generic.id\t\t= n;\n\t\ts_serveroptions.playerName[n].generic.ownerdraw\t= PlayerName_Draw;\n\t\ts_serveroptions.playerName[n].color\t\t\t\t= color_orange;\n\t\ts_serveroptions.playerName[n].style\t\t\t\t= UI_SMALLFONT;\n\t\ts_serveroptions.playerName[n].string\t\t\t= s_serveroptions.playerNameBuffers[n];\n\t\ts_serveroptions.playerName[n].generic.top\t\t= s_serveroptions.playerName[n].generic.y;\n\t\ts_serveroptions.playerName[n].generic.bottom\t= s_serveroptions.playerName[n].generic.y + SMALLCHAR_HEIGHT;\n\t\ts_serveroptions.playerName[n].generic.left\t\t= s_serveroptions.playerName[n].generic.x - SMALLCHAR_HEIGHT/ 2;\n\t\ts_serveroptions.playerName[n].generic.right\t\t= s_serveroptions.playerName[n].generic.x + 16 * SMALLCHAR_WIDTH;\n\n\t\ts_serveroptions.playerTeam[n].generic.type\t\t= MTYPE_SPINCONTROL;\n\t\ts_serveroptions.playerTeam[n].generic.flags\t\t= QMF_SMALLFONT;\n\t\ts_serveroptions.playerTeam[n].generic.x\t\t\t= 240;\n\t\ts_serveroptions.playerTeam[n].generic.y\t\t\t= y;\n\t\ts_serveroptions.playerTeam[n].itemnames\t\t\t= playerTeam_list;\n\n\t\ty += ( SMALLCHAR_HEIGHT + 4 );\n\t}\n\n\ts_serveroptions.back.generic.type\t  = MTYPE_BITMAP;\n\ts_serveroptions.back.generic.name     = GAMESERVER_BACK0;\n\ts_serveroptions.back.generic.flags    = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_serveroptions.back.generic.callback = ServerOptions_Event;\n\ts_serveroptions.back.generic.id\t      = ID_BACK;\n\ts_serveroptions.back.generic.x\t\t  = 0;\n\ts_serveroptions.back.generic.y\t\t  = 480-64;\n\ts_serveroptions.back.width  \t\t  = 128;\n\ts_serveroptions.back.height  \t\t  = 64;\n\ts_serveroptions.back.focuspic         = GAMESERVER_BACK1;\n\n\ts_serveroptions.next.generic.type\t  = MTYPE_BITMAP;\n\ts_serveroptions.next.generic.name     = GAMESERVER_NEXT0;\n\ts_serveroptions.next.generic.flags    = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_INACTIVE|QMF_GRAYED|QMF_HIDDEN;\n\ts_serveroptions.next.generic.callback = ServerOptions_Event;\n\ts_serveroptions.next.generic.id\t      = ID_STARTSERVERNEXT;\n\ts_serveroptions.next.generic.x\t\t  = 640;\n\ts_serveroptions.next.generic.y\t\t  = 480-64-72;\n\ts_serveroptions.next.generic.statusbar  = ServerOptions_StatusBar;\n\ts_serveroptions.next.width  \t\t  = 128;\n\ts_serveroptions.next.height  \t\t  = 64;\n\ts_serveroptions.next.focuspic         = GAMESERVER_NEXT1;\n\n\ts_serveroptions.go.generic.type\t    = MTYPE_BITMAP;\n\ts_serveroptions.go.generic.name     = GAMESERVER_FIGHT0;\n\ts_serveroptions.go.generic.flags    = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_serveroptions.go.generic.callback = ServerOptions_Event;\n\ts_serveroptions.go.generic.id\t    = ID_GO;\n\ts_serveroptions.go.generic.x\t\t= 640;\n\ts_serveroptions.go.generic.y\t\t= 480-64;\n\ts_serveroptions.go.width  \t\t    = 128;\n\ts_serveroptions.go.height  \t\t    = 64;\n\ts_serveroptions.go.focuspic         = GAMESERVER_FIGHT1;\n\n\tMenu_AddItem( &s_serveroptions.menu, &s_serveroptions.banner );\n\n\tMenu_AddItem( &s_serveroptions.menu, &s_serveroptions.mappic );\n\tMenu_AddItem( &s_serveroptions.menu, &s_serveroptions.picframe );\n\n\tMenu_AddItem( &s_serveroptions.menu, &s_serveroptions.botSkill );\n\tMenu_AddItem( &s_serveroptions.menu, &s_serveroptions.player0 );\n\tfor( n = 0; n < PLAYER_SLOTS; n++ ) {\n\t\tif( n != 0 ) {\n\t\t\tMenu_AddItem( &s_serveroptions.menu, &s_serveroptions.playerType[n] );\n\t\t}\n\t\tMenu_AddItem( &s_serveroptions.menu, &s_serveroptions.playerName[n] );\n\t\tif( s_serveroptions.gametype >= GT_TEAM ) {\n\t\t\tMenu_AddItem( &s_serveroptions.menu, &s_serveroptions.playerTeam[n] );\n\t\t}\n\t}\n\n\tif( s_serveroptions.gametype != GT_CTF ) {\n\t\tMenu_AddItem( &s_serveroptions.menu, &s_serveroptions.fraglimit );\n\t}\n\telse {\n\t\tMenu_AddItem( &s_serveroptions.menu, &s_serveroptions.flaglimit );\n\t}\n\tMenu_AddItem( &s_serveroptions.menu, &s_serveroptions.timelimit );\n\tif( s_serveroptions.gametype >= GT_TEAM ) {\n\t\tMenu_AddItem( &s_serveroptions.menu, &s_serveroptions.friendlyfire );\n\t}\n\tMenu_AddItem( &s_serveroptions.menu, &s_serveroptions.pure );\n\tif( s_serveroptions.multiplayer ) {\n\t\tMenu_AddItem( &s_serveroptions.menu, &s_serveroptions.dedicated );\n\t}\n\tif( s_serveroptions.multiplayer ) {\n\t\tMenu_AddItem( &s_serveroptions.menu, &s_serveroptions.hostname );\n\t}\n\n\tMenu_AddItem( &s_serveroptions.menu, &s_serveroptions.back );\n\tMenu_AddItem( &s_serveroptions.menu, &s_serveroptions.next );\n\tMenu_AddItem( &s_serveroptions.menu, &s_serveroptions.go );\n\n\tMenu_AddItem( &s_serveroptions.menu, (void*) &s_serveroptions.punkbuster );\n\t\n\tServerOptions_SetMenuItems();\n}\n\n/*\n=================\nServerOptions_Cache\n=================\n*/\nvoid ServerOptions_Cache( void ) {\n\ttrap_R_RegisterShaderNoMip( GAMESERVER_BACK0 );\n\ttrap_R_RegisterShaderNoMip( GAMESERVER_BACK1 );\n\ttrap_R_RegisterShaderNoMip( GAMESERVER_FIGHT0 );\n\ttrap_R_RegisterShaderNoMip( GAMESERVER_FIGHT1 );\n\ttrap_R_RegisterShaderNoMip( GAMESERVER_SELECT );\n\ttrap_R_RegisterShaderNoMip( GAMESERVER_UNKNOWNMAP );\n}\n\n\n/*\n=================\nUI_ServerOptionsMenu\n=================\n*/\nstatic void UI_ServerOptionsMenu( qboolean multiplayer ) {\n\tServerOptions_MenuInit( multiplayer );\n\tUI_PushMenu( &s_serveroptions.menu );\n}\n\n\n\n/*\n=============================================================================\n\nBOT SELECT MENU *****\n\n=============================================================================\n*/\n\n\n#define BOTSELECT_BACK0\t\t\t\"menu/art/back_0\"\n#define BOTSELECT_BACK1\t\t\t\"menu/art/back_1\"\n#define BOTSELECT_ACCEPT0\t\t\"menu/art/accept_0\"\n#define BOTSELECT_ACCEPT1\t\t\"menu/art/accept_1\"\n#define BOTSELECT_SELECT\t\t\"menu/art/opponents_select\"\n#define BOTSELECT_SELECTED\t\t\"menu/art/opponents_selected\"\n#define BOTSELECT_ARROWS\t\t\"menu/art/gs_arrows_0\"\n#define BOTSELECT_ARROWSL\t\t\"menu/art/gs_arrows_l\"\n#define BOTSELECT_ARROWSR\t\t\"menu/art/gs_arrows_r\"\n\n#define PLAYERGRID_COLS\t\t\t4\n#define PLAYERGRID_ROWS\t\t\t4\n#define MAX_MODELSPERPAGE\t\t(PLAYERGRID_ROWS * PLAYERGRID_COLS)\n\n\ntypedef struct {\n\tmenuframework_s\tmenu;\n\n\tmenutext_s\t\tbanner;\n\n\tmenubitmap_s\tpics[MAX_MODELSPERPAGE];\n\tmenubitmap_s\tpicbuttons[MAX_MODELSPERPAGE];\n\tmenutext_s\t\tpicnames[MAX_MODELSPERPAGE];\n\n\tmenubitmap_s\tarrows;\n\tmenubitmap_s\tleft;\n\tmenubitmap_s\tright;\n\n\tmenubitmap_s\tgo;\n\tmenubitmap_s\tback;\n\n\tint\t\t\t\tnumBots;\n\tint\t\t\t\tmodelpage;\n\tint\t\t\t\tnumpages;\n\tint\t\t\t\tselectedmodel;\n\tint\t\t\t\tsortedBotNums[MAX_BOTS];\n\tchar\t\t\tboticons[MAX_MODELSPERPAGE][MAX_QPATH];\n\tchar\t\t\tbotnames[MAX_MODELSPERPAGE][16];\n} botSelectInfo_t;\n\nstatic botSelectInfo_t\tbotSelectInfo;\n\n\n/*\n=================\nUI_BotSelectMenu_SortCompare\n=================\n*/\nstatic int QDECL UI_BotSelectMenu_SortCompare( const void *arg1, const void *arg2 ) {\n\tint\t\t\tnum1, num2;\n\tconst char\t*info1, *info2;\n\tconst char\t*name1, *name2;\n\n\tnum1 = *(int *)arg1;\n\tnum2 = *(int *)arg2;\n\n\tinfo1 = UI_GetBotInfoByNumber( num1 );\n\tinfo2 = UI_GetBotInfoByNumber( num2 );\n\n\tname1 = Info_ValueForKey( info1, \"name\" );\n\tname2 = Info_ValueForKey( info2, \"name\" );\n\n\treturn Q_stricmp( name1, name2 );\n}\n\n\n/*\n=================\nUI_BotSelectMenu_BuildList\n=================\n*/\nstatic void UI_BotSelectMenu_BuildList( void ) {\n\tint\t\tn;\n\n\tbotSelectInfo.modelpage = 0;\n\tbotSelectInfo.numBots = UI_GetNumBots();\n\tbotSelectInfo.numpages = botSelectInfo.numBots / MAX_MODELSPERPAGE;\n\tif( botSelectInfo.numBots % MAX_MODELSPERPAGE ) {\n\t\tbotSelectInfo.numpages++;\n\t}\n\n\t// initialize the array\n\tfor( n = 0; n < botSelectInfo.numBots; n++ ) {\n\t\tbotSelectInfo.sortedBotNums[n] = n;\n\t}\n\n\t// now sort it\n\tqsort( botSelectInfo.sortedBotNums, botSelectInfo.numBots, sizeof(botSelectInfo.sortedBotNums[0]), UI_BotSelectMenu_SortCompare );\n}\n\n\n/*\n=================\nServerPlayerIcon\n=================\n*/\nstatic void ServerPlayerIcon( const char *modelAndSkin, char *iconName, int iconNameMaxSize ) {\n\tchar\t*skin;\n\tchar\tmodel[MAX_QPATH];\n\n\tQ_strncpyz( model, modelAndSkin, sizeof(model));\n\tskin = Q_strrchr( model, '/' );\n\tif ( skin ) {\n\t\t*skin++ = '\\0';\n\t}\n\telse {\n\t\tskin = \"default\";\n\t}\n\n\tCom_sprintf(iconName, iconNameMaxSize, \"models/players/%s/icon_%s.tga\", model, skin );\n\n\tif( !trap_R_RegisterShaderNoMip( iconName ) && Q_stricmp( skin, \"default\" ) != 0 ) {\n\t\tCom_sprintf(iconName, iconNameMaxSize, \"models/players/%s/icon_default.tga\", model );\n\t}\n}\n\n\n/*\n=================\nUI_BotSelectMenu_UpdateGrid\n=================\n*/\nstatic void UI_BotSelectMenu_UpdateGrid( void ) {\n\tconst char\t*info;\n\tint\t\t\ti;\n    int\t\t\tj;\n\n\tj = botSelectInfo.modelpage * MAX_MODELSPERPAGE;\n\tfor( i = 0; i < (PLAYERGRID_ROWS * PLAYERGRID_COLS); i++, j++) {\n\t\tif( j < botSelectInfo.numBots ) { \n\t\t\tinfo = UI_GetBotInfoByNumber( botSelectInfo.sortedBotNums[j] );\n\t\t\tServerPlayerIcon( Info_ValueForKey( info, \"model\" ), botSelectInfo.boticons[i], MAX_QPATH );\n\t\t\tQ_strncpyz( botSelectInfo.botnames[i], Info_ValueForKey( info, \"name\" ), 16 );\n\t\t\tQ_CleanStr( botSelectInfo.botnames[i] );\n \t\t\tbotSelectInfo.pics[i].generic.name = botSelectInfo.boticons[i];\n\t\t\tif( BotAlreadySelected( botSelectInfo.botnames[i] ) ) {\n\t\t\t\tbotSelectInfo.picnames[i].color = color_red;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tbotSelectInfo.picnames[i].color = color_orange;\n\t\t\t}\n\t\t\tbotSelectInfo.picbuttons[i].generic.flags &= ~QMF_INACTIVE;\n\t\t}\n\t\telse {\n\t\t\t// dead slot\n \t\t\tbotSelectInfo.pics[i].generic.name         = NULL;\n\t\t\tbotSelectInfo.picbuttons[i].generic.flags |= QMF_INACTIVE;\n\t\t\tbotSelectInfo.botnames[i][0] = 0;\n\t\t}\n\n \t\tbotSelectInfo.pics[i].generic.flags       &= ~QMF_HIGHLIGHT;\n \t\tbotSelectInfo.pics[i].shader               = 0;\n \t\tbotSelectInfo.picbuttons[i].generic.flags |= QMF_PULSEIFFOCUS;\n\t}\n\n\t// set selected model\n\ti = botSelectInfo.selectedmodel % MAX_MODELSPERPAGE;\n\tbotSelectInfo.pics[i].generic.flags |= QMF_HIGHLIGHT;\n\tbotSelectInfo.picbuttons[i].generic.flags &= ~QMF_PULSEIFFOCUS;\n\n\tif( botSelectInfo.numpages > 1 ) {\n\t\tif( botSelectInfo.modelpage > 0 ) {\n\t\t\tbotSelectInfo.left.generic.flags &= ~QMF_INACTIVE;\n\t\t}\n\t\telse {\n\t\t\tbotSelectInfo.left.generic.flags |= QMF_INACTIVE;\n\t\t}\n\n\t\tif( botSelectInfo.modelpage < (botSelectInfo.numpages - 1) ) {\n\t\t\tbotSelectInfo.right.generic.flags &= ~QMF_INACTIVE;\n\t\t}\n\t\telse {\n\t\t\tbotSelectInfo.right.generic.flags |= QMF_INACTIVE;\n\t\t}\n\t}\n\telse {\n\t\t// hide left/right markers\n\t\tbotSelectInfo.left.generic.flags |= QMF_INACTIVE;\n\t\tbotSelectInfo.right.generic.flags |= QMF_INACTIVE;\n\t}\n}\n\n\n/*\n=================\nUI_BotSelectMenu_Default\n=================\n*/\nstatic void UI_BotSelectMenu_Default( char *bot ) {\n\tconst char\t*botInfo;\n\tconst char\t*test;\n\tint\t\t\tn;\n\tint\t\t\ti;\n\n\tfor( n = 0; n < botSelectInfo.numBots; n++ ) {\n\t\tbotInfo = UI_GetBotInfoByNumber( n );\n\t\ttest = Info_ValueForKey( botInfo, \"name\" );\n\t\tif( Q_stricmp( bot, test ) == 0 ) {\n\t\t\tbreak;\n\t\t}\n\t}\n\tif( n == botSelectInfo.numBots ) {\n\t\tbotSelectInfo.selectedmodel = 0;\n\t\treturn;\n\t}\n\n\tfor( i = 0; i < botSelectInfo.numBots; i++ ) {\n\t\tif( botSelectInfo.sortedBotNums[i] == n ) {\n\t\t\tbreak;\n\t\t}\n\t}\n\tif( i == botSelectInfo.numBots ) {\n\t\tbotSelectInfo.selectedmodel = 0;\n\t\treturn;\n\t}\n\n\tbotSelectInfo.selectedmodel = i;\n}\n\n\n/*\n=================\nUI_BotSelectMenu_LeftEvent\n=================\n*/\nstatic void UI_BotSelectMenu_LeftEvent( void* ptr, int event ) {\n\tif( event != QM_ACTIVATED ) {\n\t\treturn;\n\t}\n\tif( botSelectInfo.modelpage > 0 ) {\n\t\tbotSelectInfo.modelpage--;\n\t\tbotSelectInfo.selectedmodel = botSelectInfo.modelpage * MAX_MODELSPERPAGE;\n\t\tUI_BotSelectMenu_UpdateGrid();\n\t}\n}\n\n\n/*\n=================\nUI_BotSelectMenu_RightEvent\n=================\n*/\nstatic void UI_BotSelectMenu_RightEvent( void* ptr, int event ) {\n\tif( event != QM_ACTIVATED ) {\n\t\treturn;\n\t}\n\tif( botSelectInfo.modelpage < botSelectInfo.numpages - 1 ) {\n\t\tbotSelectInfo.modelpage++;\n\t\tbotSelectInfo.selectedmodel = botSelectInfo.modelpage * MAX_MODELSPERPAGE;\n\t\tUI_BotSelectMenu_UpdateGrid();\n\t}\n}\n\n\n/*\n=================\nUI_BotSelectMenu_BotEvent\n=================\n*/\nstatic void UI_BotSelectMenu_BotEvent( void* ptr, int event ) {\n\tint\t\ti;\n\n\tif( event != QM_ACTIVATED ) {\n\t\treturn;\n\t}\n\n\tfor( i = 0; i < (PLAYERGRID_ROWS * PLAYERGRID_COLS); i++ ) {\n \t\tbotSelectInfo.pics[i].generic.flags &= ~QMF_HIGHLIGHT;\n \t\tbotSelectInfo.picbuttons[i].generic.flags |= QMF_PULSEIFFOCUS;\n\t}\n\n\t// set selected\n\ti = ((menucommon_s*)ptr)->id;\n\tbotSelectInfo.pics[i].generic.flags |= QMF_HIGHLIGHT;\n\tbotSelectInfo.picbuttons[i].generic.flags &= ~QMF_PULSEIFFOCUS;\n\tbotSelectInfo.selectedmodel = botSelectInfo.modelpage * MAX_MODELSPERPAGE + i;\n}\n\n\n/*\n=================\nUI_BotSelectMenu_BackEvent\n=================\n*/\nstatic void UI_BotSelectMenu_BackEvent( void* ptr, int event ) {\n\tif( event != QM_ACTIVATED ) {\n\t\treturn;\n\t}\n\tUI_PopMenu();\n}\n\n\n/*\n=================\nUI_BotSelectMenu_SelectEvent\n=================\n*/\nstatic void UI_BotSelectMenu_SelectEvent( void* ptr, int event ) {\n\tif( event != QM_ACTIVATED ) {\n\t\treturn;\n\t}\n\tUI_PopMenu();\n\n\ts_serveroptions.newBot = qtrue;\n\tQ_strncpyz( s_serveroptions.newBotName, botSelectInfo.botnames[botSelectInfo.selectedmodel % MAX_MODELSPERPAGE], 16 );\n}\n\n\n/*\n=================\nUI_BotSelectMenu_Cache\n=================\n*/\nvoid UI_BotSelectMenu_Cache( void ) {\n\ttrap_R_RegisterShaderNoMip( BOTSELECT_BACK0 );\n\ttrap_R_RegisterShaderNoMip( BOTSELECT_BACK1 );\n\ttrap_R_RegisterShaderNoMip( BOTSELECT_ACCEPT0 );\n\ttrap_R_RegisterShaderNoMip( BOTSELECT_ACCEPT1 );\n\ttrap_R_RegisterShaderNoMip( BOTSELECT_SELECT );\n\ttrap_R_RegisterShaderNoMip( BOTSELECT_SELECTED );\n\ttrap_R_RegisterShaderNoMip( BOTSELECT_ARROWS );\n\ttrap_R_RegisterShaderNoMip( BOTSELECT_ARROWSL );\n\ttrap_R_RegisterShaderNoMip( BOTSELECT_ARROWSR );\n}\n\n\nstatic void UI_BotSelectMenu_Init( char *bot ) {\n\tint\t\ti, j, k;\n\tint\t\tx, y;\n\n\tmemset( &botSelectInfo, 0 ,sizeof(botSelectInfo) );\n\tbotSelectInfo.menu.wrapAround = qtrue;\n\tbotSelectInfo.menu.fullscreen = qtrue;\n\n\tUI_BotSelectMenu_Cache();\n\n\tbotSelectInfo.banner.generic.type\t= MTYPE_BTEXT;\n\tbotSelectInfo.banner.generic.x\t\t= 320;\n\tbotSelectInfo.banner.generic.y\t\t= 16;\n\tbotSelectInfo.banner.string\t\t\t= \"SELECT BOT\";\n\tbotSelectInfo.banner.color\t\t\t= color_white;\n\tbotSelectInfo.banner.style\t\t\t= UI_CENTER;\n\n\ty =\t80;\n\tfor( i = 0, k = 0; i < PLAYERGRID_ROWS; i++) {\n\t\tx =\t180;\n\t\tfor( j = 0; j < PLAYERGRID_COLS; j++, k++ ) {\n\t\t\tbotSelectInfo.pics[k].generic.type\t\t\t\t= MTYPE_BITMAP;\n\t\t\tbotSelectInfo.pics[k].generic.flags\t\t\t\t= QMF_LEFT_JUSTIFY|QMF_INACTIVE;\n\t\t\tbotSelectInfo.pics[k].generic.x\t\t\t\t\t= x;\n\t\t\tbotSelectInfo.pics[k].generic.y\t\t\t\t\t= y;\n \t\t\tbotSelectInfo.pics[k].generic.name\t\t\t\t= botSelectInfo.boticons[k];\n\t\t\tbotSelectInfo.pics[k].width\t\t\t\t\t\t= 64;\n\t\t\tbotSelectInfo.pics[k].height\t\t\t\t\t= 64;\n\t\t\tbotSelectInfo.pics[k].focuspic\t\t\t\t\t= BOTSELECT_SELECTED;\n\t\t\tbotSelectInfo.pics[k].focuscolor\t\t\t\t= colorRed;\n\n\t\t\tbotSelectInfo.picbuttons[k].generic.type\t\t= MTYPE_BITMAP;\n\t\t\tbotSelectInfo.picbuttons[k].generic.flags\t\t= QMF_LEFT_JUSTIFY|QMF_NODEFAULTINIT|QMF_PULSEIFFOCUS;\n\t\t\tbotSelectInfo.picbuttons[k].generic.callback\t= UI_BotSelectMenu_BotEvent;\n\t\t\tbotSelectInfo.picbuttons[k].generic.id\t\t\t= k;\n\t\t\tbotSelectInfo.picbuttons[k].generic.x\t\t\t= x - 16;\n\t\t\tbotSelectInfo.picbuttons[k].generic.y\t\t\t= y - 16;\n\t\t\tbotSelectInfo.picbuttons[k].generic.left\t\t= x;\n\t\t\tbotSelectInfo.picbuttons[k].generic.top\t\t\t= y;\n\t\t\tbotSelectInfo.picbuttons[k].generic.right\t\t= x + 64;\n\t\t\tbotSelectInfo.picbuttons[k].generic.bottom\t\t= y + 64;\n\t\t\tbotSelectInfo.picbuttons[k].width\t\t\t\t= 128;\n\t\t\tbotSelectInfo.picbuttons[k].height\t\t\t\t= 128;\n\t\t\tbotSelectInfo.picbuttons[k].focuspic\t\t\t= BOTSELECT_SELECT;\n\t\t\tbotSelectInfo.picbuttons[k].focuscolor\t\t\t= colorRed;\n\n\t\t\tbotSelectInfo.picnames[k].generic.type\t\t\t= MTYPE_TEXT;\n\t\t\tbotSelectInfo.picnames[k].generic.flags\t\t\t= QMF_SMALLFONT;\n\t\t\tbotSelectInfo.picnames[k].generic.x\t\t\t\t= x + 32;\n\t\t\tbotSelectInfo.picnames[k].generic.y\t\t\t\t= y + 64;\n\t\t\tbotSelectInfo.picnames[k].string\t\t\t\t= botSelectInfo.botnames[k];\n\t\t\tbotSelectInfo.picnames[k].color\t\t\t\t\t= color_orange;\n\t\t\tbotSelectInfo.picnames[k].style\t\t\t\t\t= UI_CENTER|UI_SMALLFONT;\n\n\t\t\tx += (64 + 6);\n\t\t}\n\t\ty += (64 + SMALLCHAR_HEIGHT + 6);\n\t}\n\n\tbotSelectInfo.arrows.generic.type\t\t= MTYPE_BITMAP;\n\tbotSelectInfo.arrows.generic.name\t\t= BOTSELECT_ARROWS;\n\tbotSelectInfo.arrows.generic.flags\t\t= QMF_INACTIVE;\n\tbotSelectInfo.arrows.generic.x\t\t\t= 260;\n\tbotSelectInfo.arrows.generic.y\t\t\t= 440;\n\tbotSelectInfo.arrows.width\t\t\t\t= 128;\n\tbotSelectInfo.arrows.height\t\t\t\t= 32;\n\n\tbotSelectInfo.left.generic.type\t\t\t= MTYPE_BITMAP;\n\tbotSelectInfo.left.generic.flags\t\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\tbotSelectInfo.left.generic.callback\t\t= UI_BotSelectMenu_LeftEvent;\n\tbotSelectInfo.left.generic.x\t\t\t= 260;\n\tbotSelectInfo.left.generic.y\t\t\t= 440;\n\tbotSelectInfo.left.width  \t\t\t\t= 64;\n\tbotSelectInfo.left.height  \t\t\t\t= 32;\n\tbotSelectInfo.left.focuspic\t\t\t\t= BOTSELECT_ARROWSL;\n\n\tbotSelectInfo.right.generic.type\t    = MTYPE_BITMAP;\n\tbotSelectInfo.right.generic.flags\t\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\tbotSelectInfo.right.generic.callback\t= UI_BotSelectMenu_RightEvent;\n\tbotSelectInfo.right.generic.x\t\t\t= 321;\n\tbotSelectInfo.right.generic.y\t\t\t= 440;\n\tbotSelectInfo.right.width  \t\t\t\t= 64;\n\tbotSelectInfo.right.height  \t\t    = 32;\n\tbotSelectInfo.right.focuspic\t\t\t= BOTSELECT_ARROWSR;\n\n\tbotSelectInfo.back.generic.type\t\t= MTYPE_BITMAP;\n\tbotSelectInfo.back.generic.name\t\t= BOTSELECT_BACK0;\n\tbotSelectInfo.back.generic.flags\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\tbotSelectInfo.back.generic.callback\t= UI_BotSelectMenu_BackEvent;\n\tbotSelectInfo.back.generic.x\t\t= 0;\n\tbotSelectInfo.back.generic.y\t\t= 480-64;\n\tbotSelectInfo.back.width\t\t\t= 128;\n\tbotSelectInfo.back.height\t\t\t= 64;\n\tbotSelectInfo.back.focuspic\t\t\t= BOTSELECT_BACK1;\n\n\tbotSelectInfo.go.generic.type\t\t= MTYPE_BITMAP;\n\tbotSelectInfo.go.generic.name\t\t= BOTSELECT_ACCEPT0;\n\tbotSelectInfo.go.generic.flags\t\t= QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;\n\tbotSelectInfo.go.generic.callback\t= UI_BotSelectMenu_SelectEvent;\n\tbotSelectInfo.go.generic.x\t\t\t= 640;\n\tbotSelectInfo.go.generic.y\t\t\t= 480-64;\n\tbotSelectInfo.go.width\t\t\t\t= 128;\n\tbotSelectInfo.go.height\t\t\t\t= 64;\n\tbotSelectInfo.go.focuspic\t\t\t= BOTSELECT_ACCEPT1;\n\n\tMenu_AddItem( &botSelectInfo.menu, &botSelectInfo.banner );\n\tfor( i = 0; i < MAX_MODELSPERPAGE; i++ ) {\n\t\tMenu_AddItem( &botSelectInfo.menu,\t&botSelectInfo.pics[i] );\n\t\tMenu_AddItem( &botSelectInfo.menu,\t&botSelectInfo.picbuttons[i] );\n\t\tMenu_AddItem( &botSelectInfo.menu,\t&botSelectInfo.picnames[i] );\n\t}\n\tMenu_AddItem( &botSelectInfo.menu, &botSelectInfo.arrows );\n\tMenu_AddItem( &botSelectInfo.menu, &botSelectInfo.left );\n\tMenu_AddItem( &botSelectInfo.menu, &botSelectInfo.right );\n\tMenu_AddItem( &botSelectInfo.menu, &botSelectInfo.back );\n\tMenu_AddItem( &botSelectInfo.menu, &botSelectInfo.go );\n\n\tUI_BotSelectMenu_BuildList();\n\tUI_BotSelectMenu_Default( bot );\n\tbotSelectInfo.modelpage = botSelectInfo.selectedmodel / MAX_MODELSPERPAGE;\n\tUI_BotSelectMenu_UpdateGrid();\n}\n\n\n/*\n=================\nUI_BotSelectMenu\n=================\n*/\nvoid UI_BotSelectMenu( char *bot ) {\n\tUI_BotSelectMenu_Init( bot );\n\tUI_PushMenu( &botSelectInfo.menu );\n}\n"
  },
  {
    "path": "src/q3_ui/ui_syscalls.asm",
    "content": "code\n\nequ\ttrap_Error\t\t\t\t\t\t\t\t-1\nequ\ttrap_Print\t\t\t\t\t\t\t\t-2\nequ\ttrap_Milliseconds\t\t\t\t\t\t-3\nequ\ttrap_Cvar_Set\t\t\t\t\t\t\t-4\nequ\ttrap_Cvar_VariableValue\t\t\t\t\t-5\nequ\ttrap_Cvar_VariableStringBuffer\t\t\t-6\nequ\ttrap_Cvar_SetValue\t\t\t\t\t\t-7\nequ\ttrap_Cvar_Reset\t\t\t\t\t\t\t-8\nequ\ttrap_Cvar_Create\t\t\t\t\t\t-9\nequ\ttrap_Cvar_InfoStringBuffer\t\t\t\t-10\nequ\ttrap_Argc\t\t\t\t\t\t\t\t-11\nequ\ttrap_Argv\t\t\t\t\t\t\t\t-12\nequ\ttrap_Cmd_ExecuteText\t\t\t\t\t-13\nequ\ttrap_FS_FOpenFile\t\t\t\t\t\t-14\nequ\ttrap_FS_Read\t\t\t\t\t\t\t-15\nequ\ttrap_FS_Write\t\t\t\t\t\t\t-16\nequ\ttrap_FS_FCloseFile\t\t\t\t\t\t-17\nequ\ttrap_FS_GetFileList\t\t\t\t\t\t-18\nequ\ttrap_R_RegisterModel\t\t\t\t\t-19\nequ\ttrap_R_RegisterSkin\t\t\t\t\t\t-20\nequ\ttrap_R_RegisterShaderNoMip\t\t\t\t-21\nequ\ttrap_R_ClearScene\t\t\t\t\t\t-22\nequ\ttrap_R_AddRefEntityToScene\t\t\t\t-23\nequ\ttrap_R_AddPolyToScene\t\t\t\t\t-24\nequ\ttrap_R_AddLightToScene\t\t\t\t\t-25\nequ\ttrap_R_RenderScene\t\t\t\t\t\t-26\nequ\ttrap_R_SetColor\t\t\t\t\t\t\t-27\nequ\ttrap_R_DrawStretchPic\t\t\t\t\t-28\nequ\ttrap_UpdateScreen\t\t\t\t\t\t-29\nequ\ttrap_CM_LerpTag\t\t\t\t\t\t\t-30\nequ\ttrap_CM_LoadModel\t\t\t\t\t\t-31\nequ\ttrap_S_RegisterSound\t\t\t\t\t-32\nequ\ttrap_S_StartLocalSound\t\t\t\t\t-33\nequ\ttrap_Key_KeynumToStringBuf\t\t\t\t-34\nequ\ttrap_Key_GetBindingBuf\t\t\t\t\t-35\nequ\ttrap_Key_SetBinding\t\t\t\t\t\t-36\nequ\ttrap_Key_IsDown\t\t\t\t\t\t\t-37\nequ\ttrap_Key_GetOverstrikeMode\t\t\t\t-38\nequ\ttrap_Key_SetOverstrikeMode\t\t\t\t-39\nequ\ttrap_Key_ClearStates\t\t\t\t\t-40\nequ\ttrap_Key_GetCatcher\t\t\t\t\t\t-41\nequ\ttrap_Key_SetCatcher\t\t\t\t\t\t-42        \nequ\ttrap_GetClipboardData\t\t\t\t\t-43\nequ\ttrap_GetGlconfig\t\t\t\t\t\t-44\nequ\ttrap_GetClientState\t\t\t\t\t\t-45\nequ\ttrap_GetConfigString\t\t\t\t\t-46\nequ\ttrap_LAN_GetPingQueueCount\t\t\t\t-47\nequ\ttrap_LAN_ClearPing\t\t\t\t\t\t-48\nequ\ttrap_LAN_GetPing\t\t\t\t\t\t-49\nequ\ttrap_LAN_GetPingInfo\t\t\t\t\t-50\nequ\ttrap_Cvar_Register\t\t\t\t\t\t-51\nequ trap_Cvar_Update\t\t\t\t\t\t-52\nequ trap_MemoryRemaining\t\t\t\t\t-53\nequ\ttrap_GetCDKey\t\t\t\t\t\t\t-54\nequ\ttrap_SetCDKey\t\t\t\t\t\t\t-55\nequ trap_R_RegisterFont\t\t\t\t\t\t-56\nequ trap_R_ModelBounds\t\t\t\t\t\t-57\nequ trap_PC_AddGlobalDefine\t\t\t\t\t-58\nequ\ttrap_PC_LoadSource\t\t\t\t\t\t-59\nequ trap_PC_FreeSource\t\t\t\t\t\t-60\nequ trap_PC_ReadToken\t\t\t\t\t\t-61\nequ trap_PC_SourceFileAndLine\t\t\t\t-62\nequ trap_S_StopBackgroundTrack\t\t\t\t-63\nequ trap_S_StartBackgroundTrack\t\t\t\t-64\nequ trap_RealTime\t\t\t\t\t\t\t-65\nequ trap_LAN_GetServerCount\t\t\t\t\t-66\nequ trap_LAN_GetServerAddressString\t\t\t-67\nequ trap_LAN_GetServerInfo\t\t\t\t\t-68\nequ trap_LAN_MarkServerVisible \t\t\t\t-69\nequ trap_LAN_UpdateVisiblePings\t\t\t\t-70\nequ trap_LAN_ResetPings\t\t\t\t\t\t-71\nequ trap_LAN_LoadCachedServers\t\t\t\t-72\nequ trap_LAN_SaveCachedServers\t\t\t\t-73\nequ trap_LAN_AddServer\t\t\t\t\t\t-74\nequ trap_LAN_RemoveServer\t \t\t\t\t-75\nequ trap_CIN_PlayCinematic\t\t\t\t\t-76\nequ trap_CIN_StopCinematic\t\t\t\t\t-77\nequ trap_CIN_RunCinematic \t\t\t\t\t-78\nequ trap_CIN_DrawCinematic\t\t\t\t\t-79\nequ trap_CIN_SetExtents\t\t\t\t\t\t-80\nequ trap_R_RemapShader\t\t\t\t\t\t-81\nequ trap_VerifyCDKey\t\t\t\t\t\t-82\nequ trap_LAN_ServerStatus\t\t\t\t\t-83\nequ trap_LAN_GetServerPing\t\t\t\t\t-84\nequ trap_LAN_ServerIsVisible\t\t\t\t-85\nequ trap_LAN_CompareServers\t\t\t\t\t-86\nequ trap_FS_Seek\t\t-87\nequ trap_SetPbClStatus -88\n\nequ\tmemset\t\t\t\t\t\t-101\nequ\tmemcpy\t\t\t\t\t\t-102\nequ\tstrncpy\t\t\t\t\t\t-103\nequ\tsin\t\t\t\t\t\t\t-104\nequ\tcos\t\t\t\t\t\t\t-105\nequ\tatan2\t\t\t\t\t\t-106\nequ\tsqrt\t\t\t\t\t\t-107\nequ floor\t\t\t\t\t\t-108\nequ\tceil\t\t\t\t\t\t-109\n\n"
  },
  {
    "path": "src/q3_ui/ui_syscalls.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n#include \"ui_local.h\"\n\n// this file is only included when building a dll\n// syscalls.asm is included instead when building a qvm\n#ifdef Q3_VM\n#error \"Do not use in VM build\"\n#endif\n\nstatic intptr_t (QDECL *syscall)( intptr_t arg, ... ) = (intptr_t (QDECL *)( intptr_t, ...))-1;\n\nvoid dllEntry( intptr_t (QDECL *syscallptr)( intptr_t arg,... ) ) {\n\tsyscall = syscallptr;\n}\n\nint PASSFLOAT( float x ) {\n\tfloat\tfloatTemp;\n\tfloatTemp = x;\n\treturn *(int *)&floatTemp;\n}\n\nvoid trap_Print( const char *string ) {\n\tsyscall( UI_PRINT, string );\n}\n\nvoid trap_Error( const char *string ) {\n\tsyscall( UI_ERROR, string );\n}\n\nint trap_Milliseconds( void ) {\n\treturn syscall( UI_MILLISECONDS ); \n}\n\nvoid trap_Cvar_Register( vmCvar_t *cvar, const char *var_name, const char *value, int flags ) {\n\tsyscall( UI_CVAR_REGISTER, cvar, var_name, value, flags );\n}\n\nvoid trap_Cvar_Update( vmCvar_t *cvar ) {\n\tsyscall( UI_CVAR_UPDATE, cvar );\n}\n\nvoid trap_Cvar_Set( const char *var_name, const char *value ) {\n\tsyscall( UI_CVAR_SET, var_name, value );\n}\n\nfloat trap_Cvar_VariableValue( const char *var_name ) {\n\tint temp;\n\ttemp = syscall( UI_CVAR_VARIABLEVALUE, var_name );\n\treturn (*(float*)&temp);\n}\n\nvoid trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize ) {\n\tsyscall( UI_CVAR_VARIABLESTRINGBUFFER, var_name, buffer, bufsize );\n}\n\nvoid trap_Cvar_SetValue( const char *var_name, float value ) {\n\tsyscall( UI_CVAR_SETVALUE, var_name, PASSFLOAT( value ) );\n}\n\nvoid trap_Cvar_Reset( const char *name ) {\n\tsyscall( UI_CVAR_RESET, name ); \n}\n\nvoid trap_Cvar_Create( const char *var_name, const char *var_value, int flags ) {\n\tsyscall( UI_CVAR_CREATE, var_name, var_value, flags );\n}\n\nvoid trap_Cvar_InfoStringBuffer( int bit, char *buffer, int bufsize ) {\n\tsyscall( UI_CVAR_INFOSTRINGBUFFER, bit, buffer, bufsize );\n}\n\nint trap_Argc( void ) {\n\treturn syscall( UI_ARGC );\n}\n\nvoid trap_Argv( int n, char *buffer, int bufferLength ) {\n\tsyscall( UI_ARGV, n, buffer, bufferLength );\n}\n\nvoid trap_Cmd_ExecuteText( int exec_when, const char *text ) {\n\tsyscall( UI_CMD_EXECUTETEXT, exec_when, text );\n}\n\nint trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode ) {\n\treturn syscall( UI_FS_FOPENFILE, qpath, f, mode );\n}\n\nvoid trap_FS_Read( void *buffer, int len, fileHandle_t f ) {\n\tsyscall( UI_FS_READ, buffer, len, f );\n}\n\nvoid trap_FS_Write( const void *buffer, int len, fileHandle_t f ) {\n\tsyscall( UI_FS_WRITE, buffer, len, f );\n}\n\nvoid trap_FS_FCloseFile( fileHandle_t f ) {\n\tsyscall( UI_FS_FCLOSEFILE, f );\n}\n\nint trap_FS_GetFileList(  const char *path, const char *extension, char *listbuf, int bufsize ) {\n\treturn syscall( UI_FS_GETFILELIST, path, extension, listbuf, bufsize );\n}\n\nint trap_FS_Seek( fileHandle_t f, long offset, int origin ) {\n\treturn syscall( UI_FS_SEEK, f, offset, origin );\n}\n\nqhandle_t trap_R_RegisterModel( const char *name ) {\n\treturn syscall( UI_R_REGISTERMODEL, name );\n}\n\nqhandle_t trap_R_RegisterSkin( const char *name ) {\n\treturn syscall( UI_R_REGISTERSKIN, name );\n}\n\nvoid trap_R_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font) {\n\tsyscall( UI_R_REGISTERFONT, fontName, pointSize, font );\n}\n\nqhandle_t trap_R_RegisterShaderNoMip( const char *name ) {\n\treturn syscall( UI_R_REGISTERSHADERNOMIP, name );\n}\n\nvoid trap_R_ClearScene( void ) {\n\tsyscall( UI_R_CLEARSCENE );\n}\n\nvoid trap_R_AddRefEntityToScene( const refEntity_t *re ) {\n\tsyscall( UI_R_ADDREFENTITYTOSCENE, re );\n}\n\nvoid trap_R_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts ) {\n\tsyscall( UI_R_ADDPOLYTOSCENE, hShader, numVerts, verts );\n}\n\nvoid trap_R_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b ) {\n\tsyscall( UI_R_ADDLIGHTTOSCENE, org, PASSFLOAT(intensity), PASSFLOAT(r), PASSFLOAT(g), PASSFLOAT(b) );\n}\n\nvoid trap_R_RenderScene( const refdef_t *fd ) {\n\tsyscall( UI_R_RENDERSCENE, fd );\n}\n\nvoid trap_R_SetColor( const float *rgba ) {\n\tsyscall( UI_R_SETCOLOR, rgba );\n}\n\nvoid trap_R_DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, qhandle_t hShader ) {\n\tsyscall( UI_R_DRAWSTRETCHPIC, PASSFLOAT(x), PASSFLOAT(y), PASSFLOAT(w), PASSFLOAT(h), PASSFLOAT(s1), PASSFLOAT(t1), PASSFLOAT(s2), PASSFLOAT(t2), hShader );\n}\n\nvoid\ttrap_R_ModelBounds( clipHandle_t model, vec3_t mins, vec3_t maxs ) {\n\tsyscall( UI_R_MODELBOUNDS, model, mins, maxs );\n}\n\nvoid trap_UpdateScreen( void ) {\n\tsyscall( UI_UPDATESCREEN );\n}\n\nint trap_CM_LerpTag( orientation_t *tag, clipHandle_t mod, int startFrame, int endFrame, float frac, const char *tagName ) {\n\treturn syscall( UI_CM_LERPTAG, tag, mod, startFrame, endFrame, PASSFLOAT(frac), tagName );\n}\n\nvoid trap_S_StartLocalSound( sfxHandle_t sfx, int channelNum ) {\n\tsyscall( UI_S_STARTLOCALSOUND, sfx, channelNum );\n}\n\nsfxHandle_t\ttrap_S_RegisterSound( const char *sample, qboolean compressed ) {\n\treturn syscall( UI_S_REGISTERSOUND, sample, compressed );\n}\n\nvoid trap_Key_KeynumToStringBuf( int keynum, char *buf, int buflen ) {\n\tsyscall( UI_KEY_KEYNUMTOSTRINGBUF, keynum, buf, buflen );\n}\n\nvoid trap_Key_GetBindingBuf( int keynum, char *buf, int buflen ) {\n\tsyscall( UI_KEY_GETBINDINGBUF, keynum, buf, buflen );\n}\n\nvoid trap_Key_SetBinding( int keynum, const char *binding ) {\n\tsyscall( UI_KEY_SETBINDING, keynum, binding );\n}\n\nqboolean trap_Key_IsDown( int keynum ) {\n\treturn syscall( UI_KEY_ISDOWN, keynum );\n}\n\nqboolean trap_Key_GetOverstrikeMode( void ) {\n\treturn syscall( UI_KEY_GETOVERSTRIKEMODE );\n}\n\nvoid trap_Key_SetOverstrikeMode( qboolean state ) {\n\tsyscall( UI_KEY_SETOVERSTRIKEMODE, state );\n}\n\nvoid trap_Key_ClearStates( void ) {\n\tsyscall( UI_KEY_CLEARSTATES );\n}\n\nint trap_Key_GetCatcher( void ) {\n\treturn syscall( UI_KEY_GETCATCHER );\n}\n\nvoid trap_Key_SetCatcher( int catcher ) {\n\tsyscall( UI_KEY_SETCATCHER, catcher );\n}\n\nvoid trap_GetClipboardData( char *buf, int bufsize ) {\n\tsyscall( UI_GETCLIPBOARDDATA, buf, bufsize );\n}\n\nvoid trap_GetClientState( uiClientState_t *state ) {\n\tsyscall( UI_GETCLIENTSTATE, state );\n}\n\nvoid trap_GetGlconfig( glconfig_t *glconfig ) {\n\tsyscall( UI_GETGLCONFIG, glconfig );\n}\n\nint trap_GetConfigString( int index, char* buff, int buffsize ) {\n\treturn syscall( UI_GETCONFIGSTRING, index, buff, buffsize );\n}\n\nint\ttrap_LAN_GetServerCount( int source ) {\n\treturn syscall( UI_LAN_GETSERVERCOUNT, source );\n}\n\nvoid trap_LAN_GetServerAddressString( int source, int n, char *buf, int buflen ) {\n\tsyscall( UI_LAN_GETSERVERADDRESSSTRING, source, n, buf, buflen );\n}\n\nvoid trap_LAN_GetServerInfo( int source, int n, char *buf, int buflen ) {\n\tsyscall( UI_LAN_GETSERVERINFO, source, n, buf, buflen );\n}\n\nint trap_LAN_GetServerPing( int source, int n ) {\n\treturn syscall( UI_LAN_GETSERVERPING, source, n );\n}\n\nint trap_LAN_GetPingQueueCount( void ) {\n\treturn syscall( UI_LAN_GETPINGQUEUECOUNT );\n}\n\nint trap_LAN_ServerStatus( const char *serverAddress, char *serverStatus, int maxLen ) {\n\treturn syscall( UI_LAN_SERVERSTATUS, serverAddress, serverStatus, maxLen );\n}\n\nvoid trap_LAN_SaveCachedServers() {\n\tsyscall( UI_LAN_SAVECACHEDSERVERS );\n}\n\nvoid trap_LAN_LoadCachedServers() {\n\tsyscall( UI_LAN_LOADCACHEDSERVERS );\n}\n\nvoid trap_LAN_ResetPings(int n) {\n\tsyscall( UI_LAN_RESETPINGS, n );\n}\n\nvoid trap_LAN_ClearPing( int n ) {\n\tsyscall( UI_LAN_CLEARPING, n );\n}\n\nvoid trap_LAN_GetPing( int n, char *buf, int buflen, int *pingtime ) {\n\tsyscall( UI_LAN_GETPING, n, buf, buflen, pingtime );\n}\n\nvoid trap_LAN_GetPingInfo( int n, char *buf, int buflen ) {\n\tsyscall( UI_LAN_GETPINGINFO, n, buf, buflen );\n}\n\nvoid trap_LAN_MarkServerVisible( int source, int n, qboolean visible ) {\n\tsyscall( UI_LAN_MARKSERVERVISIBLE, source, n, visible );\n}\n\nint trap_LAN_ServerIsVisible( int source, int n) {\n\treturn syscall( UI_LAN_SERVERISVISIBLE, source, n );\n}\n\nqboolean trap_LAN_UpdateVisiblePings( int source ) {\n\treturn syscall( UI_LAN_UPDATEVISIBLEPINGS, source );\n}\n\nint trap_LAN_AddServer(int source, const char *name, const char *addr) {\n\treturn syscall( UI_LAN_ADDSERVER, source, name, addr );\n}\n\nvoid trap_LAN_RemoveServer(int source, const char *addr) {\n\tsyscall( UI_LAN_REMOVESERVER, source, addr );\n}\n\nint trap_LAN_CompareServers( int source, int sortKey, int sortDir, int s1, int s2 ) {\n\treturn syscall( UI_LAN_COMPARESERVERS, source, sortKey, sortDir, s1, s2 );\n}\n\nint trap_MemoryRemaining( void ) {\n\treturn syscall( UI_MEMORY_REMAINING );\n}\n\nvoid trap_GetCDKey( char *buf, int buflen ) {\n\tsyscall( UI_GET_CDKEY, buf, buflen );\n}\n\nvoid trap_SetCDKey( char *buf ) {\n\tsyscall( UI_SET_CDKEY, buf );\n}\n\nint trap_PC_AddGlobalDefine( char *define ) {\n\treturn syscall( UI_PC_ADD_GLOBAL_DEFINE, define );\n}\n\nint trap_PC_LoadSource( const char *filename ) {\n\treturn syscall( UI_PC_LOAD_SOURCE, filename );\n}\n\nint trap_PC_FreeSource( int handle ) {\n\treturn syscall( UI_PC_FREE_SOURCE, handle );\n}\n\nint trap_PC_ReadToken( int handle, pc_token_t *pc_token ) {\n\treturn syscall( UI_PC_READ_TOKEN, handle, pc_token );\n}\n\nint trap_PC_SourceFileAndLine( int handle, char *filename, int *line ) {\n\treturn syscall( UI_PC_SOURCE_FILE_AND_LINE, handle, filename, line );\n}\n\nvoid trap_S_StopBackgroundTrack( void ) {\n\tsyscall( UI_S_STOPBACKGROUNDTRACK );\n}\n\nvoid trap_S_StartBackgroundTrack( const char *intro, const char *loop) {\n\tsyscall( UI_S_STARTBACKGROUNDTRACK, intro, loop );\n}\n\nint trap_RealTime(qtime_t *qtime) {\n\treturn syscall( UI_REAL_TIME, qtime );\n}\n\n// this returns a handle.  arg0 is the name in the format \"idlogo.roq\", set arg1 to NULL, alteredstates to qfalse (do not alter gamestate)\nint trap_CIN_PlayCinematic( const char *arg0, int xpos, int ypos, int width, int height, int bits) {\n  return syscall(UI_CIN_PLAYCINEMATIC, arg0, xpos, ypos, width, height, bits);\n}\n \n// stops playing the cinematic and ends it.  should always return FMV_EOF\n// cinematics must be stopped in reverse order of when they are started\ne_status trap_CIN_StopCinematic(int handle) {\n  return syscall(UI_CIN_STOPCINEMATIC, handle);\n}\n\n\n// will run a frame of the cinematic but will not draw it.  Will return FMV_EOF if the end of the cinematic has been reached.\ne_status trap_CIN_RunCinematic (int handle) {\n  return syscall(UI_CIN_RUNCINEMATIC, handle);\n}\n \n\n// draws the current frame\nvoid trap_CIN_DrawCinematic (int handle) {\n  syscall(UI_CIN_DRAWCINEMATIC, handle);\n}\n \n\n// allows you to resize the animation dynamically\nvoid trap_CIN_SetExtents (int handle, int x, int y, int w, int h) {\n  syscall(UI_CIN_SETEXTENTS, handle, x, y, w, h);\n}\n\n\nvoid\ttrap_R_RemapShader( const char *oldShader, const char *newShader, const char *timeOffset ) {\n\tsyscall( UI_R_REMAP_SHADER, oldShader, newShader, timeOffset );\n}\n\nqboolean trap_VerifyCDKey( const char *key, const char *chksum) {\n\treturn syscall( UI_VERIFY_CDKEY, key, chksum);\n}\n\nvoid trap_SetPbClStatus( int status ) {\n\tsyscall( UI_SET_PBCLSTATUS, status );\n}\n"
  },
  {
    "path": "src/q3_ui/ui_team.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n//\n// ui_team.c\n//\n\n#include \"ui_local.h\"\n\n\n#define TEAMMAIN_FRAME\t\"menu/art/cut_frame\"\n\n#define ID_JOINRED\t\t100\n#define ID_JOINBLUE\t\t101\n#define ID_JOINGAME\t\t102\n#define ID_SPECTATE\t\t103\n\n\ntypedef struct\n{\n\tmenuframework_s\tmenu;\n\tmenubitmap_s\tframe;\n\tmenutext_s\t\tjoinred;\n\tmenutext_s\t\tjoinblue;\n\tmenutext_s\t\tjoingame;\n\tmenutext_s\t\tspectate;\n} teammain_t;\n\nstatic teammain_t\ts_teammain;\n\n// bk001204 - unused\n//static menuframework_s\ts_teammain_menu;\n//static menuaction_s\t\ts_teammain_orders;\n//static menuaction_s\t\ts_teammain_voice;\n//static menuaction_s\t\ts_teammain_joinred;\n//static menuaction_s\t\ts_teammain_joinblue;\n//static menuaction_s\t\ts_teammain_joingame;\n//static menuaction_s\t\ts_teammain_spectate;\n\n\n/*\n===============\nTeamMain_MenuEvent\n===============\n*/\nstatic void TeamMain_MenuEvent( void* ptr, int event ) {\n\tif( event != QM_ACTIVATED ) {\n\t\treturn;\n\t}\n\n\tswitch( ((menucommon_s*)ptr)->id ) {\n\tcase ID_JOINRED:\n\t\ttrap_Cmd_ExecuteText( EXEC_APPEND, \"cmd team red\\n\" );\n\t\tUI_ForceMenuOff();\n\t\tbreak;\n\n\tcase ID_JOINBLUE:\n\t\ttrap_Cmd_ExecuteText( EXEC_APPEND, \"cmd team blue\\n\" );\n\t\tUI_ForceMenuOff();\n\t\tbreak;\n\n\tcase ID_JOINGAME:\n\t\ttrap_Cmd_ExecuteText( EXEC_APPEND, \"cmd team free\\n\" );\n\t\tUI_ForceMenuOff();\n\t\tbreak;\n\n\tcase ID_SPECTATE:\n\t\ttrap_Cmd_ExecuteText( EXEC_APPEND, \"cmd team spectator\\n\" );\n\t\tUI_ForceMenuOff();\n\t\tbreak;\n\t}\n}\n\n\n/*\n===============\nTeamMain_MenuInit\n===============\n*/\nvoid TeamMain_MenuInit( void ) {\n\tint\t\ty;\n\tint\t\tgametype;\n\tchar\tinfo[MAX_INFO_STRING];\n\n\tmemset( &s_teammain, 0, sizeof(s_teammain) );\n\n\tTeamMain_Cache();\n\n\ts_teammain.menu.wrapAround = qtrue;\n\ts_teammain.menu.fullscreen = qfalse;\n\n\ts_teammain.frame.generic.type   = MTYPE_BITMAP;\n\ts_teammain.frame.generic.flags\t= QMF_INACTIVE;\n\ts_teammain.frame.generic.name   = TEAMMAIN_FRAME;\n\ts_teammain.frame.generic.x\t\t= 142;\n\ts_teammain.frame.generic.y\t\t= 118;\n\ts_teammain.frame.width\t\t\t= 359;\n\ts_teammain.frame.height\t\t\t= 256;\n\n\ty = 194;\n\n\ts_teammain.joinred.generic.type     = MTYPE_PTEXT;\n\ts_teammain.joinred.generic.flags    = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_teammain.joinred.generic.id       = ID_JOINRED;\n\ts_teammain.joinred.generic.callback = TeamMain_MenuEvent;\n\ts_teammain.joinred.generic.x        = 320;\n\ts_teammain.joinred.generic.y        = y;\n\ts_teammain.joinred.string           = \"JOIN RED\";\n\ts_teammain.joinred.style            = UI_CENTER|UI_SMALLFONT;\n\ts_teammain.joinred.color            = colorRed;\n\ty += 20;\n\n\ts_teammain.joinblue.generic.type     = MTYPE_PTEXT;\n\ts_teammain.joinblue.generic.flags    = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_teammain.joinblue.generic.id       = ID_JOINBLUE;\n\ts_teammain.joinblue.generic.callback = TeamMain_MenuEvent;\n\ts_teammain.joinblue.generic.x        = 320;\n\ts_teammain.joinblue.generic.y        = y;\n\ts_teammain.joinblue.string           = \"JOIN BLUE\";\n\ts_teammain.joinblue.style            = UI_CENTER|UI_SMALLFONT;\n\ts_teammain.joinblue.color            = colorRed;\n\ty += 20;\n\n\ts_teammain.joingame.generic.type     = MTYPE_PTEXT;\n\ts_teammain.joingame.generic.flags    = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_teammain.joingame.generic.id       = ID_JOINGAME;\n\ts_teammain.joingame.generic.callback = TeamMain_MenuEvent;\n\ts_teammain.joingame.generic.x        = 320;\n\ts_teammain.joingame.generic.y        = y;\n\ts_teammain.joingame.string           = \"JOIN GAME\";\n\ts_teammain.joingame.style            = UI_CENTER|UI_SMALLFONT;\n\ts_teammain.joingame.color            = colorRed;\n\ty += 20;\n\n\ts_teammain.spectate.generic.type     = MTYPE_PTEXT;\n\ts_teammain.spectate.generic.flags    = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_teammain.spectate.generic.id       = ID_SPECTATE;\n\ts_teammain.spectate.generic.callback = TeamMain_MenuEvent;\n\ts_teammain.spectate.generic.x        = 320;\n\ts_teammain.spectate.generic.y        = y;\n\ts_teammain.spectate.string           = \"SPECTATE\";\n\ts_teammain.spectate.style            = UI_CENTER|UI_SMALLFONT;\n\ts_teammain.spectate.color            = colorRed;\n\ty += 20;\n\n\ttrap_GetConfigString(CS_SERVERINFO, info, MAX_INFO_STRING);   \n\tgametype = atoi( Info_ValueForKey( info,\"g_gametype\" ) );\n\t\t\t      \n\t// set initial states\n\tswitch( gametype ) {\n\tcase GT_SINGLE_PLAYER:\n\tcase GT_FFA:\n\tcase GT_TOURNAMENT:\n\t\ts_teammain.joinred.generic.flags  |= QMF_GRAYED;\n\t\ts_teammain.joinblue.generic.flags |= QMF_GRAYED;\n\t\tbreak;\n\n\tdefault:\n\tcase GT_TEAM:\n\tcase GT_CTF:\n\t\ts_teammain.joingame.generic.flags |= QMF_GRAYED;\n\t\tbreak;\n\t}\n\n\tMenu_AddItem( &s_teammain.menu, (void*) &s_teammain.frame );\n\tMenu_AddItem( &s_teammain.menu, (void*) &s_teammain.joinred );\n\tMenu_AddItem( &s_teammain.menu, (void*) &s_teammain.joinblue );\n\tMenu_AddItem( &s_teammain.menu, (void*) &s_teammain.joingame );\n\tMenu_AddItem( &s_teammain.menu, (void*) &s_teammain.spectate );\n}\n\n\n/*\n===============\nTeamMain_Cache\n===============\n*/\nvoid TeamMain_Cache( void ) {\n\ttrap_R_RegisterShaderNoMip( TEAMMAIN_FRAME );\n}\n\n\n/*\n===============\nUI_TeamMainMenu\n===============\n*/\nvoid UI_TeamMainMenu( void ) {\n\tTeamMain_MenuInit();\n\tUI_PushMenu ( &s_teammain.menu );\n}\n"
  },
  {
    "path": "src/q3_ui/ui_teamorders.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n/*\n=======================================================================\n\nTEAM ORDERS MENU\n\n=======================================================================\n*/\n\n\n#include \"ui_local.h\"\n\n\n#define ART_FRAME\t\t\"menu/art/addbotframe\"\n#define ART_BACK0\t\t\"menu/art/back_0\"\n#define ART_BACK1\t\t\"menu/art/back_1\"\t\n\n#define ID_LIST_BOTS\t\t10\n#define ID_LIST_CTF_ORDERS\t11\n#define ID_LIST_TEAM_ORDERS\t12\n\n\ntypedef struct {\n\tmenuframework_s\tmenu;\n\n\tmenutext_s\t\tbanner;\n\tmenubitmap_s\tframe;\n\n\tmenulist_s\t\tlist;\n\n\tmenubitmap_s\tback;\n\n\tint\t\t\t\tgametype;\n\tint\t\t\t\tnumBots;\n\tint\t\t\t\tselectedBot;\n\tchar\t\t\t*bots[9];\n\tchar\t\t\tbotNames[9][16];\n} teamOrdersMenuInfo_t;\n\nstatic teamOrdersMenuInfo_t\tteamOrdersMenuInfo;\n\n#define NUM_CTF_ORDERS\t\t7\nstatic const char *ctfOrders[] = {\n\t\"I Am the Leader\",\n\t\"Defend the Base\",\n\t\"Follow Me\",\n\t\"Get Enemy Flag\",\n\t\"Camp Here\",\n\t\"Report\",\n\t\"I Relinquish Command\",\n\tNULL\n};\nstatic const char *ctfMessages[] = {\n\t\"i am the leader\",\n\t\"%s defend the base\",\n\t\"%s follow me\",\n\t\"%s get enemy flag\",\n\t\"%s camp here\",\n\t\"%s report\",\n\t\"i stop being the leader\",\n\tNULL\n};\n\n#define NUM_TEAM_ORDERS\t\t6\nstatic const char *teamOrders[] = {\n\t\"I Am the Leader\",\n\t\"Follow Me\",\n\t\"Roam\",\n\t\"Camp Here\",\n\t\"Report\",\n\t\"I Relinquish Command\",\n\tNULL\n};\nstatic const char *teamMessages[] = {\n\t\"i am the leader\",\n\t\"%s follow me\",\n\t\"%s roam\",\n\t\"%s camp here\",\n\t\"%s report\",\n\t\"i stop being the leader\",\n\tNULL\n};\n\n\n/*\n===============\nUI_TeamOrdersMenu_BackEvent\n===============\n*/\nstatic void UI_TeamOrdersMenu_BackEvent( void *ptr, int event ) {\n\tif( event != QM_ACTIVATED ) {\n\t\treturn;\n\t}\n\tUI_PopMenu();\n}\n\n\n/*\n===============\nUI_TeamOrdersMenu_SetList\n===============\n*/\nstatic void UI_TeamOrdersMenu_SetList( int id ) {\n\tswitch( id ) {\n\tdefault:\n\tcase ID_LIST_BOTS:\n\t\tteamOrdersMenuInfo.list.generic.id = id;\n\t\tteamOrdersMenuInfo.list.numitems = teamOrdersMenuInfo.numBots;\n\t\tteamOrdersMenuInfo.list.itemnames = (const char **)teamOrdersMenuInfo.bots;\n\t\t break;\n\n\tcase ID_LIST_CTF_ORDERS:\n\t\tteamOrdersMenuInfo.list.generic.id = id;\n\t\tteamOrdersMenuInfo.list.numitems = NUM_CTF_ORDERS;\n\t\tteamOrdersMenuInfo.list.itemnames = ctfOrders;\n\t\tbreak;\n\n\tcase ID_LIST_TEAM_ORDERS:\n\t\tteamOrdersMenuInfo.list.generic.id = id;\n\t\tteamOrdersMenuInfo.list.numitems = NUM_TEAM_ORDERS;\n\t\tteamOrdersMenuInfo.list.itemnames = teamOrders;\n\t\tbreak;\n\t}\n\n\tteamOrdersMenuInfo.list.generic.bottom = teamOrdersMenuInfo.list.generic.top + teamOrdersMenuInfo.list.numitems * PROP_HEIGHT;\n}\n\n\n/*\n=================\nUI_TeamOrdersMenu_Key\n=================\n*/\nsfxHandle_t UI_TeamOrdersMenu_Key( int key ) {\n\tmenulist_s\t*l;\n\tint\tx;\n\tint\ty;\n\tint\tindex;\n\n\tl = (menulist_s\t*)Menu_ItemAtCursor( &teamOrdersMenuInfo.menu );\n\tif( l != &teamOrdersMenuInfo.list ) {\n\t\treturn Menu_DefaultKey( &teamOrdersMenuInfo.menu, key );\n\t}\n\n\tswitch( key ) {\n\t\tcase K_MOUSE1:\n\t\t\tx = l->generic.left;\n\t\t\ty = l->generic.top;\n\t\t\tif( UI_CursorInRect( x, y, l->generic.right - x, l->generic.bottom - y ) ) {\n\t\t\t\tindex = (uis.cursory - y) / PROP_HEIGHT;\n\t\t\t\tl->oldvalue = l->curvalue;\n\t\t\t\tl->curvalue = index;\n\n\t\t\t\tif( l->generic.callback ) {\n\t\t\t\t\tl->generic.callback( l, QM_ACTIVATED );\n\t\t\t\t\treturn menu_move_sound;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn menu_null_sound;\n\n\t\tcase K_KP_UPARROW:\n\t\tcase K_UPARROW:\n\t\t\tl->oldvalue = l->curvalue;\n\n\t\t\tif( l->curvalue == 0 ) {\n\t\t\t\tl->curvalue = l->numitems - 1;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tl->curvalue--;\n\t\t\t}\n\t\t\treturn menu_move_sound;\n\n\t\tcase K_KP_DOWNARROW:\n\t\tcase K_DOWNARROW:\n\t\t\tl->oldvalue = l->curvalue;\n\n\t\t\tif( l->curvalue == l->numitems - 1 ) {\n\t\t\t\tl->curvalue = 0;;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tl->curvalue++;\n\t\t\t}\n\t\t\treturn menu_move_sound;\n\t}\n\n\treturn Menu_DefaultKey( &teamOrdersMenuInfo.menu, key );\n}\n\n\n/*\n=================\nUI_TeamOrdersMenu_ListDraw\n=================\n*/\nstatic void UI_TeamOrdersMenu_ListDraw( void *self ) {\n\tmenulist_s\t*l;\n\tint\t\t\tx;\n\tint\t\t\ty;\n\tint\t\t\ti;\n\tfloat\t\t*color;\n\tqboolean\thasfocus;\n\tint\t\t\tstyle;\n\n\tl = (menulist_s *)self;\n\n\thasfocus = (l->generic.parent->cursor == l->generic.menuPosition);\n\n\tx =\t320;//l->generic.x;\n\ty =\tl->generic.y;\n\tfor( i = 0; i < l->numitems; i++ ) {\n\t\tstyle = UI_LEFT|UI_SMALLFONT|UI_CENTER;\n\t\tif( i == l->curvalue ) {\n\t\t\tcolor = color_yellow;\n\t\t\tif( hasfocus ) {\n\t\t\t\tstyle |= UI_PULSE;\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tcolor = color_orange;\n\t\t}\n\n\t\tUI_DrawProportionalString( x, y, l->itemnames[i], style, color );\n\t\ty += PROP_HEIGHT;\n\t}\n}\n\n\n/*\n===============\nUI_TeamOrdersMenu_ListEvent\n===============\n*/\nstatic void UI_TeamOrdersMenu_ListEvent( void *ptr, int event ) {\n\tint\t\tid;\n\tint\t\tselection;\n\tchar\tmessage[256];\n\n\tif (event != QM_ACTIVATED)\n\t\treturn;\n\n\tid = ((menulist_s *)ptr)->generic.id;\n\tselection = ((menulist_s *)ptr)->curvalue;\n\n\tif( id == ID_LIST_BOTS ) {\n\t\tteamOrdersMenuInfo.selectedBot = selection;\n\t\tif( teamOrdersMenuInfo.gametype == GT_CTF ) {\n\t\t\tUI_TeamOrdersMenu_SetList( ID_LIST_CTF_ORDERS );\n\t\t}\n\t\telse {\n\t\t\tUI_TeamOrdersMenu_SetList( ID_LIST_TEAM_ORDERS );\n\t\t}\n\t\treturn;\n\t}\n\n\tif( id == ID_LIST_CTF_ORDERS ) {\n\t\tCom_sprintf( message, sizeof(message), ctfMessages[selection], teamOrdersMenuInfo.botNames[teamOrdersMenuInfo.selectedBot] );\n\t}\n\telse {\n\t\tCom_sprintf( message, sizeof(message), teamMessages[selection], teamOrdersMenuInfo.botNames[teamOrdersMenuInfo.selectedBot] );\n\t}\n\n\ttrap_Cmd_ExecuteText( EXEC_APPEND, va( \"say_team \\\"%s\\\"\\n\", message ) );\n\tUI_PopMenu();\n}\n\n\n/*\n===============\nUI_TeamOrdersMenu_BuildBotList\n===============\n*/\nstatic void UI_TeamOrdersMenu_BuildBotList( void ) {\n\tuiClientState_t\tcs;\n\tint\t\tnumPlayers;\n\tint\t\tisBot;\n\tint\t\tn;\n\tchar\tplayerTeam;\n\tchar\tbotTeam;\n\tchar\tinfo[MAX_INFO_STRING];\n\n\tfor( n = 0; n < 9; n++ ) {\n\t\tteamOrdersMenuInfo.bots[n] = teamOrdersMenuInfo.botNames[n];\n\t}\n\n\ttrap_GetClientState( &cs );\n\n\tQ_strncpyz( teamOrdersMenuInfo.botNames[0], \"Everyone\", 16 );\n\tteamOrdersMenuInfo.numBots = 1;\n\n\ttrap_GetConfigString( CS_SERVERINFO, info, sizeof(info) );\n\tnumPlayers = atoi( Info_ValueForKey( info, \"sv_maxclients\" ) );\n\tteamOrdersMenuInfo.gametype = atoi( Info_ValueForKey( info, \"g_gametype\" ) );\n\n\tfor( n = 0; n < numPlayers && teamOrdersMenuInfo.numBots < 9; n++ ) {\n\t\ttrap_GetConfigString( CS_PLAYERS + n, info, MAX_INFO_STRING );\n\n\t\tplayerTeam = TEAM_SPECTATOR; // bk001204 = possible uninit use\n\n\t\tif( n == cs.clientNum ) {\n\t\t\tplayerTeam = *Info_ValueForKey( info, \"t\" );\n\t\t\tcontinue;\n\t\t}\n\n\t\tisBot = atoi( Info_ValueForKey( info, \"skill\" ) );\n\t\tif( !isBot ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tbotTeam = *Info_ValueForKey( info, \"t\" );\n\t\tif( botTeam != playerTeam ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tQ_strncpyz( teamOrdersMenuInfo.botNames[teamOrdersMenuInfo.numBots], Info_ValueForKey( info, \"n\" ), 16 );\n\t\tQ_CleanStr( teamOrdersMenuInfo.botNames[teamOrdersMenuInfo.numBots] );\n\t\tteamOrdersMenuInfo.numBots++;\n\t}\n}\n\n\n/*\n===============\nUI_TeamOrdersMenu_Init\n===============\n*/\nstatic void UI_TeamOrdersMenu_Init( void ) {\n\tUI_TeamOrdersMenu_Cache();\n\n\tmemset( &teamOrdersMenuInfo, 0, sizeof(teamOrdersMenuInfo) );\n\tteamOrdersMenuInfo.menu.fullscreen = qfalse;\n\tteamOrdersMenuInfo.menu.key = UI_TeamOrdersMenu_Key;\n\n\tUI_TeamOrdersMenu_BuildBotList();\n\n\tteamOrdersMenuInfo.banner.generic.type\t\t= MTYPE_BTEXT;\n\tteamOrdersMenuInfo.banner.generic.x\t\t\t= 320;\n\tteamOrdersMenuInfo.banner.generic.y\t\t\t= 16;\n\tteamOrdersMenuInfo.banner.string\t\t\t= \"TEAM ORDERS\";\n\tteamOrdersMenuInfo.banner.color\t\t\t\t= color_white;\n\tteamOrdersMenuInfo.banner.style\t\t\t\t= UI_CENTER;\n\n\tteamOrdersMenuInfo.frame.generic.type\t\t= MTYPE_BITMAP;\n\tteamOrdersMenuInfo.frame.generic.flags\t\t= QMF_INACTIVE;\n\tteamOrdersMenuInfo.frame.generic.name\t\t= ART_FRAME;\n\tteamOrdersMenuInfo.frame.generic.x\t\t\t= 320-233;\n\tteamOrdersMenuInfo.frame.generic.y\t\t\t= 240-166;\n\tteamOrdersMenuInfo.frame.width\t\t\t\t= 466;\n\tteamOrdersMenuInfo.frame.height\t\t\t\t= 332;\n\n\tteamOrdersMenuInfo.list.generic.type\t\t= MTYPE_SCROLLLIST;\n\tteamOrdersMenuInfo.list.generic.flags\t\t= QMF_PULSEIFFOCUS;\n\tteamOrdersMenuInfo.list.generic.ownerdraw\t= UI_TeamOrdersMenu_ListDraw;\n\tteamOrdersMenuInfo.list.generic.callback\t= UI_TeamOrdersMenu_ListEvent;\n\tteamOrdersMenuInfo.list.generic.x\t\t\t= 320-64;\n\tteamOrdersMenuInfo.list.generic.y\t\t\t= 120;\n\n\tteamOrdersMenuInfo.back.generic.type\t\t= MTYPE_BITMAP;\n\tteamOrdersMenuInfo.back.generic.name\t\t= ART_BACK0;\n\tteamOrdersMenuInfo.back.generic.flags\t\t= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\tteamOrdersMenuInfo.back.generic.callback\t= UI_TeamOrdersMenu_BackEvent;\n\tteamOrdersMenuInfo.back.generic.x\t\t\t= 0;\n\tteamOrdersMenuInfo.back.generic.y\t\t\t= 480-64;\n\tteamOrdersMenuInfo.back.width\t\t\t\t= 128;\n\tteamOrdersMenuInfo.back.height\t\t\t\t= 64;\n\tteamOrdersMenuInfo.back.focuspic\t\t\t= ART_BACK1;\n\n\tMenu_AddItem( &teamOrdersMenuInfo.menu, &teamOrdersMenuInfo.banner );\n\tMenu_AddItem( &teamOrdersMenuInfo.menu, &teamOrdersMenuInfo.frame );\n\tMenu_AddItem( &teamOrdersMenuInfo.menu, &teamOrdersMenuInfo.list );\n\tMenu_AddItem( &teamOrdersMenuInfo.menu, &teamOrdersMenuInfo.back );\n\n\tteamOrdersMenuInfo.list.generic.left = 220;\n\tteamOrdersMenuInfo.list.generic.top = teamOrdersMenuInfo.list.generic.y;\n\tteamOrdersMenuInfo.list.generic.right = 420;\n\tUI_TeamOrdersMenu_SetList( ID_LIST_BOTS );\n}\n\n\n/*\n=================\nUI_TeamOrdersMenu_Cache\n=================\n*/\nvoid UI_TeamOrdersMenu_Cache( void ) {\n\ttrap_R_RegisterShaderNoMip( ART_FRAME );\n\ttrap_R_RegisterShaderNoMip( ART_BACK0 );\n\ttrap_R_RegisterShaderNoMip( ART_BACK1 );\n}\n\n\n/*\n===============\nUI_TeamOrdersMenu\n===============\n*/\nvoid UI_TeamOrdersMenu( void ) {\n\tUI_TeamOrdersMenu_Init();\n\tUI_PushMenu( &teamOrdersMenuInfo.menu );\n}\n\n\n/*\n===============\nUI_TeamOrdersMenu_f\n===============\n*/\nvoid UI_TeamOrdersMenu_f( void ) {\n\tuiClientState_t\tcs;\n\tchar\tinfo[MAX_INFO_STRING];\n\tint\t\tteam;\n\n\t// make sure it's a team game\n\ttrap_GetConfigString( CS_SERVERINFO, info, sizeof(info) );\n\tteamOrdersMenuInfo.gametype = atoi( Info_ValueForKey( info, \"g_gametype\" ) );\n\tif( teamOrdersMenuInfo.gametype < GT_TEAM ) {\n\t\treturn;\n\t}\n\n\t// not available to spectators\n\ttrap_GetClientState( &cs );\n\ttrap_GetConfigString( CS_PLAYERS + cs.clientNum, info, MAX_INFO_STRING );\n\tteam = atoi( Info_ValueForKey( info, \"t\" ) );\n\tif( team == TEAM_SPECTATOR ) {\n\t\treturn;\n\t}\n\n\tUI_TeamOrdersMenu();\n}\n"
  },
  {
    "path": "src/q3_ui/ui_video.c",
    "content": "/*\n===========================================================================\nCopyright (C) 1999-2005 Id Software, Inc.\n\nThis file is part of Quake III Arena source code.\n\nQuake III Arena source code is free software; you can redistribute it\nand/or modify it under the terms of the GNU General Public License as\npublished by the Free Software Foundation; either version 2 of the License,\nor (at your option) any later version.\n\nQuake III Arena source code is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Foobar; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n===========================================================================\n*/\n//\n#include \"ui_local.h\"\n\nvoid GraphicsOptions_MenuInit( void );\n\n/*\n=======================================================================\n\nDRIVER INFORMATION MENU\n\n=======================================================================\n*/\n\n\n#define DRIVERINFO_FRAMEL\t\"menu/art/frame2_l\"\n#define DRIVERINFO_FRAMER\t\"menu/art/frame1_r\"\n#define DRIVERINFO_BACK0\t\"menu/art/back_0\"\n#define DRIVERINFO_BACK1\t\"menu/art/back_1\"\n\nstatic char* driverinfo_artlist[] = \n{\n\tDRIVERINFO_FRAMEL,\n\tDRIVERINFO_FRAMER,\n\tDRIVERINFO_BACK0,\n\tDRIVERINFO_BACK1,\n\tNULL,\n};\n\n#define ID_DRIVERINFOBACK\t100\n\ntypedef struct\n{\n\tmenuframework_s\tmenu;\n\tmenutext_s\t\tbanner;\n\tmenubitmap_s\tback;\n\tmenubitmap_s\tframel;\n\tmenubitmap_s\tframer;\n\tchar\t\t\tstringbuff[1024];\n\tchar*\t\t\tstrings[64];\n\tint\t\t\t\tnumstrings;\n} driverinfo_t;\n\nstatic driverinfo_t\ts_driverinfo;\n\n/*\n=================\nDriverInfo_Event\n=================\n*/\nstatic void DriverInfo_Event( void* ptr, int event )\n{\n\tif (event != QM_ACTIVATED)\n\t\treturn;\n\n\tswitch (((menucommon_s*)ptr)->id)\n\t{\n\t\tcase ID_DRIVERINFOBACK:\n\t\t\tUI_PopMenu();\n\t\t\tbreak;\n\t}\n}\n\n/*\n=================\nDriverInfo_MenuDraw\n=================\n*/\nstatic void DriverInfo_MenuDraw( void )\n{\n\tint\ti;\n\tint\ty;\n\n\tMenu_Draw( &s_driverinfo.menu );\n\n\tUI_DrawString( 320, 80, \"VENDOR\", UI_CENTER|UI_SMALLFONT, color_red );\n\tUI_DrawString( 320, 152, \"PIXELFORMAT\", UI_CENTER|UI_SMALLFONT, color_red );\n\tUI_DrawString( 320, 192, \"EXTENSIONS\", UI_CENTER|UI_SMALLFONT, color_red );\n\n\tUI_DrawString( 320, 80+16, uis.glconfig.vendor_string, UI_CENTER|UI_SMALLFONT, text_color_normal );\n\tUI_DrawString( 320, 96+16, uis.glconfig.version_string, UI_CENTER|UI_SMALLFONT, text_color_normal );\n\tUI_DrawString( 320, 112+16, uis.glconfig.renderer_string, UI_CENTER|UI_SMALLFONT, text_color_normal );\n\tUI_DrawString( 320, 152+16, va (\"color(%d-bits) Z(%d-bits) stencil(%d-bits)\", uis.glconfig.colorBits, uis.glconfig.depthBits, uis.glconfig.stencilBits), UI_CENTER|UI_SMALLFONT, text_color_normal );\n\n\t// double column\n\ty = 192+16;\n\tfor (i=0; i<s_driverinfo.numstrings/2; i++) {\n\t\tUI_DrawString( 320-4, y, s_driverinfo.strings[i*2], UI_RIGHT|UI_SMALLFONT, text_color_normal );\n\t\tUI_DrawString( 320+4, y, s_driverinfo.strings[i*2+1], UI_LEFT|UI_SMALLFONT, text_color_normal );\n\t\ty += SMALLCHAR_HEIGHT;\n\t}\n\n\tif (s_driverinfo.numstrings & 1)\n\t\tUI_DrawString( 320, y, s_driverinfo.strings[s_driverinfo.numstrings-1], UI_CENTER|UI_SMALLFONT, text_color_normal );\n}\n\n/*\n=================\nDriverInfo_Cache\n=================\n*/\nvoid DriverInfo_Cache( void )\n{\n\tint\ti;\n\n\t// touch all our pics\n\tfor (i=0; ;i++)\n\t{\n\t\tif (!driverinfo_artlist[i])\n\t\t\tbreak;\n\t\ttrap_R_RegisterShaderNoMip(driverinfo_artlist[i]);\n\t}\n}\n\n/*\n=================\nUI_DriverInfo_Menu\n=================\n*/\nstatic void UI_DriverInfo_Menu( void )\n{\n\tchar*\teptr;\n\tint\t\ti;\n\tint\t\tlen;\n\n\t// zero set all our globals\n\tmemset( &s_driverinfo, 0 ,sizeof(driverinfo_t) );\n\n\tDriverInfo_Cache();\n\n\ts_driverinfo.menu.fullscreen = qtrue;\n\ts_driverinfo.menu.draw       = DriverInfo_MenuDraw;\n\n\ts_driverinfo.banner.generic.type  = MTYPE_BTEXT;\n\ts_driverinfo.banner.generic.x\t  = 320;\n\ts_driverinfo.banner.generic.y\t  = 16;\n\ts_driverinfo.banner.string\t\t  = \"DRIVER INFO\";\n\ts_driverinfo.banner.color\t      = color_white;\n\ts_driverinfo.banner.style\t      = UI_CENTER;\n\n\ts_driverinfo.framel.generic.type  = MTYPE_BITMAP;\n\ts_driverinfo.framel.generic.name  = DRIVERINFO_FRAMEL;\n\ts_driverinfo.framel.generic.flags = QMF_INACTIVE;\n\ts_driverinfo.framel.generic.x\t  = 0;\n\ts_driverinfo.framel.generic.y\t  = 78;\n\ts_driverinfo.framel.width  \t      = 256;\n\ts_driverinfo.framel.height  \t  = 329;\n\n\ts_driverinfo.framer.generic.type  = MTYPE_BITMAP;\n\ts_driverinfo.framer.generic.name  = DRIVERINFO_FRAMER;\n\ts_driverinfo.framer.generic.flags = QMF_INACTIVE;\n\ts_driverinfo.framer.generic.x\t  = 376;\n\ts_driverinfo.framer.generic.y\t  = 76;\n\ts_driverinfo.framer.width  \t      = 256;\n\ts_driverinfo.framer.height  \t  = 334;\n\n\ts_driverinfo.back.generic.type\t   = MTYPE_BITMAP;\n\ts_driverinfo.back.generic.name     = DRIVERINFO_BACK0;\n\ts_driverinfo.back.generic.flags    = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_driverinfo.back.generic.callback = DriverInfo_Event;\n\ts_driverinfo.back.generic.id\t   = ID_DRIVERINFOBACK;\n\ts_driverinfo.back.generic.x\t\t   = 0;\n\ts_driverinfo.back.generic.y\t\t   = 480-64;\n\ts_driverinfo.back.width  \t\t   = 128;\n\ts_driverinfo.back.height  \t\t   = 64;\n\ts_driverinfo.back.focuspic         = DRIVERINFO_BACK1;\n\n  // TTimo: overflow with particularly long GL extensions (such as the gf3)\n  // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=399\n  // NOTE: could have pushed the size of stringbuff, but the list is already out of the screen\n  // (no matter what your resolution)\n  Q_strncpyz(s_driverinfo.stringbuff, uis.glconfig.extensions_string, 1024);\n\n\t// build null terminated extension strings\n\teptr = s_driverinfo.stringbuff;\n\twhile ( s_driverinfo.numstrings<40 && *eptr )\n\t{\n\t\twhile ( *eptr && *eptr == ' ' )\n\t\t\t*eptr++ = '\\0';\n\n\t\t// track start of valid string\n\t\tif (*eptr && *eptr != ' ')\n\t\t\ts_driverinfo.strings[s_driverinfo.numstrings++] = eptr;\n\n\t\twhile ( *eptr && *eptr != ' ' )\n\t\t\teptr++;\n\t}\n\n\t// safety length strings for display\n\tfor (i=0; i<s_driverinfo.numstrings; i++) {\n\t\tlen = (int)strlen(s_driverinfo.strings[i]);\n\t\tif (len > 32) {\n\t\t\ts_driverinfo.strings[i][len-1] = '>';\n\t\t\ts_driverinfo.strings[i][len]   = '\\0';\n\t\t}\n\t}\n\n\tMenu_AddItem( &s_driverinfo.menu, &s_driverinfo.banner );\n\tMenu_AddItem( &s_driverinfo.menu, &s_driverinfo.framel );\n\tMenu_AddItem( &s_driverinfo.menu, &s_driverinfo.framer );\n\tMenu_AddItem( &s_driverinfo.menu, &s_driverinfo.back );\n\n\tUI_PushMenu( &s_driverinfo.menu );\n}\n\n/*\n=======================================================================\n\nGRAPHICS OPTIONS MENU\n\n=======================================================================\n*/\n\n#define GRAPHICSOPTIONS_FRAMEL\t\"menu/art/frame2_l\"\n#define GRAPHICSOPTIONS_FRAMER\t\"menu/art/frame1_r\"\n#define GRAPHICSOPTIONS_BACK0\t\"menu/art/back_0\"\n#define GRAPHICSOPTIONS_BACK1\t\"menu/art/back_1\"\n#define GRAPHICSOPTIONS_ACCEPT0\t\"menu/art/accept_0\"\n#define GRAPHICSOPTIONS_ACCEPT1\t\"menu/art/accept_1\"\n\nstatic const char *s_drivers[] =\n{\n\tOPENGL_DRIVER_NAME,\n\t0\n};\n\n#define ID_BACK2\t\t101\n#define ID_FULLSCREEN\t102\n#define ID_LIST\t\t\t103\n#define ID_MODE\t\t\t104\n#define ID_DRIVERINFO\t105\n#define ID_GRAPHICS\t\t106\n#define ID_DISPLAY\t\t107\n#define ID_SOUND\t\t108\n#define ID_NETWORK\t\t109\n\ntypedef struct {\n\tmenuframework_s\tmenu;\n\n\tmenutext_s\t\tbanner;\n\tmenubitmap_s\tframel;\n\tmenubitmap_s\tframer;\n\n\tmenutext_s\t\tgraphics;\n\tmenutext_s\t\tdisplay;\n\tmenutext_s\t\tsound;\n\tmenutext_s\t\tnetwork;\n\n\tmenulist_s\t\tlist;\n\tmenulist_s\t\tmode;\n\tmenulist_s\t\tdriver;\n\tmenuslider_s\ttq;\n\tmenulist_s  \tfs;\n\tmenulist_s  \tlighting;\n\tmenulist_s  \tallow_extensions;\n\tmenulist_s  \ttexturebits;\n\tmenulist_s  \tcolordepth;\n\tmenulist_s  \tgeometry;\n\tmenulist_s  \tfilter;\n\tmenutext_s\t\tdriverinfo;\n\n\tmenubitmap_s\tapply;\n\tmenubitmap_s\tback;\n} graphicsoptions_t;\n\ntypedef struct\n{\n\tint mode;\n\tqboolean fullscreen;\n\tint tq;\n\tint lighting;\n\tint colordepth;\n\tint texturebits;\n\tint geometry;\n\tint filter;\n\tint driver;\n\tqboolean extensions;\n} InitialVideoOptions_s;\n\nstatic InitialVideoOptions_s\ts_ivo;\nstatic graphicsoptions_t\t\ts_graphicsoptions;\t\n\nstatic InitialVideoOptions_s s_ivo_templates[] =\n{\n\t{\n\t\t4, qtrue, 2, 0, 2, 2, 1, 1, 0, qtrue\t// JDC: this was tq 3\n\t},\n\t{\n\t\t3, qtrue, 2, 0, 0, 0, 1, 0, 0, qtrue\n\t},\n\t{\n\t\t2, qtrue, 1, 0, 1, 0, 0, 0, 0, qtrue\n\t},\n\t{\n\t\t2, qtrue, 1, 1, 1, 0, 0, 0, 0, qtrue\n\t},\n\t{\n\t\t3, qtrue, 1, 0, 0, 0, 1, 0, 0, qtrue\n\t}\n};\n\n#define NUM_IVO_TEMPLATES ( sizeof( s_ivo_templates ) / sizeof( s_ivo_templates[0] ) )\n\n/*\n=================\nGraphicsOptions_GetInitialVideo\n=================\n*/\nstatic void GraphicsOptions_GetInitialVideo( void )\n{\n\ts_ivo.colordepth  = s_graphicsoptions.colordepth.curvalue;\n\ts_ivo.driver      = s_graphicsoptions.driver.curvalue;\n\ts_ivo.mode        = s_graphicsoptions.mode.curvalue;\n\ts_ivo.fullscreen  = s_graphicsoptions.fs.curvalue;\n\ts_ivo.extensions  = s_graphicsoptions.allow_extensions.curvalue;\n\ts_ivo.tq          = s_graphicsoptions.tq.curvalue;\n\ts_ivo.lighting    = s_graphicsoptions.lighting.curvalue;\n\ts_ivo.geometry    = s_graphicsoptions.geometry.curvalue;\n\ts_ivo.filter      = s_graphicsoptions.filter.curvalue;\n\ts_ivo.texturebits = s_graphicsoptions.texturebits.curvalue;\n}\n\n/*\n=================\nGraphicsOptions_CheckConfig\n=================\n*/\nstatic void GraphicsOptions_CheckConfig( void )\n{\n\tint i;\n\n\tfor ( i = 0; i < NUM_IVO_TEMPLATES; i++ )\n\t{\n\t\tif ( s_ivo_templates[i].colordepth != s_graphicsoptions.colordepth.curvalue )\n\t\t\tcontinue;\n\t\tif ( s_ivo_templates[i].driver != s_graphicsoptions.driver.curvalue )\n\t\t\tcontinue;\n\t\tif ( s_ivo_templates[i].mode != s_graphicsoptions.mode.curvalue )\n\t\t\tcontinue;\n\t\tif ( s_ivo_templates[i].fullscreen != s_graphicsoptions.fs.curvalue )\n\t\t\tcontinue;\n\t\tif ( s_ivo_templates[i].tq != s_graphicsoptions.tq.curvalue )\n\t\t\tcontinue;\n\t\tif ( s_ivo_templates[i].lighting != s_graphicsoptions.lighting.curvalue )\n\t\t\tcontinue;\n\t\tif ( s_ivo_templates[i].geometry != s_graphicsoptions.geometry.curvalue )\n\t\t\tcontinue;\n\t\tif ( s_ivo_templates[i].filter != s_graphicsoptions.filter.curvalue )\n\t\t\tcontinue;\n//\t\tif ( s_ivo_templates[i].texturebits != s_graphicsoptions.texturebits.curvalue )\n//\t\t\tcontinue;\n\t\ts_graphicsoptions.list.curvalue = i;\n\t\treturn;\n\t}\n\ts_graphicsoptions.list.curvalue = 4;\n}\n\n/*\n=================\nGraphicsOptions_UpdateMenuItems\n=================\n*/\nstatic void GraphicsOptions_UpdateMenuItems( void )\n{\n\tif ( s_graphicsoptions.driver.curvalue == 1 )\n\t{\n\t\ts_graphicsoptions.fs.curvalue = 1;\n\t\ts_graphicsoptions.fs.generic.flags |= QMF_GRAYED;\n\t\ts_graphicsoptions.colordepth.curvalue = 1;\n\t}\n\telse\n\t{\n\t\ts_graphicsoptions.fs.generic.flags &= ~QMF_GRAYED;\n\t}\n\n\tif ( s_graphicsoptions.fs.curvalue == 0 || s_graphicsoptions.driver.curvalue == 1 )\n\t{\n\t\ts_graphicsoptions.colordepth.curvalue = 0;\n\t\ts_graphicsoptions.colordepth.generic.flags |= QMF_GRAYED;\n\t}\n\telse\n\t{\n\t\ts_graphicsoptions.colordepth.generic.flags &= ~QMF_GRAYED;\n\t}\n\n\tif ( s_graphicsoptions.allow_extensions.curvalue == 0 )\n\t{\n\t\tif ( s_graphicsoptions.texturebits.curvalue == 0 )\n\t\t{\n\t\t\ts_graphicsoptions.texturebits.curvalue = 1;\n\t\t}\n\t}\n\n\ts_graphicsoptions.apply.generic.flags |= QMF_HIDDEN|QMF_INACTIVE;\n\n\tif ( s_ivo.mode != s_graphicsoptions.mode.curvalue )\n\t{\n\t\ts_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);\n\t}\n\tif ( s_ivo.fullscreen != s_graphicsoptions.fs.curvalue )\n\t{\n\t\ts_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);\n\t}\n\tif ( s_ivo.extensions != s_graphicsoptions.allow_extensions.curvalue )\n\t{\n\t\ts_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);\n\t}\n\tif ( s_ivo.tq != s_graphicsoptions.tq.curvalue )\n\t{\n\t\ts_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);\n\t}\n\tif ( s_ivo.lighting != s_graphicsoptions.lighting.curvalue )\n\t{\n\t\ts_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);\n\t}\n\tif ( s_ivo.colordepth != s_graphicsoptions.colordepth.curvalue )\n\t{\n\t\ts_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);\n\t}\n\tif ( s_ivo.driver != s_graphicsoptions.driver.curvalue )\n\t{\n\t\ts_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);\n\t}\n\tif ( s_ivo.texturebits != s_graphicsoptions.texturebits.curvalue )\n\t{\n\t\ts_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);\n\t}\n\tif ( s_ivo.geometry != s_graphicsoptions.geometry.curvalue )\n\t{\n\t\ts_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);\n\t}\n\tif ( s_ivo.filter != s_graphicsoptions.filter.curvalue )\n\t{\n\t\ts_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);\n\t}\n\n\tGraphicsOptions_CheckConfig();\n}\t\n\n/*\n=================\nGraphicsOptions_ApplyChanges\n=================\n*/\nstatic void GraphicsOptions_ApplyChanges( void *unused, int notification )\n{\n\tif (notification != QM_ACTIVATED)\n\t\treturn;\n\n\tswitch ( s_graphicsoptions.texturebits.curvalue  )\n\t{\n\tcase 0:\n\t\ttrap_Cvar_SetValue( \"r_texturebits\", 0 );\n\t\tbreak;\n\tcase 1:\n\t\ttrap_Cvar_SetValue( \"r_texturebits\", 16 );\n\t\tbreak;\n\tcase 2:\n\t\ttrap_Cvar_SetValue( \"r_texturebits\", 32 );\n\t\tbreak;\n\t}\n\ttrap_Cvar_SetValue( \"r_picmip\", 3 - s_graphicsoptions.tq.curvalue );\n\ttrap_Cvar_SetValue( \"r_allowExtensions\", s_graphicsoptions.allow_extensions.curvalue );\n\ttrap_Cvar_SetValue( \"r_mode\", s_graphicsoptions.mode.curvalue );\n\ttrap_Cvar_SetValue( \"r_fullscreen\", s_graphicsoptions.fs.curvalue );\n\ttrap_Cvar_Set( \"r_glDriver\", ( char * ) s_drivers[s_graphicsoptions.driver.curvalue] );\n\tswitch ( s_graphicsoptions.colordepth.curvalue )\n\t{\n\tcase 0:\n\t\ttrap_Cvar_SetValue( \"r_colorbits\", 0 );\n\t\ttrap_Cvar_SetValue( \"r_depthbits\", 0 );\n\t\ttrap_Cvar_SetValue( \"r_stencilbits\", 0 );\n\t\tbreak;\n\tcase 1:\n\t\ttrap_Cvar_SetValue( \"r_colorbits\", 16 );\n\t\ttrap_Cvar_SetValue( \"r_depthbits\", 16 );\n\t\ttrap_Cvar_SetValue( \"r_stencilbits\", 0 );\n\t\tbreak;\n\tcase 2:\n\t\ttrap_Cvar_SetValue( \"r_colorbits\", 32 );\n\t\ttrap_Cvar_SetValue( \"r_depthbits\", 24 );\n\t\tbreak;\n\t}\n\ttrap_Cvar_SetValue( \"r_vertexLight\", s_graphicsoptions.lighting.curvalue );\n\n\tif ( s_graphicsoptions.geometry.curvalue == 2 )\n\t{\n\t\ttrap_Cvar_SetValue( \"r_lodBias\", 0 );\n\t\ttrap_Cvar_SetValue( \"r_subdivisions\", 4 );\n\t}\n\telse if ( s_graphicsoptions.geometry.curvalue == 1 )\n\t{\n\t\ttrap_Cvar_SetValue( \"r_lodBias\", 1 );\n\t\ttrap_Cvar_SetValue( \"r_subdivisions\", 12 );\n\t}\n\telse\n\t{\n\t\ttrap_Cvar_SetValue( \"r_lodBias\", 1 );\n\t\ttrap_Cvar_SetValue( \"r_subdivisions\", 20 );\n\t}\n\n\tif ( s_graphicsoptions.filter.curvalue )\n\t{\n\t\ttrap_Cvar_Set( \"r_textureMode\", \"GL_LINEAR_MIPMAP_LINEAR\" );\n\t}\n\telse\n\t{\n\t\ttrap_Cvar_Set( \"r_textureMode\", \"GL_LINEAR_MIPMAP_NEAREST\" );\n\t}\n\n\ttrap_Cmd_ExecuteText( EXEC_APPEND, \"vid_restart\\n\" );\n}\n\n/*\n=================\nGraphicsOptions_Event\n=================\n*/\nstatic void GraphicsOptions_Event( void* ptr, int event ) {\n\tInitialVideoOptions_s *ivo;\n\n\tif( event != QM_ACTIVATED ) {\n\t \treturn;\n\t}\n\n\tswitch( ((menucommon_s*)ptr)->id ) {\n\tcase ID_MODE:\n\t\t// clamp 3dfx video modes\n\t\tif ( s_graphicsoptions.driver.curvalue == 1 )\n\t\t{\n\t\t\tif ( s_graphicsoptions.mode.curvalue < 2 )\n\t\t\t\ts_graphicsoptions.mode.curvalue = 2;\n\t\t\telse if ( s_graphicsoptions.mode.curvalue > 6 )\n\t\t\t\ts_graphicsoptions.mode.curvalue = 6;\n\t\t}\n\t\tbreak;\n\n\tcase ID_LIST:\n\t\tivo = &s_ivo_templates[s_graphicsoptions.list.curvalue];\n\n\t\ts_graphicsoptions.mode.curvalue        = ivo->mode;\n\t\ts_graphicsoptions.tq.curvalue          = ivo->tq;\n\t\ts_graphicsoptions.lighting.curvalue    = ivo->lighting;\n\t\ts_graphicsoptions.colordepth.curvalue  = ivo->colordepth;\n\t\ts_graphicsoptions.texturebits.curvalue = ivo->texturebits;\n\t\ts_graphicsoptions.geometry.curvalue    = ivo->geometry;\n\t\ts_graphicsoptions.filter.curvalue      = ivo->filter;\n\t\ts_graphicsoptions.fs.curvalue          = ivo->fullscreen;\n\t\tbreak;\n\n\tcase ID_DRIVERINFO:\n\t\tUI_DriverInfo_Menu();\n\t\tbreak;\n\n\tcase ID_BACK2:\n\t\tUI_PopMenu();\n\t\tbreak;\n\n\tcase ID_GRAPHICS:\n\t\tbreak;\n\n\tcase ID_DISPLAY:\n\t\tUI_PopMenu();\n\t\tUI_DisplayOptionsMenu();\n\t\tbreak;\n\n\tcase ID_SOUND:\n\t\tUI_PopMenu();\n\t\tUI_SoundOptionsMenu();\n\t\tbreak;\n\n\tcase ID_NETWORK:\n\t\tUI_PopMenu();\n\t\tUI_NetworkOptionsMenu();\n\t\tbreak;\n\t}\n}\n\n\n/*\n================\nGraphicsOptions_TQEvent\n================\n*/\nstatic void GraphicsOptions_TQEvent( void *ptr, int event ) {\n\tif( event != QM_ACTIVATED ) {\n\t \treturn;\n\t}\n\ts_graphicsoptions.tq.curvalue = (int)(s_graphicsoptions.tq.curvalue + 0.5);\n}\n\n\n/*\n================\nGraphicsOptions_MenuDraw\n================\n*/\nvoid GraphicsOptions_MenuDraw (void)\n{\n//APSFIX - rework this\n\tGraphicsOptions_UpdateMenuItems();\n\n\tMenu_Draw( &s_graphicsoptions.menu );\n}\n\n/*\n=================\nGraphicsOptions_SetMenuItems\n=================\n*/\nstatic void GraphicsOptions_SetMenuItems( void )\n{\n\ts_graphicsoptions.mode.curvalue = trap_Cvar_VariableValue( \"r_mode\" );\n\tif ( s_graphicsoptions.mode.curvalue < 0 )\n\t{\n\t\ts_graphicsoptions.mode.curvalue = 3;\n\t}\n\ts_graphicsoptions.fs.curvalue = trap_Cvar_VariableValue(\"r_fullscreen\");\n\ts_graphicsoptions.allow_extensions.curvalue = trap_Cvar_VariableValue(\"r_allowExtensions\");\n\ts_graphicsoptions.tq.curvalue = 3-trap_Cvar_VariableValue( \"r_picmip\");\n\tif ( s_graphicsoptions.tq.curvalue < 0 )\n\t{\n\t\ts_graphicsoptions.tq.curvalue = 0;\n\t}\n\telse if ( s_graphicsoptions.tq.curvalue > 3 )\n\t{\n\t\ts_graphicsoptions.tq.curvalue = 3;\n\t}\n\n\ts_graphicsoptions.lighting.curvalue = trap_Cvar_VariableValue( \"r_vertexLight\" ) != 0;\n\tswitch ( ( int ) trap_Cvar_VariableValue( \"r_texturebits\" ) )\n\t{\n\tdefault:\n\tcase 0:\n\t\ts_graphicsoptions.texturebits.curvalue = 0;\n\t\tbreak;\n\tcase 16:\n\t\ts_graphicsoptions.texturebits.curvalue = 1;\n\t\tbreak;\n\tcase 32:\n\t\ts_graphicsoptions.texturebits.curvalue = 2;\n\t\tbreak;\n\t}\n\n\tif ( !Q_stricmp( UI_Cvar_VariableString( \"r_textureMode\" ), \"GL_LINEAR_MIPMAP_NEAREST\" ) )\n\t{\n\t\ts_graphicsoptions.filter.curvalue = 0;\n\t}\n\telse\n\t{\n\t\ts_graphicsoptions.filter.curvalue = 1;\n\t}\n\n\tif ( trap_Cvar_VariableValue( \"r_lodBias\" ) > 0 )\n\t{\n\t\tif ( trap_Cvar_VariableValue( \"r_subdivisions\" ) >= 20 )\n\t\t{\n\t\t\ts_graphicsoptions.geometry.curvalue = 0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\ts_graphicsoptions.geometry.curvalue = 1;\n\t\t}\n\t}\n\telse\n\t{\n\t\ts_graphicsoptions.geometry.curvalue = 2;\n\t}\n\n\tswitch ( ( int ) trap_Cvar_VariableValue( \"r_colorbits\" ) )\n\t{\n\tdefault:\n\tcase 0:\n\t\ts_graphicsoptions.colordepth.curvalue = 0;\n\t\tbreak;\n\tcase 16:\n\t\ts_graphicsoptions.colordepth.curvalue = 1;\n\t\tbreak;\n\tcase 32:\n\t\ts_graphicsoptions.colordepth.curvalue = 2;\n\t\tbreak;\n\t}\n\n\tif ( s_graphicsoptions.fs.curvalue == 0 )\n\t{\n\t\ts_graphicsoptions.colordepth.curvalue = 0;\n\t}\n\tif ( s_graphicsoptions.driver.curvalue == 1 )\n\t{\n\t\ts_graphicsoptions.colordepth.curvalue = 1;\n\t}\n}\n\n/*\n================\nGraphicsOptions_MenuInit\n================\n*/\nvoid GraphicsOptions_MenuInit( void )\n{\n\tstatic const char *s_driver_names[] =\n\t{\n\t\t\"Default\",\n\t\t\"Voodoo\",\n\t\t0\n\t};\n\n\tstatic const char *tq_names[] =\n\t{\n\t\t\"Default\",\n\t\t\"16 bit\",\n\t\t\"32 bit\",\n\t\t0\n\t};\n\n\tstatic const char *s_graphics_options_names[] =\n\t{\n\t\t\"High Quality\",\n\t\t\"Normal\",\n\t\t\"Fast\",\n\t\t\"Fastest\",\n\t\t\"Custom\",\n\t\t0\n\t};\n\n\tstatic const char *lighting_names[] =\n\t{\n\t\t\"Lightmap\",\n\t\t\"Vertex\",\n\t\t0\n\t};\n\n\tstatic const char *colordepth_names[] =\n\t{\n\t\t\"Default\",\n\t\t\"16 bit\",\n\t\t\"32 bit\",\n\t\t0\n\t};\n\n\tstatic const char *resolutions[] = \n\t{\n\t\t\"320x240\",\n\t\t\"400x300\",\n\t\t\"512x384\",\n\t\t\"640x480\",\n\t\t\"800x600\",\n\t\t\"960x720\",\n\t\t\"1024x768\",\n\t\t\"1152x864\",\n\t\t\"1280x1024\",\n\t\t\"1600x1200\",\n\t\t\"2048x1536\",\n\t\t\"856x480 wide screen\",\n\t\t0\n\t};\n\tstatic const char *filter_names[] =\n\t{\n\t\t\"Bilinear\",\n\t\t\"Trilinear\",\n\t\t0\n\t};\n\tstatic const char *quality_names[] =\n\t{\n\t\t\"Low\",\n\t\t\"Medium\",\n\t\t\"High\",\n\t\t0\n\t};\n\tstatic const char *enabled_names[] =\n\t{\n\t\t\"Off\",\n\t\t\"On\",\n\t\t0\n\t};\n\n\tint y;\n\n\t// zero set all our globals\n\tmemset( &s_graphicsoptions, 0 ,sizeof(graphicsoptions_t) );\n\n\tGraphicsOptions_Cache();\n\n\ts_graphicsoptions.menu.wrapAround = qtrue;\n\ts_graphicsoptions.menu.fullscreen = qtrue;\n\ts_graphicsoptions.menu.draw       = GraphicsOptions_MenuDraw;\n\n\ts_graphicsoptions.banner.generic.type  = MTYPE_BTEXT;\n\ts_graphicsoptions.banner.generic.x\t   = 320;\n\ts_graphicsoptions.banner.generic.y\t   = 16;\n\ts_graphicsoptions.banner.string  \t   = \"SYSTEM SETUP\";\n\ts_graphicsoptions.banner.color         = color_white;\n\ts_graphicsoptions.banner.style         = UI_CENTER;\n\n\ts_graphicsoptions.framel.generic.type  = MTYPE_BITMAP;\n\ts_graphicsoptions.framel.generic.name  = GRAPHICSOPTIONS_FRAMEL;\n\ts_graphicsoptions.framel.generic.flags = QMF_INACTIVE;\n\ts_graphicsoptions.framel.generic.x\t   = 0;\n\ts_graphicsoptions.framel.generic.y\t   = 78;\n\ts_graphicsoptions.framel.width  \t   = 256;\n\ts_graphicsoptions.framel.height  \t   = 329;\n\n\ts_graphicsoptions.framer.generic.type  = MTYPE_BITMAP;\n\ts_graphicsoptions.framer.generic.name  = GRAPHICSOPTIONS_FRAMER;\n\ts_graphicsoptions.framer.generic.flags = QMF_INACTIVE;\n\ts_graphicsoptions.framer.generic.x\t   = 376;\n\ts_graphicsoptions.framer.generic.y\t   = 76;\n\ts_graphicsoptions.framer.width  \t   = 256;\n\ts_graphicsoptions.framer.height  \t   = 334;\n\n\ts_graphicsoptions.graphics.generic.type\t\t= MTYPE_PTEXT;\n\ts_graphicsoptions.graphics.generic.flags\t= QMF_RIGHT_JUSTIFY;\n\ts_graphicsoptions.graphics.generic.id\t\t= ID_GRAPHICS;\n\ts_graphicsoptions.graphics.generic.callback\t= GraphicsOptions_Event;\n\ts_graphicsoptions.graphics.generic.x\t\t= 216;\n\ts_graphicsoptions.graphics.generic.y\t\t= 240 - 2 * PROP_HEIGHT;\n\ts_graphicsoptions.graphics.string\t\t\t= \"GRAPHICS\";\n\ts_graphicsoptions.graphics.style\t\t\t= UI_RIGHT;\n\ts_graphicsoptions.graphics.color\t\t\t= color_red;\n\n\ts_graphicsoptions.display.generic.type\t\t= MTYPE_PTEXT;\n\ts_graphicsoptions.display.generic.flags\t\t= QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_graphicsoptions.display.generic.id\t\t= ID_DISPLAY;\n\ts_graphicsoptions.display.generic.callback\t= GraphicsOptions_Event;\n\ts_graphicsoptions.display.generic.x\t\t\t= 216;\n\ts_graphicsoptions.display.generic.y\t\t\t= 240 - PROP_HEIGHT;\n\ts_graphicsoptions.display.string\t\t\t= \"DISPLAY\";\n\ts_graphicsoptions.display.style\t\t\t\t= UI_RIGHT;\n\ts_graphicsoptions.display.color\t\t\t\t= color_red;\n\n\ts_graphicsoptions.sound.generic.type\t\t= MTYPE_PTEXT;\n\ts_graphicsoptions.sound.generic.flags\t\t= QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_graphicsoptions.sound.generic.id\t\t\t= ID_SOUND;\n\ts_graphicsoptions.sound.generic.callback\t= GraphicsOptions_Event;\n\ts_graphicsoptions.sound.generic.x\t\t\t= 216;\n\ts_graphicsoptions.sound.generic.y\t\t\t= 240;\n\ts_graphicsoptions.sound.string\t\t\t\t= \"SOUND\";\n\ts_graphicsoptions.sound.style\t\t\t\t= UI_RIGHT;\n\ts_graphicsoptions.sound.color\t\t\t\t= color_red;\n\n\ts_graphicsoptions.network.generic.type\t\t= MTYPE_PTEXT;\n\ts_graphicsoptions.network.generic.flags\t\t= QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_graphicsoptions.network.generic.id\t\t= ID_NETWORK;\n\ts_graphicsoptions.network.generic.callback\t= GraphicsOptions_Event;\n\ts_graphicsoptions.network.generic.x\t\t\t= 216;\n\ts_graphicsoptions.network.generic.y\t\t\t= 240 + PROP_HEIGHT;\n\ts_graphicsoptions.network.string\t\t\t= \"NETWORK\";\n\ts_graphicsoptions.network.style\t\t\t\t= UI_RIGHT;\n\ts_graphicsoptions.network.color\t\t\t\t= color_red;\n\n\ty = 240 - 6 * (BIGCHAR_HEIGHT + 2);\n\ts_graphicsoptions.list.generic.type     = MTYPE_SPINCONTROL;\n\ts_graphicsoptions.list.generic.name     = \"Graphics Settings:\";\n\ts_graphicsoptions.list.generic.flags    = QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\ts_graphicsoptions.list.generic.x        = 400;\n\ts_graphicsoptions.list.generic.y        = y;\n\ts_graphicsoptions.list.generic.callback = GraphicsOptions_Event;\n\ts_graphicsoptions.list.generic.id       = ID_LIST;\n\ts_graphicsoptions.list.itemnames        = s_graphics_options_names;\n\ty += 2 * ( BIGCHAR_HEIGHT + 2 );\n\n\ts_graphicsoptions.driver.generic.type  = MTYPE_SPINCONTROL;\n\ts_graphicsoptions.driver.generic.name  = \"GL Driver:\";\n\ts_graphicsoptions.driver.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\ts_graphicsoptions.driver.generic.x     = 400;\n\ts_graphicsoptions.driver.generic.y     = y;\n\ts_graphicsoptions.driver.itemnames     = s_driver_names;\n\ts_graphicsoptions.driver.curvalue      = 0;\n\ty += BIGCHAR_HEIGHT+2;\n\n\t// references/modifies \"r_allowExtensions\"\n\ts_graphicsoptions.allow_extensions.generic.type     = MTYPE_SPINCONTROL;\n\ts_graphicsoptions.allow_extensions.generic.name\t    = \"GL Extensions:\";\n\ts_graphicsoptions.allow_extensions.generic.flags\t= QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\ts_graphicsoptions.allow_extensions.generic.x\t    = 400;\n\ts_graphicsoptions.allow_extensions.generic.y\t    = y;\n\ts_graphicsoptions.allow_extensions.itemnames        = enabled_names;\n\ty += BIGCHAR_HEIGHT+2;\n\n\t// references/modifies \"r_mode\"\n\ts_graphicsoptions.mode.generic.type     = MTYPE_SPINCONTROL;\n\ts_graphicsoptions.mode.generic.name     = \"Video Mode:\";\n\ts_graphicsoptions.mode.generic.flags    = QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\ts_graphicsoptions.mode.generic.x        = 400;\n\ts_graphicsoptions.mode.generic.y        = y;\n\ts_graphicsoptions.mode.itemnames        = resolutions;\n\ts_graphicsoptions.mode.generic.callback = GraphicsOptions_Event;\n\ts_graphicsoptions.mode.generic.id       = ID_MODE;\n\ty += BIGCHAR_HEIGHT+2;\n\n\t// references \"r_colorbits\"\n\ts_graphicsoptions.colordepth.generic.type     = MTYPE_SPINCONTROL;\n\ts_graphicsoptions.colordepth.generic.name     = \"Color Depth:\";\n\ts_graphicsoptions.colordepth.generic.flags    = QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\ts_graphicsoptions.colordepth.generic.x        = 400;\n\ts_graphicsoptions.colordepth.generic.y        = y;\n\ts_graphicsoptions.colordepth.itemnames        = colordepth_names;\n\ty += BIGCHAR_HEIGHT+2;\n\n\t// references/modifies \"r_fullscreen\"\n\ts_graphicsoptions.fs.generic.type     = MTYPE_SPINCONTROL;\n\ts_graphicsoptions.fs.generic.name\t  = \"Fullscreen:\";\n\ts_graphicsoptions.fs.generic.flags\t  = QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\ts_graphicsoptions.fs.generic.x\t      = 400;\n\ts_graphicsoptions.fs.generic.y\t      = y;\n\ts_graphicsoptions.fs.itemnames\t      = enabled_names;\n\ty += BIGCHAR_HEIGHT+2;\n\n\t// references/modifies \"r_vertexLight\"\n\ts_graphicsoptions.lighting.generic.type  = MTYPE_SPINCONTROL;\n\ts_graphicsoptions.lighting.generic.name\t = \"Lighting:\";\n\ts_graphicsoptions.lighting.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\ts_graphicsoptions.lighting.generic.x\t = 400;\n\ts_graphicsoptions.lighting.generic.y\t = y;\n\ts_graphicsoptions.lighting.itemnames     = lighting_names;\n\ty += BIGCHAR_HEIGHT+2;\n\n\t// references/modifies \"r_lodBias\" & \"subdivisions\"\n\ts_graphicsoptions.geometry.generic.type  = MTYPE_SPINCONTROL;\n\ts_graphicsoptions.geometry.generic.name\t = \"Geometric Detail:\";\n\ts_graphicsoptions.geometry.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\ts_graphicsoptions.geometry.generic.x\t = 400;\n\ts_graphicsoptions.geometry.generic.y\t = y;\n\ts_graphicsoptions.geometry.itemnames     = quality_names;\n\ty += BIGCHAR_HEIGHT+2;\n\n\t// references/modifies \"r_picmip\"\n\ts_graphicsoptions.tq.generic.type\t= MTYPE_SLIDER;\n\ts_graphicsoptions.tq.generic.name\t= \"Texture Detail:\";\n\ts_graphicsoptions.tq.generic.flags\t= QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\ts_graphicsoptions.tq.generic.x\t\t= 400;\n\ts_graphicsoptions.tq.generic.y\t\t= y;\n\ts_graphicsoptions.tq.minvalue       = 0;\n\ts_graphicsoptions.tq.maxvalue       = 3;\n\ts_graphicsoptions.tq.generic.callback = GraphicsOptions_TQEvent;\n\ty += BIGCHAR_HEIGHT+2;\n\n\t// references/modifies \"r_textureBits\"\n\ts_graphicsoptions.texturebits.generic.type  = MTYPE_SPINCONTROL;\n\ts_graphicsoptions.texturebits.generic.name\t= \"Texture Quality:\";\n\ts_graphicsoptions.texturebits.generic.flags\t= QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\ts_graphicsoptions.texturebits.generic.x\t    = 400;\n\ts_graphicsoptions.texturebits.generic.y\t    = y;\n\ts_graphicsoptions.texturebits.itemnames     = tq_names;\n\ty += BIGCHAR_HEIGHT+2;\n\n\t// references/modifies \"r_textureMode\"\n\ts_graphicsoptions.filter.generic.type   = MTYPE_SPINCONTROL;\n\ts_graphicsoptions.filter.generic.name\t= \"Texture Filter:\";\n\ts_graphicsoptions.filter.generic.flags\t= QMF_PULSEIFFOCUS|QMF_SMALLFONT;\n\ts_graphicsoptions.filter.generic.x\t    = 400;\n\ts_graphicsoptions.filter.generic.y\t    = y;\n\ts_graphicsoptions.filter.itemnames      = filter_names;\n\ty += 2*BIGCHAR_HEIGHT;\n\n\ts_graphicsoptions.driverinfo.generic.type     = MTYPE_PTEXT;\n\ts_graphicsoptions.driverinfo.generic.flags    = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_graphicsoptions.driverinfo.generic.callback = GraphicsOptions_Event;\n\ts_graphicsoptions.driverinfo.generic.id       = ID_DRIVERINFO;\n\ts_graphicsoptions.driverinfo.generic.x        = 320;\n\ts_graphicsoptions.driverinfo.generic.y        = y;\n\ts_graphicsoptions.driverinfo.string           = \"Driver Info\";\n\ts_graphicsoptions.driverinfo.style            = UI_CENTER|UI_SMALLFONT;\n\ts_graphicsoptions.driverinfo.color            = color_red;\n\ty += BIGCHAR_HEIGHT+2;\n\n\ts_graphicsoptions.back.generic.type\t    = MTYPE_BITMAP;\n\ts_graphicsoptions.back.generic.name     = GRAPHICSOPTIONS_BACK0;\n\ts_graphicsoptions.back.generic.flags    = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;\n\ts_graphicsoptions.back.generic.callback = GraphicsOptions_Event;\n\ts_graphicsoptions.back.generic.id\t    = ID_BACK2;\n\ts_graphicsoptions.back.generic.x\t\t= 0;\n\ts_graphicsoptions.back.generic.y\t\t= 480-64;\n\ts_graphicsoptions.back.width  \t\t    = 128;\n\ts_graphicsoptions.back.height  \t\t    = 64;\n\ts_graphicsoptions.back.focuspic         = GRAPHICSOPTIONS_BACK1;\n\n\ts_graphicsoptions.apply.generic.type     = MTYPE_BITMAP;\n\ts_graphicsoptions.apply.generic.name     = GRAPHICSOPTIONS_ACCEPT0;\n\ts_graphicsoptions.apply.generic.flags    = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_HIDDEN|QMF_INACTIVE;\n\ts_graphicsoptions.apply.generic.callback = GraphicsOptions_ApplyChanges;\n\ts_graphicsoptions.apply.generic.x        = 640;\n\ts_graphicsoptions.apply.generic.y        = 480-64;\n\ts_graphicsoptions.apply.width  \t\t     = 128;\n\ts_graphicsoptions.apply.height  \t\t = 64;\n\ts_graphicsoptions.apply.focuspic         = GRAPHICSOPTIONS_ACCEPT1;\n\n\tMenu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.banner );\n\tMenu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.framel );\n\tMenu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.framer );\n\n\tMenu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.graphics );\n\tMenu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.display );\n\tMenu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.sound );\n\tMenu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.network );\n\n\tMenu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.list );\n\tMenu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.driver );\n\tMenu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.allow_extensions );\n\tMenu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.mode );\n\tMenu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.colordepth );\n\tMenu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.fs );\n\tMenu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.lighting );\n\tMenu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.geometry );\n\tMenu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.tq );\n\tMenu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.texturebits );\n\tMenu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.filter );\n\tMenu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.driverinfo );\n\n\tMenu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.back );\n\tMenu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.apply );\n\n\tGraphicsOptions_SetMenuItems();\n\tGraphicsOptions_GetInitialVideo();\n}\n\n\n/*\n=================\nGraphicsOptions_Cache\n=================\n*/\nvoid GraphicsOptions_Cache( void ) {\n\ttrap_R_RegisterShaderNoMip( GRAPHICSOPTIONS_FRAMEL );\n\ttrap_R_RegisterShaderNoMip( GRAPHICSOPTIONS_FRAMER );\n\ttrap_R_RegisterShaderNoMip( GRAPHICSOPTIONS_BACK0 );\n\ttrap_R_RegisterShaderNoMip( GRAPHICSOPTIONS_BACK1 );\n\ttrap_R_RegisterShaderNoMip( GRAPHICSOPTIONS_ACCEPT0 );\n\ttrap_R_RegisterShaderNoMip( GRAPHICSOPTIONS_ACCEPT1 );\n}\n\n\n/*\n=================\nUI_GraphicsOptionsMenu\n=================\n*/\nvoid UI_GraphicsOptionsMenu( void ) {\n\tGraphicsOptions_MenuInit();\n\tUI_PushMenu( &s_graphicsoptions.menu );\n\tMenu_SetCursorToItem( &s_graphicsoptions.menu, &s_graphicsoptions.graphics );\n}\n\n"
  },
  {
    "path": "tools/bin2hex.cpp",
    "content": "#include <cstdint>\n#include <cstdio>\n\nint main(int argc, char* argv[]) {\n    if (argc != 3) {\n        printf(\"Usage: bin2hex <input_file> <output_array_name>\\n\");\n        return - 1;\n    }\n    FILE* f = fopen(argv[1], \"rb\");\n    if (!f) {\n        printf(\"Could not open file for reading: %s\\n\", argv[1]);\n        return -1;\n    }\n\n    const int line_length = 16;\n    long long size = 0;\n\n    printf(\"unsigned char %s[] = {\\n\\t\", argv[2]);\n\n    int byte = fgetc(f);\n    while (byte != EOF) {\n        printf(\"0x%.2X\", byte);\n\n        byte = fgetc(f);\n        if (byte != EOF) printf(\", \");\n\n        size++;\n        if (size % line_length == 0) printf(\"\\n\\t\");\n    }\n\n    printf(\"\\n};\\n\");\n    printf(\"long long %s_size = %lld;\", argv[2], size);\n\n    if (!feof(f)) {\n        printf(\"Could not read entire file: %s\", argv[1]);\n    }\n\n    fclose(f);\n    return 0;\n}\n"
  },
  {
    "path": "visual-studio/DeclareDPIAware.manifest",
    "content": "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\" xmlns:asmv3=\"urn:schemas-microsoft-com:asm.v3\" >\n  <asmv3:application>\n    <asmv3:windowsSettings xmlns=\"http://schemas.microsoft.com/SMI/2005/WindowsSettings\">\n      <dpiAware>true/pm</dpiAware>\n    </asmv3:windowsSettings>\n  </asmv3:application>\n</assembly>\n"
  },
  {
    "path": "visual-studio/botlib.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{A410161F-AE9F-485D-A01F-5294891430A6}</ProjectGuid>\n    <RootNamespace>botlib</RootNamespace>\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseOfMfc>false</UseOfMfc>\n    <CharacterSet>MultiByte</CharacterSet>\n    <PlatformToolset>v143</PlatformToolset>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseOfMfc>false</UseOfMfc>\n    <CharacterSet>MultiByte</CharacterSet>\n    <PlatformToolset>v143</PlatformToolset>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n    <Import Project=\"props\\shared.props\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n    <Import Project=\"props\\shared.props\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup>\n    <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\n    <CodeAnalysisRuleSet Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">AllRules.ruleset</CodeAnalysisRuleSet>\n    <CodeAnalysisRules Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" />\n    <CodeAnalysisRuleAssemblies Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" />\n    <CodeAnalysisRuleSet Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">AllRules.ruleset</CodeAnalysisRuleSet>\n    <CodeAnalysisRules Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" />\n    <CodeAnalysisRuleAssemblies Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" />\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <EnableMicrosoftCodeAnalysis>false</EnableMicrosoftCodeAnalysis>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <EnableMicrosoftCodeAnalysis>false</EnableMicrosoftCodeAnalysis>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <Optimization>MaxSpeed</Optimization>\n      <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;BOTLIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <StringPooling>true</StringPooling>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <SuppressStartupBanner>true</SuppressStartupBanner>\n      <CompileAs>CompileAsCpp</CompileAs>\n    </ClCompile>\n    <ResourceCompile>\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Culture>0x0409</Culture>\n    </ResourceCompile>\n    <Lib>\n      <SuppressStartupBanner>true</SuppressStartupBanner>\n    </Lib>\n    <Bscmake>\n      <OutputFile>\n      </OutputFile>\n    </Bscmake>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;BOTLIB;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <SuppressStartupBanner>true</SuppressStartupBanner>\n      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n      <CompileAs>CompileAsCpp</CompileAs>\n    </ClCompile>\n    <ResourceCompile>\n      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Culture>0x0409</Culture>\n    </ResourceCompile>\n    <Lib>\n      <SuppressStartupBanner>true</SuppressStartupBanner>\n    </Lib>\n    <Bscmake>\n      <OutputFile>\n      </OutputFile>\n    </Bscmake>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\be_aas_bspq3.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\be_aas_cluster.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\be_aas_debug.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\be_aas_entity.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\be_aas_file.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\be_aas_main.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\be_aas_move.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\be_aas_optimize.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\be_aas_reach.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\be_aas_route.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\be_aas_routealt.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\be_aas_sample.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\be_ai_char.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\be_ai_chat.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\be_ai_gen.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\be_ai_goal.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\be_ai_move.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\be_ai_weap.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\be_ai_weight.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\be_ea.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\be_interface.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\l_crc.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\l_libvar.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\l_log.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\l_memory.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\l_precomp.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\l_script.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\l_struct.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\src\\engine\\botlib\\aasfile.h\" />\n    <ClInclude Include=\"..\\src\\engine\\botlib\\be_aas_bsp.h\" />\n    <ClInclude Include=\"..\\src\\engine\\botlib\\be_aas_cluster.h\" />\n    <ClInclude Include=\"..\\src\\engine\\botlib\\be_aas_debug.h\" />\n    <ClInclude Include=\"..\\src\\engine\\botlib\\be_aas_def.h\" />\n    <ClInclude Include=\"..\\src\\engine\\botlib\\be_aas_entity.h\" />\n    <ClInclude Include=\"..\\src\\engine\\botlib\\be_aas_file.h\" />\n    <ClInclude Include=\"..\\src\\engine\\botlib\\be_aas_funcs.h\" />\n    <ClInclude Include=\"..\\src\\engine\\botlib\\be_aas_main.h\" />\n    <ClInclude Include=\"..\\src\\engine\\botlib\\be_aas_move.h\" />\n    <ClInclude Include=\"..\\src\\engine\\botlib\\be_aas_optimize.h\" />\n    <ClInclude Include=\"..\\src\\engine\\botlib\\be_aas_reach.h\" />\n    <ClInclude Include=\"..\\src\\engine\\botlib\\be_aas_route.h\" />\n    <ClInclude Include=\"..\\src\\engine\\botlib\\be_aas_routealt.h\" />\n    <ClInclude Include=\"..\\src\\engine\\botlib\\be_aas_sample.h\" />\n    <ClInclude Include=\"..\\src\\engine\\botlib\\be_ai_weight.h\" />\n    <ClInclude Include=\"..\\src\\engine\\botlib\\be_interface.h\" />\n    <ClInclude Include=\"..\\src\\game\\bg_public.h\" />\n    <ClInclude Include=\"..\\src\\engine\\qcommon\\cm_public.h\" />\n    <ClInclude Include=\"..\\src\\game\\g_public.h\" />\n    <ClInclude Include=\"..\\src\\engine\\botlib\\l_crc.h\" />\n    <ClInclude Include=\"..\\src\\engine\\botlib\\l_libvar.h\" />\n    <ClInclude Include=\"..\\src\\engine\\botlib\\l_log.h\" />\n    <ClInclude Include=\"..\\src\\engine\\botlib\\l_memory.h\" />\n    <ClInclude Include=\"..\\src\\engine\\botlib\\l_precomp.h\" />\n    <ClInclude Include=\"..\\src\\engine\\botlib\\l_script.h\" />\n    <ClInclude Include=\"..\\src\\engine\\botlib\\l_struct.h\" />\n    <ClInclude Include=\"..\\src\\engine\\botlib\\l_utils.h\" />\n    <ClInclude Include=\"..\\src\\game\\q_shared.h\" />\n    <ClInclude Include=\"..\\src\\engine\\qcommon\\qcommon.h\" />\n    <ClInclude Include=\"..\\src\\engine\\qcommon\\qfiles.h\" />\n    <ClInclude Include=\"..\\src\\engine\\server\\server.h\" />\n    <ClInclude Include=\"..\\src\\game\\surfaceflags.h\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "visual-studio/botlib.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Source Files\">\n      <UniqueIdentifier>{02c99512-ec2f-4e36-86fd-7e0b58150614}</UniqueIdentifier>\n      <Extensions>cpp;c;cxx;rc;def;r;odl;idl;hpj;bat</Extensions>\n    </Filter>\n    <Filter Include=\"Header Files\">\n      <UniqueIdentifier>{e7c38243-e2d9-4d6c-9f17-a95e4f5f47fc}</UniqueIdentifier>\n      <Extensions>h;hpp;hxx;hm;inl</Extensions>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\be_aas_bspq3.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\be_aas_cluster.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\be_aas_debug.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\be_aas_entity.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\be_aas_file.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\be_aas_main.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\be_aas_move.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\be_aas_optimize.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\be_aas_reach.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\be_aas_route.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\be_aas_routealt.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\be_aas_sample.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\be_ai_char.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\be_ai_chat.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\be_ai_gen.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\be_ai_goal.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\be_ai_move.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\be_ai_weap.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\be_ai_weight.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\be_ea.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\be_interface.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\l_crc.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\l_libvar.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\l_log.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\l_memory.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\l_precomp.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\l_script.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\botlib\\l_struct.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\src\\engine\\botlib\\aasfile.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\botlib\\be_aas_bsp.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\botlib\\be_aas_cluster.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\botlib\\be_aas_debug.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\botlib\\be_aas_def.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\botlib\\be_aas_entity.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\botlib\\be_aas_file.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\botlib\\be_aas_funcs.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\botlib\\be_aas_main.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\botlib\\be_aas_move.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\botlib\\be_aas_optimize.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\botlib\\be_aas_reach.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\botlib\\be_aas_route.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\botlib\\be_aas_routealt.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\botlib\\be_aas_sample.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\botlib\\be_ai_weight.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\botlib\\be_interface.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\game\\bg_public.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\qcommon\\cm_public.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\game\\g_public.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\botlib\\l_crc.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\botlib\\l_libvar.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\botlib\\l_log.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\botlib\\l_memory.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\botlib\\l_precomp.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\botlib\\l_script.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\botlib\\l_struct.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\botlib\\l_utils.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\game\\q_shared.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\qcommon\\qcommon.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\qcommon\\qfiles.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\server\\server.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\game\\surfaceflags.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "visual-studio/cgame.def",
    "content": "EXPORTS\n\tvmMain\n\tdllEntry\n"
  },
  {
    "path": "visual-studio/cgame.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{C878E295-CB82-4B40-8ECF-5CE5525466FA}</ProjectGuid>\n    <RootNamespace>cgame</RootNamespace>\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\n    <UseOfMfc>false</UseOfMfc>\n    <PlatformToolset>v143</PlatformToolset>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\n    <UseOfMfc>false</UseOfMfc>\n    <PlatformToolset>v143</PlatformToolset>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n    <Import Project=\"$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props\" />\n    <Import Project=\"props\\shared.props\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n    <Import Project=\"$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props\" />\n    <Import Project=\"props\\shared.props\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup>\n    <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\n    <LinkIncremental Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">false</LinkIncremental>\n    <LinkIncremental Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">false</LinkIncremental>\n    <CodeAnalysisRuleSet Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">AllRules.ruleset</CodeAnalysisRuleSet>\n    <CodeAnalysisRules Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" />\n    <CodeAnalysisRuleAssemblies Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" />\n    <CodeAnalysisRuleSet Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">AllRules.ruleset</CodeAnalysisRuleSet>\n    <CodeAnalysisRules Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" />\n    <CodeAnalysisRuleAssemblies Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" />\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <TargetName>cgame</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <TargetName>cgame</TargetName>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <Midl>\n      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <MkTypLibCompatible>true</MkTypLibCompatible>\n      <SuppressStartupBanner>true</SuppressStartupBanner>\n      <TypeLibraryName>.\\Debug/cgame.tlb</TypeLibraryName>\n      <HeaderFileName>\n      </HeaderFileName>\n    </Midl>\n    <ClCompile>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <WarningLevel>Level3</WarningLevel>\n      <SuppressStartupBanner>true</SuppressStartupBanner>\n      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n    </ClCompile>\n    <ResourceCompile>\n      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Culture>0x0409</Culture>\n    </ResourceCompile>\n    <Link>\n      <SuppressStartupBanner>true</SuppressStartupBanner>\n      <ModuleDefinitionFile>cgame.def</ModuleDefinitionFile>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Windows</SubSystem>\n      <BaseAddress>0x30000000</BaseAddress>\n    </Link>\n    <Bscmake>\n      <OutputFile>\n      </OutputFile>\n    </Bscmake>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <Midl>\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <MkTypLibCompatible>true</MkTypLibCompatible>\n      <SuppressStartupBanner>true</SuppressStartupBanner>\n      <TypeLibraryName>.\\Release/cgame.tlb</TypeLibraryName>\n      <HeaderFileName>\n      </HeaderFileName>\n    </Midl>\n    <ClCompile>\n      <Optimization>MaxSpeed</Optimization>\n      <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <StringPooling>true</StringPooling>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <WarningLevel>Level3</WarningLevel>\n      <SuppressStartupBanner>true</SuppressStartupBanner>\n    </ClCompile>\n    <ResourceCompile>\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Culture>0x0409</Culture>\n    </ResourceCompile>\n    <Link>\n      <SuppressStartupBanner>true</SuppressStartupBanner>\n      <ModuleDefinitionFile>cgame.def</ModuleDefinitionFile>\n      <SubSystem>Windows</SubSystem>\n      <BaseAddress>0x30000000</BaseAddress>\n    </Link>\n    <Bscmake>\n      <OutputFile>\n      </OutputFile>\n    </Bscmake>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\src\\game\\bg_misc.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\bg_pmove.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\bg_slidemove.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\cgame\\cg_consolecmds.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\cgame\\cg_draw.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\cgame\\cg_drawtools.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\cgame\\cg_effects.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\cgame\\cg_ents.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\cgame\\cg_event.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\cgame\\cg_info.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\cgame\\cg_localents.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\cgame\\cg_main.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\cgame\\cg_marks.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\cgame\\cg_players.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\cgame\\cg_playerstate.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\cgame\\cg_predict.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\cgame\\cg_scoreboard.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\cgame\\cg_servercmds.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\cgame\\cg_snapshot.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\cgame\\cg_syscalls.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\cgame\\cg_view.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\cgame\\cg_weapons.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\q_math.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\q_shared.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS</PreprocessorDefinitions>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\src\\game\\bg_public.h\" />\n    <ClInclude Include=\"..\\src\\cgame\\cg_local.h\" />\n    <ClInclude Include=\"..\\src\\cgame\\cg_public.h\" />\n    <ClInclude Include=\"..\\src\\game\\q_shared.h\" />\n    <ClInclude Include=\"..\\src\\game\\surfaceflags.h\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "visual-studio/cgame.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Source Files\">\n      <UniqueIdentifier>{dd28f453-e1cd-4091-b6f4-41ece1c9b44f}</UniqueIdentifier>\n      <Extensions>c</Extensions>\n    </Filter>\n    <Filter Include=\"Header Files\">\n      <UniqueIdentifier>{74a61878-baea-4625-96de-6f64a05d44f1}</UniqueIdentifier>\n      <Extensions>h</Extensions>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\src\\game\\bg_misc.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\bg_pmove.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\bg_slidemove.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\cgame\\cg_consolecmds.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\cgame\\cg_draw.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\cgame\\cg_drawtools.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\cgame\\cg_effects.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\cgame\\cg_ents.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\cgame\\cg_event.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\cgame\\cg_info.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\cgame\\cg_localents.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\cgame\\cg_main.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\cgame\\cg_marks.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\cgame\\cg_players.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\cgame\\cg_playerstate.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\cgame\\cg_predict.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\cgame\\cg_scoreboard.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\cgame\\cg_servercmds.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\cgame\\cg_snapshot.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\cgame\\cg_syscalls.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\cgame\\cg_view.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\cgame\\cg_weapons.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\q_math.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\q_shared.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\src\\game\\bg_public.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\cgame\\cg_local.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\cgame\\cg_public.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\game\\q_shared.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\game\\surfaceflags.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "visual-studio/game.def",
    "content": "EXPORTS\n\tdllEntry\n\tvmMain\n"
  },
  {
    "path": "visual-studio/game.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{F9EE10DA-2404-4154-B904-F93C936C040A}</ProjectGuid>\n    <RootNamespace>game</RootNamespace>\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\n    <UseOfMfc>false</UseOfMfc>\n    <PlatformToolset>v143</PlatformToolset>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\n    <UseOfMfc>false</UseOfMfc>\n    <PlatformToolset>v143</PlatformToolset>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n    <Import Project=\"$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props\" />\n    <Import Project=\"props\\shared.props\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n    <Import Project=\"$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props\" />\n    <Import Project=\"props\\shared.props\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup>\n    <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\n    <LinkIncremental Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">false</LinkIncremental>\n    <LinkIncremental Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">false</LinkIncremental>\n    <CodeAnalysisRuleSet Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">AllRules.ruleset</CodeAnalysisRuleSet>\n    <CodeAnalysisRules Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" />\n    <CodeAnalysisRuleAssemblies Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" />\n    <CodeAnalysisRuleSet Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">AllRules.ruleset</CodeAnalysisRuleSet>\n    <CodeAnalysisRules Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" />\n    <CodeAnalysisRuleAssemblies Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" />\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <TargetName>qagame</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <TargetName>qagame</TargetName>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <Midl>\n      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <MkTypLibCompatible>true</MkTypLibCompatible>\n      <SuppressStartupBanner>true</SuppressStartupBanner>\n      <TypeLibraryName>.\\Debug/game.tlb</TypeLibraryName>\n      <HeaderFileName>\n      </HeaderFileName>\n    </Midl>\n    <ClCompile>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <WarningLevel>Level3</WarningLevel>\n      <SuppressStartupBanner>true</SuppressStartupBanner>\n      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n    </ClCompile>\n    <ResourceCompile>\n      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Culture>0x0409</Culture>\n    </ResourceCompile>\n    <Link>\n      <SuppressStartupBanner>true</SuppressStartupBanner>\n      <ModuleDefinitionFile>game.def</ModuleDefinitionFile>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Windows</SubSystem>\n      <BaseAddress>0x20000000</BaseAddress>\n    </Link>\n    <Bscmake>\n      <OutputFile>\n      </OutputFile>\n    </Bscmake>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <Midl>\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <MkTypLibCompatible>true</MkTypLibCompatible>\n      <SuppressStartupBanner>true</SuppressStartupBanner>\n      <TypeLibraryName>.\\Release/game.tlb</TypeLibraryName>\n      <HeaderFileName>\n      </HeaderFileName>\n    </Midl>\n    <ClCompile>\n      <Optimization>MaxSpeed</Optimization>\n      <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;GLOBALRANK;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <StringPooling>true</StringPooling>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <WarningLevel>Level3</WarningLevel>\n      <SuppressStartupBanner>true</SuppressStartupBanner>\n    </ClCompile>\n    <ResourceCompile>\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Culture>0x0409</Culture>\n    </ResourceCompile>\n    <Link>\n      <SuppressStartupBanner>true</SuppressStartupBanner>\n      <ModuleDefinitionFile>game.def</ModuleDefinitionFile>\n      <SubSystem>Windows</SubSystem>\n      <BaseAddress>0x20000000</BaseAddress>\n    </Link>\n    <Bscmake>\n      <OutputFile>\n      </OutputFile>\n    </Bscmake>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\src\\game\\ai_chat.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;GLOBALRANK</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\ai_cmd.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;GLOBALRANK</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\ai_dmnet.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;GLOBALRANK</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\ai_dmq3.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;GLOBALRANK</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\ai_main.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;GLOBALRANK</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\ai_team.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;GLOBALRANK</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\ai_vcmd.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;GLOBALRANK</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\bg_misc.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;GLOBALRANK</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\bg_pmove.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;GLOBALRANK</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\bg_slidemove.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;GLOBALRANK</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\g_active.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;GLOBALRANK</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\g_arenas.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;GLOBALRANK</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\g_bot.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;GLOBALRANK</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\g_client.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;GLOBALRANK</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\g_cmds.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;GLOBALRANK</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\g_combat.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;GLOBALRANK</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\g_items.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;GLOBALRANK</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\g_main.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;GLOBALRANK</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\g_mem.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;GLOBALRANK</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\g_misc.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;GLOBALRANK</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\g_missile.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;GLOBALRANK</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\g_mover.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;GLOBALRANK</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\g_session.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;GLOBALRANK</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\g_spawn.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;GLOBALRANK</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\g_svcmds.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;GLOBALRANK</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\g_syscalls.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;GLOBALRANK</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\g_target.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;GLOBALRANK</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\g_team.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;GLOBALRANK</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\g_trigger.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;GLOBALRANK</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\g_utils.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;GLOBALRANK</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\g_weapon.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;GLOBALRANK</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\q_math.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;GLOBALRANK</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\q_shared.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;GLOBALRANK</PreprocessorDefinitions>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\src\\game\\ai_chat.h\" />\n    <ClInclude Include=\"..\\src\\game\\ai_cmd.h\" />\n    <ClInclude Include=\"..\\src\\game\\ai_dmnet.h\" />\n    <ClInclude Include=\"..\\src\\game\\ai_dmq3.h\" />\n    <ClInclude Include=\"..\\src\\game\\ai_main.h\" />\n    <ClInclude Include=\"..\\src\\game\\ai_team.h\" />\n    <ClInclude Include=\"..\\src\\game\\ai_vcmd.h\" />\n    <ClInclude Include=\"..\\src\\game\\be_aas.h\" />\n    <ClInclude Include=\"..\\src\\game\\be_ai_char.h\" />\n    <ClInclude Include=\"..\\src\\game\\be_ai_chat.h\" />\n    <ClInclude Include=\"..\\src\\game\\be_ai_gen.h\" />\n    <ClInclude Include=\"..\\src\\game\\be_ai_goal.h\" />\n    <ClInclude Include=\"..\\src\\game\\be_ai_move.h\" />\n    <ClInclude Include=\"..\\src\\game\\be_ai_weap.h\" />\n    <ClInclude Include=\"..\\src\\game\\be_ea.h\" />\n    <ClInclude Include=\"..\\src\\game\\bg_local.h\" />\n    <ClInclude Include=\"..\\src\\game\\bg_public.h\" />\n    <ClInclude Include=\"..\\src\\game\\botlib.h\" />\n    <ClInclude Include=\"..\\src\\game\\chars.h\" />\n    <ClInclude Include=\"..\\src\\game\\g_local.h\" />\n    <ClInclude Include=\"..\\src\\game\\g_public.h\" />\n    <ClInclude Include=\"..\\src\\game\\g_team.h\" />\n    <ClInclude Include=\"..\\src\\game\\inv.h\" />\n    <ClInclude Include=\"..\\src\\game\\match.h\" />\n    <ClInclude Include=\"..\\src\\game\\q_shared.h\" />\n    <ClInclude Include=\"..\\src\\game\\surfaceflags.h\" />\n    <ClInclude Include=\"..\\src\\game\\syn.h\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "visual-studio/game.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Source Files\">\n      <UniqueIdentifier>{4f60c42a-7b16-49ee-ae78-3d9c92940074}</UniqueIdentifier>\n      <Extensions>cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90</Extensions>\n    </Filter>\n    <Filter Include=\"Header Files\">\n      <UniqueIdentifier>{6df2c1fe-9962-4eb4-9485-a3f2efb6296e}</UniqueIdentifier>\n      <Extensions>h;hpp;hxx;hm;inl;fi;fd</Extensions>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\src\\game\\ai_chat.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\ai_cmd.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\ai_dmnet.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\ai_dmq3.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\ai_main.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\ai_team.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\ai_vcmd.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\bg_misc.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\bg_pmove.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\bg_slidemove.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\g_active.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\g_arenas.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\g_bot.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\g_client.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\g_cmds.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\g_combat.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\g_items.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\g_main.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\g_mem.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\g_misc.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\g_missile.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\g_mover.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\g_session.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\g_spawn.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\g_svcmds.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\g_syscalls.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\g_target.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\g_team.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\g_trigger.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\g_utils.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\g_weapon.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\q_math.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\q_shared.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\src\\game\\ai_chat.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\game\\ai_cmd.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\game\\ai_dmnet.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\game\\ai_dmq3.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\game\\ai_main.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\game\\ai_team.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\game\\ai_vcmd.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\game\\be_aas.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\game\\be_ai_char.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\game\\be_ai_chat.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\game\\be_ai_gen.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\game\\be_ai_goal.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\game\\be_ai_move.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\game\\be_ai_weap.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\game\\be_ea.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\game\\bg_local.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\game\\bg_public.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\game\\botlib.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\game\\chars.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\game\\g_local.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\game\\g_public.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\game\\g_team.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\game\\inv.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\game\\match.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\game\\q_shared.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\game\\surfaceflags.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\game\\syn.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "visual-studio/props/shared.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ImportGroup Label=\"PropertySheets\" />\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup>\n    <OutDir>$(ProjectDir)..\\bin\\$(PlatformName)\\$(Configuration)\\</OutDir>\n    <IntDir>$(ProjectDir)..\\bin\\$(PlatformName)\\$(Configuration)\\intermediate\\$(ProjectName)\\</IntDir>\n  </PropertyGroup>\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <TreatWarningAsError>true</TreatWarningAsError>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup>\n    <ClCompile />\n    <ClCompile>\n      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemGroup />\n</Project>"
  },
  {
    "path": "visual-studio/q3_ui.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{D454C4C7-7765-4149-ABAD-05FDEB9D94F8}</ProjectGuid>\n    <RootNamespace>q3_ui</RootNamespace>\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\n    <UseOfMfc>false</UseOfMfc>\n    <CharacterSet>MultiByte</CharacterSet>\n    <PlatformToolset>v143</PlatformToolset>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\n    <UseOfMfc>false</UseOfMfc>\n    <CharacterSet>MultiByte</CharacterSet>\n    <PlatformToolset>v143</PlatformToolset>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n    <Import Project=\"$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props\" />\n    <Import Project=\"props\\shared.props\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n    <Import Project=\"$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props\" />\n    <Import Project=\"props\\shared.props\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup>\n    <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\n    <LinkIncremental Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">false</LinkIncremental>\n    <LinkIncremental Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">false</LinkIncremental>\n    <CodeAnalysisRuleSet Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">AllRules.ruleset</CodeAnalysisRuleSet>\n    <CodeAnalysisRules Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" />\n    <CodeAnalysisRuleAssemblies Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" />\n    <CodeAnalysisRuleSet Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">AllRules.ruleset</CodeAnalysisRuleSet>\n    <CodeAnalysisRules Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" />\n    <CodeAnalysisRuleAssemblies Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" />\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <TargetName>ui</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <TargetName>ui</TargetName>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <Midl>\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <MkTypLibCompatible>true</MkTypLibCompatible>\n      <SuppressStartupBanner>true</SuppressStartupBanner>\n      <TypeLibraryName>.\\Release/q3_ui.tlb</TypeLibraryName>\n      <HeaderFileName>\n      </HeaderFileName>\n    </Midl>\n    <ClCompile>\n      <Optimization>MaxSpeed</Optimization>\n      <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;Q3_UI_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <StringPooling>true</StringPooling>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <WarningLevel>Level3</WarningLevel>\n      <SuppressStartupBanner>true</SuppressStartupBanner>\n    </ClCompile>\n    <ResourceCompile>\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Culture>0x0409</Culture>\n    </ResourceCompile>\n    <Link>\n      <SuppressStartupBanner>true</SuppressStartupBanner>\n      <ModuleDefinitionFile>ui.def</ModuleDefinitionFile>\n    </Link>\n    <Bscmake>\n      <OutputFile>\n      </OutputFile>\n    </Bscmake>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <Midl>\n      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <MkTypLibCompatible>true</MkTypLibCompatible>\n      <SuppressStartupBanner>true</SuppressStartupBanner>\n      <TypeLibraryName>.\\..\\..\\q3_ui___Win32_Debug/q3_ui.tlb</TypeLibraryName>\n      <HeaderFileName>\n      </HeaderFileName>\n    </Midl>\n    <ClCompile>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;UI_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <WarningLevel>Level3</WarningLevel>\n      <SuppressStartupBanner>true</SuppressStartupBanner>\n      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n    </ClCompile>\n    <ResourceCompile>\n      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Culture>0x0409</Culture>\n    </ResourceCompile>\n    <Link>\n      <SuppressStartupBanner>true</SuppressStartupBanner>\n      <ModuleDefinitionFile>ui.def</ModuleDefinitionFile>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <BaseAddress>0x40000000</BaseAddress>\n    </Link>\n    <Bscmake>\n      <OutputFile>\n      </OutputFile>\n    </Bscmake>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\src\\game\\bg_misc.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\q_math.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\q_shared.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_addbots.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_atoms.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_cdkey.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_cinematics.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_confirm.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_connect.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_controls2.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_credits.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_demo2.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_display.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_gameinfo.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_ingame.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_main.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_menu.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_mfield.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_mods.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_network.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_options.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_playermodel.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_players.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_playersettings.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_preferences.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_qmenu.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_removebots.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_serverinfo.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_servers2.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_setup.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_sound.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_sparena.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_specifyserver.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_splevel.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_sppostgame.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_spreset.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_spskill.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_startserver.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_syscalls.c\" />\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_team.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_teamorders.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_video.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS</PreprocessorDefinitions>\n      <BasicRuntimeChecks Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">EnableFastChecks</BasicRuntimeChecks>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS</PreprocessorDefinitions>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <CustomBuildStep Include=\"..\\src\\q3_ui\\keycodes.h\" />\n    <CustomBuildStep Include=\"..\\src\\game\\q_shared.h\" />\n    <CustomBuildStep Include=\"..\\src\\q3_ui\\ui_local.h\" />\n    <CustomBuildStep Include=\"..\\src\\q3_ui\\ui_public.h\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "visual-studio/q3_ui.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Source Files\">\n      <UniqueIdentifier>{b2fdcf3a-f4f0-4f57-81aa-bfd9670d8f3e}</UniqueIdentifier>\n      <Extensions>cpp;c;cxx;rc;def;r;odl;idl;hpj;bat</Extensions>\n    </Filter>\n    <Filter Include=\"Header Files\">\n      <UniqueIdentifier>{39dbc53c-1a17-4545-8e03-7ee706636594}</UniqueIdentifier>\n      <Extensions>h;hpp;hxx;hm;inl</Extensions>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\src\\game\\bg_misc.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\q_math.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\q_shared.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_addbots.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_atoms.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_cdkey.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_cinematics.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_confirm.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_connect.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_controls2.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_credits.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_demo2.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_display.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_gameinfo.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_ingame.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_main.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_menu.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_mfield.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_mods.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_network.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_options.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_playermodel.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_players.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_playersettings.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_preferences.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_qmenu.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_removebots.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_serverinfo.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_servers2.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_setup.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_sound.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_sparena.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_specifyserver.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_splevel.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_sppostgame.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_spreset.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_spskill.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_startserver.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_syscalls.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_team.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_teamorders.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\q3_ui\\ui_video.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <CustomBuildStep Include=\"..\\src\\q3_ui\\keycodes.h\">\n      <Filter>Header Files</Filter>\n    </CustomBuildStep>\n    <CustomBuildStep Include=\"..\\src\\game\\q_shared.h\">\n      <Filter>Header Files</Filter>\n    </CustomBuildStep>\n    <CustomBuildStep Include=\"..\\src\\q3_ui\\ui_local.h\">\n      <Filter>Header Files</Filter>\n    </CustomBuildStep>\n    <CustomBuildStep Include=\"..\\src\\q3_ui\\ui_public.h\">\n      <Filter>Header Files</Filter>\n    </CustomBuildStep>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "visual-studio/quake3.sln",
    "content": "Microsoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio 15\nVisualStudioVersion = 15.0.26228.4\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"engine\", \"engine\", \"{5B54F488-44F9-4D22-AD98-5AF9B29D27F9}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"botlib\", \"botlib.vcxproj\", \"{A410161F-AE9F-485D-A01F-5294891430A6}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"cgame\", \"cgame.vcxproj\", \"{C878E295-CB82-4B40-8ECF-5CE5525466FA}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"game\", \"game.vcxproj\", \"{F9EE10DA-2404-4154-B904-F93C936C040A}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"q3_ui\", \"q3_ui.vcxproj\", \"{D454C4C7-7765-4149-ABAD-05FDEB9D94F8}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"quake3\", \"quake3.vcxproj\", \"{81CB51C4-B434-4E12-B69B-BAEE102F2852}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"renderer\", \"renderer.vcxproj\", \"{AB424155-FBED-4D8D-B007-5B6CF93EA395}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|x64 = Debug|x64\n\t\tRelease|x64 = Release|x64\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{A410161F-AE9F-485D-A01F-5294891430A6}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{A410161F-AE9F-485D-A01F-5294891430A6}.Debug|x64.Build.0 = Debug|x64\n\t\t{A410161F-AE9F-485D-A01F-5294891430A6}.Release|x64.ActiveCfg = Release|x64\n\t\t{A410161F-AE9F-485D-A01F-5294891430A6}.Release|x64.Build.0 = Release|x64\n\t\t{C878E295-CB82-4B40-8ECF-5CE5525466FA}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{C878E295-CB82-4B40-8ECF-5CE5525466FA}.Debug|x64.Build.0 = Debug|x64\n\t\t{C878E295-CB82-4B40-8ECF-5CE5525466FA}.Release|x64.ActiveCfg = Release|x64\n\t\t{C878E295-CB82-4B40-8ECF-5CE5525466FA}.Release|x64.Build.0 = Release|x64\n\t\t{F9EE10DA-2404-4154-B904-F93C936C040A}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{F9EE10DA-2404-4154-B904-F93C936C040A}.Debug|x64.Build.0 = Debug|x64\n\t\t{F9EE10DA-2404-4154-B904-F93C936C040A}.Release|x64.ActiveCfg = Release|x64\n\t\t{F9EE10DA-2404-4154-B904-F93C936C040A}.Release|x64.Build.0 = Release|x64\n\t\t{D454C4C7-7765-4149-ABAD-05FDEB9D94F8}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{D454C4C7-7765-4149-ABAD-05FDEB9D94F8}.Debug|x64.Build.0 = Debug|x64\n\t\t{D454C4C7-7765-4149-ABAD-05FDEB9D94F8}.Release|x64.ActiveCfg = Release|x64\n\t\t{D454C4C7-7765-4149-ABAD-05FDEB9D94F8}.Release|x64.Build.0 = Release|x64\n\t\t{81CB51C4-B434-4E12-B69B-BAEE102F2852}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{81CB51C4-B434-4E12-B69B-BAEE102F2852}.Debug|x64.Build.0 = Debug|x64\n\t\t{81CB51C4-B434-4E12-B69B-BAEE102F2852}.Release|x64.ActiveCfg = Release|x64\n\t\t{81CB51C4-B434-4E12-B69B-BAEE102F2852}.Release|x64.Build.0 = Release|x64\n\t\t{AB424155-FBED-4D8D-B007-5B6CF93EA395}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{AB424155-FBED-4D8D-B007-5B6CF93EA395}.Debug|x64.Build.0 = Debug|x64\n\t\t{AB424155-FBED-4D8D-B007-5B6CF93EA395}.Release|x64.ActiveCfg = Release|x64\n\t\t{AB424155-FBED-4D8D-B007-5B6CF93EA395}.Release|x64.Build.0 = Release|x64\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(NestedProjects) = preSolution\n\t\t{A410161F-AE9F-485D-A01F-5294891430A6} = {5B54F488-44F9-4D22-AD98-5AF9B29D27F9}\n\t\t{81CB51C4-B434-4E12-B69B-BAEE102F2852} = {5B54F488-44F9-4D22-AD98-5AF9B29D27F9}\n\t\t{AB424155-FBED-4D8D-B007-5B6CF93EA395} = {5B54F488-44F9-4D22-AD98-5AF9B29D27F9}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "visual-studio/quake3.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{81CB51C4-B434-4E12-B69B-BAEE102F2852}</ProjectGuid>\n    <RootNamespace>quake3</RootNamespace>\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseOfMfc>false</UseOfMfc>\n    <PlatformToolset>v143</PlatformToolset>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseOfMfc>false</UseOfMfc>\n    <PlatformToolset>v143</PlatformToolset>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n    <Import Project=\"$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props\" />\n    <Import Project=\"props\\shared.props\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n    <Import Project=\"$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props\" />\n    <Import Project=\"props\\shared.props\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup>\n    <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\n    <LinkIncremental Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">true</LinkIncremental>\n    <LinkIncremental Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">false</LinkIncremental>\n    <CodeAnalysisRuleSet Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">AllRules.ruleset</CodeAnalysisRuleSet>\n    <CodeAnalysisRules Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" />\n    <CodeAnalysisRuleAssemblies Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" />\n    <CodeAnalysisRuleSet Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">AllRules.ruleset</CodeAnalysisRuleSet>\n    <CodeAnalysisRules Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" />\n    <CodeAnalysisRuleAssemblies Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" />\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <TargetName>$(ProjectName)-ke</TargetName>\n    <EnableMicrosoftCodeAnalysis>false</EnableMicrosoftCodeAnalysis>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <TargetName>$(ProjectName)-ke</TargetName>\n    <EnableMicrosoftCodeAnalysis>false</EnableMicrosoftCodeAnalysis>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <Midl>\n      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <MkTypLibCompatible>true</MkTypLibCompatible>\n      <SuppressStartupBanner>true</SuppressStartupBanner>\n      <TypeLibraryName>.\\Debug/quake3.tlb</TypeLibraryName>\n      <HeaderFileName>\n      </HeaderFileName>\n    </Midl>\n    <ClCompile>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <WarningLevel>Level3</WarningLevel>\n      <SuppressStartupBanner>true</SuppressStartupBanner>\n      <CompileAs>CompileAsCpp</CompileAs>\n    </ClCompile>\n    <ResourceCompile>\n      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Culture>0x0409</Culture>\n    </ResourceCompile>\n    <Link>\n      <AdditionalDependencies>winmm.lib;wsock32.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <SuppressStartupBanner>true</SuppressStartupBanner>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Windows</SubSystem>\n      <StackReserveSize>8388608</StackReserveSize>\n      <AdditionalLibraryDirectories>$(ProjectDir)..\\..\\third_party\\lib</AdditionalLibraryDirectories>\n    </Link>\n    <Bscmake>\n      <OutputFile>\n      </OutputFile>\n    </Bscmake>\n    <PostBuildEvent />\n    <Manifest>\n      <AdditionalManifestFiles>DeclareDPIAware.manifest</AdditionalManifestFiles>\n    </Manifest>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <Midl>\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <MkTypLibCompatible>true</MkTypLibCompatible>\n      <SuppressStartupBanner>true</SuppressStartupBanner>\n      <TypeLibraryName>.\\Release/quake3.tlb</TypeLibraryName>\n      <HeaderFileName>\n      </HeaderFileName>\n    </Midl>\n    <ClCompile>\n      <Optimization>MaxSpeed</Optimization>\n      <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <StringPooling>true</StringPooling>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <WarningLevel>Level3</WarningLevel>\n      <SuppressStartupBanner>true</SuppressStartupBanner>\n      <CompileAs>CompileAsCpp</CompileAs>\n    </ClCompile>\n    <ResourceCompile>\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Culture>0x0409</Culture>\n    </ResourceCompile>\n    <Link>\n      <AdditionalDependencies>winmm.lib;wsock32.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <SuppressStartupBanner>true</SuppressStartupBanner>\n      <SubSystem>Windows</SubSystem>\n      <StackReserveSize>8388608</StackReserveSize>\n      <AdditionalLibraryDirectories>$(ProjectDir)..\\..\\third_party\\lib</AdditionalLibraryDirectories>\n    </Link>\n    <Bscmake>\n      <OutputFile>\n      </OutputFile>\n    </Bscmake>\n    <Manifest>\n      <AdditionalManifestFiles>DeclareDPIAware.manifest</AdditionalManifestFiles>\n    </Manifest>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\src\\engine\\server\\sv_bot.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\server\\sv_ccmds.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\server\\sv_client.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\server\\sv_game.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\server\\sv_init.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\server\\sv_main.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\server\\sv_net_chan.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\server\\sv_snapshot.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\server\\sv_world.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\client\\cl_cgame.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\client\\cl_cin.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\client\\cl_console.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\client\\cl_input.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\client\\cl_keys.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\client\\cl_main.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\client\\cl_net_chan.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\client\\cl_parse.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\client\\cl_scrn.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\client\\cl_ui.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\client\\snd_adpcm.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\client\\snd_dma.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\client\\snd_mem.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\client\\snd_mix.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\client\\snd_wavelet.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\platform\\win_input.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\platform\\win_main.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\platform\\win_net.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\platform\\win_shared.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\platform\\win_snd.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\platform\\win_syscon.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\platform\\win_wndproc.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\qcommon\\cm_load.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\qcommon\\cm_patch.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\qcommon\\cm_polylib.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\qcommon\\cm_test.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\qcommon\\cm_trace.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\qcommon\\cmd.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\qcommon\\common.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\qcommon\\cvar.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\qcommon\\files.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\qcommon\\huffman.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\qcommon\\md4.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\qcommon\\msg.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\qcommon\\net_chan.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\q_math.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\q_shared.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\qcommon\\unzip.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\qcommon\\vm.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\qcommon\\vm_interpreted.c\">\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Disabled</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Optimization Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">MaxSpeed</Optimization>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\src\\game\\bg_public.h\" />\n    <ClInclude Include=\"..\\src\\cgame\\cg_public.h\" />\n    <ClInclude Include=\"..\\src\\engine\\client\\client.h\" />\n    <ClInclude Include=\"..\\src\\engine\\qcommon\\cm_local.h\" />\n    <ClInclude Include=\"..\\src\\engine\\qcommon\\cm_patch.h\" />\n    <ClInclude Include=\"..\\src\\engine\\qcommon\\cm_polylib.h\" />\n    <ClInclude Include=\"..\\src\\engine\\qcommon\\cm_public.h\" />\n    <ClInclude Include=\"..\\src\\game\\g_public.h\" />\n    <ClInclude Include=\"..\\src\\q3_ui\\keycodes.h\" />\n    <ClInclude Include=\"..\\src\\engine\\client\\keys.h\" />\n    <ClInclude Include=\"..\\src\\game\\q_shared.h\" />\n    <ClInclude Include=\"..\\src\\engine\\qcommon\\qcommon.h\" />\n    <ClInclude Include=\"..\\src\\engine\\qcommon\\qfiles.h\" />\n    <ClInclude Include=\"..\\src\\engine\\renderer\\qgl.h\" />\n    <ClInclude Include=\"..\\src\\engine\\platform\\resource.h\" />\n    <ClInclude Include=\"..\\src\\engine\\server\\server.h\" />\n    <ClInclude Include=\"..\\src\\engine\\client\\snd_local.h\" />\n    <ClInclude Include=\"..\\src\\engine\\client\\snd_public.h\" />\n    <ClInclude Include=\"..\\src\\game\\surfaceflags.h\" />\n    <ClInclude Include=\"..\\src\\engine\\renderer\\tr_local.h\" />\n    <ClInclude Include=\"..\\src\\engine\\renderer\\tr_public.h\" />\n    <ClInclude Include=\"..\\src\\cgame\\tr_types.h\" />\n    <ClInclude Include=\"..\\src\\q3_ui\\ui_public.h\" />\n    <ClInclude Include=\"..\\src\\engine\\qcommon\\unzip.h\" />\n    <ClInclude Include=\"..\\src\\engine\\qcommon\\vm_local.h\" />\n    <ClInclude Include=\"..\\src\\engine\\platform\\win_local.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"..\\src\\engine\\platform\\qe3.ico\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"..\\src\\engine\\platform\\winquake.rc\">\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <AdditionalIncludeDirectories Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">platform;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <AdditionalIncludeDirectories Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">platform;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ResourceCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"botlib.vcxproj\">\n      <Project>{a410161f-ae9f-485d-a01f-5294891430a6}</Project>\n      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\n    </ProjectReference>\n    <ProjectReference Include=\"renderer.vcxproj\">\n      <Project>{ab424155-fbed-4d8d-b007-5b6cf93ea395}</Project>\n      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\n    </ProjectReference>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "visual-studio/quake3.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Source Files\">\n      <UniqueIdentifier>{fe747a0c-d121-4af0-8e7e-16dc5f854815}</UniqueIdentifier>\n      <Extensions>cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90</Extensions>\n    </Filter>\n    <Filter Include=\"Source Files\\server\">\n      <UniqueIdentifier>{4bc1f185-7cce-406d-92bb-60e30e9c6d39}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source Files\\client\">\n      <UniqueIdentifier>{ee4ec941-90c2-4111-84e5-3a384ec99170}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source Files\\platform\">\n      <UniqueIdentifier>{f4a5c1df-75fc-4bb6-b7eb-edcec29ede73}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source Files\\common\">\n      <UniqueIdentifier>{1e1e1f17-ddaf-4ae0-abcd-15b563cfa1c9}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Header Files\">\n      <UniqueIdentifier>{66675b2c-a1a7-474b-b647-10e3802914eb}</UniqueIdentifier>\n      <Extensions>h;hpp;hxx;hm;inl;fi;fd</Extensions>\n    </Filter>\n    <Filter Include=\"Resource Files\">\n      <UniqueIdentifier>{5bf50589-37bc-4aca-af0b-913fa2808755}</UniqueIdentifier>\n      <Extensions>ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe</Extensions>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\src\\engine\\server\\sv_bot.c\">\n      <Filter>Source Files\\server</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\server\\sv_ccmds.c\">\n      <Filter>Source Files\\server</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\server\\sv_client.c\">\n      <Filter>Source Files\\server</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\server\\sv_game.c\">\n      <Filter>Source Files\\server</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\server\\sv_init.c\">\n      <Filter>Source Files\\server</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\server\\sv_main.c\">\n      <Filter>Source Files\\server</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\server\\sv_net_chan.c\">\n      <Filter>Source Files\\server</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\server\\sv_snapshot.c\">\n      <Filter>Source Files\\server</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\server\\sv_world.c\">\n      <Filter>Source Files\\server</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\client\\cl_cgame.c\">\n      <Filter>Source Files\\client</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\client\\cl_cin.c\">\n      <Filter>Source Files\\client</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\client\\cl_console.c\">\n      <Filter>Source Files\\client</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\client\\cl_input.c\">\n      <Filter>Source Files\\client</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\client\\cl_keys.c\">\n      <Filter>Source Files\\client</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\client\\cl_main.c\">\n      <Filter>Source Files\\client</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\client\\cl_net_chan.c\">\n      <Filter>Source Files\\client</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\client\\cl_parse.c\">\n      <Filter>Source Files\\client</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\client\\cl_scrn.c\">\n      <Filter>Source Files\\client</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\client\\cl_ui.c\">\n      <Filter>Source Files\\client</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\client\\snd_adpcm.c\">\n      <Filter>Source Files\\client</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\client\\snd_dma.c\">\n      <Filter>Source Files\\client</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\client\\snd_mem.c\">\n      <Filter>Source Files\\client</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\client\\snd_mix.c\">\n      <Filter>Source Files\\client</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\client\\snd_wavelet.c\">\n      <Filter>Source Files\\client</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\platform\\win_input.c\">\n      <Filter>Source Files\\platform</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\platform\\win_main.c\">\n      <Filter>Source Files\\platform</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\platform\\win_net.c\">\n      <Filter>Source Files\\platform</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\platform\\win_shared.c\">\n      <Filter>Source Files\\platform</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\platform\\win_snd.c\">\n      <Filter>Source Files\\platform</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\platform\\win_syscon.c\">\n      <Filter>Source Files\\platform</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\platform\\win_wndproc.c\">\n      <Filter>Source Files\\platform</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\qcommon\\cm_load.c\">\n      <Filter>Source Files\\common</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\qcommon\\cm_patch.c\">\n      <Filter>Source Files\\common</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\qcommon\\cm_polylib.c\">\n      <Filter>Source Files\\common</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\qcommon\\cm_test.c\">\n      <Filter>Source Files\\common</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\qcommon\\cm_trace.c\">\n      <Filter>Source Files\\common</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\qcommon\\cmd.c\">\n      <Filter>Source Files\\common</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\qcommon\\common.c\">\n      <Filter>Source Files\\common</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\qcommon\\cvar.c\">\n      <Filter>Source Files\\common</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\qcommon\\files.c\">\n      <Filter>Source Files\\common</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\qcommon\\huffman.c\">\n      <Filter>Source Files\\common</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\qcommon\\md4.c\">\n      <Filter>Source Files\\common</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\qcommon\\msg.c\">\n      <Filter>Source Files\\common</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\qcommon\\net_chan.c\">\n      <Filter>Source Files\\common</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\q_math.c\">\n      <Filter>Source Files\\common</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\game\\q_shared.c\">\n      <Filter>Source Files\\common</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\qcommon\\unzip.c\">\n      <Filter>Source Files\\common</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\qcommon\\vm.c\">\n      <Filter>Source Files\\common</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\qcommon\\vm_interpreted.c\">\n      <Filter>Source Files\\common</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\src\\game\\bg_public.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\cgame\\cg_public.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\client\\client.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\qcommon\\cm_local.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\qcommon\\cm_patch.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\qcommon\\cm_polylib.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\qcommon\\cm_public.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\game\\g_public.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\client\\keys.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\game\\q_shared.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\qcommon\\qcommon.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\qcommon\\qfiles.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\renderer\\qgl.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\platform\\resource.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\server\\server.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\client\\snd_local.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\client\\snd_public.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\game\\surfaceflags.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\renderer\\tr_local.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\renderer\\tr_public.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\cgame\\tr_types.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\q3_ui\\ui_public.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\qcommon\\unzip.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\qcommon\\vm_local.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\platform\\win_local.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\q3_ui\\keycodes.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"..\\src\\engine\\platform\\qe3.ico\">\n      <Filter>Resource Files</Filter>\n    </None>\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"..\\src\\engine\\platform\\winquake.rc\">\n      <Filter>Resource Files</Filter>\n    </ResourceCompile>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "visual-studio/renderer.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{AB424155-FBED-4D8D-B007-5B6CF93EA395}</ProjectGuid>\n    <RootNamespace>renderer</RootNamespace>\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseOfMfc>false</UseOfMfc>\n    <CharacterSet>MultiByte</CharacterSet>\n    <PlatformToolset>v143</PlatformToolset>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseOfMfc>false</UseOfMfc>\n    <CharacterSet>MultiByte</CharacterSet>\n    <PlatformToolset>v143</PlatformToolset>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n    <Import Project=\"$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props\" />\n    <Import Project=\"props\\shared.props\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n    <Import Project=\"$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props\" />\n    <Import Project=\"props\\shared.props\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup>\n    <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\n    <CodeAnalysisRuleSet Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">AllRules.ruleset</CodeAnalysisRuleSet>\n    <CodeAnalysisRules Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" />\n    <CodeAnalysisRuleAssemblies Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" />\n    <CodeAnalysisRuleSet Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">AllRules.ruleset</CodeAnalysisRuleSet>\n    <CodeAnalysisRules Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" />\n    <CodeAnalysisRuleAssemblies Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" />\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <EnableMicrosoftCodeAnalysis>false</EnableMicrosoftCodeAnalysis>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <EnableMicrosoftCodeAnalysis>false</EnableMicrosoftCodeAnalysis>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <Optimization>MaxSpeed</Optimization>\n      <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <StringPooling>true</StringPooling>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <WarningLevel>Level3</WarningLevel>\n      <SuppressStartupBanner>true</SuppressStartupBanner>\n      <CompileAs>CompileAsCpp</CompileAs>\n    </ClCompile>\n    <ResourceCompile>\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Culture>0x0409</Culture>\n    </ResourceCompile>\n    <Lib>\n      <SuppressStartupBanner>true</SuppressStartupBanner>\n    </Lib>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <WarningLevel>Level3</WarningLevel>\n      <SuppressStartupBanner>true</SuppressStartupBanner>\n      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n      <CompileAs>CompileAsCpp</CompileAs>\n    </ClCompile>\n    <ResourceCompile>\n      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <Culture>0x0409</Culture>\n    </ResourceCompile>\n    <Lib>\n      <SuppressStartupBanner>true</SuppressStartupBanner>\n    </Lib>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\dx.cpp\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\hlsl_compiled\\multi_texture_add_ge80_ps.cpp\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\hlsl_compiled\\multi_texture_add_gt0_ps.cpp\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\hlsl_compiled\\multi_texture_add_lt80_ps.cpp\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\hlsl_compiled\\multi_texture_add_ps.cpp\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\hlsl_compiled\\multi_texture_clipping_plane_vs.cpp\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\hlsl_compiled\\multi_texture_mul_ge80_ps.cpp\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\hlsl_compiled\\multi_texture_mul_gt0_ps.cpp\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\hlsl_compiled\\multi_texture_mul_lt80_ps.cpp\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\hlsl_compiled\\multi_texture_mul_ps.cpp\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\hlsl_compiled\\multi_texture_vs.cpp\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\hlsl_compiled\\single_texture_clipping_plane_vs.cpp\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\hlsl_compiled\\single_texture_ge80_ps.cpp\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\hlsl_compiled\\single_texture_gt0_ps.cpp\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\hlsl_compiled\\single_texture_lt80_ps.cpp\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\hlsl_compiled\\single_texture_ps.cpp\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\hlsl_compiled\\single_texture_vs.cpp\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\spirv\\apply_gamma_comp.cpp\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\spirv\\multi_texture_add_frag.cpp\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\spirv\\multi_texture_clipping_plane_vert.cpp\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\spirv\\multi_texture_mul_frag.cpp\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\spirv\\multi_texture_vert.cpp\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\spirv\\single_texture_clipping_plane_vert.cpp\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\spirv\\single_texture_frag.cpp\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\spirv\\single_texture_vert.cpp\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\tr_animation.c\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\tr_backend.c\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\tr_bsp.c\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\tr_cmds.c\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\tr_curve.c\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\tr_font.c\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\tr_image.c\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\tr_init.c\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\tr_light.c\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\tr_main.c\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\tr_marks.c\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\tr_mesh.c\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\tr_model.c\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\tr_noise.c\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\tr_scene.c\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\tr_shade.c\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\tr_shade_calc.c\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\tr_shader.c\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\tr_shadows.c\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\tr_sky.c\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\tr_surface.c\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\tr_world.c\" />\n    <ClCompile Include=\"..\\src\\engine\\platform\\win_gamma.c\" />\n    <ClCompile Include=\"..\\src\\engine\\platform\\win_glimp.c\" />\n    <ClCompile Include=\"..\\src\\engine\\platform\\win_qgl.c\" />\n    <ClCompile Include=\"..\\src\\engine\\renderer\\vk.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\src\\engine\\qcommon\\cm_public.h\" />\n    <ClInclude Include=\"..\\src\\engine\\renderer\\dx.h\" />\n    <ClInclude Include=\"..\\src\\engine\\renderer\\vk.h\" />\n    <ClInclude Include=\"..\\src\\game\\q_shared.h\" />\n    <ClInclude Include=\"..\\src\\engine\\qcommon\\qcommon.h\" />\n    <ClInclude Include=\"..\\src\\engine\\qcommon\\qfiles.h\" />\n    <ClInclude Include=\"..\\src\\engine\\renderer\\qgl.h\" />\n    <ClInclude Include=\"..\\src\\game\\surfaceflags.h\" />\n    <ClInclude Include=\"..\\src\\engine\\renderer\\tr_local.h\" />\n    <ClInclude Include=\"..\\src\\engine\\renderer\\tr_public.h\" />\n    <ClInclude Include=\"..\\src\\cgame\\tr_types.h\" />\n    <ClInclude Include=\"..\\src\\engine\\platform\\win_local.h\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "visual-studio/renderer.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Source Files\">\n      <UniqueIdentifier>{d0725174-4427-41e2-8844-faeb9784a696}</UniqueIdentifier>\n      <Extensions>cpp;c;cxx;rc;def;r;odl;idl;hpj;bat</Extensions>\n    </Filter>\n    <Filter Include=\"Header Files\">\n      <UniqueIdentifier>{b5fac841-7437-493f-ad30-4b4cedd1acfe}</UniqueIdentifier>\n      <Extensions>h;hpp;hxx;hm;inl</Extensions>\n    </Filter>\n    <Filter Include=\"Source Files\\spirv\">\n      <UniqueIdentifier>{b30d21cf-a2ec-44d4-80d2-73c969c32a41}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source Files\\hlsl_compiled\">\n      <UniqueIdentifier>{ff161648-6f6d-46ac-af5d-08fdfb82914a}</UniqueIdentifier>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\tr_animation.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\tr_backend.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\tr_bsp.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\tr_cmds.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\tr_curve.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\tr_font.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\tr_image.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\tr_init.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\tr_light.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\tr_main.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\tr_marks.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\tr_mesh.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\tr_model.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\tr_noise.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\tr_scene.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\tr_shade.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\tr_shade_calc.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\tr_shader.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\tr_shadows.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\tr_sky.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\tr_surface.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\tr_world.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\platform\\win_gamma.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\platform\\win_glimp.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\platform\\win_qgl.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\vk.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\spirv\\multi_texture_add_frag.cpp\">\n      <Filter>Source Files\\spirv</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\spirv\\multi_texture_mul_frag.cpp\">\n      <Filter>Source Files\\spirv</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\spirv\\multi_texture_vert.cpp\">\n      <Filter>Source Files\\spirv</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\spirv\\single_texture_frag.cpp\">\n      <Filter>Source Files\\spirv</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\spirv\\single_texture_vert.cpp\">\n      <Filter>Source Files\\spirv</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\spirv\\multi_texture_clipping_plane_vert.cpp\">\n      <Filter>Source Files\\spirv</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\spirv\\single_texture_clipping_plane_vert.cpp\">\n      <Filter>Source Files\\spirv</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\dx.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\hlsl_compiled\\single_texture_ps.cpp\">\n      <Filter>Source Files\\hlsl_compiled</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\hlsl_compiled\\single_texture_vs.cpp\">\n      <Filter>Source Files\\hlsl_compiled</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\hlsl_compiled\\multi_texture_add_ps.cpp\">\n      <Filter>Source Files\\hlsl_compiled</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\hlsl_compiled\\multi_texture_mul_ps.cpp\">\n      <Filter>Source Files\\hlsl_compiled</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\hlsl_compiled\\multi_texture_vs.cpp\">\n      <Filter>Source Files\\hlsl_compiled</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\hlsl_compiled\\multi_texture_clipping_plane_vs.cpp\">\n      <Filter>Source Files\\hlsl_compiled</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\hlsl_compiled\\single_texture_clipping_plane_vs.cpp\">\n      <Filter>Source Files\\hlsl_compiled</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\hlsl_compiled\\multi_texture_add_ge80_ps.cpp\">\n      <Filter>Source Files\\hlsl_compiled</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\hlsl_compiled\\multi_texture_add_gt0_ps.cpp\">\n      <Filter>Source Files\\hlsl_compiled</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\hlsl_compiled\\multi_texture_add_lt80_ps.cpp\">\n      <Filter>Source Files\\hlsl_compiled</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\hlsl_compiled\\multi_texture_mul_ge80_ps.cpp\">\n      <Filter>Source Files\\hlsl_compiled</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\hlsl_compiled\\multi_texture_mul_gt0_ps.cpp\">\n      <Filter>Source Files\\hlsl_compiled</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\hlsl_compiled\\multi_texture_mul_lt80_ps.cpp\">\n      <Filter>Source Files\\hlsl_compiled</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\hlsl_compiled\\single_texture_ge80_ps.cpp\">\n      <Filter>Source Files\\hlsl_compiled</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\hlsl_compiled\\single_texture_gt0_ps.cpp\">\n      <Filter>Source Files\\hlsl_compiled</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\hlsl_compiled\\single_texture_lt80_ps.cpp\">\n      <Filter>Source Files\\hlsl_compiled</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\src\\engine\\renderer\\shaders\\spirv\\apply_gamma_comp.cpp\">\n      <Filter>Source Files\\spirv</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\src\\engine\\qcommon\\cm_public.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\game\\q_shared.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\qcommon\\qcommon.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\qcommon\\qfiles.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\renderer\\qgl.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\renderer\\tr_local.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\renderer\\tr_public.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\platform\\win_local.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\game\\surfaceflags.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\cgame\\tr_types.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\renderer\\vk.h\">\n      <Filter>Source Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\src\\engine\\renderer\\dx.h\">\n      <Filter>Source Files</Filter>\n    </ClInclude>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "visual-studio/ui.def",
    "content": "EXPORTS\n\tvmMain\n\tdllEntry\n"
  }
]